diff --git a/src/device/service/drivers/oc_driver/OCDriver.py b/src/device/service/drivers/oc_driver/OCDriver.py index 8d437ccc8dd3b92d246db20127bc916c3b8ec5b4..c5a2439589fb5bab4874929a6850e19b22306f80 100644 --- a/src/device/service/drivers/oc_driver/OCDriver.py +++ b/src/device/service/drivers/oc_driver/OCDriver.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import time import json -import logging, pytz, queue, re, threading -#import lxml.etree as ET +import logging, pytz, re, threading from typing import Any, List, Tuple, Union from apscheduler.executors.pool import ThreadPoolExecutor from apscheduler.jobstores.memory import MemoryJobStore @@ -22,12 +22,11 @@ from apscheduler.schedulers.background import BackgroundScheduler from ncclient.manager import Manager, connect_ssh from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method from common.tools.client.RetryDecorator import delay_exponential -from common.type_checkers.Checkers import chk_type +from common.type_checkers.Checkers import chk_length, chk_string, chk_type from device.service.driver_api.Exceptions import UnsupportedResourceKeyException from device.service.driver_api._Driver import _Driver -from device.service.driver_api.AnyTreeTools import TreeNode +from .templates import compose_config, cli_compose_config, ufi_interface, cisco_interface from .templates.VPN.common import seperate_port_config -#from .Tools import xml_pretty_print, xml_to_dict, xml_to_file from .templates.VPN.roadms import ( create_optical_band, disable_media_channel, delete_optical_band, create_media_channel_v2 ) @@ -36,11 +35,10 @@ from .RetryDecorator import retry from context.client.ContextClient import ContextClient from common.proto.context_pb2 import OpticalConfig from .templates.discovery_tool.transponders import transponder_values_extractor -from .templates.discovery_tool.roadms import roadm_values_extractor, extract_media_channels +from .templates.discovery_tool.roadms import roadm_values_extractor from .templates.discovery_tool.open_roadm import openroadm_values_extractor from .templates.VPN.openroadm import network_media_channel_handler - DEBUG_MODE = False logging.getLogger('ncclient.manager').setLevel(logging.DEBUG if DEBUG_MODE else logging.WARNING) logging.getLogger('ncclient.transport.ssh').setLevel(logging.DEBUG if DEBUG_MODE else logging.WARNING) @@ -51,9 +49,6 @@ logging.getLogger('monitoring-client').setLevel(logging.INFO if DEBUG_MODE else RE_GET_ENDPOINT_FROM_INTERFACE_KEY = re.compile(r'.*interface\[([^\]]+)\].*') RE_GET_ENDPOINT_FROM_INTERFACE_XPATH = re.compile(r".*interface\[oci\:name\='([^\]]+)'\].*") -# Collection of samples through NetConf is very slow and each request collects all the data. -# Populate a cache periodically (when first interface is interrogated). -# Evict data after some seconds, when data is considered as outdated SAMPLE_EVICTION_SECONDS = 30.0 # seconds SAMPLE_RESOURCE_KEY = 'interfaces/interface/state/counters' @@ -200,6 +195,65 @@ def edit_config( #results[i] = True results.append(result) + + if netconf_handler.vendor == "CISCO": + if "L2VSI" in resources[0][1]: + #Configure by CLI + logger.warning("CLI Configuration") + cli_compose_config(resources, delete=delete, host= netconf_handler._NetconfSessionHandler__address, user=netconf_handler._NetconfSessionHandler__username, passw=netconf_handler._NetconfSessionHandler__password) + for i,resource in enumerate(resources): + results.append(True) + else: + logger.warning("CLI Configuration CISCO INTERFACE") + cisco_interface(resources, delete=delete, host= netconf_handler._NetconfSessionHandler__address, user=netconf_handler._NetconfSessionHandler__username, passw=netconf_handler._NetconfSessionHandler__password) + for i,resource in enumerate(resources): + results.append(True) + elif netconf_handler.vendor == "UFISPACE": + #Configure by CLI + logger.warning("CLI Configuration: {:s}".format(resources)) + ufi_interface(resources, delete=delete, host= netconf_handler._NetconfSessionHandler__address, user=netconf_handler._NetconfSessionHandler__username, passw=netconf_handler._NetconfSessionHandler__password) + for i,resource in enumerate(resources): + results.append(True) + else: + for i,resource in enumerate(resources): + str_resource_name = 'resources[#{:d}]'.format(i) + try: + logger.debug('[{:s}] resource = {:s}'.format(str_method, str(resource))) + chk_type(str_resource_name, resource, (list, tuple)) + chk_length(str_resource_name, resource, min_length=2, max_length=2) + resource_key,resource_value = resource + chk_string(str_resource_name + '.key', resource_key, allow_empty=False) + str_config_messages = compose_config( # get template for configuration + resource_key, resource_value, delete=delete, vendor=netconf_handler.vendor, message_renderer=netconf_handler.message_renderer) + for str_config_message in str_config_messages: # configuration of the received templates + if str_config_message is None: raise UnsupportedResourceKeyException(resource_key) + logger.debug('[{:s}] str_config_message[{:d}] = {:s}'.format( + str_method, len(str_config_message), str(str_config_message))) + netconf_handler.edit_config( # configure the device + config=str_config_message, target=target, default_operation=default_operation, + test_option=test_option, error_option=error_option, format=format) + if commit_per_rule: + netconf_handler.commit() # configuration commit + if 'table_connections' in resource_key: + time.sleep(5) # CPU usage might exceed critical level after route redistribution, BGP daemon needs time to reload + + #results[i] = True + results.append(True) + except Exception as e: # pylint: disable=broad-except + str_operation = 'preparing' if target == 'candidate' else ('deleting' if delete else 'setting') + msg = '[{:s}] Exception {:s} {:s}: {:s}' + logger.exception(msg.format(str_method, str_operation, str_resource_name, str(resource))) + #results[i] = e # if validation fails, store the exception + results.append(e) + + if not commit_per_rule: + try: + netconf_handler.commit() + except Exception as e: # pylint: disable=broad-except + msg = '[{:s}] Exception committing: {:s}' + str_operation = 'preparing' if target == 'candidate' else ('deleting' if delete else 'setting') + logger.exception(msg.format(str_method, str_operation, str(resources))) + results = [e for _ in resources] # if commit fails, set exception in each resource return results diff --git a/src/device/service/drivers/oc_driver/templates/IP_LINK/IP_LINK_multivendor.py b/src/device/service/drivers/oc_driver/templates/IP_LINK/IP_LINK_multivendor.py new file mode 100755 index 0000000000000000000000000000000000000000..f4f6ad4dd0000e6b78352a129c87dc0c56aa7d53 --- /dev/null +++ b/src/device/service/drivers/oc_driver/templates/IP_LINK/IP_LINK_multivendor.py @@ -0,0 +1,59 @@ +# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# 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. + +from yattag import Doc, indent + +def ip_link_mgmt(data,vendor, delete): + doc, tag, text = Doc().tagtext() + + ID = data['endpoint_id']['endpoint_uuid']['uuid'] + DATA = data["rule_set"] + + with tag('interfaces', xmlns="http://openconfig.net/yang/interfaces"): + if delete == True: + with tag('interface' ,'xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete"'): + with tag('name'):text(ID) + else: + with tag('interface'): + with tag('name'):text(ID) + with tag('config'): + with tag('name'):text(ID) + with tag('type', 'xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type"'):text('ianaift:l3ipvlan') + with tag('enabled'):text('true') + with tag('subinterfaces'): + with tag('subinterface'): + if vendor is None or vendor == 'ADVA': + with tag('index'): text('0') + with tag('config'): + with tag('index'): text('0') + if vendor == 'ADVA' and not 'vlan'in data: + with tag('untagged-allowed', 'xmlns="http://www.advaoptical.com/cim/adva-dnos-oc-interfaces"'):text('true') + with tag('vlan', xmlns="http://openconfig.net/yang/vlan"): + with tag('match'): + with tag('single-tagged'): + with tag('config'): + with tag('vlan-id'):text(DATA['vlan']) + with tag('ipv4', xmlns="http://openconfig.net/yang/interfaces/ip"): + with tag('addresses'): + with tag('address'): + with tag('ip'):text(DATA['ip']) + with tag('config'): + with tag('ip'):text(DATA['ip']) + with tag('prefix-length'):text(DATA['mask']) + result = indent( + doc.getvalue(), + indentation = ' '*2, + newline = '\r\n' + ) + return result \ No newline at end of file diff --git a/src/device/service/drivers/oc_driver/templates/Tools.py b/src/device/service/drivers/oc_driver/templates/Tools.py index 71f827dfe80a5064723e1287ae4419f1d38bde5e..eeb3b253c6704f861d0d9d94d8e35331a27a245b 100644 --- a/src/device/service/drivers/oc_driver/templates/Tools.py +++ b/src/device/service/drivers/oc_driver/templates/Tools.py @@ -13,12 +13,10 @@ # limitations under the License. import re,logging -import json import lxml.etree as ET -from typing import Collection, Dict, Any +from typing import Collection, Dict +from .IP_LINK.IP_LINK_multivendor import ip_link_mgmt -from yattag import Doc, indent -from .VPN.physical import create_optical_channel def add_value_from_tag(target : Dict, field_name: str, field_value : ET.Element, cast=None) -> None: if isinstance(field_value,str) or field_value is None or field_value.text is None: return @@ -49,14 +47,12 @@ def add_value_from_collection(target : Dict, field_name: str, field_value : Coll # Return: [dict] Set of templates generated according to the configuration rule """ -def generate_templates(resource_key: str, resource_value: str, channel:str) -> str: # template management to be configured +def generate_templates(resource_key: str, resource_value: str, delete: bool,vendor:str) -> str: # template management to be configured result_templates = [] - data={} - data['name']=channel - data['resource_key']=resource_key - data['value']=resource_value - #result_templates.append(create_physical_config(data)) + list_resource_key = resource_key.split("/") # the rule resource key management + if "ip_link" in list_resource_key[1]: # network instance rules management + result_templates.append(ip_link_mgmt(resource_value,vendor,delete)) return result_templates diff --git a/src/device/service/drivers/oc_driver/templates/__init__.py b/src/device/service/drivers/oc_driver/templates/__init__.py index 53d5157f750bfb085125cbd33faff1cec5924e14..2c83aee416b5f44ba03d804a1a6c0fb5bc127f50 100644 --- a/src/device/service/drivers/oc_driver/templates/__init__.py +++ b/src/device/service/drivers/oc_driver/templates/__init__.py @@ -12,3 +12,288 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json, logging, lxml.etree as ET, re +import time +from typing import Any, Dict, Optional +from jinja2 import Environment, PackageLoader, select_autoescape +import paramiko +from .Tools import generate_templates + +LOGGER = logging.getLogger(__name__) + + + +LOGGER = logging.getLogger(__name__) +RE_REMOVE_FILTERS = re.compile(r'\[[^\]]+\]') +RE_REMOVE_FILTERS_2 = re.compile(r'\/[a-z]+:') +EMPTY_CONFIG = '<config></config>' +EMPTY_FILTER = '<filter></filter>' +JINJA_ENV = Environment(loader=PackageLoader('device.service.drivers.openconfig'), autoescape=select_autoescape()) + +""" +# Method Name: compose_config + +# Parameters: + - resource_key: [str] Variable to identify the rule to be executed. + - resource_value: [str] Variable with the configuration parameters of the rule to be executed. + - delete: [bool] Variable to identify whether to create or delete the rule. + - vendor: [str] Variable to identify the vendor of the equipment to be configured. + - message_renderer [str] Variable to dientify template generation method. Can be "jinja" or "pyangbind". + +# Functionality: + This method calls the function obtains the equipment configuration template according to the value of the variable "message_renderer". + Depending on the value of this variable, it gets the template with "jinja" or "pyangbind". + +# Return: + [dict] Set of templates obtained according to the configuration method +""" + +def compose_config( # template generation + resource_key : str, resource_value : str, delete : bool = False, vendor : Optional[str] = None, message_renderer = str +) -> str: + + if (message_renderer == "pyangbind"): + templates = (generate_templates(resource_key, resource_value, delete, vendor)) + return [ + '<config>{:s}</config>'.format(template) # format correction + for template in templates + ] + + elif (message_renderer == "jinja"): + templates = [] + template_name = '{:s}/edit_config.xml'.format(RE_REMOVE_FILTERS.sub('', resource_key)) + templates.append(JINJA_ENV.get_template(template_name)) + data : Dict[str, Any] = json.loads(resource_value) + + operation = 'delete' if delete else 'merge' # others + #operation = 'delete' if delete else '' # ipinfusion? + + return [ + '<config>{:s}</config>'.format( + template.render(**data, operation=operation, vendor=vendor).strip()) + for template in templates + ] + + else: + raise ValueError('Invalid message_renderer value: {}'.format(message_renderer)) + +""" +# Method Name: cli_compose_config + +# Parameters: + - resource_key: [str] Variable to identify the rule to be executed. + - resource_value: [str] Variable with the configuration parameters of the rule to be executed. + - delete: [bool] Variable to identify whether to create or delete the rule. + - vendor: [str] Variable to identify the vendor of the equipment to be configured. + - message_renderer [str] Variable to dientify template generation method. Can be "jinja" or "pyangbind". + +# Functionality: + This method calls the function obtains the equipment configuration template according to the value of the variable "message_renderer". + Depending on the value of this variable, it gets the template with "jinja" or "pyangbind". + +# Return: + [dict] Set of templates obtained according to the configuration method +""" + +def cli_compose_config(resources, delete: bool, host: str, user: str, passw: str): #Method used for configuring via CLI directly L2VPN in CISCO devices + + key_value_data = {} + + for path, json_str in resources: + key_value_data[path] = json_str + + # Iterate through the resources and extract parameter values dynamically + for path, json_str in resources: + data = json.loads(json_str) + if 'VC_ID' in data: vc_id = data['VC_ID'] + if 'connection_point' in data: connection_point = data['connection_point'] + if 'remote_system' in data: remote_system = data['remote_system'] + if 'interface' in data: + interface = data['interface'] + interface = interface.split("-") #New Line To Avoid Bad Endpoint Name In CISCO + interface = interface[1] + if 'vlan_id' in data: vlan_id = data['vlan_id'] + if 'name' in data: ni_name = data['name'] + if 'type' in data: ni_type = data['type'] + if 'index' in data: subif_index = data['index'] + if 'description' in data: description = data['description'] + else: description = " " + + # initialize the SSH client + ssh_client = paramiko.SSHClient() + ssh_client.load_system_host_keys() + # add to known hosts + ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + try: + ssh_client.connect(hostname=host, username=user, password=passw, look_for_keys=False) + #print("Connection successful") + LOGGER.warning("Connection successful") + except: + #print("[!] Cannot connect to the SSH Server") + LOGGER.warning("[!] Cannot connect to the SSH Server") + exit() + + try: + # Open an SSH shell + channel = ssh_client.invoke_shell() + channel.send('enable\n') + time.sleep(1) + channel.send('conf term\n') + time.sleep(0.1) + channel.send(f"interface {interface} l2transport\n") + time.sleep(0.1) + channel.send('description l2vpn_vpws_example\n') + time.sleep(0.1) + channel.send(f"encapsulation dot1q {vlan_id}\n") + time.sleep(0.1) + channel.send('mtu 9088\n') + time.sleep(0.1) + channel.send('commit\n') + time.sleep(0.1) + + channel.send('l2vpn\n') + time.sleep(0.1) + channel.send('load-balancing flow src-dst-ip\n') + time.sleep(0.1) + channel.send('pw-class l2vpn_vpws_profile_example\n') + time.sleep(0.1) + channel.send('encapsulation mpls\n') + time.sleep(0.1) + channel.send('transport-mode vlan passthrough\n') + time.sleep(0.1) + channel.send('control-word\n') + time.sleep(0.1) + channel.send('exit\n') + time.sleep(0.1) + channel.send('l2vpn\n') + time.sleep(0.1) + channel.send('xconnect group l2vpn_vpws_group_example\n') + time.sleep(0.1) + channel.send(f"p2p {ni_name}\n") + time.sleep(0.1) + channel.send(f"interface {interface}\n") #Ignore the VlanID because the interface already includes the vlanid tag + time.sleep(0.1) + channel.send(f"neighbor ipv4 {remote_system} pw-id {vc_id}\n") + time.sleep(0.1) + channel.send('pw-class l2vpn_vpws_profile_example\n') + time.sleep(0.1) + channel.send('exit\n') + time.sleep(0.1) + channel.send(f"description {description}\n") + time.sleep(0.1) + channel.send('commit\n') + time.sleep(0.1) + # Capturar la salida del comando + output = channel.recv(65535).decode('utf-8') + #print(output) + LOGGER.warning(output) + # Close the SSH shell + channel.close() + + except Exception as e: + LOGGER.exception(f"Error with the CLI configuration: {e}") + + # Close the SSH client + ssh_client.close() + +def ufi_interface(resources, delete: bool, host: str, user: str, passw: str): #Method used for configuring via CLI directly L2VPN in CISCO devices + + key_value_data = {} + + for path, json_str in resources: + key_value_data[path] = json_str + + # initialize the SSH client + ssh_client = paramiko.SSHClient() + ssh_client.load_system_host_keys() + # add to known hosts + ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + try: + ssh_client.connect(hostname=host, username=user, password=passw, look_for_keys=False) + LOGGER.warning("Connection successful") + except: + LOGGER.warning("[!] Cannot connect to the SSH Server") + exit() + interface = 'ge100-0/0/3/1' + ip = '1.1.1.1' + mask = '24' + vlan = '1212' + try: + # Open an SSH shell + channel = ssh_client.invoke_shell() + time.sleep(5) + channel.send('config\n') + time.sleep(1) + channel.send(f'interfaces {interface} \n') + time.sleep(1) + channel.send('admin-state enabled \n') + time.sleep(1) + channel.send(f'ipv4-address {ip}/{mask} \n') + time.sleep(1) + channel.send(f'vlan-id {vlan} \n') + time.sleep(1) + channel.send('commit\n') + time.sleep(1) + + output = channel.recv(65535).decode('utf-8') + LOGGER.warning(output) + # Close the SSH shell + channel.close() + + except Exception as e: + LOGGER.exception(f"Error with the CLI configuration: {e}") + + # Close the SSH client + ssh_client.close() + +def cisco_interface(resources, delete: bool, host: str, user: str, passw: str): #Method used for configuring via CLI directly L2VPN in CISCO devices + + key_value_data = {} + for path, json_str in resources: + key_value_data[path] = json_str + + # initialize the SSH client + ssh_client = paramiko.SSHClient() + ssh_client.load_system_host_keys() + # add to known hosts + ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + try: + ssh_client.connect(hostname=host, username=user, password=passw, look_for_keys=False) + LOGGER.warning("Connection successful") + except: + LOGGER.warning("[!] Cannot connect to the SSH Server") + exit() + interface = 'FourHundredGigE0/0/0/10.1212' + ip = '1.1.1.1' + mask = '24' + vlan = '1212' + try: + # Open an SSH shell + channel = ssh_client.invoke_shell() + time.sleep(1) + channel.send('config\n') + time.sleep(0.1) + channel.send(f'interface {interface} \n') + time.sleep(0.1) + channel.send('no shutdown\n') + time.sleep(0.1) + channel.send(f'ipv4 address {ip}/{mask} \n') + time.sleep(0.1) + channel.send(f'encapsulation dot1q {vlan} \n') + time.sleep(0.1) + channel.send('commit\n') + time.sleep(0.1) + + output = channel.recv(65535).decode('utf-8') + LOGGER.warning(output) + # Close the SSH shell + channel.close() + + except Exception as e: + LOGGER.exception(f"Error with the CLI configuration: {e}") + + # Close the SSH client + ssh_client.close() diff --git a/src/service/service/service_handlers/__init__.py b/src/service/service/service_handlers/__init__.py index c2961192931670a87691a077e127d74a445a923a..dac6656107055656595a14e8b8dabfe8555daad2 100644 --- a/src/service/service/service_handlers/__init__.py +++ b/src/service/service/service_handlers/__init__.py @@ -115,6 +115,12 @@ SERVICE_HANDLERS = [ FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, } ]), + (IP_LinkServiceHandler, [ + { + FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_IPLINK, + FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_OC, + } + ]), (QKDServiceHandler, [ { FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_QKD, diff --git a/src/service/service/service_handlers/ip_link/IP_LinkServiceHandler.py b/src/service/service/service_handlers/ip_link/IP_LinkServiceHandler.py index cbb42a5c89c8db32c327e13122b219c1c1ec3c55..d02f71bc73821da9e2690bd888e49244bd3c002f 100644 --- a/src/service/service/service_handlers/ip_link/IP_LinkServiceHandler.py +++ b/src/service/service/service_handlers/ip_link/IP_LinkServiceHandler.py @@ -43,9 +43,6 @@ class IP_LinkServiceHandler(_ServiceHandler): chk_type('endpoints', endpoints, list) if len(endpoints) == 0: return [] - service_uuid = self.__service.service_id.service_uuid.uuid - settings = self.__settings_handler.get('/settings') - results = [] for endpoint in endpoints: try: diff --git a/src/service/service/service_handlers/oc/ConfigRules.py b/src/service/service/service_handlers/oc/ConfigRules.py new file mode 100644 index 0000000000000000000000000000000000000000..e2de985b15494f55923749a4d09f3febfe66c917 --- /dev/null +++ b/src/service/service/service_handlers/oc/ConfigRules.py @@ -0,0 +1,57 @@ +# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# 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 logging +from typing import Any, Dict, List, Optional, Tuple +from service.service.service_handler_api.AnyTreeTools import TreeNode +LOGGER = logging.getLogger(__name__) + +def get_value(field_name : str, *containers, default=None) -> Optional[Any]: + if len(containers) == 0: raise Exception('No containers specified') + for container in containers: + if field_name not in container: continue + return container[field_name] + return default + +def setup_config_rules( + endpoint_name : str, endpoint_ip_link : List [Tuple] +) -> List[Dict]: + + json_config_rules = [ + ] + + for res_key, res_value in endpoint_ip_link: + json_config_rules.append( + {'action': 1, 'ip_link': res_value} + ) + + return json_config_rules + +def teardown_config_rules( + service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str, endpoint_name : str, + service_settings : TreeNode, device_settings : TreeNode, endpoint_settings : TreeNode +) -> List[Dict]: + + if service_settings is None: return [] + if device_settings is None: return [] + if endpoint_settings is None: return [] + + json_settings : Dict = service_settings.value + json_device_settings : Dict = device_settings.value + json_endpoint_settings : Dict = endpoint_settings.value + + settings = (json_settings, json_endpoint_settings, json_device_settings) + + json_config_rules = [] + return json_config_rules diff --git a/src/service/service/service_handlers/oc/OCServiceHandler.py b/src/service/service/service_handlers/oc/OCServiceHandler.py index 462685c3d1e40dd7af9a2f5dc297a2ae06d02588..49212d1aa5e82097627709dc77fe6d99914b6d98 100644 --- a/src/service/service/service_handlers/oc/OCServiceHandler.py +++ b/src/service/service/service_handlers/oc/OCServiceHandler.py @@ -15,16 +15,17 @@ import json, logging from typing import Any, List, Optional, Tuple, Union from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method -from common.proto.context_pb2 import DeviceId, Service +from common.proto.context_pb2 import ConfigRule, DeviceId, Service from common.tools.object_factory.Device import json_device_id from common.type_checkers.Checkers import chk_type from common.DeviceTypes import DeviceTypeEnum -from service.service.service_handler_api.Tools import get_endpoint_matching +from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching from service.service.service_handler_api._ServiceHandler import _ServiceHandler from service.service.service_handler_api.SettingsHandler import SettingsHandler from service.service.task_scheduler.TaskExecutor import TaskExecutor +from .ConfigRules import setup_config_rules, teardown_config_rules from .OCTools import ( - convert_endpoints_to_flows, endpoints_to_flows, + convert_endpoints_to_flows #handle_flows_names, check_media_channel_existance ) @@ -68,6 +69,28 @@ class OCServiceHandler(_ServiceHandler): #handled_flows=handle_flows_names(flows=flows,task_executor=self.__task_executor) results = [] + for endpoint in endpoints: + try: + device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) + + device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) + endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) + endpoint_ip_link = self.__settings_handler.get_endpoint_ip_link(device_obj, endpoint_obj) + endpoint_name = endpoint_obj.name + json_config_rules = setup_config_rules( + endpoint_name, endpoint_ip_link) + + if len(json_config_rules) > 0: + del device_obj.device_config.config_rules[:] + for json_config_rule in json_config_rules: + device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) + self.__task_executor.configure_device(device_obj) + + results.append(True) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unable to SetEndpoint({:s})'.format(str(endpoint))) + results.append(e) + LOGGER.info(f"flows {flows} ") LOGGER.info(f"settings {settings} ") @@ -102,6 +125,32 @@ class OCServiceHandler(_ServiceHandler): settings = self.__settings_handler.get('/settings') results = [] + + for endpoint in endpoints: + try: + device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) + + device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) + device_settings = self.__settings_handler.get_device_settings(device_obj) + endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) + endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) + endpoint_name = endpoint_obj.name + + json_config_rules = teardown_config_rules( + service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name, + settings, device_settings, endpoint_settings) + + if len(json_config_rules) > 0: + del device_obj.device_config.config_rules[:] + for json_config_rule in json_config_rules: + device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) + self.__task_executor.configure_device(device_obj) + + results.append(True) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unable to DeleteEndpoint({:s})'.format(str(endpoint))) + results.append(e) + for device_uuid, dev_flows in flows.items(): try: channel_indexes= []