Support flow of Getting VNF package

Supported the following operations to get the VNF package
information from NFVO when starting LCM operation.
    - VNF packages (GET)
    - VNF package content (GET)
    - VNFD in an individual VNF package (GET)
    - Individual VNF package artifact (GET)

Implements: blueprint support-vnfm-operations
Spec: https://specs.openstack.org/openstack/tacker-specs/specs/victoria/support-sol003-vnfm-operations.html

Change-Id: Ibdafdda815f8e130226b9d8eef4f18639f01292c
(cherry picked from commit 9d95f91504)
This commit is contained in:
Aldinson Esto 2020-08-24 19:24:54 +09:00 committed by Toshiaki Takahashi
parent b7321d208f
commit e72a66bbba
29 changed files with 1977 additions and 387 deletions

View File

@ -206,7 +206,8 @@ terminate = {
'properties': {
'terminationType': {'type': 'string',
'enum': ['FORCEFUL', 'GRACEFUL']},
'gracefulTerminationTimeout': {'type': 'integer', 'minimum': 0}
'gracefulTerminationTimeout': {'type': 'integer', 'minimum': 0},
'additionalParams': parameter_types.keyvalue_pairs,
},
'required': ['terminationType'],
'additionalProperties': False,

View File

@ -116,18 +116,11 @@ class ViewBuilder(base.BaseViewBuilder):
return {"_links": _links}
def _get_vnf_instance_info(self,
vnf_instance, api_version=None):
def _get_vnf_instance_info(self, vnf_instance):
vnf_instance_dict = vnf_instance.to_dict()
if vnf_instance_dict.get('vim_connection_info'):
vnf_instance_dict['vim_connection_info'] = \
self._get_vim_conn_info(vnf_instance_dict.get(
'vim_connection_info', []))
if 'vnf_metadata' in vnf_instance_dict:
metadata_val = vnf_instance_dict.pop('vnf_metadata')
vnf_instance_dict['metadata'] = metadata_val
vnf_metadata = vnf_instance_dict.pop("vnf_metadata")
if vnf_metadata:
vnf_instance_dict.update({"metadata": vnf_metadata})
vnf_instance_dict = utils.convert_snakecase_to_camelcase(
vnf_instance_dict)

View File

@ -13,11 +13,20 @@
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import requests
import six
import tacker.conf
import webob
from oslo_db.exception import DBDuplicateEntry
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
from oslo_utils import excutils
from oslo_utils import timeutils
from oslo_utils import uuidutils
from sqlalchemy import exc as sqlexc
import ast
import functools
@ -25,20 +34,18 @@ import json
import re
import traceback
import six
from six.moves import http_client
from six.moves.urllib import parse
import webob
from tacker._i18n import _
from tacker.api.schemas import vnf_lcm
from tacker.api import validation
from tacker.api.views import vnf_lcm as vnf_lcm_view
from tacker.api.vnflcm.v1 import sync_resource
from tacker.common import exceptions
from tacker.common import utils
from tacker.conductor.conductorrpc import vnf_lcm_rpc
import tacker.conf
from tacker.db.vnfm import vnfm_db
from tacker.extensions import nfvo
from tacker.extensions import vnfm
from tacker import manager
@ -47,9 +54,11 @@ from tacker.objects import fields
from tacker.objects import vnf_lcm_subscriptions as subscription_obj
from tacker.plugins.common import constants
from tacker.policies import vnf_lcm as vnf_lcm_policies
import tacker.vnfm.nfvo_client as nfvo_client
from tacker.vnfm import vim_client
from tacker import wsgi
CONF = tacker.conf.CONF
LOG = logging.getLogger(__name__)
@ -307,37 +316,102 @@ class VnfLcmController(wsgi.Controller):
return vnf_lcm_op_occs_id
def _create_vnf(self, context, vnf_instance, default_vim, attributes=None):
tenant_id = vnf_instance.tenant_id
vnfd_id = vnf_instance.vnfd_id
name = vnf_instance.vnf_instance_name
description = vnf_instance.vnf_instance_description
vnf_id = vnf_instance.id
vim_id = default_vim.get('vim_id')
placement_attr = default_vim.get('placement_attr', {})
try:
with context.session.begin(subtransactions=True):
vnf_db = vnfm_db.VNF(id=vnf_id,
tenant_id=tenant_id,
name=name,
description=description,
instance_id=None,
vnfd_id=vnfd_id,
vim_id=vim_id,
placement_attr=placement_attr,
status=constants.INACTIVE,
error_reason=None,
deleted_at=datetime.min)
context.session.add(vnf_db)
for key, value in attributes.items():
arg = vnfm_db.VNFAttribute(
id=uuidutils.generate_uuid(), vnf_id=vnf_id,
key=key, value=str(value))
context.session.add(arg)
except DBDuplicateEntry as e:
raise exceptions.DuplicateEntity(
_type="vnf",
entry=e.columns)
def _destroy_vnf(self, context, vnf_instance):
with context.session.begin(subtransactions=True):
if vnf_instance.id:
now = timeutils.utcnow()
updated_values = {'deleted_at': now, 'status':
'PENDING_DELETE'}
context.session.query(vnfm_db.VNFAttribute).filter_by(
vnf_id=vnf_instance.id).delete()
context.session.query(vnfm_db.VNF).filter_by(
id=vnf_instance.id).update(updated_values)
def _update_package_usage_state(self, context, vnf_package):
"""Update vnf package usage state to IN_USE/NOT_IN_USE
If vnf package is not used by any of the vnf instances, it's usage
state should be set to NOT_IN_USE otherwise it should be set to
IN_USE.
"""
result = vnf_package.is_package_in_use(context)
if result:
vnf_package.usage_state = fields.PackageUsageStateType.IN_USE
else:
vnf_package.usage_state = fields.PackageUsageStateType.NOT_IN_USE
vnf_package.save()
@wsgi.response(http_client.CREATED)
@wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN))
@validation.schema(vnf_lcm.create)
def create(self, request, body):
context = request.environ['tacker.context']
context.can(vnf_lcm_policies.VNFLCM % 'create')
try:
req_body = utils.convert_camelcase_to_snakecase(body)
vnfd_id = req_body.get('vnfd_id')
try:
vnfd = objects.VnfPackageVnfd.get_by_id(request.context,
vnfd_id)
except exceptions.VnfPackageVnfdNotFound as exc:
raise webob.exc.HTTPBadRequest(explanation=six.text_type(exc))
except exceptions.VnfPackageVnfdNotFound:
vnf_package_info = self._find_vnf_package_info('vnfdId',
vnfd_id)
if not vnf_package_info:
msg = (
_("Can not find requested to NFVO, \
vnf package info: vnfdId=[%s]") %
vnfd_id)
return self._make_problem_detail(
msg, 404, title='Not Found')
vnfd = sync_resource.SyncVnfPackage.create_package(
context,
vnf_package_info)
if not vnfd:
msg = (
_("Can not find requested to NFVO, \
vnf package vnfd: %s") %
vnfd_id)
return self._make_problem_detail(
msg, 500, 'Internal Server Error')
try:
# get default vim information
vim_client_obj = vim_client.VimClient()
default_vim = vim_client_obj.get_vim(context)
# set vim_connection_info
access_info = {
'username': default_vim.get('vim_auth', {}).get('username'),
'password': default_vim.get('vim_auth', {}).get('password'),
'region': default_vim.get('placement_attr', {}).get('region'),
'tenant': default_vim.get('tenant')
}
vim_con_info = objects.VimConnectionInfo(id=default_vim.get('vim_id'),
vim_id=default_vim.get('vim_id'),
vim_type=default_vim.get('vim_type'),
access_info=access_info)
vnf_instance = objects.VnfInstance(
context=request.context,
vnf_instance_name=req_body.get('vnf_instance_name'),
@ -349,14 +423,28 @@ class VnfLcmController(wsgi.Controller):
vnf_product_name=vnfd.vnf_product_name,
vnf_software_version=vnfd.vnf_software_version,
vnfd_version=vnfd.vnfd_version,
vnf_pkg_id=vnfd.package_uuid,
tenant_id=request.context.project_id,
vnf_metadata=req_body.get('metadata'))
try:
vnf_instance.create()
# add default vim to vim_connection_info
setattr(vnf_instance, 'vim_connection_info', [vim_con_info])
# create entry to 'vnf' table and 'vnf_attribute' table
attributes = {'placement_attr': default_vim.
get('placement_attr', {})}
self._create_vnf(context, vnf_instance,
default_vim, attributes)
# get vnf package
vnf_package = objects.VnfPackage.get_by_id(context,
vnfd.package_uuid, expected_attrs=['vnfd'])
# Update VNF Package to IN_USE
self._update_package_usage_state(context, vnf_package)
except Exception:
with excutils.save_and_reraise_exception():
# roll back db changes
self._destroy_vnf(context, vnf_instance)
vnf_instance.destroy(context)
self._update_package_usage_state(context, vnf_package)
# create notification data
notification = {
@ -367,14 +455,49 @@ class VnfLcmController(wsgi.Controller):
'vnfInstance': {
'href': self._get_vnf_instance_href(vnf_instance)}}}
# call send nootification
# call sendNotification
self.rpc_api.send_notification(context, notification)
vnf_instance.save()
result = self._view_builder.create(vnf_instance)
headers = {"location": self._get_vnf_instance_href(vnf_instance)}
return wsgi.ResponseObject(result, headers=headers)
except nfvo.VimDefaultNotDefined as exc:
raise webob.exc.HTTPBadRequest(explanation=six.text_type(exc))
except(sqlexc.SQLAlchemyError, Exception)\
as exc:
raise webob.exc.HTTPInternalServerError(
explanation=six.text_type(exc))
except webob.exc.HTTPNotFound as e:
return self._make_problem_detail(str(e), 404,
'Not Found')
except webob.exc.HTTPInternalServerError as e:
return self._make_problem_detail(str(e), 500,
'Internal Server Error')
except Exception as e:
return self._make_problem_detail(str(e), 500,
'Internal Server Error')
def _find_vnf_package_info(self, filter_key, filter_val):
try:
vnf_package_info_res = \
nfvo_client.VnfPackageRequest.index(params={
"filter":
"(eq,{},{})".format(filter_key, filter_val)
})
except requests.exceptions.RequestException as e:
LOG.exception(e)
return None
if not vnf_package_info_res.ok:
return None
vnf_package_info = vnf_package_info_res.json()
if (not vnf_package_info or len(vnf_package_info) == 0):
return None
return vnf_package_info[0]
@wsgi.response(http_client.OK)
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND))
def show(self, request, id):
@ -401,8 +524,16 @@ class VnfLcmController(wsgi.Controller):
@check_vnf_state(action="delete",
instantiation_state=[fields.VnfInstanceState.NOT_INSTANTIATED],
task_state=[None])
def _delete(self, context, vnf_instance):
@check_vnf_status(action="delete",
status=[constants.INACTIVE])
def _delete(self, context, vnf_instance, vnf):
vnf_package_vnfd = objects.VnfPackageVnfd.get_by_id(context,
vnf_instance.vnfd_id)
vnf_instance.destroy(context)
self._destroy_vnf(context, vnf_instance)
vnf_package = objects.VnfPackage.get_by_id(context,
vnf_package_vnfd.package_uuid, expected_attrs=['vnfd'])
self._update_package_usage_state(context, vnf_package)
@wsgi.response(http_client.NO_CONTENT)
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND,
@ -411,7 +542,8 @@ class VnfLcmController(wsgi.Controller):
context = request.environ['tacker.context']
vnf_instance = self._get_vnf_instance(context, id)
self._delete(context, vnf_instance)
vnf = self._get_vnf(context, id)
self._delete(context, vnf_instance, vnf)
notification = {
"notificationType": "VnfIdentifierDeletionNotification",

View File

@ -0,0 +1,138 @@
#
# 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.
from oslo_config import cfg
from oslo_log import log as logging
from tacker.common import csar_utils
from tacker.common import exceptions
from tacker.common import utils
from tacker.conductor.conductorrpc import vnf_pkgm_rpc
from tacker.glance_store import store as glance_store
from tacker import objects
from tacker.objects import fields
import tacker.vnfm.nfvo_client as nfvo_client
import time
import webob
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
class SyncVnfPackage:
vnf_package_rpc_api = vnf_pkgm_rpc.VNFPackageRPCAPI()
@classmethod
def create_package(cls, context, vnf_package_info):
"""vnf_package, create a vnf_package_vnfd table."""
vnf_package_info = utils.convert_camelcase_to_snakecase(
vnf_package_info)
try:
vnf_package = cls.__create_vnf_package(context, vnf_package_info)
except Exception as exc:
raise webob.exc.HTTPInternalServerError(
explanation=exc)
try:
artifact_paths = cls._get_artifact_paths(vnf_package_info)
vnf_package_binary = \
nfvo_client.VnfPackageRequest.download_vnf_packages(
vnf_package.id, artifact_paths)
except nfvo_client.UndefinedExternalSettingException as exc:
raise webob.exc.HTTPNotFound(explanation=exc)
except (nfvo_client.FaliedDownloadContentException, Exception) as exc:
raise webob.exc.HTTPInternalServerError(
explanation=exc)
try:
(location, size, _, multihash, _) = glance_store.store_csar(
context, vnf_package.id, vnf_package_binary)
cls.__update_vnf_package(vnf_package, location, size, multihash)
cls.vnf_package_rpc_api.upload_vnf_package_content(
context, vnf_package)
vnf_package_vnfd = cls._get_vnf_package_vnfd(
context, vnf_package_info.get('vnfd_id'))
except Exception as exc:
raise webob.exc.HTTPInternalServerError(
explanation=exc)
return vnf_package_vnfd
@classmethod
def _get_artifact_paths(cls, vnf_package_info):
additional_artifacts = vnf_package_info.get('additional_artifacts')
if additional_artifacts is None:
return None
return [artifact.get('artifact_path')
for artifact in additional_artifacts
if 'artifact_path' in artifact]
@classmethod
def __store_csar(cls, context, id, body):
(location, size, checksum, multihash,
loc_meta) = glance_store.store_csar(context, id, body)
return location, size, checksum, multihash, loc_meta
@classmethod
def __load_csar(cls, context, vnf_package):
location = vnf_package.location_glance_store
zip_path = glance_store.load_csar(vnf_package.id, location)
vnf_data, flavours = csar_utils.load_csar_data(
context.elevated(), vnf_package.id, zip_path)
return vnf_data, flavours
@classmethod
def __create_vnf_package(cls, context, vnf_package_info):
"""VNF Package Table Registration."""
vnf_package = objects.VnfPackage(
context=context,
id=vnf_package_info.get('id'),
onboarding_state=fields.PackageOnboardingStateType.CREATED,
operational_state=fields.PackageOperationalStateType.DISABLED,
usage_state=fields.PackageUsageStateType.NOT_IN_USE,
tenant_id=context.project_id
)
vnf_package.create()
return vnf_package
@classmethod
def __update_vnf_package(cls, vnf_package, location, size, multihash):
"""VNF Package Table Update."""
vnf_package.algorithm = CONF.vnf_package.hashing_algorithm
vnf_package.location_glance_store = location
vnf_package.hash = multihash
vnf_package.size = size
vnf_package.save()
@classmethod
def _get_vnf_package_vnfd(cls, context, vnfd_id):
"""Get VNF Package VNFD."""
for num in range(CONF.vnf_lcm.retry_num):
try:
vnfd = objects.VnfPackageVnfd.get_by_id(
context,
vnfd_id)
return vnfd
except exceptions.VnfPackageVnfdNotFound:
LOG.debug("retry_wait %s" %
CONF.vnf_lcm.retry_wait)
time.sleep(CONF.vnf_lcm.retry_wait)
return None

View File

@ -13,8 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from io import BytesIO
import json
import mimetypes
import os
@ -302,19 +302,37 @@ class VnfPkgmController(wsgi.Controller):
context = request.environ['tacker.context']
context.can(vnf_package_policies.VNFPKGM % 'upload_package_content')
vnf_package = self._get_vnf_package(id, request)
# check if id is of type uuid format
if not uuidutils.is_uuid_like(id):
msg = _("Can not find requested vnf package: %s") % id
return self._make_problem_detail('Not Found', msg, 404)
try:
vnf_package = vnf_package_obj.VnfPackage.get_by_id(
request.context, id)
except exceptions.VnfPackageNotFound:
msg = _("Can not find requested vnf package: %s") % id
return self._make_problem_detail('Not Found', msg, 404)
except Exception as e:
return self._make_problem_detail(
'Internal Server Error', str(e), 500)
if vnf_package.onboarding_state != \
fields.PackageOnboardingStateType.CREATED:
msg = _("VNF Package %(id)s onboarding state "
"is not %(onboarding)s")
raise webob.exc.HTTPConflict(explanation=msg % {"id": id,
"onboarding": fields.PackageOnboardingStateType.CREATED})
return self._make_problem_detail('Conflict', msg % {"id": id,
"onboarding": fields.PackageOnboardingStateType.CREATED},
409)
vnf_package.onboarding_state = (
fields.PackageOnboardingStateType.UPLOADING)
try:
vnf_package.save()
except Exception as e:
return self._make_problem_detail(
'Internal Server Error', str(e), 500)
try:
(location, size, checksum, multihash,
@ -323,16 +341,29 @@ class VnfPkgmController(wsgi.Controller):
with excutils.save_and_reraise_exception():
vnf_package.onboarding_state = (
fields.PackageOnboardingStateType.CREATED)
try:
vnf_package.save()
vnf_package.onboarding_state = (
fields.PackageOnboardingStateType.PROCESSING)
except Exception as e:
return self._make_problem_detail(
'Internal Server Error', str(e), 500)
vnf_package.algorithm = CONF.vnf_package.hashing_algorithm
vnf_package.hash = multihash
vnf_package.location_glance_store = location
vnf_package.size = size
try:
vnf_package.save()
except Exception as e:
vnf_package.onboarding_state = (
fields.PackageOnboardingStateType.CREATED)
try:
vnf_package.save()
except Exception as e:
return self._make_problem_detail(
'Internal Server Error', str(e), 500)
return self._make_problem_detail(
'Internal Server Error', str(e), 500)
# process vnf_package
self.rpc_api.upload_vnf_package_content(context, vnf_package)
@ -618,6 +649,16 @@ class VnfPkgmController(wsgi.Controller):
return buff.getvalue()
def _make_problem_detail(self, title, detail, status):
res = webob.Response(content_type='application/problem+json')
problemDetails = {}
problemDetails['title'] = title
problemDetails['detail'] = detail
problemDetails['status'] = status
res.text = json.dumps(problemDetails)
res.status_int = status
return res
def create_resource():
body_deserializers = {

View File

@ -12,6 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from copy import deepcopy
import hashlib
import os
import re
@ -29,6 +30,7 @@ import zipfile
from tacker.common import exceptions
import tacker.conf
from tacker.extensions import vnfm
import urllib.request as urllib2
@ -124,8 +126,10 @@ def _get_software_image(custom_defs, nodetemplate_name, node_tpl):
properties = node_tpl['properties']
sw_image_artifact = _get_sw_image_artifact(node_tpl.get('artifacts'))
if sw_image_artifact:
image_path = sw_image_artifact['file'].lstrip("./")
properties['sw_image_data'].update(
{'software_image_id': nodetemplate_name})
{'software_image_id': nodetemplate_name,
'image_path': image_path})
sw_image_data = properties['sw_image_data']
if 'metadata' in sw_image_artifact:
sw_image_data.update({'metadata':
@ -137,7 +141,79 @@ def _populate_flavour_data(tosca):
flavours = []
if tosca.nested_tosca_templates_with_topology:
for tp in tosca.nested_tosca_templates_with_topology:
_get_flavour_data(tp, flavours)
sw_image_list = []
# Setting up flavour data
flavour_id = tp.substitution_mappings.properties.get('flavour_id')
if flavour_id:
flavour = {'flavour_id': flavour_id}
tpl_dict = dict()
# get from top-vnfd data
for key, value in tosca.tpl.items():
if key in CONF.vnf_package.get_top_list:
tpl_dict[key] = value
# get from lower-vnfd data
tpl_dict['topology_template'] = dict()
tpl_dict['topology_template']['policies'] = \
tp.tpl.get('policies')
tpl_dict['topology_template']['node_templates'] = \
deepcopy(tp.tpl.get('node_templates'))
for e_node in CONF.vnf_package.exclude_node:
if tpl_dict['topology_template']['node_templates'].\
get(e_node):
del (tpl_dict['topology_template']
['node_templates'][e_node])
tpl_dict['topology_template']['inputs'] = \
deepcopy(tp.tpl.get('inputs'))
for del_input in CONF.vnf_package.del_input_list:
if tpl_dict['topology_template']['inputs'].get(del_input):
del tpl_dict['topology_template']['inputs'][del_input]
if len(tpl_dict['topology_template']['inputs']) < 1:
del tpl_dict['topology_template']['inputs']
flavour.update({'tpl_dict': tpl_dict})
instantiation_levels = _get_instantiation_levels(tp.policies)
if instantiation_levels:
flavour.update(
{'instantiation_levels': instantiation_levels})
mgmt_driver = None
for template_name, node_tpl in \
tp.tpl.get('node_templates').items():
# check the flavour property in vnf data
_update_flavour_data_from_vnf(
tp.custom_defs, node_tpl, flavour)
if node_tpl['type'] in CONF.vnf_package.get_lower_list:
if node_tpl['type'] == "tosca.nodes.nfv.VDU.Tacker":
# get mgmt_driver
mgmt_driver_flavour = \
node_tpl['properties'].get('mgmt_driver')
if mgmt_driver_flavour:
if mgmt_driver and \
mgmt_driver_flavour != mgmt_driver:
raise vnfm.MultipleMGMTDriversSpecified()
mgmt_driver = mgmt_driver_flavour
flavour.update({'mgmt_driver': mgmt_driver})
for template_name, node_tpl in \
tp.tpl.get('node_templates').items():
# Update the software image data
sw_image = _get_software_image(tp.custom_defs,
template_name,
node_tpl)
if sw_image:
sw_image_list.append(sw_image)
# Add software images for flavour
if sw_image_list:
flavour.update({'sw_images': sw_image_list})
if flavour:
flavours.append(flavour)
else:
_get_flavour_data(tosca.topology_template, flavours)

View File

@ -356,5 +356,9 @@ class UserDataUpdateCreateFailed(TackerException):
"or created after %(retries)d retries.")
class DBAccessError(TackerException):
message = _("DB Access Error")
class SeeOther(TackerException):
code = 303

View File

@ -18,6 +18,7 @@ import functools
import inspect
import json
import os
import oslo_messaging
import shutil
import sys
import time
@ -28,7 +29,6 @@ import yaml
from glance_store import exceptions as store_exceptions
from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging
from oslo_serialization import jsonutils
from oslo_service import periodic_task
from oslo_service import service
@ -42,20 +42,25 @@ from sqlalchemy.orm import exc as orm_exc
from tacker import auth
from tacker.common import coordination
from tacker.common import csar_utils
from tacker.common import driver_manager
from tacker.common import exceptions
from tacker.common import log
from tacker.common import safe_utils
from tacker.common import topics
from tacker.common import utils
import tacker.conf
from tacker import context as t_context
from tacker.db.common_services import common_services_db
from tacker.db.nfvo import nfvo_db
from tacker.db.vnfm import vnfm_db
from tacker.extensions import nfvo
from tacker.glance_store import store as glance_store
from tacker import manager
from tacker import objects
from tacker.objects import fields
from tacker.objects.vnf_package import VnfPackagesList
from tacker.objects import vnfd as vnfd_db
from tacker.objects import vnfd_attribute as vnfd_attribute_db
from tacker.plugins.common import constants
from tacker import service as tacker_service
from tacker import version
@ -63,7 +68,7 @@ from tacker.vnflcm import utils as vnflcm_utils
from tacker.vnflcm import vnflcm_driver
from tacker.vnfm import plugin
CONF = cfg.CONF
CONF = tacker.conf.CONF
# NOTE(tpatil): keystone_authtoken opts registered explicitly as conductor
# service doesn't use the keystonemiddleware.authtoken middleware as it's
@ -97,6 +102,13 @@ cfg.CONF.register_opts(OPTS, 'keystone_authtoken')
LOG = logging.getLogger(__name__)
_INACTIVE_STATUS = ('INACTIVE')
_ACTIVE_STATUS = ('ACTIVE')
_PENDING_STATUS = ('PENDING_CREATE',
'PENDING_TERMINATE',
'PENDING_DELETE',
'PENDING_HEAL')
def _delete_csar(context, vnf_package):
# Delete from glance store
@ -154,6 +166,9 @@ class Conductor(manager.Manager):
super(Conductor, self).__init__(host=self.conf.host)
self.vnfm_plugin = plugin.VNFMPlugin()
self.vnflcm_driver = vnflcm_driver.VnfLcmDriver()
self.vnf_manager = driver_manager.DriverManager(
'tacker.tacker.vnfm.drivers',
cfg.CONF.tacker.infra_driver)
def start(self):
coordination.COORDINATOR.start()
@ -223,7 +238,7 @@ class Conductor(manager.Manager):
vnf_sw_image.min_ram = 0
vnf_sw_image.min_disk = int(sw_image.get('min_disk').split()[0])
vnf_sw_image.size = int(sw_image.get('size').split()[0])
vnf_sw_image.image_path = ''
vnf_sw_image.image_path = sw_image['image_path']
vnf_sw_image.software_image_id = sw_image['software_image_id']
vnf_sw_image.metadata = sw_image.get('metadata', dict())
vnf_sw_image.create()
@ -233,6 +248,7 @@ class Conductor(manager.Manager):
deploy_flavour.package_uuid = package_uuid
deploy_flavour.flavour_id = flavour['flavour_id']
deploy_flavour.flavour_description = flavour['flavour_description']
if flavour.get('instantiation_levels'):
deploy_flavour.instantiation_levels = \
flavour.get('instantiation_levels')
deploy_flavour.create()
@ -273,28 +289,56 @@ class Conductor(manager.Manager):
package_vnfd.vnfd_version = vnf_data.get('descriptor_version')
package_vnfd.create()
self._onboard_vnfd(context, vnf_package, vnf_data, flavours)
for flavour in flavours:
self._create_flavour(context, vnf_package.id, flavour)
def _onboard_vnfd(self, context, vnf_package, vnf_data, flavours):
vnfd = vnfd_db.Vnfd(context=context)
vnfd.id = vnf_data.get('descriptor_id')
vnfd.tenant_id = context.tenant_id
vnfd.name = vnf_data.get('product_name') + '-' + \
vnf_data.get('descriptor_version')
vnfd.discription = vnf_data.get('discription')
for flavour in flavours:
if flavour.get('mgmt_driver'):
vnfd.mgmt_driver = flavour.get('mgmt_driver')
break
vnfd.create()
for flavour in flavours:
vnfd_attribute = vnfd_attribute_db.VnfdAttribute(context=context)
vnfd_attribute.id = uuidutils.generate_uuid()
vnfd_attribute.vnfd_id = vnf_data.get('descriptor_id')
vnfd_attribute.key = 'vnfd_' + flavour['flavour_id']
vnfd_attribute.value = \
yaml.dump(flavour.get('tpl_dict'), default_flow_style=False)
vnfd_attribute.create()
break
@revert_upload_vnf_package
def upload_vnf_package_content(self, context, vnf_package):
vnf_package.onboarding_state = (
fields.PackageOnboardingStateType.PROCESSING)
try:
vnf_package.save()
location = vnf_package.location_glance_store
zip_path = glance_store.load_csar(vnf_package.id, location)
vnf_data, flavours, vnf_artifacts = csar_utils.load_csar_data(
context.elevated(), vnf_package.id, zip_path)
self._onboard_vnf_package(
context,
vnf_package,
vnf_data,
flavours,
vnf_artifacts)
self._onboard_vnf_package(context, vnf_package, vnf_data, flavours)
vnf_package.onboarding_state = (
fields.PackageOnboardingStateType.ONBOARDED)
vnf_package.operational_state = (
fields.PackageOperationalStateType.ENABLED)
vnf_package.save()
except Exception as msg:
raise Exception(msg)
@revert_upload_vnf_package
def upload_vnf_package_from_uri(self, context, vnf_package,
address_information, user_name=None,
@ -433,6 +477,180 @@ class Conductor(manager.Manager):
vnf_package.save()
@log.log
def _change_vnf_status(self, context, vnf_id,
current_statuses, new_status, error_reason=None):
'''Change vnf status and add error reason if error'''
LOG.debug("Change status of vnf %s from %s to %s", vnf_id,
current_statuses, new_status)
with context.session.begin(subtransactions=True):
updated_values = {
'status': new_status, 'updated_at': timeutils.utcnow()}
vnf_model = (context.session.query(
vnfm_db.VNF).filter_by(id=vnf_id).first())
if not vnf_model:
raise exceptions.VnfInstanceNotFound(
message="VNF {} not found".format(vnf_id))
if vnf_model.status not in current_statuses:
raise exceptions.VnfConflictState(
message='Cannot change status to {} \
while in {}'.format(
updated_values['status'], vnf_model.status))
vnf_model.update(updated_values)
def _update_vnf_attributes(self, context, vnf_dict, current_statuses,
new_status):
with context.session.begin(subtransactions=True):
try:
modified_attributes = {}
added_attributes = {}
updated_values = {
'mgmt_ip_address': vnf_dict['mgmt_ip_address'],
'status': new_status,
'updated_at': timeutils.utcnow()}
vnf_model = (context.session.query(vnfm_db.VNF).filter_by(
id=vnf_dict['id']).first())
if not vnf_model:
raise exceptions.VnfInstanceNotFound(
message="VNF {} not found".format(vnf_dict['id']))
if vnf_model.status not in current_statuses:
raise exceptions.VnfConflictState(
message='Cannot change status to {} while \
in {}'.format(updated_values['status'],
vnf_model.status))
vnf_model.update(updated_values)
for key, val in vnf_dict['attributes'].items():
vnf_attr_model = (context.session.query(
vnfm_db.VNFAttribute).
filter_by(vnf_id=vnf_dict['id']).
filter_by(key=key).first())
if vnf_attr_model:
modified_attributes.update(
{vnf_attr_model.key: vnf_attr_model.value})
vnf_attr_model.update({'value': val})
else:
added_attributes.update({key: val})
vnf_attr_model = vnfm_db.VNFAttribute(
id=uuidutils.generate_uuid(),
vnf_id=vnf_dict['id'],
key=key, value=val)
context.session.add(vnf_attr_model)
except Exception as exc:
with excutils.save_and_reraise_exception():
LOG.error("Error in updating tables {}".format(str(exc)))
# Roll back modified/added vnf attributes
for key, val in modified_attributes.items():
vnf_attr_model = (context.session.query(
vnfm_db.VNFAttribute).
filter_by(vnf_id=vnf_dict['id']).
filter_by(key=key).first())
if vnf_attr_model:
vnf_attr_model.update({'value': val})
for key, val in added_attributes.items():
vnf_attr_model = (context.session.query(
vnfm_db.VNFAttribute).
filter_by(vnf_id=vnf_dict['id']).
filter_by(key=key).first())
if vnf_attr_model:
vnf_attr_model.delete()
@log.log
def _build_instantiated_vnf_info(self, context, vnf_instance,
instantiate_vnf_req=None):
try:
# if instantiate_vnf_req is not present, create from vnf_instance
if not instantiate_vnf_req:
instantiate_vnf_req = objects.InstantiateVnfRequest.\
from_vnf_instance(vnf_instance)
# update instantiated vnf info based on created stack resources
if hasattr(vnf_instance.instantiated_vnf_info, 'instance_id'):
# get final vnfd_dict
vnfd_dict = vnflcm_utils._get_vnfd_dict(context,
vnf_instance.vnfd_id,
instantiate_vnf_req.flavour_id)
# get vim_connection info from request
vim_info = vnflcm_utils._get_vim(context,
instantiate_vnf_req.vim_connection_info)
vim_connection_info = objects.VimConnectionInfo.\
obj_from_primitive(vim_info, context)
vnflcm_utils._build_instantiated_vnf_info(vnfd_dict,
instantiate_vnf_req, vnf_instance,
vim_id=vim_connection_info.vim_id)
if vnf_instance.instantiated_vnf_info.instance_id:
self.vnf_manager.invoke(vim_connection_info.vim_type,
'post_vnf_instantiation', context=context,
vnf_instance=vnf_instance,
vim_connection_info=vim_connection_info)
except Exception as ex:
try:
vnf_instance.instantiated_vnf_info.reinitialize()
vnf_instance.instantiated_vnf_info.save()
finally:
error_msg = "Failed to build instantiation information \
for vnf {} because {}".\
format(vnf_instance.id, encodeutils.
exception_to_unicode(ex))
LOG.error("_build_instantiated_vnf_info error {}".
format(error_msg))
raise exceptions.TackerException(message=error_msg)
@log.log
def _update_instantiated_vnf_info(
self, context, vnf_instance, heal_vnf_request):
try:
vim_info = vnflcm_utils._get_vim(context,
vnf_instance.vim_connection_info)
vim_connection_info = \
objects.VimConnectionInfo.obj_from_primitive(
vim_info, context)
self.vnf_manager.invoke(
vim_connection_info.vim_type, 'post_heal_vnf',
context=context, vnf_instance=vnf_instance,
vim_connection_info=vim_connection_info,
heal_vnf_request=heal_vnf_request)
except Exception as exp:
error_msg = \
"Failed to update instantiation information for vnf {}: {}".\
format(vnf_instance.id, encodeutils.exception_to_unicode(exp))
LOG.error("_update_instantiated_vnf_info error {}".
format(error_msg))
raise exceptions.TackerException(message=error_msg)
@log.log
def _add_additional_vnf_info(self, context, vnf_instance):
'''this method adds misc info to 'vnf' table'''
try:
if hasattr(vnf_instance.instantiated_vnf_info, 'instance_id'):
if vnf_instance.instantiated_vnf_info.instance_id:
# add instance_id info
instance_id = vnf_instance.instantiated_vnf_info.\
instance_id
with context.session.begin(subtransactions=True):
updated_values = {'instance_id': instance_id}
context.session.query(vnfm_db.VNF).filter_by(
id=vnf_instance.id).update(updated_values)
except Exception as ex:
# with excutils.save_and_reraise_exception():
error_msg = "Failed to add additional vnf info to vnf {}. Details -\
{}".format(
vnf_instance.id, str(ex))
LOG.error("_add_additional_vnf_info error {}".format(error_msg))
raise exceptions.TackerException(message=error_msg)
@periodic_task.periodic_task(spacing=CONF.vnf_package_delete_interval)
def _run_cleanup_vnf_packages(self, context):
"""Delete orphan extracted csar zip and files from extracted path
@ -490,7 +708,6 @@ class Conductor(manager.Manager):
fields.LcmOccsOperationType.INSTANTIATE)
operation_state = kwargs.get('operation_state',
fields.LcmOccsOperationState.PROCESSING)
evacuate_end_list = kwargs.get('evacuate_end_list', None)
is_automatic_invocation = \
kwargs.get('is_automatic_invocation', False)
error = kwargs.get('error', None)
@ -546,8 +763,7 @@ class Conductor(manager.Manager):
operation_state == fields.LcmOccsOperationState.FAILED_TEMP):
affected_resources = vnflcm_utils._get_affected_resources(
old_vnf_instance=old_vnf_instance,
new_vnf_instance=vnf_instance,
extra_list=evacuate_end_list)
new_vnf_instance=vnf_instance)
affected_resources_snake_case = \
utils.convert_camelcase_to_snakecase(affected_resources)
resource_change_obj = \
@ -666,6 +882,7 @@ class Conductor(manager.Manager):
self,
context,
vnf_instance,
vnf_dict,
instantiate_vnf,
vnf_lcm_op_occs_id):
@ -679,30 +896,23 @@ class Conductor(manager.Manager):
request_obj=instantiate_vnf
)
# Check if vnf is already instantiated.
vnf_instance = objects.VnfInstance.get_by_id(context,
vnf_instance.id)
if vnf_instance.instantiation_state == \
fields.VnfInstanceState.INSTANTIATED:
LOG.error("Vnf instance %(id)s is already in %(state)s state.",
{"id": vnf_instance.id,
"state": vnf_instance.instantiation_state})
return
# change vnf_status
if vnf_dict['status'] == 'INACTIVE':
vnf_dict['status'] = 'PENDING_CREATE'
self._change_vnf_status(context, vnf_instance.id,
_INACTIVE_STATUS, 'PENDING_CREATE')
self.vnflcm_driver.instantiate_vnf(context, vnf_instance,
instantiate_vnf)
vnf_dict, instantiate_vnf)
self._build_instantiated_vnf_info(context,
vnf_instance,
instantiate_vnf_req=instantiate_vnf)
vnf_package_vnfd = objects.VnfPackageVnfd.get_by_id(
context, vnf_instance.vnfd_id)
vnf_package = objects.VnfPackage.get_by_id(
context, vnf_package_vnfd.package_uuid,
expected_attrs=['vnfd'])
try:
self._update_package_usage_state(context, vnf_package)
except Exception:
with excutils.save_and_reraise_exception():
LOG.error("Failed to update usage_state of vnf package %s",
vnf_package.id)
self._update_vnf_attributes(context, vnf_dict,
_PENDING_STATUS, _ACTIVE_STATUS)
self.vnflcm_driver._vnf_instance_update(context, vnf_instance,
instantiation_state=fields.VnfInstanceState.
INSTANTIATED, task_state=None)
# Update vnf_lcm_op_occs table and send notification "COMPLETED"
self._send_lcm_op_occ_notification(
@ -715,6 +925,12 @@ class Conductor(manager.Manager):
)
except Exception as ex:
self._change_vnf_status(context, vnf_instance.id,
_PENDING_STATUS, 'ERROR')
self._build_instantiated_vnf_info(context, vnf_instance,
instantiate_vnf)
# Update vnf_lcm_op_occs table and send notification "FAILED_TEMP"
self._send_lcm_op_occ_notification(
context=context,
@ -730,17 +946,6 @@ class Conductor(manager.Manager):
def terminate(self, context, vnf_lcm_op_occs_id,
vnf_instance, terminate_vnf_req, vnf_dict):
try:
# Check if vnf is in instantiated state.
vnf_instance = objects.VnfInstance.get_by_id(context,
vnf_instance.id)
if vnf_instance.instantiation_state == \
fields.VnfInstanceState.NOT_INSTANTIATED:
LOG.error("Terminate action cannot be performed on vnf %(id)s "
"which is in %(state)s state.",
{"id": vnf_instance.id,
"state": vnf_instance.instantiation_state})
return
old_vnf_instance = copy.deepcopy(vnf_instance)
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
@ -753,22 +958,18 @@ class Conductor(manager.Manager):
operation=fields.LcmOccsOperationType.TERMINATE
)
self.vnflcm_driver.terminate_vnf(context, vnf_instance,
terminate_vnf_req,
vnf_lcm_op_occs_id)
self._change_vnf_status(context, vnf_instance.id,
_ACTIVE_STATUS, 'PENDING_TERMINATE')
vnf_package_vnfd = \
objects.VnfPackageVnfd.get_by_id(context, vnf_instance.vnfd_id)
vnf_package = \
objects.VnfPackage.get_by_id(context,
vnf_package_vnfd.package_uuid,
expected_attrs=['vnfd'])
try:
self._update_package_usage_state(context, vnf_package)
except Exception:
with excutils.save_and_reraise_exception():
LOG.error("Failed to update usage_state of vnf package %s",
vnf_package.id)
self.vnflcm_driver.terminate_vnf(context, vnf_instance,
terminate_vnf_req)
self._change_vnf_status(context, vnf_instance.id,
_PENDING_STATUS, 'INACTIVE')
self.vnflcm_driver._vnf_instance_update(context, vnf_instance,
vim_connection_info=[], task_state=None,
instantiation_state=fields.VnfInstanceState.NOT_INSTANTIATED)
vnf_instance.instantiated_vnf_info.reinitialize()
# Update vnf_lcm_op_occs table and send notification "COMPLETED"
self._send_lcm_op_occ_notification(
@ -782,6 +983,10 @@ class Conductor(manager.Manager):
)
except Exception as exc:
# set vnf_status to error
self._change_vnf_status(context, vnf_instance.id,
_PENDING_STATUS, 'ERROR')
# Update vnf_lcm_op_occs table and send notification "FAILED_TEMP"
self._send_lcm_op_occ_notification(
context=context,
@ -803,19 +1008,6 @@ class Conductor(manager.Manager):
vnf_lcm_op_occs_id):
try:
evacuate_end_list = []
# Check if vnf is in instantiated state.
vnf_instance = objects.VnfInstance.get_by_id(context,
vnf_instance.id)
if vnf_instance.instantiation_state == \
fields.VnfInstanceState.NOT_INSTANTIATED:
LOG.error("Heal action cannot be performed on vnf %(id)s "
"which is in %(state)s state.",
{"id": vnf_instance.id,
"state": vnf_instance.instantiation_state})
return
old_vnf_instance = copy.deepcopy(vnf_instance)
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
@ -828,15 +1020,25 @@ class Conductor(manager.Manager):
operation=fields.LcmOccsOperationType.HEAL
)
heal_result = \
self.vnflcm_driver.heal_vnf(context, vnf_instance, vnf_dict,
heal_vnf_request,
vnf_lcm_op_occs_id)
# update vnf status to PENDING_HEAL
self._change_vnf_status(context, vnf_instance.id,
_ACTIVE_STATUS, constants.PENDING_HEAL)
self.vnflcm_driver.heal_vnf(context, vnf_instance,
vnf_dict, heal_vnf_request)
self._update_instantiated_vnf_info(context, vnf_instance,
heal_vnf_request)
# update instance_in in vnf_table
self._add_additional_vnf_info(context, vnf_instance)
# update vnf status to ACTIVE
self._change_vnf_status(context, vnf_instance.id,
_PENDING_STATUS, constants.ACTIVE)
# during .save() ,instantiated_vnf_info is also saved to DB
self.vnflcm_driver._vnf_instance_update(context, vnf_instance,
task_state=None)
# update vnf_lcm_op_occs and send notification "COMPLETED"
if heal_result:
evacuate_end_list = heal_result.get('evacuate_end_list')
self._send_lcm_op_occ_notification(
context=context,
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
@ -844,10 +1046,16 @@ class Conductor(manager.Manager):
vnf_instance=vnf_instance,
request_obj=heal_vnf_request,
operation=fields.LcmOccsOperationType.HEAL,
operation_state=fields.LcmOccsOperationState.COMPLETED,
evacuate_end_list=evacuate_end_list
operation_state=fields.LcmOccsOperationState.COMPLETED
)
except Exception as ex:
# update vnf_status to 'ERROR' and create event with 'ERROR' status
self._change_vnf_status(context, vnf_instance,
_PENDING_STATUS, constants.ERROR, str(ex))
# call _update_instantiated_vnf_info for notification
self._update_instantiated_vnf_info(context, vnf_instance,
heal_vnf_request)
# update vnf_lcm_op_occs and send notification "FAILED_TEMP"
self._send_lcm_op_occ_notification(
@ -858,7 +1066,6 @@ class Conductor(manager.Manager):
request_obj=heal_vnf_request,
operation=fields.LcmOccsOperationType.HEAL,
operation_state=fields.LcmOccsOperationState.FAILED_TEMP,
evacuate_end_list=evacuate_end_list,
error=str(ex)
)

View File

@ -56,7 +56,28 @@ Possible values:
Related options:
* None
"""))]
""")),
cfg.ListOpt('get_top_list',
default=['tosca_definitions_version',
'description', 'metadata'],
help=_("List of items to get from top-vnfd")),
cfg.ListOpt('exclude_node',
default=['VNF'],
help=_("Exclude node from node_template")),
cfg.ListOpt('get_lower_list',
default=['tosca.nodes.nfv.VNF', 'tosca.nodes.nfv.VDU.Tacker'],
help=_("List of types to get from lower-vnfd")),
cfg.ListOpt('del_input_list',
default=['descriptor_id', 'descriptor_version'
'provider', 'product_name', 'software_version',
'vnfm_info', 'flavour_id', 'flavour_description'],
help=_("List of del inputs from lower-vnfd")),
]
vnf_package_group = cfg.OptGroup('vnf_package',
title='vnf_package options',

View File

@ -201,8 +201,8 @@ class VnfInstance(model_base.BASE, models.SoftDeleteMixin,
task_state = sa.Column(sa.String(255), nullable=True)
vim_connection_info = sa.Column(sa.JSON(), nullable=True)
tenant_id = sa.Column('tenant_id', sa.String(length=64), nullable=False)
vnf_metadata = sa.Column(sa.JSON(), nullable=True)
vnf_pkg_id = sa.Column(types.Uuid, nullable=False)
vnf_metadata = sa.Column(sa.JSON(), nullable=True)
class VnfInstantiatedInfo(model_base.BASE, models.SoftDeleteMixin,

View File

@ -34,6 +34,7 @@ def register_all():
__import__('tacker.objects.vim_connection')
__import__('tacker.objects.instantiate_vnf_req')
__import__('tacker.objects.vnf_resources')
__import__('tacker.objects.vnfd')
__import__('tacker.objects.vnf_lcm_op_occs')
__import__('tacker.objects.terminate_vnf_req')
__import__('tacker.objects.vnf_artifact')

View File

@ -51,6 +51,8 @@ class TerminateVnfRequest(base.TackerObject, base.TackerPersistentObject):
termination_type = data_dict.get('termination_type')
graceful_termination_timeout = \
data_dict.get('graceful_termination_timeout', 0)
additional_params = data_dict.get('additional_params', {})
return cls(termination_type=termination_type,
graceful_termination_timeout=graceful_termination_timeout)
graceful_termination_timeout=graceful_termination_timeout,
additional_params=additional_params)

View File

@ -12,11 +12,13 @@
# 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
from oslo_log import log as logging
from oslo_utils import timeutils
from oslo_utils import uuidutils
from oslo_versionedobjects import base as ovoo_base
from sqlalchemy import exc
from sqlalchemy.orm import joinedload
from sqlalchemy_filters import apply_filters
@ -135,6 +137,18 @@ def _make_vnf_instance_list(context, vnf_instance_list, db_vnf_instance_list,
return vnf_instance_list
# decorator to catch DBAccess exception
def _wrap_object_error(method):
def wrapper(*args, **kwargs):
try:
method(*args, **kwargs)
except exc.SQLAlchemyError:
raise exceptions.DBAccessError
return wrapper
@base.TackerObjectRegistry.register
class VnfInstance(base.TackerObject, base.TackerPersistentObject,
base.TackerObjectDictCompat):
@ -157,10 +171,10 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
'vim_connection_info': fields.ListOfObjectsField(
'VimConnectionInfo', nullable=True, default=[]),
'tenant_id': fields.StringField(nullable=False),
'instantiated_vnf_info': fields.ObjectField('InstantiatedVnfInfo',
nullable=True, default=None),
'vnf_pkg_id': fields.StringField(nullable=False),
'vnf_metadata': fields.DictOfStringsField(nullable=True, default={})
'vnf_metadata': fields.DictOfStringsField(nullable=True, default={}),
'instantiated_vnf_info': fields.ObjectField('InstantiatedVnfInfo',
nullable=True, default=None)
}
ALL_ATTRIBUTES = {
@ -239,12 +253,20 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
updates['id'] = uuidutils.generate_uuid()
self.id = updates['id']
# add default vnf_instance_name if not specified
# format: 'vnf' + <vnf instance id>
if 'vnf_instance_name' not in updates or \
not updates.get("vnf_instance_name"):
updates['vnf_instance_name'] = 'vnf-' + self.id
self.vnf_instance_name = updates['vnf_instance_name']
db_vnf_instance = _vnf_instance_create(self._context, updates)
expected_attrs = ["instantiated_vnf_info"]
self._from_db_object(self._context, self, db_vnf_instance,
expected_attrs=expected_attrs)
@base.remotable
@_wrap_object_error
def save(self):
context = self._context
@ -263,6 +285,10 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
field_list = getattr(self, field)
updates[field] = [obj.obj_to_primitive() for obj in field_list]
elif field in changes:
if (field == 'vnf_instance_name' and
not self[field]):
self.vnf_instance_name = 'vnf-' + self.id
updates[field] = self[field]
expected_attrs = ["instantiated_vnf_info"]
@ -277,6 +303,15 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
self.instantiated_vnf_info.save()
@base.remotable
@_wrap_object_error
def update_metadata(self, data):
_metadata = copy.deepcopy(self['vnf_metadata'])
_metadata.update(data)
self['vnf_metadata'] = _metadata
self.save()
@base.remotable
@_wrap_object_error
def destroy(self, context):
if not self.obj_attr_is_set('id'):
raise exceptions.ObjectActionError(action='destroy',
@ -293,8 +328,8 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
'vnf_provider': self.vnf_provider,
'vnf_product_name': self.vnf_product_name,
'vnf_software_version': self.vnf_software_version,
'vnf_pkg_id': self.vnf_pkg_id,
'vnfd_version': self.vnfd_version,
'vnf_pkg_id': self.vnf_pkg_id,
'vnf_metadata': self.vnf_metadata}
if (self.instantiation_state == fields.VnfInstanceState.INSTANTIATED

View File

@ -14,6 +14,7 @@
# under the License.
from oslo_log import log as logging
from oslo_utils import timeutils
from tacker.common import exceptions
from tacker.common import utils
@ -27,6 +28,17 @@ from tacker.objects import fields
LOG = logging.getLogger(__name__)
@db_api.context_manager.writer
def _destroy_instantiated_vnf_info(context, uuid):
now = timeutils.utcnow()
updated_values = {'deleted': True,
'deleted_at': now
}
api.model_query(context, models.VnfInstantiatedInfo). \
filter_by(vnf_instance_id=uuid). \
update(updated_values, synchronize_session=False)
@db_api.context_manager.writer
def _instantiate_vnf_info_update(context, vnf_instance_id, values):
vnf_info = api.model_query(context, models.VnfInstantiatedInfo). \
@ -375,6 +387,14 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
self.vnf_state = fields.VnfOperationalStateType.STOPPED
self.vnfc_info = []
@base.remotable
def destroy(self, context):
if not self.obj_attr_is_set('vnf_instance_id'):
raise exceptions.ObjectActionError(action='destroy',
reason='no uuid')
_destroy_instantiated_vnf_info(context, self.vnf_instance_id)
@base.TackerObjectRegistry.register
class VnfExtCpInfo(base.TackerObject, base.TackerObjectDictCompat,

View File

@ -502,9 +502,6 @@ class VnfPackage(base.TackerObject, base.TackerPersistentObject,
@base.remotable
def create(self):
if self.obj_attr_is_set('id'):
raise exceptions.ObjectActionError(action='create',
reason=_('already created'))
updates = self.obj_get_changes()
if 'id' not in updates:

View File

@ -59,6 +59,29 @@ def _vnf_package_vnfd_get_by_id(context, vnfd_id):
return result
@db_api.context_manager.reader
def _get_vnf_package_vnfd_by_vnfid(context, vnfpkgid):
sql = ("select"
" t1.vnfd_id,"
" t1.vnf_provider,"
" t1.vnf_product_name,"
" t1.vnf_software_version,"
" t1.vnfd_version,"
" t2.name"
" from "
" vnf_package_vnfd t1,"
" vnf t2 "
" where"
" t1.vnfd_id=t2.vnfd_id"
" and"
" t2.id= :vnfpkgid")
result = context.session.execute(sql, {'vnfpkgid': vnfpkgid})
for line in result:
return line
@base.TackerObjectRegistry.register
class VnfPackageVnfd(base.TackerObject, base.TackerObjectDictCompat,
base.TackerPersistentObject):
@ -104,6 +127,10 @@ class VnfPackageVnfd(base.TackerObject, base.TackerObjectDictCompat,
self._context, updates)
self._from_db_object(self._context, self, db_vnf_package_vnfd)
@base.remotable_classmethod
def get_vnf_package_vnfd_by_vnfid(self, context, vnfid):
return _get_vnf_package_vnfd_by_vnfid(context, vnfid)
@classmethod
def obj_from_db_obj(cls, context, db_obj):
return cls._from_db_object(context, cls(), db_obj)

132
tacker/objects/vnfd.py Normal file
View File

@ -0,0 +1,132 @@
# 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.
from oslo_utils import timeutils
from oslo_log import log as logging
from tacker.db import api as db_api
from tacker.db.db_sqlalchemy import api
from tacker.db.db_sqlalchemy import models
from tacker.db.vnfm import vnfm_db
from tacker.objects import base
from tacker.objects import fields
LOG = logging.getLogger(__name__)
@db_api.context_manager.writer
def _vnfd_create(context, values):
vnfd = vnfm_db.VNFD()
vnfd.update(values)
vnfd.save(context.session)
return vnfd
@db_api.context_manager.reader
def _get_vnfd_id(context, id):
try:
vnf_package_vnfd = \
api.model_query(context, models.VnfPackageVnfd).\
filter_by(package_uuid=id).first()
except Exception:
LOG.info("select vnf_package_vnfd failed")
if vnf_package_vnfd:
return vnf_package_vnfd.vnfd_id
else:
return None
@db_api.context_manager.reader
def _check_vnfd(context, id):
try:
vnfd = api.model_query(context, vnfm_db.VNFD).filter_by(id=id).first()
except Exception:
LOG.info("select vnfd failed")
if vnfd:
return "TRUE"
else:
return "FALSE"
@db_api.context_manager.writer
def _vnfd_delete(context, id):
try:
api.model_query(context, vnfm_db.VNFD).filter_by(id=id).delete()
except Exception:
LOG.info("delete vnfd failed")
@db_api.context_manager.writer
def _vnfd_destroy(context, id):
now = timeutils.utcnow()
updated_values = {'deleted_at': now}
try:
api.model_query(context, vnfm_db.VNFD).\
filter_by(id=id).\
update(updated_values, synchronize_session=False)
except Exception:
LOG.info("destroy vnfdfailed")
@base.TackerObjectRegistry.register
class Vnfd(base.TackerObject, base.TackerObjectDictCompat,
base.TackerPersistentObject):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'id': fields.UUIDField(nullable=False),
'tenant_id': fields.UUIDField(nullable=False),
'name': fields.StringField(nullable=False),
'description': fields.StringField(nullable=True),
'mgmt_driver': fields.StringField(nullable=True),
'deleted_at': fields.DateTimeField(nullable=True),
}
@staticmethod
def _from_db_object(context, vnfd, db_vnfd):
for key in vnfd.fields:
if db_vnfd.get(key):
setattr(vnfd, key, db_vnfd[key])
vnfd._context = context
vnfd.obj_reset_changes()
return vnfd
@base.remotable
def create(self):
updates = self.obj_get_changes()
db_vnfd = _vnfd_create(
self._context, updates)
self._from_db_object(self._context, self, db_vnfd)
@classmethod
def obj_from_db_obj(cls, context, db_obj):
return cls._from_db_object(context, cls(), db_obj)
@base.remotable
def destroy(self, id):
_vnfd_destroy(self._context, id)
@base.remotable
def delete(self, id):
_vnfd_delete(self._context, id)
@base.remotable
def check_vnfd(self, id):
return _check_vnfd(self._context, id)

View File

@ -0,0 +1,124 @@
# Copyright 2019 NTT DATA.
#
# 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.
from oslo_log import log as logging
from tacker.db import api as db_api
from tacker.db.db_sqlalchemy import api
from tacker.db.db_sqlalchemy import models
from tacker.db.vnfm import vnfm_db
from tacker.objects import base
from tacker.objects import fields
LOG = logging.getLogger(__name__)
@db_api.context_manager.writer
def _vnfd_attribute_create(context, values):
vnfd_attribute = vnfm_db.VNFDAttribute()
vnfd_attribute.update(values)
vnfd_attribute.save(context.session)
return vnfd_attribute
@db_api.context_manager.reader
def _get_vnfd_id(context, id):
try:
vnf_package_vnfd = \
api.model_query(context, models.VnfPackageVnfd).\
filter_by(package_uuid=id).first()
except Exception:
LOG.info("select vnfd_attribute failed")
if vnf_package_vnfd:
return vnf_package_vnfd.vnfd_id
else:
return None
@db_api.context_manager.reader
def _check_vnfd_attribute(context, id):
try:
vnfd_attribute = \
api.model_query(context, vnfm_db.VNFDAttribute).\
filter_by(vnfd_id=id).first()
except Exception:
LOG.info("select vnfd_attribute failed")
if vnfd_attribute:
return "TRUE"
else:
return "FALSE"
@db_api.context_manager.writer
def _vnfd_attribute_delete(context, id):
try:
api.model_query(context, vnfm_db.VNFDAttribute).\
filter_by(vnfd_id=id).delete()
except Exception:
LOG.info("delete vnfd_attribute failed")
@base.TackerObjectRegistry.register
class VnfdAttribute(base.TackerObject, base.TackerObjectDictCompat,
base.TackerPersistentObject):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'id': fields.UUIDField(nullable=False),
'vnfd_id': fields.UUIDField(nullable=False),
'key': fields.StringField(nullable=True),
'value': fields.StringField(nullable=True),
}
@staticmethod
def _from_db_object(context, vnfd_attribute, db_vnfd_attribute):
for key in vnfd_attribute.fields:
if db_vnfd_attribute.get(key):
setattr(vnfd_attribute, key, db_vnfd_attribute[key])
vnfd_attribute._context = context
vnfd_attribute.obj_reset_changes()
return vnfd_attribute
@base.remotable
def create(self):
updates = self.obj_get_changes()
db_vnfd_attribute = _vnfd_attribute_create(
self._context, updates)
self._from_db_object(self._context, self, db_vnfd_attribute)
@classmethod
def obj_from_db_obj(cls, context, db_obj):
return cls._from_db_object(context, cls(), db_obj)
@base.remotable
def destroy(self, id):
vnfd_attribute_id = _get_vnfd_id(self._context, id)
if vnfd_attribute_id:
_vnfd_attribute_delete(self._context, vnfd_attribute_id)
@base.remotable
def delete(self, id):
_vnfd_attribute_delete(self._context, id)
@base.remotable
def check_vnfd_attribute(self, id):
return _check_vnfd_attribute(self._context, id)

View File

@ -14,31 +14,29 @@
# limitations under the License.
import base64
import fixtures
import json
import os
import requests
import shutil
import six.moves.urllib.error as urlerr
import sys
from unittest import mock
import fixtures
import tacker.conf
import yaml
from glance_store import exceptions as store_exceptions
from oslo_config import cfg
import requests
from six.moves import urllib
import six.moves.urllib.error as urlerr
import yaml
from tacker import auth
from tacker.common import coordination
from tacker.common import csar_utils
from tacker.common import exceptions
from tacker.conductor import conductor_server
import tacker.conf
from tacker import context
from tacker.glance_store import store as glance_store
from tacker import objects
from tacker.objects import fields
from tacker.plugins.common import constants
from tacker.tests.unit import base as unit_base
from tacker.tests.unit.conductor import fakes
from tacker.tests.unit.db.base import SqlTestCase
@ -46,9 +44,14 @@ from tacker.tests.unit.db import utils as db_utils
from tacker.tests.unit.objects import fakes as fake_obj
from tacker.tests.unit.vnflcm import fakes as vnflcm_fakes
from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import client
from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import \
fixture_data_utils as fd_utils
import tacker.tests.unit.vnfm.test_nfvo_client as nfvo_client
from tacker.tests import utils
from tacker.tests import uuidsentinel
import unittest
from unittest import mock
CONF = tacker.conf.CONF
@ -254,14 +257,16 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
return vnf_pack_vnfd_obj
@mock.patch('tacker.conductor.conductor_server.Conductor'
'._update_vnf_attributes')
@mock.patch('tacker.conductor.conductor_server.Conductor'
'._change_vnf_status')
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(coordination.Coordinator, 'get_lock')
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
def test_instantiate_vnf_instance(self, mock_vnf_by_id,
mock_package_in_use,
mock_get_lock,
mock_save):
mock_get_lock, mock_save, mock_change_vnf_status,
mock_update_vnf_attributes):
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
mock_vnf_by_id.return_value = \
objects.VnfLcmOpOcc(context=self.context,
@ -270,19 +275,23 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
vnf_package_vnfd = self._create_and_upload_vnf_package()
vnf_instance_data = fake_obj.get_vnf_instance_data(
vnf_package_vnfd.vnfd_id)
mock_package_in_use.return_value = False
vnf_instance = objects.VnfInstance(context=self.context,
**vnf_instance_data)
vnf_instance.create()
instantiate_vnf_req = vnflcm_fakes.get_instantiate_vnf_request_obj()
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
self.conductor.instantiate(self.context, vnf_instance,
instantiate_vnf_req,
vnf_lcm_op_occs_id)
vnf_dict = {"status": "ACTIVE"}
self.conductor.instantiate(self.context, vnf_instance, vnf_dict,
instantiate_vnf_req, vnf_lcm_op_occs_id)
self.vnflcm_driver.instantiate_vnf.assert_called_once_with(
self.context, mock.ANY, instantiate_vnf_req)
mock_package_in_use.assert_called_once()
self.context, mock.ANY, vnf_dict, instantiate_vnf_req)
self.vnflcm_driver._vnf_instance_update.assert_called_once()
mock_change_vnf_status. \
assert_called_once_with(self.context, vnf_instance.id,
mock.ANY, 'PENDING_CREATE')
mock_update_vnf_attributes.assert_called_once()
@unittest.skip("Such test is no longer feasible.")
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(coordination.Coordinator, 'get_lock')
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
@ -316,6 +325,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
{'id': vnf_instance.id,
'state': fields.VnfInstanceState.INSTANTIATED})
@unittest.skip("Such test is no longer feasible.")
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(coordination.Coordinator, 'get_lock')
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
@ -351,9 +361,12 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
self.context, mock.ANY, instantiate_vnf_req)
mock_vnf_package_in_use.assert_called_once()
@mock.patch('tacker.conductor.conductor_server.Conductor'
'._update_vnf_attributes')
@mock.patch('tacker.conductor.conductor_server.Conductor'
'._change_vnf_status')
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(coordination.Coordinator, 'get_lock')
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
@mock.patch.object(objects.LccnSubscriptionRequest,
'vnf_lcm_subscriptions_get')
@mock.patch('tacker.conductor.conductor_server.LOG')
@ -362,7 +375,8 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
def test_instantiate_vnf_instance_failed_with_exception(
self, mock_res, mock_vnf_by_id, mock_log,
mock_vnf_lcm_subscriptions_get,
mock_is_package_in_use, mock_get_lock, mock_save):
mock_get_lock, mock_save, mock_change_vnf_status,
mock_update_vnf_attributes):
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
mock_vnf_by_id.return_value = \
objects.VnfLcmOpOcc(context=self.context,
@ -376,38 +390,32 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
vnf_instance.create()
instantiate_vnf_req = vnflcm_fakes.get_instantiate_vnf_request_obj()
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
vnf_dict = {"status": "ACTIVE"}
m_vnf_lcm_subscriptions = \
[mock.MagicMock(**fakes.get_vnf_lcm_subscriptions())]
mock_vnf_lcm_subscriptions_get.return_value = \
m_vnf_lcm_subscriptions
mock_is_package_in_use.side_effect = Exception
mock_update_vnf_attributes.side_effect = Exception
mock_res.return_value = {}
self.conductor.instantiate(self.context, vnf_instance,
instantiate_vnf_req,
vnf_lcm_op_occs_id)
self.conductor.instantiate(self.context, vnf_instance, vnf_dict,
instantiate_vnf_req, vnf_lcm_op_occs_id)
self.vnflcm_driver.instantiate_vnf.assert_called_once_with(
self.context, mock.ANY, instantiate_vnf_req)
mock_is_package_in_use.assert_called_once()
expected_log = 'Failed to update usage_state of vnf package %s'
mock_log.error.assert_called_once_with(expected_log,
vnf_package_vnfd.package_uuid)
self.context, vnf_instance, vnf_dict, instantiate_vnf_req)
mock_change_vnf_status.assert_called_with(self.context,
vnf_instance.id, mock.ANY, 'ERROR')
mock_update_vnf_attributes.assert_called_once()
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_send_lcm_op_occ_notification')
@mock.patch('tacker.conductor.conductor_server.Conductor'
'._change_vnf_status')
@mock.patch('tacker.conductor.conductor_server.Conductor'
'._send_lcm_op_occ_notification')
@mock.patch.object(coordination.Coordinator, 'get_lock')
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
def test_terminate_vnf_instance(self, mock_package_in_use,
mock_get_lock,
mock_send_notification):
vnf_package_vnfd = self._create_and_upload_vnf_package()
vnf_instance_data = fake_obj.get_vnf_instance_data(
vnf_package_vnfd.vnfd_id)
mock_package_in_use.return_value = True
vnf_instance_data['instantiation_state'] =\
fields.VnfInstanceState.INSTANTIATED
vnf_instance = objects.VnfInstance(context=self.context,
**vnf_instance_data)
vnf_instance.create()
def test_terminate_vnf_instance(self, mock_get_lock,
mock_send_notification,
mock_change_vnf_status):
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
vnf_instance = fd_utils. \
get_vnf_instance_object(instantiated_vnf_info=inst_vnf_info)
terminate_vnf_req = objects.TerminateVnfRequest(
termination_type=fields.VnfInstanceTerminationType.GRACEFUL,
@ -415,14 +423,43 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
vnf_dict = db_utils.get_dummy_vnf(instance_id=self.instance_uuid)
self.conductor.terminate(self.context, vnf_lcm_op_occs_id,
vnf_instance,
terminate_vnf_req, vnf_dict)
vnf_instance, terminate_vnf_req, vnf_dict)
self.vnflcm_driver.terminate_vnf.assert_called_once_with(
self.context, mock.ANY, terminate_vnf_req,
vnf_lcm_op_occs_id)
mock_package_in_use.assert_called_once()
self.context, vnf_instance, terminate_vnf_req)
self.vnflcm_driver._vnf_instance_update.assert_called_once()
self.assertEqual(mock_send_notification.call_count, 2)
self.assertEqual(mock_change_vnf_status.call_count, 2)
@mock.patch('tacker.conductor.conductor_server.Conductor'
'._change_vnf_status')
@mock.patch('tacker.conductor.conductor_server.Conductor'
'._send_lcm_op_occ_notification')
@mock.patch.object(coordination.Coordinator, 'get_lock')
def test_terminate_vnf_instance_exception(self, mock_get_lock,
mock_send_notification,
mock_change_vnf_status):
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
vnf_instance = fd_utils. \
get_vnf_instance_object(instantiated_vnf_info=inst_vnf_info)
mock_send_notification.side_effect = Exception
terminate_vnf_req = objects.TerminateVnfRequest(
termination_type=fields.VnfInstanceTerminationType.GRACEFUL,
additional_params={"key": "value"})
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
vnf_dict = db_utils.get_dummy_vnf(instance_id=self.instance_uuid)
try:
self.conductor.terminate(self.context, vnf_lcm_op_occs_id,
vnf_instance, terminate_vnf_req, vnf_dict)
except Exception:
pass
self.vnflcm_driver.terminate_vnf.assert_not_called()
mock_change_vnf_status.assert_called_once_with(self.context,
vnf_instance.id, mock.ANY, 'ERROR')
self.assertEqual(mock_send_notification.call_count, 2)
@unittest.skip("Such test is no longer feasible.")
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_send_lcm_op_occ_notification')
@mock.patch.object(coordination.Coordinator, 'get_lock')
@ -458,6 +495,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
{'id': vnf_instance.id,
'state': fields.VnfInstanceState.NOT_INSTANTIATED})
@unittest.skip("Such test is no longer feasible.")
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_send_lcm_op_occ_notification')
@mock.patch.object(coordination.Coordinator, 'get_lock')
@ -489,6 +527,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
vnf_lcm_op_occs_id)
mock_vnf_package_is_package_in_use.assert_called_once()
@unittest.skip("Such test is no longer feasible.")
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_send_lcm_op_occ_notification')
@mock.patch.object(coordination.Coordinator, 'get_lock')
@ -520,6 +559,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
vnf_lcm_op_occs_id)
mock_vnf_package_is_package_in_use.assert_called_once()
@unittest.skip("Such test is no longer feasible.")
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_send_lcm_op_occ_notification')
@mock.patch.object(coordination.Coordinator, 'get_lock')
@ -552,11 +592,18 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
mock_log.error.assert_called_once_with(expected_msg,
vnf_package_vnfd.package_uuid)
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_add_additional_vnf_info')
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_update_instantiated_vnf_info')
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_change_vnf_status')
@mock.patch.object(objects.VnfLcmOpOcc, "save")
@mock.patch.object(coordination.Coordinator, 'get_lock')
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
def test_heal_vnf_instance(self, mock_vnf_by_id, mock_get_lock,
mock_save):
mock_save, mock_change_vnf_status,
mock_update_insta_vnf_info, mock_add_additional_vnf_info):
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
mock_vnf_by_id.return_value = \
objects.VnfLcmOpOcc(context=self.context,
@ -575,7 +622,49 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
self.conductor.heal(self.context, vnf_instance, vnf_dict,
heal_vnf_req, vnf_lcm_op_occs_id)
self.assertEqual(mock_change_vnf_status.call_count, 2)
mock_update_insta_vnf_info. \
assert_called_once_with(self.context, vnf_instance, heal_vnf_req)
mock_add_additional_vnf_info. \
assert_called_once_with(self.context, vnf_instance)
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_send_lcm_op_occ_notification')
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_update_instantiated_vnf_info')
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_change_vnf_status')
@mock.patch('tacker.conductor.conductor_server.Conductor.'
'_add_additional_vnf_info')
@mock.patch.object(coordination.Coordinator, 'get_lock')
@mock.patch('tacker.conductor.conductor_server.LOG')
def test_heal_vnf_instance_exception(self,
mock_log, mock_get_lock, mock_add_additional_vnf_info,
mock_change_vnf_status, mock_update_insta_vnf_info,
mock_send_notification):
vnf_package_vnfd = self._create_and_upload_vnf_package()
vnf_instance_data = fake_obj.get_vnf_instance_data(
vnf_package_vnfd.vnfd_id)
vnf_instance_data['instantiation_state'] =\
fields.VnfInstanceState.NOT_INSTANTIATED
vnf_instance = objects.VnfInstance(context=self.context,
**vnf_instance_data)
vnf_instance.create()
mock_add_additional_vnf_info.side_effect = Exception
heal_vnf_req = objects.HealVnfRequest(cause="healing request")
vnf_dict = {"fake": "fake_dict"}
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
self.conductor.heal(self.context, vnf_instance, vnf_dict,
heal_vnf_req, vnf_lcm_op_occs_id)
mock_change_vnf_status.assert_called_with(self.context,
vnf_instance, mock.ANY, constants.ERROR, "")
mock_update_insta_vnf_info.assert_called_with(self.context,
vnf_instance, heal_vnf_req)
self.assertEqual(mock_send_notification.call_count, 2)
@unittest.skip("Such test is no longer feasible.")
@mock.patch.object(coordination.Coordinator, 'get_lock')
@mock.patch('tacker.conductor.conductor_server.LOG')
def test_heal_vnf_instance_already_not_instantiated(self,

View File

@ -97,9 +97,15 @@ class TestVnfPackage(SqlTestCase):
uuidsentinel.invalid_uuid)
def test_create_with_id(self):
vnf_obj = {'id': uuidsentinel.uuid}
vnf_pack = objects.VnfPackage(context=self.context, **vnf_obj)
self.assertRaises(exceptions.ObjectActionError, vnf_pack.create)
vnfpkgm = objects.VnfPackage(context=self.context,
**fakes.vnf_package_data)
vnfpkgm['id'] = uuidsentinel.uuid
vnfpkgm.create()
self.assertTrue(vnfpkgm.id)
self.assertEqual('CREATED', vnfpkgm.onboarding_state)
self.assertEqual('NOT_IN_USE', vnfpkgm.usage_state)
self.assertEqual('DISABLED', vnfpkgm.operational_state)
self.assertEqual(0, vnfpkgm.size)
def test_save(self):
self.vnf_package.onboarding_state = 'ONBOARDED'

View File

@ -119,8 +119,8 @@ def _model_non_instantiated_vnf_instance(**updates):
'vnf_software_version': '1.0',
'tenant_id': uuidsentinel.tenant_id,
'vnfd_id': uuidsentinel.vnfd_id,
'vnf_pkg_id': uuidsentinel.vnf_pkg_id,
'vnfd_version': '1.0',
'vnf_pkg_id': uuidsentinel.vnf_pkg_id,
'vnf_metadata': {"key": "value"}}
if updates:

View File

@ -26,6 +26,7 @@ import webob
from webob import exc
from tacker.api.vnflcm.v1 import controller
from tacker.api.vnflcm.v1 import sync_resource
from tacker.common import exceptions
from tacker.conductor.conductorrpc.vnf_lcm_rpc import VNFLcmRPCAPI
from tacker import context
@ -42,9 +43,15 @@ from tacker.tests.unit import fake_request
import tacker.tests.unit.nfvo.test_nfvo_plugin as nfvo_plugin
from tacker.tests.unit.vnflcm import fakes
from tacker.tests import uuidsentinel
import tacker.vnfm.nfvo_client as nfvo_client
from tacker.vnfm.nfvo_client import VnfPackageRequest
from tacker.vnfm import vim_client
class FakeVimClient(mock.Mock):
pass
def _get_template(name):
filename = os.path.abspath(os.path.join(os.path.dirname(__file__),
'../../etc/samples/' + str(name)))
@ -231,29 +238,31 @@ class TestController(base.TestCase):
res.status_int = status
return res
@mock.patch.object(objects.VnfInstance, 'save')
@mock.patch.object(vim_client.VimClient, "get_vim")
@mock.patch.object(objects.vnf_package.VnfPackage, 'get_by_id')
@mock.patch.object(objects.vnf_package.VnfPackage, 'save')
@mock.patch('tacker.api.vnflcm.v1.controller.'
'VnfLcmController._update_package_usage_state')
@mock.patch.object(objects.VnfPackage, 'get_by_id')
@mock.patch('tacker.api.vnflcm.v1.controller.'
'VnfLcmController._create_vnf')
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.vnf_instance, '_vnf_instance_create')
@mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
def test_create_without_name_and_description(
self, mock_get_by_id_package_vnfd,
mock_vnf_instance_create, mock_package_save,
mock_get_by_id_package, mock_get_vim,
mock_save):
mock_get_vim.return_value = self.vim_info
mock_get_by_id_package_vnfd.return_value = \
fakes.return_vnf_package_vnfd()
mock_get_by_id_package.return_value = \
fakes.return_vnf_package_with_deployment_flavour()
self, mock_get_by_id,
mock_vnf_instance_create,
mock_get_service_plugins,
mock_private_create_vnf,
mock_vnf_package_get_by_id,
mock_update_package_usage_state,
mock_get_vim):
mock_get_by_id.return_value = fakes.return_vnf_package_vnfd()
updates = {'vnfd_id': uuidsentinel.vnfd_id,
'vnf_instance_description': None,
'vnf_instance_name': None,
'vnf_pkg_id': uuidsentinel.vnf_pkg_id,
'vnf_metadata': {"key": "value"}}
mock_vnf_instance_create.return_value =\
fakes.return_vnf_instance_model(**updates)
@ -262,7 +271,6 @@ class TestController(base.TestCase):
'metadata': {"key": "value"}}
req.body = jsonutils.dump_as_bytes(body)
req.headers['Content-Type'] = 'application/json'
req.headers['Version'] = '2.6.1'
req.method = 'POST'
# Call create API
@ -271,15 +279,15 @@ class TestController(base.TestCase):
self.assertEqual(http_client.CREATED, resp.status_code)
updates = {'vnfInstanceDescription': None, 'vnfInstanceName': None}
expected_vnf = fakes.fake_vnf_instance_response(
instantiated_state=fields.VnfInstanceState.NOT_INSTANTIATED,
**updates)
expected_vnf = fakes.fake_vnf_instance_response(**updates)
location_header = ('http://localhost/vnflcm/v1/vnf_instances/%s'
% resp.json['id'])
self.assertEqual(expected_vnf, resp.json)
self.assertEqual(location_header, resp.headers['location'])
@mock.patch('tacker.api.vnflcm.v1.controller.'
'VnfLcmController._create_vnf')
@mock.patch.object(objects.VnfInstance, 'save')
@mock.patch.object(vim_client.VimClient, "get_vim")
@mock.patch.object(objects.vnf_package.VnfPackage, 'get_by_id')
@ -290,7 +298,7 @@ class TestController(base.TestCase):
self, mock_get_by_id_package_vnfd,
mock_vnf_instance_create, mock_package_save,
mock_get_by_id_package, mock_get_vim,
mock_save):
mock_save, mock_create_vnf):
mock_get_vim.return_value = self.vim_info
mock_get_by_id_package_vnfd.return_value = \
fakes.return_vnf_package_vnfd()
@ -313,13 +321,13 @@ class TestController(base.TestCase):
req = fake_request.HTTPRequest.blank('/vnf_instances')
req.body = jsonutils.dump_as_bytes(body)
req.headers['Content-Type'] = 'application/json'
req.headers['Version'] = '2.6.1'
req.method = 'POST'
# Call Create API
resp = req.get_response(self.app)
self.assertEqual(http_client.CREATED, resp.status_code)
updates = {"vnfInstanceName": "SampleVnf",
"vnfInstanceDescription": "SampleVnf Description"}
expected_vnf = fakes.fake_vnf_instance_response(**updates)
@ -329,49 +337,6 @@ class TestController(base.TestCase):
self.assertEqual(expected_vnf, resp.json)
self.assertEqual(location_header, resp.headers['location'])
@mock.patch.object(objects.VnfInstance, 'save')
@mock.patch.object(vim_client.VimClient, "get_vim")
@mock.patch.object(objects.vnf_package.VnfPackage, 'get_by_id')
@mock.patch.object(objects.vnf_package.VnfPackage, 'save')
@mock.patch.object(objects.vnf_instance, '_vnf_instance_create')
@mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
def test_create_without_name_and_description_with_v241(
self, mock_get_by_id_package_vnfd,
mock_vnf_instance_create, mock_package_save,
mock_get_by_id_package, mock_get_vim,
mock_save):
mock_get_vim.return_value = self.vim_info
mock_get_by_id_package_vnfd.return_value = \
fakes.return_vnf_package_vnfd()
mock_get_by_id_package.return_value = \
fakes.return_vnf_package_with_deployment_flavour()
updates = {'vnfd_id': uuidsentinel.vnfd_id,
'vnf_instance_description': None,
'vnf_instance_name': None,
'vnf_pkg_id': uuidsentinel.vnf_pkg_id,
'metadata': {'key': 'value'}}
mock_vnf_instance_create.return_value =\
fakes.return_vnf_instance_model(**updates)
req = fake_request.HTTPRequest.blank('/vnf_instances')
body = {'vnfdId': uuidsentinel.vnfd_id}
req.body = jsonutils.dump_as_bytes(body)
req.headers['Content-Type'] = 'application/json'
req.headers['Version'] = ''
req.method = 'POST'
# Call create API
resp = req.get_response(self.app)
self.assertEqual(http_client.CREATED, resp.status_code)
updates = {'vnfInstanceDescription': None, 'vnfInstanceName': None}
expected_vnf = fakes.fake_vnf_instance_response(**updates)
self.assertEqual(expected_vnf, resp.json)
@ddt.data(
{'attribute': 'vnfdId', 'value': True,
'expected_type': 'uuid'},
@ -384,13 +349,7 @@ class TestController(base.TestCase):
{'attribute': 'vnfInstanceDescription', 'value': True,
'expected_type': 'description'},
{'attribute': 'vnfInstanceDescription', 'value': 123,
'expected_type': 'description'},
{'attribute': 'metadata', 'value': ['val1', 'val2'],
'expected_type': 'object'},
{'attribute': 'metadata', 'value': True,
'expected_type': 'object'},
{'attribute': 'metadata', 'value': 123,
'expected_type': 'object'},
'expected_type': 'description'}
)
@ddt.unpack
def test_create_with_invalid_request_body(
@ -404,7 +363,6 @@ class TestController(base.TestCase):
body.update({attribute: value})
req.body = jsonutils.dump_as_bytes(body)
req.headers['Content-Type'] = 'application/json'
req.headers['Version'] = '2.6.1'
req.method = 'POST'
exception = self.assertRaises(
exceptions.ValidationError, self.controller.create,
@ -428,28 +386,160 @@ class TestController(base.TestCase):
self.assertEqual(expected_message, exception.msg)
@mock.patch.object(sync_resource.SyncVnfPackage, 'create_package')
@mock.patch.object(nfvo_client.VnfPackageRequest, "index")
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
def test_create_non_existing_vnf_package_vnfd(self, mock_vnf_by_id):
def test_create_non_existing_vnf_package_vnfd(self, mock_vnf_by_id,
mock_get_service_plugins,
mock_index,
mock_create_package):
mock_vnf_by_id.side_effect = exceptions.VnfPackageVnfdNotFound
mock_create_package.return_value = fakes.return_vnf_package_vnfd()
mock_response = mock.MagicMock()
mock_response.ok = True
mock_response.json = mock.MagicMock()
mock_response.json.return_value = ['aaa', 'bbb', 'ccc']
mock_index.return_value = mock_response
body = {'vnfdId': uuidsentinel.vnfd_id,
'metadata': {"key": "value"}}
req = fake_request.HTTPRequest.blank('/vnf_instances')
req.body = jsonutils.dump_as_bytes(body)
req.headers['Content-Type'] = 'application/json'
req.headers['Version'] = '2.6.1'
req.method = 'POST'
self.assertRaises(exc.HTTPBadRequest, self.controller.create, req,
body=body)
def test_create_without_vnfd_id(self):
@mock.patch.object(vim_client.VimClient, "get_vim")
@mock.patch('tacker.api.vnflcm.v1.controller.'
'VnfLcmController._update_package_usage_state')
@mock.patch.object(objects.VnfPackage, 'get_by_id')
@mock.patch('tacker.api.vnflcm.v1.controller.'
'VnfLcmController._create_vnf')
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(sync_resource.SyncVnfPackage, 'create_package')
@mock.patch.object(VnfPackageRequest, "index")
@mock.patch.object(objects.vnf_instance, '_vnf_instance_create')
@mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
def test_create_vnf_package_not_found(
self, mock_get_by_id_package_vnfd,
mock_vnf_instance_create,
mock_index, mock_create_pkg,
mock_get_service_plugins,
mock_private_create_vnf,
mock_vnf_package_get_by_id,
mock_update_package_usage_state,
mock_get_vim):
mock_get_by_id_package_vnfd.side_effect =\
exceptions.VnfPackageVnfdNotFound
mock_response = mock.MagicMock()
mock_response.ok = True
mock_response.json = mock.MagicMock()
mock_response.json.return_value = ['aaa', 'bbb', 'ccc']
mock_index.return_value = mock_response
mock_create_pkg.return_value = fakes.return_vnf_package_vnfd()
updates = {'vnfd_id': uuidsentinel.vnfd_id}
mock_vnf_instance_create.return_value =\
fakes.return_vnf_instance_model(**updates)
body = {'vnfdId': uuidsentinel.vnfd_id}
req = fake_request.HTTPRequest.blank('/vnf_instances')
req.body = jsonutils.dump_as_bytes(body)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
req.environ['tacker.context'] = self.context
# Call Create API
resp = req.get_response(self.app)
self.assertEqual(http_client.CREATED, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(sync_resource.SyncVnfPackage, 'create_package')
@mock.patch.object(VnfPackageRequest, "index")
@mock.patch.object(objects.vnf_instance, '_vnf_instance_create')
@mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
def test_create_vnf_package_vnfd_not_found(
self, mock_get_by_id_package_vnfd,
mock_vnf_instance_create,
mock_index, mock_create_pkg,
mock_get_service_plugins):
mock_get_by_id_package_vnfd.side_effect =\
exceptions.VnfPackageVnfdNotFound
mock_response = mock.MagicMock()
mock_response.ok = True
mock_response.json = mock.MagicMock()
mock_response.json.return_value = ['aaa', 'bbb', 'ccc']
mock_index.return_value = mock_response
mock_create_pkg.return_value = None
updates = {'vnfd_id': uuidsentinel.vnfd_id}
mock_vnf_instance_create.return_value =\
fakes.return_vnf_instance_model(**updates)
body = {'vnfdId': uuidsentinel.vnfd_id}
req = fake_request.HTTPRequest.blank('/vnf_instances')
req.body = jsonutils.dump_as_bytes(body)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
# Call Create API
resp = req.get_response(self.app)
self.assertEqual(http_client.INTERNAL_SERVER_ERROR, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(VnfPackageRequest, "index")
@mock.patch.object(objects.vnf_instance, '_vnf_instance_create')
@mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
def test_create_non_vnf_package_info(
self, mock_get_by_id_package_vnfd,
mock_vnf_instance_create,
mock_index, mock_get_service_plugins):
mock_get_by_id_package_vnfd.side_effect =\
exceptions.VnfPackageVnfdNotFound
mock_response = mock.MagicMock()
mock_response.ok = False
mock_response.json = mock.MagicMock()
mock_response.json.return_value = {}
mock_index.return_value = mock_response
updates = {'vnfd_id': uuidsentinel.vnfd_id}
mock_vnf_instance_create.return_value =\
fakes.return_vnf_instance_model(**updates)
body = {'vnfdId': uuidsentinel.vnfd_id}
req = fake_request.HTTPRequest.blank('/vnf_instances')
req.body = jsonutils.dump_as_bytes(body)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
# Call Create API
resp = req.get_response(self.app)
self.assertEqual(http_client.NOT_FOUND, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
def test_create_without_vnfd_id(self, mock_get_service_plugins):
body = {"vnfInstanceName": "SampleVnfInstance",
'metadata': {"key": "value"}}
"metadata": {"key": "value"}}
req = fake_request.HTTPRequest.blank(
'/vnf_instances')
req.body = jsonutils.dump_as_bytes(body)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
resp = req.get_response(self.app)
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
@ddt.data('PATCH', 'PUT', 'HEAD', 'DELETE')
@ -461,29 +551,38 @@ class TestController(base.TestCase):
req.headers['Content-Type'] = 'application/json'
req.method = method
resp = req.get_response(self.app)
self.assertEqual(http_client.METHOD_NOT_ALLOWED, resp.status_code)
@ddt.data({'name': "A" * 256, 'description': "VNF Description",
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@ddt.data({'name': "A" * 256,
'description': "VNF Description",
'meta': {"key": "value"}},
{'name': 'Fake-VNF', 'description': "A" * 1025,
{'name': 'Fake-VNF',
'description': "A" * 1025,
'meta': {"key": "value"}},
{'name': 'Fake-VNF', 'description': "VNF Description",
{'name': 'Fake-VNF',
'description': "VNF Description",
'meta': {"key": "v" * 256}})
@ddt.unpack
def test_create_max_length_exceeded_for_vnf_name_and_description(
self, name, description, meta):
self, values, mock_get_service_plugins):
name = values['name']
meta = values['meta']
description = values['description']
# vnf instance_name and description with length greater than max
# length defined
body = {"vnfInstanceName": name,
"vnfdId": uuidsentinel.vnfd_id,
"vnfInstanceDescription": description,
"metadata": meta}
'metadata': meta}
req = fake_request.HTTPRequest.blank(
'/vnf_instances')
req.body = jsonutils.dump_as_bytes(body)
req.headers['Content-Type'] = 'application/json'
req.method = 'POST'
resp = req.get_response(self.app)
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
@ -1487,9 +1586,14 @@ class TestController(base.TestCase):
resp = req.get_response(self.app)
self.assertEqual(http_client.METHOD_NOT_ALLOWED, resp.status_code)
@mock.patch('tacker.api.vnflcm.v1.controller.'
'VnfLcmController._delete')
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
@mock.patch.object(objects.vnf_instance, '_destroy_vnf_instance')
def test_delete(self, mock_destroy_vnf_instance, mock_vnf_by_id):
def test_delete(self, mock_destroy_vnf_instance, mock_vnf_by_id,
mock_get_service_plugins, mock_private_delete):
req = fake_request.HTTPRequest.blank(
'/vnf_instances/%s' % uuidsentinel.vnf_instance_id)
req.method = 'DELETE'
@ -1500,7 +1604,6 @@ class TestController(base.TestCase):
resp = req.get_response(self.app)
self.assertEqual(http_client.NO_CONTENT, resp.status_code)
mock_destroy_vnf_instance.assert_called_once()
@mock.patch.object(objects.VnfInstance, "get_by_id")
def test_delete_with_non_existing_vnf_instance(self, mock_vnf_by_id):

View File

@ -0,0 +1,350 @@
# 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.
import ddt
from tacker.api.vnflcm.v1 import sync_resource as sync
from tacker.conductor.conductorrpc import vnf_pkgm_rpc
from tacker import context
from tacker.db.nfvo import nfvo_db
from tacker.glance_store import store as glance_store
from tacker import objects
from tacker.tests.unit import base
from tacker.tests.unit.vnflcm import fakes as vnflcm_fakes
from tacker.tests.unit.vnfpkgm import fakes as vnfpkgm_fakes
from tacker.tests import uuidsentinel
import tacker.vnfm.nfvo_client as nfvo_client
from unittest import mock
from webob import exc
@ddt.ddt
class TestSyncVnfPackage(base.TestCase):
def setUp(self):
super(TestSyncVnfPackage, self).setUp()
self.context = context.ContextBase(
uuidsentinel.user_id,
uuidsentinel.project_id,
is_admin=True)
self.vim = nfvo_db.Vim()
def tearDown(self):
super(TestSyncVnfPackage, self).tearDown()
self.addCleanup(mock.patch.stopall)
@mock.patch.object(glance_store, 'store_csar')
@mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd,
'get_by_id')
@mock.patch.object(objects.vnf_package, '_vnf_package_create')
@mock.patch.object(objects.vnf_package.VnfPackage, 'save')
@mock.patch.object(objects.vnf_package.VnfPackage, '_from_db_object')
@mock.patch.object(nfvo_client.VnfPackageRequest, 'download_vnf_packages')
@mock.patch.object(vnf_pkgm_rpc.VNFPackageRPCAPI,
"upload_vnf_package_content")
def test_package_and_package_vnfd_creation_successful(self,
mock_upload_vnf_package_content,
mock_nfvo_download_vnf_packages,
mock_from_db_vnf_package,
mock_save_vnf_package,
mock_vnf_package,
mock_get_by_id,
mock_glance_store):
# glance_store mock Settings
mock_glance_store.return_value = 'location', 0, 'checksum',\
'multihash', 'loc_meta'
updates = {'additionalArtifacts': [
{
'artifactPath': 'sample1_file.yaml',
'checksum': {
'hash':
'53b504e608eef3d19a\
22413bf6ee72f42091fbb5213e6a876a3a22f6c3c94fe1',
'algorithm': 'SHA-256'
}
},
{
'artifactPath': 'sample2_file.yaml',
'checksum': {
'hash':
'43b504e608eef3d19a\
22413bf6ee72f42091fbb5213e6a876a3a22f6c3c94fe1',
'algorithm': 'SHA-256'
}
}
]}
vnf_package_info = vnfpkgm_fakes.index_response(
remove_attrs=['userDefinedData'],
vnf_package_updates=updates)[0]
exp_vnf_package_vnfd = \
vnflcm_fakes.fake_vnf_package_vnfd_model_dict(**updates)
mock_get_by_id.return_value = exp_vnf_package_vnfd
vnf_package_vnfd = sync.SyncVnfPackage.create_package(
self.context, vnf_package_info)
# Expected value setting
self.assertEqual(exp_vnf_package_vnfd.get('package_uuid'),
vnf_package_vnfd.get('package_uuid'))
self.assertEqual(exp_vnf_package_vnfd.get('vnfd_id'),
vnf_package_vnfd.get('vnfd_id'))
self.assertEqual(exp_vnf_package_vnfd.get('vnf_provider'),
vnf_package_vnfd.get('vnf_provider'))
self.assertEqual(exp_vnf_package_vnfd.get('vnf_product_name'),
vnf_package_vnfd.get('vnf_product_name'))
self.assertEqual(exp_vnf_package_vnfd.get('vnf_software_version'),
vnf_package_vnfd.get('vnf_software_version'))
self.assertEqual(exp_vnf_package_vnfd.get('vnfd_version'),
vnf_package_vnfd.get('vnfd_version'))
# Check if a mock is called even once
mock_upload_vnf_package_content.assert_called()
mock_nfvo_download_vnf_packages.assert_called()
mock_from_db_vnf_package.assert_called()
mock_save_vnf_package.assert_called()
mock_vnf_package.assert_called()
mock_get_by_id.assert_called()
mock_glance_store.assert_called()
@mock.patch.object(objects.vnf_package, '_vnf_package_create')
def test_package_and_package_vnfd_creation_package_create_err(self,
mock_vnf_package):
# vnf_package mock Settings
mock_vnf_package.side_effect = Exception
# SyncVnfPackage.create_package
vnf_package_info = vnfpkgm_fakes.index_response()[0]
self.assertRaises(
exc.HTTPInternalServerError,
sync.SyncVnfPackage.create_package,
self.context,
vnf_package_info)
# Check if a mock is called even once
mock_vnf_package.assert_called()
@mock.patch.object(objects.vnf_package, '_vnf_package_create')
@mock.patch.object(objects.vnf_package.VnfPackage, '_from_db_object')
@mock.patch.object(nfvo_client.VnfPackageRequest, 'download_vnf_packages')
def test_package_and_package_vnfd_creation_undefinedexcep(self,
mock_nfvo_download_vnf_packages,
mock_from_db_vnf_package,
mock_vnf_package):
# VnfPackageRequest.download_vnf_packages mock Settings
mock_nfvo_download_vnf_packages.side_effect = \
nfvo_client.UndefinedExternalSettingException(
"Vnf package the external setting to 'base_url' undefined.")
# SyncVnfPackage.create_package
vnf_package_info = vnfpkgm_fakes.index_response()[0]
self.assertRaises(
exc.HTTPNotFound,
sync.SyncVnfPackage.create_package,
self.context,
vnf_package_info)
# Check if a mock is called even once
mock_vnf_package.assert_called()
mock_from_db_vnf_package.assert_called()
mock_nfvo_download_vnf_packages.assert_called()
@mock.patch.object(objects.vnf_package, '_vnf_package_create')
@mock.patch.object(objects.vnf_package.VnfPackage, '_from_db_object')
@mock.patch.object(nfvo_client.VnfPackageRequest, 'download_vnf_packages')
def test_package_and_package_vnfd_creation_falieddownloadexcep(self,
mock_nfvo_download_vnf_packages,
mock_from_db_vnf_package,
mock_vnf_package):
# VnfPackageRequest.download_vnf_packages mock Settings
vnf_package_zip = ''
mock_nfvo_download_vnf_packages.side_effect = \
nfvo_client.FaliedDownloadContentException(
"Failed response content, vnf_package_zip={}".format(
vnf_package_zip))
# SyncVnfPackage.create_package
vnf_package_info = vnfpkgm_fakes.index_response()[0]
self.assertRaises(
exc.HTTPInternalServerError,
sync.SyncVnfPackage.create_package,
self.context,
vnf_package_info)
# Check if a mock is called even once
mock_vnf_package.assert_called()
mock_from_db_vnf_package.assert_called()
mock_nfvo_download_vnf_packages.assert_called()
@mock.patch.object(objects.vnf_package, '_vnf_package_create')
@mock.patch.object(objects.vnf_package.VnfPackage, '_from_db_object')
@mock.patch.object(nfvo_client.VnfPackageRequest, 'download_vnf_packages')
def test_package_and_package_vnfd_creation_exception(self,
mock_nfvo_download_vnf_packages,
mock_from_db_vnf_package,
mock_vnf_package):
# VnfPackageRequest.download_vnf_packages mock Settings
mock_nfvo_download_vnf_packages.side_effect = Exception
# SyncVnfPackage.create_package
vnf_package_info = vnfpkgm_fakes.index_response()[0]
self.assertRaises(
exc.HTTPInternalServerError,
sync.SyncVnfPackage.create_package,
self.context,
vnf_package_info)
# Check if a mock is called even once
mock_vnf_package.assert_called()
mock_from_db_vnf_package.assert_called()
mock_nfvo_download_vnf_packages.assert_called()
@mock.patch.object(glance_store, 'store_csar')
@mock.patch.object(objects.vnf_package, '_vnf_package_create')
@mock.patch.object(objects.vnf_package.VnfPackage, '_from_db_object')
@mock.patch.object(nfvo_client.VnfPackageRequest, 'download_vnf_packages')
def test_package_and_package_vnfd_creation_store_csar_err(self,
mock_nfvo_download_vnf_packages,
mock_from_db_vnf_package,
mock_vnf_package,
mock_glance_store):
# glance_store mock Settings
mock_glance_store.side_effect = Exception
# SyncVnfPackage.create_package
vnf_package_info = vnfpkgm_fakes.index_response()[0]
self.assertRaises(
exc.HTTPInternalServerError,
sync.SyncVnfPackage.create_package,
self.context,
vnf_package_info)
# Check if a mock is called even once
mock_vnf_package.assert_called()
mock_from_db_vnf_package.assert_called()
mock_nfvo_download_vnf_packages.assert_called()
mock_glance_store.assert_called()
@mock.patch.object(glance_store, 'store_csar')
@mock.patch.object(objects.vnf_package, '_vnf_package_create')
@mock.patch.object(objects.vnf_package.VnfPackage, 'save')
@mock.patch.object(objects.vnf_package.VnfPackage, '_from_db_object')
@mock.patch.object(nfvo_client.VnfPackageRequest, 'download_vnf_packages')
def test_package_and_package_vnfd_creation_package_upde_err(self,
mock_nfvo_download_vnf_packages,
mock_from_db_vnf_package,
mock_save_vnf_package,
mock_vnf_package,
mock_glance_store):
# glance_store mock Settings
mock_glance_store.return_value = 'location', 0, 'checksum',\
'multihash', 'loc_meta'
# vnf_package mock Settings
mock_save_vnf_package.side_effect = Exception
# SyncVnfPackage.create_package
vnf_package_info = vnfpkgm_fakes.index_response()[0]
self.assertRaises(
exc.HTTPInternalServerError,
sync.SyncVnfPackage.create_package,
self.context,
vnf_package_info)
# Check if a mock is called even once
mock_nfvo_download_vnf_packages.assert_called()
mock_from_db_vnf_package.assert_called()
mock_save_vnf_package.assert_called()
mock_vnf_package.assert_called()
mock_glance_store.assert_called()
@mock.patch.object(glance_store, 'store_csar')
@mock.patch.object(vnf_pkgm_rpc.VNFPackageRPCAPI,
'upload_vnf_package_content')
@mock.patch.object(objects.vnf_package, '_vnf_package_create')
@mock.patch.object(objects.vnf_package.VnfPackage, 'save')
@mock.patch.object(objects.vnf_package.VnfPackage, '_from_db_object')
@mock.patch.object(nfvo_client.VnfPackageRequest, 'download_vnf_packages')
def test_package_and_package_vnfd_creation_rpc_err(self,
mock_nfvo_download_vnf_packages,
mock_from_db_vnf_package,
mock_save_vnf_package,
mock_vnf_package,
mock_upload_vnf_package_content,
mock_glance_store):
# glance_store mock Settings
mock_glance_store.return_value = 'location', 0, 'checksum',\
'multihash', 'loc_meta'
mock_upload_vnf_package_content.side_effect = Exception
# SyncVnfPackage.create_package
vnf_package_info = vnfpkgm_fakes.index_response()[0]
self.assertRaises(
exc.HTTPInternalServerError,
sync.SyncVnfPackage.create_package,
self.context,
vnf_package_info)
# Check if a mock is called even once
mock_nfvo_download_vnf_packages.assert_called()
mock_from_db_vnf_package.assert_called()
mock_save_vnf_package.assert_called()
mock_vnf_package.assert_called()
mock_upload_vnf_package_content.assert_called()
mock_glance_store.assert_called()
@mock.patch.object(glance_store, 'store_csar')
@mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd,
'get_by_id')
@mock.patch.object(objects.vnf_package, '_vnf_package_create')
@mock.patch.object(objects.vnf_package.VnfPackage, 'save')
@mock.patch.object(objects.vnf_package.VnfPackage, '_from_db_object')
@mock.patch.object(nfvo_client.VnfPackageRequest, 'download_vnf_packages')
def test_package_and_get_package_vnfd_err(self,
mock_nfvo_download_vnf_packages,
mock_from_db_vnf_package,
mock_save_vnf_package,
mock_vnf_package,
mock_get_by_id,
mock_glance_store):
# glance_store mock Settings
mock_glance_store.return_value = 'location', 0, 'checksum',\
'multihash', 'loc_meta'
# vnf_package_vnfd mock Settings
mock_get_by_id.side_effect = Exception
# SyncVnfPackage.create_package
vnf_package_info = vnfpkgm_fakes.index_response()[0]
self.assertRaises(
exc.HTTPInternalServerError,
sync.SyncVnfPackage.create_package,
self.context,
vnf_package_info)
# Check if a mock is called even once
mock_nfvo_download_vnf_packages.assert_called()
mock_from_db_vnf_package.assert_called()
mock_save_vnf_package.assert_called()
mock_vnf_package.assert_called()
mock_get_by_id.assert_called()
mock_glance_store.assert_called()

View File

@ -19,6 +19,7 @@ import shutil
from unittest import mock
from oslo_config import cfg
from oslo_utils import uuidutils
from tacker.common import exceptions
from tacker.common import utils
from tacker import context
@ -32,6 +33,26 @@ from tacker.vnflcm import vnflcm_driver
from tacker.vnfm import vim_client
vnf_dict = {
'id': uuidutils.generate_uuid(),
'mgmt_ip_address': '{"VDU1": "a.b.c.d"}',
'vim_id': '6261579e-d6f3-49ad-8bc3-a9cb974778ff',
'instance_id': 'a737497c-761c-11e5-89c3-9cb6541d805d',
'vnfd': {
'attributes': {
'heat_template': {
'resources': {
'VDU1': {
'properties': {
'networks': [{'port': {'get_resource': 'CP1'}}]}
}
}
}
}
}
}
OPTS_INFRA_DRIVER = [
cfg.ListOpt(
'infra_driver', default=['noop', 'openstack', 'kubernetes'],
@ -100,6 +121,10 @@ class FakeVimClient(mock.Mock):
pass
class FakeTackerManager(mock.MagicMock):
pass
class TestVnflcmDriver(db_base.SqlTestCase):
def setUp(self):
@ -136,11 +161,13 @@ class TestVnflcmDriver(db_base.SqlTestCase):
'test_project'}, 'vim_type': 'openstack'}
self.vim_client.get_vim.return_value = vim_obj
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(objects.VnfResource, 'create')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(objects.VnfInstance, "save")
def test_instantiate_vnf(self, mock_vnf_instance_save,
mock_vnf_package_vnfd, mock_create):
mock_vnf_package_vnfd, mock_create,
mock_final_vnf_dict):
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
@ -156,19 +183,22 @@ class TestVnflcmDriver(db_base.SqlTestCase):
test_utils.copy_csar_files(fake_csar, "vnflcm4")
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.instantiate_vnf(self.context, vnf_instance_obj,
driver.instantiate_vnf(self.context, vnf_instance_obj, vnf_dict,
instantiate_vnf_req_obj)
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
self.assertEqual(2, mock_vnf_instance_save.call_count)
self.assertEqual(4, self._vnf_manager.invoke.call_count)
mock_final_vnf_dict.assert_called_once()
shutil.rmtree(fake_csar)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(objects.VnfResource, 'create')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(objects.VnfInstance, "save")
def test_instantiate_vnf_with_ext_virtual_links(
self, mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create):
self, mock_vnf_instance_save, mock_vnf_package_vnfd,
mock_create, mock_final_vnf_dict):
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
@ -186,19 +216,22 @@ class TestVnflcmDriver(db_base.SqlTestCase):
test_utils.copy_csar_files(fake_csar, "vnflcm4")
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.instantiate_vnf(self.context, vnf_instance_obj,
driver.instantiate_vnf(self.context, vnf_instance_obj, vnf_dict,
instantiate_vnf_req_obj)
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
self.assertEqual(2, mock_vnf_instance_save.call_count)
self.assertEqual(4, self._vnf_manager.invoke.call_count)
mock_final_vnf_dict.assert_called_once()
shutil.rmtree(fake_csar)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(objects.VnfResource, 'create')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(objects.VnfInstance, "save")
def test_instantiate_vnf_vim_connection_info(
self, mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create):
self, mock_vnf_instance_save, mock_vnf_package_vnfd,
mock_create, mock_final_vnf_dict):
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
@ -216,19 +249,22 @@ class TestVnflcmDriver(db_base.SqlTestCase):
test_utils.copy_csar_files(fake_csar, "vnflcm4")
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.instantiate_vnf(self.context, vnf_instance_obj,
driver.instantiate_vnf(self.context, vnf_instance_obj, vnf_dict,
instantiate_vnf_req_obj)
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
self.assertEqual(2, mock_vnf_instance_save.call_count)
self.assertEqual(4, self._vnf_manager.invoke.call_count)
mock_final_vnf_dict.assert_called_once()
shutil.rmtree(fake_csar)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(objects.VnfResource, 'create')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(objects.VnfInstance, "save")
def test_instantiate_vnf_infra_fails_to_instantiate(
self, mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create):
self, mock_vnf_instance_save, mock_vnf_package_vnfd,
mock_create, mock_final_vnf_dict):
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
@ -247,7 +283,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
self._mock_vnf_manager(fail_method_name="instantiate_vnf")
driver = vnflcm_driver.VnfLcmDriver()
error = self.assertRaises(exceptions.VnfInstantiationFailed,
driver.instantiate_vnf, self.context, vnf_instance_obj,
driver.instantiate_vnf, self.context, vnf_instance_obj, vnf_dict,
instantiate_vnf_req_obj)
expected_error = ("Vnf instantiation failed for vnf %s, error: "
"instantiate_vnf failed")
@ -257,15 +293,17 @@ class TestVnflcmDriver(db_base.SqlTestCase):
vnf_instance_obj.instantiation_state)
self.assertEqual(2, mock_vnf_instance_save.call_count)
self.assertEqual(2, self._vnf_manager.invoke.call_count)
mock_final_vnf_dict.assert_called_once()
shutil.rmtree(fake_csar)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(objects.VnfResource, 'create')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(objects.VnfInstance, "save")
def test_instantiate_vnf_infra_fails_to_wait_after_instantiate(
self, mock_vnf_instance_save, mock_vnf_package_vnfd,
mock_create):
mock_create, mock_final_vnf_dict):
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
@ -284,7 +322,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
self._mock_vnf_manager(fail_method_name='create_wait')
driver = vnflcm_driver.VnfLcmDriver()
error = self.assertRaises(exceptions.VnfInstantiationWaitFailed,
driver.instantiate_vnf, self.context, vnf_instance_obj,
driver.instantiate_vnf, self.context, vnf_instance_obj, vnf_dict,
instantiate_vnf_req_obj)
expected_error = ("Vnf instantiation wait failed for vnf %s, error: "
"create_wait failed")
@ -294,14 +332,16 @@ class TestVnflcmDriver(db_base.SqlTestCase):
vnf_instance_obj.instantiation_state)
self.assertEqual(3, mock_vnf_instance_save.call_count)
self.assertEqual(5, self._vnf_manager.invoke.call_count)
mock_final_vnf_dict.assert_called_once()
shutil.rmtree(fake_csar)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(objects.VnfResource, 'create')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(objects.VnfInstance, "save")
def test_instantiate_vnf_with_short_notation(self, mock_vnf_instance_save,
mock_vnf_package_vnfd, mock_create):
mock_vnf_package_vnfd, mock_create,
mock_final_vnf_dict):
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
@ -318,17 +358,20 @@ class TestVnflcmDriver(db_base.SqlTestCase):
fake_csar, "sample_vnf_package_csar_with_short_notation")
self._mock_vnf_manager(vnf_resource_count=2)
driver = vnflcm_driver.VnfLcmDriver()
driver.instantiate_vnf(self.context, vnf_instance_obj,
driver.instantiate_vnf(self.context, vnf_instance_obj, vnf_dict,
instantiate_vnf_req_obj)
self.assertEqual(2, mock_create.call_count)
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
mock_final_vnf_dict.assert_called_once()
shutil.rmtree(fake_csar)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(objects.VnfResource, 'create')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(objects.VnfInstance, "save")
def test_instantiate_vnf_with_single_vnfd(self, mock_vnf_instance_save,
mock_vnf_package_vnfd, mock_create):
mock_vnf_package_vnfd, mock_create,
mock_final_vnf_dict):
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
@ -345,10 +388,11 @@ class TestVnflcmDriver(db_base.SqlTestCase):
fake_csar, "sample_vnfpkg_no_meta_single_vnfd")
self._mock_vnf_manager(vnf_resource_count=2)
driver = vnflcm_driver.VnfLcmDriver()
driver.instantiate_vnf(self.context, vnf_instance_obj,
driver.instantiate_vnf(self.context, vnf_instance_obj, vnf_dict,
instantiate_vnf_req_obj)
self.assertEqual(2, mock_create.call_count)
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
mock_final_vnf_dict.assert_called_once()
shutil.rmtree(fake_csar)
@mock.patch.object(objects.VnfInstance, "save")
@ -454,6 +498,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
self.assertEqual(2, mock_vnf_instance_save.call_count)
self.assertEqual(3, self._vnf_manager.invoke.call_count)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(vim_client.VimClient, "get_vim")
@mock.patch.object(objects.VnfResource, "create")
@ -463,7 +508,8 @@ class TestVnflcmDriver(db_base.SqlTestCase):
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
def test_heal_vnf_without_vnfc_instance(self, mock_log, mock_save,
mock_vnf_resource_list, mock_resource_destroy,
mock_resource_create, mock_vim, mock_vnf_package_vnfd):
mock_resource_create, mock_vim, mock_vnf_package_vnfd,
mock_final_vnf_dict):
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
@ -494,7 +540,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
uuidsentinel.instance_id
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.heal_vnf(self.context, vnf_instance, heal_vnf_req)
driver.heal_vnf(self.context, vnf_instance, vnf_dict, heal_vnf_req)
self.assertEqual(1, mock_save.call_count)
# vnf resource software images will be deleted during
# deleting vnf instance.
@ -509,7 +555,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
"is completed successfully")
mock_log.info.assert_called_with(expected_msg,
vnf_instance.id)
mock_final_vnf_dict.assert_called_once()
shutil.rmtree(fake_csar)
@mock.patch.object(objects.VnfInstance, "save")
@ -527,7 +573,8 @@ class TestVnflcmDriver(db_base.SqlTestCase):
self._mock_vnf_manager(fail_method_name='delete')
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(exceptions.VnfHealFailed,
driver.heal_vnf, self.context, vnf_instance, heal_vnf_req)
driver.heal_vnf, self.context, vnf_instance,
vnf_dict, heal_vnf_req)
self.assertEqual(1, mock_save.call_count)
self.assertEqual(1, self._vnf_manager.invoke.call_count)
self.assertEqual(fields.VnfInstanceTaskState.ERROR,
@ -537,6 +584,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
'state. Error: delete failed')
mock_log.error.assert_called_with(expected_msg % vnf_instance.id)
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
@mock.patch.object(vim_client.VimClient, "get_vim")
@mock.patch.object(objects.VnfResource, "create")
@ -547,7 +595,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
def test_heal_vnf_without_vnfc_instance_infra_instantiate_vnf_fail(self,
mock_log, mock_save, mock_vnf_resource_list,
mock_resource_destroy, mock_resource_create, mock_vim,
mock_vnf_package_vnfd):
mock_vnf_package_vnfd, mock_final_vnf_dict):
vnf_package_vnfd = fakes.return_vnf_package_vnfd()
vnf_package_id = vnf_package_vnfd.package_uuid
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
@ -568,7 +616,8 @@ class TestVnflcmDriver(db_base.SqlTestCase):
self._mock_vnf_manager(fail_method_name='instantiate_vnf')
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(exceptions.VnfHealFailed,
driver.heal_vnf, self.context, vnf_instance, heal_vnf_req)
driver.heal_vnf, self.context,
vnf_instance, vnf_dict, heal_vnf_req)
self.assertEqual(1, mock_save.call_count)
# vnf resource software images will be deleted during
# deleting vnf instance.
@ -586,6 +635,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
'error: instantiate_vnf failed')
mock_log.error.assert_called_with(expected_msg % (vnf_instance.id,
vnf_instance.id))
mock_final_vnf_dict.assert_called_once()
@mock.patch.object(objects.VnfInstance, "save")
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
@ -599,7 +649,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
self._mock_vnf_manager()
driver = vnflcm_driver.VnfLcmDriver()
driver.heal_vnf(self.context, vnf_instance, heal_vnf_req)
driver.heal_vnf(self.context, vnf_instance, mock.ANY, heal_vnf_req)
self.assertEqual(1, mock_save.call_count)
self.assertEqual(3, self._vnf_manager.invoke.call_count)
@ -623,7 +673,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(exceptions.VnfHealFailed,
driver.heal_vnf, self.context, vnf_instance,
heal_vnf_req)
mock.ANY, heal_vnf_req)
self.assertEqual(1, mock_save.call_count)
self.assertEqual(1, self._vnf_manager.invoke.call_count)
@ -656,7 +706,8 @@ class TestVnflcmDriver(db_base.SqlTestCase):
# it will work and vnflcm can update the vnfc resources
# properly and hence the _vnf_manager.invoke.call_count
# should be 3 instead of 2.
driver.heal_vnf(self.context, vnf_instance, heal_vnf_req)
driver.heal_vnf(self.context, vnf_instance, mock.ANY,
heal_vnf_req)
self.assertEqual(1, mock_save.call_count)
self.assertEqual(3, self._vnf_manager.invoke.call_count)
@ -684,7 +735,8 @@ class TestVnflcmDriver(db_base.SqlTestCase):
self._mock_vnf_manager(fail_method_name='post_heal_vnf')
driver = vnflcm_driver.VnfLcmDriver()
self.assertRaises(exceptions.VnfHealFailed,
driver.heal_vnf, self.context, vnf_instance, heal_vnf_req)
driver.heal_vnf, self.context, vnf_instance,
mock.ANY, heal_vnf_req)
self.assertEqual(1, mock_save.call_count)
self.assertEqual(3, self._vnf_manager.invoke.call_count)

View File

@ -73,6 +73,7 @@ class TestVIMClient(base.TestCase):
region_name='TestRegionOne')
vim_expect = {'vim_auth': {'password': '****'}, 'vim_id': 'aaaa',
'vim_name': 'VIM0', 'vim_type': 'test_vim',
'placement_attr': {'regions': ['TestRegionOne']},
'tenant': 'test'}
self.assertEqual(vim_expect, vim_result)
@ -89,6 +90,7 @@ class TestVIMClient(base.TestCase):
region_name='TestRegionOne')
vim_expect = {'vim_auth': {'password': '****'}, 'vim_id': 'aaaa',
'vim_name': 'aaaa', 'vim_type': 'test_vim',
'placement_attr': {'regions': ['TestRegionOne']},
'tenant': 'test'}
self.assertEqual(vim_expect, vim_result)

View File

@ -15,6 +15,7 @@
from unittest import mock
import ddt
import json
import os
from oslo_serialization import jsonutils
from six.moves import http_client
@ -47,6 +48,16 @@ class TestController(base.TestCase):
def app(self):
return fakes.wsgi_app_v1()
def _make_problem_detail(self, title, detail, status):
res = exc.Response(content_type='application/problem+json')
problemDetails = {}
problemDetails['title'] = title
problemDetails['detail'] = detail
problemDetails['status'] = status
res.text = json.dumps(problemDetails)
res.status_int = status
return res
@mock.patch.object(vnf_package, '_vnf_package_create')
@mock.patch.object(vnf_package.VnfPackage, '_from_db_object')
def test_create_with_status_202(self, mock_from_db, mock_vnf_pack):
@ -594,27 +605,32 @@ class TestController(base.TestCase):
req = fake_request.HTTPRequest.blank(
'/vnf_packages/%s/package_content'
% constants.INVALID_UUID)
exception = self.assertRaises(exc.HTTPNotFound,
self.controller.upload_vnf_package_content,
req, constants.INVALID_UUID,
body=mock.mock_open())
self.assertEqual(
"Can not find requested vnf package: %s" % constants.INVALID_UUID,
exception.explanation)
req.headers['Content-Type'] = 'application/zip'
req.method = 'PUT'
req.body = jsonutils.dump_as_bytes(mock.mock_open())
msg = _("Can not find requested vnf package: %s") \
% constants.INVALID_UUID
res = self._make_problem_detail('Not Found', msg, 404)
resp = req.get_response(self.app)
self.assertEqual(res.text, resp.text)
@mock.patch.object(vnf_package.VnfPackage, "get_by_id")
def test_upload_vnf_package_content_without_vnf_pack(self,
mock_vnf_by_id):
msg = _("Can not find requested vnf package: %s") % constants.UUID
mock_vnf_by_id.side_effect = exc.HTTPNotFound(explanation=msg)
mock_vnf_by_id.side_effect = \
tacker_exc.VnfPackageNotFound(explanation=msg)
req = fake_request.HTTPRequest.blank(
'/vnf_packages/%s/package_content' % constants.UUID)
exception = self.assertRaises(
exc.HTTPNotFound, self.controller.upload_vnf_package_content,
req, constants.UUID, body=mock.mock_open())
self.assertEqual(
"Can not find requested vnf package: %s" % constants.UUID,
exception.explanation)
req.headers['Content-Type'] = 'application/zip'
req.method = 'PUT'
req.body = jsonutils.dump_as_bytes(mock.mock_open())
msg = _("Can not find requested vnf package: %s") % constants.UUID
res = self._make_problem_detail('Not Found', msg, 404)
resp = req.get_response(self.app)
self.assertEqual(res.text, resp.text)
@mock.patch.object(vnf_package.VnfPackage, "get_by_id")
def test_upload_vnf_package_content_with_invalid_status(self,
@ -624,9 +640,15 @@ class TestController(base.TestCase):
mock_vnf_by_id.return_value = vnf_obj
req = fake_request.HTTPRequest.blank(
'/vnf_packages/%s/package_content' % constants.UUID)
self.assertRaises(exc.HTTPConflict,
self.controller.upload_vnf_package_content,
req, constants.UUID, body=mock.mock_open())
req.headers['Content-Type'] = 'application/zip'
req.method = 'PUT'
req.body = jsonutils.dump_as_bytes(mock.mock_open())
msg = _("VNF Package %s onboarding state is not CREATED") \
% constants.UUID
res = self._make_problem_detail('Conflict', msg, 409)
resp = req.get_response(self.app)
self.assertEqual(res.text, resp.text)
@mock.patch.object(urllib.request, 'urlopen')
@mock.patch.object(VNFPackageRPCAPI, "upload_vnf_package_from_uri")

View File

@ -359,7 +359,17 @@ def _create_grant_request(vnfd_dict, package_uuid):
return vnf_software_images
def _make_final_vnf_dict(vnfd_dict, id, name, param_values):
def _make_final_vnf_dict(vnfd_dict, id, name, param_values, vnf_dict=None):
if vnf_dict:
final_vnf_dict = vnf_dict
final_vnf_dict['vnfd']['attributes'].\
update({'vnfd': str(vnfd_dict)})
final_vnf_dict['attributes'].\
update({'param_values': str(param_values)})
final_vnf_dict['attributes'].\
update({'stack_name': name or ("vnflcm_" + id)})
return final_vnf_dict
else:
return {'vnfd': {
'attributes': {
'vnfd': str(vnfd_dict)}},
@ -517,6 +527,9 @@ def _build_instantiated_vnf_info(vnfd_dict, instantiate_vnf_req,
inst_vnf_info.ext_managed_virtual_link_info = \
_build_ext_managed_virtual_link_info(instantiate_vnf_req,
inst_vnf_info)
inst_vnf_info.additional_params = instantiate_vnf_req.additional_params
vnf_instance.instantiated_vnf_info = inst_vnf_info

View File

@ -132,8 +132,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
setattr(vnf_instance, k, v)
vnf_instance.save()
def _instantiate_vnf(self, context, vnf_instance, vim_connection_info,
instantiate_vnf_req):
def _instantiate_vnf(self, context, vnf_instance, vnf_dict,
vim_connection_info, instantiate_vnf_req):
vnfd_dict = vnflcm_utils._get_vnfd_dict(context, vnf_instance.vnfd_id,
instantiate_vnf_req.flavour_id)
base_hot_dict = vnflcm_utils._get_base_hot_dict(
@ -166,7 +166,7 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
vnfd_dict_to_create_final_dict = copy.deepcopy(vnfd_dict)
final_vnf_dict = vnflcm_utils._make_final_vnf_dict(
vnfd_dict_to_create_final_dict, vnf_instance.id,
vnf_instance.vnf_instance_name, param_for_subs_map)
vnf_instance.vnf_instance_name, param_for_subs_map, vnf_dict)
try:
instance_id = self._vnf_manager.invoke(
@ -224,7 +224,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
@log.log
@rollback_vnf_instantiated_resources
def instantiate_vnf(self, context, vnf_instance, instantiate_vnf_req):
def instantiate_vnf(self, context, vnf_instance, vnf_dict,
instantiate_vnf_req):
vim_connection_info_list = vnflcm_utils.\
_get_vim_connection_info_from_vnf_req(vnf_instance,
@ -239,8 +240,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
vim_connection_info = objects.VimConnectionInfo.obj_from_primitive(
vim_info, context)
self._instantiate_vnf(context, vnf_instance, vim_connection_info,
instantiate_vnf_req)
self._instantiate_vnf(context, vnf_instance, vnf_dict,
vim_connection_info, instantiate_vnf_req)
self._vnf_instance_update(context, vnf_instance,
instantiation_state=fields.VnfInstanceState.INSTANTIATED,
@ -363,8 +364,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
raise exceptions.VnfHealFailed(id=vnf_instance.id,
error=encodeutils.exception_to_unicode(exp))
def _respawn_vnf(self, context, vnf_instance, vim_connection_info,
heal_vnf_request):
def _respawn_vnf(self, context, vnf_instance, vnf_dict,
vim_connection_info, heal_vnf_request):
try:
self._delete_vnf_instance_resources(context, vnf_instance,
vim_connection_info, update_instantiated_state=False)
@ -388,8 +389,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
from_vnf_instance(vnf_instance)
try:
self._instantiate_vnf(context, vnf_instance, vim_connection_info,
instantiate_vnf_request)
self._instantiate_vnf(context, vnf_instance, vnf_dict,
vim_connection_info, instantiate_vnf_request)
except Exception as exc:
with excutils.save_and_reraise_exception() as exc_ctxt:
exc_ctxt.reraise = False
@ -407,7 +408,7 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
@log.log
@revert_to_error_task_state
def heal_vnf(self, context, vnf_instance, heal_vnf_request):
def heal_vnf(self, context, vnf_instance, vnf_dict, heal_vnf_request):
LOG.info("Request received for healing vnf '%s'", vnf_instance.id)
vim_info = vnflcm_utils._get_vim(context,
vnf_instance.vim_connection_info)
@ -416,8 +417,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
vim_info, context)
if not heal_vnf_request.vnfc_instance_id:
self._respawn_vnf(context, vnf_instance, vim_connection_info,
heal_vnf_request)
self._respawn_vnf(context, vnf_instance, vnf_dict,
vim_connection_info, heal_vnf_request)
else:
self._heal_vnf(context, vnf_instance, vim_connection_info,
heal_vnf_request)

View File

@ -64,7 +64,8 @@ class VimClient(object):
vim_res = {'vim_auth': vim_auth, 'vim_id': vim_info['id'],
'vim_name': vim_info.get('name', vim_info['id']),
'vim_type': vim_info['type'],
'tenant': vim_info['tenant_id']}
'tenant': vim_info['tenant_id'],
'placement_attr': vim_info.get('placement_attr', {})}
return vim_res
@staticmethod