diff --git a/.github/workflows/publish-chart.yml b/.github/workflows/publish-chart.yml new file mode 100644 index 00000000..4e35c44e --- /dev/null +++ b/.github/workflows/publish-chart.yml @@ -0,0 +1,65 @@ +name: Release Helm Chart + +on: + push: + branches: + - main + tags: + - 'v*.*.*' + pull_request: + branches: + - main + +jobs: + helm-chart: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Helm + uses: azure/setup-helm@v4 + with: + version: v3.16.2 + + - name: Determine chart version + id: chart_version + run: | + if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]]; then + # Use SHA for main branch + CHART_VERSION="0.0.0-$(echo ${{ github.sha }} | cut -c1-7)" + elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + # Use tag version (strip 'v' prefix) + CHART_VERSION="${GITHUB_REF#refs/tags/v}" + else + # Use PR SHA for dry run + CHART_VERSION="0.0.0-$(echo ${{ github.sha }} | cut -c1-7)" + fi + echo "version=$CHART_VERSION" >> $GITHUB_OUTPUT + + - name: Install Kustomize + run: | + curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash + mv kustomize /usr/local/bin + + - name: Prepare CRDs folder + run: | + mkdir -p dist/chart/crds + kustomize build config/default | yq ea 'select(.kind == "CustomResourceDefinition")' > dist/chart/crds/crds.yaml + rm -rf dist/chart/templates/crd + + - name: Package Helm chart + run: | + helm package dist/chart --version ${{ steps.chart_version.outputs.version }} + + - name: Log in to GitHub Container Registry + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io -u ${{ github.actor }} --password-stdin + + - name: Push Helm chart to GHCR + run: | + helm push boot-operator-${{ steps.chart_version.outputs.version }}.tgz oci://ghcr.io/${{ github.repository_owner }}/charts diff --git a/.github/workflows/test-chart.yml b/.github/workflows/test-chart.yml new file mode 100644 index 00000000..9b015620 --- /dev/null +++ b/.github/workflows/test-chart.yml @@ -0,0 +1,70 @@ +name: Test Chart + +permissions: + contents: read + +on: + push: + pull_request: + +jobs: + test-e2e: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Install Helm + run: | + curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash + + - name: Verify Helm installation + run: helm version + + - name: Lint Helm Chart + run: | + helm lint ./dist/chart + + - name: Install the latest version of kind + run: | + curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 + chmod +x ./kind + sudo mv ./kind /usr/local/bin/kind + + - name: Verify kind installation + run: kind version + + - name: Create kind cluster + run: kind create cluster + + - name: Prepare boot-operator + run: | + go mod tidy + make docker-build IMG=boot-operator:v0.1.0 + kind load docker-image boot-operator:v0.1.0 + + - name: Install cert-manager via Helm + run: | + 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 + + - name: Wait for cert-manager to be ready + run: | + kubectl wait --namespace cert-manager --for=condition=available --timeout=300s deployment/cert-manager + kubectl wait --namespace cert-manager --for=condition=available --timeout=300s deployment/cert-manager-cainjector + kubectl wait --namespace cert-manager --for=condition=available --timeout=300s deployment/cert-manager-webhook + + - name: Install Helm chart for project + run: | + helm install my-release ./dist/chart --create-namespace --namespace boot-operator-system + + - name: Check Helm release status + run: | + helm status my-release --namespace boot-operator-system diff --git a/Makefile b/Makefile index 12a9340c..d25be786 100644 --- a/Makefile +++ b/Makefile @@ -171,6 +171,10 @@ e2e-deploy: manifests kustomize ## Deploy controller to the K8s cluster specifie undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. $(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - +.PHONY: helm +helm: manifests kubebuilder + $(KUBEBUILDER) edit --plugins=helm/v1-alpha + ##@ Dependencies ## Location to install dependencies to @@ -187,6 +191,7 @@ GOLANGCI_LINT = $(LOCALBIN)/golangci-lint ADDLICENSE ?= $(LOCALBIN)/addlicense GOIMPORTS ?= $(LOCALBIN)/goimports GEN_CRD_API_REFERENCE_DOCS ?= $(LOCALBIN)/gen-crd-api-reference-docs +KUBEBUILDER ?= $(LOCALBIN)/kubebuilder-$(KUBEBUILDER_VERSION) ## Tool Versions KUSTOMIZE_VERSION ?= v5.5.0 @@ -199,6 +204,7 @@ GOLANGCI_LINT_VERSION ?= v2.1 ADDLICENSE_VERSION ?= v1.1.1 GOIMPORTS_VERSION ?= v0.31.0 GEN_CRD_API_REFERENCE_DOCS_VERSION ?= v0.3.0 +KUBEBUILDER_VERSION ?= v4.5.1 .PHONY: kustomize kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. @@ -257,6 +263,11 @@ gen-crd-api-reference-docs: $(GEN_CRD_API_REFERENCE_DOCS) ## Download gen-crd-ap $(GEN_CRD_API_REFERENCE_DOCS): $(LOCALBIN) $(call go-install-tool,$(GEN_CRD_API_REFERENCE_DOCS),github.com/ahmetb/gen-crd-api-reference-docs,$(GEN_CRD_API_REFERENCE_DOCS_VERSION)) +.PHONY: kubebuilder +kubebuilder: $(KUBEBUILDER) ## Download kubebuilder locally if necessary. +$(KUBEBUILDER): $(LOCALBIN) + $(call go-install-tool,$(KUBEBUILDER),sigs.k8s.io/kubebuilder/v4,$(KUBEBUILDER_VERSION)) + # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary # $2 - package url which can be installed diff --git a/PROJECT b/PROJECT index 88183c73..72fe52a8 100644 --- a/PROJECT +++ b/PROJECT @@ -5,6 +5,8 @@ domain: ironcore.dev layout: - go.kubebuilder.io/v4 +plugins: + helm.kubebuilder.io/v1-alpha: {} projectName: boot-operator repo: github.com/ironcore-dev/boot-operator resources: diff --git a/REUSE.toml b/REUSE.toml index 072f9d93..fcff7f45 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -4,13 +4,43 @@ SPDX-PackageSupplier = "IronCore authors " SPDX-PackageDownloadLocation = "https://github.com/ironcore-dev/boot-operator" [[annotations]] -path = [".github/**", ".gitignore", "CODEOWNERS", "Dockerfile", "Makefile", "PROJECT", "config/**", "gen/**", "go.mod", "go.sum", "hack/**", "server/**", "templates/**", "internal/**", "cmd/**", "api/**", "config/**", "test/**", "CONTRIBUTING.md", "PROJECT", "mkdocs.yml", ".dockerignore", ".golangci.yml", "REUSE.toml"] +path = [ + ".github/**", + ".gitignore", + "CODEOWNERS", + "Dockerfile", + "Makefile", + "PROJECT", + "config/**", + "dist/**", + "dist/**", + "gen/**", + "go.mod", + "go.sum", + "hack/**", + "server/**", + "templates/**", + "internal/**", + "cmd/**", + "api/**", + "config/**", + "test/**", + "CONTRIBUTING.md", + "PROJECT", + "mkdocs.yml", + ".dockerignore", + ".golangci.yml", + "REUSE.toml" +] precedence = "aggregate" SPDX-FileCopyrightText = "2025 SAP SE or an SAP affiliate company and IronCore contributors" SPDX-License-Identifier = "Apache-2.0" [[annotations]] -path = ["docs/**", "README.md"] +path = [ + "docs/**", + "README.md" +] precedence = "aggregate" SPDX-FileCopyrightText = "2025 SAP SE or an SAP affiliate company and IronCore contributors" SPDX-License-Identifier = "Apache-2.0" diff --git a/dist/chart/.helmignore b/dist/chart/.helmignore new file mode 100644 index 00000000..7d92f7fb --- /dev/null +++ b/dist/chart/.helmignore @@ -0,0 +1,25 @@ +# Patterns to ignore when building Helm packages. +# Operating system files +.DS_Store + +# Version control directories +.git/ +.gitignore +.bzr/ +.hg/ +.hgignore +.svn/ + +# Backup and temporary files +*.swp +*.tmp +*.bak +*.orig +*~ + +# IDE and editor-related files +.idea/ +.vscode/ + +# Helm chart artifacts +dist/chart/*.tgz diff --git a/dist/chart/Chart.yaml b/dist/chart/Chart.yaml new file mode 100644 index 00000000..699132ad --- /dev/null +++ b/dist/chart/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v2 +name: boot-operator +description: A Helm chart to distribute the project boot-operator +type: application +version: 0.1.0 +appVersion: "0.1.0" +icon: "https://example.com/icon.png" diff --git a/dist/chart/templates/_helpers.tpl b/dist/chart/templates/_helpers.tpl new file mode 100644 index 00000000..8d60239b --- /dev/null +++ b/dist/chart/templates/_helpers.tpl @@ -0,0 +1,50 @@ +{{- define "chart.name" -}} +{{- if .Chart }} + {{- if .Chart.Name }} + {{- .Chart.Name | trunc 63 | trimSuffix "-" }} + {{- else if .Values.nameOverride }} + {{ .Values.nameOverride | trunc 63 | trimSuffix "-" }} + {{- else }} + boot-operator + {{- end }} +{{- else }} + boot-operator +{{- end }} +{{- end }} + + +{{- define "chart.labels" -}} +{{- if .Chart.AppVersion -}} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +{{- if .Chart.Version }} +helm.sh/chart: {{ .Chart.Version | quote }} +{{- end }} +app.kubernetes.io/name: {{ include "chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + + +{{- define "chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + + +{{- define "chart.hasMutatingWebhooks" -}} +{{- $hasMutating := false }} +{{- range . }} + {{- if eq .type "mutating" }} + $hasMutating = true }}{{- end }} +{{- end }} +{{ $hasMutating }}}}{{- end }} + + +{{- define "chart.hasValidatingWebhooks" -}} +{{- $hasValidating := false }} +{{- range . }} + {{- if eq .type "validating" }} + $hasValidating = true }}{{- end }} +{{- end }} +{{ $hasValidating }}}}{{- end }} diff --git a/dist/chart/templates/certmanager/certificate.yaml b/dist/chart/templates/certmanager/certificate.yaml new file mode 100644 index 00000000..72da9bcd --- /dev/null +++ b/dist/chart/templates/certmanager/certificate.yaml @@ -0,0 +1,60 @@ +{{- if .Values.certmanager.enable }} +# Self-signed Issuer +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: selfsigned-issuer + namespace: {{ .Release.Namespace }} +spec: + selfSigned: {} +{{- if .Values.webhook.enable }} +--- +# Certificate for the webhook +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + annotations: + {{- if .Values.crd.keep }} + "helm.sh/resource-policy": keep + {{- end }} + name: serving-cert + namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + dnsNames: + - boot-operator.{{ .Release.Namespace }}.svc + - boot-operator.{{ .Release.Namespace }}.svc.cluster.local + - boot-operator-webhook-service.{{ .Release.Namespace }}.svc + issuerRef: + kind: Issuer + name: selfsigned-issuer + secretName: webhook-server-cert +{{- end }} +{{- if .Values.metrics.enable }} +--- +# Certificate for the metrics +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + annotations: + {{- if .Values.crd.keep }} + "helm.sh/resource-policy": keep + {{- end }} + labels: + {{- include "chart.labels" . | nindent 4 }} + name: metrics-certs + namespace: {{ .Release.Namespace }} +spec: + dnsNames: + - boot-operator.{{ .Release.Namespace }}.svc + - boot-operator.{{ .Release.Namespace }}.svc.cluster.local + - boot-operator-metrics-service.{{ .Release.Namespace }}.svc + issuerRef: + kind: Issuer + name: selfsigned-issuer + secretName: metrics-server-cert +{{- end }} +{{- end }} diff --git a/dist/chart/templates/crd/boot.ironcore.dev_httpbootconfigs.yaml b/dist/chart/templates/crd/boot.ironcore.dev_httpbootconfigs.yaml new file mode 100755 index 00000000..31bdbbbc --- /dev/null +++ b/dist/chart/templates/crd/boot.ironcore.dev_httpbootconfigs.yaml @@ -0,0 +1,94 @@ +{{- if .Values.crd.enable }} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + annotations: + {{- if .Values.crd.keep }} + "helm.sh/resource-policy": keep + {{- end }} + controller-gen.kubebuilder.io/version: v0.16.0 + name: httpbootconfigs.boot.ironcore.dev +spec: + group: boot.ironcore.dev + names: + kind: HTTPBootConfig + listKind: HTTPBootConfigList + plural: httpbootconfigs + singular: httpbootconfig + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.state + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: HTTPBootConfig is the Schema for the httpbootconfigs 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: HTTPBootConfigSpec defines the desired state of HTTPBootConfig + properties: + ignitionSecretRef: + description: IgnitionSecretRef is a reference to the secret containing + Ignition configuration. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + systemIPs: + description: SystemIPs is a list of IP addresses assigned to the server. + items: + type: string + type: array + systemUUID: + description: SystemUUID is the unique identifier (UUID) of the server. + type: string + ukiURL: + description: UKIURL is the URL where the UKI (Unified Kernel Image) + is hosted. + type: string + type: object + status: + description: HTTPBootConfigStatus defines the observed state of HTTPBootConfig + properties: + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +{{- end -}} diff --git a/dist/chart/templates/crd/boot.ironcore.dev_ipxebootconfigs.yaml b/dist/chart/templates/crd/boot.ironcore.dev_ipxebootconfigs.yaml new file mode 100755 index 00000000..7056daa3 --- /dev/null +++ b/dist/chart/templates/crd/boot.ironcore.dev_ipxebootconfigs.yaml @@ -0,0 +1,126 @@ +{{- if .Values.crd.enable }} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + annotations: + {{- if .Values.crd.keep }} + "helm.sh/resource-policy": keep + {{- end }} + controller-gen.kubebuilder.io/version: v0.16.0 + name: ipxebootconfigs.boot.ironcore.dev +spec: + group: boot.ironcore.dev + names: + kind: IPXEBootConfig + listKind: IPXEBootConfigList + plural: ipxebootconfigs + singular: ipxebootconfig + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.state + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: IPXEBootConfig is the Schema for the ipxebootconfigs 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: IPXEBootConfigSpec defines the desired state of IPXEBootConfig + properties: + ignitionSecretRef: + description: IgnitionSecretRef is a reference to the secret containing + the Ignition configuration. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + image: + description: Image is deprecated and will be removed. + type: string + initrdURL: + description: InitrdURL is the URL where the Initrd (initial RAM disk) + of the OS is hosted, eg. the URL to the Initrd layer of the OS OCI + image. + type: string + ipxeScriptSecretRef: + description: IPXEScriptSecretRef is a reference to the secret containing + the custom IPXE script. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + ipxeServerURL: + description: IPXEServerURL is deprecated and will be removed. + type: string + kernelURL: + description: KernelURL is the URL where the kernel of the OS is hosted, + eg. the URL to the Kernel layer of the OS OCI image. + type: string + squashfsURL: + description: SquashfsURL is the URL where the Squashfs of the OS is + hosted, eg. the URL to the Squashfs layer of the OS OCI image. + type: string + systemIPs: + description: SystemIPs is a list of IP addresses assigned to the server. + items: + type: string + type: array + systemUUID: + description: SystemUUID is the unique identifier (UUID) of the server. + type: string + type: object + status: + description: IPXEBootConfigStatus defines the observed state of IPXEBootConfig + properties: + state: + description: 'Important: Run "make" to regenerate code after modifying + this file' + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +{{- end -}} diff --git a/dist/chart/templates/manager/manager.yaml b/dist/chart/templates/manager/manager.yaml new file mode 100644 index 00000000..e0ea1d6f --- /dev/null +++ b/dist/chart/templates/manager/manager.yaml @@ -0,0 +1,78 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: boot-operator-controller-manager + namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} + control-plane: controller-manager +spec: + replicas: {{ .Values.controllerManager.replicas }} + strategy: + type: {{ .Values.controllerManager.strategy.type | quote }} + selector: + matchLabels: + {{- include "chart.selectorLabels" . | nindent 6 }} + control-plane: controller-manager + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + {{- include "chart.labels" . | nindent 8 }} + control-plane: controller-manager + {{- if and .Values.controllerManager.pod .Values.controllerManager.pod.labels }} + {{- range $key, $value := .Values.controllerManager.pod.labels }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + spec: + containers: + - name: manager + args: + {{- range .Values.controllerManager.manager.args }} + - {{ . }} + {{- end }} + command: + - /manager + image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag }} + {{- if .Values.controllerManager.manager.env }} + env: + {{- range $key, $value := .Values.controllerManager.manager.env }} + - name: {{ $key }} + value: {{ $value }} + {{- end }} + {{- end }} + livenessProbe: + {{- toYaml .Values.controllerManager.manager.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.controllerManager.manager.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.controllerManager.manager.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.controllerManager.manager.containerSecurityContext | nindent 12 }} + {{- if and .Values.certmanager.enable (or .Values.webhook.enable .Values.metrics.enable) }} + volumeMounts: + {{- if and .Values.metrics.enable .Values.certmanager.enable }} + - name: metrics-certs + mountPath: /tmp/k8s-metrics-server/metrics-certs + readOnly: true + {{- end }} + {{- end }} + securityContext: + {{- toYaml .Values.controllerManager.podSecurityContext | nindent 8 }} + serviceAccountName: {{ .Values.controllerManager.serviceAccountName }} + hostNetwork: {{ .Values.controllerManager.hostNetwork }} + terminationGracePeriodSeconds: {{ .Values.controllerManager.terminationGracePeriodSeconds }} + {{- if and .Values.certmanager.enable (or .Values.webhook.enable .Values.metrics.enable) }} + volumes: + {{- if and .Values.metrics.enable .Values.certmanager.enable }} + - name: metrics-certs + secret: + secretName: metrics-server-cert + {{- end }} + {{- end }} + {{- if .Values.controllerManager.tolerations }} + tolerations: + {{- toYaml .Values.controllerManager.tolerations | nindent 8 }} + {{- end }} diff --git a/dist/chart/templates/metrics/metrics-service.yaml b/dist/chart/templates/metrics/metrics-service.yaml new file mode 100644 index 00000000..60a0f5da --- /dev/null +++ b/dist/chart/templates/metrics/metrics-service.yaml @@ -0,0 +1,17 @@ +{{- if .Values.metrics.enable }} +apiVersion: v1 +kind: Service +metadata: + name: boot-operator-controller-manager-metrics-service + namespace: {{ .Release.Namespace }} + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + ports: + - port: 8443 + targetPort: 8443 + protocol: TCP + name: https + selector: + control-plane: controller-manager +{{- end }} diff --git a/dist/chart/templates/prometheus/monitor.yaml b/dist/chart/templates/prometheus/monitor.yaml new file mode 100644 index 00000000..361217c0 --- /dev/null +++ b/dist/chart/templates/prometheus/monitor.yaml @@ -0,0 +1,39 @@ +# To integrate with Prometheus. +{{- if .Values.prometheus.enable }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: boot-operator-controller-manager-metrics-monitor + namespace: {{ .Release.Namespace }} +spec: + endpoints: + - path: /metrics + port: https + scheme: https + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + tlsConfig: + {{- if .Values.certmanager.enable }} + serverName: boot-operator-controller-manager-metrics-service.{{ .Release.Namespace }}.svc + # Apply secure TLS configuration with cert-manager + insecureSkipVerify: false + ca: + secret: + name: metrics-server-cert + key: ca.crt + cert: + secret: + name: metrics-server-cert + key: tls.crt + keySecret: + name: metrics-server-cert + key: tls.key + {{- else }} + # Development/Test mode (insecure configuration) + insecureSkipVerify: true + {{- end }} + selector: + matchLabels: + control-plane: controller-manager +{{- end }} diff --git a/dist/chart/templates/rbac/auth_proxy_client_clusterrole.yaml b/dist/chart/templates/rbac/auth_proxy_client_clusterrole.yaml new file mode 100755 index 00000000..7ef1bcc8 --- /dev/null +++ b/dist/chart/templates/rbac/auth_proxy_client_clusterrole.yaml @@ -0,0 +1,13 @@ +{{- if .Values.rbac.enable }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: boot-operator-metrics-reader +rules: +- nonResourceURLs: + - "/metrics" + verbs: + - get +{{- end -}} diff --git a/dist/chart/templates/rbac/auth_proxy_role.yaml b/dist/chart/templates/rbac/auth_proxy_role.yaml new file mode 100755 index 00000000..2bb72f41 --- /dev/null +++ b/dist/chart/templates/rbac/auth_proxy_role.yaml @@ -0,0 +1,21 @@ +{{- if .Values.rbac.enable }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +{{- end -}} diff --git a/dist/chart/templates/rbac/auth_proxy_role_binding.yaml b/dist/chart/templates/rbac/auth_proxy_role_binding.yaml new file mode 100755 index 00000000..493b38a4 --- /dev/null +++ b/dist/chart/templates/rbac/auth_proxy_role_binding.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.enable }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: proxy-role +subjects: +- kind: ServiceAccount + name: {{ .Values.controllerManager.serviceAccountName }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/dist/chart/templates/rbac/auth_proxy_service.yaml b/dist/chart/templates/rbac/auth_proxy_service.yaml new file mode 100755 index 00000000..b665f0dc --- /dev/null +++ b/dist/chart/templates/rbac/auth_proxy_service.yaml @@ -0,0 +1,17 @@ +{{- if .Values.rbac.enable }} +apiVersion: v1 +kind: Service +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: {{ .Values.controllerManager.serviceAccountName }}-metrics-service + namespace: {{ .Release.Namespace }} +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: + control-plane: controller-manager +{{- end -}} diff --git a/dist/chart/templates/rbac/httpbootconfig_editor_role.yaml b/dist/chart/templates/rbac/httpbootconfig_editor_role.yaml new file mode 100755 index 00000000..03206b12 --- /dev/null +++ b/dist/chart/templates/rbac/httpbootconfig_editor_role.yaml @@ -0,0 +1,28 @@ +{{- if .Values.rbac.enable }} +# permissions for end users to edit httpbootconfigs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: httpbootconfig-editor-role +rules: +- apiGroups: + - boot.ironcore.dev + resources: + - httpbootconfigs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - boot.ironcore.dev + resources: + - httpbootconfigs/status + verbs: + - get +{{- end -}} diff --git a/dist/chart/templates/rbac/httpbootconfig_viewer_role.yaml b/dist/chart/templates/rbac/httpbootconfig_viewer_role.yaml new file mode 100755 index 00000000..b82c9e2d --- /dev/null +++ b/dist/chart/templates/rbac/httpbootconfig_viewer_role.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.enable }} +# permissions for end users to view httpbootconfigs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: httpbootconfig-viewer-role +rules: +- apiGroups: + - boot.ironcore.dev + resources: + - httpbootconfigs + verbs: + - get + - list + - watch +- apiGroups: + - boot.ironcore.dev + resources: + - httpbootconfigs/status + verbs: + - get +{{- end -}} diff --git a/dist/chart/templates/rbac/ipxebootconfig_editor_role.yaml b/dist/chart/templates/rbac/ipxebootconfig_editor_role.yaml new file mode 100755 index 00000000..5afca5fa --- /dev/null +++ b/dist/chart/templates/rbac/ipxebootconfig_editor_role.yaml @@ -0,0 +1,28 @@ +{{- if .Values.rbac.enable }} +# permissions for end users to edit ipxebootconfigs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: ipxebootconfig-editor-role +rules: +- apiGroups: + - boot.ironcore.dev + resources: + - ipxebootconfigs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - boot.ironcore.dev + resources: + - ipxebootconfigs/status + verbs: + - get +{{- end -}} diff --git a/dist/chart/templates/rbac/ipxebootconfig_viewer_role.yaml b/dist/chart/templates/rbac/ipxebootconfig_viewer_role.yaml new file mode 100755 index 00000000..3c6f66f9 --- /dev/null +++ b/dist/chart/templates/rbac/ipxebootconfig_viewer_role.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.enable }} +# permissions for end users to view ipxebootconfigs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: ipxebootconfig-viewer-role +rules: +- apiGroups: + - boot.ironcore.dev + resources: + - ipxebootconfigs + verbs: + - get + - list + - watch +- apiGroups: + - boot.ironcore.dev + resources: + - ipxebootconfigs/status + verbs: + - get +{{- end -}} diff --git a/dist/chart/templates/rbac/leader_election_role.yaml b/dist/chart/templates/rbac/leader_election_role.yaml new file mode 100755 index 00000000..574da3bf --- /dev/null +++ b/dist/chart/templates/rbac/leader_election_role.yaml @@ -0,0 +1,42 @@ +{{- if .Values.rbac.enable }} +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + namespace: {{ .Release.Namespace }} + name: boot-operator-leader-election-role +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 +{{- end -}} diff --git a/dist/chart/templates/rbac/leader_election_role_binding.yaml b/dist/chart/templates/rbac/leader_election_role_binding.yaml new file mode 100755 index 00000000..c4db5ad4 --- /dev/null +++ b/dist/chart/templates/rbac/leader_election_role_binding.yaml @@ -0,0 +1,17 @@ +{{- if .Values.rbac.enable }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + namespace: {{ .Release.Namespace }} + name: boot-operator-leader-election-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: boot-operator-leader-election-role +subjects: +- kind: ServiceAccount + name: {{ .Values.controllerManager.serviceAccountName }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/dist/chart/templates/rbac/role.yaml b/dist/chart/templates/rbac/role.yaml new file mode 100755 index 00000000..b40396bb --- /dev/null +++ b/dist/chart/templates/rbac/role.yaml @@ -0,0 +1,89 @@ +{{- if .Values.rbac.enable }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: boot-operator-manager-role +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +- apiGroups: + - boot.ironcore.dev + resources: + - httpbootconfig + - ipxebootconfig + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: + - boot.ironcore.dev + resources: + - httpbootconfig/status + - ipxebootconfig/status + verbs: + - get +- apiGroups: + - boot.ironcore.dev + resources: + - httpbootconfigs + - ipxebootconfigs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - boot.ironcore.dev + resources: + - httpbootconfigs/finalizers + - ipxebootconfigs/finalizers + verbs: + - update +- apiGroups: + - boot.ironcore.dev + resources: + - httpbootconfigs/status + - ipxebootconfigs/status + verbs: + - get + - patch + - update +- apiGroups: + - metal.ironcore.dev + resources: + - serverbootconfigurations + - servers + verbs: + - get + - list + - watch +- apiGroups: + - metal.ironcore.dev + resources: + - serverbootconfigurations/finalizers + verbs: + - update +- apiGroups: + - metal.ironcore.dev + resources: + - serverbootconfigurations/status + verbs: + - get + - patch + - update +{{- end -}} diff --git a/dist/chart/templates/rbac/role_binding.yaml b/dist/chart/templates/rbac/role_binding.yaml new file mode 100755 index 00000000..8822ef43 --- /dev/null +++ b/dist/chart/templates/rbac/role_binding.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.enable }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + name: boot-operator-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: boot-operator-manager-role +subjects: +- kind: ServiceAccount + name: {{ .Values.controllerManager.serviceAccountName }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/dist/chart/templates/rbac/service_account.yaml b/dist/chart/templates/rbac/service_account.yaml new file mode 100755 index 00000000..93e0a323 --- /dev/null +++ b/dist/chart/templates/rbac/service_account.yaml @@ -0,0 +1,15 @@ +{{- if .Values.rbac.enable }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + {{- include "chart.labels" . | nindent 4 }} + {{- if and .Values.controllerManager.serviceAccount .Values.controllerManager.serviceAccount.annotations }} + annotations: + {{- range $key, $value := .Values.controllerManager.serviceAccount.annotations }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + name: {{ .Values.controllerManager.serviceAccountName }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/dist/chart/values.yaml b/dist/chart/values.yaml new file mode 100644 index 00000000..d354602b --- /dev/null +++ b/dist/chart/values.yaml @@ -0,0 +1,87 @@ +# [MANAGER]: Manager Deployment Configurations +controllerManager: + replicas: 1 + manager: + image: + repository: registry/boot-operator + tag: "v0.1.0" + args: + - "--ipxe-service-url=ipxe-service-url" + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + livenessProbe: + initialDelaySeconds: 15 + periodSeconds: 20 + httpGet: + path: /healthz + port: 8081 + readinessProbe: + initialDelaySeconds: 5 + periodSeconds: 10 + httpGet: + path: /readyz + port: 8081 + containerSecurityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + podSecurityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + terminationGracePeriodSeconds: 10 + serviceAccountName: controller-manager + hostNetwork: false + strategy: + type: Recreate + tolerations: + - key: node-role.kubernetes.io/control-plane + effect: NoSchedule + +# [RBAC]: To enable RBAC (Permissions) configurations +rbac: + enable: true + +# [CRDs]: To enable the CRDs +crd: + # This option determines whether the CRDs are included + # in the installation process. + enable: true + + # Enabling this option adds the "helm.sh/resource-policy": keep + # annotation to the CRD, ensuring it remains installed even when + # the Helm release is uninstalled. + # NOTE: Removing the CRDs will also remove all cert-manager CR(s) + # (Certificates, Issuers, ...) due to garbage collection. + keep: false + +# [METRICS]: Set to true to generate manifests for exporting metrics. +# To disable metrics export set false, and ensure that the +# ControllerManager argument "--metrics-bind-address=:8443" is removed. +metrics: + enable: false + +# [WEBHOOKS]: Webhooks configuration +# The following configuration is automatically generated from the manifests +# generated by controller-gen. To update run 'make manifests' and +# the edit command with the '--force' flag +webhook: + enable: true + +# [PROMETHEUS]: To enable a ServiceMonitor to export metrics to Prometheus set true +prometheus: + enable: false + +# [CERT-MANAGER]: To enable cert-manager injection to webhooks set true +certmanager: + enable: true + +# [NETWORK POLICIES]: To enable NetworkPolicies set true +networkPolicy: + enable: false diff --git a/docs/usage/installation.md b/docs/usage/installation.md new file mode 100644 index 00000000..6b982865 --- /dev/null +++ b/docs/usage/installation.md @@ -0,0 +1,81 @@ +# Helm Installation Guide + +This guide will help you install the Boot Operator using Helm. + +## Prerequisites + +- Kubernetes cluster (v1.16+) +- Helm (v3.0.0+) + +## Steps + +1. **Install the Chart** + + Install the Boot Operator chart with the default values. + + ```sh + helm install boot-operator dist/chart + ``` + + To customize the installation, you can override the default values using a `values.yaml` file or the `--set` flag. + + ```sh + helm install boot-operator dist/chart -f /path/to/your/values.yaml + ``` + +2. **Verify the Installation** + + Check the status of the Helm release to ensure that the Boot Operator is installed successfully. + + ```sh + helm status boot-operator + ``` + + You should see output indicating that the Boot Operator pods are running. + +## Configuration + +The `values.yaml` file allows you to configure various aspects of the Boot Operator. Below are some of the key configurations: + +### Controller Manager + +| Key | Description | Default Value | +|------------------------------------|-----------------------------------------------------------------------------|--------------------------------| +| `controllerManager.replicas` | Number of replicas for the manager deployment | `1` | +| `controllerManager.manager.image.repository` | Image repository for the manager container | `registry/boot-operator` | +| `controllerManager.manager.image.tag` | Image tag for the manager container | `"v0.1.0"` | +| `controllerManager.manager.args` | Arguments for the manager container | `--ipxe-service-url=ipxe-service-url` | +| `controllerManager.manager.resources` | Resource requests and limits for the manager container | `{cpu: 500m, memory: 128Mi}` (limits), `{cpu: 10m, memory: 64Mi}` (requests) | +| `controllerManager.manager.livenessProbe` | Liveness probe configuration for the manager container | `{initialDelaySeconds: 15, periodSeconds: 20, httpGet: {path: /healthz, port: 8081}}` | +| `controllerManager.manager.readinessProbe` | Readiness probe configuration for the manager container | `{initialDelaySeconds: 5, periodSeconds: 10, httpGet: {path: /readyz, port: 8081}}` | +| `controllerManager.manager.containerSecurityContext` | Security context for the manager container | `{allowPrivilegeEscalation: false, capabilities: {drop: ["ALL"]}}` | +| `controllerManager.podSecurityContext` | Security context for the manager pod | `{runAsNonRoot: true, seccompProfile: {type: RuntimeDefault}}` | +| `controllerManager.terminationGracePeriodSeconds` | Termination grace period for the manager pod | `10` | +| `controllerManager.serviceAccountName` | Service account name for the manager pod | `controller-manager` | +| `controllerManager.tolerations` | Tolerations for the manager pod | `[{key: node-role.kubernetes.io/control-plane, effect: NoSchedule}]` | +| `controllerManager.hostNetwork` | Enable host networking for the manager pod | `false` | +| `controllerManager.strategy.type` | Deployment strategy for the manager pod | `Recreate` | + +- **rbac**: Enable or disable RBAC. +- **crd**: Enable or disable CRDs. +- **metrics**: Enable or disable metrics export. +- **webhook**: Enable or disable webhooks. +- **prometheus**: Enable or disable Prometheus ServiceMonitor. +- **certmanager**: Enable or disable cert-manager injection. +- **networkPolicy**: Enable or disable NetworkPolicies. + +Refer to the `values.yaml` file for more details on each configuration option. + +## Uninstallation + +To uninstall the Boot Operator, run the following command: + +```sh +helm uninstall boot-operator +``` + +This will remove all the resources associated with the Boot Operator. + +## Additional Information + +For more detailed information, refer to the official documentation and Helm chart repository. \ No newline at end of file