mirror of https://github.com/rancher/dashboard.git
280 lines
6.8 KiB
JavaScript
280 lines
6.8 KiB
JavaScript
import { insertAt } from '@shell/utils/array';
|
|
import { colorForState, stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
|
|
import { NODE, WORKLOAD_TYPES } from '@shell/config/types';
|
|
import { escapeHtml, shortenedImage } from '@shell/utils/string';
|
|
import WorkloadService from '@shell/models/workload.service';
|
|
import { deleteProperty } from '@shell/utils/object';
|
|
|
|
export const WORKLOAD_PRIORITY = {
|
|
[WORKLOAD_TYPES.DEPLOYMENT]: 1,
|
|
[WORKLOAD_TYPES.CRON_JOB]: 2,
|
|
[WORKLOAD_TYPES.DAEMON_SET]: 3,
|
|
[WORKLOAD_TYPES.STATEFUL_SET]: 4,
|
|
[WORKLOAD_TYPES.JOB]: 5,
|
|
[WORKLOAD_TYPES.REPLICA_SET]: 6,
|
|
[WORKLOAD_TYPES.REPLICATION_CONTROLLER]: 7,
|
|
};
|
|
|
|
export default class Pod extends WorkloadService {
|
|
_os = undefined;
|
|
|
|
get inStore() {
|
|
return this.$rootGetters['currentProduct'].inStore;
|
|
}
|
|
|
|
set os(operatingSystem) {
|
|
this._os = operatingSystem;
|
|
}
|
|
|
|
get os() {
|
|
if (this._os) {
|
|
return this._os;
|
|
}
|
|
|
|
return this?.node?.status?.nodeInfo?.operatingSystem;
|
|
}
|
|
|
|
get node() {
|
|
try {
|
|
const schema = this.$store.getters[`cluster/schemaFor`](NODE);
|
|
|
|
if (schema) {
|
|
this.$dispatch(`find`, { type: NODE, id: this.spec.nodeName });
|
|
}
|
|
} catch {}
|
|
|
|
return this.$getters['byId'](NODE, this.spec.nodeName);
|
|
}
|
|
|
|
get _availableActions() {
|
|
const out = super._availableActions;
|
|
|
|
// Add backwards, each one to the top
|
|
insertAt(out, 0, { divider: true });
|
|
insertAt(out, 0, this.openLogsMenuItem);
|
|
insertAt(out, 0, this.openShellMenuItem);
|
|
|
|
return out;
|
|
}
|
|
|
|
get openShellMenuItem() {
|
|
return {
|
|
action: 'openShell',
|
|
enabled: !!this.links.view && this.isRunning,
|
|
icon: 'icon-chevron-right',
|
|
label: 'Execute Shell',
|
|
total: 1,
|
|
};
|
|
}
|
|
|
|
get openLogsMenuItem() {
|
|
return {
|
|
action: 'openLogs',
|
|
enabled: !!this.links.view,
|
|
icon: 'icon icon-chevron-right',
|
|
label: 'View Logs',
|
|
total: 1,
|
|
};
|
|
}
|
|
|
|
get containerActions() {
|
|
const out = [];
|
|
|
|
insertAt(out, 0, this.openLogsMenuItem);
|
|
insertAt(out, 0, this.openShellMenuItem);
|
|
|
|
return out;
|
|
}
|
|
|
|
get defaultContainerName() {
|
|
const containers = this.spec.containers;
|
|
const desirable = containers.filter((c) => c.name !== 'istio-proxy');
|
|
|
|
if ( desirable.length ) {
|
|
return desirable[0].name;
|
|
}
|
|
|
|
return containers[0]?.name;
|
|
}
|
|
|
|
openShell(containerName = this.defaultContainerName) {
|
|
this.$dispatch('wm/open', {
|
|
id: `${ this.id }-shell`,
|
|
label: this.nameDisplay,
|
|
icon: 'terminal',
|
|
component: 'ContainerShell',
|
|
attrs: {
|
|
pod: this,
|
|
initialContainer: containerName
|
|
}
|
|
}, { root: true });
|
|
}
|
|
|
|
openLogs(containerName = this.defaultContainerName) {
|
|
this.$dispatch('wm/open', {
|
|
id: `${ this.id }-logs`,
|
|
label: this.nameDisplay,
|
|
icon: 'file',
|
|
component: 'ContainerLogs',
|
|
attrs: {
|
|
pod: this,
|
|
initialContainer: containerName
|
|
}
|
|
}, { root: true });
|
|
}
|
|
|
|
containerStateDisplay(status) {
|
|
const state = Object.keys(status.state || {})[0];
|
|
|
|
return stateDisplay(state);
|
|
}
|
|
|
|
containerStateColor(status) {
|
|
const state = Object.keys(status.state || {})[0];
|
|
|
|
return colorForState(state);
|
|
}
|
|
|
|
containerIsInit(container) {
|
|
const { initContainers = [] } = this.spec;
|
|
|
|
return initContainers.includes(container);
|
|
}
|
|
|
|
get imageNames() {
|
|
return this.spec.containers.map((container) => shortenedImage(container.image));
|
|
}
|
|
|
|
get workloadRef() {
|
|
const owners = this.getOwners() || [];
|
|
const workloads = owners.filter((owner) => {
|
|
return Object.values(WORKLOAD_TYPES).includes(owner.type);
|
|
}).sort((a, b) => {
|
|
// Prioritize types so that deployments come before replicasets and such.
|
|
const ia = WORKLOAD_PRIORITY[a.type];
|
|
const ib = WORKLOAD_PRIORITY[b.type];
|
|
|
|
return ia - ib;
|
|
});
|
|
|
|
return workloads[0];
|
|
}
|
|
|
|
get ownedByWorkload() {
|
|
return !!this.workloadRef;
|
|
}
|
|
|
|
get details() {
|
|
const out = [
|
|
{
|
|
label: this.t('workload.detailTop.podIP'),
|
|
content: this.status.podIP
|
|
},
|
|
];
|
|
|
|
if ( this.workloadRef ) {
|
|
out.push({
|
|
label: 'Workload',
|
|
formatter: 'LinkName',
|
|
formatterOpts: {
|
|
value: this.workloadRef.name,
|
|
type: this.workloadRef.type,
|
|
namespace: this.workloadRef.namespace
|
|
},
|
|
content: this.workloadRef.name
|
|
});
|
|
}
|
|
|
|
if ( this.spec.nodeName ) {
|
|
out.push({
|
|
label: 'Node',
|
|
formatter: 'LinkName',
|
|
formatterOpts: { type: NODE, value: this.spec.nodeName },
|
|
content: this.spec.nodeName,
|
|
});
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
get isRunning() {
|
|
return this.status.phase === 'Running';
|
|
}
|
|
|
|
// Use by pod list to group the pods by node
|
|
get groupByNode() {
|
|
const name = this.spec?.nodeName || this.$rootGetters['i18n/t']('generic.none');
|
|
|
|
return this.$rootGetters['i18n/t']('resourceTable.groupLabel.node', { name: escapeHtml(name) });
|
|
}
|
|
|
|
get restartCount() {
|
|
if (this.status.containerStatuses) {
|
|
return this.status?.containerStatuses[0].restartCount || 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
processSaveResponse(res) {
|
|
if (res._headers && res._headers.warning) {
|
|
const warnings = res._headers.warning.split('299') || [];
|
|
const hasPsaWarnings = warnings.filter((warning) => warning.includes('violate PodSecurity')).length;
|
|
|
|
if (hasPsaWarnings) {
|
|
this.$dispatch('growl/warning', {
|
|
title: this.$rootGetters['i18n/t']('growl.podSecurity.title'),
|
|
message: this.$rootGetters['i18n/t']('growl.podSecurity.message'),
|
|
timeout: 5000,
|
|
}, { root: true });
|
|
}
|
|
}
|
|
}
|
|
|
|
save() {
|
|
const prev = { ...this };
|
|
|
|
const { metadata, spec } = this.spec.template;
|
|
|
|
this.spec = {
|
|
...this.spec,
|
|
...spec
|
|
};
|
|
|
|
this.metadata = {
|
|
...this.metadata,
|
|
...metadata
|
|
};
|
|
|
|
delete this.spec.template;
|
|
|
|
// IF there is an error POD world model get overwritten
|
|
// For the workloads this need be reset back
|
|
return this._save(...arguments).catch((e) => {
|
|
this.spec = prev.spec;
|
|
this.metadata = prev.metadata;
|
|
|
|
return Promise.reject(e);
|
|
});
|
|
}
|
|
|
|
cleanForSave(data) {
|
|
const val = super.cleanForSave(data);
|
|
|
|
// remove fields from containers
|
|
val.spec?.containers?.forEach((container) => {
|
|
this.cleanContainerForSave(container);
|
|
});
|
|
|
|
// remove fields from initContainers
|
|
val.spec?.initContainers?.forEach((container) => {
|
|
this.cleanContainerForSave(container);
|
|
});
|
|
|
|
// This is probably added by generic workload components that shouldn't be added to pods
|
|
deleteProperty(val, 'spec.selector');
|
|
|
|
return val;
|
|
}
|
|
}
|