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]}
252 # Jinja loop for Role in roles_data.yaml
253 {% for role in roles %}
254 # Resources generated for {{role.name}} Role
255 {{role.name}}ServiceChain:
256 type: OS::TripleO::Services
259 get_param: {{role.name}}Services
260 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
261 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
262 DefaultPasswords: {get_attr: [DefaultPasswords, passwords]}
264 # Filter any null/None service_names which may be present due to mapping
265 # of services to OS::Heat::None
266 {{role.name}}ServiceNames:
267 type: OS::Heat::Value
268 depends_on: {{role.name}}ServiceChain
270 type: comma_delimited_list
273 expression: coalesce($.data, []).where($ != null)
274 data: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
276 {{role.name}}HostsDeployment:
277 type: OS::Heat::StructuredDeployments
279 name: {{role.name}}HostsDeployment
280 config: {get_attr: [hostsConfig, config_id]}
281 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
283 {{role.name}}AllNodesDeployment:
284 type: OS::Heat::StructuredDeployments
286 {% for role_inner in roles %}
287 - {{role_inner.name}}HostsDeployment
290 name: {{role.name}}AllNodesDeployment
291 config: {get_attr: [allNodesConfig, config_id]}
292 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
294 # Note we have to use yaql to look up the first hostname/ip in the
295 # list because heat path based attributes operate on the attribute
296 # inside the ResourceGroup, not the exposed list ref discussion in
297 # https://bugs.launchpad.net/heat/+bug/1640488
298 # The coalesce is needed because $.data is None during heat validation
301 expression: coalesce($.data, []).first(null)
302 data: {get_attr: [{{role.name}}, hostname]}
305 expression: coalesce($.data, []).first(null)
306 data: {get_attr: [{{role.name}}, ip_address]}
308 {{role.name}}AllNodesValidationDeployment:
309 type: OS::Heat::StructuredDeployments
310 depends_on: {{role.name}}AllNodesDeployment
312 name: {{role.name}}AllNodesValidationDeployment
313 config: {get_resource: AllNodesValidationConfig}
314 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
316 {{role.name}}IpListMap:
317 type: OS::TripleO::Network::Ports::NetIpListMap
319 ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
320 ExternalIpList: {get_attr: [{{role.name}}, external_ip_address]}
321 InternalApiIpList: {get_attr: [{{role.name}}, internal_api_ip_address]}
322 StorageIpList: {get_attr: [{{role.name}}, storage_ip_address]}
323 StorageMgmtIpList: {get_attr: [{{role.name}}, storage_mgmt_ip_address]}
324 TenantIpList: {get_attr: [{{role.name}}, tenant_ip_address]}
325 ManagementIpList: {get_attr: [{{role.name}}, management_ip_address]}
326 EnabledServices: {get_attr: [{{role.name}}ServiceNames, value]}
327 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
328 ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
330 # Note (shardy) this somewhat complex yaql may be replaced
331 # with a map_deep_merge function in ocata. It merges the
332 # list of maps, but appends to colliding lists so we can
333 # create a map of lists for all nodes for each network
335 expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
337 - {get_attr: [{{role.name}}, hostname_map]}
340 type: OS::Heat::ResourceGroup
343 count: {get_param: {{role.name}}Count}
344 removal_policies: {get_param: {{role.name}}RemovalPolicies}
346 type: OS::TripleO::{{role.name}}
348 CloudDomain: {get_param: CloudDomain}
349 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
350 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
353 template: {get_param: {{role.name}}HostnameFormat}
355 '%stackname%': {get_param: 'OS::stack_name'}
357 {% if role.name != 'Compute' %}
358 {{role.name}}SchedulerHints: {get_param: {{role.name}}SchedulerHints}
360 NovaComputeSchedulerHints: {get_param: NovaComputeSchedulerHints}
362 ServiceConfigSettings:
364 - get_attr: [{{role.name}}ServiceChain, role_data, config_settings]
366 - get_attr: [{{r.name}}ServiceChain, role_data, global_config_settings]
368 # This next step combines two yaql passes:
369 # - The inner one does a deep merge on the service_config_settings for all roles
370 # - The outer one filters the map based on the services enabled for the role
371 # then merges the result into one map.
373 expression: let(root => $) -> $.data.map.items().where($[0] in coalesce($root.data.services, [])).select($[1]).reduce($1.mergeWith($2), {})
377 expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
380 - get_attr: [{{r.name}}ServiceChain, role_data, service_config_settings]
382 services: {get_attr: [{{role.name}}ServiceNames, value]}
383 ServiceNames: {get_attr: [{{role.name}}ServiceNames, value]}
384 MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChain, role_data, monitoring_subscriptions]}
385 ServiceMetadataSettings: {get_attr: [{{role.name}}ServiceChain, role_data, service_metadata_settings]}
389 type: OS::TripleO::Hosts::SoftwareConfig
395 - add_vips_to_etc_hosts
396 - {get_attr: [VipHosts, value]}
399 {% for role in roles %}
402 - {get_attr: [{{role.name}}, hosts_entry]}
406 type: OS::TripleO::AllNodes::SoftwareConfig
408 cloud_name_external: {get_param: CloudName}
409 cloud_name_internal_api: {get_param: CloudNameInternal}
410 cloud_name_storage: {get_param: CloudNameStorage}
411 cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
412 cloud_name_ctlplane: {get_param: CloudNameCtlplane}
416 {% for role in roles %}
417 - {get_attr: [{{role.name}}ServiceNames, value]}
422 $.data.groups.flatten()
425 {% for role in roles %}
426 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_groups]}
431 $.data.sources.flatten()
434 {% for role in roles %}
435 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_sources]}
437 controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
438 controller_names: {get_attr: [{{primary_role_name}}, hostname]}
440 # Note (shardy) this somewhat complex yaql may be replaced
441 # with a map_deep_merge function in ocata. It merges the
442 # list of maps, but appends to colliding lists when a service
443 # is deployed on more than one role
445 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
448 {% for role in roles %}
449 - {get_attr: [{{role.name}}IpListMap, service_ips]}
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_hostnames]}
459 short_service_node_names:
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, short_service_hostnames]}
467 short_service_bootstrap_node:
469 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
472 {% for role in roles %}
473 - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
475 # FIXME(shardy): These require further work to move into service_ips
476 memcache_node_ips: {get_attr: [{{primary_role_name}}IpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
477 NetVipMap: {get_attr: [VipMap, net_ip_map]}
478 RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
479 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
480 DeployIdentifier: {get_param: DeployIdentifier}
481 UpdateIdentifier: {get_param: UpdateIdentifier}
484 type: OS::Heat::RandomString
489 type: OS::Heat::RandomString
492 salt: {get_param: RabbitCookieSalt}
495 type: OS::TripleO::DefaultPasswords
497 DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
498 DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
499 DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
500 DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
501 DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
503 # creates the network architecture
505 type: OS::TripleO::Network
508 type: OS::TripleO::Network::Ports::ControlPlaneVipPort
511 name: control_virtual_ip
512 network: {get_param: NeutronControlPlaneID}
513 fixed_ips: {get_param: ControlFixedIPs}
514 replacement_policy: AUTO
518 type: OS::TripleO::Network::Ports::RedisVipPort
520 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
521 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
522 PortName: redis_virtual_ip
523 NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
525 FixedIPs: {get_param: RedisVirtualFixedIPs}
527 # The public VIP is on the External net, falls back to ctlplane
530 type: OS::TripleO::Network::Ports::ExternalVipPort
532 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
533 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
534 PortName: public_virtual_ip
535 FixedIPs: {get_param: PublicVirtualFixedIPs}
537 InternalApiVirtualIP:
539 type: OS::TripleO::Network::Ports::InternalApiVipPort
541 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
542 PortName: internal_api_virtual_ip
543 FixedIPs: {get_param: InternalApiVirtualFixedIPs}
547 type: OS::TripleO::Network::Ports::StorageVipPort
549 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
550 PortName: storage_virtual_ip
551 FixedIPs: {get_param: StorageVirtualFixedIPs}
553 StorageMgmtVirtualIP:
555 type: OS::TripleO::Network::Ports::StorageMgmtVipPort
557 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
558 PortName: storage_management_virtual_ip
559 FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
562 type: OS::TripleO::Network::Ports::NetVipMap
564 ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
565 ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
566 ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
567 InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
568 InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
569 StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
570 StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
571 StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
572 StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
573 # No tenant or management VIP required
575 # All Nodes Validations
576 AllNodesValidationConfig:
577 type: OS::TripleO::AllNodes::Validation
582 - - {get_attr: [{{primary_role_name}}, resource.0.external_ip_address]}
583 - {get_attr: [{{primary_role_name}}, resource.0.internal_api_ip_address]}
584 - {get_attr: [{{primary_role_name}}, resource.0.storage_ip_address]}
585 - {get_attr: [{{primary_role_name}}, resource.0.storage_mgmt_ip_address]}
586 - {get_attr: [{{primary_role_name}}, resource.0.tenant_ip_address]}
587 - {get_attr: [{{primary_role_name}}, resource.0.management_ip_address]}
590 type: OS::TripleO::Tasks::UpdateWorkflow
592 {% for role in roles %}
593 - {{role.name}}AllNodesDeployment
597 {% for role in roles %}
598 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
601 deploy_identifier: {get_param: DeployIdentifier}
602 update_identifier: {get_param: UpdateIdentifier}
604 # Optional ExtraConfig for all nodes - all roles are passed in here, but
605 # the nested template may configure each role differently (or not at all)
607 type: OS::TripleO::AllNodesExtraConfig
610 {% for role in roles %}
611 - {{role.name}}AllNodesValidationDeployment
615 {% for role in roles %}
616 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
619 # Post deployment steps for all roles
621 type: OS::TripleO::PostDeploySteps
623 {% for role in roles %}
624 - {{role.name}}AllNodesDeployment
628 {% for role in roles %}
629 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
631 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
633 {% for role in roles %}
634 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
639 description: Asserts that the keystone endpoints have been provisioned.
642 description: URL for the Overcloud Keystone service
643 value: {get_attr: [EndpointMapData, value, KeystonePublic, uri]}
645 description: Keystone Admin VIP endpoint
646 value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
649 Mapping of the resources with the needed info for their endpoints.
650 This includes the protocol used, the IP, port and also a full
651 representation of the URI.
652 value: {get_attr: [EndpointMapData, value]}
655 The content that should be appended to your /etc/hosts if you want to get
656 hostname-based access to the deployed nodes (useful for testing without
661 - - {get_attr: [hostsConfig, hosts_entries]}
662 - - {get_attr: [VipHosts, value]}
664 description: The services enabled on each role
666 {% for role in roles %}
667 {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
670 description: The configuration data associated with each role
672 {% for role in roles %}
673 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}