From 72bbd345c11c057b2da0abfe09514639bcdecd10 Mon Sep 17 00:00:00 2001
From: ismaeel <mohammad.ismaael@cnit.it>
Date: Mon, 15 Apr 2024 06:05:03 +0000
Subject: [PATCH] Roadm endpoints auto discovery

---
 src/context/service/database/OpticalConfig.py |  6 +-
 .../database/models/OpticalConfigModel.py     |  4 +-
 .../service/drivers/oc_driver/OCDriver.py     | 48 ++++++-----
 .../drivers/oc_driver/templates/Tools.py      | 84 ++++++++++++++-----
 4 files changed, 99 insertions(+), 43 deletions(-)

diff --git a/src/context/service/database/OpticalConfig.py b/src/context/service/database/OpticalConfig.py
index 8251af887..3884e5f57 100644
--- a/src/context/service/database/OpticalConfig.py
+++ b/src/context/service/database/OpticalConfig.py
@@ -72,9 +72,9 @@ def set_opticalconfig(db_engine : Engine, request : OpticalConfig):
            {
                                     "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"]],}
+                                    "interfaces"        :"",
+                                    "channel_namespace" : config.get("channel_namespace",None),
+                                    "endpoints"         : [json.dumps(endpoint) for endpoint in config.get("endpoints",[])],}
                                    
         )
             
diff --git a/src/context/service/database/models/OpticalConfigModel.py b/src/context/service/database/models/OpticalConfigModel.py
index 9937f342d..a2007886c 100644
--- a/src/context/service/database/models/OpticalConfigModel.py
+++ b/src/context/service/database/models/OpticalConfigModel.py
@@ -38,9 +38,9 @@ class OpticalConfigModel(_Base):
         return {
             "channels"          : [channel.dump() for channel in self.channels],
             "transceivers"      : {"transceiver": [transciever for transciever in self.transcievers]},
-            "interfaces"        : {"interface": json.loads(self.interfaces)},
+            "interfaces"        : {"interface":json.loads(self.interfaces) if self.interfaces else ''},
             "channel_namespace" : self.channel_namespace,
-            "endpoints"         : [json.loads(endpoint) for endpoint in self.endpoints],
+            "endpoints"         : [json.loads(endpoint) for endpoint in self.endpoints if endpoint],
             
         }
         
diff --git a/src/device/service/drivers/oc_driver/OCDriver.py b/src/device/service/drivers/oc_driver/OCDriver.py
index 1e9ea74c9..3f91df18c 100644
--- a/src/device/service/drivers/oc_driver/OCDriver.py
+++ b/src/device/service/drivers/oc_driver/OCDriver.py
@@ -38,7 +38,7 @@ from common.proto.context_pb2 import (
     OpticalConfig,
     ConfigActionEnum, Device, DeviceDriverEnum, DeviceId, DeviceList, DeviceOperationalStatusEnum, Empty
     ,OpticalConfigId,Uuid)
-from .templates.Tools import extractor
+from .templates.Tools import roadm_values_extractor, transponder_values_extractor
 from .Tools import generate_uuid_from_numbers
 DEBUG_MODE = False
 logging.getLogger('ncclient.manager').setLevel(logging.DEBUG if DEBUG_MODE else logging.WARNING)
@@ -83,6 +83,7 @@ class NetconfSessionHandler:
         self.__manager_params   = settings.get('manager_params', {})
         self.__nc_params        = settings.get('nc_params', {})
         self.__message_renderer = settings.get('message_renderer','jinja')
+      
         self.__manager : Manager   = None
         self.__candidate_supported = False
        
@@ -198,6 +199,7 @@ class OCDriver(_Driver):
         super().__init__(DRIVER_NAME, address, port, **settings)
         self.__logger = logging.getLogger('{:s}:[{:s}:{:s}]'.format(str(__name__), str(self.address), str(self.port)))
         self.__lock = threading.Lock()
+        
         #self.__initial = TreeNode('.')
         #self.__running = TreeNode('.')
         self.__subscriptions = TreeNode('.')
