1048 lines
46 KiB
Python
1048 lines
46 KiB
Python
# Copyright 2016 Red Hat 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.
|
|
|
|
from oslo_utils import uuidutils
|
|
import random
|
|
import sqlalchemy as sa
|
|
|
|
from oslo_log import log as logging
|
|
from six import iteritems
|
|
from sqlalchemy import orm
|
|
from sqlalchemy.orm import exc as orm_exc
|
|
from tacker.db import db_base
|
|
from tacker.db import model_base
|
|
from tacker.db import models_v1
|
|
from tacker.db import types
|
|
from tacker.extensions import nfvo
|
|
from tacker.extensions.nfvo_plugins import vnffg
|
|
from tacker import manager
|
|
from tacker.plugins.common import constants
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
_ACTIVE_UPDATE = (constants.ACTIVE, constants.PENDING_UPDATE)
|
|
_ACTIVE_UPDATE_ERROR_DEAD = (
|
|
constants.PENDING_CREATE, constants.ACTIVE, constants.PENDING_UPDATE,
|
|
constants.ERROR, constants.DEAD)
|
|
_VALID_VNFFG_UPDATE_ATTRIBUTES = ('name', 'description', 'vnf_mapping')
|
|
_VALID_SFC_UPDATE_ATTRIBUTES = ('chain', 'symmetrical')
|
|
_VALID_FC_UPDATE_ATTRIBUTES = ()
|
|
MATCH_CRITERIA = (
|
|
'eth_type', 'eth_src', 'eth_dst', 'vlan_id', 'vlan_pcp', 'mpls_label',
|
|
'mpls_tc', 'ip_dscp', 'ip_ecn', 'ip_src_prefix', 'ip_dst_prefix',
|
|
'ip_proto', 'destination_port_range', 'source_port_range',
|
|
'network_src_port_id', 'network_dst_port_id', 'network_id', 'network_name',
|
|
'tenant_id', 'icmpv4_type', 'icmpv4_code', 'arp_op', 'arp_spa',
|
|
'arp_tpa', 'arp_sha', 'arp_tha', 'ipv6_src', 'ipv6_dst', 'ipv6_flabel',
|
|
'icmpv6_type', 'icmpv6_code', 'ipv6_nd_target', 'ipv6_nd_sll',
|
|
'ipv6_nd_tll')
|
|
|
|
MATCH_DB_KEY_LIST = (
|
|
'eth_type', 'eth_src', 'eth_dst', 'vlan_id', 'vlan_pcp', 'mpls_label',
|
|
'mpls_tc', 'ip_dscp', 'ip_ecn', 'ip_src_prefix', 'ip_dst_prefix',
|
|
'ip_proto', 'destination_port_min', 'destination_port_max',
|
|
'source_port_min', 'source_port_max', 'network_src_port_id',
|
|
'network_dst_port_id', 'network_id', 'tenant_id', 'icmpv4_type',
|
|
'icmpv4_code', 'arp_op', 'arp_spa', 'arp_tpa', 'arp_sha', 'arp_tha',
|
|
'ipv6_src', 'ipv6_dst', 'ipv6_flabel', 'icmpv6_type', 'icmpv6_code',
|
|
'ipv6_nd_target', 'ipv6_nd_sll', 'ipv6_nd_tll'
|
|
)
|
|
|
|
CP = 'connection_points'
|
|
|
|
|
|
class VnffgTemplate(model_base.BASE, models_v1.HasId, models_v1.HasTenant):
|
|
"""Represents template to create a VNF Forwarding Graph."""
|
|
|
|
# Descriptive name
|
|
name = sa.Column(sa.String(255), nullable=False)
|
|
description = sa.Column(sa.Text)
|
|
|
|
# Vnffg template
|
|
template = sa.Column(types.Json)
|
|
|
|
# Vnffgd template source - onboarded
|
|
template_source = sa.Column(sa.String(255), server_default='onboarded')
|
|
|
|
|
|
class Vnffg(model_base.BASE, models_v1.HasTenant, models_v1.HasId):
|
|
"""VNF Forwarding Graph Data Model"""
|
|
|
|
name = sa.Column(sa.String(255), nullable=False)
|
|
description = sa.Column(sa.String(255), nullable=True)
|
|
|
|
# List of associated NFPs
|
|
forwarding_paths = orm.relationship("VnffgNfp", backref="vnffg")
|
|
|
|
vnffgd_id = sa.Column(types.Uuid, sa.ForeignKey('vnffgtemplates.id'))
|
|
vnffgd = orm.relationship('VnffgTemplate')
|
|
|
|
status = sa.Column(sa.String(255), nullable=False)
|
|
|
|
# Mapping of VNFD to VNF instance names
|
|
vnf_mapping = sa.Column(types.Json)
|
|
|
|
attributes = sa.Column(types.Json)
|
|
|
|
|
|
class VnffgNfp(model_base.BASE, models_v1.HasTenant, models_v1.HasId):
|
|
"""Network Forwarding Path Data Model"""
|
|
|
|
name = sa.Column(sa.String(255), nullable=False)
|
|
vnffg_id = sa.Column(types.Uuid, sa.ForeignKey('vnffgs.id'),
|
|
nullable=False)
|
|
|
|
# List of associated classifiers
|
|
classifiers = orm.relationship('VnffgClassifier', backref='nfp')
|
|
chain = orm.relationship('VnffgChain', backref='nfp',
|
|
uselist=False)
|
|
|
|
status = sa.Column(sa.String(255), nullable=False)
|
|
path_id = sa.Column(sa.String(255), nullable=False)
|
|
|
|
# symmetry of forwarding path
|
|
symmetrical = sa.Column(sa.Boolean(), default=False)
|
|
|
|
|
|
class VnffgChain(model_base.BASE, models_v1.HasTenant, models_v1.HasId):
|
|
"""Service Function Chain Data Model"""
|
|
|
|
status = sa.Column(sa.String(255), nullable=False)
|
|
|
|
instance_id = sa.Column(sa.String(255), nullable=True)
|
|
|
|
# symmetry of forwarding path
|
|
symmetrical = sa.Column(sa.Boolean(), default=False)
|
|
|
|
# chain
|
|
chain = sa.Column(types.Json)
|
|
|
|
path_id = sa.Column(sa.String(255), nullable=False)
|
|
nfp_id = sa.Column(types.Uuid, sa.ForeignKey('vnffgnfps.id'))
|
|
|
|
|
|
class VnffgClassifier(model_base.BASE, models_v1.HasTenant, models_v1.HasId):
|
|
"""VNFFG NFP Classifier Data Model"""
|
|
|
|
status = sa.Column(sa.String(255), nullable=False)
|
|
|
|
instance_id = sa.Column(sa.String(255), nullable=True)
|
|
|
|
chain_id = sa.Column(types.Uuid, sa.ForeignKey('vnffgchains.id'))
|
|
chain = orm.relationship('VnffgChain', backref='classifier',
|
|
uselist=False, foreign_keys=[chain_id])
|
|
nfp_id = sa.Column(types.Uuid, sa.ForeignKey('vnffgnfps.id'))
|
|
# match criteria
|
|
match = orm.relationship('ACLMatchCriteria')
|
|
|
|
|
|
class ACLMatchCriteria(model_base.BASE, models_v1.HasId):
|
|
"""Represents ACL match criteria of a classifier."""
|
|
|
|
vnffgc_id = sa.Column(types.Uuid, sa.ForeignKey('vnffgclassifiers.id'))
|
|
eth_src = sa.Column(sa.String(36), nullable=True)
|
|
eth_dst = sa.Column(sa.String(36), nullable=True)
|
|
eth_type = sa.Column(sa.String(36), nullable=True)
|
|
vlan_id = sa.Column(sa.Integer, nullable=True)
|
|
vlan_pcp = sa.Column(sa.Integer, nullable=True)
|
|
mpls_label = sa.Column(sa.Integer, nullable=True)
|
|
mpls_tc = sa.Column(sa.Integer, nullable=True)
|
|
ip_dscp = sa.Column(sa.Integer, nullable=True)
|
|
ip_ecn = sa.Column(sa.Integer, nullable=True)
|
|
ip_src_prefix = sa.Column(sa.String(36), nullable=True)
|
|
ip_dst_prefix = sa.Column(sa.String(36), nullable=True)
|
|
source_port_min = sa.Column(sa.Integer, nullable=True)
|
|
source_port_max = sa.Column(sa.Integer, nullable=True)
|
|
destination_port_min = sa.Column(sa.Integer, nullable=True)
|
|
destination_port_max = sa.Column(sa.Integer, nullable=True)
|
|
ip_proto = sa.Column(sa.Integer, nullable=True)
|
|
network_id = sa.Column(types.Uuid, nullable=True)
|
|
network_src_port_id = sa.Column(types.Uuid, nullable=True)
|
|
network_dst_port_id = sa.Column(types.Uuid, nullable=True)
|
|
tenant_id = sa.Column(sa.String(64), nullable=True)
|
|
icmpv4_type = sa.Column(sa.Integer, nullable=True)
|
|
icmpv4_code = sa.Column(sa.Integer, nullable=True)
|
|
arp_op = sa.Column(sa.Integer, nullable=True)
|
|
arp_spa = sa.Column(sa.String(36), nullable=True)
|
|
arp_tpa = sa.Column(sa.String(36), nullable=True)
|
|
arp_sha = sa.Column(sa.String(36), nullable=True)
|
|
arp_tha = sa.Column(sa.String(36), nullable=True)
|
|
ipv6_src = sa.Column(sa.String(36), nullable=True)
|
|
ipv6_dst = sa.Column(sa.String(36), nullable=True)
|
|
ipv6_flabel = sa.Column(sa.Integer, nullable=True)
|
|
icmpv6_type = sa.Column(sa.Integer, nullable=True)
|
|
icmpv6_code = sa.Column(sa.Integer, nullable=True)
|
|
ipv6_nd_target = sa.Column(sa.String(36), nullable=True)
|
|
ipv6_nd_sll = sa.Column(sa.String(36), nullable=True)
|
|
ipv6_nd_tll = sa.Column(sa.String(36), nullable=True)
|
|
|
|
|
|
class VnffgPluginDbMixin(vnffg.VNFFGPluginBase, db_base.CommonDbMixin):
|
|
|
|
def __init__(self):
|
|
super(VnffgPluginDbMixin, self).__init__()
|
|
|
|
def create_vnffg(self, context, vnffg):
|
|
vnffg_dict = self._create_vnffg_pre(context, vnffg)
|
|
sfc_instance = uuidutils.generate_uuid()
|
|
fc_instance = uuidutils.generate_uuid()
|
|
self._create_vnffg_post(context, sfc_instance,
|
|
fc_instance, vnffg_dict)
|
|
self._create_vnffg_status(context, vnffg_dict)
|
|
return vnffg_dict
|
|
|
|
def get_vnffg(self, context, vnffg_id, fields=None):
|
|
vnffg_db = self._get_resource(context, Vnffg, vnffg_id)
|
|
return self._make_vnffg_dict(vnffg_db, fields)
|
|
|
|
def get_vnffgs(self, context, filters=None, fields=None):
|
|
return self._get_collection(context, Vnffg, self._make_vnffg_dict,
|
|
filters=filters, fields=fields)
|
|
|
|
def update_vnffg(self, context, vnffg_id, vnffg):
|
|
vnffg_dict = self._update_vnffg_pre(context, vnffg_id)
|
|
self._update_vnffg_post(context, vnffg_id, constants.ACTIVE, vnffg)
|
|
return vnffg_dict
|
|
|
|
def delete_vnffg(self, context, vnffg_id):
|
|
self._delete_vnffg_pre(context, vnffg_id)
|
|
self._delete_vnffg_post(context, vnffg_id, False)
|
|
|
|
def create_vnffgd(self, context, vnffgd):
|
|
template = vnffgd['vnffgd']
|
|
LOG.debug('template %s', template)
|
|
tenant_id = self._get_tenant_id_for_create(context, template)
|
|
template_source = template.get('template_source')
|
|
|
|
with context.session.begin(subtransactions=True):
|
|
template_id = uuidutils.generate_uuid()
|
|
template_db = VnffgTemplate(
|
|
id=template_id,
|
|
tenant_id=tenant_id,
|
|
name=template.get('name'),
|
|
description=template.get('description'),
|
|
template=template.get('template'),
|
|
template_source=template_source)
|
|
context.session.add(template_db)
|
|
|
|
LOG.debug('template_db %(template_db)s',
|
|
{'template_db': template_db})
|
|
return self._make_template_dict(template_db)
|
|
|
|
def get_vnffgd(self, context, vnffgd_id, fields=None):
|
|
template_db = self._get_resource(context, VnffgTemplate,
|
|
vnffgd_id)
|
|
return self._make_template_dict(template_db, fields)
|
|
|
|
def get_vnffgds(self, context, filters=None, fields=None):
|
|
if ('template_source' in filters) and \
|
|
(filters['template_source'][0] == 'all'):
|
|
filters.pop('template_source')
|
|
return self._get_collection(context, VnffgTemplate,
|
|
self._make_template_dict,
|
|
filters=filters, fields=fields)
|
|
|
|
def delete_vnffgd(self, context, vnffgd_id):
|
|
with context.session.begin(subtransactions=True):
|
|
vnffg_db = context.session.query(Vnffg).filter_by(
|
|
vnffgd_id=vnffgd_id).first()
|
|
if vnffg_db is not None:
|
|
raise nfvo.VnffgdInUse(vnffgd_id=vnffgd_id)
|
|
|
|
template_db = self._get_resource(context, VnffgTemplate,
|
|
vnffgd_id)
|
|
context.session.delete(template_db)
|
|
|
|
def get_classifier(self, context, classifier_id, fields=None):
|
|
classifier_db = self._get_resource(context, VnffgClassifier,
|
|
classifier_id)
|
|
return self._make_classifier_dict(classifier_db, fields)
|
|
|
|
def get_classifiers(self, context, filters=None, fields=None):
|
|
return self._get_collection(context, VnffgClassifier,
|
|
self._make_classifier_dict,
|
|
filters=filters, fields=fields)
|
|
|
|
def create_classifiers_map(self, classifier_ids, instance_ids):
|
|
return {classifier_id: instance_ids[i]
|
|
for i, classifier_id in enumerate(classifier_ids)}
|
|
|
|
def get_nfp(self, context, nfp_id, fields=None):
|
|
nfp_db = self._get_resource(context, VnffgNfp, nfp_id)
|
|
return self._make_nfp_dict(nfp_db, fields)
|
|
|
|
def get_nfps(self, context, filters=None, fields=None):
|
|
return self._get_collection(context, VnffgNfp,
|
|
self._make_nfp_dict,
|
|
filters=filters, fields=fields)
|
|
|
|
def get_sfc(self, context, sfc_id, fields=None):
|
|
chain_db = self._get_resource(context, VnffgChain, sfc_id)
|
|
return self._make_chain_dict(chain_db, fields)
|
|
|
|
def get_sfcs(self, context, filters=None, fields=None):
|
|
return self._get_collection(context, VnffgChain,
|
|
self._make_chain_dict,
|
|
filters=filters, fields=fields)
|
|
|
|
def _update_template_params(self, original, paramvalues, param_matched):
|
|
if 'get_input' not in str(original):
|
|
return
|
|
if isinstance(original, dict):
|
|
for key_, value in iteritems(original):
|
|
if isinstance(value, dict) and 'get_input' in value:
|
|
if value['get_input'] in paramvalues:
|
|
original[key_] = paramvalues[value['get_input']]
|
|
param_matched.setdefault(value['get_input'], 0)
|
|
param_matched[value['get_input']] += 1
|
|
else:
|
|
raise nfvo.VnffgTemplateParamParsingException(
|
|
get_input=value['get_input'])
|
|
else:
|
|
self._update_template_params(value,
|
|
paramvalues, param_matched)
|
|
elif isinstance(original, list):
|
|
for element in original:
|
|
self._update_template_params(element,
|
|
paramvalues, param_matched)
|
|
|
|
def _process_parameterized_template(self, dev_attrs, vnffgd_template):
|
|
param_vattrs_dict = dev_attrs.pop('param_values', None)
|
|
param_matched = {}
|
|
if isinstance(param_vattrs_dict, dict):
|
|
self._update_template_params(vnffgd_template,
|
|
param_vattrs_dict, param_matched)
|
|
else:
|
|
raise nfvo.VnffgParamValueFormatError(
|
|
param_value=param_vattrs_dict)
|
|
for param_key in param_vattrs_dict.keys():
|
|
if param_matched.get(param_key) is None:
|
|
raise nfvo.VnffgParamValueNotUsed(param_key=param_key)
|
|
|
|
# called internally, not by REST API
|
|
def _create_vnffg_pre(self, context, vnffg):
|
|
vnffg = vnffg['vnffg']
|
|
LOG.debug('vnffg %s', vnffg)
|
|
tenant_id = self._get_tenant_id_for_create(context, vnffg)
|
|
name = vnffg.get('name')
|
|
vnffg_id = vnffg.get('id') or uuidutils.generate_uuid()
|
|
template_id = vnffg['vnffgd_id']
|
|
symmetrical = vnffg['symmetrical']
|
|
|
|
with context.session.begin(subtransactions=True):
|
|
template_db = self._get_resource(context, VnffgTemplate,
|
|
template_id)
|
|
LOG.debug('vnffg template %s', template_db)
|
|
|
|
if vnffg.get('attributes') and \
|
|
vnffg['attributes'].get('param_values'):
|
|
vnffg_param = vnffg['attributes']
|
|
vnffgd_topology_template = \
|
|
template_db.template['vnffgd']['topology_template']
|
|
self._process_parameterized_template(vnffg_param,
|
|
vnffgd_topology_template)
|
|
template_db.template['vnffgd']['topology_template'] = \
|
|
vnffgd_topology_template
|
|
|
|
vnf_members = self._get_vnffg_property(template_db.template,
|
|
'constituent_vnfs')
|
|
LOG.debug('Constituent VNFs: %s', vnf_members)
|
|
vnf_mapping = self._get_vnf_mapping(context, vnffg.get(
|
|
'vnf_mapping'), vnf_members)
|
|
LOG.debug('VNF Mapping: %s', vnf_mapping)
|
|
# create NFP dict
|
|
nfp_dict = self._create_nfp_pre(template_db)
|
|
LOG.debug('NFP: %s', nfp_dict)
|
|
vnffg_db = Vnffg(id=vnffg_id,
|
|
tenant_id=tenant_id,
|
|
name=name,
|
|
description=template_db.description,
|
|
vnf_mapping=vnf_mapping,
|
|
vnffgd_id=template_id,
|
|
attributes=template_db.get('template'),
|
|
status=constants.PENDING_CREATE)
|
|
context.session.add(vnffg_db)
|
|
|
|
nfp_id = uuidutils.generate_uuid()
|
|
sfc_id = uuidutils.generate_uuid()
|
|
|
|
matches = self._policy_to_acl_criteria(context, template_db,
|
|
nfp_dict['name'],
|
|
vnf_mapping)
|
|
LOG.debug('acl_matches %s', matches)
|
|
|
|
classifier_ids = [uuidutils.generate_uuid() for i in matches]
|
|
|
|
nfp_db = VnffgNfp(id=nfp_id, vnffg_id=vnffg_id,
|
|
tenant_id=tenant_id,
|
|
name=nfp_dict['name'],
|
|
status=constants.PENDING_CREATE,
|
|
path_id=nfp_dict['path_id'],
|
|
symmetrical=symmetrical)
|
|
context.session.add(nfp_db)
|
|
|
|
chain = self._create_port_chain(context, vnf_mapping, template_db,
|
|
nfp_dict['name'])
|
|
LOG.debug('chain: %s', chain)
|
|
sfc_db = VnffgChain(id=sfc_id,
|
|
tenant_id=tenant_id,
|
|
status=constants.PENDING_CREATE,
|
|
symmetrical=symmetrical,
|
|
chain=chain,
|
|
nfp_id=nfp_id,
|
|
path_id=nfp_dict['path_id'])
|
|
|
|
context.session.add(sfc_db)
|
|
|
|
for i, classifier_id in enumerate(classifier_ids):
|
|
|
|
sfcc_db = VnffgClassifier(id=classifier_id,
|
|
tenant_id=tenant_id,
|
|
status=constants.PENDING_CREATE,
|
|
nfp_id=nfp_id,
|
|
chain_id=sfc_id)
|
|
context.session.add(sfcc_db)
|
|
|
|
match_db_table = ACLMatchCriteria(
|
|
id=uuidutils.generate_uuid(),
|
|
vnffgc_id=classifier_id,
|
|
**matches[i])
|
|
|
|
context.session.add(match_db_table)
|
|
|
|
return self._make_vnffg_dict(vnffg_db)
|
|
|
|
@staticmethod
|
|
def _create_nfp_pre(template_db):
|
|
template = template_db.template['vnffgd']['topology_template']
|
|
nfp_dict = dict()
|
|
vnffg_name = list(template['groups'].keys())[0]
|
|
# we assume only one NFP for initial implementation
|
|
nfp_dict['name'] = template['groups'][vnffg_name]['members'][0]
|
|
nfp_dict['path_id'] = template['node_templates'][nfp_dict['name']][
|
|
'properties']['id']
|
|
|
|
if not nfp_dict['path_id']:
|
|
# TODO(trozet): do we need to check if this path ID is already
|
|
# taken by another VNFFG
|
|
nfp_dict['path_id'] = random.randint(1, 16777216)
|
|
|
|
return nfp_dict
|
|
|
|
def _create_port_chain(self, context, vnf_mapping, template_db, nfp_name):
|
|
"""Creates a list of physical port ids to represent an ordered chain
|
|
|
|
:param context: SQL session context
|
|
:param vnf_mapping: dict of VNFD to VNF instance mappings
|
|
:param template_db: VNFFG Descriptor
|
|
:param nfp_name: name of the forwarding path with chain requirements
|
|
:return: list of port chain including vnf name and list of CPs
|
|
"""
|
|
chain_list = []
|
|
prev_forwarder = None
|
|
vnfm_plugin = manager.TackerManager.get_service_plugins()['VNFM']
|
|
# Build the list of logical chain representation
|
|
logical_chain = self._get_nfp_attribute(template_db.template,
|
|
nfp_name, 'path')
|
|
# Build physical port chain
|
|
for element in logical_chain:
|
|
if element['forwarder'] not in vnf_mapping.keys():
|
|
raise nfvo.NfpForwarderNotFoundException(vnfd=element[
|
|
'forwarder'],
|
|
mapping=vnf_mapping)
|
|
# TODO(trozet): validate CP in VNFD has forwarding capability
|
|
# Find VNF resources
|
|
vnf = vnfm_plugin.get_vnf_resources(context,
|
|
vnf_mapping[element[
|
|
'forwarder']]
|
|
)
|
|
vnf_info = vnfm_plugin.get_vnf(context,
|
|
vnf_mapping[element['forwarder']])
|
|
vnf_cp = None
|
|
for resource in vnf:
|
|
if resource['name'] == element['capability']:
|
|
vnf_cp = resource['id']
|
|
break
|
|
if vnf_cp is None:
|
|
raise nfvo.VnffgCpNotFoundException(cp_id=element[
|
|
'capability'], vnf_id=vnf_mapping[element['forwarder']])
|
|
# Check if this is a new VNF entry in the chain
|
|
if element['forwarder'] != prev_forwarder:
|
|
chain_list.append({'name': vnf_info['name'],
|
|
CP: [vnf_cp]})
|
|
prev_forwarder = element['forwarder']
|
|
# Must be an egress CP
|
|
else:
|
|
if len(chain_list[-1][CP]) > 1:
|
|
raise nfvo.NfpRequirementsException(vnfd=element[
|
|
'forwarder'])
|
|
else:
|
|
chain_list[-1][CP].append(vnf_cp)
|
|
|
|
return chain_list
|
|
|
|
@staticmethod
|
|
def _get_vnffg_property(template, vnffg_property):
|
|
template = template['vnffgd']['topology_template']
|
|
vnffg_name = list(template['groups'].keys())[0]
|
|
try:
|
|
return template['groups'][vnffg_name]['properties'][vnffg_property]
|
|
except KeyError:
|
|
raise nfvo.VnffgPropertyNotFoundException(
|
|
vnffg_property=vnffg_property)
|
|
|
|
@staticmethod
|
|
def _get_nfp_attribute(template, nfp, attribute):
|
|
"""Finds any attribute of an NFP described in a template
|
|
|
|
:param template: VNFFGD template
|
|
:param nfp: name of NFP
|
|
:param attribute: attribute to find
|
|
:return: value of attribute from template
|
|
"""
|
|
template = template['vnffgd']['topology_template']
|
|
try:
|
|
attr_val = VnffgPluginDbMixin._search_value(
|
|
template['node_templates'][nfp], attribute)
|
|
if attr_val is None:
|
|
LOG.debug('NFP %(nfp)s, attr %(attr)s',
|
|
{'nfp': template['node_templates'][nfp],
|
|
'attr': attribute})
|
|
raise nfvo.NfpAttributeNotFoundException(attribute=attribute)
|
|
else:
|
|
return attr_val
|
|
except KeyError:
|
|
raise nfvo.NfpAttributeNotFoundException(attribute=attribute)
|
|
|
|
@staticmethod
|
|
def _search_value(search_dict, search_key):
|
|
for k, v in search_dict.items():
|
|
if k == search_key:
|
|
return v
|
|
elif isinstance(v, dict):
|
|
val = VnffgPluginDbMixin._search_value(v, search_key)
|
|
if val is not None:
|
|
return val
|
|
|
|
def _get_vnf_mapping(self, context, vnf_mapping, vnf_members):
|
|
"""Creates/validates a mapping of VNFD names to VNF IDs for NFP.
|
|
|
|
:param context: SQL session context
|
|
:param vnf_mapping: dict of requested VNFD:VNF_ID mappings
|
|
:param vnf_members: list of constituent VNFs from a VNFFG
|
|
:return: dict of VNFD:VNF_ID mappings
|
|
"""
|
|
vnfm_plugin = manager.TackerManager.get_service_plugins()['VNFM']
|
|
new_mapping = dict()
|
|
|
|
for vnfd in vnf_members:
|
|
# there should only be one ID returned for a unique name
|
|
try:
|
|
vnfd_id = vnfm_plugin.get_vnfds(context, {'name': [vnfd]},
|
|
fields=['id']).pop()['id']
|
|
except Exception:
|
|
raise nfvo.VnffgdVnfdNotFoundException(vnfd_name=vnfd)
|
|
if vnfd_id is None:
|
|
raise nfvo.VnffgdVnfdNotFoundException(vnfd_name=vnfd)
|
|
else:
|
|
# if no VNF mapping, we need to abstractly look for instances
|
|
# that match VNFD
|
|
if vnf_mapping is None or vnfd not in vnf_mapping.keys():
|
|
# find suitable VNFs from vnfd_id
|
|
LOG.debug('Searching VNFS with id %s', vnfd_id)
|
|
vnf_list = vnfm_plugin.get_vnfs(context,
|
|
{'vnfd_id': [vnfd_id]},
|
|
fields=['id'])
|
|
if len(vnf_list) == 0:
|
|
raise nfvo.VnffgInvalidMappingException(vnfd_name=vnfd)
|
|
else:
|
|
LOG.debug('Matching VNFs found %s', vnf_list)
|
|
vnf_list = [vnf['id'] for vnf in vnf_list]
|
|
if len(vnf_list) > 1:
|
|
new_mapping[vnfd] = random.choice(vnf_list)
|
|
else:
|
|
new_mapping[vnfd] = vnf_list[0]
|
|
# if VNF mapping, validate instances exist and match the VNFD
|
|
else:
|
|
vnf_vnfd = vnfm_plugin.get_vnf(context, vnf_mapping[vnfd],
|
|
fields=['vnfd_id'])
|
|
if vnf_vnfd is not None:
|
|
vnf_vnfd_id = vnf_vnfd['vnfd_id']
|
|
else:
|
|
raise nfvo.VnffgInvalidMappingException(vnfd_name=vnfd)
|
|
if vnfd_id != vnf_vnfd_id:
|
|
raise nfvo.VnffgInvalidMappingException(vnfd_name=vnfd)
|
|
else:
|
|
new_mapping[vnfd] = vnf_mapping.pop(vnfd)
|
|
self._validate_vim(context, new_mapping.values())
|
|
return new_mapping
|
|
|
|
def _validate_vim(self, context, vnfs):
|
|
"""Validates all VNFs are in the same VIM
|
|
|
|
:param context: SQL Session Context
|
|
:param vnfs: List of VNF instance IDs
|
|
:return: None
|
|
"""
|
|
LOG.debug('validating vim for vnfs %s', vnfs)
|
|
vnfm_plugin = manager.TackerManager.get_service_plugins()['VNFM']
|
|
vim_id = None
|
|
for vnf in vnfs:
|
|
vnf_dict = vnfm_plugin.get_vnf(context, vnf)
|
|
if vim_id is None:
|
|
vim_id = vnf_dict['vim_id']
|
|
elif vnf_dict['vim_id'] != vim_id:
|
|
raise nfvo.VnffgVimMappingException(vnf_id=vnf, vim_id=vim_id)
|
|
|
|
def _validate_criteria(self, criteria):
|
|
"""Validate whether or not the classifiers are unique.
|
|
|
|
We define a classifier as unique when at least one
|
|
key-value pair is different from another classifier.
|
|
"""
|
|
if not criteria:
|
|
raise nfvo.NfpPolicyCriteriaIndexError()
|
|
elif len(criteria) == 1:
|
|
pass
|
|
else:
|
|
for index, dict_one in enumerate(criteria):
|
|
if index != (len(criteria) - 1):
|
|
for dict_two in criteria[(index + 1):]:
|
|
if dict_one == dict_two:
|
|
raise nfvo. \
|
|
NfpDuplicatePolicyCriteria(first_dict=dict_one,
|
|
sec_dict=dict_two)
|
|
|
|
def _policy_to_acl_criteria(self, context, template_db, nfp_name,
|
|
vnf_mapping):
|
|
template = template_db.template['vnffgd']['topology_template']
|
|
nfp = template['node_templates'][nfp_name]
|
|
try:
|
|
policy = nfp['properties']['policy']
|
|
except KeyError:
|
|
raise nfvo.NfpPolicyNotFoundException(policy=nfp)
|
|
|
|
if 'type' in policy:
|
|
if policy['type'] != 'ACL':
|
|
raise nfvo.NfpPolicyTypeError(type=policy['type'])
|
|
|
|
if 'criteria' not in policy:
|
|
raise nfvo.NfpPolicyCriteriaError(
|
|
error="Missing criteria in policy")
|
|
|
|
self._validate_criteria(policy['criteria'])
|
|
|
|
matches = []
|
|
for criteria in policy['criteria']:
|
|
match = dict()
|
|
for key, val in criteria.items():
|
|
if key in MATCH_CRITERIA:
|
|
match.update(self._convert_criteria(context, key, val,
|
|
vnf_mapping))
|
|
else:
|
|
raise nfvo.NfpPolicyCriteriaError(error="Unsupported "
|
|
"criteria: "
|
|
"{}".format(key))
|
|
matches.append(match)
|
|
|
|
return matches
|
|
|
|
def _convert_criteria(self, context, criteria, value, vnf_mapping):
|
|
"""Method is used to convert criteria to proper db value from template
|
|
|
|
:param context: SQL session context
|
|
:param criteria: input criteria name
|
|
:param value: input value
|
|
:param vnf_mapping: mapping of VNFD to VNF instances
|
|
:return: converted dictionary
|
|
"""
|
|
|
|
if criteria.endswith('_range'):
|
|
prefix = criteria[:-6]
|
|
criteria_min = prefix + "_min"
|
|
criteria_max = prefix + "_max"
|
|
try:
|
|
min_val, max_val = value.split('-')
|
|
except ValueError:
|
|
raise nfvo.NfpPolicyCriteriaError(error="Range missing or "
|
|
"incorrect for "
|
|
"%s".format(criteria))
|
|
return {criteria_min: int(min_val), criteria_max: int(max_val)}
|
|
|
|
elif criteria.endswith('_name'):
|
|
prefix = criteria[:-5]
|
|
vnf_id = list(vnf_mapping.values())[0]
|
|
new_value = self._vim_resource_name_to_id(context, prefix, value,
|
|
vnf_id)
|
|
new_name = prefix + "_id"
|
|
return {new_name: new_value}
|
|
|
|
else:
|
|
return {criteria: value}
|
|
|
|
def _vim_resource_name_to_id(self, context, resource, name, vnf_id):
|
|
"""Converts a VIM resource name to its ID
|
|
|
|
:param context: SQL session context
|
|
:param resource: resource type to find (network, subnet, etc)
|
|
:param name: name of the resource to find its ID
|
|
:param vnf_id: A VNF instance ID that is part of the chain to which
|
|
the classifier will apply to
|
|
:return: ID of the resource name
|
|
"""
|
|
# this should be overridden with driver call to find ID given name
|
|
# for resource
|
|
return uuidutils.generate_uuid()
|
|
|
|
# called internally, not by REST API
|
|
# instance_id = None means error on creation
|
|
def _create_vnffg_post(self, context, sfc_instance_id,
|
|
classifiers_map, vnffg_dict):
|
|
LOG.debug('SFC created instance is %s', sfc_instance_id)
|
|
LOG.debug('Flow Classifiers created instances are %s',
|
|
[classifiers_map[item] for item in classifiers_map])
|
|
nfp_dict = self.get_nfp(context, vnffg_dict['forwarding_paths'])
|
|
sfc_id = nfp_dict['chain_id']
|
|
with context.session.begin(subtransactions=True):
|
|
query = (self._model_query(context, VnffgChain).
|
|
filter(VnffgChain.id == sfc_id).
|
|
filter(VnffgChain.status == constants.PENDING_CREATE).
|
|
one())
|
|
query.update({'instance_id': sfc_instance_id})
|
|
if sfc_instance_id is None:
|
|
query.update({'status': constants.ERROR})
|
|
else:
|
|
query.update({'status': constants.ACTIVE})
|
|
for classifier_id, fc_instance_id in classifiers_map.items():
|
|
query = (self._model_query(context, VnffgClassifier).
|
|
filter(VnffgClassifier.id == classifier_id).
|
|
filter(VnffgClassifier.status ==
|
|
constants.PENDING_CREATE).
|
|
one())
|
|
query.update({'instance_id': fc_instance_id})
|
|
|
|
if fc_instance_id is None:
|
|
query.update({'status': constants.ERROR})
|
|
else:
|
|
query.update({'status': constants.ACTIVE})
|
|
|
|
def _create_vnffg_status(self, context, vnffg):
|
|
nfp = self.get_nfp(context, vnffg['forwarding_paths'])
|
|
chain = self.get_sfc(context, nfp['chain_id'])
|
|
|
|
if chain['status'] == constants.ERROR:
|
|
self._update_all_status(context, vnffg['id'], nfp['id'],
|
|
constants.ERROR)
|
|
|
|
elif chain['status'] == constants.ACTIVE:
|
|
classifiers_active_state = True
|
|
for classifier in [self.get_classifier(context, classifier_id)
|
|
for classifier_id in nfp['classifier_ids']]:
|
|
|
|
if classifier['status'] == constants.ACTIVE:
|
|
continue
|
|
elif classifier['status'] == constants.ERROR:
|
|
classifiers_active_state = False
|
|
break
|
|
|
|
if classifiers_active_state:
|
|
self._update_all_status(context, vnffg['id'], nfp['id'],
|
|
constants.ACTIVE)
|
|
else:
|
|
self._update_all_status(context, vnffg['id'], nfp['id'],
|
|
constants.ERROR)
|
|
|
|
def _update_all_status(self, context, vnffg_id, nfp_id, status):
|
|
with context.session.begin(subtransactions=True):
|
|
query = (self._model_query(context, Vnffg).
|
|
filter(Vnffg.id == vnffg_id))
|
|
query.update({'status': status})
|
|
nfp_query = (self._model_query(context, VnffgNfp).
|
|
filter(VnffgNfp.id == nfp_id))
|
|
nfp_query.update({'status': status})
|
|
|
|
def _make_vnffg_dict(self, vnffg_db, fields=None):
|
|
LOG.debug('vnffg_db %s', vnffg_db)
|
|
LOG.debug('vnffg_db nfp %s', vnffg_db.forwarding_paths)
|
|
res = {
|
|
'forwarding_paths': vnffg_db.forwarding_paths[0]['id']
|
|
}
|
|
key_list = ('id', 'tenant_id', 'name', 'description',
|
|
'vnf_mapping', 'status', 'vnffgd_id', 'attributes')
|
|
res.update((key, vnffg_db[key]) for key in key_list)
|
|
return self._fields(res, fields)
|
|
|
|
def _update_vnffg_pre(self, context, vnffg_id):
|
|
vnffg = self.get_vnffg(context, vnffg_id)
|
|
nfp = self.get_nfp(context, vnffg['forwarding_paths'])
|
|
sfc = self.get_sfc(context, nfp['chain_id'])
|
|
classifiers = [self.get_classifier(context, classifier_id) for
|
|
classifier_id in nfp['classifier_ids']]
|
|
with context.session.begin(subtransactions=True):
|
|
vnffg_db = self._get_vnffg_db(context, vnffg['id'], _ACTIVE_UPDATE,
|
|
constants.PENDING_UPDATE)
|
|
self._get_nfp_db(context, nfp['id'], _ACTIVE_UPDATE,
|
|
constants.PENDING_UPDATE)
|
|
self._get_sfc_db(context, sfc['id'], _ACTIVE_UPDATE,
|
|
constants.PENDING_UPDATE)
|
|
for classifier in classifiers:
|
|
self._get_classifier_db(context, classifier['id'],
|
|
_ACTIVE_UPDATE,
|
|
constants.PENDING_UPDATE)
|
|
return self._make_vnffg_dict(vnffg_db)
|
|
|
|
def _update_vnffg_post(self, context, vnffg_id, new_status,
|
|
new_vnffg=None):
|
|
vnffg = self.get_vnffg(context, vnffg_id)
|
|
nfp = self.get_nfp(context, vnffg['forwarding_paths'])
|
|
sfc_id = nfp['chain_id']
|
|
classifier_ids = nfp['classifier_ids']
|
|
with context.session.begin(subtransactions=True):
|
|
query = (self._model_query(context, VnffgChain).
|
|
filter(VnffgChain.id == sfc_id).
|
|
filter(VnffgChain.status == constants.PENDING_UPDATE))
|
|
query.update({'status': new_status})
|
|
for classifier_id in classifier_ids:
|
|
query = (self._model_query(context, VnffgClassifier).
|
|
filter(VnffgClassifier.id == classifier_id).
|
|
filter(VnffgClassifier.status ==
|
|
constants.PENDING_UPDATE))
|
|
query.update({'status': new_status})
|
|
|
|
query = (self._model_query(context, Vnffg).
|
|
filter(Vnffg.id == vnffg['id']).
|
|
filter(Vnffg.status == constants.PENDING_UPDATE))
|
|
query.update({'status': new_status})
|
|
|
|
nfp_query = (self._model_query(context, VnffgNfp).
|
|
filter(VnffgNfp.id == nfp['id']).
|
|
filter(VnffgNfp.status == constants.PENDING_UPDATE))
|
|
nfp_query.update({'status': new_status})
|
|
|
|
if new_vnffg is not None:
|
|
for key in _VALID_VNFFG_UPDATE_ATTRIBUTES:
|
|
query.update({key: new_vnffg[key]})
|
|
nfp_query.update({'symmetrical': new_vnffg['symmetrical']})
|
|
|
|
def _update_sfc_post(self, context, sfc_id, new_status, new_sfc=None):
|
|
with context.session.begin(subtransactions=True):
|
|
sfc_query = (self._model_query(context, VnffgChain).
|
|
filter(VnffgChain.id == sfc_id).
|
|
filter(VnffgChain.status == constants.PENDING_UPDATE))
|
|
sfc_query.update({'status': new_status})
|
|
|
|
if new_sfc is not None:
|
|
for key in _VALID_SFC_UPDATE_ATTRIBUTES:
|
|
sfc_query.update({key: new_sfc[key]})
|
|
|
|
def _update_classifier_post(self, context, classifier_ids, new_status,
|
|
new_fc=None):
|
|
with context.session.begin(subtransactions=True):
|
|
for classifier_id in classifier_ids:
|
|
fc_query = (self._model_query(context, VnffgClassifier).
|
|
filter(VnffgClassifier.id == classifier_id).
|
|
filter(VnffgClassifier.status ==
|
|
constants.PENDING_UPDATE))
|
|
fc_query.update({'status': new_status})
|
|
|
|
if new_fc is not None:
|
|
for key in _VALID_FC_UPDATE_ATTRIBUTES:
|
|
fc_query.update({key: new_fc[key]})
|
|
|
|
def _get_vnffg_db(self, context, vnffg_id, current_statuses, new_status):
|
|
try:
|
|
vnffg_db = (
|
|
self._model_query(context, Vnffg).
|
|
filter(Vnffg.id == vnffg_id).
|
|
filter(Vnffg.status.in_(current_statuses)).
|
|
with_lockmode('update').one())
|
|
except orm_exc.NoResultFound:
|
|
raise nfvo.VnffgNotFoundException(vnffg_id=vnffg_id)
|
|
if vnffg_db.status == constants.PENDING_UPDATE:
|
|
raise nfvo.VnffgInUse(vnffg_id=vnffg_id)
|
|
vnffg_db.update({'status': new_status})
|
|
return vnffg_db
|
|
|
|
def _get_nfp_db(self, context, nfp_id, current_statuses, new_status):
|
|
try:
|
|
nfp_db = (
|
|
self._model_query(context, VnffgNfp).
|
|
filter(VnffgNfp.id == nfp_id).
|
|
filter(VnffgNfp.status.in_(current_statuses)).
|
|
with_lockmode('update').one())
|
|
except orm_exc.NoResultFound:
|
|
raise nfvo.NfpNotFoundException(nfp_id=nfp_id)
|
|
if nfp_db.status == constants.PENDING_UPDATE:
|
|
raise nfvo.NfpInUse(nfp_id=nfp_id)
|
|
nfp_db.update({'status': new_status})
|
|
return nfp_db
|
|
|
|
def _get_sfc_db(self, context, sfc_id, current_statuses, new_status):
|
|
try:
|
|
sfc_db = (
|
|
self._model_query(context, VnffgChain).
|
|
filter(VnffgChain.id == sfc_id).
|
|
filter(VnffgChain.status.in_(current_statuses)).
|
|
with_lockmode('update').one())
|
|
except orm_exc.NoResultFound:
|
|
raise nfvo.SfcNotFoundException(sfc_id=sfc_id)
|
|
if sfc_db.status == constants.PENDING_UPDATE:
|
|
raise nfvo.SfcInUse(sfc_id=sfc_id)
|
|
sfc_db.update({'status': new_status})
|
|
return sfc_db
|
|
|
|
def _get_classifier_db(self, context, fc_id, current_statuses, new_status):
|
|
try:
|
|
fc_db = (
|
|
self._model_query(context, VnffgClassifier).
|
|
filter(VnffgClassifier.id == fc_id).
|
|
filter(VnffgClassifier.status.in_(current_statuses)).
|
|
with_lockmode('update').one())
|
|
except orm_exc.NoResultFound:
|
|
raise nfvo.ClassifierNotFoundException(fc_id=fc_id)
|
|
if fc_db.status == constants.PENDING_UPDATE:
|
|
raise nfvo.ClassifierInUse(fc_id=fc_id)
|
|
fc_db.update({'status': new_status})
|
|
return fc_db
|
|
|
|
def _delete_vnffg_pre(self, context, vnffg_id):
|
|
vnffg = self.get_vnffg(context, vnffg_id)
|
|
nfp = self.get_nfp(context, vnffg['forwarding_paths'])
|
|
chain = self.get_sfc(context, nfp['chain_id'])
|
|
classifiers = [self.get_classifier(context, classifier_id)
|
|
for classifier_id in nfp['classifier_ids']]
|
|
with context.session.begin(subtransactions=True):
|
|
vnffg_db = self._get_vnffg_db(
|
|
context, vnffg['id'], _ACTIVE_UPDATE_ERROR_DEAD,
|
|
constants.PENDING_DELETE)
|
|
self._get_nfp_db(context, nfp['id'], _ACTIVE_UPDATE_ERROR_DEAD,
|
|
constants.PENDING_DELETE)
|
|
self._get_sfc_db(context, chain['id'], _ACTIVE_UPDATE_ERROR_DEAD,
|
|
constants.PENDING_DELETE)
|
|
for classifier in classifiers:
|
|
self._get_classifier_db(context, classifier['id'],
|
|
_ACTIVE_UPDATE_ERROR_DEAD,
|
|
constants.PENDING_DELETE)
|
|
|
|
return self._make_vnffg_dict(vnffg_db)
|
|
|
|
def _delete_vnffg_post(self, context, vnffg_id, error):
|
|
vnffg = self.get_vnffg(context, vnffg_id)
|
|
nfp = self.get_nfp(context, vnffg['forwarding_paths'])
|
|
chain = self.get_sfc(context, nfp['chain_id'])
|
|
classifiers = [self.get_classifier(context, classifier_id)
|
|
for classifier_id in nfp['classifier_ids']]
|
|
fc_queries = []
|
|
match_queries = []
|
|
with context.session.begin(subtransactions=True):
|
|
vnffg_query = (
|
|
self._model_query(context, Vnffg).
|
|
filter(Vnffg.id == vnffg['id']).
|
|
filter(Vnffg.status == constants.PENDING_DELETE))
|
|
nfp_query = (
|
|
self._model_query(context, VnffgNfp).
|
|
filter(VnffgNfp.id == nfp['id']).
|
|
filter(VnffgNfp.status == constants.PENDING_DELETE))
|
|
sfc_query = (
|
|
self._model_query(context, VnffgChain).
|
|
filter(VnffgChain.id == chain['id']).
|
|
filter(VnffgChain.status == constants.PENDING_DELETE))
|
|
for classifier in classifiers:
|
|
fc_queries.append((
|
|
self._model_query(context, VnffgClassifier).
|
|
filter(VnffgClassifier.id == classifier['id']).
|
|
filter(VnffgClassifier.status ==
|
|
constants.PENDING_DELETE)))
|
|
match_queries.append((
|
|
self._model_query(context, ACLMatchCriteria).
|
|
filter(ACLMatchCriteria.vnffgc_id == classifier['id'])))
|
|
if error:
|
|
vnffg_query.update({'status': constants.ERROR})
|
|
nfp_query.update({'status': constants.ERROR})
|
|
sfc_query.update({'status': constants.ERROR})
|
|
for fc_query in fc_queries:
|
|
fc_query.update({'status': constants.ERROR})
|
|
else:
|
|
for match_query in match_queries:
|
|
match_query.delete()
|
|
for fc_query in fc_queries:
|
|
fc_query.delete()
|
|
sfc_query.delete()
|
|
nfp_query.delete()
|
|
vnffg_query.delete()
|
|
|
|
vnffgd_id = vnffg.get('vnffgd_id')
|
|
template_db = self._get_resource(context, VnffgTemplate,
|
|
vnffgd_id)
|
|
|
|
if template_db.get('template_source') == 'inline':
|
|
self.delete_vnffgd(context, vnffgd_id)
|
|
|
|
def _make_template_dict(self, template, fields=None):
|
|
res = {}
|
|
key_list = ('id', 'tenant_id', 'name', 'description', 'template',
|
|
'template_source')
|
|
res.update((key, template[key]) for key in key_list)
|
|
return self._fields(res, fields)
|
|
|
|
def _make_acl_match_dict(self, acl_match_db):
|
|
key_list = MATCH_DB_KEY_LIST
|
|
return {key: entry[key] for key in key_list for entry in acl_match_db
|
|
if entry[key]}
|
|
|
|
def _make_classifier_dict(self, classifier_db, fields=None):
|
|
LOG.debug('classifier_db %s', classifier_db)
|
|
LOG.debug('classifier_db match %s', classifier_db.match)
|
|
res = {
|
|
'match': self._make_acl_match_dict(classifier_db.match)
|
|
}
|
|
key_list = ('id', 'tenant_id', 'instance_id', 'status', 'chain_id',
|
|
'nfp_id')
|
|
res.update((key, classifier_db[key]) for key in key_list)
|
|
return self._fields(res, fields)
|
|
|
|
def _make_nfp_dict(self, nfp_db, fields=None):
|
|
LOG.debug('nfp_db %s', nfp_db)
|
|
res = {'chain_id': nfp_db.chain['id'],
|
|
'classifier_ids': [classifier['id'] for classifier in
|
|
nfp_db.classifiers]}
|
|
key_list = ('name', 'id', 'tenant_id', 'symmetrical', 'status',
|
|
'path_id', 'vnffg_id')
|
|
res.update((key, nfp_db[key]) for key in key_list)
|
|
return self._fields(res, fields)
|
|
|
|
def _make_chain_dict(self, chain_db, fields=None):
|
|
LOG.debug('chain_db %s', chain_db)
|
|
res = {}
|
|
key_list = ('id', 'tenant_id', 'symmetrical', 'status', 'chain',
|
|
'path_id', 'nfp_id', 'instance_id')
|
|
res.update((key, chain_db[key]) for key in key_list)
|
|
return self._fields(res, fields)
|
|
|
|
def _get_resource(self, context, model, res_id):
|
|
try:
|
|
return self._get_by_id(context, model, res_id)
|
|
except orm_exc.NoResultFound:
|
|
if issubclass(model, Vnffg):
|
|
raise nfvo.VnffgNotFoundException(vnffg_id=res_id)
|
|
elif issubclass(model, VnffgClassifier):
|
|
raise nfvo.ClassifierNotFoundException(classifier_id=res_id)
|
|
if issubclass(model, VnffgTemplate):
|
|
raise nfvo.VnffgdNotFoundException(vnffgd_id=res_id)
|
|
if issubclass(model, VnffgChain):
|
|
raise nfvo.SfcNotFoundException(sfc_id=res_id)
|
|
else:
|
|
raise
|