Merge remote-tracking branch 'origin/master' into ldapper

Conflicts:
	app.py
This commit is contained in:
Jake Moshenko 2014-05-13 16:55:02 -04:00
commit 11c6c5fa52
10 changed files with 75 additions and 23 deletions

2
app.py
View file

@ -16,6 +16,7 @@ from data.users import UserAuthentication
from util.analytics import Analytics from util.analytics import Analytics
from util.exceptionlog import Sentry from util.exceptionlog import Sentry
from data.billing import Billing from data.billing import Billing
from data.buildlogs import BuildLogs
OVERRIDE_CONFIG_FILENAME = 'conf/stack/config.py' OVERRIDE_CONFIG_FILENAME = 'conf/stack/config.py'
@ -49,6 +50,7 @@ userfiles = Userfiles(app)
analytics = Analytics(app) analytics = Analytics(app)
billing = Billing(app) billing = Billing(app)
sentry = Sentry(app) sentry = Sentry(app)
build_logs = BuildLogs(app)
authentication = UserAuthentication(app) authentication = UserAuthentication(app)
database.configure(app.config) database.configure(app.config)

View file

@ -80,7 +80,7 @@ class DefaultConfig(object):
AUTHENTICATION_TYPE = 'Database' AUTHENTICATION_TYPE = 'Database'
# Build logs # Build logs
BUILDLOGS = BuildLogs('logs.quay.io') # Change me BUILDLOGS_OPTIONS = ['logs.quay.io']
# Real-time user events # Real-time user events
USER_EVENTS = UserEventBuilder('logs.quay.io') USER_EVENTS = UserEventBuilder('logs.quay.io')

View file

@ -1,10 +1,12 @@
import redis import redis
import json import json
from util.dynamic import import_class
class BuildStatusRetrievalError(Exception): class BuildStatusRetrievalError(Exception):
pass pass
class BuildLogs(object): class RedisBuildLogs(object):
ERROR = 'error' ERROR = 'error'
COMMAND = 'command' COMMAND = 'command'
PHASE = 'phase' PHASE = 'phase'
@ -70,3 +72,30 @@ class BuildLogs(object):
raise BuildStatusRetrievalError('Cannot retrieve build status') raise BuildStatusRetrievalError('Cannot retrieve build status')
return json.loads(fetched) if fetched else None 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)

View file

@ -3,7 +3,7 @@ import json
from flask import request 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, from endpoints.api import (RepositoryParamResource, parse_args, query_param, nickname, resource,
require_repo_read, require_repo_write, validate_json_request, require_repo_read, require_repo_write, validate_json_request,
ApiResource, internal_only, format_date, api, Unauthorized, NotFound) ApiResource, internal_only, format_date, api, Unauthorized, NotFound)
@ -17,7 +17,6 @@ from util.names import parse_robot_username
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
build_logs = app.config['BUILDLOGS']
def get_trigger_config(trigger): def get_trigger_config(trigger):

View file

