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 {{role.name}}HostsDeployment:
265 type: OS::Heat::StructuredDeployments
267 name: {{role.name}}HostsDeployment
268 config: {get_attr: [hostsConfig, config_id]}
269 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
271 {{role.name}}AllNodesDeployment:
272 type: OS::Heat::StructuredDeployments
274 {% for role_inner in roles %}
275 - {{role_inner.name}}HostsDeployment
278 name: {{role.name}}AllNodesDeployment
279 config: {get_attr: [allNodesConfig, config_id]}
280 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
282 # Note we have to use yaql to look up the first hostname/ip in the
283 # list because heat path based attributes operate on the attribute
284 # inside the ResourceGroup, not the exposed list ref discussion in
285 # https://bugs.launchpad.net/heat/+bug/1640488
286 # The coalesce is needed because $.data is None during heat validation
289 expression: coalesce($.data, []).first(null)
290 data: {get_attr: [{{role.name}}, hostname]}
293 expression: coalesce($.data, []).first(null)
294 data: {get_attr: [{{role.name}}, ip_address]}
296 {{role.name}}AllNodesValidationDeployment:
297 type: OS::Heat::StructuredDeployments
298 depends_on: {{role.name}}AllNodesDeployment
300 name: {{role.name}}AllNodesValidationDeployment
301 config: {get_resource: AllNodesValidationConfig}
302 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
304 {{role.name}}IpListMap:
305 type: OS::TripleO::Network::Ports::NetIpListMap
307 ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
308 ExternalIpList: {get_attr: [{{role.name}}, external_ip_address]}
309 InternalApiIpList: {get_attr: [{{role.name}}, internal_api_ip_address]}
310 StorageIpList: {get_attr: [{{role.name}}, storage_ip_address]}
311 StorageMgmtIpList: {get_attr: [{{role.name}}, storage_mgmt_ip_address]}
312 TenantIpList: {get_attr: [{{role.name}}, tenant_ip_address]}
313 ManagementIpList: {get_attr: [{{role.name}}, management_ip_address]}
314 EnabledServices: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
315 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
316 ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
318 # Note (shardy) this somewhat complex yaql may be replaced
319 # with a map_deep_merge function in ocata. It merges the
320 # list of maps, but appends to colliding lists so we can
321 # create a map of lists for all nodes for each network
323 expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
325 - {get_attr: [{{role.name}}, hostname_map]}
328 type: OS::Heat::ResourceGroup
331 count: {get_param: {{role.name}}Count}
332 removal_policies: {get_param: {{role.name}}RemovalPolicies}
334 type: OS::TripleO::{{role.name}}
336 CloudDomain: {get_param: CloudDomain}
337 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
338 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
341 template: {get_param: {{role.name}}HostnameFormat}
343 '%stackname%': {get_param: 'OS::stack_name'}
345 {% if role.name != 'Compute' %}
346 {{role.name}}SchedulerHints: {get_param: {{role.name}}SchedulerHints}
348 NovaComputeSchedulerHints: {get_param: NovaComputeSchedulerHints}
350 ServiceConfigSettings:
352 - get_attr: [{{role.name}}ServiceChain, role_data, config_settings]
354 - get_attr: [{{r.name}}ServiceChain, role_data, global_config_settings]
356 # This next step combines two yaql passes:
357 # - The inner one does a deep merge on the service_config_settings for all roles
358 # - The outer one filters the map based on the services enabled for the role
359 # then merges the result into one map.
361 expression: let(root => $) -> $.data.map.items().where($[0] in coalesce($root.data.services, [])).select($[1]).reduce($1.mergeWith($2), {})
365 expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
368 - get_attr: [{{r.name}}ServiceChain, role_data, service_config_settings]
370 services: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
371 ServiceNames: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
372 MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChain, role_data, monitoring_subscriptions]}
373 ServiceMetadataSettings: {get_attr: [{{role.name}}ServiceChain, role_data, service_metadata_settings]}
377 type: OS::TripleO::Hosts::SoftwareConfig
383 - add_vips_to_etc_hosts
384 - {get_attr: [VipHosts, value]}
387 {% for role in roles %}
390 - {get_attr: [{{role.name}}, hosts_entry]}
394 type: OS::TripleO::AllNodes::SoftwareConfig
396 cloud_name_external: {get_param: CloudName}
397 cloud_name_internal_api: {get_param: CloudNameInternal}
398 cloud_name_storage: {get_param: CloudNameStorage}
399 cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
400 cloud_name_ctlplane: {get_param: CloudNameCtlplane}
404 {% for role in roles %}
405 - {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
410 $.data.groups.flatten()
413 {% for role in roles %}
414 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_groups]}
419 $.data.sources.flatten()
422 {% for role in roles %}
423 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_sources]}
425 controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
426 controller_names: {get_attr: [{{primary_role_name}}, hostname]}
428 # Note (shardy) this somewhat complex yaql may be replaced
429 # with a map_deep_merge function in ocata. It merges the
430 # list of maps, but appends to colliding lists when a service
431 # is deployed on more than one role
433 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
436 {% for role in roles %}
437 - {get_attr: [{{role.name}}IpListMap, service_ips]}
441 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
444 {% for role in roles %}
445 - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
447 short_service_node_names:
449 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
452 {% for role in roles %}
453 - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
455 short_service_bootstrap_node:
457 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
460 {% for role in roles %}
461 - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
463 # FIXME(shardy): These require further work to move into service_ips
464 memcache_node_ips: {get_attr: [{{primary_role_name}}IpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
465 NetVipMap: {get_attr: [VipMap, net_ip_map]}
466 RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
467 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
468 DeployIdentifier: {get_param: DeployIdentifier}
469 UpdateIdentifier: {get_param: UpdateIdentifier}
472 type: OS::Heat::RandomString
477 type: OS::Heat::RandomString
480 salt: {get_param: RabbitCookieSalt}
483 type: OS::TripleO::DefaultPasswords
485 DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
486 DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
487 DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
488 DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
489 DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
491 # creates the network architecture
493 type: OS::TripleO::Network
496 type: OS::TripleO::Network::Ports::ControlPlaneVipPort
499 name: control_virtual_ip
500 network: {get_param: NeutronControlPlaneID}
501 fixed_ips: {get_param: ControlFixedIPs}
502 replacement_policy: AUTO
506 type: OS::TripleO::Network::Ports::RedisVipPort
508 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
509 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
510 PortName: redis_virtual_ip
511 NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
513 FixedIPs: {get_param: RedisVirtualFixedIPs}
515 # The public VIP is on the External net, falls back to ctlplane
518 type: OS::TripleO::Network::Ports::ExternalVipPort
520 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
521 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
522 PortName: public_virtual_ip
523 FixedIPs: {get_param: PublicVirtualFixedIPs}
525 InternalApiVirtualIP:
527 type: OS::TripleO::Network::Ports::InternalApiVipPort
529 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
530 PortName: internal_api_virtual_ip
531 FixedIPs: {get_param: InternalApiVirtualFixedIPs}
535 type: OS::TripleO::Network::Ports::StorageVipPort
537 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
538 PortName: storage_virtual_ip
539 FixedIPs: {get_param: StorageVirtualFixedIPs}
541 StorageMgmtVirtualIP:
543 type: OS::TripleO::Network::Ports::StorageMgmtVipPort
545 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
546 PortName: storage_management_virtual_ip
547 FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
550 type: OS::TripleO::Network::Ports::NetVipMap
552 ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
553 ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
554 ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
555 InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
556 InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
557 StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
558 StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
559 StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
560 StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
561 # No tenant or management VIP required
563 # All Nodes Validations
564 AllNodesValidationConfig:
565 type: OS::TripleO::AllNodes::Validation
571 expression: coalesce($.data, []).first(null)
572 data: {get_attr: [Controller, external_ip_address]}
574 expression: coalesce($.data, []).first(null)
575 data: {get_attr: [Controller, internal_api_ip_address]}
577 expression: coalesce($.data, []).first(null)
578 data: {get_attr: [Controller, storage_ip_address]}
580 expression: coalesce($.data, []).first(null)
581 data: {get_attr: [Controller, storage_mgmt_ip_address]}
583 expression: coalesce($.data, []).first(null)
584 data: {get_attr: [Controller, tenant_ip_address]}
586 expression: coalesce($.data, []).first(null)
587 data: {get_attr: [Controller, 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}}ServiceChain, role_data, service_names]}
670 description: The configuration data associated with each role
672 {% for role in roles %}
673 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}