2013-12-27 22:19:14 +00:00
|
|
|
import logging
|
2014-02-26 00:39:43 +00:00
|
|
|
import urlparse
|
|
|
|
import json
|
2014-03-26 22:36:59 +00:00
|
|
|
import string
|
2013-12-27 22:19:14 +00:00
|
|
|
|
2014-03-25 18:32:26 +00:00
|
|
|
from flask import make_response, render_template, request
|
|
|
|
from flask.ext.login import login_user, UserMixin
|
2013-12-27 22:19:14 +00:00
|
|
|
from flask.ext.principal import identity_changed
|
2014-03-26 22:36:59 +00:00
|
|
|
from random import SystemRandom
|
2013-12-27 22:19:14 +00:00
|
|
|
|
|
|
|
from data import model
|
2014-02-26 00:39:43 +00:00
|
|
|
from data.queue import dockerfile_build_queue
|
2013-12-27 22:19:14 +00:00
|
|
|
from app import app, login_manager
|
2013-12-27 23:01:44 +00:00
|
|
|
from auth.permissions import QuayDeferredPermissionUser
|
2014-03-19 22:21:58 +00:00
|
|
|
from auth import scopes
|
2014-03-17 16:01:13 +00:00
|
|
|
from endpoints.api.discovery import swagger_route_data
|
2014-03-11 18:30:00 +00:00
|
|
|
from werkzeug.routing import BaseConverter
|
2013-12-27 22:19:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2014-02-18 20:50:15 +00:00
|
|
|
route_data = None
|
|
|
|
|
2014-03-11 18:30:00 +00:00
|
|
|
class RepoPathConverter(BaseConverter):
|
2014-03-11 18:42:53 +00:00
|
|
|
regex = '[\.a-zA-Z0-9_\-]+/[\.a-zA-Z0-9_\-]+'
|
2014-03-11 18:30:00 +00:00
|
|
|
weight = 200
|
|
|
|
|
|
|
|
app.url_map.converters['repopath'] = RepoPathConverter
|
|
|
|
|
|
|
|
|
2014-02-18 20:50:15 +00:00
|
|
|
def get_route_data():
|
|
|
|
global route_data
|
|
|
|
if route_data:
|
|
|
|
return route_data
|
|
|
|
|
2014-03-15 03:40:41 +00:00
|
|
|
route_data = swagger_route_data(include_internal=True, compact=True)
|
2014-02-18 20:50:15 +00:00
|
|
|
return route_data
|
|
|
|
|
|
|
|
|
2014-02-16 23:59:24 +00:00
|
|
|
def truthy_param(param):
|
|
|
|
return param not in {False, 'false', 'False', '0', 'FALSE', '', 'null'}
|
|
|
|
|
|
|
|
|
2013-12-27 22:19:14 +00:00
|
|
|
@login_manager.user_loader
|
|
|
|
def load_user(username):
|
2014-03-17 16:01:13 +00:00
|
|
|
logger.debug('User loader loading deferred user: %s' % username)
|
2013-12-27 22:19:14 +00:00
|
|
|
return _LoginWrappedDBUser(username)
|
|
|
|
|
2014-03-17 16:01:13 +00:00
|
|
|
|
2013-12-27 22:19:14 +00:00
|
|
|
class _LoginWrappedDBUser(UserMixin):
|
|
|
|
def __init__(self, db_username, db_user=None):
|
|
|
|
|
|
|
|
self._db_username = db_username
|
|
|
|
self._db_user = db_user
|
|
|
|
|
|
|
|
def db_user(self):
|
|
|
|
if not self._db_user:
|
|
|
|
self._db_user = model.get_user(self._db_username)
|
|
|
|
return self._db_user
|
|
|
|
|
|
|
|
def is_authenticated(self):
|
|
|
|
return self.db_user() is not None
|
|
|
|
|
|
|
|
def is_active(self):
|
|
|
|
return self.db_user().verified
|
|
|
|
|
|
|
|
def get_id(self):
|
|
|
|
return unicode(self._db_username)
|
|
|
|
|
|
|
|
|
|
|
|
def common_login(db_user):
|
|
|
|
if login_user(_LoginWrappedDBUser(db_user.username, db_user)):
|
|
|
|
logger.debug('Successfully signed in as: %s' % db_user.username)
|
2014-03-19 22:21:58 +00:00
|
|
|
new_identity = QuayDeferredPermissionUser(db_user.username, 'username', {scopes.DIRECT_LOGIN})
|
2013-12-27 22:19:14 +00:00
|
|
|
identity_changed.send(app, identity=new_identity)
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
logger.debug('User could not be logged in, inactive?.')
|
|
|
|
return False
|
2013-12-28 19:07:44 +00:00
|
|
|
|
|
|
|
|
2013-12-30 22:05:27 +00:00
|
|
|
@app.errorhandler(model.DataModelException)
|
|
|
|
def handle_dme(ex):
|
2014-02-25 21:54:49 +00:00
|
|
|
logger.exception(ex)
|
2014-03-19 00:32:37 +00:00
|
|
|
return make_response(json.dumps({'message': ex.message}), 400)
|
2013-12-30 22:05:27 +00:00
|
|
|
|
|
|
|
|
2014-03-26 22:36:59 +00:00
|
|
|
def random_string():
|
|
|
|
random = SystemRandom()
|
|
|
|
return ''.join([random.choice(string.ascii_uppercase + string.digits) for _ in range(8)])
|
|
|
|
|
2014-02-18 20:50:15 +00:00
|
|
|
def render_page_template(name, **kwargs):
|
2014-03-26 22:36:59 +00:00
|
|
|
resp = make_response(render_template(name, route_data=json.dumps(get_route_data()),
|
2014-04-02 16:22:32 +00:00
|
|
|
cache_buster=random_string(), **kwargs))
|
2014-02-18 20:50:15 +00:00
|
|
|
resp.headers['X-FRAME-OPTIONS'] = 'DENY'
|
2014-02-21 19:52:40 +00:00
|
|
|
return resp
|
2014-02-26 00:39:43 +00:00
|
|
|
|
|
|
|
|
2014-03-12 23:19:39 +00:00
|
|
|
def check_repository_usage(user_or_org, plan_found):
|
|
|
|
private_repos = model.get_private_repo_count(user_or_org.username)
|
|
|
|
repos_allowed = plan_found['privateRepos']
|
2014-03-12 04:49:03 +00:00
|
|
|
|
2014-03-12 23:19:39 +00:00
|
|
|
if private_repos > repos_allowed:
|
|
|
|
model.create_notification('over_private_usage', user_or_org, {'namespace': user_or_org.username})
|
|
|
|
else:
|
|
|
|
model.delete_notifications_by_kind(user_or_org, 'over_private_usage')
|
2014-03-12 04:49:03 +00:00
|
|
|
|
|
|
|
|
2014-02-26 00:39:43 +00:00
|
|
|
def start_build(repository, dockerfile_id, tags, build_name, subdir, manual,
|
2014-04-02 01:49:06 +00:00
|
|
|
trigger=None, pull_robot_name=None):
|
2014-02-26 00:39:43 +00:00
|
|
|
host = urlparse.urlparse(request.url).netloc
|
|
|
|
repo_path = '%s/%s/%s' % (host, repository.namespace, repository.name)
|
|
|
|
|
|
|
|
token = model.create_access_token(repository, 'write')
|
|
|
|
logger.debug('Creating build %s with repo %s tags %s and dockerfile_id %s',
|
|
|
|
build_name, repo_path, tags, dockerfile_id)
|
|
|
|
|
|
|
|
job_config = {
|
|
|
|
'docker_tags': tags,
|
|
|
|
'repository': repo_path,
|
2014-04-02 01:49:06 +00:00
|
|
|
'build_subdir': subdir
|
2014-02-26 00:39:43 +00:00
|
|
|
}
|
2014-03-27 22:33:13 +00:00
|
|
|
|
2014-02-26 00:39:43 +00:00
|
|
|
build_request = model.create_repository_build(repository, token, job_config,
|
|
|
|
dockerfile_id, build_name,
|
2014-04-02 01:49:06 +00:00
|
|
|
trigger, pull_robot_name = pull_robot_name)
|
2014-02-26 00:39:43 +00:00
|
|
|
|
|
|
|
dockerfile_build_queue.put(json.dumps({
|
|
|
|
'build_uuid': build_request.uuid,
|
|
|
|
'namespace': repository.namespace,
|
|
|
|
'repository': repository.name,
|
2014-04-02 01:49:06 +00:00
|
|
|
'pull_credentials': model.get_pull_credentials(pull_robot_name) if pull_robot_name else None
|
2014-02-26 00:39:43 +00:00
|
|
|
}), retries_remaining=1)
|
|
|
|
|
|
|
|
metadata = {
|
|
|
|
'repo': repository.name,
|
|
|
|
'namespace': repository.namespace,
|
|
|
|
'fileid': dockerfile_id,
|
|
|
|
'manual': manual,
|
|
|
|
}
|
|
|
|
|
|
|
|
if trigger:
|
|
|
|
metadata['trigger_id'] = trigger.uuid
|
|
|
|
metadata['config'] = json.loads(trigger.config)
|
|
|
|
metadata['service'] = trigger.service.name
|
|
|
|
|
|
|
|
model.log_action('build_dockerfile', repository.namespace,
|
|
|
|
ip=request.remote_addr, metadata=metadata,
|
|
|
|
repository=repository)
|
|
|
|
|
2014-03-15 03:40:41 +00:00
|
|
|
return build_request
|