From 3abd9d1afac46a50474ec9486c500e2f98f34337 Mon Sep 17 00:00:00 2001 From: Nicolas Belouin Date: Mon, 18 May 2026 16:39:15 +0200 Subject: [PATCH 1/3] Update metal3 chart to 0.15.0 Signed-off-by: Nicolas Belouin --- packages/baremetal-operator/charts/Chart.yaml | 4 +- .../crds/customresource-baremetalhosts.yaml | 84 +++++++++++++++++-- .../crds/customresource-hardwaredata.yaml | 4 + .../baremetal-operator/charts/values.yaml | 2 +- packages/ironic/charts/Chart.yaml | 4 +- packages/ironic/charts/templates/NOTES.txt | 16 ---- packages/ironic/charts/templates/_helpers.tpl | 5 ++ .../templates/configmap-ipa-downloader.yaml | 12 --- .../ironic/charts/templates/configmap.yaml | 11 ++- .../ironic/charts/templates/deployment.yaml | 51 +++++------ packages/ironic/charts/values.yaml | 10 ++- packages/mariadb/charts/Chart.yaml | 2 +- packages/metal3/charts/Chart.yaml | 10 +-- packages/metal3/charts/values.yaml | 12 +-- 14 files changed, 147 insertions(+), 80 deletions(-) delete mode 100644 packages/ironic/charts/templates/NOTES.txt delete mode 100644 packages/ironic/charts/templates/configmap-ipa-downloader.yaml diff --git a/packages/baremetal-operator/charts/Chart.yaml b/packages/baremetal-operator/charts/Chart.yaml index f77a859b..26a1c097 100644 --- a/packages/baremetal-operator/charts/Chart.yaml +++ b/packages/baremetal-operator/charts/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 -appVersion: 0.11.2 +appVersion: 0.12.3 description: A Helm chart for baremetal-operator, used by Metal3 name: baremetal-operator type: application -version: 0.11.2 +version: 0.12.3 diff --git a/packages/baremetal-operator/charts/crds/customresource-baremetalhosts.yaml b/packages/baremetal-operator/charts/crds/customresource-baremetalhosts.yaml index 9c2d7213..511fddda 100644 --- a/packages/baremetal-operator/charts/crds/customresource-baremetalhosts.yaml +++ b/packages/baremetal-operator/charts/crds/customresource-baremetalhosts.yaml @@ -212,14 +212,23 @@ spec: ExternallyProvisioned means something else has provisioned the image running on the host, and the operator should only manage the power status. This field is used for integration with already - provisioned hosts and when pivoting hosts between clusters. If - unsure, leave this field as false. + provisioned hosts and when pivoting hosts between clusters. + + This field can be set to true either: + 1. During initial host creation (e.g., for pre-provisioned hosts) + 2. After inspection completes when the host reaches Available state + + When used in environments with Cluster API Provider Metal3 (CAPM3), + ensure hosts are labeled appropriately so CAPM3's host selector can + distinguish them from CAPM3-managed hosts. If unsure, leave this + field as false. type: boolean firmware: description: |- Firmware (BIOS) configuration for bare metal server. If set, the requested settings will be applied before the host is provisioned. - Only some vendor drivers support this field. An alternative is to + + Deprecated: no longer supported by any driver. An alternative is to use HostFirmwareSettings resources that allow changing arbitrary values and support the generic Redfish-based drivers. properties: @@ -260,7 +269,7 @@ spec: checksum: description: |- Checksum is the checksum for the image. Required for all formats - except for "live-iso". + except for "live-iso" and OCI images (oci://). type: string checksumType: description: |- @@ -622,6 +631,67 @@ spec: status: description: BareMetalHostStatus defines the observed state of BareMetalHost. properties: + conditions: + description: Conditions defines current service state of the BareMetalHost. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map errorCount: default: 0 description: ErrorCount records how many times the host has encoutered @@ -706,6 +776,7 @@ spec: type: object type: object hostname: + description: Name of the host at the inspection time. type: string nics: description: List of network interfaces for the host. @@ -742,6 +813,9 @@ spec: name: description: The name of the network interface, e.g. "en0" type: string + pciAddress: + description: The NIC PCI address + type: string pxe: description: Whether the NIC is PXE Bootable type: boolean @@ -996,7 +1070,7 @@ spec: checksum: description: |- Checksum is the checksum for the image. Required for all formats - except for "live-iso". + except for "live-iso" and OCI images (oci://). type: string checksumType: description: |- diff --git a/packages/baremetal-operator/charts/crds/customresource-hardwaredata.yaml b/packages/baremetal-operator/charts/crds/customresource-hardwaredata.yaml index 661478a6..0d1029ef 100644 --- a/packages/baremetal-operator/charts/crds/customresource-hardwaredata.yaml +++ b/packages/baremetal-operator/charts/crds/customresource-hardwaredata.yaml @@ -87,6 +87,7 @@ spec: type: object type: object hostname: + description: Name of the host at the inspection time. type: string nics: description: List of network interfaces for the host. @@ -123,6 +124,9 @@ spec: name: description: The name of the network interface, e.g. "en0" type: string + pciAddress: + description: The NIC PCI address + type: string pxe: description: Whether the NIC is PXE Bootable type: boolean diff --git a/packages/baremetal-operator/charts/values.yaml b/packages/baremetal-operator/charts/values.yaml index 0b26737b..4fba6c6c 100644 --- a/packages/baremetal-operator/charts/values.yaml +++ b/packages/baremetal-operator/charts/values.yaml @@ -28,7 +28,7 @@ images: baremetalOperator: repository: registry.opensuse.org/isv/suse/edge/containers/images/baremetal-operator pullPolicy: IfNotPresent - tag: "0.11.2.0" + tag: "0.12.3.0" imagePullSecrets: [] nameOverride: "manger" diff --git a/packages/ironic/charts/Chart.yaml b/packages/ironic/charts/Chart.yaml index 5744d857..f012cc64 100644 --- a/packages/ironic/charts/Chart.yaml +++ b/packages/ironic/charts/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 -appVersion: 32.0.0 +appVersion: 35.0.0 description: A Helm chart for Ironic, used by Metal3 name: ironic type: application -version: 0.12.2 +version: 0.13.0 diff --git a/packages/ironic/charts/templates/NOTES.txt b/packages/ironic/charts/templates/NOTES.txt deleted file mode 100644 index eb10ff46..00000000 --- a/packages/ironic/charts/templates/NOTES.txt +++ /dev/null @@ -1,16 +0,0 @@ -1. Get the application URL by running these commands: -{{- if eq .Values.service.type "NodePort" }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "ironic.fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if eq .Values.service.type "LoadBalancer" }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "ironic.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "ironic.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:6385 -{{- else if eq .Values.service.type "ClusterIP" }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "ironic.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} diff --git a/packages/ironic/charts/templates/_helpers.tpl b/packages/ironic/charts/templates/_helpers.tpl index d82e2279..1dd83c52 100644 --- a/packages/ironic/charts/templates/_helpers.tpl +++ b/packages/ironic/charts/templates/_helpers.tpl @@ -82,6 +82,11 @@ Get ironic CA volumeMounts mountPath: "/certs/ca/vmedia" readOnly: true {{- end }} +{{- if .Values.global.trustedCAs }} +- name: trusted-ca + mountPath: "/certs/ca/trusted" + readOnly: true +{{- end }} {{- end }} {{/* diff --git a/packages/ironic/charts/templates/configmap-ipa-downloader.yaml b/packages/ironic/charts/templates/configmap-ipa-downloader.yaml deleted file mode 100644 index 0536c000..00000000 --- a/packages/ironic/charts/templates/configmap-ipa-downloader.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: ironic-ipa-downloader - labels: - {{- include "ironic.labels" . | nindent 4 }} -data: - {{- with .Values.baremetaloperator }} - {{ if .ipaBaseUri }} - IPA_BASEURI: {{ .ipaBaseUri }} - {{ end }} - {{ end }} diff --git a/packages/ironic/charts/templates/configmap.yaml b/packages/ironic/charts/templates/configmap.yaml index 52bafeb5..ee6acc2c 100644 --- a/packages/ironic/charts/templates/configmap.yaml +++ b/packages/ironic/charts/templates/configmap.yaml @@ -32,15 +32,20 @@ data: {{- if ( .Values.global.enable_tls ) }} RESTART_CONTAINER_CERTIFICATE_UPDATED: "true" IRONIC_KERNEL_PARAMS: {{ .Values.global.ironicKernelParams }} tls.enabled=true - IPA_INSECURE: "0" + IRONIC_IPA_INSECURE: "0" IRONIC_REVERSE_PROXY_SETUP: "true" + {{- if .Values.global.trustedCAs }} + WEBSERVER_CACERT_FILE: /certs/ca/trusted/ca-bundle.pem + {{- else }} + WEBSERVER_CACERT_FILE: /var/lib/ca-certificates/ca-bundle.pem + {{- end }} {{- if ( .Values.global.enable_vmedia_tls ) }} VMEDIA_TLS_PORT: "{{ .Values.global.vmediaTLSPort }}" {{- end }} {{- else }} RESTART_CONTAINER_CERTIFICATE_UPDATED: "false" IRONIC_KERNEL_PARAMS: {{ .Values.global.ironicKernelParams }} - IPA_INSECURE: "1" + IRONIC_IPA_INSECURE: "1" IRONIC_REVERSE_PROXY_SETUP: "false" {{- end }} {{- if ( .Values.global.enable_basicAuth ) }} @@ -54,4 +59,4 @@ data: {{- end }} {{- with .Values.ironicExtraEnv -}} {{ toYaml . | nindent 2 }} - {{- end -}} + {{- end -}} \ No newline at end of file diff --git a/packages/ironic/charts/templates/deployment.yaml b/packages/ironic/charts/templates/deployment.yaml index bec53574..34d0180d 100644 --- a/packages/ironic/charts/templates/deployment.yaml +++ b/packages/ironic/charts/templates/deployment.yaml @@ -146,14 +146,6 @@ spec: - name: cert-ironic mountPath: "/certs/ironic" readOnly: true - - mountPath: /etc/pki/trust/anchors - name: trusted-certs - readOnly: true - lifecycle: - postStart: - exec: - command: - - update-ca-certificates {{- end }} {{- if .Values.global.enable_dnsmasq }} - name: ironic-dnsmasq @@ -206,15 +198,28 @@ spec: {{- toYaml .Values.securityContext | nindent 10 }} command: - /usr/local/bin/get-resource.sh - envFrom: - - configMapRef: - name: ironic-ipa-downloader + env: + {{- if .Values.ipa.useHauler }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: REGISTRY_INSECURE + value: "true" + {{- end }} + - name: IPA_BASEURI + {{- if .Values.ipa.baseUri }} + value: {{ .Values.ipa.baseUri }} + {{- else if .Values.images.ipa }} + {{- $image := .Values.images.ipa }} + {{- $url := urlParse ( print "oci://" $image.repository ) }} + {{- if .Values.ipa.useHauler }} + {{- $url := set $url "host" "$(HOST_IP):6545" }} + {{- end }} + value: {{ urlJoin $url }}:{{ .Values.images.ipa.tag }} + {{- end }} volumeMounts: {{- include "ironic.sharedVolumeMount" . | nindent 10 }} - {{- if .Values.global.enable_tls }} - - mountPath: /tmp/ironic-certificates - name: trusted-certs - {{- end }} volumes: - name: ironic-data-volume {{- if .Values.persistence.ironic.size }} @@ -227,16 +232,13 @@ spec: - name: ironic-basic-auth secret: secretName: ironic-basic-auth + {{- end }} + {{- if .Values.global.trustedCAs }} + - name: trusted-ca + configMap: + name: {{ .Values.global.trustedCAs }} + {{- end }} {{- if .Values.global.enable_tls }} - - name: trusted-certs - projected: - sources: - - secret: - name: ironic-cacert - {{- if .Values.global.additionalTrustedCAs }} - - secret: - name: tls-ca-additional - {{- end }} - name: cert-ironic-ca secret: secretName: ironic-cacert @@ -252,7 +254,6 @@ spec: secretName: ironic-vmedia-cert {{- end }} {{- end }} - {{- end }} {{- with .Values.global.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/packages/ironic/charts/values.yaml b/packages/ironic/charts/values.yaml index 58f31ca3..367d803d 100644 --- a/packages/ironic/charts/values.yaml +++ b/packages/ironic/charts/values.yaml @@ -64,11 +64,14 @@ images: ironic: repository: registry.opensuse.org/isv/suse/edge/containers/images/ironic pullPolicy: IfNotPresent - tag: 32.0.0.1 + tag: 35.0.0.1 ironicIPADownloader: repository: registry.opensuse.org/isv/suse/edge/containers/images/ironic-ipa-downloader pullPolicy: IfNotPresent - tag: 3.0.11 + tag: 3.1.1 + ipa: + repository: registry.opensuse.org/isv/suse/edge/containers/images/ironic-python-agent + tag: 3.0.8 nameOverride: "" fullnameOverride: "" @@ -84,6 +87,9 @@ serviceAccount: podAnnotations: {} +ipa: + useHauler: false + podSecurityContext: runAsUser: 10475 fsGroup: 10475 diff --git a/packages/mariadb/charts/Chart.yaml b/packages/mariadb/charts/Chart.yaml index 17bbd822..9feaf258 100644 --- a/packages/mariadb/charts/Chart.yaml +++ b/packages/mariadb/charts/Chart.yaml @@ -3,4 +3,4 @@ appVersion: "11.8" description: A Helm chart for MariaDB, used by Metal3 name: mariadb type: application -version: 0.6.2 +version: 0.6.3 diff --git a/packages/metal3/charts/Chart.yaml b/packages/metal3/charts/Chart.yaml index f8023431..e7be9c69 100644 --- a/packages/metal3/charts/Chart.yaml +++ b/packages/metal3/charts/Chart.yaml @@ -1,19 +1,19 @@ apiVersion: v2 -appVersion: 0.13.1 +appVersion: 0.15.0 dependencies: - alias: metal3-baremetal-operator name: baremetal-operator repository: file://./charts/baremetal-operator - version: 0.11.2 + version: 0.12.3 - alias: metal3-ironic name: ironic repository: file://./charts/ironic - version: 0.12.2 + version: 0.13.0 - alias: metal3-mariadb condition: global.enable_mariadb name: mariadb repository: file://./charts/mariadb - version: 0.6.2 + version: 0.6.3 - alias: metal3-media condition: global.enable_metal3_media_server name: media @@ -23,4 +23,4 @@ description: A Helm chart that installs all of the dependencies needed for Metal icon: https://github.com/cncf/artwork/raw/master/projects/metal3/icon/color/metal3-icon-color.svg name: metal3 type: application -version: 0.13.1 +version: 0.15.0 diff --git a/packages/metal3/charts/values.yaml b/packages/metal3/charts/values.yaml index ec23de5a..a7b9adc3 100644 --- a/packages/metal3/charts/values.yaml +++ b/packages/metal3/charts/values.yaml @@ -32,12 +32,13 @@ global: ironicUsername: "" ironicPassword: "" - # whether to have additional trusted CA - # NOTE: If enabled, a secret with name tls-ca-additional should be deployed - # The secret should be like this: + # CA bundle to be trusted by Ironic and its python agent, should be the + # name of a deployed ConfigMap in the same namespace. If left empty the + # default public CA bundle will be used. + # The ConfigMap should be like this: # data: - # ca-additional.crt: - additionalTrustedCAs: false + # ca-bundle.pem: + trustedCAs: "" # Will be used when tls is enabled vmediaTLSPort: 6185 @@ -90,7 +91,6 @@ metal3-media: mediaVolume: hostPath: /opt/media - # # ironic service # From 99d992853317fb7aeb1801ea67816927dc49d0cf Mon Sep 17 00:00:00 2001 From: Nicolas Belouin Date: Mon, 18 May 2026 16:47:05 +0200 Subject: [PATCH 2/3] make charts/html Signed-off-by: Nicolas Belouin --- assets/metal3/metal3-0.15.0.tgz | Bin 0 -> 37138 bytes charts/metal3/0.15.0/.helmignore | 23 + charts/metal3/0.15.0/Chart.yaml | 26 + charts/metal3/0.15.0/README.md | 100 ++ charts/metal3/0.15.0/app-readme.md | 1 + .../charts/baremetal-operator/.helmignore | 23 + .../charts/baremetal-operator/Chart.yaml | 6 + .../crds/customresource-baremetalhosts.yaml | 1359 +++++++++++++++++ .../customresource-bmceventsubscriptions.yaml | 91 ++ .../crds/customresource-dataimages.yaml | 81 + .../crds/customresource-firmwareschemas.yaml | 96 ++ .../crds/customresource-hardwaredata.yaml | 239 +++ ...customresource-hostfirmwarecomponents.yaml | 174 +++ .../customresource-hostfirmwaresettings.yaml | 158 ++ .../customresource-hostupdatepolicies.yaml | 62 + .../customresource-preprovisioningimages.yaml | 180 +++ .../baremetal-operator/templates/NOTES.txt | 16 + .../baremetal-operator/templates/_helpers.tpl | 79 + .../templates/certificate.yaml | 14 + .../templates/clusterrole-manager.yaml | 206 +++ .../templates/clusterrolebinding-manager.yaml | 14 + .../templates/configmap-ironic.yaml | 31 + .../templates/deployment.yaml | 112 ++ .../baremetal-operator/templates/issuer.yaml | 8 + .../templates/metrics_auth_role.yaml | 19 + .../templates/metrics_auth_role_binding.yaml | 14 + .../templates/metrics_reader_role.yaml | 11 + .../templates/metrics_service.yaml | 15 + .../baremetal-operator/templates/role.yaml | 45 + .../templates/rolebinding.yaml | 13 + .../templates/service-webhook.yaml | 14 + .../templates/serviceaccount.yaml | 12 + .../validatingwebhookconfiguration.yaml | 51 + .../charts/baremetal-operator/values.yaml | 91 ++ .../metal3/0.15.0/charts/ironic/.helmignore | 23 + charts/metal3/0.15.0/charts/ironic/Chart.yaml | 6 + charts/metal3/0.15.0/charts/ironic/README.md | 24 + .../charts/ironic/templates/_helpers.tpl | 137 ++ .../charts/ironic/templates/certificates.yaml | 40 + .../charts/ironic/templates/configmap.yaml | 62 + .../charts/ironic/templates/deployment.yaml | 272 ++++ .../charts/ironic/templates/issuers.yaml | 16 + .../0.15.0/charts/ironic/templates/pvc.yaml | 26 + .../charts/ironic/templates/secret-tls.yaml | 16 + .../ironic/templates/secrets-basic-auth.yaml | 33 + .../charts/ironic/templates/service.yaml | 40 + .../ironic/templates/serviceaccount.yaml | 12 + .../metal3/0.15.0/charts/ironic/values.yaml | 172 +++ .../metal3/0.15.0/charts/mariadb/.helmignore | 24 + .../metal3/0.15.0/charts/mariadb/Chart.yaml | 6 + .../charts/mariadb/templates/_helpers.tpl | 64 + .../mariadb/templates/configmap-mariadb.yaml | 13 + .../charts/mariadb/templates/configmap.yaml | 11 + .../charts/mariadb/templates/deployment.yaml | 122 ++ .../0.15.0/charts/mariadb/templates/pvc.yaml | 24 + .../charts/mariadb/templates/secret.yaml | 21 + .../mariadb/templates/service-account.yaml | 13 + .../charts/mariadb/templates/service.yaml | 15 + .../metal3/0.15.0/charts/mariadb/values.yaml | 68 + charts/metal3/0.15.0/charts/media/.helmignore | 23 + charts/metal3/0.15.0/charts/media/Chart.yaml | 6 + .../0.15.0/charts/media/templates/NOTES.txt | 22 + .../charts/media/templates/_helpers.tpl | 63 + .../charts/media/templates/deployment.yaml | 62 + .../0.15.0/charts/media/templates/hpa.yaml | 28 + .../charts/media/templates/ingress.yaml | 61 + .../media/templates/persistentvolume.yaml | 18 + .../templates/persistentvolumeclaim.yaml | 14 + .../charts/media/templates/service.yaml | 16 + .../media/templates/serviceaccount.yaml | 12 + .../charts/media/templates/storageclass.yaml | 9 + charts/metal3/0.15.0/charts/media/values.yaml | 122 ++ charts/metal3/0.15.0/templates/NOTES.txt | 3 + charts/metal3/0.15.0/templates/_helpers.tpl | 77 + charts/metal3/0.15.0/values.yaml | 116 ++ index.html | 4 +- index.yaml | 30 + 77 files changed, 5328 insertions(+), 2 deletions(-) create mode 100644 assets/metal3/metal3-0.15.0.tgz create mode 100644 charts/metal3/0.15.0/.helmignore create mode 100644 charts/metal3/0.15.0/Chart.yaml create mode 100644 charts/metal3/0.15.0/README.md create mode 100644 charts/metal3/0.15.0/app-readme.md create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/.helmignore create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/Chart.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-dataimages.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hardwaredata.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostfirmwarecomponents.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostupdatepolicies.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/NOTES.txt create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/_helpers.tpl create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/certificate.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/clusterrole-manager.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/clusterrolebinding-manager.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/configmap-ironic.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/deployment.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/issuer.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_auth_role.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_auth_role_binding.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_reader_role.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_service.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/role.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/rolebinding.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/service-webhook.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/serviceaccount.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/templates/validatingwebhookconfiguration.yaml create mode 100644 charts/metal3/0.15.0/charts/baremetal-operator/values.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/.helmignore create mode 100644 charts/metal3/0.15.0/charts/ironic/Chart.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/README.md create mode 100644 charts/metal3/0.15.0/charts/ironic/templates/_helpers.tpl create mode 100644 charts/metal3/0.15.0/charts/ironic/templates/certificates.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/templates/configmap.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/templates/deployment.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/templates/issuers.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/templates/pvc.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/templates/secret-tls.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/templates/secrets-basic-auth.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/templates/service.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/templates/serviceaccount.yaml create mode 100644 charts/metal3/0.15.0/charts/ironic/values.yaml create mode 100644 charts/metal3/0.15.0/charts/mariadb/.helmignore create mode 100644 charts/metal3/0.15.0/charts/mariadb/Chart.yaml create mode 100644 charts/metal3/0.15.0/charts/mariadb/templates/_helpers.tpl create mode 100644 charts/metal3/0.15.0/charts/mariadb/templates/configmap-mariadb.yaml create mode 100644 charts/metal3/0.15.0/charts/mariadb/templates/configmap.yaml create mode 100644 charts/metal3/0.15.0/charts/mariadb/templates/deployment.yaml create mode 100644 charts/metal3/0.15.0/charts/mariadb/templates/pvc.yaml create mode 100644 charts/metal3/0.15.0/charts/mariadb/templates/secret.yaml create mode 100644 charts/metal3/0.15.0/charts/mariadb/templates/service-account.yaml create mode 100644 charts/metal3/0.15.0/charts/mariadb/templates/service.yaml create mode 100644 charts/metal3/0.15.0/charts/mariadb/values.yaml create mode 100644 charts/metal3/0.15.0/charts/media/.helmignore create mode 100644 charts/metal3/0.15.0/charts/media/Chart.yaml create mode 100644 charts/metal3/0.15.0/charts/media/templates/NOTES.txt create mode 100644 charts/metal3/0.15.0/charts/media/templates/_helpers.tpl create mode 100644 charts/metal3/0.15.0/charts/media/templates/deployment.yaml create mode 100644 charts/metal3/0.15.0/charts/media/templates/hpa.yaml create mode 100644 charts/metal3/0.15.0/charts/media/templates/ingress.yaml create mode 100644 charts/metal3/0.15.0/charts/media/templates/persistentvolume.yaml create mode 100644 charts/metal3/0.15.0/charts/media/templates/persistentvolumeclaim.yaml create mode 100644 charts/metal3/0.15.0/charts/media/templates/service.yaml create mode 100644 charts/metal3/0.15.0/charts/media/templates/serviceaccount.yaml create mode 100644 charts/metal3/0.15.0/charts/media/templates/storageclass.yaml create mode 100644 charts/metal3/0.15.0/charts/media/values.yaml create mode 100644 charts/metal3/0.15.0/templates/NOTES.txt create mode 100644 charts/metal3/0.15.0/templates/_helpers.tpl create mode 100644 charts/metal3/0.15.0/values.yaml diff --git a/assets/metal3/metal3-0.15.0.tgz b/assets/metal3/metal3-0.15.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..f1b5aad5893b7eeb5e1789b931e25dd41b1676cd GIT binary patch literal 37138 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 + +cat <<-EOF | kubectl apply -f - +apiVersion: metallb.io/v1beta1 +kind: IPAddressPool +metadata: + name: ironic-ip-pool + namespace: metallb-system +spec: + addresses: + - ${STATIC_IRONIC_IP}/32 + serviceAllocation: + priority: 100 + serviceSelectors: + - matchExpressions: + - {key: app.kubernetes.io/name, operator: In, values: [metal3-ironic]} +EOF + +cat <<-EOF | kubectl apply -f - +apiVersion: metallb.io/v1beta1 +kind: L2Advertisement +metadata: + name: ironic-ip-pool-l2-adv + namespace: metallb-system +spec: + ipAddressPools: + - ironic-ip-pool +EOF +``` + +5. Create new values.yaml file that will override some of the default properties: + +```bash +TMP_DIR=$(mktemp -d) +cat > ${TMP_DIR}/values.yaml << EOF +global: + ironicIP: "" +EOF +``` + +# Install + +```bash +helm install \ + metal3 suse-edge/metal3 \ + --namespace metal3-system \ + --create-namespace + -f ${TMP_DIR}/values.yaml +``` + +# How to upgrade the chart +1. Run `helm dependency update .` in this chart to download/update the dependent charts. + +2. Identify the appropriate subchart values settings and create an appropriate override values YAML file. + * Ensure that the relevant ironic and baremetal-operator settings match. + +3. Install the chart using a command like the following: + +```console +$ helm upgrade heavy-metal . --namespace metal-cubed --create-namespace --install --values ~/overrides.yaml +``` diff --git a/charts/metal3/0.15.0/app-readme.md b/charts/metal3/0.15.0/app-readme.md new file mode 100644 index 00000000..ffa1c862 --- /dev/null +++ b/charts/metal3/0.15.0/app-readme.md @@ -0,0 +1 @@ +The metal3 chart is a parent chart that installs all of the other charts that a metal3 deployment needs, but doesn't actually deploy any services itself. \ No newline at end of file diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/.helmignore b/charts/metal3/0.15.0/charts/baremetal-operator/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/Chart.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/Chart.yaml new file mode 100644 index 00000000..26a1c097 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 0.12.3 +description: A Helm chart for baremetal-operator, used by Metal3 +name: baremetal-operator +type: application +version: 0.12.3 diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml new file mode 100644 index 00000000..511fddda --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml @@ -0,0 +1,1359 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: baremetal-operator-system/baremetal-operator-serving-cert + controller-gen.kubebuilder.io/version: v0.16.5 + labels: + clusterctl.cluster.x-k8s.io: "" + name: baremetalhosts.metal3.io +spec: + group: metal3.io + names: + kind: BareMetalHost + listKind: BareMetalHostList + plural: baremetalhosts + shortNames: + - bmh + - bmhost + singular: baremetalhost + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Operational status + jsonPath: .status.operationalStatus + name: Status + priority: 1 + type: string + - description: Provisioning status + jsonPath: .status.provisioning.state + name: State + type: string + - description: Consumer using this host + jsonPath: .spec.consumerRef.name + name: Consumer + type: string + - description: Address of management controller + jsonPath: .spec.bmc.address + name: BMC + priority: 1 + type: string + - description: Whether the host is online or not + jsonPath: .spec.online + name: Online + type: string + - description: Type of the most recent error + jsonPath: .status.errorType + name: Error + type: string + - description: Time duration since creation of BaremetalHost + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: BareMetalHost is the Schema for the baremetalhosts API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BareMetalHostSpec defines the desired state of BareMetalHost. + properties: + architecture: + description: |- + CPU architecture of the host, e.g. "x86_64" or "aarch64". If unset, + eventually populated by inspection. + type: string + automatedCleaningMode: + default: metadata + description: |- + When set to disabled, automated cleaning will be skipped + during provisioning and deprovisioning. + enum: + - metadata + - disabled + type: string + bmc: + description: |- + How do we connect to the BMC (Baseboard Management Controller) on + the host? + properties: + address: + description: |- + Address holds the URL for accessing the controller on the network. + The scheme part designates the driver to use with the host. + type: string + credentialsName: + description: |- + The name of the secret containing the BMC credentials (requires + keys "username" and "password"). + type: string + disableCertificateVerification: + description: |- + DisableCertificateVerification disables verification of server + certificates when using HTTPS to connect to the BMC. This is + required when the server certificate is self-signed, but is + insecure because it allows a man-in-the-middle to intercept the + connection. + type: boolean + required: + - address + - credentialsName + type: object + bootMACAddress: + description: |- + The MAC address of the NIC used for provisioning the host. In case + of network boot, this is the MAC address of the PXE booting + interface. The MAC address of the BMC must never be used here! + pattern: '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}' + type: string + bootMode: + description: |- + Select the method of initializing the hardware during boot. + Defaults to UEFI. Legacy boot should only be used for hardware that + does not support UEFI correctly. Set to UEFISecureBoot to turn + secure boot on automatically after provisioning. + enum: + - UEFI + - UEFISecureBoot + - legacy + type: string + consumerRef: + description: |- + ConsumerRef can be used to store information about something + that is using a host. When it is not empty, the host is + considered "in use". The common use case is a link to a Machine + resource when the host is used by Cluster API. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + customDeploy: + description: |- + A custom deploy procedure. This is an advanced feature that allows + using a custom deploy step provided by a site-specific deployment + ramdisk. Most users will want to use "image" instead. Setting this + field triggers provisioning. + properties: + method: + description: |- + Custom deploy method name. + This name is specific to the deploy ramdisk used. If you don't have + a custom deploy ramdisk, you shouldn't use CustomDeploy. + type: string + required: + - method + type: object + description: + description: Description is a human-entered text used to help identify + the host. + type: string + disablePowerOff: + description: |- + When set to true, power off of the node will be disabled, + instead, a reboot will be used in place of power on/off + type: boolean + externallyProvisioned: + description: |- + ExternallyProvisioned means something else has provisioned the + image running on the host, and the operator should only manage + the power status. This field is used for integration with already + provisioned hosts and when pivoting hosts between clusters. + + This field can be set to true either: + 1. During initial host creation (e.g., for pre-provisioned hosts) + 2. After inspection completes when the host reaches Available state + + When used in environments with Cluster API Provider Metal3 (CAPM3), + ensure hosts are labeled appropriately so CAPM3's host selector can + distinguish them from CAPM3-managed hosts. If unsure, leave this + field as false. + type: boolean + firmware: + description: |- + Firmware (BIOS) configuration for bare metal server. If set, the + requested settings will be applied before the host is provisioned. + + Deprecated: no longer supported by any driver. An alternative is to + use HostFirmwareSettings resources that allow changing arbitrary + values and support the generic Redfish-based drivers. + properties: + simultaneousMultithreadingEnabled: + description: Allows a single physical processor core to appear + as several logical processors. + enum: + - true + - false + type: boolean + sriovEnabled: + description: SR-IOV support enables a hypervisor to create virtual + instances of a PCI-express device, potentially increasing performance. + enum: + - true + - false + type: boolean + virtualizationEnabled: + description: Supports the virtualization of platform hardware. + enum: + - true + - false + type: boolean + type: object + hardwareProfile: + description: |- + What is the name of the hardware profile for this host? + Hardware profiles are deprecated and should not be used. + Use the separate fields Architecture and RootDeviceHints instead. + Set to "empty" to prepare for the future version of the API + without hardware profiles. + type: string + image: + description: |- + Image holds the details of the image to be provisioned. Populating + the image will cause the host to start provisioning. + properties: + checksum: + description: |- + Checksum is the checksum for the image. Required for all formats + except for "live-iso" and OCI images (oci://). + type: string + checksumType: + description: |- + ChecksumType is the checksum algorithm for the image, e.g md5, sha256 or sha512. + The special value "auto" can be used to detect the algorithm from the checksum. + If missing, MD5 is used. If in doubt, use "auto". + enum: + - md5 + - sha256 + - sha512 + - auto + type: string + format: + description: |- + Format contains the format of the image (raw, qcow2, ...). + When set to "live-iso", an ISO 9660 image referenced by the url will + be live-booted and not deployed to disk. + enum: + - raw + - qcow2 + - vdi + - vmdk + - live-iso + type: string + url: + description: URL is a location of an image to deploy. + type: string + required: + - url + type: object + inspectionMode: + description: |- + Specifies the mode for host inspection. + "disabled" - no inspection will be performed + "agent" - normal agent-based inspection will run + enum: + - disabled + - agent + type: string + metaData: + description: |- + MetaData holds the reference to the Secret containing host metadata + which is passed to the Config Drive. By default, metadata will be + generated for the host, so most users do not need to set this field. + properties: + name: + description: name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: namespace defines the space within which the secret + name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + networkData: + description: |- + NetworkData holds the reference to the Secret containing network + configuration which is passed to the Config Drive and interpreted + by the first boot software such as cloud-init. + properties: + name: + description: name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: namespace defines the space within which the secret + name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + online: + description: |- + Should the host be powered on? If the host is currently in a stable + state (e.g. provisioned), its power state will be forced to match + this value. + type: boolean + preprovisioningNetworkDataName: + description: |- + PreprovisioningNetworkDataName is the name of the Secret in the + local namespace containing network configuration which is passed to + the preprovisioning image, and to the Config Drive if not overridden + by specifying NetworkData. + type: string + raid: + description: |- + RAID configuration for bare metal server. If set, the RAID settings + will be applied before the host is provisioned. If not, the current + settings will not be modified. Only one of the sub-fields + hardwareRAIDVolumes and softwareRAIDVolumes can be set at the same + time. + properties: + hardwareRAIDVolumes: + description: |- + The list of logical disks for hardware RAID, if rootDeviceHints isn't used, first volume is root volume. + You can set the value of this field to `[]` to clear all the hardware RAID configurations. + items: + description: HardwareRAIDVolume defines the desired configuration + of volume in hardware RAID. + properties: + controller: + description: The name of the RAID controller to use. + type: string + level: + description: |- + RAID level for the logical disk. The following levels are supported: + 0, 1, 2, 5, 6, 1+0, 5+0, 6+0 (drivers may support only some of them). + enum: + - "0" + - "1" + - "2" + - "5" + - "6" + - 1+0 + - 5+0 + - 6+0 + type: string + name: + description: |- + Name of the volume. Should be unique within the Node. If not + specified, the name will be auto-generated. + maxLength: 64 + type: string + numberOfPhysicalDisks: + description: |- + Integer, number of physical disks to use for the logical disk. + Defaults to minimum number of disks required for the particular RAID + level. + minimum: 1 + type: integer + physicalDisks: + description: |- + Optional list of physical disk names to be used for the hardware RAID volumes. The disk names are interpreted + by the hardware RAID controller, and the format is hardware specific. + items: + type: string + type: array + rotational: + description: |- + Select disks with only rotational (if set to true) or solid-state + (if set to false) storage. By default, any disks can be picked. + type: boolean + sizeGibibytes: + description: |- + Size of the logical disk to be created in GiB. If unspecified or + set be 0, the maximum capacity of disk will be used for logical + disk. + minimum: 0 + type: integer + required: + - level + type: object + nullable: true + type: array + softwareRAIDVolumes: + description: |- + The list of logical disks for software RAID, if rootDeviceHints isn't used, first volume is root volume. + If HardwareRAIDVolumes is set this item will be invalid. + The number of created Software RAID devices must be 1 or 2. + If there is only one Software RAID device, it has to be a RAID-1. + If there are two, the first one has to be a RAID-1, while the RAID level for the second one can be 0, 1, or 1+0. + As the first RAID device will be the deployment device, + enforcing a RAID-1 reduces the risk of ending up with a non-booting host in case of a disk failure. + Software RAID will always be deleted. + items: + description: SoftwareRAIDVolume defines the desired configuration + of volume in software RAID. + properties: + level: + description: |- + RAID level for the logical disk. The following levels are supported: + 0, 1 and 1+0. + enum: + - "0" + - "1" + - 1+0 + type: string + physicalDisks: + description: A list of device hints, the number of items + should be greater than or equal to 2. + items: + description: |- + RootDeviceHints holds the hints for specifying the storage location + for the root filesystem for the image. + properties: + deviceName: + description: |- + A Linux device name like "/dev/vda", or a by-path link to it like + "/dev/disk/by-path/pci-0000:01:00.0-scsi-0:2:0:0". The hint must match + the actual value exactly. + type: string + hctl: + description: |- + A SCSI bus address like 0:0:0:0. The hint must match the actual + value exactly. + type: string + minSizeGigabytes: + description: The minimum size of the device in Gigabytes. + minimum: 0 + type: integer + model: + description: |- + A vendor-specific device identifier. The hint can be a + substring of the actual value. + type: string + rotational: + description: True if the device should use spinning + media, false otherwise. + type: boolean + serialNumber: + description: |- + Device serial number. The hint must match the actual value + exactly. + type: string + vendor: + description: |- + The name of the vendor or manufacturer of the device. The hint + can be a substring of the actual value. + type: string + wwn: + description: |- + Unique storage identifier. The hint must match the actual value + exactly. + type: string + wwnVendorExtension: + description: |- + Unique vendor storage identifier. The hint must match the + actual value exactly. + type: string + wwnWithExtension: + description: |- + Unique storage identifier with the vendor extension + appended. The hint must match the actual value exactly. + type: string + type: object + minItems: 2 + type: array + sizeGibibytes: + description: |- + Size of the logical disk to be created in GiB. + If unspecified or set be 0, the maximum capacity of disk will be used for logical disk. + minimum: 0 + type: integer + required: + - level + type: object + maxItems: 2 + nullable: true + type: array + type: object + rootDeviceHints: + description: |- + Provide guidance about how to choose the device for the image + being provisioned. The default is currently to use /dev/sda as + the root device. + properties: + deviceName: + description: |- + A Linux device name like "/dev/vda", or a by-path link to it like + "/dev/disk/by-path/pci-0000:01:00.0-scsi-0:2:0:0". The hint must match + the actual value exactly. + type: string + hctl: + description: |- + A SCSI bus address like 0:0:0:0. The hint must match the actual + value exactly. + type: string + minSizeGigabytes: + description: The minimum size of the device in Gigabytes. + minimum: 0 + type: integer + model: + description: |- + A vendor-specific device identifier. The hint can be a + substring of the actual value. + type: string + rotational: + description: True if the device should use spinning media, false + otherwise. + type: boolean + serialNumber: + description: |- + Device serial number. The hint must match the actual value + exactly. + type: string + vendor: + description: |- + The name of the vendor or manufacturer of the device. The hint + can be a substring of the actual value. + type: string + wwn: + description: |- + Unique storage identifier. The hint must match the actual value + exactly. + type: string + wwnVendorExtension: + description: |- + Unique vendor storage identifier. The hint must match the + actual value exactly. + type: string + wwnWithExtension: + description: |- + Unique storage identifier with the vendor extension + appended. The hint must match the actual value exactly. + type: string + type: object + taints: + description: |- + Taints is the full, authoritative list of taints to apply to + the corresponding Machine. This list will overwrite any + modifications made to the Machine on an ongoing basis. + items: + description: |- + The node this Taint is attached to has the "effect" on + any pod that does not tolerate the Taint. + properties: + effect: + description: |- + Required. The effect of the taint on pods + that do not tolerate the taint. + Valid effects are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Required. The taint key to be applied to a node. + type: string + timeAdded: + description: TimeAdded represents the time at which the taint + was added. + format: date-time + type: string + value: + description: The taint value corresponding to the taint key. + type: string + required: + - effect + - key + type: object + type: array + userData: + description: |- + UserData holds the reference to the Secret containing the user data + which is passed to the Config Drive and interpreted by the + first-boot software such as cloud-init. The format of user data is + specific to the first-boot software. + properties: + name: + description: name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: namespace defines the space within which the secret + name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + required: + - online + type: object + status: + description: BareMetalHostStatus defines the observed state of BareMetalHost. + properties: + conditions: + description: Conditions defines current service state of the BareMetalHost. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + errorCount: + default: 0 + description: ErrorCount records how many times the host has encoutered + an error since the last successful operation + type: integer + errorMessage: + description: The last error message reported by the provisioning subsystem. + type: string + errorType: + description: |- + ErrorType indicates the type of failure encountered when the + OperationalStatus is OperationalStatusError + enum: + - provisioned registration error + - registration error + - inspection error + - preparation error + - provisioning error + - power management error + - servicing error + type: string + goodCredentials: + description: The last credentials we were able to validate as working. + properties: + credentials: + description: |- + SecretReference represents a Secret Reference. It has enough information to retrieve secret + in any namespace + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which the + secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + credentialsVersion: + type: string + type: object + hardware: + description: |- + The hardware discovered to exist on the host. + This field will be removed in the next API version in favour of the + separate HardwareData resource. + properties: + cpu: + description: Details of the CPU(s) in the system. + properties: + arch: + type: string + clockMegahertz: + description: ClockSpeed is a clock speed in MHz + format: double + type: number + count: + type: integer + flags: + items: + type: string + type: array + model: + type: string + type: object + firmware: + description: System firmware information. + properties: + bios: + description: The BIOS for this firmware + properties: + date: + description: The release/build date for this BIOS + type: string + vendor: + description: The vendor name for this BIOS + type: string + version: + description: The version of the BIOS + type: string + type: object + type: object + hostname: + description: Name of the host at the inspection time. + type: string + nics: + description: List of network interfaces for the host. + items: + description: NIC describes one network interface on the host. + properties: + ip: + description: |- + The IP address of the interface. This will be an IPv4 or IPv6 address + if one is present. If both IPv4 and IPv6 addresses are present in a + dual-stack environment, two nics will be output, one with each IP. + type: string + lldp: + description: LLDP data for this interface + properties: + portID: + description: The switch port ID from LLDP + type: string + switchID: + description: The switch chassis ID from LLDP + type: string + switchSystemName: + description: The switch system name from LLDP + type: string + type: object + mac: + description: The device MAC address + pattern: '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}' + type: string + model: + description: The vendor and product IDs of the NIC, e.g. + "0x8086 0x1572" + type: string + name: + description: The name of the network interface, e.g. "en0" + type: string + pciAddress: + description: The NIC PCI address + type: string + pxe: + description: Whether the NIC is PXE Bootable + type: boolean + speedGbps: + description: The speed of the device in Gigabits per second + type: integer + vlanId: + description: The untagged VLAN ID + format: int32 + maximum: 4094 + minimum: 0 + type: integer + vlans: + description: The VLANs available + items: + description: VLAN represents the name and ID of a VLAN. + properties: + id: + description: VLANID is a 12-bit 802.1Q VLAN identifier + format: int32 + maximum: 4094 + minimum: 0 + type: integer + name: + type: string + type: object + type: array + type: object + type: array + ramMebibytes: + description: The host's amount of memory in Mebibytes. + type: integer + storage: + description: List of storage (disk, SSD, etc.) available to the + host. + items: + description: Storage describes one storage device (disk, SSD, + etc.) on the host. + properties: + alternateNames: + description: |- + A list of alternate Linux device names of the disk, e.g. "/dev/sda". + Note that this list is not exhaustive, and names may not be stable + across reboots. + items: + type: string + type: array + hctl: + description: The SCSI location of the device + type: string + model: + description: Hardware model + type: string + name: + description: |- + A Linux device name of the disk, e.g. + "/dev/disk/by-path/pci-0000:01:00.0-scsi-0:2:0:0". This will be a name + that is stable across reboots if one is available. + type: string + rotational: + description: |- + Whether this disk represents rotational storage. + This field is not recommended for usage, please + prefer using 'Type' field instead, this field + will be deprecated eventually. + type: boolean + serialNumber: + description: The serial number of the device + type: string + sizeBytes: + description: The size of the disk in Bytes + format: int64 + type: integer + type: + description: 'Device type, one of: HDD, SSD, NVME.' + enum: + - HDD + - SSD + - NVME + type: string + vendor: + description: The name of the vendor of the device + type: string + wwn: + description: The WWN of the device + type: string + wwnVendorExtension: + description: The WWN Vendor extension of the device + type: string + wwnWithExtension: + description: The WWN with the extension + type: string + type: object + type: array + systemVendor: + description: System vendor information. + properties: + manufacturer: + type: string + productName: + type: string + serialNumber: + type: string + type: object + type: object + hardwareProfile: + description: |- + The name of the profile matching the hardware details. + Hardware profiles are deprecated and should not be relied on. + type: string + lastUpdated: + description: LastUpdated identifies when this status was last observed. + format: date-time + type: string + operationHistory: + description: |- + OperationHistory holds information about operations performed + on this host. + properties: + deprovision: + description: |- + OperationMetric contains metadata about an operation (inspection, + provisioning, etc.) used for tracking metrics. + properties: + end: + format: date-time + nullable: true + type: string + start: + format: date-time + nullable: true + type: string + type: object + inspect: + description: |- + OperationMetric contains metadata about an operation (inspection, + provisioning, etc.) used for tracking metrics. + properties: + end: + format: date-time + nullable: true + type: string + start: + format: date-time + nullable: true + type: string + type: object + provision: + description: |- + OperationMetric contains metadata about an operation (inspection, + provisioning, etc.) used for tracking metrics. + properties: + end: + format: date-time + nullable: true + type: string + start: + format: date-time + nullable: true + type: string + type: object + register: + description: |- + OperationMetric contains metadata about an operation (inspection, + provisioning, etc.) used for tracking metrics. + properties: + end: + format: date-time + nullable: true + type: string + start: + format: date-time + nullable: true + type: string + type: object + type: object + operationalStatus: + description: OperationalStatus holds the status of the host + enum: + - "" + - OK + - discovered + - error + - delayed + - detached + - servicing + type: string + poweredOn: + description: |- + The currently detected power state of the host. This field may get + briefly out of sync with the actual state of the hardware while + provisioning processes are running. + type: boolean + provisioning: + description: Information tracked by the provisioner. + properties: + ID: + description: |- + The hosts's ID from the underlying provisioning tool (e.g. the + Ironic node UUID). + type: string + bootMode: + description: BootMode indicates the boot mode used to provision + the host. + enum: + - UEFI + - UEFISecureBoot + - legacy + type: string + customDeploy: + description: Custom deploy procedure applied to the host. + properties: + method: + description: |- + Custom deploy method name. + This name is specific to the deploy ramdisk used. If you don't have + a custom deploy ramdisk, you shouldn't use CustomDeploy. + type: string + required: + - method + type: object + firmware: + description: The firmware settings that have been applied. + properties: + simultaneousMultithreadingEnabled: + description: Allows a single physical processor core to appear + as several logical processors. + enum: + - true + - false + type: boolean + sriovEnabled: + description: SR-IOV support enables a hypervisor to create + virtual instances of a PCI-express device, potentially increasing + performance. + enum: + - true + - false + type: boolean + virtualizationEnabled: + description: Supports the virtualization of platform hardware. + enum: + - true + - false + type: boolean + type: object + image: + description: |- + Image holds the details of the last image successfully + provisioned to the host. + properties: + checksum: + description: |- + Checksum is the checksum for the image. Required for all formats + except for "live-iso" and OCI images (oci://). + type: string + checksumType: + description: |- + ChecksumType is the checksum algorithm for the image, e.g md5, sha256 or sha512. + The special value "auto" can be used to detect the algorithm from the checksum. + If missing, MD5 is used. If in doubt, use "auto". + enum: + - md5 + - sha256 + - sha512 + - auto + type: string + format: + description: |- + Format contains the format of the image (raw, qcow2, ...). + When set to "live-iso", an ISO 9660 image referenced by the url will + be live-booted and not deployed to disk. + enum: + - raw + - qcow2 + - vdi + - vmdk + - live-iso + type: string + url: + description: URL is a location of an image to deploy. + type: string + required: + - url + type: object + raid: + description: The RAID configuration that has been applied. + properties: + hardwareRAIDVolumes: + description: |- + The list of logical disks for hardware RAID, if rootDeviceHints isn't used, first volume is root volume. + You can set the value of this field to `[]` to clear all the hardware RAID configurations. + items: + description: HardwareRAIDVolume defines the desired configuration + of volume in hardware RAID. + properties: + controller: + description: The name of the RAID controller to use. + type: string + level: + description: |- + RAID level for the logical disk. The following levels are supported: + 0, 1, 2, 5, 6, 1+0, 5+0, 6+0 (drivers may support only some of them). + enum: + - "0" + - "1" + - "2" + - "5" + - "6" + - 1+0 + - 5+0 + - 6+0 + type: string + name: + description: |- + Name of the volume. Should be unique within the Node. If not + specified, the name will be auto-generated. + maxLength: 64 + type: string + numberOfPhysicalDisks: + description: |- + Integer, number of physical disks to use for the logical disk. + Defaults to minimum number of disks required for the particular RAID + level. + minimum: 1 + type: integer + physicalDisks: + description: |- + Optional list of physical disk names to be used for the hardware RAID volumes. The disk names are interpreted + by the hardware RAID controller, and the format is hardware specific. + items: + type: string + type: array + rotational: + description: |- + Select disks with only rotational (if set to true) or solid-state + (if set to false) storage. By default, any disks can be picked. + type: boolean + sizeGibibytes: + description: |- + Size of the logical disk to be created in GiB. If unspecified or + set be 0, the maximum capacity of disk will be used for logical + disk. + minimum: 0 + type: integer + required: + - level + type: object + nullable: true + type: array + softwareRAIDVolumes: + description: |- + The list of logical disks for software RAID, if rootDeviceHints isn't used, first volume is root volume. + If HardwareRAIDVolumes is set this item will be invalid. + The number of created Software RAID devices must be 1 or 2. + If there is only one Software RAID device, it has to be a RAID-1. + If there are two, the first one has to be a RAID-1, while the RAID level for the second one can be 0, 1, or 1+0. + As the first RAID device will be the deployment device, + enforcing a RAID-1 reduces the risk of ending up with a non-booting host in case of a disk failure. + Software RAID will always be deleted. + items: + description: SoftwareRAIDVolume defines the desired configuration + of volume in software RAID. + properties: + level: + description: |- + RAID level for the logical disk. The following levels are supported: + 0, 1 and 1+0. + enum: + - "0" + - "1" + - 1+0 + type: string + physicalDisks: + description: A list of device hints, the number of items + should be greater than or equal to 2. + items: + description: |- + RootDeviceHints holds the hints for specifying the storage location + for the root filesystem for the image. + properties: + deviceName: + description: |- + A Linux device name like "/dev/vda", or a by-path link to it like + "/dev/disk/by-path/pci-0000:01:00.0-scsi-0:2:0:0". The hint must match + the actual value exactly. + type: string + hctl: + description: |- + A SCSI bus address like 0:0:0:0. The hint must match the actual + value exactly. + type: string + minSizeGigabytes: + description: The minimum size of the device in + Gigabytes. + minimum: 0 + type: integer + model: + description: |- + A vendor-specific device identifier. The hint can be a + substring of the actual value. + type: string + rotational: + description: True if the device should use spinning + media, false otherwise. + type: boolean + serialNumber: + description: |- + Device serial number. The hint must match the actual value + exactly. + type: string + vendor: + description: |- + The name of the vendor or manufacturer of the device. The hint + can be a substring of the actual value. + type: string + wwn: + description: |- + Unique storage identifier. The hint must match the actual value + exactly. + type: string + wwnVendorExtension: + description: |- + Unique vendor storage identifier. The hint must match the + actual value exactly. + type: string + wwnWithExtension: + description: |- + Unique storage identifier with the vendor extension + appended. The hint must match the actual value exactly. + type: string + type: object + minItems: 2 + type: array + sizeGibibytes: + description: |- + Size of the logical disk to be created in GiB. + If unspecified or set be 0, the maximum capacity of disk will be used for logical disk. + minimum: 0 + type: integer + required: + - level + type: object + maxItems: 2 + nullable: true + type: array + type: object + rootDeviceHints: + description: The root device hints used to provision the host. + properties: + deviceName: + description: |- + A Linux device name like "/dev/vda", or a by-path link to it like + "/dev/disk/by-path/pci-0000:01:00.0-scsi-0:2:0:0". The hint must match + the actual value exactly. + type: string + hctl: + description: |- + A SCSI bus address like 0:0:0:0. The hint must match the actual + value exactly. + type: string + minSizeGigabytes: + description: The minimum size of the device in Gigabytes. + minimum: 0 + type: integer + model: + description: |- + A vendor-specific device identifier. The hint can be a + substring of the actual value. + type: string + rotational: + description: True if the device should use spinning media, + false otherwise. + type: boolean + serialNumber: + description: |- + Device serial number. The hint must match the actual value + exactly. + type: string + vendor: + description: |- + The name of the vendor or manufacturer of the device. The hint + can be a substring of the actual value. + type: string + wwn: + description: |- + Unique storage identifier. The hint must match the actual value + exactly. + type: string + wwnVendorExtension: + description: |- + Unique vendor storage identifier. The hint must match the + actual value exactly. + type: string + wwnWithExtension: + description: |- + Unique storage identifier with the vendor extension + appended. The hint must match the actual value exactly. + type: string + type: object + state: + description: An indicator for what the provisioner is doing with + the host. + type: string + required: + - ID + - state + type: object + triedCredentials: + description: The last credentials we sent to the provisioning backend. + properties: + credentials: + description: |- + SecretReference represents a Secret Reference. It has enough information to retrieve secret + in any namespace + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which the + secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + credentialsVersion: + type: string + type: object + required: + - errorCount + - errorMessage + - operationalStatus + - poweredOn + - provisioning + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml new file mode 100644 index 00000000..d5341f49 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml @@ -0,0 +1,91 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.5 + labels: + clusterctl.cluster.x-k8s.io: "" + name: bmceventsubscriptions.metal3.io +spec: + group: metal3.io + names: + kind: BMCEventSubscription + listKind: BMCEventSubscriptionList + plural: bmceventsubscriptions + shortNames: + - bes + - bmcevent + singular: bmceventsubscription + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The most recent error message + jsonPath: .status.error + name: Error + type: string + - description: Time duration since creation of BMCEventSubscription + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: BMCEventSubscription is the Schema for the fast eventing API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + context: + description: Arbitrary user-provided context for the event + type: string + destination: + description: A webhook URL to send events to + type: string + hostName: + description: A reference to a BareMetalHost + type: string + httpHeadersRef: + description: |- + A secret containing HTTP headers which should be passed along to the Destination + when making a request + properties: + name: + description: name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: namespace defines the space within which the secret + name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + type: object + status: + properties: + error: + type: string + subscriptionID: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-dataimages.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-dataimages.yaml new file mode 100644 index 00000000..fa4176b3 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-dataimages.yaml @@ -0,0 +1,81 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.5 + name: dataimages.metal3.io +spec: + group: metal3.io + names: + kind: DataImage + listKind: DataImageList + plural: dataimages + singular: dataimage + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: DataImage is the Schema for the dataimages API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: DataImageSpec defines the desired state of DataImage. + properties: + url: + description: |- + Url is the address of the dataImage that we want to attach + to a BareMetalHost + type: string + required: + - url + type: object + status: + description: DataImageStatus defines the observed state of DataImage. + properties: + attachedImage: + description: Currently attached DataImage + properties: + url: + type: string + required: + - url + type: object + error: + description: Error count and message when attaching/detaching + properties: + count: + type: integer + message: + type: string + required: + - count + - message + type: object + lastReconciled: + description: Time of last reconciliation + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml new file mode 100644 index 00000000..2eae7b6e --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml @@ -0,0 +1,96 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.5 + labels: + clusterctl.cluster.x-k8s.io: "" + name: firmwareschemas.metal3.io +spec: + group: metal3.io + names: + kind: FirmwareSchema + listKind: FirmwareSchemaList + plural: firmwareschemas + singular: firmwareschema + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: FirmwareSchema is the Schema for the firmwareschemas API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: FirmwareSchemaSpec defines the desired state of FirmwareSchema. + properties: + hardwareModel: + description: The hardware model associated with this schema + type: string + hardwareVendor: + description: The hardware vendor associated with this schema + type: string + schema: + additionalProperties: + description: Additional data describing the firmware setting. + properties: + allowable_values: + description: The allowable value for an Enumeration type setting. + items: + type: string + type: array + attribute_type: + description: The type of setting. + enum: + - Enumeration + - String + - Integer + - Boolean + - Password + type: string + lower_bound: + description: The lowest value for an Integer type setting. + type: integer + max_length: + description: Maximum length for a String type setting. + type: integer + min_length: + description: Minimum length for a String type setting. + type: integer + read_only: + description: Whether or not this setting is read only. + type: boolean + unique: + description: |- + Whether or not this setting's value is unique to this node, e.g. + a serial number. + type: boolean + upper_bound: + description: The highest value for an Integer type setting. + type: integer + type: object + description: Map of firmware name to schema + type: object + required: + - schema + type: object + type: object + served: true + storage: true diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hardwaredata.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hardwaredata.yaml new file mode 100644 index 00000000..0d1029ef --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hardwaredata.yaml @@ -0,0 +1,239 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.5 + labels: + clusterctl.cluster.x-k8s.io: "" + name: hardwaredata.metal3.io +spec: + group: metal3.io + names: + kind: HardwareData + listKind: HardwareDataList + plural: hardwaredata + shortNames: + - hd + singular: hardwaredata + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Time duration since creation of HardwareData + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: HardwareData is the Schema for the hardwaredata API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: HardwareDataSpec defines the desired state of HardwareData. + properties: + hardware: + description: The hardware discovered on the host during its inspection. + properties: + cpu: + description: Details of the CPU(s) in the system. + properties: + arch: + type: string + clockMegahertz: + description: ClockSpeed is a clock speed in MHz + format: double + type: number + count: + type: integer + flags: + items: + type: string + type: array + model: + type: string + type: object + firmware: + description: System firmware information. + properties: + bios: + description: The BIOS for this firmware + properties: + date: + description: The release/build date for this BIOS + type: string + vendor: + description: The vendor name for this BIOS + type: string + version: + description: The version of the BIOS + type: string + type: object + type: object + hostname: + description: Name of the host at the inspection time. + type: string + nics: + description: List of network interfaces for the host. + items: + description: NIC describes one network interface on the host. + properties: + ip: + description: |- + The IP address of the interface. This will be an IPv4 or IPv6 address + if one is present. If both IPv4 and IPv6 addresses are present in a + dual-stack environment, two nics will be output, one with each IP. + type: string + lldp: + description: LLDP data for this interface + properties: + portID: + description: The switch port ID from LLDP + type: string + switchID: + description: The switch chassis ID from LLDP + type: string + switchSystemName: + description: The switch system name from LLDP + type: string + type: object + mac: + description: The device MAC address + pattern: '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}' + type: string + model: + description: The vendor and product IDs of the NIC, e.g. + "0x8086 0x1572" + type: string + name: + description: The name of the network interface, e.g. "en0" + type: string + pciAddress: + description: The NIC PCI address + type: string + pxe: + description: Whether the NIC is PXE Bootable + type: boolean + speedGbps: + description: The speed of the device in Gigabits per second + type: integer + vlanId: + description: The untagged VLAN ID + format: int32 + maximum: 4094 + minimum: 0 + type: integer + vlans: + description: The VLANs available + items: + description: VLAN represents the name and ID of a VLAN. + properties: + id: + description: VLANID is a 12-bit 802.1Q VLAN identifier + format: int32 + maximum: 4094 + minimum: 0 + type: integer + name: + type: string + type: object + type: array + type: object + type: array + ramMebibytes: + description: The host's amount of memory in Mebibytes. + type: integer + storage: + description: List of storage (disk, SSD, etc.) available to the + host. + items: + description: Storage describes one storage device (disk, SSD, + etc.) on the host. + properties: + alternateNames: + description: |- + A list of alternate Linux device names of the disk, e.g. "/dev/sda". + Note that this list is not exhaustive, and names may not be stable + across reboots. + items: + type: string + type: array + hctl: + description: The SCSI location of the device + type: string + model: + description: Hardware model + type: string + name: + description: |- + A Linux device name of the disk, e.g. + "/dev/disk/by-path/pci-0000:01:00.0-scsi-0:2:0:0". This will be a name + that is stable across reboots if one is available. + type: string + rotational: + description: |- + Whether this disk represents rotational storage. + This field is not recommended for usage, please + prefer using 'Type' field instead, this field + will be deprecated eventually. + type: boolean + serialNumber: + description: The serial number of the device + type: string + sizeBytes: + description: The size of the disk in Bytes + format: int64 + type: integer + type: + description: 'Device type, one of: HDD, SSD, NVME.' + enum: + - HDD + - SSD + - NVME + type: string + vendor: + description: The name of the vendor of the device + type: string + wwn: + description: The WWN of the device + type: string + wwnVendorExtension: + description: The WWN Vendor extension of the device + type: string + wwnWithExtension: + description: The WWN with the extension + type: string + type: object + type: array + systemVendor: + description: System vendor information. + properties: + manufacturer: + type: string + productName: + type: string + serialNumber: + type: string + type: object + type: object + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostfirmwarecomponents.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostfirmwarecomponents.yaml new file mode 100644 index 00000000..a465189e --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostfirmwarecomponents.yaml @@ -0,0 +1,174 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.5 + labels: + clusterctl.cluster.x-k8s.io: "" + name: hostfirmwarecomponents.metal3.io +spec: + group: metal3.io + names: + kind: HostFirmwareComponents + listKind: HostFirmwareComponentsList + plural: hostfirmwarecomponents + singular: hostfirmwarecomponents + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: HostFirmwareComponents is the Schema for the hostfirmwarecomponents + API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: HostFirmwareComponentsSpec defines the desired state of HostFirmwareComponents. + properties: + updates: + items: + description: FirmwareUpdate defines a firmware update specification. + properties: + component: + type: string + url: + type: string + required: + - component + - url + type: object + type: array + required: + - updates + type: object + status: + description: HostFirmwareComponentsStatus defines the observed state of + HostFirmwareComponents. + properties: + components: + description: Components is the list of all available firmware components + and their information. + items: + description: FirmwareComponentStatus defines the status of a firmware + component. + properties: + component: + type: string + currentVersion: + type: string + initialVersion: + type: string + lastVersionFlashed: + type: string + updatedAt: + format: date-time + type: string + required: + - component + - initialVersion + type: object + type: array + conditions: + description: Track whether updates stored in the spec are valid based + on the schema + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + lastUpdated: + description: Time that the status was last updated + format: date-time + type: string + updates: + description: |- + Updates is the list of all firmware components that should be updated + they are specified via name and url fields. + items: + description: FirmwareUpdate defines a firmware update specification. + properties: + component: + type: string + url: + type: string + required: + - component + - url + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml new file mode 100644 index 00000000..8bdb8f51 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml @@ -0,0 +1,158 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.5 + labels: + clusterctl.cluster.x-k8s.io: "" + name: hostfirmwaresettings.metal3.io +spec: + group: metal3.io + names: + kind: HostFirmwareSettings + listKind: HostFirmwareSettingsList + plural: hostfirmwaresettings + shortNames: + - hfs + singular: hostfirmwaresettings + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: HostFirmwareSettings is the Schema for the hostfirmwaresettings + API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: HostFirmwareSettingsSpec defines the desired state of HostFirmwareSettings. + properties: + settings: + additionalProperties: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + description: Settings are the desired firmware settings stored as + name/value pairs. + type: object + required: + - settings + type: object + status: + description: HostFirmwareSettingsStatus defines the observed state of + HostFirmwareSettings. + properties: + conditions: + description: Track whether settings stored in the spec are valid based + on the schema + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + lastUpdated: + description: Time that the status was last updated + format: date-time + type: string + schema: + description: |- + FirmwareSchema is a reference to the Schema used to describe each + FirmwareSetting. By default, this will be a Schema in the same + Namespace as the settings but it can be overwritten in the Spec + properties: + name: + description: '`name` is the reference to the schema.' + type: string + namespace: + description: '`namespace` is the namespace of the where the schema + is stored.' + type: string + required: + - name + - namespace + type: object + settings: + additionalProperties: + type: string + description: Settings are the firmware settings stored as name/value + pairs + type: object + required: + - settings + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostupdatepolicies.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostupdatepolicies.yaml new file mode 100644 index 00000000..611b8f3b --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-hostupdatepolicies.yaml @@ -0,0 +1,62 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.5 + labels: + clusterctl.cluster.x-k8s.io: "" + name: hostupdatepolicies.metal3.io +spec: + group: metal3.io + names: + kind: HostUpdatePolicy + listKind: HostUpdatePolicyList + plural: hostupdatepolicies + singular: hostupdatepolicy + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: HostUpdatePolicy is the Schema for the hostupdatepolicy API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: HostUpdatePolicySpec defines the desired state of HostUpdatePolicy. + properties: + firmwareSettings: + description: Defines policy for changing firmware settings + enum: + - onPreparing + - onReboot + type: string + firmwareUpdates: + description: Defines policy for updating firmware + enum: + - onPreparing + - onReboot + type: string + type: object + status: + description: HostUpdatePolicyStatus defines the observed state of HostUpdatePolicy. + type: object + type: object + served: true + storage: true diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml new file mode 100644 index 00000000..3841cd32 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml @@ -0,0 +1,180 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.5 + labels: + clusterctl.cluster.x-k8s.io: "" + name: preprovisioningimages.metal3.io +spec: + group: metal3.io + names: + kind: PreprovisioningImage + listKind: PreprovisioningImageList + plural: preprovisioningimages + shortNames: + - ppimg + singular: preprovisioningimage + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Whether the image is ready + jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - description: The reason for the image readiness status + jsonPath: .status.conditions[?(@.type=='Ready')].reason + name: Reason + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: PreprovisioningImage is the Schema for the preprovisioningimages + API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: PreprovisioningImageSpec defines the desired state of PreprovisioningImage. + properties: + acceptFormats: + description: acceptFormats is a list of acceptable image formats. + items: + description: ImageFormat enumerates the allowed image formats + enum: + - iso + - initrd + type: string + type: array + architecture: + description: architecture is the processor architecture for which + to build the image. + type: string + networkDataName: + description: |- + networkDataName is the name of a Secret in the local namespace that + contains network data to build in to the image. + type: string + type: object + status: + description: PreprovisioningImageStatus defines the observed state of + PreprovisioningImage. + properties: + architecture: + description: architecture is the processor architecture for which + the image is built + type: string + conditions: + description: conditions describe the state of the built image + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + extraKernelParams: + description: |- + extraKernelParams is a string with extra parameters to pass to the + kernel when booting the image over network. Only makes sense for initrd images. + type: string + format: + description: |- + format is the type of image that is available at the download url: + either iso or initrd. + enum: + - iso + - initrd + type: string + imageUrl: + description: imageUrl is the URL from which the built image can be + downloaded. + type: string + kernelUrl: + description: |- + kernelUrl is the URL from which the kernel of the image can be downloaded. + Only makes sense for initrd images. + type: string + networkData: + description: |- + networkData is a reference to the version of the Secret containing the + network data used to build the image. + properties: + name: + type: string + version: + type: string + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/NOTES.txt b/charts/metal3/0.15.0/charts/baremetal-operator/templates/NOTES.txt new file mode 100644 index 00000000..47f9ee7e --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/NOTES.txt @@ -0,0 +1,16 @@ +1. Get the application URL by running these commands: +{{- if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "baremetal-operator.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "baremetal-operator.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "baremetal-operator.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "baremetal-operator.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/_helpers.tpl b/charts/metal3/0.15.0/charts/baremetal-operator/templates/_helpers.tpl new file mode 100644 index 00000000..e5057e3a --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/_helpers.tpl @@ -0,0 +1,79 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "baremetal-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "baremetal-operator.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "baremetal-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "baremetal-operator.labels" -}} +helm.sh/chart: {{ include "baremetal-operator.chart" . }} +{{ include "baremetal-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "baremetal-operator.selectorLabels" -}} +app.kubernetes.io/component: baremetal-operator +app.kubernetes.io/name: {{ include "baremetal-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "baremetal-operator.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "baremetal-operator.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create the URL to use for connecting to the Ironic servers (e.g. API, cache) +*/}} +{{- define "baremetal-operator.ironicHttpHost" -}} +{{- $hostIP := include "metal3.hostIP" . -}} +{{- with .Values.global }} +{{- if .provisioningHostname }} +{{- .provisioningHostname }} +{{- else if regexMatch ".*:.*" $hostIP}} +{{- print "[" $hostIP "]" }} +{{- else }} +{{- $hostIP }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/certificate.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/certificate.yaml new file mode 100644 index 00000000..2d424b75 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/certificate.yaml @@ -0,0 +1,14 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "baremetal-operator.fullname" . }}-serving-cert + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} +spec: + dnsNames: + - baremetal-operator-webhook-service.{{ .Release.Namespace }}.svc + - baremetal-operator-webhook-service.{{ .Release.Namespace }}.svc.cluster.local + issuerRef: + kind: Issuer + name: {{ include "baremetal-operator.fullname" . }}-selfsigned-issuer + secretName: bmo-webhook-server-cert diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/clusterrole-manager.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/clusterrole-manager.yaml new file mode 100644 index 00000000..ec4351ad --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/clusterrole-manager.yaml @@ -0,0 +1,206 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: {{ include "baremetal-operator.fullname" . }}-manager-role + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - events + verbs: + - create + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - update + - watch +- apiGroups: + - metal3.io + resources: + - baremetalhosts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - baremetalhosts/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - bmceventsubscriptions + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - bmceventsubscriptions/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - firmwareschemas + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - firmwareschemas/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - hardware/finalizers + verbs: + - update +- apiGroups: + - metal3.io + resources: + - hardwaredata + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - hostfirmwaresettings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - hostfirmwaresettings/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - preprovisioningimages + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - preprovisioningimages/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - dataimages + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - dataimages/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - hostfirmwarecomponents + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - hostfirmwarecomponents/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - hostupdatepolicies + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - hostupdatepolicies/status + verbs: + - get + - patch + - update diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/clusterrolebinding-manager.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/clusterrolebinding-manager.yaml new file mode 100644 index 00000000..b02f6ba6 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/clusterrolebinding-manager.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "baremetal-operator.fullname" . }}-manager-rolebinding + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "baremetal-operator.fullname" . }}-manager-role +subjects: +- kind: ServiceAccount + name: {{ include "baremetal-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/configmap-ironic.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/configmap-ironic.yaml new file mode 100644 index 00000000..d850d2c8 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/configmap-ironic.yaml @@ -0,0 +1,31 @@ + {{- $enableTLS := .Values.global.enable_tls }} + {{- $enableVMediaTLS := .Values.global.enable_vmedia_tls }} + {{- $protocol := ternary "https" "http" $enableTLS }} + {{- $ironicHost := include "baremetal-operator.ironicHttpHost" . | required "Missing host information for BMO to connect to Ironic" }} + {{- $ironicApiHost := print $ironicHost ":6385" }} + {{- $ironicBootHost := print $ironicHost ":6180" }} + {{- $ironicCacheHost := print $ironicHost ":6180" }} + +apiVersion: v1 +data: + IRONIC_ENDPOINT: "{{ $protocol }}://{{ $ironicApiHost }}/v1/" + # Switch VMedia to HTTP if enable_vmedia_tls is false + {{- if and $enableTLS $enableVMediaTLS }} + {{- $ironicBootHost = print $ironicHost ":" .Values.global.vmediaTLSPort }} + {{- $ironicCacheHost = print $ironicHost ":" .Values.global.vmediaTLSPort }} + {{- $protocol = "https" }} + RESTART_CONTAINER_CERTIFICATE_UPDATED: "true" + {{- else }} + {{- $protocol = "http" }} + RESTART_CONTAINER_CERTIFICATE_UPDATED: "false" + {{- end }} + CACHEURL: "{{ $protocol }}://{{ $ironicCacheHost }}/images" + {{- if .Values.baremetaloperator.externalHttpIPv6 }} + {{- $port := ternary .Values.global.vmediaTLSPort .Values.baremetaloperator.httpPort $enableVMediaTLS }} + IRONIC_EXTERNAL_URL_V6: "{{ $protocol }}://[{{ .Values.baremetaloperator.externalHttpIPv6 }}]:{{ $port }}" + {{- end }} +kind: ConfigMap +metadata: + name: baremetal-operator-ironic + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/deployment.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/deployment.yaml new file mode 100644 index 00000000..7cc103cf --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/deployment.yaml @@ -0,0 +1,112 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} + control-plane: controller-manager + webhook: metal3-io-v1alpha1-baremetalhost + name: {{ include "baremetal-operator.fullname" . }}-controller-manager +spec: + minReadySeconds: 10 + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "baremetal-operator.selectorLabels" . | nindent 6 }} + control-plane: controller-manager + template: + metadata: + annotations: + checksum/config-env: {{ include (print $.Template.BasePath "/configmap-ironic.yaml") . | sha256sum }} + labels: + {{- include "baremetal-operator.selectorLabels" . | nindent 8 }} + control-plane: controller-manager + webhook: metal3-io-v1alpha1-baremetalhost + spec: + containers: + - args: + - --enable-leader-election + - --tls-min-version=TLS13 + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + envFrom: + - configMapRef: + name: {{ include "baremetal-operator.fullname" . }}-ironic + image: "{{ .Values.images.baremetalOperator.repository }}:{{ .Values.images.baremetalOperator.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.images.baremetalOperator.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + livenessProbe: + failureThreshold: 10 + httpGet: + path: /healthz + port: 9440 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 2 + name: manager + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + - containerPort: 8443 + protocol: TCP + name: https + readinessProbe: + failureThreshold: 10 + httpGet: + path: /readyz + port: 9440 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 2 + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + {{- if .Values.global.enable_basicAuth }} + - name: ironic-basic-auth + mountPath: "/opt/metal3/auth/ironic/username" + subPath: username + readOnly: true + - name: ironic-basic-auth + mountPath: "/opt/metal3/auth/ironic/password" + subPath: password + readOnly: true + {{- end }} + {{- if .Values.global.enable_tls }} + - name: cacert + mountPath: "/opt/metal3/certs/ca" + readOnly: true + {{- end }} + serviceAccountName: {{ include "baremetal-operator.serviceAccountName" . }} + terminationGracePeriodSeconds: 10 + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: bmo-webhook-server-cert + {{- if .Values.global.enable_basicAuth }} + - name: ironic-basic-auth + secret: + secretName: ironic-basic-auth + {{- end }} + {{- if .Values.global.enable_tls }} + - name: cacert + secret: + secretName: ironic-cacert + {{- end }} + {{- with .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/issuer.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/issuer.yaml new file mode 100644 index 00000000..9b12180f --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/issuer.yaml @@ -0,0 +1,8 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} + name: {{ include "baremetal-operator.fullname" . }}-selfsigned-issuer +spec: + selfSigned: {} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_auth_role.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_auth_role.yaml new file mode 100644 index 00000000..ffa9756a --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_auth_role.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "baremetal-operator.fullname" . }}-metrics-auth-role + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_auth_role_binding.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_auth_role_binding.yaml new file mode 100644 index 00000000..dce821ec --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_auth_role_binding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "baremetal-operator.fullname" . }}-metrics-auth-rolebinding + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "baremetal-operator.fullname" . }}-metrics-auth-role +subjects: +- kind: ServiceAccount + name: {{ include "baremetal-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_reader_role.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_reader_role.yaml new file mode 100644 index 00000000..c93d5b9e --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_reader_role.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "baremetal-operator.fullname" . }}-metrics-reader + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} +rules: +- nonResourceURLs: + - "/metrics" + verbs: + - get diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_service.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_service.yaml new file mode 100644 index 00000000..b1c39a78 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/metrics_service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} + control-plane: controller-manager + name: {{ include "baremetal-operator.fullname" . }}-controller-manager-metrics-service +spec: + ipFamilyPolicy: PreferDualStack + ports: + - name: https + port: 8443 + targetPort: https + selector: + control-plane: controller-manager diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/role.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/role.yaml new file mode 100644 index 00000000..313066a4 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/role.yaml @@ -0,0 +1,45 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "baremetal-operator.fullname" . }}-leader-election-role + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - configmaps/status + verbs: + - get + - update + - patch +- apiGroups: + - "" + resources: + - events + verbs: + - create +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/rolebinding.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/rolebinding.yaml new file mode 100644 index 00000000..4492103e --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/rolebinding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "baremetal-operator.fullname" . }}-leader-election-rolebinding + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "baremetal-operator.fullname" . }}-leader-election-role +subjects: +- kind: ServiceAccount + name: {{ include "baremetal-operator.serviceAccountName" . }} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/service-webhook.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/service-webhook.yaml new file mode 100644 index 00000000..25868cfc --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/service-webhook.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} + name: {{ include "baremetal-operator.fullname" . }}-webhook-service +spec: + ipFamilyPolicy: PreferDualStack + ports: + - port: 443 + targetPort: 9443 + selector: + control-plane: controller-manager + webhook: metal3-io-v1alpha1-baremetalhost diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/serviceaccount.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/serviceaccount.yaml new file mode 100644 index 00000000..4eab8805 --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "baremetal-operator.serviceAccountName" . }} + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/templates/validatingwebhookconfiguration.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/templates/validatingwebhookconfiguration.yaml new file mode 100644 index 00000000..55746b9e --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/templates/validatingwebhookconfiguration.yaml @@ -0,0 +1,51 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "baremetal-operator.fullname" . }}-serving-cert + name: {{ include "baremetal-operator.fullname" . }}-validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + - v1beta + clientConfig: + service: + name: {{ include "baremetal-operator.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metal3-io-v1alpha1-baremetalhost + failurePolicy: Fail + name: baremetalhost.metal3.io + rules: + - apiGroups: + - metal3.io + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - baremetalhosts + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta + clientConfig: + service: + name: {{ include "baremetal-operator.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metal3-io-v1alpha1-bmceventsubscription + failurePolicy: Fail + name: bmceventsubscription.metal3.io + rules: + - apiGroups: + - metal3.io + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - bmceventsubscriptions + sideEffects: None diff --git a/charts/metal3/0.15.0/charts/baremetal-operator/values.yaml b/charts/metal3/0.15.0/charts/baremetal-operator/values.yaml new file mode 100644 index 00000000..4fba6c6c --- /dev/null +++ b/charts/metal3/0.15.0/charts/baremetal-operator/values.yaml @@ -0,0 +1,91 @@ +# Default values for baremetal-operator. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +global: + # specify comma serparate beginning and end of the range of IP + # addresses the DHCP server will manage. + dhcpRange: 192.168.20.20,192.168.20.80 + + # Network interface on which provisioning network can be accessed + provisioningInterface: ens4 + + # IP Address assigned to network interface on provisioning network + provisioningIP: 192.168.20.5 + + # If running in a multi-node kubernetes cluster, "pin" the baremtal container + # to the same host where the ironic and media containers + # arerunning. Uncomment the nodeSelector and update the hostname accordingly. + #nodeSelector: + #kubernetes.io/hostname: "my-hostname" + + # Comment this out when pinning the baremetal-operator container to a specfic host. + nodeSelector: {} + +replicaCount: 1 + +images: + baremetalOperator: + repository: registry.opensuse.org/isv/suse/edge/containers/images/baremetal-operator + pullPolicy: IfNotPresent + tag: "0.12.3.0" + +imagePullSecrets: [] +nameOverride: "manger" +fullnameOverride: "baremetal-operator" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "baremetal-operator-controller-manager" + +podAnnotations: {} + +securityContext: + runAsUser: 11000 + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + +service: + type: ClusterIP + port: 80 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +tolerations: [] + +affinity: {} + +baremetaloperator: + httpPort: "6180" + + # IPv6 used for accessing the Ironic HTTP server for BMCs with an IPv6 only address. + # It should not be used in conjunction with 'provisioningHostname' unless BMCs do not + # support hostnames. + externalHttpIPv6: "" diff --git a/charts/metal3/0.15.0/charts/ironic/.helmignore b/charts/metal3/0.15.0/charts/ironic/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/metal3/0.15.0/charts/ironic/Chart.yaml b/charts/metal3/0.15.0/charts/ironic/Chart.yaml new file mode 100644 index 00000000..f012cc64 --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 35.0.0 +description: A Helm chart for Ironic, used by Metal3 +name: ironic +type: application +version: 0.13.0 diff --git a/charts/metal3/0.15.0/charts/ironic/README.md b/charts/metal3/0.15.0/charts/ironic/README.md new file mode 100644 index 00000000..860ebcab --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/README.md @@ -0,0 +1,24 @@ +## How to Enable Provisioning Network + +By default PXE boot functionality is disabled, so deployments via e.g redfish-virtualmedia may +be performed without any dedicated provisioning network. + +For PXE boot a dedicated network is required, in this case we run a dnsmasq instance to provide +DHCP and require a dedicated NIC for connectivity to the provisioning network on each host. + +To enable this mode you must provide the following additional configuration (note the values are +examples and will depend on your environment): + +``` +global: + enable_dnsmasq: true + enable_pxe_boot: true + dnsmasqDefaultRouter: 192.168.21.254 + dnsmasqDNSServer: 192.168.20.5 + dhcpRange: 192.168.20.20,192.168.20.80 + provisioningInterface: ens4 + provisioningIP: 192.168.20.5 +``` + +Note that these values *must not* conflict with your controlplane or other networks otherwise unexpected +behavior is likely - a dedicated physical network is required in this configuration. diff --git a/charts/metal3/0.15.0/charts/ironic/templates/_helpers.tpl b/charts/metal3/0.15.0/charts/ironic/templates/_helpers.tpl new file mode 100644 index 00000000..1dd83c52 --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/templates/_helpers.tpl @@ -0,0 +1,137 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "ironic.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "ironic.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "ironic.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "ironic.labels" -}} +helm.sh/chart: {{ include "ironic.chart" . }} +{{ include "ironic.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "ironic.selectorLabels" -}} +app.kubernetes.io/component: ironic +app.kubernetes.io/name: {{ include "ironic.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "ironic.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "ironic.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Shared directory volumeMount +*/}} +{{- define "ironic.sharedVolumeMount" -}} +- mountPath: /shared + name: ironic-data-volume +{{- end }} + +{{/* +Get ironic CA volumeMounts +*/}} +{{- define "ironic.CAVolumeMounts" -}} +- name: cert-ironic-ca + mountPath: "/certs/ca/ironic" + readOnly: true +{{- if .Values.global.enable_vmedia_tls }} +- name: cert-ironic-vmedia-ca + mountPath: "/certs/ca/vmedia" + readOnly: true +{{- end }} +{{- if .Values.global.trustedCAs }} +- name: trusted-ca + mountPath: "/certs/ca/trusted" + readOnly: true +{{- end }} +{{- end }} + +{{/* +Get the formatted "External" hostname or IP based URL +*/}} +{{- define "ironic.externalHttpUrl" }} +{{- $host := ternary (include "metal3.hostIP" .) .Values.global.externalHttpHost (empty .Values.global.externalHttpHost) }} +{{- if regexMatch ".*:.*" $host }} +{{- $host = print "[" $host "]" }} +{{- end }} +{{- $protocol := "http" }} +{{- $port := "6180" }} +{{- if .Values.global.enable_vmedia_tls }} +{{- $protocol = "https" }} +{{- $port = .Values.global.vmediaTLSPort | default "6185" }} +{{- end }} +{{- print $protocol "://" $host ":" $port }} +{{- end }} + +{{/* +Get the command to use for Liveness and Readiness probes +*/}} +{{- define "ironic.probeCommand" }} +{{- $host := "127.0.0.1" }} +{{- if eq .Values.listenOnAll false }} +{{- $host = coalesce .Values.global.provisioningIP .Values.global.ironicIP .Values.global.provisioningHostname }} +{{- if regexMatch ".*:.*" $host }} +{{- $host = print "[" $host "]" }} +{{- end }} +{{- end }} +{{- print "curl -sSfk https://" $host ":6385" }} +{{- end }} + +{{/* +Create the subjectAltNames section to be set on the Certificate +*/}} +{{- define "ironic.subjectAltNames" -}} +{{- with .Values.global }} +{{- if .provisioningHostname }} +dnsNames: +- {{ .provisioningHostname }} +{{- end -}} +{{- if or .ironicIP .provisioningIP }} +ipAddresses: + - {{ coalesce .provisioningIP .ironicIP }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/metal3/0.15.0/charts/ironic/templates/certificates.yaml b/charts/metal3/0.15.0/charts/ironic/templates/certificates.yaml new file mode 100644 index 00000000..af69a907 --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/templates/certificates.yaml @@ -0,0 +1,40 @@ +{{- if .Values.global.enable_tls -}} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: ironic-cacert +spec: + commonName: ironic-ca + isCA: true + {{- include "ironic.subjectAltNames" . | indent 2 }} + issuerRef: + kind: Issuer + name: selfsigned-issuer + secretName: ironic-cacert +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: ironic-cert +spec: + commonName: ironic-cert + {{- include "ironic.subjectAltNames" . | indent 2 }} + issuerRef: + kind: Issuer + name: ca-issuer + secretName: ironic-cert +{{- if .Values.global.enable_vmedia_tls }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: ironic-vmedia-cert +spec: + commonName: ironic-vmedia-cert + {{- include "ironic.subjectAltNames" . | indent 2 }} + issuerRef: + kind: Issuer + name: ca-issuer + secretName: ironic-vmedia-cert +{{- end }} +{{- end }} diff --git a/charts/metal3/0.15.0/charts/ironic/templates/configmap.yaml b/charts/metal3/0.15.0/charts/ironic/templates/configmap.yaml new file mode 100644 index 00000000..ee6acc2c --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/templates/configmap.yaml @@ -0,0 +1,62 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ironic + labels: + {{- include "ironic.labels" . | nindent 4 }} +data: + {{- if ( .Values.global.enable_dnsmasq ) }} + DNSMASQ_DNS_SERVER_ADDRESS: {{ .Values.global.dnsmasqDNSServer }} + DNSMASQ_DEFAULT_ROUTER: {{ .Values.global.dnsmasqDefaultRouter }} + DHCP_RANGE: {{ .Values.global.dhcpRange }} + {{- end }} + {{- if .Values.debug.ironicRamdiskSshKey }} + IRONIC_RAMDISK_SSH_KEY: {{ .Values.debug.ironicRamdiskSshKey }} + {{- end }} + HTTP_PORT: "6180" + PREDICTABLE_NIC_NAMES: "{{ .Values.global.predictableNicNames }}" + IRONIC_EXTERNAL_HTTP_URL: {{ include "ironic.externalHttpUrl" . }} + ENABLE_PXE_BOOT: "{{ .Values.global.enable_pxe_boot }}" + {{- if .Values.global.provisioningInterface }} + PROVISIONING_INTERFACE: {{ .Values.global.provisioningInterface }} + {{- end }} + {{- if .Values.global.provisioningIP }} + PROVISIONING_IP: {{ include "metal3.hostIP" . }} + {{- else if .Values.global.ironicIP }} + IRONIC_IP: {{ include "metal3.hostIP" . }} + {{- else if .Values.global.provisioningHostname }} + IRONIC_URL_HOSTNAME: {{ .Values.global.provisioningHostname }} + {{- end }} + IRONIC_FAST_TRACK: "true" + LISTEN_ALL_INTERFACES: "{{ .Values.listenOnAll }}" + {{- if ( .Values.global.enable_tls ) }} + RESTART_CONTAINER_CERTIFICATE_UPDATED: "true" + IRONIC_KERNEL_PARAMS: {{ .Values.global.ironicKernelParams }} tls.enabled=true + IRONIC_IPA_INSECURE: "0" + IRONIC_REVERSE_PROXY_SETUP: "true" + {{- if .Values.global.trustedCAs }} + WEBSERVER_CACERT_FILE: /certs/ca/trusted/ca-bundle.pem + {{- else }} + WEBSERVER_CACERT_FILE: /var/lib/ca-certificates/ca-bundle.pem + {{- end }} + {{- if ( .Values.global.enable_vmedia_tls ) }} + VMEDIA_TLS_PORT: "{{ .Values.global.vmediaTLSPort }}" + {{- end }} + {{- else }} + RESTART_CONTAINER_CERTIFICATE_UPDATED: "false" + IRONIC_KERNEL_PARAMS: {{ .Values.global.ironicKernelParams }} + IRONIC_IPA_INSECURE: "1" + IRONIC_REVERSE_PROXY_SETUP: "false" + {{- end }} + {{- if ( .Values.global.enable_basicAuth ) }} + AUTH_STRATEGY: "http_basic" + {{- end }} + {{- if .Values.global.enable_mariadb }} + MARIADB_HOST: {{ .Values.global.databaseServiceName }}.{{ .Release.Namespace }}.svc.cluster.local + IRONIC_USE_MARIADB: "true" + {{- else }} + IRONIC_USE_MARIADB: "false" + {{- end }} + {{- with .Values.ironicExtraEnv -}} + {{ toYaml . | nindent 2 }} + {{- end -}} \ No newline at end of file diff --git a/charts/metal3/0.15.0/charts/ironic/templates/deployment.yaml b/charts/metal3/0.15.0/charts/ironic/templates/deployment.yaml new file mode 100644 index 00000000..34d0180d --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/templates/deployment.yaml @@ -0,0 +1,272 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "ironic.fullname" . }} + labels: + {{- include "ironic.labels" . | nindent 4 }} +spec: + minReadySeconds: 10 + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "ironic.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + annotations: + checksum/config-env: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "ironic.selectorLabels" . | nindent 8 }} + spec: + {{- if .Values.podSecurityContext }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- end }} + {{- if .Values.baremetaloperator.ironichostNetwork }} + hostNetwork: {{ .Values.baremetaloperator.ironichostNetwork }} + {{- end }} + containers: + - name: ironic-httpd + image: {{ .Values.images.ironic.repository }}:{{ .Values.images.ironic.tag }} + imagePullPolicy: {{ .Values.images.ironic.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + command: + - /bin/runhttpd + envFrom: + - configMapRef: + name: ironic + livenessProbe: + exec: + command: ["sh", "-c", "{{ include "ironic.probeCommand" . }}"] + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + ports: + {{- if and .Values.global.enable_tls .Values.global.enable_vmedia_tls }} + - containerPort: {{ .Values.global.vmediaTLSPort }} + name: httpd-tls + protocol: TCP + {{- else }} + - containerPort: 6180 + name: httpd + protocol: TCP + {{- end }} + readinessProbe: + exec: + command: ["sh", "-c", "{{ include "ironic.probeCommand" . }}"] + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + {{- if .Values.global.enable_tls }} + {{- include "ironic.CAVolumeMounts" . | nindent 10 }} + - name: cert-ironic + mountPath: "/certs/ironic" + readOnly: true + {{- if .Values.global.enable_vmedia_tls }} + - name: cert-ironic-vmedia + mountPath: "/certs/vmedia" + readOnly: true + {{- end }} + {{- end }} + - name: ironic-log-watch + image: {{ .Values.images.ironic.repository }}:{{ .Values.images.ironic.tag }} + imagePullPolicy: {{ .Values.images.ironic.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + command: + - /bin/runlogwatch.sh + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + - name: ironic + image: {{ .Values.images.ironic.repository }}:{{ .Values.images.ironic.tag }} + imagePullPolicy: {{ .Values.images.ironic.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + command: + - /bin/runironic + envFrom: + - configMapRef: + name: ironic + env: + {{- if .Values.global.enable_basicAuth }} + - name: IRONIC_HTPASSWD + valueFrom: + secretKeyRef: + name: ironic-basic-auth + key: htpasswd + {{- end }} + {{- if .Values.global.enable_mariadb }} + - name: MARIADB_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: ironic-mariadb + {{- end }} + livenessProbe: + exec: + command: ["/bin/ironic-liveness"] + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 10 + successThreshold: 1 + failureThreshold: 10 + ports: + - containerPort: 6385 + name: api + protocol: TCP + readinessProbe: + exec: + command: ["/bin/ironic-readiness"] + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 10 + successThreshold: 1 + failureThreshold: 10 + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + {{- if .Values.global.enable_basicAuth }} + - mountPath: "/auth/ironic/auth-config" + name: ironic-basic-auth + subPath: auth-config + readOnly: true + {{- end }} + {{- if .Values.global.enable_tls }} + {{- include "ironic.CAVolumeMounts" . | nindent 10 }} + - name: cert-ironic + mountPath: "/certs/ironic" + readOnly: true + {{- end }} + {{- if .Values.global.enable_dnsmasq }} + - name: ironic-dnsmasq + image: {{ .Values.images.ironic.repository }}:{{ .Values.images.ironic.tag }} + imagePullPolicy: {{ .Values.images.ironic.pullPolicy }} + securityContext: + {{- merge .Values.securityContext .Values.dnsmasqSecurityContext | toYaml | nindent 10 }} + command: + - /bin/rundnsmasq + envFrom: + - configMapRef: + name: ironic + livenessProbe: + exec: + command: + - sh + - -c + - ss -lun | grep :67 && ss -lun | grep :69 + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + ports: + - containerPort: 67 + name: dhcp + protocol: UDP + - containerPort: 69 + name: tftp + protocol: UDP + readinessProbe: + exec: + command: + - sh + - -c + - ss -lun | grep :67 && ss -lun | grep :69 + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + {{- end }} + initContainers: + - name: ironic-ipa-downloader + image: {{ .Values.images.ironicIPADownloader.repository }}:{{ .Values.images.ironicIPADownloader.tag }} + imagePullPolicy: {{ .Values.images.ironicIPADownloader.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + command: + - /usr/local/bin/get-resource.sh + env: + {{- if .Values.ipa.useHauler }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: REGISTRY_INSECURE + value: "true" + {{- end }} + - name: IPA_BASEURI + {{- if .Values.ipa.baseUri }} + value: {{ .Values.ipa.baseUri }} + {{- else if .Values.images.ipa }} + {{- $image := .Values.images.ipa }} + {{- $url := urlParse ( print "oci://" $image.repository ) }} + {{- if .Values.ipa.useHauler }} + {{- $url := set $url "host" "$(HOST_IP):6545" }} + {{- end }} + value: {{ urlJoin $url }}:{{ .Values.images.ipa.tag }} + {{- end }} + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + volumes: + - name: ironic-data-volume + {{- if .Values.persistence.ironic.size }} + persistentVolumeClaim: + claimName: ironic-shared-volume + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.global.enable_basicAuth }} + - name: ironic-basic-auth + secret: + secretName: ironic-basic-auth + {{- end }} + {{- if .Values.global.trustedCAs }} + - name: trusted-ca + configMap: + name: {{ .Values.global.trustedCAs }} + {{- end }} + {{- if .Values.global.enable_tls }} + - name: cert-ironic-ca + secret: + secretName: ironic-cacert + - name: cert-ironic + secret: + secretName: ironic-cert + {{- if .Values.global.enable_vmedia_tls }} + - name: cert-ironic-vmedia-ca + secret: + secretName: ironic-cacert + - name: cert-ironic-vmedia + secret: + secretName: ironic-vmedia-cert + {{- end }} + {{- end }} + {{- with .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.global.dnsPolicy }} + dnsPolicy: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/metal3/0.15.0/charts/ironic/templates/issuers.yaml b/charts/metal3/0.15.0/charts/ironic/templates/issuers.yaml new file mode 100644 index 00000000..f97de264 --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/templates/issuers.yaml @@ -0,0 +1,16 @@ +{{- if .Values.global.enable_tls -}} +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: selfsigned-issuer +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: ca-issuer +spec: + ca: + secretName: ironic-cacert +{{- end }} diff --git a/charts/metal3/0.15.0/charts/ironic/templates/pvc.yaml b/charts/metal3/0.15.0/charts/ironic/templates/pvc.yaml new file mode 100644 index 00000000..c757dd3f --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/templates/pvc.yaml @@ -0,0 +1,26 @@ +{{- if .Values.persistence.ironic.size }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: ironic-shared-volume + {{- if .Values.persistence.ironic.keep }} + annotations: + "helm.sh/resource-policy": keep + {{- end }} +spec: + accessModes: + {{- if .Values.persistence.ironic.accessMode }} + - {{ .Values.persistence.ironic.accessMode }} + {{- else if eq (int .Values.replicaCount) 1 }} + - ReadWriteOnce + {{- else }} + - ReadWriteMany + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.ironic.size }} + {{- if .Values.persistence.ironic.storageClass }} + storageClassName: {{ .Values.persistence.ironic.storageClass }} + {{- end }} + volumeMode: Filesystem +{{- end }} diff --git a/charts/metal3/0.15.0/charts/ironic/templates/secret-tls.yaml b/charts/metal3/0.15.0/charts/ironic/templates/secret-tls.yaml new file mode 100644 index 00000000..1f1611dd --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/templates/secret-tls.yaml @@ -0,0 +1,16 @@ +{{- if and (.Values.global.enable_tls) + (ne .Values.tlscerts.crt "") + (ne .Values.tlscerts.key "") + (ne .Values.tlscerts.cacert "") -}} +apiVersion: v1 +kind: Secret +metadata: + name: ironic-cacert + labels: + {{- include "ironic.labels" . | nindent 4 }} +type: Opaque +data: + tls.crt: {{ .Values.tlscerts.crt | toString | b64enc }} + tls.key: {{ .Values.tlscerts.key | toString | b64enc }} + ca.crt: {{ .Values.tlscerts.cacert | toString | b64enc }} +{{- end }} diff --git a/charts/metal3/0.15.0/charts/ironic/templates/secrets-basic-auth.yaml b/charts/metal3/0.15.0/charts/ironic/templates/secrets-basic-auth.yaml new file mode 100644 index 00000000..0ef47d37 --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/templates/secrets-basic-auth.yaml @@ -0,0 +1,33 @@ +{{- if .Values.global.enable_basicAuth }} + +{{- $ironicUsername := "" -}} +{{- $ironicPassword := "" -}} +{{- $ironicSecretName := "ironic-basic-auth" -}} + +# Check if the secret is deployed and has a password +{{- $oldIronicSecret := lookup "v1" "Secret" .Release.Namespace $ironicSecretName }} +{{- if and $oldIronicSecret (index $oldIronicSecret.data "username") (index $oldIronicSecret.data "password") }} +{{- $ironicUsername = b64dec (index $oldIronicSecret.data "username" | toString) -}} +{{- $ironicPassword = b64dec (index $oldIronicSecret.data "password" | toString) -}} +# If not, check if a username and password are provided in values.yaml +{{- else if and (.Values.global.auth.ironicUsername) (.Values.global.auth.ironicPassword) }} +{{- $ironicUsername = .Values.global.auth.ironicUsername -}} +{{- $ironicPassword = .Values.global.auth.ironicPassword -}} +{{- else }} +# If no username and password are provided in values.yaml, generate new ones +{{- $ironicUsername = "ironic" -}} +{{- $ironicPassword = (randAlphaNum 20) -}} +{{- end }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ $ironicSecretName }} +type: Opaque +data: + username: {{ $ironicUsername | b64enc }} + password: {{ $ironicPassword | b64enc }} + htpasswd: {{ b64enc (htpasswd $ironicUsername $ironicPassword) }} + auth-config: | + {{- printf "[ironic]\nauth_type=http_basic\nusername: %s\npassword: %s" $ironicUsername $ironicPassword | b64enc | nindent 4 }} + +{{- end }} diff --git a/charts/metal3/0.15.0/charts/ironic/templates/service.yaml b/charts/metal3/0.15.0/charts/ironic/templates/service.yaml new file mode 100644 index 00000000..aaeb2615 --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/templates/service.yaml @@ -0,0 +1,40 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "ironic.fullname" . }} + labels: + {{- include "ironic.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ipFamilyPolicy: PreferDualStack + ports: + {{- $enableTLS := .Values.global.enable_tls }} + {{- $enableVMediaTLS := .Values.global.enable_vmedia_tls }} + {{- range .Values.service.ports }} + {{- if and (eq .name "httpd") (or (not $enableTLS) (not $enableVMediaTLS)) }} + - name: {{ .name }} + port: {{ .port }} + protocol: {{ .protocol }} + targetPort: {{ .targetPort }} + {{- else if and (eq .name "httpd-tls") ($enableTLS) ($enableVMediaTLS) }} + - name: {{ .name }} + port: {{ .port }} + protocol: {{ .protocol }} + targetPort: {{ .targetPort }} + {{- else if and (ne .name "httpd") (ne .name "httpd-tls") }} + - name: {{ .name }} + port: {{ .port }} + protocol: {{ .protocol }} + targetPort: {{ .targetPort }} + {{- end }} + {{- end }} + selector: + {{- include "ironic.selectorLabels" . | nindent 4 }} + {{- if or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort") }} + externalIPs: + {{- toYaml .Values.service.externalIPs | nindent 4 }} + {{- end }} diff --git a/charts/metal3/0.15.0/charts/ironic/templates/serviceaccount.yaml b/charts/metal3/0.15.0/charts/ironic/templates/serviceaccount.yaml new file mode 100644 index 00000000..25fcc8d5 --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "ironic.serviceAccountName" . }} + labels: + {{- include "ironic.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/metal3/0.15.0/charts/ironic/values.yaml b/charts/metal3/0.15.0/charts/ironic/values.yaml new file mode 100644 index 00000000..367d803d --- /dev/null +++ b/charts/metal3/0.15.0/charts/ironic/values.yaml @@ -0,0 +1,172 @@ +# Default values for ironic. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +global: + # whether to enable dnsmasq on the provisioning network (for PXE boot) + enable_dnsmasq: false + + # whether to enable PXE boot capability + # NOTE: enable_dnsmasq must set to 'true' in order for this option to be effective. + enable_pxe_boot: false + + # DNS Policy of the Ironic pod + dnsPolicy: "ClusterFirstWithHostNet" + + # IP address of the router associated with the specified DHCP + # address range + dnsmasqDefaultRouter: "" + + # IP address of the dns server to be provided with DHCP + # response + dnsmasqDNSServer: "" + + # specify comma-delimited xrange of IP addresses the DHCP server will manage. + # e.g 192.168.20.20,192.168.20.80 + dhcpRange: "" + + # Network interface on which provisioning network can be accessed + # Note this must be a dedicated NIC separate from the controlplane network + provisioningInterface: "" + + # IP Address assigned to network interface on provisioning network + provisioningIP: "" + + # Fully Qualified Domain Name used by Ironic for both binding (to the + # associated IPv4 and/or IPv6 addresses) and exposing the API, dnsmask and + # media, also used by BMO. Note, this is the only way to enable a fully + # working dual-stack configuration. + provisioningHostname: "" + + # Whether the NIC names should be predictable or not + predictableNicNames: "true" + + # The kernel params for Ironic + ironicKernelParams: "console=ttyS0" + + databaseServiceName: "metal3-mariadb" + + # In a multi-node kubernetes cluster, we need to "pin" the + # ironic containers to the given host where the + # provisioningIP exists. Uncomment the nodeSelector + # here and update the hostname accordingly. + #nodeSelector: + #kubernetes.io/hostname: "csrancher-n1" + + # Comment this out when pinning the pdns containers to a specfic host. + nodeSelector: {} + +replicaCount: 1 + +listenOnAll: true + +images: + ironic: + repository: registry.opensuse.org/isv/suse/edge/containers/images/ironic + pullPolicy: IfNotPresent + tag: 35.0.0.1 + ironicIPADownloader: + repository: registry.opensuse.org/isv/suse/edge/containers/images/ironic-ipa-downloader + pullPolicy: IfNotPresent + tag: 3.1.1 + ipa: + repository: registry.opensuse.org/isv/suse/edge/containers/images/ironic-python-agent + tag: 3.0.8 + +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +ipa: + useHauler: false + +podSecurityContext: + runAsUser: 10475 + fsGroup: 10475 + +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + +dnsmasqSecurityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + +service: + type: LoadBalancer + annotations: {} + externalIPs: [] + ports: + - name: httpd + port: 6180 + protocol: TCP + targetPort: 6180 + - name: httpd-tls + port: 6185 + protocol: TCP + targetPort: 6185 + - name: api + port: 6385 + protocol: TCP + targetPort: 6385 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +tolerations: [] + +affinity: {} + +baremetaloperator: + cloudflareApiToken: "foo" + ironichostNetwork: true + +debug: + ironicRamdiskSshKey: "" + +ironicExtraEnv: {} + +tlscerts: + cacert: "" + key: "" + crt: "" + +persistence: + ironic: + # storageClass for the ironic shared volume + # Ensure the storageClass is defined + storageClass: "" + # size of the ironic shared volume e.g "1Gi" + # When unset persistent storage is disabled and emptyDir is enabled + size: "" + # accessMode of the ironic shared volume PVC + # If empty defaults to ReadWriteOnce when replicaCount=1 otherwise ReadWriteMany + accessMode: "" + # flag to indicate to keep pvc upon helm uninstall + keep: false diff --git a/charts/metal3/0.15.0/charts/mariadb/.helmignore b/charts/metal3/0.15.0/charts/mariadb/.helmignore new file mode 100644 index 00000000..898df488 --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/.helmignore @@ -0,0 +1,24 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ + diff --git a/charts/metal3/0.15.0/charts/mariadb/Chart.yaml b/charts/metal3/0.15.0/charts/mariadb/Chart.yaml new file mode 100644 index 00000000..9feaf258 --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: "11.8" +description: A Helm chart for MariaDB, used by Metal3 +name: mariadb +type: application +version: 0.6.3 diff --git a/charts/metal3/0.15.0/charts/mariadb/templates/_helpers.tpl b/charts/metal3/0.15.0/charts/mariadb/templates/_helpers.tpl new file mode 100644 index 00000000..bd963d0e --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/templates/_helpers.tpl @@ -0,0 +1,64 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "mariadb.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "mariadb.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "mariadb.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "mariadb.labels" -}} +helm.sh/chart: {{ include "mariadb.chart" . }} +{{ include "mariadb.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "mariadb.selectorLabels" -}} +app.kubernetes.io/component: mariadb +app.kubernetes.io/name: {{ include "mariadb.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "mariadb.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "mariadb.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + diff --git a/charts/metal3/0.15.0/charts/mariadb/templates/configmap-mariadb.yaml b/charts/metal3/0.15.0/charts/mariadb/templates/configmap-mariadb.yaml new file mode 100644 index 00000000..8decd409 --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/templates/configmap-mariadb.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: mariadb-config + labels: + {{- include "mariadb.labels" . | nindent 4 }} +data: + ironic.conf: | + [mariadb] + max_connections 64 + max_heap_table_size 1M + innodb_buffer_pool_size 5M + innodb_log_buffer_size 512K \ No newline at end of file diff --git a/charts/metal3/0.15.0/charts/mariadb/templates/configmap.yaml b/charts/metal3/0.15.0/charts/mariadb/templates/configmap.yaml new file mode 100644 index 00000000..da642adc --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/templates/configmap.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: mariadb-cm + labels: + {{- include "mariadb.labels" . | nindent 4 }} +data: + MARIADB_USER: ironic + MARIADB_RANDOM_ROOT_PASSWORD: "yes" + MARIADB_DATABASE: ironic + MARIADB_AUTO_UPGRADE: "yes" \ No newline at end of file diff --git a/charts/metal3/0.15.0/charts/mariadb/templates/deployment.yaml b/charts/metal3/0.15.0/charts/mariadb/templates/deployment.yaml new file mode 100644 index 00000000..fa0fd52c --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/templates/deployment.yaml @@ -0,0 +1,122 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "mariadb.fullname" . }} + labels: + {{- include "mariadb.labels" . | nindent 4 }} +spec: + replicas: {{.Values.replicaCount}} + selector: + matchLabels: + {{- include "mariadb.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "mariadb.selectorLabels" . | nindent 8 }} + spec: + {{- $volmounts := toYaml .Values.volumeMounts | trim | nindent 10 }} + {{- $volumes := toYaml .Values.volumes | trim | nindent 8 }} + serviceAccountName: {{ include "mariadb.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + # This would run during entrypoint if run as root + - name: set-volume-owners + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + securityContext: + runAsUser: 0 + allowPrivilegeEscalation: true + capabilities: + drop: + - ALL + add: + - CHOWN + - FOWNER + - DAC_OVERRIDE + seccompProfile: + type: RuntimeDefault + volumeMounts: + - name: mariadb-conf + mountPath: /etc/mysql/conf.d + - name: mariadb-run + mountPath: /run/mysql + {{- $volmounts }} + command: ['bash', '-c', 'source /usr/local/bin/docker-entrypoint.sh && docker_create_db_directories'] + env: + - name: DATADIR + value: /var/lib/mysql + - name: SOCKET + value: /run/mysql/mysql.sock + containers: + - name: mariadb + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + envFrom: + - configMapRef: + name: mariadb-cm + env: + - name: MARIADB_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: ironic-mariadb + lifecycle: + preStop: + exec: + command: + - sh + - -c + - mysqladmin shutdown -uironic -p$(printenv MARIADB_PASSWORD) + livenessProbe: + exec: + command: + - healthcheck.sh + - --connect + - --innodb_initialized + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + ports: + - containerPort: 3306 + name: mariadb + protocol: TCP + readinessProbe: + exec: + command: + - healthcheck.sh + - --connect + - --innodb_initialized + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + volumeMounts: + - name: mariadb-conf + mountPath: /etc/mysql/conf.d + - name: mariadb-run + mountPath: /run/mysql + {{- $volmounts }} + {{- with .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: mariadb-conf + configMap: + name: mariadb-config + - name: mariadb-run + emptyDir: + sizeLimit: 20Mi + {{- $volumes }} diff --git a/charts/metal3/0.15.0/charts/mariadb/templates/pvc.yaml b/charts/metal3/0.15.0/charts/mariadb/templates/pvc.yaml new file mode 100644 index 00000000..573e1525 --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/templates/pvc.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mariadb-volume-claim + {{- if .Values.persistence.keep }} + annotations: + "helm.sh/resource-policy": keep + {{- end }} +spec: + accessModes: + {{- if .Values.persistence.accessMode }} + - {{ .Values.persistence.accessMode }} + {{- else if eq (int .Values.replicaCount) 1 }} + - ReadWriteOnce + {{- else }} + - ReadWriteMany + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size }} + {{- if .Values.persistence.storageClass }} + storageClassName: {{ .Values.persistence.storageClass }} + {{- end }} + volumeMode: Filesystem diff --git a/charts/metal3/0.15.0/charts/mariadb/templates/secret.yaml b/charts/metal3/0.15.0/charts/mariadb/templates/secret.yaml new file mode 100644 index 00000000..3cde9e58 --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/templates/secret.yaml @@ -0,0 +1,21 @@ +{{- $secret_name := "ironic-mariadb" -}} + +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secret_name }} + labels: + {{- include "mariadb.labels" . | nindent 4 }} +type: Opaque +data: + # Check if the secret is deployed and has a password + {{- $old_sec := lookup "v1" "Secret" .Release.Namespace $secret_name }} + {{- if and $old_sec (index $old_sec.data "password") }} + password: {{ index $old_sec.data "password" }} + {{- else if .Values.password }} + # If not, check if a password is provided in values.yaml + password: {{ .Values.password | toString | b64enc }} + {{- else }} + # If no secret and no password in values.yaml, generate a new password + password: {{ randAlphaNum 20 | b64enc }} + {{- end }} \ No newline at end of file diff --git a/charts/metal3/0.15.0/charts/mariadb/templates/service-account.yaml b/charts/metal3/0.15.0/charts/mariadb/templates/service-account.yaml new file mode 100644 index 00000000..16794876 --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/templates/service-account.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "mariadb.serviceAccountName" . }} + labels: + {{- include "mariadb.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} + diff --git a/charts/metal3/0.15.0/charts/mariadb/templates/service.yaml b/charts/metal3/0.15.0/charts/mariadb/templates/service.yaml new file mode 100644 index 00000000..471702b9 --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.global.databaseServiceName }} + labels: + {{- include "mariadb.labels" . | nindent 4 }} +spec: + ipFamilyPolicy: PreferDualStack + type: {{ .Values.service.type }} + selector: + {{- include "mariadb.selectorLabels" . | nindent 4 }} + ports: + {{- with .Values.service.ports }} + {{- toYaml . | nindent 2 }} + {{- end }} diff --git a/charts/metal3/0.15.0/charts/mariadb/values.yaml b/charts/metal3/0.15.0/charts/mariadb/values.yaml new file mode 100644 index 00000000..a1796e8f --- /dev/null +++ b/charts/metal3/0.15.0/charts/mariadb/values.yaml @@ -0,0 +1,68 @@ +global: + databaseServiceName: "metal3-mariadb" + nodeSelector: {} + +replicaCount: 1 + +service: + type: ClusterIP + ports: + - protocol: TCP + port: 3306 + targetPort: 3306 + +image: + repository: registry.suse.com/suse/mariadb + pullPolicy: IfNotPresent + tag: 11.8 + +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: + runAsUser: 60 + fsGroup: 60 + +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + +# Password for the mariadb ironic user +password: "" + +persistence: + # storageClass for the mariadb data volume + storageClass: "" + # size of the mariadb data volume + size: "1Gi" + # accessMode of the mariadb data volume PVC + # If empty defaults to ReadWriteOnce when replicaCount=1 otherwise ReadWriteMany + accessMode: "" + # flag to indicate to keep pvc upon helm uninstall + keep: false + +volumeMounts: + - name: mariadb-data-volume + mountPath: /var/lib/mysql + subPath: data + +volumes: + - name: mariadb-data-volume + persistentVolumeClaim: + claimName: mariadb-volume-claim diff --git a/charts/metal3/0.15.0/charts/media/.helmignore b/charts/metal3/0.15.0/charts/media/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/metal3/0.15.0/charts/media/Chart.yaml b/charts/metal3/0.15.0/charts/media/Chart.yaml new file mode 100644 index 00000000..fb4d3d7e --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 1.21.0 +description: A Helm chart for Media, used by Metal3 +name: media +type: application +version: 0.7.1 diff --git a/charts/metal3/0.15.0/charts/media/templates/NOTES.txt b/charts/metal3/0.15.0/charts/media/templates/NOTES.txt new file mode 100644 index 00000000..6823b8ca --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "media.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "media.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "media.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "media.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/charts/metal3/0.15.0/charts/media/templates/_helpers.tpl b/charts/metal3/0.15.0/charts/media/templates/_helpers.tpl new file mode 100644 index 00000000..ae2a31da --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "media.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "media.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "media.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "media.labels" -}} +helm.sh/chart: {{ include "media.chart" . }} +{{ include "media.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "media.selectorLabels" -}} +app.kubernetes.io/component: media +app.kubernetes.io/name: {{ include "media.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "media.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "media.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/metal3/0.15.0/charts/media/templates/deployment.yaml b/charts/metal3/0.15.0/charts/media/templates/deployment.yaml new file mode 100644 index 00000000..6605cbc3 --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/templates/deployment.yaml @@ -0,0 +1,62 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "media.fullname" . }} + labels: + {{- include "media.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "media.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + rollme: {{ randAlphaNum 5 | quote }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "media.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "media.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/metal3/0.15.0/charts/media/templates/hpa.yaml b/charts/metal3/0.15.0/charts/media/templates/hpa.yaml new file mode 100644 index 00000000..296a627b --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "media.fullname" . }} + labels: + {{- include "media.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "media.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/metal3/0.15.0/charts/media/templates/ingress.yaml b/charts/metal3/0.15.0/charts/media/templates/ingress.yaml new file mode 100644 index 00000000..bc816995 --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "media.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "media.labels" . | nindent 4 }} + {{- with $_ := merge .Values.ingress.annotations $.Values.global.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ tpl .host $ }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/metal3/0.15.0/charts/media/templates/persistentvolume.yaml b/charts/metal3/0.15.0/charts/media/templates/persistentvolume.yaml new file mode 100644 index 00000000..97e08f3f --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/templates/persistentvolume.yaml @@ -0,0 +1,18 @@ +{{- if eq .Values.mediaVolume.storageClassName "local" }} +--- +kind: PersistentVolume +apiVersion: v1 +metadata: + name: media + labels: + {{- include "media.labels" . | nindent 4 }} +spec: + storageClassName: {{ .Values.mediaVolume.storageClassName }} + accessModes: + {{ toYaml .Values.mediaVolume.accessModes }} + capacity: + storage: {{ .Values.mediaVolume.storage }} + hostPath: + path: {{ .Values.mediaVolume.hostPath }} + type: DirectoryOrCreate +{{- end }} diff --git a/charts/metal3/0.15.0/charts/media/templates/persistentvolumeclaim.yaml b/charts/metal3/0.15.0/charts/media/templates/persistentvolumeclaim.yaml new file mode 100644 index 00000000..d2c7e5d3 --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/templates/persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: media + labels: + {{- include "media.labels" . | nindent 4 }} +spec: + storageClassName: {{ .Values.mediaVolume.storageClassName }} + accessModes: + {{ toYaml .Values.mediaVolume.accessModes }} + resources: + requests: + storage: {{ .Values.mediaVolume.storage }} diff --git a/charts/metal3/0.15.0/charts/media/templates/service.yaml b/charts/metal3/0.15.0/charts/media/templates/service.yaml new file mode 100644 index 00000000..f8f524b5 --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "media.fullname" . }} + labels: + {{- include "media.labels" . | nindent 4 }} +spec: + ipFamilyPolicy: PreferDualStack + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "media.selectorLabels" . | nindent 4 }} diff --git a/charts/metal3/0.15.0/charts/media/templates/serviceaccount.yaml b/charts/metal3/0.15.0/charts/media/templates/serviceaccount.yaml new file mode 100644 index 00000000..513a44ab --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "media.serviceAccountName" . }} + labels: + {{- include "media.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/metal3/0.15.0/charts/media/templates/storageclass.yaml b/charts/metal3/0.15.0/charts/media/templates/storageclass.yaml new file mode 100644 index 00000000..001cdd9b --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/templates/storageclass.yaml @@ -0,0 +1,9 @@ +--- +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: {{ include "media.fullname" . }} + labels: + {{- include "media.labels" . | nindent 4 }} +provisioner: kubernetes.io/no-provisioner +volumeBindingMode: WaitForFirstConsumer diff --git a/charts/metal3/0.15.0/charts/media/values.yaml b/charts/metal3/0.15.0/charts/media/values.yaml new file mode 100644 index 00000000..843cbbd2 --- /dev/null +++ b/charts/metal3/0.15.0/charts/media/values.yaml @@ -0,0 +1,122 @@ +# Default values for media. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +global: + # Global ingress annotations that is shared by all the ingress services. + # For example, use it to override extern-dns records. + ingress: + annotations: {} + # The IP to register with external-dns for this service + #external-dns.alpha.kubernetes.io/target: 192.168.20.5 + + # If running in a multi-node kubernetes cluster, "pin" the media container + # to the given host where the /opt/media volume exists. Uncomment the + # nodeSelector and update the hostname accordingly. + #nodeSelector: + #kubernetes.io/hostname: "my-hostname" + + # Comment this out when pinning the media container to a specfic host. + nodeSelector: {} + +replicaCount: 1 + +image: + repository: registry.suse.com/suse/nginx + pullPolicy: IfNotPresent + tag: 1.21 + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: + runAsUser: 499 + fsGroup: 486 + +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: media.suse.baremetal + paths: + - path: / + pathType: Prefix + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +tolerations: [] + +affinity: {} + +# volumes +volumes: + - name: assets + persistentVolumeClaim: + claimName: media + - name: run + emptyDir: + sizeLimit: 10Mi + +# volume mounts +volumeMounts: + - mountPath: /srv/www/htdocs + name: assets + - mountPath: /run + name: run + +# media volume settings +mediaVolume: + storageClassName: local + accessModes: + - ReadOnlyMany + hostPath: /opt/media + storage: 5Gi diff --git a/charts/metal3/0.15.0/templates/NOTES.txt b/charts/metal3/0.15.0/templates/NOTES.txt new file mode 100644 index 00000000..ecac059d --- /dev/null +++ b/charts/metal3/0.15.0/templates/NOTES.txt @@ -0,0 +1,3 @@ +TBD: Document the deployed application/service endpoints + +You should now be ready to install and configure ClusterAPI. diff --git a/charts/metal3/0.15.0/templates/_helpers.tpl b/charts/metal3/0.15.0/templates/_helpers.tpl new file mode 100644 index 00000000..c1725ceb --- /dev/null +++ b/charts/metal3/0.15.0/templates/_helpers.tpl @@ -0,0 +1,77 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "metal3.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "metal3.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "metal3.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "metal3.labels" -}} +helm.sh/chart: {{ include "metal3.chart" . }} +{{ include "metal3.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "metal3.selectorLabels" -}} +app.kubernetes.io/name: {{ include "metal3.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "metal3.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "metal3.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Produce the correct IP or hostname for Ironic provisioning +*/}} +{{- define "metal3.hostIP" -}} +{{- with .Values.global }} +{{- if and .provisioningHostname (or .provisioningIP .ironicIP) }} +{{ fail "Please provide either provisioningHostname or provisioningIP or ironicIP" }} +{{- end }} +{{- if and .provisioningIP .ironicIP }} +{{ fail "Please provide either ironicIP or provisioningIP" }} +{{- end }} +{{- coalesce .provisioningIP .ironicIP }} +{{- end }} +{{- end }} diff --git a/charts/metal3/0.15.0/values.yaml b/charts/metal3/0.15.0/values.yaml new file mode 100644 index 00000000..a7b9adc3 --- /dev/null +++ b/charts/metal3/0.15.0/values.yaml @@ -0,0 +1,116 @@ +# The metal3 chart is a parent chart that installs +# all of the other charts that a metal3 deployment needs, +# but doesn't actually deploy any services itself. + +global: + # IP on which the Ironic services will be exposed + ironicIP: "" + + # whether to enable mariadb (default is sqlite) + enable_mariadb: false + + # whether to enable media server. + enable_metal3_media_server: false + + # whether to enable dnsmasq on the provisioning network (for PXE boot) + enable_dnsmasq: false + + # whether to enable PXE boot capability + # NOTE: enable_dnsmasq must set to 'true' in order for this option to be effective. + enable_pxe_boot: false + + # whether to enable tls + enable_tls: true + + # whether to enable the TLS of the Virtual Media. + enable_vmedia_tls: true + + # whether to enable basic auth + enable_basicAuth: true + + auth: + ironicUsername: "" + ironicPassword: "" + + # CA bundle to be trusted by Ironic and its python agent, should be the + # name of a deployed ConfigMap in the same namespace. If left empty the + # default public CA bundle will be used. + # The ConfigMap should be like this: + # data: + # ca-bundle.pem: + trustedCAs: "" + + # Will be used when tls is enabled + vmediaTLSPort: 6185 + + # IP address of the router associated with the specified DHCP + # address range + dnsmasqDefaultRouter: "" + + # IP address of the dns server to be provided with DHCP + # response + dnsmasqDNSServer: "" + + # specify comma-delimited range of IP addresses the DHCP server will manage. + # e.g 192.168.20.20,192.168.20.80 + dhcpRange: "" + + # Network interface on which provisioning network can be accessed + provisioningInterface: "" + + # IP Address assigned to network interface on provisioning network + provisioningIP: "" + + # Fully Qualified Domain Name used by Ironic for both binding (to the + # associated IPv4 and/or IPv6 addresses) and exposing the API, dnsmask and + # media, also used by BMO. Note, this is the only way to enable a fully + # working dual-stack configuration. + provisioningHostname: "" + + # Hostname or IP for accessing the Ironic API server from a non-provisioning network + externalHttpHost: "" + + # Name for the MariaDB service + databaseServiceName: metal3-mariadb + + # In a multi-node cluster use the node selector to ensure the pods + # all run on the same host where the dnsmasqDNSServer and provisioningIP + # and /opt/media exist. Uncomment the nodeSelector and update the + # hostname accordingly. + #nodeSelector: + #kubernetes.io/hostname: "csrancher-n1" + +# +# media service +# + +# Override any settings for the metal3 media service here +metal3-media: + # location where media files should be placed so that they are + # available to the Ironic deployment services. + mediaVolume: + hostPath: /opt/media + +# +# ironic service +# + +# Override any settings for the metal3 ironic service here +# Ensure the storageClass is defined +metal3-ironic: + service: + type: LoadBalancer + persistence: + ironic: + # storageClass for the ironic shared volume + storageClass: "" + +# +# Database Service +# + +# Override any settings for the metal3 mariadb service here +metal3-mariadb: + # storageClass for the mysql datastore + persistence: + storageClass: "" diff --git a/index.html b/index.html index 9c02cb3b..5d55899e 100755 --- a/index.html +++ b/index.html @@ -267,14 +267,14 @@

