mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-08-16 12:49:14 +00:00
* feat: allow suer give static IP for VM * feat: add feature flag --------- (cherry picked from commit 531ed03796c9263523dc5ae866ccb3bc1906510d) Signed-off-by: Andy Lee <andy.lee@suse.com> Co-authored-by: Andy Lee <andy.lee@suse.com>
This commit is contained in:
parent
94566b2b54
commit
a067751cba
@ -73,7 +73,8 @@ const FEATURE_FLAGS = {
|
|||||||
'supportFilesystem',
|
'supportFilesystem',
|
||||||
'disableResourcePooling',
|
'disableResourcePooling',
|
||||||
'expandOnlineEncryptedVolume',
|
'expandOnlineEncryptedVolume',
|
||||||
'longhornV2HugepageSettings'
|
'longhornV2HugepageSettings',
|
||||||
|
'staticIPForVM',
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -81,6 +81,7 @@ export const HCI = {
|
|||||||
VOLUME_MODE_ACCESS_MODES: 'cdi.harvesterhci.io/storageProfileVolumeModeAccessModes',
|
VOLUME_MODE_ACCESS_MODES: 'cdi.harvesterhci.io/storageProfileVolumeModeAccessModes',
|
||||||
VOLUME_SNAPSHOT_CLASS: 'cdi.harvesterhci.io/storageProfileVolumeSnapshotClass',
|
VOLUME_SNAPSHOT_CLASS: 'cdi.harvesterhci.io/storageProfileVolumeSnapshotClass',
|
||||||
MAC_ADDRESS: 'harvesterhci.io/mac-address',
|
MAC_ADDRESS: 'harvesterhci.io/mac-address',
|
||||||
|
STATIC_IP: 'static-ip.harvesterhci.io',
|
||||||
NODE_UPGRADE_PAUSE_MAP: 'harvesterhci.io/node-upgrade-pause-map',
|
NODE_UPGRADE_PAUSE_MAP: 'harvesterhci.io/node-upgrade-pause-map',
|
||||||
CDI_POPULATOR_KIND: 'cdi.kubevirt.io/storage.populator.kind',
|
CDI_POPULATOR_KIND: 'cdi.kubevirt.io/storage.populator.kind',
|
||||||
CNI_NETWORKS: 'k8s.v1.cni.cncf.io/networks',
|
CNI_NETWORKS: 'k8s.v1.cni.cncf.io/networks',
|
||||||
|
|||||||
@ -133,6 +133,10 @@ export default {
|
|||||||
}];
|
}];
|
||||||
|
|
||||||
return this.isMasquerade ? masquerade : other;
|
return this.isMasquerade ? masquerade : other;
|
||||||
|
},
|
||||||
|
|
||||||
|
staticIPForVMEnabled() {
|
||||||
|
return this.$store.getters['harvester-common/getFeatureEnabled']('staticIPForVM');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -150,6 +154,7 @@ export default {
|
|||||||
isSingle(neu) {
|
isSingle(neu) {
|
||||||
if (!neu) {
|
if (!neu) {
|
||||||
this.value['macAddress'] = '';
|
this.value['macAddress'] = '';
|
||||||
|
this.value['staticIp'] = '';
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,6 +168,7 @@ export default {
|
|||||||
if (neu === MANAGEMENT_NETWORK) {
|
if (neu === MANAGEMENT_NETWORK) {
|
||||||
this.value.isPod = true;
|
this.value.isPod = true;
|
||||||
this.value.macAddress = '';
|
this.value.macAddress = '';
|
||||||
|
this.value.staticIp = '';
|
||||||
} else {
|
} else {
|
||||||
this.value.isPod = false;
|
this.value.isPod = false;
|
||||||
}
|
}
|
||||||
@ -289,9 +295,30 @@ export default {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div
|
||||||
|
v-if="showAdvanced"
|
||||||
|
class="row"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="staticIPForVMEnabled"
|
||||||
|
data-testid="input-hen-staticIp"
|
||||||
|
class="col span-6"
|
||||||
|
>
|
||||||
|
<InputOrDisplay
|
||||||
|
:name="t('harvester.fields.staticIp')"
|
||||||
|
:value="value.staticIp"
|
||||||
|
:mode="mode"
|
||||||
|
>
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="value.staticIp"
|
||||||
|
label-key="harvester.fields.staticIp"
|
||||||
|
:mode="mode"
|
||||||
|
:tooltip="t('harvester.virtualMachine.volume.staticIpTip', { nic_name: value.name || 'default' })"
|
||||||
|
@update:value="update"
|
||||||
|
/>
|
||||||
|
</InputOrDisplay>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="showAdvanced"
|
|
||||||
data-testid="input-hen-macAddress"
|
data-testid="input-hen-macAddress"
|
||||||
class="col span-6"
|
class="col span-6"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -36,6 +36,10 @@ export default {
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
ips() {
|
ips() {
|
||||||
|
if (this.staticAnnotationIP.length) {
|
||||||
|
return this.staticAnnotationIP;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.vmiIp.length) {
|
if (this.vmiIp.length) {
|
||||||
return [...this.vmiIp, ...this.networkAnnotationIP]
|
return [...this.vmiIp, ...this.networkAnnotationIP]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
@ -45,6 +49,24 @@ export default {
|
|||||||
return this.customAnnotationIP;
|
return this.customAnnotationIP;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
staticAnnotationIP() {
|
||||||
|
const annotations = this.row?.metadata?.annotations || {};
|
||||||
|
const staticIpPrefix = `${ HCI_ANNOTATIONS.STATIC_IP }/`;
|
||||||
|
|
||||||
|
return Object.entries(annotations)
|
||||||
|
.filter(([key, value]) => key.startsWith(staticIpPrefix) && !!value)
|
||||||
|
.map(([key, value]) => {
|
||||||
|
const nicName = key.slice(staticIpPrefix.length);
|
||||||
|
const ip = String(value).replace(/\/[\d\D]*/, '');
|
||||||
|
|
||||||
|
return {
|
||||||
|
ip,
|
||||||
|
name: nicName
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(({ ip }) => isIpv4(ip));
|
||||||
|
},
|
||||||
|
|
||||||
customAnnotationIP() {
|
customAnnotationIP() {
|
||||||
const annotationIp = get(this.row, `metadata.annotations."${ HCI_ANNOTATIONS.CUSTOM_IP }"`);
|
const annotationIp = get(this.row, `metadata.annotations."${ HCI_ANNOTATIONS.CUSTOM_IP }"`);
|
||||||
|
|
||||||
|
|||||||
@ -376,6 +376,7 @@ harvester:
|
|||||||
network: Network
|
network: Network
|
||||||
model: Model
|
model: Model
|
||||||
macAddress: MAC address
|
macAddress: MAC address
|
||||||
|
staticIp: Static IP
|
||||||
port: Port
|
port: Port
|
||||||
protocol: Protocol
|
protocol: Protocol
|
||||||
remove: Remove
|
remove: Remove
|
||||||
@ -750,6 +751,7 @@ harvester:
|
|||||||
dragTip: Drag and drop volumes, or use the volume's arrows, to change the boot order.
|
dragTip: Drag and drop volumes, or use the volume's arrows, to change the boot order.
|
||||||
volumeTip: The virtual machine only contains a CD-ROM volume. You may want to add additional disk volumes.
|
volumeTip: The virtual machine only contains a CD-ROM volume. You may want to add additional disk volumes.
|
||||||
macTip: "MAC address as seen inside the guest system."
|
macTip: "MAC address as seen inside the guest system."
|
||||||
|
staticIpTip: "Static IP that will be stored to annotation static-ip.harvesterhci.io/{nic_name}."
|
||||||
volumeUpdate: 'Set volume { name } successfully'
|
volumeUpdate: 'Set volume { name } successfully'
|
||||||
type: Type
|
type: Type
|
||||||
size: Size
|
size: Size
|
||||||
|
|||||||
@ -630,6 +630,8 @@ export default {
|
|||||||
|
|
||||||
const networks = vm.spec.template.spec.networks || [];
|
const networks = vm.spec.template.spec.networks || [];
|
||||||
const interfaces = vm.spec.template.spec.domain.devices.interfaces || [];
|
const interfaces = vm.spec.template.spec.domain.devices.interfaces || [];
|
||||||
|
const annotations = vm.metadata?.annotations || {};
|
||||||
|
const staticIpPrefix = `${ HCI_ANNOTATIONS.STATIC_IP }/`;
|
||||||
|
|
||||||
const out = interfaces.map( (I, index) => {
|
const out = interfaces.map( (I, index) => {
|
||||||
const network = networks.find( (N) => I.name === N.name);
|
const network = networks.find( (N) => I.name === N.name);
|
||||||
@ -646,6 +648,7 @@ export default {
|
|||||||
newCreateId: (fromTemplate || init) ? randomStr(10) : false,
|
newCreateId: (fromTemplate || init) ? randomStr(10) : false,
|
||||||
model: I.model,
|
model: I.model,
|
||||||
networkName: isPod ? MANAGEMENT_NETWORK : network?.multus?.networkName,
|
networkName: isPod ? MANAGEMENT_NETWORK : network?.multus?.networkName,
|
||||||
|
staticIp: annotations[`${ staticIpPrefix }${ I.name }`] || '',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -747,6 +750,8 @@ export default {
|
|||||||
|
|
||||||
const vm = this.resourceType === HCI.VM ? this.value : this.value.spec.vm;
|
const vm = this.resourceType === HCI.VM ? this.value : this.value.spec.vm;
|
||||||
|
|
||||||
|
this.syncStaticIpAnnotations(vm);
|
||||||
|
|
||||||
// parse reserved memory
|
// parse reserved memory
|
||||||
if (!this.reservedMemory) {
|
if (!this.reservedMemory) {
|
||||||
delete vm.metadata.annotations[HCI_ANNOTATIONS.VM_RESERVED_MEMORY];
|
delete vm.metadata.annotations[HCI_ANNOTATIONS.VM_RESERVED_MEMORY];
|
||||||
@ -768,6 +773,30 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
syncStaticIpAnnotations(vm) {
|
||||||
|
if (!vm?.metadata) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vm.metadata.annotations) {
|
||||||
|
vm.metadata.annotations = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const staticIpPrefix = `${ HCI_ANNOTATIONS.STATIC_IP }/`;
|
||||||
|
|
||||||
|
Object.keys(vm.metadata.annotations).forEach((key) => {
|
||||||
|
if (key.startsWith(staticIpPrefix)) {
|
||||||
|
delete vm.metadata.annotations[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.networkRows.forEach((row) => {
|
||||||
|
if (row.name && row.staticIp) {
|
||||||
|
vm.metadata.annotations[`${ staticIpPrefix }${ row.name }`] = row.staticIp;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
setCPUAndMemory() {
|
setCPUAndMemory() {
|
||||||
if (this.cpuMemoryHotplugEnabled) {
|
if (this.cpuMemoryHotplugEnabled) {
|
||||||
// set CPU
|
// set CPU
|
||||||
@ -1807,6 +1836,15 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
networkRows: {
|
||||||
|
handler() {
|
||||||
|
const vm = this.resourceType === HCI.VM ? this.value : this.value?.spec?.vm;
|
||||||
|
|
||||||
|
this.syncStaticIpAnnotations(vm);
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
|
||||||
diskRows: {
|
diskRows: {
|
||||||
handler(neu, old) {
|
handler(neu, old) {
|
||||||
if (Array.isArray(neu)) {
|
if (Array.isArray(neu)) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user