Add create action for quotas
This patch adds create action for quotas panel in Admin dashboard. Change-Id: I71e042ddcd9fd68ed03bf189b61d8b43aac16933 Partial-Implements: blueprint add-quotas-panel
This commit is contained in:
parent
dd70cba6dd
commit
cb7518790f
@ -264,8 +264,8 @@ class Quotas(generic.View):
|
||||
"""
|
||||
created = magnum.quotas_create(request, **request.DATA)
|
||||
return rest_utils.CreatedResponse(
|
||||
('/api/container_infra/quotas/%s/%s' % created.id,
|
||||
created.resource),
|
||||
('/api/container_infra/quotas/%s/%s' % (
|
||||
created.project_id, created.resource)),
|
||||
created.to_dict())
|
||||
|
||||
|
||||
|
@ -205,8 +205,8 @@
|
||||
});
|
||||
}
|
||||
|
||||
function createQuota(projectId, resource, params) {
|
||||
return apiService.post('/api/container_infra/quotas/' + projectId + '/' + resource, params)
|
||||
function createQuota(params) {
|
||||
return apiService.post('/api/container_infra/quotas/', params)
|
||||
.error(function() {
|
||||
toastService.add('error', gettext('Unable to create quota.'));
|
||||
});
|
||||
|
@ -176,20 +176,18 @@
|
||||
{
|
||||
"func": "createQuota",
|
||||
"method": "post",
|
||||
"path": "/api/container_infra/quotas/123/Cluster",
|
||||
"path": "/api/container_infra/quotas/",
|
||||
"data": {
|
||||
"project_id": "123",
|
||||
"resource": "Cluster",
|
||||
"hard_limit": "1"
|
||||
"hard_limit": 1
|
||||
},
|
||||
"error": "Unable to create quota.",
|
||||
"testInput": [
|
||||
"123",
|
||||
"Cluster",
|
||||
{
|
||||
"project_id": "123",
|
||||
"resource": "Cluster",
|
||||
"hard_limit": "1"
|
||||
"hard_limit": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @ngname horizon.dashboard.container-infra.quotas.actions
|
||||
*
|
||||
* @description
|
||||
* Provides all of the actions for quotas.
|
||||
*/
|
||||
angular.module('horizon.dashboard.container-infra.quotas.actions',
|
||||
[
|
||||
'horizon.framework',
|
||||
'horizon.dashboard.container-infra'
|
||||
])
|
||||
.run(registerQuotaActions);
|
||||
|
||||
registerQuotaActions.$inject = [
|
||||
'horizon.framework.conf.resource-type-registry.service',
|
||||
'horizon.framework.util.i18n.gettext',
|
||||
'horizon.dashboard.container-infra.quotas.create.service',
|
||||
'horizon.dashboard.container-infra.quotas.resourceType'
|
||||
];
|
||||
|
||||
function registerQuotaActions (
|
||||
registry,
|
||||
gettext,
|
||||
createQuotaService,
|
||||
resourceType) {
|
||||
|
||||
var quotaResourceType = registry.getResourceType(resourceType);
|
||||
quotaResourceType.globalActions
|
||||
.append({
|
||||
id: 'createQuotaAction',
|
||||
service: createQuotaService,
|
||||
template: {
|
||||
type: 'create',
|
||||
text: gettext('Create Quota')
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
describe('register quota actions module', function() {
|
||||
var registry;
|
||||
beforeEach(module('horizon.dashboard.container-infra.quotas.actions'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
registry = $injector.get('horizon.framework.conf.resource-type-registry.service');
|
||||
}));
|
||||
|
||||
it('registers Create Quota as a batch action', function() {
|
||||
var actions = registry.getResourceType('OS::Magnum::Quota').globalActions;
|
||||
expect(actionHasId(actions, 'createQuotaAction')).toBe(true);
|
||||
});
|
||||
|
||||
function actionHasId(list, value) {
|
||||
return list.filter(matchesId).length === 1;
|
||||
|
||||
function matchesId(action) {
|
||||
if (action.id === value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name horizon.dashboard.container-infra.quotas.create.service
|
||||
* @description Service for the container-infra quota create modal
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.container-infra.quotas')
|
||||
.factory('horizon.dashboard.container-infra.quotas.create.service', createService);
|
||||
|
||||
createService.$inject = [
|
||||
'$location',
|
||||
'horizon.app.core.openstack-service-api.magnum',
|
||||
'horizon.app.core.openstack-service-api.policy',
|
||||
'horizon.framework.util.actions.action-result.service',
|
||||
'horizon.framework.util.i18n.gettext',
|
||||
'horizon.framework.util.q.extensions',
|
||||
'horizon.framework.widgets.form.ModalFormService',
|
||||
'horizon.framework.widgets.toast.service',
|
||||
'horizon.dashboard.container-infra.quotas.resourceType',
|
||||
'horizon.dashboard.container-infra.quotas.workflow'
|
||||
];
|
||||
|
||||
function createService(
|
||||
$location, magnum, policy, actionResult, gettext, $qExtensions, modal, toast,
|
||||
resourceType, workflow
|
||||
) {
|
||||
|
||||
var config;
|
||||
var message = {
|
||||
success: gettext('Quota %s was successfully created.')
|
||||
};
|
||||
|
||||
var service = {
|
||||
perform: perform,
|
||||
allowed: allowed
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
//////////////
|
||||
|
||||
function perform(selected, $scope) {
|
||||
config = workflow.init('create', gettext('Create'), $scope);
|
||||
if (typeof selected !== 'undefined') {
|
||||
config.model.id = selected.id;
|
||||
}
|
||||
return modal.open(config).then(submit);
|
||||
}
|
||||
|
||||
function allowed() {
|
||||
return $qExtensions.booleanAsPromise(true);
|
||||
}
|
||||
|
||||
function submit(context) {
|
||||
context.model = cleanNullProperties(context.model);
|
||||
return magnum.createQuota(context.model).then(success, true);
|
||||
}
|
||||
|
||||
function cleanNullProperties(model) {
|
||||
// Initially clean fields that don't have any value.
|
||||
// Not only "null", blank too.
|
||||
for (var key in model) {
|
||||
if (model.hasOwnProperty(key) && model[key] === null || model[key] === "") {
|
||||
delete model[key];
|
||||
}
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
function success(response) {
|
||||
response.data.id = response.data.uuid;
|
||||
toast.add('success', interpolate(message.success, [response.data.id]));
|
||||
var result = actionResult.getActionResult()
|
||||
.created(resourceType, response.data.id);
|
||||
return result.result;
|
||||
}
|
||||
}
|
||||
})();
|
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
describe('horizon.dashboard.container-infra.quotas.create.service', function() {
|
||||
|
||||
var service, $scope, $q, deferred, magnum, workflow;
|
||||
var model = {
|
||||
id: 1
|
||||
};
|
||||
var modal = {
|
||||
open: function(config) {
|
||||
config.model = model;
|
||||
deferred = $q.defer();
|
||||
deferred.resolve(config);
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////
|
||||
|
||||
beforeEach(module('horizon.app.core'));
|
||||
beforeEach(module('horizon.framework'));
|
||||
beforeEach(module('horizon.dashboard.container-infra.quotas'));
|
||||
|
||||
beforeEach(module(function($provide) {
|
||||
$provide.value('horizon.framework.widgets.form.ModalFormService', modal);
|
||||
}));
|
||||
|
||||
beforeEach(inject(function($injector, _$rootScope_, _$q_) {
|
||||
$q = _$q_;
|
||||
$scope = _$rootScope_.$new();
|
||||
service = $injector.get('horizon.dashboard.container-infra.quotas.create.service');
|
||||
magnum = $injector.get('horizon.app.core.openstack-service-api.magnum');
|
||||
workflow = $injector.get('horizon.dashboard.container-infra.quotas.workflow');
|
||||
deferred = $q.defer();
|
||||
deferred.resolve({data: {id: 1}});
|
||||
spyOn(magnum, 'createQuota').and.returnValue(deferred.promise);
|
||||
spyOn(modal, 'open').and.callThrough();
|
||||
spyOn(workflow, 'init').and.returnValue({model: model});
|
||||
}));
|
||||
|
||||
it('should check the policy if the user is allowed to create quota', function() {
|
||||
var allowed = service.allowed();
|
||||
expect(allowed).toBeTruthy();
|
||||
});
|
||||
|
||||
it('open the modal', inject(function($timeout) {
|
||||
service.perform(model, $scope);
|
||||
|
||||
expect(modal.open).toHaveBeenCalled();
|
||||
|
||||
$timeout.flush();
|
||||
$scope.$apply();
|
||||
|
||||
expect(magnum.createQuota).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
})();
|
@ -25,7 +25,8 @@
|
||||
angular
|
||||
.module('horizon.dashboard.container-infra.quotas',
|
||||
[
|
||||
'ngRoute'
|
||||
'ngRoute',
|
||||
'horizon.dashboard.container-infra.quotas.actions'
|
||||
])
|
||||
.constant('horizon.dashboard.container-infra.quotas.events', events())
|
||||
.constant(
|
||||
|
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('horizon.dashboard.container-infra.quotas')
|
||||
.factory(
|
||||
'horizon.dashboard.container-infra.quotas.workflow',
|
||||
QuotaWorkflow);
|
||||
|
||||
QuotaWorkflow.$inject = [
|
||||
'horizon.dashboard.container-infra.basePath',
|
||||
'horizon.app.core.workflow.factory',
|
||||
'horizon.framework.util.i18n.gettext',
|
||||
'horizon.app.core.openstack-service-api.keystone'
|
||||
];
|
||||
|
||||
function QuotaWorkflow(basePath, workflowService, gettext, keystone) {
|
||||
var workflow = {
|
||||
init: init
|
||||
};
|
||||
|
||||
function init(action, title, $scope) {
|
||||
var schema, form, model;
|
||||
var projects = [{value:"", name: gettext("Choose a Project")}];
|
||||
var resources = [{value:"Cluster", name: gettext("Cluster")}];
|
||||
|
||||
// schema
|
||||
schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'project_id': {
|
||||
title: gettext('Project'),
|
||||
type: 'string'
|
||||
},
|
||||
'resource': {
|
||||
title: gettext('Resource'),
|
||||
type: 'string'
|
||||
},
|
||||
'hard_limit': {
|
||||
title: gettext('Hard Limit'),
|
||||
type: 'number',
|
||||
minimum: 1
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// form
|
||||
form = [
|
||||
{
|
||||
type: 'section',
|
||||
htmlClass: 'row',
|
||||
items: [
|
||||
{
|
||||
type: 'section',
|
||||
htmlClass: 'col-xs-12',
|
||||
items: [
|
||||
{
|
||||
key: 'project_id',
|
||||
type: 'select',
|
||||
titleMap: projects,
|
||||
required: true,
|
||||
readonly: action === 'update'
|
||||
},
|
||||
{
|
||||
key: 'resource',
|
||||
type: 'select',
|
||||
titleMap: resources,
|
||||
required: true,
|
||||
readonly: action === 'update'
|
||||
},
|
||||
{
|
||||
key: 'hard_limit',
|
||||
placeholder: gettext('Limit for this resource.'),
|
||||
required: true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
keystone.getProjects().then(onGetProjects);
|
||||
|
||||
function onGetProjects(response) {
|
||||
angular.forEach(response.data.items, function(item) {
|
||||
projects.push({value: item.id, name: item.name});
|
||||
});
|
||||
form[0].items[0].items[0].titleMap = projects;
|
||||
}
|
||||
|
||||
model = {
|
||||
id: "",
|
||||
project_id: "",
|
||||
resource: "Cluster",
|
||||
hard_limit: null
|
||||
};
|
||||
|
||||
var config = {
|
||||
title: title,
|
||||
schema: schema,
|
||||
form: form,
|
||||
model: model
|
||||
};
|
||||
|
||||
$scope.model = model;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
return workflow;
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
describe('horizon.dashboard.container-infra.quotas.workflow', function() {
|
||||
|
||||
var workflow, $scope, $q, keystone, deferred;
|
||||
|
||||
beforeEach(module('horizon.app.core'));
|
||||
beforeEach(module('horizon.framework'));
|
||||
beforeEach(module('horizon.dashboard.container-infra.quotas'));
|
||||
|
||||
beforeEach(inject(function($injector, _$rootScope_, _$q_) {
|
||||
$q = _$q_;
|
||||
$scope = _$rootScope_.$new();
|
||||
workflow = $injector.get('horizon.dashboard.container-infra.quotas.workflow');
|
||||
keystone = $injector.get('horizon.app.core.openstack-service-api.keystone');
|
||||
deferred = $q.defer();
|
||||
deferred.resolve({data:{items:{1:{name:1},2:{name:2}}}});
|
||||
spyOn(keystone, 'getProjects').and.returnValue(deferred.promise);
|
||||
}));
|
||||
|
||||
it('should be init', inject(function($timeout) {
|
||||
var config = workflow.init('create', 'Create Quota', $scope);
|
||||
$timeout.flush();
|
||||
expect(config.title).toBeDefined();
|
||||
expect(config.schema).toBeDefined();
|
||||
expect(config.form).toBeDefined();
|
||||
expect(config.model).toBeDefined();
|
||||
}));
|
||||
});
|
||||
})();
|
Loading…
x
Reference in New Issue
Block a user