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: pike
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
175 {{role.name}}Parameters:
177 description: Optional Role Specific parameters to be provided to service
181 # Identifiers to trigger tasks on nodes
186 Setting to a previously unused value during stack-update will trigger
187 package update on all nodes
192 Setting this to a unique value will re-run any deployment tasks which
193 perform configuration on a Heat stack-update.
198 Set to true to append per network Vips to /etc/hosts on each node.
201 add_vips_to_etc_hosts: {equals : [{get_param: AddVipsToEtcHosts}, True]}
206 type: OS::Heat::Value
215 IP: {get_attr: [VipMap, net_ip_map, external]}
216 HOST: {get_param: CloudName}
220 IP: {get_attr: [VipMap, net_ip_map, ctlplane]}
221 HOST: {get_param: CloudNameCtlplane}
225 IP: {get_attr: [VipMap, net_ip_map, internal_api]}
226 HOST: {get_param: CloudNameInternal}
230 IP: {get_attr: [VipMap, net_ip_map, storage]}
231 HOST: {get_param: CloudNameStorage}
235 IP: {get_attr: [VipMap, net_ip_map, storage_mgmt]}
236 HOST: {get_param: CloudNameStorageManagement}
238 HeatAuthEncryptionKey:
239 type: OS::Heat::RandomString
242 type: OS::Heat::RandomString
247 type: OS::Heat::RandomString
252 type: OS::TripleO::ServiceNetMap
255 type: OS::TripleO::EndpointMap
258 external: {get_param: CloudName}
259 internal_api: {get_param: CloudNameInternal}
260 storage: {get_param: CloudNameStorage}
261 storage_mgmt: {get_param: CloudNameStorageManagement}
262 ctlplane: {get_param: CloudNameCtlplane}
263 NetIpMap: {get_attr: [VipMap, net_ip_map]}
264 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
267 type: OS::Heat::Value
270 value: {get_attr: [EndpointMap, endpoint_map]}
273 type: OS::TripleO::Ssh::KnownHostsConfig
278 {% for role in roles %}
279 - {get_attr: [{{role.name}}, known_hosts_entry]}
282 # Jinja loop for Role in roles_data.yaml
283 {% for role in roles %}
284 # Resources generated for {{role.name}} Role
285 {{role.name}}ServiceChain:
286 type: OS::TripleO::Services
289 get_param: {{role.name}}Services
290 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
291 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
292 DefaultPasswords: {get_attr: [DefaultPasswords, passwords]}
293 RoleName: {{role.name}}
294 RoleParameters: {get_param: {{role.name}}Parameters}
296 # Lookup of role_data via heat outputs is slow, so workaround this by caching
297 # the value in an OS::Heat::Value resource
298 {{role.name}}ServiceChainRoleData:
299 type: OS::Heat::Value
302 value: {get_attr: [{{role.name}}ServiceChain, role_data]}
304 # Filter any null/None service_names which may be present due to mapping
305 # of services to OS::Heat::None
306 {{role.name}}ServiceNames:
307 type: OS::Heat::Value
308 depends_on: {{role.name}}ServiceChain
310 type: comma_delimited_list
313 expression: coalesce($.data, []).where($ != null)
314 data: {get_attr: [{{role.name}}ServiceChainRoleData, value, service_names]}
316 {{role.name}}HostsDeployment:
317 type: OS::Heat::StructuredDeployments
319 name: {{role.name}}HostsDeployment
320 config: {get_attr: [hostsConfig, config_id]}
321 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
323 {{role.name}}SshKnownHostsDeployment:
324 type: OS::Heat::StructuredDeployments
326 name: {{role.name}}SshKnownHostsDeployment
327 config: {get_resource: SshKnownHostsConfig}
328 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
330 {{role.name}}AllNodesDeployment:
331 type: OS::Heat::StructuredDeployments
333 {% for role_inner in roles %}
334 - {{role_inner.name}}HostsDeployment
337 name: {{role.name}}AllNodesDeployment
338 config: {get_attr: [allNodesConfig, config_id]}
339 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
341 # Note we have to use yaql to look up the first hostname/ip in the
342 # list because heat path based attributes operate on the attribute
343 # inside the ResourceGroup, not the exposed list ref discussion in
344 # https://bugs.launchpad.net/heat/+bug/1640488
345 # The coalesce is needed because $.data is None during heat validation
348 expression: coalesce($.data, []).first(null)
349 data: {get_attr: [{{role.name}}, hostname]}
352 expression: coalesce($.data, []).first(null)
353 data: {get_attr: [{{role.name}}, ip_address]}
355 {{role.name}}AllNodesValidationDeployment:
356 type: OS::Heat::StructuredDeployments
357 depends_on: {{role.name}}AllNodesDeployment
359 name: {{role.name}}AllNodesValidationDeployment
360 config: {get_resource: AllNodesValidationConfig}
361 servers: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
363 {{role.name}}IpListMap:
364 type: OS::TripleO::Network::Ports::NetIpListMap
366 ControlPlaneIpList: {get_attr: [{{role.name}}, ip_address]}
367 ExternalIpList: {get_attr: [{{role.name}}, external_ip_address]}
368 InternalApiIpList: {get_attr: [{{role.name}}, internal_api_ip_address]}
369 StorageIpList: {get_attr: [{{role.name}}, storage_ip_address]}
370 StorageMgmtIpList: {get_attr: [{{role.name}}, storage_mgmt_ip_address]}
371 TenantIpList: {get_attr: [{{role.name}}, tenant_ip_address]}
372 ManagementIpList: {get_attr: [{{role.name}}, management_ip_address]}
373 EnabledServices: {get_attr: [{{role.name}}ServiceNames, value]}
374 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
375 ServiceHostnameList: {get_attr: [{{role.name}}, hostname]}
376 NetworkHostnameMap: {get_attr: [{{role.name}}NetworkHostnameMap, value]}
378 {{role.name}}NetworkHostnameMap:
379 type: OS::Heat::Value
383 # Note (shardy) this somewhat complex yaql may be replaced
384 # with a map_deep_merge function in ocata. It merges the
385 # list of maps, but appends to colliding lists so we can
386 # create a map of lists for all nodes for each network
388 expression: dict($.data.where($ != null).flatten().selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
390 - {get_attr: [{{role.name}}, hostname_map]}
393 type: OS::Heat::ResourceGroup
397 max_batch_size: {get_param: NodeCreateBatchSize}
399 count: {get_param: {{role.name}}Count}
400 removal_policies: {get_param: {{role.name}}RemovalPolicies}
402 type: OS::TripleO::{{role.name}}
404 CloudDomain: {get_param: CloudDomain}
405 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map]}
406 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
409 template: {get_param: {{role.name}}HostnameFormat}
411 '%stackname%': {get_param: 'OS::stack_name'}
413 {% if role.name != 'Compute' %}
414 {{role.name}}SchedulerHints: {get_param: {{role.name}}SchedulerHints}
416 NovaComputeSchedulerHints: {get_param: NovaComputeSchedulerHints}
418 ServiceConfigSettings:
420 - get_attr: [{{role.name}}ServiceChainRoleData, value, config_settings]
422 - get_attr: [{{r.name}}ServiceChain, role_data, global_config_settings]
424 # This next step combines two yaql passes:
425 # - The inner one does a deep merge on the service_config_settings for all roles
426 # - The outer one filters the map based on the services enabled for the role
427 # then merges the result into one map.
429 expression: let(root => $) -> $.data.map.items().where($[0] in coalesce($root.data.services, [])).select($[1]).reduce($1.mergeWith($2), {})
433 expression: $.data.where($ != null).reduce($1.mergeWith($2), {})
436 - get_attr: [{{r.name}}ServiceChain, role_data, service_config_settings]
438 services: {get_attr: [{{role.name}}ServiceNames, value]}
439 ServiceNames: {get_attr: [{{role.name}}ServiceNames, value]}
440 MonitoringSubscriptions: {get_attr: [{{role.name}}ServiceChainRoleData, value, monitoring_subscriptions]}
441 ServiceMetadataSettings: {get_attr: [{{role.name}}ServiceChainRoleData, value, service_metadata_settings]}
445 type: OS::TripleO::Hosts::SoftwareConfig
451 - add_vips_to_etc_hosts
452 - {get_attr: [VipHosts, value]}
455 {% for role in roles %}
458 - {get_attr: [{{role.name}}, hosts_entry]}
462 type: OS::TripleO::AllNodes::SoftwareConfig
464 cloud_name_external: {get_param: CloudName}
465 cloud_name_internal_api: {get_param: CloudNameInternal}
466 cloud_name_storage: {get_param: CloudNameStorage}
467 cloud_name_storage_mgmt: {get_param: CloudNameStorageManagement}
468 cloud_name_ctlplane: {get_param: CloudNameCtlplane}
472 {% for role in roles %}
473 - {get_attr: [{{role.name}}ServiceNames, value]}
478 $.data.groups.flatten()
481 {% for role in roles %}
482 - {get_attr: [{{role.name}}ServiceChainRoleData, value, logging_groups]}
487 $.data.sources.flatten()
490 {% for role in roles %}
491 - {get_attr: [{{role.name}}ServiceChainRoleData, value, logging_sources]}
493 controller_ips: {get_attr: [{{primary_role_name}}, ip_address]}
494 controller_names: {get_attr: [{{primary_role_name}}, hostname]}
496 # Note (shardy) this somewhat complex yaql may be replaced
497 # with a map_deep_merge function in ocata. It merges the
498 # list of maps, but appends to colliding lists when a service
499 # is deployed on more than one role
501 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
504 {% for role in roles %}
505 - {get_attr: [{{role.name}}IpListMap, service_ips]}
509 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
512 {% for role in roles %}
513 - {get_attr: [{{role.name}}IpListMap, service_hostnames]}
515 short_service_node_names:
517 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten()]))
520 {% for role in roles %}
521 - {get_attr: [{{role.name}}IpListMap, short_service_hostnames]}
523 short_service_bootstrap_node:
525 expression: dict($.data.l.where($ != null).selectMany($.items()).groupBy($[0], $[1], [$[0], $[1].flatten().first()]))
528 {% for role in roles %}
529 - {get_attr: [{{role.name}}IpListMap, short_service_bootstrap_hostnames]}
531 # FIXME(shardy): These require further work to move into service_ips
532 memcache_node_ips: {get_attr: [{{primary_role_name}}IpListMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, MemcachedNetwork]}]}
533 NetVipMap: {get_attr: [VipMap, net_ip_map]}
534 RedisVirtualIP: {get_attr: [RedisVirtualIP, ip_address]}
535 ServiceNetMap: {get_attr: [ServiceNetMap, service_net_map_lower]}
536 DeployIdentifier: {get_param: DeployIdentifier}
537 UpdateIdentifier: {get_param: UpdateIdentifier}
540 type: OS::Heat::RandomString
545 type: OS::Heat::RandomString
548 salt: {get_param: RabbitCookieSalt}
551 type: OS::TripleO::DefaultPasswords
553 DefaultMysqlRootPassword: {get_attr: [MysqlRootPassword, value]}
554 DefaultRabbitCookie: {get_attr: [RabbitCookie, value]}
555 DefaultHeatAuthEncryptionKey: {get_attr: [HeatAuthEncryptionKey, value]}
556 DefaultPcsdPassword: {get_attr: [PcsdPassword, value]}
557 DefaultHorizonSecret: {get_attr: [HorizonSecret, value]}
559 # creates the network architecture
561 type: OS::TripleO::Network
564 type: OS::TripleO::Network::Ports::ControlPlaneVipPort
567 name: control_virtual_ip
568 network: {get_param: NeutronControlPlaneID}
569 fixed_ips: {get_param: ControlFixedIPs}
570 replacement_policy: AUTO
574 type: OS::TripleO::Network::Ports::RedisVipPort
576 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
577 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
578 PortName: redis_virtual_ip
579 NetworkName: {get_attr: [ServiceNetMap, service_net_map, RedisNetwork]}
581 FixedIPs: {get_param: RedisVirtualFixedIPs}
583 # The public VIP is on the External net, falls back to ctlplane
586 type: OS::TripleO::Network::Ports::ExternalVipPort
588 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
589 ControlPlaneNetwork: {get_param: NeutronControlPlaneID}
590 PortName: public_virtual_ip
591 FixedIPs: {get_param: PublicVirtualFixedIPs}
593 InternalApiVirtualIP:
595 type: OS::TripleO::Network::Ports::InternalApiVipPort
597 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
598 PortName: internal_api_virtual_ip
599 FixedIPs: {get_param: InternalApiVirtualFixedIPs}
603 type: OS::TripleO::Network::Ports::StorageVipPort
605 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
606 PortName: storage_virtual_ip
607 FixedIPs: {get_param: StorageVirtualFixedIPs}
609 StorageMgmtVirtualIP:
611 type: OS::TripleO::Network::Ports::StorageMgmtVipPort
613 ControlPlaneIP: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
614 PortName: storage_management_virtual_ip
615 FixedIPs: {get_param: StorageMgmtVirtualFixedIPs}
618 type: OS::TripleO::Network::Ports::NetVipMap
620 ControlPlaneIp: {get_attr: [ControlVirtualIP, fixed_ips, 0, ip_address]}
621 ExternalIp: {get_attr: [PublicVirtualIP, ip_address]}
622 ExternalIpUri: {get_attr: [PublicVirtualIP, ip_address_uri]}
623 InternalApiIp: {get_attr: [InternalApiVirtualIP, ip_address]}
624 InternalApiIpUri: {get_attr: [InternalApiVirtualIP, ip_address_uri]}
625 StorageIp: {get_attr: [StorageVirtualIP, ip_address]}
626 StorageIpUri: {get_attr: [StorageVirtualIP, ip_address_uri]}
627 StorageMgmtIp: {get_attr: [StorageMgmtVirtualIP, ip_address]}
628 StorageMgmtIpUri: {get_attr: [StorageMgmtVirtualIP, ip_address_uri]}
629 # No tenant or management VIP required
631 # All Nodes Validations
632 AllNodesValidationConfig:
633 type: OS::TripleO::AllNodes::Validation
639 expression: coalesce($.data, []).first(null)
640 data: {get_attr: [{{primary_role_name}}, external_ip_address]}
642 expression: coalesce($.data, []).first(null)
643 data: {get_attr: [{{primary_role_name}}, internal_api_ip_address]}
645 expression: coalesce($.data, []).first(null)
646 data: {get_attr: [{{primary_role_name}}, storage_ip_address]}
648 expression: coalesce($.data, []).first(null)
649 data: {get_attr: [{{primary_role_name}}, storage_mgmt_ip_address]}
651 expression: coalesce($.data, []).first(null)
652 data: {get_attr: [{{primary_role_name}}, tenant_ip_address]}
654 expression: coalesce($.data, []).first(null)
655 data: {get_attr: [{{primary_role_name}}, management_ip_address]}
658 type: OS::TripleO::Tasks::UpdateWorkflow
660 {% for role in roles %}
661 - {{role.name}}AllNodesDeployment
665 {% for role in roles %}
666 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
669 deploy_identifier: {get_param: DeployIdentifier}
670 update_identifier: {get_param: UpdateIdentifier}
672 # Optional ExtraConfig for all nodes - all roles are passed in here, but
673 # the nested template may configure each role differently (or not at all)
675 type: OS::TripleO::AllNodesExtraConfig
678 {% for role in roles %}
679 - {{role.name}}AllNodesValidationDeployment
683 {% for role in roles %}
684 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
687 # Post deployment steps for all roles
689 type: OS::TripleO::PostDeploySteps
691 - AllNodesExtraConfig
692 {% for role in roles %}
693 - {{role.name}}AllNodesDeployment
697 {% for role in roles %}
698 {{role.name}}: {get_attr: [{{role.name}}, attributes, nova_server_resource]}
700 EndpointMap: {get_attr: [EndpointMap, endpoint_map]}
702 {% for role in roles %}
703 {{role.name}}: {get_attr: [{{role.name}}ServiceChainRoleData, value]}
708 description: Asserts that the keystone endpoints have been provisioned.
711 description: URL for the Overcloud Keystone service
712 value: {get_attr: [EndpointMapData, value, KeystonePublic, uri]}
714 description: Keystone Admin VIP endpoint
715 value: {get_attr: [VipMap, net_ip_map, {get_attr: [ServiceNetMap, service_net_map, KeystoneAdminApiNetwork]}]}
718 Mapping of the resources with the needed info for their endpoints.
719 This includes the protocol used, the IP, port and also a full
720 representation of the URI.
721 value: {get_attr: [EndpointMapData, value]}
724 The content that should be appended to your /etc/hosts if you want to get
725 hostname-based access to the deployed nodes (useful for testing without
730 - - {get_attr: [hostsConfig, hosts_entries]}
731 - - {get_attr: [VipHosts, value]}
733 description: The services enabled on each role
735 {% for role in roles %}
736 {{role.name}}: {get_attr: [{{role.name}}ServiceNames, value]}
739 description: The configuration data associated with each role
741 {% for role in roles %}
742 {{role.name}}: {get_attr: [{{role.name}}ServiceChainRoleData, value]}
745 description: Mapping of each network to a list of IPs for each role
747 {% for role in roles %}
748 {{role.name}}: {get_attr: [{{role.name}}IpListMap, net_ip_map]}
751 description: Mapping of each network to a list of hostnames for each role
753 {% for role in roles %}
754 {{role.name}}: {get_attr: [{{role.name}}NetworkHostnameMap, value]}