Merge remote-tracking branch 'origin/master' into ldapper
Conflicts: app.py
This commit is contained in:
commit
11c6c5fa52
10 changed files with 75 additions and 23 deletions
2
app.py
2
app.py
|
@ -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)
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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)
|
|
@ -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):
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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'
|
||||||
|
|
||||||
|
|
|
@ -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
7
util/dynamic.py
Normal 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
|
|
@ -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>']
|
||||||
|
|
Reference in a new issue