Loading proto/device.proto +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ service DeviceService { rpc GetInitialConfig (context.DeviceId ) returns (context.DeviceConfig ) {} rpc MonitorDeviceKpi (MonitoringSettings ) returns (context.Empty ) {} rpc SSETelemetrySubscribe(monitoring.SSEMonitoringSubscriptionConfig) returns (monitoring.SSEMonitoringSubscriptionResponse ) {} rpc UpdateDeviceInventory(context.DeviceId ) returns (context.Empty ) {} } message MonitoringSettings { Loading src/context/service/database/Device.py +11 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ from .models.DeviceModel import DeviceModel from .models.EndPointModel import EndPointModel from .models.ComponentModel import ComponentModel from .models.TopologyModel import TopologyDeviceModel, TopologyModel from .models.ConfigRuleModel import DeviceConfigRuleModel, ConfigRuleKindEnum from .models.enums.DeviceDriver import grpc_to_enum__device_driver from .models.enums.DeviceOperationalStatus import grpc_to_enum__device_operational_status from .models.enums.KpiSampleType import grpc_to_enum__kpi_sample_type Loading Loading @@ -243,6 +244,9 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi device_topology_ids = [obj.dump_id() for obj in device_topologies] #LOGGER.warning('device_topology_ids={:s}'.format(str(device_topology_ids))) # Delete old components of the device to make sure they are fully updated session.query(ComponentModel).filter_by(device_uuid=device_uuid).delete() updated_components = False if len(components_data) > 0: Loading @@ -261,6 +265,13 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi component_updates = session.execute(stmt).fetchall() updated_components = any([(updated_at > created_at) for created_at,updated_at in component_updates]) # Delete old /inventory config rules of the device to make sure they are fully updated session.query(DeviceConfigRuleModel).filter( DeviceConfigRuleModel.device_uuid == device_uuid, DeviceConfigRuleModel.kind == ConfigRuleKindEnum.CUSTOM, DeviceConfigRuleModel.data.contains('/inventory') ).delete(synchronize_session=False) changed_config_rules = upsert_config_rules(session, config_rules, device_uuid=device_uuid) return updated or updated_endpoints or updated_components or changed_config_rules, device_topology_ids Loading src/device/client/DeviceClient.py +8 −0 Original line number Diff line number Diff line Loading @@ -113,3 +113,11 @@ class DeviceClient: response = self.stub.SSETelemetrySubscribe(request) LOGGER.debug('SSETelemetrySubscribe result: {:s}'.format(grpc_message_to_json_string(response))) return response @RETRY_DECORATOR def UpdateDeviceInventory(self, request : DeviceId) -> Empty: LOGGER.debug('UpdateDeviceInventory request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.UpdateDeviceInventory(request) LOGGER.debug('UpdateDeviceInventory result: {:s}'.format(grpc_message_to_json_string(response))) return response src/device/service/DeviceServiceServicerImpl.py +60 −2 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_a from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException from common.proto.context_pb2 import ( Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link, OpticalConfig, OpticalConfigId OpticalConfig, OpticalConfigId, ConfigActionEnum ) from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceServicer Loading @@ -37,7 +37,7 @@ from .Tools import ( check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules, deconfigure_rules, get_device_controller_uuid, populate_config_rules, populate_endpoint_monitoring_resources, populate_endpoints, populate_initial_config_rules, subscribe_kpi, unsubscribe_kpi, update_endpoints subscribe_kpi, unsubscribe_kpi, update_endpoints, _raw_config_rules_to_grpc ) LOGGER = logging.getLogger(__name__) Loading Loading @@ -441,3 +441,61 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): ) return SSEMonitoringSubscriptionResponse() @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def UpdateDeviceInventory(self, request : DeviceId, context : grpc.ServicerContext) -> Empty: device_uuid = request.device_uuid.uuid self.mutex_queues.wait_my_turn(device_uuid) try: context_client = ContextClient() device = get_device(context_client, device_uuid, rw_copy=True) if device is None: raise NotFoundException('Device', device_uuid) driver : _Driver = get_driver(self.driver_instance_cache, device) if driver is None: msg = ERROR_MISSING_DRIVER.format(device_uuid=str(device_uuid)) raise OperationFailedException('UpdateDeviceInventory', extra_details=msg) # Clear and populate endpoints again from the driver del device.device_endpoints[:] new_sub_devices = dict() new_sub_links = dict() sorted_sub_device_uuids = list() new_optical_configs = dict() errors = populate_endpoints( device, driver, self.monitoring_loops, new_sub_devices, sorted_sub_device_uuids, new_sub_links, new_optical_configs ) if len(errors) > 0: raise OperationFailedException('UpdateDeviceInventory', extra_details=errors) from device.service.driver_api._Driver import RESOURCE_INVENTORY results_getconfig = driver.GetConfig([RESOURCE_INVENTORY]) # Filter out existing /inventory rules to prevent duplicates or leftovers new_rules = [] for rule in device.device_config.config_rules: if rule.WhichOneof('config_rule') == 'custom': if '/inventory' in rule.custom.resource_key: continue new_rules.append(rule) del device.device_config.config_rules[:] device.device_config.config_rules.extend(new_rules) # Convert new inventory rules and update device config errors = _raw_config_rules_to_grpc( device_uuid, device.device_config, 'Error getting inventory resource {resource_key} on device {device_uuid}: {error}', ConfigActionEnum.CONFIGACTION_SET, results_getconfig ) if len(errors) > 0: raise OperationFailedException('UpdateDeviceInventory', extra_details=errors) context_client.SetDevice(device) context_client.close() return Empty() except Exception as e: LOGGER.exception('Error updating inventory of device {:s}'.format(str(device_uuid))) raise e src/webui/service/device/routes.py +14 −1 Original line number Diff line number Diff line Loading @@ -181,6 +181,19 @@ def detail(device_uuid: str): return render_template( 'device/detail.html', device=device_obj, dde=DeviceDriverEnum, dose=DeviceOperationalStatusEnum) @device.route('detail/<path:device_uuid>/update_inventory', methods=['GET', 'POST']) def update_inventory(device_uuid: str): try: device_id = DeviceId() device_id.device_uuid.uuid = device_uuid device_client.connect() device_client.UpdateDeviceInventory(device_id) device_client.close() flash(f'Inventory of device "{device_uuid}" was successfully updated.', 'success') except Exception as e: flash(f'Problem updating inventory of device "{device_uuid}": {str(e)}', 'danger') return redirect(url_for('device.detail', device_uuid=device_uuid)) @device.route('inventory/<path:device_uuid>', methods=['GET', 'POST']) def inventory(device_uuid: str): context_client.connect() Loading Loading
proto/device.proto +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ service DeviceService { rpc GetInitialConfig (context.DeviceId ) returns (context.DeviceConfig ) {} rpc MonitorDeviceKpi (MonitoringSettings ) returns (context.Empty ) {} rpc SSETelemetrySubscribe(monitoring.SSEMonitoringSubscriptionConfig) returns (monitoring.SSEMonitoringSubscriptionResponse ) {} rpc UpdateDeviceInventory(context.DeviceId ) returns (context.Empty ) {} } message MonitoringSettings { Loading
src/context/service/database/Device.py +11 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ from .models.DeviceModel import DeviceModel from .models.EndPointModel import EndPointModel from .models.ComponentModel import ComponentModel from .models.TopologyModel import TopologyDeviceModel, TopologyModel from .models.ConfigRuleModel import DeviceConfigRuleModel, ConfigRuleKindEnum from .models.enums.DeviceDriver import grpc_to_enum__device_driver from .models.enums.DeviceOperationalStatus import grpc_to_enum__device_operational_status from .models.enums.KpiSampleType import grpc_to_enum__kpi_sample_type Loading Loading @@ -243,6 +244,9 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi device_topology_ids = [obj.dump_id() for obj in device_topologies] #LOGGER.warning('device_topology_ids={:s}'.format(str(device_topology_ids))) # Delete old components of the device to make sure they are fully updated session.query(ComponentModel).filter_by(device_uuid=device_uuid).delete() updated_components = False if len(components_data) > 0: Loading @@ -261,6 +265,13 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi component_updates = session.execute(stmt).fetchall() updated_components = any([(updated_at > created_at) for created_at,updated_at in component_updates]) # Delete old /inventory config rules of the device to make sure they are fully updated session.query(DeviceConfigRuleModel).filter( DeviceConfigRuleModel.device_uuid == device_uuid, DeviceConfigRuleModel.kind == ConfigRuleKindEnum.CUSTOM, DeviceConfigRuleModel.data.contains('/inventory') ).delete(synchronize_session=False) changed_config_rules = upsert_config_rules(session, config_rules, device_uuid=device_uuid) return updated or updated_endpoints or updated_components or changed_config_rules, device_topology_ids Loading
src/device/client/DeviceClient.py +8 −0 Original line number Diff line number Diff line Loading @@ -113,3 +113,11 @@ class DeviceClient: response = self.stub.SSETelemetrySubscribe(request) LOGGER.debug('SSETelemetrySubscribe result: {:s}'.format(grpc_message_to_json_string(response))) return response @RETRY_DECORATOR def UpdateDeviceInventory(self, request : DeviceId) -> Empty: LOGGER.debug('UpdateDeviceInventory request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.UpdateDeviceInventory(request) LOGGER.debug('UpdateDeviceInventory result: {:s}'.format(grpc_message_to_json_string(response))) return response
src/device/service/DeviceServiceServicerImpl.py +60 −2 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_a from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException from common.proto.context_pb2 import ( Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link, OpticalConfig, OpticalConfigId OpticalConfig, OpticalConfigId, ConfigActionEnum ) from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceServicer Loading @@ -37,7 +37,7 @@ from .Tools import ( check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules, deconfigure_rules, get_device_controller_uuid, populate_config_rules, populate_endpoint_monitoring_resources, populate_endpoints, populate_initial_config_rules, subscribe_kpi, unsubscribe_kpi, update_endpoints subscribe_kpi, unsubscribe_kpi, update_endpoints, _raw_config_rules_to_grpc ) LOGGER = logging.getLogger(__name__) Loading Loading @@ -441,3 +441,61 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): ) return SSEMonitoringSubscriptionResponse() @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def UpdateDeviceInventory(self, request : DeviceId, context : grpc.ServicerContext) -> Empty: device_uuid = request.device_uuid.uuid self.mutex_queues.wait_my_turn(device_uuid) try: context_client = ContextClient() device = get_device(context_client, device_uuid, rw_copy=True) if device is None: raise NotFoundException('Device', device_uuid) driver : _Driver = get_driver(self.driver_instance_cache, device) if driver is None: msg = ERROR_MISSING_DRIVER.format(device_uuid=str(device_uuid)) raise OperationFailedException('UpdateDeviceInventory', extra_details=msg) # Clear and populate endpoints again from the driver del device.device_endpoints[:] new_sub_devices = dict() new_sub_links = dict() sorted_sub_device_uuids = list() new_optical_configs = dict() errors = populate_endpoints( device, driver, self.monitoring_loops, new_sub_devices, sorted_sub_device_uuids, new_sub_links, new_optical_configs ) if len(errors) > 0: raise OperationFailedException('UpdateDeviceInventory', extra_details=errors) from device.service.driver_api._Driver import RESOURCE_INVENTORY results_getconfig = driver.GetConfig([RESOURCE_INVENTORY]) # Filter out existing /inventory rules to prevent duplicates or leftovers new_rules = [] for rule in device.device_config.config_rules: if rule.WhichOneof('config_rule') == 'custom': if '/inventory' in rule.custom.resource_key: continue new_rules.append(rule) del device.device_config.config_rules[:] device.device_config.config_rules.extend(new_rules) # Convert new inventory rules and update device config errors = _raw_config_rules_to_grpc( device_uuid, device.device_config, 'Error getting inventory resource {resource_key} on device {device_uuid}: {error}', ConfigActionEnum.CONFIGACTION_SET, results_getconfig ) if len(errors) > 0: raise OperationFailedException('UpdateDeviceInventory', extra_details=errors) context_client.SetDevice(device) context_client.close() return Empty() except Exception as e: LOGGER.exception('Error updating inventory of device {:s}'.format(str(device_uuid))) raise e
src/webui/service/device/routes.py +14 −1 Original line number Diff line number Diff line Loading @@ -181,6 +181,19 @@ def detail(device_uuid: str): return render_template( 'device/detail.html', device=device_obj, dde=DeviceDriverEnum, dose=DeviceOperationalStatusEnum) @device.route('detail/<path:device_uuid>/update_inventory', methods=['GET', 'POST']) def update_inventory(device_uuid: str): try: device_id = DeviceId() device_id.device_uuid.uuid = device_uuid device_client.connect() device_client.UpdateDeviceInventory(device_id) device_client.close() flash(f'Inventory of device "{device_uuid}" was successfully updated.', 'success') except Exception as e: flash(f'Problem updating inventory of device "{device_uuid}": {str(e)}', 'danger') return redirect(url_for('device.detail', device_uuid=device_uuid)) @device.route('inventory/<path:device_uuid>', methods=['GET', 'POST']) def inventory(device_uuid: str): context_client.connect() Loading