Commit 56292820 authored by Pablo Armingol's avatar Pablo Armingol
Browse files

Merge branch 'feat/tid_ietf_slice' of https://labs.etsi.org/rep/tfs/controller...

Merge branch 'feat/tid_ietf_slice' of https://labs.etsi.org/rep/tfs/controller into feat/tid-add-support-for-ietf-slices
parents 657912ce 7def79c1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ spec:
        - containerPort: 9192
        env:
        - name: LOG_LEVEL
          value: "INFO"
          value: "DEBUG"
        - name: SLICE_GROUPING
          value: "DISABLE"
        envFrom:
+75 −21
Original line number Diff line number Diff line
@@ -106,8 +106,68 @@ class DescriptorLoader:
        self.__links       = self.__descriptors.get('links'      , [])
        self.__services    = self.__descriptors.get('services'   , [])
        self.__slices      = self.__descriptors.get('slices'     , [])
        self.__slices = self.__descriptors.get('ietf-network-slice-service:network-slice-services', {})
        self.__connections = self.__descriptors.get('connections', [])

        if self.__slices: 
            json_out = {"slices": [
                {
                    "slice_id": {
                        "context_id": {"context_uuid": {"uuid": "admin"}},
                        "slice_uuid": {}
                    },
                    "name": {},
                    "slice_config": {"config_rules": [
                        {"action": 1, "custom": {"resource_key": "/settings", "resource_value": {
                        "address_families": ["IPV4"], "bgp_as": 65000, "bgp_route_target": "65000:333", "mtu": 1512
                        }}}
                    ]},
                    "slice_constraints": [
                        {"sla_capacity": {"capacity_gbps": 20.0}},
                        {"sla_availability": {"availability": 20.0, "num_disjoint_paths": 1, "all_active": True}},
                        {"sla_isolation": {"isolation_level": [0]}}
                    ],
                    "slice_endpoint_ids": [
            
                    ],
                    "slice_status": {"slice_status": 1}
                }
            ]}

            for slice_service in self.__slices["slice-service"]:
                for slice in json_out["slices"]:
                    slice["slice_id"]["slice_uuid"] = { "uuid": slice_service["id"]}
                    slice["name"] = slice_service["description"]
                    sdp = slice_service["sdps"]["sdp"]
                    for elemento in sdp:
                        attcircuits = elemento["attachment-circuits"]["attachment-circuit"]
                        for attcircuit in attcircuits:
                            resource_key = "/device[{sdp_id}]/endpoint[{endpoint_id}]/settings".format(sdp_id = elemento["id"], endpoint_id = attcircuit["ac-tp-id"])

                            for tag in attcircuit['ac-tags']['ac-tag']:
                                if tag.get('tag-type') == 'ietf-nss:vlan-id':
                                    vlan_id = tag.get('value')
                                else:
                                    vlan_id = 0

                            slice["slice_config"]["config_rules"].append( {"action": 1, "custom": {"resource_key": resource_key, "resource_value": {
                                "router_id": elemento.get("node-id",[]), "sub_interface_index": 0, "vlan_id": vlan_id
                            }}})
                            slice["slice_endpoint_ids"].append({
                                "device_id": {"device_uuid": {"uuid": elemento["id"]}},
                                "endpoint_uuid": {"uuid": attcircuit["ac-tp-id"]},
                                "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, 
                                "topology_uuid": {"uuid": "admin"}}
                            })
                            slice["slice_constraints"].append({"endpoint_location": {
                                "endpoint_id": {"device_id": {"device_uuid": {"uuid": elemento["id"]}}, "endpoint_uuid": {"uuid": attcircuit["ac-tp-id"]}},
                                "location": {"region": "4"}
                        }})

            # Convertir a JSON de salida
            #json_output = json.dumps(json_out, indent=2)
            self.__slices      = json_out.get('slices'     , [])

        self.__contexts_add   = None
        self.__topologies_add = None
        self.__devices_add    = None
@@ -195,7 +255,7 @@ class DescriptorLoader:
        _slices = {}
        for slice_ in self.__slices:
            context_uuid = slice_['slice_id']['context_id']['context_uuid']['uuid']
            _slices.setdefault(context_uuid, []).append(slice_)
            _slices.setdefault(context_uuid, []).append(slice_) #no tenemos context_uuid en este formato, lo meto a mano?
        return _slices

    @property
@@ -236,8 +296,7 @@ class DescriptorLoader:
        self.__ctx_cli.connect()
        self._process_descr('context',    'add',    self.__ctx_cli.SetContext,    Context,    self.__contexts_add  )
        self._process_descr('topology',   'add',    self.__ctx_cli.SetTopology,   Topology,   self.__topologies_add)
        self._process_descr('controller', 'add',    self.__ctx_cli.SetDevice,     Device,     controllers          )
        self._process_descr('device',     'add',    self.__ctx_cli.SetDevice,     Device,     network_devices      )
        self._process_descr('device',     'add',    self.__ctx_cli.SetDevice,     Device,     self.__devices       )
        self._process_descr('link',       'add',    self.__ctx_cli.SetLink,       Link,       self.__links         )
        self._process_descr('service',    'add',    self.__ctx_cli.SetService,    Service,    self.__services      )
        self._process_descr('slice',      'add',    self.__ctx_cli.SetSlice,      Slice,      self.__slices        )
@@ -265,8 +324,6 @@ class DescriptorLoader:
        self.__services_add = get_descriptors_add_services(self.__services)
        self.__slices_add = get_descriptors_add_slices(self.__slices)

        controllers_add, network_devices_add = split_controllers_and_network_devices(self.__devices_add)

        self.__ctx_cli.connect()
        self.__dev_cli.connect()
        self.__svc_cli.connect()
