Merge "feat(nova): Allow users to set 'host' for scheduler and conductor services"

This commit is contained in:
Zuul
2026-03-19 19:52:08 +00:00
committed by Gerrit Code Review
8 changed files with 399 additions and 2 deletions

View File

@@ -53,6 +53,9 @@ tcp_established = "ESTABLISHED"
def _get_hostname(topic, use_fqdn):
configured_host = cfg.CONF.host
if configured_host:
return configured_host
if use_fqdn and topic == "compute":
return socket.getfqdn()
return socket.gethostname()

View File

@@ -15,6 +15,7 @@ limitations under the License.
*/}}
set -x
exec nova-conductor \
--config-file /etc/nova/nova.conf \
--config-dir /etc/nova/nova.conf.d

View File

@@ -39,7 +39,7 @@ exec:
- conductor
{{- end }}
{{- if .Values.manifests.deployment_conductor }}
{{- if and .Values.manifests.deployment_conductor (not .Values.manifests.statefulset_conductor) }}
{{- $envAll := . }}
{{- $mounts_nova_conductor := .Values.pod.mounts.nova_conductor.nova_conductor }}

View File

@@ -39,7 +39,7 @@ exec:
- scheduler
{{- end }}
{{- if .Values.manifests.deployment_scheduler }}
{{- if and .Values.manifests.deployment_scheduler (not .Values.manifests.statefulset_scheduler) }}
{{- $envAll := . }}
{{- $mounts_nova_scheduler := .Values.pod.mounts.nova_scheduler.nova_scheduler }}

View File

