Compare commits

..
Author SHA1 Message Date
Yiya Chen 2aaa0a55a2 feat: add default value (#548)
Signed-off-by: Yi-Ya Chen <yiya.chen@suse.com>
2025-10-09 13:37:06 +08:00
Andy Lee 5c2a23924d fix: allow to edit as yaml if has empty CPU or memory (#547)
* fix: allow edit as yaml in create VM page if empty CPU or memory

Signed-off-by: Andy Lee <andy.lee@suse.com>

* refactor: remove getCPUMemoryValidation

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
2025-10-08 16:11:27 +08:00
Yiya Chen 7af8a82838 feat: remove machine type dropdown (#546)
Signed-off-by: Yi-Ya Chen <yiya.chen@suse.com>
2025-10-08 13:41:35 +08:00
Caio Torres 3b343bcaca fix: create new secret on vm creation (#537)
Signed-off-by: Caio Torres <caio.torres@suse.com>
2025-10-07 17:23:18 +08:00
renovate[bot] 6ddd35d661 deps: update dependency @types/node to v20.19.19 (#542)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-07 12:01:21 +08:00
Andy Lee bd28ba6f71 feat: add network policy page (#536)
* feat: add Network Policiies page

Signed-off-by: Andy Lee <andy.lee@suse.com>

* ci: add build

Signed-off-by: Andy Lee <andy.lee@suse.com>

* ci: ensure FROM and TO exist

Signed-off-by: Andy Lee <andy.lee@suse.com>

* ci: skip commitlint if FROM and TO emtpy

Signed-off-by: Andy Lee <andy.lee@suse.com>

* revert: unnecessary change

* feat: add banner

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
2025-10-03 09:38:31 +08:00
Andy Lee 4bb67153ce fix: set maxSockets : 1 if not enabled cpuMemoryhotplug (#539) 2025-10-02 17:50:16 +08:00
12 changed files with 119 additions and 40 deletions
+1
View File
@@ -50,6 +50,7 @@ jobs:
echo "FROM=$FROM"
echo "TO=$TO"
npx commitlint --from "$FROM" --to "$TO" --verbose
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
+1
View File
@@ -8,4 +8,5 @@ export const DOC = {
STORAGE_NETWORK_EXAMPLE: `/advanced/storagenetwork#configuration-example`,
SUPPORT_BUNDLE_NAMESPACES: `/advanced/index/#support-bundle-namespaces`,
VPC_CONFIGURATION_EXAMPLES: `/networking/kubeovn-vpc#vpc-peering-configuration-examples`,
NETWORK_POLICY: `/networking/kubeovn-vm-isolation/#network-policies`,
};
+3 -2
View File
@@ -39,7 +39,6 @@ const FEATURE_FLAGS = {
],
'v1.5.1': [],
'v1.6.0': [
'vmMachineTypes',
'customSupportBundle',
'csiOnlineExpandValidation',
'vmNetworkMigration',
@@ -50,7 +49,9 @@ const FEATURE_FLAGS = {
'vmCloneRunStrategy',
],
'v1.6.1': [],
'v1.7.0': []
'v1.7.0': [
'vmMachineTypeAuto'
]
};
const generateFeatureFlags = () => {
+17
View File
@@ -10,6 +10,7 @@ import {
LOGGING,
STORAGE_CLASS,
SECRET,
NETWORK_POLICY
} from '@shell/config/types';
import { HCI, VOLUME_SNAPSHOT } from '../types';
import {
@@ -425,6 +426,7 @@ export function init($plugin, store) {
HCI.CLUSTER_NETWORK,
HCI.NETWORK_ATTACHMENT,
HCI.VPC,
NETWORK_POLICY,
HCI.LB,
HCI.IP_POOL,
],
@@ -566,6 +568,21 @@ export function init($plugin, store) {
ifHaveType: HCI.VPC,
});
configureType(NETWORK_POLICY, { hiddenNamespaceGroupButton: true, canYaml: false });
virtualType({
labelKey: 'harvester.networkPolicy.label',
name: NETWORK_POLICY,
namespaced: true,
weight: 186,
route: {
name: `${ PRODUCT_NAME }-c-cluster-resource`,
params: { resource: NETWORK_POLICY }
},
exact: false,
ifHaveType: NETWORK_POLICY,
});
configureType(HCI.SNAPSHOT, {
isCreatable: false,
location: {
@@ -338,6 +338,15 @@ export default {
saveVM(buttonCb) {
clear(this.errors);
this.validateCPUMemory();
// block create VM flow if has validation errors
if (this.errors.length) {
buttonCb(false);
return;
}
if (this.isSingle) {
this.saveSingle(buttonCb);
} else {
@@ -345,6 +354,18 @@ export default {
}
},
validateCPUMemory() {
const { cpu, memory } = this;
if ((!cpu)) {
this.errors.push(this.t('validation.required', { key: this.t('harvester.virtualMachine.input.cpu') }, true));
}
if ((!memory)) {
this.errors.push(this.t('validation.required', { key: this.t('harvester.virtualMachine.input.memory') }, true));
}
},
async saveSingle(buttonCb) {
this.parseVM();
this.value.spec.template.spec.hostname = this.hostname ? this.hostname : this.value.metadata.name;
@@ -466,9 +487,7 @@ export default {
}
}
const cpuMemoryErrors = this.getCPUMemoryValidation();
const accessCredentialsErrors = this.getAccessCredentialsValidation();
const errors = [...cpuMemoryErrors, ...accessCredentialsErrors];
const errors = this.getAccessCredentialsValidation();
if (errors.length > 0) {
return Promise.reject(errors);
@@ -873,7 +892,10 @@ export default {
/>
</div>
<div class="col span-6">
<div
v-if="!value.vmMachineTypeAutoFeatureEnabled"
class="col span-6"
>
<LabeledSelect
v-model:value="machineType"
label-key="harvester.virtualMachine.input.MachineType"
@@ -0,0 +1,42 @@
<script>
import NetworkPolicy from '@shell/edit/networking.k8s.io.networkpolicy';
import { Banner } from '@components/Banner';
import { DOC } from '../config/doc-links';
import { docLink } from '../utils/feature-flags';
export default {
components: {
NetworkPolicy,
Banner
},
computed: {
networkPolicyDocLink() {
const version = this.$store.getters['harvester-common/getServerVersion']();
return docLink(DOC.NETWORK_POLICY, version);
}
}
};
</script>
<template>
<div class="network-policy-edit">
<Banner color="info">
<t
k="harvester.networkPolicy.banner"
:url="networkPolicyDocLink"
:raw="true"
/>
</Banner>
<NetworkPolicy v-bind="$attrs" />
</div>
</template>
<style lang="scss" scoped>
.network-policy-edit {
flex: auto;
display: flex;
flex-direction: column;
}
</style>
+8
View File
@@ -1106,6 +1106,9 @@ harvester:
remoteVpc:
label: Remote VPC
infoBanner: The static route destination CIDR must cover all subnets CIDR from remote VPC Peer. Read <a href="{url}" target="_blank">VPC Peering Configuration Examples</a> for more information.
networkPolicy:
label: Network Policies
banner: The network policies must be used for VMs attached to overlay networks. Please read the <a href="{url}" target="_blank">harvester document</a> how the network policy works.
network:
label: Virtual Machine Networks
tabs:
@@ -1832,6 +1835,11 @@ typeLabel:
one { Virtual Private Cloud }
other { Virtual Private Clouds }
}
networking.k8s.io.networkpolicy: |-
{count, plural,
one { Network Policy }
other { Network Policies }
}
harvesterhci.io.cloudtemplate: |-
{count, plural,
one { Cloud Configuration Template }
+6 -21
View File
@@ -273,7 +273,7 @@ export default {
needNewSecret() {
// When creating a template it is always necessary to create a new secret.
return this.showYaml ? false : this.resourceType === HCI.VM_VERSION || this.isCreate;
return this.isCreate ? true : this.showYaml ? false : this.resourceType === HCI.VM_VERSION;
},
defaultTerminationSetting() {
@@ -299,9 +299,11 @@ export default {
async created() {
await this.$store.dispatch(`${ this.inStore }/findAll`, { type: SECRET });
if (this.value.vmMachineTypesFeatureEnabled) {
if (!this.value.vmMachineTypeAutoFeatureEnabled) {
try {
const url = this.$store.getters['harvester-common/getHarvesterClusterUrl']('v1/harvester/clusters/local?link=machineTypes');
const url = this.$store.getters['harvester-common/getHarvesterClusterUrl'](
'v1/harvester/clusters/local?link=machineTypes'
);
const machineTypes = await this.$store.dispatch('harvester/request', { url });
this.machineTypes = machineTypes;
@@ -687,14 +689,12 @@ export default {
set(this.spec.template.spec, 'domain.memory.maxGuest', this.maxMemory);
set(this.spec.template.spec, 'domain.resources.limits.memory', this.maxMemory);
} else {
this.spec.template.spec.domain.cpu.maxSockets = 1;
this.spec.template.spec.domain.cpu.sockets = 1;
this.spec.template.spec.domain.cpu.cores = this.cpu;
this.spec.template.spec.domain.resources.limits.cpu = this.cpu?.toString();
this.spec.template.spec.domain.resources.limits.memory = this.memory;
// clean below fields as we don't need them if not enable CPU and memory hotplug
if (this.spec?.template?.spec?.domain?.cpu?.maxSockets) {
delete this.spec.template.spec.domain.cpu.maxSockets;
}
if (this.spec?.template?.spec?.domain?.memory?.maxGuest) {
delete this.spec.template.spec.domain.memory.maxGuest;
}
@@ -1369,21 +1369,6 @@ export default {
}
},
getCPUMemoryValidation() {
const errors = [];
const { cpu, memory } = this;
if ((!cpu)) {
errors.push(this.t('validation.required', { key: this.t('harvester.virtualMachine.input.cpu') }, true));
}
if ((!memory)) {
errors.push(this.t('validation.required', { key: this.t('harvester.virtualMachine.input.memory') }, true));
}
return errors;
},
getAccessCredentialsValidation() {
const errors = [];
@@ -1236,8 +1236,8 @@ export default class VirtVm extends HarvesterResource {
return this.$rootGetters['harvester-common/getFeatureEnabled']('thirdPartyStorage');
}
get vmMachineTypesFeatureEnabled() {
return this.$rootGetters['harvester-common/getFeatureEnabled']('vmMachineTypes');
get vmMachineTypeAutoFeatureEnabled() {
return this.$rootGetters['harvester-common/getFeatureEnabled']('vmMachineTypeAuto');
}
get isBackupTargetUnavailable() {
@@ -16,7 +16,10 @@ export default class HciVlanConfig extends HarvesterResource {
uplink: {
nics: [],
linkAttributes: {},
bondOptions: { mode: 'active-backup' },
bondOptions: {
mode: 'active-backup',
miimon: -1
},
},
};
+6 -7
View File
@@ -3,17 +3,19 @@ import { HCI as HCI_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations
export function getVmCPUMemoryValues(vm) {
if (!vm) {
return {
cpu: 0,
cpu: null,
memory: null,
isHotplugEnabled: false
};
}
const isHotplugEnabled = isCPUMemoryHotPlugEnabled(vm);
const { sockets = 1, threads = 1, cores = null } = vm.spec.template.spec.domain.cpu || {};
const cpu = cores === null ? null : sockets * threads * cores;
if (isHotplugEnabled) {
return {
cpu: vm.spec.template.spec.domain.cpu.sockets,
cpu,
memory: vm.spec.template.spec.domain?.memory?.guest || null,
maxCpu: vm.spec.template.spec.domain.cpu?.maxSockets || 0,
maxMemory: vm.spec.template.spec.domain?.memory?.maxGuest || null,
@@ -21,7 +23,7 @@ export function getVmCPUMemoryValues(vm) {
};
} else {
return {
cpu: vm.spec.template.spec.domain.cpu.cores,
cpu,
memory: vm.spec.template.spec.domain.resources?.limits?.memory || null,
isHotplugEnabled
};
@@ -29,8 +31,5 @@ export function getVmCPUMemoryValues(vm) {
}
export function isCPUMemoryHotPlugEnabled(vm) {
return vm?.metadata?.annotations[HCI_ANNOTATIONS.VM_CPU_MEMORY_HOTPLUG] === 'true' ||
!!vm?.spec?.template?.spec?.domain.cpu?.maxSockets ||
!!vm?.spec?.template?.spec?.domain?.memory?.maxGuest ||
false;
return vm?.metadata?.annotations[HCI_ANNOTATIONS.VM_CPU_MEMORY_HOTPLUG] === 'true' || !!vm?.spec?.template?.spec?.domain?.memory?.maxGuest || false;
}
+3 -3
View File
@@ -3114,9 +3114,9 @@
"@types/node" "*"
"@types/node@*", "@types/node@20.10.8", "@types/node@^14.14.31", "@types/node@~20.19.0":
version "20.19.17"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.19.17.tgz#41b52697373aef8a43b3b92f33b43f329b2d674b"
integrity sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ==
version "20.19.19"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.19.19.tgz#18c8982becd5728f92e5f1939f2f3dc85604abcd"
integrity sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==
dependencies:
undici-types "~6.21.0"