mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-10-01 03:36:04 +08:00
Latest changes from harvester/master
Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import { BadgeState } from '@components/BadgeState';
|
||||
import { Banner } from '@components/Banner';
|
||||
import { RadioGroup, RadioButton } from '@components/Form/Radio';
|
||||
import HarvesterDisk from '../../mixins/harvester-disk';
|
||||
import DiskTags from '../../components/DiskTags';
|
||||
import Tags from '../../components/DiskTags';
|
||||
import { HCI } from '../../types';
|
||||
import { LONGHORN_SYSTEM } from './index';
|
||||
|
||||
@@ -17,7 +17,7 @@ export default {
|
||||
Banner,
|
||||
RadioGroup,
|
||||
RadioButton,
|
||||
DiskTags,
|
||||
Tags,
|
||||
},
|
||||
|
||||
mixins: [
|
||||
@@ -44,6 +44,18 @@ export default {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
targetDisk() {
|
||||
return this.disks.find(disk => disk.name === this.value.name);
|
||||
},
|
||||
schedulableTooltipMessage() {
|
||||
const { name, path } = this.value;
|
||||
|
||||
if (this.targetDisk && !this.targetDisk.allowScheduling && name && path) {
|
||||
return this.t('harvester.host.disk.allowScheduling.tooltip', { name, path });
|
||||
} else {
|
||||
return this.schedulableCondition.message;
|
||||
}
|
||||
},
|
||||
allowSchedulingOptions() {
|
||||
return [{
|
||||
label: this.t('generic.enabled'),
|
||||
@@ -171,7 +183,7 @@ export default {
|
||||
<div v-if="!value.isNew">
|
||||
<div class="row">
|
||||
<div class="col span-12">
|
||||
<DiskTags
|
||||
<Tags
|
||||
v-model:value="value.tags"
|
||||
:label="t('harvester.host.disk.tags.label')"
|
||||
:add-label="t('harvester.host.disk.tags.addLabel')"
|
||||
@@ -181,6 +193,16 @@ export default {
|
||||
</div>
|
||||
<div class="row mt-10">
|
||||
<div class="col span-12">
|
||||
<div class="pull-left">
|
||||
<RadioGroup
|
||||
v-model:value="value.allowScheduling"
|
||||
name="diskScheduling"
|
||||
:label="t('harvester.host.disk.allowScheduling.label')"
|
||||
:mode="mode"
|
||||
:options="allowSchedulingOptions"
|
||||
:row="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
{{ t('harvester.host.disk.conditions') }}:
|
||||
<BadgeState
|
||||
@@ -191,9 +213,9 @@ export default {
|
||||
class="mr-10 ml-10 state"
|
||||
/>
|
||||
<BadgeState
|
||||
v-clean-tooltip="schedulableCondition.message"
|
||||
:color="schedulableCondition.status === 'True' ? 'bg-success' : 'bg-error' "
|
||||
:icon="schedulableCondition.status === 'True' ? 'icon-checkmark' : 'icon-warning' "
|
||||
v-clean-tooltip="schedulableTooltipMessage"
|
||||
:color="schedulableCondition.status === 'True' && targetDisk?.allowScheduling ? 'bg-success' : 'bg-error' "
|
||||
:icon="schedulableCondition.status === 'True' && targetDisk?.allowScheduling ? 'icon-checkmark' : 'icon-warning' "
|
||||
label="Schedulable"
|
||||
class="mr-10 state"
|
||||
/>
|
||||
|
||||
@@ -5,6 +5,7 @@ import UnitInput from '@shell/components/form/UnitInput';
|
||||
import { RadioGroup } from '@components/Form/Radio';
|
||||
import { Checkbox } from '@components/Form/Checkbox';
|
||||
import { HCI } from '../../types';
|
||||
import { DOC_LINKS } from '../../config/doc-links';
|
||||
|
||||
export const ksmtunedMode = [{
|
||||
value: 'standard',
|
||||
@@ -86,6 +87,10 @@ export default {
|
||||
|
||||
showKsmt() {
|
||||
return this.spec.run === 'run';
|
||||
},
|
||||
|
||||
ksmtunedLink() {
|
||||
return DOC_LINKS.KSMTUNED_MODE;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -135,7 +140,7 @@ export default {
|
||||
<Checkbox v-model:value="enableMergeAcrossNodes" :mode="mode" class="check mb-20" type="checkbox" :label="t('harvester.host.ksmtuned.enableMergeNodes')" />
|
||||
|
||||
<h3>
|
||||
<t k="harvester.host.ksmtuned.modeLink" :raw="true" />
|
||||
<t k="harvester.host.ksmtuned.modeLink" :raw="true" :url="ksmtunedLink" />
|
||||
</h3>
|
||||
<RadioGroup
|
||||
v-model:value="spec.mode"
|
||||
|
||||
@@ -25,10 +25,10 @@ import { _EDIT } from '@shell/config/query-params';
|
||||
import { sortBy } from '@shell/utils/sort';
|
||||
import { Banner } from '@components/Banner';
|
||||
import { HCI } from '../../types';
|
||||
import DiskTags from '../../components/DiskTags';
|
||||
import HarvesterDisk from './HarvesterDisk';
|
||||
import HarvesterSeeder from './HarvesterSeeder';
|
||||
import HarvesterKsmtuned from './HarvesterKsmtuned';
|
||||
import Tags from '../../components/DiskTags';
|
||||
|
||||
export const LONGHORN_SYSTEM = 'longhorn-system';
|
||||
|
||||
@@ -46,7 +46,7 @@ export default {
|
||||
ButtonDropdown,
|
||||
KeyValue,
|
||||
Banner,
|
||||
DiskTags,
|
||||
Tags,
|
||||
Loading,
|
||||
HarvesterSeeder,
|
||||
MessageLink,
|
||||
@@ -478,10 +478,11 @@ export default {
|
||||
|
||||
const disks = this.longhornNode?.spec?.disks || {};
|
||||
|
||||
// update each disk tags and scheduling
|
||||
this.newDisks.map((disk) => {
|
||||
(disks[disk.name] || {}).tags = disk.tags;
|
||||
(disks[disk.name] || {}).allowScheduling = disk.allowScheduling;
|
||||
});
|
||||
|
||||
let count = 0;
|
||||
|
||||
const retrySave = async() => {
|
||||
@@ -505,7 +506,9 @@ export default {
|
||||
}
|
||||
};
|
||||
|
||||
await retrySave();
|
||||
if (this.longhornNode) {
|
||||
await retrySave();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -547,7 +550,7 @@ export default {
|
||||
class="row mb-20"
|
||||
>
|
||||
<div class="col span-12">
|
||||
<DiskTags
|
||||
<Tags
|
||||
v-model:value="longhornNode.spec.tags"
|
||||
:label="t('harvester.host.tags.label')"
|
||||
:add-label="t('harvester.host.tags.addLabel')"
|
||||
@@ -650,7 +653,6 @@ export default {
|
||||
:value="filteredLabels"
|
||||
:add-label="t('labels.addLabel')"
|
||||
:mode="mode"
|
||||
:title="t('labels.labels.title')"
|
||||
:read-allowed="false"
|
||||
:value-can-be-empty="true"
|
||||
@update:value="updateHostLabels"
|
||||
|
||||
@@ -143,10 +143,19 @@ export default {
|
||||
},
|
||||
|
||||
input(neu) {
|
||||
const pattern = /^([1-9]|[1-9][0-9]{1,2}|[1-3][0-9]{3}|40[0-9][0-4])$/;
|
||||
if (neu === '') {
|
||||
this.config.vlan = '';
|
||||
|
||||
if (!pattern.test(neu) && neu !== '') {
|
||||
this.config.vlan = neu > 4094 ? 4094 : 1;
|
||||
return;
|
||||
}
|
||||
const newValue = Number(neu);
|
||||
|
||||
if (newValue > 4094) {
|
||||
this.config.vlan = 4094;
|
||||
} else if (newValue < 1) {
|
||||
this.config.vlan = 1;
|
||||
} else {
|
||||
this.config.vlan = newValue;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { STORAGE_CLASS, LONGHORN } from '@shell/config/types';
|
||||
import { allHash } from '@shell/utils/promise';
|
||||
import { clone } from '@shell/utils/object';
|
||||
import { CSI_DRIVER } from '../../types';
|
||||
import DiskTags from '../../components/DiskTags';
|
||||
import Tags from '../../components/DiskTags';
|
||||
|
||||
const LONGHORN_DRIVER = 'driver.longhorn.io';
|
||||
|
||||
@@ -34,7 +34,7 @@ export default {
|
||||
Tab,
|
||||
Tabbed,
|
||||
Loading,
|
||||
DiskTags,
|
||||
Tags,
|
||||
},
|
||||
|
||||
mixins: [CreateEditView],
|
||||
@@ -304,7 +304,7 @@ export default {
|
||||
/>
|
||||
</div>
|
||||
<div class="col span-8 value">
|
||||
<DiskTags
|
||||
<Tags
|
||||
v-model:value="scope.row.value.values"
|
||||
:add-label="t('generic.add')"
|
||||
:mode="modeOverride"
|
||||
|
||||
@@ -162,6 +162,7 @@ export default {
|
||||
buttonCb(false);
|
||||
}
|
||||
} else {
|
||||
this.value.spec.url = this.value.spec.url?.trim() || '';
|
||||
this.save(buttonCb);
|
||||
}
|
||||
},
|
||||
@@ -277,6 +278,7 @@ export default {
|
||||
:can-yaml="showEditAsYaml ? true : false"
|
||||
:apply-hooks="applyHooks"
|
||||
@finish="saveImage"
|
||||
@error="e=>errors=e"
|
||||
>
|
||||
<NameNsDescription
|
||||
ref="nd"
|
||||
|
||||
@@ -18,7 +18,6 @@ import { HCI as HCI_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations
|
||||
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||
import { AFTER_SAVE_HOOKS } from '@shell/mixins/child-hook';
|
||||
import { HCI } from '../types';
|
||||
import { RunStrategys } from '../config/harvester-map';
|
||||
import VM_MIXIN from '../mixins/harvester-vm';
|
||||
import Reserved from './kubevirt.io.virtualmachine/VirtualMachineReserved';
|
||||
import Volume from './kubevirt.io.virtualmachine/VirtualMachineVolume';
|
||||
@@ -74,7 +73,6 @@ export default {
|
||||
description: '',
|
||||
defaultVersion: null,
|
||||
isDefaultVersion: false,
|
||||
RunStrategys,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -263,7 +261,7 @@ export default {
|
||||
<Tab
|
||||
name="nodeScheduling"
|
||||
:label="t('workload.container.titles.nodeScheduling')"
|
||||
:weight="-89"
|
||||
:weight="-3"
|
||||
>
|
||||
<template #default="{active}">
|
||||
<NodeScheduling
|
||||
@@ -274,7 +272,7 @@ export default {
|
||||
</template>
|
||||
</Tab>
|
||||
|
||||
<Tab :label="t('harvester.tab.vmScheduling')" name="vmScheduling" :weight="-90">
|
||||
<Tab :label="t('harvester.tab.vmScheduling')" name="vmScheduling" :weight="-4">
|
||||
<template #default="{active}">
|
||||
<PodAffinity
|
||||
:mode="mode"
|
||||
@@ -287,13 +285,42 @@ export default {
|
||||
</template>
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
:name="t('generic.labels')"
|
||||
:label="t('harvester.tab.instanceLabel')"
|
||||
:weight="-5"
|
||||
>
|
||||
<Labels
|
||||
:default-container-class="'labels-and-annotations-container'"
|
||||
:value="value"
|
||||
:mode="mode"
|
||||
:display-side-by-side="false"
|
||||
:show-annotations="false"
|
||||
:show-label-title="false"
|
||||
>
|
||||
<template #labels="{toggler}">
|
||||
<KeyValue
|
||||
key="labels"
|
||||
:value="value.instanceLabels"
|
||||
:protected-keys="value.systemLabels || []"
|
||||
:toggle-filter="toggler"
|
||||
:add-label="t('labels.addLabel')"
|
||||
:mode="mode"
|
||||
:read-allowed="false"
|
||||
:value-can-be-empty="true"
|
||||
@input="value.setInstanceLabels($event)"
|
||||
/>
|
||||
</template>
|
||||
</Labels>
|
||||
</Tab>
|
||||
|
||||
<Tab name="advanced" :label="t('harvester.tab.advanced')" :weight="-99">
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<LabeledSelect
|
||||
v-model:value="runStrategy"
|
||||
label-key="harvester.virtualMachine.runStrategy"
|
||||
:options="RunStrategys"
|
||||
:options="runStrategies"
|
||||
:mode="mode"
|
||||
/>
|
||||
</div>
|
||||
@@ -308,6 +335,37 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<LabeledSelect
|
||||
v-model:value="maintenanceStrategy"
|
||||
label-key="harvester.virtualMachine.maintenanceStrategy.label"
|
||||
:options="maintenanceStrategies"
|
||||
:get-option-label="getMaintenanceStrategyOptionLabel"
|
||||
:mode="mode"
|
||||
/>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<Reserved
|
||||
:reserved-memory="reservedMemory"
|
||||
:mode="mode"
|
||||
@updateReserved="updateReserved"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<Checkbox
|
||||
v-model:value="cpuPinning"
|
||||
class="check"
|
||||
type="checkbox"
|
||||
label-key="harvester.virtualMachine.cpuPinning.label"
|
||||
:mode="mode"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-20">
|
||||
<a v-if="showAdvanced" v-t="'harvester.generic.showMore'" role="button" @click="toggleAdvanced" />
|
||||
<a v-else v-t="'harvester.generic.showMore'" role="button" @click="toggleAdvanced" />
|
||||
@@ -315,13 +373,6 @@ export default {
|
||||
|
||||
<div v-if="showAdvanced">
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<Reserved
|
||||
:reserved-memory="reservedMemory"
|
||||
:mode="mode"
|
||||
@updateReserved="updateReserved"
|
||||
/>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<UnitInput
|
||||
v-model:value="terminationGracePeriodSeconds"
|
||||
@@ -386,35 +437,6 @@ export default {
|
||||
:mode="mode"
|
||||
/>
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
:name="t('generic.labels')"
|
||||
:label="t('harvester.tab.instanceLabel')"
|
||||
:weight="-99"
|
||||
>
|
||||
<Labels
|
||||
:default-container-class="'labels-and-annotations-container'"
|
||||
:value="value"
|
||||
:mode="mode"
|
||||
:display-side-by-side="false"
|
||||
:show-annotations="false"
|
||||
:show-label-title="false"
|
||||
>
|
||||
<template #labels="{toggler}">
|
||||
<KeyValue
|
||||
key="labels"
|
||||
:value="value.instanceLabels"
|
||||
:protected-keys="value.systemLabels || []"
|
||||
:toggle-filter="toggler"
|
||||
:add-label="t('labels.addLabel')"
|
||||
:mode="mode"
|
||||
:read-allowed="false"
|
||||
:value-can-be-empty="true"
|
||||
@update:value="value.setInstanceLabels($event)"
|
||||
/>
|
||||
</template>
|
||||
</Labels>
|
||||
</Tab>
|
||||
</Tabbed>
|
||||
</CruResource>
|
||||
</template>
|
||||
|
||||
@@ -56,6 +56,7 @@ export default {
|
||||
const hash = await allHash(_hash);
|
||||
|
||||
this.snapshots = hash.snapshots;
|
||||
this.images = hash.images;
|
||||
|
||||
const defaultStorage = this.$store.getters[`harvester/all`](STORAGE_CLASS).find( O => O.isDefault);
|
||||
|
||||
@@ -77,6 +78,7 @@ export default {
|
||||
storage,
|
||||
imageId,
|
||||
snapshots: [],
|
||||
images: [],
|
||||
};
|
||||
},
|
||||
|
||||
@@ -108,10 +110,8 @@ export default {
|
||||
},
|
||||
|
||||
imageOption() {
|
||||
const choices = this.$store.getters['harvester/all'](HCI.IMAGE);
|
||||
|
||||
return sortBy(
|
||||
choices
|
||||
this.images
|
||||
.filter(obj => obj.isReady)
|
||||
.map((obj) => {
|
||||
return {
|
||||
@@ -249,7 +249,17 @@ export default {
|
||||
|
||||
this.value['spec'] = spec;
|
||||
},
|
||||
updateImage() {
|
||||
if (this.isVMImage && this.imageId) {
|
||||
const imageResource = this.images?.find(image => this.imageId === image.id);
|
||||
const imageSize = Math.max(imageResource?.status?.size, imageResource?.status?.virtualSize);
|
||||
|
||||
if (imageSize) {
|
||||
this.storage = `${ Math.ceil(imageSize / 1024 / 1024 / 1024) }Gi`;
|
||||
}
|
||||
}
|
||||
this.update();
|
||||
},
|
||||
generateYaml() {
|
||||
const out = saferDump(this.value);
|
||||
|
||||
@@ -300,7 +310,7 @@ export default {
|
||||
required
|
||||
:mode="mode"
|
||||
class="mb-20"
|
||||
@update:value="update"
|
||||
@update:value="updateImage"
|
||||
/>
|
||||
|
||||
<LabeledSelect
|
||||
|
||||
+16
-7
@@ -140,15 +140,24 @@ export default {
|
||||
|
||||
onImageChange() {
|
||||
const imageResource = this.$store.getters['harvester/all'](HCI.IMAGE)?.find( I => this.value.image === I.id);
|
||||
const isIsoImage = /iso$/i.test(imageResource?.imageSuffix);
|
||||
const imageSize = Math.max(imageResource?.status?.size, imageResource?.status?.virtualSize);
|
||||
|
||||
if (this.idx === 0) {
|
||||
if (/iso$/i.test(imageResource?.imageSuffix)) {
|
||||
this.value['type'] = 'cd-rom';
|
||||
this.value['bus'] = 'sata';
|
||||
} else {
|
||||
this.value['type'] = 'disk';
|
||||
this.value['bus'] = 'virtio';
|
||||
if (isIsoImage) {
|
||||
this.value['type'] = 'cd-rom';
|
||||
this.value['bus'] = 'sata';
|
||||
} else {
|
||||
this.value['type'] = 'disk';
|
||||
this.value['bus'] = 'virtio';
|
||||
}
|
||||
|
||||
if (imageSize) {
|
||||
let imageSizeGiB = Math.ceil(imageSize / 1024 / 1024 / 1024);
|
||||
|
||||
if (!isIsoImage) {
|
||||
imageSizeGiB = Math.max(imageSizeGiB, 10);
|
||||
}
|
||||
this.value['size'] = `${ imageSizeGiB }Gi`;
|
||||
}
|
||||
|
||||
this.update();
|
||||
|
||||
@@ -28,7 +28,6 @@ import CreateEditView from '@shell/mixins/create-edit-view';
|
||||
|
||||
import { parseVolumeClaimTemplates } from '@pkg/utils/vm';
|
||||
import VM_MIXIN from '../../mixins/harvester-vm';
|
||||
import { RunStrategys } from '../../config/harvester-map';
|
||||
import { HCI } from '../../types';
|
||||
import RestartVMDialog from '../../dialog/RestartVMDialog';
|
||||
import VirtualMachineVGpuDevices from './VirtualMachineVGpuDevices/index';
|
||||
@@ -40,6 +39,8 @@ import Network from './VirtualMachineNetwork';
|
||||
import Volume from './VirtualMachineVolume';
|
||||
import SSHKey from './VirtualMachineSSHKey';
|
||||
import Reserved from './VirtualMachineReserved';
|
||||
import { Banner } from '@components/Banner';
|
||||
import MessageLink from '@shell/components/MessageLink';
|
||||
|
||||
export default {
|
||||
name: 'HarvesterEditVM',
|
||||
@@ -68,6 +69,8 @@ export default {
|
||||
UnitInput,
|
||||
VirtualMachineVGpuDevices,
|
||||
KeyValue,
|
||||
Banner,
|
||||
MessageLink
|
||||
},
|
||||
|
||||
mixins: [CreateEditView, VM_MIXIN],
|
||||
@@ -96,13 +99,19 @@ export default {
|
||||
isOpen: false,
|
||||
hostname,
|
||||
isRestartImmediately,
|
||||
RunStrategys,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters({ t: 'i18n/t' }),
|
||||
|
||||
to() {
|
||||
return {
|
||||
name: 'harvester-c-cluster-resource',
|
||||
params: { cluster: this.$store.getters['clusterId'], resource: HCI.HOST },
|
||||
};
|
||||
},
|
||||
|
||||
machineTypeOptions() {
|
||||
return [{
|
||||
label: 'None',
|
||||
@@ -173,6 +182,26 @@ export default {
|
||||
hasStartAction() {
|
||||
return this.value.hasAction('start');
|
||||
},
|
||||
|
||||
enableCpuPinningCheckbox() {
|
||||
if (this.mode === 'create') {
|
||||
return this.nodes.some(node => node.isCPUManagerEnabled); // any one of nodes has label cpuManager=true
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
showCpuPinningBanner() {
|
||||
if (this.mode === 'edit') {
|
||||
return this.cpuPinning !== !!this.cloneVM.spec.template.spec.domain.cpu.dedicatedCpuPlacement;
|
||||
}
|
||||
|
||||
if (this.mode === 'create') {
|
||||
return this.nodes.every(node => !node.isCPUManagerEnabled); // no node enabled CPU manager
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
@@ -273,6 +302,15 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
cancelAction() {
|
||||
const { fromPage = HCI.VM } = this.$route?.query; // default back to VM list page
|
||||
const cancelOverride = {
|
||||
name: this.doneRoute,
|
||||
params: { resource: fromPage }
|
||||
};
|
||||
|
||||
this.$router.replace(cancelOverride);
|
||||
},
|
||||
saveVM(buttonCb) {
|
||||
clear(this.errors);
|
||||
|
||||
@@ -437,12 +475,14 @@ export default {
|
||||
id="vm"
|
||||
:done-route="doneRoute"
|
||||
:resource="value"
|
||||
:cancelEvent="true"
|
||||
:mode="mode"
|
||||
:can-yaml="isSingle ? true : false"
|
||||
:errors="errors"
|
||||
:generate-yaml="generateYaml"
|
||||
:apply-hooks="applyHooks"
|
||||
@finish="saveVM"
|
||||
@cancel="cancelAction"
|
||||
>
|
||||
<RadioGroup
|
||||
v-if="isCreate"
|
||||
@@ -606,44 +646,54 @@ export default {
|
||||
/>
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
v-if="enabledSriovgpu"
|
||||
:label="t('harvester.tab.vGpuDevices')"
|
||||
name="vGpuDevices"
|
||||
:weight="-6"
|
||||
>
|
||||
<VirtualMachineVGpuDevices
|
||||
:mode="mode"
|
||||
:value="spec.template.spec"
|
||||
:vm="value"
|
||||
/>
|
||||
<Tab v-if="enabledSriovgpu" :label="t('harvester.tab.vGpuDevices')" name="vGpuDevices" :weight="-6">
|
||||
<VirtualMachineVGpuDevices :mode="mode" :value="spec.template.spec" :vm="value" />
|
||||
</Tab>
|
||||
|
||||
<Tab v-if="isEdit" :label="t('harvester.tab.accessCredentials')" name="accessCredentials" :weight="-7">
|
||||
<AccessCredentials v-model:value="accessCredentials" :mode="mode" :resource="value" :is-qemu-installed="isQemuInstalled" />
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
v-if="isEdit"
|
||||
:label="t('harvester.tab.accessCredentials')"
|
||||
name="accessCredentials"
|
||||
:weight="-7"
|
||||
name="instanceLabel"
|
||||
:label="t('harvester.tab.instanceLabel')"
|
||||
:weight="-8"
|
||||
>
|
||||
<AccessCredentials
|
||||
v-model:value="accessCredentials"
|
||||
<Labels
|
||||
:default-container-class="'labels-and-annotations-container'"
|
||||
:value="value"
|
||||
:mode="mode"
|
||||
:resource="value"
|
||||
:is-qemu-installed="isQemuInstalled"
|
||||
/>
|
||||
:display-side-by-side="false"
|
||||
:show-annotations="false"
|
||||
:show-label-title="false"
|
||||
>
|
||||
<template #labels="{toggler}">
|
||||
<KeyValue
|
||||
key="labels"
|
||||
:value="value.instanceLabels"
|
||||
:protected-keys="value.systemLabels || []"
|
||||
:toggle-filter="toggler"
|
||||
:add-label="t('labels.addLabel')"
|
||||
:mode="mode"
|
||||
:read-allowed="false"
|
||||
:value-can-be-empty="true"
|
||||
@update:value="value.setInstanceLabels($event)"
|
||||
/>
|
||||
</template>
|
||||
</Labels>
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
name="advanced"
|
||||
:label="t('harvester.tab.advanced')"
|
||||
:weight="-8"
|
||||
:weight="-9"
|
||||
>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<LabeledSelect
|
||||
v-model:value="runStrategy"
|
||||
label-key="harvester.virtualMachine.runStrategy"
|
||||
:options="RunStrategys"
|
||||
:options="runStrategies"
|
||||
:mode="mode"
|
||||
/>
|
||||
</div>
|
||||
@@ -659,24 +709,30 @@ export default {
|
||||
</div>
|
||||
|
||||
<div class="row mb-20">
|
||||
<a
|
||||
v-if="showAdvanced"
|
||||
v-t="'harvester.generic.showMore'"
|
||||
role="button"
|
||||
@click="toggleAdvanced"
|
||||
/>
|
||||
<a
|
||||
v-else
|
||||
v-t="'harvester.generic.showMore'"
|
||||
role="button"
|
||||
@click="toggleAdvanced"
|
||||
/>
|
||||
<div class="col span-6">
|
||||
<LabeledSelect
|
||||
v-model:value="maintenanceStrategy"
|
||||
label-key="harvester.virtualMachine.maintenanceStrategy.label"
|
||||
:options="maintenanceStrategies"
|
||||
:get-option-label="getMaintenanceStrategyOptionLabel"
|
||||
:mode="mode"
|
||||
/>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<Reserved
|
||||
:reserved-memory="reservedMemory"
|
||||
:mode="mode"
|
||||
@updateReserved="updateReserved"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="showAdvanced"
|
||||
class="mb-20"
|
||||
>
|
||||
<div class="row mb-20">
|
||||
<a v-if="showAdvanced" v-t="'harvester.generic.showMore'" role="button" @click="toggleAdvanced" />
|
||||
<a v-else v-t="'harvester.generic.showMore'" role="button" @click="toggleAdvanced" />
|
||||
</div>
|
||||
|
||||
<div v-if="showAdvanced" class="mb-20">
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<LabeledInput
|
||||
@@ -698,13 +754,6 @@ export default {
|
||||
</div>
|
||||
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<Reserved
|
||||
:reserved-memory="reservedMemory"
|
||||
:mode="mode"
|
||||
@updateReserved="updateReserved"
|
||||
/>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<UnitInput
|
||||
v-model:value="terminationGracePeriodSeconds"
|
||||
@@ -730,6 +779,16 @@ export default {
|
||||
@updateDataTemplateId="updateDataTemplateId"
|
||||
/>
|
||||
|
||||
<Checkbox
|
||||
v-model:value="cpuPinning"
|
||||
:disabled="!enableCpuPinningCheckbox"
|
||||
class="check"
|
||||
type="checkbox"
|
||||
tooltip-key="harvester.virtualMachine.cpuPinning.tooltip"
|
||||
label-key="harvester.virtualMachine.cpuPinning.label"
|
||||
:mode="mode"
|
||||
/>
|
||||
|
||||
<Checkbox
|
||||
v-model:value="installUSBTablet"
|
||||
class="check mt-20"
|
||||
@@ -773,35 +832,21 @@ export default {
|
||||
:label="t('harvester.virtualMachine.secureBoot')"
|
||||
:mode="mode"
|
||||
/>
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
name="instanceLabel"
|
||||
:label="t('harvester.tab.instanceLabel')"
|
||||
:weight="-99"
|
||||
>
|
||||
<Labels
|
||||
:default-container-class="'labels-and-annotations-container'"
|
||||
:value="value"
|
||||
:mode="mode"
|
||||
:display-side-by-side="false"
|
||||
:show-annotations="false"
|
||||
:show-label-title="false"
|
||||
<Banner
|
||||
v-if="showCpuPinningBanner"
|
||||
color="warning"
|
||||
>
|
||||
<template #labels="{toggler}">
|
||||
<KeyValue
|
||||
key="labels"
|
||||
:value="value.instanceLabels"
|
||||
:protected-keys="value.systemLabels || []"
|
||||
:toggle-filter="toggler"
|
||||
:add-label="t('labels.addLabel')"
|
||||
:mode="mode"
|
||||
:read-allowed="false"
|
||||
:value-can-be-empty="true"
|
||||
@update:value="value.setInstanceLabels($event)"
|
||||
/>
|
||||
</template>
|
||||
</Labels>
|
||||
<MessageLink
|
||||
v-if="mode === 'create'"
|
||||
:to="to"
|
||||
prefix-label="harvester.virtualMachine.advancedOptions.cpuManager.prefix"
|
||||
middle-label="harvester.virtualMachine.advancedOptions.cpuManager.middle"
|
||||
suffix-label="harvester.virtualMachine.advancedOptions.cpuManager.suffix"
|
||||
/>
|
||||
<span v-if="mode==='edit'">
|
||||
{{ t('harvester.virtualMachine.cpuPinning.restartVMMessage') }}
|
||||
</span>
|
||||
</Banner>
|
||||
</Tab>
|
||||
</Tabbed>
|
||||
|
||||
|
||||
@@ -314,12 +314,21 @@ export default {
|
||||
} else if (selector[HOSTNAME] && Object.keys(selector).length === 1) {
|
||||
const matchNode = allNodes.find(n => n.id === selector[HOSTNAME]);
|
||||
|
||||
this.matchingNodes = {
|
||||
matched: 1,
|
||||
total: allNodes.length,
|
||||
none: false,
|
||||
sample: matchNode ? matchNode.nameDisplay : selector[HOSTNAME],
|
||||
};
|
||||
if (matchNode) {
|
||||
this.matchingNodes = {
|
||||
matched: 1,
|
||||
total: allNodes.length,
|
||||
none: false,
|
||||
sample: matchNode.nameDisplay,
|
||||
};
|
||||
} else {
|
||||
this.matchingNodes = {
|
||||
matched: 0,
|
||||
total: 0,
|
||||
none: true,
|
||||
sample: null,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
const match = matching(allNodes, selector);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user