1 {%- set primary_role = [roles[0]] -%}
2 {%- for role in roles -%}
3 {%- if 'primary' in role.tags and 'controller' in role.tags -%}
4 {%- set _ = primary_role.pop() -%}
5 {%- set _ = primary_role.append(role) -%}
8 {%- set primary_role_name = primary_role[0].name -%}
9 # primary role is: {{primary_role_name}}
10 heat_template_version: ocata
13 Deploy an OpenStack environment, consisting of several node types (roles),
14 Controller, Compute, BlockStorage, SwiftStorage and CephStorage. The Storage
15 roles enable independent scaling of the storage components, but the minimal
16 deployment is one Controller and one Compute node.
19 # TODO(shadower): we should probably use the parameter groups to put
23 # Common parameters (not specific to a role)
25 default: overcloud.localdomain
26 description: The DNS name of this cloud. E.g. ci-overcloud.tripleo.org
29 default: overcloud.internalapi.localdomain
31 The DNS name of this cloud's internal API endpoint. E.g.
32 'ci-overcloud.internalapi.tripleo.org'.
35 default: overcloud.storage.localdomain
37 The DNS name of this cloud's storage endpoint. E.g.
38 'ci-overcloud.storage.tripleo.org'.
40 CloudNameStorageManagement:
41 default: overcloud.storagemgmt.localdomain
43 The DNS name of this cloud's storage management endpoint. E.g.
44 'ci-overcloud.storagemgmt.tripleo.org'.
47 default: overcloud.ctlplane.localdomain
49 The DNS name of this cloud's storage management endpoint. E.g.
50 'ci-overcloud.management.tripleo.org'.
55 Control the IP allocation for the ControlVirtualIP port. E.g.
56 [{'ip_address':'1.2.3.4'}]
58 InternalApiVirtualFixedIPs:
61 Control the IP allocation for the InternalApiVirtualInterface port. E.g.
62 [{'ip_address':'1.2.3.4'}]
64 NeutronControlPlaneID:
67 description: Neutron ID or name for ctlplane network.
68 NeutronPublicInterface:
70 description: What interface to bridge onto br-ex for network nodes.
72 PublicVirtualFixedIPs:
75 Control the IP allocation for the PublicVirtualInterface port. E.g.
76 [{'ip_address':'1.2.3.4'}]
81 description: Salt for the rabbit cookie, change this to force the randomly generated rabbit cookie to change.
82 StorageVirtualFixedIPs:
85 Control the IP allocation for the StorageVirtualInterface port. E.g.
86 [{'ip_address':'1.2.3.4'}]
88 StorageMgmtVirtualFixedIPs:
91 Control the IP allocation for the StorageMgmgVirtualInterface port. E.g.
92 [{'ip_address':'1.2.3.4'}]
97 Control the IP allocation for the virtual IP used by Redis. E.g.
98 [{'ip_address':'1.2.3.4'}]
101 default: 'localdomain'
104 The DNS domain used for the hosts. This should match the dhcp_domain
105 configured in the Undercloud neutron. Defaults to localdomain.
109 Extra properties or metadata passed to Nova for the created nodes in
110 the overcloud. It's accessible via the Nova metadata API.
113 # Compute-specific params
114 # FIXME(shardy) handle these deprecated names as they don't match compute.yaml
115 HypervisorNeutronPhysicalBridge:
118 An OVS bridge to create on each hypervisor. This defaults to br-ex the
119 same as the control plane nodes, as we have a uniform configuration of
120 the openvswitch agent. Typically should not need to be changed.
122 HypervisorNeutronPublicInterface:
124 description: What interface to add to the HypervisorNeutronPhysicalBridge.
129 description: Maxiumum batch size for creating nodes
132 # Jinja loop for Role in role_data.yaml
133 {% for role in roles %}
134 # Parameters generated for {{role.name}} Role
135 {{role.name}}Services:
136 description: A list of service resources (configured in the Heat
137 resource_registry) which represent nested stacks
138 for each service that should get installed on the {{role.name}} role.
139 type: comma_delimited_list
142 description: Number of {{role.name}} nodes to deploy
144 default: {{role.CountDefault|default(0)}}
146 {{role.name}}HostnameFormat:
149 Format for {{role.name}} node hostnames
150 Note %index% is translated into the index of the node, e.g 0/1/2 etc
151 and %stackname% is replaced with the stack name e.g overcloud
152 {% if role.HostnameFormatDefault %}
153 default: "{{role.HostnameFormatDefault}}"
155 default: "%stackname%-{{role.name.lower()}}-%index%"
158 {{role.name}}RemovalPolicies:
162 List of resources to be removed from {{role.name}} ResourceGroup when
163 doing an update which requires removal of specific resources.
164 Example format ComputeRemovalPolicies: [{'resource_list': ['0']}]
166 {% if role.name != 'Compute' %}
167 {{role.name}}SchedulerHints:
169 NovaComputeSchedulerHints:
172 description: Optional scheduler hints to pass to nova
176 # Identifiers to trigger tasks on nodes
181 Setting to a previously unused value during stack-update will trigger
182 package update on all nodes
187 Setting this to a unique value will re-run any deployment tasks which
188 perform configuration on a Heat stack-update.
193 Set to true to append per network Vips to /etc/hosts on each node.
196 add_vips_to_etc_hosts: {equals : [{get_param: AddVipsToEtcHosts}, True]}
201 type: OS::Heat::Value
210 IP: {get_attr: [VipMap, net_ip_map, external]}
211 HOST: {get_param: CloudName}
215 IP: {get_attr: [VipMap, net_ip_map, ctlplane]}
216 HOST: {get_param: CloudNameCtlplane}
220 IP: {get_attr: [VipMap, net_ip_map, internal_api]}
221 HOST: {get_param: CloudNameInternal}
225 IP: {get_attr: [VipMap, net_ip_map, storage]}
226 HOST: {get_param: CloudNameStorage}
230 IP: {get_attr: [VipMap, net_ip_map, storage_mgmt]}
231 HOST: {get_param: CloudNameStorageManagement}
233 HeatAuthEncryptionKey:
234 type: OS::Heat::RandomString
237 type: OS::Heat::RandomString
242 type: OS::Heat::RandomString
247 type: OS::TripleO::ServiceNetMap
250 type: OS::TripleO::EndpointMap
253 external: {get_param: CloudName}
254 internal_api: {get_param: CloudNameInternal}
255 storage: {get_param: CloudNameStorage}
256 storage_mgmt: {get_param: CloudNameStorageManagement}
257 ctlplane: {get_param: CloudNameCtlplane}
258 NetIpMap: {get_attr: [VipMap, net_ip_map]}
259 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
262 type: OS::Heat::Value
265 value: {get_attr: [EndpointMap, endpoint_map]}
268 type: OS::TripleO::Ssh::KnownHostsConfig
273 {% for role in roles %}
274 - {get_attr: [{{role.name}}, known_hosts_entry]}
277 # Jinja loop for Role in roles_data.yaml
278 {% for role in roles %}
279 # Resources generated for {{role.name}} Role
280 {{role.name}}ServiceChain:
281 type: OS::TripleO::Services
284 get_param: {{role.name}}Services
285 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
286 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
287 DefaultPasswords: {get_attr: [DefaultPasswords, passwords]}
289 # Filter any null/None service_names which may be present due to mapping
290 # of services to OS::Heat::None
291 {{role.name}}ServiceNames:
292 type: OS::Heat::Value
293 depends_on: {{role.name}}ServiceChain
295 type: comma_delimited_list
298 expression: coalesce($.data, []).where($ != null)
299 data: {get_attr: [{{role.name}}ServiceChain, role_data, service_names]}
301 {{role.name}}HostsDeployment:
302 type: OS::Heat::StructuredDeployments
304 name: {{role.name}}HostsDeployment
305 config: {get_attr: [hostsConfig, config_id]}
306 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
308 {{role.name}}SshKnownHostsDeployment:
309 type: OS::Heat::StructuredDeployments
311 name: {{role.name}}SshKnownHostsDeployment
312 config: {get_resource: SshKnownHostsConfig}
313 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
315 {{role.name}}AllNodesDeployment:
316 type: OS::Heat::StructuredDeployments
318 {% for role_inner in roles %}
319 - {{role_inner.name}}HostsDeployment
322 name: {{role.name}}AllNodesDeployment
323 config: {get_attr: [allNodesConfig, config_id]}
324 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
326 # Note we have to use yaql to look up the first hostname/ip in the
327 # list because heat path based attributes operate on the attribute
328 # inside the ResourceGroup, not the exposed list ref discussion in
329 # https://bugs.launchpad.net/heat/+bug/1640488
330 # The coalesce is needed because $.data is None during heat validation
333 expression: coalesce($.data, []).first(null)
334 data: {get_attr: [{{role.name}}, hostname]}
337 expression: coalesce($.data, []).first(null)
338 data: {get_attr: [{{role.name}}, ip_address]}
340 {{role.name}}AllNodesValidationDeployment:
341 type: OS::Heat::StructuredDeployments
342 depends_on: {{role.name}}AllNodesDeployment
344 name: {{role.name}}AllNodesValidationDeployment
345 config: {get_resource: AllNodesValidationConfig}
346 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
348 {{role.name}}IpListMap:
349 type: OS::TripleO::Network::Ports::NetIpListMap
351 ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
352 ExternalIpList: {get_attr: [{{role.name}}, external_ip_address]}
353 InternalApiIpList: {get_attr: [{{role.name}}, internal_api_ip_address]}
354 StorageIpList: {get_attr: [{{role.name}}, storage_ip_address]}
355 StorageMgmtIpList: {get_attr: [{{role.name}}, storage_mgmt_ip_address]}
356 TenantIpList: {get_attr: [{{role.name}}, tenant_ip_address]}
357 ManagementIpList: {get_attr: [{{role.name}}, management_ip_address]}
358 EnabledServices: {get_attr: [{{role.name}}ServiceNames, value]}
359 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
360 ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
362 # Note (shardy) this somewhat complex yaql may be replaced
363 # with a map_deep_merge function in ocata. It merges the
364 # list of maps, but appends to colliding lists so we can
365 # create a map of lists for all nodes for each network
367 expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
369 - {get_attr: [{{role.name}}, hostname_map]}
372 type: OS::Heat::ResourceGroup
376 max_batch_size: {get_param: NodeCreateBatchSize}
378 count: {get_param: {{role.name}}Count}
379 removal_policies: {get_param: {{role.name}}RemovalPolicies}
381 type: OS::TripleO::{{role.name}}
383 CloudDomain: {get_param: CloudDomain}
384 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
385 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
388 template: {get_param: {{role.name}}HostnameFormat}
390 '%stackname%': {get_param: 'OS::stack_name'}
392 {% if role.name != 'Compute' %}
393 {{role.name}}SchedulerHints: {get_param: {{role.name}}SchedulerHints}
395 NovaComputeSchedulerHints: {get_param: NovaComputeSchedulerHints}
397 ServiceConfigSettings:
399 - get_attr: [{{role.name}}ServiceChain, role_data, config_settings]
401 - get_attr: [{{r.name}}ServiceChain, role_data, global_config_settings]
403 # This next step combines two yaql passes:
404 # - The inner one does a deep merge on the service_config_settings for all roles
405 # - The outer one filters the map based on the services enabled for the role
406 # then merges the result into one map.
408 expression: let(root => $) -> $.data.map.items().where($[0] in coalesce($root.data.services, [])).select($[1]).reduce($1.mergeWith($2), {})
412 expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
415 - get_attr: [{{r.name}}ServiceChain, role_data, service_config_settings]
417 services: {get_attr: [{{role.name}}ServiceNames, value]}
418 ServiceNames: {get_attr: [{{role.name}}ServiceNames, value]}
419 MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChain, role_data, monitoring_subscriptions]}
420 ServiceMetadataSettings: {get_attr: [{{role.name}}ServiceChain, role_data, service_metadata_settings]}
424 type: OS::TripleO::Hosts::SoftwareConfig
430 - add_vips_to_etc_hosts
431 - {get_attr: [VipHosts, value]}
434 {% for role in roles %}
437 - {get_attr: [{{role.name}}, hosts_entry]}
441 type: OS::TripleO::AllNodes::SoftwareConfig
443 cloud_name_external: {get_param: CloudName}
444 cloud_name_internal_api: {get_param: CloudNameInternal}
445 cloud_name_storage: {get_param: CloudNameStorage}
446 cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
447 cloud_name_ctlplane: {get_param: CloudNameCtlplane}
451 {% for role in roles %}
452 - {get_attr: [{{role.name}}ServiceNames, value]}
457 $.data.groups.flatten()
460 {% for role in roles %}
461 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_groups]}
466 $.data.sources.flatten()
469 {% for role in roles %}
470 - {get_attr: [{{role.name}}ServiceChain, role_data, logging_sources]}
472 controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
473 controller_names: {get_attr: [{{primary_role_name}}, hostname]}
475 # Note (shardy) this somewhat complex yaql may be replaced
476 # with a map_deep_merge function in ocata. It merges the
477 # list of maps, but appends to colliding lists when a service
478 # is deployed on more than one role
480 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
483 {% for role in roles %}
484 - {get_attr: [{{role.name}}IpListMap, service_ips]}
488 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
491 {% for role in roles %}
492 - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
494 short_service_node_names:
496 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
499 {% for role in roles %}
500 - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
502 short_service_bootstrap_node:
504 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
507 {% for role in roles %}
508 - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
510 # FIXME(shardy): These require further work to move into service_ips
511 memcache_node_ips: {get_attr: [{{primary_role_name}}IpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
512 NetVipMap: {get_attr: [VipMap, net_ip_map]}
513 RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
514 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
515 DeployIdentifier: {get_param: DeployIdentifier}
516 UpdateIdentifier: {get_param: UpdateIdentifier}
519 type: OS::Heat::RandomString
524 type: OS::Heat::RandomString
527 salt: {get_param: RabbitCookieSalt}
530 type: OS::TripleO::DefaultPasswords
532 DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
533 DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
534 DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
535 DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
536 DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
538 # creates the network architecture
540 type: OS::TripleO::Network
543 type: OS::TripleO::Network::Ports::ControlPlaneVipPort
546 name: control_virtual_ip
547 network: {get_param: NeutronControlPlaneID}
548 fixed_ips: {get_param: ControlFixedIPs}
549 replacement_policy: AUTO
553 type: OS::TripleO::Network::Ports::RedisVipPort
555 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
556 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
557 PortName: redis_virtual_ip
558 NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
560 FixedIPs: {get_param: RedisVirtualFixedIPs}
562 # The public VIP is on the External net, falls back to ctlplane
565 type: OS::TripleO::Network::Ports::ExternalVipPort
567 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
568 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
569 PortName: public_virtual_ip
570 FixedIPs: {get_param: PublicVirtualFixedIPs}
572 InternalApiVirtualIP:
574 type: OS::TripleO::Network::Ports::InternalApiVipPort
576 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
577 PortName: internal_api_virtual_ip
578 FixedIPs: {get_param: InternalApiVirtualFixedIPs}
582 type: OS::TripleO::Network::Ports::StorageVipPort
584 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
585 PortName: storage_virtual_ip
586 FixedIPs: {get_param: StorageVirtualFixedIPs}
588 StorageMgmtVirtualIP:
590 type: OS::TripleO::Network::Ports::StorageMgmtVipPort
592 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
593 PortName: storage_management_virtual_ip
594 FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
597 type: OS::TripleO::Network::Ports::NetVipMap
599 ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
600 ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
601 ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
602 InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
603 InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
604 StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
605 StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
606 StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
607 StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
608 # No tenant or management VIP required
610 # All Nodes Validations
611 AllNodesValidationConfig:
612 type: OS::TripleO::AllNodes::Validation
618 expression: coalesce($.data, []).first(null)
619 data: {get_attr: [{{primary_role_name}}, external_ip_address]}
621 expression: coalesce($.data, []).first(null)
622 data: {get_attr: [{{primary_role_name}}, internal_api_ip_address]}
624 expression: coalesce($.data, []).first(null)
625 data: {get_attr: [{{primary_role_name}}, storage_ip_address]}
627 expression: coalesce($.data, []).first(null)
628 data: {get_attr: [{{primary_role_name}}, storage_mgmt_ip_address]}
630 expression: coalesce($.data, []).first(null)
631 data: {get_attr: [{{primary_role_name}}, tenant_ip_address]}
633 expression: coalesce($.data, []).first(null)
634 data: {get_attr: [{{primary_role_name}}, management_ip_address]}
637 type: OS::TripleO::Tasks::UpdateWorkflow
639 {% for role in roles %}
640 - {{role.name}}AllNodesDeployment
644 {% for role in roles %}
645 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
648 deploy_identifier: {get_param: DeployIdentifier}
649 update_identifier: {get_param: UpdateIdentifier}
651 # Optional ExtraConfig for all nodes - all roles are passed in here, but
652 # the nested template may configure each role differently (or not at all)
654 type: OS::TripleO::AllNodesExtraConfig
657 {% for role in roles %}
658 - {{role.name}}AllNodesValidationDeployment
662 {% for role in roles %}
663 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
666 # Post deployment steps for all roles
668 type: OS::TripleO::PostDeploySteps
670 {% for role in roles %}
671 - {{role.name}}AllNodesDeployment
675 {% for role in roles %}
676 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
678 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
680 {% for role in roles %}
681 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
686 description: Asserts that the keystone endpoints have been provisioned.
689 description: URL for the Overcloud Keystone service
690 value: {get_attr: [EndpointMapData, value, KeystonePublic, uri]}
692 description: Keystone Admin VIP endpoint
693 value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
696 Mapping of the resources with the needed info for their endpoints.
697 This includes the protocol used, the IP, port and also a full
698 representation of the URI.
699 value: {get_attr: [EndpointMapData, value]}
702 The content that should be appended to your /etc/hosts if you want to get
703 hostname-based access to the deployed nodes (useful for testing without
708 - - {get_attr: [hostsConfig, hosts_entries]}
709 - - {get_attr: [VipHosts, value]}
711 description: The services enabled on each role
713 {% for role in roles %}
714 {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
717 description: The configuration data associated with each role
719 {% for role in roles %}
720 {{role.name}}: {get_attr: [{{role.name}}ServiceChain, role_data]}
723 description: Mapping of each network to a list of IPs for each role
725 {% for role in roles %}
726 {{role.name}}: {get_attr: [{{role.name}}IpListMap, net_ip_map]}