@@ -212,13 +214,12 @@ class OCDriver(_Driver):
         self._temp_address=f"{address}{port}"
         self.__out_samples = queue.Queue()
         self.__netconf_handler = NetconfSessionHandler(self.address, self.port, **(self.settings))
-      
+        self.__type = self.settings.get("type","optical-transponder")
         self.__device_uuid=device_uuid
       
         self.Connect()
-        #self.GetConfig()
-        #self.__samples_cache = SamplesCache(self.__netconf_handler, self.__logger)
-
+        logging.info(f"settings {settings}")
+        
     def Connect(self) -> bool:
         with self.__lock:
             if self.__started.is_set(): return True
@@ -251,21 +252,35 @@ class OCDriver(_Driver):
         chk_type('resources', resource_keys, list)
         results = []
         opticalConfig= OpticalConfig()
-        j=0
+        
         
         with self.__lock:
            
      
             context_client.connect()
             config={}
-            channels_lst=[]
+            
             transceivers={}
+            oc_values={}
+            ports_result=[]
           
             try:
                 xml_data = self.__netconf_handler.get().data_xml
-                transceivers,interfaces,channels_lst,channel_namespace,endpoints,ports_result=extractor(data_xml=xml_data,resource_keys=filter_fields,dic=config)     
-                            
-                logging.info(f"xml response {xml_data}")
+                
+                if (self.__type == "optical-transponder"):
+                    extracted_values=transponder_values_extractor(data_xml=xml_data,resource_keys=filter_fields,dic=config)     
+                    transceivers,optical_channels_params,channel_namespace,endpoints,ports_result=extracted_values
+                    oc_values["channels"]=optical_channels_params
+                    oc_values["transceivers"]=transceivers     
+                    oc_values["channel_namespace"]=channel_namespace
+                    oc_values["endpoints"]=endpoints
+                    oc_values["ports"]=ports_result
+                else :
+                    extracted_values=roadm_values_extractor(data_xml=xml_data,resource_keys=filter_fields,dic=config)
+                    ports_result = extracted_values[0]
+                
+                        
+              
                 
             except Exception as e: # pylint: disable=broad-except
                         MSG = 'Exception retrieving {:s}'
@@ -276,15 +291,10 @@ class OCDriver(_Driver):
           #///////////////////////// store optical configurtaion  ////////////////////////////////////////////////////////
             
             
-            value_dic={}
-            value_dic["channels"]=channels_lst
-            value_dic["transceivers"]=transceivers  
-            value_dic["interfaces"]=interfaces        
-            value_dic["channel_namespace"]=channel_namespace
-            value_dic["endpoints"]=endpoints
-            value_dic["ports"]=ports_result
-            logging.info(f"parameters {value_dic}")
-            opticalConfig.config=json.dumps(value_dic)
+          
+           
+            logging.info(f"parameters {oc_values}")
+            opticalConfig.config=json.dumps(oc_values)
             opticalConfig.opticalconfig_id.opticalconfig_uuid=self.__device_uuid if self.__device_uuid is not None else ""
             config_id=context_client.SetOpticalConfig(opticalConfig)
            
diff --git a/src/device/service/drivers/oc_driver/templates/Tools.py b/src/device/service/drivers/oc_driver/templates/Tools.py
index a088d4a1f..704cb76a4 100644
--- a/src/device/service/drivers/oc_driver/templates/Tools.py
+++ b/src/device/service/drivers/oc_driver/templates/Tools.py
@@ -238,40 +238,33 @@ def has_opticalbands(xml_data:str):
     return has_opticalbands
   
 def extract_ports_based_on_type (xml_data:str):
-    pattern = r'\bPORT\b'
+    pattern = r':\s*PORT\b'
     xml_bytes = xml_data.encode("utf-8")
     root = ET.fromstring(xml_bytes)
-
     namespace = {'oc': 'http://openconfig.net/yang/platform', 'typex': 'http://openconfig.net/yang/platform-types'}
     ports = []
-    components = root.findall('.//oc:type',namespace)
-
-    
+    components = root.findall(".//oc:state[oc:type]",namespace)
     for component in components:
