mirror of https://github.com/rancher/dashboard.git
298 lines
7.4 KiB
Vue
298 lines
7.4 KiB
Vue
<script>
|
|
import { Banner } from '@components/Banner';
|
|
import GroupPanel from '@shell/components/GroupPanel';
|
|
import PodAffinity from '@shell/components/form/PodAffinity';
|
|
import NodeAffinity from '@shell/components/form/NodeAffinity';
|
|
import ContainerResourceLimit from '@shell/components/ContainerResourceLimit';
|
|
import Tolerations from '@shell/components/form/Tolerations';
|
|
import { cleanUp } from '@shell/utils/object';
|
|
import { fetchSetting } from '@shell/utils/settings';
|
|
import { RadioGroup } from '@components/Form/Radio';
|
|
|
|
// Affinity radio button choices
|
|
const DEFAULT = 'default';
|
|
const CUSTOM = 'custom';
|
|
|
|
// This is the form for Agent Configuration
|
|
// Used for both Cluster Agent and Fleet Agent configuration
|
|
export default {
|
|
components: {
|
|
Banner,
|
|
ContainerResourceLimit,
|
|
GroupPanel,
|
|
PodAffinity,
|
|
NodeAffinity,
|
|
RadioGroup,
|
|
Tolerations,
|
|
},
|
|
props: {
|
|
value: {
|
|
type: Object,
|
|
default: () => {},
|
|
},
|
|
|
|
mode: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
|
|
type: {
|
|
type: String,
|
|
required: true,
|
|
}
|
|
},
|
|
|
|
async fetch() {
|
|
// Default affinity
|
|
const settingId = `${ this.type }-agent-default-affinity`;
|
|
const setting = await fetchSetting(this.$store, settingId);
|
|
|
|
if (setting) {
|
|
try {
|
|
const parsed = JSON.parse(setting.value || setting.default);
|
|
|
|
this.defaultAffinity = parsed || {};
|
|
} catch (e) {
|
|
console.error('Could not parse agent default setting', e); // eslint-disable-line no-console
|
|
this.defaultAffinity = {};
|
|
}
|
|
}
|
|
},
|
|
|
|
data() {
|
|
const nodeAffinity = this.value?.overrideAffinity?.nodeAffinity;
|
|
const podAffinity = this.value?.overrideAffinity?.podAffinity;
|
|
const podAntiAffinity = this.value?.overrideAffinity?.podAntiAffinity;
|
|
|
|
let hasAffinityPopulated = false;
|
|
|
|
if ((nodeAffinity && Object.keys(nodeAffinity).length) ||
|
|
(podAffinity && Object.keys(podAffinity).length) ||
|
|
(podAntiAffinity && Object.keys(podAntiAffinity).length)) {
|
|
hasAffinityPopulated = true;
|
|
}
|
|
|
|
return {
|
|
defaultAffinity: {},
|
|
affinitySetting: hasAffinityPopulated ? CUSTOM : DEFAULT,
|
|
nodeAffinity: {}
|
|
};
|
|
},
|
|
|
|
created() {
|
|
this.ensureValue();
|
|
},
|
|
|
|
computed: {
|
|
flatResources: {
|
|
get() {
|
|
const { limits = {}, requests = {} } = this.value.overrideResourceRequirements || {};
|
|
const {
|
|
cpu: limitsCpu,
|
|
memory: limitsMemory,
|
|
} = limits;
|
|
const { cpu: requestsCpu, memory: requestsMemory } = requests;
|
|
|
|
return {
|
|
limitsCpu,
|
|
limitsMemory,
|
|
requestsCpu,
|
|
requestsMemory,
|
|
};
|
|
},
|
|
set(neu) {
|
|
const {
|
|
limitsCpu,
|
|
limitsMemory,
|
|
requestsCpu,
|
|
requestsMemory,
|
|
} = neu;
|
|
|
|
const existing = this.value?.overrideResourceRequirements || {};
|
|
|
|
delete existing.requests;
|
|
delete existing.limits;
|
|
|
|
const out = {
|
|
...existing,
|
|
requests: {
|
|
cpu: requestsCpu,
|
|
memory: requestsMemory,
|
|
},
|
|
limits: {
|
|
cpu: limitsCpu,
|
|
memory: limitsMemory,
|
|
},
|
|
};
|
|
|
|
this.$set(this.value, 'overrideResourceRequirements', cleanUp(out));
|
|
},
|
|
},
|
|
|
|
affinityOptions() {
|
|
return [{
|
|
label: this.t('cluster.agentConfig.affinity.default'),
|
|
value: DEFAULT,
|
|
}, {
|
|
label: this.t('cluster.agentConfig.affinity.custom'),
|
|
value: CUSTOM,
|
|
}];
|
|
},
|
|
|
|
canEditAffinity() {
|
|
return this.affinitySetting === CUSTOM;
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
value() {
|
|
this.ensureValue();
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
ensureValue() {
|
|
// Ensure we have the model structure needed for the form controls
|
|
if (this.value) {
|
|
this.value.overrideAffinity = this.value.overrideAffinity || {};
|
|
this.value.appendTolerations = this.value.appendTolerations || [];
|
|
this.value.overrideResourceRequirements = this.value.overrideResourceRequirements || {};
|
|
|
|
this.nodeAffinity = this.value?.overrideAffinity?.nodeAffinity || {};
|
|
}
|
|
},
|
|
|
|
affinitySettingChange() {
|
|
if (this.affinitySetting === CUSTOM) {
|
|
const parsedDefaultAffinites = JSON.parse(JSON.stringify(this.defaultAffinity));
|
|
|
|
// Copy the default so that the user can edit it
|
|
// this will cover the pod affinities
|
|
this.$set(this.value, 'overrideAffinity', parsedDefaultAffinites);
|
|
|
|
// in order not to break the node affinity component, let's go for a slightly different way of handling the logic here
|
|
if (parsedDefaultAffinites.nodeAffinity) {
|
|
this.nodeAffinity = parsedDefaultAffinites.nodeAffinity;
|
|
}
|
|
} else {
|
|
this.$set(this.value, 'overrideAffinity', {});
|
|
}
|
|
},
|
|
updateNodeAffinity(val) {
|
|
this.$set(this.value.overrideAffinity, 'nodeAffinity', val);
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<Banner
|
|
:closable="false"
|
|
color="info"
|
|
label-key="cluster.agentConfig.banners.advanced"
|
|
/>
|
|
|
|
<GroupPanel
|
|
label-key="cluster.agentConfig.groups.podRequestsAndLimits"
|
|
class="mt-20"
|
|
>
|
|
<Banner
|
|
:closable="false"
|
|
color="info"
|
|
label-key="cluster.agentConfig.banners.limits"
|
|
/>
|
|
<ContainerResourceLimit
|
|
v-model="flatResources"
|
|
:mode="mode"
|
|
:show-tip="false"
|
|
:handle-gpu-limit="false"
|
|
class="mt-10"
|
|
/>
|
|
</GroupPanel>
|
|
|
|
<GroupPanel
|
|
label-key="cluster.agentConfig.groups.podTolerations"
|
|
class="mt-20"
|
|
>
|
|
<Banner
|
|
:closable="false"
|
|
color="info"
|
|
label-key="cluster.agentConfig.banners.tolerations"
|
|
/>
|
|
<Tolerations
|
|
v-model="value.appendTolerations"
|
|
:mode="mode"
|
|
class="mt-10"
|
|
/>
|
|
</GroupPanel>
|
|
|
|
<GroupPanel
|
|
label-key="cluster.agentConfig.groups.podAffinity"
|
|
class="mt-20"
|
|
>
|
|
<RadioGroup
|
|
v-model="affinitySetting"
|
|
name="affinity-override"
|
|
:mode="mode"
|
|
:options="affinityOptions"
|
|
class="mt-10"
|
|
data-testid="affinity-options"
|
|
@input="affinitySettingChange"
|
|
/>
|
|
|
|
<Banner
|
|
v-if="canEditAffinity"
|
|
:closable="false"
|
|
color="warning"
|
|
>
|
|
<p v-clean-html="t('cluster.agentConfig.banners.windowsCompatibility', {}, true)" />
|
|
</Banner>
|
|
|
|
<h4 v-if="canEditAffinity">
|
|
{{ t('cluster.agentConfig.subGroups.podAffinityAnti') }}
|
|
</h4>
|
|
|
|
<PodAffinity
|
|
v-if="canEditAffinity"
|
|
v-model="value"
|
|
field="overrideAffinity"
|
|
:mode="mode"
|
|
class="mt-0 mb-20"
|
|
:all-namespaces-option-available="true"
|
|
:force-input-namespace-selection="true"
|
|
:remove-labeled-input-namespace-label="true"
|
|
data-testid="pod-affinity"
|
|
/>
|
|
|
|
<div
|
|
v-if="canEditAffinity"
|
|
class="separator"
|
|
/>
|
|
<h4
|
|
v-if="canEditAffinity"
|
|
class="mt-20"
|
|
>
|
|
{{ t('cluster.agentConfig.subGroups.nodeAffinity') }}
|
|
</h4>
|
|
|
|
<NodeAffinity
|
|
v-if="canEditAffinity"
|
|
v-model="nodeAffinity"
|
|
:matching-selector-display="true"
|
|
:mode="mode"
|
|
class="mt-0"
|
|
data-testid="node-affinity"
|
|
@input="updateNodeAffinity"
|
|
/>
|
|
</GroupPanel>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.separator {
|
|
width: 100%;
|
|
border-top: 1px solid var(--border);
|
|
}
|
|
</style>
|