Add a basic usage counter for enterprise
This commit is contained in:
parent
93cd7de0e0
commit
109850b428
8 changed files with 109 additions and 29 deletions
|
@ -2210,6 +2210,14 @@ def confirm_team_invite(code, user):
|
||||||
found.delete_instance()
|
found.delete_instance()
|
||||||
return (team, inviter)
|
return (team, inviter)
|
||||||
|
|
||||||
|
|
||||||
|
def get_repository_usage():
|
||||||
|
repo_pull = LogEntryKind.get(name = 'pull_repo')
|
||||||
|
return (LogEntry.select().where(LogEntry.kind == repo_pull, ~(LogEntry.repository >> None))
|
||||||
|
.group_by(LogEntry.ip)
|
||||||
|
.group_by(LogEntry.repository)
|
||||||
|
.count())
|
||||||
|
|
||||||
def archivable_buildlogs_query():
|
def archivable_buildlogs_query():
|
||||||
presumed_dead_date = datetime.utcnow() - PRESUMED_DEAD_BUILD_AGE
|
presumed_dead_date = datetime.utcnow() - PRESUMED_DEAD_BUILD_AGE
|
||||||
return (RepositoryBuild.select()
|
return (RepositoryBuild.select()
|
||||||
|
|
|
@ -52,6 +52,25 @@ def user_view(user):
|
||||||
'super_user': user.username in app.config['SUPER_USERS']
|
'super_user': user.username in app.config['SUPER_USERS']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@resource('/v1/superuser/usage/')
|
||||||
|
@internal_only
|
||||||
|
@show_if(features.SUPER_USERS)
|
||||||
|
class UsageInformation(ApiResource):
|
||||||
|
""" Resource for returning the usage information for enterprise customers. """
|
||||||
|
@require_fresh_login
|
||||||
|
@nickname('getSystemUsage')
|
||||||
|
def get(self):
|
||||||
|
""" Returns the number of repository handles currently held. """
|
||||||
|
if SuperUserPermission().can():
|
||||||
|
return {
|
||||||
|
'usage': model.get_repository_usage(),
|
||||||
|
'allowed': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
abort(403)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@resource('/v1/superuser/users/')
|
@resource('/v1/superuser/users/')
|
||||||
@internal_only
|
@internal_only
|
||||||
@show_if(features.SUPER_USERS)
|
@show_if(features.SUPER_USERS)
|
||||||
|
|
|
@ -3131,38 +3131,38 @@ p.editable:hover i {
|
||||||
stroke-width: 1.5px;
|
stroke-width: 1.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-chart {
|
.usage-chart-element {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-chart .count-text {
|
.usage-chart-element .count-text {
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-chart.limit-at path.arc-0 {
|
.usage-chart-element.limit-at path.arc-0 {
|
||||||
fill: #c09853;
|
fill: #c09853;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-chart.limit-over path.arc-0 {
|
.usage-chart-element.limit-over path.arc-0 {
|
||||||
fill: #b94a48;
|
fill: #b94a48;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-chart.limit-near path.arc-0 {
|
.usage-chart-element.limit-near path.arc-0 {
|
||||||
fill: #468847;
|
fill: #468847;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-chart.limit-over path.arc-1 {
|
.usage-chart-element.limit-over path.arc-1 {
|
||||||
fill: #fcf8e3;
|
fill: #fcf8e3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-chart.limit-at path.arc-1 {
|
.usage-chart-element.limit-at path.arc-1 {
|
||||||
fill: #f2dede;
|
fill: #f2dede;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-chart.limit-near path.arc-1 {
|
.usage-chart-element.limit-near path.arc-1 {
|
||||||
fill: #dff0d8;
|
fill: #dff0d8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Chart -->
|
<!-- Chart -->
|
||||||
<div>
|
<div class="usage-chart" total="subscribedPlan.privateRepos || 0"
|
||||||
<div id="repository-usage-chart" class="usage-chart limit-{{limit}}"></div>
|
current="subscription.usedPrivateRepos || 0"
|
||||||
<span class="usage-caption" ng-show="chart">Repository Usage</span>
|
limit="limit"
|
||||||
</div>
|
usage-title="Repository Usage"
|
||||||
|
ng-show="!planLoading"></div>
|
||||||
|
|
||||||
<!-- Plans Table -->
|
<!-- Plans Table -->
|
||||||
<table class="table table-hover plans-list-table" ng-show="!planLoading">
|
<table class="table table-hover plans-list-table" ng-show="!planLoading">
|
||||||
|
|
2
static/directives/usage-chart.html
Normal file
2
static/directives/usage-chart.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<span id="usage-chart-element" class="usage-chart-element" ng-class="'limit-' + limit" ng-show="total != null"></span>
|
||||||
|
<span class="usage-caption" ng-show="total != null && usageTitle">{{ usageTitle }}</span>
|
|
@ -4540,23 +4540,6 @@ quayApp.directive('planManager', function () {
|
||||||
$scope.planChanged({ 'plan': subscribedPlan });
|
$scope.planChanged({ 'plan': subscribedPlan });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sub.usedPrivateRepos > $scope.subscribedPlan.privateRepos) {
|
|
||||||
$scope.limit = 'over';
|
|
||||||
} else if (sub.usedPrivateRepos == $scope.subscribedPlan.privateRepos) {
|
|
||||||
$scope.limit = 'at';
|
|
||||||
} else if (sub.usedPrivateRepos >= $scope.subscribedPlan.privateRepos * 0.7) {
|
|
||||||
$scope.limit = 'near';
|
|
||||||
} else {
|
|
||||||
$scope.limit = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$scope.chart) {
|
|
||||||
$scope.chart = new UsageChart();
|
|
||||||
$scope.chart.draw('repository-usage-chart');
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.chart.update(sub.usedPrivateRepos || 0, $scope.subscribedPlan.privateRepos || 0);
|
|
||||||
|
|
||||||
$scope.planChanging = false;
|
$scope.planChanging = false;
|
||||||
$scope.planLoading = false;
|
$scope.planLoading = false;
|
||||||
});
|
});
|
||||||
|
@ -5929,6 +5912,54 @@ quayApp.directive('notificationsBubble', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
quayApp.directive('usageChart', function () {
|
||||||
|
var directiveDefinitionObject = {
|
||||||
|
priority: 0,
|
||||||
|
templateUrl: '/static/directives/usage-chart.html',
|
||||||
|
replace: false,
|
||||||
|
transclude: false,
|
||||||
|
restrict: 'C',
|
||||||
|
scope: {
|
||||||
|
'current': '=current',
|
||||||
|
'total': '=total',
|
||||||
|
'limit': '=limit',
|
||||||
|
'usageTitle': '@usageTitle'
|
||||||
|
},
|
||||||
|
controller: function($scope, $element) {
|
||||||
|
$scope.limit = "";
|
||||||
|
|
||||||
|
var chart = null;
|
||||||
|
|
||||||
|
var update = function() {
|
||||||
|
if ($scope.current == null || $scope.total == null) { return; }
|
||||||
|
if (!chart) {
|
||||||
|
chart = new UsageChart();
|
||||||
|
chart.draw('usage-chart-element');
|
||||||
|
}
|
||||||
|
|
||||||
|
var current = $scope.current || 0;
|
||||||
|
var total = $scope.total || 0;
|
||||||
|
if (current > total) {
|
||||||
|
$scope.limit = 'over';
|
||||||
|
} else if (current == total) {
|
||||||
|
$scope.limit = 'at';
|
||||||
|
} else if (current >= total * 0.7) {
|
||||||
|
$scope.limit = 'near';
|
||||||
|
} else {
|
||||||
|
$scope.limit = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.update($scope.current, $scope.total);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$watch('current', update);
|
||||||
|
$scope.$watch('total', update);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return directiveDefinitionObject;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
quayApp.directive('notificationView', function () {
|
quayApp.directive('notificationView', function () {
|
||||||
var directiveDefinitionObject = {
|
var directiveDefinitionObject = {
|
||||||
priority: 0,
|
priority: 0,
|
||||||
|
|
|
@ -2788,6 +2788,15 @@ function SuperUserAdminCtrl($scope, ApiService, Features, UserService) {
|
||||||
$scope.logsCounter = 0;
|
$scope.logsCounter = 0;
|
||||||
$scope.newUser = {};
|
$scope.newUser = {};
|
||||||
$scope.createdUsers = [];
|
$scope.createdUsers = [];
|
||||||
|
$scope.systemUsage = null;
|
||||||
|
|
||||||
|
$scope.getUsage = function() {
|
||||||
|
if ($scope.systemUsage) { return; }
|
||||||
|
|
||||||
|
ApiService.getSystemUsage().then(function(resp) {
|
||||||
|
$scope.systemUsage = resp;
|
||||||
|
}, ApiService.errorDisplay('Cannot load system usage. Please contact support.'))
|
||||||
|
}
|
||||||
|
|
||||||
$scope.loadLogs = function() {
|
$scope.loadLogs = function() {
|
||||||
$scope.logsCounter++;
|
$scope.logsCounter++;
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:void(0)" data-toggle="tab" data-target="#create-user">Create User</a>
|
<a href="javascript:void(0)" data-toggle="tab" data-target="#create-user">Create User</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="javascript:void(0)" data-toggle="tab" data-target="#usage-counter" ng-click="getUsage()">System Usage</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:void(0)" data-toggle="tab" data-target="#logs" ng-click="loadLogs()">System Logs</a>
|
<a href="javascript:void(0)" data-toggle="tab" data-target="#logs" ng-click="loadLogs()">System Logs</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -27,6 +30,13 @@
|
||||||
<div class="logsView" makevisible="logsCounter" all-logs="true"></div>
|
<div class="logsView" makevisible="logsCounter" all-logs="true"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Usage tab -->
|
||||||
|
<div id="usage-counter" class="tab-pane">
|
||||||
|
<div class="quay-spinner" ng-show="systemUsage == null"></div>
|
||||||
|
<div class="usage-chart" total="systemUsage.allowed" limit="systemUsageLimit"
|
||||||
|
current="systemUsage.usage" usage-title="Container Usage"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Create user tab -->
|
<!-- Create user tab -->
|
||||||
<div id="create-user" class="tab-pane">
|
<div id="create-user" class="tab-pane">
|
||||||
<span class="quay-spinner" ng-show="creatingUser"></span>
|
<span class="quay-spinner" ng-show="creatingUser"></span>
|
||||||
|
|
Reference in a new issue