@@ -0,0 +1,189 @@
{{/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- define "novaConductorLivenessProbeTemplate" }}
exec:
command:
- python
- /tmp/health-probe.py
- --config-file
- /etc/nova/nova.conf
- --config-dir
- /etc/nova/nova.conf.d
- --service-queue-name
- conductor
- --liveness-probe
{{- end }}
{{- define "novaConductorReadinessProbeTemplate" }}
exec:
command:
- python
- /tmp/health-probe.py
- --config-file
- /etc/nova/nova.conf
- --config-dir
- /etc/nova/nova.conf.d
- --service-queue-name
- conductor
{{- end }}
{{- if .Values.manifests.statefulset_conductor }}
{{- $envAll := . }}
{{- $mounts_nova_conductor := .Values.pod.mounts.nova_conductor.nova_conductor }}
{{- $mounts_nova_conductor_init := .Values.pod.mounts.nova_conductor.init_container }}
{{- $etcSources := .Values.pod.etcSources.nova_conductor }}
{{- if eq .Values.manifests.secret_ks_etc true }}
{{- $etcSources = append $etcSources (dict "secret" (dict "name" "nova-ks-etc")) }}
{{- end }}
{{- $serviceAccountName := "nova-conductor" }}
{{ tuple $envAll "conductor" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nova-conductor
annotations:
{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
labels:
{{ tuple $envAll "nova" "conductor" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
spec:
serviceName: nova-conductor
replicas: {{ .Values.pod.replicas.conductor }}
selector:
matchLabels:
{{ tuple $envAll "nova" "conductor" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
podManagementPolicy: Parallel
{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_statefulset" | indent 2 }}
template:
metadata:
labels:
{{ tuple $envAll "nova" "conductor" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
annotations:
{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
{{ tuple "nova_conductor" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
{{ dict "envAll" $envAll "podName" "nova-conductor" "containerNames" (list "nova-conductor" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
spec:
{{ tuple "nova_conductor" . | include "helm-toolkit.snippets.kubernetes_pod_priority_class" | indent 6 }}
{{ tuple "nova_conductor" . | include "helm-toolkit.snippets.kubernetes_pod_runtime_class" | indent 6 }}
serviceAccountName: {{ $serviceAccountName }}
{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
affinity:
{{ tuple $envAll "nova" "conductor" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
nodeSelector:
{{ .Values.labels.conductor.node_selector_key }}: {{ .Values.labels.conductor.node_selector_value }}
{{ if $envAll.Values.pod.tolerations.nova.enabled }}
{{ tuple $envAll "nova" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
{{ end }}
initContainers:
{{ tuple $envAll "conductor" $mounts_nova_conductor_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
containers:
- name: nova-conductor
{{ tuple $envAll "nova_conductor" | include "helm-toolkit.snippets.image" | indent 10 }}
{{ tuple $envAll $envAll.Values.pod.resources.conductor | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
{{ dict "envAll" $envAll "application" "nova" "container" "nova_conductor" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
{{ dict "envAll" $envAll "component" "conductor" "container" "default" "type" "liveness" "probeTemplate" (include "novaConductorLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
{{ dict "envAll" $envAll "component" "conductor" "container" "default" "type" "readiness" "probeTemplate" (include "novaConductorReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
env:
- name: RPC_PROBE_TIMEOUT
value: "{{ .Values.pod.probes.rpc_timeout }}"
- name: RPC_PROBE_RETRIES
value: "{{ .Values.pod.probes.rpc_retries }}"
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: metadata.name
{{- if or .Values.manifests.certificates .Values.tls.identity }}
- name: REQUESTS_CA_BUNDLE
value: "/etc/nova/certs/ca.crt"
{{- end }}
command:
- /bin/bash
- -c
- |
set -x
{{- if empty .Values.conf.nova.DEFAULT.host }}
# When using StatefulSet, use the pod hostname for stable service names
cat > /tmp/nova-conductor-host.conf << EOF
[DEFAULT]
host = ${HOSTNAME}
EOF
exec nova-conductor --config-file /etc/nova/nova.conf --config-file /tmp/nova-conductor-host.conf --config-dir /etc/nova/nova.conf.d
{{- else }}
exec /tmp/nova-conductor.sh
{{- end }}
volumeMounts:
- name: pod-tmp
mountPath: /tmp
- name: oslo-lock-path
mountPath: {{ .Values.conf.nova.oslo_concurrency.lock_path }}
- name: nova-bin
mountPath: /tmp/nova-conductor.sh
subPath: nova-conductor.sh
readOnly: true
- name: nova-bin
mountPath: /tmp/health-probe.py
subPath: health-probe.py
readOnly: true
- name: nova-etc
mountPath: /etc/nova/nova.conf
subPath: nova.conf
readOnly: true
- name: nova-etc-snippets
mountPath: /etc/nova/nova.conf.d/
readOnly: true
{{- if .Values.conf.nova.DEFAULT.log_config_append }}
- name: nova-etc
mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
readOnly: true
{{- end }}
- name: nova-etc
mountPath: /etc/nova/policy.yaml
subPath: policy.yaml
readOnly: true
{{- dict "enabled" (or .Values.manifests.certificates .Values.tls.identity) "name" .Values.secrets.tls.compute.osapi.internal "path" "/etc/nova/certs" "certs" (tuple "ca.crt") | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal "path" "/etc/rabbitmq/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
{{ if $mounts_nova_conductor.volumeMounts }}{{ toYaml $mounts_nova_conductor.volumeMounts | indent 12 }}{{ end }}
volumes:
- name: pod-tmp
emptyDir: {}
- name: oslo-lock-path
emptyDir: {}
- name: nova-bin
configMap:
name: nova-bin
defaultMode: 0555
- name: nova-etc
secret:
secretName: nova-etc
defaultMode: 0444
- name: nova-etc-snippets
{{- if $etcSources }}
projected:
sources:
{{ toYaml $etcSources | indent 14 }}
{{- else }}
emptyDir: {}
{{ end }}
{{- dict "enabled" (or .Values.manifests.certificates .Values.tls.identity) "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
{{ if $mounts_nova_conductor.volumes }}{{ toYaml $mounts_nova_conductor.volumes | indent 8 }}{{ end }}
{{- end }}

View File

@@ -0,0 +1,189 @@
{{/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- define "novaSchedulerLivenessProbeTemplate" }}
exec:
command:
- python
- /tmp/health-probe.py
- --config-file
- /etc/nova/nova.conf
- --config-dir
- /etc/nova/nova.conf.d
- --service-queue-name
- scheduler
- --liveness-probe
{{- end }}
{{- define "novaSchedulerReadinessProbeTemplate" }}
exec:
command:
- python
- /tmp/health-probe.py
- --config-file
- /etc/nova/nova.conf
- --config-dir
- /etc/nova/nova.conf.d
- --service-queue-name
- scheduler
{{- end }}
{{- if .Values.manifests.statefulset_scheduler }}
{{- $envAll := . }}
{{- $mounts_nova_scheduler := .Values.pod.mounts.nova_scheduler.nova_scheduler }}
{{- $mounts_nova_scheduler_init := .Values.pod.mounts.nova_scheduler.init_container }}
{{- $etcSources := .Values.pod.etcSources.nova_scheduler }}
{{- if eq .Values.manifests.secret_ks_etc true }}
{{- $etcSources = append $etcSources (dict "secret" (dict "name" "nova-ks-etc")) }}
{{- end }}
{{- $serviceAccountName := "nova-scheduler" }}
{{ tuple $envAll "scheduler" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nova-scheduler
annotations:
{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
labels:
{{ tuple $envAll "nova" "scheduler" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
spec:
serviceName: nova-scheduler
replicas: {{ .Values.pod.replicas.scheduler }}
selector:
matchLabels:
{{ tuple $envAll "nova" "scheduler" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
podManagementPolicy: Parallel
{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_statefulset" | indent 2 }}
template:
metadata:
labels:
{{ tuple $envAll "nova" "scheduler" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
annotations:
{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
{{ tuple "nova_scheduler" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
{{ dict "envAll" $envAll "podName" "nova-scheduler" "containerNames" (list "nova-scheduler" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
spec:
{{ tuple "nova_scheduler" . | include "helm-toolkit.snippets.kubernetes_pod_priority_class" | indent 6 }}
{{ tuple "nova_scheduler" . | include "helm-toolkit.snippets.kubernetes_pod_runtime_class" | indent 6 }}
serviceAccountName: {{ $serviceAccountName }}
{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
affinity:
{{ tuple $envAll "nova" "scheduler" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
nodeSelector:
{{ .Values.labels.scheduler.node_selector_key }}: {{ .Values.labels.scheduler.node_selector_value }}
{{ if $envAll.Values.pod.tolerations.nova.enabled }}
{{ tuple $envAll "nova" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
{{ end }}
initContainers:
{{ tuple $envAll "scheduler" $mounts_nova_scheduler_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
containers:
- name: nova-scheduler
{{ tuple $envAll "nova_scheduler" | include "helm-toolkit.snippets.image" | indent 10 }}
{{ tuple $envAll $envAll.Values.pod.resources.scheduler | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
{{ dict "envAll" $envAll "application" "nova" "container" "nova_scheduler" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
{{ dict "envAll" $envAll "component" "scheduler" "container" "default" "type" "liveness" "probeTemplate" (include "novaSchedulerLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
{{ dict "envAll" $envAll "component" "scheduler" "container" "default" "type" "readiness" "probeTemplate" (include "novaSchedulerReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
env:
- name: RPC_PROBE_TIMEOUT
value: "{{ .Values.pod.probes.rpc_timeout }}"
- name: RPC_PROBE_RETRIES
value: "{{ .Values.pod.probes.rpc_retries }}"
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: metadata.name
{{- if or .Values.manifests.certificates .Values.tls.identity }}
- name: REQUESTS_CA_BUNDLE
value: "/etc/nova/certs/ca.crt"
{{- end }}
command:
- /bin/bash
- -c
- |
set -xe
{{- if empty .Values.conf.nova.DEFAULT.host }}
# When using StatefulSet, use the pod hostname for stable service names
cat > /tmp/nova-scheduler-host.conf << EOF
[DEFAULT]
host = ${HOSTNAME}
EOF
exec nova-scheduler --config-file /etc/nova/nova.conf --config-file /tmp/nova-scheduler-host.conf --config-dir /etc/nova/nova.conf.d
{{- else }}
exec /tmp/nova-scheduler.sh
{{- end }}
volumeMounts:
- name: pod-tmp
mountPath: /tmp
- name: oslo-lock-path
mountPath: {{ .Values.conf.nova.oslo_concurrency.lock_path }}
- name: nova-bin
mountPath: /tmp/nova-scheduler.sh
subPath: nova-scheduler.sh
readOnly: true
- name: nova-bin
mountPath: /tmp/health-probe.py
subPath: health-probe.py
readOnly: true
- name: nova-etc
mountPath: /etc/nova/nova.conf
subPath: nova.conf
readOnly: true
- name: nova-etc-snippets
mountPath: /etc/nova/nova.conf.d/
readOnly: true
{{- if .Values.conf.nova.DEFAULT.log_config_append }}
- name: nova-etc
mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
readOnly: true
{{- end }}
- name: nova-etc
mountPath: /etc/nova/policy.yaml
subPath: policy.yaml
readOnly: true
{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
{{- dict "enabled" (or .Values.manifests.certificates .Values.tls.identity) "name" .Values.secrets.tls.compute.osapi.internal "path" "/etc/nova/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal "path" "/etc/rabbitmq/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
{{ if $mounts_nova_scheduler.volumeMounts }}{{ toYaml $mounts_nova_scheduler.volumeMounts | indent 12 }}{{ end }}
volumes:
- name: pod-tmp
emptyDir: {}
- name: oslo-lock-path
emptyDir: {}
- name: nova-bin
configMap:
name: nova-bin
defaultMode: 0555
- name: nova-etc
secret:
secretName: nova-etc
defaultMode: 0444
- name: nova-etc-snippets
{{- if $etcSources }}
projected:
sources:
{{ toYaml $etcSources | indent 14 }}
{{- else }}
emptyDir: {}
{{ end }}
{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
{{- dict "enabled" (or .Values.manifests.certificates .Values.tls.identity) "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
{{ if $mounts_nova_scheduler.volumes }}{{ toYaml $mounts_nova_scheduler.volumes | indent 8 }}{{ end }}
{{- end }}

View File

@@ -2711,6 +2711,12 @@ manifests:
deployment_serialproxy: true
deployment_spiceproxy: true
deployment_scheduler: true
# NOTE: StatefulSets provide stable pod hostnames (e.g., nova-conductor-0, nova-conductor-1)
# which are used as service host names in `openstack compute service list`.
# When enabled, the corresponding deployment_* manifest is automatically disabled.
# This ensures service names remain stable across pod restarts.
statefulset_conductor: false
statefulset_scheduler: false
ingress_metadata: true
ingress_novncproxy: true
ingress_serialproxy: true

View File

@@ -0,0 +1,9 @@
---
nova:
- |
Allows users to set custom 'host' values for nova conductor and scheduler
services. This may be useful for kubernetes users, where new deploys of
scheduler and conductor use the pod names, leaaving stale compute service entries
which are eventually cleaned by the nova-service-cleaner job.
Ref: https://docs.openstack.org/nova/latest/configuration/config.html#DEFAULT.host
...