Main Page/Openstack Container Configuration Steps

== Intro ==
We have seen how to build the containers with kolla, but these containers are not configured at all, lets try to see how they are configured
== Containers Steps ==
First we define our containerized services on THT/environments/docker.yaml
resource_registry:
 OS::TripleO::Services::Docker: ../puppet/services/docker.yaml
 # Default Neutron ML2 puppet plugin to use when NeutronCorePlugin is set to ML2
 OS::TripleO::Docker::NeutronMl2PluginBase: ../puppet/services/neutron-plugin-ml2.yaml
 #NOTE (dprince) add roles to be docker enabled as we support them
 OS::TripleO::Services::NovaLibvirt: ../docker/services/nova-libvirt.yaml
 #OS::TripleO::Services::ComputeNeutronOvsAgent: ../docker/services/neutron-ovs-agent.yaml
 OS::TripleO::Services::NovaCompute: ../docker/services/nova-compute.yaml
 OS::TripleO::Services::Keystone: ../docker/services/keystone.yaml
..
 OS::TripleO::Services::NovaScheduler: ../docker/services/nova-scheduler.yaml
 OS::TripleO::Services::NovaVncProxy: ../docker/services/nova-vnc-proxy.yaml
 #OS::TripleO::Services::NeutronServer: ../docker/services/neutron-api.yaml #neutron is still not containerized on Pike
 #OS::TripleO::Services::NeutronApi: ../docker/services/neutron-api.yaml
...
...
The list below represents the correlation between the baremetal and the containers steps. These steps are executed sequentially:
 Containers config files generated per hiera settings.
 Load Balancer configuration baremetal
 Step 1 baremetal
 Step 1 containers
 Core Services (Database/Rabbit/NTP/etc.)
 Step 2 baremetal
 Step 2 containers
 Early Openstack Service setup (Ringbuilder, etc.)
 Step 3 baremetal
 Step 3 containers
 General OpenStack Services
 Step 4 baremetal
 Step 4 containers
 Keystone containers post initialization (tenant, service, endpoint creation)
 Service activation (Pacemaker)
 Step 5 baremetal
 Step 5 containers
If we want to check what is done on each step we should check THT/docker/services/<service>.yaml
Lets focus on nova-api.yaml , most of it should be valid for other services as well. We can see to following interesting data:
-puppet_config
-kolla_config
-docker_config_scripts
-docker_config
 -step_2
 -step_3
 -step_4
 -step_5
-upgrade_tasks
Step3 seems interesting, we can see there how commands are executed on different container each:
 step_3:
 nova_api_db_sync:
 start_order: 0
 image: *nova_api_image
 net: host
 detach: false
 user: root
 volumes: &nova_api_bootstrap_volumes
 list_concat:
 - {get_attr: [ContainersCommon, volumes]}
 -
 - /var/lib/config-data/nova/etc/my.cnf.d/tripleo.cnf:/etc/my.cnf.d/tripleo.cnf:ro
 - /var/lib/config-data/nova/etc/nova/:/etc/nova/:ro
 - /var/log/containers/nova:/var/log/nova
 - /var/log/containers/httpd/nova-api:/var/log/httpd
 command: "/usr/bin/bootstrap_host_exec nova_api su nova -s /bin/bash -c '/usr/bin/nova-manage api_db sync'"
 nova_api_map_cell0:
 start_order: 1
 image: *nova_api_image
 net: host
 detach: false
 user: root
 volumes: *nova_api_bootstrap_volumes
 command: "/usr/bin/bootstrap_host_exec nova_api su nova -s /bin/bash -c '/usr/bin/nova-manage cell_v2 map_cell0'"
 nova_api_ensure_default_cell:
 start_order: 2
 image: *nova_api_image
 net: host
 detach: false
 volumes:
 list_concat:
 - *nova_api_bootstrap_volumes
 -
 - /var/lib/config-data/nova/etc/my.cnf.d/tripleo.cnf:/etc/my.cnf.d/tripleo.cnf:ro
 - /var/lib/config-data/nova/etc/nova/:/etc/nova/:ro
 - /var/log/containers/nova:/var/log/nova
 - /var/lib/docker-config-scripts/nova_api_ensure_default_cell.sh:/nova_api_ensure_default_cell.sh:ro
 user: root
 command: "/usr/bin/bootstrap_host_exec nova_api /nova_api_ensure_default_cell.sh"
 nova_db_sync:
 start_order: 3
 image: *nova_api_image
 net: host
 detach: false
 volumes: *nova_api_bootstrap_volumes
 user: root
 command: "/usr/bin/bootstrap_host_exec nova_api su nova -s /bin/bash -c '/usr/bin/nova-manage db sync'"
