From 606de0934eba989f5918981d8f61272d7347f8fa756acc81d978fcde78800947 Mon Sep 17 00:00:00 2001 From: Denislav Prodanov Date: Mon, 21 Oct 2024 15:18:05 +0300 Subject: [PATCH 1/3] init for moving Edge 3.1 images from IBS --- cluster-api-controller-image/Dockerfile | 36 +++ cluster-api-controller-image/_service | 17 ++ cluster-api-operator-image/Dockerfile | 35 +++ cluster-api-operator-image/_service | 17 ++ cluster-api-provider-metal3-image/Dockerfile | 36 +++ cluster-api-provider-metal3-image/_service | 17 ++ .../Dockerfile | 36 +++ .../_service | 17 ++ .../Dockerfile | 36 +++ .../_service | 17 ++ edge-image-builder-image/Dockerfile | 40 +++ edge-image-builder-image/_service | 14 + edge-image-builder-image/artifacts.yaml | 16 ++ ip-address-manager-image/Dockerfile | 36 +++ ip-address-manager-image/_service | 17 ++ ironic-image/Dockerfile | 91 +++++++ ironic-image/_service | 17 ++ ironic-image/apache2-vmedia.conf.j2 | 27 ++ ironic-image/auth-common.sh | 71 +++++ ironic-image/configure-ironic.sh | 102 +++++++ ironic-image/configure-nonroot.sh | 50 ++++ ironic-image/dnsmasq.conf.j2 | 79 ++++++ ironic-image/httpd-ironic-api.conf.j2 | 85 ++++++ ironic-image/httpd-modules.conf | 21 ++ ironic-image/httpd.conf.j2 | 84 ++++++ ironic-image/inspector-apache.conf.j2 | 57 ++++ ironic-image/inspector.ipxe.j2 | 10 + ironic-image/ironic-common.sh | 110 ++++++++ ironic-image/ironic-inspector.conf.j2 | 68 +++++ ironic-image/ironic.conf.j2 | 253 ++++++++++++++++++ ironic-image/mkisofs_wrapper | 3 + ironic-image/network-data-schema-empty.json | 1 + ironic-image/prepare-efi.sh | 27 ++ ironic-image/rundnsmasq | 35 +++ ironic-image/runhttpd | 101 +++++++ ironic-image/runironic | 25 ++ ironic-image/runironic-api | 13 + ironic-image/runironic-conductor | 20 ++ ironic-image/runironic-exporter | 12 + ironic-image/runironic-inspector | 62 +++++ ironic-image/runlogwatch.sh | 20 ++ ironic-image/tls-common.sh | 101 +++++++ ironic-ipa-downloader-image/Dockerfile | 45 ++++ ironic-ipa-downloader-image/_service | 17 ++ .../configure-nonroot.sh | 12 + ironic-ipa-downloader-image/get-resource.sh | 71 +++++ 46 files changed, 2077 insertions(+) create mode 100644 cluster-api-controller-image/Dockerfile create mode 100644 cluster-api-controller-image/_service create mode 100644 cluster-api-operator-image/Dockerfile create mode 100644 cluster-api-operator-image/_service create mode 100644 cluster-api-provider-metal3-image/Dockerfile create mode 100644 cluster-api-provider-metal3-image/_service create mode 100644 cluster-api-provider-rke2-bootstrap-image/Dockerfile create mode 100644 cluster-api-provider-rke2-bootstrap-image/_service create mode 100644 cluster-api-provider-rke2-controlplane-image/Dockerfile create mode 100644 cluster-api-provider-rke2-controlplane-image/_service create mode 100644 edge-image-builder-image/Dockerfile create mode 100644 edge-image-builder-image/_service create mode 100644 edge-image-builder-image/artifacts.yaml create mode 100644 ip-address-manager-image/Dockerfile create mode 100644 ip-address-manager-image/_service create mode 100644 ironic-image/Dockerfile create mode 100644 ironic-image/_service create mode 100644 ironic-image/apache2-vmedia.conf.j2 create mode 100644 ironic-image/auth-common.sh create mode 100644 ironic-image/configure-ironic.sh create mode 100644 ironic-image/configure-nonroot.sh create mode 100644 ironic-image/dnsmasq.conf.j2 create mode 100644 ironic-image/httpd-ironic-api.conf.j2 create mode 100644 ironic-image/httpd-modules.conf create mode 100644 ironic-image/httpd.conf.j2 create mode 100644 ironic-image/inspector-apache.conf.j2 create mode 100644 ironic-image/inspector.ipxe.j2 create mode 100644 ironic-image/ironic-common.sh create mode 100644 ironic-image/ironic-inspector.conf.j2 create mode 100644 ironic-image/ironic.conf.j2 create mode 100644 ironic-image/mkisofs_wrapper create mode 100644 ironic-image/network-data-schema-empty.json create mode 100644 ironic-image/prepare-efi.sh create mode 100644 ironic-image/rundnsmasq create mode 100644 ironic-image/runhttpd create mode 100644 ironic-image/runironic create mode 100644 ironic-image/runironic-api create mode 100644 ironic-image/runironic-conductor create mode 100644 ironic-image/runironic-exporter create mode 100644 ironic-image/runironic-inspector create mode 100644 ironic-image/runlogwatch.sh create mode 100644 ironic-image/tls-common.sh create mode 100644 ironic-ipa-downloader-image/Dockerfile create mode 100644 ironic-ipa-downloader-image/_service create mode 100644 ironic-ipa-downloader-image/configure-nonroot.sh create mode 100644 ironic-ipa-downloader-image/get-resource.sh diff --git a/cluster-api-controller-image/Dockerfile b/cluster-api-controller-image/Dockerfile new file mode 100644 index 0000000..f4057c5 --- /dev/null +++ b/cluster-api-controller-image/Dockerfile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%cluster-api-controller:v%%cluster-api_version%% +#!BuildTag: %%IMG_PREFIX%%cluster-api-controller:%%cluster-api_version%% +#!BuildTag: %%IMG_PREFIX%%cluster-api-controller:%%cluster-api_version%%-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-175 shadow; zypper -n clean; rm -rf /var/log/* + +FROM micro AS final +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.cluster-api +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE cluster-api Container Image" +LABEL org.opencontainers.image.description="cluster-api based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="%%cluster-api_version%%" +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%cluster-api:%%cluster-api_version%%-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +RUN mv /usr/bin/cluster-api-controller /manager +# Use uid of nonroot user (65532) because kubernetes expects numeric user when applying pod security policies +USER 65532 +ENTRYPOINT [ "/manager" ] diff --git a/cluster-api-controller-image/_service b/cluster-api-controller-image/_service new file mode 100644 index 0000000..9f48c56 --- /dev/null +++ b/cluster-api-controller-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%cluster-api_version%% + cluster-api-175 + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + diff --git a/cluster-api-operator-image/Dockerfile b/cluster-api-operator-image/Dockerfile new file mode 100644 index 0000000..8244d9c --- /dev/null +++ b/cluster-api-operator-image/Dockerfile @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%cluster-api-operator:%%cluster-api-operator_version%% +#!BuildTag: %%IMG_PREFIX%%cluster-api-operator:%%cluster-api-operator_version%%-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-operator-012 shadow; zypper -n clean; rm -rf /var/log/* + +FROM micro AS final +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.cluster-api-operator +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE cluster-api-operator Container Image" +LABEL org.opencontainers.image.description="cluster-api-operator based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="%%cluster-api-operator_version%%" +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%cluster-api-operator:%%cluster-api-operator_version%%-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +RUN mv /usr/bin/cluster-api-operator-controller /manager +# Use uid of nonroot user (65532) because kubernetes expects numeric user when applying pod security policies +USER 65532 +ENTRYPOINT [ "/manager" ] diff --git a/cluster-api-operator-image/_service b/cluster-api-operator-image/_service new file mode 100644 index 0000000..646f2d0 --- /dev/null +++ b/cluster-api-operator-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%cluster-api-operator_version%% + cluster-api-operator-012 + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + diff --git a/cluster-api-provider-metal3-image/Dockerfile b/cluster-api-provider-metal3-image/Dockerfile new file mode 100644 index 0000000..edd6d38 --- /dev/null +++ b/cluster-api-provider-metal3-image/Dockerfile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%cluster-api-provider-metal3:v%%cluster-api-provider-metal3_version%% +#!BuildTag: %%IMG_PREFIX%%cluster-api-provider-metal3:%%cluster-api-provider-metal3_version%% +#!BuildTag: %%IMG_PREFIX%%cluster-api-provider-metal3:%%cluster-api-provider-metal3_version%%-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-provider-metal3-171 shadow; zypper -n clean; rm -rf /var/log/* + +FROM micro AS final +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.cluster-api-provider-metal3 +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE cluster-api-provider-metal3 Container Image" +LABEL org.opencontainers.image.description="cluster-api-provider-metal3 based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="%%cluster-api-provider-metal3_version%%" +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%cluster-api-provider-metal3:%%cluster-api-provider-metal3_version%%-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +RUN mv /usr/bin/cluster-api-provider-metal3 /manager +# Use uid of nonroot user (65532) because kubernetes expects numeric user when applying pod security policies +USER 65532 +ENTRYPOINT [ "/manager" ] diff --git a/cluster-api-provider-metal3-image/_service b/cluster-api-provider-metal3-image/_service new file mode 100644 index 0000000..2ef5aa3 --- /dev/null +++ b/cluster-api-provider-metal3-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%cluster-api-provider-metal3_version%% + cluster-api-provider-metal3-171 + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + diff --git a/cluster-api-provider-rke2-bootstrap-image/Dockerfile b/cluster-api-provider-rke2-bootstrap-image/Dockerfile new file mode 100644 index 0000000..902d5db --- /dev/null +++ b/cluster-api-provider-rke2-bootstrap-image/Dockerfile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%cluster-api-provider-rke2-bootstrap:v%%cluster-api-provider-rke2_version%% +#!BuildTag: %%IMG_PREFIX%%cluster-api-provider-rke2-bootstrap:%%cluster-api-provider-rke2_version%% +#!BuildTag: %%IMG_PREFIX%%cluster-api-provider-rke2-bootstrap:%%cluster-api-provider-rke2_version%%-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-provider-rke2-070-bootstrap shadow; zypper -n clean; rm -rf /var/log/* + +FROM micro AS final +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.cluster-api-provider-rke2 +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE cluster-api-provider-rke2 Container Image" +LABEL org.opencontainers.image.description="cluster-api-provider-rke2 based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="%%cluster-api-provider-rke2_version%%" +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%cluster-api-provider-rke2-bootstrap:%%cluster-api-provider-rke2_version%%-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +RUN mv /usr/bin/rke2-bootstrap-manager /manager +# Use uid of nonroot user (65532) because kubernetes expects numeric user when applying pod security policies +USER 65532 +ENTRYPOINT [ "/manager" ] diff --git a/cluster-api-provider-rke2-bootstrap-image/_service b/cluster-api-provider-rke2-bootstrap-image/_service new file mode 100644 index 0000000..fa241da --- /dev/null +++ b/cluster-api-provider-rke2-bootstrap-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%cluster-api-provider-rke2_version%% + cluster-api-provider-rke2-070-bootstrap + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + diff --git a/cluster-api-provider-rke2-controlplane-image/Dockerfile b/cluster-api-provider-rke2-controlplane-image/Dockerfile new file mode 100644 index 0000000..db8ac94 --- /dev/null +++ b/cluster-api-provider-rke2-controlplane-image/Dockerfile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%cluster-api-provider-rke2-controlplane:v%%cluster-api-provider-rke2_version%% +#!BuildTag: %%IMG_PREFIX%%cluster-api-provider-rke2-controlplane:%%cluster-api-provider-rke2_version%% +#!BuildTag: %%IMG_PREFIX%%cluster-api-provider-rke2-controlplane:%%cluster-api-provider-rke2_version%%-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-provider-rke2-070-control-plane shadow; zypper -n clean; rm -rf /var/log/* + +FROM micro AS final +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.cluster-api-provider-rke2 +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE cluster-api-provider-rke2 Container Image" +LABEL org.opencontainers.image.description="cluster-api-provider-rke2 based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="%%cluster-api-provider-rke2_version%%" +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%cluster-api-provider-rke2-controlplane:%%cluster-api-provider-rke2_version%%-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +RUN mv /usr/bin/rke2-control-plane-manager /manager +# Use uid of nonroot user (65532) because kubernetes expects numeric user when applying pod security policies +USER 65532 +ENTRYPOINT [ "/manager" ] diff --git a/cluster-api-provider-rke2-controlplane-image/_service b/cluster-api-provider-rke2-controlplane-image/_service new file mode 100644 index 0000000..7d398fe --- /dev/null +++ b/cluster-api-provider-rke2-controlplane-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%cluster-api-provider-rke2_version%% + cluster-api-provider-rke2-070-control-plane + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + diff --git a/edge-image-builder-image/Dockerfile b/edge-image-builder-image/Dockerfile new file mode 100644 index 0000000..714da54 --- /dev/null +++ b/edge-image-builder-image/Dockerfile @@ -0,0 +1,40 @@ +#!BuildTag: %%IMG_PREFIX%%edge-image-builder:1.1.0 +#!BuildTag: %%IMG_PREFIX%%edge-image-builder:1.1.0-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-base:$SLE_VERSION +MAINTAINER SUSE LLC (https://www.suse.com/) + +COPY artifacts.yaml artifacts.yaml + +RUN sed -i -e 's%^# rpm.install.excludedocs = no.*%rpm.install.excludedocs = yes%g' /etc/zypp/zypp.conf +RUN zypper --non-interactive install --no-recommends edge-image-builder-110 qemu-x86 qemu-uefi-aarch64 cni-plugins; zypper -n clean; rm -rf /var/log/* + +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.edge-image-builder +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE edge-image-builder Container Image" +LABEL org.opencontainers.image.description="edge-image-builder based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="1.1.0" +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%edge-image-builder:1.1.0-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +# Make adjustments for running guestfish and image modifications on aarch64 +# guestfish looks for very specific locations on the filesystem for UEFI firmware +# and also expects the boot kernel to be a portable executable (PE), not ELF. +RUN mkdir -p /usr/share/edk2/aarch64 && \ + cp /usr/share/qemu/aavmf-aarch64-code.bin /usr/share/edk2/aarch64/QEMU_EFI-pflash.raw && \ + cp /usr/share/qemu/aavmf-aarch64-vars.bin /usr/share/edk2/aarch64/vars-template-pflash.raw && \ + mv /boot/vmlinux* /boot/backup-vmlinux + +ENTRYPOINT ["/usr/bin/eib"] + diff --git a/edge-image-builder-image/_service b/edge-image-builder-image/_service new file mode 100644 index 0000000..3990297 --- /dev/null +++ b/edge-image-builder-image/_service @@ -0,0 +1,14 @@ + + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + artifacts.yaml + CHART_REPO=$(rpm --macros=/root/.rpmmacros -E %chart_repo) + CHART_REPO + + + diff --git a/edge-image-builder-image/artifacts.yaml b/edge-image-builder-image/artifacts.yaml new file mode 100644 index 0000000..c1c06f3 --- /dev/null +++ b/edge-image-builder-image/artifacts.yaml @@ -0,0 +1,16 @@ +metallb: + chart: metallb-chart + repository: %%CHART_REPO%%/3.1 + version: 0.14.9 +endpoint-copier-operator: + chart: endpoint-copier-operator-chart + repository: %%CHART_REPO%%/3.1 + version: 0.2.1 +kubernetes: + k3s: + selinuxPackage: k3s-selinux-1.6-1.slemicro.noarch + selinuxRepository: https://rpm.rancher.io/k3s/stable/common/slemicro/noarch + rke2: + selinuxPackage: rke2-selinux + selinuxRepository: https://rpm.rancher.io/rke2/stable/common/slemicro/noarch + diff --git a/ip-address-manager-image/Dockerfile b/ip-address-manager-image/Dockerfile new file mode 100644 index 0000000..672ad17 --- /dev/null +++ b/ip-address-manager-image/Dockerfile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%ip-address-manager:v%%ip-address-manager_version%% +#!BuildTag: %%IMG_PREFIX%%ip-address-manager:%%ip-address-manager_version%% +#!BuildTag: %%IMG_PREFIX%%ip-address-manager:%%ip-address-manager_version%%-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN zypper --installroot /installroot --non-interactive install --no-recommends ip-address-manager-171 shadow; zypper -n clean; rm -rf /var/log/* + +FROM micro AS final +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.ip-address-manager +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE ip-address-manager Container Image" +LABEL org.opencontainers.image.description="ip-address-manager based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="%%ip-address-manager_version%%" +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%ip-address-manager:%%ip-address-manager_version%%-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +RUN mv /usr/bin/ip-address-manager /manager +# Use uid of nonroot user (65532) because kubernetes expects numeric user when applying pod security policies +USER 65532 +ENTRYPOINT [ "/manager" ] diff --git a/ip-address-manager-image/_service b/ip-address-manager-image/_service new file mode 100644 index 0000000..a0d1450 --- /dev/null +++ b/ip-address-manager-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%ip-address-manager_version%% + ip-address-manager-171 + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + diff --git a/ironic-image/Dockerfile b/ironic-image/Dockerfile new file mode 100644 index 0000000..830d31f --- /dev/null +++ b/ironic-image/Dockerfile @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%ironic:24.1.2.0 +#!BuildTag: %%IMG_PREFIX%%ironic:24.1.2.0-%RELEASE% +#!BuildVersion: 15.6 + +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base + +RUN set -euo pipefail; zypper -n in --no-recommends gcc git make xz-devel shim dosfstools mtools glibc-extra grub2-x86_64-efi grub2; zypper -n clean; rm -rf /var/log/* +WORKDIR /tmp +COPY prepare-efi.sh /bin/ +RUN set -euo pipefail; chmod +x /bin/prepare-efi.sh +RUN /bin/prepare-efi.sh + +COPY --from=micro / /installroot/ +RUN sed -i -e 's%^# rpm.install.excludedocs = no.*%rpm.install.excludedocs = yes%g' /etc/zypp/zypp.conf +RUN zypper --installroot /installroot --non-interactive install --no-recommends python311-devel python311 python311-pip python-dracclient python311-sushy-oem-idrac python311-proliantutils python311-sushy python3-ironicclient git curl sles-release tar gzip vim gawk dnsmasq dosfstools apache2 apache2-mod_wsgi inotify-tools ipcalc ipmitool iproute2 procps qemu-tools sqlite3 util-linux xorriso tftp syslinux ipxe-bootimgs python311-sushy-tools crudini openstack-ironic openstack-ironic-inspector-api + +FROM micro AS final +MAINTAINER SUSE LLC (https://www.suse.com/) +# Define labels according to https://en.opensuse.org/Building_derived_containers +LABEL org.opencontainers.image.title="SLE Openstack Ironic Container Image" +LABEL org.opencontainers.image.description="Openstack Ironic based on the SLE Base Container Image." +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opencontainers.image.version="24.1.2.0" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%ironic:24.1.2.0-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / + +RUN set -euo pipefail; ln -s /usr/bin/python3.11 /usr/local/bin/python3; \ + ln -s /usr/bin/pydoc3.11 /usr/local/bin/pydoc + +ENV GRUB_DIR=/tftpboot/boot/grub + +# workaround for mkisofs command failing +RUN echo 'alias mkisofs="xorriso -as mkisofs"' >> ~/.bashrc +COPY mkisofs_wrapper /usr/bin/mkisofs +RUN set -euo pipefail; chmod +x /usr/bin/mkisofs + +COPY auth-common.sh configure-ironic.sh ironic-common.sh rundnsmasq runhttpd runironic runironic-api runironic-conductor runironic-exporter runironic-inspector runlogwatch.sh tls-common.sh configure-nonroot.sh /bin/ +RUN set -euo pipefail; chmod +x /bin/auth-common.sh; chmod +x /bin/configure-ironic.sh; chmod +x /bin/ironic-common.sh; chmod +x /bin/rundnsmasq; chmod +x /bin/runhttpd; chmod +x /bin/runironic; chmod +x /bin/runironic-api; chmod +x /bin/runironic-conductor; chmod +x /bin/runironic-exporter; chmod +x /bin/runironic-inspector; chmod +x /bin/runlogwatch.sh; chmod +x /bin/tls-common.sh; chmod +x /bin/configure-nonroot.sh; +RUN mkdir -p /tftpboot +RUN mkdir -p $GRUB_DIR + +# No need to support the Legacy BIOS boot +#RUN cp /usr/share/syslinux/pxelinux.0 /tftpboot +#RUN cp /usr/share/syslinux/chain.c32 /tftpboot/ + +# IRONIC # +RUN cp /usr/share/ipxe/undionly.kpxe /tftpboot/undionly.kpxe +RUN cp /usr/share/ipxe/ipxe-x86_64.efi /tftpboot/ipxe.efi +COPY --from=base /tmp/esp.img /tmp/uefi_esp.img + +COPY ironic.conf.j2 /etc/ironic/ +COPY inspector.ipxe.j2 httpd-ironic-api.conf.j2 /tmp/ +COPY network-data-schema-empty.json /etc/ironic/ + +# DNSMASQ +COPY dnsmasq.conf.j2 /etc/ + +# Custom httpd config, removes all but the bare minimum needed modules +COPY httpd.conf.j2 /etc/httpd/conf/ +COPY httpd-modules.conf /etc/httpd/conf.modules.d/ +COPY apache2-vmedia.conf.j2 /etc/httpd-vmedia.conf.j2 + +# IRONIC-INSPECTOR # +RUN mkdir -p /var/lib/ironic /var/lib/ironic-inspector && \ + sqlite3 /var/lib/ironic/ironic.db "pragma journal_mode=wal" && \ + sqlite3 /var/lib/ironic-inspector/ironic-inspector.db "pragma journal_mode=wal" + +COPY ironic-inspector.conf.j2 /etc/ironic-inspector/ +COPY inspector-apache.conf.j2 /etc/httpd/conf.d/ + +# Workaround +# Removing the 010-ironic.conf file that comes with the package +RUN rm /etc/ironic/ironic.conf.d/010-ironic.conf + +# configure non-root user and set relevant permissions +RUN configure-nonroot.sh && \ + rm -f /bin/configure-nonroot.sh diff --git a/ironic-image/_service b/ironic-image/_service new file mode 100644 index 0000000..219c79f --- /dev/null +++ b/ironic-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%openstack-ironic_version%% + openstack-ironic + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + diff --git a/ironic-image/apache2-vmedia.conf.j2 b/ironic-image/apache2-vmedia.conf.j2 new file mode 100644 index 0000000..1d7ad21 --- /dev/null +++ b/ironic-image/apache2-vmedia.conf.j2 @@ -0,0 +1,27 @@ +Listen {{ env.VMEDIA_TLS_PORT }} + + + ErrorLog /dev/stderr + LogLevel debug + CustomLog /dev/stdout combined + + SSLEngine on + SSLProtocol {{ env.IRONIC_VMEDIA_SSL_PROTOCOL }} + SSLCertificateFile {{ env.IRONIC_VMEDIA_CERT_FILE }} + SSLCertificateKeyFile {{ env.IRONIC_VMEDIA_KEY_FILE }} + + + AllowOverride None + Require all granted + + + + Options Indexes FollowSymLinks + AllowOverride None + Require all granted + + + + + SSLRequireSSL + diff --git a/ironic-image/auth-common.sh b/ironic-image/auth-common.sh new file mode 100644 index 0000000..9906776 --- /dev/null +++ b/ironic-image/auth-common.sh @@ -0,0 +1,71 @@ +#!/usr/bin/bash + +set -euxo pipefail + +export IRONIC_HTPASSWD=${IRONIC_HTPASSWD:-${HTTP_BASIC_HTPASSWD:-}} +export INSPECTOR_HTPASSWD=${INSPECTOR_HTPASSWD:-${HTTP_BASIC_HTPASSWD:-}} +export IRONIC_DEPLOYMENT="${IRONIC_DEPLOYMENT:-}" +export IRONIC_REVERSE_PROXY_SETUP=${IRONIC_REVERSE_PROXY_SETUP:-false} +export INSPECTOR_REVERSE_PROXY_SETUP=${INSPECTOR_REVERSE_PROXY_SETUP:-false} + +IRONIC_HTPASSWD_FILE=/etc/ironic/htpasswd +INSPECTOR_HTPASSWD_FILE=/etc/ironic-inspector/htpasswd + +configure_client_basic_auth() +{ + local auth_config_file="/auth/$1/auth-config" + local dest="${2:-/etc/ironic/ironic.conf}" + if [[ -f "${auth_config_file}" ]]; then + # Merge configurations in the "auth" directory into the default ironic configuration file because there is no way to choose the configuration file + # when running the api as a WSGI app. + crudini --merge "${dest}" < "${auth_config_file}" + fi +} + +configure_json_rpc_auth() +{ + export JSON_RPC_AUTH_STRATEGY="noauth" + if [[ -n "${IRONIC_HTPASSWD}" ]]; then + if [[ "${IRONIC_DEPLOYMENT}" == "Conductor" ]]; then + export JSON_RPC_AUTH_STRATEGY="http_basic" + printf "%s\n" "${IRONIC_HTPASSWD}" > "${IRONIC_HTPASSWD_FILE}-rpc" + else + printf "%s\n" "${IRONIC_HTPASSWD}" > "${IRONIC_HTPASSWD_FILE}" + fi + fi +} + +configure_ironic_auth() +{ + local config=/etc/ironic/ironic.conf + # Configure HTTP basic auth for API server + if [[ -n "${IRONIC_HTPASSWD}" ]]; then + printf "%s\n" "${IRONIC_HTPASSWD}" > "${IRONIC_HTPASSWD_FILE}" + if [[ "${IRONIC_REVERSE_PROXY_SETUP}" == "false" ]]; then + crudini --set "${config}" DEFAULT auth_strategy http_basic + crudini --set "${config}" DEFAULT http_basic_auth_user_file "${IRONIC_HTPASSWD_FILE}" + fi + fi +} + +configure_inspector_auth() +{ + local config=/etc/ironic-inspector/ironic-inspector.conf + if [[ -n "${INSPECTOR_HTPASSWD}" ]]; then + printf "%s\n" "${INSPECTOR_HTPASSWD}" > "${INSPECTOR_HTPASSWD_FILE}" + if [[ "${INSPECTOR_REVERSE_PROXY_SETUP}" == "false" ]]; then + crudini --set "${config}" DEFAULT auth_strategy http_basic + crudini --set "${config}" DEFAULT http_basic_auth_user_file "${INSPECTOR_HTPASSWD_FILE}" + fi + fi +} + +write_htpasswd_files() +{ + if [[ -n "${IRONIC_HTPASSWD:-}" ]]; then + printf "%s\n" "${IRONIC_HTPASSWD}" > "${IRONIC_HTPASSWD_FILE}" + fi + if [[ -n "${INSPECTOR_HTPASSWD:-}" ]]; then + printf "%s\n" "${INSPECTOR_HTPASSWD}" > "${INSPECTOR_HTPASSWD_FILE}" + fi +} diff --git a/ironic-image/configure-ironic.sh b/ironic-image/configure-ironic.sh new file mode 100644 index 0000000..fa07f43 --- /dev/null +++ b/ironic-image/configure-ironic.sh @@ -0,0 +1,102 @@ +#!/usr/bin/bash + +set -euxo pipefail + +IRONIC_DEPLOYMENT="${IRONIC_DEPLOYMENT:-}" +IRONIC_EXTERNAL_IP="${IRONIC_EXTERNAL_IP:-}" + +# Define the VLAN interfaces to be included in introspection report, e.g. +# all - all VLANs on all interfaces using LLDP information +# - all VLANs on a particular interface using LLDP information +# - a particular VLAN on an interface, not relying on LLDP +export IRONIC_INSPECTOR_VLAN_INTERFACES=${IRONIC_INSPECTOR_VLAN_INTERFACES:-all} + +# shellcheck disable=SC1091 +. /bin/tls-common.sh +# shellcheck disable=SC1091 +. /bin/ironic-common.sh +# shellcheck disable=SC1091 +. /bin/auth-common.sh + +export HTTP_PORT=${HTTP_PORT:-80} + +MARIADB_PASSWORD=${MARIADB_PASSWORD} +MARIADB_DATABASE=${MARIADB_DATABASE:-ironic} +MARIADB_USER=${MARIADB_USER:-ironic} +MARIADB_HOST=${MARIADB_HOST:-127.0.0.1} +export MARIADB_CONNECTION="mysql+pymysql://${MARIADB_USER}:${MARIADB_PASSWORD}@${MARIADB_HOST}/${MARIADB_DATABASE}?charset=utf8" +if [[ "$MARIADB_TLS_ENABLED" == "true" ]]; then + export MARIADB_CONNECTION="${MARIADB_CONNECTION}&ssl=on&ssl_ca=${MARIADB_CACERT_FILE}" +fi + +# TODO(dtantsur): remove the explicit default once we get +# https://review.opendev.org/761185 in the repositories +NUMPROC="$(grep -c "^processor" /proc/cpuinfo)" +if [[ "$NUMPROC" -lt 4 ]]; then + NUMPROC=4 +fi +export NUMWORKERS=${NUMWORKERS:-$NUMPROC} + +export IRONIC_USE_MARIADB=${IRONIC_USE_MARIADB:-true} +export IRONIC_EXPOSE_JSON_RPC=${IRONIC_EXPOSE_JSON_RPC:-true} + +# Whether to enable fast_track provisioning or not +export IRONIC_FAST_TRACK=${IRONIC_FAST_TRACK:-true} + +# Whether cleaning disks before and after deployment +export IRONIC_AUTOMATED_CLEAN=${IRONIC_AUTOMATED_CLEAN:-true} + +# Wheter to enable the sensor data collection +export SEND_SENSOR_DATA=${SEND_SENSOR_DATA:-false} + +# Set of collectors that should be used with IPA inspection +export IRONIC_IPA_COLLECTORS=${IRONIC_IPA_COLLECTORS:-default,logs} + +wait_for_interface_or_ip + +# Hostname to use for the current conductor instance. +export IRONIC_CONDUCTOR_HOST=${IRONIC_CONDUCTOR_HOST:-${IRONIC_URL_HOST}} + +export IRONIC_BASE_URL=${IRONIC_BASE_URL:-"${IRONIC_SCHEME}://${IRONIC_URL_HOST}:${IRONIC_ACCESS_PORT}"} +export IRONIC_INSPECTOR_BASE_URL=${IRONIC_INSPECTOR_BASE_URL:-"${IRONIC_INSPECTOR_SCHEME}://${IRONIC_URL_HOST}:${IRONIC_INSPECTOR_ACCESS_PORT}"} + +if [[ -n "$IRONIC_EXTERNAL_IP" ]]; then + export IRONIC_EXTERNAL_CALLBACK_URL="${IRONIC_SCHEME}://${IRONIC_EXTERNAL_IP}:${IRONIC_ACCESS_PORT}" + if [[ "$IRONIC_VMEDIA_TLS_SETUP" == "true" ]]; then + export IRONIC_EXTERNAL_HTTP_URL="https://${IRONIC_EXTERNAL_IP}:${VMEDIA_TLS_PORT}" + else + export IRONIC_EXTERNAL_HTTP_URL="http://${IRONIC_EXTERNAL_IP}:${HTTP_PORT}" + fi + export IRONIC_INSPECTOR_CALLBACK_ENDPOINT_OVERRIDE="https://${IRONIC_EXTERNAL_IP}:${IRONIC_INSPECTOR_ACCESS_PORT}" +fi + +IMAGE_CACHE_PREFIX=/shared/html/images/ironic-python-agent +if [[ -f "${IMAGE_CACHE_PREFIX}.kernel" ]] && [[ -f "${IMAGE_CACHE_PREFIX}.initramfs" ]]; then + export IRONIC_DEFAULT_KERNEL="${IMAGE_CACHE_PREFIX}.kernel" + export IRONIC_DEFAULT_RAMDISK="${IMAGE_CACHE_PREFIX}.initramfs" +fi + +if [[ -f /etc/ironic/ironic.conf ]]; then + # Make a copy of the original supposed empty configuration file + cp /etc/ironic/ironic.conf /etc/ironic/ironic.conf_orig +fi + +# oslo.config also supports Config Opts From Environment, log them to stdout +echo 'Options set from Environment variables' +env | grep "^OS_" || true + +mkdir -p /shared/html +mkdir -p /shared/ironic_prometheus_exporter + +configure_json_rpc_auth + +# The original ironic.conf is empty, and can be found in ironic.conf_orig +render_j2_config /etc/ironic/ironic.conf.j2 /etc/ironic/ironic.conf + +if [[ "${USE_IRONIC_INSPECTOR}" == "true" ]]; then + configure_client_basic_auth ironic-inspector +fi +configure_client_basic_auth ironic-rpc + +# Make sure ironic traffic bypasses any proxies +export NO_PROXY="${NO_PROXY:-},$IRONIC_IP" diff --git a/ironic-image/configure-nonroot.sh b/ironic-image/configure-nonroot.sh new file mode 100644 index 0000000..caeec02 --- /dev/null +++ b/ironic-image/configure-nonroot.sh @@ -0,0 +1,50 @@ +#!/usr/bin/bash + +NONROOT_UID=10475 +NONROOT_GID=10475 +USER="ironic-suse" + +groupadd -r -g ${NONROOT_GID} ${USER} +useradd -r -g ${NONROOT_GID} \ + -u ${NONROOT_UID} \ + -d /var/lib/ironic \ + -s /sbin/nologin \ + ${USER} + +# create ironic's http_root directory +mkdir -p /shared/html +chown "${NONROOT_UID}":"${NONROOT_GID}" /shared/html + +# we'll bind mount shared ca and ironic/inspector certificate dirs here +# that need to have correct ownership as the entire ironic in BMO +# deployment shares a single fsGroup in manifest's securityContext +mkdir -p /certs/ca +chown "${NONROOT_UID}":"${NONROOT_GID}" /certs{,/ca} +chmod 2775 /certs{,/ca} + +# apache2 permission changes +chown -R "${NONROOT_UID}":"${NONROOT_GID}" /etc/apache2 +chown -R "${NONROOT_UID}":"${NONROOT_GID}" /run + +# ironic, inspector and httpd related changes +chown -R "${NONROOT_UID}":"${NONROOT_GID}" /etc/ironic /etc/httpd /etc/httpd +chown -R "${NONROOT_UID}":"${NONROOT_GID}" /etc/ironic-inspector +chown -R "${NONROOT_UID}":"${NONROOT_GID}" /var/log +chmod 2775 /etc/ironic /etc/ironic-inspector /etc/httpd/conf /etc/httpd/conf.d +chmod 664 /etc/ironic/* /etc/ironic-inspector/* /etc/httpd/conf/* /etc/httpd/conf.d/* + +chown -R "${NONROOT_UID}":"${NONROOT_GID}" /var/lib/ironic +chown -R "${NONROOT_UID}":"${NONROOT_GID}" /var/lib/ironic-inspector +chmod 2775 /var/lib/ironic /var/lib/ironic-inspector +chmod 664 /var/lib/ironic/ironic.db /var/lib/ironic-inspector/ironic-inspector.db + +# dnsmasq, and the capabilities required to run it as non-root user +chown -R "${NONROOT_UID}":"${NONROOT_GID}" /etc/dnsmasq.conf /var/lib/dnsmasq +chmod 2775 /var/lib/dnsmasq +touch /var/lib/dnsmasq/dnsmasq.leases +chmod 664 /etc/dnsmasq.conf /var/lib/dnsmasq/dnsmasq.leases + +# ca-certificates permission changes +touch /var/lib/ca-certificates/ca-bundle.pem.new +chown -R "${NONROOT_UID}":"${NONROOT_GID}" /var/lib/ca-certificates/ +chmod -R +w /var/lib/ca-certificates/ diff --git a/ironic-image/dnsmasq.conf.j2 b/ironic-image/dnsmasq.conf.j2 new file mode 100644 index 0000000..502de9a --- /dev/null +++ b/ironic-image/dnsmasq.conf.j2 @@ -0,0 +1,79 @@ +interface={{ env.PROVISIONING_INTERFACE }} +bind-dynamic +enable-tftp +tftp-root=/shared/tftpboot +log-queries + +# Configure listening for DNS (0 disables DNS) +port={{ env.DNS_PORT }} + +{%- if env.DHCP_RANGE | length %} +log-dhcp +dhcp-range={{ env.DHCP_RANGE }} + +# It can be used when setting DNS or GW variables. +{%- if env["GATEWAY_IP"] is undefined %} +# Disable default router(s) +dhcp-option=3 +{% else %} +dhcp-option=option{% if ":" in env["GATEWAY_IP"] %}6{% endif %}:router,{{ env["GATEWAY_IP"] }} +{% endif %} +{%- if env["DNS_IP"] is undefined %} +# Disable DNS over provisioning network +dhcp-option=6 +{% else %} +dhcp-option=option{% if ":" in env["DNS_IP"] %}6{% endif %}:dns-server,{{ env["DNS_IP"] }} +{% endif %} + +{%- if env.IPV == "4" or env.IPV is undefined %} +# IPv4 Configuration: +dhcp-match=ipxe,175 +# Client is already running iPXE; move to next stage of chainloading +dhcp-boot=tag:ipxe,http://{{ env.IRONIC_URL_HOST }}:{{ env.HTTP_PORT }}/boot.ipxe + +# Note: Need to test EFI booting +dhcp-match=set:efi,option:client-arch,7 +dhcp-match=set:efi,option:client-arch,9 +dhcp-match=set:efi,option:client-arch,11 +# Client is PXE booting over EFI without iPXE ROM; send EFI version of iPXE chainloader +dhcp-boot=tag:efi,tag:!ipxe,snponly.efi + +# Client is running PXE over BIOS; send BIOS version of iPXE chainloader +dhcp-boot=/undionly.kpxe,{{ env.IRONIC_IP }} +{% endif %} + +{% if env.IPV == "6" %} +# IPv6 Configuration: +enable-ra +ra-param={{ env.PROVISIONING_INTERFACE }},0,0 + +dhcp-vendorclass=set:pxe6,enterprise:343,PXEClient +dhcp-userclass=set:ipxe6,iPXE +dhcp-option=tag:pxe6,option6:bootfile-url,tftp://{{ env.IRONIC_URL_HOST }}/snponly.efi +dhcp-option=tag:ipxe6,option6:bootfile-url,http://{{ env.IRONIC_URL_HOST }}:{{ env.HTTP_PORT }}/boot.ipxe + +# It can be used when setting DNS or GW variables. +{%- if env["GATEWAY_IP"] is undefined %} +# Disable default router(s) +dhcp-option=3 +{% else %} +dhcp-option=3,{{ env["GATEWAY_IP"] }} +{% endif %} +{%- if env["DNS_IP"] is undefined %} +# Disable DNS over provisioning network +dhcp-option=6 +{% else %} +dhcp-option=6,{{ env["DNS_IP"] }} +{% endif %} +{% endif %} +{% endif %} + +{%- if env.DHCP_IGNORE | length %} +dhcp-ignore={{ env.DHCP_IGNORE }} +{% endif %} + +{%- if env.DHCP_HOSTS | length %} +{%- for item in env.DHCP_HOSTS.split(";") %} +dhcp-host={{ item }} +{%- endfor %} +{% endif %} diff --git a/ironic-image/httpd-ironic-api.conf.j2 b/ironic-image/httpd-ironic-api.conf.j2 new file mode 100644 index 0000000..2132c9f --- /dev/null +++ b/ironic-image/httpd-ironic-api.conf.j2 @@ -0,0 +1,85 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +{% if env.LISTEN_ALL_INTERFACES | lower == "true" %} +Listen {{ env.IRONIC_LISTEN_PORT }} + +{% else %} +Listen {{ env.IRONIC_URL_HOST }}:{{ env.IRONIC_LISTEN_PORT }} + +{% endif %} + + {% if env.IRONIC_REVERSE_PROXY_SETUP | lower == "true" %} + + {% if env.IRONIC_PRIVATE_PORT == "unix" %} + ProxyPass "/" "unix:/shared/ironic.sock|http://127.0.0.1/" + ProxyPassReverse "/" "unix:/shared/ironic.sock|http://127.0.0.1/" + {% else %} + ProxyPass "/" "http://127.0.0.1:{{ env.IRONIC_PRIVATE_PORT }}/" + ProxyPassReverse "/" "http://127.0.0.1:{{ env.IRONIC_PRIVATE_PORT }}/" + {% endif %} + + {% else %} + WSGIDaemonProcess ironic user=ironic group=ironic threads=10 display-name=%{GROUP} + WSGIScriptAlias / /usr/bin/ironic-api-wsgi + {% endif %} + + SetEnv APACHE_RUN_USER ironic-suse + SetEnv APACHE_RUN_GROUP ironic-suse + WSGIProcessGroup ironic-suse + + ErrorLog /dev/stderr + LogLevel debug + CustomLog /dev/stdout combined + +{% if env.IRONIC_TLS_SETUP == "true" %} + SSLEngine on + SSLProtocol {{ env.IRONIC_SSL_PROTOCOL }} + SSLCertificateFile {{ env.IRONIC_CERT_FILE }} + SSLCertificateKeyFile {{ env.IRONIC_KEY_FILE }} +{% endif %} + + {% if env.IRONIC_REVERSE_PROXY_SETUP | lower == "true" %} + + {% if "IRONIC_HTPASSWD" in env and env.IRONIC_HTPASSWD | length %} + AuthType Basic + AuthName "Restricted area" + AuthUserFile "/etc/ironic/htpasswd" + Require valid-user + {% endif %} + + {% else %} + + WSGIProcessGroup ironic + WSGIApplicationGroup %{GLOBAL} + AllowOverride None + + {% if "IRONIC_HTPASSWD" in env and env.IRONIC_HTPASSWD | length %} + AuthType Basic + AuthName "Restricted WSGI area" + AuthUserFile "/etc/ironic/htpasswd" + Require valid-user + {% else %} + Require all granted + {% endif %} + + {% endif %} + + + Require all granted + + + + Require all granted + + diff --git a/ironic-image/httpd-modules.conf b/ironic-image/httpd-modules.conf new file mode 100644 index 0000000..c1c5aaa --- /dev/null +++ b/ironic-image/httpd-modules.conf @@ -0,0 +1,21 @@ +# Bare minimum set of modules +LoadModule log_config_module /usr/lib64/apache2/mod_log_config.so +LoadModule mime_module /usr/lib64/apache2/mod_mime.so +LoadModule dir_module /usr/lib64/apache2/mod_dir.so +LoadModule authz_core_module /usr/lib64/apache2/mod_authz_core.so +#LoadModule unixd_module modules/mod_unixd.so +#LoadModule mpm_event_module modules/mod_mpm_event.so +LoadModule wsgi_module /usr/lib64/apache2/mod_wsgi.so +LoadModule ssl_module /usr/lib64/apache2/mod_ssl.so +LoadModule env_module /usr/lib64/apache2/mod_env.so +LoadModule proxy_module /usr/lib64/apache2/mod_proxy.so +LoadModule proxy_ajp_module /usr/lib64/apache2/mod_proxy_ajp.so +LoadModule proxy_balancer_module /usr/lib64/apache2/mod_proxy_balancer.so +LoadModule proxy_http_module /usr/lib64/apache2/mod_proxy_http.so +LoadModule slotmem_shm_module /usr/lib64/apache2/mod_slotmem_shm.so +LoadModule headers_module /usr/lib64/apache2/mod_headers.so +LoadModule authn_core_module /usr/lib64/apache2/mod_authn_core.so +LoadModule auth_basic_module /usr/lib64/apache2/mod_auth_basic.so +LoadModule authn_file_module /usr/lib64/apache2/mod_authn_file.so +LoadModule authz_user_module /usr/lib64/apache2/mod_authz_user.so +LoadModule access_compat_module /usr/lib64/apache2/mod_access_compat.so diff --git a/ironic-image/httpd.conf.j2 b/ironic-image/httpd.conf.j2 new file mode 100644 index 0000000..16f5470 --- /dev/null +++ b/ironic-image/httpd.conf.j2 @@ -0,0 +1,84 @@ +ServerRoot "/etc/httpd" +{%- if env.LISTEN_ALL_INTERFACES | lower == "true" %} +Listen [::]:{{ env.HTTP_PORT }} +{% else %} +Listen {{ env.IRONIC_URL_HOST }}:{{ env.HTTP_PORT }} +{% endif %} +Include conf.modules.d/*.conf +User ironic-suse +Group ironic-suse + + + AllowOverride none + Require all denied + + +DocumentRoot "/shared/html" + + + Options Indexes FollowSymLinks + AllowOverride None + Require all granted + + +{%- if env.HTTPD_SERVE_NODE_IMAGES | lower == "true" %} + + Options Indexes FollowSymLinks + AllowOverride None + Require all granted + +{% endif %} + + + DirectoryIndex index.html + + + + Require all denied + + +ErrorLog "/dev/stderr" + +LogLevel warn + + + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined + LogFormat "%h %l %u %t \"%r\" %>s %b" common + + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio + + CustomLog "/dev/stderr" combined + + + + TypesConfig /etc/mime.types + AddType application/x-compress .Z + AddType application/x-gzip .gz .tgz + AddType text/html .shtml + AddOutputFilter INCLUDES .shtml + + +AddDefaultCharset UTF-8 + + + MIMEMagicFile conf/magic + + +PidFile /var/tmp/httpd.pid + +# EnableSendfile directive could speed up deployments but it could also cause +# issues depending on the underlying file system, to learn more: +# https://httpd.apache.org/docs/current/mod/core.html#enablesendfile +{%- if env.HTTPD_ENABLE_SENDFILE | lower == "true" %} +EnableSendfile on +{% endif %} + +# http TRACE can be subjected to abuse and should be disabled +TraceEnable off + +# provide minimal server information +ServerTokens Prod +ServerSignature Off + +IncludeOptional conf.d/*.conf + diff --git a/ironic-image/inspector-apache.conf.j2 b/ironic-image/inspector-apache.conf.j2 new file mode 100644 index 0000000..b0a9d7f --- /dev/null +++ b/ironic-image/inspector-apache.conf.j2 @@ -0,0 +1,57 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +{% if env.LISTEN_ALL_INTERFACES | lower == "true" %} +Listen {{ env.IRONIC_INSPECTOR_LISTEN_PORT }} + +{% else %} +Listen {{ env.IRONIC_URL_HOST }}:{{ env.IRONIC_INSPECTOR_LISTEN_PORT }} + +{% endif %} + {% if env.IRONIC_INSPECTOR_PRIVATE_PORT == "unix" %} + ProxyPass "/" "unix:/shared/inspector.sock|http://127.0.0.1/" + ProxyPassReverse "/" "unix:/shared/inspector.sock|http://127.0.0.1/" + {% else %} + ProxyPass "/" "http://127.0.0.1:{{ env.IRONIC_INSPECTOR_PRIVATE_PORT }}/" + ProxyPassReverse "/" "http://127.0.0.1:{{ env.IRONIC_INSPECTOR_PRIVATE_PORT }}/" + {% endif %} + + SetEnv APACHE_RUN_USER ironic-suse + SetEnv APACHE_RUN_GROUP ironic-suse + + ErrorLog /dev/stdout + LogLevel debug + CustomLog /dev/stdout combined + + SSLEngine On + SSLProtocol {{ env.IRONIC_SSL_PROTOCOL }} + SSLCertificateFile {{ env.IRONIC_INSPECTOR_CERT_FILE }} + SSLCertificateKeyFile {{ env.IRONIC_INSPECTOR_KEY_FILE }} + + {% if "INSPECTOR_HTPASSWD" in env and env.INSPECTOR_HTPASSWD | length %} + + AuthType Basic + AuthName "Restricted area" + AuthUserFile "/etc/ironic-inspector/htpasswd" + Require valid-user + + + + Require all granted + + + + Require all granted + + {% endif %} + diff --git a/ironic-image/inspector.ipxe.j2 b/ironic-image/inspector.ipxe.j2 new file mode 100644 index 0000000..93f8c75 --- /dev/null +++ b/ironic-image/inspector.ipxe.j2 @@ -0,0 +1,10 @@ +#!ipxe + +:retry_boot +echo In inspector.ipxe +imgfree +# NOTE(dtantsur): keep inspection kernel params in [mdns]params in +# ironic-inspector-image and configuration in configure-ironic.sh +kernel --timeout 60000 http://{{ env.IRONIC_IP }}:{{ env.HTTP_PORT }}/images/ironic-python-agent.kernel ipa-insecure=1 ipa-inspection-collectors={{ env.IRONIC_IPA_COLLECTORS }} systemd.journald.forward_to_console=yes BOOTIF=${mac} ipa-debug=1 ipa-enable-vlan-interfaces={{ env.IRONIC_INSPECTOR_VLAN_INTERFACES }} ipa-inspection-dhcp-all-interfaces=1 ipa-collect-lldp=1 {{ env.INSPECTOR_EXTRA_ARGS }} initrd=ironic-python-agent.initramfs {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} || goto retry_boot +initrd --timeout 60000 http://{{ env.IRONIC_IP }}:{{ env.HTTP_PORT }}/images/ironic-python-agent.initramfs || goto retry_boot +boot diff --git a/ironic-image/ironic-common.sh b/ironic-image/ironic-common.sh new file mode 100644 index 0000000..f388c6b --- /dev/null +++ b/ironic-image/ironic-common.sh @@ -0,0 +1,110 @@ +#!/usr/bin/bash + +set -euxo pipefail + +IRONIC_IP="${IRONIC_IP:-}" +PROVISIONING_INTERFACE="${PROVISIONING_INTERFACE:-}" +PROVISIONING_IP="${PROVISIONING_IP:-}" +PROVISIONING_MACS="${PROVISIONING_MACS:-}" + +get_provisioning_interface() +{ + if [[ -n "$PROVISIONING_INTERFACE" ]]; then + # don't override the PROVISIONING_INTERFACE if one is provided + echo "$PROVISIONING_INTERFACE" + return + fi + + local interface="provisioning" + + if [[ -n "${PROVISIONING_IP}" ]]; then + if ip -br addr show | grep -qi " ${PROVISIONING_IP}/"; then + interface="$(ip -br addr show | grep -i " ${PROVISIONING_IP}/" | cut -f 1 -d ' ' | cut -f 1 -d '@')" + fi + fi + + for mac in ${PROVISIONING_MACS//,/ }; do + if ip -br link show up | grep -qi "$mac"; then + interface="$(ip -br link show up | grep -i "$mac" | cut -f 1 -d ' ' | cut -f 1 -d '@')" + break + fi + done + + echo "$interface" +} + +PROVISIONING_INTERFACE="$(get_provisioning_interface)" +export PROVISIONING_INTERFACE + +export LISTEN_ALL_INTERFACES="${LISTEN_ALL_INTERFACES:-true}" + +# Wait for the interface or IP to be up, sets $IRONIC_IP +wait_for_interface_or_ip() +{ + # If $PROVISIONING_IP is specified, then we wait for that to become available on an interface, otherwise we look at $PROVISIONING_INTERFACE for an IP + if [[ -n "$PROVISIONING_IP" ]]; then + # Convert the address using ipcalc which strips out the subnet. For IPv6 addresses, this will give the short-form address + IRONIC_IP="$(ipcalc "${PROVISIONING_IP}" | grep "^Address:" | awk '{print $2}')" + export IRONIC_IP + until grep -F " ${IRONIC_IP}/" <(ip -br addr show); do + echo "Waiting for ${IRONIC_IP} to be configured on an interface" + sleep 1 + done + else + until [[ -n "$IRONIC_IP" ]]; do + echo "Waiting for ${PROVISIONING_INTERFACE} interface to be configured" + IRONIC_IP="$(ip -br add show scope global up dev "${PROVISIONING_INTERFACE}" | awk '{print $3}' | sed -e 's%/.*%%' | head -n 1)" + export IRONIC_IP + sleep 1 + done + fi + + # If the IP contains a colon, then it's an IPv6 address, and the HTTP + # host needs surrounding with brackets + if [[ "$IRONIC_IP" =~ .*:.* ]]; then + export IPV=6 + export IRONIC_URL_HOST="[$IRONIC_IP]" + else + export IPV=4 + export IRONIC_URL_HOST="$IRONIC_IP" + fi +} + +render_j2_config() +{ + python3 -c 'import os; import sys; import jinja2; sys.stdout.write(jinja2.Template(sys.stdin.read()).render(env=os.environ))' < "$1" > "$2" +} + +run_ironic_dbsync() +{ + if [[ "${IRONIC_USE_MARIADB:-true}" == "true" ]]; then + # It's possible for the dbsync to fail if mariadb is not up yet, so + # retry until success + until ironic-dbsync --config-file /etc/ironic/ironic.conf upgrade; do + echo "WARNING: ironic-dbsync failed, retrying" + sleep 1 + done + else + # SQLite does not support some statements. Fortunately, we can just create + # the schema in one go instead of going through an upgrade. + ironic-dbsync --config-file /etc/ironic/ironic.conf create_schema + fi +} + +# Use the special value "unix" for unix sockets +export IRONIC_PRIVATE_PORT=${IRONIC_PRIVATE_PORT:-6388} +export IRONIC_INSPECTOR_PRIVATE_PORT=${IRONIC_INSPECTOR_PRIVATE_PORT:-5049} + +export IRONIC_ACCESS_PORT=${IRONIC_ACCESS_PORT:-6385} +export IRONIC_LISTEN_PORT=${IRONIC_LISTEN_PORT:-$IRONIC_ACCESS_PORT} + +export IRONIC_INSPECTOR_ACCESS_PORT=${IRONIC_INSPECTOR_ACCESS_PORT:-5050} +export IRONIC_INSPECTOR_LISTEN_PORT=${IRONIC_INSPECTOR_LISTEN_PORT:-$IRONIC_INSPECTOR_ACCESS_PORT} + +# If this is false, built-in inspection is used. +export USE_IRONIC_INSPECTOR=${USE_IRONIC_INSPECTOR:-true} +export IRONIC_INSPECTOR_ENABLE_DISCOVERY=${IRONIC_INSPECTOR_ENABLE_DISCOVERY:-false} +if [[ "${USE_IRONIC_INSPECTOR}" != "true" ]] && [[ "${IRONIC_INSPECTOR_ENABLE_DISCOVERY}" == "true" ]]; then + echo "Discovery is only supported with ironic-inspector at this point" + exit 1 +fi diff --git a/ironic-image/ironic-inspector.conf.j2 b/ironic-image/ironic-inspector.conf.j2 new file mode 100644 index 0000000..9932980 --- /dev/null +++ b/ironic-image/ironic-inspector.conf.j2 @@ -0,0 +1,68 @@ +[DEFAULT] +auth_strategy = noauth +debug = true +transport_url = fake:// +use_stderr = true +{% if env.INSPECTOR_REVERSE_PROXY_SETUP == "true" %} +{% if env.IRONIC_INSPECTOR_PRIVATE_PORT == "unix" %} +listen_unix_socket = /shared/inspector.sock +# NOTE(dtantsur): this is not ideal, but since the socket is accessed from +# another container, we need to make it world-writeable. +listen_unix_socket_mode = 0666 +{% else %} +listen_port = {{ env.IRONIC_INSPECTOR_PRIVATE_PORT }} +listen_address = 127.0.0.1 +{% endif %} +{% elif env.LISTEN_ALL_INTERFACES | lower == "true" %} +listen_port = {{ env.IRONIC_INSPECTOR_LISTEN_PORT }} +listen_address = :: +{% else %} +listen_port = {{ env.IRONIC_INSPECTOR_LISTEN_PORT }} +listen_address = {{ env.IRONIC_IP }} +{% endif %} +host = {{ env.IRONIC_IP }} +{% if env.IRONIC_INSPECTOR_TLS_SETUP == "true" and env.INSPECTOR_REVERSE_PROXY_SETUP == "false" %} +use_ssl = true +{% endif %} + +[database] +connection = sqlite:////var/lib/ironic-inspector/ironic-inspector.db + +{% if env.IRONIC_INSPECTOR_ENABLE_DISCOVERY == "true" %} +[discovery] +enroll_node_driver = ipmi +{% endif %} + +[ironic] +auth_type = none +endpoint_override = {{ env.IRONIC_BASE_URL }} +{% if env.IRONIC_TLS_SETUP == "true" %} +cafile = {{ env.IRONIC_CACERT_FILE }} +insecure = {{ env.IRONIC_INSECURE }} +{% endif %} + +[processing] +add_ports = all +always_store_ramdisk_logs = true +keep_ports = present +{% if env.IRONIC_INSPECTOR_ENABLE_DISCOVERY == "true" %} +node_not_found_hook = enroll +{% endif %} +permit_active_introspection = true +power_off = false +processing_hooks = $default_processing_hooks,lldp_basic +ramdisk_logs_dir = /shared/log/ironic-inspector/ramdisk +store_data = database + +[pxe_filter] +driver = noop + +[service_catalog] +auth_type = none +endpoint_override = {{ env.IRONIC_INSPECTOR_BASE_URL }} + +{% if env.IRONIC_INSPECTOR_TLS_SETUP == "true" and env.INSPECTOR_REVERSE_PROXY_SETUP == "false" %} +[ssl] +cert_file = {{ env.IRONIC_INSPECTOR_CERT_FILE }} +key_file = {{ env.IRONIC_INSPECTOR_KEY_FILE }} +{% endif %} diff --git a/ironic-image/ironic.conf.j2 b/ironic-image/ironic.conf.j2 new file mode 100644 index 0000000..5bce6d2 --- /dev/null +++ b/ironic-image/ironic.conf.j2 @@ -0,0 +1,253 @@ +[DEFAULT] +{% if env.AUTH_STRATEGY is defined %} +auth_strategy = {{ env.AUTH_STRATEGY }} +{% if env.AUTH_STRATEGY == "http_basic" %} +http_basic_auth_user_file=/etc/ironic/htpasswd +{% endif %} +{% else %} +auth_strategy = noauth +{% endif %} +debug = true +default_deploy_interface = direct +default_inspect_interface = {% if env.USE_IRONIC_INSPECTOR == "true" %}inspector{% else %}agent{% endif %} +default_network_interface = noop +enabled_bios_interfaces = idrac-wsman,no-bios,redfish,idrac-redfish,irmc,ilo +enabled_boot_interfaces = ipxe,ilo-ipxe,pxe,ilo-pxe,fake,redfish-virtual-media,idrac-redfish-virtual-media,ilo-virtual-media +enabled_deploy_interfaces = direct,fake,ramdisk,custom-agent +# NOTE(dtantsur): when changing this, make sure to update the driver +# dependencies in Dockerfile. +enabled_hardware_types = ipmi,idrac,irmc,fake-hardware,redfish,manual-management,ilo,ilo5 +enabled_inspect_interfaces = {% if env.USE_IRONIC_INSPECTOR == "true" %}inspector{% else %}agent{% endif %},idrac-wsman,irmc,fake,redfish,ilo +enabled_management_interfaces = ipmitool,idrac-wsman,irmc,fake,redfish,idrac-redfish,ilo,ilo5,noop +enabled_power_interfaces = ipmitool,idrac-wsman,irmc,fake,redfish,idrac-redfish,ilo +enabled_raid_interfaces = no-raid,irmc,agent,fake,idrac-wsman,redfish,idrac-redfish,ilo5 +enabled_vendor_interfaces = no-vendor,ipmitool,idrac-wsman,idrac-redfish,redfish,ilo,fake +enabled_firmware_interfaces = no-firmware,fake,redfish +{% if env.IRONIC_EXPOSE_JSON_RPC | lower == "true" %} +rpc_transport = json-rpc +{% else %} +rpc_transport = none +{% endif %} +use_stderr = true +# NOTE(dtantsur): the default md5 is not compatible with FIPS mode +hash_ring_algorithm = sha256 +my_ip = {{ env.IRONIC_IP }} +{% if env.IRONIC_DEPLOYMENT == "Conductor" and env.JSON_RPC_AUTH_STRATEGY == "noauth" %} +# if access is unauthenticated, we bind only to localhost - use that as the +# host name also, so that the client can find the server +# If we run both API and conductor in the same pod, use localhost +host = localhost +{% else %} +host = {{ env.IRONIC_CONDUCTOR_HOST }} +{% endif %} + +# If a path to a certificate is defined, use that first for webserver +{% if env.WEBSERVER_CACERT_FILE %} +webserver_verify_ca = {{ env.WEBSERVER_CACERT_FILE }} +{% elif env.IRONIC_INSECURE == "true" %} +webserver_verify_ca = false +{% endif %} + +isolinux_bin = /usr/share/syslinux/isolinux.bin + +# NOTE(dtantsur): this path is specific to the GRUB image that is built into +# the ESP provided in [conductor]bootloader. +grub_config_path = EFI/BOOT/grub.cfg + +[agent] +deploy_logs_collect = always +deploy_logs_local_path = /shared/log/ironic/deploy +# NOTE(dtantsur): in some environments temporary networking issues can cause +# the whole deployment to fail on inability to reach the ramdisk. Increasing +# retries here works around such problems without affecting the normal path. +# See https://bugzilla.redhat.com/show_bug.cgi?id=1822763 +max_command_attempts = 30 + +[api] +{% if env.IRONIC_REVERSE_PROXY_SETUP == "true" %} +{% if env.IRONIC_PRIVATE_PORT == "unix" %} +unix_socket = /shared/ironic.sock +# NOTE(dtantsur): this is not ideal, but since the socket is accessed from +# another container, we need to make it world-writeable. +unix_socket_mode = 0666 +{% else %} +host_ip = 127.0.0.1 +port = {{ env.IRONIC_PRIVATE_PORT }} +{% endif %} +public_endpoint = {{ env.IRONIC_BASE_URL }} +{% else %} +host_ip = {% if env.LISTEN_ALL_INTERFACES | lower == "true" %}::{% else %}{{ env.IRONIC_IP }}{% endif %} +port = {{ env.IRONIC_LISTEN_PORT }} +{% if env.IRONIC_TLS_SETUP == "true" %} +enable_ssl_api = true +{% endif %} +{% endif %} +api_workers = {{ env.NUMWORKERS }} + +# Disable schema validation so we can pass nmstate format +network_data_schema = /etc/ironic/network-data-schema-empty.json + +[conductor] +automated_clean = {{ env.IRONIC_AUTOMATED_CLEAN }} +# NOTE(dtantsur): keep aligned with [pxe]boot_retry_timeout below. +deploy_callback_timeout = 4800 +send_sensor_data = {{ env.SEND_SENSOR_DATA }} +# NOTE(TheJulia): Do not lower this value below 120 seconds. +# Power state is checked every 60 seconds and BMC activity should +# be avoided more often than once every sixty seconds. +send_sensor_data_interval = 160 +bootloader = {{ env.IRONIC_BOOT_BASE_URL }}/uefi_esp.img +verify_step_priority_override = management.clear_job_queue:90 +# We don't use this feature, and it creates an additional load on the database +node_history = False +# Provide for a timeout longer than 60 seconds for certain vendor's hardware +power_state_change_timeout = 120 +{% if env.IRONIC_DEFAULT_KERNEL is defined %} +deploy_kernel = file://{{ env.IRONIC_DEFAULT_KERNEL }} +{% endif %} +{% if env.IRONIC_DEFAULT_RAMDISK is defined %} +deploy_ramdisk = file://{{ env.IRONIC_DEFAULT_RAMDISK }} +{% endif %} + +[database] +{% if env.IRONIC_USE_MARIADB | lower == "false" %} +connection = sqlite:////var/lib/ironic/ironic.sqlite +# Synchronous mode is required for data integrity in case of operating system +# crash. In our case we restart the container from scratch, so we can save some +# IO by not doing syncs all the time. +sqlite_synchronous = False +{% else %} +connection = {{ env.MARIADB_CONNECTION }} +{% endif %} + +[deploy] +default_boot_option = local +erase_devices_metadata_priority = 10 +erase_devices_priority = 0 +http_root = /shared/html/ +http_url = {{ env.IRONIC_BOOT_BASE_URL }} +fast_track = {{ env.IRONIC_FAST_TRACK }} +{% if env.IRONIC_BOOT_ISO_SOURCE %} +ramdisk_image_download_source = {{ env.IRONIC_BOOT_ISO_SOURCE }} +{% endif %} +{% if env.IRONIC_EXTERNAL_HTTP_URL %} +external_http_url = {{ env.IRONIC_EXTERNAL_HTTP_URL }} +{% elif env.IRONIC_VMEDIA_TLS_SETUP == "true" %} +external_http_url = https://{{ env.IRONIC_URL_HOST }}:{{ env.VMEDIA_TLS_PORT }} +{% endif %} +{% if env.IRONIC_EXTERNAL_CALLBACK_URL %} +external_callback_url = {{ env.IRONIC_EXTERNAL_CALLBACK_URL }} +{% endif %} + +[dhcp] +dhcp_provider = none + +[inspector] +power_off = {{ false if env.IRONIC_FAST_TRACK == "true" else true }} +# NOTE(dtantsur): keep inspection arguments synchronized with inspector.ipxe +# Also keep in mind that only parameters unique for inspection go here. +# No need to duplicate pxe_append_params/kernel_append_params. +extra_kernel_params = ipa-inspection-collectors={{ env.IRONIC_IPA_COLLECTORS }} ipa-enable-vlan-interfaces={{ env.IRONIC_INSPECTOR_VLAN_INTERFACES }} ipa-inspection-dhcp-all-interfaces=1 ipa-collect-lldp=1 net.ifnames={{ '0' if env.PREDICTABLE_NIC_NAMES == 'false' else '1' }} + +{% if env.USE_IRONIC_INSPECTOR == "true" %} +endpoint_override = {{ env.IRONIC_INSPECTOR_BASE_URL }} +{% if env.IRONIC_INSPECTOR_TLS_SETUP == "true" %} +cafile = {{ env.IRONIC_INSPECTOR_CACERT_FILE }} +insecure = {{ env.IRONIC_INSPECTOR_INSECURE }} +{% endif %} +{% if env.IRONIC_INSPECTOR_CALLBACK_ENDPOINT_OVERRIDE %} +callback_endpoint_override = {{ env.IRONIC_INSPECTOR_CALLBACK_ENDPOINT_OVERRIDE }} +{% endif %} +{% else %} +hooks = $default_hooks,parse-lldp +add_ports = all +keep_ports = present +{% endif %} + +[ipmi] +# use_ipmitool_retries transfers the responsibility of retrying to ipmitool +# when supported. If set to false, then ipmitool is called as follows : +# $ipmitool -R 1 -N 1 ... +# and Ironic handles the retry loop. +use_ipmitool_retries = false +# The following parameters are the defaults in Ironic. They are used in the +# following way if use_ipmitool_retries is set to true: +# $ipmitool -R -N ... +# where : +# X = command_retry_timeout / min_command_interval +# Y = min_command_interval +# If use_ipmitool_retries is false, then ironic retries X times, with an +# interval of Y in between each tries. +min_command_interval = 5 +command_retry_timeout = 60 +# List of possible cipher suites versions that can be +# supported by the hardware in case the field `cipher_suite` +# is not set for the node. (list value) +cipher_suite_versions = 3,17 + +{% if env.IRONIC_EXPOSE_JSON_RPC | lower == "true" %} +[json_rpc] +# We assume that when we run API and conductor in the same container, they use +# authentication over localhost, using the same credentials as API, to prevent +# unauthenticated connections from other processes in the same host since the +# containers are in host networking. +auth_strategy = {{ env.JSON_RPC_AUTH_STRATEGY }} +http_basic_auth_user_file = /etc/ironic/htpasswd-rpc +{% if env.IRONIC_DEPLOYMENT == "Conductor" and env.JSON_RPC_AUTH_STRATEGY == "noauth" %} +# if access is unauthenticated, we bind only to localhost - use that as the +# host name also, so that the client can find the server +host_ip = localhost +{% else %} +host_ip = {% if env.LISTEN_ALL_INTERFACES | lower == "true" %}::{% else %}{{ env.IRONIC_IP }}{% endif %} +{% endif %} +{% if env.IRONIC_TLS_SETUP == "true" %} +use_ssl = true +cafile = {{ env.IRONIC_CACERT_FILE }} +insecure = {{ env.IRONIC_INSECURE }} +{% endif %} +{% endif %} + +[nova] +send_power_notifications = false + +[oslo_messaging_notifications] +driver = prometheus_exporter +location = /shared/ironic_prometheus_exporter +transport_url = fake:// + +[pxe] +# NOTE(dtantsur): keep this value at least 3x lower than +# [conductor]deploy_callback_timeout so that at least some retries happen. +# The default settings enable 3 retries after 20 minutes each. +boot_retry_timeout = 1200 +images_path = /shared/html/tmp +instance_master_path = /shared/html/master_images +tftp_master_path = /shared/tftpboot/master_images +tftp_root = /shared/tftpboot +kernel_append_params = nofb nomodeset vga=normal ipa-insecure={{ env.IPA_INSECURE }} {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} systemd.journald.forward_to_console=yes +# This makes networking boot templates generated even for nodes using local +# boot (the default), ensuring that they boot correctly even if they start +# netbooting for some reason (e.g. with the noop management interface). +enable_netboot_fallback = true +# Enable the fallback path to in-band inspection +ipxe_fallback_script = inspector.ipxe + +[redfish] +use_swift = false +kernel_append_params = nofb nomodeset vga=normal ipa-insecure={{ env.IPA_INSECURE }} {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} systemd.journald.forward_to_console=yes + +[ilo] +kernel_append_params = nofb nomodeset vga=normal ipa-insecure={{ env.IPA_INSECURE }} {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} systemd.journald.forward_to_console=yes +use_web_server_for_images = true + +[irmc] +kernel_append_params = nofb nomodeset vga=normal ipa-insecure={{ env.IPA_INSECURE }} {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} systemd.journald.forward_to_console=yes + +[service_catalog] +endpoint_override = {{ env.IRONIC_BASE_URL }} + +{% if env.IRONIC_TLS_SETUP == "true" %} +[ssl] +cert_file = {{ env.IRONIC_CERT_FILE }} +key_file = {{ env.IRONIC_KEY_FILE }} +{% endif %} diff --git a/ironic-image/mkisofs_wrapper b/ironic-image/mkisofs_wrapper new file mode 100644 index 0000000..d1d1a3c --- /dev/null +++ b/ironic-image/mkisofs_wrapper @@ -0,0 +1,3 @@ +#!/bin/sh + +xorriso -as mkisofs "${@}" \ No newline at end of file diff --git a/ironic-image/network-data-schema-empty.json b/ironic-image/network-data-schema-empty.json new file mode 100644 index 0000000..d31a3bc --- /dev/null +++ b/ironic-image/network-data-schema-empty.json @@ -0,0 +1 @@ +{} diff --git a/ironic-image/prepare-efi.sh b/ironic-image/prepare-efi.sh new file mode 100644 index 0000000..84e0808 --- /dev/null +++ b/ironic-image/prepare-efi.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +set -euxo pipefail + +ARCH=$(uname -m) +DEST=${2:-/tmp/esp.img} +OS=${1:-sles} + +BOOTEFI=BOOTX64.efi +GRUBEFI=grubx64.efi + +dd bs=1024 count=6400 if=/dev/zero of=$DEST +mkfs.msdos -F 12 -n 'ESP_IMAGE' $DEST + +mkdir -p /boot/efi/EFI/BOOT +cp -L /usr/lib64/efi/shim.efi /boot/efi/EFI/BOOT/$BOOTEFI +mkdir -p /boot/efi/EFI/$OS +#cp /usr/share/grub2/x86_64-efi/grub.efi /boot/efi/EFI/$OS/$GRUBEFI +cp /usr/share/grub2/x86_64-efi/grub.efi /boot/efi/EFI/$OS/grub.efi + +mmd -i $DEST EFI +mmd -i $DEST EFI/BOOT +mcopy -i $DEST -v /boot/efi/EFI/BOOT/$BOOTEFI ::EFI/BOOT +#mcopy -i $DEST -v /boot/efi/EFI/$OS/$GRUBEFI ::EFI/BOOT +mcopy -i $DEST -v /boot/efi/EFI/$OS/grub.efi ::EFI/BOOT +mdir -i $DEST ::EFI/BOOT; + diff --git a/ironic-image/rundnsmasq b/ironic-image/rundnsmasq new file mode 100644 index 0000000..92af2eb --- /dev/null +++ b/ironic-image/rundnsmasq @@ -0,0 +1,35 @@ +#!/usr/bin/bash + +set -eux + +# shellcheck disable=SC1091 +. /bin/ironic-common.sh + +export HTTP_PORT=${HTTP_PORT:-80} +DNSMASQ_EXCEPT_INTERFACE=${DNSMASQ_EXCEPT_INTERFACE:-lo} +export DNS_PORT=${DNS_PORT:-0} + +wait_for_interface_or_ip +if [[ "${DNS_IP:-}" == "provisioning" ]]; then + export DNS_IP="$IRONIC_URL_HOST" +fi + +mkdir -p /shared/tftpboot +mkdir -p /shared/html/images +mkdir -p /shared/html/pxelinux.cfg + +# Copy files to shared mount +cp /tftpboot/undionly.kpxe /tftpboot/snponly.efi /shared/tftpboot + +# Template and write dnsmasq.conf +# we template via /tmp as sed otherwise creates temp files in /etc directory +# where we can't write +python3 -c 'import os; import sys; import jinja2; sys.stdout.write(jinja2.Template(sys.stdin.read()).render(env=os.environ))' /tmp/dnsmasq.conf + +for iface in $(echo "$DNSMASQ_EXCEPT_INTERFACE" | tr ',' ' '); do + sed -i -e "/^interface=.*/ a\except-interface=${iface}" /tmp/dnsmasq.conf +done +cat /tmp/dnsmasq.conf > /etc/dnsmasq.conf +rm /tmp/dnsmasq.conf + +exec /usr/sbin/dnsmasq -d -q -C /etc/dnsmasq.conf diff --git a/ironic-image/runhttpd b/ironic-image/runhttpd new file mode 100644 index 0000000..57e7c97 --- /dev/null +++ b/ironic-image/runhttpd @@ -0,0 +1,101 @@ +#!/usr/bin/bash + +# shellcheck disable=SC1091 +. /bin/tls-common.sh +. /bin/ironic-common.sh +. /bin/auth-common.sh + +export HTTP_PORT=${HTTP_PORT:-80} +export VMEDIA_TLS_PORT=${VMEDIA_TLS_PORT:-8083} + +INSPECTOR_ORIG_HTTPD_CONFIG=/etc/httpd/conf.d/inspector-apache.conf.j2 +INSPECTOR_RESULT_HTTPD_CONFIG=/etc/httpd/conf.d/ironic-inspector.conf +export IRONIC_REVERSE_PROXY_SETUP=${IRONIC_REVERSE_PROXY_SETUP:-false} +export INSPECTOR_REVERSE_PROXY_SETUP=${INSPECTOR_REVERSE_PROXY_SETUP:-false} + +# In Metal3 context they are called node images in Ironic context they are +# called user images. +export HTTPD_SERVE_NODE_IMAGES="${HTTPD_SERVE_NODE_IMAGES:-true}" + +# Whether to enable fast_track provisioning or not +IRONIC_FAST_TRACK=${IRONIC_FAST_TRACK:-true} + +# Whether to activate the EnableSendfile apache directive for httpd +HTTPD_ENABLE_SENDFILE="${HTTPD_ENABLE_SENDFILE:-false}" + +# Set of collectors that should be used with IPA inspection +export IRONIC_IPA_COLLECTORS=${IRONIC_IPA_COLLECTORS:-default,logs} + +wait_for_interface_or_ip + +mkdir -p /shared/html +chmod 0777 /shared/html + +IRONIC_BASE_URL="${IRONIC_SCHEME}://${IRONIC_URL_HOST}" + +if [[ "${USE_IRONIC_INSPECTOR}" == "true" ]]; then + INSPECTOR_EXTRA_ARGS=" ipa-inspection-callback-url=${IRONIC_BASE_URL}:${IRONIC_INSPECTOR_ACCESS_PORT}/v1/continue" +else + INSPECTOR_EXTRA_ARGS=" ipa-inspection-callback-url=${IRONIC_BASE_URL}:${IRONIC_ACCESS_PORT}/v1/continue_inspection" +fi + +if [[ "$IRONIC_FAST_TRACK" == "true" ]]; then + INSPECTOR_EXTRA_ARGS+=" ipa-api-url=${IRONIC_BASE_URL}:${IRONIC_ACCESS_PORT}" +fi +export INSPECTOR_EXTRA_ARGS + +# Copy files to shared mount +render_j2_config /tmp/inspector.ipxe.j2 /shared/html/inspector.ipxe +cp /tmp/uefi_esp.img /shared/html/uefi_esp.img + +# Render the core httpd config +render_j2_config /etc/httpd/conf/httpd.conf.j2 /etc/httpd/conf/httpd.conf + +if [[ "$USE_IRONIC_INSPECTOR" == "true" ]] && [[ "$IRONIC_INSPECTOR_TLS_SETUP" == "true" ]]; then + if [[ "${INSPECTOR_REVERSE_PROXY_SETUP}" == "true" ]]; then + render_j2_config "$INSPECTOR_ORIG_HTTPD_CONFIG" "$INSPECTOR_RESULT_HTTPD_CONFIG" + fi +else + export INSPECTOR_REVERSE_PROXY_SETUP="false" # If TLS is not used, we have no reason to use the reverse proxy +fi + +if [[ "$IRONIC_TLS_SETUP" == "true" ]]; then + if [[ "${IRONIC_REVERSE_PROXY_SETUP}" == "true" ]]; then + render_j2_config /tmp/httpd-ironic-api.conf.j2 /etc/httpd/conf.d/ironic.conf + fi +else + export IRONIC_REVERSE_PROXY_SETUP="false" # If TLS is not used, we have no reason to use the reverse proxy +fi + +write_htpasswd_files + +# Render httpd TLS configuration for /shared/html/ +if [[ "$IRONIC_VMEDIA_TLS_SETUP" == "true" ]]; then + render_j2_config /etc/httpd-vmedia.conf.j2 /etc/httpd/conf.d/vmedia.conf +fi + +# Set up inotify to kill the container (restart) whenever cert files for ironic inspector change +if [[ "$IRONIC_INSPECTOR_TLS_SETUP" == "true" ]] && [[ "${RESTART_CONTAINER_CERTIFICATE_UPDATED}" == "true" ]]; then + # shellcheck disable=SC2034 + inotifywait -m -e delete_self "${IRONIC_INSPECTOR_CERT_FILE}" | while read -r file event; do + kill -WINCH $(pgrep httpd) + done & +fi + +# Set up inotify to kill the container (restart) whenever cert files for ironic api change +if [[ "$IRONIC_TLS_SETUP" == "true" ]] && [[ "${RESTART_CONTAINER_CERTIFICATE_UPDATED}" == "true" ]]; then + # shellcheck disable=SC2034 + inotifywait -m -e delete_self "${IRONIC_CERT_FILE}" | while read -r file event; do + kill -WINCH $(pgrep httpd) + done & +fi + +# Set up inotify to kill the container (restart) whenever cert of httpd for /shared/html/ path change +if [[ "$IRONIC_VMEDIA_TLS_SETUP" == "true" ]] && [[ "${RESTART_CONTAINER_CERTIFICATE_UPDATED}" == "true" ]]; then + # shellcheck disable=SC2034 + inotifywait -m -e delete_self "${IRONIC_VMEDIA_CERT_FILE}" | while read -r file event; do + kill -WINCH $(pgrep httpd) + done & +fi + +exec /usr/sbin/httpd -DFOREGROUND -f /etc/httpd/conf/httpd.conf diff --git a/ironic-image/runironic b/ironic-image/runironic new file mode 100644 index 0000000..5dd6ef2 --- /dev/null +++ b/ironic-image/runironic @@ -0,0 +1,25 @@ +#!/usr/bin/bash + +# These settings must go before configure-ironic since it has different +# defaults. +export IRONIC_USE_MARIADB=${IRONIC_USE_MARIADB:-false} +export IRONIC_EXPOSE_JSON_RPC=${IRONIC_EXPOSE_JSON_RPC:-false} + +# shellcheck disable=SC1091 +. /bin/configure-ironic.sh + +# Ramdisk logs +mkdir -p /shared/log/ironic/deploy + +run_ironic_dbsync + +if [[ "$IRONIC_TLS_SETUP" == "true" ]] && [[ "${RESTART_CONTAINER_CERTIFICATE_UPDATED}" == "true" ]]; then + # shellcheck disable=SC2034 + inotifywait -m -e delete_self "${IRONIC_CERT_FILE}" | while read -r file event; do + kill $(pgrep ironic) + done & +fi + +configure_ironic_auth + +exec /usr/bin/ironic diff --git a/ironic-image/runironic-api b/ironic-image/runironic-api new file mode 100644 index 0000000..9deb9ac --- /dev/null +++ b/ironic-image/runironic-api @@ -0,0 +1,13 @@ +#!/usr/bin/bash + +export IRONIC_DEPLOYMENT="API" + +# shellcheck disable=SC1091 +. /bin/configure-ironic.sh + +export IRONIC_REVERSE_PROXY_SETUP=false + +python3 -c 'import os; import sys; import jinja2; sys.stdout.write(jinja2.Template(sys.stdin.read()).render(env=os.environ))' < /tmp/httpd-ironic-api.conf.j2 > /etc/httpd/conf.d/ironic.conf + +# shellcheck disable=SC1091 +. /bin/runhttpd diff --git a/ironic-image/runironic-conductor b/ironic-image/runironic-conductor new file mode 100644 index 0000000..64b2c82 --- /dev/null +++ b/ironic-image/runironic-conductor @@ -0,0 +1,20 @@ +#!/usr/bin/bash + +export IRONIC_DEPLOYMENT="Conductor" + +# shellcheck disable=SC1091 +. /bin/configure-ironic.sh + +# Ramdisk logs +mkdir -p /shared/log/ironic/deploy + +run_ironic_dbsync + +if [[ "$IRONIC_TLS_SETUP" == "true" ]] && [[ "${RESTART_CONTAINER_CERTIFICATE_UPDATED}" == "true" ]]; then + # shellcheck disable=SC2034 + inotifywait -m -e delete_self "${IRONIC_CERT_FILE}" | while read -r file event; do + kill $(pgrep ironic) + done & +fi + +exec /usr/bin/ironic-conductor diff --git a/ironic-image/runironic-exporter b/ironic-image/runironic-exporter new file mode 100644 index 0000000..f2f60f2 --- /dev/null +++ b/ironic-image/runironic-exporter @@ -0,0 +1,12 @@ +#!/usr/bin/bash + +# shellcheck disable=SC1091 +. /bin/configure-ironic.sh + +FLASK_RUN_HOST=${FLASK_RUN_HOST:-0.0.0.0} +FLASK_RUN_PORT=${FLASK_RUN_PORT:-9608} + +export IRONIC_CONFIG="/etc/ironic/ironic.conf" + +exec gunicorn -b "${FLASK_RUN_HOST}:${FLASK_RUN_PORT}" -w 4 \ + ironic_prometheus_exporter.app.wsgi:application diff --git a/ironic-image/runironic-inspector b/ironic-image/runironic-inspector new file mode 100644 index 0000000..c43782d --- /dev/null +++ b/ironic-image/runironic-inspector @@ -0,0 +1,62 @@ +#!/usr/bin/bash + +set -euxo pipefail + +CONFIG=/etc/ironic-inspector/ironic-inspector.conf + +export IRONIC_INSPECTOR_ENABLE_DISCOVERY=${IRONIC_INSPECTOR_ENABLE_DISCOVERY:-false} +export INSPECTOR_REVERSE_PROXY_SETUP=${INSPECTOR_REVERSE_PROXY_SETUP:-false} + +# shellcheck disable=SC1091 +. /bin/tls-common.sh +# shellcheck disable=SC1091 +. /bin/ironic-common.sh +# shellcheck disable=SC1091 +. /bin/auth-common.sh + +if [[ "$USE_IRONIC_INSPECTOR" == "false" ]]; then + echo "FATAL: ironic-inspector is disabled via USE_IRONIC_INSPECTOR" + exit 1 +fi + +wait_for_interface_or_ip + +IRONIC_INSPECTOR_PORT=${IRONIC_INSPECTOR_ACCESS_PORT} +if [[ "$IRONIC_INSPECTOR_TLS_SETUP" == "true" ]]; then + if [[ "${INSPECTOR_REVERSE_PROXY_SETUP}" == "true" ]] && [[ "${IRONIC_INSPECTOR_PRIVATE_PORT}" != "unix" ]]; then + IRONIC_INSPECTOR_PORT=$IRONIC_INSPECTOR_PRIVATE_PORT + fi +else + export INSPECTOR_REVERSE_PROXY_SETUP="false" # If TLS is not used, we have no reason to use the reverse proxy +fi + +export IRONIC_INSPECTOR_BASE_URL="${IRONIC_INSPECTOR_SCHEME}://${IRONIC_URL_HOST}:${IRONIC_INSPECTOR_PORT}" +export IRONIC_BASE_URL="${IRONIC_SCHEME}://${IRONIC_URL_HOST}:${IRONIC_ACCESS_PORT}" + +build_j2_config() +{ + local CONFIG_FILE="$1" + python3 -c 'import os; import sys; import jinja2; sys.stdout.write(jinja2.Template(sys.stdin.read()).render(env=os.environ))' < "$CONFIG_FILE.j2" +} + +# Merge with the original configuration file from the package. +build_j2_config "$CONFIG" | crudini --merge "$CONFIG" + +configure_inspector_auth + +configure_client_basic_auth ironic "${CONFIG}" + +ironic-inspector-dbsync --config-file "${CONFIG}" upgrade + +if [[ "$INSPECTOR_REVERSE_PROXY_SETUP" == "false" ]] && [[ "${RESTART_CONTAINER_CERTIFICATE_UPDATED}" == "true" ]]; then + # shellcheck disable=SC2034 + inotifywait -m -e delete_self "${IRONIC_INSPECTOR_CERT_FILE}" | while read -r file event; do + kill $(pgrep ironic) + done & +fi + +# Make sure ironic traffic bypasses any proxies +export NO_PROXY="${NO_PROXY:-},$IRONIC_IP" + +# shellcheck disable=SC2086 +exec /usr/bin/ironic-inspector diff --git a/ironic-image/runlogwatch.sh b/ironic-image/runlogwatch.sh new file mode 100644 index 0000000..8b2124e --- /dev/null +++ b/ironic-image/runlogwatch.sh @@ -0,0 +1,20 @@ +#!/usr/bin/bash + +# Ramdisk logs path +LOG_DIRS=("/shared/log/ironic/deploy" "/shared/log/ironic-inspector/ramdisk") + +while :; do + for LOG_DIR in "${LOG_DIRS[@]}"; do + if ! ls "${LOG_DIR}"/*.tar.gz 1> /dev/null 2>&1; then + continue + fi + + for fn in "${LOG_DIR}"/*.tar.gz; do + echo "************ Contents of $fn ramdisk log file bundle **************" + tar -xOzvvf "$fn" | sed -e "s/^/$(basename "$fn"): /" + rm -f "$fn" + done + done + + sleep 5 +done diff --git a/ironic-image/tls-common.sh b/ironic-image/tls-common.sh new file mode 100644 index 0000000..992f475 --- /dev/null +++ b/ironic-image/tls-common.sh @@ -0,0 +1,101 @@ +#!/bin/bash + +export IRONIC_CERT_FILE=/certs/ironic/tls.crt +export IRONIC_KEY_FILE=/certs/ironic/tls.key +export IRONIC_CACERT_FILE=/certs/ca/ironic/tls.crt +export IRONIC_INSECURE=${IRONIC_INSECURE:-false} +export IRONIC_SSL_PROTOCOL=${IRONIC_SSL_PROTOCOL:-"-ALL +TLSv1.2 +TLSv1.3"} +export IRONIC_VMEDIA_SSL_PROTOCOL=${IRONIC_VMEDIA_SSL_PROTOCOL:-"ALL"} + +export IRONIC_INSPECTOR_CERT_FILE=/certs/ironic-inspector/tls.crt +export IRONIC_INSPECTOR_KEY_FILE=/certs/ironic-inspector/tls.key +export IRONIC_INSPECTOR_CACERT_FILE=/certs/ca/ironic-inspector/tls.crt +export IRONIC_INSPECTOR_INSECURE=${IRONIC_INSPECTOR_INSECURE:-$IRONIC_INSECURE} + +export IRONIC_VMEDIA_CERT_FILE=/certs/vmedia/tls.crt +export IRONIC_VMEDIA_KEY_FILE=/certs/vmedia/tls.key + +export RESTART_CONTAINER_CERTIFICATE_UPDATED=${RESTART_CONTAINER_CERTIFICATE_UPDATED:-"false"} + +export MARIADB_CACERT_FILE=/certs/ca/mariadb/tls.crt + +mkdir -p /certs/ironic +mkdir -p /certs/ironic-inspector +mkdir -p /certs/ca/ironic +mkdir -p /certs/ca/ironic-inspector + +if [[ -f "$IRONIC_CERT_FILE" ]] && [[ ! -f "$IRONIC_KEY_FILE" ]]; then + echo "Missing TLS Certificate key file $IRONIC_KEY_FILE" + exit 1 +fi +if [[ ! -f "$IRONIC_CERT_FILE" ]] && [[ -f "$IRONIC_KEY_FILE" ]]; then + echo "Missing TLS Certificate file $IRONIC_CERT_FILE" + exit 1 +fi + +if [[ -f "$IRONIC_INSPECTOR_CERT_FILE" ]] && [[ ! -f "$IRONIC_INSPECTOR_KEY_FILE" ]]; then + echo "Missing TLS Certificate key file $IRONIC_INSPECTOR_KEY_FILE" + exit 1 +fi +if [[ ! -f "$IRONIC_INSPECTOR_CERT_FILE" ]] && [[ -f "$IRONIC_INSPECTOR_KEY_FILE" ]]; then + echo "Missing TLS Certificate file $IRONIC_INSPECTOR_CERT_FILE" + exit 1 +fi + +if [[ -f "$IRONIC_VMEDIA_CERT_FILE" ]] && [[ ! -f "$IRONIC_VMEDIA_KEY_FILE" ]]; then + echo "Missing TLS Certificate key file $IRONIC_VMEDIA_KEY_FILE" + exit 1 +fi +if [[ ! -f "$IRONIC_VMEDIA_CERT_FILE" ]] && [[ -f "$IRONIC_VMEDIA_KEY_FILE" ]]; then + echo "Missing TLS Certificate file $IRONIC_VMEDIA_CERT_FILE" + exit 1 +fi + +copy_atomic() +{ + local src="$1" + local dest="$2" + local tmpdest + + tmpdest=$(mktemp "$dest.XXX") + cp "$src" "$tmpdest" + # Hard linking is atomic, but only works on the same volume + ln -f "$tmpdest" "$dest" + rm -f "$tmpdest" +} + +if [[ -f "$IRONIC_CERT_FILE" ]] || [[ -f "$IRONIC_CACERT_FILE" ]]; then + export IRONIC_TLS_SETUP="true" + export IRONIC_SCHEME="https" + if [[ ! -f "$IRONIC_CACERT_FILE" ]]; then + copy_atomic "$IRONIC_CERT_FILE" "$IRONIC_CACERT_FILE" + fi +else + export IRONIC_TLS_SETUP="false" + export IRONIC_SCHEME="http" +fi + +if [[ -f "$IRONIC_INSPECTOR_CERT_FILE" ]] || [[ -f "$IRONIC_INSPECTOR_CACERT_FILE" ]]; then + export IRONIC_INSPECTOR_TLS_SETUP="true" + export IRONIC_INSPECTOR_SCHEME="https" + if [[ ! -f "$IRONIC_INSPECTOR_CACERT_FILE" ]]; then + copy_atomic "$IRONIC_INSPECTOR_CERT_FILE" "$IRONIC_INSPECTOR_CACERT_FILE" + fi +else + export IRONIC_INSPECTOR_TLS_SETUP="false" + export IRONIC_INSPECTOR_SCHEME="http" +fi + +if [[ -f "$IRONIC_VMEDIA_CERT_FILE" ]]; then + export IRONIC_VMEDIA_SCHEME="https" + export IRONIC_VMEDIA_TLS_SETUP="true" +else + export IRONIC_VMEDIA_SCHEME="http" + export IRONIC_VMEDIA_TLS_SETUP="false" +fi + +if [[ -f "$MARIADB_CACERT_FILE" ]]; then + export MARIADB_TLS_ENABLED="true" +else + export MARIADB_TLS_ENABLED="false" +fi diff --git a/ironic-ipa-downloader-image/Dockerfile b/ironic-ipa-downloader-image/Dockerfile new file mode 100644 index 0000000..98fa91e --- /dev/null +++ b/ironic-ipa-downloader-image/Dockerfile @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%ironic-ipa-downloader:2.0.0 +#!BuildTag: %%IMG_PREFIX%%ironic-ipa-downloader:2.0.0-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN sed -i -e 's%^# rpm.install.excludedocs = no.*%rpm.install.excludedocs = yes%g' /etc/zypp/zypp.conf +RUN zypper --installroot /installroot --non-interactive install --no-recommends openstack-ironic-image-200-x86_64 python311-devel python311 python311-pip tar gawk git curl xz fakeroot shadow sed cpio; zypper -n clean; rm -rf /var/log/* +#RUN zypper --installroot /installroot --non-interactive install --no-recommends sles-release; +RUN cp /usr/bin/getopt /installroot/ + +FROM micro AS final + +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.ironic +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE Based Ironic IPA Downloader Container Image" +LABEL org.opencontainers.image.description="ironic-ipa-downloader based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="2.0.0" +LABEL org.opencontainers.image.url="https://www.suse.com/solutions/edge-computing/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%ironic-ipa-downloader:2.0.0-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +RUN cp /getopt /usr/bin/ +RUN cp /srv/tftpboot/openstack-ironic-image/initrd.xz /tmp +RUN cp /srv/tftpboot/openstack-ironic-image/openstack-ironic-image*.kernel /tmp +# configure non-root user +COPY configure-nonroot.sh /bin/ +RUN set -euo pipefail; chmod +x /bin/configure-nonroot.sh +RUN set -euo pipefail; /bin/configure-nonroot.sh && rm -f /bin/configure-nonroot.sh +COPY get-resource.sh /usr/local/bin/get-resource.sh + +RUN set -euo pipefail; chmod +x /usr/local/bin/get-resource.sh diff --git a/ironic-ipa-downloader-image/_service b/ironic-ipa-downloader-image/_service new file mode 100644 index 0000000..67ff653 --- /dev/null +++ b/ironic-ipa-downloader-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%openstack-ironic-image-200-x86_64_version%% + openstack-ironic-image-200-x86_64 + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + diff --git a/ironic-ipa-downloader-image/configure-nonroot.sh b/ironic-ipa-downloader-image/configure-nonroot.sh new file mode 100644 index 0000000..e85754f --- /dev/null +++ b/ironic-ipa-downloader-image/configure-nonroot.sh @@ -0,0 +1,12 @@ +#!/usr/bin/bash + +NONROOT_UID=10475 +NONROOT_GID=10475 +USER="ironic-suse" + +groupadd -r -g ${NONROOT_GID} ${USER} +useradd -r -g ${NONROOT_GID} \ + -u ${NONROOT_UID} \ + -d /home \ + -s /sbin/nologin \ + ${USER} diff --git a/ironic-ipa-downloader-image/get-resource.sh b/ironic-ipa-downloader-image/get-resource.sh new file mode 100644 index 0000000..373553f --- /dev/null +++ b/ironic-ipa-downloader-image/get-resource.sh @@ -0,0 +1,71 @@ +#!/bin/bash -xe +#CACHEURL=http://172.22.0.1/images + +# Check and set http(s)_proxy. Required for cURL to use a proxy +export http_proxy=${http_proxy:-$HTTP_PROXY} +export https_proxy=${https_proxy:-$HTTPS_PROXY} +export no_proxy=${no_proxy:-$NO_PROXY} + +# Which image should we use +if [ -z "${IPA_BASEURI}" ]; then + # SLES BASED IPA - openstack-ironic-image-x86_64 package + mkdir -p /shared/html/images + cp /tmp/initrd.xz /shared/html/images/ironic-python-agent.initramfs + cp /tmp/openstack-ironic-image*.x86_64*.kernel /shared/html/images/ironic-python-agent.kernel +else + FILENAME=ironic-python-agent + FILENAME_EXT=.tar + FFILENAME=$FILENAME$FILENAME_EXT + + mkdir -p /shared/html/images /shared/tmp + cd /shared/html/images + + TMPDIR=$(mktemp -d -p /shared/tmp) + + # If we have a CACHEURL and nothing has yet been downloaded + # get header info from the cache + ls -l + if [ -n "$CACHEURL" -a ! -e $FFILENAME.headers ] ; then + curl -g --verbose --fail -O "$CACHEURL/$FFILENAME.headers" || true + fi + + # Download the most recent version of IPA + if [ -e $FFILENAME.headers ] ; then + ETAG=$(awk '/ETag:/ {print $2}' $FFILENAME.headers | tr -d "\r") + cd $TMPDIR + curl -g --verbose --dump-header $FFILENAME.headers -O $IPA_BASEURI/$FFILENAME --header "If-None-Match: $ETAG" || cp /shared/html/images/$FFILENAME.headers . + # curl didn't download anything because we have the ETag already + # but we don't have it in the images directory + # Its in the cache, go get it + ETAG=$(awk '/ETag:/ {print $2}' $FFILENAME.headers | tr -d "\"\r") + if [ ! -s $FFILENAME -a ! -e /shared/html/images/$FILENAME-$ETAG/$FFILENAME ] ; then + mv /shared/html/images/$FFILENAME.headers . + curl -g --verbose -O "$CACHEURL/$FILENAME-$ETAG/$FFILENAME" + fi + else + cd $TMPDIR + curl -g --verbose --dump-header $FFILENAME.headers -O $IPA_BASEURI/$FFILENAME + fi + + if [ -s $FFILENAME ] ; then + tar -xf $FFILENAME + + ETAG=$(awk '/ETag:/ {print $2}' $FFILENAME.headers | tr -d "\"\r") + cd - + chmod 755 $TMPDIR + mv $TMPDIR $FILENAME-$ETAG + ln -sf $FILENAME-$ETAG/$FFILENAME.headers $FFILENAME.headers + ln -sf $FILENAME-$ETAG/$FILENAME.initramfs $FILENAME.initramfs + ln -sf $FILENAME-$ETAG/$FILENAME.kernel $FILENAME.kernel + else + rm -rf $TMPDIR + fi +fi + +if [ -d "/tmp/ironic-certificates" ]; then + mkdir -p /tmp/ca/tmp-initrd && cd /tmp/ca/tmp-initrd + xz -d -c -k --fast /shared/html/images/ironic-python-agent.initramfs | fakeroot -s ../initrd.fakeroot cpio -i + mkdir -p etc/ironic-python-agent.d/ca-certs + cp /tmp/ironic-certificates/* etc/ironic-python-agent.d/ca-certs/ + find . | fakeroot -i ../initrd.fakeroot cpio -o -H newc | xz --check=crc32 --x86 --lzma2 --fast > /shared/html/images/ironic-python-agent.initramfs +fi \ No newline at end of file From 148e26cf721f3b76f30b437002e1437fd9cfb34528f9ffa93c62cb9f2bd19aa1 Mon Sep 17 00:00:00 2001 From: Denislav Prodanov Date: Mon, 21 Oct 2024 16:17:49 +0300 Subject: [PATCH 2/3] moved charts/images --- baremetal-operator-image/Dockerfile | 34 ++ baremetal-operator-image/_service | 17 + cdi-chart/Chart.yaml | 9 + cdi-chart/_service | 8 + cdi-chart/crds.obscpio | Bin 0 -> 356864 bytes cdi-chart/templates.obscpio | Bin 0 -> 26624 bytes cdi-chart/values.yaml | 38 ++ cluster-api-controller-image/Dockerfile | 2 +- cluster-api-controller-image/_service | 2 +- cluster-api-operator-image/Dockerfile | 2 +- cluster-api-operator-image/_service | 2 +- cluster-api-provider-metal3-image/Dockerfile | 2 +- cluster-api-provider-metal3-image/_service | 2 +- .../Dockerfile | 2 +- .../_service | 2 +- .../Dockerfile | 2 +- .../_service | 2 +- edge-image-builder-image/Dockerfile | 2 +- ip-address-manager-image/Dockerfile | 2 +- ip-address-manager-image/_service | 2 +- ironic-ipa-downloader-image/Dockerfile | 2 +- ironic-ipa-downloader-image/_service | 4 +- metal3-chart/Chart.yaml | 27 ++ metal3-chart/README.md | 100 ++++ metal3-chart/_service | 15 + metal3-chart/app-readme.md | 1 + metal3-chart/charts.obscpio | Bin 0 -> 189440 bytes metal3-chart/templates.obscpio | Bin 0 -> 2560 bytes metal3-chart/values.yaml | 130 +++++ metallb-chart/Chart.yaml | 23 + metallb-chart/README.md | 169 +++++++ metallb-chart/_service | 15 + metallb-chart/charts.obscpio | Bin 0 -> 141824 bytes metallb-chart/policy.obscpio | Bin 0 -> 3072 bytes metallb-chart/templates.obscpio | Bin 0 -> 60928 bytes metallb-chart/values.schema.json | 448 ++++++++++++++++++ metallb-chart/values.yaml | 380 +++++++++++++++ metallb-controller-image/Dockerfile | 32 ++ metallb-controller-image/_service | 17 + metallb-speaker-image/Dockerfile | 32 ++ metallb-speaker-image/_service | 17 + sriov-crd-chart/Chart.yaml | 13 + sriov-crd-chart/_service | 8 + sriov-crd-chart/templates.obscpio | Bin 0 -> 47104 bytes sriov-network-operator-chart/Chart.yaml | 28 ++ sriov-network-operator-chart/README.md | 130 +++++ sriov-network-operator-chart/_service | 8 + sriov-network-operator-chart/app-README.md | 13 + sriov-network-operator-chart/charts.obscpio | Bin 0 -> 90112 bytes .../templates.obscpio | Bin 0 -> 28160 bytes sriov-network-operator-chart/values.yaml | 124 +++++ upgrade-controller-chart/Chart.yaml | 13 + upgrade-controller-chart/_service | 16 + upgrade-controller-chart/charts.obscpio | Bin 0 -> 15360 bytes upgrade-controller-chart/templates.obscpio | Bin 0 -> 12800 bytes upgrade-controller-chart/values.yaml | 91 ++++ upgrade-controller-image/Dockerfile | 38 ++ upgrade-controller-image/_service | 10 + 58 files changed, 2020 insertions(+), 16 deletions(-) create mode 100644 baremetal-operator-image/Dockerfile create mode 100644 baremetal-operator-image/_service create mode 100644 cdi-chart/Chart.yaml create mode 100644 cdi-chart/_service create mode 100644 cdi-chart/crds.obscpio create mode 100644 cdi-chart/templates.obscpio create mode 100644 cdi-chart/values.yaml create mode 100644 metal3-chart/Chart.yaml create mode 100644 metal3-chart/README.md create mode 100644 metal3-chart/_service create mode 100644 metal3-chart/app-readme.md create mode 100644 metal3-chart/charts.obscpio create mode 100644 metal3-chart/templates.obscpio create mode 100644 metal3-chart/values.yaml create mode 100644 metallb-chart/Chart.yaml create mode 100644 metallb-chart/README.md create mode 100644 metallb-chart/_service create mode 100644 metallb-chart/charts.obscpio create mode 100644 metallb-chart/policy.obscpio create mode 100644 metallb-chart/templates.obscpio create mode 100644 metallb-chart/values.schema.json create mode 100644 metallb-chart/values.yaml create mode 100644 metallb-controller-image/Dockerfile create mode 100644 metallb-controller-image/_service create mode 100644 metallb-speaker-image/Dockerfile create mode 100644 metallb-speaker-image/_service create mode 100644 sriov-crd-chart/Chart.yaml create mode 100644 sriov-crd-chart/_service create mode 100644 sriov-crd-chart/templates.obscpio create mode 100644 sriov-network-operator-chart/Chart.yaml create mode 100644 sriov-network-operator-chart/README.md create mode 100644 sriov-network-operator-chart/_service create mode 100644 sriov-network-operator-chart/app-README.md create mode 100644 sriov-network-operator-chart/charts.obscpio create mode 100644 sriov-network-operator-chart/templates.obscpio create mode 100644 sriov-network-operator-chart/values.yaml create mode 100644 upgrade-controller-chart/Chart.yaml create mode 100644 upgrade-controller-chart/_service create mode 100644 upgrade-controller-chart/charts.obscpio create mode 100644 upgrade-controller-chart/templates.obscpio create mode 100644 upgrade-controller-chart/values.yaml create mode 100644 upgrade-controller-image/Dockerfile create mode 100644 upgrade-controller-image/_service diff --git a/baremetal-operator-image/Dockerfile b/baremetal-operator-image/Dockerfile new file mode 100644 index 0000000..6b45179 --- /dev/null +++ b/baremetal-operator-image/Dockerfile @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%baremetal-operator:%%baremetal-operator_version%% +#!BuildTag: %%IMG_PREFIX%%baremetal-operator:%%baremetal-operator_version%%-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN zypper --installroot /installroot --non-interactive install --no-recommends baremetal-operator iproute2 bind-utils vim shadow; zypper -n clean; rm -rf /var/log/* + +FROM micro AS final +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.baremetal-operator +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE baremetal-operator Container Image" +LABEL org.opencontainers.image.description="baremetal-operator based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="%%baremetal-operator_version%%" +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%baremetal-operator:%%baremetal-operator_version%%-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +RUN groupadd -r -g 11000 bmo +RUN useradd -u 11000 -g 11000 bmo +ENTRYPOINT [ "/usr/bin/baremetal-operator" ] diff --git a/baremetal-operator-image/_service b/baremetal-operator-image/_service new file mode 100644 index 0000000..88c8e8c --- /dev/null +++ b/baremetal-operator-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%baremetal-operator_version%% + baremetal-operator + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + diff --git a/cdi-chart/Chart.yaml b/cdi-chart/Chart.yaml new file mode 100644 index 0000000..641cfc7 --- /dev/null +++ b/cdi-chart/Chart.yaml @@ -0,0 +1,9 @@ +#!BuildTag: %%IMG_PREFIX%%cdi-chart:0.4.0 +#!BuildTag: %%IMG_PREFIX%%cdi-chart:0.4.0-%RELEASE% +apiVersion: v2 +appVersion: 1.60.1 +description: A Helm chart for Containerized Data Importer (CDI) +icon: https://raw.githubusercontent.com/cncf/artwork/main/projects/kubevirt/icon/color/kubevirt-icon-color.svg +name: cdi +type: application +version: 0.4.0 diff --git a/cdi-chart/_service b/cdi-chart/_service new file mode 100644 index 0000000..6b8f891 --- /dev/null +++ b/cdi-chart/_service @@ -0,0 +1,8 @@ + + + + Chart.yaml + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + + diff --git a/cdi-chart/crds.obscpio b/cdi-chart/crds.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..934dbbbe293092174fb46c35378f87526154d3e78ee13025221b7272264ab260 GIT binary patch literal 356864 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 Z)^_8*xPJfg&0k)>|K%@#`HL^~_5b~9yoUe) literal 0 HcmV?d00001 diff --git a/cdi-chart/templates.obscpio b/cdi-chart/templates.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..f1fb05f1303c34d3034362b2d373771e14003a3db6707f41aa1c8f59b7631450 GIT binary patch literal 26624 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 literal 0 HcmV?d00001 diff --git a/cdi-chart/values.yaml b/cdi-chart/values.yaml new file mode 100644 index 0000000..b4c1fef --- /dev/null +++ b/cdi-chart/values.yaml @@ -0,0 +1,38 @@ +deployment: + version: 1.60.1-150600.3.9.1 + operatorImage: registry.suse.com/suse/sles/15.6/cdi-operator + controllerImage: registry.suse.com/suse/sles/15.6/cdi-controller + importerImage: registry.suse.com/suse/sles/15.6/cdi-importer + clonerImage: registry.suse.com/suse/sles/15.6/cdi-cloner + apiserverImage: registry.suse.com/suse/sles/15.6/cdi-apiserver + uploadserverImage: registry.suse.com/suse/sles/15.6/cdi-uploadserver + uploadproxyImage: registry.suse.com/suse/sles/15.6/cdi-uploadproxy + pullPolicy: IfNotPresent + +cdi: + config: + featureGates: + - HonorWaitForFirstConsumer + imagePullPolicy: "IfNotPresent" + infra: + nodeSelector: + kubernetes.io/os: linux + tolerations: + - key: CriticalAddonsOnly + operator: Exists + uninstallStrategy: "" + workload: + nodeSelector: + kubernetes.io/os: linux + +hookImage: rancher/kubectl:v1.30.2 +hookRestartPolicy: OnFailure +hookSecurityContext: + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + runAsUser: 1000 + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL diff --git a/cluster-api-controller-image/Dockerfile b/cluster-api-controller-image/Dockerfile index f4057c5..758da5e 100644 --- a/cluster-api-controller-image/Dockerfile +++ b/cluster-api-controller-image/Dockerfile @@ -8,7 +8,7 @@ FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base COPY --from=micro / /installroot/ -RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-175 shadow; zypper -n clean; rm -rf /var/log/* +RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api shadow; zypper -n clean; rm -rf /var/log/* FROM micro AS final # Define labels according to https://en.opensuse.org/Building_derived_containers diff --git a/cluster-api-controller-image/_service b/cluster-api-controller-image/_service index 9f48c56..05f906c 100644 --- a/cluster-api-controller-image/_service +++ b/cluster-api-controller-image/_service @@ -4,7 +4,7 @@ Dockerfile %%cluster-api_version%% - cluster-api-175 + cluster-api patch diff --git a/cluster-api-operator-image/Dockerfile b/cluster-api-operator-image/Dockerfile index 8244d9c..b6fbc89 100644 --- a/cluster-api-operator-image/Dockerfile +++ b/cluster-api-operator-image/Dockerfile @@ -7,7 +7,7 @@ FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base COPY --from=micro / /installroot/ -RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-operator-012 shadow; zypper -n clean; rm -rf /var/log/* +RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-operator shadow; zypper -n clean; rm -rf /var/log/* FROM micro AS final # Define labels according to https://en.opensuse.org/Building_derived_containers diff --git a/cluster-api-operator-image/_service b/cluster-api-operator-image/_service index 646f2d0..1edc617 100644 --- a/cluster-api-operator-image/_service +++ b/cluster-api-operator-image/_service @@ -4,7 +4,7 @@ Dockerfile %%cluster-api-operator_version%% - cluster-api-operator-012 + cluster-api-operator patch diff --git a/cluster-api-provider-metal3-image/Dockerfile b/cluster-api-provider-metal3-image/Dockerfile index edd6d38..727007d 100644 --- a/cluster-api-provider-metal3-image/Dockerfile +++ b/cluster-api-provider-metal3-image/Dockerfile @@ -8,7 +8,7 @@ FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base COPY --from=micro / /installroot/ -RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-provider-metal3-171 shadow; zypper -n clean; rm -rf /var/log/* +RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-provider-metal3 shadow; zypper -n clean; rm -rf /var/log/* FROM micro AS final # Define labels according to https://en.opensuse.org/Building_derived_containers diff --git a/cluster-api-provider-metal3-image/_service b/cluster-api-provider-metal3-image/_service index 2ef5aa3..ec4e439 100644 --- a/cluster-api-provider-metal3-image/_service +++ b/cluster-api-provider-metal3-image/_service @@ -4,7 +4,7 @@ Dockerfile %%cluster-api-provider-metal3_version%% - cluster-api-provider-metal3-171 + cluster-api-provider-metal3 patch diff --git a/cluster-api-provider-rke2-bootstrap-image/Dockerfile b/cluster-api-provider-rke2-bootstrap-image/Dockerfile index 902d5db..6f3be33 100644 --- a/cluster-api-provider-rke2-bootstrap-image/Dockerfile +++ b/cluster-api-provider-rke2-bootstrap-image/Dockerfile @@ -8,7 +8,7 @@ FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base COPY --from=micro / /installroot/ -RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-provider-rke2-070-bootstrap shadow; zypper -n clean; rm -rf /var/log/* +RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-provider-rke2-bootstrap shadow; zypper -n clean; rm -rf /var/log/* FROM micro AS final # Define labels according to https://en.opensuse.org/Building_derived_containers diff --git a/cluster-api-provider-rke2-bootstrap-image/_service b/cluster-api-provider-rke2-bootstrap-image/_service index fa241da..430aa7c 100644 --- a/cluster-api-provider-rke2-bootstrap-image/_service +++ b/cluster-api-provider-rke2-bootstrap-image/_service @@ -4,7 +4,7 @@ Dockerfile %%cluster-api-provider-rke2_version%% - cluster-api-provider-rke2-070-bootstrap + cluster-api-provider-rke2-bootstrap patch diff --git a/cluster-api-provider-rke2-controlplane-image/Dockerfile b/cluster-api-provider-rke2-controlplane-image/Dockerfile index db8ac94..011bc75 100644 --- a/cluster-api-provider-rke2-controlplane-image/Dockerfile +++ b/cluster-api-provider-rke2-controlplane-image/Dockerfile @@ -8,7 +8,7 @@ FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base COPY --from=micro / /installroot/ -RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-provider-rke2-070-control-plane shadow; zypper -n clean; rm -rf /var/log/* +RUN zypper --installroot /installroot --non-interactive install --no-recommends cluster-api-provider-rke2-control-plane shadow; zypper -n clean; rm -rf /var/log/* FROM micro AS final # Define labels according to https://en.opensuse.org/Building_derived_containers diff --git a/cluster-api-provider-rke2-controlplane-image/_service b/cluster-api-provider-rke2-controlplane-image/_service index 7d398fe..1fbc59e 100644 --- a/cluster-api-provider-rke2-controlplane-image/_service +++ b/cluster-api-provider-rke2-controlplane-image/_service @@ -4,7 +4,7 @@ Dockerfile %%cluster-api-provider-rke2_version%% - cluster-api-provider-rke2-070-control-plane + cluster-api-provider-rke2-control-plane patch diff --git a/edge-image-builder-image/Dockerfile b/edge-image-builder-image/Dockerfile index 714da54..60ac9b6 100644 --- a/edge-image-builder-image/Dockerfile +++ b/edge-image-builder-image/Dockerfile @@ -8,7 +8,7 @@ MAINTAINER SUSE LLC (https://www.suse.com/) COPY artifacts.yaml artifacts.yaml RUN sed -i -e 's%^# rpm.install.excludedocs = no.*%rpm.install.excludedocs = yes%g' /etc/zypp/zypp.conf -RUN zypper --non-interactive install --no-recommends edge-image-builder-110 qemu-x86 qemu-uefi-aarch64 cni-plugins; zypper -n clean; rm -rf /var/log/* +RUN zypper --non-interactive install --no-recommends edge-image-builder qemu-x86 qemu-uefi-aarch64 cni-plugins; zypper -n clean; rm -rf /var/log/* # Define labels according to https://en.opensuse.org/Building_derived_containers # labelprefix=com.suse.application.edge-image-builder diff --git a/ip-address-manager-image/Dockerfile b/ip-address-manager-image/Dockerfile index 672ad17..af19182 100644 --- a/ip-address-manager-image/Dockerfile +++ b/ip-address-manager-image/Dockerfile @@ -8,7 +8,7 @@ FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base COPY --from=micro / /installroot/ -RUN zypper --installroot /installroot --non-interactive install --no-recommends ip-address-manager-171 shadow; zypper -n clean; rm -rf /var/log/* +RUN zypper --installroot /installroot --non-interactive install --no-recommends ip-address-manager shadow; zypper -n clean; rm -rf /var/log/* FROM micro AS final # Define labels according to https://en.opensuse.org/Building_derived_containers diff --git a/ip-address-manager-image/_service b/ip-address-manager-image/_service index a0d1450..56cf294 100644 --- a/ip-address-manager-image/_service +++ b/ip-address-manager-image/_service @@ -4,7 +4,7 @@ Dockerfile %%ip-address-manager_version%% - ip-address-manager-171 + ip-address-manager patch diff --git a/ironic-ipa-downloader-image/Dockerfile b/ironic-ipa-downloader-image/Dockerfile index 98fa91e..bb061bc 100644 --- a/ironic-ipa-downloader-image/Dockerfile +++ b/ironic-ipa-downloader-image/Dockerfile @@ -8,7 +8,7 @@ FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base COPY --from=micro / /installroot/ RUN sed -i -e 's%^# rpm.install.excludedocs = no.*%rpm.install.excludedocs = yes%g' /etc/zypp/zypp.conf -RUN zypper --installroot /installroot --non-interactive install --no-recommends openstack-ironic-image-200-x86_64 python311-devel python311 python311-pip tar gawk git curl xz fakeroot shadow sed cpio; zypper -n clean; rm -rf /var/log/* +RUN zypper --installroot /installroot --non-interactive install --no-recommends openstack-ironic-image-x86_64 python311-devel python311 python311-pip tar gawk git curl xz fakeroot shadow sed cpio; zypper -n clean; rm -rf /var/log/* #RUN zypper --installroot /installroot --non-interactive install --no-recommends sles-release; RUN cp /usr/bin/getopt /installroot/ diff --git a/ironic-ipa-downloader-image/_service b/ironic-ipa-downloader-image/_service index 67ff653..3480bd2 100644 --- a/ironic-ipa-downloader-image/_service +++ b/ironic-ipa-downloader-image/_service @@ -3,8 +3,8 @@ Dockerfile - %%openstack-ironic-image-200-x86_64_version%% - openstack-ironic-image-200-x86_64 + %%openstack-ironic-image-x86_64_version%% + openstack-ironic-image-x86_64 patch diff --git a/metal3-chart/Chart.yaml b/metal3-chart/Chart.yaml new file mode 100644 index 0000000..50f2777 --- /dev/null +++ b/metal3-chart/Chart.yaml @@ -0,0 +1,27 @@ +#!BuildTag: %%IMG_PREFIX%%metal3-chart:0.8.1 +#!BuildTag: %%IMG_PREFIX%%metal3-chart:0.8.1-%RELEASE% +apiVersion: v2 +appVersion: 1.16.0 +dependencies: +- alias: metal3-baremetal-operator + name: baremetal-operator + repository: file://./charts/baremetal-operator + version: 0.5.0 +- alias: metal3-ironic + name: ironic + repository: file://./charts/ironic + version: 0.7.0 +- alias: metal3-mariadb + name: mariadb + repository: file://./charts/mariadb + version: 0.5.4 +- alias: metal3-media + condition: global.enable_metal3_media_server + name: media + repository: file://./charts/media + version: 0.5.0 +description: A Helm chart that installs all of the dependencies needed for Metal3 +icon: https://github.com/cncf/artwork/raw/master/projects/metal3/icon/color/metal3-icon-color.svg +name: metal3 +type: application +version: 0.8.1 diff --git a/metal3-chart/README.md b/metal3-chart/README.md new file mode 100644 index 0000000..c6ccadd --- /dev/null +++ b/metal3-chart/README.md @@ -0,0 +1,100 @@ +# Prerequisites +There are two dependencies that are not managed through the metal3 chart because are related to applications that have a cluster-wide scope: `cert-manager` and a LoadBalancer Service provider such as `metallb` or `kube-vip`. + +## Cert Manager +In order to successfully deploy metal3 the cluster must have already installed the `cert-manager`. + +You can install it through `helm` with: +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update +helm install \ + cert-manager jetstack/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --set installCRDs=true +``` +, or via `kubectl` with: +```bash +kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.1/cert-manager.yaml +``` + +## MetalLB (Optional) +Ironic currently requires a staticIP address and MetalLB is one option to achieve that. + +1. If K3s is used as Kubernetes distribution, then it should be started with `--disable=servicelb` flag. Ref https://metallb.universe.tf/configuration/k3s/ +2. Find 1 free IP address in the network. +3. Install `MetalLB` through `helm` with: + +```bash +helm repo add suse-edge https://suse-edge.github.io/charts +helm install \ + metallb suse-edge/metallb \ + --namespace metallb-system \ + --create-namespace +``` + +4. Provide the IP pool configuration with: + +```bash +export STATIC_IRONIC_IP= + +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/metal3-chart/_service b/metal3-chart/_service new file mode 100644 index 0000000..c3f6878 --- /dev/null +++ b/metal3-chart/_service @@ -0,0 +1,15 @@ + + + + values.yaml + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + + Chart.yaml + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + + diff --git a/metal3-chart/app-readme.md b/metal3-chart/app-readme.md new file mode 100644 index 0000000..a7572b9 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts.obscpio b/metal3-chart/charts.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..c3b1f6c9ef7d814628bd678502988a1b9d3df4afd6c3e3159ea1c080d6efc21e GIT binary patch literal 189440 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

VK^b~Y%!{woY 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 TXIp!J_`@GSlAnJ*F$VrWaeM*~ literal 0 HcmV?d00001 diff --git a/metal3-chart/templates.obscpio b/metal3-chart/templates.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..a34873e1449e7225f5dc6c7c9de950e43c0a2147a3245fa59b943cc39e5cd868 GIT binary patch literal 2560 zcmeHJTTk0C6z+3>#UUCJFx5@RXc5vLy21k*DicLadqQsFP-{+{#STyv{`-zENiU&X z-j^4<_PKuNJI4(N;UMgVJsOA8<0!=MxJSR5HS8sQyM{gY8&CTE_$WF0(sSp7fm>1E zem%eX(|W1(L(S4$P|Z|#e0hB~A^K6bTCMBvrzdbKqcUZg20ddCvs}nIi-G33;1Sha zW?jXKdmb@hS)5CrY1MB3mL;f}EJX~Ne1Iu~g3)*mS_03Mra}PCVu)mx@Vl~LFcPKG ztQh`0C+!wyzRW!~;l4ZfKC@V%%3HZt7_H=fJ7Xeeg(5l^n0{-q=pMAs9&;0_$v&eg z1DV);G^2$k?St;~b9=GqATkNh7z8Q9><)<$4WP5Uq@~b6MpkQV?2sEON~Wyj7+~&{s=)Q0B;LXHd}Ox!Hp1B&43#B)7YaE3b_QlY+w9M6^^4l*FKZlv7q@42j^9MH?bkK(RuCr(B~&ETNup1$$F0CxUW1 zo)}r4-GRzkv`^aS307M$ibgGBSY=JI?AD=nXI#SrM;0J6&^hu6oq!46UT??Mh^%AF zlN!qEvWC+`Rzcmke-GRO)9`ja*>q06)o8z2Pp^nE)*v_|D3dLZac^!r2pi4j{M#CNXz2FfMP0DmESPgD(Er*f;U>d|lraf8v9G3$e{4%_M9_VEXAr2wjU?WSUy` z1<4|(xz6*KLiRIqbAVT`7L6iVn&(X#;%=pY7auxl)3r;&u8g2{F%r4??8B;t^xh_8 zs= + additionalTrustedCAs: false + + # Will be used when tls is enabled + vmediaTLSPort: 6185 + + # IP address of the router associated with the specified DHCP + # address range + dnsmasqDefaultRouter: "" + + # IP address of the dns server to be provided with DHCP + # response + dnsmasqDNSServer: "" + + # specify comma-delimited range of IP addresses the DHCP server will manage. + # e.g 192.168.20.20,192.168.20.80 + dhcpRange: "" + + # Network interface on which provisioning network can be accessed + provisioningInterface: "" + + # IP Address assigned to network interface on provisioning network + provisioningIP: "" + + # 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 + image: + repository: "%%IMG_REPO%%/%%IMG_PREFIX%%ironic" + +# +# ironic service +# + +# Override any settings for the metal3 ironic service here +# Ensure the storageClass is defined +metal3-ironic: + service: + type: LoadBalancer + persistence: + ironic: + # storageClass for the ironic shared volume + storageClass: "" + images: + ironic: + repository: "%%IMG_REPO%%/%%IMG_PREFIX%%ironic" + ironicIPADownloader: + repository: "%%IMG_REPO%%/%%IMG_PREFIX%%ironic-ipa-downloader" + +# +# Database Service +# + +# Override any settings for the metal3 mariadb service here +metal3-mariadb: + # storageClass for the mysql datastore + persistence: + storageClass: "" + image: + repository: "registry.suse.com/edge/mariadb" + tag: "10.6.15.1" + +# +# Baremetal Operator +# + +# Override any settings for the metal3 baremetal-operator service here +metal3-baremetal-operator: + images: + baremetalOperator: + repository: "%%IMG_REPO%%/%%IMG_PREFIX%%baremetal-operator" + rbacProxy: + repository: "%%IMG_REPO%%/%%IMG_PREFIX%%kube-rbac-proxy" + tag: "v0.18.0" + + diff --git a/metallb-chart/Chart.yaml b/metallb-chart/Chart.yaml new file mode 100644 index 0000000..6531cd1 --- /dev/null +++ b/metallb-chart/Chart.yaml @@ -0,0 +1,23 @@ +#!BuildTag: %%IMG_PREFIX%%metallb-chart:0.14.9 +#!BuildTag: %%IMG_PREFIX%%metallb-chart:0.14.9-%RELEASE% +apiVersion: v2 +appVersion: v0.14.3 +dependencies: +- condition: frrk8s.enabled + name: frr-k8s + repository: file://./charts/frr-k8s + version: 0.0.15 +- condition: crds.enabled + name: metallb-crds + repository: file://./charts/metallb-crds + version: 0.14.8 +description: A network load-balancer implementation for Kubernetes using standard + routing protocols +home: https://metallb.universe.tf +icon: https://metallb.universe.tf/images/logo/metallb-white.png +kubeVersion: '>= 1.19.0-0' +name: metallb +sources: +- https://github.com/metallb/metallb +type: application +version: 0.14.9 diff --git a/metallb-chart/README.md b/metallb-chart/README.md new file mode 100644 index 0000000..68692d1 --- /dev/null +++ b/metallb-chart/README.md @@ -0,0 +1,169 @@ +# metallb + +![Version: 0.14.8](https://img.shields.io/badge/Version-0.14.8-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.14.8](https://img.shields.io/badge/AppVersion-v0.14.8-informational?style=flat-square) + +A network load-balancer implementation for Kubernetes using standard routing protocols + +**Homepage:** + +## Source Code + +* + +## Requirements + +Kubernetes: `>= 1.19.0-0` + +| Repository | Name | Version | +|------------|------|---------| +| | crds | 0.14.8 | +| https://metallb.github.io/frr-k8s | frr-k8s | 0.0.14 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| controller.affinity | object | `{}` | | +| controller.enabled | bool | `true` | | +| controller.extraContainers | list | `[]` | | +| controller.image.pullPolicy | string | `nil` | | +| controller.image.repository | string | `"registry.opensuse.org/isv/suse/edge/metallb/images/metallb-controller"` | | +| controller.image.tag | string | `nil` | | +| controller.labels | object | `{}` | | +| controller.livenessProbe.enabled | bool | `true` | | +| controller.livenessProbe.failureThreshold | int | `3` | | +| controller.livenessProbe.initialDelaySeconds | int | `10` | | +| controller.livenessProbe.periodSeconds | int | `10` | | +| controller.livenessProbe.successThreshold | int | `1` | | +| controller.livenessProbe.timeoutSeconds | int | `1` | | +| controller.logLevel | string | `"info"` | Controller log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` | +| controller.nodeSelector | object | `{}` | | +| controller.podAnnotations | object | `{}` | | +| controller.priorityClassName | string | `""` | | +| controller.readinessProbe.enabled | bool | `true` | | +| controller.readinessProbe.failureThreshold | int | `3` | | +| controller.readinessProbe.initialDelaySeconds | int | `10` | | +| controller.readinessProbe.periodSeconds | int | `10` | | +| controller.readinessProbe.successThreshold | int | `1` | | +| controller.readinessProbe.timeoutSeconds | int | `1` | | +| controller.resources | object | `{}` | | +| controller.runtimeClassName | string | `""` | | +| controller.securityContext.fsGroup | int | `65534` | | +| controller.securityContext.runAsNonRoot | bool | `true` | | +| controller.securityContext.runAsUser | int | `65534` | | +| controller.serviceAccount.annotations | object | `{}` | | +| controller.serviceAccount.create | bool | `true` | | +| controller.serviceAccount.name | string | `""` | | +| controller.strategy.type | string | `"RollingUpdate"` | | +| controller.tlsCipherSuites | string | `""` | | +| controller.tlsMinVersion | string | `"VersionTLS12"` | | +| controller.tolerations | list | `[]` | | +| crds.enabled | bool | `true` | | +| crds.validationFailurePolicy | string | `"Fail"` | | +| frrk8s.enabled | bool | `false` | | +| frrk8s.external | bool | `false` | | +| frrk8s.namespace | string | `""` | | +| fullnameOverride | string | `""` | | +| imagePullSecrets | list | `[]` | | +| loadBalancerClass | string | `""` | | +| nameOverride | string | `""` | | +| prometheus.controllerMetricsTLSSecret | string | `""` | | +| prometheus.metricsPort | int | `7472` | | +| prometheus.namespace | string | `""` | | +| prometheus.podMonitor.additionalLabels | object | `{}` | | +| prometheus.podMonitor.annotations | object | `{}` | | +| prometheus.podMonitor.enabled | bool | `false` | | +| prometheus.podMonitor.interval | string | `nil` | | +| prometheus.podMonitor.jobLabel | string | `"app.kubernetes.io/name"` | | +| prometheus.podMonitor.metricRelabelings | list | `[]` | | +| prometheus.podMonitor.relabelings | list | `[]` | | +| prometheus.prometheusRule.additionalLabels | object | `{}` | | +| prometheus.prometheusRule.addressPoolExhausted.enabled | bool | `true` | | +| prometheus.prometheusRule.addressPoolExhausted.labels.severity | string | `"alert"` | | +| prometheus.prometheusRule.addressPoolUsage.enabled | bool | `true` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[0].labels.severity | string | `"warning"` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[0].percent | int | `75` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[1].labels.severity | string | `"warning"` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[1].percent | int | `85` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[2].labels.severity | string | `"alert"` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[2].percent | int | `95` | | +| prometheus.prometheusRule.annotations | object | `{}` | | +| prometheus.prometheusRule.bgpSessionDown.enabled | bool | `true` | | +| prometheus.prometheusRule.bgpSessionDown.labels.severity | string | `"alert"` | | +| prometheus.prometheusRule.configNotLoaded.enabled | bool | `true` | | +| prometheus.prometheusRule.configNotLoaded.labels.severity | string | `"warning"` | | +| prometheus.prometheusRule.enabled | bool | `false` | | +| prometheus.prometheusRule.extraAlerts | list | `[]` | | +| prometheus.prometheusRule.staleConfig.enabled | bool | `true` | | +| prometheus.prometheusRule.staleConfig.labels.severity | string | `"warning"` | | +| prometheus.rbacPrometheus | bool | `true` | | +| prometheus.rbacProxy.pullPolicy | string | `nil` | | +| prometheus.rbacProxy.repository | string | `"registry.opensuse.org/isv/suse/edge/metallb/images/kube-rbac-proxy"` | | +| prometheus.rbacProxy.tag | string | `"v0.12.0"` | | +| prometheus.scrapeAnnotations | bool | `false` | | +| prometheus.serviceAccount | string | `""` | | +| prometheus.serviceMonitor.controller.additionalLabels | object | `{}` | | +| prometheus.serviceMonitor.controller.annotations | object | `{}` | | +| prometheus.serviceMonitor.controller.tlsConfig.insecureSkipVerify | bool | `true` | | +| prometheus.serviceMonitor.enabled | bool | `false` | | +| prometheus.serviceMonitor.interval | string | `nil` | | +| prometheus.serviceMonitor.jobLabel | string | `"app.kubernetes.io/name"` | | +| prometheus.serviceMonitor.metricRelabelings | list | `[]` | | +| prometheus.serviceMonitor.relabelings | list | `[]` | | +| prometheus.serviceMonitor.speaker.additionalLabels | object | `{}` | | +| prometheus.serviceMonitor.speaker.annotations | object | `{}` | | +| prometheus.serviceMonitor.speaker.tlsConfig.insecureSkipVerify | bool | `true` | | +| prometheus.speakerMetricsTLSSecret | string | `""` | | +| rbac.create | bool | `true` | | +| speaker.affinity | object | `{}` | | +| speaker.enabled | bool | `true` | | +| speaker.excludeInterfaces.enabled | bool | `true` | | +| speaker.extraContainers | list | `[]` | | +| speaker.frr.enabled | bool | `true` | | +| speaker.frr.image.pullPolicy | string | `nil` | | +| speaker.frr.image.repository | string | `"registry.opensuse.org/isv/suse/edge/metallb/images/frr"` | | +| speaker.frr.image.tag | string | `"8.4.2"` | | +| speaker.frr.metricsPort | int | `7473` | | +| speaker.frr.resources | object | `{}` | | +| speaker.frrMetrics.resources | object | `{}` | | +| speaker.ignoreExcludeLB | bool | `false` | | +| speaker.image.pullPolicy | string | `nil` | | +| speaker.image.repository | string | `"registry.opensuse.org/isv/suse/edge/metallb/images/metallb-speaker"` | | +| speaker.image.tag | string | `nil` | | +| speaker.labels | object | `{}` | | +| speaker.livenessProbe.enabled | bool | `true` | | +| speaker.livenessProbe.failureThreshold | int | `3` | | +| speaker.livenessProbe.initialDelaySeconds | int | `10` | | +| speaker.livenessProbe.periodSeconds | int | `10` | | +| speaker.livenessProbe.successThreshold | int | `1` | | +| speaker.livenessProbe.timeoutSeconds | int | `1` | | +| speaker.logLevel | string | `"info"` | Speaker log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` | +| speaker.memberlist.enabled | bool | `true` | | +| speaker.memberlist.mlBindAddrOverride | string | `""` | | +| speaker.memberlist.mlBindPort | int | `7946` | | +| speaker.memberlist.mlSecretKeyPath | string | `"/etc/ml_secret_key"` | | +| speaker.nodeSelector | object | `{}` | | +| speaker.podAnnotations | object | `{}` | | +| speaker.priorityClassName | string | `""` | | +| speaker.readinessProbe.enabled | bool | `true` | | +| speaker.readinessProbe.failureThreshold | int | `3` | | +| speaker.readinessProbe.initialDelaySeconds | int | `10` | | +| speaker.readinessProbe.periodSeconds | int | `10` | | +| speaker.readinessProbe.successThreshold | int | `1` | | +| speaker.readinessProbe.timeoutSeconds | int | `1` | | +| speaker.reloader.resources | object | `{}` | | +| speaker.resources | object | `{}` | | +| speaker.runtimeClassName | string | `""` | | +| speaker.securityContext | object | `{}` | | +| speaker.serviceAccount.annotations | object | `{}` | | +| speaker.serviceAccount.create | bool | `true` | | +| speaker.serviceAccount.name | string | `""` | | +| speaker.startupProbe.enabled | bool | `true` | | +| speaker.startupProbe.failureThreshold | int | `30` | | +| speaker.startupProbe.periodSeconds | int | `5` | | +| speaker.tolerateMaster | bool | `true` | | +| speaker.tolerations | list | `[]` | | +| speaker.updateStrategy.type | string | `"RollingUpdate"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.10.0](https://github.com/norwoodj/helm-docs/releases/v1.10.0) diff --git a/metallb-chart/_service b/metallb-chart/_service new file mode 100644 index 0000000..c3f6878 --- /dev/null +++ b/metallb-chart/_service @@ -0,0 +1,15 @@ + + + + values.yaml + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + + Chart.yaml + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + + diff --git a/metallb-chart/charts.obscpio b/metallb-chart/charts.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..abb1383f99ee8639d46f2cfa69228fefbbb887f5d9a9f27c4092133c548adc90 GIT binary patch literal 141824 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 Ezp`dB+5i9m literal 0 HcmV?d00001 diff --git a/metallb-chart/policy.obscpio b/metallb-chart/policy.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..09b648f40e16e9bd2ec34efe3330313becc9ce053978835af1711318a06d888f GIT binary patch literal 3072 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 +# parameter must be provided to both the speaker and the controller. +loadBalancerClass: "" + +# To configure MetalLB, you must specify ONE of the following two +# options. + +rbac: + # create specifies whether to install and use RBAC rules. + create: true + +prometheus: + # scrape annotations specifies whether to add Prometheus metric + # auto-collection annotations to pods. See + # https://github.com/prometheus/prometheus/blob/release-2.1/documentation/examples/prometheus-kubernetes.yml + # for a corresponding Prometheus configuration. Alternatively, you + # may want to use the Prometheus Operator + # (https://github.com/coreos/prometheus-operator) for more powerful + # monitoring configuration. If you use the Prometheus operator, this + # can be left at false. + scrapeAnnotations: false + + # port both controller and speaker will listen on for metrics + metricsPort: 7472 + + # if set, enables rbac proxy on the controller and speaker to expose + # the metrics via tls. + # secureMetricsPort: 9120 + + # the name of the secret to be mounted in the speaker pod + # to expose the metrics securely. If not present, a self signed + # certificate to be used. + speakerMetricsTLSSecret: "" + + # the name of the secret to be mounted in the controller pod + # to expose the metrics securely. If not present, a self signed + # certificate to be used. + controllerMetricsTLSSecret: "" + + # prometheus doens't have the permission to scrape all namespaces so we give it permission to scrape metallb's one + rbacPrometheus: true + + # the service account used by prometheus + # required when " .Values.prometheus.rbacPrometheus == true " and " .Values.prometheus.podMonitor.enabled=true or prometheus.serviceMonitor.enabled=true " + serviceAccount: "" + + # the namespace where prometheus is deployed + # required when " .Values.prometheus.rbacPrometheus == true " and " .Values.prometheus.podMonitor.enabled=true or prometheus.serviceMonitor.enabled=true " + namespace: "" + + # the image to be used for the kuberbacproxy container + rbacProxy: + repository: "%%IMG_REPO%%/%%IMG_PREFIX%%kube-rbac-proxy" + tag: "v0.18.0" + pullPolicy: IfNotPresent + + # Prometheus Operator PodMonitors + podMonitor: + # enable support for Prometheus Operator + enabled: false + + # optional additionnal labels for podMonitors + additionalLabels: {} + + # optional annotations for podMonitors + annotations: {} + + # Job label for scrape target + jobLabel: "app.kubernetes.io/name" + + # Scrape interval. If not set, the Prometheus default scrape interval is used. + interval: + + # metric relabel configs to apply to samples before ingestion. + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + # relabel configs to apply to samples before ingestion. + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # target_label: nodename + # replacement: $1 + # action: replace + + # Prometheus Operator ServiceMonitors. To be used as an alternative + # to podMonitor, supports secure metrics. + serviceMonitor: + # enable support for Prometheus Operator + enabled: false + + speaker: + # optional additional labels for the speaker serviceMonitor + additionalLabels: {} + # optional additional annotations for the speaker serviceMonitor + annotations: {} + # optional tls configuration for the speaker serviceMonitor, in case + # secure metrics are enabled. + tlsConfig: + insecureSkipVerify: true + + controller: + # optional additional labels for the controller serviceMonitor + additionalLabels: {} + # optional additional annotations for the controller serviceMonitor + annotations: {} + # optional tls configuration for the controller serviceMonitor, in case + # secure metrics are enabled. + tlsConfig: + insecureSkipVerify: true + + # Job label for scrape target + jobLabel: "app.kubernetes.io/name" + + # Scrape interval. If not set, the Prometheus default scrape interval is used. + interval: + + # metric relabel configs to apply to samples before ingestion. + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + # relabel configs to apply to samples before ingestion. + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # target_label: nodename + # replacement: $1 + # action: replace + + # Prometheus Operator alertmanager alerts + prometheusRule: + # enable alertmanager alerts + enabled: false + + # optional additionnal labels for prometheusRules + additionalLabels: {} + + # optional annotations for prometheusRules + annotations: {} + + # MetalLBStaleConfig + staleConfig: + enabled: true + labels: + severity: warning + + # MetalLBConfigNotLoaded + configNotLoaded: + enabled: true + labels: + severity: warning + + # MetalLBAddressPoolExhausted + addressPoolExhausted: + enabled: true + labels: + severity: alert + + addressPoolUsage: + enabled: true + thresholds: + - percent: 75 + labels: + severity: warning + - percent: 85 + labels: + severity: warning + - percent: 95 + labels: + severity: alert + + # MetalLBBGPSessionDown + bgpSessionDown: + enabled: true + labels: + severity: alert + + extraAlerts: [] + +# controller contains configuration specific to the MetalLB cluster +# controller. +controller: + enabled: true + # -- Controller log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` + logLevel: info + # command: /controller + # webhookMode: enabled + image: + repository: "%%IMG_REPO%%/%%IMG_PREFIX%%metallb-controller" + tag: "v0.14.8" + pullPolicy: IfNotPresent + ## @param controller.updateStrategy.type Metallb controller deployment strategy type. + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy + ## e.g: + ## strategy: + ## type: RollingUpdate + ## rollingUpdate: + ## maxSurge: 25% + ## maxUnavailable: 25% + ## + strategy: + type: RollingUpdate + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. If not set and create is + # true, a name is generated using the fullname template + name: "" + annotations: {} + securityContext: + runAsNonRoot: true + # nobody + runAsUser: 65534 + fsGroup: 65534 + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + resources: {} + # limits: + # cpu: 100m + # memory: 100Mi + nodeSelector: {} + tolerations: [] + priorityClassName: "" + runtimeClassName: "" + affinity: {} + podAnnotations: {} + labels: {} + livenessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + tlsMinVersion: "VersionTLS12" + tlsCipherSuites: "" + + extraContainers: [] + +# speaker contains configuration specific to the MetalLB speaker +# daemonset. +speaker: + enabled: true + # command: /speaker + # -- Speaker log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` + logLevel: info + tolerateMaster: true + memberlist: + enabled: true + mlBindPort: 7946 + mlBindAddrOverride: "" + mlSecretKeyPath: "/etc/ml_secret_key" + excludeInterfaces: + enabled: true + # ignore the exclude-from-external-loadbalancer label + ignoreExcludeLB: false + + image: + repository: "%%IMG_REPO%%/%%IMG_PREFIX%%metallb-speaker" + tag: "v0.14.8" + pullPolicy: IfNotPresent + ## @param speaker.updateStrategy.type Speaker daemonset strategy type + ## ref: https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/ + ## + updateStrategy: + ## StrategyType + ## Can be set to RollingUpdate or OnDelete + ## + type: RollingUpdate + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. If not set and create is + # true, a name is generated using the fullname template + name: "" + annotations: {} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + ## Defines a secret name for the controller to generate a memberlist encryption secret + ## By default secretName: {{ "metallb.fullname" }}-memberlist + ## + # secretName: + resources: {} + # limits: + # cpu: 100m + # memory: 100Mi + nodeSelector: {} + tolerations: [] + priorityClassName: "" + affinity: {} + ## Selects which runtime class will be used by the pod. + runtimeClassName: "" + podAnnotations: {} + labels: {} + livenessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + startupProbe: + enabled: true + failureThreshold: 30 + periodSeconds: 5 + # frr contains configuration specific to the MetalLB FRR container, + # for speaker running alongside FRR. + frr: + enabled: false + image: + repository: "%%IMG_REPO%%/%%IMG_PREFIX%%frr" + tag: "8.4" + pullPolicy: IfNotPresent + metricsPort: 7473 + resources: {} + + # if set, enables a rbac proxy sidecar container on the speaker to + # expose the frr metrics via tls. + # secureMetricsPort: 9121 + + + reloader: + resources: {} + + frrMetrics: + resources: {} + + extraContainers: [] + +crds: + enabled: true + validationFailurePolicy: Fail + +# frrk8s contains the configuration related to using an frrk8s instance +# (github.com/metallb/frr-k8s) as the backend for the BGP implementation. +# This allows configuring additional frr parameters in combination to those +# applied by MetalLB. +frrk8s: + # if set, enables frrk8s as a backend. This is mutually exclusive to frr + # mode. + enabled: false + external: false + namespace: "" diff --git a/metallb-controller-image/Dockerfile b/metallb-controller-image/Dockerfile new file mode 100644 index 0000000..2b48337 --- /dev/null +++ b/metallb-controller-image/Dockerfile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%metallb-controller:v%%metallb-controller_version%% +#!BuildTag: %%IMG_PREFIX%%metallb-controller:v%%metallb-controller_version%%-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN zypper --installroot /installroot --non-interactive install --no-recommends metallb-controller; zypper -n clean; rm -rf /var/log/* + +FROM micro AS final +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.metallb +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE Metallb Controller Container Image" +LABEL org.opencontainers.image.description="metallb-controller based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="%%metallb-controller_version%%" +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%metallb-controller:v%%metallb-controller_version%%-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +ENTRYPOINT ["/controller"] diff --git a/metallb-controller-image/_service b/metallb-controller-image/_service new file mode 100644 index 0000000..11af884 --- /dev/null +++ b/metallb-controller-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%metallb-controller_version%% + metallb-controller + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + \ No newline at end of file diff --git a/metallb-speaker-image/Dockerfile b/metallb-speaker-image/Dockerfile new file mode 100644 index 0000000..6a9157f --- /dev/null +++ b/metallb-speaker-image/Dockerfile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%metallb-speaker:v%%metallb-speaker_version%% +#!BuildTag: %%IMG_PREFIX%%metallb-speaker:v%%metallb-speaker_version%%-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN zypper --installroot /installroot --non-interactive install --no-recommends metallb-speaker; zypper -n clean; rm -rf /var/log/* + +FROM micro AS final +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.metallb +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE Metallb Speaker Container Image" +LABEL org.opencontainers.image.description="metallb-speaker based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="%%metallb-speaker_version%%" +LABEL org.opencontainers.image.url="https://www.suse.com/products/server/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%metallb-speaker:v%%metallb-speaker_version%%-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="l3" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +ENTRYPOINT ["/speaker"] diff --git a/metallb-speaker-image/_service b/metallb-speaker-image/_service new file mode 100644 index 0000000..1ed0813 --- /dev/null +++ b/metallb-speaker-image/_service @@ -0,0 +1,17 @@ + + + + + Dockerfile + %%metallb-speaker_version%% + metallb-speaker + patch + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + \ No newline at end of file diff --git a/sriov-crd-chart/Chart.yaml b/sriov-crd-chart/Chart.yaml new file mode 100644 index 0000000..5953b18 --- /dev/null +++ b/sriov-crd-chart/Chart.yaml @@ -0,0 +1,13 @@ +#!BuildTag: %%IMG_PREFIX%%sriov-crd-chart:1.3.0-%RELEASE% +#!BuildTag: %%IMG_PREFIX%%sriov-crd-chart:1.3.0 +annotations: + catalog.cattle.io/experimental: "true" + catalog.cattle.io/hidden: "true" + catalog.cattle.io/namespace: cattle-sriov-system + catalog.cattle.io/permits-os: linux + catalog.cattle.io/release-name: sriov-crd +apiVersion: v2 +description: Installs the CRDs for the SR-IOV operator +name: sriov-crd +type: application +version: 1.3.0 diff --git a/sriov-crd-chart/_service b/sriov-crd-chart/_service new file mode 100644 index 0000000..6b8f891 --- /dev/null +++ b/sriov-crd-chart/_service @@ -0,0 +1,8 @@ + + + + Chart.yaml + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + + diff --git a/sriov-crd-chart/templates.obscpio b/sriov-crd-chart/templates.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..3995b9fa48d11b897bcfbe85f5cbccf97c6c80c8704b0a4056481bc687b148ed GIT binary patch literal 47104 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 literal 0 HcmV?d00001 diff --git a/sriov-network-operator-chart/Chart.yaml b/sriov-network-operator-chart/Chart.yaml new file mode 100644 index 0000000..538f7e3 --- /dev/null +++ b/sriov-network-operator-chart/Chart.yaml @@ -0,0 +1,28 @@ +#!BuildTag: %%IMG_PREFIX%%sriov-network-operator-chart:1.3.0-%RELEASE% +#!BuildTag: %%IMG_PREFIX%%sriov-network-operator-chart:1.3.0 +annotations: + catalog.cattle.io/auto-install: sriov-crd=match + catalog.cattle.io/experimental: "true" + catalog.cattle.io/namespace: cattle-sriov-system + catalog.cattle.io/os: linux + catalog.cattle.io/permits-os: linux + catalog.cattle.io/upstream-version: 1.3.0 +apiVersion: v2 +appVersion: v1.3.0 +dependencies: +- condition: sriov-nfd.enabled + name: sriov-nfd + repository: file://./charts/sriov-nfd + version: 0.15.6 +description: SR-IOV network operator configures and manages SR-IOV networks in the + kubernetes cluster +home: https://github.com/k8snetworkplumbingwg/sriov-network-operator +icon: https://charts.rancher.io/assets/logos/sr-iov.svg +keywords: +- sriov +kubeVersion: '>= 1.16.0-0' +name: sriov-network-operator +sources: +- https://github.com/k8snetworkplumbingwg/sriov-network-operator +type: application +version: 1.3.0 diff --git a/sriov-network-operator-chart/README.md b/sriov-network-operator-chart/README.md new file mode 100644 index 0000000..86b0519 --- /dev/null +++ b/sriov-network-operator-chart/README.md @@ -0,0 +1,130 @@ +# SR-IOV Network Operator Helm Chart + +SR-IOV Network Operator Helm Chart provides an easy way to install, configure and manage +the lifecycle of SR-IOV network operator. + +## SR-IOV Network Operator +SR-IOV Network Operator leverages [Kubernetes CRDs](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) +and [Operator SDK](https://github.com/operator-framework/operator-sdk) to configure and manage SR-IOV networks in a Kubernetes cluster. + +SR-IOV Network Operator features: +- Initialize the supported SR-IOV NIC types on selected nodes. +- Provision/upgrade SR-IOV device plugin executable on selected node. +- Provision/upgrade SR-IOV CNI plugin executable on selected nodes. +- Manage configuration of SR-IOV device plugin on host. +- Generate net-att-def CRs for SR-IOV CNI plugin +- Supports operation in a virtualized Kubernetes deployment + - Discovers VFs attached to the Virtual Machine (VM) + - Does not require attached of associated PFs + - VFs can be associated to SriovNetworks by selecting the appropriate PciAddress as the RootDevice in the SriovNetworkNodePolicy + +## QuickStart + +### Prerequisites + +- Kubernetes v1.17+ +- Helm v3 + +### Install Helm + +Helm provides an install script to copy helm binary to your system: +``` +$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 +$ chmod 500 get_helm.sh +$ ./get_helm.sh +``` + +For additional information and methods for installing Helm, refer to the official [helm website](https://helm.sh/) + +### Deploy SR-IOV Network Operator + +``` +# Install Operator +$ helm install -n sriov-network-operator --create-namespace --wait sriov-network-operator ./ + +# View deployed resources +$ kubectl -n sriov-network-operator get pods +``` + +In the case that [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) is enabled, the sriov network operator namespace will require a security level of 'privileged' +``` +$ kubectl label ns sriov-network-operator pod-security.kubernetes.io/enforce=privileged +``` + +## Chart parameters + +In order to tailor the deployment of the network operator to your cluster needs +We have introduced the following Chart parameters. + +| Name | Type | Default | description | +| ---- |------|---------|-------------| +| `imagePullSecrets` | list | `[]` | An optional list of references to secrets to use for pulling any of the SR-IOV Network Operator image | +| `supportedExtraNICs` | list | `[]` | An optional list of whitelisted NICs | + +### Operator parameters + +| Name | Type | Default | description | +| ---- | ---- | ------- | ----------- | +| `operator.tolerations` | list | `[{"key":"node-role.kubernetes.io/master","operator":"Exists","effect":"NoSchedule"},{"key":"node-role.kubernetes.io/control-plane","operator":"Exists","effect":"NoSchedule"}]` | Operator's tolerations | +| `operator.nodeSelector` | object | {} | Operator's node selector | +| `operator.affinity` | object | `{"nodeAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"weight":1,"preference":{"matchExpressions":[{"key":"node-role.kubernetes.io/master","operator":"In","values":[""]}]}},{"weight":1,"preference":{"matchExpressions":[{"key":"node-role.kubernetes.io/control-plane","operator":"In","values":[""]}]}}]}}` | Operator's afffinity configuration | +| `operator.nameOverride` | string | `` | Operator's resource name override | +| `operator.fullnameOverride` | string | `` | Operator's resource full name override | +| `operator.resourcePrefix` | string | `openshift.io` | Device plugin resource prefix | +| `operator.cniBinPath` | string | `/opt/cni/bin` | Path for CNI binary | +| `operator.clustertype` | string | `kubernetes` | Cluster environment type | + +#### Admission Controllers parameters + +The admission controllers can be enabled by switching on a single parameter `operator.admissionControllers.enabled`. By +default, the user needs to pre-create Kubernetes Secrets that match the names provided in +`operator.admissionControllers.certificates.secretNames`. The secrets should have 3 fields populated with the relevant +content: +* `ca.crt` (value needs to be base64 encoded twice) +* `tls.crt` +* `tls.key` + +Aside from the aforementioned mode, the chart supports 3 more modes for certificate consumption by the admission +controllers, which can be found in the table below. In a nutshell, the modes that are supported are: +* Consume pre-created Certificates managed by cert-manager +* Generate self signed Certificates managed by cert-manager +* Specify the content of the certificates as Helm values + +| Name | Type | Default | description | +| ---- | ---- | ------- | ----------- | +| `operator.admissionControllers.enabled` | bool | false | Flag that switches on the admission controllers | +| `operator.admissionControllers.certificates.secretNames.operator` | string | `operator-webhook-cert` | Secret that stores the certificate for the Operator's admission controller | +| `operator.admissionControllers.certificates.secretNames.injector` | string | `network-resources-injector-cert` | Secret that stores the certificate for the Network Resources Injector's admission controller | +| `operator.admissionControllers.certificates.certManager.enabled` | bool | false | Flag that switches on consumption of certificates managed by cert-manager | +| `operator.admissionControllers.certificates.certManager.generateSelfSigned` | bool | false | Flag that switches on generation of self signed certificates managed by cert-manager. The secrets in which the certificates are stored will have the names provided in `operator.admissionControllers.certificates.secretNames` | +| `operator.admissionControllers.certificates.custom.enabled` | bool | false | Flag that switches on consumption of user provided certificates that are part of `operator.admissionControllers.certificates.custom.operator` and `operator.admissionControllers.certificates.custom.injector` objects | +| `operator.admissionControllers.certificates.custom.operator.caCrt` | string | `` | The CA certificate to be used by the Operator's admission controller | +| `operator.admissionControllers.certificates.custom.operator.tlsCrt` | string | `` | The public part of the certificate to be used by the Operator's admission controller | +| `operator.admissionControllers.certificates.custom.operator.tlsKey` | string | `` | The private part of the certificate to be used by the Operator's admission controller | +| `operator.admissionControllers.certificates.custom.injector.caCrt` | string | `` | The CA certificate to be used by the Network Resources Injector's admission controller | +| `operator.admissionControllers.certificates.custom.injector.tlsCrt` | string | `` | The public part of the certificate to be used by the Network Resources Injector's admission controller | +| `operator.admissionControllers.certificates.custom.injector.tlsKey` | string | `` | The private part of the certificate to be used by the Network Resources Injector's admission controller | + +### SR-IOV Operator Configuration Parameters + +This section contains general parameters that apply to both the operator and daemon componets of SR-IOV Network Operator. + +| Name | Type | Default | description | +| ---- | ---- | ------- | ----------- | +| `sriovOperatorConfig.deploy` | bool | `false` | deploy SriovOperatorConfig custom resource | +| `sriovOperatorConfig.configDaemonNodeSelector` | map[string]string | `{}` | node slectors for sriov-network-config-daemon | +| `sriovOperatorConfig.logLevel` | int | `2` | log level for both operator and sriov-network-config-daemon | +| `sriovOperatorConfig.disableDrain` | bool | `false` | disable node draining when configuring SR-IOV, set to true in case of a single node cluster or any other justifiable reason | +| `sriovOperatorConfig.configurationMode` | string | `daemon` | sriov-network-config-daemon configuration mode. either `daemon` or `systemd` | + +### Images parameters + +| Name | description | +| ---- | ----------- | +| `images.operator` | Operator controller image | +| `images.sriovConfigDaemon` | Daemon node agent image | +| `images.sriovCni` | SR-IOV CNI image | +| `images.ibSriovCni` | InfiniBand SR-IOV CNI image | +| `images.sriovDevicePlugin` | SR-IOV device plugin image | +| `images.resourcesInjector` | Resources Injector image | +| `images.webhook` | Operator Webhook image | diff --git a/sriov-network-operator-chart/_service b/sriov-network-operator-chart/_service new file mode 100644 index 0000000..6b8f891 --- /dev/null +++ b/sriov-network-operator-chart/_service @@ -0,0 +1,8 @@ + + + + Chart.yaml + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + + diff --git a/sriov-network-operator-chart/app-README.md b/sriov-network-operator-chart/app-README.md new file mode 100644 index 0000000..7dcf664 --- /dev/null +++ b/sriov-network-operator-chart/app-README.md @@ -0,0 +1,13 @@ +# Rancher SR-IOV Network Operator + +This chart is based on the upstream [k8snetworkplumbingwg/sriov-network-operator](https://github.com/k8snetworkplumbingwg/sriov-network-operator) project. The chart deploys the SR-IOV Operator and its CRDs, which are designed to help the user provision and configure the SR-IOV CNI in a cluster that uses [Multus CNI](https://github.com/k8snetworkplumbingwg/multus-cni), to provide high performing extra network interfaces to pods. This chart is expected to be deployed on an RKE2 cluster and only meant for advanced use cases where multiple CNI plugins and high performing network interfaces on pods are required. Users who do not need these features are not advised to install this chart. + +The chart installs the following components: + + - SR-IOV Operator - An operator that helps provision and configure the SR-IOV CNI plugin and SR-IOV Device plugin + - SR-IOV Network Config Daemon - A Daemon deployed by the Operator that discovers SR-IOV NICs on each node + +Note that SR-IOV requires NICs that support SR-IOV and the activation of specific configuration options in the operating system. Nodes that fulfill these requirements should be labeled with: `feature.node.kubernetes.io/network-sriov.capable=true`. + +The SR-IOV Network Config Daemon will be deployed on such capable nodes. For more information on how to use this feature, refer to our RKE2 networking docs. + diff --git a/sriov-network-operator-chart/charts.obscpio b/sriov-network-operator-chart/charts.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..829a2b43ad300e0c36883a1df78a297e772ffb6a170d27eae45cf79ec982f851 GIT binary patch literal 90112 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 literal 0 HcmV?d00001 diff --git a/sriov-network-operator-chart/templates.obscpio b/sriov-network-operator-chart/templates.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..036de0ba4fc00771549e1ace83e428a12c4e5b298880775a34aa9d7ac9cdf305 GIT binary patch literal 28160 zcmd^IZFAd3lJ?i*ub41S#m<=&Nr{rIs{24ww4;keDWv?ewY!A^!J&i|2rvMsmv!>r z@9B8~1|UE}vgA0osOAwe4wZwzJ*B&wkt9q2I0cY*+kl zwdHp_+1;IXXM4LH@qA}b{>F0!r+&+C>Hiw6)r$Fi;n^{dwj3VDbKAEsct{_k=AAwF zo;`c^`E!H0GiLi!_M-X0_Le+q1`8hAaS%4SZ%;hlo6g-Ras$5~_;DC`9uHrpz=X|G zm|wESAAi&oN)Y>(FYz9s;K$19kDt!Zm7mhH`uyv*HauJ|841p ze3}JgZp4x|lV!}PpINZH!XUO|$k$omxz61I z>v=c!UG!KS)`Af7C|E*|qK51Li#t%2N8t5ZcDS;08*E@=Lk$}U+r_orGwnh+v7M&9j4y-G{kIUG=GA^A?UAw&BQ(vZ z9416Sp1aWR*q$#An7{Nq%#pMlkbBp6yycX$da)I0&Hzuqb=D-~P|bue=GhbOMI`RR z&~E5NLQ@yNGatr|`!U<0?!u+V1(pT_FW!a0av{Ew8a7}_fuF(9DnXapMQ;|tG!pOV zi?T531I+RwaQ!%ag0&=aqZs{O2i|hd9nW^>>1%$CH|bX=@MrGD++L)QB2L0DzhCok zVo>?xPd|c`!U5O|g`!{xQ@-$myLqPLsm6NEg7@M~ViWyM(4rf~2V!Xn7&64FS9z8WtQ!!27E%V!yB2KTmRu5WwpzcIxE zI>(IV0;_2$Ri#>2*0JJ=?KoKN4VfXePQ``3O(5vtb0JY{WJU@fxj%k%>CR$UfHGQK ze-_$N94?)B2?;A2y*WP~G(f=64BgnVbBS+-bM>PW1R;nw%@7HBp)UR?e2hrG&oQ6I znRhHoSq{gm%+N`5mK71nsD{)T5JxbZe4lT}a1}7BWHQzok*vX}j#RKxE!~x5O-ihx zs;aRcOlj$XcQ54Q9u#nA8M^UZdG9#`L0*>Y@e4jJlSCM4ffAAt^V=A|pd5Cx5aeiE zMx|DveBqHomn;oAl%}?=w>yujVI_i7J_=*K%Z(th;c})I!b&`z2CusE_FqMFH_v>| zr|goCSlOrS*m~>y0H1PrdOjF832M4L%COEr)m$)J>quo<4h!>K)ISIY^u79MN(r5j2Hsh18}?QIY;dpgBFJHV0*-%~D5 zwAE&T&n|--76%N9$Ht?^(dh@Kj7YL`dsPehjE8_aV3%LncS|65P;f2N9@wR=4`^b4?g-7^1v(+Vzqycn&^;& zV?;)_kqw^m#vQjqb`1vzY`+sBlpELcL_lJ~nb?ZLVq#+v%(0w1p!KfF&My(bh%SSr zH`S0fTZF+Bt^{U_Vb1_>Ic%~svA8SwsZoH2X3vaa2x3>8f^NOxQf#HY7d~e8T_V<0 zT}P5o(FJV-j3J{G7S*#N4Be?R>3y+BZA!zQ7rRpL zE_JcT)NK}7fpkv!%wBp`r$$E>WyJPKMWtjYG9T5oSL3;n(ko#m7-BUP_thkRl;OmO zBBPnU!9uc@nUed5!lxd>uZ7JPaW!Hu!@5XOfz`J%DnT8DwtvCd^Q%|v`87NEAJ+Wi zkI$dsw)*jm)qjW%*gx?9KM)^&enk-3SO|1jSx6aENxpc&#W5ToxLAIw1pRvE!>;KGck?>4x)YJ><^y491xB4qqr^o>P z7C`~}ApCy%Aa^mMnHec4>4U;@`7VCCPvb3)vjUR1JQlexDMCftV+F030BG9Z>uD@4 zkBbIP45~1oB&HA%Gjg$?Jl?{QQViGeUHo%q2;~$}s#iukj&0|XB7zOrT^E5ma-1vm zQYyp+{TT`oz0#hZ8L*PVlgLQnuoCkf@(T!$G!rUdUC?KJzN8}&`0LV)XKaPwt?*#i zfK(x>blEGSNDhm!_2ZmlMqHm~=*>hd9*$b#+=wg}H*Q5DxyIa!G~4NZ6z+e zU}AesVW6;e3~3RKn)by73nzZo<}>y(i?Vt z$b7)sPz)pniEXdk*dl7^TplOK{d6uM_dQvUKu<5VCwGuvsAQPU+?)jnsiYl>kM+WLPtC0X>c; z?U%9v0D;_is);5Xaqu^!vSkt+_VsF(S(pgPx^C^6kmI|wv3{bvldX$76k!UDK8YXb z2gSpTu^vnBJxaSY9_n5nFi5ps>dB+>p~&TWh)U1^5Jf@OLVVZv>`0`1!JI~Sh*8fQ zG*Jx)FDbY!Ge#tfjL?}oN6z6HQe9*m));F3jX7Q!&(YzxJY>qQMw)J;l4vx~S0*9z z0KQ&~=nN7Ubg#52mD=@CMp4g#Qei*RsIcIbrQ&&(+O^%utRM818KjYX3Cj>flrcgA zd9VgBwl7kK5E1GaDIFO-M6ym{G9#2+|75%{{g9lq-;fm=8=R8woW&AWtJRW8EGhgP znKU7C@9^rxHPCbaI!}^h_{ZLP|7UC1I~k16di{aXgpgu;y5w)eV4iJEuVyayrb+T3 zJxPDWyE8k!JYYJnvq{~FJcUdbdfvw)oQqlg;gNN8(tB4(#uv@3;C~+hiA^(`0Itkz zDx{Lwqv6}5;nADk@bC%gb|+(!oGO$Xpc`pF9DF$H53IA}_wSB|Ps#E_ifr*SZ+YSR z)p(z2v1TB{!THD2(J$6$Fg|@h>JP@&(eQr<{qxh&6OAX)P#xjlIG)uOYsPbWHW>AY zdeX&=jwm%O%ZSdvX7x$)sDBDseP(2V|_{dFfBW0$P93AvujLhiG;DV&fXs% zTjN20G&moZ_V6#HhO+uAEPd)ss(fLWhFpu%pT0JnogS7d#pA6_8O9}JKRp~gP2c2= z3ul`g#KOKugX2MOJg`0tM&qN?VFo56I(oCzTP!}v8y;oilCH9EVD`^?=RcQY&7WK% zn*YZ2X;Cl3-amdnJ|B#%^S_;y7_cHiS8@4s?3YZ$xzJCd7fA#jrbbp7n0RQx5T1`tkB`Apt3Mc>AH6;5_mD(nCDvD}QR$p#jsw>dWoE84Wf}&}b?RlB z!zH5cL2k0teFbuLVu4BSy=EuF2>Nm&??PqIy&p7fG>6tnZwQxhWDSPBH^+m+>LOhz zOB<>Eo&B~9;uT@Vy@1TKd(LPgfc>7;ADtHsqS)3+$-*U^5?@@p`9+$ydH7YNR?gcM zE&(yeZaN{wZPTBJ$n>|$fg(jnM_R-IQj^TqHxm=d#w0}|WaZp|_G^dYjQH6Ulhk*1 zjF@EhKv$;Sn7IK)`j)uKq(T{g#ZX^9j9GnX!aFTJ`Ac@QUn5?b$sH82=*n`^-PSpQ zo8)9F#mS6aTgt(0kWGx5@dB4tKY!l(srF8#Y_jv?aW+FUo5DGSojjmCTbRZULnM^r z=smu)V`hg)(&P)=<3iqNggl=RiL)`?=R#5_GIC!D2%E*B>s%qsSi`v>E_;Za-F{E> z83~Xydo=L9JEVr<5~#31&mCJNBjMNYNaPd=UF-$G(Y)+dST5pTXWP5omlB&r$Z+!r zvCg_^kX-j1@Vq{>e8j+FzXsbLx1@>s% zNG|z4FW^Y>GR^)HoND$VK$wQf?hf~z1WK7kvXW)P5NVu$&KRCMKFzrvigxz$8LQ17 zBDznDeUd?hjzmkej6LMgggBMN z;w>=b*a)@|h*)?M5I6!UqZQ*y`K&jY`Q*`Wg5f$pNE5kw;rFk@`dW6a7i)KA8@|)h zMFlq4@Q$usV662j!H6U6826Pt4@U-5ooM^La^o*hEWkr1{tFK`*Ov=cFHb~3kpNaV z@*>2&|9bu9OV$!H`@J|?dM;`Lkibuo*JivR1FBw18>}WdlMX}&ou?nh>a4TQW;VIj zl$b8DS4JX2r$=ud36VlW8M5+*`>kE5+iJ0cUOgy=;ajIp5N7D`jruK1q)7YVf?A{h`$nKAH@VNB&J`%PsvTgYnW zx3JFf9Z3Bv4@ZS;;A*vZll5!dKkuIsxA00~HMU?iym1KS0M5(B7a&S!Gq|ZV4Z-vR$%g+GpHgmkRTf zu_CH_J=z?>w-ohIbbwN?xXr?is?3uYN%N{*aUGSy#)h|rH5R1gLJ~%emGxAVBGP^- zU4W8H{!0p=Ji~~ zm@Gc>z_KMx6)tRg0gk=ln&*m`WNOOL=3It93aDJIB9pS`v7>yIXT7u-PNf0dXBLs| z@&sjYzC6s74YJ&4L|M7?Ro$R9-s46I{X!fMl-0GpKDE@E?EiA9z2{KwGut`&6>A!~ ziCB=uIzS0_4=|BrFCS+uz)jL%u0z~~w%>?FiHm?bRf6Id(rkUXI%&HhgZEV!EECsG z7d8@4YPuqqjO;$tEIN`GnwF+x_swuX5*Nrs*3I4TLnboUC(z|OHKO?DHu`b;%51}p zapiUDYsi49(^9fF)eCt#8PK$RO&Lh~{0cH)_EjbW+W*c*XHdf+6Xz9i`^vufUe&v} zZISy-v0j~Ciu!~i2LshTlqX(z79h8jC-$Pi9gUWYMGzvC+wfhd;i5>DHXKJNN#a@V zPK#TgK7H70w~)ZN-`d}0?e4yf|8^WoT{NIN-FMdb?OA8v0Gt#7wp;J4Pe4e}DePV+ z4|{tt;g$gIc8%V5w*k1@HF_6-`vVLt+k4Xv+un1gD?ICT%&7ugYaLuNrvTi}13KL5Q$e$dYoj)f z$F0GByVdCbdf4k&9q~(()9${8MC|XsHpnS%4IUo$c8qr5N9A_O@X;TnwL&|iBS=7L zgM}SlVRW7Ce$rr{6h}1}UZehnZOy≧!=j#$NoXL4#;_C!oL87XR(g;EO?zKN-MX zYOz}i+%-V=2z0+3)Ee9x(4<9ep+$vMkiuz#!M#>n7=>a`>(E3zC1`O8ss#Gjgof^{ zgWgNY=wMC?Ku^whI{T30H}~m3C(eYgdeHyR)-nAloiP zwwFcbB*@-`fjvdOu{H5;W9v=-q`SA%-myBju%R@R9lpcbyHiZn?o@DerNJJwdmjxD zze!u{bz6|HmXL#Aak<`gtl#*QTfZLfP;DQpD`8uEgt$vx>=}T8LHtLelWWnoTBWUaXhL?{)at|zQ5L|nPW$Hrr1YGB>LCC2_3kGj z$$NWKHbJn)qS zE&{ev^zD|3AE^LrV#_AvEMyb%lf`y$iyJ4yqrOV(r_F+N^9=_h>r>3Y{p$4xUQes$ z80a%*!>6z=xrex~IyF}3#)I1hZO*9h5^Y6TFq5%PQ9Y>SOfxxxPqq)#G%Yr)k9JGW zbklrCYIcfK*U&{>(BE+myTnl>7Bu?k&c{pKK)Gf0MxA(Qa1fty;@zi`qnwUm)k!iH z5WPbt5GoKM+kJ{Uo(nOiX6++RsR_4$kEsU=&eFNIV^bBOD8R^nL4m0dDuVNF!3mKu zFQdYqJ9p_+9B0WQwEF_bzr?Y_;h114*iE6hm(AMI3}@)FQjtIcKaMU|L@HD)p1CoO zpHUbIr^)CXbfObR#4Box50Y1zo)%1{;5YFHJ8ivJ(k~PCDv;9mRoJicsi>>xVkmT+ zq_}^-$xaDQI3zJ<0+f2*vk&h{sXi_KA!_^(<<5lFFsfjbHKPnEG(KhoQXUEj_K;>l zyvbtGEQ{Gzq9dWijj^)Sfz=rojZ!_!kF1}T{8Ht=KB&%rr_2tI&cEybjS~s0et&I4 zEjEloUU92z7bLi(7}jUrj4rptAVl0Ey%SV;6{o3&D@-U%=_YW*pTup!V{t_gGp)sk z)I#zmn~w_v(WJ6+QtL&5W63WWRat3b1PzSIU&Vr=b-3g;ZA_4WXGS!~vH-azi%x%_ z2U2)&C?SZyFNgDkCR4CV5lLeumJ^`j+$t7v7)IGVnNbbVq;N>eKjkVwR)E?RS3iWWxDA}JnYlK|&`K_8$eOGGHHHLe z29p`L66HUu`JV1tG2q zOM;=lWTMO~+9Z*i)L$=OtJUH$K9$@pk2j6{8}w4y+^*1vIG?CJe^6d|q!ukF^j8+d z1ysl*_;Y}wo|&{@eayNks;uEEtqnP1^KtXXn%4DMzH&qa6Kh|+ElG0E2H;9 ze=EnUcP16}z9@HOMd1-Umy(Hk3ta248O2^JE`{fAo3u42pViJ)9?c}&Ln|MmZCX<| zX*5kl#xfEApWGyoEqK)FUMJ(<^2DyEyBg)|r*M4_RgBW3PnLFS(uAX`wbWCkDP73q zT3Xb_dOj7kV9DQhS+~9_8%lw>%|FUV+6cE + + + values.yaml + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + + Chart.yaml + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + + + diff --git a/upgrade-controller-chart/charts.obscpio b/upgrade-controller-chart/charts.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..9d4e3e8f3b61918405b47362bc1077cf1f516478ad925232703c02867adb03a9 GIT binary patch literal 15360 zcmeHOZFAek5%y>OiVK^WS`Gn{k}KPs@nk%*(|TgJ8A(ptSZZ&>u%Gad&^o)>ZyM{^OZgIIV$9?E;bpu$1z_33d?q$z}2 zaTpb1mBqXe^4`5BKF74^@q}w0?DAyNbX6mWuhaASAZ+cnPXFCW4mNRmB>9+^4jmXYoJ*__uX7qQ?{ zcq^WOI9ZTPX~ub;2WC~g!*_94h=e#P{p-ilkJ8c2XeFJqqX3}aLVDIN9SAq6tyfe7)=oV7vA zGZf!Uc$_WyM1iD*OR-W6A>0`QnB>`aFTX!N-x^@7A)8wiut>6EDVScx=4q}Tx9MO2 zZ8oOOvK-sxMI;Q4^p5^&M_rpuBMlt>>urrPf^RemQ*rJ>qh(kjLPIZ0=fDp*=OW96 z6i_V^5PHq=|LkWG6#fqIbCDAuCYNa$hoq5sEC3@&7fJN%20Hdk75T~x6)Z{$ktaN6 zH#{!I5L?jkH2+q74M4OnE0Y>TwM6dX@;c200MFAYTNXtor=!s#Dy%9%Y*!_Oemx?y zkw>$#NOL&~#f^wZGFo^%50+7Z-O5~yz-~_wlMoZ6zY6~ZrYPl+TZn3lA^|d4G=`Ma zH{SFg7U=>B4rdym=1+AdWa~(%&R(2f;H}0;pPN3SYHACI>}e5a!6-oziOuGDx>8U@ z5@somMm+>^1R-FuoUNjQ#Nw9{28a%Fm-VMSNz#JN1S>OG6A|uCd6}?NsA7BybGAGB z8=oDWk@V<5_CCG3VXVugK5otI#^G9|9R6`+%T%#!k5~p(*s| z)IvRM|0gLXCU=AL?5kr)v0fAZL7`+ zjESUla>(NEvAf47Kb|~v97r{dlRxd5x2MvsqU5E*p4kx1Zd3o%z<8eXwG+8LjLBX& z{kqN|STCP{P55qK3X{!_GN*3?D%7c0;m`0H7mC1FI-X`8W5-})eMP3RA11%_( z9d^;EC+;P(dTJ<;%!DEd*1tP3m5_c?icCJ$XH7qtQ%HkS86ihle^PXH^3o6TlgZE? zChr4z({HsjKu?!xdSrYr>tzAf4!aj@pBW>Vy_QOEtfzIkmVTaij0~0o>mEG1p(B3U z1njNwJt|?;!yw13jahCP@5Im?%lD>|=3L$y7rBW;=%-6Y2JjYKCrXq+l{0CR@q(Ou4>DpGF#+46dp>=$?s67G~3Z`tu;#2%%~`#s#u1B0culJN(HNPDvw49 zRhPVgdsG6MvUl&8f2Kvw-_#A+`}ZRZL`e{rpwvt|G046QgQ}$0WTc+u?dV8zCTd$xiFQ;iTj~4bF%90SrC}^Y%iLGtAQLpI? z%~lh;NHM5Tr3jl569(){qDWgp`ak2va>}TT1{14`v{Z4RCnEGr+(hEmsBBGgkyKOo z{y`<%7y=hASccArbb zze!o29P}Sv8m`%e{<3gwva)WKh;-$%VI=u17SD6sm{v}uTH6SZp4TQbDs02M;oj(W zDRB9atBcn>jg_Ytba%rjbQJj(IvRMA0yGP0Uwci2djf+_%SAzdX&Any!1m-78t$+n z#zywDG{ya?_8s+6`mRxKV+D=sxXr!3C9b1o`p;FGXz;k@s*YBx`|XP5C_Jc(T6X@s1&Nmxkv3^y>;j8Tz)GuD5O%1?zx;puKMWNZamUd# zgLwbgANxmxHYl3*)^m3s$Zwd`)*J&g5h-v_LR*`^b@W{-0qd(xQmZ(3=vm{i2d5T{ z@+NQ&ge}^6Vr}7Yd&#&`f8Ce>6Hw+kZZx+r)lx`VvAQx<_u1%pz}>078}~00bjn;N z7j)5$qbku&fN#`)fI6tMc&!ja+!9jb0qi5kb$kL-h>HaVF(I*2HC&YlF`xD>CE8*v zTYSd8N!zWO5vt*3qW<9)C=-~Rn&Z;=y~9{Rbd5$JL)DLQkxTowVyX)jI?Ywx8W7*~ z&(iWsUnheN8<^ix8M+N`!lrc#xPd9V96Yt?L}IR z=>M35vpH%iD(tw3x-Kaj8tsT@G~`{VHvgp&R$v>YSR1-g39~qmmQsfbnFOtD6uEHJ zc0h8QUADw%o!6a72s;qHCTf!snxDsO>ZPgngO5)ZXk0<0M2%3|A5c?^y0sb7LPQ-T z>Y)TjtmWpjwA2=|IzBh?PEuxU<;*O zhDP_Y6~B8Wk_8o^j*lLlJa&@12g_`g_pc&R6>_M&6WspNz6%xHs~d9W+x8-VvDsNm z9ptPgmA7y{5&_N(T~i?Y{o3Hek8&rN{*)M?;2II3?4&uI%mI zmES@PAUshTQNtAP=Eh!Wfpfc>31^FkB;28Z7<e;8{cEZd^fdK&`M-_Mf-UydSvt>(zbp zW$ZoqaX7ttPu;^U3(Zg4ZL zuer!$0|M9{wrIzMDQdUwIR=xDVUyyd6Ttp{fZ&jlZ4?y>T@z2JF`f~v`z9}--uh8T zmu%&qsr$cr+Wv+X`!%aF5?|r5t#0UtLwhd|@>EiHuW4?^?Im|@BRVI|r zA~^PZT~P#I0>?e;GWb|IFJpFJ3c-A;2JZTqL+wrYEQ-;gO?`bi>D!0a@xup%Ud;?#z4f$hAd}!< zJvjWjvI$p*A7K&PWeUw!uO%IDknh>J&^fNXmvdN~8|N^|aOey+FlS zqwYp|BCdxs?^>)|iyMr2Dh_YiW*3m&7~pnhldnE6ksU}0#c0;I+H7;f;JoTs+{md+ z_03kfcCermR(X!{-nCi~s;me)H~1k)tQA|^47{e)k(%s=kG&-R!?a#hLAfQYid$iZ zf@?$wRruUWpmAO`>U{PZp-Z7^d=&7hU!jn3qtbXAb$vmmrrs4hf{$cg&dd2cy6dIf zkwc%qIjw+LUPuKJ#e6DbQ9>NYH8UPS+bCqCSP{!Vm} DmB3## literal 0 HcmV?d00001 diff --git a/upgrade-controller-chart/templates.obscpio b/upgrade-controller-chart/templates.obscpio new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..c619dbc6961143b7d8de8e011c4c4f7de40271cf8df71cde346a23656836a5e0 GIT binary patch literal 12800 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 literal 0 HcmV?d00001 diff --git a/upgrade-controller-chart/values.yaml b/upgrade-controller-chart/values.yaml new file mode 100644 index 0000000..91ec22e --- /dev/null +++ b/upgrade-controller-chart/values.yaml @@ -0,0 +1,91 @@ +# Default values for upgrade-controller. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: %%IMG_REPO%%/%%IMG_PREFIX%%upgrade-controller + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +env: + releaseManifest: + image: %%IMG_REPO%%/%%IMG_PREFIX%%release-manifest + kubectl: + image: %%IMG_REPO%%/%%IMG_PREFIX%%kubectl + version: 1.30.3 + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: 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: {} +podLabels: {} + +podSecurityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + +securityContext: + capabilities: + drop: + - ALL + allowPrivilegeEscalation: false + +webhookService: + name: webhook-server + type: ClusterIP + port: 443 + targetPort: 9443 + +resources: {} + +livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 +readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + +# Always keep the cert volume first in case others are appended +# or adjust the certificate resources lookup. +volumes: + - name: cert + secret: + secretName: webhook-server-cert + defaultMode: 420 + optional: false + +volumeMounts: + - name: cert + mountPath: "/tmp/k8s-webhook-server/serving-certs" + readOnly: true + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +crds: + enabled: true diff --git a/upgrade-controller-image/Dockerfile b/upgrade-controller-image/Dockerfile new file mode 100644 index 0000000..92d0f99 --- /dev/null +++ b/upgrade-controller-image/Dockerfile @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: Apache-2.0 +#!BuildTag: %%IMG_PREFIX%%upgrade-controller:0.1.0 +#!BuildTag: %%IMG_PREFIX%%upgrade-controller:0.1.0-%RELEASE% +#!BuildVersion: 15.6 +ARG SLE_VERSION +FROM registry.suse.com/bci/bci-micro:$SLE_VERSION AS micro + +FROM registry.suse.com/bci/bci-base:$SLE_VERSION AS base +COPY --from=micro / /installroot/ +RUN zypper --installroot /installroot --non-interactive install --no-recommends upgrade-controller; zypper -n clean; rm -rf /var/log/* + +FROM micro AS final + +# Define labels according to https://en.opensuse.org/Building_derived_containers +# labelprefix=com.suse.application.upgrade-controller +LABEL org.opencontainers.image.authors="SUSE LLC (https://www.suse.com/)" +LABEL org.opencontainers.image.title="SLE Edge Upgrade Controller Container Image" +LABEL org.opencontainers.image.description="Edge Update Controller Image based on the SLE Base Container Image." +LABEL org.opencontainers.image.version="0.1.0" +LABEL org.opencontainers.image.url="https://www.suse.com/solutions/edge-computing/" +LABEL org.opencontainers.image.created="%BUILDTIME%" +LABEL org.opencontainers.image.vendor="SUSE LLC" +LABEL org.opensuse.reference="%%IMG_REPO%%/%%IMG_PREFIX%%upgrade-controller:0.1.0-%RELEASE%" +LABEL org.openbuildservice.disturl="%DISTURL%" +LABEL com.suse.supportlevel="techpreview" +LABEL com.suse.eula="SUSE Combined EULA February 2024" +LABEL com.suse.lifecycle-url="https://www.suse.com/lifecycle" +LABEL com.suse.image-type="application" +LABEL com.suse.release-stage="released" +# endlabelprefix + +COPY --from=base /installroot / +RUN mv /usr/bin/upgrade-controller /manager +# Use uid of nonroot user (65532) because kubernetes expects numeric user when applying pod security policies +USER 65532 + +ENTRYPOINT [ "/manager" ] + diff --git a/upgrade-controller-image/_service b/upgrade-controller-image/_service new file mode 100644 index 0000000..0041dd1 --- /dev/null +++ b/upgrade-controller-image/_service @@ -0,0 +1,10 @@ + + + + Dockerfile + IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix) + IMG_PREFIX + IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo) + IMG_REPO + + From 21086b77bb3a012ac0888e2810f0c7baf1f8493999571eb4011bbda0206657aa Mon Sep 17 00:00:00 2001 From: Denislav Prodanov Date: Tue, 22 Oct 2024 10:51:51 +0300 Subject: [PATCH 3/3] unpack obscpio files --- cdi-chart/{crds.obscpio => crds/cdi.yaml} | Bin 356864 -> 356467 bytes cdi-chart/templates.obscpio | Bin 26624 -> 0 bytes cdi-chart/templates/NOTES.txt | 2 + cdi-chart/templates/_helpers.tpl | 62 + cdi-chart/templates/_hooks.tpl | 47 + cdi-chart/templates/cdi-operator.yaml | 671 +++++++++ cdi-chart/templates/cdi-uninstall-hooks.yaml | 69 + cdi-chart/templates/cdi.yaml | 21 + cdi-chart/templates/crd-uninstall-hooks.yaml | 55 + cdi-chart/templates/crd-upgrade-hooks.yaml | 80 ++ cdi-chart/templates/namespace-hooks.yaml | 56 + metal3-chart/charts.obscpio | Bin 189440 -> 0 bytes .../charts/baremetal-operator/.helmignore | 23 + .../charts/baremetal-operator/Chart.yaml | 6 + .../crds/customresource-baremetalhosts.yaml | 1148 ++++++++++++++++ .../customresource-bmceventsubscriptions.yaml | 85 ++ .../crds/customresource-dataimages.yaml | 75 + .../crds/customresource-firmwareschemas.yaml | 90 ++ .../crds/customresource-hardwaredata.yaml | 211 +++ ...customresource-hostfirmwarecomponents.yaml | 178 +++ .../customresource-hostfirmwaresettings.yaml | 164 +++ .../customresource-preprovisioningimages.yaml | 183 +++ .../baremetal-operator/templates/NOTES.txt | 16 + .../baremetal-operator/templates/_helpers.tpl | 63 + .../templates/certificate.yaml | 14 + .../templates/clusterrole-manager.yaml | 186 +++ .../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 | 30 + .../templates/configmap.yaml | 19 + .../templates/deployment.yaml | 131 ++ .../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 | 90 ++ metal3-chart/charts/ironic/.helmignore | 23 + metal3-chart/charts/ironic/Chart.yaml | 6 + metal3-chart/charts/ironic/README.md | 24 + .../charts/ironic/templates/NOTES.txt | 16 + .../charts/ironic/templates/_helpers.tpl | 88 ++ .../charts/ironic/templates/certificates.yaml | 56 + .../templates/configmap-ipa-downloader.yaml | 12 + .../charts/ironic/templates/configmap.yaml | 86 ++ .../charts/ironic/templates/deployment.yaml | 367 +++++ .../charts/ironic/templates/issuers.yaml | 16 + metal3-chart/charts/ironic/templates/pvc.yaml | 24 + .../charts/ironic/templates/secret-tls.yaml | 16 + .../ironic/templates/secrets-basic-auth.yaml | 62 + .../charts/ironic/templates/service.yaml | 39 + .../ironic/templates/serviceaccount.yaml | 12 + metal3-chart/charts/ironic/values.yaml | 153 +++ metal3-chart/charts/mariadb/.helmignore | 24 + metal3-chart/charts/mariadb/Chart.yaml | 6 + .../charts/mariadb/templates/_helpers.tpl | 64 + .../charts/mariadb/templates/configmap.yaml | 8 + .../charts/mariadb/templates/deployment.yaml | 85 ++ .../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-chart/charts/mariadb/values.yaml | 67 + metal3-chart/charts/media/.helmignore | 23 + metal3-chart/charts/media/Chart.yaml | 6 + metal3-chart/charts/media/templates/NOTES.txt | 22 + .../charts/media/templates/_helpers.tpl | 63 + .../charts/media/templates/deployment.yaml | 66 + metal3-chart/charts/media/templates/hpa.yaml | 28 + .../charts/media/templates/ingress.yaml | 61 + .../media/templates/persistentvolume.yaml | 18 + .../templates/persistentvolumeclaim.yaml | 14 + .../charts/media/templates/service.yaml | 15 + .../media/templates/serviceaccount.yaml | 12 + .../charts/media/templates/storageclass.yaml | 9 + .../templates/tests/test-connection.yaml | 15 + metal3-chart/charts/media/values.yaml | 117 ++ metal3-chart/templates/NOTES.txt | 3 + .../_helpers.tpl} | Bin 2560 -> 1772 bytes metallb-chart/charts.obscpio | Bin 141824 -> 0 bytes metallb-chart/charts/frr-k8s/Chart.yaml | 11 + metallb-chart/charts/frr-k8s/README.md | 96 ++ .../frrk8s.metallb.io_frrconfigurations.yaml | 462 +++++++ .../crds/frrk8s.metallb.io_frrnodestates.yaml | 65 + .../charts/frr-k8s/templates/NOTES.txt | 4 + .../charts/frr-k8s/templates/_helpers.tpl | 63 + .../charts/frr-k8s/templates/controller.yaml | 431 ++++++ .../charts/frr-k8s/templates/rbac.yaml | 73 + .../frr-k8s/templates/service-accounts.yaml | 16 + .../frr-k8s/templates/service-monitor.yaml | 128 ++ .../charts/frr-k8s/templates/webhooks.yaml | 163 +++ .../charts/frr-k8s/values.schema.json | 387 ++++++ metallb-chart/charts/frr-k8s/values.yaml | 176 +++ metallb-chart/charts/metallb-crds/.helmignore | 23 + metallb-chart/charts/metallb-crds/Chart.yaml | 10 + metallb-chart/charts/metallb-crds/README.md | 11 + .../charts/metallb-crds/templates/crds.yaml | 1205 +++++++++++++++++ metallb-chart/policy.obscpio | Bin 3072 -> 0 bytes metallb-chart/policy/controller.rego | 16 + metallb-chart/policy/rbac.rego | 27 + metallb-chart/policy/speaker.rego | 30 + metallb-chart/templates.obscpio | Bin 60928 -> 0 bytes metallb-chart/templates/NOTES.txt | 4 + metallb-chart/templates/_helpers.tpl | 113 ++ metallb-chart/templates/controller.yaml | 194 +++ .../templates/deprecated_configInline.yaml | 3 + .../templates/exclude-l2-config.yaml | 25 + metallb-chart/templates/podmonitor.yaml | 106 ++ metallb-chart/templates/prometheusrules.yaml | 84 ++ metallb-chart/templates/rbac.yaml | 212 +++ metallb-chart/templates/service-accounts.yaml | 30 + metallb-chart/templates/servicemonitor.yaml | 194 +++ metallb-chart/templates/speaker.yaml | 568 ++++++++ metallb-chart/templates/webhooks.yaml | 150 ++ sriov-crd-chart/templates.obscpio | Bin 47104 -> 0 bytes ...sriovnetwork.openshift.io_ovsnetworks.yaml | 105 ++ ...vnetwork.openshift.io_sriovibnetworks.yaml | 78 ++ ...openshift.io_sriovnetworknodepolicies.yaml | 209 +++ ...k.openshift.io_sriovnetworknodestates.yaml | 343 +++++ ....openshift.io_sriovnetworkpoolconfigs.yaml | 123 ++ ...iovnetwork.openshift.io_sriovnetworks.yaml | 136 ++ ...ork.openshift.io_sriovoperatorconfigs.yaml | 114 ++ sriov-network-operator-chart/charts.obscpio | Bin 90112 -> 0 bytes .../charts/sriov-nfd/.helmignore | 23 + .../charts/sriov-nfd/Chart.yaml | 14 + .../charts/sriov-nfd/README.md | 10 + .../charts/sriov-nfd/crds/nfd-api-crds.yaml | 426 ++++++ .../charts/sriov-nfd/templates/_helpers.tpl | 107 ++ .../templates/cert-manager-certs.yaml | 68 + .../templates/cert-manager-issuer.yaml | 42 + .../sriov-nfd/templates/clusterrole.yaml | 119 ++ .../templates/clusterrolebinding.yaml | 52 + .../charts/sriov-nfd/templates/master.yaml | 145 ++ .../charts/sriov-nfd/templates/nfd-gc.yaml | 77 ++ .../sriov-nfd/templates/nfd-master-conf.yaml | 12 + .../templates/nfd-topologyupdater-conf.yaml | 10 + .../sriov-nfd/templates/nfd-worker-conf.yaml | 12 + .../sriov-nfd/templates/prometheus.yaml | 26 + .../charts/sriov-nfd/templates/role.yaml | 24 + .../sriov-nfd/templates/rolebinding.yaml | 18 + .../charts/sriov-nfd/templates/service.yaml | 20 + .../sriov-nfd/templates/serviceaccount.yaml | 58 + .../templates/topologyupdater-crds.yaml | 278 ++++ .../sriov-nfd/templates/topologyupdater.yaml | 156 +++ .../charts/sriov-nfd/templates/worker.yaml | 162 +++ .../charts/sriov-nfd/values.yaml | 534 ++++++++ .../templates.obscpio | Bin 28160 -> 0 bytes .../templates/NOTES.txt | 17 + .../templates/_helpers.tpl | 85 ++ .../templates/_webhook-certs.tpl | 31 + .../templates/certificate.yaml | 71 + .../templates/certmanagercerts.yaml | 41 + .../templates/clusterrole.yaml | 111 ++ .../templates/clusterrolebinding.yaml | 29 + .../templates/configmap.yaml | 47 + .../templates/operator.yaml | 116 ++ .../templates/role.yaml | 138 ++ .../templates/rolebinding.yaml | 44 + .../templates/secrets.yaml | 20 + .../templates/serviceaccount.yaml | 15 + .../templates/sriovoperatorconfig.yaml | 17 + .../templates/validate-install-crd.yaml | 20 + .../charts/lifecycle-crds/Chart.yaml | 6 + .../templates/release-manifest-crd.yaml | 135 ++ .../templates/upgrade-plan-crd.yaml} | Bin 15360 -> 8833 bytes upgrade-controller-chart/templates.obscpio | Bin 12800 -> 0 bytes upgrade-controller-chart/templates/NOTES.txt | 0 .../templates/_helpers.tpl | 83 ++ .../templates/certificate.yaml | 28 + .../templates/clusterrole.yaml | 114 ++ .../templates/clusterrole_binding.yaml | 14 + .../templates/deployment.yaml | 85 ++ .../templates/leader_election_role.yaml | 40 + .../leader_election_role_binding.yaml | 15 + .../templates/serviceaccount.yaml | 14 + .../validating_webhook_configuration.yaml | 29 + .../templates/webhook_service.yaml | 15 + 182 files changed, 15763 insertions(+) rename cdi-chart/{crds.obscpio => crds/cdi.yaml} (99%) delete mode 100644 cdi-chart/templates.obscpio create mode 100644 cdi-chart/templates/NOTES.txt create mode 100644 cdi-chart/templates/_helpers.tpl create mode 100644 cdi-chart/templates/_hooks.tpl create mode 100644 cdi-chart/templates/cdi-operator.yaml create mode 100644 cdi-chart/templates/cdi-uninstall-hooks.yaml create mode 100644 cdi-chart/templates/cdi.yaml create mode 100644 cdi-chart/templates/crd-uninstall-hooks.yaml create mode 100644 cdi-chart/templates/crd-upgrade-hooks.yaml create mode 100644 cdi-chart/templates/namespace-hooks.yaml delete mode 100644 metal3-chart/charts.obscpio create mode 100644 metal3-chart/charts/baremetal-operator/.helmignore create mode 100644 metal3-chart/charts/baremetal-operator/Chart.yaml create mode 100644 metal3-chart/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml create mode 100644 metal3-chart/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml create mode 100644 metal3-chart/charts/baremetal-operator/crds/customresource-dataimages.yaml create mode 100644 metal3-chart/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml create mode 100644 metal3-chart/charts/baremetal-operator/crds/customresource-hardwaredata.yaml create mode 100644 metal3-chart/charts/baremetal-operator/crds/customresource-hostfirmwarecomponents.yaml create mode 100644 metal3-chart/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml create mode 100644 metal3-chart/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/NOTES.txt create mode 100644 metal3-chart/charts/baremetal-operator/templates/_helpers.tpl create mode 100644 metal3-chart/charts/baremetal-operator/templates/certificate.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/clusterrole-manager.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/clusterrole-metrics-reader.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/clusterrole-proxy.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/clusterrolebinding-manager.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/clusterrolebinding-proxy.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/configmap-ironic.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/configmap.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/deployment.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/issuer.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/role.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/rolebinding.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/service-controller-manager.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/service-webhook.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/serviceaccount.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/tests/test-connection.yaml create mode 100644 metal3-chart/charts/baremetal-operator/templates/validatingwebhookconfiguration.yaml create mode 100644 metal3-chart/charts/baremetal-operator/values.yaml create mode 100644 metal3-chart/charts/ironic/.helmignore create mode 100644 metal3-chart/charts/ironic/Chart.yaml create mode 100644 metal3-chart/charts/ironic/README.md create mode 100644 metal3-chart/charts/ironic/templates/NOTES.txt create mode 100644 metal3-chart/charts/ironic/templates/_helpers.tpl create mode 100644 metal3-chart/charts/ironic/templates/certificates.yaml create mode 100644 metal3-chart/charts/ironic/templates/configmap-ipa-downloader.yaml create mode 100644 metal3-chart/charts/ironic/templates/configmap.yaml create mode 100644 metal3-chart/charts/ironic/templates/deployment.yaml create mode 100644 metal3-chart/charts/ironic/templates/issuers.yaml create mode 100644 metal3-chart/charts/ironic/templates/pvc.yaml create mode 100644 metal3-chart/charts/ironic/templates/secret-tls.yaml create mode 100644 metal3-chart/charts/ironic/templates/secrets-basic-auth.yaml create mode 100644 metal3-chart/charts/ironic/templates/service.yaml create mode 100644 metal3-chart/charts/ironic/templates/serviceaccount.yaml create mode 100644 metal3-chart/charts/ironic/values.yaml create mode 100644 metal3-chart/charts/mariadb/.helmignore create mode 100644 metal3-chart/charts/mariadb/Chart.yaml create mode 100644 metal3-chart/charts/mariadb/templates/_helpers.tpl create mode 100644 metal3-chart/charts/mariadb/templates/configmap.yaml create mode 100644 metal3-chart/charts/mariadb/templates/deployment.yaml create mode 100644 metal3-chart/charts/mariadb/templates/pvc.yaml create mode 100644 metal3-chart/charts/mariadb/templates/secret.yaml create mode 100644 metal3-chart/charts/mariadb/templates/service-account.yaml create mode 100644 metal3-chart/charts/mariadb/templates/service.yaml create mode 100644 metal3-chart/charts/mariadb/values.yaml create mode 100644 metal3-chart/charts/media/.helmignore create mode 100644 metal3-chart/charts/media/Chart.yaml create mode 100644 metal3-chart/charts/media/templates/NOTES.txt create mode 100644 metal3-chart/charts/media/templates/_helpers.tpl create mode 100644 metal3-chart/charts/media/templates/deployment.yaml create mode 100644 metal3-chart/charts/media/templates/hpa.yaml create mode 100644 metal3-chart/charts/media/templates/ingress.yaml create mode 100644 metal3-chart/charts/media/templates/persistentvolume.yaml create mode 100644 metal3-chart/charts/media/templates/persistentvolumeclaim.yaml create mode 100644 metal3-chart/charts/media/templates/service.yaml create mode 100644 metal3-chart/charts/media/templates/serviceaccount.yaml create mode 100644 metal3-chart/charts/media/templates/storageclass.yaml create mode 100644 metal3-chart/charts/media/templates/tests/test-connection.yaml create mode 100644 metal3-chart/charts/media/values.yaml create mode 100644 metal3-chart/templates/NOTES.txt rename metal3-chart/{templates.obscpio => templates/_helpers.tpl} (69%) delete mode 100644 metallb-chart/charts.obscpio create mode 100644 metallb-chart/charts/frr-k8s/Chart.yaml create mode 100644 metallb-chart/charts/frr-k8s/README.md create mode 100644 metallb-chart/charts/frr-k8s/crds/frrk8s.metallb.io_frrconfigurations.yaml create mode 100644 metallb-chart/charts/frr-k8s/crds/frrk8s.metallb.io_frrnodestates.yaml create mode 100644 metallb-chart/charts/frr-k8s/templates/NOTES.txt create mode 100644 metallb-chart/charts/frr-k8s/templates/_helpers.tpl create mode 100644 metallb-chart/charts/frr-k8s/templates/controller.yaml create mode 100644 metallb-chart/charts/frr-k8s/templates/rbac.yaml create mode 100644 metallb-chart/charts/frr-k8s/templates/service-accounts.yaml create mode 100644 metallb-chart/charts/frr-k8s/templates/service-monitor.yaml create mode 100644 metallb-chart/charts/frr-k8s/templates/webhooks.yaml create mode 100644 metallb-chart/charts/frr-k8s/values.schema.json create mode 100644 metallb-chart/charts/frr-k8s/values.yaml create mode 100644 metallb-chart/charts/metallb-crds/.helmignore create mode 100644 metallb-chart/charts/metallb-crds/Chart.yaml create mode 100644 metallb-chart/charts/metallb-crds/README.md create mode 100644 metallb-chart/charts/metallb-crds/templates/crds.yaml delete mode 100644 metallb-chart/policy.obscpio create mode 100644 metallb-chart/policy/controller.rego create mode 100644 metallb-chart/policy/rbac.rego create mode 100644 metallb-chart/policy/speaker.rego delete mode 100644 metallb-chart/templates.obscpio create mode 100644 metallb-chart/templates/NOTES.txt create mode 100644 metallb-chart/templates/_helpers.tpl create mode 100644 metallb-chart/templates/controller.yaml create mode 100644 metallb-chart/templates/deprecated_configInline.yaml create mode 100644 metallb-chart/templates/exclude-l2-config.yaml create mode 100644 metallb-chart/templates/podmonitor.yaml create mode 100644 metallb-chart/templates/prometheusrules.yaml create mode 100644 metallb-chart/templates/rbac.yaml create mode 100644 metallb-chart/templates/service-accounts.yaml create mode 100644 metallb-chart/templates/servicemonitor.yaml create mode 100644 metallb-chart/templates/speaker.yaml create mode 100644 metallb-chart/templates/webhooks.yaml delete mode 100644 sriov-crd-chart/templates.obscpio create mode 100644 sriov-crd-chart/templates/sriovnetwork.openshift.io_ovsnetworks.yaml create mode 100644 sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovibnetworks.yaml create mode 100644 sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworknodepolicies.yaml create mode 100644 sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworknodestates.yaml create mode 100644 sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworkpoolconfigs.yaml create mode 100644 sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworks.yaml create mode 100644 sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovoperatorconfigs.yaml delete mode 100644 sriov-network-operator-chart/charts.obscpio create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/.helmignore create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/Chart.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/README.md create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/crds/nfd-api-crds.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/_helpers.tpl create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/cert-manager-certs.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/cert-manager-issuer.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/clusterrole.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/clusterrolebinding.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/master.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-gc.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-master-conf.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-topologyupdater-conf.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-worker-conf.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/prometheus.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/role.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/rolebinding.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/service.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/serviceaccount.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/topologyupdater-crds.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/topologyupdater.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/templates/worker.yaml create mode 100644 sriov-network-operator-chart/charts/sriov-nfd/values.yaml delete mode 100644 sriov-network-operator-chart/templates.obscpio create mode 100644 sriov-network-operator-chart/templates/NOTES.txt create mode 100644 sriov-network-operator-chart/templates/_helpers.tpl create mode 100644 sriov-network-operator-chart/templates/_webhook-certs.tpl create mode 100644 sriov-network-operator-chart/templates/certificate.yaml create mode 100644 sriov-network-operator-chart/templates/certmanagercerts.yaml create mode 100644 sriov-network-operator-chart/templates/clusterrole.yaml create mode 100644 sriov-network-operator-chart/templates/clusterrolebinding.yaml create mode 100644 sriov-network-operator-chart/templates/configmap.yaml create mode 100644 sriov-network-operator-chart/templates/operator.yaml create mode 100644 sriov-network-operator-chart/templates/role.yaml create mode 100644 sriov-network-operator-chart/templates/rolebinding.yaml create mode 100644 sriov-network-operator-chart/templates/secrets.yaml create mode 100644 sriov-network-operator-chart/templates/serviceaccount.yaml create mode 100644 sriov-network-operator-chart/templates/sriovoperatorconfig.yaml create mode 100644 sriov-network-operator-chart/templates/validate-install-crd.yaml create mode 100644 upgrade-controller-chart/charts/lifecycle-crds/Chart.yaml create mode 100644 upgrade-controller-chart/charts/lifecycle-crds/templates/release-manifest-crd.yaml rename upgrade-controller-chart/{charts.obscpio => charts/lifecycle-crds/templates/upgrade-plan-crd.yaml} (57%) delete mode 100644 upgrade-controller-chart/templates.obscpio create mode 100644 upgrade-controller-chart/templates/NOTES.txt create mode 100644 upgrade-controller-chart/templates/_helpers.tpl create mode 100644 upgrade-controller-chart/templates/certificate.yaml create mode 100644 upgrade-controller-chart/templates/clusterrole.yaml create mode 100644 upgrade-controller-chart/templates/clusterrole_binding.yaml create mode 100644 upgrade-controller-chart/templates/deployment.yaml create mode 100644 upgrade-controller-chart/templates/leader_election_role.yaml create mode 100644 upgrade-controller-chart/templates/leader_election_role_binding.yaml create mode 100644 upgrade-controller-chart/templates/serviceaccount.yaml create mode 100644 upgrade-controller-chart/templates/validating_webhook_configuration.yaml create mode 100644 upgrade-controller-chart/templates/webhook_service.yaml diff --git a/cdi-chart/crds.obscpio b/cdi-chart/crds/cdi.yaml similarity index 99% rename from cdi-chart/crds.obscpio rename to cdi-chart/crds/cdi.yaml index 934dbbbe293092174fb46c35378f87526154d3e78ee13025221b7272264ab260..8621e0f2176d59edb2a13b07fdb9d519fd672ab92ae40a6874a9cc271fc4eeae 100644 GIT binary patch delta 25 gcmZp8BKrA(Xk$%l4P$E!Q)>-#YYofR8rI?h0G5Xeh5!Hn delta 429 zcmezTK(yhBXuW|s5E>d7nVFcIB_|sIfrVkB35Yf@Ofv)128IwmP{hnE#lkYx0>n23 zYBYw(1NB2d3Y12tQegtgMJdJl$tjt7m5I4I42cDqjm)jgjIGQ}t;|3M%T{LAf`WPm osGDG#@Y686@vFj=O@ax91UY*8xCSXIDl&jUJ%k!CQW%TP0GRVVd;kCd diff --git a/cdi-chart/templates.obscpio b/cdi-chart/templates.obscpio deleted file mode 100644 index f1fb05f1303c34d3034362b2d373771e14003a3db6707f41aa1c8f59b7631450..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26624 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 diff --git a/cdi-chart/templates/NOTES.txt b/cdi-chart/templates/NOTES.txt new file mode 100644 index 0000000..f6a43a4 --- /dev/null +++ b/cdi-chart/templates/NOTES.txt @@ -0,0 +1,2 @@ +Verify that all CDI components are installed correctly: + kubectl get all -n {{ .Release.Namespace }} diff --git a/cdi-chart/templates/_helpers.tpl b/cdi-chart/templates/_helpers.tpl new file mode 100644 index 0000000..5f2e091 --- /dev/null +++ b/cdi-chart/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "cdi.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 "cdi.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 "cdi.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cdi.labels" -}} +helm.sh/chart: {{ include "cdi.chart" . }} +{{ include "cdi.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "cdi.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cdi.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "cdi.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "cdi.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/cdi-chart/templates/_hooks.tpl b/cdi-chart/templates/_hooks.tpl new file mode 100644 index 0000000..d857801 --- /dev/null +++ b/cdi-chart/templates/_hooks.tpl @@ -0,0 +1,47 @@ +{{/* Hook annotations */}} +{{- define "cdi.hook.annotations" -}} + annotations: + "helm.sh/hook": {{ .hookType }} + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + "helm.sh/hook-weight": {{ .hookWeight | quote }} +{{- end -}} + +{{/* Namespace modifying hook annotations */}} +{{- define "cdi.namespaceHook.annotations" -}} +{{ template "cdi.hook.annotations" merge (dict "hookType" "pre-install") . }} +{{- end -}} + +{{/* CRD upgrading hook annotations */}} +{{- define "cdi.crdUpgradeHook.annotations" -}} +{{ template "cdi.hook.annotations" merge (dict "hookType" "pre-upgrade") . }} +{{- end -}} + +{{/* Custom resource uninstalling hook annotations */}} +{{- define "cdi.crUninstallHook.annotations" -}} +{{ template "cdi.hook.annotations" merge (dict "hookType" "pre-delete") . }} +{{- end -}} + +{{/* CRD uninstalling hook annotations */}} +{{- define "cdi.crdUninstallHook.annotations" -}} +{{ template "cdi.hook.annotations" merge (dict "hookType" "post-delete") . }} +{{- end -}} + +{{/* Namespace modifying hook name */}} +{{- define "cdi.namespaceHook.name" -}} +{{ include "cdi.fullname" . }}-namespace-modify +{{- end }} + +{{/* CRD upgrading hook name */}} +{{- define "cdi.crdUpgradeHook.name" -}} +{{ include "cdi.fullname" . }}-crd-upgrade +{{- end }} + +{{/* Custom resource uninstalling hook name */}} +{{- define "cdi.crUninstallHook.name" -}} +{{ include "cdi.fullname" . }}-uninstall +{{- end }} + +{{/* CRD uninstalling hook name */}} +{{- define "cdi.crdUninstallHook.name" -}} +{{ include "cdi.fullname" . }}-crd-uninstall +{{- end }} diff --git a/cdi-chart/templates/cdi-operator.yaml b/cdi-chart/templates/cdi-operator.yaml new file mode 100644 index 0000000..f6ab6fe --- /dev/null +++ b/cdi-chart/templates/cdi-operator.yaml @@ -0,0 +1,671 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + operator.cdi.kubevirt.io: "" + name: cdi-operator-cluster +rules: + - apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + - clusterroles + verbs: + - get + - list + - watch + - create + - update + - delete + - apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + verbs: + - get + - list + - watch + - update + - create + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + - customresourcedefinitions/status + verbs: + - get + - list + - watch + - create + - update + - delete + - apiGroups: + - cdi.kubevirt.io + - upload.cdi.kubevirt.io + resources: + - '*' + verbs: + - '*' + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + - mutatingwebhookconfigurations + verbs: + - create + - list + - watch + - apiGroups: + - admissionregistration.k8s.io + resourceNames: + - cdi-api-dataimportcron-validate + - cdi-api-populator-validate + - cdi-api-datavolume-validate + - cdi-api-validate + - objecttransfer-api-validate + resources: + - validatingwebhookconfigurations + verbs: + - get + - update + - delete + - apiGroups: + - admissionregistration.k8s.io + resourceNames: + - cdi-api-datavolume-mutate + - cdi-api-pvc-mutate + resources: + - mutatingwebhookconfigurations + verbs: + - get + - update + - delete + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + verbs: + - get + - list + - watch + - create + - update + - delete + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - persistentvolumes + verbs: + - get + - list + - watch + - apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshots + verbs: + - get + - list + - watch + - apiGroups: + - cdi.kubevirt.io + resources: + - datavolumes + verbs: + - list + - get + - apiGroups: + - cdi.kubevirt.io + resources: + - datasources + verbs: + - get + - apiGroups: + - cdi.kubevirt.io + resources: + - volumeclonesources + verbs: + - get + - list + - watch + - apiGroups: + - cdi.kubevirt.io + resources: + - storageprofiles + verbs: + - get + - list + - watch + - apiGroups: + - cdi.kubevirt.io + resources: + - cdis + verbs: + - get + - list + - watch + - apiGroups: + - cdi.kubevirt.io + resources: + - cdiconfigs + verbs: + - get + - list + - watch + - apiGroups: + - cdi.kubevirt.io + resources: + - cdis/finalizers + verbs: + - update + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - get + - list + - watch + - create + - update + - delete + - deletecollection + - patch + - apiGroups: + - "" + resources: + - persistentvolumes + verbs: + - get + - list + - watch + - update + - apiGroups: + - "" + resources: + - persistentvolumeclaims/finalizers + - pods/finalizers + verbs: + - update + - apiGroups: + - "" + resources: + - pods + - services + verbs: + - get + - list + - watch + - create + - delete + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - create + - apiGroups: + - storage.k8s.io + resources: + - storageclasses + - csidrivers + verbs: + - get + - list + - watch + - apiGroups: + - config.openshift.io + resources: + - proxies + - infrastructures + verbs: + - get + - list + - watch + - apiGroups: + - config.openshift.io + resources: + - clusterversions + verbs: + - get + - apiGroups: + - cdi.kubevirt.io + resources: + - '*' + verbs: + - '*' + - apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshots + - volumesnapshotclasses + - volumesnapshotcontents + verbs: + - get + - list + - watch + - create + - delete + - apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshots + verbs: + - update + - deletecollection + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list + - watch + - apiGroups: + - scheduling.k8s.io + resources: + - priorityclasses + verbs: + - get + - list + - watch + - apiGroups: + - image.openshift.io + resources: + - imagestreams + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - secrets + verbs: + - create + - apiGroups: + - kubevirt.io + resources: + - virtualmachines/finalizers + verbs: + - update + - apiGroups: + - forklift.cdi.kubevirt.io + resources: + - ovirtvolumepopulators + - openstackvolumepopulators + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - get + - apiGroups: + - cdi.kubevirt.io + resources: + - dataimportcrons + verbs: + - get + - list + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + operator.cdi.kubevirt.io: "" + name: cdi-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cdi-operator-cluster +subjects: + - kind: ServiceAccount + name: cdi-operator + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + operator.cdi.kubevirt.io: "" + name: cdi-operator + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app: containerized-data-importer + app.kubernetes.io/component: storage + app.kubernetes.io/managed-by: cdi-operator + cdi.kubevirt.io: "" + name: cdi-operator + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + - roles + verbs: + - get + - list + - watch + - create + - update + - delete + - apiGroups: + - "" + resources: + - serviceaccounts + - configmaps + - events + - secrets + - services + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - apps + resources: + - deployments + - deployments/finalizers + verbs: + - get + - list + - watch + - create + - update + - delete + - apiGroups: + - route.openshift.io + resources: + - routes + - routes/custom-host + verbs: + - get + - list + - watch + - create + - update + - apiGroups: + - config.openshift.io + resources: + - proxies + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + - prometheusrules + verbs: + - get + - list + - watch + - create + - delete + - update + - patch + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - create + - update + - apiGroups: + - "" + resources: + - secrets + - configmaps + verbs: + - get + - list + - watch + - create + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - delete + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - batch + resources: + - cronjobs + verbs: + - get + - list + - watch + - create + - update + - deletecollection + - apiGroups: + - batch + resources: + - jobs + verbs: + - create + - deletecollection + - list + - watch + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - create + - update + - apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - get + - list + - watch + - apiGroups: + - route.openshift.io + resources: + - routes + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - apiGroups: + - "" + resources: + - services + - endpoints + - pods + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app: containerized-data-importer + app.kubernetes.io/component: storage + app.kubernetes.io/managed-by: cdi-operator + cdi.kubevirt.io: "" + name: cdi-operator + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cdi-operator +subjects: + - kind: ServiceAccount + name: cdi-operator + namespace: {{ .Release.Namespace }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + cdi.kubevirt.io: cdi-operator + name: cdi-operator + operator.cdi.kubevirt.io: "" + prometheus.cdi.kubevirt.io: "true" + name: cdi-operator + namespace: {{ .Release.Namespace }} +spec: + replicas: 1 + selector: + matchLabels: + name: cdi-operator + operator.cdi.kubevirt.io: "" + strategy: {} + template: + metadata: + labels: + cdi.kubevirt.io: cdi-operator + name: cdi-operator + operator.cdi.kubevirt.io: "" + prometheus.cdi.kubevirt.io: "true" + spec: + affinity: + podAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: cdi.kubevirt.io + operator: In + values: + - cdi-operator + topologyKey: kubernetes.io/hostname + weight: 1 + containers: + - env: + - name: DEPLOY_CLUSTER_RESOURCES + value: "true" + - name: OPERATOR_VERSION + value: {{ .Values.deployment.version }} + - name: CONTROLLER_IMAGE + value: {{ .Values.deployment.controllerImage }}:{{ .Values.deployment.version }} + - name: IMPORTER_IMAGE + value: {{ .Values.deployment.importerImage }}:{{ .Values.deployment.version }} + - name: CLONER_IMAGE + value: {{ .Values.deployment.clonerImage }}:{{ .Values.deployment.version }} + - name: OVIRT_POPULATOR_IMAGE + value: {{ .Values.deployment.importerImage }}:{{ .Values.deployment.version }} + - name: APISERVER_IMAGE + value: {{ .Values.deployment.apiserverImage }}:{{ .Values.deployment.version }} + - name: UPLOAD_SERVER_IMAGE + value: {{ .Values.deployment.uploadserverImage }}:{{ .Values.deployment.version }} + - name: UPLOAD_PROXY_IMAGE + value: {{ .Values.deployment.uploadproxyImage }}:{{ .Values.deployment.version }} + - name: VERBOSITY + value: "1" + - name: PULL_POLICY + value: {{ .Values.deployment.pullPolicy }} + - name: MONITORING_NAMESPACE + image: {{ .Values.deployment.operatorImage }}:{{ .Values.deployment.version }} + imagePullPolicy: {{ .Values.deployment.pullPolicy }} + name: cdi-operator + ports: + - containerPort: 8080 + name: metrics + protocol: TCP + resources: + requests: + cpu: 100m + memory: 150Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + nodeSelector: + kubernetes.io/os: linux + securityContext: + runAsNonRoot: true + serviceAccountName: cdi-operator + tolerations: + - key: CriticalAddonsOnly + operator: Exists diff --git a/cdi-chart/templates/cdi-uninstall-hooks.yaml b/cdi-chart/templates/cdi-uninstall-hooks.yaml new file mode 100644 index 0000000..d737539 --- /dev/null +++ b/cdi-chart/templates/cdi-uninstall-hooks.yaml @@ -0,0 +1,69 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.crUninstallHook.name" . }} + {{ template "cdi.crUninstallHook.annotations" (dict "hookWeight" 1) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "cdi.crUninstallHook.name" . }} + {{ template "cdi.crUninstallHook.annotations" (dict "hookWeight" 1) }} +rules: + - apiGroups: [ "cdi.kubevirt.io" ] + resources: [ "cdis" ] + resourceNames: + - "cdi" + verbs: [ "delete" ] + - apiGroups: [ "apps" ] + resources: [ "deployments" ] + verbs: [ "get", "list" ] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "cdi.crUninstallHook.name" . }} + {{ template "cdi.crUninstallHook.annotations" (dict "hookWeight" 2) }} +subjects: + - kind: ServiceAccount + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.crUninstallHook.name" . }} +roleRef: + kind: ClusterRole + name: {{ template "cdi.crUninstallHook.name" . }} + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.crUninstallHook.name" . }} + {{ template "cdi.crUninstallHook.annotations" (dict "hookWeight" 3) }} +spec: + template: + metadata: + name: {{ template "cdi.crUninstallHook.name" . }} + spec: + serviceAccountName: {{ template "cdi.crUninstallHook.name" . }} + restartPolicy: {{ .Values.hookRestartPolicy }} + containers: + - name: {{ template "cdi.crUninstallHook.name" . }} + image: {{ .Values.hookImage }} + securityContext: + {{- toYaml .Values.hookSecurityContext | nindent 12 }} + args: + - delete + - cdi + - cdi + - name: {{ template "cdi.crUninstallHook.name" . }}-cleanup + image: {{ .Values.hookImage }} + securityContext: + {{- toYaml .Values.hookSecurityContext | nindent 12 }} + args: + - wait + - --for=delete + - deployments/cdi-apiserver + - deployments/cdi-deployment + - deployments/cdi-uploadproxy + - --timeout=60s diff --git a/cdi-chart/templates/cdi.yaml b/cdi-chart/templates/cdi.yaml new file mode 100644 index 0000000..b3e476d --- /dev/null +++ b/cdi-chart/templates/cdi.yaml @@ -0,0 +1,21 @@ +apiVersion: cdi.kubevirt.io/v1beta1 +kind: CDI +metadata: + name: cdi +spec: + {{- with .Values.cdi.config }} + config: + {{- toYaml . | nindent 4 }} + {{- end }} + imagePullPolicy: {{ .Values.cdi.imagePullPolicy }} + {{- with .Values.cdi.infra }} + infra: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if .Values.cdi.uninstallStrategy }} + uninstallStrategy: {{ .Values.cdi.uninstallStrategy }} + {{- end }} + {{- with .Values.cdi.workload }} + workload: + {{- toYaml . | nindent 4 }} + {{- end }} diff --git a/cdi-chart/templates/crd-uninstall-hooks.yaml b/cdi-chart/templates/crd-uninstall-hooks.yaml new file mode 100644 index 0000000..19bdaf2 --- /dev/null +++ b/cdi-chart/templates/crd-uninstall-hooks.yaml @@ -0,0 +1,55 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.crdUninstallHook.name" . }} + {{ template "cdi.crdUninstallHook.annotations" (dict "hookWeight" 1) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "cdi.crdUninstallHook.name" . }} + {{ template "cdi.crdUninstallHook.annotations" (dict "hookWeight" 1) }} +rules: + - apiGroups: [ "apiextensions.k8s.io" ] + resources: [ "customresourcedefinitions" ] + resourceNames: + - "cdis.cdi.kubevirt.io" + verbs: [ "delete" ] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "cdi.crdUninstallHook.name" . }} + {{ template "cdi.crdUninstallHook.annotations" (dict "hookWeight" 2) }} +subjects: + - kind: ServiceAccount + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.crdUninstallHook.name" . }} +roleRef: + kind: ClusterRole + name: {{ template "cdi.crdUninstallHook.name" . }} + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.crdUninstallHook.name" . }} + {{ template "cdi.crdUninstallHook.annotations" (dict "hookWeight" 3) }} +spec: + template: + metadata: + name: {{ template "cdi.crdUninstallHook.name" . }} + spec: + serviceAccountName: {{ template "cdi.crdUninstallHook.name" . }} + restartPolicy: {{ .Values.hookRestartPolicy }} + containers: + - name: {{ template "cdi.crdUninstallHook.name" . }} + image: {{ .Values.hookImage }} + args: + - delete + - customresourcedefinitions + - cdis.cdi.kubevirt.io + securityContext: + {{- toYaml .Values.hookSecurityContext | nindent 12 }} diff --git a/cdi-chart/templates/crd-upgrade-hooks.yaml b/cdi-chart/templates/crd-upgrade-hooks.yaml new file mode 100644 index 0000000..f650adc --- /dev/null +++ b/cdi-chart/templates/crd-upgrade-hooks.yaml @@ -0,0 +1,80 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: cdi-crd-manifest + {{ template "cdi.crdUpgradeHook.annotations" (dict "hookWeight" 1) }} +data: + crd: |- + {{ $.Files.Get "crds/cdi.yaml" | nindent 4 }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.crdUpgradeHook.name" . }} + {{ template "cdi.crdUpgradeHook.annotations" (dict "hookWeight" 2) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "cdi.crdUpgradeHook.name" . }} + {{ template "cdi.crdUpgradeHook.annotations" (dict "hookWeight" 2) }} +rules: + - apiGroups: [ "" ] + resources: [ "configmaps" ] + resourceNames: + - "cdi-crd-manifest" + verbs: [ "get" ] + - apiGroups: [ "apiextensions.k8s.io" ] + resources: [ "customresourcedefinitions" ] + resourceNames: + - "cdis.cdi.kubevirt.io" + verbs: [ "get", "patch" ] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "cdi.crdUpgradeHook.name" . }} + {{ template "cdi.crdUpgradeHook.annotations" (dict "hookWeight" 3) }} +subjects: + - kind: ServiceAccount + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.crdUpgradeHook.name" . }} +roleRef: + kind: ClusterRole + name: {{ template "cdi.crdUpgradeHook.name" . }} + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.crdUpgradeHook.name" . }} + {{ template "cdi.crdUpgradeHook.annotations" (dict "hookWeight" 4) }} +spec: + template: + metadata: + name: {{ template "cdi.crdUpgradeHook.name" . }} + spec: + serviceAccountName: {{ template "cdi.crdUpgradeHook.name" . }} + restartPolicy: {{ .Values.hookRestartPolicy }} + containers: + - name: {{ template "cdi.crdUpgradeHook.name" . }} + image: {{ .Values.hookImage }} + args: + - apply + - -f + - /etc/manifests/crd.yaml + securityContext: + {{- toYaml .Values.hookSecurityContext | nindent 12 }} + volumeMounts: + - name: crd-volume + mountPath: /etc/manifests + volumes: + - name: crd-volume + configMap: + name: cdi-crd-manifest + items: + - key: crd + path: crd.yaml diff --git a/cdi-chart/templates/namespace-hooks.yaml b/cdi-chart/templates/namespace-hooks.yaml new file mode 100644 index 0000000..30d16a4 --- /dev/null +++ b/cdi-chart/templates/namespace-hooks.yaml @@ -0,0 +1,56 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.namespaceHook.name" . }} + {{ template "cdi.namespaceHook.annotations" (dict "hookWeight" 1) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "cdi.namespaceHook.name" . }} + {{ template "cdi.namespaceHook.annotations" (dict "hookWeight" 1) }} +rules: + - apiGroups: [ "" ] + resources: [ "namespaces" ] + resourceNames: + - {{ .Release.Namespace | quote }} + verbs: [ "get", "patch" ] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "cdi.namespaceHook.name" . }} + {{ template "cdi.namespaceHook.annotations" (dict "hookWeight" 2) }} +subjects: + - kind: ServiceAccount + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.namespaceHook.name" . }} +roleRef: + kind: ClusterRole + name: {{ template "cdi.namespaceHook.name" . }} + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "cdi.namespaceHook.name" . }} + {{ template "cdi.namespaceHook.annotations" (dict "hookWeight" 3) }} +spec: + template: + metadata: + name: {{ template "cdi.namespaceHook.name" . }} + spec: + serviceAccountName: {{ template "cdi.namespaceHook.name" . }} + restartPolicy: {{ .Values.hookRestartPolicy }} + containers: + - name: {{ template "cdi.namespaceHook.name" . }} + securityContext: + {{- toYaml .Values.hookSecurityContext | nindent 12 }} + image: {{ .Values.hookImage }} + args: + - label + - namespace + - {{ .Release.Namespace }} + - cdi.kubevirt.io= diff --git a/metal3-chart/charts.obscpio b/metal3-chart/charts.obscpio deleted file mode 100644 index c3b1f6c9ef7d814628bd678502988a1b9d3df4afd6c3e3159ea1c080d6efc21e..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 189440 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

VK^b~Y%!{woY zFYKQ0>`wtP{YZ1reFluQCS2v{JSgc+G2=K#kX453_M z3DZ`}2!}EUdpo&h#ht*LYl7>IxcYa5W*k0TDqCQgNB`?!#WjXh7)!T=#JXVK4Rb8X zJe6L$S;%^3xp#Q^gl=K{cQXZvbY2`R)`>Y9)N|xhoKRPS6kv3-e zi$}AORBuyDXXa!qBbzvhP-SowH%ECuXhC|yf(7v?h&rXG+lpdq{ll~MXPd$Lhu+h# zk$u8NJpWgtL6nOC1yz_2eqb>!ELg=qXhjp;@Xq7n{@w_)>4(Za$wBNV6Gld1LAip( zb@;!Y2j8K}8iNvQQ8|rqr9GUKwi8wE`_pNO&?_O8Du8Bo4Ig8Lem^|N`3Q7v+&*SH zIh?fGR!IdGk2fmX;fO_# z(x0qF9QvFJySq!Vp9qq9KkTxg-f!LA#=yWKdetspsj!5>-qIc3O z7lFfE$9nZ~NvSiy@l^Kl2XH~We-s=a@0Keh(Y)VzSZ`Z3TPfj)ffX=t4zO`GmlWH% zV>1IFcr~0XKG=bfo9x!@C7fjd9WeLxpoQDNC_Xy~TbBqSMlPojp;N3V8o78CD1HpXOM?Wkwat;_&SF#iZ{-AQ^M-4pnokwf1x_veT&nLK zj^Z|TymP#V9JX2?+bSN)OcjG_gmI0ZVM)4MA04WG!aeb+eb)&ihYs6C)=McN%PGfQ zWVi0=bsMViMR(dCwwVcaYrVI%zTR1HC;bFZwl=o#s8z)kCLGF|1Ll-h_!V60WirMd z!d$4J3|vULowus{M)QX_XF1K$Le)ji_Hb0DC;}6b3I_yfgk}a01C(mIRVX?EV`k;b zC23~bf?7rA!-5$A9t8-z$JGT|X~-o~Ngs_4zJG!khWjQQm@$qBu4P~ideQhaJ1xir zjV>YFsx(NXFJKxL$puz5Af$w!9|r2fOxagjm=ck_zEIPNdQ2~KB;tPFlbB?XV=)_0AhiYMxmfbpnKOvFd&CwGV6Rr0Y!B3ks zWwjgY)LN=bY33)jGwD_}IF<@uhSc0bpdl77Ib5O0XW1^9p42G@esNuY42ByS3%Dzp ziK{|LH&~CxO?7}3=BEP}Km#}`{Ofj&T0oW4TKdxaqVRClKquxpbZW0Zkyxdsu}$mI zrY*i+7u#gptr**6PpLE&ok`k)9N_;p@lDGEyjh5oJ>%0j8WB5Lkdyne5azUmfqa|= zG`Vl_vOc6q%!1&P9__pv+%!^7*KB&}}A6DmiN$cNEBT*$ct}zKt z8B|5VYb7o3ZqD)0oiT-2K5zP7vXRrZ_fBsG6*1R#1^T5Q>IFOTOW>Z*a~R?#i?b+j zRk#syjhnDy#uYESHp<-CaA(eOBNx|Cqjv(Vz*HsUV`Ew~6}07-Rn~7iPmPj(Vf~h0 z7^d;OSDJs3-M4udS#ieL4h~Jttdjm~35+!7(d-?rQcp@xg$lgEZxH_{9Az29jH3}# zC{k5!4xIeF8|j_wl7Tr$?du65643J+x1wYSe_IF*Co3VOXHlOKA>6SVyo)CzQ`Uma z;{G@UvJOl*7kN}5K0(9zRPzW7PFO8U;)2n?bjGTje8};PoW+gAO9e8xeym&tq!c19 z1D0?AL<3!$yisTZ2$0k{?=AGnOAe>OV5T@^UvW`f49_n<>#9(+3rd1ckTcszHA2yr z?jPdm!llZ}ZPx?Xe^IdQgX2Z6@UX^McI{%Rt=8Bs?)Pl{s5-k?a;5Tk0~s@B^Q7A_ zxBuz5FAi}eW=-#hSnK%T#y0j3@@5wDcl$ffp?uA8^EM@zEal8j_BAP3%U+xWQ1NyU zqQm7)JFs7ALugN0YQR3u&mx-Co7i~;k2_cOts!V{V}{7%n1y$*B@wjEaUvKw*Mx8` zhP=KVX=UE3MK8&r%@bWrIpui8n@T=f7g0%*fc&{PmVC&T`6HOFLRKdAW~6j5gDN}c zzpK=6SE=FH6wA1CMj-vt{HD%`a@!NZiE|vu6tzJ|P1#P9Nw5|a%cyB3Uh}o6@p8Ds zT_j!As_$4WE+-G|3o)``FUui+9SSJjaC(7K$H9+Bub6iN#a0F?O;{*pl};IL?mzHw z2aP=e$N4B1j5r?F-@9Q+2(69u5{f$#^BhHIwF5=SD2h@uZwJy7N`1hWCntx&g+f3| zMV5uka-3=D%K`ylZ;xX7Cp7KSE;L?4X{}f=4pArs)h;ngDPd9oP|h@*KiT#Q-|&q? zL{Vrn6M>E;iDBn+ElUmjGCJ!WWI}O&3`uNC6u-St*mqqRX_v(bV8a61ieCO&pFS~T z&}ksoD{@|1D4kFS6FVOhEr{uL1MCa>d46b4?h9tl(AFsOI3D&Lv`WCJR^yVTeD+28 zaT^nx3hL)oxV_yKKK0^Tcvxer5IJCAc_)n_F{74aKG&X++Q&`pnL&R;>UG0Rsk3LK zj`j`g8QcI7#h!xekF3pr8)C%kIi?&I18GB9psB}LOxYi&K%_84kyP7>rz z8`;TphoE>f#T=VeL%T_agw$eG(%sNJ0{!=yUEw9@FY7617v?x~_4i0GT8q##+r(3KVC{!ZQy<0d{c*CN4j9dWRuq{$8Ee2dOY}xb$DeE07n9CGG%MHsARJ z?lPHJfkusuKX<_iWm>ge=B_TSGOchtP!pWsn6>q>2~Km@l)=6X6=AvHDrYiZI@HCP zZynQ%2}JVEZ6GU!zrB9?;o0W9%_lAH0IiUX@rR2F!Akn>#RR8k_>P_lt(HBFQT$!P z98MYFLhAS{b`-V<14qU-FugTqoj%0yuB1@>Iabe~Qi| zk|hIx8fP#qz^b4hlo%hi($fdTy~kHl2V8Omqky*%g_|+-oWB*iD(5_zEmfC_J@Tb9 z16C(P1n)p&>ga9aO%G;jmvRIW@KMmxvKiIiOsX4mf!fELl@>FBzzHPDqLF|1pfo(! z!JcXyRZ+WSijE{hz&z{%Ep-47%#mUeFb`+YqT`RSTf#;yI-RcK*`W3CMq@KPvqNcd z#sW_fO0(#1$V}8=qIQ+(N&r}%#2IxCY{^I^v;=iiQQI>^2Z<867}YAE`|X&E64SoK zivH1?t3yy#?ZK>qBl*Q!;q*oQD2YaAZ4_CaV8xf<$;9nw35gXUqk9B@QXjVnk!S)L zgGUJTU}7Q|67AunjegqW;b4G!g1}l1!B}UY1Te8OBlD((B17m}E(EnAr9z?2tpf;U0^Ow;-MEJv@}!|LA3=;ntoxfSn5fXJwXAbdCYb<3ci0cFFjUZ}E^#PeEL5mpY^^Ximy$3%VA|DB;Q-Ul%7d;)h0g!6{ z3~R$4f?;zOz!*L;WdV&r0cp^-EGf-{3>ArOM(qvcpWnb@2AKgARC;JqKPA_gE99m} z-4raw(n3Fs!Q)h1gqPUUxiefvqfuLrix5GL;CV2sSuuUeRPZpOm@2tdryGd8-hGXl z)5MGnbw06@;tWT4s8EQLPkE`Ag$qIb%1?6YA<0pJrq&$N@giP%!JA_xmq}~ZF-{Fj z;!hp%ai2+qNdnGlDma3DD?+z|i}@V+cDmj3;k={Cjk`!%KE@f@{2IUEbb!Ia@hs`$ zl4UgNf)4GxVc11{NE_{F*+EDpo$=rvaZlPrG4bD&tr;AdtbuI2e~{C%D+iY)w&w}T zAnv0AH_D(x8B4lM)Ok6KuDVd9c^2CyYqpgKk}gq6y7%NiHy(?eST-Gy9&a|8vQHe< z6p7Z7?u`azPw|@XWB2LOplJavOyb3?Pg6s7H7pBzh>L}0m#TH$+C^mlizZ_n;Y$T3 z)bi+jZdN9nNU5a$HMyK;Wo;~c{+=KkH^LIGZ$!aGSyCZ)`TmGBLVo}&bngM5o2*q` z$huex`$_W?ahTaSn~%r4(R37hBD5W%Y@5aq%52RXZ~X|`v8Oy$wIZfkcY}4gBgonQ zjIvIVU^XlM%DusCitcH@f?8Utd`MnWOj-|wkHqQ)Imt?PIJU(4kFTz50%x6OB3 zpsvC-P#($G8jV5-v`7_eC8=NAsT9N3t}4<;{7|r03Mf@@Lw*Je-{oJzkV$PM(iF-% zE8n%Ty+}f3#z_gyWZREMQ(MfdXo*no*W;=}j};^5)p+<=Mx*OP>!b4(sdaFE?)wH- z9m*w&Rw8yu5TS$d%;=YffOJ`pEy5iPDk2etd#)(6CcY&d?V7uN|qYa^9Xl7G8TzjA<(x1JF?&Ua#&?ni*APYab)K=7Sc%%{cM=c=O8(&M z0!{Umfb_nrns0uaAV%SG1p*%*wfA1Xfu$#7hh@pB5itR!6N(%&oKw@r)FJa1ok2Kn z@M4C`cBZbOoc@Qw;m%$gCHEv8Kr@OUrx5aoL9wMcKyyNs2nBQ{{)dX9h$plg44S?v z5_0~FO@<-Y@HYuCS!Gr%D^l3FP^iC5N8z0GO2Zn8a)G>H9Jc>o5v^j+voaR@2qQC! z;=>UgKN%ktDJTks(fceEN)Un(Kd0E8+!Kn2FhN>l#eRX+0f_^(!z8hi4Zv(2bbK)+ zQk0M%u|J`E&uU2`Sj}8eV(TJ_0Z#jHRaH`-2)HBo2sLxkOE|j4KhAVoyvNQnBM-=y zlzeP)u>vuGwL$9mnG-3Tmh)A-hU4-X%QK|bvS0nG^I{KuCbpQ4l$a9f2mc_B9Fxh zgz5^Iuz3NSaCFWnw2QHeSJ?pzlI#WJ!BaT%F2aqcn{-0qx2L@g?s}#u8g@m!_SoXF zY%A{~_HYCTgn7|ODxp*kC04P{6Hip}@lXyK9|ilnPcfbnn5pIt{}l^MzyV3UTXFJ} zy=r^KpuHX8{-98z{3VD}@{;87zN(pj+1xz$5lBjh2XO-U{skmE{OdH2;a*iDs12>aXyb53^N-ZcFyQ$R=bu&eY`#DFhKEw6PEyGU3el;y95i6^7f7MycCA0N z&vb-&=Cb;kcS;za0nrbr*7Op|3J+}NY_%Acs@EKM6_bH}-p<>B%s|Pz%fYbh&3N#> z;U|v56+yx=) zx)nh=3u)gp%WW_zlajm0MmUahucQ?4(1H_U1@WR%@IX?Q5`}mCyTe**4~@SKl+#Nq z7W|HwR34bSJV`B5v3et;4pSU6`O_J<^_`g8>*iXACPGzLCOt#IHP^<-YzRbYW}Co!#joa|v*A8!YDoa|kIy3qcu zE?FUNRRYb6BFGUx$1o>&9!t$qF1b>D*Ds5vl`b;B?}|2z)%u~6UdqC|$DsN-~M%OyGMmeL8sD80|z*aB6rHy2X7P=q%G(T}@>fWZC zk1kL>b;g>918jx>Dvjb%E$Es<$WgbrEmdsnv(R_!;!MTSHjZ3eIRstylbws!U?uoB zte;wzMcF~-1Z>G$PLzJu4M;VU{-jxI1P25vCt@?#3ir$-m;W#^M+AsTfXfx&F9jp= z86lWIJHg*^BEe$yqJsk!vAIfs3SR<%9)@Gj{`Kd#zf!YcxGVxUQSXS0%+f({cIoV~ z*ah2pG%j^$I@Ee;Zo6bOhN^+HdbkJKHQGu!NM~|OMg!?_mQrQnVqN4oqFI(cLEqVb zxeWEXT~RLCHcJW;c_6>?ErS|3Br&Yc(s97_r43JO2`i_x*@%bxjd8j!NXR#-QJ?2e zHPutMbZM^~vOrN6m2v#xxFuNsYwxcce|`Gb&A;~kvi{en`2Wqnte5z#m2l-&kG^jQ zt;%Xic;71vTpiO*kycQu9e@gz??Iu8_l?+qjMkV74$#3ZQNGnJxHH}O`-B%q(ytB zS)D7E(aMzM&8? zp{H>*xq!1RL7hkJ8YsY{Rt-1Fb|o8kP&Gw0i6x0@BMD)fl_!`asI10EV`*Z-p>-`t zc%U3>XOP4b93wcCRToXcclPD`F@;4cD5!(=>+%^ymc00WSXuT-8#`Ab-D#k9_ zjqtD)sdQz_^3Nk##ZI?YTh0ofGCpamf>1IVokg$TO=&n;jF7Pahi~Pl*9xPIpOg4( zeuYJzDU~HM-{Al%ZB`WJNvevwh56YOcSI9eA(O+qgoaSsRl&zEloF{M9HAkM#a3l5 zD=4E!>x1CfP^JW|sEB%uj*u6VdZoujjFTK72ssCLH~N%i&H|_wppc~msy&xS*!~4# zBt)dc0nESQ3m4by14s;a+1KjO!m`i(xur$ z5t&&4)vgn4o1+mixpL%53C`a1M1kS#H57<=1Hyzf>+sj3Gtt^GB(wko^3nQ?+T+Nb#^5 z-R??icUE9fB}af8LUY_4<5J5+ns8vr+E5aia0#&TxkMIGMZ_A%(nj7cc-kO{HpQ0O;AX4E zj+{j+X--xx9NRVx58VoU75jLVCeRX)mnZ@0b2}=e>|e}c2<2Rg`C;3hyytXchslAW z1iY1cf7kINYk;(RMxg*?ADc@J8iZ!r3m^R#Iv@w9I-1&-Po)&as7B0t!KE{ zs5{6fj@-rKXtb2dGju)3MjL^SC$kGzlo=<8Vzn3h%&3iUXYfuk9ZKAF1BM<)gJEa_ zID;6gcXl;ITy5=_I>6t)oK+P%ZF{aqGa?9#=Nv-{+PWQqyGtUle}Dl%VuTQ#dXx>V=oR` zEI}E9(xt)pc_~J4kXs8ZyqjAhV%#rtMFXH3!g>3mL?MTnw2~D*(TiBYkV_}_#of=*+YT9F0_V&*u4{(O zh^?tFE|8@O77K35qQ57NTk$z)s)PKrpK{C1!M=&L#+^I0 z#XNYE#Xg&bmg=)!iDp91E9I5Wbm<;mZhb8gs@~#Swx>#H1+{bqqp}8lEawK+lrt2P z)JTEgMix|!2&oeu71oi1=QeJe)LBHCrUa$1gx+uv-N*{6p?saSn#v#4;%ZU1npD+m0BIn zV)ok#KXzn>mb%uN*jcoku8P0Mg5$6T( zli`Xga{kyuRs}~b2!k8>4!`k=Gl<*QxZpd*@f}s4{SfyUCpM3R0F#p|MxI`w6G-#P zH7m2GSrL7g!I+VRT@${6h_gX_ihs{z_H&AB!yXr5>8XHA1xgs6$;quxp$SQXLY}~0 z?;gnsCYrUPvoqYv^v9VAO30UiOmmV6Y7pbBknvV?l+2Xdog9F`_eqv&O%T_Pq-(## zT#}hbI5c4_rW%p@p_Py_lO!MT}U2A@D6(i+TkZn+dnbRA$eAe;-~RZTdV>cwTVVapS3e1dP1YQIpKggJR=lcIbs%nI%PMUnkqB5 zZ5EhksBLnX=Xr(rwTDJN#|Hf1vj+Enel*QK_3{r{iCt<AD&)vyLfEDVVZ zn#`~bRm)@y8Wsubd6gT0rAZnT_ zT@Dzpk#}uef|S?wBJfYVsSF&1p3i3SjO`HpG?0AQW~1XH%)E(!Qp%cqR7_A^z(r5Y zUQ3!L5HK7W#)4oeJd{og5d0xI?YyrJggVFFAT0)@vsnPsZq_JE{ZtBvce?RBi zr9uTg03KDU`$##ic_0g@moIMinS)+r`vOvWeeWo(Y?#xmLVL|SeM@zzfDJ(+s6y6x zyg0uA%c@qy3BrgFaXuU3QV(J~fg02;+9TK5KIR2jJw$d`zK!y&L-^IUQZGJ)2_@W) z!KRLMg|0Tze=E4gHcNMM|1_~#VHi#C$5sr&OoI@`M#HL-@d=~R;d*e z*yQK*Q>l{96+!=8`!39>@IU!Xez!uD)>&Jp`E2+x{5I4Bs`+gr8*b#Oz|E(O9 zL)IOBbUa0N74aV^5Z<=pgGsRe^0!h3PAx9vxk-zRDJuDY6>|-&EP(~3#HR#VCINV}~wh^#WCh#|(kz$imY-T?}!} zU$*!ZE8BA2cL zig*&qPu`jtnhg6TOj{`<9Bw|?+sQ2}?gTc00)^D<3|X}6*H<$RA5Q(F)ERTI;(YBL zrUAJodM(9>j#aEX`m!rIoNmPl09`)e!8`uDnSw;#DGnA;jMJ|pmAp=ICRhnlfYEQ7 zhlV|r;>kb~Wi%Kd(wSHJ`tM;-A!lSfks=P2z;UG~;H1jP=oE#8J6$008c~%?gAsh< z=(?yCShlwu=QS;|M&r;^8!LNVm<$tfk*jZ0F_2FyJ(FQk!~WW^W}ET~0v?5n^BbxR z?i9^~ytxaFdUgxKve{*^)_skqj0iUQn^~Ww(MS>)$-7fL9ZHq6jx1_-eDl;X-O&;?`XaZ&dDO9;yl< za~=mSYFREKwWZ)dDAcYJqRnQ?Nd1YpRI3ndjC_I zAUnUWm^=mDlqIxvQ^qi@ZPtUL-!>bU{??31v~8WJ%R{W$#Mo53F4eCTnr&8P?$iR( z24x^nsbD{LquVH@{qx$+RDmm1% z?AhoBr7}?MnyBVe?Xf&kQ{Our#cfI=HkoxzJmk)1T0!-T8XN(|3-b+ z2_uINz5riK30Y1#?z*)Lm8qd4F%r6w3BQ6%y-dc-UoaOcW(CZa+j*;Y!A3N!3*Pi_ zRHi5b6OsxmB#phu;Ms__DilppeOshV)*p`#$FQ~#0wQr23m&|o*n#*;Xr&=KrjkBd zNb&v&4#w`Aly5AifQ;|FS`D1FJDXl4%ROHSRm#r6Dy+Wqsx+@vg&W?Sa~PNl8OOc2 za+kXtPW4EIX$A6)7=Z!M-_>11Eh3b^cuH1)ZZ1$N(8;Mi4H93~Y3(w&iryTQ@9*ly z!;jQ1kIzs@dKVcAxtj(DZ}y*mVm1N*tH7qsek$J+g^C7^=CUe2*t4L?S(K$V%FVd{ ztaKETeJV<&k-a7O{Pfd-Mdx<-8wk8<5~5pykA9y;u--a?jc?RBOwH*dxx~dpfskH^ z`?N_@R;y6XwLzIqttlInW`4EU8HH61jwOP^keZ4wG(=m?LT?mth*!utQMOB_hjWU7 zfB&gJ2Fu^k_2W-gX|NuRo9dv{QQQ!Y3jc$}_%xb*0z#G3TJh47^{`RJm}Qv)B1nN4 z3CU;FF=x?&v=dyMstWQlI_JkJPfa{N8;7-CWi7MtdQ-k#6auJX2*i>YP>K1maaBcp z?B2z0{lT3T7;9-X#6Y~nF)^x|6(`X_JB`LM%}p$0K9)ikL<(2jVMNhe8$yghs6RJ3 zn5L3s;%ACjlYjk~qj10sWi^>b5aFpvwS{E=AYEwg1~LfU#vzr+ss~y44|G6_0~iQy zQZaE6ovC^vf{psDk;+ccsV4}NcmhO4fg85KCgC3CmT54dyY ziOkcNe+EhwLV`${8S@kIj!*2ong9OR<&$(Z-*L*k{<^?_Wr?D}q-9#qok+P8DMEpY zeJNElY`Ak#=J?sjwl~TbwN|4o8uOUiR6%zsi;!*=FTb^e*FO}#Z|4FFJum%H$@nN5 zh1VY4k8kuoUIAEz{vpB8(ctx@hE^sX9f$JJj$oPTF*1IY>w8r5K_ZFOV4+`VYo$^9 ze!p3|Pe8e=L1ix=XH0z%y)8%TN3)_@U#%7H?H0Qw!#Ny7g9mXLys>#d34Ua8^fOz( zZvkiKY$Vk|@`EW%hOXmz9Q$446?4Tec}lSlzj^~?zcWpttL5(!5Q4boHQ6{KwNrG< zaK)&3{nPu}zY2(IJNWVWi#_j0`U)}VNasp4OB#(3UfTEFE2~whtE;&aJ7-?q`s$#E z)^pF_cob9C8|_PI)x5^JT>*!Phn#)IS@}OmM}2hsaZS<#B3g zDmB7MMKH<5PGy0tRjgp4a32~Iw4xzsly*O&Wdt8x*-w-sf-^>umaZ@yPn zfY8Iy(!@J!O-g_hk~;w_l>sm5mrzZuY8uoi{m$gs&^cBq1zrIgP7v{But>PZV}4p? zYvTK-PnKKUyRt+$@m-p=TPhPy$a3!c|2;u#M5UzZY9J@~q~d9oB-(oOjRGwmS55hq zUGVf~$slD@g#?Y>et$!v;sC?H{ccHjV>jW!zH^oo_}!*)v$@%=ctHHxDwE1 zYcoSH4sm9HLxS3>*rgO;LO#^kreOntA;DfSaa7|~38JB8d;{K*(;!vsx?-vA z1SD~Rfab1MOrt8ru54td6#MTUJY3U)wn= zrC9@RF0HH0E*w_=q}tkqR*Q|DN52I2*V)bhm!6sXYkcxUXMD6Qj!+KtmMjZ<%$iju zsfgh$AY!vv6-xzKxLPWxbn3CMoJs9Y4ZeAah#nO4X;|m80;;zHsK#WZL0;H!3bj5f zK#C=At^sRp9UNVr4bK;vT%hDkk@Hs>;#-*Dm$z9Bl+d9|**d8WD}wT?dZU!Bpp!JJ z49b=T?#ag$Nm-!`7WFr11r^glh_y?Vjrdbr+=h)D{BEWff6vQ(bOH+f-K*)i%`?McJk?>ySzPlAd7n$Kf2t z^4RFFPpK|S(3Cl!r@| z5(vs_7Ip*5*zHWW%#v!PwNR-;bNn;Jc;`|qxxlmSLn@Ni0_DW1nMBJt)mW@|ym%Bu zqGdm|+qyPwENSdKmjz8`J!gURD@mqXtyD^E%-y3JLMs8PU8y>@#`Or;+~HoP_ij?T zv<6j4hs3Bs8hoo%FRh1bs+)3Wkb4pKib1+q94S=;FO?j1H~5-L4lB^A_^G<0DW^nx zE46UgWW`XGsc4QryJaHy$%S^@Lc z>!NZ^SURm*8?^#YiTJ-+ebfr5Vy21cYFHzcqpRI0T~S^rTnzHuv{ov+ckEwhaaZl| zP3_-*Wz({*ek!T+#~PFM23})z>E^0#cK2A<-A!w&l6;?9UzIRw*9RLdDLl7YXO+;Y z4BNZp>2+Xe$MV8cYqdg15FCF9QjU$P)|obKy4tk0P8$vFDt$%U@?S^3_%8eA3Z^!# zy-K*CPFnNl^Huj@Px&A2<_IObr5db++<46?8g+NfGh~+tUtJxj0Y?$?pFVsj-!wN? zsLe{W9a3-%Mu+!T7ivh06o>j1MjRTO4Qy=LqKVr<+t=Rr*Jk|Jp+=J$Mhyv)GRLPB zqRG(I-&R~6&8>3<@6e)I4Wx$D$X7~QrP3?$(m^+|+I1AoZXjw~{nr`yu3o-&F0pHs zja1Y%9kea%>& z!Cg1ApQ&HmR-Aql!_+~gi81P!nH93;vz3=60ZFq|6Vq~oV&CVLgL;9cQ(2kltlGF- zB3`vY=^|Z0xwICfqwCztaInT38jH@*NNyt@{01UUr_RGu=42|DG7aQQ6UkCz);V}L zG3C-}shAP3&RSr&@}W0iv?gYnGqz@?86s0zp0;9aa`B{zIi`cCHo=;iUCuZfm|EEa zuNcRzFMZXz%FQTe6kH+orjs#>Dn`-FT)JJ>t2B6=Q8qAgg3NrW80H-0y7dWLC2y8* zSmj1bDkEfc732DhqPw|4;u~9q5n>82V1GgVNLDVW7~gG{yyZS#D;Tvwsp-HA?j>G# zhYH(>%;){#VTf!-=JGd6ZjueNYdSNYY7eB)ERQQo$iQ#P@9|U)s9Yg#`!aIl-Uf$P zz@vgDELL?3MZH*@)ZST2>BEFYr@W}{Nnl=mV3I3`ueUHO!qcSXIp zX!1XIMZLh5g%v^yRjd*v;J;Q;FTZR+wOSTalxmgED9sB~A#&-JjU7DHOm<6e3kgP+ z-lxelmY?TRnmMn$lrB7kYKZ!uTXLIPJ~vxZ{>kFh)}~9ZeP{}kt>EMDYhSE?jsNx5 zd*NXH^hvaipJ%=B3IDs^JKL21uJ`nBJlWhFJUx55(c|-tUUaJO@xA=?%zw?(^gmC& zvA^~~#(B~`MX)E6!HwEVxOmp>qh@GVlQUR++lU0sOG-ItPCD1&c=W{=?RI-DoDOX% zIJobI>1LaB-akt^!?=6dTSHDb5J=NF97RdInDryX2O~c|vth3h3#O!_3=Jo^!zD?w z4W+VZ)Ao5Z>AYW@MpCQ^IYbCtYZ7e*m+PG#DgXci${|D}`|$_~$fH?*KI-)K*A7;P z;I$P7 z^Mg>r*W?x6O0($*S6xOWI7tfxL(Jv}S-&XzIUSBwTA*I*`C=5#{NLkq6w6~~2l;%8 z;zTUkVW=p>XtTnP%u6^roY5JERXSRXCuWdLWRvt~L%DUg6=a#HO%MWg4Me^TY+{iA zOybF5IKS8mI?D1L%&2yd{QS2E|GmQn_3gL!kNC~~hi^?Q8K_csE0A~QiLSq#Z(|7| z8Z77^y{1v)!n1-DGQ%L7yy9Wtt&E=nU&aspl_97scG(L@(~D4J&=cHV91FiwWMe`m z+lPB^9&IUbph|V&b-ml{1mUZsKC6w+HYf}|0A3SFG z3Gux;P&E&QF@PGCFj?UaU^!T0HpZs&M;XQ@dBmUz%=-iw>$gs`2=wR z7B&c=IaEeaDGPa^gnvJrXw*%H=WW(*M5s}Jj_f&Ikg+YOPble<&UkRo zO4j7QGyVc!bE1MkWQx=QsrCv6h8*%airC!G}jtMgSb;OtJ3HFW07w}_9ixj?8E zV=u)@;@a_jl`UX)( zJEtqz78NUrjYNJMEMH+&B=|>`GH|sdtuXy8F&5D;3#n`a^VriK&#`W2-0+rvN*13s z)0e)3ll)RI8i3At^G&VP#-y2&vCdnJn4#2tpP>#}r==>nriDN*9}we;!I(;CyHK{M z0My{T)Y_uW{fu0h8m)3`AGO+1-NctQjqSBUveez6*py7fw(Oc@BTffKU@Fj89bVar z#AdTt;(TXne5>nNK5|y2%}A}z3lLz5k9=U<$*EYRxjmz1QXEz>+y6}%$?^|pl`OR^ zx-0nzb7)k!8f>$MMs0-DC+nu7jekh@%FRnOtq9t6rm(eR5y}!>+Z;DsPAvZzQZ&z1 z6+v>A#cWpGuXMrZkOOg`<3It`jk6QLA)}}!gd~s1#;CsHKkoPiD~4%jUc|9sTgB~T(Cq^AscKv* zTa}5`zLGUuAUH8Si(@2EG$hiw>JZoullW@l!&3T(J-HS9(%QBq>3(UI;M+Q!#pl3^ zwh9_aqK;o$yV3b9M8%n3TI}jCAV~jWKboCKKSbBxN(brVVYz`85z1q%C%6 zCivOsb})F(;rvoeL`vFYEzjfA#Ti=3x#OeWBPer^C`7-_di|yKYk+yjC{b?}ikUD` z68!FiSuS?i9}Q-ZX@)#6V)dO2efxs8bkS?Vd$UV;)ZX47AkXQf94G`!F6n2A1=2Ew6V!{;a<#S+6cfk1CwH?x zQ3X^jY($|Y<0A$#ND2vE$Ob%Vk?BnCKA^I6(?r1a<-l`tP+D^+XE<7@fwwo@EpDf)o?jjRQ3sJhpa zVNg$*+XhrNQ%@OUT((uCvsG=YWX0Up%A4l+li3eTu&}EG8*FKns@mWSWf$(z=OuYT z)uGdfM~q_$BvBPMq`1bmHOBcUifm-zpctEE^{rY!lp+Qobrk-Y(i+>ZO3_p_c3=gv z)-rq|CFBwh3TJ~kXERWu9N@w!)}k7j&?Y!#U_teGaQ`g@$pl~+1gw5R5iB5LPB(3v zXqu>7SjZrNQ6wM*@=TY44TJMVh_THhph0((oJ6bdBD?DqW?q3B*?>FYE1Z-aXoS`&I7G zw-5jJWl2}HqD}Y2MyzVKPZO=4GL|j57BI}_QSc%hCHT*e6WRRA2vufjb44Qq4ng@8 z5A$03D1UGIz9~tBW+fjx+a4QIcBQ1i8qM(+*c*RC^X(XA8-D6>H}guBbO8duBG?Zn z*Fomk7N2%uMc^a?zOuBUsah1}i&-wqrOLF5_S2}3lB(EIXQ+8R3uo8aXs{Dtp9Ra~ z{n^52hjTiD;6V~aL5B&$i+jXFmH6T5a0CY@Rj&c-dY_GkV(FBUU^t%QL;|Z>moaKZ zL?3t=U7|+d)q&J_FqkC0-p1qO#pxg(!~TCUo_8Pq?ZH1#&k^z}8qgnsXAes{$*tAL zz0HzF**bjiGgcuM9~NTU{PvZ7gkFE?*gw4QAAUvDa%=eQ&uv}UT+f}iUp@R=wxHiW zyy0^8pN#4(Aqhl5EB6eVX|_f2^S;x~#rsO7gZCBJiRXpNrh>my(bbne7g-QE$I-OF z+Azo3@1yG_p9~=(o3yX@A_(mefR-@D@#8G~0kSw69b$hOd-`yMLZQ8C#j2?4bp~m| z%tK&MNO@W$OPvz)X^4X*qXfN|{>40ziU8O@Wp`JHW{h);!1%s8!RrY$w{iGB@(BW* zlwh%Q=T*<8`ba!JS0#sHy@Z@mqL!X6ALM8&4qj{iJarZFnL=!uD8sf|&2cC#22hArBv5y;*%r@>-ERQ`Qp zRJ?y4SWGQib)({n6lUH~v&1{H@4<%_(j8M5a z(+w_*PbvAhK0Za3U+~HC6uuE!nYt8DQGzO$G=FHn%CPx|Uv%7sQ{079+=WwceMs<} zjrNlV@=syQ(pOfhWepvj&9{b+Aqbs=TYP~-Im8R$KtVhJzOS+c%&z>4m~ZU%QryGy zVRMYAoDXeWAiv9g;3{~1R{Y!=KU>iC%Y2n;9#tF!IEE77wBuP@t%6)MYKF>^6=1gl zNu^Iaz*5fct?B4NO9V+Fo4?O$p?vPDD{mSOXQk$fN1O4R#JDez-=r-5Wh_&7-tU|K zdWAnyN=ccL(iv2kmzU?YYC# z;O?M3Q+BDx-5s>w9kkyaw5R)Yt)EuoRF;E=v+tel`R<^7NnfE|c6ZQzchHVNm%D@Z zf7gR{njSyu^{t{2BNexY`7jp%y;EpiI))HyhW~^cCEm$lx|o*uMx;nCh?U1m8)}UAP#{8CrvrOaZI9x= z$en@)Go;+kAiqz|8!a5<2fR$IB3xX#=GAt(#FC^6 z{uf`kyd(KVn)6Q6n2yH{@{VLY&6SE$M(wNU^dgSm8_vn|P0AfSPDN9PGj3&KZPtm^ z7|dYYHX}$=hA=YLOe}xh3Z6W9j9J4*7~<~Q{7{~KqYsm4gsF>XD&KKPGzY`BvD_!P z{bT+dMKc6YPH@?0CSXjzHYrJa7`JU`L_1v;7YO)RTbl2uE6Iv)Hf?N9jSPEiWy;F3 z!i>r@=bs=eWHI3i5VcU~o?~QhVZL0D?j};ip!kQ#5lK(8Bs7p@0$Fr{d{JCb*8o4^ z9b$(yPzQNoc!^RTsh%yrUdh9P-17C8NXoLM4hy~1!_LB#3Ubil(WRb@B;=3=SQ?Tt z?h{AZ7?W;lx#ehWhhCs-ftpqQjQcu|i_0q=Z=`v?!rd@j->uw?|KOFEVYC_r^0^0}N}P6M z8{lc0Q?N!Sd}4LSMmnKHF~NA6oEzPiSI~y%$co3i+}4=P+XUfYJVZ8$81~dTR3FoD zIsf1rMn?(UpVYe8$;15|c0@6mA;JQ!_RjQ$!wGG*c0X+MrU{ZkehfNC&~%sv>%e-# zU~G0*vqi)PnVh$AS(pmpO*GwX609x8JZ9N6teLriX@fn>(*H>8**DnTFd4?`fx$)v z?y`4^SatlWiNcijYUmh~$$GVJg08_PwZ3Rz<(-M8lm$ZkfkKB2g>+$&MWVKlatLbH zPD^LL-Z^@{eezsJ)DC_;+_ir=Mg$u==y9{+b?xV8XW+#IsUacQ{>x0NNA(3gD(BYo z$-m$fd$9D+^s*o5>s9;$z4b_Zq4=g|4|r_z*EZS%2GMjBUyrfDdgc9enq+xpchk0? zLxw|O-LfC%W&+t@k$3+v?w3Ln848Y=Jr#H2kgEeLxW{_+;@CWsLDby%EPv|Mj+>tv`E;>D3>$(^+pr!$5wH zwzwOygQQKO$))XuaCIj>e7*bbV0<76pZUauL0t%94J{7m|Jh3GUse=J}y)v371c zgq?o8+|}{n_ReSM&pmL%VBI0KNo=S%ND)>T#7&fv;S45Wb_Od}64FlRmY5n&ope8b zje8@k@dl9XL~v|${4_8DLACtL%2b$ z^3tS(Y1%%&1mGcD;N1Co2W*O)^7)zPGMmSLN2c&pq%5`09jWxz^H4`aI685DaX5=l zovXHHV?McnPID2DkX2k{opNO$`Fg*P94u1Z?jj0D^NZh7p5r&_k%#x40@MCTTJmtT z8;!yxk!o9DmWJ`b6}R?XvXGOPJcc>gjATF#rS#K{^qn$T-m_1L>FI%j7Yr8Fq3W!BH`f`!TNOpX?l_JtIxTKoVo$CbbFl`d^mVm&|A$?Z*pv(=(QZ2F@oc zsJipUJ&x_xD~X1mdzkK)sCWOn3txV|&& zZ{rX#zaXrDRFQ&%9kgllq%ns<4*6C$p3b{!PjuO=s~>g|$TB0QnJmC=vpCfu+m|_* zB?GuEbeJ{cDxM9z=-8Jlql0i~Xhsm8H>OiN1@W0EmcqXc6fL1Xk&2FXryN|#sPhpL zPEvc+AIlSc6crG+gMCrPmu!Y|6JZ|h5`HV7=F@>>bBWqK{E8-`31J8MmWmMmxAn}P zyAmy`LO8IWqr369O!AH#@2=L=&5f(w9>wR-oafM)X5S+3YhH0_w=ciV?Lp<6JP$D; zVG#~dx4CC6xv8(Xac3X@ksG#3KNja`69EmkNJ&_?i#c;+%_GUZZ$KCi(RRO20et`g zCYDN7+(z*ejRY|ek;w;UlXw)r#~sV)uw+Zuog&>NQYO!{I2aFwow9v|VQQj=?IX(; z4*WOr+J!dOA)JomrR~MK?8u~*i_f!5Slr6@h$5nSY|6e{f?FxN8ud^Cp|H>^iQq^e zi{_I2X@rsUjTZ+NPD|BTvtcud+OY}Q$RuI@X~q)-YL(%f+M6>cbKN>VdGVb$_Q`L2 zExB3h{V^L-XNbO@CNW(MoKjCr=9b)Q62o;X!COn_>Yo;Vq2?j7jx8PV*|2~#?m|N> zxX!GmjcCn; zJ7R-w8}P>(7ie^arae@s3&c=E(#1RKJD*#Qt&=$3#(cT?*z#MA4}CS6een9^`Eh6d zVg5z06TmAXLGUPaN>49OQUhkVJ4G#|#e|Uye2r{_tZ#&bz#ypbh2%@sWXG)o?00lK zfEA33*icRLor*1h+`?!P9K7Cr{_gPg(aE=8KA={J3T%u{gW8=^vy_-YI}Vs;A42lt z+t$Ypjk%7fkUy`#mCU6?;`bK9;UxkzA*AN(ff+{gSneGz;m8d{y51 zSlA#@!e{1>-&=w}{~{J|6%3Crg;;xsTlx#BCbUNtJ6zq(PrxgrR{SnRI4De~s!4$I z$jRRd_LzeeiCmFi5;^tGqAQ*iELdoVNhNtHA`ddyJ7l&!W^A`L9GrwEe~%Y(-$Zsd zy;7lRQ;=vd$4B>9p77+dAGEJln?_d8GShhc{OHZz&hvMLnH0E9IBq2d0&Cdw20C-; z&qXHd^C)=0@bC|5eGDeTw6oR00wXH~>kpwRe*DQ^Hr!Qy|NT)B z0Bi)w4No9WNCfTSWeJh4JLh!4P*nxe&g+Ad?Y)ENM?R^9(KcJ}Us`f4V<0jrJF4M& zPbF6RSjAR4)vY%O8k<`w;J6>wxenou3$Afx0FeNx%%)aomscZMN-Ww~>`3)D2r~3> zFton)rArj$COzI;iWQgpAC333-nxzXui4MwcQ-#P>RIV|7yU)345H;ozqq-s^~p+> zJ%Ce$FiW?iVc9z-lNd+5dVd7FwzwnO0Uf+N^+RvDU`rY!%V+v4)s$UdA2dDFx6{{1 zPezE=!arB^1m?q{(mNh|@`*D!w?fyOshv0%K0}4aNi=BdSkg-#d~+;sq@b^3zps=l z71e#^4i^Y}t82$>9E{=OoswJ>fp6`k^gsT5cWj!So^y|=b@eUTJH;`k;=+(2oi~xu zbkbPoQRZ~ytF0jQOy+Ov*hV%^K)pPs+luQtj_sBn)xC!E2{QGz z?AQFIn|~JzHb16+O&fMo_^dg9YV2^m+w{AHpM5=eE!eu9pM`J^jPj4QgLXc^FcFUIU~g6n#s>kX{p|@lYQnW4~^z` zX*&_xXTj9BqJP)`FBC-~{}_EP4FhUxY%dP5^PwEL?AlqjhQu!g9_YZ-m2K=3VRX!f z(6Pl_RnbYqq11zC)G{7Y-Hf8kdK6O|@C=Q_*b2&y#oYaK#k=m2J@2UFPpf}5<4*|~ zgG=6uCTG8d$gy#VnNsr3$o_YDgkUrIa4YyHW-lM}?cDc;hmL_m9Vnkkc1u1N3vL{% zsdBfk7le1D2Z5~7PbwS`Cnd2^67R!ZdRzTeTftTu3S~?S`vLdew3TD3YJ8!MZf`MCNqXenM6k!j|@P_Q2twn6asm zmBc{m2l$@VD^@u(xhd*~&d-9@eQfpTPv$X%mR5 z=j50!_p8Hyxrybv0XOqP6DL(B*Kmrq5;@Xrg5`s36)lfyM`CuB;QIR;)A2tgLLXr& zLF+HAp!Ke``ohAo4o09tuhELvriv{j%D9tUbY%dw_P7})J-eW4<rU8e?oS|kSK;(jn-R)qT9oueTrDkypnaS9+0K)m06B$ z?8gdJT^_JnDa&I@FLOc}f~=y6GD?*~4-L3>Yo~>c426s1xBhl_^umiS>6~>!c}cK# zLos#=D<9KdGhXaQ?B<#{>^NH}IWg!qv$mc=(MG@HAO?DDePW=8sdQZeD`T?b&Iw7| zLCgFCa=Is>)&_L|6vR&6Ke)MC9+qCeVGP4+b{6A%jBmwbXECI&CRY>Ve5gud+w|yT zHB!LtZOWa?w^JnC#~^oGdK<@kgU|(z5-4zXYnNMtL4AJD&ys$+;{EQ;rZ$uHO|E7$ zwKd{U8BVH_@b~$E~ckb5+)R7wz?2RRS zSyHtn{#|Ud{BO(lK-iE722I5r=jBB#(^uJToR%oN&Zpbc;Y&mm^LtSPf-lqWT3efs zpFJ&pvS-8E%RhX&{&c3-Sk@{rSfzjtta_wvSHU zWk;Sn&yP;_UhM7Qmh?NlEWHaX&sY$d2;2*f;eta>Ph~A`WiL-o4jGW4Jo+xjP%t0l zL&F|uL$xu-%mp?TR&qEZoh2VfWE+iH3)(rDl84I5m=3gT{yq_0I%VIc3nN_y5}}eG z$#UZyFQ)fKceZz4KF1+u4NGJLz$EHDIZn&&^TSuK|NicW=SK(6U%jgblTtN>Vy?op zr`O0mh3CtHT$P z7rOhxQ_0!Z+}Ha})AL~)i`-~mkbIVs)sn}Q6Ll7q`PGz$hw;FpZ7?FIiYiMxGyBc; zNG7-y8pEA8K^c09wG$6-fE8p6DJC~;!Rv*t)5A#PR!DF9+B3;34KJpD(A+LLT_o41 z@dqHv9}}^+75sdkP4B-o&*hdd9??2R@Xij^$IJZ!EO8;pz627HY#u4iLgEKlpg?5eS3=IzPF;YX>nVPC3zuBqB-1c4^G1!x=2xt1Ej>mA(x zUXB6TTrDQGr!oOFsiViT?q}%HA*&-KBA!KG+zW8Qkm{9`$kvCZJoaKZqRoH=EdBQo z#V8hcFF2t)E?G?FbUsJ`2*IPcBdPV|(fSenaadQEktA-(J;$~S0F&rkBU~RK85Z1) z@W;t<+JAd!N*p7@3BM#t0bHf<1x}*QT4(q8-7&5WMgXy+{*pI4$H9QLf|Jnx^=lJ{L-2RzdPP!Q&SWxd5Q}`c|GY}|ukA_*!U1t=e$r2|QV%V8KqopZ3j;B1&&v@eIV`63*NcF$xC zPMJX7%sVbzLlm>qft(}`Sl=Dpx6{6`k-xlTSXdp+4R(pu*In37{{z*`MqBsHYFLA18}a_3MqLjy$o+_n#>%d+_G-gikth;tg_@!-pP zev)+l0(L}aZS5pBim75X26HfcFc>djW*7{_!F`7KpZJQ44k5`yp2&nFllj2p*a{wC z-_oS%lIa1yY%GfC1Jb90ePsmV?8dZEtpg$wr-+0KT>Q-1@^EWy?bly_T~lq9%8F5% z4SCW7AM<$nA$oTTGbMd)+U@E^x+6?sG{a^8Z#Fu;&1anr$k3-x0M#}-I6j7>&S|pV z;nCFKqCY)ibZ+kB_0GonqZHJ7=Na$k!}QM?LaA} zWe&g)hHzgA`9aRFgv1cmJSf0jGNBl^e7GVc!*2lQi{Vh4S%ysX&#NJzEhdQ9g&2qi zVDF3Ya)`!Y#?kP7gyRuh(8)3D^x_(~!!f5GuFaTMjs|T`H3*UX9{%-ed*@lx+`v66 zYnJv-rIo6B_X0ELmV%5_*F7cO8!+-P`1|($D@L{=^9+x1C|TKHH|mdgymJXDN&zBU z4n+d4nxh%c5n`o%syJZnWNdmbEw+hv%AA(TYyr(YFQhbnKs2rFkPu&yfbUX%SNjmG ztV1m1Gz<6td18Sk7<(kC zy|7&}oWHQ*a+vY#OI17T(cKeO1bHY1_!NV&ieJkFnZLm1IR6O@O^Oy}m9(Y6nDc{?VC9qz5rc_-L2e>3x(imle- zNniw^={4;K>MZg&CUoi*MTrHk_+6`_-NubQb8`4W!~SvmAsa6FjfaSo^mHl%0TGpY zzCilllie#Pemue`C$%gRX7?lmt85}WUR?~~q3|-KDGUNnJa3?I_U<9Gn@DvmACXGD z=#i5f+<=m38X^Nt6fhs5jKmR9Mxp>%zR#SvwAg|mCR~6s{{Pzh(x$kMWNm-uSDZn< z*YdpXZh=-4;Wwg{X5bRtzS&P%fkrnIvfY}h>}oti-6cew304p%F;KbQi+`t=W@xzXP~EN*Fx86Yc)^Y;!}nAD8yS5btU!=ER566 z#hM|661M^Z`lQH)2|zj@hsSBfC3kf`=YcQ}IEcxd2}TA*@sEG4tfXar@ZF)9NdF=`yq>n2EmL6bmyVV|QV< zUX_%s*|FmWb{*kSZyNE{jVV3VEE@SpYt&3f{lt+JDecPuX-5xOp<0W zCWO<3K$^lUkki&vV&@M3hl(+_={X00xfya2uK(}_NP^GBL}rf%(N|O8?}$NSpmv;4 zi2W)Iwegj*2@wg!$a@P!d3<@rjd|x>21I~P^frZK$=dp(=UiS+@oxyoslmqAYX{6W1h#WBnb5wi=N`{v6Dy6o z!Y+Aqb;{OSV{dQ{JIv4fgnpwhP^^Wv&`FMauCk(Q1%kLyu=&dLc?QCTP;3 zPyR*}Fx?s~ew#=G7@s5Su#n~eHvFz6Oq4A&!f?0af!FoSI}wT;|rVe6<+qk z4kZb1xI`o5zfpZJ)%PFV=>BItxcV=$4X?M@4E;DPd(p7x7d@%%9M)o| z{pj>s`?Zsq-t-Vg0JG!ThOLCgr3;0yUw5_0g%ZD5&W~v!L6RX`H@q@w4r;^(`5N$V zb`kFCmY8(t+t(y?5?y8MLR6ebRZeQ0i}`dl^b@fk0MR*w>+J@3YV5hI6HWMU1TZNS z7b9Po8+AggW)MX!Md=_BUBtlC5m_i8!|oZeseE|VnGEoS5$tRsHGEy(>-?~@)-dW# z5iuf(euP-FloW8}J6?#H9=y$Z5N30vyhFTTolXZ2S^^SUL)(siQ6@tI(w`b+EH>!M zH1a1)J2B9(R-@cPS5|XI@r5-15wil)8>;zB;@yJuiRJ#u&l0Ji%pxTw1Y-SG{Ze|g z>UYPm?-Let7-4tyxCfNZV|CVsAZFerijW1-e;Wh$-c=!7JAgov2JX$i-7Ii#67n%< zCpw03G<5)K#_WGH(dd&tng5KqI z^f1o%4Zqd3DVEmQ6hof11tb2vKYpkCqdC}e%h4}_|En0DnJ&Tc(9NTS+fHlWWf}93 z+U^%_=gek58Hx`}TE`;sD{;%CQ*EDZvMkK4s7PiBRFR$Z&L0wZLrCbx{yVu{K|6pL z8lzON_R^7J{Uyhoi^1#!NT%9=h>q4xDm6l>wQc}g?F7g}bgP=!dp$cp>&?oUpdy2z zwqi)NlvQY1jT&R}Iop9=Uzg7klSoXh`1vrx6MBhq+Fasoh>sh$*mm$L{^4M^zrX*} zQ_1U@#O+qA1xss07Xg0W-`nm# z{{B#aeX;kR;L7kGG(4F(fzTaeQ?VPXQ03Q^U7Mvuh(3^L=kfgeckX=~Wlh>wf48z^ zP4EjwWv*3Nt<3tYUz!E3Us<~PcU-|wBkeS@JMxcAR!B2J@OMk;mmkO(2atZNi6+1d zJ!M4FOW+bDz?O4$9z;=ik&G3KVGD4+!C>t2@+_Q!X-NzO+BX%-8XUqE@qF`;x z6@do{5IP>zS{ck|fky-$AV%b&6fV(AV`R`h|{5`MTM><)!s&gfr z&*Eh*+uHjG!8K`X;R5^`B4#){2~DeDnJWv+$@#s}?6`ON^SB3x+j7>U=jQ}(syL4S zD4UV*2(MeWtpvz)83FebGFY{iqTfY5A_QKxT;hy{|ugvdAu?;JAttn zgc0W263*Q}=35@Mgj|;E*!O^uent$qsC{B#rU`32UBAQ=?#=rNxOLy0x{9 z!G}d1trA#T@UES`lKXOa(vGu)?05({KHrh|2G)&UnC2bL6MrZ{W(IDeE0BkqMC7K*D`hd5G*(-Az(lf=2r zFhcOLC))>g*At~CZ~(0xoW)+KhcUK$5PAUu*B7=(b94SnJ2P2 z6sGU_qW+YYMn=O?Zs?E9CQZXa6|jfU;btckeb@p0DMy@~mwec9k~buAsHE^6N6X$3 z+$_(~{h`MLSP*+;-SZ<>;s&^Hd)ebd`45omaP+s}SzwO>HML=q`cTNhlBa#TEQfkz zRGv6U*nuSfVl5vYcg?bC-SQlaA;TITlgzG4PiFX@nGIXfoxTyY7;-o+H5$V2H>Y9a zqJ6YHhK-~B+PMqmGC`O>or&SN)4JpqPl8Dc(=Fx+_da%hLcEBS)?%==G;M-r4zdX(AcFZCia1=YZ_9C8E$@z-W7=T_eCb*lcg? zBh0~Cdt)CtH1?RlhN+t)=bI2p1CR3GBFYg0CJLGB#tG13BWg+ecKoimjW9FA{@La0 z!Oqorv5xG^zIE+sLHgV{aAMsK4UuKx<Ttx`OwTbANFSaIB&bdGpB(i=e05(nSYwkm>cW*lGb>0z;{@dMt<7Z zsZ)()u4&`bVSuop%MTEs{tfW#Fb_x6T;?5W`>d;6JXG-Ridt%fBZk7`ww?o_O_*BV#(DqT10i%0 z26kQ@zIgY`oe_?R_c?E)19->1mt$W<}SSJ4en&}`G6+Ha6 zSU+^jVM8qNHH-bfuVK%cC5&n~438qFb_rZSymK5Az4FY=-41LLhD$|~q(BuwqPoGj zUQa3OkvVi%KxA_1(Z}KklY8)*U9LRk@YgGlxk+5Y-CWY(9do~E@Xji1@|a(N;}B5B zL_Vk4O7uTT3NysfcpI@L874W&@`1vnAb|C??WlOEOPok=vgvsds3F5x&fj!=DGyP| zD>aRLsHUqpRE_z}3hx)7Bjo06gE6M+n! zP5>Ycg-6UD%qQ-r>Q?s}P2ql$jRvYD^|jhkGxIqXw6)?6E(91+LPfni^q$;w5`N$G z78S>LaT2BvA{XLJ4H>;NfwF}!-z=~6y$4I?8d>+dq*j{{tzquRsn#Id;m!l}PY=Z|zmoLo?b*sySGdYwBiH~S&l<@mC%$$33VH20pZgu$!5 zBdDuToSN^#BW2B#Vx~oM6!M)7xFb|eij7Vh2JzB%#pTezd*XRW(0k;MH1lZTY@RU( z|FH8NyR0Oh#PeoesR`G#kF)vsw6+SHDQon*Z^paNlR47YfNO*qoYkE)q z@P@g|LmH(8cJamW_DZou^N6h2!<(#-F-8<`mc!3&9=OJW&=GlJiA0<;7{m29oI6m&^(PT`gO791MH7+&s&-}m>C5^`I~r&}JN~s+_655v)?*Drsm|xrl09#CWLHryN^(^}*+NqDEO zWl|88T-P7xYKaN6spKLOCxWHzc%z}5Y1oAe_TRcXC!k_WKEYntf4;0=G%nW?drsqj zevpk84K=)0atf#UXQt$u@}uGEdS>O$tqiJE}I}ZyfZ0ox2%^v zJ1opjh$KwU`}_ZO`2C9)2Z#Gxd#|?k@UZbQG8pd*gES*~lGzrAxi`Z9O>HWKVk4q5 znGGV^3%P_owx0A~K07$vd-3vMYcD&~jnKS(nw`!1K;omrz5dSAt;TkqjZG^jn?7R6 zL6uPSCa-02=(VjSi1s|a`};p2De#}NK^OFpjn3T8hr2KKn5mjkP5I1ucW>+Q_U1wV z`)6B+OlG~)f4+q!V0u{x((sYw9P;!+fRcT@+}}E^=CVc?cupc&rtMRIcU#UtO*f4G zQXk4m*T`4R0_E93ji-`vC%R+c!7-<6 z$VjIwWOwhytL^>m7dzWKPY<_uKrB!Cn~et)9`uF8u$4}-<6;RA%pRYQjXZXskJ{;x z3~J4?(QJ((3w-sgzY`~dGf6Xic)e#Y4tehE|Fr#t=b0q@;9*qx{?pd?eiA%+v3I!r zy#G|rx60x4q`!Y~c(B*s{IPy;aTp6untXh=y??N^bBO#=8Ia-BYsOxFkKwR3Vl1zk z;mZ1M6}Di2b3qFd)j@yn;BfQB&Ov{B2V&Od*51MPlkLs^0nV!3$N2AYGA#q?NAQ}h zXNbj$ZK)DjWjz(TG+7|Xu%P8n>3R4aG0gRV>Wf9)+I+bOYFrhe!v@*gg4hS-f_(n_ zPgtdcmrQ{eRwe|nonLPeG7^#BgiqVYxP*6Us7|li3RQS@nC!_!OUJEeuq-W$<|>)K z8=mWEMS{UV`pxJHBj1RUqO-W+uK)7jhr@mBl!L9OkVM5*K)ogfg0N=u>t!%_;NKvn zR7j0B7{HMxoWz23xn^}|Z+s|WceV7AU3tpClG#xtU(eFI_P1-x+EEt1sW?QoB3eni zv&*wDzWB#KdVgHm`sI?B67+@Vou%hr5^cS^^2Z*|ZlX$aKejmU~Uh#!Nqb zcE&`h7#wd3m`a%*M)J8Guh9v~-T#sk*gpnz+S)j=*1j);ZsQ+B{g*NwSRfqR3)j;C z0E__%+DW!8C>^l>yzqv=x!?4ElpVT2=Y8p*%k-$XGYO$3zh*Qi8$cJ6`vcm0$xP2! zNLf&$4y`37r}jmaN^!STXR?`W8vXs14fanE8j_YHnc3?9!2^>+@#?+V1`_87b7gDY z&1y1J2$|0eaYlLqw1`nvBdATMtIOJ8BR!KGjn6_Ztw<$CQ2onGpCZ0t4|nqnwuWpK z;uIxGlYe6WGsCiVYsX=|7k&IS>>M$DU&5))@LOrGi@%SJ%>e`|MNP`OxX1Vu zgpyjNZ_YhA>~dRsB0;xIM{CT3L2I;(Y+NK+fXe-dylcI;Hq!U4YbSQExaRjD!v_zB z_fPJxhdX(@pzEHoQvS7=8#l4l=-TQ zb$&0iPF`kQ94S}3YY&jO8gUPfr{l{RPRfm&ddpSU!-dGOl107t9P6Z*wZ5Y8JGDD`6%iuqJ-7T2sh!6PKk{}fj z@gdJ%Ah&k+G43hA#YTMhsa!PyNsG z%|$PEbcFfg@hj6+gBx|rx0m?$Xz(-sot^Xd3Hn+2m5A!)GPM&2qOo9dy(LdZf7 zVOg=VgW^y9=g&GPlPT7XS_F~83XeyK4u%)1Z-9Wo5fH^Q7D~Y--t(av+({A99GY-JN_5aKNEKDZTf`^ekWG~I{3g?al?@-Gv;guqS2m=j|D7( zkwbw6Mz(X|#ha9VumUS98paWI@nuquDIsmxs!y-G$c&Br(d7tx|FkzQ-}LxLZ!|m| z0efWkyzZyA3=JnY&7;Q{dT|5qzjr3HUC=ycg-?j>xKXU%>#lXzaSA99OmV6&PD@E( zPvp32471ScN>v}0!j)X6)Lpg@35Es*BuRfg0=A~ajZ$e4j?34RtFs|DuS&GcD5bvz zFY;SO{{l}_gi*^*NBlP@t4eohT;EK(k%T@b9-crPP67~EHDVX7{fRu_oC%egoQ?fO z^Cj}DnU%z~b$$>cT+I(`E-c{@by&R}>kj5YwB0B!PRAF&pzC@?7_vKqV=4;49?eZ}p({JG zXH9PE%9acMVA36?068KAy5y@U7Hkx}HufKu9N?MQMuDvcsRExctn4NN6ap&h97U4r z*bzeKW>iO|LO_v`!k7p7g+~r~*pP7_xM`?Wj88&_ zcT}*}LhYyk6C9)^;do+R17|6ZDP{;*hRRrJh8l3Z^iIM0Pfw&CYn8a4UlH4P?6G*E9+}$7LTEy35EFIMIvY zqp2Iw7y-y~FuleXAZa=}$H6UI znHh+$i=!#*L=X^8c=&!5hT8Z_nT41)!x|l5UU7TgIky!&M{nfgYwM4mk8O&Gv0&83 zRh{2r1rMVq+{Ktfwo!aL!+yG_Ckd!)4I`Wnen|@M+(D5Z^P9UbU(Uv7=sKWit}_TJ5<&++K4f4Y^nR`L8Q0A>1E{52Bf#F|Pq1CRrEoUWAoRhfICYU` zUH&AIU*&j>-D+Te?_4Ybg8Yg>VEU%__U&6_)*Mcbbv)(41^}SUWDYZJqDm}64Sa|Wc-3GSIfZ_dZ$D7(rQf`k)0+$iop9p^fi>XUQy;Jfdr z2fJ>T>s&z(hDHo(tmwiwi-Y)Z={SfBbn@O1q&&GMZ)o&cg#KE_cvFu<t0h(vp2BJ} z)lDIKtD1hbzyNS-p91Y|qK!B{ZG50(_{v+iNwhBRy!52S9Q9`kHfqMyEFR5$Ts8%h zu~y{_GH2>s;!zM{)dt_%N3l+Z4mQ#?@%i5v1EFhQLiSmMSOoDz29EGlzvO`2a4se# zB}QK%j$pp^1#NYVCh!d+Ad7WY4v?8_>vCq|(Hv0IfDmKk5f2GxuaDN=X}Di!qo}S# zEc!9QJ+c`uZ)CUXKx}u8`-d!GwS{&skH#0^__NEHk{0wlJrxG+&5=p#F`PxVp29hF zC(T3Kib=L4ja0B%sh`YxZ9QU&jV(TZ>UJqb3u5u(E&M5ZbrXEk4G&GO{u5|Z!~SNB zMu&@9U=E*{&f+4lLthADGZ}-Q!n)CU!ej@Q`wwhTv&r$~Y@;~X+)dinwwV%6aX?bRFhkoYgX7BXCi2OQ338+EBA)h}u-lq@F7IaYkuroK4G2D%&udL~U3Xyy941 z@?pnGB)&LQQuvOeRb-Bv#lw7XEcSYs>=)SIhnh}HjIoA>>-ds#VfymHYl{Y|*p0QjqG@U= zw<7o=2Kv&a4Q~sD5p_y@ReIUz_3*n4)s^x7^)GT%b{0o4(&Aw0ue|)j7`DsHB8eRB z!`i{6k)?$pSq*iZ-o?q)M%h6rY1l|K@^Cr+3?W1-bL6m!H1r<_uR&OG3g{<&BFCPLI>d}rY&fr_-Qbn;Xd#Q?tz)mtGqhLC0Mo=g43nf zVr}T}tQW1tB0EnsxT$miuQ;@ZpRekCcHx>W;Mu_^{IaVm`~31ec(%gGC~3n( z@|+t8MH``P*4oZ(iQ3RFRUW$^)r;vSEbgG4Kb4;*wVyb9bed! zj3@E$ZkMBTT-|Tt28 zLC=3gXq4)>iLI?z%^8iOMnLoEX6*9IL(Y;{lkePHt!0?M>< zrWP{bVl+e8d7K8P39py&O$urn?%oF-?g;kJHQhNJlO&bClBWyB1^tt0cTVamQY<)` z-eWd!IdGFm%Yxi@<#&lyPALG#%4vKH;N+50R8SMmI?+@|nP9wHS3brSaBEj$0;z|_ zb1uvVi}zO3VlKa}l=;~tL}t(nnM9uU83uaRHVHv18Ubo`^Qa09R?J&k;mB;2huHM) zLtWa*L~qXxAl53;=+!o+A##AwipgAovMr}oVO&J=ggC+Yx1RyENrm>)D|kaKnnMPh zUwQNJyF4q@X7Httgj;Bs9^w?mCK3Ns=xxr4y+S8K6veZRzr}8~MoK&U&Rg@Modtin z6c4Tr;vMS|>wi^iWjJ;Ci-PWWz-~Hael)D>_SARH6K*I@g<5HB9PNbu`PrBE(tMZEJ0&%zs*cz-G9Pv)om=w@+~?mk-f zy`Q<5huAu@I*HBr_2s}XsAUrIKxw%FPGyRuO7G3O3Kc3z`~b(^ztfHHY!`lF=J^5r zv93R1g({d!1>^S;HT+Pg*U9Jr_h+M7h{l>t!!F~wbrt;NLY{@X@=HLP`LHCkmmsQ} z)KN0b{9M`^MPC?eG(v)%!Zkq6%+9Eu^R4@ z(}$V?3rON@lkL5mLzJ*cuD~4HT2ZfPi=ayaaq_4(y(e@RMx|4nFoNs=c=k8A*kfON(NSaDW;H*z|;G^tz$}6nTtn0 zN;g$P-c!LyRyMPt-RzzB!#n*kbDhEg%$n|e z4c+1MGjHId;YDy&esbGT!r=Xc4A=y5lE7TlseNAt+a@iupUxrBX5Pz?-59GbKZDolc_!N)~|Kx*GQC9tPWBA@HUVKA-ohSPkIc| zDo50sB({fywbpz2C@;L5=cvbBbsF%l@CV+~tYM~Pj55uNAgruaFkGM5ulu~)XIyvT zYhX{6Q`BCa7yn-w~>Y9t( zwEUWDOzOqHTMO4*eAmT;y#wzVyyW0pCtdSYRShCE)anMgnVy*yCX(zc%(ugFk`d^4 z`RLg>CshreKgTGPti}d`14n+ z`qf{pvN*(|aM7GM5}n#ulRK(NUmzyvkTdr--5KHJN$4V2Q0D&Pdw*`FhL1u2La?gs TXIp!J_`@GSlAnJ*F$VrWaeM*~ diff --git a/metal3-chart/charts/baremetal-operator/.helmignore b/metal3-chart/charts/baremetal-operator/.helmignore new file mode 100644 index 0000000..1b9a9cc --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/Chart.yaml b/metal3-chart/charts/baremetal-operator/Chart.yaml new file mode 100644 index 0000000..1900441 --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 0.6.1 +description: A Helm chart for baremetal-operator, used by Metal3 +name: baremetal-operator +type: application +version: 0.5.0 diff --git a/metal3-chart/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml b/metal3-chart/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml new file mode 100644 index 0000000..6406700 --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/crds/customresource-baremetalhosts.yaml @@ -0,0 +1,1148 @@ +--- +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? + Hardware profiles are deprecated and should not be used. Use the + separate fields Architecture and RootDeviceHints instead. Set to + "empty" to prepare for the future version of the API without hardware + profiles. + type: string + image: + description: Image holds the details of the image to be provisioned. + 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 or sha512. The special value "auto" can be used + to detect the algorithm from the checksum. If missing, MD5 is + used. If in doubt, use "auto". + enum: + - md5 + - sha256 + - sha512 + - auto + type: string + format: + description: 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: + alternateNames: + description: A list of alternate Linux device names of the + disk, e.g. "/dev/sda". Note that this list is not exhaustive, + and names may not be stable across reboots. + items: + type: string + type: array + hctl: + description: The SCSI location of the device + type: string + model: + description: Hardware model + type: string + name: + description: A Linux device name of the disk, e.g. "/dev/disk/by-path/pci-0000:01:00.0-scsi-0:2:0:0". + This will be a name that is stable across reboots if one + is available. + type: string + rotational: + description: Whether this disk represents rotational storage. + This field is not recommended for usage, please prefer + using 'Type' field instead, this field will be deprecated + eventually. + type: boolean + serialNumber: + description: The serial number of the device + type: string + sizeBytes: + description: The size of the disk in Bytes + format: int64 + type: integer + type: + description: 'Device type, one of: HDD, SSD, NVME.' + enum: + - HDD + - SSD + - NVME + type: string + vendor: + description: The name of the vendor of the device + type: string + wwn: + description: The WWN of the device + type: string + wwnVendorExtension: + description: The WWN Vendor extension of the device + type: string + wwnWithExtension: + description: The WWN with the extension + type: string + type: object + type: array + systemVendor: + description: 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 or sha512. The special value "auto" + can be used to detect the algorithm from the checksum. If + missing, MD5 is used. If in doubt, use "auto". + enum: + - md5 + - sha256 + - sha512 + - auto + type: string + format: + description: 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/metal3-chart/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml b/metal3-chart/charts/baremetal-operator/crds/customresource-bmceventsubscriptions.yaml new file mode 100644 index 0000000..c0dc2bf --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/crds/customresource-dataimages.yaml b/metal3-chart/charts/baremetal-operator/crds/customresource-dataimages.yaml new file mode 100644 index 0000000..c1bb7b0 --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/crds/customresource-dataimages.yaml @@ -0,0 +1,75 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + name: dataimages.metal3.io +spec: + group: metal3.io + names: + kind: DataImage + listKind: DataImageList + plural: dataimages + singular: dataimage + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: DataImage is the Schema for the dataimages API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: DataImageSpec defines the desired state of DataImage. + properties: + url: + description: Url is the address of the dataImage that we want to attach + to a BareMetalHost + type: string + required: + - url + type: object + status: + description: DataImageStatus defines the observed state of DataImage. + properties: + attachedImage: + description: Currently attached DataImage + properties: + url: + type: string + required: + - url + type: object + error: + description: Error count and message when attaching/detaching + properties: + count: + type: integer + message: + type: string + required: + - count + - message + type: object + lastReconciled: + description: Time of last reconciliation + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/metal3-chart/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml b/metal3-chart/charts/baremetal-operator/crds/customresource-firmwareschemas.yaml new file mode 100644 index 0000000..3b3c4fe --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/crds/customresource-hardwaredata.yaml b/metal3-chart/charts/baremetal-operator/crds/customresource-hardwaredata.yaml new file mode 100644 index 0000000..7a39068 --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/crds/customresource-hardwaredata.yaml @@ -0,0 +1,211 @@ +--- +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: + alternateNames: + description: A list of alternate Linux device names of the + disk, e.g. "/dev/sda". Note that this list is not exhaustive, + and names may not be stable across reboots. + items: + type: string + type: array + hctl: + description: The SCSI location of the device + type: string + model: + description: Hardware model + type: string + name: + description: A Linux device name of the disk, e.g. "/dev/disk/by-path/pci-0000:01:00.0-scsi-0:2:0:0". + This will be a name that is stable across reboots if one + is available. + type: string + rotational: + description: Whether this disk represents rotational storage. + This field is not recommended for usage, please prefer + using 'Type' field instead, this field will be deprecated + eventually. + type: boolean + serialNumber: + description: The serial number of the device + type: string + sizeBytes: + description: The size of the disk in Bytes + format: int64 + type: integer + type: + description: 'Device type, one of: HDD, SSD, NVME.' + enum: + - HDD + - SSD + - NVME + type: string + vendor: + description: The name of the vendor of the device + type: string + wwn: + description: The WWN of the device + type: string + wwnVendorExtension: + description: The WWN Vendor extension of the device + type: string + wwnWithExtension: + description: The WWN with the extension + type: string + type: object + type: array + systemVendor: + description: 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/metal3-chart/charts/baremetal-operator/crds/customresource-hostfirmwarecomponents.yaml b/metal3-chart/charts/baremetal-operator/crds/customresource-hostfirmwarecomponents.yaml new file mode 100644 index 0000000..2962d52 --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/crds/customresource-hostfirmwarecomponents.yaml @@ -0,0 +1,178 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + name: hostfirmwarecomponents.metal3.io +spec: + group: metal3.io + names: + kind: HostFirmwareComponents + listKind: HostFirmwareComponentsList + plural: hostfirmwarecomponents + singular: hostfirmwarecomponents + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: HostFirmwareComponents is the Schema for the hostfirmwarecomponents + API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: HostFirmwareComponentsSpec defines the desired state of HostFirmwareComponents. + properties: + updates: + items: + description: FirmwareUpdate defines a firmware update specification. + properties: + component: + type: string + url: + type: string + required: + - component + - url + type: object + type: array + required: + - updates + type: object + status: + description: HostFirmwareComponentsStatus defines the observed state of + HostFirmwareComponents. + properties: + components: + description: Components is the list of all available firmware components + and their information. + items: + description: FirmwareComponentStatus defines the status of a firmware + component. + properties: + component: + type: string + currentVersion: + type: string + initialVersion: + type: string + lastVersionFlashed: + type: string + updatedAt: + format: date-time + type: string + required: + - component + - initialVersion + type: object + type: array + conditions: + description: Track whether updates stored in the spec are valid based + on the schema + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- 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 + updates: + description: Updates is the list of all firmware components that should + be updated they are specified via name and url fields. + items: + description: FirmwareUpdate defines a firmware update specification. + properties: + component: + type: string + url: + type: string + required: + - component + - url + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/metal3-chart/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml b/metal3-chart/charts/baremetal-operator/crds/customresource-hostfirmwaresettings.yaml new file mode 100644 index 0000000..62679cf --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml b/metal3-chart/charts/baremetal-operator/crds/customresource-preprovisioningimages.yaml new file mode 100644 index 0000000..f743a89 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/NOTES.txt b/metal3-chart/charts/baremetal-operator/templates/NOTES.txt new file mode 100644 index 0000000..a46dc2b --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/templates/NOTES.txt @@ -0,0 +1,16 @@ +1. Get the application URL by running these commands: +{{- if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "baremetal-operator.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "baremetal-operator.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "baremetal-operator.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "baremetal-operator.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/metal3-chart/charts/baremetal-operator/templates/_helpers.tpl b/metal3-chart/charts/baremetal-operator/templates/_helpers.tpl new file mode 100644 index 0000000..08dc581 --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "baremetal-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "baremetal-operator.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "baremetal-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "baremetal-operator.labels" -}} +helm.sh/chart: {{ include "baremetal-operator.chart" . }} +{{ include "baremetal-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "baremetal-operator.selectorLabels" -}} +app.kubernetes.io/component: baremetal-operator +app.kubernetes.io/name: {{ include "baremetal-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "baremetal-operator.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "baremetal-operator.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/metal3-chart/charts/baremetal-operator/templates/certificate.yaml b/metal3-chart/charts/baremetal-operator/templates/certificate.yaml new file mode 100644 index 0000000..ad0fd88 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/clusterrole-manager.yaml b/metal3-chart/charts/baremetal-operator/templates/clusterrole-manager.yaml new file mode 100644 index 0000000..e55cb06 --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/templates/clusterrole-manager.yaml @@ -0,0 +1,186 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: {{ include "baremetal-operator.fullname" . }}-manager-role + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - events + verbs: + - create + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - update + - watch +- apiGroups: + - metal3.io + resources: + - baremetalhosts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - baremetalhosts/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - bmceventsubscriptions + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - bmceventsubscriptions/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - firmwareschemas + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - firmwareschemas/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - hardware/finalizers + verbs: + - update +- apiGroups: + - metal3.io + resources: + - hardwaredata + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - hostfirmwaresettings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - hostfirmwaresettings/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - preprovisioningimages + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - preprovisioningimages/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - dataimages + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - dataimages/status + verbs: + - get + - patch + - update +- apiGroups: + - metal3.io + resources: + - hostfirmwarecomponents + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - metal3.io + resources: + - hostfirmwarecomponents/status + verbs: + - get + - patch + - update diff --git a/metal3-chart/charts/baremetal-operator/templates/clusterrole-metrics-reader.yaml b/metal3-chart/charts/baremetal-operator/templates/clusterrole-metrics-reader.yaml new file mode 100644 index 0000000..cad7903 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/clusterrole-proxy.yaml b/metal3-chart/charts/baremetal-operator/templates/clusterrole-proxy.yaml new file mode 100644 index 0000000..db6d71d --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/clusterrolebinding-manager.yaml b/metal3-chart/charts/baremetal-operator/templates/clusterrolebinding-manager.yaml new file mode 100644 index 0000000..bfce20a --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/clusterrolebinding-proxy.yaml b/metal3-chart/charts/baremetal-operator/templates/clusterrolebinding-proxy.yaml new file mode 100644 index 0000000..5207b62 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/configmap-ironic.yaml b/metal3-chart/charts/baremetal-operator/templates/configmap-ironic.yaml new file mode 100644 index 0000000..20d3b8c --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/templates/configmap-ironic.yaml @@ -0,0 +1,30 @@ + {{- $enableTLS := .Values.global.enable_tls }} + {{- $enableVMediaTLS := .Values.global.enable_vmedia_tls }} + {{- $protocol := ternary "https" "http" $enableTLS }} + {{- $ironicIP := .Values.global.ironicIP | default "" }} + {{- $ironicApiHost := print $ironicIP ":6385" }} + {{- $ironicInspectorHost := print $ironicIP ":5050" }} + {{- $ironicBootHost := print $ironicIP ":6180" }} + {{- $ironicCacheHost := print $ironicIP ":6180" }} + +apiVersion: v1 +data: + IRONIC_ENDPOINT: "{{ $protocol }}://{{ $ironicApiHost }}/v1/" + IRONIC_INSPECTOR_ENDPOINT: "{{ $protocol }}://{{ $ironicInspectorHost }}/v1/" + RESTART_CONTAINER_CERTIFICATE_UPDATED: "false" + # Switch VMedia to HTTP if enable_vmedia_tls is false + {{- if and $enableTLS $enableVMediaTLS }} + {{- $ironicBootHost = print $ironicIP ":" .Values.global.vmediaTLSPort }} + {{- $ironicCacheHost = print $ironicIP ":" .Values.global.vmediaTLSPort }} + {{- $protocol = "https" }} + {{- else }} + {{- $protocol = "http" }} + {{- end }} + CACHEURL: "{{ $protocol }}://{{ $ironicCacheHost }}/images" + DEPLOY_KERNEL_URL: "{{ $protocol }}://{{ $ironicBootHost }}/images/ironic-python-agent.kernel" + DEPLOY_RAMDISK_URL: "{{ $protocol }}://{{ $ironicBootHost }}/images/ironic-python-agent.initramfs" +kind: ConfigMap +metadata: + name: baremetal-operator-ironic + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} diff --git a/metal3-chart/charts/baremetal-operator/templates/configmap.yaml b/metal3-chart/charts/baremetal-operator/templates/configmap.yaml new file mode 100644 index 0000000..b22579a --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/deployment.yaml b/metal3-chart/charts/baremetal-operator/templates/deployment.yaml new file mode 100644 index 0000000..877c714 --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/templates/deployment.yaml @@ -0,0 +1,131 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + {{- include "baremetal-operator.labels" . | nindent 4 }} + control-plane: controller-manager + webhook: metal3-io-v1alpha1-baremetalhost + name: {{ include "baremetal-operator.fullname" . }}-controller-manager +spec: + minReadySeconds: 10 + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "baremetal-operator.selectorLabels" . | nindent 6 }} + control-plane: controller-manager + template: + metadata: + labels: + {{- include "baremetal-operator.selectorLabels" . | nindent 8 }} + 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.images.baremetalOperator.repository }}:{{ .Values.images.baremetalOperator.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.images.baremetalOperator.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + livenessProbe: + failureThreshold: 10 + httpGet: + path: /healthz + port: 9440 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 2 + name: manager + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + readinessProbe: + failureThreshold: 10 + httpGet: + path: /readyz + port: 9440 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 2 + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + {{- if .Values.global.enable_basicAuth }} + - name: ironic-basic-auth + mountPath: "/opt/metal3/auth/ironic/username" + subPath: username + readOnly: true + - name: ironic-basic-auth + mountPath: "/opt/metal3/auth/ironic/password" + subPath: password + readOnly: true + - name: ironic-inspector-basic-auth + mountPath: "/opt/metal3/auth/ironic-inspector/username" + subPath: username + readOnly: true + - name: ironic-inspector-basic-auth + mountPath: "/opt/metal3/auth/ironic-inspector/password" + subPath: password + readOnly: true + {{- end }} + {{- if .Values.global.enable_tls }} + - name: cacert + mountPath: "/opt/metal3/certs/ca" + readOnly: true + {{- end }} + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8085/ + - --logtostderr=true + - --v=10 + image: "{{ .Values.images.rbacProxy.repository }}:{{ .Values.images.rbacProxy.tag }}" + imagePullPolicy: {{ .Values.images.rbacProxy.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + serviceAccountName: {{ include "baremetal-operator.serviceAccountName" . }} + terminationGracePeriodSeconds: 10 + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: bmo-webhook-server-cert + {{- if .Values.global.enable_basicAuth }} + - name: ironic-basic-auth + secret: + secretName: ironic-basic-auth + - name: ironic-inspector-basic-auth + secret: + secretName: ironic-inspector-basic-auth + {{- end }} + {{- if .Values.global.enable_tls }} + - name: cacert + secret: + secretName: ironic-cacert + {{- end }} + {{- with .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/metal3-chart/charts/baremetal-operator/templates/issuer.yaml b/metal3-chart/charts/baremetal-operator/templates/issuer.yaml new file mode 100644 index 0000000..c9d1522 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/role.yaml b/metal3-chart/charts/baremetal-operator/templates/role.yaml new file mode 100644 index 0000000..d56496f --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/rolebinding.yaml b/metal3-chart/charts/baremetal-operator/templates/rolebinding.yaml new file mode 100644 index 0000000..5704c6a --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/service-controller-manager.yaml b/metal3-chart/charts/baremetal-operator/templates/service-controller-manager.yaml new file mode 100644 index 0000000..64f39a6 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/service-webhook.yaml b/metal3-chart/charts/baremetal-operator/templates/service-webhook.yaml new file mode 100644 index 0000000..67fea7f --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/serviceaccount.yaml b/metal3-chart/charts/baremetal-operator/templates/serviceaccount.yaml new file mode 100644 index 0000000..14376e8 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/tests/test-connection.yaml b/metal3-chart/charts/baremetal-operator/templates/tests/test-connection.yaml new file mode 100644 index 0000000..28715fe --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/templates/validatingwebhookconfiguration.yaml b/metal3-chart/charts/baremetal-operator/templates/validatingwebhookconfiguration.yaml new file mode 100644 index 0000000..1cefe78 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/baremetal-operator/values.yaml b/metal3-chart/charts/baremetal-operator/values.yaml new file mode 100644 index 0000000..cf7fad4 --- /dev/null +++ b/metal3-chart/charts/baremetal-operator/values.yaml @@ -0,0 +1,90 @@ +# Default values for baremetal-operator. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +global: + # specify comma serparate beginning and end of the range of IP + # addresses the DHCP server will manage. + dhcpRange: 192.168.20.20,192.168.20.80 + + # Network interface on which provisioning network can be accessed + provisioningInterface: ens4 + + # IP Address assigned to network interface on provisioning network + provisioningIP: 192.168.20.5 + + # If running in a multi-node kubernetes cluster, "pin" the baremtal container + # to the same host where the ironic and media containers + # arerunning. Uncomment the nodeSelector and update the hostname accordingly. + #nodeSelector: + #kubernetes.io/hostname: "my-hostname" + + # Comment this out when pinning the baremetal-operator container to a specfic host. + nodeSelector: {} + +replicaCount: 1 + +images: + baremetalOperator: + repository: registry.opensuse.org/isv/suse/edge/metal3/containers/images/baremetal-operator + pullPolicy: IfNotPresent + tag: "0.6.1" + rbacProxy: + repository: registry.opensuse.org/isv/suse/edge/metal3/containers/images/kube-rbac-proxy + pullPolicy: IfNotPresent + tag: "v0.14.2" + +imagePullSecrets: [] +nameOverride: "manger" +fullnameOverride: "baremetal-operator" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "baremetal-operator-controller-manager" + +podAnnotations: {} + +securityContext: + runAsUser: 11000 + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + +service: + type: ClusterIP + port: 80 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +tolerations: [] + +affinity: {} + +baremetaloperator: + httpPort: "6180" diff --git a/metal3-chart/charts/ironic/.helmignore b/metal3-chart/charts/ironic/.helmignore new file mode 100644 index 0000000..1b9a9cc --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/ironic/Chart.yaml b/metal3-chart/charts/ironic/Chart.yaml new file mode 100644 index 0000000..a9d39ec --- /dev/null +++ b/metal3-chart/charts/ironic/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 24.1.2 +description: A Helm chart for Ironic, used by Metal3 +name: ironic +type: application +version: 0.7.0 diff --git a/metal3-chart/charts/ironic/README.md b/metal3-chart/charts/ironic/README.md new file mode 100644 index 0000000..d88fccc --- /dev/null +++ b/metal3-chart/charts/ironic/README.md @@ -0,0 +1,24 @@ +## How to Enable Provisioning Network + +By default PXE boot functionality is disabled, so deployments via e.g redfish-virtualmedia may +be performed without any dedicated provisioning network. + +For PXE boot a dedicated network is required, in this case we run a dnsmasq instance to provide +DHCP and require a dedicated NIC for connectivity to the provisioning network on each host. + +To enable this mode you must provide the following additional configuration (note the values are +examples and will depend on your environment): + +``` +global: + enable_dnsmasq: true + enable_pxe_boot: true + dnsmasqDefaultRouter: 192.168.21.254 + dnsmasqDNSServer: 192.168.20.5 + dhcpRange: 192.168.20.20,192.168.20.80 + provisioningInterface: ens4 + provisioningIP: 192.168.20.5 +``` + +Note that these values *must not* conflict with your controlplane or other networks otherwise unexpected +behavior is likely - a dedicated physical network is required in this configuration. diff --git a/metal3-chart/charts/ironic/templates/NOTES.txt b/metal3-chart/charts/ironic/templates/NOTES.txt new file mode 100644 index 0000000..acc38ed --- /dev/null +++ b/metal3-chart/charts/ironic/templates/NOTES.txt @@ -0,0 +1,16 @@ +1. Get the application URL by running these commands: +{{- if eq .Values.service.type "NodePort" }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "ironic.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if eq .Values.service.type "LoadBalancer" }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "ironic.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "ironic.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:6385 +{{- else if eq .Values.service.type "ClusterIP" }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "ironic.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/metal3-chart/charts/ironic/templates/_helpers.tpl b/metal3-chart/charts/ironic/templates/_helpers.tpl new file mode 100644 index 0000000..eb97966 --- /dev/null +++ b/metal3-chart/charts/ironic/templates/_helpers.tpl @@ -0,0 +1,88 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "ironic.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "ironic.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "ironic.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "ironic.labels" -}} +helm.sh/chart: {{ include "ironic.chart" . }} +{{ include "ironic.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "ironic.selectorLabels" -}} +app.kubernetes.io/component: ironic +app.kubernetes.io/name: {{ include "ironic.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "ironic.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "ironic.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Shared directory volumeMount +*/}} +{{- define "ironic.sharedVolumeMount" -}} +- mountPath: /shared + name: ironic-data-volume +{{- end }} + +{{/* +Get ironic CA volumeMounts +*/}} +{{- define "ironic.CAVolumeMounts" -}} +- name: cert-ironic-ca + mountPath: "/certs/ca/ironic" + readOnly: true +- name: cert-ironic-inspector-ca + mountPath: "/certs/ca/ironic-inspector" + readOnly: true +{{- if .Values.global.enable_vmedia_tls }} +- name: cert-ironic-vmedia-ca + mountPath: "/certs/ca/vmedia" + readOnly: true +{{- end }} +{{- end }} diff --git a/metal3-chart/charts/ironic/templates/certificates.yaml b/metal3-chart/charts/ironic/templates/certificates.yaml new file mode 100644 index 0000000..f745c34 --- /dev/null +++ b/metal3-chart/charts/ironic/templates/certificates.yaml @@ -0,0 +1,56 @@ +{{- if .Values.global.enable_tls -}} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: ironic-cacert +spec: + commonName: ironic-ca + isCA: true + ipAddresses: + - {{ .Values.global.ironicIP }} + issuerRef: + kind: Issuer + name: selfsigned-issuer + secretName: ironic-cacert +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: ironic-cert +spec: + commonName: ironic-cert + ipAddresses: + - {{ .Values.global.ironicIP }} + issuerRef: + kind: Issuer + name: ca-issuer + secretName: ironic-cert +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: ironic-inspector-cert +spec: + commonName: ironic-inspector-cert + ipAddresses: + - {{ .Values.global.ironicIP }} + issuerRef: + kind: Issuer + name: ca-issuer + secretName: ironic-inspector-cert +{{- if .Values.global.enable_vmedia_tls }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: ironic-vmedia-cert +spec: + commonName: ironic-vmedia-cert + ipAddresses: + - {{ .Values.global.ironicIP }} + issuerRef: + kind: Issuer + name: ca-issuer + secretName: ironic-vmedia-cert +{{- end }} +{{- end }} diff --git a/metal3-chart/charts/ironic/templates/configmap-ipa-downloader.yaml b/metal3-chart/charts/ironic/templates/configmap-ipa-downloader.yaml new file mode 100644 index 0000000..3636717 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/ironic/templates/configmap.yaml b/metal3-chart/charts/ironic/templates/configmap.yaml new file mode 100644 index 0000000..3a66c9d --- /dev/null +++ b/metal3-chart/charts/ironic/templates/configmap.yaml @@ -0,0 +1,86 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ironic-bmo + labels: + {{- include "ironic.labels" . | nindent 4 }} +data: + {{- $enableTLS := .Values.global.enable_tls }} + {{- $enableVMediaTLS := .Values.global.enable_vmedia_tls }} + {{- $protocol := ternary "https" "http" $enableTLS }} + {{- $ironicIP := .Values.global.ironicIP | default "" }} + {{- $ironicApiHost := print $ironicIP ":6385" }} + {{- $ironicInspectorHost := print $ironicIP ":5050" }} + {{- $ironicBootHost := print $ironicIP ":6180" }} + {{- $ironicCacheHost := print $ironicIP ":6180" }} + + {{- 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" + PREDICTABLE_NIC_NAMES: "{{ .Values.global.predictableNicNames }}" + USE_IRONIC_INSPECTOR: "true" + IRONIC_API_BASE_URL: {{ $protocol }}://{{ $ironicApiHost }} + IRONIC_API_HOST: {{ $ironicApiHost }} + IRONIC_API_HTTPD_SERVER_NAME: {{ $ironicApiHost }} + 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 }} + # Switch VMedia to HTTP if enable_vmedia_tls is false + {{- if and $enableTLS $enableVMediaTLS }} + {{- $ironicBootHost = print $ironicIP ":" .Values.global.vmediaTLSPort }} + {{- $ironicCacheHost = print $ironicIP ":" .Values.global.vmediaTLSPort }} + {{- $protocol = "https" }} + {{- else }} + {{- $protocol = "http" }} + {{- end }} + IRONIC_EXTERNAL_HTTP_URL: {{ $protocol }}://{{ $ironicCacheHost }} + 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_BOOT_BASE_URL: {{ $protocol }}://{{ $ironicBootHost }} + 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_USE_MARIADB: "true" + LISTEN_ALL_INTERFACES: "true" + {{- if .Values.global.ironicIP }} + IRONIC_IP: {{ .Values.global.ironicIP }} + {{- end }} + {{- if ( .Values.global.enable_tls ) }} + RESTART_CONTAINER_CERTIFICATE_UPDATED: "true" + IRONIC_KERNEL_PARAMS: {{ .Values.global.ironicKernelParams }} tls.enabled=true + IPA_INSECURE: "0" + IRONIC_REVERSE_PROXY_SETUP: "true" + INSPECTOR_REVERSE_PROXY_SETUP: "true" + {{- if ( .Values.global.enable_vmedia_tls ) }} + VMEDIA_TLS_PORT: "{{ .Values.global.vmediaTLSPort }}" + {{- end }} + {{- else }} + RESTART_CONTAINER_CERTIFICATE_UPDATED: "false" + IRONIC_KERNEL_PARAMS: {{ .Values.global.ironicKernelParams }} + IPA_INSECURE: "1" + IRONIC_REVERSE_PROXY_SETUP: "false" + {{- end }} + {{- if ( .Values.global.enable_basicAuth ) }} + AUTH_STRATEGY: "http_basic" + INSPECTOR_AUTH_STRATEGY: "http_basic" + {{- end }} + MARIADB_HOST: {{ .Values.global.databaseServiceName }}.{{ .Release.Namespace }}.svc.cluster.local diff --git a/metal3-chart/charts/ironic/templates/deployment.yaml b/metal3-chart/charts/ironic/templates/deployment.yaml new file mode 100644 index 0000000..7f5e39d --- /dev/null +++ b/metal3-chart/charts/ironic/templates/deployment.yaml @@ -0,0 +1,367 @@ +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: + {{- if .Values.podSecurityContext }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- end }} + {{- if .Values.baremetaloperator.ironichostNetwork }} + hostNetwork: {{ .Values.baremetaloperator.ironichostNetwork }} + {{- end }} + containers: + - name: ironic-httpd + image: {{ .Values.images.ironic.repository }}:{{ .Values.images.ironic.tag }} + imagePullPolicy: {{ .Values.images.ironic.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + command: + - /bin/runhttpd + envFrom: + - configMapRef: + name: ironic-bmo + livenessProbe: + exec: + command: + - /bin/sh + - -c + - curl {{ if and .Values.global.enable_tls .Values.global.enable_vmedia_tls }}-sSfk https://127.0.0.1:{{ .Values.global.vmediaTLSPort }}/boot.ipxe {{ else }}-sSf http://127.0.0.1:6180/boot.ipxe{{ end }} + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + ports: + {{- if and .Values.global.enable_tls .Values.global.enable_vmedia_tls }} + - containerPort: {{ .Values.global.vmediaTLSPort }} + name: httpd-tls + protocol: TCP + {{- else }} + - containerPort: 6180 + name: httpd + protocol: TCP + {{- end }} + readinessProbe: + exec: + command: + - /bin/sh + - -c + - curl {{ if and .Values.global.enable_tls .Values.global.enable_vmedia_tls }}-sSfk https://127.0.0.1:{{ .Values.global.vmediaTLSPort }}/boot.ipxe {{ else }}-sSf http://127.0.0.1:6180/boot.ipxe{{ end }} + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + {{- if .Values.global.enable_tls }} + {{- include "ironic.CAVolumeMounts" . | nindent 10 }} + - name: cert-ironic + mountPath: "/certs/ironic" + readOnly: true + - name: cert-ironic-inspector + mountPath: "/certs/ironic-inspector" + readOnly: true + {{- if .Values.global.enable_vmedia_tls }} + - name: cert-ironic-vmedia + mountPath: "/certs/vmedia" + readOnly: true + {{- end }} + - mountPath: /shared/html/tstcerts + name: cert-ironic-ca + readOnly: true + {{- 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: + {{- if .Values.global.enable_basicAuth }} + - name: INSPECTOR_HTPASSWD + valueFrom: + secretKeyRef: + name: ironic-inspector-basic-auth + key: htpasswd + {{- end }} + - name: MARIADB_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: ironic-mariadb + livenessProbe: + exec: + command: + - /bin/sh + - -c + - curl -sSf http://127.0.0.1:{{ if .Values.global.enable_tls }}5049{{ else }}5050{{ end }} + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + ports: + - containerPort: 5050 + name: inspector + protocol: TCP + readinessProbe: + exec: + command: + - /bin/sh + - -c + - curl -sSf http://127.0.0.1:{{ if .Values.global.enable_tls }}5049{{ else }}5050{{ end }} + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + {{- if .Values.global.enable_basicAuth }} + - mountPath: "/auth/ironic/auth-config" + name: ironic-basic-auth + subPath: auth-config + readOnly: true + - mountPath: "/auth/ironic-inspector/auth-config" + name: ironic-inspector-basic-auth + subPath: auth-config + readOnly: true + {{- end }} + {{- if .Values.global.enable_tls }} + {{- include "ironic.CAVolumeMounts" . | nindent 10 }} + - name: cert-ironic-inspector + mountPath: "/certs/ironic-inspector" + readOnly: true + {{- 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: + {{- if .Values.global.enable_basicAuth }} + - name: IRONIC_HTPASSWD + valueFrom: + secretKeyRef: + name: ironic-basic-auth + key: htpasswd + {{- end }} + - name: MARIADB_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: ironic-mariadb + livenessProbe: + exec: + command: + - /bin/sh + - -c + - curl -sSf http://127.0.0.1:{{ if .Values.global.enable_tls }}6388{{ else }}6385{{ end }} + 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:{{ if .Values.global.enable_tls }}6388{{ else }}6385{{ end }} + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + volumeMounts: + {{- include "ironic.sharedVolumeMount" . | nindent 10 }} + {{- if .Values.global.enable_basicAuth }} + - mountPath: "/auth/ironic/auth-config" + name: ironic-basic-auth + subPath: auth-config + readOnly: true + - mountPath: "/auth/ironic-inspector/auth-config" + name: ironic-inspector-basic-auth + subPath: auth-config + readOnly: true + {{- end }} + {{- if .Values.global.enable_tls }} + {{- include "ironic.CAVolumeMounts" . | nindent 10 }} + - name: cert-ironic + mountPath: "/certs/ironic" + readOnly: true + - mountPath: /etc/pki/trust/anchors + name: trusted-certs + readOnly: true + lifecycle: + postStart: + exec: + command: + - update-ca-certificates + {{- end }} + {{- if .Values.global.enable_dnsmasq }} + - name: ironic-dnsmasq + 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 }} + 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 }} + - mountPath: /tmp/ironic-certificates + name: trusted-certs + {{- end }} + volumes: + - name: ironic-data-volume + persistentVolumeClaim: + claimName: ironic-shared-volume + {{- if .Values.global.enable_basicAuth }} + - name: ironic-basic-auth + secret: + secretName: ironic-basic-auth + - name: ironic-inspector-basic-auth + secret: + secretName: ironic-inspector-basic-auth + {{- if .Values.global.enable_tls }} + - name: trusted-certs + projected: + sources: + - secret: + name: ironic-cacert + {{- if .Values.global.additionalTrustedCAs }} + - secret: + name: tls-ca-additional + {{- end }} + - name: cert-ironic-ca + secret: + secretName: ironic-cacert + - name: cert-ironic + secret: + secretName: ironic-cert + - name: cert-ironic-inspector-ca + secret: + secretName: ironic-cacert + - name: cert-ironic-inspector + secret: + secretName: ironic-inspector-cert + {{- if .Values.global.enable_vmedia_tls }} + - name: cert-ironic-vmedia-ca + secret: + secretName: ironic-cacert + - name: cert-ironic-vmedia + secret: + secretName: ironic-vmedia-cert + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.global.dnsPolicy }} + dnsPolicy: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/metal3-chart/charts/ironic/templates/issuers.yaml b/metal3-chart/charts/ironic/templates/issuers.yaml new file mode 100644 index 0000000..b03cbcc --- /dev/null +++ b/metal3-chart/charts/ironic/templates/issuers.yaml @@ -0,0 +1,16 @@ +{{- if .Values.global.enable_tls -}} +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: selfsigned-issuer +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: ca-issuer +spec: + ca: + secretName: ironic-cacert +{{- end }} diff --git a/metal3-chart/charts/ironic/templates/pvc.yaml b/metal3-chart/charts/ironic/templates/pvc.yaml new file mode 100644 index 0000000..e50c856 --- /dev/null +++ b/metal3-chart/charts/ironic/templates/pvc.yaml @@ -0,0 +1,24 @@ +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 diff --git a/metal3-chart/charts/ironic/templates/secret-tls.yaml b/metal3-chart/charts/ironic/templates/secret-tls.yaml new file mode 100644 index 0000000..173d2fb --- /dev/null +++ b/metal3-chart/charts/ironic/templates/secret-tls.yaml @@ -0,0 +1,16 @@ +{{- if and (.Values.global.enable_tls) + (ne .Values.tlscerts.crt "") + (ne .Values.tlscerts.key "") + (ne .Values.tlscerts.cacert "") -}} +apiVersion: v1 +kind: Secret +metadata: + name: ironic-cacert + labels: + {{- include "ironic.labels" . | nindent 4 }} +type: Opaque +data: + tls.crt: {{ .Values.tlscerts.crt | toString | b64enc }} + tls.key: {{ .Values.tlscerts.key | toString | b64enc }} + ca.crt: {{ .Values.tlscerts.cacert | toString | b64enc }} +{{- end }} diff --git a/metal3-chart/charts/ironic/templates/secrets-basic-auth.yaml b/metal3-chart/charts/ironic/templates/secrets-basic-auth.yaml new file mode 100644 index 0000000..aa5736d --- /dev/null +++ b/metal3-chart/charts/ironic/templates/secrets-basic-auth.yaml @@ -0,0 +1,62 @@ +{{- if .Values.global.enable_basicAuth }} + +{{- $ironicUsername := "" -}} +{{- $ironicPassword := "" -}} +{{- $ironicSecretName := "ironic-basic-auth" -}} + +# Check if the secret is deployed and has a password +{{- $oldIronicSecret := lookup "v1" "Secret" .Release.Namespace $ironicSecretName }} +{{- if and $oldIronicSecret (index $oldIronicSecret.data "username") (index $oldIronicSecret.data "password") }} +{{- $ironicUsername = b64dec (index $oldIronicSecret.data "username" | toString) -}} +{{- $ironicPassword = b64dec (index $oldIronicSecret.data "password" | toString) -}} +# If not, check if a username and password are provided in values.yaml +{{- else if and (.Values.global.auth.ironicUsername) (.Values.global.auth.ironicPassword) }} +{{- $ironicUsername = .Values.global.auth.ironicUsername -}} +{{- $ironicPassword = .Values.global.auth.ironicPassword -}} +{{- else }} +# If no username and password are provided in values.yaml, generate new ones +{{- $ironicUsername = "ironic" -}} +{{- $ironicPassword = (randAlphaNum 20) -}} +{{- end }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ $ironicSecretName }} +type: Opaque +data: + username: {{ $ironicUsername | b64enc }} + password: {{ $ironicPassword | b64enc }} + htpasswd: {{ b64enc (htpasswd $ironicUsername $ironicPassword) }} + auth-config: | + {{- printf "[ironic]\nauth_type=http_basic\nusername: %s\npassword: %s" $ironicUsername $ironicPassword | b64enc | nindent 4 }} +--- +{{- $ironicInspectorUsername := "" -}} +{{- $ironicInspectorPassword := "" -}} +{{- $inspectorSecretName := "ironic-inspector-basic-auth" -}} + +# Check if the secret is deployed and has a password +{{- $oldInspectorSecret := lookup "v1" "Secret" .Release.Namespace $inspectorSecretName }} +{{- if and $oldInspectorSecret (index $oldInspectorSecret.data "username") (index $oldInspectorSecret.data "password") }} +{{- $ironicInspectorUsername = b64dec (index $oldInspectorSecret.data "username" | toString) -}} +{{- $ironicInspectorPassword = b64dec (index $oldInspectorSecret.data "password" | toString) -}} +# If not, check if a username and password are provided in values.yaml +{{- else if and (.Values.global.auth.ironicInspectorUsername) (.Values.global.auth.ironicInspectorPassword) }} +{{- $ironicInspectorUsername = .Values.global.auth.ironicInspectorUsername -}} +{{- $ironicInspectorPassword = .Values.global.auth.ironicInspectorPassword -}} +{{- else }} +# If no username and password are provided in values.yaml, generate new ones +{{- $ironicInspectorUsername = "ironic" -}} +{{- $ironicInspectorPassword = (randAlphaNum 20) -}} +{{- end }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ $inspectorSecretName }} +type: Opaque +data: + username: {{ $ironicInspectorUsername | b64enc }} + password: {{ $ironicInspectorPassword | b64enc }} + htpasswd: {{ b64enc (htpasswd $ironicInspectorUsername $ironicInspectorPassword) }} + auth-config: | + {{- printf "[inspector]\nauth_type=http_basic\nusername: %s\npassword: %s" $ironicInspectorUsername $ironicInspectorPassword | b64enc | nindent 4 }} +{{- end }} diff --git a/metal3-chart/charts/ironic/templates/service.yaml b/metal3-chart/charts/ironic/templates/service.yaml new file mode 100644 index 0000000..f3f0b51 --- /dev/null +++ b/metal3-chart/charts/ironic/templates/service.yaml @@ -0,0 +1,39 @@ +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 }} + ports: + {{- $enableTLS := .Values.global.enable_tls }} + {{- $enableVMediaTLS := .Values.global.enable_vmedia_tls }} + {{- range .Values.service.ports }} + {{- if and (eq .name "httpd") (or (not $enableTLS) (not $enableVMediaTLS)) }} + - name: {{ .name }} + port: {{ .port }} + protocol: {{ .protocol }} + targetPort: {{ .targetPort }} + {{- else if and (eq .name "httpd-tls") ($enableTLS) ($enableVMediaTLS) }} + - name: {{ .name }} + port: {{ .port }} + protocol: {{ .protocol }} + targetPort: {{ .targetPort }} + {{- else if and (ne .name "httpd") (ne .name "httpd-tls") }} + - name: {{ .name }} + port: {{ .port }} + protocol: {{ .protocol }} + targetPort: {{ .targetPort }} + {{- end }} + {{- end }} + selector: + {{- include "ironic.selectorLabels" . | nindent 4 }} + {{- if or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort") }} + externalIPs: + {{- toYaml .Values.service.externalIPs | nindent 4 }} + {{- end }} diff --git a/metal3-chart/charts/ironic/templates/serviceaccount.yaml b/metal3-chart/charts/ironic/templates/serviceaccount.yaml new file mode 100644 index 0000000..c94a90f --- /dev/null +++ b/metal3-chart/charts/ironic/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "ironic.serviceAccountName" . }} + labels: + {{- include "ironic.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/metal3-chart/charts/ironic/values.yaml b/metal3-chart/charts/ironic/values.yaml new file mode 100644 index 0000000..2ffb69a --- /dev/null +++ b/metal3-chart/charts/ironic/values.yaml @@ -0,0 +1,153 @@ +# Default values for ironic. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +global: + # whether to enable dnsmasq on the provisioning network (for PXE boot) + enable_dnsmasq: false + + # whether to enable PXE boot capability + # NOTE: enable_dnsmasq must set to 'true' in order for this option to be effective. + enable_pxe_boot: false + + # DNS Policy of the Ironic pod + dnsPolicy: "ClusterFirstWithHostNet" + + # IP address of the router associated with the specified DHCP + # address range + dnsmasqDefaultRouter: "" + + # IP address of the dns server to be provided with DHCP + # response + dnsmasqDNSServer: "" + + # specify comma-delimited xrange of IP addresses the DHCP server will manage. + # e.g 192.168.20.20,192.168.20.80 + dhcpRange: "" + + # Network interface on which provisioning network can be accessed + # Note this must be a dedicated NIC separate from the controlplane network + provisioningInterface: "" + + # IP Address assigned to network interface on provisioning network + provisioningIP: "" + + # Whether the NIC names should be predictable or not + predictableNicNames: "true" + + # The kernel params for Ironic + ironicKernelParams: "console=ttyS0" + + databaseServiceName: "metal3-mariadb" + + # In a multi-node kubernetes cluster, we need to "pin" the + # ironic containers to the given host where the + # provisioningIP exists. Uncomment the nodeSelector + # here and update the hostname accordingly. + #nodeSelector: + #kubernetes.io/hostname: "csrancher-n1" + + # Comment this out when pinning the pdns containers to a specfic host. + nodeSelector: {} + +replicaCount: 1 + +images: + ironic: + repository: registry.opensuse.org/isv/suse/edge/metal3/containers/images/ironic + pullPolicy: IfNotPresent + tag: 24.1.2.0 + ironicIPADownloader: + repository: registry.opensuse.org/isv/suse/edge/metal3/containers/images/ironic-ipa-downloader + pullPolicy: IfNotPresent + tag: 2.0.0 + +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: LoadBalancer + annotations: {} + externalIPs: [] + ports: + - name: httpd + port: 6180 + protocol: TCP + targetPort: 6180 + - name: httpd-tls + port: 6185 + protocol: TCP + targetPort: 6185 + - name: inspector + port: 5050 + protocol: TCP + targetPort: 5050 + - name: api + port: 6385 + protocol: TCP + targetPort: 6385 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +tolerations: [] + +affinity: {} + +baremetaloperator: + cloudflareApiToken: "foo" + ironichostNetwork: true + +debug: + ironicRamdiskSshKey: "" + +tlscerts: + cacert: "" + key: "" + crt: "" + +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/metal3-chart/charts/mariadb/.helmignore b/metal3-chart/charts/mariadb/.helmignore new file mode 100644 index 0000000..f0907ec --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/mariadb/Chart.yaml b/metal3-chart/charts/mariadb/Chart.yaml new file mode 100644 index 0000000..df93690 --- /dev/null +++ b/metal3-chart/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.5.4 diff --git a/metal3-chart/charts/mariadb/templates/_helpers.tpl b/metal3-chart/charts/mariadb/templates/_helpers.tpl new file mode 100644 index 0000000..d3d47e4 --- /dev/null +++ b/metal3-chart/charts/mariadb/templates/_helpers.tpl @@ -0,0 +1,64 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "mariadb.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "mariadb.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "mariadb.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "mariadb.labels" -}} +helm.sh/chart: {{ include "mariadb.chart" . }} +{{ include "mariadb.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "mariadb.selectorLabels" -}} +app.kubernetes.io/component: mariadb +app.kubernetes.io/name: {{ include "mariadb.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "mariadb.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "mariadb.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + diff --git a/metal3-chart/charts/mariadb/templates/configmap.yaml b/metal3-chart/charts/mariadb/templates/configmap.yaml new file mode 100644 index 0000000..59a2cc1 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/mariadb/templates/deployment.yaml b/metal3-chart/charts/mariadb/templates/deployment.yaml new file mode 100644 index 0000000..070c2fb --- /dev/null +++ b/metal3-chart/charts/mariadb/templates/deployment.yaml @@ -0,0 +1,85 @@ +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 + lifecycle: + preStop: + exec: + command: + - sh + - -c + - mysqladmin shutdown -uironic -p$(printenv MARIADB_PASSWORD) + 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/metal3-chart/charts/mariadb/templates/pvc.yaml b/metal3-chart/charts/mariadb/templates/pvc.yaml new file mode 100644 index 0000000..fa0a176 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/mariadb/templates/secret.yaml b/metal3-chart/charts/mariadb/templates/secret.yaml new file mode 100644 index 0000000..d4b2318 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/mariadb/templates/service-account.yaml b/metal3-chart/charts/mariadb/templates/service-account.yaml new file mode 100644 index 0000000..5101f01 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/mariadb/templates/service.yaml b/metal3-chart/charts/mariadb/templates/service.yaml new file mode 100644 index 0000000..5d0d75d --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/mariadb/values.yaml b/metal3-chart/charts/mariadb/values.yaml new file mode 100644 index 0000000..7d2fbce --- /dev/null +++ b/metal3-chart/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/suse/edge/metal3/containers/images/suse/mariadb + pullPolicy: IfNotPresent + tag: 10.6.15.1 + +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/metal3-chart/charts/media/.helmignore b/metal3-chart/charts/media/.helmignore new file mode 100644 index 0000000..1b9a9cc --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/media/Chart.yaml b/metal3-chart/charts/media/Chart.yaml new file mode 100644 index 0000000..544c704 --- /dev/null +++ b/metal3-chart/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.5.0 diff --git a/metal3-chart/charts/media/templates/NOTES.txt b/metal3-chart/charts/media/templates/NOTES.txt new file mode 100644 index 0000000..c6350f5 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/media/templates/_helpers.tpl b/metal3-chart/charts/media/templates/_helpers.tpl new file mode 100644 index 0000000..37c5e87 --- /dev/null +++ b/metal3-chart/charts/media/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "media.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "media.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "media.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "media.labels" -}} +helm.sh/chart: {{ include "media.chart" . }} +{{ include "media.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "media.selectorLabels" -}} +app.kubernetes.io/component: media +app.kubernetes.io/name: {{ include "media.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "media.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "media.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/metal3-chart/charts/media/templates/deployment.yaml b/metal3-chart/charts/media/templates/deployment.yaml new file mode 100644 index 0000000..9dccd57 --- /dev/null +++ b/metal3-chart/charts/media/templates/deployment.yaml @@ -0,0 +1,66 @@ +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 }} + command: + - /usr/sbin/httpd + args: + - -DFOREGROUND + 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/metal3-chart/charts/media/templates/hpa.yaml b/metal3-chart/charts/media/templates/hpa.yaml new file mode 100644 index 0000000..0bd8a10 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/media/templates/ingress.yaml b/metal3-chart/charts/media/templates/ingress.yaml new file mode 100644 index 0000000..576ecb9 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/media/templates/persistentvolume.yaml b/metal3-chart/charts/media/templates/persistentvolume.yaml new file mode 100644 index 0000000..8ebf28c --- /dev/null +++ b/metal3-chart/charts/media/templates/persistentvolume.yaml @@ -0,0 +1,18 @@ +{{- if eq .Values.mediaVolume.storageClassName "local" }} +--- +kind: PersistentVolume +apiVersion: v1 +metadata: + name: media + labels: + {{- include "media.labels" . | nindent 4 }} +spec: + storageClassName: {{ .Values.mediaVolume.storageClassName }} + accessModes: + {{ toYaml .Values.mediaVolume.accessModes }} + capacity: + storage: {{ .Values.mediaVolume.storage }} + hostPath: + path: {{ .Values.mediaVolume.hostPath }} + type: DirectoryOrCreate +{{- end }} diff --git a/metal3-chart/charts/media/templates/persistentvolumeclaim.yaml b/metal3-chart/charts/media/templates/persistentvolumeclaim.yaml new file mode 100644 index 0000000..7cb52f8 --- /dev/null +++ b/metal3-chart/charts/media/templates/persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: media + labels: + {{- include "media.labels" . | nindent 4 }} +spec: + storageClassName: {{ .Values.mediaVolume.storageClassName }} + accessModes: + {{ toYaml .Values.mediaVolume.accessModes }} + resources: + requests: + storage: {{ .Values.mediaVolume.storage }} diff --git a/metal3-chart/charts/media/templates/service.yaml b/metal3-chart/charts/media/templates/service.yaml new file mode 100644 index 0000000..93598e5 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/media/templates/serviceaccount.yaml b/metal3-chart/charts/media/templates/serviceaccount.yaml new file mode 100644 index 0000000..3badde4 --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/media/templates/storageclass.yaml b/metal3-chart/charts/media/templates/storageclass.yaml new file mode 100644 index 0000000..6c491aa --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/media/templates/tests/test-connection.yaml b/metal3-chart/charts/media/templates/tests/test-connection.yaml new file mode 100644 index 0000000..f96c62c --- /dev/null +++ b/metal3-chart/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/metal3-chart/charts/media/values.yaml b/metal3-chart/charts/media/values.yaml new file mode 100644 index 0000000..9f46ebe --- /dev/null +++ b/metal3-chart/charts/media/values.yaml @@ -0,0 +1,117 @@ +# Default values for media. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +global: + # Global ingress annotations that is shared by all the ingress services. + # For example, use it to override extern-dns records. + ingress: + annotations: {} + # The IP to register with external-dns for this service + #external-dns.alpha.kubernetes.io/target: 192.168.20.5 + + # If running in a multi-node kubernetes cluster, "pin" the media container + # to the given host where the /opt/media volume exists. Uncomment the + # nodeSelector and update the hostname accordingly. + #nodeSelector: + #kubernetes.io/hostname: "my-hostname" + + # Comment this out when pinning the media container to a specfic host. + nodeSelector: {} + +replicaCount: 1 + +image: + repository: registry.opensuse.org/isv/suse/edge/metal3/containers/images/ironic + pullPolicy: IfNotPresent + tag: 24.1.2.0 + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: + runAsUser: 10475 + fsGroup: 10475 + +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: media.suse.baremetal + paths: + - path: / + pathType: Prefix + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +tolerations: [] + +affinity: {} + +# volumes +volumes: + - name: assets + persistentVolumeClaim: + claimName: media + +# volume mounts +volumeMounts: + - mountPath: /srv/www/htdocs + name: assets + +# media volume settings +mediaVolume: + storageClassName: local + accessModes: + - ReadOnlyMany + hostPath: /opt/media + storage: 5Gi diff --git a/metal3-chart/templates/NOTES.txt b/metal3-chart/templates/NOTES.txt new file mode 100644 index 0000000..acbebf0 --- /dev/null +++ b/metal3-chart/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/metal3-chart/templates.obscpio b/metal3-chart/templates/_helpers.tpl similarity index 69% rename from metal3-chart/templates.obscpio rename to metal3-chart/templates/_helpers.tpl index a34873e1449e7225f5dc6c7c9de950e43c0a2147a3245fa59b943cc39e5cd868..67024ddf677cb808435db5143bb97fc37e505b9643cc02d4e398560182db87f3 100644 GIT binary patch delta 9 QcmZn=dBeN8h4Bp=025mSxBvhE delta 803 zcmc&xK~BRk5X=drNSxpSn-8QmqDjTA&>kuwKy5CZkQ;AEB-gfL2k0q0iHG$OI7t(6 zfWob7$zzW_TF-cQ_Hj{@*bPc3<77QaiK_`^R}B)HMJ*EA?Hv)-`qdvC^VKPJhfW50KCuLN&gi?YzG&=M14@x9IpEt a$#S~5n=gYPX!^UVJ2={W?EdFJIR65fnT8+$ diff --git a/metallb-chart/charts.obscpio b/metallb-chart/charts.obscpio deleted file mode 100644 index abb1383f99ee8639d46f2cfa69228fefbbb887f5d9a9f27c4092133c548adc90..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141824 zcmeFa?Rp!zu`W7)kFKI4XRXZ4GAUBBJY((U?4xhXBhfOyWGT;Vr%AR%S|ppp56N;S z=h+u>&du#BIqzElx`Adl*^=$aB$1La$!?%fC=?2XLRF#kL+OW7xm5PsFWQ&w68@f* zgAPAS<;&;tSt>tMpQRt4Kksb*7_7JSZ}U;s<@Bd{9DQDzZ|$x>o=(;-$K%5FkCSik zht^H|ozk-QpFgbq2>+69e-KRle!o>{k2^%d!l8XBeP2L>XI}^hO@p<096F^9(rW<@ zFCK`)i}Z0=n+AhX-=78`hD8g-1*IR$z8e2|ekeP5l-CXXCHzqKGw|3Ydlc{dLH`?n z)N2OgNiQ63c{l4T{%92cEEP+|^0SprFlmo_qp6hH_S*e$*71h^w09GDw`0@@#$I^o z9aO6;-Ea_WdEM!BG}&5P)5Bk!4N-JF35wIpm0p`IEhw?p8~9hjWUU`wg$6?5w%eNq z#nJF;<$Bf%A`JiZ=a*i&Sbk9~6-s|v8TxEokN3(XoQ>PTWNW1mwRY8;c4w_(I~*9m zW`?Xx??$MLzVv%-^eh~%5M$}FP+@b$<=+nGGXC<8S-BjTIlFAk%-EVaWcatbzrA;| zUmSG4`Q}N~$(29+B_f6zt)IU&wCxS9ij!_H=yxW?UbxosJ6FM)E?rQC3%%iGI37rc z{r>-)Oz--^%S&)*Ve-q&9|zxgfA~v1Ntq=ruzbNHWS%y*=ecf4D{+m&P0qfotSsi; zmG8fQ1@;|*`?kLS-urJu#}qF9^UBJTCtgiB%-an+!ODtNA)C!qy=w5wtTzq@!EicR zS@{VJJst)S3R~V^Eq?y%%F3@^H5i4H-ZUKFdB1uU@Ham65PH9^{93U7^pE%%-g_uc zxrYx$Bvc~iO}{@2(Dtw1PXQrw%7*ARK7)1K5A#a0ju>wfz7e4Vlebu{h$LV ztuXB4sr*Po4p(-0Gns7$8g-tdaGR{3f*s)u=irL5>* zUiOB)DT{`!4?&yQ{`GHvpDWhC_3tJ-{jh!Q0-Xcc=}n05ZZMu!!>Qne8V2=Czdwm_ z*Ery#C{n68n)UlBs1JMnBtmhWu|1|%cQNDcI8jkDoJ~Olew#x#hBNg^CJVreV!2pK ztpFAt_u7-4-mtUX>5PL3Il`)0UjG529>RW6?bC2fV)uqZ@*g&T*huRmfGfd^qKgKI z{g?!84E>2h&ISLX{H&Y;UY9NAZKWId{b|<){UfAy67+pXQ8H(4Me1VHwU&C+J{^axVA+HO5Kb(&&ZU}`^)4vg4f~wUdf?|q z-L1&U+4K8*LEpct1z7Aw`sljlQj+j)WoQz;uygNflUW-p{Uin1xq)`uoAw3)=GuIN zb7+QF$H7fNX=Y6uuAV~s-EcS^hy6YjA*d~0pGAw_$!s$9T7ef1@!ut+J9Oc{KK1_E z30ku&eqnun-umMqKLgDC@n5}g?EQ6!NhL9lW z`H4T7LX^aVlh%J-7+Vxh@qQ1o2Aa@ceog|Nji6`+wJ8B#-4(gfap_cr;DWZ%kaE_1 zhiXHjzQIOl-0LJN#pUvp8I7S>PrJcvQpD$dRgwAH?t%_gWIgKjeBt_WO)#r$ zq>p#0-PK(HLP;fL6}zhPx~)!H_+W3~j{;klu=8OpD!v8^1^xskFJ14uIa|~EeQZtZ8>K+o{g&98 z)&(xhy7uBVupaCK#Ywvx4E*AUNjUuGZ!4a+`bYI-b<0~d))Bre=z`(+YOOQ&FQiQpz;0beFho zv>r8XzD4+~j+GUugRcA~Dz<9+r=R>RpSlw1*doOhS+j9x!8B|m=rIVV0}H8_)SfIn z93Yf^SHU+?Gng( zG1qVFU7|awJP70a2z%S%KW-N5t$Y@>^(>6L1-1)@vjNJ-^GrAv+j$XM{Gt9)gw#3YCJ`xrp<7^2QwL?a{{8g z&6ZXUN~)}Xl?K8e-o3e;qbF+^$;9vGFOu=|@=+DB2x00hgfqm>#wMwTqS@7ehzZRn zi8fYa!|xaDUkylT-AiF$*5O||Bdd3KyDdiZ1P4ZMk1i|W^b}?TPTqN(1bzjU zFH3Zrx;ERIXJ$n+zZ3MfMk6k1jl!zC|4)oU#54EheWf`jph?#Z-_I>_d}|>lg+;q| zS4js*8Y?GZSmu*O_~;&5^a488ulT#w0Oq(h(ewI(NfB;NWY1OKEiq$~b zhivA;N*1wX5u_x? z+JYb=E1;xq9Sn3$KZtCL#u*zKv1jNCYPRWS1W{u-wAdj@R#QZ8sik|S+07BahSaw@Aanf>x?K+q)i)yI`%D!Bl_^>^x5-MmlSpS5p_E zBb$|0%jfxRO&PYe zl{sELr1J*1`x4EVeio>mb0R_d7|$hX-&l|n{c>dKbCL!G5#9H|2#|ed+_UMR~ zH#IU@i=2MDK&oM>au0Z&F3*j7>Rg>0Y5;W)cozdrktul)XBpFRmwt0-r%47?$c((H zlF}EnlA)WLN(u{WY}E^Qrlvq%U9w|SU`!uZ(|Zx|Y=jMT2Y6FZ5nW98yznp=(g7vd zwB8NqZ|%kG2KOuvC+yjbOPr(reGVU_*%}Q&(8Q8?$z7zjJStD`c}rZ%@CowSik{WH z5u2GyMHcjBYT%b>BeJ?|rH-=n(sUqQ?z703nMg)mc)(nOkRA9#o;=M9gNViQvOLx* z@qAhg?Q#}?Z$SDU9% zE7%ZsY~u{1OhO*+R`)XZA=zZk+JFPTnH@y&qkAQ#Vo#3ubVXm!KzIukuTPi+-R`k!**h37|Ca9{`$IuV`| z7gv&-QFJAi8D;gU=`gPXrYL~6s9Cni#F$u=b^s*!2Wu&Opb^TEs`X`a5PBZ3XY&IF z+KSiR+#A$O$a$Cki{aWL%kCAQ^Dly(E`#S+5Q|D0!a_An!FOhI@`NV=aW#9%Scq&A zjArH&I72U@X z?ggBLo@-8*?!-HS|L(Q%&FrUP${CWs=4LS(`#h~haWJ< z&%|pT6E^rb-SSWf3LJNTr{nMv-C~oT$4R#3Rh1jF4sQa0$eO7TQ+7zS9XrjZA_*(F z2k_d)M+Y#tvP#!{IEfY7i~wlU^y`2^?||{72&+#Zg^lZ!;9WLj*qGRt*Mg5e!b#yb7FQ`)PJVZTzBI?v3LmTE7^aG)MxG7mZ&qa0mKQ}+DOe-MP3hUFz|dJc7$Pnt9T+Xy zTOPfd6@cC)czgQPQ##4SG>X9DW%s*C)_O$ zkya(u4(o9KGMJa&)#g@0)i6*H+H}{uWb`e#OQa9a+K9A<7Wr|Du#r|{#`ij5Fr55p>UDiYB@=tF*Pu6H z2rt2zDULymjN}t<5<)%lt{BMN19E9K&^Y8$>rWGg@t{%H&hIddqM3w1c)p5(AjfpP z)*Xinkmvy~h@0h=B5>%fdPU_IS&WMn-G;oEFGc#HEJft11rT9$(x&lQ)~f4E3QLcg zkbABWQ;+yY#2_Y|f)SovFgn4gAKvK!`b}|;@N&@=+k?d(GJ)6+k$adIz#r3s);k|j zO5=FIKHjMnAwF6F$j~hatk`o#O|{dQ%tmx34+Ye8wMSNU;E9$4-efjXq6Gpe1)gA` zdBI{+k7CX7ipLg5X+clCP=fs7cOI8CyiR`Xc}yYB6qJA4PqwP zr?hUh;Ug{ZpHMO(aMTC}kE)CADXE5K-#Csdl6h1wq)O~RZj=cYf8xCkTb`KA1s5$W z5I1!dOa-7h6Tv8FxYBc638^Nr5mcGPgFljdBEd;JYpCE{A@SC_JyVA>&&WQat{`oh z7XB|K4?S(<*R&Ls4Y=Wio8nGs23YwpWDsscWK^JHqR68FSSJ^7ZBz>I6R!Z##gbdz zbr6hnry%y=llyVY`xDv!{kI)Iz%eko^sAB()JcBDQt)duZGWYY(67+xrU4dol>Dyv zUw?|ADc_@G3Ccj*@87fD`}aRbU3_@obWQXa@$^=&=9=WZejlq#?}7e%A}zQWYEXEN ze9=?3y#Ep5uc`6BzAb+L-5;Z;ieKIfA8mPr#coBfA$j_UEF!J8yg!zs=Z4<;Jp%OY z`K3i!a>{7^w9UaLS78I|9$NrPG)l!4EZ5izC~db;u=crMG+q^5Lino$%5H(@E<-$U zk396O16R{w^~*?Pt%@WhF*BDek;Is;PrUz|!;6rPXy;#a&r?*u-2AanOkKtt$}V4a z8|X5i!hb4GauPEc18*21vNrW6*ON6EQ9*@*8mBeYuKrcPlvxv4_{YUaF9Q%Yy4^Z9 zIVdF!?<#c{waFPyXdmN>-wY9$ja(DDxP0h6k{tzz=Lw}jRq$$adpF;#TRQ5~L%8@1 z@#4_A)vk@&U1A3(xMEl8s+;;y+`s|)T#%{lQ*&gGsQKtkq-gh)x72c|PI9VIaK@oJ zDlCVS!)#2W?W>@~8lqhgo%uBjqlgV7L!CugMY~hgNXjAzTur+uJO~Dew33L-VAvkt z$)d_N3n0)k0PoyEwbHUbIzhr(`8V-qp}tu(IIntt|9c^ZDE0Y|hF4)H@H?_`TPtqA zH|R}e(kp_uM>A|rN~HnHt0#bq)FSfmq=%=rW2XjW`D$u;I_E&CiD>*8bwzYj#jA6l z-)nb0eFBI4L9i;QjS!fG3mp|?juS*M7pUY>oraIM+wl%vw<5w;_YtdKoc_o2;@l5g z9&p}VZ z!p#n5z6WNhq}c=oz#2%!!$Tx+u`I9P0huq@dA56QiCruzjRUiB^9IQ0(}R)7BhSGIIK;L=l4WRRP~(}N9>D4=4H&XW zVq29%7coVHG40x@tJua`^(nGUm2g54Jp@7$pGaWvtp%oWu!i#GJxO4mDIxHC4ZpHG#UWl=hydU3_j1al)ZK=`s6B z{!GM(wl5{-Gp`N$`9>7_xg{xuaEIYij0sD%kRrl=8{t0GT3+qYyJFtyq>gS$=H%iVd4i$8mT~CzU3b+A={@%&5fD_|C+~;g|S2Y7PlKt*C=&-4?~K~2`UvJB|yvt zYTrrt5NKE|8JHV`#!$wbq48kZM5DhJoOhl_JXPnYPKl~UnW{Ssv8lSI1iQ#ZZGTi* zzJMsSWp(%-Bd8jtG78W}n?+~v6AK428eI*0pCZ_@?PjBr))CT|yLBWS;N%s>bg1-S z1(pBOl0FV3bJ=WY!Ba;!Njy%}_Wd%9w-d0coB6^u6v-8*cWXcphY>9tLyRYD9p)ce zgKf3okK4?g*q*{%vIZjKi~=1&QWs9TLFY*%m>kNg9f3MTvt9^STfdhL57}HXh61H% zLb;D-iG(b2fmhwH)$vsA(ABc11|=>k#_O1do@_ceKBOjgnmk0}aw*~Y9FAbv8HE@O zwaE5+Xbvl1iwZHI{(|Use3^zxa%20%%?9;SNrxi(sNL?-(A$N|-QV@GH*sj;d0%;~ zI4Y9@2Z1V2{FgCWwxmoJR^+vy81WVtTsYmS_c&7yrIFDP6OINSEdh4Z1pu2!7Xp0K zx*FMXfsYbwwsUw&rV{1JZUMu}IoP4D$d@dKcBUbY<&q<{2m?0Qy6l{)V?;+v@s;{> zsIzmhXG$B)j4}&AM1lvBA}RES$D+J}$WKw>FhfOdn%OZ7dRN^RruBR$SVyAb=1Im^ z3Bt{ZPgREh#yv0{Fjy!_nI!GOUPM}G&y%p-Bjq!CMH>(n2aX4lTyQB$@5!=3QRsGH zy=YHQlv>*hv|<@|#s21u(t_@@j^S3Vm#b!gtI?p*6#K#FI9HORAiF8|J2D7e!(7l0 zCph-4gBg+SGvv9}*dI>JsgyD7Mq6R6t0Ocilag#kHp`d+vS2tknMpC!r_gL)Fjj}s z+yacVXiv!4Tp<@MO?T6c^#wQ#{ExlCY_R36Z*n`A^#?NPVhai>=|x%~=|g6@pxq6R zB13pqgZUYr5E3IU*ka*kQy8yyz*9kcz%r2|uxK!+U7Rw@S~R)CDer(2s_l>HRYAGf zg$+x^4T7_9q};<6f;kcw4U1>oJ4A$RmIki;XY=vjy~j{;k1yz3G>Y2P5jSOj%Rh|t z-N}+ygm|AxD|=R$VO&GKTipA!@BNw_e-$d&)_M#W-Rbnpmc^r4B|$s54@U zR0nTZYK(YTKt9-^!V&byU^*Ku9A!m8?JSrHP>)7^+W%5CJOJ@T@(@uYp?TWfhhfkx z1L{a!H=cO=7H!gs3A0FoNKzM4G0=)$^(&_|-J2VDZjBqqRY=fw<--J+Z5PnSK(gF;ykyB0_ zW&~v+Uqo%y^Esv8og{P!gIxTQbNIv`UmLblrZ{N=$=K0J`5L_y9~{iUh5h!YbW)S! z4>7?d7e&ru0d(ubS_U3VaO7gD$_8T;UY;3?habpaw0FA(xR^D>SL6g2@;yrRTJm86UQ|;X;PNLMeG~nebaKZ+gXJT`_#(eu0 zj&AgY^P1Iz@6v@?{!OPsjj~bMd?3}$hE^Tl;1EV1^#HvTDk!WJ+T7Qm2kAKF+dle} zVb)l(C1>H@u2l?4w`(3!fZ+40BdKLrnFl*WxAHUzWZ1TzIzr z;@OMmKdisVwG&fEaxQY_S3cFJ*U3%4qdh}D?)?=vdPjSigA7A~xN9%bL3&6a2jwR} z8mhd(#mo)`209hkJUVY&fSZhs+S%!@ta&%%%PeLjRToYZMRtebjs(+qvZ&1rPRS-c zZXX?t7hY&geEV?JgS1`?8!t*k(Fq ztBc-f`MeNePoj}?Nohq|7)4W#fz&(qUwYv~xw$9PZR=}J^pbdVD&G85l5E;8=@Sv5 zkk@j1De)EJxrCT1x@0v{g&Yx)drivGH7a`fS0;r_-t|e9jtqslRw-S_SPd7gRjR0> zG?m~*wnJ4mHtFA!la|XBeV-Soo zCm7(j;SdoLuqe=(ZZ=vZM^q#CU}b2PRL|FQ&g?sx6dOE!gumWnBwB~E;0L4I#84@e2UzAp!_t6T}D#U&sIiy?x?kkfC zoo7wAgjD9B8iQ+kUB)n@=ZVuoMXdRM!As9KH#Zh(k){&E^0vH=j>r0zfjr+8;VEBJ z&3*fw$7{^I|NPHIWpYs8^Zxr~PNbGl1!Q162sR(LxXcLlHqqsCp#TAypNv_QIk7DL zAkTl$3$uifo?I9#lY`n;eR7&--igy`?AK+6H2u?AdFnI`z`?=M;B?#G$*D{`8W(c( zNz8A?^Upgvy?G|Kb$ofQv{hJ<5%J2P1sbaI%v2x(e*$a|En&FOkfeI71l%%voGKgO zY+BA8Uxg`W)JY0DwA%+(rYd^WktjFxO_^x%@)Q=u9E5{5Bc}R-oGJLY;x4aT%GpK9 zDR?+Wm;&4ltICHl4_hIE#as}YYrRwlH;IPe#@P>VCo+U$VueiN%{63v~?_!lc=%}?Bor_(hlu=s37lX@7ETuUb!c_|}NzjQ%7GI(Y zIbYAR2k9FF>Z+!;YI>im_ninRrS7O7(%c1QBZ;tb5+7 z8x7U+C%txoEw8Erc2p8CE@*3jl4H;i>S%{C!6n6-mDpKu_QW2WKW8^O@J9tz8zC|S$!}uHrG3&Czns1fZS%=^X3YTK zk#Z8|4hHJrVp-)RIVb6J9IY7a5lz6TYnlMO@((YT6F;(Im7j0?xX8mqwGjE4EZevl zhR$ceQWNE2*3euOugOfDGn`^`hO;i&n`sYijRWatABABXlVeU8TNEmbmz-W!X5**g z%T42yj@v>4mWdZ&u0g4R6H#o!&CyB+-pK7KR%)OQDB^M?lRNY8m;4i|8?dfEG^JdAyV3x|h=)FF^ry_a^JVKwlfM#b0^$=#8* z)-RteaoOe6VB{XQd_fK^k#p<*QiQd(RTC5@TAs|&O=CflfdSbA|4RFk=O7pxv3Yqc z>c$<^Mcl~>hg!tGlAh5hsTD<>x%gb2CN3u|o4FrxS%V&pc?N=INnv9k>M;-05>I4R zNB#S-v0+_0lbMkb|4S`b#2Y^Hm$fOFk5&q=GbY%f;R;Y!;fF81g04ybMt4}0E~w{= zu!z{Hzz~`}9^5SIQ@cg(A-fl}ZOHZ?`&<|sVpdR=fQPipd&=?;Hd1}`nQJTGU%@lf z%U$IjLe$`3CQ1HYrPpjL4G0~2hisE8J#>m;Q zQLgobHY{bPv6k`{7P;Wwi_e_Fi3ZjX-=TM|#>rA~Kca{mc7>_^G?DWPsQa%XNZ?@_ z$;X{UII&y2zzOZ{m93sYA!n58d1Xt`y~3g2}0msM&=ty2YbuH@J7|0_+KST@>yx(S{x~E z${$QZn~%Q2Vv!t>y!^x-8cIH{8RD?~mDY@V>>;LMRYj~W=Qd}W)=j--rllOy6}qU3 z2;%8WIFJpkYkXSHV)qkPdSAZ0&*WLB-?9mM(#3c@WEM=(5pLB6>Wj@xkO zqq2r8e=BN7V)xSZ??q|iaV4GtV;=FqgBT}+6wqqHk<=LXp*!IjrRKisA?wCRgzG=v zvm?=Qp~}WZX!-sgrj`=6xg8^4J1q6j&n*%l`^YNG10`IhQ1UFFh85Q|Q|X@j0|HQ7 zoy!9+ZqHP^haw)gmDhlC&qi`<@5^G0RX4FrtB|IJ;svE9!-XYsqNR#0CXHF^7IB9o zIMgyrr*7rfku-mr*f=bn3;Ph6?#)I6@N`V3+#`fk8H|HTfe?yn zXwwaGc+7Z7@ot1R5xKlzWkoC6&fnP8;7m;y6WhYzp z95EcirYblU96U!lpGuZ3It1a8L2>#eC%{%l5q-e|Qw^%q+cdJOBWL5qlIiM=175(G z^g29eSLe|<2A0O>I>X#>xY|eEQNgT-#;G87mNEKPs+Y5%q>=+m1|x%<97?PHKA@|M z_o0I1{zpg&#jfdM!WpJy6{U$AF`+K#F#Uvj{mTq)KDy2cqUKm}Y zQuHagO7~QH@ua5|HT_*Yda4v4r4O5W?NEfR8o|z+J=h5~i>R1KUFH-*_SX~^H;7@O z&CKz@GC9PRlQg-b;N_%`LM`{;E}@Qs zCd`c}yYU!VSs6Hol(Yy*(Ny3~4&(&WRhB*idyjQj7Yr2ogo?Tm1>PL;55r-B`JU7r zV@dd$dT7HY9&?gs|7A9%o2gU!Duiz6# zLB41#7YZcRhg{RaaK&PcE)keY!JEeyc)45{BM z`f{RFq@aoG8?;U%$H=Uiv~+ax2_Xw7wS>S;n^Wv>pzKqb7=H&d^^heNS1T|@IO5yv zciI=m0+ZS^S~5m#fNLwjGHo(_Ookq;Ib3PkW^$E&s+AMUdl-Ol`3nH7;uoCWFqtwM zvcRAOv1m0@$6Bl96rt7-KqxruK<;38(uvG8PDmT5)JsVl)<+URh6qBIvdg$7 z>@r{y^?3obST`^?z|8lRGje%D%;Dbht!Wwa;kgot{i;)LGcukXXY;#L2wNnOifo56S-xwh+$Ytt`!B58D@pl^7Bl@@lf5( zFy~~>yNnmiEXCw9`I?AG$T-a^i8UvOAFuTAxCj0BywW2Q2)VBFh)Ty3pWHmR z6!Ib0zvWAH1d-Bp#+wS3EYnd17lm~BLo9I9;1s%$7O2%=g1FCly~DlZuJD=wFk1#$RbXP$892pkUuY0T`1UJuS^rfda~0xT>#mTa_qB zY|+N!Fy(%SjHyrj*oCUxRF<1Ic5xa%&;=S`Mcq!JkJB4RBC&mQwW+oNFy{(xw*Vbf z<}Wddets|YItE5SxYd&3uc|dql}+{!mri3xF%@;%ERL#!Y2&0KzxDRUp@R_1S!%iA zQNR(Era`Ari`yfY_esOd0ZyHpa}U3$?%FAdE}B<&EtflfKHYU)?zdyvgzn00@7#$^ z*4U9=J1F34>K@c@b@ANa{#Ia~rDBu!aZQSl6}T9w8_Xs}U0mN>Uep(X;<{Dmo;nQ- zdQh>A6hPqwAA|U!x|(WJ197gWW1KN=Dg9e?>n!3A)pdFC-L6I6?y7TD7`!p=apnTn zFJjIGyl<*vaxQqkdcVwgp$w4aEQYmR?c~yG0@Ig*KRzSfrcJzp&)}q zIhDH$<22;0hYv#As=pZF`{PS%&KRboxbxU)G#}tnN*wh1OW=SwC8o^0?{b*dj z72q6cTo12<;Q?$>V79dzf4qjJ1!9tkc_wRaA|5Rb;j98Bw?6fo>uaT`h50D~x0Agv$;F8UV-ticMKZ9)1#6)4m<&SeS zxlG#AC>m7j;lI(`jJp4CJlUdo=XoE(maJPjWu7UH32o^zk>*p=?!$_oDwxX=Lg0j!Y)U9b`8;iz z*#V&v9G&7SW~kB_QtQeJW717k|0JE3uy)#pC1c&f7SM+`!Ss~5xb9oopp#hh^hBA% zC(k;XiO=%N+P8805~d)W4o37-yH;%@KRT89mpx6!Ex&yl?esV`ENisKw?(EL!~x_d zbuU`-{_!fZL_1SBH|NJw8x&+M$r-0crMhSz$K27{mb78Kd?{N;2(dINA}nHB(n^fWsS8n!ihfNj<3?m%i_{ED z)Bolh>&&!M+N5nLx83R4hOs9tIWt}VfpGbkX?MB}THP?bHYcRtd}9k6*jFa8xo8jG zV&NSfX&yE`bW^ez%2{DVryLT-UCYzfK(QH2K4a}G%ps_>8QgmeZ?`|vS;_k&cFM>k zy7e;RPQ5Is*3BLkDgw*nr*uu%a+E~{TW|N$S9;6g$%xE67O(k!7S&K;s6XrFYVyys+FwOY5!P=PF<{KqwMU@!p!_dcxj5bCQW@6>k^oMbPX|{K9 zDln;FauwXHeJ##Qs;>0`uGZvbD3(^CGD9Iu9o{w5C|Zw8&*nCCviXn#>$NI1Gv#EO=|6 zFq0YUxiN zFX@M;XSuNtWigb#9by;BF{>fY_;|i!H3zMxP|#%xZ4@dX3BQzjX?8*}zeMKV_>pB4 zGd##3nep_^P?`(Jik+YqKyT{KHI0WXU4RF%G#rj0S7{q7Aaw_8EJs7S5Xs<|fBd$x zeX?IW-QL~*E+!6%-VOZzv|E7s&KZN32@W5Cp>;d*}%oIO;%*l-E^d!TO3@Itpt884;tEX_d zBC(!g5vx;?wr)_!6bG1$%n$)@#v7PfuY&yvGCT*Xz%GY)h*L3vBT5K%bT614*Rpv!QGQ@}=q2H(RV zab^yub+FNzV(Cv7ifWs?L>x@dd^u z0q`>iCIRgMBjacy@j@cmuq{o5Gf;bL*dxKQO;JP2r6oLZ6ZU5VT%-=o%38~fF@~$5 zHL(UPrlj}UbTC?jGLVo|>hODbCF^LcDa2yK5fnr^t=qmfyTrJgCvlfEI=o2F(fp4n zoWz1L#ipIXGAHmufh%?TTdWz@Fz70LXmHZt(`y^p(Hc@<(AJi?Fk;z)KOFH2aAy>vGUp??{&JNMj@?nIOBk7_i5N{QX_M@Ig)+$Y(oaXHgvyG4~^ko z4f#X1$I0&cok34xmd6O=lW;zWn_|*N4BfYftH@yLJW~dsUHdw(1>*zNT~~~RIHW>+ z6WEI0UV+z{^+DrO4Q_hDtyZFC8WcS61a^@KrybJGG4gKHyl3XXvH{{8Svp7&=W6Xw zcOszo5|<T=YNaUe3_&Ow%7nuMyP%pjQ8yf*lems1 zTT!D@>@kZ(wpkqs&6PWrQ=T4CJ)6oDG`dH^flBPh>rcVkt?qBv_vK~5Yn<+x9|?Uy z+H-M79mfCf%YAQ9isi5~Xvq44Prykcl)XaJ#f;2vb%L1>2$cgO&$0dEfn zoB^B`^(|Ov+G;6g^DW8|b$$`Gl_I{HAHb^<1p8Iy>=R^(09SKxa46mHD_>>~4DXnPVG`l3Jp{ezY8+GPqjJQ3qG8k& z-3`mj$_}6y5;gXwHs=Knb}pgO^9B%Idu=uuuT5Yn3D&^%H2AIQk({i#?QGZU`<439 zn~IX|rg=&5;kTy<+LahjU!!XvuH4P_54a;S18@yGM%7j9#@rX6xrG;tCwUDyLw6!C<4B*3fc9AjjVSm^~qdziIgJb zxg|w}740(f9aRi!m6s6YNN)cI+CB6W9YgxWYarmj=s-#c02(cORFeo5{h*qqH7H8W znI!De-9%{$0SfcRkSA!sQe-Q2MxT%-=oA{%0smZuxRNSP64dcH!dT% z7Kg4?R(E)_GOs1qO;3>O1~=d773gI9-TQ;R+RJij{h6kbtYeHCCM}E>0Qn(nfUHH1 z7`uX{o+h!V>s%7G#M6zK)gvB#GajWavZW@8-K1js05G;;2*dzZ)#<*nYr z>2MWs2aeokCGttDDA-;q zam6NIu8OXMBd|47Uh^8G*bJT=w^fYjdxa&(3%?Bc+-9L8Tw;h3ouf}ppP)fg*J{ox zhXXnCOW_I#b-jW?fIUR?#ejPc(Ger^fWdHHhe5%>$s&c^a4e0rfP*4JAAv!`ODL89 zC7hx6;Id$#84PGaO7Ywusu#*o$#JUu!BRve$47`2YK;A%+GE8UoHUK0^sk|HsT>!; zPwO~}N&eu~n6~8($YSVJn>gd>c*uGox2>uB&!FZZPr+DUBTtQliy|a|_hV66$@om0 z&oGN)0U@1al0s_vaHE<*EXXtLIxx+qD&G&znw4TLOE_SOYR9M6J?nmd&e#Pjj_oxg zgHcO0dM)3T0IT2IPJ|X0?s0xYw;0({#c^;L3fi+~BM5b5H;{}~`k>W)M*D1h!qHSw zbm_HYrw1Kf#+s20*EQ3n_~i(OiA|rWbSxomu49sAs?KBd0~?rayOK-h99;dHceJ@L zKGq2cjYv7e>OO-NRMi|_Ql^b)EFQgqKoTvXzp^FYoHbBXR)XnmIKFm{;xdmlFvkj$ zuzihCEs?7nM1&GD)!kkXPGiU!qaM*f8QDe)vRuzb(L3=n!h!?)kzsUIO;uSgJ|#Rg z3Ds_qi;LCVLJScogl(GTSh1u>n4^r4Tnt_&YAo8I&Z3%x`0DEQ;~M+~c$s}<#g2)l z%gh~|rkx|%M@68VIdRO@q9Y7B1XS#Hq1TENpmnbG1Qx#$TtsA**KQDc1=sqo9P?5A z7$b|-l%5cgkwo+p>~3jFLIO}ZWL6phn>54L9?7VRJ<_6Wruz?gv6#;VC@y&qHz3YM z#}CitRCph5Pa2r6xB;$Y<`cU^>potIuRPzyZdB^NLhKW^yuYljQQ3qo=qdco+WfaY z@(SbQOHaw2OB5EQk>I{k&Dw1glHoSP`4c}k}>M{`kNCdjUrg22#faJGjX2+Er`{1@)@X;yZEkb~kPrHRn_mrmjfwN5)z3``tH{gQLUu2S>;1 z|Ep_|5j-e)aw7(OzzdMphR`J!P$8`vz*ns1XT2 z$77mSv*Hl*fU+lo7`63Vd1psXG3+V-3RDY~{z#5-R*rd{G|5ziphP52L+RBGOHtIh zbdGafbghgzgvCFnfUU(n%#qld@(bq&o8|^<2?Z>9Vo#XgzlSo9ZDC=Qn zt4|AM-OcdB+wM^+ofLP z3--x4&&U~vLTWCJB!NopkNj57aFt}R3JjnfD~65ox!_gy>+h@EXVDsywYxS8t6AZr z3ItN;qup48 z%G{ZtFJIFFlP+W9MjyOOSq36yb~!3%tkTtwDo5{YjU6~!p6*v2^5Yt?TYcVeQ-{^goVnsq5!x>f$4#spPOZmxlCHt~ zPn-|qC?02b+Jy}ME&3=8CO(`lAitNKa6|nQKR@_QMQA)RSFJ>KdXwRwrXEb7adVh|4mA->jw!Nt99Nt3P`Ki48 zh%*1yCaeL<_HYR7$ys#2*W&(!o_9DcOWO(!p1^CQEe``%yv;uTRtGdzzlnsNWyDjs;G~DV1Y}IAGP2AQ;keg z@k?V2yK@WoE;(XS9as)qESxiD!I{&D9`yzHq$jBnihCW#^J&1J^gR&#J za;U!9c25KGtIK!8s}PLF;v4niAH}Xlb>LZ&VG%9sg+ugri#uFHxM&roHwCUBDMnRm zC7548m;)li{v917=U!2WfOTL@?6M7k^HArpTVM$MT~8BD(TKmezNgKSWVr?U&x!Il z_|2vXRpA0Nt1&mo$M}}K`Ke-Abaj5ak9XNAIZ{jW0M^p#q>YSIrqufB+rYHB0tI*q zgDhM<+>KL#DOTW!SfEF2FpRUHSf*a9X;oN{$voe3Rv}H^6#JUNOR9leYikcWeX*L< zyrLUhvv`ZGArEn(-5bG+vM`z9a>mI^IG4QN-`#t)|Grw=et&jUfAxNQzxKYo{^R?@ z-IMpVSKI5G&!5JnPRUo1pQlEu2aS@7qzIzA5qA_65LsWK zQ^`w_vYL`>C{e_lsI|DBB>hRR(6$mFr0gN?B?7JfEMcff5GpA^mWmHYQ#V0Om50r- zBaWeyjAnF58CZRWWJ1{47^w%=ODDbPg%t>X0y8M{U`f)OE$;vpJ;;UYdU%ZO^PAy5 zulI=RJ#5I9Npn49bIwrnVpW%n@S*56hDFE0O{pZ7>mi3QOq1H|kfGj&wAr zIoZ!CTUXsQHQ{7+3#aYF*~ds?l1;`%{8B^Ihc46H$6mmYl+<^7*+m zBzN{5EaRhZQ0qq0VfX6YC$ zZA|*%kW>1YqkD5CB!l4q64CUG0M^-#=Hbi5Kx4^8l)zb2D;01u)BZeMolV^rXOR2B zHyM&rvNg@OgR^3td`YJZ`h4b#QZy|?fbN6B)R-1brc;QKNzVlJndrwXS}5H21_Vo@ z@LY?&ftdanqdYe{m+{s?l zid>2w7iHN>2$EE}YGRe6>yg}MDi9+Nk}1)2m3^aVq6yV7Q^lidy)drX(IN>tZ9D4r zqiEfnpmvVd1GRA^pp;GHe2h5@YCB^hKb+h#o12$@cxLYWSjJ0|n~zMFnM3b=H|XP> ze^Q)|`q2B=zDFLs!4@-)NGvC>HF`O~Wl=t|%Wiq!uYqk?YGwc9$T(tAn9ylToU$aD z`id@B(D%bcJi?-@GMh*X<5s3qu#;t?JqJs^(di|Sd=-&Y!?yQ)L%#L~wHb2oee_lf zs~i)Xu7cdI=*7r5VOrp#e}`QdbSos9?~qGm$t|v&A*UK)L+OS`6I&puCWuRH`%LmN zL9DL#6VAZY{j*XFltGFqIE*1vg=BfL@@{;q6T<9OYAj0!IYwuES6n$_5)hSEkexFp zqR0$Gnkm4@q;lIs9uZ~_n-EW?%^>m`+bp`qN)06y>0xc(%*%+Jx`^4{&Arb^L=Lvi;q=m5{f|lEKX`FW)w<%!Q;p_< zh&8}vv@D*p29xu{WGlfy%7B`5K{Dhb$cmYhML@-~CE1f*nQ9f8H0pa(r$+e|jE3~h zZKSCAuT^jL{p$TE5VGzd$BL4)nFty|OrC=n8Nh#KO^_BZrKIAmyCXSDb$qVDTKL0dU4^oikrdhlYXrE`8BFd8PpcSom<9i4 za)P^Nvdx%pZAqkD65Z04Lc(z|LgZVE-{W`2UX#mm4?Ui2Jb&KV{4rQJ`k@qK zN%f_yKh0zFSvL2BnYCTpunJ66yk@ksiGxc?aLBD^AW4{RZ5b{}oz=lb%|v5cbke%6 zll!&ULY7w~8+=xLu>vEQBv6EzXUjXGY3_IjS#|d&D_yL{Tb`VH!;?a{Qk)IpL_5a) z^V7?f9(ZM8i8VPmovgtDBs35TNT51Js55K`99eY*4UVC$2|s^=<2b`MA@44`n0W>RI|uzto`aIvyu2XAe9Gl(t20@u!Y=uusx#m zQ))Ws{0-8w`qQrU9BU!~41+5njfY7dK#_x{BbxXhzAJhR{6QXIsY#TWJ%k5I$i-LO ztG%xw4m1FWUA00rcWWM!y-ik%7?L&lSE0XBY<(Kz0sb`)x>xw!y)r*1H^a3U5FHti zV^3uq`Mx;09j$y{Z28yt7Z+OKUswpQR=)p#P^0O?TN*izkM{P_E_^q5%i>BAdC>ed zRUD62iZ_!s%(-iG`$m~7`N!MOsp~J62M9{pJJ~M|Iv8tV>XkqIC7O4_mm5ESYvxsN zaD}B@bX-`(*IIt(Dp=E{3#xFzNssnFC(}DP)m&oC3lnJBKBFuwoZ`)@|vrKiW?;zJMG+VI$rAwNHr;!pNJ4b0&@aa zDy~^88114YHq!ZGCd%}+^Xqf(#a+6jNsicMkSWtqi0*()mdYtMQ9t zJQKsj2sbkM{VmUGSDrJs^9(6D?KgM0hYTyIsBp#KrBLWG#*#Uau>O(2FOr|O-Tc&QesRtWo?Ka48PgGSE1 z;bhR89uXBB1Vlv*{JJjSrIb*OuoqWOa+xIlNQ)T&{}c#nSgY#&=QPp5!B~5G0q8JEb`z>)^v-%JNb7E^HNO@tdU{^WVcfgn zzzio{D)J4M7>3y)?X%k3YqxWHtg61F?gR3c}bXd;p71UcGz5>+Qltj}by z20$FUhR_gP@rFyC=B|FT=DX9z;{K2rB!k|OLapXaVqzlFY>zcx(N1+tV)%5&m2QCk zA{BiocNp7kOcs1;OilB=|!%Ys>CY-HGy3;Z82dhN8PZ>>^ z=oVZFkurB2a8>taLkl7%0bD8PaXEoXBKbmN#S^04$V2+}Lqnb3sk<0@Eu_;OPu4oT z;c{)#yDIo&C{5&1xE-&7+zi=7#(Rp&30CYU(eY^lQN^NgE(UuzuSA+TPnHiB1)U`O zMLt~u)QN~AX5=H1vASQYgE&ej#uJR28X}8t=P6`Hi)t>xbCOBvYtlyHy-w{yiFcyAZqmT^~Dy1XVl;$FDke z9HU8r0}{LGD#S8Jk7|TD#Wa23r>dZc?R3Meadu%x*2Kc4hUJhu>}WEgT#t$P#Or`F zF)o{=RhEEYvq>2ndsM|pIVdH>pDDGg9WAt|P+&0+aFe$Y-`t__Ij^U(*E|CPk_@Um z%-8*Jf{R@0;Mp7n86mmzPXw98rqb4o$^xgN^<#CaN&^E z?uKT?{X!#!!N9({FQ7qhS=1eZry$9+HhK_bArq0HZVja*lC%fNhz_RgLQ1P3a&Q9d z<2@X@GBiAmteyu=lQtZY{F|jga^jH+xoI!PniSlnzZ@J~gl5PZe=aA#-1L@GGtVU1 zmrU`HyGVT9n=os6Ic-!FMUqOVp_ry-ecFF0J05@-GJ}bTQExyZ7!$U5(jx9#>Ut*K zSZXg+UVZenUO$$^2GBrYZwyiAilWh^0MIfft*5zJYkl)s3Jx)2rMz6sSJqzOp=3Pq z$Jd5>Dj$MuFR+V8kL7FhR?exwASq}@xdA9Av9drflXX3okvtj^08AnwgvJ=j1qw=d zr_EU=q=&k|>kY8pgUoVkR|_}b!ED6?k2?%f+K4RXJuR$0R~~Ym(PNiatff*;p+j~{ zPy|r#Df@7N+8}i@=4R2aA^nou%7?P5P4M)U{aXmeiT9yL%ch%(z&)Nf~SZA4P?r1$dg$%u6|@;lteLc!q` zG1&e^j>#)V&Ch4bIy~LBAqnSM2Cc;Fd9zj$69Hfuw-WF1`fHiEdLx};^%N#6dtp%K zm?LzwgAt!3Un>?$Y>(&7Tn>11j=Q88cv|+M?PD8n&FGx%$@M%|HPwq#UfN?l%?Zp7 zow2JcpcU$OX{h386~`G(A*vgogtb8qBk6!VlyBrm_;D14N$L8 zhw2bFE-T1|o-lSjMFBCP2{2@Mf-wLqf-$H$Flife=8dgSWNm;SEo70+?a@N^Xd%0& zb(2EpA8#Q`$f6u}vP2DAP*5Ap5*B>tUtJ**L#*7#!SD*FIgSuw5t`IwBfjOO8iyQZ zjH<8&v(Oiyu@sft=Jc(V2osvfEoT4cfB(M>sPbl`|MS29KM{><8|zeTDSu%t$E9+( zU{;Rji>@ZSUi8k8R8L(Vdvtp9j3-xIfzxc`IczP)kd;g@M=Gc#iFP9U9EorEXLVW; zviW==DUtIcmC}~G$(N!fn#w~=6iZO^`R7q{F~Q7P#M~*5qNl@E875j1h|8n}irakN znwU6h;@V8}JiKc~n=N|#@FK=7zPLDA-!kmeJTUC|<4yz*&L48nl`>F@mvAxZ#rDB_}*7$gWwN z4nF>f<-ttR#?zcTOkhgo3+pzy z)DuTF&{7JH^^~PN{1XTB?aCgn4c#89tF@9CNgWt~Nfot~$DzkIt^@7c2lh6rCAwq) zV6062ROVl_prxaq#-XaDL;bm4DIJPgEvmD(KZ!=3nvMX=O9u=NE@k%C;t zBvK_)7{tO)*fwSzbyjcO-IbzD0fxjw%Gl1sZk)jT(4WBHe!5}RG%Wsg+U^esWGZzu zm1^)awU&>eDhY_$gQto(Lr4rTYMhm7y!b#H*UbJ5y%OIpBAs%OYfx05OQdC7*ih_V z=q?#lLN{<}SjKb|ZwwhLWJ6ZIjhLU^-be(Jnf_V3pBP>Bt;rDIs0lUAkA_dZN(g70 zr{4ZY@IIbmNcX~Ef~WE%O~TobbJI+r`K2kQpbFDtN##Pu>1#U^KrmrVAd^JY1=HYo z9;~6do;hhvKUrBfq?%x85_OMZI4sD;eyMF}ilQBxpidv(oNh`^(G()+3C|!9bkXrT zGx4CHawGSa_UwGmrYr6z&WLe|vxL(x8|S40OhL}g4o1mNS3X=cKNjLFFOngzpqhcu z8Z7LkmWzp$`z~<$w?S|$9F;=EI}3^_oKg(ic6%D}RE^7&dr)^}Jv)~BV6*3#?d!+c zFzgX0`!BVAr{kJ$|#hef<8k zx_`iw_G9|z1z^7(x2kc}9!s|9KqvtXxJaG`^zI;i4WWmwifHKK0#xh}1X&tW2$G*j zI|`!7?t!rm;+l!;QS72=q+E7ds0fy2E^$r^mXeL92hrhyWt^9YSD8_SCtfyYmrs|0 zAw0sBH;CC@9^*#c9ly`mv@v#Vuy-Jji`va#cIw@nf`v;Nc=RoLya6gvuo2WWsw`lz zJdBW{#$%Ko_jzd?!qq6bVaqC)a5_y^<5U2VANP6gO7H%9+~+BJm}Nbi*HpQD^F5}q zf%~}6gTZOb%UCL7dg)s#VcO;f^>Lra)#`Dd7xTyCJ};&Pzdi2r9`|_>M|{bBp12XE zt%iA4K=C$GscV$gwsnOI+n}A#`QG&4)eXA<_s`K*Z$v*V6irjbJx94`wLY}}R;>N2 zg+m<*I>$NKU@5dBZ|#&=o`vT72X7`-#T0vy_8Lr>8ypG)ZO36KpF3otQj(Gx2&Fv! z_i&07W>52l1g|g(kh+Tuk~X-)vF$8qb;Iylp6W!JX125?zHC>50?aesCc1+=0{d_# zJ+76e$F=fqwb6N9@9peWo39(S#>MNmrGrLQ-j$|%Z%36{qknkTukO7q?cbgZIy;?G zfA{TK=XJBOd00IwziZb|HcpzOpE`%vr_t$x3?F~>H*&Ewsd{K-9wv=#&zec)$E@)hn4HM zrPurCAC5kD%Kdkhdh>Pl-PP^cb#>>Waj|jos$cQ1_dnH})p4ivqEUa>uLRed-RiJ? z8#KzlyscL&&BM+H;GQ=3%bWFgqc`V`@2OinJbQb6a8qwIZX1J-eyef* z@%*}5y(sVBy?IytP%T}QFPfFz`dRf=<6UQXQRfdpcePbdBBPp$IBd2O&csSZw_oquTd0e9f9UtGK$p0BqMnbbZj zUk7KKr^oA~?%BbP|8`J)TdV!J?jLmCH1>9`JI$`&*`J;@N)?Rv=mFxQ64)~({rg^rxS-t*oy)mp#&kimcfZOX_f1K3!n&&~i zymQ%>JGQf)&FlKR{muH} z>*LCx^Hb&1!SnO$i(&0u^V#0puzXw|z58kX_1LfPtXKP^{@L}5i#L0XkFD}((!M@u zR6f1FIoUgUR(VyapPjv!RZ62*7tM?7^NmW_7I}Xn!vG6`kt)6 z9@O>@&Rb{a<%_+ypX#N`8ODBwd9z+QYx-{vfBY1jHIMy`i*f7v;%(!w`TC^sVyE?? zbJ*JJg9$2?>UyX9=J3F;9hNbdr<})=<4^sQ+Mu&{{$XeMb}&7ymrhD&!{)OV=B2-1 z{i#{r|8zEdy<6KDoxJT=8W-;>Xt{q}Y4&g1@2Y3b=Jk60RrRiV_TnJuH|sx@`xC&u zJsWo3ov%0Fp1tb73SOOTUNowc>PElP9K0R-XXQ=wx85i>Zkoez{bca*`N{BNx3*rc z)Zgt~pZ7a^Z_m23P6>7D&0iYpox76{RS26=DFB}w-%Zvl8=cLcK6Phr`$rq#|6iK* zgQNPe)2x2j`4sF|&pP|J92~rA z-hp2HUaw+KR*=N#VyE(IXXowUN63}VG2m9uKUBNt8>2zcY);zy{hc?>gRnL@m|X0i zZ`3wAr?pqjK4n0)Q5jd>U6tzV)0^hr&dphKRO);>=v7OvKU5E=KI&}L8dc2KgI&PA zIcbzPnvgFS`>%)f{>2e+IH(Rf)#llYQlnovY7AZ+oz?g6ss|U(AQN^w``uBie6@Zt zfINNIIfC5VZ}yLF{p;7ekd23}(m|7OI|r}pwS(6;wS()AC)d@pU>{>Kglsx{ab6i* z^sA81)mNPhz^$De5TC0X$QZ~sJZ~J`K>odf{2RB=x?{i5-t2tZA-+3}ca_7pje}FH zBSXNbwXR2#v$N`llls9c$i|On!|wAc=5=)gYtH&;ud?1etM}h-_|5ZjXXEIu^{#){ zdeu2S@4fIFX9xR!>Ek)^Z9?aG(`>%0mz(|CyVv#3r^a1puQPbtz`N%5E#y@1{QBf3 zXdaCl<^C^?!|n}m=`~+qiq2pSlN ze)lA3Oy3-@S2q3Yay8hi9{V45j!q7)O0Bck&s(3G7nR2J)7jbdyxAz-yxBiE?VMel zv>|P4<;r36@M>J!KcM{eTjjT#=fjIvwe?NEGpwNR)ANgi1I)Q@$-nOUjStOVe%fek zTpUi{zNx?70l${32Nl0n`*DoP_N=u&-TA5X;&tm&rv_Tx)?QWKQSMySJC*a&LB08| zI&GB?-c;Xpo_D}&SSS7J+1v7)!|6}w9~$Fksd?5qtbFo^Soen2dh65v_+ou?3OV;n zwY)PqIlKB;UGFwqA1Kd8SV#M3)#1+3*}Id?^RuvA!5Uusa9uuWzP*7gKJm{!4(k2p z&>!v`zb&=Ptzo}ZYfLwS!N=~KSCwh!uz%ValpB@((Ru3~@V!1-2foi*gU+jJvp;JB zr$+t!_Uz#G`kVc3t#&vnHxFOzR$pO}*sqS8d)w>P^6Nv$&@$HIgX%hHaD6d4d3SMs z*7$ggHQ)?u#rny+>Q98*X?7ab^60kG@9))`ult?;&M&P`SDP1iQ}EO4n%_J)Z`8Z5 zJEabIYJam`s$%`<|5E?3U8;TPG>^;G8}Q+%@@jvhIqXlW;9mz@^d)pkg@9KvK;hWlve&bW;;-qm=K5taVSl3T44$FQ2u)OnTclt}`Rpr7TyvBG} zH%|uT+FAdg)M#9M0(~2ea}sD&+acHU%$P2TWZ#t`~5@e4$b`rbVcZkZ(qKQwh2_qdq~6=JusO@bTm(t zOI;UClv|j68_DaU{iK{lZF$Tq!Jr}iBG!qkk_Er16lCixu;95lOnC6Fo-htQZ+sDV zYtkf5_&QIH+QS{=fxL;5NVJort+S@|!z zVZT#Ho|vVrR#h$}xQ?)SR+IcPPbEoa^t+7@$AL(AJ$(i zOu=*i95DBD#mP99l~k!v_n3Kz)R4#w;Yp-w(at%{5GS4&l2cVt28o=>6v;nj;73q% z8pRg)*esfks*R-UN7^8(k_(zq1(r9a%E4DKyA@Sr;iOPS)W60_;EMrNF3iioEv3ah zy8+Lg-tb65l)SW9JG;w@Hp^Us$0{1*xAE$gU5aGjOXXgh7%4|N_v@T6>_5bZR}p?e z2bL6AG;mDea~qCRhs#;qwwwneK1-R-Q5LNGudIqckM@>! zff|%5j7;97XB2d()>4FHfE81aTS!5b7*pF8mf}!TnW5n&!k9m{OO57Bj%l`tE_kAF z&2_LK{l*l`dZUm{yj4U=kz4uB&`&|?Tu0|DnAA@)+D>`A=(zmS$Au8OS4)!!QCdAP zV>9L390?yyQcUo9Pm>g_mHc~X4(3Obl*z#?qDQ=S9j^jnFFMY2x())^M; zs<+|rPZCATGzPO#a(ShQRcmR6%C1ci4=^7^#tRs~o+68f5B`46gFvMJbS48TKnyUWocix|0 zdS&lF|8rrP|9-ikktJA@^oWOqFFOJ+5$vf=Y}h>ME+o`FV$HuS%ulQ=%|QP@kZ7({ z@?O65<`sIKefZ=wjoeWdBwIUEO{;(1>BEej$nk&a-9n2-E>99(!}m^3g`FfVf#jZ@ z!0gHRY{aB7hY|LQ`0`xs3B2GVu0$DLA-+vAA^`}_8(?O$CRM7POih$5L+`yz%=M@@ zdNxz{O))nYy-E;tu;r#$IH*=tUS|fjX3ykI1SPlh;TUo3xL2*p+vs!b1~crFDp7R; zn297LA-Tcg5RvDyg6)x?isPWQ`tfao{eS(_38)ip<4& zcg5I$p;RQdW6_%mx)vqX{sLq683HVQgpizxYXu~kngfWyyoAjM7e@s`z|<}oSwP{% ziH@_08othzeLU-+;Cejku!OiH!!u;b@8ql_52}yx#Mam@Jgima@}CYl)K6BUkbaCO ze#{$%%gg7lM6x-O-}4^nIUJWEnrzqxE))W!d3ekl<=%2;Q_6f-XQ48AALEH1^F|rA z(4X1I7k0tNyiqna?C%ThHl|>HA!nV7tL64FZ`3UKm&hAs&iK=fFjiXGf2ePOc0_<( zY#b~UOTb?E?9DwIk)duRB}X(kR2%Ec1&c`l_XeVf{gnKdypi{ z3XnUBc{UWLP^{$KJPkQEvsCCs4Ww~9AX1*B_+4^;mi zh^^{O%E3DEOqhO_=8mJm?a{eLQBM8qjI=(NS61WS*tte$`!E0SB4z40SU&pRWNh$$ zZ@xE3mNb5Ndcw&1Z=Gd`!CaCBQr2KW;(7$1AsVxhj){r?#+R_&!*)xHxwwPzs`L3j zABSwnW(WjRUM~=!*$VliKao)RU+qpZ>z;?S3>>+l1*3}-gxBJD!RYy1#Guux)QN)z z%^T(k&J#Asm3S)=@c2-Np@c#ip|AErIA&rpRBDaT{Nz>%93S$4$KZ@>H(V{C0f#i+ zbUW17Pl$?#;}+gXp;Bv_BY&kEMpHg<0Y#Qd_82Mm7%BG{DaQb5mDm@-Eo+_NCg`tC zdRGO1-0mXCqCK6BgEdT*0?OTxT=4xU4mwY`4F1F2k|H6qJXS6$>I#{~0dtmYO4|)B z2tvscIiS70?r#N4`R9ILmd&A6PqqhTX+H_*Kj8h zWt*ON9?nEGa#d9sCPr{R)ga}Zgo`E~QL@UlICnTg!F3wEQe)Ef$Kna=2vY?ZYbumc zdP>tp7FYbpwVVRj$l?IU8Za#S-tN&}RW2;)eS9h!C(=28#8r&#o=G=lV5(2?f-Nxa zR>2d2?+9yCe!<2fWz90R_^Do}X_^?vXjM-iNNr`eG&vh`u7QqP@GkrQ6$3UUk1^bR zxOY@%a{V0@i%fLrblm2kaCL){k~$)^62aXWBbmkw>8gRj+_x2uh275OM4!drb}M8F z_7+SWt>qYW?s~*JT`Y+|eQ|v=J>&tax-o3w;-H6iTBZa{t<8<);jo-s{kw6`u^nzHs8?>*ZO}~EM z>-VN|mmt(-Z-U@-HbL4+hw&p7_XG~$GD8PkTE(CSLb)7=0|6!1G=cgUWJ2amOp_^l zmkK-TaiS62UZh4<&J6c-#8D16A$Jx{n5|A`voI3{~>X5XW zMiSOuuvGAM-oF0ke%VA$nAE!2POi54;&=M8C3n1xIN%-3%4UoB-v8Xe=^cjL5kBCm84u0jqwF7+X0 z+ottwR*y9Md|Q-gA2Nyd9}xuZGT>9AujJJ`b8~2b>ngBo%!uG#D)@4+yeg92QM1j< zS~H!=a%wj9rk1BphiU#XHU|~Nj$g6Kh~206v!s>J+9fGOdHi*inzjsPKLsG#>g7Ut zfr3;^z>9`1p(N9EqIQlN1G8^*hBQ+M>!B7ynM9{XZmK}dNYzWqpzGrM=3Fh}5V&uI8C?elTZ__$|$+%s}!{Dbz4 z3!2Tg{74R7TThIyI7ek_=SRdsUEQW~(zPwYiN7I$NIQ#_+Ee zcGO>w(s8SUAbodQu@|oJ9G*&BuGpjFb?1I&AuKl$>c+Cf+he?t66WTzBpUKEc2-Ti z#@nyuuG$-ID^H749?AAIZs8SDppb<+2C504)^EFDJ~v!2ijh;v&MWvm`d-lQK&Y< zUa+&#P!#jevxE+9W`dls1#nnmBA|({=ZOF4agKYCcmUVAw0%9VMw78GpHgc4fSnz% zvjcYaRbyu(fs#khMlbkcf@@7mR4}daJU7k#C3=4gplxXpD8yK#PYnM-u-37F=_a4) zMc|-pE(1=_iDz?|E+FPwLUC2d@(A!Qk&#V^*Cs$VJnmbWD+FP1mb@)V+Txwd@-~ z#$fs1uwmQT`15_JO;CUb3%YRUSg?$=R4)1L?Ct5Xrg;N)Go9+w-HRRnYA?92;x<$3 z`mS5-AU1ohR&_zLR_+<&l`L-O_^u7?^jQI>BffYzIOCta`A}l+J3x(axh}*2S z*8R@gE4@{9Wj)K`wKlc87xiYjkn?!d<#wO=tb<~++=9Sr z9R`<`9c|eR!7wYpV)YH(Kv~EuW|t7CoX6^=?VB4#51XzDBZOLIZ~Wm_BbGJY&C^bH zIISo!`&o-wFdJwFY^;EunQbxu1xF;xdD2tMn^QjFu6Z~6^9XJ4UPC%DTV#nl9(|L` zIB_S@3y}V`#;CO58bp5=@&0HPR-fvItrgTLxryoQNih?u+J^xlH&^hhLaz$8OuF4g z)`S-sM+5%FwR{{8zL0?XQbOQ%w(o<|(&I4FH1hAKIWDYKcgjY~OEhs7(ipjBB!`AB zkDUQhFV2mwUC-(oZ?rpymO*LJ4sdIfCAHjEh`-C`d;5l?J18x1xi;@|Y}-oz8kClQ z0T>NR3rEqQw8XQ@{XZxz&_Q4uL&$e*9g~ZDYsGq-N=s5dDnRW-$5%zTo#>r-6P{ql zc>D$+Ikoe~Vyu0EP!ro?a=xnL$YiX2B(s5j~VloO>RbswM{ ziAQ)$?M{kUIj8WDQy0l>L{-yEHicja#!<3$70#hWd#@|?x_KmYgO|7sZHZyx(dZTs z=P*jqmv#e*sq5wj1~#wjS%nxR)V3?cX+=!_$5nO97%VynshcjA)%3brR5&DVBC+t= zR;XStv(;FxL-i+i>f~d9ybO?+0rK*yAuo~q$U|PD7kn{6iEb?PD(F@E#7cXhq}QR| zq7tCU-_Gx7U4%$mUOxzuSA>~FeTs6&{G>z|nQEaaF^(@0qzW@X?#gv zyC`e2N*OF`YQWt&R$b{HzC$)}bJO#3^|NhZ1ms$!Y@lw?M37r8N57M!%1^dWqqyJ5 zb}x4wQOEMVpi8yC3;NVp@%_34=M^xa%yDlwt9KafO`ZmWudj7vN4H56X`s8X zoj5b}Ii?3CS>152wS^Kh(s;~@?!xur-N{G%d^joll;(@6UAqUD7pG^FFBeBgNAD7! Ezp`dB+5i9m diff --git a/metallb-chart/charts/frr-k8s/Chart.yaml b/metallb-chart/charts/frr-k8s/Chart.yaml new file mode 100644 index 0000000..2fa4501 --- /dev/null +++ b/metallb-chart/charts/frr-k8s/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +appVersion: v0.0.14 +description: A cloud native wrapper of FRR +home: https://metallb.universe.tf +icon: https://metallb.universe.tf/images/logo/metallb-white.png +kubeVersion: '>= 1.19.0-0' +name: frr-k8s +sources: +- https://github.com/metallb/frr-k8s +type: application +version: 0.0.15 diff --git a/metallb-chart/charts/frr-k8s/README.md b/metallb-chart/charts/frr-k8s/README.md new file mode 100644 index 0000000..0418d64 --- /dev/null +++ b/metallb-chart/charts/frr-k8s/README.md @@ -0,0 +1,96 @@ +# frr-k8s + +![Version: 0.0.14](https://img.shields.io/badge/Version-0.0.14-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.0.14](https://img.shields.io/badge/AppVersion-v0.0.14-informational?style=flat-square) + +A cloud native wrapper of FRR + +**Homepage:** + +## Source Code + +* + +## Requirements + +Kubernetes: `>= 1.19.0-0` + +| Repository | Name | Version | +|------------|------|---------| +| | crds | 0.0.14 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| crds.enabled | bool | `true` | | +| crds.validationFailurePolicy | string | `"Fail"` | | +| frrk8s.affinity | object | `{}` | | +| frrk8s.alwaysBlock | string | `""` | | +| frrk8s.disableCertRotation | bool | `false` | | +| frrk8s.frr.image.pullPolicy | string | `nil` | | +| frrk8s.frr.image.repository | string | `"quay.io/frrouting/frr"` | | +| frrk8s.frr.image.tag | string | `"9.1.0"` | | +| frrk8s.frr.metricsBindAddress | string | `"127.0.0.1"` | | +| frrk8s.frr.metricsPort | int | `7573` | | +| frrk8s.frr.resources | object | `{}` | | +| frrk8s.frr.secureMetricsPort | int | `9141` | | +| frrk8s.frrMetrics.resources | object | `{}` | | +| frrk8s.healthPort | int | `8081` | | +| frrk8s.image.pullPolicy | string | `nil` | | +| frrk8s.image.repository | string | `"quay.io/metallb/frr-k8s"` | | +| frrk8s.image.tag | string | `nil` | | +| frrk8s.labels.app | string | `"frr-k8s"` | | +| frrk8s.livenessProbe.enabled | bool | `true` | | +| frrk8s.livenessProbe.failureThreshold | int | `3` | | +| frrk8s.livenessProbe.initialDelaySeconds | int | `10` | | +| frrk8s.livenessProbe.periodSeconds | int | `10` | | +| frrk8s.livenessProbe.successThreshold | int | `1` | | +| frrk8s.livenessProbe.timeoutSeconds | int | `1` | | +| frrk8s.logLevel | string | `"info"` | Controller log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` | +| frrk8s.nodeSelector | object | `{}` | | +| frrk8s.podAnnotations | object | `{}` | | +| frrk8s.priorityClassName | string | `""` | | +| frrk8s.readinessProbe.enabled | bool | `true` | | +| frrk8s.readinessProbe.failureThreshold | int | `3` | | +| frrk8s.readinessProbe.initialDelaySeconds | int | `10` | | +| frrk8s.readinessProbe.periodSeconds | int | `10` | | +| frrk8s.readinessProbe.successThreshold | int | `1` | | +| frrk8s.readinessProbe.timeoutSeconds | int | `1` | | +| frrk8s.reloader.resources | object | `{}` | | +| frrk8s.resources | object | `{}` | | +| frrk8s.restartOnRotatorSecretRefresh | bool | `false` | | +| frrk8s.runtimeClassName | string | `""` | | +| frrk8s.serviceAccount.annotations | object | `{}` | | +| frrk8s.serviceAccount.create | bool | `true` | | +| frrk8s.serviceAccount.name | string | `""` | | +| frrk8s.startupProbe.enabled | bool | `true` | | +| frrk8s.startupProbe.failureThreshold | int | `30` | | +| frrk8s.startupProbe.periodSeconds | int | `5` | | +| frrk8s.tolerateMaster | bool | `true` | | +| frrk8s.tolerations | list | `[]` | | +| frrk8s.updateStrategy.type | string | `"RollingUpdate"` | | +| fullnameOverride | string | `""` | | +| nameOverride | string | `""` | | +| prometheus.metricsBindAddress | string | `"127.0.0.1"` | | +| prometheus.metricsPort | int | `7572` | | +| prometheus.metricsTLSSecret | string | `""` | | +| prometheus.namespace | string | `""` | | +| prometheus.rbacPrometheus | bool | `false` | | +| prometheus.rbacProxy.pullPolicy | string | `nil` | | +| prometheus.rbacProxy.repository | string | `"gcr.io/kubebuilder/kube-rbac-proxy"` | | +| prometheus.rbacProxy.tag | string | `"v0.12.0"` | | +| prometheus.scrapeAnnotations | bool | `false` | | +| prometheus.secureMetricsPort | int | `9140` | | +| prometheus.serviceAccount | string | `""` | | +| prometheus.serviceMonitor.additionalLabels | object | `{}` | | +| prometheus.serviceMonitor.annotations | object | `{}` | | +| prometheus.serviceMonitor.enabled | bool | `false` | | +| prometheus.serviceMonitor.interval | string | `nil` | | +| prometheus.serviceMonitor.jobLabel | string | `"app.kubernetes.io/name"` | | +| prometheus.serviceMonitor.metricRelabelings | list | `[]` | | +| prometheus.serviceMonitor.relabelings | list | `[]` | | +| prometheus.serviceMonitor.tlsConfig.insecureSkipVerify | bool | `true` | | +| rbac.create | bool | `true` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.10.0](https://github.com/norwoodj/helm-docs/releases/v1.10.0) diff --git a/metallb-chart/charts/frr-k8s/crds/frrk8s.metallb.io_frrconfigurations.yaml b/metallb-chart/charts/frr-k8s/crds/frrk8s.metallb.io_frrconfigurations.yaml new file mode 100644 index 0000000..2813767 --- /dev/null +++ b/metallb-chart/charts/frr-k8s/crds/frrk8s.metallb.io_frrconfigurations.yaml @@ -0,0 +1,462 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: frrconfigurations.frrk8s.metallb.io +spec: + group: frrk8s.metallb.io + names: + kind: FRRConfiguration + listKind: FRRConfigurationList + plural: frrconfigurations + singular: frrconfiguration + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: FRRConfiguration is a piece of FRR configuration. + 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: FRRConfigurationSpec defines the desired state of FRRConfiguration. + properties: + bgp: + description: BGP is the configuration related to the BGP protocol. + properties: + bfdProfiles: + description: BFDProfiles is the list of bfd profiles to be used + when configuring the neighbors. + items: + description: |- + BFDProfile is the configuration related to the BFD protocol associated + to a BGP session. + properties: + detectMultiplier: + description: |- + Configures the detection multiplier to determine + packet loss. The remote transmission interval will be multiplied + by this value to determine the connection loss detection timer. + format: int32 + maximum: 255 + minimum: 2 + type: integer + echoInterval: + description: |- + Configures the minimal echo receive transmission + interval that this system is capable of handling in milliseconds. + Defaults to 50ms + format: int32 + maximum: 60000 + minimum: 10 + type: integer + echoMode: + description: |- + Enables or disables the echo transmission mode. + This mode is disabled by default, and not supported on multi + hops setups. + type: boolean + minimumTtl: + description: |- + For multi hop sessions only: configure the minimum + expected TTL for an incoming BFD control packet. + format: int32 + maximum: 254 + minimum: 1 + type: integer + name: + description: |- + The name of the BFD Profile to be referenced in other parts + of the configuration. + type: string + passiveMode: + description: |- + Mark session as passive: a passive session will not + attempt to start the connection and will wait for control packets + from peer before it begins replying. + type: boolean + receiveInterval: + description: |- + The minimum interval that this system is capable of + receiving control packets in milliseconds. + Defaults to 300ms. + format: int32 + maximum: 60000 + minimum: 10 + type: integer + transmitInterval: + description: |- + The minimum transmission interval (less jitter) + that this system wants to use to send BFD control packets in + milliseconds. Defaults to 300ms + format: int32 + maximum: 60000 + minimum: 10 + type: integer + required: + - name + type: object + type: array + routers: + description: Routers is the list of routers we want FRR to configure + (one per VRF). + items: + description: Router represent a neighbor router we want FRR + to connect to. + properties: + asn: + description: ASN is the AS number to use for the local end + of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + id: + description: ID is the BGP router ID + type: string + imports: + description: Imports is the list of imported VRFs we want + for this router / vrf. + items: + description: Import represents the possible imported VRFs + to a given router. + properties: + vrf: + description: Vrf is the vrf we want to import from + type: string + type: object + type: array + neighbors: + description: Neighbors is the list of neighbors we want + to establish BGP sessions with. + items: + description: Neighbor represents a BGP Neighbor we want + FRR to connect to. + properties: + address: + description: Address is the IP address to establish + the session with. + type: string + asn: + description: ASN is the AS number to use for the local + end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + bfdProfile: + description: |- + BFDProfile is the name of the BFD Profile to be used for the BFD session associated + to the BGP session. If not set, the BFD session won't be set up. + type: string + connectTime: + description: Requested BGP connect time, controls + how long BGP waits between connection attempts to + a neighbor. + type: string + x-kubernetes-validations: + - message: connect time should be between 1 seconds + to 65535 + rule: duration(self).getSeconds() >= 1 && duration(self).getSeconds() + <= 65535 + - message: connect time should contain a whole number + of seconds + rule: duration(self).getMilliseconds() % 1000 == + 0 + disableMP: + default: false + description: To set if we want to disable MP BGP that + will separate IPv4 and IPv6 route exchanges into + distinct BGP sessions. + type: boolean + ebgpMultiHop: + description: EBGPMultiHop indicates if the BGPPeer + is multi-hops away. + type: boolean + enableGracefulRestart: + description: |- + EnableGracefulRestart allows BGP peer to continue to forward data packets along + known routes while the routing protocol information is being restored. If + the session is already established, the configuration will have effect + after reconnecting to the peer + type: boolean + holdTime: + description: |- + HoldTime is the requested BGP hold time, per RFC4271. + Defaults to 180s. + type: string + keepaliveTime: + description: |- + KeepaliveTime is the requested BGP keepalive time, per RFC4271. + Defaults to 60s. + type: string + password: + description: |- + Password to be used for establishing the BGP session. + Password and PasswordSecret are mutually exclusive. + type: string + passwordSecret: + description: |- + PasswordSecret is name of the authentication secret for the neighbor. + the secret must be of type "kubernetes.io/basic-auth", and created in the + same namespace as the frr-k8s daemon. The password is stored in the + secret as the key "password". + Password and PasswordSecret are mutually exclusive. + 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 + port: + description: |- + Port is the port to dial when establishing the session. + Defaults to 179. + maximum: 16384 + minimum: 0 + type: integer + sourceaddress: + description: |- + SourceAddress is the IPv4 or IPv6 source address to use for the BGP + session to this neighbour, may be specified as either an IP address + directly or as an interface name + type: string + toAdvertise: + description: |- + ToAdvertise represents the list of prefixes to advertise to the given neighbor + and the associated properties. + properties: + allowed: + description: |- + Allowed is is the list of prefixes allowed to be propagated to + this neighbor. They must match the prefixes defined in the router. + properties: + mode: + default: filtered + description: |- + Mode is the mode to use when handling the prefixes. + When set to "filtered", only the prefixes in the given list will be allowed. + When set to "all", all the prefixes configured on the router will be allowed. + enum: + - all + - filtered + type: string + prefixes: + items: + type: string + type: array + type: object + withCommunity: + description: |- + PrefixesWithCommunity is a list of prefixes that are associated to a + bgp community when being advertised. The prefixes associated to a given local pref + must be in the prefixes allowed to be advertised. + items: + description: CommunityPrefixes is a list of + prefixes associated to a community. + properties: + community: + description: Community is the community + associated to the prefixes. + type: string + prefixes: + description: Prefixes is the list of prefixes + associated to the community. + format: cidr + items: + type: string + minItems: 1 + type: array + type: object + type: array + withLocalPref: + description: |- + PrefixesWithLocalPref is a list of prefixes that are associated to a local + preference when being advertised. The prefixes associated to a given local pref + must be in the prefixes allowed to be advertised. + items: + description: LocalPrefPrefixes is a list of + prefixes associated to a local preference. + properties: + localPref: + description: LocalPref is the local preference + associated to the prefixes. + format: int32 + type: integer + prefixes: + description: Prefixes is the list of prefixes + associated to the local preference. + format: cidr + items: + type: string + minItems: 1 + type: array + type: object + type: array + type: object + toReceive: + description: ToReceive represents the list of prefixes + to receive from the given neighbor. + properties: + allowed: + description: |- + Allowed is the list of prefixes allowed to be received from + this neighbor. + properties: + mode: + default: filtered + description: |- + Mode is the mode to use when handling the prefixes. + When set to "filtered", only the prefixes in the given list will be allowed. + When set to "all", all the prefixes configured on the router will be allowed. + enum: + - all + - filtered + type: string + prefixes: + items: + description: PrefixSelector is a filter + of prefixes to receive. + properties: + ge: + description: |- + The prefix length modifier. This selector accepts any matching prefix with length + greater or equal the given value. + format: int32 + maximum: 128 + minimum: 1 + type: integer + le: + description: |- + The prefix length modifier. This selector accepts any matching prefix with length + less or equal the given value. + format: int32 + maximum: 128 + minimum: 1 + type: integer + prefix: + format: cidr + type: string + type: object + type: array + type: object + type: object + required: + - address + - asn + type: object + type: array + prefixes: + description: Prefixes is the list of prefixes we want to + advertise from this router instance. + items: + type: string + type: array + vrf: + description: VRF is the host vrf used to establish sessions + from this router. + type: string + required: + - asn + type: object + type: array + type: object + nodeSelector: + description: |- + NodeSelector limits the nodes that will attempt to apply this config. + When specified, the configuration will be considered only on nodes + whose labels match the specified selectors. + When it is not specified all nodes will attempt to apply this config. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + raw: + description: |- + Raw is a snippet of raw frr configuration that gets appended to the + one rendered translating the type safe API. + properties: + priority: + description: |- + Priority is the order with this configuration is appended to the + bottom of the rendered configuration. A higher value means the + raw config is appended later in the configuration file. + type: integer + rawConfig: + description: |- + Config is a raw FRR configuration to be appended to the configuration + rendered via the k8s api. + type: string + type: object + type: object + status: + description: FRRConfigurationStatus defines the observed state of FRRConfiguration. + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/metallb-chart/charts/frr-k8s/crds/frrk8s.metallb.io_frrnodestates.yaml b/metallb-chart/charts/frr-k8s/crds/frrk8s.metallb.io_frrnodestates.yaml new file mode 100644 index 0000000..66f4196 --- /dev/null +++ b/metallb-chart/charts/frr-k8s/crds/frrk8s.metallb.io_frrnodestates.yaml @@ -0,0 +1,65 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: frrnodestates.frrk8s.metallb.io +spec: + group: frrk8s.metallb.io + names: + kind: FRRNodeState + listKind: FRRNodeStateList + plural: frrnodestates + singular: frrnodestate + scope: Cluster + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: FRRNodeState exposes the status of the FRR instance running on + each node. + 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: FRRNodeStateSpec defines the desired state of FRRNodeState. + type: object + status: + description: FRRNodeStateStatus defines the observed state of FRRNodeState. + properties: + lastConversionResult: + description: LastConversionResult is the status of the last translation + between the `FRRConfiguration`s resources and FRR's configuration, + contains "success" or an error. + type: string + lastReloadResult: + description: LastReloadResult represents the status of the last configuration + update operation by FRR, contains "success" or an error. + type: string + runningConfig: + description: RunningConfig represents the current FRR running config, + which is the configuration the FRR instance is currently running + with. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/metallb-chart/charts/frr-k8s/templates/NOTES.txt b/metallb-chart/charts/frr-k8s/templates/NOTES.txt new file mode 100644 index 0000000..813ab8a --- /dev/null +++ b/metallb-chart/charts/frr-k8s/templates/NOTES.txt @@ -0,0 +1,4 @@ +FRR-k8s is now running in the cluster. + +Now you can configure it via its CRs. Please refer to the frr-k8s official docs +on how to use the CRs. diff --git a/metallb-chart/charts/frr-k8s/templates/_helpers.tpl b/metallb-chart/charts/frr-k8s/templates/_helpers.tpl new file mode 100644 index 0000000..8b728d2 --- /dev/null +++ b/metallb-chart/charts/frr-k8s/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "frrk8s.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 "frrk8s.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 "frrk8s.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "frrk8s.labels" -}} +helm.sh/chart: {{ include "frrk8s.chart" . }} +{{ include "frrk8s.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "frrk8s.selectorLabels" -}} +app.kubernetes.io/name: {{ include "frrk8s.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the frrk8s service account to use +*/}} +{{- define "frrk8s.serviceAccountName" -}} +{{- if .Values.frrk8s.serviceAccount.create }} +{{- default (printf "%s-controller" (include "frrk8s.fullname" .)) .Values.frrk8s.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.frrk8s.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/metallb-chart/charts/frr-k8s/templates/controller.yaml b/metallb-chart/charts/frr-k8s/templates/controller.yaml new file mode 100644 index 0000000..50badde --- /dev/null +++ b/metallb-chart/charts/frr-k8s/templates/controller.yaml @@ -0,0 +1,431 @@ +# FRR expects to have these files owned by frr:frr on startup. +# Having them in a ConfigMap allows us to modify behaviors: for example enabling more daemons on startup. +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "frrk8s.fullname" . }}-frr-startup + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "frrk8s.labels" . | nindent 4 }} + app.kubernetes.io/component: frr-k8s +data: + daemons: | + # This file tells the frr package which daemons to start. + # + # Sample configurations for these daemons can be found in + # /usr/share/doc/frr/examples/. + # + # ATTENTION: + # + # When activating a daemon for the first time, a config file, even if it is + # empty, has to be present *and* be owned by the user and group "frr", else + # the daemon will not be started by /etc/init.d/frr. The permissions should + # be u=rw,g=r,o=. + # When using "vtysh" such a config file is also needed. It should be owned by + # group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. + # + # The watchfrr and zebra daemons are always started. + # + bgpd=yes + ospfd=no + ospf6d=no + ripd=no + ripngd=no + isisd=no + pimd=no + ldpd=no + nhrpd=no + eigrpd=no + babeld=no + sharpd=no + pbrd=no + bfdd=yes + fabricd=no + vrrpd=no + + # + # If this option is set the /etc/init.d/frr script automatically loads + # the config via "vtysh -b" when the servers are started. + # Check /etc/pam.d/frr if you intend to use "vtysh"! + # + vtysh_enable=yes + zebra_options=" -A 127.0.0.1 -s 90000000" + bgpd_options=" -A 127.0.0.1" + ospfd_options=" -A 127.0.0.1" + ospf6d_options=" -A ::1" + ripd_options=" -A 127.0.0.1" + ripngd_options=" -A ::1" + isisd_options=" -A 127.0.0.1" + pimd_options=" -A 127.0.0.1" + ldpd_options=" -A 127.0.0.1" + nhrpd_options=" -A 127.0.0.1" + eigrpd_options=" -A 127.0.0.1" + babeld_options=" -A 127.0.0.1" + sharpd_options=" -A 127.0.0.1" + pbrd_options=" -A 127.0.0.1" + staticd_options="-A 127.0.0.1" + bfdd_options=" -A 127.0.0.1" + fabricd_options="-A 127.0.0.1" + vrrpd_options=" -A 127.0.0.1" + + # configuration profile + # + #frr_profile="traditional" + #frr_profile="datacenter" + + # + # This is the maximum number of FD's that will be available. + # Upon startup this is read by the control files and ulimit + # is called. Uncomment and use a reasonable value for your + # setup if you are expecting a large number of peers in + # say BGP. + #MAX_FDS=1024 + + # The list of daemons to watch is automatically generated by the init script. + #watchfrr_options="" + + # for debugging purposes, you can specify a "wrap" command to start instead + # of starting the daemon directly, e.g. to use valgrind on ospfd: + # ospfd_wrap="/usr/bin/valgrind" + # or you can use "all_wrap" for all daemons, e.g. to use perf record: + # all_wrap="/usr/bin/perf record --call-graph -" + # the normal daemon command is added to this at the end. + vtysh.conf: |+ + service integrated-vtysh-config + frr.conf: |+ + ! This file gets overriden the first time the speaker renders a config. + ! So anything configured here is only temporary. + frr version 8.0 + frr defaults traditional + hostname Router + line vty + log file /etc/frr/frr.log informational +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ template "frrk8s.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "frrk8s.labels" . | nindent 4 }} + app.kubernetes.io/component: frr-k8s + {{- range $key, $value := .Values.frrk8s.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + {{- if .Values.frrk8s.updateStrategy }} + updateStrategy: {{- toYaml .Values.frrk8s.updateStrategy | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "frrk8s.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: frr-k8s + template: + metadata: + labels: + {{- include "frrk8s.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: frr-k8s + {{- range $key, $value := .Values.frrk8s.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + {{- if .Values.frrk8s.runtimeClassName }} + runtimeClassName: {{ .Values.frrk8s.runtimeClassName }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ template "frrk8s.serviceAccountName" . }} + terminationGracePeriodSeconds: 0 + hostNetwork: true + volumes: + - name: frr-sockets + emptyDir: {} + - name: frr-startup + configMap: + name: {{ template "frrk8s.fullname" . }}-frr-startup + - name: frr-conf + emptyDir: {} + - name: reloader + emptyDir: {} + - name: metrics + emptyDir: {} + {{- if .Values.prometheus.metricsTLSSecret }} + - name: metrics-certs + secret: + secretName: {{ .Values.prometheus.metricsTLSSecret }} + {{- end }} + initContainers: + # Copies the initial config files with the right permissions to the shared volume. + - name: cp-frr-files + image: {{ .Values.frrk8s.frr.image.repository }}:{{ .Values.frrk8s.frr.image.tag | default .Chart.AppVersion }} + securityContext: + runAsUser: 100 + runAsGroup: 101 + command: ["/bin/sh", "-c", "cp -rLf /tmp/frr/* /etc/frr/"] + volumeMounts: + - name: frr-startup + mountPath: /tmp/frr + - name: frr-conf + mountPath: /etc/frr + # Copies the reloader to the shared volume between the speaker and reloader. + - name: cp-reloader + image: {{ .Values.frrk8s.image.repository }}:{{ .Values.frrk8s.image.tag | default .Chart.AppVersion }} + command: ["/bin/sh", "-c", "cp -f /frr-reloader.sh /etc/frr_reloader/"] + volumeMounts: + - name: reloader + mountPath: /etc/frr_reloader + # Copies the metrics exporter + - name: cp-metrics + image: {{ .Values.frrk8s.image.repository }}:{{ .Values.frrk8s.image.tag | default .Chart.AppVersion }} + command: ["/bin/sh", "-c", "cp -f /frr-metrics /etc/frr_metrics/"] + volumeMounts: + - name: metrics + mountPath: /etc/frr_metrics + shareProcessNamespace: true + containers: + - name: controller + image: {{ .Values.frrk8s.image.repository }}:{{ .Values.frrk8s.image.tag | default .Chart.AppVersion }} + {{- if .Values.frrk8s.image.pullPolicy }} + imagePullPolicy: {{ .Values.frrk8s.image.pullPolicy }} + {{- end }} + command: + - /frr-k8s + args: + - "--node-name=$(NODE_NAME)" + - "--namespace=$(NAMESPACE)" + - "--metrics-bind-address={{.Values.prometheus.metricsBindAddress}}:{{ .Values.prometheus.metricsPort }}" + {{- with .Values.frrk8s.logLevel }} + - --log-level={{ . }} + {{- end }} + - --health-probe-bind-address={{.Values.prometheus.metricsBindAddress}}:{{ .Values.frrk8s.healthPort }} + {{- if .Values.frrk8s.alwaysBlock }} + - --always-block={{ .Values.frrk8s.alwaysBlock }} + {{- end }} + env: + - name: FRR_CONFIG_FILE + value: /etc/frr_reloader/frr.conf + - name: FRR_RELOADER_PID_FILE + value: /etc/frr_reloader/reloader.pid + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + ports: + - containerPort: {{ .Values.prometheus.metricsPort }} + name: monitoring + {{- if .Values.frrk8s.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /healthz + port: {{ .Values.frrk8s.healthPort }} + host: {{ .Values.prometheus.metricsBindAddress }} + initialDelaySeconds: {{ .Values.frrk8s.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.frrk8s.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.frrk8s.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.frrk8s.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.frrk8s.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.frrk8s.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /healthz + port: {{ .Values.frrk8s.healthPort }} + host: {{ .Values.prometheus.metricsBindAddress }} + initialDelaySeconds: {{ .Values.frrk8s.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.frrk8s.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.frrk8s.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.frrk8s.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.frrk8s.readinessProbe.failureThreshold }} + {{- end }} + {{- with .Values.frrk8s.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + add: + - NET_RAW + volumeMounts: + - name: reloader + mountPath: /etc/frr_reloader + - name: frr + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_ADMIN + - NET_BIND_SERVICE + image: {{ .Values.frrk8s.frr.image.repository }}:{{ .Values.frrk8s.frr.image.tag | default .Chart.AppVersion }} + {{- if .Values.frrk8s.frr.image.pullPolicy }} + imagePullPolicy: {{ .Values.frrk8s.frr.image.pullPolicy }} + {{- end }} + env: + - name: TINI_SUBREAPER + value: "true" + volumeMounts: + - name: frr-sockets + mountPath: /var/run/frr + - name: frr-conf + mountPath: /etc/frr + # The command is FRR's default entrypoint & waiting for the log file to appear and tailing it. + # If the log file isn't created in 60 seconds the tail fails and the container is restarted. + # This workaround is needed to have the frr logs as part of kubectl logs -c frr < controller_pod_name >. + command: + - /bin/sh + - -c + - | + /sbin/tini -- /usr/lib/frr/docker-start & + attempts=0 + until [[ -f /etc/frr/frr.log || $attempts -eq 60 ]]; do + sleep 1 + attempts=$(( $attempts + 1 )) + done + tail -f /etc/frr/frr.log + {{- with .Values.frrk8s.frr.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.frrk8s.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /livez + port: {{ .Values.frrk8s.frr.metricsPort }} + host: {{ .Values.frrk8s.frr.metricsBindAddress }} + periodSeconds: {{ .Values.frrk8s.livenessProbe.periodSeconds }} + failureThreshold: {{ .Values.frrk8s.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.frrk8s.startupProbe.enabled }} + startupProbe: + httpGet: + path: /livez + port: {{ .Values.frrk8s.frr.metricsPort }} + host: {{ .Values.frrk8s.frr.metricsBindAddress }} + failureThreshold: {{ .Values.frrk8s.startupProbe.failureThreshold }} + periodSeconds: {{ .Values.frrk8s.startupProbe.periodSeconds }} + {{- end }} + - name: reloader + image: {{ .Values.frrk8s.frr.image.repository }}:{{ .Values.frrk8s.frr.image.tag | default .Chart.AppVersion }} + {{- if .Values.frrk8s.frr.image.pullPolicy }} + imagePullPolicy: {{ .Values.frrk8s.frr.image.pullPolicy }} + {{- end }} + command: ["/etc/frr_reloader/frr-reloader.sh"] + volumeMounts: + - name: frr-sockets + mountPath: /var/run/frr + - name: frr-conf + mountPath: /etc/frr + - name: reloader + mountPath: /etc/frr_reloader + {{- with .Values.frrk8s.reloader.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + - name: frr-metrics + image: {{ .Values.frrk8s.frr.image.repository }}:{{ .Values.frrk8s.frr.image.tag | default .Chart.AppVersion }} + command: ["/etc/frr_metrics/frr-metrics"] + args: + - --metrics-port={{ .Values.frrk8s.frr.metricsPort }} + - --metrics-bind-address={{ .Values.frrk8s.frr.metricsBindAddress }} + ports: + - containerPort: {{ .Values.frrk8s.frr.metricsPort }} + name: monitoring + volumeMounts: + - name: frr-sockets + mountPath: /var/run/frr + - name: frr-conf + mountPath: /etc/frr + - name: metrics + mountPath: /etc/frr_metrics + {{- with .Values.frrk8s.frrMetrics.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + - name: kube-rbac-proxy + image: {{ .Values.prometheus.rbacProxy.repository }}:{{ .Values.prometheus.rbacProxy.tag }} + imagePullPolicy: {{ .Values.prometheus.rbacProxy.pullPolicy }} + args: + - --logtostderr + - --secure-listen-address=:{{ .Values.prometheus.secureMetricsPort }} + - --upstream=http://{{.Values.prometheus.metricsBindAddress}}:{{ .Values.prometheus.metricsPort }}/ + - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + {{- if .Values.prometheus.metricsTLSSecret }} + - --tls-private-key-file=/etc/metrics/tls.key + - --tls-cert-file=/etc/metrics/tls.crt + {{- end }} + ports: + - containerPort: {{ .Values.prometheus.secureMetricsPort }} + name: metricshttps + resources: + requests: + cpu: 10m + memory: 20Mi + terminationMessagePolicy: FallbackToLogsOnError + {{- if .Values.prometheus.metricsTLSSecret }} + volumeMounts: + - name: metrics-certs + mountPath: /etc/metrics + readOnly: true + {{- end }} + - name: kube-rbac-proxy-frr + image: {{ .Values.prometheus.rbacProxy.repository }}:{{ .Values.prometheus.rbacProxy.tag | default .Chart.AppVersion }} + imagePullPolicy: {{ .Values.prometheus.rbacProxy.pullPolicy }} + args: + - --logtostderr + - --secure-listen-address=:{{ .Values.frrk8s.frr.secureMetricsPort }} + - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + - --upstream=http://{{ .Values.frrk8s.frr.metricsBindAddress }}:{{ .Values.frrk8s.frr.metricsPort }}/ + {{- if .Values.prometheus.metricsTLSSecret }} + - --tls-private-key-file=/etc/metrics/tls.key + - --tls-cert-file=/etc/metrics/tls.crt + {{- end }} + ports: + - containerPort: {{ .Values.frrk8s.frr.secureMetricsPort }} + name: metricshttps + resources: + requests: + cpu: 10m + memory: 20Mi + terminationMessagePolicy: FallbackToLogsOnError + {{- if .Values.prometheus.metricsTLSSecret }} + volumeMounts: + - name: metrics-certs + mountPath: /etc/metrics + readOnly: true + {{- end }} + nodeSelector: + "kubernetes.io/os": linux + {{- with .Values.frrk8s.nodeSelector }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.frrk8s.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.frrk8s.tolerateMaster .Values.frrk8s.tolerations }} + tolerations: + {{- if .Values.frrk8s.tolerateMaster }} + - key: node-role.kubernetes.io/master + effect: NoSchedule + operator: Exists + - key: node-role.kubernetes.io/control-plane + effect: NoSchedule + operator: Exists + {{- end }} + {{- with .Values.frrk8s.tolerations }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} + {{- with .Values.frrk8s.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} diff --git a/metallb-chart/charts/frr-k8s/templates/rbac.yaml b/metallb-chart/charts/frr-k8s/templates/rbac.yaml new file mode 100644 index 0000000..5c0b9d6 --- /dev/null +++ b/metallb-chart/charts/frr-k8s/templates/rbac.yaml @@ -0,0 +1,73 @@ +{{- if .Values.rbac.create -}} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "frrk8s.fullname" . }}-controller + labels: {{- include "frrk8s.labels" . | nindent 4 }} +rules: +- apiGroups: ["frrk8s.metallb.io"] + resources: ["frrconfigurations"] + verbs: ["get", "list", "watch"] +- apiGroups: ["frrk8s.metallb.io"] + resources: ["frrnodestates"] + verbs: ["get", "list", "watch", "create", "delete", "patch", "update"] +- apiGroups: ["frrk8s.metallb.io"] + resources: ["frrnodestates/status"] + verbs: ["get", "patch", "update"] +- apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: ["subjectaccessreviews"] + verbs: ["create"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get", "list", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resourceNames: ["frr-k8s-validating-webhook-configuration"] + resources: ["validatingwebhookconfigurations"] + verbs: ["update"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "frrk8s.fullname" . }}-controller + labels: {{- include "frrk8s.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "frrk8s.fullname" . }}-controller +subjects: +- kind: ServiceAccount + name: {{ include "frrk8s.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "frrk8s.fullname" . }}-controller + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "frrk8s.labels" . | nindent 4 }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list", "watch","update"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "frrk8s.fullname" . }}-controller + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "frrk8s.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "frrk8s.fullname" . }}-controller +subjects: +- kind: ServiceAccount + name: {{ include "frrk8s.serviceAccountName" . }} +{{ end -}} diff --git a/metallb-chart/charts/frr-k8s/templates/service-accounts.yaml b/metallb-chart/charts/frr-k8s/templates/service-accounts.yaml new file mode 100644 index 0000000..c3d7423 --- /dev/null +++ b/metallb-chart/charts/frr-k8s/templates/service-accounts.yaml @@ -0,0 +1,16 @@ +{{- if .Values.frrk8s.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "frrk8s.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "frrk8s.labels" . | nindent 4 }} + app.kubernetes.io/component: controller + {{- with .Values.frrk8s.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} + diff --git a/metallb-chart/charts/frr-k8s/templates/service-monitor.yaml b/metallb-chart/charts/frr-k8s/templates/service-monitor.yaml new file mode 100644 index 0000000..323c442 --- /dev/null +++ b/metallb-chart/charts/frr-k8s/templates/service-monitor.yaml @@ -0,0 +1,128 @@ +{{- if .Values.prometheus.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "frrk8s.fullname" . }}-frr-k8s-monitor + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "frrk8s.labels" . | nindent 4 }} + app.kubernetes.io/component: frr-k8s + {{- if .Values.prometheus.serviceMonitor.additionalLabels }} +{{ toYaml .Values.prometheus.serviceMonitor.additionalLabels | indent 4 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.annotations }} + annotations: +{{ toYaml .Values.prometheus.serviceMonitor.annotations | indent 4 }} + {{- end }} +spec: + endpoints: + - port: "metricshttps" + honorLabels: true + {{- if .Values.prometheus.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.prometheus.serviceMonitor.metricRelabelings | nindent 8 }} + {{- end -}} + {{- if .Values.prometheus.serviceMonitor.relabelings }} + relabelings: + {{- toYaml .Values.prometheus.serviceMonitor.relabelings | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.interval }} + interval: {{ .Values.prometheus.serviceMonitor.interval }} + {{- end -}} +{{ if .Values.prometheus.secureMetricsPort }} + bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token" + scheme: "https" +{{- if .Values.prometheus.serviceMonitor.tlsConfig }} + tlsConfig: +{{ toYaml .Values.prometheus.serviceMonitor.tlsConfig | indent 8 }} +{{- end }} +{{ end }} +{{ if .Values.frrk8s.frr.secureMetricsPort }} + - port: "frrmetricshttps" + honorLabels: true + {{- if .Values.prometheus.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.prometheus.serviceMonitor.metricRelabelings | nindent 8 }} + {{- end -}} + {{- if .Values.prometheus.serviceMonitor.relabelings }} + relabelings: + {{- toYaml .Values.prometheus.serviceMonitor.relabelings | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.interval }} + interval: {{ .Values.prometheus.serviceMonitor.interval }} + {{- end }} + bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token" + scheme: "https" +{{- if .Values.prometheus.serviceMonitor.tlsConfig }} + tlsConfig: +{{ toYaml .Values.prometheus.serviceMonitor.tlsConfig | indent 8 }} +{{- end }} +{{- end }} + jobLabel: {{ .Values.prometheus.serviceMonitor.jobLabel | quote }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + name: {{ template "frrk8s.fullname" . }}-frr-k8s-monitor-service +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/scrape: "true" + {{- if .Values.prometheus.serviceMonitor.annotations }} +{{ toYaml .Values.prometheus.serviceMonitor.annotations | indent 4 }} + {{- end }} + labels: + name: {{ template "frrk8s.fullname" . }}-frr-k8s-monitor-service + name: {{ template "frrk8s.fullname" . }}-frr-k8s-monitor-service + namespace: {{ .Release.Namespace | quote }} +spec: + selector: + {{- include "frrk8s.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: frr-k8s + clusterIP: None + ports: + - name: "metricshttps" + port: {{ .Values.prometheus.secureMetricsPort }} + targetPort: {{ .Values.prometheus.secureMetricsPort }} + - name: frrmetricshttps + port: {{ .Values.frrk8s.frr.secureMetricsPort }} + targetPort: {{ .Values.frrk8s.frr.secureMetricsPort }} + sessionAffinity: None + type: ClusterIP +--- +{{- if .Values.prometheus.rbacPrometheus }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "frrk8s.fullname" . }}-prometheus + namespace: {{ .Release.Namespace | quote }} +rules: + - apiGroups: + - "" + resources: + - pods + - services + - endpoints + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "frrk8s.fullname" . }}-prometheus + namespace: {{ .Release.Namespace | quote }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "frrk8s.fullname" . }}-prometheus +subjects: + - kind: ServiceAccount + name: {{ required ".Values.prometheus.serviceAccount must be defined when .Values.prometheus.serviceMonitor.enabled == true" .Values.prometheus.serviceAccount }} + namespace: {{ required ".Values.prometheus.namespace must be defined when .Values.prometheus.serviceMonitor.enabled == true" .Values.prometheus.namespace }} +{{- end }} +{{- end }} diff --git a/metallb-chart/charts/frr-k8s/templates/webhooks.yaml b/metallb-chart/charts/frr-k8s/templates/webhooks.yaml new file mode 100644 index 0000000..a84b3b6 --- /dev/null +++ b/metallb-chart/charts/frr-k8s/templates/webhooks.yaml @@ -0,0 +1,163 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "frrk8s.fullname" . }}-webhook-server + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "frrk8s.labels" . | nindent 4 }} + app.kubernetes.io/component: frr-k8s-webhook-server + {{- range $key, $value := .Values.frrk8s.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/component: frr-k8s-webhook-server + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: frr-k8s-webhook-server + labels: + app.kubernetes.io/component: frr-k8s-webhook-server + spec: + {{- if .Values.frrk8s.runtimeClassName }} + runtimeClassName: {{ .Values.frrk8s.runtimeClassName }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.podSecurityContext }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- end }} + containers: + - command: + - /frr-k8s + args: + {{- with .Values.frrk8s.logLevel }} + - --log-level={{ . }} + {{- end }} + - "--webhook-mode=onlywebhook" + {{- if .Values.frrk8s.disableCertRotation }} + - "--disable-cert-rotation=true" + {{- end }} + {{- if .Values.frrk8s.restartOnRotatorSecretRefresh }} + - "--restart-on-rotator-secret-refresh=true" + {{- end }} + - "--namespace=$(NAMESPACE)" + - --health-probe-bind-address=:8081 + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + image: {{ .Values.frrk8s.image.repository }}:{{ .Values.frrk8s.image.tag | default .Chart.AppVersion }} + {{- if .Values.frrk8s.image.pullPolicy }} + imagePullPolicy: {{ .Values.frrk8s.image.pullPolicy }} + {{- end }} + name: frr-k8s-webhook-server + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + {{- if .Values.frrk8s.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: {{ .Values.frrk8s.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.frrk8s.livenessProbe.periodSeconds }} + failureThreshold: {{ .Values.frrk8s.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.frrk8s.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: {{ .Values.frrk8s.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.frrk8s.readinessProbe.periodSeconds }} + failureThreshold: {{ .Values.frrk8s.readinessProbe.failureThreshold }} + {{- end }} + {{- with .Values.frrk8s.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + volumeMounts: + - name: cert + mountPath: /tmp/k8s-webhook-server/serving-certs + readOnly: true + {{- with .Values.frrk8s.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.frrk8s.tolerateMaster .Values.frrk8s.tolerations }} + tolerations: + {{- if .Values.frrk8s.tolerateMaster }} + - key: node-role.kubernetes.io/master + effect: NoSchedule + operator: Exists + - key: node-role.kubernetes.io/control-plane + effect: NoSchedule + operator: Exists + {{- end }} + {{- with .Values.frrk8s.tolerations }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} + {{- with .Values.frrk8s.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: frr-k8s-webhook-server-cert + serviceAccountName: {{ template "frrk8s.serviceAccountName" . }} + terminationGracePeriodSeconds: 10 +--- +apiVersion: v1 +kind: Secret +metadata: + name: frr-k8s-webhook-server-cert + namespace: {{ .Release.Namespace | quote }} +--- +apiVersion: v1 +kind: Service +metadata: + name: frr-k8s-webhook-service + namespace: {{ .Release.Namespace | quote }} +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + app.kubernetes.io/component: frr-k8s-webhook-server +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: frr-k8s-validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: frr-k8s-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-frrk8s-metallb-io-v1beta1-frrconfiguration + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: frrconfigurationsvalidationwebhook.metallb.io + rules: + - apiGroups: + - frrk8s.metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - frrconfigurations + sideEffects: None diff --git a/metallb-chart/charts/frr-k8s/values.schema.json b/metallb-chart/charts/frr-k8s/values.schema.json new file mode 100644 index 0000000..67ec727 --- /dev/null +++ b/metallb-chart/charts/frr-k8s/values.schema.json @@ -0,0 +1,387 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "title": "Values", + "type": "object", + "definitions": { + "prometheusAlert": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "enabled" + ] + }, + "probe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + }, + "required": [ + "failureThreshold", + "initialDelaySeconds", + "periodSeconds", + "successThreshold", + "timeoutSeconds" + ] + }, + "component": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "logLevel": { + "type": "string", + "enum": [ + "all", + "debug", + "info", + "warn", + "error", + "none" + ] + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "pullPolicy": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + ] + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "annotations": { + "type": "object" + } + } + }, + "resources": { + "type": "object" + }, + "nodeSelector": { + "type": "object" + }, + "tolerations": { + "type": "array", + "items": { + "type": "object" + } + }, + "priorityClassName": { + "type": "string" + }, + "runtimeClassName": { + "type": "string" + }, + "affinity": { + "type": "object" + }, + "podAnnotations": { + "type": "object" + }, + "livenessProbe": { + "$ref": "#/definitions/probe" + }, + "readinessProbe": { + "$ref": "#/definitions/probe" + } + }, + "required": [ + "image", + "serviceAccount" + ] + } + }, + "properties": { + "imagePullSecrets": { + "description": "Secrets used for pulling images", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "nameOverride": { + "description": "Override chart name", + "type": "string" + }, + "fullNameOverride": { + "description": "Override fully qualified app name", + "type": "string" + }, + "rbac": { + "description": "RBAC configuration", + "type": "object", + "properties": { + "create": { + "description": "Enable RBAC", + "type": "boolean" + } + } + }, + "prometheus": { + "description": "Prometheus monitoring config", + "type": "object", + "properties": { + "scrapeAnnotations": { + "type": "boolean" + }, + "metricsPort": { + "type": "integer" + }, + "secureMetricsPort": { + "type": "integer" + }, + "rbacPrometheus": { + "type": "boolean" + }, + "serviceAccount": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "rbacProxy": { + "description": "kube-rbac-proxy configuration", + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "serviceMonitor": { + "description": "Prometheus Operator ServiceMonitors", + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "jobLabel": { + "type": "string" + }, + "interval": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "metricRelabelings": { + "type": "array", + "items": { + "type": "object" + } + }, + "relabelings": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + }, + "frrk8s": { + "allOf": [ + { + "$ref": "#/definitions/component" + }, + { + "description": "FRR-K8s controller", + "type": "object", + "properties": { + "tolerateMaster": { + "type": "boolean" + }, + "updateStrategy": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ] + }, + "runtimeClassName": { + "type": "string" + }, + "secretName": { + "type": "string" + }, + "frr": { + "description": "The FRR properties in the controller", + "type": "object", + "properties": { + "image": { + "$ref": "#/definitions/component/properties/image" + }, + "metricsPort": { + "type": "integer" + }, + "secureMetricsPort": { + "type": "integer" + }, + "resources:": { + "type": "object" + } + }, + "required": [ + "enabled" + ] + }, + "command": { + "type": "string" + }, + "reloader": { + "type": "object", + "properties": { + "resources": { + "type": "object" + } + } + }, + "frrMetrics": { + "type": "object", + "properties": { + "resources": { + "type": "object" + } + } + } + }, + "required": [ + "tolerateMaster" + ] + } + ] + }, + "crds": { + "description": "CRD configuration", + "type": "object", + "properties": { + "enabled": { + "description": "Enable CRDs", + "type": "boolean" + }, + "validationFailurePolicy": { + "description": "Failure policy to use with validating webhooks", + "type": "string", + "enum": [ + "Ignore", + "Fail" + ] + } + } + } + }, + "frrk8s": { + "allOf": [ + { + "$ref": "#/definitions/component" + }, + { + "description": "FRRk8s Controller", + "type": "object", + "properties": { + "strategy": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ] + }, + "command": { + "type": "string" + }, + "webhookMode": { + "type": "string" + } + } + } + ] + } + }, + "required": [ + "frrk8s" + ] +} \ No newline at end of file diff --git a/metallb-chart/charts/frr-k8s/values.yaml b/metallb-chart/charts/frr-k8s/values.yaml new file mode 100644 index 0000000..87731fe --- /dev/null +++ b/metallb-chart/charts/frr-k8s/values.yaml @@ -0,0 +1,176 @@ +# Default values for frr-k8s. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +nameOverride: "" +fullnameOverride: "" + +rbac: + # create specifies whether to install and use RBAC rules. + create: true + +podSecurityContext: + seccompProfile: + type: RuntimeDefault + +prometheus: + # scrape annotations specifies whether to add Prometheus metric + # auto-collection annotations to pods. See + # https://github.com/prometheus/prometheus/blob/release-2.1/documentation/examples/prometheus-kubernetes.yml + # for a corresponding Prometheus configuration. Alternatively, you + # may want to use the Prometheus Operator + # (https://github.com/coreos/prometheus-operator) for more powerful + # monitoring configuration. If you use the Prometheus operator, this + # can be left at false. + scrapeAnnotations: false + + # bind addr frr-k8s will use for metrics + metricsBindAddress: 127.0.0.1 + + # port frr-k8s will listen on for metrics + metricsPort: 7572 + + # if set, enables rbac proxy on frr-k8s to expose + # the metrics via tls. + secureMetricsPort: 9140 + + # the name of the secret to be mounted in the frr-k8s pod + # to expose the metrics securely. If not present, a self signed + # certificate to be used. + metricsTLSSecret: "" + + # prometheus doens't have the permission to scrape all namespaces so we give it permission to scrape metallb's one + rbacPrometheus: false + + # the service account used by prometheus + # required when " .Values.prometheus.rbacPrometheus == true " and " prometheus.serviceMonitor.enabled=true " + serviceAccount: "" + + # the namespace where prometheus is deployed + # required when " .Values.prometheus.rbacPrometheus == true " and " prometheus.serviceMonitor.enabled=true " + namespace: "" + + # the image to be used for the kuberbacproxy container + rbacProxy: + repository: "registry.opensuse.org/isv/suse/edge/metallb/images/kube-rbac-proxy" + tag: "v0.18.0" + pullPolicy: IfNotPresent + + # Prometheus Operator ServiceMonitors. + serviceMonitor: + # enable support for Prometheus Operator + enabled: false + + additionalLabels: {} + # optional additional annotations for the controller serviceMonitor + annotations: {} + # optional tls configuration for the controller serviceMonitor, in case + # secure metrics are enabled. + tlsConfig: + insecureSkipVerify: true + + # Job label for scrape target + jobLabel: "app.kubernetes.io/name" + + # Scrape interval. If not set, the Prometheus default scrape interval is used. + interval: + + # metric relabel configs to apply to samples before ingestion. + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + # relabel configs to apply to samples before ingestion. + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # target_label: nodename + # replacement: $1 + # action: replace + +# controller contains configuration specific to the FRRK8s controller +# daemonset. +frrk8s: + # -- Controller log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` + logLevel: info + tolerateMaster: true + image: + repository: "registry.opensuse.org/isv/suse/edge/metallb/images/frr-k8s" + tag: "v0.0.14" + pullPolicy: IfNotPresent + ## @param controller.updateStrategy.type FRR-K8s controller daemonset strategy type + ## ref: https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/ + ## + updateStrategy: + ## StrategyType + ## Can be set to RollingUpdate or OnDelete + ## + type: RollingUpdate + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. If not set and create is + # true, a name is generated using the fullname template + name: "" + annotations: {} + ## Defines a secret name for the controller to generate a memberlist encryption secret + ## By default secretName: {{ "metallb.fullname" }}-memberlist + ## + # secretName: + resources: {} + # limits: + # cpu: 100m + # memory: 100Mi + nodeSelector: {} + tolerations: [] + priorityClassName: "" + affinity: {} + ## Selects which runtime class will be used by the pod. + runtimeClassName: "" + podAnnotations: {} + labels: + app: frr-k8s + healthPort: 8081 + livenessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + startupProbe: + enabled: true + failureThreshold: 30 + periodSeconds: 5 + ## A comma separated list of cidrs we want always to block for incoming routes + alwaysBlock: "" + ## Specifies whether the cert rotator works as part of the webhook. + disableCertRotation: false + ## Specifies whether the pod restarts when the rotator refreshes the cert secret. + ## Enabling this proved useful for the webhook's stability when it is redeployed multiple times in succession. + restartOnRotatorSecretRefresh: false + # frr contains configuration specific to the FRR container, + frr: + image: + repository: "registry.opensuse.org/isv/suse/edge/metallb/images/frr" + tag: "8.4" + pullPolicy: IfNotPresent + metricsBindAddress: 127.0.0.1 + metricsPort: 7573 + resources: {} + secureMetricsPort: 9141 + reloader: + resources: {} + frrMetrics: + resources: {} +crds: + validationFailurePolicy: Fail diff --git a/metallb-chart/charts/metallb-crds/.helmignore b/metallb-chart/charts/metallb-crds/.helmignore new file mode 100644 index 0000000..1b9a9cc --- /dev/null +++ b/metallb-chart/charts/metallb-crds/.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/metallb-chart/charts/metallb-crds/Chart.yaml b/metallb-chart/charts/metallb-crds/Chart.yaml new file mode 100644 index 0000000..6d070fc --- /dev/null +++ b/metallb-chart/charts/metallb-crds/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +appVersion: v0.14.9 +description: MetalLB CRDs +home: https://metallb.universe.tf +icon: https://metallb.universe.tf/images/logo/metallb-white.png +name: metallb-crds +sources: +- https://github.com/metallb/metallb +type: application +version: 0.14.8 diff --git a/metallb-chart/charts/metallb-crds/README.md b/metallb-chart/charts/metallb-crds/README.md new file mode 100644 index 0000000..58cf71b --- /dev/null +++ b/metallb-chart/charts/metallb-crds/README.md @@ -0,0 +1,11 @@ +# crds + +![Version: 0.14.3](https://img.shields.io/badge/Version-0.14.3-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.14.3](https://img.shields.io/badge/AppVersion-v0.14.3-informational?style=flat-square) + +MetalLB CRDs + +**Homepage:** + +## Source Code + +* diff --git a/metallb-chart/charts/metallb-crds/templates/crds.yaml b/metallb-chart/charts/metallb-crds/templates/crds.yaml new file mode 100644 index 0000000..9341bb4 --- /dev/null +++ b/metallb-chart/charts/metallb-crds/templates/crds.yaml @@ -0,0 +1,1205 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: bfdprofiles.metallb.io +spec: + group: metallb.io + names: + kind: BFDProfile + listKind: BFDProfileList + plural: bfdprofiles + singular: bfdprofile + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.passiveMode + name: Passive Mode + type: boolean + - jsonPath: .spec.transmitInterval + name: Transmit Interval + type: integer + - jsonPath: .spec.receiveInterval + name: Receive Interval + type: integer + - jsonPath: .spec.detectMultiplier + name: Multiplier + type: integer + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + BFDProfile represents the settings of the bfd session that can be + optionally associated with a BGP session. + 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: BFDProfileSpec defines the desired state of BFDProfile. + properties: + detectMultiplier: + description: |- + Configures the detection multiplier to determine + packet loss. The remote transmission interval will be multiplied + by this value to determine the connection loss detection timer. + format: int32 + maximum: 255 + minimum: 2 + type: integer + echoInterval: + description: |- + Configures the minimal echo receive transmission + interval that this system is capable of handling in milliseconds. + Defaults to 50ms + format: int32 + maximum: 60000 + minimum: 10 + type: integer + echoMode: + description: |- + Enables or disables the echo transmission mode. + This mode is disabled by default, and not supported on multi + hops setups. + type: boolean + minimumTtl: + description: |- + For multi hop sessions only: configure the minimum + expected TTL for an incoming BFD control packet. + format: int32 + maximum: 254 + minimum: 1 + type: integer + passiveMode: + description: |- + Mark session as passive: a passive session will not + attempt to start the connection and will wait for control packets + from peer before it begins replying. + type: boolean + receiveInterval: + description: |- + The minimum interval that this system is capable of + receiving control packets in milliseconds. + Defaults to 300ms. + format: int32 + maximum: 60000 + minimum: 10 + type: integer + transmitInterval: + description: |- + The minimum transmission interval (less jitter) + that this system wants to use to send BFD control packets in + milliseconds. Defaults to 300ms + format: int32 + maximum: 60000 + minimum: 10 + type: integer + type: object + status: + description: BFDProfileStatus defines the observed state of BFDProfile. + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: bgpadvertisements.metallb.io +spec: + group: metallb.io + names: + kind: BGPAdvertisement + listKind: BGPAdvertisementList + plural: bgpadvertisements + singular: bgpadvertisement + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.ipAddressPools + name: IPAddressPools + type: string + - jsonPath: .spec.ipAddressPoolSelectors + name: IPAddressPool Selectors + type: string + - jsonPath: .spec.peers + name: Peers + type: string + - jsonPath: .spec.nodeSelectors + name: Node Selectors + priority: 10 + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + BGPAdvertisement allows to advertise the IPs coming + from the selected IPAddressPools via BGP, setting the parameters of the + BGP Advertisement. + 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: BGPAdvertisementSpec defines the desired state of BGPAdvertisement. + properties: + aggregationLength: + default: 32 + description: The aggregation-length advertisement option lets you “roll up” the /32s into a larger prefix. Defaults to 32. Works for IPv4 addresses. + format: int32 + minimum: 1 + type: integer + aggregationLengthV6: + default: 128 + description: The aggregation-length advertisement option lets you “roll up” the /128s into a larger prefix. Defaults to 128. Works for IPv6 addresses. + format: int32 + type: integer + communities: + description: |- + The BGP communities to be associated with the announcement. Each item can be a standard community of the + form 1234:1234, a large community of the form large:1234:1234:1234 or the name of an alias defined in the + Community CRD. + items: + type: string + type: array + ipAddressPoolSelectors: + description: |- + A selector for the IPAddressPools which would get advertised via this advertisement. + If no IPAddressPool is selected by this or by the list, the advertisement is applied to all the IPAddressPools. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + ipAddressPools: + description: The list of IPAddressPools to advertise via this advertisement, selected by name. + items: + type: string + type: array + localPref: + description: |- + The BGP LOCAL_PREF attribute which is used by BGP best path algorithm, + Path with higher localpref is preferred over one with lower localpref. + format: int32 + type: integer + nodeSelectors: + description: NodeSelectors allows to limit the nodes to announce as next hops for the LoadBalancer IP. When empty, all the nodes having are announced as next hops. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + peers: + description: |- + Peers limits the bgppeer to advertise the ips of the selected pools to. + When empty, the loadbalancer IP is announced to all the BGPPeers configured. + items: + type: string + type: array + type: object + status: + description: BGPAdvertisementStatus defines the observed state of BGPAdvertisement. + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: bgppeers.metallb.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlGWlRDQ0EwMmdBd0lCQWdJVU5GRW1XcTM3MVpKdGkrMmlSQzk1WmpBV1MxZ3dEUVlKS29aSWh2Y05BUUVMDQpCUUF3UWpFTE1Ba0dBMVVFQmhNQ1dGZ3hGVEFUQmdOVkJBY01ERVJsWm1GMWJIUWdRMmwwZVRFY01Cb0dBMVVFDQpDZ3dUUkdWbVlYVnNkQ0JEYjIxd1lXNTVJRXgwWkRBZUZ3MHlNakEzTVRrd09UTXlNek5hRncweU1qQTRNVGd3DQpPVE15TXpOYU1FSXhDekFKQmdOVkJBWVRBbGhZTVJVd0V3WURWUVFIREF4RVpXWmhkV3gwSUVOcGRIa3hIREFhDQpCZ05WQkFvTUUwUmxabUYxYkhRZ1EyOXRjR0Z1ZVNCTWRHUXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDDQpEd0F3Z2dJS0FvSUNBUUNxVFpxMWZRcC9vYkdlenhES0o3OVB3Ny94azJwellualNzMlkzb1ZYSm5sRmM4YjVlDQpma2ZZQnY2bndscW1keW5PL2phWFBaQmRQSS82aFdOUDBkdVhadEtWU0NCUUpyZzEyOGNXb3F0MGNTN3pLb1VpDQpvcU1tQ0QvRXVBeFFNZjhRZDF2c1gvVllkZ0poVTZBRXJLZEpIaXpFOUJtUkNkTDBGMW1OVW55Rk82UnRtWFZUDQpidkxsTDVYeTc2R0FaQVBLOFB4aVlDa0NtbDdxN0VnTWNiOXlLWldCYmlxQ3VkTXE5TGJLNmdKNzF6YkZnSXV4DQo1L1pXK2JraTB2RlplWk9ZODUxb1psckFUNzJvMDI4NHNTWW9uN0pHZVZkY3NoUnh5R1VpSFpSTzdkaXZVTDVTDQpmM2JmSDFYbWY1ZDQzT0NWTWRuUUV2NWVaOG8zeWVLa3ZrbkZQUGVJMU9BbjdGbDlFRVNNR2dhOGFaSG1URSttDQpsLzlMSmdDYjBnQmtPT0M0WnV4bWh2aERKV1EzWnJCS3pMQlNUZXN0NWlLNVlwcXRWVVk2THRyRW9FelVTK1lsDQpwWndXY2VQWHlHeHM5ZURsR3lNVmQraW15Y3NTU1UvVno2Mmx6MnZCS21NTXBkYldDQWhud0RsRTVqU2dyMjRRDQp0eGNXLys2N3d5KzhuQlI3UXdqVTFITndVRjBzeERWdEwrZ1NHVERnSEVZSlhZelYvT05zMy94TkpoVFNPSkxNDQpoeXNVdyttaGdackdhbUdXcHVIVU1DUitvTWJzMTc1UkcrQjJnUFFHVytPTjJnUTRyOXN2b0ZBNHBBQm8xd1dLDQpRYjRhY3pmeVVscElBOVFoSmFsZEY3S3dPSHVlV3gwRUNrNXg0T2tvVDBvWVp0dzFiR0JjRGtaSmF3SURBUUFCDQpvMU13VVRBZEJnTlZIUTRFRmdRVW90UlNIUm9IWTEyRFZ4R0NCdEhpb1g2ZmVFQXdId1lEVlIwakJCZ3dGb0FVDQpvdFJTSFJvSFkxMkRWeEdDQnRIaW9YNmZlRUF3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCDQpBUXNGQUFPQ0FnRUFSbkpsWWRjMTFHd0VxWnh6RDF2R3BDR2pDN2VWTlQ3aVY1d3IybXlybHdPYi9aUWFEa0xYDQpvVStaOVVXT1VlSXJTdzUydDdmQUpvVVAwSm5iYkMveVIrU1lqUGhvUXNiVHduOTc2ZldBWTduM3FMOXhCd1Y0DQphek41OXNjeUp0dlhMeUtOL2N5ak1ReDRLajBIMFg0bWJ6bzVZNUtzWWtYVU0vOEFPdWZMcEd0S1NGVGgrSEFDDQpab1Q5YnZHS25adnNHd0tYZFF0Wnh0akhaUjVqK3U3ZGtQOTJBT051RFNabS8rWVV4b2tBK09JbzdSR3BwSHNXDQo1ZTdNY0FTVXRtb1FORXd6dVFoVkJaRWQ1OGtKYjUrV0VWbGNzanlXNnRTbzErZ25tTWNqR1BsMWgxR2hVbjV4DQpFY0lWRnBIWXM5YWo1NmpBSjk1MVQvZjhMaWxmTlVnanBLQ0c1bnl0SUt3emxhOHNtdGlPdm1UNEpYbXBwSkI2DQo4bmdHRVluVjUrUTYwWFJ2OEhSSGp1VG9CRHVhaERrVDA2R1JGODU1d09FR2V4bkZpMXZYWUxLVllWb1V2MXRKDQo4dVdUR1pwNllDSVJldlBqbzg5ZytWTlJSaVFYUThJd0dybXE5c0RoVTlqTjA0SjdVL1RvRDFpNHE3VnlsRUc5DQorV1VGNkNLaEdBeTJIaEhwVncyTGFoOS9lUzdZMUZ1YURrWmhPZG1laG1BOCtqdHNZamJadnR5Mm1SWlF0UUZzDQpUU1VUUjREbUR2bVVPRVRmeStpRHdzK2RkWXVNTnJGeVVYV2dkMnpBQU4ydVl1UHFGY2pRcFNPODFzVTJTU3R3DQoxVzAyeUtYOGJEYmZFdjBzbUh3UzliQnFlSGo5NEM1Mjg0YXpsdTBmaUdpTm1OUEM4ckJLRmhBPQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ== + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /convert + conversionReviewVersions: + - v1beta1 + - v1beta2 + group: metallb.io + names: + kind: BGPPeer + listKind: BGPPeerList + plural: bgppeers + singular: bgppeer + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.peerAddress + name: Address + type: string + - jsonPath: .spec.peerASN + name: ASN + type: string + - jsonPath: .spec.bfdProfile + name: BFD Profile + type: string + - jsonPath: .spec.ebgpMultiHop + name: Multi Hops + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: BGPPeer is the Schema for the peers 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: BGPPeerSpec defines the desired state of Peer. + properties: + bfdProfile: + type: string + ebgpMultiHop: + description: EBGP peer is multi-hops away + type: boolean + holdTime: + description: Requested BGP hold time, per RFC4271. + type: string + keepaliveTime: + description: Requested BGP keepalive time, per RFC4271. + type: string + myASN: + description: AS number to use for the local end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + nodeSelectors: + description: |- + Only connect to this peer on nodes that match one of these + selectors. + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + minItems: 1 + type: array + required: + - key + - operator + - values + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: array + password: + description: Authentication password for routers enforcing TCP MD5 authenticated sessions + type: string + peerASN: + description: AS number to expect from the remote end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + peerAddress: + description: Address to dial when establishing the session. + type: string + peerPort: + description: Port to dial when establishing the session. + maximum: 16384 + minimum: 0 + type: integer + routerID: + description: BGP router ID to advertise to the peer + type: string + sourceAddress: + description: Source address to use when establishing the session. + type: string + required: + - myASN + - peerASN + - peerAddress + type: object + status: + description: BGPPeerStatus defines the observed state of Peer. + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.peerAddress + name: Address + type: string + - jsonPath: .spec.peerASN + name: ASN + type: string + - jsonPath: .spec.bfdProfile + name: BFD Profile + type: string + - jsonPath: .spec.ebgpMultiHop + name: Multi Hops + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: BGPPeer is the Schema for the peers 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: BGPPeerSpec defines the desired state of Peer. + properties: + bfdProfile: + description: The name of the BFD Profile to be used for the BFD session associated to the BGP session. If not set, the BFD session won't be set up. + type: string + connectTime: + description: Requested BGP connect time, controls how long BGP waits between connection attempts to a neighbor. + type: string + x-kubernetes-validations: + - message: connect time should be between 1 seconds to 65535 + rule: duration(self).getSeconds() >= 1 && duration(self).getSeconds() <= 65535 + - message: connect time should contain a whole number of seconds + rule: duration(self).getMilliseconds() % 1000 == 0 + disableMP: + default: false + description: To set if we want to disable MP BGP that will separate IPv4 and IPv6 route exchanges into distinct BGP sessions. + type: boolean + ebgpMultiHop: + description: To set if the BGPPeer is multi-hops away. Needed for FRR mode only. + type: boolean + enableGracefulRestart: + description: |- + EnableGracefulRestart allows BGP peer to continue to forward data packets along + known routes while the routing protocol information is being restored. + This field is immutable because it requires restart of the BGP session + Supported for FRR mode only. + type: boolean + x-kubernetes-validations: + - message: EnableGracefulRestart cannot be changed after creation + rule: self == oldSelf + holdTime: + description: Requested BGP hold time, per RFC4271. + type: string + keepaliveTime: + description: Requested BGP keepalive time, per RFC4271. + type: string + myASN: + description: AS number to use for the local end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + nodeSelectors: + description: |- + Only connect to this peer on nodes that match one of these + selectors. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + password: + description: Authentication password for routers enforcing TCP MD5 authenticated sessions + type: string + passwordSecret: + description: |- + passwordSecret is name of the authentication secret for BGP Peer. + the secret must be of type "kubernetes.io/basic-auth", and created in the + same namespace as the MetalLB deployment. The password is stored in the + secret as the key "password". + 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 + peerASN: + description: AS number to expect from the remote end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + peerAddress: + description: Address to dial when establishing the session. + type: string + peerPort: + default: 179 + description: Port to dial when establishing the session. + maximum: 16384 + minimum: 0 + type: integer + routerID: + description: BGP router ID to advertise to the peer + type: string + sourceAddress: + description: Source address to use when establishing the session. + type: string + vrf: + description: |- + To set if we want to peer with the BGPPeer using an interface belonging to + a host vrf + type: string + required: + - myASN + - peerASN + - peerAddress + type: object + status: + description: BGPPeerStatus defines the observed state of Peer. + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: communities.metallb.io +spec: + group: metallb.io + names: + kind: Community + listKind: CommunityList + plural: communities + singular: community + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: |- + Community is a collection of aliases for communities. + Users can define named aliases to be used in the BGPPeer CRD. + 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: CommunitySpec defines the desired state of Community. + properties: + communities: + items: + properties: + name: + description: The name of the alias for the community. + type: string + value: + description: |- + The BGP community value corresponding to the given name. Can be a standard community of the form 1234:1234 + or a large community of the form large:1234:1234:1234. + type: string + type: object + type: array + type: object + status: + description: CommunityStatus defines the observed state of Community. + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ipaddresspools.metallb.io +spec: + group: metallb.io + names: + kind: IPAddressPool + listKind: IPAddressPoolList + plural: ipaddresspools + singular: ipaddresspool + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.autoAssign + name: Auto Assign + type: boolean + - jsonPath: .spec.avoidBuggyIPs + name: Avoid Buggy IPs + type: boolean + - jsonPath: .spec.addresses + name: Addresses + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + IPAddressPool represents a pool of IP addresses that can be allocated + to LoadBalancer services. + 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: IPAddressPoolSpec defines the desired state of IPAddressPool. + properties: + addresses: + description: |- + A list of IP address ranges over which MetalLB has authority. + You can list multiple ranges in a single pool, they will all share the + same settings. Each range can be either a CIDR prefix, or an explicit + start-end range of IPs. + items: + type: string + type: array + autoAssign: + default: true + description: |- + AutoAssign flag used to prevent MetallB from automatic allocation + for a pool. + type: boolean + avoidBuggyIPs: + default: false + description: |- + AvoidBuggyIPs prevents addresses ending with .0 and .255 + to be used by a pool. + type: boolean + serviceAllocation: + description: |- + AllocateTo makes ip pool allocation to specific namespace and/or service. + The controller will use the pool with lowest value of priority in case of + multiple matches. A pool with no priority set will be used only if the + pools with priority can't be used. If multiple matching IPAddressPools are + available it will check for the availability of IPs sorting the matching + IPAddressPools by priority, starting from the highest to the lowest. If + multiple IPAddressPools have the same priority, choice will be random. + properties: + namespaceSelectors: + description: |- + NamespaceSelectors list of label selectors to select namespace(s) for ip pool, + an alternative to using namespace list. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + namespaces: + description: Namespaces list of namespace(s) on which ip pool can be attached. + items: + type: string + type: array + priority: + description: Priority priority given for ip pool while ip allocation on a service. + type: integer + serviceSelectors: + description: |- + ServiceSelectors list of label selector to select service(s) for which ip pool + can be used for ip allocation. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + type: object + required: + - addresses + type: object + status: + description: IPAddressPoolStatus defines the observed state of IPAddressPool. + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: l2advertisements.metallb.io +spec: + group: metallb.io + names: + kind: L2Advertisement + listKind: L2AdvertisementList + plural: l2advertisements + singular: l2advertisement + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.ipAddressPools + name: IPAddressPools + type: string + - jsonPath: .spec.ipAddressPoolSelectors + name: IPAddressPool Selectors + type: string + - jsonPath: .spec.interfaces + name: Interfaces + type: string + - jsonPath: .spec.nodeSelectors + name: Node Selectors + priority: 10 + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + L2Advertisement allows to advertise the LoadBalancer IPs provided + by the selected pools via L2. + 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: L2AdvertisementSpec defines the desired state of L2Advertisement. + properties: + interfaces: + description: |- + A list of interfaces to announce from. The LB IP will be announced only from these interfaces. + If the field is not set, we advertise from all the interfaces on the host. + items: + type: string + type: array + ipAddressPoolSelectors: + description: |- + A selector for the IPAddressPools which would get advertised via this advertisement. + If no IPAddressPool is selected by this or by the list, the advertisement is applied to all the IPAddressPools. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + ipAddressPools: + description: The list of IPAddressPools to advertise via this advertisement, selected by name. + items: + type: string + type: array + nodeSelectors: + description: NodeSelectors allows to limit the nodes to announce as next hops for the LoadBalancer IP. When empty, all the nodes having are announced as next hops. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + type: object + status: + description: L2AdvertisementStatus defines the observed state of L2Advertisement. + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: servicel2statuses.metallb.io +spec: + group: metallb.io + names: + kind: ServiceL2Status + listKind: ServiceL2StatusList + plural: servicel2statuses + singular: servicel2status + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.node + name: Allocated Node + type: string + - jsonPath: .status.serviceName + name: Service Name + type: string + - jsonPath: .status.serviceNamespace + name: Service Namespace + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ServiceL2Status reveals the actual traffic status of loadbalancer services in layer2 mode. + 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: ServiceL2StatusSpec defines the desired state of ServiceL2Status. + type: object + status: + description: MetalLBServiceL2Status defines the observed state of ServiceL2Status. + properties: + interfaces: + description: Interfaces indicates the interfaces that receive the directed traffic + items: + description: InterfaceInfo defines interface info of layer2 announcement. + properties: + name: + description: Name the name of network interface card + type: string + type: object + type: array + node: + description: Node indicates the node that receives the directed traffic + type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf + serviceName: + description: ServiceName indicates the service this status represents + type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf + serviceNamespace: + description: ServiceNamespace indicates the namespace of the service + type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/metallb-chart/policy.obscpio b/metallb-chart/policy.obscpio deleted file mode 100644 index 09b648f40e16e9bd2ec34efe3330313becc9ce053978835af1711318a06d888f..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3072 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 1 minute'`}} + expr: metallb_k8s_client_config_stale_bool{job=~"{{ template "metallb.fullname" . }}.*"} == 1 + for: 1m + {{- with .Values.prometheus.prometheusRule.staleConfig.labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.prometheus.prometheusRule.configNotLoaded.enabled }} + - alert: MetalLBConfigNotLoaded + annotations: + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod + }} has not loaded for > 1 minute'`}} + expr: metallb_k8s_client_config_loaded_bool{job=~"{{ template "metallb.fullname" . }}.*"} == 0 + for: 1m + {{- with .Values.prometheus.prometheusRule.configNotLoaded.labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.prometheus.prometheusRule.addressPoolExhausted.enabled }} + - alert: MetalLBAddressPoolExhausted + annotations: + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod + }} has exhausted address pool {{ $labels.pool }} for > 1 minute'`}} + expr: metallb_allocator_addresses_in_use_total >= on(pool) metallb_allocator_addresses_total + for: 1m + {{- with .Values.prometheus.prometheusRule.addressPoolExhausted.labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + + {{- if .Values.prometheus.prometheusRule.addressPoolUsage.enabled }} + {{- range .Values.prometheus.prometheusRule.addressPoolUsage.thresholds }} + - alert: MetalLBAddressPoolUsage{{ .percent }}Percent + annotations: + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod + }} has address pool {{ $labels.pool }} past `}}{{ .percent }}{{`% usage for > 1 minute'`}} + expr: ( metallb_allocator_addresses_in_use_total / on(pool) metallb_allocator_addresses_total ) * 100 > {{ .percent }} + {{- with .labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.prometheus.prometheusRule.bgpSessionDown.enabled }} + - alert: MetalLBBGPSessionDown + annotations: + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod + }} has BGP session {{ $labels.peer }} down for > 1 minute'`}} + expr: metallb_bgp_session_up{job=~"{{ template "metallb.fullname" . }}.*"} == 0 + for: 1m + {{- with .Values.prometheus.prometheusRule.bgpSessionDown.labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- with .Values.prometheus.prometheusRule.extraAlerts }} + {{- toYaml . | nindent 4 }} + {{- end}} +{{- end }} diff --git a/metallb-chart/templates/rbac.yaml b/metallb-chart/templates/rbac.yaml new file mode 100644 index 0000000..8c66b80 --- /dev/null +++ b/metallb-chart/templates/rbac.yaml @@ -0,0 +1,212 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "metallb.fullname" . }}:controller + labels: + {{- include "metallb.labels" . | nindent 4 }} +rules: +- apiGroups: [""] + resources: ["services", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["nodes"] + verbs: ["list"] +- apiGroups: [""] + resources: ["services/status"] + verbs: ["update"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"] + resourceNames: ["metallb-webhook-configuration"] + verbs: ["create", "delete", "get", "list", "patch", "update", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"] + verbs: ["list", "watch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + resourceNames: ["bfdprofiles.metallb.io","bgpadvertisements.metallb.io", + "bgppeers.metallb.io","ipaddresspools.metallb.io","l2advertisements.metallb.io","communities.metallb.io"] + verbs: ["create", "delete", "get", "list", "patch", "update", "watch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["list", "watch"] +{{- if .Values.prometheus.secureMetricsPort }} +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: ["subjectaccessreviews"] + verbs: ["create"] +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "metallb.fullname" . }}:speaker + labels: + {{- include "metallb.labels" . | nindent 4 }} +rules: +- apiGroups: [""] + resources: ["services", "endpoints", "nodes", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +- apiGroups: ["metallb.io"] + resources: ["servicel2statuses","servicel2statuses/status"] + verbs: ["*"] +{{- if .Values.prometheus.secureMetricsPort }} +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: ["subjectaccessreviews"] + verbs: ["create"] +{{- end }} +{{- if or .Values.frrk8s.enabled .Values.frrk8s.external }} +- apiGroups: ["frrk8s.metallb.io"] + resources: ["frrconfigurations"] + verbs: ["get", "list", "watch","create","update"] +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "metallb.fullname" . }}-pod-lister + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "metallb.labels" . | nindent 4 }} +rules: +- apiGroups: [""] + resources: ["pods"] + verbs: ["list", "get"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["bfdprofiles"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["bgppeers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["l2advertisements"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["bgpadvertisements"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["ipaddresspools"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["communities"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "metallb.fullname" . }}-controller + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "metallb.labels" . | nindent 4 }} +rules: +{{- if .Values.speaker.memberlist.enabled }} +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "list", "watch"] +- apiGroups: [""] + resources: ["secrets"] + resourceNames: [{{ include "metallb.secretName" . | quote }}] + verbs: ["list"] +- apiGroups: ["apps"] + resources: ["deployments"] + resourceNames: ["{{ template "metallb.fullname" . }}-controller"] + verbs: ["get"] +{{- end }} +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "delete", "get", "list", "patch", "update", "watch"] +- apiGroups: ["metallb.io"] + resources: ["ipaddresspools"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["bgppeers"] + verbs: ["get", "list"] +- apiGroups: ["metallb.io"] + resources: ["bgpadvertisements"] + verbs: ["get", "list"] +- apiGroups: ["metallb.io"] + resources: ["l2advertisements"] + verbs: ["get", "list"] +- apiGroups: ["metallb.io"] + resources: ["communities"] + verbs: ["get", "list","watch"] +- apiGroups: ["metallb.io"] + resources: ["bfdprofiles"] + verbs: ["get", "list","watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "metallb.fullname" . }}:controller + labels: + {{- include "metallb.labels" . | nindent 4 }} +subjects: +- kind: ServiceAccount + name: {{ template "metallb.controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "metallb.fullname" . }}:controller +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "metallb.fullname" . }}:speaker + labels: + {{- include "metallb.labels" . | nindent 4 }} +subjects: +- kind: ServiceAccount + name: {{ template "metallb.speaker.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "metallb.fullname" . }}:speaker +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "metallb.fullname" . }}-pod-lister + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "metallb.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "metallb.fullname" . }}-pod-lister +subjects: +- kind: ServiceAccount + name: {{ include "metallb.speaker.serviceAccountName" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "metallb.fullname" . }}-controller + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "metallb.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "metallb.fullname" . }}-controller +subjects: +- kind: ServiceAccount + name: {{ include "metallb.controller.serviceAccountName" . }} +{{- end -}} diff --git a/metallb-chart/templates/service-accounts.yaml b/metallb-chart/templates/service-accounts.yaml new file mode 100644 index 0000000..c2157ff --- /dev/null +++ b/metallb-chart/templates/service-accounts.yaml @@ -0,0 +1,30 @@ +{{- if .Values.controller.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "metallb.controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: controller + {{- with .Values.controller.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +{{- if .Values.speaker.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "metallb.speaker.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker + {{- with .Values.speaker.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/metallb-chart/templates/servicemonitor.yaml b/metallb-chart/templates/servicemonitor.yaml new file mode 100644 index 0000000..0aacf85 --- /dev/null +++ b/metallb-chart/templates/servicemonitor.yaml @@ -0,0 +1,194 @@ +{{- if .Values.prometheus.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "metallb.fullname" . }}-speaker-monitor + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker + {{- if .Values.prometheus.serviceMonitor.speaker.additionalLabels }} +{{ toYaml .Values.prometheus.serviceMonitor.speaker.additionalLabels | indent 4 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.speaker.annotations }} + annotations: +{{ toYaml .Values.prometheus.serviceMonitor.speaker.annotations | indent 4 }} + {{- end }} +spec: + endpoints: + - port: {{ template "metrics.exposedportname" . }} + honorLabels: true + {{- if .Values.prometheus.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.prometheus.serviceMonitor.metricRelabelings | nindent 8 }} + {{- end -}} + {{- if .Values.prometheus.serviceMonitor.relabelings }} + relabelings: + {{- toYaml .Values.prometheus.serviceMonitor.relabelings | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.interval }} + interval: {{ .Values.prometheus.serviceMonitor.interval }} + {{- end -}} +{{ if .Values.prometheus.secureMetricsPort }} + bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token" + scheme: "https" +{{- if .Values.prometheus.serviceMonitor.speaker.tlsConfig }} + tlsConfig: +{{ toYaml .Values.prometheus.serviceMonitor.speaker.tlsConfig | indent 8 }} +{{- end }} +{{ end }} +{{- if .Values.speaker.frr.enabled }} + - port: {{ template "metrics.exposedfrrportname" . }} + honorLabels: true +{{ if .Values.speaker.frr.secureMetricsPort }} + {{- if .Values.prometheus.serviceMonitor.interval }} + interval: {{ .Values.prometheus.serviceMonitor.interval }} + {{- end }} + bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token" + scheme: "https" +{{- if .Values.prometheus.serviceMonitor.speaker.tlsConfig }} + tlsConfig: +{{ toYaml .Values.prometheus.serviceMonitor.speaker.tlsConfig | indent 8 }} +{{- end }} +{{- end }} +{{- end }} + jobLabel: {{ .Values.prometheus.serviceMonitor.jobLabel | quote }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + name: {{ template "metallb.fullname" . }}-speaker-monitor-service +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/scrape: "true" + {{- if .Values.prometheus.serviceMonitor.speaker.annotations }} +{{ toYaml .Values.prometheus.serviceMonitor.speaker.annotations | indent 4 }} + {{- end }} + labels: + name: {{ template "metallb.fullname" . }}-speaker-monitor-service + {{- include "metallb.labels" . | nindent 4 }} + name: {{ template "metallb.fullname" . }}-speaker-monitor-service + namespace: {{ .Release.Namespace | quote }} +spec: + selector: + {{- include "metallb.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: speaker + clusterIP: None + ports: + - name: {{ template "metrics.exposedportname" . }} + port: {{ template "metrics.exposedport" . }} + targetPort: {{ template "metrics.exposedport" . }} +{{- if .Values.speaker.frr.enabled }} + - name: {{ template "metrics.exposedfrrportname" . }} + port: {{ template "metrics.exposedfrrport" . }} + targetPort: {{ template "metrics.exposedfrrport" . }} +{{- end }} + sessionAffinity: None + type: ClusterIP +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "metallb.fullname" . }}-controller-monitor + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker + {{- if .Values.prometheus.serviceMonitor.controller.additionalLabels }} +{{ toYaml .Values.prometheus.serviceMonitor.controller.additionalLabels | indent 4 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.controller.annotations }} + annotations: +{{ toYaml .Values.prometheus.serviceMonitor.controller.annotations | indent 4 }} + {{- end }} +spec: + endpoints: + - port: {{ template "metrics.exposedportname" . }} + {{- if .Values.prometheus.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.prometheus.serviceMonitor.metricRelabelings | nindent 8 }} + {{- end -}} + {{- if .Values.prometheus.serviceMonitor.relabelings }} + relabelings: + {{- toYaml .Values.prometheus.serviceMonitor.relabelings | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.interval }} + interval: {{ .Values.prometheus.serviceMonitor.interval }} + {{- end }} + honorLabels: true +{{- if .Values.prometheus.secureMetricsPort }} + bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token" + scheme: "https" +{{- if .Values.prometheus.serviceMonitor.controller.tlsConfig }} + tlsConfig: +{{ toYaml .Values.prometheus.serviceMonitor.controller.tlsConfig | indent 8 }} +{{- end }} +{{- end }} + jobLabel: {{ .Values.prometheus.serviceMonitor.jobLabel | quote }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + name: {{ template "metallb.fullname" . }}-controller-monitor-service +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/scrape: "true" + {{- if .Values.prometheus.serviceMonitor.controller.annotations }} +{{ toYaml .Values.prometheus.serviceMonitor.controller.annotations | indent 4 }} + {{- end }} + labels: + name: {{ template "metallb.fullname" . }}-controller-monitor-service + name: {{ template "metallb.fullname" . }}-controller-monitor-service +spec: + selector: + {{- include "metallb.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: controller + clusterIP: None + ports: + - name: {{ template "metrics.exposedportname" . }} + port: {{ template "metrics.exposedport" . }} + targetPort: {{ template "metrics.exposedport" . }} + sessionAffinity: None + type: ClusterIP +--- +{{- if .Values.prometheus.rbacPrometheus }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "metallb.fullname" . }}-prometheus + namespace: {{ .Release.Namespace | quote }} +rules: + - apiGroups: + - "" + resources: + - pods + - services + - endpoints + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "metallb.fullname" . }}-prometheus + namespace: {{ .Release.Namespace | quote }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "metallb.fullname" . }}-prometheus +subjects: + - kind: ServiceAccount + name: {{ required ".Values.prometheus.serviceAccount must be defined when .Values.prometheus.serviceMonitor.enabled == true" .Values.prometheus.serviceAccount }} + namespace: {{ required ".Values.prometheus.namespace must be defined when .Values.prometheus.serviceMonitor.enabled == true" .Values.prometheus.namespace }} +{{- end }} +{{- end }} diff --git a/metallb-chart/templates/speaker.yaml b/metallb-chart/templates/speaker.yaml new file mode 100644 index 0000000..567d820 --- /dev/null +++ b/metallb-chart/templates/speaker.yaml @@ -0,0 +1,568 @@ +{{- if .Values.speaker.frr.enabled }} +{{- if or .Values.frrk8s.enabled .Values.frrk8s.external }} +{{- fail "speaker.frr.enabled and frrk8s.enabled / external are mutually exclusive!" }} +{{- end }} +{{- end }} + +{{- if and .Values.frrk8s.enabled .Values.frrk8s.external }} +{{- fail "frrk8s.enabled frrk8s.external are mutually exclusive!" }} +{{- end }} + +{{- if .Values.speaker.frr.enabled }} + +# FRR expects to have these files owned by frr:frr on startup. +# Having them in a ConfigMap allows us to modify behaviors: for example enabling more daemons on startup. +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "metallb.fullname" . }}-frr-startup + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker +data: + daemons: | + # This file tells the frr package which daemons to start. + # + # Sample configurations for these daemons can be found in + # /usr/share/doc/frr/examples/. + # + # ATTENTION: + # + # When activating a daemon for the first time, a config file, even if it is + # empty, has to be present *and* be owned by the user and group "frr", else + # the daemon will not be started by /etc/init.d/frr. The permissions should + # be u=rw,g=r,o=. + # When using "vtysh" such a config file is also needed. It should be owned by + # group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. + # + # The watchfrr and zebra daemons are always started. + # + bgpd=yes + ospfd=no + ospf6d=no + ripd=no + ripngd=no + isisd=no + pimd=no + ldpd=no + nhrpd=no + eigrpd=no + babeld=no + sharpd=no + pbrd=no + bfdd=yes + fabricd=no + vrrpd=no + + # + # If this option is set the /etc/init.d/frr script automatically loads + # the config via "vtysh -b" when the servers are started. + # Check /etc/pam.d/frr if you intend to use "vtysh"! + # + vtysh_enable=yes + zebra_options=" -A 127.0.0.1 -s 90000000" + bgpd_options=" -A 127.0.0.1 -p 0" + ospfd_options=" -A 127.0.0.1" + ospf6d_options=" -A ::1" + ripd_options=" -A 127.0.0.1" + ripngd_options=" -A ::1" + isisd_options=" -A 127.0.0.1" + pimd_options=" -A 127.0.0.1" + ldpd_options=" -A 127.0.0.1" + nhrpd_options=" -A 127.0.0.1" + eigrpd_options=" -A 127.0.0.1" + babeld_options=" -A 127.0.0.1" + sharpd_options=" -A 127.0.0.1" + pbrd_options=" -A 127.0.0.1" + staticd_options="-A 127.0.0.1" + bfdd_options=" -A 127.0.0.1" + fabricd_options="-A 127.0.0.1" + vrrpd_options=" -A 127.0.0.1" + + # configuration profile + # + #frr_profile="traditional" + #frr_profile="datacenter" + + # + # This is the maximum number of FD's that will be available. + # Upon startup this is read by the control files and ulimit + # is called. Uncomment and use a reasonable value for your + # setup if you are expecting a large number of peers in + # say BGP. + #MAX_FDS=1024 + + # The list of daemons to watch is automatically generated by the init script. + #watchfrr_options="" + + # for debugging purposes, you can specify a "wrap" command to start instead + # of starting the daemon directly, e.g. to use valgrind on ospfd: + # ospfd_wrap="/usr/bin/valgrind" + # or you can use "all_wrap" for all daemons, e.g. to use perf record: + # all_wrap="/usr/bin/perf record --call-graph -" + # the normal daemon command is added to this at the end. + vtysh.conf: |+ + service integrated-vtysh-config + frr.conf: |+ + ! This file gets overriden the first time the speaker renders a config. + ! So anything configured here is only temporary. + frr version 8.0 + frr defaults traditional + hostname Router + line vty + log file /etc/frr/frr.log informational +{{- end }} +--- +{{- if .Values.speaker.enabled }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ template "metallb.fullname" . }}-speaker + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker + {{- range $key, $value := .Values.speaker.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + {{- if .Values.speaker.updateStrategy }} + updateStrategy: {{- toYaml .Values.speaker.updateStrategy | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "metallb.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: speaker + template: + metadata: + {{- if or .Values.prometheus.scrapeAnnotations .Values.speaker.podAnnotations }} + annotations: + {{- if .Values.prometheus.scrapeAnnotations }} + prometheus.io/scrape: "true" + {{- if not .Values.speaker.frr.enabled }} + prometheus.io/port: "{{ .Values.prometheus.metricsPort }}" + {{- end }} + {{- end }} + {{- with .Values.speaker.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + labels: + {{- include "metallb.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: speaker + {{- range $key, $value := .Values.speaker.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + {{- if .Values.speaker.runtimeClassName }} + runtimeClassName: {{ .Values.speaker.runtimeClassName }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ template "metallb.speaker.serviceAccountName" . }} + terminationGracePeriodSeconds: 0 + hostNetwork: true + {{- if .Values.speaker.securityContext }} + securityContext: + {{- toYaml .Values.speaker.securityContext | nindent 8 }} + {{- end }} + volumes: + {{- if .Values.prometheus.speakerMetricsTLSSecret }} + - name: metrics-certs + secret: + secretName: {{ .Values.prometheus.speakerMetricsTLSSecret }} + {{- end }} + {{- if .Values.speaker.memberlist.enabled }} + - name: memberlist + secret: + secretName: {{ include "metallb.secretName" . }} + defaultMode: 420 + {{- end }} + {{- if .Values.speaker.excludeInterfaces.enabled }} + - name: metallb-excludel2 + configMap: + defaultMode: 256 + name: metallb-excludel2 + {{- end }} + {{- if .Values.speaker.frr.enabled }} + - name: frr-sockets + emptyDir: {} + - name: frr-startup + configMap: + name: {{ template "metallb.fullname" . }}-frr-startup + - name: frr-conf + emptyDir: {} + - name: reloader + emptyDir: {} + - name: metrics + emptyDir: {} + initContainers: + # Copies the initial config files with the right permissions to the shared volume. + - name: cp-frr-files + image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }} + securityContext: + runAsUser: 100 + runAsGroup: 101 + command: ["/bin/sh", "-c", "cp -rLf /tmp/frr/* /etc/frr/"] + volumeMounts: + - name: frr-startup + mountPath: /tmp/frr + - name: frr-conf + mountPath: /etc/frr + # Copies the reloader to the shared volume between the speaker and reloader. + - name: cp-reloader + image: {{ .Values.speaker.image.repository }}:{{ .Values.speaker.image.tag | default .Chart.AppVersion }} + command: ["/cp-tool","/frr-reloader.sh","/etc/frr_reloader/frr-reloader.sh"] + volumeMounts: + - name: reloader + mountPath: /etc/frr_reloader + # Copies the metrics exporter + - name: cp-metrics + image: {{ .Values.speaker.image.repository }}:{{ .Values.speaker.image.tag | default .Chart.AppVersion }} + command: ["/cp-tool","/frr-metrics","/etc/frr_metrics/frr-metrics"] + volumeMounts: + - name: metrics + mountPath: /etc/frr_metrics + shareProcessNamespace: true + {{- end }} + containers: + - name: speaker + image: {{ .Values.speaker.image.repository }}:{{ .Values.speaker.image.tag | default .Chart.AppVersion }} + {{- if .Values.speaker.image.pullPolicy }} + imagePullPolicy: {{ .Values.speaker.image.pullPolicy }} + {{- end }} + {{- if .Values.speaker.command }} + command: + - {{ .Values.speaker.command }} + {{- end }} + args: + - --port={{ .Values.prometheus.metricsPort }} + {{- with .Values.speaker.logLevel }} + - --log-level={{ . }} + {{- end }} + {{- if .Values.loadBalancerClass }} + - --lb-class={{ .Values.loadBalancerClass }} + {{- end }} + {{- if .Values.speaker.wanConfig }} + - --ml-wan-config + {{- end }} + {{- if .Values.speaker.ignoreExcludeLB}} + - --ignore-exclude-lb + {{- end }} + {{- if .Values.prometheus.secureMetricsPort }} + - --host=localhost + {{- end }} + {{- if .Values.frrk8s.external }} + - --frrk8s-namespace={{ required "namespace is required when frrk8s is external" .Values.frrk8s.namespace }} + {{- end }} + env: + - name: METALLB_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: METALLB_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.speaker.memberlist.enabled }} + {{- if .Values.speaker.memberlist.mlBindAddrOverride }} + - name: METALLB_ML_BIND_ADDR + value: "{{ .Values.speaker.memberlist.mlBindAddrOverride }}" + {{ else }} + - name: METALLB_ML_BIND_ADDR + valueFrom: + fieldRef: + fieldPath: status.podIP + {{ end }} + - name: METALLB_ML_LABELS + value: "app.kubernetes.io/name={{ include "metallb.name" . }},app.kubernetes.io/component=speaker" + - name: METALLB_ML_BIND_PORT + value: "{{ .Values.speaker.memberlist.mlBindPort }}" + - name: METALLB_ML_SECRET_KEY_PATH + value: "{{ .Values.speaker.memberlist.mlSecretKeyPath }}" + {{- end }} + {{- if .Values.speaker.frr.enabled }} + - name: FRR_CONFIG_FILE + value: /etc/frr_reloader/frr.conf + - name: FRR_RELOADER_PID_FILE + value: /etc/frr_reloader/reloader.pid + - name: METALLB_BGP_TYPE + value: frr + {{- end }} + {{- if or .Values.frrk8s.enabled .Values.frrk8s.external }} + - name: METALLB_BGP_TYPE + value: frr-k8s + {{- end }} + - name: METALLB_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + ports: + - name: monitoring + containerPort: {{ .Values.prometheus.metricsPort }} + {{- if .Values.speaker.memberlist.enabled }} + - name: memberlist-tcp + containerPort: {{ .Values.speaker.memberlist.mlBindPort }} + protocol: TCP + - name: memberlist-udp + containerPort: {{ .Values.speaker.memberlist.mlBindPort }} + protocol: UDP + {{- end }} + {{- if .Values.speaker.livenessProbe.enabled }} + livenessProbe: + httpGet: + {{- if .Values.prometheus.secureMetricsPort }} + host: localhost + {{- end }} + path: /metrics + port: monitoring + initialDelaySeconds: {{ .Values.speaker.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.speaker.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.speaker.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.speaker.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.speaker.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.speaker.readinessProbe.enabled }} + readinessProbe: + httpGet: + {{- if .Values.prometheus.secureMetricsPort }} + host: localhost + {{- end }} + path: /metrics + port: monitoring + initialDelaySeconds: {{ .Values.speaker.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.speaker.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.speaker.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.speaker.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.speaker.readinessProbe.failureThreshold }} + {{- end }} + {{- with .Values.speaker.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + add: + - NET_RAW + {{- if or .Values.speaker.frr.enabled .Values.speaker.memberlist.enabled .Values.speaker.excludeInterfaces.enabled }} + volumeMounts: + {{- if .Values.speaker.memberlist.enabled }} + - name: memberlist + mountPath: {{ .Values.speaker.memberlist.mlSecretKeyPath }} + {{- end }} + {{- if .Values.speaker.frr.enabled }} + - name: reloader + mountPath: /etc/frr_reloader + {{- end }} + {{- if .Values.speaker.excludeInterfaces.enabled }} + - name: metallb-excludel2 + mountPath: /etc/metallb + {{- end }} + {{- end }} + {{- if .Values.speaker.frr.enabled }} + - name: frr + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_ADMIN + - NET_BIND_SERVICE + image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }} + {{- if .Values.speaker.frr.image.pullPolicy }} + imagePullPolicy: {{ .Values.speaker.frr.image.pullPolicy }} + {{- end }} + env: + - name: TINI_SUBREAPER + value: "true" + volumeMounts: + - name: frr-sockets + mountPath: /var/run/frr + - name: frr-conf + mountPath: /etc/frr + # The command is FRR's default entrypoint & waiting for the log file to appear and tailing it. + # If the log file isn't created in 60 seconds the tail fails and the container is restarted. + # This workaround is needed to have the frr logs as part of kubectl logs -c frr < speaker_pod_name >. + command: + - /bin/sh + - -c + - | + /sbin/tini -- /usr/lib/frr/docker-start & + attempts=0 + until [[ -f /etc/frr/frr.log || $attempts -eq 60 ]]; do + sleep 1 + attempts=$(( $attempts + 1 )) + done + tail -f /etc/frr/frr.log + {{- with .Values.speaker.frr.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.speaker.livenessProbe.enabled }} + livenessProbe: + httpGet: + {{- if .Values.prometheus.secureMetricsPort }} + host: localhost + {{- end }} + path: livez + port: {{ .Values.speaker.frr.metricsPort }} + initialDelaySeconds: {{ .Values.speaker.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.speaker.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.speaker.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.speaker.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.speaker.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.speaker.startupProbe.enabled }} + startupProbe: + httpGet: + {{- if .Values.prometheus.secureMetricsPort }} + host: localhost + {{- end }} + path: /livez + port: {{ .Values.speaker.frr.metricsPort }} + failureThreshold: {{ .Values.speaker.startupProbe.failureThreshold }} + periodSeconds: {{ .Values.speaker.startupProbe.periodSeconds }} + {{- end }} + - name: reloader + image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }} + {{- if .Values.speaker.frr.image.pullPolicy }} + imagePullPolicy: {{ .Values.speaker.frr.image.pullPolicy }} + {{- end }} + command: ["/etc/frr_reloader/frr-reloader.sh"] + volumeMounts: + - name: frr-sockets + mountPath: /var/run/frr + - name: frr-conf + mountPath: /etc/frr + - name: reloader + mountPath: /etc/frr_reloader + {{- with .Values.speaker.reloader.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + - name: frr-metrics + image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }} + command: ["/etc/frr_metrics/frr-metrics"] + args: + - --metrics-port={{ .Values.speaker.frr.metricsPort }} + {{- if .Values.prometheus.secureMetricsPort }} + - --host=localhost + {{- end }} + env: + - name: VTYSH_HISTFILE + value: /dev/null + ports: + - containerPort: {{ .Values.speaker.frr.metricsPort }} + name: monitoring + volumeMounts: + - name: frr-sockets + mountPath: /var/run/frr + - name: frr-conf + mountPath: /etc/frr + - name: metrics + mountPath: /etc/frr_metrics + {{- with .Values.speaker.frrMetrics.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.prometheus.secureMetricsPort }} + - name: kube-rbac-proxy + image: {{ .Values.prometheus.rbacProxy.repository }}:{{ .Values.prometheus.rbacProxy.tag }} + imagePullPolicy: {{ .Values.prometheus.rbacProxy.pullPolicy }} + args: + - --logtostderr + - --secure-listen-address=:{{ .Values.prometheus.secureMetricsPort }} + - --upstream=http://localhost:{{ .Values.prometheus.metricsPort }}/ + - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + {{- if .Values.prometheus.speakerMetricsTLSSecret }} + - --tls-private-key-file=/etc/metrics/tls.key + - --tls-cert-file=/etc/metrics/tls.crt + {{- end }} + ports: + - containerPort: {{ .Values.prometheus.secureMetricsPort }} + name: metricshttps + resources: + requests: + cpu: 10m + memory: 20Mi + terminationMessagePolicy: FallbackToLogsOnError + {{- if .Values.prometheus.speakerMetricsTLSSecret }} + volumeMounts: + - name: metrics-certs + mountPath: /etc/metrics + readOnly: true + {{- end }} + {{ end }} + {{- if .Values.speaker.frr.enabled }} + {{- if .Values.speaker.frr.secureMetricsPort }} + - name: kube-rbac-proxy-frr + image: {{ .Values.prometheus.rbacProxy.repository }}:{{ .Values.prometheus.rbacProxy.tag | default .Chart.AppVersion }} + imagePullPolicy: {{ .Values.prometheus.rbacProxy.pullPolicy }} + args: + - --logtostderr + - --secure-listen-address=:{{ .Values.speaker.frr.secureMetricsPort }} + - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + - --upstream=http://localhost:{{ .Values.speaker.frr.metricsPort }}/ + {{- if .Values.prometheus.speakerMetricsTLSSecret }} + - --tls-private-key-file=/etc/metrics/tls.key + - --tls-cert-file=/etc/metrics/tls.crt + {{- end }} + ports: + - containerPort: {{ .Values.speaker.frr.secureMetricsPort }} + name: frrmetricshttps + env: + - name: METALLB_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + resources: + requests: + cpu: 10m + memory: 20Mi + terminationMessagePolicy: FallbackToLogsOnError + {{- if .Values.prometheus.speakerMetricsTLSSecret }} + volumeMounts: + - name: metrics-certs + mountPath: /etc/metrics + readOnly: true + {{- end }} + {{ end }} + {{- end }} + {{- if .Values.speaker.extraContainers }} + {{- toYaml .Values.speaker.extraContainers | nindent 6 }} + {{- end }} + nodeSelector: + "kubernetes.io/os": linux + {{- with .Values.speaker.nodeSelector }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.speaker.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.speaker.tolerateMaster .Values.speaker.tolerations }} + tolerations: + {{- if .Values.speaker.tolerateMaster }} + - key: node-role.kubernetes.io/master + effect: NoSchedule + operator: Exists + - key: node-role.kubernetes.io/control-plane + effect: NoSchedule + operator: Exists + {{- end }} + {{- with .Values.speaker.tolerations }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} + {{- with .Values.speaker.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} +{{- end }} diff --git a/metallb-chart/templates/webhooks.yaml b/metallb-chart/templates/webhooks.yaml new file mode 100644 index 0000000..3cdac01 --- /dev/null +++ b/metallb-chart/templates/webhooks.yaml @@ -0,0 +1,150 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: metallb-webhook-configuration + labels: + {{- include "metallb.labels" . | nindent 4 }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta2-bgppeer + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: bgppeervalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta2 + operations: + - CREATE + - UPDATE + resources: + - bgppeers + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-ipaddresspool + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: ipaddresspoolvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - ipaddresspools + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-bgpadvertisement + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: bgpadvertisementvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - bgpadvertisements + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-community + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: communityvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - communities + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-bfdprofile + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: bfdprofilevalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - DELETE + resources: + - bfdprofiles + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-l2advertisement + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: l2advertisementvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - l2advertisements + sideEffects: None +--- +apiVersion: v1 +kind: Service +metadata: + name: metallb-webhook-service + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "metallb.labels" . | nindent 4 }} +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + {{- include "metallb.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: controller +--- +apiVersion: v1 +kind: Secret +metadata: + name: metallb-webhook-cert + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "metallb.labels" . | nindent 4 }} diff --git a/sriov-crd-chart/templates.obscpio b/sriov-crd-chart/templates.obscpio deleted file mode 100644 index 3995b9fa48d11b897bcfbe85f5cbccf97c6c80c8704b0a4056481bc687b148ed..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47104 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 diff --git a/sriov-crd-chart/templates/sriovnetwork.openshift.io_ovsnetworks.yaml b/sriov-crd-chart/templates/sriovnetwork.openshift.io_ovsnetworks.yaml new file mode 100644 index 0000000..7e7d9ba --- /dev/null +++ b/sriov-crd-chart/templates/sriovnetwork.openshift.io_ovsnetworks.yaml @@ -0,0 +1,105 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ovsnetworks.sriovnetwork.openshift.io +spec: + group: sriovnetwork.openshift.io + names: + kind: OVSNetwork + listKind: OVSNetworkList + plural: ovsnetworks + singular: ovsnetwork + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OVSNetwork is the Schema for the ovsnetworks 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: OVSNetworkSpec defines the desired state of OVSNetwork + properties: + bridge: + description: |- + name of the OVS bridge, if not set OVS will automatically select bridge + based on VF PCI address + type: string + capabilities: + description: |- + Capabilities to be configured for this network. + Capabilities supported: (mac|ips), e.g. '{"mac": true}' + type: string + interfaceType: + description: The type of interface on ovs. + type: string + ipam: + description: IPAM configuration to be used for this network. + type: string + metaPlugins: + description: MetaPluginsConfig configuration to be used in order to + chain metaplugins + type: string + mtu: + description: Mtu for the OVS port + type: integer + networkNamespace: + description: Namespace of the NetworkAttachmentDefinition custom resource + type: string + resourceName: + description: OVS Network device plugin endpoint resource name + type: string + trunk: + description: Trunk configuration for the OVS port + items: + description: TrunkConfig contains configuration for bridge trunk + properties: + id: + maximum: 4095 + minimum: 0 + type: integer + maxID: + maximum: 4095 + minimum: 0 + type: integer + minID: + maximum: 4095 + minimum: 0 + type: integer + type: object + type: array + vlan: + description: Vlan to assign for the OVS port + maximum: 4095 + minimum: 0 + type: integer + required: + - resourceName + type: object + status: + description: OVSNetworkStatus defines the observed state of OVSNetwork + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovibnetworks.yaml b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovibnetworks.yaml new file mode 100644 index 0000000..8a4f88c --- /dev/null +++ b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovibnetworks.yaml @@ -0,0 +1,78 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: sriovibnetworks.sriovnetwork.openshift.io +spec: + group: sriovnetwork.openshift.io + names: + kind: SriovIBNetwork + listKind: SriovIBNetworkList + plural: sriovibnetworks + singular: sriovibnetwork + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: SriovIBNetwork is the Schema for the sriovibnetworks 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: SriovIBNetworkSpec defines the desired state of SriovIBNetwork + properties: + capabilities: + description: |- + Capabilities to be configured for this network. + Capabilities supported: (infinibandGUID), e.g. '{"infinibandGUID": true}' + type: string + ipam: + description: IPAM configuration to be used for this network. + type: string + linkState: + description: VF link state (enable|disable|auto) + enum: + - auto + - enable + - disable + type: string + metaPlugins: + description: |- + MetaPluginsConfig configuration to be used in order to chain metaplugins to the sriov interface returned + by the operator. + type: string + networkNamespace: + description: Namespace of the NetworkAttachmentDefinition custom resource + type: string + resourceName: + description: SRIOV Network device plugin endpoint resource name + type: string + required: + - resourceName + type: object + status: + description: SriovIBNetworkStatus defines the observed state of SriovIBNetwork + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworknodepolicies.yaml b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworknodepolicies.yaml new file mode 100644 index 0000000..47aacdd --- /dev/null +++ b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworknodepolicies.yaml @@ -0,0 +1,209 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: sriovnetworknodepolicies.sriovnetwork.openshift.io +spec: + group: sriovnetwork.openshift.io + names: + kind: SriovNetworkNodePolicy + listKind: SriovNetworkNodePolicyList + plural: sriovnetworknodepolicies + singular: sriovnetworknodepolicy + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: SriovNetworkNodePolicy is the Schema for the sriovnetworknodepolicies + 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: SriovNetworkNodePolicySpec defines the desired state of SriovNetworkNodePolicy + properties: + bridge: + description: |- + contains bridge configuration for matching PFs, + valid only for eSwitchMode==switchdev + properties: + ovs: + description: contains configuration for the OVS bridge, + properties: + bridge: + description: contains bridge level settings + properties: + datapathType: + description: configure datapath_type field in the Bridge + table in OVSDB + type: string + externalIDs: + additionalProperties: + type: string + description: IDs to inject to external_ids field in the + Bridge table in OVSDB + type: object + otherConfig: + additionalProperties: + type: string + description: additional options to inject to other_config + field in the bridge table in OVSDB + type: object + type: object + uplink: + description: contains settings for uplink (PF) + properties: + interface: + description: contains settings for PF interface in the + OVS bridge + properties: + externalIDs: + additionalProperties: + type: string + description: external_ids field in the Interface table + in OVSDB + type: object + options: + additionalProperties: + type: string + description: options field in the Interface table + in OVSDB + type: object + otherConfig: + additionalProperties: + type: string + description: other_config field in the Interface table + in OVSDB + type: object + type: + description: type field in the Interface table in + OVSDB + type: string + type: object + type: object + type: object + type: object + deviceType: + default: netdevice + description: The driver type for configured VFs. Allowed value "netdevice", + "vfio-pci". Defaults to netdevice. + enum: + - netdevice + - vfio-pci + type: string + eSwitchMode: + description: NIC Device Mode. Allowed value "legacy","switchdev". + enum: + - legacy + - switchdev + type: string + excludeTopology: + description: Exclude device's NUMA node when advertising this resource + by SRIOV network device plugin. Default to false. + type: boolean + externallyManaged: + description: don't create the virtual function only allocated them + to the device plugin. Defaults to false. + type: boolean + isRdma: + description: RDMA mode. Defaults to false. + type: boolean + linkType: + description: NIC Link Type. Allowed value "eth", "ETH", "ib", and + "IB". + enum: + - eth + - ETH + - ib + - IB + type: string + mtu: + description: MTU of VF + minimum: 1 + type: integer + needVhostNet: + description: mount vhost-net device. Defaults to false. + type: boolean + nicSelector: + description: NicSelector selects the NICs to be configured + properties: + deviceID: + description: The device hex code of SR-IoV device. Allowed value + "0d58", "1572", "158b", "1013", "1015", "1017", "101b". + type: string + netFilter: + description: Infrastructure Networking selection filter. Allowed + value "openstack/NetworkID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + type: string + pfNames: + description: Name of SR-IoV PF. + items: + type: string + type: array + rootDevices: + description: PCI address of SR-IoV PF. + items: + type: string + type: array + vendor: + description: The vendor hex code of SR-IoV device. Allowed value + "8086", "15b3". + type: string + type: object + nodeSelector: + additionalProperties: + type: string + description: NodeSelector selects the nodes to be configured + type: object + numVfs: + description: Number of VFs for each PF + minimum: 0 + type: integer + priority: + description: Priority of the policy, higher priority policies can + override lower ones. + maximum: 99 + minimum: 0 + type: integer + resourceName: + description: SRIOV Network device plugin endpoint resource name + type: string + vdpaType: + description: VDPA device type. Allowed value "virtio", "vhost" + enum: + - virtio + - vhost + type: string + required: + - nicSelector + - nodeSelector + - numVfs + - resourceName + type: object + status: + description: SriovNetworkNodePolicyStatus defines the observed state of + SriovNetworkNodePolicy + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworknodestates.yaml b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworknodestates.yaml new file mode 100644 index 0000000..6ed2486 --- /dev/null +++ b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworknodestates.yaml @@ -0,0 +1,343 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: sriovnetworknodestates.sriovnetwork.openshift.io +spec: + group: sriovnetwork.openshift.io + names: + kind: SriovNetworkNodeState + listKind: SriovNetworkNodeStateList + plural: sriovnetworknodestates + singular: sriovnetworknodestate + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.syncStatus + name: Sync Status + type: string + - jsonPath: .metadata.annotations.sriovnetwork\.openshift\.io/desired-state + name: Desired Sync State + type: string + - jsonPath: .metadata.annotations.sriovnetwork\.openshift\.io/current-state + name: Current Sync State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: SriovNetworkNodeState is the Schema for the sriovnetworknodestates + 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: SriovNetworkNodeStateSpec defines the desired state of SriovNetworkNodeState + properties: + bridges: + description: Bridges contains list of bridges + properties: + ovs: + items: + description: OVSConfigExt contains configuration for the concrete + OVS bridge + properties: + bridge: + description: bridge-level configuration for the bridge + properties: + datapathType: + description: configure datapath_type field in the Bridge + table in OVSDB + type: string + externalIDs: + additionalProperties: + type: string + description: IDs to inject to external_ids field in + the Bridge table in OVSDB + type: object + otherConfig: + additionalProperties: + type: string + description: additional options to inject to other_config + field in the bridge table in OVSDB + type: object + type: object + name: + description: name of the bridge + type: string + uplinks: + description: |- + uplink-level bridge configuration for each uplink(PF). + currently must contain only one element + items: + description: OVSUplinkConfigExt contains configuration + for the concrete OVS uplink(PF) + properties: + interface: + description: configuration from the Interface OVS + table for the PF + properties: + externalIDs: + additionalProperties: + type: string + description: external_ids field in the Interface + table in OVSDB + type: object + options: + additionalProperties: + type: string + description: options field in the Interface table + in OVSDB + type: object + otherConfig: + additionalProperties: + type: string + description: other_config field in the Interface + table in OVSDB + type: object + type: + description: type field in the Interface table + in OVSDB + type: string + type: object + name: + description: name of the PF interface + type: string + pciAddress: + description: pci address of the PF + type: string + required: + - pciAddress + type: object + type: array + required: + - name + type: object + type: array + type: object + interfaces: + items: + properties: + eSwitchMode: + type: string + externallyManaged: + type: boolean + linkType: + type: string + mtu: + type: integer + name: + type: string + numVfs: + type: integer + pciAddress: + type: string + vfGroups: + items: + properties: + deviceType: + type: string + isRdma: + type: boolean + mtu: + type: integer + policyName: + type: string + resourceName: + type: string + vdpaType: + type: string + vfRange: + type: string + type: object + type: array + required: + - pciAddress + type: object + type: array + type: object + status: + description: SriovNetworkNodeStateStatus defines the observed state of + SriovNetworkNodeState + properties: + bridges: + description: Bridges contains list of bridges + properties: + ovs: + items: + description: OVSConfigExt contains configuration for the concrete + OVS bridge + properties: + bridge: + description: bridge-level configuration for the bridge + properties: + datapathType: + description: configure datapath_type field in the Bridge + table in OVSDB + type: string + externalIDs: + additionalProperties: + type: string + description: IDs to inject to external_ids field in + the Bridge table in OVSDB + type: object + otherConfig: + additionalProperties: + type: string + description: additional options to inject to other_config + field in the bridge table in OVSDB + type: object + type: object + name: + description: name of the bridge + type: string + uplinks: + description: |- + uplink-level bridge configuration for each uplink(PF). + currently must contain only one element + items: + description: OVSUplinkConfigExt contains configuration + for the concrete OVS uplink(PF) + properties: + interface: + description: configuration from the Interface OVS + table for the PF + properties: + externalIDs: + additionalProperties: + type: string + description: external_ids field in the Interface + table in OVSDB + type: object + options: + additionalProperties: + type: string + description: options field in the Interface table + in OVSDB + type: object + otherConfig: + additionalProperties: + type: string + description: other_config field in the Interface + table in OVSDB + type: object + type: + description: type field in the Interface table + in OVSDB + type: string + type: object + name: + description: name of the PF interface + type: string + pciAddress: + description: pci address of the PF + type: string + required: + - pciAddress + type: object + type: array + required: + - name + type: object + type: array + type: object + interfaces: + items: + properties: + Vfs: + items: + properties: + Vlan: + type: integer + assigned: + type: string + deviceID: + type: string + driver: + type: string + guid: + type: string + mac: + type: string + mtu: + type: integer + name: + type: string + pciAddress: + type: string + representorName: + type: string + vdpaType: + type: string + vendor: + type: string + vfID: + type: integer + required: + - pciAddress + - vfID + type: object + type: array + deviceID: + type: string + driver: + type: string + eSwitchMode: + type: string + externallyManaged: + type: boolean + linkAdminState: + type: string + linkSpeed: + type: string + linkType: + type: string + mac: + type: string + mtu: + type: integer + name: + type: string + netFilter: + type: string + numVfs: + type: integer + pciAddress: + type: string + totalvfs: + type: integer + vendor: + type: string + required: + - pciAddress + type: object + type: array + lastSyncError: + type: string + syncStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworkpoolconfigs.yaml b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworkpoolconfigs.yaml new file mode 100644 index 0000000..502e0eb --- /dev/null +++ b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworkpoolconfigs.yaml @@ -0,0 +1,123 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: sriovnetworkpoolconfigs.sriovnetwork.openshift.io +spec: + group: sriovnetwork.openshift.io + names: + kind: SriovNetworkPoolConfig + listKind: SriovNetworkPoolConfigList + plural: sriovnetworkpoolconfigs + singular: sriovnetworkpoolconfig + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: SriovNetworkPoolConfig is the Schema for the sriovnetworkpoolconfigs + 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: SriovNetworkPoolConfigSpec defines the desired state of SriovNetworkPoolConfig + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: |- + maxUnavailable defines either an integer number or percentage + of nodes in the pool that can go Unavailable during an update. + + + A value larger than 1 will mean multiple nodes going unavailable during + the update, which may affect your workload stress on the remaining nodes. + Drain will respect Pod Disruption Budgets (PDBs) such as etcd quorum guards, + even if maxUnavailable is greater than one. + x-kubernetes-int-or-string: true + nodeSelector: + description: nodeSelector specifies a label selector for Nodes + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + ovsHardwareOffloadConfig: + description: OvsHardwareOffloadConfig describes the OVS HWOL configuration + for selected Nodes + properties: + name: + description: |- + Name is mandatory and must be unique. + On Kubernetes: + Name is the name of OvsHardwareOffloadConfig + On OpenShift: + Name is the name of MachineConfigPool to be enabled with OVS hardware offload + type: string + type: object + type: object + status: + description: SriovNetworkPoolConfigStatus defines the observed state of + SriovNetworkPoolConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworks.yaml b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworks.yaml new file mode 100644 index 0000000..cd807f9 --- /dev/null +++ b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovnetworks.yaml @@ -0,0 +1,136 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: sriovnetworks.sriovnetwork.openshift.io +spec: + group: sriovnetwork.openshift.io + names: + kind: SriovNetwork + listKind: SriovNetworkList + plural: sriovnetworks + singular: sriovnetwork + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: SriovNetwork is the Schema for the sriovnetworks 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: SriovNetworkSpec defines the desired state of SriovNetwork + properties: + capabilities: + description: |- + Capabilities to be configured for this network. + Capabilities supported: (mac|ips), e.g. '{"mac": true}' + type: string + ipam: + description: IPAM configuration to be used for this network. + type: string + linkState: + description: VF link state (enable|disable|auto) + enum: + - auto + - enable + - disable + type: string + logFile: + description: |- + LogFile sets the log file of the SRIOV CNI plugin logs. If unset (default), this will log to stderr and thus + to multus and container runtime logs. + type: string + logLevel: + default: info + description: |- + LogLevel sets the log level of the SRIOV CNI plugin - either of panic, error, warning, info, debug. Defaults + to info if left blank. + enum: + - panic + - error + - warning + - info + - debug + - "" + type: string + maxTxRate: + description: Maximum tx rate, in Mbps, for the VF. Defaults to 0 (no + rate limiting) + minimum: 0 + type: integer + metaPlugins: + description: |- + MetaPluginsConfig configuration to be used in order to chain metaplugins to the sriov interface returned + by the operator. + type: string + minTxRate: + description: Minimum tx rate, in Mbps, for the VF. Defaults to 0 (no + rate limiting). min_tx_rate should be <= max_tx_rate. + minimum: 0 + type: integer + networkNamespace: + description: Namespace of the NetworkAttachmentDefinition custom resource + type: string + resourceName: + description: SRIOV Network device plugin endpoint resource name + type: string + spoofChk: + description: VF spoof check, (on|off) + enum: + - "on" + - "off" + type: string + trust: + description: VF trust mode (on|off) + enum: + - "on" + - "off" + type: string + vlan: + description: VLAN ID to assign for the VF. Defaults to 0. + maximum: 4096 + minimum: 0 + type: integer + vlanProto: + description: VLAN proto to assign for the VF. Defaults to 802.1q. + enum: + - 802.1q + - 802.1Q + - 802.1ad + - 802.1AD + type: string + vlanQoS: + description: VLAN QoS ID to assign for the VF. Defaults to 0. + maximum: 7 + minimum: 0 + type: integer + required: + - resourceName + type: object + status: + description: SriovNetworkStatus defines the observed state of SriovNetwork + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovoperatorconfigs.yaml b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovoperatorconfigs.yaml new file mode 100644 index 0000000..49d5429 --- /dev/null +++ b/sriov-crd-chart/templates/sriovnetwork.openshift.io_sriovoperatorconfigs.yaml @@ -0,0 +1,114 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: sriovoperatorconfigs.sriovnetwork.openshift.io +spec: + group: sriovnetwork.openshift.io + names: + kind: SriovOperatorConfig + listKind: SriovOperatorConfigList + plural: sriovoperatorconfigs + singular: sriovoperatorconfig + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: SriovOperatorConfig is the Schema for the sriovoperatorconfigs + 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: SriovOperatorConfigSpec defines the desired state of SriovOperatorConfig + properties: + configDaemonNodeSelector: + additionalProperties: + type: string + description: NodeSelector selects the nodes to be configured + type: object + configurationMode: + description: |- + Flag to enable the sriov-network-config-daemon to use a systemd service to configure SR-IOV devices on boot + Default mode: daemon + enum: + - daemon + - systemd + type: string + disableDrain: + description: Flag to disable nodes drain during debugging + type: boolean + disablePlugins: + description: DisablePlugins is a list of sriov-network-config-daemon + plugins to disable + items: + description: PluginNameValue defines the plugin name + enum: + - mellanox + type: string + type: array + enableInjector: + description: Flag to control whether the network resource injector + webhook shall be deployed + type: boolean + enableOperatorWebhook: + description: Flag to control whether the operator admission controller + webhook shall be deployed + type: boolean + enableOvsOffload: + description: Flag to enable OVS hardware offload. Set to 'true' to + provision switchdev-configuration.service and enable OpenvSwitch + hw-offload on nodes. + type: boolean + featureGates: + additionalProperties: + type: boolean + description: FeatureGates to enable experimental features + type: object + logLevel: + description: Flag to control the log verbose level of the operator. + Set to '0' to show only the basic logs. And set to '2' to show all + the available logs. + maximum: 2 + minimum: 0 + type: integer + useCDI: + description: Flag to enable Container Device Interface mode for SR-IOV + Network Device Plugin + type: boolean + type: object + status: + description: SriovOperatorConfigStatus defines the observed state of SriovOperatorConfig + properties: + injector: + description: Show the runtime status of the network resource injector + webhook + type: string + operatorWebhook: + description: Show the runtime status of the operator admission controller + webhook + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/sriov-network-operator-chart/charts.obscpio b/sriov-network-operator-chart/charts.obscpio deleted file mode 100644 index 829a2b43ad300e0c36883a1df78a297e772ffb6a170d27eae45cf79ec982f851..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90112 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 diff --git a/sriov-network-operator-chart/charts/sriov-nfd/.helmignore b/sriov-network-operator-chart/charts/sriov-nfd/.helmignore new file mode 100644 index 0000000..1b9a9cc --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/.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/sriov-network-operator-chart/charts/sriov-nfd/Chart.yaml b/sriov-network-operator-chart/charts/sriov-nfd/Chart.yaml new file mode 100644 index 0000000..5415b0d --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +appVersion: v0.15.6 +description: Detects hardware features available on each node in a Kubernetes cluster, + and advertises those features using node labels +home: https://github.com/kubernetes-sigs/node-feature-discovery +keywords: +- feature-discovery +- feature-detection +- node-labels +name: sriov-nfd +sources: +- https://github.com/kubernetes-sigs/node-feature-discovery +type: application +version: 0.15.6 diff --git a/sriov-network-operator-chart/charts/sriov-nfd/README.md b/sriov-network-operator-chart/charts/sriov-nfd/README.md new file mode 100644 index 0000000..9aa6c75 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/README.md @@ -0,0 +1,10 @@ +# Node Feature Discovery + +Node Feature Discovery (NFD) is a Kubernetes add-on for detecting hardware +features and system configuration. Detected features are advertised as node +labels. NFD provides flexible configuration and extension points for a wide +range of vendor and application specific node labeling needs. + +See +[NFD documentation](https://kubernetes-sigs.github.io/node-feature-discovery/v0.15/deployment/helm.html) +for deployment instructions. diff --git a/sriov-network-operator-chart/charts/sriov-nfd/crds/nfd-api-crds.yaml b/sriov-network-operator-chart/charts/sriov-nfd/crds/nfd-api-crds.yaml new file mode 100644 index 0000000..0339f35 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/crds/nfd-api-crds.yaml @@ -0,0 +1,426 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + name: nodefeatures.nfd.k8s-sigs.io +spec: + group: nfd.k8s-sigs.io + names: + kind: NodeFeature + listKind: NodeFeatureList + plural: nodefeatures + singular: nodefeature + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NodeFeature resource holds the features discovered for one node + in the cluster. + 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: NodeFeatureSpec describes a NodeFeature object. + properties: + features: + description: Features is the full "raw" features data that has been + discovered. + properties: + attributes: + additionalProperties: + description: AttributeFeatureSet is a set of features having + string value. + properties: + elements: + additionalProperties: + type: string + type: object + required: + - elements + type: object + description: Attributes contains all the attribute-type features + of the node. + type: object + flags: + additionalProperties: + description: FlagFeatureSet is a set of simple features only + containing names without values. + properties: + elements: + additionalProperties: + description: Nil is a dummy empty struct for protobuf + compatibility + type: object + type: object + required: + - elements + type: object + description: Flags contains all the flag-type features of the + node. + type: object + instances: + additionalProperties: + description: InstanceFeatureSet is a set of features each of + which is an instance having multiple attributes. + properties: + elements: + items: + description: InstanceFeature represents one instance of + a complex features, e.g. a device. + properties: + attributes: + additionalProperties: + type: string + type: object + required: + - attributes + type: object + type: array + required: + - elements + type: object + description: Instances contains all the instance-type features + of the node. + type: object + type: object + labels: + additionalProperties: + type: string + description: Labels is the set of node labels that are requested to + be created. + type: object + type: object + required: + - spec + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + name: nodefeaturerules.nfd.k8s-sigs.io +spec: + group: nfd.k8s-sigs.io + names: + kind: NodeFeatureRule + listKind: NodeFeatureRuleList + plural: nodefeaturerules + shortNames: + - nfr + singular: nodefeaturerule + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NodeFeatureRule resource specifies a configuration for feature-based + customization of node objects, such as node labeling. + 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: NodeFeatureRuleSpec describes a NodeFeatureRule. + properties: + rules: + description: Rules is a list of node customization rules. + items: + description: Rule defines a rule for node customization such as + labeling. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to create if the rule matches. + type: object + extendedResources: + additionalProperties: + type: string + description: ExtendedResources to create if the rule matches. + type: object + labels: + additionalProperties: + type: string + description: Labels to create if the rule matches. + type: object + labelsTemplate: + description: LabelsTemplate specifies a template to expand for + dynamically generating multiple labels. Data (after template + expansion) must be keys with an optional value ([=]) + separated by newlines. + type: string + matchAny: + description: MatchAny specifies a list of matchers one of which + must match. + items: + description: MatchAnyElem specifies one sub-matcher of MatchAny. + properties: + matchFeatures: + description: MatchFeatures specifies a set of matcher + terms all of which must match. + items: + description: FeatureMatcherTerm defines requirements + against one feature set. All requirements (specified + as MatchExpressions) are evaluated against each element + in the feature set. + properties: + feature: + description: Feature is the name of the feature + set to match against. + type: string + matchExpressions: + additionalProperties: + description: MatchExpression specifies an expression + to evaluate against a set of input values. It + contains an operator that is applied when matching + the input and an array of values that the operator + evaluates the input against. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: Value is the list of values that + the operand evaluates the input against. + Value should be empty if the operator is + Exists, DoesNotExist, IsTrue or IsFalse. + Value should contain exactly one element + if the operator is Gt or Lt and exactly + two elements if the operator is GtLt. In + other cases Value should contain at least + one element. + items: + type: string + type: array + required: + - op + type: object + description: MatchExpressions is the set of per-element + expressions evaluated. These match against the + value of the specified elements. + type: object + matchName: + description: MatchName in an expression that is + matched against the name of each element in the + feature set. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: Value is the list of values that + the operand evaluates the input against. Value + should be empty if the operator is Exists, + DoesNotExist, IsTrue or IsFalse. Value should + contain exactly one element if the operator + is Gt or Lt and exactly two elements if the + operator is GtLt. In other cases Value should + contain at least one element. + items: + type: string + type: array + required: + - op + type: object + required: + - feature + type: object + type: array + required: + - matchFeatures + type: object + type: array + matchFeatures: + description: MatchFeatures specifies a set of matcher terms + all of which must match. + items: + description: FeatureMatcherTerm defines requirements against + one feature set. All requirements (specified as MatchExpressions) + are evaluated against each element in the feature set. + properties: + feature: + description: Feature is the name of the feature set to + match against. + type: string + matchExpressions: + additionalProperties: + description: MatchExpression specifies an expression + to evaluate against a set of input values. It contains + an operator that is applied when matching the input + and an array of values that the operator evaluates + the input against. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: Value is the list of values that the + operand evaluates the input against. Value should + be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly + one element if the operator is Gt or Lt and exactly + two elements if the operator is GtLt. In other + cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + description: MatchExpressions is the set of per-element + expressions evaluated. These match against the value + of the specified elements. + type: object + matchName: + description: MatchName in an expression that is matched + against the name of each element in the feature set. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: Value is the list of values that the + operand evaluates the input against. Value should + be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly + one element if the operator is Gt or Lt and exactly + two elements if the operator is GtLt. In other cases + Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + required: + - feature + type: object + type: array + name: + description: Name of the rule. + type: string + taints: + description: Taints to create if the rule matches. + 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 + vars: + additionalProperties: + type: string + description: Vars is the variables to store if the rule matches. + Variables do not directly inflict any changes in the node + object. However, they can be referenced from other rules enabling + more complex rule hierarchies, without exposing intermediary + output values as labels. + type: object + varsTemplate: + description: VarsTemplate specifies a template to expand for + dynamically generating multiple variables. Data (after template + expansion) must be keys with an optional value ([=]) + separated by newlines. + type: string + required: + - name + type: object + type: array + required: + - rules + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/_helpers.tpl b/sriov-network-operator-chart/charts/sriov-nfd/templates/_helpers.tpl new file mode 100644 index 0000000..f8b1e30 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/_helpers.tpl @@ -0,0 +1,107 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "node-feature-discovery.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 "node-feature-discovery.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 -}} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "node-feature-discovery.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "node-feature-discovery.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "node-feature-discovery.labels" -}} +helm.sh/chart: {{ include "node-feature-discovery.chart" . }} +{{ include "node-feature-discovery.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define "node-feature-discovery.selectorLabels" -}} +app.kubernetes.io/name: {{ include "node-feature-discovery.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Create the name of the service account which the nfd master will use +*/}} +{{- define "node-feature-discovery.master.serviceAccountName" -}} +{{- if .Values.master.serviceAccount.create -}} + {{ default (include "node-feature-discovery.fullname" .) .Values.master.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.master.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account which the nfd worker will use +*/}} +{{- define "node-feature-discovery.worker.serviceAccountName" -}} +{{- if .Values.worker.serviceAccount.create -}} + {{ default (printf "%s-worker" (include "node-feature-discovery.fullname" .)) .Values.worker.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.worker.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account which topologyUpdater will use +*/}} +{{- define "node-feature-discovery.topologyUpdater.serviceAccountName" -}} +{{- if .Values.topologyUpdater.serviceAccount.create -}} + {{ default (printf "%s-topology-updater" (include "node-feature-discovery.fullname" .)) .Values.topologyUpdater.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.topologyUpdater.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account which nfd-gc will use +*/}} +{{- define "node-feature-discovery.gc.serviceAccountName" -}} +{{- if .Values.gc.serviceAccount.create -}} + {{ default (printf "%s-gc" (include "node-feature-discovery.fullname" .)) .Values.gc.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.gc.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/cert-manager-certs.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/cert-manager-certs.yaml new file mode 100644 index 0000000..43a647a --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/cert-manager-certs.yaml @@ -0,0 +1,68 @@ +{{- if .Values.tls.certManager }} +{{- if .Values.master.enable }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: nfd-master-cert + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + secretName: nfd-master-cert + subject: + organizations: + - node-feature-discovery + commonName: nfd-master + dnsNames: + # must match the service name + - {{ include "node-feature-discovery.fullname" . }}-master + # first one is configured for use by the worker; below are for completeness + - {{ include "node-feature-discovery.fullname" . }}-master.{{ include "node-feature-discovery.namespace" . }}.svc + - {{ include "node-feature-discovery.fullname" . }}-master.{{ include "node-feature-discovery.namespace" . }}.svc.cluster.local + issuerRef: + name: nfd-ca-issuer + kind: Issuer + group: cert-manager.io +{{- end }} +--- +{{- if .Values.worker.enable }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: nfd-worker-cert + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + secretName: nfd-worker-cert + subject: + organizations: + - node-feature-discovery + commonName: nfd-worker + dnsNames: + - {{ include "node-feature-discovery.fullname" . }}-worker.{{ include "node-feature-discovery.namespace" . }}.svc.cluster.local + issuerRef: + name: nfd-ca-issuer + kind: Issuer + group: cert-manager.io +{{- end }} + +{{- if .Values.topologyUpdater.enable }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: nfd-topology-updater-cert + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + secretName: nfd-topology-updater-cert + subject: + organizations: + - node-feature-discovery + commonName: nfd-topology-updater + dnsNames: + - {{ include "node-feature-discovery.fullname" . }}-topology-updater.{{ include "node-feature-discovery.namespace" . }}.svc.cluster.local + issuerRef: + name: nfd-ca-issuer + kind: Issuer + group: cert-manager.io +{{- end }} + +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/cert-manager-issuer.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/cert-manager-issuer.yaml new file mode 100644 index 0000000..742ebe1 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/cert-manager-issuer.yaml @@ -0,0 +1,42 @@ +{{- if .Values.tls.certManager }} +# See https://cert-manager.io/docs/configuration/selfsigned/#bootstrapping-ca-issuers +# - Create a self signed issuer +# - Use this to create a CA cert +# - Use this to now create a CA issuer +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: nfd-ca-bootstrap + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + selfSigned: {} + +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: nfd-ca-cert + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + isCA: true + secretName: nfd-ca-cert + subject: + organizations: + - node-feature-discovery + commonName: nfd-ca-cert + issuerRef: + name: nfd-ca-bootstrap + kind: Issuer + group: cert-manager.io + +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: nfd-ca-issuer + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + ca: + secretName: nfd-ca-cert +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/clusterrole.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/clusterrole.yaml new file mode 100644 index 0000000..8853613 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/clusterrole.yaml @@ -0,0 +1,119 @@ +{{- if and .Values.master.enable .Values.master.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "node-feature-discovery.fullname" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - nodes + - nodes/status + verbs: + - get + - patch + - update + - list +- apiGroups: + - nfd.k8s-sigs.io + resources: + - nodefeatures + - nodefeaturerules + verbs: + - get + - list + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create +- apiGroups: + - coordination.k8s.io + resources: + - leases + resourceNames: + - "nfd-master.nfd.kubernetes.io" + verbs: + - get + - update +{{- end }} + +{{- if and .Values.topologyUpdater.enable .Values.topologyUpdater.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list +- apiGroups: + - "" + resources: + - nodes/proxy + verbs: + - get +- apiGroups: + - "" + resources: + - pods + verbs: + - get +- apiGroups: + - topology.node.k8s.io + resources: + - noderesourcetopologies + verbs: + - create + - get + - update +{{- end }} + +{{- if and .Values.gc.enable .Values.gc.rbac.create (or .Values.enableNodeFeatureApi .Values.topologyUpdater.enable) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-gc + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - nodes + verbs: + - list + - watch +- apiGroups: + - "" + resources: + - nodes/proxy + verbs: + - get +- apiGroups: + - topology.node.k8s.io + resources: + - noderesourcetopologies + verbs: + - delete + - list +- apiGroups: + - nfd.k8s-sigs.io + resources: + - nodefeatures + verbs: + - delete + - list +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/clusterrolebinding.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..1d49ec5 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/clusterrolebinding.yaml @@ -0,0 +1,52 @@ +{{- if and .Values.master.enable .Values.master.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "node-feature-discovery.fullname" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "node-feature-discovery.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "node-feature-discovery.master.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} +{{- end }} + +{{- if and .Values.topologyUpdater.enable .Values.topologyUpdater.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater +subjects: +- kind: ServiceAccount + name: {{ include "node-feature-discovery.topologyUpdater.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} +{{- end }} + +{{- if and .Values.gc.enable .Values.gc.rbac.create (or .Values.enableNodeFeatureApi .Values.topologyUpdater.enable) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-gc + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "node-feature-discovery.fullname" . }}-gc +subjects: +- kind: ServiceAccount + name: {{ include "node-feature-discovery.gc.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/master.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/master.yaml new file mode 100644 index 0000000..19b543a --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/master.yaml @@ -0,0 +1,145 @@ +{{- if .Values.master.enable }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-master + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + role: master + {{- with .Values.master.deploymentAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.master.replicaCount }} + selector: + matchLabels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 6 }} + role: master + template: + metadata: + labels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 8 }} + role: master + {{- with .Values.master.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "node-feature-discovery.master.serviceAccountName" . }} + enableServiceLinks: false + securityContext: + {{- toYaml .Values.master.podSecurityContext | nindent 8 }} + containers: + - name: master + securityContext: + {{- toYaml .Values.master.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + livenessProbe: + grpc: + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 10 + readinessProbe: + grpc: + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 10 + ports: + - containerPort: {{ .Values.master.port | default "8080" }} + name: grpc + - containerPort: {{ .Values.master.metricsPort | default "8081" }} + name: metrics + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + command: + - "nfd-master" + resources: + {{- toYaml .Values.master.resources | nindent 12 }} + args: + {{- if .Values.master.instance | empty | not }} + - "-instance={{ .Values.master.instance }}" + {{- end }} + {{- if not .Values.enableNodeFeatureApi }} + - "-port={{ .Values.master.port | default "8080" }}" + - "-enable-nodefeature-api=false" + {{- else if gt (int .Values.master.replicaCount) 1 }} + - "-enable-leader-election" + {{- end }} + {{- if .Values.master.extraLabelNs | empty | not }} + - "-extra-label-ns={{- join "," .Values.master.extraLabelNs }}" + {{- end }} + {{- if .Values.master.denyLabelNs | empty | not }} + - "-deny-label-ns={{- join "," .Values.master.denyLabelNs }}" + {{- end }} + {{- if .Values.master.resourceLabels | empty | not }} + - "-resource-labels={{- join "," .Values.master.resourceLabels }}" + {{- end }} + {{- if .Values.master.enableTaints }} + - "-enable-taints" + {{- end }} + {{- if .Values.master.crdController | kindIs "invalid" | not }} + - "-crd-controller={{ .Values.master.crdController }}" + {{- else }} + ## By default, disable crd controller for other than the default instances + - "-crd-controller={{ .Values.master.instance | empty }}" + {{- end }} + {{- if .Values.master.featureRulesController | kindIs "invalid" | not }} + - "-featurerules-controller={{ .Values.master.featureRulesController }}" + {{- end }} + {{- if .Values.master.resyncPeriod }} + - "-resync-period={{ .Values.master.resyncPeriod }}" + {{- end }} + {{- if .Values.master.nfdApiParallelism | empty | not }} + - "-nfd-api-parallelism={{ .Values.master.nfdApiParallelism }}" + {{- end }} + {{- if .Values.tls.enable }} + - "-ca-file=/etc/kubernetes/node-feature-discovery/certs/ca.crt" + - "-key-file=/etc/kubernetes/node-feature-discovery/certs/tls.key" + - "-cert-file=/etc/kubernetes/node-feature-discovery/certs/tls.crt" + {{- end }} + - "-metrics={{ .Values.master.metricsPort | default "8081" }}" + volumeMounts: + {{- if .Values.tls.enable }} + - name: nfd-master-cert + mountPath: "/etc/kubernetes/node-feature-discovery/certs" + readOnly: true + {{- end }} + - name: nfd-master-conf + mountPath: "/etc/kubernetes/node-feature-discovery" + readOnly: true + volumes: + {{- if .Values.tls.enable }} + - name: nfd-master-cert + secret: + secretName: nfd-master-cert + {{- end }} + - name: nfd-master-conf + configMap: + name: {{ include "node-feature-discovery.fullname" . }}-master-conf + items: + - key: nfd-master.conf + path: nfd-master.conf + {{- with .Values.master.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.master.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.master.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-gc.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-gc.yaml new file mode 100644 index 0000000..641202b --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-gc.yaml @@ -0,0 +1,77 @@ +{{- if and .Values.gc.enable (or .Values.enableNodeFeatureApi .Values.topologyUpdater.enable) -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-gc + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + role: gc + {{- with .Values.gc.deploymentAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.gc.replicaCount | default 1 }} + selector: + matchLabels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 6 }} + role: gc + template: + metadata: + labels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 8 }} + role: gc + {{- with .Values.gc.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "node-feature-discovery.gc.serviceAccountName" . }} + dnsPolicy: ClusterFirstWithHostNet + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.gc.podSecurityContext | nindent 8 }} + containers: + - name: gc + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + command: + - "nfd-gc" + args: + {{- if .Values.gc.interval | empty | not }} + - "-gc-interval={{ .Values.gc.interval }}" + {{- end }} + resources: + {{- toYaml .Values.gc.resources | nindent 12 }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: [ "ALL" ] + readOnlyRootFilesystem: true + runAsNonRoot: true + ports: + - name: metrics + containerPort: {{ .Values.gc.metricsPort | default "8081"}} + + {{- with .Values.gc.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.gc.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.gc.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-master-conf.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-master-conf.yaml new file mode 100644 index 0000000..be92601 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-master-conf.yaml @@ -0,0 +1,12 @@ +{{- if .Values.master.enable }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-master-conf + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +data: + nfd-master.conf: |- + {{- .Values.master.config | toYaml | nindent 4 }} +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-topologyupdater-conf.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-topologyupdater-conf.yaml new file mode 100644 index 0000000..1680d69 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-topologyupdater-conf.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater-conf + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +data: + nfd-topology-updater.conf: |- + {{- .Values.topologyUpdater.config | toYaml | nindent 4 }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-worker-conf.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-worker-conf.yaml new file mode 100644 index 0000000..3e1148d --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/nfd-worker-conf.yaml @@ -0,0 +1,12 @@ +{{- if .Values.worker.enable }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-worker-conf + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +data: + nfd-worker.conf: |- + {{- .Values.worker.config | toYaml | nindent 4 }} +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/prometheus.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/prometheus.yaml new file mode 100644 index 0000000..cbc8f85 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/prometheus.yaml @@ -0,0 +1,26 @@ +{{- if .Values.prometheus.enable }} +# Prometheus Monitor Service (Metrics) +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: {{ include "node-feature-discovery.fullname" . }} + labels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 4 }} + {{- with .Values.prometheus.labels }} + {{ toYaml . | nindent 4 }} + {{- end }} +spec: + podMetricsEndpoints: + - honorLabels: true + interval: 10s + path: /metrics + port: metrics + scheme: http + namespaceSelector: + matchNames: + - {{ include "node-feature-discovery.namespace" . }} + selector: + matchExpressions: + - {key: app.kubernetes.io/instance, operator: In, values: ["{{ .Release.Name }}"]} + - {key: app.kubernetes.io/name, operator: In, values: ["{{ include "node-feature-discovery.name" . }}"]} +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/role.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/role.yaml new file mode 100644 index 0000000..06ca73e --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/role.yaml @@ -0,0 +1,24 @@ +{{- if and .Values.worker.enable .Values.worker.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-worker + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +rules: +- apiGroups: + - nfd.k8s-sigs.io + resources: + - nodefeatures + verbs: + - create + - get + - update +- apiGroups: + - "" + resources: + - pods + verbs: + - get +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/rolebinding.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/rolebinding.yaml new file mode 100644 index 0000000..46ac7f7 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/rolebinding.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.worker.enable .Values.worker.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-worker + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "node-feature-discovery.fullname" . }}-worker +subjects: +- kind: ServiceAccount + name: {{ include "node-feature-discovery.worker.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} +{{- end }} + diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/service.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/service.yaml new file mode 100644 index 0000000..a82c22d --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/service.yaml @@ -0,0 +1,20 @@ +{{- if and (not .Values.enableNodeFeatureApi) .Values.master.enable }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-master + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + role: master +spec: + type: {{ .Values.master.service.type }} + ports: + - port: {{ .Values.master.service.port | default "8080" }} + targetPort: grpc + protocol: TCP + name: grpc + selector: + {{- include "node-feature-discovery.selectorLabels" . | nindent 4 }} + role: master +{{- end}} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/serviceaccount.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/serviceaccount.yaml new file mode 100644 index 0000000..52706f7 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/serviceaccount.yaml @@ -0,0 +1,58 @@ +{{- if and .Values.master.enable .Values.master.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "node-feature-discovery.master.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + {{- with .Values.master.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} + +{{- if and .Values.topologyUpdater.enable .Values.topologyUpdater.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "node-feature-discovery.topologyUpdater.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + {{- with .Values.topologyUpdater.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} + +{{- if and .Values.gc.enable .Values.gc.serviceAccount.create (or .Values.enableNodeFeatureApi .Values.topologyUpdater.enable) }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "node-feature-discovery.gc.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + {{- with .Values.gc.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} + +{{- if and .Values.worker.enable .Values.worker.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "node-feature-discovery.worker.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + {{- with .Values.worker.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/topologyupdater-crds.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/topologyupdater-crds.yaml new file mode 100644 index 0000000..94b7b35 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/topologyupdater-crds.yaml @@ -0,0 +1,278 @@ +{{- if and .Values.topologyUpdater.enable .Values.topologyUpdater.createCRDs -}} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/pull/1870 + controller-gen.kubebuilder.io/version: v0.11.2 + creationTimestamp: null + name: noderesourcetopologies.topology.node.k8s.io +spec: + group: topology.node.k8s.io + names: + kind: NodeResourceTopology + listKind: NodeResourceTopologyList + plural: noderesourcetopologies + shortNames: + - node-res-topo + singular: noderesourcetopology + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NodeResourceTopology describes node resources and their topology. + 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 + topologyPolicies: + items: + type: string + type: array + zones: + description: ZoneList contains an array of Zone objects. + items: + description: Zone represents a resource topology zone, e.g. socket, + node, die or core. + properties: + attributes: + description: AttributeList contains an array of AttributeInfo objects. + items: + description: AttributeInfo contains one attribute of a Zone. + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + costs: + description: CostList contains an array of CostInfo objects. + items: + description: CostInfo describes the cost (or distance) between + two Zones. + properties: + name: + type: string + value: + format: int64 + type: integer + required: + - name + - value + type: object + type: array + name: + type: string + parent: + type: string + resources: + description: ResourceInfoList contains an array of ResourceInfo + objects. + items: + description: ResourceInfo contains information about one resource + type. + properties: + allocatable: + anyOf: + - type: integer + - type: string + description: Allocatable quantity of the resource, corresponding + to allocatable in node status, i.e. total amount of this + resource available to be used by pods. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + available: + anyOf: + - type: integer + - type: string + description: Available is the amount of this resource currently + available for new (to be scheduled) pods, i.e. Allocatable + minus the resources reserved by currently running pods. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + capacity: + anyOf: + - type: integer + - type: string + description: Capacity of the resource, corresponding to capacity + in node status, i.e. total amount of this resource that + the node has. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + name: + description: Name of the resource. + type: string + required: + - allocatable + - available + - capacity + - name + type: object + type: array + type: + type: string + required: + - name + - type + type: object + type: array + required: + - topologyPolicies + - zones + type: object + served: true + storage: false + - name: v1alpha2 + schema: + openAPIV3Schema: + description: NodeResourceTopology describes node resources and their topology. + 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 + attributes: + description: AttributeList contains an array of AttributeInfo objects. + items: + description: AttributeInfo contains one attribute of a Zone. + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + 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 + topologyPolicies: + description: 'DEPRECATED (to be removed in v1beta1): use top level attributes + if needed' + items: + type: string + type: array + zones: + description: ZoneList contains an array of Zone objects. + items: + description: Zone represents a resource topology zone, e.g. socket, + node, die or core. + properties: + attributes: + description: AttributeList contains an array of AttributeInfo objects. + items: + description: AttributeInfo contains one attribute of a Zone. + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + costs: + description: CostList contains an array of CostInfo objects. + items: + description: CostInfo describes the cost (or distance) between + two Zones. + properties: + name: + type: string + value: + format: int64 + type: integer + required: + - name + - value + type: object + type: array + name: + type: string + parent: + type: string + resources: + description: ResourceInfoList contains an array of ResourceInfo + objects. + items: + description: ResourceInfo contains information about one resource + type. + properties: + allocatable: + anyOf: + - type: integer + - type: string + description: Allocatable quantity of the resource, corresponding + to allocatable in node status, i.e. total amount of this + resource available to be used by pods. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + available: + anyOf: + - type: integer + - type: string + description: Available is the amount of this resource currently + available for new (to be scheduled) pods, i.e. Allocatable + minus the resources reserved by currently running pods. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + capacity: + anyOf: + - type: integer + - type: string + description: Capacity of the resource, corresponding to capacity + in node status, i.e. total amount of this resource that + the node has. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + name: + description: Name of the resource. + type: string + required: + - allocatable + - available + - capacity + - name + type: object + type: array + type: + type: string + required: + - name + - type + type: object + type: array + required: + - zones + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/topologyupdater.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/topologyupdater.yaml new file mode 100644 index 0000000..28ed58b --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/topologyupdater.yaml @@ -0,0 +1,156 @@ +{{- if .Values.topologyUpdater.enable -}} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + role: topology-updater + {{- with .Values.topologyUpdater.daemonsetAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 6 }} + role: topology-updater + template: + metadata: + labels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 8 }} + role: topology-updater + {{- with .Values.topologyUpdater.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "node-feature-discovery.topologyUpdater.serviceAccountName" . }} + dnsPolicy: ClusterFirstWithHostNet + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.topologyUpdater.podSecurityContext | nindent 8 }} + containers: + - name: topology-updater + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: NODE_ADDRESS + valueFrom: + fieldRef: + fieldPath: status.hostIP + command: + - "nfd-topology-updater" + args: + - "-podresources-socket=/host-var/lib/kubelet-podresources/kubelet.sock" + {{- if .Values.topologyUpdater.updateInterval | empty | not }} + - "-sleep-interval={{ .Values.topologyUpdater.updateInterval }}" + {{- else }} + - "-sleep-interval=3s" + {{- end }} + {{- if .Values.topologyUpdater.watchNamespace | empty | not }} + - "-watch-namespace={{ .Values.topologyUpdater.watchNamespace }}" + {{- else }} + - "-watch-namespace=*" + {{- end }} + {{- if .Values.tls.enable }} + - "-ca-file=/etc/kubernetes/node-feature-discovery/certs/ca.crt" + - "-key-file=/etc/kubernetes/node-feature-discovery/certs/tls.key" + - "-cert-file=/etc/kubernetes/node-feature-discovery/certs/tls.crt" + {{- end }} + {{- if .Values.topologyUpdater.podSetFingerprint }} + - "-pods-fingerprint" + {{- end }} + {{- if .Values.topologyUpdater.kubeletConfigPath | empty | not }} + - "-kubelet-config-uri=file:///host-var/kubelet-config" + {{- end }} + {{- if .Values.topologyUpdater.kubeletStateDir | empty }} + # Disable kubelet state tracking by giving an empty path + - "-kubelet-state-dir=" + {{- end }} + - -metrics={{ .Values.topologyUpdater.metricsPort | default "8081"}} + ports: + - name: metrics + containerPort: {{ .Values.topologyUpdater.metricsPort | default "8081"}} + volumeMounts: + {{- if .Values.topologyUpdater.kubeletConfigPath | empty | not }} + - name: kubelet-config + mountPath: /host-var/kubelet-config + {{- end }} + - name: kubelet-podresources-sock + mountPath: /host-var/lib/kubelet-podresources/kubelet.sock + - name: host-sys + mountPath: /host-sys + {{- if .Values.topologyUpdater.kubeletStateDir | empty | not }} + - name: kubelet-state-files + mountPath: /host-var/lib/kubelet + readOnly: true + {{- end }} + {{- if .Values.tls.enable }} + - name: nfd-topology-updater-cert + mountPath: "/etc/kubernetes/node-feature-discovery/certs" + readOnly: true + {{- end }} + - name: nfd-topology-updater-conf + mountPath: "/etc/kubernetes/node-feature-discovery" + readOnly: true + + resources: + {{- toYaml .Values.topologyUpdater.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.topologyUpdater.securityContext | nindent 12 }} + volumes: + - name: host-sys + hostPath: + path: "/sys" + {{- if .Values.topologyUpdater.kubeletConfigPath | empty | not }} + - name: kubelet-config + hostPath: + path: {{ .Values.topologyUpdater.kubeletConfigPath }} + {{- end }} + - name: kubelet-podresources-sock + hostPath: + {{- if .Values.topologyUpdater.kubeletPodResourcesSockPath | empty | not }} + path: {{ .Values.topologyUpdater.kubeletPodResourcesSockPath }} + {{- else }} + path: /var/lib/kubelet/pod-resources/kubelet.sock + {{- end }} + {{- if .Values.topologyUpdater.kubeletStateDir | empty | not }} + - name: kubelet-state-files + hostPath: + path: {{ .Values.topologyUpdater.kubeletStateDir }} + {{- end }} + - name: nfd-topology-updater-conf + configMap: + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater-conf + items: + - key: nfd-topology-updater.conf + path: nfd-topology-updater.conf + {{- if .Values.tls.enable }} + - name: nfd-topology-updater-cert + secret: + secretName: nfd-topology-updater-cert + {{- end }} + + + {{- with .Values.topologyUpdater.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologyUpdater.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologyUpdater.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/templates/worker.yaml b/sriov-network-operator-chart/charts/sriov-nfd/templates/worker.yaml new file mode 100644 index 0000000..124e1a0 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/templates/worker.yaml @@ -0,0 +1,162 @@ +{{- if .Values.worker.enable }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-worker + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + role: worker + {{- with .Values.worker.daemonsetAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 6 }} + role: worker + template: + metadata: + labels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 8 }} + role: worker + {{- with .Values.worker.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + dnsPolicy: ClusterFirstWithHostNet + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "node-feature-discovery.worker.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.worker.podSecurityContext | nindent 8 }} + containers: + - name: worker + securityContext: + {{- toYaml .Values.worker.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_UID + valueFrom: + fieldRef: + fieldPath: metadata.uid + resources: + {{- toYaml .Values.worker.resources | nindent 12 }} + command: + - "nfd-worker" + args: + {{- if not .Values.enableNodeFeatureApi }} + - "-server={{ include "node-feature-discovery.fullname" . }}-master:{{ .Values.master.service.port }}" + - "-enable-nodefeature-api=false" + {{- end }} +{{- if .Values.tls.enable }} + - "-ca-file=/etc/kubernetes/node-feature-discovery/certs/ca.crt" + - "-key-file=/etc/kubernetes/node-feature-discovery/certs/tls.key" + - "-cert-file=/etc/kubernetes/node-feature-discovery/certs/tls.crt" +{{- end }} + - "-metrics={{ .Values.worker.metricsPort | default "8081"}}" + ports: + - name: metrics + containerPort: {{ .Values.worker.metricsPort | default "8081"}} + volumeMounts: + - name: host-boot + mountPath: "/host-boot" + readOnly: true + - name: host-os-release + mountPath: "/host-etc/os-release" + readOnly: true + - name: host-sys + mountPath: "/host-sys" + readOnly: true + - name: host-usr-lib + mountPath: "/host-usr/lib" + readOnly: true + - name: host-lib + mountPath: "/host-lib" + readOnly: true + {{- if .Values.worker.mountUsrSrc }} + - name: host-usr-src + mountPath: "/host-usr/src" + readOnly: true + {{- end }} + - name: source-d + mountPath: "/etc/kubernetes/node-feature-discovery/source.d/" + readOnly: true + - name: features-d + mountPath: "/etc/kubernetes/node-feature-discovery/features.d/" + readOnly: true + - name: nfd-worker-conf + mountPath: "/etc/kubernetes/node-feature-discovery" + readOnly: true +{{- if .Values.tls.enable }} + - name: nfd-worker-cert + mountPath: "/etc/kubernetes/node-feature-discovery/certs" + readOnly: true +{{- end }} + volumes: + - name: host-boot + hostPath: + path: "/boot" + - name: host-os-release + hostPath: + path: "/etc/os-release" + - name: host-sys + hostPath: + path: "/sys" + - name: host-usr-lib + hostPath: + path: "/usr/lib" + - name: host-lib + hostPath: + path: "/lib" + {{- if .Values.worker.mountUsrSrc }} + - name: host-usr-src + hostPath: + path: "/usr/src" + {{- end }} + - name: source-d + hostPath: + path: "/etc/kubernetes/node-feature-discovery/source.d/" + - name: features-d + hostPath: + path: "/etc/kubernetes/node-feature-discovery/features.d/" + - name: nfd-worker-conf + configMap: + name: {{ include "node-feature-discovery.fullname" . }}-worker-conf + items: + - key: nfd-worker.conf + path: nfd-worker.conf +{{- if .Values.tls.enable }} + - name: nfd-worker-cert + secret: + secretName: nfd-worker-cert +{{- end }} + {{- with .Values.worker.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} +{{- end }} diff --git a/sriov-network-operator-chart/charts/sriov-nfd/values.yaml b/sriov-network-operator-chart/charts/sriov-nfd/values.yaml new file mode 100644 index 0000000..9d9aa94 --- /dev/null +++ b/sriov-network-operator-chart/charts/sriov-nfd/values.yaml @@ -0,0 +1,534 @@ +image: + repository: rancher/hardened-node-feature-discovery + # This should be set to 'IfNotPresent' for released version + pullPolicy: IfNotPresent + # tag, if defined will use the given image tag, else Chart.AppVersion will be used + tag: v0.15.6-build20240822 +imagePullSecrets: [] + +nameOverride: "" +fullnameOverride: "" +namespaceOverride: "" + +enableNodeFeatureApi: true + +master: + enable: true + config: ### + # noPublish: false + # autoDefaultNs: true + # extraLabelNs: ["added.ns.io","added.kubernets.io"] + # denyLabelNs: ["denied.ns.io","denied.kubernetes.io"] + # resourceLabels: ["vendor-1.com/feature-1","vendor-2.io/feature-2"] + # enableTaints: false + # labelWhiteList: "foo" + # resyncPeriod: "2h" + # klog: + # addDirHeader: false + # alsologtostderr: false + # logBacktraceAt: + # logtostderr: true + # skipHeaders: false + # stderrthreshold: 2 + # v: 0 + # vmodule: + ## NOTE: the following options are not dynamically run-time configurable + ## and require a nfd-master restart to take effect after being changed + # logDir: + # logFile: + # logFileMaxSize: 1800 + # skipLogHeaders: false + # leaderElection: + # leaseDuration: 15s + # # this value has to be lower than leaseDuration and greater than retryPeriod*1.2 + # renewDeadline: 10s + # # this value has to be greater than 0 + # retryPeriod: 2s + # nfdApiParallelism: 10 + ### + # The TCP port that nfd-master listens for incoming requests. Default: 8080 + # Deprecated this parameter is related to the deprecated gRPC API and will + # be removed with it in a future release + port: 8080 + metricsPort: 8081 + instance: + featureApi: + resyncPeriod: + denyLabelNs: [] + extraLabelNs: [] + resourceLabels: [] + enableTaints: false + crdController: null + featureRulesController: null + nfdApiParallelism: null + deploymentAnnotations: {} + replicaCount: 1 + + podSecurityContext: {} + # fsGroup: 2000 + + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: [ "ALL" ] + readOnlyRootFilesystem: true + runAsNonRoot: true + # runAsUser: 1000 + + 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: + + rbac: + create: true + + service: + type: ClusterIP + port: 8080 + + 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 + + nodeSelector: {} + + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Equal" + value: "" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/control-plane" + operator: "Equal" + value: "" + effect: "NoSchedule" + + annotations: {} + + affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: "node-role.kubernetes.io/master" + operator: In + values: [""] + - weight: 1 + preference: + matchExpressions: + - key: "node-role.kubernetes.io/control-plane" + operator: In + values: [""] + +worker: + enable: true + config: ### + #core: + # labelWhiteList: + # noPublish: false + # sleepInterval: 60s + # featureSources: [all] + # labelSources: [all] + # klog: + # addDirHeader: false + # alsologtostderr: false + # logBacktraceAt: + # logtostderr: true + # skipHeaders: false + # stderrthreshold: 2 + # v: 0 + # vmodule: + ## NOTE: the following options are not dynamically run-time configurable + ## and require a nfd-worker restart to take effect after being changed + # logDir: + # logFile: + # logFileMaxSize: 1800 + # skipLogHeaders: false + #sources: + # cpu: + # cpuid: + ## NOTE: whitelist has priority over blacklist + # attributeBlacklist: + # - "BMI1" + # - "BMI2" + # - "CLMUL" + # - "CMOV" + # - "CX16" + # - "ERMS" + # - "F16C" + # - "HTT" + # - "LZCNT" + # - "MMX" + # - "MMXEXT" + # - "NX" + # - "POPCNT" + # - "RDRAND" + # - "RDSEED" + # - "RDTSCP" + # - "SGX" + # - "SSE" + # - "SSE2" + # - "SSE3" + # - "SSE4" + # - "SSE42" + # - "SSSE3" + # - "TDX_GUEST" + # attributeWhitelist: + # kernel: + # kconfigFile: "/path/to/kconfig" + # configOpts: + # - "NO_HZ" + # - "X86" + # - "DMI" + # pci: + # deviceClassWhitelist: + # - "0200" + # - "03" + # - "12" + # deviceLabelFields: + # - "class" + # - "vendor" + # - "device" + # - "subsystem_vendor" + # - "subsystem_device" + # usb: + # deviceClassWhitelist: + # - "0e" + # - "ef" + # - "fe" + # - "ff" + # deviceLabelFields: + # - "class" + # - "vendor" + # - "device" + # local: + # hooksEnabled: false + # custom: + # # The following feature demonstrates the capabilities of the matchFeatures + # - name: "my custom rule" + # labels: + # "vendor.io/my-ng-feature": "true" + # # matchFeatures implements a logical AND over all matcher terms in the + # # list (i.e. all of the terms, or per-feature matchers, must match) + # matchFeatures: + # - feature: cpu.cpuid + # matchExpressions: + # AVX512F: {op: Exists} + # - feature: cpu.cstate + # matchExpressions: + # enabled: {op: IsTrue} + # - feature: cpu.pstate + # matchExpressions: + # no_turbo: {op: IsFalse} + # scaling_governor: {op: In, value: ["performance"]} + # - feature: cpu.rdt + # matchExpressions: + # RDTL3CA: {op: Exists} + # - feature: cpu.sst + # matchExpressions: + # bf.enabled: {op: IsTrue} + # - feature: cpu.topology + # matchExpressions: + # hardware_multithreading: {op: IsFalse} + # + # - feature: kernel.config + # matchExpressions: + # X86: {op: Exists} + # LSM: {op: InRegexp, value: ["apparmor"]} + # - feature: kernel.loadedmodule + # matchExpressions: + # e1000e: {op: Exists} + # - feature: kernel.selinux + # matchExpressions: + # enabled: {op: IsFalse} + # - feature: kernel.version + # matchExpressions: + # major: {op: In, value: ["5"]} + # minor: {op: Gt, value: ["10"]} + # + # - feature: storage.block + # matchExpressions: + # rotational: {op: In, value: ["0"]} + # dax: {op: In, value: ["0"]} + # + # - feature: network.device + # matchExpressions: + # operstate: {op: In, value: ["up"]} + # speed: {op: Gt, value: ["100"]} + # + # - feature: memory.numa + # matchExpressions: + # node_count: {op: Gt, value: ["2"]} + # - feature: memory.nv + # matchExpressions: + # devtype: {op: In, value: ["nd_dax"]} + # mode: {op: In, value: ["memory"]} + # + # - feature: system.osrelease + # matchExpressions: + # ID: {op: In, value: ["fedora", "centos"]} + # - feature: system.name + # matchExpressions: + # nodename: {op: InRegexp, value: ["^worker-X"]} + # + # - feature: local.label + # matchExpressions: + # custom-feature-knob: {op: Gt, value: ["100"]} + # + # # The following feature demonstrates the capabilities of the matchAny + # - name: "my matchAny rule" + # labels: + # "vendor.io/my-ng-feature-2": "my-value" + # # matchAny implements a logical IF over all elements (sub-matchers) in + # # the list (i.e. at least one feature matcher must match) + # matchAny: + # - matchFeatures: + # - feature: kernel.loadedmodule + # matchExpressions: + # driver-module-X: {op: Exists} + # - feature: pci.device + # matchExpressions: + # vendor: {op: In, value: ["8086"]} + # class: {op: In, value: ["0200"]} + # - matchFeatures: + # - feature: kernel.loadedmodule + # matchExpressions: + # driver-module-Y: {op: Exists} + # - feature: usb.device + # matchExpressions: + # vendor: {op: In, value: ["8086"]} + # class: {op: In, value: ["02"]} + # + # - name: "avx wildcard rule" + # labels: + # "my-avx-feature": "true" + # matchFeatures: + # - feature: cpu.cpuid + # matchName: {op: InRegexp, value: ["^AVX512"]} + # + # # The following features demonstreate label templating capabilities + # - name: "my template rule" + # labelsTemplate: | + # {{ range .system.osrelease }}vendor.io/my-system-feature.{{ .Name }}={{ .Value }} + # {{ end }} + # matchFeatures: + # - feature: system.osrelease + # matchExpressions: + # ID: {op: InRegexp, value: ["^open.*"]} + # VERSION_ID.major: {op: In, value: ["13", "15"]} + # + # - name: "my template rule 2" + # labelsTemplate: | + # {{ range .pci.device }}vendor.io/my-pci-device.{{ .class }}-{{ .device }}=with-cpuid + # {{ end }} + # matchFeatures: + # - feature: pci.device + # matchExpressions: + # class: {op: InRegexp, value: ["^06"]} + # vendor: ["8086"] + # - feature: cpu.cpuid + # matchExpressions: + # AVX: {op: Exists} + # + # # The following examples demonstrate vars field and back-referencing + # # previous labels and vars + # - name: "my dummy kernel rule" + # labels: + # "vendor.io/my.kernel.feature": "true" + # matchFeatures: + # - feature: kernel.version + # matchExpressions: + # major: {op: Gt, value: ["2"]} + # + # - name: "my dummy rule with no labels" + # vars: + # "my.dummy.var": "1" + # matchFeatures: + # - feature: cpu.cpuid + # matchExpressions: {} + # + # - name: "my rule using backrefs" + # labels: + # "vendor.io/my.backref.feature": "true" + # matchFeatures: + # - feature: rule.matched + # matchExpressions: + # vendor.io/my.kernel.feature: {op: IsTrue} + # my.dummy.var: {op: Gt, value: ["0"]} + # + # - name: "kconfig template rule" + # labelsTemplate: | + # {{ range .kernel.config }}kconfig-{{ .Name }}={{ .Value }} + # {{ end }} + # matchFeatures: + # - feature: kernel.config + # matchName: {op: In, value: ["SWAP", "X86", "ARM"]} +### + + metricsPort: 8081 + daemonsetAnnotations: {} + podSecurityContext: {} + # fsGroup: 2000 + + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: [ "ALL" ] + readOnlyRootFilesystem: true + runAsNonRoot: true + # runAsUser: 1000 + + serviceAccount: + # Specifies whether a service account should be created. + # We create this by default to make it easier for downstream users to apply PodSecurityPolicies. + 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: + + rbac: + create: true + + # Allow users to mount the hostPath /usr/src, useful for RHCOS on s390x + # Does not work on systems without /usr/src AND a read-only /usr, such as Talos + mountUsrSrc: false + + 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 + + nodeSelector: {} + + tolerations: [] + + annotations: {} + + affinity: {} + + priorityClassName: "" + +topologyUpdater: + config: ### + ## key = node name, value = list of resources to be excluded. + ## use * to exclude from all nodes. + ## an example for how the exclude list should looks like + #excludeList: + # node1: [cpu] + # node2: [memory, example/deviceA] + # *: [hugepages-2Mi] +### + + enable: false + createCRDs: false + + serviceAccount: + create: true + annotations: {} + name: + rbac: + create: true + + metricsPort: 8081 + kubeletConfigPath: + kubeletPodResourcesSockPath: + updateInterval: 60s + watchNamespace: "*" + kubeletStateDir: /var/lib/kubelet + + podSecurityContext: {} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: [ "ALL" ] + readOnlyRootFilesystem: true + runAsUser: 0 + + 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 + + nodeSelector: {} + tolerations: [] + annotations: {} + daemonsetAnnotations: {} + affinity: {} + podSetFingerprint: true + +gc: + enable: true + replicaCount: 1 + + serviceAccount: + create: true + annotations: {} + name: + rbac: + create: true + + interval: 1h + + podSecurityContext: {} + + 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 + + metricsPort: 8081 + + nodeSelector: {} + tolerations: [] + annotations: {} + deploymentAnnotations: {} + affinity: {} + +# Optionally use encryption for worker <--> master comms +# TODO: verify hostname is not yet supported +# +# If you do not enable certManager (and have it installed) you will +# need to manually, or otherwise, provision the TLS certs as secrets +tls: + enable: false + certManager: false + +prometheus: + enable: false + labels: {} diff --git a/sriov-network-operator-chart/templates.obscpio b/sriov-network-operator-chart/templates.obscpio deleted file mode 100644 index 036de0ba4fc00771549e1ace83e428a12c4e5b298880775a34aa9d7ac9cdf305..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28160 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≧!=j#$NoXL4#;_C!oL87XR(g;EO?zKN-MX zYOz}i+%-V=2z0+3)Ee9x(4<9ep+$vMkiuz#!M#>n7=>a`>(E3zC1`O8ss#Gjgof^{ zgWgNY=wMC?Ku^whI{T30H}~m3C(eYgdeHyR)-nAloiP zwwFcbB*@-`fjvdOu{H5;W9v=-q`SA%-myBju%R@R9lpcbyHiZn?o@DerNJJwdmjxD zze!u{bz6|HmXL#Aak<`gtl#*QTfZLfP;DQpD`8uEgt$vx>=}T8LHtLelWWnoTBWUaXhL?{)at|zQ5L|nPW$Hrr1YGB>LCC2_3kGj z$$NWKHbJn)qS zE&{ev^zD|3AE^LrV#_AvEMyb%lf`y$iyJ4yqrOV(r_F+N^9=_h>r>3Y{p$4xUQes$ z80a%*!>6z=xrex~IyF}3#)I1hZO*9h5^Y6TFq5%PQ9Y>SOfxxxPqq)#G%Yr)k9JGW zbklrCYIcfK*U&{>(BE+myTnl>7Bu?k&c{pKK)Gf0MxA(Qa1fty;@zi`qnwUm)k!iH z5WPbt5GoKM+kJ{Uo(nOiX6++RsR_4$kEsU=&eFNIV^bBOD8R^nL4m0dDuVNF!3mKu zFQdYqJ9p_+9B0WQwEF_bzr?Y_;h114*iE6hm(AMI3}@)FQjtIcKaMU|L@HD)p1CoO zpHUbIr^)CXbfObR#4Box50Y1zo)%1{;5YFHJ8ivJ(k~PCDv;9mRoJicsi>>xVkmT+ zq_}^-$xaDQI3zJ<0+f2*vk&h{sXi_KA!_^(<<5lFFsfjbHKPnEG(KhoQXUEj_K;>l zyvbtGEQ{Gzq9dWijj^)Sfz=rojZ!_!kF1}T{8Ht=KB&%rr_2tI&cEybjS~s0et&I4 zEjEloUU92z7bLi(7}jUrj4rptAVl0Ey%SV;6{o3&D@-U%=_YW*pTup!V{t_gGp)sk z)I#zmn~w_v(WJ6+QtL&5W63WWRat3b1PzSIU&Vr=b-3g;ZA_4WXGS!~vH-azi%x%_ z2U2)&C?SZyFNgDkCR4CV5lLeumJ^`j+$t7v7)IGVnNbbVq;N>eKjkVwR)E?RS3iWWxDA}JnYlK|&`K_8$eOGGHHHLe z29p`L66HUu`JV1tG2q zOM;=lWTMO~+9Z*i)L$=OtJUH$K9$@pk2j6{8}w4y+^*1vIG?CJe^6d|q!ukF^j8+d z1ysl*_;Y}wo|&{@eayNks;uEEtqnP1^KtXXn%4DMzH&qa6Kh|+ElG0E2H;9 ze=EnUcP16}z9@HOMd1-Umy(Hk3ta248O2^JE`{fAo3u42pViJ)9?c}&Ln|MmZCX<| zX*5kl#xfEApWGyoEqK)FUMJ(<^2DyEyBg)|r*M4_RgBW3PnLFS(uAX`wbWCkDP73q zT3Xb_dOj7kV9DQhS+~9_8%lw>%|FUV+6cEzbd5r+^xrYM1=F-_EDa&*m1VsQ-fQCCWJM+yq!`=P0 z;iG|Z2Y#keztc9&?YaTal1XeK4YS>p(lD1IX)HCH?IyXqZN}?F#Ot(rWRBw)hSkAA z$QE6vO{~7<5`AC=Hp`p>A(Op*5VAIjXdJ{qq7Wb!L(-)#4hhR-P6KL)UCSnpSUAgy zd772Gqq3uy^H`}1!$A6sBRT@VCsBL0_ON$3+>evOzCK8)XbWp*o0Yu zLqqAYiasN57s;^5^1To{p5yJHt%qA{Xd@vX-P^oBV2X#kq=imeBFIp}J_RMDaUBbb zpvqp7KFW8hWw%8YZ^{r%Q_>65z_R}HC~8Dz@Od>uqn0fO#3h&!y^B34kA*r^5mEQ} zn~!5-Vq>*Yu{G9Xq-ObDg;8R)c>azux)^2gfyoaQF^?Cx0swzf zoXhG+goD@XB7OlOATEI6^mexT3`QZrJdKb=iQtMK73TS`+AaR4GMOb|*nfZ%6>Mic zO8p=t_G(~t;u`|Y zsc=9poC-Ff#IuQK^WR_BFO5)8nZ7*jEiGx_OB@kJ$yn6s5@@ABt4 zF}m;xl*`f;qUA&!v9`IeumGtuBL77`7oGpdi!45q F`43Q8n*aa+ diff --git a/upgrade-controller-chart/templates.obscpio b/upgrade-controller-chart/templates.obscpio deleted file mode 100644 index c619dbc6961143b7d8de8e011c4c4f7de40271cf8df71cde346a23656836a5e0..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12800 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 diff --git a/upgrade-controller-chart/templates/NOTES.txt b/upgrade-controller-chart/templates/NOTES.txt new file mode 100644 index 0000000..473a0f4 diff --git a/upgrade-controller-chart/templates/_helpers.tpl b/upgrade-controller-chart/templates/_helpers.tpl new file mode 100644 index 0000000..892acbd --- /dev/null +++ b/upgrade-controller-chart/templates/_helpers.tpl @@ -0,0 +1,83 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "upgrade-controller.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 "upgrade-controller.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 "upgrade-controller.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "upgrade-controller.labels" -}} +helm.sh/chart: {{ include "upgrade-controller.chart" . }} +{{ include "upgrade-controller.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "upgrade-controller.selectorLabels" -}} +app.kubernetes.io/name: {{ include "upgrade-controller.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "upgrade-controller.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "upgrade-controller.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Webhook service name +*/}} +{{- define "upgrade-controller.webhookServiceName" -}} +{{ .Release.Name }}-webhook +{{- end }} + +{{/* +Certificate issuer name +*/}} +{{- define "upgrade-controller.certificateIssuer" -}} +{{ .Release.Name }}-self-signed-issuer +{{- end }} + +{{/* +Certificate name +*/}} +{{- define "upgrade-controller.certificate" -}} +{{ .Release.Name }}-serving-cert +{{- end }} diff --git a/upgrade-controller-chart/templates/certificate.yaml b/upgrade-controller-chart/templates/certificate.yaml new file mode 100644 index 0000000..6805cdd --- /dev/null +++ b/upgrade-controller-chart/templates/certificate.yaml @@ -0,0 +1,28 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + labels: + {{- include "upgrade-controller.labels" . | nindent 4 }} + name: {{ include "upgrade-controller.certificateIssuer" . }} + namespace: {{ .Release.Namespace }} +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + labels: + {{- include "upgrade-controller.labels" . | nindent 4 }} + app.kubernetes.io/component: certificate + name: {{ include "upgrade-controller.certificate" . }} + namespace: {{ .Release.Namespace }} +spec: + dnsNames: + - {{ include "upgrade-controller.webhookServiceName" . }}.{{ .Release.Namespace }}.svc + - {{ include "upgrade-controller.webhookServiceName" . }}.{{ .Release.Namespace }}.svc.cluster.local + issuerRef: + kind: Issuer + name: {{ include "upgrade-controller.certificateIssuer" . }} + {{- with first .Values.volumes }} + secretName: {{ .secret.secretName }} + {{- end }} diff --git a/upgrade-controller-chart/templates/clusterrole.yaml b/upgrade-controller-chart/templates/clusterrole.yaml new file mode 100644 index 0000000..8e9c6e7 --- /dev/null +++ b/upgrade-controller-chart/templates/clusterrole.yaml @@ -0,0 +1,114 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "upgrade-controller.fullname" . }} + labels: + {{- include "upgrade-controller.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - nodes + verbs: + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - watch +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get +- apiGroups: + - batch + resources: + - jobs + verbs: + - create + - get + - list + - watch +- apiGroups: + - batch + resources: + - jobs/status + verbs: + - get +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - helm.cattle.io + resources: + - helmcharts + verbs: + - create + - get + - list + - update + - watch +- apiGroups: + - helm.cattle.io + resources: + - helmcharts/status + verbs: + - get +- apiGroups: + - lifecycle.suse.com + resources: + - releasemanifests + verbs: + - create + - get + - list + - watch +- apiGroups: + - lifecycle.suse.com + resources: + - upgradeplans + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - lifecycle.suse.com + resources: + - upgradeplans/finalizers + verbs: + - update +- apiGroups: + - lifecycle.suse.com + resources: + - upgradeplans/status + verbs: + - get + - patch + - update +- apiGroups: + - upgrade.cattle.io + resources: + - plans + verbs: + - create + - delete + - get + - list + - watch diff --git a/upgrade-controller-chart/templates/clusterrole_binding.yaml b/upgrade-controller-chart/templates/clusterrole_binding.yaml new file mode 100644 index 0000000..5ef4e17 --- /dev/null +++ b/upgrade-controller-chart/templates/clusterrole_binding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "upgrade-controller.fullname" . }} + labels: + {{- include "upgrade-controller.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "upgrade-controller.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "upgrade-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/upgrade-controller-chart/templates/deployment.yaml b/upgrade-controller-chart/templates/deployment.yaml new file mode 100644 index 0000000..4488189 --- /dev/null +++ b/upgrade-controller-chart/templates/deployment.yaml @@ -0,0 +1,85 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "upgrade-controller.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "upgrade-controller.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "upgrade-controller.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "upgrade-controller.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "upgrade-controller.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + - --leader-elect + - --health-probe-bind-address=:8081 + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: RELEASE_MANIFEST_IMAGE + value: {{ .Values.env.releaseManifest.image }} + - name: KUBECTL_IMAGE + value: {{ .Values.env.kubectl.image }} + - name: KUBECTL_VERSION + value: {{ .Values.env.kubectl.version }} + - name: SERVICE_ACCOUNT_NAME + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + ports: + - name: {{ .Values.webhookService.name }} + containerPort: {{ .Values.webhookService.targetPort }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.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/upgrade-controller-chart/templates/leader_election_role.yaml b/upgrade-controller-chart/templates/leader_election_role.yaml new file mode 100644 index 0000000..acebc4f --- /dev/null +++ b/upgrade-controller-chart/templates/leader_election_role.yaml @@ -0,0 +1,40 @@ +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "upgrade-controller.fullname" . }}-leader-election + namespace: {{ .Release.Namespace }} + labels: + {{- include "upgrade-controller.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/upgrade-controller-chart/templates/leader_election_role_binding.yaml b/upgrade-controller-chart/templates/leader_election_role_binding.yaml new file mode 100644 index 0000000..1a0e7d2 --- /dev/null +++ b/upgrade-controller-chart/templates/leader_election_role_binding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "upgrade-controller.fullname" . }}-leader-election + namespace: {{ .Release.Namespace }} + labels: + {{- include "upgrade-controller.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "upgrade-controller.fullname" . }}-leader-election +subjects: +- kind: ServiceAccount + name: {{ include "upgrade-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/upgrade-controller-chart/templates/serviceaccount.yaml b/upgrade-controller-chart/templates/serviceaccount.yaml new file mode 100644 index 0000000..f860a12 --- /dev/null +++ b/upgrade-controller-chart/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "upgrade-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "upgrade-controller.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/upgrade-controller-chart/templates/validating_webhook_configuration.yaml b/upgrade-controller-chart/templates/validating_webhook_configuration.yaml new file mode 100644 index 0000000..43ad580 --- /dev/null +++ b/upgrade-controller-chart/templates/validating_webhook_configuration.yaml @@ -0,0 +1,29 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: {{ include "upgrade-controller.fullname" . }}-validating-webhook-configuration + labels: + {{- include "upgrade-controller.labels" . | nindent 4 }} + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "upgrade-controller.certificate" . }} +webhooks: + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "upgrade-controller.webhookServiceName" . }} + namespace: {{ .Release.Namespace }} + path: /validate-lifecycle-suse-com-v1alpha1-upgradeplan + failurePolicy: Fail + name: upgrade-plan-policy.suse.com + rules: + - apiGroups: + - lifecycle.suse.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - upgradeplans + sideEffects: None diff --git a/upgrade-controller-chart/templates/webhook_service.yaml b/upgrade-controller-chart/templates/webhook_service.yaml new file mode 100644 index 0000000..f8b48fe --- /dev/null +++ b/upgrade-controller-chart/templates/webhook_service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "upgrade-controller.webhookServiceName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "upgrade-controller.labels" . | nindent 4 }} +spec: + type: {{ .Values.webhookService.type }} + ports: + - port: {{ .Values.webhookService.port }} + targetPort: {{ .Values.webhookService.targetPort }} + protocol: TCP + selector: + {{- include "upgrade-controller.selectorLabels" . | nindent 4 }}