Implementation of Tacker NFV MANO API

Introduce new Tacker REST API endpoints 'vnfd' and 'vnf' based on NFV
MANO in 'vnfm' extension. Existing 'device' and'device_template'
endpoints will be retained for backward compatibility.

Change-Id: I9dffd4bee25b1f49aea7478f2bd779cf0f6dfb49
Implements: blueprint tacker-api-mano
This commit is contained in:
Sripriya 2015-08-11 13:00:01 -07:00
parent 2c4e277b9d
commit f8bc9cc05c
19 changed files with 814 additions and 202 deletions

View File

@ -1,4 +1,4 @@
[DEFAULT] [DEFAULT]
test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_LOG_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./tacker/tests/unit} $LISTOPT $IDOPTION test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_LOG_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./tacker/tests/unit/vm} $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE test_id_option=--load-list $IDFILE
test_list_option=--list test_list_option=--list

View File

@ -0,0 +1,279 @@
************************
Tacker MANO API Overview
************************
Tacker MANO API introduces new REST API end-points based on ETSI NFV MANO
standards [1]. The two new resources introduced are 'vnfd' and 'vnf' for
describing the 'vnfm' extension. The resources request and response formats are
described in below sections.
API versions
============
Lists information for Tacker API version.
**GET /**
List API versions - Lists information about all Networking API versions.
::
Response:
{
"versions": [
{
"status": "CURRENT",
"id": "v1.0",
"links": [
{
"href": "http://10.18.160.13:8888/v1.0",
"rel": "self"
}
]
}
]
}
Vnfds
=====
**GET /v1.0/vnfds**
List vnfds - List vnfds stored in the VNF catalog.
::
Response:
{
"vnfds": [
{
"service_types": [
{
"service_type": "vnfd",
"id": "378b774d-89f5-4634-9c65-9c49ed6f00ce"
}
],
"description": "OpenWRT with services",
"tenant_id": "4dd6c1d7b6c94af980ca886495bcfed0",
"mgmt_driver": "openwrt",
"infra_driver": "heat",
"attributes": {
"vnfd": "template_name: OpenWRT\r\ndescription:
template_description <sample_vnfd_template>"
},
"id": "247b045e-d64f-4ae0-a3b4-8441b9e5892c",
"name": "openwrt_services"
}
]
}
**GET /v1.0/vnfds/{vnfd_id}**
Show vnfd - Show information for a specified vnfd id.
::
Response:
{
"vnfd": {
"service_types": [
{
"service_type": "vnfd",
"id": "378b774d-89f5-4634-9c65-9c49ed6f00ce"
}
],
"description": "OpenWRT with services",
"tenant_id": "4dd6c1d7b6c94af980ca886495bcfed0",
"mgmt_driver": "openwrt",
"infra_driver": "heat",
"attributes": {
"vnfd": "template_name: OpenWRT\r\ndescription:
template_description <sample_vnfd_template>"
},
"id": "247b045e-d64f-4ae0-a3b4-8441b9e5892c",
"name": "openwrt_services"
}
}
**POST /v1.0/vnfds**
Create vnfd - Create a vnfd entry based on the vnfd template.
::
Request:
{"auth": {"tenantName": "admin", "passwordCredentials": {"username": "admin",
"password": "devstack"}}, "vnfd": {"attributes": {"vnfd": "template_name:
OpenWRT \r\ndescription: OpenWRT router\r\n\r\nservice_properties:\r\n Id:
sample-vnfd\r\n vendor: tacker\r\n version: 1\r\n\r\nvdus:\r\n vdu1:\r\n
id: vdu1\r\n vm_image: cirros-0.3.2-x86_64-uec\r\n instance_type:
m1.tiny\r\n\r\n network_interfaces:\r\n management:\r\n network:
net_mgmt\r\n management: true\r\n pkt_in:\r\n network:
net0\r\n pkt_out:\r\n network: net1\r\n\r\n placement_policy:
\r\n availability_zone: nova\r\n\r\n auto-scaling: noop\r\n
monitoring_policy: noop\r\n failure_policy: noop\r\n\r\n config:\r\n
param0: key0\r\n param1: key1"}, "service_types": [{"service_type":
"vnfd"}], "mgmt_driver": "noop", "infra_driver": "heat"}}
::
Response:
{
"vnfd": {
"service_types": [
{
"service_type": "vnfd",
"id": "336fe422-9fba-47c7-87fb-d48475c3e0ce"
}
],
"description": "OpenWRT router",
"tenant_id": "4dd6c1d7b6c94af980ca886495bcfed0",
"mgmt_driver": "noop",
"infra_driver": "heat",
"attributes": {
"vnfd": "template_name: OpenWRT \r\ndescription:
template_description <sample_vnfd_template>"
},
"id": "ab10a543-22ee-43af-a441-05a9d32a57da",
"name": "OpenWRT"
}
}
**DELETE /v1.0/vnfds/{vnfd_id}**
Delete vnfd - Deletes a specified vnfd_id from the VNF catalog.
This operation does not accept a request body and does not return a response
body.
Vnfs
====
**GET /v1.0/vnfs**
List vnfs - Lists instantiated vnfs in VNF Manager
::
Response:
{
"vnfs": [
{
"status": "ACTIVE",
"name": "open_wrt",
"tenant_id": "4dd6c1d7b6c94af980ca886495bcfed0",
"instance_id": "f7c93726-fb8d-4036-8349-2e82f196e8f6",
"mgmt_url": "{\"vdu1\": \"192.168.120.3\"}",
"attributes": {
"service_type": "firewall",
"param_values": "",
"heat_template": "description: sample_template_description
type: OS::Nova::Server\n",
"monitoring_policy": "noop",
"failure_policy": "noop"
},
"id": "c9b4f5a5-d304-473a-a57e-b665b1f9eb8f",
"description": "OpenWRT with services"
}
]
}
**GET /v1.0/vnfs/{vnf_id}**
Show vnf - Show information for a specified vnf_id.
::
Response:
{
"vnf": [
{
"status": "ACTIVE",
"name": "open_wrt",
"tenant_id": "4dd6c1d7b6c94af980ca886495bcfed0",
"instance_id": "f7c93726-fb8d-4036-8349-2e82f196e8f6",
"mgmt_url": "{\"vdu1\": \"192.168.120.3\"}",
"attributes": {
"service_type": "firewall",
"param_values": "",
"heat_template": "description: OpenWRT with services\n
sample_template_description type: OS::Nova::Server\n",
"monitoring_policy": "noop", "failure_policy": "noop"
},
"id": "c9b4f5a5-d304-473a-a57e-b665b1f9eb8f",
"description": "OpenWRT with services"
}
]
}
**POST /v1.0/vnfs**
Create vnf - Create a vnf based on the vnfd template id.
::
Request:
{"auth": {"tenantName": "admin", "passwordCredentials": {"username": "admin",
"password": "devstack"}}, "vnf":
{"vnfd_id": "d770ddd7-6014-4191-92d8-a2cd7a6cecd8"}}
::
Response:
{
"vnf": {
"status": "PENDING_CREATE",
"name": "",
"tenant_id": "4dd6c1d7b6c94af980ca886495bcfed0",
"description": "OpenWRT with services",
"instance_id": "4f0d6222-afa0-4f02-8e19-69e7e4fd7edc",
"mgmt_url": null,
"attributes": {
"service_type": "firewall",
"heat_template": "description: OpenWRT with services\n
<sample_heat_template> type: OS::Nova::Server\n",
"monitoring_policy": "noop",
"failure_policy": "noop"
},
"id": "e3158513-92f4-4587-b949-70ad0bcbb2dd",
"vnfd_id": "247b045e-d64f-4ae0-a3b4-8441b9e5892c"
}
}
**PUT /v1.0/vnfs/{vnf_id}**
Update vnf - Update a vnf based on user config file or data.
::
Request:
{"auth": {"tenantName": "admin", "passwordCredentials": {"username": "admin",
"password": "devstack"}}, "vnf": {"attributes": {"config": "vdus:\n vdu1:
<sample_vdu_config> \n\n"}}}
::
Response:
{
"vnf": {
"status": "PENDING_UPDATE",
"name": "",
"tenant_id": "4dd6c1d7b6c94af980ca886495bcfed0",
"instance_id": "4f0d6222-afa0-4f02-8e19-69e7e4fd7edc",
"mgmt_url": "{\"vdu1\": \"192.168.120.4\"}",
"attributes": {
"service_type": "firewall",
"monitoring_policy": "noop",
"config": "vdus:\n vdu1:\n config: {<sample_vdu_config>
type: OS::Nova::Server\n",
"failure_policy": "noop"
},
"id": "e3158513-92f4-4587-b949-70ad0bcbb2dd",
"description": "OpenWRT with services"
}
}
**DELETE /v1.0/vnfs/{vnf_id}**
Delete vnf - Deletes a specified vnf_id from the VNF list.

View File

@ -61,7 +61,7 @@ lock_path = $state_path/lock
# #
# service_plugins = # service_plugins =
# Example: service_plugins = router,firewall,lbaas,vpnaas,metering # Example: service_plugins = router,firewall,lbaas,vpnaas,metering
service_plugins = tacker.vm.plugin.ServiceVMPlugin service_plugins = tacker.vm.plugin.VNFMPlugin
# Paste configuration file # Paste configuration file
# api_paste_config = api-paste.ini # api_paste_config = api-paste.ini

View File

@ -18,6 +18,7 @@ netaddr>=0.7.12
#python-tackerclient>=2.3.4,<3 #python-tackerclient>=2.3.4,<3
SQLAlchemy<1.1.0,>=0.9.7 SQLAlchemy<1.1.0,>=0.9.7
WebOb>=1.2.3 WebOb>=1.2.3
python-heatclient>=0.3.0
python-keystoneclient>=1.1.0 python-keystoneclient>=1.1.0
alembic>=0.7.2 alembic>=0.7.2
six>=1.9.0 six>=1.9.0

View File

@ -43,7 +43,7 @@ console_scripts =
tacker-rootwrap = oslo.rootwrap.cmd:main tacker-rootwrap = oslo.rootwrap.cmd:main
tacker.service_plugins = tacker.service_plugins =
dummy = tacker.tests.unit.dummy_plugin:DummyServicePlugin dummy = tacker.tests.unit.dummy_plugin:DummyServicePlugin
servicevm = tacker.vm.plugin.ServiceVMPlugin vnfm = tacker.vm.plugin:VNFMPlugin
tacker.openstack.common.cache.backends = tacker.openstack.common.cache.backends =
memory = tacker.openstack.common.cache._backends.memory:MemoryBackend memory = tacker.openstack.common.cache._backends.memory:MemoryBackend
tacker.servicevm.device.drivers = tacker.servicevm.device.drivers =

View File

@ -40,6 +40,8 @@ core_opts = [
help=_("The API paste config file to use")), help=_("The API paste config file to use")),
cfg.StrOpt('api_extensions_path', default="", cfg.StrOpt('api_extensions_path', default="",
help=_("The path for API extensions")), help=_("The path for API extensions")),
cfg.ListOpt('service_plugins', default=[],
help=_("The service plugins Tacker will use")),
cfg.StrOpt('policy_file', default="policy.json", cfg.StrOpt('policy_file', default="policy.json",
help=_("The policy file to use")), help=_("The policy file to use")),
cfg.StrOpt('auth_strategy', default='keystone', cfg.StrOpt('auth_strategy', default='keystone',

View File

@ -32,7 +32,7 @@ from tacker.db import api as qdbapi
from tacker.db import db_base from tacker.db import db_base
from tacker.db import model_base from tacker.db import model_base
from tacker.db import models_v1 from tacker.db import models_v1
from tacker.extensions import servicevm from tacker.extensions import vnfm
from tacker import manager from tacker import manager
from tacker.openstack.common import log as logging from tacker.openstack.common import log as logging
from tacker.openstack.common import uuidutils from tacker.openstack.common import uuidutils
@ -265,8 +265,7 @@ class ServiceContextEntry(dict):
}) })
class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase, class VNFMPluginDb(vnfm.VNFMPluginBase, db_base.CommonDbMixin):
db_base.CommonDbMixin):
@property @property
def _core_plugin(self): def _core_plugin(self):
@ -278,20 +277,20 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
def __init__(self): def __init__(self):
qdbapi.register_models() qdbapi.register_models()
super(ServiceResourcePluginDb, self).__init__() super(VNFMPluginDb, self).__init__()
def _get_resource(self, context, model, id): def _get_resource(self, context, model, id):
try: try:
return self._get_by_id(context, model, id) return self._get_by_id(context, model, id)
except orm_exc.NoResultFound: except orm_exc.NoResultFound:
if issubclass(model, DeviceTemplate): if issubclass(model, DeviceTemplate):
raise servicevm.DeviceTemplateNotFound(device_tempalte_id=id) raise vnfm.DeviceTemplateNotFound(device_tempalte_id=id)
elif issubclass(model, ServiceType): elif issubclass(model, ServiceType):
raise servicevm.ServiceTypeNotFound(service_type_id=id) raise vnfm.ServiceTypeNotFound(service_type_id=id)
elif issubclass(model, ServiceInstance): elif issubclass(model, ServiceInstance):
raise servicevm.ServiceInstanceNotFound(service_instance_id=id) raise vnfm.ServiceInstanceNotFound(service_instance_id=id)
if issubclass(model, Device): if issubclass(model, Device):
raise servicevm.DeviceNotFound(device_id=id) raise vnfm.DeviceNotFound(device_id=id)
else: else:
raise raise
@ -390,13 +389,13 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
if (not attributes.is_attr_set(infra_driver)): if (not attributes.is_attr_set(infra_driver)):
LOG.debug(_('hosting device driver unspecified')) LOG.debug(_('hosting device driver unspecified'))
raise servicevm.InfraDriverNotSpecified() raise vnfm.InfraDriverNotSpecified()
if (not attributes.is_attr_set(mgmt_driver)): if (not attributes.is_attr_set(mgmt_driver)):
LOG.debug(_('mgmt driver unspecified')) LOG.debug(_('mgmt driver unspecified'))
raise servicevm.MGMTDriverNotSpecified() raise vnfm.MGMTDriverNotSpecified()
if (not attributes.is_attr_set(service_types)): if (not attributes.is_attr_set(service_types)):
LOG.debug(_('service types unspecified')) LOG.debug(_('service types unspecified'))
raise servicevm.SeviceTypesNotSpecified() raise vnfm.SeviceTypesNotSpecified()
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
template_id = str(uuid.uuid4()) template_id = str(uuid.uuid4())
@ -444,7 +443,7 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
devices_db = context.session.query(Device).filter_by( devices_db = context.session.query(Device).filter_by(
template_id=device_template_id).first() template_id=device_template_id).first()
if devices_db is not None: if devices_db is not None:
raise servicevm.DeviceTemplateInUse( raise vnfm.DeviceTemplateInUse(
device_template_id=device_template_id) device_template_id=device_template_id)
context.session.query(ServiceType).filter_by( context.session.query(ServiceType).filter_by(
@ -597,9 +596,9 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
filter(Device.status.in_(current_statuses)). filter(Device.status.in_(current_statuses)).
with_lockmode('update').one()) with_lockmode('update').one())
except orm_exc.NoResultFound: except orm_exc.NoResultFound:
raise servicevm.DeviceNotFound(device_id=device_id) raise vnfm.DeviceNotFound(device_id=device_id)
if device_db.status == constants.PENDING_UPDATE: if device_db.status == constants.PENDING_UPDATE:
raise servicevm.DeviceInUse(device_id=device_id) raise vnfm.DeviceInUse(device_id=device_id)
device_db.update({'status': new_status}) device_db.update({'status': new_status})
return device_db return device_db
@ -633,7 +632,7 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
binding_db = (context.session.query(ServiceDeviceBinding). binding_db = (context.session.query(ServiceDeviceBinding).
filter_by(device_id=device_id).first()) filter_by(device_id=device_id).first())
if binding_db is not None: if binding_db is not None:
raise servicevm.DeviceInUse(device_id=device_id) raise vnfm.DeviceInUse(device_id=device_id)
device_db = self._get_device_db( device_db = self._get_device_db(
context, device_id, _ACTIVE_UPDATE_ERROR_DEAD, context, device_id, _ACTIVE_UPDATE_ERROR_DEAD,
constants.PENDING_DELETE) constants.PENDING_DELETE)
@ -851,7 +850,7 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
with_lockmode('update').one()) with_lockmode('update').one())
if service_instance.managed_by_user != managed_by_user: if service_instance.managed_by_user != managed_by_user:
raise servicevm.ServiceInstanceNotManagedByUser( raise vnfm.ServiceInstanceNotManagedByUser(
service_instance_id=service_instance_id) service_instance_id=service_instance_id)
service_instance.status = constants.PENDING_DELETE service_instance.status = constants.PENDING_DELETE
@ -864,7 +863,7 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
assert binding_db assert binding_db
# check only. _post method will delete it. # check only. _post method will delete it.
if len(binding_db) > 1: if len(binding_db) > 1:
raise servicevm.ServiceInstanceInUse( raise vnfm.ServiceInstanceInUse(
service_instance_id=service_instance_id) service_instance_id=service_instance_id)
def _delete_service_instance_post(self, context, service_instance_id): def _delete_service_instance_post(self, context, service_instance_id):
@ -930,3 +929,18 @@ class ServiceResourcePluginDb(servicevm.ServiceVMPluginBase,
return self._get_collection( return self._get_collection(
context, ServiceInstance, self._make_service_instance_dict, context, ServiceInstance, self._make_service_instance_dict,
filters=filters, fields=fields) filters=filters, fields=fields)
def get_vnfs(self, context, filters=None, fields=None):
return self.get_devices(context, filters, fields)
def get_vnf(self, context, vnf_id, fields=None):
return self.get_device(context, vnf_id, fields)
def delete_vnfd(self, context, vnfd_id):
self.delete_device_template(context, vnfd_id)
def get_vnfd(self, context, vnfd_id, fields=None):
return self.get_device_template(context, vnfd_id, fields)
def get_vnfds(self, context, filters=None, fields=None):
return self.get_device_templates(context, filters, fields)

View File

@ -1,11 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2015 Intel Corporation..
#
# Copyright 2013, 2014 Intel Corporation.
# Copyright 2013, 2014 Isaku Yamahata <isaku.yamahata at intel com>
# <isaku.yamahata at gmail com>
# All Rights Reserved. # All Rights Reserved.
# #
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
# a copy of the License at # a copy of the License at
@ -17,8 +12,6 @@
# 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.
#
# @author: Isaku Yamahata, Intel Corporation.
import abc import abc
@ -30,7 +23,7 @@ from tacker.api.v1 import resource_helper
from tacker.common import exceptions from tacker.common import exceptions
from tacker.openstack.common import log as logging from tacker.openstack.common import log as logging
from tacker.plugins.common import constants from tacker.plugins.common import constants
from tacker.services.service_base import ServicePluginBase from tacker.services.service_base import NFVPluginBase
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -163,9 +156,137 @@ def _validate_service_context_list(data, valid_values=None):
attr.validators['type:service_type_list'] = _validate_service_type_list attr.validators['type:service_type_list'] = _validate_service_type_list
attr.validators['type:service_context_list'] = _validate_service_context_list attr.validators['type:service_context_list'] = _validate_service_context_list
RESOURCE_ATTRIBUTE_MAP = { RESOURCE_ATTRIBUTE_MAP = {
'vnfds': {
'id': {
'allow_post': False,
'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True,
'primary_key': True,
},
'tenant_id': {
'allow_post': True,
'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True,
},
'name': {
'allow_post': True,
'allow_put': True,
'validate': {'type:string': None},
'is_visible': True,
'default': '',
},
'description': {
'allow_post': True,
'allow_put': True,
'validate': {'type:string': None},
'is_visible': True,
'default': '',
},
'service_types': {
'allow_post': True,
'allow_put': False,
'convert_to': attr.convert_to_list,
'validate': {'type:service_type_list': None},
'is_visible': True,
'default': attr.ATTR_NOT_SPECIFIED,
},
'infra_driver': {
'allow_post': True,
'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
'default': attr.ATTR_NOT_SPECIFIED,
},
'mgmt_driver': {
'allow_post': True,
'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
'default': attr.ATTR_NOT_SPECIFIED,
},
'attributes': {
'allow_post': True,
'allow_put': False,
'convert_to': attr.convert_none_to_empty_dict,
'validate': {'type:dict_or_nodata': None},
'is_visible': True,
'default': None,
},
},
'vnfs': {
'id': {
'allow_post': False,
'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True,
'primary_key': True
},
'tenant_id': {
'allow_post': True,
'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True
},
'vnfd_id': {
'allow_post': True,
'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True,
},
'name': {
'allow_post': True,
'allow_put': True,
'validate': {'type:string': None},
'is_visible': True,
'default': '',
},
'description': {
'allow_post': True,
'allow_put': True,
'validate': {'type:string': None},
'is_visible': True,
'default': '',
},
'instance_id': {
'allow_post': False,
'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
},
'mgmt_url': {
'allow_post': False,
'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
},
'attributes': {
'allow_post': True,
'allow_put': True,
'validate': {'type:dict_or_none': None},
'is_visible': True,
'default': {},
},
'service_contexts': {
'allow_post': True,
'allow_put': False,
'validate': {'type:service_context_list': None},
'is_visible': True,
'default': [],
},
'status': {
'allow_post': False,
'allow_put': False,
'is_visible': True,
},
},
'device_templates': { 'device_templates': {
'id': { 'id': {
'allow_post': False, 'allow_post': False,
@ -288,109 +409,31 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_visible': True, 'is_visible': True,
'default': [], 'default': [],
}, },
'services': {
'allow_post': False,
'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True,
},
'status': { 'status': {
'allow_post': False, 'allow_post': False,
'allow_put': False, 'allow_put': False,
'is_visible': True, 'is_visible': True,
}, },
}, },
# 'service_instances': {
# 'id': {
# 'allow_post': False,
# 'allow_put': False,
# 'validate': {'type:uuid': None},
# 'is_visible': True,
# 'primary_key': True
# },
# 'tenant_id': {
# 'allow_post': True,
# 'allow_put': False,
# 'validate': {'type:string': None},
# 'required_by_policy': True,
# 'is_visible': True
# },
# 'name': {
# 'allow_post': True,
# 'allow_put': True,
# 'validate': {'type:string': None},
# 'is_visible': True,
# },
# 'service_type_id': {
# 'allow_post': True,
# 'allow_put': False,
# 'validate': {'type:uuid': None},
# 'is_visible': True,
# },
# 'service_table_id': {
# 'allow_post': True,
# 'allow_put': False,
# 'validate': {'type:string': None},
# 'is_visible': True,
# },
# 'mgmt_driver': {
# 'allow_post': True,
# 'allow_put': False,
# 'validate': {'type:string': None},
# 'is_visible': True,
# },
# 'mgmt_url': {
# 'allow_post': True,
# 'allow_put': False,
# 'validate': {'type:string': None},
# 'is_visible': True,
# },
# 'service_contexts': {
# 'allow_post': True,
# 'allow_put': False,
# 'validate': {'type:service_context_list': None},
# 'is_visible': True,
# },
# 'devices': {
# 'allow_post': True,
# 'allow_put': False,
# 'validate': {'type:uuid_list': None},
# 'convert_to': attr.convert_to_list,
# 'is_visible': True,
# },
# 'status': {
# 'allow_post': False,
# 'allow_put': False,
# 'is_visible': True,
# },
# 'kwargs': {
# 'allow_post': True,
# 'allow_put': True,
# 'validate': {'type:dict_or_none': None},
# 'is_visible': True,
# 'default': {},
# },
# },
} }
class Servicevm(extensions.ExtensionDescriptor): class Vnfm(extensions.ExtensionDescriptor):
@classmethod @classmethod
def get_name(cls): def get_name(cls):
return 'Service VM' return 'VNFM'
@classmethod @classmethod
def get_alias(cls): def get_alias(cls):
return 'servicevm' return 'VNF Manager'
@classmethod @classmethod
def get_description(cls): def get_description(cls):
return "Extension for ServiceVM service" return "Extension for VNF Manager"
@classmethod @classmethod
def get_namespace(cls): def get_namespace(cls):
return 'http://wiki.openstack.org/Tacker/ServiceVM' return 'http://wiki.openstack.org/Tacker'
@classmethod @classmethod
def get_updated(cls): def get_updated(cls):
@ -401,23 +444,19 @@ class Servicevm(extensions.ExtensionDescriptor):
special_mappings = {} special_mappings = {}
plural_mappings = resource_helper.build_plural_mappings( plural_mappings = resource_helper.build_plural_mappings(
special_mappings, RESOURCE_ATTRIBUTE_MAP) special_mappings, RESOURCE_ATTRIBUTE_MAP)
plural_mappings['devices'] = 'device'
plural_mappings['service_types'] = 'service_type' plural_mappings['service_types'] = 'service_type'
plural_mappings['service_contexts'] = 'service_context' plural_mappings['service_contexts'] = 'service_context'
plural_mappings['services'] = 'service'
attr.PLURALS.update(plural_mappings) attr.PLURALS.update(plural_mappings)
action_map = {'device': {'attach_interface': 'PUT',
'detach_interface': 'PUT'}}
return resource_helper.build_resource_info( return resource_helper.build_resource_info(
plural_mappings, RESOURCE_ATTRIBUTE_MAP, constants.SERVICEVM, plural_mappings, RESOURCE_ATTRIBUTE_MAP, constants.VNFM,
translate_name=True, action_map=action_map) translate_name=True)
@classmethod @classmethod
def get_plugin_interface(cls): def get_plugin_interface(cls):
return ServiceVMPluginBase return VNFMPluginBase
def update_attributes_map(self, attributes): def update_attributes_map(self, attributes):
super(Servicevm, self).update_attributes_map( super(Vnfm, self).update_attributes_map(
attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP) attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)
def get_extended_resources(self, version): def get_extended_resources(self, version):
@ -426,16 +465,52 @@ class Servicevm(extensions.ExtensionDescriptor):
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class ServiceVMPluginBase(ServicePluginBase): class VNFMPluginBase(NFVPluginBase):
def get_plugin_name(self): def get_plugin_name(self):
return constants.SERVICEVM return constants.VNFM
def get_plugin_type(self): def get_plugin_type(self):
return constants.SERVICEVM return constants.VNFM
def get_plugin_description(self): def get_plugin_description(self):
return 'Service VM plugin' return 'Tacker VNF Manager plugin'
@abc.abstractmethod
def create_vnfd(self, context, vnfd):
pass
@abc.abstractmethod
def delete_vnfd(self, context, vnfd_id):
pass
@abc.abstractmethod
def get_vnfd(self, context, vnfd_id, fields=None):
pass
@abc.abstractmethod
def get_vnfds(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def get_vnfs(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def get_vnf(self, context, vnf_id, fields=None):
pass
@abc.abstractmethod
def create_vnf(self, context, vnf):
pass
@abc.abstractmethod
def update_vnf(
self, context, vnf_id, vnf):
pass
@abc.abstractmethod
def delete_vnf(self, context, vnf_id):
pass
@abc.abstractmethod @abc.abstractmethod
def create_device_template(self, context, device_template): def create_device_template(self, context, device_template):
@ -473,24 +548,3 @@ class ServiceVMPluginBase(ServicePluginBase):
@abc.abstractmethod @abc.abstractmethod
def delete_device(self, context, device_id): def delete_device(self, context, device_id):
pass pass
@abc.abstractmethod
def attach_interface(self, context, id, port_id):
pass
@abc.abstractmethod
def detach_interface(self, contexct, id, port_id):
pass
@abc.abstractmethod
def get_service_instances(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def get_service_instance(self, context, service_instance_id, fields=None):
pass
@abc.abstractmethod
def update_service_instance(self, context, service_instance_id,
service_instance):
pass

View File

@ -107,8 +107,7 @@ class TackerManager(object):
Starts from the core plugin and checks if it supports Starts from the core plugin and checks if it supports
advanced services then loads classes provided in configuration. advanced services then loads classes provided in configuration.
""" """
# plugin_providers = cfg.CONF.service_plugins plugin_providers = cfg.CONF.service_plugins
plugin_providers = ['tacker.vm.plugin.ServiceVMPlugin']
LOG.debug(_("Loading service plugins: %s"), plugin_providers) LOG.debug(_("Loading service plugins: %s"), plugin_providers)
for provider in plugin_providers: for provider in plugin_providers:
if provider == '': if provider == '':

View File

@ -18,18 +18,12 @@
# service type constants: # service type constants:
CORE = "CORE" CORE = "CORE"
DUMMY = "DUMMY" DUMMY = "DUMMY"
SERVICEVM = "SERVICEVM" VNFM = "VNFM"
#maps extension alias to service type
EXT_TO_SERVICE_MAPPING = {
'dummy': DUMMY,
'servicevm': SERVICEVM,
}
COMMON_PREFIXES = { COMMON_PREFIXES = {
CORE: "", CORE: "",
DUMMY: "/dummy_svc", DUMMY: "/dummy_svc",
SERVICEVM: "", VNFM: "",
} }
# Service operation status constants # Service operation status constants

View File

@ -27,7 +27,7 @@ LOG = logging.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class ServicePluginBase(extensions.PluginInterface): class NFVPluginBase(extensions.PluginInterface):
"""Define base interface for any Advanced Service plugin.""" """Define base interface for any Advanced Service plugin."""
supported_extension_aliases = [] supported_extension_aliases = []

View File

@ -30,7 +30,7 @@ class VnfTestJSON(base.BaseTackerTest):
toscal_str = open(yaml_file).read() toscal_str = open(yaml_file).read()
data['tosca'] = toscal_str data['tosca'] = toscal_str
toscal = data['tosca'] toscal = data['tosca']
tosca_arg = {'vnfd': {'vnfd': toscal}} tosca_arg = {'vnfd': {'attributes': {'vnfd': toscal}}}
vnfd_instance = self.client.create_vnfd(body=tosca_arg) vnfd_instance = self.client.create_vnfd(body=tosca_arg)
self.assertIsNotNone(vnfd_instance) self.assertIsNotNone(vnfd_instance)

View File

@ -0,0 +1,49 @@
# Copyright 2015 Brocade Communications System, Inc.
# 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 fixtures
import testtools
from tacker.db import api as db_api
from tacker.db import model_base
class SqlFixture(fixtures.Fixture):
# flag to indicate that the models have been loaded
_TABLES_ESTABLISHED = False
def setUp(self):
super(SqlFixture, self).setUp()
# Register all data models
engine = db_api.get_engine()
if not SqlFixture._TABLES_ESTABLISHED:
model_base.BASE.metadata.create_all(engine)
SqlFixture._TABLES_ESTABLISHED = True
def clear_tables():
with engine.begin() as conn:
for table in reversed(
model_base.BASE.metadata.sorted_tables):
conn.execute(table.delete())
self.addCleanup(clear_tables)
class SqlTestCase(testtools.TestCase):
def setUp(self):
super(SqlTestCase, self).setUp()
self.useFixture(SqlFixture())

View File

@ -0,0 +1,60 @@
# Copyright 2015 Brocade Communications System, Inc.
# 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.
def get_dummy_vnfd_obj():
return {u'vnfd': {u'service_types': [{u'service_type': u'vnfd'}],
'name': 'dummy_vnfd', 'tenant_id':
u'ad7ebc56538745a08ef7c5e97f8bd437', u'mgmt_driver': u'noop',
u'infra_driver': u'fake_driver', u'attributes': {u'vnfd':
u'template_name: OpenWRT'
u' \r\ndescription: OpenWRT router'
u'\r\n\r\nservice_properties:\r\n'
u' Id: sample-vnfd\r\n vendor:'
u' tacker\r\n version: '
u'1\r\n\r\nvdus:'
u'\r\n vdu1:\r\n id: vdu1\r\n'
u' vm_image:'
u' cirros-0.3.2-x86_64-uec\r\n'
u' instance_type: m1.tiny\r\n\r\n'
u' network_interfaces:\r\n'
u' management:\r\n'
u' network: net_mgmt\r\n'
u' management: true\r\n'
u' pkt_in:\r\n network:'
u' net0\r\n pkt_out:\r\n'
u' network: net1\r\n\r\n'
u' placement_policy:\r\n'
u' availability_zone: nova\r\n'
u'\r'
u'\n auto-scaling: noop\r\n'
u' monitoring_policy: noop\r\n'
u' failure_policy: noop\r\n\r\n'
u' config:\r\n param0: key0'
u'\r\n param1: key1'},
'description': 'dummy_vnfd_description'},
u'auth': {u'tenantName': u'admin', u'passwordCredentials': {
u'username': u'admin', u'password': u'devstack'}}}
def get_dummy_vnf_obj():
return {'vnf': {'description': 'dummy_vnf_description', 'tenant_id':
u'ad7ebc56538745a08ef7c5e97f8bd437', 'name': 'dummy_vnf',
'service_contexts': [], 'attributes': {}}}
def get_dummy_vnf_config_obj():
return {'vnf': {u'attributes': {u'config': {'vdus': {'vdu1': {
'config': {'firewall': 'dummy_firewall_values'}}}}}}}

View File

View File

@ -0,0 +1,162 @@
# Copyright 2015 Brocade Communications System, Inc.
# 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
import uuid
from tacker import context
from tacker.db.vm import vm_db
from tacker.tests.unit.db import base as db_base
from tacker.tests.unit.db import utils
from tacker.vm import plugin
class FakeDriverManager(mock.Mock):
def invoke(self, *args, **kwargs):
if 'create' in args:
return str(uuid.uuid4())
class FakeDeviceStatus(mock.Mock):
pass
class FakeGreenPool(mock.Mock):
pass
class TestVNFMPlugin(db_base.SqlTestCase):
def setUp(self):
super(TestVNFMPlugin, self).setUp()
self.addCleanup(mock.patch.stopall)
self.context = context.get_admin_context()
self._mock_device_manager()
self._mock_device_status()
self._mock_green_pool()
self.vnfm_plugin = plugin.VNFMPlugin()
def _mock_device_manager(self):
self._device_manager = mock.Mock(wraps=FakeDriverManager())
self._device_manager.__contains__ = mock.Mock(
return_value=True)
fake_device_manager = mock.Mock()
fake_device_manager.return_value = self._device_manager
self._mock(
'tacker.common.driver_manager.DriverManager', fake_device_manager)
def _mock_device_status(self):
self._device_status = mock.Mock(wraps=FakeDeviceStatus())
fake_device_status = mock.Mock()
fake_device_status.return_value = self._device_status
self._mock(
'tacker.vm.monitor.DeviceStatus', fake_device_status)
def _mock_green_pool(self):
self._pool = mock.Mock(wraps=FakeGreenPool())
fake_green_pool = mock.Mock()
fake_green_pool.return_value = self._pool
self._mock(
'eventlet.GreenPool', fake_green_pool)
def _mock(self, target, new=mock.DEFAULT):
patcher = mock.patch(target, new)
return patcher.start()
def _insert_dummy_device_template(self):
session = self.context.session
device_template = vm_db.DeviceTemplate(
id='eb094833-995e-49f0-a047-dfb56aaf7c4e',
tenant_id='ad7ebc56538745a08ef7c5e97f8bd437',
name='fake_template',
description='fake_template_description',
infra_driver='fake_driver',
mgmt_driver='fake_mgmt_driver')
session.add(device_template)
session.flush()
return device_template
def _insert_dummy_device(self):
session = self.context.session
device_db = vm_db.Device(id='6261579e-d6f3-49ad-8bc3-a9cb974778ff',
tenant_id='ad7ebc56538745a08ef7c5e97f8bd437',
name='fake_device',
description='fake_device_description',
instance_id=
'da85ea1a-4ec4-4201-bbb2-8d9249eca7ec',
template_id=
'eb094833-995e-49f0-a047-dfb56aaf7c4e',
status='ACTIVE')
session.add(device_db)
session.flush()
return device_db
def test_create_vnfd(self):
vnfd_obj = utils.get_dummy_vnfd_obj()
result = self.vnfm_plugin.create_vnfd(self.context, vnfd_obj)
self.assertIsNotNone(result)
self.assertIn('id', result)
self.assertIn('service_types', result)
self.assertIn('attributes', result)
self._device_manager.invoke.assert_called_once_with(mock.ANY,
mock.ANY,
plugin=mock.ANY,
context=mock.ANY,
device_template=
mock.ANY)
def test_create_vnf(self):
device_template_obj = self._insert_dummy_device_template()
vnf_obj = utils.get_dummy_vnf_obj()
vnf_obj['vnf']['vnfd_id'] = device_template_obj['id']
result = self.vnfm_plugin.create_vnf(self.context, vnf_obj)
self.assertIsNotNone(result)
self.assertIn('id', result)
self.assertIn('instance_id', result)
self.assertIn('status', result)
self.assertIn('attributes', result)
self.assertIn('mgmt_url', result)
self._device_manager.invoke.assert_called_with(mock.ANY, mock.ANY,
plugin=mock.ANY,
context=mock.ANY,
device=mock.ANY)
self._pool.spawn_n.assert_called_once_with(mock.ANY)
def test_delete_vnf(self):
self._insert_dummy_device_template()
dummy_device_obj = self._insert_dummy_device()
self.vnfm_plugin.delete_vnf(self.context, dummy_device_obj[
'id'])
self._device_manager.invoke.assert_called_with(mock.ANY, mock.ANY,
plugin=mock.ANY,
context=mock.ANY,
device_id=mock.ANY)
self._device_status.delete_hosting_device.assert_called_with(mock.ANY)
self._pool.spawn_n.assert_called_once_with(mock.ANY, mock.ANY,
mock.ANY)
def test_update_vnf(self):
self._insert_dummy_device_template()
dummy_device_obj = self._insert_dummy_device()
vnf_config_obj = utils.get_dummy_vnf_config_obj()
result = self.vnfm_plugin.update_vnf(self.context, dummy_device_obj[
'id'], vnf_config_obj)
self.assertIsNotNone(result)
self.assertEqual(dummy_device_obj['id'], result['id'])
self.assertIn('instance_id', result)
self.assertIn('status', result)
self.assertIn('attributes', result)
self.assertIn('mgmt_url', result)
self._pool.spawn_n.assert_called_once_with(mock.ANY, mock.ANY,
mock.ANY)

View File

@ -31,7 +31,7 @@ from keystoneclient.v2_0 import client as ks_client
from oslo_config import cfg from oslo_config import cfg
from tacker.common import log from tacker.common import log
from tacker.extensions import servicevm from tacker.extensions import vnfm
from tacker.openstack.common import jsonutils from tacker.openstack.common import jsonutils
from tacker.openstack.common import log as logging from tacker.openstack.common import log as logging
from tacker.vm.drivers import abstract_driver from tacker.vm.drivers import abstract_driver
@ -119,13 +119,13 @@ class DeviceHeat(abstract_driver.DeviceAbstractDriver):
self._update_params(value, paramvalues[key], False) self._update_params(value, paramvalues[key], False)
else: else:
LOG.debug('Key missing Value: %s', key) LOG.debug('Key missing Value: %s', key)
raise servicevm.InputValuesMissing() raise vnfm.InputValuesMissing()
elif 'get_input' in value: elif 'get_input' in value:
if value['get_input'] in paramvalues: if value['get_input'] in paramvalues:
original[key] = paramvalues[value['get_input']] original[key] = paramvalues[value['get_input']]
else: else:
LOG.debug('Key missing Value: %s', key) LOG.debug('Key missing Value: %s', key)
raise servicevm.InputValuesMissing() raise vnfm.InputValuesMissing()
else: else:
self._update_params(value, paramvalues, True) self._update_params(value, paramvalues, True)
@ -172,12 +172,12 @@ class DeviceHeat(abstract_driver.DeviceAbstractDriver):
LOG.debug('param_vattrs_yaml', param_vattrs_dict) LOG.debug('param_vattrs_yaml', param_vattrs_dict)
except Exception as e: except Exception as e:
LOG.debug("Not Well Formed: %s", str(e)) LOG.debug("Not Well Formed: %s", str(e))
raise servicevm.ParamYAMLNotWellFormed( raise vnfm.ParamYAMLNotWellFormed(
error_msg_details=str(e)) error_msg_details=str(e))
else: else:
self._update_params(vnfd_dict, param_vattrs_dict) self._update_params(vnfd_dict, param_vattrs_dict)
else: else:
raise servicevm.ParamYAMLInputMissing() raise vnfm.ParamYAMLInputMissing()
KEY_LIST = (('description', 'description'), KEY_LIST = (('description', 'description'),
) )
@ -231,7 +231,7 @@ class DeviceHeat(abstract_driver.DeviceAbstractDriver):
'user_data_format'] 'user_data_format']
properties['user_data'] = vdu_dict['user_data'] properties['user_data'] = vdu_dict['user_data']
elif 'user_data' in vdu_dict or 'user_data_format' in vdu_dict: elif 'user_data' in vdu_dict or 'user_data_format' in vdu_dict:
raise servicevm.UserDataFormatNotFound() raise vnfm.UserDataFormatNotFound()
if ('placement_policy' in vdu_dict and if ('placement_policy' in vdu_dict and
'availability_zone' in vdu_dict['placement_policy']): 'availability_zone' in vdu_dict['placement_policy']):
properties['availability_zone'] = vdu_dict[ properties['availability_zone'] = vdu_dict[
@ -449,7 +449,7 @@ class HeatClient:
return self.stacks.create(**fields) return self.stacks.create(**fields)
except heatException.HTTPException: except heatException.HTTPException:
type_, value, tb = sys.exc_info() type_, value, tb = sys.exc_info()
raise servicevm.HeatClientException(msg=value) raise vnfm.HeatClientException(msg=value)
def delete(self, stack_id): def delete(self, stack_id):
try: try:

View File

@ -31,7 +31,7 @@ from tacker.common import driver_manager
from tacker import context as t_context from tacker import context as t_context
from tacker.db.vm import proxy_db # noqa from tacker.db.vm import proxy_db # noqa
from tacker.db.vm import vm_db from tacker.db.vm import vm_db
from tacker.extensions import servicevm from tacker.extensions import vnfm
from tacker.openstack.common import excutils from tacker.openstack.common import excutils
from tacker.openstack.common import log as logging from tacker.openstack.common import log as logging
from tacker.plugins.common import constants from tacker.plugins.common import constants
@ -41,7 +41,7 @@ from tacker.vm import monitor
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class ServiceVMMgmtMixin(object): class VNFMMgmtMixin(object):
OPTS = [ OPTS = [
cfg.MultiStrOpt( cfg.MultiStrOpt(
'mgmt_driver', default=[], 'mgmt_driver', default=[],
@ -52,7 +52,7 @@ class ServiceVMMgmtMixin(object):
cfg.CONF.register_opts(OPTS, 'servicevm') cfg.CONF.register_opts(OPTS, 'servicevm')
def __init__(self): def __init__(self):
super(ServiceVMMgmtMixin, self).__init__() super(VNFMMgmtMixin, self).__init__()
self._mgmt_manager = driver_manager.DriverManager( self._mgmt_manager = driver_manager.DriverManager(
'tacker.servicevm.mgmt.drivers', cfg.CONF.servicevm.mgmt_driver) 'tacker.servicevm.mgmt.drivers', cfg.CONF.servicevm.mgmt_driver)
@ -152,7 +152,7 @@ class ServiceVMMgmtMixin(object):
service_instance=service_instance_dict, kwargs=kwargs) service_instance=service_instance_dict, kwargs=kwargs)
class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin): class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
"""ServiceVMPlugin which supports ServiceVM framework """ServiceVMPlugin which supports ServiceVM framework
""" """
OPTS = [ OPTS = [
@ -161,10 +161,10 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
help=_('Hosting device drivers servicevm plugin will use')), help=_('Hosting device drivers servicevm plugin will use')),
] ]
cfg.CONF.register_opts(OPTS, 'servicevm') cfg.CONF.register_opts(OPTS, 'servicevm')
supported_extension_aliases = ['servicevm'] supported_extension_aliases = ['vnfm']
def __init__(self): def __init__(self):
super(ServiceVMPlugin, self).__init__() super(VNFMPlugin, self).__init__()
self._pool = eventlet.GreenPool() self._pool = eventlet.GreenPool()
self._device_manager = driver_manager.DriverManager( self._device_manager = driver_manager.DriverManager(
'tacker.servicevm.device.drivers', 'tacker.servicevm.device.drivers',
@ -184,18 +184,18 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
infra_driver = template.get('infra_driver') infra_driver = template.get('infra_driver')
if not attributes.is_attr_set(infra_driver): if not attributes.is_attr_set(infra_driver):
LOG.debug(_('hosting device driver must be specified')) LOG.debug(_('hosting device driver must be specified'))
raise servicevm.InfraDriverNotSpecified() raise vnfm.InfraDriverNotSpecified()
if infra_driver not in self._device_manager: if infra_driver not in self._device_manager:
LOG.debug(_('unknown hosting device driver ' LOG.debug(_('unknown hosting device driver '
'%(infra_driver)s in %(drivers)s'), '%(infra_driver)s in %(drivers)s'),
{'infra_driver': infra_driver, {'infra_driver': infra_driver,
'drivers': cfg.CONF.servicevm.infra_driver}) 'drivers': cfg.CONF.servicevm.infra_driver})
raise servicevm.InvalidInfraDriver(infra_driver=infra_driver) raise vnfm.InvalidInfraDriver(infra_driver=infra_driver)
service_types = template.get('service_types') service_types = template.get('service_types')
if not attributes.is_attr_set(service_types): if not attributes.is_attr_set(service_types):
LOG.debug(_('service type must be specified')) LOG.debug(_('service type must be specified'))
raise servicevm.ServiceTypesNotSpecified() raise vnfm.ServiceTypesNotSpecified()
for service_type in service_types: for service_type in service_types:
# TODO(yamahata): # TODO(yamahata):
# framework doesn't know what services are valid for now. # framework doesn't know what services are valid for now.
@ -206,7 +206,7 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
infra_driver, 'create_device_template_pre', plugin=self, infra_driver, 'create_device_template_pre', plugin=self,
context=context, device_template=device_template) context=context, device_template=device_template)
return super(ServiceVMPlugin, self).create_device_template( return super(VNFMPlugin, self).create_device_template(
context, device_template) context, device_template)
########################################################################### ###########################################################################
@ -258,7 +258,7 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
self._device_manager.invoke( self._device_manager.invoke(
driver_name, 'create_wait', plugin=self, context=context, driver_name, 'create_wait', plugin=self, context=context,
device_dict=device_dict, device_id=instance_id) device_dict=device_dict, device_id=instance_id)
except servicevm.DeviceCreateWaitFailed: except vnfm.DeviceCreateWaitFailed:
instance_id = None instance_id = None
del device_dict['instance_id'] del device_dict['instance_id']
@ -415,27 +415,6 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
self._delete_device_post(context, device_id, None) self._delete_device_post(context, device_id, None)
self.spawn_n(self._delete_device_wait, context, device_dict) self.spawn_n(self._delete_device_wait, context, device_dict)
def _do_interface(self, context, device_id, port_id, action):
device_dict = self._update_device_pre(context, device_id)
driver_name = self._infra_driver_name(device_dict)
instance_id = self._instance_id(device_dict)
try:
self._device_manager.invoke(driver_name, action, plugin=self,
context=context, device_id=instance_id)
except Exception:
with excutils.save_and_reraise_exception():
device_dict['status'] = constants.ERROR
self._update_device_post(context, device_id, constants.ERROR)
self._update_device_post(context, device_dict['id'], constants.ACTIVE)
def attach_interface(self, context, id, port_id):
return self._do_interface(context, id, port_id, 'attach_interface')
def detach_interface(self, context, id, port_id):
return self._do_interface(context, id, port_id, 'dettach_interface')
########################################################################### ###########################################################################
# logical service instance # logical service instance
# #
@ -473,7 +452,7 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
def _create_service_instance_db(self, context, device_id, def _create_service_instance_db(self, context, device_id,
service_instance_param, managed_by_user): service_instance_param, managed_by_user):
return super(ServiceVMPlugin, self)._create_service_instance( return super(VNFMPlugin, self)._create_service_instance(
context, device_id, service_instance_param, managed_by_user) context, device_id, service_instance_param, managed_by_user)
def _create_service_instance_by_type( def _create_service_instance_by_type(
@ -683,3 +662,24 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
self.spawn_n( self.spawn_n(
self._delete_service_instance_wait, context, device, self._delete_service_instance_wait, context, device,
service_instance, {}, None, None) service_instance, {}, None, None)
def create_vnf(self, context, vnf):
vnf['device'] = vnf.pop('vnf')
vnf_attributes = vnf['device']
vnf_attributes['template_id'] = vnf_attributes.pop('vnfd_id')
vnf_dict = self.create_device(context, vnf)
vnf_dict['vnfd_id'] = vnf_dict.pop('template_id')
return vnf_dict
def update_vnf(
self, context, vnf_id, vnf):
vnf['device'] = vnf.pop('vnf')
return self.update_device(context, vnf_id, vnf)
def delete_vnf(self, context, vnf_id):
self.delete_device(context, vnf_id)
def create_vnfd(self, context, vnfd):
vnfd['device_template'] = vnfd.pop('vnfd')
new_dict = self.create_device_template(context, vnfd)
return new_dict

View File

@ -2,7 +2,7 @@
# TODO(yamahata): enable tests of py26, py27, py33, py34. # TODO(yamahata): enable tests of py26, py27, py33, py34.
# Those unit tests are temporalily disabled until its stabilization # Those unit tests are temporalily disabled until its stabilization
#envlist = py26,py27,py33,py34,pep8 #envlist = py26,py27,py33,py34,pep8
envlist = pep8 envlist = pep8,py27
minversion = 1.6 minversion = 1.6
skipsdist = True skipsdist = True
@ -10,8 +10,6 @@ skipsdist = True
# disable unit tests for now until stabilization # disable unit tests for now until stabilization
[testenv:py26] [testenv:py26]
commands = bash -c "echo do nothing for py26 for now. enable after stablized" commands = bash -c "echo do nothing for py26 for now. enable after stablized"
[testenv:py27]
commands = bash -c "echo do nothing for py27 for now. enable after stablized"
[testenv:py33] [testenv:py33]
commands = bash -c "echo do nothing for py33 for now. enable after stablized" commands = bash -c "echo do nothing for py33 for now. enable after stablized"
[testenv:py34] [testenv:py34]