break out network-isolation prep into it's own role

This commit is contained in:
Wesley Hayutin 2016-08-18 17:09:44 -04:00
parent d8937f732d
commit d50d4847e3
11 changed files with 74 additions and 634 deletions

View File

@ -1,17 +1,9 @@
undercloud_config_file: undercloud.conf.j2
undercloud_install_script: undercloud-install.sh.j2
undercloud_post_install_script: undercloud-install-post.sh.j2
undercloud_install_log: "{{ working_dir }}/undercloud_install.log"
undercloud_post_install_log: "{{ working_dir }}/undercloud_post_install.log"
network_environment_file: network-environment.yaml.j2
undercloud_hieradata_override_file: quickstart-hieradata-overrides.yaml.j2
overcloud_prep_network_script: overcloud-prep-network.sh.j2
overcloud_prep_network_log: "{{ working_dir }}/overcloud_prep_network.log"
etwork_environment_file: network-environment.yaml.j2
undercloud_network_cidr: 192.0.2.0/24
step_introspect: false
bash_deploy_ramdisk: false
step_install_undercloud: true
network_environment_args:
ExternalNetCidr: "{{ undercloud_external_network_cidr }}"
ExternalAllocationPools: >
@ -22,8 +14,3 @@ network_environment_args:
ControlPlaneDefaultRoute: "{{ undercloud_network_cidr|nthhost(1) }}"
EC2MetadataIp: "{{ undercloud_network_cidr|nthhost(1) }}"
DnsServers: [ '{{ external_network_cidr|nthhost(1) }}' ]
# Which libvirt session should we use? Using `qemu://session` does
# not require privileged access (but does require the setup performed by the
# `environment/setup` role).
libvirt_uri: qemu:///session

View File

@ -1,25 +1,7 @@
# Creat the scripts that will be used to deploy the undercloud
# environment.
- name: Create undercloud configuration
template:
src: "{{ undercloud_config_file }}"
dest: "./undercloud.conf"
mode: 0600
# Creat the overcloud-prep-network scripts that will be used to setup the undercloud for network isolation
- name: Create undercloud hieradata overrides
- name: Create overcloud-prep-network script
template:
src: "{{ undercloud_hieradata_override_file }}"
dest: "./quickstart-hieradata-overrides.yaml"
mode: 0600
- name: Create undercloud install script
template:
src: "{{ undercloud_install_script }}"
dest: "{{ working_dir }}/undercloud-install.sh"
mode: 0755
- name: Create undercloud post-install script
template:
src: "{{ undercloud_post_install_script }}"
dest: "{{ working_dir }}/undercloud-post-install.sh"
src: "{{ overcloud_prep_network_script }}"
dest: "{{ working_dir }}/overcloud-prep-network.sh"
mode: 0755

View File

@ -1,19 +0,0 @@
- name: Prepare directory with extra logs
file: dest=/var/log/extra state=directory
become: true
# No need to install dstat package here because it is part of the images
- name: Run dstat for collecting metrics during 2 hours
command: >
dstat -tcmndrylpg --nocolor --output /var/log/extra/dstat-csv.log 1 7200 \
>/dev/null
async: 7200
poll: 0
become: true
when: step_install_undercloud
- name: Install the undercloud
shell: |
{{ working_dir }}/undercloud-install.sh > \
{{ undercloud_install_log }} 2>&1
when: step_install_undercloud

View File

@ -2,35 +2,6 @@
tags:
- undercloud-scripts
- include: install-undercloud.yml
tags:
- undercloud-install
# Ironic defaults to using `qemu:///system`. When running libvirtd
# unprivileged we need to use `qemu:///session`. This allows us to pass
# the value of libvirt_uri into /etc/ironic/ironic.conf.
- name: Configure Ironic pxe_ssh driver
when: release in ['mitaka', 'liberty']
delegate_to: undercloud
ini_file:
dest: /etc/ironic/ironic.conf
section: ssh
option: libvirt_uri
value: '{{ libvirt_uri }}'
become: true
tags:
- undercloud-install
- name: restart ironic conductor after changing configuration
when: release in ['mitaka', 'liberty']
become: true
service:
name: openstack-ironic-conductor
enabled: yes
state: restarted
tags:
- undercloud-install
- include: post-install.yml
tags:
- undercloud-post-install
- overcloud-prep-network.yml

