diff --git a/Chart.yaml b/Chart.yaml index de3c2da..5badfbe 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: edge-gitops-vms description: Edge GitOps VMs type: application -version: 0.4.0 +version: 0.5.0 dependencies: [ ] diff --git a/README.md b/README.md index c2dca5d..3980281 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # edge-gitops-vms -![Version: 0.4.0](https://img.shields.io/badge/Version-0.4.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) +![Version: 0.5.0](https://img.shields.io/badge/Version-0.5.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) Edge GitOps VMs @@ -8,6 +8,10 @@ This chart is used to set up Edge GitOps VMs in conjunction with OpenShift Virtu ### Notable changes +* v0.5.0: Change default VM type to rhel9 and workload type to server; change other defaults to "gitops-vms" from "edge-gitops-vms" +* v0.5.0: Change default waitForMetalNode to false +* v0.5.0: Add optional additional disks per VM; use spec.runStrategy instead of spec.running (default Always); default machineType q35 (KubeVirt generic q35 alias) +* v0.5.0: Fix Windows OS detection (Helm 3/4); skip cloud-init and SSH access credentials for Windows * v0.4.0: Parameterize ESO API version and default it to v1 * v0.3.5: Several fixes to separate DataSources from VM namespace * v0.3.4: Correct order of coalesce arguments for main disk storage bus @@ -36,7 +40,7 @@ This chart is used to set up Edge GitOps VMs in conjunction with OpenShift Virtu | rbac.roleBindings[0].subjects.apiGroup | string | `""` | | | rbac.roleBindings[0].subjects.kind | string | `"ServiceAccount"` | | | rbac.roleBindings[0].subjects.name | string | `"ansible-edge-gitops-sa"` | | -| rbac.roleBindings[0].subjects.namespace | string | `"edge-gitops-vms"` | | +| rbac.roleBindings[0].subjects.namespace | string | `"gitops-vms"` | | | rbac.roles[0].apiGroups[0] | string | `"machine.openshift.io"` | | | rbac.roles[0].createRole | bool | `true` | | | rbac.roles[0].name | string | `"view-machine-api"` | | @@ -51,6 +55,7 @@ This chart is used to set up Edge GitOps VMs in conjunction with OpenShift Virtu | secretStore.name | string | `"vault-backend"` | | | serviceAccountName | string | `"ansible-edge-gitops-sa"` | | | vmDefaults.accessMode | string | `"ReadWriteMany"` | | +| vmDefaults.additionalDiskStorageBus | string | `"virtio"` | | | vmDefaults.cloudInitSecret | string | `"secret/data/hub/cloud-init"` | | | vmDefaults.cloudinitsecret | string | `"secret/data/hub/cloud-init"` | | | vmDefaults.cores | int | `1` | | @@ -59,10 +64,10 @@ This chart is used to set up Edge GitOps VMs in conjunction with OpenShift Virtu | vmDefaults.externalDataSourceAnnotations."cdi.kubevirt.io/storage.bind.immediate.requested" | string | `"true"` | | | vmDefaults.externalDataSourceNamespace | string | `"openshift-virtualization-os-images"` | | | vmDefaults.flavor | string | `"medium"` | | -| vmDefaults.machineType | string | `"pc-q35-rhel8.4.0"` | | +| vmDefaults.machineType | string | `"q35"` | | | vmDefaults.mainDiskStorageBus | string | `"virtio"` | | | vmDefaults.memory | string | `"4Gi"` | | -| vmDefaults.os | string | `"rhel8"` | | +| vmDefaults.os | string | `"rhel9"` | | | vmDefaults.ports[0].name | string | `"ssh"` | | | vmDefaults.ports[0].port | int | `22` | | | vmDefaults.ports[0].protocol | string | `"TCP"` | | @@ -72,19 +77,20 @@ This chart is used to set up Edge GitOps VMs in conjunction with OpenShift Virtu | vmDefaults.routeEnableTlsBlock | bool | `false` | | | vmDefaults.routeTlsTermination | string | `"passthrough"` | | | vmDefaults.routes | object | `{}` | | +| vmDefaults.runStrategy | string | `"Always"` | | | vmDefaults.serviceType | string | `"NodePort"` | | | vmDefaults.sockets | int | `1` | | | vmDefaults.sshpubkeyfield | string | `"publickey"` | | | vmDefaults.sshsecret | string | `"secret/data/hub/vm-ssh"` | | | vmDefaults.storage | string | `"30Gi"` | | | vmDefaults.storageClassName | string | `"ocs-storagecluster-ceph-rbd-virtualization"` | | -| vmDefaults.template | string | `"rhel8-desktop-medium"` | | +| vmDefaults.template | string | `"rhel9-server-medium"` | | | vmDefaults.threads | int | `1` | | | vmDefaults.volumeMode | string | `"Block"` | | -| vmDefaults.workload | string | `"desktop"` | | -| vmNamespace | string | `"edge-gitops-vms"` | | +| vmDefaults.workload | string | `"server"` | | +| vmNamespace | string | `"gitops-vms"` | | | vms | object | `{}` | | -| waitForMetalNode | bool | `true` | | +| waitForMetalNode | bool | `false` | | ---------------------------------------------- Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2) diff --git a/README.md.gotmpl b/README.md.gotmpl index 17bea3a..7284a1d 100644 --- a/README.md.gotmpl +++ b/README.md.gotmpl @@ -9,6 +9,10 @@ This chart is used to set up Edge GitOps VMs in conjunction with OpenShift Virtu ### Notable changes +* v0.5.0: Change default VM type to rhel9 and workload type to server; change other defaults to "gitops-vms" from "edge-gitops-vms" +* v0.5.0: Change default waitForMetalNode to false +* v0.5.0: Add optional additional disks per VM; use spec.runStrategy instead of spec.running (default Always); default machineType q35 (KubeVirt generic q35 alias) +* v0.5.0: Fix Windows OS detection (Helm 3/4); skip cloud-init and SSH access credentials for Windows * v0.4.0: Parameterize ESO API version and default it to v1 * v0.3.5: Several fixes to separate DataSources from VM namespace * v0.3.4: Correct order of coalesce arguments for main disk storage bus diff --git a/templates/virtual-machines.yaml b/templates/virtual-machines.yaml index 0b08cd5..d946cc1 100644 --- a/templates/virtual-machines.yaml +++ b/templates/virtual-machines.yaml @@ -1,8 +1,9 @@ {{- $def := .Values.vmDefaults }} {{- range $vm, $vmr := .Values.vms }} -{{- $windows := contains (coalesce $vmr.os $def.os) "windows" }} +{{- $os := coalesce $vmr.os $def.os }} +{{- $windows := regexMatch "(?i)windows" $os }} {{- $role := coalesce $vmr.role $def.role }} -{{- if not $.Values.disableExternalSecrets }} +{{- if and (not $windows) (not $.Values.disableExternalSecrets) }} --- apiVersion: {{ $.Values.secretStore.esoApiVersion }} kind: ExternalSecret @@ -32,7 +33,8 @@ spec: {{- range $i := until $ctr }} {{- $idx := printf "%03d" (add $i 1) }} {{- $identifier := printf "%s-%s-%s" (coalesce $vmr.os $def.os) $role $idx }} -{{- if not $.Values.disableExternalSecrets }} +{{- $additionalDisks := coalesce $vmr.additionalDisks $def.additionalDisks (list) }} +{{- if and (not $windows) (not $.Values.disableExternalSecrets) }} --- apiVersion: {{ $.Values.secretStore.esoApiVersion }} kind: ExternalSecret @@ -113,7 +115,31 @@ spec: storage: {{ coalesce $vmr.storage $def.storage }} storageClassName: {{ coalesce $vmr.storageClassName $def.storageClassName }} volumeMode: {{ coalesce $vmr.volumeMode $def.volumeMode }} - running: true + {{- range $disk := $additionalDisks }} + - apiVersion: cdi.kubevirt.io/v1beta1 + kind: DataVolume + metadata: + name: {{ $identifier }}-{{ required "additionalDisks[].name is required" $disk.name }} + spec: + {{- if $disk.dataVolume }} + sourceRef: + kind: DataSource + name: {{ $disk.dataVolume }} + namespace: {{ $def.externalDataSourceNamespace }} + {{- else }} + source: + blank: {} + {{- end }} + pvc: + accessModes: + - {{ coalesce $disk.accessMode $vmr.accessMode $def.accessMode }} + resources: + requests: + storage: {{ required (printf "additionalDisks[%s].storage is required" (required "additionalDisks[].name is required" $disk.name)) $disk.storage }} + storageClassName: {{ coalesce $disk.storageClassName $vmr.storageClassName $def.storageClassName }} + volumeMode: {{ coalesce $disk.volumeMode $vmr.volumeMode $def.volumeMode }} + {{- end }} + runStrategy: {{ coalesce $vmr.runStrategy $def.runStrategy "Always" }} template: metadata: annotations: @@ -128,7 +154,7 @@ spec: kubevirt.io/size: {{ coalesce $vmr.flavor $def.flavor }} vm.kubevirt.io/name: {{ $identifier }} spec: - {{- if not $.Values.disableExternalSecrets }} + {{- if and (not $windows) (not $.Values.disableExternalSecrets) }} accessCredentials: - sshPublicKey: propagationMethod: @@ -158,7 +184,12 @@ spec: - disk: bus: {{ coalesce $vmr.mainDiskStorageBus $def.mainDiskStorageBus }} name: {{ $identifier }} - {{- if not $.Values.disableExternalSecrets }} + {{- range $disk := $additionalDisks }} + - disk: + bus: {{ coalesce $disk.bus $vmr.additionalDiskStorageBus $def.additionalDiskStorageBus $vmr.mainDiskStorageBus $def.mainDiskStorageBus }} + name: {{ $identifier }}-{{ $disk.name }} + {{- end }} + {{- if and (not $windows) (not $.Values.disableExternalSecrets) }} - disk: bus: virtio name: cloudinitdisk @@ -186,7 +217,12 @@ spec: - dataVolume: name: {{ $identifier }} # name of the disk referenced in this file name: {{ $identifier }} # name of the disk referenced in this file - {{- if not $.Values.disableExternalSecrets }} + {{- range $disk := $additionalDisks }} + - dataVolume: + name: {{ $identifier }}-{{ $disk.name }} + name: {{ $identifier }}-{{ $disk.name }} + {{- end }} + {{- if and (not $windows) (not $.Values.disableExternalSecrets) }} - name: cloudinitdisk cloudInitConfigDrive: secretRef: diff --git a/tests/virtual-machines_test.yaml b/tests/virtual-machines_test.yaml new file mode 100644 index 0000000..0599a46 --- /dev/null +++ b/tests/virtual-machines_test.yaml @@ -0,0 +1,151 @@ +--- +suite: virtual-machines +templates: + - templates/virtual-machines.yaml +release: + name: test + namespace: gitops-vms +tests: + - it: uses runStrategy instead of running + set: + disableExternalSecrets: true + vms: + testvm: + role: test + count: 1 + documentSelector: + path: kind + value: VirtualMachine + asserts: + - notExists: + path: spec.running + - equal: + path: spec.runStrategy + value: Always + - equal: + path: spec.template.spec.domain.machine.type + value: q35 + + - it: renders additional blank disks + set: + disableExternalSecrets: true + vms: + testvm: + role: test + count: 1 + additionalDisks: + - name: data + storage: 50Gi + documentSelector: + path: kind + value: VirtualMachine + asserts: + - equal: + path: spec.dataVolumeTemplates[1].metadata.name + value: rhel9-test-001-data + - equal: + path: spec.dataVolumeTemplates[1].spec.source.blank + value: {} + - equal: + path: spec.dataVolumeTemplates[1].spec.pvc.resources.requests.storage + value: 50Gi + - contains: + path: spec.template.spec.domain.devices.disks + content: + disk: + bus: virtio + name: rhel9-test-001-data + + - it: windows defaults additional disks to virtio and omits cloud-init + set: + vms: + winvm: + role: desktop + count: 1 + os: windows2k22 + additionalDisks: + - name: data + storage: 80Gi + documentSelector: + path: kind + value: VirtualMachine + asserts: + - contains: + path: spec.template.spec.domain.devices.disks + content: + disk: + bus: virtio + name: windows2k22-desktop-001-data + - notContains: + path: spec.template.spec.domain.devices.disks + content: + name: cloudinitdisk + - notContains: + path: spec.template.spec.volumes + content: + name: cloudinitdisk + - notExists: + path: spec.template.spec.accessCredentials + - exists: + path: spec.template.spec.domain.devices.tpm + - matchRegex: + path: metadata.annotations["vm.kubevirt.io/validations"] + pattern: '"min": 4294967296' + + - it: windows skips cloud-init and ssh external secrets + set: + vms: + winvm: + role: desktop + count: 1 + os: windows2k22 + asserts: + - hasDocuments: + count: 2 + + - it: linux still renders cloud-init when external secrets enabled + set: + vms: + linuxvm: + role: server + count: 1 + os: rhel9 + documentSelector: + path: kind + value: VirtualMachine + asserts: + - contains: + path: spec.template.spec.domain.devices.disks + content: + disk: + bus: virtio + name: cloudinitdisk + - contains: + path: spec.template.spec.volumes + content: + name: cloudinitdisk + cloudInitConfigDrive: + secretRef: + name: cloudinit-server + + - it: windows honors per-disk sata bus override + set: + vms: + winvm: + role: desktop + count: 1 + os: windows2k22 + additionalDisks: + - name: data + storage: 80Gi + bus: sata + documentSelector: + path: kind + value: VirtualMachine + asserts: + - contains: + path: spec.template.spec.domain.devices.disks + content: + disk: + bus: sata + name: windows2k22-desktop-001-data diff --git a/values.yaml b/values.yaml index 1904682..114b138 100644 --- a/values.yaml +++ b/values.yaml @@ -8,9 +8,9 @@ secretStore: name: vault-backend kind: ClusterSecretStore -vmNamespace: edge-gitops-vms +vmNamespace: gitops-vms -waitForMetalNode: true +waitForMetalNode: false jobTerminationGracePeriod: 3600 vmDefaults: @@ -23,19 +23,24 @@ vmDefaults: storageClassName: "ocs-storagecluster-ceph-rbd-virtualization" volumeMode: "Block" count: 1 - # Could also be sata + # Override per VM or per additionalDisks[].bus (e.g. sata for generic Windows images). mainDiskStorageBus: virtio + additionalDiskStorageBus: virtio + # Always | RerunOnFailure | Manual | Halted | Once (mutually exclusive with spec.running) + runStrategy: Always flavor: medium - workload: desktop - os: rhel8 + workload: server + os: rhel9 efi: false storage: 30Gi memory: 4Gi + # Generic q35 alias (KubeVirt AMD64 default); libvirt resolves per node. Prefer this over + # pc-q35-rhel9.x.0 unless you must pin a version for live-migration homogeneity. machineType: q35 cores: 1 sockets: 1 threads: 1 - template: rhel8-desktop-medium + template: rhel9-server-medium sshsecret: secret/data/hub/vm-ssh #checkov:skip=CKV_SECRET_6:External Secret cloudinitsecret: secret/data/hub/cloud-init sshpubkeyfield: publickey @@ -66,6 +71,12 @@ vmDefaults: # Define the VMs you want to create with any specific attributes from vmDefaults # in an overrides file. +# Per-VM additionalDisks (optional; can also be set under vmDefaults): +# additionalDisks: +# - name: data +# storage: 100Gi +# # bus, accessMode, storageClassName, volumeMode optional (inherit vmDefaults) +# # dataVolume: clone from a DataSource name; omit for a blank disk vms: {} registryCredentialExternalSecrets: {} @@ -120,7 +131,7 @@ rbac: subjects: kind: ServiceAccount name: ansible-edge-gitops-sa - namespace: edge-gitops-vms + namespace: gitops-vms apiGroup: "" roleRef: kind: ClusterRole