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