Merge pull request 'init for moving Edge 3.1 images from IBS' (#1) from import-3.1 into main

Reviewed-on: #1
Reviewed-by: Nicolas Belouin <nbelouin@noreply.src.opensuse.org>
This commit is contained in:
Denislav Prodanov 2024-10-22 10:34:19 +02:00
commit 984b53264c
250 changed files with 25168 additions and 0 deletions

View File

@ -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" ]

View File

@ -0,0 +1,17 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service mode="buildtime" name="docker_label_helper"/>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="regex">%%baremetal-operator_version%%</param>
<param name="package">baremetal-operator</param>
<param name="parse-version">patch</param>
</service>
<service name="replace_using_env" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
</service>
</services>

9
cdi-chart/Chart.yaml Normal file
View File

@ -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

8
cdi-chart/_service Normal file
View File

@ -0,0 +1,8 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service name="replace_using_env" mode="buildtime">
<param name="file">Chart.yaml</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
</service>
</services>

5082
cdi-chart/crds/cdi.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
Verify that all CDI components are installed correctly:
kubectl get all -n {{ .Release.Namespace }}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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

View File

@ -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

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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

View File

@ -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=

38
cdi-chart/values.yaml Normal file
View File

@ -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

View File

@ -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 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" ]

View File

@ -0,0 +1,17 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service mode="buildtime" name="docker_label_helper"/>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="regex">%%cluster-api_version%%</param>
<param name="package">cluster-api</param>
<param name="parse-version">patch</param>
</service>
<service name="replace_using_env" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
</service>
</services>

View File

@ -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 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" ]

View File

@ -0,0 +1,17 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service mode="buildtime" name="docker_label_helper"/>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="regex">%%cluster-api-operator_version%%</param>
<param name="package">cluster-api-operator</param>
<param name="parse-version">patch</param>
</service>
<service name="replace_using_env" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
</service>
</services>

View File

@ -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 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" ]

View File

@ -0,0 +1,17 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service mode="buildtime" name="docker_label_helper"/>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="regex">%%cluster-api-provider-metal3_version%%</param>
<param name="package">cluster-api-provider-metal3</param>
<param name="parse-version">patch</param>
</service>
<service name="replace_using_env" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
</service>
</services>

View File

@ -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-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" ]

View File

@ -0,0 +1,17 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service mode="buildtime" name="docker_label_helper"/>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="regex">%%cluster-api-provider-rke2_version%%</param>
<param name="package">cluster-api-provider-rke2-bootstrap</param>
<param name="parse-version">patch</param>
</service>
<service name="replace_using_env" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
</service>
</services>

View File

@ -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-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" ]

View File

@ -0,0 +1,17 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service mode="buildtime" name="docker_label_helper"/>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="regex">%%cluster-api-provider-rke2_version%%</param>
<param name="package">cluster-api-provider-rke2-control-plane</param>
<param name="parse-version">patch</param>
</service>
<service name="replace_using_env" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
</service>
</services>

View File

@ -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 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"]

View File

@ -0,0 +1,14 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service name="replace_using_env" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
<param name="file">artifacts.yaml</param>
<param name="eval">CHART_REPO=$(rpm --macros=/root/.rpmmacros -E %chart_repo)</param>
<param name="var">CHART_REPO</param>
</service>
</services>

View File

@ -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

View File

@ -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 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" ]

View File

@ -0,0 +1,17 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service mode="buildtime" name="docker_label_helper"/>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="regex">%%ip-address-manager_version%%</param>
<param name="package">ip-address-manager</param>
<param name="parse-version">patch</param>
</service>
<service name="replace_using_env" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
</service>
</services>

91
ironic-image/Dockerfile Normal file
View File

@ -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

17
ironic-image/_service Normal file
View File

@ -0,0 +1,17 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service mode="buildtime" name="docker_label_helper"/>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="regex">%%openstack-ironic_version%%</param>
<param name="package">openstack-ironic</param>
<param name="parse-version">patch</param>
</service>
<service name="replace_using_env" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
</service>
</services>

View File

@ -0,0 +1,27 @@
Listen {{ env.VMEDIA_TLS_PORT }}
<VirtualHost *:{{ 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 }}
<Directory "/shared">
AllowOverride None
Require all granted
</Directory>
<Directory "/shared/html">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
<Location ~ "^/(redfish|ilo)/">
SSLRequireSSL
</Location>

View File

@ -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
}

View File

@ -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
# <interface> - all VLANs on a particular interface using LLDP information
# <interface.vlan> - 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"

View File

@ -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/

View File

@ -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 %}

View File

@ -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 }}
<VirtualHost *:{{ env.IRONIC_LISTEN_PORT }}>
{% else %}
Listen {{ env.IRONIC_URL_HOST }}:{{ env.IRONIC_LISTEN_PORT }}
<VirtualHost {{ 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" %}
<Location />
{% if "IRONIC_HTPASSWD" in env and env.IRONIC_HTPASSWD | length %}
AuthType Basic
AuthName "Restricted area"
AuthUserFile "/etc/ironic/htpasswd"
Require valid-user
{% endif %}
</Location>
{% else %}
<Directory /usr/bin >
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 %}
</Directory>
{% endif %}
<Location ~ "^/(v1/?)?$" >
Require all granted
</Location>
<Location ~ "^/(v1/)?(lookup|heartbeat|continue_inspection)" >
Require all granted
</Location>
</VirtualHost>

View File

@ -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

View File

@ -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
<Directory />
AllowOverride none
Require all denied
</Directory>
DocumentRoot "/shared/html"
<Directory "/shared/html">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
{%- if env.HTTPD_SERVE_NODE_IMAGES | lower == "true" %}
<Directory "/shared/html/images">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
{% endif %}
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
<Files ".ht*">
Require all denied
</Files>
ErrorLog "/dev/stderr"
LogLevel warn
<IfModule log_config_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
CustomLog "/dev/stderr" combined
</IfModule>
<IfModule mime_module>
TypesConfig /etc/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
</IfModule>
AddDefaultCharset UTF-8
<IfModule mime_magic_module>
MIMEMagicFile conf/magic
</IfModule>
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

View File

@ -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 }}
<VirtualHost *:{{ env.IRONIC_INSPECTOR_LISTEN_PORT }}>
{% else %}
Listen {{ env.IRONIC_URL_HOST }}:{{ env.IRONIC_INSPECTOR_LISTEN_PORT }}
<VirtualHost {{ 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 %}
<Location / >
AuthType Basic
AuthName "Restricted area"
AuthUserFile "/etc/ironic-inspector/htpasswd"
Require valid-user
</Location>
<Location ~ "^/(v1/?)?$" >
Require all granted
</Location>
<Location /v1/continue >
Require all granted
</Location>
{% endif %}
</VirtualHost>

View File

@ -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

View File

@ -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

View File

@ -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 %}

253
ironic-image/ironic.conf.j2 Normal file
View File

@ -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 <X> -N <Y> ...
# 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 %}

View File

@ -0,0 +1,3 @@
#!/bin/sh
xorriso -as mkisofs "${@}"

View File

@ -0,0 +1 @@
{}

View File

@ -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;

35
ironic-image/rundnsmasq Normal file
View File

@ -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))' </etc/dnsmasq.conf.j2 >/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

101
ironic-image/runhttpd Normal file
View File

@ -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/<redifsh;ilo>
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/<redifsh;ilo> 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

25
ironic-image/runironic Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

101
ironic-image/tls-common.sh Normal file
View File

@ -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

View File

@ -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-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

View File

@ -0,0 +1,17 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service mode="buildtime" name="docker_label_helper"/>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="regex">%%openstack-ironic-image-x86_64_version%%</param>
<param name="package">openstack-ironic-image-x86_64</param>
<param name="parse-version">patch</param>
</service>
<service name="replace_using_env" mode="buildtime">
<param name="file">Dockerfile</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
</service>
</services>

View File

@ -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}

View File

@ -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

27
metal3-chart/Chart.yaml Normal file
View File

@ -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

100
metal3-chart/README.md Normal file
View File

@ -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=<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: "<STATIC_IRONIC_IP>"
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
```

15
metal3-chart/_service Normal file
View File

@ -0,0 +1,15 @@
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service name="replace_using_env" mode="buildtime">
<param name="file">values.yaml</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
<param name="eval">IMG_REPO=$(rpm --macros=/root/.rpmmacros -E %img_repo)</param>
<param name="var">IMG_REPO</param>
</service>
<service name="replace_using_env" mode="buildtime">
<param name="file">Chart.yaml</param>
<param name="eval">IMG_PREFIX=$(rpm --macros=/root/.rpmmacros -E %img_prefix)</param>
<param name="var">IMG_PREFIX</param>
</service>
</services>

View File

@ -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.

View File

@ -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/

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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: {}

View File

@ -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: {}

View File

@ -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

View File

@ -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: {}

View File

@ -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: {}

View File

@ -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: {}

View File

@ -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: {}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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: {}

View File

@ -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

View File

@ -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" . }}

View File

@ -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

View File

@ -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

View File

@ -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 }}

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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/

View File

@ -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

View File

@ -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.

View File

@ -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 }}

View File

@ -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 }}

Some files were not shown because too many files have changed in this diff Show More