Add MESO component that allows:
- Apmec to collaborate with other orchestration frameworks (e.g, NFV framework) - for oprators to excecute smart placement decisions of MEC applications Change-Id: I28fe23029f11632f1909967238b9fd440aa6f936
This commit is contained in:
parent
c41e2d080d
commit
bff90fa0b1
356
apmec/db/meso/meso_db.py
Normal file
356
apmec/db/meso/meso_db.py
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
# 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 datetime import datetime
|
||||||
|
|
||||||
|
from oslo_db.exception import DBDuplicateEntry
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import timeutils
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
from sqlalchemy.orm import exc as orm_exc
|
||||||
|
from sqlalchemy import schema
|
||||||
|
|
||||||
|
from apmec.common import exceptions
|
||||||
|
from apmec.db.common_services import common_services_db_plugin
|
||||||
|
from apmec.db import db_base
|
||||||
|
from apmec.db import model_base
|
||||||
|
from apmec.db import models_v1
|
||||||
|
from apmec.db import types
|
||||||
|
from apmec.extensions import meso
|
||||||
|
from apmec.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)
|
||||||
|
CREATE_STATES = (constants.PENDING_CREATE, constants.DEAD)
|
||||||
|
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
# db tables
|
||||||
|
|
||||||
|
class MESD(model_base.BASE, models_v1.HasId, models_v1.HasTenant,
|
||||||
|
models_v1.Audit):
|
||||||
|
"""Represents MESD to create MES."""
|
||||||
|
|
||||||
|
__tablename__ = 'mesd'
|
||||||
|
# Descriptive name
|
||||||
|
name = sa.Column(sa.String(255), nullable=False)
|
||||||
|
description = sa.Column(sa.Text)
|
||||||
|
# Mesd template source - onboarded
|
||||||
|
template_source = sa.Column(sa.String(255), server_default='onboarded')
|
||||||
|
mesd_mapping = sa.Column(types.Json, nullable=True)
|
||||||
|
# (key, value) pair to spin up
|
||||||
|
attributes = orm.relationship('MESDAttribute',
|
||||||
|
backref='mesd')
|
||||||
|
|
||||||
|
__table_args__ = (
|
||||||
|
schema.UniqueConstraint(
|
||||||
|
"tenant_id",
|
||||||
|
"name",
|
||||||
|
name="uniq_mesd0tenant_id0name"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class MESDAttribute(model_base.BASE, models_v1.HasId):
|
||||||
|
"""Represents attributes necessary for creation of mes in (key, value) pair
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = 'mesd_attribute'
|
||||||
|
mesd_id = sa.Column(types.Uuid, sa.ForeignKey('mesd.id'),
|
||||||
|
nullable=False)
|
||||||
|
key = sa.Column(sa.String(255), nullable=False)
|
||||||
|
value = sa.Column(sa.TEXT(65535), nullable=True)
|
||||||
|
|
||||||
|
|
||||||
|
class MES(model_base.BASE, models_v1.HasId, models_v1.HasTenant,
|
||||||
|
models_v1.Audit):
|
||||||
|
"""Represents network services that deploys services.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = 'mes'
|
||||||
|
mesd_id = sa.Column(types.Uuid, sa.ForeignKey('mesd.id'))
|
||||||
|
mesd = orm.relationship('MESD')
|
||||||
|
mes_mapping = sa.Column(types.Json, nullable=True)
|
||||||
|
reused = sa.Column(types.Json, nullable=True)
|
||||||
|
name = sa.Column(sa.String(255), nullable=False)
|
||||||
|
description = sa.Column(sa.Text, nullable=True)
|
||||||
|
|
||||||
|
# Dict of MEA details that network service launches
|
||||||
|
mea_ids = sa.Column(sa.TEXT(65535), nullable=True)
|
||||||
|
|
||||||
|
# Dict of mgmt urls that network servic launches
|
||||||
|
mgmt_urls = sa.Column(sa.TEXT(65535), nullable=True)
|
||||||
|
|
||||||
|
status = sa.Column(sa.String(64), nullable=False)
|
||||||
|
vim_id = sa.Column(types.Uuid, sa.ForeignKey('vims.id'), nullable=False)
|
||||||
|
error_reason = sa.Column(sa.Text, nullable=True)
|
||||||
|
|
||||||
|
__table_args__ = (
|
||||||
|
schema.UniqueConstraint(
|
||||||
|
"tenant_id",
|
||||||
|
"name",
|
||||||
|
name="uniq_mes0tenant_id0name"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class MESOPluginDb(meso.MESOPluginBase, db_base.CommonDbMixin):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(MESOPluginDb, self).__init__()
|
||||||
|
self._cos_db_plg = common_services_db_plugin.CommonServicesPluginDb()
|
||||||
|
|
||||||
|
def _get_resource(self, context, model, id):
|
||||||
|
try:
|
||||||
|
return self._get_by_id(context, model, id)
|
||||||
|
except orm_exc.NoResultFound:
|
||||||
|
if issubclass(model, MESD):
|
||||||
|
raise meso.MESDNotFound(mesd_id=id)
|
||||||
|
if issubclass(model, MES):
|
||||||
|
raise meso.MESNotFound(mes_id=id)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def _get_mes_db(self, context, mes_id, current_statuses, new_status):
|
||||||
|
try:
|
||||||
|
mes_db = (
|
||||||
|
self._model_query(context, MES).
|
||||||
|
filter(MES.id == mes_id).
|
||||||
|
filter(MES.status.in_(current_statuses)).
|
||||||
|
with_lockmode('update').one())
|
||||||
|
except orm_exc.NoResultFound:
|
||||||
|
raise meso.MESNotFound(mes_id=mes_id)
|
||||||
|
mes_db.update({'status': new_status})
|
||||||
|
return mes_db
|
||||||
|
|
||||||
|
def _make_attributes_dict(self, attributes_db):
|
||||||
|
return dict((attr.key, attr.value) for attr in attributes_db)
|
||||||
|
|
||||||
|
def _make_mesd_dict(self, mesd, fields=None):
|
||||||
|
res = {
|
||||||
|
'attributes': self._make_attributes_dict(mesd['attributes']),
|
||||||
|
}
|
||||||
|
key_list = ('id', 'tenant_id', 'name', 'description', 'mesd_mapping',
|
||||||
|
'created_at', 'updated_at', 'template_source')
|
||||||
|
res.update((key, mesd[key]) for key in key_list)
|
||||||
|
return self._fields(res, fields)
|
||||||
|
|
||||||
|
def _make_dev_attrs_dict(self, dev_attrs_db):
|
||||||
|
return dict((arg.key, arg.value) for arg in dev_attrs_db)
|
||||||
|
|
||||||
|
def _make_mes_dict(self, mes_db, fields=None):
|
||||||
|
LOG.debug('mes_db %s', mes_db)
|
||||||
|
res = {}
|
||||||
|
key_list = ('id', 'tenant_id', 'mesd_id', 'name', 'description', 'mes_mapping', # noqa
|
||||||
|
'mea_ids', 'status', 'mgmt_urls', 'error_reason', 'reused',
|
||||||
|
'vim_id', 'created_at', 'updated_at')
|
||||||
|
res.update((key, mes_db[key]) for key in key_list)
|
||||||
|
return self._fields(res, fields)
|
||||||
|
|
||||||
|
def create_mesd(self, context, mesd):
|
||||||
|
mesd = mesd['mesd']
|
||||||
|
LOG.debug('mesd %s', mesd)
|
||||||
|
tenant_id = self._get_tenant_id_for_create(context, mesd)
|
||||||
|
template_source = mesd.get('template_source')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
mesd_id = uuidutils.generate_uuid()
|
||||||
|
mesd_db = MESD(
|
||||||
|
id=mesd_id,
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
name=mesd.get('name'),
|
||||||
|
description=mesd.get('description'),
|
||||||
|
mesd_mapping=mesd.get('mesd_mapping'),
|
||||||
|
deleted_at=datetime.min,
|
||||||
|
template_source=template_source)
|
||||||
|
context.session.add(mesd_db)
|
||||||
|
for (key, value) in mesd.get('attributes', {}).items():
|
||||||
|
attribute_db = MESDAttribute(
|
||||||
|
id=uuidutils.generate_uuid(),
|
||||||
|
mesd_id=mesd_id,
|
||||||
|
key=key,
|
||||||
|
value=value)
|
||||||
|
context.session.add(attribute_db)
|
||||||
|
except DBDuplicateEntry as e:
|
||||||
|
raise exceptions.DuplicateEntity(
|
||||||
|
_type="mesd",
|
||||||
|
entry=e.columns)
|
||||||
|
LOG.debug('mesd_db %(mesd_db)s %(attributes)s ',
|
||||||
|
{'mesd_db': mesd_db,
|
||||||
|
'attributes': mesd_db.attributes})
|
||||||
|
mesd_dict = self._make_mesd_dict(mesd_db)
|
||||||
|
LOG.debug('mesd_dict %s', mesd_dict)
|
||||||
|
self._cos_db_plg.create_event(
|
||||||
|
context, res_id=mesd_dict['id'],
|
||||||
|
res_type=constants.RES_TYPE_MESD,
|
||||||
|
res_state=constants.RES_EVT_ONBOARDED,
|
||||||
|
evt_type=constants.RES_EVT_CREATE,
|
||||||
|
tstamp=mesd_dict[constants.RES_EVT_CREATED_FLD])
|
||||||
|
return mesd_dict
|
||||||
|
|
||||||
|
def delete_mesd(self,
|
||||||
|
context,
|
||||||
|
mesd_id,
|
||||||
|
soft_delete=True):
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
mess_db = context.session.query(MES).filter_by(
|
||||||
|
mesd_id=mesd_id).first()
|
||||||
|
if mess_db is not None and mess_db.deleted_at is None:
|
||||||
|
raise meso.MESDInUse(mesd_id=mesd_id)
|
||||||
|
|
||||||
|
mesd_db = self._get_resource(context, MESD,
|
||||||
|
mesd_id)
|
||||||
|
if soft_delete:
|
||||||
|
mesd_db.update({'deleted_at': timeutils.utcnow()})
|
||||||
|
self._cos_db_plg.create_event(
|
||||||
|
context, res_id=mesd_db['id'],
|
||||||
|
res_type=constants.RES_TYPE_MESD,
|
||||||
|
res_state=constants.RES_EVT_NA_STATE,
|
||||||
|
evt_type=constants.RES_EVT_DELETE,
|
||||||
|
tstamp=mesd_db[constants.RES_EVT_DELETED_FLD])
|
||||||
|
else:
|
||||||
|
context.session.query(MESDAttribute).filter_by(
|
||||||
|
mesd_id=mesd_id).delete()
|
||||||
|
context.session.delete(mesd_db)
|
||||||
|
|
||||||
|
def get_mesd(self, context, mesd_id, fields=None):
|
||||||
|
mesd_db = self._get_resource(context, MESD, mesd_id)
|
||||||
|
return self._make_mesd_dict(mesd_db)
|
||||||
|
|
||||||
|
def get_mesds(self, context, filters, fields=None):
|
||||||
|
if ('template_source' in filters) and \
|
||||||
|
(filters['template_source'][0] == 'all'):
|
||||||
|
filters.pop('template_source')
|
||||||
|
return self._get_collection(context, MESD,
|
||||||
|
self._make_mesd_dict,
|
||||||
|
filters=filters, fields=fields)
|
||||||
|
|
||||||
|
# reference implementation. needs to be overrided by subclass
|
||||||
|
def create_mes(self, context, mes):
|
||||||
|
LOG.debug('mes %s', mes)
|
||||||
|
mes = mes['mes']
|
||||||
|
tenant_id = self._get_tenant_id_for_create(context, mes)
|
||||||
|
mesd_id = mes['mesd_id']
|
||||||
|
vim_id = mes['vim_id']
|
||||||
|
name = mes.get('name')
|
||||||
|
mes_mapping = mes['mes_mapping']
|
||||||
|
mes_id = uuidutils.generate_uuid()
|
||||||
|
try:
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
mesd_db = self._get_resource(context, MESD,
|
||||||
|
mesd_id)
|
||||||
|
mes_db = MES(id=mes_id,
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
name=name,
|
||||||
|
description=mesd_db.description,
|
||||||
|
mea_ids=None,
|
||||||
|
status=constants.PENDING_CREATE,
|
||||||
|
mes_mapping=mes_mapping,
|
||||||
|
reused=None,
|
||||||
|
mgmt_urls=None,
|
||||||
|
mesd_id=mesd_id,
|
||||||
|
vim_id=vim_id,
|
||||||
|
error_reason=None,
|
||||||
|
deleted_at=datetime.min)
|
||||||
|
context.session.add(mes_db)
|
||||||
|
except DBDuplicateEntry as e:
|
||||||
|
raise exceptions.DuplicateEntity(
|
||||||
|
_type="mes",
|
||||||
|
entry=e.columns)
|
||||||
|
return self._make_mes_dict(mes_db)
|
||||||
|
|
||||||
|
def create_mes_post(self, context, mes_id,
|
||||||
|
mes_status, error_reason, args):
|
||||||
|
LOG.debug('mes ID %s', mes_id)
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
mes_db = self._get_resource(context, MES,
|
||||||
|
mes_id)
|
||||||
|
mes_db.update({'status': mes_status})
|
||||||
|
mes_db.update({'error_reason': error_reason})
|
||||||
|
mes_db.update({'updated_at': timeutils.utcnow()})
|
||||||
|
mes_db.update({'reused': args.get("NS")})
|
||||||
|
mes_dict = self._make_mes_dict(mes_db)
|
||||||
|
return mes_dict
|
||||||
|
|
||||||
|
# reference implementation. needs to be overrided by subclass
|
||||||
|
def delete_mes(self, context, mes_id):
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
mes_db = self._get_mes_db(
|
||||||
|
context, mes_id, _ACTIVE_UPDATE_ERROR_DEAD,
|
||||||
|
constants.PENDING_DELETE)
|
||||||
|
deleted_mes_db = self._make_mes_dict(mes_db)
|
||||||
|
return deleted_mes_db
|
||||||
|
|
||||||
|
def delete_mes_post(self, context, mes_id,
|
||||||
|
error_reason, soft_delete=True, error=False):
|
||||||
|
mes = self.get_mes(context, mes_id)
|
||||||
|
mesd_id = mes.get('mesd_id')
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
query = (
|
||||||
|
self._model_query(context, MES).
|
||||||
|
filter(MES.id == mes_id).
|
||||||
|
filter(MES.status == constants.PENDING_DELETE))
|
||||||
|
if error:
|
||||||
|
query.update({'status': constants.ERROR})
|
||||||
|
if error_reason:
|
||||||
|
query.update({'error_reason': error_reason})
|
||||||
|
else:
|
||||||
|
if soft_delete:
|
||||||
|
deleted_time_stamp = timeutils.utcnow()
|
||||||
|
query.update({'deleted_at': deleted_time_stamp})
|
||||||
|
|
||||||
|
else:
|
||||||
|
query.delete()
|
||||||
|
template_db = self._get_resource(context, MESD, mesd_id)
|
||||||
|
if template_db.get('template_source') == 'inline':
|
||||||
|
self.delete_mesd(context, mesd_id)
|
||||||
|
|
||||||
|
def get_mes(self, context, mes_id, fields=None):
|
||||||
|
mes_db = self._get_resource(context, MES, mes_id)
|
||||||
|
return self._make_mes_dict(mes_db)
|
||||||
|
|
||||||
|
def get_mess(self, context, filters=None, fields=None):
|
||||||
|
return self._get_collection(context, MES,
|
||||||
|
self._make_mes_dict,
|
||||||
|
filters=filters, fields=fields)
|
||||||
|
|
||||||
|
def _update_mes_pre(self, context, mes_id):
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
mes_db = self._get_mes_db(context, mes_id, _ACTIVE_UPDATE, constants.PENDING_UPDATE) # noqa
|
||||||
|
return self._make_mes_dict(mes_db)
|
||||||
|
|
||||||
|
def _update_mes_post(self, context, mes_id, error_reason, mes_status, args): # noqa
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
mes_db = self._get_resource(context, MES, mes_id)
|
||||||
|
mes_db.update({'status': mes_status})
|
||||||
|
mes_db.update({'error_reason': error_reason})
|
||||||
|
mes_db.update({'updated_at': timeutils.utcnow()})
|
||||||
|
mes_db.update({'reused': args.get('NS')})
|
||||||
|
mes_dict = self._make_mes_dict(mes_db)
|
||||||
|
return mes_dict
|
||||||
|
|
||||||
|
def _update_mes_status(self, context, mes_id, new_status):
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
mes_db = self._get_mes_db(context, mes_id, _ACTIVE_UPDATE, new_status) # noqa
|
||||||
|
return self._make_mes_dict(mes_db)
|
||||||
|
|
||||||
|
def update_mes(self, context, mes_id, mes):
|
||||||
|
self._update_mes_pre(context, mes_id)
|
||||||
|
self._update_mes_post(context, mes_id, constants.ACTIVE, None)
|
@ -1,61 +0,0 @@
|
|||||||
# 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 abc
|
|
||||||
import six
|
|
||||||
|
|
||||||
from apmec.common import exceptions
|
|
||||||
from apmec.services import service_base
|
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
|
||||||
class MESPluginBase(service_base.MECPluginBase):
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_mesd(self, context, mesd):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_mesd(self, context, mesd_id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_mesd(self, context, mesd_id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_mesds(self, context, filters=None, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_mes(self, context, mes):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_mess(self, context, filters=None, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_mes(self, context, mes_id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_mes(self, context, mes_id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MESDNotFound(exceptions.NotFound):
|
|
||||||
message = _('MESD %(mesd_id)s could not be found')
|
|
||||||
|
|
||||||
|
|
||||||
class MESNotFound(exceptions.NotFound):
|
|
||||||
message = _('MES %(mes_id)s could not be found')
|
|
320
apmec/extensions/meso.py
Normal file
320
apmec/extensions/meso.py
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
# Copyright 2016 Brocade Communications Systems 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 abc
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
from apmec._i18n import _
|
||||||
|
from apmec.api import extensions
|
||||||
|
from apmec.api.v1 import attributes as attr
|
||||||
|
from apmec.api.v1 import resource_helper
|
||||||
|
from apmec.common import exceptions
|
||||||
|
from apmec.plugins.common import constants
|
||||||
|
from apmec.services import service_base
|
||||||
|
|
||||||
|
|
||||||
|
class MESDInUse(exceptions.InUse):
|
||||||
|
message = _('MESD %(mesd_id)s is still in use')
|
||||||
|
|
||||||
|
|
||||||
|
class MESInUse(exceptions.InUse):
|
||||||
|
message = _('MES %(mes_id)s is still in use')
|
||||||
|
|
||||||
|
|
||||||
|
class NoTasksException(exceptions.ApmecException):
|
||||||
|
message = _('No tasks to run for %(action)s on %(resource)s')
|
||||||
|
|
||||||
|
|
||||||
|
class MESDNotFound(exceptions.NotFound):
|
||||||
|
message = _('MESD %(mesd_id)s could not be found')
|
||||||
|
|
||||||
|
|
||||||
|
class MESNotFound(exceptions.NotFound):
|
||||||
|
message = _('MES %(mes_id)s could not be found')
|
||||||
|
|
||||||
|
|
||||||
|
class ToscaParserFailed(exceptions.InvalidInput):
|
||||||
|
message = _("tosca-parser failed: - %(error_msg_details)s")
|
||||||
|
|
||||||
|
|
||||||
|
class NSDNotFound(exceptions.NotFound):
|
||||||
|
message = _('NSD template(s) not existed for MESD %(mesd_name)')
|
||||||
|
|
||||||
|
|
||||||
|
class VNFFGDNotFound(exceptions.NotFound):
|
||||||
|
message = _('VNFFGD template(s) not existed for MESD %(mesd_name)')
|
||||||
|
|
||||||
|
|
||||||
|
class MECDriverNotfound(exceptions.NotFound):
|
||||||
|
message = _('MEC driver not specified for the MESD %(mesd_name)')
|
||||||
|
|
||||||
|
|
||||||
|
class NFVDriverNotFound(exceptions.NotFound):
|
||||||
|
message = _('NFV driver is not specified for the MESD %(mesd_name)')
|
||||||
|
|
||||||
|
|
||||||
|
RESOURCE_ATTRIBUTE_MAP = {
|
||||||
|
'mesds': {
|
||||||
|
'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,
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'allow_post': True,
|
||||||
|
'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'is_visible': True,
|
||||||
|
'default': '',
|
||||||
|
},
|
||||||
|
'mesd_mapping': {
|
||||||
|
'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'convert_to': attr.convert_none_to_empty_dict,
|
||||||
|
'validate': {'type:dict_or_nodata': None},
|
||||||
|
'is_visible': True,
|
||||||
|
'default': '',
|
||||||
|
},
|
||||||
|
'created_at': {
|
||||||
|
'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'is_visible': True,
|
||||||
|
},
|
||||||
|
'updated_at': {
|
||||||
|
'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'is_visible': True,
|
||||||
|
},
|
||||||
|
'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,
|
||||||
|
},
|
||||||
|
'template_source': {
|
||||||
|
'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'is_visible': True,
|
||||||
|
'default': 'onboarded'
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
'mess': {
|
||||||
|
'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,
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'allow_post': True,
|
||||||
|
'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'is_visible': True,
|
||||||
|
'default': '',
|
||||||
|
},
|
||||||
|
'created_at': {
|
||||||
|
'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'is_visible': True,
|
||||||
|
},
|
||||||
|
'updated_at': {
|
||||||
|
'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'is_visible': True,
|
||||||
|
},
|
||||||
|
'mes_mapping': {
|
||||||
|
'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'convert_to': attr.convert_none_to_empty_dict,
|
||||||
|
'validate': {'type:dict_or_nodata': None},
|
||||||
|
'is_visible': True,
|
||||||
|
'default': '',
|
||||||
|
},
|
||||||
|
'reused': {
|
||||||
|
'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'convert_to': attr.convert_none_to_empty_dict,
|
||||||
|
'validate': {'type:dict_or_nodata': None},
|
||||||
|
'is_visible': True,
|
||||||
|
'default': '',
|
||||||
|
},
|
||||||
|
'mesd_id': {
|
||||||
|
'allow_post': True,
|
||||||
|
'allow_put': False,
|
||||||
|
'validate': {'type:uuid': None},
|
||||||
|
'is_visible': True,
|
||||||
|
'default': None,
|
||||||
|
},
|
||||||
|
'vim_id': {
|
||||||
|
'allow_post': True,
|
||||||
|
'allow_put': False,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'is_visible': True,
|
||||||
|
'default': '',
|
||||||
|
},
|
||||||
|
'status': {
|
||||||
|
'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'is_visible': True,
|
||||||
|
},
|
||||||
|
'error_reason': {
|
||||||
|
'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'is_visible': True,
|
||||||
|
},
|
||||||
|
'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,
|
||||||
|
},
|
||||||
|
'mesd_template': {
|
||||||
|
'allow_post': True,
|
||||||
|
'allow_put': True,
|
||||||
|
'validate': {'type:dict_or_nodata': None},
|
||||||
|
'is_visible': True,
|
||||||
|
'default': None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Meso(extensions.ExtensionDescriptor):
|
||||||
|
@classmethod
|
||||||
|
def get_name(cls):
|
||||||
|
return 'MEC Service Orchestrator'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_alias(cls):
|
||||||
|
return 'MESO'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_description(cls):
|
||||||
|
return "Extension for MEC Service Orchestrator"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_namespace(cls):
|
||||||
|
return 'http://wiki.openstack.org/Apmec'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_updated(cls):
|
||||||
|
return "2015-12-21T10:00:00-00:00"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_resources(cls):
|
||||||
|
special_mappings = {}
|
||||||
|
plural_mappings = resource_helper.build_plural_mappings(
|
||||||
|
special_mappings, RESOURCE_ATTRIBUTE_MAP)
|
||||||
|
attr.PLURALS.update(plural_mappings)
|
||||||
|
return resource_helper.build_resource_info(
|
||||||
|
plural_mappings, RESOURCE_ATTRIBUTE_MAP, constants.MESO,
|
||||||
|
translate_name=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_plugin_interface(cls):
|
||||||
|
return MESOPluginBase
|
||||||
|
|
||||||
|
def update_attributes_map(self, attributes):
|
||||||
|
super(Meso, self).update_attributes_map(
|
||||||
|
attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)
|
||||||
|
|
||||||
|
def get_extended_resources(self, version):
|
||||||
|
version_map = {'1.0': RESOURCE_ATTRIBUTE_MAP}
|
||||||
|
return version_map.get(version, {})
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class MESOPluginBase(service_base.MECPluginBase):
|
||||||
|
def get_plugin_name(self):
|
||||||
|
return constants.MESO
|
||||||
|
|
||||||
|
def get_plugin_type(self):
|
||||||
|
return constants.MESO
|
||||||
|
|
||||||
|
def get_plugin_description(self):
|
||||||
|
return 'Apmec MEC service Orchestrator plugin'
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def create_mesd(self, context, mesd):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def delete_mesd(self, context, mesd_id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_mesd(self, context, mesd_id, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_mesds(self, context, filters=None, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def create_mes(self, context, mes):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_mess(self, context, filters=None, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_mes(self, context, mes_id, fields=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def delete_mes(self, context, mes_id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def update_mes(self, context, mes_id, mes):
|
||||||
|
pass
|
0
apmec/meso/__init__.py
Normal file
0
apmec/meso/__init__.py
Normal file
0
apmec/meso/drivers/__init__.py
Normal file
0
apmec/meso/drivers/__init__.py
Normal file
0
apmec/meso/drivers/nfv_drivers/__init__.py
Normal file
0
apmec/meso/drivers/nfv_drivers/__init__.py
Normal file
44
apmec/meso/drivers/nfv_drivers/abstract_driver.py
Normal file
44
apmec/meso/drivers/nfv_drivers/abstract_driver.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# 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 abc
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
from apmec.api import extensions
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class NfvAbstractDriver(extensions.PluginInterface):
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_type(self):
|
||||||
|
"""Get NFV Driver type
|
||||||
|
|
||||||
|
Return one of predefined types of NFV drivers.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_name(self):
|
||||||
|
"""Get NFV driver name
|
||||||
|
|
||||||
|
Return a symbolic name for the NFV driver.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_description(self):
|
||||||
|
pass
|
278
apmec/meso/drivers/nfv_drivers/tacker_driver.py
Normal file
278
apmec/meso/drivers/nfv_drivers/tacker_driver.py
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
# 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 keystoneauth1 import identity
|
||||||
|
from keystoneauth1 import session
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from apmec.meso.drivers.nfv_drivers import abstract_driver
|
||||||
|
|
||||||
|
from tackerclient.v1_0 import client as tacker_client
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class Tacker_Driver(abstract_driver.NfvAbstractDriver):
|
||||||
|
"""Driver for NFV
|
||||||
|
|
||||||
|
OpenStack driver handles interactions with local as well as
|
||||||
|
remote OpenStack instances. The driver invokes keystone service for VIM
|
||||||
|
authorization and validation. The driver is also responsible for
|
||||||
|
discovering placement attributes such as regions, availability zones
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_type(self):
|
||||||
|
return 'tacker'
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return 'OpenStack Tacker Driver'
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
return 'OpenStack Tacker Driver'
|
||||||
|
|
||||||
|
def nsd_create(self, auth_attr, nsd_dict):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.nsd_create(nsd_dict)
|
||||||
|
|
||||||
|
def nsd_get_by_name(self, auth_attr, nsd_name):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.nsd_get_by_name(nsd_name)
|
||||||
|
|
||||||
|
def nsd_get(self, auth_attr, nsd_id):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.nsd_get(nsd_id)
|
||||||
|
|
||||||
|
def ns_create(self, auth_attr, ns_dict):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.ns_create(ns_dict)
|
||||||
|
|
||||||
|
def ns_get_by_name(self, auth_attr, ns_name):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.ns_get(ns_name)
|
||||||
|
|
||||||
|
def ns_get(self, auth_attr, ns_id):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.ns_get(ns_id)
|
||||||
|
|
||||||
|
def ns_check(self, auth_attr, ns_id):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.ns_check(ns_id)
|
||||||
|
|
||||||
|
def ns_delete_by_name(self, auth_attr, ns_name):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.ns_delete(ns_name)
|
||||||
|
|
||||||
|
def ns_delete(self, auth_attr, ns_id):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.ns_delete(ns_id)
|
||||||
|
|
||||||
|
def ns_update(self, auth_attr, ns_id, ns_dict):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.ns_update(ns_id, ns_dict)
|
||||||
|
|
||||||
|
def vnfd_create(self, auth_attr, vnfd_dict):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnfd_create(vnfd_dict)
|
||||||
|
|
||||||
|
def vnf_create(self, auth_attr, vnf_dict):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnf_create(vnf_dict)
|
||||||
|
|
||||||
|
def vnf_get(self, auth_attr, vnf_id):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnf_get(vnf_id)
|
||||||
|
|
||||||
|
def vnfd_get(self, auth_attr, vnfd_id):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnfd_get(vnfd_id)
|
||||||
|
|
||||||
|
def vnffgd_get_by_name(self, auth_attr, vnffgd_name):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnffgd_get(vnffgd_name)
|
||||||
|
|
||||||
|
def vnffgd_get(self, auth_attr, vnffgd_id):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnffgd_get(vnffgd_id)
|
||||||
|
|
||||||
|
def vnffg_create(self, auth_attr, vnffg_dict):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnffg_create(vnffg_dict)
|
||||||
|
|
||||||
|
def vnffg_get_by_name(self, auth_attr, vnffg_name):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnffg_get(vnffg_name)
|
||||||
|
|
||||||
|
def vnffg_get(self, auth_attr, vnffg_id):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnffg_get(vnffg_id)
|
||||||
|
|
||||||
|
def vnffg_delete_by_name(self, auth_attr, vnffg_name):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnffg_delete(vnffg_name)
|
||||||
|
|
||||||
|
def vnffg_delete(self, auth_attr, vnffg_id):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnffg_delete(vnffg_id)
|
||||||
|
|
||||||
|
def vnffg_check(self, auth_attr, vnffg_id):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.vnffg_check(vnffg_id)
|
||||||
|
|
||||||
|
def vnffg_update(self, auth_attr, vnffg_id, vnffg_dict):
|
||||||
|
tacker_client = TackerClient(auth_attr)
|
||||||
|
return tacker_client.ns_update(vnffg_id, vnffg_dict)
|
||||||
|
|
||||||
|
|
||||||
|
class TackerClient(object):
|
||||||
|
"""Tacker Client class for VNFM and NFVO negotiation"""
|
||||||
|
|
||||||
|
def __init__(self, auth_attr):
|
||||||
|
auth = identity.Password(**auth_attr)
|
||||||
|
sess = session.Session(auth=auth)
|
||||||
|
self.client = tacker_client.Client(session=sess)
|
||||||
|
|
||||||
|
def nsd_create(self, nsd_dict):
|
||||||
|
nsd_instance = self.client.create_nsd(body=nsd_dict)
|
||||||
|
if nsd_instance:
|
||||||
|
return nsd_instance['nsd']['id']
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def nsd_get_by_name(self, nsd_name):
|
||||||
|
nsd_dict = self.client.list_nsds()
|
||||||
|
nsd_list = nsd_dict['nsds']
|
||||||
|
nsd_dict = None
|
||||||
|
for nsd in nsd_list:
|
||||||
|
if nsd['name'] == nsd_name:
|
||||||
|
nsd_dict = nsd
|
||||||
|
return nsd_dict
|
||||||
|
|
||||||
|
def nsd_get(self, nsd_id):
|
||||||
|
nsd_dict = self.client.show_nsd(nsd_id)
|
||||||
|
return nsd_dict['nsd']
|
||||||
|
|
||||||
|
def ns_create(self, ns_dict):
|
||||||
|
ns_instance = self.client.create_ns(body=ns_dict)
|
||||||
|
if ns_instance:
|
||||||
|
return ns_instance['ns']['id']
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def ns_get_by_name(self, ns_name):
|
||||||
|
ns_dict = self.client.list_nsds()
|
||||||
|
ns_list = ns_dict['nss']
|
||||||
|
ns_id = None
|
||||||
|
for ns in ns_list:
|
||||||
|
if ns['name'] == ns_name:
|
||||||
|
ns_id = ns['id']
|
||||||
|
return ns_id
|
||||||
|
|
||||||
|
def ns_get(self, ns_id):
|
||||||
|
ns_instance = self.client.show_ns(ns_id)
|
||||||
|
return ns_instance['ns']
|
||||||
|
|
||||||
|
def ns_delete_by_name(self, ns_name):
|
||||||
|
ns_id = self.ns_get_by_name(ns_name)
|
||||||
|
if ns_id:
|
||||||
|
self.client.delete_ns(ns_id)
|
||||||
|
|
||||||
|
def ns_check(self, ns_id):
|
||||||
|
ns_dict = self.client.list_nss()
|
||||||
|
ns_list = ns_dict['nss']
|
||||||
|
check = False
|
||||||
|
for ns in ns_list:
|
||||||
|
if ns['id'] == ns_id:
|
||||||
|
check = True
|
||||||
|
return check
|
||||||
|
|
||||||
|
def ns_delete(self, ns_id):
|
||||||
|
return self.client.delete_ns(ns_id)
|
||||||
|
|
||||||
|
def ns_update(self, ns_id, ns_dict):
|
||||||
|
return self.client.update_ns(ns_id, ns_dict)
|
||||||
|
|
||||||
|
def vnfd_create(self, vnfd_dict):
|
||||||
|
vnfd_instance = self.client.create_vnfd(body=vnfd_dict)
|
||||||
|
if vnfd_instance:
|
||||||
|
return vnfd_instance['vnf']['id']
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def vnf_create(self, vnf_dict):
|
||||||
|
vnf_instance = self.client.create_vnf(body=vnf_dict)
|
||||||
|
if vnf_instance:
|
||||||
|
return vnf_instance['vnf']['id']
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def vnf_get(self, vnf_id):
|
||||||
|
vnf_instance = self.client.show_vnf(vnf_id)
|
||||||
|
return vnf_instance['vnf']
|
||||||
|
|
||||||
|
def vnfd_get(self, vnfd_id):
|
||||||
|
vnfd_instance = self.client.show_vnfd(vnfd_id)
|
||||||
|
return vnfd_instance['vnfd']
|
||||||
|
|
||||||
|
def vnffgd_get_by_name(self, vnffgd_name):
|
||||||
|
vnffgd_dict = self.client.list_vnffgds()
|
||||||
|
vnffgd_list = vnffgd_dict['vnffgds']
|
||||||
|
vnffgd_dict = None
|
||||||
|
for vnffgd in vnffgd_list:
|
||||||
|
if vnffgd['name'] == vnffgd_name:
|
||||||
|
vnffgd_dict = vnffgd
|
||||||
|
return vnffgd_dict
|
||||||
|
|
||||||
|
def vnffgd_get(self, vnffgd_id):
|
||||||
|
vnffgd_instance = self.client.show_vnffgd(vnffgd_id)
|
||||||
|
return vnffgd_instance['vnffgd']
|
||||||
|
|
||||||
|
def vnffg_create(self, vnffgd_dict):
|
||||||
|
vnffg_instance = self.client.create_vnffg(body=vnffgd_dict)
|
||||||
|
if vnffg_instance:
|
||||||
|
return vnffg_instance['vnffg']['id']
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def vnffg_get_by_name(self, vnffg_name):
|
||||||
|
vnffg_dict = self.client.list_vnffgs()
|
||||||
|
vnffg_list = vnffg_dict['vnffgs']
|
||||||
|
vnffg_id = None
|
||||||
|
for vnffg in vnffg_list:
|
||||||
|
if vnffg['name'] == vnffg_name:
|
||||||
|
vnffg_id = vnffg['id']
|
||||||
|
return vnffg_id
|
||||||
|
|
||||||
|
def vnffg_get(self, vnffg_id):
|
||||||
|
vnffg_instance = self.client.show_vnffg(vnffg_id)
|
||||||
|
return vnffg_instance['vnffg']
|
||||||
|
|
||||||
|
def vnffg_delete_by_name(self, vnffg_name):
|
||||||
|
vnffg_id = self.vnffg_get_by_name(vnffg_name)
|
||||||
|
if vnffg_id:
|
||||||
|
self.client.delete_vnffg(vnffg_id)
|
||||||
|
|
||||||
|
def vnffg_delete(self, vnffg_id):
|
||||||
|
return self.client.delete_vnffg(vnffg_id)
|
||||||
|
|
||||||
|
def vnffg_check(self, vnffg_id):
|
||||||
|
vnffg_dict = self.client.list_vnffgs()
|
||||||
|
vnffg_list = vnffg_dict['vnffgs']
|
||||||
|
check = False
|
||||||
|
for vnffg in vnffg_list:
|
||||||
|
if vnffg['id'] == vnffg_id:
|
||||||
|
check = True
|
||||||
|
return check
|
||||||
|
|
||||||
|
def vnffg_update(self, vnffg_id, vnffg_dict):
|
||||||
|
return self.client.update_ns(vnffg_id, vnffg_dict)
|
943
apmec/meso/meso_plugin.py
Normal file
943
apmec/meso/meso_plugin.py
Normal file
@ -0,0 +1,943 @@
|
|||||||
|
# Copyright 2016 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 ast
|
||||||
|
import copy
|
||||||
|
import eventlet
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import excutils
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
|
||||||
|
from apmec._i18n import _
|
||||||
|
from apmec.common import driver_manager
|
||||||
|
from apmec.common import log
|
||||||
|
from apmec.common import utils
|
||||||
|
from apmec.db.meso import meso_db
|
||||||
|
from apmec.extensions import common_services as cs
|
||||||
|
from apmec.extensions import meso
|
||||||
|
from apmec import manager
|
||||||
|
|
||||||
|
from apmec.mem import vim_client
|
||||||
|
from apmec.plugins.common import constants
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
CONF = cfg.CONF
|
||||||
|
NS_RETRIES = 30
|
||||||
|
NS_RETRY_WAIT = 6
|
||||||
|
MEC_RETRIES = 30
|
||||||
|
MEC_RETRY_WAIT = 6
|
||||||
|
VNFFG_RETRIES = 30
|
||||||
|
VNFFG_RETRY_WAIT = 6
|
||||||
|
|
||||||
|
|
||||||
|
def config_opts():
|
||||||
|
return [('meso', MesoPlugin.OPTS)]
|
||||||
|
|
||||||
|
|
||||||
|
NF_CAP_MAX = 3
|
||||||
|
VNF_LIST = ['VNF1', 'VNF2', 'VNF2', 'VNF3', 'VNF4', 'VNF5', 'VNF6']
|
||||||
|
VM_CAPA = dict()
|
||||||
|
for vnf_name in VNF_LIST:
|
||||||
|
VM_CAPA[vnf_name] = random.randint(1, NF_CAP_MAX)
|
||||||
|
|
||||||
|
|
||||||
|
class MesoPlugin(meso_db.MESOPluginDb):
|
||||||
|
"""MESO reference plugin for MESO extension
|
||||||
|
|
||||||
|
Implements the MESO extension and defines public facing APIs for VIM
|
||||||
|
operations. MESO internally invokes the appropriate VIM driver in
|
||||||
|
backend based on configured VIM types. Plugin also interacts with MEM
|
||||||
|
extension for providing the specified VIM information
|
||||||
|
"""
|
||||||
|
supported_extension_aliases = ['meso']
|
||||||
|
|
||||||
|
OPTS = [
|
||||||
|
cfg.ListOpt(
|
||||||
|
'nfv_drivers', default=['tacker'],
|
||||||
|
help=_('NFV drivers for launching NSs')),
|
||||||
|
]
|
||||||
|
cfg.CONF.register_opts(OPTS, 'meso')
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(MesoPlugin, self).__init__()
|
||||||
|
self._pool = eventlet.GreenPool()
|
||||||
|
self._nfv_drivers = driver_manager.DriverManager(
|
||||||
|
'apmec.meso.drivers',
|
||||||
|
cfg.CONF.meso.nfv_drivers)
|
||||||
|
self.vim_client = vim_client.VimClient()
|
||||||
|
|
||||||
|
def get_auth_dict(self, context):
|
||||||
|
auth = CONF.keystone_authtoken
|
||||||
|
return {
|
||||||
|
'auth_url': auth.auth_url + '/v3',
|
||||||
|
'token': context.auth_token,
|
||||||
|
'project_domain_name': auth.project_domain_name or context.domain,
|
||||||
|
'project_name': context.tenant_name
|
||||||
|
}
|
||||||
|
|
||||||
|
def spawn_n(self, function, *args, **kwargs):
|
||||||
|
self._pool.spawn_n(function, *args, **kwargs)
|
||||||
|
|
||||||
|
def _build_vim_auth(self, context, vim_info):
|
||||||
|
LOG.debug('VIM id is %s', vim_info['id'])
|
||||||
|
vim_auth = vim_info['auth_cred']
|
||||||
|
vim_auth['password'] = self._decode_vim_auth(context,
|
||||||
|
vim_info['id'],
|
||||||
|
vim_auth)
|
||||||
|
vim_auth['auth_url'] = vim_info['auth_url']
|
||||||
|
|
||||||
|
# These attributes are needless for authentication
|
||||||
|
# from keystone, so we remove them.
|
||||||
|
needless_attrs = ['key_type', 'secret_uuid']
|
||||||
|
for attr in needless_attrs:
|
||||||
|
if attr in vim_auth:
|
||||||
|
vim_auth.pop(attr, None)
|
||||||
|
return vim_auth
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def create_mesd(self, context, mesd):
|
||||||
|
mesd_data = mesd['mesd']
|
||||||
|
template = mesd_data['attributes'].get('mesd')
|
||||||
|
if isinstance(template, dict):
|
||||||
|
mesd_data['attributes']['mesd'] = yaml.safe_dump(
|
||||||
|
template)
|
||||||
|
LOG.debug('mesd %s', mesd_data)
|
||||||
|
|
||||||
|
if 'template_source' in mesd_data:
|
||||||
|
template_source = mesd_data.get('template_source')
|
||||||
|
else:
|
||||||
|
template_source = "onboarded"
|
||||||
|
mesd['mesd']['template_source'] = template_source
|
||||||
|
|
||||||
|
self._parse_template_input(context, mesd)
|
||||||
|
return super(MesoPlugin, self).create_mesd(
|
||||||
|
context, mesd)
|
||||||
|
|
||||||
|
def _parse_template_input(self, context, mesd):
|
||||||
|
mesd_dict = mesd['mesd']
|
||||||
|
mesd_yaml = mesd_dict['attributes'].get('mesd')
|
||||||
|
inner_mesd_dict = yaml.safe_load(mesd_yaml)
|
||||||
|
mesd_dict['mesd_mapping'] = dict()
|
||||||
|
LOG.debug('mesd_dict: %s', inner_mesd_dict)
|
||||||
|
# From import we can deploy both NS and MEC Application
|
||||||
|
nsd_imports = inner_mesd_dict['imports'].get('nsds')
|
||||||
|
vnffg_imports = inner_mesd_dict['imports'].get('vnffgds')
|
||||||
|
if nsd_imports:
|
||||||
|
nsd_tpls = nsd_imports.get('nsd_templates')
|
||||||
|
nfv_driver = nsd_imports.get('nfv_driver')
|
||||||
|
if not nsd_tpls:
|
||||||
|
raise meso.NSDNotFound(mesd_name=mesd_dict['name'])
|
||||||
|
if nfv_driver.lower() not in\
|
||||||
|
[driver.lower() for driver in constants.NFV_DRIVER]:
|
||||||
|
raise meso.NFVDriverNotFound(mesd_name=mesd_dict['name'])
|
||||||
|
if isinstance(nsd_tpls, list):
|
||||||
|
mesd_dict['attributes']['nsds'] = '-'.join(nsd_tpls)
|
||||||
|
mesd_dict['mesd_mapping']['NSD'] = nsd_tpls
|
||||||
|
if vnffg_imports:
|
||||||
|
vnffgd_tpls = vnffg_imports.get('vnffgd_templates')
|
||||||
|
nfv_driver = vnffg_imports.get('nfv_driver')
|
||||||
|
if not vnffgd_tpls:
|
||||||
|
raise meso.VNFFGDNotFound(mesd_name=mesd_dict['name'])
|
||||||
|
if nfv_driver.lower() not in \
|
||||||
|
[driver.lower() for driver in constants.NFV_DRIVER]:
|
||||||
|
raise meso.NFVDriverNotFound(mesd_name=mesd_dict['name'])
|
||||||
|
if isinstance(vnffgd_tpls, list):
|
||||||
|
mesd_dict['mesd_mapping']['VNFFGD'] = vnffgd_tpls
|
||||||
|
mesd_dict['attributes']['vnffgds'] = '-'.join(vnffgd_tpls)
|
||||||
|
|
||||||
|
if ('description' not in mesd_dict or
|
||||||
|
mesd_dict['description'] == ''):
|
||||||
|
mesd_dict['description'] = inner_mesd_dict.get(
|
||||||
|
'description', '')
|
||||||
|
if (('name' not in mesd_dict or
|
||||||
|
not len(mesd_dict['name'])) and
|
||||||
|
'metadata' in inner_mesd_dict):
|
||||||
|
mesd_dict['name'] = inner_mesd_dict['metadata'].get(
|
||||||
|
'template_name', '')
|
||||||
|
|
||||||
|
LOG.debug('mesd %s', mesd)
|
||||||
|
|
||||||
|
def _get_mead_id(self, mead_name, onboarded_meads):
|
||||||
|
for mead in onboarded_meads:
|
||||||
|
if mead_name == mead['name']:
|
||||||
|
return mead['id']
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def create_mes(self, context, mes):
|
||||||
|
"""Create MES and corresponding MEAs.
|
||||||
|
|
||||||
|
:param mes: mes dict which contains mesd_id and attributes
|
||||||
|
This method has 2 steps:
|
||||||
|
step-1: Call MEO API to create MEAs
|
||||||
|
step-2: Call Tacker drivers to create NSs
|
||||||
|
"""
|
||||||
|
mes_info = mes['mes']
|
||||||
|
name = mes_info['name']
|
||||||
|
mes_info['mes_mapping'] = dict()
|
||||||
|
|
||||||
|
if mes_info.get('mesd_template'):
|
||||||
|
mesd_name = utils.generate_resource_name(name, 'inline')
|
||||||
|
mesd = {'mesd': {
|
||||||
|
'attributes': {'mesd': mes_info['mesd_template']},
|
||||||
|
'description': mes_info['description'],
|
||||||
|
'name': mesd_name,
|
||||||
|
'template_source': 'inline',
|
||||||
|
'tenant_id': mes_info['tenant_id']}}
|
||||||
|
mes_info['mesd_id'] = self.create_mesd(context, mesd).get('id')
|
||||||
|
|
||||||
|
mesd = self.get_mesd(context, mes['mes']['mesd_id'])
|
||||||
|
mesd_dict = yaml.safe_load(mesd['attributes']['mesd'])
|
||||||
|
meo_plugin = manager.ApmecManager.get_service_plugins()['MEO']
|
||||||
|
|
||||||
|
region_name = mes.setdefault('placement_attr', {}).get(
|
||||||
|
'region_name', None)
|
||||||
|
vim_res = self.vim_client.get_vim(context, mes['mes']['vim_id'],
|
||||||
|
region_name)
|
||||||
|
# driver_type = vim_res['vim_type']
|
||||||
|
if not mes['mes']['vim_id']:
|
||||||
|
mes['mes']['vim_id'] = vim_res['vim_id']
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# Detect MANO driver here:
|
||||||
|
# Defined in the Tosca template
|
||||||
|
nfv_driver = None
|
||||||
|
if mesd_dict['imports'].get('nsds'):
|
||||||
|
nfv_driver = mesd_dict['imports']['nsds']['nfv_driver']
|
||||||
|
nfv_driver = nfv_driver.lower()
|
||||||
|
if mesd_dict['imports'].get('vnffgds'):
|
||||||
|
nfv_driver = mesd_dict['imports']['vnffgds']['nfv_driver']
|
||||||
|
nfv_driver = nfv_driver.lower()
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
def _find_vnf_ins(cd_mes):
|
||||||
|
al_ns_id_list = cd_mes['mes_mapping'].get('NS')
|
||||||
|
if not al_ns_id_list:
|
||||||
|
return None, None
|
||||||
|
al_ns_id = al_ns_id_list[0]
|
||||||
|
try:
|
||||||
|
ns_instance = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'ns_get',
|
||||||
|
ns_id=al_ns_id,
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
except Exception:
|
||||||
|
return None, None
|
||||||
|
if ns_instance['status'] != 'ACTIVE':
|
||||||
|
return None, None
|
||||||
|
al_vnf = ns_instance['vnf_ids']
|
||||||
|
al_vnf_dict = ast.literal_eval(al_vnf)
|
||||||
|
return ns_instance['id'], al_vnf_dict
|
||||||
|
|
||||||
|
def _run_meso_algorithm(req_vnf_list):
|
||||||
|
is_accepted = False
|
||||||
|
al_mes_list = self.get_mess(context)
|
||||||
|
ns_candidate = dict()
|
||||||
|
for al_mes in al_mes_list:
|
||||||
|
ns_candidate[al_mes['id']] = dict()
|
||||||
|
if al_mes['status'] != "ACTIVE":
|
||||||
|
continue
|
||||||
|
al_ns_id, al_vnf_dict = _find_vnf_ins(al_mes)
|
||||||
|
if not al_ns_id:
|
||||||
|
continue
|
||||||
|
ns_candidate[al_mes['id']][al_ns_id] = dict()
|
||||||
|
for req_vnf_dict in req_vnf_list:
|
||||||
|
for vnf_name, al_vnf_id in al_vnf_dict.items():
|
||||||
|
if req_vnf_dict['name'] == vnf_name:
|
||||||
|
# Todo: remember to change this with VM capacity
|
||||||
|
len_diff =\
|
||||||
|
len([lend for lend in
|
||||||
|
al_mes['reused'][vnf_name]
|
||||||
|
if lend > 0])
|
||||||
|
avail = len_diff - req_vnf_dict['nf_ins']
|
||||||
|
ns_candidate[al_mes['id']][al_ns_id].\
|
||||||
|
update({vnf_name: avail})
|
||||||
|
|
||||||
|
ns_cds = dict()
|
||||||
|
deep_ns = dict()
|
||||||
|
for mesid, ns_data_dict in ns_candidate.items():
|
||||||
|
for nsid, resev_dict in ns_data_dict.items():
|
||||||
|
if len(resev_dict) == len(req_vnf_list):
|
||||||
|
nf_ins_list =\
|
||||||
|
[nf_ins for nf_name, nf_ins in
|
||||||
|
resev_dict.items() if nf_ins >= 0]
|
||||||
|
if len(nf_ins_list) == len(req_vnf_list):
|
||||||
|
total_ins = sum(nf_ins_list)
|
||||||
|
ns_cds[mesid] = total_ins
|
||||||
|
else:
|
||||||
|
extra_nf_ins_list =\
|
||||||
|
[-nf_ins for nf_name, nf_ins in
|
||||||
|
resev_dict.items() if nf_ins < 0]
|
||||||
|
total_ins = sum(extra_nf_ins_list)
|
||||||
|
deep_ns[mesid] = total_ins
|
||||||
|
if ns_cds:
|
||||||
|
selected_mes1 = min(ns_cds, key=ns_cds.get)
|
||||||
|
is_accepted = True
|
||||||
|
return is_accepted, selected_mes1, None
|
||||||
|
if deep_ns:
|
||||||
|
selected_mes2 = min(deep_ns, key=deep_ns.get)
|
||||||
|
is_accepted = True
|
||||||
|
return is_accepted, selected_mes2, ns_candidate[selected_mes2]
|
||||||
|
|
||||||
|
return is_accepted, None, None
|
||||||
|
|
||||||
|
build_nsd_dict = dict()
|
||||||
|
if mesd_dict['imports'].get('nsds'):
|
||||||
|
# For framework evaluation
|
||||||
|
nsd_template = mesd_dict['imports']['nsds']['nsd_templates']
|
||||||
|
if isinstance(nsd_template, dict):
|
||||||
|
if nsd_template.get('requirements'):
|
||||||
|
req_nf_dict = nsd_template['requirements']
|
||||||
|
req_nf_list = list()
|
||||||
|
for vnf_dict in req_nf_dict:
|
||||||
|
# Todo: make the requests more natural
|
||||||
|
req_nf_list.append(
|
||||||
|
{'name': vnf_dict['name'],
|
||||||
|
'nf_ins': int(vnf_dict['vnfd_template'][5])})
|
||||||
|
is_accepted, cd_mes_id, cd_vnf_dict =\
|
||||||
|
_run_meso_algorithm(req_nf_list)
|
||||||
|
if is_accepted:
|
||||||
|
new_mesd_dict = dict()
|
||||||
|
ref_mesd_dict = copy.deepcopy(mesd_dict)
|
||||||
|
ref_mesd_dict['imports']['nsds']['nsd_templates']['requirements'] = \
|
||||||
|
req_nf_list
|
||||||
|
new_mesd_dict['mes'] = dict()
|
||||||
|
new_mesd_dict['mes'] =\
|
||||||
|
{'mesd_template': yaml.safe_dump(ref_mesd_dict)}
|
||||||
|
self.update_mes(context, cd_mes_id, new_mesd_dict)
|
||||||
|
return cd_mes_id
|
||||||
|
else:
|
||||||
|
# Create the inline NS with the following template
|
||||||
|
import_list = list()
|
||||||
|
node_dict = dict()
|
||||||
|
for vnfd in req_nf_dict:
|
||||||
|
import_list.append(vnfd['vnfd_template'])
|
||||||
|
node = 'tosca.nodes.nfv.' + vnfd['name']
|
||||||
|
node_dict[vnfd['name']] = {'type': node}
|
||||||
|
build_nsd_dict['tosca_definitions_version'] =\
|
||||||
|
'tosca_simple_profile_for_nfv_1_0_0'
|
||||||
|
build_nsd_dict['description'] = mes_info['description']
|
||||||
|
build_nsd_dict['imports'] = import_list
|
||||||
|
build_nsd_dict['topology_template'] = dict()
|
||||||
|
build_nsd_dict['topology_template']['node_templates'] =\
|
||||||
|
node_dict
|
||||||
|
|
||||||
|
nsds = mesd['attributes'].get('nsds')
|
||||||
|
mes_info['mes_mapping']['NS'] = list()
|
||||||
|
if nsds:
|
||||||
|
nsds_list = nsds.split('-')
|
||||||
|
for nsd in nsds_list:
|
||||||
|
ns_name = nsd + '-' + name + '-' + uuidutils.generate_uuid() # noqa
|
||||||
|
nsd_instance = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver,
|
||||||
|
'nsd_get_by_name',
|
||||||
|
nsd_name=nsd,
|
||||||
|
auth_attr=vim_res['vim_auth'],)
|
||||||
|
if nsd_instance:
|
||||||
|
ns_arg = {'ns': {'nsd_id': nsd_instance['id'],
|
||||||
|
'name': ns_name}}
|
||||||
|
ns_id = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'ns_create',
|
||||||
|
ns_dict=ns_arg,
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
mes_info['mes_mapping']['NS'].append(ns_id)
|
||||||
|
if build_nsd_dict:
|
||||||
|
ns_name = 'nsd' + name + '-' + uuidutils.generate_uuid()
|
||||||
|
ns_arg = {'ns': {'nsd_template': build_nsd_dict,
|
||||||
|
'name': ns_name,
|
||||||
|
'description': mes_info['description'],
|
||||||
|
'vim_id': '',
|
||||||
|
'tenant_id': mes_info['tenant_id'],
|
||||||
|
'attributes': {}}}
|
||||||
|
ns_id = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'ns_create',
|
||||||
|
ns_dict=ns_arg,
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
mes_info['mes_mapping']['NS'].append(ns_id)
|
||||||
|
|
||||||
|
vnffgds = mesd['attributes'].get('vnffgds')
|
||||||
|
if mesd_dict['imports'].get('vnffgds'):
|
||||||
|
vnffgds_list = vnffgds.split('-')
|
||||||
|
mes_info['mes_mapping']['VNFFG'] = list()
|
||||||
|
for vnffgd in vnffgds_list:
|
||||||
|
vnffg_name = vnffgds + '-' + name + '-' + uuidutils.generate_uuid() # noqa
|
||||||
|
vnffgd_instance = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'vnffgd_get_by_name',
|
||||||
|
vnffgd_name=vnffgd,
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
if vnffgd_instance:
|
||||||
|
vnffg_arg = {'vnffg': {'vnffgd_id': vnffgd_instance['id'], 'name': vnffg_name}} # noqa
|
||||||
|
vnffg_id = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'vnffg_create',
|
||||||
|
vnffg_dict=vnffg_arg,
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
mes_info['mes_mapping']['VNFFG'].append(vnffg_id)
|
||||||
|
|
||||||
|
# meca_id = dict()
|
||||||
|
# Create MEAs using MEO APIs
|
||||||
|
try:
|
||||||
|
meca_name = 'meca' + '-' + name + '-' + uuidutils.generate_uuid()
|
||||||
|
# Separate the imports out from template
|
||||||
|
mead_tpl_dict = dict()
|
||||||
|
mead_tpl_dict['imports'] =\
|
||||||
|
mesd_dict['imports']['meads']['mead_templates']
|
||||||
|
mecad_dict = copy.deepcopy(mesd_dict)
|
||||||
|
mecad_dict.pop('imports')
|
||||||
|
mecad_dict.update(mead_tpl_dict)
|
||||||
|
LOG.debug('mesd %s', mecad_dict)
|
||||||
|
meca_arg = {'meca': {'mecad_template': mecad_dict, 'name': meca_name, # noqa
|
||||||
|
'description': mes_info['description'],
|
||||||
|
'tenant_id': mes_info['tenant_id'],
|
||||||
|
'vim_id': mes_info['vim_id'],
|
||||||
|
'attributes': {}}}
|
||||||
|
meca_dict = meo_plugin.create_meca(context, meca_arg)
|
||||||
|
mes_info['mes_mapping']['MECA'] = meca_dict['id']
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error('Error while creating the MECAs: %s', e)
|
||||||
|
# Call Tacker client driver
|
||||||
|
|
||||||
|
mes_dict = super(MesoPlugin, self).create_mes(context, mes)
|
||||||
|
|
||||||
|
def _create_mes_wait(self_obj, mes_id):
|
||||||
|
args = dict()
|
||||||
|
mes_status = "ACTIVE"
|
||||||
|
ns_status = "PENDING_CREATE"
|
||||||
|
vnffg_status = "PENDING_CREATE"
|
||||||
|
mec_status = "PENDING_CREATE"
|
||||||
|
ns_retries = NS_RETRIES
|
||||||
|
mec_retries = MEC_RETRIES
|
||||||
|
vnffg_retries = VNFFG_RETRIES
|
||||||
|
mes_mapping = self.get_mes(context, mes_id)['mes_mapping']
|
||||||
|
# Check MECA
|
||||||
|
meca_id = mes_mapping['MECA']
|
||||||
|
while mec_status == "PENDING_CREATE" and mec_retries > 0:
|
||||||
|
time.sleep(MEC_RETRY_WAIT)
|
||||||
|
mec_status = meo_plugin.get_meca(context, meca_id)['status']
|
||||||
|
LOG.debug('status: %s', mec_status)
|
||||||
|
if mec_status == 'ACTIVE' or mec_status == 'ERROR':
|
||||||
|
break
|
||||||
|
mec_retries = mec_retries - 1
|
||||||
|
error_reason = None
|
||||||
|
if mec_retries == 0 and mec_status == 'PENDING_CREATE':
|
||||||
|
error_reason = _(
|
||||||
|
"MES creation is not completed within"
|
||||||
|
" {wait} seconds as creation of MECA").format(
|
||||||
|
wait=MEC_RETRIES * MEC_RETRY_WAIT)
|
||||||
|
# Check NS/VNFFG status
|
||||||
|
if mes_mapping.get('NS'):
|
||||||
|
ns_list = mes_mapping['NS']
|
||||||
|
while ns_status == "PENDING_CREATE" and ns_retries > 0:
|
||||||
|
time.sleep(NS_RETRY_WAIT)
|
||||||
|
# Todo: support multiple NSs
|
||||||
|
ns_instance = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'ns_get',
|
||||||
|
ns_id=ns_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
ns_status = ns_instance['status']
|
||||||
|
LOG.debug('status: %s', ns_status)
|
||||||
|
if ns_status == 'ACTIVE' or ns_status == 'ERROR':
|
||||||
|
break
|
||||||
|
ns_retries = ns_retries - 1
|
||||||
|
error_reason = None
|
||||||
|
if ns_retries == 0 and ns_status == 'PENDING_CREATE':
|
||||||
|
error_reason = _(
|
||||||
|
"MES creation is not completed within"
|
||||||
|
" {wait} seconds as creation of NS(s)").format(
|
||||||
|
wait=NS_RETRIES * NS_RETRY_WAIT)
|
||||||
|
|
||||||
|
# Determine args
|
||||||
|
ns_cd = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'ns_get',
|
||||||
|
ns_id=ns_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
ns_instance_dict = ns_cd['mgmt_urls']
|
||||||
|
ns_instance_list = ast.literal_eval(ns_instance_dict)
|
||||||
|
args['NS'] = dict()
|
||||||
|
|
||||||
|
for vnf_name, mgmt_url_list in ns_instance_list.items():
|
||||||
|
# Todo: remember to change this with VM capacity
|
||||||
|
vm_capacity = VM_CAPA[vnf_name]
|
||||||
|
orig = [vm_capacity] * len(mgmt_url_list)
|
||||||
|
args['NS'][vnf_name] = [(val - 1) for val in orig]
|
||||||
|
|
||||||
|
if mes_mapping.get('VNFFG'):
|
||||||
|
while vnffg_status == "PENDING_CREATE" and vnffg_retries > 0:
|
||||||
|
time.sleep(VNFFG_RETRY_WAIT)
|
||||||
|
vnffg_list = mes_mapping['VNFFG']
|
||||||
|
# Todo: support multiple VNFFGs
|
||||||
|
vnffg_instance = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'vnffg_get',
|
||||||
|
vnffg_id=vnffg_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
vnffg_status = vnffg_instance['status']
|
||||||
|
LOG.debug('status: %s', vnffg_status)
|
||||||
|
if vnffg_status == 'ACTIVE' or vnffg_status == 'ERROR':
|
||||||
|
break
|
||||||
|
vnffg_retries = vnffg_retries - 1
|
||||||
|
error_reason = None
|
||||||
|
if vnffg_retries == 0 and vnffg_status == 'PENDING_CREATE':
|
||||||
|
error_reason = _(
|
||||||
|
"MES creation is not completed within"
|
||||||
|
" {wait} seconds as creation of VNFFG(s)").format(
|
||||||
|
wait=VNFFG_RETRIES * VNFFG_RETRY_WAIT)
|
||||||
|
if mec_status == "ERROR" or ns_status == "ERROR" or vnffg_status == "ERROR": # noqa
|
||||||
|
mes_status = "ERROR"
|
||||||
|
if error_reason:
|
||||||
|
mes_status = "PENDING_CREATE"
|
||||||
|
|
||||||
|
super(MesoPlugin, self).create_mes_post(context, mes_id, mes_status, error_reason, args) # noqa
|
||||||
|
self.spawn_n(_create_mes_wait, self, mes_dict['id'])
|
||||||
|
return mes_dict
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def _update_params(self, original, paramvalues):
|
||||||
|
for key, value in (original).items():
|
||||||
|
if not isinstance(value, dict) or 'get_input' not in str(value):
|
||||||
|
pass
|
||||||
|
elif isinstance(value, dict):
|
||||||
|
if 'get_input' in value:
|
||||||
|
if value['get_input'] in paramvalues:
|
||||||
|
original[key] = paramvalues[value['get_input']]
|
||||||
|
else:
|
||||||
|
LOG.debug('Key missing Value: %s', key)
|
||||||
|
raise cs.InputValuesMissing(key=key)
|
||||||
|
else:
|
||||||
|
self._update_params(value, paramvalues)
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def _process_parameterized_input(self, attrs, mesd_dict):
|
||||||
|
param_vattrs_dict = attrs.pop('param_values', None)
|
||||||
|
if param_vattrs_dict:
|
||||||
|
for node in \
|
||||||
|
mesd_dict['topology_template']['node_templates'].values():
|
||||||
|
if 'get_input' in str(node):
|
||||||
|
self._update_params(node, param_vattrs_dict['mesd'])
|
||||||
|
else:
|
||||||
|
raise cs.ParamYAMLInputMissing()
|
||||||
|
|
||||||
|
@log.log
|
||||||
|
def delete_mes(self, context, mes_id):
|
||||||
|
mes = super(MesoPlugin, self).get_mes(context, mes_id)
|
||||||
|
mesd = self.get_mesd(context, mes['mesd_id'])
|
||||||
|
mesd_dict = yaml.safe_load(mesd['attributes']['mesd'])
|
||||||
|
vim_res = self.vim_client.get_vim(context, mes['vim_id'])
|
||||||
|
mes_mapping = mes['mes_mapping']
|
||||||
|
meca_id = mes_mapping['MECA']
|
||||||
|
meo_plugin = manager.ApmecManager.get_service_plugins()['MEO']
|
||||||
|
try:
|
||||||
|
meca_id = meo_plugin.delete_meca(context, meca_id)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error('Error while deleting the MECA(s): %s', e)
|
||||||
|
|
||||||
|
if mes_mapping.get('NS'):
|
||||||
|
# Todo: support multiple NSs
|
||||||
|
ns_id = mes_mapping['NS'][0]
|
||||||
|
nfv_driver = None
|
||||||
|
if mesd_dict['imports'].get('nsds'):
|
||||||
|
nfv_driver = mesd_dict['imports']['nsds']['nfv_driver']
|
||||||
|
nfv_driver = nfv_driver.lower()
|
||||||
|
if not nfv_driver:
|
||||||
|
raise meso.NFVDriverNotFound(mesd_name=mesd_dict['name'])
|
||||||
|
try:
|
||||||
|
self._nfv_drivers.invoke(
|
||||||
|
nfv_driver,
|
||||||
|
'ns_delete',
|
||||||
|
ns_id=ns_id,
|
||||||
|
auth_attr=vim_res['vim_auth'])
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error('Error while deleting the NS(s): %s', e)
|
||||||
|
if mes_mapping.get('VNFFG'):
|
||||||
|
# Todo: support multiple VNFFGs
|
||||||
|
vnffg_id = mes_mapping['VNFFG'][0]
|
||||||
|
nfv_driver = None
|
||||||
|
if mesd_dict['imports'].get('vnffgds'):
|
||||||
|
nfv_driver = mesd_dict['imports']['vnffgds']['nfv_driver']
|
||||||
|
nfv_driver = nfv_driver.lower()
|
||||||
|
if not nfv_driver:
|
||||||
|
raise meso.NFVDriverNotFound(mesd_name=mesd_dict['name'])
|
||||||
|
try:
|
||||||
|
self._nfv_drivers.invoke(
|
||||||
|
nfv_driver,
|
||||||
|
'vnffg_delete',
|
||||||
|
vnffg_id=vnffg_id,
|
||||||
|
auth_attr=vim_res['vim_auth'])
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error('Error while deleting the VNFFG(s): %s', e)
|
||||||
|
|
||||||
|
super(MesoPlugin, self).delete_mes(context, mes_id)
|
||||||
|
|
||||||
|
def _delete_mes_wait(mes_id):
|
||||||
|
ns_status = "PENDING_DELETE"
|
||||||
|
vnffg_status = "PENDING_DELETE"
|
||||||
|
mec_status = "PENDING_DELETE"
|
||||||
|
ns_retries = NS_RETRIES
|
||||||
|
mec_retries = MEC_RETRIES
|
||||||
|
vnffg_retries = VNFFG_RETRIES
|
||||||
|
error_reason_meca = None
|
||||||
|
error_reason_ns = None
|
||||||
|
error_reason_vnffg = None
|
||||||
|
# Check MECA
|
||||||
|
while mec_status == "PENDING_DELETE" and mec_retries > 0:
|
||||||
|
time.sleep(MEC_RETRY_WAIT)
|
||||||
|
meca_id = mes_mapping['MECA']
|
||||||
|
meca_list = meo_plugin.get_mecas(context)
|
||||||
|
is_deleted = True
|
||||||
|
for meca in meca_list:
|
||||||
|
if meca_id in meca['id']:
|
||||||
|
is_deleted = False
|
||||||
|
if is_deleted:
|
||||||
|
break
|
||||||
|
mec_status = meo_plugin.get_meca(context, meca_id)['status']
|
||||||
|
LOG.debug('status: %s', mec_status)
|
||||||
|
if mec_status == 'ERROR':
|
||||||
|
break
|
||||||
|
mec_retries = mec_retries - 1
|
||||||
|
if mec_retries == 0 and mec_status == 'PENDING_DELETE':
|
||||||
|
error_reason_meca = _(
|
||||||
|
"MES deletion is not completed within"
|
||||||
|
" {wait} seconds as deletion of MECA").format(
|
||||||
|
wait=MEC_RETRIES * MEC_RETRY_WAIT)
|
||||||
|
# Check NS/VNFFG status
|
||||||
|
if mes_mapping.get('NS'):
|
||||||
|
while ns_status == "PENDING_DELETE" and ns_retries > 0:
|
||||||
|
time.sleep(NS_RETRY_WAIT)
|
||||||
|
ns_list = mes_mapping['NS']
|
||||||
|
# Todo: support multiple NSs
|
||||||
|
is_existed = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'ns_check',
|
||||||
|
ns_id=ns_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
if not is_existed:
|
||||||
|
break
|
||||||
|
ns_instance = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'ns_get',
|
||||||
|
ns_id=ns_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
ns_status = ns_instance['status']
|
||||||
|
LOG.debug('status: %s', ns_status)
|
||||||
|
if ns_status == 'ERROR':
|
||||||
|
break
|
||||||
|
ns_retries = ns_retries - 1
|
||||||
|
if ns_retries == 0 and ns_status == 'PENDING_DELETE':
|
||||||
|
error_reason_ns = _(
|
||||||
|
"MES deletion is not completed within"
|
||||||
|
" {wait} seconds as deletion of NS(s)").format(
|
||||||
|
wait=NS_RETRIES * NS_RETRY_WAIT)
|
||||||
|
if mes_mapping.get('VNFFG'):
|
||||||
|
while vnffg_status == "PENDING_DELETE" and vnffg_retries > 0:
|
||||||
|
time.sleep(VNFFG_RETRY_WAIT)
|
||||||
|
vnffg_list = mes_mapping['VNFFG']
|
||||||
|
# Todo: support multiple VNFFGs
|
||||||
|
is_existed = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'vnffg_check',
|
||||||
|
vnffg_id=vnffg_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
if not is_existed:
|
||||||
|
break
|
||||||
|
vnffg_instance = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'vnffg_get',
|
||||||
|
vnffg_id=vnffg_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
vnffg_status = vnffg_instance['status']
|
||||||
|
LOG.debug('status: %s', vnffg_status)
|
||||||
|
if vnffg_status == 'ERROR':
|
||||||
|
break
|
||||||
|
vnffg_retries = vnffg_retries - 1
|
||||||
|
if vnffg_retries == 0 and vnffg_status == 'PENDING_DELETE':
|
||||||
|
error_reason_vnffg = _(
|
||||||
|
"MES deletion is not completed within"
|
||||||
|
" {wait} seconds as deletion of VNFFG(s)").format(
|
||||||
|
wait=VNFFG_RETRIES * VNFFG_RETRY_WAIT)
|
||||||
|
error = False
|
||||||
|
if mec_status == "ERROR" or ns_status == "ERROR" or vnffg_status == "ERROR": # noqa
|
||||||
|
error = True
|
||||||
|
error_reason = None
|
||||||
|
for reason in [error_reason_meca, error_reason_ns, error_reason_vnffg]: # noqa
|
||||||
|
error_reason = reason if reason else None
|
||||||
|
|
||||||
|
super(MesoPlugin, self).delete_mes_post(
|
||||||
|
context, mes_id, error_reason=error_reason, error=error)
|
||||||
|
self.spawn_n(_delete_mes_wait, mes['id'])
|
||||||
|
return mes['id']
|
||||||
|
|
||||||
|
def update_mes(self, context, mes_id, mes):
|
||||||
|
args = dict()
|
||||||
|
mes_info = mes['mes']
|
||||||
|
old_mes = super(MesoPlugin, self).get_mes(context, mes_id)
|
||||||
|
name = old_mes['name']
|
||||||
|
lftover = dict()
|
||||||
|
# vm_capacity = 3
|
||||||
|
# create inline mesd if given by user
|
||||||
|
|
||||||
|
def _update_nsd_template(req_mesd_dict):
|
||||||
|
build_nsd_dict = dict()
|
||||||
|
if req_mesd_dict['imports'].get('nsds'):
|
||||||
|
args['NS'] = dict()
|
||||||
|
# Todo: Support multiple NSs
|
||||||
|
# For framework evaluation
|
||||||
|
nsd_templates = req_mesd_dict['imports']['nsds']['nsd_templates'] # noqa
|
||||||
|
if isinstance(nsd_templates, dict):
|
||||||
|
if nsd_templates.get('requirements'):
|
||||||
|
old_reused = old_mes['reused']
|
||||||
|
vnf_mapping_list = nsd_templates['requirements']
|
||||||
|
for vnf_mapping_dict in vnf_mapping_list:
|
||||||
|
for old_vnf_name, old_nfins_list in old_reused.items(): # noqa
|
||||||
|
if vnf_mapping_dict['name'] == old_vnf_name:
|
||||||
|
len_diff = len([lend for lend in old_nfins_list if lend > 0]) # noqa
|
||||||
|
diff = len_diff - vnf_mapping_dict['nf_ins'] # noqa
|
||||||
|
if diff < 0:
|
||||||
|
lftover.update({old_vnf_name: -diff})
|
||||||
|
vm_capacity = VM_CAPA[old_vnf_name]
|
||||||
|
old_reused[old_vnf_name].extend([vm_capacity] * (-diff)) # noqa
|
||||||
|
# old_reused[old_vnf_name] = diff
|
||||||
|
temp = vnf_mapping_dict['nf_ins']
|
||||||
|
for index, nfins in enumerate(old_nfins_list): # noqa
|
||||||
|
if nfins > 0:
|
||||||
|
old_nfins_list[index] = old_nfins_list[index] - 1 # noqa
|
||||||
|
temp = temp - 1
|
||||||
|
if temp == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
formal_req = list()
|
||||||
|
for nf_name, nf_ins in lftover.items():
|
||||||
|
vnfd_name = 'vnfd' + nf_name[3] + str(nf_ins)
|
||||||
|
formal_req.append(vnfd_name)
|
||||||
|
|
||||||
|
if formal_req:
|
||||||
|
build_nsd_dict['tosca_definitions_version'] = 'tosca_simple_profile_for_nfv_1_0_0' # noqa
|
||||||
|
build_nsd_dict['description'] = old_mes['description']
|
||||||
|
build_nsd_dict['imports'] = formal_req
|
||||||
|
build_nsd_dict['topology_template'] = dict()
|
||||||
|
build_nsd_dict['topology_template']['node_templates'] = dict() # noqa
|
||||||
|
for nf_name, nf_ins in lftover.items():
|
||||||
|
node = 'tosca.nodes.nfv.' + nf_name
|
||||||
|
node_dict = dict()
|
||||||
|
node_dict['type'] = node
|
||||||
|
build_nsd_dict['topology_template']['node_templates'].update({nf_name: node_dict}) # noqa
|
||||||
|
return build_nsd_dict
|
||||||
|
|
||||||
|
if mes_info.get('mesd_template'):
|
||||||
|
# Build vnf_dict here
|
||||||
|
mes_name = utils.generate_resource_name(name, 'inline')
|
||||||
|
mesd = {'mesd': {'tenant_id': old_mes['tenant_id'],
|
||||||
|
'name': mes_name,
|
||||||
|
'attributes': {
|
||||||
|
'mesd': mes_info['mesd_template']},
|
||||||
|
'template_source': 'inline',
|
||||||
|
'description': old_mes['description']}}
|
||||||
|
try:
|
||||||
|
mes_info['mesd_id'] = \
|
||||||
|
self.create_mesd(context, mesd).get('id')
|
||||||
|
except Exception:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
super(MesoPlugin, self)._update_mes_status(context, mes_id, constants.ACTIVE) # noqa
|
||||||
|
|
||||||
|
mesd = self.get_mesd(context, mes_info['mesd_id'])
|
||||||
|
mesd_dict = yaml.safe_load(mesd['attributes']['mesd'])
|
||||||
|
new_mesd_mapping = mesd['mesd_mapping']
|
||||||
|
region_name = mes.setdefault('placement_attr', {}).get(
|
||||||
|
'region_name', None)
|
||||||
|
vim_res = self.vim_client.get_vim(context, old_mes['vim_id'],
|
||||||
|
region_name)
|
||||||
|
|
||||||
|
if mesd_dict['imports'].get('meads'):
|
||||||
|
# Update MECA
|
||||||
|
meo_plugin = manager.ApmecManager.get_service_plugins()['MEO']
|
||||||
|
# Build the MECA template here
|
||||||
|
mead_tpl_dict = dict()
|
||||||
|
mead_tpl_dict['imports'] =\
|
||||||
|
mesd_dict['imports']['meads']['mead_templates']
|
||||||
|
mecad_dict = copy.deepcopy(mesd_dict)
|
||||||
|
mecad_dict.pop('imports')
|
||||||
|
mecad_dict.update(mead_tpl_dict)
|
||||||
|
mecad_arg = {'meca': {'mecad_template': mecad_dict}}
|
||||||
|
old_meca_id = old_mes['mes_mapping']['MECA']
|
||||||
|
meca_id = meo_plugin.update_meca(context, old_meca_id, mecad_arg) # noqa
|
||||||
|
|
||||||
|
if mesd_dict['imports'].get('nsds'):
|
||||||
|
nfv_driver = None
|
||||||
|
nfv_driver = mesd_dict['imports']['nsds'].get('nfv_driver')
|
||||||
|
if not nfv_driver:
|
||||||
|
raise meso.NFVDriverNotFound(mesd_name=mesd_dict['name'])
|
||||||
|
nfv_driver = nfv_driver.lower()
|
||||||
|
|
||||||
|
req_mesd_dict = yaml.safe_load(mes_info['mesd_template'])
|
||||||
|
new_nsd_template = _update_nsd_template(req_mesd_dict)
|
||||||
|
nsd_template = None
|
||||||
|
if isinstance(new_mesd_mapping.get('NSD'), list):
|
||||||
|
nsd_name = new_mesd_mapping['NSD'][0]
|
||||||
|
nsd_dict = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'nsd_get_by_name',
|
||||||
|
nsd_name=nsd_name,
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
nsd_template = yaml.safe_load(nsd_dict['attributes']['nsd'])
|
||||||
|
actual_nsd_template = new_nsd_template if new_nsd_template else nsd_template # noqa
|
||||||
|
if actual_nsd_template:
|
||||||
|
old_ns_id = old_mes['mes_mapping']['NS'][0]
|
||||||
|
ns_arg = {'ns': {'nsd_template': actual_nsd_template}}
|
||||||
|
self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'ns_update',
|
||||||
|
ns_id=old_ns_id,
|
||||||
|
ns_dict=ns_arg,
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
|
||||||
|
if mesd_dict['imports'].get('vnffgds'):
|
||||||
|
# Todo: Support multiple VNFFGs
|
||||||
|
nfv_driver = None
|
||||||
|
nfv_driver = mesd_dict['imports']['nsds'].get('nfv_driver')
|
||||||
|
if not nfv_driver:
|
||||||
|
raise meso.NFVDriverNotFound(mesd_name=mesd_dict['name'])
|
||||||
|
nfv_driver = nfv_driver.lower()
|
||||||
|
vnffgd_name = new_mesd_mapping['VNFFGD'][0]
|
||||||
|
vnffgd_dict = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'vnffgd_get_by_name',
|
||||||
|
vnffgd_name=vnffgd_name,
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
vnffgd_template = yaml.safe_load(
|
||||||
|
vnffgd_dict['attributes']['vnffgd'])
|
||||||
|
old_vnffg_id = old_mes['mes_mapping']['VNFFG'][0]
|
||||||
|
vnffg_arg = {'vnffg': {'vnffgd_template': vnffgd_template}}
|
||||||
|
self._nfv_drivers.invoke(
|
||||||
|
nfv_driver,
|
||||||
|
'vnffg_update',
|
||||||
|
vnffg_id=old_vnffg_id,
|
||||||
|
vnffg_dict=vnffg_arg,
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
|
||||||
|
mes_dict = super(MesoPlugin, self)._update_mes_pre(context, mes_id)
|
||||||
|
|
||||||
|
def _update_mes_wait(self_obj, mes_id):
|
||||||
|
args = dict()
|
||||||
|
mes_status = "ACTIVE"
|
||||||
|
ns_status = "PENDING_UPDATE"
|
||||||
|
vnffg_status = "PENDING_UPDATE"
|
||||||
|
mec_status = "PENDING_UPDATE"
|
||||||
|
ns_retries = NS_RETRIES
|
||||||
|
mec_retries = MEC_RETRIES
|
||||||
|
vnffg_retries = VNFFG_RETRIES
|
||||||
|
error_reason_meca = None
|
||||||
|
error_reason_ns = None
|
||||||
|
error_reason_vnffg = None
|
||||||
|
# Check MECA
|
||||||
|
if mesd_dict['imports'].get('meads'):
|
||||||
|
while mec_status == "PENDING_UPDATE" and mec_retries > 0:
|
||||||
|
time.sleep(MEC_RETRY_WAIT)
|
||||||
|
meca_id = old_mes['mes_mapping']['MECA']
|
||||||
|
meca_list = meo_plugin.get_mecas(context)
|
||||||
|
is_deleted = True
|
||||||
|
for meca in meca_list:
|
||||||
|
if meca_id in meca['id']:
|
||||||
|
is_deleted = False
|
||||||
|
if is_deleted:
|
||||||
|
break
|
||||||
|
mec_status = meo_plugin.get_meca(context, meca_id)['status'] # noqa
|
||||||
|
LOG.debug('status: %s', mec_status)
|
||||||
|
if mec_status == 'ERROR':
|
||||||
|
break
|
||||||
|
mec_retries = mec_retries - 1
|
||||||
|
if mec_retries == 0 and mec_status == 'PENDING_UPDATE':
|
||||||
|
error_reason_meca = _(
|
||||||
|
"MES update is not completed within"
|
||||||
|
" {wait} seconds as update of MECA").format(
|
||||||
|
wait=MEC_RETRIES * MEC_RETRY_WAIT)
|
||||||
|
# Check NS/VNFFG status
|
||||||
|
if mesd_dict['imports'].get('nsds'):
|
||||||
|
while ns_status == "PENDING_UPDATE" and ns_retries > 0:
|
||||||
|
time.sleep(NS_RETRY_WAIT)
|
||||||
|
ns_list = old_mes['mes_mapping']['NS']
|
||||||
|
# Todo: support multiple NSs
|
||||||
|
is_existed = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'ns_check',
|
||||||
|
ns_id=ns_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
if not is_existed:
|
||||||
|
break
|
||||||
|
ns_instance = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'ns_get',
|
||||||
|
ns_id=ns_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
ns_status = ns_instance['status']
|
||||||
|
LOG.debug('status: %s', ns_status)
|
||||||
|
if ns_status == 'ERROR':
|
||||||
|
break
|
||||||
|
ns_retries = ns_retries - 1
|
||||||
|
if ns_retries == 0 and ns_status == 'PENDING_UPDATE':
|
||||||
|
error_reason_ns = _(
|
||||||
|
"MES update is not completed within"
|
||||||
|
" {wait} seconds as update of NS(s)").format(
|
||||||
|
wait=NS_RETRIES * NS_RETRY_WAIT)
|
||||||
|
|
||||||
|
if mesd_dict['imports'].get('vnffgds'):
|
||||||
|
while vnffg_status == "PENDING_UPDATE" and vnffg_retries > 0:
|
||||||
|
time.sleep(VNFFG_RETRY_WAIT)
|
||||||
|
vnffg_list = old_mes['mes_mapping']['VNFFG']
|
||||||
|
# Todo: support multiple VNFFGs
|
||||||
|
is_existed = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'vnffg_check',
|
||||||
|
vnffg_id=vnffg_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
if not is_existed:
|
||||||
|
break
|
||||||
|
vnffg_instance = self._nfv_drivers.invoke(
|
||||||
|
nfv_driver, # How to tell it is Tacker
|
||||||
|
'vnffg_get',
|
||||||
|
vnffg_id=vnffg_list[0],
|
||||||
|
auth_attr=vim_res['vim_auth'], )
|
||||||
|
vnffg_status = vnffg_instance['status']
|
||||||
|
LOG.debug('status: %s', vnffg_status)
|
||||||
|
if vnffg_status == 'ERROR':
|
||||||
|
break
|
||||||
|
vnffg_retries = vnffg_retries - 1
|
||||||
|
if vnffg_retries == 0 and vnffg_status == 'PENDING_UPDATE':
|
||||||
|
error_reason_vnffg = _(
|
||||||
|
"MES update is not completed within"
|
||||||
|
" {wait} seconds as update of VNFFG(s)").format(
|
||||||
|
wait=VNFFG_RETRIES * VNFFG_RETRY_WAIT)
|
||||||
|
args['NS'] = old_mes['reused']
|
||||||
|
if mec_status == "ERROR" or ns_status == "ERROR" or vnffg_status == "ERROR": # noqa
|
||||||
|
mes_status = "ERROR"
|
||||||
|
error_reason = None
|
||||||
|
for reason in [error_reason_meca, error_reason_ns, error_reason_vnffg]: # noqa
|
||||||
|
if reason:
|
||||||
|
error_reason = reason
|
||||||
|
mes_status = "PENDING_UPDATE"
|
||||||
|
super(MesoPlugin, self)._update_mes_post(context, mes_id, error_reason, mes_status, args) # noqa
|
||||||
|
|
||||||
|
self.spawn_n(_update_mes_wait, self, mes_dict['id'])
|
||||||
|
return mes_dict
|
@ -4,6 +4,8 @@ wrap_width = 79
|
|||||||
namespace = apmec.common.config
|
namespace = apmec.common.config
|
||||||
namespace = apmec.wsgi
|
namespace = apmec.wsgi
|
||||||
namespace = apmec.service
|
namespace = apmec.service
|
||||||
|
namespace = apmec.meso.meso_plugin
|
||||||
|
namespace = apmec.meso.drivers.nfv_drivers.tacker_driver
|
||||||
namespace = apmec.meo.meo_plugin
|
namespace = apmec.meo.meo_plugin
|
||||||
namespace = apmec.meo.drivers.vim.openstack_driver
|
namespace = apmec.meo.drivers.vim.openstack_driver
|
||||||
namespace = apmec.keymgr
|
namespace = apmec.keymgr
|
||||||
@ -24,4 +26,4 @@ namespace = oslo.messaging
|
|||||||
namespace = oslo.db
|
namespace = oslo.db
|
||||||
namespace = oslo.log
|
namespace = oslo.log
|
||||||
namespace = oslo.policy
|
namespace = oslo.policy
|
||||||
namespace = oslo.service.service
|
namespace = oslo.service.service
|
@ -44,7 +44,10 @@ apmec.service_plugins =
|
|||||||
dummy = apmec.tests.unit.dummy_plugin:DummyServicePlugin
|
dummy = apmec.tests.unit.dummy_plugin:DummyServicePlugin
|
||||||
mem = apmec.mem.plugin:MEMPlugin
|
mem = apmec.mem.plugin:MEMPlugin
|
||||||
meo = apmec.meo.meo_plugin:MeoPlugin
|
meo = apmec.meo.meo_plugin:MeoPlugin
|
||||||
|
meso = apmec.meso.meso_plugin:MesoPlugin
|
||||||
commonservices = apmec.plugins.common_services.common_services_plugin:CommonServicesPlugin
|
commonservices = apmec.plugins.common_services.common_services_plugin:CommonServicesPlugin
|
||||||
|
apmec.meso.drivers =
|
||||||
|
tacker = apmec.meso.drivers.nfv_drivers.tacker_driver:Tacker_Driver
|
||||||
apmec.meo.vim.drivers =
|
apmec.meo.vim.drivers =
|
||||||
openstack = apmec.meo.drivers.vim.openstack_driver:OpenStack_Driver
|
openstack = apmec.meo.drivers.vim.openstack_driver:OpenStack_Driver
|
||||||
apmec.openstack.common.cache.backends =
|
apmec.openstack.common.cache.backends =
|
||||||
@ -71,6 +74,8 @@ oslo.config.opts =
|
|||||||
apmec.service = apmec.service:config_opts
|
apmec.service = apmec.service:config_opts
|
||||||
apmec.meo.meo_plugin = apmec.meo.meo_plugin:config_opts
|
apmec.meo.meo_plugin = apmec.meo.meo_plugin:config_opts
|
||||||
apmec.meo.drivers.vim.openstack_driver = apmec.meo.drivers.vim.openstack_driver:config_opts
|
apmec.meo.drivers.vim.openstack_driver = apmec.meo.drivers.vim.openstack_driver:config_opts
|
||||||
|
apmec.meso.meso_plugin = apmec.meso.meso_plugin:config_opts
|
||||||
|
apmec.mseo.drivers.nfv_drivers.tacker_driver = apmec.meso.drivers.nfv_drivers.tacker_driver:config_opts
|
||||||
apmec.keymgr = apmec.keymgr:config_opts
|
apmec.keymgr = apmec.keymgr:config_opts
|
||||||
apmec.mem.monitor = apmec.mem.monitor:config_opts
|
apmec.mem.monitor = apmec.mem.monitor:config_opts
|
||||||
apmec.mem.plugin = apmec.mem.plugin:config_opts
|
apmec.mem.plugin = apmec.mem.plugin:config_opts
|
||||||
|
Loading…
Reference in New Issue
Block a user