lets examine paunch, you can see these containers are on exited state, since the command is executed once when deploying and then it exists (they run on foreground mode, detach: false ):
# paunch list | grep nova-api | grep step3
| tripleo_step3 | nova_db_sync | 192.168.24.1:8787/rhosp12/openstack-nova-api:2017-12-06.2 | /usr/bin/bootstrap_host_exec nova_api su nova -s /bin/bash -c '/usr/bin/nova-manage db sync' | exited |
| tripleo_step3 | nova_api_ensure_default_cell | 192.168.24.1:8787/rhosp12/openstack-nova-api:2017-12-06.2 | /usr/bin/bootstrap_host_exec nova_api /nova_api_ensure_default_cell.sh | exited |
| tripleo_step3 | nova_api_map_cell0 | 192.168.24.1:8787/rhosp12/openstack-nova-api:2017-12-06.2 | /usr/bin/bootstrap_host_exec nova_api su nova -s /bin/bash -c '/usr/bin/nova-manage cell_v2 map_cell0' | exited |
| tripleo_step3 | nova_api_db_sync | 192.168.24.1:8787/rhosp12/openstack-nova-api:2017-12-06.2 | /usr/bin/bootstrap_host_exec nova_api su nova -s /bin/bash -c '/usr/bin/nova-manage api_db sync' | exited |
Lets try to figure out how containers are configured, it should be done before step3 because, but how ?
THT/docker/docker-puppet.py script is responsible for generating the config files for each service. The script is called from the deploy-steps.j2 file and it takes a json file as configuration. The json files passed to this script are built out of the puppet_config parameter set in every service template (explained in the Docker specific settings section).
The docker-puppet.py execution results in a oneshot container being executed (usually named puppet-$service_name) to generate the configuration options or run other service specific initialization tasks. Example: Create Keystone endpoints.
Lets check its content, just mp_puppet_config function and main:
def mp_puppet_config((config_volume, puppet_tags, manifest, config_image, volumes)):
 ...
 sh_script = '/var/lib/docker-puppet/docker-puppet.sh'
 with open(sh_script, 'w') as script_file:
 os.chmod(script_file.name, 0755)
 script_file.write("""#!/bin/bash
 set -ex
 mkdir -p /etc/puppet
 cp -a /tmp/puppet-etc/* /etc/puppet
 rm -Rf /etc/puppet/ssl # not in use and causes permission errors
 echo "{\\"step\\": $STEP}" > /etc/puppet/hieradata/docker.json
 TAGS=""
 if [ -n "$PUPPET_TAGS" ]; then
 TAGS="--tags \"$PUPPET_TAGS\""
 fi
 ...
 set +e
 FACTER_hostname=$HOSTNAME FACTER_uuid=docker /usr/bin/puppet apply \
 --detailed-exitcodes --color=false --logdest syslog --logdest console $TAGS /etc/config.pp
 
 ... 
 # Disables archiving
 if [ -z "$NO_ARCHIVE" ]; then
 archivedirs=("/etc" "/root" "/opt" "/var/lib/ironic/tftpboot" "/var/lib/ironic/httpboot" "/var/www" "/var/spool/cron" "/var/lib/nova/.ssh")
 rsync_srcs=""
 for d in "${archivedirs[@]}"; do
 if [ -d "$d" ]; then
 rsync_srcs+=" $d"
 fi
 done
 rsync -a -R --delay-updates --delete-after $rsync_srcs /var/lib/config-data/${NAME}
 mkdir -p /var/lib/config-data/puppet-generated/${NAME}
 rsync -a -R -0 --delay-updates --delete-after \
 --files-from=<(find $rsync_srcs -newer /tmp/the_origin_of_time -not -path '/etc/puppet*' -print0) \
 / /var/lib/config-data/puppet-generated/${NAME}
 tar -c -f - /var/lib/config-data/${NAME} --mtime='1970-01-01' | md5sum | awk '{print $1}' > /var/lib/config-data/${NAME}.md5sum
 tar -c -f - /var/lib/config-data/puppet-generated/${NAME} --mtime='1970-01-01' | md5sum | awk '{print $1}' > /var/lib/config-data/puppet-generated/${NAME}.md5sum
 fi
 """)
 with tempfile.NamedTemporaryFile() as tmp_man:
 with open(tmp_man.name, 'w') as man_file:
 man_file.write('include ::tripleo::packages\n')
 man_file.write(manifest)
 rm_container('docker-puppet-%s' % config_volume)
 pull_image(config_image)
 dcmd = ['/usr/bin/docker', 'run',
 '--user', 'root',
 '--name', 'docker-puppet-%s' % config_volume,
 '--health-cmd', '/bin/true',
 '--env', 'PUPPET_TAGS=%s' % puppet_tags,
 '--env', 'NAME=%s' % config_volume,
 '--env', 'HOSTNAME=%s' % short_hostname(),
 '--env', 'NO_ARCHIVE=%s' % os.environ.get('NO_ARCHIVE', ),
 '--env', 'STEP=%s' % os.environ.get('STEP', '6'),
 '--volume', '%s:/etc/config.pp:ro' % tmp_man.name,
 '--volume', '/etc/puppet/:/tmp/puppet-etc/:ro',
 '--volume', '/usr/share/openstack-puppet/modules/:/usr/share/openstack-puppet/modules/:ro',
 '--volume', '%s:/var/lib/config-data/:rw' % os.environ.get('CONFIG_VOLUME_PREFIX', '/var/lib/config-data'),
 '--volume', 'tripleo_logs:/var/log/tripleo/',
 # Syslog socket for puppet logs
 '--volume', '/dev/log:/dev/log',
 # OpenSSL trusted CA injection
 '--volume', '/etc/pki/ca-trust/extracted:/etc/pki/ca-trust/extracted:ro',
 '--volume', '/etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro',
 '--volume', '/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/certs/ca-bundle.trust.crt:ro',
 '--volume', '/etc/pki/tls/cert.pem:/etc/pki/tls/cert.pem:ro',
 # script injection
 '--volume', '%s:%s:rw' % (sh_script, sh_script) ]
 for volume in volumes:
 if volume:
 dcmd.extend(['--volume', volume])
 dcmd.extend(['--entrypoint', sh_script])
 env = {}
 # NOTE(flaper87): Always copy the DOCKER_* environment variables as
 # they contain the access data for the docker daemon.
 for k in filter(lambda k: k.startswith('DOCKER'), os.environ.keys()):
 env[k] = os.environ.get(k)
 if os.environ.get('NET_HOST', 'false') == 'true':
 log.debug('NET_HOST enabled')
 dcmd.extend(['--net', 'host', '--volume',
 '/etc/hosts:/etc/hosts:ro'])
 dcmd.append(config_image)
 log.debug('Running docker command: %s' % ' '.join(dcmd))
 ######### Here it sems where the containers are launched ###################
 
 subproc = subprocess.Popen(dcmd, stdout=subprocess.PIPE,
 stderr=subprocess.PIPE, env=env)
 cmd_stdout, cmd_stderr = subproc.communicate()
 # puppet with --detailed-exitcodes will return 0 for success and no changes
 # and 2 for success and resource changes. Other numbers are failures
 if subproc.returncode not in [0, 2]:
 log.error('Failed running docker-puppet.py for %s' % config_volume)
 if cmd_stdout:
 log.error(cmd_stdout)
 if cmd_stderr:
 log.error(cmd_stderr)
 else:
 if cmd_stdout:
 log.debug(cmd_stdout)
 if cmd_stderr:
 log.debug(cmd_stderr)
 # only delete successful runs, for debugging
 rm_container('docker-puppet-%s' % config_volume)
 log.info('Finished processing puppet configs')
 return subproc.returncode
