Add angular delete server groups action
This patch adds delete actions for angular server groups panel. Change-Id: I9cd887fb315a5523c44c48d284cdea3a6673b3b2 Partial-Implements: blueprint ng-server-groups
This commit is contained in:
parent
df857f00b5
commit
37647dd318
@ -938,6 +938,11 @@ def server_group_create(request, **kwargs):
|
||||
**kwargs)
|
||||
|
||||
|
||||
@profiler.trace
|
||||
def server_group_delete(request, servergroup_id):
|
||||
novaclient(request).server_groups.delete(servergroup_id)
|
||||
|
||||
|
||||
@profiler.trace
|
||||
def service_list(request, binary=None):
|
||||
return novaclient(request).services.list(binary=binary)
|
||||
|
@ -448,6 +448,19 @@ class ServerGroups(generic.View):
|
||||
)
|
||||
|
||||
|
||||
@urls.register
|
||||
class ServerGroup(generic.View):
|
||||
url_regex = r'nova/servergroups/(?P<servergroup_id>[^/]+)/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def delete(self, request, servergroup_id):
|
||||
"""Delete a specific server group
|
||||
|
||||
DELETE http://localhost/api/nova/servergroups/<servergroup_id>
|
||||
"""
|
||||
api.nova.server_group_delete(request, servergroup_id)
|
||||
|
||||
|
||||
@urls.register
|
||||
class ServerMetadata(generic.View):
|
||||
"""API for server metadata."""
|
||||
|
@ -54,6 +54,7 @@
|
||||
getServers: getServers,
|
||||
getServerGroups: getServerGroups,
|
||||
createServerGroup: createServerGroup,
|
||||
deleteServerGroup: deleteServerGroup,
|
||||
deleteServer: deleteServer,
|
||||
pauseServer: pauseServer,
|
||||
unpauseServer: unpauseServer,
|
||||
@ -355,6 +356,28 @@
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name deleteServerGroup
|
||||
* @description
|
||||
* Delete a single server group by ID.
|
||||
*
|
||||
* @param {String} serverGroupId
|
||||
* Server Group to delete
|
||||
*
|
||||
* @param {boolean} suppressError
|
||||
* If passed in, this will not show the default error handling
|
||||
* (horizon alert).
|
||||
*
|
||||
* @returns {Object} The result of the API call
|
||||
*/
|
||||
function deleteServerGroup(serverGroupId, suppressError) {
|
||||
var promise = apiService.delete('/api/nova/servergroups/' + serverGroupId + '/');
|
||||
return suppressError ? promise : promise.error(function() {
|
||||
var msg = gettext('Unable to delete the server group with id %(id)s');
|
||||
toastService.add('error', interpolate(msg, { id: serverGroupId }, true));
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* @name deleteServer
|
||||
* @description
|
||||
|
@ -312,6 +312,13 @@
|
||||
"new server group"
|
||||
]
|
||||
},
|
||||
{
|
||||
"func": "deleteServerGroup",
|
||||
"method": "delete",
|
||||
"path": "/api/nova/servergroups/1/",
|
||||
"error": "Unable to delete the server group with id 1",
|
||||
"testInput": [1]
|
||||
},
|
||||
{
|
||||
"func": "getExtensions",
|
||||
"method": "get",
|
||||
|
@ -31,17 +31,39 @@
|
||||
|
||||
registerServerGroupActions.$inject = [
|
||||
'horizon.app.core.server_groups.actions.create.service',
|
||||
'horizon.app.core.server_groups.actions.delete.service',
|
||||
'horizon.app.core.server_groups.resourceType',
|
||||
'horizon.framework.conf.resource-type-registry.service'
|
||||
];
|
||||
|
||||
function registerServerGroupActions(
|
||||
createService,
|
||||
deleteService,
|
||||
serverGroupResourceTypeCode,
|
||||
registry
|
||||
) {
|
||||
var serverGroupResourceType = registry.getResourceType(serverGroupResourceTypeCode);
|
||||
|
||||
serverGroupResourceType.itemActions
|
||||
.append({
|
||||
id: 'deleteServerGroupAction',
|
||||
service: deleteService,
|
||||
template: {
|
||||
type: 'delete',
|
||||
text: gettext('Delete Server Group')
|
||||
}
|
||||
});
|
||||
|
||||
serverGroupResourceType.batchActions
|
||||
.append({
|
||||
id: 'batchDeleteServerGroupAction',
|
||||
service: deleteService,
|
||||
template: {
|
||||
type: 'delete-selected',
|
||||
text: gettext('Delete Server Groups')
|
||||
}
|
||||
});
|
||||
|
||||
serverGroupResourceType.globalActions
|
||||
.append({
|
||||
id: 'createServerGroupAction',
|
||||
|
@ -23,6 +23,16 @@
|
||||
registry = $injector.get('horizon.framework.conf.resource-type-registry.service');
|
||||
}));
|
||||
|
||||
it('registers Delete Server Group as an item action', function() {
|
||||
var actions = registry.getResourceType('OS::Nova::ServerGroup').itemActions;
|
||||
expect(actionHasId(actions, 'deleteServerGroupAction')).toBe(true);
|
||||
});
|
||||
|
||||
it('registers Delete Server Group as a batch action', function() {
|
||||
var actions = registry.getResourceType('OS::Nova::ServerGroup').batchActions;
|
||||
expect(actionHasId(actions, 'batchDeleteServerGroupAction')).toBe(true);
|
||||
});
|
||||
|
||||
it('registers Create Server Group as a global action', function() {
|
||||
var actions = registry.getResourceType('OS::Nova::ServerGroup').globalActions;
|
||||
expect(actionHasId(actions, 'createServerGroupAction')).toBe(true);
|
||||
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.app.core.server_groups')
|
||||
.factory('horizon.app.core.server_groups.actions.delete.service', deleteServerGroupService);
|
||||
|
||||
deleteServerGroupService.$inject = [
|
||||
'horizon.app.core.openstack-service-api.nova',
|
||||
'horizon.app.core.openstack-service-api.policy',
|
||||
'horizon.app.core.server_groups.resourceType',
|
||||
'horizon.framework.util.actions.action-result.service',
|
||||
'horizon.framework.util.i18n.ngettext',
|
||||
'horizon.framework.widgets.modal.deleteModalService'
|
||||
];
|
||||
|
||||
/*
|
||||
* @ngdoc factory
|
||||
* @name horizon.app.core.server_groups.actions.delete.service
|
||||
*
|
||||
* @Description
|
||||
* Brings up the delete server groups confirmation modal dialog.
|
||||
|
||||
* On submit, delete given server groups.
|
||||
* On cancel, do nothing.
|
||||
*/
|
||||
function deleteServerGroupService(
|
||||
nova,
|
||||
policy,
|
||||
serverGroupResourceType,
|
||||
actionResultService,
|
||||
ngettext,
|
||||
deleteModal
|
||||
) {
|
||||
return {
|
||||
allowed: allowed,
|
||||
perform: perform
|
||||
};
|
||||
|
||||
//////////////
|
||||
|
||||
function allowed() {
|
||||
return policy.ifAllowed(
|
||||
{rules: [['compute', 'os_compute_api:os-server-groups:delete']]});
|
||||
}
|
||||
|
||||
function perform(items, scope) {
|
||||
var servergroups = angular.isArray(items) ? items : [items];
|
||||
var context = {
|
||||
labels: labelize(servergroups.length),
|
||||
deleteEntity: deleteServerGroup
|
||||
};
|
||||
return deleteModal.open(scope, servergroups, context).then(deleteResult);
|
||||
}
|
||||
|
||||
function deleteResult(deleteModalResult) {
|
||||
// To make the result of this action generically useful, reformat the return
|
||||
// from the deleteModal into a standard form
|
||||
var actionResult = actionResultService.getActionResult();
|
||||
deleteModalResult.pass.forEach(function markDeleted(item) {
|
||||
actionResult.deleted(serverGroupResourceType, item.context.id);
|
||||
});
|
||||
deleteModalResult.fail.forEach(function markFailed(item) {
|
||||
actionResult.failed(serverGroupResourceType, item.context.id);
|
||||
});
|
||||
return actionResult.result;
|
||||
}
|
||||
|
||||
function labelize(count) {
|
||||
return {
|
||||
title: ngettext(
|
||||
'Confirm Delete Server Group',
|
||||
'Confirm Delete Server Groups', count),
|
||||
message: ngettext(
|
||||
'You have selected "%s". Deleted Server Group is not recoverable.',
|
||||
'You have selected "%s". Deleted Server Groups are not recoverable.', count),
|
||||
submit: ngettext(
|
||||
'Delete Server Group',
|
||||
'Delete Server Groups', count),
|
||||
success: ngettext(
|
||||
'Deleted Server Group: %s.',
|
||||
'Deleted Server Groups: %s.', count),
|
||||
error: ngettext(
|
||||
'Unable to delete Server Group: %s.',
|
||||
'Unable to delete Server Groups: %s.', count)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function deleteServerGroup(servergroup) {
|
||||
return nova.deleteServerGroup(servergroup, true);
|
||||
}
|
||||
}
|
||||
})();
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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.app.core.server_groups.actions.delete.service', function() {
|
||||
|
||||
var $scope, deferredModal, novaAPI, service;
|
||||
var deleteModalService = {
|
||||
open: function () {
|
||||
deferredModal.resolve({
|
||||
pass: [{context: {id: 'pass'}}],
|
||||
fail: [{context: {id: 'fail'}}]
|
||||
});
|
||||
return deferredModal.promise;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
|
||||
beforeEach(module('horizon.app.core'));
|
||||
beforeEach(module('horizon.app.core.server_groups'));
|
||||
beforeEach(module('horizon.framework'));
|
||||
beforeEach(module('horizon.framework.widgets.modal', function($provide) {
|
||||
$provide.value('horizon.framework.widgets.modal.deleteModalService', deleteModalService);
|
||||
}));
|
||||
beforeEach(inject(function($injector, _$rootScope_, $q) {
|
||||
$scope = _$rootScope_.$new();
|
||||
deferredModal = $q.defer();
|
||||
novaAPI = $injector.get('horizon.app.core.openstack-service-api.nova');
|
||||
service = $injector.get('horizon.app.core.server_groups.actions.delete.service');
|
||||
}));
|
||||
|
||||
describe('perform method', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
spyOn(deleteModalService, 'open').and.callThrough();
|
||||
});
|
||||
|
||||
////////////
|
||||
|
||||
it('should open the delete modal and show correct labels, single object', testSingleLabels);
|
||||
it('should open the delete modal and show correct labels, plural objects', testPluralLabels);
|
||||
it('should open the delete modal with correct entities', testEntities);
|
||||
it('should only delete server groups that are valid', testValids);
|
||||
it('should pass in a function that deletes a server group', testNova);
|
||||
it('should check the policy if the user is allowed to delete server group', testAllowed);
|
||||
|
||||
////////////
|
||||
|
||||
function testSingleLabels() {
|
||||
var servergroups = {name: 'sg'};
|
||||
service.perform(servergroups);
|
||||
|
||||
$scope.$apply();
|
||||
|
||||
var labels = deleteModalService.open.calls.argsFor(0)[2].labels;
|
||||
expect(deleteModalService.open).toHaveBeenCalled();
|
||||
angular.forEach(labels, function eachLabel(label) {
|
||||
expect(label.toLowerCase()).toContain('server group');
|
||||
});
|
||||
}
|
||||
|
||||
function testPluralLabels() {
|
||||
var servergroups = [{name: 'sg1'}, {name: 'sg2'}];
|
||||
service.perform(servergroups);
|
||||
|
||||
$scope.$apply();
|
||||
|
||||
var labels = deleteModalService.open.calls.argsFor(0)[2].labels;
|
||||
expect(deleteModalService.open).toHaveBeenCalled();
|
||||
angular.forEach(labels, function eachLabel(label) {
|
||||
expect(label.toLowerCase()).toContain('server groups');
|
||||
});
|
||||
}
|
||||
|
||||
function testEntities() {
|
||||
var servergroups = [{name: 'sg1'}, {name: 'sg2'}, {name: 'sg3'}];
|
||||
service.perform(servergroups);
|
||||
|
||||
$scope.$apply();
|
||||
|
||||
var entities = deleteModalService.open.calls.argsFor(0)[1];
|
||||
expect(deleteModalService.open).toHaveBeenCalled();
|
||||
expect(entities.length).toEqual(servergroups.length);
|
||||
}
|
||||
|
||||
function testValids() {
|
||||
var servergroups = [{name: 'sg1'}, {name: 'sg2'}, {name: 'sg3'}];
|
||||
service.perform(servergroups);
|
||||
|
||||
$scope.$apply();
|
||||
|
||||
var entities = deleteModalService.open.calls.argsFor(0)[1];
|
||||
expect(deleteModalService.open).toHaveBeenCalled();
|
||||
expect(entities.length).toBe(servergroups.length);
|
||||
expect(entities[0].name).toEqual('sg1');
|
||||
expect(entities[1].name).toEqual('sg2');
|
||||
expect(entities[2].name).toEqual('sg3');
|
||||
}
|
||||
|
||||
function testNova() {
|
||||
spyOn(novaAPI, 'deleteServerGroup').and.callFake(angular.noop);
|
||||
var servergroups = [{id: 1, name: 'sg1'}, {id: 2, name: 'sg2'}];
|
||||
service.perform(servergroups);
|
||||
|
||||
$scope.$apply();
|
||||
|
||||
var contextArg = deleteModalService.open.calls.argsFor(0)[2];
|
||||
var deleteFunction = contextArg.deleteEntity;
|
||||
deleteFunction(servergroups[0].id);
|
||||
expect(novaAPI.deleteServerGroup).toHaveBeenCalledWith(servergroups[0].id, true);
|
||||
}
|
||||
|
||||
function testAllowed() {
|
||||
var allowed = service.allowed();
|
||||
expect(allowed).toBeTruthy();
|
||||
}
|
||||
}); // end of delete modal
|
||||
|
||||
}); // end of delete server group
|
||||
|
||||
})();
|
@ -388,6 +388,13 @@ class NovaRestTestCase(test.TestCase):
|
||||
self.mock_server_group_create.assert_called_once_with(
|
||||
request, **server_group_data)
|
||||
|
||||
@test.create_mocks({api.nova: ['server_group_delete']})
|
||||
def test_server_group_delete(self):
|
||||
request = self.mock_rest_request()
|
||||
self.mock_server_group_delete.return_value = None
|
||||
nova.ServerGroup().delete(request, "1")
|
||||
self.mock_server_group_delete.assert_called_once_with(request, "1")
|
||||
|
||||
#
|
||||
# Server Metadata
|
||||
#
|
||||
|
@ -657,3 +657,13 @@ class ComputeApiTests(test.APIMockTestCase):
|
||||
self.assertEqual(servergroup.policies, ret_val.policies)
|
||||
novaclient.versions.get_current.assert_called_once_with()
|
||||
novaclient.server_groups.create.assert_called_once_with(**kwargs)
|
||||
|
||||
def test_server_group_delete(self):
|
||||
servergroup_id = self.server_groups.first().id
|
||||
novaclient = self.stub_novaclient()
|
||||
novaclient.server_groups.delete.return_value = None
|
||||
|
||||
api_val = api.nova.server_group_delete(self.request, servergroup_id)
|
||||
|
||||
self.assertIsNone(api_val)
|
||||
novaclient.server_groups.delete.assert_called_once_with(servergroup_id)
|
||||
|
@ -6,4 +6,4 @@ features:
|
||||
Project->Compute panel group. The panel turns on if Nova API
|
||||
extension 'ServerGroups' is available. It displays information about
|
||||
server groups.
|
||||
Supported actions: create.
|
||||
Supported actions: create, delete.
|
||||
|
Loading…
x
Reference in New Issue
Block a user