a2d501d387ee90b6ded4385717d6db961e980528
[apex-tripleo-heat-templates.git] / overcloud.j2.yaml
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) -%}
6   {%- endif -%}
7 {%- endfor -%}
8 {%- set primary_role_name = primary_role[0].name -%}
9 # primary role is: {{primary_role_name}}
10 heat_template_version: ocata
11
12 description: >
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.
17
18
19 # TODO(shadower): we should probably use the parameter groups to put
20 # some order in here.
21 parameters:
22
23   # Common parameters (not specific to a role)
24   CloudName:
25     default: overcloud.localdomain
26     description: The DNS name of this cloud. E.g. ci-overcloud.tripleo.org
27     type: string
28   CloudNameInternal:
29     default: overcloud.internalapi.localdomain
30     description: >
31       The DNS name of this cloud's internal API endpoint. E.g.
32       'ci-overcloud.internalapi.tripleo.org'.
33     type: string
34   CloudNameStorage:
35     default: overcloud.storage.localdomain
36     description: >
37       The DNS name of this cloud's storage endpoint. E.g.
38       'ci-overcloud.storage.tripleo.org'.
39     type: string
40   CloudNameStorageManagement:
41     default: overcloud.storagemgmt.localdomain
42     description: >
43       The DNS name of this cloud's storage management endpoint. E.g.
44       'ci-overcloud.storagemgmt.tripleo.org'.
45     type: string
46   CloudNameCtlplane:
47     default: overcloud.ctlplane.localdomain
48     description: >
49       The DNS name of this cloud's storage management endpoint. E.g.
50       'ci-overcloud.management.tripleo.org'.
51     type: string
52   ControlFixedIPs:
53     default: []
54     description: Should be used for arbitrary ips.
55     type: json
56   InternalApiVirtualFixedIPs:
57     default: []
58     description: >
59         Control the IP allocation for the InternalApiVirtualInterface port. E.g.
60         [{'ip_address':'1.2.3.4'}]
61     type: json
62   NeutronControlPlaneID:
63     default: 'ctlplane'
64     type: string
65     description: Neutron ID or name for ctlplane network.
66   NeutronPublicInterface:
67     default: nic1
68     description: What interface to bridge onto br-ex for network nodes.
69     type: string
70   PublicVirtualFixedIPs:
71     default: []
72     description: >
73         Control the IP allocation for the PublicVirtualInterface port. E.g.
74         [{'ip_address':'1.2.3.4'}]
75     type: json
76   RabbitCookieSalt:
77     type: string
78     default: unset
79     description: Salt for the rabbit cookie, change this to force the randomly generated rabbit cookie to change.
80   StorageVirtualFixedIPs:
81     default: []
82     description: >
83         Control the IP allocation for the StorageVirtualInterface port. E.g.
84         [{'ip_address':'1.2.3.4'}]
85     type: json
86   StorageMgmtVirtualFixedIPs:
87     default: []
88     description: >
89         Control the IP allocation for the StorageMgmgVirtualInterface port. E.g.
90         [{'ip_address':'1.2.3.4'}]
91     type: json
92   RedisVirtualFixedIPs:
93     default: []
94     description: >
95         Control the IP allocation for the virtual IP used by Redis. E.g.
96         [{'ip_address':'1.2.3.4'}]
97     type: json
98   CloudDomain:
99     default: 'localdomain'
100     type: string
101     description: >
102       The DNS domain used for the hosts. This should match the dhcp_domain
103       configured in the Undercloud neutron. Defaults to localdomain.
104   ServerMetadata:
105     default: {}
106     description: >
107       Extra properties or metadata passed to Nova for the created nodes in
108       the overcloud. It's accessible via the Nova metadata API.
109     type: json
110
111 # Compute-specific params
112 # FIXME(shardy) handle these deprecated names as they don't match compute.yaml
113   HypervisorNeutronPhysicalBridge:
114     default: 'br-ex'
115     description: >
116       An OVS bridge to create on each hypervisor. This defaults to br-ex the
117       same as the control plane nodes, as we have a uniform configuration of
118       the openvswitch agent. Typically should not need to be changed.
119     type: string
120   HypervisorNeutronPublicInterface:
121     default: nic1
122     description: What interface to add to the HypervisorNeutronPhysicalBridge.
123     type: string
124
125   NodeCreateBatchSize:
126     default: 30
127     description: Maxiumum batch size for creating nodes
128     type: number
129
130   # Jinja loop for Role in role_data.yaml
131 {% for role in roles %}
132   # Parameters generated for {{role.name}} Role
133   {{role.name}}Services:
134     description: A list of service resources (configured in the Heat
135                  resource_registry) which represent nested stacks
136                  for each service that should get installed on the {{role.name}} role.
137     type: comma_delimited_list
138
139   {{role.name}}Count:
140     description: Number of {{role.name}} nodes to deploy
141     type: number
142     default: {{role.CountDefault|default(0)}}
143
144   {{role.name}}HostnameFormat:
145     type: string
146     description: >
147       Format for {{role.name}} node hostnames
148       Note %index% is translated into the index of the node, e.g 0/1/2 etc
149       and %stackname% is replaced with the stack name e.g overcloud
150   {% if role.HostnameFormatDefault %}
151     default: "{{role.HostnameFormatDefault}}"
152   {% else %}
153     default: "%stackname%-{{role.name.lower()}}-%index%"
154   {% endif %}
155
156   {{role.name}}RemovalPolicies:
157     default: []
158     type: json
159     description: >
160       List of resources to be removed from {{role.name}} ResourceGroup when
161       doing an update which requires removal of specific resources.
162       Example format ComputeRemovalPolicies: [{'resource_list': ['0']}]
163
164 {% if role.name != 'Compute' %}
165   {{role.name}}SchedulerHints:
166 {% else %}
167   NovaComputeSchedulerHints:
168 {% endif %}
169     type: json
170     description: Optional scheduler hints to pass to nova
171     default: {}
172 {% endfor %}
173
174   # Identifiers to trigger tasks on nodes
175   UpdateIdentifier:
176     default: ''
177     type: string
178     description: >
179       Setting to a previously unused value during stack-update will trigger
180       package update on all nodes
181   DeployIdentifier:
182     default: ''
183     type: string
184     description: >
185       Setting this to a unique value will re-run any deployment tasks which
186       perform configuration on a Heat stack-update.
187   AddVipsToEtcHosts:
188     default: True
189     type: boolean
190     description: >
191       Set to true to append per network Vips to /etc/hosts on each node.
192
193 conditions:
194   add_vips_to_etc_hosts: {equals : [{get_param: AddVipsToEtcHosts}, True]}
195
196 resources:
197
198   VipHosts:
199     type: OS::Heat::Value
200     properties:
201       type: string
202       value:
203         list_join:
204         - "\n"
205         - - str_replace:
206               template: IP  HOST
207               params:
208                 IP: {get_attr: [VipMap, net_ip_map, external]}
209                 HOST: {get_param: CloudName}
210           - str_replace:
211               template: IP  HOST
212               params:
213                 IP: {get_attr: [VipMap, net_ip_map, ctlplane]}
214                 HOST: {get_param: CloudNameCtlplane}
215           - str_replace:
216               template: IP  HOST
217               params:
218                 IP: {get_attr: [VipMap, net_ip_map, internal_api]}
219                 HOST: {get_param: CloudNameInternal}
220           - str_replace:
221               template: IP  HOST
222               params:
223                 IP: {get_attr: [VipMap, net_ip_map, storage]}
224                 HOST: {get_param: CloudNameStorage}
225           - str_replace:
226               template: IP  HOST
227               params:
228                 IP: {get_attr: [VipMap, net_ip_map, storage_mgmt]}
229                 HOST: {get_param: CloudNameStorageManagement}
230
231   HeatAuthEncryptionKey:
232     type: OS::Heat::RandomString
233
234   PcsdPassword:
235     type: OS::Heat::RandomString
236     properties:
237       length: 16
238
239   HorizonSecret:
240     type: OS::Heat::RandomString
241     properties:
242       length: 10
243
244   ServiceNetMap:
245     type: OS::TripleO::ServiceNetMap
246
247   EndpointMap:
248     type: OS::TripleO::EndpointMap
249     properties:
250       CloudEndpoints:
251         external: {get_param: CloudName}
252         internal_api: {get_param: CloudNameInternal}
253         storage: {get_param: CloudNameStorage}
254         storage_mgmt: {get_param: CloudNameStorageManagement}
255         ctlplane: {get_param: CloudNameCtlplane}
256       NetIpMap: {get_attr: [VipMap, net_ip_map]}
257       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
258
259   EndpointMapData:
260     type: OS::Heat::Value
261     properties:
262       type: json
263       value: {get_attr: [EndpointMap, endpoint_map]}
264
265   SshKnownHostsConfig:
266     type: OS::TripleO::Ssh::KnownHostsConfig
267     properties:
268       known_hosts:
269         list_join:
270           - ''
271           {% for role in roles %}
272           - {get_attr: [{{role.name}}, known_hosts_entry]}
273           {% endfor %}
274
275   # Jinja loop for Role in roles_data.yaml
276 {% for role in roles %}
277   # Resources generated for {{role.name}} Role
278   {{role.name}}ServiceChain:
279     type: OS::TripleO::Services
280     properties:
281       Services:
282         get_param: {{role.name}}Services
283       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
284       EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
285       DefaultPasswords: {get_attr: [DefaultPasswords, passwords]}
286
287   # Filter any null/None service_names which may be present due to mapping
288   # of services to OS::Heat::None
289   {{role.name}}ServiceNames:
290     type: OS::Heat::Value
291     depends_on: {{role.name}}ServiceChain
292     properties:
293       type: comma_delimited_list
294       value:
295         yaql:
296           expression: coalesce($.data, []).where($ != null)
297           data: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
298
299   {{role.name}}HostsDeployment:
300     type: OS::Heat::StructuredDeployments
301     properties:
302       name: {{role.name}}HostsDeployment
303       config: {get_attr: [hostsConfig, config_id]}
304       servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
305
306   {{role.name}}SshKnownHostsDeployment:
307     type: OS::Heat::StructuredDeployments
308     properties:
309       name: {{role.name}}SshKnownHostsDeployment
310       config: {get_resource: SshKnownHostsConfig}
311       servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
312
313   {{role.name}}AllNodesDeployment:
314     type: OS::Heat::StructuredDeployments
315     depends_on:
316 {% for role_inner in roles %}
317       - {{role_inner.name}}HostsDeployment
318 {% endfor %}
319     properties:
320       name: {{role.name}}AllNodesDeployment
321       config: {get_attr: [allNodesConfig, config_id]}
322       servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
323       input_values:
324         # Note we have to use yaql to look up the first hostname/ip in the
325         # list because heat path based attributes operate on the attribute
326         # inside the ResourceGroup, not the exposed list ref discussion in
327         # https://bugs.launchpad.net/heat/+bug/1640488
328         # The coalesce is needed because $.data is None during heat validation
329         bootstrap_nodeid:
330           yaql:
331             expression: coalesce($.data, []).first(null)
332             data: {get_attr: [{{role.name}}, hostname]}
333         bootstrap_nodeid_ip:
334           yaql:
335             expression: coalesce($.data, []).first(null)
336             data: {get_attr: [{{role.name}}, ip_address]}
337
338   {{role.name}}AllNodesValidationDeployment:
339     type: OS::Heat::StructuredDeployments
340     depends_on: {{role.name}}AllNodesDeployment
341     properties:
342       name: {{role.name}}AllNodesValidationDeployment
343       config: {get_resource: AllNodesValidationConfig}
344       servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
345
346   {{role.name}}IpListMap:
347     type: OS::TripleO::Network::Ports::NetIpListMap
348     properties:
349       ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
350       ExternalIpList: {get_attr: [{{role.name}}, external_ip_address]}
351       InternalApiIpList: {get_attr: [{{role.name}}, internal_api_ip_address]}
352       StorageIpList: {get_attr: [{{role.name}}, storage_ip_address]}
353       StorageMgmtIpList: {get_attr: [{{role.name}}, storage_mgmt_ip_address]}
354       TenantIpList: {get_attr: [{{role.name}}, tenant_ip_address]}
355       ManagementIpList: {get_attr: [{{role.name}}, management_ip_address]}
356       EnabledServices: {get_attr: [{{role.name}}ServiceNames, value]}
357       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
358       ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
359       NetworkHostnameMap:
360         # Note (shardy) this somewhat complex yaql may be replaced
361         # with a map_deep_merge function in ocata.  It merges the
362         # list of maps, but appends to colliding lists so we can
363         # create a map of lists for all nodes for each network
364         yaql:
365           expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
366           data:
367             - {get_attr: [{{role.name}}, hostname_map]}
368
369   {{role.name}}:
370     type: OS::Heat::ResourceGroup
371     depends_on: Networks
372     update_policy:
373       batch_create:
374         max_batch_size: {get_param: NodeCreateBatchSize}
375     properties:
376       count: {get_param: {{role.name}}Count}
377       removal_policies: {get_param: {{role.name}}RemovalPolicies}
378       resource_def:
379         type: OS::TripleO::{{role.name}}
380         properties:
381           CloudDomain: {get_param: CloudDomain}
382           ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
383           EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
384           Hostname:
385             str_replace:
386               template: {get_param: {{role.name}}HostnameFormat}
387               params:
388                 '%stackname%': {get_param: 'OS::stack_name'}
389           NodeIndex: '%index%'
390   {% if role.name != 'Compute' %}
391           {{role.name}}SchedulerHints: {get_param: {{role.name}}SchedulerHints}
392   {% else %}
393           NovaComputeSchedulerHints: {get_param: NovaComputeSchedulerHints}
394   {% endif %}
395           ServiceConfigSettings:
396             map_merge:
397               -  get_attr: [{{role.name}}ServiceChain, role_data, config_settings]
398           {% for r in roles %}
399               - get_attr: [{{r.name}}ServiceChain, role_data, global_config_settings]
400           {% endfor %}
401               # This next step combines two yaql passes:
402               # - The inner one does a deep merge on the service_config_settings for all roles
403               # - The outer one filters the map based on the services enabled for the role
404               #   then merges the result into one map.
405               - yaql:
406                   expression: let(root => $) -> $.data.map.items().where($[0] in coalesce($root.data.services, [])).select($[1]).reduce($1.mergeWith($2), {})
407                   data:
408                     map:
409                       yaql:
410                         expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
411                         data:
412                         {% for r in roles %}
413                           - get_attr: [{{r.name}}ServiceChain, role_data, service_config_settings]
414                         {% endfor %}
415                     services: {get_attr: [{{role.name}}ServiceNames, value]}
416           ServiceNames: {get_attr: [{{role.name}}ServiceNames, value]}
417           MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChain, role_data, monitoring_subscriptions]}
418           ServiceMetadataSettings: {get_attr: [{{role.name}}ServiceChain, role_data, service_metadata_settings]}
419 {% endfor %}
420
421   hostsConfig:
422     type: OS::TripleO::Hosts::SoftwareConfig
423     properties:
424       hosts:
425         list_join:
426         - "\n"
427         - - if:
428             - add_vips_to_etc_hosts
429             - {get_attr: [VipHosts, value]}
430             - ''
431         -
432 {% for role in roles %}
433           - list_join:
434             - ""
435             - {get_attr: [{{role.name}}, hosts_entry]}
436 {% endfor %}
437
438   allNodesConfig:
439     type: OS::TripleO::AllNodes::SoftwareConfig
440     properties:
441       cloud_name_external: {get_param: CloudName}
442       cloud_name_internal_api: {get_param: CloudNameInternal}
443       cloud_name_storage: {get_param: CloudNameStorage}
444       cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
445       cloud_name_ctlplane: {get_param: CloudNameCtlplane}
446       enabled_services:
447         list_join:
448           - ','
449 {% for role in roles %}
450           - {get_attr: [{{role.name}}ServiceNames, value]}
451 {% endfor %}
452       logging_groups:
453         yaql:
454           expression: >
455             $.data.groups.flatten()
456           data:
457             groups:
458 {% for role in roles %}
459               - {get_attr: [{{role.name}}ServiceChain, role_data, logging_groups]}
460 {% endfor %}
461       logging_sources:
462         yaql:
463           expression: >
464             $.data.sources.flatten()
465           data:
466             sources:
467 {% for role in roles %}
468               - {get_attr: [{{role.name}}ServiceChain, role_data, logging_sources]}
469 {% endfor %}
470       controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
471       controller_names: {get_attr: [{{primary_role_name}}, hostname]}
472       service_ips:
473         # Note (shardy) this somewhat complex yaql may be replaced
474         # with a map_deep_merge function in ocata.  It merges the
475         # list of maps, but appends to colliding lists when a service
476         # is deployed on more than one role
477         yaql:
478           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
479           data:
480             l:
481 {% for role in roles %}
482               - {get_attr: [{{role.name}}IpListMap, service_ips]}
483 {% endfor %}
484       service_node_names:
485         yaql:
486           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
487           data:
488             l:
489 {% for role in roles %}
490               - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
491 {% endfor %}
492       short_service_node_names:
493         yaql:
494           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
495           data:
496             l:
497 {% for role in roles %}
498               - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
499 {% endfor %}
500       short_service_bootstrap_node:
501         yaql:
502           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
503           data:
504             l:
505 {% for role in roles %}
506               - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
507 {% endfor %}
508       # FIXME(shardy): These require further work to move into service_ips
509       memcache_node_ips: {get_attr: [{{primary_role_name}}IpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
510       NetVipMap: {get_attr: [VipMap, net_ip_map]}
511       RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
512       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
513       DeployIdentifier: {get_param: DeployIdentifier}
514       UpdateIdentifier: {get_param: UpdateIdentifier}
515
516   MysqlRootPassword:
517     type: OS::Heat::RandomString
518     properties:
519       length: 10
520
521   RabbitCookie:
522     type: OS::Heat::RandomString
523     properties:
524       length: 20
525       salt: {get_param: RabbitCookieSalt}
526
527   DefaultPasswords:
528     type: OS::TripleO::DefaultPasswords
529     properties:
530       DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
531       DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
532       DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
533       DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
534       DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
535
536   # creates the network architecture
537   Networks:
538     type: OS::TripleO::Network
539
540   ControlVirtualIP:
541     type: OS::TripleO::Network::Ports::ControlPlaneVipPort
542     depends_on: Networks
543     properties:
544       name: control_virtual_ip
545       network: {get_param: NeutronControlPlaneID}
546       fixed_ips: {get_param: ControlFixedIPs}
547       replacement_policy: AUTO
548
549   RedisVirtualIP:
550     depends_on: Networks
551     type: OS::TripleO::Network::Ports::RedisVipPort
552     properties:
553       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
554       ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
555       PortName: redis_virtual_ip
556       NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
557       ServiceName: redis
558       FixedIPs: {get_param: RedisVirtualFixedIPs}
559
560   # The public VIP is on the External net, falls back to ctlplane
561   PublicVirtualIP:
562     depends_on: Networks
563     type: OS::TripleO::Network::Ports::ExternalVipPort
564     properties:
565       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
566       ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
567       PortName: public_virtual_ip
568       FixedIPs: {get_param: PublicVirtualFixedIPs}
569
570   InternalApiVirtualIP:
571     depends_on: Networks
572     type: OS::TripleO::Network::Ports::InternalApiVipPort
573     properties:
574       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
575       PortName: internal_api_virtual_ip
576       FixedIPs: {get_param: InternalApiVirtualFixedIPs}
577
578   StorageVirtualIP:
579     depends_on: Networks
580     type: OS::TripleO::Network::Ports::StorageVipPort
581     properties:
582       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
583       PortName: storage_virtual_ip
584       FixedIPs: {get_param: StorageVirtualFixedIPs}
585
586   StorageMgmtVirtualIP:
587     depends_on: Networks
588     type: OS::TripleO::Network::Ports::StorageMgmtVipPort
589     properties:
590       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
591       PortName: storage_management_virtual_ip
592       FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
593
594   VipMap:
595     type: OS::TripleO::Network::Ports::NetVipMap
596     properties:
597       ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
598       ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
599       ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
600       InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
601       InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
602       StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
603       StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
604       StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
605       StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
606       # No tenant or management VIP required
607
608   # All Nodes Validations
609   AllNodesValidationConfig:
610     type: OS::TripleO::AllNodes::Validation
611     properties:
612       PingTestIps:
613         list_join:
614         - ' '
615         - - yaql:
616               expression: coalesce($.data, []).first(null)
617               data: {get_attr: [{{primary_role_name}}, external_ip_address]}
618           - yaql:
619               expression: coalesce($.data, []).first(null)
620               data: {get_attr: [{{primary_role_name}}, internal_api_ip_address]}
621           - yaql:
622               expression: coalesce($.data, []).first(null)
623               data: {get_attr: [{{primary_role_name}}, storage_ip_address]}
624           - yaql:
625               expression: coalesce($.data, []).first(null)
626               data: {get_attr: [{{primary_role_name}}, storage_mgmt_ip_address]}
627           - yaql:
628               expression: coalesce($.data, []).first(null)
629               data: {get_attr: [{{primary_role_name}}, tenant_ip_address]}
630           - yaql:
631               expression: coalesce($.data, []).first(null)
632               data: {get_attr: [{{primary_role_name}}, management_ip_address]}
633
634   UpdateWorkflow:
635     type: OS::TripleO::Tasks::UpdateWorkflow
636     depends_on:
637 {% for role in roles %}
638       - {{role.name}}AllNodesDeployment
639 {% endfor %}
640     properties:
641       servers:
642 {% for role in roles %}
643         {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
644 {% endfor %}
645       input_values:
646         deploy_identifier: {get_param: DeployIdentifier}
647         update_identifier: {get_param: UpdateIdentifier}
648
649   # Optional ExtraConfig for all nodes - all roles are passed in here, but
650   # the nested template may configure each role differently (or not at all)
651   AllNodesExtraConfig:
652     type: OS::TripleO::AllNodesExtraConfig
653     depends_on:
654       - UpdateWorkflow
655 {% for role in roles %}
656       - {{role.name}}AllNodesValidationDeployment
657 {% endfor %}
658     properties:
659       servers:
660 {% for role in roles %}
661         {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
662 {% endfor %}
663
664   # Post deployment steps for all roles
665   AllNodesDeploySteps:
666     type: OS::TripleO::PostDeploySteps
667     depends_on:
668 {% for role in roles %}
669       - {{role.name}}AllNodesDeployment
670 {% endfor %}
671     properties:
672       servers:
673 {% for role in roles %}
674         {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
675 {% endfor %}
676       EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
677       role_data:
678 {% for role in roles %}
679         {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
680 {% endfor %}
681
682 outputs:
683   ManagedEndpoints:
684     description: Asserts that the keystone endpoints have been provisioned.
685     value: true
686   KeystoneURL:
687     description: URL for the Overcloud Keystone service
688     value: {get_attr: [EndpointMapData, value, KeystonePublic, uri]}
689   KeystoneAdminVip:
690     description: Keystone Admin VIP endpoint
691     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
692   EndpointMap:
693     description: |
694       Mapping of the resources with the needed info for their endpoints.
695       This includes the protocol used, the IP, port and also a full
696       representation of the URI.
697     value: {get_attr: [EndpointMapData, value]}
698   HostsEntry:
699     description: |
700       The content that should be appended to your /etc/hosts if you want to get
701       hostname-based access to the deployed nodes (useful for testing without
702       setting up a DNS).
703     value:
704       list_join:
705       - "\n"
706       - - {get_attr: [hostsConfig, hosts_entries]}
707       - - {get_attr: [VipHosts, value]}
708   EnabledServices:
709     description: The services enabled on each role
710     value:
711 {% for role in roles %}
712       {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
713 {% endfor %}
714   RoleData:
715     description: The configuration data associated with each role
716     value:
717 {% for role in roles %}
718       {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
719 {% endfor %}
720   RoleNetIpMap:
721     description: Mapping of each network to a list of IPs for each role
722     value:
723 {% for role in roles %}
724       {{role.name}}: {get_attr: [{{role.name}}IpListMap, net_ip_map]}
725 {% endfor %}