mirror of https://github.com/portainer/portainer
delete force terminating namespace (#7081)
parent
75fef397d3
commit
e5e57978af
|
@ -26,6 +26,14 @@ angular.module('portainer.kubernetes').factory('KubernetesNamespaces', [
|
||||||
transformResponse: rawResponse,
|
transformResponse: rawResponse,
|
||||||
ignoreLoadingBar: true,
|
ignoreLoadingBar: true,
|
||||||
},
|
},
|
||||||
|
getJSON: {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
},
|
||||||
|
transformResponse: rawResponse,
|
||||||
|
ignoreLoadingBar: true,
|
||||||
|
},
|
||||||
create: { method: 'POST' },
|
create: { method: 'POST' },
|
||||||
update: { method: 'PUT' },
|
update: { method: 'PUT' },
|
||||||
delete: { method: 'DELETE' },
|
delete: { method: 'DELETE' },
|
||||||
|
|
|
@ -17,6 +17,8 @@ class KubernetesNamespaceService {
|
||||||
this.getAllAsync = this.getAllAsync.bind(this);
|
this.getAllAsync = this.getAllAsync.bind(this);
|
||||||
this.createAsync = this.createAsync.bind(this);
|
this.createAsync = this.createAsync.bind(this);
|
||||||
this.deleteAsync = this.deleteAsync.bind(this);
|
this.deleteAsync = this.deleteAsync.bind(this);
|
||||||
|
this.getJSONAsync = this.getJSONAsync.bind(this);
|
||||||
|
this.updateFinalizeAsync = this.updateFinalizeAsync.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,6 +38,31 @@ class KubernetesNamespaceService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET namesspace in JSON format
|
||||||
|
*/
|
||||||
|
async getJSONAsync(name) {
|
||||||
|
try {
|
||||||
|
const params = new KubernetesCommonParams();
|
||||||
|
params.id = name;
|
||||||
|
await this.KubernetesNamespaces().status(params).$promise;
|
||||||
|
return await this.KubernetesNamespaces().getJSON(params).$promise;
|
||||||
|
} catch (err) {
|
||||||
|
throw new PortainerError('Unable to retrieve namespace', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update finalize
|
||||||
|
*/
|
||||||
|
async updateFinalizeAsync(namespace) {
|
||||||
|
try {
|
||||||
|
return await this.KubernetesNamespaces().update({ id: namespace.metadata.name, action: 'finalize' }, namespace).$promise;
|
||||||
|
} catch (err) {
|
||||||
|
throw new PortainerError('Unable to update namespace', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getAllAsync() {
|
async getAllAsync() {
|
||||||
try {
|
try {
|
||||||
const data = await this.KubernetesNamespaces().get().$promise;
|
const data = await this.KubernetesNamespaces().get().$promise;
|
||||||
|
|
|
@ -2,12 +2,13 @@ import angular from 'angular';
|
||||||
|
|
||||||
class KubernetesResourcePoolsController {
|
class KubernetesResourcePoolsController {
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor($async, $state, Notifications, ModalService, KubernetesResourcePoolService) {
|
constructor($async, $state, Notifications, ModalService, KubernetesResourcePoolService, KubernetesNamespaceService) {
|
||||||
this.$async = $async;
|
this.$async = $async;
|
||||||
this.$state = $state;
|
this.$state = $state;
|
||||||
this.Notifications = Notifications;
|
this.Notifications = Notifications;
|
||||||
this.ModalService = ModalService;
|
this.ModalService = ModalService;
|
||||||
this.KubernetesResourcePoolService = KubernetesResourcePoolService;
|
this.KubernetesResourcePoolService = KubernetesResourcePoolService;
|
||||||
|
this.KubernetesNamespaceService = KubernetesNamespaceService;
|
||||||
|
|
||||||
this.onInit = this.onInit.bind(this);
|
this.onInit = this.onInit.bind(this);
|
||||||
this.getResourcePools = this.getResourcePools.bind(this);
|
this.getResourcePools = this.getResourcePools.bind(this);
|
||||||
|
@ -20,7 +21,19 @@ class KubernetesResourcePoolsController {
|
||||||
let actionCount = selectedItems.length;
|
let actionCount = selectedItems.length;
|
||||||
for (const pool of selectedItems) {
|
for (const pool of selectedItems) {
|
||||||
try {
|
try {
|
||||||
await this.KubernetesResourcePoolService.delete(pool);
|
const isTerminating = pool.Namespace.Status === 'Terminating';
|
||||||
|
if (isTerminating) {
|
||||||
|
const ns = await this.KubernetesNamespaceService.getJSONAsync(pool.Namespace.Name);
|
||||||
|
ns.$promise.then(async (namespace) => {
|
||||||
|
const n = JSON.parse(namespace.data);
|
||||||
|
if (n.spec && n.spec.finalizers) {
|
||||||
|
delete n.spec.finalizers;
|
||||||
|
}
|
||||||
|
await this.KubernetesNamespaceService.updateFinalizeAsync(n);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await this.KubernetesResourcePoolService.delete(pool);
|
||||||
|
}
|
||||||
this.Notifications.success('Namespace successfully removed', pool.Namespace.Name);
|
this.Notifications.success('Namespace successfully removed', pool.Namespace.Name);
|
||||||
const index = this.resourcePools.indexOf(pool);
|
const index = this.resourcePools.indexOf(pool);
|
||||||
this.resourcePools.splice(index, 1);
|
this.resourcePools.splice(index, 1);
|
||||||
|
@ -36,14 +49,15 @@ class KubernetesResourcePoolsController {
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAction(selectedItems) {
|
removeAction(selectedItems) {
|
||||||
this.ModalService.confirmDeletion(
|
const isTerminatingNS = selectedItems.some((pool) => pool.Namespace.Status === 'Terminating');
|
||||||
'Do you want to remove the selected namespace(s)? All the resources associated to the selected namespace(s) will be removed too.',
|
const message = isTerminatingNS
|
||||||
(confirmed) => {
|
? 'At least one namespace is in a terminating state. For terminating state namespaces, you may continue and force removal, but doing so without having properly cleaned up may lead to unstable and unpredictable behavior. Are you sure you wish to proceed?'
|
||||||
if (confirmed) {
|
: 'Do you want to remove the selected namespace(s)? All the resources associated to the selected namespace(s) will be removed too. Are you sure you wish to proceed?';
|
||||||
return this.$async(this.removeActionAsync, selectedItems);
|
this.ModalService.confirmWithTitle(isTerminatingNS ? 'Force namespace removal' : 'Are you sure?', message, (confirmed) => {
|
||||||
}
|
if (confirmed) {
|
||||||
|
return this.$async(this.removeActionAsync, selectedItems);
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getResourcePoolsAsync() {
|
async getResourcePoolsAsync() {
|
||||||
|
|
|
@ -100,6 +100,25 @@ export function confirmDeletion(message: string, callback: ConfirmCallback) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function confirmWithTitle(
|
||||||
|
title: string,
|
||||||
|
message: string,
|
||||||
|
callback: ConfirmCallback
|
||||||
|
) {
|
||||||
|
const messageSanitized = sanitize(message);
|
||||||
|
confirm({
|
||||||
|
title: sanitize(title),
|
||||||
|
message: messageSanitized,
|
||||||
|
buttons: {
|
||||||
|
confirm: {
|
||||||
|
label: 'Remove',
|
||||||
|
className: 'btn-danger',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
callback,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function confirmDetachment(message: string, callback: ConfirmCallback) {
|
export function confirmDetachment(message: string, callback: ConfirmCallback) {
|
||||||
const messageSanitized = sanitize(message);
|
const messageSanitized = sanitize(message);
|
||||||
confirm({
|
confirm({
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
confirmWebEditorDiscard,
|
confirmWebEditorDiscard,
|
||||||
confirm,
|
confirm,
|
||||||
confirmForceChangePassword,
|
confirmForceChangePassword,
|
||||||
|
confirmWithTitle,
|
||||||
} from './confirm';
|
} from './confirm';
|
||||||
import {
|
import {
|
||||||
confirmContainerDeletion,
|
confirmContainerDeletion,
|
||||||
|
@ -58,5 +59,6 @@ export function ModalServiceAngular() {
|
||||||
selectRegistry,
|
selectRegistry,
|
||||||
confirmContainerDeletion,
|
confirmContainerDeletion,
|
||||||
confirmForceChangePassword,
|
confirmForceChangePassword,
|
||||||
|
confirmWithTitle,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue