From b0a8b35dd91148f62561a7f34213ea61ada65165 Mon Sep 17 00:00:00 2001 From: mrwho Date: Sun, 19 Jul 2026 14:41:22 +0300 Subject: [PATCH] feat(infra): add uyuni role for configuration management Added new ansible role `roles/uyuni/` to enable configuration and management of Uyuni satellite server infrastructure. --- .../uyuni/files/uyuni/server-helm/.helmignore | 3 + .../uyuni/files/uyuni/server-helm/Chart.yaml | 8 + roles/uyuni/files/uyuni/server-helm/README.md | 309 ++++++ .../uyuni/server-helm/templates/NOTES.txt | 6 + .../uyuni/server-helm/templates/_helpers.tpl | 107 ++ .../uyuni/server-helm/templates/coco.yaml | 97 ++ .../uyuni/server-helm/templates/config.yaml | 25 + .../files/uyuni/server-helm/templates/db.yaml | 90 ++ .../uyuni/server-helm/templates/gateway.yaml | 86 ++ .../uyuni/server-helm/templates/hub.yaml | 51 + .../uyuni/server-helm/templates/ingress.yaml | 431 ++++++++ .../uyuni/server-helm/templates/pvcs.yaml | 27 + .../uyuni/server-helm/templates/routes.yaml | 226 +++++ .../uyuni/server-helm/templates/saline.yaml | 67 ++ .../uyuni/server-helm/templates/server.yaml | 552 ++++++++++ .../uyuni/server-helm/templates/services.yaml | 293 ++++++ .../server-helm/templates/tcp-routes.yaml | 110 ++ .../uyuni/server-helm/templates/tftp.yaml | 57 ++ .../server-helm/templates/traefik-routes.yaml | 150 +++ roles/uyuni/files/uyuni/server-helm/test.sh | 19 + .../uyuni/files/uyuni/server-helm/tito.props | 3 + .../uyuni/server-helm/values.schema.json | 451 +++++++++ .../uyuni/files/uyuni/server-helm/values.yaml | 952 ++++++++++++++++++ 23 files changed, 4120 insertions(+) create mode 100644 roles/uyuni/files/uyuni/server-helm/.helmignore create mode 100644 roles/uyuni/files/uyuni/server-helm/Chart.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/README.md create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/NOTES.txt create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/_helpers.tpl create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/coco.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/config.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/db.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/gateway.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/hub.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/ingress.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/pvcs.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/routes.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/saline.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/server.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/services.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/tcp-routes.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/tftp.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/templates/traefik-routes.yaml create mode 100644 roles/uyuni/files/uyuni/server-helm/test.sh create mode 100644 roles/uyuni/files/uyuni/server-helm/tito.props create mode 100644 roles/uyuni/files/uyuni/server-helm/values.schema.json create mode 100644 roles/uyuni/files/uyuni/server-helm/values.yaml diff --git a/roles/uyuni/files/uyuni/server-helm/.helmignore b/roles/uyuni/files/uyuni/server-helm/.helmignore new file mode 100644 index 0000000..5a2b175 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/.helmignore @@ -0,0 +1,3 @@ +/*.changes +/_* + diff --git a/roles/uyuni/files/uyuni/server-helm/Chart.yaml b/roles/uyuni/files/uyuni/server-helm/Chart.yaml new file mode 100644 index 0000000..dc70e50 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/Chart.yaml @@ -0,0 +1,8 @@ +apiVersion: v2 +appVersion: "2026.06" +description: Uyuni server +home: https://www.uyuni-project.org/ +icon: https://www.uyuni-project.org/img/uyuni-logo.svg +name: server-helm +type: application +version: 5.2.9 diff --git a/roles/uyuni/files/uyuni/server-helm/README.md b/roles/uyuni/files/uyuni/server-helm/README.md new file mode 100644 index 0000000..9d8ea63 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/README.md @@ -0,0 +1,309 @@ +# server-helm + +This chart installs [Uyuni server](https://uyuni-project.org). +This is deploying the core features, [the uyuni-charts repository](https://github.com/uyuni-project/uyuni-charts) contains some examples Helm charts using it in conjunction with other tools. + +## Configuration + +### Secrets + +The following secrets with `kubernetes.io/basic-auth` type are required. +They need to contain a `username` and a `password` key. + +- `db-admin-credentials`: PostgreSQL administrator credentials +- `db-credentials`: credentials for the internal database user +- `reportdb-credentials`: credentials for the report database user +- `admin-credentials`: credentials for the server administrator + +SCC organization mirroring credentials can be automatically set if the name of secret of `kubernetes.io/basic-auth` type with those credentials is set as `server.sccSecret` value. + +The following TLS secrets are expected: + +- `db-cert`: is the TLS certificate for the report database and needs to have the `db` and `reportdb` Subject Alternate Names as well as the FQDN exposed to the outside world +- `uyuni-cert`: is the TLS certificate for the ingress rule and needs to have the public FQDN as Subject Alternate Name. + +Pulling images from a registry requiring authentication requires a secret of `kubernetes.io/dockerconfigjson` type. +Its name needs to be passed as the `registrySecret` value. + +### ConfigMaps + +The Root CA certificate of `db-cert` and `uyuni-cert` are expected in ConfigMaps named `db-ca` and `uyuni-ca` with the certificate in the `ca.crt` key. + +### Persistent Volumes + +The following persistent volume claims will be created and will need to be bound to persistent volumes. + +- `ca-certs`: (default size: 10Mi) +- `etc-apache2`: (default size: 1Mi) +- `etc-cobbler`: (default size: 1Mi) +- `etc-postfix`: (default size: 1Mi) +- `etc-rhn`: (default size: 1Mi) +- `etc-salt`: (default size: 1Mi) +- `etc-sssd`: (default size: 1Mi) +- `etc-sysconfig`: (default size: 20Mi) +- `etc-systemd-multi`: (default size: 1Mi) +- `etc-systemd-sockets`: (default size: 1Mi) +- `etc-tomcat`: (default size: 1Mi) +- `run-salt-master`: (default size: 10Mi) +- `srv-formulametadata`: (default size: 10Mi) +- `srv-pillar`: (default size: 10Mi) +- `srv-salt`: (default size: 10Mi) +- `srv-spacewalk`: (default size: 10Mi) +- `srv-susemanager`: (default size: 1Mi) +- `srv-tftpboot`: (default size: 300Mi) +- `srv-www`: (default size: 100Gi) +- `var-cache`: (default size: 10Gi) +- `var-cobbler`: (default size: 10Mi) +- `var-log`: (default size: 2Gi) +- `var-pgsql18`: (default size: 50Gi) +- `var-salt`: (default size: 10Mi) +- `var-search`: (default size: 10Gi) +- `var-spacewalk`: (default size: 100Gi) + +They all are using the `ReadWriteOnce` access mode and can be configured in the values. + +Changing the default volume sizes according to the distributions you plan to synchronize and manage is recommended. +See the [requirements documentation](https://www.uyuni-project.org/uyuni-docs/en/uyuni/installation-and-upgrade/uyuni-install-requirements.html) for more information. + +The `volumes.storageClass` can be used to change the storage class of all the persistent volume claims. +This would be overridden by each claim's `volumes..storageClass` value. + +The storage class supports a special `"-"` value to force the storage class to the empty string. +This is different from the `""` value representing the default storage class by not setting any storage class at all. + +Additional volumes can be attached to the server pod with `server.extraVolumes` and mounted into the server container with `server.extraVolumeMounts`. +This is useful for optional content volumes like `inter-server-sync` data without changing the chart templates. + +For example: + +```yaml +server: + extraVolumes: + - name: inter-server-sync-data + persistentVolumeClaim: + claimName: inter-server-sync-data + + extraVolumeMounts: + - name: inter-server-sync-data + mountPath: /inter-server-sync-data + readOnly: true +``` + +### Node Tuning + +For each of the components it is possible to tune the node where the pod will be scheduled. +This chart supports a **default** configuration with **local overrides**, allowing baseline rules to be set for all pods and customized for specific components when needed. + +Scheduling can be controlled using `nodeSelector`, `affinity`, `tolerations`, or `nodeName`. It is not necessary to use all of them; simply choose the method that matches the cluster's scheduling strategy. + +For example, to set a baseline rule for all components but override the placement for the `db` pod specifically, the `values.yaml` would look like this: + +```yaml +# DEFAULTS +# These rules apply to all pods unless overridden by a specific component. +placement: + nodeSelector: + environment: production + + tolerations: + - key: "server-tier" + operator: "Equal" + value: "true" + effect: "NoSchedule" + +# LOCAL OVERRIDES +# These rules apply ONLY to the specific component and override the global equivalents. +db: + nodeSelector: + "kubernetes.io/hostname": "node-42" + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: "kubernetes.io/hostname" + operator: In + values: + - "node-42" + + # nodeName: "node-42" +``` + +### Exposing ports + +Uyuni requires some TCP and UDP ports to be routed to its services. +Here is a list of the ports to map: + + +| Protocol | Port | Service name | Service port | | +| -------- | ----- | ------------ | ------------ | ------------------------------------------------ | +| TCP | 5432 | reportdb | 5432 | | +| TCP | 4505 | salt | 4505 | | +| TCP | 4506 | salt | 4506 | | +| TCP | 8001 | taskomatic | 8001 | Only if installed with `exposeJavaDebug = true` | +| TCP | 8002 | search | 8002 | Only if installed with `exposeJavaDebug = true` | +| TCP | 8003 | tomcat | 8003 | Only if installed with `exposeJavaDebug = true` | + + +Exposing the `tftp` service has to be done differently due to the way TFTP protocol is working. +Either use the host network using the `tftp.hostNetwork` value or configure a load balancer for the `tftp` service. +Note that not all load balancers will work: `serviceLB` implementation is not compatible with TFTP protocol, while MetalLB works. + +### Ingress vs Gateway API + +The helm chart deploys ingress rules by default. +Switching to [Gateway API](https://gateway-api.sigs.k8s.io/) instead is possible though requires more effort. +The Gateway API implementation used in this helm chart is aligned with the one handled by the traefik shipped with the latest RKE2. + +Using the Gateway API routes is still experimental as some of the needed resources, namely `TCPRoute` are not stable yet. +To enable it, set the `gateway.enable` value. +The other values in the `gateway` structure may need to be set depending on the cluster setup. + +**Note that on RKE2 1.35 on top of enabling Traefik with Gateway API, the `TLSRoute` and `TCPRoute` CRDs need to be manually added and the Traefik helm chart has to be deployed with the `providers.kubernetesGateway.experimentalChannel`.** + +### AppArmor + +If the node where the server pod is running has AppArmor, the containerd profile won't let it mount the cgroup2 file system. +This can be addressed in two different ways. +The easiest, but unsafe way is to set `server.superPrivileged=true` value so the server containers run unconfined. +Otherwise set the `server.apparmorProfile` to the name of a profile containing a definition like the following. +If using exactly this content, the name of the profile to use will be `k8s-systemd-uyuni`. + +To deploy the AppArmor profile, copy this content to `/etc/apparmor.d/k8s-systemd-uyuni` and run `apparmor_parser -r /etc/apparmor.d/k8s-systemd-uyuni` to load it. + +``` +#include + +profile k8s-systemd-uyuni flags=(attach_disconnected,mediate_deleted) { + #include + #include + + # Standard container permissions + file, + network, + capability, + ptrace, + unix, + + # Deny writes to critical kernel interfaces that systemd doesn't need to change + deny /sys/firmware/** rwklx, + deny /sys/kernel/debug/** rwklx, + + # Broadly allow the specific flag combinations used for systemd hardening + # This covers /dev/pts/, /dev/mqueue/, and the previous /etc/ errors. + mount options=(ro, nosuid, noexec, nodev, remount, bind) -> **, + mount options=(ro, nosuid, noexec, remount, bind) -> **, + mount options=(ro, nosuid, nodev, remount, bind) -> **, + mount options=(ro, nosuid, remount, bind) -> **, + mount options=(ro, remount, bind) -> **, + + # Allow mount propagation (Required for systemd to function at all) + mount options=(rw, rslave) -> **, + mount options=(rw, slave) -> **, + mount options=(rw, shared) -> **, + + # Specific filesystem types for systemd's API mounts + mount fstype=tmpfs options=(rw, nosuid, nodev, noexec) -> /tmp/, + mount fstype=tmpfs options=(rw, nosuid, nodev) -> /tmp/, + mount fstype=tmpfs -> /run/**, + mount fstype=cgroup2 -> /sys/fs/cgroup/, + mount fstype=mqueue -> /dev/mqueue/, + mount fstype=fusectl -> /sys/fs/fuse/connections/, + mount fstype=devpts -> /dev/pts/, + + # Generic remounts (for general compatibility) + mount options=(rw, remount) -> **, + mount options=(ro, remount) -> **, + + # Required for the uyuni server container specifically + /sys/fs/cgroup/** rw, + /run/** rw, + /var/** rw, + # Allow reading the various config volumes mapped in the chart + /etc/** r, +} +``` + +### SELinux + +If the node where the server pod is running has SELinux and RKE2 is configured to use it, the container won't be able to mount the cgroup2 file system. +This can be addressed in two different ways. +The easiest, but unsafe way is to set `server.superPrivileged=true` value so the server containers run with the `spc_t` label. +Otherwise set the `server.selinuxType` to the name of a custom SELinux type granting only the permissions needed by the server pod. +Defining a dedicated type — rather than extending the generic `container_t` — ensures the extra permissions are not granted to every other container running on the node. +If using exactly the policy below, the name of the type to use will be `uyuni_container_t`. + +To deploy the policy, create a `/root/systemdcontainerpolicy.te` file with this content: + +```sepolicy +module systemdcontainerpolicy 1.0; + +require { + attribute domain; + attribute container_domain; + attribute mcs_constrained_type; + attribute container_net_domain; + attribute svirt_sandbox_domain; + attribute sandbox_net_domain; + attribute syslog_client_type; + attribute can_dump_kernel; + attribute can_receive_kernel_messages; + attribute corenet_unconfined_type; + attribute corenet_unlabeled_type; + attribute kernel_system_state_reader; + attribute pcmcia_typeattr_1; + attribute process_user_target; + role system_r; + type cgroup_t; + type tmpfs_t; + type proc_t; + + class dir { search write add_name create remove_name rmdir setattr getattr mounton }; + class file { create open write append read unlink setattr getattr watch }; + class filesystem { mount getattr relabelfrom relabelto remount unmount }; + class netlink_audit_socket { nlmsg_relay }; +} + +# Declare the uyuni_container_t type and associate it with standard container attributes. +type uyuni_container_t, domain, container_domain, container_net_domain, mcs_constrained_type, svirt_sandbox_domain, sandbox_net_domain, syslog_client_type, can_dump_kernel, can_receive_kernel_messages, corenet_unconfined_type, corenet_unlabeled_type, kernel_system_state_reader, pcmcia_typeattr_1, process_user_target; + +# Associate with the system_r role +role system_r types uyuni_container_t; + +#============= uyuni_container_t ============== +allow uyuni_container_t cgroup_t:dir { add_name create remove_name rmdir setattr write search getattr }; +allow uyuni_container_t cgroup_t:file { create open write append read setattr getattr unlink watch }; +allow uyuni_container_t cgroup_t:filesystem { mount getattr relabelfrom relabelto }; + +# Allow systemd's credential helper (sd-mkdcreds) to use /dev/shm as a mount point for service credentials. +allow uyuni_container_t tmpfs_t:dir mounton; + +# Standard lookups and attributes for the mount point +allow uyuni_container_t tmpfs_t:dir { getattr search }; + +# Allow systemd to mount/remount the proc filesystem for namespacing +allow uyuni_container_t proc_t:filesystem { mount remount unmount }; + +# Required to use directories as mount points +allow uyuni_container_t proc_t:dir mounton; + +# Allow su and PAM inside the container to log audits to the kernel +allow uyuni_container_t self:netlink_audit_socket { nlmsg_relay }; +``` + +Then compile and load it: + +```sh +checkmodule -M -m -o /root/systemdcontainerpolicy.mod /root/systemdcontainerpolicy.te +semodule_package -o /root/systemdcontainerpolicy.pp -m /root/systemdcontainerpolicy.mod +semodule -i /root/systemdcontainerpolicy.pp +``` + +## Usage + +Once installed, the web interface can be accessed directly on the configured FQDN. + +## More Info + +Check the product documentation: https://www.uyuni-project.org/uyuni-docs diff --git a/roles/uyuni/files/uyuni/server-helm/templates/NOTES.txt b/roles/uyuni/files/uyuni/server-helm/templates/NOTES.txt new file mode 100644 index 0000000..d459f67 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/NOTES.txt @@ -0,0 +1,6 @@ +Thank you for installing the {{ .Chart.Description }}! +Connect to the web UI using the credentials from the admin-credentials secret: + + https://{{ .Values.global.fqdn }} + +Documentation can be found at {{ .Chart.Home }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/_helpers.tpl b/roles/uyuni/files/uyuni/server-helm/templates/_helpers.tpl new file mode 100644 index 0000000..d0d48d8 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/_helpers.tpl @@ -0,0 +1,107 @@ +{{/* uyuni.image computes the image URL out of the global registry and tag as well as overridden values. */}} +{{/* "name", the image name */}} +{{/* "global", the root object */}} +{{/* "local", the configuration object containing the image and tag to override with */}} +{{- define "uyuni.image" -}} +{{- $tag := .global.Values.tag -}} +{{- if .local.tag -}} +{{- $tag = .local.tag -}} +{{- end -}} +{{- $uri := (printf "%s/%s:%s" (required "The repository value is required!" .global.Values.repository) .name $tag) -}} +{{- if .local.image -}} +{{- $uri = (printf "%s:%s" .local.image $tag) -}} +{{- end -}} +{{- $uri -}} +{{- end -}} + +{{/* uyuni.pvc writes the manifest for a PVC. */}} +{{/* "root", the top context, */}} +{{/* "name", the volume name, */}} +{{/* "volume", the volume config data dictionary of the volume, */}} +{{/* "defaultSize", the default size of the volume in case the user messes it up in the values, */}} +{{/* "accessMode", the access mode to use for the volume */}} +{{- define "uyuni.pvc" -}} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .name }} + namespace: {{ .root.Release.Namespace | quote }} + labels: + app.kubernetes.io/part-of: uyuni +{{- if .volume.extraLabels }} +{{ toYaml .volume.extraLabels | nindent 4 }} +{{- end }} +{{- if .volume.annotations }} + annotations: +{{ toYaml .volume.annotations | nindent 4 }} +{{- end }} +spec: +{{- $storageClass := .root.Values.volumes.storageClass }} +{{- if .volume.storageClass }} + {{ $storageClass = .volume.storageClass }} +{{- end }} +{{- if $storageClass }} + {{- if eq "-" $storageClass }} + storageClassName: "" + {{- else }} + storageClassName: {{ $storageClass | quote }} + {{- end }} +{{- end }} + accessModes: + - {{ .accessMode }} + resources: + requests: + storage: {{ .volume.size | default .defaultSize | quote }} +{{- if .volume.volumeName }} + volumeName: {{ .volume.volumeName | quote }} +{{- end }} +{{- if .volume.selector }} + selector: +{{ toYaml .volume.selector | nindent 4 }} +{{- end }} +--- +{{- end -}} + +{{- define "uyuni.pgPVCName" -}} +var-pgsql18 +{{- end -}} + +{{/* uyuni.nodePlacement writes the node placement properties for a pod */}} +{{/* "global": the global placement configuration data */}} +{{/* "local": the overwriting configurantion data */}} +{{- define "uyuni.nodePlacement" -}} +{{- $globalNode := .global | default (dict) -}} +{{- $localNode := .local | default (dict) -}} + +{{- /* Handle nodeSelector */ -}} +{{- $nodeSelector := $globalNode.nodeSelector -}} +{{- if $localNode.nodeSelector }}{{ $nodeSelector = $localNode.nodeSelector }}{{ end -}} +{{- if $nodeSelector }} +nodeSelector: +{{- toYaml $nodeSelector | nindent 2 }} +{{- end }} + +{{- /* Handle affinity */ -}} +{{- $affinity := $globalNode.affinity -}} +{{- if $localNode.affinity }}{{ $affinity = $localNode.affinity }}{{ end -}} +{{- if $affinity }} +affinity: +{{- toYaml $affinity | nindent 2 }} +{{- end }} + +{{- /* Handle tolerations */ -}} +{{- $tolerations := $globalNode.tolerations -}} +{{- if $localNode.tolerations }}{{ $tolerations = $localNode.tolerations }}{{ end -}} +{{- if $tolerations }} +tolerations: +{{- toYaml $tolerations | nindent 2 }} +{{- end }} + +{{- /* Handle nodeName */ -}} +{{- $nodeName := $globalNode.nodeName -}} +{{- if $localNode.nodeName }}{{ $nodeName = $localNode.nodeName }}{{ end -}} +{{- if $nodeName }} +nodeName: {{ $nodeName | quote }} +{{- end }} + +{{- end -}} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/coco.yaml b/roles/uyuni/files/uyuni/server-helm/templates/coco.yaml new file mode 100644 index 0000000..ec4ce59 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/coco.yaml @@ -0,0 +1,97 @@ +{{- if gt (default .Values.coco.replicas 0 | int) 0 }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/component: coco-attestation + app.kubernetes.io/part-of: uyuni + name: coco-attestation + namespace: "{{ .Release.Namespace }}" +spec: + replicas: {{ default .Values.coco.replicas 0 | int }} + selector: + matchLabels: + app.kubernetes.io/component: coco-attestation + app.kubernetes.io/part-of: uyuni + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/component: coco-attestation + app.kubernetes.io/part-of: uyuni + spec: +{{- include "uyuni.nodePlacement" (dict "global" .Values.placement "local" .Values.coco) | nindent 6 }} + containers: + - env: + - name: database_user + valueFrom: + secretKeyRef: + key: username + name: db-credentials + optional: false + - name: database_password + valueFrom: + secretKeyRef: + key: password + name: db-credentials + optional: false + - name: database_host + valueFrom: + configMapKeyRef: + key: db_host + name: uyuni-config + optional: false + - name: database_port + valueFrom: + configMapKeyRef: + key: db_port + name: uyuni-config + optional: false + - name: database_name + valueFrom: + configMapKeyRef: + key: db_name + name: uyuni-config + optional: false + image: {{ include "uyuni.image" (dict "name" "server-attestation" "global" . "local" .Values.coco) }} + imagePullPolicy: {{ .Values.pullPolicy }} + name: coco +{{- if .Values.registrySecret }} + imagePullSecrets: + - name: {{ .Values.registrySecret }} +{{- end }} + initContainers: + - command: + - sh + - -c + - |2 + until pg_isready -U $MANAGER_USER -h $MANAGER_DB_HOST -p $MANAGER_DB_PORT -d $MANAGER_DB_NAME; do + sleep 60 + done + env: + - name: MANAGER_DB_HOST + valueFrom: + configMapKeyRef: + key: db_host + name: uyuni-config + optional: false + - name: MANAGER_DB_PORT + valueFrom: + configMapKeyRef: + key: db_port + name: uyuni-config + optional: false + - name: MANAGER_DB_NAME + value: susemanager + - name: MANAGER_USER + valueFrom: + configMapKeyRef: + key: db_name + name: uyuni-config + optional: false + image: {{ include "uyuni.image" (dict "name" "server" "global" . "local" .Values.server) }} + imagePullPolicy: {{ .Values.pullPolicy }} + name: db-waiter +{{- end }} + diff --git a/roles/uyuni/files/uyuni/server-helm/templates/config.yaml b/roles/uyuni/files/uyuni/server-helm/templates/config.yaml new file mode 100644 index 0000000..e45238a --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/config.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/part-of: uyuni + name: uyuni-config + namespace: "{{ .Release.Namespace }}" +data: + fqdn: {{ required "global.fqdn is needed!" .Values.global.fqdn }} + email: {{ required "server.email is needed!" .Values.server.email }} + {{- if .Values.db.enable }} + db_host: db + db_port: "5432" + db_name: "susemanager" + reportdb_host: reportdb + reportdb_port: "5432" + reportdb_name: reportdb + {{- else }} + db_host: {{ .Values.db.internal.host | default "db" }} + db_port: "{{ .Values.db.internal.port | default 5432 }}" + db_name: {{ .Values.db.internal.name | default "susemanager " }} + reportdb_host: {{ .Values.db.report.host | default "reportdb" }} + reportdb_port: "{{ .Values.db.report.port | default 5432 }}" + reportdb_name: {{ .Values.db.report.name | default "reportdb" }} + {{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/db.yaml b/roles/uyuni/files/uyuni/server-helm/templates/db.yaml new file mode 100644 index 0000000..d732a48 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/db.yaml @@ -0,0 +1,90 @@ +{{- if .Values.db.enable }} +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/component: db + app.kubernetes.io/part-of: uyuni + name: db + namespace: "{{ .Release.Namespace }}" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: db + app.kubernetes.io/part-of: uyuni + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/component: db + app.kubernetes.io/part-of: uyuni + spec: +{{- include "uyuni.nodePlacement" (dict "global" .Values.placement "local" .Values.db) | nindent 6 }} + containers: + - env: + - name: TZ + value: {{ .Values.timezone | default "Etc/UTC" }} + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + key: username + name: db-admin-credentials + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: db-admin-credentials + - name: MANAGER_USER + valueFrom: + secretKeyRef: + key: username + name: db-credentials + - name: MANAGER_PASS + valueFrom: + secretKeyRef: + key: password + name: db-credentials + - name: REPORT_DB_USER + valueFrom: + secretKeyRef: + key: username + name: reportdb-credentials + - name: REPORT_DB_PASS + valueFrom: + secretKeyRef: + key: password + name: reportdb-credentials + image: {{ include "uyuni.image" (dict "name" "server-postgresql" "global" . "local" .Values.db) }} + imagePullPolicy: {{ .Values.pullPolicy }} + name: db + volumeMounts: + - mountPath: /var/lib/pgsql/data + subPath: data + name: var-pgsql + - mountPath: /etc/pki + name: tls-secret +{{- if .Values.registrySecret }} + imagePullSecrets: + - name: {{ .Values.registrySecret }} +{{- end }} + securityContext: + fsGroup: 999 + volumes: + - name: var-pgsql + persistentVolumeClaim: + claimName: {{ include "uyuni.pgPVCName" . }} + - name: tls-secret + secret: + items: + - key: tls.crt + path: tls/certs/spacewalk.crt + - key: tls.key + mode: 256 + path: tls/private/pg-spacewalk.key + - key: ca.crt + path: trust/anchors/LOCAL-RHN-ORG-TRUSTED-SSL-CERT + secretName: db-cert +{{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/gateway.yaml b/roles/uyuni/files/uyuni/server-helm/templates/gateway.yaml new file mode 100644 index 0000000..7618d99 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/gateway.yaml @@ -0,0 +1,86 @@ +{{- if and .Values.gateway.enable (eq .Values.gateway.name "") }} +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: uyuni-gateway + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + gatewayClassName: "{{ .Values.gateway.class }}" + listeners: + # HTTP/HTTPS Listeners + - name: {{ default .Values.gateway.listeners.http.name "web" }} + protocol: HTTP + port: {{ default .Values.gateway.listeners.http.port 8000 }} + allowedRoutes: + namespaces: + from: Same + + - name: {{ default .Values.gateway.listeners.http.name "websecure" }} + protocol: HTTPS + port: {{ default .Values.gateway.listeners.https.port 8443 }} + tls: + mode: Terminate + certificateRefs: + - name: uyuni-cert + allowedRoutes: + namespaces: + from: Same + + # TCP Listeners + {{- if ne (default .Values.services.type .Values.services.salt.type) "NodePort" }} + - name: salt-publish + protocol: TCP + port: 4505 + allowedRoutes: + namespaces: + from: Same + + - name: salt-request + protocol: TCP + port: 4506 + allowedRoutes: + namespaces: + from: Same + {{- end }} + + {{- if and .Values.db.enable (ne (default .Values.services.type .Values.services.reportdb.type) "NodePort") }} + - name: reportdb-pgsql + protocol: TCP + port: 5432 + allowedRoutes: + namespaces: + from: Same + {{- end }} + + # Debug TCP Listeners + {{- if .Values.exposeJavaDebug }} + {{- if ne (default .Values.services.type .Values.services.taskomatic.type) "NodePort" }} + - name: tasko-debug + protocol: TCP + port: 8001 + allowedRoutes: + namespaces: + from: Same + {{- end }} + + {{- if ne (default .Values.services.type .Values.services.search.type) "NodePort" }} + - name: search-debug + protocol: TCP + port: 8002 + allowedRoutes: + namespaces: + from: Same + {{- end }} + + {{- if ne (default .Values.services.type .Values.services.tomcat.type) "NodePort" }} + - name: tomcat-debug + protocol: TCP + port: 8003 + allowedRoutes: + namespaces: + from: Same + {{- end }} + {{- end }} +{{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/hub.yaml b/roles/uyuni/files/uyuni/server-helm/templates/hub.yaml new file mode 100644 index 0000000..39e3bee --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/hub.yaml @@ -0,0 +1,51 @@ +{{- if default .Values.hubAPI.enable false }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/component: hub-xmlrpc + app.kubernetes.io/part-of: uyuni + name: hub-xmlrpc + namespace: "{{ .Release.Namespace }}" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: hub-xmlrpc + app.kubernetes.io/part-of: uyuni + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/component: hub-xmlrpc + app.kubernetes.io/part-of: uyuni + spec: +{{- include "uyuni.nodePlacement" (dict "global" .Values.placement "local" .Values.hubAPI) | nindent 6 }} + containers: + - env: + - name: HUB_API_URL + value: http://web/rpc/api + - name: HUB_CONNECT_USING_SSL + value: "true" + image: {{ include "uyuni.image" (dict "name" "server-hub-xmlrpc-api" "global" . "local" .Values.hubAPI) }} + imagePullPolicy: {{ .Values.pullPolicy }} + name: hub-xmlrpc + ports: + - containerPort: 2830 +{{- if .Values.registrySecret }} + imagePullSecrets: + - name: {{ .Values.registrySecret }} +{{- end }} + initContainers: + - command: + - sh + - -c + - |2 + until curl -L http://web/rhn/manager/api/api/getVersion; do + sleep 60 + done + image: {{ include "uyuni.image" (dict "name" "server-hub-xmlrpc-api" "global" . "local" .Values.hubAPI) }} + imagePullPolicy: {{ .Values.pullPolicy }} + name: server-waiter +{{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/ingress.yaml b/roles/uyuni/files/uyuni/server-helm/templates/ingress.yaml new file mode 100644 index 0000000..5f54e95 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/ingress.yaml @@ -0,0 +1,431 @@ +{{- if not .Values.gateway.enable }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + creationTimestamp: null + name: uyuni-ingress-ssl + namespace: "{{ .Release.Namespace }}" + annotations: + {{- if eq ((.Values.ingress).type) "traefik" }} + traefik.ingress.kubernetes.io/router.tls: "true" + traefik.ingress.kubernetes.io/router.tls.domains.n.main: "{{ required "global.fqdn is needed!" .Values.global.fqdn }}" + traefik.ingress.kubernetes.io/router.entrypoints: "websecure" + traefik.ingress.kubernetes.io/router.priority: "1" + traefik.ingress.kubernetes.io/router.middlewares: "{{ .Release.Namespace }}-uyuni-strip-prefixes@kubernetescrd" + {{- end }} + {{- if (((.Values.ingress).annotations).ssl) }} +{{ toYaml .Values.ingress.annotations.ssl | indent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: uyuni + app.kubernetes.io/component: server +spec: + {{- if ((.Values.ingress).class) }} + ingressClassName: {{ .Values.ingress.class }} + {{- end }} + tls: + - hosts: + - {{ required "global.fqdn is needed!" .Values.global.fqdn }} + secretName: uyuni-cert + rules: + - host: {{ required "global.fqdn is needed!" .Values.global.fqdn }} + http: + paths: + - path: / + backend: + service: + name: web + port: + number: 80 + pathType: Prefix + {{- if ne .Values.enableMonitoring false }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + creationTimestamp: null + name: exporters-ingress-ssl + namespace: "{{ .Release.Namespace }}" + annotations: + {{- if eq ((.Values.ingress).type) "traefik" }} + traefik.ingress.kubernetes.io/router.tls: "true" + traefik.ingress.kubernetes.io/router.tls.domains.n.main: "{{ required "global.fqdn is needed!" .Values.global.fqdn }}" + traefik.ingress.kubernetes.io/router.entrypoints: "websecure" + traefik.ingress.kubernetes.io/router.priority: "100" + traefik.ingress.kubernetes.io/router.middlewares: "{{ .Release.Namespace }}-uyuni-strip-prefixes@kubernetescrd" + {{- end }} + {{- if (((.Values.ingress).annotations).exporters) }} +{{ toYaml .Values.ingress.annotations.exporters | indent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: uyuni + app.kubernetes.io/component: server +spec: + {{- if ((.Values.ingress).class) }} + ingressClassName: {{ .Values.ingress.class }} + {{- end }} + tls: + - hosts: + - {{ required "global.fqdn is needed!" .Values.global.fqdn }} + secretName: uyuni-cert + rules: + - host: {{ required "global.fqdn is needed!" .Values.global.fqdn }} + http: + paths: + - path: /postgresql-exporter + backend: + service: + name: tomcat-internal + port: + number: 9187 + pathType: Prefix + - path: /node-exporter + backend: + service: + name: tomcat-internal + port: + number: 9100 + pathType: Prefix + - path: /tasko-exporter + backend: + service: + name: taskomatic-internal + port: + number: 9800 + pathType: Prefix + - path: /tasko-jmx + backend: + service: + name: taskomatic-internal + port: + number: 5557 + pathType: Prefix + - path: /tomcat-jmx + backend: + service: + name: tomcat-internal + port: + number: 5556 + pathType: Prefix + {{- end }} + {{- if .Values.saline.enable }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + creationTimestamp: null + name: saline-ingress-ssl + namespace: "{{ .Release.Namespace }}" + annotations: + {{- if eq ((.Values.ingress).type) "traefik" }} + traefik.ingress.kubernetes.io/router.tls: "true" + traefik.ingress.kubernetes.io/router.tls.domains.n.main: "{{ required "global.fqdn is needed!" .Values.global.fqdn }}" + traefik.ingress.kubernetes.io/router.entrypoints: "websecure" + traefik.ingress.kubernetes.io/router.priority: "100" + traefik.ingress.kubernetes.io/router.middlewares: "{{ .Release.Namespace }}-uyuni-strip-prefixes@kubernetescrd" + {{- end }} + {{- if (((.Values.ingress).annotations).saline) }} +{{ toYaml .Values.ingress.annotations.saline | indent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: uyuni + app.kubernetes.io/component: saline +spec: + {{- if ((.Values.ingress).class) }} + ingressClassName: {{ .Values.ingress.class }} + {{- end }} + tls: + - hosts: + - {{ required "global.fqdn is needed!" .Values.global.fqdn }} + secretName: uyuni-cert + rules: + - host: {{ required "global.fqdn is needed!" .Values.global.fqdn }} + http: + paths: + - backend: + service: + name: saline + port: + number: 8216 + path: /saline + pathType: Prefix + {{- end }} + {{- if default .Values.hubAPI.enable false }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + creationTimestamp: null + name: hubapi-ingress-ssl + namespace: "{{ .Release.Namespace }}" + annotations: + {{- if eq ((.Values.ingress).type) "traefik" }} + traefik.ingress.kubernetes.io/router.tls: "true" + traefik.ingress.kubernetes.io/router.tls.domains.n.main: "{{ required "global.fqdn is needed!" .Values.global.fqdn }}" + traefik.ingress.kubernetes.io/router.entrypoints: "websecure" + traefik.ingress.kubernetes.io/router.priority: "100" + traefik.ingress.kubernetes.io/router.middlewares: "{{ .Release.Namespace }}-uyuni-strip-prefixes@kubernetescrd" + {{- end }} + {{- if (((.Values.ingress).annotations).hub) }} +{{ toYaml .Values.ingress.annotations.hub | indent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: uyuni + app.kubernetes.io/component: hub-xmlrpc +spec: + {{- if ((.Values.ingress).class) }} + ingressClassName: {{ .Values.ingress.class }} + {{- end }} + tls: + - hosts: + - {{ required "global.fqdn is needed!" .Values.global.fqdn }} + secretName: uyuni-cert + rules: + - host: {{ required "global.fqdn is needed!" .Values.global.fqdn }} + http: + paths: + - path: /hub/rpc/api + backend: + service: + name: hub-xmlrpc + port: + number: 2830 + pathType: Prefix + {{- end }} + {{- if eq ((.Values.ingress).type) "traefik" }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + creationTimestamp: null + name: uyuni-ingress-ssl-redirect + namespace: "{{ .Release.Namespace }}" + annotations: + traefik.ingress.kubernetes.io/router.middlewares: "{{ .Release.Namespace }}-uyuni-https-redirect@kubernetescrd" + traefik.ingress.kubernetes.io/router.entrypoints: "web" + traefik.ingress.kubernetes.io/router.priority: "1" + {{- if (((.Values.ingress).annotations).sslRedirect) }} +{{ toYaml .Values.ingress.annotations.sslRedirect | indent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: uyuni + app.kubernetes.io/component: server +spec: + {{- if ((.Values.ingress).class) }} + ingressClassName: {{ .Values.ingress.class }} + {{- end }} + rules: + - host: {{ required "global.fqdn is needed!" .Values.global.fqdn }} + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: / + pathType: Prefix + {{- if default .Values.hubAPI.enable false }} + - backend: + service: + name: hub-xmlrpc + port: + number: 2830 + path: /hub/rpc/api + pathType: Prefix + {{- end }} + {{- end }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + creationTimestamp: null + name: uyuni-ingress-nossl + namespace: "{{ .Release.Namespace }}" + annotations: + {{- if eq ((.Values.ingress).type) "traefik" }} + traefik.ingress.kubernetes.io/router.tls: "false" + traefik.ingress.kubernetes.io/router.entrypoints: "web" + traefik.ingress.kubernetes.io/router.priority: "100" + traefik.ingress.kubernetes.io/router.middlewares: "{{ .Release.Namespace }}-uyuni-strip-prefixes@kubernetescrd" + {{- end }} + {{- if (((.Values.ingress).annotations).nossl) }} +{{ toYaml .Values.ingress.annotations.nossl | indent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: uyuni + app.kubernetes.io/component: server +spec: + {{- if ((.Values.ingress).class) }} + ingressClassName: {{ .Values.ingress.class }} + {{- end }} + rules: + - host: {{ required "global.fqdn is needed!" .Values.global.fqdn }} + http: + paths: + - backend: + service: + name: web + port: + number: 80 + path: /pub + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /rhn/kickstart/DownloadFile + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /rhn/common/DownloadFile + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /rhn/rpc/api + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /rpc/api + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /rhn/errors + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /rhn/ty/TinyUrl + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /rhn/websocket + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /rhn/metrics + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /cobbler_api + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /cblr + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /httpboot + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /images + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /cobbler + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /os-images + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /tftp + pathType: Prefix + - backend: + service: + name: web + port: + number: 80 + path: /docs + pathType: Prefix + {{- if ne .Values.enableMonitoring false }} + - path: /postgresql-exporter + backend: + service: + name: tomcat-internal + port: + number: 9187 + pathType: Prefix + - path: /node-exporter + backend: + service: + name: tomcat-internal + port: + number: 9100 + pathType: Prefix + - path: /tasko-exporter + backend: + service: + name: taskomatic-internal + port: + number: 9800 + pathType: Prefix + - path: /tasko-jmx + backend: + service: + name: taskomatic-internal + port: + number: 5557 + pathType: Prefix + - path: /tomcat-jmx + backend: + service: + name: tomcat-internal + port: + number: 5556 + pathType: Prefix + {{- end }} + {{- if .Values.saline.enable }} + - backend: + service: + name: saline + port: + number: 8216 + path: /saline + pathType: Prefix + {{- end }} + {{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/pvcs.yaml b/roles/uyuni/files/uyuni/server-helm/templates/pvcs.yaml new file mode 100644 index 0000000..810378c --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/pvcs.yaml @@ -0,0 +1,27 @@ +{{ include "uyuni.pvc" (dict "root" . "name" "ca-certs" "volume" (index .Values.volumes "ca-certs") "defaultSize" "10Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "etc-apache2" "volume" (index .Values.volumes "etc-apache2") "defaultSize" "1Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "etc-cobbler" "volume" (index .Values.volumes "etc-cobbler") "defaultSize" "1Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "etc-postfix" "volume" (index .Values.volumes "etc-postfix") "defaultSize" "1Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "etc-rhn" "volume" (index .Values.volumes "etc-rhn") "defaultSize" "1Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "etc-salt" "volume" (index .Values.volumes "etc-salt") "defaultSize" "1Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "etc-sssd" "volume" (index .Values.volumes "etc-sssd") "defaultSize" "1Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "etc-sysconfig" "volume" (index .Values.volumes "etc-sysconfig") "defaultSize" "20Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "etc-systemd-multi" "volume" (index .Values.volumes "etc-systemd-multi") "defaultSize" "1Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "etc-systemd-sockets" "volume" (index .Values.volumes "etc-systemd-sockets") "defaultSize" "1Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "etc-tomcat" "volume" (index .Values.volumes "etc-tomcat") "defaultSize" "1Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "run-salt-master" "volume" (index .Values.volumes "run-salt-master") "defaultSize" "10Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "srv-formulametadata" "volume" (index .Values.volumes "srv-formulametadata") "defaultSize" "10Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "srv-pillar" "volume" (index .Values.volumes "srv-pillar") "defaultSize" "10Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "srv-salt" "volume" (index .Values.volumes "srv-salt") "defaultSize" "10Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "srv-spacewalk" "volume" (index .Values.volumes "srv-spacewalk") "defaultSize" "10Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "srv-susemanager" "volume" (index .Values.volumes "srv-susemanager") "defaultSize" "1Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "srv-tftpboot" "volume" (index .Values.volumes "srv-tftpboot") "defaultSize" "300Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "srv-www" "volume" (index .Values.volumes "srv-www") "defaultSize" "100Gi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "var-cache" "volume" (index .Values.volumes "var-cache") "defaultSize" "10Gi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "var-cobbler" "volume" (index .Values.volumes "var-cobbler") "defaultSize" "10Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "var-log" "volume" (index .Values.volumes "var-log") "defaultSize" "2Gi" "accessMode" "ReadWriteOnce") }} +{{- $pgPVCName := include "uyuni.pgPVCName" . }} +{{ include "uyuni.pvc" (dict "root" . "name" $pgPVCName "volume" (index .Values.volumes "var-pgsql") "defaultSize" "50Gi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "var-salt" "volume" (index .Values.volumes "var-salt") "defaultSize" "10Mi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "var-search" "volume" (index .Values.volumes "var-search") "defaultSize" "10Gi" "accessMode" "ReadWriteOnce") }} +{{ include "uyuni.pvc" (dict "root" . "name" "var-spacewalk" "volume" (index .Values.volumes "var-spacewalk") "defaultSize" "100Gi" "accessMode" "ReadWriteOnce") }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/routes.yaml b/roles/uyuni/files/uyuni/server-helm/templates/routes.yaml new file mode 100644 index 0000000..fdc79d0 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/routes.yaml @@ -0,0 +1,226 @@ +{{- if .Values.gateway.enable }} +{{- $fqdn := required "global.fqdn is needed!" .Values.global.fqdn -}} +{{- $gatewayName := .Values.gateway.name | default "uyuni-gateway" -}} + +# SSL Redirection (Port 80 to 443) +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: uyuni-ssl-redirect + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + parentRefs: + - name: {{ $gatewayName }} + sectionName: {{ .Values.gateway.listeners.http.name }} + hostnames: + - {{ $fqdn | quote }} + rules: + - filters: + - type: RequestRedirect + requestRedirect: + scheme: https + statusCode: 301 +--- +# HTTPS Routes +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: uyuni-https-routes + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + parentRefs: + - name: {{ $gatewayName }} + sectionName: {{ .Values.gateway.listeners.https.name }} + hostnames: + - {{ $fqdn | quote }} + rules: + {{- if ne .Values.enableMonitoring false }} + # postgresql exporter + - matches: + - path: { type: PathPrefix, value: /postgresql-exporter } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: tomcat-internal + port: 9187 + + # Node exporter + - matches: + - path: { type: PathPrefix, value: /node-exporter } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: tomcat-internal + port: 9100 + + # Tomcat Monitoring JMX + - matches: + - path: { type: PathPrefix, value: /tomcat-jmx } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: tomcat-internal + port: 5556 + + # Taskomatic Monitoring Exporter + - matches: + - path: { type: PathPrefix, value: /tasko-exporter } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: taskomatic-internal + port: 9800 + + # Taskomatic Monitoring JMX + - matches: + - path: { type: PathPrefix, value: /tasko-jmx } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: taskomatic-internal + port: 5557 + {{- end }} + {{- if .Values.saline.enable }} + - matches: + - path: { type: PathPrefix, value: /saline } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: saline + port: 8216 + {{- end }} + {{- if default .Values.hubAPI.enable false }} + - matches: + - path: { type: PathPrefix, value: /hub/rpc/api } + backendRefs: + - name: hub-xmlrpc + port: 2830 + {{- end }} + - matches: + - path: { type: PathPrefix, value: / } + backendRefs: + - name: web + port: 80 +--- +# Non-SSL Paths +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: uyuni-nossl-routes + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + parentRefs: + - name: {{ $gatewayName }} + sectionName: {{ .Values.gateway.listeners.http.name }} + hostnames: + - {{ $fqdn | quote }} + rules: + # Standard Non-SSL Paths + - matches: + - path: { type: PathPrefix, value: /pub } + - path: { type: PathPrefix, value: /rhn/kickstart/DownloadFile } + - path: { type: PathPrefix, value: /rhn/common/DownloadFile } + - path: { type: PathPrefix, value: /rhn/rpc/api } + - path: { type: PathPrefix, value: /rpc/api } + - path: { type: PathPrefix, value: /rhn/errors } + - path: { type: PathPrefix, value: /rhn/ty/TinyUrl } + - path: { type: PathPrefix, value: /rhn/websocket } + - path: { type: PathPrefix, value: /rhn/metrics } + - path: { type: PathPrefix, value: /cobbler_api } + - path: { type: PathPrefix, value: /cobbler } + - path: { type: PathPrefix, value: /cblr } + - path: { type: PathPrefix, value: /httpboot } + - path: { type: PathPrefix, value: /images } + - path: { type: PathPrefix, value: /os-images } + - path: { type: PathPrefix, value: /tftp } + - path: { type: PathPrefix, value: /docs } + backendRefs: + - name: web + port: 80 + + {{- if ne .Values.enableMonitoring false }} + # postgresql exporter + - matches: + - path: { type: PathPrefix, value: /postgresql-exporter } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: tomcat-internal + port: 9187 + + # Node exporter + - matches: + - path: { type: PathPrefix, value: /node-exporter } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: tomcat-internal + port: 9100 + + # Tomcat Monitoring JMX + - matches: + - path: { type: PathPrefix, value: /tomcat-jmx } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: tomcat-internal + port: 5556 + + # Taskomatic Monitoring Exporter + - matches: + - path: { type: PathPrefix, value: /tasko-exporter } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: taskomatic-internal + port: 9800 + + # Taskomatic Monitoring JMX + - matches: + - path: { type: PathPrefix, value: /tasko-jmx } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: taskomatic-internal + port: 5557 + {{- end }} + {{- if .Values.saline.enable }} + - matches: + - path: { type: PathPrefix, value: /saline } + filters: + - type: URLRewrite + urlRewrite: + path: { type: ReplacePrefixMatch, replacePrefixMatch: / } + backendRefs: + - name: saline + port: 8216 + {{- end }} + {{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/saline.yaml b/roles/uyuni/files/uyuni/server-helm/templates/saline.yaml new file mode 100644 index 0000000..9e3c154 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/saline.yaml @@ -0,0 +1,67 @@ +{{- if default .Values.saline.enable false }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/component: saline + app.kubernetes.io/part-of: uyuni + name: saline + namespace: "{{ .Release.Namespace }}" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: saline + app.kubernetes.io/part-of: uyuni + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/component: saline + app.kubernetes.io/part-of: uyuni + spec: +{{- include "uyuni.nodePlacement" (dict "global" .Values.placement "local" .Values.saline) | nindent 6 }} + containers: + - env: + - name: NOSSL + value: "YES" + - name: TZ + value: {{ .Values.timezone | default "Etc/UTC" }} + image: {{ include "uyuni.image" (dict "name" "server-saline" "global" . "local" .Values.saline) }} + imagePullPolicy: {{ .Values.pullPolicy }} + name: saline + ports: + - containerPort: 8216 + volumeMounts: + - mountPath: /run/salt/master + name: run-salt-master + - mountPath: /etc/salt + name: etc-salt +{{- if .Values.registrySecret }} + imagePullSecrets: + - name: {{ .Values.registrySecret }} +{{- end }} + initContainers: + - command: + - sh + - -c + - |2 + until curl -L http://web/rhn/manager/api/api/getVersion; do + sleep 60 + done + image: {{ include "uyuni.image" (dict "name" "server-saline" "global" . "local" .Values.saline) }} + imagePullPolicy: {{ .Values.pullPolicy }} + name: server-waiter + securityContext: + seLinuxOptions: + level: "s0" + volumes: + - name: run-salt-master + persistentVolumeClaim: + claimName: run-salt-master + - name: etc-salt + persistentVolumeClaim: + claimName: etc-salt +{{- end }} + diff --git a/roles/uyuni/files/uyuni/server-helm/templates/server.yaml b/roles/uyuni/files/uyuni/server-helm/templates/server.yaml new file mode 100644 index 0000000..d1700f9 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/server.yaml @@ -0,0 +1,552 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + name: uyuni + namespace: "{{ .Release.Namespace }}" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + spec: +{{- include "uyuni.nodePlacement" (dict "global" .Values.placement "local" .Values.server) | nindent 6 }} + containers: + - env: + - name: container + value: oci + - name: TZ + value: {{ .Values.timezone | default "Etc/UTC" }} +{{- if and .Values.server.mirror (or .Values.server.mirror.claimName .Values.server.mirror.hostPath) }} + - name: MIRROR_PATH + value: /mirror +{{- end }} + - name: ADMIN_USER + valueFrom: + secretKeyRef: + key: username + name: admin-credentials + optional: false + - name: ADMIN_PASS + valueFrom: + secretKeyRef: + key: password + name: admin-credentials + optional: false + - name: MANAGER_USER + valueFrom: + secretKeyRef: + key: username + name: db-credentials + optional: false + - name: MANAGER_PASS + valueFrom: + secretKeyRef: + key: password + name: db-credentials + optional: false + - name: REPORT_DB_USER + valueFrom: + secretKeyRef: + key: username + name: reportdb-credentials + optional: false + - name: REPORT_DB_PASS + valueFrom: + secretKeyRef: + key: password + name: reportdb-credentials + optional: false + - name: MANAGER_DB_NAME + value: susemanager + - name: MANAGER_DB_HOST + value: db + - name: MANAGER_DB_CA_CERT + value: /etc/pki/trust/anchors/DB-RHN-ORG-TRUSTED-SSL-CERT + - name: MANAGER_DB_PORT + value: "5432" + - name: EXTERNALDB_PROVIDER + - name: ISS_PARENT + - name: REPORT_DB_NAME + value: reportdb + - name: REPORT_DB_HOST + value: reportdb + - name: REPORT_DB_CA_CERT + value: /etc/pki/trust/anchors/DB-RHN-ORG-TRUSTED-SSL-CERT + - name: REPORT_DB_PORT + value: "5432" + - name: MANAGER_ADMIN_EMAIL + valueFrom: + configMapKeyRef: + key: email + name: uyuni-config + optional: false + - name: MANAGER_MAIL_FROM + valueFrom: + configMapKeyRef: + key: email + name: uyuni-config + optional: false + - name: UYUNI_HOSTNAME + valueFrom: + configMapKeyRef: + key: fqdn + name: uyuni-config + optional: false +{{- if .Values.exposeJavaDebug }} + - name: DEBUG_JAVA + value: "true" +{{- end }} +{{- if .Values.server.sccSecret }} + - name: SCC_USER + valueFrom: + secretKeyRef: + key: username + name: {{ .Values.server.sccSecret }} + optional: false + - name: SCC_PASS + valueFrom: + secretKeyRef: + key: password + name: {{ .Values.server.sccSecret }} + optional: false +{{- end }} +{{- if .Values.server.systemdLogLevel }} + - name: SYSTEMD_LOG_TARGET + value: console + - name: SYSTEMD_LOG_LEVEL + value: {{ .Values.server.systemdLogLevel }} + tty: true +{{- end }} + image: {{ include "uyuni.image" (dict "name" "server" "global" . "local" .Values.server) }} + imagePullPolicy: {{ .Values.pullPolicy }} + lifecycle: + preStop: + exec: + command: + - /bin/sh + - -c + - spacewalk-service stop + name: uyuni + securityContext: + capabilities: + add: + - SYS_ADMIN + seLinuxOptions: + level: "s0" + {{- if .Values.server.superPrivileged }} + type: "spc_t" + {{- else if .Values.server.selinuxType }} + type: {{ .Values.server.selinuxType | quote }} + {{- end }} + {{- if .Values.server.superPrivileged }} + appArmorProfile: + type: Unconfined + {{- else if .Values.server.apparmorProfile }} + appArmorProfile: + type: Localhost + localhostProfile: {{ .Values.server.apparmorProfile }} + {{- end }} + ports: + - containerPort: 80 + - containerPort: 4505 + - containerPort: 4506 + - containerPort: 25151 +{{- if .Values.exposeJavaDebug | default false }} + - containerPort: 8001 + - containerPort: 8002 + - containerPort: 8003 +{{- end }} + - containerPort: 9100 +{{- if ne .Values.enableMonitoring false }} + - containerPort: 5556 + - containerPort: 5557 + - containerPort: 9187 + - containerPort: 9800 +{{- end }} + startupProbe: + exec: + command: + - /usr/bin/startup-check.sh + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3600 # Max 10h + livenessProbe: + exec: + command: + - /usr/bin/liveness-check.sh + timeoutSeconds: 5 + failureThreshold: 5 + periodSeconds: 60 + readinessProbe: + httpGet: + path: /rhn/manager/api/api/getVersion + port: 80 + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + initialDelaySeconds: 120 + volumeMounts: + - mountPath: /var/lib/cobbler + name: var-cobbler + - mountPath: /var/lib/rhn/search + name: var-search + - mountPath: /var/lib/salt + name: var-salt + - mountPath: /var/cache + name: var-cache + - mountPath: /var/spacewalk + name: var-spacewalk + - mountPath: /var/log + name: var-log + - mountPath: /srv/salt + name: srv-salt + - mountPath: /srv/www/ + name: srv-www + - mountPath: /srv/tftpboot + name: srv-tftpboot + - mountPath: /srv/formula_metadata + name: srv-formulametadata + - mountPath: /srv/pillar + name: srv-pillar + - mountPath: /srv/susemanager + name: srv-susemanager + - mountPath: /srv/spacewalk + name: srv-spacewalk + - mountPath: /etc/pki/trust/anchors/ + name: ca-certs + - mountPath: /run/salt/master + name: run-salt-master + - mountPath: /etc/apache2 + name: etc-apache2 + - mountPath: /etc/systemd/system/multi-user.target.wants + name: etc-systemd-multi + - mountPath: /etc/systemd/system/sockets.target.wants + name: etc-systemd-sockets + - mountPath: /etc/salt + name: etc-salt + - mountPath: /etc/tomcat + name: etc-tomcat + - mountPath: /etc/cobbler + name: etc-cobbler + - mountPath: /etc/sysconfig + name: etc-sysconfig + - mountPath: /etc/postfix + name: etc-postfix + - mountPath: /etc/sssd + name: etc-sssd + - mountPath: /etc/rhn + name: etc-rhn + - mountPath: /etc/pki/trust/anchors/LOCAL-RHN-ORG-TRUSTED-SSL-CERT + name: ca-cert + readOnly: true + subPath: ca.crt + - mountPath: /usr/share/susemanager/salt/certs/RHN-ORG-TRUSTED-SSL-CERT + name: ca-cert + readOnly: true + subPath: ca.crt + - mountPath: /srv/www/htdocs/pub/RHN-ORG-TRUSTED-SSL-CERT + name: ca-cert + readOnly: true + subPath: ca.crt + - mountPath: /etc/pki/trust/anchors/DB-RHN-ORG-TRUSTED-SSL-CERT + name: db-ca-cert + readOnly: true + subPath: ca.crt + - mountPath: /etc/pki/ + name: tls + - mountPath: /run + name: run + - mountPath: /sys/fs/cgroup + name: sys-fs-cgroup +{{- if and .Values.server.mirror (or .Values.server.mirror.claimName .Values.server.mirror.hostPath) }} + - name: mirror + mountPath: /mirror +{{- end }} +{{- if .Values.server.extraVolumeMounts }} +{{ toYaml .Values.server.extraVolumeMounts | nindent 8 }} +{{- end }} +{{- if .Values.registrySecret }} + imagePullSecrets: + - name: {{ .Values.registrySecret }} +{{- end }} + initContainers: + - command: + - sh + - -x + - -c + - |2 + # Fill the empty volumes + for vol in /var/lib/cobbler \ + /var/lib/rhn/search \ + /var/lib/salt \ + /var/cache \ + /var/log \ + /srv/salt \ + /srv/www \ + /srv/tftpboot \ + /srv/formula_metadata \ + /srv/pillar \ + /srv/susemanager \ + /srv/spacewalk \ + /etc/apache2 \ + /etc/rhn \ + /etc/systemd/system/multi-user.target.wants \ + /etc/systemd/system/sockets.target.wants \ + /etc/salt \ + /etc/tomcat \ + /etc/cobbler \ + /etc/sysconfig \ + /etc/postfix \ + /etc/sssd + do + chown --reference=$vol /mnt$vol; + chmod --reference=$vol /mnt$vol; + if [ -z "$(ls -A /mnt$vol)" ]; then + cp -a $vol/. /mnt$vol; + fi + done + image: {{ include "uyuni.image" (dict "name" "server" "global" . "local" .Values.server) }} + imagePullPolicy: {{ .Values.pullPolicy }} + name: init-volumes + securityContext: + seLinuxOptions: + level: "s0" + volumeMounts: + - mountPath: /mnt/var/lib/cobbler + name: var-cobbler + - mountPath: /mnt/var/lib/rhn/search + name: var-search + - mountPath: /mnt/var/lib/salt + name: var-salt + - mountPath: /mnt/var/cache + name: var-cache + - mountPath: /mnt/var/spacewalk + name: var-spacewalk + - mountPath: /mnt/var/log + name: var-log + - mountPath: /mnt/srv/salt + name: srv-salt + - mountPath: /mnt/srv/www/ + name: srv-www + - mountPath: /mnt/srv/tftpboot + name: srv-tftpboot + - mountPath: /mnt/srv/formula_metadata + name: srv-formulametadata + - mountPath: /mnt/srv/pillar + name: srv-pillar + - mountPath: /mnt/srv/susemanager + name: srv-susemanager + - mountPath: /mnt/srv/spacewalk + name: srv-spacewalk + - mountPath: /mnt/etc/pki/trust/anchors/ + name: ca-certs + - mountPath: /mnt/run/salt/master + name: run-salt-master + - mountPath: /mnt/etc/apache2 + name: etc-apache2 + - mountPath: /mnt/etc/systemd/system/multi-user.target.wants + name: etc-systemd-multi + - mountPath: /mnt/etc/systemd/system/sockets.target.wants + name: etc-systemd-sockets + - mountPath: /mnt/etc/salt + name: etc-salt + - mountPath: /mnt/etc/tomcat + name: etc-tomcat + - mountPath: /mnt/etc/cobbler + name: etc-cobbler + - mountPath: /mnt/etc/sysconfig + name: etc-sysconfig + - mountPath: /mnt/etc/postfix + name: etc-postfix + - mountPath: /mnt/etc/sssd + name: etc-sssd + - mountPath: /mnt/etc/rhn + name: etc-rhn + - command: + - sh + - -c + - |2 + until pg_isready -U $MANAGER_USER -h $MANAGER_DB_HOST -p $MANAGER_DB_PORT -d $MANAGER_DB_NAME; do + sleep 60 + done + + until pg_isready -U $REPORT_DB_USER -h $REPORT_DB_HOST -p $REPORT_DB_PORT -d $REPORT_DB_NAME; do + sleep 60 + done + env: + - name: MANAGER_DB_HOST + valueFrom: + configMapKeyRef: + key: "db_host" + name: uyuni-config + optional: false + - name: MANAGER_DB_PORT + valueFrom: + configMapKeyRef: + key: "db_port" + name: uyuni-config + optional: false + - name: MANAGER_DB_NAME + valueFrom: + configMapKeyRef: + key: "db_name" + name: uyuni-config + optional: false + - name: MANAGER_USER + valueFrom: + secretKeyRef: + key: username + name: db-credentials + optional: false + - name: REPORT_DB_HOST + valueFrom: + configMapKeyRef: + key: "reportdb_host" + name: uyuni-config + optional: false + - name: REPORT_DB_PORT + valueFrom: + configMapKeyRef: + key: "reportdb_port" + name: uyuni-config + optional: false + - name: REPORT_DB_NAME + valueFrom: + configMapKeyRef: + key: "reportdb_name" + name: uyuni-config + optional: false + - name: REPORT_DB_USER + valueFrom: + secretKeyRef: + key: username + name: reportdb-credentials + optional: false + image: {{ include "uyuni.image" (dict "name" "server" "global" . "local" .Values.server) }} + imagePullPolicy: {{ .Values.pullPolicy }} + name: db-waiter + volumes: + - name: var-cobbler + persistentVolumeClaim: + claimName: var-cobbler + - name: var-search + persistentVolumeClaim: + claimName: var-search + - name: var-salt + persistentVolumeClaim: + claimName: var-salt + - name: var-cache + persistentVolumeClaim: + claimName: var-cache + - name: var-spacewalk + persistentVolumeClaim: + claimName: var-spacewalk + - name: var-log + persistentVolumeClaim: + claimName: var-log + - name: srv-salt + persistentVolumeClaim: + claimName: srv-salt + - name: srv-www + persistentVolumeClaim: + claimName: srv-www + - name: srv-tftpboot + persistentVolumeClaim: + claimName: srv-tftpboot + - name: srv-formulametadata + persistentVolumeClaim: + claimName: srv-formulametadata + - name: srv-pillar + persistentVolumeClaim: + claimName: srv-pillar + - name: srv-susemanager + persistentVolumeClaim: + claimName: srv-susemanager + - name: srv-spacewalk + persistentVolumeClaim: + claimName: srv-spacewalk + - name: ca-certs + persistentVolumeClaim: + claimName: ca-certs + - name: run-salt-master + persistentVolumeClaim: + claimName: run-salt-master + - name: etc-apache2 + persistentVolumeClaim: + claimName: etc-apache2 + - name: etc-systemd-multi + persistentVolumeClaim: + claimName: etc-systemd-multi + - name: etc-systemd-sockets + persistentVolumeClaim: + claimName: etc-systemd-sockets + - name: etc-salt + persistentVolumeClaim: + claimName: etc-salt + - name: etc-tomcat + persistentVolumeClaim: + claimName: etc-tomcat + - name: etc-cobbler + persistentVolumeClaim: + claimName: etc-cobbler + - name: etc-sysconfig + persistentVolumeClaim: + claimName: etc-sysconfig + - name: etc-postfix + persistentVolumeClaim: + claimName: etc-postfix + - name: etc-sssd + persistentVolumeClaim: + claimName: etc-sssd + - name: etc-rhn + persistentVolumeClaim: + claimName: etc-rhn + - configMap: + defaultMode: 420 + name: uyuni-ca + name: ca-cert + - configMap: + defaultMode: 420 + name: db-ca + name: db-ca-cert + - name: tls + secret: + defaultMode: 420 + items: + - key: tls.crt + path: tls/certs/spacewalk.crt + - key: tls.key + mode: 256 + path: tls/private/spacewalk.key + secretName: uyuni-cert + - emptyDir: + medium: Memory + sizeLimit: 256Mi + name: run + - name: sys-fs-cgroup + emptyDir: +{{- if .Values.server.mirror }} + {{- if .Values.server.mirror.claimName }} + - name: mirror + persistentVolumeClaim: + claimName: {{ .Values.server.mirror.claimName }} + {{- else if .Values.server.mirror.hostPath }} + - name: mirror + hostPath: + path: {{ .Values.server.mirror.hostPath }} + {{- end }} +{{- end }} +{{- if .Values.server.extraVolumes }} +{{ toYaml .Values.server.extraVolumes | nindent 6 }} +{{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/services.yaml b/roles/uyuni/files/uyuni/server-helm/templates/services.yaml new file mode 100644 index 0000000..0750475 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/services.yaml @@ -0,0 +1,293 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + name: cobbler + namespace: "{{ .Release.Namespace }}" +spec: + ports: + - name: cobbler + port: 25151 + selector: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + type: ClusterIP +{{- if .Values.db.enable }} +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: db + app.kubernetes.io/part-of: uyuni + name: db + namespace: "{{ .Release.Namespace }}" +spec: + ports: + - name: pgsql + port: 5432 + selector: + app.kubernetes.io/component: db + app.kubernetes.io/part-of: uyuni + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: db + app.kubernetes.io/part-of: uyuni + name: reportdb + namespace: "{{ .Release.Namespace }}" +{{- if or .Values.services.annotations .Values.services.reportdb.annotations }} + annotations: +{{ toYaml ( mergeOverwrite (dict) (default (dict) .Values.services.annotations) (default (dict) .Values.services.reportdb.annotations) ) | indent 4 }} +{{- end }} +spec: + ports: + - name: pgsql + port: 5432 +{{- if eq (default .Values.services.type .Values.services.reportdb.type) "NodePort" }} + nodePort: {{ .Values.services.reportdb.ports.pgsql }} +{{- end }} + selector: + app.kubernetes.io/component: db + app.kubernetes.io/part-of: uyuni + type: {{ .Values.services.reportdb.type | default .Values.services.type }} +{{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + name: salt + namespace: "{{ .Release.Namespace }}" +{{- if or .Values.services.annotations .Values.services.salt.annotations }} + annotations: +{{ toYaml ( mergeOverwrite (dict) (default (dict) .Values.services.annotations) (default (dict) .Values.services.salt.annotations) ) | indent 4 }} +{{- end }} +spec: + ports: + - name: publish + port: 4505 +{{- if eq (default .Values.services.type .Values.services.salt.type) "NodePort" }} + nodePort: {{ .Values.services.salt.ports.publish }} +{{- end }} + - name: request + port: 4506 +{{- if eq (default .Values.services.type .Values.services.salt.type) "NodePort" }} + nodePort: {{ .Values.services.salt.ports.request }} +{{- end }} + selector: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + type: {{ .Values.services.salt.type | default .Values.services.type }} +--- +{{- if .Values.exposeJavaDebug | default false }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + name: search + namespace: "{{ .Release.Namespace }}" +{{- if or .Values.services.annotations .Values.services.search.annotations }} + annotations: +{{ toYaml ( mergeOverwrite (dict) (default (dict) .Values.services.annotations) (default (dict) .Values.services.search.annotations) ) | indent 4 }} +{{- end }} +spec: + ports: + - name: debug + port: 8002 +{{- if eq (default .Values.services.type .Values.services.search.type) "NodePort" }} + nodePort: {{ .Values.services.search.ports.debug }} +{{- end }} + selector: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + type: {{ .Values.services.search.type | default .Values.services.type }} +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + name: taskomatic + namespace: "{{ .Release.Namespace }}" +{{- if or .Values.services.annotations .Values.services.taskomatic.annotations }} + annotations: +{{ toYaml ( mergeOverwrite (dict) (default (dict) .Values.services.annotations) (default (dict) .Values.services.taskomatic.annotations) ) | indent 4 }} +{{- end }} +spec: + ports: + - name: debug + port: 8001 +{{- if eq (default .Values.services.type .Values.services.taskomatic.type) "NodePort" }} + nodePort: {{ .Values.services.taskomatic.ports.debug }} +{{- end }} + selector: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + type: {{ .Values.services.taskomatic.type | default .Values.services.type }} +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + name: tomcat + namespace: "{{ .Release.Namespace }}" +{{- if or .Values.services.annotations .Values.services.tomcat.annotations }} + annotations: +{{ toYaml ( mergeOverwrite (dict) (default (dict) .Values.services.annotations) (default (dict) .Values.services.tomcat.annotations) ) | indent 4 }} +{{- end }} +spec: + ports: + - name: debug + port: 8003 +{{- if eq (default .Values.services.type .Values.services.tomcat.type) "NodePort" }} + nodePort: {{ .Values.services.tomcat.ports.debug }} +{{- end }} + selector: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + type: {{ .Values.services.tomcat.type | default .Values.services.type }} +--- +{{- end }} +{{- if ne .Values.enableMonitoring false }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + name: taskomatic-internal + namespace: "{{ .Release.Namespace }}" +spec: + ports: + - name: jmx + port: 5557 + - name: mtrx + port: 9800 + selector: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + type: ClusterIP +--- +{{- end }} +{{- if and .Values.tftp.enable (not .Values.tftp.hostNetwork) }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: tftp + app.kubernetes.io/part-of: uyuni + name: tftp + namespace: "{{ .Release.Namespace }}" +{{- if or .Values.services.annotations .Values.services.tftp.annotations }} + annotations: +{{ toYaml ( mergeOverwrite (dict) (default (dict) .Values.services.annotations) (default (dict) .Values.services.tftp.annotations) ) | indent 4 }} +{{- end }} +spec: + ports: + - name: tftp + port: 69 + protocol: UDP + targetPort: 69 + selector: + app.kubernetes.io/component: tftp + app.kubernetes.io/part-of: uyuni + # ClusterIP or NodePort wouldn't work for TFTP if not using the host network + type: LoadBalancer + # Ensures all packets from a single client go to the same pod + sessionAffinity: ClientIP + # Preserves the client's source IP and avoids extra hops between nodes + externalTrafficPolicy: Local +--- +{{- end }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + name: tomcat-internal + namespace: "{{ .Release.Namespace }}" +spec: + ports: + - name: node-exporter + port: 9100 +{{- if ne .Values.enableMonitoring false }} + - name: jmx + port: 5556 + - name: pgsql-exporter + port: 9187 +{{- end }} + selector: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + name: web + namespace: "{{ .Release.Namespace }}" +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 80 + selector: + app.kubernetes.io/component: server + app.kubernetes.io/part-of: uyuni + type: ClusterIP +{{- if default .Values.hubAPI.enable false }} +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: hub-xmlrpc + app.kubernetes.io/part-of: uyuni + name: hub-xmlrpc + namespace: "{{ .Release.Namespace }}" +spec: + ports: + - name: hub + port: 2830 + selector: + app.kubernetes.io/component: hub-xmlrpc + app.kubernetes.io/part-of: uyuni + type: ClusterIP +{{- end }} +{{- if default .Values.saline.enable false }} +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: saline + app.kubernetes.io/part-of: uyuni + name: saline + namespace: "{{ .Release.Namespace }}" +spec: + ports: + - name: saline + port: 8216 + selector: + app.kubernetes.io/component: saline + app.kubernetes.io/part-of: uyuni + type: ClusterIP +{{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/tcp-routes.yaml b/roles/uyuni/files/uyuni/server-helm/templates/tcp-routes.yaml new file mode 100644 index 0000000..68dcffd --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/tcp-routes.yaml @@ -0,0 +1,110 @@ +{{- if .Values.gateway.enable }} +{{- $gatewayName := .Values.gateway.name | default "uyuni-gateway" -}} +{{- if ne (default .Values.services.type .Values.services.salt.type) "NodePort" }} +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: TCPRoute +metadata: + name: salt-publish + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + parentRefs: + - name: {{ $gatewayName }} + sectionName: salt-publish + rules: + - backendRefs: + - name: salt + port: 4505 +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: TCPRoute +metadata: + name: salt-request + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + parentRefs: + - name: {{ $gatewayName }} + sectionName: salt-request + rules: + - backendRefs: + - name: salt + port: 4506 +{{- end }} +{{- if and .Values.db.enable (ne (default .Values.services.type .Values.services.reportdb.type) "NodePort") }} +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: TCPRoute +metadata: + name: reportdb-pgsql + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + parentRefs: + - name: {{ $gatewayName }} + sectionName: reportdb-pgsql + rules: + - backendRefs: + - name: reportdb + port: 5432 +{{- end }} +{{- if .Values.exposeJavaDebug }} +{{- if ne (default .Values.services.type .Values.services.taskomatic.type) "NodePort" }} +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: TCPRoute +metadata: + name: tasko-debug + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + parentRefs: + - name: {{ $gatewayName }} + sectionName: tasko-debug + rules: + - backendRefs: + - name: taskomatic + port: 8001 +{{- end }} +{{- if ne (default .Values.services.type .Values.services.search.type) "NodePort" }} +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: TCPRoute +metadata: + name: search-debug + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + parentRefs: + - name: {{ $gatewayName }} + sectionName: search-debug + rules: + - backendRefs: + - name: search + port: 8002 +{{- end }} +{{- if ne (default .Values.services.type .Values.services.tomcat.type) "NodePort" }} +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: TCPRoute +metadata: + name: tomcat-debug + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + parentRefs: + - name: {{ $gatewayName }} + sectionName: tomcat-debug + rules: + - backendRefs: + - name: tomcat + port: 8003 +{{- end }} +{{- end }} +{{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/tftp.yaml b/roles/uyuni/files/uyuni/server-helm/templates/tftp.yaml new file mode 100644 index 0000000..87a6016 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/tftp.yaml @@ -0,0 +1,57 @@ +{{- if .Values.tftp.enable }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/component: tftp + app.kubernetes.io/part-of: uyuni + name: tftp + namespace: "{{ .Release.Namespace }}" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: tftp + app.kubernetes.io/part-of: uyuni + template: + metadata: + labels: + app.kubernetes.io/component: tftp + app.kubernetes.io/part-of: uyuni + spec: +{{- include "uyuni.nodePlacement" (dict "global" .Values.placement "local" .Values.tftp) | nindent 6 }} +{{- if .Values.tftp.hostNetwork }} + dnsPolicy: ClusterFirstWithHostNet + hostNetwork: true +{{- end }} + containers: + - name: tftp + image: {{ include "uyuni.image" (dict "name" "proxy-tftpd" "global" . "local" .Values.tftp) }} + imagePullPolicy: {{ .Values.pullPolicy }} + command: + - /usr/bin/tftp_wrapper.py + - --httpHost + - web.{{ .Release.Namespace }}.svc + - --proxyFqdn + - {{ .Values.global.fqdn }} + - --serverFqdn + - {{ .Values.global.fqdn }} + ports: + - containerPort: 69 + protocol: UDP +{{- if .Values.registrySecret }} + imagePullSecrets: + - name: {{ .Values.registrySecret }} +{{- end }} + initContainers: + - command: + - sh + - -c + - |2 + until curl -L http://web/rhn/manager/api/api/getVersion; do + sleep 60 + done + image: {{ include "uyuni.image" (dict "name" "proxy-tftpd" "global" . "local" .Values.tftp) }} + imagePullPolicy: {{ .Values.pullPolicy }} + name: server-waiter +{{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/templates/traefik-routes.yaml b/roles/uyuni/files/uyuni/server-helm/templates/traefik-routes.yaml new file mode 100644 index 0000000..956a2b4 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/templates/traefik-routes.yaml @@ -0,0 +1,150 @@ +{{- if and (not .Values.gateway.enable) (eq ((.Values.ingress).type) "traefik") }} +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: uyuni-https-redirect + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni +spec: + redirectScheme: + scheme: https + permanent: true +--- +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: uyuni-strip-prefixes + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/part-of: uyuni +spec: + stripPrefix: + prefixes: + - /postgresql-exporter + - /node-exporter + - /tasko-exporter + - /tasko-jmx + - /tomcat-jmx + - /saline +{{- if ne (default .Values.services.type .Values.services.reportdb.type) "NodePort" }} +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRouteTCP +metadata: + name: reportdb-pgsql-route + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni + annotations: + kubernetes.io/ingress.class: {{ .Values.ingress.class }} +spec: + entryPoints: + - reportdb-pgsql + routes: + - match: HostSNI(`*`) + services: + - name: reportdb + port: 5432 +{{- end }} +{{- if ne (default .Values.services.type .Values.services.salt.type) "NodePort" }} +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRouteTCP +metadata: + name: salt-publish-route + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni + annotations: + kubernetes.io/ingress.class: {{ .Values.ingress.class }} +spec: + entryPoints: + - salt-publish + routes: + - match: HostSNI(`*`) + services: + - name: salt + port: 4505 +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRouteTCP +metadata: + name: salt-request-route + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni + annotations: + kubernetes.io/ingress.class: {{ .Values.ingress.class }} +spec: + entryPoints: + - salt-request + routes: + - match: HostSNI(`*`) + services: + - name: salt + port: 4506 +{{- end }} +{{- if .Values.exposeJavaDebug }} +{{- if ne (default .Values.services.type .Values.services.taskomatic.type) "NodePort" }} +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRouteTCP +metadata: + name: tomcat-debug-route + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni + annotations: + kubernetes.io/ingress.class: {{ .Values.ingress.class }} +spec: + entryPoints: + - tomcat-debug + routes: + - match: HostSNI(`*`) + services: + - name: tomcat + port: 8003 +{{- end }} +{{- if ne (default .Values.services.type .Values.services.search.type) "NodePort" }} +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRouteTCP +metadata: + name: search-debug-route + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni + annotations: + kubernetes.io/ingress.class: {{ .Values.ingress.class }} +spec: + entryPoints: + - search-debug + routes: + - match: HostSNI(`*`) + services: + - name: search + port: 8002 +{{- end }} +{{- if ne (default .Values.services.type .Values.services.tomcat.type) "NodePort" }} +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRouteTCP +metadata: + name: tasko-debug-route + namespace: "{{ .Release.Namespace }}" + labels: + app.kubernetes.io/part-of: uyuni + annotations: + kubernetes.io/ingress.class: {{ .Values.ingress.class }} +spec: + entryPoints: + - tasko-debug + routes: + - match: HostSNI(`*`) + services: + - name: taskomatic + port: 8001 +{{- end }} +{{- end }} +{{- end }} diff --git a/roles/uyuni/files/uyuni/server-helm/test.sh b/roles/uyuni/files/uyuni/server-helm/test.sh new file mode 100644 index 0000000..d979477 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/test.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# Requires to install helm unittest plugin: +# helm plugin install --verify=false https://github.com/helm-unittest/helm-unittest +helm unittest . + +# Requires to install kubeconform: +# zypper in kubeconform +# The remote schema location is to validate the Traefik CRDs. +helm template . --set global.fqdn=test.local --set hubAPI.enable=true --set coco.replicas=3 --set saline.enable=true | \ + kubeconform -summary -strict \ + -schema-location default \ + -schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' + +# Check the API Gateway resources +helm template . --set global.fqdn=test.local --set hubAPI.enable=true --set coco.replicas=3 --set saline.enable=true --set gateway.enable=true --set gateway.class=gw | \ + kubeconform -summary -strict \ + -schema-location default \ + -schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' diff --git a/roles/uyuni/files/uyuni/server-helm/tito.props b/roles/uyuni/files/uyuni/server-helm/tito.props new file mode 100644 index 0000000..8f359c2 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/tito.props @@ -0,0 +1,3 @@ +[buildconfig] +builder = custom.ChartBuilder +tagger = tito.tagger.SUSEContainerTagger diff --git a/roles/uyuni/files/uyuni/server-helm/values.schema.json b/roles/uyuni/files/uyuni/server-helm/values.schema.json new file mode 100644 index 0000000..4c20192 --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/values.schema.json @@ -0,0 +1,451 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "title": "Values", + "type": "object", + "required": [ + "global", + "repository" + ], + "properties": { + "repository": { + "type": "string", + "description": "The default repository for images", + "default": "registry.opensuse.org/uyuni" + }, + "tag": { + "type": "string", + "description": "The default tag to use for images", + "default": "latest" + }, + "pullPolicy": { + "type": "string", + "enum": ["Always", "IfNotPresent", "Never"], + "default": "IfNotPresent" + }, + "registrySecret": { + "type": "string", + "description": "Name of the secret which contains the credentials for the registry", + "default": "" + }, + "timezone": { + "type": "string", + "description": "The time zone to set in the containers", + "default": "Etc/UTC" + }, + "placement": { + "$ref": "#/definitions/nodeSelectorConfig", + "description": "Default node placement rules for all pods" + }, + "global": { + "type": "object", + "required": [ + "fqdn" + ], + "properties": { + "fqdn": { + "type": "string", + "description": "The fully qualified domain name the server will answer to" + } + } + }, + "server": { + "type": ["object", "null"], + "description": "configuration of the server component", + "allOf": [ + { "$ref": "#/definitions/imageConfig" }, + { "$ref": "#/definitions/nodeSelectorConfig" } + ], + "properties": { + "email": { + "type": "string", + "description": "Email address for notifications sent by the server", + "default": "admin@uyuni.lab.org" + }, + "superPrivileged": { + "type": "boolean", + "description": "Run the server container with super privileges, bypassing a lot of selinux or AppArmor checks. This is dangerous!", + "default": false + }, + "apparmorProfile": { + "type": "string", + "description": "appArmor profile is the name of an AppArmor profile to use for the server pod." + }, + "selinuxType": { + "type": "string", + "description": "SELinux type is the name of the SELinux type to use for the server pod." + }, + "systemdLogLevel": { + "type": "string", + "enum": ["debug", "info", "notice", "warning", "err", "crit", "alert", "emerg", ""], + "description": "Value passed to systemd's --log-level parameter, can be useful for debugging" + }, + "mirror": { + "type": "object", + "description": "Defines a volume or host path to mount as server.susemanager.fromdir", + "properties": { + "claimName": { + "type": "string" + }, + "hostPath": { + "type": "string" + } + } + }, + "extraVolumes": { + "type": ["array", "null"], + "description": "Additional Kubernetes volumes for the server pod", + "items": { + "type": "object" + } + }, + "extraVolumeMounts": { + "type": ["array", "null"], + "description": "Additional volume mounts for the server container", + "items": { + "type": "object" + } + }, + "sccSecret": { + "type": "string", + "description": "the name of a basic-auth secret with the organization mirroring credentials to set up on the server.", + "default": "" + } + } + }, + "tftp": { + "type": ["object", "null"], + "description": "configuration of the tftp server component", + "allOf": [ + { "$ref": "#/definitions/imageConfig" }, + { "$ref": "#/definitions/nodeSelectorConfig" } + ], + "properties": { + "hostNetwork": { + "type": "boolean", + "description": "Use the host network instead of Kubernetes network infrastructure", + "default": false + }, + "enable": { + "type": "boolean", + "description": "Deploy the TFTP server to PXE boot systems", + "default": true + } + } + }, + "volumes": { + "type": "object", + "description": "Defines the volume claims for the server components", + "properties": { + "storageClass": { + "type": ["string", "null"], + "description": "default storage class to use for the volume claims" + }, + "var-pgsql": { "$ref": "#/definitions/volumeConfig" }, + "var-spacewalk": { "$ref": "#/definitions/volumeConfig" }, + "var-cache": { "$ref": "#/definitions/volumeConfig" }, + "var-log": { "$ref": "#/definitions/volumeConfig" }, + "srv-www": { "$ref": "#/definitions/volumeConfig" }, + "srv-tftpboot": { "$ref": "#/definitions/volumeConfig" }, + "ca-certs": { "$ref": "#/definitions/volumeConfig" }, + "etc-apache2": { "$ref": "#/definitions/volumeConfig" }, + "etc-cobbler": { "$ref": "#/definitions/volumeConfig" }, + "etc-postfix": { "$ref": "#/definitions/volumeConfig" }, + "etc-rhn": { "$ref": "#/definitions/volumeConfig" }, + "etc-salt": { "$ref": "#/definitions/volumeConfig" }, + "etc-sssd": { "$ref": "#/definitions/volumeConfig" }, + "etc-sysconfig": { "$ref": "#/definitions/volumeConfig" }, + "etc-systemd-multi": { "$ref": "#/definitions/volumeConfig" }, + "etc-systemd-sockets": { "$ref": "#/definitions/volumeConfig" }, + "etc-tomcat": { "$ref": "#/definitions/volumeConfig" }, + "run-salt-master": { "$ref": "#/definitions/volumeConfig" }, + "srv-formulametadata": { "$ref": "#/definitions/volumeConfig" }, + "srv-pillar": { "$ref": "#/definitions/volumeConfig" }, + "srv-salt": { "$ref": "#/definitions/volumeConfig" }, + "srv-spacewalk": { "$ref": "#/definitions/volumeConfig" }, + "srv-susemanager": { "$ref": "#/definitions/volumeConfig" }, + "var-cobbler": { "$ref": "#/definitions/volumeConfig" }, + "var-salt": { "$ref": "#/definitions/volumeConfig" }, + "var-search": { "$ref": "#/definitions/volumeConfig" } + } + }, + "services": { + "type": ["object"], + "description": "Services tuning properties", + "properties": { + "type": { + "type": "string", + "description": "type of all the externally-facing services. Can be overridden on each service", + "enum": ["ClusterIP", "NodePort", "LoadBalancer"], + "default": "ClusterIP" + }, + "annotations": { + "type": ["object", "null"], + "description": "annotations to set to all the services. Merged with the service ones." + }, + "reportdb": { + "$ref": "#/definitions/serviceConfig", + "description": "values for the reportdb service. The ports keys can only be pgsql (5432)" + }, + "salt": { + "$ref": "#/definitions/serviceConfig", + "description": "values for the salt master service. The ports keys can be one of 'publish' (4505) or 'request' (4506)" + }, + "search": { + "$ref": "#/definitions/serviceConfig", + "description": "values for the search server service. The ports keys can only be debug (8002)" + }, + "taskomatic": { + "$ref": "#/definitions/serviceConfig", + "description": "values for the taskomatic service. The ports keys can only be debug (8001)" + }, + "tomcat": { + "$ref": "#/definitions/serviceConfig", + "description": "values for the tomcat service. The ports keys can only be debug (8003)" + }, + "tftp": { + "type": ["object", "null"], + "description": "values for the tomcat service. Changing the service type doesn't make sense for TFTP", + "properties": { + "annotations": { + "type": ["object", "null"], + "description": "annotations to set to the service. This can be helpful to configure a load balancer" + } + } + } + } + }, + "exposeJavaDebug": { + "type": "boolean", + "description": "Expose ports 8001, 8002, and 8003 for Java debugging", + "default": false + }, + "enableMonitoring": { + "type": "boolean", + "description": "Expose metrics ports for Prometheus scraping", + "default": true + }, + "ingress": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Type of ingress used (supported values: traefik, '')", + "enum": ["traefik", ""], + "default": "traefik" + }, + "class": { + "type": "string", + "description": "Name of the ingress class to use. This value will be used in traefik routes annotations.", + "default": "traefik" + }, + "annotations": { + "type": "object", + "description": "Custom annotations for ingress rules", + "properties": { + "ssl": { "type": "object" }, + "sslRedirect": { "type": "object" }, + "nossl": { "type": "object" }, + "saline": { "type": "object" }, + "hub": { "type": "object" }, + "exporters": { "type": "object" } + } + } + } + }, + "gateway": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the gateway to use. An empty string value means that a gateway will be deployed and named uyuni-gateway.", + "default": "" + }, + "class": { + "type": "string", + "description": "Name of the gateway class to use. For rke2 with traefik, it is likely to be 'traefik'.", + "default": "" + }, + "listeners": { + "type": "object", + "description": "Gateway listeners configuration", + "properties": { + "http": { + "$ref": "#/definitions/listener", + "description": "Configuration of the HTTP listener. Defaults are adjusted to traefik on rke2" + }, + "https": { + "$ref": "#/definitions/listener", + "description": "Configuration of the HTTPS listener. Defaults are adjusted to traefik on rke2" + } + } + } + } + }, + "hubAPI": { + "type": ["object", "null"], + "description": "configuration of the hub API component", + "allOf": [ + { "$ref": "#/definitions/imageConfig" }, + { "$ref": "#/definitions/nodeSelectorConfig" } + ], + "properties": { + "enable": { + "type": "boolean", + "description": "Enable or disable the Hub XML-RPC API deployment", + "default": false + } + } + }, + "coco": { + "type": ["object", "null"], + "description": "configuration of the confidential computing attestation component", + "allOf": [ + { "$ref": "#/definitions/imageConfig" }, + { "$ref": "#/definitions/nodeSelectorConfig" } + ], + "properties": { + "replicas": { + "type": "integer", + "description": "Number of replicas for confidential computing attestation", + "minimum": 0, + "default": 0 + } + } + }, + "saline": { + "type": ["object", "null"], + "description": "configuration of the saline component", + "allOf": [ + { "$ref": "#/definitions/imageConfig" }, + { "$ref": "#/definitions/nodeSelectorConfig" } + ], + "properties": { + "enable": { + "type": "boolean", + "description": "Deploy Saline for salt master monitoring", + "default": false + } + } + }, + "db": { + "type": ["object", "null"], + "description": "configuration of the PostgreSQL database", + "allOf": [ + { "$ref": "#/definitions/imageConfig" }, + { "$ref": "#/definitions/nodeSelectorConfig" } + ], + "properties": { + "enable": { + "type": "boolean", + "description": "Deploy a PostgreSQL instance.", + "default": true + }, + "internal": { "ref": "#/definitions/dbConnectionConfig" }, + "report": { "ref": "#/definitions/dbConnectionConfig" } + } + } + }, + "definitions": { + "nodeSelectorConfig": { + "type": ["object", "null"], + "properties": { + "nodeSelector": { "type": ["object", "null"], "description": "Node label matching rules." }, + "affinity": { "type": ["object", "null"], "description": "Advanced scheduling rules." }, + "tolerations": { "type": ["array", "null"], "description": "Node taint tolerations." }, + "nodeName": { "type": ["string", "null"], "description": "Specific node assignment." } + } + }, + "imageConfig": { + "type": ["object", "null"], + "properties": { + "image": { + "type": ["string", "null"], + "description": "The image full URL without tag" + }, + "tag": { + "type": ["string", "null"], + "description": "The image tag" + } + } + }, + "dbConnectionConfig": { + "type": ["object", "null"], + "properties": { + "host": { + "type": ["string", "null"], + "description": "FQDN to use to connect to the database" + }, + "port": { + "type": ["integer", "null"], + "description": "port to use to connect to the database", + "default": 5432 + }, + "name": { + "type": ["string", "null"], + "description": "Postgresql database name to connect to" + } + } + }, + "volumeConfig": { + "type": "object", + "properties": { + "size": { + "type": "string", + "description": "Requested volume size" + }, + "storageClass": { + "type": ["string", "null"], + "description": "storage class to use for the volume claim" + }, + "extraLabels": { + "type": ["object", "null"], + "description": "labels to add to the volume claim" + }, + "annotations": { + "type": ["object", "null"], + "description": "annotations to set to the volume claim" + }, + "volumeName": { + "type": ["string", "null"], + "description": "volume to force binding to if set" + }, + "selector": { + "type": ["object", "null"], + "description": "selector to set on the volume claim" + } + } + }, + "serviceConfig": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Type of service to define", + "enum": ["ClusterIP", "NodePort", "LoadBalancer", ""], + "default": "" + }, + "ports": { + "type": "object", + "description": "Ports to expose by the service when using the NodePort type. Values need to match the port name of the service" + }, + "annotations": { + "type": ["object", "null"], + "description": "annotations to set to the service. This can be helpful to configure a load balancer" + } + } + }, + "listener": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name of the listener" + }, + "port": { + "type": "integer", + "description": "the port of the listener" + } + } + } + } +} diff --git a/roles/uyuni/files/uyuni/server-helm/values.yaml b/roles/uyuni/files/uyuni/server-helm/values.yaml new file mode 100644 index 0000000..5b031eb --- /dev/null +++ b/roles/uyuni/files/uyuni/server-helm/values.yaml @@ -0,0 +1,952 @@ +# The default repository with the path where to find all the images. +repository: registry.opensuse.org/uyuni +# The default tag to use for images, can be overridden for each image. +tag: latest + +# Ref: https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy +pullPolicy: "IfNotPresent" + +# registrySecret defines the name of secret to use to pull the images from the +# registry with authentication. Leave empty for no authentication. +# +# To create the secret, see: +# https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ +registrySecret: "" + +# The time zone to set in the containers +timezone: "Etc/UTC" + +# Server component configuration +server: + # image overrides the default image computed using the repository property + # Leave undefined to use the default + image: + # tag overrides the default tag in the tag property + # Leave undefined to use the default + tag: + + # Email will be the email used for the notifications sent by the server. + email: "admin@uyuni.lab.org" + + # sccSecret is the name of a basic-auth secret with the organization mirroring credentials to set up on the server. + sccSecret: "" + + # mirror defines a volume or host path to mount in the container as server.susemanager.fromdir value. + # Use either claimName or hostPath to reference the volume source. + # + # If the value is set before the first run of the server, the rhn.conf file will be adjusted during the setup. + mirror: + # claimName is the name of the PVC to use for the mirror volume. + # When using set, both the claim and the PV need to be defined before running the chart. + claimName: "" + # hostPath is the path on the node to mount as mirror. + # Using this is strongly discouraged as it is tied to where the server runs. + hostPath: "" + + # extraVolumes defines additional Kubernetes volumes for the server pod. + # This can be used to mount operator-managed volumes without modifying the chart templates. + extraVolumes: [] + + # extraVolumeMounts defines additional mounts for the server container. + # Every entry must reference a volume from server.extraVolumes or another + # volume already defined in the pod. + extraVolumeMounts: [] + + # superPrivileged may need to be set to true to run on a cluster with selinux or AppArmor enforced. + # This is only for the server pod, since it runs systemd. + # Setting this to true opens a big security can of worms. + superPrivileged: false + + # systemdLogLevel will be passed to systemd's --log-level parameter. + # Note, that this will add a tty to the container. + # The possible values are debug, info, notice, warning, err, crit, alert, emerg or "" to keep the default. + systemdLogLevel: "" + + # appArmor profile is the name of an AppArmor profile to use for the server pod. + # The profile need to be showing up in the aa-status command output. + apparmorProfile: "" + + # SELinux type is the name of the SELinux type to use for the server pod. + # By default, it's not set so the container runtime's default (typically container_t) is used, + # or spc_t if superPrivileged is enabled. + selinuxType: "" + + +global: + # fqdn is the fully qualified name the server will answer as. + # Changing this value renames the server and changes the server FQDN in the database, handle with care. + # This value is required. + fqdn: + +# Services tuning properties. +services: + + # type of all the externally-facing services. Can be overridden on each service. + # Ref: https://kubernetes.io/docs/concepts/services-networking/service/ + type: ClusterIP + + # annotations to set to all the services. Merged with the service ones. + annotations: + + # Values setting up the reportdb service. + reportdb: + # Type of service to define, overriding the global setting + type: "" + # Ports to expose by the service when using the NodePort type. + ports: + # postgresql port to expose, usually known as port 5432. + pgsql: 30032 + # Annotations to set on the service. + # This can be useful to configure a load balancer for example. + annotations: + + # Values setting up the salt service. + salt: + # Type of service to define, overriding the global setting + type: "" + # Ports to expose by the service when using the NodePort type. + ports: + # Salt publish port, usually known as port 4505 + publish: 30005 + # Salt request port, usually known as port 4506 + request: 30006 + # Annotations to set on the service. + # This can be useful to configure a load balancer for example. + annotations: + + # Values setting up the search server service. + # This is only for debugging purpose. + search: + # Type of service to define, overriding the global setting + type: "" + # Ports to expose by the service when using the NodePort type. + ports: + # Java debug port, usually known as port 8002 + debug: 30002 + # Annotations to set on the service. + # This can be useful to configure a load balancer for example. + annotations: + + # Values setting up the taskomatic service. + # This is only for debugging purpose. + taskomatic: + # Type of service to define, overriding the global setting + type: "" + # Ports to expose by the service when using the NodePort type. + ports: + # Java debug port, usually known as port 8001 + debug: 30001 + # Annotations to set on the service. + # This can be useful to configure a load balancer for example. + annotations: + + # Values setting up the tomcat service. + # This is only for debugging purpose. + tomcat: + # Type of service to define, overriding the global setting + type: "" + # Ports to expose by the service when using the NodePort type. + ports: + # Java debug port, usually known as port 8003 + debug: 30003 + # Annotations to set on the service. + # This can be useful to configure a load balancer for example. + annotations: + + # Values setting up the tftp service. + # This service can only set annotations: changing the type doesn't make sense. + tftp: + # Annotations to set on the service. + # This can be useful to configure a load balancer for example. + annotations: + +# exposeJavaDebug will expose the 8001, 8002 and 8003 ports to connect a Java debugger +# to taskomatic, search server and tomcat respectively +exposeJavaDebug: false + +# enableMonitoring will create the ingress or gateway routes for the prometheus exporters. +enableMonitoring: true + +ingress: + # ingress.type defines the ingress that is used in the cluster. + # It can be "traefik" or any other value. + type: "traefik" + # Specify the ingress class name to use. Empty, means that the default one will be used. + # If using the traefik end points and TCP routers, this value needs to match Traefik's + # --providers.kubernetescrd.ingressclass parameter's value. + # On rke2 this is likely to be "traefik". On K3S it is likely to be "" + class: "traefik" + # annotations can be used to set custom annotations on the created ingress rules. + # This can be used to configure another ingress than the ones already wired with the ingress.type. + # The ssl annotations can also be used to set a cert-manager issuer like: + # ingress: + # annotations: + # ssl: + # cert-manager.io/cluster-issuer: uyuniIssuer + annotations: + # ssl holds the annotations for the main ssl ingress. + ssl: {} + # sslRedirect holds the annotations for the ssl redirect ingress. + # This ingress is only created if the ingress type is set to 'traefik'. + sslRedirect: {} + # nossl holds the annotations for the HTTP ingress. + nossl: {} + # saline holds the annotations for the saline ssl ingress. + saline: {} + # hub holds the annotations for the hub API ssl ingress. + hub: {} + # exporters holds the annotations for the prometheus exporters SSL ingress. + exporters: {} + +# Gateway configures the Gateway API. +gateway: + # If enabled, Gateway API 1.4 resources will be deployed instead of the ingress ones. + # Note that TCPRoute is used and is still in alpha2 stage. + enable: false + + # Name of the gateway class to use. For rke2 with traefik, it is likely to be "traefik". + class: "" + + # Name of the gateway to use. An empty string value means that a gateway will be deployed and named uyuni-gateway. + name: "" + + listeners: + http: + # Name to set for the gateway http listener. The default is adjusted for traefik on rke2 + name: "web" + # Port to set for the gateway http listener. The default is adjusted for traefik on rke2 + port: 8000 + https: + # Name to set for the gateway https listener. The default is adjusted for traefik on rke2 + name: "websecure" + # Port to set for the gateway https listener. The default is adjusted for traefik on rke2 + port: 8443 + +# TFTP server configuration +tftp: + # image overrides the default image computed using the repository property + # Leave undefined to use the default + image: + # tag overrides the default tag in the tag property + # Leave undefined to use the default + tag: + # enable or disable the TFTP server. + enable: false + + # Use the host network to bypass the Kubernetes network layers. + # This may be needed if not using a LoadBalancer for the TFTP server. + # Note that this may be more complex to manage on multi-node clusters. + hostNetwork: false + +# hub API component configuration +hubAPI: + # image overrides the default image computed using the repository property + # Leave undefined to use the default + image: + # tag overrides the default tag in the tag property + # Leave undefined to use the default + tag: + # enable or disable the Hub XML-RPC API deployment. + enable: false + +# Confidential computing attestation component configuration +coco: + # image overrides the default image computed using the repository property + # Leave undefined to use the default + image: + # tag overrides the default tag in the tag property + # Leave undefined to use the default + tag: + # number of replicas for the confidential computing attestation deployment. + replicas: 0 + +# Saline component configuration +saline: + # image overrides the default image computed using the repository property + # Leave undefined to use the default + image: + # tag overrides the default tag in the tag property + # Leave undefined to use the default + tag: + + # set to true to deploy saline and provide salt master metrics + enable: false + +# PostgreSQL database configuration +db: + # image overrides the default image computed using the repository property + # Leave undefined to use the default + image: + # tag overrides the default tag in the tag property + # Leave undefined to use the default + tag: + # enable to deploy a PostgreSQL instance. + # WARNING: using a third party database is not tested and supported for now. + enable: true + + # Configuration of the internal database connection + # WARNING: Only taken into account if db is disabled + internal: + # Host name to use for the internal database. + # It should be added to the SANs of the database TLS certificate + host: + # Port to use to connect to the internal database + port: 5432 + # Name of the postgresql database to connect to + name: + + # Configuration of the report database connection + # WARNING: Only taken into account if db is disabled + report: + # Host name to use for the report database. + # It should be added to the SANs of the database TLS certificate + host: + # Port to use to connect to the internal database + port: 5432 + # Name of the postgresql database to connect to + name: + +# Configuration of the persistent volume claims. +volumes: + # Default storage class name to use for all the claims + storageClass: + + # var-pgsql is the volume for the database, + # a fast and big enough persistent volume will be needed. + var-pgsql: + # size is the requested volume size. + # The size of the postgresql data volume needs to be at least 50Gi. + # This value is required. + size: 50Gi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + # var-spacewalk contains the synchronized packages and needs to be sized depending on the distributions to manage. + var-spacewalk: + # size is the requested volume size. + # See https://www.uyuni-project.org/uyuni-docs/en/uyuni/installation-and-upgrade/uyuni-install-requirements.html + # how to estimate the size depending on the distributions. + # This value is required. + size: 100Gi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + # var-cache is the volume holding the cache for the server. + var-cache: + # size is the requested volume size. + # See https://www.uyuni-project.org/uyuni-docs/en/uyuni/installation-and-upgrade/uyuni-install-requirements.html + # how to estimate the size. + # This value is required. + size: 10Gi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + # var-log is the volume holding the log files for the server pod. + var-log: + # size is the requested volume size. + # This value is required. + size: 2Gi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + # srv-www is the volume containing the files published over HTTP. + # This also includes the unpacked auto-installation distribution ISOs. + srv-www: + # size is the requested volume size. + # Take into account the number and size of the distributions unpacked ISO images to use for auto-installation. + # This value is required. + size: 100Gi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + srv-tftpboot: + # size is the requested volume size. + # This value is required. + size: 300Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + ca-certs: + # size is the requested volume size. + # This value is required. + size: 10Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + etc-apache2: + # size is the requested volume size. + # This value is required. + size: 1Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + etc-cobbler: + # size is the requested volume size. + # This value is required. + size: 1Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + etc-postfix: + # size is the requested volume size. + # This value is required. + size: 1Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + etc-rhn: + # size is the requested volume size. + # This value is required. + size: 1Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + etc-salt: + # size is the requested volume size. + # This value is required. + size: 1Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + etc-sssd: + # size is the requested volume size. + # This value is required. + size: 1Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + etc-sysconfig: + # size is the requested volume size. + # This value is required. + size: 20Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + etc-systemd-multi: + # size is the requested volume size. + # This value is required. + size: 1Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + etc-systemd-sockets: + # size is the requested volume size. + # This value is required. + size: 1Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + etc-tomcat: + # size is the requested volume size. + # This value is required. + size: 1Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + run-salt-master: + # size is the requested volume size. + # This value is required. + size: 10Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + # srv-formulametadata contains the custom Salt Formulas metadata. + srv-formulametadata: + # size is the requested volume size. + # This value is required. + size: 10Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + # srv-pillar contains the custom Salt pillar. + srv-pillar: + # size is the requested volume size. + # This value is required. + size: 10Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + # srv-salt contains the custom Salt states. + srv-salt: + # size is the requested volume size. + # This value is required. + size: 10Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + srv-spacewalk: + # size is the requested volume size. + # This value is required. + size: 10Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + srv-susemanager: + # size is the requested volume size. + # This value is required. + size: 1Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + var-cobbler: + # size is the requested volume size. + # This value is required. + size: 10Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + var-salt: + # size is the requested volume size. + # This value is required. + size: 10Mi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: + + var-search: + # size is the requested volume size. + # This value is required. + size: 10Gi + + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default storage class. + storageClass: + + # extraLabels adds custom labels to the PVC metadata + extraLabels: + + # annotations sets annotations to the PVC. + # This may be useful to configure some storage backends + annotations: + + # volumeName sets the volumeName to bind to if defined. + volumeName: + + # selector is rendered with toYAML and can be used to bind to a specific PV. + selector: