1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

Enable the ability to cordon/uncordon/drain nodes (#4723)

* feat(node): Enable the ability to cordon/uncordon/drain nodes

* feat(cluster): check if there is a drain operation somewhere

* feat(kubernetes): allow to cordon, uncordon, drain nodes

* refacto(kubernetes): set a constant for drain label name

* fix(node): Relocate the warning message next to the dropdown and change the information message
This commit is contained in:
Maxime Bajeux 2021-03-15 22:36:14 +01:00 committed by GitHub
parent 660bc2dadf
commit 32a9a2e46b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 182 additions and 13 deletions

View file

@ -1,6 +1,6 @@
import _ from 'lodash-es';
import { KubernetesNode, KubernetesNodeDetails, KubernetesNodeTaint } from 'Kubernetes/node/models';
import { KubernetesNode, KubernetesNodeDetails, KubernetesNodeTaint, KubernetesNodeAvailabilities, KubernetesPortainerNodeDrainLabel } from 'Kubernetes/node/models';
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
import { KubernetesNodeFormValues, KubernetesNodeTaintFormValues, KubernetesNodeLabelFormValues } from 'Kubernetes/node/formValues';
import { KubernetesNodeCreatePayload, KubernetesNodeTaintPayload } from 'Kubernetes/node/payload';
@ -30,6 +30,11 @@ class KubernetesNodeConverter {
NetworkUnavailable: networkUnavailable && networkUnavailable.status === 'True',
};
res.Availability = KubernetesNodeAvailabilities.ACTIVE;
if (data.spec.unschedulable === true) {
res.Availability = _.has(data.metadata.labels, KubernetesPortainerNodeDrainLabel) ? KubernetesNodeAvailabilities.DRAIN : KubernetesNodeAvailabilities.PAUSE;
}
if (ready.status === 'False') {
res.Status = 'Unhealthy';
} else if (ready.status === 'Unknown' || res.Conditions.MemoryPressure || res.Conditions.PIDPressure || res.Conditions.DiskPressure || res.Conditions.NetworkUnavailable) {
@ -67,6 +72,8 @@ class KubernetesNodeConverter {
static nodeToFormValues(node) {
const res = new KubernetesNodeFormValues();
res.Availability = node.Availability;
res.Taints = _.map(node.Taints, (taint) => {
const res = new KubernetesNodeTaintFormValues();
res.Key = taint.Key;
@ -92,6 +99,8 @@ class KubernetesNodeConverter {
static formValuesToNode(node, formValues) {
const res = angular.copy(node);
res.Availability = formValues.Availability;
const filteredTaints = _.filter(formValues.Taints, (taint) => !taint.NeedsDeletion);
res.Taints = _.map(filteredTaints, (item) => {
const taint = new KubernetesNodeTaint();
@ -130,6 +139,15 @@ class KubernetesNodeConverter {
payload.metadata.labels = node.Labels;
if (node.Availability !== KubernetesNodeAvailabilities.ACTIVE) {
payload.spec.unschedulable = true;
if (node.Availability === KubernetesNodeAvailabilities.DRAIN) {
payload.metadata.labels[KubernetesPortainerNodeDrainLabel] = '';
} else {
delete payload.metadata.labels[KubernetesPortainerNodeDrainLabel];
}
}
return payload;
}

View file

@ -1,6 +1,7 @@
const _KubernetesNodeFormValues = Object.freeze({
Taints: [],
Labels: [],
Availability: '',
});
export class KubernetesNodeFormValues {

View file

@ -1,3 +1,5 @@
export const KubernetesPortainerNodeDrainLabel = 'io.portainer/node-status-drain';
/**
* KubernetesNode Model
*/
@ -14,6 +16,7 @@ const _KubernetesNode = Object.freeze({
Api: false,
Taints: [],
Port: 0,
Availability: '',
});
export class KubernetesNode {
@ -58,6 +61,12 @@ export class KubernetesNodeTaint {
}
}
export const KubernetesNodeAvailabilities = Object.freeze({
ACTIVE: 'Active',
PAUSE: 'Pause',
DRAIN: 'Drain',
});
export const KubernetesNodeTaintEffects = Object.freeze({
NOSCHEDULE: 'NoSchedule',
PREFERNOSCHEDULE: 'PreferNoSchedule',

View file

@ -57,7 +57,8 @@ class KubernetesNodeService {
const newNode = KubernetesNodeConverter.formValuesToNode(node, nodeFormValues);
const payload = KubernetesNodeConverter.patchPayload(node, newNode);
const data = await this.KubernetesNodes().patch(params, payload).$promise;
return data;
const patchedNode = KubernetesNodeConverter.apiToNodeDetails(data);
return patchedNode;
} catch (err) {
throw { msg: 'Unable to patch node', err: err };
}