Implement rpc conductor for vnf packages
Added new RPC APIs for uploading and deleting vnf packages. Partial-Implements: blueprint tosca-csar-mgmt-driver Co-Author: Neha Alhat <neha.alhat@nttdata.com> Change-Id: Ia5051f3c1bf2ce5f45c94711a67be5f9a8ef21d0
This commit is contained in:
parent
34b661ad08
commit
a95ffbc668
|
@ -0,0 +1,63 @@
|
|||
# Copyright (C) 2019 NTT DATA
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# 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 oslo_messaging
|
||||
|
||||
from tacker.common import rpc
|
||||
from tacker.common import topics
|
||||
from tacker.objects import base as objects_base
|
||||
|
||||
|
||||
class VNFPackageRPCAPI(object):
|
||||
|
||||
target = oslo_messaging.Target(
|
||||
exchange='tacker',
|
||||
topic=topics.TOPIC_CONDUCTOR,
|
||||
fanout=False,
|
||||
version='1.0')
|
||||
|
||||
def upload_vnf_package_content(self, context, vnf_package, cast=True):
|
||||
serializer = objects_base.TackerObjectSerializer()
|
||||
|
||||
client = rpc.get_client(self.target, version_cap=None,
|
||||
serializer=serializer)
|
||||
cctxt = client.prepare()
|
||||
rpc_method = cctxt.cast if cast else cctxt.call
|
||||
return rpc_method(context, 'upload_vnf_package_content',
|
||||
vnf_package=vnf_package)
|
||||
|
||||
def upload_vnf_package_from_uri(self, context, vnf_package,
|
||||
address_information, user_name=None,
|
||||
password=None, cast=True):
|
||||
serializer = objects_base.TackerObjectSerializer()
|
||||
|
||||
client = rpc.get_client(self.target, version_cap=None,
|
||||
serializer=serializer)
|
||||
cctxt = client.prepare()
|
||||
rpc_method = cctxt.cast if cast else cctxt.call
|
||||
return rpc_method(context, 'upload_vnf_package_from_uri',
|
||||
vnf_package=vnf_package,
|
||||
address_information=address_information,
|
||||
user_name=user_name, password=password)
|
||||
|
||||
def delete_vnf_package(self, context, vnf_package, cast=True):
|
||||
serializer = objects_base.TackerObjectSerializer()
|
||||
|
||||
client = rpc.get_client(self.target, version_cap=None,
|
||||
serializer=serializer)
|
||||
cctxt = client.prepare()
|
||||
rpc_method = cctxt.cast if cast else cctxt.call
|
||||
return rpc_method(context, 'delete_vnf_package',
|
||||
vnf_package=vnf_package)
|
|
@ -14,8 +14,10 @@
|
|||
|
||||
import datetime
|
||||
|
||||
import oslo_messaging as messaging
|
||||
from oslo_utils import versionutils
|
||||
from oslo_versionedobjects import base as ovoo_base
|
||||
from oslo_versionedobjects import exception as ovoo_exc
|
||||
|
||||
from tacker import objects
|
||||
from tacker.objects import fields as obj_fields
|
||||
|
@ -117,6 +119,63 @@ class TackerObject(ovoo_base.VersionedObject):
|
|||
self._changed_fields.clear()
|
||||
|
||||
|
||||
class TackerObjectSerializer(messaging.NoOpSerializer):
|
||||
"""A TackerObject-aware Serializer.
|
||||
|
||||
This implements the Oslo Serializer interface and provides the
|
||||
ability to serialize and deserialize TackerObject entities. Any service
|
||||
that needs to accept or return TackerObjects as arguments or result values
|
||||
should pass this to its RPCClient and RPCServer objects.
|
||||
"""
|
||||
|
||||
def _process_object(self, context, objprim):
|
||||
try:
|
||||
objinst = TackerObject.obj_from_primitive(objprim, context=context)
|
||||
except ovoo_exc.IncompatibleObjectVersion:
|
||||
raise
|
||||
return objinst
|
||||
|
||||
def _process_iterable(self, context, action_fn, values):
|
||||
"""Process an iterable, taking an action on each value.
|
||||
|
||||
:param:context: Request context
|
||||
:param:action_fn: Action to take on each item in values
|
||||
:param:values: Iterable container of things to take action on
|
||||
:returns: A new container of the same type (except set) with
|
||||
items from values having had action applied.
|
||||
"""
|
||||
iterable = values.__class__
|
||||
if issubclass(iterable, dict):
|
||||
return iterable(**{k: action_fn(context, v)
|
||||
for k, v in values.items()})
|
||||
else:
|
||||
# NOTE(nirajsingh) A set can't have an unhashable value inside,
|
||||
# such as a dict. Convert the set to list, which is fine, since we
|
||||
# can't send them over RPC anyway. We convert it to list as this
|
||||
# way there will be no semantic change between the fake rpc driver
|
||||
# used in functional test and a normal rpc driver.
|
||||
if iterable == set:
|
||||
iterable = list
|
||||
return iterable([action_fn(context, value) for value in values])
|
||||
|
||||
def serialize_entity(self, context, entity):
|
||||
if isinstance(entity, (tuple, list, set, dict)):
|
||||
entity = self._process_iterable(context, self.serialize_entity,
|
||||
entity)
|
||||
elif (hasattr(entity, 'obj_to_primitive') and
|
||||
callable(entity.obj_to_primitive)):
|
||||
entity = entity.obj_to_primitive()
|
||||
return entity
|
||||
|
||||
def deserialize_entity(self, context, entity):
|
||||
if isinstance(entity, dict) and 'tacker_object.name' in entity:
|
||||
entity = self._process_object(context, entity)
|
||||
elif isinstance(entity, (tuple, list, set, dict)):
|
||||
entity = self._process_iterable(context, self.deserialize_entity,
|
||||
entity)
|
||||
return entity
|
||||
|
||||
|
||||
class TackerPersistentObject(object):
|
||||
"""Mixin class for Persistent objects.
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
# Copyright (C) 2019 NTT DATA
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# 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 mock
|
||||
|
||||
from tacker.common.rpc import BackingOffClient
|
||||
from tacker.conductor.conductorrpc import vnf_pkgm_rpc
|
||||
from tacker.objects import vnf_package
|
||||
from tacker.tests import base
|
||||
from tacker.tests.unit.conductor import fakes
|
||||
|
||||
|
||||
class VnfPackageRPCTestCase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(VnfPackageRPCTestCase, self).setUp()
|
||||
self.context = self.fake_admin_context()
|
||||
self.rpc_api = vnf_pkgm_rpc.VNFPackageRPCAPI()
|
||||
self.cctxt_mock = mock.MagicMock()
|
||||
|
||||
def test_upload_vnf_package_content(self):
|
||||
|
||||
@mock.patch.object(BackingOffClient, 'prepare')
|
||||
def _test(prepare_mock):
|
||||
prepare_mock.return_value = self.cctxt_mock
|
||||
vnf_package_obj = vnf_package.VnfPackage(
|
||||
self.context, **fakes.VNF_UPLOAD_VNF_PACKAGE_CONTENT)
|
||||
self.rpc_api.upload_vnf_package_content(self.context,
|
||||
vnf_package_obj, cast=True)
|
||||
prepare_mock.assert_called()
|
||||
self.cctxt_mock.cast.assert_called_once_with(
|
||||
self.context, 'upload_vnf_package_content',
|
||||
vnf_package=vnf_package_obj)
|
||||
_test()
|
||||
|
||||
def test_upload_vnf_package_from_uri(self):
|
||||
fake_addressInformation = "http://test_csar.zip"
|
||||
|
||||
@mock.patch.object(BackingOffClient, 'prepare')
|
||||
def _test(prepare_mock):
|
||||
prepare_mock.return_value = self.cctxt_mock
|
||||
vnf_package_obj = vnf_package.VnfPackage(self.context,
|
||||
**fakes.VNF_DATA)
|
||||
self.rpc_api.upload_vnf_package_from_uri(self.context,
|
||||
vnf_package_obj,
|
||||
fake_addressInformation,
|
||||
cast=True)
|
||||
prepare_mock.assert_called()
|
||||
self.cctxt_mock.cast.assert_called_once_with(
|
||||
self.context, 'upload_vnf_package_from_uri',
|
||||
vnf_package=vnf_package_obj,
|
||||
address_information=fake_addressInformation,
|
||||
password=None, user_name=None)
|
||||
_test()
|
||||
|
||||
def test_delete_vnf_package(self):
|
||||
|
||||
@mock.patch.object(BackingOffClient, 'prepare')
|
||||
def _test(prepare_mock):
|
||||
prepare_mock.return_value = self.cctxt_mock
|
||||
vnf_package_obj = vnf_package.VnfPackage(self.context,
|
||||
**fakes.VNF_DATA)
|
||||
self.rpc_api.delete_vnf_package(self.context,
|
||||
vnf_package_obj, cast=True)
|
||||
prepare_mock.assert_called()
|
||||
self.cctxt_mock.cast.assert_called_once_with(
|
||||
self.context, 'delete_vnf_package',
|
||||
vnf_package=vnf_package_obj)
|
||||
_test()
|
|
@ -0,0 +1,42 @@
|
|||
# Copyright (C) 2019 NTT DATA
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# 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 tacker.tests import uuidsentinel
|
||||
|
||||
|
||||
VNF_UPLOAD_VNF_PACKAGE_CONTENT = {
|
||||
'algorithm': 'sha512', 'created_at': '2019-08-16T06:57:09Z',
|
||||
'deleted': False, 'deleted_at': None,
|
||||
'hash': 'ce48b8ba15bfb060fb70471cf955bef433e4513973b4bac42b37c36f57357dc35'
|
||||
'bf788c16545d3a59781914adf19fca26d6984583b7739e55c447383d774356a',
|
||||
'id': uuidsentinel.tenant_id,
|
||||
'location_glance_store': 'file:///var/lib/glance/images/'
|
||||
'd617ea52-b16b-417e-a68c-08dfb69aab9e',
|
||||
'onboarding_state': 'PROCESSING', 'operational_state': 'DISABLED',
|
||||
'tenant_id': uuidsentinel.tenant_id,
|
||||
'updated_at': '2019-08-16T06:57:30Z',
|
||||
'usage_state': 'NOT_IN_USE', 'user_data': {'abc': 'xyz'}}
|
||||
|
||||
VNF_DATA = {
|
||||
'created_at': '2019-08-16T06:57:09Z',
|
||||
'deleted': False, 'deleted_at': None,
|
||||
'id': uuidsentinel.id,
|
||||
'onboarding_state': 'UPLOADING',
|
||||
'operational_state': 'DISABLED',
|
||||
'tenant_id': uuidsentinel.tenant_id,
|
||||
'updated_at': '2019-08-16T06:57:30Z',
|
||||
'usage_state': 'NOT_IN_USE',
|
||||
'user_data': {'abc': 'xyz'}
|
||||
}
|
Loading…
Reference in New Issue