101c5263ba8afea4ff38632815510d16278bb51a
[oom/offline-installer.git] / tools / cicdansible / heat / installer.yaml
1 #This is the environment heat template, compatible with openstack ocata.
2 heat_template_version: 2017-02-24
3 description: "Heat template for deploying onap env"
4 parameters:
5   auth_key:
6     label: "Auth public key"
7     description: "The public key used to authenticate to instances"
8     type: string
9   node_flavor_name:
10     label: "name of node flavor"
11     description: "The name of the flavor used to create kubernetes nodes"
12     type: string
13     constraints:
14       - custom_constraint: nova.flavor
15         description: "need to specify a valid flavor"
16   infra_flavor_name:
17     label: "name of infra flavor"
18     description: "flavor used to create infra instance"
19     type: string
20     constraints:
21       - custom_constraint: nova.flavor
22         description: "need to specify a valid flavor"
23   installer_flavor_name:
24     label: "name of installer flavor"
25     description: "flavor used to create installer instance"
26     type: string
27     constraints:
28       - custom_constraint: nova.flavor
29         description: "need to specify a valid flavor"
30   image_name:
31     label: "image name"
32     description: "name of the image from which to create all instances, should be rhel/centos 7.9 image"
33     type: string
34     constraints:
35       - custom_constraint: glance.image
36         description: "must specify a valid image name"
37   subnet_cidr:
38     label: "private subnet cidr"
39     description: "Cidr of a private subnet instances will be connected to"
40     type: string
41     constraints:
42       - custom_constraint: net_cidr
43   subnet_range_start:
44     label: "subnet dhcp allocation range start"
45     description: "Start of range of dhcp allocatable ips on private subnet"
46     type: string
47     constraints:
48       - custom_constraint: ip_addr
49   subnet_range_end:
50     label: "end of subnet dhcp allocation range"
51     description: "End of private subnet's dhcp allocation range"
52     type: string
53     constraints:
54       - custom_constraint: ip_addr
55   router_addr:
56     label: "ip address of router"
57     description: "IP address of the router allowing access to other networks incl. company network"
58     type: string
59     constraints:
60       - custom_constraint: ip_addr
61   dns_nameservers:
62     label: "dns resolvers"
63     description: "List of dns resolvers"
64     type: comma_delimited_list
65   public_network_name:
66     label: "name of the public network"
67     description: "Name of the public, internet facing network, also allowing access to company internal hosts"
68     type: string
69     constraints:
70       - custom_constraint: neutron.network
71         description: "Must specify a valid network name or id"
72   external_subnet_cidr:
73     label: "external subnet cidr"
74     description: "The CIDR of the external subnet, that should be accessible from instances, even when internet access is cut. Putting 0.0.0.0/0 here means access to internet."
75     type: string
76     constraints:
77       - custom_constraint: net_cidr
78   installer_ip:
79     label: "floating ip of the installer"
80     description: "a pre-allocated floating ip that will be associated with the installer instance"
81     type: string
82   infra_ip:
83     label: "floating ip of the infra"
84     description: "a pre-allocated floating ip that will be associated with the infrastructure instance"
85     type: string
86   node_ip:
87     label: "floating ip of the first node"
88     description: "a pre-allocated floating ip that will be associated with the first kubernetes node and allow accessing onap"
89     type: string
90   num_nodes:
91     label: "num nodes"
92     description: "the number of kubernetes nodes to create, min 1"
93     type: number
94     constraints:
95       - range: { min: 1 }
96         description: "must be a positive number"
97   use_volume_for_nfs:
98     type: boolean
99     label: "use volume for nfs storage"
100     description: "Indicates whether a cinder volume should be used for nfs storage or not. If not checked, the nfs would be stored in the root disk"
101   demo_network:
102     label: "demo net id"
103     type: string
104     description: "specifies id of network used for demo usecases"
105     default: ""
106   docker_storage_size:
107     label: "nodes' docker storage size"
108     type: number
109     description: "Size of the volume for the docker storage on nodes"
110 conditions:
111   #Condition for nfs volume usage.
112   use_volume_for_nfs: { get_param: use_volume_for_nfs }
113 resources:
114   # Security group used to secure access to instances.
115   secgroup:
116     type: OS::Neutron::SecurityGroup
117     properties:
118       rules:
119         # Egress rule allowing access to external_subnet_cidr.
120         - direction: egress
121           ethertype: IPv4
122           remote_ip_prefix: { get_param: external_subnet_cidr }
123         # Ingress rule, allowing also inbound access by external network.
124         - direction: ingress
125           ethertype: IPv4
126           remote_ip_prefix: { get_param: external_subnet_cidr }
127         # Allow outbound communication with the internal subnet.
128         - direction: egress
129           ethertype: IPv4
130           remote_ip_prefix: { get_param: subnet_cidr }
131         # Allow inbound communication from internal network.
132         - direction: ingress
133           ethertype: IPv4
134           remote_ip_prefix: { get_param: subnet_cidr }
135         # Allow outbound access to 169.254.0.0/16, mainly for metadata. We do not need inbound.
136         - direction: egress
137           ethertype: IPv4
138           remote_ip_prefix: 169.254.0.0/16
139   #A network that our test environment will be connected to.
140   privnet:
141     type: OS::Neutron::Net
142   #Subnet that instances will live in.
143   privsubnet:
144     type: OS::Neutron::Subnet
145     properties:
146       network: { get_resource: privnet }
147       cidr: { get_param: subnet_cidr }
148       allocation_pools:
149         - { start: { get_param: subnet_range_start }, end: { get_param: subnet_range_end } }
150       gateway_ip: { get_param: router_addr }
151       dns_nameservers: { get_param: dns_nameservers }
152       ip_version: 4
153   #A port connected to the private network, taken by router.
154   routerport:
155     type: OS::Neutron::Port
156     properties:
157       network: { get_resource: privnet }
158       fixed_ips:
159         - { subnet: { get_resource: privsubnet }, ip_address: { get_param: router_addr } }
160       security_groups: [{ get_resource: secgroup }]
161   #This is a router, routing between us and the internet.
162   #It has an external gateway to public network.
163   router:
164     type: OS::Neutron::Router
165     properties:
166       external_gateway_info:
167         network: { get_param: public_network_name }
168   #This is a router interface connecting it to our private subnet's router port.
169   routercon:
170     type: OS::Neutron::RouterInterface
171     properties:
172       router: { get_resource: router }
173       port: { get_resource: routerport }
174
175   #Key used to authenticate to instances as root.
176   key:
177     type: OS::Nova::KeyPair
178     properties:
179       name: { get_param: "OS::stack_name" }
180       public_key: { get_param: auth_key }
181   #Handle to signal about starting up of instances.
182   instance_wait_handle:
183     type: OS::Heat::WaitConditionHandle
184   #Monitor waiting for all instances to start.
185   instance_wait:
186     type: OS::Heat::WaitCondition
187     properties:
188       handle: { get_resource: instance_wait_handle }
189       timeout: 1200
190       count:
191         yaql:
192           data: { num_nodes: { get_param: num_nodes } }
193           #This is number of all nodes + 2 (infra instance and installer)
194           expression: "$.data.num_nodes + 2"
195   #Affinity Policy - nodes spread onto as many physical machines as possible (aka. .anti-affinity.).
196   anti_affinity_group:
197    type: OS::Nova::ServerGroup
198    properties:
199      name: k8s nodes on separate computes
200      policies:
201       - anti-affinity
202   #Resource group to deploy n nodes using node template for each, each node numbered starting from 0.
203   nodes:
204     type: OS::Heat::ResourceGroup
205     properties:
206       count: { get_param: num_nodes }
207       resource_def:
208         type: node.yaml
209         properties:
210           nodenum: "%index%"
211           key_name: { get_resource: key }
212           image_name: { get_param: image_name }
213           network: { get_resource: privnet }
214           subnet: { get_resource: privsubnet }
215           flavor_name: { get_param: node_flavor_name }
216           notify_command: { get_attr: ["instance_wait_handle", "curl_cli"] }
217           security_group: { get_resource: secgroup }
218           demo_network: { get_param: demo_network }
219           docker_storage_size: { get_param: docker_storage_size }
220           scheduler_hints:
221             group: { get_resource: anti_affinity_group }
222     depends_on: [routercon, instance_wait_handle]
223   #Nfs storage volume for first node.
224   nfs_storage:
225     type: OS::Cinder::Volume
226     condition: use_volume_for_nfs
227     properties:
228       name: nfs_storage
229       size: 50
230   #Attachment of volume to first node.
231   nfs_storage_attachment:
232     type: OS::Cinder::VolumeAttachment
233     condition: use_volume_for_nfs
234     properties:
235       instance_uuid: { get_attr: [nodes, "resource.0"] }
236       volume_id: { get_resource: nfs_storage }
237   #Floating ip association for node (first only).
238   node_fip_assoc:
239     type: OS::Neutron::FloatingIPAssociation
240     properties:
241       floatingip_id: { get_param: node_ip }
242       port_id: { get_attr: ["nodes", "resource.0.port_id"] }
243   #Openstack volume used for storing resources.
244   resources_storage:
245     type: "OS::Cinder::Volume"
246     properties:
247       name: "resources_storage"
248       size: 120
249   #Instance representing infrastructure instance, created using subtemplate.
250   infra:
251     type: "instance.yaml"
252     properties:
253       instance_name: infra
254       network: { get_resource: privnet }
255       subnet: { get_resource: privsubnet }
256       key_name: { get_resource: key }
257       flavor_name: { get_param: infra_flavor_name }
258       image_name: { get_param: image_name }
259       notify_command: { get_attr: ["instance_wait_handle", "curl_cli"] }
260       security_group: { get_resource: secgroup }
261       scheduler_hints: {}
262       demo_network: { get_param: demo_network }
263     depends_on: [instance_wait_handle]
264   #Volume attachment for infra node.
265   resources_storage_attachment:
266     type: OS::Cinder::VolumeAttachment
267     properties:
268       volume_id: { get_resource: resources_storage }
269       instance_uuid: { get_resource: infra }
270   #Floating ip association for infra.
271   infra_fip_assoc:
272     type: OS::Neutron::FloatingIPAssociation
273     properties:
274       floatingip_id: { get_param: infra_ip }
275       port_id: { get_attr: ["infra", "port_id"] }
276   #Small installer vm having access to other instances, used to install onap.
277   installer:
278     type: "instance.yaml"
279     properties:
280       instance_name: installer
281       image_name: { get_param: image_name }
282       flavor_name: { get_param: installer_flavor_name }
283       key_name: { get_resource: key }
284       network: { get_resource: privnet }
285       subnet: { get_resource: privsubnet }
286       notify_command: { get_attr: ["instance_wait_handle", "curl_cli"] }
287       security_group: { get_resource: secgroup }
288       scheduler_hints: {}
289     depends_on: instance_wait_handle
290   #Floating ip for installer.
291   installer_fip_assoc:
292     type: OS::Neutron::FloatingIPAssociation
293     properties:
294       floatingip_id: { get_param: installer_ip }
295       port_id: { get_attr: [installer, port_id] }
296   #Map of node volumes, taken from volumes output param.
297   node_volumes:
298     type: OS::Heat::Value
299     properties:
300       type: json
301       #We need yaql transformation to be done on the volume map.
302       value:
303         yaql:
304           data:
305             #This is a map of node number to value of "volumes" attribute, that contains
306             #a list of volumes written as pairs [volumeid, mountpoint].
307             volumes: { get_attr: [nodes, attributes, volumes] }
308           #We need yaql expressions to transform node numbers to node names in the form "node0" and similar.
309           #However we don't need anything more complicated.
310           expression: "$.data.volumes?.items()?.toDict('node'+str($[0]), $[1])"
311   #List of infra specific volumes (not a map as above).
312   infra_volumes:
313     type: OS::Heat::Value
314     properties:
315       value:
316         - [{ get_resource: resources_storage }, "/opt/onap"]
317   #Contains node0 specific volume list.
318   node0_volumes:
319     type: OS::Heat::Value
320     properties:
321       #Note that it returns an empty list if nfs volume is disabled.
322       value:
323         if:
324           - use_volume_for_nfs
325           - - [{ get_resource: nfs_storage }, "/dockerdata-nfs"]
326           - []
327 #Output values
328 outputs:
329   network_name:
330     value: {get_attr: [privnet, name] }
331     description: "Name of private network"
332   network_id:
333     value: { get_resource: privnet }
334     description: "ID of private network"
335   subnet_id:
336     value: { get_resource: privsubnet }
337     description: "ID of private subnet"
338   installer_ip:
339     value: { get_attr: [installer, ip] }
340     description: "Internal ip of installer instance"
341   infra_ip:
342     value: { get_attr: [infra, ip] }
343     description: "Internal ip of infra instance"
344   node_ips:
345     value: { get_attr: [nodes, ip] }
346     description: "Serialized json list of node internal ips starting at node0"
347   volumes:
348     description: "map of volumes per each instance"
349     value:
350       #Can do deep merging only with yaql.
351       yaql:
352         data:
353           node_volumes: { get_attr: [node_volumes, value]}
354           infra_volumes: { infra: { get_attr: [infra_volumes, value] }}
355           node0_volumes: {node0: { get_attr: [node0_volumes, value] }}
356         expression: "$.data.node_volumes?.mergeWith($.data.infra_volumes)?.mergeWith($.data.node0_volumes)"