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