Charts

- +

metal3 - (0.13.1@0.13.1) + (0.15.0@0.15.0) github link diff --git a/index.yaml b/index.yaml index ebf136e9..c100d073 100755 --- a/index.yaml +++ b/index.yaml @@ -665,6 +665,36 @@ entries: - assets/kubevirt-dashboard-extension/kubevirt-dashboard-extension-0.1.0.tgz version: 0.1.0 metal3: + - apiVersion: v2 + appVersion: 0.15.0 + created: "2026-05-18T16:45:54.333759407+02:00" + dependencies: + - alias: metal3-baremetal-operator + name: baremetal-operator + repository: file://./charts/baremetal-operator + version: 0.12.3 + - alias: metal3-ironic + name: ironic + repository: file://./charts/ironic + version: 0.13.0 + - alias: metal3-mariadb + condition: global.enable_mariadb + name: mariadb + repository: file://./charts/mariadb + version: 0.6.3 + - alias: metal3-media + condition: global.enable_metal3_media_server + name: media + repository: file://./charts/media + version: 0.7.1 + description: A Helm chart that installs all of the dependencies needed for Metal3 + digest: e842fd3331e4d35d269672b1e9637ea58ea164ba8214350acd70de00540c5a94 + icon: https://github.com/cncf/artwork/raw/master/projects/metal3/icon/color/metal3-icon-color.svg + name: metal3 + type: application + urls: + - assets/metal3/metal3-0.15.0.tgz + version: 0.15.0 - apiVersion: v2 appVersion: 0.13.1 created: "2026-02-06T16:16:01.651553274+01:00" From e8792554b2f0dd8e450aa3bc98ef918b6b1bbe89 Mon Sep 17 00:00:00 2001 From: Nicolas Belouin Date: Fri, 22 May 2026 14:55:08 +0200 Subject: [PATCH 3/3] Increase workflow timeout Signed-off-by: Nicolas Belouin --- .github/workflows/test-metal3-helm-chart.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-metal3-helm-chart.yml b/.github/workflows/test-metal3-helm-chart.yml index 1b21008b..5478a53c 100644 --- a/.github/workflows/test-metal3-helm-chart.yml +++ b/.github/workflows/test-metal3-helm-chart.yml @@ -81,8 +81,8 @@ jobs: run: | export KUBECONFIG=/etc/rancher/k3s/k3s.yaml - # Set a timeout of 5 minutes - timeout=$((SECONDS + 300)) + # Set a timeout of 10 minutes + timeout=$((SECONDS + 600)) while [ $SECONDS -lt $timeout ]; do # Run the kubectl command to get pod information