Merge "Add ceilometer ipmi agent"
[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             - ""
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         - - yaql:
591               expression: coalesce($.data, []).first(null)
592               data: {get_attr: [{{primary_role_name}}, external_ip_address]}
593           - yaql:
594               expression: coalesce($.data, []).first(null)
595               data: {get_attr: [{{primary_role_name}}, internal_api_ip_address]}
596           - yaql:
597               expression: coalesce($.data, []).first(null)
598               data: {get_attr: [{{primary_role_name}}, storage_ip_address]}
599           - yaql:
600               expression: coalesce($.data, []).first(null)
601               data: {get_attr: [{{primary_role_name}}, storage_mgmt_ip_address]}
602           - yaql:
603               expression: coalesce($.data, []).first(null)
604               data: {get_attr: [{{primary_role_name}}, tenant_ip_address]}
605           - yaql:
606               expression: coalesce($.data, []).first(null)
607               data: {get_attr: [{{primary_role_name}}, management_ip_address]}
608
609   UpdateWorkflow:
610     type: OS::TripleO::Tasks::UpdateWorkflow
611     depends_on:
612 {% for role in roles %}
613       - {{role.name}}AllNodesDeployment
614 {% endfor %}
615     properties:
616       servers:
617 {% for role in roles %}
618         {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
619 {% endfor %}
620       input_values:
621         deploy_identifier: {get_param: DeployIdentifier}
622         update_identifier: {get_param: UpdateIdentifier}
623
624   # Optional ExtraConfig for all nodes - all roles are passed in here, but
625   # the nested template may configure each role differently (or not at all)
626   AllNodesExtraConfig:
627     type: OS::TripleO::AllNodesExtraConfig
628     depends_on:
629       - UpdateWorkflow
630 {% for role in roles %}
631       - {{role.name}}AllNodesValidationDeployment
632 {% endfor %}
633     properties:
634       servers:
635 {% for role in roles %}
636         {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
637 {% endfor %}
638
639   # Post deployment steps for all roles
640   AllNodesDeploySteps:
641     type: OS::TripleO::PostDeploySteps
642     depends_on:
643 {% for role in roles %}
644       - {{role.name}}AllNodesDeployment
645 {% endfor %}
646     properties:
647       servers:
648 {% for role in roles %}
649         {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
650 {% endfor %}
651       EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
652       role_data:
653 {% for role in roles %}
654         {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
655 {% endfor %}
656
657 outputs:
658   ManagedEndpoints:
659     description: Asserts that the keystone endpoints have been provisioned.
660     value: true
661   KeystoneURL:
662     description: URL for the Overcloud Keystone service
663     value: {get_attr: [EndpointMapData, value, KeystonePublic, uri]}
664   KeystoneAdminVip:
665     description: Keystone Admin VIP endpoint
666     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
667   EndpointMap:
668     description: |
669       Mapping of the resources with the needed info for their endpoints.
670       This includes the protocol used, the IP, port and also a full
671       representation of the URI.
672     value: {get_attr: [EndpointMapData, value]}
673   HostsEntry:
674     description: |
675       The content that should be appended to your /etc/hosts if you want to get
676       hostname-based access to the deployed nodes (useful for testing without
677       setting up a DNS).
678     value:
679       list_join:
680       - "\n"
681       - - {get_attr: [hostsConfig, hosts_entries]}
682       - - {get_attr: [VipHosts, value]}
683   EnabledServices:
684     description: The services enabled on each role
685     value:
686 {% for role in roles %}
687       {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
688 {% endfor %}
689   RoleData:
690     description: The configuration data associated with each role
691     value:
692 {% for role in roles %}
693       {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
694 {% endfor %}