View File

@ -0,0 +1,13 @@
- name: Prepare the network-isolation required networks on the undercloud
shell: |
{{ working_dir }}/overcloud-prep-network.sh > \
{{ overcloud_prep_network_log }} 2>&1
- name: Create network environment file for network isolation
tags:
- undercloud-scripts
template:
src: "{{ network_environment_file }}"
dest: "{{ working_dir }}/network-environment.yaml"
mode: 0755
when: network_isolation

View File

@ -1,39 +0,0 @@
# Extract the undercloud admin password from
# `undercloud-passwords.conf`.
- name: Get undercloud admin password
command: >
awk -F= '$1 == "undercloud_admin_password" {print $2}'
{{ working_dir }}/undercloud-passwords.conf
register: undercloud_admin_password
- name: Copy stackrc to ansible host
tags:
- undercloud-post-install
fetch:
flat: true
src: stackrc
dest: "{{ local_working_dir }}/stackrc"
# We need this (and the previous task) in order to replace the
# `sudo hiera admin_password` with an actual password in the `stackrc`
# file.
- name: Update admin password in local credentials file
delegate_to: localhost
lineinfile:
dest: "{{ local_working_dir }}/stackrc"
line: "export OS_PASSWORD={{ undercloud_admin_password.stdout }}"
regexp: "OS_PASSWORD"
- name: Prepare the undercloud for deploy
shell: |
{{ working_dir }}/undercloud-post-install.sh > \
{{ undercloud_post_install_log }} 2>&1
- name: Create network environment file for network isolation
tags:
- undercloud-scripts
template:
src: "{{ network_environment_file }}"
dest: "{{ working_dir }}/network-environment.yaml"
mode: 0755
when: network_isolation

View File

@ -0,0 +1,53 @@
#!/bin/bash
set -eux
### --start_docs
## --------------------------------------------------
## Prepare the undercloud for deploying the overcloud
## --------------------------------------------------
## ########################
## Prepare Your Environment
## ########################
## * Source in the undercloud credentials.
## ::
source {{ working_dir }}/stackrc
{% if network_isolation == true and ipv6 == false %}
## ################
## Setup Networking
## ################
## * Enable NAT for "external" network.
## ::
RULE="-s {{undercloud_external_network_cidr}} ! -d {{undercloud_external_network_cidr}} -j MASQUERADE"
if ! sudo iptables -t nat -C BOOTSTACK_MASQ $RULE; then
sudo iptables -t nat -A BOOTSTACK_MASQ $RULE
sudo sh -c 'iptables-save > /etc/sysconfig/iptables'
fi
{% for name, network in (undercloud_networks|default({})).items() if name == 'external' %}
sudo bash -c 'cat <<EOF > /etc/sysconfig/network-scripts/ifcfg-vlan{{ network.tag }}
DEVICE=vlan{{ network.tag }}
ONBOOT=yes
DEVICETYPE={{ network.device_type }}
TYPE={{ network.type }}
BOOTPROTO=static
IPADDR={{ network.address }}
NETMASK={{ network.netmask }}
OVS_BRIDGE={{ network.ovs_bridge }}
OVS_OPTIONS={{ network.ovs_options }}
EOF'
sudo ifup ifcfg-vlan{{ network.tag }}
{% endfor %}
{%endif%}
### --stop_docs

View File

@ -1,4 +0,0 @@
# Ironic defaults to using `qemu:///system`. When running libvirtd
# unprivileged we need to use `qemu:///session`. This allows us to pass
# the value of libvirt_uri into /etc/ironic/ironic.conf.
ironic::drivers::ssh::libvirt_uri: '{{libvirt_uri}}'

View File

