Commit 038b7470 authored by Pablo Armingol's avatar Pablo Armingol
Browse files

feat: implement UpdateDeviceInventory functionality across service, client, and web UI layers

parent e9863e69
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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 {
+8 −0
Original line number Diff line number Diff line
@@ -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
+49 −2
Original line number Diff line number Diff line
@@ -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
@@ -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__)
@@ -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

+14 −1
Original line number Diff line number Diff line
@@ -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()
+6 −0
Original line number Diff line number Diff line
@@ -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>