开始使用 v2 Tacker

摘要

本讲座将使您能够

  • 使用 Tacker v2 API 在 OpenStack 上创建和删除示例 VNF

本讲座介绍了 Tacker 支持的两种 VNF 部署类型。

“使用 LCM 操作用户数据的 VNF 部署”是可选的。该部分将用以下标注进行说明 [这是特定于 UserData 的部分]。

下图显示了本讲座中使用的示例 VNF。

../../../_images/sample-vnf.svg

注意

本教程中使用的 VIM 配置、VNF 包和实例化参数文件位于仓库中。

注意

您可以使用以下命令查看 Tacker 的日志

$ sudo journalctl -u devstack@tacker.service
$ sudo journalctl -u devstack@tacker-conductor.service

先决条件

应安装以下软件包

  • tacker

  • python-tackerclient

配置

加载客户端操作的凭据

在运行任何 Tacker 命令之前,需要先获取您的凭据。

注意

有关详细信息,请参阅 创建 OpenStack 客户端环境脚本。 在本文档中,设置如下

OS_REGION_NAME=RegionOne
OS_PROJECT_DOMAIN_ID=default
OS_CACERT=
OS_AUTH_URL=http://192.168.56.10/identity
OS_TENANT_NAME=nfv
OS_USER_DOMAIN_ID=default
OS_USERNAME=nfv_user
OS_VOLUME_API_VERSION=3
OS_AUTH_TYPE=password
OS_PROJECT_NAME=nfv
OS_PASSWORD=devstack
OS_IDENTITY_API_VERSION=3

您可以通过检查以下命令是否能正常工作来确认 Tacker 是否可用

$ openstack vim list

注意

请参阅 命令行界面参考 以查找所有可用命令。

注册 VIM

  1. 准备 VIM 配置文件

    您可以使用设置脚本生成 VIM 配置文件,也可以按照 注册 VIM 的配置文件 中所述从头开始编辑它。 该脚本会从您的环境变量中查找配置参数,例如用户名或密码。 以下是生成 OpenStack VIM 配置文件的示例,名为 vim_config.yaml。 在本文档中,TACKER_ROOT 是您服务器上 tacker 仓库的根目录。

    $ bash TACKER_ROOT/tools/gen_vim_config.sh -p nfv --os-user nfv_user \
      --os-disable-cert-verify
    Config for OpenStack VIM 'vim_config.yaml' generated.
    

    支持从命令行配置参数的几种选项。 有关详细信息,请参阅帮助信息 -h

    注意

    有关工具详细信息,请参阅 注册 VIM 的配置文件

    您也可以使用示例配置文件 (vim_config.yaml) 代替使用脚本。

    $ cp TACKER_ROOT/doc/source/user/v2/getting_started/conf/vim_config.yaml ./
    $ vi vim_config.yaml
    
    auth_url: 'http://192.168.56.10/identity'
    username: "nfv_user"
    password: "devstack"
    project_name: "nfv"
    domain_name: "default"
    project_domain_name: "default"
    user_domain_name: "default"
    cert_verify: "False"
    
  2. 注册默认 VIM

    设置好 VIM 配置文件后,您可以通过 openstack 命令使用 --is-default 选项注册默认 VIM。

    $ openstack vim register --config-file ./vim_config.yaml \
      --is-default --fit-width openstack-admin-vim
    +----------------+-----------------------------------------------------+
    | Field          | Value                                               |
    +----------------+-----------------------------------------------------+
    | auth_cred      | {                                                   |
    |                |     "username": "nfv_user",                         |
    |                |     "user_domain_name": "default",                  |
    |                |     "cert_verify": "False",                         |
    |                |     "project_id": null,                             |
    |                |     "project_name": "nfv",                          |
    |                |     "project_domain_name": "default",               |
    |                |     "auth_url": "http://192.168.56.10/identity/v3", |
    |                |     "key_type": "barbican_key",                     |
    |                |     "secret_uuid": "***",                           |
    |                |     "password": "***"                               |
    |                | }                                                   |
    | auth_url       | http://192.168.56.10/identity/v3                    |
    | created_at     | 2023-11-30 08:32:48.869451                          |
    | description    |                                                     |
    | extra          |                                                     |
    | id             | bff267c4-6fc9-46b5-be53-15a6a3680033                |
    | is_default     | True                                                |
    | name           | openstack-admin-vim                                 |
    | placement_attr | {                                                   |
    |                |     "regions": [                                    |
    |                |         "RegionOne"                                 |
    |                |     ]                                               |
    |                | }                                                   |
    | project_id     | ebbc6cf1a03d49918c8e408535d87268                    |
    | status         | ACTIVE                                              |
    | type           | openstack                                           |
    | updated_at     | None                                                |
    | vim_project    | {                                                   |
    |                |     "name": "nfv",                                  |
    |                |     "project_domain_name": "default"                |
    |                | }                                                   |
    +----------------+-----------------------------------------------------+
    

创建并上传 VNF 包

