From 00effe6e228c683a545fe70d3f9598bd3a30a105 Mon Sep 17 00:00:00 2001 From: Pallab Pain Date: Sun, 8 Sep 2024 20:34:04 +0530 Subject: [PATCH] docs: adds extensive CLI documentation The CLI has lacked extensive documentation for most part and that leaves its users confused about its usage. This commit attempts to solve that problem by adding some elaborate docstrings to the commands with examples such that the users can figure out things by reading it. --- CONTRIBUTING.md | 49 ++++++++++++ README.md | 92 +++++++--------------- docs/source/_static/logo-dark-mode.png | Bin 6060 -> 0 bytes docs/source/_static/logo-dark-mode.svg | 14 ++++ docs/source/_static/logo-light-mode.png | Bin 5747 -> 0 bytes docs/source/_static/logo-light-mode.svg | 14 ++++ docs/source/_static/riocli-logo-dark.png | Bin 0 -> 4113 bytes docs/source/_static/riocli-logo-light.png | Bin 0 -> 7049 bytes docs/source/conf.py | 6 +- docs/source/index.rst | 34 +++++--- docs/source/managedservice.rst | 10 --- riocli/__init__.py | 2 +- riocli/apply/__init__.py | 91 ++++++++++++++++++--- riocli/apply/explain.py | 19 +++++ riocli/apply/template.py | 18 ++++- riocli/auth/__init__.py | 6 +- riocli/auth/login.py | 49 ++++++++++-- riocli/auth/logout.py | 4 +- riocli/auth/refresh_token.py | 17 ++-- riocli/auth/status.py | 6 +- riocli/auth/token.py | 15 +++- riocli/bootstrap.py | 35 ++++---- riocli/chart/__init__.py | 12 ++- riocli/chart/apply.py | 31 +++++++- riocli/chart/chart.py | 2 +- riocli/chart/delete.py | 30 ++++++- riocli/chart/info.py | 2 +- riocli/chart/list.py | 2 +- riocli/chart/search.py | 2 +- riocli/completion/__init__.py | 2 +- riocli/config/__init__.py | 2 +- riocli/constants/__init__.py | 2 +- riocli/constants/colors.py | 2 +- riocli/constants/symbols.py | 2 +- riocli/deployment/__init__.py | 2 +- riocli/deployment/delete.py | 35 ++++++-- riocli/deployment/execute.py | 27 ++++++- riocli/deployment/inspect.py | 8 +- riocli/deployment/list.py | 17 +++- riocli/deployment/logs.py | 14 +++- riocli/deployment/status.py | 9 ++- riocli/deployment/update.py | 10 +-- riocli/deployment/util.py | 7 +- riocli/deployment/wait.py | 10 ++- riocli/device/config.py | 2 +- riocli/device/create.py | 2 +- riocli/device/delete.py | 32 +++++++- riocli/device/deployment.py | 2 +- riocli/device/execute.py | 16 +++- riocli/device/files.py | 65 +++++++++++++-- riocli/device/inspect.py | 8 +- riocli/device/label.py | 23 ++---- riocli/device/list.py | 6 +- riocli/device/metric.py | 20 ++--- riocli/device/migrate.py | 23 ++++-- riocli/device/onboard.py | 11 ++- riocli/device/tools/__init__.py | 11 ++- riocli/device/tools/device_init.py | 11 ++- riocli/device/tools/forward.py | 6 +- riocli/device/tools/rapyuta_logs.py | 7 +- riocli/device/tools/scp.py | 17 +++- riocli/device/tools/service.py | 19 ++++- riocli/device/tools/ssh.py | 46 ++++++++--- riocli/device/tools/util.py | 2 +- riocli/device/topic.py | 2 +- riocli/device/vpn.py | 25 ++++-- riocli/disk/__init__.py | 7 +- riocli/disk/create.py | 19 +++-- riocli/disk/delete.py | 38 +++++++-- riocli/disk/list.py | 14 +++- riocli/disk/util.py | 2 +- riocli/exceptions/__init__.py | 2 +- riocli/hwil/__init__.py | 7 +- riocli/hwil/create.py | 30 ++++++- riocli/hwil/delete.py | 20 ++++- riocli/hwil/execute.py | 5 +- riocli/hwil/inspect.py | 4 +- riocli/hwil/login.py | 10 ++- riocli/hwil/ssh.py | 9 ++- riocli/jsonschema/validate.py | 2 +- riocli/managedservice/__init__.py | 3 +- riocli/managedservice/delete.py | 2 +- riocli/managedservice/inspect.py | 2 +- riocli/managedservice/list.py | 2 +- riocli/managedservice/list_providers.py | 2 +- riocli/network/__init__.py | 2 +- riocli/network/delete.py | 32 +++++++- riocli/network/inspect.py | 13 +-- riocli/network/list.py | 14 +++- riocli/network/util.py | 2 +- riocli/organization/__init__.py | 13 ++- riocli/organization/inspect.py | 9 ++- riocli/organization/invite_user.py | 16 +++- riocli/organization/list.py | 10 +-- riocli/organization/remove_user.py | 5 +- riocli/organization/select.py | 25 ++++-- riocli/organization/users.py | 6 +- riocli/organization/utils.py | 2 +- riocli/package/__init__.py | 2 +- riocli/package/deployment.py | 2 +- riocli/package/inspect.py | 2 +- riocli/package/list.py | 2 +- riocli/package/model.py | 2 +- riocli/parameter/__init__.py | 13 ++- riocli/parameter/apply.py | 25 +++++- riocli/parameter/delete.py | 8 +- riocli/parameter/diff.py | 7 +- riocli/parameter/download.py | 14 +++- riocli/parameter/list.py | 6 +- riocli/parameter/upload.py | 32 +++++++- riocli/parameter/utils.py | 2 +- riocli/project/create.py | 8 +- riocli/project/delete.py | 10 ++- riocli/project/features/__init__.py | 2 +- riocli/project/inspect.py | 8 +- riocli/project/list.py | 18 ++++- riocli/project/select.py | 8 +- riocli/project/update_owner.py | 8 +- riocli/project/whoami.py | 6 +- riocli/rosbag/__init__.py | 2 +- riocli/secret/__init__.py | 2 +- riocli/secret/delete.py | 2 +- riocli/secret/inspect.py | 2 +- riocli/secret/list.py | 2 +- riocli/shell/__init__.py | 17 ++-- riocli/shell/prompt.py | 2 +- riocli/static_route/__init__.py | 2 +- riocli/static_route/create.py | 11 ++- riocli/static_route/delete.py | 9 ++- riocli/static_route/inspect.py | 8 +- riocli/static_route/list.py | 14 +++- riocli/static_route/open.py | 6 +- riocli/static_route/util.py | 2 +- riocli/usergroup/__init__.py | 15 +++- riocli/usergroup/delete.py | 8 +- riocli/usergroup/inspect.py | 8 +- riocli/usergroup/list.py | 8 +- riocli/usergroup/util.py | 2 +- riocli/utils/__init__.py | 2 +- riocli/utils/context.py | 2 +- riocli/utils/execute.py | 2 +- riocli/utils/spinner.py | 2 +- riocli/utils/ssh_tunnel.py | 2 +- riocli/vpn/__init__.py | 9 ++- riocli/vpn/connect.py | 16 +++- riocli/vpn/disconnect.py | 12 ++- riocli/vpn/machines.py | 24 +++--- riocli/vpn/ping.py | 17 ++-- riocli/vpn/status.py | 16 ++-- 149 files changed, 1303 insertions(+), 504 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 docs/source/_static/logo-dark-mode.png create mode 100644 docs/source/_static/logo-dark-mode.svg delete mode 100644 docs/source/_static/logo-light-mode.png create mode 100644 docs/source/_static/logo-light-mode.svg create mode 100644 docs/source/_static/riocli-logo-dark.png create mode 100644 docs/source/_static/riocli-logo-light.png delete mode 100644 docs/source/managedservice.rst diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..61c48441 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,49 @@ +# Contribution Guidelines +## Setup your development environment + +The project uses [pipenv](https://pipenv.pypa.io/en/latest/) for +development. It needs to be installed to setup the development environment. + +``` bash +pip install pipenv +``` + +Once Pipenv is installed, a Python virtual environment can be quickly +bootstrapped by running the following commands in the root of the repository. + +``` bash +pipenv install --dev +``` + +This will create a virtual environment in the Pipenv's preconfigured location +(if one doesn't already exists). It will also install all the dependencies and +`riocli` package in the location. + +To run the CLI (or any command) under the context of Pipenv's virtual +environment, prepend the commands with `pipenv run` + +```bash +pipenv run rio +``` + +To run the RIO CLI from the source directly, you can use `riocli` module +directly. + +``` bash +pipenv run python -m riocli +``` + +New dependencies can be installed directly using `pipenv`. This modifies the +`Pipfile` and `Pipfile.lock`. + +``` bash +pipenv install {dependency} +``` + +But using the `pipenv` directly doesn't sync the dependencies in the +`setup.py` file. For this, the project uses a utility called `pipenv-setup` +which allows us to sync the dependencies. + +``` bash +pipenv run pipenv-setup sync +``` diff --git a/README.md b/README.md index 631e00cb..4bb699d3 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,61 @@ -# Rapyuta CLI +# rapyuta.io CLI -Rapyuta CLI exposes features of Rapyuta.io platform on the command-line. +The rapyuta.io CLI exposes features of the rapyuta.io cloud platform on the command-line. -The application is written in Python 3 and it is distributed through PyPI for -Python 3 environments. +The application is written in Python 3, and it is distributed through PyPI for Python 3 environments. For Reference on directory structure please refer Please have a look at the corresponding article: http://gehrcke.de/2014/02/distributing-a-python-command-line-application/ -## Install +## Installation -Rio CLI is available on PyPI index and can be installed directly by running the -following command. +### Installing the `AppImage` -``` bash -pip install rapyuta-io-cli +You can install the latest `AppImage` using the following command. + +```bash +curl -fSsL https://cli.rapyuta.io/install.sh | bash ``` +> Note: The `AppImage` is a self-contained executable that can be run on any Linux distribution. +However, it is not supported for non-Linux systems. + +### Installing via `pip` + +```bash +pip install rapyuta-io-cli +``` On Unix-like systems it places the `rio` executable in the user's PATH. On Windows it places the `rio.exe` in the centralized `Scripts` directory which should be in the user's PATH. +### Installing from source + To install the CLI from source, you can use the `setup.py` script directly. Clone the repository and from the root of the directory, run the following command. -``` bash +```bash +git clone git@github.com:rapyuta-robotics/rapyuta-io-cli.git +cd rapyuta-io-cli python setup.py install ``` ## Getting Started -To begin using the CLI, it must be authenticated with the Platform. - -``` bash -rio auth login -``` - -The Email and Password can either be given through flags (for scripting -purposes) or interactively through the Prompts. - -NOTE: Entering password as a Flag is not recommended because it leaves the -Traces. +To begin using the CLI, it must be authenticated with rapyuta.io. -## Development - -Rio CLI project uses [Pipenv](https://pipenv.pypa.io/en/latest/) for -development. It needs to be installed to setup the development environment. - -``` bash -pip install pipenv -``` - -Once Pipenv is installed, a Python virtual environment can be quickly -bootstrapped by running the following commands in the root of the repository. - -``` bash -pipenv install --dev -``` - -This will create a virtual environment in the Pipenv's preconfigured location -(if one doesn't already exists). It will also install all the dependencies and -`riocli` package in the location. - -To run the CLI (or any command) under the context of Pipenv's virtual -environment, prepend the commands with `pipenv run` - ```bash -pipenv run rio -``` - -To run the RIO CLI from the source directly, you can use `riocli` module -directly. - -``` bash -pipenv run python -m riocli +rio auth login ``` -New dependencies can be installed directly using `pipenv`. This modifies the -`Pipfile` and `Pipfile.lock`. +The `email` and `password` can either be given through flags (for scripting purposes) or interactively through the prompt. -``` bash -pipenv install {dependency} -``` +> Note: Entering the password as a flag is not recommended because it leaves the traces. -But using the `pipenv` directly doesn't sync the dependencies in the -`setup.py` file. For this, the project uses a utility called `pipenv-setup` -which allows us to sync the dependencies. +Once set up, run `rio --help` to see the available commands. -``` bash -pipenv run pipenv-setup sync -``` +## References +* [Development Guide](CONTRIBUTING.md) \ No newline at end of file diff --git a/docs/source/_static/logo-dark-mode.png b/docs/source/_static/logo-dark-mode.png deleted file mode 100644 index f34585f1a20654c12f76023539fedaf71907d0db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6060 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 + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_static/logo-light-mode.png b/docs/source/_static/logo-light-mode.png deleted file mode 100644 index 4639835f535abf3dd2563c69aab1c753def3a3b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5747 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 diff --git a/docs/source/_static/logo-light-mode.svg b/docs/source/_static/logo-light-mode.svg new file mode 100644 index 00000000..63bea6ea --- /dev/null +++ b/docs/source/_static/logo-light-mode.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs/source/_static/riocli-logo-dark.png b/docs/source/_static/riocli-logo-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..7a4e41f2d55508ef4b87ca94cdbbf67f12812158 GIT binary patch literal 4113 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
ZVG1%(pe*Q<6rHXp;1P}p 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 literal 0 HcmV?d00001 diff --git a/docs/source/conf.py b/docs/source/conf.py index 32253d15..181a85e4 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -2,7 +2,7 @@ import os import sys -project = u'rapyuta.io CLI' +project = u'CLI' copyright = u'2024, Rapyuta Robotics' author = u'Rapyuta Robotics' @@ -26,8 +26,8 @@ html_favicon = 'favicon.ico' html_static_path = ['_static'] html_theme_options = { - "light_logo": "logo-light-mode.png", - "dark_logo": "logo-dark-mode.png", + "light_logo": "logo-light-mode.svg", + "dark_logo": "logo-dark-mode.svg", } html_css_files = ['css/rio-sphinx.css'] html_js_files = ['js/rio-sphinx.js'] diff --git a/docs/source/index.rst b/docs/source/index.rst index 4bde6f42..0b56bc12 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,7 +1,7 @@ -Welcome to Rapyuta.io CLI documentation! +Welcome to rapyuta.io CLI documentation! ======================================== -Rapyuta CLI exposes features of Rapyuta.io platform on the command-line. +The rapyuta.io CLI (aka riocli) exposes features of Rapyuta.io platform on the command-line. The application is written in Python 3 and it is distributed through PyPI for Python 3 environments. @@ -9,45 +9,58 @@ Python 3 environments. Installation -------------- -It is recommended you install the latest Python SDK using pip +Installing the ``AppImage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can install the latest ``AppImage`` on your Linux systems using the following command. .. code:: bash - pip install rapyuta-io + curl -fSsL https://cli.rapyuta.io/install.sh | bash + +Installing via ``pip`` +~~~~~~~~~~~~~~~~~~~~~~ -Rio CLI is available on PyPI index and can be installed directly by running the -following command. +Alternatively, you can install the CLI using ``pip``. .. code:: bash pip install rapyuta-io-cli + On Unix-like systems it places the ``rio`` executable in the user's PATH. On Windows it places the ``rio.exe`` in the centralized ``Scripts`` directory which should be in the user's PATH. +Installing from source +~~~~~~~~~~~~~~~~~~~~~~~ + To install the CLI from source, you can use the ``setup.py`` script directly. Clone the repository and from the root of the directory, run the following command. .. code:: bash + git clone git@github.com:rapyuta-robotics/rapyuta-io-cli.git + cd rapyuta-io-cli python setup.py install + Getting Started --------------- -To begin using the CLI, it must be authenticated with the Platform. +To begin using the CLI, it must be authenticated with rapyuta.io. .. code:: bash rio auth login -The Email and Password can either be given through flags (for scripting +The ``email`` and ``password`` can either be given through flags (for scripting purposes) or interactively through the Prompts. -NOTE: Entering password as a Flag is not recommended because it leaves the -Traces. +.. note:: + + Entering ``password`` as a flag is not recommended because it leaves the traces. Commands -------- @@ -66,7 +79,6 @@ Rapyuta CLI has commands for all rapyuta.io resources. You can read more about t Device Disk Hardware-in-Loop - ManagedService Network Organization Package diff --git a/docs/source/managedservice.rst b/docs/source/managedservice.rst deleted file mode 100644 index 47571069..00000000 --- a/docs/source/managedservice.rst +++ /dev/null @@ -1,10 +0,0 @@ -Managed Service -=============== - -.. toctree:: - :maxdepth: 3 - :caption: Contents: - -.. click:: riocli.managedservice:managedservice - :prog: rio managedservice - :nested: full diff --git a/riocli/__init__.py b/riocli/__init__.py index ecff8f22..dd6b3e1a 100644 --- a/riocli/__init__.py +++ b/riocli/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/apply/__init__.py b/riocli/apply/__init__.py index 86401a92..7a202ca7 100644 --- a/riocli/apply/__init__.py +++ b/riocli/apply/__init__.py @@ -32,19 +32,19 @@ help_options_color=Colors.GREEN, ) @click.option('--dryrun', '-d', is_flag=True, default=False, - help='dry run the yaml files without applying any change') + help='Dry run the yaml files without applying any change') @click.option('--show-graph', '-g', is_flag=True, default=False, help='Opens a mermaid.live dependency graph') @click.option('--values', '-v', - help="path to values yaml file. key/values " + help="Path to values yaml file. Key/values " "specified in the values file can be " "used as variables in template YAMLs") @click.option('--secrets', '-s', - help="secret files are sops encoded value files. " + help="Secret files are sops encoded value files. " "rio-cli expects sops to be authorized for " "decoding files on this computer") @click.option('--workers', '-w', - help="number of parallel workers while running apply " + help="Number of parallel workers while running apply " "command. defaults to 6.", type=int) @click.option('-f', '--force', '--silent', 'silent', is_flag=True, type=click.BOOL, default=False, @@ -65,8 +65,46 @@ def apply( silent: bool = False, show_graph: bool = False, ) -> None: - """ - Apply resource manifests + """Apply resource manifests. + + The apply command provides the mechanism to create or update + resources on rapyuta.io defined in YAML manifests making the + process declarative and repeatable. The command can take multiple + files, paths or globs as arguments and parse the manifests to + create or update resources. It also supports Jinja templating + and secret management with sops. + + You can provide a values file with the ``--values`` option and a + sops encrypted secret file with ``--secret`` option. Currently, the + command supports only one values and secret file. + + You can use the ``--show-graph`` option to visualize the + dependency graph of the resources defined in the manifests. + + The --dryrun option can be used to execute the manifests without + actually creating the resources. This is useful to validate the + manifests before applying them. + + You can specify the number of parallel workers with the ``--workers`` + option. The default value is ``6``. + + The ``--silent``, ``--force`` or ``-f`` option lets you skip the confirmation + prompt before applying the manifests. This is particularly useful + in CI/CD pipelines. + + Usage Examples: + + Apply a single manifest file with secret and values file. + + $ rio apply -v values.yaml -s secrets.yaml manifest.yaml + + Apply manifests from a directory with secret and values file. + + $ rio apply -v values.yaml -s secrets.yaml templates/ + + Apply manifests from a directory without confirmation prompt. + + $ rio apply -f templates/ """ glob_files, abs_values, abs_secrets = process_files_values_secrets( files, values, secrets) @@ -105,7 +143,7 @@ def apply( help_options_color=Colors.GREEN, ) @click.option('--dryrun', '-d', is_flag=True, default=False, - help='dry run the yaml files without applying any change') + help='Dry run the yaml files without applying any change') @click.option('--values', '-v', help="Path to values yaml file. key/values specified in the" " values file can be used as variables in template YAMLs") @@ -116,7 +154,7 @@ def apply( type=click.BOOL, default=False, help="Skip confirmation") @click.option('--workers', '-w', - help="number of parallel workers while running apply " + help="Number of parallel workers while running apply " "command. defaults to 6.", type=int) @click.option('--retry-count', '-rc', type=int, default=50, help="Number of retries before a resource creation times out status, defaults to 50") @@ -133,8 +171,41 @@ def delete( workers: int = 6, silent: bool = False ) -> None: - """ - Removes resources defined in the manifest + """Removes resources via manifests + + The delete command provides the mechanism to remove resources on + rapyuta.io defined in YAML manifests making the process declarative + and repeatable. The command can take multiple files, paths or globs + as arguments and parse the manifests to remove resources. It also + supports Jinja templating and secret management with sops. You can + provide a values file with the --values option and a sops encrypted + secret file with ``--secret`` option. Currently, the command supports + only one values and secret file. + + The ``--dryrun`` option can be used to execute the manifests without + actually deleting the resources. This is useful to validate the + manifests before applying them. + + You can specify the number of parallel workers with the ``--workers`` + option. The default value is ``6``. + + The ``--silent``, ``--force`` or ``-f`` option lets you skip the confirmation + prompt before applying the manifests. This is particularly useful + in CI/CD pipelines. + + Usage Examples: + + Delete a single manifest file with secret and values file. + + $ rio delete -v values.yaml -s secrets.yaml manifest.yaml + + Delete manifests from a directory with secret and values file. + + $ rio delete -v values.yaml -s secrets.yaml templates/ + + Delete manifests from a directory without confirmation prompt. + + $ rio delete -f templates/ """ glob_files, abs_values, abs_secrets = process_files_values_secrets( files, values, secrets) diff --git a/riocli/apply/explain.py b/riocli/apply/explain.py index 90f04e8f..af909559 100644 --- a/riocli/apply/explain.py +++ b/riocli/apply/explain.py @@ -29,6 +29,7 @@ help='List all examples supported in rio explain command' ) def list_examples() -> None: + """List all examples supported in rio explain command.""" path = Path(__file__).parent.joinpath('manifests') examples = [] @@ -49,6 +50,24 @@ def list_examples() -> None: default=None) @click.argument('resource') def explain(resource: str, templates: str = None) -> None: + """Explain a resource manifest for the given type. + + The explain command can be used to generate a sample + resource manifest using the examples that are shown + in the output. This is particularly useful to understand + the structure of the manifest and the fields that are + required for the resource. + + Usage Examples: + + View examples for deployment + + $ rio explain deployment + + View examples for usergroup + + $ rio explain usergroup + """ if templates: path = Path(templates) else: diff --git a/riocli/apply/template.py b/riocli/apply/template.py index 417c45ad..062bcae6 100644 --- a/riocli/apply/template.py +++ b/riocli/apply/template.py @@ -36,8 +36,22 @@ 'expects sops to be authorized for decoding files on this computer') @click.argument('files', nargs=-1) def template(values: str, secrets: str, files: Iterable[str]) -> None: - """ - Print manifests with filled values + """Print manifests with values and secrets applied + + The template command can be used to preview the manifests + with values and secrets applied. This is particularly useful + to check if the values and secrets are correctly substituted + in the manifests before applying them. + + Just like the apply command, the template command also accepts + a list of files as arguments. You can specify one or more files, + directories or glob pattern. + + However, it will only accept on values and secrets file as input. + + Usage Examples: + + rio template manifests/*.yaml -v values.yaml -s secrets.yaml """ glob_files, abs_values, abs_secrets = process_files_values_secrets( files, values, secrets) diff --git a/riocli/auth/__init__.py b/riocli/auth/__init__.py index 7211d180..ecaf03e0 100644 --- a/riocli/auth/__init__.py +++ b/riocli/auth/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,9 +32,7 @@ help_options_color=Colors.GREEN, ) def auth(): - """ - Account and Login on Rapyuta.io - """ + """Login and token management""" pass diff --git a/riocli/auth/login.py b/riocli/auth/login.py index 892c9924..c2bdc539 100644 --- a/riocli/auth/login.py +++ b/riocli/auth/login.py @@ -57,12 +57,51 @@ def login( interactive: bool, auth_token: str, ) -> None: - """ - Log into your rapyuta.io account using the CLI. This is required to - use most commands of the CLI. + """Log into your rapyuta.io account. + + This is the first step to start using the CLI. - You can log in with your email and password or just with and auth token - if you already have one. + You can log in with your email and password or + just with and auth token if you already have one. + The command works in an interactive mode by default + and will prompt you to enter your credentials and + select the organization and project you want to work + with. + + You can also use the command in non-interactive mode + by providing the email and password as arguments and + setting the --no-interactive or --silent flag. In this + mode, you can also set the organization and project + using the --organization and --project flags. If you + do not provide the organization and project, you will + have to set them later using the `rio organization select` + and `rio project select` commands. + + Note: If you have special characters in your password, then + consider putting them in quotes to avoid the terminal from + interpreting them otherwise. + + Usage Examples: + + Login interactively + + $ rio auth login + + Login interactively with email and password + + $ rio auth login --email YOUR_EMAIL --password YOUR_PASSWORD + + Login non-interactively with email and password + + $ rio auth login --email YOUR_EMAIL --password YOUR_PASSWORD --no-interactive + + Login non-interactively with email, password, organization and project + + $ rio auth login --email YOUR_EMAIL --password YOUR_PASSWORD --organization YOUR_ORG --project YOUR_PROJECT --silent + + Login with auth token + + $ rio auth login --auth-token YOUR_AUTH_TOKEN """ ctx = get_root_context(ctx) diff --git a/riocli/auth/logout.py b/riocli/auth/logout.py index 548a593e..998dd697 100644 --- a/riocli/auth/logout.py +++ b/riocli/auth/logout.py @@ -25,9 +25,7 @@ ) @click.pass_context def logout(ctx: click.Context): - """ - Log out from the Rapyuta.io account using the CLI. - """ + """Log out from your rapyuta.io account.""" if not ctx.obj.exists: return diff --git a/riocli/auth/refresh_token.py b/riocli/auth/refresh_token.py index 86c968d9..260682fd 100644 --- a/riocli/auth/refresh_token.py +++ b/riocli/auth/refresh_token.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -27,17 +27,15 @@ help_options_color=Colors.GREEN, ) @click.pass_context -@click.option( - '--password', - type=str, - help='Password for the rapyuta.io account', -) +@click.option('--password', type=str, help='Password for the rapyuta.io account') @click.option('--interactive/--no-interactive', '--interactive/--silent', is_flag=True, type=bool, default=True, help='Make login interactive') def refresh_token(ctx: click.Context, password: str, interactive: bool): - """ - Refreshes the authentication token after it expires + """Refreshes the authentication token. + + If the stores auth token has expired, this command will prompt the + user to enter the password to refresh the token. """ config = get_config_from_context(ctx) email = config.data.get('email_id', None) @@ -55,7 +53,8 @@ def refresh_token(ctx: click.Context, password: str, interactive: bool): refreshed = api_refresh_token(existing_token) if not refreshed: if not interactive and password is None: - click.secho('existing token expired, re-run rio auth refresh-token in interactive mode or pass the password using the flag') + click.secho('The existing token has expired, re-run rio auth refresh-token ' + 'in interactive mode or pass the password using the flag.') raise SystemExit(1) password = password or click.prompt('Password', hide_input=True) diff --git a/riocli/auth/status.py b/riocli/auth/status.py index 7844be4e..5d404a55 100644 --- a/riocli/auth/status.py +++ b/riocli/auth/status.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,9 +25,7 @@ ) @click.pass_context def status(ctx: click.Context): - """ - Shows the login status of the CLI - """ + """Shows the current login status.""" if not ctx.obj.exists: click.secho('🔒You are logged out', fg=Colors.YELLOW) raise SystemExit(1) diff --git a/riocli/auth/token.py b/riocli/auth/token.py index 30d0356c..def9fe65 100644 --- a/riocli/auth/token.py +++ b/riocli/auth/token.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,8 +32,17 @@ @click.option("--level", default=0, help="Level of the token. 0 = low, 1 = med, 2 = high") def token(email: str, password: str, level: int = 0): - """ - Generates a fresh rapyuta.io auth token + """Generates a new rapyuta.io auth token. + + There may be times when you just need a new auth token. + This command will generate a new token for you based on + the level you specify. The default level is 0. You will + have to specify a valid email and password. + + The token levels are as follows: + 0 = low, 24 hours + 1 = medium, 7 days + 2 = high, 30 days """ config = Configuration() diff --git a/riocli/bootstrap.py b/riocli/bootstrap.py index 371c280c..e9a8a5c6 100644 --- a/riocli/bootstrap.py +++ b/riocli/bootstrap.py @@ -24,7 +24,7 @@ from click_plugins import with_plugins from pkg_resources import iter_entry_points -from riocli.apply import apply, explain, delete, template, list_examples +from riocli.apply import apply, delete, explain, list_examples, template from riocli.auth import auth from riocli.chart import chart from riocli.completion import completion @@ -44,15 +44,10 @@ from riocli.project import project from riocli.rosbag import rosbag from riocli.secret import secret -from riocli.shell import shell, deprecated_repl +from riocli.shell import deprecated_repl, shell from riocli.static_route import static_route from riocli.usergroup import usergroup -from riocli.utils import ( - check_for_updates, - pip_install_cli, - is_pip_installation, - update_appimage, -) +from riocli.utils import (check_for_updates, is_pip_installation, pip_install_cli, update_appimage) from riocli.vpn import vpn @@ -65,6 +60,7 @@ ) @click.pass_context def cli(ctx: Context, config: str = None): + """Manage rapyuta.io features on the command-line""" ctx.obj = Configuration(filepath=config) @@ -78,22 +74,18 @@ def safe_cli(): else: cli() + @cli.command("help") @click.pass_context def cli_help(ctx): - """ - Prints the help message - """ + """Print the help message.""" click.echo(cli.get_help(ctx)) @cli.command() def version(): - """ - Version of the CLI/SDK - """ - click.echo("rio {} / SDK {}".format(__version__, rapyuta_io.__version__)) - return + """View installed CLI and SDK versions.""" + click.echo(f'rio {__version__} / SDK {rapyuta_io.__version__}') @cli.command('update') @@ -101,8 +93,15 @@ def version(): type=click.BOOL, default=False, help="Skip confirmation") def update(silent: bool) -> None: - """ - Update the CLI to the latest version + """Update the CLI to the latest version. + + You can update your existing installation of the CLI to + its latest version. Based on the installation method, i.e. + pip or AppImage, the command will update the right + installation. + + You can skip the confirmation prompt by using the --silent or + --force or -f flag. """ available, latest = check_for_updates(__version__) if not available: diff --git a/riocli/chart/__init__.py b/riocli/chart/__init__.py index 72e93fd8..0aa658cf 100644 --- a/riocli/chart/__init__.py +++ b/riocli/chart/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,9 +29,13 @@ help_options_color=Colors.GREEN, ) def chart() -> None: - """ - Rapyuta Charts is a way to package the complete Application for - Rapyuta.io Platform. + """Rapyuta chart is a way to package applications. + + With rapyuta chart, you can create, install, and manage applications + that are a collection of one or more deployments and other resources. + A chart comprises a collection of manifest files that define the + resources to be created. It may also offer customization by means of + values or secrets. """ pass diff --git a/riocli/chart/apply.py b/riocli/chart/apply.py index bf83dbed..c16d4585 100644 --- a/riocli/chart/apply.py +++ b/riocli/chart/apply.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -56,7 +56,34 @@ def apply_chart( retry_count: int = 50, retry_interval: int = 6, silent: bool = False) -> None: - """Install a chart from the rapyuta-charts repository.""" + """Install a chart from the rapyuta-charts repository. + + This command is based on the ``rio apply`` command. However, + the manifests are pulled from rapyuta-charts repository on + GitHub. A rapyuta chart is collection of manifest files with + default values. + + The chart can be customized by providing custom values and + secrets files using the ``--values`` and ``--secrets`` flags respectively. + + The ``--workers`` flag can be used to specify the number of parallel + workers while running the apply command. The default value is 6. + + The ``--dryrun`` flag can be used to test the installation process + without actually installing the chart. + + Repository: https://github.com/rapyuta-robotics/rapyuta-charts + + Usage Examples: + + Apply a chart with values and secrets files + + $ rio chart apply ioconfig-syncer -v values.yaml -s secrets.yaml + + Apply a chart with values and secrets files without confirmation + + $ rio chart apply ioconfig-syncer -v values.yaml -s secrets.yaml -f + """ versions = find_chart(chart) if len(versions) > 1: click.secho( diff --git a/riocli/chart/chart.py b/riocli/chart/chart.py index 6418a680..16f63f9d 100644 --- a/riocli/chart/chart.py +++ b/riocli/chart/chart.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/chart/delete.py b/riocli/chart/delete.py index c3ba804f..bff8a0a5 100644 --- a/riocli/chart/delete.py +++ b/riocli/chart/delete.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -44,7 +44,33 @@ def delete_chart( secrets: str, dryrun: bool = False, silent: bool = False) -> None: - """Uninstall a chart.""" + """Delete a chart. + + The delete command is based on the `rio delete` command + and is used to delete a chart that you have installed + using the `rio chart apply` command. The manifest files + are pulled from the rapyuta-charts repository. The command + accepts custom values and secrets files that you may have + used while installing the chart. + + You can skip confirmation by using the `--silent` or `--force` + or the `-f` flag. + + The `--dryrun` flag can be used to test the deletion process + without actually deleting the chart. + + Repository: https://github.com/rapyuta-robotics/rapyuta-charts + + Usage Examples: + + Delete a chart + + $ rio chart delete postgres + + Delete a chart without confirmation + + $ rio chart delete postgres --silent + """ versions = find_chart(chart) if len(versions) > 1: click.secho('More than one charts are available, ' diff --git a/riocli/chart/info.py b/riocli/chart/info.py index 492a8c55..cc9bda71 100644 --- a/riocli/chart/info.py +++ b/riocli/chart/info.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/chart/list.py b/riocli/chart/list.py index 1f55a910..c4339440 100644 --- a/riocli/chart/list.py +++ b/riocli/chart/list.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/chart/search.py b/riocli/chart/search.py index d8d747f9..0e85d19f 100644 --- a/riocli/chart/search.py +++ b/riocli/chart/search.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/completion/__init__.py b/riocli/completion/__init__.py index ef451a46..56c693ed 100644 --- a/riocli/completion/__init__.py +++ b/riocli/completion/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/config/__init__.py b/riocli/config/__init__.py index c3da6ee6..7b407d72 100644 --- a/riocli/config/__init__.py +++ b/riocli/config/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/constants/__init__.py b/riocli/constants/__init__.py index 31975eff..f10bda61 100644 --- a/riocli/constants/__init__.py +++ b/riocli/constants/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/constants/colors.py b/riocli/constants/colors.py index e2be344e..1b35d4ba 100644 --- a/riocli/constants/colors.py +++ b/riocli/constants/colors.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/constants/symbols.py b/riocli/constants/symbols.py index 3bc16ed5..cda687e0 100644 --- a/riocli/constants/symbols.py +++ b/riocli/constants/symbols.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/deployment/__init__.py b/riocli/deployment/__init__.py index 246fbe06..0291ba47 100644 --- a/riocli/deployment/__init__.py +++ b/riocli/deployment/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/deployment/delete.py b/riocli/deployment/delete.py index 06d95948..224989bc 100644 --- a/riocli/deployment/delete.py +++ b/riocli/deployment/delete.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,8 +20,7 @@ from riocli.config import new_v2_client from riocli.constants import Colors, Symbols from riocli.deployment.model import Deployment -from riocli.deployment.util import fetch_deployments -from riocli.deployment.util import print_deployments_for_confirmation +from riocli.deployment.util import fetch_deployments, print_deployments_for_confirmation from riocli.utils import tabulate_data from riocli.utils.execute import apply_func_with_result from riocli.utils.spinner import with_spinner @@ -50,8 +49,34 @@ def delete_deployment( workers: int = 10, spinner=None, ) -> None: - """ - Deletes one or more deployments given a name or a pattern + """Delete one or more deployments with a name or a regex pattern. + + You can specify a deployment name or a regex pattern to delete one + or more deployment. + + If you want to delete all the deployments, then + simply use the ``--all`` flag. + + If you want to delete deployments without confirmation, then use the + ``--force`` or ``--silent`` or ``-f`` + + Usage Examples: + + Delete a deployment by name + + $ rio deployment delete DEPLOYMENT_NAME + + Delete a deployment without confirmation + + $ rio deployment delete DEPLOYMENT_NAME --force + + Delete all deployments in the project + + $ rio deployment delete --all + + Delete deployments using regex pattern + + $ rio deployment delete "DEPLOYMENT.*" """ client = new_v2_client() if not (deployment_name_or_regex or delete_all): diff --git a/riocli/deployment/execute.py b/riocli/deployment/execute.py index 32d6aeb2..d1556720 100644 --- a/riocli/deployment/execute.py +++ b/riocli/deployment/execute.py @@ -47,8 +47,31 @@ def execute_command( deployment_name: str, command: typing.List[str] ) -> None: - """ - Execute commands on a device deployment + """Execute a command on a device deployment + + You can execute a command on a deployment running on a device. + In case there are more than one executable in the deployment, + you can specify the executable name using the ``--exec`` option. + If you do not specify the executable name, you will be prompted + to select one from the list of executables. If the deployment + only has one executable, it will be selected automatically. + + You can specify the shell using the ``--shell`` option. The default + shell is ``/bin/bash``. You can also specify the user using the ``--user`` + option. The default user is ``root``. + + Please ensure that you enclose the command in quotes to avoid + any issues with the command parsing. + + Usage Examples: + + Execute a command on a device deployment with one executable + + $ rio deployment execute DEPLOYMENT_NAME 'ls -l' + + Execute a command on a device deployment with multiple executables + + $ rio deployment execute DEPLOYMENT_NAME --exec EXECUTABLE_NAME 'ls -l' """ try: client = new_v2_client() diff --git a/riocli/deployment/inspect.py b/riocli/deployment/inspect.py index f65751a7..86dedea8 100644 --- a/riocli/deployment/inspect.py +++ b/riocli/deployment/inspect.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -37,8 +37,10 @@ def inspect_deployment( format_type: str, deployment_name: str, ) -> None: - """ - Inspect the deployment resource + """Inspect the deployment resource + + Prints the deployment resource in the specified format. + The supported formats are ``json`` and ``yaml``. Default is ``yaml``. """ try: client = new_v2_client() diff --git a/riocli/deployment/list.py b/riocli/deployment/list.py index e9b087dc..f49c7dec 100644 --- a/riocli/deployment/list.py +++ b/riocli/deployment/list.py @@ -60,8 +60,21 @@ def list_deployments( labels: typing.List[str], wide: bool = False, ) -> None: - """ - List the deployments in the selected project + """List the deployments in the current project + + You can filter the deployments by phase and labels. + + The -w or --wide flag prints more details about the deployments. + + Usage Examples: + + Filter by phase + + $ rio deployment list --phase InProgress --phase Stopped + + Filter by labels + + $ rio deployment list --label key1=value1 --label key2=value2 """ query = { 'phases': phase, diff --git a/riocli/deployment/logs.py b/riocli/deployment/logs.py index 480113c6..8044b215 100644 --- a/riocli/deployment/logs.py +++ b/riocli/deployment/logs.py @@ -35,8 +35,18 @@ def deployment_logs( exec_name: str, deployment_name: str, ) -> None: - """ - Stream live logs from cloud deployments (not supported for device deployments) + """Stream live logs from cloud deployments. + + You can stream logs from a deployment running on the cloud. + In case there are more than one executable in the deployment, + you can specify the executable name using the --exec option. + + If there are multiple replicas of the deployment, you can specify + the replica number using the --replica option. The default replica + number is 0. + + Note: The logs are streamed in real-time. Press Ctrl+C to stop the + log streaming. Also, device deployments do not support log streaming. """ try: # TODO(pallab): when no exec name is given, implement the logic to set default or prompt a selection. diff --git a/riocli/deployment/status.py b/riocli/deployment/status.py index 6c248521..2261b084 100644 --- a/riocli/deployment/status.py +++ b/riocli/deployment/status.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -26,8 +26,11 @@ ) @click.argument('deployment-name', type=str) def status(deployment_name: str) -> None: - """ - Current status of the deployment + """Print the current status of a deployment. + + The command simply prints the current status of the deployment. + This is useful in scripts and automation where you need to check + the status of a deployment. """ try: client = new_v2_client() diff --git a/riocli/deployment/update.py b/riocli/deployment/update.py index 049ffc1f..16c6d6b7 100644 --- a/riocli/deployment/update.py +++ b/riocli/deployment/update.py @@ -53,7 +53,7 @@ def update_deployment( update_all: bool = False, spinner: Yaspin = None, ) -> None: - """Updates one or more deployments""" + """Use the restart command instead""" _update(force, workers, deployment_name_or_regex, update_all, spinner) @@ -81,19 +81,19 @@ def restart_deployment( ) -> None: """Restarts one or more deployments by name or regex. - Examples: + Usage Examples: Restart a specific deployment - >> rio deployment restart amr01 + $ rio deployment restart amr01 Restart all deployments in the project - >> rio deployment restart --all + $ rio deployment restart --all Restart deployments matching a regex. - >> rio deployment restart amr.* + $ rio deployment restart amr.* """ _update(force, workers, deployment_name_or_regex, update_all, spinner) diff --git a/riocli/deployment/util.py b/riocli/deployment/util.py index a45e255f..61079646 100644 --- a/riocli/deployment/util.py +++ b/riocli/deployment/util.py @@ -16,14 +16,12 @@ import typing import click -from rapyuta_io import DeploymentPhaseConstants from rapyuta_io.clients.deployment import Deployment -from riocli.config import new_client, new_v2_client +from riocli.config import new_v2_client from riocli.constants import Colors from riocli.deployment.list import DEFAULT_PHASES from riocli.utils import tabulate_data -from riocli.utils.selector import show_selection from riocli.v2client import Client from riocli.v2client.enums import DeploymentPhaseConstants @@ -77,10 +75,11 @@ def get_deployment_guid(client: Client, name: str) -> str: def get_deployment_name(client: Client, guid: str) -> str: deployments = client.list_deployments(query={'guids': [guid]}) if len(deployments) == 0: - raise DeploymentNotFound + raise Exception('deployment not found') return deployments[0].metadata.name + def fetch_deployments( client: Client, deployment_name_or_regex: str, diff --git a/riocli/deployment/wait.py b/riocli/deployment/wait.py index 92b010f4..f5b6c791 100644 --- a/riocli/deployment/wait.py +++ b/riocli/deployment/wait.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,8 +32,10 @@ def wait_for_deployment( deployment_name: str, spinner=None, ) -> None: - """ - Wait until the deployment succeeds/fails + """Wait until the deployment succeeds/fails + + This command is useful in scripts or automation when you + explicitly want to wait for the deployment to complete. """ try: client = new_v2_client() @@ -55,4 +57,4 @@ def wait_for_deployment( except Exception as e: spinner.text = click.style(str(e), fg=Colors.RED) spinner.red.fail(Symbols.ERROR) - raise SystemExit(1) \ No newline at end of file + raise SystemExit(1) diff --git a/riocli/device/config.py b/riocli/device/config.py index 09d9cf21..7bb95901 100644 --- a/riocli/device/config.py +++ b/riocli/device/config.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/device/create.py b/riocli/device/create.py index 146e8a26..4b2cde38 100644 --- a/riocli/device/create.py +++ b/riocli/device/create.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/device/delete.py b/riocli/device/delete.py index 822aaa35..90f1459b 100644 --- a/riocli/device/delete.py +++ b/riocli/device/delete.py @@ -22,7 +22,7 @@ from yaspin.api import Yaspin from riocli.config import new_client -from riocli.constants import Symbols, Colors +from riocli.constants import Colors, Symbols from riocli.device.util import fetch_devices from riocli.utils import tabulate_data from riocli.utils.execute import apply_func_with_result @@ -50,8 +50,34 @@ def delete_device( delete_all: bool = False, spinner: Yaspin = None, ) -> None: - """ - Deletes one more devices + """Delete one or more devices with a name or a regex pattern. + + You can specify a name or a regex pattern to delete one + or more devices. + + If you want to delete all the device, then + simply use the --all flag. + + If you want to delete devices without confirmation, then + use the --force or --silent or -f + + Usage Examples: + + Delete a device by name + + $ rio device delete DEVICE_NAME + + Delete a device without confirmation + + $ rio device delete DEVICE_NAME --force + + Delete all device in the project + + $ rio device delete --all + + Delete devices using regex pattern + + $ rio device delete "DISK.*" """ client = new_client() if not (device_name_or_regex or delete_all): diff --git a/riocli/device/deployment.py b/riocli/device/deployment.py index 1926a229..53ddffc2 100644 --- a/riocli/device/deployment.py +++ b/riocli/device/deployment.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/device/execute.py b/riocli/device/execute.py index 0d4505a2..4fe3ce15 100644 --- a/riocli/device/execute.py +++ b/riocli/device/execute.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -39,8 +39,18 @@ def execute_command( shell: str, command: typing.List[str] ) -> None: - """ - Execute commands on the Device + """Execute commands on a device. + + You can specify the user and shell to run the command in. + To specify the user, use the --user flag. The default is + root. To specify the shell, use the --shell flag. The default + shell is /bin/bash. + + Make sure you put your command in quotes to avoid any issues. + + Usage Examples: + + $ rio device execute DEVICE_NAME "ls -l" """ try: response = run_on_device( diff --git a/riocli/device/files.py b/riocli/device/files.py index 85d3b8c1..9c9a31e8 100644 --- a/riocli/device/files.py +++ b/riocli/device/files.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,9 +14,8 @@ from datetime import datetime, timedelta import click -from click_help_colors import HelpColorsCommand -from click_help_colors import HelpColorsGroup -from rapyuta_io.clients import LogsUploadRequest, LogUploads, SharedURL +from click_help_colors import HelpColorsCommand, HelpColorsGroup +from rapyuta_io.clients import LogUploads, LogsUploadRequest, SharedURL from riocli.config import new_client from riocli.constants import Colors, Symbols @@ -33,8 +32,10 @@ help_options_color=Colors.RED, ) def device_uploads() -> None: - """ - Uploaded files from the Device + """Manage file uploads from a device. + + Provides a convenient way to upload from a device to the cloud + and later download, share and perform operations on the uploaded files. """ pass @@ -46,6 +47,11 @@ def device_uploads() -> None: @click.argument('device-name', type=str) @name_to_guid def list_uploads(device_name: str, device_guid: str) -> None: + """List all files uploaded from a device. + + Lists all the files uploaded from a device along + with their size and status. + """ try: client = new_client() device = client.get_device(device_id=device_guid) @@ -81,6 +87,34 @@ def create_upload( purge: bool, spinner=None, ) -> None: + """Upload a file from a device to the cloud. + + You can set the maximum upload rate for the upload operation + --max-upload-rate flag. The default rate is 1MB/s. + + If there already exists a file upload with the same name, you + can override it using the --override flag. The default is set + to false. + + Setting the --purge flag will delete the file from the device + once it is uploaded. The default is set to false. This option + is useful when you want to free up space on the device after + uploading the file. + + Usage Examples: + + Upload a file from a device with a max upload rate of 2MB/s + + $ rio device uploads create DEVICE_NAME FILE_NAME FILE_PATH --max-upload-rate 2097152 + + Upload a file from the device and delete it after it uploads + + $ rio device uploads create DEVICE_NAME FILE_NAME FILE_PATH --purge + + Upload a file from the device and override the existing file on the cloud + + $ rio device uploads create DEVICE_NAME FILE_NAME FILE_PATH --override + """ try: client = new_client() device = client.get_device(device_id=device_guid) @@ -116,6 +150,7 @@ def upload_status( file_name: str, request_id: str, ) -> None: + """Check the status of a file upload.""" try: client = new_client() device = client.get_device(device_id=device_guid) @@ -144,6 +179,7 @@ def delete_upload( request_id: str, spinner=None ) -> None: + """Delete an uploaded file.""" try: client = new_client() device = client.get_device(device_id=device_guid) @@ -174,6 +210,7 @@ def download_log( request_id: str, spinner=None ) -> None: + """Download a file from the device.""" try: client = new_client() device = client.get_device(device_id=device_guid) @@ -204,6 +241,7 @@ def cancel_upload( request_id: str, spinner=None ) -> None: + """Cancel an ongoing upload operation.""" try: client = new_client() device = client.get_device(device_id=device_guid) @@ -236,6 +274,21 @@ def shared_url( expiry: int, spinner=None ) -> None: + """Share a URL for an uploaded file. + + The command creates a shared public URL for the file + uploaded from the device. The URl can be used to download + the file later from any location. + + Optionally, you can set an expiry on the URL using the + --expiry flag. The default expiry is 7 days. + + Usage Examples: + + Share a URL for an uploaded file with 10 day expiry + + $ rio device uploads share DEVICE_NAME FILE_NAME --expiry 10 + """ try: client = new_client() device = client.get_device(device_id=device_guid) diff --git a/riocli/device/inspect.py b/riocli/device/inspect.py index 98046767..a37e1557 100644 --- a/riocli/device/inspect.py +++ b/riocli/device/inspect.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,8 +32,10 @@ @click.argument('device-name', type=str) @name_to_guid def inspect_device(format_type: str, device_name: str, device_guid: str) -> None: - """ - Inspect the device resource + """Print the details of a device. + + You can specify the format of the output using the --format flag. + The default format is yaml. You can choose between json and yaml. """ try: client = new_client() diff --git a/riocli/device/label.py b/riocli/device/label.py index 889b4b0e..cbe25936 100644 --- a/riocli/device/label.py +++ b/riocli/device/label.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,8 +32,9 @@ help_options_color=Colors.GREEN, ) def device_labels() -> None: - """ - Device Labels + """Manage device labels. + + Labels a key-value pair that you can attach to a device. """ pass @@ -42,9 +43,7 @@ def device_labels() -> None: @click.argument('device-name', type=str) @name_to_guid def list_labels(device_name: str, device_guid: str) -> None: - """ - List all the labels for the Device - """ + """List all the labels for a device.""" try: client = new_client() device = client.get_device(device_id=device_guid) @@ -61,9 +60,7 @@ def list_labels(device_name: str, device_guid: str) -> None: @click.argument('value', type=str) @name_to_guid def create_label(device_name: str, device_guid: str, key: str, value: str) -> None: - """ - Create a label for the Device - """ + """Create a new label on a device""" try: with spinner(): client = new_client() @@ -81,9 +78,7 @@ def create_label(device_name: str, device_guid: str, key: str, value: str) -> No @click.argument('value', type=str) @name_to_guid def update_label(device_name: str, device_guid: str, key: str, value: str) -> None: - """ - Update the label for the Device - """ + """Update a label on a device""" try: with spinner(): _update_label(device_guid, key, value) @@ -98,9 +93,7 @@ def update_label(device_name: str, device_guid: str, key: str, value: str) -> No @click.argument('key', type=str) @name_to_guid def delete_label(device_name: str, device_guid: str, key: str) -> None: - """ - Delete the label for the Device - """ + """Delete a label on a device.""" try: with spinner(): _delete_label(device_guid, key) diff --git a/riocli/device/list.py b/riocli/device/list.py index 85e62808..bb3ad384 100644 --- a/riocli/device/list.py +++ b/riocli/device/list.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,9 +29,7 @@ help_options_color=Colors.GREEN, ) def list_devices() -> None: - """ - List all the devices in the selected Project - """ + """List all the devices in the current project.""" try: client = new_client() devices = client.get_all_devices() diff --git a/riocli/device/metric.py b/riocli/device/metric.py index aef9978f..3946af22 100644 --- a/riocli/device/metric.py +++ b/riocli/device/metric.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,8 +32,10 @@ help_options_color='green', ) def device_metrics(): - """ - Device Metrics + """Interact with device metrics. + + You can list, subscribe or unsubscribe to metrics for a device + conveniently from the CLI. """ pass @@ -42,9 +44,7 @@ def device_metrics(): @click.argument('device-name', type=str) @name_to_guid def list_metrics(device_name: str, device_guid: str) -> None: - """ - Lists all the available metrics for the Device - """ + """Lists all the available metrics for a device.""" try: client = new_client() device = client.get_device(device_id=device_guid) @@ -60,9 +60,7 @@ def list_metrics(device_name: str, device_guid: str) -> None: @click.argument('metric', type=click.Choice(['cpu', 'memory', 'disk', 'diskio', 'network', 'wireless'])) @name_to_guid def subscribe_metrics(device_name: str, device_guid: str, metric: str) -> None: - """ - Subscribes the metrics to start collecting it - """ + """Subscribe to a metric to start collecting it.""" try: client = new_client() with spinner(): @@ -79,9 +77,7 @@ def subscribe_metrics(device_name: str, device_guid: str, metric: str) -> None: @click.argument('metric', type=click.Choice(['cpu', 'memory', 'disk', 'diskio', 'network', 'wireless'])) @name_to_guid def unsubscribe_metrics(device_name: str, device_guid: str, metric: str) -> None: - """ - Un-subscribes the metrics to stop collecting it - """ + """Unsubscribe a metric to stop collecting it.""" try: client = new_client() with spinner(): diff --git a/riocli/device/migrate.py b/riocli/device/migrate.py index bc09b005..20b28f9c 100644 --- a/riocli/device/migrate.py +++ b/riocli/device/migrate.py @@ -16,10 +16,9 @@ from yaspin.core import Yaspin from riocli.config import new_client +from riocli.constants import Colors, Symbols from riocli.device.util import migrate_device_to_project, name_to_guid from riocli.project.util import name_to_guid as project_name_to_guid - -from riocli.constants import Colors, Symbols from riocli.utils.spinner import with_spinner @@ -45,8 +44,16 @@ def migrate_project(ctx: click.Context, device_name: str, device_guid: str, project_name: str, project_guid: str, enable_vpn: bool, advertise_routes: bool, spinner: Yaspin) -> None: - """ - Migrate the device from current project to the target project. + """Migrate a device from current project to the target project. + + This process may take some time since it involves multiple steps. + + Optionally, you can enable VPN on the device after migration. Use + the --enable-vpn flag to enable VPN on the device. + + If you want to advertise the subnets configured in the project to VPN peers, + use the --advertise-routes flag. This is usually applicable for edge devices + that are configured as subnet routers. """ try: migrate_device_to_project(ctx, device_guid, project_guid) @@ -58,12 +65,14 @@ def migrate_project(ctx: click.Context, device_name: str, device_guid: str, spinner.text = 'Enabling VPN on device...' client = new_client() client.set_project(project_guid) - client.toggle_features(device_id=device_guid, features=[('vpn', True)], - config={'vpn': {'advertise_routes': advertise_routes}}) + client.toggle_features( + device_id=device_guid, + features=[('vpn', True)], + config={'vpn': {'advertise_routes': advertise_routes}}, + ) spinner.write(click.style('{} Enabled VPN on the device.'.format(Symbols.SUCCESS), fg=Colors.GREEN)) except Exception as e: spinner.text = click.style( 'Failed to migrate device: {}'.format(e), Colors.RED) spinner.red.fail(Symbols.ERROR) raise SystemExit(1) from e - diff --git a/riocli/device/onboard.py b/riocli/device/onboard.py index fc1e5383..77adf7e2 100644 --- a/riocli/device/onboard.py +++ b/riocli/device/onboard.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,12 +21,11 @@ @click.argument('device-name', type=str) @name_to_guid def device_onboard(device_name: str, device_guid: str) -> None: - """ - Generates the on-boarding script for the Device - - To onboard the current device, run the following + """Generates the on-boarding script for a device. - exec $(rio device onboard {device-name}) + You are supposed to run the script on the device to onboard it. + Copy the script to the device and run it. The device will be + onboarded to the rapyuta.io in the selected project. """ try: client = new_client() diff --git a/riocli/device/tools/__init__.py b/riocli/device/tools/__init__.py index 67e29e77..cd3e2200 100644 --- a/riocli/device/tools/__init__.py +++ b/riocli/device/tools/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ from riocli.device.tools.device_init import device_init from riocli.device.tools.forward import port_forward from riocli.device.tools.rapyuta_logs import rapyuta_agent_logs -from riocli.device.tools.ssh import ssh_authorize_key, device_ssh +from riocli.device.tools.ssh import device_ssh, ssh_authorize_key from .scp import scp from .service import service @@ -29,6 +29,13 @@ help_options_color='green', ) def tools(): + """Tools for managing devices. + + A collection of commands that provide a way + to conveniently interact with devices and services + running on them. The commands also enable you to + script and automate tasks on devices. + """ pass diff --git a/riocli/device/tools/device_init.py b/riocli/device/tools/device_init.py index dc1dfeef..348fe01e 100644 --- a/riocli/device/tools/device_init.py +++ b/riocli/device/tools/device_init.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import click from riocli.config import Configuration -from riocli.constants import Symbols, Colors +from riocli.constants import Colors, Symbols from riocli.device.util import name_to_guid from riocli.utils import run_bash from riocli.utils.execute import run_on_device @@ -28,8 +28,11 @@ @with_spinner(text="Initializing device...", timer=True) @name_to_guid def device_init(device_name: str, device_guid: str, spinner=None) -> None: - """ - Initialize device for use with device tools. This is required to be executed first before all tools sub-commands. + """Initialize a device for use with device tools. + + This is required to be executed first before all tools sub-commands. + The command will install the necessary tools on the device and locally + on the machine you are running this command on. """ try: _setup_device(device_guid=device_guid, spinner=spinner) diff --git a/riocli/device/tools/forward.py b/riocli/device/tools/forward.py index 712c30aa..bfb98f9b 100644 --- a/riocli/device/tools/forward.py +++ b/riocli/device/tools/forward.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,9 +32,7 @@ @click.argument('local-port', type=int, default=0, required=False) @name_to_guid def port_forward(device_name: str, device_guid: str, remote_port: int, local_port: int) -> None: - """ - Forwards the port on the Device to local machine - """ + """Forwards a port on the device to local machine.""" try: path = random_string(8, 5) if local_port == 0: diff --git a/riocli/device/tools/rapyuta_logs.py b/riocli/device/tools/rapyuta_logs.py index 158940fc..59f1207b 100644 --- a/riocli/device/tools/rapyuta_logs.py +++ b/riocli/device/tools/rapyuta_logs.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,6 +25,11 @@ @click.argument('device-name', type=str) @name_to_guid def rapyuta_agent_logs(device_name: str, device_guid: str) -> None: + """Stream rapyuta agent logs from the device. + + This is useful for debugging issues with the rapyuta + agent running on the device. + """ try: path = random_string(8, 5) local_port = get_free_tcp_port() diff --git a/riocli/device/tools/scp.py b/riocli/device/tools/scp.py index 9ca49a51..5baf0205 100644 --- a/riocli/device/tools/scp.py +++ b/riocli/device/tools/scp.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ from yaspin.api import Yaspin from riocli.config import new_client -from riocli.constants import Symbols, Colors +from riocli.constants import Colors, Symbols from riocli.device.tools.util import copy_from_device, copy_to_device from riocli.device.util import is_remote_path from riocli.utils.spinner import with_spinner @@ -32,8 +32,17 @@ @click.argument('destination', nargs=1) @with_spinner(text='Copying files...') def scp(source: str, destination: str, spinner: Yaspin = None) -> None: - """ - An scp like interface to copy files to and from the device + """SCP like interface to copy files to and from a device. + + Usage Examples: + + Copy a file from local filesystem to the device + + $ rio device tools scp /path/to/local/file :/path/to/remote/file + + Copy a file from the device to the local filesystem + + $ rio device tools scp :/path/to/remote/file /path/to/local/file """ try: client = new_client() diff --git a/riocli/device/tools/service.py b/riocli/device/tools/service.py index 20ad26cb..1bb22801 100644 --- a/riocli/device/tools/service.py +++ b/riocli/device/tools/service.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ @click.argument('device-name', type=str) @name_to_guid def status_all(device_name: str, device_guid: str) -> None: + """Get the status of all services on the device.""" try: remote_service_cmd_list = ['service', '--status-all'] response = run_on_device(device_guid=device_guid, command=remote_service_cmd_list) @@ -31,6 +32,7 @@ def status_all(device_name: str, device_guid: str) -> None: def run_service_cmd(device_guid, service_name, service_cmd=""): + """Run a service command on the device.""" try: remote_service_cmd_list = ['service', service_name, service_cmd] response = run_on_device(device_guid=device_guid, command=remote_service_cmd_list) @@ -45,6 +47,7 @@ def run_service_cmd(device_guid, service_name, service_cmd=""): @click.argument('service-name', nargs=1) @name_to_guid def status(device_name: str, device_guid: str, service_name) -> None: + """Get the status of a service on the device.""" run_service_cmd(device_guid, service_name, 'status') @@ -53,6 +56,7 @@ def status(device_name: str, device_guid: str, service_name) -> None: @click.argument('service-name', nargs=1) @name_to_guid def start(device_name: str, device_guid: str, service_name) -> None: + """Start a service on the device.""" run_service_cmd(device_guid, service_name, 'start') @@ -61,6 +65,7 @@ def start(device_name: str, device_guid: str, service_name) -> None: @click.argument('service-name', nargs=1) @name_to_guid def stop(device_name: str, device_guid: str, service_name) -> None: + """Stop a service on the device.""" run_service_cmd(device_guid, service_name, 'stop') @@ -69,6 +74,7 @@ def stop(device_name: str, device_guid: str, service_name) -> None: @click.argument('service-name', nargs=1) @name_to_guid def reload(device_name: str, device_guid: str, service_name) -> None: + """Reload a service on the device.""" run_service_cmd(device_guid, service_name, 'reload') @@ -77,6 +83,7 @@ def reload(device_name: str, device_guid: str, service_name) -> None: @click.argument('service-name', nargs=1) @name_to_guid def force_reload(device_name: str, device_guid: str, service_name) -> None: + """Force reload a service on the device.""" run_service_cmd(device_guid, service_name, 'force_reload') @@ -85,13 +92,17 @@ def force_reload(device_name: str, device_guid: str, service_name) -> None: @click.argument('service-name', nargs=1) @name_to_guid def restart(device_name: str, device_guid: str, service_name) -> None: + """Restart a service on the device.""" run_service_cmd(device_guid, service_name, 'restart') -@click.group() +@click.group( + hidden=True +) def service(): - """ - System manager commands + """System management commands for services on the device. + + Offers a set of commands to manage services on the device. """ pass diff --git a/riocli/device/tools/ssh.py b/riocli/device/tools/ssh.py index 45e51e52..dd78e1d8 100644 --- a/riocli/device/tools/ssh.py +++ b/riocli/device/tools/ssh.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,11 +17,7 @@ from click_help_colors import HelpColorsCommand from riocli.constants import Colors, Symbols -from riocli.device.tools.util import ( - run_tunnel_on_device, - run_tunnel_on_local, - copy_to_device, -) +from riocli.device.tools.util import (copy_to_device, run_tunnel_on_device, run_tunnel_on_local) from riocli.device.util import name_to_guid from riocli.utils import random_string from riocli.utils.execute import run_on_device @@ -52,12 +48,27 @@ def device_ssh( remote_port: int, x_forward: bool, ) -> None: - """ - SSH to the Device + """SSH into a device. + + Note: Make sure that you have executed the `rio device tools init` + command before trying to SSH. + + You can select the user to SSH into the device with the `--user` flag. + The default user is `root`. + + You can also specify the local port to forward the SSH connection to + using the `--local-port` flag. If not specified, a random port will be + selected. + + You can also specify the remote port on the device on which the SSH server + is listening using the `--remote-port` flag. The default port is 22. + + You can enable X Forwarding over SSH using the `--x-forward` flag. """ extra_args = "" if not x_forward: extra_args = extra_args + " -X " + try: path = random_string(8, 5) if not local_port: @@ -88,8 +99,23 @@ def device_ssh( @name_to_guid def ssh_authorize_key(device_name: str, device_guid: str, user: str, public_key_file: click.Path, spinner=None) -> None: - """ - Authorize Public SSH Key + """Authorize your local machine's public SSH key + + This command will add the public SSH key of your local machine to the + authorized keys of the specified device. This will allow you to SSH into + the device without a password. + + You can specify the user for which the SSH keys are added using the `--user` + flag. The default user is `root`. + + You can also specify the path to the public key file using the `public-key-file` + argument. The default path is `~/.ssh/id_rsa.pub`. + + Usage Examples: + + Authorize the default public key for the root user + + $ rio device tools ssh-authorize DEVICE_NAME """ try: temp_path = "/tmp/{}".format(random_string(8, 5)) diff --git a/riocli/device/tools/util.py b/riocli/device/tools/util.py index 6a1f946b..567db8b1 100644 --- a/riocli/device/tools/util.py +++ b/riocli/device/tools/util.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/device/topic.py b/riocli/device/topic.py index e401424a..3dd3f804 100644 --- a/riocli/device/topic.py +++ b/riocli/device/topic.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/device/vpn.py b/riocli/device/vpn.py index 1dda61fe..5066f037 100644 --- a/riocli/device/vpn.py +++ b/riocli/device/vpn.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -42,10 +42,25 @@ @click.option('--advertise-routes', is_flag=True, type=click.BOOL, default=False, help="Advertise subnets configured in project to VPN peers") -def toggle_vpn(devices: typing.List, enable: bool, - silent: bool = False, advertise_routes: bool = False) -> None: - """ - Enable or disable VPN client on the device +def toggle_vpn( + devices: typing.List, + enable: bool, + silent: bool = False, + advertise_routes: bool = False, +) -> None: + """Enable or disable VPN client on the device. + + Optionally, you can configure the device to advertise a subnet + if the project is configured with a subnet range. Please note + that --advertise-routes is only a flag and does not provide you + an option to specify the subnet range. + + You can specify the devices using their names or UUIDs using the + --devices flag. If you do not specify any devices, the state will + be applied to all online devices in the project. + + If you want to skip the confirmation prompt, use the --silent or + --force or -f flag. Examples: diff --git a/riocli/disk/__init__.py b/riocli/disk/__init__.py index d6c4cedf..9d9c42fa 100644 --- a/riocli/disk/__init__.py +++ b/riocli/disk/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -27,8 +27,9 @@ help_options_color=Colors.GREEN, ) def disk() -> None: - """ - Persistent disks + """Manage cloud disks. + + Create, list, and delete cloud disks. """ pass diff --git a/riocli/disk/create.py b/riocli/disk/create.py index e5197564..1c0cfb11 100644 --- a/riocli/disk/create.py +++ b/riocli/disk/create.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,10 +15,10 @@ from click_help_colors import HelpColorsCommand from yaspin.api import Yaspin -from riocli.constants import Colors, Symbols, Regions +from riocli.config import new_v2_client +from riocli.constants import Colors, Regions, Symbols from riocli.disk.enum import DiskCapacity from riocli.utils.spinner import with_spinner -from riocli.config import new_v2_client SUPPORTED_CAPACITIES = [ DiskCapacity.GiB_4.value, @@ -55,8 +55,17 @@ def create_disk( region: str = 'jp', spinner: Yaspin = None ) -> None: - """ - Creates a new disk + """Creates a new cloud disk. + + You can create a disk with a specific capacity and region. + The command will create a disk and wait until it is ready + to use. + + Usage Examples: + + Create a new 4GB disk in the JP region + + $ rio disk create DISK_NAME --capacity 4 --region jp """ client = new_v2_client() payload = { diff --git a/riocli/disk/delete.py b/riocli/disk/delete.py index 097e87a4..404fc2ae 100644 --- a/riocli/disk/delete.py +++ b/riocli/disk/delete.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,9 +19,9 @@ from yaspin.api import Yaspin from riocli.config import new_v2_client -from riocli.constants import Symbols, Colors +from riocli.constants import Colors, Symbols from riocli.disk.model import Disk -from riocli.disk.util import fetch_disks, display_disk_list +from riocli.disk.util import display_disk_list, fetch_disks from riocli.utils import tabulate_data from riocli.utils.execute import apply_func_with_result from riocli.utils.spinner import with_spinner @@ -37,7 +37,7 @@ @click.option('--force', '-f', is_flag=True, default=False, help='Skip confirmation', type=bool) @click.option('-a', '--all', 'delete_all', is_flag=True, default=False, - help='Deletes all deployments in the project') + help='Deletes all disks in the project') @click.option('--workers', '-w', help="Number of parallel workers while running deleting disks. Defaults to 10", type=int, default=10) @@ -50,8 +50,34 @@ def delete_disk( workers: int = 10, spinner: Yaspin = None ) -> None: - """ - Deletes a disk + """Delete one or more disks with a name or a regex pattern. + + You can specify a name or a regex pattern to delete one + or more disks. + + If you want to delete all the disks, then + simply use the ``--all`` flag. + + If you want to delete disks without confirmation, then use the + ``--force`` or ``--silent`` or ``-f``. + + Usage Examples: + + Delete a disk by name + + $ rio disk delete DISK_NAME + + Delete a disk without confirmation + + $ rio disk delete DISK_NAME --force + + Delete all disks in the project + + $ rio disk delete --all + + Delete disks using regex pattern + + $ rio disk delete "DISK.*" """ client = new_v2_client() diff --git a/riocli/disk/list.py b/riocli/disk/list.py index 20a8892b..3b84776f 100644 --- a/riocli/disk/list.py +++ b/riocli/disk/list.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -28,10 +28,16 @@ help_options_color=Colors.GREEN, ) @click.option('--label', '-l', 'labels', multiple=True, type=click.STRING, - default=(), help='Filter the deployment list by labels') + default=(), help='Filter the disk list by labels') def list_disks(labels: typing.List[str]) -> None: - """ - List the disks in the selected project + """List the disks in the current project. + + Additionally, you can filter the list by labels using the + ``--label`` or ``-l`` flag. + + Usage Examples: + + $ rio disk list -l app=postgres """ try: client = new_v2_client(with_project=True) diff --git a/riocli/disk/util.py b/riocli/disk/util.py index 1c6a7279..824fbd41 100644 --- a/riocli/disk/util.py +++ b/riocli/disk/util.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/exceptions/__init__.py b/riocli/exceptions/__init__.py index fb53854d..b956b5bc 100644 --- a/riocli/exceptions/__init__.py +++ b/riocli/exceptions/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/hwil/__init__.py b/riocli/hwil/__init__.py index ddb2c866..01d57435 100644 --- a/riocli/hwil/__init__.py +++ b/riocli/hwil/__init__.py @@ -32,7 +32,12 @@ help_options_color=Colors.GREEN, ) def hwildevice(): - """Manage Hardware-in-the-Loop (HWIL) devices""" + """Manage Hardware-in-the-Loop (HWIL) devices. + + Hardware-in-the-Loop (HWIL) devices are virtual devices that + can be used to test devices on rapyuta.io. The set of commands + provide a convenient way to manage these devices and access them. + """ pass diff --git a/riocli/hwil/create.py b/riocli/hwil/create.py index 91edf7fa..1e9d30a3 100644 --- a/riocli/hwil/create.py +++ b/riocli/hwil/create.py @@ -45,7 +45,35 @@ def create_device( codename: str, spinner: Yaspin = None, ) -> None: - """Create a new hardware-in-the-loop device.""" + """Create a new hardware-in-the-loop device. + + You can specify the parameters to create the kind of device + you want using the --arch, --os and the --codename flags. + + The --arch defines the architecture of the device, which + can be either amd64 or arm64. + + The --os defines the type of the OS, which can be either + debian or ubuntu. + + The --codename defines the code name of the OS, which can + be either bionic, focal, jammy or bullseye. + + Usage Example: + + Create a new device with the name 'my-device' and the default + + $ rio hwil create my-device + + Create a new device with the name 'my-device' and custom + parameters for example, arm64 architecture, debian OS and + bullseye codename. + + $ rio hwil create my-device --arch arm64 --os debian --codename bullseye + + Note: All combinations of the --arch, --os and --codename flags may not always + work. Please contact io-support for more information. + """ info = click.style(f'{Symbols.INFO} Device configuration = {os}:{codename}:{arch}', fg=Colors.CYAN, bold=True) spinner.write(info) diff --git a/riocli/hwil/delete.py b/riocli/hwil/delete.py index ad967dc0..26806e46 100644 --- a/riocli/hwil/delete.py +++ b/riocli/hwil/delete.py @@ -37,8 +37,26 @@ def delete_device( force: bool, spinner: Yaspin = None, ) -> None: - """Delete one or more devices""" + """Delete one or more devices. + You can specify the device names to delete using the + device names as arguments. If you want to delete multiple + devices, you can specify multiple device names separated + by spaces. + + You can skip confirmation by using the ``--force`` or ``-f`` + or the ``--silent`` flag. + + Usage Examples: + + Delete a single device by name + + $ rio hwil delete my-device + + Delete multiple devices by name + + $ rio hwil delete my-device1 my-device2 my-device3 + """ if not devices: spinner.text = click.style('No device names provided', fg=Colors.RED) spinner.red.fail(Symbols.ERROR) diff --git a/riocli/hwil/execute.py b/riocli/hwil/execute.py index 54edc77a..a02293a1 100644 --- a/riocli/hwil/execute.py +++ b/riocli/hwil/execute.py @@ -31,7 +31,10 @@ @click.argument('command', required=True, type=str) @name_to_id def execute(device_name: str, device_id: str, command: str) -> None: - """Execute a command on a hardware-in-the-loop device.""" + """Execute a command on a hardware-in-the-loop device. + + Ensure that you wrap the command in quotes to avoid any issues. + """ try: code, stdout, stderr = execute_command(new_hwil_client(), device_id, command) sys.stdout.write(stdout) diff --git a/riocli/hwil/inspect.py b/riocli/hwil/inspect.py index a38e536e..3ca188ed 100644 --- a/riocli/hwil/inspect.py +++ b/riocli/hwil/inspect.py @@ -37,9 +37,7 @@ def inspect_device( device_name: str, device_id: str ) -> None: - """ - Inspect the hardware-in-the-loop device. - """ + """Print the details of a hardware-in-the-loop device.""" client = new_hwil_client() try: diff --git a/riocli/hwil/login.py b/riocli/hwil/login.py index e53a1970..130804d1 100644 --- a/riocli/hwil/login.py +++ b/riocli/hwil/login.py @@ -45,7 +45,15 @@ def login( password: str, interactive: bool = True, ) -> None: - """Log in to HWIL.""" + """Authenticate with HWIL API. + + This is mandatory to use the HWIL commands and also + to create virtual devices with the device manifest. + + You can choose to login non-interactively by providing + --username and --password flags or interactively by + not providing any flags. + """ ctx = get_root_context(ctx) if interactive: diff --git a/riocli/hwil/ssh.py b/riocli/hwil/ssh.py index 05cebc42..ffa9cb82 100644 --- a/riocli/hwil/ssh.py +++ b/riocli/hwil/ssh.py @@ -30,7 +30,14 @@ @click.argument('device-name', required=True, type=str) @name_to_id def ssh(device_name: str, device_id: str, spinner=None) -> None: - """SSH into the hardware-in-the-loop device.""" + """SSH into a hardware-in-the-loop device. + + This command acts as a wrapper on top of the ``ssh`` command. + It fetches the static IP address of the device and logs you in + using the username configured for the device at the time of its + creation. You will be prompted for the password which is also + presented to you on the terminal. + """ try: device = new_hwil_client().get_device(device_id) diff --git a/riocli/jsonschema/validate.py b/riocli/jsonschema/validate.py index 2c5f24cf..55fa3bb2 100644 --- a/riocli/jsonschema/validate.py +++ b/riocli/jsonschema/validate.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/managedservice/__init__.py b/riocli/managedservice/__init__.py index f47b74e3..c15cd8a6 100644 --- a/riocli/managedservice/__init__.py +++ b/riocli/managedservice/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ cls=HelpColorsGroup, help_headers_color='yellow', help_options_color='green', + hidden=True, ) def managedservice() -> None: """ diff --git a/riocli/managedservice/delete.py b/riocli/managedservice/delete.py index 7601f187..94cb9383 100644 --- a/riocli/managedservice/delete.py +++ b/riocli/managedservice/delete.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/managedservice/inspect.py b/riocli/managedservice/inspect.py index 2ff7567a..50136a42 100644 --- a/riocli/managedservice/inspect.py +++ b/riocli/managedservice/inspect.py @@ -1,4 +1,4 @@ -# Copyright 2022 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/managedservice/list.py b/riocli/managedservice/list.py index efddcee8..c1a4488f 100644 --- a/riocli/managedservice/list.py +++ b/riocli/managedservice/list.py @@ -1,4 +1,4 @@ -# Copyright 2022 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/managedservice/list_providers.py b/riocli/managedservice/list_providers.py index 92ab3b11..7ea22553 100644 --- a/riocli/managedservice/list_providers.py +++ b/riocli/managedservice/list_providers.py @@ -1,4 +1,4 @@ -# Copyright 2022 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/network/__init__.py b/riocli/network/__init__.py index 865de419..20b55111 100644 --- a/riocli/network/__init__.py +++ b/riocli/network/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/network/delete.py b/riocli/network/delete.py index 88ed4620..858dc6ec 100644 --- a/riocli/network/delete.py +++ b/riocli/network/delete.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -48,8 +48,34 @@ def delete_network( workers: int = 10, spinner: Yaspin = None ) -> None: - """ - Deletes a network + """Delete one or more networks with a name or a regex pattern. + + You can specify a name or a regex pattern to delete one + or more networks. + + If you want to delete all the networks, then + simply use the ``--all`` flag. + + If you want to delete networks without confirmation, then use the + ``--force`` or ``--silent`` or ``-f``. + + Usage Examples: + + Delete a network by name + + $ rio network delete NETWORK_NAME + + Delete a network without confirmation + + $ rio network delete NETWORK_NAME --force + + Delete all networks in the project + + $ rio network delete --all + + Delete networks using regex pattern + + $ rio network delete "NETWORK.*" """ client = new_v2_client() diff --git a/riocli/network/inspect.py b/riocli/network/inspect.py index 95692c84..9209d626 100644 --- a/riocli/network/inspect.py +++ b/riocli/network/inspect.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. import click -from click_help_colors import HelpColorsCommand +from munch import unmunchify +from riocli.config import new_v2_client from riocli.constants import Colors from riocli.utils import inspect_with_format -from riocli.config import new_v2_client -from munch import unmunchify @click.command('inspect') @@ -25,8 +24,10 @@ type=click.Choice(['json', 'yaml'], case_sensitive=False)) @click.argument('network-name') def inspect_network(format_type: str, network_name: str) -> None: - """ - Inspect the network resource + """Print the details of a network. + + You can specify the format of the output using the ``--format`` flag. + The supported formats are ``json`` and ``yaml``. Default is ``yaml``. """ try: client = new_v2_client() diff --git a/riocli/network/list.py b/riocli/network/list.py index 4a312e8f..1ea760ca 100644 --- a/riocli/network/list.py +++ b/riocli/network/list.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -33,8 +33,16 @@ @click.option('--label', '-l', 'labels', multiple=True, type=click.STRING, default=(), help='Filter the deployment list by labels') def list_networks(network: str, labels: typing.List[str]) -> None: - """ - List the networks in the selected project + """List the networks in the current project. + + You can also filter the list by specifying labels using + the ``--label`` or the ``-l`` flag. + + Usage Examples: + + List all networks with label "app=nginx" + + $ rio network list --label app=nginx """ try: client = new_v2_client(with_project=True) diff --git a/riocli/network/util.py b/riocli/network/util.py index 6d64bf93..1a4bfdcf 100644 --- a/riocli/network/util.py +++ b/riocli/network/util.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/organization/__init__.py b/riocli/organization/__init__.py index 398c5338..a85a0b9c 100644 --- a/riocli/organization/__init__.py +++ b/riocli/organization/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -30,8 +30,15 @@ help_options_color=Colors.GREEN, ) def organization() -> None: - """ - Organizations in rapyuta.io + """Interact with organizations. + + In rapyuta.io, an organization is the top-level entity that + contains all the projects and resources. Using the CLI, you + can view and select organizations, it's users, invite users, + and remove users. + + Note that in order to invite or remove users, you need to login + as the organization admin. """ pass diff --git a/riocli/organization/inspect.py b/riocli/organization/inspect.py index 9ad297ff..b072e19d 100644 --- a/riocli/organization/inspect.py +++ b/riocli/organization/inspect.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -38,8 +38,11 @@ def inspect_organization( organization_guid: str, organization_short_id: str, ) -> None: - """ - Inspect an organization + """Inspect an organization. + + Provides an overview of the organization. The output + is not the exact ouptut of the API, but a more human-readable + version of the organization details. """ try: organization = get_organization_details(organization_guid) diff --git a/riocli/organization/invite_user.py b/riocli/organization/invite_user.py index 44925982..23192c66 100644 --- a/riocli/organization/invite_user.py +++ b/riocli/organization/invite_user.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -30,8 +30,18 @@ @click.argument('user-email', type=str) @click.pass_context def invite_user(ctx: click.Context, user_email: str) -> None: - """ - Invite a new user to the current organization + """Invite a new user to the current organization. + + If the user does not have a rapyuta.io account, they will + receive an email with an invitation to join the organization. + If the user already has an account, they will be added to + the organization. + + Usage Examples: + + Add a new user to the organization + + $ rio organization invite-user user@email.com """ ctx = get_root_context(ctx) diff --git a/riocli/organization/list.py b/riocli/organization/list.py index dae57f7a..9a5b4f9d 100644 --- a/riocli/organization/list.py +++ b/riocli/organization/list.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -28,12 +28,10 @@ ) @click.pass_context def list_organizations(ctx: click.Context) -> None: - """ - List all the organizations that you are a part of - - Example: + """List all the organizations for the current user. - rio organization list + You will only see the organizations that you are a + part of. The current organization is highlighted in green. """ try: client = new_client(with_project=False) diff --git a/riocli/organization/remove_user.py b/riocli/organization/remove_user.py index 0160569f..15e81748 100644 --- a/riocli/organization/remove_user.py +++ b/riocli/organization/remove_user.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -30,8 +30,7 @@ @click.argument('user-email', type=str) @click.pass_context def remove_user(ctx: click.Context, user_email: str) -> None: - """ - Remove a user from the current organization + """Remove a user from the current organization """ ctx = get_root_context(ctx) diff --git a/riocli/organization/select.py b/riocli/organization/select.py index f6cb2139..de5b9fd2 100644 --- a/riocli/organization/select.py +++ b/riocli/organization/select.py @@ -42,14 +42,27 @@ def select_organization( organization_short_id: str, interactive: bool, ) -> None: - """ - Sets the current organization to the one provided - in the argument and prompts you to select a new project - in the changed organization + """Set the current organization. + + You can set the current organization using the name + or the guid of the organization. You will be prompted + to select a project if you are running the command in + an interactive mode. + + To simply set the organization without selecting a project, + use the `--no-interactive` or `--silent` flag. + + If your organization name has spaces, use quotes around the name. + + Usage Examples: + + Set the current organization to 'Platform JP Staging' + + $ rio organization select 'Platform JP Staging' - Example: + Set the current organization to 'Platform JP Staging' without selecting a project - rio organization select other-org + $ rio organization select 'Platform JP Staging' --silent """ ctx = get_root_context(ctx) diff --git a/riocli/organization/users.py b/riocli/organization/users.py index 3e7b9ec9..0e4fa006 100644 --- a/riocli/organization/users.py +++ b/riocli/organization/users.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,9 +29,7 @@ ) @click.pass_context def list_users(ctx: click.Context) -> None: - """ - Lists all users in the organization. - """ + """Lists all users in the organization.""" ctx = get_root_context(ctx) current_user_email = ctx.obj.data.get('email_id') diff --git a/riocli/organization/utils.py b/riocli/organization/utils.py index 83b81f62..eee98ff3 100644 --- a/riocli/organization/utils.py +++ b/riocli/organization/utils.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/package/__init__.py b/riocli/package/__init__.py index 3ba2f409..5520b8c6 100644 --- a/riocli/package/__init__.py +++ b/riocli/package/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/package/deployment.py b/riocli/package/deployment.py index 79fa69fd..46790f26 100644 --- a/riocli/package/deployment.py +++ b/riocli/package/deployment.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/package/inspect.py b/riocli/package/inspect.py index ed329240..5fd7f91e 100644 --- a/riocli/package/inspect.py +++ b/riocli/package/inspect.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/package/list.py b/riocli/package/list.py index 6ad8fb0f..1d6b556c 100644 --- a/riocli/package/list.py +++ b/riocli/package/list.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/package/model.py b/riocli/package/model.py index becf3bc3..8c7cb57f 100644 --- a/riocli/package/model.py +++ b/riocli/package/model.py @@ -1,4 +1,4 @@ -# Copyright 2022 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/parameter/__init__.py b/riocli/parameter/__init__.py index b6f3f780..8674d0e1 100644 --- a/riocli/parameter/__init__.py +++ b/riocli/parameter/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -31,8 +31,15 @@ help_options_color=Colors.GREEN, ) def parameter() -> None: - """ - Manage configuration parameters for your devices and deployments + """Configuration parameters for your devices and deployments. + + The configuration parameters are file based configs that are + stored in a directory-like structure. You can upload, download, + and apply these configurations to your devices and deployments. + + The platform ensures the availability of the configurations at + predefined paths on the devices and deployments as well as the + deployments in the cloud. """ pass diff --git a/riocli/parameter/apply.py b/riocli/parameter/apply.py index 452da9b1..292ad308 100644 --- a/riocli/parameter/apply.py +++ b/riocli/parameter/apply.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -54,8 +54,27 @@ def apply_configurations( device_name_pattern: str = None, silent: bool = False, ) -> None: - """ - Apply a set of configurations to a list of devices + """Apply a set of configuration parameter trees to a list of devices. + + You can either specify the device names using the ``--devices`` flag or + use the ``--device-name-pattern`` flag to apply configurations to devices. + + Note that the ``--devices`` flag will be ignored if the ``--device-name-pattern`` + flag is provided. + + You can specify the trees to apply using the ``--tree-names`` flag. + + Skip the confirmation prompt by using the ``--force`` or ``--silent`` or the ``-f`` flag. + + Usage Examples: + + Apply configurations to a list of devices + + $ rio parameter apply --devices device1 --devices device2 --tree-names tree1 + + Apply configurations to devices using a regex pattern + + $ rio parameter apply --device-name-pattern 'amr.*' --tree-names params """ client = new_client() diff --git a/riocli/parameter/delete.py b/riocli/parameter/delete.py index e9bb64bc..2d84ac91 100644 --- a/riocli/parameter/delete.py +++ b/riocli/parameter/delete.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -41,8 +41,10 @@ def delete_configurations( tree: str, silent: bool = False ) -> None: - """ - Deletes the configuration parameter tree. + """Delete a configuration parameter tree. + + You can skip the confirmation prompt by using the ``--force`` or + ``--silent`` or ``-f`` flag. """ click.secho('Configuration Parameter {} will be deleted'.format(tree)) diff --git a/riocli/parameter/diff.py b/riocli/parameter/diff.py index a3b38a4f..9873aa86 100644 --- a/riocli/parameter/diff.py +++ b/riocli/parameter/diff.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -42,8 +42,9 @@ help='Tree names to fetch') @click.argument('path', type=click.Path(exists=True), required=False) def diff_configurations(path: str, tree_names: Tuple = None) -> None: - """ - Diff between the local and cloud configuration trees. + """Diff between the local and cloud configuration trees. + + You can specify the tree names to diff using the ``--tree-names`` flag. """ trees = filter_trees(path, tree_names) diff --git a/riocli/parameter/download.py b/riocli/parameter/download.py index 3e4845e7..5a9612c7 100644 --- a/riocli/parameter/download.py +++ b/riocli/parameter/download.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ from click_help_colors import HelpColorsCommand from riocli.config import new_client -from riocli.constants import Symbols, Colors +from riocli.constants import Colors, Symbols from riocli.utils.spinner import with_spinner @@ -50,8 +50,14 @@ def download_configurations( delete_existing: bool = False, spinner=None ) -> None: - """ - Download configuration parameter trees from rapyuta.io + """Download configuration parameter trees from rapyuta.io. + + You can specify the tree names to download using the ``--tree-names`` flag. + + If you do not specify any tree names, all the trees will be downloaded. + + You can also specify the ``--overwrite`` or ``--delete-existing`` flag to + overwrite the existing parameter tree on the local machine. """ if path is None: # Not using the Context Manager because diff --git a/riocli/parameter/list.py b/riocli/parameter/list.py index 9acb8f9d..8fde8655 100644 --- a/riocli/parameter/list.py +++ b/riocli/parameter/list.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -26,9 +26,7 @@ help_options_color=Colors.GREEN, ) def list_configuration_trees() -> None: - """ - List the Configuration Parameter Trees. - """ + """List the configuration parameter trees in current project.""" try: data = list_trees() trees = [[tree] for tree in data] diff --git a/riocli/parameter/upload.py b/riocli/parameter/upload.py index f92cc656..4af7a3eb 100644 --- a/riocli/parameter/upload.py +++ b/riocli/parameter/upload.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -47,8 +47,34 @@ def upload_configurations( delete_existing: bool = False, silent: bool = False ) -> None: - """ - Upload a directories as configuration parameters. + """Upload directories as configuration parameter trees. + + You can upload one or more directories as configuration + parameter trees on rapyuta.io. If you do not wish to + upload all the directories as a tree you can specify + the directory names using the ``--tree-names`` flag. + Directories that match the tree names will be parsed and + uploaded. + + You can also specify the ``--recreate`` or ``--delete-existing`` + flag to overwrite the existing parameter tree on rapyuta.io. + + You can skip the confirmation prompt by using the ``--force`` or + ``--silent`` or the ``-f`` flag. + + Usage Examples: + + Upload all directories as configuration parameter trees + + $ rio parameter upload . + + Upload only the directories "config" and "secrets" + + $ rio parameter upload . --tree-names config --tree-names secrets + + Recreate the existing parameter tree + + $ rio parameter upload . --recreate """ try: trees = filter_trees(path, tree_names) diff --git a/riocli/parameter/utils.py b/riocli/parameter/utils.py index dca2a22a..dd454f31 100644 --- a/riocli/parameter/utils.py +++ b/riocli/parameter/utils.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/project/create.py b/riocli/project/create.py index d5cdbbc5..a52a8e62 100644 --- a/riocli/project/create.py +++ b/riocli/project/create.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -40,8 +40,10 @@ def create_project( organization_short_id: str, spinner=None, ) -> None: - """ - Creates a new project + """Create a new project. + + If you do not specify the organization, the project will + be created in the current organization. """ if not organization_guid: organization_guid = ctx.obj.data.get('organization_id') diff --git a/riocli/project/delete.py b/riocli/project/delete.py index 73800679..f4a182d1 100644 --- a/riocli/project/delete.py +++ b/riocli/project/delete.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ from click_help_colors import HelpColorsCommand from riocli.config import new_v2_client -from riocli.constants import Symbols, Colors +from riocli.constants import Colors, Symbols from riocli.project.util import name_to_guid from riocli.utils.spinner import with_spinner @@ -37,8 +37,10 @@ def delete_project( project_guid: str, spinner=None, ) -> None: - """ - Deletes a project + """Delete a project. + + You can skip the confirmation prompt by using the ``--force`` + or ``-f`` or the ``--silent`` flag. """ if not force: with spinner.hidden(): diff --git a/riocli/project/features/__init__.py b/riocli/project/features/__init__.py index 95e011ba..ffbdb8dc 100644 --- a/riocli/project/features/__init__.py +++ b/riocli/project/features/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/project/inspect.py b/riocli/project/inspect.py index 6c6426fd..341c8e1d 100644 --- a/riocli/project/inspect.py +++ b/riocli/project/inspect.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -33,8 +33,10 @@ @name_to_guid def inspect_project(format_type: str, project_name: str, project_guid: str) -> None: - """ - Inspect the project resource + """Print the project details. + + You can specify the format of the output using the ``--format`` flag. + The supported formats are ``json`` and ``yaml``. Default is ``yaml``. """ try: client = new_v2_client(with_project=False) diff --git a/riocli/project/list.py b/riocli/project/list.py index cd0b16cb..e258f4fd 100644 --- a/riocli/project/list.py +++ b/riocli/project/list.py @@ -46,8 +46,22 @@ def list_projects( labels: typing.List[str] = (), wide: bool = False, ) -> None: - """ - List all the projects you are part of + """List all the projects you are a part of in current organization. + + You can also filter the list by specifying labels using the ``--label`` + or the ``-l`` flag. + + For more details, you can use the ``--wide`` or the ``-w`` flag. + + Usage Examples: + + List all projects with label "release=3.0" + + $ rio project list --label release=3.0 + + List projects with the wide option + + $ rio project list --wide """ # If organization is not passed in the options, use organization_guid = organization_guid or ctx.obj.data.get('organization_id') diff --git a/riocli/project/select.py b/riocli/project/select.py index 376c256f..82de2ab5 100644 --- a/riocli/project/select.py +++ b/riocli/project/select.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -34,8 +34,10 @@ def select_project( project_name: str, project_guid: str, ) -> None: - """ - Sets the given project in the CLI context. All other resources use this project to act upon. + """Switch to a different project in the current organization. + + The project will be set in the CLI's context and will be used + for all the subsequent commands. """ ctx = get_root_context(ctx) diff --git a/riocli/project/update_owner.py b/riocli/project/update_owner.py index 2d48a128..c32af786 100644 --- a/riocli/project/update_owner.py +++ b/riocli/project/update_owner.py @@ -42,7 +42,13 @@ def update_owner( Update the owner of the project. The command will show an interactive list of users in the project if - you do not specify --user-email. You can select the new owner from the list. + you do not specify ``--user-email.`` You can select the new owner from the list. + + Usage Examples: + + Update the owner of the project to a specific user + + $ rio project update-owner PROJECT --user-email user@email.com """ config = get_config_from_context(ctx) client = config.new_v2_client(with_project=False) diff --git a/riocli/project/whoami.py b/riocli/project/whoami.py index 034da931..6fea259a 100644 --- a/riocli/project/whoami.py +++ b/riocli/project/whoami.py @@ -32,8 +32,10 @@ @name_to_guid @click.pass_context def whoami(ctx: click.Context, project_name: str, project_guid: str) -> None: - """ - Find the role of the current user in a project. + """Find your role in a project. + + If you do not specify the project name, the command will use the project + set in the CLI context. """ if not ctx.obj.data.get('email_id'): raise LoggedOut diff --git a/riocli/rosbag/__init__.py b/riocli/rosbag/__init__.py index 3437ac70..d9e4dabe 100644 --- a/riocli/rosbag/__init__.py +++ b/riocli/rosbag/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/secret/__init__.py b/riocli/secret/__init__.py index 22b16d4c..5985f6fb 100644 --- a/riocli/secret/__init__.py +++ b/riocli/secret/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/secret/delete.py b/riocli/secret/delete.py index 0fbc1b4b..69930ded 100644 --- a/riocli/secret/delete.py +++ b/riocli/secret/delete.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/secret/inspect.py b/riocli/secret/inspect.py index 80c76ce6..a6149aab 100644 --- a/riocli/secret/inspect.py +++ b/riocli/secret/inspect.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/secret/list.py b/riocli/secret/list.py index b08e177a..e8d063a3 100644 --- a/riocli/secret/list.py +++ b/riocli/secret/list.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/shell/__init__.py b/riocli/shell/__init__.py index 7284ce18..de867f8e 100644 --- a/riocli/shell/__init__.py +++ b/riocli/shell/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,18 +19,21 @@ from prompt_toolkit.history import FileHistory, ThreadedHistory from riocli.config import Configuration +from riocli.constants import Colors from riocli.shell.prompt import prompt_callback @click.command( cls=HelpColorsCommand, - help_headers_color='yellow', - help_options_color='green', + help_headers_color=Colors.YELLOW, + help_options_color=Colors.GREEN, ) @click.pass_context def shell(ctx: click.Context): - """ - Interactive Shell for Rapyuta.io + """Start an interactive shell + + The shell provides an interactive environment to run commands + and is useful for running multiple commands in a single session. """ start_shell(ctx) @@ -38,8 +41,8 @@ def shell(ctx: click.Context): @click.command( 'repl', cls=HelpColorsCommand, - help_headers_color='yellow', - help_options_color='green', + help_headers_color=Colors.YELLOW, + help_options_color=Colors.GREEN, hidden=True ) @click.pass_context diff --git a/riocli/shell/prompt.py b/riocli/shell/prompt.py index 14281169..8deafbef 100644 --- a/riocli/shell/prompt.py +++ b/riocli/shell/prompt.py @@ -1,4 +1,4 @@ -# Copyright 2022 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/static_route/__init__.py b/riocli/static_route/__init__.py index d14b22f3..3cb805e0 100644 --- a/riocli/static_route/__init__.py +++ b/riocli/static_route/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/static_route/create.py b/riocli/static_route/create.py index d66fc266..45dc61ad 100644 --- a/riocli/static_route/create.py +++ b/riocli/static_route/create.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ from riocli.constants import Colors, Symbols from riocli.utils.spinner import with_spinner + @click.command( 'create', cls=HelpColorsCommand, @@ -27,8 +28,12 @@ @click.argument('name', type=str) @with_spinner(text="Creating static route...") def create_static_route(name: str, spinner=None) -> None: - """ - Creates a new static route + """Create a new static route + + Please note that the name you provide while creating the + static route will be suffixed with the organization's + short guid in the backend. Please run the list command + to view the name of the static route and inspect it later. """ try: client = new_v2_client(with_project=True) diff --git a/riocli/static_route/delete.py b/riocli/static_route/delete.py index 6c549a01..3186804e 100644 --- a/riocli/static_route/delete.py +++ b/riocli/static_route/delete.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ from riocli.constants import Colors, Symbols from riocli.utils.spinner import with_spinner + @click.command( 'delete', cls=HelpColorsCommand, @@ -32,8 +33,10 @@ def delete_static_route( force: bool, spinner=None, ) -> None: - """ - Deletes a static route + """Delete a static route. + + To skip confirmation, use the ``--force`` or ``-f`` or + the ``--silent`` flag. """ with spinner.hidden(): if not force: diff --git a/riocli/static_route/inspect.py b/riocli/static_route/inspect.py index 3f8a4bb5..eb0d6cc4 100644 --- a/riocli/static_route/inspect.py +++ b/riocli/static_route/inspect.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -34,8 +34,10 @@ def inspect_static_route( format_type: str, static_route: str, ) -> None: - """ - Inspect a static route + """Print the details of a static route. + + You can choose the format of the output using the ``--format`` flag. + The supported formats are ``json`` and ``yaml``. Default is ``yaml``. """ try: client = new_v2_client() diff --git a/riocli/static_route/list.py b/riocli/static_route/list.py index b4097177..8af5d249 100644 --- a/riocli/static_route/list.py +++ b/riocli/static_route/list.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,8 +32,16 @@ @click.option('--label', '-l', 'labels', multiple=True, type=click.STRING, default=(), help='Filter the deployment list by labels') def list_static_routes(labels: typing.List[str]) -> None: - """ - List the static routes in the selected project + """List the static routes in the current project. + + You can filter the list by providing labels using + the ``--label`` or ``-l`` flag. + + Usage Examples: + + List static routes with label 'app=web' + + $ rio static-route list --label app=web """ try: client = new_v2_client(with_project=True) diff --git a/riocli/static_route/open.py b/riocli/static_route/open.py index 9f1fa082..7d6d7bb4 100644 --- a/riocli/static_route/open.py +++ b/riocli/static_route/open.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -26,9 +26,7 @@ ) @click.argument('static-route', type=str) def open_static_route(static_route) -> None: - """ - Opens the static route in the default browser - """ + """Open a static route in the default browser.""" try: client = new_v2_client() route = client.get_static_route(static_route) diff --git a/riocli/static_route/util.py b/riocli/static_route/util.py index ab7cc6b9..19f22a1d 100644 --- a/riocli/static_route/util.py +++ b/riocli/static_route/util.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/usergroup/__init__.py b/riocli/usergroup/__init__.py index 69839067..02e9513d 100644 --- a/riocli/usergroup/__init__.py +++ b/riocli/usergroup/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -28,8 +28,17 @@ help_options_color=Colors.GREEN, ) def usergroup() -> None: - """ - Manage usergroups on rapyuta.io + """Manage usergroups in current organization. + + Usergroups are a way to organize users and projects + in your organization. You can create usergroups and + add users and projects to them. This helps in managing + access control and permissions in your organization. + + Users can be part of multiple usergroups and projects + can be part of multiple usergroups. You can further + make some users admins of a usergroup and they will + have the permissions to manage the usergroup. """ pass diff --git a/riocli/usergroup/delete.py b/riocli/usergroup/delete.py index ad7eeccb..0f9b87ca 100644 --- a/riocli/usergroup/delete.py +++ b/riocli/usergroup/delete.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -41,8 +41,10 @@ def delete_usergroup( force: bool, spinner: Yaspin = None, ) -> None: - """ - Delete usergroup from organization + """Delete a usergroup from current organization. + + To skip confirmation, use the ``--force`` or ``-f`` or + the ``--silent`` flag. """ if not force: with spinner.hidden(): diff --git a/riocli/usergroup/inspect.py b/riocli/usergroup/inspect.py index ea1e81bf..71586979 100644 --- a/riocli/usergroup/inspect.py +++ b/riocli/usergroup/inspect.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -35,8 +35,10 @@ @click.pass_context @name_to_guid def inspect_usergroup(ctx: click.Context, format_type: str, group_name: str, group_guid: str, spinner=None) -> None: - """ - Inspect the usergroup resource + """Print the details of a usergroup + + You choose the format of the output using the ``--format`` flag. + The supported formats are ``json`` and ``yaml``. Default is ``yaml``. """ try: client = new_client() diff --git a/riocli/usergroup/list.py b/riocli/usergroup/list.py index 551c237b..458050f6 100644 --- a/riocli/usergroup/list.py +++ b/riocli/usergroup/list.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ import click from click_help_colors import HelpColorsCommand + from riocli.config import new_client from riocli.constants import Colors from riocli.utils import tabulate_data @@ -29,10 +30,7 @@ ) @click.pass_context def list_usergroup(ctx: click.Context) -> None: - """ - List all user groups in selected organization - """ - + """List all user groups in current organization.""" try: client = new_client() org_guid = ctx.obj.data.get('organization_id') diff --git a/riocli/usergroup/util.py b/riocli/usergroup/util.py index 861eb66f..9120df9e 100644 --- a/riocli/usergroup/util.py +++ b/riocli/usergroup/util.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/utils/__init__.py b/riocli/utils/__init__.py index bda73ed6..64040bab 100644 --- a/riocli/utils/__init__.py +++ b/riocli/utils/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/utils/context.py b/riocli/utils/context.py index 3e7787ca..bc4063aa 100644 --- a/riocli/utils/context.py +++ b/riocli/utils/context.py @@ -1,4 +1,4 @@ -# Copyright 2022 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/utils/execute.py b/riocli/utils/execute.py index 83f58eef..2ab9afc1 100644 --- a/riocli/utils/execute.py +++ b/riocli/utils/execute.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/utils/spinner.py b/riocli/utils/spinner.py index 822a97e1..ee753d96 100644 --- a/riocli/utils/spinner.py +++ b/riocli/utils/spinner.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/utils/ssh_tunnel.py b/riocli/utils/ssh_tunnel.py index e8f9f39b..64be9358 100644 --- a/riocli/utils/ssh_tunnel.py +++ b/riocli/utils/ssh_tunnel.py @@ -1,4 +1,4 @@ -# Copyright 2021 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/riocli/vpn/__init__.py b/riocli/vpn/__init__.py index c2eec2cc..ab63af2a 100644 --- a/riocli/vpn/__init__.py +++ b/riocli/vpn/__init__.py @@ -28,8 +28,13 @@ help_options_color='green', ) def vpn() -> None: - """ - Connect your machine to the current project's VPN network + """Connect to the rapyuta.io VPN + + You can connect to the rapyuta.io VPN from your system + and access the machines in the VPN. You can view other + machines in the VPN, ping them, and check the status of + the VPN connection. You can also register a new machine + that may not be able to run the CLI. """ pass diff --git a/riocli/vpn/connect.py b/riocli/vpn/connect.py index 9e178efe..63c5473d 100644 --- a/riocli/vpn/connect.py +++ b/riocli/vpn/connect.py @@ -51,8 +51,20 @@ @click.pass_context @with_spinner(text="Connecting...") def connect(ctx: click.Context, update_hosts: bool, spinner: Yaspin): - """ - Connect to the current project's VPN network + """Connect to the current project's VPN network. + + Simpy run the command to connect to the VPN network + of the current project. If ``tailscale`` isn't found + on the system then the command will prompt to install + the required tools. + + If the VPN is not enabled in the + project, the command will inform the user to enable + it on the project. + + If you are already connected to the VPN, the command + will prompt to stop the current connection and connect + to the project's VPN. """ config = get_config_from_context(ctx) diff --git a/riocli/vpn/disconnect.py b/riocli/vpn/disconnect.py index 8f389306..187e9a7e 100644 --- a/riocli/vpn/disconnect.py +++ b/riocli/vpn/disconnect.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,8 +32,14 @@ ) @click.pass_context def disconnect(ctx: click.Context): - """ - Disconnect from the project's VPN network + """Disconnect from the project's VPN network. + + Simply run the command to disconnect from the VPN network. + + If ``tailscale`` isn't found on the system then the command will + prompt to install the required tools. While it may seem unnecessary + to install the tools to disconnect, it is works as a safety measure + to ensure that the user has the required tools to connect to the VPN. """ try: install_vpn_tools() diff --git a/riocli/vpn/machines.py b/riocli/vpn/machines.py index 370e489c..c04d8d2c 100644 --- a/riocli/vpn/machines.py +++ b/riocli/vpn/machines.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from typing import Iterable + import click from click_help_colors import HelpColorsCommand, HelpColorsGroup from yaspin.core import Yaspin @@ -44,8 +45,10 @@ def machines() -> None: help_options_color=Colors.GREEN, ) def list_machines() -> None: - """ - List all the registered Machines on the VPN. + """List all the registered machines on the VPN. + + This command lists all the machines that are registered + on the VPN using the CLI. """ labels = 'machine-key=true' @@ -67,10 +70,14 @@ def list_machines() -> None: @click.argument('name', type=str) @click.argument('node_key', type=str) @click.pass_context -@with_spinner(text="Registering Machine...") +@with_spinner(text="Registering machine...") def register_machine(ctx: click.Context, name: str, node_key: str, spinner: Yaspin) -> None: - """ - Register an Android or iOS Tailscale Client in the Project VPN. + """Register an Android or iOS Tailscale Client in the project's VPN. + + Provide a name and the node key of the machine to register it + in the project's VPN. The node key can be obtained from the + Tailscale client running on the machine. The name can be any + name that you want to give to the machine. """ labels = get_binding_labels() labels['machine-key'] = 'true' @@ -95,12 +102,9 @@ def register_machine(ctx: click.Context, name: str, node_key: str, spinner: Yasp help_options_color=Colors.GREEN, ) @click.argument('name', type=str) -@with_spinner(text="De-registering Machine...") +@with_spinner(text="De-registering machine...") def deregister_machine(name: str, spinner: Yaspin) -> None: - """ - Register an Android or iOS Tailscale Client in the Project VPN. - """ - + """Deregister an Android or iOS Tailscale Client in the Project VPN.""" try: client = new_v2_client() client.delete_instance_binding("rio-internal-headscale", name) diff --git a/riocli/vpn/ping.py b/riocli/vpn/ping.py index 59e393c4..147d4411 100644 --- a/riocli/vpn/ping.py +++ b/riocli/vpn/ping.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,12 +18,7 @@ from riocli.constants import Colors, Symbols from riocli.utils.spinner import with_spinner -from riocli.vpn.util import ( - install_vpn_tools, - is_tailscale_up, - get_tailscale_status, - tailscale_ping -) +from riocli.vpn.util import (get_tailscale_status, install_vpn_tools, is_tailscale_up, tailscale_ping) @click.command( @@ -35,8 +30,12 @@ @click.pass_context @with_spinner(text="Pinging all peers...") def ping_all(ctx: click.Context, spinner: Yaspin = None): - """ - Ping all the peers in the network + """Ping all the peers in the network. + + This command will ping all the peers in the network. It is + convenient to check the connectivity of all the peers in the + network. Also, it helps establish a direct connection with + the peers. """ try: with spinner.hidden(): diff --git a/riocli/vpn/status.py b/riocli/vpn/status.py index ccea7b36..392a7850 100644 --- a/riocli/vpn/status.py +++ b/riocli/vpn/status.py @@ -1,4 +1,4 @@ -# Copyright 2023 Rapyuta Robotics +# Copyright 2024 Rapyuta Robotics # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,12 +18,7 @@ from riocli.config import new_v2_client from riocli.constants import Colors, Symbols from riocli.utils import tabulate_data -from riocli.vpn.util import ( - install_vpn_tools, - is_tailscale_up, - get_tailscale_status, - is_vpn_enabled_in_project, -) +from riocli.vpn.util import (get_tailscale_status, install_vpn_tools, is_tailscale_up, is_vpn_enabled_in_project) @click.command( @@ -36,8 +31,11 @@ help='Print more details', type=bool) @click.pass_context def status(ctx: click.Context, wide: bool = False): - """ - Check VPN status + """Check VPN network status. + + You can view all the connected peers in the VPN network. + + User the ``--wide`` flag to view more details about the peers. """ try: install_vpn_tools()