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

Several changes:

Common:
- added ORM helper function get_related_instances
- minor modifications in ORM framework

Proto:
- field/message/enum renamings in context.proto to normalize notation

Context:
- Expanded service/database/Models.py into separate models to facilitate coding
- Completed implementation of Get/Set/List/Remove methods for Context, Topology, Device, Link, and EndPoint; also completed for relation models between topology and device/link, and ConfigModels
- Implemented test units for Get/Set/List/Remove methods for Context, Topology, Device, Link, and EndPoint
- Implemented skeleton for Get/Set/List/Remove methods for Service.
- Added Tools.py with helper methods to fimplify handling of enums between ORM and gRPC messages.
parent 41122c06
Loading
Loading
Loading
Loading
+18 −17
Original line number Diff line number Diff line
@@ -118,9 +118,9 @@ message Device {
  DeviceId device_id = 1;
  string device_type = 2;
  DeviceConfig device_config = 3;
  DeviceOperationalStatus devive_operational_status = 4;
  DeviceOperationalStatusEnum device_operational_status = 4;
  repeated DeviceDriverEnum device_drivers = 5;
  repeated EndPoint endpoints = 6;
  repeated EndPoint device_endpoints = 6;
}

message DeviceConfig {
@@ -136,10 +136,10 @@ enum DeviceDriverEnum {
  DEVICEDRIVER_ONF_TR_352 = 5;
}

enum DeviceOperationalStatus {
  UNDEFINED = 0;
  DISABLED = 1;
  ENABLED = 2;
enum DeviceOperationalStatusEnum {
  DEVICEOPERATIONALSTATUS_UNDEFINED = 0;
  DEVICEOPERATIONALSTATUS_DISABLED = 1;
  DEVICEOPERATIONALSTATUS_ENABLED = 2;
}

message DeviceIdList {
@@ -163,7 +163,7 @@ message LinkId {

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

message LinkIdList {
@@ -189,9 +189,9 @@ message ServiceId {
message Service {
  ServiceId service_id = 1;
  ServiceTypeEnum service_type = 2;
  repeated EndPointId endpoint_ids = 3;
  repeated Constraint constraints = 4;
  ServiceState service_state = 5;
  repeated EndPointId service_endpoint_ids = 3;
  repeated Constraint service_constraints = 4;
  ServiceStatus service_status = 5;
  ServiceConfig service_config = 6;
}

@@ -202,14 +202,15 @@ enum ServiceTypeEnum {
  SERVICETYPE_TAPI_CONNECTIVITY_SERVICE = 3;
}

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

message ServiceState {
  ServiceStateEnum service_state = 1;
message ServiceStatus {
  ServiceStatusEnum service_status = 1;
}

message ServiceConfig {
@@ -239,7 +240,7 @@ message EndPointId {

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


+2 −2
Original line number Diff line number Diff line
from typing import List, Union

def key_to_str(key : Union[str, List[str]]) -> str:
def key_to_str(key : Union[str, List[str]], separator : str = '/') -> str:
    if isinstance(key, str): return key
    return '/'.join(map(str, key))
    return separator.join(map(str, key))
+16 −1
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@ from typing import Any, Dict, List, Mapping, Optional, Set, Tuple, Union
from common.orm.Database import Database
from common.orm.backend.Tools import key_to_str
from common.orm.fields.ForeignKeyField import ForeignKeyField
from common.type_checkers.Checkers import chk_issubclass
from ..Exceptions import ConstraintException, MutexException
from ..fields.Field import Field
from ..fields.PrimaryKeyField import PrimaryKeyField
@@ -291,3 +290,19 @@ class Model(metaclass=MetaModel):
            for name in self._field_names_list # pylint: disable=no-member
        )
        return '{:s}({:s})'.format(self._class_name, arguments)

def get_related_instances(
    source_instance : Model, relation_model_class : MetaModel, relation_field_name : str) -> Set[Model]:
    navigation_fk_field : ForeignKeyField = getattr(relation_model_class, relation_field_name, None)
    if navigation_fk_field is None or not isinstance(navigation_fk_field, ForeignKeyField):
        msg = 'relation_field_name({:s}) must be a ForeignKeyField in relation_model_class({:s})'
        raise AttributeError(msg.format(relation_field_name, relation_model_class.__name__))
    target_model_class = navigation_fk_field.foreign_model
    database = source_instance.database
    db_target_instances = set()
    for db_relation_pk,_ in source_instance.references(relation_model_class):
        db_relation = relation_model_class(database, db_relation_pk)
        target_fk_field = getattr(db_relation, relation_field_name, None)
        if target_fk_field is None: continue
        db_target_instances.add(target_model_class(database, target_fk_field))
    return db_target_instances
+121 −115

File changed.

Preview size limit exceeded, changes collapsed.

+56 −0
Original line number Diff line number Diff line
import functools, hashlib, logging, operator
from enum import Enum
from typing import Dict, List
from common.orm.fields.EnumeratedField import EnumeratedField
from common.orm.fields.ForeignKeyField import ForeignKeyField
from common.orm.fields.IntegerField import IntegerField
from common.orm.fields.PrimaryKeyField import PrimaryKeyField
from common.orm.fields.StringField import StringField
from common.orm.model.Model import Model
from context.proto.context_pb2 import ConfigActionEnum
from context.service.database.Tools import grpc_to_enum

LOGGER = logging.getLogger(__name__)

class ORM_ConfigActionEnum(Enum):
    UNDEFINED = ConfigActionEnum.CONFIGACTION_UNDEFINED
    SET       = ConfigActionEnum.CONFIGACTION_SET
    DELETE    = ConfigActionEnum.CONFIGACTION_DELETE

grpc_to_enum__config_action = functools.partial(
    grpc_to_enum, ConfigActionEnum, ORM_ConfigActionEnum)

def remove_dict_key(dictionary : Dict, key : str):
    dictionary.pop(key, None)
    return dictionary

def config_key_hasher(resource_key : str, digest_size : int = 8):
    hasher = hashlib.blake2b(digest_size=digest_size)
    hasher.update(resource_key.encode('UTF-8'))
    return hasher.hexdigest()

class ConfigModel(Model):
    pk = PrimaryKeyField()

    def dump(self) -> List[Dict]:
        db_config_rule_pks = self.references(ConfigRuleModel)
        config_rules = [ConfigRuleModel(self.database, pk).dump(include_position=True) for pk,_ in db_config_rule_pks]
        config_rules = sorted(config_rules, key=operator.itemgetter('position'))
        return [remove_dict_key(config_rule, 'position') for config_rule in config_rules]

class ConfigRuleModel(Model):
    pk = PrimaryKeyField()
    config_fk = ForeignKeyField(ConfigModel)
    position = IntegerField(min_value=0, required=True)
    action = EnumeratedField(ORM_ConfigActionEnum, required=True)
    key = StringField(required=True, allow_empty=False)
    value = StringField(required=True, allow_empty=False)

    def dump(self, include_position=True) -> Dict: # pylint: disable=arguments-differ
        result = {
            'action': self.action.value,
            'resource_key': self.key,
            'resource_value': self.value,
        }
        if include_position: result['position'] = self.position
        return result
Loading