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.
117 # Jinja loop for Role in role_data.yaml
118 {% for role in roles %}
119 # Parameters generated for {{role.name}} Role
120 {{role.name}}Services:
121 description: A list of service resources (configured in the Heat
122 resource_registry) which represent nested stacks
123 for each service that should get installed on the {{role.name}} role.
124 type: comma_delimited_list
127 description: Number of {{role.name}} nodes to deploy
129 default: {{role.CountDefault|default(0)}}
131 {{role.name}}HostnameFormat:
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}}"
140 default: "%stackname%-{{role.name.lower()}}-%index%"
143 {{role.name}}RemovalPolicies:
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']}]
151 {% if role.name != 'Compute' %}
152 {{role.name}}SchedulerHints:
154 NovaComputeSchedulerHints:
157 description: Optional scheduler hints to pass to nova
161 # Identifiers to trigger tasks on nodes
166 Setting to a previously unused value during stack-update will trigger
167 package update on all nodes
172 Setting this to a unique value will re-run any deployment tasks which
173 perform configuration on a Heat stack-update.
178 Set to true to append per network Vips to /etc/hosts on each node.
181 add_vips_to_etc_hosts: {equals : [{get_param: AddVipsToEtcHosts}, True]}
186 type: OS::Heat::Value
195 IP: {get_attr: [VipMap, net_ip_map, external]}
196 HOST: {get_param: CloudName}
200 IP: {get_attr: [VipMap, net_ip_map, ctlplane]}
201 HOST: {get_param: CloudNameCtlplane}
205 IP: {get_attr: [VipMap, net_ip_map, internal_api]}
206 HOST: {get_param: CloudNameInternal}
210 IP: {get_attr: [VipMap, net_ip_map, storage]}
211 HOST: {get_param: CloudNameStorage}
215 IP: {get_attr: [VipMap, net_ip_map, storage_mgmt]}
216 HOST: {get_param: CloudNameStorageManagement}
218 HeatAuthEncryptionKey:
219 type: OS::Heat::RandomString
222 type: OS::Heat::RandomString
227 type: OS::Heat::RandomString
232 type: OS::TripleO::ServiceNetMap
235 type: OS::TripleO::EndpointMap
238 external: {get_param: CloudName}
239 internal_api: {get_param: CloudNameInternal}
240 storage: {get_param: CloudNameStorage}
241 storage_mgmt: {get_param: CloudNameStorageManagement}
242 ctlplane: {get_param: CloudNameCtlplane}
243 NetIpMap: {get_attr: [VipMap, net_ip_map]}
244 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
247 type: OS::Heat::Value
250 value: {get_attr: [EndpointMap, endpoint_map]}
253 type: OS::TripleO::Ssh::KnownHostsConfig
258 {% for role in roles %}
259 - {get_attr: [{{role.name}}, known_hosts_entry]}
262 # Jinja loop for Role in roles_data.yaml
263 {% for role in roles %}
264 # Resources generated for {{role.name}} Role
265 {{role.name}}ServiceChain:
266 type: OS::TripleO::Services
269 get_param: {{role.name}}Services
270 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
271 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
272 DefaultPasswords: {get_attr: [DefaultPasswords, passwords]}
274 # Filter any null/None service_names which may be present due to mapping
275 # of services to OS::Heat::None
276 {{role.name}}ServiceNames:
277 type: OS::Heat::Value
278 depends_on: {{role.name}}ServiceChain
280 type: comma_delimited_list
283 expression: coalesce($.data, []).where($ != null)
284 data: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
286 {{role.name}}HostsDeployment:
287 type: OS::Heat::StructuredDeployments
289 name: {{role.name}}HostsDeployment
290 config: {get_attr: [hostsConfig, config_id]}
291 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
293 {{role.name}}SshKnownHostsDeployment:
294 type: OS::Heat::StructuredDeployments
296 name: {{role.name}}SshKnownHostsDeployment
297 config: {get_resource: SshKnownHostsConfig}
298 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
300 {{role.name}}AllNodesDeployment:
301 type: OS::Heat::StructuredDeployments
303 {% for role_inner in roles %}
304 - {{role_inner.name}}HostsDeployment
307 name: {{role.name}}AllNodesDeployment
308 config: {get_attr: [allNodesConfig, config_id]}
309 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
311 # Note we have to use yaql to look up the first hostname/ip in the
312 # list because heat path based attributes operate on the attribute
313 # inside the ResourceGroup, not the exposed list ref discussion in
314 # https://bugs.launchpad.net/heat/+bug/1640488
315 # The coalesce is needed because $.data is None during heat validation
318 expression: coalesce($.data, []).first(null)
319 data: {get_attr: [{{role.name}}, hostname]}
322 expression: coalesce($.data, []).first(null)
323 data: {get_attr: [{{role.name}}, ip_address]}
325 {{role.name}}AllNodesValidationDeployment:
326 type: OS::Heat::StructuredDeployments
327 depends_on: {{role.name}}AllNodesDeployment
329 name: {{role.name}}AllNodesValidationDeployment
330 config: {get_resource: AllNodesValidationConfig}
331 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
333 {{role.name}}IpListMap:
334 type: OS::TripleO::Network::Ports::NetIpListMap
336 ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
337 ExternalIpList: {get_attr: [{{role.name}}, external_ip_address]}
338 InternalApiIpList: {get_attr: [{{role.name}}, internal_api_ip_address]}
339 StorageIpList: {get_attr: [{{role.name}}, storage_ip_address]}
340 StorageMgmtIpList: {get_attr: [{{role.name}}, storage_mgmt_ip_address]}
341 TenantIpList: {get_attr: [{{role.name}}, tenant_ip_address]}
342 ManagementIpList: {get_attr: [{{role.name}}, management_ip_address]}
343 EnabledServices: {get_attr: [{{role.name}}ServiceNames, value]}
344 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
345 ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
347 # Note (shardy) this somewhat complex yaql may be replaced
348 # with a map_deep_merge function in ocata. It merges the
349 # list of maps, but appends to colliding lists so we can
350 # create a map of lists for all nodes for each network
352 expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
354 - {get_attr: [{{role.name}}, hostname_map]}
357 type: OS::Heat::ResourceGroup
360 count: {get_param: {{role.name}}Count}
361 removal_policies: {get_param: {{role.name}}RemovalPolicies}
363 type: OS::TripleO::{{role.name}}
365 CloudDomain: {get_param: CloudDomain}
366 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
367 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
370 template: {get_param: {{role.name}}HostnameFormat}
372 '%stackname%': {get_param: 'OS::stack_name'}
374 {% if role.name != 'Compute' %}
375 {{role.name}}SchedulerHints: {get_param: {{role.name}}SchedulerHints}
377 NovaComputeSchedulerHints: {get_param: NovaComputeSchedulerHints}
379 ServiceConfigSettings:
381 - get_attr: [{{role.name}}ServiceChain, role_data, config_settings]
383 - get_attr: [{{r.name}}ServiceChain, role_data, global_config_settings]
385 # This next step combines two yaql passes:
386 # - The inner one does a deep merge on the service_config_settings for all roles
387 # - The outer one filters the map based on the services enabled for the role
388 # then merges the result into one map.
390 expression: let(root => $) -> $.data.map.items().where($[0] in coalesce($root.data.services, [])).select($[1]).reduce($1.mergeWith($2), {})
394 expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
397 - get_attr: [{{r.name}}ServiceChain, role_data, service_config_settings]
399 services: {get_attr: [{{role.name}}ServiceNames, value]}
400 ServiceNames: {get_attr: [{{role.name}}ServiceNames, value]}
401 MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChain, role_data, monitoring_subscriptions]}
402 ServiceMetadataSettings: {get_attr: [{{role.name}}ServiceChain, role_data, service_metadata_settings]}
406 type: OS::TripleO::Hosts::SoftwareConfig
412 - add_vips_to_etc_hosts
413 - {get_attr: [VipHosts, value]}
416 {% for role in roles %}
419 - {get_attr: [{{role.name}}, hosts_entry]}
423 type: OS::TripleO::AllNodes::SoftwareConfig
425 cloud_name_external: {get_param: CloudName}
426 cloud_name_internal_api: {get_param: CloudNameInternal}
427 cloud_name_storage: {get_param: CloudNameStorage}
428 cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
429 cloud_name_ctlplane: {get_param: CloudNameCtlplane}
433 {% for role in roles %}
434 - {get_attr: [{{role.name}}ServiceNames, value]}
439 $.data.groups.flatten()
442 {% for role in roles %}
443 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_groups]}
448 $.data.sources.flatten()
451 {% for role in roles %}
452 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_sources]}
454 controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
455 controller_names: {get_attr: [{{primary_role_name}}, hostname]}
457 # Note (shardy) this somewhat complex yaql may be replaced
458 # with a map_deep_merge function in ocata. It merges the
459 # list of maps, but appends to colliding lists when a service
460 # is deployed on more than one role
462 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
465 {% for role in roles %}
466 - {get_attr: [{{role.name}}IpListMap, service_ips]}
470 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
473 {% for role in roles %}
474 - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
476 short_service_node_names:
478 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
481 {% for role in roles %}
482 - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
484 short_service_bootstrap_node:
486 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
489 {% for role in roles %}
490 - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
492 # FIXME(shardy): These require further work to move into service_ips
493 memcache_node_ips: {get_attr: [{{primary_role_name}}IpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
494 NetVipMap: {get_attr: [VipMap, net_ip_map]}
495 RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
496 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
497 DeployIdentifier: {get_param: DeployIdentifier}
498 UpdateIdentifier: {get_param: UpdateIdentifier}
501 type: OS::Heat::RandomString
506 type: OS::Heat::RandomString
509 salt: {get_param: RabbitCookieSalt}
512 type: OS::TripleO::DefaultPasswords
514 DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
515 DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
516 DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
517 DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
518 DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
520 # creates the network architecture
522 type: OS::TripleO::Network
525 type: OS::TripleO::Network::Ports::ControlPlaneVipPort
528 name: control_virtual_ip
529 network: {get_param: NeutronControlPlaneID}
530 fixed_ips: {get_param: ControlFixedIPs}
531 replacement_policy: AUTO
535 type: OS::TripleO::Network::Ports::RedisVipPort
537 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
538 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
539 PortName: redis_virtual_ip
540 NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
542 FixedIPs: {get_param: RedisVirtualFixedIPs}
544 # The public VIP is on the External net, falls back to ctlplane
547 type: OS::TripleO::Network::Ports::ExternalVipPort
549 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
550 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
551 PortName: public_virtual_ip
552 FixedIPs: {get_param: PublicVirtualFixedIPs}
554 InternalApiVirtualIP:
556 type: OS::TripleO::Network::Ports::InternalApiVipPort
558 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
559 PortName: internal_api_virtual_ip
560 FixedIPs: {get_param: InternalApiVirtualFixedIPs}
564 type: OS::TripleO::Network::Ports::StorageVipPort
566 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
567 PortName: storage_virtual_ip
568 FixedIPs: {get_param: StorageVirtualFixedIPs}
570 StorageMgmtVirtualIP:
572 type: OS::TripleO::Network::Ports::StorageMgmtVipPort
574 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
575 PortName: storage_management_virtual_ip
576 FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
579 type: OS::TripleO::Network::Ports::NetVipMap
581 ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
582 ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
583 ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
584 InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
585 InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
586 StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
587 StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
588 StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
589 StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
590 # No tenant or management VIP required
592 # All Nodes Validations
593 AllNodesValidationConfig:
594 type: OS::TripleO::AllNodes::Validation
599 - - {get_attr: [{{primary_role_name}}, resource.0.external_ip_address]}
600 - {get_attr: [{{primary_role_name}}, resource.0.internal_api_ip_address]}
601 - {get_attr: [{{primary_role_name}}, resource.0.storage_ip_address]}
602 - {get_attr: [{{primary_role_name}}, resource.0.storage_mgmt_ip_address]}
603 - {get_attr: [{{primary_role_name}}, resource.0.tenant_ip_address]}
604 - {get_attr: [{{primary_role_name}}, resource.0.management_ip_address]}
607 type: OS::TripleO::Tasks::UpdateWorkflow
609 {% for role in roles %}
610 - {{role.name}}AllNodesDeployment
614 {% for role in roles %}
615 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
618 deploy_identifier: {get_param: DeployIdentifier}
619 update_identifier: {get_param: UpdateIdentifier}
621 # Optional ExtraConfig for all nodes - all roles are passed in here, but
622 # the nested template may configure each role differently (or not at all)
624 type: OS::TripleO::AllNodesExtraConfig
627 {% for role in roles %}
628 - {{role.name}}AllNodesValidationDeployment
632 {% for role in roles %}
633 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
636 # Post deployment steps for all roles
638 type: OS::TripleO::PostDeploySteps
640 {% for role in roles %}
641 - {{role.name}}AllNodesDeployment
645 {% for role in roles %}
646 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
648 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
650 {% for role in roles %}
651 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
656 description: Asserts that the keystone endpoints have been provisioned.
659 description: URL for the Overcloud Keystone service
660 value: {get_attr: [EndpointMapData, value, KeystonePublic, uri]}
662 description: Keystone Admin VIP endpoint
663 value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
666 Mapping of the resources with the needed info for their endpoints.
667 This includes the protocol used, the IP, port and also a full
668 representation of the URI.
669 value: {get_attr: [EndpointMapData, value]}
672 The content that should be appended to your /etc/hosts if you want to get
673 hostname-based access to the deployed nodes (useful for testing without
678 - - {get_attr: [hostsConfig, hosts_entries]}
679 - - {get_attr: [VipHosts, value]}
681 description: The services enabled on each role
683 {% for role in roles %}
684 {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
687 description: The configuration data associated with each role
689 {% for role in roles %}
690 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}