-       
-         
-        if component is not None and re.search(pattern,component.text):
-            
-           
-            name_element = component.getprevious()  
+         type_ele = component.find(".//oc:type",namespace)
+         match = re.search(pattern, type_ele.text)
+         if match is not None :
+            name_element= component.find(".//oc:name",namespace)
             port_name =name_element.text       
             port_index=name_element.text.split("-")[1]
             port = (port_name,port_index)
             ports.append(port)
     return ports  
     
-def extractor(data_xml:str,resource_keys:list,dic:dict):
+def transponder_values_extractor(data_xml:str,resource_keys:list,dic:dict):
    
     endpoints=[]
     is_opticalband=has_opticalbands(xml_data=data_xml)
-   
     channel_namespace=extract_channel_xmlns(data_xml=data_xml,is_opticalband=is_opticalband)
     # channel_names=extract_channels_based_on_type(xml_data=data_xml) 
     # if len(channel_names)==0 :
     channel_names= extract_channels_based_on_channelnamespace(xml_data=data_xml,channel_namespace=channel_namespace,is_opticalband=is_opticalband)
     ports = extract_ports_based_on_type(data_xml)
-   
-    lst_dic=[]
+    optical_channels_params=[]
     ports_result=[]
     if (is_opticalband):
         endpoints=channel_names
@@ -282,13 +275,15 @@ def extractor(data_xml:str,resource_keys:list,dic:dict):
             for resource_key in resource_keys  :
                 
                 if (resource_key != 'interface'):
-                    dic=extract_value(dic=dic,resource_key=resource_key,xml_data=data_xml,channel_name=channel_name,channel_namespace=channel_namespace)  
+                  
+                    dic=extract_value(dic=dic,resource_key=resource_key,xml_data=data_xml
+                                      ,channel_name=channel_name,channel_namespace=channel_namespace)  
                  
             dic["name"]=channel_name
             endpoints.append({"endpoint_uuid":{"uuid":channel_name}})
-            lst_dic.append(dic)                
+            optical_channels_params.append(dic)                
     transceivers_dic=extract_tranceiver(data_xml=data_xml,dic={})
-    interfaces_dic=extract_interface(xml_data=data_xml,dic={})
+    #interfaces_dic=extract_interface(xml_data=data_xml,dic={})
     if len(ports)>0 :
       for port in ports :
         endpoint_name,endpoint_id=port
@@ -297,4 +292,55 @@ def extractor(data_xml:str,resource_keys:list,dic:dict):
         ports_result.append((resource_key, resource_value))
       
    
-    return [transceivers_dic,interfaces_dic,lst_dic,channel_namespace,endpoints,ports_result]
\ No newline at end of file
+    return [transceivers_dic,optical_channels_params,channel_namespace,endpoints,ports_result]
+  
+#########################################################################  
+  
+#################################### ROADMAs ############################
+  
+##########################################################################  
+
+def extract_roadm_ports (xml_data:str):
+  
+    ports =[]
+    pattern = r'\bMG_ON_OPTICAL_PORT_WAVEBAND\b'
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    with open('xml.log', 'w') as f:
+         print(xml_bytes, file=f)
+    
+
+    namespace = {'oc': 'http://openconfig.net/yang/platform'}
+    ports = []
+    components = root.findall('.//oc:component',namespace)
+    print(f"component {components}")
+    
+    
+    for component  in components:
+       
+        properties = component.find(".//oc:properties",namespace)
+       
+        if (properties is not None):
+            for property in properties :
+                value = property.find(".//oc:value",namespace)
+              
+                if (re.search(pattern,value.text)):
+                    name_element= component.find(".//oc:name",namespace)
+                    ports.append(name_element.text)
+    return ports                
+
+
+
+  
+def roadm_values_extractor (data_xml:str,resource_keys:list,dic:dict):
+     ports_result=[]
+     ports = extract_roadm_ports(data_xml)
+     
+     if len(ports)>0 :
+      for port in ports :
+        
+        resource_key = '/endpoints/endpoint[{:s}]'.format(port)
+        resource_value = {'uuid': port, 'type':'MG_ON_OPTICAL_PORT_WAVEBAND'}
+        ports_result.append((resource_key, resource_value))
+      
+     return [ports_result]   
\ No newline at end of file
-- 
GitLab