Merge "Ensure all HostsDeployments finish before puppet"
[apex-tripleo-heat-templates.git] / overcloud.j2.yaml
1 heat_template_version: 2016-10-14
2
3 description: >
4   Deploy an OpenStack environment, consisting of several node types (roles),
5   Controller, Compute, BlockStorage, SwiftStorage and CephStorage. The Storage
6   roles enable independent scaling of the storage components, but the minimal
7   deployment is one Controller and one Compute node.
8
9
10 # TODO(shadower): we should probably use the parameter groups to put
11 # some order in here.
12 parameters:
13
14   # Common parameters (not specific to a role)
15   CloudName:
16     default: overcloud.localdomain
17     description: The DNS name of this cloud. E.g. ci-overcloud.tripleo.org
18     type: string
19   CloudNameInternal:
20     default: overcloud.internalapi.localdomain
21     description: >
22       The DNS name of this cloud's internal API endpoint. E.g.
23       'ci-overcloud.internalapi.tripleo.org'.
24     type: string
25   CloudNameStorage:
26     default: overcloud.storage.localdomain
27     description: >
28       The DNS name of this cloud's storage endpoint. E.g.
29       'ci-overcloud.storage.tripleo.org'.
30     type: string
31   CloudNameStorageManagement:
32     default: overcloud.storagemgmt.localdomain
33     description: >
34       The DNS name of this cloud's storage management endpoint. E.g.
35       'ci-overcloud.storagemgmt.tripleo.org'.
36     type: string
37   CloudNameCtlplane:
38     default: overcloud.ctlplane.localdomain
39     description: >
40       The DNS name of this cloud's storage management endpoint. E.g.
41       'ci-overcloud.management.tripleo.org'.
42     type: string
43   ControlFixedIPs:
44     default: []
45     description: Should be used for arbitrary ips.
46     type: json
47   InternalApiVirtualFixedIPs:
48     default: []
49     description: >
50         Control the IP allocation for the InternalApiVirtualInterface port. E.g.
51         [{'ip_address':'1.2.3.4'}]
52     type: json
53   NeutronControlPlaneID:
54     default: 'ctlplane'
55     type: string
56     description: Neutron ID or name for ctlplane network.
57   NeutronPublicInterface:
58     default: nic1
59     description: What interface to bridge onto br-ex for network nodes.
60     type: string
61   PublicVirtualFixedIPs:
62     default: []
63     description: >
64         Control the IP allocation for the PublicVirtualInterface port. E.g.
65         [{'ip_address':'1.2.3.4'}]
66     type: json
67   RabbitCookieSalt:
68     type: string
69     default: unset
70     description: Salt for the rabbit cookie, change this to force the randomly generated rabbit cookie to change.
71   StorageVirtualFixedIPs:
72     default: []
73     description: >
74         Control the IP allocation for the StorageVirtualInterface port. E.g.
75         [{'ip_address':'1.2.3.4'}]
76     type: json
77   StorageMgmtVirtualFixedIPs:
78     default: []
79     description: >
80         Control the IP allocation for the StorageMgmgVirtualInterface port. E.g.
81         [{'ip_address':'1.2.3.4'}]
82     type: json
83   RedisVirtualFixedIPs:
84     default: []
85     description: >
86         Control the IP allocation for the virtual IP used by Redis. E.g.
87         [{'ip_address':'1.2.3.4'}]
88     type: json
89   CloudDomain:
90     default: 'localdomain'
91     type: string
92     description: >
93       The DNS domain used for the hosts. This should match the dhcp_domain
94       configured in the Undercloud neutron. Defaults to localdomain.
95   ServerMetadata:
96     default: {}
97     description: >
98       Extra properties or metadata passed to Nova for the created nodes in
99       the overcloud. It's accessible via the Nova metadata API.
100     type: json
101
102 # Compute-specific params
103 # FIXME(shardy) handle these deprecated names as they don't match compute.yaml
104   HypervisorNeutronPhysicalBridge:
105     default: 'br-ex'
106     description: >
107       An OVS bridge to create on each hypervisor. This defaults to br-ex the
108       same as the control plane nodes, as we have a uniform configuration of
109       the openvswitch agent. Typically should not need to be changed.
110     type: string
111   HypervisorNeutronPublicInterface:
112     default: nic1
113     description: What interface to add to the HypervisorNeutronPhysicalBridge.
114     type: string
115
116   # Jinja loop for Role in role_data.yaml
117 {% for role in roles %}
118   # Parameters generated for {{role.name}} Role
119   {{role.name}}Services:
120     description: A list of service resources (configured in the Heat
121                  resource_registry) which represent nested stacks
122                  for each service that should get installed on the {{role.name}} role.
123     type: comma_delimited_list
124     default: {{role.ServicesDefault|default([])}}
125
126   {{role.name}}Count:
127     description: Number of {{role.name}} nodes to deploy
128     type: number
129     default: {{role.CountDefault|default(0)}}
130
131   {{role.name}}HostnameFormat:
132     type: string
133     description: >
134       Format for {{role.name}} node hostnames
135       Note %index% is translated into the index of the node, e.g 0/1/2 etc
136       and %stackname% is replaced with the stack name e.g overcloud
137   {% if role.HostnameFormatDefault %}
138     default: "{{role.HostnameFormatDefault}}"
139   {% else %}
140     default: "%stackname%-{{role.name.lower()}}-%index%"
141   {% endif %}
142
143   {{role.name}}RemovalPolicies:
144     default: []
145     type: json
146     description: >
147       List of resources to be removed from {{role.name}} ResourceGroup when
148       doing an update which requires removal of specific resources.
149       Example format ComputeRemovalPolicies: [{'resource_list': ['0']}]
150
151 {% if role.name != 'Compute' %}
152   {{role.name}}SchedulerHints:
153 {% else %}
154   NovaComputeSchedulerHints:
155 {% endif %}
156     type: json
157     description: Optional scheduler hints to pass to nova
158     default: {}
159 {% endfor %}
160
161   # Identifiers to trigger tasks on nodes
162   UpdateIdentifier:
163     default: ''
164     type: string
165     description: >
166       Setting to a previously unused value during stack-update will trigger
167       package update on all nodes
168   DeployIdentifier:
169     default: ''
170     type: string
171     description: >
172       Setting this to a unique value will re-run any deployment tasks which
173       perform configuration on a Heat stack-update.
174
175 resources:
176
177   HeatAuthEncryptionKey:
178     type: OS::Heat::RandomString
179
180   PcsdPassword:
181     type: OS::Heat::RandomString
182     properties:
183       length: 16
184
185   HorizonSecret:
186     type: OS::Heat::RandomString
187     properties:
188       length: 10
189
190   ServiceNetMap:
191     type: OS::TripleO::ServiceNetMap
192
193   EndpointMap:
194     type: OS::TripleO::EndpointMap
195     properties:
196       CloudEndpoints:
197         external: {get_param: CloudName}
198         internal_api: {get_param: CloudNameInternal}
199         storage: {get_param: CloudNameStorage}
200         storage_mgmt: {get_param: CloudNameStorageManagement}
201         ctlplane: {get_param: CloudNameCtlplane}
202       NetIpMap: {get_attr: [VipMap, net_ip_map]}
203       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
204
205   # Jinja loop for Role in roles_data.yaml
206 {% for role in roles %}
207   # Resources generated for {{role.name}} Role
208   {{role.name}}ServiceChain:
209     type: OS::TripleO::Services
210     properties:
211       Services:
212         get_param: {{role.name}}Services
213       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
214       EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
215       DefaultPasswords: {get_attr: [DefaultPasswords, passwords]}
216
217   {{role.name}}HostsDeployment:
218     type: OS::Heat::StructuredDeployments
219     properties:
220       name: {{role.name}}HostsDeployment
221       config: {get_attr: [hostsConfig, config_id]}
222       servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
223
224   {{role.name}}AllNodesDeployment:
225     type: OS::Heat::StructuredDeployments
226     depends_on:
227 {% for role_inner in roles %}
228       - {{role_inner.name}}HostsDeployment
229 {% endfor %}
230     properties:
231       name: {{role.name}}AllNodesDeployment
232       config: {get_attr: [allNodesConfig, config_id]}
233       servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
234       input_values:
235         bootstrap_nodeid: {get_attr: [{{role.name}}, resource.0.hostname]}
236         bootstrap_nodeid_ip: {get_attr: [{{role.name}}, resource.0.ip_address]}
237
238   {{role.name}}AllNodesValidationDeployment:
239     type: OS::Heat::StructuredDeployments
240     depends_on: {{role.name}}AllNodesDeployment
241     properties:
242       name: {{role.name}}AllNodesValidationDeployment
243       config: {get_resource: AllNodesValidationConfig}
244       servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
245
246   {{role.name}}IpListMap:
247     type: OS::TripleO::Network::Ports::NetIpListMap
248     properties:
249       ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
250       ExternalIpList: {get_attr: [{{role.name}}, external_ip_address]}
251       InternalApiIpList: {get_attr: [{{role.name}}, internal_api_ip_address]}
252       StorageIpList: {get_attr: [{{role.name}}, storage_ip_address]}
253       StorageMgmtIpList: {get_attr: [{{role.name}}, storage_mgmt_ip_address]}
254       TenantIpList: {get_attr: [{{role.name}}, tenant_ip_address]}
255       ManagementIpList: {get_attr: [{{role.name}}, management_ip_address]}
256       EnabledServices: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
257       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
258       ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
259       NetworkHostnameMap:
260         # Note (shardy) this somewhat complex yaql may be replaced
261         # with a map_deep_merge function in ocata.  It merges the
262         # list of maps, but appends to colliding lists so we can
263         # create a map of lists for all nodes for each network
264         yaql:
265           expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
266           data:
267             - {get_attr: [{{role.name}}, hostname_map]}
268
269   {{role.name}}:
270     type: OS::Heat::ResourceGroup
271     depends_on: Networks
272     properties:
273       count: {get_param: {{role.name}}Count}
274       removal_policies: {get_param: {{role.name}}RemovalPolicies}
275       resource_def:
276         type: OS::TripleO::{{role.name}}
277         properties:
278           CloudDomain: {get_param: CloudDomain}
279           ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
280           EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
281           Hostname:
282             str_replace:
283               template: {get_param: {{role.name}}HostnameFormat}
284               params:
285                 '%stackname%': {get_param: 'OS::stack_name'}
286           NodeIndex: '%index%'
287   {% if role.name != 'Compute' %}
288           {{role.name}}SchedulerHints: {get_param: {{role.name}}SchedulerHints}
289   {% else %}
290           NovaComputeSchedulerHints: {get_param: NovaComputeSchedulerHints}
291   {% endif %}
292           ServiceConfigSettings:
293             map_merge:
294               -  get_attr: [{{role.name}}ServiceChain, role_data, config_settings]
295           {% for r in roles %}
296               - get_attr: [{{r.name}}ServiceChain, role_data, global_config_settings]
297           {% endfor %}
298               # This next step combines two yaql passes:
299               # - The inner one does a deep merge on the service_config_settings for all roles
300               # - The outer one filters the map based on the services enabled for the role
301               #   then merges the result into one map.
302               - yaql:
303                   expression: let(root => $) -> $.data.map.items().where($[0] in $root.data.services).select($[1]).reduce($1.mergeWith($2), {})
304                   data:
305                     map:
306                       yaql:
307                         expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
308                         data:
309                         {% for r in roles %}
310                           - get_attr: [{{r.name}}ServiceChain, role_data, service_config_settings]
311                         {% endfor %}
312                     services: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
313           ServiceNames: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
314           MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChain, role_data, monitoring_subscriptions]}
315 {% endfor %}
316
317   hostsConfig:
318     type: OS::TripleO::Hosts::SoftwareConfig
319     properties:
320       hosts:
321 {% for role in roles %}
322         - list_join:
323             - '\n'
324             - {get_attr: [{{role.name}}, hosts_entry]}
325 {% endfor %}
326
327   allNodesConfig:
328     type: OS::TripleO::AllNodes::SoftwareConfig
329     properties:
330       cloud_name_external: {get_param: CloudName}
331       cloud_name_internal_api: {get_param: CloudNameInternal}
332       cloud_name_storage: {get_param: CloudNameStorage}
333       cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
334       cloud_name_ctlplane: {get_param: CloudNameCtlplane}
335       enabled_services:
336         list_join:
337           - ','
338 {% for role in roles %}
339           - {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
340 {% endfor %}
341       logging_groups:
342         yaql:
343           expression: >
344             $.data.groups.flatten()
345           data:
346             groups:
347 {% for role in roles %}
348               - {get_attr: [{{role.name}}ServiceChain, role_data, logging_groups]}
349 {% endfor %}
350       logging_sources:
351         yaql:
352           expression: >
353             $.data.sources.flatten()
354           data:
355             sources:
356 {% for role in roles %}
357               - {get_attr: [{{role.name}}ServiceChain, role_data, logging_sources]}
358 {% endfor %}
359       controller_ips: {get_attr: [Controller, ip_address]}
360       controller_names: {get_attr: [Controller, hostname]}
361       service_ips:
362         # Note (shardy) this somewhat complex yaql may be replaced
363         # with a map_deep_merge function in ocata.  It merges the
364         # list of maps, but appends to colliding lists when a service
365         # is deployed on more than one role
366         yaql:
367           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
368           data:
369             l:
370 {% for role in roles %}
371               - {get_attr: [{{role.name}}IpListMap, service_ips]}
372 {% endfor %}
373       service_node_names:
374         yaql:
375           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
376           data:
377             l:
378 {% for role in roles %}
379               - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
380 {% endfor %}
381       short_service_node_names:
382         yaql:
383           expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
384           data:
385             l:
386 {% for role in roles %}
387               - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
388 {% endfor %}
389       # FIXME(shardy): These require further work to move into service_ips
390       memcache_node_ips: {get_attr: [ControllerIpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
391       NetVipMap: {get_attr: [VipMap, net_ip_map]}
392       RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
393       ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
394       DeployIdentifier: {get_param: DeployIdentifier}
395       UpdateIdentifier: {get_param: UpdateIdentifier}
396
397   MysqlRootPassword:
398     type: OS::Heat::RandomString
399     properties:
400       length: 10
401
402   RabbitCookie:
403     type: OS::Heat::RandomString
404     properties:
405       length: 20
406       salt: {get_param: RabbitCookieSalt}
407
408   DefaultPasswords:
409     type: OS::TripleO::DefaultPasswords
410     properties:
411       DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
412       DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
413       DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
414       DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
415       DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
416
417   # creates the network architecture
418   Networks:
419     type: OS::TripleO::Network
420
421   ControlVirtualIP:
422     type: OS::Neutron::Port
423     depends_on: Networks
424     properties:
425       name: control_virtual_ip
426       network: {get_param: NeutronControlPlaneID}
427       fixed_ips: {get_param: ControlFixedIPs}
428       replacement_policy: AUTO
429
430   RedisVirtualIP:
431     depends_on: Networks
432     type: OS::TripleO::Network::Ports::RedisVipPort
433     properties:
434       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
435       ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
436       PortName: redis_virtual_ip
437       NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
438       ServiceName: redis
439       FixedIPs: {get_param: RedisVirtualFixedIPs}
440
441   # The public VIP is on the External net, falls back to ctlplane
442   PublicVirtualIP:
443     depends_on: Networks
444     type: OS::TripleO::Network::Ports::ExternalVipPort
445     properties:
446       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
447       ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
448       PortName: public_virtual_ip
449       FixedIPs: {get_param: PublicVirtualFixedIPs}
450
451   InternalApiVirtualIP:
452     depends_on: Networks
453     type: OS::TripleO::Network::Ports::InternalApiVipPort
454     properties:
455       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
456       PortName: internal_api_virtual_ip
457       FixedIPs: {get_param: InternalApiVirtualFixedIPs}
458
459   StorageVirtualIP:
460     depends_on: Networks
461     type: OS::TripleO::Network::Ports::StorageVipPort
462     properties:
463       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
464       PortName: storage_virtual_ip
465       FixedIPs: {get_param: StorageVirtualFixedIPs}
466
467   StorageMgmtVirtualIP:
468     depends_on: Networks
469     type: OS::TripleO::Network::Ports::StorageMgmtVipPort
470     properties:
471       ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
472       PortName: storage_management_virtual_ip
473       FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
474
475   VipMap:
476     type: OS::TripleO::Network::Ports::NetVipMap
477     properties:
478       ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
479       ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
480       ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
481       InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
482       InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
483       StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
484       StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
485       StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
486       StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
487       # No tenant or management VIP required
488
489   # All Nodes Validations
490   AllNodesValidationConfig:
491     type: OS::TripleO::AllNodes::Validation
492     properties:
493       PingTestIps:
494         list_join:
495         - ' '
496         - - {get_attr: [Controller, resource.0.external_ip_address]}
497           - {get_attr: [Controller, resource.0.internal_api_ip_address]}
498           - {get_attr: [Controller, resource.0.storage_ip_address]}
499           - {get_attr: [Controller, resource.0.storage_mgmt_ip_address]}
500           - {get_attr: [Controller, resource.0.tenant_ip_address]}
501           - {get_attr: [Controller, resource.0.management_ip_address]}
502
503   UpdateWorkflow:
504     type: OS::TripleO::Tasks::UpdateWorkflow
505     depends_on:
506 {% for role in roles %}
507       - {{role.name}}AllNodesDeployment
508 {% endfor %}
509     properties:
510       servers:
511 {% for role in roles %}
512         {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
513 {% endfor %}
514       input_values:
515         deploy_identifier: {get_param: DeployIdentifier}
516         update_identifier: {get_param: UpdateIdentifier}
517
518   # Optional ExtraConfig for all nodes - all roles are passed in here, but
519   # the nested template may configure each role differently (or not at all)
520   AllNodesExtraConfig:
521     type: OS::TripleO::AllNodesExtraConfig
522     depends_on:
523       - UpdateWorkflow
524 {% for role in roles %}
525       - {{role.name}}AllNodesValidationDeployment
526 {% endfor %}
527     properties:
528 {% for role in roles %}
529       servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
530 {% endfor %}
531
532   # Post deployment steps for all roles
533   AllNodesDeploySteps:
534     type: OS::TripleO::PostDeploySteps
535 {% for role in roles %}
536     depends_on:
537       - {{role.name}}AllNodesDeployment
538 {% endfor %}
539     properties:
540       servers:
541 {% for role in roles %}
542         {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
543 {% endfor %}
544       role_data:
545 {% for role in roles %}
546         {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
547 {% endfor %}
548
549 outputs:
550   ManagedEndpoints:
551     description: Asserts that the keystone endpoints have been provisioned.
552     value: true
553   KeystoneURL:
554     description: URL for the Overcloud Keystone service
555     value: {get_attr: [EndpointMap, endpoint_map, KeystonePublic, uri]}
556   KeystoneAdminVip:
557     description: Keystone Admin VIP endpoint
558     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
559   PublicVip:
560     description: Controller VIP for public API endpoints
561     value: {get_attr: [VipMap, net_ip_map, external]}
562   AodhInternalVip:
563     description: VIP for Aodh API internal endpoint
564     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, AodhApiNetwork]}]}
565   CeilometerInternalVip:
566     description: VIP for Ceilometer API internal endpoint
567     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, CeilometerApiNetwork]}]}
568   CephRgwInternalVip:
569     description: VIP for Ceph RGW internal endpoint
570     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, CephRgwNetwork]}]}
571   CinderInternalVip:
572     description: VIP for Cinder API internal endpoint
573     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, CinderApiNetwork]}]}
574   GlanceInternalVip:
575     description: VIP for Glance API internal endpoint
576     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, GlanceApiNetwork]}]}
577   GnocchiInternalVip:
578     description: VIP for Gnocchi API internal endpoint
579     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, GnocchiApiNetwork]}]}
580   HeatInternalVip:
581     description: VIP for Heat API internal endpoint
582     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, HeatApiNetwork]}]}
583   IronicInternalVip:
584     description: VIP for Ironic API internal endpoint
585     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, IronicApiNetwork]}]}
586   KeystoneInternalVip:
587     description: VIP for Keystone API internal endpoint
588     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystonePublicApiNetwork]}]}
589   ManilaInternalVip:
590     description: VIP for Manila API internal endpoint
591     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, ManilaApiNetwork]}]}
592   NeutronInternalVip:
593     description: VIP for Neutron API internal endpoint
594     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, NeutronApiNetwork]}]}
595   NovaInternalVip:
596     description: VIP for Nova API internal endpoint
597     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, NovaApiNetwork]}]}
598   OpenDaylightInternalVip:
599     description: VIP for OpenDaylight API internal endpoint
600     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, OpenDaylightApiNetwork]}]}
601   SaharaInternalVip:
602     description: VIP for Sahara API internal endpoint
603     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, SaharaApiNetwork]}]}
604   SwiftInternalVip:
605     description: VIP for Swift Proxy internal endpoint
606     value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, SwiftProxyNetwork]}]}
607   EndpointMap:
608     description: |
609       Mapping of the resources with the needed info for their endpoints.
610       This includes the protocol used, the IP, port and also a full
611       representation of the URI.
612     value: {get_attr: [EndpointMap, endpoint_map]}
613   HostsEntry:
614     description: |
615       The content that should be appended to your /etc/hosts if you want to get
616       hostname-based access to the deployed nodes (useful for testing without
617       setting up a DNS).
618     value:
619       list_join:
620       - "\n"
621       - - {get_attr: [hostsConfig, hosts_entries]}
622       -
623         - str_replace:
624             template: IP  HOST
625             params:
626               IP: {get_attr: [VipMap, net_ip_map, external]}
627               HOST: {get_param: CloudName}
628         - str_replace:
629             template: IP  HOST
630             params:
631               IP: {get_attr: [VipMap, net_ip_map, ctlplane]}
632               HOST: {get_param: CloudNameCtlplane}
633         - str_replace:
634             template: IP  HOST
635             params:
636               IP: {get_attr: [VipMap, net_ip_map, internal_api]}
637               HOST: {get_param: CloudNameInternal}
638         - str_replace:
639             template: IP  HOST
640             params:
641               IP: {get_attr: [VipMap, net_ip_map, storage]}
642               HOST: {get_param: CloudNameStorage}
643         - str_replace:
644             template: IP  HOST
645             params:
646               IP: {get_attr: [VipMap, net_ip_map, storage_mgmt]}
647               HOST: {get_param: CloudNameStorageManagement}
648   EnabledServices:
649     description: The services enabled on each role
650     value:
651 {% for role in roles %}
652       {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
653 {% endfor %}