Add VNF resource details to get vnf API

Adds physical id and type of VDUs, CPs and VLs of a VNF to
get vnf API.

APIImpact
Change-Id: I469b91c1a000e7a47ae1d4313ed83de26e1391b2
Partial-Bug: #1602112
This commit is contained in:
Janki Chhatbar 2016-07-12 09:55:54 +05:30 committed by Janki
parent c7d279df84
commit 2e766e122b
8 changed files with 144 additions and 0 deletions

View File

@ -0,0 +1,3 @@
---
features:
- Added API to fetch VNF components details.

View File

@ -140,6 +140,15 @@ class FilePathMissing(exceptions.InvalidInput):
"tosca.artifacts.Deployment.Image.VM artifact type")
class InfraDriverUnreachable(exceptions.ServiceUnavailable):
message = _("Could not retrieve VNF resource IDs and"
" types. Please check %(service)s status.")
class VNFInactive(exceptions.InvalidInput):
message = _("VNF %(vnf_id)s is not in Active state %(message)s")
def _validate_service_type_list(data, valid_values=None):
if not isinstance(data, list):
msg = _("invalid data format for service list: '%s'") % data
@ -358,6 +367,33 @@ SUB_RESOURCE_ATTRIBUTE_MAP = {
}
}
}
},
'resources': {
'parent': {
'collection_name': 'vnfs',
'member_name': 'vnf'
},
'members': {
'resource': {
'parameters': {
'name': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
'type': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
'id': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
}
}
}
}
}
@ -464,6 +500,10 @@ class VNFMPluginBase(service_base.NFVPluginBase):
def get_vnf(self, context, vnf_id, fields=None):
pass
@abc.abstractmethod
def get_vnf_resources(self, context, vnf_id, fields=None, filters=None):
pass
@abc.abstractmethod
def create_vnf(self, context, vnf):
pass

View File

@ -53,6 +53,12 @@ class VnfTestCreate(base.BaseTackerTest):
if vim_id:
self.assertEqual(vim_id, vnf_instance['vnf']['vim_id'])
# Get vnf details when vnf is in active state
vnf_details = self.client.list_vnf_resources(vnf_id)['resources'][0]
self.assertIn('name', vnf_details)
self.assertIn('id', vnf_details)
self.assertIn('type', vnf_details)
# Delete vnf_instance with vnf_id
try:
self.client.delete_vnf(vnf_id)

View File

@ -20,6 +20,7 @@ import os
import yaml
from tacker import context
from tacker.extensions import vnfm
from tacker.tests.unit import base
from tacker.tests.unit.db import utils
from tacker.vnfm.infra_drivers.heat import heat
@ -143,6 +144,28 @@ class TestDeviceHeat(base.TestCase):
'id': 'eb84260e-5ff7-4332-b032-50a14d6c1123', 'description':
u'OpenWRT with services'}
def _get_expected_active_vnf(self):
return {'status': 'ACTIVE',
'instance_id': None,
'name': u'test_openwrt',
'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437',
'vnfd_id': u'eb094833-995e-49f0-a047-dfb56aaf7c4e',
'vnfd': {
'service_types': [{
'service_type': u'vnfd',
'id': u'4a4c2d44-8a52-4895-9a75-9d1c76c3e738'}],
'description': u'OpenWRT with services',
'tenant_id': u'ad7ebc56538745a08ef7c5e97f8bd437',
'mgmt_driver': u'openwrt',
'infra_driver': u'heat',
'attributes': {u'vnfd': self.vnfd_openwrt},
'id': u'fb048660-dc1b-4f0f-bd89-b023666650ec',
'name': u'openwrt_services'},
'mgmt_url': '{"vdu1": "192.168.120.31"}',
'service_context': [],
'id': 'eb84260e-5ff7-4332-b032-50a14d6c1123',
'description': u'OpenWRT with services'}
def test_create(self):
vnf_obj = utils.get_dummy_device_obj()
expected_result = '4a4c2d44-8a52-4895-9a75-9d1c76c3e738'
@ -408,3 +431,12 @@ class TestDeviceHeat(base.TestCase):
files={'scaling.yaml': 'hot_scale_custom.yaml'},
is_monitor=False
)
def test_get_resource_info(self):
vnf_obj = self._get_expected_active_vnf()
print(vnf_obj)
self.assertRaises(vnfm.InfraDriverUnreachable,
self.heat_driver.get_resource_info,
plugin=None, context=self.context, vnf_info=vnf_obj,
auth_attr=utils.get_vim_auth_obj(),
region_name=None)

