Merge "Add angular delete server groups action"

This commit is contained in:
Zuul 2018-03-20 03:56:00 +00:00 committed by Gerrit Code Review
commit 5b9a34d401
11 changed files with 341 additions and 1 deletions

View File

@ -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)

View File

@ -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."""

View File

@ -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

View File

@ -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",

View File

@ -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',

View File

@ -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);

View File

@ -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);
}
}
})();

View File

@ -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
})();

View File

@ -390,6 +390,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
#

View File

@ -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)

View File

@ -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.