dashboard/shell/models/harvester/pod.js

186 lines
4.8 KiB
JavaScript

import includes from 'lodash/includes';
import { findBy } from '@shell/utils/array';
import { get } from '@shell/utils/object';
import { NODE } from '@shell/config/types';
import Resource from '@shell/plugins/dashboard-store/resource-class';
const POD_STATUS_NOT_SCHEDULABLE = 'POD_NOT_SCHEDULABLE';
const POD_STATUS_FAILED = 'POD_FAILED';
const POD_STATUS_CRASHLOOP_BACKOFF = 'POD_CRASHLOOP_BACKOFF';
const POD_STATUS_UNKNOWN = 'POD_STATUS_UNKNOWN';
const POD_STATUS_CONTAINER_FAILING = 'POD_CONTAINER_FAILING';
const POD_STATUS_NOT_READY = 'POD_NOT_READY';
const POD_STATUS_PENDING = 'POD_STATUS_PENDING';
const POD_STATUS_COMPLETED = 'POD_STATUS_COMPLETED';
const POD_STATUS_SUCCEEDED = 'POD_STATUS_SUCCEEDED';
const POD_STATUS_RUNNING = 'POD_STATUS_RUNNING';
const failedWaitingContainerReasons = ['ImagePullBackOff', 'ErrImagePull', 'CrashLoopBackOff'];
const failedTerminationContainerReasons = ['Error'];
const errorStatusMapper = {
Failed: POD_STATUS_FAILED,
CrashLoopBackOff: POD_STATUS_CRASHLOOP_BACKOFF,
Unknown: POD_STATUS_UNKNOWN,
};
const okStatusMapper = {
Pending: POD_STATUS_PENDING,
Running: POD_STATUS_RUNNING,
Completed: POD_STATUS_COMPLETED,
Succeeded: POD_STATUS_SUCCEEDED,
};
const stateReasonResolver = {
terminated: ({ reason, exitCode }) => `Terminated with ${ reason }${ exitCode ? ` (exit code ${ exitCode }).` : '.' }`,
waiting: ({ reason }) => `Waiting (${ reason }).`,
};
export default class HciPod extends Resource {
get inStore() {
return this.$rootGetters['currentProduct'].inStore;
}
get nodes() {
return this.$rootGetters[`${ this.inStore }/all`](NODE);
}
get node() {
const { nodeName } = this.spec;
return this.nodes.filter((node) => {
return node?.metadata?.name === nodeName;
})[0];
}
get getPodStatus() {
return this.isNotSchedulable ||
this.hasErrorStatus ||
this.isContainerFailing ||
this.isNotReady ||
this.hasOkStatus || { status: POD_STATUS_UNKNOWN };
}
get isNotSchedulable() {
if (!this.isPodSchedulable) {
const conditions = get(this, 'status.conditions');
const podScheduledCond = findBy(conditions, 'type', 'PodScheduled');
return {
status: POD_STATUS_NOT_SCHEDULABLE,
message: podScheduledCond.message || 'Pod scheduling failed.',
};
}
return null;
}
get hasErrorStatus() {
const status = errorStatusMapper[this?.status?.phase];
if (status) {
return {
status,
message: this.getContainerStatusReason(this.findFailingContainerStatus),
};
}
return null;
}
get isPodSchedulable() {
const conditions = get(this, 'status.conditions');
const podScheduledCond = findBy(conditions, 'type', 'PodScheduled');
return !(
podScheduledCond &&
podScheduledCond.status !== 'True' &&
podScheduledCond.reason === 'Unschedulable'
);
}
get findFailingContainerStatus() {
return (get(this, 'status.containerStatuses'), []).find((container) => {
return !container.ready &&
(includes(failedWaitingContainerReasons, get(container, 'state.waiting.reason')) ||
includes(failedTerminationContainerReasons, get(container, 'state.terminated.reason')));
});
}
get getContainerStatusReason() {
return (containerStatus) => {
if (containerStatus) {
const stateName = Object.getOwnPropertyNames(containerStatus.state).find(
pn => !!containerStatus.state[pn].reason,
);
if (stateName) {
const state = containerStatus.state[stateName];
return (
state.message ||
(stateReasonResolver[stateName] && stateReasonResolver[stateName](state)) ||
stateName
);
}
}
return undefined;
};
}
get isContainerFailing() {
const failingContainer = this.findFailingContainerStatus;
if (failingContainer) {
return {
status: POD_STATUS_CONTAINER_FAILING,
message: this.getContainerStatusReason(failingContainer),
};
}
return null;
}
get isNotReady() {
const message = this.findPodFalseStatusConditionMessage;
if (message) {
return {
status: POD_STATUS_NOT_READY,
message,
};
}
return null;
}
get hasOkStatus() {
const status = okStatusMapper[this?.status?.phase];
if (status) {
return { status };
}
return null;
}
get findPodFalseStatusConditionMessage() {
const notReadyConditions = this.getPodFalseStatusConditions;
if (notReadyConditions.length > 0) {
return notReadyConditions[0].message || `Step: ${ notReadyConditions[0].type }`;
}
return undefined;
}
get getPodFalseStatusConditions() {
const conditions = get(this, 'status.conditions') || [];
return conditions.filter(condition => condition.status !== 'True');
}
}