准备 VNF 包

  1. 创建 VNF 包 CSAR 目录

    $ mkdir -p ./sample_vnf_package_csar/TOSCA-Metadata \
      ./sample_vnf_package_csar/Definitions \
      ./sample_vnf_package_csar/BaseHOT/simple/nested \
      ./sample_vnf_package_csar/Files
    

    [这是特定于 UserData 的部分] 使用 UserData 时,创建以下目录。

    $ mkdir -p ./sample_vnf_package_csar/UserData
    
  2. 创建一个 TOSCA.meta 文件

    $ vi ./sample_vnf_package_csar/TOSCA-Metadata/TOSCA.meta
    
    TOSCA-Meta-File-Version: 1.0
    Created-by: Dummy User
    CSAR-Version: 1.1
    Entry-Definitions: Definitions/sample_vnfd_top.yaml
    
  3. 下载 ETSI 定义文件

    您应该将 ${TOSCA_VERSION} 设置为适当的 TOSCA 服务模板版本之一 (SOL001),例如 export TOSCA_VERSION=v2.6.1

    重要提示

    您还应该检查 tacker 是否支持 TOSCA 服务模板的版本。 请参阅 基于 ETSI NFV-SOL001 的 VNF 描述符 (VNFD) 以获取支持的版本。

    $ cd ./sample_vnf_package_csar/Definitions
    $ wget https://forge.etsi.org/rep/nfv/SOL001/raw/${TOSCA_VERSION}/etsi_nfv_sol001_common_types.yaml
    $ wget https://forge.etsi.org/rep/nfv/SOL001/raw/${TOSCA_VERSION}/etsi_nfv_sol001_vnfd_types.yaml
    
  4. 创建 VNFD 文件

    • 创建 sample_vnfd_top.yaml

      $ vi ./sample_vnfd_top.yaml
      
      tosca_definitions_version: tosca_simple_yaml_1_2
      
      description: Sample VNF
      
      imports:
        - etsi_nfv_sol001_common_types.yaml
        - etsi_nfv_sol001_vnfd_types.yaml
        - sample_vnfd_types.yaml
        - sample_vnfd_df_simple.yaml
      
      topology_template:
        inputs:
          selected_flavour:
            type: string
            description: VNF deployment flavour selected by the consumer. It is provided in the API
      
        node_templates:
          VNF:
            type: company.provider.VNF
            properties:
              flavour_id: { get_input: selected_flavour }
              descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177
              provider: Company
              product_name: Sample VNF
              software_version: '1.0'
              descriptor_version: '1.0'
              vnfm_info:
                - Tacker
      
    • 创建 sample_vnfd_types.yaml

      $ vi ./sample_vnfd_types.yaml
      
      tosca_definitions_version: tosca_simple_yaml_1_2
      
      description: VNF type definition
      
      imports:
        - etsi_nfv_sol001_common_types.yaml
        - etsi_nfv_sol001_vnfd_types.yaml
      
      node_types:
        company.provider.VNF:
          derived_from: tosca.nodes.nfv.VNF
          properties:
            descriptor_id:
              type: string
              constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 ] ]
              default: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177
            descriptor_version:
              type: string
              constraints: [ valid_values: [ '1.0' ] ]
              default: '1.0'
            provider:
              type: string
              constraints: [ valid_values: [ 'Company' ] ]
              default: 'Company'
            product_name:
              type: string
              constraints: [ valid_values: [ 'Sample VNF' ] ]
              default: 'Sample VNF'
            software_version:
              type: string
              constraints: [ valid_values: [ '1.0' ] ]
              default: '1.0'
            vnfm_info:
              type: list
              entry_schema:
                type: string
                constraints: [ valid_values: [ Tacker ] ]
              default: [ Tacker ]
            flavour_id:
              type: string
              constraints: [ valid_values: [ simple ] ]
              default: simple
            flavour_description:
              type: string
              default: This is the default flavour description
          requirements:
            - virtual_link_internal:
                capability: tosca.capabilities.nfv.VirtualLinkable
          interfaces:
            Vnflcm:
              type: tosca.interfaces.nfv.Vnflcm
      

      注意

      description_id 必须全局唯一,即您不能使用相同的 description_id 创建多个 VNFD。

    • 创建 sample_vnfd_df_simple.yaml

      $ vi ./sample_vnfd_df_simple.yaml
      
      tosca_definitions_version: tosca_simple_yaml_1_2
      
      description: Simple deployment flavour for Sample VNF
      
      imports:
        - etsi_nfv_sol001_common_types.yaml
        - etsi_nfv_sol001_vnfd_types.yaml
        - sample_vnfd_types.yaml
      
      topology_template:
        inputs:
          descriptor_id:
            type: string
          descriptor_version:
            type: string
          provider:
            type: string
          product_name:
            type: string
          software_version:
            type: string
          vnfm_info:
            type: list
            entry_schema:
              type: string
          flavour_id:
            type: string
          flavour_description:
            type: string
      
        substitution_mappings:
          node_type: company.provider.VNF
          properties:
            flavour_id: simple
      
        node_templates:
          VNF:
            type: company.provider.VNF
            properties:
              flavour_description: A simple flavour
            interfaces:
              Vnflcm:
                instantiate_start: []
                instantiate_end: []
                terminate_start: []
                terminate_end: []
                modify_information_start: []
                modify_information_end: []
                heal_start: []
                heal_end: []
                scale_start: []
                scale_end: []
      
          VDU1:
            type: tosca.nodes.nfv.Vdu.Compute
            properties:
              name: VDU1
              description: VDU1 compute node
              vdu_profile:
                min_number_of_instances: 1
                max_number_of_instances: 3
              sw_image_data:
                name: cirros-0.5.2-x86_64-disk
                version: '0.5.2'
                checksum:
                  algorithm: sha-256
                  hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
                container_format: bare
                disk_format: qcow2
                min_disk: 1 GB
                size: 1 GB
            capabilities:
              virtual_compute:
                properties:
                  requested_additional_capabilities:
                    properties:
                      requested_additional_capability_name: m1.tiny
                      support_mandatory: true
                      target_performance_parameters:
                        entry_schema: test
                  virtual_memory:
                    virtual_mem_size: 512 MB
                  virtual_cpu:
                    num_virtual_cpu: 1
                  virtual_local_storage:
                    - size_of_storage: 1 GB
      
          CP1:
            type: tosca.nodes.nfv.VduCp
            properties:
              layer_protocols: [ ipv4 ]
              order: 4
            requirements:
              - virtual_binding: VDU1
              - virtual_link: internalVL1
      
          internalVL1:
            type: tosca.nodes.nfv.VnfVirtualLink
            properties:
              connectivity_type:
                layer_protocols: [ ipv4 ]
              description: Internal Virtual link in the VNF
              vl_profile:
                max_bitrate_requirements:
                  root: 1048576
                  leaf: 1048576
                min_bitrate_requirements:
                  root: 1048576
                  leaf: 1048576
                virtual_link_protocol_data:
                  - associated_layer_protocol: ipv4
                    l3_protocol_data:
                      ip_version: ipv4
                      cidr: 10.0.0.0/24
      
        policies:
          - scaling_aspects:
              type: tosca.policies.nfv.ScalingAspects
              properties:
                aspects:
                  VDU1_scale:
                    name: VDU1_scale
                    description: VDU1 scaling aspect
                    max_scale_level: 2
                    step_deltas:
                      - delta_1
      
          - VDU1_initial_delta:
              type: tosca.policies.nfv.VduInitialDelta
              properties:
                initial_delta:
                  number_of_instances: 1
              targets: [ VDU1 ]
      
          - VDU1_scaling_aspect_deltas:
              type: tosca.policies.nfv.VduScalingAspectDeltas
              properties:
                aspect: VDU1_scale
                deltas:
                  delta_1:
                    number_of_instances: 1
              targets: [ VDU1 ]
      
          - instantiation_levels:
              type: tosca.policies.nfv.InstantiationLevels
              properties:
                levels:
                  instantiation_level_1:
                    description: Smallest size
                    scale_info:
                      VDU1_scale:
                        scale_level: 0
                  instantiation_level_2:
                    description: Largest size
                    scale_info:
                      VDU1_scale:
                        scale_level: 2
                default_level: instantiation_level_1
      
          - VDU1_instantiation_levels:
              type: tosca.policies.nfv.VduInstantiationLevels
              properties:
                levels:
                  instantiation_level_1:
                    number_of_instances: 1
                  instantiation_level_2:
                    number_of_instances: 3
              targets: [ VDU1 ]
      
          - internalVL1_instantiation_levels:
              type: tosca.policies.nfv.VirtualLinkInstantiationLevels
              properties:
                levels:
                  instantiation_level_1:
                    bitrate_requirements:
                      root: 1048576
                      leaf: 1048576
                  instantiation_level_2:
                    bitrate_requirements:
                      root: 1048576
                      leaf: 1048576
              targets: [ internalVL1 ]
      

      注意

      应该根据“VNF”中的属性更新 flavour_description,但 Tacker 无法处理它。 实例化后,sample_vnfd_types.yaml 中的默认值始终被使用。

  5. 创建 BaseHOT 文件

    $ cd -
    $ vi ./sample_vnf_package_csar/BaseHOT/simple/sample_lcm_hot.yaml
    $ vi ./sample_vnf_package_csar/BaseHOT/simple/nested/VDU1.yaml
    
    • sample_lcm_hot.yaml

      heat_template_version: 2013-05-23
      description: 'imple Base HOT for Sample VNF'
      
      parameters:
        nfv:
          type: json
      
      resources:
        VDU1:
          type: VDU1.yaml
          properties:
            flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
            image: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
            net: { get_resource: internalVL1 }
      
        internalVL1:
          type: OS::Neutron::Net
      
        internalVL1_subnet:
          type: OS::Neutron::Subnet
          properties:
            ip_version: 4
            network:
              get_resource: internalVL1
            cidr: 10.0.0.0/24
      
      outputs: {}
      
    • VDU1.yaml

      heat_template_version: 2013-05-23
      description: 'VDU1 HOT for Sample VNF'
      
      parameters:
        flavor:
          type: string
        image:
          type: string
        net:
          type: string
      
      resources:
        VDU1:
          type: OS::Nova::Server
          properties:
            flavor: { get_param: flavor }
            image: { get_param: image }
            name: VDU1
            networks:
            - port:
                get_resource: VDU1_CP1
      
        VDU1_CP1:
          type: OS::Neutron::Port
          properties:
            network: { get_param: net }
      
  6. [这是特定于 UserData 的部分] 创建 UserData 文件

    $ cd ./sample_vnf_package_csar/UserData/
    $ touch ./__init__.py
    $ vi ./lcm_user_data.py
    

    注意

    有关详细信息,请参阅 UserData 脚本 (VNF LCM v2)。 在本文档中,使用了以下“StandardUserData”。

    # Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
    # All Rights Reserved.
    #
    #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    #    not use this file except in compliance with the License. You may obtain
    #    a copy of the License at
    #
    #         https://apache.org/licenses/LICENSE-2.0
    #
    #    Unless required by applicable law or agreed to in writing, software
    #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    #    License for the specific language governing permissions and limitations
    #    under the License.
    
    import copy
    import yaml
    
    from tacker.sol_refactored.common import common_script_utils
    from tacker.sol_refactored.common import vnf_instance_utils as inst_utils
    from tacker.sol_refactored.infra_drivers.openstack import userdata_utils
    
    
    def add_idx(name, index):
        return f'{name}-{index}'
    
    
    def rm_idx(name_idx):
        return name_idx.rpartition('-')[0]
    
    
    def add_idx_to_vdu_template(vdu_template, vdu_idx):
        """Add index to the third element of get_param
    
        ex. input VDU template:
        ---
        VDU1:
          type: VDU1.yaml
          properties:
            flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
            image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
            net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
        ---
    
        output VDU template:
        ---
        VDU1:
          type: VDU1.yaml
          properties:
            flavor: { get_param: [ nfv, VDU, VDU1-1, computeFlavourId ] }
            image-VDU1: { get_param: [ nfv, VDU, VDU1-1, vcImageId ] }
            net1: { get_param: [ nfv, CP, VDU1_CP1-1, network ] }
        ---
        """
        res = copy.deepcopy(vdu_template)
        for prop_value in res.get('properties', {}).values():
            get_param = prop_value.get('get_param')
            if (get_param is not None and
                    isinstance(get_param, list) and len(get_param) >= 4):
                get_param[2] = add_idx(get_param[2], vdu_idx)
        return res
    
    
    def _get_new_cps_from_req(cps, req, grant):
        # used by change_ext_conn and change_vnfpkg
        new_cps = {}
        for cp_name_idx, cp_value in cps.items():
            cp_name = rm_idx(cp_name_idx)
            if 'network' in cp_value:
                network = common_script_utils.get_param_network(
                    cp_name, grant, req)
                if network is None:
                    continue
                new_cps.setdefault(cp_name_idx, {})
                new_cps[cp_name_idx]['network'] = network
            if 'fixed_ips' in cp_value:
                ext_fixed_ips = common_script_utils.get_param_fixed_ips(
                    cp_name, grant, req)
                fixed_ips = []
                for i in range(len(ext_fixed_ips)):
                    if i not in cp_value['fixed_ips']:
                        break
                    ips_i = cp_value['fixed_ips'][i]
                    if 'subnet' in ips_i:
                        ips_i['subnet'] = ext_fixed_ips[i].get('subnet')
                    if 'ip_address' in ips_i:
                        ips_i['ip_address'] = ext_fixed_ips[i].get(
                            'ip_address')
                    fixed_ips.append(ips_i)
                new_cps.setdefault(cp_name_idx, {})
                new_cps[cp_name_idx]['fixed_ips'] = fixed_ips
    
        return new_cps
    
    
    def _merge_additional_params(nfv_dict, req, grant):
        if 'nfv' in req.get('additionalParams', {}):
            nfv_dict = inst_utils.json_merge_patch(
                nfv_dict, req['additionalParams']['nfv'])
        if 'nfv' in grant.get('additionalParams', {}):
            nfv_dict = inst_utils.json_merge_patch(
                nfv_dict, grant['additionalParams']['nfv'])
        return nfv_dict
    
    
    class StandardUserData(userdata_utils.AbstractUserData):
    
        @staticmethod
        def instantiate(req, inst, grant_req, grant, tmp_csar_dir):
            vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
            flavour_id = req['flavourId']
    
            hot_dict = vnfd.get_base_hot(flavour_id)
            top_hot = hot_dict['template']
    
            # first modify VDU resources
            popped_vdu = {}
            vdu_idxes = {}
            for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
                popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
                vdu_idxes[vdu_name] = 0
            zones = {}
            for res in grant_req['addResources']:
                if res['type'] != 'COMPUTE':
                    continue
                vdu_name = res['resourceTemplateId']
                if vdu_name not in popped_vdu:
                    continue
                vdu_idx = vdu_idxes[vdu_name]
                vdu_idxes[vdu_name] += 1
                zones[add_idx(vdu_name, vdu_idx)] = (
                    common_script_utils.get_param_zone_by_vnfc(
                        res['id'], grant))
                res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx)
                top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
    
            nfv_dict = common_script_utils.init_nfv_dict(top_hot)
    
            vdus = nfv_dict.get('VDU', {})
            for vdu_name_idx, vdu_value in vdus.items():
                vdu_name = rm_idx(vdu_name_idx)
                if 'computeFlavourId' in vdu_value:
                    vdu_value['computeFlavourId'] = (
                        common_script_utils.get_param_flavor(
                            vdu_name, flavour_id, vnfd, grant))
                if 'vcImageId' in vdu_value:
                    vdu_value['vcImageId'] = common_script_utils.get_param_image(
                        vdu_name, flavour_id, vnfd, grant)
                if 'locationConstraints' in vdu_value:
                    vdu_value['locationConstraints'] = zones[vdu_name_idx]
    
            cps = nfv_dict.get('CP', {})
            for cp_name, cp_value in cps.items():
                cp_name = rm_idx(cp_name)
                if 'network' in cp_value:
                    cp_value['network'] = common_script_utils.get_param_network(
                        cp_name, grant, req)
                if 'fixed_ips' in cp_value:
                    ext_fixed_ips = common_script_utils.get_param_fixed_ips(
                        cp_name, grant, req)
                    fixed_ips = []
                    for i in range(len(ext_fixed_ips)):
                        if i not in cp_value['fixed_ips']:
                            break
                        ips_i = cp_value['fixed_ips'][i]
                        if 'subnet' in ips_i:
                            ips_i['subnet'] = ext_fixed_ips[i].get('subnet')
                        if 'ip_address' in ips_i:
                            ips_i['ip_address'] = ext_fixed_ips[i].get(
                                'ip_address')
                        fixed_ips.append(ips_i)
                    cp_value['fixed_ips'] = fixed_ips
    
            common_script_utils.apply_ext_managed_vls(top_hot, req, grant)
            nfv_dict = _merge_additional_params(nfv_dict, req, grant)
    
            fields = {
                'template': yaml.safe_dump(top_hot),
                'parameters': {'nfv': nfv_dict},
                'files': {}
            }
            for key, value in hot_dict.get('files', {}).items():
                fields['files'][key] = yaml.safe_dump(value)
    
            return fields
    
        @staticmethod
        def scale(req, inst, grant_req, grant, tmp_csar_dir):
            if req['type'] == 'SCALE_OUT':
                return StandardUserData._scale_out(req, inst, grant_req, grant,
                                                  tmp_csar_dir)
            else:
                return StandardUserData._scale_in(req, inst, grant_req, grant,
                                                 tmp_csar_dir)
    
        @staticmethod
        def _scale_out(req, inst, grant_req, grant, tmp_csar_dir):
            vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
            flavour_id = inst['instantiatedVnfInfo']['flavourId']
    
            hot_dict = vnfd.get_base_hot(flavour_id)
            top_hot = hot_dict['template']
    
            # first modify VDU resources
            popped_vdu = {}
            vdu_idxes = {}
            for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
                popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
                vdu_idxes[vdu_name] = common_script_utils.get_current_capacity(
                    vdu_name, inst)
    
            zones = {}
            for res in grant_req['addResources']:
                if res['type'] != 'COMPUTE':
                    continue
                vdu_name = res['resourceTemplateId']
                if vdu_name not in popped_vdu:
                    continue
                vdu_idx = vdu_idxes[vdu_name]
                vdu_idxes[vdu_name] += 1
                zones[add_idx(vdu_name, vdu_idx)] = (
                    common_script_utils.get_param_zone_by_vnfc(
                        res['id'], grant))
                res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx)
                top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
    
            nfv_dict = common_script_utils.init_nfv_dict(top_hot)
    
            vdus = nfv_dict.get('VDU', {})
            for vdu_name_idx, vdu_value in vdus.items():
                vdu_name = rm_idx(vdu_name_idx)
                if 'computeFlavourId' in vdu_value:
                    vdu_value['computeFlavourId'] = (
                        common_script_utils.get_param_flavor(
                            vdu_name, flavour_id, vnfd, grant))
                if 'vcImageId' in vdu_value:
                    vdu_value['vcImageId'] = common_script_utils.get_param_image(
                        vdu_name, flavour_id, vnfd, grant)
                if 'locationConstraints' in vdu_value:
                    vdu_value['locationConstraints'] = zones[vdu_name_idx]
                exclude_params = [param for param, value in vdu_value.items()
                                  if value is None]
                for exclude_param in exclude_params:
                    del vdu_value[exclude_param]
    
            cps = nfv_dict.get('CP', {})
            for cp_name, cp_value in cps.items():
                cp_name = rm_idx(cp_name)
                if 'network' in cp_value:
                    cp_value['network'] = (
                        common_script_utils.get_param_network_from_inst(
                            cp_name, inst))
                if 'fixed_ips' in cp_value:
                    ext_fixed_ips = (
                        common_script_utils.get_param_fixed_ips_from_inst(
                            cp_name, inst))
                    fixed_ips = []
                    for i in range(len(ext_fixed_ips)):
                        if i not in cp_value['fixed_ips']:
                            break
                        ips_i = cp_value['fixed_ips'][i]
                        if 'subnet' in ips_i:
                            ips_i['subnet'] = ext_fixed_ips[i].get('subnet')
                        if 'ip_address' in ips_i:
                            ips_i['ip_address'] = ext_fixed_ips[i].get(
                                'ip_address')
                        fixed_ips.append(ips_i)
                    cp_value['fixed_ips'] = fixed_ips
                exclude_params = [param for param, value in cp_value.items()
                                  if value is None]
                for exclude_param in exclude_params:
                    del cp_value[exclude_param]
    
            common_script_utils.apply_ext_managed_vls_from_inst(top_hot, inst)
            nfv_dict = _merge_additional_params(nfv_dict, req, grant)
    
            fields = {
                'template': yaml.safe_dump(top_hot),
                'parameters': {'nfv': nfv_dict}
            }
    
            return fields
    
        @staticmethod
        def _scale_in(req, inst, grant_req, grant, tmp_csar_dir):
            template = {'resources': {}}
    
            for res in grant_req['removeResources']:
                if res['type'] != 'COMPUTE':
                    continue
                for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
                    if (inst_vnfc['computeResource']['resourceId'] ==
                            res['resource']['resourceId']):
                        # must be found
                        vdu_idx = inst_vnfc['metadata']['vdu_idx']
                        break
                vdu_name = res['resourceTemplateId']
                template['resources'][add_idx(vdu_name, vdu_idx)] = None
    
            fields = {
                'template': yaml.safe_dump(template),
            }
    
            return fields
    
        @staticmethod
        def scale_rollback(req, inst, grant_req, grant, tmp_csar_dir):
            vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
            flavour_id = inst['instantiatedVnfInfo']['flavourId']
    
            vdu_nodes = vnfd.get_vdu_nodes(flavour_id)
            vdu_idxes = {}
            for vdu_name in vdu_nodes.keys():
                vdu_idxes[vdu_name] = common_script_utils.get_current_capacity(
                    vdu_name, inst)
    
            template = {'resources': {}}
            for res in grant_req['addResources']:
                if res['type'] != 'COMPUTE':
                    continue
                vdu_name = res['resourceTemplateId']
                vdu_idx = vdu_idxes[vdu_name]
                vdu_idxes[vdu_name] += 1
                template['resources'][add_idx(vdu_name, vdu_idx)] = None
    
            fields = {
                'template': yaml.safe_dump(template),
            }
    
            return fields
    
        @staticmethod
        def change_ext_conn(req, inst, grant_req, grant, tmp_csar_dir):
            # change_ext_conn is interested in 'CP' only.
            # This method returns only 'CP' part in the 'nfv' dict from
            # ChangeExtVnfConnectivityRequest.
            # It is applied to json merge patch against the existing 'nfv'
            # dict by the caller.
            # NOTE: complete 'nfv' dict can not be made at the moment
            # since InstantiateVnfRequest is necessary to make it.
    
            vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
            flavour_id = inst['instantiatedVnfInfo']['flavourId']
    
            hot_dict = vnfd.get_base_hot(flavour_id)
            top_hot = hot_dict['template']
    
            # first modify VDU resources
            popped_vdu = {}
            for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
                popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
    
            for inst_vnfc in inst['instantiatedVnfInfo'].get(
                    'vnfcResourceInfo', []):
                vdu_idx = inst_vnfc['metadata'].get('vdu_idx')
                if vdu_idx is None:
                    continue
                vdu_name = inst_vnfc['vduId']
                res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx)
                top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res
    
            nfv_dict = common_script_utils.init_nfv_dict(top_hot)
    
            cps = nfv_dict.get('CP', {})
            new_cps = _get_new_cps_from_req(cps, req, grant)
    
            nfv_dict = _merge_additional_params({'CP': new_cps}, req, grant)
            fields = {'parameters': {'nfv': nfv_dict}}
    
            return fields
    
        @staticmethod
        def change_ext_conn_rollback(req, inst, grant_req, grant, tmp_csar_dir):
            fields = {
                'parameters': {
                    'nfv': inst['instantiatedVnfInfo']['metadata']['nfv']
                }
            }
    
            return fields
    
        @staticmethod
        def heal(req, inst, grant_req, grant, tmp_csar_dir):
            vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
            flavour_id = inst['instantiatedVnfInfo']['flavourId']
    
            vdus = inst['instantiatedVnfInfo']['metadata']['nfv'].get('VDU', {})
            for res in grant_req['removeResources']:
                if res['type'] != 'COMPUTE':
                    continue
                for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
                    if (inst_vnfc['computeResource']['resourceId'] ==
                            res['resource']['resourceId']):
                        # must be found
                        vdu_name = inst_vnfc['vduId']
                        vdu_idx = inst_vnfc['metadata']['vdu_idx']
                        image = common_script_utils.get_param_image(
                            vdu_name, flavour_id, vnfd, grant, fallback_vnfd=False)
                        if image is not None:
                            vdus[add_idx(vdu_name, vdu_idx)]['vcImageId'] = image
                        break
    
            nfv_dict = _merge_additional_params({'VDU': vdus}, req, grant)
            fields = {'parameters': {'nfv': nfv_dict}}
    
            return fields
    
        @staticmethod
        def change_vnfpkg(req, inst, grant_req, grant, tmp_csar_dir):
            vnfd = common_script_utils.get_vnfd(grant_req['dstVnfdId'],
                                                tmp_csar_dir)
            flavour_id = inst['instantiatedVnfInfo']['flavourId']
    
            hot_dict = vnfd.get_base_hot(flavour_id)
            top_hot = hot_dict['template']
    
            # first modify VDU resources
            popped_vdu = {}
            for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
                popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
    
            target_vnfc_res_ids = [
                res['resource']['resourceId']
                for res in grant_req['removeResources']
                if res['type'] == 'COMPUTE'
            ]
    
            cur_hot_reses = {}
            new_hot_reses = {}
            for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
                vdu_idx = inst_vnfc['metadata'].get('vdu_idx')
                if vdu_idx is None:
                    # should not be None. just check for consistency.
                    continue
                vdu_name = inst_vnfc['vduId']
                vdu_name_idx = add_idx(vdu_name, vdu_idx)
    
                res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx)
                top_hot['resources'][vdu_name_idx] = res
    
                if (inst_vnfc['computeResource']['resourceId'] in
                        target_vnfc_res_ids):
                    new_hot_reses[vdu_name_idx] = res
                else:
                    cur_hot_reses[vdu_name_idx] = res
    
            cur_nfv_dict = common_script_utils.init_nfv_dict(
                {'resources': cur_hot_reses})
            new_nfv_dict = common_script_utils.init_nfv_dict(
                {'resources': new_hot_reses})
            new_vdus = new_nfv_dict.get('VDU', {})
            vdus = inst['instantiatedVnfInfo']['metadata']['nfv'].get('VDU', {})
    
            for vdu_name_idx, vdu_value in new_vdus.items():
                vdu_name = rm_idx(vdu_name_idx)
                if 'computeFlavourId' in vdu_value:
                    vdus[vdu_name_idx]['computeFlavourId'] = (
                        common_script_utils.get_param_flavor(
                            vdu_name, flavour_id, vnfd, grant))
                if 'vcImageId' in vdu_value:
                    vdus[vdu_name_idx]['vcImageId'] = (
                        common_script_utils.get_param_image(
                            vdu_name, flavour_id, vnfd, grant))
    
            cps = cur_nfv_dict.get('CP', {})
            cps.update(new_nfv_dict.get('CP', {}))
            # NOTE: req includes only different part. some CPs in new_nfv_dict
            # may be necessary to get from inst.
            cur_cps = inst['instantiatedVnfInfo']['metadata']['nfv'].get('CP', {})
            req_cps = _get_new_cps_from_req(cps, req, grant)
            for cp_name in cps.keys():
                if cp_name in req_cps:
                    cps[cp_name] = req_cps[cp_name]
                else:
                    cps[cp_name] = cur_cps[cp_name]
    
            common_script_utils.apply_ext_managed_vls(top_hot, req, grant)
    
            nfv_dict = _merge_additional_params({'VDU': vdus, 'CP': cps},
                                                req, grant)
    
            fields = {
                'template': yaml.safe_dump(top_hot),
                'parameters': {'nfv': nfv_dict},
                'files': {},
                'existing': False
            }
            for key, value in hot_dict.get('files', {}).items():
                fields['files'][key] = yaml.safe_dump(value)
    
            return fields
    
        @staticmethod
        def change_vnfpkg_rollback(req, inst, grant_req, grant, tmp_csar_dir):
            vnfd = common_script_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
            flavour_id = inst['instantiatedVnfInfo']['flavourId']
    
            hot_dict = vnfd.get_base_hot(flavour_id)
            top_hot = hot_dict['template']
    
            # first modify VDU resources
            popped_vdu = {}
            for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys():
                popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name)
    
            for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']:
                vdu_idx = inst_vnfc['metadata'].get('vdu_idx')
                if vdu_idx is None:
                    # should not be None. just check for consistency.
                    continue
                vdu_name = inst_vnfc['vduId']
                vdu_name_idx = add_idx(vdu_name, vdu_idx)
    
                res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx)
                top_hot['resources'][vdu_name_idx] = res
    
            common_script_utils.apply_ext_managed_vls(top_hot, req, grant)
    
            fields = {
                'template': yaml.safe_dump(top_hot),
                'parameters': {
                    'nfv': inst['instantiatedVnfInfo']['metadata']['nfv']},
                'files': {},
                'existing': False
            }
            for key, value in hot_dict.get('files', {}).items():
                fields['files'][key] = yaml.safe_dump(value)
    
            return fields
    
  7. 将 VNF 包 CSAR 压缩为 zip

    $ cd -
    $ cd ./sample_vnf_package_csar
    $ zip sample_vnf_package_csar.zip \
      -r TOSCA-Metadata/ Definitions/ BaseHOT/ Files/
    

    zip 文件中的内容应如下所示。

    $ unzip -Z -1 sample_vnf_package_csar.zip
    TOSCA-Metadata/
    TOSCA-Metadata/TOSCA.meta
    Definitions/
    Definitions/sample_vnfd_types.yaml
    Definitions/etsi_nfv_sol001_vnfd_types.yaml
    Definitions/etsi_nfv_sol001_common_types.yaml
    Definitions/sample_vnfd_df_simple.yaml
    Definitions/sample_vnfd_top.yaml
    BaseHOT/
    BaseHOT/simple/
    BaseHOT/simple/nested/
    BaseHOT/simple/nested/VDU1.yaml
    BaseHOT/simple/sample_lcm_hot.yaml
    Files/
    
    • [这是特定于 UserData 的部分] 使用 UserData 时,添加 UserData 目录。

      $ zip sample_vnf_package_csar.zip -r UserData/
      

      zip 文件中的内容应如下所示。

      $ unzip -Z -1 sample_vnf_package_csar.zip
      TOSCA-Metadata/
      TOSCA-Metadata/TOSCA.meta
      Definitions/
      Definitions/sample_vnfd_types.yaml
      Definitions/etsi_nfv_sol001_vnfd_types.yaml
      Definitions/etsi_nfv_sol001_common_types.yaml
      Definitions/sample_vnfd_df_simple.yaml
      Definitions/sample_vnfd_top.yaml
      BaseHOT/
      BaseHOT/simple/
      BaseHOT/simple/nested/
      BaseHOT/simple/nested/VDU1.yaml
      BaseHOT/simple/sample_lcm_hot.yaml
      Files/
      UserData/
      UserData/__init__.py
      UserData/lcm_user_data.py
      

    在这里,您可以找到示例 VNF 包 CSAR 作为 zip 文件的结构。

