From c6bea52209881827ceea6dcd084aa6677f1e014d Mon Sep 17 00:00:00 2001 From: KUMAR SHIKHAR Date: Fri, 22 Nov 2024 17:13:32 +0530 Subject: [PATCH] feat(device): add option to exec commands asynchronously (#365) This commit adds the option to execute command on devices and deployments asynchronously. The default behaviour is still sync. However, users can simply add the --async flag to execute the command in the background. Fixes AB#16668 --- pyproject.toml | 2 +- riocli/deployment/execute.py | 19 ++++++++++++++++++- riocli/device/execute.py | 30 ++++++++++++++++++++++++------ riocli/utils/execute.py | 5 ++++- uv.lock | 8 ++++---- 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a85f5ebb..345a8af9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ dependencies = [ "python-magic>=0.4.27", "pytz", "pyyaml>=5.4.1", - "rapyuta-io>=2.1.1", + "rapyuta-io>=2.2.0", "requests>=2.20.0", "semver>=3.0.0", "setuptools", diff --git a/riocli/deployment/execute.py b/riocli/deployment/execute.py index b149a325..5ec81629 100644 --- a/riocli/deployment/execute.py +++ b/riocli/deployment/execute.py @@ -36,6 +36,14 @@ ) @click.option("--user", default="root") @click.option("--shell", default="/bin/bash") +@click.option("--timeout", default=300) +@click.option( + "--async", + "run_async", + is_flag=True, + default=False, + help="Run the command asynchronously.", +) @click.option( "--exec", "exec_name", default=None, help="Name of a executable in the component" ) @@ -44,7 +52,9 @@ def execute_command( user: str, shell: str, + timeout: int, exec_name: str, + run_async: bool, deployment_name: str, command: typing.List[str], ) -> None: @@ -61,6 +71,12 @@ def execute_command( shell is ``/bin/bash``. You can also specify the user using the ``--user`` option. The default user is ``root``. + To run the command asynchronously, set the --async flag to true. + The default value is false. + + To specify the timeout, use the --timeout + flag, providing the duration in seconds. The default value is 300. + Please ensure that you enclose the command in quotes to avoid any issues with the command parsing. @@ -112,10 +128,11 @@ def execute_command( user=user, shell=shell, command=command, - background=False, + background=run_async, deployment=deployment, exec_name=exec_name, device_name=deployment.spec.device.depends.nameOrGUID, + timeout=timeout, ) click.echo(response) except Exception as e: diff --git a/riocli/device/execute.py b/riocli/device/execute.py index 1768fd71..97ad1a19 100644 --- a/riocli/device/execute.py +++ b/riocli/device/execute.py @@ -28,19 +28,36 @@ help_options_color=Colors.GREEN, ) @click.option("--user", default="root") +@click.option("--timeout", default=300) @click.option("--shell", default="/bin/bash") +@click.option( + "--async", + "run_async", + is_flag=True, + default=False, + help="Run the command asynchronously.", +) @click.argument("device-name", type=str) @click.argument("command", nargs=-1) @name_to_guid def execute_command( - device_name: str, device_guid: str, user: str, shell: str, command: typing.List[str] + device_name: str, + device_guid: str, + user: str, + timeout: int, + shell: str, + run_async: bool, + command: typing.List[str], ) -> None: """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. + You can specify the user, shell, run-async, and timeout options to customize + the command execution. 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'. To run the command asynchronously, + set the --async flag to true. The default value is false. To + specify the timeout, use the --timeout flag, providing the duration + in seconds. The default value is 300. Make sure you put your command in quotes to avoid any issues. @@ -54,7 +71,8 @@ def execute_command( user=user, shell=shell, command=command, - background=False, + background=run_async, + timeout=timeout, ) click.secho(response) diff --git a/riocli/utils/execute.py b/riocli/utils/execute.py index 099cfc1f..e6409552 100644 --- a/riocli/utils/execute.py +++ b/riocli/utils/execute.py @@ -30,6 +30,7 @@ def run_on_device( deployment: str = None, exec_name: str = None, device_name: str = None, + timeout: int = 300, ) -> str: client = new_client() @@ -58,7 +59,9 @@ def run_on_device( if deployment: cmd = 'script -q -c "dectl exec {} -- {}"'.format(exec_name, cmd) - return device.execute_command(Command(cmd, shell=shell, bg=background, runas=user)) + return device.execute_command( + Command(cmd, shell=shell, bg=background, runas=user, timeout=timeout) + ) def apply_func( diff --git a/uv.lock b/uv.lock index 020e1060..c367c34d 100644 --- a/uv.lock +++ b/uv.lock @@ -703,7 +703,7 @@ wheels = [ [[package]] name = "rapyuta-io" -version = "2.1.1" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, @@ -714,9 +714,9 @@ dependencies = [ { name = "six" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/ab/dee990947ba02dbeaf8abf1b051ce7db0a9a5d2f846b7ab4512b3014ab1f/rapyuta_io-2.1.1.tar.gz", hash = "sha256:ddb1b60f6982f2628f6ec37f3a5e15b0cad6b0f9a0b461c3425c529da34e5c19", size = 51811 } +sdist = { url = "https://files.pythonhosted.org/packages/d1/46/5060b2467f6b917096f431d92871a7c0921c9470bd3bf6a2fe136336e0a7/rapyuta_io-2.2.0.tar.gz", hash = "sha256:198a86e8770448ad96cbfb9847e821934a27e10926c8fce0179693e183b962b1", size = 52374 } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/b3/c58a2f7f161495891ccabf2fc872e72a53b7637efc07066e6690cc93476d/rapyuta_io-2.1.1-py3-none-any.whl", hash = "sha256:1f9b6fa067efd4ff1801eaa2b65c36f5ddeabef722f8c3b2d4b0b428dca1a708", size = 60304 }, + { url = "https://files.pythonhosted.org/packages/44/42/97ebb12973b2d3d1f2426eb9731d228473932ff0600b41e44f7e90863958/rapyuta_io-2.2.0-py3-none-any.whl", hash = "sha256:54727a57cb84aa26c23acb5c35b20e6299b553a32dd9ff5a0aaec4e4b4eb907c", size = 60836 }, ] [[package]] @@ -792,7 +792,7 @@ requires-dist = [ { name = "python-magic", specifier = ">=0.4.27" }, { name = "pytz" }, { name = "pyyaml", specifier = ">=5.4.1" }, - { name = "rapyuta-io", specifier = ">=2.1.1" }, + { name = "rapyuta-io", specifier = ">=2.2.0" }, { name = "requests", specifier = ">=2.20.0" }, { name = "semver", specifier = ">=3.0.0" }, { name = "setuptools" },