From deaac1e16d407dd74aaf0e8554e414221e933826 Mon Sep 17 00:00:00 2001 From: Ivo Petrov Date: Tue, 19 Dec 2023 17:03:50 +0200 Subject: [PATCH] Fix security context issue for Metal3 in upstream Sylva (#68) * Move 0.2.0 to 0.2.1 * Use non-root security context for ironic, bmo and mariadb * make charts --- assets/metal3/metal3-0.2.1.tgz | Bin 0 -> 34686 bytes charts/metal3/0.2.1/.helmignore | 23 + charts/metal3/0.2.1/Chart.yaml | 25 + charts/metal3/0.2.1/README.md | 101 ++ charts/metal3/0.2.1/app-readme.md | 1 + .../charts/baremetal-operator/.helmignore | 23 + .../charts/baremetal-operator/Chart.yaml | 6 + .../crds/customresource-baremetalhosts.yaml | 1132 +++++++++++++++++ .../customresource-bmceventsubscriptions.yaml | 85 ++ .../crds/customresource-firmwareschemas.yaml | 90 ++ .../crds/customresource-hardwaredata.yaml | 203 +++ .../customresource-hostfirmwaresettings.yaml | 164 +++ .../customresource-preprovisioningimages.yaml | 183 +++ .../baremetal-operator/templates/NOTES.txt | 22 + .../baremetal-operator/templates/_helpers.tpl | 62 + .../templates/certificate.yaml | 14 + .../templates/clusterrole-manager.yaml | 146 +++ .../templates/clusterrole-metrics-reader.yaml | 11 + .../templates/clusterrole-proxy.yaml | 19 + .../templates/clusterrolebinding-manager.yaml | 14 + .../templates/clusterrolebinding-proxy.yaml | 14 + .../templates/configmap-ironic.yaml | 24 + .../templates/configmap.yaml | 19 + .../templates/deployment.yaml | 92 ++ .../baremetal-operator/templates/issuer.yaml | 8 + .../baremetal-operator/templates/role.yaml | 45 + .../templates/rolebinding.yaml | 13 + .../templates/service-controller-manager.yaml | 14 + .../templates/service-webhook.yaml | 13 + .../templates/serviceaccount.yaml | 12 + .../templates/tests/test-connection.yaml | 15 + .../validatingwebhookconfiguration.yaml | 51 + .../charts/baremetal-operator/values.yaml | 101 ++ charts/metal3/0.2.1/charts/ironic/.helmignore | 23 + charts/metal3/0.2.1/charts/ironic/Chart.yaml | 6 + charts/metal3/0.2.1/charts/ironic/README.md | 52 + .../0.2.1/charts/ironic/templates/NOTES.txt | 22 + .../charts/ironic/templates/_helpers.tpl | 249 ++++ .../ironic/templates/certificate-ca.yaml | 31 + .../templates/certificate-letsencrtpt.yaml | 20 + .../ironic/templates/configmap-certs.yaml | 22 + .../templates/configmap-ipa-downloader.yaml | 12 + .../charts/ironic/templates/configmap.yaml | 70 + .../charts/ironic/templates/deployment.yaml | 294 +++++ .../charts/ironic/templates/ingress.yaml | 81 ++ .../charts/ironic/templates/issuer-ca.yaml | 13 + .../ironic/templates/issuer-letsEncrypt.yaml | 33 + .../ironic/templates/issuer-self-signed.yaml | 12 + .../0.2.1/charts/ironic/templates/pvc.yaml | 26 + .../ironic/templates/secret-cloudfare.yaml | 13 + .../charts/ironic/templates/secret-tls.yaml | 15 + .../charts/ironic/templates/service.yaml | 24 + .../ironic/templates/serviceaccount.yaml | 12 + charts/metal3/0.2.1/charts/ironic/values.yaml | 204 +++ .../metal3/0.2.1/charts/mariadb/.helmignore | 24 + charts/metal3/0.2.1/charts/mariadb/Chart.yaml | 6 + .../charts/mariadb/templates/_helpers.tpl | 63 + .../charts/mariadb/templates/configmap.yaml | 8 + .../charts/mariadb/templates/deployment.yaml | 78 ++ .../0.2.1/charts/mariadb/templates/pvc.yaml | 24 + .../charts/mariadb/templates/secret.yaml | 21 + .../mariadb/templates/service-account.yaml | 13 + .../charts/mariadb/templates/service.yaml | 14 + .../metal3/0.2.1/charts/mariadb/values.yaml | 67 + charts/metal3/0.2.1/charts/media/.helmignore | 23 + charts/metal3/0.2.1/charts/media/Chart.yaml | 6 + .../0.2.1/charts/media/templates/NOTES.txt | 22 + .../0.2.1/charts/media/templates/_helpers.tpl | 62 + .../charts/media/templates/deployment.yaml | 62 + .../0.2.1/charts/media/templates/hpa.yaml | 28 + .../0.2.1/charts/media/templates/ingress.yaml | 61 + .../media/templates/persistentvolume.yaml | 16 + .../templates/persistentvolumeclaim.yaml | 14 + .../0.2.1/charts/media/templates/service.yaml | 15 + .../media/templates/serviceaccount.yaml | 12 + .../charts/media/templates/storageclass.yaml | 9 + .../templates/tests/test-connection.yaml | 15 + charts/metal3/0.2.1/charts/media/values.yaml | 112 ++ charts/metal3/0.2.1/templates/NOTES.txt | 3 + charts/metal3/0.2.1/templates/_helpers.tpl | 62 + charts/metal3/0.2.1/values.yaml | 99 ++ index.yaml | 29 + 82 files changed, 4947 insertions(+) create mode 100644 assets/metal3/metal3-0.2.1.tgz create mode 100644 charts/metal3/0.2.1/.helmignore create mode 100644 charts/metal3/0.2.1/Chart.yaml create mode 100644 charts/metal3/0.2.1/README.md create mode 100644 charts/metal3/0.2.1/app-readme.md create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/.helmignore create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/Chart.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-hardwaredata.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/NOTES.txt create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/_helpers.tpl create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/certificate.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrole-manager.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrole-metrics-reader.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrole-proxy.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrolebinding-manager.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrolebinding-proxy.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/configmap-ironic.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/configmap.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/deployment.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/issuer.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/role.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/rolebinding.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/service-controller-manager.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/service-webhook.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/serviceaccount.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/tests/test-connection.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/templates/validatingwebhookconfiguration.yaml create mode 100644 charts/metal3/0.2.1/charts/baremetal-operator/values.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/.helmignore create mode 100644 charts/metal3/0.2.1/charts/ironic/Chart.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/README.md create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/NOTES.txt create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/_helpers.tpl create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/certificate-ca.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/certificate-letsencrtpt.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/configmap-certs.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/configmap-ipa-downloader.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/configmap.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/deployment.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/ingress.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/issuer-ca.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/issuer-letsEncrypt.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/issuer-self-signed.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/pvc.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/secret-cloudfare.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/secret-tls.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/service.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/templates/serviceaccount.yaml create mode 100644 charts/metal3/0.2.1/charts/ironic/values.yaml create mode 100644 charts/metal3/0.2.1/charts/mariadb/.helmignore create mode 100644 charts/metal3/0.2.1/charts/mariadb/Chart.yaml create mode 100644 charts/metal3/0.2.1/charts/mariadb/templates/_helpers.tpl create mode 100644 charts/metal3/0.2.1/charts/mariadb/templates/configmap.yaml create mode 100644 charts/metal3/0.2.1/charts/mariadb/templates/deployment.yaml create mode 100644 charts/metal3/0.2.1/charts/mariadb/templates/pvc.yaml create mode 100644 charts/metal3/0.2.1/charts/mariadb/templates/secret.yaml create mode 100644 charts/metal3/0.2.1/charts/mariadb/templates/service-account.yaml create mode 100644 charts/metal3/0.2.1/charts/mariadb/templates/service.yaml create mode 100644 charts/metal3/0.2.1/charts/mariadb/values.yaml create mode 100644 charts/metal3/0.2.1/charts/media/.helmignore create mode 100644 charts/metal3/0.2.1/charts/media/Chart.yaml create mode 100644 charts/metal3/0.2.1/charts/media/templates/NOTES.txt create mode 100644 charts/metal3/0.2.1/charts/media/templates/_helpers.tpl create mode 100644 charts/metal3/0.2.1/charts/media/templates/deployment.yaml create mode 100644 charts/metal3/0.2.1/charts/media/templates/hpa.yaml create mode 100644 charts/metal3/0.2.1/charts/media/templates/ingress.yaml create mode 100644 charts/metal3/0.2.1/charts/media/templates/persistentvolume.yaml create mode 100644 charts/metal3/0.2.1/charts/media/templates/persistentvolumeclaim.yaml create mode 100644 charts/metal3/0.2.1/charts/media/templates/service.yaml create mode 100644 charts/metal3/0.2.1/charts/media/templates/serviceaccount.yaml create mode 100644 charts/metal3/0.2.1/charts/media/templates/storageclass.yaml create mode 100644 charts/metal3/0.2.1/charts/media/templates/tests/test-connection.yaml create mode 100644 charts/metal3/0.2.1/charts/media/values.yaml create mode 100644 charts/metal3/0.2.1/templates/NOTES.txt create mode 100644 charts/metal3/0.2.1/templates/_helpers.tpl create mode 100644 charts/metal3/0.2.1/values.yaml diff --git a/assets/metal3/metal3-0.2.1.tgz b/assets/metal3/metal3-0.2.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3451095384f0f6c928fea57183b2016efff7c2d8 GIT binary patch literal 34686 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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.2.1/app-readme.md b/charts/metal3/0.2.1/app-readme.md new file mode 100644 index 00000000..ffa1c862 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/baremetal-operator/.helmignore b/charts/metal3/0.2.1/charts/baremetal-operator/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/baremetal-operator/Chart.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/Chart.yaml new file mode 100644 index 00000000..566b5c6c --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 1.16.0 +description: A Helm chart for baremetal-operator, used by Metal3 +name: baremetal-operator +type: application +version: 0.2.1 diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml new file mode 100644 index 00000000..c70e82a3 --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml @@ -0,0 +1,1132 @@ +--- +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.12.1 + 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: The type of hardware detected + jsonPath: .status.hardwareProfile + name: Hardware_Profile + 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 avoided + during provisioning and deprovisioning. + enum: + - metadata + - disabled + type: string + bmc: + description: How do we connect to the BMC? + properties: + address: + description: Address holds the URL for accessing the controller + on the network. + 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: Which MAC address will PXE boot? This is optional for + some types, but required for libvirt VMs driven by vbmc. + 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. + 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". + 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. TODO: this design is not final and this field is + subject to change in the future.' + 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. + 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 + externallyProvisioned: + description: ExternallyProvisioned means something else is managing + the image running on the host and the operator should only manage + the power status and hardware inventory inspection. If the Image + field is filled in, this field is ignored. + type: boolean + firmware: + description: BIOS configuration for bare metal server + properties: + simultaneousMultithreadingEnabled: + description: 'Allows a single physical processor core to appear + as several logical processors. This supports following options: + true, false.' + 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. + This supports following options: true, false.' + enum: + - true + - false + type: boolean + virtualizationEnabled: + description: 'Supports the virtualization of platform hardware. + This supports following options: true, false.' + enum: + - true + - false + type: boolean + type: object + hardwareProfile: + description: What is the name of the hardware profile for this host? + It should only be necessary to set this when inspection cannot automatically + determine the profile. + type: string + image: + description: Image holds the details of the image to be provisioned. + properties: + checksum: + description: Checksum is the checksum for the image. + type: string + checksumType: + description: ChecksumType is the checksum algorithm for the image. + e.g md5, sha256, sha512 + enum: + - md5 + - sha256 + - sha512 + type: string + format: + description: DiskFormat contains the format of the image (raw, + qcow2, ...). Needs to be set to raw for raw images streaming. + Note live-iso means an iso referenced by the url will be live-booted + and not deployed to disk, and in this case the checksum options + are not required and if specified will be ignored. + 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 + metaData: + description: MetaData holds the reference to the Secret containing + host metadata (e.g. meta_data.json) which is passed to the Config + Drive. + 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 (e.g content of network_data.json) which is + passed to the Config Drive. + 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 server be online? + type: boolean + preprovisioningNetworkDataName: + description: PreprovisioningNetworkDataName is the name of the Secret + in the local namespace containing network configuration (e.g content + of network_data.json) 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 + 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.' + 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, volume 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 or solid-state + storage + type: boolean + sizeGibibytes: + description: Size (Integer) 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 node 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;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 (Integer) 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. + 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. It is only written for NoExecute taints. + 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 to be passed to the host before it boots. + 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: + 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 + 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. + properties: + cpu: + description: CPU describes one processor on the host. + 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: Firmware describes the firmware on the host. + 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: + type: string + nics: + 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 + 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 + 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: + type: integer + storage: + items: + description: Storage describes one storage device (disk, SSD, + etc.) on the host. + properties: + hctl: + description: The SCSI location of the device + type: string + model: + description: Hardware model + type: string + name: + description: The Linux device name of the disk, e.g. "/dev/sda". + Note that this may not be stable across reboots. + 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: HardwareSystemVendor stores details about the whole + hardware system. + 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. + 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 + type: string + poweredOn: + description: indicator for whether or not the host is powered on + type: boolean + provisioning: + description: Information tracked by the provisioner. + properties: + ID: + description: The machine's UUID from the underlying provisioning + tool + type: string + bootMode: + description: BootMode indicates the boot mode used to provision + the node + 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 Bios set by the user + properties: + simultaneousMultithreadingEnabled: + description: 'Allows a single physical processor core to appear + as several logical processors. This supports following options: + true, false.' + 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. This supports following options: true, false.' + enum: + - true + - false + type: boolean + virtualizationEnabled: + description: 'Supports the virtualization of platform hardware. + This supports following options: true, false.' + 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. + type: string + checksumType: + description: ChecksumType is the checksum algorithm for the + image. e.g md5, sha256, sha512 + enum: + - md5 + - sha256 + - sha512 + type: string + format: + description: DiskFormat contains the format of the image (raw, + qcow2, ...). Needs to be set to raw for raw images streaming. + Note live-iso means an iso referenced by the url will be + live-booted and not deployed to disk, and in this case the + checksum options are not required and if specified will + be ignored. + 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 set by the user + 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.' + 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, volume 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 or solid-state + storage + type: boolean + sizeGibibytes: + description: Size (Integer) 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 node 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;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 (Integer) 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 RootDevicehints set by the user + 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 indiciator 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 + - hardwareProfile + - operationalStatus + - poweredOn + - provisioning + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml new file mode 100644 index 00000000..9aed81fa --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml @@ -0,0 +1,85 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + 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.2.1/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml new file mode 100644 index 00000000..30da8204 --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml @@ -0,0 +1,90 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + 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.2.1/charts/baremetal-operator/crds/customresource-hardwaredata.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-hardwaredata.yaml new file mode 100644 index 00000000..5887da88 --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-hardwaredata.yaml @@ -0,0 +1,203 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + 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: CPU describes one processor on the host. + 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: Firmware describes the firmware on the host. + 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: + type: string + nics: + 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 + 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 + 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: + type: integer + storage: + items: + description: Storage describes one storage device (disk, SSD, + etc.) on the host. + properties: + hctl: + description: The SCSI location of the device + type: string + model: + description: Hardware model + type: string + name: + description: The Linux device name of the disk, e.g. "/dev/sda". + Note that this may not be stable across reboots. + 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: HardwareSystemVendor stores details about the whole + hardware system. + 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.2.1/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml new file mode 100644 index 00000000..68cd974a --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml @@ -0,0 +1,164 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + 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. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + 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. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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.2.1/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml new file mode 100644 index 00000000..e722883c --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml @@ -0,0 +1,183 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + 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. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + 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. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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.2.1/charts/baremetal-operator/templates/NOTES.txt b/charts/metal3/0.2.1/charts/baremetal-operator/templates/NOTES.txt new file mode 100644 index 00000000..f08da916 --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/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 "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.2.1/charts/baremetal-operator/templates/_helpers.tpl b/charts/metal3/0.2.1/charts/baremetal-operator/templates/_helpers.tpl new file mode 100644 index 00000000..a0c581c1 --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +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/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 }} diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/templates/certificate.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/certificate.yaml new file mode 100644 index 00000000..2d424b75 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/baremetal-operator/templates/clusterrole-manager.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrole-manager.yaml new file mode 100644 index 00000000..79ab1b4e --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrole-manager.yaml @@ -0,0 +1,146 @@ +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 diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrole-metrics-reader.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrole-metrics-reader.yaml new file mode 100644 index 00000000..1bcde61d --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrole-metrics-reader.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.2.1/charts/baremetal-operator/templates/clusterrole-proxy.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrole-proxy.yaml new file mode 100644 index 00000000..96d62086 --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrole-proxy.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "baremetal-operator.fullname" . }}-proxy-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.2.1/charts/baremetal-operator/templates/clusterrolebinding-manager.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrolebinding-manager.yaml new file mode 100644 index 00000000..b02f6ba6 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/baremetal-operator/templates/clusterrolebinding-proxy.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrolebinding-proxy.yaml new file mode 100644 index 00000000..4745ace8 --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/clusterrolebinding-proxy.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "baremetal-operator.fullname" . }}-proxy-rolebinding + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "baremetal-operator.fullname" . }}-proxy-role +subjects: +- kind: ServiceAccount + name: {{ include "baremetal-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/templates/configmap-ironic.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/configmap-ironic.yaml new file mode 100644 index 00000000..c51295fe --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/configmap-ironic.yaml @@ -0,0 +1,24 @@ +{{- $ironicApiHost := .Values.global.ironicApiHost }} +{{- $ironicBootHost := .Values.global.ironicBootHost }} +{{- $ironicInspectorHost := .Values.global.ironicInspectorHost }} +{{- $ironicCacheHost := .Values.global.ironicCacheHost }} + +{{- if .Values.global.ironicIP }} +{{- $ironicApiHost = print .Values.global.ironicIP ":6385" }} +{{- $ironicBootHost = print .Values.global.ironicIP ":6180" }} +{{- $ironicInspectorHost = print .Values.global.ironicIP ":5050" }} +{{- $ironicCacheHost = print .Values.global.ironicIP ":6180" }} +{{- end }} +apiVersion: v1 +data: + CACHEURL: "http://{{ $ironicCacheHost }}/images" + DEPLOY_KERNEL_URL: "http://{{ $ironicBootHost }}/images/ironic-python-agent.kernel" + DEPLOY_RAMDISK_URL: "http://{{ $ironicBootHost }}/images/ironic-python-agent.initramfs" + IRONIC_ENDPOINT: "http://{{ $ironicApiHost }}/v1/" + IRONIC_INSPECTOR_ENDPOINT: "http://{{ $ironicInspectorHost }}/v1/" + RESTART_CONTAINER_CERTIFICATE_UPDATED: "false" +kind: ConfigMap +metadata: + name: baremetal-operator-ironic + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/templates/configmap.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/configmap.yaml new file mode 100644 index 00000000..db575684 --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/configmap.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +data: + controller_manager_config.yaml: | + apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 + kind: ControllerManagerConfig + health: + healthProbeBindAddress: :9440 + metrics: + bindAddress: 127.0.0.1:8085 + webhook: + port: 9443 + leaderElection: + leaderElect: true + resourceName: a9498140.metal3.io +kind: ConfigMap +metadata: + name: baremetal-operator-manager-config + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/templates/deployment.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/deployment.yaml new file mode 100644 index 00000000..4f19cf32 --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/deployment.yaml @@ -0,0 +1,92 @@ +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: + control-plane: controller-manager + template: + metadata: + labels: + control-plane: controller-manager + webhook: metal3-io-v1alpha1-baremetalhost + spec: + containers: + - args: + - --metrics-addr=127.0.0.1:8085 + - --enable-leader-election + 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.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.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 + 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 + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8085/ + - --logtostderr=true + - --v=10 + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + serviceAccountName: {{ include "baremetal-operator.serviceAccountName" . }} + terminationGracePeriodSeconds: 10 + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: bmo-webhook-server-cert + {{- with .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/templates/issuer.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/issuer.yaml new file mode 100644 index 00000000..9b12180f --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/baremetal-operator/templates/role.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/role.yaml new file mode 100644 index 00000000..313066a4 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/baremetal-operator/templates/rolebinding.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/rolebinding.yaml new file mode 100644 index 00000000..4492103e --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/baremetal-operator/templates/service-controller-manager.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/service-controller-manager.yaml new file mode 100644 index 00000000..1578efaa --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/service-controller-manager.yaml @@ -0,0 +1,14 @@ +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: + ports: + - name: https + port: 8443 + targetPort: https + selector: + control-plane: controller-manager diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/templates/service-webhook.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/service-webhook.yaml new file mode 100644 index 00000000..7c947f9d --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/service-webhook.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} + name: {{ include "baremetal-operator.fullname" . }}-webhook-service +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + control-plane: controller-manager + webhook: metal3-io-v1alpha1-baremetalhost diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/templates/serviceaccount.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/serviceaccount.yaml new file mode 100644 index 00000000..4eab8805 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/baremetal-operator/templates/tests/test-connection.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/tests/test-connection.yaml new file mode 100644 index 00000000..7c003b50 --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "baremetal-operator.fullname" . }}-test-connection" + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "baremetal-operator.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/charts/metal3/0.2.1/charts/baremetal-operator/templates/validatingwebhookconfiguration.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/templates/validatingwebhookconfiguration.yaml new file mode 100644 index 00000000..55746b9e --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/baremetal-operator/values.yaml b/charts/metal3/0.2.1/charts/baremetal-operator/values.yaml new file mode 100644 index 00000000..d386130d --- /dev/null +++ b/charts/metal3/0.2.1/charts/baremetal-operator/values.yaml @@ -0,0 +1,101 @@ +# 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 + +image: + repository: registry.opensuse.org/isv/metal3/bci/baremetal-operator/containerfile/suse/baremetal-operator + pullPolicy: IfNotPresent + tag: "0.4.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 + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: baremetal-operator.suse.baremetal + paths: + - path: / + pathType: ImplementationSpecific + 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: {} + +baremetaloperator: + httpPort: "6180" diff --git a/charts/metal3/0.2.1/charts/ironic/.helmignore b/charts/metal3/0.2.1/charts/ironic/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/ironic/Chart.yaml b/charts/metal3/0.2.1/charts/ironic/Chart.yaml new file mode 100644 index 00000000..af648663 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 1.16.0 +description: A Helm chart for Ironic, used by Metal3 +name: ironic +type: application +version: 0.2.1 diff --git a/charts/metal3/0.2.1/charts/ironic/README.md b/charts/metal3/0.2.1/charts/ironic/README.md new file mode 100644 index 00000000..baea5948 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/README.md @@ -0,0 +1,52 @@ +## How to Enable TLS + +Currently TLS is implemented only for ironic helm chart. + +In order to enable TLS, common options to be maintained in values.yaml or the override files + +``` +global.enable_tls: true +global.enable_ironic: true +ingress.tlsSource: self ( Valid Options: "self, letsEncrypt, secrets") +tls: ingress (Where to offload the TLS/SSL encryption – Valid Options: "ingress, ironic" +``` + +Additional options if + +- tlsSource letsEncrypt + +### Pre-requistes + +- tlsSource secrets + +Ironic helm-chart values.yaml or overrides file +``` +tls.cacert: +tls.key: +tls.crt: +``` + +## 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.2.1/charts/ironic/templates/NOTES.txt b/charts/metal3/0.2.1/charts/ironic/templates/NOTES.txt new file mode 100644 index 00000000..56372dee --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/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 }}://{{ tpl $host.host $ }}{{ .path }} + {{- end }} +{{- end }} +{{- else 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/charts/metal3/0.2.1/charts/ironic/templates/_helpers.tpl b/charts/metal3/0.2.1/charts/ironic/templates/_helpers.tpl new file mode 100644 index 00000000..e666acbc --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/_helpers.tpl @@ -0,0 +1,249 @@ +{{/* +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/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 certificate volumeMounts +*/}} +{{- define "ironic.certVolumeMounts" -}} +- mountPath: /certs/ironic/tls.crt + name: ironic-certs + subPath: tls.crt +- mountPath: /certs/ironic/tls.key + name: ironic-certs + subPath: tls.key +- mountPath: /certs/ironic-inspector/tls.crt + name: ironic-insp-certs + subPath: tls.crt +- mountPath: /certs/ironic-inspector/tls.key + name: ironic-insp-certs + subPath: tls.key +- mountPath: /certs/ca/ironic/tls.crt + name: ironic-cacerts + subPath: tls.crt +- mountPath: /certs/ca/ironic-inspector/tls.crt + name: ironic-insp-cacerts + subPath: tls.crt +{{- end }} + + +{{/* +Get secret volumeMounts +*/}} +{{- define "ironic.secretVolMounts" -}} +- name: ironic-certs + mountPath: "/certs/ironic" + readOnly: true +- name: ironic-insp-certs + mountPath: "/certs/ironic-inspector" + readOnly: true +- name: vmedia-certs + mountPath: "/certs/vmedia" + readOnly: true +- name: vmedia-ca-certs + mountPath: "/certs/ca/vmedia" + readOnly: true +{{- end }} + +{{/* +Get cacert volumeMounts +*/}} +{{- define "ironic.cacertVolumeMounts" -}} +- mountPath: /etc/pki/trust/anchors/ca.crt + name: ironic-trustca + subPath: tls.cacert +- mountPath: /shared/html/tstcerts/ca.crt + name: ironicipa-trustca + subPath: tls.cacert +{{- end }} + +{{/* +Get trust cert volumeMounts +*/}} +{{- define "ironic.trustVolMounts" -}} +- name: ironic-trustcerts + mountPath: "/etc/pki/trust/anchors" + readOnly: true +- name: ironicipa-trustcerts + mountPath: "/shared/html/tstcerts" + readOnly: true +{{- end }} + +{{/* +Get letsEncrypt volumeMounts +*/}} +{{- define "ironic.letsEncryptVolMounts" -}} +- mountPath: /etc/pki/trust/anchors/ca.crt + name: ironic-le-trustca + subPath: tls.lecacert +- mountPath: /shared/html/tstcerts/ca.crt + name: ironicipa-le-trustca + subPath: tls.lecacert +{{- end }} + + +{{/* +Get ironic volumes +*/}} +{{- define "ironic.volumes" -}} +{{- if .Values.global.enable_ironic }} +- name: ironic-data-volume + persistentVolumeClaim: + claimName: ironic-shared-volume +{{- end }} +{{- if .Values.global.enable_ironic }} +{{- if .Values.global.enable_tls }} +{{- if eq .Values.ingress.tlsSource "secrets" }} +- name: ironic-trustca + configMap: + defaultMode: 493 + name: ironic-certs +- name: ironicipa-trustca + configMap: + defaultMode: 493 + name: ironic-certs +{{- end }} +{{- if (eq .Values.ingress.tlsSource "self") }} +- name: ironic-trustcerts + secret: + secretName: ironic-cacert +- name: ironicipa-trustcerts + secret: + secretName: ironic-cacert +{{- end }} +{{- if (eq .Values.ingress.tlsSource "letsEncrypt") }} +- name: ironic-le-trustca + configMap: + defaultMode: 493 + name: ironic-certs +- name: ironicipa-le-trustca + configMap: + defaultMode: 493 + name: ironic-certs +{{- end }} +{{- end }} +{{- if and ($.Values.global.enable_tls) (eq .Values.ingress.tlsSource "secrets") (eq .Values.tls "ironic") }} +- name: ironic-certs + configMap: + defaultMode: 493 + name: ironic-certs +- name: ironic-insp-certs + configMap: + defaultMode: 493 + name: ironic-certs +- name: ironic-cacerts + configMap: + defaultMode: 493 + name: ironic-certs +- name: ironic-insp-cacerts + configMap: + defaultMode: 493 + name: ironic-certs +{{- end }} +{{- if and ($.Values.global.enable_tls) (or (eq .Values.ingress.tlsSource "self") (eq .Values.ingress.tlsSource "letsEncrypt")) (eq .Values.tls "ironic") }} +- name: ironic-certs + secret: + secretName: ironic-cacert +- name: ironic-insp-certs + secret: + secretName: ironic-cacert +- name: vmedia-certs + secret: + secretName: ironic-cacert +- name: vmedia-ca-certs + secret: + secretName: ironic-cacert +{{- end }} +{{- end }} +{{- end }} + +{{/* +Get ironic tls volumeMounts +*/}} +{{- define "ironic.tlsVolumeMounts" -}} +{{- if (eq .Values.ingress.tlsSource "secrets") }} + {{- include "ironic.cacertVolumeMounts" . }} +{{- end }} +{{- if (eq .Values.ingress.tlsSource "self") }} + {{- include "ironic.trustVolMounts" . }} +{{- end }} +{{- if (eq .Values.ingress.tlsSource "letsEncrypt") }} + {{- include "ironic.letsEncryptVolMounts" . }} +{{- end }} +{{- end }} +{{- if and ($.Values.global.enable_tls) (eq .Values.tls "ironic") }} +{{- if (eq .Values.ingress.tlsSource "secrets") }} + {{- include "ironic.certVolumeMounts" . }} +{{- end }} +{{- if or (eq .Values.ingress.tlsSource "self") (eq .Values.ingress.tlsSource "letsEncrypt") }} + {{- include "ironic.secretVolMounts" . }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/metal3/0.2.1/charts/ironic/templates/certificate-ca.yaml b/charts/metal3/0.2.1/charts/ironic/templates/certificate-ca.yaml new file mode 100644 index 00000000..3821ec87 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/certificate-ca.yaml @@ -0,0 +1,31 @@ +{{- if and (.Values.ingress.enabled) (.Values.global.enable_ironic) -}} + {{- if and ($.Values.global.enable_tls) (eq .Values.ingress.tlsSource "self") -}} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "ironic.fullname" . }}-tls-ca + labels: + {{- include "ironic.labels" . | nindent 4 }} +spec: + secretName: ironic-cacert + isCA: true + commonName: {{ include "ironic.fullname" . }} + duration: 2160h # 90d + renewBefore: 360h + subject: + organizations: + - Suse + countries: + - US + organizationalUnits: + - DEV + issuerRef: + name: {{ include "ironic.fullname" . }} + kind: ClusterIssuer + dnsNames: + - api.ironic.{{ .Values.global.dnsDomain }} + - cache.ironic.{{ .Values.global.dnsDomain }} + - boot.ironic.{{ .Values.global.dnsDomain }} + - inspector.ironic.{{ .Values.global.dnsDomain }} + {{- end -}} +{{- end -}} diff --git a/charts/metal3/0.2.1/charts/ironic/templates/certificate-letsencrtpt.yaml b/charts/metal3/0.2.1/charts/ironic/templates/certificate-letsencrtpt.yaml new file mode 100644 index 00000000..ec0e1c9d --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/certificate-letsencrtpt.yaml @@ -0,0 +1,20 @@ +{{- if and (.Values.ingress.enabled) (.Values.global.enable_ironic) -}} + {{- if and ($.Values.global.enable_tls) (eq .Values.ingress.tlsSource "letsEncrypt") -}} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "ironic.fullname" . }}-tls-ca + labels: + {{- include "ironic.labels" . | nindent 4 }} +spec: + secretName: ironic-cacert + issuerRef: + name: {{ include "ironic.fullname" . }} + kind: Issuer + dnsNames: + - api.ironic.{{ .Values.global.dnsDomain }} + - inspector.ironic.{{ .Values.global.dnsDomain }} + - boot.ironic.{{ .Values.global.dnsDomain }} + - cache.ironic.{{ .Values.global.dnsDomain }} + {{- end -}} +{{- end -}} diff --git a/charts/metal3/0.2.1/charts/ironic/templates/configmap-certs.yaml b/charts/metal3/0.2.1/charts/ironic/templates/configmap-certs.yaml new file mode 100644 index 00000000..2e662856 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/configmap-certs.yaml @@ -0,0 +1,22 @@ +{{- if and (or (eq .Values.ingress.tlsSource "letsEncrypt") (eq .Values.ingress.tlsSource "secrets")) (.Values.global.enable_ironic) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: ironic-certs + labels: + {{- include "ironic.labels" . | nindent 4 }} +data: + {{- if .Values.tlscerts.key }} + tls.key: {{ .Values.tlscerts.key | quote }} + {{- end }} + {{- if .Values.tlscerts.crt }} + tls.crt: {{ .Values.tlscerts.crt | quote}} + {{- end }} + {{- if .Values.tlscerts.cacert }} + tls.cacert: {{ .Values.tlscerts.cacert | quote}} + {{- end }} + {{- if .Values.tlscerts.lecacert }} + tls.lecacert: {{ .Values.tlscerts.lecacert | quote}} + {{- end }} +{{- end -}} + diff --git a/charts/metal3/0.2.1/charts/ironic/templates/configmap-ipa-downloader.yaml b/charts/metal3/0.2.1/charts/ironic/templates/configmap-ipa-downloader.yaml new file mode 100644 index 00000000..0536c000 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/configmap-ipa-downloader.yaml @@ -0,0 +1,12 @@ +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/charts/metal3/0.2.1/charts/ironic/templates/configmap.yaml b/charts/metal3/0.2.1/charts/ironic/templates/configmap.yaml new file mode 100644 index 00000000..934d09ca --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/configmap.yaml @@ -0,0 +1,70 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ironic-bmo + labels: + {{- include "ironic.labels" . | nindent 4 }} +data: + {{- $protocol := "http" }} + {{- $ironicApiHost := .Values.global.ironicApiHost }} + {{- $ironicBootHost := .Values.global.ironicBootHost }} + {{- $ironicInspectorHost := .Values.global.ironicInspectorHost }} + {{- $ironicCacheHost := .Values.global.ironicCacheHost }} + + {{- if .Values.global.ironicIP }} + {{- $ironicApiHost = print .Values.global.ironicIP ":6385" }} + {{- $ironicBootHost = print .Values.global.ironicIP ":6180" }} + {{- $ironicInspectorHost = print .Values.global.ironicIP ":5050" }} + {{- $ironicCacheHost = print .Values.global.ironicIP ":6180" }} + {{- end }} + + {{- if ( .Values.global.enable_tls ) }} + {{- $protocol = "https" }} + {{- end }} + {{- if ( .Values.global.enable_dnsmasq ) }} + DNSMASQ_BOOT_SERVER_ADDRESS: {{ $ironicBootHost }} + 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" + CACHEURL: {{ $protocol }}://{{ $ironicCacheHost }}/images + DEPLOY_KERNEL_URL: {{ $protocol }}://{{ $ironicBootHost }}/images/ironic-python-agent.kernel + DEPLOY_RAMDISK_URL: {{ $protocol }}://{{ $ironicBootHost }}/images/ironic-python-agent.initramfs + IRONIC_API_BASE_URL: {{ $protocol }}://{{ $ironicApiHost }} + IRONIC_API_HOST: {{ $ironicApiHost }} + IRONIC_API_HTTPD_SERVER_NAME: {{ $ironicApiHost }} + IRONIC_BOOT_BASE_URL: {{ $protocol }}://{{ $ironicBootHost }} + IRONIC_ENDPOINT: {{ $protocol }}://{{ $ironicApiHost }}/v1/ + IRONIC_INSPECTOR_BASE_URL: {{ $protocol }}://{{ $ironicInspectorHost }} + IRONIC_INSPECTOR_ENDPOINT: {{ $protocol }}://{{ $ironicInspectorHost }}/v1/ + IRONIC_INSPECTOR_HOST: {{ $ironicInspectorHost }} + IRONIC_INSPECTOR_HTTPD_SERVER_NAME: {{ $ironicInspectorHost }} + IRONIC_VMEDIA_HTTPD_SERVER_NAME: {{ $ironicBootHost }} + ENABLE_PXE_BOOT: "{{ .Values.global.enable_pxe_boot }}" + {{- if .Values.global.provisioningInterface }} + PROVISIONING_INTERFACE: {{ .Values.global.provisioningInterface }} + {{- end }} + {{- if .Values.global.provisioningIP }} + PROVISIONING_IP: {{ .Values.global.provisioningIP }} + {{- end }} + IRONIC_INSPECTOR_VLAN_INTERFACES: all + IRONIC_ILO_USE_SWIFT: "false" + IRONIC_ILO_USE_WEB_SERVER_FOR_IMAGES: "true" + IRONIC_FAST_TRACK: "true" + IRONIC_REVERSE_PROXY_SETUP: "false" + IRONIC_USE_MARIADB: "true" + LISTEN_ALL_INTERFACES: "true" + {{- if ( .Values.global.enable_tls ) }} + RESTART_CONTAINER_CERTIFICATE_UPDATED: "true" + IRONIC_KERNEL_PARAMS: console=ttyS0 suse.cafile={{ $protocol }}://{{ $ironicBootHost }}/tstcerts/ca.crt + IPA_INSECURE: "0" + {{- else }} + RESTART_CONTAINER_CERTIFICATE_UPDATED: "false" + IRONIC_KERNEL_PARAMS: console=ttyS0 + IPA_INSECURE: "1" + {{- end }} + DATABASE_HOST: {{ .Values.global.databaseServiceName }}.{{ .Release.Namespace }}.svc.cluster.local diff --git a/charts/metal3/0.2.1/charts/ironic/templates/deployment.yaml b/charts/metal3/0.2.1/charts/ironic/templates/deployment.yaml new file mode 100644 index 00000000..08b76a30 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/deployment.yaml @@ -0,0 +1,294 @@ +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: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "ironic.selectorLabels" . | nindent 8 }} + spec: + {{- $tlssource := .Values.ingress.tlsSource }} + {{- if .Values.podSecurityContext }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- end }} + {{- if .Values.baremetaloperator.ironichostNetwork }} + hostNetwork: {{ .Values.baremetaloperator.ironichostNetwork }} + {{- end }} + containers: + {{- if .Values.global.enable_ironic }} + - 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-bmo + {{- if and (eq $.Values.global.provisioningInterface "") (eq $.Values.global.provisioningIP "") }} + env: + - name: PROVISIONING_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- end }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + - curl -sSf http://127.0.0.1:6180/boot.ipxe || curl -sSfk https://127.0.0.1:6180/boot.ipxe + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + ports: + - containerPort: 6180 + name: httpd + protocol: TCP + readinessProbe: + exec: + command: + - /bin/sh + - -c + - curl -sSf http://127.0.0.1:6180/boot.ipxe || curl -sSfk https://127.0.0.1:6180/boot.ipxe + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + {{- if .Values.global.enable_tls }} + {{- include "ironic.tlsVolumeMounts" . | nindent 10 }} + {{- end }} + - name: ironic-inspector + image: {{ .Values.images.ironic.repository }}:{{ .Values.images.ironic.tag }} + imagePullPolicy: {{ .Values.images.ironic.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + command: + - /bin/runironic-inspector + envFrom: + - configMapRef: + name: ironic-bmo + env: + - name: MARIADB_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: ironic-mariadb + {{- if and (eq $.Values.global.provisioningInterface "") (eq $.Values.global.provisioningIP "") }} + - name: PROVISIONING_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- end }} + livenessProbe: + exec: + command: + - sh + - -c + - curl -sSf http://127.0.0.1:5050 || curl -sSf -k https://127.0.0.1:5050 + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + ports: + - containerPort: 5050 + name: inspector + protocol: TCP + readinessProbe: + exec: + command: + - sh + - -c + - curl -sSf http://127.0.0.1:5050 || curl -sSf -k https://127.0.0.1:5050 + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + {{- if .Values.global.enable_tls }} + {{- include "ironic.tlsVolumeMounts" . | nindent 10 }} + {{- 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-bmo + env: + - name: MARIADB_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: ironic-mariadb + {{- if and (eq $.Values.global.provisioningInterface "") (eq $.Values.global.provisioningIP "") }} + - name: PROVISIONING_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- end }} + livenessProbe: + exec: + command: + - /bin/sh + - -c + - curl -sSf http://127.0.0.1:6385 || curl -sSfk https://127.0.0.1:6385 + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + ports: + - containerPort: 6385 + name: api + protocol: TCP + readinessProbe: + exec: + command: + - /bin/sh + - -c + - curl -sSf http://127.0.0.1:6385 || curl -sSfk https://127.0.0.1:6385 + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + {{- if .Values.global.enable_tls }} + {{- include "ironic.tlsVolumeMounts" . | nindent 10 }} + {{- end }} + {{- if .Values.global.enable_tls }} + lifecycle: + postStart: + exec: + command: + - update-ca-certificates + {{- end }} + {{- end }} + {{- if .Values.global.enable_dnsmasq }} + - name: ironic-dnsmasq + image: {{ .Values.images.ironic.repository }}:{{ .Values.images.ironic.tag }} + imagePullPolicy: {{ .Values.images.ironic.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + command: + - /bin/rundnsmasq + envFrom: + - configMapRef: + name: ironic-bmo + 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 }} + {{- if .Values.global.enable_ironic }} + 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 + envFrom: + - configMapRef: + name: ironic-ipa-downloader + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + {{- if .Values.global.enable_tls }} + {{- if (eq $tlssource "secrets") }} + {{- include "ironic.cacertVolumeMounts" . | nindent 10 }} + {{- end }} + {{- if (eq $tlssource "self") }} + {{- include "ironic.trustVolMounts" . | nindent 10 }} + {{- end }} + {{- end }} + {{- end }} + volumes: + {{- include "ironic.volumes" . | nindent 8 }} + {{- 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.2.1/charts/ironic/templates/ingress.yaml b/charts/metal3/0.2.1/charts/ironic/templates/ingress.yaml new file mode 100644 index 00000000..38b4c7a6 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/ingress.yaml @@ -0,0 +1,81 @@ +{{- if and (.Values.ingress.enabled) (.Values.global.enable_ironic) -}} +{{- $fullName := include "ironic.fullname" . -}} +{{- 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 ($.Values.global.enable_tls) }} + {{ $_ := set .Values.ingress.annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true"}} + {{- if (eq .Values.tls "ironic") }} + {{ $_ := set .Values.ingress.annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS"}} + {{ $_ := set .Values.ingress.annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "false"}} + {{- end }} +{{- if or ( eq .Values.ingress.tlsSource "letsEncrypt" ) ( eq .Values.ingress.tlsSource "self" ) }} + {{ $_ := set .Values.ingress.annotations "certmanager.k8s.io/issuer" $fullName}} +{{- end }} +{{- else }} + {{ $_ := set .Values.ingress.annotations "nginx.ingress.kubernetes.io/ssl-redirect" "false"}} +{{- 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 "ironic.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 }} + - {{ tpl . $ }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + defaultBackend: + {{- with (index .Values.ingress.hosts 0) }} + service: + name: {{ $fullName }} + port: + {{- range .paths }} + name: {{ .portname }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ tpl .host $}} + http: + paths: + {{- range .paths }} + - backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + name: {{ .portname }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ .portname }} + {{- end }} + path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/metal3/0.2.1/charts/ironic/templates/issuer-ca.yaml b/charts/metal3/0.2.1/charts/ironic/templates/issuer-ca.yaml new file mode 100644 index 00000000..5f786ff4 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/issuer-ca.yaml @@ -0,0 +1,13 @@ +{{- if and (.Values.ingress.enabled) (.Values.global.enable_ironic) -}} + {{- if and ($.Values.global.enable_tls) (eq .Values.ingress.tlsSource "self") -}} +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "ironic.fullname" . }}-tls + labels: + {{- include "ironic.labels" . | nindent 4 }} +spec: + ca: + secretName: ironic-cacert + {{- end -}} +{{- end -}} diff --git a/charts/metal3/0.2.1/charts/ironic/templates/issuer-letsEncrypt.yaml b/charts/metal3/0.2.1/charts/ironic/templates/issuer-letsEncrypt.yaml new file mode 100644 index 00000000..349a21d4 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/issuer-letsEncrypt.yaml @@ -0,0 +1,33 @@ +{{- if and (.Values.ingress.enabled) (.Values.global.enable_ironic) -}} + {{- if and ($.Values.global.enable_tls) (eq .Values.ingress.tlsSource "letsEncrypt") -}} +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "ironic.fullname" . }} + labels: + {{- include "ironic.labels" . | nindent 4 }} +spec: + {{- $relname := .Release.Name }} + acme: + {{- if eq .Values.letsEncrypt.environment "production" }} + server: https://acme-v02.api.letsencrypt.org/directory + {{- else }} + server: https://acme-staging-v02.api.letsencrypt.org/directory + {{- end }} + email: '' + privateKeySecretRef: + name: letsencrypt-private-key + solvers: + - selector: + dnsNames: + - "api.ironic.{{ .Values.global.dnsDomain }}" + - "inspector.ironic.{{ .Values.global.dnsDomain }}" + - "boot.ironic.{{ .Values.global.dnsDomain }}" + - "cache.ironic.{{ .Values.global.dnsDomain }}" + dns01: + cloudflare: + apiTokenSecretRef: + name: {{ include "ironic.fullname" . }}-dns-provider-credentials + key: api-token + {{- end -}} +{{- end -}} diff --git a/charts/metal3/0.2.1/charts/ironic/templates/issuer-self-signed.yaml b/charts/metal3/0.2.1/charts/ironic/templates/issuer-self-signed.yaml new file mode 100644 index 00000000..3c87709d --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/issuer-self-signed.yaml @@ -0,0 +1,12 @@ +{{- if and (.Values.ingress.enabled) (.Values.global.enable_ironic) -}} + {{- if and ($.Values.global.enable_tls) (eq .Values.ingress.tlsSource "self") -}} +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: {{ include "ironic.fullname" . }} + labels: + {{- include "ironic.labels" . | nindent 4 }} +spec: + selfSigned: {} + {{- end -}} +{{- end -}} diff --git a/charts/metal3/0.2.1/charts/ironic/templates/pvc.yaml b/charts/metal3/0.2.1/charts/ironic/templates/pvc.yaml new file mode 100644 index 00000000..756814b7 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/pvc.yaml @@ -0,0 +1,26 @@ +{{- if .Values.global.enable_ironic -}} +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.2.1/charts/ironic/templates/secret-cloudfare.yaml b/charts/metal3/0.2.1/charts/ironic/templates/secret-cloudfare.yaml new file mode 100644 index 00000000..14eb8b1c --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/secret-cloudfare.yaml @@ -0,0 +1,13 @@ +{{- if and ( .Values.ingress.enabled) (.Values.global.enable_ironic) -}} + {{- if and ($.Values.global.enable_tls) (eq .Values.ingress.tlsSource "letsEncrypt") -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "ironic.fullname" . }}-dns-provider-credentials + labels: + {{- include "ironic.labels" . | nindent 4 }} +type: Opaque +stringData: + api-token: {{ .Values.baremetaloperator.cloudflareApiToken }} + {{- end }} +{{- end }} diff --git a/charts/metal3/0.2.1/charts/ironic/templates/secret-tls.yaml b/charts/metal3/0.2.1/charts/ironic/templates/secret-tls.yaml new file mode 100644 index 00000000..419a8b7e --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/secret-tls.yaml @@ -0,0 +1,15 @@ +{{- if and ( .Values.ingress.enabled) (.Values.global.enable_ironic) -}} + {{- if and ($.Values.global.enable_tls) (eq .Values.ingress.tlsSource "secrets") -}} +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 }} +{{- end }} diff --git a/charts/metal3/0.2.1/charts/ironic/templates/service.yaml b/charts/metal3/0.2.1/charts/ironic/templates/service.yaml new file mode 100644 index 00000000..e2fbd48d --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/service.yaml @@ -0,0 +1,24 @@ +{{- if .Values.global.enable_ironic -}} +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 }} + {{- with .Values.service.ports }} + ports: + {{- toYaml . | nindent 4 }} + {{- 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 }} +{{- end -}} diff --git a/charts/metal3/0.2.1/charts/ironic/templates/serviceaccount.yaml b/charts/metal3/0.2.1/charts/ironic/templates/serviceaccount.yaml new file mode 100644 index 00000000..8784a5b6 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if and (.Values.serviceAccount.create) (.Values.global.enable_ironic) -}} +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.2.1/charts/ironic/values.yaml b/charts/metal3/0.2.1/charts/ironic/values.yaml new file mode 100644 index 00000000..52edf4c0 --- /dev/null +++ b/charts/metal3/0.2.1/charts/ironic/values.yaml @@ -0,0 +1,204 @@ +# Default values for ironic. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +global: + enable_tls: false + # whether to enable dnsmasq on the provisioning network (for PXE boot) + enable_dnsmasq: false + + # whether to enable Ironic services besides dnsmasq. + # NOTE: enable_dnsmasq has precedence over this option. If enable_dnsmasq is set + # to 'true' while enable_ironic is set to 'false', dnsmasq service will still be + # enabled. + enable_ironic: true + + # 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 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 + # Note this must be a dedicated NIC separate from the controlplane network + provisioningInterface: "" + + # IP Address assigned to network interface on provisioning network + provisioningIP: "" + + databaseServiceName: "metal3-mariadb" + + # 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 + + # 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 + +images: + ironic: + repository: registry.opensuse.org/isv/metal3/bci/ironic/containerfile/suse/ironic + pullPolicy: IfNotPresent + tag: 21.1.1 + ironicIPADownloader: + repository: registry.opensuse.org/isv/metal3/bci/ironic/containerfile/suse/ironic-ipa-downloader + pullPolicy: IfNotPresent + tag: latest + +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: 10475 + fsGroup: 10475 + +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + +service: + type: NodePort + annotations: {} + externalIPs: [] + ports: + - name: httpd + port: 6180 + protocol: TCP + targetPort: 6180 + - name: inspector + port: 5050 + protocol: TCP + targetPort: 5050 + - name: api + port: 6385 + protocol: TCP + targetPort: 6385 + +ingress: + enabled: true + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: "{{ .Values.global.ironicApiHost }}" + paths: + - path: / + pathType: Prefix + portname: api + - host: "{{ .Values.global.ironicInspectorHost }}" + paths: + - path: / + pathType: Prefix + portname: inspector + - host: "{{ .Values.global.ironicBootHost }}" + paths: + - path: / + pathType: Prefix + portname: httpd + - host: "{{ .Values.global.ironicCacheHost }}" + paths: + - path: / + pathType: Prefix + portname: httpd + + # self,letsEncrypt,secrets + tlsSource: self + tls: + - secretName: ironic-cacert + hosts: + - "{{ .Values.global.ironicApiHost }}" + - "{{ .Values.global.ironicBootHost }}" + - "{{ .Values.global.ironicCacheHost }}" + - "{{ .Values.global.ironicInspectorHost }}" + + +letsEncrypt: + # email: none@example.com + environment: staging + +# +# tls +# Where to offload the TLS/SSL encryption +# - ingress (default) +# - ironic +tls: ingress + +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: "" + +tlscerts: {} + +persistence: + ironic: + # storageClass for the ironic shared volume + # Ensure the storageClass is defined + storageClass: "" + # size of the ironic shared volume + size: "1Gi" + # 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.2.1/charts/mariadb/.helmignore b/charts/metal3/0.2.1/charts/mariadb/.helmignore new file mode 100644 index 00000000..898df488 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/mariadb/Chart.yaml b/charts/metal3/0.2.1/charts/mariadb/Chart.yaml new file mode 100644 index 00000000..4ebc470a --- /dev/null +++ b/charts/metal3/0.2.1/charts/mariadb/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 10.6.7 +description: A Helm chart for MariaDB, used by Metal3 +name: mariadb +type: application +version: 0.2.1 diff --git a/charts/metal3/0.2.1/charts/mariadb/templates/_helpers.tpl b/charts/metal3/0.2.1/charts/mariadb/templates/_helpers.tpl new file mode 100644 index 00000000..dbff3a16 --- /dev/null +++ b/charts/metal3/0.2.1/charts/mariadb/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* +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/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.2.1/charts/mariadb/templates/configmap.yaml b/charts/metal3/0.2.1/charts/mariadb/templates/configmap.yaml new file mode 100644 index 00000000..ef498a98 --- /dev/null +++ b/charts/metal3/0.2.1/charts/mariadb/templates/configmap.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: mariadb-cm + labels: + {{- include "mariadb.labels" . | nindent 4 }} +data: + RESTART_CONTAINER_CERTIFICATE_UPDATED: "false" diff --git a/charts/metal3/0.2.1/charts/mariadb/templates/deployment.yaml b/charts/metal3/0.2.1/charts/mariadb/templates/deployment.yaml new file mode 100644 index 00000000..580a88ce --- /dev/null +++ b/charts/metal3/0.2.1/charts/mariadb/templates/deployment.yaml @@ -0,0 +1,78 @@ +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 12 }} + {{- $volumes := toYaml .Values.volumes | trim | nindent 8 }} + serviceAccountName: {{ include "mariadb.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: mariadb + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + env: + - name: MARIADB_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: ironic-mariadb + - name: RESTART_CONTAINER_CERTIFICATE_UPDATED + valueFrom: + configMapKeyRef: + name: mariadb-cm + key: RESTART_CONTAINER_CERTIFICATE_UPDATED + livenessProbe: + exec: + command: + - sh + - -c + - mysqladmin status -uironic -p$(printenv MARIADB_PASSWORD) + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + ports: + - containerPort: 3306 + name: mariadb + protocol: TCP + readinessProbe: + exec: + command: + - sh + - -c + - mysqladmin status -uironic -p$(printenv MARIADB_PASSWORD) + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + volumeMounts: + {{- $volmounts }} + {{- with .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + {{- $volumes }} diff --git a/charts/metal3/0.2.1/charts/mariadb/templates/pvc.yaml b/charts/metal3/0.2.1/charts/mariadb/templates/pvc.yaml new file mode 100644 index 00000000..573e1525 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/mariadb/templates/secret.yaml b/charts/metal3/0.2.1/charts/mariadb/templates/secret.yaml new file mode 100644 index 00000000..3cde9e58 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/mariadb/templates/service-account.yaml b/charts/metal3/0.2.1/charts/mariadb/templates/service-account.yaml new file mode 100644 index 00000000..16794876 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/mariadb/templates/service.yaml b/charts/metal3/0.2.1/charts/mariadb/templates/service.yaml new file mode 100644 index 00000000..46b731fb --- /dev/null +++ b/charts/metal3/0.2.1/charts/mariadb/templates/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.global.databaseServiceName }} + labels: + {{- include "mariadb.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + selector: + {{- include "mariadb.selectorLabels" . | nindent 4 }} + ports: + {{- with .Values.service.ports }} + {{- toYaml . | nindent 2 }} + {{- end }} \ No newline at end of file diff --git a/charts/metal3/0.2.1/charts/mariadb/values.yaml b/charts/metal3/0.2.1/charts/mariadb/values.yaml new file mode 100644 index 00000000..deb8c2fd --- /dev/null +++ b/charts/metal3/0.2.1/charts/mariadb/values.yaml @@ -0,0 +1,67 @@ +global: + databaseServiceName: "metal3-mariadb" + nodeSelector: {} + +replicaCount: 1 + +service: + type: ClusterIP + ports: + - protocol: TCP + port: 3306 + targetPort: 3306 + +image: + repository: registry.opensuse.org/isv/metal3/bci/ironic/containerfile/suse/mariadb + pullPolicy: Always + tag: 10.6.7 + +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: 10060 + fsGroup: 10060 + +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 + +volumes: + - name: mariadb-data-volume + persistentVolumeClaim: + claimName: mariadb-volume-claim diff --git a/charts/metal3/0.2.1/charts/media/.helmignore b/charts/metal3/0.2.1/charts/media/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/media/Chart.yaml b/charts/metal3/0.2.1/charts/media/Chart.yaml new file mode 100644 index 00000000..1929be34 --- /dev/null +++ b/charts/metal3/0.2.1/charts/media/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 1.16.0 +description: A Helm chart for Media, used by Metal3 +name: media +type: application +version: 0.2.0 diff --git a/charts/metal3/0.2.1/charts/media/templates/NOTES.txt b/charts/metal3/0.2.1/charts/media/templates/NOTES.txt new file mode 100644 index 00000000..6823b8ca --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/media/templates/_helpers.tpl b/charts/metal3/0.2.1/charts/media/templates/_helpers.tpl new file mode 100644 index 00000000..5cbd4de4 --- /dev/null +++ b/charts/metal3/0.2.1/charts/media/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +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/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.2.1/charts/media/templates/deployment.yaml b/charts/metal3/0.2.1/charts/media/templates/deployment.yaml new file mode 100644 index 00000000..f37bcaa9 --- /dev/null +++ b/charts/metal3/0.2.1/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 | default .Chart.AppVersion }}" + 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.2.1/charts/media/templates/hpa.yaml b/charts/metal3/0.2.1/charts/media/templates/hpa.yaml new file mode 100644 index 00000000..296a627b --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/media/templates/ingress.yaml b/charts/metal3/0.2.1/charts/media/templates/ingress.yaml new file mode 100644 index 00000000..bc816995 --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/media/templates/persistentvolume.yaml b/charts/metal3/0.2.1/charts/media/templates/persistentvolume.yaml new file mode 100644 index 00000000..be5c9afd --- /dev/null +++ b/charts/metal3/0.2.1/charts/media/templates/persistentvolume.yaml @@ -0,0 +1,16 @@ +--- +kind: PersistentVolume +apiVersion: v1 +metadata: + name: media + labels: + {{- include "media.labels" . | nindent 4 }} +spec: + storageClassName: local + accessModes: + - ReadOnlyMany + capacity: + storage: 5Gi + hostPath: + path: {{ .Values.mediaVolume.hostPath }} + type: DirectoryOrCreate diff --git a/charts/metal3/0.2.1/charts/media/templates/persistentvolumeclaim.yaml b/charts/metal3/0.2.1/charts/media/templates/persistentvolumeclaim.yaml new file mode 100644 index 00000000..a61d16ba --- /dev/null +++ b/charts/metal3/0.2.1/charts/media/templates/persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: media + labels: + {{- include "media.labels" . | nindent 4 }} +spec: + storageClassName: local + accessModes: + - ReadOnlyMany + resources: + requests: + storage: 5Mi diff --git a/charts/metal3/0.2.1/charts/media/templates/service.yaml b/charts/metal3/0.2.1/charts/media/templates/service.yaml new file mode 100644 index 00000000..5f199299 --- /dev/null +++ b/charts/metal3/0.2.1/charts/media/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "media.fullname" . }} + labels: + {{- include "media.labels" . | nindent 4 }} +spec: + 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.2.1/charts/media/templates/serviceaccount.yaml b/charts/metal3/0.2.1/charts/media/templates/serviceaccount.yaml new file mode 100644 index 00000000..513a44ab --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/media/templates/storageclass.yaml b/charts/metal3/0.2.1/charts/media/templates/storageclass.yaml new file mode 100644 index 00000000..001cdd9b --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/charts/media/templates/tests/test-connection.yaml b/charts/metal3/0.2.1/charts/media/templates/tests/test-connection.yaml new file mode 100644 index 00000000..aa4fe238 --- /dev/null +++ b/charts/metal3/0.2.1/charts/media/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "media.fullname" . }}-test-connection" + labels: + {{- include "media.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "media.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/charts/metal3/0.2.1/charts/media/values.yaml b/charts/metal3/0.2.1/charts/media/values.yaml new file mode 100644 index 00000000..d565e61b --- /dev/null +++ b/charts/metal3/0.2.1/charts/media/values.yaml @@ -0,0 +1,112 @@ +# 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: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "1.22.0-alpine" + +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: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +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 + +# volume mounts +volumeMounts: + - mountPath: /usr/share/nginx/html + name: assets + +# media volume settings +mediaVolume: + hostPath: /opt/media diff --git a/charts/metal3/0.2.1/templates/NOTES.txt b/charts/metal3/0.2.1/templates/NOTES.txt new file mode 100644 index 00000000..ecac059d --- /dev/null +++ b/charts/metal3/0.2.1/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.2.1/templates/_helpers.tpl b/charts/metal3/0.2.1/templates/_helpers.tpl new file mode 100644 index 00000000..17b1ac8c --- /dev/null +++ b/charts/metal3/0.2.1/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +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 }} diff --git a/charts/metal3/0.2.1/values.yaml b/charts/metal3/0.2.1/values.yaml new file mode 100644 index 00000000..070ff393 --- /dev/null +++ b/charts/metal3/0.2.1/values.yaml @@ -0,0 +1,99 @@ +# 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 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 Ironic services besides dnsmasq. + # NOTE: enable_dnsmasq has precedence over this option. If enable_dnsmasq is set + # to 'true' while enable_ironic is set to 'false', dnsmasq service will still be + # enabled. + enable_ironic: true + + # Host of the Ironic API + ironicApiHost: "" + # Host of the Ironic Inspector + ironicInspectorHost: "" + # Host of the Ironic Boot + ironicBootHost: "" + # Host of the Ironic Cache + ironicCacheHost: "" + + # 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: "" + + # 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 + ingress: + enabled: false + + 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.yaml b/index.yaml index b9b67437..7842caf1 100755 --- a/index.yaml +++ b/index.yaml @@ -167,6 +167,35 @@ entries: urls: - assets/metal3/metal3-0.3.0.tgz version: 0.3.0 + - apiVersion: v2 + appVersion: 1.16.0 + created: "2023-12-19T11:22:03.148444+02:00" + dependencies: + - alias: metal3-baremetal-operator + name: baremetal-operator + repository: file://./charts/baremetal-operator + version: 0.2.1 + - alias: metal3-ironic + name: ironic + repository: file://./charts/ironic + version: 0.2.1 + - alias: metal3-mariadb + name: mariadb + repository: file://./charts/mariadb + version: 0.2.1 + - alias: metal3-media + condition: global.enable_metal3_media_server + name: media + repository: file://./charts/media + version: 0.2.0 + description: A Helm chart that installs all of the dependencies needed for Metal3 + digest: 3cb7688578afc4e6e4f1c1181fd4314f15b1c86ac04f6b433c328e6eb5cfd89e + 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.2.1.tgz + version: 0.2.1 - apiVersion: v2 appVersion: 1.16.0 created: "2023-11-27T16:49:36.891948+02:00"