创建 VNF 包

  1. 执行 vnfpkgm create

    记下“VNF 包 ID”,因为它将在下一步中使用。

    $ cd -
    $ openstack vnf package create
    +-------------------+-------------------------------------------------------------------------------------------------+
    | Field             | Value                                                                                           |
    +-------------------+-------------------------------------------------------------------------------------------------+
    | ID                | 6e6b7a6d-0ebe-4085-96c2-b34269d837f9                                                            |
    | Links             | {                                                                                               |
    |                   |     "self": {                                                                                   |
    |                   |         "href": "/vnfpkgm/v1/vnf_packages/6e6b7a6d-0ebe-4085-96c2-b34269d837f9"                 |
    |                   |     },                                                                                          |
    |                   |     "packageContent": {                                                                         |
    |                   |         "href": "/vnfpkgm/v1/vnf_packages/6e6b7a6d-0ebe-4085-96c2-b34269d837f9/package_content" |
    |                   |     }                                                                                           |
    |                   | }                                                                                               |
    | Onboarding State  | CREATED                                                                                         |
    | Operational State | DISABLED                                                                                        |
    | Usage State       | NOT_IN_USE                                                                                      |
    | User Defined Data | {}                                                                                              |
    +-------------------+-------------------------------------------------------------------------------------------------+
    

