# 4.4. VNF Modularity¶

## 4.4.1. ONAP Heat Orchestration Templates: Overview¶

ONAP supports a modular Heat Orchestration Template design pattern, referred to as VNF Modularity.

## 4.4.2. ONAP VNF Modularity Overview¶

With VNF Modularity, a single VNF may be composed from one or more Heat Orchestration Templates, each of which represents a subset of the overall VNF. These component parts are referred to as “VNF Modules”. During orchestration, these modules are deployed incrementally to create the complete VNF.

A modular Heat Orchestration Template can be either one of the following types:

1. Base Module
2. Incremental Module
3. Cinder Volume Module

(R-37028) - The VNF MUST be composed of one “base” module.

Requirement: R-41215
target: VNF
keyword: MAY

The VNF MAY have zero to many “incremental” modules.

(R-20974) - The VNF MUST deploy the base module first, prior to the incremental modules.

ONAP also supports the concept of an optional, independently deployed Cinder volume via a separate Heat Orchestration Templates, referred to as a Cinder Volume Module. This allows the volume to persist after a Virtual Machine (VM) (i.e., OS::Nova::Server) is deleted, allowing the volume to be reused on another instance (e.g., during a failover activity).

(R-11200) - The VNF MUST keep the scope of a Cinder volume module, when it exists, to be 1:1 with the VNF Base Module or Incremental Module.

(R-38474) - The VNF MUST have a corresponding environment file for a Base Module.

(R-81725) - The VNF MUST have a corresponding environment file for an Incremental Module.

(R-53433) - The VNF MUST have a corresponding environment file for a Cinder Volume Module.

These concepts will be described in more detail throughout the document. This overview is provided to set the stage and help clarify the concepts that will be introduced.

## 4.4.3. ONAP VNF Modularity¶

ONAP supports a modular Heat Orchestration Template design pattern, referred to as VNF Modularity. With this approach, a single VNF may be composed from one or more Heat Orchestration Templates, each of which represents a subset of the overall VNF. These component parts are referred to as “VNF Modules”. During orchestration, these modules are deployed incrementally to create the complete VNF.

A modular Heat Orchestration Template can be either one of the following types:

1. Base Module
2. Incremental Module
3. Cinder Volume Module

A VNF must be composed of one “base” module and may be composed of zero to many “incremental” modules. The base module must be deployed first, prior to the incremental modules.

ONAP also supports the concept of an optional, independently deployed Cinder volume via a separate Heat Orchestration Templates, referred to as a Cinder Volume Module. This allows the volume to persist after a VM (i.e., OS::Nova::Server) is deleted, allowing the volume to be reused on another instance (e.g., during a failover activity).

The scope of a Cinder volume module, when it exists, must be 1:1 with a Base module or Incremental Module.

A Base Module must have a corresponding environment file.

An Incremental Module must have a corresponding environment file.

A Cinder Volume Module must have a corresponding environment file.

A VNF module (base, incremental, cinder) may support nested templates.

A shared Heat Orchestration Template resource must be defined in the base module. A shared resource is a resource that that will be referenced by another resource that is defined in the Base Module and/or one or more incremental modules.

When the shared resource needs to be referenced by a resource in an incremental module, the UUID of the shared resource must be exposed by declaring an ONAP Base Module Output Parameter.

Note that a Cinder volume is not a shared resource. A volume template must correspond 1:1 with a base module or incremental module.

An example of a shared resource is the resource OS::Neutron::SecurityGroup. Security groups are sets of IP filter rules that are applied to a VNF’s networking. The resource OS::Neutron::Port has a property security_groups which provides the security groups associated with port. The value of parameter(s) associated with this property must be the UUIDs of the resource(s) OS::Neutron::SecurityGroup.

Note: A Cinder volume is not considered a shared resource. A volume template must correspond 1:1 with a base template or add-on module template.

## 4.4.4. Suggested Patterns for Modular VNFs¶

There are numerous variations of VNF modularity. Below are two suggested usage patterns.

Option 1: Modules per VNFC type

1. Base module contains only the shared resources.
2. Group all VMs (e.g., VNFCs) of a given type (i.e. {vm-type}) into its own incremental module. That is, the VNF has an incremental module for each {vm-type}.
3. For a given {vm-type} incremental module, the VNF may have
1. One incremental module used for both initial turn up and re-used for scaling. This approach is used when the number of VMs instantiated will be the same for initial deployment and scaling.
2. Two incremental modules, where one is used for initial turn up and one is used for scaling. This approach is used when the number of VMs instantiated will be different for initial deployment and scaling.

Option 2: Base VNF with Incremental Growth Modules

1. Base module contains a complete initial VNF instance
2. Incremental modules for incremental scaling units
1. May contain VMs of multiple types in logical scaling combinations
2. May be separated by VM type for multi-dimensional scaling

