mirror of https://github.com/rancher/dashboard.git
663 lines
16 KiB
Vue
663 lines
16 KiB
Vue
<script>
|
|
import difference from 'lodash/difference';
|
|
import { mapGetters } from 'vuex';
|
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
|
import FormValidation from '@shell/mixins/form-validation';
|
|
|
|
import { set, get } from '@shell/utils/object';
|
|
import { Banner } from '@components/Banner';
|
|
import { Checkbox } from '@components/Form/Checkbox';
|
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
import YamlEditor from '@shell/components/YamlEditor';
|
|
import { LEGACY } from '@shell/store/features';
|
|
import semver from 'semver';
|
|
|
|
const HARVESTER = 'harvester';
|
|
|
|
export default {
|
|
components: {
|
|
Banner,
|
|
Checkbox,
|
|
LabeledSelect,
|
|
YamlEditor,
|
|
},
|
|
|
|
mixins: [CreateEditView, FormValidation],
|
|
|
|
props: {
|
|
mode: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
|
|
value: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
|
|
provider: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
|
|
psps: {
|
|
type: Object,
|
|
default: null,
|
|
required: false
|
|
},
|
|
|
|
credential: {
|
|
type: Object,
|
|
default: null,
|
|
required: false
|
|
},
|
|
|
|
userChartValues: {
|
|
type: Object,
|
|
required: true
|
|
},
|
|
cisOverride: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
|
|
cisPsaChangeBanner: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
allPsps: {
|
|
type: Array,
|
|
required: false,
|
|
default: null
|
|
},
|
|
allPsas: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
|
|
addonVersions: {
|
|
type: Array,
|
|
required: false,
|
|
default: null
|
|
},
|
|
needsPsp: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
selectedVersion: {
|
|
type: Object,
|
|
required: true
|
|
},
|
|
versionOptions: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
isHarvesterDriver: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
isHarvesterIncompatible: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
showDeprecatedPatchVersions: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
clusterIsAlreadyCreated: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
isElementalCluster: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
hasPsaTemplates: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
isK3s: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
haveArgInfo: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
showCni: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
showCloudProvider: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
unsupportedCloudProvider: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
cloudProviderOptions: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
},
|
|
|
|
computed: {
|
|
...mapGetters({ features: 'features/get' }),
|
|
|
|
/**
|
|
* Check presence of PSPs as template or CLI creation
|
|
*/
|
|
|
|
hasPsps() {
|
|
return !!this.psps?.count;
|
|
},
|
|
|
|
serverConfig() {
|
|
return this.value.spec.rkeConfig.machineGlobalConfig;
|
|
},
|
|
|
|
agentConfig() {
|
|
return this.value.agentConfig;
|
|
},
|
|
|
|
/**
|
|
* Define introduction of PSA and return need of PSA templates based on min k8s version
|
|
*/
|
|
needsPSA() {
|
|
const release = this.value?.spec?.kubernetesVersion || '';
|
|
const version = release.match(/\d+/g);
|
|
const isRequiredVersion = version?.length ? +version[0] > 1 || +version[1] >= 23 : false;
|
|
|
|
return isRequiredVersion;
|
|
},
|
|
|
|
profileOptions() {
|
|
const out = (this.agentArgs?.profile?.options || []).map((x) => {
|
|
return { label: x, value: x };
|
|
});
|
|
|
|
out.unshift({
|
|
label: this.$store.getters['i18n/t']('cluster.rke2.cisProfile.option'),
|
|
value: ''
|
|
});
|
|
|
|
return out;
|
|
},
|
|
|
|
/**
|
|
* Allow to display override if PSA is needed and profile is set
|
|
*/
|
|
hasCisOverride() {
|
|
return (this.serverConfig?.profile || this.agentConfig?.profile) && this.needsPSA &&
|
|
// Also check other cases on when to display the override
|
|
this.hasPsaTemplates && this.showCisProfile && this.isCisSupported;
|
|
},
|
|
|
|
pspOptions() {
|
|
if ( this.isK3s ) {
|
|
return null;
|
|
}
|
|
const out = [{
|
|
label: this.$store.getters['i18n/t']('cluster.rke2.defaultPodSecurityPolicyTemplateName.option'),
|
|
value: ''
|
|
}];
|
|
|
|
if ( this.allPsps ) {
|
|
for ( const pspt of this.allPsps ) {
|
|
out.push({
|
|
label: pspt.nameDisplay,
|
|
value: pspt.id,
|
|
});
|
|
}
|
|
}
|
|
const cur = this.value.spec.defaultPodSecurityPolicyTemplateName;
|
|
|
|
if ( cur && !out.find((x) => x.value === cur) ) {
|
|
out.unshift({ label: `${ cur } (Current)`, value: cur });
|
|
}
|
|
|
|
return out;
|
|
},
|
|
|
|
/**
|
|
* Disable PSA if CIS hardening is enabled, except override
|
|
*/
|
|
isPsaDisabled() {
|
|
const cisValue = this.agentConfig?.profile || this.serverConfig?.profile;
|
|
|
|
return !(!cisValue || this.cisOverride) && this.hasPsaTemplates && this.isCisSupported;
|
|
},
|
|
|
|
/**
|
|
* Get the default label for the PSA template option
|
|
*/
|
|
defaultPsaOptionLabel() {
|
|
const optionCase = !this.needsPsp && !this.isK3s ? 'default' : 'none';
|
|
|
|
return this.$store.getters['i18n/t'](`cluster.rke2.defaultPodSecurityAdmissionConfigurationTemplateName.option.${ optionCase }`);
|
|
},
|
|
|
|
/**
|
|
* Convert PSA templates into options, sorting and flagging if any selected
|
|
*/
|
|
psaOptions() {
|
|
if ( !this.needsPSA ) {
|
|
return [];
|
|
}
|
|
const out = [{
|
|
label: this.defaultPsaOptionLabel,
|
|
value: ''
|
|
}];
|
|
|
|
if ( this.allPsas ) {
|
|
for ( const psa of this.allPsas ) {
|
|
out.push({
|
|
label: psa.nameDisplay,
|
|
value: psa.id,
|
|
});
|
|
}
|
|
}
|
|
const cur = this.value.spec.defaultPodSecurityAdmissionConfigurationTemplateName;
|
|
|
|
if ( cur && !out.find((x) => x.value === cur) ) {
|
|
out.unshift({ label: `${ cur } (Current)`, value: cur });
|
|
}
|
|
|
|
return out;
|
|
},
|
|
|
|
/**
|
|
* Check if current CIS profile is required and listed in the options
|
|
*/
|
|
isCisSupported() {
|
|
const cisProfile = this.serverConfig.profile || this.agentConfig.profile;
|
|
|
|
return !cisProfile || this.profileOptions.map((option) => option.value).includes(cisProfile);
|
|
},
|
|
|
|
disableOptions() {
|
|
return (this.serverArgs.disable.options || []).map((value) => {
|
|
return {
|
|
label: this.$store.getters['i18n/withFallback'](`cluster.${ this.isK3s ? 'k3s' : 'rke2' }.systemService."${ value }"`, null, value.replace(/^(rke2|rancher)-/, '')),
|
|
value,
|
|
};
|
|
});
|
|
},
|
|
|
|
serverArgs() {
|
|
return this.selectedVersion?.serverArgs || {};
|
|
},
|
|
|
|
agentArgs() {
|
|
return this.selectedVersion?.agentArgs || {};
|
|
},
|
|
|
|
/**
|
|
* The addons (kube charts) applicable for the selected kube version
|
|
*
|
|
* { [chartName:string]: { repo: string, version: string } }
|
|
*/
|
|
chartVersions() {
|
|
return this.selectedVersion?.charts || {};
|
|
},
|
|
|
|
showCisProfile() {
|
|
return (this.provider === 'custom' || this.isElementalCluster) && ( this.serverArgs?.profile || this.agentArgs?.profile );
|
|
},
|
|
|
|
enabledSystemServices: {
|
|
get() {
|
|
const out = difference(this.serverArgs.disable.options, this.serverConfig.disable || []);
|
|
|
|
return out;
|
|
},
|
|
|
|
set(neu) {
|
|
const out = difference(this.serverArgs.disable.options, neu);
|
|
|
|
this.$emit('enabled-system-services-changed', out);
|
|
},
|
|
},
|
|
|
|
showCloudConfigYaml() {
|
|
if ( !this.agentArgs['cloud-provider-name'] ) {
|
|
return false;
|
|
}
|
|
|
|
const name = this.agentConfig['cloud-provider-name'];
|
|
|
|
if ( !name ) {
|
|
return false;
|
|
}
|
|
|
|
switch ( name ) {
|
|
case 'none': return false;
|
|
case 'aws': return false;
|
|
case 'rancher-vsphere': return false;
|
|
case HARVESTER: return false;
|
|
default: return true;
|
|
}
|
|
},
|
|
|
|
showVsphereNote() {
|
|
if ( !this.agentArgs['cloud-provider-name'] ) {
|
|
return false;
|
|
}
|
|
|
|
const name = this.agentConfig['cloud-provider-name'];
|
|
|
|
return name === 'rancher-vsphere';
|
|
},
|
|
|
|
showk8s21LegacyWarning() {
|
|
const isLegacyEnabled = this.features(LEGACY);
|
|
|
|
if (!isLegacyEnabled) {
|
|
return false;
|
|
}
|
|
const selectedVersion = semver.coerce(this.value.spec.kubernetesVersion);
|
|
|
|
return semver.satisfies(selectedVersion, '>=1.21.0');
|
|
},
|
|
|
|
ciliumIpv6: {
|
|
get() {
|
|
// eslint-disable-next-line no-unused-vars
|
|
const cni = this.serverConfig.cni; // force this property to recalculate if cni was changed away from cilium and chartValues['rke-cilium'] deleted
|
|
|
|
return this.userChartValues[this.chartVersionKey('rke2-cilium')]?.cilium?.ipv6?.enabled || false;
|
|
},
|
|
set(val) {
|
|
this.$emit('cilium-ipv6-changed', val);
|
|
}
|
|
},
|
|
|
|
canNotEditCloudProvider() {
|
|
const canNotEdit = this.clusterIsAlreadyCreated && !this.unsupportedCloudProvider;
|
|
|
|
return canNotEdit;
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
set,
|
|
|
|
chartVersionKey(name) {
|
|
const addonVersion = this.addonVersions.find((av) => av.name === name);
|
|
|
|
return addonVersion ? `${ name }-${ addonVersion.version }` : name;
|
|
},
|
|
get,
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<Banner
|
|
v-if="!haveArgInfo"
|
|
color="warning"
|
|
:label="t('cluster.banner.haveArgInfo')"
|
|
/>
|
|
<Banner
|
|
v-if="showk8s21LegacyWarning"
|
|
color="warning"
|
|
:label="t('cluster.legacyWarning')"
|
|
/>
|
|
<Banner
|
|
v-if="isHarvesterDriver && isHarvesterIncompatible && showCloudProvider"
|
|
color="warning"
|
|
>
|
|
<span
|
|
v-clean-html="t('cluster.harvester.warning.cloudProvider.incompatible', null, true)"
|
|
/>
|
|
</Banner>
|
|
<div class="row mb-10">
|
|
<div class="col span-6">
|
|
<LabeledSelect
|
|
v-model="value.spec.kubernetesVersion"
|
|
:mode="mode"
|
|
:options="versionOptions"
|
|
label-key="cluster.kubernetesVersion.label"
|
|
@input="$emit('kubernetes-changed', $event)"
|
|
/>
|
|
<Checkbox
|
|
:value="showDeprecatedPatchVersions"
|
|
:label="t('cluster.kubernetesVersion.deprecatedPatches')"
|
|
:tooltip="t('cluster.kubernetesVersion.deprecatedPatchWarning')"
|
|
class="patch-version"
|
|
@input="$emit('show-deprecated-patch-versions-changed', $event)"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-if="showCloudProvider"
|
|
class="col span-6"
|
|
>
|
|
<LabeledSelect
|
|
v-model="agentConfig['cloud-provider-name']"
|
|
:mode="mode"
|
|
:disabled="canNotEditCloudProvider"
|
|
:options="cloudProviderOptions"
|
|
:label="t('cluster.rke2.cloudProvider.label')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="showCni"
|
|
:style="{'align-items':'center'}"
|
|
class="row"
|
|
>
|
|
<div class="col span-6">
|
|
<LabeledSelect
|
|
v-model="serverConfig.cni"
|
|
:mode="mode"
|
|
:disabled="clusterIsAlreadyCreated"
|
|
:options="serverArgs.cni.options"
|
|
:label="t('cluster.rke2.cni.label')"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-if="serverConfig.cni === 'cilium' || serverConfig.cni === 'multus,cilium'"
|
|
class="col"
|
|
>
|
|
<Checkbox
|
|
v-model="ciliumIpv6"
|
|
:mode="mode"
|
|
:label="t('cluster.rke2.address.ipv6.enable')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<template v-if="showVsphereNote">
|
|
<Banner
|
|
color="warning"
|
|
label-key="cluster.cloudProvider.rancher-vsphere.note"
|
|
/>
|
|
</template>
|
|
<template v-else-if="showCloudConfigYaml">
|
|
<div class="spacer" />
|
|
|
|
<div class="col span-12">
|
|
<Banner
|
|
v-if="unsupportedCloudProvider"
|
|
class="error mt-5"
|
|
>
|
|
{{ t('cluster.rke2.cloudProvider.unsupported') }}
|
|
</Banner>
|
|
<h3>
|
|
{{ t('cluster.rke2.cloudProvider.header') }}
|
|
</h3>
|
|
<YamlEditor
|
|
ref="yaml"
|
|
v-model="agentConfig['cloud-provider-config']"
|
|
:editor-mode="mode === 'view' ? 'VIEW_CODE' : 'EDIT_CODE'"
|
|
initial-yaml-values="# Cloud Provider Config"
|
|
class="yaml-editor"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="spacer" />
|
|
|
|
<h3>
|
|
{{ t('cluster.rke2.security.header') }}
|
|
</h3>
|
|
<Banner
|
|
v-if="isEdit && !needsPsp && hasPsps"
|
|
color="warning"
|
|
:label="t('cluster.banner.invalidPsps')"
|
|
/>
|
|
<Banner
|
|
v-else-if="isCreate && !needsPsp"
|
|
color="info"
|
|
:label="t('cluster.banner.removedPsp')"
|
|
/>
|
|
<Banner
|
|
v-else-if="isCreate && hasPsps"
|
|
color="info"
|
|
:label="t('cluster.banner.deprecatedPsp')"
|
|
/>
|
|
|
|
<Banner
|
|
v-if="showCisProfile && !isCisSupported && isEdit"
|
|
color="info"
|
|
>
|
|
<p v-clean-html="t('cluster.rke2.banner.cisUnsupported', {cisProfile: serverConfig.profile || agentConfig.profile}, true)" />
|
|
</Banner>
|
|
|
|
<div class="row mb-10">
|
|
<div
|
|
v-if="pspOptions && needsPsp"
|
|
class="col span-6"
|
|
>
|
|
<!-- PSP template selector -->
|
|
<LabeledSelect
|
|
v-model="value.spec.defaultPodSecurityPolicyTemplateName"
|
|
data-testid="rke2-custom-edit-psp"
|
|
:mode="mode"
|
|
:options="pspOptions"
|
|
:label="t('cluster.rke2.defaultPodSecurityPolicyTemplateName.label')"
|
|
@input="$emit('psp-changed', $event)"
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
v-if="showCisProfile"
|
|
class="col span-6"
|
|
>
|
|
<LabeledSelect
|
|
v-if="serverArgs && serverArgs.profile"
|
|
v-model="serverConfig.profile"
|
|
:mode="mode"
|
|
:options="profileOptions"
|
|
:label="t('cluster.rke2.cis.sever')"
|
|
@input="$emit('cis-changed')"
|
|
/>
|
|
<LabeledSelect
|
|
v-else-if="agentArgs && agentArgs.profile"
|
|
v-model="agentConfig.profile"
|
|
data-testid="rke2-custom-edit-cis-agent"
|
|
:mode="mode"
|
|
:options="profileOptions"
|
|
:label="t('cluster.rke2.cis.agent')"
|
|
@input="$emit('cis-changed')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<template v-if="hasCisOverride">
|
|
<Checkbox
|
|
v-model="cisOverride"
|
|
:mode="mode"
|
|
:label="t('cluster.rke2.cis.override')"
|
|
@input="$emit('psa-default-changed')"
|
|
/>
|
|
|
|
<Banner
|
|
v-if="cisOverride"
|
|
color="warning"
|
|
:label="t('cluster.rke2.banner.cisOverride')"
|
|
/>
|
|
<Banner
|
|
v-if="cisPsaChangeBanner && !cisOverride"
|
|
color="info"
|
|
:label="t('cluster.rke2.banner.psaChange')"
|
|
/>
|
|
</template>
|
|
|
|
<div
|
|
v-if="needsPSA"
|
|
class="row mb-10 mt-10"
|
|
>
|
|
<div class="col span-6">
|
|
<!-- PSA template selector -->
|
|
<LabeledSelect
|
|
v-model="value.spec.defaultPodSecurityAdmissionConfigurationTemplateName"
|
|
:mode="mode"
|
|
data-testid="rke2-custom-edit-psa"
|
|
:options="psaOptions"
|
|
:disabled="isPsaDisabled"
|
|
:label="t('cluster.rke2.defaultPodSecurityAdmissionConfigurationTemplateName.label')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col span-12 mt-20">
|
|
<Checkbox
|
|
v-if="serverArgs['secrets-encryption']"
|
|
v-model="serverConfig['secrets-encryption']"
|
|
:mode="mode"
|
|
:label="t('cluster.rke2.secretEncryption.label')"
|
|
/>
|
|
<Checkbox
|
|
v-model="value.spec.enableNetworkPolicy"
|
|
:mode="mode"
|
|
:label="t('cluster.rke2.enableNetworkPolicy.label')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
v-if="serverConfig.cni === 'cilium' && value.spec.enableNetworkPolicy"
|
|
class="row"
|
|
>
|
|
<div class="col span-12">
|
|
<Banner
|
|
color="info"
|
|
:label="t('cluster.rke2.enableNetworkPolicy.warning')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="spacer" />
|
|
|
|
<div
|
|
v-if="serverArgs.disable"
|
|
class="row"
|
|
>
|
|
<div class="col span-12">
|
|
<div>
|
|
<h3>
|
|
{{ t('cluster.rke2.systemService.header') }}
|
|
</h3>
|
|
</div>
|
|
<Checkbox
|
|
v-for="opt in disableOptions"
|
|
:key="opt.value"
|
|
v-model="enabledSystemServices"
|
|
:mode="mode"
|
|
:label="opt.label"
|
|
:value-when-true="opt.value"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.patch-version {
|
|
margin-top: 5px;
|
|
}
|
|
</style>
|