Skip to content

Commit

Permalink
feat: allow users to provide device's managed object id instead of ex…
Browse files Browse the repository at this point in the history
…ternal identity

Allowing user's to provide the managed object id allows better integration with other tooling (e.g. go-c8y-cli).
This allows other tooling to perform custom lookups to retrieve the managed object id and just pass that to c8ylp when it it started.
  • Loading branch information
reubenmiller committed May 7, 2024
1 parent 04ad0d5 commit 27d7dfa
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 9 deletions.
2 changes: 1 addition & 1 deletion c8ylp/cli/connect/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 33 additions & 1 deletion c8ylp/cli/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,34 @@ 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:
logging.info(
"Checking if given value is a managed object id. value=%s",
opts.device,
)
mor = client.get_managed_object_by_id(opts.device)
logging.info(
"Found device via managed object id. value=%s", opts.device
)
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
logging.info(
"Given device value is not a managed object id. value=%s, reason=%s",
opts.device,
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")

Expand Down Expand Up @@ -778,3 +805,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()
2 changes: 1 addition & 1 deletion c8ylp/cli/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion c8ylp/plugins/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
47 changes: 45 additions & 2 deletions c8ylp/rest_client/c8yclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"""

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/cli/C8YLP_CONNECT_SSH.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/cli/C8YLP_PLUGIN_COMMAND.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 "--"
Expand Down
2 changes: 1 addition & 1 deletion docs/cli/C8YLP_SERVER.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 27d7dfa

Please sign in to comment.