1 {% set primary_role_name = roles[0].name -%}
2 heat_template_version: ocata
5 Deploy an OpenStack environment, consisting of several node types (roles),
6 Controller, Compute, BlockStorage, SwiftStorage and CephStorage. The Storage
7 roles enable independent scaling of the storage components, but the minimal
8 deployment is one Controller and one Compute node.
11 # TODO(shadower): we should probably use the parameter groups to put
15 # Common parameters (not specific to a role)
17 default: overcloud.localdomain
18 description: The DNS name of this cloud. E.g. ci-overcloud.tripleo.org
21 default: overcloud.internalapi.localdomain
23 The DNS name of this cloud's internal API endpoint. E.g.
24 'ci-overcloud.internalapi.tripleo.org'.
27 default: overcloud.storage.localdomain
29 The DNS name of this cloud's storage endpoint. E.g.
30 'ci-overcloud.storage.tripleo.org'.
32 CloudNameStorageManagement:
33 default: overcloud.storagemgmt.localdomain
35 The DNS name of this cloud's storage management endpoint. E.g.
36 'ci-overcloud.storagemgmt.tripleo.org'.
39 default: overcloud.ctlplane.localdomain
41 The DNS name of this cloud's storage management endpoint. E.g.
42 'ci-overcloud.management.tripleo.org'.
46 description: Should be used for arbitrary ips.
48 InternalApiVirtualFixedIPs:
51 Control the IP allocation for the InternalApiVirtualInterface port. E.g.
52 [{'ip_address':'1.2.3.4'}]
54 NeutronControlPlaneID:
57 description: Neutron ID or name for ctlplane network.
58 NeutronPublicInterface:
60 description: What interface to bridge onto br-ex for network nodes.
62 PublicVirtualFixedIPs:
65 Control the IP allocation for the PublicVirtualInterface port. E.g.
66 [{'ip_address':'1.2.3.4'}]
71 description: Salt for the rabbit cookie, change this to force the randomly generated rabbit cookie to change.
72 StorageVirtualFixedIPs:
75 Control the IP allocation for the StorageVirtualInterface port. E.g.
76 [{'ip_address':'1.2.3.4'}]
78 StorageMgmtVirtualFixedIPs:
81 Control the IP allocation for the StorageMgmgVirtualInterface port. E.g.
82 [{'ip_address':'1.2.3.4'}]
87 Control the IP allocation for the virtual IP used by Redis. E.g.
88 [{'ip_address':'1.2.3.4'}]
91 default: 'localdomain'
94 The DNS domain used for the hosts. This should match the dhcp_domain
95 configured in the Undercloud neutron. Defaults to localdomain.
99 Extra properties or metadata passed to Nova for the created nodes in
100 the overcloud. It's accessible via the Nova metadata API.
103 # Compute-specific params
104 # FIXME(shardy) handle these deprecated names as they don't match compute.yaml
105 HypervisorNeutronPhysicalBridge:
108 An OVS bridge to create on each hypervisor. This defaults to br-ex the
109 same as the control plane nodes, as we have a uniform configuration of
110 the openvswitch agent. Typically should not need to be changed.
112 HypervisorNeutronPublicInterface:
114 description: What interface to add to the HypervisorNeutronPhysicalBridge.
119 description: Maxiumum batch size for creating nodes
122 # Jinja loop for Role in role_data.yaml
123 {% for role in roles %}
124 # Parameters generated for {{role.name}} Role
125 {{role.name}}Services:
126 description: A list of service resources (configured in the Heat
127 resource_registry) which represent nested stacks
128 for each service that should get installed on the {{role.name}} role.
129 type: comma_delimited_list
132 description: Number of {{role.name}} nodes to deploy
134 default: {{role.CountDefault|default(0)}}
136 {{role.name}}HostnameFormat:
139 Format for {{role.name}} node hostnames
140 Note %index% is translated into the index of the node, e.g 0/1/2 etc
141 and %stackname% is replaced with the stack name e.g overcloud
142 {% if role.HostnameFormatDefault %}
143 default: "{{role.HostnameFormatDefault}}"
145 default: "%stackname%-{{role.name.lower()}}-%index%"
148 {{role.name}}RemovalPolicies:
152 List of resources to be removed from {{role.name}} ResourceGroup when
153 doing an update which requires removal of specific resources.
154 Example format ComputeRemovalPolicies: [{'resource_list': ['0']}]
156 {% if role.name != 'Compute' %}
157 {{role.name}}SchedulerHints:
159 NovaComputeSchedulerHints:
162 description: Optional scheduler hints to pass to nova
166 # Identifiers to trigger tasks on nodes
171 Setting to a previously unused value during stack-update will trigger
172 package update on all nodes
177 Setting this to a unique value will re-run any deployment tasks which
178 perform configuration on a Heat stack-update.
183 Set to true to append per network Vips to /etc/hosts on each node.
186 add_vips_to_etc_hosts: {equals : [{get_param: AddVipsToEtcHosts}, True]}
191 type: OS::Heat::Value
200 IP: {get_attr: [VipMap, net_ip_map, external]}
201 HOST: {get_param: CloudName}
205 IP: {get_attr: [VipMap, net_ip_map, ctlplane]}
206 HOST: {get_param: CloudNameCtlplane}
210 IP: {get_attr: [VipMap, net_ip_map, internal_api]}
211 HOST: {get_param: CloudNameInternal}
215 IP: {get_attr: [VipMap, net_ip_map, storage]}
216 HOST: {get_param: CloudNameStorage}
220 IP: {get_attr: [VipMap, net_ip_map, storage_mgmt]}
221 HOST: {get_param: CloudNameStorageManagement}
223 HeatAuthEncryptionKey:
224 type: OS::Heat::RandomString
227 type: OS::Heat::RandomString
232 type: OS::Heat::RandomString
237 type: OS::TripleO::ServiceNetMap
240 type: OS::TripleO::EndpointMap
243 external: {get_param: CloudName}
244 internal_api: {get_param: CloudNameInternal}
245 storage: {get_param: CloudNameStorage}
246 storage_mgmt: {get_param: CloudNameStorageManagement}
247 ctlplane: {get_param: CloudNameCtlplane}
248 NetIpMap: {get_attr: [VipMap, net_ip_map]}
249 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
252 type: OS::Heat::Value
255 value: {get_attr: [EndpointMap, endpoint_map]}
257 # Jinja loop for Role in roles_data.yaml
258 {% for role in roles %}
259 # Resources generated for {{role.name}} Role
260 {{role.name}}ServiceChain:
261 type: OS::TripleO::Services
264 get_param: {{role.name}}Services
265 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
266 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
267 DefaultPasswords: {get_attr: [DefaultPasswords, passwords]}
269 # Filter any null/None service_names which may be present due to mapping
270 # of services to OS::Heat::None
271 {{role.name}}ServiceNames:
272 type: OS::Heat::Value
273 depends_on: {{role.name}}ServiceChain
275 type: comma_delimited_list
278 expression: coalesce($.data, []).where($ != null)
279 data: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
281 {{role.name}}HostsDeployment:
282 type: OS::Heat::StructuredDeployments
284 name: {{role.name}}HostsDeployment
285 config: {get_attr: [hostsConfig, config_id]}
286 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
288 {{role.name}}AllNodesDeployment:
289 type: OS::Heat::StructuredDeployments
291 {% for role_inner in roles %}
292 - {{role_inner.name}}HostsDeployment
295 name: {{role.name}}AllNodesDeployment
296 config: {get_attr: [allNodesConfig, config_id]}
297 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
299 # Note we have to use yaql to look up the first hostname/ip in the
300 # list because heat path based attributes operate on the attribute
301 # inside the ResourceGroup, not the exposed list ref discussion in
302 # https://bugs.launchpad.net/heat/+bug/1640488
303 # The coalesce is needed because $.data is None during heat validation
306 expression: coalesce($.data, []).first(null)
307 data: {get_attr: [{{role.name}}, hostname]}
310 expression: coalesce($.data, []).first(null)
311 data: {get_attr: [{{role.name}}, ip_address]}
313 {{role.name}}AllNodesValidationDeployment:
314 type: OS::Heat::StructuredDeployments
315 depends_on: {{role.name}}AllNodesDeployment
317 name: {{role.name}}AllNodesValidationDeployment
318 config: {get_resource: AllNodesValidationConfig}
319 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
321 {{role.name}}IpListMap:
322 type: OS::TripleO::Network::Ports::NetIpListMap
324 ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
325 ExternalIpList: {get_attr: [{{role.name}}, external_ip_address]}
326 InternalApiIpList: {get_attr: [{{role.name}}, internal_api_ip_address]}
327 StorageIpList: {get_attr: [{{role.name}}, storage_ip_address]}
328 StorageMgmtIpList: {get_attr: [{{role.name}}, storage_mgmt_ip_address]}
329 TenantIpList: {get_attr: [{{role.name}}, tenant_ip_address]}
330 ManagementIpList: {get_attr: [{{role.name}}, management_ip_address]}
331 EnabledServices: {get_attr: [{{role.name}}ServiceNames, value]}
332 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
333 ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
335 # Note (shardy) this somewhat complex yaql may be replaced
336 # with a map_deep_merge function in ocata. It merges the
337 # list of maps, but appends to colliding lists so we can
338 # create a map of lists for all nodes for each network
340 expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
342 - {get_attr: [{{role.name}}, hostname_map]}
345 type: OS::Heat::ResourceGroup
349 max_batch_size: {get_param: NodeCreateBatchSize}
351 count: {get_param: {{role.name}}Count}
352 removal_policies: {get_param: {{role.name}}RemovalPolicies}
354 type: OS::TripleO::{{role.name}}
356 CloudDomain: {get_param: CloudDomain}
357 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
358 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
361 template: {get_param: {{role.name}}HostnameFormat}
363 '%stackname%': {get_param: 'OS::stack_name'}
365 {% if role.name != 'Compute' %}
366 {{role.name}}SchedulerHints: {get_param: {{role.name}}SchedulerHints}
368 NovaComputeSchedulerHints: {get_param: NovaComputeSchedulerHints}
370 ServiceConfigSettings:
372 - get_attr: [{{role.name}}ServiceChain, role_data, config_settings]
374 - get_attr: [{{r.name}}ServiceChain, role_data, global_config_settings]
376 # This next step combines two yaql passes:
377 # - The inner one does a deep merge on the service_config_settings for all roles
378 # - The outer one filters the map based on the services enabled for the role
379 # then merges the result into one map.
381 expression: let(root => $) -> $.data.map.items().where($[0] in coalesce($root.data.services, [])).select($[1]).reduce($1.mergeWith($2), {})
385 expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
388 - get_attr: [{{r.name}}ServiceChain, role_data, service_config_settings]
390 services: {get_attr: [{{role.name}}ServiceNames, value]}
391 ServiceNames: {get_attr: [{{role.name}}ServiceNames, value]}
392 MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChain, role_data, monitoring_subscriptions]}
393 ServiceMetadataSettings: {get_attr: [{{role.name}}ServiceChain, role_data, service_metadata_settings]}
397 type: OS::TripleO::Hosts::SoftwareConfig
403 - add_vips_to_etc_hosts
404 - {get_attr: [VipHosts, value]}
407 {% for role in roles %}
410 - {get_attr: [{{role.name}}, hosts_entry]}
414 type: OS::TripleO::AllNodes::SoftwareConfig
416 cloud_name_external: {get_param: CloudName}
417 cloud_name_internal_api: {get_param: CloudNameInternal}
418 cloud_name_storage: {get_param: CloudNameStorage}
419 cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
420 cloud_name_ctlplane: {get_param: CloudNameCtlplane}
424 {% for role in roles %}
425 - {get_attr: [{{role.name}}ServiceNames, value]}
430 $.data.groups.flatten()
433 {% for role in roles %}
434 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_groups]}
439 $.data.sources.flatten()
442 {% for role in roles %}
443 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_sources]}
445 controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
446 controller_names: {get_attr: [{{primary_role_name}}, hostname]}
448 # Note (shardy) this somewhat complex yaql may be replaced
449 # with a map_deep_merge function in ocata. It merges the
450 # list of maps, but appends to colliding lists when a service
451 # is deployed on more than one role
453 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
456 {% for role in roles %}
457 - {get_attr: [{{role.name}}IpListMap, service_ips]}
461 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
464 {% for role in roles %}
465 - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
467 short_service_node_names:
469 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
472 {% for role in roles %}
473 - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
475 short_service_bootstrap_node:
477 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
480 {% for role in roles %}
481 - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
483 # FIXME(shardy): These require further work to move into service_ips
484 memcache_node_ips: {get_attr: [{{primary_role_name}}IpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
485 NetVipMap: {get_attr: [VipMap, net_ip_map]}
486 RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
487 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
488 DeployIdentifier: {get_param: DeployIdentifier}
489 UpdateIdentifier: {get_param: UpdateIdentifier}
492 type: OS::Heat::RandomString
497 type: OS::Heat::RandomString
500 salt: {get_param: RabbitCookieSalt}
503 type: OS::TripleO::DefaultPasswords
505 DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
506 DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
507 DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
508 DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
509 DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
511 # creates the network architecture
513 type: OS::TripleO::Network
516 type: OS::TripleO::Network::Ports::ControlPlaneVipPort
519 name: control_virtual_ip
520 network: {get_param: NeutronControlPlaneID}
521 fixed_ips: {get_param: ControlFixedIPs}
522 replacement_policy: AUTO
526 type: OS::TripleO::Network::Ports::RedisVipPort
528 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
529 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
530 PortName: redis_virtual_ip
531 NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
533 FixedIPs: {get_param: RedisVirtualFixedIPs}
535 # The public VIP is on the External net, falls back to ctlplane
538 type: OS::TripleO::Network::Ports::ExternalVipPort
540 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
541 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
542 PortName: public_virtual_ip
543 FixedIPs: {get_param: PublicVirtualFixedIPs}
545 InternalApiVirtualIP:
547 type: OS::TripleO::Network::Ports::InternalApiVipPort
549 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
550 PortName: internal_api_virtual_ip
551 FixedIPs: {get_param: InternalApiVirtualFixedIPs}
555 type: OS::TripleO::Network::Ports::StorageVipPort
557 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
558 PortName: storage_virtual_ip
559 FixedIPs: {get_param: StorageVirtualFixedIPs}
561 StorageMgmtVirtualIP:
563 type: OS::TripleO::Network::Ports::StorageMgmtVipPort
565 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
566 PortName: storage_management_virtual_ip
567 FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
570 type: OS::TripleO::Network::Ports::NetVipMap
572 ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
573 ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
574 ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
575 InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
576 InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
577 StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
578 StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
579 StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
580 StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
581 # No tenant or management VIP required
583 # All Nodes Validations
584 AllNodesValidationConfig:
585 type: OS::TripleO::AllNodes::Validation
590 - - {get_attr: [{{primary_role_name}}, resource.0.external_ip_address]}
591 - {get_attr: [{{primary_role_name}}, resource.0.internal_api_ip_address]}
592 - {get_attr: [{{primary_role_name}}, resource.0.storage_ip_address]}
593 - {get_attr: [{{primary_role_name}}, resource.0.storage_mgmt_ip_address]}
594 - {get_attr: [{{primary_role_name}}, resource.0.tenant_ip_address]}
595 - {get_attr: [{{primary_role_name}}, resource.0.management_ip_address]}
598 type: OS::TripleO::Tasks::UpdateWorkflow
600 {% for role in roles %}
601 - {{role.name}}AllNodesDeployment
605 {% for role in roles %}
606 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
609 deploy_identifier: {get_param: DeployIdentifier}
610 update_identifier: {get_param: UpdateIdentifier}
612 # Optional ExtraConfig for all nodes - all roles are passed in here, but
613 # the nested template may configure each role differently (or not at all)
615 type: OS::TripleO::AllNodesExtraConfig
618 {% for role in roles %}
619 - {{role.name}}AllNodesValidationDeployment
623 {% for role in roles %}
624 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
627 # Post deployment steps for all roles
629 type: OS::TripleO::PostDeploySteps
631 {% for role in roles %}
632 - {{role.name}}AllNodesDeployment
636 {% for role in roles %}
637 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
639 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
641 {% for role in roles %}
642 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
647 description: Asserts that the keystone endpoints have been provisioned.
650 description: URL for the Overcloud Keystone service
651 value: {get_attr: [EndpointMapData, value, KeystonePublic, uri]}
653 description: Keystone Admin VIP endpoint
654 value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
657 Mapping of the resources with the needed info for their endpoints.
658 This includes the protocol used, the IP, port and also a full
659 representation of the URI.
660 value: {get_attr: [EndpointMapData, value]}
663 The content that should be appended to your /etc/hosts if you want to get
664 hostname-based access to the deployed nodes (useful for testing without
669 - - {get_attr: [hostsConfig, hosts_entries]}
670 - - {get_attr: [VipHosts, value]}
672 description: The services enabled on each role
674 {% for role in roles %}
675 {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
678 description: The configuration data associated with each role
680 {% for role in roles %}
681 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}