{%- set _networks = [] -%} {%- for network in networks -%} {%- set _networks = _networks.append(network.name) -%} {%- endfor -%} heat_template_version: rocky description: 'All Nodes Config for Puppet' parameters: {%- for network in networks if network.vip|default(false) %} cloud_name_{{network.name_lower}}: type: string {%- endfor %} cloud_name_ctlplane: type: string enabled_services: type: comma_delimited_list controller_ips: type: comma_delimited_list service_ips: type: json service_node_names: type: json short_service_node_names: type: json short_service_bootstrap_node: type: json controller_names: type: comma_delimited_list NetVipMap: type: json RedisVirtualIP: type: string default: '' ServiceNetMap: type: json DeployIdentifier: type: string default: '' description: > Setting this to a unique value will re-run any deployment tasks which perform configuration on a Heat stack-update. UpdateIdentifier: type: string default: '' description: > Setting to a previously unused value during stack-update will trigger package update on all nodes StackAction: type: string description: > Heat action on performed top-level stack. Note StackUpdateType is set to UPGRADE when a major-version upgrade is in progress. constraints: - allowed_values: ['CREATE', 'UPDATE'] StackUpdateType: type: string description: > Type of update, to differentiate between UPGRADE and UPDATE cases when StackAction is UPDATE (both are the same stack action). constraints: - allowed_values: ['', 'UPGRADE', 'FASTFORWARDUPGRADE'] default: '' EnableInternalTLS: type: boolean default: false AllNodesExtraMapData: type: json default: {} description: Map of extra data (hieradata) to set on each node. {%- for network in networks %} {{network.name}}NetName: default: {{network.name_lower}} description: The name of the {{network.name_lower}} network. type: string {%- endfor %} resources: allNodesConfigValue: type: OS::Heat::Value properties: value: yaql: expression: $.data.all_nodes_extra_map_data.mergeWith($.data.all_nodes) data: all_nodes_extra_map_data: {get_param: AllNodesExtraMapData} all_nodes: map_merge: - enabled_services: yaql: expression: $.data.distinct() data: {get_param: enabled_services} # This writes out a mapping of service_name_enabled: 'true' # For any services not enabled, hiera foo_enabled will # return nil, as it's undefined - map_merge: repeat: template: # Note this must be string 'true' due to # https://bugs.launchpad.net/heat/+bug/1617203 SERVICE_enabled: 'true' for_each: SERVICE: {get_param: enabled_services} # Dynamically generate per-service network data # This works as follows (outer->inner functions) # yaql - filters services where no mapping exists in ServiceNetMap # map_replace: substitute e.g heat_api_network with network name from ServiceNetMap # map_merge/repeat: generate a per-service mapping - yaql: # This filters any entries where the value hasn't been substituted for # a list, e.g it's still $service_network. This happens when there is # no network defined for the service in the ServiceNetMap, which is OK # as not all services have to be bound to a network, so we filter them expression: dict($.data.map.items().where(isString($[1]) and not $[1].endsWith("_network"))) data: map: map_replace: - map_merge: repeat: template: SERVICE_network: SERVICE_network for_each: SERVICE: {get_param: enabled_services} - values: {get_param: ServiceNetMap} # Keystone doesn't provide separate entries for the public # and admin endpoints, so we need to add them here manually # like we do in the vip-config below - keystone_admin_api_network: {get_param: [ServiceNetMap, keystone_admin_api_network]} keystone_public_api_network: {get_param: [ServiceNetMap, keystone_public_api_network]} # provides a mapping of service_name_ips to a list of IPs - {get_param: service_ips} - {get_param: service_node_names} - {get_param: short_service_node_names} - {get_param: short_service_bootstrap_node} - controller_node_ips: list_join: - ',' - {get_param: controller_ips} controller_node_names: list_join: - ',' - {get_param: controller_names} deploy_identifier: {get_param: DeployIdentifier} update_identifier: {get_param: UpdateIdentifier} stack_action: {get_param: StackAction} stack_update_type: {get_param: StackUpdateType} allNodesConfigImpl: type: OS::Heat::StructuredConfig properties: group: hiera config: datafiles: bootstrap_node: bootstrap_nodeid: {get_input: bootstrap_nodeid} bootstrap_nodeid_ip: {get_input: bootstrap_nodeid_ip} all_nodes: {get_attr: [allNodesConfigValue, value]} vip_data: map_merge: # Dynamically generate per-service VIP data based on enabled_services # This works as follows (outer->inner functions) # yaql - filters services where no mapping exists in ServiceNetMap # map_replace: substitute e.g internal_api with the IP from NetVipMap # map_replace: substitute e.g heat_api_network with network name from ServiceNetMap # map_merge/repeat: generate a per-service mapping - yaql: # This filters any entries where the value hasn't been substituted for # a list, e.g it's still $service_network. This happens when there is # no network defined for the service in the ServiceNetMap, which is OK # as not all services have to be bound to a network, so we filter them expression: dict($.data.map.items().where(isString($[1]) and not $[1].endsWith("_network"))) data: map: map_replace: - map_replace: - map_merge: repeat: template: SERVICE_vip: SERVICE_network for_each: SERVICE: {get_param: enabled_services} - values: {get_param: ServiceNetMap} - values: {get_param: NetVipMap} - keystone_admin_api_vip: get_param: [NetVipMap, {get_param: [ServiceNetMap, keystone_admin_api_network]}] keystone_public_api_vip: get_param: [NetVipMap, {get_param: [ServiceNetMap, keystone_public_api_network]}] public_virtual_ip: {get_param: [NetVipMap, {get_param: ExternalNetName}]} controller_virtual_ip: {get_param: [NetVipMap, ctlplane]} {%- if 'InternalApi' in _networks %} # the internal_api_virtual_ip is needed for contrail only internal_api_virtual_ip: {get_param: [NetVipMap, {get_param: InternalApiNetName}]} {%- endif %} network_virtual_ips: {%- for network in networks if network.vip|default(false) %} # External virtual ip is currently being handled separately as public_virtual_ip. # Likewise, optional StorageNFS virtual ip is handled separately as ganesha_vip. {%- if network.name != 'External' and network.name != 'StorageNFS' %} {{network.name_lower}}: ip_address: {get_param: [NetVipMap, {get_param: {{network.name}}NetName}]} index: {{loop.index}} {%- endif %} {%- endfor %} redis_vip: {get_param: RedisVirtualIP} {%- for network in networks if network.name == 'StorageNFS' %} ganesha_vip: {get_param: [NetVipMap, {get_param: StorageNFSNetName}]} {%- endfor %} # public_virtual_ip and controller_virtual_ip are needed in # both HAproxy & keepalived. tripleo::haproxy::public_virtual_ip: {get_param: [NetVipMap, {get_param: ExternalNetName}]} tripleo::haproxy::controller_virtual_ip: {get_param: [NetVipMap, ctlplane]} tripleo::keepalived::public_virtual_ip: {get_param: [NetVipMap, {get_param: ExternalNetName}]} tripleo::keepalived::controller_virtual_ip: {get_param: [NetVipMap, ctlplane]} tripleo::keepalived::redis_virtual_ip: {get_param: RedisVirtualIP} tripleo::redis_notification::haproxy_monitor_ip: {get_param: [NetVipMap, ctlplane]} {%- for network in networks if network.vip|default(false) %} cloud_name_{{network.name_lower}}: {get_param: cloud_name_{{network.name_lower}}} {%- endfor %} cloud_name_ctlplane: {get_param: cloud_name_ctlplane} enable_internal_tls: {get_param: EnableInternalTLS} outputs: config_id: description: The ID of the allNodesConfigImpl resource. value: {get_resource: allNodesConfigImpl} all_nodes_config: description: The all_nodes hieradata config value: {get_attr: [allNodesConfigValue, value]}