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