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/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 +49 −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,50 @@ 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, include_endpoints=False, include_components=False, include_config_rules=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) 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 src/webui/service/templates/device/detail.html +6 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,12 @@ Delete device </button> </div> <div class="col-sm-3"> <a id="update_inventory" class="btn btn-info" href="{{ url_for('device.update_inventory', device_uuid=device.device_id.device_uuid.uuid) }}"> <i class="bi bi-arrow-clockwise"></i> Update Inventory </a> </div> </div> <br> 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/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 +49 −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,50 @@ 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, include_endpoints=False, include_components=False, include_config_rules=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) 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
src/webui/service/templates/device/detail.html +6 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,12 @@ Delete device </button> </div> <div class="col-sm-3"> <a id="update_inventory" class="btn btn-info" href="{{ url_for('device.update_inventory', device_uuid=device.device_id.device_uuid.uuid) }}"> <i class="bi bi-arrow-clockwise"></i> Update Inventory </a> </div> </div> <br> Loading