######## Here starts main ##########
# Holds all the information for each process to consume.
# Instead of starting them all linearly we run them using a process
# pool. This creates a list of arguments for the above function
# to consume.
process_map = []
for config_volume in configs:
 service = configs[config_volume]
 puppet_tags = service[1] or ''
 manifest = service[2] or ''
 config_image = service[3] or ''
 volumes = service[4] if len(service) > 4 else []
 if puppet_tags:
 puppet_tags = "file,file_line,concat,augeas,cron,%s" % puppet_tags
 else:
 puppet_tags = "file,file_line,concat,augeas,cron"
 process_map.append([config_volume, puppet_tags, manifest, config_image, volumes])
for p in process_map:
 log.debug('- %s' % p)
# Fire off processes to perform each configuration. Defaults
# to the number of CPUs on the system.
p = multiprocessing.Pool(process_count)
returncodes = list(p.map(mp_puppet_config, process_map))
config_volumes = [pm[0] for pm in process_map]
success = True
for returncode, config_volume in zip(returncodes, config_volumes):
 if returncode not in [0, 2]:
 log.error('ERROR configuring %s' % config_volume)
 success = False
# Update the startup configs with the config hash we generated above
config_volume_prefix = os.environ.get('CONFIG_VOLUME_PREFIX', '/var/lib/config-data')
log.debug('CONFIG_VOLUME_PREFIX: %s' % config_volume_prefix)
startup_configs = os.environ.get('STARTUP_CONFIG_PATTERN', '/var/lib/tripleo-config/docker-container-startup-config-step_*.json')
log.debug('STARTUP_CONFIG_PATTERN: %s' % startup_configs)
infiles = glob.glob('/var/lib/tripleo-config/docker-container-startup-config-step_*.json')
for infile in infiles:
 with open(infile) as f:
 infile_data = json.load(f)
 for k, v in infile_data.iteritems():
 config_volume = match_config_volume(config_volume_prefix, v)
 if config_volume:
 config_hash = get_config_hash(config_volume)
 if config_hash:
 env = v.get('environment', [])
 env.append("TRIPLEO_CONFIG_HASH=%s" % config_hash)
 log.debug("Updating config hash for %s, config_volume=%s hash=%s" % (k, config_volume, config_hash))
 infile_data[k]['environment'] = env
 outfile = os.path.join(os.path.dirname(infile), "hashed-" + os.path.basename(infile))
 with open(outfile, 'w') as out_f:
 os.chmod(out_f.name, 0600)
 json.dump(infile_data, out_f)