View File

@ -32,6 +32,10 @@ class FakeDriverManager(mock.Mock):
def invoke(self, *args, **kwargs):
if 'create' in args:
return str(uuid.uuid4())
if 'get_resource_info' in args:
return {'resources': {'name': 'dummy_vnf',
'type': 'dummy',
'id': str(uuid.uuid4())}}
class FakeVNFMonitor(mock.Mock):
@ -208,6 +212,22 @@ class TestVNFMPlugin(db_base.SqlTestCase):
res_state=mock.ANY, res_type=constants.RES_TYPE_VNF,
tstamp=mock.ANY, details=mock.ANY)
def test_show_vnf_details_vnf_inactive(self):
self._insert_dummy_device_template()
vnf_obj = utils.get_dummy_vnf_obj()
result = self.vnfm_plugin.create_vnf(self.context, vnf_obj)
self.assertRaises(vnfm.VNFInactive, self.vnfm_plugin.get_vnf_resources,
self.context, result['id'])
def test_show_vnf_details_vnf_active(self):
self._insert_dummy_device_template()
active_vnf = self._insert_dummy_device()
resources = self.vnfm_plugin.get_vnf_resources(self.context,
active_vnf['id'])[0]
self.assertIn('name', resources)
self.assertIn('type', resources)
self.assertIn('id', resources)
def test_delete_vnf(self):
self._insert_dummy_device_template()
dummy_device_obj = self._insert_dummy_device()

View File

@ -629,3 +629,24 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
self._handle_vnf_scaling(context, policy_)
return scale['scale']
def get_vnf_resources(self, context, vnf_id, fields=None, filters=None):
vnf_info = self.get_vnf(context, vnf_id)
infra_driver = vnf_info['vnfd']['infra_driver']
auth = self.get_vim(context, vnf_info)
if vnf_info['status'] == constants.ACTIVE:
vnf_details = self._vnf_manager.invoke(infra_driver,
'get_resource_info',
plugin=self,
context=context,
vnf_info=vnf_info,
auth_attr=auth)
resources = [{'name': name,
'type': info.get('type'),
'id': info.get('id')}
for name, info in vnf_details.items()]
return resources
# Raise exception when VNF.status != ACTIVE
else:
raise vnfm.VNFInactive(vnf_id=vnf_id,
message=_(' Cannot fetch details'))

View File

@ -68,3 +68,9 @@ class DeviceAbstractDriver(extensions.PluginInterface):
@abc.abstractmethod
def delete_wait(self, plugin, context, vnf_id):
pass
@abc.abstractmethod
def get_resource_info(self, plugin, context, vnf_info, auth_attr,
region_name=None):
'''Fetches optional details of a VNF'''
pass

View File

@ -854,6 +854,21 @@ class DeviceHeat(abstract_driver.DeviceAbstractDriver,
return jsonutils.dumps(mgmt_ips)
def get_resource_info(self, plugin, context, vnf_info, auth_attr,
region_name=None):
stack_id = vnf_info['instance_id']
heatclient_ = HeatClient(auth_attr, region_name)
try:
resources_ids = heatclient_.resource_get_list(stack_id)
details_dict = {resource.resource_name:
{"id": resource.physical_resource_id,
"type": resource.resource_type}
for resource in resources_ids}
return details_dict
# Raise exception when Heat API service is not available
except Exception:
raise vnfm.InfraDriverUnreachable(service="Heat API service")
class HeatClient(object):
def __init__(self, auth_attr, region_name=None):
@ -861,6 +876,7 @@ class HeatClient(object):
self.heat = clients.OpenstackClients(auth_attr, region_name).heat
self.stacks = self.heat.stacks
self.resource_types = self.heat.resource_types
self.resources = self.heat.resources
def create(self, fields):
fields = fields.copy()