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]}
246 # Jinja loop for Role in roles_data.yaml
247 {% for role in roles %}
248 # Resources generated for {{role.name}} Role
249 {{role.name}}ServiceChain:
250 type: OS::TripleO::Services
253 get_param: {{role.name}}Services
254 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
255 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
256 DefaultPasswords: {get_attr: [DefaultPasswords, passwords]}
258 # Filter any null/None service_names which may be present due to mapping
259 # of services to OS::Heat::None
260 {{role.name}}ServiceNames:
261 type: OS::Heat::Value
262 depends_on: {{role.name}}ServiceChain
264 type: comma_delimited_list
267 expression: coalesce($.data, []).where($ != null)
268 data: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
270 {{role.name}}HostsDeployment:
271 type: OS::Heat::StructuredDeployments
273 name: {{role.name}}HostsDeployment
274 config: {get_attr: [hostsConfig, config_id]}
275 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
277 {{role.name}}AllNodesDeployment:
278 type: OS::Heat::StructuredDeployments
280 {% for role_inner in roles %}
281 - {{role_inner.name}}HostsDeployment
284 name: {{role.name}}AllNodesDeployment
285 config: {get_attr: [allNodesConfig, config_id]}
286 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
288 # Note we have to use yaql to look up the first hostname/ip in the
289 # list because heat path based attributes operate on the attribute
290 # inside the ResourceGroup, not the exposed list ref discussion in
291 # https://bugs.launchpad.net/heat/+bug/1640488
292 # The coalesce is needed because $.data is None during heat validation
295 expression: coalesce($.data, []).first(null)
296 data: {get_attr: [{{role.name}}, hostname]}
299 expression: coalesce($.data, []).first(null)
300 data: {get_attr: [{{role.name}}, ip_address]}
302 {{role.name}}AllNodesValidationDeployment:
303 type: OS::Heat::StructuredDeployments
304 depends_on: {{role.name}}AllNodesDeployment
306 name: {{role.name}}AllNodesValidationDeployment
307 config: {get_resource: AllNodesValidationConfig}
308 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
310 {{role.name}}IpListMap:
311 type: OS::TripleO::Network::Ports::NetIpListMap
313 ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
314 ExternalIpList: {get_attr: [{{role.name}}, external_ip_address]}
315 InternalApiIpList: {get_attr: [{{role.name}}, internal_api_ip_address]}
316 StorageIpList: {get_attr: [{{role.name}}, storage_ip_address]}
317 StorageMgmtIpList: {get_attr: [{{role.name}}, storage_mgmt_ip_address]}
318 TenantIpList: {get_attr: [{{role.name}}, tenant_ip_address]}
319 ManagementIpList: {get_attr: [{{role.name}}, management_ip_address]}
320 EnabledServices: {get_attr: [{{role.name}}ServiceNames, value]}
321 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
322 ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
324 # Note (shardy) this somewhat complex yaql may be replaced
325 # with a map_deep_merge function in ocata. It merges the
326 # list of maps, but appends to colliding lists so we can
327 # create a map of lists for all nodes for each network
329 expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
331 - {get_attr: [{{role.name}}, hostname_map]}
334 type: OS::Heat::ResourceGroup
337 count: {get_param: {{role.name}}Count}
338 removal_policies: {get_param: {{role.name}}RemovalPolicies}
340 type: OS::TripleO::{{role.name}}
342 CloudDomain: {get_param: CloudDomain}
343 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
344 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
347 template: {get_param: {{role.name}}HostnameFormat}
349 '%stackname%': {get_param: 'OS::stack_name'}
351 {% if role.name != 'Compute' %}
352 {{role.name}}SchedulerHints: {get_param: {{role.name}}SchedulerHints}
354 NovaComputeSchedulerHints: {get_param: NovaComputeSchedulerHints}
356 ServiceConfigSettings:
358 - get_attr: [{{role.name}}ServiceChain, role_data, config_settings]
360 - get_attr: [{{r.name}}ServiceChain, role_data, global_config_settings]
362 # This next step combines two yaql passes:
363 # - The inner one does a deep merge on the service_config_settings for all roles
364 # - The outer one filters the map based on the services enabled for the role
365 # then merges the result into one map.
367 expression: let(root => $) -> $.data.map.items().where($[0] in coalesce($root.data.services, [])).select($[1]).reduce($1.mergeWith($2), {})
371 expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
374 - get_attr: [{{r.name}}ServiceChain, role_data, service_config_settings]
376 services: {get_attr: [{{role.name}}ServiceNames, value]}
377 ServiceNames: {get_attr: [{{role.name}}ServiceNames, value]}
378 MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChain, role_data, monitoring_subscriptions]}
379 ServiceMetadataSettings: {get_attr: [{{role.name}}ServiceChain, role_data, service_metadata_settings]}
383 type: OS::TripleO::Hosts::SoftwareConfig
389 - add_vips_to_etc_hosts
390 - {get_attr: [VipHosts, value]}
393 {% for role in roles %}
396 - {get_attr: [{{role.name}}, hosts_entry]}
400 type: OS::TripleO::AllNodes::SoftwareConfig
402 cloud_name_external: {get_param: CloudName}
403 cloud_name_internal_api: {get_param: CloudNameInternal}
404 cloud_name_storage: {get_param: CloudNameStorage}
405 cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
406 cloud_name_ctlplane: {get_param: CloudNameCtlplane}
410 {% for role in roles %}
411 - {get_attr: [{{role.name}}ServiceNames, value]}
416 $.data.groups.flatten()
419 {% for role in roles %}
420 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_groups]}
425 $.data.sources.flatten()
428 {% for role in roles %}
429 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_sources]}
431 controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
432 controller_names: {get_attr: [{{primary_role_name}}, hostname]}
434 # Note (shardy) this somewhat complex yaql may be replaced
435 # with a map_deep_merge function in ocata. It merges the
436 # list of maps, but appends to colliding lists when a service
437 # is deployed on more than one role
439 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
442 {% for role in roles %}
443 - {get_attr: [{{role.name}}IpListMap, service_ips]}
447 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
450 {% for role in roles %}
451 - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
453 short_service_node_names:
455 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
458 {% for role in roles %}
459 - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
461 short_service_bootstrap_node:
463 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
466 {% for role in roles %}
467 - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
469 # FIXME(shardy): These require further work to move into service_ips
470 memcache_node_ips: {get_attr: [{{primary_role_name}}IpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
471 NetVipMap: {get_attr: [VipMap, net_ip_map]}
472 RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
473 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
474 DeployIdentifier: {get_param: DeployIdentifier}
475 UpdateIdentifier: {get_param: UpdateIdentifier}
478 type: OS::Heat::RandomString
483 type: OS::Heat::RandomString
486 salt: {get_param: RabbitCookieSalt}
489 type: OS::TripleO::DefaultPasswords
491 DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
492 DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
493 DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
494 DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
495 DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
497 # creates the network architecture
499 type: OS::TripleO::Network
502 type: OS::TripleO::Network::Ports::ControlPlaneVipPort
505 name: control_virtual_ip
506 network: {get_param: NeutronControlPlaneID}
507 fixed_ips: {get_param: ControlFixedIPs}
508 replacement_policy: AUTO
512 type: OS::TripleO::Network::Ports::RedisVipPort
514 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
515 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
516 PortName: redis_virtual_ip
517 NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
519 FixedIPs: {get_param: RedisVirtualFixedIPs}
521 # The public VIP is on the External net, falls back to ctlplane
524 type: OS::TripleO::Network::Ports::ExternalVipPort
526 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
527 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
528 PortName: public_virtual_ip
529 FixedIPs: {get_param: PublicVirtualFixedIPs}
531 InternalApiVirtualIP:
533 type: OS::TripleO::Network::Ports::InternalApiVipPort
535 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
536 PortName: internal_api_virtual_ip
537 FixedIPs: {get_param: InternalApiVirtualFixedIPs}
541 type: OS::TripleO::Network::Ports::StorageVipPort
543 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
544 PortName: storage_virtual_ip
545 FixedIPs: {get_param: StorageVirtualFixedIPs}
547 StorageMgmtVirtualIP:
549 type: OS::TripleO::Network::Ports::StorageMgmtVipPort
551 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
552 PortName: storage_management_virtual_ip
553 FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
556 type: OS::TripleO::Network::Ports::NetVipMap
558 ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
559 ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
560 ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
561 InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
562 InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
563 StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
564 StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
565 StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
566 StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
567 # No tenant or management VIP required
569 # All Nodes Validations
570 AllNodesValidationConfig:
571 type: OS::TripleO::AllNodes::Validation
576 - - {get_attr: [{{primary_role_name}}, resource.0.external_ip_address]}
577 - {get_attr: [{{primary_role_name}}, resource.0.internal_api_ip_address]}
578 - {get_attr: [{{primary_role_name}}, resource.0.storage_ip_address]}
579 - {get_attr: [{{primary_role_name}}, resource.0.storage_mgmt_ip_address]}
580 - {get_attr: [{{primary_role_name}}, resource.0.tenant_ip_address]}
581 - {get_attr: [{{primary_role_name}}, resource.0.management_ip_address]}
584 type: OS::TripleO::Tasks::UpdateWorkflow
586 {% for role in roles %}
587 - {{role.name}}AllNodesDeployment
591 {% for role in roles %}
592 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
595 deploy_identifier: {get_param: DeployIdentifier}
596 update_identifier: {get_param: UpdateIdentifier}
598 # Optional ExtraConfig for all nodes - all roles are passed in here, but
599 # the nested template may configure each role differently (or not at all)
601 type: OS::TripleO::AllNodesExtraConfig
604 {% for role in roles %}
605 - {{role.name}}AllNodesValidationDeployment
609 {% for role in roles %}
610 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
613 # Post deployment steps for all roles
615 type: OS::TripleO::PostDeploySteps
617 {% for role in roles %}
618 - {{role.name}}AllNodesDeployment
622 {% for role in roles %}
623 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
625 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
627 {% for role in roles %}
628 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
633 description: Asserts that the keystone endpoints have been provisioned.
636 description: URL for the Overcloud Keystone service
637 value: {get_attr: [EndpointMap, endpoint_map, KeystonePublic, uri]}
639 description: Keystone Admin VIP endpoint
640 value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
643 Mapping of the resources with the needed info for their endpoints.
644 This includes the protocol used, the IP, port and also a full
645 representation of the URI.
646 value: {get_attr: [EndpointMap, endpoint_map]}
649 The content that should be appended to your /etc/hosts if you want to get
650 hostname-based access to the deployed nodes (useful for testing without
655 - - {get_attr: [hostsConfig, hosts_entries]}
656 - - {get_attr: [VipHosts, value]}
658 description: The services enabled on each role
660 {% for role in roles %}
661 {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
664 description: The configuration data associated with each role
666 {% for role in roles %}
667 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}