if not success:
 sys.exit(1)
Remember that the config is stored on in the host/var/lib/config-data/puppet-generated/ directory, and these config files are mounted to the containers
# docker inspect <nova_api_container_uuid
 "Mounts": [
 {
 "Source": "/etc/ssh/ssh_known_hosts",
 "Destination": "/etc/ssh/ssh_known_hosts",
 "Mode": "ro",
 "RW": false,
 "Propagation": "rprivate"
 },
 {
 "Source": "/var/lib/kolla/config_files/nova_api.json",
 "Destination": "/var/lib/kolla/config_files/config.json", 
 "Mode": "ro",
 "RW": false,
 "Propagation": "rprivate"
 },
 {
 "Source": "/var/lib/config-data/puppet-generated/nova", <====
 "Destination": "/var/lib/kolla/config_files/src",
 "Mode": "ro",
 "RW": false,
 "Propagation": "rprivate"
 }
I need to clarify how /etc/nova/ reaches the the container since config files are mounted on /var/lib/kolla/config_files/src, perhaps the the mounted files are merged with the root filesystem ?
== Full nova-api.yaml ==
heat_template_version: pike
description: >
 OpenStack containerized Nova API service
parameters:
 DockerNovaApiImage:
 description: image
 type: string
 DockerNovaConfigImage:
 description: The container image to use for the nova config_volume
 type: string
 EndpointMap:
 default: {}
 description: Mapping of service endpoint -> protocol. Typically set
 via parameter_defaults in the resource registry.
 type: json
 ServiceData:
 default: {}
 description: Dictionary packing service data
 type: json
 ServiceNetMap:
 default: {}
 description: Mapping of service_name -> network name. Typically set
 via parameter_defaults in the resource registry. This
 mapping overrides those in ServiceNetMapDefaults.
 type: json
 DefaultPasswords:
 default: {}
 type: json
 RoleName:
 default: ''
 description: Role name on which the service is applied
 type: string
 RoleParameters:
 default: {}
 description: Parameters specific to the role
 type: json
 EnableInternalTLS:
 type: boolean
 default: false
 UpgradeRemoveUnusedPackages:
 default: false
 description: Remove package if the service is being disabled during upgrade
 type: boolean
 DeployIdentifier:
 default: ''
 type: string
 description: >
 Setting this to a unique value will re-run any deployment tasks which
 perform configuration on a Heat stack-update.
conditions:
 internal_tls_enabled: {equals: [{get_param: EnableInternalTLS}, true]}
resources:
 ContainersCommon:
 type: ./containers-common.yaml
 MySQLClient:
 type: ../../puppet/services/database/mysql-client.yaml
 NovaApiBase:
 type: ../../puppet/services/nova-api.yaml
 properties:
 EndpointMap: {get_param: EndpointMap}
 ServiceData: {get_param: ServiceData}
 ServiceNetMap: {get_param: ServiceNetMap}
 DefaultPasswords: {get_param: DefaultPasswords}
 RoleName: {get_param: RoleName}
 RoleParameters: {get_param: RoleParameters}
outputs:
 role_data:
 description: Role data for the Nova API role.
 value:
 service_name: {get_attr: [NovaApiBase, role_data, service_name]}
 config_settings:
 map_merge:
 - get_attr: [NovaApiBase, role_data, config_settings]
 - apache::default_vhost: false
 logging_source: {get_attr: [NovaApiBase, role_data, logging_source]}
 logging_groups: {get_attr: [NovaApiBase, role_data, logging_groups]}
 step_config: &step_config
 list_join:
 - "\n"
 - - "['Nova_cell_v2'].each |String $val| { noop_resource($val) }"
 - {get_attr: [NovaApiBase, role_data, step_config]}
 - {get_attr: [MySQLClient, role_data, step_config]}
 service_config_settings: {get_attr: [NovaApiBase, role_data, service_config_settings]}
 # BEGIN DOCKER SETTINGS
 puppet_config:
 config_volume: nova
 puppet_tags: nova_config
 step_config: *step_config
 config_image: {get_param: DockerNovaConfigImage}
 kolla_config:
 /var/lib/kolla/config_files/nova_api.json:
 command: /usr/sbin/httpd -DFOREGROUND
 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
 /var/lib/kolla/config_files/nova_api_cron.json:
 command: /usr/sbin/crond -n
 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
 docker_config_scripts:
 nova_api_discover_hosts.sh:
 mode: "0700"
 content: |
 #!/bin/bash
 export OS_PROJECT_DOMAIN_NAME=$(crudini --get /etc/nova/nova.conf keystone_authtoken project_domain_name)
 export OS_USER_DOMAIN_NAME=$(crudini --get /etc/nova/nova.conf keystone_authtoken user_domain_name)
 export OS_PROJECT_NAME=$(crudini --get /etc/nova/nova.conf keystone_authtoken project_name)
 export OS_USERNAME=$(crudini --get /etc/nova/nova.conf keystone_authtoken username)
 export OS_PASSWORD=$(crudini --get /etc/nova/nova.conf keystone_authtoken password)
 export OS_AUTH_URL=$(crudini --get /etc/nova/nova.conf keystone_authtoken auth_url)
 export OS_AUTH_TYPE=password
 export OS_IDENTITY_API_VERSION=3
 echo "(cellv2) Running cell_v2 host discovery"
 timeout=600
 loop_wait=30
 declare -A discoverable_hosts
 for host in $(hiera -c /etc/puppet/hiera.yaml cellv2_discovery_hosts | sed -e '/^nil$/d' | tr "," " "); do discoverable_hosts[$host]=1; done
 timeout_at=$(( $(date +"%s") + ${timeout} ))
 echo "(cellv2) Waiting ${timeout} seconds for hosts to register"
 finished=0
 while : ; do
 for host in $(openstack -q compute service list -c 'Host' -c 'Zone' -f value | awk '$2 != "internal" { print $1 }'); do
 if (( discoverable_hosts[$host] == 1 )); then
 echo "(cellv2) compute node $host has registered"
 unset discoverable_hosts[$host]
 fi
 done
 finished=1
 for host in "${!discoverable_hosts[@]}"; do
 if (( ${discoverable_hosts[$host]} == 1 )); then
 echo "(cellv2) compute node $host has not registered"
 finished=0
 fi
 done
 remaining=$(( $timeout_at - $(date +"%s") ))
 if (( $finished == 1 )); then
 echo "(cellv2) All nodes registered"
 break
 elif (( $remaining <= 0 )); then
 echo "(cellv2) WARNING: timeout waiting for nodes to register, running host discovery regardless"
 echo "(cellv2) Expected host list:" $(hiera -c /etc/puppet/hiera.yaml cellv2_discovery_hosts | sed -e '/^nil$/d' | sort -u | tr ',' ' ')
 echo "(cellv2) Detected host list:" $(openstack -q compute service list -c 'Host' -c 'Zone' -f value | awk '$2 != "internal" { print $1 }' | sort -u | tr '\n', ' ')
 break
 else
 echo "(cellv2) Waiting ${remaining} seconds for hosts to register"
 sleep $loop_wait
 fi
 done
 echo "(cellv2) Running host discovery..."
 su nova -s /bin/bash -c "/usr/bin/nova-manage cell_v2 discover_hosts --verbose"
 nova_api_ensure_default_cell.sh:
 mode: "0700"
 content: |
 #!/bin/bash
 DEFID=$(nova-manage cell_v2 list_cells | sed -e '1,3d' -e '$d' | awk -F ' *| *' '$2 == "default" {print $4}')
 if [ "$DEFID" ]; then
 echo "(cellv2) Updating default cell_v2 cell $DEFID"
 su nova -s /bin/bash -c "/usr/bin/nova-manage cell_v2 update_cell --cell_uuid $DEFID --name=default"
 else
 echo "(cellv2) Creating default cell_v2 cell"
 su nova -s /bin/bash -c "/usr/bin/nova-manage cell_v2 create_cell --name=default"
 fi
 docker_config:
 # db sync runs before permissions set by kolla_config
 step_2:
 nova_init_logs:
 image: &nova_api_image {get_param: DockerNovaApiImage}
 privileged: false
 user: root
 volumes:
 - /var/log/containers/nova:/var/log/nova
 - /var/log/containers/httpd/nova-api:/var/log/httpd
 command: ['/bin/bash', '-c', 'chown -R nova:nova /var/log/nova']
 step_3:
 nova_api_db_sync:
 start_order: 0
 image: *nova_api_image
 net: host
 detach: false
 user: root
 volumes: &nova_api_bootstrap_volumes
 list_concat:
 - {get_attr: [ContainersCommon, volumes]}
 -
 - /var/lib/config-data/nova/etc/my.cnf.d/tripleo.cnf:/etc/my.cnf.d/tripleo.cnf:ro
 - /var/lib/config-data/nova/etc/nova/:/etc/nova/:ro
 - /var/log/containers/nova:/var/log/nova
 - /var/log/containers/httpd/nova-api:/var/log/httpd
 command: "/usr/bin/bootstrap_host_exec nova_api su nova -s /bin/bash -c '/usr/bin/nova-manage api_db sync'"
 nova_api_map_cell0:
 start_order: 1
 image: *nova_api_image
 net: host
 detach: false
 user: root
 volumes: *nova_api_bootstrap_volumes
 command: "/usr/bin/bootstrap_host_exec nova_api su nova -s /bin/bash -c '/usr/bin/nova-manage cell_v2 map_cell0'"
 nova_api_ensure_default_cell:
 start_order: 2
 image: *nova_api_image
 net: host
 detach: false
 volumes:
 list_concat:
 - *nova_api_bootstrap_volumes
 -
 - /var/lib/config-data/nova/etc/my.cnf.d/tripleo.cnf:/etc/my.cnf.d/tripleo.cnf:ro
 - /var/lib/config-data/nova/etc/nova/:/etc/nova/:ro
 - /var/log/containers/nova:/var/log/nova
 - /var/lib/docker-config-scripts/nova_api_ensure_default_cell.sh:/nova_api_ensure_default_cell.sh:ro
 user: root
 command: "/usr/bin/bootstrap_host_exec nova_api /nova_api_ensure_default_cell.sh"
 nova_db_sync:
 start_order: 3
 image: *nova_api_image
 net: host
 detach: false
 volumes: *nova_api_bootstrap_volumes
 user: root
 command: "/usr/bin/bootstrap_host_exec nova_api su nova -s /bin/bash -c '/usr/bin/nova-manage db sync'"
 step_4:
 nova_api:
 start_order: 2
 image: *nova_api_image
 net: host
 user: root
 privileged: true
 restart: always
 volumes:
 list_concat:
 - {get_attr: [ContainersCommon, volumes]}
 -
 - /var/lib/kolla/config_files/nova_api.json:/var/lib/kolla/config_files/config.json:ro
 - /var/lib/config-data/puppet-generated/nova/:/var/lib/kolla/config_files/src:ro
 - /var/log/containers/nova:/var/log/nova
 - /var/log/containers/httpd/nova-api:/var/log/httpd
 -
 if:
 - internal_tls_enabled
 - /etc/pki/tls/certs/httpd:/etc/pki/tls/certs/httpd:ro
 - ''
 -
 if:
 - internal_tls_enabled
 - /etc/pki/tls/private/httpd:/etc/pki/tls/private/httpd:ro
 - ''
 environment:
 - KOLLA_CONFIG_STRATEGY=COPY_ALWAYS
 nova_api_cron:
 image: *nova_api_image
 net: host
 user: root
 privileged: false
 restart: always
 healthcheck:
 test: /bin/true
 volumes:
 list_concat:
 - {get_attr: [ContainersCommon, volumes]}
 -
 - /var/lib/kolla/config_files/nova_api_cron.json:/var/lib/kolla/config_files/config.json:ro
 - /var/lib/config-data/puppet-generated/nova/:/var/lib/kolla/config_files/src:ro
 - /var/log/containers/nova:/var/log/nova
 - /var/log/containers/httpd/nova-api:/var/log/httpd
 environment:
 - KOLLA_CONFIG_STRATEGY=COPY_ALWAYS
 step_5:
 nova_api_discover_hosts:
 start_order: 1
 image: *nova_api_image
 net: host
 detach: false
 volumes:
 list_concat:
 - *nova_api_bootstrap_volumes
 -
 - /var/lib/config-data/nova/etc/my.cnf.d/tripleo.cnf:/etc/my.cnf.d/tripleo.cnf:ro
 - /var/lib/config-data/nova/etc/nova/:/etc/nova/:ro
 - /var/log/containers/nova:/var/log/nova
 - /var/lib/docker-config-scripts/nova_api_discover_hosts.sh:/nova_api_discover_hosts.sh:ro
 user: root
 command: "/usr/bin/bootstrap_host_exec nova_api /nova_api_discover_hosts.sh"
 environment:
 # NOTE: this should force this container to re-run on each
 # update (scale-out, etc.)
 - list_join:
 - ''
 - - 'TRIPLEO_DEPLOY_IDENTIFIER='
 - {get_param: DeployIdentifier}
 metadata_settings:
 get_attr: [NovaApiBase, role_data, metadata_settings]
 host_prep_tasks:
 - name: create persistent logs directory
 file:
 path: "{{ item }}"
 state: directory
 with_items:
 - /var/log/containers/nova
 - /var/log/containers/httpd/nova-api
 upgrade_tasks:
 - name: Stop and disable nova_api service
 tags: step2
 service: name=openstack-nova-api state=stopped enabled=no
 - name: Remove openstack-nova-api package if operator requests it
 yum: name=openstack-nova-api state=removed
 tags: step2
 ignore_errors: True
 when: {get_param: UpgradeRemoveUnusedPackages}
 - name: remove old nova cron jobs
 tags: step2
 file:
 path: /var/spool/cron/nova
 state: absent
To know the command line that will be used for a specific container you can use:
$ sudo paunch debug --file /var/lib/tripleo-config/docker-container-startup-config-step_3.json --container ironic_db_sync --action print-cmd
For more information