Merge "Release 7.0.0.0b2"
[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   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::Heat::RandomString
246
247   PcsdPassword:
248     type: OS::Heat::RandomString
249     properties:
250       length: 16
251
252   HorizonSecret:
253     type: OS::Heat::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::Heat::StructuredDeployments
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 {% endfor %}
450
451 {% for role in roles %}
452   {{role.name}}Servers:
453     type: OS::Heat::Value
454     depends_on: {{role.name}}
455     properties:
456       type: json
457       value:
458         yaql:
459           expression: let(servers=>switch(isDict($.data.servers) => $.data.servers, true => {})) -> $servers.deleteAll($servers.keys().where($servers[$] = null))
460           data:
461             servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
462 {% endfor %}
463
464   # This resource just creates a dict out of the DeploymentServerBlacklist,
465   # which is a list. The dict is used in the role templates to set a condition
466   # on whether to create the deployment resources. We can't use the list
467   # directly because there is no way to ask Heat if a list contains a specific
468   # value.
469   DeploymentServerBlacklistDict:
470     type: OS::Heat::Value
471     properties:
472       type: json
473       value:
474         map_merge:
475           repeat:
476             template:
477               hostname: 1
478             for_each:
479               hostname: {get_param: DeploymentServerBlacklist}
480
481   hostsConfig:
482     type: OS::TripleO::Hosts::SoftwareConfig
483     properties:
484       hosts:
485         list_join:
486         - "\n"
487         - - if:
488             - add_vips_to_etc_hosts
489             - {get_attr: [VipHosts, value]}
490             - ''
491         -
492 {% for role in roles %}
493           - list_join:
494             - ""
495             - {get_attr: [{{role.name}}, hosts_entry]}
496 {% endfor %}
497
498   allNodesConfig:
499     type: OS::TripleO::AllNodes::SoftwareConfig
500     properties:
501       cloud_name_external: {get_param: CloudName}
502       cloud_name_internal_api: {get_param: CloudNameInternal}
503       cloud_name_storage: {get_param: CloudNameStorage}
504       cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
505       cloud_name_ctlplane: {get_param: CloudNameCtlplane}
506       enabled_services:
507         list_join:
508           - ','
509 {% for role in roles %}
510           - {get_attr: [{{role.name}}ServiceNames, value]}
511 {% endfor %}
512       logging_groups:
513         yaql:
514           expression: >
515             $.data.groups.flatten()
516           data:
517             groups:
518 {% for role in roles %}
519               - {get_attr: [{{role.name}}ServiceChainRoleData, value, logging_groups]}
520 {% endfor %}
521       logging_sources:
522         yaql:
523           expression: >
524             $.data.sources.flatten()
525           data:
526             sources:
527 {% for role in roles %}
528               - {get_attr: [{{role.name}}ServiceChainRoleData, value, logging_sources]}
529 {% endfor %}
530       controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
531       controller_names: {get_attr: [{{primary_role_name}}, hostname]}
532       service_ips:
533         # Note (shardy) this somewhat complex yaql may be replaced
534         # with a map_deep_merge function in ocata.  It merges the
535         # list of maps, but appends to colliding lists when a service
536         # is deployed on more than one role
537         yaql:
538           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
539           data:
540             l:
541 {% for role in roles %}
542               - {get_attr: [{{role.name}}IpListMap, service_ips]}
543 {% endfor %}
544       service_node_names:
545         yaql:
546           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
547           data:
548             l:
549 {% for role in roles %}
550               - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
551 {% endfor %}
552       short_service_node_names:
553         yaql:
554           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
555           data:
556             l:
557 {% for role in roles %}
558               - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
559 {% endfor %}
560       short_service_bootstrap_node:
561         yaql:
562           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
563           data:
564             l:
565 {% for role in roles %}
566               - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
567 {% endfor %}
568       # FIXME(shardy): These require further work to move into service_ips
569       memcache_node_ips: {get_attr: [{{primary_role_name}}IpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
570       NetVipMap: {get_attr: [VipMap, net_ip_map]}
571       RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
572       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
573       DeployIdentifier: {get_param: DeployIdentifier}
574       UpdateIdentifier: {get_param: UpdateIdentifier}
575
576   MysqlRootPassword:
577     type: OS::Heat::RandomString
578     properties:
579       length: 10
580
581   RabbitCookie:
582     type: OS::Heat::RandomString
583     properties:
584       length: 20
585       salt: {get_param: RabbitCookieSalt}
586
587   DefaultPasswords:
588     type: OS::TripleO::DefaultPasswords
589     properties:
590       DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
591       DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
592       DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
593       DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
594       DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
595
596   # creates the network architecture
597   Networks:
598     type: OS::TripleO::Network
599
600   ControlVirtualIP:
601     type: OS::TripleO::Network::Ports::ControlPlaneVipPort
602     depends_on: Networks
603     properties:
604       name: control_virtual_ip
605       network: {get_param: NeutronControlPlaneID}
606       fixed_ips: {get_param: ControlFixedIPs}
607       replacement_policy: AUTO
608
609   RedisVirtualIP:
610     depends_on: Networks
611     type: OS::TripleO::Network::Ports::RedisVipPort
612     properties:
613       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
614       ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
615       PortName: redis_virtual_ip
616       NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
617       ServiceName: redis
618       FixedIPs: {get_param: RedisVirtualFixedIPs}
619
620   # The public VIP is on the External net, falls back to ctlplane
621   PublicVirtualIP:
622     depends_on: Networks
623     type: OS::TripleO::Network::Ports::ExternalVipPort
624     properties:
625       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
626       ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
627       PortName: public_virtual_ip
628       FixedIPs: {get_param: PublicVirtualFixedIPs}
629
630   InternalApiVirtualIP:
631     depends_on: Networks
632     type: OS::TripleO::Network::Ports::InternalApiVipPort
633     properties:
634       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
635       PortName: internal_api_virtual_ip
636       FixedIPs: {get_param: InternalApiVirtualFixedIPs}
637
638   StorageVirtualIP:
639     depends_on: Networks
640     type: OS::TripleO::Network::Ports::StorageVipPort
641     properties:
642       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
643       PortName: storage_virtual_ip
644       FixedIPs: {get_param: StorageVirtualFixedIPs}
645
646   StorageMgmtVirtualIP:
647     depends_on: Networks
648     type: OS::TripleO::Network::Ports::StorageMgmtVipPort
649     properties:
650       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
651       PortName: storage_management_virtual_ip
652       FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
653
654   VipMap:
655     type: OS::TripleO::Network::Ports::NetVipMap
656     properties:
657       ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
658       ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
659       ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
660       InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
661       InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
662       StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
663       StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
664       StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
665       StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
666       # No tenant or management VIP required
667
668   # All Nodes Validations
669   AllNodesValidationConfig:
670     type: OS::TripleO::AllNodes::Validation
671     properties:
672       PingTestIps:
673         list_join:
674         - ' '
675         - - yaql:
676               expression: coalesce($.data, []).first(null)
677               data: {get_attr: [{{primary_role_name}}, external_ip_address]}
678           - yaql:
679               expression: coalesce($.data, []).first(null)
680               data: {get_attr: [{{primary_role_name}}, internal_api_ip_address]}
681           - yaql:
682               expression: coalesce($.data, []).first(null)
683               data: {get_attr: [{{primary_role_name}}, storage_ip_address]}
684           - yaql:
685               expression: coalesce($.data, []).first(null)
686               data: {get_attr: [{{primary_role_name}}, storage_mgmt_ip_address]}
687           - yaql:
688               expression: coalesce($.data, []).first(null)
689               data: {get_attr: [{{primary_role_name}}, tenant_ip_address]}
690           - yaql:
691               expression: coalesce($.data, []).first(null)
692               data: {get_attr: [{{primary_role_name}}, management_ip_address]}
693
694   UpdateWorkflow:
695     type: OS::TripleO::Tasks::UpdateWorkflow
696     depends_on:
697 {% for role in roles %}
698       - {{role.name}}AllNodesDeployment
699 {% endfor %}
700     properties:
701       servers:
702 {% for role in roles %}
703         {{role.name}}: {get_attr: [{{role.name}}Servers, value]}
704 {% endfor %}
705       input_values:
706         deploy_identifier: {get_param: DeployIdentifier}
707         update_identifier: {get_param: UpdateIdentifier}
708
709   # Optional ExtraConfig for all nodes - all roles are passed in here, but
710   # the nested template may configure each role differently (or not at all)
711   AllNodesExtraConfig:
712     type: OS::TripleO::AllNodesExtraConfig
713     depends_on:
714       - UpdateWorkflow
715 {% for role in roles %}
716       - {{role.name}}AllNodesValidationDeployment
717 {% endfor %}
718     properties:
719       servers:
720 {% for role in roles %}
721         {{role.name}}: {get_attr: [{{role.name}}Servers, value]}
722 {% endfor %}
723
724   # Post deployment steps for all roles
725   AllNodesDeploySteps:
726     type: OS::TripleO::PostDeploySteps
727     depends_on:
728       - AllNodesExtraConfig
729 {% for role in roles %}
730       - {{role.name}}AllNodesDeployment
731 {% endfor %}
732     properties:
733       servers:
734 {% for role in roles %}
735         {{role.name}}: {get_attr: [{{role.name}}Servers, value]}
736 {% endfor %}
737       EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
738       role_data:
739 {% for role in roles %}
740         {{role.name}}: {get_attr: [{{role.name}}ServiceChainRoleData, value]}
741 {% endfor %}
742
743 outputs:
744   ManagedEndpoints:
745     description: Asserts that the keystone endpoints have been provisioned.
746     value: true
747   KeystoneURL:
748     description: URL for the Overcloud Keystone service
749     value: {get_attr: [EndpointMapData, value, KeystonePublic, uri]}
750   KeystoneAdminVip:
751     description: Keystone Admin VIP endpoint
752     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
753   EndpointMap:
754     description: |
755       Mapping of the resources with the needed info for their endpoints.
756       This includes the protocol used, the IP, port and also a full
757       representation of the URI.
758     value: {get_attr: [EndpointMapData, value]}
759   HostsEntry:
760     description: |
761       The content that should be appended to your /etc/hosts if you want to get
762       hostname-based access to the deployed nodes (useful for testing without
763       setting up a DNS).
764     value:
765       list_join:
766       - "\n"
767       - - {get_attr: [hostsConfig, hosts_entries]}
768       - - {get_attr: [VipHosts, value]}
769   EnabledServices:
770     description: The services enabled on each role
771     value:
772 {% for role in roles %}
773       {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
774 {% endfor %}
775   RoleData:
776     description: The configuration data associated with each role
777     value:
778 {% for role in roles %}
779       {{role.name}}: {get_attr: [{{role.name}}ServiceChainRoleData, value]}
780 {% endfor %}
781   RoleNetIpMap:
782     description: Mapping of each network to a list of IPs for each role
783     value:
784 {% for role in roles %}
785       {{role.name}}: {get_attr: [{{role.name}}IpListMap, net_ip_map]}
786 {% endfor %}
787   RoleNetHostnameMap:
788     description: Mapping of each network to a list of hostnames for each role
789     value:
790 {% for role in roles %}
791       {{role.name}}: {get_attr: [{{role.name}}NetworkHostnameMap, value]}
792 {% endfor %}