@ -84,7 +84,7 @@ function createOrganizationTeam(ApiService, orgname, teamname, callback) {
'teamname': teamname 'teamname': teamname
}; };
ApiService.updateOrganizationTeam(data, params).then(callback, function() { ApiService.updateOrganizationTeam(data, params).then(callback, function(resp) {
bootbox.dialog({ bootbox.dialog({
"message": resp.data ? resp.data : 'The team could not be created', "message": resp.data ? resp.data : 'The team could not be created',
"title": "Cannot create team", "title": "Cannot create team",

View file

@ -4,11 +4,16 @@ $.fn.clipboardCopy = function() {
clip.on('complete', function() { clip.on('complete', function() {
// Resets the animation. // Resets the animation.
var elem = $('#clipboardCopied')[0]; var elem = $('#clipboardCopied')[0];
if (!elem) {
return;
}
elem.style.display = 'none'; elem.style.display = 'none';
elem.classList.remove('animated'); elem.classList.remove('animated');
// Show the notification. // Show the notification.
setTimeout(function() { setTimeout(function() {
if (!elem) { return; }
elem.style.display = 'inline-block'; elem.style.display = 'inline-block';
elem.classList.add('animated'); elem.classList.add('animated');
}, 10); }, 10);
@ -1016,7 +1021,6 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
$scope.currentParentEntry = null; $scope.currentParentEntry = null;
$scope.currentBuild = build; $scope.currentBuild = build;
$scope.currentBuildIndex = index;
if (opt_updateURL) { if (opt_updateURL) {
if (build) { if (build) {
@ -1094,8 +1098,18 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
ApiService.getRepoBuildStatus(null, params, true).then(function(resp) { ApiService.getRepoBuildStatus(null, params, true).then(function(resp) {
// Note: We use extend here rather than replacing as Angular is depending on the // Note: We use extend here rather than replacing as Angular is depending on the
// root build object to remain the same object. // root build object to remain the same object.
$.extend(true, $scope.builds[$scope.currentBuildIndex], resp); var matchingBuilds = $.grep($scope.builds, function(elem) {
var currentBuild = $scope.builds[$scope.currentBuildIndex]; 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(); checkPollTimer();
// Load the updated logs for the build. // Load the updated logs for the build.
@ -1184,12 +1198,12 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
$scope.getBadgeFormat = function(format, repo) { $scope.getBadgeFormat = function(format, repo) {
if (!repo) { return; } if (!repo) { return; }
var imageUrl = Config.getUrl('/' + namespace + '/' + name + '/status'); var imageUrl = Config.getUrl('/repository/' + namespace + '/' + name + '/status');
if (!$scope.repo.is_public) { if (!$scope.repo.is_public) {
imageUrl += '?token=' + $scope.repo.status_token; imageUrl += '?token=' + $scope.repo.status_token;
} }
var linkUrl = Config.getUrl('/' + namespace + '/' + name); var linkUrl = Config.getUrl('/repository/' + namespace + '/' + name);
switch (format) { switch (format) {
case 'svg': case 'svg':
@ -1587,6 +1601,7 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
$scope.cuser = jQuery.extend({}, user); $scope.cuser = jQuery.extend({}, user);
if ($scope.cuser.logins) {
for (var i = 0; i < $scope.cuser.logins.length; i++) { for (var i = 0; i < $scope.cuser.logins.length; i++) {
if ($scope.cuser.logins[i].service == 'github') { if ($scope.cuser.logins[i].service == 'github') {
var githubId = $scope.cuser.logins[i].service_identifier; var githubId = $scope.cuser.logins[i].service_identifier;
@ -1595,6 +1610,7 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
}); });
} }
} }
}
}); });
$scope.readyForPlan = function() { $scope.readyForPlan = function() {

View file

@ -24,8 +24,9 @@ class TestConfig(DefaultConfig):
STORAGE_TYPE = 'FakeStorage' STORAGE_TYPE = 'FakeStorage'
BUILDLOGS = TestBuildLogs('logs.quay.io', 'devtable', 'building', BUILDLOGS_MODULE_AND_CLASS = ('test.testlogs', 'testlogs.TestBuildLogs')
'deadbeef-dead-beef-dead-beefdeadbeef') BUILDLOGS_OPTIONS = ['logs.quay.io', 'devtable', 'building',
'deadbeef-dead-beef-dead-beefdeadbeef']
USERFILES_TYPE = 'FakeUserfiles' USERFILES_TYPE = 'FakeUserfiles'

View file

@ -5,7 +5,7 @@ from loremipsum import get_sentence
from functools import wraps from functools import wraps
from copy import deepcopy from copy import deepcopy
from data.buildlogs import BuildLogs from data.buildlogs import RedisBuildLogs
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -32,7 +32,7 @@ def maybe_advance_script(is_get_status=False):
return inner_advance return inner_advance
class TestBuildLogs(BuildLogs): class TestBuildLogs(RedisBuildLogs):
COMMAND_TYPES = ['FROM', 'MAINTAINER', 'RUN', 'CMD', 'EXPOSE', 'ENV', 'ADD', COMMAND_TYPES = ['FROM', 'MAINTAINER', 'RUN', 'CMD', 'EXPOSE', 'ENV', 'ADD',
'ENTRYPOINT', 'VOLUME', 'USER', 'WORKDIR'] 'ENTRYPOINT', 'VOLUME', 'USER', 'WORKDIR']
STATUS_TEMPLATE = { STATUS_TEMPLATE = {

7
util/dynamic.py Normal file
View file

@ -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

View file

@ -21,7 +21,7 @@ from collections import defaultdict
from data.queue import dockerfile_build_queue from data.queue import dockerfile_build_queue
from data import model from data import model
from workers.worker import Worker, WorkerUnhealthyException, JobException 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.safetar import safe_extractall
from util.dockerfileparse import parse_dockerfile, ParsedDockerfile, serialize_dockerfile from util.dockerfileparse import parse_dockerfile, ParsedDockerfile, serialize_dockerfile
@ -34,8 +34,6 @@ formatter = logging.Formatter(FORMAT)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
build_logs = app.config['BUILDLOGS']
TIMEOUT_PERIOD_MINUTES = 20 TIMEOUT_PERIOD_MINUTES = 20
CACHE_EXPIRATION_PERIOD_HOURS = 24 CACHE_EXPIRATION_PERIOD_HOURS = 24
NO_TAGS = ['<none>:<none>'] NO_TAGS = ['<none>:<none>']