From 278c28f3504f69187f5036beba1dadcf1746d9e9 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Thu, 8 May 2014 19:09:43 -0400 Subject: [PATCH 1/5] Fix NPE in user service --- static/js/controllers.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/static/js/controllers.js b/static/js/controllers.js index e44e3447b..2b2c4225e 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -1587,12 +1587,14 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use $scope.cuser = jQuery.extend({}, user); - for (var i = 0; i < $scope.cuser.logins.length; i++) { - if ($scope.cuser.logins[i].service == 'github') { - var githubId = $scope.cuser.logins[i].service_identifier; - $http.get('https://api.github.com/user/' + githubId).success(function(resp) { - $scope.githubLogin = resp.login; - }); + if ($scope.cuser.logins) { + for (var i = 0; i < $scope.cuser.logins.length; i++) { + if ($scope.cuser.logins[i].service == 'github') { + var githubId = $scope.cuser.logins[i].service_identifier; + $http.get('https://api.github.com/user/' + githubId).success(function(resp) { + $scope.githubLogin = resp.login; + }); + } } } }); From e2992d08bbdeea8a0fa62e0441dbdb24ce363b1d Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Fri, 9 May 2014 17:23:35 -0400 Subject: [PATCH 2/5] Further JS fixes --- static/js/app.js | 2 +- static/js/controllers.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/static/js/app.js b/static/js/app.js index 8d6869978..9c701d62a 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -84,7 +84,7 @@ function createOrganizationTeam(ApiService, orgname, teamname, callback) { 'teamname': teamname }; - ApiService.updateOrganizationTeam(data, params).then(callback, function() { + ApiService.updateOrganizationTeam(data, params).then(callback, function(resp) { bootbox.dialog({ "message": resp.data ? resp.data : 'The team could not be created', "title": "Cannot create team", diff --git a/static/js/controllers.js b/static/js/controllers.js index 2b2c4225e..e32c0797a 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -4,11 +4,16 @@ $.fn.clipboardCopy = function() { clip.on('complete', function() { // Resets the animation. var elem = $('#clipboardCopied')[0]; + if (!elem) { + return; + } + elem.style.display = 'none'; elem.classList.remove('animated'); // Show the notification. setTimeout(function() { + if (!elem) { return; } elem.style.display = 'inline-block'; elem.classList.add('animated'); }, 10); From b4e091baddc2ffc470ae2853688af2ba318036a6 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Fri, 9 May 2014 17:54:11 -0400 Subject: [PATCH 3/5] Fix the build view controller to always search for the build to update --- static/js/controllers.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/static/js/controllers.js b/static/js/controllers.js index e32c0797a..d9684cbdc 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -1021,7 +1021,6 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope $scope.currentParentEntry = null; $scope.currentBuild = build; - $scope.currentBuildIndex = index; if (opt_updateURL) { if (build) { @@ -1099,8 +1098,18 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope ApiService.getRepoBuildStatus(null, params, true).then(function(resp) { // Note: We use extend here rather than replacing as Angular is depending on the // root build object to remain the same object. - $.extend(true, $scope.builds[$scope.currentBuildIndex], resp); - var currentBuild = $scope.builds[$scope.currentBuildIndex]; + var matchingBuilds = $.grep($scope.builds, function(elem) { + return elem['id'] == resp['id'] + }); + + var currentBuild = matchingBuilds.length > 0 ? matchingBuilds[0] : null; + if (currentBuild) { + currentBuild = $.extend(true, currentBuild, resp); + } else { + currentBuild = resp; + $scope.builds.push(currentBuild); + } + checkPollTimer(); // Load the updated logs for the build. From bcb993a91448c3ab9d989ea6bcacfa4369184a6e Mon Sep 17 00:00:00 2001 From: Jake Moshenko Date: Fri, 9 May 2014 18:45:11 -0400 Subject: [PATCH 4/5] Set up the build logs to use our fake build logs on test and local. --- app.py | 2 ++ config.py | 2 +- data/buildlogs.py | 31 ++++++++++++++++++++++++++++++- endpoints/api/build.py | 3 +-- test/testconfig.py | 5 +++-- test/testlogs.py | 4 ++-- util/dynamic.py | 7 +++++++ workers/dockerfilebuild.py | 4 +--- 8 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 util/dynamic.py diff --git a/app.py b/app.py index aa663418c..f1b029b55 100644 --- a/app.py +++ b/app.py @@ -13,6 +13,7 @@ from data.userfiles import Userfiles from util.analytics import Analytics from util.exceptionlog import Sentry from data.billing import Billing +from data.buildlogs import BuildLogs OVERRIDE_CONFIG_FILENAME = 'conf/stack/config.py' @@ -46,3 +47,4 @@ userfiles = Userfiles(app) analytics = Analytics(app) billing = Billing(app) sentry = Sentry(app) +build_logs = BuildLogs(app) diff --git a/config.py b/config.py index d5fc126cb..54650e566 100644 --- a/config.py +++ b/config.py @@ -73,7 +73,7 @@ class DefaultConfig(object): STORAGE_PATH = 'test/data/registry' # Build logs - BUILDLOGS = BuildLogs('logs.quay.io') # Change me + BUILDLOGS_OPTIONS = ['logs.quay.io'] # Real-time user events USER_EVENTS = UserEventBuilder('logs.quay.io') diff --git a/data/buildlogs.py b/data/buildlogs.py index 43723e211..033a6a043 100644 --- a/data/buildlogs.py +++ b/data/buildlogs.py @@ -1,10 +1,12 @@ import redis import json +from util.dynamic import import_class + class BuildStatusRetrievalError(Exception): pass -class BuildLogs(object): +class RedisBuildLogs(object): ERROR = 'error' COMMAND = 'command' PHASE = 'phase' @@ -70,3 +72,30 @@ class BuildLogs(object): raise BuildStatusRetrievalError('Cannot retrieve build status') return json.loads(fetched) if fetched else None + +class BuildLogs(object): + def __init__(self, app=None): + self.app = app + if app is not None: + self.state = self.init_app(app) + else: + self.state = None + + def init_app(self, app): + buildlogs_options = app.config.get('BUILDLOGS_OPTIONS', []) + buildlogs_import = app.config.get('BUILDLOGS_MODULE_AND_CLASS', None) + + if buildlogs_import is None: + klass = RedisBuildLogs + else: + klass = import_class(buildlogs_import[0], buildlogs_import[1]) + + buildlogs = klass(*buildlogs_options) + + # register extension with app + app.extensions = getattr(app, 'extensions', {}) + app.extensions['buildlogs'] = buildlogs + return buildlogs + + def __getattr__(self, name): + return getattr(self.state, name, None) \ No newline at end of file diff --git a/endpoints/api/build.py b/endpoints/api/build.py index c9bd2cf3a..0255f1c60 100644 --- a/endpoints/api/build.py +++ b/endpoints/api/build.py @@ -3,7 +3,7 @@ import json from flask import request -from app import app, userfiles as user_files +from app import app, userfiles as user_files, build_logs from endpoints.api import (RepositoryParamResource, parse_args, query_param, nickname, resource, require_repo_read, require_repo_write, validate_json_request, ApiResource, internal_only, format_date, api, Unauthorized, NotFound) @@ -17,7 +17,6 @@ from util.names import parse_robot_username logger = logging.getLogger(__name__) -build_logs = app.config['BUILDLOGS'] def get_trigger_config(trigger): diff --git a/test/testconfig.py b/test/testconfig.py index d012af469..e03c2328f 100644 --- a/test/testconfig.py +++ b/test/testconfig.py @@ -24,7 +24,8 @@ class TestConfig(DefaultConfig): STORAGE_TYPE = 'FakeStorage' - BUILDLOGS = TestBuildLogs('logs.quay.io', 'devtable', 'building', - 'deadbeef-dead-beef-dead-beefdeadbeef') + BUILDLOGS_MODULE_AND_CLASS = ('test.testlogs', 'testlogs.TestBuildLogs') + BUILDLOGS_OPTIONS = ['logs.quay.io', 'devtable', 'building', + 'deadbeef-dead-beef-dead-beefdeadbeef'] USERFILES_TYPE = 'FakeUserfiles' diff --git a/test/testlogs.py b/test/testlogs.py index b8e399dad..fa3c2bec2 100644 --- a/test/testlogs.py +++ b/test/testlogs.py @@ -5,7 +5,7 @@ from loremipsum import get_sentence from functools import wraps from copy import deepcopy -from data.buildlogs import BuildLogs +from data.buildlogs import RedisBuildLogs logger = logging.getLogger(__name__) @@ -32,7 +32,7 @@ def maybe_advance_script(is_get_status=False): return inner_advance -class TestBuildLogs(BuildLogs): +class TestBuildLogs(RedisBuildLogs): COMMAND_TYPES = ['FROM', 'MAINTAINER', 'RUN', 'CMD', 'EXPOSE', 'ENV', 'ADD', 'ENTRYPOINT', 'VOLUME', 'USER', 'WORKDIR'] STATUS_TEMPLATE = { diff --git a/util/dynamic.py b/util/dynamic.py new file mode 100644 index 000000000..975a4d930 --- /dev/null +++ b/util/dynamic.py @@ -0,0 +1,7 @@ +def import_class(module_name, class_name): + """ Import a class given the specified module name and class name. """ + klass = __import__(module_name) + class_segments = class_name.split('.') + for segment in class_segments: + klass = getattr(klass, segment) + return klass diff --git a/workers/dockerfilebuild.py b/workers/dockerfilebuild.py index b6a098fe5..66ee4a9b1 100644 --- a/workers/dockerfilebuild.py +++ b/workers/dockerfilebuild.py @@ -21,7 +21,7 @@ from collections import defaultdict from data.queue import dockerfile_build_queue from data import model from workers.worker import Worker, WorkerUnhealthyException, JobException -from app import app, userfiles as user_files +from app import app, userfiles as user_files, build_logs from util.safetar import safe_extractall from util.dockerfileparse import parse_dockerfile, ParsedDockerfile, serialize_dockerfile @@ -34,8 +34,6 @@ formatter = logging.Formatter(FORMAT) logger = logging.getLogger(__name__) -build_logs = app.config['BUILDLOGS'] - TIMEOUT_PERIOD_MINUTES = 20 CACHE_EXPIRATION_PERIOD_HOURS = 24 NO_TAGS = [':'] From 8327d9fdbf11373da689f53805c4dba443e0ec73 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Mon, 12 May 2014 19:03:42 -0400 Subject: [PATCH 5/5] Fix URLs of the generated build status badges --- static/js/controllers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/js/controllers.js b/static/js/controllers.js index d9684cbdc..555356993 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -1198,12 +1198,12 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams $scope.getBadgeFormat = function(format, repo) { if (!repo) { return; } - var imageUrl = Config.getUrl('/' + namespace + '/' + name + '/status'); + var imageUrl = Config.getUrl('/repository/' + namespace + '/' + name + '/status'); if (!$scope.repo.is_public) { imageUrl += '?token=' + $scope.repo.status_token; } - var linkUrl = Config.getUrl('/' + namespace + '/' + name); + var linkUrl = Config.getUrl('/repository/' + namespace + '/' + name); switch (format) { case 'svg':