Skip to content
Snippets Groups Projects
Commit b6b9d698 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Context compoent:

- progress on migration to CockroachDB (partial)
parent 177e96a8
No related branches found
No related tags found
2 merge requests!54Release 2.0.0,!34Context Scalability extensions using CockroachDB + Removal of Stateful database inside Device + other
Showing with 709 additions and 804 deletions
...@@ -36,14 +36,16 @@ cd $PROJECTDIR/src ...@@ -36,14 +36,16 @@ cd $PROJECTDIR/src
#export REDIS_SERVICE_HOST=$(kubectl get node $TFS_K8S_HOSTNAME -o 'jsonpath={.status.addresses[?(@.type=="InternalIP")].address}') #export REDIS_SERVICE_HOST=$(kubectl get node $TFS_K8S_HOSTNAME -o 'jsonpath={.status.addresses[?(@.type=="InternalIP")].address}')
#export REDIS_SERVICE_PORT=$(kubectl --namespace $TFS_K8S_NAMESPACE get service redis-tests -o 'jsonpath={.spec.ports[?(@.port==6379)].nodePort}') #export REDIS_SERVICE_PORT=$(kubectl --namespace $TFS_K8S_NAMESPACE get service redis-tests -o 'jsonpath={.spec.ports[?(@.port==6379)].nodePort}')
export CRDB_URI="cockroachdb://tfs:tfs123@10.1.7.195:26257/tfs?sslmode=require" #export CRDB_URI="cockroachdb://tfs:tfs123@127.0.0.1:26257/tfs_test?sslmode=require"
export CRDB_URI="cockroachdb://tfs:tfs123@10.1.7.195:26257/tfs_test?sslmode=require"
export PYTHONPATH=/home/tfs/tfs-ctrl/src export PYTHONPATH=/home/tfs/tfs-ctrl/src
# Run unitary tests and analyze coverage of code at same time # Run unitary tests and analyze coverage of code at same time
#coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose --maxfail=1 \ #coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose --maxfail=1 \
# context/tests/test_unitary.py # context/tests/test_unitary.py
pytest --log-level=INFO --verbose -o log_cli=true --maxfail=1 \ # --log-level=INFO -o log_cli=true
pytest --verbose --maxfail=1 --durations=0 \
context/tests/test_unitary.py context/tests/test_unitary.py
#kubectl --namespace $TFS_K8S_NAMESPACE delete service redis-tests #kubectl --namespace $TFS_K8S_NAMESPACE delete service redis-tests
This diff is collapsed.
...@@ -20,21 +20,31 @@ LOGGER = logging.getLogger(__name__) ...@@ -20,21 +20,31 @@ LOGGER = logging.getLogger(__name__)
APP_NAME = 'tfs' APP_NAME = 'tfs'
class Engine: class Engine:
def get_engine(self) -> sqlalchemy.engine.Engine: @staticmethod
def get_engine() -> sqlalchemy.engine.Engine:
crdb_uri = get_setting('CRDB_URI') crdb_uri = get_setting('CRDB_URI')
try: try:
engine = sqlalchemy.create_engine( engine = sqlalchemy.create_engine(
crdb_uri, connect_args={'application_name': APP_NAME}, echo=False, future=True) crdb_uri, connect_args={'application_name': APP_NAME}, echo=True, future=True)
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
LOGGER.exception('Failed to connect to database: {:s}'.format(crdb_uri)) LOGGER.exception('Failed to connect to database: {:s}'.format(crdb_uri))
return None return None
try: try:
if not sqlalchemy_utils.database_exists(engine.url): Engine.create_database(engine)
sqlalchemy_utils.create_database(engine.url)
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
LOGGER.exception('Failed to check/create to database: {:s}'.format(crdb_uri)) LOGGER.exception('Failed to check/create to database: {:s}'.format(engine.url))
return None return None
return engine return engine
@staticmethod
def create_database(engine : sqlalchemy.engine.Engine) -> None:
if not sqlalchemy_utils.database_exists(engine.url):
sqlalchemy_utils.create_database(engine.url)
@staticmethod
def drop_database(engine : sqlalchemy.engine.Engine) -> None:
if sqlalchemy_utils.database_exists(engine.url):
sqlalchemy_utils.drop_database(engine.url)
...@@ -45,7 +45,7 @@ def main(): ...@@ -45,7 +45,7 @@ def main():
metrics_port = get_metrics_port() metrics_port = get_metrics_port()
start_http_server(metrics_port) start_http_server(metrics_port)
db_engine = Engine().get_engine() db_engine = Engine.get_engine()
rebuild_database(db_engine, drop_if_exists=False) rebuild_database(db_engine, drop_if_exists=False)
# Get message broker instance # Get message broker instance
......
...@@ -12,15 +12,12 @@ ...@@ -12,15 +12,12 @@
# 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 logging from typing import Dict, List
from typing import Dict
from sqlalchemy import Column, Float, String from sqlalchemy import Column, Float, String
from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from ._Base import _Base from ._Base import _Base
LOGGER = logging.getLogger(__name__)
class ContextModel(_Base): class ContextModel(_Base):
__tablename__ = 'context' __tablename__ = 'context'
context_uuid = Column(UUID(as_uuid=False), primary_key=True) context_uuid = Column(UUID(as_uuid=False), primary_key=True)
...@@ -28,33 +25,20 @@ class ContextModel(_Base): ...@@ -28,33 +25,20 @@ class ContextModel(_Base):
created_at = Column(Float) created_at = Column(Float)
topology = relationship('TopologyModel', back_populates='context') topology = relationship('TopologyModel', back_populates='context')
#service = relationship('ServiceModel', back_populates='context')
#slice = relationship('SliceModel', back_populates='context')
def dump_id(self) -> Dict: def dump_id(self) -> Dict:
return {'context_uuid': {'uuid': self.context_uuid}} return {'context_uuid': {'uuid': self.context_uuid}}
#@staticmethod
#def main_pk_name():
# return 'context_uuid'
"""
def dump_service_ids(self) -> List[Dict]:
from .ServiceModel import ServiceModel # pylint: disable=import-outside-toplevel
db_service_pks = self.references(ServiceModel)
return [ServiceModel(self.database, pk).dump_id() for pk,_ in db_service_pks]
def dump_topology_ids(self) -> List[Dict]: def dump_topology_ids(self) -> List[Dict]:
from .TopologyModel import TopologyModel # pylint: disable=import-outside-toplevel return
db_topology_pks = self.references(TopologyModel)
return [TopologyModel(self.database, pk).dump_id() for pk,_ in db_topology_pks] def dump(self) -> Dict:
""" return {
'context_id' : self.dump_id(),
def dump(self, 'name' : self.context_name,
include_services : bool = True, # pylint: disable=arguments-differ 'topology_ids': [obj.dump_id() for obj in self.topology],
include_slices : bool = True, # pylint: disable=arguments-differ #'service_ids' : [obj.dump_id() for obj in self.service ],
include_topologies : bool = True # pylint: disable=arguments-differ #'slice_ids' : [obj.dump_id() for obj in self.slice ],
) -> Dict: }
result = {'context_id': self.dump_id(), 'name': self.context_name}
# if include_services: result['service_ids'] = self.dump_service_ids()
# if include_slices: result['slice_ids'] = self.dump_slice_ids()
# if include_topologies: result['topology_ids'] = self.dump_topology_ids()
return result
...@@ -11,17 +11,18 @@ ...@@ -11,17 +11,18 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# 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 enum import enum
import functools, logging import functools, logging
import uuid #import uuid
from typing import Dict, List from typing import Dict #, List
from common.orm.Database import Database #from common.orm.Database import Database
from common.orm.backend.Tools import key_to_str #from common.orm.backend.Tools import key_to_str
from common.proto.context_pb2 import DeviceDriverEnum, DeviceOperationalStatusEnum from common.proto.context_pb2 import DeviceDriverEnum, DeviceOperationalStatusEnum
from sqlalchemy import Column, ForeignKey, String, Enum from sqlalchemy import Column, Float, ForeignKey, String, Enum
from sqlalchemy.dialects.postgresql import UUID, ARRAY from sqlalchemy.dialects.postgresql import UUID, ARRAY
from context.service.database._Base import Base
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from context.service.database._Base import _Base
from .Tools import grpc_to_enum from .Tools import grpc_to_enum
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
...@@ -46,80 +47,152 @@ class ORM_DeviceOperationalStatusEnum(enum.Enum): ...@@ -46,80 +47,152 @@ class ORM_DeviceOperationalStatusEnum(enum.Enum):
grpc_to_enum__device_operational_status = functools.partial( grpc_to_enum__device_operational_status = functools.partial(
grpc_to_enum, DeviceOperationalStatusEnum, ORM_DeviceOperationalStatusEnum) grpc_to_enum, DeviceOperationalStatusEnum, ORM_DeviceOperationalStatusEnum)
class DeviceModel(Base): class DeviceModel(_Base):
__tablename__ = 'Device' __tablename__ = 'device'
device_uuid = Column(UUID(as_uuid=False), primary_key=True) device_uuid = Column(UUID(as_uuid=False), primary_key=True)
device_type = Column(String) device_name = Column(String(), nullable=False)
device_config_uuid = Column(UUID(as_uuid=False), ForeignKey("Config.config_uuid", ondelete='CASCADE')) device_type = Column(String(), nullable=False)
device_operational_status = Column(Enum(ORM_DeviceOperationalStatusEnum, create_constraint=False, #device_config_uuid = Column(UUID(as_uuid=False), ForeignKey('config.config_uuid', ondelete='CASCADE'))
native_enum=False)) device_operational_status = Column(Enum(ORM_DeviceOperationalStatusEnum))
device_drivers = Column(ARRAY(Enum(ORM_DeviceDriverEnum), dimensions=1))
created_at = Column(Float)
# Relationships # Relationships
device_config = relationship("ConfigModel", passive_deletes=True, lazy="joined") topology_device = relationship('TopologyDeviceModel', back_populates='devices')
driver = relationship("DriverModel", passive_deletes=True, back_populates="device") #device_config = relationship("ConfigModel", passive_deletes=True, lazy="joined")
endpoints = relationship("EndPointModel", passive_deletes=True, back_populates="device") endpoints = relationship('EndPointModel', passive_deletes=True, back_populates='device')
def dump_id(self) -> Dict: def dump_id(self) -> Dict:
return {'device_uuid': {'uuid': self.device_uuid}} return {'device_uuid': {'uuid': self.device_uuid}}
def dump_config(self) -> Dict: def dump(self) -> Dict:
return self.device_config.dump() return {
'device_id' : self.dump_id(),
def dump_drivers(self) -> List[int]: 'name' : self.device_name,
response = [] 'device_type' : self.device_type,
for a in self.driver:
response.append(a.dump())
return response
def dump_endpoints(self) -> List[Dict]:
response = []
for a in self.endpoints:
response.append(a.dump())
return response
def dump( # pylint: disable=arguments-differ
self, include_config_rules=True, include_drivers=True, include_endpoints=True
) -> Dict:
result = {
'device_id': self.dump_id(),
'device_type': self.device_type,
'device_operational_status': self.device_operational_status.value, 'device_operational_status': self.device_operational_status.value,
'device_drivers' : [d.value for d in self.device_drivers],
#'device_config' : {'config_rules': self.device_config.dump()},
#'device_endpoints' : [ep.dump() for ep in self.endpoints],
} }
if include_config_rules: result.setdefault('device_config', {})['config_rules'] = self.dump_config()
if include_drivers: result['device_drivers'] = self.dump_drivers()
if include_endpoints: result['device_endpoints'] = self.dump_endpoints()
return result
@staticmethod
def main_pk_name():
return 'device_uuid'
class DriverModel(Base): # pylint: disable=abstract-method #def set_drivers(database : Database, db_device : DeviceModel, grpc_device_drivers):
__tablename__ = 'Driver' # db_device_pk = db_device.device_uuid
# driver_uuid = Column(UUID(as_uuid=False), primary_key=True) # for driver in grpc_device_drivers:
device_uuid = Column(UUID(as_uuid=False), ForeignKey("Device.device_uuid", ondelete='CASCADE'), primary_key=True) # orm_driver = grpc_to_enum__device_driver(driver)
driver = Column(Enum(ORM_DeviceDriverEnum, create_constraint=False, native_enum=False)) # str_device_driver_key = key_to_str([db_device_pk, orm_driver.name])
# db_device_driver = DriverModel(database, str_device_driver_key)
# Relationships # db_device_driver.device_fk = db_device
device = relationship("DeviceModel", back_populates="driver") # db_device_driver.driver = orm_driver
# db_device_driver.save()
def dump(self) -> Dict: # def set_kpi_sample_types(self, db_endpoint: EndPointModel, grpc_endpoint_kpi_sample_types):
return self.driver.value # db_endpoint_pk = db_endpoint.endpoint_uuid
# for kpi_sample_type in grpc_endpoint_kpi_sample_types:
@staticmethod # orm_kpi_sample_type = grpc_to_enum__kpi_sample_type(kpi_sample_type)
def main_pk_name(): # # str_endpoint_kpi_sample_type_key = key_to_str([db_endpoint_pk, orm_kpi_sample_type.name])
return 'device_uuid' # data = {'endpoint_uuid': db_endpoint_pk,
# 'kpi_sample_type': orm_kpi_sample_type.name,
# 'kpi_uuid': str(uuid.uuid4())}
# db_endpoint_kpi_sample_type = KpiSampleTypeModel(**data)
# self.database.create(db_endpoint_kpi_sample_type)
# def set_drivers(self, db_device: DeviceModel, grpc_device_drivers):
# db_device_pk = db_device.device_uuid
# for driver in grpc_device_drivers:
# orm_driver = grpc_to_enum__device_driver(driver)
# str_device_driver_key = key_to_str([db_device_pk, orm_driver.name])
# driver_config = {
# # "driver_uuid": str(uuid.uuid4()),
# "device_uuid": db_device_pk,
# "driver": orm_driver.name
# }
# db_device_driver = DriverModel(**driver_config)
# db_device_driver.device_fk = db_device
# db_device_driver.driver = orm_driver
#
# self.database.create_or_update(db_device_driver)
def set_drivers(database : Database, db_device : DeviceModel, grpc_device_drivers): # def update_config(
db_device_pk = db_device.device_uuid # self, session, db_parent_pk: str, config_name: str,
for driver in grpc_device_drivers: # raw_config_rules: List[Tuple[ORM_ConfigActionEnum, str, str]]
orm_driver = grpc_to_enum__device_driver(driver) # ) -> List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]]:
str_device_driver_key = key_to_str([db_device_pk, orm_driver.name]) #
db_device_driver = DriverModel(database, str_device_driver_key) # created = False
db_device_driver.device_fk = db_device #
db_device_driver.driver = orm_driver # db_config = session.query(ConfigModel).filter_by(**{ConfigModel.main_pk_name(): db_parent_pk}).one_or_none()
db_device_driver.save() # if not db_config:
# db_config = ConfigModel()
# setattr(db_config, ConfigModel.main_pk_name(), db_parent_pk)
# session.add(db_config)
# session.commit()
# created = True
#
# LOGGER.info('UPDATED-CONFIG: {}'.format(db_config.dump()))
#
# db_objects: List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]] = [(db_config, created)]
#
# for position, (action, resource_key, resource_value) in enumerate(raw_config_rules):
# if action == ORM_ConfigActionEnum.SET:
# result : Tuple[ConfigRuleModel, bool] = self.set_config_rule(
# db_config, position, resource_key, resource_value)
# db_config_rule, updated = result
# db_objects.append((db_config_rule, updated))
# elif action == ORM_ConfigActionEnum.DELETE:
# self.delete_config_rule(db_config, resource_key)
# else:
# msg = 'Unsupported action({:s}) for resource_key({:s})/resource_value({:s})'
# raise AttributeError(
# msg.format(str(ConfigActionEnum.Name(action)), str(resource_key), str(resource_value)))
#
# return db_objects
#
# def set_config_rule(self, db_config: ConfigModel, position: int, resource_key: str, resource_value: str,
# ): # -> Tuple[ConfigRuleModel, bool]:
#
# from src.context.service.database.Tools import fast_hasher
# str_rule_key_hash = fast_hasher(resource_key)
# str_config_rule_key = key_to_str([db_config.config_uuid, str_rule_key_hash], separator=':')
# pk = str(uuid.uuid5(uuid.UUID('9566448d-e950-425e-b2ae-7ead656c7e47'), str_config_rule_key))
# data = {'config_rule_uuid': pk, 'config_uuid': db_config.config_uuid, 'position': position,
# 'action': ORM_ConfigActionEnum.SET, 'key': resource_key, 'value': resource_value}
# to_add = ConfigRuleModel(**data)
#
# result, updated = self.database.create_or_update(to_add)
# return result, updated
#
# def delete_config_rule(
# self, db_config: ConfigModel, resource_key: str
# ) -> None:
#
# from src.context.service.database.Tools import fast_hasher
# str_rule_key_hash = fast_hasher(resource_key)
# str_config_rule_key = key_to_str([db_config.pk, str_rule_key_hash], separator=':')
#
# db_config_rule = self.database.get_object(ConfigRuleModel, str_config_rule_key, raise_if_not_found=False)
#
# if db_config_rule is None:
# return
# db_config_rule.delete()
#
# def delete_all_config_rules(self, db_config: ConfigModel) -> None:
#
# db_config_rule_pks = db_config.references(ConfigRuleModel)
# for pk, _ in db_config_rule_pks: ConfigRuleModel(self.database, pk).delete()
#
# """
# for position, (action, resource_key, resource_value) in enumerate(raw_config_rules):
# if action == ORM_ConfigActionEnum.SET:
# result: Tuple[ConfigRuleModel, bool] = set_config_rule(
# database, db_config, position, resource_key, resource_value)
# db_config_rule, updated = result
# db_objects.append((db_config_rule, updated))
# elif action == ORM_ConfigActionEnum.DELETE:
# delete_config_rule(database, db_config, resource_key)
# else:
# msg = 'Unsupported action({:s}) for resource_key({:s})/resource_value({:s})'
# raise AttributeError(
# msg.format(str(ConfigActionEnum.Name(action)), str(resource_key), str(resource_value)))
#
# return db_objects
# """
...@@ -12,93 +12,63 @@ ...@@ -12,93 +12,63 @@
# 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 logging import enum, functools
from typing import Dict, List, Optional, Tuple from typing import Dict
from common.orm.Database import Database from sqlalchemy import Column, String, Enum, ForeignKeyConstraint
from common.orm.HighLevel import get_object from sqlalchemy.dialects.postgresql import ARRAY, UUID
from common.orm.backend.Tools import key_to_str
from common.proto.context_pb2 import EndPointId
from .KpiSampleType import ORM_KpiSampleTypeEnum, grpc_to_enum__kpi_sample_type
from sqlalchemy import Column, ForeignKey, String, Enum, ForeignKeyConstraint
from sqlalchemy.dialects.postgresql import UUID
from context.service.database._Base import Base
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
LOGGER = logging.getLogger(__name__) from common.proto.kpi_sample_types_pb2 import KpiSampleType
from ._Base import _Base
from .Tools import grpc_to_enum
class EndPointModel(Base): class ORM_KpiSampleTypeEnum(enum.Enum):
__tablename__ = 'EndPoint' UNKNOWN = KpiSampleType.KPISAMPLETYPE_UNKNOWN
topology_uuid = Column(UUID(as_uuid=False), ForeignKey("Topology.topology_uuid"), primary_key=True) PACKETS_TRANSMITTED = KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED
device_uuid = Column(UUID(as_uuid=False), ForeignKey("Device.device_uuid", ondelete='CASCADE'), primary_key=True) PACKETS_RECEIVED = KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED
endpoint_uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True) BYTES_TRANSMITTED = KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED
endpoint_type = Column(String) BYTES_RECEIVED = KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED
grpc_to_enum__kpi_sample_type = functools.partial(
grpc_to_enum, KpiSampleType, ORM_KpiSampleTypeEnum)
# Relationships class EndPointModel(_Base):
kpi_sample_types = relationship("KpiSampleTypeModel", passive_deletes=True, back_populates="EndPoint") __tablename__ = 'endpoint'
device = relationship("DeviceModel", back_populates="endpoints") context_uuid = Column(UUID(as_uuid=False), primary_key=True)
topology_uuid = Column(UUID(as_uuid=False), primary_key=True)
device_uuid = Column(UUID(as_uuid=False), primary_key=True)
endpoint_uuid = Column(UUID(as_uuid=False), primary_key=True)
endpoint_type = Column(String)
kpi_sample_types = Column(ARRAY(Enum(ORM_KpiSampleTypeEnum), dimensions=1))
@staticmethod __table_args__ = (
def main_pk_name(): ForeignKeyConstraint(
return 'endpoint_uuid' ['context_uuid', 'topology_uuid'],
['topology.context_uuid', 'topology.topology_uuid'],
ondelete='CASCADE'),
ForeignKeyConstraint(
['device_uuid'],
['device.device_uuid'],
ondelete='CASCADE'),
)
def delete(self) -> None: topology = relationship('TopologyModel', back_populates='endpoints')
for db_kpi_sample_type_pk,_ in self.references(KpiSampleTypeModel): device = relationship('DeviceModel', back_populates='endpoints')
KpiSampleTypeModel(self.database, db_kpi_sample_type_pk).delete()
super().delete()
def dump_id(self) -> Dict: def dump_id(self) -> Dict:
result = { result = {
'topology_id': self.topology.dump_id(),
'device_id': self.device.dump_id(), 'device_id': self.device.dump_id(),
'endpoint_uuid': {'uuid': self.endpoint_uuid}, 'endpoint_uuid': {'uuid': self.endpoint_uuid},
} }
return result return result
def dump_kpi_sample_types(self) -> List[int]:
# db_kpi_sample_type_pks = self.references(KpiSampleTypeModel)
# return [KpiSampleTypeModel(self.database, pk).dump() for pk,_ in db_kpi_sample_type_pks]
response = []
for a in self.kpi_sample_types:
response.append(a.dump())
return response
def dump( # pylint: disable=arguments-differ
self, include_kpi_sample_types=True
) -> Dict:
result = {
'endpoint_id': self.dump_id(),
'endpoint_type': self.endpoint_type,
}
if include_kpi_sample_types: result['kpi_sample_types'] = self.dump_kpi_sample_types()
return result
class KpiSampleTypeModel(Base): # pylint: disable=abstract-method
__tablename__ = 'KpiSampleType'
kpi_uuid = Column(UUID(as_uuid=False), primary_key=True)
endpoint_uuid = Column(UUID(as_uuid=False), ForeignKey("EndPoint.endpoint_uuid", ondelete='CASCADE'))
kpi_sample_type = Column(Enum(ORM_KpiSampleTypeEnum, create_constraint=False,
native_enum=False))
# __table_args__ = (ForeignKeyConstraint([endpoint_uuid], [EndPointModel.endpoint_uuid]), {})
# Relationships
EndPoint = relationship("EndPointModel", passive_deletes=True, back_populates="kpi_sample_types")
def dump(self) -> Dict: def dump(self) -> Dict:
return self.kpi_sample_type.value return {
'endpoint_id' : self.dump_id(),
def main_pk_name(self): 'endpoint_type' : self.endpoint_type,
return 'kpi_uuid' 'kpi_sample_types': [kst.value for kst in self.kpi_sample_types],
}
"""
def set_kpi_sample_types(database : Database, db_endpoint : EndPointModel, grpc_endpoint_kpi_sample_types):
db_endpoint_pk = db_endpoint.pk
for kpi_sample_type in grpc_endpoint_kpi_sample_types:
orm_kpi_sample_type = grpc_to_enum__kpi_sample_type(kpi_sample_type)
str_endpoint_kpi_sample_type_key = key_to_str([db_endpoint_pk, orm_kpi_sample_type.name])
db_endpoint_kpi_sample_type = KpiSampleTypeModel(database, str_endpoint_kpi_sample_type_key)
db_endpoint_kpi_sample_type.endpoint_fk = db_endpoint
db_endpoint_kpi_sample_type.kpi_sample_type = orm_kpi_sample_type
db_endpoint_kpi_sample_type.save()
"""
# def get_endpoint( # def get_endpoint(
# database : Database, grpc_endpoint_id : EndPointId, # database : Database, grpc_endpoint_id : EndPointId,
# validate_topology_exists : bool = True, validate_device_in_topology : bool = True # validate_topology_exists : bool = True, validate_device_in_topology : bool = True
......
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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 functools
import enum
from common.proto.kpi_sample_types_pb2 import KpiSampleType
from .Tools import grpc_to_enum
class ORM_KpiSampleTypeEnum(enum.Enum):
UNKNOWN = KpiSampleType.KPISAMPLETYPE_UNKNOWN
PACKETS_TRANSMITTED = KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED
PACKETS_RECEIVED = KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED
BYTES_TRANSMITTED = KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED
BYTES_RECEIVED = KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED
grpc_to_enum__kpi_sample_type = functools.partial(
grpc_to_enum, KpiSampleType, ORM_KpiSampleTypeEnum)
...@@ -13,39 +13,39 @@ ...@@ -13,39 +13,39 @@
# limitations under the License. # limitations under the License.
import logging import logging
from sqlalchemy import Column, ForeignKey from sqlalchemy import Column, ForeignKey, ForeignKeyConstraint
from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.dialects.postgresql import UUID
from context.service.database._Base import Base from sqlalchemy.orm import relationship
from context.service.database._Base import _Base
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
#
# class ConnectionSubServiceModel(Model): # pylint: disable=abstract-method # class ConnectionSubServiceModel(Model):
# pk = PrimaryKeyField() # pk = PrimaryKeyField()
# connection_fk = ForeignKeyField(ConnectionModel) # connection_fk = ForeignKeyField(ConnectionModel)
# sub_service_fk = ForeignKeyField(ServiceModel) # sub_service_fk = ForeignKeyField(ServiceModel)
# #
class LinkEndPointModel(Base): # pylint: disable=abstract-method #class LinkEndPointModel(Base):
__tablename__ = 'LinkEndPoint' # __tablename__ = 'LinkEndPoint'
# uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True) # # uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True)
link_uuid = Column(UUID(as_uuid=False), ForeignKey("Link.link_uuid")) # link_uuid = Column(UUID(as_uuid=False), ForeignKey("Link.link_uuid"))
endpoint_uuid = Column(UUID(as_uuid=False), ForeignKey("EndPoint.endpoint_uuid"), primary_key=True) # endpoint_uuid = Column(UUID(as_uuid=False), ForeignKey("EndPoint.endpoint_uuid"), primary_key=True)
@staticmethod
def main_pk_name():
return 'endpoint_uuid'
# #
# class ServiceEndPointModel(Model): # pylint: disable=abstract-method # @staticmethod
# def main_pk_name():
# return 'endpoint_uuid'
#
# class ServiceEndPointModel(Model):
# pk = PrimaryKeyField() # pk = PrimaryKeyField()
# service_fk = ForeignKeyField(ServiceModel) # service_fk = ForeignKeyField(ServiceModel)
# endpoint_fk = ForeignKeyField(EndPointModel) # endpoint_fk = ForeignKeyField(EndPointModel)
# #
# class SliceEndPointModel(Model): # pylint: disable=abstract-method # class SliceEndPointModel(Model):
# pk = PrimaryKeyField() # pk = PrimaryKeyField()
# slice_fk = ForeignKeyField(SliceModel) # slice_fk = ForeignKeyField(SliceModel)
# endpoint_fk = ForeignKeyField(EndPointModel) # endpoint_fk = ForeignKeyField(EndPointModel)
# #
# class SliceServiceModel(Model): # pylint: disable=abstract-method # class SliceServiceModel(Model):
# pk = PrimaryKeyField() # pk = PrimaryKeyField()
# slice_fk = ForeignKeyField(SliceModel) # slice_fk = ForeignKeyField(SliceModel)
# service_fk = ForeignKeyField(ServiceMo# pylint: disable=abstract-method # service_fk = ForeignKeyField(ServiceMo# pylint: disable=abstract-method
...@@ -55,26 +55,32 @@ class LinkEndPointModel(Base): # pylint: disable=abstract-method ...@@ -55,26 +55,32 @@ class LinkEndPointModel(Base): # pylint: disable=abstract-method
# endpoint_uuid = Column(UUID(as_uuid=False), ForeignKey("EndPoint.endpoint_uuid")) # endpoint_uuid = Column(UUID(as_uuid=False), ForeignKey("EndPoint.endpoint_uuid"))
#del) #del)
# #
# class SliceSubSliceModel(Model): # pylint: disable=abstract-method # class SliceSubSliceModel(Model):
# pk = PrimaryKeyField() # pk = PrimaryKeyField()
# slice_fk = ForeignKeyField(SliceModel) # slice_fk = ForeignKeyField(SliceModel)
# sub_slice_fk = ForeignKeyField(SliceModel) # sub_slice_fk = ForeignKeyField(SliceModel)
class TopologyDeviceModel(Base): # pylint: disable=abstract-method class TopologyDeviceModel(_Base):
__tablename__ = 'TopologyDevice' __tablename__ = 'topology_device'
# uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True) context_uuid = Column(UUID(as_uuid=False), primary_key=True)
topology_uuid = Column(UUID(as_uuid=False), ForeignKey("Topology.topology_uuid")) topology_uuid = Column(UUID(as_uuid=False), primary_key=True)
device_uuid = Column(UUID(as_uuid=False), ForeignKey("Device.device_uuid"), primary_key=True) device_uuid = Column(UUID(as_uuid=False), primary_key=True)
@staticmethod topologies = relationship('TopologyModel', back_populates='topology_device')
def main_pk_name(): devices = relationship('DeviceModel', back_populates='topology_device')
return 'device_uuid'
# __table_args__ = (
class TopologyLinkModel(Base): # pylint: disable=abstract-method ForeignKeyConstraint(
__tablename__ = 'TopologyLink' ['context_uuid', 'topology_uuid'],
topology_uuid = Column(UUID(as_uuid=False), ForeignKey("Topology.topology_uuid")) ['topology.context_uuid', 'topology.topology_uuid'],
link_uuid = Column(UUID(as_uuid=False), ForeignKey("Link.link_uuid"), primary_key=True) ondelete='CASCADE'),
ForeignKeyConstraint(
['device_uuid'],
['device.device_uuid'],
ondelete='CASCADE'),
)
@staticmethod #class TopologyLinkModel(Base):
def main_pk_name(): # __tablename__ = 'TopologyLink'
return 'link_uuid' # topology_uuid = Column(UUID(as_uuid=False), ForeignKey("Topology.topology_uuid"))
\ No newline at end of file # link_uuid = Column(UUID(as_uuid=False), ForeignKey("Link.link_uuid"), primary_key=True)
...@@ -12,40 +12,35 @@ ...@@ -12,40 +12,35 @@
# 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 logging #, operator from typing import Dict
from typing import Dict #, List from sqlalchemy import Column, Float, ForeignKey, String
from sqlalchemy import Column, ForeignKey
from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from ._Base import _Base from ._Base import _Base
LOGGER = logging.getLogger(__name__)
class TopologyModel(_Base): class TopologyModel(_Base):
__tablename__ = 'Topology' __tablename__ = 'topology'
context_uuid = Column(UUID(as_uuid=False), ForeignKey('context.context_uuid'), primary_key=True) context_uuid = Column(UUID(as_uuid=False), ForeignKey('context.context_uuid'), primary_key=True)
topology_uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True) topology_uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True)
topology_name = Column(String(), nullable=False)
created_at = Column(Float)
# Relationships # Relationships
context = relationship('ContextModel', back_populates='topology') context = relationship('ContextModel', back_populates='topology')
topology_device = relationship('TopologyDeviceModel', back_populates='topologies')
#topology_link = relationship('TopologyLinkModel', back_populates='topology')
endpoints = relationship('EndPointModel', back_populates='topology')
def dump_id(self) -> Dict: def dump_id(self) -> Dict:
context_id = self.context.dump_id()
return { return {
'context_id': context_id, 'context_id': self.context.dump_id(),
'topology_uuid': {'uuid': self.topology_uuid}, 'topology_uuid': {'uuid': self.topology_uuid},
} }
#@staticmethod
#def main_pk_name() -> str:
# return 'topology_uuid'
def dump(self) -> Dict: def dump(self) -> Dict:
# pylint: disable=arguments-differ return {
result = {'topology_id': self.dump_id()} 'topology_id': self.dump_id(),
# params: , devices=None, links=None 'name' : self.topology_name,
#if devices: 'device_ids' : [{'device_uuid': {'uuid': td.device_uuid}} for td in self.topology_device],
# result['device_ids'] = [device.dump_id() for device in devices] #'link_ids' : [{'link_uuid' : {'uuid': td.link_uuid }} for td in self.topology_link ],
#if links: }
# result['link_ids'] = [link.dump_id() for link in links]
return result
...@@ -11,7 +11,3 @@ ...@@ -11,7 +11,3 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# 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.
from ._Base import _Base, rebuild_database
from .ContextModel import ContextModel
from .TopologyModel import TopologyModel
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment