diff --git a/c8ylp/cli/connect/ssh.py b/c8ylp/cli/connect/ssh.py index 07739b58..2447a875 100644 --- a/c8ylp/cli/connect/ssh.py +++ b/c8ylp/cli/connect/ssh.py @@ -55,7 +55,7 @@ def cli(ctx: click.Context, ssh_user: str, additional_args: List[str], **kwargs) from being interpreted by c8ylp (i.e. to avoid clashes with c8ylp). \b - DEVICE is the device's external identity + DEVICE is the device's external identity or managed object id Example 1: Start an interactive SSH connection diff --git a/c8ylp/cli/core.py b/c8ylp/cli/core.py index cfa40cd1..e18018d4 100644 --- a/c8ylp/cli/core.py +++ b/c8ylp/cli/core.py @@ -611,7 +611,27 @@ def pre_start_checks( try: client = create_client(ctx, opts) - mor = client.get_managed_object(opts.device, opts.external_type) + + mor = None + + if is_id_like(opts.device): + try: + opts.show_info("Checking if given value is a managed object id") + mor = client.get_managed_object_by_id(opts.device) + opts.show_info("Found device via managed object id") + except Exception as ex: + # info message as the external lookup will also be tried + # in case if the external id just looks like an managed object id + opts.show_info( + f"Given device value is not a managed object id. reason={ex}" + ) + + # Lookup mo if not already set (e.g. any previous attempts failed) + if not mor: + mor = client.get_managed_object_by_external_id( + opts.device, opts.external_type + ) + config_id = get_config_id(ctx, mor, opts.config) device_id = mor.get("id") @@ -778,3 +798,8 @@ def start_proxy( ctx.exit(exit_code) else: opts.show_info("Exiting") + + +def is_id_like(value: str) -> bool: + """Check if a value is likely to be an internal id""" + return value.isnumeric() diff --git a/c8ylp/cli/server.py b/c8ylp/cli/server.py index 97462777..748b5a02 100644 --- a/c8ylp/cli/server.py +++ b/c8ylp/cli/server.py @@ -34,7 +34,7 @@ def server( """Start local proxy in server mode \b - DEVICE is the device's external identity + DEVICE is the device's external identity or managed object id Once the local proxy has started, clients such as ssh and scp can be used to establish a connection to the device. diff --git a/c8ylp/plugins/command.py b/c8ylp/plugins/command.py index 2de53b1c..1a630649 100644 --- a/c8ylp/plugins/command.py +++ b/c8ylp/plugins/command.py @@ -43,7 +43,7 @@ def cli(ctx: click.Context, additional_args: List[str], **kwargs): Start once-off proxy and execute a (local) script/command \b - DEVICE is the device's external identity + DEVICE is the device's external identity or managed object id REMOTE_COMMANDS is the script or command to run after the proxy has been started All additional arguments will be passed to the script/command. Use "--" before diff --git a/c8ylp/rest_client/c8yclient.py b/c8ylp/rest_client/c8yclient.py index 35f29e67..aa4a92ff 100644 --- a/c8ylp/rest_client/c8yclient.py +++ b/c8ylp/rest_client/c8yclient.py @@ -68,6 +68,16 @@ def __init__(self, device: str, host: str) -> None: super().__init__(message) +class CumulocityDeviceIDNotFound(Exception): + """Cumulocity device managed object id not found error""" + + def __init__(self, device: str, host: str) -> None: + message = ( + f"A device with the id '{device}' was not found in Cumulocity host: {host}" + ) + super().__init__(message) + + class BearerAuth(requests.auth.AuthBase): """Bearer/token based authorization""" @@ -341,8 +351,41 @@ def get_external_id( self.logger.error(error) raise error - def get_managed_object( - self, serial_number: str, identity_type: str = "c8y_Serial" + def get_managed_object_by_id(self, mo_id: str): + """Get a managed object by looking it up via its external identity + + Args: + mo_id (str): Managed object id + + Raises: + CumulocityPermissionDeviceError: Error when the user does not have the correct permissions + to access the API or device + CumulocityDeviceIDNotFound: If the managed object id is not found + Exception: Unexpected error + + Returns: + Dict[str, Any]: Device managed object + """ + response = self.session.get(f"/inventory/managedObjects/{mo_id}") + if response.status_code == 200: + return json.loads(response.content.decode("utf-8")) + + error = Exception( + f"Error retrieving device. Status Code {response.status_code}, " + f"device (id)={mo_id}, host={self.url}, user={self.user}" + ) + if response.status_code == 401: + error = CumulocityPermissionDeviceError(self.user, mo_id, self.url) + elif response.status_code == 404: + error = CumulocityDeviceIDNotFound(mo_id, self.url) + + self.logger.error(error) + raise error + + def get_managed_object_by_external_id( + self, + serial_number: str, + identity_type: str = "c8y_Serial", ) -> Dict[str, Any]: """Get a managed object by looking it up via its external identity diff --git a/docs/cli/C8YLP_CONNECT_SSH.md b/docs/cli/C8YLP_CONNECT_SSH.md index 0d81011d..12683994 100644 --- a/docs/cli/C8YLP_CONNECT_SSH.md +++ b/docs/cli/C8YLP_CONNECT_SSH.md @@ -13,7 +13,7 @@ Usage: c8ylp connect ssh [OPTIONS] DEVICE [REMOTE_COMMANDS]... Use "--" before the remote commands to prevent the arguments from being interpreted by c8ylp (i.e. to avoid clashes with c8ylp). - DEVICE is the device's external identity + DEVICE is the device's external identity or managed object id Example 1: Start an interactive SSH connection diff --git a/docs/cli/C8YLP_PLUGIN_COMMAND.md b/docs/cli/C8YLP_PLUGIN_COMMAND.md index 5ab573af..c02170a9 100644 --- a/docs/cli/C8YLP_PLUGIN_COMMAND.md +++ b/docs/cli/C8YLP_PLUGIN_COMMAND.md @@ -6,7 +6,7 @@ Usage: c8ylp plugin command [OPTIONS] DEVICE [REMOTE_COMMANDS]... Start once-off proxy and execute a (local) script/command - DEVICE is the device's external identity + DEVICE is the device's external identity or managed object id REMOTE_COMMANDS is the script or command to run after the proxy has been started All additional arguments will be passed to the script/command. Use "--" diff --git a/docs/cli/C8YLP_SERVER.md b/docs/cli/C8YLP_SERVER.md index 4523d0bf..a1ced534 100644 --- a/docs/cli/C8YLP_SERVER.md +++ b/docs/cli/C8YLP_SERVER.md @@ -6,7 +6,7 @@ Usage: c8ylp server [OPTIONS] DEVICE Start local proxy in server mode - DEVICE is the device's external identity + DEVICE is the device's external identity or managed object id Once the local proxy has started, clients such as ssh and scp can be used to establish a connection to the device.