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
This commit is contained in:
parent
a7dc3ab6b5
commit
9d95f91504
@ -206,7 +206,8 @@ terminate = {
|
|||||||
'properties': {
|
'properties': {
|
||||||
'terminationType': {'type': 'string',
|
'terminationType': {'type': 'string',
|
||||||
'enum': ['FORCEFUL', 'GRACEFUL']},
|
'enum': ['FORCEFUL', 'GRACEFUL']},
|
||||||
'gracefulTerminationTimeout': {'type': 'integer', 'minimum': 0}
|
'gracefulTerminationTimeout': {'type': 'integer', 'minimum': 0},
|
||||||
|
'additionalParams': parameter_types.keyvalue_pairs,
|
||||||
},
|
},
|
||||||
'required': ['terminationType'],
|
'required': ['terminationType'],
|
||||||
'additionalProperties': False,
|
'additionalProperties': False,
|
||||||
|
@ -116,18 +116,11 @@ class ViewBuilder(base.BaseViewBuilder):
|
|||||||
|
|
||||||
return {"_links": _links}
|
return {"_links": _links}
|
||||||
|
|
||||||
def _get_vnf_instance_info(self,
|
def _get_vnf_instance_info(self, vnf_instance):
|
||||||
vnf_instance, api_version=None):
|
|
||||||
vnf_instance_dict = vnf_instance.to_dict()
|
vnf_instance_dict = vnf_instance.to_dict()
|
||||||
if vnf_instance_dict.get('vim_connection_info'):
|
vnf_metadata = vnf_instance_dict.pop("vnf_metadata")
|
||||||
vnf_instance_dict['vim_connection_info'] = \
|
if vnf_metadata:
|
||||||
self._get_vim_conn_info(vnf_instance_dict.get(
|
vnf_instance_dict.update({"metadata": vnf_metadata})
|
||||||
'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_instance_dict = utils.convert_snakecase_to_camelcase(
|
vnf_instance_dict = utils.convert_snakecase_to_camelcase(
|
||||||
vnf_instance_dict)
|
vnf_instance_dict)
|
||||||
|
|
||||||
|
@ -13,11 +13,20 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# 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_log import log as logging
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
from oslo_utils import encodeutils
|
from oslo_utils import encodeutils
|
||||||
|
from oslo_utils import excutils
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
from sqlalchemy import exc as sqlexc
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
import functools
|
import functools
|
||||||
@ -25,20 +34,18 @@ import json
|
|||||||
import re
|
import re
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import six
|
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
from six.moves.urllib import parse
|
from six.moves.urllib import parse
|
||||||
import webob
|
|
||||||
|
|
||||||
|
|
||||||
from tacker._i18n import _
|
from tacker._i18n import _
|
||||||
from tacker.api.schemas import vnf_lcm
|
from tacker.api.schemas import vnf_lcm
|
||||||
from tacker.api import validation
|
from tacker.api import validation
|
||||||
from tacker.api.views import vnf_lcm as vnf_lcm_view
|
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 exceptions
|
||||||
from tacker.common import utils
|
from tacker.common import utils
|
||||||
from tacker.conductor.conductorrpc import vnf_lcm_rpc
|
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 nfvo
|
||||||
from tacker.extensions import vnfm
|
from tacker.extensions import vnfm
|
||||||
from tacker import manager
|
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.objects import vnf_lcm_subscriptions as subscription_obj
|
||||||
from tacker.plugins.common import constants
|
from tacker.plugins.common import constants
|
||||||
from tacker.policies import vnf_lcm as vnf_lcm_policies
|
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.vnfm import vim_client
|
||||||
from tacker import wsgi
|
from tacker import wsgi
|
||||||
|
|
||||||
|
|
||||||
CONF = tacker.conf.CONF
|
CONF = tacker.conf.CONF
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -307,73 +316,187 @@ class VnfLcmController(wsgi.Controller):
|
|||||||
|
|
||||||
return vnf_lcm_op_occs_id
|
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.response(http_client.CREATED)
|
||||||
@wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN))
|
@wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN))
|
||||||
@validation.schema(vnf_lcm.create)
|
@validation.schema(vnf_lcm.create)
|
||||||
def create(self, request, body):
|
def create(self, request, body):
|
||||||
context = request.environ['tacker.context']
|
context = request.environ['tacker.context']
|
||||||
context.can(vnf_lcm_policies.VNFLCM % 'create')
|
context.can(vnf_lcm_policies.VNFLCM % 'create')
|
||||||
|
|
||||||
req_body = utils.convert_camelcase_to_snakecase(body)
|
|
||||||
vnfd_id = req_body.get('vnfd_id')
|
|
||||||
try:
|
try:
|
||||||
|
req_body = utils.convert_camelcase_to_snakecase(body)
|
||||||
|
vnfd_id = req_body.get('vnfd_id')
|
||||||
vnfd = objects.VnfPackageVnfd.get_by_id(request.context,
|
vnfd = objects.VnfPackageVnfd.get_by_id(request.context,
|
||||||
vnfd_id)
|
vnfd_id)
|
||||||
except exceptions.VnfPackageVnfdNotFound as exc:
|
except exceptions.VnfPackageVnfdNotFound:
|
||||||
raise webob.exc.HTTPBadRequest(explanation=six.text_type(exc))
|
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')
|
||||||
|
|
||||||
# get default vim information
|
vnfd = sync_resource.SyncVnfPackage.create_package(
|
||||||
vim_client_obj = vim_client.VimClient()
|
context,
|
||||||
default_vim = vim_client_obj.get_vim(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
|
vnf_instance = objects.VnfInstance(
|
||||||
access_info = {
|
context=request.context,
|
||||||
'username': default_vim.get('vim_auth', {}).get('username'),
|
vnf_instance_name=req_body.get('vnf_instance_name'),
|
||||||
'password': default_vim.get('vim_auth', {}).get('password'),
|
vnf_instance_description=req_body.get(
|
||||||
'region': default_vim.get('placement_attr', {}).get('region'),
|
'vnf_instance_description'),
|
||||||
'tenant': default_vim.get('tenant')
|
vnfd_id=vnfd_id,
|
||||||
}
|
instantiation_state=fields.VnfInstanceState.NOT_INSTANTIATED,
|
||||||
vim_con_info = objects.VimConnectionInfo(id=default_vim.get('vim_id'),
|
vnf_provider=vnfd.vnf_provider,
|
||||||
vim_id=default_vim.get('vim_id'),
|
vnf_product_name=vnfd.vnf_product_name,
|
||||||
vim_type=default_vim.get('vim_type'),
|
vnf_software_version=vnfd.vnf_software_version,
|
||||||
access_info=access_info)
|
vnfd_version=vnfd.vnfd_version,
|
||||||
|
tenant_id=request.context.project_id,
|
||||||
|
vnf_metadata=req_body.get('metadata'))
|
||||||
|
|
||||||
vnf_instance = objects.VnfInstance(
|
try:
|
||||||
context=request.context,
|
vnf_instance.create()
|
||||||
vnf_instance_name=req_body.get('vnf_instance_name'),
|
|
||||||
vnf_instance_description=req_body.get(
|
|
||||||
'vnf_instance_description'),
|
|
||||||
vnfd_id=vnfd_id,
|
|
||||||
instantiation_state=fields.VnfInstanceState.NOT_INSTANTIATED,
|
|
||||||
vnf_provider=vnfd.vnf_provider,
|
|
||||||
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'))
|
|
||||||
|
|
||||||
vnf_instance.create()
|
# 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)
|
||||||
|
|
||||||
# add default vim to vim_connection_info
|
# create notification data
|
||||||
setattr(vnf_instance, 'vim_connection_info', [vim_con_info])
|
notification = {
|
||||||
|
'notificationType':
|
||||||
# create notification data
|
|
||||||
notification = {
|
|
||||||
'notificationType':
|
|
||||||
fields.LcmOccsNotificationType.VNF_ID_CREATION_NOTIFICATION,
|
fields.LcmOccsNotificationType.VNF_ID_CREATION_NOTIFICATION,
|
||||||
'vnfInstanceId': vnf_instance.id,
|
'vnfInstanceId': vnf_instance.id,
|
||||||
'links': {
|
'links': {
|
||||||
'vnfInstance': {
|
'vnfInstance': {
|
||||||
'href': self._get_vnf_instance_href(vnf_instance)}}}
|
'href': self._get_vnf_instance_href(vnf_instance)}}}
|
||||||
|
|
||||||
# call send nootification
|
# call sendNotification
|
||||||
self.rpc_api.send_notification(context, notification)
|
self.rpc_api.send_notification(context, notification)
|
||||||
vnf_instance.save()
|
|
||||||
|
|
||||||
result = self._view_builder.create(vnf_instance)
|
result = self._view_builder.create(vnf_instance)
|
||||||
headers = {"location": self._get_vnf_instance_href(vnf_instance)}
|
headers = {"location": self._get_vnf_instance_href(vnf_instance)}
|
||||||
return wsgi.ResponseObject(result, headers=headers)
|
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.response(http_client.OK)
|
||||||
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND))
|
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND))
|
||||||
@ -401,8 +524,16 @@ class VnfLcmController(wsgi.Controller):
|
|||||||
@check_vnf_state(action="delete",
|
@check_vnf_state(action="delete",
|
||||||
instantiation_state=[fields.VnfInstanceState.NOT_INSTANTIATED],
|
instantiation_state=[fields.VnfInstanceState.NOT_INSTANTIATED],
|
||||||
task_state=[None])
|
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)
|
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.response(http_client.NO_CONTENT)
|
||||||
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND,
|
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND,
|
||||||
@ -411,7 +542,8 @@ class VnfLcmController(wsgi.Controller):
|
|||||||
context = request.environ['tacker.context']
|
context = request.environ['tacker.context']
|
||||||
|
|
||||||
vnf_instance = self._get_vnf_instance(context, id)
|
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 = {
|
notification = {
|
||||||
"notificationType": "VnfIdentifierDeletionNotification",
|
"notificationType": "VnfIdentifierDeletionNotification",
|
||||||
|
138
tacker/api/vnflcm/v1/sync_resource.py
Normal file
138
tacker/api/vnflcm/v1/sync_resource.py
Normal 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
|
@ -13,8 +13,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
import json
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@ -302,19 +302,37 @@ class VnfPkgmController(wsgi.Controller):
|
|||||||
context = request.environ['tacker.context']
|
context = request.environ['tacker.context']
|
||||||
context.can(vnf_package_policies.VNFPKGM % 'upload_package_content')
|
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 != \
|
if vnf_package.onboarding_state != \
|
||||||
fields.PackageOnboardingStateType.CREATED:
|
fields.PackageOnboardingStateType.CREATED:
|
||||||
msg = _("VNF Package %(id)s onboarding state "
|
msg = _("VNF Package %(id)s onboarding state "
|
||||||
"is not %(onboarding)s")
|
"is not %(onboarding)s")
|
||||||
raise webob.exc.HTTPConflict(explanation=msg % {"id": id,
|
return self._make_problem_detail('Conflict', msg % {"id": id,
|
||||||
"onboarding": fields.PackageOnboardingStateType.CREATED})
|
"onboarding": fields.PackageOnboardingStateType.CREATED},
|
||||||
|
409)
|
||||||
|
|
||||||
vnf_package.onboarding_state = (
|
vnf_package.onboarding_state = (
|
||||||
fields.PackageOnboardingStateType.UPLOADING)
|
fields.PackageOnboardingStateType.UPLOADING)
|
||||||
|
|
||||||
vnf_package.save()
|
try:
|
||||||
|
vnf_package.save()
|
||||||
|
except Exception as e:
|
||||||
|
return self._make_problem_detail(
|
||||||
|
'Internal Server Error', str(e), 500)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
(location, size, checksum, multihash,
|
(location, size, checksum, multihash,
|
||||||
@ -323,16 +341,29 @@ class VnfPkgmController(wsgi.Controller):
|
|||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
vnf_package.onboarding_state = (
|
vnf_package.onboarding_state = (
|
||||||
fields.PackageOnboardingStateType.CREATED)
|
fields.PackageOnboardingStateType.CREATED)
|
||||||
vnf_package.save()
|
try:
|
||||||
|
vnf_package.save()
|
||||||
vnf_package.onboarding_state = (
|
except Exception as e:
|
||||||
fields.PackageOnboardingStateType.PROCESSING)
|
return self._make_problem_detail(
|
||||||
|
'Internal Server Error', str(e), 500)
|
||||||
|
|
||||||
vnf_package.algorithm = CONF.vnf_package.hashing_algorithm
|
vnf_package.algorithm = CONF.vnf_package.hashing_algorithm
|
||||||
vnf_package.hash = multihash
|
vnf_package.hash = multihash
|
||||||
vnf_package.location_glance_store = location
|
vnf_package.location_glance_store = location
|
||||||
vnf_package.size = size
|
vnf_package.size = size
|
||||||
vnf_package.save()
|
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
|
# process vnf_package
|
||||||
self.rpc_api.upload_vnf_package_content(context, vnf_package)
|
self.rpc_api.upload_vnf_package_content(context, vnf_package)
|
||||||
@ -618,6 +649,16 @@ class VnfPkgmController(wsgi.Controller):
|
|||||||
|
|
||||||
return buff.getvalue()
|
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():
|
def create_resource():
|
||||||
body_deserializers = {
|
body_deserializers = {
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
from copy import deepcopy
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@ -29,6 +30,7 @@ import zipfile
|
|||||||
|
|
||||||
from tacker.common import exceptions
|
from tacker.common import exceptions
|
||||||
import tacker.conf
|
import tacker.conf
|
||||||
|
from tacker.extensions import vnfm
|
||||||
import urllib.request as urllib2
|
import urllib.request as urllib2
|
||||||
|
|
||||||
|
|
||||||
@ -124,8 +126,10 @@ def _get_software_image(custom_defs, nodetemplate_name, node_tpl):
|
|||||||
properties = node_tpl['properties']
|
properties = node_tpl['properties']
|
||||||
sw_image_artifact = _get_sw_image_artifact(node_tpl.get('artifacts'))
|
sw_image_artifact = _get_sw_image_artifact(node_tpl.get('artifacts'))
|
||||||
if sw_image_artifact:
|
if sw_image_artifact:
|
||||||
|
image_path = sw_image_artifact['file'].lstrip("./")
|
||||||
properties['sw_image_data'].update(
|
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']
|
sw_image_data = properties['sw_image_data']
|
||||||
if 'metadata' in sw_image_artifact:
|
if 'metadata' in sw_image_artifact:
|
||||||
sw_image_data.update({'metadata':
|
sw_image_data.update({'metadata':
|
||||||
@ -137,7 +141,79 @@ def _populate_flavour_data(tosca):
|
|||||||
flavours = []
|
flavours = []
|
||||||
if tosca.nested_tosca_templates_with_topology:
|
if tosca.nested_tosca_templates_with_topology:
|
||||||
for tp in 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:
|
else:
|
||||||
_get_flavour_data(tosca.topology_template, flavours)
|
_get_flavour_data(tosca.topology_template, flavours)
|
||||||
|
|
||||||
|
@ -356,5 +356,9 @@ class UserDataUpdateCreateFailed(TackerException):
|
|||||||
"or created after %(retries)d retries.")
|
"or created after %(retries)d retries.")
|
||||||
|
|
||||||
|
|
||||||
|
class DBAccessError(TackerException):
|
||||||
|
message = _("DB Access Error")
|
||||||
|
|
||||||
|
|
||||||
class SeeOther(TackerException):
|
class SeeOther(TackerException):
|
||||||
code = 303
|
code = 303
|
||||||
|
@ -18,6 +18,7 @@ import functools
|
|||||||
import inspect
|
import inspect
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import oslo_messaging
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
@ -28,7 +29,6 @@ import yaml
|
|||||||
from glance_store import exceptions as store_exceptions
|
from glance_store import exceptions as store_exceptions
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import oslo_messaging
|
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
from oslo_service import periodic_task
|
from oslo_service import periodic_task
|
||||||
from oslo_service import service
|
from oslo_service import service
|
||||||
@ -42,20 +42,25 @@ from sqlalchemy.orm import exc as orm_exc
|
|||||||
from tacker import auth
|
from tacker import auth
|
||||||
from tacker.common import coordination
|
from tacker.common import coordination
|
||||||
from tacker.common import csar_utils
|
from tacker.common import csar_utils
|
||||||
|
from tacker.common import driver_manager
|
||||||
from tacker.common import exceptions
|
from tacker.common import exceptions
|
||||||
from tacker.common import log
|
from tacker.common import log
|
||||||
from tacker.common import safe_utils
|
from tacker.common import safe_utils
|
||||||
from tacker.common import topics
|
from tacker.common import topics
|
||||||
from tacker.common import utils
|
from tacker.common import utils
|
||||||
|
import tacker.conf
|
||||||
from tacker import context as t_context
|
from tacker import context as t_context
|
||||||
from tacker.db.common_services import common_services_db
|
from tacker.db.common_services import common_services_db
|
||||||
from tacker.db.nfvo import nfvo_db
|
from tacker.db.nfvo import nfvo_db
|
||||||
|
from tacker.db.vnfm import vnfm_db
|
||||||
from tacker.extensions import nfvo
|
from tacker.extensions import nfvo
|
||||||
from tacker.glance_store import store as glance_store
|
from tacker.glance_store import store as glance_store
|
||||||
from tacker import manager
|
from tacker import manager
|
||||||
from tacker import objects
|
from tacker import objects
|
||||||
from tacker.objects import fields
|
from tacker.objects import fields
|
||||||
from tacker.objects.vnf_package import VnfPackagesList
|
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.plugins.common import constants
|
||||||
from tacker import service as tacker_service
|
from tacker import service as tacker_service
|
||||||
from tacker import version
|
from tacker import version
|
||||||
@ -63,7 +68,7 @@ from tacker.vnflcm import utils as vnflcm_utils
|
|||||||
from tacker.vnflcm import vnflcm_driver
|
from tacker.vnflcm import vnflcm_driver
|
||||||
from tacker.vnfm import plugin
|
from tacker.vnfm import plugin
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = tacker.conf.CONF
|
||||||
|
|
||||||
# NOTE(tpatil): keystone_authtoken opts registered explicitly as conductor
|
# NOTE(tpatil): keystone_authtoken opts registered explicitly as conductor
|
||||||
# service doesn't use the keystonemiddleware.authtoken middleware as it's
|
# 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__)
|
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):
|
def _delete_csar(context, vnf_package):
|
||||||
# Delete from glance store
|
# Delete from glance store
|
||||||
@ -154,6 +166,9 @@ class Conductor(manager.Manager):
|
|||||||
super(Conductor, self).__init__(host=self.conf.host)
|
super(Conductor, self).__init__(host=self.conf.host)
|
||||||
self.vnfm_plugin = plugin.VNFMPlugin()
|
self.vnfm_plugin = plugin.VNFMPlugin()
|
||||||
self.vnflcm_driver = vnflcm_driver.VnfLcmDriver()
|
self.vnflcm_driver = vnflcm_driver.VnfLcmDriver()
|
||||||
|
self.vnf_manager = driver_manager.DriverManager(
|
||||||
|
'tacker.tacker.vnfm.drivers',
|
||||||
|
cfg.CONF.tacker.infra_driver)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
coordination.COORDINATOR.start()
|
coordination.COORDINATOR.start()
|
||||||
@ -223,7 +238,7 @@ class Conductor(manager.Manager):
|
|||||||
vnf_sw_image.min_ram = 0
|
vnf_sw_image.min_ram = 0
|
||||||
vnf_sw_image.min_disk = int(sw_image.get('min_disk').split()[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.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.software_image_id = sw_image['software_image_id']
|
||||||
vnf_sw_image.metadata = sw_image.get('metadata', dict())
|
vnf_sw_image.metadata = sw_image.get('metadata', dict())
|
||||||
vnf_sw_image.create()
|
vnf_sw_image.create()
|
||||||
@ -233,8 +248,9 @@ class Conductor(manager.Manager):
|
|||||||
deploy_flavour.package_uuid = package_uuid
|
deploy_flavour.package_uuid = package_uuid
|
||||||
deploy_flavour.flavour_id = flavour['flavour_id']
|
deploy_flavour.flavour_id = flavour['flavour_id']
|
||||||
deploy_flavour.flavour_description = flavour['flavour_description']
|
deploy_flavour.flavour_description = flavour['flavour_description']
|
||||||
deploy_flavour.instantiation_levels = \
|
if flavour.get('instantiation_levels'):
|
||||||
flavour.get('instantiation_levels')
|
deploy_flavour.instantiation_levels = \
|
||||||
|
flavour.get('instantiation_levels')
|
||||||
deploy_flavour.create()
|
deploy_flavour.create()
|
||||||
|
|
||||||
sw_images = flavour.get('sw_images')
|
sw_images = flavour.get('sw_images')
|
||||||
@ -273,27 +289,55 @@ class Conductor(manager.Manager):
|
|||||||
package_vnfd.vnfd_version = vnf_data.get('descriptor_version')
|
package_vnfd.vnfd_version = vnf_data.get('descriptor_version')
|
||||||
package_vnfd.create()
|
package_vnfd.create()
|
||||||
|
|
||||||
|
self._onboard_vnfd(context, vnf_package, vnf_data, flavours)
|
||||||
|
|
||||||
for flavour in flavours:
|
for flavour in flavours:
|
||||||
self._create_flavour(context, vnf_package.id, flavour)
|
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
|
@revert_upload_vnf_package
|
||||||
def upload_vnf_package_content(self, context, vnf_package):
|
def upload_vnf_package_content(self, context, vnf_package):
|
||||||
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)
|
|
||||||
vnf_package.onboarding_state = (
|
vnf_package.onboarding_state = (
|
||||||
fields.PackageOnboardingStateType.ONBOARDED)
|
fields.PackageOnboardingStateType.PROCESSING)
|
||||||
vnf_package.operational_state = (
|
try:
|
||||||
fields.PackageOperationalStateType.ENABLED)
|
vnf_package.save()
|
||||||
|
|
||||||
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_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
|
@revert_upload_vnf_package
|
||||||
def upload_vnf_package_from_uri(self, context, vnf_package,
|
def upload_vnf_package_from_uri(self, context, vnf_package,
|
||||||
@ -433,6 +477,180 @@ class Conductor(manager.Manager):
|
|||||||
|
|
||||||
vnf_package.save()
|
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)
|
@periodic_task.periodic_task(spacing=CONF.vnf_package_delete_interval)
|
||||||
def _run_cleanup_vnf_packages(self, context):
|
def _run_cleanup_vnf_packages(self, context):
|
||||||
"""Delete orphan extracted csar zip and files from extracted path
|
"""Delete orphan extracted csar zip and files from extracted path
|
||||||
@ -490,7 +708,6 @@ class Conductor(manager.Manager):
|
|||||||
fields.LcmOccsOperationType.INSTANTIATE)
|
fields.LcmOccsOperationType.INSTANTIATE)
|
||||||
operation_state = kwargs.get('operation_state',
|
operation_state = kwargs.get('operation_state',
|
||||||
fields.LcmOccsOperationState.PROCESSING)
|
fields.LcmOccsOperationState.PROCESSING)
|
||||||
evacuate_end_list = kwargs.get('evacuate_end_list', None)
|
|
||||||
is_automatic_invocation = \
|
is_automatic_invocation = \
|
||||||
kwargs.get('is_automatic_invocation', False)
|
kwargs.get('is_automatic_invocation', False)
|
||||||
error = kwargs.get('error', None)
|
error = kwargs.get('error', None)
|
||||||
@ -546,8 +763,7 @@ class Conductor(manager.Manager):
|
|||||||
operation_state == fields.LcmOccsOperationState.FAILED_TEMP):
|
operation_state == fields.LcmOccsOperationState.FAILED_TEMP):
|
||||||
affected_resources = vnflcm_utils._get_affected_resources(
|
affected_resources = vnflcm_utils._get_affected_resources(
|
||||||
old_vnf_instance=old_vnf_instance,
|
old_vnf_instance=old_vnf_instance,
|
||||||
new_vnf_instance=vnf_instance,
|
new_vnf_instance=vnf_instance)
|
||||||
extra_list=evacuate_end_list)
|
|
||||||
affected_resources_snake_case = \
|
affected_resources_snake_case = \
|
||||||
utils.convert_camelcase_to_snakecase(affected_resources)
|
utils.convert_camelcase_to_snakecase(affected_resources)
|
||||||
resource_change_obj = \
|
resource_change_obj = \
|
||||||
@ -666,6 +882,7 @@ class Conductor(manager.Manager):
|
|||||||
self,
|
self,
|
||||||
context,
|
context,
|
||||||
vnf_instance,
|
vnf_instance,
|
||||||
|
vnf_dict,
|
||||||
instantiate_vnf,
|
instantiate_vnf,
|
||||||
vnf_lcm_op_occs_id):
|
vnf_lcm_op_occs_id):
|
||||||
|
|
||||||
@ -679,30 +896,23 @@ class Conductor(manager.Manager):
|
|||||||
request_obj=instantiate_vnf
|
request_obj=instantiate_vnf
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if vnf is already instantiated.
|
# change vnf_status
|
||||||
vnf_instance = objects.VnfInstance.get_by_id(context,
|
if vnf_dict['status'] == 'INACTIVE':
|
||||||
vnf_instance.id)
|
vnf_dict['status'] = 'PENDING_CREATE'
|
||||||
if vnf_instance.instantiation_state == \
|
self._change_vnf_status(context, vnf_instance.id,
|
||||||
fields.VnfInstanceState.INSTANTIATED:
|
_INACTIVE_STATUS, 'PENDING_CREATE')
|
||||||
LOG.error("Vnf instance %(id)s is already in %(state)s state.",
|
|
||||||
{"id": vnf_instance.id,
|
|
||||||
"state": vnf_instance.instantiation_state})
|
|
||||||
return
|
|
||||||
|
|
||||||
self.vnflcm_driver.instantiate_vnf(context, vnf_instance,
|
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(
|
self._update_vnf_attributes(context, vnf_dict,
|
||||||
context, vnf_instance.vnfd_id)
|
_PENDING_STATUS, _ACTIVE_STATUS)
|
||||||
vnf_package = objects.VnfPackage.get_by_id(
|
self.vnflcm_driver._vnf_instance_update(context, vnf_instance,
|
||||||
context, vnf_package_vnfd.package_uuid,
|
instantiation_state=fields.VnfInstanceState.
|
||||||
expected_attrs=['vnfd'])
|
INSTANTIATED, task_state=None)
|
||||||
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)
|
|
||||||
|
|
||||||
# Update vnf_lcm_op_occs table and send notification "COMPLETED"
|
# Update vnf_lcm_op_occs table and send notification "COMPLETED"
|
||||||
self._send_lcm_op_occ_notification(
|
self._send_lcm_op_occ_notification(
|
||||||
@ -715,6 +925,12 @@ class Conductor(manager.Manager):
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as ex:
|
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"
|
# Update vnf_lcm_op_occs table and send notification "FAILED_TEMP"
|
||||||
self._send_lcm_op_occ_notification(
|
self._send_lcm_op_occ_notification(
|
||||||
context=context,
|
context=context,
|
||||||
@ -730,17 +946,6 @@ class Conductor(manager.Manager):
|
|||||||
def terminate(self, context, vnf_lcm_op_occs_id,
|
def terminate(self, context, vnf_lcm_op_occs_id,
|
||||||
vnf_instance, terminate_vnf_req, vnf_dict):
|
vnf_instance, terminate_vnf_req, vnf_dict):
|
||||||
try:
|
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)
|
old_vnf_instance = copy.deepcopy(vnf_instance)
|
||||||
|
|
||||||
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
|
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
|
||||||
@ -753,22 +958,18 @@ class Conductor(manager.Manager):
|
|||||||
operation=fields.LcmOccsOperationType.TERMINATE
|
operation=fields.LcmOccsOperationType.TERMINATE
|
||||||
)
|
)
|
||||||
|
|
||||||
self.vnflcm_driver.terminate_vnf(context, vnf_instance,
|
self._change_vnf_status(context, vnf_instance.id,
|
||||||
terminate_vnf_req,
|
_ACTIVE_STATUS, 'PENDING_TERMINATE')
|
||||||
vnf_lcm_op_occs_id)
|
|
||||||
|
|
||||||
vnf_package_vnfd = \
|
self.vnflcm_driver.terminate_vnf(context, vnf_instance,
|
||||||
objects.VnfPackageVnfd.get_by_id(context, vnf_instance.vnfd_id)
|
terminate_vnf_req)
|
||||||
vnf_package = \
|
self._change_vnf_status(context, vnf_instance.id,
|
||||||
objects.VnfPackage.get_by_id(context,
|
_PENDING_STATUS, 'INACTIVE')
|
||||||
vnf_package_vnfd.package_uuid,
|
|
||||||
expected_attrs=['vnfd'])
|
self.vnflcm_driver._vnf_instance_update(context, vnf_instance,
|
||||||
try:
|
vim_connection_info=[], task_state=None,
|
||||||
self._update_package_usage_state(context, vnf_package)
|
instantiation_state=fields.VnfInstanceState.NOT_INSTANTIATED)
|
||||||
except Exception:
|
vnf_instance.instantiated_vnf_info.reinitialize()
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
LOG.error("Failed to update usage_state of vnf package %s",
|
|
||||||
vnf_package.id)
|
|
||||||
|
|
||||||
# Update vnf_lcm_op_occs table and send notification "COMPLETED"
|
# Update vnf_lcm_op_occs table and send notification "COMPLETED"
|
||||||
self._send_lcm_op_occ_notification(
|
self._send_lcm_op_occ_notification(
|
||||||
@ -782,6 +983,10 @@ class Conductor(manager.Manager):
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as exc:
|
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"
|
# Update vnf_lcm_op_occs table and send notification "FAILED_TEMP"
|
||||||
self._send_lcm_op_occ_notification(
|
self._send_lcm_op_occ_notification(
|
||||||
context=context,
|
context=context,
|
||||||
@ -803,19 +1008,6 @@ class Conductor(manager.Manager):
|
|||||||
vnf_lcm_op_occs_id):
|
vnf_lcm_op_occs_id):
|
||||||
|
|
||||||
try:
|
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)
|
old_vnf_instance = copy.deepcopy(vnf_instance)
|
||||||
|
|
||||||
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
|
# Update vnf_lcm_op_occs table and send notification "PROCESSING"
|
||||||
@ -828,15 +1020,25 @@ class Conductor(manager.Manager):
|
|||||||
operation=fields.LcmOccsOperationType.HEAL
|
operation=fields.LcmOccsOperationType.HEAL
|
||||||
)
|
)
|
||||||
|
|
||||||
heal_result = \
|
# update vnf status to PENDING_HEAL
|
||||||
self.vnflcm_driver.heal_vnf(context, vnf_instance, vnf_dict,
|
self._change_vnf_status(context, vnf_instance.id,
|
||||||
heal_vnf_request,
|
_ACTIVE_STATUS, constants.PENDING_HEAL)
|
||||||
vnf_lcm_op_occs_id)
|
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"
|
# 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(
|
self._send_lcm_op_occ_notification(
|
||||||
context=context,
|
context=context,
|
||||||
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
vnf_lcm_op_occs_id=vnf_lcm_op_occs_id,
|
||||||
@ -844,10 +1046,16 @@ class Conductor(manager.Manager):
|
|||||||
vnf_instance=vnf_instance,
|
vnf_instance=vnf_instance,
|
||||||
request_obj=heal_vnf_request,
|
request_obj=heal_vnf_request,
|
||||||
operation=fields.LcmOccsOperationType.HEAL,
|
operation=fields.LcmOccsOperationType.HEAL,
|
||||||
operation_state=fields.LcmOccsOperationState.COMPLETED,
|
operation_state=fields.LcmOccsOperationState.COMPLETED
|
||||||
evacuate_end_list=evacuate_end_list
|
|
||||||
)
|
)
|
||||||
except Exception as ex:
|
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"
|
# update vnf_lcm_op_occs and send notification "FAILED_TEMP"
|
||||||
self._send_lcm_op_occ_notification(
|
self._send_lcm_op_occ_notification(
|
||||||
@ -858,7 +1066,6 @@ class Conductor(manager.Manager):
|
|||||||
request_obj=heal_vnf_request,
|
request_obj=heal_vnf_request,
|
||||||
operation=fields.LcmOccsOperationType.HEAL,
|
operation=fields.LcmOccsOperationType.HEAL,
|
||||||
operation_state=fields.LcmOccsOperationState.FAILED_TEMP,
|
operation_state=fields.LcmOccsOperationState.FAILED_TEMP,
|
||||||
evacuate_end_list=evacuate_end_list,
|
|
||||||
error=str(ex)
|
error=str(ex)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -56,7 +56,28 @@ Possible values:
|
|||||||
|
|
||||||
Related options:
|
Related options:
|
||||||
* None
|
* 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',
|
vnf_package_group = cfg.OptGroup('vnf_package',
|
||||||
title='vnf_package options',
|
title='vnf_package options',
|
||||||
|
@ -201,8 +201,8 @@ class VnfInstance(model_base.BASE, models.SoftDeleteMixin,
|
|||||||
task_state = sa.Column(sa.String(255), nullable=True)
|
task_state = sa.Column(sa.String(255), nullable=True)
|
||||||
vim_connection_info = sa.Column(sa.JSON(), nullable=True)
|
vim_connection_info = sa.Column(sa.JSON(), nullable=True)
|
||||||
tenant_id = sa.Column('tenant_id', sa.String(length=64), nullable=False)
|
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_pkg_id = sa.Column(types.Uuid, nullable=False)
|
||||||
|
vnf_metadata = sa.Column(sa.JSON(), nullable=True)
|
||||||
|
|
||||||
|
|
||||||
class VnfInstantiatedInfo(model_base.BASE, models.SoftDeleteMixin,
|
class VnfInstantiatedInfo(model_base.BASE, models.SoftDeleteMixin,
|
||||||
|
@ -34,6 +34,7 @@ def register_all():
|
|||||||
__import__('tacker.objects.vim_connection')
|
__import__('tacker.objects.vim_connection')
|
||||||
__import__('tacker.objects.instantiate_vnf_req')
|
__import__('tacker.objects.instantiate_vnf_req')
|
||||||
__import__('tacker.objects.vnf_resources')
|
__import__('tacker.objects.vnf_resources')
|
||||||
|
__import__('tacker.objects.vnfd')
|
||||||
__import__('tacker.objects.vnf_lcm_op_occs')
|
__import__('tacker.objects.vnf_lcm_op_occs')
|
||||||
__import__('tacker.objects.terminate_vnf_req')
|
__import__('tacker.objects.terminate_vnf_req')
|
||||||
__import__('tacker.objects.vnf_artifact')
|
__import__('tacker.objects.vnf_artifact')
|
||||||
|
@ -51,6 +51,8 @@ class TerminateVnfRequest(base.TackerObject, base.TackerPersistentObject):
|
|||||||
termination_type = data_dict.get('termination_type')
|
termination_type = data_dict.get('termination_type')
|
||||||
graceful_termination_timeout = \
|
graceful_termination_timeout = \
|
||||||
data_dict.get('graceful_termination_timeout', 0)
|
data_dict.get('graceful_termination_timeout', 0)
|
||||||
|
additional_params = data_dict.get('additional_params', {})
|
||||||
|
|
||||||
return cls(termination_type=termination_type,
|
return cls(termination_type=termination_type,
|
||||||
graceful_termination_timeout=graceful_termination_timeout)
|
graceful_termination_timeout=graceful_termination_timeout,
|
||||||
|
additional_params=additional_params)
|
||||||
|
@ -12,11 +12,13 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
import copy
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
from oslo_versionedobjects import base as ovoo_base
|
from oslo_versionedobjects import base as ovoo_base
|
||||||
|
from sqlalchemy import exc
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
from sqlalchemy_filters import apply_filters
|
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
|
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
|
@base.TackerObjectRegistry.register
|
||||||
class VnfInstance(base.TackerObject, base.TackerPersistentObject,
|
class VnfInstance(base.TackerObject, base.TackerPersistentObject,
|
||||||
base.TackerObjectDictCompat):
|
base.TackerObjectDictCompat):
|
||||||
@ -157,10 +171,10 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
|
|||||||
'vim_connection_info': fields.ListOfObjectsField(
|
'vim_connection_info': fields.ListOfObjectsField(
|
||||||
'VimConnectionInfo', nullable=True, default=[]),
|
'VimConnectionInfo', nullable=True, default=[]),
|
||||||
'tenant_id': fields.StringField(nullable=False),
|
'tenant_id': fields.StringField(nullable=False),
|
||||||
'instantiated_vnf_info': fields.ObjectField('InstantiatedVnfInfo',
|
|
||||||
nullable=True, default=None),
|
|
||||||
'vnf_pkg_id': fields.StringField(nullable=False),
|
'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 = {
|
ALL_ATTRIBUTES = {
|
||||||
@ -239,12 +253,20 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
|
|||||||
updates['id'] = uuidutils.generate_uuid()
|
updates['id'] = uuidutils.generate_uuid()
|
||||||
self.id = updates['id']
|
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)
|
db_vnf_instance = _vnf_instance_create(self._context, updates)
|
||||||
expected_attrs = ["instantiated_vnf_info"]
|
expected_attrs = ["instantiated_vnf_info"]
|
||||||
self._from_db_object(self._context, self, db_vnf_instance,
|
self._from_db_object(self._context, self, db_vnf_instance,
|
||||||
expected_attrs=expected_attrs)
|
expected_attrs=expected_attrs)
|
||||||
|
|
||||||
@base.remotable
|
@base.remotable
|
||||||
|
@_wrap_object_error
|
||||||
def save(self):
|
def save(self):
|
||||||
context = self._context
|
context = self._context
|
||||||
|
|
||||||
@ -263,6 +285,10 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
|
|||||||
field_list = getattr(self, field)
|
field_list = getattr(self, field)
|
||||||
updates[field] = [obj.obj_to_primitive() for obj in field_list]
|
updates[field] = [obj.obj_to_primitive() for obj in field_list]
|
||||||
elif field in changes:
|
elif field in changes:
|
||||||
|
if (field == 'vnf_instance_name' and
|
||||||
|
not self[field]):
|
||||||
|
self.vnf_instance_name = 'vnf-' + self.id
|
||||||
|
|
||||||
updates[field] = self[field]
|
updates[field] = self[field]
|
||||||
|
|
||||||
expected_attrs = ["instantiated_vnf_info"]
|
expected_attrs = ["instantiated_vnf_info"]
|
||||||
@ -277,6 +303,15 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
|
|||||||
self.instantiated_vnf_info.save()
|
self.instantiated_vnf_info.save()
|
||||||
|
|
||||||
@base.remotable
|
@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):
|
def destroy(self, context):
|
||||||
if not self.obj_attr_is_set('id'):
|
if not self.obj_attr_is_set('id'):
|
||||||
raise exceptions.ObjectActionError(action='destroy',
|
raise exceptions.ObjectActionError(action='destroy',
|
||||||
@ -293,8 +328,8 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
|
|||||||
'vnf_provider': self.vnf_provider,
|
'vnf_provider': self.vnf_provider,
|
||||||
'vnf_product_name': self.vnf_product_name,
|
'vnf_product_name': self.vnf_product_name,
|
||||||
'vnf_software_version': self.vnf_software_version,
|
'vnf_software_version': self.vnf_software_version,
|
||||||
'vnf_pkg_id': self.vnf_pkg_id,
|
|
||||||
'vnfd_version': self.vnfd_version,
|
'vnfd_version': self.vnfd_version,
|
||||||
|
'vnf_pkg_id': self.vnf_pkg_id,
|
||||||
'vnf_metadata': self.vnf_metadata}
|
'vnf_metadata': self.vnf_metadata}
|
||||||
|
|
||||||
if (self.instantiation_state == fields.VnfInstanceState.INSTANTIATED
|
if (self.instantiation_state == fields.VnfInstanceState.INSTANTIATED
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import timeutils
|
||||||
|
|
||||||
from tacker.common import exceptions
|
from tacker.common import exceptions
|
||||||
from tacker.common import utils
|
from tacker.common import utils
|
||||||
@ -27,6 +28,17 @@ from tacker.objects import fields
|
|||||||
LOG = logging.getLogger(__name__)
|
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
|
@db_api.context_manager.writer
|
||||||
def _instantiate_vnf_info_update(context, vnf_instance_id, values):
|
def _instantiate_vnf_info_update(context, vnf_instance_id, values):
|
||||||
vnf_info = api.model_query(context, models.VnfInstantiatedInfo). \
|
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.vnf_state = fields.VnfOperationalStateType.STOPPED
|
||||||
self.vnfc_info = []
|
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
|
@base.TackerObjectRegistry.register
|
||||||
class VnfExtCpInfo(base.TackerObject, base.TackerObjectDictCompat,
|
class VnfExtCpInfo(base.TackerObject, base.TackerObjectDictCompat,
|
||||||
|
@ -502,9 +502,6 @@ class VnfPackage(base.TackerObject, base.TackerPersistentObject,
|
|||||||
|
|
||||||
@base.remotable
|
@base.remotable
|
||||||
def create(self):
|
def create(self):
|
||||||
if self.obj_attr_is_set('id'):
|
|
||||||
raise exceptions.ObjectActionError(action='create',
|
|
||||||
reason=_('already created'))
|
|
||||||
updates = self.obj_get_changes()
|
updates = self.obj_get_changes()
|
||||||
|
|
||||||
if 'id' not in updates:
|
if 'id' not in updates:
|
||||||
|
@ -59,6 +59,29 @@ def _vnf_package_vnfd_get_by_id(context, vnfd_id):
|
|||||||
return result
|
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
|
@base.TackerObjectRegistry.register
|
||||||
class VnfPackageVnfd(base.TackerObject, base.TackerObjectDictCompat,
|
class VnfPackageVnfd(base.TackerObject, base.TackerObjectDictCompat,
|
||||||
base.TackerPersistentObject):
|
base.TackerPersistentObject):
|
||||||
@ -104,6 +127,10 @@ class VnfPackageVnfd(base.TackerObject, base.TackerObjectDictCompat,
|
|||||||
self._context, updates)
|
self._context, updates)
|
||||||
self._from_db_object(self._context, self, db_vnf_package_vnfd)
|
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
|
@classmethod
|
||||||
def obj_from_db_obj(cls, context, db_obj):
|
def obj_from_db_obj(cls, context, db_obj):
|
||||||
return cls._from_db_object(context, cls(), db_obj)
|
return cls._from_db_object(context, cls(), db_obj)
|
||||||
|
132
tacker/objects/vnfd.py
Normal file
132
tacker/objects/vnfd.py
Normal 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)
|
124
tacker/objects/vnfd_attribute.py
Normal file
124
tacker/objects/vnfd_attribute.py
Normal 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)
|
@ -14,31 +14,29 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
import fixtures
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import requests
|
||||||
import shutil
|
import shutil
|
||||||
|
import six.moves.urllib.error as urlerr
|
||||||
import sys
|
import sys
|
||||||
from unittest import mock
|
import tacker.conf
|
||||||
|
import yaml
|
||||||
import fixtures
|
|
||||||
|
|
||||||
from glance_store import exceptions as store_exceptions
|
from glance_store import exceptions as store_exceptions
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
import requests
|
|
||||||
from six.moves import urllib
|
from six.moves import urllib
|
||||||
import six.moves.urllib.error as urlerr
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
from tacker import auth
|
from tacker import auth
|
||||||
from tacker.common import coordination
|
from tacker.common import coordination
|
||||||
from tacker.common import csar_utils
|
from tacker.common import csar_utils
|
||||||
from tacker.common import exceptions
|
from tacker.common import exceptions
|
||||||
from tacker.conductor import conductor_server
|
from tacker.conductor import conductor_server
|
||||||
import tacker.conf
|
|
||||||
from tacker import context
|
from tacker import context
|
||||||
from tacker.glance_store import store as glance_store
|
from tacker.glance_store import store as glance_store
|
||||||
from tacker import objects
|
from tacker import objects
|
||||||
from tacker.objects import fields
|
from tacker.objects import fields
|
||||||
|
from tacker.plugins.common import constants
|
||||||
from tacker.tests.unit import base as unit_base
|
from tacker.tests.unit import base as unit_base
|
||||||
from tacker.tests.unit.conductor import fakes
|
from tacker.tests.unit.conductor import fakes
|
||||||
from tacker.tests.unit.db.base import SqlTestCase
|
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.objects import fakes as fake_obj
|
||||||
from tacker.tests.unit.vnflcm import fakes as vnflcm_fakes
|
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 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
|
import tacker.tests.unit.vnfm.test_nfvo_client as nfvo_client
|
||||||
from tacker.tests import utils
|
from tacker.tests import utils
|
||||||
from tacker.tests import uuidsentinel
|
from tacker.tests import uuidsentinel
|
||||||
|
import unittest
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
|
||||||
CONF = tacker.conf.CONF
|
CONF = tacker.conf.CONF
|
||||||
|
|
||||||
@ -254,14 +257,16 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
|||||||
|
|
||||||
return vnf_pack_vnfd_obj
|
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(objects.VnfLcmOpOcc, "save")
|
||||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
|
||||||
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||||
def test_instantiate_vnf_instance(self, mock_vnf_by_id,
|
def test_instantiate_vnf_instance(self, mock_vnf_by_id,
|
||||||
mock_package_in_use,
|
mock_get_lock, mock_save, mock_change_vnf_status,
|
||||||
mock_get_lock,
|
mock_update_vnf_attributes):
|
||||||
mock_save):
|
|
||||||
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||||
mock_vnf_by_id.return_value = \
|
mock_vnf_by_id.return_value = \
|
||||||
objects.VnfLcmOpOcc(context=self.context,
|
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_package_vnfd = self._create_and_upload_vnf_package()
|
||||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
||||||
vnf_package_vnfd.vnfd_id)
|
vnf_package_vnfd.vnfd_id)
|
||||||
mock_package_in_use.return_value = False
|
|
||||||
vnf_instance = objects.VnfInstance(context=self.context,
|
vnf_instance = objects.VnfInstance(context=self.context,
|
||||||
**vnf_instance_data)
|
**vnf_instance_data)
|
||||||
vnf_instance.create()
|
vnf_instance.create()
|
||||||
instantiate_vnf_req = vnflcm_fakes.get_instantiate_vnf_request_obj()
|
instantiate_vnf_req = vnflcm_fakes.get_instantiate_vnf_request_obj()
|
||||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
self.conductor.instantiate(self.context, vnf_instance,
|
vnf_dict = {"status": "ACTIVE"}
|
||||||
instantiate_vnf_req,
|
self.conductor.instantiate(self.context, vnf_instance, vnf_dict,
|
||||||
vnf_lcm_op_occs_id)
|
instantiate_vnf_req, vnf_lcm_op_occs_id)
|
||||||
self.vnflcm_driver.instantiate_vnf.assert_called_once_with(
|
self.vnflcm_driver.instantiate_vnf.assert_called_once_with(
|
||||||
self.context, mock.ANY, instantiate_vnf_req)
|
self.context, mock.ANY, vnf_dict, instantiate_vnf_req)
|
||||||
mock_package_in_use.assert_called_once()
|
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(objects.VnfLcmOpOcc, "save")
|
||||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
||||||
@ -316,6 +325,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
|||||||
{'id': vnf_instance.id,
|
{'id': vnf_instance.id,
|
||||||
'state': fields.VnfInstanceState.INSTANTIATED})
|
'state': fields.VnfInstanceState.INSTANTIATED})
|
||||||
|
|
||||||
|
@unittest.skip("Such test is no longer feasible.")
|
||||||
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
@mock.patch.object(objects.VnfLcmOpOcc, "save")
|
||||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
@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)
|
self.context, mock.ANY, instantiate_vnf_req)
|
||||||
mock_vnf_package_in_use.assert_called_once()
|
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(objects.VnfLcmOpOcc, "save")
|
||||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
|
||||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||||
'vnf_lcm_subscriptions_get')
|
'vnf_lcm_subscriptions_get')
|
||||||
@mock.patch('tacker.conductor.conductor_server.LOG')
|
@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(
|
def test_instantiate_vnf_instance_failed_with_exception(
|
||||||
self, mock_res, mock_vnf_by_id, mock_log,
|
self, mock_res, mock_vnf_by_id, mock_log,
|
||||||
mock_vnf_lcm_subscriptions_get,
|
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()
|
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||||
mock_vnf_by_id.return_value = \
|
mock_vnf_by_id.return_value = \
|
||||||
objects.VnfLcmOpOcc(context=self.context,
|
objects.VnfLcmOpOcc(context=self.context,
|
||||||
@ -376,38 +390,32 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
|||||||
vnf_instance.create()
|
vnf_instance.create()
|
||||||
instantiate_vnf_req = vnflcm_fakes.get_instantiate_vnf_request_obj()
|
instantiate_vnf_req = vnflcm_fakes.get_instantiate_vnf_request_obj()
|
||||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
|
vnf_dict = {"status": "ACTIVE"}
|
||||||
m_vnf_lcm_subscriptions = \
|
m_vnf_lcm_subscriptions = \
|
||||||
[mock.MagicMock(**fakes.get_vnf_lcm_subscriptions())]
|
[mock.MagicMock(**fakes.get_vnf_lcm_subscriptions())]
|
||||||
mock_vnf_lcm_subscriptions_get.return_value = \
|
mock_vnf_lcm_subscriptions_get.return_value = \
|
||||||
m_vnf_lcm_subscriptions
|
m_vnf_lcm_subscriptions
|
||||||
mock_is_package_in_use.side_effect = Exception
|
mock_update_vnf_attributes.side_effect = Exception
|
||||||
mock_res.return_value = {}
|
mock_res.return_value = {}
|
||||||
self.conductor.instantiate(self.context, vnf_instance,
|
self.conductor.instantiate(self.context, vnf_instance, vnf_dict,
|
||||||
instantiate_vnf_req,
|
instantiate_vnf_req, vnf_lcm_op_occs_id)
|
||||||
vnf_lcm_op_occs_id)
|
|
||||||
self.vnflcm_driver.instantiate_vnf.assert_called_once_with(
|
self.vnflcm_driver.instantiate_vnf.assert_called_once_with(
|
||||||
self.context, mock.ANY, instantiate_vnf_req)
|
self.context, vnf_instance, vnf_dict, instantiate_vnf_req)
|
||||||
mock_is_package_in_use.assert_called_once()
|
mock_change_vnf_status.assert_called_with(self.context,
|
||||||
expected_log = 'Failed to update usage_state of vnf package %s'
|
vnf_instance.id, mock.ANY, 'ERROR')
|
||||||
mock_log.error.assert_called_once_with(expected_log,
|
mock_update_vnf_attributes.assert_called_once()
|
||||||
vnf_package_vnfd.package_uuid)
|
|
||||||
|
|
||||||
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
@mock.patch('tacker.conductor.conductor_server.Conductor'
|
||||||
'_send_lcm_op_occ_notification')
|
'._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(coordination.Coordinator, 'get_lock')
|
||||||
@mock.patch.object(objects.VnfPackage, 'is_package_in_use')
|
def test_terminate_vnf_instance(self, mock_get_lock,
|
||||||
def test_terminate_vnf_instance(self, mock_package_in_use,
|
mock_send_notification,
|
||||||
mock_get_lock,
|
mock_change_vnf_status):
|
||||||
mock_send_notification):
|
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
|
||||||
vnf_package_vnfd = self._create_and_upload_vnf_package()
|
vnf_instance = fd_utils. \
|
||||||
vnf_instance_data = fake_obj.get_vnf_instance_data(
|
get_vnf_instance_object(instantiated_vnf_info=inst_vnf_info)
|
||||||
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()
|
|
||||||
|
|
||||||
terminate_vnf_req = objects.TerminateVnfRequest(
|
terminate_vnf_req = objects.TerminateVnfRequest(
|
||||||
termination_type=fields.VnfInstanceTerminationType.GRACEFUL,
|
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_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
vnf_dict = db_utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
vnf_dict = db_utils.get_dummy_vnf(instance_id=self.instance_uuid)
|
||||||
self.conductor.terminate(self.context, vnf_lcm_op_occs_id,
|
self.conductor.terminate(self.context, vnf_lcm_op_occs_id,
|
||||||
vnf_instance,
|
vnf_instance, terminate_vnf_req, vnf_dict)
|
||||||
terminate_vnf_req, vnf_dict)
|
|
||||||
|
|
||||||
self.vnflcm_driver.terminate_vnf.assert_called_once_with(
|
self.vnflcm_driver.terminate_vnf.assert_called_once_with(
|
||||||
self.context, mock.ANY, terminate_vnf_req,
|
self.context, vnf_instance, terminate_vnf_req)
|
||||||
vnf_lcm_op_occs_id)
|
self.vnflcm_driver._vnf_instance_update.assert_called_once()
|
||||||
mock_package_in_use.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.'
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
'_send_lcm_op_occ_notification')
|
'_send_lcm_op_occ_notification')
|
||||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
@ -458,6 +495,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
|||||||
{'id': vnf_instance.id,
|
{'id': vnf_instance.id,
|
||||||
'state': fields.VnfInstanceState.NOT_INSTANTIATED})
|
'state': fields.VnfInstanceState.NOT_INSTANTIATED})
|
||||||
|
|
||||||
|
@unittest.skip("Such test is no longer feasible.")
|
||||||
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
'_send_lcm_op_occ_notification')
|
'_send_lcm_op_occ_notification')
|
||||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
@ -489,6 +527,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
|||||||
vnf_lcm_op_occs_id)
|
vnf_lcm_op_occs_id)
|
||||||
mock_vnf_package_is_package_in_use.assert_called_once()
|
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.'
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
'_send_lcm_op_occ_notification')
|
'_send_lcm_op_occ_notification')
|
||||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
@ -520,6 +559,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
|||||||
vnf_lcm_op_occs_id)
|
vnf_lcm_op_occs_id)
|
||||||
mock_vnf_package_is_package_in_use.assert_called_once()
|
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.'
|
@mock.patch('tacker.conductor.conductor_server.Conductor.'
|
||||||
'_send_lcm_op_occ_notification')
|
'_send_lcm_op_occ_notification')
|
||||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
@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,
|
mock_log.error.assert_called_once_with(expected_msg,
|
||||||
vnf_package_vnfd.package_uuid)
|
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(objects.VnfLcmOpOcc, "save")
|
||||||
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
@mock.patch.object(coordination.Coordinator, 'get_lock')
|
||||||
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")
|
||||||
def test_heal_vnf_instance(self, mock_vnf_by_id, mock_get_lock,
|
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()
|
lcm_op_occs_data = fakes.get_lcm_op_occs_data()
|
||||||
mock_vnf_by_id.return_value = \
|
mock_vnf_by_id.return_value = \
|
||||||
objects.VnfLcmOpOcc(context=self.context,
|
objects.VnfLcmOpOcc(context=self.context,
|
||||||
@ -574,8 +621,50 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
|||||||
vnf_dict = {"fake": "fake_dict"}
|
vnf_dict = {"fake": "fake_dict"}
|
||||||
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id
|
||||||
self.conductor.heal(self.context, vnf_instance, vnf_dict,
|
self.conductor.heal(self.context, vnf_instance, vnf_dict,
|
||||||
heal_vnf_req, vnf_lcm_op_occs_id)
|
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.object(coordination.Coordinator, 'get_lock')
|
||||||
@mock.patch('tacker.conductor.conductor_server.LOG')
|
@mock.patch('tacker.conductor.conductor_server.LOG')
|
||||||
def test_heal_vnf_instance_already_not_instantiated(self,
|
def test_heal_vnf_instance_already_not_instantiated(self,
|
||||||
|
@ -97,9 +97,15 @@ class TestVnfPackage(SqlTestCase):
|
|||||||
uuidsentinel.invalid_uuid)
|
uuidsentinel.invalid_uuid)
|
||||||
|
|
||||||
def test_create_with_id(self):
|
def test_create_with_id(self):
|
||||||
vnf_obj = {'id': uuidsentinel.uuid}
|
vnfpkgm = objects.VnfPackage(context=self.context,
|
||||||
vnf_pack = objects.VnfPackage(context=self.context, **vnf_obj)
|
**fakes.vnf_package_data)
|
||||||
self.assertRaises(exceptions.ObjectActionError, vnf_pack.create)
|
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):
|
def test_save(self):
|
||||||
self.vnf_package.onboarding_state = 'ONBOARDED'
|
self.vnf_package.onboarding_state = 'ONBOARDED'
|
||||||
|
@ -119,8 +119,8 @@ def _model_non_instantiated_vnf_instance(**updates):
|
|||||||
'vnf_software_version': '1.0',
|
'vnf_software_version': '1.0',
|
||||||
'tenant_id': uuidsentinel.tenant_id,
|
'tenant_id': uuidsentinel.tenant_id,
|
||||||
'vnfd_id': uuidsentinel.vnfd_id,
|
'vnfd_id': uuidsentinel.vnfd_id,
|
||||||
'vnf_pkg_id': uuidsentinel.vnf_pkg_id,
|
|
||||||
'vnfd_version': '1.0',
|
'vnfd_version': '1.0',
|
||||||
|
'vnf_pkg_id': uuidsentinel.vnf_pkg_id,
|
||||||
'vnf_metadata': {"key": "value"}}
|
'vnf_metadata': {"key": "value"}}
|
||||||
|
|
||||||
if updates:
|
if updates:
|
||||||
|
@ -26,6 +26,7 @@ import webob
|
|||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from tacker.api.vnflcm.v1 import controller
|
from tacker.api.vnflcm.v1 import controller
|
||||||
|
from tacker.api.vnflcm.v1 import sync_resource
|
||||||
from tacker.common import exceptions
|
from tacker.common import exceptions
|
||||||
from tacker.conductor.conductorrpc.vnf_lcm_rpc import VNFLcmRPCAPI
|
from tacker.conductor.conductorrpc.vnf_lcm_rpc import VNFLcmRPCAPI
|
||||||
from tacker import context
|
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
|
import tacker.tests.unit.nfvo.test_nfvo_plugin as nfvo_plugin
|
||||||
from tacker.tests.unit.vnflcm import fakes
|
from tacker.tests.unit.vnflcm import fakes
|
||||||
from tacker.tests import uuidsentinel
|
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
|
from tacker.vnfm import vim_client
|
||||||
|
|
||||||
|
|
||||||
|
class FakeVimClient(mock.Mock):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _get_template(name):
|
def _get_template(name):
|
||||||
filename = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
filename = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||||
'../../etc/samples/' + str(name)))
|
'../../etc/samples/' + str(name)))
|
||||||
@ -231,29 +238,31 @@ class TestController(base.TestCase):
|
|||||||
res.status_int = status
|
res.status_int = status
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@mock.patch.object(objects.VnfInstance, 'save')
|
|
||||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||||
@mock.patch.object(objects.vnf_package.VnfPackage, 'get_by_id')
|
@mock.patch('tacker.api.vnflcm.v1.controller.'
|
||||||
@mock.patch.object(objects.vnf_package.VnfPackage, 'save')
|
'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_instance, '_vnf_instance_create')
|
||||||
@mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
|
@mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd, 'get_by_id')
|
||||||
def test_create_without_name_and_description(
|
def test_create_without_name_and_description(
|
||||||
self, mock_get_by_id_package_vnfd,
|
self, mock_get_by_id,
|
||||||
mock_vnf_instance_create, mock_package_save,
|
mock_vnf_instance_create,
|
||||||
mock_get_by_id_package, mock_get_vim,
|
mock_get_service_plugins,
|
||||||
mock_save):
|
mock_private_create_vnf,
|
||||||
mock_get_vim.return_value = self.vim_info
|
mock_vnf_package_get_by_id,
|
||||||
mock_get_by_id_package_vnfd.return_value = \
|
mock_update_package_usage_state,
|
||||||
fakes.return_vnf_package_vnfd()
|
mock_get_vim):
|
||||||
mock_get_by_id_package.return_value = \
|
mock_get_by_id.return_value = fakes.return_vnf_package_vnfd()
|
||||||
fakes.return_vnf_package_with_deployment_flavour()
|
|
||||||
|
|
||||||
updates = {'vnfd_id': uuidsentinel.vnfd_id,
|
updates = {'vnfd_id': uuidsentinel.vnfd_id,
|
||||||
'vnf_instance_description': None,
|
'vnf_instance_description': None,
|
||||||
'vnf_instance_name': None,
|
'vnf_instance_name': None,
|
||||||
'vnf_pkg_id': uuidsentinel.vnf_pkg_id,
|
'vnf_pkg_id': uuidsentinel.vnf_pkg_id,
|
||||||
'vnf_metadata': {"key": "value"}}
|
'vnf_metadata': {"key": "value"}}
|
||||||
|
|
||||||
mock_vnf_instance_create.return_value =\
|
mock_vnf_instance_create.return_value =\
|
||||||
fakes.return_vnf_instance_model(**updates)
|
fakes.return_vnf_instance_model(**updates)
|
||||||
|
|
||||||
@ -262,7 +271,6 @@ class TestController(base.TestCase):
|
|||||||
'metadata': {"key": "value"}}
|
'metadata': {"key": "value"}}
|
||||||
req.body = jsonutils.dump_as_bytes(body)
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
req.headers['Content-Type'] = 'application/json'
|
req.headers['Content-Type'] = 'application/json'
|
||||||
req.headers['Version'] = '2.6.1'
|
|
||||||
req.method = 'POST'
|
req.method = 'POST'
|
||||||
|
|
||||||
# Call create API
|
# Call create API
|
||||||
@ -271,15 +279,15 @@ class TestController(base.TestCase):
|
|||||||
self.assertEqual(http_client.CREATED, resp.status_code)
|
self.assertEqual(http_client.CREATED, resp.status_code)
|
||||||
|
|
||||||
updates = {'vnfInstanceDescription': None, 'vnfInstanceName': None}
|
updates = {'vnfInstanceDescription': None, 'vnfInstanceName': None}
|
||||||
expected_vnf = fakes.fake_vnf_instance_response(
|
expected_vnf = fakes.fake_vnf_instance_response(**updates)
|
||||||
instantiated_state=fields.VnfInstanceState.NOT_INSTANTIATED,
|
|
||||||
**updates)
|
|
||||||
location_header = ('http://localhost/vnflcm/v1/vnf_instances/%s'
|
location_header = ('http://localhost/vnflcm/v1/vnf_instances/%s'
|
||||||
% resp.json['id'])
|
% resp.json['id'])
|
||||||
|
|
||||||
self.assertEqual(expected_vnf, resp.json)
|
self.assertEqual(expected_vnf, resp.json)
|
||||||
self.assertEqual(location_header, resp.headers['location'])
|
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(objects.VnfInstance, 'save')
|
||||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
@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, 'get_by_id')
|
||||||
@ -290,7 +298,7 @@ class TestController(base.TestCase):
|
|||||||
self, mock_get_by_id_package_vnfd,
|
self, mock_get_by_id_package_vnfd,
|
||||||
mock_vnf_instance_create, mock_package_save,
|
mock_vnf_instance_create, mock_package_save,
|
||||||
mock_get_by_id_package, mock_get_vim,
|
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_vim.return_value = self.vim_info
|
||||||
mock_get_by_id_package_vnfd.return_value = \
|
mock_get_by_id_package_vnfd.return_value = \
|
||||||
fakes.return_vnf_package_vnfd()
|
fakes.return_vnf_package_vnfd()
|
||||||
@ -313,13 +321,13 @@ class TestController(base.TestCase):
|
|||||||
req = fake_request.HTTPRequest.blank('/vnf_instances')
|
req = fake_request.HTTPRequest.blank('/vnf_instances')
|
||||||
req.body = jsonutils.dump_as_bytes(body)
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
req.headers['Content-Type'] = 'application/json'
|
req.headers['Content-Type'] = 'application/json'
|
||||||
req.headers['Version'] = '2.6.1'
|
|
||||||
req.method = 'POST'
|
req.method = 'POST'
|
||||||
|
|
||||||
# Call Create API
|
# Call Create API
|
||||||
resp = req.get_response(self.app)
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
self.assertEqual(http_client.CREATED, resp.status_code)
|
self.assertEqual(http_client.CREATED, resp.status_code)
|
||||||
|
|
||||||
updates = {"vnfInstanceName": "SampleVnf",
|
updates = {"vnfInstanceName": "SampleVnf",
|
||||||
"vnfInstanceDescription": "SampleVnf Description"}
|
"vnfInstanceDescription": "SampleVnf Description"}
|
||||||
expected_vnf = fakes.fake_vnf_instance_response(**updates)
|
expected_vnf = fakes.fake_vnf_instance_response(**updates)
|
||||||
@ -329,49 +337,6 @@ class TestController(base.TestCase):
|
|||||||
self.assertEqual(expected_vnf, resp.json)
|
self.assertEqual(expected_vnf, resp.json)
|
||||||
self.assertEqual(location_header, resp.headers['location'])
|
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(
|
@ddt.data(
|
||||||
{'attribute': 'vnfdId', 'value': True,
|
{'attribute': 'vnfdId', 'value': True,
|
||||||
'expected_type': 'uuid'},
|
'expected_type': 'uuid'},
|
||||||
@ -384,13 +349,7 @@ class TestController(base.TestCase):
|
|||||||
{'attribute': 'vnfInstanceDescription', 'value': True,
|
{'attribute': 'vnfInstanceDescription', 'value': True,
|
||||||
'expected_type': 'description'},
|
'expected_type': 'description'},
|
||||||
{'attribute': 'vnfInstanceDescription', 'value': 123,
|
{'attribute': 'vnfInstanceDescription', 'value': 123,
|
||||||
'expected_type': 'description'},
|
'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'},
|
|
||||||
)
|
)
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_create_with_invalid_request_body(
|
def test_create_with_invalid_request_body(
|
||||||
@ -404,7 +363,6 @@ class TestController(base.TestCase):
|
|||||||
body.update({attribute: value})
|
body.update({attribute: value})
|
||||||
req.body = jsonutils.dump_as_bytes(body)
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
req.headers['Content-Type'] = 'application/json'
|
req.headers['Content-Type'] = 'application/json'
|
||||||
req.headers['Version'] = '2.6.1'
|
|
||||||
req.method = 'POST'
|
req.method = 'POST'
|
||||||
exception = self.assertRaises(
|
exception = self.assertRaises(
|
||||||
exceptions.ValidationError, self.controller.create,
|
exceptions.ValidationError, self.controller.create,
|
||||||
@ -428,28 +386,160 @@ class TestController(base.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(expected_message, exception.msg)
|
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')
|
@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_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,
|
body = {'vnfdId': uuidsentinel.vnfd_id,
|
||||||
'metadata': {"key": "value"}}
|
'metadata': {"key": "value"}}
|
||||||
req = fake_request.HTTPRequest.blank('/vnf_instances')
|
req = fake_request.HTTPRequest.blank('/vnf_instances')
|
||||||
req.body = jsonutils.dump_as_bytes(body)
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
req.headers['Content-Type'] = 'application/json'
|
req.headers['Content-Type'] = 'application/json'
|
||||||
req.headers['Version'] = '2.6.1'
|
|
||||||
req.method = 'POST'
|
req.method = 'POST'
|
||||||
self.assertRaises(exc.HTTPBadRequest, self.controller.create, req,
|
self.assertRaises(exc.HTTPBadRequest, self.controller.create, req,
|
||||||
body=body)
|
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",
|
body = {"vnfInstanceName": "SampleVnfInstance",
|
||||||
'metadata': {"key": "value"}}
|
"metadata": {"key": "value"}}
|
||||||
req = fake_request.HTTPRequest.blank(
|
req = fake_request.HTTPRequest.blank(
|
||||||
'/vnf_instances')
|
'/vnf_instances')
|
||||||
req.body = jsonutils.dump_as_bytes(body)
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
req.headers['Content-Type'] = 'application/json'
|
req.headers['Content-Type'] = 'application/json'
|
||||||
req.method = 'POST'
|
req.method = 'POST'
|
||||||
resp = req.get_response(self.app)
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||||
|
|
||||||
@ddt.data('PATCH', 'PUT', 'HEAD', 'DELETE')
|
@ddt.data('PATCH', 'PUT', 'HEAD', 'DELETE')
|
||||||
@ -461,29 +551,38 @@ class TestController(base.TestCase):
|
|||||||
req.headers['Content-Type'] = 'application/json'
|
req.headers['Content-Type'] = 'application/json'
|
||||||
req.method = method
|
req.method = method
|
||||||
resp = req.get_response(self.app)
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
self.assertEqual(http_client.METHOD_NOT_ALLOWED, resp.status_code)
|
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',
|
||||||
'meta': {"key": "value"}},
|
return_value={'VNFM': FakeVNFMPlugin()})
|
||||||
{'name': 'Fake-VNF', 'description': "A" * 1025,
|
@ddt.data({'name': "A" * 256,
|
||||||
'meta': {"key": "value"}},
|
'description': "VNF Description",
|
||||||
{'name': 'Fake-VNF', 'description': "VNF Description",
|
'meta': {"key": "value"}},
|
||||||
'meta': {"key": "v" * 256}})
|
{'name': 'Fake-VNF',
|
||||||
@ddt.unpack
|
'description': "A" * 1025,
|
||||||
|
'meta': {"key": "value"}},
|
||||||
|
{'name': 'Fake-VNF',
|
||||||
|
'description': "VNF Description",
|
||||||
|
'meta': {"key": "v" * 256}})
|
||||||
def test_create_max_length_exceeded_for_vnf_name_and_description(
|
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
|
# vnf instance_name and description with length greater than max
|
||||||
# length defined
|
# length defined
|
||||||
body = {"vnfInstanceName": name,
|
body = {"vnfInstanceName": name,
|
||||||
"vnfdId": uuidsentinel.vnfd_id,
|
"vnfdId": uuidsentinel.vnfd_id,
|
||||||
"vnfInstanceDescription": description,
|
"vnfInstanceDescription": description,
|
||||||
"metadata": meta}
|
'metadata': meta}
|
||||||
req = fake_request.HTTPRequest.blank(
|
req = fake_request.HTTPRequest.blank(
|
||||||
'/vnf_instances')
|
'/vnf_instances')
|
||||||
req.body = jsonutils.dump_as_bytes(body)
|
req.body = jsonutils.dump_as_bytes(body)
|
||||||
req.headers['Content-Type'] = 'application/json'
|
req.headers['Content-Type'] = 'application/json'
|
||||||
req.method = 'POST'
|
req.method = 'POST'
|
||||||
resp = req.get_response(self.app)
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
self.assertEqual(http_client.BAD_REQUEST, resp.status_code)
|
||||||
|
|
||||||
@mock.patch.object(TackerManager, 'get_service_plugins',
|
@mock.patch.object(TackerManager, 'get_service_plugins',
|
||||||
@ -1487,9 +1586,14 @@ class TestController(base.TestCase):
|
|||||||
resp = req.get_response(self.app)
|
resp = req.get_response(self.app)
|
||||||
self.assertEqual(http_client.METHOD_NOT_ALLOWED, resp.status_code)
|
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, "_vnf_instance_get_by_id")
|
||||||
@mock.patch.object(objects.vnf_instance, '_destroy_vnf_instance')
|
@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(
|
req = fake_request.HTTPRequest.blank(
|
||||||
'/vnf_instances/%s' % uuidsentinel.vnf_instance_id)
|
'/vnf_instances/%s' % uuidsentinel.vnf_instance_id)
|
||||||
req.method = 'DELETE'
|
req.method = 'DELETE'
|
||||||
@ -1500,7 +1604,6 @@ class TestController(base.TestCase):
|
|||||||
resp = req.get_response(self.app)
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
self.assertEqual(http_client.NO_CONTENT, resp.status_code)
|
self.assertEqual(http_client.NO_CONTENT, resp.status_code)
|
||||||
mock_destroy_vnf_instance.assert_called_once()
|
|
||||||
|
|
||||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||||
def test_delete_with_non_existing_vnf_instance(self, mock_vnf_by_id):
|
def test_delete_with_non_existing_vnf_instance(self, mock_vnf_by_id):
|
||||||
|
350
tacker/tests/unit/vnflcm/test_sync_resource.py
Normal file
350
tacker/tests/unit/vnflcm/test_sync_resource.py
Normal 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()
|
@ -19,6 +19,7 @@ import shutil
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_utils import uuidutils
|
||||||
from tacker.common import exceptions
|
from tacker.common import exceptions
|
||||||
from tacker.common import utils
|
from tacker.common import utils
|
||||||
from tacker import context
|
from tacker import context
|
||||||
@ -32,6 +33,26 @@ from tacker.vnflcm import vnflcm_driver
|
|||||||
from tacker.vnfm import vim_client
|
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 = [
|
OPTS_INFRA_DRIVER = [
|
||||||
cfg.ListOpt(
|
cfg.ListOpt(
|
||||||
'infra_driver', default=['noop', 'openstack', 'kubernetes'],
|
'infra_driver', default=['noop', 'openstack', 'kubernetes'],
|
||||||
@ -100,6 +121,10 @@ class FakeVimClient(mock.Mock):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FakeTackerManager(mock.MagicMock):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestVnflcmDriver(db_base.SqlTestCase):
|
class TestVnflcmDriver(db_base.SqlTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -136,11 +161,13 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
'test_project'}, 'vim_type': 'openstack'}
|
'test_project'}, 'vim_type': 'openstack'}
|
||||||
self.vim_client.get_vim.return_value = vim_obj
|
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.VnfResource, 'create')
|
||||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||||
@mock.patch.object(objects.VnfInstance, "save")
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
def test_instantiate_vnf(self, mock_vnf_instance_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_vnfd = fakes.return_vnf_package_vnfd()
|
||||||
vnf_package_id = vnf_package_vnfd.package_uuid
|
vnf_package_id = vnf_package_vnfd.package_uuid
|
||||||
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
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")
|
test_utils.copy_csar_files(fake_csar, "vnflcm4")
|
||||||
self._mock_vnf_manager()
|
self._mock_vnf_manager()
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
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)
|
instantiate_vnf_req_obj)
|
||||||
|
|
||||||
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
|
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
|
||||||
self.assertEqual(2, mock_vnf_instance_save.call_count)
|
self.assertEqual(2, mock_vnf_instance_save.call_count)
|
||||||
self.assertEqual(4, self._vnf_manager.invoke.call_count)
|
self.assertEqual(4, self._vnf_manager.invoke.call_count)
|
||||||
|
mock_final_vnf_dict.assert_called_once()
|
||||||
shutil.rmtree(fake_csar)
|
shutil.rmtree(fake_csar)
|
||||||
|
|
||||||
|
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
|
||||||
@mock.patch.object(objects.VnfResource, 'create')
|
@mock.patch.object(objects.VnfResource, 'create')
|
||||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||||
@mock.patch.object(objects.VnfInstance, "save")
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
def test_instantiate_vnf_with_ext_virtual_links(
|
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_vnfd = fakes.return_vnf_package_vnfd()
|
||||||
vnf_package_id = vnf_package_vnfd.package_uuid
|
vnf_package_id = vnf_package_vnfd.package_uuid
|
||||||
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
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")
|
test_utils.copy_csar_files(fake_csar, "vnflcm4")
|
||||||
self._mock_vnf_manager()
|
self._mock_vnf_manager()
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
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)
|
instantiate_vnf_req_obj)
|
||||||
|
|
||||||
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
|
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
|
||||||
self.assertEqual(2, mock_vnf_instance_save.call_count)
|
self.assertEqual(2, mock_vnf_instance_save.call_count)
|
||||||
self.assertEqual(4, self._vnf_manager.invoke.call_count)
|
self.assertEqual(4, self._vnf_manager.invoke.call_count)
|
||||||
|
mock_final_vnf_dict.assert_called_once()
|
||||||
shutil.rmtree(fake_csar)
|
shutil.rmtree(fake_csar)
|
||||||
|
|
||||||
|
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
|
||||||
@mock.patch.object(objects.VnfResource, 'create')
|
@mock.patch.object(objects.VnfResource, 'create')
|
||||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||||
@mock.patch.object(objects.VnfInstance, "save")
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
def test_instantiate_vnf_vim_connection_info(
|
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_vnfd = fakes.return_vnf_package_vnfd()
|
||||||
vnf_package_id = vnf_package_vnfd.package_uuid
|
vnf_package_id = vnf_package_vnfd.package_uuid
|
||||||
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
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")
|
test_utils.copy_csar_files(fake_csar, "vnflcm4")
|
||||||
self._mock_vnf_manager()
|
self._mock_vnf_manager()
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
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)
|
instantiate_vnf_req_obj)
|
||||||
|
|
||||||
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
|
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
|
||||||
self.assertEqual(2, mock_vnf_instance_save.call_count)
|
self.assertEqual(2, mock_vnf_instance_save.call_count)
|
||||||
self.assertEqual(4, self._vnf_manager.invoke.call_count)
|
self.assertEqual(4, self._vnf_manager.invoke.call_count)
|
||||||
|
mock_final_vnf_dict.assert_called_once()
|
||||||
shutil.rmtree(fake_csar)
|
shutil.rmtree(fake_csar)
|
||||||
|
|
||||||
|
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
|
||||||
@mock.patch.object(objects.VnfResource, 'create')
|
@mock.patch.object(objects.VnfResource, 'create')
|
||||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||||
@mock.patch.object(objects.VnfInstance, "save")
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
def test_instantiate_vnf_infra_fails_to_instantiate(
|
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_vnfd = fakes.return_vnf_package_vnfd()
|
||||||
vnf_package_id = vnf_package_vnfd.package_uuid
|
vnf_package_id = vnf_package_vnfd.package_uuid
|
||||||
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
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")
|
self._mock_vnf_manager(fail_method_name="instantiate_vnf")
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
error = self.assertRaises(exceptions.VnfInstantiationFailed,
|
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)
|
instantiate_vnf_req_obj)
|
||||||
expected_error = ("Vnf instantiation failed for vnf %s, error: "
|
expected_error = ("Vnf instantiation failed for vnf %s, error: "
|
||||||
"instantiate_vnf failed")
|
"instantiate_vnf failed")
|
||||||
@ -257,15 +293,17 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
vnf_instance_obj.instantiation_state)
|
vnf_instance_obj.instantiation_state)
|
||||||
self.assertEqual(2, mock_vnf_instance_save.call_count)
|
self.assertEqual(2, mock_vnf_instance_save.call_count)
|
||||||
self.assertEqual(2, self._vnf_manager.invoke.call_count)
|
self.assertEqual(2, self._vnf_manager.invoke.call_count)
|
||||||
|
mock_final_vnf_dict.assert_called_once()
|
||||||
|
|
||||||
shutil.rmtree(fake_csar)
|
shutil.rmtree(fake_csar)
|
||||||
|
|
||||||
|
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
|
||||||
@mock.patch.object(objects.VnfResource, 'create')
|
@mock.patch.object(objects.VnfResource, 'create')
|
||||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||||
@mock.patch.object(objects.VnfInstance, "save")
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
def test_instantiate_vnf_infra_fails_to_wait_after_instantiate(
|
def test_instantiate_vnf_infra_fails_to_wait_after_instantiate(
|
||||||
self, mock_vnf_instance_save, mock_vnf_package_vnfd,
|
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_vnfd = fakes.return_vnf_package_vnfd()
|
||||||
vnf_package_id = vnf_package_vnfd.package_uuid
|
vnf_package_id = vnf_package_vnfd.package_uuid
|
||||||
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
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')
|
self._mock_vnf_manager(fail_method_name='create_wait')
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
error = self.assertRaises(exceptions.VnfInstantiationWaitFailed,
|
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)
|
instantiate_vnf_req_obj)
|
||||||
expected_error = ("Vnf instantiation wait failed for vnf %s, error: "
|
expected_error = ("Vnf instantiation wait failed for vnf %s, error: "
|
||||||
"create_wait failed")
|
"create_wait failed")
|
||||||
@ -294,14 +332,16 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
vnf_instance_obj.instantiation_state)
|
vnf_instance_obj.instantiation_state)
|
||||||
self.assertEqual(3, mock_vnf_instance_save.call_count)
|
self.assertEqual(3, mock_vnf_instance_save.call_count)
|
||||||
self.assertEqual(5, self._vnf_manager.invoke.call_count)
|
self.assertEqual(5, self._vnf_manager.invoke.call_count)
|
||||||
|
mock_final_vnf_dict.assert_called_once()
|
||||||
shutil.rmtree(fake_csar)
|
shutil.rmtree(fake_csar)
|
||||||
|
|
||||||
|
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
|
||||||
@mock.patch.object(objects.VnfResource, 'create')
|
@mock.patch.object(objects.VnfResource, 'create')
|
||||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||||
@mock.patch.object(objects.VnfInstance, "save")
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
def test_instantiate_vnf_with_short_notation(self, mock_vnf_instance_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_vnfd = fakes.return_vnf_package_vnfd()
|
||||||
vnf_package_id = vnf_package_vnfd.package_uuid
|
vnf_package_id = vnf_package_vnfd.package_uuid
|
||||||
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
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")
|
fake_csar, "sample_vnf_package_csar_with_short_notation")
|
||||||
self._mock_vnf_manager(vnf_resource_count=2)
|
self._mock_vnf_manager(vnf_resource_count=2)
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
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)
|
instantiate_vnf_req_obj)
|
||||||
self.assertEqual(2, mock_create.call_count)
|
self.assertEqual(2, mock_create.call_count)
|
||||||
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
|
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
|
||||||
|
mock_final_vnf_dict.assert_called_once()
|
||||||
shutil.rmtree(fake_csar)
|
shutil.rmtree(fake_csar)
|
||||||
|
|
||||||
|
@mock.patch('tacker.vnflcm.utils._make_final_vnf_dict')
|
||||||
@mock.patch.object(objects.VnfResource, 'create')
|
@mock.patch.object(objects.VnfResource, 'create')
|
||||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||||
@mock.patch.object(objects.VnfInstance, "save")
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
def test_instantiate_vnf_with_single_vnfd(self, mock_vnf_instance_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_vnfd = fakes.return_vnf_package_vnfd()
|
||||||
vnf_package_id = vnf_package_vnfd.package_uuid
|
vnf_package_id = vnf_package_vnfd.package_uuid
|
||||||
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
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")
|
fake_csar, "sample_vnfpkg_no_meta_single_vnfd")
|
||||||
self._mock_vnf_manager(vnf_resource_count=2)
|
self._mock_vnf_manager(vnf_resource_count=2)
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
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)
|
instantiate_vnf_req_obj)
|
||||||
self.assertEqual(2, mock_create.call_count)
|
self.assertEqual(2, mock_create.call_count)
|
||||||
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
|
self.assertEqual("INSTANTIATED", vnf_instance_obj.instantiation_state)
|
||||||
|
mock_final_vnf_dict.assert_called_once()
|
||||||
shutil.rmtree(fake_csar)
|
shutil.rmtree(fake_csar)
|
||||||
|
|
||||||
@mock.patch.object(objects.VnfInstance, "save")
|
@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(2, mock_vnf_instance_save.call_count)
|
||||||
self.assertEqual(3, self._vnf_manager.invoke.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(objects.VnfPackageVnfd, 'get_by_id')
|
||||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||||
@mock.patch.object(objects.VnfResource, "create")
|
@mock.patch.object(objects.VnfResource, "create")
|
||||||
@ -463,7 +508,8 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
||||||
def test_heal_vnf_without_vnfc_instance(self, mock_log, mock_save,
|
def test_heal_vnf_without_vnfc_instance(self, mock_log, mock_save,
|
||||||
mock_vnf_resource_list, mock_resource_destroy,
|
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_vnfd = fakes.return_vnf_package_vnfd()
|
||||||
vnf_package_id = vnf_package_vnfd.package_uuid
|
vnf_package_id = vnf_package_vnfd.package_uuid
|
||||||
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
||||||
@ -494,7 +540,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
uuidsentinel.instance_id
|
uuidsentinel.instance_id
|
||||||
self._mock_vnf_manager()
|
self._mock_vnf_manager()
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
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)
|
self.assertEqual(1, mock_save.call_count)
|
||||||
# vnf resource software images will be deleted during
|
# vnf resource software images will be deleted during
|
||||||
# deleting vnf instance.
|
# deleting vnf instance.
|
||||||
@ -509,7 +555,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
"is completed successfully")
|
"is completed successfully")
|
||||||
mock_log.info.assert_called_with(expected_msg,
|
mock_log.info.assert_called_with(expected_msg,
|
||||||
vnf_instance.id)
|
vnf_instance.id)
|
||||||
|
mock_final_vnf_dict.assert_called_once()
|
||||||
shutil.rmtree(fake_csar)
|
shutil.rmtree(fake_csar)
|
||||||
|
|
||||||
@mock.patch.object(objects.VnfInstance, "save")
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
@ -527,7 +573,8 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
self._mock_vnf_manager(fail_method_name='delete')
|
self._mock_vnf_manager(fail_method_name='delete')
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
self.assertRaises(exceptions.VnfHealFailed,
|
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, mock_save.call_count)
|
||||||
self.assertEqual(1, self._vnf_manager.invoke.call_count)
|
self.assertEqual(1, self._vnf_manager.invoke.call_count)
|
||||||
self.assertEqual(fields.VnfInstanceTaskState.ERROR,
|
self.assertEqual(fields.VnfInstanceTaskState.ERROR,
|
||||||
@ -537,6 +584,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
'state. Error: delete failed')
|
'state. Error: delete failed')
|
||||||
mock_log.error.assert_called_with(expected_msg % vnf_instance.id)
|
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(objects.VnfPackageVnfd, 'get_by_id')
|
||||||
@mock.patch.object(vim_client.VimClient, "get_vim")
|
@mock.patch.object(vim_client.VimClient, "get_vim")
|
||||||
@mock.patch.object(objects.VnfResource, "create")
|
@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,
|
def test_heal_vnf_without_vnfc_instance_infra_instantiate_vnf_fail(self,
|
||||||
mock_log, mock_save, mock_vnf_resource_list,
|
mock_log, mock_save, mock_vnf_resource_list,
|
||||||
mock_resource_destroy, mock_resource_create, mock_vim,
|
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_vnfd = fakes.return_vnf_package_vnfd()
|
||||||
vnf_package_id = vnf_package_vnfd.package_uuid
|
vnf_package_id = vnf_package_vnfd.package_uuid
|
||||||
mock_vnf_package_vnfd.return_value = vnf_package_vnfd
|
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')
|
self._mock_vnf_manager(fail_method_name='instantiate_vnf')
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
self.assertRaises(exceptions.VnfHealFailed,
|
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, mock_save.call_count)
|
||||||
# vnf resource software images will be deleted during
|
# vnf resource software images will be deleted during
|
||||||
# deleting vnf instance.
|
# deleting vnf instance.
|
||||||
@ -586,6 +635,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
'error: instantiate_vnf failed')
|
'error: instantiate_vnf failed')
|
||||||
mock_log.error.assert_called_with(expected_msg % (vnf_instance.id,
|
mock_log.error.assert_called_with(expected_msg % (vnf_instance.id,
|
||||||
vnf_instance.id))
|
vnf_instance.id))
|
||||||
|
mock_final_vnf_dict.assert_called_once()
|
||||||
|
|
||||||
@mock.patch.object(objects.VnfInstance, "save")
|
@mock.patch.object(objects.VnfInstance, "save")
|
||||||
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
@mock.patch('tacker.vnflcm.vnflcm_driver.LOG')
|
||||||
@ -599,7 +649,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
|
|
||||||
self._mock_vnf_manager()
|
self._mock_vnf_manager()
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
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(1, mock_save.call_count)
|
||||||
self.assertEqual(3, self._vnf_manager.invoke.call_count)
|
self.assertEqual(3, self._vnf_manager.invoke.call_count)
|
||||||
|
|
||||||
@ -623,7 +673,7 @@ class TestVnflcmDriver(db_base.SqlTestCase):
|
|||||||
driver = vnflcm_driver.VnfLcmDriver()
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
self.assertRaises(exceptions.VnfHealFailed,
|
self.assertRaises(exceptions.VnfHealFailed,
|
||||||
driver.heal_vnf, self.context, vnf_instance,
|
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, mock_save.call_count)
|
||||||
self.assertEqual(1, self._vnf_manager.invoke.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
|
# it will work and vnflcm can update the vnfc resources
|
||||||
# properly and hence the _vnf_manager.invoke.call_count
|
# properly and hence the _vnf_manager.invoke.call_count
|
||||||
# should be 3 instead of 2.
|
# 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(1, mock_save.call_count)
|
||||||
self.assertEqual(3, self._vnf_manager.invoke.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')
|
self._mock_vnf_manager(fail_method_name='post_heal_vnf')
|
||||||
driver = vnflcm_driver.VnfLcmDriver()
|
driver = vnflcm_driver.VnfLcmDriver()
|
||||||
self.assertRaises(exceptions.VnfHealFailed,
|
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(1, mock_save.call_count)
|
||||||
self.assertEqual(3, self._vnf_manager.invoke.call_count)
|
self.assertEqual(3, self._vnf_manager.invoke.call_count)
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ class TestVIMClient(base.TestCase):
|
|||||||
region_name='TestRegionOne')
|
region_name='TestRegionOne')
|
||||||
vim_expect = {'vim_auth': {'password': '****'}, 'vim_id': 'aaaa',
|
vim_expect = {'vim_auth': {'password': '****'}, 'vim_id': 'aaaa',
|
||||||
'vim_name': 'VIM0', 'vim_type': 'test_vim',
|
'vim_name': 'VIM0', 'vim_type': 'test_vim',
|
||||||
|
'placement_attr': {'regions': ['TestRegionOne']},
|
||||||
'tenant': 'test'}
|
'tenant': 'test'}
|
||||||
self.assertEqual(vim_expect, vim_result)
|
self.assertEqual(vim_expect, vim_result)
|
||||||
|
|
||||||
@ -89,6 +90,7 @@ class TestVIMClient(base.TestCase):
|
|||||||
region_name='TestRegionOne')
|
region_name='TestRegionOne')
|
||||||
vim_expect = {'vim_auth': {'password': '****'}, 'vim_id': 'aaaa',
|
vim_expect = {'vim_auth': {'password': '****'}, 'vim_id': 'aaaa',
|
||||||
'vim_name': 'aaaa', 'vim_type': 'test_vim',
|
'vim_name': 'aaaa', 'vim_type': 'test_vim',
|
||||||
|
'placement_attr': {'regions': ['TestRegionOne']},
|
||||||
'tenant': 'test'}
|
'tenant': 'test'}
|
||||||
self.assertEqual(vim_expect, vim_result)
|
self.assertEqual(vim_expect, vim_result)
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
@ -47,6 +48,16 @@ class TestController(base.TestCase):
|
|||||||
def app(self):
|
def app(self):
|
||||||
return fakes.wsgi_app_v1()
|
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, '_vnf_package_create')
|
||||||
@mock.patch.object(vnf_package.VnfPackage, '_from_db_object')
|
@mock.patch.object(vnf_package.VnfPackage, '_from_db_object')
|
||||||
def test_create_with_status_202(self, mock_from_db, mock_vnf_pack):
|
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(
|
req = fake_request.HTTPRequest.blank(
|
||||||
'/vnf_packages/%s/package_content'
|
'/vnf_packages/%s/package_content'
|
||||||
% constants.INVALID_UUID)
|
% constants.INVALID_UUID)
|
||||||
exception = self.assertRaises(exc.HTTPNotFound,
|
req.headers['Content-Type'] = 'application/zip'
|
||||||
self.controller.upload_vnf_package_content,
|
req.method = 'PUT'
|
||||||
req, constants.INVALID_UUID,
|
req.body = jsonutils.dump_as_bytes(mock.mock_open())
|
||||||
body=mock.mock_open())
|
|
||||||
self.assertEqual(
|
msg = _("Can not find requested vnf package: %s") \
|
||||||
"Can not find requested vnf package: %s" % constants.INVALID_UUID,
|
% constants.INVALID_UUID
|
||||||
exception.explanation)
|
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")
|
@mock.patch.object(vnf_package.VnfPackage, "get_by_id")
|
||||||
def test_upload_vnf_package_content_without_vnf_pack(self,
|
def test_upload_vnf_package_content_without_vnf_pack(self,
|
||||||
mock_vnf_by_id):
|
mock_vnf_by_id):
|
||||||
msg = _("Can not find requested vnf package: %s") % constants.UUID
|
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(
|
req = fake_request.HTTPRequest.blank(
|
||||||
'/vnf_packages/%s/package_content' % constants.UUID)
|
'/vnf_packages/%s/package_content' % constants.UUID)
|
||||||
exception = self.assertRaises(
|
req.headers['Content-Type'] = 'application/zip'
|
||||||
exc.HTTPNotFound, self.controller.upload_vnf_package_content,
|
req.method = 'PUT'
|
||||||
req, constants.UUID, body=mock.mock_open())
|
req.body = jsonutils.dump_as_bytes(mock.mock_open())
|
||||||
self.assertEqual(
|
|
||||||
"Can not find requested vnf package: %s" % constants.UUID,
|
msg = _("Can not find requested vnf package: %s") % constants.UUID
|
||||||
exception.explanation)
|
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")
|
@mock.patch.object(vnf_package.VnfPackage, "get_by_id")
|
||||||
def test_upload_vnf_package_content_with_invalid_status(self,
|
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
|
mock_vnf_by_id.return_value = vnf_obj
|
||||||
req = fake_request.HTTPRequest.blank(
|
req = fake_request.HTTPRequest.blank(
|
||||||
'/vnf_packages/%s/package_content' % constants.UUID)
|
'/vnf_packages/%s/package_content' % constants.UUID)
|
||||||
self.assertRaises(exc.HTTPConflict,
|
req.headers['Content-Type'] = 'application/zip'
|
||||||
self.controller.upload_vnf_package_content,
|
req.method = 'PUT'
|
||||||
req, constants.UUID, body=mock.mock_open())
|
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(urllib.request, 'urlopen')
|
||||||
@mock.patch.object(VNFPackageRPCAPI, "upload_vnf_package_from_uri")
|
@mock.patch.object(VNFPackageRPCAPI, "upload_vnf_package_from_uri")
|
||||||
|
@ -359,15 +359,25 @@ def _create_grant_request(vnfd_dict, package_uuid):
|
|||||||
return vnf_software_images
|
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):
|
||||||
return {'vnfd': {
|
if vnf_dict:
|
||||||
'attributes': {
|
final_vnf_dict = vnf_dict
|
||||||
'vnfd': str(vnfd_dict)}},
|
final_vnf_dict['vnfd']['attributes'].\
|
||||||
'id': id,
|
update({'vnfd': str(vnfd_dict)})
|
||||||
'name': name,
|
final_vnf_dict['attributes'].\
|
||||||
'attributes': {
|
update({'param_values': str(param_values)})
|
||||||
'param_values': str(param_values),
|
final_vnf_dict['attributes'].\
|
||||||
'stack_name': name or ("vnflcm_" + id)}}
|
update({'stack_name': name or ("vnflcm_" + id)})
|
||||||
|
return final_vnf_dict
|
||||||
|
else:
|
||||||
|
return {'vnfd': {
|
||||||
|
'attributes': {
|
||||||
|
'vnfd': str(vnfd_dict)}},
|
||||||
|
'id': id,
|
||||||
|
'name': name,
|
||||||
|
'attributes': {
|
||||||
|
'param_values': str(param_values),
|
||||||
|
'stack_name': name or ("vnflcm_" + id)}}
|
||||||
|
|
||||||
|
|
||||||
def _get_flavour_based_vnfd(csar_path, flavour_id):
|
def _get_flavour_based_vnfd(csar_path, flavour_id):
|
||||||
@ -517,6 +527,9 @@ def _build_instantiated_vnf_info(vnfd_dict, instantiate_vnf_req,
|
|||||||
inst_vnf_info.ext_managed_virtual_link_info = \
|
inst_vnf_info.ext_managed_virtual_link_info = \
|
||||||
_build_ext_managed_virtual_link_info(instantiate_vnf_req,
|
_build_ext_managed_virtual_link_info(instantiate_vnf_req,
|
||||||
inst_vnf_info)
|
inst_vnf_info)
|
||||||
|
|
||||||
|
inst_vnf_info.additional_params = instantiate_vnf_req.additional_params
|
||||||
|
|
||||||
vnf_instance.instantiated_vnf_info = inst_vnf_info
|
vnf_instance.instantiated_vnf_info = inst_vnf_info
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,8 +132,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
|
|||||||
setattr(vnf_instance, k, v)
|
setattr(vnf_instance, k, v)
|
||||||
vnf_instance.save()
|
vnf_instance.save()
|
||||||
|
|
||||||
def _instantiate_vnf(self, context, vnf_instance, vim_connection_info,
|
def _instantiate_vnf(self, context, vnf_instance, vnf_dict,
|
||||||
instantiate_vnf_req):
|
vim_connection_info, instantiate_vnf_req):
|
||||||
vnfd_dict = vnflcm_utils._get_vnfd_dict(context, vnf_instance.vnfd_id,
|
vnfd_dict = vnflcm_utils._get_vnfd_dict(context, vnf_instance.vnfd_id,
|
||||||
instantiate_vnf_req.flavour_id)
|
instantiate_vnf_req.flavour_id)
|
||||||
base_hot_dict = vnflcm_utils._get_base_hot_dict(
|
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)
|
vnfd_dict_to_create_final_dict = copy.deepcopy(vnfd_dict)
|
||||||
final_vnf_dict = vnflcm_utils._make_final_vnf_dict(
|
final_vnf_dict = vnflcm_utils._make_final_vnf_dict(
|
||||||
vnfd_dict_to_create_final_dict, vnf_instance.id,
|
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:
|
try:
|
||||||
instance_id = self._vnf_manager.invoke(
|
instance_id = self._vnf_manager.invoke(
|
||||||
@ -224,7 +224,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
|
|||||||
|
|
||||||
@log.log
|
@log.log
|
||||||
@rollback_vnf_instantiated_resources
|
@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.\
|
vim_connection_info_list = vnflcm_utils.\
|
||||||
_get_vim_connection_info_from_vnf_req(vnf_instance,
|
_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_connection_info = objects.VimConnectionInfo.obj_from_primitive(
|
||||||
vim_info, context)
|
vim_info, context)
|
||||||
|
|
||||||
self._instantiate_vnf(context, vnf_instance, vim_connection_info,
|
self._instantiate_vnf(context, vnf_instance, vnf_dict,
|
||||||
instantiate_vnf_req)
|
vim_connection_info, instantiate_vnf_req)
|
||||||
|
|
||||||
self._vnf_instance_update(context, vnf_instance,
|
self._vnf_instance_update(context, vnf_instance,
|
||||||
instantiation_state=fields.VnfInstanceState.INSTANTIATED,
|
instantiation_state=fields.VnfInstanceState.INSTANTIATED,
|
||||||
@ -363,8 +364,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
|
|||||||
raise exceptions.VnfHealFailed(id=vnf_instance.id,
|
raise exceptions.VnfHealFailed(id=vnf_instance.id,
|
||||||
error=encodeutils.exception_to_unicode(exp))
|
error=encodeutils.exception_to_unicode(exp))
|
||||||
|
|
||||||
def _respawn_vnf(self, context, vnf_instance, vim_connection_info,
|
def _respawn_vnf(self, context, vnf_instance, vnf_dict,
|
||||||
heal_vnf_request):
|
vim_connection_info, heal_vnf_request):
|
||||||
try:
|
try:
|
||||||
self._delete_vnf_instance_resources(context, vnf_instance,
|
self._delete_vnf_instance_resources(context, vnf_instance,
|
||||||
vim_connection_info, update_instantiated_state=False)
|
vim_connection_info, update_instantiated_state=False)
|
||||||
@ -388,8 +389,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
|
|||||||
from_vnf_instance(vnf_instance)
|
from_vnf_instance(vnf_instance)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._instantiate_vnf(context, vnf_instance, vim_connection_info,
|
self._instantiate_vnf(context, vnf_instance, vnf_dict,
|
||||||
instantiate_vnf_request)
|
vim_connection_info, instantiate_vnf_request)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
with excutils.save_and_reraise_exception() as exc_ctxt:
|
with excutils.save_and_reraise_exception() as exc_ctxt:
|
||||||
exc_ctxt.reraise = False
|
exc_ctxt.reraise = False
|
||||||
@ -407,7 +408,7 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
|
|||||||
|
|
||||||
@log.log
|
@log.log
|
||||||
@revert_to_error_task_state
|
@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)
|
LOG.info("Request received for healing vnf '%s'", vnf_instance.id)
|
||||||
vim_info = vnflcm_utils._get_vim(context,
|
vim_info = vnflcm_utils._get_vim(context,
|
||||||
vnf_instance.vim_connection_info)
|
vnf_instance.vim_connection_info)
|
||||||
@ -416,8 +417,8 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
|
|||||||
vim_info, context)
|
vim_info, context)
|
||||||
|
|
||||||
if not heal_vnf_request.vnfc_instance_id:
|
if not heal_vnf_request.vnfc_instance_id:
|
||||||
self._respawn_vnf(context, vnf_instance, vim_connection_info,
|
self._respawn_vnf(context, vnf_instance, vnf_dict,
|
||||||
heal_vnf_request)
|
vim_connection_info, heal_vnf_request)
|
||||||
else:
|
else:
|
||||||
self._heal_vnf(context, vnf_instance, vim_connection_info,
|
self._heal_vnf(context, vnf_instance, vim_connection_info,
|
||||||
heal_vnf_request)
|
heal_vnf_request)
|
||||||
|
@ -64,7 +64,8 @@ class VimClient(object):
|
|||||||
vim_res = {'vim_auth': vim_auth, 'vim_id': vim_info['id'],
|
vim_res = {'vim_auth': vim_auth, 'vim_id': vim_info['id'],
|
||||||
'vim_name': vim_info.get('name', vim_info['id']),
|
'vim_name': vim_info.get('name', vim_info['id']),
|
||||||
'vim_type': vim_info['type'],
|
'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
|
return vim_res
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
Loading…
Reference in New Issue
Block a user