VNFRQTS - Dynamic Release Notes
[vnfrqts/requirements.git] / docs / Chapter5 / Heat / ONAP Heat Template Constructs.rst
1 .. Licensed under a Creative Commons Attribution 4.0 International License.
2 .. http://creativecommons.org/licenses/by/4.0
3 .. Copyright 2017 AT&T Intellectual Property.  All rights reserved.
4
5 .. _ONAP Heat Heat Template Constructs:
6
7 ONAP Heat Heat Template Constructs
8 --------------------------------------
9
10 .. _Nested Heat Templates:
11
12 Nested Heat Templates
13 ^^^^^^^^^^^^^^^^^^^^^^^^^
14
15 ONAP supports nested Heat templates per the OpenStack specifications.
16 Nested templates may be suitable for larger VNFs that contain many
17 repeated instances of the same VM type(s). A common usage pattern is to
18 create a nested template for each {vm-type} along with its supporting
19 resources. The VNF module may then reference these component templates
20 either statically by repeated definition or dynamically by using the
21 resource OS::Heat::ResourceGroup.
22
23 Nested Heat Template Requirements
24 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25
26 ONAP supports nested Heat Orchestration Templates.
27
28 As stated in Requirements :need:`R-36582`, :need:`R-56721`, and
29 :need:`R-30395`, a Base Module, Incremental Module, and Cinder Volume
30 Module may use nested heat.
31
32 .. req::
33     :id: R-00228
34     :target: VNF
35     :keyword: MAY
36
37     A VNF's Heat Orchestration Template **MAY**
38     reference the nested heat statically by repeated definition.
39
40 .. req::
41     :id: R-01101
42     :target: VNF
43     :keyword: MAY
44     :updated: casablanca
45
46     A VNF's Heat Orchestration Template **MAY**
47     reference the nested heat dynamically using the resource
48     ``OS::Heat::ResourceGroup``.
49
50 .. req::
51     :id: R-60011
52     :target: VNF
53     :keyword: MUST
54     :validation_mode: static
55     :updated: casablanca
56
57     A VNF's Heat Orchestration Template **MUST** have no more than
58     two levels of nesting.
59
60 .. req::
61     :id: R-70112
62     :target: VNF
63     :keyword: MUST
64     :validation_mode: static
65     :introduced: casablanca
66
67     A VNF's Heat Orchestration Template **MUST** reference a Nested YAML
68     file by name. The use of ``resource_registry`` in the VNF's Heat
69     Orchestration Templates Environment File **MUST NOT** be used.
70
71 Two levels of nesting is defined as follows:  A base module, incremental
72 module, or cinder volume module references a nested heat file either
73 statically or by using the resource ``OS::Heat::ResourceGroup``.
74 The referenced YAML heat file is the first level of nested heat.
75 If first level nested YAML file references a nested heat file, that file is
76 the second level of nested heat.
77
78 As stated in requirement :need:`R-99646`, a VNF's YAML files
79 (i.e, Heat Orchestration Template files and Nested files) **MUST**
80 have a unique name in the scope of the VNF.
81
82 .. req::
83     :id: R-52530
84     :target: VNF
85     :keyword: MUST
86     :validation_mode: static
87     :updated: casablanca
88
89     A VNF's Heat Orchestration Template's Nested YAML file
90     **MUST** be in the same directory hierarchy as the VNF's Heat
91     Orchestration Templates.
92
93 .. req::
94     :id: R-90022
95     :target: VNF
96     :keyword: MAY
97
98     A VNF's Nested YAML file **MAY** be invoked more than
99     once by a VNF's Heat Orchestration Template.
100
101 .. req::
102     :id: R-04344
103     :target: VNF
104     :keyword: MAY
105
106     A VNF's Nested YAML file **MAY** be invoked by more than one of
107     a VNF's Heat Orchestration Templates (when the VNF is composed of two
108     or more Heat Orchestration Templates).
109
110 Note that as stated in requirement :need:`R-00011`, a VNF's Heat Orchestration
111 Template's Nested YAML file's parameter's **MUST NOT** have a parameter
112 constraint defined.
113
114 .. req::
115     :id: R-11041
116     :target: VNF
117     :keyword: MUST
118     :validation_mode: static
119     :updated: casablanca
120
121     All parameters defined in a VNFs Nested YAML file
122     **MUST** be passed in as properties of the resource calling
123     the nested yaml file.
124
125 Note that:
126
127 As stated in Requirement :need:`R-44491`, if a VNF's Heat Orchestration
128 Template's ``OS::Nova::Server`` Resource ``metadata`` map value parameter
129 ``vnf_id`` is passed into a Nested YAML file, the parameter name
130 ``vnf_id`` **MUST NOT** change.
131
132 As stated in Requirement :need:`R-86237`, if a VNF's Heat Orchestration
133 Template's ``OS::Nova::Server`` Resource ``metadata`` map value parameter
134 ``vf_module_id`` is passed into a Nested YAML file, the parameter name
135 ``vf_module_id`` **MUST NOT** change.
136
137 As stated in Requirement :need:`R-16576`, if a VNF's Heat Orchestration
138 Template's ``OS::Nova::Server`` Resource ``metadata`` map value parameter
139 ``vnf_name`` is passed into a Nested YAML file, the parameter name
140 ``vnf_name`` **MUST NOT** change.
141
142 As stated in Requirement :need:`R-49177`, if a VNF's Heat Orchestration
143 Template's ``OS::Nova::Server`` Resource ``metadata`` map value parameter
144 ``vf_module_name`` is passed into a Nested YAML file, the parameter name
145 ``vf_module_name`` **MUST NOT** change.
146
147 As stated in Requirement :need:`R-70757`, if a VNF's Heat Orchestration
148 Template's ``OS::Nova::Server`` Resource ``metadata`` map value parameter
149 ``vm_role`` is passed into a Nested YAML file, the parameter name
150 ``vm_role`` **MUST NOT** change.
151
152 As stated in Requirement :need:`R-22441`, if a VNF's Heat Orchestration
153 Template's ``OS::Nova::Server`` Resource ``metadata`` map value parameter
154 ``vf_module_index`` is passed into a Nested YAML file, the parameter
155 name ``vf_module_index`` **MUST NOT** change.
156
157 As stated in Requirement :need:`R-75202`, if a VNF's Heat Orchestration
158 Template's ``OS::Nova::Server`` Resource ``metadata`` map value parameter
159 ``workload_context`` is passed into a Nested YAML file, the parameter
160 name ``workload_context`` **MUST NOT** change.
161
162 As stated in Requirement :need:`R-62954`, if a VNF's Heat Orchestration
163 Template's ``OS::Nova::Server`` Resource ``metadata`` map value parameter
164 ``environment_context`` is passed into a Nested YAML file, the parameter
165 name ``environment_context`` **MUST NOT** change.
166
167 With nested templates, outputs are required to expose any resource
168 properties of the child templates to the parent template. Those would
169 not explicitly be declared as parameters but simply referenced as
170 ``get_attribute`` targets against the "parent" resource.
171
172 A parameter declared in the outputs: section of a nested template can
173 be accessed from the parent template as an attribute (i.e., via
174 ``get_attr``) of the "pseudo resource" whose type is in the nested
175 template. In the case of a ``OS::Heat::ResourceGroup``, an output will be
176 an attribute of the ``OS::Heat::ResourceGroup`` itself, and will be an
177 array from the perspective of the parent template.
178
179 .. req::
180     :id: R-17528
181     :target: VNF
182     :keyword: MUST
183     :validation_mode: static
184     :updated: casablanca
185
186     A VNF's Heat Orchestration Template's first level Nested YAML file
187     **MUST NOT** contain more than one ``OS::Nova::Server`` resource.
188     A VNF's Heat Orchestration Template's second level Nested YAML file
189     **MUST NOT** contain an ``OS::Nova::Server`` resource.
190
191 Nested Heat Template Example: Static
192 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
193
194 incremental.yaml
195
196 .. code-block:: yaml
197
198   resources:
199     dns_server_0:
200       type: nested.yaml
201       properties:
202         dns_image_name: { get_param: dns_image_name }
203         dns_flavor_name: { get_param: dns_flavor_name }
204         availability_zone: { get_param: availability_zone_0 }
205         security_group: { get_param: DNS_shared_sec_grp_id }
206         oam_net_id: { get_param: oam_protected_net_id }
207         dns_oam_ip: { get_param: dns_oam_ip_0 }
208         dns_name: { get_param: dns_name_0 }
209         vnf_name: { get_param: vnf_name }
210         vnf_id: { get_param: vnf_id }
211         vf_module_id: {get_param: vf_module_id}
212
213     dns_server_1:
214       type: nested.yaml
215       properties:
216         dns_image_name: { get_param: dns_image_name }
217         dns_flavor_name: { get_param: dns_flavor_name }
218         availability_zone: { get_param: availability_zone_1 }
219         security_group: { get_param: DNS_shared_sec_grp_id }
220         oam_net_id: { get_param: oam_protected_net_id }
221         dns_oam_ip: { get_param: dns_oam_ip_1 }
222         dns_name: { get_param: dns_name_1 }
223         vnf_name: { get_param: vnf_name }
224         vnf_id: { get_param: vnf_id }
225         vf_module_id: {get_param: vf_module_id}
226
227 nested.yaml
228
229 .. code-block:: yaml
230
231   dns_oam_0_port:
232     type: OS::Neutron::Port
233     properties:
234       name:
235         str_replace:
236           template: VNF_NAME_dns_oam_port
237           params:
238             VNF_NAME: {get_param: vnf_name}
239       network: { get_param: oam_net_id }
240       fixed_ips: [{ "ip_address": { get_param: dns_oam_ip }}]
241       security_groups: [{ get_param: security_group }]
242
243   dns_servers:
244     type: OS::Nova::Server
245     properties:
246       name: { get_param: dns_names }
247       image: { get_param: dns_image_name }
248       flavor: { get_param: dns_flavor_name }
249       availability_zone: { get_param: availability_zone }
250       networks:
251       - port: { get_resource: dns_oam_0_port }
252       metadata:
253         vnf_id: { get_param: vnf_id }
254         vf_module_id: { get_param: vf_module_id }
255         vnf_name {get_param: vnf_name }
256
257 Use of Heat ResourceGroup
258 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
259
260 The OS::Heat::ResourceGroup is a useful Heat element for creating
261 multiple instances of a given resource or collection of resources.
262 Typically, it is used with a nested Heat template to create, for
263 example, a set of identical OS::Nova::Server resources plus their
264 related OS::Neutron::Port resources via a single resource in a master
265 template.
266
267 OS::Heat::ResourceGroup may be used to simplify the structure of a Heat
268 template that creates multiple instances of the same VM type.
269
270 However, there are important caveats to be aware of:
271
272 OS::Heat::ResourceGroup does not deal with structured parameters
273 (comma-delimited-list and json) as one might typically expect. In
274 particular, when using a list-based parameter, where each list element
275 corresponds to one instance of the ResourceGroup, it is not possible to
276 use the intrinsic "loop variable" %index% in the OS::Heat::ResourceGroup
277 definition.
278
279 For instance, the following is **not** valid Heat for
280 OS::Heat::ResourceGroup:
281
282 .. code-block:: yaml
283
284   type: OS::Heat::ResourceGroup
285   properties:
286       . . .
287       resource_def:
288         type: my_nested_vm_template.yaml
289         properties:
290           name: {get_param: [vm_name_list, "%index%"]}
291
292 Although this appears to use the nth entry of the vm_name_list list for
293 the nth element of the OS::Heat::ResourceGroup, it will in fact result
294 in a Heat exception. When parameters are provided as a list (one for
295 each element of a OS::Heat::ResourceGroup), you must pass the complete
296 parameter to the nested template along with the current index as
297 separate parameters.
298
299 Below is an example of an **acceptable** Heat Syntax for a
300 ResourceGroup:
301
302 .. code-block:: yaml
303
304   type: OS::Heat::ResourceGroup
305   properties:
306     . . .
307     resource_def:
308       type: my_nested_vm_template.yaml
309       properties:
310         names: {get_param: vm_name_list}
311         index: "%index%"
312
313 You can then reference within the nested template as:
314
315 { get_param: [names, {get_param: index} ] }
316
317 OS::Heat::ResourceGroup Property count
318 ++++++++++++++++++++++++++++++++++++++++
319
320
321 .. req::
322     :id: R-50011
323     :target: VNF
324     :keyword: MUST
325     :validation_mode: static
326     :updated: casablanca
327
328     A VNF's Heat Orchestration Template's ``OS::Heat::ResourceGroup``
329     property ``count`` **MUST** be enumerated in the VNF's
330     Heat Orchestration Template's Environment File and **MUST** be
331     assigned a value.
332
333 This is required for ONAP to build the TOSCA model for the VNF.
334
335 .. code-block:: yaml
336
337   type: OS::Heat::ResourceGroup
338   properties:
339     count: { get_param: count }
340     index_var: index
341     resource_def:
342       type: my_nested_vm_template.yaml
343       properties:
344         names: {get_param: vm_name_list}
345         index: index
346
347 Availability Zone and ResourceGroups
348 ++++++++++++++++++++++++++++++++++++++++
349
350 The resource OS::Heat::ResourceGroup and the property availability_zone
351 has been an "issue" with a few VNFs since ONAP only supports
352 availability_zone as a string parameter and not as a
353 comma_delimited_list. This makes it difficult to use a
354 OS::Heat::ResourceGroup to create Virtual Machines in more than one
355 availability zone.
356
357 There are numerous solutions to this issue. Below are two suggested
358 usage patterns.
359
360 **Option 1:** create a CDL in the OS::Heat::ResourceGroup. In the
361 resource type: OS::Heat::ResourceGroup, create a comma_delimited_list
362 availability_zones by using the intrinsic function list_join.
363
364 .. code-block:: yaml
365
366   <resource name>:
367     type: OS::Heat::ResourceGroup
368     properties:
369       count: { get_param: node_count }
370       index_var: index
371       resource_def:
372         type: nested.yaml
373         properties:
374           index: index
375           availability_zones: { list_join: [',', [ { get_param: availability_zone_0 }, { get_param: availability_zone_1 } ] ] }
376
377 In the nested heat
378
379 .. code-block:: yaml
380
381   parameters:
382     availability_zones:
383       type: comma_delimited_list
384       description:
385
386   resources:
387     servers:
388       type: OS::Nova::Server
389       properties:
390         name: { get_param: [ dns_names, get_param: index ] }
391         image: { get_param: dns_image_name }
392         flavor: { get_param: dns_flavor_name }
393         availability_zone: { get_param: [ availability_zones, get_param: index ] }
394
395 **Option 2:** Create a CDL by passing the availability zone parameter
396 into a nested heat template. An example is provided below.
397
398 base.yaml
399
400 .. code-block:: yaml
401
402   availability_zone_list:
403      type: az_list_generate.yaml
404      properties:
405        availability_zone_0: { get_param: availability_zone_0 }
406        availability_zone_1: { get_param: availability_zone_1 }
407
408     create_virtual_machines:
409       type: OS::Heat::ResourceGroup
410       properties:
411         count: { get_param: count }
412         index_var: $INDEX
413         resource_def:
414           type: nest_file.yaml
415           properties:
416             index: $INDEX
417             availability_zone_0 : { get_attr: [availability_zone_list, general_zones ] }
418             . . .
419
420 az_list_generate.yaml
421
422 .. code-block:: yaml
423
424   parameters:
425     availability_zone_0:
426       type: string
427       description: availability zone 0
428
429     availability_zone_1:
430       type: string
431       description: availability zone 1
432
433   outputs:
434
435     general_zones:
436       value: [
437         { get_param: availability_zone_0 },
438         { get_param: availability_zone_1 },
439         { get_param: availability_zone_0 },
440         { get_param: availability_zone_1 },
441         { get_param: availability_zone_0 },
442         { get_param: availability_zone_1 },
443   ]
444
445
446 Nested Heat Template Example: OS::Heat::ResourceGroup
447 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
448
449 In this example, ocgapp_volume.yml creates volumes using a
450 OS::Heat::ResourceGroup that uses nested heat by calling
451 ocgapp_nested_volume.yml. ocgapp_volume.yml has an outputs: parameter
452 ocgapp_volume_ids which is declared a input parameter of type: json in
453 ocgapp_volume.yml.
454
455
456 This is an example of requirement :need:`R-07443`, where
457 a VNF's Heat Orchestration Templates' Cinder Volume Module Output
458 Parameter's name and type **MUST** match the input parameter name and type
459 in the corresponding Base Module or Incremental Module unless the Output
460 Parameter is of the type ``comma_delimited_list``, then the corresponding
461 input parameter **MUST** be declared as type ``json``.
462
463 ocgapp_volume.yml
464
465 .. code-block:: yaml
466
467   heat_template_version: 2014-10-16
468
469   description: Template for the volumes
470
471   parameters:
472     vnf_name:
473       type: string
474       label: OCG VNF Name
475       description: OCG VNF Name
476     ocgapp_volume_size_0:
477       type: number
478       label: Cinder volume 1 size
479       description: the size of the Cinder volume
480       constraints:
481       - range: { min: 100, max: 400 }
482     ocgapp_volume_type_0:
483       type: string
484       label: app vm 1 volume type
485       description: the name of the target volume backend for the first OCG APP
486     volume_count:
487       type: number
488       label: volume count
489       description: number of volumes needed
490
491   resources:
492     ocgapp_volume_resource_group:
493       type: OS::Heat::ResourceGroup
494       properties:
495         count: {get_param: volume_count}
496         index_var: index
497         resource_def:
498           type: ocgapp_nested_volume.yml
499           properties:
500             index: index
501             size: {get_param: ocgapp_volume_size_0}
502             volume_type: {get_param: ocgapp_volume_type_0}
503             vnf_name: {get_param: vnf_name}
504
505   outputs:
506     ocgapp_volume_ids:
507     description: ocgapp volume ids
508     value: {get_attr: [ocgapp_volume_resource_group, ocgapp_volume_id_0]}
509
510 ocgapp_nested_volume.yml
511
512 .. code-block:: yaml
513
514  heat_template_version: 2014-10-16
515
516  description: nested heat
517
518  parameters:
519    index:
520      type: number
521      label: Volume Index
522      description: number of volumes to spin up
523    size:
524      type: number
525      label: Volume Size
526      description: size of the cinder volumes
527    volume_type:
528      type: string
529      label: Volume Type
530      description: type of cinder volumes
531    vnf_name:
532      type: string
533      label: VNF Name
534      description: vnf name
535
536  resources:
537    ocgapp_volume_0:
538      type: OS::Cinder::Volume
539      properties:
540        size: {get_param: size}
541        volume_type: {get_param: volume_type}
542        name:
543          str_replace:
544            template: VF_NAME_STACK_NAME_INDEX
545            params:
546              VF_NAME: { get_param: vnf_name }
547              STACK_NAME: { get_param: 'OS::stack_name' }
548              INDEX: {get_param: index}
549
550  outputs:
551    ocgapp_volume_id_0:
552    description: the ocgapp volume uuid
553    value: {get_resource: ocgapp_volume_0}
554
555 Below is a screen shot of parameter ocgapp_volume_ids from the OpenStack
556 Horizon GUI showing the output.
557
558 .. image:: ../../heat_picture3.png
559   :height: 334px
560   :width: 1186px
561   :scale: 50 %
562
563 The heat template below is a partial heat template,
564
565 ocgapp.yml
566
567 .. code-block:: yaml
568
569   heat_template_version: 2014-10-16
570
571   #file version 1.0
572   description: OCG Apps template
573
574   parameters:
575     ocgapp_volume_ids:
576       type: json
577       description: Unique IDs for volumes
578
579   resources:
580     ocgapp_server_0:
581       type: OS::Nova::Server
582       properties:
583     . . . .
584     ocgapp_server_1:
585       type: OS::Nova::Server
586       properties:
587     . . . .
588     ocgapp_volume_attachment_0:
589       type: OS::Cinder::VolumeAttachment
590       properties:
591         volume_id: {get_param: [ocgapp_volume_ids, 0]}
592         instance_uuid: {get_resource: ocgapp_server_0}
593     ocgapp_volume_attachment_1:
594       type: OS::Cinder::VolumeAttachment
595       properties:
596         volume_id: {get_param: [ocgapp_volume_ids, 1]}
597         instance_uuid: {get_resource: ocgapp_server_1}
598
599 External References
600 ^^^^^^^^^^^^^^^^^^^^^^
601
602 Heat templates *must not* reference any HTTP-based resource
603 definitions, any HTTP-based nested configurations, or any HTTP-based
604 environment files.
605
606 -  During orchestration, ONAP *must not* retrieve any such resources
607    from external/untrusted/unknown sources.
608
609 -  VNF images must not contain external references in user-data or other
610    configuration/operational scripts that are specified via Heat or
611    encoded into the VNF image itself.
612
613 *Note: HTTP-based references are acceptable if the HTTP-based reference
614 is accessing information utilizing the VM private/internal network.*
615
616 Note that Namespaces in XML (defined at
617 http://www.w3.org/TR/2009/REC-xml-names-20091208/) are allowed if the
618 Heat Orchestration Template is describing and storing software
619 configuration information. An XML namespace is identified by a URI
620 reference. A Uniform Resource Identifier (URI) is a string of characters
621 which identifies an Internet Resource. The most common URI is the
622 Uniform Resource Locator (URL) which identifies an Internet domain
623 address. Another, not so common type of URI is the Universal Resource
624 Name (URN). The namespace URI is not used by XML the parser to look up
625 information. The purpose of using an URI is to give the namespace a
626 unique name.
627
628 Heat Files Support (get_file)
629 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
630
631 Heat Templates may contain the inclusion of text files into Heat
632 templates via the Heat get_file directive. This may be used, for
633 example, to define a common "user-data" script, or to inject files into
634 a VM on startup via the "personality" property.
635
636 Support for Heat Files is subject to the following limitations:
637
638
639 .. req::
640     :id: R-76718
641     :target: VNF
642     :keyword: MUST
643     :validation_mode: static
644     :updated: casablanca
645
646     If a VNF's Heat Orchestration Template uses the intrinsic function
647     ``get_file``, the ``get_file`` target **MUST** be referenced in
648     the Heat Orchestration Template by file name.
649
650 The ``get_file`` target files are on-boarded to SDC in the same package
651 that contains the VNF's complete Heat Orchestration Template.
652
653
654 .. req::
655     :id: R-41888
656     :target: VNF
657     :keyword: MUST NOT
658     :validation_mode: static
659     :updated: casablanca
660
661     A VNF's Heat Orchestration Template intrinsic function
662     ``get_file`` **MUST NOT** utilize URL-based file retrieval.
663
664 .. req::
665     :id: R-87848
666     :target: VNF
667     :keyword: MUST
668     :validation_mode: static
669     :updated: casablanca
670
671     When using the intrinsic function get_file, ONAP does not support
672     a directory hierarchy for included files. All files must be in a
673     single, flat directory per VNF. A VNF's Heat Orchestration
674     Template's ``get_file`` target files **MUST** be in the same
675     directory hierarchy as the VNF's Heat Orchestration Templates.
676
677 ONAP does not support a hierarchical structure.  A VNF's YAML files
678 must be in a single, flat directory.
679
680 .. req::
681     :id: R-05050
682     :target: VNF
683     :keyword: MAY
684     :updated: casablanca
685
686     A VNF's Heat Orchestration Templates intrinsic function
687     ``get_file`` <content key> **MAY** be used:
688
689         * more than once in a VNF's Heat Orchestration Template
690         * in two or more of a VNF's Heat Orchestration Templates
691         * in a VNF's Heat Orchestration Templates nested YAML file
692
693 Key Pairs
694 ^^^^^^^^^^
695
696 When Nova Servers are created via Heat templates, they may be passed a
697 "keypair" which provides an ssh key to the 'root' login on the newly
698 created VM. This is often done so that an initial root key/password does
699 not need to be hard-coded into the image.
700
701 Key pairs are unusual in OpenStack, because they are the one resource
702 that is owned by an OpenStack User as opposed to being owned by an
703 OpenStack Tenant. As a result, they are usable only by the User that
704 created the keypair. This causes a problem when a Heat template attempts
705 to reference a keypair by name, because it assumes that the keypair was
706 previously created by a specific ONAP user ID.
707
708 When a keypair is assigned to a server, the SSH public-key is
709 provisioned on the VMs at instantiation time. They keypair itself is not
710 referenced further by the VM (i.e. if the keypair is updated with a new
711 public key, it would only apply to subsequent VMs created with that
712 keypair).
713
714 Due to this behavior, the recommended usage of keypairs is in a more
715 generic manner which does not require the pre-requisite creation of a
716 keypair. The Heat should be structured in such a way as to:
717
718  -  Pass a public key as a parameter value instead of a keypair name
719
720  -  Create a new keypair within the VNF Heat templates (in the base module)
721     based on an existing public key for use within that VNF
722
723 By following this approach, the end result is the same as pre-creating
724 the keypair using the public key – i.e., that public key will be
725 provisioned in the new VM. However, this recommended approach also makes
726 sure that a known public key is supplied (instead of having OpenStack
727 generate a public/private pair to be saved and tracked outside of ONAP).
728 It also removes any access/ownership issues over the created keypair.
729
730 The public keys may be enumerated as a VNF Orchestration Constant in the
731 environment file (since it is public, it is not a secret key), or passed
732 at run-time as instance-specific parameters. ONAP will never
733 automatically assign a public/private key pair.
734
735 *Example (create keypair with an existing ssh public-key for {vm-type}
736 of lb (for load balancer)):*
737
738 .. code-block:: yaml
739
740   parameters:
741     vnf_name:
742       type: string
743     lb_ssh_public_key:
744       type: string
745
746   resources:
747     lb_keypair_0:
748       type: OS::Nova::Keypair
749       properties:
750         name:
751           str_replace:
752             template: VNF_NAME_key_pair
753             params:
754               VNF_NAME: { get_param: vnf_name }
755         public_key: {get_param: lb_ssh_public_key}
756         save_private_key: false
757
758 Security Groups
759 ^^^^^^^^^^^^^^^^^
760
761 OpenStack allows a tenant to create Security groups and define rules
762 within the security groups.
763
764 Security groups, with their rules, may either be created in the Heat
765 Orchestration Template or they can be pre-created in OpenStack and
766 referenced within the Heat template via parameter(s). There can be a
767 different approach for security groups assigned to ports on internal
768 (intra-VNF) networks or external networks (inter-VNF). Furthermore,
769 there can be a common security group across all VMs for a specific
770 network or it can vary by VM (i.e., {vm-type}) and network type (i.e.,
771 {network-role}).
772
773 Anti-Affinity and Affinity Rules
774 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
775
776 Anti-affinity or affinity rules are supported using normal OpenStack
777 OS::Nova::ServerGroup resources. Separate ServerGroups are typically
778 created for each VM type to prevent them from residing on the same host,
779 but they can be applied to multiple VM types to extend the
780 affinity/anti-affinity across related VM types as well.
781
782 *Example:*
783
784 In this example, the {network-role} has been defined as oam to represent
785 an oam network and the {vm-type} have been defined as lb for load
786 balancer and db for database.
787
788 .. code-block:: yaml
789
790   resources:
791     db_server_group:
792       type: OS::Nova::ServerGroup
793       properties:
794         name:
795           str_replace:
796             params:
797               $vnf_name: {get_param: vnf_name}
798             template: $vnf_name-server_group1
799         policies:
800         - anti-affinity
801     lb_server_group:
802       type: OS::Nova::ServerGroup
803       properties:
804         name:
805           str_replace:
806             params:
807               $vnf_name: {get_param: vnf_name}
808             template: $vnf_name-server_group2
809         policies:
810         - affinity
811     db_server_0:
812       type: OS::Nova::Server
813       properties:
814         ...
815         scheduler_hints:
816         group: {get_resource: db_server_group}
817     db_server_1:
818       type: OS::Nova::Server
819       properties:
820         ...
821         scheduler_hints:
822         group: {get_resource: db_server_group}
823     lb_server_0:
824       type: OS::Nova::Server
825       properties:
826         ...
827         scheduler_hints:
828         group: {get_resource: lb_server_group}
829
830 Resource Data Synchronization
831 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
832
833 For cases where synchronization is required in the orchestration of Heat
834 resources, two approaches are recommended:
835
836 -  Standard Heat depends_on property for resources
837
838    -  Assures that one resource completes before the dependent resource
839       is orchestrated.
840
841    -  Definition of completeness to OpenStack may not be sufficient
842       (e.g., a VM is considered complete by OpenStack when it is ready
843       to be booted, not when the application is up and running).
844
845 -  Use of Heat Notifications
846
847    -  Create OS::Heat::WaitCondition and OS::Heat::WaitConditionHandle
848       resources.
849
850    -  Pre-requisite resources issue *wc_notify* commands in user_data.
851
852    -  Dependent resource define depends_on in the
853       OS::Heat::WaitCondition resource.
854
855 *Example: "depends_on" case*
856
857 In this example, the {network-role} has been defined as oam to represent
858 an oam network and the {vm-type} has been defined as oam to represent an
859 oam server.
860
861 .. code-block:: yaml
862
863   resources:
864     oam_server_01:
865       type: OS::Nova::Server
866       properties:
867         name: {get_param: [oam_names, 0]}
868         image: {get_param: oam_image_name}
869         flavor: {get_param: oam_flavor_name}
870         availability_zone: {get_param: availability_zone_0}
871         networks:
872         - port: {get_resource: oam01_port_0}
873         - port: {get_resource: oam01_port_1}
874         user_data:
875         scheduler_hints: {group: {get_resource: oam_servergroup}}
876         user_data_format: RAW
877     oam_01_port_0:
878       type: OS::Neutron::Port
879       properties:
880         network: {get_resource: oam_net_name}
881         fixed_ips: [{"ip_address": {get_param: [oam_oam_net_ips, 1]}}]
882         security_groups: [{get_resource: oam_security_group}]
883     oam_01_port_1:
884       type: OS::Neutron::Port
885       properties:
886         network: {get_param: oam_net_name}
887         fixed_ips: [{"ip_address": {get_param: [oam_oam_net_ips, 2]}}]
888         security_groups: [{get_resource: oam_security_group}]
889     oam_volume_attachment_0:
890       type: OS::Cinder::VolumeAttachment
891       depends_on: oam_server_01
892       properties:
893         volume_id: {get_param: oam_vol_1}
894         mountpoint: /dev/vdb
895         instance_uuid: {get_resource: oam_server_01}
896
897