Commit f9929ea6 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Context service and Database API rework

- Complete rework of Database API
- Integration of Database API into Context
- Improvement of API

This commit is not a final implementation, just an intermediate backup.
parent d6c52c05
Loading
Loading
Loading
Loading
+202 −45
Original line number Diff line number Diff line
syntax = "proto3";
package context;


service ContextService {
  rpc GetTopology (Empty) returns (Topology) {}

  rpc AddLink(Link) returns (LinkId) {}
  rpc GetContextIds (Empty     ) returns (ContextIdList ) {}
  rpc GetContexts   (Empty     ) returns (ContextList   ) {}
  rpc GetContext    (ContextId ) returns (Context       ) {}
  rpc SetContext    (Context   ) returns (ContextId     ) {}
  rpc DeleteContext (ContextId ) returns (Empty         ) {}

  rpc GetTopologyIds(ContextId ) returns (TopologyIdList) {}
  rpc GetTopologies (ContextId ) returns (TopologyList  ) {}
  rpc GetTopology   (TopologyId) returns (Topology      ) {}
  rpc SetTopology   (Topology  ) returns (TopologyId    ) {}
  rpc DeleteTopology(TopologyId) returns (Empty         ) {}

  rpc GetDeviceIds  (Empty     ) returns (DeviceIdList  ) {}
  rpc GetDevices    (Empty     ) returns (DeviceList    ) {}
  rpc GetDevice     (DeviceId  ) returns (Device        ) {}
  rpc SetDevice     (Device    ) returns (DeviceId      ) {}
  rpc RemoveDevice  (DeviceId  ) returns (Empty         ) {}

  rpc GetLinkIds    (Empty     ) returns (LinkIdList    ) {}
  rpc GetLinks      (Empty     ) returns (LinkList      ) {}
  rpc GetLink       (LinkId    ) returns (Link          ) {}
  rpc SetLink       (Link      ) returns (LinkId        ) {}
  rpc DeleteLink    (LinkId    ) returns (Empty         ) {}

  rpc GetServiceIds (ContextId ) returns (ServiceIdList ) {}
  rpc GetServices   (ContextId ) returns (ServiceList   ) {}
  rpc GetService    (ServiceId ) returns (Service       ) {}
  rpc SetService    (Service   ) returns (ServiceId     ) {}
  rpc DeleteService (ServiceId ) returns (Empty         ) {}
}

// ----- Generic -------------------------------------------------------------------------------------------------------
message Empty {}

message Uuid {
  string uuid = 1;
}

