Stop container before deletion

When container is running, stop the container before deletion.

Change-Id: I940c36d47070be213c376f8140300aa3e10bbf02
This commit is contained in:
Shu Muto 2017-12-06 15:17:54 +09:00
parent a4cb8d1f24
commit 9fee717602
6 changed files with 192 additions and 14 deletions

View File

@ -152,9 +152,8 @@ def container_update(request, id, **kwargs):
return args
def container_delete(request, id, force=False):
# TODO(shu-mutou): force option should be provided by user.
return zunclient(request).containers.delete(id, force=force)
def container_delete(request, **kwargs):
return zunclient(request).containers.delete(**kwargs)
def container_list(request, limit=None, marker=None, sort_key=None,

View File

@ -38,14 +38,6 @@ class Container(generic.View):
"""Get a specific container"""
return change_to_id(client.container_show(request, id).to_dict())
@rest_utils.ajax(data_required=True)
def delete(self, request, id):
"""Delete single Container forcely by id.
Returns HTTP 204 (no content) on successful deletion.
"""
return client.container_delete(request, id, force=True)
@rest_utils.ajax(data_required=True)
def patch(self, request, id):
"""Update a Container.
@ -91,6 +83,19 @@ class ContainerActions(generic.View):
elif action == 'attach':
return client.container_attach(request, id)
@rest_utils.ajax(data_required=True)
def delete(self, request, id, action):
"""Delete specified Container with option.
Returns HTTP 204 (no content) on successful deletion.
"""
opts = {'id': id}
if action == 'force':
opts['force'] = True
elif action == 'stop':
opts['stop'] = True
return client.container_delete(request, **opts)
@urls.register
class Containers(generic.View):
@ -114,7 +119,8 @@ class Containers(generic.View):
Returns HTTP 204 (no content) on successful deletion.
"""
for id in request.DATA:
client.container_delete(request, id)
opts = {'id': id}
client.container_delete(request, **opts)
@rest_utils.ajax(data_required=True)
def post(self, request):

View File

@ -36,6 +36,7 @@
'horizon.dashboard.container.containers.update.service',
'horizon.dashboard.container.containers.delete.service',
'horizon.dashboard.container.containers.delete-force.service',
'horizon.dashboard.container.containers.delete-stop.service',
'horizon.dashboard.container.containers.start.service',
'horizon.dashboard.container.containers.stop.service',
'horizon.dashboard.container.containers.restart.service',
@ -54,6 +55,7 @@
updateContainerService,
deleteContainerService,
deleteContainerForceService,
deleteContainerStopService,
startContainerService,
stopContainerService,
restartContainerService,
@ -158,6 +160,14 @@
text: gettext('Delete Container')
}
})
.append({
id: 'deleteContainerStopAction',
service: deleteContainerStopService,
template: {
type: 'delete',
text: gettext('Stop and Delete Container')
}
})
.append({
id: 'deleteContainerForceAction',
service: deleteContainerForceService,

View File

@ -0,0 +1,153 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use self 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 factory
* @name horizon.dashboard.container.containers.delete-stop.service
* @Description
* Brings up the stop and delete container confirmation modal dialog.
* On submit, delete after stop selected resources.
* On cancel, do nothing.
*/
angular
.module('horizon.dashboard.container.containers')
.factory('horizon.dashboard.container.containers.delete-stop.service', deleteStopService);
deleteStopService.$inject = [
'$location',
'$q',
'horizon.app.core.openstack-service-api.zun',
'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.modal.deleteModalService',
'horizon.framework.widgets.toast.service',
'horizon.dashboard.container.containers.resourceType',
'horizon.dashboard.container.containers.events',
'horizon.dashboard.container.containers.validStates'
];
function deleteStopService(
$location, $q, zun, policy, actionResult, gettext, $qExtensions, deleteModal,
toast, resourceType, events, validStates
) {
var scope;
var context = {
labels: null,
deleteEntity: deleteEntity,
successEvent: events.DELETE_SUCCESS
};
var service = {
initAction: initAction,
allowed: allowed,
perform: perform
};
var notAllowedMessage = gettext("You are not allowed to stop and delete container: %s");
return service;
//////////////
function initAction() {
}
function allowed(container) {
return $qExtensions.booleanAsPromise(
validStates.delete_stop.indexOf(container.status) >= 0
);
}
// delete selected resource objects
function perform(selected, newScope) {
scope = newScope;
selected = angular.isArray(selected) ? selected : [selected];
context.labels = labelize(selected.length);
return $qExtensions.allSettled(selected.map(checkPermission)).then(afterCheck);
}
function labelize(count) {
return {
title: ngettext('Confirm Delete After Stop Container',
'Confirm Delete After Stop Containers', count),
/* eslint-disable max-len */
message: ngettext('You have selected "%s". Please confirm your selection. The container will be stopped before deleting. Deleted container is not recoverable.',
'You have selected "%s". Please confirm your selection. The containers will be stopped before deleting. Deleted containers are not recoverable.', count),
/* eslint-enable max-len */
submit: ngettext('Delete Container After Stop',
'Delete Containers After Stop', count),
success: ngettext('Deleted Container After Stop: %s.',
'Deleted Containers After Stop: %s.', count),
error: ngettext('Unable to delete Container after stopping: %s.',
'Unable to delete Containers after stopping: %s.', count)
};
}
// for batch delete
function checkPermission(selected) {
return {promise: allowed(selected), context: selected};
}
// for batch delete
function afterCheck(result) {
var outcome = $q.reject(); // Reject the promise by default
if (result.fail.length > 0) {
toast.add('error', getMessage(notAllowedMessage, result.fail));
outcome = $q.reject(result.fail);
}
if (result.pass.length > 0) {
outcome = deleteModal.open(scope, result.pass.map(getEntity), context).then(createResult);
}
return outcome;
}
function createResult(deleteModalResult) {
// To make the result of this action generically useful, reformat the return
// from the deleteModal into a standard form
var result = actionResult.getActionResult();
deleteModalResult.pass.forEach(function markDeleted(item) {
result.deleted(resourceType, getEntity(item).id);
});
deleteModalResult.fail.forEach(function markFailed(item) {
result.failed(resourceType, getEntity(item).id);
});
if (result.result.failed.length === 0 && result.result.deleted.length > 0) {
$location.path('/project/container/containers');
} else {
return result.result;
}
}
function getMessage(message, entities) {
return interpolate(message, [entities.map(getName).join(", ")]);
}
function getName(result) {
return getEntity(result).name;
}
// for batch delete
function getEntity(result) {
return result.context;
}
// call delete REST API
function deleteEntity(id) {
return zun.deleteContainerStop(id, true);
}
}
})();

View File

@ -67,7 +67,8 @@
delete_force: [
states.CREATED, states.CREATING, states.ERROR, states.RUNNING,
states.STOPPED, states.UNKNOWN, states.DELETED
]
],
delete_stop: [states.RUNNING]
};
}

View File

@ -35,6 +35,7 @@
deleteContainer: deleteContainer,
deleteContainers: deleteContainers,
deleteContainerForce: deleteContainerForce,
deleteContainerStop: deleteContainerStop,
startContainer: startContainer,
stopContainer: stopContainer,
logsContainer: logsContainer,
@ -88,13 +89,21 @@
}
function deleteContainerForce(id, suppressError) {
var promise = apiService.delete(containersPath + id, [id]);
var promise = apiService.delete(containersPath + id + '/force', [id]);
return suppressError ? promise : promise.error(function() {
var msg = gettext('Unable to delete forcely the Container with id: %(id)s');
toastService.add('error', interpolate(msg, { id: id }, true));
});
}
function deleteContainerStop(id, suppressError) {
var promise = apiService.delete(containersPath + id + '/stop', [id]);
return suppressError ? promise : promise.error(function() {
var msg = gettext('Unable to stop and delete the Container with id: %(id)s');
toastService.add('error', interpolate(msg, { id: id }, true));
});
}
function startContainer(id) {
var msg = gettext('Unable to start Container.');
return apiService.post(containersPath + id + '/start').error(error(msg));