上传 VNF 包

  1. 执行 vnfpkgm upload

    需要将“VNF 包 ID” 6e6b7a6d-0ebe-4085-96c2-b34269d837f9 替换为从 创建 VNF 包 中获得的适当 ID。

    $ openstack vnf package upload \
      --path ./sample_vnf_package_csar/sample_vnf_package_csar.zip \
      6e6b7a6d-0ebe-4085-96c2-b34269d837f9
    Upload request for VNF package 6e6b7a6d-0ebe-4085-96c2-b34269d837f9 has been accepted.
    

检查创建的 VNF 包

  1. 确认“入职状态”为 ONBOARDED

    $ openstack vnf package list
    +--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
    | Id                                   | Vnf Product Name | Onboarding State | Usage State | Operational State | Links                                                                                           |
    +--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
    | 6e6b7a6d-0ebe-4085-96c2-b34269d837f9 | Sample VNF       | ONBOARDED        | NOT_IN_USE  | ENABLED           | {                                                                                               |
    |                                      |                  |                  |             |                   |     "self": {                                                                                   |
    |                                      |                  |                  |             |                   |         "href": "/vnfpkgm/v1/vnf_packages/6e6b7a6d-0ebe-4085-96c2-b34269d837f9"                 |
    |                                      |                  |                  |             |                   |     },                                                                                          |
    |                                      |                  |                  |             |                   |     "packageContent": {                                                                         |
    |                                      |                  |                  |             |                   |         "href": "/vnfpkgm/v1/vnf_packages/6e6b7a6d-0ebe-4085-96c2-b34269d837f9/package_content" |
    |                                      |                  |                  |             |                   |     }                                                                                           |
    |                                      |                  |                  |             |                   | }                                                                                               |
    +--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
    

