# resource_properties_data

created_at: 2025-12-01 09:42:18.713337
data:
  {"volumes": ["/var/log/containers/nova:/var/log/nova"], "host_prep_tasks": [{"name": "create persistent directories", "file": {"path": "{{ item.path }}", "setype": "{{ item.setype }}", "state": "directory", "mode": "{{ item.mode }}"}, "with_items": [{"path": "/var/log/containers/nova", "setype": "container_file_t", "mode": "0750"}]}], "cmd_extra_args": "", "tuple:('docker_config', 'step_2')": {"nova_compute_init_log": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "net": "none", "privileged": false, "user": "root", "volumes": ["/var/log/containers/nova:/var/log/nova:z"], "command": ["/bin/bash", "-c", "chown -R nova:nova /var/log/nova"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}}, "config_settings": null, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-52-7jfofxryzovo-NovaLogging-ayboqwjd77yw/a247da0d-72ca-4548-bd2e-c5058014fd4d"}


created_at: 2025-12-01 09:42:18.759851
data:
  {"tuple:('role_data', 'config_settings')": {"nova::my_ip": "%{hiera('internal_api')}", "nova::rabbit_use_ssl": "False", "nova::keystone::service_user::send_service_user_token": true, "nova::keystone::service_user::project_name": "service", "nova::keystone::service_user::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::keystone::service_user::auth_url": "http://172.17.0.2:5000", "nova::keystone::service_user::region_name": "regionOne", "nova::placement::project_name": "service", "nova::placement::password": "dYVRSnGa4R5DjmK0t4f9aWqpK", "nova::placement::auth_url": "http://172.17.0.2:5000", "nova::placement::region_name": "regionOne", "nova::placement::valid_interfaces": "internal", "nova::os_region_name": "regionOne", "nova::logging::debug": true, "nova::purge_config": false, "nova::network::neutron::project_name": "service", "nova::network::neutron::username": "neutron", "nova::network::neutron::region_name": "regionOne", "nova::dhcp_domain": "", "nova::network::neutron::password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "nova::network::neutron::auth_url": "http://172.17.0.2:5000/v3", "nova::network::neutron::valid_interfaces": "internal", "nova::glance::valid_interfaces": "internal", "nova::rabbit_heartbeat_timeout_threshold": 60, "nova::cinder_catalog_info": "volumev3:cinderv3:internalURL", "nova::host": "%{hiera('fqdn_canonical')}", "nova::notify_on_state_change": "vm_and_task_state", "nova::notification_driver": ["messagingv2"], "nova::notification_format": "unversioned", "nova::network::neutron::auth_type": "v3password", "nova::db::database_db_max_retries": -1, "nova::db::database_max_retries": -1, "nova::network::neutron::ovs_bridge": "br-int", "nova::compute::sync_power_state_interval": 600, "nova_is_additional_cell": false, "nova::cross_az_attach": true, "nova::cache::enabled": true, "nova::cache::tls_enabled": false, "nova::cache::backend": "dogpile.cache.memcached", "nova::rabbit_heartbeat_in_pthread": false, "nova::ovsdb_connection": ""}, "tuple:('role_data', 'config_settings', 'nova::logging::debug')": true, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-52-7jfofxryzovo-NovaBase-3w6lkfzmblej/ff2276e6-d155-4844-bd7c-8c36896a43d9"}


created_at: 2025-12-01 09:42:18.783956
data:
  {"tuple:('role_data', 'step_config')": null, "tuple:('role_data', 'docker_config')": {"step_2": {"nova_compute_init_log": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "net": "none", "privileged": false, "user": "root", "volumes": ["/var/log/containers/nova:/var/log/nova:z"], "command": ["/bin/bash", "-c", "chown -R nova:nova /var/log/nova"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}}, "step_3": {"nova_statedir_owner": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "net": "none", "user": "root", "security_opt": ["label=disable"], "privileged": false, "detach": false, "volumes": ["/var/lib/nova:/var/lib/nova:shared", "/var/lib/_nova_secontext:/var/lib/_nova_secontext:shared,z", "/var/lib/container-config-scripts:/container-config-scripts:z"], "command": "/container-config-scripts/pyshim.sh /container-config-scripts/nova_statedir_ownership.py", "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821", "__OS_DEBUG": "true", "NOVA_STATEDIR_OWNERSHIP_SKIP": "triliovault-mounts"}}}, "step_5": {"nova_compute": {"start_order": 3, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "ulimit": ["nofile=131072", "memlock=67108864"], "ipc": "host", "net": "host", "privileged": true, "user": "nova", "restart": "always", "depends_on": ["tripleo_nova_libvirt.target"], "healthcheck": {"test": "/openstack/healthcheck 5672"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/nova:/var/log/nova", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/var/lib/kolla/config_files/nova_compute.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/config-data/puppet-generated/iscsid/etc/iscsi:/var/lib/kolla/config_files/src-iscsid:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/dev:/dev", "/lib/modules:/lib/modules:ro", "/run:/run", "/run/nova:/run/nova:z", "/var/lib/iscsi:/var/lib/iscsi:z", "/var/lib/libvirt:/var/lib/libvirt:shared", "/sys/class/net:/sys/class/net", "/sys/bus/pci:/sys/bus/pci", "/boot:/boot:ro", "/var/lib/nova:/var/lib/nova:shared"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS", "LIBGUESTFS_BACKEND": "direct"}}, "nova_wait_for_compute_service": {"start_order": 4, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "net": "host", "detach": false, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/kolla/config_files/nova_compute_wait_for_compute_service.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/log/containers/nova:/var/log/nova", "/var/lib/container-config-scripts:/container-config-scripts"], "user": "nova", "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS", "__OS_DEBUG": "true"}}}}, "tuple:('role_data', 'service_names')": null, "tuple:('role_data', 'container_config_scripts')": {"container_puppet_apply.sh": {"mode": "0700", "content": "#!/bin/bash\nset -eux\nSTEP=$1\nTAGS=$2\nCONFIG=$3\nEXTRA_ARGS=${4:-''}\nif [ -d /tmp/puppet-etc ]; then\n  # ignore copy failures as these may be the same file depending on docker mounts\n  cp -a /tmp/puppet-etc/* /etc/puppet || true\nfi\necho \"{\\\"step\\\": ${STEP}}\" > /etc/puppet/hieradata/docker_puppet.json\n# $::deployment_type in puppet-tripleo\nexport FACTER_deployment_type=containers\nset +e\npuppet apply $EXTRA_ARGS \\\n    --verbose \\\n    --detailed-exitcodes \\\n    --summarize \\\n    --color=false \\\n    --modulepath /etc/puppet/modules:/opt/stack/puppet-modules:/usr/share/openstack-puppet/modules \\\n    --tags $TAGS \\\n    -e \"noop_resource('package'); ${CONFIG}\"\nrc=$?\nset -e\nset +ux\nif [ $rc -eq 2 -o $rc -eq 0 ]; then\n    exit 0\nfi\nexit $rc\n"}, "pyshim.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n# Copyright 2018 Red Hat Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n#\n# Usage: pyshim.sh <script and/or arguments>\n#\n# Unfortunately THT doesn't know which version of python might be in a\n# container so we need this script to be able to try python3 or python2\n# depending on availability.  Since this is a temporary shim until we've\n# fully cut over to python3, we check for the existence of python3 first\n# before falling back to python2. This will help in the transition from\n# python2 based containers to python3.\n\nshow_usage() {\n    echo \"Usage: pyshim.sh <script and/or arguments>\"\n}\n\nif [ $# -lt 1 ]\nthen\n    show_usage\n    exit 1\nfi\n\nset -x\nif command -v python3 >/dev/null; then\n    python3 \"$@\"\nelif command -v python2 >/dev/null; then\n    python2 \"$@\"\nelif command -v python >/dev/null; then\n    python \"$@\"\nelse\n    echo \"ERROR: python is not available!\"\n    exit 1\nfi\n"}, "pacemaker_restart_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nset -u\n\n# ./pacemaker_restart_bundle.sh mysql galera galera-bundle Master _\n# ./pacemaker_restart_bundle.sh redis redis redis-bundle Slave Master\n# ./pacemaker_restart_bundle.sh ovn_dbs ovndb_servers ovn-dbs-bundle Slave Master\nRESTART_SCRIPTS_DIR=$(dirname $0)\nTRIPLEO_SERVICE=$1\nRESOURCE_NAME=$2\nBUNDLE_NAME=$3\nWAIT_TARGET_LOCAL=$4\nWAIT_TARGET_ANYWHERE=${5:-_}\nTRIPLEO_MINOR_UPDATE=\"${TRIPLEO_MINOR_UPDATE:-false}\"\nTRIPLEO_HA_WRAPPER_RESOURCE_EXISTS=\"${TRIPLEO_HA_WRAPPER_RESOURCE_EXISTS:-false}\"\n\nbundle_can_be_restarted() {\n    local bundle=$1\n    # As long as the resource bundle is managed by pacemaker and is\n    # not meant to stay stopped, no matter the state of any inner\n    # pcmk_remote or ocf resource, we should restart it to give it a\n    # chance to read the new config.\n    [ \"$(crm_resource --meta -r $1 -g is-managed 2>/dev/null)\" != \"false\" ] && \\\n    [ \"$(crm_resource --meta -r $1 -g target-role 2>/dev/null)\" != \"Stopped\" ]\n}\n\nlog() {\n    local msg=$1\n    logger -t pcmkrestart \"$1\"\n}\n\nHOSTNAME=$(/bin/hostname -s)\nif [ x\"${TRIPLEO_MINOR_UPDATE,,}\" != x\"true\" ]; then\n    if [ x\"${TRIPLEO_HA_WRAPPER_RESOURCE_EXISTS,,}\" = x\"false\" ]; then\n        # Do not restart during initial deployment, as the resource\n        # has just been created.\n        SERVICE_NODEID=$(/bin/hiera -c /etc/puppet/hiera.yaml \"${TRIPLEO_SERVICE}_short_bootstrap_node_name\")\n        if [[ \"${HOSTNAME,,}\" == \"${SERVICE_NODEID,,}\" ]]; then\n            log \"Initial deployment, skipping the restart of ${BUNDLE_NAME}\"\n\tfi\n        exit 0\n    else\n        # During a stack update, this script is called in parallel on\n        # every node the resource runs on, after the service's configs\n        # have been updated on all nodes. So we need to run pcs only\n        # once (e.g. on the service's boostrap node).\n        if bundle_can_be_restarted ${BUNDLE_NAME}; then\n            SERVICE_NODEID=$(/bin/hiera -c /etc/puppet/hiera.yaml \"${TRIPLEO_SERVICE}_short_bootstrap_node_name\")\n            if [[ \"${HOSTNAME,,}\" == \"${SERVICE_NODEID,,}\" ]]; then\n                replicas_running=$(crm_resource -Q -r $BUNDLE_NAME --locate 2>&1 | wc -l)\n                if [ \"$replicas_running\" != \"0\" ]; then\n                    log \"Restarting ${BUNDLE_NAME} globally. Stopping:\"\n                    /sbin/pcs resource disable --wait=600 $BUNDLE_NAME\n                    log \"Restarting ${BUNDLE_NAME} globally. Starting:\"\n                    /sbin/pcs resource enable --wait=600 $BUNDLE_NAME\n                else\n                    log \"${BUNDLE_NAME} is not running anywhere,\" \\\n                         \"cleaning up to restart it globally if necessary\"\n                    /sbin/pcs resource cleanup $BUNDLE_NAME\n                fi\n            else\n                log \"Skipping global restart of ${BUNDLE_NAME} on ${HOSTNAME} it will be restarted by node ${SERVICE_NODEID}\"\n            fi\n\n        else\n            log \"No global restart needed for ${BUNDLE_NAME}.\"\n        fi\n    fi\nelse\n    # During a minor update workflow however, a host gets fully\n    # updated before updating the next one. So unlike stack\n    # update, at the time this script is called, the service's\n    # configs aren't updated on all nodes yet. So only restart the\n    # resource locally, where it's guaranteed that the config is\n    # up to date.\n    HOST=$(facter hostname)\n\n    if bundle_can_be_restarted ${BUNDLE_NAME}; then\n\t# if the resource is running locally, restart it\n\tif crm_resource -r $BUNDLE_NAME --locate 2>&1 | grep -w -q \"${HOST}\"; then\n            log \"Restarting ${BUNDLE_NAME} locally on '${HOST}'\"\n            /sbin/pcs resource restart $BUNDLE_NAME \"${HOST}\"\n\n\telse\n\t    # At this point, if no resource is running locally, it's\n\t    # either because a) it has failed previously, or b) because\n\t    # it's an A/P resource running elsewhere.\n\t    # By cleaning up resource, we ensure that a) it will try to\n\t    # restart, or b) it won't do anything if the resource is\n\t    # already running elsewhere.\n            log \"${BUNDLE_NAME} is currently not running on '${HOST}',\" \\\n                 \"cleaning up its state to restart it if necessary\"\n            /sbin/pcs resource cleanup $BUNDLE_NAME node=\"${HOST}\"\n\tfi\n\n\t# Wait until the resource is in the expected target state\n\t$RESTART_SCRIPTS_DIR/pacemaker_wait_bundle.sh \\\n            $RESOURCE_NAME $BUNDLE_NAME \\\n            \"$WAIT_TARGET_LOCAL\" \"$WAIT_TARGET_ANYWHERE\" \\\n\t    \"${HOST}\" 600\n    else\n        log \"No restart needed for ${BUNDLE_NAME}.\"\n    fi\nfi\n"}, "pacemaker_wait_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# ----\n# Wait for an OCF resource or a bundle to be restarted\n# ----\n# e.g.:\n# M/S OCF:      $0 galera galera-bundle Master\n# clone OCF:    $0 rabbitmq rabbitmq-bundle Started\n# A/P M/S OCF:  $0 redis redis-bundle Slave Master\n# A/P bundle:   $0 openstack-cinder-volume openstack-cinder-volume _ Started\n# clone bundle: $0 haproxy-bundle haproxy-bundle Started\n\n# design note 1:\n#  - this script is called during a minor update; it is called\n#    once per node that hosts a service replica.\n#  - the purpose of this script is to ensure that restarting the\n#    service replica locally won't disrupt the service availability\n#    for the end user. To reach that goal, the script waits until the\n#    service is restarted locally or globallu and reaches a given\n#    target state (i.e. Started, Slave or Master).\n# design note 2:\n#   - we don't want to track restart error: our only job is to ensure\n#     service restart synchronization, not service health.\n#   - In particular, we don't want to error out in case the resource\n#     cannot be restarted locally, because that would make the minor\n#     update fail, even if potentially other replicas still provide\n#     the service.\n# design note 3:\n#   - we can bail out early if we determine that the resource can't\n#     be restarted automatically by pacemaker (e.g. its \"blocked\",\n#     unmanaged or disabled).\n\nlog() {\n    local msg=$1\n    echo \"$(date -u): $1\"\n}\n\nusage() {\n    echo 2>&1 \"Usage: $0 NAME BUNDLE_NAME ROLE_LOCAL [ROLE_ANYWHERE] [HOST] [TIMEOUT]\"\n    exit 1\n}\n\npacemaker_supports_promoted() {\n    # The Promoted token is only matched in recent pacemaker versions\n    grep -wq \"<value>Promoted</value>\" /usr/share/pacemaker/resources-*.rng\n}\n\n#\n# Utility functions to detect stuck resources\n#\n\nbundle_failures_locally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    local replica_name\n    for i in $(seq 0 $last); do\n\treplica_name=${BUNDLE_NAME}-${engine}-${i}\n\tcrm_failcount -q -G -r $replica_name -N $HOST\n    done\n}\n\nbundle_failures_globally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    for i in $(seq 0 $last); do\n\tcrm_failcount -q -G -r ${BUNDLE_NAME}-${engine}-${i}\n    done\n}\n\nbundle_running_globally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    # return the number of running bundles replica, i.e. the number of\n    # docker/podman resource replicas currently running in the cluster\n    crm_mon --as-xml | xmllint --xpath \"count(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource[@resource_agent='${OCF}:heartbeat:${engine}']/node)\" -\n}\n\nocf_failures_globally() {\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    local bundle_node\n    for i in $(seq 0 $last); do\n\tbundle_node=${BUNDLE_NAME}-${i}\n\tcrm_failcount -q -G -r $NAME -N $bundle_node\n    done\n}\n\ndid_resource_failed_locally() {\n    local failures\n    local running\n    local remotehost\n    if [ \"${NAME}\" != \"${BUNDLE_NAME}\" ]; then\n\t# if we're dealing with an ocf resource, it is running on a\n\t# pacemaker_remote rather that on the real host, and the\n\t# failcounts are thus associated to the pcmk remote. Replace\n\t# the host's name with the pcmk remote's name.\n        remotehost=$(crm_mon --as-xml | xmllint --xpath \"string(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource/node[@name='${HOST}']/../../resource[@resource_agent='${OCF}:pacemaker:remote']/@id)\" -)\n\tif [ -n \"${remotehost}\" ]; then\n\t    crm_failcount -q -G -r $NAME -N $remotehost | grep -q -w INFINITY\n\t    return $?\n\tfi\n\t# If no pcmk remote is currently running, the failcount from\n\t# the ocf resource is useless, compute the failcount from the\n\t# bundle case instead (computed below).\n    fi\n\n    # for bundles, pacemaker can run any bundle replica locally\n    # (e.g. galera-bundle-docker-{0,1,2}), and a failure happens when\n    # there are no more replica to try.\n    # That is, when _at least_ one replica failed locally, and all the\n    # others either failed or are currently running elsewhere.\n    failures=$(bundle_failures_locally $HOST | grep -c -w INFINITY)\n    running=$(bundle_running_globally)\n    test $failures -gt 0 && \\\n    test $(( $failures + $running )) -ge $BUNDLE_REPLICAS\n}\n\ndid_resource_failed_globally() {\n    local remotecount\n    local failures\n    if [ \"${NAME}\" != \"${BUNDLE_NAME}\" ]; then\n\t# we check the state of an ocf resource only if the\n\t# pcmkremotes are started\n        remotecount=$(crm_mon --as-xml | xmllint --xpath \"count(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource[@resource_agent='${OCF}:pacemaker:remote']/node)\" -)\n\tif [ \"${remotecount}\" = \"0\" ]; then\n\t    # no pcmkremote is running, so check the bundle state\n\t    # instead of checking the ocf resource\n\t    # bundle failed if all ${BUNDLE_REPLICAS} replicas failed\n\t    failures=$(bundle_failures_globally | grep -c -w INFINITY)\n\t    test $failures -eq $BUNDLE_REPLICAS\n\telse\n\t    # ocf resource failed if it failed to start on\n\t    # all $BUNDLE_REPLICAS bundle nodes\n\t    failures=$(ocf_failures_globally | grep -c -w INFINITY)\n\t    test $failures -eq $BUNDLE_REPLICAS\n\tfi\n    else\n\t# bundle failed if all ${BUNDLE_REPLICAS} replicas failed\n\tfailures=$(bundle_failures_globally | grep -c -w INFINITY)\n\ttest $failures -eq $BUNDLE_REPLICAS\n    fi\n}\n\n\n# Input validation\n#\n\nNAME=$1\nif [ -z \"${NAME}\" ]; then\n    echo 2>&1 \"Error: argument NAME must not be empty\"\n    exit 1\nfi\n\nBUNDLE_NAME=$2\nif [ -z \"${BUNDLE_NAME}\" ]; then\n    echo 2>&1 \"Error: argument BUNDLE_NAME must not be empty\"\n    exit 1\nfi\n\nROLE_LOCAL=$3\nif [ \"${ROLE_LOCAL}\" = \"_\" ]; then\n    ROLE_LOCAL=\"\"\nfi\n\nROLE_ANYWHERE=$4\nif [ \"${ROLE_ANYWHERE}\" = \"_\" ]; then\n    ROLE_ANYWHERE=\"\"\nfi\n\nif [ -z \"${ROLE_LOCAL}\" ]; then\n    if [ -z \"${ROLE_ANYWHERE}\" ]; then\n        echo 2>&1 \"Error: either ROLE_LOCAL or ROLE_ANYWHERE must be non empty\"\n        exit 1\n    fi\nelse\n    if !(echo \"${ROLE_LOCAL}\" | grep -q -x -E \"(Started|Slave|Master|Unpromoted|Promoted)\"); then\n        echo 2>&1 \"Error: argument ROLE_LOCAL must be either 'Started' 'Slave' 'Master' 'Unpromoted' or 'Promoted'\"\n        exit 1\n    fi\nfi\n\nif [ -n \"${ROLE_ANYWHERE}\" ] && !(echo \"${ROLE_ANYWHERE}\" | grep -q -x -E \"(Started|Slave|Master|Unpromoted|Promoted)\"); then\n    echo 2>&1 \"Error: argument ROLE_ANYWHERE must be either 'Started' 'Slave' 'Master' 'Unpromoted' or 'Promoted'\"\n    exit 1\nfi\n\n# Ensure compatibility with pacemaker 2.1\nif pacemaker_supports_promoted; then\n    ROLE_LOCAL=$(echo \"$ROLE_LOCAL\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    ROLE_ANYWHERE=$(echo \"$ROLE_ANYWHERE\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    OCF=\"ocf\"\nelse\n    OCF=\"ocf:\"\nfi\n\nHOST=${5:-$(facter hostname)}\nTIMEOUT=${6:-600}\n\n\n# Configure the search\n# ----\n# Note: we can't use crm_resource in all searches because we can't\n# easily extract the host the OCF resources run on (crm_resource\n# returns the pcmk-remote nodes rather than the hosts)\n# So instead, we implement various searches with XPath directly.\n\nif [ \"${BUNDLE_NAME}\" != \"${NAME}\" ]; then\n# ocf resource\nlocal_resource_xpath=\"//bundle/replica/resource[@resource_agent='${OCF}:pacemaker:remote']/node[@name='${HOST}']/../../resource[@id='${NAME}']\"\nany_resource_xpath=\"//bundle//resource[@id='${NAME}']\"\nreplicas_xpath=\"//bundle/primitive[@id='${BUNDLE_NAME}']/../*[boolean(@image) and boolean(@replicas)]\"\nelse\n# bundle resource\nlocal_resource_xpath=\"//bundle[@id='${NAME}']/replica/resource/node[@name='${HOST}']/../../resource\"\nany_resource_xpath=\"//bundle[@id='${NAME}']//resource\"\nreplicas_xpath=\"//bundle[@id='${BUNDLE_NAME}']/*[boolean(@image) and boolean(@replicas)]\"\nfi\n\nbundle_def_xpath=\"//bundle[@id='${BUNDLE_NAME}']/*[boolean(@image) and boolean(@replicas)]\"\nBUNDLE_CONTAINER_ENGINE=$(cibadmin -Q | xmllint --xpath \"name(${bundle_def_xpath})\" -)\nBUNDLE_REPLICAS=$(cibadmin -Q | xmllint --xpath \"string(${bundle_def_xpath}/@replicas)\" -)\n\n\n# The wait algorithm follows a two-stage approach\n#  1. Depending on how the script is called, we first check whether\n#     the resource is restarted locally. An A/P resource may be\n#     restarted elsewhere in the cluster.\n#  2. If needed, check whether the A/P resource has restarted\n#     elsewhere. For A/P M/S resources, in case the resource is\n#     restarted as Slave locally, ensure a Master is available.\n\nsuccess=1\nbailout=1\ntimeout=$TIMEOUT\nrole=\"\"\n\n# Stage 1: local check\nif [ -n \"$ROLE_LOCAL\" ]; then\n    log \"Waiting until ${NAME} has restarted on ${HOST} and is in state ${ROLE_LOCAL}\"\n    log \"Will probe resource state with the following XPath pattern: ${local_resource_xpath}\"\n\n    while [ $timeout -gt 0 ] && [ $bailout -ne 0 ] && [ $success -ne 0 ]; do\n        resource=$(crm_mon -r --as-xml | xmllint --xpath \"${local_resource_xpath}\" - 2>/dev/null)\n        role=$(echo \"${resource}\" | sed -ne 's/.*\\Wrole=\"\\([^\"]*\\)\".*/\\1/p')\n\n\tif [ \"$(crm_resource --meta -r ${NAME} -g is-managed 2>/dev/null)\" = \"false\" ]; then\n            log \"${NAME} is unmanaged, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif [ \"$(crm_resource --meta -r ${NAME} -g target-role 2>/dev/null)\" = \"Stopped\" ]; then\n            log \"${NAME} is disabled, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif echo \"${resource}\" | grep -q -w \"\\Wblocked=\\\"true\\\"\"; then\n            log \"${NAME} is blocked, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif did_resource_failed_locally; then\n            log \"${NAME} is in failed state, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif [ \"$role\" = \"$ROLE_LOCAL\" ]; then\n            success=0\n            continue\n        elif [ -n \"$ROLE_ANYWHERE\" ] && [ \"$role\" = \"$ROLE_ANYWHERE\" ]; then\n            # A/P: we are restarted in the expected state\n            success=0\n            continue\n        else\n            log \"Waiting for ${NAME} to transition to role ${ROLE_LOCAL} on ${HOST}\"\n        fi\n\n        if [ $bailout -ne 0 ] && [ $success -ne 0 ]; then\n            sleep 4\n            timeout=$((timeout-4))\n        fi\n    done\nfi\n\n# Stage 2: global check\nif [ $timeout -gt 0 ] && [ -n \"$ROLE_ANYWHERE\" ] && [ \"$role\" != \"$ROLE_ANYWHERE\" ]; then\n    log \"Wait until ${NAME} is restarted anywhere in the cluster in state ${ROLE_ANYWHERE}\"\n    log \"Will probe resource state with the following XPath pattern: ${any_resource_xpath}\"\n\n    success=1\n    bailout=1\n    while [ $timeout -gt 0 ] && [ $bailout -ne 0 ] && [ $success -ne 0 ]; do\n        resources=$(crm_mon -r --as-xml | xmllint --xpath \"${any_resource_xpath}\" - 2>/dev/null)\n\tif [ \"$(crm_resource --meta -r ${NAME} -g is-managed 2>/dev/null)\" = \"false\" ]; then\n            log \"${NAME} is unmanaged, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif [ \"$(crm_resource --meta -r ${NAME} -g target-role 2>/dev/null)\" = \"Stopped\" ]; then\n            log \"${NAME} is disabled, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif ! (echo \"${resources}\" | grep -q -w \"\\Wblocked=\\\"false\\\"\"); then\n            log \"${NAME} blocked, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif did_resource_failed_globally; then\n            log \"${NAME} is in failed state, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif echo \"${resources}\" | grep -q -w \"\\Wrole=\\\"${ROLE_ANYWHERE}\\\"\"; then\n            success=0\n            continue\n        else\n            log \"Waiting for ${NAME} to transition to role ${ROLE_ANYWHERE} anywhere in the cluster\"\n        fi\n\n        if [ $bailout -ne 0 ] && [ $success -ne 0 ]; then\n            sleep 4\n            timeout=$((timeout-4))\n        fi\n    done\nfi\n\nif [ $timeout -le 0 ]; then\n    log \"Timeout reached after ${TIMEOUT}s while waiting for ${NAME} to be restarted\"\nelif [ $bailout -le 0 ]; then\n    log \"Restart monitoring for ${NAME} cancelled\"\nfi\n\nif [ $success -eq 0 ]; then\n    log \"${NAME} successfully restarted\"\nelse\n    log \"${NAME} was not restarted properly\"\nfi\n\n# Don't block minor update or stack update if the wait was unsuccessful\nexit 0\n"}, "wait-port-and-run.sh": {"mode": "0755", "content": "#!/usr/bin/bash\nset -eu\n\nHOST=$1\nPORT=$2\n\necho \"$(date -u): Checking whether we can bind to ${HOST}:${PORT}\"\nwhile (ss -Htnl src \"${HOST}\" \"sport = :${PORT}\" | grep -wq \"${PORT}\"); do\n    echo \"$(date -u): ${HOST}:${PORT} still in use, waiting...\";\n    sleep 10;\ndone\n\nshift 2\nCOMMAND=\"$*\"\nif [ -z \"${COMMAND}\" ]; then\n    COMMAND=\"true\"\nfi\nexec $COMMAND\n"}, "pacemaker_resource_lock.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nMAX_RETRIES=10\nCIB_ENOTFOUND=105\n\nusage() {\n   echo \"Set a global property in the cluster with a validity timestamp.\"\n   echo \"Usage:\"\n   echo \"   $0 --acquire <lock_name> <lock_owner> <lock_ttl_in_seconds>\"\n   echo \"   $0 --release <lock_name> <lock_owner>\"\n   echo\n}\n\nlog() {\n    echo \"$(date -u): $1\" 1>&2\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\nlock_create() {\n    local name=$1\n    local data=$2\n    # cibadmin won't overwrite a key if someone else succeeded to create it concurrently\n    cibadmin --sync-call --scope crm_config --create --xml-text \"<cluster_property_set id='${name}'><nvpair id='${name}-pair' name='${name}' value='${data}'/></cluster_property_set>\" &>/dev/null\n    return $?\n}\n\nlock_update() {\n    local name=$1\n    local expected_data=$2\n    local new_data=$3\n    # we only update the lock we expect to see, so we can't update someone else's lock\n    cibadmin --sync-call --scope crm_config --modify --xpath \"//cluster_property_set/nvpair[@name='${name}' and @value='${expected_data}']/..\" --xml-text \"<nvpair id='${name}-pair' name='${name}' value='${new_data}'/>\" &>/dev/null\n    return $?\n}\n\nlock_delete() {\n    local name=$1\n    local expected_data=$2\n    # we only delete the lock we expect to see, so we can't delete someone else's lock\n    cibadmin --sync-call --scope crm_config --delete --xpath \"//cluster_property_set/nvpair[@name='${name}' and @value='${expected_data}']/..\" &>/dev/null\n    return $?\n}\n\nlock_get() {\n    local lockname=$1\n    local res\n    local rc\n    res=$(cibadmin --query --scope crm_config --xpath \"//cluster_property_set/nvpair[@name='$lockname']\" 2>/dev/null)\n    rc=$?\n    if [ $rc -eq 0 ]; then\n        echo \"$res\" | sed -n 's/.*value=\"\\([^\"]*\\)\".*/\\1/p'\n    fi\n    return $rc\n}\n\nlock_owner() {\n    local lock=$1\n    echo \"$lock\" | cut -d':' -f1\n}\n\nlock_has_expired() {\n    local lock=$1\n    local expiry=$(echo \"$lock\" | cut -d':' -f2)\n    local now=$(date +%s)\n    test $now -ge $expiry\n}\n\n\n# Perform a lock action and restart if the CIB has been modified before\n# committing the lock action\ntry_action() {\n    local fun=$1\n    local lock=$2\n    local requester=$3\n    local args=${4:-}\n    local tries=$MAX_RETRIES\n    local rc=1\n    if [ \"$fun\" = \"lock_acquire\" ] || [ \"$fun\" = \"lock_release\" ]; then\n        log \"Try running $fun\"\n    else\n        return 2\n    fi\n    while [ $rc -ne 0 ]; do\n        $fun $lock $requester $args\n        rc=$?\n        if [ $rc -eq 0 ]; then\n            log \"Operation $1 succeeded\"\n            return 0\n        elif [ $rc -eq 3 ]; then\n            # rc == 3 -> CIB changed before push\n            if [ $tries -eq 0 ]; then\n                log \"Failed to commit after $MAX_RETRIES retries. Bailing out.\"\n                return 2\n            else\n                log \"Failed to commit. Retrying operation.\"\n                tries=$(($tries - 1))\n            fi\n        elif [ $rc -eq 2 ]; then\n            # rc == 2 -> unrecoverable cib error (e.g. pacemaker down)\n            log \"Unexpected failure. Bailing out\"\n            return $rc\n        else\n            # rc == 1 -> lock error (not owner, lock doesn't exists)\n            return $rc\n        fi\n    done\n}\n\n# The lock mechanism uses cibadmin's atomic creation so cluster-wide\n# state coherency is guaranteed by pacemaker\nlock_acquire() {\n    local lockname=$1\n    local requester=$2\n    local ttl=$3\n    local rc\n    local lock\n    local expiry\n    local owner\n\n    log \"Check whether the lock is already held in the CIB\"\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        log \"Could not retrieve info from the CIB\"\n        return 2\n    fi\n\n    if [ -n \"$lock\" ]; then\n        lock_has_expired $lock\n        rc=$?\n        if [ $rc -eq 0 ]; then\n            log \"Lock has expired, now available for being held\"\n        else\n            # lock is still held. check whether we're the owner\n            owner=$(lock_owner $lock)\n            if [ \"$owner\" = \"$requester\" ];then\n                log \"Requester already owns the lock, acquiring attempt will just reconfigure the TTL\"\n            else\n                log \"Lock is held by someone else ($owner)\"\n                return 1\n            fi\n        fi\n    else\n        log \"Lock is not held yet\"\n    fi\n\n    # prepare the lock info\n    expiry=$(($(date +%s) + $ttl))\n\n    if [ -n \"$lock\" ]; then\n        log \"Attempting to update the lock\"\n        lock_update $lockname \"$lock\" \"$requester:$expiry\"\n        rc=$?\n    else\n        log \"Attempting to acquire the lock\"\n        lock_create $lockname \"$requester:$expiry\"\n        rc=$?\n    fi\n\n    if [ $rc -eq 0 ]; then\n        log \"Lock '$lockname' acquired by '$requester', valid until $(date -d @$expiry)\"\n        return 0\n    else\n        log \"CIB changed, lock cannot be acquired\"\n        return 3\n    fi\n}\n\n\n# The lock mechanism uses the CIB's num_updates tag to implement\n# a conditional store. Cluster-wide locking is guaranteed by pacemaker\nlock_release() {\n    local lockname=$1\n    local requester=$2\n    local rc\n    local lock\n    local owner\n\n    log \"Check whether the lock is already held in the CIB\"\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        log \"Could not retrieve info from the CIB\"\n        return 2\n    fi\n\n    if [ -z \"$lock\" ]; then\n        log \"Lock doesn't exist. Nothing to release\"\n        return 0\n    else\n        log \"Lock exists, check whether we're the owner\"\n        owner=$(lock_owner $lock)\n        if [ \"$owner\" != \"$requester\" ];then\n            log \"Lock is held by someone else ($owner), will not unlock\"\n            return 1\n        fi\n    fi\n\n    lock_delete $lockname \"$lock\"\n    rc=$?\n\n    if [ $rc -eq 0 ]; then\n        log \"Lock '$lockname' released by '$requester'\"\n        return 0\n    else\n        log \"CIB deletion error, lock cannot be released\"\n        return 3\n    fi\n}\n\n\n# Retrieve the owner of a lock from the CIB\n# this is a read-only operation, so no need to log debug info\nlock_get_owner() {\n    local lockname=$1\n    local rc\n    local lock\n    local owner\n\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        return 2\n    fi\n\n    if [ -z \"$lock\" ]; then\n        return 1\n    else\n        lock_owner $lock\n        return 0\n    fi\n}\n\n\nACTION=$1\nLOCKNAME=$2\nREQUESTER=$3\nTTL=${4:-60}\n\nif [ -z \"$ACTION\" ]; then\n    error \"Action must be specified\"\nfi\n\nif [ $ACTION != \"--help\" ]; then\n    if [ -z \"$LOCKNAME\" ]; then\n        error \"You must specific a lock name\"\n    fi\n    if [ $ACTION != \"--owner\" ] && [ $ACTION != \"-o\" ]; then\n        if [ -z \"$REQUESTER\" ]; then\n            error \"You must specific a lock requester\"\n        fi\n    fi\nfi\n\ncase $ACTION in\n    --help) usage; exit 0;;\n    --acquire|-a) try_action lock_acquire $LOCKNAME $REQUESTER $TTL;;\n    --release|-r) try_action lock_release $LOCKNAME $REQUESTER;;\n    --acquire-once|-A) lock_acquire $LOCKNAME $REQUESTER $TTL;;\n    --owner|-o) lock_get_owner $LOCKNAME;;\n    *) error \"Invalid action\";;\nesac\nexit $?\n"}, "pacemaker_mutex_restart_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# pacemaker_mutex_restart_bundle.sh --lock mysql galera galera-bundle Master _\n# pacemaker_mutex_restart_bundle.sh --lock ovn_dbs ovndb_servers ovn-dbs-bundle Slave Master\n\nset -u\n\nusage() {\n    echo \"Restart a clustered resource in a coordinated way across the cluster\"\n    echo \"Usage:\"\n    echo \"   $0 --lock <tripleo-service> <pcmk-resource> <pcmk-bundle> <target-state-local> <target-state-cluster>\"\n    echo\n}\n\nlog() {\n    echo \"$(date -u): $1\"\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\npacemaker_supports_promoted() {\n    # The Promoted token is only matched in recent pacemaker versions\n    grep -wq \"<value>Promoted</value>\" /usr/share/pacemaker/resources-*.rng\n}\n\nACTION=$1\ncase $ACTION in\n    --help) usage; exit 0;;\n    --lock) ;;\n    *) error \"Unknown action '$ACTION'\";;\nesac\n\nTRIPLEO_SERVICE=$2\nLOCK_NAME=${TRIPLEO_SERVICE}-restart-lock\nLOCK_OWNER=$(crm_node -n 2>/dev/null)\nrc=$?\nif [ $rc -ne 0 ]; then\n    if [ $rc -eq 102 ]; then\n        log \"Cluster is not running locally, no need to restart resource $TRIPLEO_SERVICE\"\n        exit 0\n    else\n        error \"Unexpected error while connecting to the cluster (rc: $rc), bailing out\"\n    fi\nfi\n\nRESOURCE_NAME=$3\nBUNDLE_NAME=$4\nWAIT_TARGET_LOCAL=$5\nWAIT_TARGET_ANYWHERE=${6:-_}\n\nif pacemaker_supports_promoted; then\n    WAIT_TARGET_LOCAL=$(echo \"$5\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    WAIT_TARGET_ANYWHERE=$(echo \"${6:-_}\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    promoted_role=\"Promoted\"\nelse\n    promoted_role=\"Master\"\nfi\n\n# The lock TTL should accomodate for the resource start/promote timeout\nif [ \"$RESOURCE_NAME\" != \"$BUNDLE_NAME\" ]; then\n    if [ \"$WAIT_TARGET_LOCAL\" = \"$promoted_role\" ] || [ \"$WAIT_TARGET_ANYWHERE\" = \"$promoted_role\" ]; then\n        rsc_op=\"promote\"\n    else\n        rsc_op=\"start\"\n    fi\n    # <op id=\"galera-promote-interval-0s\" interval=\"0s\" name=\"promote\" on-fail=\"block\" timeout=\"300s\"/>\n    PCMK_TTL=$(cibadmin -Q | xmllint -xpath \"string(//primitive[@id='${RESOURCE_NAME}']/operations/op[@name='${rsc_op}']/@timeout)\" - | sed 's/s$//')\n    LOCK_TTL=$((PCMK_TTL + 30))\nelse\n    # The podman RA's default start timeout\n    LOCK_TTL=90\nfi\n\nlog \"Acquire a ${LOCK_TTL}s restart lock for service $TRIPLEO_SERVICE before restarting it\"\n# Loop until we hold the lock. The lock has a TTL, so we're guaranteed to get it eventually\nrc=1\nwhile [ $rc -ne 0 ]; do\n    /var/lib/container-config-scripts/pacemaker_resource_lock.sh --acquire $LOCK_NAME $LOCK_OWNER $LOCK_TTL\n    rc=$?\n    if [ $rc != 0 ]; then\n        if [ $rc -gt 1 ]; then\n            error \"Could not acquire lock due to unrecoverable error (rc: $rc), bailing out\"\n        else\n            log \"Could not acquire lock, retrying\"\n            sleep 10\n        fi\n    fi\ndone\n\nlog \"Restart the service $TRIPLEO_SERVICE locally\"\n# Reuse the local restart script in t-h-t (driven by env var TRIPLEO_MINOR_UPDATE)\nTRIPLEO_MINOR_UPDATE=true /var/lib/container-config-scripts/pacemaker_restart_bundle.sh $TRIPLEO_SERVICE $RESOURCE_NAME $BUNDLE_NAME $WAIT_TARGET_LOCAL $WAIT_TARGET_ANYWHERE\n\n# If we reached this point, always try to release the lock\nlog \"Release the restart lock for service $TRIPLEO_SERVICE\"\n/var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $LOCK_NAME $LOCK_OWNER\nrc=$?\nif [ $rc -ne 0 ] && [ $rc -ne 1 ]; then\n    error \"Could not release held lock (rc: $rc)\"\nfi\n"}, "pacemaker_mutex_shutdown.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# pacemaker_mutex_shutdown.sh --acquire\n# pacemaker_mutex_shutdown.sh --release\n\nset -u\n\nusage() {\n    echo \"Shutdown a cluster node in a coordinated way across the cluster\"\n    echo \"Usage:\"\n    echo \"   $0 --acquire # prevent other node from shutting down until we hold the lock\"\n    echo \"   $0 --release # release the lock, other node can compete for the shutdown lock\"\n    echo\n}\n\nlog() {\n    echo \"$(date -u): $1\"\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\n# Loop until we hold the lock. The lock has a TTL, so we're guaranteed to get it eventually\nshutdown_lock_acquire() {\n    local lockname=$1\n    local requester=$2\n    local ttl=$3\n    local rc=1\n    local current_owner\n    local owner_stopped\n    local owner_rc\n\n    log \"Acquiring the shutdown lock\"\n    while [ $rc -ne 0 ]; do\n        /var/lib/container-config-scripts/pacemaker_resource_lock.sh --acquire-once $lockname $requester $ttl\n        rc=$?\n        if [ $rc -ne 0 ]; then\n            if [ $rc -eq 2 ]; then\n                error \"Could not acquire the shutdown lock due to unrecoverable error (rc: $rc), bailing out\"\n            else\n                # The lock is held by another node.\n                current_owner=$(/var/lib/container-config-scripts/pacemaker_resource_lock.sh --owner $lockname)\n                owner_rc=$?\n                if [ $owner_rc -eq 2 ]; then\n                    error \"Could not get the shutdown lock owner due to unrecoverable error (rc: $owner_rc), bailing out\"\n                fi\n                if [ $owner_rc -eq 0 ]; then\n                    # If the owner is marked as offline, that means it has shutdown and\n                    # we can clean the lock preemptively and try to acquire it.\n                    owner_stopped=$(crm_mon -1X | xmllint --xpath 'count(//nodes/node[@name=\"'${current_owner}'\" and @online=\"false\" and @unclean=\"false\"])' -)\n                    if [ \"${owner_stopped}\" = \"1\" ]; then\n                        log \"Shutdown lock held by stopped node '${current_owner}', lock can be released\"\n                        /var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $lockname $current_owner\n                        continue\n                    fi\n                fi\n                log \"Shutdown lock held by another node (rc: $rc), retrying\"\n                sleep 10\n            fi\n        fi\n    done\n    log \"Shutdown lock acquired\"\n    return 0\n}\n\n\n# Release the lock if we still own it. Not owning it anymore is not fatal\nshutdown_lock_release() {\n    local lockname=$1\n    local requester=$2\n    local rc\n\n    log \"Releasing the shutdown lock\"\n    /var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $lockname $requester\n    rc=$?\n    if [ $rc -ne 0 ]; then\n        if [ $rc -gt 1 ]; then\n            error \"Could not release the shutdown lock due to unrecoverable error (rc: $rc), bailing out\"\n        else\n            log \"Shutdown lock no longer held, nothing to do\"\n        fi\n    else\n        log \"Shutdown lock released\"\n    fi\n    return 0\n}\n\n\nACTION=$1\nif [ -z \"$ACTION\" ]; then\n    error \"Action must be specified\"\nfi\n\nLOCK_NAME=tripleo-shutdown-lock\nLOCK_OWNER=$(crm_node -n 2>/dev/null)\nrc=$?\nif [ $rc -ne 0 ]; then\n    if [ $rc -eq 102 ]; then\n        log \"Cluster is not running locally, no need to aquire the shutdown lock\"\n        exit 0\n    else\n        error \"Unexpected error while connecting to the cluster (rc: $rc), bailing out\"\n    fi\nfi\n\n# We start with a very high TTL, that long enough to accomodate a cluster stop.\n# As soon as the node will get offline, the other competing node will be entitled\n# to steal the lock, so they should never wait that long in practice.\nLOCK_TTL=600\n\n\ncase $ACTION in\n    --help) usage; exit 0;;\n    --acquire|-a) shutdown_lock_acquire ${LOCK_NAME} ${LOCK_OWNER} ${LOCK_TTL};;\n    --release|-r) shutdown_lock_release ${LOCK_NAME} ${LOCK_OWNER};;\n    *) error \"Invalid action\";;\nesac\nexit $?\n"}, "nova_statedir_ownership.py": {"mode": "0700", "content": "#!/usr/bin/python3\n#\n# Copyright 2018 Red Hat Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\nimport logging\nimport os\nimport pwd\nimport selinux\nimport stat\nimport sys\n\ndebug = os.getenv('__OS_DEBUG', 'false')\n\nif debug.lower() == 'true':\n    loglevel = logging.DEBUG\nelse:\n    loglevel = logging.INFO\n\nlogging.basicConfig(stream=sys.stdout, level=loglevel)\nLOG = logging.getLogger('nova_statedir')\n\n\nclass PathManager(object):\n    \"\"\"Helper class to manipulate ownership of a given path\"\"\"\n    def __init__(self, path):\n        self.path = path\n        self.uid = None\n        self.gid = None\n        self.is_dir = None\n        self.secontext = None\n        self._update()\n\n    def _update(self):\n        try:\n            statinfo = os.stat(self.path)\n            self.is_dir = stat.S_ISDIR(statinfo.st_mode)\n            self.uid = statinfo.st_uid\n            self.gid = statinfo.st_gid\n            self.secontext = selinux.lgetfilecon(self.path)[1]\n        except Exception:\n            LOG.exception('Could not update metadata for %s', self.path)\n            raise\n\n    def __str__(self):\n        return \"uid: {} gid: {} path: {}{}\".format(\n            self.uid,\n            self.gid,\n            self.path,\n            '/' if self.is_dir else ''\n        )\n\n    def has_owner(self, uid, gid):\n        return self.uid == uid and self.gid == gid\n\n    def has_either(self, uid, gid):\n        return self.uid == uid or self.gid == gid\n\n    def chown(self, uid, gid):\n        target_uid = -1\n        target_gid = -1\n        if self.uid != uid:\n            target_uid = uid\n        if self.gid != gid:\n            target_gid = gid\n        if (target_uid, target_gid) != (-1, -1):\n            LOG.info('Changing ownership of %s from %d:%d to %d:%d',\n                     self.path,\n                     self.uid,\n                     self.gid,\n                     self.uid if target_uid == -1 else target_uid,\n                     self.gid if target_gid == -1 else target_gid)\n            try:\n                os.chown(self.path, target_uid, target_gid)\n                self._update()\n            except Exception:\n                LOG.exception('Could not change ownership of %s: ',\n                              self.path)\n                raise\n        else:\n            LOG.info('Ownership of %s already %d:%d',\n                     self.path,\n                     uid,\n                     gid)\n\n    def chcon(self, context):\n        # If dir returns whether to recusively set context\n        try:\n            try:\n                selinux.lsetfilecon(self.path, context)\n                LOG.info('Setting selinux context of %s to %s',\n                     self.path, context)\n                return True\n            except OSError as e:\n                if self.is_dir and e.errno == 95:\n                    # Operation not supported, assume NFS mount and skip\n                    LOG.info('Setting selinux context not supported for %s',\n                             self.path)\n                    return False\n                else:\n                    raise\n        except Exception:\n            LOG.exception('Could not set selinux context of %s to %s:',\n                          self.path, context)\n            raise\n\n\nclass NovaStatedirOwnershipManager(object):\n    \"\"\"Class to manipulate the ownership of the nova statedir (/var/lib/nova).\n\n       The nova uid/gid differ on the host and container images. An upgrade\n       that switches from host systemd services to docker requires a change in\n       ownership. Previously this was a naive recursive chown, however this\n       causes issues if nova instance are shared via an NFS mount: any open\n       filehandles in qemu/libvirt fail with an I/O error (LP1778465).\n\n       Instead the upgrade/FFU ansible tasks now lay down a marker file when\n       stopping and disabling the host systemd services. We use this file to\n       determine the host nova uid/gid. We then walk the tree and update any\n       files that have the host uid/gid to the docker nova uid/gid. As files\n       owned by root/qemu etc... are ignored this avoids the issues with open\n       filehandles. The marker is removed once the tree has been walked.\n\n       For subsequent runs, or for a new deployment, we simply ensure that the\n       docker nova user/group owns all directories. This is required as the\n       directories are created with root ownership in host_prep_tasks (the\n       docker nova uid/gid is not known in this context).\n    \"\"\"\n    def __init__(self, statedir, upgrade_marker='upgrade_marker',\n                 nova_user='nova', secontext_marker='../_nova_secontext',\n                 exclude_paths=None):\n        self.statedir = statedir\n        self.nova_user = nova_user\n\n        self.upgrade_marker_path = os.path.join(statedir, upgrade_marker)\n        self.secontext_marker_path = os.path.normpath(os.path.join(statedir, secontext_marker))\n        self.upgrade = os.path.exists(self.upgrade_marker_path)\n\n        self.exclude_paths = [self.upgrade_marker_path]\n        if exclude_paths is not None:\n            for p in exclude_paths:\n                if not p.startswith(os.path.sep):\n                    p = os.path.join(self.statedir, p)\n                self.exclude_paths.append(p)\n\n        self.target_uid, self.target_gid = self._get_nova_ids()\n        self.previous_uid, self.previous_gid = self._get_previous_nova_ids()\n        self.id_change = (self.target_uid, self.target_gid) != \\\n            (self.previous_uid, self.previous_gid)\n        self.target_secontext = self._get_secontext()\n\n    def _get_nova_ids(self):\n        nova_uid, nova_gid = pwd.getpwnam(self.nova_user)[2:4]\n        return nova_uid, nova_gid\n\n    def _get_previous_nova_ids(self):\n        if self.upgrade:\n            statinfo = os.stat(self.upgrade_marker_path)\n            return statinfo.st_uid, statinfo.st_gid\n        else:\n            return self._get_nova_ids()\n\n    def _get_secontext(self):\n        if os.path.exists(self.secontext_marker_path):\n            return selinux.lgetfilecon(self.secontext_marker_path)[1]\n        else:\n            return None\n\n    def _walk(self, top, chcon=True):\n        for f in os.listdir(top):\n            pathname = os.path.join(top, f)\n\n            if pathname in self.exclude_paths:\n                continue\n\n            try:\n                pathinfo = PathManager(pathname)\n                LOG.info(\"Checking %s\", pathinfo)\n                if pathinfo.is_dir:\n                    # Always chown the directories\n                    pathinfo.chown(self.target_uid, self.target_gid)\n                    chcon_r = chcon\n                    if chcon:\n                        chcon_r = pathinfo.chcon(self.target_secontext)\n                    self._walk(pathname, chcon_r)\n                elif self.id_change:\n                    # Only chown files if it's an upgrade and the file is owned by\n                    # the host nova uid/gid\n                    pathinfo.chown(\n                        self.target_uid if pathinfo.uid == self.previous_uid\n                        else pathinfo.uid,\n                        self.target_gid if pathinfo.gid == self.previous_gid\n                        else pathinfo.gid\n                    )\n                    if chcon:\n                        pathinfo.chcon(self.target_secontext)\n            except Exception:\n                # Likely to have been caused by external systems\n                # interacting with this directory tree,\n                # especially on NFS e.g snapshot dirs.\n                # Just ignore it and continue on to the next entry\n                continue\n\n    def run(self):\n        LOG.info('Applying nova statedir ownership')\n        LOG.info('Target ownership for %s: %d:%d',\n                 self.statedir,\n                 self.target_uid,\n                 self.target_gid)\n\n        pathinfo = PathManager(self.statedir)\n        LOG.info(\"Checking %s\", pathinfo)\n        pathinfo.chown(self.target_uid, self.target_gid)\n        chcon = self.target_secontext is not None\n\n        if chcon:\n            pathinfo.chcon(self.target_secontext)\n\n        self._walk(self.statedir, chcon)\n\n        if self.upgrade:\n            LOG.info('Removing upgrade_marker %s',\n                     self.upgrade_marker_path)\n            os.unlink(self.upgrade_marker_path)\n\n        LOG.info('Nova statedir ownership complete')\n\n\ndef get_exclude_paths():\n    exclude_paths = os.environ.get('NOVA_STATEDIR_OWNERSHIP_SKIP')\n    if exclude_paths is not None:\n        exclude_paths = exclude_paths.split(os.pathsep)\n    return exclude_paths\n\n\nif __name__ == '__main__':\n    NovaStatedirOwnershipManager('/var/lib/nova', exclude_paths=get_exclude_paths()).run()\n"}, "nova_wait_for_compute_service.py": {"mode": "0755", "content": "#!/usr/bin/python3\n#\n# Copyright 2018 Red Hat Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\nimport argparse\nimport logging\nimport os\nimport six\nimport socket\nimport sys\nimport time\n\n\nfrom keystoneauth1 import loading\nfrom keystoneauth1 import session\n\nfrom novaclient import client\n\n# In python3 SafeConfigParser was renamed to ConfigParser and the default\n# for duplicate options default to true. In case of nova it is valid to\n# have duplicate option lines, e.g. passthrough_whitelist which leads to\n# issues reading the nova.conf\n# https://bugs.launchpad.net/tripleo/+bug/1827775\nif six.PY3:\n    from six.moves.configparser import ConfigParser\n    config = ConfigParser(strict=False)\nelse:\n    from six.moves.configparser import SafeConfigParser\n    config = SafeConfigParser()\n\ndebug = os.getenv('__OS_DEBUG', 'false')\n\nif debug.lower() == 'true':\n    loglevel = logging.DEBUG\nelse:\n    loglevel = logging.INFO\n\nlogging.basicConfig(stream=sys.stdout, level=loglevel)\nLOG = logging.getLogger('nova_wait_for_compute_service')\n\niterations = 60\ntimeout = 10\nnova_cfg = '/etc/nova/nova.conf'\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser(usage='%(prog)s [options]')\n    parser.add_argument('-k', '--insecure',\n                        action=\"store_false\",\n                        dest='insecure',\n                        default=True,\n                        help='Allow insecure connection when using SSL')\n\n    args = parser.parse_args()\n    LOG.debug('Running with parameter insecure = %s',\n              args.insecure)\n\n    if os.path.isfile(nova_cfg):\n        try:\n            config.read(nova_cfg)\n        except Exception:\n            LOG.exception('Error while reading nova.conf:')\n    else:\n        LOG.error('Nova configuration file %s does not exist', nova_cfg)\n        sys.exit(1)\n\n    my_host = config.get('DEFAULT', 'host')\n    if not my_host:\n        # If host isn't set nova defaults to this\n        my_host = socket.gethostname()\n\n    loader = loading.get_plugin_loader('password')\n    auth = loader.load_from_options(\n        auth_url=config.get('neutron',\n                            'auth_url'),\n        username=config.get('neutron',\n                            'username'),\n        password=config.get('neutron',\n                            'password'),\n        project_name=config.get('neutron',\n                                'project_name'),\n        project_domain_name=config.get('neutron',\n                                       'project_domain_name'),\n        user_domain_name=config.get('neutron',\n                                    'user_domain_name'))\n    sess = session.Session(auth=auth, verify=args.insecure)\n    nova = client.Client('2.11', session=sess, endpoint_type='internal',\n                         region_name=config.get('neutron', 'region_name'))\n\n    # Wait until this host is listed in the service list\n    for i in range(iterations):\n        try:\n            service_list = nova.services.list(binary='nova-compute')\n            for entry in service_list:\n                host = getattr(entry, 'host', '')\n                zone = getattr(entry, 'zone', '')\n                if host == my_host and zone != 'internal':\n                    LOG.info('Nova-compute service registered')\n                    sys.exit(0)\n            LOG.info('Waiting for nova-compute service to register')\n        except Exception:\n            LOG.exception(\n                'Error while waiting for nova-compute service to register')\n        time.sleep(timeout)\nsys.exit(1)\n\n# vim: set et ts=4 sw=4 :\n"}}, "tuple:('role_data', 'service_name')": "nova_compute", "tuple:('role_data', 'config_settings')": {"nova::my_ip": "%{hiera('internal_api')}", "nova::rabbit_use_ssl": "False", "nova::keystone::service_user::send_service_user_token": true, "nova::keystone::service_user::project_name": "service", "nova::keystone::service_user::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::keystone::service_user::auth_url": "http://172.17.0.2:5000", "nova::keystone::service_user::region_name": "regionOne", "nova::placement::project_name": "service", "nova::placement::password": "dYVRSnGa4R5DjmK0t4f9aWqpK", "nova::placement::auth_url": "http://172.17.0.2:5000", "nova::placement::region_name": "regionOne", "nova::placement::valid_interfaces": "internal", "nova::os_region_name": "regionOne", "nova::logging::debug": true, "nova::purge_config": false, "nova::network::neutron::project_name": "service", "nova::network::neutron::username": "neutron", "nova::network::neutron::region_name": "regionOne", "nova::dhcp_domain": "", "nova::network::neutron::password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "nova::network::neutron::auth_url": "http://172.17.0.2:5000/v3", "nova::network::neutron::valid_interfaces": "internal", "nova::glance::valid_interfaces": "internal", "nova::rabbit_heartbeat_timeout_threshold": 60, "nova::cinder_catalog_info": "volumev3:cinderv3:internalURL", "nova::host": "%{hiera('fqdn_canonical')}", "nova::notify_on_state_change": "vm_and_task_state", "nova::notification_driver": ["messagingv2"], "nova::notification_format": "unversioned", "nova::network::neutron::auth_type": "v3password", "nova::db::database_db_max_retries": -1, "nova::db::database_max_retries": -1, "nova::network::neutron::ovs_bridge": "br-int", "nova::compute::sync_power_state_interval": 600, "nova_is_additional_cell": false, "nova::cross_az_attach": true, "nova::cache::enabled": true, "nova::cache::tls_enabled": false, "nova::cache::backend": "dogpile.cache.memcached", "nova::rabbit_heartbeat_in_pthread": false, "nova::ovsdb_connection": "", "nova::compute::vcpu_pin_set": [], "nova::compute::cpu_shared_set": [], "nova::compute::cpu_dedicated_set": [], "nova::compute::reserved_host_memory": 512, "nova::compute::reserved_huge_pages": [], "nova::compute::neutron_physnets_numa_nodes_mapping": {}, "nova::compute::neutron_tunnel_numa_nodes": [], "nova::compute::resume_guests_state_on_host_boot": false, "nova::compute::libvirt::rx_queue_size": 512, "nova::compute::libvirt::tx_queue_size": 512, "nova::compute::libvirt::file_backed_memory": 0, "nova::compute::libvirt::volume_use_multipath": false, "nova::compute::libvirt::hw_machine_type": "x86_64=pc-q35-rhel9.0.0", "nova::compute::mkisofs_cmd": "mkisofs", "compute_enable_ksm": false, "nova::compute::rbd::libvirt_images_rbd_pool": "vms", "tripleo::profile::base::nova::compute::nova_nfs_enabled": false, "nfs_backend_enable": false, "nfs_share": "", "nfs_options": "context=system_u:object_r:nfs_t:s0", "nfs_vers": "4.2", "nova::compute::libvirt::num_pcie_ports": 16, "nova::compute::libvirt::mem_stats_period_seconds": 10, "nova::compute::rbd::ephemeral_storage": true, "resume_guests_state_on_host_boot": false, "nova::cpu_allocation_ratio": 0.0, "nova::ram_allocation_ratio": 1.0, "nova::disk_allocation_ratio": 0.0, "nova::compute::max_disk_devices_to_attach": -1, "nova::compute::libvirt::pmem_namespaces": "", "nova_pmem_namespaces": "", "nova::compute::image_cache::remove_unused_original_minimum_age_seconds": 86400, "nova::compute::libvirt::swtpm_enabled": false, "nova::compute::vgpu::vgpu_types_device_addresses_mapping": {}, "compute_disable_irqbalance": false, "nova::compute::libvirt::cpu_mode": "host-model", "nova::compute::libvirt::cpu_models": [], "nova::compute::libvirt::cpu_model_extra_flags": "", "nova_compute_opt_volumes": [], "nova_compute_startup_delay": 0, "nova_compute_opt_env_vars": {}, "nova::workarounds::never_download_image_if_on_rbd": false, "nova::compute::image_type_exclude_list": [], "nova_permit_post_copy": true, "nova_permit_auto_converge": true, "nova_libvirt_max_queues": 0, "nova_glance_enable_rbd_download": false, "nova_glance_rbd_download_multistore_id": "", "nova::compute::force_raw_images": true, "nova::compute::use_cow_images": true, "nova::compute::libvirt::preallocate_images": "none", "nova::compute::image_cache::manager_interval": 2400, "nova::compute::image_cache::remove_unused_base_images": true, "nova::compute::image_cache::remove_unused_resized_minimum_age_seconds": 3600, "nova::compute::image_cache::precache_concurrency": 1, "nova::compute::provider::custom_inventories": {}, "nova::compute::rbd::libvirt_images_rbd_glance_copy_poll_interval": 15, "nova::compute::rbd::libvirt_images_rbd_glance_copy_timeout": 600, "ContainerNovaComputeImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "ContainerNovaLibvirtConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "nova::compute::libvirt::manage_libvirt_services": false, "nova::compute::pci::passthrough": "[{\"devname\": \"dummy-dev\", \"physical_network\": \"dummy_sriov_net\"}]", "nova::compute::libvirt::migration_support": false, "tripleo::profile::base::nova::migration::client::nova_compute_enabled": true, "tripleo::profile::base::nova::migration::client::ssh_private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAzcb1z+kYP10UjkTBH4bnxvCXWz+dyTwFHtURjBt2vADgeeph\nNxBRnTe7kysE8m58KHuFJ9m5Lda/KgKrFCJtgtjfquQJzcbJ6cf4qblilLacQG34\nUqc4FLUXkSvAwIriLJX2iGDvg2ff7bAofuD5ya41OU61HEHhtZi2xLEA0I9jQlVS\n0p8PrJy8OAfMDIKQT3ORDfK2QEuLMrabug2dY2vv5b9SASjQrCB+7kYLVxSoUaUq\nociPrBn5na3NMqU+dh7r0P2mpOnQEUb4vRbw2p89Y10YdibzXVad0PbRcZjEpgQr\nNeZIbfMuFDDfSfu0pye7Vm5HzvAwtjUCMQPbBQIDAQABAoIBABA/DBTWv2fvrmBi\nt0I8J9WoexqxYoC+MPbmzy4NOqOY1VNqzAAWVSTUS9MdS2FK+plFOOJIXOFsmfn0\nIGB3k2Ch3lujCc8dFoxTK6O8YJ2DIvT6ebRbQjputCY6NEtyhToMVCmFfB0XOP70\n47P/Ir/nwokvi9POTWBFmiOo7q27vOV0Aa3tJ8DfjcDqIvQTpykQlFHvW+pZ+QhH\nWi9jGCuJP/vLletAHDttmxJ5jnB7ok2UPE/fv46OThx85LNkUmM7P+5qUAT0k2Ke\nB7Q2YSeMjFmaWqnDAq0XbnX6SZGBjIwVYCcUaFqTQdcaHfiDdZQk+4RtCdYJWU8s\n4iCM8KUCgYEA8K39Ux/JO+ut9vqmpTeunq5X4Gl2lmd5Fto1a40QcYAC2iYSwqXM\nsrldOQkWWTQXvcF5lKEDeFGDhDfXX/eMHAeQTGWvKTKun0q7SdIgD8mKHUW+yaSb\nMRMVbNZZ8MDM2mOoOXGVQMcIzEOFPr6+TbnfVu0eTHCvKyMFe/2+q5sCgYEA2uA3\nJmHmehdkX8pQJfW9O4BeJbKZ+dLuF7vI0RXcHRBQa4nOTBFAu5UpaCYMWrC+YQS/\nzWk2FWOyvGL8z5hmPUKcR69GX8vzoYrMIAIvNF5UZAoCwFTDYNYrDFEM5QPhkrln\nH86FPtay/NscrT915j0tz39SWAOBYhbhwyS4jd8CgYEAnhzPZUJmgxTrbmtv+u4/\nq0NBu83M+DX12Mt1eLhtawL73LBSdslRVsBru8J6ihOs3R4zby7wBqUWT1AYD5Wi\n1+8oHuhWUCxZh5AixfZi1bxDHcPp+LJIuc6drqiK4ZzndzktFL/Hm4yl/PsGmBfb\nEVjgnkycMP9+NEqHmdMy5a0CgYBlBEyPy2la+gbaav5YtrTyjElnbqm/8ojurT1+\num8PfuMO7tgmpWPR74LfzYewJ5iGIHIBdMiAULZCWhFCIp01MtP8BboeJnw4F14k\ne72bltmuHiys5bIStGXD1nh0DjmCxU0CEgfPO7n6F4qBryNT8vJ8rM+tTVjek574\nuK7w0wKBgATiv5ZBvdtkO8bDigFvEc9IFNPYGYG2D8JsNU2u6j3FYN/FOQD3UzEj\n/UFz30SOilehDSftmPUGBA3us2CVYA4hJ+SGT71SZeUyOqrmlZhMXGWk3FQn9l7f\n8F0ABR1Kt9K6Wa4shCRBDFgDTmIlqXBgbRTZlJ/OSNae1IBm1UBv\n-----END RSA PRIVATE KEY-----\n", "tripleo::profile::base::nova::migration::client::ssh_port": 2022, "nova::compute::rbd::libvirt_images_rbd_glance_store_name": "default_backend", "nova::compute::rbd::libvirt_images_rbd_ceph_conf": "/etc/ceph/ceph.conf", "nova::compute::rbd::libvirt_rbd_user": "openstack", "nova::compute::rbd::rbd_keyring": "client.openstack", "tripleo::profile::base::nova::compute::cinder_nfs_backend": false, "rbd_persistent_storage": true, "rbd_disk_cachemodes": ["network=writeback"], "nova::cinder::username": "cinder", "nova::cinder::auth_type": "v3password", "nova::cinder::project_name": "service", "nova::cinder::password": "oRdXUvbfKZDA6CMRoTsL6bGXm", "nova::cinder::auth_url": "http://172.17.0.2:5000/v3", "nova::cinder::region_name": "regionOne", "nova::compute::rbd::libvirt_rbd_secret_key": "AQC8YS1pAAAAABAA+BwWKS55FZMjOG5kO1Z5kw==", "nova::compute::rbd::libvirt_rbd_secret_uuid": "dc518f93-7195-5458-af10-a92142534ce2", "nova::compute::instance_usage_audit": true, "nova::compute::instance_usage_audit_period": "hour", "nova::compute::consecutive_build_service_disable_threshold": "10", "nova::compute::live_migration_wait_for_vif_plug": true, "nova::migration::libvirt::live_migration_permit_post_copy": true, "nova::migration::libvirt::live_migration_permit_auto_converge": true, "nova::migration::libvirt::live_migration_tunnelled": false, "nova::compute::vncserver_proxyclient_address": "%{hiera('internal_api')}", "nova::compute::vncproxy_host": "172.21.0.2", "nova::vncproxy::common::vncproxy_protocol": "http", "nova::vncproxy::common::vncproxy_host": "172.21.0.2", "nova::vncproxy::common::vncproxy_port": "6080", "nova::compute::verify_glance_signatures": false, "nova::workarounds::disable_compute_service_check_for_ffu": false}, "role_data": {"service_name": "nova_compute", "monitoring_subscription": "overcloud-nova-compute", "config_settings": {"nova::my_ip": "%{hiera('internal_api')}", "nova::rabbit_use_ssl": "False", "nova::keystone::service_user::send_service_user_token": true, "nova::keystone::service_user::project_name": "service", "nova::keystone::service_user::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::keystone::service_user::auth_url": "http://172.17.0.2:5000", "nova::keystone::service_user::region_name": "regionOne", "nova::placement::project_name": "service", "nova::placement::password": "dYVRSnGa4R5DjmK0t4f9aWqpK", "nova::placement::auth_url": "http://172.17.0.2:5000", "nova::placement::region_name": "regionOne", "nova::placement::valid_interfaces": "internal", "nova::os_region_name": "regionOne", "nova::logging::debug": true, "nova::purge_config": false, "nova::network::neutron::project_name": "service", "nova::network::neutron::username": "neutron", "nova::network::neutron::region_name": "regionOne", "nova::dhcp_domain": "", "nova::network::neutron::password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "nova::network::neutron::auth_url": "http://172.17.0.2:5000/v3", "nova::network::neutron::valid_interfaces": "internal", "nova::glance::valid_interfaces": "internal", "nova::rabbit_heartbeat_timeout_threshold": 60, "nova::cinder_catalog_info": "volumev3:cinderv3:internalURL", "nova::host": "%{hiera('fqdn_canonical')}", "nova::notify_on_state_change": "vm_and_task_state", "nova::notification_driver": ["messagingv2"], "nova::notification_format": "unversioned", "nova::network::neutron::auth_type": "v3password", "nova::db::database_db_max_retries": -1, "nova::db::database_max_retries": -1, "nova::network::neutron::ovs_bridge": "br-int", "nova::compute::sync_power_state_interval": 600, "nova_is_additional_cell": false, "nova::cross_az_attach": true, "nova::cache::enabled": true, "nova::cache::tls_enabled": false, "nova::cache::backend": "dogpile.cache.memcached", "nova::rabbit_heartbeat_in_pthread": false, "nova::ovsdb_connection": "", "nova::compute::vcpu_pin_set": [], "nova::compute::cpu_shared_set": [], "nova::compute::cpu_dedicated_set": [], "nova::compute::reserved_host_memory": 512, "nova::compute::reserved_huge_pages": [], "nova::compute::neutron_physnets_numa_nodes_mapping": {}, "nova::compute::neutron_tunnel_numa_nodes": [], "nova::compute::resume_guests_state_on_host_boot": false, "nova::compute::libvirt::rx_queue_size": 512, "nova::compute::libvirt::tx_queue_size": 512, "nova::compute::libvirt::file_backed_memory": 0, "nova::compute::libvirt::volume_use_multipath": false, "nova::compute::libvirt::hw_machine_type": "x86_64=pc-q35-rhel9.0.0", "nova::compute::mkisofs_cmd": "mkisofs", "compute_enable_ksm": false, "nova::compute::rbd::libvirt_images_rbd_pool": "vms", "tripleo::profile::base::nova::compute::nova_nfs_enabled": false, "nfs_backend_enable": false, "nfs_share": "", "nfs_options": "context=system_u:object_r:nfs_t:s0", "nfs_vers": "4.2", "nova::compute::libvirt::num_pcie_ports": 16, "nova::compute::libvirt::mem_stats_period_seconds": 10, "nova::compute::rbd::ephemeral_storage": true, "resume_guests_state_on_host_boot": false, "nova::cpu_allocation_ratio": 0.0, "nova::ram_allocation_ratio": 1.0, "nova::disk_allocation_ratio": 0.0, "nova::compute::max_disk_devices_to_attach": -1, "nova::compute::libvirt::pmem_namespaces": "", "nova_pmem_namespaces": "", "nova::compute::image_cache::remove_unused_original_minimum_age_seconds": 86400, "nova::compute::libvirt::swtpm_enabled": false, "nova::compute::vgpu::vgpu_types_device_addresses_mapping": {}, "compute_disable_irqbalance": false, "nova::compute::libvirt::cpu_mode": "host-model", "nova::compute::libvirt::cpu_models": [], "nova::compute::libvirt::cpu_model_extra_flags": "", "nova_compute_opt_volumes": [], "nova_compute_startup_delay": 0, "nova_compute_opt_env_vars": {}, "nova::workarounds::never_download_image_if_on_rbd": false, "nova::compute::image_type_exclude_list": [], "nova_permit_post_copy": true, "nova_permit_auto_converge": true, "nova_libvirt_max_queues": 0, "nova_glance_enable_rbd_download": false, "nova_glance_rbd_download_multistore_id": "", "nova::compute::force_raw_images": true, "nova::compute::use_cow_images": true, "nova::compute::libvirt::preallocate_images": "none", "nova::compute::image_cache::manager_interval": 2400, "nova::compute::image_cache::remove_unused_base_images": true, "nova::compute::image_cache::remove_unused_resized_minimum_age_seconds": 3600, "nova::compute::image_cache::precache_concurrency": 1, "nova::compute::provider::custom_inventories": {}, "nova::compute::rbd::libvirt_images_rbd_glance_copy_poll_interval": 15, "nova::compute::rbd::libvirt_images_rbd_glance_copy_timeout": 600, "ContainerNovaComputeImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "ContainerNovaLibvirtConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "nova::compute::libvirt::manage_libvirt_services": false, "nova::compute::pci::passthrough": "[{\"devname\": \"dummy-dev\", \"physical_network\": \"dummy_sriov_net\"}]", "nova::compute::libvirt::migration_support": false, "tripleo::profile::base::nova::migration::client::nova_compute_enabled": true, "tripleo::profile::base::nova::migration::client::ssh_private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAzcb1z+kYP10UjkTBH4bnxvCXWz+dyTwFHtURjBt2vADgeeph\nNxBRnTe7kysE8m58KHuFJ9m5Lda/KgKrFCJtgtjfquQJzcbJ6cf4qblilLacQG34\nUqc4FLUXkSvAwIriLJX2iGDvg2ff7bAofuD5ya41OU61HEHhtZi2xLEA0I9jQlVS\n0p8PrJy8OAfMDIKQT3ORDfK2QEuLMrabug2dY2vv5b9SASjQrCB+7kYLVxSoUaUq\nociPrBn5na3NMqU+dh7r0P2mpOnQEUb4vRbw2p89Y10YdibzXVad0PbRcZjEpgQr\nNeZIbfMuFDDfSfu0pye7Vm5HzvAwtjUCMQPbBQIDAQABAoIBABA/DBTWv2fvrmBi\nt0I8J9WoexqxYoC+MPbmzy4NOqOY1VNqzAAWVSTUS9MdS2FK+plFOOJIXOFsmfn0\nIGB3k2Ch3lujCc8dFoxTK6O8YJ2DIvT6ebRbQjputCY6NEtyhToMVCmFfB0XOP70\n47P/Ir/nwokvi9POTWBFmiOo7q27vOV0Aa3tJ8DfjcDqIvQTpykQlFHvW+pZ+QhH\nWi9jGCuJP/vLletAHDttmxJ5jnB7ok2UPE/fv46OThx85LNkUmM7P+5qUAT0k2Ke\nB7Q2YSeMjFmaWqnDAq0XbnX6SZGBjIwVYCcUaFqTQdcaHfiDdZQk+4RtCdYJWU8s\n4iCM8KUCgYEA8K39Ux/JO+ut9vqmpTeunq5X4Gl2lmd5Fto1a40QcYAC2iYSwqXM\nsrldOQkWWTQXvcF5lKEDeFGDhDfXX/eMHAeQTGWvKTKun0q7SdIgD8mKHUW+yaSb\nMRMVbNZZ8MDM2mOoOXGVQMcIzEOFPr6+TbnfVu0eTHCvKyMFe/2+q5sCgYEA2uA3\nJmHmehdkX8pQJfW9O4BeJbKZ+dLuF7vI0RXcHRBQa4nOTBFAu5UpaCYMWrC+YQS/\nzWk2FWOyvGL8z5hmPUKcR69GX8vzoYrMIAIvNF5UZAoCwFTDYNYrDFEM5QPhkrln\nH86FPtay/NscrT915j0tz39SWAOBYhbhwyS4jd8CgYEAnhzPZUJmgxTrbmtv+u4/\nq0NBu83M+DX12Mt1eLhtawL73LBSdslRVsBru8J6ihOs3R4zby7wBqUWT1AYD5Wi\n1+8oHuhWUCxZh5AixfZi1bxDHcPp+LJIuc6drqiK4ZzndzktFL/Hm4yl/PsGmBfb\nEVjgnkycMP9+NEqHmdMy5a0CgYBlBEyPy2la+gbaav5YtrTyjElnbqm/8ojurT1+\num8PfuMO7tgmpWPR74LfzYewJ5iGIHIBdMiAULZCWhFCIp01MtP8BboeJnw4F14k\ne72bltmuHiys5bIStGXD1nh0DjmCxU0CEgfPO7n6F4qBryNT8vJ8rM+tTVjek574\nuK7w0wKBgATiv5ZBvdtkO8bDigFvEc9IFNPYGYG2D8JsNU2u6j3FYN/FOQD3UzEj\n/UFz30SOilehDSftmPUGBA3us2CVYA4hJ+SGT71SZeUyOqrmlZhMXGWk3FQn9l7f\n8F0ABR1Kt9K6Wa4shCRBDFgDTmIlqXBgbRTZlJ/OSNae1IBm1UBv\n-----END RSA PRIVATE KEY-----\n", "tripleo::profile::base::nova::migration::client::ssh_port": 2022, "nova::compute::rbd::libvirt_images_rbd_glance_store_name": "default_backend", "nova::compute::rbd::libvirt_images_rbd_ceph_conf": "/etc/ceph/ceph.conf", "nova::compute::rbd::libvirt_rbd_user": "openstack", "nova::compute::rbd::rbd_keyring": "client.openstack", "tripleo::profile::base::nova::compute::cinder_nfs_backend": false, "rbd_persistent_storage": true, "rbd_disk_cachemodes": ["network=writeback"], "nova::cinder::username": "cinder", "nova::cinder::auth_type": "v3password", "nova::cinder::project_name": "service", "nova::cinder::password": "oRdXUvbfKZDA6CMRoTsL6bGXm", "nova::cinder::auth_url": "http://172.17.0.2:5000/v3", "nova::cinder::region_name": "regionOne", "nova::compute::rbd::libvirt_rbd_secret_key": "AQC8YS1pAAAAABAA+BwWKS55FZMjOG5kO1Z5kw==", "nova::compute::rbd::libvirt_rbd_secret_uuid": "dc518f93-7195-5458-af10-a92142534ce2", "nova::compute::instance_usage_audit": true, "nova::compute::instance_usage_audit_period": "hour", "nova::compute::consecutive_build_service_disable_threshold": "10", "nova::compute::live_migration_wait_for_vif_plug": true, "nova::migration::libvirt::live_migration_permit_post_copy": true, "nova::migration::libvirt::live_migration_permit_auto_converge": true, "nova::migration::libvirt::live_migration_tunnelled": false, "nova::compute::vncserver_proxyclient_address": "%{hiera('internal_api')}", "nova::compute::vncproxy_host": "172.21.0.2", "nova::vncproxy::common::vncproxy_protocol": "http", "nova::vncproxy::common::vncproxy_host": "172.21.0.2", "nova::vncproxy::common::vncproxy_port": "6080", "nova::compute::verify_glance_signatures": false, "nova::workarounds::disable_compute_service_check_for_ffu": false}, "service_config_settings": {"rsyslog": {"tripleo_logging_sources_nova_compute": [{"tag": "openstack.nova.compute", "file": "/var/log/containers/nova/nova-compute.log"}]}, "collectd": {"tripleo.collectd.plugins.nova_compute": ["virt"], "collectd::plugin::virt::connection": "qemu:///system"}}, "puppet_config": {"config_volume": "nova_libvirt", "puppet_tags": "nova_config", "step_config": "# TODO(emilien): figure how to deal with libvirt profile.\n# We'll probably treat it like we do with Neutron plugins.\n# Until then, just include it in the default nova-compute role.\ninclude tripleo::profile::base::nova::compute::libvirt\n", "config_image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1"}, "kolla_config": {"/var/lib/kolla/config_files/nova_compute.json": {"command": "/usr/bin/nova-compute ", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-iscsid/*", "dest": "/etc/iscsi/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-ceph/", "dest": "/etc/ceph/", "merge": true, "preserve_properties": true}], "permissions": [{"path": "/var/log/nova", "owner": "nova:nova", "recurse": true}, {"path": "/etc/ceph/ceph.client.openstack.keyring", "owner": "nova:nova", "perm": "0600"}]}, "/var/lib/kolla/config_files/nova_compute_wait_for_compute_service.json": {"command": "/container-config-scripts/pyshim.sh /container-config-scripts/nova_wait_for_compute_service.py", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}], "permissions": [{"path": "/var/log/nova", "owner": "nova:nova", "recurse": true}]}}, "container_config_scripts": {"container_puppet_apply.sh": {"mode": "0700", "content": "#!/bin/bash\nset -eux\nSTEP=$1\nTAGS=$2\nCONFIG=$3\nEXTRA_ARGS=${4:-''}\nif [ -d /tmp/puppet-etc ]; then\n  # ignore copy failures as these may be the same file depending on docker mounts\n  cp -a /tmp/puppet-etc/* /etc/puppet || true\nfi\necho \"{\\\"step\\\": ${STEP}}\" > /etc/puppet/hieradata/docker_puppet.json\n# $::deployment_type in puppet-tripleo\nexport FACTER_deployment_type=containers\nset +e\npuppet apply $EXTRA_ARGS \\\n    --verbose \\\n    --detailed-exitcodes \\\n    --summarize \\\n    --color=false \\\n    --modulepath /etc/puppet/modules:/opt/stack/puppet-modules:/usr/share/openstack-puppet/modules \\\n    --tags $TAGS \\\n    -e \"noop_resource('package'); ${CONFIG}\"\nrc=$?\nset -e\nset +ux\nif [ $rc -eq 2 -o $rc -eq 0 ]; then\n    exit 0\nfi\nexit $rc\n"}, "pyshim.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n# Copyright 2018 Red Hat Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n#\n# Usage: pyshim.sh <script and/or arguments>\n#\n# Unfortunately THT doesn't know which version of python might be in a\n# container so we need this script to be able to try python3 or python2\n# depending on availability.  Since this is a temporary shim until we've\n# fully cut over to python3, we check for the existence of python3 first\n# before falling back to python2. This will help in the transition from\n# python2 based containers to python3.\n\nshow_usage() {\n    echo \"Usage: pyshim.sh <script and/or arguments>\"\n}\n\nif [ $# -lt 1 ]\nthen\n    show_usage\n    exit 1\nfi\n\nset -x\nif command -v python3 >/dev/null; then\n    python3 \"$@\"\nelif command -v python2 >/dev/null; then\n    python2 \"$@\"\nelif command -v python >/dev/null; then\n    python \"$@\"\nelse\n    echo \"ERROR: python is not available!\"\n    exit 1\nfi\n"}, "pacemaker_restart_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nset -u\n\n# ./pacemaker_restart_bundle.sh mysql galera galera-bundle Master _\n# ./pacemaker_restart_bundle.sh redis redis redis-bundle Slave Master\n# ./pacemaker_restart_bundle.sh ovn_dbs ovndb_servers ovn-dbs-bundle Slave Master\nRESTART_SCRIPTS_DIR=$(dirname $0)\nTRIPLEO_SERVICE=$1\nRESOURCE_NAME=$2\nBUNDLE_NAME=$3\nWAIT_TARGET_LOCAL=$4\nWAIT_TARGET_ANYWHERE=${5:-_}\nTRIPLEO_MINOR_UPDATE=\"${TRIPLEO_MINOR_UPDATE:-false}\"\nTRIPLEO_HA_WRAPPER_RESOURCE_EXISTS=\"${TRIPLEO_HA_WRAPPER_RESOURCE_EXISTS:-false}\"\n\nbundle_can_be_restarted() {\n    local bundle=$1\n    # As long as the resource bundle is managed by pacemaker and is\n    # not meant to stay stopped, no matter the state of any inner\n    # pcmk_remote or ocf resource, we should restart it to give it a\n    # chance to read the new config.\n    [ \"$(crm_resource --meta -r $1 -g is-managed 2>/dev/null)\" != \"false\" ] && \\\n    [ \"$(crm_resource --meta -r $1 -g target-role 2>/dev/null)\" != \"Stopped\" ]\n}\n\nlog() {\n    local msg=$1\n    logger -t pcmkrestart \"$1\"\n}\n\nHOSTNAME=$(/bin/hostname -s)\nif [ x\"${TRIPLEO_MINOR_UPDATE,,}\" != x\"true\" ]; then\n    if [ x\"${TRIPLEO_HA_WRAPPER_RESOURCE_EXISTS,,}\" = x\"false\" ]; then\n        # Do not restart during initial deployment, as the resource\n        # has just been created.\n        SERVICE_NODEID=$(/bin/hiera -c /etc/puppet/hiera.yaml \"${TRIPLEO_SERVICE}_short_bootstrap_node_name\")\n        if [[ \"${HOSTNAME,,}\" == \"${SERVICE_NODEID,,}\" ]]; then\n            log \"Initial deployment, skipping the restart of ${BUNDLE_NAME}\"\n\tfi\n        exit 0\n    else\n        # During a stack update, this script is called in parallel on\n        # every node the resource runs on, after the service's configs\n        # have been updated on all nodes. So we need to run pcs only\n        # once (e.g. on the service's boostrap node).\n        if bundle_can_be_restarted ${BUNDLE_NAME}; then\n            SERVICE_NODEID=$(/bin/hiera -c /etc/puppet/hiera.yaml \"${TRIPLEO_SERVICE}_short_bootstrap_node_name\")\n            if [[ \"${HOSTNAME,,}\" == \"${SERVICE_NODEID,,}\" ]]; then\n                replicas_running=$(crm_resource -Q -r $BUNDLE_NAME --locate 2>&1 | wc -l)\n                if [ \"$replicas_running\" != \"0\" ]; then\n                    log \"Restarting ${BUNDLE_NAME} globally. Stopping:\"\n                    /sbin/pcs resource disable --wait=600 $BUNDLE_NAME\n                    log \"Restarting ${BUNDLE_NAME} globally. Starting:\"\n                    /sbin/pcs resource enable --wait=600 $BUNDLE_NAME\n                else\n                    log \"${BUNDLE_NAME} is not running anywhere,\" \\\n                         \"cleaning up to restart it globally if necessary\"\n                    /sbin/pcs resource cleanup $BUNDLE_NAME\n                fi\n            else\n                log \"Skipping global restart of ${BUNDLE_NAME} on ${HOSTNAME} it will be restarted by node ${SERVICE_NODEID}\"\n            fi\n\n        else\n            log \"No global restart needed for ${BUNDLE_NAME}.\"\n        fi\n    fi\nelse\n    # During a minor update workflow however, a host gets fully\n    # updated before updating the next one. So unlike stack\n    # update, at the time this script is called, the service's\n    # configs aren't updated on all nodes yet. So only restart the\n    # resource locally, where it's guaranteed that the config is\n    # up to date.\n    HOST=$(facter hostname)\n\n    if bundle_can_be_restarted ${BUNDLE_NAME}; then\n\t# if the resource is running locally, restart it\n\tif crm_resource -r $BUNDLE_NAME --locate 2>&1 | grep -w -q \"${HOST}\"; then\n            log \"Restarting ${BUNDLE_NAME} locally on '${HOST}'\"\n            /sbin/pcs resource restart $BUNDLE_NAME \"${HOST}\"\n\n\telse\n\t    # At this point, if no resource is running locally, it's\n\t    # either because a) it has failed previously, or b) because\n\t    # it's an A/P resource running elsewhere.\n\t    # By cleaning up resource, we ensure that a) it will try to\n\t    # restart, or b) it won't do anything if the resource is\n\t    # already running elsewhere.\n            log \"${BUNDLE_NAME} is currently not running on '${HOST}',\" \\\n                 \"cleaning up its state to restart it if necessary\"\n            /sbin/pcs resource cleanup $BUNDLE_NAME node=\"${HOST}\"\n\tfi\n\n\t# Wait until the resource is in the expected target state\n\t$RESTART_SCRIPTS_DIR/pacemaker_wait_bundle.sh \\\n            $RESOURCE_NAME $BUNDLE_NAME \\\n            \"$WAIT_TARGET_LOCAL\" \"$WAIT_TARGET_ANYWHERE\" \\\n\t    \"${HOST}\" 600\n    else\n        log \"No restart needed for ${BUNDLE_NAME}.\"\n    fi\nfi\n"}, "pacemaker_wait_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# ----\n# Wait for an OCF resource or a bundle to be restarted\n# ----\n# e.g.:\n# M/S OCF:      $0 galera galera-bundle Master\n# clone OCF:    $0 rabbitmq rabbitmq-bundle Started\n# A/P M/S OCF:  $0 redis redis-bundle Slave Master\n# A/P bundle:   $0 openstack-cinder-volume openstack-cinder-volume _ Started\n# clone bundle: $0 haproxy-bundle haproxy-bundle Started\n\n# design note 1:\n#  - this script is called during a minor update; it is called\n#    once per node that hosts a service replica.\n#  - the purpose of this script is to ensure that restarting the\n#    service replica locally won't disrupt the service availability\n#    for the end user. To reach that goal, the script waits until the\n#    service is restarted locally or globallu and reaches a given\n#    target state (i.e. Started, Slave or Master).\n# design note 2:\n#   - we don't want to track restart error: our only job is to ensure\n#     service restart synchronization, not service health.\n#   - In particular, we don't want to error out in case the resource\n#     cannot be restarted locally, because that would make the minor\n#     update fail, even if potentially other replicas still provide\n#     the service.\n# design note 3:\n#   - we can bail out early if we determine that the resource can't\n#     be restarted automatically by pacemaker (e.g. its \"blocked\",\n#     unmanaged or disabled).\n\nlog() {\n    local msg=$1\n    echo \"$(date -u): $1\"\n}\n\nusage() {\n    echo 2>&1 \"Usage: $0 NAME BUNDLE_NAME ROLE_LOCAL [ROLE_ANYWHERE] [HOST] [TIMEOUT]\"\n    exit 1\n}\n\npacemaker_supports_promoted() {\n    # The Promoted token is only matched in recent pacemaker versions\n    grep -wq \"<value>Promoted</value>\" /usr/share/pacemaker/resources-*.rng\n}\n\n#\n# Utility functions to detect stuck resources\n#\n\nbundle_failures_locally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    local replica_name\n    for i in $(seq 0 $last); do\n\treplica_name=${BUNDLE_NAME}-${engine}-${i}\n\tcrm_failcount -q -G -r $replica_name -N $HOST\n    done\n}\n\nbundle_failures_globally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    for i in $(seq 0 $last); do\n\tcrm_failcount -q -G -r ${BUNDLE_NAME}-${engine}-${i}\n    done\n}\n\nbundle_running_globally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    # return the number of running bundles replica, i.e. the number of\n    # docker/podman resource replicas currently running in the cluster\n    crm_mon --as-xml | xmllint --xpath \"count(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource[@resource_agent='${OCF}:heartbeat:${engine}']/node)\" -\n}\n\nocf_failures_globally() {\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    local bundle_node\n    for i in $(seq 0 $last); do\n\tbundle_node=${BUNDLE_NAME}-${i}\n\tcrm_failcount -q -G -r $NAME -N $bundle_node\n    done\n}\n\ndid_resource_failed_locally() {\n    local failures\n    local running\n    local remotehost\n    if [ \"${NAME}\" != \"${BUNDLE_NAME}\" ]; then\n\t# if we're dealing with an ocf resource, it is running on a\n\t# pacemaker_remote rather that on the real host, and the\n\t# failcounts are thus associated to the pcmk remote. Replace\n\t# the host's name with the pcmk remote's name.\n        remotehost=$(crm_mon --as-xml | xmllint --xpath \"string(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource/node[@name='${HOST}']/../../resource[@resource_agent='${OCF}:pacemaker:remote']/@id)\" -)\n\tif [ -n \"${remotehost}\" ]; then\n\t    crm_failcount -q -G -r $NAME -N $remotehost | grep -q -w INFINITY\n\t    return $?\n\tfi\n\t# If no pcmk remote is currently running, the failcount from\n\t# the ocf resource is useless, compute the failcount from the\n\t# bundle case instead (computed below).\n    fi\n\n    # for bundles, pacemaker can run any bundle replica locally\n    # (e.g. galera-bundle-docker-{0,1,2}), and a failure happens when\n    # there are no more replica to try.\n    # That is, when _at least_ one replica failed locally, and all the\n    # others either failed or are currently running elsewhere.\n    failures=$(bundle_failures_locally $HOST | grep -c -w INFINITY)\n    running=$(bundle_running_globally)\n    test $failures -gt 0 && \\\n    test $(( $failures + $running )) -ge $BUNDLE_REPLICAS\n}\n\ndid_resource_failed_globally() {\n    local remotecount\n    local failures\n    if [ \"${NAME}\" != \"${BUNDLE_NAME}\" ]; then\n\t# we check the state of an ocf resource only if the\n\t# pcmkremotes are started\n        remotecount=$(crm_mon --as-xml | xmllint --xpath \"count(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource[@resource_agent='${OCF}:pacemaker:remote']/node)\" -)\n\tif [ \"${remotecount}\" = \"0\" ]; then\n\t    # no pcmkremote is running, so check the bundle state\n\t    # instead of checking the ocf resource\n\t    # bundle failed if all ${BUNDLE_REPLICAS} replicas failed\n\t    failures=$(bundle_failures_globally | grep -c -w INFINITY)\n\t    test $failures -eq $BUNDLE_REPLICAS\n\telse\n\t    # ocf resource failed if it failed to start on\n\t    # all $BUNDLE_REPLICAS bundle nodes\n\t    failures=$(ocf_failures_globally | grep -c -w INFINITY)\n\t    test $failures -eq $BUNDLE_REPLICAS\n\tfi\n    else\n\t# bundle failed if all ${BUNDLE_REPLICAS} replicas failed\n\tfailures=$(bundle_failures_globally | grep -c -w INFINITY)\n\ttest $failures -eq $BUNDLE_REPLICAS\n    fi\n}\n\n\n# Input validation\n#\n\nNAME=$1\nif [ -z \"${NAME}\" ]; then\n    echo 2>&1 \"Error: argument NAME must not be empty\"\n    exit 1\nfi\n\nBUNDLE_NAME=$2\nif [ -z \"${BUNDLE_NAME}\" ]; then\n    echo 2>&1 \"Error: argument BUNDLE_NAME must not be empty\"\n    exit 1\nfi\n\nROLE_LOCAL=$3\nif [ \"${ROLE_LOCAL}\" = \"_\" ]; then\n    ROLE_LOCAL=\"\"\nfi\n\nROLE_ANYWHERE=$4\nif [ \"${ROLE_ANYWHERE}\" = \"_\" ]; then\n    ROLE_ANYWHERE=\"\"\nfi\n\nif [ -z \"${ROLE_LOCAL}\" ]; then\n    if [ -z \"${ROLE_ANYWHERE}\" ]; then\n        echo 2>&1 \"Error: either ROLE_LOCAL or ROLE_ANYWHERE must be non empty\"\n        exit 1\n    fi\nelse\n    if !(echo \"${ROLE_LOCAL}\" | grep -q -x -E \"(Started|Slave|Master|Unpromoted|Promoted)\"); then\n        echo 2>&1 \"Error: argument ROLE_LOCAL must be either 'Started' 'Slave' 'Master' 'Unpromoted' or 'Promoted'\"\n        exit 1\n    fi\nfi\n\nif [ -n \"${ROLE_ANYWHERE}\" ] && !(echo \"${ROLE_ANYWHERE}\" | grep -q -x -E \"(Started|Slave|Master|Unpromoted|Promoted)\"); then\n    echo 2>&1 \"Error: argument ROLE_ANYWHERE must be either 'Started' 'Slave' 'Master' 'Unpromoted' or 'Promoted'\"\n    exit 1\nfi\n\n# Ensure compatibility with pacemaker 2.1\nif pacemaker_supports_promoted; then\n    ROLE_LOCAL=$(echo \"$ROLE_LOCAL\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    ROLE_ANYWHERE=$(echo \"$ROLE_ANYWHERE\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    OCF=\"ocf\"\nelse\n    OCF=\"ocf:\"\nfi\n\nHOST=${5:-$(facter hostname)}\nTIMEOUT=${6:-600}\n\n\n# Configure the search\n# ----\n# Note: we can't use crm_resource in all searches because we can't\n# easily extract the host the OCF resources run on (crm_resource\n# returns the pcmk-remote nodes rather than the hosts)\n# So instead, we implement various searches with XPath directly.\n\nif [ \"${BUNDLE_NAME}\" != \"${NAME}\" ]; then\n# ocf resource\nlocal_resource_xpath=\"//bundle/replica/resource[@resource_agent='${OCF}:pacemaker:remote']/node[@name='${HOST}']/../../resource[@id='${NAME}']\"\nany_resource_xpath=\"//bundle//resource[@id='${NAME}']\"\nreplicas_xpath=\"//bundle/primitive[@id='${BUNDLE_NAME}']/../*[boolean(@image) and boolean(@replicas)]\"\nelse\n# bundle resource\nlocal_resource_xpath=\"//bundle[@id='${NAME}']/replica/resource/node[@name='${HOST}']/../../resource\"\nany_resource_xpath=\"//bundle[@id='${NAME}']//resource\"\nreplicas_xpath=\"//bundle[@id='${BUNDLE_NAME}']/*[boolean(@image) and boolean(@replicas)]\"\nfi\n\nbundle_def_xpath=\"//bundle[@id='${BUNDLE_NAME}']/*[boolean(@image) and boolean(@replicas)]\"\nBUNDLE_CONTAINER_ENGINE=$(cibadmin -Q | xmllint --xpath \"name(${bundle_def_xpath})\" -)\nBUNDLE_REPLICAS=$(cibadmin -Q | xmllint --xpath \"string(${bundle_def_xpath}/@replicas)\" -)\n\n\n# The wait algorithm follows a two-stage approach\n#  1. Depending on how the script is called, we first check whether\n#     the resource is restarted locally. An A/P resource may be\n#     restarted elsewhere in the cluster.\n#  2. If needed, check whether the A/P resource has restarted\n#     elsewhere. For A/P M/S resources, in case the resource is\n#     restarted as Slave locally, ensure a Master is available.\n\nsuccess=1\nbailout=1\ntimeout=$TIMEOUT\nrole=\"\"\n\n# Stage 1: local check\nif [ -n \"$ROLE_LOCAL\" ]; then\n    log \"Waiting until ${NAME} has restarted on ${HOST} and is in state ${ROLE_LOCAL}\"\n    log \"Will probe resource state with the following XPath pattern: ${local_resource_xpath}\"\n\n    while [ $timeout -gt 0 ] && [ $bailout -ne 0 ] && [ $success -ne 0 ]; do\n        resource=$(crm_mon -r --as-xml | xmllint --xpath \"${local_resource_xpath}\" - 2>/dev/null)\n        role=$(echo \"${resource}\" | sed -ne 's/.*\\Wrole=\"\\([^\"]*\\)\".*/\\1/p')\n\n\tif [ \"$(crm_resource --meta -r ${NAME} -g is-managed 2>/dev/null)\" = \"false\" ]; then\n            log \"${NAME} is unmanaged, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif [ \"$(crm_resource --meta -r ${NAME} -g target-role 2>/dev/null)\" = \"Stopped\" ]; then\n            log \"${NAME} is disabled, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif echo \"${resource}\" | grep -q -w \"\\Wblocked=\\\"true\\\"\"; then\n            log \"${NAME} is blocked, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif did_resource_failed_locally; then\n            log \"${NAME} is in failed state, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif [ \"$role\" = \"$ROLE_LOCAL\" ]; then\n            success=0\n            continue\n        elif [ -n \"$ROLE_ANYWHERE\" ] && [ \"$role\" = \"$ROLE_ANYWHERE\" ]; then\n            # A/P: we are restarted in the expected state\n            success=0\n            continue\n        else\n            log \"Waiting for ${NAME} to transition to role ${ROLE_LOCAL} on ${HOST}\"\n        fi\n\n        if [ $bailout -ne 0 ] && [ $success -ne 0 ]; then\n            sleep 4\n            timeout=$((timeout-4))\n        fi\n    done\nfi\n\n# Stage 2: global check\nif [ $timeout -gt 0 ] && [ -n \"$ROLE_ANYWHERE\" ] && [ \"$role\" != \"$ROLE_ANYWHERE\" ]; then\n    log \"Wait until ${NAME} is restarted anywhere in the cluster in state ${ROLE_ANYWHERE}\"\n    log \"Will probe resource state with the following XPath pattern: ${any_resource_xpath}\"\n\n    success=1\n    bailout=1\n    while [ $timeout -gt 0 ] && [ $bailout -ne 0 ] && [ $success -ne 0 ]; do\n        resources=$(crm_mon -r --as-xml | xmllint --xpath \"${any_resource_xpath}\" - 2>/dev/null)\n\tif [ \"$(crm_resource --meta -r ${NAME} -g is-managed 2>/dev/null)\" = \"false\" ]; then\n            log \"${NAME} is unmanaged, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif [ \"$(crm_resource --meta -r ${NAME} -g target-role 2>/dev/null)\" = \"Stopped\" ]; then\n            log \"${NAME} is disabled, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif ! (echo \"${resources}\" | grep -q -w \"\\Wblocked=\\\"false\\\"\"); then\n            log \"${NAME} blocked, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif did_resource_failed_globally; then\n            log \"${NAME} is in failed state, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif echo \"${resources}\" | grep -q -w \"\\Wrole=\\\"${ROLE_ANYWHERE}\\\"\"; then\n            success=0\n            continue\n        else\n            log \"Waiting for ${NAME} to transition to role ${ROLE_ANYWHERE} anywhere in the cluster\"\n        fi\n\n        if [ $bailout -ne 0 ] && [ $success -ne 0 ]; then\n            sleep 4\n            timeout=$((timeout-4))\n        fi\n    done\nfi\n\nif [ $timeout -le 0 ]; then\n    log \"Timeout reached after ${TIMEOUT}s while waiting for ${NAME} to be restarted\"\nelif [ $bailout -le 0 ]; then\n    log \"Restart monitoring for ${NAME} cancelled\"\nfi\n\nif [ $success -eq 0 ]; then\n    log \"${NAME} successfully restarted\"\nelse\n    log \"${NAME} was not restarted properly\"\nfi\n\n# Don't block minor update or stack update if the wait was unsuccessful\nexit 0\n"}, "wait-port-and-run.sh": {"mode": "0755", "content": "#!/usr/bin/bash\nset -eu\n\nHOST=$1\nPORT=$2\n\necho \"$(date -u): Checking whether we can bind to ${HOST}:${PORT}\"\nwhile (ss -Htnl src \"${HOST}\" \"sport = :${PORT}\" | grep -wq \"${PORT}\"); do\n    echo \"$(date -u): ${HOST}:${PORT} still in use, waiting...\";\n    sleep 10;\ndone\n\nshift 2\nCOMMAND=\"$*\"\nif [ -z \"${COMMAND}\" ]; then\n    COMMAND=\"true\"\nfi\nexec $COMMAND\n"}, "pacemaker_resource_lock.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nMAX_RETRIES=10\nCIB_ENOTFOUND=105\n\nusage() {\n   echo \"Set a global property in the cluster with a validity timestamp.\"\n   echo \"Usage:\"\n   echo \"   $0 --acquire <lock_name> <lock_owner> <lock_ttl_in_seconds>\"\n   echo \"   $0 --release <lock_name> <lock_owner>\"\n   echo\n}\n\nlog() {\n    echo \"$(date -u): $1\" 1>&2\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\nlock_create() {\n    local name=$1\n    local data=$2\n    # cibadmin won't overwrite a key if someone else succeeded to create it concurrently\n    cibadmin --sync-call --scope crm_config --create --xml-text \"<cluster_property_set id='${name}'><nvpair id='${name}-pair' name='${name}' value='${data}'/></cluster_property_set>\" &>/dev/null\n    return $?\n}\n\nlock_update() {\n    local name=$1\n    local expected_data=$2\n    local new_data=$3\n    # we only update the lock we expect to see, so we can't update someone else's lock\n    cibadmin --sync-call --scope crm_config --modify --xpath \"//cluster_property_set/nvpair[@name='${name}' and @value='${expected_data}']/..\" --xml-text \"<nvpair id='${name}-pair' name='${name}' value='${new_data}'/>\" &>/dev/null\n    return $?\n}\n\nlock_delete() {\n    local name=$1\n    local expected_data=$2\n    # we only delete the lock we expect to see, so we can't delete someone else's lock\n    cibadmin --sync-call --scope crm_config --delete --xpath \"//cluster_property_set/nvpair[@name='${name}' and @value='${expected_data}']/..\" &>/dev/null\n    return $?\n}\n\nlock_get() {\n    local lockname=$1\n    local res\n    local rc\n    res=$(cibadmin --query --scope crm_config --xpath \"//cluster_property_set/nvpair[@name='$lockname']\" 2>/dev/null)\n    rc=$?\n    if [ $rc -eq 0 ]; then\n        echo \"$res\" | sed -n 's/.*value=\"\\([^\"]*\\)\".*/\\1/p'\n    fi\n    return $rc\n}\n\nlock_owner() {\n    local lock=$1\n    echo \"$lock\" | cut -d':' -f1\n}\n\nlock_has_expired() {\n    local lock=$1\n    local expiry=$(echo \"$lock\" | cut -d':' -f2)\n    local now=$(date +%s)\n    test $now -ge $expiry\n}\n\n\n# Perform a lock action and restart if the CIB has been modified before\n# committing the lock action\ntry_action() {\n    local fun=$1\n    local lock=$2\n    local requester=$3\n    local args=${4:-}\n    local tries=$MAX_RETRIES\n    local rc=1\n    if [ \"$fun\" = \"lock_acquire\" ] || [ \"$fun\" = \"lock_release\" ]; then\n        log \"Try running $fun\"\n    else\n        return 2\n    fi\n    while [ $rc -ne 0 ]; do\n        $fun $lock $requester $args\n        rc=$?\n        if [ $rc -eq 0 ]; then\n            log \"Operation $1 succeeded\"\n            return 0\n        elif [ $rc -eq 3 ]; then\n            # rc == 3 -> CIB changed before push\n            if [ $tries -eq 0 ]; then\n                log \"Failed to commit after $MAX_RETRIES retries. Bailing out.\"\n                return 2\n            else\n                log \"Failed to commit. Retrying operation.\"\n                tries=$(($tries - 1))\n            fi\n        elif [ $rc -eq 2 ]; then\n            # rc == 2 -> unrecoverable cib error (e.g. pacemaker down)\n            log \"Unexpected failure. Bailing out\"\n            return $rc\n        else\n            # rc == 1 -> lock error (not owner, lock doesn't exists)\n            return $rc\n        fi\n    done\n}\n\n# The lock mechanism uses cibadmin's atomic creation so cluster-wide\n# state coherency is guaranteed by pacemaker\nlock_acquire() {\n    local lockname=$1\n    local requester=$2\n    local ttl=$3\n    local rc\n    local lock\n    local expiry\n    local owner\n\n    log \"Check whether the lock is already held in the CIB\"\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        log \"Could not retrieve info from the CIB\"\n        return 2\n    fi\n\n    if [ -n \"$lock\" ]; then\n        lock_has_expired $lock\n        rc=$?\n        if [ $rc -eq 0 ]; then\n            log \"Lock has expired, now available for being held\"\n        else\n            # lock is still held. check whether we're the owner\n            owner=$(lock_owner $lock)\n            if [ \"$owner\" = \"$requester\" ];then\n                log \"Requester already owns the lock, acquiring attempt will just reconfigure the TTL\"\n            else\n                log \"Lock is held by someone else ($owner)\"\n                return 1\n            fi\n        fi\n    else\n        log \"Lock is not held yet\"\n    fi\n\n    # prepare the lock info\n    expiry=$(($(date +%s) + $ttl))\n\n    if [ -n \"$lock\" ]; then\n        log \"Attempting to update the lock\"\n        lock_update $lockname \"$lock\" \"$requester:$expiry\"\n        rc=$?\n    else\n        log \"Attempting to acquire the lock\"\n        lock_create $lockname \"$requester:$expiry\"\n        rc=$?\n    fi\n\n    if [ $rc -eq 0 ]; then\n        log \"Lock '$lockname' acquired by '$requester', valid until $(date -d @$expiry)\"\n        return 0\n    else\n        log \"CIB changed, lock cannot be acquired\"\n        return 3\n    fi\n}\n\n\n# The lock mechanism uses the CIB's num_updates tag to implement\n# a conditional store. Cluster-wide locking is guaranteed by pacemaker\nlock_release() {\n    local lockname=$1\n    local requester=$2\n    local rc\n    local lock\n    local owner\n\n    log \"Check whether the lock is already held in the CIB\"\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        log \"Could not retrieve info from the CIB\"\n        return 2\n    fi\n\n    if [ -z \"$lock\" ]; then\n        log \"Lock doesn't exist. Nothing to release\"\n        return 0\n    else\n        log \"Lock exists, check whether we're the owner\"\n        owner=$(lock_owner $lock)\n        if [ \"$owner\" != \"$requester\" ];then\n            log \"Lock is held by someone else ($owner), will not unlock\"\n            return 1\n        fi\n    fi\n\n    lock_delete $lockname \"$lock\"\n    rc=$?\n\n    if [ $rc -eq 0 ]; then\n        log \"Lock '$lockname' released by '$requester'\"\n        return 0\n    else\n        log \"CIB deletion error, lock cannot be released\"\n        return 3\n    fi\n}\n\n\n# Retrieve the owner of a lock from the CIB\n# this is a read-only operation, so no need to log debug info\nlock_get_owner() {\n    local lockname=$1\n    local rc\n    local lock\n    local owner\n\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        return 2\n    fi\n\n    if [ -z \"$lock\" ]; then\n        return 1\n    else\n        lock_owner $lock\n        return 0\n    fi\n}\n\n\nACTION=$1\nLOCKNAME=$2\nREQUESTER=$3\nTTL=${4:-60}\n\nif [ -z \"$ACTION\" ]; then\n    error \"Action must be specified\"\nfi\n\nif [ $ACTION != \"--help\" ]; then\n    if [ -z \"$LOCKNAME\" ]; then\n        error \"You must specific a lock name\"\n    fi\n    if [ $ACTION != \"--owner\" ] && [ $ACTION != \"-o\" ]; then\n        if [ -z \"$REQUESTER\" ]; then\n            error \"You must specific a lock requester\"\n        fi\n    fi\nfi\n\ncase $ACTION in\n    --help) usage; exit 0;;\n    --acquire|-a) try_action lock_acquire $LOCKNAME $REQUESTER $TTL;;\n    --release|-r) try_action lock_release $LOCKNAME $REQUESTER;;\n    --acquire-once|-A) lock_acquire $LOCKNAME $REQUESTER $TTL;;\n    --owner|-o) lock_get_owner $LOCKNAME;;\n    *) error \"Invalid action\";;\nesac\nexit $?\n"}, "pacemaker_mutex_restart_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# pacemaker_mutex_restart_bundle.sh --lock mysql galera galera-bundle Master _\n# pacemaker_mutex_restart_bundle.sh --lock ovn_dbs ovndb_servers ovn-dbs-bundle Slave Master\n\nset -u\n\nusage() {\n    echo \"Restart a clustered resource in a coordinated way across the cluster\"\n    echo \"Usage:\"\n    echo \"   $0 --lock <tripleo-service> <pcmk-resource> <pcmk-bundle> <target-state-local> <target-state-cluster>\"\n    echo\n}\n\nlog() {\n    echo \"$(date -u): $1\"\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\npacemaker_supports_promoted() {\n    # The Promoted token is only matched in recent pacemaker versions\n    grep -wq \"<value>Promoted</value>\" /usr/share/pacemaker/resources-*.rng\n}\n\nACTION=$1\ncase $ACTION in\n    --help) usage; exit 0;;\n    --lock) ;;\n    *) error \"Unknown action '$ACTION'\";;\nesac\n\nTRIPLEO_SERVICE=$2\nLOCK_NAME=${TRIPLEO_SERVICE}-restart-lock\nLOCK_OWNER=$(crm_node -n 2>/dev/null)\nrc=$?\nif [ $rc -ne 0 ]; then\n    if [ $rc -eq 102 ]; then\n        log \"Cluster is not running locally, no need to restart resource $TRIPLEO_SERVICE\"\n        exit 0\n    else\n        error \"Unexpected error while connecting to the cluster (rc: $rc), bailing out\"\n    fi\nfi\n\nRESOURCE_NAME=$3\nBUNDLE_NAME=$4\nWAIT_TARGET_LOCAL=$5\nWAIT_TARGET_ANYWHERE=${6:-_}\n\nif pacemaker_supports_promoted; then\n    WAIT_TARGET_LOCAL=$(echo \"$5\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    WAIT_TARGET_ANYWHERE=$(echo \"${6:-_}\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    promoted_role=\"Promoted\"\nelse\n    promoted_role=\"Master\"\nfi\n\n# The lock TTL should accomodate for the resource start/promote timeout\nif [ \"$RESOURCE_NAME\" != \"$BUNDLE_NAME\" ]; then\n    if [ \"$WAIT_TARGET_LOCAL\" = \"$promoted_role\" ] || [ \"$WAIT_TARGET_ANYWHERE\" = \"$promoted_role\" ]; then\n        rsc_op=\"promote\"\n    else\n        rsc_op=\"start\"\n    fi\n    # <op id=\"galera-promote-interval-0s\" interval=\"0s\" name=\"promote\" on-fail=\"block\" timeout=\"300s\"/>\n    PCMK_TTL=$(cibadmin -Q | xmllint -xpath \"string(//primitive[@id='${RESOURCE_NAME}']/operations/op[@name='${rsc_op}']/@timeout)\" - | sed 's/s$//')\n    LOCK_TTL=$((PCMK_TTL + 30))\nelse\n    # The podman RA's default start timeout\n    LOCK_TTL=90\nfi\n\nlog \"Acquire a ${LOCK_TTL}s restart lock for service $TRIPLEO_SERVICE before restarting it\"\n# Loop until we hold the lock. The lock has a TTL, so we're guaranteed to get it eventually\nrc=1\nwhile [ $rc -ne 0 ]; do\n    /var/lib/container-config-scripts/pacemaker_resource_lock.sh --acquire $LOCK_NAME $LOCK_OWNER $LOCK_TTL\n    rc=$?\n    if [ $rc != 0 ]; then\n        if [ $rc -gt 1 ]; then\n            error \"Could not acquire lock due to unrecoverable error (rc: $rc), bailing out\"\n        else\n            log \"Could not acquire lock, retrying\"\n            sleep 10\n        fi\n    fi\ndone\n\nlog \"Restart the service $TRIPLEO_SERVICE locally\"\n# Reuse the local restart script in t-h-t (driven by env var TRIPLEO_MINOR_UPDATE)\nTRIPLEO_MINOR_UPDATE=true /var/lib/container-config-scripts/pacemaker_restart_bundle.sh $TRIPLEO_SERVICE $RESOURCE_NAME $BUNDLE_NAME $WAIT_TARGET_LOCAL $WAIT_TARGET_ANYWHERE\n\n# If we reached this point, always try to release the lock\nlog \"Release the restart lock for service $TRIPLEO_SERVICE\"\n/var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $LOCK_NAME $LOCK_OWNER\nrc=$?\nif [ $rc -ne 0 ] && [ $rc -ne 1 ]; then\n    error \"Could not release held lock (rc: $rc)\"\nfi\n"}, "pacemaker_mutex_shutdown.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# pacemaker_mutex_shutdown.sh --acquire\n# pacemaker_mutex_shutdown.sh --release\n\nset -u\n\nusage() {\n    echo \"Shutdown a cluster node in a coordinated way across the cluster\"\n    echo \"Usage:\"\n    echo \"   $0 --acquire # prevent other node from shutting down until we hold the lock\"\n    echo \"   $0 --release # release the lock, other node can compete for the shutdown lock\"\n    echo\n}\n\nlog() {\n    echo \"$(date -u): $1\"\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\n# Loop until we hold the lock. The lock has a TTL, so we're guaranteed to get it eventually\nshutdown_lock_acquire() {\n    local lockname=$1\n    local requester=$2\n    local ttl=$3\n    local rc=1\n    local current_owner\n    local owner_stopped\n    local owner_rc\n\n    log \"Acquiring the shutdown lock\"\n    while [ $rc -ne 0 ]; do\n        /var/lib/container-config-scripts/pacemaker_resource_lock.sh --acquire-once $lockname $requester $ttl\n        rc=$?\n        if [ $rc -ne 0 ]; then\n            if [ $rc -eq 2 ]; then\n                error \"Could not acquire the shutdown lock due to unrecoverable error (rc: $rc), bailing out\"\n            else\n                # The lock is held by another node.\n                current_owner=$(/var/lib/container-config-scripts/pacemaker_resource_lock.sh --owner $lockname)\n                owner_rc=$?\n                if [ $owner_rc -eq 2 ]; then\n                    error \"Could not get the shutdown lock owner due to unrecoverable error (rc: $owner_rc), bailing out\"\n                fi\n                if [ $owner_rc -eq 0 ]; then\n                    # If the owner is marked as offline, that means it has shutdown and\n                    # we can clean the lock preemptively and try to acquire it.\n                    owner_stopped=$(crm_mon -1X | xmllint --xpath 'count(//nodes/node[@name=\"'${current_owner}'\" and @online=\"false\" and @unclean=\"false\"])' -)\n                    if [ \"${owner_stopped}\" = \"1\" ]; then\n                        log \"Shutdown lock held by stopped node '${current_owner}', lock can be released\"\n                        /var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $lockname $current_owner\n                        continue\n                    fi\n                fi\n                log \"Shutdown lock held by another node (rc: $rc), retrying\"\n                sleep 10\n            fi\n        fi\n    done\n    log \"Shutdown lock acquired\"\n    return 0\n}\n\n\n# Release the lock if we still own it. Not owning it anymore is not fatal\nshutdown_lock_release() {\n    local lockname=$1\n    local requester=$2\n    local rc\n\n    log \"Releasing the shutdown lock\"\n    /var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $lockname $requester\n    rc=$?\n    if [ $rc -ne 0 ]; then\n        if [ $rc -gt 1 ]; then\n            error \"Could not release the shutdown lock due to unrecoverable error (rc: $rc), bailing out\"\n        else\n            log \"Shutdown lock no longer held, nothing to do\"\n        fi\n    else\n        log \"Shutdown lock released\"\n    fi\n    return 0\n}\n\n\nACTION=$1\nif [ -z \"$ACTION\" ]; then\n    error \"Action must be specified\"\nfi\n\nLOCK_NAME=tripleo-shutdown-lock\nLOCK_OWNER=$(crm_node -n 2>/dev/null)\nrc=$?\nif [ $rc -ne 0 ]; then\n    if [ $rc -eq 102 ]; then\n        log \"Cluster is not running locally, no need to aquire the shutdown lock\"\n        exit 0\n    else\n        error \"Unexpected error while connecting to the cluster (rc: $rc), bailing out\"\n    fi\nfi\n\n# We start with a very high TTL, that long enough to accomodate a cluster stop.\n# As soon as the node will get offline, the other competing node will be entitled\n# to steal the lock, so they should never wait that long in practice.\nLOCK_TTL=600\n\n\ncase $ACTION in\n    --help) usage; exit 0;;\n    --acquire|-a) shutdown_lock_acquire ${LOCK_NAME} ${LOCK_OWNER} ${LOCK_TTL};;\n    --release|-r) shutdown_lock_release ${LOCK_NAME} ${LOCK_OWNER};;\n    *) error \"Invalid action\";;\nesac\nexit $?\n"}, "nova_statedir_ownership.py": {"mode": "0700", "content": "#!/usr/bin/python3\n#\n# Copyright 2018 Red Hat Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\nimport logging\nimport os\nimport pwd\nimport selinux\nimport stat\nimport sys\n\ndebug = os.getenv('__OS_DEBUG', 'false')\n\nif debug.lower() == 'true':\n    loglevel = logging.DEBUG\nelse:\n    loglevel = logging.INFO\n\nlogging.basicConfig(stream=sys.stdout, level=loglevel)\nLOG = logging.getLogger('nova_statedir')\n\n\nclass PathManager(object):\n    \"\"\"Helper class to manipulate ownership of a given path\"\"\"\n    def __init__(self, path):\n        self.path = path\n        self.uid = None\n        self.gid = None\n        self.is_dir = None\n        self.secontext = None\n        self._update()\n\n    def _update(self):\n        try:\n            statinfo = os.stat(self.path)\n            self.is_dir = stat.S_ISDIR(statinfo.st_mode)\n            self.uid = statinfo.st_uid\n            self.gid = statinfo.st_gid\n            self.secontext = selinux.lgetfilecon(self.path)[1]\n        except Exception:\n            LOG.exception('Could not update metadata for %s', self.path)\n            raise\n\n    def __str__(self):\n        return \"uid: {} gid: {} path: {}{}\".format(\n            self.uid,\n            self.gid,\n            self.path,\n            '/' if self.is_dir else ''\n        )\n\n    def has_owner(self, uid, gid):\n        return self.uid == uid and self.gid == gid\n\n    def has_either(self, uid, gid):\n        return self.uid == uid or self.gid == gid\n\n    def chown(self, uid, gid):\n        target_uid = -1\n        target_gid = -1\n        if self.uid != uid:\n            target_uid = uid\n        if self.gid != gid:\n            target_gid = gid\n        if (target_uid, target_gid) != (-1, -1):\n            LOG.info('Changing ownership of %s from %d:%d to %d:%d',\n                     self.path,\n                     self.uid,\n                     self.gid,\n                     self.uid if target_uid == -1 else target_uid,\n                     self.gid if target_gid == -1 else target_gid)\n            try:\n                os.chown(self.path, target_uid, target_gid)\n                self._update()\n            except Exception:\n                LOG.exception('Could not change ownership of %s: ',\n                              self.path)\n                raise\n        else:\n            LOG.info('Ownership of %s already %d:%d',\n                     self.path,\n                     uid,\n                     gid)\n\n    def chcon(self, context):\n        # If dir returns whether to recusively set context\n        try:\n            try:\n                selinux.lsetfilecon(self.path, context)\n                LOG.info('Setting selinux context of %s to %s',\n                     self.path, context)\n                return True\n            except OSError as e:\n                if self.is_dir and e.errno == 95:\n                    # Operation not supported, assume NFS mount and skip\n                    LOG.info('Setting selinux context not supported for %s',\n                             self.path)\n                    return False\n                else:\n                    raise\n        except Exception:\n            LOG.exception('Could not set selinux context of %s to %s:',\n                          self.path, context)\n            raise\n\n\nclass NovaStatedirOwnershipManager(object):\n    \"\"\"Class to manipulate the ownership of the nova statedir (/var/lib/nova).\n\n       The nova uid/gid differ on the host and container images. An upgrade\n       that switches from host systemd services to docker requires a change in\n       ownership. Previously this was a naive recursive chown, however this\n       causes issues if nova instance are shared via an NFS mount: any open\n       filehandles in qemu/libvirt fail with an I/O error (LP1778465).\n\n       Instead the upgrade/FFU ansible tasks now lay down a marker file when\n       stopping and disabling the host systemd services. We use this file to\n       determine the host nova uid/gid. We then walk the tree and update any\n       files that have the host uid/gid to the docker nova uid/gid. As files\n       owned by root/qemu etc... are ignored this avoids the issues with open\n       filehandles. The marker is removed once the tree has been walked.\n\n       For subsequent runs, or for a new deployment, we simply ensure that the\n       docker nova user/group owns all directories. This is required as the\n       directories are created with root ownership in host_prep_tasks (the\n       docker nova uid/gid is not known in this context).\n    \"\"\"\n    def __init__(self, statedir, upgrade_marker='upgrade_marker',\n                 nova_user='nova', secontext_marker='../_nova_secontext',\n                 exclude_paths=None):\n        self.statedir = statedir\n        self.nova_user = nova_user\n\n        self.upgrade_marker_path = os.path.join(statedir, upgrade_marker)\n        self.secontext_marker_path = os.path.normpath(os.path.join(statedir, secontext_marker))\n        self.upgrade = os.path.exists(self.upgrade_marker_path)\n\n        self.exclude_paths = [self.upgrade_marker_path]\n        if exclude_paths is not None:\n            for p in exclude_paths:\n                if not p.startswith(os.path.sep):\n                    p = os.path.join(self.statedir, p)\n                self.exclude_paths.append(p)\n\n        self.target_uid, self.target_gid = self._get_nova_ids()\n        self.previous_uid, self.previous_gid = self._get_previous_nova_ids()\n        self.id_change = (self.target_uid, self.target_gid) != \\\n            (self.previous_uid, self.previous_gid)\n        self.target_secontext = self._get_secontext()\n\n    def _get_nova_ids(self):\n        nova_uid, nova_gid = pwd.getpwnam(self.nova_user)[2:4]\n        return nova_uid, nova_gid\n\n    def _get_previous_nova_ids(self):\n        if self.upgrade:\n            statinfo = os.stat(self.upgrade_marker_path)\n            return statinfo.st_uid, statinfo.st_gid\n        else:\n            return self._get_nova_ids()\n\n    def _get_secontext(self):\n        if os.path.exists(self.secontext_marker_path):\n            return selinux.lgetfilecon(self.secontext_marker_path)[1]\n        else:\n            return None\n\n    def _walk(self, top, chcon=True):\n        for f in os.listdir(top):\n            pathname = os.path.join(top, f)\n\n            if pathname in self.exclude_paths:\n                continue\n\n            try:\n                pathinfo = PathManager(pathname)\n                LOG.info(\"Checking %s\", pathinfo)\n                if pathinfo.is_dir:\n                    # Always chown the directories\n                    pathinfo.chown(self.target_uid, self.target_gid)\n                    chcon_r = chcon\n                    if chcon:\n                        chcon_r = pathinfo.chcon(self.target_secontext)\n                    self._walk(pathname, chcon_r)\n                elif self.id_change:\n                    # Only chown files if it's an upgrade and the file is owned by\n                    # the host nova uid/gid\n                    pathinfo.chown(\n                        self.target_uid if pathinfo.uid == self.previous_uid\n                        else pathinfo.uid,\n                        self.target_gid if pathinfo.gid == self.previous_gid\n                        else pathinfo.gid\n                    )\n                    if chcon:\n                        pathinfo.chcon(self.target_secontext)\n            except Exception:\n                # Likely to have been caused by external systems\n                # interacting with this directory tree,\n                # especially on NFS e.g snapshot dirs.\n                # Just ignore it and continue on to the next entry\n                continue\n\n    def run(self):\n        LOG.info('Applying nova statedir ownership')\n        LOG.info('Target ownership for %s: %d:%d',\n                 self.statedir,\n                 self.target_uid,\n                 self.target_gid)\n\n        pathinfo = PathManager(self.statedir)\n        LOG.info(\"Checking %s\", pathinfo)\n        pathinfo.chown(self.target_uid, self.target_gid)\n        chcon = self.target_secontext is not None\n\n        if chcon:\n            pathinfo.chcon(self.target_secontext)\n\n        self._walk(self.statedir, chcon)\n\n        if self.upgrade:\n            LOG.info('Removing upgrade_marker %s',\n                     self.upgrade_marker_path)\n            os.unlink(self.upgrade_marker_path)\n\n        LOG.info('Nova statedir ownership complete')\n\n\ndef get_exclude_paths():\n    exclude_paths = os.environ.get('NOVA_STATEDIR_OWNERSHIP_SKIP')\n    if exclude_paths is not None:\n        exclude_paths = exclude_paths.split(os.pathsep)\n    return exclude_paths\n\n\nif __name__ == '__main__':\n    NovaStatedirOwnershipManager('/var/lib/nova', exclude_paths=get_exclude_paths()).run()\n"}, "nova_wait_for_compute_service.py": {"mode": "0755", "content": "#!/usr/bin/python3\n#\n# Copyright 2018 Red Hat Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\nimport argparse\nimport logging\nimport os\nimport six\nimport socket\nimport sys\nimport time\n\n\nfrom keystoneauth1 import loading\nfrom keystoneauth1 import session\n\nfrom novaclient import client\n\n# In python3 SafeConfigParser was renamed to ConfigParser and the default\n# for duplicate options default to true. In case of nova it is valid to\n# have duplicate option lines, e.g. passthrough_whitelist which leads to\n# issues reading the nova.conf\n# https://bugs.launchpad.net/tripleo/+bug/1827775\nif six.PY3:\n    from six.moves.configparser import ConfigParser\n    config = ConfigParser(strict=False)\nelse:\n    from six.moves.configparser import SafeConfigParser\n    config = SafeConfigParser()\n\ndebug = os.getenv('__OS_DEBUG', 'false')\n\nif debug.lower() == 'true':\n    loglevel = logging.DEBUG\nelse:\n    loglevel = logging.INFO\n\nlogging.basicConfig(stream=sys.stdout, level=loglevel)\nLOG = logging.getLogger('nova_wait_for_compute_service')\n\niterations = 60\ntimeout = 10\nnova_cfg = '/etc/nova/nova.conf'\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser(usage='%(prog)s [options]')\n    parser.add_argument('-k', '--insecure',\n                        action=\"store_false\",\n                        dest='insecure',\n                        default=True,\n                        help='Allow insecure connection when using SSL')\n\n    args = parser.parse_args()\n    LOG.debug('Running with parameter insecure = %s',\n              args.insecure)\n\n    if os.path.isfile(nova_cfg):\n        try:\n            config.read(nova_cfg)\n        except Exception:\n            LOG.exception('Error while reading nova.conf:')\n    else:\n        LOG.error('Nova configuration file %s does not exist', nova_cfg)\n        sys.exit(1)\n\n    my_host = config.get('DEFAULT', 'host')\n    if not my_host:\n        # If host isn't set nova defaults to this\n        my_host = socket.gethostname()\n\n    loader = loading.get_plugin_loader('password')\n    auth = loader.load_from_options(\n        auth_url=config.get('neutron',\n                            'auth_url'),\n        username=config.get('neutron',\n                            'username'),\n        password=config.get('neutron',\n                            'password'),\n        project_name=config.get('neutron',\n                                'project_name'),\n        project_domain_name=config.get('neutron',\n                                       'project_domain_name'),\n        user_domain_name=config.get('neutron',\n                                    'user_domain_name'))\n    sess = session.Session(auth=auth, verify=args.insecure)\n    nova = client.Client('2.11', session=sess, endpoint_type='internal',\n                         region_name=config.get('neutron', 'region_name'))\n\n    # Wait until this host is listed in the service list\n    for i in range(iterations):\n        try:\n            service_list = nova.services.list(binary='nova-compute')\n            for entry in service_list:\n                host = getattr(entry, 'host', '')\n                zone = getattr(entry, 'zone', '')\n                if host == my_host and zone != 'internal':\n                    LOG.info('Nova-compute service registered')\n                    sys.exit(0)\n            LOG.info('Waiting for nova-compute service to register')\n        except Exception:\n            LOG.exception(\n                'Error while waiting for nova-compute service to register')\n        time.sleep(timeout)\nsys.exit(1)\n\n# vim: set et ts=4 sw=4 :\n"}}, "docker_config": {"step_2": {"nova_compute_init_log": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "net": "none", "privileged": false, "user": "root", "volumes": ["/var/log/containers/nova:/var/log/nova:z"], "command": ["/bin/bash", "-c", "chown -R nova:nova /var/log/nova"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}}, "step_3": {"nova_statedir_owner": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "net": "none", "user": "root", "security_opt": ["label=disable"], "privileged": false, "detach": false, "volumes": ["/var/lib/nova:/var/lib/nova:shared", "/var/lib/_nova_secontext:/var/lib/_nova_secontext:shared,z", "/var/lib/container-config-scripts:/container-config-scripts:z"], "command": "/container-config-scripts/pyshim.sh /container-config-scripts/nova_statedir_ownership.py", "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821", "__OS_DEBUG": "true", "NOVA_STATEDIR_OWNERSHIP_SKIP": "triliovault-mounts"}}}, "step_5": {"nova_compute": {"start_order": 3, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "ulimit": ["nofile=131072", "memlock=67108864"], "ipc": "host", "net": "host", "privileged": true, "user": "nova", "restart": "always", "depends_on": ["tripleo_nova_libvirt.target"], "healthcheck": {"test": "/openstack/healthcheck 5672"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/nova:/var/log/nova", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/var/lib/kolla/config_files/nova_compute.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/config-data/puppet-generated/iscsid/etc/iscsi:/var/lib/kolla/config_files/src-iscsid:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/dev:/dev", "/lib/modules:/lib/modules:ro", "/run:/run", "/run/nova:/run/nova:z", "/var/lib/iscsi:/var/lib/iscsi:z", "/var/lib/libvirt:/var/lib/libvirt:shared", "/sys/class/net:/sys/class/net", "/sys/bus/pci:/sys/bus/pci", "/boot:/boot:ro", "/var/lib/nova:/var/lib/nova:shared"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS", "LIBGUESTFS_BACKEND": "direct"}}, "nova_wait_for_compute_service": {"start_order": 4, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "net": "host", "detach": false, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/kolla/config_files/nova_compute_wait_for_compute_service.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/log/containers/nova:/var/log/nova", "/var/lib/container-config-scripts:/container-config-scripts"], "user": "nova", "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS", "__OS_DEBUG": "true"}}}}, "host_prep_tasks": [{"name": "create persistent directories", "file": {"path": "{{ item.path }}", "setype": "{{ item.setype }}", "state": "directory", "mode": "{{ item.mode }}"}, "with_items": [{"path": "/var/log/containers/nova", "setype": "container_file_t", "mode": "0750"}]}, {"name": "Check for /var/lib/nova/instances directory exitance", "stat": {"path": "/var/lib/nova/instances"}, "register": "check_nova_instances_result"}, {"name": "create persistent directories", "file": {"path": "{{ item.path }}", "state": "directory", "setype": "{{ item.setype | default(omit) }}"}, "with_items": [{"path": "/var/lib/nova", "setype": "container_file_t"}, {"path": "/var/lib/_nova_secontext", "setype": "container_file_t"}, {"path": "/var/lib/nova/instances", "setype": "container_file_t"}, {"path": "/var/lib/libvirt", "setype": "container_file_t"}, {"path": "/etc/tmpfiles.d"}]}, {"name": "ensure /run/nova is present upon reboot", "copy": {"dest": "/etc/tmpfiles.d/run-nova.conf", "content": "d /run/nova 0777 root root - -\n"}}, {"name": "create tempfiles", "command": "systemd-tmpfiles --create"}, {"name": "Mount Nova NFS Share", "vars": {"nfs_backend_enable": false, "nfs_share": "", "nfs_options": "context=system_u:object_r:nfs_t:s0", "nfs_vers": "4.2"}, "mount": {"name": "/var/lib/nova/instances", "state": "mounted", "fstype": "nfs4", "src": "{{nfs_share}}", "opts": "_netdev,bg,{{nfs_options}},nfsvers={{nfs_vers}}"}, "when": "nfs_backend_enable|bool"}, {"name": "delay installation of systemd-container", "when": "check_nova_instances_result.stat.exists", "block": [{"name": "check systemd-container package installed or not", "package": {"name": "systemd-container", "state": "present"}, "check_mode": true, "register": "is_systemd_container_package", "failed_when": false}, {"name": "get latest package from downloaded package versions", "shell": "ls -1t /var/tmp/systemd-container* | head -1", "register": "latest_systemd_container_package", "when": ["is_systemd_container_package is defined", "('changed' in is_systemd_container_package)", "is_systemd_container_package.changed"], "failed_when": false}, {"name": "Install systemd-container package on boot", "copy": {"dest": "/etc/systemd/system/install-systemd-container.service", "content": "[Unit]\nDescription=Install systemd container package on system boot\nBefore=tripleo_nova_virtqemud.service\n\n[Service]\nType=oneshot\nExecStart=/usr/bin/rpm -ivh {{ latest_systemd_container_package.stdout }}\nExecStartPost=rm -f /var/tmp/systemd-container*\n\n[Install]\nWantedBy=multi-user.target\n"}, "when": ["latest_systemd_container_package is defined", "('stdout' in latest_systemd_container_package)", "is_systemd_container_package is defined", "('changed' in is_systemd_container_package)", "is_systemd_container_package.changed"]}, {"name": "enable install-systemd-container on compute boot", "systemd": {"name": "install-systemd-container", "state": "stopped", "enabled": true, "daemon_reload": true}, "when": ["is_systemd_container_package is defined", "('changed' in is_systemd_container_package)", "is_systemd_container_package.changed"]}, {"name": "check if install-systemd-container service exists", "stat": {"path": "/etc/systemd/system/install-systemd-container.service"}, "register": "install_systemd_container_result"}, {"name": "disable and mask install-systemd-container on compute boot", "systemd": {"name": "install-systemd-container", "enabled": false, "masked": true, "daemon_reload": true}, "when": ["is_systemd_container_package is defined", "('changed' in is_systemd_container_package)", "not is_systemd_container_package.changed", "install_systemd_container_result.stat.exists"]}]}, {"name": "is Nova Resume Guests State On Host Boot enabled", "set_fact": {"resume_guests_state_on_host_boot_enabled": false}}, {"name": "install libvirt-guests systemd unit file (docker)", "when": ["resume_guests_state_on_host_boot_enabled|bool", "container_cli == 'docker'"], "block": [{"name": "libvirt-guests unit to stop nova_compute container before shutdown VMs", "copy": {"dest": "/etc/systemd/system/libvirt-guests.service", "content": "[Unit]\nDescription=Suspend/Resume Running libvirt Guests\nAfter=network.target\nAfter=time-sync.target\nAfter=virt-guest-shutdown.target\nAfter=docker.service\nAfter=tripleo-container-shutdown.service\nAfter=rhel-push-plugin.service\nDocumentation=man:libvirtd(8)\nDocumentation=https://libvirt.org\n\n[Service]\nEnvironmentFile=-/var/lib/config-data/puppet-generated/nova_libvirt/etc/sysconfig/libvirt-guests\n# Hack just call traditional service until we factor\n# out the code\nExecStart=/bin/{{container_cli}} exec nova_libvirt /bin/sh -x /usr/libexec/libvirt-guests.sh start\nExecStop=/bin/{{container_cli}} stop nova_compute\nExecStop=/bin/{{container_cli}}  exec nova_libvirt /bin/sh -x /usr/libexec/libvirt-guests.sh stop\nType=oneshot\nRemainAfterExit=yes\nStandardOutput=journal+console\nTimeoutStopSec=0\n\n[Install]\nWantedBy=multi-user.target\n"}}, {"name": "Making sure virt-guest-shutdown.target is present", "copy": {"dest": "/etc/systemd/system/virt-guest-shutdown.target", "content": "[Unit]\nDescription=Libvirt guests shutdown\nDocumentation=https://libvirt.org\nAfter=systemd-machined.service\nAfter=network-online.target\nAfter=tripleo_nova_libvirt.target\nBefore=tripleo_nova_compute.service\n"}}, {"name": "libvirt-guests enable VM shutdown on compute reboot/shutdown", "systemd": {"name": "libvirt-guests", "enabled": true, "daemon_reload": true}}]}, {"name": "install tripleo_nova_libvirt_guests systemd unit file (podman)", "when": ["resume_guests_state_on_host_boot_enabled|bool", "container_cli == 'podman'"], "block": [{"name": "libvirt-guests unit to stop nova_compute container before shutdown VMs (monolithic libvirt)", "copy": {"dest": "/etc/systemd/system/tripleo_nova_libvirt_guests.service", "content": "[Unit]\nDescription=Suspend libvirt Guests in tripleo\nRequires=virt-guest-shutdown.target\nAfter=systemd-machined.service\nAfter=network-online.target\nAfter=tripleo_nova_libvirt.target\nBefore=tripleo_nova_compute.service\nDocumentation=man:libvirtd(8)\nDocumentation=https://libvirt.org\n\n[Service]\nEnvironmentFile=-/etc/sysconfig/libvirt-guests\nExecStart=/bin/podman exec nova_libvirt /bin/rm -f /var/lib/libvirt/libvirt-guests\nExecStop=/bin/podman exec nova_libvirt /bin/sh -x /usr/libexec/libvirt-guests.sh shutdown\nType=oneshot\nRemainAfterExit=yes\nStandardOutput=journal+console\nTimeoutStopSec=0\n\n[Install]\nWantedBy=multi-user.target\n"}, "when": "tripleo_nova_libvirt_virsh_container | default('nova_libvirt') == 'nova_libvirt'"}, {"name": "libvirt-guests unit to stop nova_compute container before shutdown VMs (modular libvirt)", "copy": {"dest": "/etc/systemd/system/tripleo_nova_libvirt_guests.service", "content": "[Unit]\nDescription=Suspend libvirt Guests in tripleo\nRequires=virt-guest-shutdown.target\nAfter=systemd-machined.service\nAfter=network-online.target\nAfter=tripleo_nova_libvirt.target\nBefore=tripleo_nova_compute.service\nDocumentation=man:libvirtd(8)\nDocumentation=https://libvirt.org\n\n[Service]\nEnvironmentFile=-/etc/sysconfig/libvirt-guests\nExecStart=/bin/podman exec nova_virtproxyd /bin/rm -f /var/lib/libvirt/libvirt-guests\nExecStop=/bin/podman exec nova_virtproxyd /bin/sh -x /usr/libexec/libvirt-guests.sh shutdown\nType=oneshot\nRemainAfterExit=yes\nStandardOutput=journal+console\nTimeoutStopSec=0\n\n[Install]\nWantedBy=multi-user.target\n"}, "when": "tripleo_nova_libvirt_virsh_container | default('nova_libvirt') != 'nova_libvirt'"}, {"name": "Making sure virt-guest-shutdown.target is present", "copy": {"dest": "/etc/systemd/system/virt-guest-shutdown.target", "content": "[Unit]\nDescription=Libvirt guests shutdown\nDocumentation=https://libvirt.org\nAfter=systemd-machined.service\nAfter=network-online.target\nAfter=tripleo_nova_libvirt.target\nBefore=tripleo_nova_compute.service\n"}}, {"name": "tripleo_nova_libvirt_guests enable VM shutdown on compute reboot/shutdown", "systemd": {"name": "tripleo_nova_libvirt_guests", "enabled": true, "daemon_reload": true}}]}, {"name": "ensure ceph configurations exist", "file": {"path": "/var/lib/tripleo-config/ceph", "state": "directory"}}, {"name": "enable virt_sandbox_use_netlink for healthcheck", "seboolean": {"name": "virt_sandbox_use_netlink", "persistent": true, "state": true}, "when": ["ansible_facts.selinux is defined", "ansible_facts.selinux.status == \"enabled\""]}, {"name": "Do we prepend nova startup with a delay", "set_fact": {"nova_compute_delay": 0}}, {"name": "install nova-compute delay wrapper script", "copy": {"content": "#!/usr/libexec/platform-python\n\"\"\"\nThis wrapper was created to add an optional delay to the startup of nova-compute.\nWe know that instances will fail to boot, after a compute reboot, if ceph is not\nhealthy.\n\nIdeally, we would poll ceph to get its health, but it's not guaranteed that the\ncompute node will have access to the keys.\n\"\"\"\n\nimport os\nimport sys\nimport time\nimport logging\nimport argparse\n\nparser = argparse.ArgumentParser(description='Process some integers.')\nparser.add_argument('--config-file', dest='nova_config', action='store',\n                    default=\"/etc/nova/nova.conf\",\n                    help='path to nova configuration (default: /etc/nova/nova.conf)')\nparser.add_argument('--nova-binary', dest='nova_binary', action='store',\n                    default=\"/usr/bin/nova-compute\",\n                    help='path to nova compute binary (default: /usr/bin/nova-compute)')\nparser.add_argument('--delay', dest='delay', action='store',\n                    default=120, type=int,\n                    help='Number of seconds to wait until nova-compute is started')\nparser.add_argument('--state-dir', dest='state_dir', action='store',\n                    default=\"/run/nova/startup\", help='state-file directory')\nparser.add_argument('--state-file', dest='state_file', action='store',\n                    default=\"nova-compute-delayed\",\n                    help='file exists if we already delayed nova-compute startup')\n\n\nsections = {}\n(args, remaining) = parser.parse_known_args(sys.argv)\n\nreal_args = [args.nova_binary, '--config-file', args.nova_config]\nreal_args.extend(remaining[1:])\n\nif not os.path.isdir(args.state_dir):\n  os.makedirs(args.state_dir, mode = 0o751)\n\nstate_file_name = os.path.join(args.state_dir, args.state_file)\n\nif not os.path.isfile(state_file_name):\n    logging.info(\"Delaying nova-compute startup by %s seconds\" % args.delay)\n    time.sleep(args.delay)\n    open(state_file_name, 'a').close()\n\nlogging.info(\"Executing %s\" % real_args)\nos.execv(args.nova_binary, real_args)\n", "dest": "/var/lib/nova/delay-nova-compute", "mode": 493}, "when": "nova_compute_delay|int > 0"}, {"name": "Is irqbalance enabled", "set_fact": {"compute_irqbalance_disabled": false}}, {"name": "disable irqbalance service on compute", "when": "compute_irqbalance_disabled|bool", "service": {"name": "irqbalance.service", "state": "stopped", "enabled": false}}], "deploy_steps_tasks": [{"name": "install systemd-container for a greenfield", "when": ["step|int == 1", "not check_nova_instances_result.stat.exists"], "package": {"name": "systemd-container", "state": "present"}}, {"name": "validate nova-compute container state", "containers.podman.podman_container_info": {"name": "nova_compute"}, "register": "nova_compute_infos", "failed_when": ["nova_compute_infos.containers.0.Healthcheck.Status is defined", "'healthy' not in nova_compute_infos.containers.0.Healthcheck.Status"], "retries": 10, "delay": 30, "tags": ["opendev-validation", "opendev-validation-nova"], "when": ["container_cli == 'podman'", "not container_healthcheck_disabled", "step|int == 6"]}, {"name": "manage PMEM namespaces for vPMEM", "include_role": {"name": "tripleo_nvdimm"}, "vars": {"tripleo_nvdimm_pmem_namespaces": ""}, "when": ["step|int == 1", "tripleo_nvdimm_pmem_namespaces != ''"]}, {"name": "manage OS version 9 specific sysctls", "when": ["step|int == 1", "ansible_facts['os_family'] == 'RedHat'", "ansible_facts['distribution_major_version'] is version('9', '==')"], "block": [{"name": "Enable post-copy by setting unprivileged_userfaultfd", "sysctl": {"name": "vm.unprivileged_userfaultfd", "value": 1, "sysctl_set": true, "sysctl_file": "/etc/sysctl.d/99-tripleo-postcopy.conf", "state": "present", "reload": true}}]}, {"name": "enable/disable ksm", "when": ["step|int == 1"], "block": [{"name": "is KSM enabled", "set_fact": {"compute_ksm_enabled": false}}, {"name": "disable KSM on compute", "when": "not compute_ksm_enabled|bool", "block": [{"name": "Check for ksm", "shell": "systemctl is-active ksm.service || systemctl is-enabled ksm.service", "become": true, "failed_when": false, "register": "ksm_service_check"}, {"name": "disable KSM services", "service": {"name": "{{ item }}", "state": "stopped", "enabled": false}, "with_items": ["ksm.service", "ksmtuned.service"], "when": ["ksm_service_check.rc is defined", "ksm_service_check.rc == 0"], "register": "ksmdisabled"}, {"name": "delete PageKSM after disable ksm on compute", "command": "echo 2 >/sys/kernel/mm/ksm/run", "when": ["ksm_service_check.rc is defined", "ksm_service_check.rc == 0", "ksmdisabled is changed"]}]}, {"name": "enable KSM on compute", "when": "compute_ksm_enabled|bool", "block": [{"name": "make sure package providing ksmtuned is installed (RHEL8 or CentOS8)", "package": {"name": "qemu-kvm-common", "state": "present"}, "when": ["ansible_facts['distribution_major_version'] is version('8', '==')"]}, {"name": "make sure package providing ksmtuned is installed (RHEL9 or CentOS9)", "package": {"name": "ksmtuned", "state": "present"}, "when": ["ansible_facts['distribution_major_version'] is version('9', '==')"]}, {"name": "enable ksmtunded", "service": {"name": "{{ item }}", "state": "started", "enabled": true}, "with_items": ["ksm.service", "ksmtuned.service"]}]}]}], "external_post_deploy_tasks": [{"block": [{"name": "is additonal Cell?", "set_fact": {"nova_additional_cell": false}}, {"name": "check if discover hosts is required", "when": ["not nova_additional_cell|bool", "nova_cellv2_discovery_done is not defined"], "block": [{"name": "discover via nova_manager?", "set_fact": {"nova_cellv2_discovery_delegate_host": "{{ groups['nova_manager'][0] }}", "nova_cellv2_discovery_container": "nova_manager"}, "when": ["groups['nova_manager'] is defined and (groups['nova_manager']|length>0)"]}, {"name": "discover via nova_api?", "set_fact": {"nova_cellv2_discovery_delegate_host": "{{ groups['nova_api'][0] }}", "nova_cellv2_discovery_container": "nova_api"}, "when": ["nova_cellv2_discovery_delegate_host is not defined", "groups['nova_api'] is defined and (groups['nova_api']|length>0)"]}, {"name": "Warn if no discovery host available", "fail": {"msg": "No hosts available to run nova cell_v2 host discovery."}, "ignore_errors": true, "when": ["nova_cellv2_discovery_delegate_host is not defined"]}, {"name": "Discovering nova hosts", "command": "{{ container_cli }} exec {{ nova_cellv2_discovery_container }} nova-manage cell_v2 discover_hosts --by-service", "become": true, "changed_when": false, "delegate_to": "{{ nova_cellv2_discovery_delegate_host }}", "when": ["nova_cellv2_discovery_delegate_host is defined"]}, {"set_fact": {"nova_cellv2_discovery_done": true}}]}]}], "upgrade_tasks": [{"name": "Remove openstack-nova-compute and python-nova package during upgrade", "package": {"name": ["openstack-nova-compute", "python-nova"], "state": "removed"}, "failed_when": false, "when": "step|int == 2"}, {"name": "nova_compute pre system_upgrade tasks", "tags": ["never", "system_upgrade", "system_upgrade_run", "system_upgrade_nfsmounts"], "when": ["step|int == 3", "upgrade_leapp_enabled"], "block": [{"name": "Unmount Nova NFS Share", "vars": {"nfs_backend_enable": false}, "mount": {"name": "/var/lib/nova/instances", "state": "absent", "fstype": "nfs4"}, "when": "nfs_backend_enable|bool"}]}, {"name": "nova_compute post system_upgrade tasks", "tags": ["never", "system_upgrade", "system_upgrade_run", "system_upgrade_nfsmounts"], "when": ["step|int == 5", "upgrade_leapp_enabled"], "block": [{"name": "Mount Nova NFS Share", "vars": {"nfs_backend_enable": false, "nfs_share": "", "nfs_options": "context=system_u:object_r:nfs_t:s0", "nfs_vers": "4.2"}, "mount": {"name": "/var/lib/nova/instances", "state": "mounted", "fstype": "nfs4", "src": "{{nfs_share}}", "opts": "_netdev,bg,{{nfs_options}},nfsvers={{nfs_vers}}"}, "when": "nfs_backend_enable|bool"}]}], "update_tasks": [{"name": "Remove openstack-nova-compute and python-nova package during upgrade", "package": {"name": ["openstack-nova-compute", "python-nova"], "state": "removed"}, "failed_when": false, "when": "step|int == 2"}], "post_update_tasks": [{"name": "Ensure instanceha directory is purged", "when": "step|int == 1", "become": true, "file": {"path": "/var/lib/nova/instanceha", "state": "absent"}}], "post_upgrade_tasks": [{"name": "Ensure instanceha directory is purged", "when": "step|int == 1", "become": true, "file": {"path": "/var/lib/nova/instanceha", "state": "absent"}}], "scale_tasks": [{"when": ["step|int == 1", "container_cli == 'podman'"], "tags": "down", "become": true, "environment": {"OS_CLOUD": "standalone"}, "block": [{"name": "Get nova-compute service ID", "command": "openstack compute service list --service nova-compute --column ID --column Host --format yaml", "register": "nova_compute_service_result", "delegate_to": "{{ groups['Undercloud'] | first }}", "check_mode": false, "changed_when": false}, {"name": "is additional Cell?", "set_fact": {"is_additional_cell": false}}, {"name": "Set fact for nova_compute services", "set_fact": {"nova_compute_service": "{{ nova_compute_service_result.stdout | from_yaml | selectattr('Host', 'match', ansible_facts['fqdn'] ~ '.*') | list }}"}, "delegate_to": "{{ groups['Undercloud'] | first }}", "check_mode": false}, {"name": "Check search output", "fail": {"msg": "Found multiple `{{ ansible_facts['fqdn'] }}`, which is unexpected. This means that the FQDN of the selected device to disable is either wrong or is sharing a name with another host, which is also wrong. Please correct this issue before continuing. Nova service list return data can be found here -> {{ nova_compute_service }}."}, "when": ["(nova_compute_service | length) > 1"]}, {"name": "Disable nova services", "when": ["(nova_compute_service | length) == 1"], "block": [{"name": "Disable nova-compute service", "command": "openstack compute service set {{ nova_compute_service[0].Host }} nova-compute --disable", "delegate_to": "{{ groups['Undercloud'] | first }}", "check_mode": false, "when": ["not is_additional_cell|bool"]}, {"name": "Stop nova-compute container", "service": {"name": "tripleo_nova_compute", "state": "stopped", "enabled": false}, "become": true, "register": "stop_nova_compute", "failed_when": "('msg' in stop_nova_compute and 'Could not find the requested service tripleo_nova_compute' not in stop_nova_compute.msg) or ('rc' in stop_nova_compute and stop_nova_compute.rc != 0)"}, {"name": "Delete nova-compute service", "command": "openstack compute service delete {{ nova_compute_service[0].ID }}", "delegate_to": "{{ groups['Undercloud'] | first }}", "check_mode": false}]}]}]}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-52-7jfofxryzovo/13aa803e-199f-4c85-a4c5-2f1799596b17"}


created_at: 2025-12-01 09:42:19.140737
data:
  {"type": "json", "value": {"vhostuser_socket_group": "qemu", "nova_libvirt_opt_volumes": [], "ContainerNovaLibvirtImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ContainerNovaLibvirtConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1"}}


created_at: 2025-12-01 09:42:25.214498
data:
  {"value": {"vhostuser_socket_group": "qemu", "nova_libvirt_opt_volumes": [], "ContainerNovaLibvirtImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ContainerNovaLibvirtConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1"}}


created_at: 2025-12-01 09:42:25.258678
data:
  {"update_tasks": [{"name": "check systemd-container package present or not", "package": {"name": "systemd-container", "state": "present"}, "check_mode": true, "register": "is_systemd_container_package"}, {"name": "download systemd-container package if not present", "yum": {"name": "systemd-container", "state": "present", "download_only": true, "download_dir": "/var/tmp/"}, "when": "is_systemd_container_package.changed"}], "volumes": ["/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z"], "kolla_permissions": [{"path": "/etc/ceph/ceph.client.openstack.keyring", "owner": "nova:nova", "perm": "0600"}], "kolla_config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-ceph/", "dest": "/etc/ceph/", "merge": true, "preserve_properties": true}], "config_settings": {"nova::compute::libvirt::qemu::memory_backing_dir": ""}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-53-xxifwlu6bbre-NovaLibvirtCommon-wzp6fn3t35td/ba001afb-b462-4f44-9135-b928f93775e2"}


created_at: 2025-12-01 09:42:25.304182
data:
  {"container_puppet_apply_volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/var/lib/container-config-scripts/container_puppet_apply.sh:/container_puppet_apply.sh:ro", "/etc/puppet:/tmp/puppet-etc:ro", "/usr/share/openstack-puppet/modules:/usr/share/openstack-puppet/modules:ro"], "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro"], "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-53-xxifwlu6bbre-ContainersCommon-qjo77zvzpvbc/e29f7015-09f1-480e-8d1a-cbc71d0c73e3"}


created_at: 2025-12-01 09:42:25.375511
data:
  {"tuple:('role_data', 'config_settings')": {"nova::my_ip": "%{hiera('internal_api')}", "nova::rabbit_use_ssl": "False", "nova::keystone::service_user::send_service_user_token": true, "nova::keystone::service_user::project_name": "service", "nova::keystone::service_user::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::keystone::service_user::auth_url": "http://172.17.0.2:5000", "nova::keystone::service_user::region_name": "regionOne", "nova::placement::project_name": "service", "nova::placement::password": "dYVRSnGa4R5DjmK0t4f9aWqpK", "nova::placement::auth_url": "http://172.17.0.2:5000", "nova::placement::region_name": "regionOne", "nova::placement::valid_interfaces": "internal", "nova::os_region_name": "regionOne", "nova::logging::debug": true, "nova::purge_config": false, "nova::network::neutron::project_name": "service", "nova::network::neutron::username": "neutron", "nova::network::neutron::region_name": "regionOne", "nova::dhcp_domain": "", "nova::network::neutron::password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "nova::network::neutron::auth_url": "http://172.17.0.2:5000/v3", "nova::network::neutron::valid_interfaces": "internal", "nova::glance::valid_interfaces": "internal", "nova::rabbit_heartbeat_timeout_threshold": 60, "nova::cinder_catalog_info": "volumev3:cinderv3:internalURL", "nova::host": "%{hiera('fqdn_canonical')}", "nova::notify_on_state_change": "vm_and_task_state", "nova::notification_driver": ["messagingv2"], "nova::notification_format": "unversioned", "nova::network::neutron::auth_type": "v3password", "nova::db::database_db_max_retries": -1, "nova::db::database_max_retries": -1, "nova::network::neutron::ovs_bridge": "br-int", "nova::compute::sync_power_state_interval": 600, "nova_is_additional_cell": false, "nova::cross_az_attach": true, "nova::cache::enabled": true, "nova::cache::tls_enabled": false, "nova::cache::backend": "dogpile.cache.memcached", "nova::rabbit_heartbeat_in_pthread": false, "nova::ovsdb_connection": ""}, "tuple:('role_data', 'config_settings', 'nova::logging::debug')": true, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-53-xxifwlu6bbre-NovaBase-nnpdze23cp26/ed945cbf-b4b5-49a1-b10f-027eb6246324"}


created_at: 2025-12-01 09:42:25.413677
data:
  {"volumes": ["/var/log/containers/libvirt:/var/log/libvirt:shared,z"], "host_prep_tasks": [{"name": "create persistent directories", "file": {"path": "{{ item.path }}", "setype": "{{ item.setype }}", "state": "directory", "mode": "{{ item.mode }}"}, "with_items": [{"path": "/var/log/containers/libvirt", "setype": "container_file_t", "mode": "0750"}]}], "config_settings": {"nova::compute::libvirt::log_outputs": "1:file:/var/log/libvirt/libvirtd.log", "nova::compute::libvirt::virtlogd::log_outputs": "1:file:/var/log/libvirt/virtlogd.log", "nova::compute::libvirt::virtsecretd::log_outputs": "1:file:/var/log/libvirt/virtsecretd.log", "nova::compute::libvirt::virtnodedevd::log_outputs": "1:file:/var/log/libvirt/virtnodedevd.log", "nova::compute::libvirt::virtqemud::log_outputs": "1:file:/var/log/libvirt/virtqemud.log", "nova::compute::libvirt::virtproxyd::log_outputs": "1:file:/var/log/libvirt/virtproxyd.log", "nova::compute::libvirt::virtstoraged::log_outputs": "1:file:/var/log/libvirt/virtstoraged.log"}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-53-xxifwlu6bbre-NovaLibvirtLogging-db5cvti5elhr/8575bb10-d1c0-4031-bbc3-c861a0eed61a"}


created_at: 2025-12-01 09:42:25.432624
data:
  {"tuple:('role_data', 'step_config')": null, "tuple:('role_data', 'docker_config')": {"step_2": {"nova_virtqemud_init_logs": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "net": "none", "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "user": "root", "volumes": ["/var/log/containers/libvirt/swtpm:/var/log/swtpm:shared,z"], "command": ["/bin/bash", "-c", "chown -R tss:tss /var/log/swtpm"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}, "create_virtlogd_wrapper": {"start_order": 1, "detach": false, "cgroupns": "host", "net": "host", "pid": "host", "user": "root", "command": ["/container_puppet_apply.sh", "4", "file", "include ::tripleo::profile::base::nova::virtlogd_wrapper"], "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/var/lib/container-config-scripts/container_puppet_apply.sh:/container_puppet_apply.sh:ro", "/etc/puppet:/tmp/puppet-etc:ro", "/usr/share/openstack-puppet/modules:/usr/share/openstack-puppet/modules:ro", "/var/lib/container-config-scripts:/var/lib/container-config-scripts:shared,z"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}}, "step_3": {"nova_virtlogd_wrapper": {"start_order": 0, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtlogd.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/container-config-scripts/virtlogd_wrapper:/usr/local/bin/virtlogd_wrapper:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}, "nova_virtsecretd": {"start_order": 1, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "pids_limit": 65536, "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "depends_on": ["tripleo_nova_virtlogd_wrapper.service"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtsecretd.json:/var/lib/kolla/config_files/config.json:ro"]}, "nova_virtnodedevd": {"start_order": 2, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "pids_limit": 65536, "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "depends_on": ["tripleo_nova_virtlogd_wrapper.service"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtnodedevd.json:/var/lib/kolla/config_files/config.json:ro"]}, "nova_virtstoraged": {"start_order": 3, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "pids_limit": 65536, "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "depends_on": ["tripleo_nova_virtlogd_wrapper.service"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtstoraged.json:/var/lib/kolla/config_files/config.json:ro"]}, "nova_virtqemud": {"start_order": 4, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "pids_limit": 65536, "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "depends_on": ["tripleo_nova_virtlogd_wrapper.service"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtqemud.json:/var/lib/kolla/config_files/config.json:ro", "/var/log/containers/libvirt/swtpm:/var/log/swtpm:z"]}, "nova_virtproxyd": {"start_order": 5, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "pids_limit": 65536, "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "depends_on": ["tripleo_nova_virtlogd_wrapper.service"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtproxyd.json:/var/lib/kolla/config_files/config.json:ro"]}}, "step_4": {"nova_libvirt_init_secret": {"detach": false, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "security_opt": ["label=disable"], "privileged": false, "user": "root", "cgroupns": "host", "net": "host", "environment": {"LIBVIRT_DEFAULT_URI": "qemu:///system"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/config-data/puppet-generated/nova_libvirt/etc/nova:/etc/nova", "/etc/libvirt:/etc/libvirt", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/lib/container-config-scripts/nova_libvirt_init_secret.sh:/nova_libvirt_init_secret.sh:ro", "/var/lib/tripleo-config/ceph:/etc/ceph:ro"], "command": "/nova_libvirt_init_secret.sh ceph:openstack"}}}, "tuple:('role_data', 'service_names')": null, "tuple:('role_data', 'container_config_scripts')": {"nova_libvirt_init_secret.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nset -e\n\nCEPH_INFO=($*)\n\nif [ -z \"$CEPH_INFO\" ]; then\n    echo \"error: At least one CLUSTER:CLIENT tuple must be specified\"\n    exit 1\nfi\n\necho \"------------------------------------------------\"\necho \"Initializing virsh secrets for: ${CEPH_INFO[@]}\"\n\nfor INFO in ${CEPH_INFO[@]}; do\n    IFS=: read CLUSTER CLIENT <<< $INFO\n    if [ ! -f /etc/ceph/${CLUSTER}.conf ]; then\n        echo \"Error: /etc/ceph/${CLUSTER}.conf was not found\"\n        echo \"Path to nova_libvirt_init_secret was ${CEPH_INFO}\"\n        exit 1\n    fi\n    FSID=$(awk '$1 == \"fsid\" {print $3}' /etc/ceph/${CLUSTER}.conf)\n    if [ -z \"${FSID}\" ]; then\n        echo \"Error: /etc/ceph/${CLUSTER}.conf contained an empty fsid definition\"\n        echo \"Check your ceph configuration\"\n        exit 1\n    fi\n\n    echo \"--------\"\n    echo \"Initializing the virsh secret for '$CLUSTER' cluster ($FSID) '$CLIENT' client\"\n\n    # Ensure the secret XML file exists. Puppet should have created a secret.xml\n    # file for the first cluster's secret, so detect when to use that file.\n    if grep -q $FSID /etc/nova/secret.xml; then\n        SECRET_FILE=\"/etc/nova/secret.xml\"\n        SECRET_NAME=\"client.${CLIENT} secret\"\n    else\n        SECRET_FILE=\"/etc/nova/${CLUSTER}-secret.xml\"\n        SECRET_NAME=\"${CLUSTER}.client.${CLIENT} secret\"\n    fi\n\n    if [ ! -f $SECRET_FILE ]; then\n        echo \"Creating $SECRET_FILE\"\n        cat <<EOF > $SECRET_FILE\n<secret ephemeral='no' private='no'>\n  <usage type='ceph'>\n    <name>${SECRET_NAME}</name>\n  </usage>\n  <uuid>${FSID}</uuid>\n</secret>\nEOF\n    else\n        echo \"The $SECRET_FILE file already exists\"\n    fi\n\n    # Ensure the libvirt secret is defined\n    if /usr/bin/virsh secret-list | grep -q $FSID; then\n        echo \"The virsh secret for $FSID has already been defined\"\n    else\n        /usr/bin/virsh secret-define --file $SECRET_FILE\n    fi\n\n    # Fetch the key from the keyring and ensure the secret is set\n    KEY=$(awk '$1 == \"key\" {print $3}' /etc/ceph/${CLUSTER}.client.${CLIENT}.keyring)\n    if /usr/bin/virsh secret-get-value $FSID 2>/dev/null | grep -q $KEY; then\n        echo \"The virsh secret for $FSID has already been set\"\n    else\n        /usr/bin/virsh secret-set-value --secret $FSID --base64 $KEY\n    fi\ndone\n"}}, "tuple:('role_data', 'service_name')": "nova_libvirt", "tuple:('role_data', 'config_settings')": {"nova::my_ip": "%{hiera('internal_api')}", "nova::rabbit_use_ssl": "False", "nova::keystone::service_user::send_service_user_token": true, "nova::keystone::service_user::project_name": "service", "nova::keystone::service_user::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::keystone::service_user::auth_url": "http://172.17.0.2:5000", "nova::keystone::service_user::region_name": "regionOne", "nova::placement::project_name": "service", "nova::placement::password": "dYVRSnGa4R5DjmK0t4f9aWqpK", "nova::placement::auth_url": "http://172.17.0.2:5000", "nova::placement::region_name": "regionOne", "nova::placement::valid_interfaces": "internal", "nova::os_region_name": "regionOne", "nova::logging::debug": true, "nova::purge_config": false, "nova::network::neutron::project_name": "service", "nova::network::neutron::username": "neutron", "nova::network::neutron::region_name": "regionOne", "nova::dhcp_domain": "", "nova::network::neutron::password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "nova::network::neutron::auth_url": "http://172.17.0.2:5000/v3", "nova::network::neutron::valid_interfaces": "internal", "nova::glance::valid_interfaces": "internal", "nova::rabbit_heartbeat_timeout_threshold": 60, "nova::cinder_catalog_info": "volumev3:cinderv3:internalURL", "nova::host": "%{hiera('fqdn_canonical')}", "nova::notify_on_state_change": "vm_and_task_state", "nova::notification_driver": ["messagingv2"], "nova::notification_format": "unversioned", "nova::network::neutron::auth_type": "v3password", "nova::db::database_db_max_retries": -1, "nova::db::database_max_retries": -1, "nova::network::neutron::ovs_bridge": "br-int", "nova::compute::sync_power_state_interval": 600, "nova_is_additional_cell": false, "nova::cross_az_attach": true, "nova::cache::enabled": true, "nova::cache::tls_enabled": false, "nova::cache::backend": "dogpile.cache.memcached", "nova::rabbit_heartbeat_in_pthread": false, "nova::ovsdb_connection": "", "vhostuser_socket_group": "qemu", "nova_libvirt_opt_volumes": [], "ContainerNovaLibvirtImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ContainerNovaLibvirtConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "nova::compute::libvirt::log_outputs": "1:file:/var/log/libvirt/libvirtd.log", "nova::compute::libvirt::virtlogd::log_outputs": "1:file:/var/log/libvirt/virtlogd.log", "nova::compute::libvirt::virtsecretd::log_outputs": "1:file:/var/log/libvirt/virtsecretd.log", "nova::compute::libvirt::virtnodedevd::log_outputs": "1:file:/var/log/libvirt/virtnodedevd.log", "nova::compute::libvirt::virtqemud::log_outputs": "1:file:/var/log/libvirt/virtqemud.log", "nova::compute::libvirt::virtproxyd::log_outputs": "1:file:/var/log/libvirt/virtproxyd.log", "nova::compute::libvirt::virtstoraged::log_outputs": "1:file:/var/log/libvirt/virtstoraged.log", "nova::compute::libvirt::qemu::memory_backing_dir": "", "nova::compute::libvirt::manage_libvirt_services": false, "tripleo::profile::base::nova::virtlogd_wrapper::enable_wrapper": true, "tripleo::profile::base::nova::virtlogd_wrapper::virtlogd_process_wrapper": "/var/lib/container-config-scripts/virtlogd_wrapper", "tripleo::profile::base::nova::virtlogd_wrapper::virtlogd_image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "tripleo::profile::base::nova::virtlogd_wrapper::debug": true, "nova::compute::libvirt::migration_support": false, "nova::compute::rbd::libvirt_images_rbd_ceph_conf": "/etc/ceph/ceph.conf", "nova::compute::rbd::libvirt_rbd_user": "openstack", "tripleo::profile::base::nova::compute_libvirt_shared::nova_rbd_ceph_conf_path": "/var/lib/tripleo-config/ceph", "nova::compute::rbd::rbd_keyring": "client.openstack", "nova::compute::rbd::libvirt_rbd_secret_key": "AQC8YS1pAAAAABAA+BwWKS55FZMjOG5kO1Z5kw==", "nova::compute::rbd::libvirt_rbd_secret_uuid": "dc518f93-7195-5458-af10-a92142534ce2", "tripleo::profile::base::nova::migration::client::libvirt_enabled": true, "tripleo::profile::base::nova::migration::client::ssh_private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAzcb1z+kYP10UjkTBH4bnxvCXWz+dyTwFHtURjBt2vADgeeph\nNxBRnTe7kysE8m58KHuFJ9m5Lda/KgKrFCJtgtjfquQJzcbJ6cf4qblilLacQG34\nUqc4FLUXkSvAwIriLJX2iGDvg2ff7bAofuD5ya41OU61HEHhtZi2xLEA0I9jQlVS\n0p8PrJy8OAfMDIKQT3ORDfK2QEuLMrabug2dY2vv5b9SASjQrCB+7kYLVxSoUaUq\nociPrBn5na3NMqU+dh7r0P2mpOnQEUb4vRbw2p89Y10YdibzXVad0PbRcZjEpgQr\nNeZIbfMuFDDfSfu0pye7Vm5HzvAwtjUCMQPbBQIDAQABAoIBABA/DBTWv2fvrmBi\nt0I8J9WoexqxYoC+MPbmzy4NOqOY1VNqzAAWVSTUS9MdS2FK+plFOOJIXOFsmfn0\nIGB3k2Ch3lujCc8dFoxTK6O8YJ2DIvT6ebRbQjputCY6NEtyhToMVCmFfB0XOP70\n47P/Ir/nwokvi9POTWBFmiOo7q27vOV0Aa3tJ8DfjcDqIvQTpykQlFHvW+pZ+QhH\nWi9jGCuJP/vLletAHDttmxJ5jnB7ok2UPE/fv46OThx85LNkUmM7P+5qUAT0k2Ke\nB7Q2YSeMjFmaWqnDAq0XbnX6SZGBjIwVYCcUaFqTQdcaHfiDdZQk+4RtCdYJWU8s\n4iCM8KUCgYEA8K39Ux/JO+ut9vqmpTeunq5X4Gl2lmd5Fto1a40QcYAC2iYSwqXM\nsrldOQkWWTQXvcF5lKEDeFGDhDfXX/eMHAeQTGWvKTKun0q7SdIgD8mKHUW+yaSb\nMRMVbNZZ8MDM2mOoOXGVQMcIzEOFPr6+TbnfVu0eTHCvKyMFe/2+q5sCgYEA2uA3\nJmHmehdkX8pQJfW9O4BeJbKZ+dLuF7vI0RXcHRBQa4nOTBFAu5UpaCYMWrC+YQS/\nzWk2FWOyvGL8z5hmPUKcR69GX8vzoYrMIAIvNF5UZAoCwFTDYNYrDFEM5QPhkrln\nH86FPtay/NscrT915j0tz39SWAOBYhbhwyS4jd8CgYEAnhzPZUJmgxTrbmtv+u4/\nq0NBu83M+DX12Mt1eLhtawL73LBSdslRVsBru8J6ihOs3R4zby7wBqUWT1AYD5Wi\n1+8oHuhWUCxZh5AixfZi1bxDHcPp+LJIuc6drqiK4ZzndzktFL/Hm4yl/PsGmBfb\nEVjgnkycMP9+NEqHmdMy5a0CgYBlBEyPy2la+gbaav5YtrTyjElnbqm/8ojurT1+\num8PfuMO7tgmpWPR74LfzYewJ5iGIHIBdMiAULZCWhFCIp01MtP8BboeJnw4F14k\ne72bltmuHiys5bIStGXD1nh0DjmCxU0CEgfPO7n6F4qBryNT8vJ8rM+tTVjek574\nuK7w0wKBgATiv5ZBvdtkO8bDigFvEc9IFNPYGYG2D8JsNU2u6j3FYN/FOQD3UzEj\n/UFz30SOilehDSftmPUGBA3us2CVYA4hJ+SGT71SZeUyOqrmlZhMXGWk3FQn9l7f\n8F0ABR1Kt9K6Wa4shCRBDFgDTmIlqXBgbRTZlJ/OSNae1IBm1UBv\n-----END RSA PRIVATE KEY-----\n", "tripleo::profile::base::nova::migration::client::ssh_port": 2022, "nova::compute::libvirt::services::libvirt_virt_type": "kvm", "nova::compute::libvirt::virt_type": "kvm", "nova::compute::libvirt::enabled_perf_events": [], "nova::compute::libvirt::qemu::configure_qemu": true, "nova::compute::libvirt::qemu::max_files": 32768, "nova::compute::libvirt::qemu::max_processes": 131072, "nova::migration::qemu::configure_qemu": true, "nova::migration::qemu::migration_port_min": 61152, "nova::migration::qemu::migration_port_max": 61215, "nova::compute::libvirt::vncserver_listen": "%{hiera('internal_api')}", "nova::compute::libvirt::log_filters": "1:libvirt 1:qemu 1:conf 1:security 3:event 3:json 3:file 3:object 1:util", "nova::compute::libvirt::virtlogd::log_filters": "1:logging 4:object 4:json 4:event 1:util", "rbd_persistent_storage": true, "rbd_disk_cachemodes": ["network=writeback"], "nova::compute::libvirt::virtsecretd::log_filters": "1:qemu 1:libvirt 4:object 4:json 4:event 1:util", "nova::compute::libvirt::virtnodedevd::log_filters": "1:qemu 1:libvirt 4:object 4:json 4:event 1:util", "nova::compute::libvirt::virtstoraged::log_filters": "1:qemu 1:libvirt 4:object 4:json 4:event 1:util", "nova::compute::libvirt::virtqemud::log_filters": "1:qemu 1:libvirt 4:object 4:json 4:event 1:util", "nova::compute::libvirt::virtproxyd::log_filters": "1:qemu 1:libvirt 4:object 4:json 4:event 1:util", "tripleo::profile::base::nova::libvirt::modular_libvirt": true, "nova::compute::libvirt::services::modular_libvirt": true, "nova::compute::libvirt::modular_libvirt": true, "nova::migration::libvirt::modular_libvirt": true, "nova::migration::libvirt::live_migration_inbound_addr": "%{hiera('fqdn_internal_api')}"}, "role_data": {"service_name": "nova_libvirt", "firewall_rules": {"200 nova_libvirt": {"dport": [16514, "61152-61215", "5900-6923"]}}, "ansible_group_vars": {"tripleo_nova_libvirt_virsh_container": "nova_virtproxyd"}, "monitoring_subscription": "overcloud-nova-libvirt", "config_settings": {"nova::my_ip": "%{hiera('internal_api')}", "nova::rabbit_use_ssl": "False", "nova::keystone::service_user::send_service_user_token": true, "nova::keystone::service_user::project_name": "service", "nova::keystone::service_user::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::keystone::service_user::auth_url": "http://172.17.0.2:5000", "nova::keystone::service_user::region_name": "regionOne", "nova::placement::project_name": "service", "nova::placement::password": "dYVRSnGa4R5DjmK0t4f9aWqpK", "nova::placement::auth_url": "http://172.17.0.2:5000", "nova::placement::region_name": "regionOne", "nova::placement::valid_interfaces": "internal", "nova::os_region_name": "regionOne", "nova::logging::debug": true, "nova::purge_config": false, "nova::network::neutron::project_name": "service", "nova::network::neutron::username": "neutron", "nova::network::neutron::region_name": "regionOne", "nova::dhcp_domain": "", "nova::network::neutron::password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "nova::network::neutron::auth_url": "http://172.17.0.2:5000/v3", "nova::network::neutron::valid_interfaces": "internal", "nova::glance::valid_interfaces": "internal", "nova::rabbit_heartbeat_timeout_threshold": 60, "nova::cinder_catalog_info": "volumev3:cinderv3:internalURL", "nova::host": "%{hiera('fqdn_canonical')}", "nova::notify_on_state_change": "vm_and_task_state", "nova::notification_driver": ["messagingv2"], "nova::notification_format": "unversioned", "nova::network::neutron::auth_type": "v3password", "nova::db::database_db_max_retries": -1, "nova::db::database_max_retries": -1, "nova::network::neutron::ovs_bridge": "br-int", "nova::compute::sync_power_state_interval": 600, "nova_is_additional_cell": false, "nova::cross_az_attach": true, "nova::cache::enabled": true, "nova::cache::tls_enabled": false, "nova::cache::backend": "dogpile.cache.memcached", "nova::rabbit_heartbeat_in_pthread": false, "nova::ovsdb_connection": "", "vhostuser_socket_group": "qemu", "nova_libvirt_opt_volumes": [], "ContainerNovaLibvirtImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ContainerNovaLibvirtConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "nova::compute::libvirt::log_outputs": "1:file:/var/log/libvirt/libvirtd.log", "nova::compute::libvirt::virtlogd::log_outputs": "1:file:/var/log/libvirt/virtlogd.log", "nova::compute::libvirt::virtsecretd::log_outputs": "1:file:/var/log/libvirt/virtsecretd.log", "nova::compute::libvirt::virtnodedevd::log_outputs": "1:file:/var/log/libvirt/virtnodedevd.log", "nova::compute::libvirt::virtqemud::log_outputs": "1:file:/var/log/libvirt/virtqemud.log", "nova::compute::libvirt::virtproxyd::log_outputs": "1:file:/var/log/libvirt/virtproxyd.log", "nova::compute::libvirt::virtstoraged::log_outputs": "1:file:/var/log/libvirt/virtstoraged.log", "nova::compute::libvirt::qemu::memory_backing_dir": "", "nova::compute::libvirt::manage_libvirt_services": false, "tripleo::profile::base::nova::virtlogd_wrapper::enable_wrapper": true, "tripleo::profile::base::nova::virtlogd_wrapper::virtlogd_process_wrapper": "/var/lib/container-config-scripts/virtlogd_wrapper", "tripleo::profile::base::nova::virtlogd_wrapper::virtlogd_image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "tripleo::profile::base::nova::virtlogd_wrapper::debug": true, "nova::compute::libvirt::migration_support": false, "nova::compute::rbd::libvirt_images_rbd_ceph_conf": "/etc/ceph/ceph.conf", "nova::compute::rbd::libvirt_rbd_user": "openstack", "tripleo::profile::base::nova::compute_libvirt_shared::nova_rbd_ceph_conf_path": "/var/lib/tripleo-config/ceph", "nova::compute::rbd::rbd_keyring": "client.openstack", "nova::compute::rbd::libvirt_rbd_secret_key": "AQC8YS1pAAAAABAA+BwWKS55FZMjOG5kO1Z5kw==", "nova::compute::rbd::libvirt_rbd_secret_uuid": "dc518f93-7195-5458-af10-a92142534ce2", "tripleo::profile::base::nova::migration::client::libvirt_enabled": true, "tripleo::profile::base::nova::migration::client::ssh_private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAzcb1z+kYP10UjkTBH4bnxvCXWz+dyTwFHtURjBt2vADgeeph\nNxBRnTe7kysE8m58KHuFJ9m5Lda/KgKrFCJtgtjfquQJzcbJ6cf4qblilLacQG34\nUqc4FLUXkSvAwIriLJX2iGDvg2ff7bAofuD5ya41OU61HEHhtZi2xLEA0I9jQlVS\n0p8PrJy8OAfMDIKQT3ORDfK2QEuLMrabug2dY2vv5b9SASjQrCB+7kYLVxSoUaUq\nociPrBn5na3NMqU+dh7r0P2mpOnQEUb4vRbw2p89Y10YdibzXVad0PbRcZjEpgQr\nNeZIbfMuFDDfSfu0pye7Vm5HzvAwtjUCMQPbBQIDAQABAoIBABA/DBTWv2fvrmBi\nt0I8J9WoexqxYoC+MPbmzy4NOqOY1VNqzAAWVSTUS9MdS2FK+plFOOJIXOFsmfn0\nIGB3k2Ch3lujCc8dFoxTK6O8YJ2DIvT6ebRbQjputCY6NEtyhToMVCmFfB0XOP70\n47P/Ir/nwokvi9POTWBFmiOo7q27vOV0Aa3tJ8DfjcDqIvQTpykQlFHvW+pZ+QhH\nWi9jGCuJP/vLletAHDttmxJ5jnB7ok2UPE/fv46OThx85LNkUmM7P+5qUAT0k2Ke\nB7Q2YSeMjFmaWqnDAq0XbnX6SZGBjIwVYCcUaFqTQdcaHfiDdZQk+4RtCdYJWU8s\n4iCM8KUCgYEA8K39Ux/JO+ut9vqmpTeunq5X4Gl2lmd5Fto1a40QcYAC2iYSwqXM\nsrldOQkWWTQXvcF5lKEDeFGDhDfXX/eMHAeQTGWvKTKun0q7SdIgD8mKHUW+yaSb\nMRMVbNZZ8MDM2mOoOXGVQMcIzEOFPr6+TbnfVu0eTHCvKyMFe/2+q5sCgYEA2uA3\nJmHmehdkX8pQJfW9O4BeJbKZ+dLuF7vI0RXcHRBQa4nOTBFAu5UpaCYMWrC+YQS/\nzWk2FWOyvGL8z5hmPUKcR69GX8vzoYrMIAIvNF5UZAoCwFTDYNYrDFEM5QPhkrln\nH86FPtay/NscrT915j0tz39SWAOBYhbhwyS4jd8CgYEAnhzPZUJmgxTrbmtv+u4/\nq0NBu83M+DX12Mt1eLhtawL73LBSdslRVsBru8J6ihOs3R4zby7wBqUWT1AYD5Wi\n1+8oHuhWUCxZh5AixfZi1bxDHcPp+LJIuc6drqiK4ZzndzktFL/Hm4yl/PsGmBfb\nEVjgnkycMP9+NEqHmdMy5a0CgYBlBEyPy2la+gbaav5YtrTyjElnbqm/8ojurT1+\num8PfuMO7tgmpWPR74LfzYewJ5iGIHIBdMiAULZCWhFCIp01MtP8BboeJnw4F14k\ne72bltmuHiys5bIStGXD1nh0DjmCxU0CEgfPO7n6F4qBryNT8vJ8rM+tTVjek574\nuK7w0wKBgATiv5ZBvdtkO8bDigFvEc9IFNPYGYG2D8JsNU2u6j3FYN/FOQD3UzEj\n/UFz30SOilehDSftmPUGBA3us2CVYA4hJ+SGT71SZeUyOqrmlZhMXGWk3FQn9l7f\n8F0ABR1Kt9K6Wa4shCRBDFgDTmIlqXBgbRTZlJ/OSNae1IBm1UBv\n-----END RSA PRIVATE KEY-----\n", "tripleo::profile::base::nova::migration::client::ssh_port": 2022, "nova::compute::libvirt::services::libvirt_virt_type": "kvm", "nova::compute::libvirt::virt_type": "kvm", "nova::compute::libvirt::enabled_perf_events": [], "nova::compute::libvirt::qemu::configure_qemu": true, "nova::compute::libvirt::qemu::max_files": 32768, "nova::compute::libvirt::qemu::max_processes": 131072, "nova::migration::qemu::configure_qemu": true, "nova::migration::qemu::migration_port_min": 61152, "nova::migration::qemu::migration_port_max": 61215, "nova::compute::libvirt::vncserver_listen": "%{hiera('internal_api')}", "nova::compute::libvirt::log_filters": "1:libvirt 1:qemu 1:conf 1:security 3:event 3:json 3:file 3:object 1:util", "nova::compute::libvirt::virtlogd::log_filters": "1:logging 4:object 4:json 4:event 1:util", "rbd_persistent_storage": true, "rbd_disk_cachemodes": ["network=writeback"], "nova::compute::libvirt::virtsecretd::log_filters": "1:qemu 1:libvirt 4:object 4:json 4:event 1:util", "nova::compute::libvirt::virtnodedevd::log_filters": "1:qemu 1:libvirt 4:object 4:json 4:event 1:util", "nova::compute::libvirt::virtstoraged::log_filters": "1:qemu 1:libvirt 4:object 4:json 4:event 1:util", "nova::compute::libvirt::virtqemud::log_filters": "1:qemu 1:libvirt 4:object 4:json 4:event 1:util", "nova::compute::libvirt::virtproxyd::log_filters": "1:qemu 1:libvirt 4:object 4:json 4:event 1:util", "tripleo::profile::base::nova::libvirt::modular_libvirt": true, "nova::compute::libvirt::services::modular_libvirt": true, "nova::compute::libvirt::modular_libvirt": true, "nova::migration::libvirt::modular_libvirt": true, "nova::migration::libvirt::live_migration_inbound_addr": "%{hiera('fqdn_internal_api')}"}, "puppet_config": {"config_volume": "nova_libvirt", "puppet_tags": "libvirtd_config,virtlogd_config,virtproxyd_config,virtqemud_config,virtnodedevd_config,virtsecretd_config,virtstoraged_config,nova_config,file,libvirt_tls_password", "step_config": "include tripleo::profile::base::nova::libvirt\n", "config_image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1"}, "kolla_config": {"/var/lib/kolla/config_files/nova_virtlogd.json": {"command": "/usr/local/bin/virtlogd_wrapper", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-ceph/", "dest": "/etc/ceph/", "merge": true, "preserve_properties": true}], "permissions": [{"path": "/etc/ceph/ceph.client.openstack.keyring", "owner": "nova:nova", "perm": "0600"}]}, "/var/lib/kolla/config_files/nova_virtsecretd.json": {"command": "/usr/sbin/virtsecretd --config /etc/libvirt/virtsecretd.conf", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-ceph/", "dest": "/etc/ceph/", "merge": true, "preserve_properties": true}], "permissions": [{"path": "/etc/ceph/ceph.client.openstack.keyring", "owner": "nova:nova", "perm": "0600"}]}, "/var/lib/kolla/config_files/nova_virtnodedevd.json": {"command": "/usr/sbin/virtnodedevd --config /etc/libvirt/virtnodedevd.conf", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-ceph/", "dest": "/etc/ceph/", "merge": true, "preserve_properties": true}], "permissions": [{"path": "/etc/ceph/ceph.client.openstack.keyring", "owner": "nova:nova", "perm": "0600"}]}, "/var/lib/kolla/config_files/nova_virtstoraged.json": {"command": "/usr/sbin/virtstoraged --config /etc/libvirt/virtstoraged.conf", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-ceph/", "dest": "/etc/ceph/", "merge": true, "preserve_properties": true}], "permissions": [{"path": "/etc/ceph/ceph.client.openstack.keyring", "owner": "nova:nova", "perm": "0600"}]}, "/var/lib/kolla/config_files/nova_virtqemud.json": {"command": "/usr/sbin/virtqemud --config /etc/libvirt/virtqemud.conf", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-ceph/", "dest": "/etc/ceph/", "merge": true, "preserve_properties": true}], "permissions": [{"path": "/etc/ceph/ceph.client.openstack.keyring", "owner": "nova:nova", "perm": "0600"}]}, "/var/lib/kolla/config_files/nova_virtproxyd.json": {"command": "/usr/sbin/virtproxyd --config /etc/libvirt/virtproxyd.conf", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-ceph/", "dest": "/etc/ceph/", "merge": true, "preserve_properties": true}], "permissions": [{"path": "/etc/ceph/ceph.client.openstack.keyring", "owner": "nova:nova", "perm": "0600"}]}}, "container_config_scripts": {"nova_libvirt_init_secret.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nset -e\n\nCEPH_INFO=($*)\n\nif [ -z \"$CEPH_INFO\" ]; then\n    echo \"error: At least one CLUSTER:CLIENT tuple must be specified\"\n    exit 1\nfi\n\necho \"------------------------------------------------\"\necho \"Initializing virsh secrets for: ${CEPH_INFO[@]}\"\n\nfor INFO in ${CEPH_INFO[@]}; do\n    IFS=: read CLUSTER CLIENT <<< $INFO\n    if [ ! -f /etc/ceph/${CLUSTER}.conf ]; then\n        echo \"Error: /etc/ceph/${CLUSTER}.conf was not found\"\n        echo \"Path to nova_libvirt_init_secret was ${CEPH_INFO}\"\n        exit 1\n    fi\n    FSID=$(awk '$1 == \"fsid\" {print $3}' /etc/ceph/${CLUSTER}.conf)\n    if [ -z \"${FSID}\" ]; then\n        echo \"Error: /etc/ceph/${CLUSTER}.conf contained an empty fsid definition\"\n        echo \"Check your ceph configuration\"\n        exit 1\n    fi\n\n    echo \"--------\"\n    echo \"Initializing the virsh secret for '$CLUSTER' cluster ($FSID) '$CLIENT' client\"\n\n    # Ensure the secret XML file exists. Puppet should have created a secret.xml\n    # file for the first cluster's secret, so detect when to use that file.\n    if grep -q $FSID /etc/nova/secret.xml; then\n        SECRET_FILE=\"/etc/nova/secret.xml\"\n        SECRET_NAME=\"client.${CLIENT} secret\"\n    else\n        SECRET_FILE=\"/etc/nova/${CLUSTER}-secret.xml\"\n        SECRET_NAME=\"${CLUSTER}.client.${CLIENT} secret\"\n    fi\n\n    if [ ! -f $SECRET_FILE ]; then\n        echo \"Creating $SECRET_FILE\"\n        cat <<EOF > $SECRET_FILE\n<secret ephemeral='no' private='no'>\n  <usage type='ceph'>\n    <name>${SECRET_NAME}</name>\n  </usage>\n  <uuid>${FSID}</uuid>\n</secret>\nEOF\n    else\n        echo \"The $SECRET_FILE file already exists\"\n    fi\n\n    # Ensure the libvirt secret is defined\n    if /usr/bin/virsh secret-list | grep -q $FSID; then\n        echo \"The virsh secret for $FSID has already been defined\"\n    else\n        /usr/bin/virsh secret-define --file $SECRET_FILE\n    fi\n\n    # Fetch the key from the keyring and ensure the secret is set\n    KEY=$(awk '$1 == \"key\" {print $3}' /etc/ceph/${CLUSTER}.client.${CLIENT}.keyring)\n    if /usr/bin/virsh secret-get-value $FSID 2>/dev/null | grep -q $KEY; then\n        echo \"The virsh secret for $FSID has already been set\"\n    else\n        /usr/bin/virsh secret-set-value --secret $FSID --base64 $KEY\n    fi\ndone\n"}}, "docker_config": {"step_2": {"nova_virtqemud_init_logs": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "net": "none", "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "user": "root", "volumes": ["/var/log/containers/libvirt/swtpm:/var/log/swtpm:shared,z"], "command": ["/bin/bash", "-c", "chown -R tss:tss /var/log/swtpm"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}, "create_virtlogd_wrapper": {"start_order": 1, "detach": false, "cgroupns": "host", "net": "host", "pid": "host", "user": "root", "command": ["/container_puppet_apply.sh", "4", "file", "include ::tripleo::profile::base::nova::virtlogd_wrapper"], "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/var/lib/container-config-scripts/container_puppet_apply.sh:/container_puppet_apply.sh:ro", "/etc/puppet:/tmp/puppet-etc:ro", "/usr/share/openstack-puppet/modules:/usr/share/openstack-puppet/modules:ro", "/var/lib/container-config-scripts:/var/lib/container-config-scripts:shared,z"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}}, "step_3": {"nova_virtlogd_wrapper": {"start_order": 0, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtlogd.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/container-config-scripts/virtlogd_wrapper:/usr/local/bin/virtlogd_wrapper:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}, "nova_virtsecretd": {"start_order": 1, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "pids_limit": 65536, "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "depends_on": ["tripleo_nova_virtlogd_wrapper.service"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtsecretd.json:/var/lib/kolla/config_files/config.json:ro"]}, "nova_virtnodedevd": {"start_order": 2, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "pids_limit": 65536, "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "depends_on": ["tripleo_nova_virtlogd_wrapper.service"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtnodedevd.json:/var/lib/kolla/config_files/config.json:ro"]}, "nova_virtstoraged": {"start_order": 3, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "pids_limit": 65536, "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "depends_on": ["tripleo_nova_virtlogd_wrapper.service"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtstoraged.json:/var/lib/kolla/config_files/config.json:ro"]}, "nova_virtqemud": {"start_order": 4, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "pids_limit": 65536, "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "depends_on": ["tripleo_nova_virtlogd_wrapper.service"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtqemud.json:/var/lib/kolla/config_files/config.json:ro", "/var/log/containers/libvirt/swtpm:/var/log/swtpm:z"]}, "nova_virtproxyd": {"start_order": 5, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "ulimit": ["nofile=131072", "nproc=126960"], "cgroupns": "host", "net": "host", "pid": "host", "pids_limit": 65536, "privileged": true, "security_opt": ["label=level:s0", "label=type:spc_t", "label=filetype:container_file_t"], "restart": "always", "depends_on": ["tripleo_nova_virtlogd_wrapper.service"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/libvirt:/var/log/libvirt:shared,z", "/lib/modules:/lib/modules:ro", "/dev:/dev", "/run:/run", "/sys/fs/cgroup:/sys/fs/cgroup", "/sys/fs/selinux:/sys/fs/selinux", "/etc/selinux/config:/etc/selinux/config:ro", "/etc/libvirt:/etc/libvirt:shared", "/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/cache/libvirt:/var/cache/libvirt:shared", "/var/lib/vhost_sockets:/var/lib/vhost_sockets", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/var/lib/tripleo-config/ceph:/var/lib/kolla/config_files/src-ceph:z", "/var/lib/kolla/config_files/nova_virtproxyd.json:/var/lib/kolla/config_files/config.json:ro"]}}, "step_4": {"nova_libvirt_init_secret": {"detach": false, "image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1", "security_opt": ["label=disable"], "privileged": false, "user": "root", "cgroupns": "host", "net": "host", "environment": {"LIBVIRT_DEFAULT_URI": "qemu:///system"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/config-data/puppet-generated/nova_libvirt/etc/nova:/etc/nova", "/etc/libvirt:/etc/libvirt", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/libvirt:/var/lib/libvirt:shared", "/var/lib/container-config-scripts/nova_libvirt_init_secret.sh:/nova_libvirt_init_secret.sh:ro", "/var/lib/tripleo-config/ceph:/etc/ceph:ro"], "command": "/nova_libvirt_init_secret.sh ceph:openstack"}}}, "deploy_steps_tasks": [{"name": "Ensure recovery of containerized virtqemud", "when": "step|int == 4", "become": true, "block": [{"name": "Create virtqemud recovery script", "copy": {"dest": "/usr/libexec/recover_tripleo_nova_virtqemud.sh", "mode": "0755", "content": "#!/bin/bash\npgrep -f /sbin/virtqemud\n[ $? -eq 0 ] && exit 0\nkill -9 $(cat /run/nova_virtqemud.pid)\n"}}, {"name": "Create virtqemud recovery trigger service", "copy": {"dest": "/etc/systemd/system/tripleo_nova_virtqemud_recover.service", "mode": "0644", "content": "[Unit]\nDescription=Check and recover tripleo_nova_virtqemud\nAfter=tripleo_nova_virtqemud.service\nRequisite=tripleo_nova_virtqemud.service\n[Service]\nType=oneshot\nExecStart=bash /usr/libexec/recover_tripleo_nova_virtqemud.sh\nSyslogIdentifier=recover_tripleo_nova_virtqemud\n[Install]\nWantedBy=multi-user.target\n"}}, {"name": "Create virtqemud recovery trigger timer", "copy": {"dest": "/etc/systemd/system/tripleo_nova_virtqemud_recover.timer", "mode": "0644", "content": "[Unit]\nDescription=Check and recover tripleo_nova_virtqemud every 10m\nPartOf=tripleo_nova_virtqemud.service\n[Timer]\nOnCalendar=*:5/10\nOnActiveSec=120\nOnUnitActiveSec=60\nRandomizedDelaySec=1m\n[Install]\nWantedBy=timers.target\n"}}, {"name": "Enable virtqemud recovery trigger service", "systemd": {"name": "tripleo_nova_virtqemud_recover.service", "enabled": true, "daemon_reload": true}}, {"name": "Enable virtqemud recovery trigger timer", "systemd": {"name": "tripleo_nova_virtqemud_recover.timer", "enabled": true, "state": "restarted", "daemon_reload": true}, "register": "virtqemud_recover_timer_result"}, {"name": "Really enable virtqemud recovery trigger timer", "shell": {"cmd": "systemctl enable --now tripleo_nova_virtqemud_recover.timer"}, "when": "virtqemud_recover_timer_result.status.UnitFileState != \"enabled\""}]}, {"name": "Set up systemd target for libvirt services", "when": "step|int == 4", "block": [{"name": "Create systemd file", "copy": {"dest": "/etc/systemd/system/tripleo_nova_libvirt.target", "mode": "0644", "owner": "root", "group": "root", "content": "[Unit]\nWants=tripleo_nova_virtsecretd.service\nWants=tripleo_nova_virtnodedevd.service\nWants=tripleo_nova_virtstoraged.service\nWants=tripleo_nova_virtproxyd.service\nWants=tripleo_nova_virtqemud.service\nAfter=tripleo_nova_virtsecretd.service\nAfter=tripleo_nova_virtnodedevd.service\nAfter=tripleo_nova_virtstoraged.service\nAfter=tripleo_nova_virtproxyd.service\nAfter=tripleo_nova_virtqemud.service\n"}, "become": true, "register": "libvirt_target_result"}, {"name": "Reload systemd", "systemd": {"name": "tripleo_nova_libvirt.target", "enabled": true, "state": "restarted", "daemon_reload": true}, "become": true, "when": "libvirt_target_result.changed"}]}], "host_prep_tasks": [{"name": "create persistent directories", "file": {"path": "{{ item.path }}", "setype": "{{ item.setype }}", "state": "directory", "mode": "{{ item.mode }}"}, "with_items": [{"path": "/var/log/containers/libvirt", "setype": "container_file_t", "mode": "0750"}]}, {"name": "create libvirt persistent data directories", "file": {"path": "{{ item.path }}", "state": "directory", "setype": "{{ item.setype | default(omit) }}", "mode": "{{ item.mode | default(omit) }}"}, "with_items": [{"path": "/etc/libvirt", "setype": "container_file_t"}, {"path": "/etc/libvirt/secrets", "setype": "container_file_t"}, {"path": "/etc/libvirt/qemu", "setype": "container_file_t"}, {"path": "/var/lib/libvirt", "setype": "container_file_t"}, {"path": "/var/cache/libvirt"}, {"path": "/var/lib/nova", "setype": "container_file_t"}, {"path": "/run/libvirt"}, {"path": "/var/log/containers/libvirt/swtpm", "setype": "container_file_t", "mode": "0770"}]}, {"name": "ensure qemu group is present on the host", "group": {"name": "qemu", "gid": 107, "state": "present"}}, {"name": "ensure qemu user is present on the host", "user": {"name": "qemu", "uid": 107, "group": "qemu", "state": "present", "shell": "/sbin/nologin", "comment": "qemu user"}}, {"name": "create directory for vhost-user sockets with qemu ownership", "file": {"path": "/var/lib/vhost_sockets", "state": "directory", "owner": "qemu", "group": "qemu", "setype": "virt_cache_t", "seuser": "system_u"}}, {"name": "ensure ceph configurations exist", "file": {"path": "/var/lib/tripleo-config/ceph", "state": "directory"}}, {"name": "check if libvirt is installed", "command": "/usr/bin/rpm -q libvirt-daemon", "failed_when": false, "register": "libvirt_installed", "check_mode": false}, {"name": "make sure libvirt services are disabled and masked", "service": {"name": "{{ item }}", "state": "stopped", "enabled": false, "masked": true, "daemon_reload": true}, "with_items": ["libvirtd.service", "virtlogd.socket"], "when": "libvirt_installed.rc == 0"}, {"name": "ensure /run/libvirt is present upon reboot", "copy": {"dest": "/etc/tmpfiles.d/run-libvirt.conf", "content": "d /run/libvirt 0755 root root - -\n"}}, {"name": "Enable os_enable_vtpm SELinux boolean for vTPM", "seboolean": {"name": "os_enable_vtpm", "persistent": true, "state": true}, "when": ["ansible_facts.selinux is defined", "ansible_facts.selinux.status == \"enabled\""]}, [{"name": "remove gnutls-qemu.config", "file": {"path": "/etc/crypto-policies/local.d/gnutls-qemu.config", "state": "absent"}, "register": "update_gnutls_config"}], {"name": "update crypto policies", "command": "update-crypto-policies", "when": "update_gnutls_config.changed"}], "metadata_settings": [], "upgrade_tasks": [{"name": "Fail if we are on RHEL8 as this is monolithic libvirt deployment", "when": ["step|int == 0", "'system_upgrade' not in ansible_run_tags", "ansible_facts['distribution_major_version'] is version('8', '==')"], "fail": {"msg": "Use of the Modular Libvirt deployment on RHEL8 results in loss of workloads. Use NovaLibvirtLegacy in roles data."}}, {"name": "nova_libvirt_container_tmpfile_cleanup", "when": "step|int == 1", "block": [{"name": "Remove old tmpfiles.d config", "file": {"path": "/etc/tmpfiles.d/var-run-libvirt.conf", "state": "absent"}}]}, {"name": "Get container virtlogd image", "when": "step|int == 1", "tags": "always", "set_fact": {"virtlogd_image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1"}}, {"name": "Force pull image novalibvirt", "when": ["step|int == 1"], "containers.podman.podman_image": {"name": "{{ virtlogd_image }}", "force": true}}, {"name": "Diff OS release in container image and baremetal", "when": "step|int == 1", "shell": "diff /etc/redhat-release <(podman run {{ virtlogd_image }} cat /etc/redhat-release)\n", "args": {"executable": "/bin/bash"}, "failed_when": false, "register": "libvirt_ubi_diff"}, {"name": "Fail if UBI of the container does not match RHEL of running host", "when": ["'system_upgrade' not in ansible_run_tags", "step|int == 1", "libvirt_ubi_diff.rc == 1"], "fail": {"msg": "The host operating system versus container UBI does not match.\n{{ libvirt_ubi_diff.stdout }}\nMost likely container passed to NovaLibvirt was EL8 one.\nYou have to pass the correct container for container-image-prepare.\nIf you would continue all running workloads would get destroyed.\n"}}, {"name": "Switch virtlogd image before system upgrade", "when": "step|int == 1", "tags": ["never", "system_upgrade"], "block": [{"name": "Get running image version", "shell": "podman ps --filter name=^nova_virtlogd$ --format \"{% raw %}{{ .Image }}{% endraw %}\"\n", "register": "old_virtlogd_image"}, {"name": "Switch running image to new image in wrapper script", "shell": "set -o pipefail\nsed -i -e 's|{{ old_virtlogd_image.stdout }}|{{ virtlogd_image }}|' /var/lib/container-config-scripts/virtlogd_wrapper\n", "when": ["old_virtlogd_image.stdout != virtlogd_image", "old_virtlogd_image.stdout != ''"]}]}], "update_tasks": [{"name": "check systemd-container package present or not", "package": {"name": "systemd-container", "state": "present"}, "check_mode": true, "register": "is_systemd_container_package"}, {"name": "download systemd-container package if not present", "yum": {"name": "systemd-container", "state": "present", "download_only": true, "download_dir": "/var/tmp/"}, "when": "is_systemd_container_package.changed"}, {"name": "nova_libvirt_container_tmpfile_cleanup", "when": "step|int == 1", "block": [{"name": "Remove old tmpfiles.d config", "file": {"path": "/etc/tmpfiles.d/var-run-libvirt.conf", "state": "absent"}}]}]}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-53-xxifwlu6bbre/24eea22a-d8a3-4b10-8d7b-afc8c9605ef2"}


created_at: 2025-12-01 09:42:25.803708
data:
  {"EndpointMap": {"AodhAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8042", "protocol": "http", "uri": "http://172.17.0.2:8042", "uri_no_suffix": "http://172.17.0.2:8042"}, "AodhInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8042", "protocol": "http", "uri": "http://172.17.0.2:8042", "uri_no_suffix": "http://172.17.0.2:8042"}, "AodhPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8042", "protocol": "http", "uri": "http://172.21.0.2:8042", "uri_no_suffix": "http://172.21.0.2:8042"}, "BarbicanAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9311", "protocol": "http", "uri": "http://172.17.0.2:9311", "uri_no_suffix": "http://172.17.0.2:9311"}, "BarbicanInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9311", "protocol": "http", "uri": "http://172.17.0.2:9311", "uri_no_suffix": "http://172.17.0.2:9311"}, "BarbicanPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "9311", "protocol": "http", "uri": "http://172.21.0.2:9311", "uri_no_suffix": "http://172.21.0.2:9311"}, "CephDashboardInternal": {"host": "192.168.122.99", "host_nobrackets": "192.168.122.99", "port": "8444", "protocol": "http", "uri": "http://192.168.122.99:8444", "uri_no_suffix": "http://192.168.122.99:8444"}, "CephGrafanaInternal": {"host": "172.18.0.2", "host_nobrackets": "172.18.0.2", "port": "3100", "protocol": "http", "uri": "http://172.18.0.2:3100", "uri_no_suffix": "http://172.18.0.2:3100"}, "CephRgwAdmin": {"host": "172.18.0.2", "host_nobrackets": "172.18.0.2", "port": "8080", "protocol": "http", "uri": "http://172.18.0.2:8080/swift/v1/AUTH_%(project_id)s", "uri_no_suffix": "http://172.18.0.2:8080"}, "CephRgwInternal": {"host": "172.18.0.2", "host_nobrackets": "172.18.0.2", "port": "8080", "protocol": "http", "uri": "http://172.18.0.2:8080/swift/v1/AUTH_%(project_id)s", "uri_no_suffix": "http://172.18.0.2:8080"}, "CephRgwPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8080", "protocol": "http", "uri": "http://172.21.0.2:8080/swift/v1/AUTH_%(project_id)s", "uri_no_suffix": "http://172.21.0.2:8080"}, "CinderAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8776", "protocol": "http", "uri": "http://172.17.0.2:8776/v1/%(tenant_id)s", "uri_no_suffix": "http://172.17.0.2:8776"}, "CinderInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8776", "protocol": "http", "uri": "http://172.17.0.2:8776/v1/%(tenant_id)s", "uri_no_suffix": "http://172.17.0.2:8776"}, "CinderPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8776", "protocol": "http", "uri": "http://172.21.0.2:8776/v1/%(tenant_id)s", "uri_no_suffix": "http://172.21.0.2:8776"}, "CinderV2Admin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8776", "protocol": "http", "uri": "http://172.17.0.2:8776/v2/%(tenant_id)s", "uri_no_suffix": "http://172.17.0.2:8776"}, "CinderV2Internal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8776", "protocol": "http", "uri": "http://172.17.0.2:8776/v2/%(tenant_id)s", "uri_no_suffix": "http://172.17.0.2:8776"}, "CinderV2Public": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8776", "protocol": "http", "uri": "http://172.21.0.2:8776/v2/%(tenant_id)s", "uri_no_suffix": "http://172.21.0.2:8776"}, "CinderV3Admin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8776", "protocol": "http", "uri": "http://172.17.0.2:8776/v3/%(tenant_id)s", "uri_no_suffix": "http://172.17.0.2:8776"}, "CinderV3Internal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8776", "protocol": "http", "uri": "http://172.17.0.2:8776/v3/%(tenant_id)s", "uri_no_suffix": "http://172.17.0.2:8776"}, "CinderV3Public": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8776", "protocol": "http", "uri": "http://172.21.0.2:8776/v3/%(tenant_id)s", "uri_no_suffix": "http://172.21.0.2:8776"}, "DesignateAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9001", "protocol": "http", "uri": "http://172.17.0.2:9001/v2", "uri_no_suffix": "http://172.17.0.2:9001"}, "DesignateInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9001", "protocol": "http", "uri": "http://172.17.0.2:9001/v2", "uri_no_suffix": "http://172.17.0.2:9001"}, "DesignatePublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "9001", "protocol": "http", "uri": "http://172.21.0.2:9001/v2", "uri_no_suffix": "http://172.21.0.2:9001"}, "DockerRegistryInternal": {"host": "192.168.122.99", "host_nobrackets": "192.168.122.99", "port": "8787", "protocol": "http", "uri": "http://192.168.122.99:8787", "uri_no_suffix": "http://192.168.122.99:8787"}, "GaneshaInternal": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "2049", "protocol": "nfs", "uri": "nfs://172.21.0.2:2049", "uri_no_suffix": "nfs://172.21.0.2:2049"}, "GlanceAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9293", "protocol": "http", "uri": "http://172.17.0.2:9293", "uri_no_suffix": "http://172.17.0.2:9293"}, "GlanceInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9293", "protocol": "http", "uri": "http://172.17.0.2:9293", "uri_no_suffix": "http://172.17.0.2:9293"}, "GlancePublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "9292", "protocol": "http", "uri": "http://172.21.0.2:9292", "uri_no_suffix": "http://172.21.0.2:9292"}, "GnocchiAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8041", "protocol": "http", "uri": "http://172.17.0.2:8041", "uri_no_suffix": "http://172.17.0.2:8041"}, "GnocchiInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8041", "protocol": "http", "uri": "http://172.17.0.2:8041", "uri_no_suffix": "http://172.17.0.2:8041"}, "GnocchiPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8041", "protocol": "http", "uri": "http://172.21.0.2:8041", "uri_no_suffix": "http://172.21.0.2:8041"}, "HeatAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8004", "protocol": "http", "uri": "http://172.17.0.2:8004/v1/%(tenant_id)s", "uri_no_suffix": "http://172.17.0.2:8004"}, "HeatInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8004", "protocol": "http", "uri": "http://172.17.0.2:8004/v1/%(tenant_id)s", "uri_no_suffix": "http://172.17.0.2:8004"}, "HeatPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8004", "protocol": "http", "uri": "http://172.21.0.2:8004/v1/%(tenant_id)s", "uri_no_suffix": "http://172.21.0.2:8004"}, "HeatCfnAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8000", "protocol": "http", "uri": "http://172.17.0.2:8000/v1", "uri_no_suffix": "http://172.17.0.2:8000"}, "HeatCfnInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8000", "protocol": "http", "uri": "http://172.17.0.2:8000/v1", "uri_no_suffix": "http://172.17.0.2:8000"}, "HeatCfnPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8000", "protocol": "http", "uri": "http://172.21.0.2:8000/v1", "uri_no_suffix": "http://172.21.0.2:8000"}, "HorizonPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "80", "protocol": "http", "uri": "http://172.21.0.2:80/dashboard", "uri_no_suffix": "http://172.21.0.2:80"}, "IronicAdmin": {"host": "192.168.122.99", "host_nobrackets": "192.168.122.99", "port": "6385", "protocol": "http", "uri": "http://192.168.122.99:6385/v1", "uri_no_suffix": "http://192.168.122.99:6385"}, "IronicInternal": {"host": "192.168.122.99", "host_nobrackets": "192.168.122.99", "port": "6385", "protocol": "http", "uri": "http://192.168.122.99:6385/v1", "uri_no_suffix": "http://192.168.122.99:6385"}, "IronicPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "6385", "protocol": "http", "uri": "http://172.21.0.2:6385/v1", "uri_no_suffix": "http://172.21.0.2:6385"}, "IronicInspectorAdmin": {"host": "", "host_nobrackets": "", "port": "5050", "protocol": "http", "uri": "http://:5050", "uri_no_suffix": "http://:5050"}, "IronicInspectorInternal": {"host": "", "host_nobrackets": "", "port": "5050", "protocol": "http", "uri": "http://:5050", "uri_no_suffix": "http://:5050"}, "IronicInspectorPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "5050", "protocol": "http", "uri": "http://172.21.0.2:5050", "uri_no_suffix": "http://172.21.0.2:5050"}, "KeystoneAdmin": {"host": "192.168.122.99", "host_nobrackets": "192.168.122.99", "port": "35357", "protocol": "http", "uri": "http://192.168.122.99:35357/", "uri_no_suffix": "http://192.168.122.99:35357"}, "KeystoneInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "5000", "protocol": "http", "uri": "http://172.17.0.2:5000/", "uri_no_suffix": "http://172.17.0.2:5000"}, "KeystonePublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "5000", "protocol": "http", "uri": "http://172.21.0.2:5000/", "uri_no_suffix": "http://172.21.0.2:5000"}, "KeystoneV3Admin": {"host": "192.168.122.99", "host_nobrackets": "192.168.122.99", "port": "35357", "protocol": "http", "uri": "http://192.168.122.99:35357/v3", "uri_no_suffix": "http://192.168.122.99:35357"}, "KeystoneV3Internal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "5000", "protocol": "http", "uri": "http://172.17.0.2:5000/v3", "uri_no_suffix": "http://172.17.0.2:5000"}, "KeystoneV3Public": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "5000", "protocol": "http", "uri": "http://172.21.0.2:5000/v3", "uri_no_suffix": "http://172.21.0.2:5000"}, "ManilaAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8786", "protocol": "http", "uri": "http://172.17.0.2:8786/v2", "uri_no_suffix": "http://172.17.0.2:8786"}, "ManilaInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8786", "protocol": "http", "uri": "http://172.17.0.2:8786/v2", "uri_no_suffix": "http://172.17.0.2:8786"}, "ManilaPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8786", "protocol": "http", "uri": "http://172.21.0.2:8786/v2", "uri_no_suffix": "http://172.21.0.2:8786"}, "ManilaV1Admin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8786", "protocol": "http", "uri": "http://172.17.0.2:8786/v1/%(tenant_id)s", "uri_no_suffix": "http://172.17.0.2:8786"}, "ManilaV1Internal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8786", "protocol": "http", "uri": "http://172.17.0.2:8786/v1/%(tenant_id)s", "uri_no_suffix": "http://172.17.0.2:8786"}, "ManilaV1Public": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8786", "protocol": "http", "uri": "http://172.21.0.2:8786/v1/%(tenant_id)s", "uri_no_suffix": "http://172.21.0.2:8786"}, "MetricsQdrPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "5666", "protocol": "amqp", "uri": "amqp://172.21.0.2:5666", "uri_no_suffix": "amqp://172.21.0.2:5666"}, "MysqlInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "3306", "protocol": "mysql+pymysql", "uri": "mysql+pymysql://172.17.0.2:3306", "uri_no_suffix": "mysql+pymysql://172.17.0.2:3306"}, "NeutronAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9696", "protocol": "http", "uri": "http://172.17.0.2:9696", "uri_no_suffix": "http://172.17.0.2:9696"}, "NeutronInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9696", "protocol": "http", "uri": "http://172.17.0.2:9696", "uri_no_suffix": "http://172.17.0.2:9696"}, "NeutronPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "9696", "protocol": "http", "uri": "http://172.21.0.2:9696", "uri_no_suffix": "http://172.21.0.2:9696"}, "NovaAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8774", "protocol": "http", "uri": "http://172.17.0.2:8774/v2.1", "uri_no_suffix": "http://172.17.0.2:8774"}, "NovaInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8774", "protocol": "http", "uri": "http://172.17.0.2:8774/v2.1", "uri_no_suffix": "http://172.17.0.2:8774"}, "NovaPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8774", "protocol": "http", "uri": "http://172.21.0.2:8774/v2.1", "uri_no_suffix": "http://172.21.0.2:8774"}, "NovaMetadataInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8775", "protocol": "http", "uri": "http://172.17.0.2:8775", "uri_no_suffix": "http://172.17.0.2:8775"}, "NovaVNCProxyAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "6080", "protocol": "http", "uri": "http://172.17.0.2:6080", "uri_no_suffix": "http://172.17.0.2:6080"}, "NovaVNCProxyInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "6080", "protocol": "http", "uri": "http://172.17.0.2:6080", "uri_no_suffix": "http://172.17.0.2:6080"}, "NovaVNCProxyPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "6080", "protocol": "http", "uri": "http://172.21.0.2:6080", "uri_no_suffix": "http://172.21.0.2:6080"}, "NovajoinAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9090", "protocol": "http", "uri": "http://172.17.0.2:9090/v1", "uri_no_suffix": "http://172.17.0.2:9090"}, "NovajoinInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9090", "protocol": "http", "uri": "http://172.17.0.2:9090/v1", "uri_no_suffix": "http://172.17.0.2:9090"}, "NovajoinPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "9090", "protocol": "http", "uri": "http://172.21.0.2:9090/v1", "uri_no_suffix": "http://172.21.0.2:9090"}, "OctaviaAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9876", "protocol": "http", "uri": "http://172.17.0.2:9876", "uri_no_suffix": "http://172.17.0.2:9876"}, "OctaviaInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "9876", "protocol": "http", "uri": "http://172.17.0.2:9876", "uri_no_suffix": "http://172.17.0.2:9876"}, "OctaviaPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "9876", "protocol": "http", "uri": "http://172.21.0.2:9876", "uri_no_suffix": "http://172.21.0.2:9876"}, "PlacementAdmin": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8778", "protocol": "http", "uri": "http://172.17.0.2:8778/placement", "uri_no_suffix": "http://172.17.0.2:8778"}, "PlacementInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8778", "protocol": "http", "uri": "http://172.17.0.2:8778/placement", "uri_no_suffix": "http://172.17.0.2:8778"}, "PlacementPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8778", "protocol": "http", "uri": "http://172.21.0.2:8778/placement", "uri_no_suffix": "http://172.21.0.2:8778"}, "SwiftAdmin": {"host": "172.18.0.2", "host_nobrackets": "172.18.0.2", "port": "8080", "protocol": "http", "uri": "http://172.18.0.2:8080", "uri_no_suffix": "http://172.18.0.2:8080"}, "SwiftInternal": {"host": "172.18.0.2", "host_nobrackets": "172.18.0.2", "port": "8080", "protocol": "http", "uri": "http://172.18.0.2:8080/v1/AUTH_%(tenant_id)s", "uri_no_suffix": "http://172.18.0.2:8080"}, "SwiftPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8080", "protocol": "http", "uri": "http://172.21.0.2:8080/v1/AUTH_%(tenant_id)s", "uri_no_suffix": "http://172.21.0.2:8080"}, "SwiftS3Admin": {"host": "172.18.0.2", "host_nobrackets": "172.18.0.2", "port": "8080", "protocol": "http", "uri": "http://172.18.0.2:8080", "uri_no_suffix": "http://172.18.0.2:8080"}, "SwiftS3Internal": {"host": "172.18.0.2", "host_nobrackets": "172.18.0.2", "port": "8080", "protocol": "http", "uri": "http://172.18.0.2:8080", "uri_no_suffix": "http://172.18.0.2:8080"}, "SwiftS3Public": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "8080", "protocol": "http", "uri": "http://172.21.0.2:8080", "uri_no_suffix": "http://172.21.0.2:8080"}, "MysqlCellInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "3306", "protocol": "mysql+pymysql", "uri": "mysql+pymysql://172.17.0.2:3306", "uri_no_suffix": "mysql+pymysql://172.17.0.2:3306"}, "NovaVNCProxyCellPublic": {"host": "172.21.0.2", "host_nobrackets": "172.21.0.2", "port": "6080", "protocol": "http", "uri": "http://172.21.0.2:6080", "uri_no_suffix": "http://172.21.0.2:6080"}, "NovaMetadataCellInternal": {"host": "172.17.0.2", "host_nobrackets": "172.17.0.2", "port": "8775", "protocol": "http", "uri": "http://172.17.0.2:8775", "uri_no_suffix": "http://172.17.0.2:8775"}}, "ServiceNetMap": {"ApacheNetwork": "internal_api", "NeutronTenantNetwork": "tenant", "AodhApiNetwork": "internal_api", "BarbicanApiNetwork": "internal_api", "GnocchiApiNetwork": "internal_api", "MongodbNetwork": "internal_api", "CinderApiNetwork": "internal_api", "CinderIscsiNetwork": "storage", "GlanceApiNetwork": "internal_api", "GlanceApiEdgeNetwork": "internal_api", "GlanceApiInternalNetwork": "internal_api", "IronicApiNetwork": "ctlplane", "IronicNetwork": "baremetal", "IronicInspectorNetwork": "baremetal", "KeystoneAdminApiNetwork": "ctlplane", "KeystonePublicApiNetwork": "internal_api", "ManilaApiNetwork": "internal_api", "NeutronApiNetwork": "internal_api", "OctaviaApiNetwork": "internal_api", "HeatApiNetwork": "internal_api", "HeatApiCfnNetwork": "internal_api", "HeatApiCloudwatchNetwork": "internal_api", "NovaApiNetwork": "internal_api", "PlacementNetwork": "internal_api", "NovaMetadataNetwork": "internal_api", "NovaLibvirtNetwork": "internal_api", "NovajoinNetwork": "internal_api", "SwiftStorageNetwork": "storage_mgmt", "SwiftProxyNetwork": "storage", "HorizonNetwork": "internal_api", "MemcachedNetwork": "internal_api", "OsloMessagingRpcNetwork": "internal_api", "OsloMessagingNotifyNetwork": "internal_api", "RabbitmqNetwork": "internal_api", "RabbitmqManagementNetwork": "internal_api", "QdrNetwork": "internal_api", "RedisNetwork": "internal_api", "GaneshaNetwork": "external", "MysqlNetwork": "internal_api", "SnmpdNetwork": "ctlplane", "CephClusterNetwork": "storage_mgmt", "CephDashboardNetwork": "ctlplane", "CephGrafanaNetwork": "storage", "CephMonNetwork": "storage", "CephRgwNetwork": "storage", "PublicNetwork": "external", "InternalApiNetwork": "internal_api", "OpendaylightApiNetwork": "internal_api", "OvnDbsNetwork": "internal_api", "DockerRegistryNetwork": "ctlplane", "PacemakerNetwork": "internal_api", "PacemakerRemoteNetwork": "internal_api", "DesignateApiNetwork": "internal_api", "DesignateMdnsNetwork": "internal_api", "DesignateWorkerNetwork": "external", "DesignateBindNetwork": "external", "BINDNetwork": "external", "EtcdNetwork": "internal_api", "HaproxyNetwork": "ctlplane", "UnboundNetwork": "external", "StandaloneHostnameResolveNetwork": "internal_api", "StandaloneMetricsQdrNetwork": "internal_api", "NovaVncProxyNetwork": "internal_api"}, "RoleName": "Standalone", "RoleParameters": {"OVNCMSOptions": "enable-chassis-as-gw"}}


created_at: 2025-12-01 09:42:26.823559
data:
  {"type": "json", "value": {"ContainerNovaComputeImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "ContainerNovaLibvirtConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1"}}


created_at: 2025-12-01 09:42:30.055895
data:
  {"volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro"], "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-54-dje5sal4neu5-ContainersCommon-jwhxgb37siih/ada57717-39a8-41de-b903-4b9f56bc3401"}


created_at: 2025-12-01 09:42:30.112807
data:
  {"tuple:('role_data', 'step_config')": "include tripleo::profile::base::sshd", "tuple:('role_data', 'config_settings')": {"tripleo::profile::base::sshd::bannertext": "", "tripleo::profile::base::sshd::motd": "", "tripleo::profile::base::sshd::options": {"HostKey": ["/etc/ssh/ssh_host_rsa_key", "/etc/ssh/ssh_host_ecdsa_key", "/etc/ssh/ssh_host_ed25519_key"], "SyslogFacility": "AUTHPRIV", "AuthorizedKeysFile": ".ssh/authorized_keys", "ChallengeResponseAuthentication": "no", "GSSAPIAuthentication": "no", "GSSAPICleanupCredentials": "no", "UsePAM": "yes", "UseDNS": "no", "PrintMotd": "no", "X11Forwarding": "yes", "AcceptEnv": ["LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES", "LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT", "LC_IDENTIFICATION LC_ALL LANGUAGE", "XMODIFIERS"], "Subsystem": "sftp  /usr/libexec/openssh/sftp-server"}, "tripleo::profile::base::sshd::password_authentication": "no"}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-54-dje5sal4neu5-SshdBase-rvlfqjgn22ny/13ed5b2c-dfdc-4b3d-90cd-241bf160d17f"}


created_at: 2025-12-01 09:42:30.115477
data:
  {"value": {"ContainerNovaComputeImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "ContainerNovaLibvirtConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1"}}


created_at: 2025-12-01 09:42:30.123649
data:
  {"tuple:('role_data', 'step_config')": null, "tuple:('role_data', 'docker_config')": {"step_4": {"nova_migration_target": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "net": "host", "privileged": true, "user": "root", "restart": "always", "healthcheck": {"test": "/openstack/healthcheck"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/kolla/config_files/nova-migration-target.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/etc/ssh:/host-ssh:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}}}, "tuple:('role_data', 'service_names')": null, "tuple:('role_data', 'container_config_scripts')": null, "tuple:('role_data', 'service_name')": "nova_migration_target", "tuple:('role_data', 'config_settings')": {"tripleo::profile::base::sshd::bannertext": "", "tripleo::profile::base::sshd::motd": "", "tripleo::profile::base::sshd::options": {"HostKey": ["/etc/ssh/ssh_host_rsa_key", "/etc/ssh/ssh_host_ecdsa_key", "/etc/ssh/ssh_host_ed25519_key"], "SyslogFacility": "AUTHPRIV", "AuthorizedKeysFile": ".ssh/authorized_keys", "ChallengeResponseAuthentication": "no", "GSSAPIAuthentication": "no", "GSSAPICleanupCredentials": "no", "UsePAM": "yes", "UseDNS": "no", "PrintMotd": "no", "X11Forwarding": "yes", "AcceptEnv": ["LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES", "LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT", "LC_IDENTIFICATION LC_ALL LANGUAGE", "XMODIFIERS"], "Subsystem": "sftp  /usr/libexec/openssh/sftp-server"}, "tripleo::profile::base::sshd::password_authentication": "no", "tripleo::profile::base::nova::migration::target::ssh_authorized_keys": ["ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNxvXP6Rg/XRSORMEfhufG8JdbP53JPAUe1RGMG3a8AOB56mE3EFGdN7uTKwTybnwoe4Un2bkt1r8qAqsUIm2C2N+q5AnNxsnpx/ipuWKUtpxAbfhSpzgUtReRK8DAiuIslfaIYO+DZ9/tsCh+4PnJrjU5TrUcQeG1mLbEsQDQj2NCVVLSnw+snLw4B8wMgpBPc5EN8rZAS4sytpu6DZ1ja+/lv1IBKNCsIH7uRgtXFKhRpSqhyI+sGfmdrc0ypT52HuvQ/aak6dARRvi9FvDanz1jXRh2JvNdVp3Q9tFxmMSmBCs15kht8y4UMN9J+7SnJ7tWbkfO8DC2NQIxA9sF Generated by TripleO"], "tripleo::profile::base::nova::migration::target::ssh_localaddrs": ["%{hiera('cold_migration_ssh_inbound_addr')}", "%{hiera('live_migration_ssh_inbound_addr')}"], "live_migration_ssh_inbound_addr": "%{hiera('internal_api')}", "cold_migration_ssh_inbound_addr": "%{hiera('internal_api')}", "tripleo::profile::base::sshd::port": [22]}, "role_data": {"service_name": "nova_migration_target", "firewall_rules": {"113 nova_migration_target accept libvirt subnet 172.17.0.0/24": {"source": "172.17.0.0/24", "proto": "tcp", "dport": 2022}, "113 nova_migration_target accept api subnet 172.17.0.0/24": {"source": "172.17.0.0/24", "proto": "tcp", "dport": 2022}}, "config_settings": {"tripleo::profile::base::sshd::bannertext": "", "tripleo::profile::base::sshd::motd": "", "tripleo::profile::base::sshd::options": {"HostKey": ["/etc/ssh/ssh_host_rsa_key", "/etc/ssh/ssh_host_ecdsa_key", "/etc/ssh/ssh_host_ed25519_key"], "SyslogFacility": "AUTHPRIV", "AuthorizedKeysFile": ".ssh/authorized_keys", "ChallengeResponseAuthentication": "no", "GSSAPIAuthentication": "no", "GSSAPICleanupCredentials": "no", "UsePAM": "yes", "UseDNS": "no", "PrintMotd": "no", "X11Forwarding": "yes", "AcceptEnv": ["LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES", "LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT", "LC_IDENTIFICATION LC_ALL LANGUAGE", "XMODIFIERS"], "Subsystem": "sftp  /usr/libexec/openssh/sftp-server"}, "tripleo::profile::base::sshd::password_authentication": "no", "tripleo::profile::base::nova::migration::target::ssh_authorized_keys": ["ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNxvXP6Rg/XRSORMEfhufG8JdbP53JPAUe1RGMG3a8AOB56mE3EFGdN7uTKwTybnwoe4Un2bkt1r8qAqsUIm2C2N+q5AnNxsnpx/ipuWKUtpxAbfhSpzgUtReRK8DAiuIslfaIYO+DZ9/tsCh+4PnJrjU5TrUcQeG1mLbEsQDQj2NCVVLSnw+snLw4B8wMgpBPc5EN8rZAS4sytpu6DZ1ja+/lv1IBKNCsIH7uRgtXFKhRpSqhyI+sGfmdrc0ypT52HuvQ/aak6dARRvi9FvDanz1jXRh2JvNdVp3Q9tFxmMSmBCs15kht8y4UMN9J+7SnJ7tWbkfO8DC2NQIxA9sF Generated by TripleO"], "tripleo::profile::base::nova::migration::target::ssh_localaddrs": ["%{hiera('cold_migration_ssh_inbound_addr')}", "%{hiera('live_migration_ssh_inbound_addr')}"], "live_migration_ssh_inbound_addr": "%{hiera('internal_api')}", "cold_migration_ssh_inbound_addr": "%{hiera('internal_api')}", "tripleo::profile::base::sshd::port": [22]}, "puppet_config": {"config_volume": "nova_libvirt", "step_config": "include tripleo::profile::base::sshd\ninclude tripleo::profile::base::nova::migration::target", "config_image": "registry.redhat.io/rhosp-rhel9/openstack-nova-libvirt:17.1"}, "kolla_config": {"/var/lib/kolla/config_files/nova-migration-target.json": {"command": "dumb-init --single-child -- /usr/sbin/sshd -D -p 2022", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/host-ssh/ssh_host_*_key", "dest": "/etc/ssh/", "owner": "root", "perm": "0600"}]}}, "host_prep_tasks": [{"name": "Create libvirt persistent data directories", "file": {"path": "{{ item.path }}", "state": "directory", "setype": "{{ item.setype }}"}, "loop": [{"path": "/run/libvirt", "setype": "virt_var_run_t"}]}, {"name": "ensure /run/libvirt is present upon reboot", "copy": {"dest": "/etc/tmpfiles.d/run-libvirt.conf", "content": "d /run/libvirt 0755 root root - -\n"}}], "docker_config": {"step_4": {"nova_migration_target": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-compute:17.1", "net": "host", "privileged": true, "user": "root", "restart": "always", "healthcheck": {"test": "/openstack/healthcheck"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/kolla/config_files/nova-migration-target.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/config-data/puppet-generated/nova_libvirt:/var/lib/kolla/config_files/src:ro", "/etc/ssh:/host-ssh:ro", "/run/libvirt:/run/libvirt:shared,z", "/var/lib/nova:/var/lib/nova:shared"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}}}, "deploy_steps_tasks": [{"name": "validate nova-migration-target container state", "containers.podman.podman_container_info": {"name": "nova_migration_target"}, "register": "nova_migration_target_infos", "failed_when": ["nova_migration_target_infos.containers.0.Healthcheck.Status is defined", "'healthy' not in nova_migration_target_infos.containers.0.Healthcheck.Status"], "retries": 10, "delay": 30, "tags": ["opendev-validation", "opendev-validation-nova"], "when": ["container_cli == 'podman'", "not container_healthcheck_disabled", "step|int == 5"]}], "update_tasks": [{"name": "nova_migration_target_tmpfile_cleanup", "when": "step|int == 1", "block": [{"name": "Remove old tmpfiles.d config", "file": {"path": "/etc/tmpfiles.d/var-run-libvirt.conf", "state": "absent"}}]}], "upgrade_tasks": [{"name": "nova_migration_target_tmpfile_cleanup", "when": "step|int == 1", "block": [{"name": "Remove old tmpfiles.d config", "file": {"path": "/etc/tmpfiles.d/var-run-libvirt.conf", "state": "absent"}}]}]}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-54-dje5sal4neu5/74d14fdf-1094-420d-830b-d05a6dc036ee"}


created_at: 2025-12-01 09:42:33.542198
data:
  {"type": "json", "value": {"ContainerNovaVncProxyImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-novncproxy:17.1", "ContainerNovaConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-api:17.1"}}


created_at: 2025-12-01 09:42:33.570873
data:
  {"value": {"ContainerNovaVncProxyImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-novncproxy:17.1", "ContainerNovaConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-api:17.1"}}


created_at: 2025-12-01 09:42:33.654637
data:
  {"ContainerNovaImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-novncproxy:17.1", "NovaServiceName": "vncproxy"}


created_at: 2025-12-01 09:42:33.785186
data:
  {"type": "json", "value": {"ContainerNovaImage": "registry.redhat.io/rhosp-rhel9/openstack-nova-novncproxy:17.1"}}


created_at: 2025-12-01 09:42:36.640533
data:
  {"tuple:('role_data', 'service_config_settings', 'mysql')": {"nova::db::mysql::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::db::mysql::user": "nova", "nova::db::mysql::host": "%", "nova::db::mysql::dbname": "nova"}, "tuple:('role_data', 'config_settings')": {"nova::database_connection": "mysql+pymysql://nova:dSyjAjYTpDrZAHQaM4GGXWDxx@172.17.0.2/nova?read_default_file=/etc/my.cnf.d/tripleo.cnf&read_default_group=tripleo"}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-55-kjfkznxixvt5-NovaDBClient-ebd5suknoixs/f006eba3-7562-4f23-bd41-f1128c643ae0"}


created_at: 2025-12-01 09:42:36.695746
data:
  {"tuple:('role_data', 'step_config')": "include tripleo::profile::base::database::mysql::client", "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-55-kjfkznxixvt5-MySQLClient-qtuuoud2ky3i/3cb97562-7df4-40e3-b82b-7e4d782e3c53"}


created_at: 2025-12-01 09:42:36.748694
data:
  {"volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro"], "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-55-kjfkznxixvt5-ContainersCommon-wo6h473hvryy/9837be3c-2f40-4505-9beb-653be3cbd783"}


created_at: 2025-12-01 09:42:36.859682
data:
  {"volumes": ["/var/log/containers/nova:/var/log/nova"], "host_prep_tasks": [{"name": "create persistent directories", "file": {"path": "{{ item.path }}", "setype": "{{ item.setype }}", "state": "directory", "mode": "{{ item.mode }}"}, "with_items": [{"path": "/var/log/containers/nova", "setype": "container_file_t", "mode": "0750"}]}], "config_settings": null, "cmd_extra_args": "", "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-55-kjfkznxixvt5-NovaLogging-5tw33xlpxzjb/fccd8c80-6d5b-448b-8914-21ba605acfcb"}


created_at: 2025-12-01 09:42:36.915696
data:
  {"tuple:('role_data', 'config_settings')": {"nova::my_ip": "%{hiera('internal_api')}", "nova::rabbit_use_ssl": "False", "nova::keystone::service_user::send_service_user_token": true, "nova::keystone::service_user::project_name": "service", "nova::keystone::service_user::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::keystone::service_user::auth_url": "http://172.17.0.2:5000", "nova::keystone::service_user::region_name": "regionOne", "nova::placement::project_name": "service", "nova::placement::password": "dYVRSnGa4R5DjmK0t4f9aWqpK", "nova::placement::auth_url": "http://172.17.0.2:5000", "nova::placement::region_name": "regionOne", "nova::placement::valid_interfaces": "internal", "nova::os_region_name": "regionOne", "nova::logging::debug": true, "nova::purge_config": false, "nova::network::neutron::project_name": "service", "nova::network::neutron::username": "neutron", "nova::network::neutron::region_name": "regionOne", "nova::dhcp_domain": "", "nova::network::neutron::password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "nova::network::neutron::auth_url": "http://172.17.0.2:5000/v3", "nova::network::neutron::valid_interfaces": "internal", "nova::glance::valid_interfaces": "internal", "nova::rabbit_heartbeat_timeout_threshold": 60, "nova::cinder_catalog_info": "volumev3:cinderv3:internalURL", "nova::host": "%{hiera('fqdn_canonical')}", "nova::notify_on_state_change": "vm_and_task_state", "nova::notification_driver": ["messagingv2"], "nova::notification_format": "unversioned", "nova::network::neutron::auth_type": "v3password", "nova::db::database_db_max_retries": -1, "nova::db::database_max_retries": -1, "nova::network::neutron::ovs_bridge": "br-int", "nova::compute::sync_power_state_interval": 600, "nova_is_additional_cell": false, "nova::cross_az_attach": true, "nova::cache::enabled": true, "nova::cache::tls_enabled": false, "nova::cache::backend": "dogpile.cache.memcached", "nova::rabbit_heartbeat_in_pthread": false, "nova::ovsdb_connection": ""}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-55-kjfkznxixvt5-NovaBase-4ntv7bsdcpji/2047e9c2-2af4-454f-ad44-31e5f992197c"}


created_at: 2025-12-01 09:42:36.929671
data:
  {"tuple:('role_data', 'step_config')": null, "tuple:('role_data', 'docker_config')": {"step_4": {"nova_vnc_proxy": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-novncproxy:17.1", "net": "host", "privileged": false, "restart": "always", "healthcheck": {"test": "/openstack/healthcheck"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/nova:/var/log/nova", "/var/lib/kolla/config_files/nova_vnc_proxy.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/config-data/puppet-generated/nova:/var/lib/kolla/config_files/src:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}}}, "tuple:('role_data', 'service_names')": null, "tuple:('role_data', 'container_config_scripts')": null, "tuple:('role_data', 'service_name')": "nova_vnc_proxy", "tuple:('role_data', 'config_settings')": {"nova::my_ip": "%{hiera('internal_api')}", "nova::rabbit_use_ssl": "False", "nova::keystone::service_user::send_service_user_token": true, "nova::keystone::service_user::project_name": "service", "nova::keystone::service_user::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::keystone::service_user::auth_url": "http://172.17.0.2:5000", "nova::keystone::service_user::region_name": "regionOne", "nova::placement::project_name": "service", "nova::placement::password": "dYVRSnGa4R5DjmK0t4f9aWqpK", "nova::placement::auth_url": "http://172.17.0.2:5000", "nova::placement::region_name": "regionOne", "nova::placement::valid_interfaces": "internal", "nova::os_region_name": "regionOne", "nova::logging::debug": true, "nova::purge_config": false, "nova::network::neutron::project_name": "service", "nova::network::neutron::username": "neutron", "nova::network::neutron::region_name": "regionOne", "nova::dhcp_domain": "", "nova::network::neutron::password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "nova::network::neutron::auth_url": "http://172.17.0.2:5000/v3", "nova::network::neutron::valid_interfaces": "internal", "nova::glance::valid_interfaces": "internal", "nova::rabbit_heartbeat_timeout_threshold": 60, "nova::cinder_catalog_info": "volumev3:cinderv3:internalURL", "nova::host": "%{hiera('fqdn_canonical')}", "nova::notify_on_state_change": "vm_and_task_state", "nova::notification_driver": ["messagingv2"], "nova::notification_format": "unversioned", "nova::network::neutron::auth_type": "v3password", "nova::db::database_db_max_retries": -1, "nova::db::database_max_retries": -1, "nova::network::neutron::ovs_bridge": "br-int", "nova::compute::sync_power_state_interval": 600, "nova_is_additional_cell": false, "nova::cross_az_attach": true, "nova::cache::enabled": true, "nova::cache::tls_enabled": false, "nova::cache::backend": "dogpile.cache.memcached", "nova::rabbit_heartbeat_in_pthread": false, "nova::ovsdb_connection": "", "nova::database_connection": "mysql+pymysql://nova:dSyjAjYTpDrZAHQaM4GGXWDxx@172.17.0.2/nova?read_default_file=/etc/my.cnf.d/tripleo.cnf&read_default_group=tripleo", "nova::vncproxy::enabled": true, "nova::vncproxy::common::vncproxy_protocol": "http", "nova::vncproxy::common::vncproxy_host": "172.21.0.2", "nova::vncproxy::common::vncproxy_port": "6080", "nova::vncproxy::host": "%{hiera('internal_api')}"}, "role_data": {"service_name": "nova_vnc_proxy", "firewall_rules": {"137 nova_vnc_proxy": {"dport": [6080]}}, "firewall_frontend_rules": {"100 nova_vncproxy_haproxy_frontend": {"dport": [6080]}}, "firewall_ssl_frontend_rules": {"100 nova_vncproxy_haproxy_frontend_ssl": {"dport": [13080]}}, "config_settings": {"nova::my_ip": "%{hiera('internal_api')}", "nova::rabbit_use_ssl": "False", "nova::keystone::service_user::send_service_user_token": true, "nova::keystone::service_user::project_name": "service", "nova::keystone::service_user::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::keystone::service_user::auth_url": "http://172.17.0.2:5000", "nova::keystone::service_user::region_name": "regionOne", "nova::placement::project_name": "service", "nova::placement::password": "dYVRSnGa4R5DjmK0t4f9aWqpK", "nova::placement::auth_url": "http://172.17.0.2:5000", "nova::placement::region_name": "regionOne", "nova::placement::valid_interfaces": "internal", "nova::os_region_name": "regionOne", "nova::logging::debug": true, "nova::purge_config": false, "nova::network::neutron::project_name": "service", "nova::network::neutron::username": "neutron", "nova::network::neutron::region_name": "regionOne", "nova::dhcp_domain": "", "nova::network::neutron::password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "nova::network::neutron::auth_url": "http://172.17.0.2:5000/v3", "nova::network::neutron::valid_interfaces": "internal", "nova::glance::valid_interfaces": "internal", "nova::rabbit_heartbeat_timeout_threshold": 60, "nova::cinder_catalog_info": "volumev3:cinderv3:internalURL", "nova::host": "%{hiera('fqdn_canonical')}", "nova::notify_on_state_change": "vm_and_task_state", "nova::notification_driver": ["messagingv2"], "nova::notification_format": "unversioned", "nova::network::neutron::auth_type": "v3password", "nova::db::database_db_max_retries": -1, "nova::db::database_max_retries": -1, "nova::network::neutron::ovs_bridge": "br-int", "nova::compute::sync_power_state_interval": 600, "nova_is_additional_cell": false, "nova::cross_az_attach": true, "nova::cache::enabled": true, "nova::cache::tls_enabled": false, "nova::cache::backend": "dogpile.cache.memcached", "nova::rabbit_heartbeat_in_pthread": false, "nova::ovsdb_connection": "", "nova::database_connection": "mysql+pymysql://nova:dSyjAjYTpDrZAHQaM4GGXWDxx@172.17.0.2/nova?read_default_file=/etc/my.cnf.d/tripleo.cnf&read_default_group=tripleo", "nova::vncproxy::enabled": true, "nova::vncproxy::common::vncproxy_protocol": "http", "nova::vncproxy::common::vncproxy_host": "172.21.0.2", "nova::vncproxy::common::vncproxy_port": "6080", "nova::vncproxy::host": "%{hiera('internal_api')}"}, "service_config_settings": {"rabbitmq": {"get_attr": ["NovaBase", "role_data", "service_config_settings"], "rabbitmq": null}, "mysql": {"nova::db::mysql::password": "dSyjAjYTpDrZAHQaM4GGXWDxx", "nova::db::mysql::user": "nova", "nova::db::mysql::host": "%", "nova::db::mysql::dbname": "nova"}, "rsyslog": {"tripleo_logging_sources_nova_vnc_proxy": [{"tag": "openstack.nova.vncproxy", "file": "/var/log/containers/nova/nova-novncproxy.log"}]}}, "puppet_config": {"config_volume": "nova", "puppet_tags": "nova_config", "step_config": "include tripleo::profile::base::nova::vncproxy\ninclude tripleo::profile::base::database::mysql::client", "config_image": "registry.redhat.io/rhosp-rhel9/openstack-nova-api:17.1"}, "kolla_config": {"/var/lib/kolla/config_files/nova_vnc_proxy.json": {"command": "/usr/bin/nova-novncproxy --web /usr/share/novnc/ ", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-tls/*", "dest": "/", "merge": true, "preserve_properties": true, "optional": true}], "permissions": [{"path": "/var/log/nova", "owner": "nova:nova", "recurse": true}, {"path": "/etc/pki/tls/certs/novnc-proxy.crt", "owner": "root:root", "perm": "0644"}, {"path": "/etc/pki/tls/private/novnc-proxy.key", "owner": "root:qemu", "perm": "0640"}, {"path": "/etc/pki/tls/certs/libvirt-vnc-client-cert.crt", "owner": "root:root", "perm": "0644"}, {"path": "/etc/pki/tls/private/libvirt-vnc-client-cert.key", "owner": "root:qemu", "perm": "0640"}]}}, "docker_config": {"step_4": {"nova_vnc_proxy": {"image": "registry.redhat.io/rhosp-rhel9/openstack-nova-novncproxy:17.1", "net": "host", "privileged": false, "restart": "always", "healthcheck": {"test": "/openstack/healthcheck"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/nova:/var/log/nova", "/var/lib/kolla/config_files/nova_vnc_proxy.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/config-data/puppet-generated/nova:/var/lib/kolla/config_files/src:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}}}, "deploy_steps_tasks": [{"name": "validate nova-vnc-proxy container state", "containers.podman.podman_container_info": {"name": "nova_vnc_proxy"}, "register": "nova_vnc_proxy_infos", "failed_when": ["nova_vnc_proxy_infos.containers.0.Healthcheck.Status is defined", "'healthy' not in nova_vnc_proxy_infos.containers.0.Healthcheck.Status"], "retries": 10, "delay": 30, "tags": ["opendev-validation", "opendev-validation-nova"], "when": ["container_cli == 'podman'", "not container_healthcheck_disabled", "step|int == 5"]}], "host_prep_tasks": [{"name": "create persistent directories", "file": {"path": "{{ item.path }}", "setype": "{{ item.setype }}", "state": "directory", "mode": "{{ item.mode }}"}, "with_items": [{"path": "/var/log/containers/nova", "setype": "container_file_t", "mode": "0750"}]}, {"name": "ensure qemu group is present on the host", "group": {"name": "qemu", "gid": 107, "state": "present"}}, {"name": "ensure qemu user is present on the host", "user": {"name": "qemu", "uid": 107, "group": "qemu", "state": "present", "shell": "/sbin/nologin", "comment": "qemu user"}}], "post_upgrade_tasks": [{"when": ["step|int == 3"], "become": true, "environment": {"OS_CLOUD": "standalone"}, "block": [{"name": "Get nova-consoleauth service ID", "command": "openstack compute service list --service nova-consoleauth --column ID  --column Host --format yaml", "register": "nova_compute_service_result", "check_mode": false, "run_once": true, "changed_when": false, "failed_when": false, "delegate_to": "{{ groups['Undercloud'] | first }}"}, {"name": "Deleting nova-consoleauth", "command": "openstack compute service delete {{ item.ID }}", "loop": "{{ nova_compute_service_result.stdout | from_yaml | default([]) }}", "run_once": true, "delegate_to": "{{ groups['Undercloud'] | first }}", "failed_when": false}]}], "external_upgrade_tasks": [{"when": ["step|int == 1"], "tags": ["never", "system_upgrade_transfer_data", "system_upgrade_stop_services"], "block": [{"name": "Stop nova vnc proxy container", "import_role": {"name": "tripleo_container_stop"}, "vars": {"tripleo_containers_to_stop": ["nova_vnc_proxy"], "tripleo_delegate_to": "{{ groups['nova_vnc_proxy'] | difference(groups['excluded_overcloud']) }}"}}]}]}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-55-kjfkznxixvt5/c4113044-4296-4bda-acc7-19ea2dc3c655"}


created_at: 2025-12-01 09:42:37.285588
data:
  {"type": "json", "value": {"ovn_bridge_mappings": ["datacentre:br-ctlplane"], "ovn_static_bridge_mac_mappings": {"standalone": {"datacentre": "fa:16:3a:00:53:00"}}}}


created_at: 2025-12-01 09:42:39.316706
data:
  {"type": "json", "value": {"ovn::controller::ovn_bridge_mappings": ["datacentre:br-ctlplane"], "ovn::controller::ovn_cms_options": "enable-chassis-as-gw", "ovn::controller::ovn_encap_tos": "0", "vswitch::ovs::enable_hw_offload": false, "container_cpuset_cpus": "", "ContainerOvnControllerImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "ContainerOvnControllerConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1"}}


created_at: 2025-12-01 09:42:40.402120
data:
  {"volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro"], "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-56-bfjg3iqov75s-ContainersCommon-nzkcdrciqrgm/f355aa98-dcef-4f2d-9559-940ec0cca0b6"}


created_at: 2025-12-01 09:42:40.406502
data:
  {"value": {"ovn::controller::ovn_bridge_mappings": ["datacentre:br-ctlplane"], "ovn::controller::ovn_cms_options": "enable-chassis-as-gw", "ovn::controller::ovn_encap_tos": "0", "vswitch::ovs::enable_hw_offload": false, "container_cpuset_cpus": "", "ContainerOvnControllerImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "ContainerOvnControllerConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1"}}


created_at: 2025-12-01 09:42:40.410539
data:
  {"value": {"ovn_bridge_mappings": ["datacentre:br-ctlplane"], "ovn_static_bridge_mac_mappings": {"standalone": {"datacentre": "fa:16:3a:00:53:00"}}}}


created_at: 2025-12-01 09:42:40.424792
data:
  {"tuple:('role_data', 'step_config')": null, "tuple:('role_data', 'docker_config')": {"step_4": {"configure_cms_options": {"start_order": 0, "detach": false, "net": "host", "privileged": true, "user": "root", "command": ["/bin/bash", "-c", "CMS_OPTS=$(hiera ovn::controller::ovn_cms_options -c /etc/puppet/hiera.yaml);  if [ X\"$CMS_OPTS\" !=  X ]; then ovs-vsctl set open . external_ids:ovn-cms-options=$CMS_OPTS;else ovs-vsctl remove open . external_ids ovn-cms-options; fi"], "image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/lib/modules:/lib/modules:ro", "/run/openvswitch:/run/openvswitch:shared,z"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}, "ovn_controller": {"start_order": 1, "image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "net": "host", "privileged": true, "user": "root", "restart": "always", "depends_on": ["openvswitch.service"], "healthcheck": {"test": "/openstack/healthcheck 6642"}, "volumes": ["/var/lib/kolla/config_files/ovn_controller.json:/var/lib/kolla/config_files/config.json:ro", "/lib/modules:/lib/modules:ro", "/run:/run", "/var/lib/openvswitch/ovn:/run/ovn:shared,z", "/var/log/containers/openvswitch:/var/log/openvswitch:z", "/var/log/containers/openvswitch:/var/log/ovn:z"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}}}, "tuple:('role_data', 'service_names')": null, "tuple:('role_data', 'container_config_scripts')": null, "tuple:('role_data', 'service_name')": "ovn_controller", "tuple:('role_data', 'config_settings')": {"ovn::controller::ovn_bridge_mappings": ["datacentre:br-ctlplane"], "ovn::controller::ovn_cms_options": "enable-chassis-as-gw", "ovn::controller::ovn_encap_tos": "0", "vswitch::ovs::enable_hw_offload": false, "container_cpuset_cpus": "", "ContainerOvnControllerImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "ContainerOvnControllerConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "ovn::southbound::port": 6642, "ovn::controller::ovn_encap_ip": "%{hiera('tenant')}", "ovn::controller::ovn_encap_type": "geneve", "ovn::controller::ovn_bridge": "br-int", "ovn::controller::hostname": "%{hiera('fqdn_canonical')}", "ovn::controller::ovn_remote_probe_interval": 60000, "ovn::controller::ovn_openflow_probe_interval": 60, "ovn::controller::ovn_ofctrl_wait_before_clear": 8000, "ovn::controller::garp_max_timeout_sec": 0, "ovn::controller::ovn_monitor_all": true}, "role_data": {"service_name": "ovn_controller", "firewall_rules": {"118 neutron vxlan networks": {"proto": "udp", "dport": 4789, "state": []}, "119 neutron geneve networks": {"proto": "udp", "dport": 6081, "state": []}, "120 neutron geneve networks no conntrack": {"proto": "udp", "dport": 6081, "table": "raw", "chain": "OUTPUT", "jump": "NOTRACK", "action": "append", "state": ["INVALID"]}, "121 neutron geneve networks no conntrack": {"proto": "udp", "dport": 6081, "table": "raw", "chain": "PREROUTING", "jump": "NOTRACK", "action": "append", "state": ["INVALID"]}}, "config_settings": {"ovn::controller::ovn_bridge_mappings": ["datacentre:br-ctlplane"], "ovn::controller::ovn_cms_options": "enable-chassis-as-gw", "ovn::controller::ovn_encap_tos": "0", "vswitch::ovs::enable_hw_offload": false, "container_cpuset_cpus": "", "ContainerOvnControllerImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "ContainerOvnControllerConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "ovn::southbound::port": 6642, "ovn::controller::ovn_encap_ip": "%{hiera('tenant')}", "ovn::controller::ovn_encap_type": "geneve", "ovn::controller::ovn_bridge": "br-int", "ovn::controller::hostname": "%{hiera('fqdn_canonical')}", "ovn::controller::ovn_remote_probe_interval": 60000, "ovn::controller::ovn_openflow_probe_interval": 60, "ovn::controller::ovn_ofctrl_wait_before_clear": 8000, "ovn::controller::garp_max_timeout_sec": 0, "ovn::controller::ovn_monitor_all": true}, "service_config_settings": {}, "puppet_config": {"puppet_tags": "vs_config,exec", "config_volume": "ovn_controller", "step_config": "include tripleo::profile::base::neutron::agents::ovn\n", "config_image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "volumes": ["/lib/modules:/lib/modules:ro", "/run/openvswitch:/run/openvswitch:shared,z", "/etc/sysconfig/modules:/etc/sysconfig/modules"]}, "kolla_config": {"/var/lib/kolla/config_files/ovn_controller.json": {"command": "/usr/bin/ovn-controller --pidfile --log-file unix:/run/openvswitch/db.sock ", "permissions": [{"path": "/var/log/openvswitch", "owner": "root:root", "recurse": true}, {"path": "/var/log/ovn", "owner": "root:root", "recurse": true}]}}, "metadata_settings": null, "docker_config": {"step_4": {"configure_cms_options": {"start_order": 0, "detach": false, "net": "host", "privileged": true, "user": "root", "command": ["/bin/bash", "-c", "CMS_OPTS=$(hiera ovn::controller::ovn_cms_options -c /etc/puppet/hiera.yaml);  if [ X\"$CMS_OPTS\" !=  X ]; then ovs-vsctl set open . external_ids:ovn-cms-options=$CMS_OPTS;else ovs-vsctl remove open . external_ids ovn-cms-options; fi"], "image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/lib/modules:/lib/modules:ro", "/run/openvswitch:/run/openvswitch:shared,z"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}, "ovn_controller": {"start_order": 1, "image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "net": "host", "privileged": true, "user": "root", "restart": "always", "depends_on": ["openvswitch.service"], "healthcheck": {"test": "/openstack/healthcheck 6642"}, "volumes": ["/var/lib/kolla/config_files/ovn_controller.json:/var/lib/kolla/config_files/config.json:ro", "/lib/modules:/lib/modules:ro", "/run:/run", "/var/lib/openvswitch/ovn:/run/ovn:shared,z", "/var/log/containers/openvswitch:/var/log/openvswitch:z", "/var/log/containers/openvswitch:/var/log/ovn:z"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}}}, "deploy_steps_tasks": [{"name": "Certificate generation", "when": ["step|int == 1", "enable_internal_tls"], "block": [{"include_role": {"name": "linux-system-roles.certificate"}, "vars": {"certificate_requests": [{"name": "ovn_controller", "dns": "{{fqdn_internal_api}}", "principal": "ovn_controller/{{fqdn_internal_api}}@{{idm_realm}}", "key_size": "2048", "ca": "ipa"}]}}]}], "host_prep_tasks": [{"name": "create persistent directories", "file": {"path": "{{ item.path }}", "state": "directory", "setype": "{{ item.setype }}", "mode": "{{ item.mode|default(omit) }}"}, "with_items": [{"path": "/var/log/containers/openvswitch", "setype": "container_file_t", "mode": "0750"}, {"path": "/var/lib/openvswitch/ovn", "setype": "container_file_t"}]}, {"name": "enable virt_sandbox_use_netlink for healthcheck", "seboolean": {"name": "virt_sandbox_use_netlink", "persistent": true, "state": true}, "when": ["ansible_facts.selinux is defined", "ansible_facts.selinux.status == \"enabled\""]}, {"name": "Copy in cleanup script", "copy": {"content": "#!/usr/bin/bash\n# Cleanup neutron OVS bridges. To be called on startup to avoid\n# \"difficult-to-debug\" issues with partially configured resources.\n\nNEUTRON_OVS_CONF=/var/lib/config-data/puppet-generated/neutron/etc/neutron/plugins/ml2/openvswitch_agent.ini\n\nif [ -e ${NEUTRON_OVS_CONF} ];\nthen\n    INT_BRIDGE=`crudini --get ${NEUTRON_OVS_CONF} ovs integration_bridge`\n    TUN_BRIDGE=`crudini --get ${NEUTRON_OVS_CONF} ovs tunnel_bridge`\nfi\n\nfor port in `ovs-vsctl list-ports ${INT_BRIDGE:-\"br-int\"}`;\ndo\n    skip_cleanup=`ovs-vsctl --if-exists get Interface $port external_ids:skip_cleanup`\n    if ! [[ \"x$skip_cleanup\" == \"x\\\"true\\\"\" ]];\n    then\n        ovs-vsctl del-port ${INT_BRIDGE:-\"br-int\"} $port\n    fi\ndone\n\novs-vsctl --if-exists del-br ${TUN_BRIDGE:-\"br-tun\"}\n\n# Clean up trunk port bridges\nfor br in $(ovs-vsctl list-br | egrep 'tbr-[0-9a-f\\-]+'); do\n    ovs-vsctl --if-exists del-br $br\ndone\n", "dest": "/usr/libexec/neutron-cleanup", "force": true, "mode": "0755"}}, {"name": "Copy in cleanup service", "copy": {"content": "[Unit]\nDescription=Neutron cleanup on startup\nAfter=openvswitch.service network.target\nBefore=tripleo_neutron_ovs_agent.service tripleo_neutron_dhcp.service tripleo_neutron_l3_agent.service tripleo_nova_compute.service\nRefuseManualStop=yes\n\n[Service]\nType=oneshot\nExecStart=/usr/libexec/neutron-cleanup\n\n[Install]\nWantedBy=multi-user.target\n", "dest": "/usr/lib/systemd/system/neutron-cleanup.service", "force": true}}, {"name": "Enabling the cleanup service", "service": {"name": "neutron-cleanup", "enabled": true}, "when": "not (ansible_check_mode|bool)"}], "external_deploy_tasks": [{"when": ["step|int == 0"], "name": "ovn_controller_external_deploy_init", "block": [{"name": "create ovn mac address for Standalone role nodes", "tripleo_ovn_mac_addresses": {"playbook_dir": "{{ playbook_dir }}", "stack_name": "standalone", "role_name": "Standalone", "server_resource_names": "{{ groups[\"Standalone\"] }}", "ovn_bridge_mappings": ["datacentre:br-ctlplane"], "ovn_static_bridge_mac_mappings": {"standalone": {"datacentre": "fa:16:3a:00:53:00"}}}}]}], "external_update_tasks": [{"name": "Force pull image in case image name doesn't change.", "when": "step|int == 1", "tags": ["ovn", "ovn_image"], "become": true, "loop": "{{ groups['ovn_controller'] | difference(groups['excluded_overcloud']) }}", "delegate_to": "{{ item }}", "async": 600, "poll": 0, "register": "ovn_controller_image_update", "containers.podman.podman_image": {"name": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "validate_certs": false, "force": true}}, {"name": "Was the ovn_controller image pull successful.", "when": ["step|int == 1", "'results' in ovn_controller_image_update"], "tags": ["ovn", "ovn_image"], "become": true, "delegate_to": "{{ async_result_item.item }}", "async_status": {"jid": "{{ async_result_item.ansible_job_id }}"}, "loop": "{{ovn_controller_image_update.results }}", "loop_control": {"loop_var": "async_result_item"}, "register": "async_poll_results", "until": "async_poll_results.finished", "retries": 600, "delay": 1}, {"name": "OVN Container image used", "debug": {"msg": "ovn container will be using {{ image }}"}, "vars": {"image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1"}, "when": "step|int == 1", "tags": "ovn"}, {"name": "Update OVN OVS related parameters before update.", "when": ["step|int == 1"], "tags": ["ovn"], "become": true, "vars": {"timeout": 8000}, "shell": "set -e\novs-vsctl set Open_vSwitch . external_ids:ovn-ofctrl-wait-before-clear={{ timeout }}\novs-vsctl set Open_vSwitch . external_ids:ovn-monitor-all=true\novs-vsctl set Open_vSwitch . external_ids:ovn-match-northd-version=false\n", "async": 600, "poll": 0, "register": "ovs_vsctl", "loop": "{{ groups['ovn_controller'] | difference(groups['excluded_overcloud']) }}", "delegate_to": "{{ item }}"}, {"name": "Was the update of OVN OVS related parameter successful.", "when": ["step|int == 1", "'results' in ovs_vsctl"], "become": true, "tags": ["ovn"], "delegate_to": "{{ async_result_item.item }}", "async_status": {"jid": "{{ async_result_item.ansible_job_id }}"}, "loop": "{{ovs_vsctl.results }}", "loop_control": {"loop_var": "async_result_item"}, "register": "async_poll_results", "until": "async_poll_results.finished", "retries": 600, "delay": 1}, {"set_fact": {"any_ovn_host": "{{groups['ovn_controller'] | difference(groups['excluded_overcloud']) | first }}"}, "tags": "ovn", "when": "step|int == 1"}, {"name": "Find ovn_controller configs in container-startup-configs", "find": {"paths": "/var/lib/tripleo-config/container-startup-config/", "patterns": "*ovn_controller.json", "recurse": true}, "register": "ovn_cont_17_0", "delegate_to": "{{ any_ovn_host }}", "when": "(step|int == 1) and (any_ovn_host is defined) and (any_ovn_host|length > 0)", "tags": ["ovn"], "become": true}, {"name": "get directory path from the ovn_cont_17_0", "set_fact": {"ovn_config_path": "{{ ovn_cont_17_0.files.0.path | dirname }}"}, "when": "step|int == 1", "tags": "ovn"}, {"name": "Get PIDfile used by systemd on each ovn node", "when": ["step|int == 1"], "tags": ["ovn"], "become": true, "shell": "set -e\ngrep PID /etc/systemd/system/tripleo_ovn_controller.service | cut -d= -f2\n", "register": "pidfile", "loop": "{{ groups['ovn_controller'] | difference(groups['excluded_overcloud']) }}", "delegate_to": "{{ item }}"}, {"name": "Update ovn_controller.", "vars": {"config_step": "{{ ('step_4' in ovn_config_path) | ternary('4', '3')}}", "query": "results[?item == '{{item}}'].stdout"}, "when": "step|int == 1", "tags": "ovn", "become": true, "loop": "{{ groups['ovn_controller'] | difference(groups['excluded_overcloud']) }}", "delegate_to": "{{ item }}", "async": 600, "poll": 0, "register": "ovn_controller_update", "tripleo_container_manage": {"config_dir": "{{ ovn_config_path }}", "config_patterns": "*ovn_controller.json", "config_id": ["tripleo_step{{config_step}}"], "log_base_path": "{{ container_log_stdout_path }}", "debug": "{{ enable_debug | bool }}", "config_overrides": {".*ovn_controller": {"image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "conmon_pidfile": "{{ pidfile | json_query(query) | first }}", "name": "ovn_controller"}}}}, {"name": "Was the ovn_controller successful.", "when": ["step|int == 1", "'results' in ovn_controller_update"], "tags": "ovn", "become": true, "delegate_to": "{{ async_result_item.item }}", "async_status": {"jid": "{{ async_result_item.ansible_job_id }}"}, "loop": "{{ovn_controller_update.results }}", "loop_control": {"loop_var": "async_result_item"}, "register": "async_poll_results", "until": "async_poll_results.finished", "retries": 600, "delay": 1}, {"name": "Pause for 30s to give ovn_controllers time to reconnect to dbs", "when": ["step|int == 1"], "tags": "ovn", "wait_for": {"timeout": 30}}], "upgrade_tasks": [{"name": "Fetch running ovn_controller image", "shell": "set -e\npodman inspect --format \"{{'{{'}}.ImageName{{'}}'}}\" ovn_controller\n", "register": "running_ovn_image", "when": ["step|int == 4"], "tags": ["ovn", "ovn_image"]}, {"name": "Run ovn_controller upgrade", "tags": ["ovn", "ovn_image"], "vars": {"ovn_controller_image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1"}, "when": ["step|int == 4", "running_ovn_image.stdout != ovn_controller_image"], "block": [{"name": "Force pull image in case image name doesn't change.", "when": "step|int == 4", "tags": ["ovn", "ovn_image"], "containers.podman.podman_image": {"name": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "validate_certs": false, "force": true}}, {"name": "Update OVN OVS related parameters before update.", "when": ["step|int == 4"], "tags": ["ovn"], "vars": {"timeout": 8000}, "shell": "set -e\novs-vsctl set Open_vSwitch . external_ids:ovn-ofctrl-wait-before-clear={{ timeout }}\novs-vsctl set Open_vSwitch . external_ids:ovn-monitor-all=true\novs-vsctl set Open_vSwitch . external_ids:ovn-match-northd-version=false\n"}, {"name": "Find ovn_controller configs in container-startup-configs", "find": {"paths": "/var/lib/tripleo-config/container-startup-config/", "patterns": "*ovn_controller.json", "recurse": true}, "register": "ovn_cont_17_0", "when": ["step|int == 4"], "tags": ["ovn"]}, {"name": "get directory path from the ovn_cont_17_0", "set_fact": {"ovn_config_path": "{{ ovn_cont_17_0.files.0.path | dirname }}"}, "when": "step|int == 4", "tags": "ovn"}, {"name": "Get PIDfile used by systemd on each ovn node", "when": ["step|int == 4"], "tags": ["ovn"], "shell": "set -e\ngrep PID /etc/systemd/system/tripleo_ovn_controller.service | cut -d= -f2\n", "register": "pidfile"}, {"name": "Update ovn_controller.", "vars": {"config_step": "{{ ('step_4' in ovn_config_path) | ternary('4', '3')}}"}, "when": "step|int == 4", "tags": "ovn", "tripleo_container_manage": {"config_dir": "{{ ovn_config_path }}", "config_patterns": "*ovn_controller.json", "config_id": ["tripleo_step{{config_step}}"], "log_base_path": "{{ container_log_stdout_path }}", "debug": "{{ enable_debug | bool }}", "config_overrides": {".*ovn_controller": {"image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-controller:17.1", "conmon_pidfile": "{{ pidfile.stdout }}", "name": "ovn_controller"}}}}, {"name": "Pause for 30s to give ovn_controllers time to reconnect to dbs", "when": ["step|int == 4"], "tags": "ovn", "wait_for": {"timeout": 30}}]}], "scale_tasks": [{"when": ["step|int == 1", "container_cli == 'podman'"], "tags": "down", "become": true, "environment": {"OS_CLOUD": "standalone"}, "block": [{"name": "Get neutron agents ID", "command": "openstack network agent list --column ID --column Host --column Binary --format yaml", "register": "neutron_agents_result", "delegate_to": "{{ groups['Undercloud'] | first }}", "check_mode": false, "changed_when": false}, {"name": "Filter only current host", "set_fact": {"neutron_agents": "{{ neutron_agents_result.stdout | from_yaml | selectattr('Host', 'match', ansible_facts['fqdn'] ~ '.*') | list }}"}, "delegate_to": "{{ groups['Undercloud'] | first }}", "check_mode": false}, {"name": "Deleting OVN agents", "block": [{"name": "Stop OVN containers", "loop": ["tripleo_ovn_controller", "tripleo_ovn_metadata_agent"], "service": {"name": "{{ item }}", "state": "stopped", "enabled": false}, "become": true, "register": "stop_containers", "failed_when": "('msg' in stop_containers and 'Could not find the requested service' not in stop_containers.msg) or ('rc' in stop_containers and stop_containers.rc != 0)"}, {"name": "Delete neutron agents", "loop": "{{ neutron_agents }}", "loop_control": {"loop_var": "agent", "label": "{{ agent.Host }}/{{ agent.Binary }}"}, "command": "openstack network agent delete {{ agent.ID }}", "delegate_to": "{{ groups['Undercloud'] | first }}", "check_mode": false}]}]}]}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-56-bfjg3iqov75s/aefc74dc-e3bc-4576-8573-ff1e4a3b4509"}


created_at: 2025-12-01 09:42:41.754378
data:
  {"type": "json", "value": {"ContainerOvnNbDbImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-nb-db-server:17.1", "ContainerOvnSbDbImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-sb-db-server:17.1", "ContainerOvnNorthdImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-northd:17.1", "ContainerNeutronApiImage": "registry.redhat.io/rhosp-rhel9/openstack-neutron-server:17.1", "ContainerOvnMetadataImage": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1"}}


created_at: 2025-12-01 09:42:42.893649
data:
  {"volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro"], "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-57-3obq3cqfl2in-ContainersCommon-j6ojck3ifq4m/f9c6d510-75ca-4643-9325-f1d61d9dc5b3"}


created_at: 2025-12-01 09:42:42.898203
data:
  {"value": {"ContainerOvnNbDbImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-nb-db-server:17.1", "ContainerOvnSbDbImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-sb-db-server:17.1", "ContainerOvnNorthdImage": "registry.redhat.io/rhosp-rhel9/openstack-ovn-northd:17.1", "ContainerNeutronApiImage": "registry.redhat.io/rhosp-rhel9/openstack-neutron-server:17.1", "ContainerOvnMetadataImage": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1"}}


created_at: 2025-12-01 09:42:42.911939
data:
  {"tuple:('role_data', 'step_config')": null, "tuple:('role_data', 'docker_config')": {"step_0": {"ovn_cluster_north_db_server": {"start_order": 0, "image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-nb-db-server:17.1", "net": "host", "privileged": false, "restart": "always", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/kolla/config_files/ovn_cluster_north_db_server.json:/var/lib/kolla/config_files/config.json:ro", "/lib/modules:/lib/modules:ro", "/var/lib/openvswitch/ovn:/var/lib/openvswitch:shared,z", "/var/lib/openvswitch/ovn:/run/openvswitch:shared,z", "/var/log/containers/openvswitch:/var/log/openvswitch:z", "/var/lib/openvswitch/ovn:/var/lib/ovn:shared,z", "/var/lib/openvswitch/ovn:/etc/openvswitch:shared,z", "/var/lib/openvswitch/ovn:/etc/ovn:shared,z", "/var/lib/openvswitch/ovn:/run/ovn:shared,z", "/var/log/containers/openvswitch:/var/log/ovn:z", "/var/lib/config-data/ansible-generated/ovn:/var/lib/kolla/config_files/src:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}, "ovn_cluster_south_db_server": {"start_order": 0, "image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-sb-db-server:17.1", "net": "host", "privileged": false, "restart": "always", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/kolla/config_files/ovn_cluster_south_db_server.json:/var/lib/kolla/config_files/config.json:ro", "/lib/modules:/lib/modules:ro", "/var/lib/openvswitch/ovn:/var/lib/openvswitch:shared,z", "/var/lib/openvswitch/ovn:/run/openvswitch:shared,z", "/var/log/containers/openvswitch:/var/log/openvswitch:z", "/var/lib/openvswitch/ovn:/var/lib/ovn:shared,z", "/var/lib/openvswitch/ovn:/etc/openvswitch:shared,z", "/var/lib/openvswitch/ovn:/etc/ovn:shared,z", "/var/lib/openvswitch/ovn:/run/ovn:shared,z", "/var/log/containers/openvswitch:/var/log/ovn:z", "/var/lib/config-data/ansible-generated/ovn:/var/lib/kolla/config_files/src:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}, "ovn_cluster_northd": {"start_order": 2, "image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-northd:17.1", "net": "host", "privileged": false, "restart": "always", "healthcheck": {"test": "/openstack/healthcheck"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/kolla/config_files/ovn_cluster_northd.json:/var/lib/kolla/config_files/config.json:ro", "/lib/modules:/lib/modules:ro", "/var/lib/openvswitch/ovn:/run/openvswitch:shared,z", "/var/log/containers/openvswitch:/var/log/openvswitch:z", "/var/lib/openvswitch/ovn:/run/ovn:shared,z", "/var/log/containers/openvswitch:/var/log/ovn:z", "/var/lib/config-data/ansible-generated/ovn:/var/lib/kolla/config_files/src:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}}}, "tuple:('role_data', 'service_names')": null, "tuple:('role_data', 'container_config_scripts')": null, "tuple:('role_data', 'service_name')": "ovn_dbs", "tuple:('role_data', 'config_settings')": null, "role_data": {"service_name": "ovn_dbs", "firewall_rules": {"121 OVN DB server and cluster ports for 172.17.0.0/24": {"proto": "tcp", "source": "172.17.0.0/24", "dport": [6641, 6642, 6643, 6644]}}, "kolla_config": {"/var/lib/kolla/config_files/ovn_cluster_north_db_server.json": {"command": "bash -c $* -- eval source /etc/sysconfig/ovn_cluster; exec /usr/local/bin/start-nb-db-server ${OVN_NB_DB_OPTS}", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-tls/*", "dest": "/", "merge": true, "preserve_properties": true, "optional": true}], "permissions": [{"path": "/var/log/openvswitch", "owner": "root:root", "recurse": true}, {"path": "/var/log/ovn", "owner": "root:root", "recurse": true}]}, "/var/lib/kolla/config_files/ovn_cluster_south_db_server.json": {"command": "bash -c $* -- eval source /etc/sysconfig/ovn_cluster; exec /usr/local/bin/start-sb-db-server ${OVN_SB_DB_OPTS}", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-tls/*", "dest": "/", "merge": true, "preserve_properties": true, "optional": true}], "permissions": [{"path": "/var/log/openvswitch", "owner": "root:root", "recurse": true}, {"path": "/var/log/ovn", "owner": "root:root", "recurse": true}]}, "/var/lib/kolla/config_files/ovn_cluster_northd.json": {"command": "bash -c $* -- eval source /etc/sysconfig/ovn_cluster; exec /usr/bin/ovn-northd ${OVN_NORTHD_OPTS}", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}, {"source": "/var/lib/kolla/config_files/src-tls/*", "dest": "/", "merge": true, "preserve_properties": true, "optional": true}], "permissions": [{"path": "/var/log/openvswitch", "owner": "root:root", "recurse": true}, {"path": "/var/log/ovn", "owner": "root:root", "recurse": true}]}}, "docker_config": {"step_0": {"ovn_cluster_north_db_server": {"start_order": 0, "image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-nb-db-server:17.1", "net": "host", "privileged": false, "restart": "always", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/kolla/config_files/ovn_cluster_north_db_server.json:/var/lib/kolla/config_files/config.json:ro", "/lib/modules:/lib/modules:ro", "/var/lib/openvswitch/ovn:/var/lib/openvswitch:shared,z", "/var/lib/openvswitch/ovn:/run/openvswitch:shared,z", "/var/log/containers/openvswitch:/var/log/openvswitch:z", "/var/lib/openvswitch/ovn:/var/lib/ovn:shared,z", "/var/lib/openvswitch/ovn:/etc/openvswitch:shared,z", "/var/lib/openvswitch/ovn:/etc/ovn:shared,z", "/var/lib/openvswitch/ovn:/run/ovn:shared,z", "/var/log/containers/openvswitch:/var/log/ovn:z", "/var/lib/config-data/ansible-generated/ovn:/var/lib/kolla/config_files/src:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}, "ovn_cluster_south_db_server": {"start_order": 0, "image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-sb-db-server:17.1", "net": "host", "privileged": false, "restart": "always", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/kolla/config_files/ovn_cluster_south_db_server.json:/var/lib/kolla/config_files/config.json:ro", "/lib/modules:/lib/modules:ro", "/var/lib/openvswitch/ovn:/var/lib/openvswitch:shared,z", "/var/lib/openvswitch/ovn:/run/openvswitch:shared,z", "/var/log/containers/openvswitch:/var/log/openvswitch:z", "/var/lib/openvswitch/ovn:/var/lib/ovn:shared,z", "/var/lib/openvswitch/ovn:/etc/openvswitch:shared,z", "/var/lib/openvswitch/ovn:/etc/ovn:shared,z", "/var/lib/openvswitch/ovn:/run/ovn:shared,z", "/var/log/containers/openvswitch:/var/log/ovn:z", "/var/lib/config-data/ansible-generated/ovn:/var/lib/kolla/config_files/src:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}, "ovn_cluster_northd": {"start_order": 2, "image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-northd:17.1", "net": "host", "privileged": false, "restart": "always", "healthcheck": {"test": "/openstack/healthcheck"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/lib/kolla/config_files/ovn_cluster_northd.json:/var/lib/kolla/config_files/config.json:ro", "/lib/modules:/lib/modules:ro", "/var/lib/openvswitch/ovn:/run/openvswitch:shared,z", "/var/log/containers/openvswitch:/var/log/openvswitch:z", "/var/lib/openvswitch/ovn:/run/ovn:shared,z", "/var/log/containers/openvswitch:/var/log/ovn:z", "/var/lib/config-data/ansible-generated/ovn:/var/lib/kolla/config_files/src:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}}}, "global_config_settings": {"ovn_db_clustered": true}, "metadata_settings": null, "host_prep_tasks": [{"name": "create persistent directories", "file": {"path": "{{ item.path }}", "state": "directory", "setype": "{{ item.setype }}", "mode": "{{ item.mode|default(omit) }}"}, "loop": [{"path": "/var/log/containers/openvswitch", "setype": "container_file_t", "mode": "0750"}, {"path": "/var/lib/openvswitch/ovn", "setype": "container_file_t"}]}], "deploy_steps_tasks": [{"name": "set is_ovn_dbs_bootstrap_node fact", "set_fact": "is_ovn_dbs_bootstrap_node={{ovn_dbs_short_bootstrap_node_name|lower == ansible_facts['hostname']|lower}}", "when": ["step|int == 1"]}, {"name": "Populate ansible service facts so we can check for pacemaker service", "ansible.builtin.service_facts": null, "when": ["is_ovn_dbs_bootstrap_node | bool", "step|int == 1"]}, {"name": "Remove OVNDBs from Pacemaker", "when": ["step|int == 1", "is_ovn_dbs_bootstrap_node | bool", "ansible_facts['services']['pacemaker.service']['state']  | default('unknown') == 'running'"], "block": [{"name": "Fetch ovn-dbs-bundle", "shell": "pcs status |grep ovn-dbs-bundle ||true\n", "register": "ovn_dbs"}, {"name": "Fetch ovn VIP", "shell": "pcs constraint config |grep \"with ovn-dbs-bundle\" |awk '{print $1}'\n", "register": "ovn_vip"}, {"name": "Remove OVNDBs from pacemaker", "pacemaker_resource": {"resource": "ovn-dbs-bundle", "state": "delete"}, "when": "ovn_dbs.stdout |length  > 0"}, {"name": "Remove OVNDBs VIP from pacemaker", "pacemaker_resource": {"resource": "{{ ovn_vip.stdout }}", "state": "delete"}, "when": "ovn_vip.stdout |length > 0"}, {"name": "Clean up pacemaker remote nodes cache", "shell": "pcs cluster node clear ovn-dbs-bundle-0\npcs cluster node clear ovn-dbs-bundle-1\npcs cluster node clear ovn-dbs-bundle-2\ncrm_attribute --name OVN_REPL_INFO --delete\n"}, {"name": "Remove pacemaker attributes", "shell": "pcs node attribute \"{{ item }}\" ovn-dbs-role= || true\n", "loop": "{{ ovn_dbs_short_node_names }}"}]}, {"name": "Prepare OVN cluster", "when": "step|int == 1", "block": [{"name": "Certificate generation", "when": "enable_internal_tls | bool", "block": [{"include_role": {"name": "linux-system-roles.certificate"}, "vars": {"certificate_requests": [{"name": "ovn_dbs", "dns": "{{fqdn_internal_api}}", "principal": "ovn_dbs/{{fqdn_internal_api}}@{{idm_realm}}", "key_size": "2048", "ca": "ipa"}]}}]}, {"block": [{"name": "Configure OVN DBs and northd", "include_role": {"name": "tripleo_ovn_cluster"}, "vars": {"tripleo_ovn_cluster_dbs_protocol": "{{ enable_internal_tls | ternary('ssl', 'tcp', 'tcp') }}", "tripleo_ovn_cluster_network": "internal_api", "tripleo_ovn_cluster_nb_db_port": 6641, "tripleo_ovn_cluster_sb_db_port": 6642, "tripleo_ovn_cluster_nb_local_port": 6643, "tripleo_ovn_cluster_nb_remote_port": 6643, "tripleo_ovn_cluster_sb_local_port": 6644, "tripleo_ovn_cluster_sb_remote_port": 6644, "tripleo_ovn_cluster_northd_ssl_ca_cert": "/etc/ipa/ca.crt", "tripleo_ovn_cluster_sb_ssl_ca_cert": "/etc/ipa/ca.crt", "tripleo_ovn_cluster_nb_ssl_ca_cert": "/etc/ipa/ca.crt"}}]}]}, {"name": "Start OVN DBs and northd containers (bootstrap node)", "when": ["step|int == 3", "is_ovn_dbs_bootstrap_node | bool"], "block": [{"block": [{"name": "Start OVN container", "include_role": {"name": "tripleo_container_manage"}, "vars": {"tripleo_container_manage_config": "/var/lib/tripleo-config/container-startup-config/step_0", "tripleo_container_manage_config_id": "{{ ovn_container }}", "tripleo_container_manage_config_patterns": "{{ ovn_container }}.json"}, "loop": ["ovn_cluster_north_db_server", "ovn_cluster_south_db_server", "ovn_cluster_northd"], "loop_control": {"loop_var": "ovn_container"}}]}, {"name": "Set NB connection", "become": true, "shell": "podman exec ovn_cluster_north_db_server bash -c \"ovn-nbctl --no-leader-only --inactivity-probe={{ tripleo_ovn_cluster_probe_interval }} set-connection p{{ tripleo_ovn_cluster_dbs_protocol }}:{{ tripleo_ovn_cluster_nb_db_port }}:{{ tripleo_ovn_cluster_dbs_addr }}\"\n", "register": "nb_result", "retries": 20, "delay": 5, "until": "nb_result.rc == 0", "when": ["is_ovn_dbs_bootstrap_node | bool"], "vars": {"tripleo_ovn_cluster_network": "internal_api", "tripleo_ovn_cluster_nb_db_port": 6641, "tripleo_ovn_cluster_dbs_protocol": "{{ enable_internal_tls | ternary('ssl', 'tcp', 'tcp') }}", "tripleo_ovn_cluster_dbs_addr": "0.0.0.0", "tripleo_ovn_cluster_probe_interval": 60000}}, {"name": "Set SB connection", "become": true, "shell": "podman exec ovn_cluster_south_db_server bash -c \"ovn-sbctl --no-leader-only --inactivity-probe={{ tripleo_ovn_cluster_probe_interval }} set-connection p{{ tripleo_ovn_cluster_dbs_protocol }}:{{ tripleo_ovn_cluster_sb_db_port }}:{{ tripleo_ovn_cluster_dbs_addr }}\"\n", "register": "sb_result", "retries": 20, "delay": 5, "until": "sb_result.rc == 0", "when": ["is_ovn_dbs_bootstrap_node | bool"], "vars": {"tripleo_ovn_cluster_network": "internal_api", "tripleo_ovn_cluster_sb_db_port": 6642, "tripleo_ovn_cluster_dbs_protocol": "{{ enable_internal_tls | ternary('ssl', 'tcp', 'tcp') }}", "tripleo_ovn_cluster_dbs_addr": "0.0.0.0", "tripleo_ovn_cluster_probe_interval": 60000}}]}, {"name": "Start OVN DBs and northd containers (non-bootstrap nodes)", "when": ["step|int == 4", "not is_ovn_dbs_bootstrap_node | bool"], "block": [{"block": [{"name": "Start OVN container", "include_role": {"name": "tripleo_container_manage"}, "vars": {"tripleo_container_manage_config": "/var/lib/tripleo-config/container-startup-config/step_0", "tripleo_container_manage_config_id": "{{ ovn_container }}", "tripleo_container_manage_config_patterns": "{{ ovn_container }}.json"}, "loop": ["ovn_cluster_north_db_server", "ovn_cluster_south_db_server", "ovn_cluster_northd"], "loop_control": {"loop_var": "ovn_container"}}]}, {"name": "Set NB connection", "become": true, "shell": "podman exec ovn_cluster_north_db_server bash -c \"ovn-nbctl --no-leader-only --inactivity-probe={{ tripleo_ovn_cluster_probe_interval }} set-connection p{{ tripleo_ovn_cluster_dbs_protocol }}:{{ tripleo_ovn_cluster_nb_db_port }}:{{ tripleo_ovn_cluster_dbs_addr }}\"\n", "register": "nb_result", "retries": 20, "delay": 5, "until": "nb_result.rc == 0", "when": ["is_ovn_dbs_bootstrap_node | bool"], "vars": {"tripleo_ovn_cluster_network": "internal_api", "tripleo_ovn_cluster_nb_db_port": 6641, "tripleo_ovn_cluster_dbs_protocol": "{{ enable_internal_tls | ternary('ssl', 'tcp', 'tcp') }}", "tripleo_ovn_cluster_dbs_addr": "0.0.0.0", "tripleo_ovn_cluster_probe_interval": 60000}}, {"name": "Set SB connection", "become": true, "shell": "podman exec ovn_cluster_south_db_server bash -c \"ovn-sbctl --no-leader-only --inactivity-probe={{ tripleo_ovn_cluster_probe_interval }} set-connection p{{ tripleo_ovn_cluster_dbs_protocol }}:{{ tripleo_ovn_cluster_sb_db_port }}:{{ tripleo_ovn_cluster_dbs_addr }}\"\n", "register": "sb_result", "retries": 20, "delay": 5, "until": "sb_result.rc == 0", "when": ["is_ovn_dbs_bootstrap_node | bool"], "vars": {"tripleo_ovn_cluster_network": "internal_api", "tripleo_ovn_cluster_sb_db_port": 6642, "tripleo_ovn_cluster_dbs_protocol": "{{ enable_internal_tls | ternary('ssl', 'tcp', 'tcp') }}", "tripleo_ovn_cluster_dbs_addr": "0.0.0.0", "tripleo_ovn_cluster_probe_interval": 60000}}]}], "external_update_tasks": [{"name": "Run ovndbs update", "tags": ["ovn", "ovn_image"], "when": "step|int == 2", "block": [{"name": "Get OVN_Northbound cluster leader", "become": true, "shell": "podman exec -u root ovn_cluster_north_db_server ovs-appctl -t /var/run/ovn/ovnnb_db.ctl cluster/status OVN_Northbound | grep 'Leader: '\n", "register": "ovn_nb_dbs_cluster_leader", "loop": "{{groups['ovn_dbs'] | difference(groups['excluded_overcloud']) }}", "delegate_to": "{{ item }}"}, {"set_fact": {"ovn_nb_leader": "{{ ovn_nb_dbs_cluster_leader| json_query(\"results[?contains(stdout,'Leader: self')].item\") }}"}}, {"name": "Graceful stop OVN NB leader container", "delegate_to": "{{ ovn_nb_leader[0] }}", "become": true, "shell": "podman exec -u root ovn_cluster_north_db_server ovs-appctl -t /var/run/ovn/ovnnb_db.ctl exit\n"}, {"name": "Start OVN NB leader container", "delegate_to": "{{ ovn_nb_leader[0] }}", "become": true, "tripleo_container_manage": {"config_dir": "/var/lib/tripleo-config/container-startup-config/step_0", "config_id": ["ovn_cluster_north_db_server"], "config_patterns": "*ovn_cluster_north_db_server.json", "config_overrides": {".*ovn_cluster_north_db_server": {"image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-nb-db-server:17.1", "name": "ovn_cluster_north_db_server"}}}}, {"name": "Get OVN_Southbound cluster leader", "become": true, "shell": "sudo podman exec -u root ovn_cluster_south_db_server ovs-appctl -t /var/run/ovn/ovnsb_db.ctl cluster/status OVN_Southbound | grep 'Leader: '\n", "register": "ovn_sb_dbs_cluster_leader", "loop": "{{groups['ovn_dbs'] | difference(groups['excluded_overcloud']) }}", "delegate_to": "{{ item }}"}, {"set_fact": {"ovn_sb_leader": "{{ ovn_sb_dbs_cluster_leader | json_query(\"results[?contains(stdout,'Leader: self')].item\") }}"}}, {"name": "Graceful stop OVN SB leader container", "delegate_to": "{{ ovn_sb_leader[0] }}", "become": true, "shell": "sudo podman exec -u root ovn_cluster_south_db_server ovs-appctl -t /var/run/ovn/ovnsb_db.ctl exit\n"}, {"name": "Start OVN SB leader container", "delegate_to": "{{ ovn_sb_leader[0] }}", "become": true, "tripleo_container_manage": {"config_dir": "/var/lib/tripleo-config/container-startup-config/step_0", "config_id": ["ovn_cluster_south_db_server"], "config_patterns": "*ovn_cluster_south_db_server.json", "config_overrides": {".*ovn_cluster_south_db_server": {"image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-sb-db-server:17.1", "name": "ovn_cluster_south_db_server"}}}}, {"name": "Loop on OVN_Northbound cluster for leader election", "become": true, "shell": "podman exec -u root ovn_cluster_north_db_server ovs-appctl -t /var/run/ovn/ovnnb_db.ctl cluster/status OVN_Northbound | grep 'Leader: '\n", "register": "wait_leader", "delegate_to": "{{ groups['ovn_dbs'] | difference(groups['excluded_overcloud']) |  difference(ovn_nb_leader[0]) | first }}", "failed_when": "'Leader: unknown' in wait_leader.stdout or wait_leader.stderr != ''", "until": "'Leader: unknown' not in wait_leader.stdout and wait_leader.stderr == ''", "retries": 10, "delay": 5}, {"name": "Loop on OVN_Southbound cluster for leader election", "become": true, "shell": "podman exec -u root ovn_cluster_south_db_server ovs-appctl -t /var/run/ovn/ovnsb_db.ctl cluster/status OVN_Southbound | grep 'Leader: '\n", "register": "wait_leader", "delegate_to": "{{ groups['ovn_dbs'] | difference(groups['excluded_overcloud']) |  difference(ovn_nb_leader[0]) | first }}", "failed_when": "'Leader: unknown' in wait_leader.stdout or wait_leader.stderr != ''", "until": "'Leader: unknown' not in wait_leader.stdout and wait_leader.stderr == ''", "retries": 10, "delay": 5}, {"name": "Pause for 30 seconds to ensure ovn db leader knows it was elected and clients reconnect", "wait_for": {"timeout": 30}}, {"name": "Get OVN_Northbound cluster new leader", "become": true, "shell": "podman exec -u root ovn_cluster_north_db_server ovs-appctl -t /var/run/ovn/ovnnb_db.ctl cluster/status OVN_Northbound | grep 'Leader: '\n", "register": "ovn_nb_dbs_cluster_leader_new", "loop": "{{groups['ovn_dbs'] | difference(groups['excluded_overcloud']) }}", "until": "'Leader: unknown' not in ovn_nb_dbs_cluster_leader_new.stdout", "retries": 10, "delay": 5, "delegate_to": "{{ item }}"}, {"set_fact": {"ovn_nb_leader_new": "{{ ovn_nb_dbs_cluster_leader_new| json_query(\"results[?contains(stdout,'Leader: self')].item\") }}"}}, {"name": "Get OVN_Southbound cluster new leader", "become": true, "shell": "sudo podman exec -u root ovn_cluster_south_db_server ovs-appctl -t /var/run/ovn/ovnsb_db.ctl cluster/status OVN_Southbound | grep 'Leader: '\n", "register": "ovn_sb_dbs_cluster_leader_new", "loop": "{{groups['ovn_dbs'] | difference(groups['excluded_overcloud']) }}", "until": "'Leader: unknown' not in ovn_sb_dbs_cluster_leader_new.stdout", "retries": 10, "delay": 5, "delegate_to": "{{ item }}"}, {"set_fact": {"ovn_sb_leader_new": "{{ ovn_sb_dbs_cluster_leader_new | json_query(\"results[?contains(stdout,'Leader: self')].item\") }}"}}, {"name": "Start OVN NB containers (non-leader nodes)", "delegate_to": "{{ item }}", "become": true, "tripleo_container_manage": {"config_dir": "/var/lib/tripleo-config/container-startup-config/step_0", "config_id": ["ovn_cluster_north_db_server"], "config_patterns": "*ovn_cluster_north_db_server.json", "config_overrides": {".*ovn_cluster_north_db_server": {"image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-nb-db-server:17.1", "name": "ovn_cluster_north_db_server"}}}, "loop": "{{groups['ovn_dbs'] | difference(groups['excluded_overcloud']) | difference(ovn_nb_leader[0])| difference(ovn_nb_leader_new[0])}}", "loop_control": {"pause": 15}}, {"name": "Start OVN SB containers (non-leader nodes)", "delegate_to": "{{ item }}", "become": true, "tripleo_container_manage": {"config_dir": "/var/lib/tripleo-config/container-startup-config/step_0", "config_id": ["ovn_cluster_south_db_server"], "config_patterns": "*ovn_cluster_south_db_server.json", "config_overrides": {".*ovn_cluster_south_db_server": {"image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-sb-db-server:17.1", "name": "ovn_cluster_south_db_server"}}}, "loop": "{{groups['ovn_dbs'] | difference(groups['excluded_overcloud']) | difference(ovn_sb_leader[0])| difference(ovn_sb_leader_new[0])}}", "loop_control": {"pause": 15}}, {"name": "Pause for 50 seconds before restarting new leaders of OVN", "wait_for": {"timeout": 50}}, {"name": "Graceful stop OVN NB new-leader container", "delegate_to": "{{ ovn_nb_leader_new[0] }}", "become": true, "shell": "podman exec -u root ovn_cluster_north_db_server ovs-appctl -t /var/run/ovn/ovnnb_db.ctl exit\n", "when": "ovn_nb_leader_new[0] != ovn_nb_leader[0]"}, {"name": "Start OVN NB containers (new-leader nodes)", "delegate_to": "{{ ovn_nb_leader_new[0] }}", "become": true, "tripleo_container_manage": {"config_dir": "/var/lib/tripleo-config/container-startup-config/step_0", "config_id": ["ovn_cluster_north_db_server"], "config_patterns": "*ovn_cluster_north_db_server.json", "config_overrides": {".*ovn_cluster_north_db_server": {"image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-nb-db-server:17.1", "name": "ovn_cluster_north_db_server"}}}, "when": "ovn_nb_leader_new[0] != ovn_nb_leader[0]"}, {"name": "Graceful stop OVN SB new-leader container", "delegate_to": "{{ ovn_sb_leader_new[0] }}", "become": true, "shell": "sudo podman exec -u root ovn_cluster_south_db_server ovs-appctl -t /var/run/ovn/ovnsb_db.ctl exit\n", "when": "ovn_sb_leader_new[0] != ovn_sb_leader[0]"}, {"name": "Start OVN SB containers (new-leader nodes)", "delegate_to": "{{ ovn_sb_leader_new[0] }}", "become": true, "tripleo_container_manage": {"config_dir": "/var/lib/tripleo-config/container-startup-config/step_0", "config_id": ["ovn_cluster_south_db_server"], "config_patterns": "*ovn_cluster_south_db_server.json", "config_overrides": {".*ovn_cluster_south_db_server": {"image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-sb-db-server:17.1", "name": "ovn_cluster_south_db_server"}}}, "when": "ovn_sb_leader_new[0] != ovn_sb_leader[0]"}, {"name": "Start OVN northd container", "delegate_to": "{{ item }}", "become": true, "tripleo_container_manage": {"config_dir": "/var/lib/tripleo-config/container-startup-config/step_0", "config_id": ["ovn_cluster_northd"], "config_patterns": "*ovn_cluster_northd.json", "config_overrides": {".*ovn_cluster_northd": {"image": "registry.redhat.io/rhosp-rhel9/openstack-ovn-northd:17.1", "name": "ovn_cluster_northd"}}}, "loop": "{{groups['ovn_dbs'] | difference(groups['excluded_overcloud'])}}", "loop_control": {"pause": 15}}]}], "update_tasks": [{"name": "Configure OVN cluster during update", "when": "step|int == 4", "block": [{"name": "Configure OVN DBs and northd", "include_role": {"name": "tripleo_ovn_cluster"}, "vars": {"tripleo_ovn_cluster_dbs_protocol": "{{ enable_internal_tls | ternary('ssl', 'tcp', 'tcp') }}", "tripleo_ovn_cluster_network": "internal_api", "tripleo_ovn_cluster_nb_db_port": 6641, "tripleo_ovn_cluster_sb_db_port": 6642, "tripleo_ovn_cluster_nb_local_port": 6643, "tripleo_ovn_cluster_nb_remote_port": 6643, "tripleo_ovn_cluster_sb_local_port": 6644, "tripleo_ovn_cluster_sb_remote_port": 6644, "tripleo_ovn_cluster_northd_ssl_ca_cert": "/etc/ipa/ca.crt", "tripleo_ovn_cluster_sb_ssl_ca_cert": "/etc/ipa/ca.crt", "tripleo_ovn_cluster_nb_ssl_ca_cert": "/etc/ipa/ca.crt"}}]}, {"name": "Update OVN cluster containers", "when": "step|int == 4", "block": [{"name": "Start OVN container", "include_role": {"name": "tripleo_container_manage"}, "vars": {"tripleo_container_manage_config": "/var/lib/tripleo-config/container-startup-config/step_0", "tripleo_container_manage_config_id": "{{ ovn_container }}", "tripleo_container_manage_config_patterns": "{{ ovn_container }}.json"}, "loop": ["ovn_cluster_north_db_server", "ovn_cluster_south_db_server", "ovn_cluster_northd"], "loop_control": {"loop_var": "ovn_container"}}]}]}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-57-3obq3cqfl2in/99aca588-e532-472e-ad55-8b18c4cc5091"}


created_at: 2025-12-01 09:42:45.286932
data:
  {"type": "json", "value": {"ContainerOvnMetadataImage": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "ContainerNeutronConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-neutron-server:17.1"}}


created_at: 2025-12-01 09:42:48.405284
data:
  {"container_puppet_apply_volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/var/lib/container-config-scripts/container_puppet_apply.sh:/container_puppet_apply.sh:ro", "/etc/puppet:/tmp/puppet-etc:ro", "/usr/share/openstack-puppet/modules:/usr/share/openstack-puppet/modules:ro"], "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro"], "container_config_scripts": {"container_puppet_apply.sh": {"mode": "0700", "content": "#!/bin/bash\nset -eux\nSTEP=$1\nTAGS=$2\nCONFIG=$3\nEXTRA_ARGS=${4:-''}\nif [ -d /tmp/puppet-etc ]; then\n  # ignore copy failures as these may be the same file depending on docker mounts\n  cp -a /tmp/puppet-etc/* /etc/puppet || true\nfi\necho \"{\\\"step\\\": ${STEP}}\" > /etc/puppet/hieradata/docker_puppet.json\n# $::deployment_type in puppet-tripleo\nexport FACTER_deployment_type=containers\nset +e\npuppet apply $EXTRA_ARGS \\\n    --verbose \\\n    --detailed-exitcodes \\\n    --summarize \\\n    --color=false \\\n    --modulepath /etc/puppet/modules:/opt/stack/puppet-modules:/usr/share/openstack-puppet/modules \\\n    --tags $TAGS \\\n    -e \"noop_resource('package'); ${CONFIG}\"\nrc=$?\nset -e\nset +ux\nif [ $rc -eq 2 -o $rc -eq 0 ]; then\n    exit 0\nfi\nexit $rc\n"}, "pyshim.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n# Copyright 2018 Red Hat Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n#\n# Usage: pyshim.sh <script and/or arguments>\n#\n# Unfortunately THT doesn't know which version of python might be in a\n# container so we need this script to be able to try python3 or python2\n# depending on availability.  Since this is a temporary shim until we've\n# fully cut over to python3, we check for the existence of python3 first\n# before falling back to python2. This will help in the transition from\n# python2 based containers to python3.\n\nshow_usage() {\n    echo \"Usage: pyshim.sh <script and/or arguments>\"\n}\n\nif [ $# -lt 1 ]\nthen\n    show_usage\n    exit 1\nfi\n\nset -x\nif command -v python3 >/dev/null; then\n    python3 \"$@\"\nelif command -v python2 >/dev/null; then\n    python2 \"$@\"\nelif command -v python >/dev/null; then\n    python \"$@\"\nelse\n    echo \"ERROR: python is not available!\"\n    exit 1\nfi\n"}, "pacemaker_restart_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nset -u\n\n# ./pacemaker_restart_bundle.sh mysql galera galera-bundle Master _\n# ./pacemaker_restart_bundle.sh redis redis redis-bundle Slave Master\n# ./pacemaker_restart_bundle.sh ovn_dbs ovndb_servers ovn-dbs-bundle Slave Master\nRESTART_SCRIPTS_DIR=$(dirname $0)\nTRIPLEO_SERVICE=$1\nRESOURCE_NAME=$2\nBUNDLE_NAME=$3\nWAIT_TARGET_LOCAL=$4\nWAIT_TARGET_ANYWHERE=${5:-_}\nTRIPLEO_MINOR_UPDATE=\"${TRIPLEO_MINOR_UPDATE:-false}\"\nTRIPLEO_HA_WRAPPER_RESOURCE_EXISTS=\"${TRIPLEO_HA_WRAPPER_RESOURCE_EXISTS:-false}\"\n\nbundle_can_be_restarted() {\n    local bundle=$1\n    # As long as the resource bundle is managed by pacemaker and is\n    # not meant to stay stopped, no matter the state of any inner\n    # pcmk_remote or ocf resource, we should restart it to give it a\n    # chance to read the new config.\n    [ \"$(crm_resource --meta -r $1 -g is-managed 2>/dev/null)\" != \"false\" ] && \\\n    [ \"$(crm_resource --meta -r $1 -g target-role 2>/dev/null)\" != \"Stopped\" ]\n}\n\nlog() {\n    local msg=$1\n    logger -t pcmkrestart \"$1\"\n}\n\nHOSTNAME=$(/bin/hostname -s)\nif [ x\"${TRIPLEO_MINOR_UPDATE,,}\" != x\"true\" ]; then\n    if [ x\"${TRIPLEO_HA_WRAPPER_RESOURCE_EXISTS,,}\" = x\"false\" ]; then\n        # Do not restart during initial deployment, as the resource\n        # has just been created.\n        SERVICE_NODEID=$(/bin/hiera -c /etc/puppet/hiera.yaml \"${TRIPLEO_SERVICE}_short_bootstrap_node_name\")\n        if [[ \"${HOSTNAME,,}\" == \"${SERVICE_NODEID,,}\" ]]; then\n            log \"Initial deployment, skipping the restart of ${BUNDLE_NAME}\"\n\tfi\n        exit 0\n    else\n        # During a stack update, this script is called in parallel on\n        # every node the resource runs on, after the service's configs\n        # have been updated on all nodes. So we need to run pcs only\n        # once (e.g. on the service's boostrap node).\n        if bundle_can_be_restarted ${BUNDLE_NAME}; then\n            SERVICE_NODEID=$(/bin/hiera -c /etc/puppet/hiera.yaml \"${TRIPLEO_SERVICE}_short_bootstrap_node_name\")\n            if [[ \"${HOSTNAME,,}\" == \"${SERVICE_NODEID,,}\" ]]; then\n                replicas_running=$(crm_resource -Q -r $BUNDLE_NAME --locate 2>&1 | wc -l)\n                if [ \"$replicas_running\" != \"0\" ]; then\n                    log \"Restarting ${BUNDLE_NAME} globally. Stopping:\"\n                    /sbin/pcs resource disable --wait=600 $BUNDLE_NAME\n                    log \"Restarting ${BUNDLE_NAME} globally. Starting:\"\n                    /sbin/pcs resource enable --wait=600 $BUNDLE_NAME\n                else\n                    log \"${BUNDLE_NAME} is not running anywhere,\" \\\n                         \"cleaning up to restart it globally if necessary\"\n                    /sbin/pcs resource cleanup $BUNDLE_NAME\n                fi\n            else\n                log \"Skipping global restart of ${BUNDLE_NAME} on ${HOSTNAME} it will be restarted by node ${SERVICE_NODEID}\"\n            fi\n\n        else\n            log \"No global restart needed for ${BUNDLE_NAME}.\"\n        fi\n    fi\nelse\n    # During a minor update workflow however, a host gets fully\n    # updated before updating the next one. So unlike stack\n    # update, at the time this script is called, the service's\n    # configs aren't updated on all nodes yet. So only restart the\n    # resource locally, where it's guaranteed that the config is\n    # up to date.\n    HOST=$(facter hostname)\n\n    if bundle_can_be_restarted ${BUNDLE_NAME}; then\n\t# if the resource is running locally, restart it\n\tif crm_resource -r $BUNDLE_NAME --locate 2>&1 | grep -w -q \"${HOST}\"; then\n            log \"Restarting ${BUNDLE_NAME} locally on '${HOST}'\"\n            /sbin/pcs resource restart $BUNDLE_NAME \"${HOST}\"\n\n\telse\n\t    # At this point, if no resource is running locally, it's\n\t    # either because a) it has failed previously, or b) because\n\t    # it's an A/P resource running elsewhere.\n\t    # By cleaning up resource, we ensure that a) it will try to\n\t    # restart, or b) it won't do anything if the resource is\n\t    # already running elsewhere.\n            log \"${BUNDLE_NAME} is currently not running on '${HOST}',\" \\\n                 \"cleaning up its state to restart it if necessary\"\n            /sbin/pcs resource cleanup $BUNDLE_NAME node=\"${HOST}\"\n\tfi\n\n\t# Wait until the resource is in the expected target state\n\t$RESTART_SCRIPTS_DIR/pacemaker_wait_bundle.sh \\\n            $RESOURCE_NAME $BUNDLE_NAME \\\n            \"$WAIT_TARGET_LOCAL\" \"$WAIT_TARGET_ANYWHERE\" \\\n\t    \"${HOST}\" 600\n    else\n        log \"No restart needed for ${BUNDLE_NAME}.\"\n    fi\nfi\n"}, "pacemaker_wait_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# ----\n# Wait for an OCF resource or a bundle to be restarted\n# ----\n# e.g.:\n# M/S OCF:      $0 galera galera-bundle Master\n# clone OCF:    $0 rabbitmq rabbitmq-bundle Started\n# A/P M/S OCF:  $0 redis redis-bundle Slave Master\n# A/P bundle:   $0 openstack-cinder-volume openstack-cinder-volume _ Started\n# clone bundle: $0 haproxy-bundle haproxy-bundle Started\n\n# design note 1:\n#  - this script is called during a minor update; it is called\n#    once per node that hosts a service replica.\n#  - the purpose of this script is to ensure that restarting the\n#    service replica locally won't disrupt the service availability\n#    for the end user. To reach that goal, the script waits until the\n#    service is restarted locally or globallu and reaches a given\n#    target state (i.e. Started, Slave or Master).\n# design note 2:\n#   - we don't want to track restart error: our only job is to ensure\n#     service restart synchronization, not service health.\n#   - In particular, we don't want to error out in case the resource\n#     cannot be restarted locally, because that would make the minor\n#     update fail, even if potentially other replicas still provide\n#     the service.\n# design note 3:\n#   - we can bail out early if we determine that the resource can't\n#     be restarted automatically by pacemaker (e.g. its \"blocked\",\n#     unmanaged or disabled).\n\nlog() {\n    local msg=$1\n    echo \"$(date -u): $1\"\n}\n\nusage() {\n    echo 2>&1 \"Usage: $0 NAME BUNDLE_NAME ROLE_LOCAL [ROLE_ANYWHERE] [HOST] [TIMEOUT]\"\n    exit 1\n}\n\npacemaker_supports_promoted() {\n    # The Promoted token is only matched in recent pacemaker versions\n    grep -wq \"<value>Promoted</value>\" /usr/share/pacemaker/resources-*.rng\n}\n\n#\n# Utility functions to detect stuck resources\n#\n\nbundle_failures_locally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    local replica_name\n    for i in $(seq 0 $last); do\n\treplica_name=${BUNDLE_NAME}-${engine}-${i}\n\tcrm_failcount -q -G -r $replica_name -N $HOST\n    done\n}\n\nbundle_failures_globally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    for i in $(seq 0 $last); do\n\tcrm_failcount -q -G -r ${BUNDLE_NAME}-${engine}-${i}\n    done\n}\n\nbundle_running_globally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    # return the number of running bundles replica, i.e. the number of\n    # docker/podman resource replicas currently running in the cluster\n    crm_mon --as-xml | xmllint --xpath \"count(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource[@resource_agent='${OCF}:heartbeat:${engine}']/node)\" -\n}\n\nocf_failures_globally() {\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    local bundle_node\n    for i in $(seq 0 $last); do\n\tbundle_node=${BUNDLE_NAME}-${i}\n\tcrm_failcount -q -G -r $NAME -N $bundle_node\n    done\n}\n\ndid_resource_failed_locally() {\n    local failures\n    local running\n    local remotehost\n    if [ \"${NAME}\" != \"${BUNDLE_NAME}\" ]; then\n\t# if we're dealing with an ocf resource, it is running on a\n\t# pacemaker_remote rather that on the real host, and the\n\t# failcounts are thus associated to the pcmk remote. Replace\n\t# the host's name with the pcmk remote's name.\n        remotehost=$(crm_mon --as-xml | xmllint --xpath \"string(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource/node[@name='${HOST}']/../../resource[@resource_agent='${OCF}:pacemaker:remote']/@id)\" -)\n\tif [ -n \"${remotehost}\" ]; then\n\t    crm_failcount -q -G -r $NAME -N $remotehost | grep -q -w INFINITY\n\t    return $?\n\tfi\n\t# If no pcmk remote is currently running, the failcount from\n\t# the ocf resource is useless, compute the failcount from the\n\t# bundle case instead (computed below).\n    fi\n\n    # for bundles, pacemaker can run any bundle replica locally\n    # (e.g. galera-bundle-docker-{0,1,2}), and a failure happens when\n    # there are no more replica to try.\n    # That is, when _at least_ one replica failed locally, and all the\n    # others either failed or are currently running elsewhere.\n    failures=$(bundle_failures_locally $HOST | grep -c -w INFINITY)\n    running=$(bundle_running_globally)\n    test $failures -gt 0 && \\\n    test $(( $failures + $running )) -ge $BUNDLE_REPLICAS\n}\n\ndid_resource_failed_globally() {\n    local remotecount\n    local failures\n    if [ \"${NAME}\" != \"${BUNDLE_NAME}\" ]; then\n\t# we check the state of an ocf resource only if the\n\t# pcmkremotes are started\n        remotecount=$(crm_mon --as-xml | xmllint --xpath \"count(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource[@resource_agent='${OCF}:pacemaker:remote']/node)\" -)\n\tif [ \"${remotecount}\" = \"0\" ]; then\n\t    # no pcmkremote is running, so check the bundle state\n\t    # instead of checking the ocf resource\n\t    # bundle failed if all ${BUNDLE_REPLICAS} replicas failed\n\t    failures=$(bundle_failures_globally | grep -c -w INFINITY)\n\t    test $failures -eq $BUNDLE_REPLICAS\n\telse\n\t    # ocf resource failed if it failed to start on\n\t    # all $BUNDLE_REPLICAS bundle nodes\n\t    failures=$(ocf_failures_globally | grep -c -w INFINITY)\n\t    test $failures -eq $BUNDLE_REPLICAS\n\tfi\n    else\n\t# bundle failed if all ${BUNDLE_REPLICAS} replicas failed\n\tfailures=$(bundle_failures_globally | grep -c -w INFINITY)\n\ttest $failures -eq $BUNDLE_REPLICAS\n    fi\n}\n\n\n# Input validation\n#\n\nNAME=$1\nif [ -z \"${NAME}\" ]; then\n    echo 2>&1 \"Error: argument NAME must not be empty\"\n    exit 1\nfi\n\nBUNDLE_NAME=$2\nif [ -z \"${BUNDLE_NAME}\" ]; then\n    echo 2>&1 \"Error: argument BUNDLE_NAME must not be empty\"\n    exit 1\nfi\n\nROLE_LOCAL=$3\nif [ \"${ROLE_LOCAL}\" = \"_\" ]; then\n    ROLE_LOCAL=\"\"\nfi\n\nROLE_ANYWHERE=$4\nif [ \"${ROLE_ANYWHERE}\" = \"_\" ]; then\n    ROLE_ANYWHERE=\"\"\nfi\n\nif [ -z \"${ROLE_LOCAL}\" ]; then\n    if [ -z \"${ROLE_ANYWHERE}\" ]; then\n        echo 2>&1 \"Error: either ROLE_LOCAL or ROLE_ANYWHERE must be non empty\"\n        exit 1\n    fi\nelse\n    if !(echo \"${ROLE_LOCAL}\" | grep -q -x -E \"(Started|Slave|Master|Unpromoted|Promoted)\"); then\n        echo 2>&1 \"Error: argument ROLE_LOCAL must be either 'Started' 'Slave' 'Master' 'Unpromoted' or 'Promoted'\"\n        exit 1\n    fi\nfi\n\nif [ -n \"${ROLE_ANYWHERE}\" ] && !(echo \"${ROLE_ANYWHERE}\" | grep -q -x -E \"(Started|Slave|Master|Unpromoted|Promoted)\"); then\n    echo 2>&1 \"Error: argument ROLE_ANYWHERE must be either 'Started' 'Slave' 'Master' 'Unpromoted' or 'Promoted'\"\n    exit 1\nfi\n\n# Ensure compatibility with pacemaker 2.1\nif pacemaker_supports_promoted; then\n    ROLE_LOCAL=$(echo \"$ROLE_LOCAL\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    ROLE_ANYWHERE=$(echo \"$ROLE_ANYWHERE\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    OCF=\"ocf\"\nelse\n    OCF=\"ocf:\"\nfi\n\nHOST=${5:-$(facter hostname)}\nTIMEOUT=${6:-600}\n\n\n# Configure the search\n# ----\n# Note: we can't use crm_resource in all searches because we can't\n# easily extract the host the OCF resources run on (crm_resource\n# returns the pcmk-remote nodes rather than the hosts)\n# So instead, we implement various searches with XPath directly.\n\nif [ \"${BUNDLE_NAME}\" != \"${NAME}\" ]; then\n# ocf resource\nlocal_resource_xpath=\"//bundle/replica/resource[@resource_agent='${OCF}:pacemaker:remote']/node[@name='${HOST}']/../../resource[@id='${NAME}']\"\nany_resource_xpath=\"//bundle//resource[@id='${NAME}']\"\nreplicas_xpath=\"//bundle/primitive[@id='${BUNDLE_NAME}']/../*[boolean(@image) and boolean(@replicas)]\"\nelse\n# bundle resource\nlocal_resource_xpath=\"//bundle[@id='${NAME}']/replica/resource/node[@name='${HOST}']/../../resource\"\nany_resource_xpath=\"//bundle[@id='${NAME}']//resource\"\nreplicas_xpath=\"//bundle[@id='${BUNDLE_NAME}']/*[boolean(@image) and boolean(@replicas)]\"\nfi\n\nbundle_def_xpath=\"//bundle[@id='${BUNDLE_NAME}']/*[boolean(@image) and boolean(@replicas)]\"\nBUNDLE_CONTAINER_ENGINE=$(cibadmin -Q | xmllint --xpath \"name(${bundle_def_xpath})\" -)\nBUNDLE_REPLICAS=$(cibadmin -Q | xmllint --xpath \"string(${bundle_def_xpath}/@replicas)\" -)\n\n\n# The wait algorithm follows a two-stage approach\n#  1. Depending on how the script is called, we first check whether\n#     the resource is restarted locally. An A/P resource may be\n#     restarted elsewhere in the cluster.\n#  2. If needed, check whether the A/P resource has restarted\n#     elsewhere. For A/P M/S resources, in case the resource is\n#     restarted as Slave locally, ensure a Master is available.\n\nsuccess=1\nbailout=1\ntimeout=$TIMEOUT\nrole=\"\"\n\n# Stage 1: local check\nif [ -n \"$ROLE_LOCAL\" ]; then\n    log \"Waiting until ${NAME} has restarted on ${HOST} and is in state ${ROLE_LOCAL}\"\n    log \"Will probe resource state with the following XPath pattern: ${local_resource_xpath}\"\n\n    while [ $timeout -gt 0 ] && [ $bailout -ne 0 ] && [ $success -ne 0 ]; do\n        resource=$(crm_mon -r --as-xml | xmllint --xpath \"${local_resource_xpath}\" - 2>/dev/null)\n        role=$(echo \"${resource}\" | sed -ne 's/.*\\Wrole=\"\\([^\"]*\\)\".*/\\1/p')\n\n\tif [ \"$(crm_resource --meta -r ${NAME} -g is-managed 2>/dev/null)\" = \"false\" ]; then\n            log \"${NAME} is unmanaged, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif [ \"$(crm_resource --meta -r ${NAME} -g target-role 2>/dev/null)\" = \"Stopped\" ]; then\n            log \"${NAME} is disabled, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif echo \"${resource}\" | grep -q -w \"\\Wblocked=\\\"true\\\"\"; then\n            log \"${NAME} is blocked, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif did_resource_failed_locally; then\n            log \"${NAME} is in failed state, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif [ \"$role\" = \"$ROLE_LOCAL\" ]; then\n            success=0\n            continue\n        elif [ -n \"$ROLE_ANYWHERE\" ] && [ \"$role\" = \"$ROLE_ANYWHERE\" ]; then\n            # A/P: we are restarted in the expected state\n            success=0\n            continue\n        else\n            log \"Waiting for ${NAME} to transition to role ${ROLE_LOCAL} on ${HOST}\"\n        fi\n\n        if [ $bailout -ne 0 ] && [ $success -ne 0 ]; then\n            sleep 4\n            timeout=$((timeout-4))\n        fi\n    done\nfi\n\n# Stage 2: global check\nif [ $timeout -gt 0 ] && [ -n \"$ROLE_ANYWHERE\" ] && [ \"$role\" != \"$ROLE_ANYWHERE\" ]; then\n    log \"Wait until ${NAME} is restarted anywhere in the cluster in state ${ROLE_ANYWHERE}\"\n    log \"Will probe resource state with the following XPath pattern: ${any_resource_xpath}\"\n\n    success=1\n    bailout=1\n    while [ $timeout -gt 0 ] && [ $bailout -ne 0 ] && [ $success -ne 0 ]; do\n        resources=$(crm_mon -r --as-xml | xmllint --xpath \"${any_resource_xpath}\" - 2>/dev/null)\n\tif [ \"$(crm_resource --meta -r ${NAME} -g is-managed 2>/dev/null)\" = \"false\" ]; then\n            log \"${NAME} is unmanaged, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif [ \"$(crm_resource --meta -r ${NAME} -g target-role 2>/dev/null)\" = \"Stopped\" ]; then\n            log \"${NAME} is disabled, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif ! (echo \"${resources}\" | grep -q -w \"\\Wblocked=\\\"false\\\"\"); then\n            log \"${NAME} blocked, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif did_resource_failed_globally; then\n            log \"${NAME} is in failed state, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif echo \"${resources}\" | grep -q -w \"\\Wrole=\\\"${ROLE_ANYWHERE}\\\"\"; then\n            success=0\n            continue\n        else\n            log \"Waiting for ${NAME} to transition to role ${ROLE_ANYWHERE} anywhere in the cluster\"\n        fi\n\n        if [ $bailout -ne 0 ] && [ $success -ne 0 ]; then\n            sleep 4\n            timeout=$((timeout-4))\n        fi\n    done\nfi\n\nif [ $timeout -le 0 ]; then\n    log \"Timeout reached after ${TIMEOUT}s while waiting for ${NAME} to be restarted\"\nelif [ $bailout -le 0 ]; then\n    log \"Restart monitoring for ${NAME} cancelled\"\nfi\n\nif [ $success -eq 0 ]; then\n    log \"${NAME} successfully restarted\"\nelse\n    log \"${NAME} was not restarted properly\"\nfi\n\n# Don't block minor update or stack update if the wait was unsuccessful\nexit 0\n"}, "wait-port-and-run.sh": {"mode": "0755", "content": "#!/usr/bin/bash\nset -eu\n\nHOST=$1\nPORT=$2\n\necho \"$(date -u): Checking whether we can bind to ${HOST}:${PORT}\"\nwhile (ss -Htnl src \"${HOST}\" \"sport = :${PORT}\" | grep -wq \"${PORT}\"); do\n    echo \"$(date -u): ${HOST}:${PORT} still in use, waiting...\";\n    sleep 10;\ndone\n\nshift 2\nCOMMAND=\"$*\"\nif [ -z \"${COMMAND}\" ]; then\n    COMMAND=\"true\"\nfi\nexec $COMMAND\n"}, "pacemaker_resource_lock.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nMAX_RETRIES=10\nCIB_ENOTFOUND=105\n\nusage() {\n   echo \"Set a global property in the cluster with a validity timestamp.\"\n   echo \"Usage:\"\n   echo \"   $0 --acquire <lock_name> <lock_owner> <lock_ttl_in_seconds>\"\n   echo \"   $0 --release <lock_name> <lock_owner>\"\n   echo\n}\n\nlog() {\n    echo \"$(date -u): $1\" 1>&2\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\nlock_create() {\n    local name=$1\n    local data=$2\n    # cibadmin won't overwrite a key if someone else succeeded to create it concurrently\n    cibadmin --sync-call --scope crm_config --create --xml-text \"<cluster_property_set id='${name}'><nvpair id='${name}-pair' name='${name}' value='${data}'/></cluster_property_set>\" &>/dev/null\n    return $?\n}\n\nlock_update() {\n    local name=$1\n    local expected_data=$2\n    local new_data=$3\n    # we only update the lock we expect to see, so we can't update someone else's lock\n    cibadmin --sync-call --scope crm_config --modify --xpath \"//cluster_property_set/nvpair[@name='${name}' and @value='${expected_data}']/..\" --xml-text \"<nvpair id='${name}-pair' name='${name}' value='${new_data}'/>\" &>/dev/null\n    return $?\n}\n\nlock_delete() {\n    local name=$1\n    local expected_data=$2\n    # we only delete the lock we expect to see, so we can't delete someone else's lock\n    cibadmin --sync-call --scope crm_config --delete --xpath \"//cluster_property_set/nvpair[@name='${name}' and @value='${expected_data}']/..\" &>/dev/null\n    return $?\n}\n\nlock_get() {\n    local lockname=$1\n    local res\n    local rc\n    res=$(cibadmin --query --scope crm_config --xpath \"//cluster_property_set/nvpair[@name='$lockname']\" 2>/dev/null)\n    rc=$?\n    if [ $rc -eq 0 ]; then\n        echo \"$res\" | sed -n 's/.*value=\"\\([^\"]*\\)\".*/\\1/p'\n    fi\n    return $rc\n}\n\nlock_owner() {\n    local lock=$1\n    echo \"$lock\" | cut -d':' -f1\n}\n\nlock_has_expired() {\n    local lock=$1\n    local expiry=$(echo \"$lock\" | cut -d':' -f2)\n    local now=$(date +%s)\n    test $now -ge $expiry\n}\n\n\n# Perform a lock action and restart if the CIB has been modified before\n# committing the lock action\ntry_action() {\n    local fun=$1\n    local lock=$2\n    local requester=$3\n    local args=${4:-}\n    local tries=$MAX_RETRIES\n    local rc=1\n    if [ \"$fun\" = \"lock_acquire\" ] || [ \"$fun\" = \"lock_release\" ]; then\n        log \"Try running $fun\"\n    else\n        return 2\n    fi\n    while [ $rc -ne 0 ]; do\n        $fun $lock $requester $args\n        rc=$?\n        if [ $rc -eq 0 ]; then\n            log \"Operation $1 succeeded\"\n            return 0\n        elif [ $rc -eq 3 ]; then\n            # rc == 3 -> CIB changed before push\n            if [ $tries -eq 0 ]; then\n                log \"Failed to commit after $MAX_RETRIES retries. Bailing out.\"\n                return 2\n            else\n                log \"Failed to commit. Retrying operation.\"\n                tries=$(($tries - 1))\n            fi\n        elif [ $rc -eq 2 ]; then\n            # rc == 2 -> unrecoverable cib error (e.g. pacemaker down)\n            log \"Unexpected failure. Bailing out\"\n            return $rc\n        else\n            # rc == 1 -> lock error (not owner, lock doesn't exists)\n            return $rc\n        fi\n    done\n}\n\n# The lock mechanism uses cibadmin's atomic creation so cluster-wide\n# state coherency is guaranteed by pacemaker\nlock_acquire() {\n    local lockname=$1\n    local requester=$2\n    local ttl=$3\n    local rc\n    local lock\n    local expiry\n    local owner\n\n    log \"Check whether the lock is already held in the CIB\"\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        log \"Could not retrieve info from the CIB\"\n        return 2\n    fi\n\n    if [ -n \"$lock\" ]; then\n        lock_has_expired $lock\n        rc=$?\n        if [ $rc -eq 0 ]; then\n            log \"Lock has expired, now available for being held\"\n        else\n            # lock is still held. check whether we're the owner\n            owner=$(lock_owner $lock)\n            if [ \"$owner\" = \"$requester\" ];then\n                log \"Requester already owns the lock, acquiring attempt will just reconfigure the TTL\"\n            else\n                log \"Lock is held by someone else ($owner)\"\n                return 1\n            fi\n        fi\n    else\n        log \"Lock is not held yet\"\n    fi\n\n    # prepare the lock info\n    expiry=$(($(date +%s) + $ttl))\n\n    if [ -n \"$lock\" ]; then\n        log \"Attempting to update the lock\"\n        lock_update $lockname \"$lock\" \"$requester:$expiry\"\n        rc=$?\n    else\n        log \"Attempting to acquire the lock\"\n        lock_create $lockname \"$requester:$expiry\"\n        rc=$?\n    fi\n\n    if [ $rc -eq 0 ]; then\n        log \"Lock '$lockname' acquired by '$requester', valid until $(date -d @$expiry)\"\n        return 0\n    else\n        log \"CIB changed, lock cannot be acquired\"\n        return 3\n    fi\n}\n\n\n# The lock mechanism uses the CIB's num_updates tag to implement\n# a conditional store. Cluster-wide locking is guaranteed by pacemaker\nlock_release() {\n    local lockname=$1\n    local requester=$2\n    local rc\n    local lock\n    local owner\n\n    log \"Check whether the lock is already held in the CIB\"\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        log \"Could not retrieve info from the CIB\"\n        return 2\n    fi\n\n    if [ -z \"$lock\" ]; then\n        log \"Lock doesn't exist. Nothing to release\"\n        return 0\n    else\n        log \"Lock exists, check whether we're the owner\"\n        owner=$(lock_owner $lock)\n        if [ \"$owner\" != \"$requester\" ];then\n            log \"Lock is held by someone else ($owner), will not unlock\"\n            return 1\n        fi\n    fi\n\n    lock_delete $lockname \"$lock\"\n    rc=$?\n\n    if [ $rc -eq 0 ]; then\n        log \"Lock '$lockname' released by '$requester'\"\n        return 0\n    else\n        log \"CIB deletion error, lock cannot be released\"\n        return 3\n    fi\n}\n\n\n# Retrieve the owner of a lock from the CIB\n# this is a read-only operation, so no need to log debug info\nlock_get_owner() {\n    local lockname=$1\n    local rc\n    local lock\n    local owner\n\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        return 2\n    fi\n\n    if [ -z \"$lock\" ]; then\n        return 1\n    else\n        lock_owner $lock\n        return 0\n    fi\n}\n\n\nACTION=$1\nLOCKNAME=$2\nREQUESTER=$3\nTTL=${4:-60}\n\nif [ -z \"$ACTION\" ]; then\n    error \"Action must be specified\"\nfi\n\nif [ $ACTION != \"--help\" ]; then\n    if [ -z \"$LOCKNAME\" ]; then\n        error \"You must specific a lock name\"\n    fi\n    if [ $ACTION != \"--owner\" ] && [ $ACTION != \"-o\" ]; then\n        if [ -z \"$REQUESTER\" ]; then\n            error \"You must specific a lock requester\"\n        fi\n    fi\nfi\n\ncase $ACTION in\n    --help) usage; exit 0;;\n    --acquire|-a) try_action lock_acquire $LOCKNAME $REQUESTER $TTL;;\n    --release|-r) try_action lock_release $LOCKNAME $REQUESTER;;\n    --acquire-once|-A) lock_acquire $LOCKNAME $REQUESTER $TTL;;\n    --owner|-o) lock_get_owner $LOCKNAME;;\n    *) error \"Invalid action\";;\nesac\nexit $?\n"}, "pacemaker_mutex_restart_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# pacemaker_mutex_restart_bundle.sh --lock mysql galera galera-bundle Master _\n# pacemaker_mutex_restart_bundle.sh --lock ovn_dbs ovndb_servers ovn-dbs-bundle Slave Master\n\nset -u\n\nusage() {\n    echo \"Restart a clustered resource in a coordinated way across the cluster\"\n    echo \"Usage:\"\n    echo \"   $0 --lock <tripleo-service> <pcmk-resource> <pcmk-bundle> <target-state-local> <target-state-cluster>\"\n    echo\n}\n\nlog() {\n    echo \"$(date -u): $1\"\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\npacemaker_supports_promoted() {\n    # The Promoted token is only matched in recent pacemaker versions\n    grep -wq \"<value>Promoted</value>\" /usr/share/pacemaker/resources-*.rng\n}\n\nACTION=$1\ncase $ACTION in\n    --help) usage; exit 0;;\n    --lock) ;;\n    *) error \"Unknown action '$ACTION'\";;\nesac\n\nTRIPLEO_SERVICE=$2\nLOCK_NAME=${TRIPLEO_SERVICE}-restart-lock\nLOCK_OWNER=$(crm_node -n 2>/dev/null)\nrc=$?\nif [ $rc -ne 0 ]; then\n    if [ $rc -eq 102 ]; then\n        log \"Cluster is not running locally, no need to restart resource $TRIPLEO_SERVICE\"\n        exit 0\n    else\n        error \"Unexpected error while connecting to the cluster (rc: $rc), bailing out\"\n    fi\nfi\n\nRESOURCE_NAME=$3\nBUNDLE_NAME=$4\nWAIT_TARGET_LOCAL=$5\nWAIT_TARGET_ANYWHERE=${6:-_}\n\nif pacemaker_supports_promoted; then\n    WAIT_TARGET_LOCAL=$(echo \"$5\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    WAIT_TARGET_ANYWHERE=$(echo \"${6:-_}\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    promoted_role=\"Promoted\"\nelse\n    promoted_role=\"Master\"\nfi\n\n# The lock TTL should accomodate for the resource start/promote timeout\nif [ \"$RESOURCE_NAME\" != \"$BUNDLE_NAME\" ]; then\n    if [ \"$WAIT_TARGET_LOCAL\" = \"$promoted_role\" ] || [ \"$WAIT_TARGET_ANYWHERE\" = \"$promoted_role\" ]; then\n        rsc_op=\"promote\"\n    else\n        rsc_op=\"start\"\n    fi\n    # <op id=\"galera-promote-interval-0s\" interval=\"0s\" name=\"promote\" on-fail=\"block\" timeout=\"300s\"/>\n    PCMK_TTL=$(cibadmin -Q | xmllint -xpath \"string(//primitive[@id='${RESOURCE_NAME}']/operations/op[@name='${rsc_op}']/@timeout)\" - | sed 's/s$//')\n    LOCK_TTL=$((PCMK_TTL + 30))\nelse\n    # The podman RA's default start timeout\n    LOCK_TTL=90\nfi\n\nlog \"Acquire a ${LOCK_TTL}s restart lock for service $TRIPLEO_SERVICE before restarting it\"\n# Loop until we hold the lock. The lock has a TTL, so we're guaranteed to get it eventually\nrc=1\nwhile [ $rc -ne 0 ]; do\n    /var/lib/container-config-scripts/pacemaker_resource_lock.sh --acquire $LOCK_NAME $LOCK_OWNER $LOCK_TTL\n    rc=$?\n    if [ $rc != 0 ]; then\n        if [ $rc -gt 1 ]; then\n            error \"Could not acquire lock due to unrecoverable error (rc: $rc), bailing out\"\n        else\n            log \"Could not acquire lock, retrying\"\n            sleep 10\n        fi\n    fi\ndone\n\nlog \"Restart the service $TRIPLEO_SERVICE locally\"\n# Reuse the local restart script in t-h-t (driven by env var TRIPLEO_MINOR_UPDATE)\nTRIPLEO_MINOR_UPDATE=true /var/lib/container-config-scripts/pacemaker_restart_bundle.sh $TRIPLEO_SERVICE $RESOURCE_NAME $BUNDLE_NAME $WAIT_TARGET_LOCAL $WAIT_TARGET_ANYWHERE\n\n# If we reached this point, always try to release the lock\nlog \"Release the restart lock for service $TRIPLEO_SERVICE\"\n/var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $LOCK_NAME $LOCK_OWNER\nrc=$?\nif [ $rc -ne 0 ] && [ $rc -ne 1 ]; then\n    error \"Could not release held lock (rc: $rc)\"\nfi\n"}, "pacemaker_mutex_shutdown.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# pacemaker_mutex_shutdown.sh --acquire\n# pacemaker_mutex_shutdown.sh --release\n\nset -u\n\nusage() {\n    echo \"Shutdown a cluster node in a coordinated way across the cluster\"\n    echo \"Usage:\"\n    echo \"   $0 --acquire # prevent other node from shutting down until we hold the lock\"\n    echo \"   $0 --release # release the lock, other node can compete for the shutdown lock\"\n    echo\n}\n\nlog() {\n    echo \"$(date -u): $1\"\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\n# Loop until we hold the lock. The lock has a TTL, so we're guaranteed to get it eventually\nshutdown_lock_acquire() {\n    local lockname=$1\n    local requester=$2\n    local ttl=$3\n    local rc=1\n    local current_owner\n    local owner_stopped\n    local owner_rc\n\n    log \"Acquiring the shutdown lock\"\n    while [ $rc -ne 0 ]; do\n        /var/lib/container-config-scripts/pacemaker_resource_lock.sh --acquire-once $lockname $requester $ttl\n        rc=$?\n        if [ $rc -ne 0 ]; then\n            if [ $rc -eq 2 ]; then\n                error \"Could not acquire the shutdown lock due to unrecoverable error (rc: $rc), bailing out\"\n            else\n                # The lock is held by another node.\n                current_owner=$(/var/lib/container-config-scripts/pacemaker_resource_lock.sh --owner $lockname)\n                owner_rc=$?\n                if [ $owner_rc -eq 2 ]; then\n                    error \"Could not get the shutdown lock owner due to unrecoverable error (rc: $owner_rc), bailing out\"\n                fi\n                if [ $owner_rc -eq 0 ]; then\n                    # If the owner is marked as offline, that means it has shutdown and\n                    # we can clean the lock preemptively and try to acquire it.\n                    owner_stopped=$(crm_mon -1X | xmllint --xpath 'count(//nodes/node[@name=\"'${current_owner}'\" and @online=\"false\" and @unclean=\"false\"])' -)\n                    if [ \"${owner_stopped}\" = \"1\" ]; then\n                        log \"Shutdown lock held by stopped node '${current_owner}', lock can be released\"\n                        /var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $lockname $current_owner\n                        continue\n                    fi\n                fi\n                log \"Shutdown lock held by another node (rc: $rc), retrying\"\n                sleep 10\n            fi\n        fi\n    done\n    log \"Shutdown lock acquired\"\n    return 0\n}\n\n\n# Release the lock if we still own it. Not owning it anymore is not fatal\nshutdown_lock_release() {\n    local lockname=$1\n    local requester=$2\n    local rc\n\n    log \"Releasing the shutdown lock\"\n    /var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $lockname $requester\n    rc=$?\n    if [ $rc -ne 0 ]; then\n        if [ $rc -gt 1 ]; then\n            error \"Could not release the shutdown lock due to unrecoverable error (rc: $rc), bailing out\"\n        else\n            log \"Shutdown lock no longer held, nothing to do\"\n        fi\n    else\n        log \"Shutdown lock released\"\n    fi\n    return 0\n}\n\n\nACTION=$1\nif [ -z \"$ACTION\" ]; then\n    error \"Action must be specified\"\nfi\n\nLOCK_NAME=tripleo-shutdown-lock\nLOCK_OWNER=$(crm_node -n 2>/dev/null)\nrc=$?\nif [ $rc -ne 0 ]; then\n    if [ $rc -eq 102 ]; then\n        log \"Cluster is not running locally, no need to aquire the shutdown lock\"\n        exit 0\n    else\n        error \"Unexpected error while connecting to the cluster (rc: $rc), bailing out\"\n    fi\nfi\n\n# We start with a very high TTL, that long enough to accomodate a cluster stop.\n# As soon as the node will get offline, the other competing node will be entitled\n# to steal the lock, so they should never wait that long in practice.\nLOCK_TTL=600\n\n\ncase $ACTION in\n    --help) usage; exit 0;;\n    --acquire|-a) shutdown_lock_acquire ${LOCK_NAME} ${LOCK_OWNER} ${LOCK_TTL};;\n    --release|-r) shutdown_lock_release ${LOCK_NAME} ${LOCK_OWNER};;\n    *) error \"Invalid action\";;\nesac\nexit $?\n"}}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-58-jyexllgjlvch-ContainersCommon-gsw56cgspcea/39b23bae-9662-4c8f-997d-02c969b7800b"}


created_at: 2025-12-01 09:42:48.409827
data:
  {"value": {"ContainerOvnMetadataImage": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "ContainerNeutronConfigImage": "registry.redhat.io/rhosp-rhel9/openstack-neutron-server:17.1"}}


created_at: 2025-12-01 09:42:48.513039
data:
  {"volumes": ["/var/log/containers/neutron:/var/log/neutron:z"], "host_prep_tasks": [{"name": "create persistent directories", "file": {"path": "{{ item.path }}", "state": "directory", "setype": "{{ item.setype }}", "mode": "{{ item.mode }}"}, "with_items": [{"path": "/var/log/containers/neutron", "setype": "container_file_t", "mode": "0750"}]}], "config_settings": null, "cmd_extra_args": "--log-file=/var/log/neutron/ovn-metadata-agent.log", "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-58-jyexllgjlvch-NeutronLogging-kxtuxp7p6i64/45603042-0cb2-4dde-8a6c-5147c0b51fdc"}


created_at: 2025-12-01 09:42:48.567894
data:
  {"tuple:('role_data', 'config_settings')": {"neutron::notification_driver": ["messagingv2"], "neutron::core_plugin": "ml2", "neutron::service_plugins": ["qos", "ovn-router", "trunk", "segments", "port_forwarding", "log"], "neutron::report_interval": 300, "neutron::logging::debug": true, "neutron::purge_config": false, "neutron::allow_overlapping_ips": true, "neutron::dhcp_agent_notification": true, "neutron::dns_domain": "localdomain", "neutron::rabbit_heartbeat_timeout_threshold": 60, "neutron::host": "%{hiera('fqdn_canonical')}", "neutron::db::database_db_max_retries": -1, "neutron::db::database_max_retries": -1, "neutron::db::sync::db_sync_timeout": 900, "neutron::global_physnet_mtu": 1500, "neutron::db::sync::extra_params": "", "neutron::vlan_transparent": false, "neutron::rabbit_heartbeat_in_pthread": false}, "tuple:('role_data', 'metadata_settings')": null, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-58-jyexllgjlvch-NeutronBase-l2x4xonkas7p/37b28f92-4a0f-41cf-ac6d-47492c855d48"}


created_at: 2025-12-01 09:42:48.588345
data:
  {"tuple:('role_data', 'step_config')": null, "tuple:('role_data', 'docker_config')": {"step_2": {"create_haproxy_wrapper": {"start_order": 1, "detach": false, "net": "host", "pid": "host", "user": "root", "command": ["/container_puppet_apply.sh", "4", "file", "include ::tripleo::profile::base::neutron::ovn_metadata_agent_wrappers"], "image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/var/lib/container-config-scripts/container_puppet_apply.sh:/container_puppet_apply.sh:ro", "/etc/puppet:/tmp/puppet-etc:ro", "/usr/share/openstack-puppet/modules:/usr/share/openstack-puppet/modules:ro", "/run/openvswitch:/run/openvswitch:shared,z", "/var/lib/neutron:/var/lib/neutron:shared,z"]}}, "step_4": {"setup_ovs_manager": {"start_order": 0, "detach": false, "net": "host", "privileged": true, "user": "root", "command": ["/container_puppet_apply.sh", "4", "exec", "include tripleo::profile::base::neutron::ovn_metadata"], "image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/var/lib/container-config-scripts/container_puppet_apply.sh:/container_puppet_apply.sh:ro", "/etc/puppet:/tmp/puppet-etc:ro", "/usr/share/openstack-puppet/modules:/usr/share/openstack-puppet/modules:ro", "/lib/modules:/lib/modules:ro", "/run/openvswitch:/run/openvswitch:shared,z"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}, "ovn_metadata_agent": {"start_order": 1, "image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "net": "host", "pid": "host", "cgroupns": "host", "privileged": true, "restart": "always", "healthcheck": {"test": "/openstack/healthcheck"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/neutron:/var/log/neutron:z", "/var/lib/kolla/config_files/ovn_metadata_agent.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/config-data/puppet-generated/neutron:/var/lib/kolla/config_files/src:ro", "/lib/modules:/lib/modules:ro", "/run/openvswitch:/run/openvswitch:shared,z", "/var/lib/neutron:/var/lib/neutron:shared,z", "/run/netns:/run/netns:shared", "/var/lib/neutron/kill_scripts:/etc/neutron/kill_scripts:shared,z", "/var/lib/neutron/ovn_metadata_haproxy_wrapper:/usr/local/bin/haproxy:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}}}, "tuple:('role_data', 'service_names')": null, "tuple:('role_data', 'container_config_scripts')": {"container_puppet_apply.sh": {"mode": "0700", "content": "#!/bin/bash\nset -eux\nSTEP=$1\nTAGS=$2\nCONFIG=$3\nEXTRA_ARGS=${4:-''}\nif [ -d /tmp/puppet-etc ]; then\n  # ignore copy failures as these may be the same file depending on docker mounts\n  cp -a /tmp/puppet-etc/* /etc/puppet || true\nfi\necho \"{\\\"step\\\": ${STEP}}\" > /etc/puppet/hieradata/docker_puppet.json\n# $::deployment_type in puppet-tripleo\nexport FACTER_deployment_type=containers\nset +e\npuppet apply $EXTRA_ARGS \\\n    --verbose \\\n    --detailed-exitcodes \\\n    --summarize \\\n    --color=false \\\n    --modulepath /etc/puppet/modules:/opt/stack/puppet-modules:/usr/share/openstack-puppet/modules \\\n    --tags $TAGS \\\n    -e \"noop_resource('package'); ${CONFIG}\"\nrc=$?\nset -e\nset +ux\nif [ $rc -eq 2 -o $rc -eq 0 ]; then\n    exit 0\nfi\nexit $rc\n"}, "pyshim.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n# Copyright 2018 Red Hat Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n#\n# Usage: pyshim.sh <script and/or arguments>\n#\n# Unfortunately THT doesn't know which version of python might be in a\n# container so we need this script to be able to try python3 or python2\n# depending on availability.  Since this is a temporary shim until we've\n# fully cut over to python3, we check for the existence of python3 first\n# before falling back to python2. This will help in the transition from\n# python2 based containers to python3.\n\nshow_usage() {\n    echo \"Usage: pyshim.sh <script and/or arguments>\"\n}\n\nif [ $# -lt 1 ]\nthen\n    show_usage\n    exit 1\nfi\n\nset -x\nif command -v python3 >/dev/null; then\n    python3 \"$@\"\nelif command -v python2 >/dev/null; then\n    python2 \"$@\"\nelif command -v python >/dev/null; then\n    python \"$@\"\nelse\n    echo \"ERROR: python is not available!\"\n    exit 1\nfi\n"}, "pacemaker_restart_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nset -u\n\n# ./pacemaker_restart_bundle.sh mysql galera galera-bundle Master _\n# ./pacemaker_restart_bundle.sh redis redis redis-bundle Slave Master\n# ./pacemaker_restart_bundle.sh ovn_dbs ovndb_servers ovn-dbs-bundle Slave Master\nRESTART_SCRIPTS_DIR=$(dirname $0)\nTRIPLEO_SERVICE=$1\nRESOURCE_NAME=$2\nBUNDLE_NAME=$3\nWAIT_TARGET_LOCAL=$4\nWAIT_TARGET_ANYWHERE=${5:-_}\nTRIPLEO_MINOR_UPDATE=\"${TRIPLEO_MINOR_UPDATE:-false}\"\nTRIPLEO_HA_WRAPPER_RESOURCE_EXISTS=\"${TRIPLEO_HA_WRAPPER_RESOURCE_EXISTS:-false}\"\n\nbundle_can_be_restarted() {\n    local bundle=$1\n    # As long as the resource bundle is managed by pacemaker and is\n    # not meant to stay stopped, no matter the state of any inner\n    # pcmk_remote or ocf resource, we should restart it to give it a\n    # chance to read the new config.\n    [ \"$(crm_resource --meta -r $1 -g is-managed 2>/dev/null)\" != \"false\" ] && \\\n    [ \"$(crm_resource --meta -r $1 -g target-role 2>/dev/null)\" != \"Stopped\" ]\n}\n\nlog() {\n    local msg=$1\n    logger -t pcmkrestart \"$1\"\n}\n\nHOSTNAME=$(/bin/hostname -s)\nif [ x\"${TRIPLEO_MINOR_UPDATE,,}\" != x\"true\" ]; then\n    if [ x\"${TRIPLEO_HA_WRAPPER_RESOURCE_EXISTS,,}\" = x\"false\" ]; then\n        # Do not restart during initial deployment, as the resource\n        # has just been created.\n        SERVICE_NODEID=$(/bin/hiera -c /etc/puppet/hiera.yaml \"${TRIPLEO_SERVICE}_short_bootstrap_node_name\")\n        if [[ \"${HOSTNAME,,}\" == \"${SERVICE_NODEID,,}\" ]]; then\n            log \"Initial deployment, skipping the restart of ${BUNDLE_NAME}\"\n\tfi\n        exit 0\n    else\n        # During a stack update, this script is called in parallel on\n        # every node the resource runs on, after the service's configs\n        # have been updated on all nodes. So we need to run pcs only\n        # once (e.g. on the service's boostrap node).\n        if bundle_can_be_restarted ${BUNDLE_NAME}; then\n            SERVICE_NODEID=$(/bin/hiera -c /etc/puppet/hiera.yaml \"${TRIPLEO_SERVICE}_short_bootstrap_node_name\")\n            if [[ \"${HOSTNAME,,}\" == \"${SERVICE_NODEID,,}\" ]]; then\n                replicas_running=$(crm_resource -Q -r $BUNDLE_NAME --locate 2>&1 | wc -l)\n                if [ \"$replicas_running\" != \"0\" ]; then\n                    log \"Restarting ${BUNDLE_NAME} globally. Stopping:\"\n                    /sbin/pcs resource disable --wait=600 $BUNDLE_NAME\n                    log \"Restarting ${BUNDLE_NAME} globally. Starting:\"\n                    /sbin/pcs resource enable --wait=600 $BUNDLE_NAME\n                else\n                    log \"${BUNDLE_NAME} is not running anywhere,\" \\\n                         \"cleaning up to restart it globally if necessary\"\n                    /sbin/pcs resource cleanup $BUNDLE_NAME\n                fi\n            else\n                log \"Skipping global restart of ${BUNDLE_NAME} on ${HOSTNAME} it will be restarted by node ${SERVICE_NODEID}\"\n            fi\n\n        else\n            log \"No global restart needed for ${BUNDLE_NAME}.\"\n        fi\n    fi\nelse\n    # During a minor update workflow however, a host gets fully\n    # updated before updating the next one. So unlike stack\n    # update, at the time this script is called, the service's\n    # configs aren't updated on all nodes yet. So only restart the\n    # resource locally, where it's guaranteed that the config is\n    # up to date.\n    HOST=$(facter hostname)\n\n    if bundle_can_be_restarted ${BUNDLE_NAME}; then\n\t# if the resource is running locally, restart it\n\tif crm_resource -r $BUNDLE_NAME --locate 2>&1 | grep -w -q \"${HOST}\"; then\n            log \"Restarting ${BUNDLE_NAME} locally on '${HOST}'\"\n            /sbin/pcs resource restart $BUNDLE_NAME \"${HOST}\"\n\n\telse\n\t    # At this point, if no resource is running locally, it's\n\t    # either because a) it has failed previously, or b) because\n\t    # it's an A/P resource running elsewhere.\n\t    # By cleaning up resource, we ensure that a) it will try to\n\t    # restart, or b) it won't do anything if the resource is\n\t    # already running elsewhere.\n            log \"${BUNDLE_NAME} is currently not running on '${HOST}',\" \\\n                 \"cleaning up its state to restart it if necessary\"\n            /sbin/pcs resource cleanup $BUNDLE_NAME node=\"${HOST}\"\n\tfi\n\n\t# Wait until the resource is in the expected target state\n\t$RESTART_SCRIPTS_DIR/pacemaker_wait_bundle.sh \\\n            $RESOURCE_NAME $BUNDLE_NAME \\\n            \"$WAIT_TARGET_LOCAL\" \"$WAIT_TARGET_ANYWHERE\" \\\n\t    \"${HOST}\" 600\n    else\n        log \"No restart needed for ${BUNDLE_NAME}.\"\n    fi\nfi\n"}, "pacemaker_wait_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# ----\n# Wait for an OCF resource or a bundle to be restarted\n# ----\n# e.g.:\n# M/S OCF:      $0 galera galera-bundle Master\n# clone OCF:    $0 rabbitmq rabbitmq-bundle Started\n# A/P M/S OCF:  $0 redis redis-bundle Slave Master\n# A/P bundle:   $0 openstack-cinder-volume openstack-cinder-volume _ Started\n# clone bundle: $0 haproxy-bundle haproxy-bundle Started\n\n# design note 1:\n#  - this script is called during a minor update; it is called\n#    once per node that hosts a service replica.\n#  - the purpose of this script is to ensure that restarting the\n#    service replica locally won't disrupt the service availability\n#    for the end user. To reach that goal, the script waits until the\n#    service is restarted locally or globallu and reaches a given\n#    target state (i.e. Started, Slave or Master).\n# design note 2:\n#   - we don't want to track restart error: our only job is to ensure\n#     service restart synchronization, not service health.\n#   - In particular, we don't want to error out in case the resource\n#     cannot be restarted locally, because that would make the minor\n#     update fail, even if potentially other replicas still provide\n#     the service.\n# design note 3:\n#   - we can bail out early if we determine that the resource can't\n#     be restarted automatically by pacemaker (e.g. its \"blocked\",\n#     unmanaged or disabled).\n\nlog() {\n    local msg=$1\n    echo \"$(date -u): $1\"\n}\n\nusage() {\n    echo 2>&1 \"Usage: $0 NAME BUNDLE_NAME ROLE_LOCAL [ROLE_ANYWHERE] [HOST] [TIMEOUT]\"\n    exit 1\n}\n\npacemaker_supports_promoted() {\n    # The Promoted token is only matched in recent pacemaker versions\n    grep -wq \"<value>Promoted</value>\" /usr/share/pacemaker/resources-*.rng\n}\n\n#\n# Utility functions to detect stuck resources\n#\n\nbundle_failures_locally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    local replica_name\n    for i in $(seq 0 $last); do\n\treplica_name=${BUNDLE_NAME}-${engine}-${i}\n\tcrm_failcount -q -G -r $replica_name -N $HOST\n    done\n}\n\nbundle_failures_globally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    for i in $(seq 0 $last); do\n\tcrm_failcount -q -G -r ${BUNDLE_NAME}-${engine}-${i}\n    done\n}\n\nbundle_running_globally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    # return the number of running bundles replica, i.e. the number of\n    # docker/podman resource replicas currently running in the cluster\n    crm_mon --as-xml | xmllint --xpath \"count(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource[@resource_agent='${OCF}:heartbeat:${engine}']/node)\" -\n}\n\nocf_failures_globally() {\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    local bundle_node\n    for i in $(seq 0 $last); do\n\tbundle_node=${BUNDLE_NAME}-${i}\n\tcrm_failcount -q -G -r $NAME -N $bundle_node\n    done\n}\n\ndid_resource_failed_locally() {\n    local failures\n    local running\n    local remotehost\n    if [ \"${NAME}\" != \"${BUNDLE_NAME}\" ]; then\n\t# if we're dealing with an ocf resource, it is running on a\n\t# pacemaker_remote rather that on the real host, and the\n\t# failcounts are thus associated to the pcmk remote. Replace\n\t# the host's name with the pcmk remote's name.\n        remotehost=$(crm_mon --as-xml | xmllint --xpath \"string(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource/node[@name='${HOST}']/../../resource[@resource_agent='${OCF}:pacemaker:remote']/@id)\" -)\n\tif [ -n \"${remotehost}\" ]; then\n\t    crm_failcount -q -G -r $NAME -N $remotehost | grep -q -w INFINITY\n\t    return $?\n\tfi\n\t# If no pcmk remote is currently running, the failcount from\n\t# the ocf resource is useless, compute the failcount from the\n\t# bundle case instead (computed below).\n    fi\n\n    # for bundles, pacemaker can run any bundle replica locally\n    # (e.g. galera-bundle-docker-{0,1,2}), and a failure happens when\n    # there are no more replica to try.\n    # That is, when _at least_ one replica failed locally, and all the\n    # others either failed or are currently running elsewhere.\n    failures=$(bundle_failures_locally $HOST | grep -c -w INFINITY)\n    running=$(bundle_running_globally)\n    test $failures -gt 0 && \\\n    test $(( $failures + $running )) -ge $BUNDLE_REPLICAS\n}\n\ndid_resource_failed_globally() {\n    local remotecount\n    local failures\n    if [ \"${NAME}\" != \"${BUNDLE_NAME}\" ]; then\n\t# we check the state of an ocf resource only if the\n\t# pcmkremotes are started\n        remotecount=$(crm_mon --as-xml | xmllint --xpath \"count(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource[@resource_agent='${OCF}:pacemaker:remote']/node)\" -)\n\tif [ \"${remotecount}\" = \"0\" ]; then\n\t    # no pcmkremote is running, so check the bundle state\n\t    # instead of checking the ocf resource\n\t    # bundle failed if all ${BUNDLE_REPLICAS} replicas failed\n\t    failures=$(bundle_failures_globally | grep -c -w INFINITY)\n\t    test $failures -eq $BUNDLE_REPLICAS\n\telse\n\t    # ocf resource failed if it failed to start on\n\t    # all $BUNDLE_REPLICAS bundle nodes\n\t    failures=$(ocf_failures_globally | grep -c -w INFINITY)\n\t    test $failures -eq $BUNDLE_REPLICAS\n\tfi\n    else\n\t# bundle failed if all ${BUNDLE_REPLICAS} replicas failed\n\tfailures=$(bundle_failures_globally | grep -c -w INFINITY)\n\ttest $failures -eq $BUNDLE_REPLICAS\n    fi\n}\n\n\n# Input validation\n#\n\nNAME=$1\nif [ -z \"${NAME}\" ]; then\n    echo 2>&1 \"Error: argument NAME must not be empty\"\n    exit 1\nfi\n\nBUNDLE_NAME=$2\nif [ -z \"${BUNDLE_NAME}\" ]; then\n    echo 2>&1 \"Error: argument BUNDLE_NAME must not be empty\"\n    exit 1\nfi\n\nROLE_LOCAL=$3\nif [ \"${ROLE_LOCAL}\" = \"_\" ]; then\n    ROLE_LOCAL=\"\"\nfi\n\nROLE_ANYWHERE=$4\nif [ \"${ROLE_ANYWHERE}\" = \"_\" ]; then\n    ROLE_ANYWHERE=\"\"\nfi\n\nif [ -z \"${ROLE_LOCAL}\" ]; then\n    if [ -z \"${ROLE_ANYWHERE}\" ]; then\n        echo 2>&1 \"Error: either ROLE_LOCAL or ROLE_ANYWHERE must be non empty\"\n        exit 1\n    fi\nelse\n    if !(echo \"${ROLE_LOCAL}\" | grep -q -x -E \"(Started|Slave|Master|Unpromoted|Promoted)\"); then\n        echo 2>&1 \"Error: argument ROLE_LOCAL must be either 'Started' 'Slave' 'Master' 'Unpromoted' or 'Promoted'\"\n        exit 1\n    fi\nfi\n\nif [ -n \"${ROLE_ANYWHERE}\" ] && !(echo \"${ROLE_ANYWHERE}\" | grep -q -x -E \"(Started|Slave|Master|Unpromoted|Promoted)\"); then\n    echo 2>&1 \"Error: argument ROLE_ANYWHERE must be either 'Started' 'Slave' 'Master' 'Unpromoted' or 'Promoted'\"\n    exit 1\nfi\n\n# Ensure compatibility with pacemaker 2.1\nif pacemaker_supports_promoted; then\n    ROLE_LOCAL=$(echo \"$ROLE_LOCAL\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    ROLE_ANYWHERE=$(echo \"$ROLE_ANYWHERE\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    OCF=\"ocf\"\nelse\n    OCF=\"ocf:\"\nfi\n\nHOST=${5:-$(facter hostname)}\nTIMEOUT=${6:-600}\n\n\n# Configure the search\n# ----\n# Note: we can't use crm_resource in all searches because we can't\n# easily extract the host the OCF resources run on (crm_resource\n# returns the pcmk-remote nodes rather than the hosts)\n# So instead, we implement various searches with XPath directly.\n\nif [ \"${BUNDLE_NAME}\" != \"${NAME}\" ]; then\n# ocf resource\nlocal_resource_xpath=\"//bundle/replica/resource[@resource_agent='${OCF}:pacemaker:remote']/node[@name='${HOST}']/../../resource[@id='${NAME}']\"\nany_resource_xpath=\"//bundle//resource[@id='${NAME}']\"\nreplicas_xpath=\"//bundle/primitive[@id='${BUNDLE_NAME}']/../*[boolean(@image) and boolean(@replicas)]\"\nelse\n# bundle resource\nlocal_resource_xpath=\"//bundle[@id='${NAME}']/replica/resource/node[@name='${HOST}']/../../resource\"\nany_resource_xpath=\"//bundle[@id='${NAME}']//resource\"\nreplicas_xpath=\"//bundle[@id='${BUNDLE_NAME}']/*[boolean(@image) and boolean(@replicas)]\"\nfi\n\nbundle_def_xpath=\"//bundle[@id='${BUNDLE_NAME}']/*[boolean(@image) and boolean(@replicas)]\"\nBUNDLE_CONTAINER_ENGINE=$(cibadmin -Q | xmllint --xpath \"name(${bundle_def_xpath})\" -)\nBUNDLE_REPLICAS=$(cibadmin -Q | xmllint --xpath \"string(${bundle_def_xpath}/@replicas)\" -)\n\n\n# The wait algorithm follows a two-stage approach\n#  1. Depending on how the script is called, we first check whether\n#     the resource is restarted locally. An A/P resource may be\n#     restarted elsewhere in the cluster.\n#  2. If needed, check whether the A/P resource has restarted\n#     elsewhere. For A/P M/S resources, in case the resource is\n#     restarted as Slave locally, ensure a Master is available.\n\nsuccess=1\nbailout=1\ntimeout=$TIMEOUT\nrole=\"\"\n\n# Stage 1: local check\nif [ -n \"$ROLE_LOCAL\" ]; then\n    log \"Waiting until ${NAME} has restarted on ${HOST} and is in state ${ROLE_LOCAL}\"\n    log \"Will probe resource state with the following XPath pattern: ${local_resource_xpath}\"\n\n    while [ $timeout -gt 0 ] && [ $bailout -ne 0 ] && [ $success -ne 0 ]; do\n        resource=$(crm_mon -r --as-xml | xmllint --xpath \"${local_resource_xpath}\" - 2>/dev/null)\n        role=$(echo \"${resource}\" | sed -ne 's/.*\\Wrole=\"\\([^\"]*\\)\".*/\\1/p')\n\n\tif [ \"$(crm_resource --meta -r ${NAME} -g is-managed 2>/dev/null)\" = \"false\" ]; then\n            log \"${NAME} is unmanaged, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif [ \"$(crm_resource --meta -r ${NAME} -g target-role 2>/dev/null)\" = \"Stopped\" ]; then\n            log \"${NAME} is disabled, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif echo \"${resource}\" | grep -q -w \"\\Wblocked=\\\"true\\\"\"; then\n            log \"${NAME} is blocked, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif did_resource_failed_locally; then\n            log \"${NAME} is in failed state, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif [ \"$role\" = \"$ROLE_LOCAL\" ]; then\n            success=0\n            continue\n        elif [ -n \"$ROLE_ANYWHERE\" ] && [ \"$role\" = \"$ROLE_ANYWHERE\" ]; then\n            # A/P: we are restarted in the expected state\n            success=0\n            continue\n        else\n            log \"Waiting for ${NAME} to transition to role ${ROLE_LOCAL} on ${HOST}\"\n        fi\n\n        if [ $bailout -ne 0 ] && [ $success -ne 0 ]; then\n            sleep 4\n            timeout=$((timeout-4))\n        fi\n    done\nfi\n\n# Stage 2: global check\nif [ $timeout -gt 0 ] && [ -n \"$ROLE_ANYWHERE\" ] && [ \"$role\" != \"$ROLE_ANYWHERE\" ]; then\n    log \"Wait until ${NAME} is restarted anywhere in the cluster in state ${ROLE_ANYWHERE}\"\n    log \"Will probe resource state with the following XPath pattern: ${any_resource_xpath}\"\n\n    success=1\n    bailout=1\n    while [ $timeout -gt 0 ] && [ $bailout -ne 0 ] && [ $success -ne 0 ]; do\n        resources=$(crm_mon -r --as-xml | xmllint --xpath \"${any_resource_xpath}\" - 2>/dev/null)\n\tif [ \"$(crm_resource --meta -r ${NAME} -g is-managed 2>/dev/null)\" = \"false\" ]; then\n            log \"${NAME} is unmanaged, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif [ \"$(crm_resource --meta -r ${NAME} -g target-role 2>/dev/null)\" = \"Stopped\" ]; then\n            log \"${NAME} is disabled, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif ! (echo \"${resources}\" | grep -q -w \"\\Wblocked=\\\"false\\\"\"); then\n            log \"${NAME} blocked, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif did_resource_failed_globally; then\n            log \"${NAME} is in failed state, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif echo \"${resources}\" | grep -q -w \"\\Wrole=\\\"${ROLE_ANYWHERE}\\\"\"; then\n            success=0\n            continue\n        else\n            log \"Waiting for ${NAME} to transition to role ${ROLE_ANYWHERE} anywhere in the cluster\"\n        fi\n\n        if [ $bailout -ne 0 ] && [ $success -ne 0 ]; then\n            sleep 4\n            timeout=$((timeout-4))\n        fi\n    done\nfi\n\nif [ $timeout -le 0 ]; then\n    log \"Timeout reached after ${TIMEOUT}s while waiting for ${NAME} to be restarted\"\nelif [ $bailout -le 0 ]; then\n    log \"Restart monitoring for ${NAME} cancelled\"\nfi\n\nif [ $success -eq 0 ]; then\n    log \"${NAME} successfully restarted\"\nelse\n    log \"${NAME} was not restarted properly\"\nfi\n\n# Don't block minor update or stack update if the wait was unsuccessful\nexit 0\n"}, "wait-port-and-run.sh": {"mode": "0755", "content": "#!/usr/bin/bash\nset -eu\n\nHOST=$1\nPORT=$2\n\necho \"$(date -u): Checking whether we can bind to ${HOST}:${PORT}\"\nwhile (ss -Htnl src \"${HOST}\" \"sport = :${PORT}\" | grep -wq \"${PORT}\"); do\n    echo \"$(date -u): ${HOST}:${PORT} still in use, waiting...\";\n    sleep 10;\ndone\n\nshift 2\nCOMMAND=\"$*\"\nif [ -z \"${COMMAND}\" ]; then\n    COMMAND=\"true\"\nfi\nexec $COMMAND\n"}, "pacemaker_resource_lock.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nMAX_RETRIES=10\nCIB_ENOTFOUND=105\n\nusage() {\n   echo \"Set a global property in the cluster with a validity timestamp.\"\n   echo \"Usage:\"\n   echo \"   $0 --acquire <lock_name> <lock_owner> <lock_ttl_in_seconds>\"\n   echo \"   $0 --release <lock_name> <lock_owner>\"\n   echo\n}\n\nlog() {\n    echo \"$(date -u): $1\" 1>&2\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\nlock_create() {\n    local name=$1\n    local data=$2\n    # cibadmin won't overwrite a key if someone else succeeded to create it concurrently\n    cibadmin --sync-call --scope crm_config --create --xml-text \"<cluster_property_set id='${name}'><nvpair id='${name}-pair' name='${name}' value='${data}'/></cluster_property_set>\" &>/dev/null\n    return $?\n}\n\nlock_update() {\n    local name=$1\n    local expected_data=$2\n    local new_data=$3\n    # we only update the lock we expect to see, so we can't update someone else's lock\n    cibadmin --sync-call --scope crm_config --modify --xpath \"//cluster_property_set/nvpair[@name='${name}' and @value='${expected_data}']/..\" --xml-text \"<nvpair id='${name}-pair' name='${name}' value='${new_data}'/>\" &>/dev/null\n    return $?\n}\n\nlock_delete() {\n    local name=$1\n    local expected_data=$2\n    # we only delete the lock we expect to see, so we can't delete someone else's lock\n    cibadmin --sync-call --scope crm_config --delete --xpath \"//cluster_property_set/nvpair[@name='${name}' and @value='${expected_data}']/..\" &>/dev/null\n    return $?\n}\n\nlock_get() {\n    local lockname=$1\n    local res\n    local rc\n    res=$(cibadmin --query --scope crm_config --xpath \"//cluster_property_set/nvpair[@name='$lockname']\" 2>/dev/null)\n    rc=$?\n    if [ $rc -eq 0 ]; then\n        echo \"$res\" | sed -n 's/.*value=\"\\([^\"]*\\)\".*/\\1/p'\n    fi\n    return $rc\n}\n\nlock_owner() {\n    local lock=$1\n    echo \"$lock\" | cut -d':' -f1\n}\n\nlock_has_expired() {\n    local lock=$1\n    local expiry=$(echo \"$lock\" | cut -d':' -f2)\n    local now=$(date +%s)\n    test $now -ge $expiry\n}\n\n\n# Perform a lock action and restart if the CIB has been modified before\n# committing the lock action\ntry_action() {\n    local fun=$1\n    local lock=$2\n    local requester=$3\n    local args=${4:-}\n    local tries=$MAX_RETRIES\n    local rc=1\n    if [ \"$fun\" = \"lock_acquire\" ] || [ \"$fun\" = \"lock_release\" ]; then\n        log \"Try running $fun\"\n    else\n        return 2\n    fi\n    while [ $rc -ne 0 ]; do\n        $fun $lock $requester $args\n        rc=$?\n        if [ $rc -eq 0 ]; then\n            log \"Operation $1 succeeded\"\n            return 0\n        elif [ $rc -eq 3 ]; then\n            # rc == 3 -> CIB changed before push\n            if [ $tries -eq 0 ]; then\n                log \"Failed to commit after $MAX_RETRIES retries. Bailing out.\"\n                return 2\n            else\n                log \"Failed to commit. Retrying operation.\"\n                tries=$(($tries - 1))\n            fi\n        elif [ $rc -eq 2 ]; then\n            # rc == 2 -> unrecoverable cib error (e.g. pacemaker down)\n            log \"Unexpected failure. Bailing out\"\n            return $rc\n        else\n            # rc == 1 -> lock error (not owner, lock doesn't exists)\n            return $rc\n        fi\n    done\n}\n\n# The lock mechanism uses cibadmin's atomic creation so cluster-wide\n# state coherency is guaranteed by pacemaker\nlock_acquire() {\n    local lockname=$1\n    local requester=$2\n    local ttl=$3\n    local rc\n    local lock\n    local expiry\n    local owner\n\n    log \"Check whether the lock is already held in the CIB\"\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        log \"Could not retrieve info from the CIB\"\n        return 2\n    fi\n\n    if [ -n \"$lock\" ]; then\n        lock_has_expired $lock\n        rc=$?\n        if [ $rc -eq 0 ]; then\n            log \"Lock has expired, now available for being held\"\n        else\n            # lock is still held. check whether we're the owner\n            owner=$(lock_owner $lock)\n            if [ \"$owner\" = \"$requester\" ];then\n                log \"Requester already owns the lock, acquiring attempt will just reconfigure the TTL\"\n            else\n                log \"Lock is held by someone else ($owner)\"\n                return 1\n            fi\n        fi\n    else\n        log \"Lock is not held yet\"\n    fi\n\n    # prepare the lock info\n    expiry=$(($(date +%s) + $ttl))\n\n    if [ -n \"$lock\" ]; then\n        log \"Attempting to update the lock\"\n        lock_update $lockname \"$lock\" \"$requester:$expiry\"\n        rc=$?\n    else\n        log \"Attempting to acquire the lock\"\n        lock_create $lockname \"$requester:$expiry\"\n        rc=$?\n    fi\n\n    if [ $rc -eq 0 ]; then\n        log \"Lock '$lockname' acquired by '$requester', valid until $(date -d @$expiry)\"\n        return 0\n    else\n        log \"CIB changed, lock cannot be acquired\"\n        return 3\n    fi\n}\n\n\n# The lock mechanism uses the CIB's num_updates tag to implement\n# a conditional store. Cluster-wide locking is guaranteed by pacemaker\nlock_release() {\n    local lockname=$1\n    local requester=$2\n    local rc\n    local lock\n    local owner\n\n    log \"Check whether the lock is already held in the CIB\"\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        log \"Could not retrieve info from the CIB\"\n        return 2\n    fi\n\n    if [ -z \"$lock\" ]; then\n        log \"Lock doesn't exist. Nothing to release\"\n        return 0\n    else\n        log \"Lock exists, check whether we're the owner\"\n        owner=$(lock_owner $lock)\n        if [ \"$owner\" != \"$requester\" ];then\n            log \"Lock is held by someone else ($owner), will not unlock\"\n            return 1\n        fi\n    fi\n\n    lock_delete $lockname \"$lock\"\n    rc=$?\n\n    if [ $rc -eq 0 ]; then\n        log \"Lock '$lockname' released by '$requester'\"\n        return 0\n    else\n        log \"CIB deletion error, lock cannot be released\"\n        return 3\n    fi\n}\n\n\n# Retrieve the owner of a lock from the CIB\n# this is a read-only operation, so no need to log debug info\nlock_get_owner() {\n    local lockname=$1\n    local rc\n    local lock\n    local owner\n\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        return 2\n    fi\n\n    if [ -z \"$lock\" ]; then\n        return 1\n    else\n        lock_owner $lock\n        return 0\n    fi\n}\n\n\nACTION=$1\nLOCKNAME=$2\nREQUESTER=$3\nTTL=${4:-60}\n\nif [ -z \"$ACTION\" ]; then\n    error \"Action must be specified\"\nfi\n\nif [ $ACTION != \"--help\" ]; then\n    if [ -z \"$LOCKNAME\" ]; then\n        error \"You must specific a lock name\"\n    fi\n    if [ $ACTION != \"--owner\" ] && [ $ACTION != \"-o\" ]; then\n        if [ -z \"$REQUESTER\" ]; then\n            error \"You must specific a lock requester\"\n        fi\n    fi\nfi\n\ncase $ACTION in\n    --help) usage; exit 0;;\n    --acquire|-a) try_action lock_acquire $LOCKNAME $REQUESTER $TTL;;\n    --release|-r) try_action lock_release $LOCKNAME $REQUESTER;;\n    --acquire-once|-A) lock_acquire $LOCKNAME $REQUESTER $TTL;;\n    --owner|-o) lock_get_owner $LOCKNAME;;\n    *) error \"Invalid action\";;\nesac\nexit $?\n"}, "pacemaker_mutex_restart_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# pacemaker_mutex_restart_bundle.sh --lock mysql galera galera-bundle Master _\n# pacemaker_mutex_restart_bundle.sh --lock ovn_dbs ovndb_servers ovn-dbs-bundle Slave Master\n\nset -u\n\nusage() {\n    echo \"Restart a clustered resource in a coordinated way across the cluster\"\n    echo \"Usage:\"\n    echo \"   $0 --lock <tripleo-service> <pcmk-resource> <pcmk-bundle> <target-state-local> <target-state-cluster>\"\n    echo\n}\n\nlog() {\n    echo \"$(date -u): $1\"\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\npacemaker_supports_promoted() {\n    # The Promoted token is only matched in recent pacemaker versions\n    grep -wq \"<value>Promoted</value>\" /usr/share/pacemaker/resources-*.rng\n}\n\nACTION=$1\ncase $ACTION in\n    --help) usage; exit 0;;\n    --lock) ;;\n    *) error \"Unknown action '$ACTION'\";;\nesac\n\nTRIPLEO_SERVICE=$2\nLOCK_NAME=${TRIPLEO_SERVICE}-restart-lock\nLOCK_OWNER=$(crm_node -n 2>/dev/null)\nrc=$?\nif [ $rc -ne 0 ]; then\n    if [ $rc -eq 102 ]; then\n        log \"Cluster is not running locally, no need to restart resource $TRIPLEO_SERVICE\"\n        exit 0\n    else\n        error \"Unexpected error while connecting to the cluster (rc: $rc), bailing out\"\n    fi\nfi\n\nRESOURCE_NAME=$3\nBUNDLE_NAME=$4\nWAIT_TARGET_LOCAL=$5\nWAIT_TARGET_ANYWHERE=${6:-_}\n\nif pacemaker_supports_promoted; then\n    WAIT_TARGET_LOCAL=$(echo \"$5\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    WAIT_TARGET_ANYWHERE=$(echo \"${6:-_}\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    promoted_role=\"Promoted\"\nelse\n    promoted_role=\"Master\"\nfi\n\n# The lock TTL should accomodate for the resource start/promote timeout\nif [ \"$RESOURCE_NAME\" != \"$BUNDLE_NAME\" ]; then\n    if [ \"$WAIT_TARGET_LOCAL\" = \"$promoted_role\" ] || [ \"$WAIT_TARGET_ANYWHERE\" = \"$promoted_role\" ]; then\n        rsc_op=\"promote\"\n    else\n        rsc_op=\"start\"\n    fi\n    # <op id=\"galera-promote-interval-0s\" interval=\"0s\" name=\"promote\" on-fail=\"block\" timeout=\"300s\"/>\n    PCMK_TTL=$(cibadmin -Q | xmllint -xpath \"string(//primitive[@id='${RESOURCE_NAME}']/operations/op[@name='${rsc_op}']/@timeout)\" - | sed 's/s$//')\n    LOCK_TTL=$((PCMK_TTL + 30))\nelse\n    # The podman RA's default start timeout\n    LOCK_TTL=90\nfi\n\nlog \"Acquire a ${LOCK_TTL}s restart lock for service $TRIPLEO_SERVICE before restarting it\"\n# Loop until we hold the lock. The lock has a TTL, so we're guaranteed to get it eventually\nrc=1\nwhile [ $rc -ne 0 ]; do\n    /var/lib/container-config-scripts/pacemaker_resource_lock.sh --acquire $LOCK_NAME $LOCK_OWNER $LOCK_TTL\n    rc=$?\n    if [ $rc != 0 ]; then\n        if [ $rc -gt 1 ]; then\n            error \"Could not acquire lock due to unrecoverable error (rc: $rc), bailing out\"\n        else\n            log \"Could not acquire lock, retrying\"\n            sleep 10\n        fi\n    fi\ndone\n\nlog \"Restart the service $TRIPLEO_SERVICE locally\"\n# Reuse the local restart script in t-h-t (driven by env var TRIPLEO_MINOR_UPDATE)\nTRIPLEO_MINOR_UPDATE=true /var/lib/container-config-scripts/pacemaker_restart_bundle.sh $TRIPLEO_SERVICE $RESOURCE_NAME $BUNDLE_NAME $WAIT_TARGET_LOCAL $WAIT_TARGET_ANYWHERE\n\n# If we reached this point, always try to release the lock\nlog \"Release the restart lock for service $TRIPLEO_SERVICE\"\n/var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $LOCK_NAME $LOCK_OWNER\nrc=$?\nif [ $rc -ne 0 ] && [ $rc -ne 1 ]; then\n    error \"Could not release held lock (rc: $rc)\"\nfi\n"}, "pacemaker_mutex_shutdown.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# pacemaker_mutex_shutdown.sh --acquire\n# pacemaker_mutex_shutdown.sh --release\n\nset -u\n\nusage() {\n    echo \"Shutdown a cluster node in a coordinated way across the cluster\"\n    echo \"Usage:\"\n    echo \"   $0 --acquire # prevent other node from shutting down until we hold the lock\"\n    echo \"   $0 --release # release the lock, other node can compete for the shutdown lock\"\n    echo\n}\n\nlog() {\n    echo \"$(date -u): $1\"\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\n# Loop until we hold the lock. The lock has a TTL, so we're guaranteed to get it eventually\nshutdown_lock_acquire() {\n    local lockname=$1\n    local requester=$2\n    local ttl=$3\n    local rc=1\n    local current_owner\n    local owner_stopped\n    local owner_rc\n\n    log \"Acquiring the shutdown lock\"\n    while [ $rc -ne 0 ]; do\n        /var/lib/container-config-scripts/pacemaker_resource_lock.sh --acquire-once $lockname $requester $ttl\n        rc=$?\n        if [ $rc -ne 0 ]; then\n            if [ $rc -eq 2 ]; then\n                error \"Could not acquire the shutdown lock due to unrecoverable error (rc: $rc), bailing out\"\n            else\n                # The lock is held by another node.\n                current_owner=$(/var/lib/container-config-scripts/pacemaker_resource_lock.sh --owner $lockname)\n                owner_rc=$?\n                if [ $owner_rc -eq 2 ]; then\n                    error \"Could not get the shutdown lock owner due to unrecoverable error (rc: $owner_rc), bailing out\"\n                fi\n                if [ $owner_rc -eq 0 ]; then\n                    # If the owner is marked as offline, that means it has shutdown and\n                    # we can clean the lock preemptively and try to acquire it.\n                    owner_stopped=$(crm_mon -1X | xmllint --xpath 'count(//nodes/node[@name=\"'${current_owner}'\" and @online=\"false\" and @unclean=\"false\"])' -)\n                    if [ \"${owner_stopped}\" = \"1\" ]; then\n                        log \"Shutdown lock held by stopped node '${current_owner}', lock can be released\"\n                        /var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $lockname $current_owner\n                        continue\n                    fi\n                fi\n                log \"Shutdown lock held by another node (rc: $rc), retrying\"\n                sleep 10\n            fi\n        fi\n    done\n    log \"Shutdown lock acquired\"\n    return 0\n}\n\n\n# Release the lock if we still own it. Not owning it anymore is not fatal\nshutdown_lock_release() {\n    local lockname=$1\n    local requester=$2\n    local rc\n\n    log \"Releasing the shutdown lock\"\n    /var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $lockname $requester\n    rc=$?\n    if [ $rc -ne 0 ]; then\n        if [ $rc -gt 1 ]; then\n            error \"Could not release the shutdown lock due to unrecoverable error (rc: $rc), bailing out\"\n        else\n            log \"Shutdown lock no longer held, nothing to do\"\n        fi\n    else\n        log \"Shutdown lock released\"\n    fi\n    return 0\n}\n\n\nACTION=$1\nif [ -z \"$ACTION\" ]; then\n    error \"Action must be specified\"\nfi\n\nLOCK_NAME=tripleo-shutdown-lock\nLOCK_OWNER=$(crm_node -n 2>/dev/null)\nrc=$?\nif [ $rc -ne 0 ]; then\n    if [ $rc -eq 102 ]; then\n        log \"Cluster is not running locally, no need to aquire the shutdown lock\"\n        exit 0\n    else\n        error \"Unexpected error while connecting to the cluster (rc: $rc), bailing out\"\n    fi\nfi\n\n# We start with a very high TTL, that long enough to accomodate a cluster stop.\n# As soon as the node will get offline, the other competing node will be entitled\n# to steal the lock, so they should never wait that long in practice.\nLOCK_TTL=600\n\n\ncase $ACTION in\n    --help) usage; exit 0;;\n    --acquire|-a) shutdown_lock_acquire ${LOCK_NAME} ${LOCK_OWNER} ${LOCK_TTL};;\n    --release|-r) shutdown_lock_release ${LOCK_NAME} ${LOCK_OWNER};;\n    *) error \"Invalid action\";;\nesac\nexit $?\n"}}, "tuple:('role_data', 'service_name')": "ovn_metadata", "tuple:('role_data', 'config_settings')": {"neutron::notification_driver": ["messagingv2"], "neutron::core_plugin": "ml2", "neutron::service_plugins": ["qos", "ovn-router", "trunk", "segments", "port_forwarding", "log"], "neutron::report_interval": 300, "neutron::logging::debug": true, "neutron::purge_config": false, "neutron::allow_overlapping_ips": true, "neutron::dhcp_agent_notification": true, "neutron::dns_domain": "localdomain", "neutron::rabbit_heartbeat_timeout_threshold": 60, "neutron::host": "%{hiera('fqdn_canonical')}", "neutron::db::database_db_max_retries": -1, "neutron::db::database_max_retries": -1, "neutron::db::sync::db_sync_timeout": 900, "neutron::global_physnet_mtu": 1500, "neutron::db::sync::extra_params": "", "neutron::vlan_transparent": false, "neutron::rabbit_heartbeat_in_pthread": false, "tripleo::profile::base::neutron::ovn_metadata_agent_wrappers::enable_haproxy_wrapper": true, "tripleo::profile::base::neutron::ovn_metadata_agent_wrappers::haproxy_process_wrapper": "/var/lib/neutron/ovn_metadata_haproxy_wrapper", "tripleo::profile::base::neutron::ovn_metadata_agent_wrappers::haproxy_image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "tripleo::profile::base::neutron::ovn_metadata_agent_wrappers::debug": true, "tripleo::profile::base::neutron::container_cli": "podman", "neutron::agents::ovn_metadata::shared_secret": "GPXe1MBnHTH4XdbuK33lTKitc", "neutron::agents::ovn_metadata::auth_password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "neutron::agents::ovn_metadata::auth_url": "http://172.17.0.2:5000", "neutron::agents::ovn_metadata::auth_tenant": "service", "neutron::agents::ovn_metadata::metadata_host": "172.17.0.2", "neutron::agents::ovn_metadata::ovsdb_connection_timeout": 180, "neutron::agents::ovn_metadata::ovsdb_probe_interval": 60000, "neutron::agents::ovn_metadata::hwol_qos_enabled": false, "ovn::northbound::port": 6641, "ovn::southbound::port": 6642, "neutron::agents::ovn_metadata::debug": true, "neutron::agents::ovn_metadata::metadata_protocol": "http", "neutron::agents::ovn_metadata::metadata_workers": "1"}, "role_data": {"service_name": "ovn_metadata", "monitoring_subscription": "overcloud-ovn-metadata", "config_settings": {"neutron::notification_driver": ["messagingv2"], "neutron::core_plugin": "ml2", "neutron::service_plugins": ["qos", "ovn-router", "trunk", "segments", "port_forwarding", "log"], "neutron::report_interval": 300, "neutron::logging::debug": true, "neutron::purge_config": false, "neutron::allow_overlapping_ips": true, "neutron::dhcp_agent_notification": true, "neutron::dns_domain": "localdomain", "neutron::rabbit_heartbeat_timeout_threshold": 60, "neutron::host": "%{hiera('fqdn_canonical')}", "neutron::db::database_db_max_retries": -1, "neutron::db::database_max_retries": -1, "neutron::db::sync::db_sync_timeout": 900, "neutron::global_physnet_mtu": 1500, "neutron::db::sync::extra_params": "", "neutron::vlan_transparent": false, "neutron::rabbit_heartbeat_in_pthread": false, "tripleo::profile::base::neutron::ovn_metadata_agent_wrappers::enable_haproxy_wrapper": true, "tripleo::profile::base::neutron::ovn_metadata_agent_wrappers::haproxy_process_wrapper": "/var/lib/neutron/ovn_metadata_haproxy_wrapper", "tripleo::profile::base::neutron::ovn_metadata_agent_wrappers::haproxy_image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "tripleo::profile::base::neutron::ovn_metadata_agent_wrappers::debug": true, "tripleo::profile::base::neutron::container_cli": "podman", "neutron::agents::ovn_metadata::shared_secret": "GPXe1MBnHTH4XdbuK33lTKitc", "neutron::agents::ovn_metadata::auth_password": "0IYW4rnlTS5pcYnzyKnFU4hPG", "neutron::agents::ovn_metadata::auth_url": "http://172.17.0.2:5000", "neutron::agents::ovn_metadata::auth_tenant": "service", "neutron::agents::ovn_metadata::metadata_host": "172.17.0.2", "neutron::agents::ovn_metadata::ovsdb_connection_timeout": 180, "neutron::agents::ovn_metadata::ovsdb_probe_interval": 60000, "neutron::agents::ovn_metadata::hwol_qos_enabled": false, "ovn::northbound::port": 6641, "ovn::southbound::port": 6642, "neutron::agents::ovn_metadata::debug": true, "neutron::agents::ovn_metadata::metadata_protocol": "http", "neutron::agents::ovn_metadata::metadata_workers": "1"}, "puppet_config": {"puppet_tags": "neutron_config,ovn_metadata_agent_config", "config_volume": "neutron", "step_config": "include tripleo::profile::base::neutron::ovn_metadata\n", "config_image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-server:17.1", "volumes": ["/lib/modules:/lib/modules:ro", "/run/openvswitch:/run/openvswitch:shared,z"]}, "kolla_config": {"/var/lib/kolla/config_files/ovn_metadata_agent.json": {"command": "/usr/bin/networking-ovn-metadata-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/networking-ovn/networking-ovn-metadata-agent.ini --log-file=/var/log/neutron/ovn-metadata-agent.log", "config_files": [{"source": "/var/lib/kolla/config_files/src/*", "dest": "/", "merge": true, "preserve_properties": true}], "permissions": [{"path": "/var/log/neutron", "owner": "neutron:neutron", "recurse": true}, {"path": "/var/lib/neutron", "owner": "neutron:neutron", "recurse": true}, {"path": "/etc/pki/tls/certs/ovn_metadata.crt", "owner": "neutron:neutron", "optional": true, "perm": "0644"}, {"path": "/etc/pki/tls/private/ovn_metadata.key", "owner": "neutron:neutron", "optional": true, "perm": "0644"}]}}, "container_config_scripts": {"container_puppet_apply.sh": {"mode": "0700", "content": "#!/bin/bash\nset -eux\nSTEP=$1\nTAGS=$2\nCONFIG=$3\nEXTRA_ARGS=${4:-''}\nif [ -d /tmp/puppet-etc ]; then\n  # ignore copy failures as these may be the same file depending on docker mounts\n  cp -a /tmp/puppet-etc/* /etc/puppet || true\nfi\necho \"{\\\"step\\\": ${STEP}}\" > /etc/puppet/hieradata/docker_puppet.json\n# $::deployment_type in puppet-tripleo\nexport FACTER_deployment_type=containers\nset +e\npuppet apply $EXTRA_ARGS \\\n    --verbose \\\n    --detailed-exitcodes \\\n    --summarize \\\n    --color=false \\\n    --modulepath /etc/puppet/modules:/opt/stack/puppet-modules:/usr/share/openstack-puppet/modules \\\n    --tags $TAGS \\\n    -e \"noop_resource('package'); ${CONFIG}\"\nrc=$?\nset -e\nset +ux\nif [ $rc -eq 2 -o $rc -eq 0 ]; then\n    exit 0\nfi\nexit $rc\n"}, "pyshim.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n# Copyright 2018 Red Hat Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n#\n# Usage: pyshim.sh <script and/or arguments>\n#\n# Unfortunately THT doesn't know which version of python might be in a\n# container so we need this script to be able to try python3 or python2\n# depending on availability.  Since this is a temporary shim until we've\n# fully cut over to python3, we check for the existence of python3 first\n# before falling back to python2. This will help in the transition from\n# python2 based containers to python3.\n\nshow_usage() {\n    echo \"Usage: pyshim.sh <script and/or arguments>\"\n}\n\nif [ $# -lt 1 ]\nthen\n    show_usage\n    exit 1\nfi\n\nset -x\nif command -v python3 >/dev/null; then\n    python3 \"$@\"\nelif command -v python2 >/dev/null; then\n    python2 \"$@\"\nelif command -v python >/dev/null; then\n    python \"$@\"\nelse\n    echo \"ERROR: python is not available!\"\n    exit 1\nfi\n"}, "pacemaker_restart_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nset -u\n\n# ./pacemaker_restart_bundle.sh mysql galera galera-bundle Master _\n# ./pacemaker_restart_bundle.sh redis redis redis-bundle Slave Master\n# ./pacemaker_restart_bundle.sh ovn_dbs ovndb_servers ovn-dbs-bundle Slave Master\nRESTART_SCRIPTS_DIR=$(dirname $0)\nTRIPLEO_SERVICE=$1\nRESOURCE_NAME=$2\nBUNDLE_NAME=$3\nWAIT_TARGET_LOCAL=$4\nWAIT_TARGET_ANYWHERE=${5:-_}\nTRIPLEO_MINOR_UPDATE=\"${TRIPLEO_MINOR_UPDATE:-false}\"\nTRIPLEO_HA_WRAPPER_RESOURCE_EXISTS=\"${TRIPLEO_HA_WRAPPER_RESOURCE_EXISTS:-false}\"\n\nbundle_can_be_restarted() {\n    local bundle=$1\n    # As long as the resource bundle is managed by pacemaker and is\n    # not meant to stay stopped, no matter the state of any inner\n    # pcmk_remote or ocf resource, we should restart it to give it a\n    # chance to read the new config.\n    [ \"$(crm_resource --meta -r $1 -g is-managed 2>/dev/null)\" != \"false\" ] && \\\n    [ \"$(crm_resource --meta -r $1 -g target-role 2>/dev/null)\" != \"Stopped\" ]\n}\n\nlog() {\n    local msg=$1\n    logger -t pcmkrestart \"$1\"\n}\n\nHOSTNAME=$(/bin/hostname -s)\nif [ x\"${TRIPLEO_MINOR_UPDATE,,}\" != x\"true\" ]; then\n    if [ x\"${TRIPLEO_HA_WRAPPER_RESOURCE_EXISTS,,}\" = x\"false\" ]; then\n        # Do not restart during initial deployment, as the resource\n        # has just been created.\n        SERVICE_NODEID=$(/bin/hiera -c /etc/puppet/hiera.yaml \"${TRIPLEO_SERVICE}_short_bootstrap_node_name\")\n        if [[ \"${HOSTNAME,,}\" == \"${SERVICE_NODEID,,}\" ]]; then\n            log \"Initial deployment, skipping the restart of ${BUNDLE_NAME}\"\n\tfi\n        exit 0\n    else\n        # During a stack update, this script is called in parallel on\n        # every node the resource runs on, after the service's configs\n        # have been updated on all nodes. So we need to run pcs only\n        # once (e.g. on the service's boostrap node).\n        if bundle_can_be_restarted ${BUNDLE_NAME}; then\n            SERVICE_NODEID=$(/bin/hiera -c /etc/puppet/hiera.yaml \"${TRIPLEO_SERVICE}_short_bootstrap_node_name\")\n            if [[ \"${HOSTNAME,,}\" == \"${SERVICE_NODEID,,}\" ]]; then\n                replicas_running=$(crm_resource -Q -r $BUNDLE_NAME --locate 2>&1 | wc -l)\n                if [ \"$replicas_running\" != \"0\" ]; then\n                    log \"Restarting ${BUNDLE_NAME} globally. Stopping:\"\n                    /sbin/pcs resource disable --wait=600 $BUNDLE_NAME\n                    log \"Restarting ${BUNDLE_NAME} globally. Starting:\"\n                    /sbin/pcs resource enable --wait=600 $BUNDLE_NAME\n                else\n                    log \"${BUNDLE_NAME} is not running anywhere,\" \\\n                         \"cleaning up to restart it globally if necessary\"\n                    /sbin/pcs resource cleanup $BUNDLE_NAME\n                fi\n            else\n                log \"Skipping global restart of ${BUNDLE_NAME} on ${HOSTNAME} it will be restarted by node ${SERVICE_NODEID}\"\n            fi\n\n        else\n            log \"No global restart needed for ${BUNDLE_NAME}.\"\n        fi\n    fi\nelse\n    # During a minor update workflow however, a host gets fully\n    # updated before updating the next one. So unlike stack\n    # update, at the time this script is called, the service's\n    # configs aren't updated on all nodes yet. So only restart the\n    # resource locally, where it's guaranteed that the config is\n    # up to date.\n    HOST=$(facter hostname)\n\n    if bundle_can_be_restarted ${BUNDLE_NAME}; then\n\t# if the resource is running locally, restart it\n\tif crm_resource -r $BUNDLE_NAME --locate 2>&1 | grep -w -q \"${HOST}\"; then\n            log \"Restarting ${BUNDLE_NAME} locally on '${HOST}'\"\n            /sbin/pcs resource restart $BUNDLE_NAME \"${HOST}\"\n\n\telse\n\t    # At this point, if no resource is running locally, it's\n\t    # either because a) it has failed previously, or b) because\n\t    # it's an A/P resource running elsewhere.\n\t    # By cleaning up resource, we ensure that a) it will try to\n\t    # restart, or b) it won't do anything if the resource is\n\t    # already running elsewhere.\n            log \"${BUNDLE_NAME} is currently not running on '${HOST}',\" \\\n                 \"cleaning up its state to restart it if necessary\"\n            /sbin/pcs resource cleanup $BUNDLE_NAME node=\"${HOST}\"\n\tfi\n\n\t# Wait until the resource is in the expected target state\n\t$RESTART_SCRIPTS_DIR/pacemaker_wait_bundle.sh \\\n            $RESOURCE_NAME $BUNDLE_NAME \\\n            \"$WAIT_TARGET_LOCAL\" \"$WAIT_TARGET_ANYWHERE\" \\\n\t    \"${HOST}\" 600\n    else\n        log \"No restart needed for ${BUNDLE_NAME}.\"\n    fi\nfi\n"}, "pacemaker_wait_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# ----\n# Wait for an OCF resource or a bundle to be restarted\n# ----\n# e.g.:\n# M/S OCF:      $0 galera galera-bundle Master\n# clone OCF:    $0 rabbitmq rabbitmq-bundle Started\n# A/P M/S OCF:  $0 redis redis-bundle Slave Master\n# A/P bundle:   $0 openstack-cinder-volume openstack-cinder-volume _ Started\n# clone bundle: $0 haproxy-bundle haproxy-bundle Started\n\n# design note 1:\n#  - this script is called during a minor update; it is called\n#    once per node that hosts a service replica.\n#  - the purpose of this script is to ensure that restarting the\n#    service replica locally won't disrupt the service availability\n#    for the end user. To reach that goal, the script waits until the\n#    service is restarted locally or globallu and reaches a given\n#    target state (i.e. Started, Slave or Master).\n# design note 2:\n#   - we don't want to track restart error: our only job is to ensure\n#     service restart synchronization, not service health.\n#   - In particular, we don't want to error out in case the resource\n#     cannot be restarted locally, because that would make the minor\n#     update fail, even if potentially other replicas still provide\n#     the service.\n# design note 3:\n#   - we can bail out early if we determine that the resource can't\n#     be restarted automatically by pacemaker (e.g. its \"blocked\",\n#     unmanaged or disabled).\n\nlog() {\n    local msg=$1\n    echo \"$(date -u): $1\"\n}\n\nusage() {\n    echo 2>&1 \"Usage: $0 NAME BUNDLE_NAME ROLE_LOCAL [ROLE_ANYWHERE] [HOST] [TIMEOUT]\"\n    exit 1\n}\n\npacemaker_supports_promoted() {\n    # The Promoted token is only matched in recent pacemaker versions\n    grep -wq \"<value>Promoted</value>\" /usr/share/pacemaker/resources-*.rng\n}\n\n#\n# Utility functions to detect stuck resources\n#\n\nbundle_failures_locally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    local replica_name\n    for i in $(seq 0 $last); do\n\treplica_name=${BUNDLE_NAME}-${engine}-${i}\n\tcrm_failcount -q -G -r $replica_name -N $HOST\n    done\n}\n\nbundle_failures_globally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    for i in $(seq 0 $last); do\n\tcrm_failcount -q -G -r ${BUNDLE_NAME}-${engine}-${i}\n    done\n}\n\nbundle_running_globally() {\n    local engine=$BUNDLE_CONTAINER_ENGINE\n    # return the number of running bundles replica, i.e. the number of\n    # docker/podman resource replicas currently running in the cluster\n    crm_mon --as-xml | xmllint --xpath \"count(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource[@resource_agent='${OCF}:heartbeat:${engine}']/node)\" -\n}\n\nocf_failures_globally() {\n    local replicas=$BUNDLE_REPLICAS\n    local last=$(($replicas - 1))\n    local bundle_node\n    for i in $(seq 0 $last); do\n\tbundle_node=${BUNDLE_NAME}-${i}\n\tcrm_failcount -q -G -r $NAME -N $bundle_node\n    done\n}\n\ndid_resource_failed_locally() {\n    local failures\n    local running\n    local remotehost\n    if [ \"${NAME}\" != \"${BUNDLE_NAME}\" ]; then\n\t# if we're dealing with an ocf resource, it is running on a\n\t# pacemaker_remote rather that on the real host, and the\n\t# failcounts are thus associated to the pcmk remote. Replace\n\t# the host's name with the pcmk remote's name.\n        remotehost=$(crm_mon --as-xml | xmllint --xpath \"string(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource/node[@name='${HOST}']/../../resource[@resource_agent='${OCF}:pacemaker:remote']/@id)\" -)\n\tif [ -n \"${remotehost}\" ]; then\n\t    crm_failcount -q -G -r $NAME -N $remotehost | grep -q -w INFINITY\n\t    return $?\n\tfi\n\t# If no pcmk remote is currently running, the failcount from\n\t# the ocf resource is useless, compute the failcount from the\n\t# bundle case instead (computed below).\n    fi\n\n    # for bundles, pacemaker can run any bundle replica locally\n    # (e.g. galera-bundle-docker-{0,1,2}), and a failure happens when\n    # there are no more replica to try.\n    # That is, when _at least_ one replica failed locally, and all the\n    # others either failed or are currently running elsewhere.\n    failures=$(bundle_failures_locally $HOST | grep -c -w INFINITY)\n    running=$(bundle_running_globally)\n    test $failures -gt 0 && \\\n    test $(( $failures + $running )) -ge $BUNDLE_REPLICAS\n}\n\ndid_resource_failed_globally() {\n    local remotecount\n    local failures\n    if [ \"${NAME}\" != \"${BUNDLE_NAME}\" ]; then\n\t# we check the state of an ocf resource only if the\n\t# pcmkremotes are started\n        remotecount=$(crm_mon --as-xml | xmllint --xpath \"count(//resources/bundle[@id='${BUNDLE_NAME}']/replica/resource[@resource_agent='${OCF}:pacemaker:remote']/node)\" -)\n\tif [ \"${remotecount}\" = \"0\" ]; then\n\t    # no pcmkremote is running, so check the bundle state\n\t    # instead of checking the ocf resource\n\t    # bundle failed if all ${BUNDLE_REPLICAS} replicas failed\n\t    failures=$(bundle_failures_globally | grep -c -w INFINITY)\n\t    test $failures -eq $BUNDLE_REPLICAS\n\telse\n\t    # ocf resource failed if it failed to start on\n\t    # all $BUNDLE_REPLICAS bundle nodes\n\t    failures=$(ocf_failures_globally | grep -c -w INFINITY)\n\t    test $failures -eq $BUNDLE_REPLICAS\n\tfi\n    else\n\t# bundle failed if all ${BUNDLE_REPLICAS} replicas failed\n\tfailures=$(bundle_failures_globally | grep -c -w INFINITY)\n\ttest $failures -eq $BUNDLE_REPLICAS\n    fi\n}\n\n\n# Input validation\n#\n\nNAME=$1\nif [ -z \"${NAME}\" ]; then\n    echo 2>&1 \"Error: argument NAME must not be empty\"\n    exit 1\nfi\n\nBUNDLE_NAME=$2\nif [ -z \"${BUNDLE_NAME}\" ]; then\n    echo 2>&1 \"Error: argument BUNDLE_NAME must not be empty\"\n    exit 1\nfi\n\nROLE_LOCAL=$3\nif [ \"${ROLE_LOCAL}\" = \"_\" ]; then\n    ROLE_LOCAL=\"\"\nfi\n\nROLE_ANYWHERE=$4\nif [ \"${ROLE_ANYWHERE}\" = \"_\" ]; then\n    ROLE_ANYWHERE=\"\"\nfi\n\nif [ -z \"${ROLE_LOCAL}\" ]; then\n    if [ -z \"${ROLE_ANYWHERE}\" ]; then\n        echo 2>&1 \"Error: either ROLE_LOCAL or ROLE_ANYWHERE must be non empty\"\n        exit 1\n    fi\nelse\n    if !(echo \"${ROLE_LOCAL}\" | grep -q -x -E \"(Started|Slave|Master|Unpromoted|Promoted)\"); then\n        echo 2>&1 \"Error: argument ROLE_LOCAL must be either 'Started' 'Slave' 'Master' 'Unpromoted' or 'Promoted'\"\n        exit 1\n    fi\nfi\n\nif [ -n \"${ROLE_ANYWHERE}\" ] && !(echo \"${ROLE_ANYWHERE}\" | grep -q -x -E \"(Started|Slave|Master|Unpromoted|Promoted)\"); then\n    echo 2>&1 \"Error: argument ROLE_ANYWHERE must be either 'Started' 'Slave' 'Master' 'Unpromoted' or 'Promoted'\"\n    exit 1\nfi\n\n# Ensure compatibility with pacemaker 2.1\nif pacemaker_supports_promoted; then\n    ROLE_LOCAL=$(echo \"$ROLE_LOCAL\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    ROLE_ANYWHERE=$(echo \"$ROLE_ANYWHERE\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    OCF=\"ocf\"\nelse\n    OCF=\"ocf:\"\nfi\n\nHOST=${5:-$(facter hostname)}\nTIMEOUT=${6:-600}\n\n\n# Configure the search\n# ----\n# Note: we can't use crm_resource in all searches because we can't\n# easily extract the host the OCF resources run on (crm_resource\n# returns the pcmk-remote nodes rather than the hosts)\n# So instead, we implement various searches with XPath directly.\n\nif [ \"${BUNDLE_NAME}\" != \"${NAME}\" ]; then\n# ocf resource\nlocal_resource_xpath=\"//bundle/replica/resource[@resource_agent='${OCF}:pacemaker:remote']/node[@name='${HOST}']/../../resource[@id='${NAME}']\"\nany_resource_xpath=\"//bundle//resource[@id='${NAME}']\"\nreplicas_xpath=\"//bundle/primitive[@id='${BUNDLE_NAME}']/../*[boolean(@image) and boolean(@replicas)]\"\nelse\n# bundle resource\nlocal_resource_xpath=\"//bundle[@id='${NAME}']/replica/resource/node[@name='${HOST}']/../../resource\"\nany_resource_xpath=\"//bundle[@id='${NAME}']//resource\"\nreplicas_xpath=\"//bundle[@id='${BUNDLE_NAME}']/*[boolean(@image) and boolean(@replicas)]\"\nfi\n\nbundle_def_xpath=\"//bundle[@id='${BUNDLE_NAME}']/*[boolean(@image) and boolean(@replicas)]\"\nBUNDLE_CONTAINER_ENGINE=$(cibadmin -Q | xmllint --xpath \"name(${bundle_def_xpath})\" -)\nBUNDLE_REPLICAS=$(cibadmin -Q | xmllint --xpath \"string(${bundle_def_xpath}/@replicas)\" -)\n\n\n# The wait algorithm follows a two-stage approach\n#  1. Depending on how the script is called, we first check whether\n#     the resource is restarted locally. An A/P resource may be\n#     restarted elsewhere in the cluster.\n#  2. If needed, check whether the A/P resource has restarted\n#     elsewhere. For A/P M/S resources, in case the resource is\n#     restarted as Slave locally, ensure a Master is available.\n\nsuccess=1\nbailout=1\ntimeout=$TIMEOUT\nrole=\"\"\n\n# Stage 1: local check\nif [ -n \"$ROLE_LOCAL\" ]; then\n    log \"Waiting until ${NAME} has restarted on ${HOST} and is in state ${ROLE_LOCAL}\"\n    log \"Will probe resource state with the following XPath pattern: ${local_resource_xpath}\"\n\n    while [ $timeout -gt 0 ] && [ $bailout -ne 0 ] && [ $success -ne 0 ]; do\n        resource=$(crm_mon -r --as-xml | xmllint --xpath \"${local_resource_xpath}\" - 2>/dev/null)\n        role=$(echo \"${resource}\" | sed -ne 's/.*\\Wrole=\"\\([^\"]*\\)\".*/\\1/p')\n\n\tif [ \"$(crm_resource --meta -r ${NAME} -g is-managed 2>/dev/null)\" = \"false\" ]; then\n            log \"${NAME} is unmanaged, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif [ \"$(crm_resource --meta -r ${NAME} -g target-role 2>/dev/null)\" = \"Stopped\" ]; then\n            log \"${NAME} is disabled, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif echo \"${resource}\" | grep -q -w \"\\Wblocked=\\\"true\\\"\"; then\n            log \"${NAME} is blocked, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif did_resource_failed_locally; then\n            log \"${NAME} is in failed state, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif [ \"$role\" = \"$ROLE_LOCAL\" ]; then\n            success=0\n            continue\n        elif [ -n \"$ROLE_ANYWHERE\" ] && [ \"$role\" = \"$ROLE_ANYWHERE\" ]; then\n            # A/P: we are restarted in the expected state\n            success=0\n            continue\n        else\n            log \"Waiting for ${NAME} to transition to role ${ROLE_LOCAL} on ${HOST}\"\n        fi\n\n        if [ $bailout -ne 0 ] && [ $success -ne 0 ]; then\n            sleep 4\n            timeout=$((timeout-4))\n        fi\n    done\nfi\n\n# Stage 2: global check\nif [ $timeout -gt 0 ] && [ -n \"$ROLE_ANYWHERE\" ] && [ \"$role\" != \"$ROLE_ANYWHERE\" ]; then\n    log \"Wait until ${NAME} is restarted anywhere in the cluster in state ${ROLE_ANYWHERE}\"\n    log \"Will probe resource state with the following XPath pattern: ${any_resource_xpath}\"\n\n    success=1\n    bailout=1\n    while [ $timeout -gt 0 ] && [ $bailout -ne 0 ] && [ $success -ne 0 ]; do\n        resources=$(crm_mon -r --as-xml | xmllint --xpath \"${any_resource_xpath}\" - 2>/dev/null)\n\tif [ \"$(crm_resource --meta -r ${NAME} -g is-managed 2>/dev/null)\" = \"false\" ]; then\n            log \"${NAME} is unmanaged, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif [ \"$(crm_resource --meta -r ${NAME} -g target-role 2>/dev/null)\" = \"Stopped\" ]; then\n            log \"${NAME} is disabled, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif ! (echo \"${resources}\" | grep -q -w \"\\Wblocked=\\\"false\\\"\"); then\n            log \"${NAME} blocked, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n\telif did_resource_failed_globally; then\n            log \"${NAME} is in failed state, will never reach target role. Bailing out\"\n            bailout=0\n            continue\n        elif echo \"${resources}\" | grep -q -w \"\\Wrole=\\\"${ROLE_ANYWHERE}\\\"\"; then\n            success=0\n            continue\n        else\n            log \"Waiting for ${NAME} to transition to role ${ROLE_ANYWHERE} anywhere in the cluster\"\n        fi\n\n        if [ $bailout -ne 0 ] && [ $success -ne 0 ]; then\n            sleep 4\n            timeout=$((timeout-4))\n        fi\n    done\nfi\n\nif [ $timeout -le 0 ]; then\n    log \"Timeout reached after ${TIMEOUT}s while waiting for ${NAME} to be restarted\"\nelif [ $bailout -le 0 ]; then\n    log \"Restart monitoring for ${NAME} cancelled\"\nfi\n\nif [ $success -eq 0 ]; then\n    log \"${NAME} successfully restarted\"\nelse\n    log \"${NAME} was not restarted properly\"\nfi\n\n# Don't block minor update or stack update if the wait was unsuccessful\nexit 0\n"}, "wait-port-and-run.sh": {"mode": "0755", "content": "#!/usr/bin/bash\nset -eu\n\nHOST=$1\nPORT=$2\n\necho \"$(date -u): Checking whether we can bind to ${HOST}:${PORT}\"\nwhile (ss -Htnl src \"${HOST}\" \"sport = :${PORT}\" | grep -wq \"${PORT}\"); do\n    echo \"$(date -u): ${HOST}:${PORT} still in use, waiting...\";\n    sleep 10;\ndone\n\nshift 2\nCOMMAND=\"$*\"\nif [ -z \"${COMMAND}\" ]; then\n    COMMAND=\"true\"\nfi\nexec $COMMAND\n"}, "pacemaker_resource_lock.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\nMAX_RETRIES=10\nCIB_ENOTFOUND=105\n\nusage() {\n   echo \"Set a global property in the cluster with a validity timestamp.\"\n   echo \"Usage:\"\n   echo \"   $0 --acquire <lock_name> <lock_owner> <lock_ttl_in_seconds>\"\n   echo \"   $0 --release <lock_name> <lock_owner>\"\n   echo\n}\n\nlog() {\n    echo \"$(date -u): $1\" 1>&2\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\nlock_create() {\n    local name=$1\n    local data=$2\n    # cibadmin won't overwrite a key if someone else succeeded to create it concurrently\n    cibadmin --sync-call --scope crm_config --create --xml-text \"<cluster_property_set id='${name}'><nvpair id='${name}-pair' name='${name}' value='${data}'/></cluster_property_set>\" &>/dev/null\n    return $?\n}\n\nlock_update() {\n    local name=$1\n    local expected_data=$2\n    local new_data=$3\n    # we only update the lock we expect to see, so we can't update someone else's lock\n    cibadmin --sync-call --scope crm_config --modify --xpath \"//cluster_property_set/nvpair[@name='${name}' and @value='${expected_data}']/..\" --xml-text \"<nvpair id='${name}-pair' name='${name}' value='${new_data}'/>\" &>/dev/null\n    return $?\n}\n\nlock_delete() {\n    local name=$1\n    local expected_data=$2\n    # we only delete the lock we expect to see, so we can't delete someone else's lock\n    cibadmin --sync-call --scope crm_config --delete --xpath \"//cluster_property_set/nvpair[@name='${name}' and @value='${expected_data}']/..\" &>/dev/null\n    return $?\n}\n\nlock_get() {\n    local lockname=$1\n    local res\n    local rc\n    res=$(cibadmin --query --scope crm_config --xpath \"//cluster_property_set/nvpair[@name='$lockname']\" 2>/dev/null)\n    rc=$?\n    if [ $rc -eq 0 ]; then\n        echo \"$res\" | sed -n 's/.*value=\"\\([^\"]*\\)\".*/\\1/p'\n    fi\n    return $rc\n}\n\nlock_owner() {\n    local lock=$1\n    echo \"$lock\" | cut -d':' -f1\n}\n\nlock_has_expired() {\n    local lock=$1\n    local expiry=$(echo \"$lock\" | cut -d':' -f2)\n    local now=$(date +%s)\n    test $now -ge $expiry\n}\n\n\n# Perform a lock action and restart if the CIB has been modified before\n# committing the lock action\ntry_action() {\n    local fun=$1\n    local lock=$2\n    local requester=$3\n    local args=${4:-}\n    local tries=$MAX_RETRIES\n    local rc=1\n    if [ \"$fun\" = \"lock_acquire\" ] || [ \"$fun\" = \"lock_release\" ]; then\n        log \"Try running $fun\"\n    else\n        return 2\n    fi\n    while [ $rc -ne 0 ]; do\n        $fun $lock $requester $args\n        rc=$?\n        if [ $rc -eq 0 ]; then\n            log \"Operation $1 succeeded\"\n            return 0\n        elif [ $rc -eq 3 ]; then\n            # rc == 3 -> CIB changed before push\n            if [ $tries -eq 0 ]; then\n                log \"Failed to commit after $MAX_RETRIES retries. Bailing out.\"\n                return 2\n            else\n                log \"Failed to commit. Retrying operation.\"\n                tries=$(($tries - 1))\n            fi\n        elif [ $rc -eq 2 ]; then\n            # rc == 2 -> unrecoverable cib error (e.g. pacemaker down)\n            log \"Unexpected failure. Bailing out\"\n            return $rc\n        else\n            # rc == 1 -> lock error (not owner, lock doesn't exists)\n            return $rc\n        fi\n    done\n}\n\n# The lock mechanism uses cibadmin's atomic creation so cluster-wide\n# state coherency is guaranteed by pacemaker\nlock_acquire() {\n    local lockname=$1\n    local requester=$2\n    local ttl=$3\n    local rc\n    local lock\n    local expiry\n    local owner\n\n    log \"Check whether the lock is already held in the CIB\"\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        log \"Could not retrieve info from the CIB\"\n        return 2\n    fi\n\n    if [ -n \"$lock\" ]; then\n        lock_has_expired $lock\n        rc=$?\n        if [ $rc -eq 0 ]; then\n            log \"Lock has expired, now available for being held\"\n        else\n            # lock is still held. check whether we're the owner\n            owner=$(lock_owner $lock)\n            if [ \"$owner\" = \"$requester\" ];then\n                log \"Requester already owns the lock, acquiring attempt will just reconfigure the TTL\"\n            else\n                log \"Lock is held by someone else ($owner)\"\n                return 1\n            fi\n        fi\n    else\n        log \"Lock is not held yet\"\n    fi\n\n    # prepare the lock info\n    expiry=$(($(date +%s) + $ttl))\n\n    if [ -n \"$lock\" ]; then\n        log \"Attempting to update the lock\"\n        lock_update $lockname \"$lock\" \"$requester:$expiry\"\n        rc=$?\n    else\n        log \"Attempting to acquire the lock\"\n        lock_create $lockname \"$requester:$expiry\"\n        rc=$?\n    fi\n\n    if [ $rc -eq 0 ]; then\n        log \"Lock '$lockname' acquired by '$requester', valid until $(date -d @$expiry)\"\n        return 0\n    else\n        log \"CIB changed, lock cannot be acquired\"\n        return 3\n    fi\n}\n\n\n# The lock mechanism uses the CIB's num_updates tag to implement\n# a conditional store. Cluster-wide locking is guaranteed by pacemaker\nlock_release() {\n    local lockname=$1\n    local requester=$2\n    local rc\n    local lock\n    local owner\n\n    log \"Check whether the lock is already held in the CIB\"\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        log \"Could not retrieve info from the CIB\"\n        return 2\n    fi\n\n    if [ -z \"$lock\" ]; then\n        log \"Lock doesn't exist. Nothing to release\"\n        return 0\n    else\n        log \"Lock exists, check whether we're the owner\"\n        owner=$(lock_owner $lock)\n        if [ \"$owner\" != \"$requester\" ];then\n            log \"Lock is held by someone else ($owner), will not unlock\"\n            return 1\n        fi\n    fi\n\n    lock_delete $lockname \"$lock\"\n    rc=$?\n\n    if [ $rc -eq 0 ]; then\n        log \"Lock '$lockname' released by '$requester'\"\n        return 0\n    else\n        log \"CIB deletion error, lock cannot be released\"\n        return 3\n    fi\n}\n\n\n# Retrieve the owner of a lock from the CIB\n# this is a read-only operation, so no need to log debug info\nlock_get_owner() {\n    local lockname=$1\n    local rc\n    local lock\n    local owner\n\n    lock=$(lock_get $lockname)\n    rc=$?\n    if [ $rc -ne 0 ] && [ $rc -ne $CIB_ENOTFOUND ]; then\n        return 2\n    fi\n\n    if [ -z \"$lock\" ]; then\n        return 1\n    else\n        lock_owner $lock\n        return 0\n    fi\n}\n\n\nACTION=$1\nLOCKNAME=$2\nREQUESTER=$3\nTTL=${4:-60}\n\nif [ -z \"$ACTION\" ]; then\n    error \"Action must be specified\"\nfi\n\nif [ $ACTION != \"--help\" ]; then\n    if [ -z \"$LOCKNAME\" ]; then\n        error \"You must specific a lock name\"\n    fi\n    if [ $ACTION != \"--owner\" ] && [ $ACTION != \"-o\" ]; then\n        if [ -z \"$REQUESTER\" ]; then\n            error \"You must specific a lock requester\"\n        fi\n    fi\nfi\n\ncase $ACTION in\n    --help) usage; exit 0;;\n    --acquire|-a) try_action lock_acquire $LOCKNAME $REQUESTER $TTL;;\n    --release|-r) try_action lock_release $LOCKNAME $REQUESTER;;\n    --acquire-once|-A) lock_acquire $LOCKNAME $REQUESTER $TTL;;\n    --owner|-o) lock_get_owner $LOCKNAME;;\n    *) error \"Invalid action\";;\nesac\nexit $?\n"}, "pacemaker_mutex_restart_bundle.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# pacemaker_mutex_restart_bundle.sh --lock mysql galera galera-bundle Master _\n# pacemaker_mutex_restart_bundle.sh --lock ovn_dbs ovndb_servers ovn-dbs-bundle Slave Master\n\nset -u\n\nusage() {\n    echo \"Restart a clustered resource in a coordinated way across the cluster\"\n    echo \"Usage:\"\n    echo \"   $0 --lock <tripleo-service> <pcmk-resource> <pcmk-bundle> <target-state-local> <target-state-cluster>\"\n    echo\n}\n\nlog() {\n    echo \"$(date -u): $1\"\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\npacemaker_supports_promoted() {\n    # The Promoted token is only matched in recent pacemaker versions\n    grep -wq \"<value>Promoted</value>\" /usr/share/pacemaker/resources-*.rng\n}\n\nACTION=$1\ncase $ACTION in\n    --help) usage; exit 0;;\n    --lock) ;;\n    *) error \"Unknown action '$ACTION'\";;\nesac\n\nTRIPLEO_SERVICE=$2\nLOCK_NAME=${TRIPLEO_SERVICE}-restart-lock\nLOCK_OWNER=$(crm_node -n 2>/dev/null)\nrc=$?\nif [ $rc -ne 0 ]; then\n    if [ $rc -eq 102 ]; then\n        log \"Cluster is not running locally, no need to restart resource $TRIPLEO_SERVICE\"\n        exit 0\n    else\n        error \"Unexpected error while connecting to the cluster (rc: $rc), bailing out\"\n    fi\nfi\n\nRESOURCE_NAME=$3\nBUNDLE_NAME=$4\nWAIT_TARGET_LOCAL=$5\nWAIT_TARGET_ANYWHERE=${6:-_}\n\nif pacemaker_supports_promoted; then\n    WAIT_TARGET_LOCAL=$(echo \"$5\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    WAIT_TARGET_ANYWHERE=$(echo \"${6:-_}\" | sed -e 's/Master/Promoted/' -e 's/Slave/Unpromoted/')\n    promoted_role=\"Promoted\"\nelse\n    promoted_role=\"Master\"\nfi\n\n# The lock TTL should accomodate for the resource start/promote timeout\nif [ \"$RESOURCE_NAME\" != \"$BUNDLE_NAME\" ]; then\n    if [ \"$WAIT_TARGET_LOCAL\" = \"$promoted_role\" ] || [ \"$WAIT_TARGET_ANYWHERE\" = \"$promoted_role\" ]; then\n        rsc_op=\"promote\"\n    else\n        rsc_op=\"start\"\n    fi\n    # <op id=\"galera-promote-interval-0s\" interval=\"0s\" name=\"promote\" on-fail=\"block\" timeout=\"300s\"/>\n    PCMK_TTL=$(cibadmin -Q | xmllint -xpath \"string(//primitive[@id='${RESOURCE_NAME}']/operations/op[@name='${rsc_op}']/@timeout)\" - | sed 's/s$//')\n    LOCK_TTL=$((PCMK_TTL + 30))\nelse\n    # The podman RA's default start timeout\n    LOCK_TTL=90\nfi\n\nlog \"Acquire a ${LOCK_TTL}s restart lock for service $TRIPLEO_SERVICE before restarting it\"\n# Loop until we hold the lock. The lock has a TTL, so we're guaranteed to get it eventually\nrc=1\nwhile [ $rc -ne 0 ]; do\n    /var/lib/container-config-scripts/pacemaker_resource_lock.sh --acquire $LOCK_NAME $LOCK_OWNER $LOCK_TTL\n    rc=$?\n    if [ $rc != 0 ]; then\n        if [ $rc -gt 1 ]; then\n            error \"Could not acquire lock due to unrecoverable error (rc: $rc), bailing out\"\n        else\n            log \"Could not acquire lock, retrying\"\n            sleep 10\n        fi\n    fi\ndone\n\nlog \"Restart the service $TRIPLEO_SERVICE locally\"\n# Reuse the local restart script in t-h-t (driven by env var TRIPLEO_MINOR_UPDATE)\nTRIPLEO_MINOR_UPDATE=true /var/lib/container-config-scripts/pacemaker_restart_bundle.sh $TRIPLEO_SERVICE $RESOURCE_NAME $BUNDLE_NAME $WAIT_TARGET_LOCAL $WAIT_TARGET_ANYWHERE\n\n# If we reached this point, always try to release the lock\nlog \"Release the restart lock for service $TRIPLEO_SERVICE\"\n/var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $LOCK_NAME $LOCK_OWNER\nrc=$?\nif [ $rc -ne 0 ] && [ $rc -ne 1 ]; then\n    error \"Could not release held lock (rc: $rc)\"\nfi\n"}, "pacemaker_mutex_shutdown.sh": {"mode": "0755", "content": "#!/usr/bin/bash\n\n# pacemaker_mutex_shutdown.sh --acquire\n# pacemaker_mutex_shutdown.sh --release\n\nset -u\n\nusage() {\n    echo \"Shutdown a cluster node in a coordinated way across the cluster\"\n    echo \"Usage:\"\n    echo \"   $0 --acquire # prevent other node from shutting down until we hold the lock\"\n    echo \"   $0 --release # release the lock, other node can compete for the shutdown lock\"\n    echo\n}\n\nlog() {\n    echo \"$(date -u): $1\"\n}\n\nerror() {\n    echo \"$(date -u): $1\" 1>&2\n    exit 1\n}\n\n# Loop until we hold the lock. The lock has a TTL, so we're guaranteed to get it eventually\nshutdown_lock_acquire() {\n    local lockname=$1\n    local requester=$2\n    local ttl=$3\n    local rc=1\n    local current_owner\n    local owner_stopped\n    local owner_rc\n\n    log \"Acquiring the shutdown lock\"\n    while [ $rc -ne 0 ]; do\n        /var/lib/container-config-scripts/pacemaker_resource_lock.sh --acquire-once $lockname $requester $ttl\n        rc=$?\n        if [ $rc -ne 0 ]; then\n            if [ $rc -eq 2 ]; then\n                error \"Could not acquire the shutdown lock due to unrecoverable error (rc: $rc), bailing out\"\n            else\n                # The lock is held by another node.\n                current_owner=$(/var/lib/container-config-scripts/pacemaker_resource_lock.sh --owner $lockname)\n                owner_rc=$?\n                if [ $owner_rc -eq 2 ]; then\n                    error \"Could not get the shutdown lock owner due to unrecoverable error (rc: $owner_rc), bailing out\"\n                fi\n                if [ $owner_rc -eq 0 ]; then\n                    # If the owner is marked as offline, that means it has shutdown and\n                    # we can clean the lock preemptively and try to acquire it.\n                    owner_stopped=$(crm_mon -1X | xmllint --xpath 'count(//nodes/node[@name=\"'${current_owner}'\" and @online=\"false\" and @unclean=\"false\"])' -)\n                    if [ \"${owner_stopped}\" = \"1\" ]; then\n                        log \"Shutdown lock held by stopped node '${current_owner}', lock can be released\"\n                        /var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $lockname $current_owner\n                        continue\n                    fi\n                fi\n                log \"Shutdown lock held by another node (rc: $rc), retrying\"\n                sleep 10\n            fi\n        fi\n    done\n    log \"Shutdown lock acquired\"\n    return 0\n}\n\n\n# Release the lock if we still own it. Not owning it anymore is not fatal\nshutdown_lock_release() {\n    local lockname=$1\n    local requester=$2\n    local rc\n\n    log \"Releasing the shutdown lock\"\n    /var/lib/container-config-scripts/pacemaker_resource_lock.sh --release $lockname $requester\n    rc=$?\n    if [ $rc -ne 0 ]; then\n        if [ $rc -gt 1 ]; then\n            error \"Could not release the shutdown lock due to unrecoverable error (rc: $rc), bailing out\"\n        else\n            log \"Shutdown lock no longer held, nothing to do\"\n        fi\n    else\n        log \"Shutdown lock released\"\n    fi\n    return 0\n}\n\n\nACTION=$1\nif [ -z \"$ACTION\" ]; then\n    error \"Action must be specified\"\nfi\n\nLOCK_NAME=tripleo-shutdown-lock\nLOCK_OWNER=$(crm_node -n 2>/dev/null)\nrc=$?\nif [ $rc -ne 0 ]; then\n    if [ $rc -eq 102 ]; then\n        log \"Cluster is not running locally, no need to aquire the shutdown lock\"\n        exit 0\n    else\n        error \"Unexpected error while connecting to the cluster (rc: $rc), bailing out\"\n    fi\nfi\n\n# We start with a very high TTL, that long enough to accomodate a cluster stop.\n# As soon as the node will get offline, the other competing node will be entitled\n# to steal the lock, so they should never wait that long in practice.\nLOCK_TTL=600\n\n\ncase $ACTION in\n    --help) usage; exit 0;;\n    --acquire|-a) shutdown_lock_acquire ${LOCK_NAME} ${LOCK_OWNER} ${LOCK_TTL};;\n    --release|-r) shutdown_lock_release ${LOCK_NAME} ${LOCK_OWNER};;\n    *) error \"Invalid action\";;\nesac\nexit $?\n"}}, "docker_config": {"step_2": {"create_haproxy_wrapper": {"start_order": 1, "detach": false, "net": "host", "pid": "host", "user": "root", "command": ["/container_puppet_apply.sh", "4", "file", "include ::tripleo::profile::base::neutron::ovn_metadata_agent_wrappers"], "image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/var/lib/container-config-scripts/container_puppet_apply.sh:/container_puppet_apply.sh:ro", "/etc/puppet:/tmp/puppet-etc:ro", "/usr/share/openstack-puppet/modules:/usr/share/openstack-puppet/modules:ro", "/run/openvswitch:/run/openvswitch:shared,z", "/var/lib/neutron:/var/lib/neutron:shared,z"]}}, "step_4": {"setup_ovs_manager": {"start_order": 0, "detach": false, "net": "host", "privileged": true, "user": "root", "command": ["/container_puppet_apply.sh", "4", "exec", "include tripleo::profile::base::neutron::ovn_metadata"], "image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/var/lib/container-config-scripts/container_puppet_apply.sh:/container_puppet_apply.sh:ro", "/etc/puppet:/tmp/puppet-etc:ro", "/usr/share/openstack-puppet/modules:/usr/share/openstack-puppet/modules:ro", "/lib/modules:/lib/modules:ro", "/run/openvswitch:/run/openvswitch:shared,z"], "environment": {"TRIPLEO_DEPLOY_IDENTIFIER": "1764581821"}}, "ovn_metadata_agent": {"start_order": 1, "image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "net": "host", "pid": "host", "cgroupns": "host", "privileged": true, "restart": "always", "healthcheck": {"test": "/openstack/healthcheck"}, "volumes": ["/etc/hosts:/etc/hosts:ro", "/etc/localtime:/etc/localtime:ro", "/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro", "/etc/pki/ca-trust/source/anchors:/etc/pki/ca-trust/source/anchors:ro", "/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro", "/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro", "/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro", "/dev/log:/dev/log", "/etc/puppet:/etc/puppet:ro", "/var/log/containers/neutron:/var/log/neutron:z", "/var/lib/kolla/config_files/ovn_metadata_agent.json:/var/lib/kolla/config_files/config.json:ro", "/var/lib/config-data/puppet-generated/neutron:/var/lib/kolla/config_files/src:ro", "/lib/modules:/lib/modules:ro", "/run/openvswitch:/run/openvswitch:shared,z", "/var/lib/neutron:/var/lib/neutron:shared,z", "/run/netns:/run/netns:shared", "/var/lib/neutron/kill_scripts:/etc/neutron/kill_scripts:shared,z", "/var/lib/neutron/ovn_metadata_haproxy_wrapper:/usr/local/bin/haproxy:ro"], "environment": {"KOLLA_CONFIG_STRATEGY": "COPY_ALWAYS"}}}}, "metadata_settings": [], "deploy_steps_tasks": [{"name": "Certificate generation", "when": ["step|int == 1", "enable_internal_tls"], "block": [{"include_role": {"name": "linux-system-roles.certificate"}, "vars": {"certificate_requests": [{"name": "ovn_metadata", "dns": "{{fqdn_internal_api}}", "principal": "ovn_metadata/{{fqdn_internal_api}}@{{idm_realm}}", "key_size": "2048", "ca": "ipa"}]}}]}], "host_prep_tasks": [{"name": "create persistent directories", "file": {"path": "{{ item.path }}", "state": "directory", "setype": "{{ item.setype }}", "mode": "{{ item.mode }}"}, "with_items": [{"path": "/var/log/containers/neutron", "setype": "container_file_t", "mode": "0750"}]}, {"name": "create /run/netns with temp namespace", "command": "ip netns add ns_temp", "register": "ipnetns_add_result", "failed_when": false}, {"name": "remove temp namespace", "command": "ip netns delete ns_temp", "failed_when": false, "when": ["ipnetns_add_result.rc is defined", "ipnetns_add_result.rc == 0"]}, {"name": "create /var/lib/neutron", "file": {"path": "/var/lib/neutron", "state": "directory", "setype": "container_file_t"}}, {"name": "set conditions", "set_fact": {"haproxy_wrapper_enabled": true, "debug_enabled": true, "docker_additional_sockets": ["/var/lib/openstack/docker.sock"]}}, {"name": "create kill_scripts directory within /var/lib/neutron", "file": {"state": "directory", "path": "/var/lib/neutron/kill_scripts"}}, {"name": "create haproxy kill script", "when": "haproxy_wrapper_enabled|bool", "copy": {"dest": "/var/lib/neutron/kill_scripts/haproxy-kill", "mode": 493, "content": "#!/bin/bash\n{% if debug_enabled|bool -%}\nset -x\n{% endif -%}\nadd_date() {\n  echo \"$(date) $@\"\n}\n\n# Set up script logging for debugging purpose.\n# It will be taken care of by logrotate since there is the .log\n# suffix.\nexec 3>&1 4>&2\ntrap 'exec 2>&4 1>&3' 0 1 2 3\nexec 1>>/var/log/neutron/kill-script.log 2>&1\n\nSIG=$1\nPID=$2\nNETNS=$(ip netns identify ${PID})\n\nif [ \"x${NETNS}\" == \"x\" ]; then\n  CLI=\"nsenter --all --preserve-credentials -t 1 podman\"\n  SIG=9\nelse\n  CLI=\"nsenter --net=/run/netns/${NETNS} --preserve-credentials -m -t 1 podman\"\nfi\n\nkill_container() {\n  add_date \"Killing container $1 ($2)\"\n  signal_container $1 $2 9\n}\n\nstop_container() {\n  add_date \"Stopping container $1 ($2)\"\n  $CLI stop $2\n}\n\nsignal_container() {\n  SIGNAL=$3\n  if [ -z \"$SIGNAL\" ]; then\n      SIGNAL=\"HUP\"\n  fi\n  add_date \"Sending signal '$SIGNAL' to $1 ($2)\"\n  $CLI kill --signal $SIGNAL $2\n}\n\ndelete_container() {\n  add_date \"Deleting container $1 ($2)\"\n  $CLI rm $2 || echo \"Deleting container $1 ($2) failed\"\n}\n\n\n{% raw -%}\nif [ -f /proc/$PID/cgroup ]; then\n  # Get container ID based on process cgroups\n  CT_ID=$(awk 'BEGIN {FS=\".scope|-\"} /\\/libpod-/ {if ($(NF-1)) print $(NF-1);exit}' /proc/$PID/cgroup)\n  CT_NAME=$($CLI inspect -f '{{.Name}}' $CT_ID)\n\n  case $SIG in\n    HUP)\n      signal_container $CT_NAME $CT_ID\n      ;;\n    9)\n      kill_container $CT_NAME $CT_ID\n      delete_container $CT_NAME $CT_ID\n      ;;\n    15)\n      stop_container $CT_NAME $CT_ID\n      delete_container $CT_NAME $CT_ID\n      ;;\n    *)\n      add_date \"Unknown action ${SIG} for ${CT_NAME} ${CT_ID}\"\n      exit 1\n      ;;\n  esac\n\nelse\n  add_date \"No such PID: ${PID}\"\n  exit 1\nfi\n{% endraw %}\n"}}], "upgrade_tasks": [], "external_update_tasks": [{"name": "Check if python3-openvswitch3.1 workaround is needed", "delegate_to": "{{ item }}", "become": true, "tags": ["ovn", "ovn_image"], "when": "step|int == 1", "shell": "if podman exec ovn_metadata_agent rpm -q python3-openvswitch3.1 > /dev/null ; then echo REQUIRED; else echo OK ; fi\n", "register": "metadata_python_ovs_3_1", "failed_when": false, "loop": "{{ groups['ovn_metadata'] | difference(groups['excluded_overcloud']) }}"}, {"name": "Update ovn_metadata_agents", "vars": {"hosts_to_update_metadata": "{{ metadata_python_ovs_3_1.results | selectattr('stdout', 'eq', 'REQUIRED') | map(attribute='item') | list }}"}, "tags": ["ovn", "ovn_image"], "when": ["step|int == 1", "hosts_to_update_metadata | length > 0"], "block": [{"name": "Force pull image in case image name doesn't change.", "become": true, "loop": "{{ hosts_to_update_metadata }}", "delegate_to": "{{ item }}", "async": 600, "poll": 0, "register": "ovn_metadata_image_update", "containers.podman.podman_image": {"name": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "validate_certs": false, "force": true}}, {"name": "Was the ovn_metadata_agent image pull successful.", "when": ["'results' in ovn_metadata_image_update"], "become": true, "delegate_to": "{{ async_result_item.item }}", "async_status": {"jid": "{{ async_result_item.ansible_job_id }}"}, "loop": "{{ovn_metadata_image_update.results }}", "loop_control": {"loop_var": "async_result_item"}, "register": "async_poll_results", "until": "async_poll_results.finished", "retries": 600, "delay": 1}, {"name": "Now rotate all ovn_metadata_agents", "tags": ["ovn_metadata_parallel"], "delegate_to": "{{ item }}", "become": true, "tripleo_container_manage": {"config_dir": "/var/lib/tripleo-config/container-startup-config/step_4", "config_id": ["ovn_metadata_agent"], "config_patterns": "*ovn_metadata_agent.json", "config_overrides": {".*ovn_metadata_agent": {"image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "name": "ovn_metadata_agent"}}}, "loop": "{{ hosts_to_update_metadata }}", "async": 600, "poll": 0}]}, {"name": "Now rotate all ovn_metadata_agents", "vars": {"hosts_to_update_metadata": "{{ metadata_python_ovs_3_1.results | selectattr('stdout', 'eq', 'REQUIRED') | map(attribute='item') | list }}"}, "tags": ["never", "ovn_metadata_serial"], "when": ["step|int == 1", "hosts_to_update_metadata | length > 0"], "delegate_to": "{{ item }}", "become": true, "tripleo_container_manage": {"config_dir": "/var/lib/tripleo-config/container-startup-config/step_4", "config_id": ["ovn_metadata_agent"], "config_patterns": "*ovn_metadata_agent.json", "config_overrides": {".*ovn_metadata_agent": {"image": "registry.redhat.io/rhosp-rhel9/openstack-neutron-metadata-agent-ovn:17.1", "name": "ovn_metadata_agent"}}}, "loop": "{{ hosts_to_update_metadata }}", "loop_control": {"pause": 1}}]}, "OS::stack_id": "arn:openstack:heat::admin:stacks/standalone-StandaloneServiceChain-6bdxzdytssyn-ServiceChain-agoxbc5yosy2-58-jyexllgjlvch/9cdcc82a-09f4-4d68-b6c6-ea13935f734b"}