message Empty {

// ----- Context -------------------------------------------------------------------------------------------------------
message ContextId {
  Uuid context_uuid = 1;
}

message Context {
  ContextId contextId= 1;
  Topology topo = 2;
  TeraFlowController ctl = 3;
  ContextId context_id = 1;
  repeated Topology topology = 2;
  TeraFlowController controller = 3;
}

message ContextId {
  Uuid contextUuid = 1;
message ContextIdList {
  repeated ContextId context_ids = 1;
}

message ContextList {
  repeated Context contexts = 1;
}


// ----- Topology ------------------------------------------------------------------------------------------------------
message TopologyId {
  ContextId context_id = 1;
  Uuid topology_uuid = 2;
}

message Topology {
  TopologyId topoId = 2;
  repeated Device device = 3;
  repeated Link link = 4; 
  TopologyId topology_id = 1;
  repeated Device devices = 2;
  repeated Link links = 3;
}

message Link {
  LinkId link_id = 1;
  repeated EndPointId endpointList = 2;
message TopologyIdList {
  repeated TopologyId topology_ids = 1;
}

message TopologyId {
  ContextId contextId = 1;
  Uuid topoId = 2;
message TopologyList {
  repeated Topology topologies = 1;
}

message Constraint {
  string constraint_type = 1;
  string constraint_value = 2;

// ----- Device --------------------------------------------------------------------------------------------------------
message DeviceId {
  Uuid device_uuid = 1;
}

message Device {
  DeviceId device_id = 1;
  string device_type = 2;
  DeviceConfig device_config = 3;
  DeviceOperationalStatus devOperationalStatus = 4;
  repeated EndPoint endpointList = 5;  
  DeviceOperationalStatus devive_operational_status = 4;
  repeated DeviceDriver device_drivers = 5;
  repeated EndPoint endpoints = 6;
}

message DeviceConfig {
  string device_config = 1;
  repeated ConfigRule config_rules = 1;
}

enum DeviceDriver {
  DRIVER_UNDEFINED = 0; // also used for emulated
  DRIVER_OPENCONFIG = 1;
  DRIVER_TRANSPORT_API = 2;
  DRIVER_P4 = 3;
  DRIVER_IETF_NETWORK_TOPOLOGY = 4;
  DRIVER_ONF_TR_352 = 5;
}

enum DeviceOperationalStatus {
  KEEP_STATUS = 0; // Do not change operational status of device (used in configure)
  DISABLED = -1;
  ENABLED = 1;
}

message DeviceIdList {
  repeated DeviceId device_ids = 1;
}

message DeviceList {
  repeated Device devices = 1;
}


// ----- Link ----------------------------------------------------------------------------------------------------------
message LinkId {
  Uuid link_uuid = 1;
}

message Link {
  LinkId link_id = 1;
  repeated EndPointId endpoints = 2;
}

message LinkIdList {
  repeated LinkId link_ids = 1;
}

message LinkList {
  repeated Link links = 1;
}


// ----- Service -------------------------------------------------------------------------------------------------------
message ServiceId {
  ContextId context_id = 1;
  Uuid service_uuid = 2;
}

message Service {
  ServiceId service_id = 1;
  ServiceType service_type = 2;
  repeated EndPointId endpoints = 3;
  repeated Constraint constraints = 4;
  ServiceState service_state = 5;
  ServiceConfig service_config = 6;
}

enum ServiceType {
  SERVICETYPE_UNKNOWN = 0;
  SERVICETYPE_L3NM = 1;
  SERVICETYPE_L2NM = 2;
  SERVICETYPE_TAPI_CONNECTIVITY_SERVICE = 3;
}

enum ServiceStateEnum {
  SERVICESTATUS_PLANNED = 0;
  SERVICESTATUS_ACTIVE =  1;
  SERVICESTATUS_PENDING_REMOVAL = 2;
}

message ServiceState {
  ServiceStateEnum service_state = 1;
}

message ServiceConfig {
  repeated ConfigRule config_rules = 1;
}

message ServiceIdList {
  repeated ServiceId service_ids = 1;
}

message ServiceList {
  repeated Service services = 1;
}


// ----- Endpoint ------------------------------------------------------------------------------------------------------
message EndPointId {
  TopologyId topology_id = 1;
  DeviceId device_id = 2;
  Uuid endpoint_uuid = 3;
}

message EndPoint {
  EndPointId port_id = 1;
  EndPointId endpoint_id = 1;
  string port_type = 2;
}

message EndPointId {
  TopologyId topoId = 1;
  DeviceId dev_id = 2;
  Uuid port_id = 3;

// ----- Configuration -------------------------------------------------------------------------------------------------
enum ConfigAction {
  CONFIGACTION_UNDEFINED = 0;
  CONFIGACTION_SET = 1;
  CONFIGACTION_DELETE = 2;
}

message DeviceId {
  Uuid device_id = 1;
message ConfigRule {
  ConfigAction action = 1;
  string resource_key = 2;
  string resource_value = 3;
}

message LinkId {
  Uuid link_id = 1;

// ----- Constraint ----------------------------------------------------------------------------------------------------
message Constraint {
  string constraint_type = 1;
  string constraint_value = 2;
}

message Uuid {
  string uuid = 1;

// ----- Connection ----------------------------------------------------------------------------------------------------
message ConnectionId {
  Uuid connection_uuid = 1;
}

enum DeviceOperationalStatus {
  KEEP_STATUS = 0; // Do not change operational status of device (used in configure)
  DISABLED    = -1;
  ENABLED     = 1;
message Connection {
  ConnectionId connection_id = 1;
  ServiceId related_service_id = 2;
  repeated EndPointId path = 3;
}

message ConnectionIdList {
  repeated ConnectionId connection_ids = 1;
}

message ConnectionList {
  repeated Connection connections = 1;
}


// ----- Miscellaneous -------------------------------------------------------------------------------------------------
message TeraFlowController {
  ContextId ctl_id = 1;
  string ipaddress = 2;
  ContextId context_id = 1;
  string ip_address = 2;
  uint32 port = 3;
}

message AuthenticationResult {
  ContextId ctl_id = 1;
  ContextId context_id = 1;
  bool authenticated = 2;
}

+6 −66
Original line number Diff line number Diff line
//Example of topology
syntax = "proto3";
package service;

import "context.proto";

service ServiceService {
  rpc GetServiceList (context.Empty) returns (ServiceList) {}
  rpc CreateService (Service) returns (ServiceId) {}
  rpc UpdateService (Service) returns (ServiceId) {}
  rpc DeleteService (ServiceId) returns (context.Empty) {}
  rpc GetServiceById (ServiceId) returns (Service) {}
  rpc GetConnectionList (context.Empty) returns (ConnectionList) {}
  
}

message ServiceList {
  repeated Service cs = 1;
}

message Service {
  ServiceId cs_id = 1;
  ServiceType serviceType = 2;
  repeated context.EndPointId endpointList = 3;
  repeated context.Constraint constraint = 4;
  ServiceState serviceState = 5;
  ServiceConfig serviceConfig = 6;
}

enum ServiceType {
  UNKNOWN = 0;
  L3NM = 1;
  L2NM = 2;
  TAPI_CONNECTIVITY_SERVICE = 3;
}

message ServiceConfig {
  string serviceConfig = 1;
}

message ServiceId {
  context.ContextId contextId = 1;
  context.Uuid cs_id = 2;
}

message ServiceIdList {
  repeated ServiceId serviceIdList = 1;
}

message ServiceState {
  ServiceStateEnum serviceState = 1;
}

enum ServiceStateEnum {
  PLANNED = 0;
  ACTIVE =  1;
  PENDING_REMOVAL = 2;
}

message ConnectionList {
  repeated Connection connectionList = 1;
}

message Connection {
  ConnectionId con_id = 1;
  ServiceId relatedServiceId = 2;
  repeated context.EndPointId path = 3;
  rpc GetServiceList   (context.Empty    ) returns (context.ServiceList   ) {}
  rpc CreateService    (context.Service  ) returns (context.ServiceId     ) {}
  rpc UpdateService    (context.Service  ) returns (context.ServiceId     ) {}
  rpc DeleteService    (context.ServiceId) returns (context.Empty         ) {}
  rpc GetServiceById   (context.ServiceId) returns (context.Service       ) {}
  rpc GetConnectionList(context.Empty    ) returns (context.ConnectionList) {}
}

message ConnectionId {
  context.Uuid con_id = 1;
}
+2 −0
Original line number Diff line number Diff line
DEFAULT_CONTEXT_UUID = 'admin'
DEFAULT_TOPOLOGY_UUID = 'admin'

src/common/database/Factory.py

deleted100644 → 0
+0 −39
Original line number Diff line number Diff line
import logging
from enum import Enum
from common.Settings import get_setting
from common.database.api.Database import Database
from common.database.engines.inmemory.InMemoryDatabaseEngine import InMemoryDatabaseEngine
from common.database.engines.redis.RedisDatabaseEngine import RedisDatabaseEngine

LOGGER = logging.getLogger(__name__)

class DatabaseEngineEnum(Enum):
    INMEMORY = 'inmemory'
    REDIS = 'redis'
    #MONGO = 'mongo'
    #RETHINK = 'rethink'
    #ETCD = 'etcd'

ENGINES = {
    DatabaseEngineEnum.INMEMORY.value: InMemoryDatabaseEngine,
    DatabaseEngineEnum.REDIS.value: RedisDatabaseEngine,
    #DatabaseEngineEnum.MONGO.value: MongoDatabase,
    #DatabaseEngineEnum.RETHINK.value: RethinkDatabase,
    #DatabaseEngineEnum.ETCD.value: EtcdDatabase,
}

DEFAULT_DB_ENGINE = DatabaseEngineEnum.INMEMORY

def get_database(engine=None, **settings) -> Database:
    # return an instance of Database initialized with selected engine.
    # Engine is selected using following criteria (first that is not None is selected):
    # 1. user selected by parameter (engine=...)
    # 2. environment variable DB_ENGINE
    # 3. default engine: INMEMORY
    if engine is None: engine = get_setting('DB_ENGINE', default=DEFAULT_DB_ENGINE)
    if engine is None: raise Exception('Database Engine not specified')
    if isinstance(engine, DatabaseEngineEnum): engine = engine.value
    engine_class = ENGINES.get(engine)
    if engine_class is None: raise Exception('Unsupported DatabaseEngine({})'.format(engine))
    LOGGER.info('Selected Database Engine: {}'.format(engine))
    return Database(engine_class(**settings))
+0 −53
Original line number Diff line number Diff line
import logging
from typing import List
from common.database.api.Exceptions import WrongDatabaseEngine, MutexException
from common.database.api.context.Context import Context
from common.database.api.context.Keys import KEY_CONTEXTS
from common.database.api.entity._Entity import _Entity
from common.database.api.entity.EntityCollection import EntityCollection
from common.database.engines._DatabaseEngine import _DatabaseEngine

LOGGER = logging.getLogger(__name__)

class Database(_Entity):
    def __init__(self, database_engine : _DatabaseEngine):
        if not isinstance(database_engine, _DatabaseEngine):
            raise WrongDatabaseEngine('database_engine must inherit from _DatabaseEngine')
        self._database_engine = database_engine
        super().__init__(self, 'root', 'database', {}, {})
        self._acquired = False
        self._owner_key = None
        self._contexts = EntityCollection(self, KEY_CONTEXTS)

    @property
    def parent(self) -> 'Database': return self

    @property
    def database_engine(self) -> _DatabaseEngine: return self._database_engine

    def __enter__(self) -> '_DatabaseEngine':
        self._acquired, self._owner_key = self._database_engine.lock()
        if not self._acquired: raise MutexException('Unable to acquire database lock')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self._database_engine.unlock(self._owner_key)

    def clear_all(self, keep_keys=set()):
        LOGGER.info('Cleaning up...')
        keys = self._database_engine.keys()
        LOGGER.info('  keys before = {}'.format(str(keys)))
        for key in keys:
            if(key in keep_keys): continue
            self._database_engine.delete(key)
        LOGGER.info('  keys after  = {}'.format(str(self._database_engine.keys())))

    def dump(self) -> List[str]:
        entries = self._database_engine.dump()
        entries.sort()
        return ['[{:>4s}] {:100s} :: {}'.format(k_type, k_name, k_value) for k_name,k_type,k_value in entries]

    @property
    def contexts(self) -> EntityCollection: return self._contexts

    def context(self, context_uuid : str) -> Context: return Context(context_uuid, self)
Loading