From 036c8e56e0408dd54306d6ae230ff246ea95a918 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Thu, 2 Apr 2015 18:54:09 -0400 Subject: [PATCH 1/2] Add proper error handling when the config volume is mounted in a read-only state. --- endpoints/api/suconfig.py | 1 + endpoints/decorated.py | 9 +++++++++ util/config/provider.py | 16 +++++++++++++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/endpoints/api/suconfig.py b/endpoints/api/suconfig.py index 10741d9f3..b1152231c 100644 --- a/endpoints/api/suconfig.py +++ b/endpoints/api/suconfig.py @@ -15,6 +15,7 @@ from auth.permissions import SuperUserPermission from auth.auth_context import get_authenticated_user from data.database import User from util.config.configutil import add_enterprise_config_defaults +from util.config.provider import CannotWriteConfigException from util.config.validator import validate_service_for_config, SSL_FILENAMES from data.runmigration import run_alembic_migration diff --git a/endpoints/decorated.py b/endpoints/decorated.py index 182f41a45..b51e1ee2e 100644 --- a/endpoints/decorated.py +++ b/endpoints/decorated.py @@ -4,6 +4,7 @@ import json from flask import make_response from app import app from util.useremails import CannotSendEmailException +from util.config.provider import CannotWriteConfigException from data import model logger = logging.getLogger(__name__) @@ -17,3 +18,11 @@ def handle_dme(ex): 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) + +@app.errorhandler(CannotWriteConfigException) +def handle_configexception(ex): + message = ('Configuration could not be written to the mounted volume. \n' + + 'Please make sure the mounted volume is not read-only and restart ' + + 'the setup process. \n\nIssue: %s' % ex) + + return make_response(json.dumps({'message': message}), 400) \ No newline at end of file diff --git a/util/config/provider.py b/util/config/provider.py index 5a2d92757..32bc4c6f9 100644 --- a/util/config/provider.py +++ b/util/config/provider.py @@ -6,6 +6,10 @@ from StringIO import StringIO logger = logging.getLogger(__name__) +class CannotWriteConfigException(Exception): + """ Exception raised when the config cannot be written. """ + pass + def _import_yaml(config_obj, config_file): with open(config_file) as f: c = yaml.safe_load(f) @@ -24,8 +28,11 @@ def _import_yaml(config_obj, config_file): def _export_yaml(config_obj, config_file): - with open(config_file, 'w') as f: - f.write(yaml.safe_dump(config_obj, encoding='utf-8', allow_unicode=True)) + try: + with open(config_file, 'w') as f: + f.write(yaml.safe_dump(config_obj, encoding='utf-8', allow_unicode=True)) + except IOError as ioe: + raise CannotWriteConfigException(str(ioe)) class BaseProvider(object): @@ -116,7 +123,10 @@ class FileConfigProvider(BaseProvider): return open(os.path.join(self.config_volume, filename), mode) def save_volume_file(self, filename, flask_file): - flask_file.save(os.path.join(self.config_volume, filename)) + try: + flask_file.save(os.path.join(self.config_volume, filename)) + except IOError as ioe: + raise CannotWriteConfigException(str(ioe)) def requires_restart(self, app_config): file_config = self.get_yaml() From 094f91fb8b544bf08cb34a9ca1880cb8e2d35adb Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Fri, 3 Apr 2015 12:13:33 -0400 Subject: [PATCH 2/2] Fix the tutorial's user events --- data/userevent.py | 8 ++++++-- endpoints/index.py | 27 +++++++++++---------------- static/js/pages/tutorial.js | 4 ++-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/data/userevent.py b/data/userevent.py index 5523da2e5..aea34226a 100644 --- a/data/userevent.py +++ b/data/userevent.py @@ -1,6 +1,9 @@ import redis import json import threading +import logging + +logger = logging.getLogger(__name__) class UserEventBuilder(object): """ @@ -68,8 +71,9 @@ class UserEvent(object): def conduct(): try: self.publish_event_data_sync(event_id, data_obj) - except Exception as e: - print e + logger.debug('Published user event %s: %s', event_id, data_obj) + except Exception: + logger.exception('Could not publish user event') thread = threading.Thread(target=conduct) thread.start() diff --git a/endpoints/index.py b/endpoints/index.py index e42696777..79e7c9041 100644 --- a/endpoints/index.py +++ b/endpoints/index.py @@ -114,13 +114,11 @@ def create_user(): # Mark that the user was logged in. event = userevents.get_event(username) event.publish_event_data('docker-cli', {'action': 'login'}) - return success else: # Mark that the login failed. event = userevents.get_event(username) event.publish_event_data('docker-cli', {'action': 'loginfailure'}) - abort(400, error_message, issue='login-failure') elif not features.USER_CREATION: @@ -231,6 +229,16 @@ def create_repository(namespace, repository): repo = model.create_repository(namespace, repository, get_authenticated_user()) + if get_authenticated_user(): + user_event_data = { + 'action': 'push_start', + 'repository': repository, + 'namespace': namespace + } + + event = userevents.get_event(get_authenticated_user().username) + event.publish_event_data('docker-cli', user_event_data) + return make_response('Created', 201) @@ -248,20 +256,6 @@ def update_images(namespace, repository): # Make sure the repo actually exists. abort(404, message='Unknown repository', issue='unknown-repo') - if get_authenticated_user(): - logger.debug('Publishing push event') - username = get_authenticated_user().username - - # Mark that the user has pushed the repo. - user_data = { - 'action': 'pushed_repo', - 'repository': repository, - 'namespace': namespace - } - - event = userevents.get_event(username) - event.publish_event_data('docker-cli', user_data) - logger.debug('GCing repository') model.garbage_collect_repository(namespace, repository) @@ -272,6 +266,7 @@ def update_images(namespace, repository): event_data = { 'updated_tags': updated_tags, } + track_and_log('push_repo', repo) spawn_notification(repo, 'repo_push', event_data) return make_response('Updated', 204) diff --git a/static/js/pages/tutorial.js b/static/js/pages/tutorial.js index d5661c73b..3f0c18cf3 100644 --- a/static/js/pages/tutorial.js +++ b/static/js/pages/tutorial.js @@ -59,7 +59,7 @@ 'templateUrl': '/static/tutorial/push-image.html', 'signal': AngularTourSignals.serverEvent('/realtime/user/subscribe?events=docker-cli', function(message, tourScope) { - var pushing = message['data']['action'] == 'push_repo'; + var pushing = message['data']['action'] == 'push_start'; if (pushing) { tourScope.repoName = message['data']['repository']; } @@ -73,7 +73,7 @@ 'templateUrl': '/static/tutorial/pushing.html', 'signal': AngularTourSignals.serverEvent('/realtime/user/subscribe?events=docker-cli', function(message, tourScope) { - return message['data']['action'] == 'pushed_repo'; + return message['data']['action'] == 'push_repo'; }), 'waitMessage': "Waiting for repository push to complete" },