Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow users to provide device's managed object id instead of the external identity #186

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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