创建和实例化 VNF

创建 VNF

  1. 查找创建 VNF 的“VNFD ID”

    示例中可以找到“VNFD ID”为 b1bb0ce7-ebca-4fa7-95ed-4840d70a1177

    $ openstack vnf package show \
      6e6b7a6d-0ebe-4085-96c2-b34269d837f9 -c 'VNFD ID'
    +---------+--------------------------------------+
    | Field   | Value                                |
    +---------+--------------------------------------+
    | VNFD ID | b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 |
    +---------+--------------------------------------+
    
  2. 创建 VNF

    需要将“VNFD ID” b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 替换为适当的 ID。

    $ openstack vnflcm create b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 \
      --os-tacker-api-version 2
    +-----------------------------+------------------------------------------------------------------------------------------------------------------+
    | Field                       | Value                                                                                                            |
    +-----------------------------+------------------------------------------------------------------------------------------------------------------+
    | ID                          | c98b05c7-bc96-43f8-a688-4d8079ffa3bf                                                                             |
    | Instantiation State         | NOT_INSTANTIATED                                                                                                 |
    | Links                       | {                                                                                                                |
    |                             |     "self": {                                                                                                    |
    |                             |         "href": "http://127.0.0.1:9890/vnflcm/v2/vnf_instances/c98b05c7-bc96-43f8-a688-4d8079ffa3bf"             |
    |                             |     },                                                                                                           |
    |                             |     "instantiate": {                                                                                             |
    |                             |         "href": "http://127.0.0.1:9890/vnflcm/v2/vnf_instances/c98b05c7-bc96-43f8-a688-4d8079ffa3bf/instantiate" |
    |                             |     }                                                                                                            |
    |                             | }                                                                                                                |
    | VNF Configurable Properties |                                                                                                                  |
    | VNF Instance Description    |                                                                                                                  |
    | VNF Instance Name           |                                                                                                                  |
    | VNF Product Name            | Sample VNF                                                                                                       |
    | VNF Provider                | Company                                                                                                          |
    | VNF Software Version        | 1.0                                                                                                              |
    | VNFD ID                     | b1bb0ce7-ebca-4fa7-95ed-4840d70a1177                                                                             |
    | VNFD Version                | 1.0                                                                                                              |
    +-----------------------------+------------------------------------------------------------------------------------------------------------------+
    

