Merge remote-tracking branch 'origin/master' into ephemeral
This commit is contained in:
commit
44f7ab53a2
46 changed files with 664 additions and 263 deletions
|
@ -4,14 +4,17 @@ import json
|
|||
import string
|
||||
import datetime
|
||||
|
||||
# Register the various exceptions via decorators.
|
||||
import endpoints.decorated
|
||||
|
||||
from flask import make_response, render_template, request, abort, session
|
||||
from flask.ext.login import login_user, UserMixin
|
||||
from flask.ext.login import login_user
|
||||
from flask.ext.principal import identity_changed
|
||||
from random import SystemRandom
|
||||
|
||||
from data import model
|
||||
from data.database import db
|
||||
from app import app, login_manager, dockerfile_build_queue, notification_queue, oauth_apps
|
||||
from app import app, oauth_apps, dockerfile_build_queue, LoginWrappedDBUser
|
||||
|
||||
from auth.permissions import QuayDeferredPermissionUser
|
||||
from auth import scopes
|
||||
|
@ -21,7 +24,6 @@ from functools import wraps
|
|||
from config import getFrontendVisibleConfig
|
||||
from external_libraries import get_external_javascript, get_external_css
|
||||
from endpoints.notificationhelper import spawn_notification
|
||||
from util.useremails import CannotSendEmailException
|
||||
|
||||
import features
|
||||
|
||||
|
@ -84,34 +86,8 @@ def param_required(param_name):
|
|||
return wrapper
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_uuid):
|
||||
logger.debug('User loader loading deferred user with uuid: %s' % user_uuid)
|
||||
return _LoginWrappedDBUser(user_uuid)
|
||||
|
||||
|
||||
class _LoginWrappedDBUser(UserMixin):
|
||||
def __init__(self, user_uuid, db_user=None):
|
||||
self._uuid = user_uuid
|
||||
self._db_user = db_user
|
||||
|
||||
def db_user(self):
|
||||
if not self._db_user:
|
||||
self._db_user = model.get_user_by_uuid(self._uuid)
|
||||
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._uuid)
|
||||
|
||||
|
||||
def common_login(db_user):
|
||||
if login_user(_LoginWrappedDBUser(db_user.uuid, db_user)):
|
||||
if login_user(LoginWrappedDBUser(db_user.uuid, db_user)):
|
||||
logger.debug('Successfully signed in as: %s (%s)' % (db_user.username, db_user.uuid))
|
||||
new_identity = QuayDeferredPermissionUser(db_user.uuid, 'user_uuid', {scopes.DIRECT_LOGIN})
|
||||
identity_changed.send(app, identity=new_identity)
|
||||
|
@ -121,17 +97,6 @@ def common_login(db_user):
|
|||
logger.debug('User could not be logged in, inactive?.')
|
||||
return False
|
||||
|
||||
|
||||
@app.errorhandler(model.DataModelException)
|
||||
def handle_dme(ex):
|
||||
logger.exception(ex)
|
||||
return make_response(json.dumps({'message': ex.message}), 400)
|
||||
|
||||
@app.errorhandler(CannotSendEmailException)
|
||||
def handle_emailexception(ex):
|
||||
message = 'Could not send email. Please contact an administrator and report this problem.'
|
||||
return make_response(json.dumps({'message': message}), 400)
|
||||
|
||||
def random_string():
|
||||
random = SystemRandom()
|
||||
return ''.join([random.choice(string.ascii_uppercase + string.digits) for _ in range(8)])
|
||||
|
|
19
endpoints/decorated.py
Normal file
19
endpoints/decorated.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
import logging
|
||||
import json
|
||||
|
||||
from flask import make_response
|
||||
from app import app
|
||||
from util.useremails import CannotSendEmailException
|
||||
from data import model
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@app.errorhandler(model.DataModelException)
|
||||
def handle_dme(ex):
|
||||
logger.exception(ex)
|
||||
return make_response(json.dumps({'message': ex.message}), 400)
|
||||
|
||||
@app.errorhandler(CannotSendEmailException)
|
||||
def handle_emailexception(ex):
|
||||
message = 'Could not send email. Please contact an administrator and report this problem.'
|
||||
return make_response(json.dumps({'message': message}), 400)
|
|
@ -305,9 +305,7 @@ def get_repository_images(namespace, repository):
|
|||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
|
||||
# TODO invalidate token?
|
||||
profile.debug('Looking up public status of repository')
|
||||
is_public = model.repository_is_public(namespace, repository)
|
||||
if permission.can() or is_public:
|
||||
if permission.can() or model.repository_is_public(namespace, repository):
|
||||
# We can't rely on permissions to tell us if a repo exists anymore
|
||||
profile.debug('Looking up repository')
|
||||
repo = model.get_repository(namespace, repository)
|
||||
|
@ -382,6 +380,11 @@ def get_search():
|
|||
resp.mimetype = 'application/json'
|
||||
return resp
|
||||
|
||||
# Note: This is *not* part of the Docker index spec. This is here for our own health check,
|
||||
# since we have nginx handle the _ping below.
|
||||
@index.route('/_internal_ping')
|
||||
def internal_ping():
|
||||
return make_response('true', 200)
|
||||
|
||||
@index.route('/_ping')
|
||||
@index.route('/_ping')
|
||||
|
|
|
@ -19,20 +19,23 @@ def track_and_log(event_name, repo, **kwargs):
|
|||
|
||||
analytics_id = 'anonymous'
|
||||
|
||||
authenticated_oauth_token = get_validated_oauth_token()
|
||||
authenticated_user = get_authenticated_user()
|
||||
authenticated_token = get_validated_token() if not authenticated_user else None
|
||||
|
||||
profile.debug('Logging the %s to Mixpanel and the log system', event_name)
|
||||
if get_validated_oauth_token():
|
||||
oauth_token = get_validated_oauth_token()
|
||||
metadata['oauth_token_id'] = oauth_token.id
|
||||
metadata['oauth_token_application_id'] = oauth_token.application.client_id
|
||||
metadata['oauth_token_application'] = oauth_token.application.name
|
||||
analytics_id = 'oauth:' + oauth_token.id
|
||||
elif get_authenticated_user():
|
||||
metadata['username'] = get_authenticated_user().username
|
||||
analytics_id = get_authenticated_user().username
|
||||
elif get_validated_token():
|
||||
metadata['token'] = get_validated_token().friendly_name
|
||||
metadata['token_code'] = get_validated_token().code
|
||||
analytics_id = 'token:' + get_validated_token().code
|
||||
if authenticated_oauth_token:
|
||||
metadata['oauth_token_id'] = authenticated_oauth_token.id
|
||||
metadata['oauth_token_application_id'] = authenticated_oauth_token.application.client_id
|
||||
metadata['oauth_token_application'] = authenticated_oauth_token.application.name
|
||||
analytics_id = 'oauth:' + authenticated_oauth_token.id
|
||||
elif authenticated_user:
|
||||
metadata['username'] = authenticated_user.username
|
||||
analytics_id = authenticated_user.username
|
||||
elif authenticated_token:
|
||||
metadata['token'] = authenticated_token.friendly_name
|
||||
metadata['token_code'] = authenticated_token.code
|
||||
analytics_id = 'token:' + authenticated_token.code
|
||||
else:
|
||||
metadata['public'] = True
|
||||
analytics_id = 'anonymous'
|
||||
|
@ -42,21 +45,27 @@ def track_and_log(event_name, repo, **kwargs):
|
|||
}
|
||||
|
||||
# Publish the user event (if applicable)
|
||||
if get_authenticated_user():
|
||||
profile.debug('Checking publishing %s to the user events system', event_name)
|
||||
if authenticated_user:
|
||||
profile.debug('Publishing %s to the user events system', event_name)
|
||||
user_event_data = {
|
||||
'action': event_name,
|
||||
'repository': repository,
|
||||
'namespace': namespace
|
||||
}
|
||||
|
||||
event = userevents.get_event(get_authenticated_user().username)
|
||||
event = userevents.get_event(authenticated_user.username)
|
||||
event.publish_event_data('docker-cli', user_event_data)
|
||||
|
||||
# Save the action to mixpanel.
|
||||
profile.debug('Logging the %s to Mixpanel', event_name)
|
||||
analytics.track(analytics_id, event_name, extra_params)
|
||||
|
||||
# Log the action to the database.
|
||||
profile.debug('Logging the %s to logs system', event_name)
|
||||
model.log_action(event_name, namespace,
|
||||
performer=get_authenticated_user(),
|
||||
performer=authenticated_user,
|
||||
ip=request.remote_addr, metadata=metadata,
|
||||
repository=repo)
|
||||
|
||||
profile.debug('Track and log of %s complete', event_name)
|
||||
|
|
|
@ -226,7 +226,7 @@ class GithubBuildTrigger(BuildTrigger):
|
|||
'personal': False,
|
||||
'repos': repo_list,
|
||||
'info': {
|
||||
'name': org.name,
|
||||
'name': org.name or org.login,
|
||||
'avatar_url': org.avatar_url
|
||||
}
|
||||
})
|
||||
|
|
|
@ -6,7 +6,7 @@ from flask import (abort, redirect, request, url_for, make_response, Response,
|
|||
from avatar_generator import Avatar
|
||||
from flask.ext.login import current_user
|
||||
from urlparse import urlparse
|
||||
from health.healthcheck import HealthCheck
|
||||
from health.healthcheck import get_healthchecker
|
||||
|
||||
from data import model
|
||||
from data.model.oauth import DatabaseAuthorizationProvider
|
||||
|
@ -27,6 +27,9 @@ import features
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Capture the unverified SSL errors.
|
||||
logging.captureWarnings(True)
|
||||
|
||||
web = Blueprint('web', __name__)
|
||||
|
||||
STATUS_TAGS = app.config['STATUS_TAGS']
|
||||
|
@ -153,33 +156,27 @@ def v1():
|
|||
return index('')
|
||||
|
||||
|
||||
# TODO(jschorr): Remove this mirrored endpoint once we migrate ELB.
|
||||
@web.route('/health', methods=['GET'])
|
||||
@web.route('/health/instance', methods=['GET'])
|
||||
@no_cache
|
||||
def health():
|
||||
db_healthy = model.check_health()
|
||||
buildlogs_healthy = build_logs.check_health()
|
||||
|
||||
check = HealthCheck.get_check(app.config['HEALTH_CHECKER'][0], app.config['HEALTH_CHECKER'][1])
|
||||
(data, is_healthy) = check.conduct_healthcheck(db_healthy, buildlogs_healthy)
|
||||
|
||||
response = jsonify(dict(data = data, is_healthy = is_healthy))
|
||||
response.status_code = 200 if is_healthy else 503
|
||||
def instance_health():
|
||||
checker = get_healthchecker(app)
|
||||
(data, status_code) = checker.check_instance()
|
||||
response = jsonify(dict(data=data, status_code=status_code))
|
||||
response.status_code = status_code
|
||||
return response
|
||||
|
||||
|
||||
# TODO(jschorr): Remove this mirrored endpoint once we migrate pingdom.
|
||||
@web.route('/status', methods=['GET'])
|
||||
@web.route('/health/endtoend', methods=['GET'])
|
||||
@no_cache
|
||||
def status():
|
||||
db_healthy = model.check_health()
|
||||
buildlogs_healthy = build_logs.check_health()
|
||||
|
||||
response = jsonify({
|
||||
'db_healthy': db_healthy,
|
||||
'buildlogs_healthy': buildlogs_healthy,
|
||||
'is_testing': app.config['TESTING'],
|
||||
})
|
||||
response.status_code = 200 if db_healthy and buildlogs_healthy else 503
|
||||
|
||||
def endtoend_health():
|
||||
checker = get_healthchecker(app)
|
||||
(data, status_code) = checker.check_endtoend()
|
||||
response = jsonify(dict(data=data, status_code=status_code))
|
||||
response.status_code = status_code
|
||||
return response
|
||||
|
||||
|
||||
|
|
Reference in a new issue