Support VNF create from inline template
Accept transient VNFD template as part of VNF creation without need for VNFD onboarding into Tacker VNFD catalog. Change-Id: I3c8bbe139dec27adbfc943d3ac9f909db8097f89 Implements: blueprint vnf-inline-template Depends-On: I719237dd04dd7fe13fb7e7964402d7074679b2d6
This commit is contained in:
parent
3e238f1bc4
commit
a3ea91d124
@ -709,7 +709,19 @@ vnfd_id:
|
||||
description: |
|
||||
The UUID of the VNFD.
|
||||
in: body
|
||||
required: true
|
||||
required: false
|
||||
type: string
|
||||
vnfd_template:
|
||||
description: |
|
||||
Template to create VNF.
|
||||
in: body
|
||||
required: false
|
||||
type: object
|
||||
vnfd_template_source:
|
||||
description: |
|
||||
Source of VNFD.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
vnfds:
|
||||
description: |
|
||||
|
@ -15,7 +15,8 @@
|
||||
"vnfd": "description: Demo example\nmetadata: {template_name: sample-tosca-vnfd}\ntopology_template:\n node_templates:\n CP1:\n properties: {anti_spoofing_protection: false, management: true, order: 0}\n requirements:\n - virtualLink: {node: VL1}\n - virtualBinding: {node: VDU1}\n type: tosca.nodes.nfv.CP.Tacker\n VDU1:\n capabilities:\n nfv_compute:\n properties: {disk_size: 1 GB, mem_size: 512 MB, num_cpus: 1}\n properties: {image: cirros-0.3.4-x86_64-uec}\n type: tosca.nodes.nfv.VDU.Tacker\n VL1:\n properties: {network_name: net_mgmt, vendor: Tacker}\n type: tosca.nodes.nfv.VL\ntosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0\n"
|
||||
},
|
||||
"id": "0fb827e7-32b0-4e5b-b300-e1b1dce8a831",
|
||||
"name": "vnfd-sample"
|
||||
"name": "vnfd-sample",
|
||||
"template_source": "onboarded or inline"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
"vnfd": "description: Demo example\nmetadata: {template_name: sample-tosca-vnfd}\ntopology_template:\n node_templates:\n CP1:\n properties: {anti_spoofing_protection: false, management: true, order: 0}\n requirements:\n - virtualLink: {node: VL1}\n - virtualBinding: {node: VDU1}\n type: tosca.nodes.nfv.CP.Tacker\n VDU1:\n capabilities:\n nfv_compute:\n properties: {disk_size: 1 GB, mem_size: 512 MB, num_cpus: 1}\n properties: {image: cirros-0.3.4-x86_64-uec}\n type: tosca.nodes.nfv.VDU.Tacker\n VL1:\n properties: {network_name: net_mgmt, vendor: Tacker}\n type: tosca.nodes.nfv.VL\ntosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0\n"
|
||||
},
|
||||
"id": "0fb827e7-32b0-4e5b-b300-e1b1dce8a831",
|
||||
"name": "vnfd-sample"
|
||||
"name": "vnfd-sample",
|
||||
"template_source": "onboarded or inline"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
{
|
||||
"vnf": {
|
||||
"tenant_id": "6673e4d4e13340acb0b847f9ecde613b",
|
||||
"vim_id": "f6bd6f24-7a0e-4111-8994-e108c5ee2ff2",
|
||||
"name": "OpenWRT",
|
||||
"description": "OpenWRT VNF",
|
||||
"attributes": {
|
||||
"config": {
|
||||
"vdus": {
|
||||
"vdu1": {
|
||||
"config": {
|
||||
"firewall": "package firewall\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"param_values": {
|
||||
"vdus": {
|
||||
"vdu1": {
|
||||
"param": {
|
||||
"vdu-name": "openwrt_vdu1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"placement_attr": {
|
||||
"region_name": "RegionOne"
|
||||
},
|
||||
"vnfd_template": {
|
||||
"tosca_definitions_version": "tosca_simple_profile_for_nfv_1_0_0",
|
||||
"description": "Demo example",
|
||||
"metadata": {
|
||||
"template_name": "sample-tosca-vnfd"},
|
||||
"topology_template": {
|
||||
"node_templates": {
|
||||
"VDU1": {
|
||||
"type": "tosca.nodes.nfv.VDU.Tacker",
|
||||
"capabilities": {
|
||||
"nfv_compute": {
|
||||
"properties": {
|
||||
"num_cpus": 1,
|
||||
"mem_size": "512 MB",
|
||||
"disk_size": "1 GB"}}},
|
||||
"properties": {"image": "cirros-0.3.4-x86_64-uec"}},
|
||||
"CP1": {
|
||||
"type": "tosca.nodes.nfv.CP.Tacker",
|
||||
"properties": {
|
||||
"order": 0,
|
||||
"management": true,
|
||||
"anti_spoofing_protection": false},
|
||||
"requirements": [
|
||||
{"virtualLink": {
|
||||
"node": "VL1"}},
|
||||
{"virtualBinding": {
|
||||
"node": "VDU1"}}]},
|
||||
"VL1": {
|
||||
"type": "tosca.nodes.nfv.VL",
|
||||
"properties": {
|
||||
"vendor": "Tacker",
|
||||
"network_name": "net_mgmt"}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -102,6 +102,7 @@ Response Parameters
|
||||
- attributes: vnfd_attributes
|
||||
- id: vnfd_id
|
||||
- name: name
|
||||
- template_source: vnfd_template_source
|
||||
|
||||
|
||||
Response Example
|
||||
@ -151,6 +152,7 @@ Response Parameters
|
||||
- attributes: vnfd_attributes
|
||||
- id: vnfd_id
|
||||
- name: name
|
||||
- template_source: vnfd_template_source
|
||||
|
||||
Response Example
|
||||
----------------
|
||||
|
@ -44,6 +44,7 @@ Request Parameters
|
||||
- config: vnf_config_opt
|
||||
- param_values: vnf_param_values_opt
|
||||
- placement_attr: vnf_placement_attr_opt
|
||||
- vnfd_template: vnfd_template
|
||||
|
||||
Request Example
|
||||
---------------
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- Support VNF create with direct VNFD template input via CLI/API without
|
||||
onboarding VNFD.
|
@ -563,6 +563,11 @@ class Controller(object):
|
||||
if 'validate' not in attr_vals:
|
||||
continue
|
||||
for rule in attr_vals['validate']:
|
||||
# skip validating vnfd_id when vnfd_template is specified to
|
||||
# create vnf
|
||||
if resource == 'vnf' and 'vnfd_template' in body['vnf'] and \
|
||||
attr == "vnfd_id" and is_create:
|
||||
continue
|
||||
res = attributes.validators[rule](res_dict[attr],
|
||||
attr_vals['validate'][rule])
|
||||
if res:
|
||||
|
@ -21,8 +21,10 @@
|
||||
import functools
|
||||
import logging as std_logging
|
||||
import os
|
||||
import random
|
||||
import signal
|
||||
import socket
|
||||
import string
|
||||
import sys
|
||||
|
||||
from eventlet.green import subprocess
|
||||
@ -306,3 +308,11 @@ def deprecate_warning(what, as_of, in_favor_of=None, remove_in=1):
|
||||
versionutils.deprecation_warning(as_of=as_of, what=what,
|
||||
in_favor_of=in_favor_of,
|
||||
remove_in=remove_in)
|
||||
|
||||
|
||||
def generate_resource_name(resource, prefix='tmpl'):
|
||||
return prefix + '-' \
|
||||
+ ''.join(random.SystemRandom().choice(
|
||||
string.ascii_lowercase + string.digits)
|
||||
for _ in range(16)) \
|
||||
+ '-' + resource
|
||||
|
@ -0,0 +1,33 @@
|
||||
# Copyright 2016 OpenStack Foundation
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# http://www.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.
|
||||
#
|
||||
|
||||
"""add template_source column
|
||||
|
||||
Revision ID: 000632983ada
|
||||
Revises: 0ae5b1ce3024
|
||||
Create Date: 2016-12-22 20:30:03.931290
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '000632983ada'
|
||||
down_revision = '0ad3bbce1c19'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade(active_plugins=None, options=None):
|
||||
op.add_column('vnfd', sa.Column('template_source', sa.String(length=255)))
|
@ -1 +1 @@
|
||||
0ad3bbce1c19
|
||||
000632983ada
|
||||
|
@ -67,6 +67,9 @@ class VNFD(model_base.BASE, models_v1.HasId, models_v1.HasTenant,
|
||||
attributes = orm.relationship('VNFDAttribute',
|
||||
backref='vnfd')
|
||||
|
||||
# vnfd template source - inline or onboarded
|
||||
template_source = sa.Column(sa.String(255))
|
||||
|
||||
|
||||
class ServiceType(model_base.BASE, models_v1.HasId, models_v1.HasTenant):
|
||||
"""Represents service type which hosting vnf provides.
|
||||
@ -184,7 +187,8 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
vnfd.service_types)
|
||||
}
|
||||
key_list = ('id', 'tenant_id', 'name', 'description',
|
||||
'mgmt_driver', 'created_at', 'updated_at')
|
||||
'mgmt_driver', 'created_at', 'updated_at',
|
||||
'template_source')
|
||||
res.update((key, vnfd[key]) for key in key_list)
|
||||
return self._fields(res, fields)
|
||||
|
||||
@ -219,6 +223,7 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
tenant_id = self._get_tenant_id_for_create(context, vnfd)
|
||||
service_types = vnfd.get('service_types')
|
||||
mgmt_driver = vnfd.get('mgmt_driver')
|
||||
template_source = vnfd.get("template_source")
|
||||
|
||||
if (not attributes.is_attr_set(service_types)):
|
||||
LOG.debug(_('service types unspecified'))
|
||||
@ -231,7 +236,8 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
tenant_id=tenant_id,
|
||||
name=vnfd.get('name'),
|
||||
description=vnfd.get('description'),
|
||||
mgmt_driver=mgmt_driver)
|
||||
mgmt_driver=mgmt_driver,
|
||||
template_source=template_source)
|
||||
context.session.add(vnfd_db)
|
||||
for (key, value) in vnfd.get('attributes', {}).items():
|
||||
attribute_db = VNFDAttribute(
|
||||
@ -288,9 +294,7 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
vnfs_db = context.session.query(VNF).filter_by(
|
||||
vnfd_id=vnfd_id).first()
|
||||
if vnfs_db is not None and vnfs_db.deleted_at is None:
|
||||
raise vnfm.VNFDInUse(
|
||||
vnfd_id=vnfd_id)
|
||||
|
||||
raise vnfm.VNFDInUse(vnfd_id=vnfd_id)
|
||||
vnfd_db = self._get_resource(context, VNFD,
|
||||
vnfd_id)
|
||||
if soft_delete:
|
||||
@ -313,6 +317,9 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
return self._make_vnfd_dict(vnfd_db)
|
||||
|
||||
def get_vnfds(self, context, filters, fields=None):
|
||||
if 'template_source' in filters and \
|
||||
filters['template_source'][0] == 'all':
|
||||
filters.pop('template_source')
|
||||
return self._get_collection(context, VNFD,
|
||||
self._make_vnfd_dict,
|
||||
filters=filters, fields=fields)
|
||||
@ -521,7 +528,8 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
tstamp=timeutils.utcnow(), details="VNF delete initiated")
|
||||
return deleted_vnf_db
|
||||
|
||||
def _delete_vnf_post(self, context, vnf_id, error, soft_delete=True):
|
||||
def _delete_vnf_post(self, context, vnf_dict, error, soft_delete=True):
|
||||
vnf_id = vnf_dict['id']
|
||||
with context.session.begin(subtransactions=True):
|
||||
query = (
|
||||
self._model_query(context, VNF).
|
||||
@ -552,6 +560,10 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
filter(VNFAttribute.vnf_id == vnf_id).delete())
|
||||
query.delete()
|
||||
|
||||
# Delete corresponding vnfd
|
||||
if vnf_dict['vnfd']['template_source'] == "inline":
|
||||
self.delete_vnfd(context, vnf_dict["vnfd_id"])
|
||||
|
||||
# reference implementation. needs to be overrided by subclass
|
||||
def create_vnf(self, context, vnf):
|
||||
vnf_dict = self._create_vnf_pre(context, vnf)
|
||||
@ -577,12 +589,12 @@ class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
|
||||
|
||||
# reference implementation. needs to be overrided by subclass
|
||||
def delete_vnf(self, context, vnf_id, soft_delete=True):
|
||||
self._delete_vnf_pre(context, vnf_id)
|
||||
vnf_dict = self._delete_vnf_pre(context, vnf_id)
|
||||
# start actual deletion of hosting vnf.
|
||||
# Waiting for completion of deletion should be done backgroundly
|
||||
# by another thread if it takes a while.
|
||||
self._delete_vnf_post(context,
|
||||
vnf_id,
|
||||
vnf_dict,
|
||||
False,
|
||||
soft_delete=soft_delete)
|
||||
|
||||
|
@ -236,6 +236,12 @@ RESOURCE_ATTRIBUTE_MAP = {
|
||||
'allow_put': False,
|
||||
'is_visible': True,
|
||||
},
|
||||
'template_source': {
|
||||
'allow_post': False,
|
||||
'allow_put': False,
|
||||
'is_visible': True,
|
||||
'default': 'onboarded'
|
||||
},
|
||||
},
|
||||
|
||||
'vnfs': {
|
||||
@ -258,6 +264,7 @@ RESOURCE_ATTRIBUTE_MAP = {
|
||||
'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'default': None
|
||||
},
|
||||
'vim_id': {
|
||||
'allow_post': True,
|
||||
@ -325,6 +332,13 @@ RESOURCE_ATTRIBUTE_MAP = {
|
||||
'allow_put': False,
|
||||
'is_visible': True,
|
||||
},
|
||||
'vnfd_template': {
|
||||
'allow_post': True,
|
||||
'allow_put': False,
|
||||
'validate': {'type:dict_or_none': None},
|
||||
'is_visible': True,
|
||||
'default': None,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,8 @@ VNF_CIRROS_CREATE_TIMEOUT = 120
|
||||
|
||||
|
||||
class VnfTestToscaCreate(base.BaseTackerTest):
|
||||
def _test_create_vnf(self, vnfd_file, vnf_name):
|
||||
def _test_create_vnf(self, vnfd_file, vnf_name,
|
||||
template_source="onboarded"):
|
||||
data = dict()
|
||||
values_str = read_file(vnfd_file)
|
||||
data['tosca'] = values_str
|
||||
@ -36,16 +37,23 @@ class VnfTestToscaCreate(base.BaseTackerTest):
|
||||
tosca_arg = {'vnfd': {'name': vnf_name,
|
||||
'attributes': {'vnfd': toscal}}}
|
||||
|
||||
# Create vnfd with tosca template
|
||||
vnfd_instance = self.client.create_vnfd(body=tosca_arg)
|
||||
self.assertIsNotNone(vnfd_instance)
|
||||
if template_source == "onboarded":
|
||||
# Create vnfd with tosca template
|
||||
vnfd_instance = self.client.create_vnfd(body=tosca_arg)
|
||||
self.assertIsNotNone(vnfd_instance)
|
||||
|
||||
# Create vnf with vnfd_id
|
||||
vnfd_id = vnfd_instance['vnfd']['id']
|
||||
vnf_arg = {'vnf': {'vnfd_id': vnfd_id, 'name': vnf_name}}
|
||||
vnf_instance = self.client.create_vnf(body=vnf_arg)
|
||||
# Create vnf with vnfd_id
|
||||
vnfd_id = vnfd_instance['vnfd']['id']
|
||||
vnf_arg = {'vnf': {'vnfd_id': vnfd_id, 'name': vnf_name}}
|
||||
vnf_instance = self.client.create_vnf(body=vnf_arg)
|
||||
self.validate_vnf_instance(vnfd_instance, vnf_instance)
|
||||
|
||||
self.validate_vnf_instance(vnfd_instance, vnf_instance)
|
||||
if template_source == 'inline':
|
||||
# create vnf directly from template
|
||||
template = yaml.load(values_str)
|
||||
vnf_arg = {'vnf': {'vnfd_template': template, 'name': vnf_name}}
|
||||
vnf_instance = self.client.create_vnf(body=vnf_arg)
|
||||
vnfd_id = vnf_instance['vnf']['vnfd_id']
|
||||
|
||||
vnf_id = vnf_instance['vnf']['id']
|
||||
self.wait_until_vnf_active(
|
||||
@ -100,10 +108,10 @@ class VnfTestToscaCreate(base.BaseTackerTest):
|
||||
self.addCleanup(self.wait_until_vnf_delete, vnf_id,
|
||||
constants.VNF_CIRROS_DELETE_TIMEOUT)
|
||||
|
||||
def test_create_delete_vnf_tosca(self):
|
||||
vnfd_id, vnf_id = self._test_create_vnf(
|
||||
'sample-tosca-vnfd.yaml',
|
||||
'test_tosca_vnf_with_cirros')
|
||||
def _test_create_delete_vnf_tosca(self, vnfd_file, vnf_name,
|
||||
template_source):
|
||||
vnfd_id, vnf_id = self._test_create_vnf(vnfd_file, vnf_name,
|
||||
template_source)
|
||||
servers = self.novaclient().servers.list()
|
||||
vdus = []
|
||||
for server in servers:
|
||||
@ -116,7 +124,18 @@ class VnfTestToscaCreate(base.BaseTackerTest):
|
||||
vdu_ports.append(port['name'])
|
||||
self.assertIn('test-cp', vdu_ports)
|
||||
self._test_delete_vnf(vnf_id)
|
||||
self._test_cleanup_vnfd(vnfd_id, vnf_id)
|
||||
if template_source == "onboarded":
|
||||
self._test_cleanup_vnfd(vnfd_id, vnf_id)
|
||||
|
||||
def test_create_delete_vnf_tosca_from_vnfd(self):
|
||||
self._test_create_delete_vnf_tosca('sample-tosca-vnfd.yaml',
|
||||
'test_tosca_vnf_with_cirros',
|
||||
'onboarded')
|
||||
|
||||
def test_create_delete_vnf_from_template(self):
|
||||
self._test_create_delete_vnf_tosca('sample-tosca-vnfd.yaml',
|
||||
'test_tosca_vnf_with_cirros_inline',
|
||||
'inline')
|
||||
|
||||
def test_create_delete_vnf_static_ip(self):
|
||||
vnfd_id, vnf_id = self._test_create_vnf(
|
||||
|
@ -46,9 +46,31 @@ def get_dummy_vnfd_obj():
|
||||
'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437',
|
||||
u'attributes': {u'vnfd': yaml.safe_load(
|
||||
tosca_vnfd_openwrt)},
|
||||
'description': 'dummy_vnfd_description'},
|
||||
'description': 'dummy_vnfd_description',
|
||||
'template_source': 'onboarded',
|
||||
u'auth': {u'tenantName': u'admin', u'passwordCredentials': {
|
||||
u'username': u'admin', u'password': u'devstack'}}}
|
||||
u'username': u'admin', u'password': u'devstack'}}}}
|
||||
|
||||
|
||||
def get_dummy_vnfd_obj_inline():
|
||||
return {u'vnfd': {u'service_types': [{u'service_type': u'vnfd'}],
|
||||
'name': 'tmpl-koeak4tqgoqo8cr4-dummy_inline_vnf',
|
||||
'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437',
|
||||
u'attributes': {u'vnfd': yaml.safe_load(
|
||||
tosca_vnfd_openwrt)},
|
||||
'template_source': 'inline',
|
||||
u'auth': {u'tenantName': u'admin', u'passwordCredentials': {
|
||||
u'username': u'admin', u'password': u'devstack'}}}}
|
||||
|
||||
|
||||
def get_dummy_inline_vnf_obj():
|
||||
return {'vnf': {'description': 'dummy_inline_vnf_description',
|
||||
'vnfd_template': yaml.safe_load(tosca_vnfd_openwrt),
|
||||
'vim_id': u'6261579e-d6f3-49ad-8bc3-a9cb974778ff',
|
||||
'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437',
|
||||
'name': 'dummy_inline_vnf',
|
||||
'attributes': {},
|
||||
'vnfd_id': None}}
|
||||
|
||||
|
||||
def get_dummy_vnf_obj():
|
||||
@ -57,7 +79,8 @@ def get_dummy_vnf_obj():
|
||||
'vim_id': u'6261579e-d6f3-49ad-8bc3-a9cb974778ff',
|
||||
'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437',
|
||||
'name': 'dummy_vnf',
|
||||
'attributes': {}}}
|
||||
'attributes': {},
|
||||
'vnfd_template': None}}
|
||||
|
||||
|
||||
def get_dummy_vnf_config_obj():
|
||||
|
@ -123,7 +123,20 @@ class TestVNFMPlugin(db_base.SqlTestCase):
|
||||
id='eb094833-995e-49f0-a047-dfb56aaf7c4e',
|
||||
tenant_id='ad7ebc56538745a08ef7c5e97f8bd437',
|
||||
name='fake_template',
|
||||
description='fake_template_description')
|
||||
description='fake_template_description',
|
||||
template_source='onboarded')
|
||||
session.add(device_template)
|
||||
session.flush()
|
||||
return device_template
|
||||
|
||||
def _insert_dummy_device_template_inline(self):
|
||||
session = self.context.session
|
||||
device_template = vnfm_db.VNFD(
|
||||
id='d58bcc4e-d0cf-11e6-bf26-cec0c932ce01',
|
||||
tenant_id='ad7ebc56538745a08ef7c5e97f8bd437',
|
||||
name='tmpl-koeak4tqgoqo8cr4-dummy_inline_vnf',
|
||||
description='inline_fake_template_description',
|
||||
template_source='inline')
|
||||
session.add(device_template)
|
||||
session.flush()
|
||||
return device_template
|
||||
@ -219,6 +232,7 @@ class TestVNFMPlugin(db_base.SqlTestCase):
|
||||
self.assertIn('attributes', result)
|
||||
self.assertIn('created_at', result)
|
||||
self.assertIn('updated_at', result)
|
||||
self.assertIn('template_source', result)
|
||||
yaml_dict = yaml.safe_load(utils.tosca_vnfd_openwrt)
|
||||
mock_tosca_template.assert_called_once_with(
|
||||
a_file=False, yaml_dict_tpl=yaml_dict)
|
||||
@ -244,7 +258,7 @@ class TestVNFMPlugin(db_base.SqlTestCase):
|
||||
self.vnfm_plugin.create_vnfd,
|
||||
self.context, vnfd_obj)
|
||||
|
||||
def test_create_vnf(self):
|
||||
def test_create_vnf_with_vnfd(self):
|
||||
self._insert_dummy_device_template()
|
||||
vnf_obj = utils.get_dummy_vnf_obj()
|
||||
result = self.vnfm_plugin.create_vnf(self.context, vnf_obj)
|
||||
@ -268,6 +282,35 @@ class TestVNFMPlugin(db_base.SqlTestCase):
|
||||
res_state=mock.ANY, res_type=constants.RES_TYPE_VNF,
|
||||
tstamp=mock.ANY, details=mock.ANY)
|
||||
|
||||
@mock.patch('tacker.vnfm.plugin.VNFMPlugin.create_vnfd')
|
||||
def test_create_vnf_from_template(self, mock_create_vnfd):
|
||||
self._insert_dummy_device_template_inline()
|
||||
mock_create_vnfd.return_value = {'id':
|
||||
'd58bcc4e-d0cf-11e6-bf26-cec0c932ce01'}
|
||||
vnf_obj = utils.get_dummy_inline_vnf_obj()
|
||||
result = self.vnfm_plugin.create_vnf(self.context, vnf_obj)
|
||||
self.assertIsNotNone(result)
|
||||
self.assertIn('id', result)
|
||||
self.assertIn('instance_id', result)
|
||||
self.assertIn('status', result)
|
||||
self.assertIn('attributes', result)
|
||||
self.assertIn('mgmt_url', result)
|
||||
self.assertIn('created_at', result)
|
||||
self.assertIn('updated_at', result)
|
||||
mock_create_vnfd.assert_called_once_with(mock.ANY, mock.ANY)
|
||||
self._device_manager.invoke.assert_called_with('test_vim',
|
||||
'create',
|
||||
plugin=mock.ANY,
|
||||
context=mock.ANY,
|
||||
vnf=mock.ANY,
|
||||
auth_attr=mock.ANY)
|
||||
self._pool.spawn_n.assert_called_once_with(mock.ANY)
|
||||
self._cos_db_plugin.create_event.assert_called_with(
|
||||
self.context, evt_type=constants.RES_EVT_CREATE,
|
||||
res_id=mock.ANY,
|
||||
res_state=mock.ANY, res_type=constants.RES_TYPE_VNF,
|
||||
tstamp=mock.ANY, details=mock.ANY)
|
||||
|
||||
def test_show_vnf_details_vnf_inactive(self):
|
||||
self._insert_dummy_device_template()
|
||||
vnf_obj = utils.get_dummy_vnf_obj()
|
||||
|
@ -163,6 +163,11 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
|
||||
# framework doesn't know what services are valid for now.
|
||||
# so doesn't check it here yet.
|
||||
pass
|
||||
if 'template_source' in vnfd_data:
|
||||
template_source = vnfd_data.get('template_source')
|
||||
else:
|
||||
template_source = 'onboarded'
|
||||
vnfd['vnfd']['template_source'] = template_source
|
||||
|
||||
self._parse_template_input(vnfd)
|
||||
return super(VNFMPlugin, self).create_vnfd(
|
||||
@ -334,6 +339,17 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
|
||||
name = vnf_info['name']
|
||||
if self._get_by_name(context, vnfm_db.VNF, name):
|
||||
raise exceptions.DuplicateResourceName(resource='VNF', name=name)
|
||||
|
||||
# if vnfd_template specified, create vnfd from template
|
||||
# create template dictionary structure same as needed in create_vnfd()
|
||||
if vnf_info.get('vnfd_template'):
|
||||
vnfd_name = utils.generate_resource_name(name, 'inline')
|
||||
vnfd = {'vnfd': {'attributes': {'vnfd': vnf_info['vnfd_template']},
|
||||
'name': vnfd_name,
|
||||
'template_source': 'inline',
|
||||
'service_types': [{'service_type': 'vnfd'}]}}
|
||||
vnf_info['vnfd_id'] = self.create_vnfd(context, vnfd).get('id')
|
||||
|
||||
vnf_attributes = vnf_info['attributes']
|
||||
if vnf_attributes.get('param_values'):
|
||||
param = vnf_attributes['param_values']
|
||||
@ -464,8 +480,7 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
|
||||
LOG.exception(_('_delete_vnf_wait'))
|
||||
|
||||
self.mgmt_delete_post(context, vnf_dict)
|
||||
vnf_id = vnf_dict['id']
|
||||
self._delete_vnf_post(context, vnf_id, e)
|
||||
self._delete_vnf_post(context, vnf_dict, e)
|
||||
|
||||
def delete_vnf(self, context, vnf_id):
|
||||
vnf_dict = self._delete_vnf_pre(context, vnf_id)
|
||||
@ -497,7 +512,7 @@ class VNFMPlugin(vnfm_db.VNFMPluginDb, VNFMMgmtMixin):
|
||||
vnf_dict['status'] = constants.ERROR
|
||||
vnf_dict['error_reason'] = six.text_type(e)
|
||||
self.mgmt_delete_post(context, vnf_dict)
|
||||
self._delete_vnf_post(context, vnf_id, e)
|
||||
self._delete_vnf_post(context, vnf_dict, e)
|
||||
|
||||
self.spawn_n(self._delete_vnf_wait, context, vnf_dict, vim_auth,
|
||||
driver_name)
|
||||
|
Loading…
Reference in New Issue
Block a user