实例化 VNF

  1. 创建 <param-file>

    必需参数

    • flavourId

    可选参数

    • instantiationLevelId

    • extVirtualLinks

    • extManagedVirtualLinks

    • vimConnectionInfo

    • localizationLanguage

    • additionalParams

    • extensions

    • vnfConfigurableProperties

    注意

    只有在您拥有默认 VIM 时,才能跳过 vimConnectionInfo

    一个名为 sample_request.json 的示例 <param-file>,包含最小参数

    $ vi ./sample_request.json
    
    {
      "flavourId": "simple"
    }
    
    • [这是特定于 UserData 的部分] 使用 UserData 时,使用以下参数。

      {
        "flavourId":"simple",
        "additionalParams": {
          "lcm-operation-user-data": "./UserData/userdata_standard.py",
          "lcm-operation-user-data-class": "StandardUserData"
        }
      }
      

      注意

      userdata_standard.py 应该替换为 UserData 文件名。 StandardUserData 应该替换为 UserData 类名。

  2. 实例化 VNF

    需要“vnf 实例的 ID”和“指向 <param-file> 的路径”来实例化 vnf。

    $ openstack vnflcm instantiate c98b05c7-bc96-43f8-a688-4d8079ffa3bf \
      ./sample_request.json --os-tacker-api-version 2
    Instantiate request for VNF Instance c98b05c7-bc96-43f8-a688-4d8079ffa3bf has been accepted.
    

    检查实例化 vnf 的详细信息。

    $ openstack vnflcm list --os-tacker-api-version 2
    +--------------------------------------+-------------------+---------------------+--------------+----------------------+------------------+--------------------------------------+
    | ID                                   | VNF Instance Name | Instantiation State | VNF Provider | VNF Software Version | VNF Product Name | VNFD ID                              |
    +--------------------------------------+-------------------+---------------------+--------------+----------------------+------------------+--------------------------------------+
    | c98b05c7-bc96-43f8-a688-4d8079ffa3bf |                   | INSTANTIATED        | Company      | 1.0                  | Sample VNF       | b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 |
    +--------------------------------------+-------------------+---------------------+--------------+----------------------+------------------+--------------------------------------+
    
    $ openstack vnflcm show c98b05c7-bc96-43f8-a688-4d8079ffa3bf \
     --fit-width --os-tacker-api-version 2
    +-----------------------------+--------------------------------------------------------------------------------------------------------------------------------+
    | Field                       | Value                                                                                                                          |
    +-----------------------------+--------------------------------------------------------------------------------------------------------------------------------+
    | ID                          | c98b05c7-bc96-43f8-a688-4d8079ffa3bf                                                                                           |
    | Instantiated Vnf Info       | {                                                                                                                              |
    |                             |     "flavourId": "simple",                                                                                                     |
    |                             |     "vnfState": "STARTED",                                                                                                     |
    |                             |     "scaleStatus": [                                                                                                           |
    |                             |         {                                                                                                                      |
    |                             |             "aspectId": "VDU1_scale",                                                                                          |
    |                             |             "scaleLevel": 0                                                                                                    |
    |                             |         }                                                                                                                      |
    |                             |     ],                                                                                                                         |
    |                             |     "maxScaleLevels": [                                                                                                        |
    |                             |         {                                                                                                                      |
    |                             |             "aspectId": "VDU1_scale",                                                                                          |
    |                             |             "scaleLevel": 2                                                                                                    |
    |                             |         }                                                                                                                      |
    |                             |     ],                                                                                                                         |
    |                             |     "vnfcResourceInfo": [                                                                                                      |
    |                             |         {                                                                                                                      |
    |                             |             "id": "6d01be26-f2be-421d-8c87-a4aa9d39300e",                                                                      |
    |                             |             "vduId": "VDU1",                                                                                                   |
    |                             |             "computeResource": {                                                                                               |
    |                             |                 "vimConnectionId": "bff267c4-6fc9-46b5-be53-15a6a3680033",                                                     |
    |                             |                 "resourceId": "6d01be26-f2be-421d-8c87-a4aa9d39300e",                                                          |
    |                             |                 "vimLevelResourceType": "OS::Nova::Server"                                                                     |
    |                             |             },                                                                                                                 |
    |                             |             "vnfcCpInfo": [                                                                                                    |
    |                             |                 {                                                                                                              |
    |                             |                     "id": "CP1-6d01be26-f2be-421d-8c87-a4aa9d39300e",                                                          |
    |                             |                     "cpdId": "CP1"                                                                                             |
    |                             |                 }                                                                                                              |
    |                             |             ],                                                                                                                 |
    |                             |             "metadata": {                                                                                                      |
    |                             |                 "creation_time": "2023-12-01T06:57:11Z",                                                                       |
    |                             |                 "stack_id": "vnf-c98b05c7-bc96-43f8-a688-4d8079ffa3bf-VDU1-6523jolwu66g/09019137-3b71-426e-8726-8572657999b2", |
    |                             |                 "vdu_idx": null,                                                                                               |
    |                             |                 "flavor": "m1.tiny",                                                                                           |
    |                             |                 "image-VDU1": "cirros-0.5.2-x86_64-disk"                                                                       |
    |                             |             }                                                                                                                  |
    |                             |         }                                                                                                                      |
    |                             |     ],                                                                                                                         |
    |                             |     "vnfVirtualLinkResourceInfo": [                                                                                            |
    |                             |         {                                                                                                                      |
    |                             |             "id": "ffa3b9cf-5135-4dc6-a7a1-dd1912d72363",                                                                      |
    |                             |             "vnfVirtualLinkDescId": "internalVL1",                                                                             |
    |                             |             "networkResource": {                                                                                               |
    |                             |                 "vimConnectionId": "bff267c4-6fc9-46b5-be53-15a6a3680033",                                                     |
    |                             |                 "resourceId": "ffa3b9cf-5135-4dc6-a7a1-dd1912d72363",                                                          |
    |                             |                 "vimLevelResourceType": "OS::Neutron::Net"                                                                     |
    |                             |             }                                                                                                                  |
    |                             |         }                                                                                                                      |
    |                             |     ],                                                                                                                         |
    |                             |     "vnfcInfo": [                                                                                                              |
    |                             |         {                                                                                                                      |
    |                             |             "id": "VDU1-6d01be26-f2be-421d-8c87-a4aa9d39300e",                                                                 |
    |                             |             "vduId": "VDU1",                                                                                                   |
    |                             |             "vnfcResourceInfoId": "6d01be26-f2be-421d-8c87-a4aa9d39300e",                                                      |
    |                             |             "vnfcState": "STARTED"                                                                                             |
    |                             |         }                                                                                                                      |
    |                             |     ],                                                                                                                         |
    |                             |     "metadata": {                                                                                                              |
    |                             |         "stack_id": "0b1b274c-a493-4a2c-994f-ee8569ff111c",                                                                    |
    |                             |         "nfv": {                                                                                                               |
    |                             |             "VDU": {                                                                                                           |
    |                             |                 "VDU1": {                                                                                                      |
    |                             |                     "computeFlavourId": "m1.tiny",                                                                             |
    |                             |                     "vcImageId": "cirros-0.5.2-x86_64-disk"                                                                    |
    |                             |                 }                                                                                                              |
    |                             |             }                                                                                                                  |
    |                             |         },                                                                                                                     |
    |                             |         "tenant": "nfv"                                                                                                        |
    |                             |     }                                                                                                                          |
    |                             | }                                                                                                                              |
    | Instantiation State         | INSTANTIATED                                                                                                                   |
    | Links                       | {                                                                                                                              |
    |                             |     "self": {                                                                                                                  |
    |                             |         "href": "http://127.0.0.1:9890/vnflcm/v2/vnf_instances/c98b05c7-bc96-43f8-a688-4d8079ffa3bf"                           |
    |                             |     },                                                                                                                         |
    |                             |     "terminate": {                                                                                                             |
    |                             |         "href": "http://127.0.0.1:9890/vnflcm/v2/vnf_instances/c98b05c7-bc96-43f8-a688-4d8079ffa3bf/terminate"                 |
    |                             |     },                                                                                                                         |
    |                             |     "scale": {                                                                                                                 |
    |                             |         "href": "http://127.0.0.1:9890/vnflcm/v2/vnf_instances/c98b05c7-bc96-43f8-a688-4d8079ffa3bf/scale"                     |
    |                             |     },                                                                                                                         |
    |                             |     "heal": {                                                                                                                  |
    |                             |         "href": "http://127.0.0.1:9890/vnflcm/v2/vnf_instances/c98b05c7-bc96-43f8-a688-4d8079ffa3bf/heal"                      |
    |                             |     },                                                                                                                         |
    |                             |     "changeExtConn": {                                                                                                         |
    |                             |         "href": "http://127.0.0.1:9890/vnflcm/v2/vnf_instances/c98b05c7-bc96-43f8-a688-4d8079ffa3bf/change_ext_conn"           |
    |                             |     }                                                                                                                          |
    |                             | }                                                                                                                              |
    | VIM Connection Info         | {                                                                                                                              |
    |                             |     "default": {                                                                                                               |
    |                             |         "vimId": "bff267c4-6fc9-46b5-be53-15a6a3680033",                                                                       |
    |                             |         "vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3",                                                                           |
    |                             |         "interfaceInfo": {                                                                                                     |
    |                             |             "endpoint": "http://192.168.56.10/identity/v3",                                                                    |
    |                             |             "skipCertificateHostnameCheck": true,                                                                              |
    |                             |             "skipCertificateVerification": true                                                                                |
    |                             |         },                                                                                                                     |
    |                             |         "accessInfo": {                                                                                                        |
    |                             |             "username": "nfv_user",                                                                                            |
    |                             |             "region": "RegionOne",                                                                                             |
    |                             |             "project": "nfv",                                                                                                  |
    |                             |             "projectDomain": "default",                                                                                        |
    |                             |             "userDomain": "default"                                                                                            |
    |                             |         },                                                                                                                     |
    |                             |         "extra": {}                                                                                                            |
    |                             |     }                                                                                                                          |
    |                             | }                                                                                                                              |
    | VNF Configurable Properties |                                                                                                                                |
    | VNF Instance Description    |                                                                                                                                |
    | VNF Instance Name           |                                                                                                                                |
    | VNF Product Name            | Sample VNF                                                                                                                     |
    | VNF Provider                | Company                                                                                                                        |
    | VNF Software Version        | 1.0                                                                                                                            |
    | VNFD ID                     | b1bb0ce7-ebca-4fa7-95ed-4840d70a1177                                                                                           |
    | VNFD Version                | 1.0                                                                                                                            |
    +-----------------------------+--------------------------------------------------------------------------------------------------------------------------------+
    

