1 {%- set primary_role = [roles[0]] -%}
2 {%- for role in roles -%}
3 {%- if 'primary' in role.tags and 'controller' in role.tags -%}
4 {%- set _ = primary_role.pop() -%}
5 {%- set _ = primary_role.append(role) -%}
8 {%- set primary_role_name = primary_role[0].name -%}
9 # primary role is: {{primary_role_name}}
10 heat_template_version: pike
13 Deploy an OpenStack environment, consisting of several node types (roles),
14 Controller, Compute, BlockStorage, SwiftStorage and CephStorage. The Storage
15 roles enable independent scaling of the storage components, but the minimal
16 deployment is one Controller and one Compute node.
19 # TODO(shadower): we should probably use the parameter groups to put
23 # Common parameters (not specific to a role)
24 {%- for network in networks if network.vip|default(false) %}
25 {%- if network.name == 'External' %}
26 # Special case the External hostname param, which is CloudName
28 default: overcloud.localdomain
29 description: The DNS name of this cloud. E.g. ci-overcloud.tripleo.org
31 {%- elif network.name == 'InternalApi' %}
32 # Special case the Internal API hostname param, which is CloudNameInternal
34 default: overcloud.{{network.name.lower()}}.localdomain
36 The DNS name of this cloud's {{network.name_lower}} endpoint. E.g.
37 'ci-overcloud.{{network.name.lower()}}.tripleo.org'.
39 {%- elif network.name == 'StorageMgmt' %}
40 # Special case StorageMgmt hostname param, which is CloudNameStorageManagement
41 CloudNameStorageManagement:
42 default: overcloud.{{network.name.lower()}}.localdomain
44 The DNS name of this cloud's {{network.name_lower}} endpoint. E.g.
45 'ci-overcloud.{{network.name.lower()}}.tripleo.org'.
48 CloudName{{network.name}}:
49 default: overcloud.{{network.name.lower()}}.localdomain
51 The DNS name of this cloud's {{network.name_lower}} endpoint. E.g.
52 'ci-overcloud.{{network.name.lower()}}.tripleo.org'.
57 default: overcloud.ctlplane.localdomain
59 The DNS name of this cloud's provisioning network endpoint. E.g.
60 'ci-overcloud.ctlplane.tripleo.org'.
65 Additional hiera configuration to inject into the cluster.
67 {%- for role in roles %}
68 {{role.name}}ExtraConfig:
71 Role specific additional hiera configuration to inject into the cluster.
73 {%- if role.deprecated_param_extraconfig is defined %}
74 {{role.deprecated_param_extraconfig}}:
77 DEPRECATED use {{role.name}}ExtraConfig instead
81 NeutronControlPlaneID:
84 description: Neutron ID or name for ctlplane network.
85 NeutronPublicInterface:
87 description: Which interface to add to the NeutronPhysicalBridge.
92 Control the IP allocation for the ControlVirtualIP port. E.g.
93 [{'ip_address':'1.2.3.4'}]
95 {%- for network in networks if network.vip|default(false) %}
96 {%- if network.name == 'External' %}
97 # TODO (dsneddon) Legacy name, eventually refactor to match network name
98 PublicVirtualFixedIPs:
101 Control the IP allocation for the PublicVirtualInterface port. E.g.
102 [{'ip_address':'1.2.3.4'}]
105 {{network.name}}VirtualFixedIPs:
108 Control the IP allocation for the {{network.name}}VirtualInterface port. E.g.
109 [{'ip_address':'1.2.3.4'}]
116 description: Salt for the rabbit cookie, change this to force the randomly generated rabbit cookie to change.
117 RedisVirtualFixedIPs:
120 Control the IP allocation for the virtual IP used by Redis. E.g.
121 [{'ip_address':'1.2.3.4'}]
124 default: 'localdomain'
127 The DNS domain used for the hosts. This must match the
128 overcloud_domain_name configured on the undercloud.
132 Extra properties or metadata passed to Nova for the created nodes in
133 the overcloud. It's accessible via the Nova metadata API.
136 # Compute-specific params
137 # FIXME(shardy) handle these deprecated names as they don't match compute.yaml
138 HypervisorNeutronPhysicalBridge:
141 An OVS bridge to create on each hypervisor. This defaults to br-ex the
142 same as the control plane nodes, as we have a uniform configuration of
143 the openvswitch agent. Typically should not need to be changed.
145 HypervisorNeutronPublicInterface:
147 description: What interface to add to the HypervisorNeutronPhysicalBridge.
152 description: Maxiumum batch size for creating nodes
155 # Jinja loop for Role in role_data.yaml
156 {% for role in roles %}
157 # Parameters generated for {{role.name}} Role
158 {{role.name}}Services:
159 description: A list of service resources (configured in the Heat
160 resource_registry) which represent nested stacks
161 for each service that should get installed on the {{role.name}} role.
162 type: comma_delimited_list
165 description: Number of {{role.name}} nodes to deploy
167 default: {{role.CountDefault|default(0)}}
169 {{role.name}}HostnameFormat:
172 Format for {{role.name}} node hostnames
173 Note %index% is translated into the index of the node, e.g 0/1/2 etc
174 and %stackname% is replaced with the stack name e.g overcloud
175 {% if role.HostnameFormatDefault %}
176 default: "{{role.HostnameFormatDefault}}"
178 default: "%stackname%-{{role.name.lower()}}-%index%"
180 {{role.name}}RemovalPolicies:
184 List of resources to be removed from {{role.name}} ResourceGroup when
185 doing an update which requires removal of specific resources.
186 Example format ComputeRemovalPolicies: [{'resource_list': ['0']}]
188 {{role.name}}SchedulerHints:
190 description: Optional scheduler hints to pass to nova
192 {%- if role.deprecated_param_scheduler_hints is defined %}
193 {{role.deprecated_param_scheduler_hints}}:
195 description: DEPRECATED - use {{role.name}}SchedulerHints instead
199 {{role.name}}Parameters:
201 description: Optional Role Specific parameters to be provided to service
205 # Identifiers to trigger tasks on nodes
210 Setting to a previously unused value during stack-update will trigger
211 package update on all nodes
216 Setting this to a unique value will re-run any deployment tasks which
217 perform configuration on a Heat stack-update.
222 Set to true to append per network Vips to /etc/hosts on each node.
224 DeploymentServerBlacklist:
226 type: comma_delimited_list
228 List of server hostnames to blacklist from any triggered deployments.
230 {% for role in roles %}
231 {%- if role.deprecated_param_scheduler_hints is defined or role.deprecated_param_extraconfig is defined %}
232 {%- if not parameter_groups_defined|default(false) %}
235 description: Do not use deprecated params, they will be removed.
237 {%- set parameter_groups_defined = true %}
240 {%- if role.deprecated_param_scheduler_hints is defined %}
241 - {{role.deprecated_param_scheduler_hints}}
243 {%- if role.deprecated_param_extraconfig is defined %}
244 - {{role.deprecated_param_extraconfig}}
249 add_vips_to_etc_hosts: {equals : [{get_param: AddVipsToEtcHosts}, True]}
254 type: OS::Heat::Value
263 IP: {get_attr: [VipMap, net_ip_map, ctlplane]}
264 HOST: {get_param: CloudNameCtlplane}
265 {%- for network in networks if network.vip|default(false) %}
266 {%- if network.name == 'External' %}
267 # Special case the External hostname param, which is CloudName
271 IP: {get_attr: [VipMap, net_ip_map, {{network.name_lower}}]}
272 HOST: {get_param: CloudName}
273 {%- elif network.name == 'InternalApi' %}
274 # Special case the Internal API hostname param, which is CloudNameInternal
278 IP: {get_attr: [VipMap, net_ip_map, {{network.name_lower}}]}
279 HOST: {get_param: CloudNameInternal}
280 {%- elif network.name == 'StorageMgmt' %}
281 # Special case StorageMgmt hostname param, which is CloudNameStorageManagement
285 IP: {get_attr: [VipMap, net_ip_map, {{network.name_lower}}]}
286 HOST: {get_param: CloudNameStorageManagement}
291 IP: {get_attr: [VipMap, net_ip_map, {{network.name_lower}}]}
292 HOST: {get_param: CloudName{{network.name}}}
296 HeatAuthEncryptionKey:
297 type: OS::TripleO::RandomString
300 type: OS::TripleO::RandomString
305 type: OS::TripleO::RandomString
310 type: OS::Heat::Value
316 - {get_attr: [Networks, net_cidr_map]}
317 - ctlplane: {get_attr: [ControlVirtualIP, subnets, 0, cidr]}
319 ctlplane: {get_param: NeutronControlPlaneID}
321 disabled: {get_attr: [ControlVirtualIP, subnets, 0, cidr]}
324 type: OS::TripleO::ServiceNetMap
327 type: OS::TripleO::EndpointMap
330 ctlplane: {get_param: CloudNameCtlplane}
331 {%- for network in networks if network.vip|default(false) %}
332 {%- if network.name == 'External' %}
333 # Special case the External hostname param, which is CloudName
334 {{network.name_lower}}: {get_param: CloudName}
335 {%- elif network.name == 'InternalApi' %}
336 # Special case the Internal API hostname param, which is CloudNameInternal
337 {{network.name_lower}}: {get_param: CloudNameInternal}
338 {%- elif network.name == 'StorageMgmt' %}
339 # Special case StorageMgmt hostname param, which is CloudNameStorageManagement
340 {{network.name_lower}}: {get_param: CloudNameStorageManagement}
342 {{network.name_lower}}: {get_param: CloudName{{network.name}}}
345 NetIpMap: {get_attr: [VipMap, net_ip_map]}
346 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
349 type: OS::Heat::Value
352 value: {get_attr: [EndpointMap, endpoint_map]}
355 type: OS::TripleO::Ssh::KnownHostsConfig
360 {% for role in roles %}
361 - {get_attr: [{{role.name}}, known_hosts_entry]}
364 # Jinja loop for Role in roles_data.yaml
365 {% for role in roles %}
366 # Resources generated for {{role.name}} Role
367 {{role.name}}ServiceChain:
368 type: OS::TripleO::Services
371 get_param: {{role.name}}Services
372 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
374 net_cidr_map: {get_attr: [NetCidrMapValue, value]}
375 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
376 DefaultPasswords: {get_attr: [DefaultPasswords, passwords]}
377 RoleName: {{role.name}}
378 RoleParameters: {get_param: {{role.name}}Parameters}
380 # Lookup of role_data via heat outputs is slow, so workaround this by caching
381 # the value in an OS::Heat::Value resource
382 {{role.name}}ServiceChainRoleData:
383 type: OS::Heat::Value
386 value: {get_attr: [{{role.name}}ServiceChain, role_data]}
388 {{role.name}}ServiceConfigSettings:
389 type: OS::Heat::Value
394 - get_attr: [{{role.name}}ServiceChainRoleData, value, config_settings]
396 - get_attr: [{{r.name}}ServiceChainRoleData, value, global_config_settings]
398 # This next step combines two yaql passes:
399 # - The inner one does a deep merge on the service_config_settings for all roles
400 # - The outer one filters the map based on the services enabled for the role
401 # then merges the result into one map.
403 expression: let(root => $) -> $.data.map.items().where($[0] in coalesce($root.data.services, [])).select($[1]).reduce($1.mergeWith($2), {})
407 expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
410 - get_attr: [{{r.name}}ServiceChainRoleData, value, service_config_settings]
412 services: {get_attr: [{{role.name}}ServiceNames, value]}
414 {{role.name}}MergedConfigSettings:
415 type: OS::Heat::Value
420 global_config_settings: {}
421 service_config_settings: {}
422 merged_config_settings:
424 - get_attr: [{{role.name}}ServiceConfigSettings, value]
425 - get_param: ExtraConfig
426 {%- if role.deprecated_param_extraconfig is defined %}
427 - get_param: {{role.deprecated_param_extraconfig}}
429 - get_param: {{role.name}}ExtraConfig
431 # Filter any null/None service_names which may be present due to mapping
432 # of services to OS::Heat::None
433 {{role.name}}ServiceNames:
434 type: OS::Heat::Value
435 depends_on: {{role.name}}ServiceChain
437 type: comma_delimited_list
440 expression: coalesce($.data, []).where($ != null)
441 data: {get_attr: [{{role.name}}ServiceChainRoleData, value, service_names]}
443 {{role.name}}HostsDeployment:
444 type: OS::Heat::StructuredDeployments
446 name: {{role.name}}HostsDeployment
447 config: {get_attr: [hostsConfig, config_id]}
448 servers: {get_attr: [{{role.name}}Servers, value]}
450 {{role.name}}SshKnownHostsDeployment:
451 type: OS::Heat::StructuredDeployments
453 name: {{role.name}}SshKnownHostsDeployment
454 config: {get_resource: SshKnownHostsConfig}
455 servers: {get_attr: [{{role.name}}Servers, value]}
457 {{role.name}}AllNodesDeployment:
458 type: OS::TripleO::AllNodesDeployment
460 {% for role_inner in roles %}
461 - {{role_inner.name}}HostsDeployment
464 name: {{role.name}}AllNodesDeployment
465 config: {get_attr: [allNodesConfig, config_id]}
466 servers: {get_attr: [{{role.name}}Servers, value]}
468 # Note we have to use yaql to look up the first hostname/ip in the
469 # list because heat path based attributes operate on the attribute
470 # inside the ResourceGroup, not the exposed list ref discussion in
471 # https://bugs.launchpad.net/heat/+bug/1640488
472 # The coalesce is needed because $.data is None during heat validation
475 expression: coalesce($.data, []).first(null)
476 data: {get_attr: [{{role.name}}, hostname]}
479 expression: coalesce($.data, []).first(null)
480 data: {get_attr: [{{role.name}}, ip_address]}
482 {{role.name}}AllNodesValidationDeployment:
483 type: OS::Heat::StructuredDeployments
484 depends_on: {{role.name}}AllNodesDeployment
486 name: {{role.name}}AllNodesValidationDeployment
487 config: {get_resource: AllNodesValidationConfig}
488 servers: {get_attr: [{{role.name}}Servers, value]}
490 {{role.name}}IpListMap:
491 type: OS::TripleO::Network::Ports::NetIpListMap
493 ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
494 {%- for network in networks %}
495 {%- if network.enabled|default(true) %}
496 {{network.name}}IpList: {get_attr: [{{role.name}}, {{network.name_lower}}_ip_address]}
498 {{network.name}}IpList: {get_attr: [{{role.name}}, ip_address]}
501 EnabledServices: {get_attr: [{{role.name}}ServiceNames, value]}
502 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
503 ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
504 NetworkHostnameMap: {get_attr: [{{role.name}}NetworkHostnameMap, value]}
506 {{role.name}}NetworkHostnameMap:
507 type: OS::Heat::Value
511 # Note (shardy) this somewhat complex yaql may be replaced
512 # with a map_deep_merge function in ocata. It merges the
513 # list of maps, but appends to colliding lists so we can
514 # create a map of lists for all nodes for each network
516 expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
518 - {get_attr: [{{role.name}}, hostname_map]}
521 type: OS::Heat::ResourceGroup
525 max_batch_size: {get_param: NodeCreateBatchSize}
527 count: {get_param: {{role.name}}Count}
528 removal_policies: {get_param: {{role.name}}RemovalPolicies}
530 type: OS::TripleO::{{role.name}}
532 CloudDomain: {get_param: CloudDomain}
533 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
534 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
537 template: {get_param: {{role.name}}HostnameFormat}
539 '%stackname%': {get_param: 'OS::stack_name'}
541 # Note, SchedulerHints must be defined here, not only in the
542 # nested template, as it can contain %index%
543 {{role.name}}SchedulerHints:
545 {%- if role.deprecated_param_scheduler_hints is defined %}
546 - {get_param: {{role.deprecated_param_scheduler_hints}}}
548 - {get_param: {{role.name}}SchedulerHints}
549 ServiceConfigSettings: {get_attr: [{{role.name}}ServiceConfigSettings, value]}
550 ServiceNames: {get_attr: [{{role.name}}ServiceNames, value]}
551 MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChainRoleData, value, monitoring_subscriptions]}
552 LoggingSources: {get_attr: [{{role.name}}ServiceChainRoleData, value, logging_sources]}
553 LoggingGroups: {get_attr: [{{role.name}}ServiceChainRoleData, value, logging_groups]}
554 ServiceMetadataSettings: {get_attr: [{{role.name}}ServiceChainRoleData, value, service_metadata_settings]}
555 DeploymentServerBlacklistDict: {get_attr: [DeploymentServerBlacklistDict, value]}
556 RoleParameters: {get_param: {{role.name}}Parameters}
559 {% for role in roles %}
560 {{role.name}}Servers:
561 type: OS::Heat::Value
562 depends_on: {{role.name}}
567 expression: let(servers=>switch(isDict($.data.servers) => $.data.servers, true => {})) -> $servers.deleteAll($servers.keys().where($servers[$] = null))
569 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
572 # This is a different format to *Servers, as it creates a map of lists
573 # whereas *Servers creates a map of maps with keys of the nested resource names
575 type: OS::Heat::Value
579 {% for role in roles %}
580 {{role.name}}: {get_attr: [{{role.name}}, nova_server_resource]}
584 expression: coalesce($.data, []).first(null)
585 data: {get_attr: [{{primary_role_name}}, nova_server_resource]}
587 # This resource just creates a dict out of the DeploymentServerBlacklist,
588 # which is a list. The dict is used in the role templates to set a condition
589 # on whether to create the deployment resources. We can't use the list
590 # directly because there is no way to ask Heat if a list contains a specific
592 DeploymentServerBlacklistDict:
593 type: OS::Heat::Value
602 hostname: {get_param: DeploymentServerBlacklist}
605 type: OS::TripleO::Hosts::SoftwareConfig
611 - add_vips_to_etc_hosts
612 - {get_attr: [VipHosts, value]}
615 {% for role in roles %}
618 - {get_attr: [{{role.name}}, hosts_entry]}
622 type: OS::TripleO::AllNodes::SoftwareConfig
624 {%- for network in networks if network.vip|default(false) %}
625 {%- if network.name == 'External' %}
626 # Special case the External hostname param, which is CloudName
627 cloud_name_{{network.name_lower}}: {get_param: CloudName}
628 {%- elif network.name == 'InternalApi' %}
629 # Special case the Internal API hostname param, which is CloudNameInternal
630 cloud_name_{{network.name_lower}}: {get_param: CloudNameInternal}
631 {%- elif network.name == 'StorageMgmt' %}
632 # Special case StorageMgmt hostname param, which is CloudNameStorageManagement
633 cloud_name_{{network.name_lower}}: {get_param: CloudNameStorageManagement}
635 cloud_name_{{network.name_lower}}: {get_param: CloudName{{network.name}}}
638 cloud_name_ctlplane: {get_param: CloudNameCtlplane}
642 {% for role in roles %}
643 - {get_attr: [{{role.name}}ServiceNames, value]}
645 cellv2_discovery_hosts:
646 # Collects compute hostnames for all roles with a service that requires cellv2 host discovery
650 expression: coalesce($.data.e.zip($.data.l).where($[0]).select($[1]).flatten(), [])
652 e: # list of true/fails for whether cellsv2 host discovery is required for the roles
653 {%- for role in roles %}
654 - {get_attr: [{{role.name}}ServiceChainRoleData, value, cellv2_discovery]}
656 l: # list of list of compute hostnames for the roles
657 {%- for role in roles %}
658 - {get_attr: [{{role.name}}, hostname_map, canonical]}
660 controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
661 controller_names: {get_attr: [{{primary_role_name}}, hostname]}
663 # Note (shardy) this somewhat complex yaql may be replaced
664 # with a map_deep_merge function in ocata. It merges the
665 # list of maps, but appends to colliding lists when a service
666 # is deployed on more than one role
668 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
671 {% for role in roles %}
672 - {get_attr: [{{role.name}}IpListMap, service_ips]}
676 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
679 {% for role in roles %}
680 - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
682 short_service_node_names:
684 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
687 {% for role in roles %}
688 - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
690 short_service_bootstrap_node:
692 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
695 {% for role in roles %}
696 - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
698 NetVipMap: {get_attr: [VipMap, net_ip_map]}
699 RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
700 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
701 DeployIdentifier: {get_param: DeployIdentifier}
702 UpdateIdentifier: {get_param: UpdateIdentifier}
705 type: OS::TripleO::RandomString
710 type: OS::TripleO::RandomString
713 salt: {get_param: RabbitCookieSalt}
716 type: OS::TripleO::DefaultPasswords
718 DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
719 DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
720 DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
721 DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
722 DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
724 # creates the network architecture
726 type: OS::TripleO::Network
729 type: OS::TripleO::Network::Ports::ControlPlaneVipPort
732 name: control_virtual_ip
733 network: {get_param: NeutronControlPlaneID}
734 fixed_ips: {get_param: ControlFixedIPs}
735 replacement_policy: AUTO
739 type: OS::TripleO::Network::Ports::RedisVipPort
741 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
742 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
743 PortName: redis_virtual_ip
744 NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
746 FixedIPs: {get_param: RedisVirtualFixedIPs}
748 {%- for network in networks if network.vip|default(false) %}
749 {%- if network.name == 'External' %}
750 # The public VIP is on the External net, falls back to ctlplane
753 type: OS::TripleO::Network::Ports::ExternalVipPort
755 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
756 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
757 PortName: public_virtual_ip
758 FixedIPs: {get_param: PublicVirtualFixedIPs}
759 {%- elif network.name == 'StorageMgmt' %}
760 {{network.name}}VirtualIP:
762 type: OS::TripleO::Network::Ports::{{network.name}}VipPort
764 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
765 PortName: storage_management_virtual_ip
766 FixedIPs: {get_param: {{network.name}}VirtualFixedIPs}
768 {{network.name}}VirtualIP:
770 type: OS::TripleO::Network::Ports::{{network.name}}VipPort
772 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
773 PortName: {{network.name_lower}}_virtual_ip
774 FixedIPs: {get_param: {{network.name}}VirtualFixedIPs}
779 type: OS::TripleO::Network::Ports::NetVipMap
781 ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
782 {%- for network in networks if network.vip|default(false) %}
783 {%- if network.name == 'External' %}
784 ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
785 ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
787 {{network.name}}Ip: {get_attr: [{{network.name}}VirtualIP, ip_address]}
788 {{network.name}}IpUri: {get_attr: [{{network.name}}VirtualIP, ip_address_uri]}
791 # No tenant or management VIP required
792 # Because of nested get_attr functions in the KeystoneAdminVip output, we
793 # can't determine which attributes of VipMap are used until after
794 # ServiceNetMap's attribute values are available.
795 depends_on: ServiceNetMap
797 # All Nodes Validations
798 AllNodesValidationConfig:
799 type: OS::TripleO::AllNodes::Validation
805 {%- for network in networks if network.enabled|default(true) %}
807 expression: coalesce($.data, []).first(null)
808 data: {get_attr: [{{primary_role_name}}, {{network.name_lower}}_ip_address]}
812 type: OS::TripleO::Tasks::UpdateWorkflow
814 {% for role in roles %}
815 - {{role.name}}AllNodesDeployment
819 {% for role in roles %}
820 {{role.name}}: {get_attr: [{{role.name}}Servers, value]}
823 deploy_identifier: {get_param: DeployIdentifier}
824 update_identifier: {get_param: UpdateIdentifier}
826 # Optional ExtraConfig for all nodes - all roles are passed in here, but
827 # the nested template may configure each role differently (or not at all)
829 type: OS::TripleO::AllNodesExtraConfig
832 {% for role in roles %}
833 - {{role.name}}AllNodesValidationDeployment
837 {% for role in roles %}
838 {{role.name}}: {get_attr: [{{role.name}}Servers, value]}
841 # Post deployment steps for all roles
843 type: OS::TripleO::PostDeploySteps
845 - AllNodesExtraConfig
846 {% for role in roles %}
847 - {{role.name}}AllNodesDeployment
851 {% for role in roles %}
852 {{role.name}}: {get_attr: [{{role.name}}Servers, value]}
854 stack_name: {get_param: 'OS::stack_name'}
855 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
856 ctlplane_service_ips:
857 # Note (shardy) this somewhat complex yaql may be replaced
858 # with a map_deep_merge function in ocata. It merges the
859 # list of maps, but appends to colliding lists when a service
860 # is deployed on more than one role
862 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
865 {% for role in roles %}
866 - {get_attr: [{{role.name}}IpListMap, ctlplane_service_ips]}
869 {% for role in roles %}
872 - {get_attr: [{{role.name}}ServiceChainRoleData, value]}
873 - {get_attr: [{{role.name}}MergedConfigSettings, value]}
876 ServerOsCollectConfigData:
877 type: OS::Heat::Value
881 {% for role in roles %}
882 {{role.name}}: {get_attr: [{{role.name}}, attributes, os_collect_config]}
885 DeployedServerEnvironment:
886 type: OS::TripleO::DeployedServerEnvironment
889 {% for role in roles %}
890 {{role.name}}DeployedServerCount: {get_param: {{role.name}}Count}
894 - {get_attr: [VipMap, net_ip_map]}
895 - redis: {get_attr: [RedisVirtualIP, ip_address]}
896 DeployedServerPortMap:
899 {% for role in roles %}
900 - {get_attr: [{{role.name}}, deployed_server_port_map]}
902 DeployedServerDeploymentSwiftDataMap:
905 {% for role in roles %}
906 - {get_attr: [{{role.name}}, deployed_server_deployment_swift_data_map]}
913 - {get_attr: [ServerOsCollectConfigData, value, {{primary_role_name}}, '0', request, metadata_url]}
919 description: Asserts that the keystone endpoints have been provisioned.
922 description: URL for the Overcloud Keystone service
923 value: {get_attr: [EndpointMapData, value, KeystonePublic, uri]}
925 description: Keystone Admin VIP endpoint
926 # Note that these nested get_attr functions require a dependency
927 # relationship between VipMap and ServiceNetMap, since we can't determine
928 # which attributes of VipMap are used until after ServiceNetMap's attribute
929 # values are available. If this is ever reworked to not use nested
930 # get_attr, that dependency can be removed.
931 value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
934 Mapping of the resources with the needed info for their endpoints.
935 This includes the protocol used, the IP, port and also a full
936 representation of the URI.
937 value: {get_attr: [EndpointMapData, value]}
940 The content that should be appended to your /etc/hosts if you want to get
941 hostname-based access to the deployed nodes (useful for testing without
946 - - {get_attr: [hostsConfig, hosts_entries]}
947 - - {get_attr: [VipHosts, value]}
949 description: The services enabled on each role
951 {% for role in roles %}
952 {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
955 description: The configuration data associated with each role
957 {% for role in roles %}
960 - {get_attr: [{{role.name}}ServiceChainRoleData, value]}
961 - {get_attr: [{{role.name}}MergedConfigSettings, value]}
964 description: The configuration workflows associated with each role
965 value: {get_attr: [AllNodesDeploySteps, RoleConfig]}
967 description: Mapping of each network to a list of IPs for each role
969 {% for role in roles %}
970 {{role.name}}: {get_attr: [{{role.name}}IpListMap, net_ip_map]}
973 description: Mapping of each network to a list of hostnames for each role
975 {% for role in roles %}
976 {{role.name}}: {get_attr: [{{role.name}}NetworkHostnameMap, value]}
978 ServerOsCollectConfigData:
979 description: The os-collect-config configuration associated with each server resource
980 value: {get_attr: [ServerOsCollectConfigData, value]}
982 description: Mapping of each network to VIP addresses. Also includes the Redis VIP.
985 - {get_attr: [VipMap, net_ip_map]}
986 - redis: {get_attr: [RedisVirtualIP, ip_address]}
988 description: Mapping of each role to a list of nova server IDs and the bootstrap ID
989 value: {get_attr: [ServerIdMap, value]}
990 DeployedServerEnvironment:
992 Environment data that can be used as input into the services stack when
994 value: {get_attr: [DeployedServerEnvironment, deployed_server_environment]}