@@ -274,8 +331,7 @@ class DescriptorLoader:

        self._process_descr('context',  'add',    self.__ctx_cli.SetContext,      Context,  self.__contexts_add  )
        self._process_descr('topology', 'add',    self.__ctx_cli.SetTopology,     Topology, self.__topologies_add)
        self._process_descr('controller', 'add',    self.__dev_cli.AddDevice,       Device,   controllers_add      )
        self._process_descr('device',     'add',    self.__dev_cli.AddDevice,       Device,   network_devices_add  )
        self._process_descr('device',   'add',    self.__dev_cli.AddDevice,       Device,   self.__devices_add   )
        self._process_descr('device',   'config', self.__dev_cli.ConfigureDevice, Device,   self.__devices_config)
        self._process_descr('link',     'add',    self.__ctx_cli.SetLink,         Link,     self.__links         )
        self._process_descr('service',  'add',    self.__svc_cli.CreateService,   Service,  self.__services_add  )
@@ -283,11 +339,9 @@ class DescriptorLoader:
        self._process_descr('slice',    'add',    self.__slc_cli.CreateSlice,     Slice,    self.__slices_add    )
        self._process_descr('slice',    'update', self.__slc_cli.UpdateSlice,     Slice,    self.__slices        )
        
        # By default the Context component automatically assigns devices and links to topologies based on their
        # endpoints, and assigns topologies, services, and slices to contexts based on their identifiers.

        # The following statement is useless; up to now, any use case requires assigning a topology, service, or
        # slice to a different context.
        # Update context and topology is useless:
        # - devices and links are assigned to topologies automatically by Context component
        # - topologies, services, and slices are assigned to contexts automatically by Context component
        #self._process_descr('context',  'update', self.__ctx_cli.SetContext,      Context,  self.__contexts      )

        # In some cases, it might be needed to assign devices and links to multiple topologies; the
+0 −2
Original line number Diff line number Diff line
@@ -59,8 +59,6 @@ def format_custom_config_rules(config_rules : List[Dict]) -> List[Dict]:
        if isinstance(custom_resource_value, (dict, list)):
            custom_resource_value = json.dumps(custom_resource_value, sort_keys=True, indent=0)
            config_rule['custom']['resource_value'] = custom_resource_value
        elif not isinstance(custom_resource_value, str):
            config_rule['custom']['resource_value'] = str(custom_resource_value)
    return config_rules

def format_device_custom_config_rules(device : Dict) -> Dict:
+32 −1
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@
import logging, lxml.etree as ET
from typing import Any, Dict, List, Tuple
from .Namespace import NAMESPACES
from .Tools import add_value_from_tag
from .Tools import add_value_from_tag, add_int_from_tag

LOGGER = logging.getLogger(__name__)

@@ -55,6 +55,8 @@ XPATH_PORTS = "//ocp:components/ocp:component"
def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]:
    response = []
    parent_types = {}
    #Initialized count to 0 for index
    count = 0
    for xml_component in xml_data.xpath(XPATH_PORTS, namespaces=NAMESPACES):
        LOGGER.info('xml_component inventario = {:s}'.format(str(ET.tostring(xml_component))))
        inventory = {}
@@ -64,6 +66,7 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]:
        inventory['attributes'] = {}
        component_reference = []
        

        component_name = xml_component.find('ocp:name', namespaces=NAMESPACES)
        if component_name is None or component_name.text is None: continue
        add_value_from_tag(inventory, 'name', component_name)        
@@ -83,6 +86,34 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]:
        
        if inventory['class'] == 'CPU' or inventory['class'] == 'STORAGE': continue

        ##Added (after the checking of the name and the class)
        #Physical index- Index of the component in the array
    
        add_int_from_tag(inventory['attributes'], 'physical-index', count)
        count +=1

        ##Added
        #FRU
        if inventory['class'] == 'FRU':
            component_isfru = xml_component.find('ocp:state/ocp:type', namespaces=NAMESPACES)
            add_value_from_tag(inventory['attributes'], 'isfru', component_isfru)
        ##ID
        component_id = xml_component.find('ocp:state/ocp:id', namespaces=NAMESPACES)
        if not component_id is None:
            add_value_from_tag(inventory['attributes'], 'id', component_id)

        ##OPER_STATUS
        component_oper_status = xml_component.find('ocp:state/ocp:oper-status', namespaces=NAMESPACES)
        if not component_oper_status is None:
            add_value_from_tag(inventory['attributes'], 'oper-status', component_oper_status)

        ##MODEL_ID  
        component_model_id = xml_component.find('ocp:state/ocp:entity-id', namespaces=NAMESPACES)
        if not component_model_id is None:
            add_value_from_tag(inventory['attributes'], 'model-id', component_model_id)
    
    ##
        
        component_empty = xml_component.find('ocp:state/ocp:empty', namespaces=NAMESPACES)
        if not component_empty is None:
            add_value_from_tag(inventory['attributes'], 'empty', component_empty)
+5 −0
Original line number Diff line number Diff line
@@ -26,6 +26,11 @@ def add_value_from_tag(target : Dict, field_name: str, field_value : ET.Element,
    if cast is not None: field_value = cast(field_value)
    target[field_name] = field_value

def add_int_from_tag(target : Dict, field_name: str, field_value : int, cast=None) -> None:
    if field_value is None: return
    if cast is not None: field_value = cast(field_value)
    target[field_name] = field_value

def add_value_from_collection(target : Dict, field_name: str, field_value : Collection) -> None:
    if field_value is None or len(field_value) == 0: return
    target[field_name] = field_value
Loading