Skip to content

Commit

Permalink
[redhat-3.7] Quota: Configuring Quota for user panel(PROJQUAY-3767) (#…
Browse files Browse the repository at this point in the history
…1353)

* Quota: Configuring Quota for user panel

* Added Quota Consumed column on Super users panel

Co-authored-by: Sunandadadi <sunanda.3094@gmail.com>
  • Loading branch information
openshift-cherrypick-robot and Sunandadadi committed Jun 1, 2022
1 parent c122741 commit abe1528
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 12 deletions.
20 changes: 20 additions & 0 deletions endpoints/api/superuser.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,26 @@ class SuperUserUserQuotaList(ApiResource):
},
}

@require_fresh_login
@verify_not_prod
@nickname(["listUserQuotaSuperUser", "listOrganizationQuotaSuperUser"])
@require_scope(scopes.SUPERUSER)
def get(self, namespace):
if SuperUserPermission().can():

try:
namespace_user = user.get_user_or_org(namespace)
except DataModelException as ex:
raise request_error(exception=ex)

if not namespace_user:
raise NotFound()

quotas = namespacequota.get_namespace_quota_list(namespace_user.username)
return [quota_view(quota) for quota in quotas]

raise Unauthorized()

@require_fresh_login
@verify_not_prod
@nickname(["createUserQuotaSuperUser", "createOrganizationQuotaSuperUser"])
Expand Down
4 changes: 4 additions & 0 deletions endpoints/api/test/test_security.py
Original file line number Diff line number Diff line change
Expand Up @@ -5819,6 +5819,10 @@
(UserQuotaLimitList, "GET", {"quota_id": 2}, None, "randomuser", 200),
(UserQuotaLimit, "GET", {"quota_id": 2, "limit_id": 2}, None, "devtable", 404),
(UserQuotaLimit, "GET", {"quota_id": 2, "limit_id": 2}, None, "randomuser", 200),
(SuperUserUserQuotaList, "GET", {"namespace": "nonexistant"}, None, None, 401),
(SuperUserUserQuotaList, "GET", {"namespace": "nonexistant"}, None, "devtable", 404),
(SuperUserUserQuotaList, "GET", {"namespace": "randomuser"}, None, "randomuser", 403),
(SuperUserUserQuotaList, "GET", {"namespace": "randomuser"}, None, "devtable", 200),
(SuperUserUserQuotaList, "POST", {"namespace": "randomuser"}, {"limit_bytes": 5000}, None, 401),
(SuperUserUserQuotaList, "POST", {"namespace": "randomuser"}, None, None, 401),
(
Expand Down
37 changes: 37 additions & 0 deletions static/directives/manage-users-tab.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
ng-if="Features.MAILING">
<a ng-click="orderBy('email')">E-mail address</a>
</td>
<td ng-class="tablePredicateClass('quota', options.predicate, options.reverse)"
ng-if="Features.QUOTA_MANAGEMENT">
<a ng-click="orderBy('quota')">Quota Consumed</a>
</td>
<td style="width: 24px;"></td>
</thead>

Expand All @@ -54,6 +58,19 @@
<td ng-if="Features.MAILING">
<a href="mailto:{{ current_user.email }}">{{ current_user.email }}</a>
</td>
<td ng-if="Features.QUOTA_MANAGEMENT">
<span ng-if="current_user.quota_report.quota_bytes">
{{
current_user.quota_report.percent_consumed ?
( bytesToHumanReadableString(current_user.quota_report.quota_bytes) + " (" + current_user.quota_report.percent_consumed + "%)") :
bytesToHumanReadableString(current_user.quota_report.quota_bytes)
}}
</span>
<span ng-if="current_user.quota_report.configured_quota && !current_user.quota_report.quota_bytes">0</span>
<span ng-if="current_user.quota_report.configured_quota">
{{ " of " + bytesToHumanReadableString(current_user.quota_report.configured_quota) }}
</span>
</td>
<td style="text-align: center;">
<span class="cor-options-menu"
ng-if="user.username != current_user.username && !current_user.super_user && !inReadOnlyMode">
Expand All @@ -80,6 +97,10 @@
ng-if="user.username != current_user.username && !current_user.super_user">
<i class="fa fa-bolt"></i> Take Ownership
</span>
<span class="cor-option" option-click="showQuotaConfig(current_user)"
quay-show="Features.QUOTA_MANAGEMENT">
<i class="fa fa-gear"></i> Configure Quota
</span>
</span>
</td>
</tr>
Expand Down Expand Up @@ -233,4 +254,20 @@ <h4 class="modal-title">Change User E-mail Address</h4>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->

<!-- Modal quota configuration -->
<div ng-repeat="current_user in orderedUsers.entries" class="org-row">
<div class="co-dialog modal fade" id="quotaConfigModal-{{ current_user.username }}">
<div class="modal-dialog">
<div class="modal-content padding-2percent">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Manage Organization Quota for {{ current_user.username }}</h4>
</div>
<quota-management-view organization="null" user="current_user" view="super-user"></quota-management-view>
</div>
</div>
</div>
</div>

</div>
32 changes: 32 additions & 0 deletions static/js/directives/ui/manage-user-tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,38 @@ angular.module('quay').directive('manageUserTab', function () {
'filter': null,
'page': 0
};
$scope.disk_size_units = {
'KB': 1024,
'MB': 1024**2,
'GB': 1024**3,
'TB': 1024**4,
};
$scope.quotaUnits = Object.keys($scope.disk_size_units);

$scope.showQuotaConfig = function (user) {
if (StateService.inReadOnlyMode()) {
return;
}

$('#quotaConfigModal-'+user.username).modal('show');
};

$scope.bytesToHumanReadableString = function(bytes) {
let units = Object.keys($scope.disk_size_units).reverse();
let result = null;
let byte_unit = null;

for (const key in units) {
byte_unit = units[key];
result = Math.round(bytes / $scope.disk_size_units[byte_unit]);
if (bytes >= $scope.disk_size_units[byte_unit]) {
return result.toString() + " " + byte_unit;
}
}

return result.toString() + " " + byte_unit;
};


$scope.showCreateUser = function () {
if (StateService.inReadOnlyMode()) {
Expand Down
54 changes: 42 additions & 12 deletions static/js/directives/ui/quota-management-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ angular.module('quay').directive('quotaManagementView', function () {
scope: {
'view': '@view',
'organization': '=organization',
'user': '=user',
},
controller: function ($scope, $timeout, $location, $element, ApiService, UserService,
TableService, Features, StateService, $q) {
Expand Down Expand Up @@ -52,9 +53,36 @@ angular.module('quay').directive('quotaManagementView', function () {
$scope.default_config_exists = false;
$scope.quota_limit_error = false;

let fetchSuperUSerNamespace = function () {
if ($scope.organization != null) {
return $scope.organization.name;
}
else {
return $scope.user.username
}
}

let fetchParams = function () {
if ($scope.organization != null) {
return {"orgname": $scope.organization.name};
}
else {
return {"namespace": $scope.user.username};
}
}

var loadOrgQuota = function () {
$scope.nameSpaceResource = ApiService.listOrganizationQuota(
null, {'orgname': $scope.organization.name}
let params = null;
let method = null;
if ($scope.organization != null){
method = ApiService.listOrganizationQuota;
} else {
method = ApiService.listUserQuotaSuperUser;
}
params = fetchParams();

$scope.nameSpaceResource = method(
null, params
).then((resp) => {
if (resp.length > 0) {
const quota = resp[0];
Expand Down Expand Up @@ -84,8 +112,11 @@ angular.module('quay').directive('quotaManagementView', function () {
$scope.prevquotaEnabled = true;
}

$scope.organization.quota_report.configured_quota = quota["limit_bytes"];
$scope.organization.quota_report.percent_consumed = (parseInt($scope.organization.quota_report.quota_bytes) / $scope.organization.quota_report.configured_quota * 100).toFixed(2);
if ($scope.organization != null) {
$scope.organization.quota_report.configured_quota = quota["limit_bytes"];
$scope.organization.quota_report.percent_consumed = (parseInt($scope.organization.quota_report.quota_bytes) / $scope.organization.quota_report.configured_quota * 100).toFixed(2);
}

}
populateDefaultQuotaLimits();
});
Expand Down Expand Up @@ -132,7 +163,7 @@ angular.module('quay').directive('quotaManagementView', function () {
if ($scope.view == "super-user") {
quotaMethod = ApiService.createOrganizationQuotaSuperUser;
} else {
quotaMethod = ApiService.createOrganizationQuota;
quotaMethod = ApiService.createNamespaceQuota;
}

}
Expand Down Expand Up @@ -184,17 +215,16 @@ angular.module('quay').directive('quotaManagementView', function () {
};

if ($scope.view == 'super-user') {
params['namespace'] = $scope.organization.name;
params['namespace'] = fetchSuperUSerNamespace();
} else {
params['orgname'] = $scope.organization.name;
}

updateOrganizationQuota(params);
}

$scope.addQuotaLimit = function () {
var params = {
'orgname': $scope.organization.name,
'orgname': fetchSuperUSerNamespace(),
'quota_id': $scope.currentQuotaConfig.id,
};

Expand All @@ -216,7 +246,7 @@ angular.module('quay').directive('quotaManagementView', function () {

$scope.updateQuotaLimit = function (limitId) {
var params = {
'orgname': $scope.organization.name,
'orgname': fetchSuperUSerNamespace(),
'quota_id': $scope.currentQuotaConfig.id,
'limit_id': limitId,
};
Expand All @@ -237,7 +267,7 @@ angular.module('quay').directive('quotaManagementView', function () {

$scope.deleteQuotaLimit = function (limitId) {
const params = {
'orgname': $scope.organization.name,
'orgname': fetchSuperUSerNamespace(),
'quota_id': $scope.currentQuotaConfig.id,
'limit_id': limitId,
}
Expand Down Expand Up @@ -465,7 +495,7 @@ angular.module('quay').directive('quotaManagementView', function () {
bootbox.confirm('Are you sure you want to delete quota for this organization? ' + alert_msg,
function(result) {
if (!result) {
return;
return;loadOrgQuota
}

let handleSuccess = function() {
Expand All @@ -483,7 +513,7 @@ angular.module('quay').directive('quotaManagementView', function () {

if ($scope.view == "super-user") {
quotaMethod = ApiService.deleteOrganizationQuotaSuperUser;
params["namespace"] = $scope.organization.name;
params["namespace"] = fetchSuperUSerNamespace();
}
else {
quotaMethod = ApiService.deleteOrganizationQuota;
Expand Down

0 comments on commit abe1528

Please sign in to comment.