@ -1,124 +0,0 @@
#!/bin/bash
set -eux
### --start_docs
## --------------------------------------------------
## Prepare the undercloud for deploying the overcloud
## --------------------------------------------------
## ########################
## Prepare Your Environment
## ########################
## * Source in the undercloud credentials.
## ::
source {{ working_dir }}/stackrc
## * Upload images to glance.
## ::
openstack overcloud image upload {% if bash_deploy_ramdisk %}--old-deploy-image{% endif %}
## * Register nodes with Ironic.
## ::
openstack baremetal import --json instackenv.json
openstack baremetal configure boot
{% if step_introspect %}
## * Introspect hardware attributes of nodes.
## ::
openstack baremetal introspection bulk start
{% endif %}
## ##############
## Flavor Details
## ##############
## * Create flavor oooq_<name> for each flavor in the ansible `flavors` variable.
{% for name, flavor in (flavors|default({})).items() if name != 'undercloud' %}
## * Remove flavor before attempting to create.
## ::
nova flavor-delete oooq_{{ name }} > /dev/null 2>&1 || true
## * We subtract 1 from the total disk size here to resolve problems
## encountered in CI in which the available disk space on the virtual
## nodes was slightly less than what we requested.
## ::
openstack flavor create --id auto \
--ram {{flavor.memory}} \
--disk $(( {{flavor.disk}} - 1)) \
--vcpus {{flavor.vcpu}} \
oooq_{{ name }}
openstack flavor set \
--property "cpu_arch"="x86_64" \
--property "capabilities:boot_option"="local" \
--property "capabilities:profile"="{{ name }}" oooq_{{ name }}
{% for propname,propval in (flavor.properties|default({})).items() %}
openstack flavor set --property "{{propname}}={{propval}}" oooq_{{ name }}
{% endfor %}
{% endfor %}
{% if network_isolation == true and ipv6 == false %}
## ################
## Setup Networking
## ################
## * Enable NAT for "external" network.
## ::
RULE="-s {{undercloud_external_network_cidr}} ! -d {{undercloud_external_network_cidr}} -j MASQUERADE"
if ! sudo iptables -t nat -C BOOTSTACK_MASQ $RULE; then
sudo iptables -t nat -A BOOTSTACK_MASQ $RULE
sudo sh -c 'iptables-save > /etc/sysconfig/iptables'
fi
{% for name, network in (undercloud_networks|default({})).items() if name == 'external' %}
sudo bash -c 'cat <<EOF > /etc/sysconfig/network-scripts/ifcfg-vlan{{ network.tag }}
DEVICE=vlan{{ network.tag }}
ONBOOT=yes
DEVICETYPE={{ network.device_type }}
TYPE={{ network.type }}
BOOTPROTO=static
IPADDR={{ network.address }}
NETMASK={{ network.netmask }}
OVS_BRIDGE={{ network.ovs_bridge }}
OVS_OPTIONS={{ network.ovs_options }}
EOF'
sudo ifup ifcfg-vlan{{ network.tag }}
{% endfor %}
{%endif%}
{% if overcloud_templates_repo is defined and overcloud_templates_path is defined %}
## * Clone the t-h-t templates if needed.
## ::
rm -rf {{ overcloud_templates_path }}
git clone {% if overcloud_templates_branch is defined %}-b {{ overcloud_templates_branch }} \
--single-branch{% endif %} {{ overcloud_templates_repo }} {{ overcloud_templates_path }}
{% if overcloud_templates_refspec is defined %}
## * Checkout an open t-h-t review if specified
## (this will stomp on the overcloud_templates_branch, so only one should be used).
## ::
pushd {{overcloud_templates_path}}
git fetch {{ overcloud_templates_repo }} {{ overcloud_templates_refspec }} && git checkout FETCH_HEAD
popd
{% endif %}
{% endif %}
### --stop_docs

View File

@ -1,16 +0,0 @@
#!/bin/bash
set -eux
### --start_docs
## -------------------------
## Installing the undercloud
## -------------------------
## ::
{% for var in (undercloud_env_vars|default([])) %}
export {{ var }}
{% endfor %}
openstack undercloud install
### --stop_docs

View File

