Skip to content
...@@ -21,7 +21,9 @@ from typing import Dict, List, Optional, Set, Tuple ...@@ -21,7 +21,9 @@ from typing import Dict, List, Optional, Set, Tuple
from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException
from common.message_broker.MessageBroker import MessageBroker from common.message_broker.MessageBroker import MessageBroker
from common.proto.context_pb2 import ( from common.proto.context_pb2 import (
Device, DeviceFilter, DeviceId, DeviceIdList, DeviceList, Empty, EventTypeEnum, TopologyId) Device, DeviceDriverEnum, DeviceFilter, DeviceId, DeviceIdList, DeviceList,
Empty, EventTypeEnum, TopologyId
)
from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.grpc.Tools import grpc_message_to_json_string
from common.tools.object_factory.Device import json_device_id from common.tools.object_factory.Device import json_device_id
from context.service.database.uuids.Topology import topology_get_uuid from context.service.database.uuids.Topology import topology_get_uuid
...@@ -103,10 +105,12 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi ...@@ -103,10 +105,12 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi
}) })
topology_uuids.add(topology_uuid) topology_uuids.add(topology_uuid)
is_oc_driver = DeviceDriverEnum.DEVICEDRIVER_OC in set(request.device_drivers)
endpoints_data : List[Dict] = list() endpoints_data : List[Dict] = list()
for i, endpoint in enumerate(request.device_endpoints): for i, endpoint in enumerate(request.device_endpoints):
endpoint_device_uuid = endpoint.endpoint_id.device_id.device_uuid.uuid endpoint_device_uuid = endpoint.endpoint_id.device_id.device_uuid.uuid
if len(endpoint_device_uuid) == 0: endpoint_device_uuid = device_uuid if len(endpoint_device_uuid) == 0 or is_oc_driver : endpoint_device_uuid = device_uuid
if endpoint_device_uuid not in {raw_device_uuid, device_uuid}: if endpoint_device_uuid not in {raw_device_uuid, device_uuid}:
raise InvalidArgumentException( raise InvalidArgumentException(
'request.device_endpoints[{:d}].device_id.device_uuid.uuid'.format(i), endpoint_device_uuid, 'request.device_endpoints[{:d}].device_id.device_uuid.uuid'.format(i), endpoint_device_uuid,
...@@ -132,6 +136,7 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi ...@@ -132,6 +136,7 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi
'created_at' : now, 'created_at' : now,
'updated_at' : now, 'updated_at' : now,
}) })
LOGGER.info(f"endpoint data {endpoints_data}")
if endpoint_topology_uuid not in topology_uuids: if endpoint_topology_uuid not in topology_uuids:
related_topologies.append({ related_topologies.append({
...@@ -199,15 +204,15 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi ...@@ -199,15 +204,15 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi
stmt = stmt.returning(TopologyDeviceModel.topology_uuid) stmt = stmt.returning(TopologyDeviceModel.topology_uuid)
topology_uuids = session.execute(stmt).fetchall() topology_uuids = session.execute(stmt).fetchall()
LOGGER.warning('RAW topology_uuids={:s}'.format(str(topology_uuids))) #LOGGER.warning('RAW topology_uuids={:s}'.format(str(topology_uuids)))
if len(topology_uuids) > 0: if len(topology_uuids) > 0:
topology_uuids = [topology_uuid[0] for topology_uuid in topology_uuids] topology_uuids = [topology_uuid[0] for topology_uuid in topology_uuids]
LOGGER.warning('NEW topology_uuids={:s}'.format(str(topology_uuids))) #LOGGER.warning('NEW topology_uuids={:s}'.format(str(topology_uuids)))
query = session.query(TopologyModel) query = session.query(TopologyModel)
query = query.filter(TopologyModel.topology_uuid.in_(topology_uuids)) query = query.filter(TopologyModel.topology_uuid.in_(topology_uuids))
device_topologies : List[TopologyModel] = query.all() device_topologies : List[TopologyModel] = query.all()
device_topology_ids = [obj.dump_id() for obj in device_topologies] device_topology_ids = [obj.dump_id() for obj in device_topologies]
LOGGER.warning('device_topology_ids={:s}'.format(str(device_topology_ids))) #LOGGER.warning('device_topology_ids={:s}'.format(str(device_topology_ids)))
updated_components = False updated_components = False
...@@ -229,7 +234,7 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi ...@@ -229,7 +234,7 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi
changed_config_rules = upsert_config_rules(session, config_rules, device_uuid=device_uuid) changed_config_rules = upsert_config_rules(session, config_rules, device_uuid=device_uuid)
return updated or updated_endpoints or changed_config_rules, device_topology_ids return updated or updated_endpoints or updated_components or changed_config_rules, device_topology_ids
updated, device_topology_ids = run_transaction(sessionmaker(bind=db_engine), callback) updated, device_topology_ids = run_transaction(sessionmaker(bind=db_engine), callback)
device_id = json_device_id(device_uuid) device_id = json_device_id(device_uuid)
......
...@@ -17,7 +17,8 @@ from typing import Dict, Iterator, Set ...@@ -17,7 +17,8 @@ from typing import Dict, Iterator, Set
from common.message_broker.Message import Message from common.message_broker.Message import Message
from common.message_broker.MessageBroker import MessageBroker from common.message_broker.MessageBroker import MessageBroker
from common.proto.context_pb2 import ( from common.proto.context_pb2 import (
ConnectionEvent, ContextEvent, DeviceEvent, EventTypeEnum, LinkEvent, ServiceEvent, SliceEvent, TopologyEvent) ConnectionEvent, ContextEvent, DeviceEvent, EventTypeEnum, LinkEvent, ServiceEvent, SliceEvent, TopologyEvent ,
OpticalConfigEvent)
class EventTopicEnum(enum.Enum): class EventTopicEnum(enum.Enum):
CONNECTION = 'connection' CONNECTION = 'connection'
...@@ -28,6 +29,8 @@ class EventTopicEnum(enum.Enum): ...@@ -28,6 +29,8 @@ class EventTopicEnum(enum.Enum):
SERVICE = 'service' SERVICE = 'service'
SLICE = 'slice' SLICE = 'slice'
TOPOLOGY = 'topology' TOPOLOGY = 'topology'
OPTICALCONFIG = 'optical-config'
TOPIC_TO_EVENTCLASS = { TOPIC_TO_EVENTCLASS = {
EventTopicEnum.CONNECTION.value : ConnectionEvent, EventTopicEnum.CONNECTION.value : ConnectionEvent,
...@@ -38,6 +41,8 @@ TOPIC_TO_EVENTCLASS = { ...@@ -38,6 +41,8 @@ TOPIC_TO_EVENTCLASS = {
EventTopicEnum.SERVICE.value : ServiceEvent, EventTopicEnum.SERVICE.value : ServiceEvent,
EventTopicEnum.SLICE.value : SliceEvent, EventTopicEnum.SLICE.value : SliceEvent,
EventTopicEnum.TOPOLOGY.value : TopologyEvent, EventTopicEnum.TOPOLOGY.value : TopologyEvent,
EventTopicEnum.OPTICALCONFIG.value : OpticalConfigEvent
} }
CONSUME_TIMEOUT = 0.5 # seconds CONSUME_TIMEOUT = 0.5 # seconds
...@@ -61,6 +66,10 @@ def notify_event_topology(messagebroker : MessageBroker, event_type : EventTypeE ...@@ -61,6 +66,10 @@ def notify_event_topology(messagebroker : MessageBroker, event_type : EventTypeE
def notify_event_device(messagebroker : MessageBroker, event_type : EventTypeEnum, device_id : Dict) -> None: def notify_event_device(messagebroker : MessageBroker, event_type : EventTypeEnum, device_id : Dict) -> None:
notify_event(messagebroker, EventTopicEnum.DEVICE, event_type, {'device_id': device_id}) notify_event(messagebroker, EventTopicEnum.DEVICE, event_type, {'device_id': device_id})
def notify_event_opticalconfig(messagebroker : MessageBroker, event_type : EventTypeEnum, opticalconfig_id : Dict) -> None:
notify_event(messagebroker, EventTopicEnum.DEVICE, event_type, {'opticalconfig_id': opticalconfig_id})
def notify_event_link(messagebroker : MessageBroker, event_type : EventTypeEnum, link_id : Dict) -> None: def notify_event_link(messagebroker : MessageBroker, event_type : EventTypeEnum, link_id : Dict) -> None:
notify_event(messagebroker, EventTopicEnum.LINK, event_type, {'link_id': link_id}) notify_event(messagebroker, EventTopicEnum.LINK, event_type, {'link_id': link_id})
......
...@@ -159,15 +159,15 @@ def link_set(db_engine : Engine, messagebroker : MessageBroker, request : Link) ...@@ -159,15 +159,15 @@ def link_set(db_engine : Engine, messagebroker : MessageBroker, request : Link)
stmt = stmt.returning(TopologyLinkModel.topology_uuid) stmt = stmt.returning(TopologyLinkModel.topology_uuid)
topology_uuids = session.execute(stmt).fetchall() topology_uuids = session.execute(stmt).fetchall()
LOGGER.warning('RAW topology_uuids={:s}'.format(str(topology_uuids))) #LOGGER.warning('RAW topology_uuids={:s}'.format(str(topology_uuids)))
if len(topology_uuids) > 0: if len(topology_uuids) > 0:
topology_uuids = [topology_uuid[0] for topology_uuid in topology_uuids] topology_uuids = [topology_uuid[0] for topology_uuid in topology_uuids]
LOGGER.warning('NEW topology_uuids={:s}'.format(str(topology_uuids))) #LOGGER.warning('NEW topology_uuids={:s}'.format(str(topology_uuids)))
query = session.query(TopologyModel) query = session.query(TopologyModel)
query = query.filter(TopologyModel.topology_uuid.in_(topology_uuids)) query = query.filter(TopologyModel.topology_uuid.in_(topology_uuids))
link_topologies : List[TopologyModel] = query.all() link_topologies : List[TopologyModel] = query.all()
link_topology_ids = [obj.dump_id() for obj in link_topologies] link_topology_ids = [obj.dump_id() for obj in link_topologies]
LOGGER.warning('link_topology_ids={:s}'.format(str(link_topology_ids))) #LOGGER.warning('link_topology_ids={:s}'.format(str(link_topology_ids)))
return updated or updated_endpoints, link_topology_ids return updated or updated_endpoints, link_topology_ids
......
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# 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 json, logging
from sqlalchemy.dialects.postgresql import insert
from common.message_broker.MessageBroker import MessageBroker
from sqlalchemy.engine import Engine
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy_cockroachdb import run_transaction
from common.proto.context_pb2 import OpticalConfig, OpticalConfigId , Empty , EventTypeEnum
from .models.OpticalConfigModel import OpticalConfigModel , OpticalChannelModel
from context.service.database.uuids.OpticalConfig import channel_get_uuid
from .Events import notify_event_opticalconfig
LOGGER = logging.getLogger(__name__)
def get_opticalconfig(db_engine : Engine):
def callback(session:Session):
optical_configs = list()
results = session.query(OpticalConfigModel).all()
for obj in results:
LOGGER.info(f"opticaln config obj from context {obj.dump()}")
optical_config = OpticalConfig()
optical_config.config = json.dumps(obj.dump())
optical_config.opticalconfig_id.opticalconfig_uuid = obj.dump_id()["opticalconfig_uuid"]
optical_configs.append(optical_config)
return optical_configs
obj = run_transaction(sessionmaker(bind=db_engine), callback)
return obj
def set_opticalconfig(db_engine : Engine, request : OpticalConfig):
LOGGER.info(f"request {request} ")
opticalconfig_id = OpticalConfigId()
opticalconfig_id.opticalconfig_uuid = request.opticalconfig_id.opticalconfig_uuid
OpticalConfig_data = []
if request.config:
channels = []
transceivers = []
config = json.loads(request.config)
if 'transceivers' in config and len(config['transceivers']['transceiver']) > 0:
transceivers = [transceiver for transceiver in config['transceivers']['transceiver']]
if 'channels' in config and len(config['channels']) > 0:
#channels = [channel['name']['index'] for channel in config['channels']]
for channel_params in config['channels']:
channels.append(
{
"channel_uuid":channel_get_uuid(channel_params['name']['index']),
"opticalconfig_uuid": request.opticalconfig_id.opticalconfig_uuid,
"channel_name" : channel_params['name']['index'],
"frequency" : int(channel_params["frequency"]) if "frequency" in channel_params else 0,
"operational_mode" : int(channel_params["operational-mode"]) if "operational-mode" in channel_params else 0,
"target_output_power" : channel_params["target-output-power"] if "target-output-power" in channel_params else '',
}
)
OpticalConfig_data.append(
{
"opticalconfig_uuid": request.opticalconfig_id.opticalconfig_uuid,
"transcievers" : transceivers,
"interfaces" : json.dumps(config["interfaces"]["interface"]),
"channel_namespace" : config["channel_namespace"],
"endpoints" : [json.dumps(endpoint) for endpoint in config["endpoints"]],}
)
LOGGER.info(f"optical config to set {OpticalConfig_data} ")
LOGGER.info(f"channels {channels}")
def callback(session:Session)->bool:
stmt = insert(OpticalConfigModel).values(OpticalConfig_data)
stmt = stmt.on_conflict_do_update(
index_elements=[OpticalConfigModel.opticalconfig_uuid],
set_=dict(
channel_namespace=stmt.excluded.channel_namespace
)
)
stmt = stmt.returning(OpticalConfigModel.opticalconfig_uuid)
opticalconfig_id = session.execute(stmt).fetchone()
if (len(channels)>0) :
stmt = insert(OpticalChannelModel).values(channels)
stmt = stmt.on_conflict_do_update(
index_elements=[OpticalChannelModel.channel_uuid , OpticalConfigModel.opticalconfig_uuid],
set_=dict(
channel_name= stmt.excluded.channel_name ,
frequency = stmt.excluded.frequency,
operational_mode=stmt.excluded.operational_mode,
target_output_power=stmt.excluded.target_output_power,
)
)
stmt = stmt.returning(OpticalChannelModel.channel_uuid)
opticalChannel_id = session.execute(stmt).fetchone()
LOGGER.info(f"new optical channel config {opticalChannel_id}")
opticalconfig_id = run_transaction(sessionmaker(bind=db_engine), callback)
return {'opticalconfig_uuid': opticalconfig_id}
def select_opticalconfig(db_engine:Engine,request:OpticalConfigId):
def callback(session : Session) -> OpticalConfig:
result = OpticalConfig()
stmt = session.query(OpticalConfigModel)
stmt = stmt.filter_by(opticalconfig_uuid=request.opticalconfig_uuid)
obj = stmt.first()
if obj is not None:
result.config = json.dumps(obj.dump())
result.opticalconfig_id.opticalconfig_uuid = obj.opticalconfig_uuid
return result
return run_transaction(sessionmaker(bind=db_engine, expire_on_commit=False), callback)
def delete_opticalconfig(db_engine : Engine ,messagebroker : MessageBroker, request : OpticalConfigId):
opticalconfig_uuid = request.opticalconfig_uuid
def callback(session : Session):
query = session.query(OpticalConfigModel)
num_deleted = session.query(OpticalConfigModel).filter_by(opticalconfig_uuid=opticalconfig_uuid).delete()
return num_deleted > 0
deleted = run_transaction(sessionmaker(bind=db_engine), callback)
if deleted:
notify_event_opticalconfig(messagebroker, EventTypeEnum.EVENTTYPE_REMOVE, opticalconfig_uuid)
return Empty()
...@@ -20,7 +20,9 @@ from sqlalchemy.orm import Session, selectinload, sessionmaker ...@@ -20,7 +20,9 @@ from sqlalchemy.orm import Session, selectinload, sessionmaker
from sqlalchemy_cockroachdb import run_transaction from sqlalchemy_cockroachdb import run_transaction
from typing import Dict, List, Optional, Set from typing import Dict, List, Optional, Set
from common.proto.context_pb2 import ( from common.proto.context_pb2 import (
ContextId, Empty, EventTypeEnum, Service, ServiceFilter, ServiceId, ServiceIdList, ServiceList) ContextId, Empty, EventTypeEnum, Service, ServiceFilter, ServiceId, ServiceIdList,
ServiceList, ServiceTypeEnum
)
from common.message_broker.MessageBroker import MessageBroker from common.message_broker.MessageBroker import MessageBroker
from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException
from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Context import json_context_id
...@@ -84,6 +86,9 @@ def service_set(db_engine : Engine, messagebroker : MessageBroker, request : Ser ...@@ -84,6 +86,9 @@ def service_set(db_engine : Engine, messagebroker : MessageBroker, request : Ser
context_uuid,service_uuid = service_get_uuid(request.service_id, service_name=service_name, allow_random=True) context_uuid,service_uuid = service_get_uuid(request.service_id, service_name=service_name, allow_random=True)
service_type = grpc_to_enum__service_type(request.service_type) service_type = grpc_to_enum__service_type(request.service_type)
if service_type is None and request.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
service_type = "OPTICAL_CONNECTIVITY"
service_status = grpc_to_enum__service_status(request.service_status.service_status) service_status = grpc_to_enum__service_status(request.service_status.service_status)
now = datetime.datetime.utcnow() now = datetime.datetime.utcnow()
......
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# 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 json
from sqlalchemy import Column, String, Integer , ForeignKey
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.orm import relationship
from ._Base import _Base
class OpticalConfigModel(_Base):
__tablename__ = 'optical_config'
opticalconfig_uuid = Column(String, primary_key=True)
transcievers = Column(ARRAY(String), nullable=True)
interfaces = Column(String, nullable=True)
channel_namespace = Column(String, nullable=True)
endpoints = Column(ARRAY(String), nullable=True)
channels = relationship("OpticalChannelModel")
def dump_id (self ):
return {
"opticalconfig_uuid":self.opticalconfig_uuid
}
def dump(self):
return {
"channels" : [channel.dump() for channel in self.channels],
"transceivers" : {"transceiver": [transciever for transciever in self.transcievers]},
"interfaces" : {"interface": json.loads(self.interfaces)},
"channel_namespace" : self.channel_namespace,
"endpoints" : [json.loads(endpoint) for endpoint in self.endpoints],
}
class OpticalChannelModel(_Base):
__tablename__ = 'optical_channel'
channel_uuid = Column(String, primary_key=True)
channel_name = Column (String,nullable=True)
frequency = Column(Integer, nullable=True)
operational_mode = Column(Integer, nullable=True)
target_output_power = Column(String, nullable=True)
opticalconfig_uuid = Column(ForeignKey('optical_config.opticalconfig_uuid', ondelete='CASCADE' ), primary_key=True)
opticalconfig = relationship('OpticalConfigModel', back_populates='channels')
def dump_id (self ):
return {
"channel_uuid":self.channel_uuid
}
def dump(self):
return {
"name" :{'index':self.channel_name},
"frequency" : self.frequency,
"target-output-power" : self.target_output_power,
"operational-mode" : self.operational_mode,
}
import operator
from sqlalchemy import CheckConstraint, Column, DateTime, Float, ForeignKey, Integer, String ,Boolean
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.types import ARRAY
from sqlalchemy.orm import relationship
from typing import Dict
from ._Base import _Base
class OpticalLinkModel(_Base):
__tablename__ = 'opticallink'
optical_link_uuid = Column(UUID(as_uuid=False), primary_key=True)
optical_link_name = Column(String, nullable=False)
length = Column(Integer, nullable=True)
source = Column(String, nullable=True)
target = Column(String, nullable=True)
optical_link_fiber= relationship("FiberModel")
created_at = Column(DateTime, nullable=False)
updated_at = Column(DateTime, nullable=False)
def dump_id(self) -> Dict:
return {'optical_link_uuid': {'uuid': self.link_uuid}}
def dump(self) -> Dict:
result = {
'optical_link_id' : self.dump_id(),
'name' : self.optical_link_name,
'details': {
"length" : self.length,
'source' : self.source,
"target" : self.target,
'fibers' : [ fiber.dump() for fiber in self.optical_link_fiber ]
}
}
return result
class FiberModel(_Base):
__tablename__ = 'fiber'
fiber_uuid = Column(UUID(as_uuid=False), primary_key=True)
fiber_length = Column(Integer, nullable=True)
source_port = Column(String, nullable=True)
destination_port = Column(String, nullable=True)
local_peer_port = Column(String, nullable=True)
remote_peer_port = Column(String, nullable=True)
used = Column(Boolean ,nullable=true)
c_slots = Column (ARRAY(Integer),nullable=True)
l_slots = Column (ARRAY(Integer),nullable=True)
s_slots = Column (ARRAY(Integer),nullable=True)
optical_link_uuid = Column(ForeignKey('opticallink.optical_link_uuid', ondelete='CASCADE' ), primary_key=True)
optical_link = relationship('OpticalLinkModel', back_populates='optical_link_fibers')
def dump_id(self) -> Dict:
return {'fiber_uuid': {'uuid': self.fiber_uuid}}
def dump(self) -> Dict:
result = {
'ID' : self.dump_id(),
'length' : self.fiber_length,
"src_port" : self.source_port,
"dst_port" : self.destination_port,
"local_peer_port" : self.local_peer_port,
"remote_peer_port" : self.remote_peer_port,
"used" : self.used,
"c_slots" : self.c_slots ,
"l_slots" : self.l_slots,
"s_slots" : self.s_slots
}
return result
\ No newline at end of file
...@@ -33,6 +33,7 @@ class ORM_DeviceDriverEnum(enum.Enum): ...@@ -33,6 +33,7 @@ class ORM_DeviceDriverEnum(enum.Enum):
GNMI_OPENCONFIG = DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG GNMI_OPENCONFIG = DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG
FLEXSCALE = DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE FLEXSCALE = DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE
IETF_ACTN = DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN IETF_ACTN = DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN
OC = DeviceDriverEnum.DEVICEDRIVER_OC
grpc_to_enum__device_driver = functools.partial( grpc_to_enum__device_driver = functools.partial(
grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum) grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum)
...@@ -28,6 +28,7 @@ class ORM_ServiceTypeEnum(enum.Enum): ...@@ -28,6 +28,7 @@ class ORM_ServiceTypeEnum(enum.Enum):
TAPI_CONNECTIVITY_SERVICE = ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE TAPI_CONNECTIVITY_SERVICE = ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE
TE = ServiceTypeEnum.SERVICETYPE_TE TE = ServiceTypeEnum.SERVICETYPE_TE
E2E = ServiceTypeEnum.SERVICETYPE_E2E E2E = ServiceTypeEnum.SERVICETYPE_E2E
OPTICAL_CONNECTIVITY = ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY
grpc_to_enum__service_type = functools.partial( grpc_to_enum__service_type = functools.partial(
grpc_to_enum, ServiceTypeEnum, ORM_ServiceTypeEnum) grpc_to_enum, ServiceTypeEnum, ORM_ServiceTypeEnum)
...@@ -14,16 +14,21 @@ ...@@ -14,16 +14,21 @@
import re import re
from enum import Enum from enum import Enum
from typing import Optional from typing import Any, Optional
# Enumeration classes are redundant with gRPC classes, but gRPC does not provide a programmatical method to retrieve # Enumeration classes are redundant with gRPC classes, but gRPC does not provide a programmatical method to retrieve
# the values it expects from strings containing the desired value symbol or its integer value, so a kind of mapping is # the values it expects from strings containing the desired value symbol or its integer value, so a kind of mapping is
# required. Besides, ORM Models expect Enum classes in EnumeratedFields; we create specific and conveniently defined # required. Besides, ORM Models expect Enum classes in EnumeratedFields; we create specific and conveniently defined
# Enum classes to serve both purposes. # Enum classes to serve both purposes.
def grpc_to_enum(grpc_enum_class, orm_enum_class : Enum, grpc_enum_value, grpc_enum_prefix : Optional[str] = None): def grpc_to_enum(
grpc_enum_class, orm_enum_class : Enum, grpc_enum_value, grpc_enum_prefix : Optional[str] = None,
fail_if_not_found : bool = False
) -> Optional[Any]:
enum_name = grpc_enum_class.Name(grpc_enum_value) enum_name = grpc_enum_class.Name(grpc_enum_value)
_orig_enum_name = enum_name
_orig_grpc_enum_prefix = grpc_enum_prefix
if grpc_enum_prefix is None: if grpc_enum_prefix is None:
grpc_enum_prefix = orm_enum_class.__name__.upper() grpc_enum_prefix = orm_enum_class.__name__.upper()
#grpc_enum_prefix = re.sub(r'^ORM_(.+)$', r'\1', grpc_enum_prefix) #grpc_enum_prefix = re.sub(r'^ORM_(.+)$', r'\1', grpc_enum_prefix)
...@@ -35,4 +40,7 @@ def grpc_to_enum(grpc_enum_class, orm_enum_class : Enum, grpc_enum_value, grpc_e ...@@ -35,4 +40,7 @@ def grpc_to_enum(grpc_enum_class, orm_enum_class : Enum, grpc_enum_value, grpc_e
enum_name = enum_name.replace(grpc_enum_prefix, '') enum_name = enum_name.replace(grpc_enum_prefix, '')
orm_enum_value = orm_enum_class._member_map_.get(enum_name) orm_enum_value = orm_enum_class._member_map_.get(enum_name)
if orm_enum_value is None and fail_if_not_found:
MSG = 'Unable to map gRPC Enum Value ({:s} / {:s}) to ORM Enum Value; grpc_enum_prefix={:s}'
raise Exception(MSG.format(str(grpc_enum_value), str(_orig_enum_name), str(_orig_grpc_enum_prefix)))
return orm_enum_value return orm_enum_value
from common.method_wrappers.ServiceExceptions import InvalidArgumentsException
from ._Builder import get_uuid_from_string, get_uuid_random
def channel_get_uuid(
channel_name :str , allow_random : bool = False
) -> str:
if len(channel_name) > 0:
return get_uuid_from_string(channel_name)
if allow_random: return get_uuid_random()
raise InvalidArgumentsException([
('channel uuid', channel_name),
], extra_details=['Channel name is required to produce a channel UUID'])
...@@ -21,7 +21,7 @@ build dbscanserving: ...@@ -21,7 +21,7 @@ build dbscanserving:
before_script: before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script: script:
- docker build -t "$IMAGE_NAME:$IMAGE_TAG" -f ./src/$IMAGE_NAME/Dockerfile . - docker buildx build -t "$IMAGE_NAME:$IMAGE_TAG" -f ./src/$IMAGE_NAME/Dockerfile .
- docker tag "$IMAGE_NAME:$IMAGE_TAG" "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" - docker tag "$IMAGE_NAME:$IMAGE_TAG" "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
- docker push "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" - docker push "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
after_script: after_script:
......
...@@ -21,7 +21,7 @@ build device: ...@@ -21,7 +21,7 @@ build device:
before_script: before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script: script:
- docker build -t "$IMAGE_NAME:$IMAGE_TAG" -f ./src/$IMAGE_NAME/Dockerfile . - docker buildx build -t "$IMAGE_NAME:$IMAGE_TAG" -f ./src/$IMAGE_NAME/Dockerfile .
- docker tag "$IMAGE_NAME:$IMAGE_TAG" "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" - docker tag "$IMAGE_NAME:$IMAGE_TAG" "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
- docker push "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" - docker push "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
after_script: after_script:
......
...@@ -12,3 +12,9 @@ ...@@ -12,3 +12,9 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os
TRUE_VALUES = {'T', 'TRUE', 'YES', '1'}
DEVICE_EMULATED_ONLY = os.environ.get('DEVICE_EMULATED_ONLY')
LOAD_ALL_DEVICE_DRIVERS = (DEVICE_EMULATED_ONLY is None) or (DEVICE_EMULATED_ONLY.upper() not in TRUE_VALUES)
...@@ -62,9 +62,11 @@ RUN python3 -m pip install -r requirements.txt ...@@ -62,9 +62,11 @@ RUN python3 -m pip install -r requirements.txt
# Add component files into working directory # Add component files into working directory
WORKDIR /var/teraflow WORKDIR /var/teraflow
COPY src/context/. context/ COPY src/context/__init__.py context/__init__.py
COPY src/context/client/. context/client/
COPY src/monitoring/__init__.py monitoring/__init__.py
COPY src/monitoring/client/. monitoring/client/
COPY src/device/. device/ COPY src/device/. device/
COPY src/monitoring/. monitoring/
RUN mkdir -p tests/tools/mock_ietf_actn_sdn_ctrl RUN mkdir -p tests/tools/mock_ietf_actn_sdn_ctrl
RUN touch tests/__init__.py RUN touch tests/__init__.py
......
...@@ -15,12 +15,12 @@ ...@@ -15,12 +15,12 @@
import grpc, logging import grpc, logging
from common.Constants import ServiceNameEnum from common.Constants import ServiceNameEnum
from common.Settings import get_service_host, get_service_port_grpc from common.Settings import get_service_host, get_service_port_grpc
from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty,OpticalConfig,OpticalConfigId
from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2 import MonitoringSettings
from common.proto.device_pb2_grpc import DeviceServiceStub from common.proto.device_pb2_grpc import DeviceServiceStub
from common.tools.client.RetryDecorator import retry, delay_exponential from common.tools.client.RetryDecorator import retry, delay_exponential
from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.grpc.Tools import grpc_message_to_json_string
from common.proto.openconfig_device_pb2_grpc import OpenConfigServiceStub
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
MAX_RETRIES = 15 MAX_RETRIES = 15
DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0) DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0)
...@@ -34,12 +34,14 @@ class DeviceClient: ...@@ -34,12 +34,14 @@ class DeviceClient:
LOGGER.debug('Creating channel to {:s}...'.format(str(self.endpoint))) LOGGER.debug('Creating channel to {:s}...'.format(str(self.endpoint)))
self.channel = None self.channel = None
self.stub = None self.stub = None
self.openconfig_stub=None
self.connect() self.connect()
LOGGER.debug('Channel created') LOGGER.debug('Channel created')
def connect(self): def connect(self):
self.channel = grpc.insecure_channel(self.endpoint) self.channel = grpc.insecure_channel(self.endpoint)
self.stub = DeviceServiceStub(self.channel) self.stub = DeviceServiceStub(self.channel)
self.openconfig_stub=OpenConfigServiceStub(self.channel)
def close(self): def close(self):
if self.channel is not None: self.channel.close() if self.channel is not None: self.channel.close()
...@@ -80,3 +82,8 @@ class DeviceClient: ...@@ -80,3 +82,8 @@ class DeviceClient:
response = self.stub.MonitorDeviceKpi(request) response = self.stub.MonitorDeviceKpi(request)
LOGGER.debug('MonitorDeviceKpi result: {:s}'.format(grpc_message_to_json_string(response))) LOGGER.debug('MonitorDeviceKpi result: {:s}'.format(grpc_message_to_json_string(response)))
return response return response
def ConfigureOpticalDevice(self, request : OpticalConfig) -> OpticalConfigId:
LOGGER.debug('ConfigureOpticalDevice request: {:s}'.format(grpc_message_to_json_string(request)))
response = self.openconfig_stub.ConfigureOpticalDevice(request)
LOGGER.debug('ConfigureOpticalDevice result: {:s}'.format(grpc_message_to_json_string(response)))
return response
...@@ -12,13 +12,17 @@ ...@@ -12,13 +12,17 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os
from common.Constants import ServiceNameEnum from common.Constants import ServiceNameEnum
from common.Settings import get_service_port_grpc from common.Settings import get_service_port_grpc
from common.proto.device_pb2_grpc import add_DeviceServiceServicer_to_server from common.proto.device_pb2_grpc import add_DeviceServiceServicer_to_server
from common.proto.openconfig_device_pb2_grpc import add_OpenConfigServiceServicer_to_server
from common.tools.service.GenericGrpcService import GenericGrpcService from common.tools.service.GenericGrpcService import GenericGrpcService
from device.Config import LOAD_ALL_DEVICE_DRIVERS
from .driver_api.DriverInstanceCache import DriverInstanceCache from .driver_api.DriverInstanceCache import DriverInstanceCache
from .DeviceServiceServicerImpl import DeviceServiceServicerImpl from .DeviceServiceServicerImpl import DeviceServiceServicerImpl
from .monitoring.MonitoringLoops import MonitoringLoops from .monitoring.MonitoringLoops import MonitoringLoops
from .OpenConfigServicer import OpenConfigServicer
# Custom gRPC settings # Custom gRPC settings
# Multiple clients might keep connections alive waiting for RPC methods to be executed. # Multiple clients might keep connections alive waiting for RPC methods to be executed.
...@@ -31,10 +35,14 @@ class DeviceService(GenericGrpcService): ...@@ -31,10 +35,14 @@ class DeviceService(GenericGrpcService):
super().__init__(port, max_workers=GRPC_MAX_WORKERS, cls_name=cls_name) super().__init__(port, max_workers=GRPC_MAX_WORKERS, cls_name=cls_name)
self.monitoring_loops = MonitoringLoops() self.monitoring_loops = MonitoringLoops()
self.device_servicer = DeviceServiceServicerImpl(driver_instance_cache, self.monitoring_loops) self.device_servicer = DeviceServiceServicerImpl(driver_instance_cache, self.monitoring_loops)
if LOAD_ALL_DEVICE_DRIVERS:
self.openconfig_device_servicer = OpenConfigServicer(driver_instance_cache,self.monitoring_loops)
def install_servicers(self): def install_servicers(self):
self.monitoring_loops.start() self.monitoring_loops.start()
add_DeviceServiceServicer_to_server(self.device_servicer, self.server) add_DeviceServiceServicer_to_server(self.device_servicer, self.server)
if LOAD_ALL_DEVICE_DRIVERS:
add_OpenConfigServiceServicer_to_server(self.openconfig_device_servicer,self.server)
def stop(self): def stop(self):
super().stop() super().stop()
......
...@@ -20,7 +20,9 @@ from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name ...@@ -20,7 +20,9 @@ from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name
from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method
from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException
from common.proto.context_pb2 import ( from common.proto.context_pb2 import (
Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link) Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link,
OpticalConfig, OpticalConfigId
)
from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2 import MonitoringSettings
from common.proto.device_pb2_grpc import DeviceServiceServicer from common.proto.device_pb2_grpc import DeviceServiceServicer
from common.tools.context_queries.Device import get_device from common.tools.context_queries.Device import get_device
...@@ -58,6 +60,7 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): ...@@ -58,6 +60,7 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
device_uuid = request.device_id.device_uuid.uuid device_uuid = request.device_id.device_uuid.uuid
connection_config_rules = check_connect_rules(request.device_config) connection_config_rules = check_connect_rules(request.device_config)
if request.device_drivers[0] != DeviceDriverEnum.DEVICEDRIVER_OC:
check_no_endpoints(request.device_endpoints) check_no_endpoints(request.device_endpoints)
t1 = time.time() t1 = time.time()
...@@ -85,9 +88,11 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): ...@@ -85,9 +88,11 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
# update device_uuid to honor UUID provided by Context # update device_uuid to honor UUID provided by Context
device_uuid = device.device_id.device_uuid.uuid device_uuid = device.device_id.device_uuid.uuid
device_name = device.name
t2 = time.time() t2 = time.time()
self.mutex_queues.add_alias(device_uuid, device_name)
self.mutex_queues.wait_my_turn(device_uuid) self.mutex_queues.wait_my_turn(device_uuid)
t3 = time.time() t3 = time.time()
try: try:
...@@ -139,6 +144,13 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): ...@@ -139,6 +144,13 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
# ZTP is not deployed; assume the device is ready while onboarding and set them as enabled. # ZTP is not deployed; assume the device is ready while onboarding and set them as enabled.
device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
# temporary line
if request.device_drivers[0] == DeviceDriverEnum.DEVICEDRIVER_OC and len(request.device_endpoints) > 0:
#for endpoint in request.device_endpoints:
# #endpoint.endpoint_id.device_id.CopyFrom(device.device_id)
# pass
device.device_endpoints.extend(request.device_endpoints)
device_id = context_client.SetDevice(device) device_id = context_client.SetDevice(device)
t10 = time.time() t10 = time.time()
......
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# 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 grpc, logging, json
from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method
from common.method_wrappers.ServiceExceptions import NotFoundException
from common.proto.context_pb2 import (
Device, DeviceId, DeviceOperationalStatusEnum, Empty, OpticalConfig, OpticalConfig
)
from common.proto.device_pb2_grpc import DeviceServiceServicer
from common.tools.context_queries.Device import get_device
from common.tools.mutex_queues.MutexQueues import MutexQueues
from context.client.ContextClient import ContextClient
from .driver_api._Driver import _Driver
from .driver_api.DriverInstanceCache import DriverInstanceCache, get_driver
from .monitoring.MonitoringLoops import MonitoringLoops
from .Tools import extract_resources
from .Tools import check_no_endpoints
LOGGER = logging.getLogger(__name__)
METRICS_POOL = MetricsPool('Device', 'RPC')
METRICS_POOL_DETAILS = MetricsPool('Device', 'execution', labels={
'driver': '', 'operation': '', 'step': '',
})
class OpenConfigServicer(DeviceServiceServicer):
def __init__(self, driver_instance_cache : DriverInstanceCache, monitoring_loops : MonitoringLoops) -> None:
LOGGER.debug('Creating Servicer...')
self.driver_instance_cache = driver_instance_cache
self.monitoring_loops = monitoring_loops
self.mutex_queues = MutexQueues()
LOGGER.debug('Servicer Created')
@safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
def AddOpenConfigDevice(self, request : OpticalConfig, context : grpc.ServicerContext) -> DeviceId:
device_uuid = request.device_id.device_uuid.uuid
check_no_endpoints(request.device_endpoints)
context_client = ContextClient()
device = get_device(context_client, device_uuid, rw_copy=True)
if device is None:
# not in context, create blank one to get UUID, and populate it below
device = Device()
device.device_id.CopyFrom(request.device_id) # pylint: disable=no-member
device.name = request.name
device.device_type = request.device_type
device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED
device.device_drivers.extend(request.device_drivers) # pylint: disable=no-member
device.device_config.CopyFrom(request.device_config)
device.device_endpoints.extend(request.device_endpoints)
# pylint: disable=no-member
device_id = context_client.SetDevice(device)
device = get_device(context_client, device_id.device_uuid.uuid, rw_copy=True)
# update device_uuid to honor UUID provided by Context
device_uuid = device.device_id.device_uuid.uuid
self.mutex_queues.wait_my_turn(device_uuid)
try:
device_id = context_client.SetDevice(device)
except Exception as error :
LOGGER.debug("error %s",error)
@safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
def ConfigureOpticalDevice (self, request : OpticalConfig, context : grpc.ServicerContext) -> Empty:
device_uuid = request.opticalconfig_id.opticalconfig_uuid
resources=[]
is_all_good=True
config =json.loads(request.config)
LOGGER.info(f" config from openconfigservicer {config}")
try:
context_client = ContextClient()
device = get_device(
context_client, device_uuid, rw_copy=True, include_endpoints=True, include_components=False,
include_config_rules=False)
LOGGER.info(f"device is {device}")
if device is None:
raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice')
resources,conditions=extract_resources(config=config,device=device)
LOGGER.info(f"from openconfigservicer {resources} and conditions {conditions}")
driver : _Driver = get_driver(self.driver_instance_cache, device)
results = driver.SetConfig(resources=resources,conditions=conditions)
for result in results:
if not result :
is_all_good=False
LOGGER.info(f"resluts {results} and is_all_good {is_all_good}")
if is_all_good:
driver.GetConfig(resource_keys=[])
#TODO: add a control with the NETCONF get
#driver.GetConfig(resource_keys=filter_fields)
except Exception as e:
LOGGER.info("error in configuring %s",e)
return Empty()
...@@ -15,12 +15,14 @@ ...@@ -15,12 +15,14 @@
import json, logging import json, logging
from typing import Any, Dict, List, Optional, Tuple, Union from typing import Any, Dict, List, Optional, Tuple, Union
from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME
from common.method_wrappers.ServiceExceptions import InvalidArgumentException from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import ConfigActionEnum, ConfigRule_ACL, Device, DeviceConfig, Link, Location from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException
from common.proto.context_pb2 import ConfigActionEnum, ConfigRule_ACL, Device, DeviceConfig, EndPoint, Link, Location
from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2 import MonitoringSettings
from common.proto.kpi_sample_types_pb2 import KpiSampleType from common.proto.kpi_sample_types_pb2 import KpiSampleType
from common.tools.grpc.ConfigRules import update_config_rule_custom from common.tools.grpc.ConfigRules import update_config_rule_custom
from common.tools.grpc.Tools import grpc_message_to_json from common.tools.grpc.Tools import grpc_message_to_json
from common.type_checkers.Checkers import chk_length, chk_type
from .driver_api._Driver import _Driver, RESOURCE_ENDPOINTS from .driver_api._Driver import _Driver, RESOURCE_ENDPOINTS
from .monitoring.MonitoringLoops import MonitoringLoops from .monitoring.MonitoringLoops import MonitoringLoops
from .ErrorMessages import ( from .ErrorMessages import (
...@@ -30,6 +32,21 @@ from .ErrorMessages import ( ...@@ -30,6 +32,21 @@ from .ErrorMessages import (
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
def get_endpoint_matching(device : Device, endpoint_uuid_or_name : str) -> EndPoint:
for endpoint in device.device_endpoints:
choices = {endpoint.endpoint_id.endpoint_uuid.uuid, endpoint.name}
if endpoint_uuid_or_name in choices: return endpoint
device_uuid = device.device_id.device_uuid.uuid
extra_details = 'Device({:s})'.format(str(device_uuid))
raise NotFoundException('Endpoint', endpoint_uuid_or_name, extra_details=extra_details)
def get_device_endpoint_uuids(endpoint : Tuple[str, str, Optional[str]]) -> Tuple[str, str]:
chk_type('endpoint', endpoint, (tuple, list))
chk_length('endpoint', endpoint, min_length=2, max_length=3)
device_uuid, endpoint_uuid = endpoint[0:2] # ignore topology_uuid by now
return device_uuid, endpoint_uuid
def check_connect_rules(device_config : DeviceConfig) -> Dict[str, Any]: def check_connect_rules(device_config : DeviceConfig) -> Dict[str, Any]:
connection_config_rules = dict() connection_config_rules = dict()
unexpected_config_rules = list() unexpected_config_rules = list()
...@@ -97,6 +114,7 @@ def populate_endpoints( ...@@ -97,6 +114,7 @@ def populate_endpoints(
resources_to_get = [RESOURCE_ENDPOINTS] resources_to_get = [RESOURCE_ENDPOINTS]
results_getconfig = driver.GetConfig(resources_to_get) results_getconfig = driver.GetConfig(resources_to_get)
LOGGER.debug('results_getconfig = {:s}'.format(str(results_getconfig))) LOGGER.debug('results_getconfig = {:s}'.format(str(results_getconfig)))
LOGGER.info('results_getconfig = {:s}'.format(str(results_getconfig)))
# first quick pass to identify need of mgmt endpoints and links # first quick pass to identify need of mgmt endpoints and links
add_mgmt_port = False add_mgmt_port = False
...@@ -434,3 +452,74 @@ def update_endpoints(src_device : Device, dst_device : Device) -> None: ...@@ -434,3 +452,74 @@ def update_endpoints(src_device : Device, dst_device : Device) -> None:
dst_topology_id = dst_endpoint_id.topology_id dst_topology_id = dst_endpoint_id.topology_id
if len(src_topology_uuid) > 0: dst_topology_id.topology_uuid.uuid = src_topology_uuid if len(src_topology_uuid) > 0: dst_topology_id.topology_uuid.uuid = src_topology_uuid
if len(src_context_uuid) > 0: dst_topology_id.context_id.context_uuid.uuid = src_context_uuid if len(src_context_uuid) > 0: dst_topology_id.context_id.context_uuid.uuid = src_context_uuid
def get_edit_target(device : Device, is_opticalband : bool) -> str:
if is_opticalband: return 'optical-band'
if device.device_type == DeviceTypeEnum.OPTICAL_ROADM: return 'media-channel'
return 'optical-channel'
def is_key_existed(key : str, keys_dic = dict, key_name_to_use = None) -> dict:
dic = {}
dic['resource_key'] = key
if key_name_to_use is not None:
dic['resource_key'] = key_name_to_use
if key in keys_dic:
dic['value'] = keys_dic[key]
else:
dic['value'] = None
return dic
def extract_resources(config : dict, device : Device) -> list:
conditions = {}
resources = []
resources.append(is_key_existed('channel_namespace', config))
resources.append(is_key_existed('add_transceiver', config))
is_opticalband = config.get('is_opticalband', False)
conditions['is_opticalband'] = is_opticalband
conditions['edit_type'] = get_edit_target(device, is_opticalband)
if 'flow' in config:
#for tuple_value in config['flow'][device.name]:
source_vals = []
dest_vals = []
for tuple_value in config['flow']:
source_port = None
destination_port = None
source_port_uuid, destination_port_uuid = tuple_value
if source_port_uuid != '0':
src_endpoint_obj = get_endpoint_matching(device, source_port_uuid)
source_port = src_endpoint_obj.name
source_vals.append(source_port)
if destination_port_uuid != '0':
dst_endpoint_obj = get_endpoint_matching(device, destination_port_uuid)
destination_port = dst_endpoint_obj.name
dest_vals.append(destination_port)
resources.append({'resource_key': 'source_port', 'value': source_vals})
resources.append({'resource_key': 'destination_port', 'value': dest_vals })
if 'new_config' in config:
lower_frequency = None
upper_frequency = None
resources.append(is_key_existed('target-output-power', keys_dic=config['new_config']))
resources.append(is_key_existed('frequency', keys_dic=config['new_config']))
resources.append(is_key_existed('operational-mode', keys_dic=config['new_config']))
resources.append(is_key_existed('line-port', keys_dic=config['new_config']))
resources.append(is_key_existed('band_type', keys_dic=config['new_config'], key_name_to_use='name'))
resources.append(is_key_existed('ob_id', keys_dic=config['new_config'], key_name_to_use='optical-band-parent'))
resources.append(is_key_existed('name', keys_dic=config['new_config'], key_name_to_use='channel_name'))
if not is_opticalband:
if 'frequency' in config['new_config'] and 'band' in config['new_config'] and conditions['edit_type'] == 'media-channel':
lower_frequency = int(int(config['new_config']['frequency']) - (int(config['new_config']['band'])/2))
upper_frequency = int(int(config['new_config']['frequency']) + (int(config['new_config']['band'])/2))
#lower_frequency = (config['new_config']['frequency'] - config['new_config']['band'])/2
#upper_frequency = (config['new_config']['frequency'] + config['new_config']['band'])/2
resources.append(is_key_existed('flow_id', keys_dic=config['new_config'], key_name_to_use='index'))
#resources.append({'resource_key':'index','value':config['new_config']['flow_id'] if 'flow_id' in config['new_config'] else None})
else:
lower_frequency = config['new_config']['low-freq'] if 'low-freq' in config['new_config'] else None
upper_frequency = config['new_config']['up-freq' ] if 'up-freq' in config['new_config'] else None
resources.append(is_key_existed('ob_id', keys_dic=config['new_config'], key_name_to_use='index'))
#resources.append({'resource_key':'index','value':config['new_config']['ob_id'] if 'ob_id' in config['new_config'] else None})
resources.append({'resource_key': 'lower-frequency', 'value': lower_frequency})
resources.append({'resource_key': 'upper-frequency', 'value': upper_frequency})
return [resources, conditions]