+
+
+
diff --git a/pkg/harvester/config/doc-links.js b/pkg/harvester/config/doc-links.js
index dae259d5..754f06b3 100644
--- a/pkg/harvester/config/doc-links.js
+++ b/pkg/harvester/config/doc-links.js
@@ -4,6 +4,7 @@ export const DOC = {
RANCHER_INTEGRATION_URL: `/rancher/rancher-integration`,
KSMTUNED_MODE: `/host/#ksmtuned-mode`,
UPGRADE_URL: `/upgrade/index`,
+ UPGRADE_CONFIG_URL: `/advanced/index#upgrade-config`,
STORAGE_NETWORK_EXAMPLE: `/advanced/storagenetwork#configuration-example`,
SUPPORT_BUNDLE_NAMESPACES: `/advanced/index/#support-bundle-namespaces`,
};
diff --git a/pkg/harvester/config/feature-flags.js b/pkg/harvester/config/feature-flags.js
index 02fe176d..6899ac70 100644
--- a/pkg/harvester/config/feature-flags.js
+++ b/pkg/harvester/config/feature-flags.js
@@ -21,6 +21,7 @@ const FEATURE_FLAGS = {
'vmSnapshotQuota',
'longhornV2LVMSupport',
'improveMaintenanceMode',
+ 'upgradeConfigSetting'
],
'v1.4.1': [],
'v1.4.2': [
diff --git a/pkg/harvester/config/settings.ts b/pkg/harvester/config/settings.ts
index 792e72c8..160389e6 100644
--- a/pkg/harvester/config/settings.ts
+++ b/pkg/harvester/config/settings.ts
@@ -34,6 +34,7 @@ export const HCI_SETTING = {
KUBECONFIG_DEFAULT_TOKEN_TTL_MINUTES: 'kubeconfig-default-token-ttl-minutes',
LONGHORN_V2_DATA_ENGINE_ENABLED: 'longhorn-v2-data-engine-enabled',
ADDITIONAL_GUEST_MEMORY_OVERHEAD_RATIO: 'additional-guest-memory-overhead-ratio',
+ UPGRADE_CONFIG: 'upgrade-config',
};
export const HCI_ALLOWED_SETTINGS = {
@@ -96,6 +97,12 @@ export const HCI_ALLOWED_SETTINGS = {
featureFlag: 'longhornV2LVMSupport'
},
[HCI_SETTING.ADDITIONAL_GUEST_MEMORY_OVERHEAD_RATIO]: { kind: 'string', from: 'import' },
+ [HCI_SETTING.UPGRADE_CONFIG]: {
+ kind: 'json',
+ from: 'import',
+ featureFlag: 'upgradeConfigSetting',
+ docPath: 'UPGRADE_CONFIG_URL'
+ },
};
export const HCI_SINGLE_CLUSTER_ALLOWED_SETTING = {
diff --git a/pkg/harvester/edit/harvesterhci.io.setting.vue b/pkg/harvester/edit/harvesterhci.io.setting.vue
index 9257c407..4b53d5c8 100644
--- a/pkg/harvester/edit/harvesterhci.io.setting.vue
+++ b/pkg/harvester/edit/harvesterhci.io.setting.vue
@@ -6,6 +6,8 @@ import LabeledSelect from '@shell/components/form/LabeledSelect';
import { TextAreaAutoGrow } from '@components/Form/TextArea';
import UnitInput from '@shell/components/form/UnitInput';
import CreateEditView from '@shell/mixins/create-edit-view';
+import { DOC } from '../config/doc-links';
+import { docLink } from '../utils/feature-flags';
import { HCI_ALLOWED_SETTINGS, HCI_SINGLE_CLUSTER_ALLOWED_SETTING, HCI_SETTING } from '../config/settings';
@@ -58,7 +60,13 @@ export default {
return {
setting,
- description: isHarvester ? t(`advancedSettings.descriptions.harv-${ this.value.id }`) : t(`advancedSettings.descriptions.${ this.value.id }`),
+ description: isHarvester ? t(
+ `advancedSettings.descriptions.harv-${ this.value.id }`,
+ this.getDocLinkParams()
+ ) : t(
+ `advancedSettings.descriptions.${ this.value.id }`,
+ this.getDocLinkParams()
+ ),
editHelp: t(`advancedSettings.editHelp.${ this.value.id }`),
enumOptions,
canReset,
@@ -171,6 +179,18 @@ export default {
if (typeof this.$refs.settingComp?.useDefault === 'function') {
this.$refs.settingComp.useDefault();
}
+ },
+ getDocLinkParams() {
+ const setting = HCI_ALLOWED_SETTINGS[this.value.id] || HCI_SINGLE_CLUSTER_ALLOWED_SETTING[this.value.id];
+
+ if (setting?.docPath) {
+ const version = this.$store.getters['harvester-common/getServerVersion']();
+ const url = docLink(DOC[setting.docPath], version);
+
+ return { url };
+ }
+
+ return {};
}
}
};
diff --git a/pkg/harvester/l10n/en-us.yaml b/pkg/harvester/l10n/en-us.yaml
index 00bb201f..ba56a61b 100644
--- a/pkg/harvester/l10n/en-us.yaml
+++ b/pkg/harvester/l10n/en-us.yaml
@@ -694,7 +694,7 @@ harvester:
network:
label: Network Data Template
title: "Network Data:"
- tip: "The network-data configuration allows you to customize the instance’s networking interfaces by assigning subnet configuration, virtual device creation (bonds, bridges, VLANs) routes and DNS configuration. Learn more"
+ tip: "The network-data configuration allows you to customize the instance's networking interfaces by assigning subnet configuration, virtual device creation (bonds, bridges, VLANs) routes and DNS configuration. Learn more"
scheduling:
affinity:
anyNode: 'Run virtual machine on any available node'
@@ -1128,6 +1128,10 @@ harvester:
uploadSuccess: "{name} uploaded successfully. Press Upgrade button to start the cluster upgrade process."
deleteImage: Please select an image to delete.
deleteSuccess: "{name} deleted successfully."
+ imagePreloadStrategy: Image Preload Strategy
+ restoreVM: Restore VM
+ strategyType: Strategy Type
+ concurrency: Concurrency
harvesterMonitoring:
label: Harvester Monitoring
section:
@@ -1621,6 +1625,7 @@ advancedSettings:
'harv-kubeconfig-default-token-ttl-minutes': 'TTL (in minutes) applied on Harvester administration kubeconfig files. Default is 0, which means to never expire.'
'harv-longhorn-v2-data-engine-enabled': 'Enable the Longhorn V2 data engine. Default is false.
Changing this setting will restart RKE2 on all nodes. This will not affect running VM workloads.
If you see "not enough hugepages-2Mi capacity" errors when enabling this setting, wait a minute for the error to clear. If the error remains, reboot the affected node.
'
'harv-additional-guest-memory-overhead-ratio': 'The ratio for kubevirt to adjust the VM overhead memory. The value could be zero, empty value or floating number between 1.0 and 10.0, default to 1.5.'
+ 'harv-upgrade-config': 'Configure image preloading and VM restore options for upgrades. See related fields in settings/upgrade-config'
typeLabel:
kubevirt.io.virtualmachine: |-
diff --git a/pkg/harvester/list/harvesterhci.io.setting.vue b/pkg/harvester/list/harvesterhci.io.setting.vue
index 05edc170..4452ebcd 100644
--- a/pkg/harvester/list/harvesterhci.io.setting.vue
+++ b/pkg/harvester/list/harvesterhci.io.setting.vue
@@ -116,7 +116,15 @@ export default {
return {
...s,
description: isHarvester ? `advancedSettings.descriptions.harv-${ s.id }` : `advancedSettings.descriptions.${ s.id }`,
- customized: (!s.readOnly && s.data.value && s.data.value !== s.data.default) || s.data.hasCustomized
+ customized: (!s.readOnly && s.data.value && (
+ s.kind === 'json' ? (() => {
+ try {
+ return JSON.stringify(JSON.parse(s.data.value)) !== JSON.stringify(JSON.parse(s.data.default));
+ } catch {
+ return s.data.value !== s.data.default;
+ }
+ })() : s.data.value !== s.data.default
+ )) || s.data.hasCustomized
};
});
}