终止和删除 VNF

终止 VNF

  1. 检查要终止的 VNF 实例 ID

    $ openstack vnflcm list --os-tacker-api-version 2
    +--------------------------------------+-------------------+---------------------+--------------+----------------------+------------------+--------------------------------------+
    | ID                                   | VNF Instance Name | Instantiation State | VNF Provider | VNF Software Version | VNF Product Name | VNFD ID                              |
    +--------------------------------------+-------------------+---------------------+--------------+----------------------+------------------+--------------------------------------+
    | c98b05c7-bc96-43f8-a688-4d8079ffa3bf |                   | INSTANTIATED        | Company      | 1.0                  | Sample VNF       | b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 |
    +--------------------------------------+-------------------+---------------------+--------------+----------------------+------------------+--------------------------------------+
    
  2. 终止 VNF 实例

    执行终止命令

    $ openstack vnflcm terminate c98b05c7-bc96-43f8-a688-4d8079ffa3bf --os-tacker-api-version 2
    Terminate request for VNF Instance 'c98b05c7-bc96-43f8-a688-4d8079ffa3bf' has been accepted.
    

    检查 VNF 实例的状态

    $ openstack vnflcm list --os-tacker-api-version 2
    +--------------------------------------+-------------------+---------------------+--------------+----------------------+------------------+--------------------------------------+
    | ID                                   | VNF Instance Name | Instantiation State | VNF Provider | VNF Software Version | VNF Product Name | VNFD ID                              |
    +--------------------------------------+-------------------+---------------------+--------------+----------------------+------------------+--------------------------------------+
    | c98b05c7-bc96-43f8-a688-4d8079ffa3bf |                   | NOT_INSTANTIATED    | Company      | 1.0                  | Sample VNF       | b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 |
    +--------------------------------------+-------------------+---------------------+--------------+----------------------+------------------+--------------------------------------+
    

