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)
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def server_group_delete(request, servergroup_id):
|
||||||
|
novaclient(request).server_groups.delete(servergroup_id)
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
def service_list(request, binary=None):
|
def service_list(request, binary=None):
|
||||||
return novaclient(request).services.list(binary=binary)
|
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
|
@urls.register
|
||||||
class ServerMetadata(generic.View):
|
class ServerMetadata(generic.View):
|
||||||
"""API for server metadata."""
|
"""API for server metadata."""
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
getServers: getServers,
|
getServers: getServers,
|
||||||
getServerGroups: getServerGroups,
|
getServerGroups: getServerGroups,
|
||||||
createServerGroup: createServerGroup,
|
createServerGroup: createServerGroup,
|
||||||
|
deleteServerGroup: deleteServerGroup,
|
||||||
deleteServer: deleteServer,
|
deleteServer: deleteServer,
|
||||||
pauseServer: pauseServer,
|
pauseServer: pauseServer,
|
||||||
unpauseServer: unpauseServer,
|
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
|
* @name deleteServer
|
||||||
* @description
|
* @description
|
||||||
|
@ -312,6 +312,13 @@
|
|||||||
"new server group"
|
"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",
|
"func": "getExtensions",
|
||||||
"method": "get",
|
"method": "get",
|
||||||
|
@ -31,17 +31,39 @@
|
|||||||
|
|
||||||
registerServerGroupActions.$inject = [
|
registerServerGroupActions.$inject = [
|
||||||
'horizon.app.core.server_groups.actions.create.service',
|
'horizon.app.core.server_groups.actions.create.service',
|
||||||
|
'horizon.app.core.server_groups.actions.delete.service',
|
||||||
'horizon.app.core.server_groups.resourceType',
|
'horizon.app.core.server_groups.resourceType',
|
||||||
'horizon.framework.conf.resource-type-registry.service'
|
'horizon.framework.conf.resource-type-registry.service'
|
||||||
];
|
];
|
||||||
|
|
||||||
function registerServerGroupActions(
|
function registerServerGroupActions(
|
||||||
createService,
|
createService,
|
||||||
|
deleteService,
|
||||||
serverGroupResourceTypeCode,
|
serverGroupResourceTypeCode,
|
||||||
registry
|
registry
|
||||||
) {
|
) {
|
||||||
var serverGroupResourceType = registry.getResourceType(serverGroupResourceTypeCode);
|
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
|
serverGroupResourceType.globalActions
|
||||||
.append({
|
.append({
|
||||||
id: 'createServerGroupAction',
|
id: 'createServerGroupAction',
|
||||||
|
@ -23,6 +23,16 @@
|
|||||||
registry = $injector.get('horizon.framework.conf.resource-type-registry.service');
|
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() {
|
it('registers Create Server Group as a global action', function() {
|
||||||
var actions = registry.getResourceType('OS::Nova::ServerGroup').globalActions;
|
var actions = registry.getResourceType('OS::Nova::ServerGroup').globalActions;
|
||||||
expect(actionHasId(actions, 'createServerGroupAction')).toBe(true);
|
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(
|
self.mock_server_group_create.assert_called_once_with(
|
||||||
request, **server_group_data)
|
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
|
# Server Metadata
|
||||||
#
|
#
|
||||||
|
@ -657,3 +657,13 @@ class ComputeApiTests(test.APIMockTestCase):
|
|||||||
self.assertEqual(servergroup.policies, ret_val.policies)
|
self.assertEqual(servergroup.policies, ret_val.policies)
|
||||||
novaclient.versions.get_current.assert_called_once_with()
|
novaclient.versions.get_current.assert_called_once_with()
|
||||||
novaclient.server_groups.create.assert_called_once_with(**kwargs)
|
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
|
Project->Compute panel group. The panel turns on if Nova API
|
||||||
extension 'ServerGroups' is available. It displays information about
|
extension 'ServerGroups' is available. It displays information about
|
||||||
server groups.
|
server groups.
|
||||||
Supported actions: create.
|
Supported actions: create, delete.
|
||||||
|
Loading…
Reference in New Issue
Block a user