tacker/tacker/db/nfvo/vnffg_db.py

1418 lines
63 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.nfvo.ns_db import NS
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.PENDING_DELETE, constants.ERROR, constants.DEAD)
_VALID_VNFFG_UPDATE_ATTRIBUTES = ('vnf_mapping',)
_VALID_SFC_UPDATE_ATTRIBUTES = ('chain', 'symmetrical')
_VALID_NFP_UPDATE_ATTRIBUTES = ('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)
# Associated Network Service
ns_id = sa.Column(types.Uuid, sa.ForeignKey('ns.id'), nullable=True)
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=True)
# 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=True)
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"""
name = sa.Column(sa.String(255), nullable=True)
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:
LOG.warning("Param input %s not used.", param_key)
def _parametrize_topology_template(self, vnffg, 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
# 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']
ns_id = vnffg.get('ns_id', None)
symmetrical_in_temp = self._get_symmetrical_template(context, vnffg)
symmetrical = symmetrical_in_temp if symmetrical_in_temp is not None \
else vnffg.get('symmetrical')
with context.session.begin(subtransactions=True):
template_db = self._get_resource(context, VnffgTemplate,
template_id)
LOG.debug('vnffg template %s', template_db)
self._parametrize_topology_template(vnffg, template_db)
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)
path_id = nfp_dict['path_id']
try:
if path_id:
vnffgNfp_db = (self._model_query(context, VnffgNfp).
filter(VnffgNfp.path_id == path_id).one())
raise nfvo.NfpDuplicatePathID(path_id=path_id,
nfp_name=vnffgNfp_db.name,
vnffg_name=name)
except orm_exc.NoResultFound:
pass
vnffg_db = Vnffg(id=vnffg_id,
tenant_id=tenant_id,
name=name,
description=template_db.description,
vnf_mapping=vnf_mapping,
vnffgd_id=template_id,
ns_id=ns_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()
classifiers = self._policy_to_acl_criteria(context, template_db,
nfp_dict['name'],
vnf_mapping)
LOG.debug('classifiers %s', classifiers)
classifier_ids = [uuidutils.generate_uuid() for i in classifiers]
nfp_db = VnffgNfp(id=nfp_id, vnffg_id=vnffg_id,
tenant_id=tenant_id,
name=nfp_dict['name'],
status=constants.PENDING_CREATE,
path_id=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=path_id)
context.session.add(sfc_db)
for i, classifier_id in enumerate(classifier_ids):
sfcc_db = VnffgClassifier(id=classifier_id,
name=classifiers[i]['name'],
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,
tenant_id=tenant_id,
**classifiers[i]['match'])
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'].get('id', None)
# 'path_id' will be updated when creating port chain is done
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],
'sfc_encap': element.get('sfc_encap', True)})
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 _validate_vnfd_in_vnf_mapping(self, vnf_mapping, vnf_members):
"""Validate whether or not the vnf_mapping is valid for update.
In the update_vnnfg procedure we need to know whether or not the
the vnf_mapping is valid so we can use it to update the chain.
"""
if not vnf_mapping:
raise nfvo.VnfMappingNotFoundException()
else:
for vnfd, vnf in vnf_mapping.items():
if vnfd not in vnf_members:
raise nfvo.VnfMappingNotValidException(vnfd=vnfd)
def _combine_current_and_new_vnf_mapping(self, context,
new_mapping, old_mapping):
"""Create an updated vnf mapping.
In this function we create an updated vnf mapping which is
a mix of the vnf_mapping which already exists in database
and the new mapping that the user passes.
"""
updated_vnf_mapping = old_mapping.copy()
updated_vnf_mapping.update(new_mapping)
return updated_vnf_mapping
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]
if 'policy' in nfp['properties']:
policy = nfp['properties']['policy']
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")
validation_list = []
for item in policy['criteria']:
if item.get('name') is None:
LOG.warning('The unnamed classifier approach'
' will be deprecated in subsequent'
' releases')
validation_list.append(item)
else:
validation_list.append(item['classifier'])
self._validate_criteria(validation_list)
classifiers = []
for criteria in policy['criteria']:
match = dict()
if criteria.get('name') is None:
criteria_dict = criteria.copy()
else:
criteria_dict = criteria['classifier'].copy()
for key, val in criteria_dict.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))
classifiers.append({'name': criteria.get('name'),
'match': match})
return classifiers
else:
return []
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, path_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):
nfp_query = (self._model_query(context, VnffgNfp).
filter(VnffgNfp.id == nfp_dict['id']).
filter(VnffgNfp.status == constants.PENDING_CREATE).
one())
nfp_query.update({'path_id': path_id})
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, 'path_id': path_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):
nfp_dict = self.get_nfp(context, nfp_id)
sfc_id = nfp_dict['chain_id']
with context.session.begin(subtransactions=True):
for classifier_id in nfp_dict['classifier_ids']:
query_cls = (self._model_query(context, VnffgClassifier).
filter(VnffgClassifier.id == classifier_id))
query_cls.update({'status': status})
query_chain = (self._model_query(context, VnffgChain).
filter(VnffgChain.id == sfc_id))
query_chain.update({'status': status})
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', 'ns_id',
'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_status_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_pre(self, context, vnffg, vnffg_id, vnffg_old):
vnffg = vnffg['vnffg']
del vnffg['symmetrical']
if vnffg.get('vnffgd_template') is None:
try:
return self._update_vnffg_without_template(context, vnffg_old,
vnffg, vnffg_id)
except (nfvo.VnfMappingNotFoundException,
nfvo.VnfMappingNotValidException) as e:
raise e
with context.session.begin(subtransactions=True):
# Templates
template_db_new = self._get_resource(context, VnffgTemplate,
vnffg['vnffgd_id'])
LOG.debug('vnffg new template %s', template_db_new)
template_db_old = self._get_resource(context, VnffgTemplate,
vnffg_old['vnffgd_id'])
LOG.debug('vnffg old template %s', template_db_old)
self._parametrize_topology_template(vnffg, template_db_new)
# VNF-Members
vnf_members_new = self._get_vnffg_property(
template_db_new.template, 'constituent_vnfs')
LOG.debug('New Constituent VNFs: %s', vnf_members_new)
vnf_members_old = self._get_vnffg_property(
template_db_old.template, 'constituent_vnfs')
LOG.debug('Old Constituent VNFs: %s', vnf_members_old)
if set(vnf_members_new) == set(vnf_members_old):
if vnffg.get('vnf_mapping') is None:
final_vnf_mapping = vnffg_old['vnf_mapping']
else:
try:
self._validate_vnfd_in_vnf_mapping(
vnffg['vnf_mapping'], vnf_members_new)
except (nfvo.VnfMappingNotFoundException,
nfvo.VnfMappingNotValidException) as e:
raise e
updated_vnf_mapping = \
self._combine_current_and_new_vnf_mapping(
context, vnffg['vnf_mapping'],
vnffg_old['vnf_mapping'])
final_vnf_mapping = self._get_vnf_mapping(
context, updated_vnf_mapping, vnf_members_new)
else:
final_vnf_mapping = self._get_vnf_mapping(context, vnffg.get(
'vnf_mapping'),
vnf_members_new)
LOG.debug('VNF Mapping: %s', final_vnf_mapping)
# Update the vnffg with the new template.
query_vnffg = (self._model_query(context, Vnffg).
filter(Vnffg.id == vnffg_old['id']).
filter(Vnffg.status == constants.PENDING_UPDATE))
query_vnffg.update({'vnf_mapping': final_vnf_mapping,
'vnffgd_id': vnffg['vnffgd_id'],
'description': template_db_new.description,
'attributes': template_db_new.get('template')})
# Delete the old_vnffgd_template if template_source is 'inline'
if template_db_old.template_source == 'inline':
self.delete_vnffgd(context, vnffg_old['vnffgd_id'])
# update NFP
nfp_dict_old = self.get_nfp(context, vnffg_old['forwarding_paths'])
LOG.debug('Current NFP: %s', nfp_dict_old)
nfp_dict_new = self._update_nfp_pre(template_db_new, nfp_dict_old)
LOG.debug('New NFP: %s', nfp_dict_new)
query_nfp = (self._model_query(context, VnffgNfp).
filter(VnffgNfp.id == nfp_dict_old['id']).
filter(VnffgNfp.status == constants.PENDING_UPDATE))
query_nfp.update(nfp_dict_new)
# update chain
chain_old = self.get_sfc(context, nfp_dict_old['chain_id'])
LOG.debug('Current chain: %s', chain_old)
chain_new = self._create_port_chain(context, final_vnf_mapping,
template_db_new,
nfp_dict_new['name'])
LOG.debug('New chain: %s', chain_new)
# to check if it is updated
update_chain = self._set_updated_chain(chain_old['chain'],
chain_new)
if update_chain:
query_chain = (self._model_query(context, VnffgChain).
filter(VnffgChain.id == chain_old['id']).
filter(VnffgChain.status == constants.
PENDING_UPDATE))
query_chain.update({'chain': chain_new,
'path_id': nfp_dict_new['path_id']})
# update classifiers
classifiers_old = []
for classifier_id in nfp_dict_old['classifier_ids']:
classifiers_old.append(self.
get_classifier(context,
classifier_id,
fields=['name', 'match', 'id']))
classifiers_new = self._policy_to_acl_criteria(context,
template_db_new,
nfp_dict_new['name'],
final_vnf_mapping)
try:
classifiers_update, classifiers_delete = \
self._find_classifiers_to_update(classifiers_old,
classifiers_new)
except nfvo.UpdateVnffgException as e:
raise e
for clsfr in classifiers_update:
if clsfr.get('id'):
for item in MATCH_DB_KEY_LIST:
if clsfr['match'].get(item) is None:
clsfr['match'][item] = None
query_match = (self._model_query(context,
ACLMatchCriteria).
filter(ACLMatchCriteria.vnffgc_id == clsfr['id']))
query_match.update(clsfr['match'])
else:
classifier_id = uuidutils.generate_uuid()
sfcc_db = VnffgClassifier(id=classifier_id,
name=clsfr['name'],
tenant_id=vnffg_old['tenant_id'],
status=constants.PENDING_CREATE,
nfp_id=nfp_dict_old['id'],
chain_id=chain_old['id'])
context.session.add(sfcc_db)
match_db = ACLMatchCriteria(
id=uuidutils.generate_uuid(),
vnffgc_id=classifier_id,
**clsfr['match'])
context.session.add(match_db)
for clsfr in classifiers_delete:
query_clsfr = (self._model_query(context, VnffgClassifier).
filter(VnffgClassifier.id == clsfr['id']).
filter(VnffgClassifier.status == constants.
PENDING_UPDATE))
query_clsfr.update({'status': constants.PENDING_DELETE})
return self.get_vnffg(context, vnffg_id)
def _find_classifiers_to_update(self, current_classifiers,
new_classifiers):
update_classifiers = []
delete_classifiers = []
names_list = []
for new_clsfr in new_classifiers:
found_name = False
if new_clsfr['name'] is None:
LOG.error('VNFFG update requires named classifiers')
raise nfvo.UpdateVnffgException(
message="Failed to update VNFFG")
for cur_clsfr in current_classifiers:
if cur_clsfr['name'] == new_clsfr['name']:
new_clsfr['id'] = cur_clsfr['id']
names_list.append(new_clsfr['name'])
update_classifiers.append(new_clsfr)
found_name = True
break
if not found_name:
names_list.append(new_clsfr['name'])
update_classifiers.append(new_clsfr)
for cur_clsfr in current_classifiers:
if cur_clsfr['name'] not in names_list:
delete_classifiers.append(cur_clsfr)
return update_classifiers, delete_classifiers
def _set_updated_chain(self, current_chain, new_chain):
if len(current_chain) != len(new_chain):
return True
else:
for i, item in enumerate(current_chain):
cp_vnf = new_chain[i]
if (cp_vnf['name'] == item['name'] and
cp_vnf['connection_points'] == item[
'connection_points']):
continue
else:
return True
return False
def _update_vnffg_without_template(self, context, old_vnffg, new_vnffg,
vnffg_id):
template_db = self._get_resource(context, VnffgTemplate,
old_vnffg['vnffgd_id'])
vnfd_members = self._get_vnffg_property(template_db.template,
'constituent_vnfs')
nfp = self.get_nfp(context, old_vnffg['forwarding_paths'])
chain_dict = self.get_sfc(context, nfp['chain_id'])
try:
self._validate_vnfd_in_vnf_mapping(new_vnffg.get('vnf_mapping'),
vnfd_members)
except (nfvo.VnfMappingNotFoundException,
nfvo.VnfMappingNotValidException) as e:
raise e
combined_vnf_mapping = self._combine_current_and_new_vnf_mapping(
context, new_vnffg['vnf_mapping'], old_vnffg['vnf_mapping'])
new_vnffg['vnf_mapping'] = self._get_vnf_mapping(context,
combined_vnf_mapping,
vnfd_members)
new_chain = self._create_port_chain(context,
new_vnffg['vnf_mapping'],
template_db,
nfp['name'])
LOG.debug('chain update: %s', new_chain)
query_vnffg = (self._model_query(context, Vnffg).
filter(Vnffg.id == old_vnffg['id']).
filter(Vnffg.status == constants.PENDING_UPDATE))
query_vnffg.update({'vnf_mapping': new_vnffg['vnf_mapping']})
query_chain = (self._model_query(context, VnffgChain).
filter(VnffgChain.id == chain_dict['id']).
filter(VnffgChain.status == constants.
PENDING_UPDATE))
query_chain.update({'chain': new_chain})
return self.get_vnffg(context, vnffg_id)
def _update_nfp_pre(self, template_db, nfp_dict_old):
template_new = template_db.template['vnffgd']['topology_template']
nfp_dict_new = dict()
vnffg_name = list(template_new['groups'].keys())[0]
nfp_dict_new['name'] = template_new['groups'][vnffg_name]['members'][0]
nfp_dict_new['path_id'] = template_new['node_templates'][nfp_dict_new[
'name']]['properties'].get('id')
if not nfp_dict_new['path_id']:
nfp_dict_new['path_id'] = nfp_dict_old['path_id']
return nfp_dict_new
def _update_vnffg_post(self, context, n_sfc_chain_id,
classifiers_map, vnffg_dict):
"""Updates the status and the n-sfc instance_ids in the db
:param context: SQL Session Context
:param n_sfc_chain_id: Id of port-chain in n-sfc side
:param classifiers_map: classifier and instance Ids map
:param vnffg_dict: vnffg dictionary
:return: None
"""
nfp_dict = self.get_nfp(context, vnffg_dict['forwarding_paths'])
sfc_id = nfp_dict['chain_id']
with context.session.begin(subtransactions=True):
query_chain = (self._model_query(context, VnffgChain).
filter(VnffgChain.id == sfc_id).
filter(VnffgChain.status == constants.PENDING_UPDATE).one())
if n_sfc_chain_id is None:
query_chain.update({'status': constants.ERROR})
else:
query_chain.update({'status': constants.ACTIVE})
for clsfr_id in nfp_dict['classifier_ids']:
query_clsfr = (self._model_query(context, VnffgClassifier).
filter(VnffgClassifier.id == clsfr_id))
if classifiers_map.get(clsfr_id):
query_clsfr.update({
'instance_id': classifiers_map[clsfr_id]})
if classifiers_map[clsfr_id]:
query_clsfr.update({'status': constants.ACTIVE})
else:
query_clsfr.update({'status': constants.ERROR})
else:
# Deletion of unused Match criterias which are
# not longer required due to the update classifier
# procedure.
query_match = (
self._model_query(context, ACLMatchCriteria).
filter(ACLMatchCriteria.vnffgc_id == clsfr_id))
query_match.delete()
query_clsfr.delete()
def _update_vnffg_status_post(self, context, vnffg, error=False,
db_state=constants.ERROR):
nfp = self.get_nfp(context, vnffg['forwarding_paths'])
chain = self.get_sfc(context, nfp['chain_id'])
if error:
if db_state == constants.ACTIVE:
self._update_all_status(context, vnffg['id'], nfp['id'],
constants.ACTIVE)
else:
self._update_all_status(context, vnffg['id'], nfp['id'],
constants.ERROR)
else:
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 _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)
ns_id = vnffg.get('ns_id')
if ns_id:
ns_db = self._get_resource(context, NS, ns_id)
# If network service is not in pending_delete status,
# raise error when delete vnffg.
if ns_db['status'] != constants.PENDING_DELETE:
raise nfvo.VnffgInUseNS(vnffg_id=vnffg_id,
ns_id=vnffg.get('ns_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 _get_symmetrical_template(self, context, vnffg):
fp_prop = self._get_fp_properties(context, vnffg)
return fp_prop.get('symmetrical', False)
def _get_correlation_template(self, context, vnffg):
fp_prop = self._get_fp_properties(context, vnffg)
return fp_prop.get('correlation', 'mpls')
def _get_fp_properties(self, context, vnffg):
vnffgd_topo = None
if vnffg.get('vnffgd_template'):
vnffgd_topo = vnffg['vnffgd_template']['topology_template']
elif vnffg.get('vnffgd_id'):
vnffgd_template = self.get_vnffgd(context, vnffg.get('vnffgd_id'))
vnffgd_topo = vnffgd_template['template']['vnffgd'][
'topology_template']
vnffg_name = list(vnffgd_topo['groups'].keys())[0]
nfp_name = vnffgd_topo['groups'][vnffg_name]['members'][0]
fp_prop = vnffgd_topo['node_templates'][nfp_name]['properties']
return fp_prop
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', 'name', '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