From 22c8ec8b5788f8eb2a6be7398e539c090517793e Mon Sep 17 00:00:00 2001 From: haseeb Date: Fri, 6 Mar 2026 20:45:39 +0530 Subject: [PATCH 1/2] fix(ironic): restore uWSGI for API to fix port binding conflict The helm chart upgrade (c8ed3cd4) switched from uWSGI to the native ironic-api command which uses Cheroot. This caused port 6385 binding conflicts because Cheroot with multiple workers each try to bind independently, unlike uWSGI's master/worker model. Restore the custom configmap-ironic-bin.yaml with uWSGI while keeping the new upstream etcSources feature for config mounting. --- components/ironic/configmap-ironic-bin.yaml | 808 ++++++++++++++++++++ components/ironic/kustomization.yaml | 4 + components/ironic/values.yaml | 2 + 3 files changed, 814 insertions(+) create mode 100644 components/ironic/configmap-ironic-bin.yaml diff --git a/components/ironic/configmap-ironic-bin.yaml b/components/ironic/configmap-ironic-bin.yaml new file mode 100644 index 000000000..f1a7ef0e6 --- /dev/null +++ b/components/ironic/configmap-ironic-bin.yaml @@ -0,0 +1,808 @@ +apiVersion: v1 +data: + db-drop.py: | + #!/usr/bin/env python + + # Drops db and user for an OpenStack Service: + # Set ROOT_DB_CONNECTION and DB_CONNECTION environment variables to contain + # SQLAlchemy strings for the root connection to the database and the one you + # wish the service to use. Alternatively, you can use an ini formatted config + # at the location specified by OPENSTACK_CONFIG_FILE, and extract the string + # from the key OPENSTACK_CONFIG_DB_KEY, in the section specified by + # OPENSTACK_CONFIG_DB_SECTION. + + import os + import sys + try: + import ConfigParser + PARSER_OPTS = {} + except ImportError: + import configparser as ConfigParser + PARSER_OPTS = {"strict": False} + import logging + from sqlalchemy import create_engine + from sqlalchemy import text + + # Create logger, console handler and formatter + logger = logging.getLogger('OpenStack-Helm DB Drop') + logger.setLevel(logging.DEBUG) + ch = logging.StreamHandler() + ch.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + + # Set the formatter and add the handler + ch.setFormatter(formatter) + logger.addHandler(ch) + + + # Get the connection string for the service db root user + if "ROOT_DB_CONNECTION" in os.environ: + db_connection = os.environ['ROOT_DB_CONNECTION'] + logger.info('Got DB root connection') + else: + logger.critical('environment variable ROOT_DB_CONNECTION not set') + sys.exit(1) + + mysql_x509 = os.getenv('MARIADB_X509', "") + ssl_args = {} + if mysql_x509: + ssl_args = {'ssl': {'ca': '/etc/mysql/certs/ca.crt', + 'key': '/etc/mysql/certs/tls.key', + 'cert': '/etc/mysql/certs/tls.crt'}} + + # Get the connection string for the service db + if "OPENSTACK_CONFIG_FILE" in os.environ: + os_conf = os.environ['OPENSTACK_CONFIG_FILE'] + if "OPENSTACK_CONFIG_DB_SECTION" in os.environ: + os_conf_section = os.environ['OPENSTACK_CONFIG_DB_SECTION'] + else: + logger.critical('environment variable OPENSTACK_CONFIG_DB_SECTION not set') + sys.exit(1) + if "OPENSTACK_CONFIG_DB_KEY" in os.environ: + os_conf_key = os.environ['OPENSTACK_CONFIG_DB_KEY'] + else: + logger.critical('environment variable OPENSTACK_CONFIG_DB_KEY not set') + sys.exit(1) + try: + config = ConfigParser.RawConfigParser(**PARSER_OPTS) + logger.info("Using {0} as db config source".format(os_conf)) + config.read(os_conf) + logger.info("Trying to load db config from {0}:{1}".format( + os_conf_section, os_conf_key)) + user_db_conn = config.get(os_conf_section, os_conf_key) + logger.info("Got config from {0}".format(os_conf)) + except: + logger.critical("Tried to load config from {0} but failed.".format(os_conf)) + raise + elif "DB_CONNECTION" in os.environ: + user_db_conn = os.environ['DB_CONNECTION'] + logger.info('Got config from DB_CONNECTION env var') + else: + logger.critical('Could not get db config, either from config file or env var') + sys.exit(1) + + # Root DB engine + try: + root_engine_full = create_engine(db_connection) + root_user = root_engine_full.url.username + root_password = root_engine_full.url.password + drivername = root_engine_full.url.drivername + host = root_engine_full.url.host + port = root_engine_full.url.port + root_engine_url = ''.join([drivername, '://', root_user, ':', root_password, '@', host, ':', str (port)]) + root_engine = create_engine(root_engine_url, connect_args=ssl_args) + connection = root_engine.connect() + connection.close() + logger.info("Tested connection to DB @ {0}:{1} as {2}".format( + host, port, root_user)) + except: + logger.critical('Could not connect to database as root user') + raise + + # User DB engine + try: + user_engine = create_engine(user_db_conn, connect_args=ssl_args) + # Get our user data out of the user_engine + database = user_engine.url.database + user = user_engine.url.username + password = user_engine.url.password + logger.info('Got user db config') + except: + logger.critical('Could not get user database config') + raise + + # Delete DB + try: + with root_engine.connect() as connection: + connection.execute(text("DROP DATABASE IF EXISTS {0}".format(database))) + try: + connection.commit() + except AttributeError: + pass + logger.info("Deleted database {0}".format(database)) + except: + logger.critical("Could not drop database {0}".format(database)) + raise + + # Delete DB User + try: + with root_engine.connect() as connection: + connection.execute(text("DROP USER IF EXISTS {0}".format(user))) + try: + connection.commit() + except AttributeError: + pass + logger.info("Deleted user {0}".format(user)) + except: + logger.critical("Could not delete user {0}".format(user)) + raise + + logger.info('Finished DB Management') + db-init.py: | + #!/usr/bin/env python + + # Creates db and user for an OpenStack Service: + # Set ROOT_DB_CONNECTION and DB_CONNECTION environment variables to contain + # SQLAlchemy strings for the root connection to the database and the one you + # wish the service to use. Alternatively, you can use an ini formatted config + # at the location specified by OPENSTACK_CONFIG_FILE, and extract the string + # from the key OPENSTACK_CONFIG_DB_KEY, in the section specified by + # OPENSTACK_CONFIG_DB_SECTION. + + import os + import sys + try: + import ConfigParser + PARSER_OPTS = {} + except ImportError: + import configparser as ConfigParser + PARSER_OPTS = {"strict": False} + import logging + from sqlalchemy import create_engine + from sqlalchemy import text + + # Create logger, console handler and formatter + logger = logging.getLogger('OpenStack-Helm DB Init') + logger.setLevel(logging.DEBUG) + ch = logging.StreamHandler() + ch.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + + # Set the formatter and add the handler + ch.setFormatter(formatter) + logger.addHandler(ch) + + + # Get the connection string for the service db root user + if "ROOT_DB_CONNECTION" in os.environ: + db_connection = os.environ['ROOT_DB_CONNECTION'] + logger.info('Got DB root connection') + else: + logger.critical('environment variable ROOT_DB_CONNECTION not set') + sys.exit(1) + + mysql_x509 = os.getenv('MARIADB_X509', "") + ssl_args = {} + if mysql_x509: + ssl_args = {'ssl': {'ca': '/etc/mysql/certs/ca.crt', + 'key': '/etc/mysql/certs/tls.key', + 'cert': '/etc/mysql/certs/tls.crt'}} + + # Get the connection string for the service db + if "OPENSTACK_CONFIG_FILE" in os.environ: + os_conf = os.environ['OPENSTACK_CONFIG_FILE'] + if "OPENSTACK_CONFIG_DB_SECTION" in os.environ: + os_conf_section = os.environ['OPENSTACK_CONFIG_DB_SECTION'] + else: + logger.critical('environment variable OPENSTACK_CONFIG_DB_SECTION not set') + sys.exit(1) + if "OPENSTACK_CONFIG_DB_KEY" in os.environ: + os_conf_key = os.environ['OPENSTACK_CONFIG_DB_KEY'] + else: + logger.critical('environment variable OPENSTACK_CONFIG_DB_KEY not set') + sys.exit(1) + try: + config = ConfigParser.RawConfigParser(**PARSER_OPTS) + logger.info("Using {0} as db config source".format(os_conf)) + config.read(os_conf) + logger.info("Trying to load db config from {0}:{1}".format( + os_conf_section, os_conf_key)) + user_db_conn = config.get(os_conf_section, os_conf_key) + logger.info("Got config from {0}".format(os_conf)) + except: + logger.critical("Tried to load config from {0} but failed.".format(os_conf)) + raise + elif "DB_CONNECTION" in os.environ: + user_db_conn = os.environ['DB_CONNECTION'] + logger.info('Got config from DB_CONNECTION env var') + else: + logger.critical('Could not get db config, either from config file or env var') + sys.exit(1) + + # Root DB engine + try: + root_engine_full = create_engine(db_connection) + root_user = root_engine_full.url.username + root_password = root_engine_full.url.password + drivername = root_engine_full.url.drivername + host = root_engine_full.url.host + port = root_engine_full.url.port + root_engine_url = ''.join([drivername, '://', root_user, ':', root_password, '@', host, ':', str (port)]) + root_engine = create_engine(root_engine_url, connect_args=ssl_args) + connection = root_engine.connect() + connection.close() + logger.info("Tested connection to DB @ {0}:{1} as {2}".format( + host, port, root_user)) + except: + logger.critical('Could not connect to database as root user') + raise + + # User DB engine + try: + user_engine = create_engine(user_db_conn, connect_args=ssl_args) + # Get our user data out of the user_engine + database = user_engine.url.database + user = user_engine.url.username + password = user_engine.url.password + logger.info('Got user db config') + except: + logger.critical('Could not get user database config') + raise + + # Create DB + try: + with root_engine.connect() as connection: + connection.execute(text("CREATE DATABASE IF NOT EXISTS {0}".format(database))) + try: + connection.commit() + except AttributeError: + pass + logger.info("Created database {0}".format(database)) + except: + logger.critical("Could not create database {0}".format(database)) + raise + + # Create DB User + try: + with root_engine.connect() as connection: + connection.execute( + text("CREATE USER IF NOT EXISTS \'{0}\'@\'%\' IDENTIFIED BY \'{1}\' {2}".format( + user, password, mysql_x509))) + connection.execute( + text("GRANT ALL ON `{0}`.* TO \'{1}\'@\'%\'".format(database, user))) + try: + connection.commit() + except AttributeError: + pass + logger.info("Created user {0} for {1}".format(user, database)) + except: + logger.critical("Could not create user {0} for {1}".format(user, database)) + raise + + # Test connection + try: + connection = user_engine.connect() + connection.close() + logger.info("Tested connection to DB @ {0}:{1}/{2} as {3}".format( + host, port, database, user)) + except: + logger.critical('Could not connect to database as user') + raise + + logger.info('Finished DB Management') + db-sync.sh: | + #!/bin/bash + + set -ex + + ironic-dbsync upgrade + ironic-api.sh: | + #!/bin/bash + + set -ex + COMMAND="${@:-start}" + + cat <<'EOF' > /etc/ironic/ironic-api-uwsgi.ini + [uwsgi] + add-header = Connection: close + buffer-size = 65535 + die-on-term = true + enable-threads = true + exit-on-reload = false + hook-master-start = unix_signal:15 gracefully_kill_them_all + http-socket = 0.0.0.0:6385 + lazy-apps = true + log-x-forwarded-for = true + master = true + processes = 4 + procname-prefix-spaced = ironic-api: + route-user-agent = ^kube-probe.* donotlog: + thunder-lock = true + worker-reload-mercy = 80 + module = ironic.wsgi:application + EOF + + function start () { + exec uwsgi --ini /etc/ironic/ironic-api-uwsgi.ini + } + + function stop () { + kill -TERM 1 + } + + $COMMAND + ironic-conductor-http-init.sh: | + #!/bin/bash + set -ex + if [ "x" == "x${PROVISIONER_INTERFACE}" ]; then + echo "Provisioner interface is not set" + exit 1 + fi + + function net_pxe_addr { + ip addr | awk "/inet / && /${PROVISIONER_INTERFACE}/{print \$2; exit }" + } + function net_pxe_ip { + echo $(net_pxe_addr) | awk -F '/' '{ print $1; exit }' + } + PXE_IP=$(net_pxe_ip) + + if [ "x" == "x${PXE_IP}" ]; then + echo "Could not find IP for pxe to bind to" + exit 1 + fi + + sed "s|OSH_PXE_IP|${PXE_IP}|g" /etc/nginx/nginx.conf > /tmp/pod-shared/nginx.conf + ironic-conductor-http.sh: | + #!/bin/bash + set -ex + mkdir -p /var/lib/openstack-helm/httpboot + cp -v /tmp/pod-shared/nginx.conf /etc/nginx/nginx.conf + exec nginx -g 'daemon off;' + ironic-conductor-init.sh: | + #!/bin/bash + + set -ex + + if [ "x" == "x${PROVISIONER_INTERFACE}" ]; then + echo "Provisioner interface is not set" + exit 1 + fi + + function net_pxe_addr { + ip addr | awk "/inet / && /${PROVISIONER_INTERFACE}/{print \$2; exit }" + } + function net_pxe_ip { + echo $(net_pxe_addr) | awk -F '/' '{ print $1; exit }' + } + PXE_IP=$(net_pxe_ip) + + if [ "x" == "x${PXE_IP}" ]; then + echo "Could not find IP for pxe to bind to" + exit 1 + fi + + # ensure the tempdir exists, read it from the config + ironictmpdir=$(python -c 'from configparser import ConfigParser;cfg = ConfigParser();cfg.read("/etc/ironic/ironic.conf");print(cfg.get("DEFAULT", "tempdir", fallback=""))') + if [ -n "${ironictmpdir}" -a ! -d "${ironictmpdir}" ]; then + mkdir -p "${ironictmpdir}" + chmod 1777 "${ironictmpdir}" + fi + + tee /tmp/pod-shared/conductor-local-ip.conf << EOF + [DEFAULT] + + # IP address of this host. If unset, will determine the IP + # programmatically. If unable to do so, will use "127.0.0.1". + # (string value) + my_ip = ${PXE_IP} + + [pxe] + # IP address of ironic-conductor node's TFTP server. (string + # value) + tftp_server = ${PXE_IP} + + [deploy] + # ironic-conductor node's HTTP server URL. Example: + # http://192.1.2.3:8080 (string value) + # from .deploy.ironic.http_url + http_url = http://${PXE_IP}:80 + EOF + ironic-conductor.sh: | + #!/bin/bash + + set -ex + + mkdir -p /var/lib/openstack-helm/ironic/images + mkdir -p /var/lib/openstack-helm/ironic/master_images + + exec ironic-conductor \ + --config-file /etc/ironic/ironic.conf \ + --config-file /tmp/pod-shared/conductor-local-ip.conf \ + --config-dir /etc/ironic/ironic.conf.d \ + ${OPTIONS} + ks-endpoints.sh: | + #!/bin/bash + + # Copyright 2017 Pete Birley + # + # 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. + + set -ex + + # Get Service ID + OS_SERVICE_ID=$( openstack service list -f csv --quote none | \ + grep ",${OS_SERVICE_NAME},${OS_SERVICE_TYPE}$" | \ + sed -e "s/,${OS_SERVICE_NAME},${OS_SERVICE_TYPE}//g" ) + + # Get Endpoint ID if it exists + OS_ENDPOINT_ID=$( openstack endpoint list -f csv --quote none | \ + grep "^[a-z0-9]*,${OS_REGION_NAME},${OS_SERVICE_NAME},${OS_SERVICE_TYPE},True,${OS_SVC_ENDPOINT}," | \ + awk -F ',' '{ print $1 }' ) + + # Making sure only a single endpoint exists for a service within a region + if [ "$(echo $OS_ENDPOINT_ID | wc -w)" -gt "1" ]; then + echo "More than one endpoint found, cleaning up" + for ENDPOINT_ID in $OS_ENDPOINT_ID; do + openstack endpoint delete ${ENDPOINT_ID} + done + unset OS_ENDPOINT_ID + fi + + # Determine if Endpoint needs updated + if [[ ${OS_ENDPOINT_ID} ]]; then + OS_ENDPOINT_URL_CURRENT=$(openstack endpoint show ${OS_ENDPOINT_ID} -f value -c url) + if [ "${OS_ENDPOINT_URL_CURRENT}" == "${OS_SERVICE_ENDPOINT}" ]; then + echo "Endpoints Match: no action required" + OS_ENDPOINT_UPDATE="False" + else + echo "Endpoints Dont Match: removing existing entries" + openstack endpoint delete ${OS_ENDPOINT_ID} + OS_ENDPOINT_UPDATE="True" + fi + else + OS_ENDPOINT_UPDATE="True" + fi + + # Update Endpoint if required + if [[ "${OS_ENDPOINT_UPDATE}" == "True" ]]; then + OS_ENDPOINT_ID=$( openstack endpoint create -f value -c id \ + --region="${OS_REGION_NAME}" \ + "${OS_SERVICE_ID}" \ + ${OS_SVC_ENDPOINT} \ + "${OS_SERVICE_ENDPOINT}" ) + fi + + # Display the Endpoint + openstack endpoint show ${OS_ENDPOINT_ID} + ks-service.sh: | + #!/bin/bash + + # Copyright 2017 Pete Birley + # + # 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. + + set -ex + + # Service boilerplate description + OS_SERVICE_DESC="${OS_REGION_NAME}: ${OS_SERVICE_NAME} (${OS_SERVICE_TYPE}) service" + + # Get Service ID if it exists + unset OS_SERVICE_ID + + # FIXME - There seems to be an issue once in a while where the + # openstack service list fails and encounters an error message such as: + # Unable to establish connection to + # https://keystone-api.openstack.svc.cluster.local:5000/v3/auth/tokens: + # ('Connection aborted.', OSError("(104, 'ECONNRESET')",)) + # During an upgrade scenario, this would cause the OS_SERVICE_ID to be blank + # and it would attempt to create a new service when it was not needed. + # This duplicate service would sometimes be used by other services such as + # Horizon and would give an 'Invalid Service Catalog' error. + # This loop allows for a 'retry' of the openstack service list in an + # attempt to get the service list as expected if it does encounter an error. + # This loop and recheck can be reverted once the underlying issue is addressed. + + # If OS_SERVICE_ID is blank then wait a few seconds to give it + # additional time and try again + for i in $(seq 3) + do + OS_SERVICE_ID=$( openstack service list -f csv --quote none | \ + grep ",${OS_SERVICE_NAME},${OS_SERVICE_TYPE}$" | \ + sed -e "s/,${OS_SERVICE_NAME},${OS_SERVICE_TYPE}//g" ) + + # If the service was found, go ahead and exit successfully. + if [[ -n "${OS_SERVICE_ID}" ]]; then + exit 0 + fi + + sleep 2 + done + + # If we've reached this point and a Service ID was not found, + # then create the service + OS_SERVICE_ID=$(openstack service create -f value -c id \ + --name="${OS_SERVICE_NAME}" \ + --description "${OS_SERVICE_DESC}" \ + --enable \ + "${OS_SERVICE_TYPE}") + ks-user.sh: | + #!/bin/bash + + # Copyright 2017 Pete Birley + # + # 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. + + set -ex + + shopt -s nocasematch + + if [[ "${SERVICE_OS_PROJECT_DOMAIN_NAME}" == "Default" ]] + then + PROJECT_DOMAIN_ID="default" + else + # Manage project domain + PROJECT_DOMAIN_ID=$(openstack domain create --or-show --enable -f value -c id \ + --description="Domain for ${SERVICE_OS_REGION_NAME}/${SERVICE_OS_PROJECT_DOMAIN_NAME}" \ + "${SERVICE_OS_PROJECT_DOMAIN_NAME}") + fi + + if [[ "${SERVICE_OS_USER_DOMAIN_NAME}" == "Default" ]] + then + USER_DOMAIN_ID="default" + else + # Manage user domain + USER_DOMAIN_ID=$(openstack domain create --or-show --enable -f value -c id \ + --description="Domain for ${SERVICE_OS_REGION_NAME}/${SERVICE_OS_USER_DOMAIN_NAME}" \ + "${SERVICE_OS_USER_DOMAIN_NAME}") + fi + + shopt -u nocasematch + + # Manage user project + USER_PROJECT_DESC="Service Project for ${SERVICE_OS_REGION_NAME}/${SERVICE_OS_PROJECT_DOMAIN_NAME}" + USER_PROJECT_ID=$(openstack project create --or-show --enable -f value -c id \ + --domain="${PROJECT_DOMAIN_ID}" \ + --description="${USER_PROJECT_DESC}" \ + "${SERVICE_OS_PROJECT_NAME}"); + + # Manage user + USER_DESC="Service User for ${SERVICE_OS_REGION_NAME}/${SERVICE_OS_USER_DOMAIN_NAME}/${SERVICE_OS_SERVICE_NAME}" + USER_ID=$(openstack user create --or-show --enable -f value -c id \ + --domain="${USER_DOMAIN_ID}" \ + --project-domain="${PROJECT_DOMAIN_ID}" \ + --project="${USER_PROJECT_ID}" \ + --description="${USER_DESC}" \ + "${SERVICE_OS_USERNAME}"); + + # Manage user password (we do this in a separate step to ensure the password is updated if required) + set +x + echo "Setting user password via: openstack user set --password=xxxxxxx ${USER_ID}" + openstack user set --password="${SERVICE_OS_PASSWORD}" "${USER_ID}" + set -x + + function ks_assign_user_role () { + if [[ "$SERVICE_OS_ROLE" == "admin" ]] + then + USER_ROLE_ID="$SERVICE_OS_ROLE" + else + USER_ROLE_ID=$(openstack role create --or-show -f value -c id "${SERVICE_OS_ROLE}"); + fi + + # Manage user role assignment + openstack role add \ + --user="${USER_ID}" \ + --user-domain="${USER_DOMAIN_ID}" \ + --project-domain="${PROJECT_DOMAIN_ID}" \ + --project="${USER_PROJECT_ID}" \ + "${USER_ROLE_ID}" + } + + # Manage user service role + IFS=',' + for SERVICE_OS_ROLE in ${SERVICE_OS_ROLES}; do + ks_assign_user_role + done + + # Manage user member role + : ${MEMBER_OS_ROLE:="member"} + export USER_ROLE_ID=$(openstack role create --or-show -f value -c id \ + "${MEMBER_OS_ROLE}"); + ks_assign_user_role + manage-cleaning-network.sh: | + #!/bin/bash + + set -ex + + if ! openstack network show ${neutron_network_name}; then + IRONIC_NEUTRON_CLEANING_NET_ID=$(openstack network create -f value -c id \ + --share \ + --provider-network-type flat \ + --provider-physical-network ${neutron_provider_network} \ + ${neutron_network_name}) + else + IRONIC_NEUTRON_CLEANING_NET_ID=$(openstack network show ${neutron_network_name} -f value -c id) + fi + + SUBNETS=$(openstack network show $IRONIC_NEUTRON_CLEANING_NET_ID -f value -c subnets) + if [ "x${SUBNETS}" != "x[]" ]; then + for SUBNET in ${SUBNETS}; do + CURRENT_SUBNET=$(openstack subnet show $SUBNET -f value -c name) + if [ "x${CURRENT_SUBNET}" == "x${neutron_subnet_name}" ]; then + openstack subnet show ${neutron_subnet_name} + SUBNET_EXISTS=true + fi + done + fi + + if [ "x${SUBNET_EXISTS}" != "xtrue" ]; then + openstack subnet create \ + --gateway ${neutron_subnet_gateway%/*} \ + --allocation-pool start=${neutron_subnet_alloc_start},end=${neutron_subnet_alloc_end} \ + --dns-nameserver ${neutron_subnet_dns_nameserver} \ + --subnet-range ${neutron_subnet_cidr} \ + --network ${neutron_network_name} \ + ${neutron_subnet_name} + fi + rabbit-init.sh: | + #!/bin/bash + set -e + # Extract connection details + RABBIT_HOSTNAME=$(echo "${RABBITMQ_ADMIN_CONNECTION}" | \ + awk -F'[@]' '{print $2}' | \ + awk -F'[:/]' '{print $1}') + RABBIT_PORT=$(echo "${RABBITMQ_ADMIN_CONNECTION}" | \ + awk -F'[@]' '{print $2}' | \ + awk -F'[:/]' '{print $2}') + + # Extract Admin User credential + RABBITMQ_ADMIN_USERNAME=$(echo "${RABBITMQ_ADMIN_CONNECTION}" | \ + awk -F'[@]' '{print $1}' | \ + awk -F'[//:]' '{print $4}') + RABBITMQ_ADMIN_PASSWORD=$(echo "${RABBITMQ_ADMIN_CONNECTION}" | \ + awk -F'[@]' '{print $1}' | \ + awk -F'[//:]' '{print $5}' | \ + sed 's/%/\\x/g' | \ + xargs -0 printf "%b") + + # Extract User credential + RABBITMQ_USERNAME=$(echo "${RABBITMQ_USER_CONNECTION}" | \ + awk -F'[@]' '{print $1}' | \ + awk -F'[//:]' '{print $4}') + RABBITMQ_PASSWORD=$(echo "${RABBITMQ_USER_CONNECTION}" | \ + awk -F'[@]' '{print $1}' | \ + awk -F'[//:]' '{print $5}' | \ + sed 's/%/\\x/g' | \ + xargs -0 printf "%b") + + # Extract User vHost + RABBITMQ_VHOST=$(echo "${RABBITMQ_USER_CONNECTION}" | \ + awk -F'[@]' '{print $2}' | \ + awk -F'[:/]' '{print $3}') + # Resolve vHost to / if no value is set + RABBITMQ_VHOST="${RABBITMQ_VHOST:-/}" + + function rabbitmqadmin_cli () { + if [ -n "$RABBITMQ_X509" ] + then + rabbitmqadmin \ + --ssl \ + --ssl-disable-hostname-verification \ + --ssl-ca-cert-file="${USER_CERT_PATH}/ca.crt" \ + --ssl-cert-file="${USER_CERT_PATH}/tls.crt" \ + --ssl-key-file="${USER_CERT_PATH}/tls.key" \ + --host="${RABBIT_HOSTNAME}" \ + --port="${RABBIT_PORT}" \ + --username="${RABBITMQ_ADMIN_USERNAME}" \ + --password="${RABBITMQ_ADMIN_PASSWORD}" \ + ${@} + else + rabbitmqadmin \ + --host="${RABBIT_HOSTNAME}" \ + --port="${RABBIT_PORT}" \ + --username="${RABBITMQ_ADMIN_USERNAME}" \ + --password="${RABBITMQ_ADMIN_PASSWORD}" \ + ${@} + fi + } + + echo "Managing: User: ${RABBITMQ_USERNAME}" + rabbitmqadmin_cli \ + declare user \ + name="${RABBITMQ_USERNAME}" \ + password="${RABBITMQ_PASSWORD}" \ + tags="user" + + echo "Deleting Guest User" + rabbitmqadmin_cli \ + delete user \ + name="guest" || true + + if [ "${RABBITMQ_VHOST}" != "/" ] + then + echo "Managing: vHost: ${RABBITMQ_VHOST}" + rabbitmqadmin_cli \ + declare vhost \ + name="${RABBITMQ_VHOST}" + else + echo "Skipping root vHost declaration: vHost: ${RABBITMQ_VHOST}" + fi + + echo "Managing: Permissions: ${RABBITMQ_USERNAME} on ${RABBITMQ_VHOST}" + rabbitmqadmin_cli \ + declare permission \ + vhost="${RABBITMQ_VHOST}" \ + user="${RABBITMQ_USERNAME}" \ + configure=".*" \ + write=".*" \ + read=".*" + + if [ ! -z "$RABBITMQ_AUXILIARY_CONFIGURATION" ] + then + echo "Applying additional configuration" + echo "${RABBITMQ_AUXILIARY_CONFIGURATION}" > /tmp/rmq_definitions.json + rabbitmqadmin_cli import /tmp/rmq_definitions.json + fi + retreive-cleaning-network.sh: | + #!/bin/bash + + set -ex + + IRONIC_NEUTRON_CLEANING_NET_ID=$(openstack network show ${neutron_network_name} -f value -c id) + tee /tmp/pod-shared/cleaning-network.conf < Date: Fri, 6 Mar 2026 21:40:25 +0530 Subject: [PATCH 2/2] updating configmap with all upstream changes from 2025.2.8 to 2025.2.14 --- components/ironic/configmap-ironic-bin.yaml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/components/ironic/configmap-ironic-bin.yaml b/components/ironic/configmap-ironic-bin.yaml index f1a7ef0e6..72c168d07 100644 --- a/components/ironic/configmap-ironic-bin.yaml +++ b/components/ironic/configmap-ironic-bin.yaml @@ -295,7 +295,12 @@ data: set -ex + # https://docs.openstack.org/ironic/latest/admin/upgrade-guide.html ironic-dbsync upgrade + + ironic-dbsync online_data_migrations + + echo 'Finished DB migrations' ironic-api.sh: | #!/bin/bash @@ -773,16 +778,6 @@ data: echo "${RABBITMQ_AUXILIARY_CONFIGURATION}" > /tmp/rmq_definitions.json rabbitmqadmin_cli import /tmp/rmq_definitions.json fi - retreive-cleaning-network.sh: | - #!/bin/bash - - set -ex - - IRONIC_NEUTRON_CLEANING_NET_ID=$(openstack network show ${neutron_network_name} -f value -c id) - tee /tmp/pod-shared/cleaning-network.conf <