Merge "Add split-stack environments"
[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 must match the
105       overcloud_domain_name configured on the undercloud.
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   DeploymentServerBlacklist:
201     default: []
202     type: comma_delimited_list
203     description: >
204       List of server hostnames to blacklist from any triggered deployments.
205
206 conditions:
207   add_vips_to_etc_hosts: {equals : [{get_param: AddVipsToEtcHosts}, True]}
208
209 resources:
210
211   VipHosts:
212     type: OS::Heat::Value
213     properties:
214       type: string
215       value:
216         list_join:
217         - "\n"
218         - - str_replace:
219               template: IP  HOST
220               params:
221                 IP: {get_attr: [VipMap, net_ip_map, external]}
222                 HOST: {get_param: CloudName}
223           - str_replace:
224               template: IP  HOST
225               params:
226                 IP: {get_attr: [VipMap, net_ip_map, ctlplane]}
227                 HOST: {get_param: CloudNameCtlplane}
228           - str_replace:
229               template: IP  HOST
230               params:
231                 IP: {get_attr: [VipMap, net_ip_map, internal_api]}
232                 HOST: {get_param: CloudNameInternal}
233           - str_replace:
234               template: IP  HOST
235               params:
236                 IP: {get_attr: [VipMap, net_ip_map, storage]}
237                 HOST: {get_param: CloudNameStorage}
238           - str_replace:
239               template: IP  HOST
240               params:
241                 IP: {get_attr: [VipMap, net_ip_map, storage_mgmt]}
242                 HOST: {get_param: CloudNameStorageManagement}
243
244   HeatAuthEncryptionKey:
245     type: OS::TripleO::RandomString
246
247   PcsdPassword:
248     type: OS::TripleO::RandomString
249     properties:
250       length: 16
251
252   HorizonSecret:
253     type: OS::TripleO::RandomString
254     properties:
255       length: 10
256
257   ServiceNetMap:
258     type: OS::TripleO::ServiceNetMap
259
260   EndpointMap:
261     type: OS::TripleO::EndpointMap
262     properties:
263       CloudEndpoints:
264         external: {get_param: CloudName}
265         internal_api: {get_param: CloudNameInternal}
266         storage: {get_param: CloudNameStorage}
267         storage_mgmt: {get_param: CloudNameStorageManagement}
268         ctlplane: {get_param: CloudNameCtlplane}
269       NetIpMap: {get_attr: [VipMap, net_ip_map]}
270       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
271
272   EndpointMapData:
273     type: OS::Heat::Value
274     properties:
275       type: json
276       value: {get_attr: [EndpointMap, endpoint_map]}
277
278   SshKnownHostsConfig:
279     type: OS::TripleO::Ssh::KnownHostsConfig
280     properties:
281       known_hosts:
282         list_join:
283           - ''
284           {% for role in roles %}
285           - {get_attr: [{{role.name}}, known_hosts_entry]}
286           {% endfor %}
287
288   # Jinja loop for Role in roles_data.yaml
289 {% for role in roles %}
290   # Resources generated for {{role.name}} Role
291   {{role.name}}ServiceChain:
292     type: OS::TripleO::Services
293     properties:
294       Services:
295         get_param: {{role.name}}Services
296       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
297       EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
298       DefaultPasswords: {get_attr: [DefaultPasswords, passwords]}
299       RoleName: {{role.name}}
300       RoleParameters: {get_param: {{role.name}}Parameters}
301
302   # Lookup of role_data via heat outputs is slow, so workaround this by caching
303   # the value in an OS::Heat::Value resource
304   {{role.name}}ServiceChainRoleData:
305     type: OS::Heat::Value
306     properties:
307       type: json
308       value: {get_attr: [{{role.name}}ServiceChain, role_data]}
309
310   # Filter any null/None service_names which may be present due to mapping
311   # of services to OS::Heat::None
312   {{role.name}}ServiceNames:
313     type: OS::Heat::Value
314     depends_on: {{role.name}}ServiceChain
315     properties:
316       type: comma_delimited_list
317       value:
318         yaql:
319           expression: coalesce($.data, []).where($ != null)
320           data: {get_attr: [{{role.name}}ServiceChainRoleData, value, service_names]}
321
322   {{role.name}}HostsDeployment:
323     type: OS::Heat::StructuredDeployments
324     properties:
325       name: {{role.name}}HostsDeployment
326       config: {get_attr: [hostsConfig, config_id]}
327       servers: {get_attr: [{{role.name}}Servers, value]}
328
329   {{role.name}}SshKnownHostsDeployment:
330     type: OS::Heat::StructuredDeployments
331     properties:
332       name: {{role.name}}SshKnownHostsDeployment
333       config: {get_resource: SshKnownHostsConfig}
334       servers: {get_attr: [{{role.name}}Servers, value]}
335
336   {{role.name}}AllNodesDeployment:
337     type: OS::TripleO::AllNodesDeployment
338     depends_on:
339 {% for role_inner in roles %}
340       - {{role_inner.name}}HostsDeployment
341 {% endfor %}
342     properties:
343       name: {{role.name}}AllNodesDeployment
344       config: {get_attr: [allNodesConfig, config_id]}
345       servers: {get_attr: [{{role.name}}Servers, value]}
346       input_values:
347         # Note we have to use yaql to look up the first hostname/ip in the
348         # list because heat path based attributes operate on the attribute
349         # inside the ResourceGroup, not the exposed list ref discussion in
350         # https://bugs.launchpad.net/heat/+bug/1640488
351         # The coalesce is needed because $.data is None during heat validation
352         bootstrap_nodeid:
353           yaql:
354             expression: coalesce($.data, []).first(null)
355             data: {get_attr: [{{role.name}}, hostname]}
356         bootstrap_nodeid_ip:
357           yaql:
358             expression: coalesce($.data, []).first(null)
359             data: {get_attr: [{{role.name}}, ip_address]}
360
361   {{role.name}}AllNodesValidationDeployment:
362     type: OS::Heat::StructuredDeployments
363     depends_on: {{role.name}}AllNodesDeployment
364     properties:
365       name: {{role.name}}AllNodesValidationDeployment
366       config: {get_resource: AllNodesValidationConfig}
367       servers: {get_attr: [{{role.name}}Servers, value]}
368
369   {{role.name}}IpListMap:
370     type: OS::TripleO::Network::Ports::NetIpListMap
371     properties:
372       ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
373       ExternalIpList: {get_attr: [{{role.name}}, external_ip_address]}
374       InternalApiIpList: {get_attr: [{{role.name}}, internal_api_ip_address]}
375       StorageIpList: {get_attr: [{{role.name}}, storage_ip_address]}
376       StorageMgmtIpList: {get_attr: [{{role.name}}, storage_mgmt_ip_address]}
377       TenantIpList: {get_attr: [{{role.name}}, tenant_ip_address]}
378       ManagementIpList: {get_attr: [{{role.name}}, management_ip_address]}
379       EnabledServices: {get_attr: [{{role.name}}ServiceNames, value]}
380       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
381       ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
382       NetworkHostnameMap: {get_attr: [{{role.name}}NetworkHostnameMap, value]}
383
384   {{role.name}}NetworkHostnameMap:
385     type: OS::Heat::Value
386     properties:
387       type: json
388       value:
389         # Note (shardy) this somewhat complex yaql may be replaced
390         # with a map_deep_merge function in ocata.  It merges the
391         # list of maps, but appends to colliding lists so we can
392         # create a map of lists for all nodes for each network
393         yaql:
394           expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
395           data:
396             - {get_attr: [{{role.name}}, hostname_map]}
397
398   {{role.name}}:
399     type: OS::Heat::ResourceGroup
400     depends_on: Networks
401     update_policy:
402       batch_create:
403         max_batch_size: {get_param: NodeCreateBatchSize}
404     properties:
405       count: {get_param: {{role.name}}Count}
406       removal_policies: {get_param: {{role.name}}RemovalPolicies}
407       resource_def:
408         type: OS::TripleO::{{role.name}}
409         properties:
410           CloudDomain: {get_param: CloudDomain}
411           ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
412           EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
413           Hostname:
414             str_replace:
415               template: {get_param: {{role.name}}HostnameFormat}
416               params:
417                 '%stackname%': {get_param: 'OS::stack_name'}
418           NodeIndex: '%index%'
419   {% if role.name != 'Compute' %}
420           {{role.name}}SchedulerHints: {get_param: {{role.name}}SchedulerHints}
421   {% else %}
422           NovaComputeSchedulerHints: {get_param: NovaComputeSchedulerHints}
423   {% endif %}
424           ServiceConfigSettings:
425             map_merge:
426               -  get_attr: [{{role.name}}ServiceChainRoleData, value, config_settings]
427           {% for r in roles %}
428               - get_attr: [{{r.name}}ServiceChain, role_data, global_config_settings]
429           {% endfor %}
430               # This next step combines two yaql passes:
431               # - The inner one does a deep merge on the service_config_settings for all roles
432               # - The outer one filters the map based on the services enabled for the role
433               #   then merges the result into one map.
434               - yaql:
435                   expression: let(root => $) -> $.data.map.items().where($[0] in coalesce($root.data.services, [])).select($[1]).reduce($1.mergeWith($2), {})
436                   data:
437                     map:
438                       yaql:
439                         expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
440                         data:
441                         {% for r in roles %}
442                           - get_attr: [{{r.name}}ServiceChain, role_data, service_config_settings]
443                         {% endfor %}
444                     services: {get_attr: [{{role.name}}ServiceNames, value]}
445           ServiceNames: {get_attr: [{{role.name}}ServiceNames, value]}
446           MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChainRoleData, value, monitoring_subscriptions]}
447           ServiceMetadataSettings: {get_attr: [{{role.name}}ServiceChainRoleData, value, service_metadata_settings]}
448           DeploymentServerBlacklistDict: {get_attr: [DeploymentServerBlacklistDict, value]}
449           RoleParameters: {get_param: {{role.name}}Parameters}
450 {% endfor %}
451
452 {% for role in roles %}
453   {{role.name}}Servers:
454     type: OS::Heat::Value
455     depends_on: {{role.name}}
456     properties:
457       type: json
458       value:
459         yaql:
460           expression: let(servers=>switch(isDict($.data.servers) => $.data.servers, true => {})) -> $servers.deleteAll($servers.keys().where($servers[$] = null))
461           data:
462             servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
463 {% endfor %}
464
465   # This resource just creates a dict out of the DeploymentServerBlacklist,
466   # which is a list. The dict is used in the role templates to set a condition
467   # on whether to create the deployment resources. We can't use the list
468   # directly because there is no way to ask Heat if a list contains a specific
469   # value.
470   DeploymentServerBlacklistDict:
471     type: OS::Heat::Value
472     properties:
473       type: json
474       value:
475         map_merge:
476           repeat:
477             template:
478               hostname: 1
479             for_each:
480               hostname: {get_param: DeploymentServerBlacklist}
481
482   hostsConfig:
483     type: OS::TripleO::Hosts::SoftwareConfig
484     properties:
485       hosts:
486         list_join:
487         - "\n"
488         - - if:
489             - add_vips_to_etc_hosts
490             - {get_attr: [VipHosts, value]}
491             - ''
492         -
493 {% for role in roles %}
494           - list_join:
495             - ""
496             - {get_attr: [{{role.name}}, hosts_entry]}
497 {% endfor %}
498
499   allNodesConfig:
500     type: OS::TripleO::AllNodes::SoftwareConfig
501     properties:
502       cloud_name_external: {get_param: CloudName}
503       cloud_name_internal_api: {get_param: CloudNameInternal}
504       cloud_name_storage: {get_param: CloudNameStorage}
505       cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
506       cloud_name_ctlplane: {get_param: CloudNameCtlplane}
507       enabled_services:
508         list_join:
509           - ','
510 {% for role in roles %}
511           - {get_attr: [{{role.name}}ServiceNames, value]}
512 {% endfor %}
513       logging_groups:
514         yaql:
515           expression: >
516             $.data.groups.flatten()
517           data:
518             groups:
519 {% for role in roles %}
520               - {get_attr: [{{role.name}}ServiceChainRoleData, value, logging_groups]}
521 {% endfor %}
522       logging_sources:
523         yaql:
524           expression: >
525             $.data.sources.flatten()
526           data:
527             sources:
528 {% for role in roles %}
529               - {get_attr: [{{role.name}}ServiceChainRoleData, value, logging_sources]}
530 {% endfor %}
531       controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
532       controller_names: {get_attr: [{{primary_role_name}}, hostname]}
533       service_ips:
534         # Note (shardy) this somewhat complex yaql may be replaced
535         # with a map_deep_merge function in ocata.  It merges the
536         # list of maps, but appends to colliding lists when a service
537         # is deployed on more than one role
538         yaql:
539           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
540           data:
541             l:
542 {% for role in roles %}
543               - {get_attr: [{{role.name}}IpListMap, service_ips]}
544 {% endfor %}
545       service_node_names:
546         yaql:
547           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
548           data:
549             l:
550 {% for role in roles %}
551               - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
552 {% endfor %}
553       short_service_node_names:
554         yaql:
555           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
556           data:
557             l:
558 {% for role in roles %}
559               - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
560 {% endfor %}
561       short_service_bootstrap_node:
562         yaql:
563           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
564           data:
565             l:
566 {% for role in roles %}
567               - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
568 {% endfor %}
569       # FIXME(shardy): These require further work to move into service_ips
570       memcache_node_ips: {get_attr: [{{primary_role_name}}IpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
571       NetVipMap: {get_attr: [VipMap, net_ip_map]}
572       RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
573       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
574       DeployIdentifier: {get_param: DeployIdentifier}
575       UpdateIdentifier: {get_param: UpdateIdentifier}
576
577   MysqlRootPassword:
578     type: OS::TripleO::RandomString
579     properties:
580       length: 10
581
582   RabbitCookie:
583     type: OS::TripleO::RandomString
584     properties:
585       length: 20
586       salt: {get_param: RabbitCookieSalt}
587
588   DefaultPasswords:
589     type: OS::TripleO::DefaultPasswords
590     properties:
591       DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
592       DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
593       DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
594       DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
595       DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
596
597   # creates the network architecture
598   Networks:
599     type: OS::TripleO::Network
600
601   ControlVirtualIP:
602     type: OS::TripleO::Network::Ports::ControlPlaneVipPort
603     depends_on: Networks
604     properties:
605       name: control_virtual_ip
606       network: {get_param: NeutronControlPlaneID}
607       fixed_ips: {get_param: ControlFixedIPs}
608       replacement_policy: AUTO
609
610   RedisVirtualIP:
611     depends_on: Networks
612     type: OS::TripleO::Network::Ports::RedisVipPort
613     properties:
614       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
615       ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
616       PortName: redis_virtual_ip
617       NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
618       ServiceName: redis
619       FixedIPs: {get_param: RedisVirtualFixedIPs}
620
621   # The public VIP is on the External net, falls back to ctlplane
622   PublicVirtualIP:
623     depends_on: Networks
624     type: OS::TripleO::Network::Ports::ExternalVipPort
625     properties:
626       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
627       ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
628       PortName: public_virtual_ip
629       FixedIPs: {get_param: PublicVirtualFixedIPs}
630
631   InternalApiVirtualIP:
632     depends_on: Networks
633     type: OS::TripleO::Network::Ports::InternalApiVipPort
634     properties:
635       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
636       PortName: internal_api_virtual_ip
637       FixedIPs: {get_param: InternalApiVirtualFixedIPs}
638
639   StorageVirtualIP:
640     depends_on: Networks
641     type: OS::TripleO::Network::Ports::StorageVipPort
642     properties:
643       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
644       PortName: storage_virtual_ip
645       FixedIPs: {get_param: StorageVirtualFixedIPs}
646
647   StorageMgmtVirtualIP:
648     depends_on: Networks
649     type: OS::TripleO::Network::Ports::StorageMgmtVipPort
650     properties:
651       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
652       PortName: storage_management_virtual_ip
653       FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
654
655   VipMap:
656     type: OS::TripleO::Network::Ports::NetVipMap
657     properties:
658       ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
659       ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
660       ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
661       InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
662       InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
663       StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
664       StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
665       StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
666       StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
667       # No tenant or management VIP required
668
669   # All Nodes Validations
670   AllNodesValidationConfig:
671     type: OS::TripleO::AllNodes::Validation
672     properties:
673       PingTestIps:
674         list_join:
675         - ' '
676         - - yaql:
677               expression: coalesce($.data, []).first(null)
678               data: {get_attr: [{{primary_role_name}}, external_ip_address]}
679           - yaql:
680               expression: coalesce($.data, []).first(null)
681               data: {get_attr: [{{primary_role_name}}, internal_api_ip_address]}
682           - yaql:
683               expression: coalesce($.data, []).first(null)
684               data: {get_attr: [{{primary_role_name}}, storage_ip_address]}
685           - yaql:
686               expression: coalesce($.data, []).first(null)
687               data: {get_attr: [{{primary_role_name}}, storage_mgmt_ip_address]}
688           - yaql:
689               expression: coalesce($.data, []).first(null)
690               data: {get_attr: [{{primary_role_name}}, tenant_ip_address]}
691           - yaql:
692               expression: coalesce($.data, []).first(null)
693               data: {get_attr: [{{primary_role_name}}, management_ip_address]}
694
695   UpdateWorkflow:
696     type: OS::TripleO::Tasks::UpdateWorkflow
697     depends_on:
698 {% for role in roles %}
699       - {{role.name}}AllNodesDeployment
700 {% endfor %}
701     properties:
702       servers:
703 {% for role in roles %}
704         {{role.name}}: {get_attr: [{{role.name}}Servers, value]}
705 {% endfor %}
706       input_values:
707         deploy_identifier: {get_param: DeployIdentifier}
708         update_identifier: {get_param: UpdateIdentifier}
709
710   # Optional ExtraConfig for all nodes - all roles are passed in here, but
711   # the nested template may configure each role differently (or not at all)
712   AllNodesExtraConfig:
713     type: OS::TripleO::AllNodesExtraConfig
714     depends_on:
715       - UpdateWorkflow
716 {% for role in roles %}
717       - {{role.name}}AllNodesValidationDeployment
718 {% endfor %}
719     properties:
720       servers:
721 {% for role in roles %}
722         {{role.name}}: {get_attr: [{{role.name}}Servers, value]}
723 {% endfor %}
724
725   # Post deployment steps for all roles
726   AllNodesDeploySteps:
727     type: OS::TripleO::PostDeploySteps
728     depends_on:
729       - AllNodesExtraConfig
730 {% for role in roles %}
731       - {{role.name}}AllNodesDeployment
732 {% endfor %}
733     properties:
734       servers:
735 {% for role in roles %}
736         {{role.name}}: {get_attr: [{{role.name}}Servers, value]}
737 {% endfor %}
738       EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
739       role_data:
740 {% for role in roles %}
741         {{role.name}}: {get_attr: [{{role.name}}ServiceChainRoleData, value]}
742 {% endfor %}
743
744   ServerOsCollectConfigData:
745     type: OS::Heat::Value
746     properties:
747       type: json
748       value:
749 {% for role in roles %}
750         {{role.name}}: {get_attr: [{{role.name}}, attributes, os_collect_config]}
751 {% endfor %}
752
753 outputs:
754   ManagedEndpoints:
755     description: Asserts that the keystone endpoints have been provisioned.
756     value: true
757   KeystoneURL:
758     description: URL for the Overcloud Keystone service
759     value: {get_attr: [EndpointMapData, value, KeystonePublic, uri]}
760   KeystoneAdminVip:
761     description: Keystone Admin VIP endpoint
762     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
763   EndpointMap:
764     description: |
765       Mapping of the resources with the needed info for their endpoints.
766       This includes the protocol used, the IP, port and also a full
767       representation of the URI.
768     value: {get_attr: [EndpointMapData, value]}
769   HostsEntry:
770     description: |
771       The content that should be appended to your /etc/hosts if you want to get
772       hostname-based access to the deployed nodes (useful for testing without
773       setting up a DNS).
774     value:
775       list_join:
776       - "\n"
777       - - {get_attr: [hostsConfig, hosts_entries]}
778       - - {get_attr: [VipHosts, value]}
779   EnabledServices:
780     description: The services enabled on each role
781     value:
782 {% for role in roles %}
783       {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
784 {% endfor %}
785   RoleData:
786     description: The configuration data associated with each role
787     value:
788 {% for role in roles %}
789       {{role.name}}: {get_attr: [{{role.name}}ServiceChainRoleData, value]}
790 {% endfor %}
791   RoleNetIpMap:
792     description: Mapping of each network to a list of IPs for each role
793     value:
794 {% for role in roles %}
795       {{role.name}}: {get_attr: [{{role.name}}IpListMap, net_ip_map]}
796 {% endfor %}
797   RoleNetHostnameMap:
798     description: Mapping of each network to a list of hostnames for each role
799     value:
800 {% for role in roles %}
801       {{role.name}}: {get_attr: [{{role.name}}NetworkHostnameMap, value]}
802 {% endfor %}
803   ServerOsCollectConfigData:
804     description: The os-collect-config configuration associated with each server resource
805     value:
806 {% for role in roles %}
807       {{role.name}}: {get_attr: [{{role.name}}, attributes, os_collect_config]}
808 {% endfor %}