1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
heat_template_version: pike
parameters:
ControlPlaneIpList:
default: []
type: comma_delimited_list
{%- for network in networks %}
{{network.name}}IpList:
default: []
type: comma_delimited_list
{%- endfor %}
EnabledServices:
default: []
type: comma_delimited_list
ServiceNetMap:
default: {}
type: json
ServiceHostnameList:
default: []
type: comma_delimited_list
NetworkHostnameMap:
default: []
type: json
{%- for network in networks %}
{{network.name}}NetName:
default: {{network.name_lower}}
description: The name of the {{network.name_lower}} network.
type: string
{%- endfor %}
resources:
# This adds the extra "services" on for keystone
# so that keystone_admin_api_network and
# keystone_public_api_network point to the correct
# network on the nodes running the "keystone" service
EnabledServicesValue:
type: OS::Heat::Value
properties:
type: comma_delimited_list
value:
yaql:
expression: let(root => $) -> $.data.extra_services.items().where($[0] in $root.data.enabled_services).select($[1]).flatten() + $root.data.enabled_services
data:
enabled_services: {get_param: EnabledServices}
extra_services:
# If anything other than keystone needs this
# then we should add an extra_networks interface
# to the service templates role_data but for
# now we hard-code the keystone special case
keystone:
- keystone_admin_api
- keystone_public_api
NetIpMapValue:
type: OS::Heat::Value
properties:
type: json
value:
map_replace:
- ctlplane: {get_param: ControlPlaneIpList}
{%- for network in networks %}
{{network.name_lower}}: {get_param: {{network.name}}IpList}
{%- endfor %}
- keys:
{%- for network in networks %}
{{network.name_lower}}: {get_param: {{network.name}}NetName}
{%- endfor %}
outputs:
net_ip_map:
description: >
A Hash containing a mapping of network names to assigned lists
of IP addresses.
value: {get_attr: [NetIpMapValue, value]}
service_ips:
description: >
Map of enabled services to a list of their IP addresses
value:
yaql:
# This filters any entries where the value hasn't been substituted for
# a list, e.g it's still $service_network. This happens when there is
# no network defined for the service in the ServiceNetMap, which is OK
# as not all services have to be bound to a network, so we filter them
expression: dict($.data.map.items().where(not isString($[1])))
data:
map:
map_replace:
- map_replace:
- map_merge:
repeat:
template:
SERVICE_node_ips: SERVICE_network
for_each:
SERVICE: {get_attr: [EnabledServicesValue, value]}
- values: {get_param: ServiceNetMap}
- values: {get_attr: [NetIpMapValue, value]}
ctlplane_service_ips:
description: >
Map of enabled services to a list of their ctlplane IP addresses
value:
yaql:
expression: dict($.data.map.items().where(len($[1]) > 0))
data:
map:
map_merge:
repeat:
template:
SERVICE_ctlplane_node_ips: {get_param: ControlPlaneIpList}
for_each:
SERVICE: {get_attr: [EnabledServicesValue, value]}
service_hostnames:
description: >
Map of enabled services to a list of hostnames where they're running
value:
map_replace:
- yaql:
# This filters any entries where the value hasn't been substituted for
# a list, e.g it's still $service_network. This happens when there is
# no network defined for the service in the ServiceNetMap, which is OK
# as not all services have to be bound to a network, so we filter them
expression: dict($.data.map.items().where(not $[1].endsWith("_network")))
data:
map:
map_replace:
- map_merge:
repeat:
template:
SERVICE_node_names: SERVICE_network
for_each:
SERVICE: {get_attr: [EnabledServicesValue, value]}
- values: {get_param: ServiceNetMap}
- values: {get_param: NetworkHostnameMap}
short_service_hostnames:
description: >
Map of enabled services to a list of hostnames where they're running regardless of the network
value:
yaql:
# If ServiceHostnameList is empty the role is deployed with zero nodes
# therefore we don't want to add any *_node_names to the map
expression: dict($.data.map.items().where(len($[1]) > 0))
data:
map:
map_merge:
repeat:
template:
SERVICE_short_node_names: {get_param: ServiceHostnameList}
for_each:
SERVICE: {get_attr: [EnabledServicesValue, value]}
short_service_bootstrap_hostnames:
description: >
Map of enabled services to a list of hostnames where they're running regardless of the network
Used for bootstrap purposes
value:
yaql:
# If ServiceHostnameList is empty the role is deployed with zero nodes
# therefore we don't want to add any *_node_names to the map
expression: dict($.data.map.items().where(len($[1]) > 0))
data:
map:
map_merge:
repeat:
template:
SERVICE_short_bootstrap_node_name: {get_param: ServiceHostnameList}
for_each:
SERVICE: {get_attr: [EnabledServicesValue, value]}
|