@ -1,364 +0,0 @@
[DEFAULT]
#
# From instack-undercloud
#
# Local file path to the necessary images. The path should be a
# directory readable by the current user that contains the full set of
# images. (string value)
{% if undercloud_image_path is defined %}
image_path = {{undercloud_image_path}}
{% else %}
#image_path = .
{% endif %}
# Fully qualified hostname (including domain) to set on the
# Undercloud. If left unset, the current hostname will be used, but
# the user is responsible for configuring all system hostname settings
# appropriately. If set, the undercloud install will configure all
# system hostname settings. (string value)
{% if undercloud_undercloud_hostname is defined %}
undercloud_hostname = {{undercloud_undercloud_hostname}}
{% else %}
#undercloud_hostname = <None>
{% endif %}
# Network CIDR for the Neutron-managed network for Overcloud
# instances. This should be the subnet used for PXE booting. (string
# value)
network_cidr = {{undercloud_network_cidr}}
# IP information for the interface on the Undercloud that will be
# handling the PXE boots and DHCP for Overcloud instances. The IP
# portion of the value will be assigned to the network interface
# defined by local_interface, with the netmask defined by the prefix
# portion of the value. (string value)
local_ip = {{undercloud_local_ip|default(
'%s/%s' % (undercloud_network_cidr|nthhost(1),
undercloud_network_cidr.split('/').1))}}
# Network gateway for the Neutron-managed network for Overcloud
# instances. This should match the local_ip above when using
# masquerading. (string value)
network_gateway = {{undercloud_network_gateway|default(
undercloud_network_cidr|nthhost(1))}}
# Virtual IP address to use for the public endpoints of Undercloud
# services. Only used if undercloud_service_certficate is set.
# (string value)
{% if undercloud_undercloud_public_vip is defined %}
undercloud_public_vip = {{undercloud_undercloud_public_vip}}
{% else %}
#undercloud_public_vip = 192.0.2.2
{% endif %}
# Virtual IP address to use for the admin endpoints of Undercloud
# services. Only used if undercloud_service_certficate is set.
# (string value)
{% if undercloud_undercloud_admin_vip is defined %}
undercloud_admin_vip = {{undercloud_undercloud_admin_vip}}
{% else %}
#undercloud_admin_vip = 192.0.2.3
{% endif %}
# Certificate file to use for OpenStack service SSL connections.
# Setting this enables SSL for the OpenStack API endpoints, leaving it
# unset disables SSL. (string value)
#undercloud_service_certificate =
# When set to True, an SSL certificate will be generated as part of
# the undercloud install and this certificate will be used in place of
# the value for undercloud_service_certificate. The resulting
# certificate will be written to
# /etc/pki/tls/certs/undercloud-[undercloud_public_vip].pem. This
# certificate is signed by CA selected by the
# "certificate_generation_ca" option. (boolean value)
#generate_service_certificate = false
{% if undercloud_generate_service_certificate is defined %}
generate_service_certificate = {{undercloud_generate_service_certificate}}
{% endif %}
# The certmonger nickname of the CA from which the certificate will be
# requested. This is used only if the generate_service_certificate
# option is set. Note that if the "local" CA is selected the
# certmonger's local CA certificate will be extracted to /etc/pki/ca-
# trust/source/anchors/cm-local-ca.pem and subsequently added to the
# trust chain. (string value)
#certificate_generation_ca = local
{% if undercloud_certificate_generation_ca is defined %}
certificate_generation_ca = {{undercloud_certificate_generation_ca}}
{% endif %}
# Network interface on the Undercloud that will be handling the PXE
# boots and DHCP for Overcloud instances. (string value)
{% if undercloud_local_interface is defined %}
local_interface = {{undercloud_local_interface}}
{% else %}
#local_interface = eth1
{% endif %}
# Network that will be masqueraded for external access, if required.
# This should be the subnet used for PXE booting. (string value)
masquerade_network = {{undercloud_masquerade_network|default(
undercloud_network_cidr)}}
# Start of DHCP allocation range for PXE and DHCP of Overcloud
# instances. (string value)
dhcp_start = {{undercloud_dhcp_start|default(
undercloud_network_cidr|nthhost(5))}}
# End of DHCP allocation range for PXE and DHCP of Overcloud
# instances. (string value)
dhcp_end = {{undercloud_dhcp_end|default(
undercloud_network_cidr|nthhost(30))}}
# Path to hieradata override file. If set, the file will be copied
# under /etc/puppet/hieradata and set as the first file in the hiera
# hierarchy. This can be used to to custom configure services beyond
# what undercloud.conf provides (string value)
hieradata_override = quickstart-hieradata-overrides.yaml
# Network interface on which inspection dnsmasq will listen. If in
# doubt, use the default value. (string value)
# Deprecated group/name - [DEFAULT]/discovery_interface
{% if undercloud_inspection_interface is defined %}
inspection_interface = {{undercloud_inspection_interface}}
{% else %}
#inspection_interface = br-ctlplane
{% endif %}
# Temporary IP range that will be given to nodes during the inspection
# process. Should not overlap with the range defined by dhcp_start
# and dhcp_end, but should be in the same network. (string value)
# Deprecated group/name - [DEFAULT]/discovery_iprange
inspection_iprange = {{undercloud_inspection_iprange|default(
'%s,%s' % (undercloud_network_cidr|nthhost(100),
undercloud_network_cidr|nthhost(120)))}}
# Whether to run benchmarks when inspecting nodes. (boolean value)
# Deprecated group/name - [DEFAULT]/discovery_runbench
{% if undercloud_inspection_runbench is defined %}
inspection_runbench = {{undercloud_inspection_runbench}}
{% else %}
#inspection_runbench = false
{% endif %}
# Whether to enable the debug log level for Undercloud OpenStack
# services. (boolean value)
{% if undercloud_undercloud_debug is defined %}
undercloud_debug = {{undercloud_undercloud_debug}}
{% else %}
#undercloud_debug = true
{% endif %}
# Whether to install Tempest in the Undercloud. (boolean value)
{% if undercloud_enable_tempest is defined %}
enable_tempest = {{undercloud_enable_tempest}}
{% else %}
#enable_tempest = true
{% endif %}
# Whether to install Mistral in the Undercloud. (boolean value)
{% if undercloud_enable_mistral is defined %}
enable_mistral = {{undercloud_enable_mistral}}
{% else %}
#enable_mistral = false
{% endif %}
# Whether to use iPXE for deploy by default. (boolean value)
{% if undercloud_ipxe_deploy is defined %}
ipxe_deploy = {{undercloud_ipxe_deploy}}
{% else %}
#ipxe_deploy = true
{% endif %}
# Whether to install Monitoring services in the Undercloud. (boolean
# value)
{% if undercloud_enable_monitoring is defined %}
enable_monitoring = {{undercloud_enable_monitoring}}
{% else %}
#enable_monitoring = false
{% endif %}
[auth]
#
# From instack-undercloud
#
# Password used for MySQL databases. If left unset, one will be
# automatically generated. (string value)
{% if undercloud_undercloud_db_password is defined %}
undercloud_db_password = {{undercloud_undercloud_db_password}}
{% else %}
#undercloud_db_password = <None>
{% endif %}
# Keystone admin token. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_admin_token is defined %}
undercloud_admin_token = {{undercloud_undercloud_admin_token}}
{% else %}
#undercloud_admin_token = <None>
{% endif %}
# Keystone admin password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_admin_password is defined %}
undercloud_admin_password = {{undercloud_undercloud_admin_password}}
{% else %}
#undercloud_admin_password = <None>
{% endif %}
# Glance service password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_glance_password is defined %}
undercloud_glance_password = {{undercloud_undercloud_glance_password}}
{% else %}
#undercloud_glance_password = <None>
{% endif %}
# Heat db encryption key(must be 16, 24, or 32 characters. If left
# unset, one will be automatically generated. (string value)
{% if undercloud_undercloud_heat_encryption_key is defined %}
undercloud_heat_encryption_key = {{undercloud_undercloud_heat_encryption_key}}
{% else %}
#undercloud_heat_encryption_key = <None>
{% endif %}
# Heat service password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_heat_password is defined %}
undercloud_heat_password = {{undercloud_undercloud_heat_password}}
{% else %}
#undercloud_heat_password = <None>
{% endif %}
# Neutron service password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_neutron_password is defined %}
undercloud_neutron_password = {{undercloud_undercloud_neutron_password}}
{% else %}
#undercloud_neutron_password = <None>
{% endif %}
# Nova service password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_nova_password is defined %}
undercloud_nova_password = {{undercloud_undercloud_nova_password}}
{% else %}
#undercloud_nova_password = <None>
{% endif %}
# Ironic service password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_ironic_password is defined %}
undercloud_ironic_password = {{undercloud_undercloud_ironic_password}}
{% else %}
#undercloud_ironic_password = <None>
{% endif %}
# Ceilometer service password. If left unset, one will be
# automatically generated. (string value)
{% if undercloud_undercloud_ceilometer_password is defined %}
undercloud_ceilometer_password = {{undercloud_undercloud_ceilometer_password}}
{% else %}
#undercloud_ceilometer_password = <None>
{% endif %}
# Aodh service password. If left unset, one will be
# automatically generated. (string value)
{% if undercloud_undercloud_aodh_password is defined %}
undercloud_aodh_password = {{undercloud_undercloud_aodh_password}}
{% else %}
#undercloud_aodh_password = <None>
{% endif %}
# Sensu service password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_sensu_password is defined %}
undercloud_sensu_password = {{undercloud_undercloud_sensu_password}}
{% else %}
#undercloud_sensu_password = <None>
{% endif %}
# Ceilometer metering secret. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_ceilometer_metering_secret is defined %}
undercloud_ceilometer_metering_secret = {{undercloud_undercloud_ceilometer_metering_secret}}
{% else %}
#undercloud_ceilometer_metering_secret = <None>
{% endif %}
# Ceilometer snmpd user. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_ceilometer_snmpd_user is defined %}
undercloud_ceilometer_snmpd_user = {{undercloud_undercloud_ceilometer_snmpd_user}}
{% else %}
#undercloud_ceilometer_snmpd_user = <None>
{% endif %}
# Ceilometer snmpd password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_ceilometer_snmpd_password is defined %}
undercloud_ceilometer_snmpd_password = {{undercloud_undercloud_ceilometer_snmpd_password}}
{% else %}
#undercloud_ceilometer_snmpd_password = <None>
{% endif %}
# Swift service password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_swift_password is defined %}
undercloud_swift_password = {{undercloud_undercloud_swift_password}}
{% else %}
#undercloud_swift_password = <None>
{% endif %}
# Mistral service password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_mistral_password is defined %}
undercloud_mistral_password = {{undercloud_undercloud_mistral_password}}
{% else %}
#undercloud_mistral_password = <None>
{% endif %}
# Rabbitmq cookie. If left unset, one will be automatically generated.
# (string value)
{% if undercloud_undercloud_rabbit_cookie is defined %}
undercloud_rabbit_cookie = {{undercloud_undercloud_rabbit_cookie}}
{% else %}
#undercloud_rabbit_cookie = <None>
{% endif %}
# Rabbitmq password. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_rabbit_password is defined %}
undercloud_rabbit_password = {{undercloud_undercloud_rabbit_password}}
{% else %}
#undercloud_rabbit_password = <None>
{% endif %}
# Rabbitmq username. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_rabbit_username is defined %}
undercloud_rabbit_username = {{undercloud_undercloud_rabbit_username}}
{% else %}
#undercloud_rabbit_username = <None>
{% endif %}
# Heat stack domain admin password. If left unset, one will be
# automatically generated. (string value)
{% if undercloud_undercloud_heat_stack_domain_admin_password is defined %}
undercloud_heat_stack_domain_admin_password = {{undercloud_undercloud_heat_stack_domain_admin_password}}
{% else %}
#undercloud_heat_stack_domain_admin_password = <None>
{% endif %}
# Swift hash suffix. If left unset, one will be automatically
# generated. (string value)
{% if undercloud_undercloud_swift_hash_suffix is defined %}
undercloud_swift_hash_suffix = {{undercloud_undercloud_swift_hash_suffix}}
{% else %}
#undercloud_swift_hash_suffix = <None>
{% endif %}