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