With no growth units, Option 2 is equivalent to the “One Heat Template per VNF” model.

Note that modularization of VNFs is not required. A single Heat Orchestration Template (a base module) may still define a complete VNF, which might be appropriate for smaller VNFs that do not have any scaling options.

## 4.4.5. Modularity Rules¶

There are some rules to follow when building modular VNF templates:

1. All VNFs must have one Base VNF Module (template) that must be the first one deployed. The base template:
1. Must include all shared resources (e.g., private networks, server groups, security groups)
2. Must expose all shared resources (by UUID) as “outputs” in its associated Heat template (i.e., ONAP Base Module Output Parameters)
3. May include initial set of VMs
4. May be operational as a stand-alone “minimum” configuration of the VNF
2. VNFs may have one or more incremental modules which:
1. Defines additional resources that can be added to an existing VNF
2. Must be complete Heat templates
1. i.e. not snippets to be incorporated into some larger template
3. Should define logical growth-units or sub-components of an overall VNF
4. On creation, receives appropriate Base Module outputs as parameters
2. must not be dependent on other Add-On VNF Modules
5. Multiple instances of an incremental Module may be added to the same VNF (e.g., incrementally grow a VNF by a fixed “add-on” growth units)
3. Each VNF Module (base or incremental) may have (optional) an associated Cinder Volume Module (see Cinder Volume Templates)
1. Volume modules must correspond 1:1 with a base module or incremental module
2. A Cinder volume may be embedded within the base module or incremental module if persistence is not required
4. Shared resource UUIDs are passed between the base module and incremental modules via Heat Outputs Parameters (i.e., Base Module Output Parameters)
1. The output parameter name in the base must match the parameter name in the add-on module

## 4.4.6. VNF Modularity Examples¶

Example: Base Module creates SecurityGroup

A VNF has a base module, named base.yaml, that defines a OS::Neutron::SecurityGroup. The security group will be referenced by an OS::Neutron::Port resource in an incremental module, named INCREMENTAL_MODULE.yaml. The base module defines a parameter in the out section named dns_sec_grp_id. dns_sec_grp_id is defined as a parameter in the incremental module. ONAP captures the UUID value of dns_sec_grp_id from the base module output statement and provides the value to the incremental module.

Note that the example below is not a complete Heat Orchestration Template. The {network-role} has been defined as oam to represent an oam network and the {vm-type} has been defined as dns.

base_MODULE.yaml

parameters:
. . .

resources:
DNS_SECURITY_GROUP:
type: OS::Neutron::SecurityGroup
properties:
description: vDNS security group
name:
str_replace:
template: VNF_NAME_sec_grp_DNS
params:
VMF_NAME: {get_param: vnf_name}
rules: [. . . . .

. . .

outputs:
dns_sec_grp_id:
description: UUID of DNS Resource SecurityGroup
value: { get_resource: DNS_SECURITY_GROUP }


INCREMENTAL_MODULE.yaml

parameters:
dns_sec_grp_id:
type: string
description: security group UUID
. . .

resources:
dns_oam_0_port:
type: OS::Neutron::Port
properties:
name:
str_replace:
template: VNF_NAME_dns_oam_port
params:
VNF_NAME: {get_param: vnf_name}
network: { get_param: oam_net_name }
fixed_ips: [{ "ip_address": { get_param: dns_oam_ip_0 }}]
security_groups: [{ get_param: dns_sec_grp_id }]


Examples: Base Module creates an internal network

A VNF has a base module, named base_module.yaml, that creates an internal network. An incremental module, named incremental_module.yaml, will create a VM that will connect to the internal network. The base module defines a parameter in the out section named int_oam_net_id. int_oam_net_id is defined as a parameter in the incremental module. ONAP captures the UUID value of int_oam_net_id from the base module output statement and provides the value to the incremental module.

Note that the example below is not a complete Heat Orchestration Template. The {network-role} has been defined as oam to represent an oam network and the {vm-type} has been defined as lb for load balancer.

base.yaml

heat_template_version: 2013-05-23

resources:
int_oam_network:
type: OS::Neutron::Network
properties:
name: {… }
. . .
outputs:
int_oam_net_id:
value: {get_resource: int_oam_network }


incremental.yaml

heat_template_version: 2013-05-23

parameters:
int_oam_net_id:
type: string
description: ID of shared private network from Base template
lb_name_0:
type: string
description: name for the add-on VM instance

Resources:
lb_server:
type: OS::Nova::Server
properties:
name: {get_param: lb_name_0}
networks:
- port: { get_resource: lb_port }
. . .

lb_port:
type: OS::Neutron::Port
properties:
network_id: { get_param: int_oam_net_id }
...