mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2025-12-13 21:21:44 +00:00
* feat: Remove guest cluster in Rancher Signed-off-by: Nick Chung <nick.chung@suse.com> * feat: add feature flag 1.6.0 Signed-off-by: Nick Chung <nick.chung@suse.com> * feat: update for review Signed-off-by: Nick Chung <nick.chung@suse.com> * chore: fix for review Signed-off-by: Nick Chung <nick.chung@suse.com> * chore: fix for review Signed-off-by: Nick Chung <nick.chung@suse.com> * refactor: reduce redundant code Signed-off-by: Andy Lee <andy.lee@suse.com> * chore: change text area to yaml editor Signed-off-by: Nick Chung <nick.chung@suse.com> * refactor: change radio and yaml editor position Signed-off-by: Andy Lee <andy.lee@suse.com> --------- Signed-off-by: Nick Chung <nick.chung@suse.com> Signed-off-by: Andy Lee <andy.lee@suse.com> Co-authored-by: Andy Lee <andy.lee@suse.com>
215 lines
6.0 KiB
Vue
215 lines
6.0 KiB
Vue
<script>
|
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
|
import { RadioGroup } from '@components/Form/Radio';
|
|
import { SECRET } from '@shell/config/types';
|
|
import { exceptionToErrorsArray } from '@shell/utils/error';
|
|
import FileSelector, { createOnSelected } from '@shell/components/form/FileSelector';
|
|
import YamlEditor from '@shell/components/YamlEditor';
|
|
|
|
export default {
|
|
name: 'HarvesterRancherCluster',
|
|
|
|
components: {
|
|
RadioGroup,
|
|
FileSelector,
|
|
YamlEditor
|
|
},
|
|
|
|
mixins: [CreateEditView],
|
|
|
|
props: {
|
|
value: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
registerBeforeHook: {
|
|
type: Function,
|
|
required: false,
|
|
default: () => {},
|
|
},
|
|
},
|
|
|
|
data() {
|
|
let parseDefaultValue = {};
|
|
|
|
try {
|
|
const data = this.value.value || this.value.default || '{}';
|
|
const parsed = JSON.parse(data);
|
|
|
|
parseDefaultValue = {
|
|
kubeConfig: '',
|
|
removeUpstreamClusterWhenNamespaceIsDeleted: parsed.removeUpstreamClusterWhenNamespaceIsDeleted || false
|
|
};
|
|
} catch (error) {
|
|
parseDefaultValue = {
|
|
kubeConfig: '',
|
|
removeUpstreamClusterWhenNamespaceIsDeleted: false
|
|
};
|
|
}
|
|
|
|
return {
|
|
parseDefaultValue,
|
|
errors: [],
|
|
existingSecret: null,
|
|
};
|
|
},
|
|
|
|
async created() {
|
|
await this.checkExistingSecret();
|
|
if (this.registerBeforeHook) {
|
|
this.registerBeforeHook(this.willSave, 'willSave');
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
onKeySelected: createOnSelected('parseDefaultValue.kubeConfig'),
|
|
|
|
update() {
|
|
if (this.parseDefaultValue.removeUpstreamClusterWhenNamespaceIsDeleted) {
|
|
this.value['value'] = JSON.stringify({ removeUpstreamClusterWhenNamespaceIsDeleted: true });
|
|
} else {
|
|
this.value['value'] = this.value.default || '{}';
|
|
}
|
|
},
|
|
|
|
async checkExistingSecret() {
|
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
|
|
await this.$store.dispatch(`${ inStore }/findAll`, { type: SECRET });
|
|
const secrets = this.$store.getters[`${ inStore }/all`](SECRET) || [];
|
|
|
|
this.existingSecret = secrets.find((secret) => secret.metadata.name === 'rancher-cluster-config' &&
|
|
secret.metadata.namespace === 'harvester-system'
|
|
);
|
|
|
|
// If the secret exists and has data, populate the kubeConfig
|
|
if (this.existingSecret?.data?.kubeConfig) {
|
|
const decodedContent = atob(this.existingSecret.data.kubeConfig);
|
|
|
|
this.parseDefaultValue.kubeConfig = decodedContent;
|
|
this.$nextTick(() => {
|
|
this.update();
|
|
});
|
|
}
|
|
},
|
|
|
|
async createOrUpdateRancherKubeConfigSecret() {
|
|
this.errors = [];
|
|
// Check if kubeConfig is provided
|
|
if (!this.parseDefaultValue.kubeConfig) {
|
|
this.errors.push(this.t('validation.required', { key: this.t('harvester.setting.rancherCluster.kubeConfig') }, true));
|
|
|
|
return Promise.reject(this.errors);
|
|
}
|
|
|
|
try {
|
|
let secret;
|
|
|
|
if (this.existingSecret) {
|
|
secret = this.existingSecret;
|
|
secret.setData('kubeConfig', this.parseDefaultValue.kubeConfig);
|
|
} else {
|
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
|
|
secret = await this.$store.dispatch(`${ inStore }/create`, {
|
|
apiVersion: 'v1',
|
|
kind: 'Secret',
|
|
metadata: {
|
|
name: 'rancher-cluster-config',
|
|
namespace: 'harvester-system'
|
|
},
|
|
type: 'secret',
|
|
data: { kubeConfig: btoa(this.parseDefaultValue.kubeConfig) }
|
|
});
|
|
}
|
|
await secret.save();
|
|
|
|
return Promise.resolve();
|
|
} catch (err) {
|
|
this.errors = exceptionToErrorsArray(err);
|
|
|
|
return Promise.reject(this.errors);
|
|
}
|
|
},
|
|
|
|
async deleteRancherKubeConfigSecret() {
|
|
if (this.existingSecret) {
|
|
this.existingSecret.remove();
|
|
}
|
|
},
|
|
|
|
async willSave() {
|
|
// Only create or update secret if enabled
|
|
if (this.parseDefaultValue.removeUpstreamClusterWhenNamespaceIsDeleted) {
|
|
await this.createOrUpdateRancherKubeConfigSecret();
|
|
} else {
|
|
await this.deleteRancherKubeConfigSecret();
|
|
}
|
|
|
|
return Promise.resolve();
|
|
},
|
|
|
|
useDefault() {
|
|
this.parseDefaultValue = {
|
|
kubeConfig: '',
|
|
removeUpstreamClusterWhenNamespaceIsDeleted: false
|
|
};
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
'parseDefaultValue.removeUpstreamClusterWhenNamespaceIsDeleted'(val, oldVal) {
|
|
if (val && !oldVal && this.existingSecret?.data?.kubeConfig) {
|
|
// Populate kubeConfig with the existing secret value
|
|
this.parseDefaultValue.kubeConfig = atob(this.existingSecret.data.kubeConfig);
|
|
}
|
|
},
|
|
'parseDefaultValue.kubeConfig'(val) {
|
|
this.$refs.yaml?.updateValue(val);
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<div class="row mt-20">
|
|
<div class="col span-12">
|
|
<RadioGroup
|
|
v-model:value="parseDefaultValue.removeUpstreamClusterWhenNamespaceIsDeleted"
|
|
:label="t('harvester.setting.rancherCluster.removeUpstreamClusterWhenNamespaceIsDeleted')"
|
|
name="removeUpstreamClusterWhenNamespaceIsDeleted"
|
|
:options="[true, false]"
|
|
:labels="[t('generic.enabled'), t('generic.disabled')]"
|
|
@update:value="update"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="parseDefaultValue.removeUpstreamClusterWhenNamespaceIsDeleted"
|
|
class="row mt-20"
|
|
>
|
|
<div class="col span-12">
|
|
<FileSelector
|
|
class="btn btn-sm bg-primary mb-10"
|
|
:label="t('generic.readFromFile')"
|
|
@selected="onKeySelected"
|
|
/>
|
|
<YamlEditor
|
|
ref="yaml"
|
|
v-model:value="parseDefaultValue.kubeConfig"
|
|
class="yaml-editor"
|
|
:editor-mode="mode === 'view' ? 'VIEW_CODE' : 'EDIT_CODE'"
|
|
@update:value="update"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
:deep(textarea) {
|
|
overflow-y: auto !important;
|
|
}
|
|
</style>
|