删除 VNF

  1. 删除 VNF 实例

    $ openstack vnflcm delete c98b05c7-bc96-43f8-a688-4d8079ffa3bf --os-tacker-api-version 2
    Vnf instance 'c98b05c7-bc96-43f8-a688-4d8079ffa3bf' is deleted successfully
    

删除 VNF 包

  1. 删除 VNF 包

    检查要删除的 VNF 包 ID

    $ openstack vnf package list
    +--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
    | Id                                   | Vnf Product Name | Onboarding State | Usage State | Operational State | Links                                                                                           |
    +--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
    | 6e6b7a6d-0ebe-4085-96c2-b34269d837f9 | Sample VNF       | ONBOARDED        | NOT_IN_USE  | ENABLED           | {                                                                                               |
    |                                      |                  |                  |             |                   |     "self": {                                                                                   |
    |                                      |                  |                  |             |                   |         "href": "/vnfpkgm/v1/vnf_packages/6e6b7a6d-0ebe-4085-96c2-b34269d837f9"                 |
    |                                      |                  |                  |             |                   |     },                                                                                          |
    |                                      |                  |                  |             |                   |     "packageContent": {                                                                         |
    |                                      |                  |                  |             |                   |         "href": "/vnfpkgm/v1/vnf_packages/6e6b7a6d-0ebe-4085-96c2-b34269d837f9/package_content" |
    |                                      |                  |                  |             |                   |     }                                                                                           |
    |                                      |                  |                  |             |                   | }                                                                                               |
    +--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
    

    将运行状态更新为 DISABLED

    $ openstack vnf package update --operational-state 'DISABLED' \
      6e6b7a6d-0ebe-4085-96c2-b34269d837f9
    +-------------------+----------+
    | Field             | Value    |
    +-------------------+----------+
    | Operational State | DISABLED |
    +-------------------+----------+
    

    检查运行状态是否已更改

    $ openstack vnf package list
    +--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
    | Id                                   | Vnf Product Name | Onboarding State | Usage State | Operational State | Links                                                                                           |
    +--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
    | 6e6b7a6d-0ebe-4085-96c2-b34269d837f9 | Sample VNF       | ONBOARDED        | NOT_IN_USE  | DISABLED          | {                                                                                               |
    |                                      |                  |                  |             |                   |     "self": {                                                                                   |
    |                                      |                  |                  |             |                   |         "href": "/vnfpkgm/v1/vnf_packages/6e6b7a6d-0ebe-4085-96c2-b34269d837f9"                 |
    |                                      |                  |                  |             |                   |     },                                                                                          |
    |                                      |                  |                  |             |                   |     "packageContent": {                                                                         |
    |                                      |                  |                  |             |                   |         "href": "/vnfpkgm/v1/vnf_packages/6e6b7a6d-0ebe-4085-96c2-b34269d837f9/package_content" |
    |                                      |                  |                  |             |                   |     }                                                                                           |
    |                                      |                  |                  |             |                   | }                                                                                               |
    +--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
    

    删除 VNF 包

    $ openstack vnf package delete 6e6b7a6d-0ebe-4085-96c2-b34269d837f9
    All specified vnf-package(s) deleted successfully