Skip to content

Commit

Permalink
exec returns the command exit code (#292)
Browse files Browse the repository at this point in the history
  • Loading branch information
Skazza94 committed Nov 24, 2024
1 parent 6c6ec57 commit c34c8db
Show file tree
Hide file tree
Showing 35 changed files with 376 additions and 113 deletions.
5 changes: 4 additions & 1 deletion src/Kathara/cli/command/CheckCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __init__(self) -> None:
help='Show a help message and exit.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)

self.console.print(create_panel("System Check", style="blue bold", justify="center"))
Expand Down Expand Up @@ -74,3 +74,6 @@ def linux_platform_info():
self.console.print("[bold green]\u2713 Container run successfully.")
except Exception as e:
self.console.print(f"[bold red]\u00d7 Running container failed: {str(e)}")
return 1

return 0
4 changes: 3 additions & 1 deletion src/Kathara/cli/command/ConnectCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def __init__(self) -> None:
help='Name of the device to connect to.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand All @@ -75,3 +75,5 @@ def run(self, current_path: str, argv: List[str]) -> None:
Kathara.get_instance().connect_tty(
machine_name=args['machine_name'], lab_hash=lab.hash, shell=args['shell'], logs=args['logs']
)

return 0
4 changes: 3 additions & 1 deletion src/Kathara/cli/command/ExecCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def __init__(self) -> None:
help='Shell command that will be executed inside the device.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand Down Expand Up @@ -108,3 +108,5 @@ def run(self, current_path: str, argv: List[str]) -> None:
sys.stderr.write(stderr)
except StopIteration:
pass

return exec_output.exit_code()
4 changes: 3 additions & 1 deletion src/Kathara/cli/command/LcleanCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def __init__(self) -> None:
help='Clean only specified devices.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand All @@ -66,3 +66,5 @@ def run(self, current_path: str, argv: List[str]) -> None:
selected_machines=set(args['machine_names']) if args['machine_names'] else None,
excluded_machines=set(args['excluded_machines']) if args['excluded_machines'] else None,
)

return 0
4 changes: 3 additions & 1 deletion src/Kathara/cli/command/LconfigCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def __init__(self) -> None:
help='Specify the collision domain to remove.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand Down Expand Up @@ -94,3 +94,5 @@ def run(self, current_path: str, argv: List[str]) -> None:
f"[red]- Removing interface on collision domain `{cd_to_remove}` from device `{machine_name}`..."
)
Kathara.get_instance().disconnect_machine_from_link(device, lab.get_link(cd_to_remove))

return 0
9 changes: 6 additions & 3 deletions src/Kathara/cli/command/LinfoCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def __init__(self) -> None:
help='Get running topology info'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand All @@ -89,11 +89,12 @@ def run(self, current_path: str, argv: List[str]) -> None:
else:
self._get_lab_live_info(lab)

return
return 0

if args['conf']:
self._get_conf_info(lab, machine_name=args['name'])
return

return 0

with self.console.status(
f"Loading...",
Expand All @@ -112,6 +113,8 @@ def run(self, current_path: str, argv: List[str]) -> None:
machines_stats = Kathara.get_instance().get_machines_stats(lab.hash)
self.console.print(create_lab_table(machines_stats))

return 0

def _get_machine_live_info(self, lab: Lab, machine_name: str) -> None:
with Live(None, refresh_per_second=12.5, screen=True) as live:
live.update(self.console.status(f"Loading...", spinner="dots"))
Expand Down
4 changes: 3 additions & 1 deletion src/Kathara/cli/command/ListCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def __init__(self) -> None:
help='Show only information about a specified device.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand All @@ -71,6 +71,8 @@ def run(self, current_path: str, argv: List[str]) -> None:
)
self.console.print(create_lab_table(machines_stats))

return 0

def _get_live_info(self, machine_name: Optional[str], all_users: bool) -> None:
machines_stats = Kathara.get_instance().get_machines_stats(machine_name=machine_name, all_users=all_users)
with Live(None, refresh_per_second=12.5, screen=True) as live:
Expand Down
4 changes: 3 additions & 1 deletion src/Kathara/cli/command/LrestartCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def __init__(self) -> None:
help='Restarts only specified devices.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand All @@ -138,3 +138,5 @@ def run(self, current_path: str, argv: List[str]) -> None:

LcleanCommand().run(current_path, lclean_argv)
LstartCommand().run(current_path, argv)

return 0
10 changes: 4 additions & 6 deletions src/Kathara/cli/command/LstartCommand.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import argparse
import os
import sys
from typing import List

from ..ui.utils import create_panel, LabMetaHighlighter
from ..ui.utils import create_lab_table
from ..ui.utils import create_panel, LabMetaHighlighter
from ... import utils
from ...exceptions import PrivilegeError, EmptyLabError
from ...foundation.cli.command.Command import Command
from ...manager.Kathara import Kathara
from ...model.Lab import Lab
from ...parser.netkit.DepParser import DepParser
from ...parser.netkit.ExtParser import ExtParser
from ...parser.netkit.FolderParser import FolderParser
Expand Down Expand Up @@ -144,7 +142,7 @@ def __init__(self) -> None:
help='Launches only specified devices.'
)

def run(self, current_path: str, argv: List[str]) -> Lab:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand Down Expand Up @@ -211,7 +209,7 @@ def run(self, current_path: str, argv: List[str]) -> Lab:
if lab_ext_exists:
self.console.print("[green]\u2713 [bold]lab.ext[/bold] file is correct.")

sys.exit(0)
return 0

lab.add_option('hosthome_mount', args['hosthome_mount'])
lab.add_option('shared_mount', args['shared_mount'])
Expand All @@ -236,4 +234,4 @@ def run(self, current_path: str, argv: List[str]) -> Lab:
machines_stats = Kathara.get_instance().get_machines_stats(lab_hash=lab.hash)
self.console.print(create_lab_table(machines_stats))

return lab
return 0
15 changes: 10 additions & 5 deletions src/Kathara/cli/command/LtestCommand.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import argparse
import os
import shutil
import sys
import time
from typing import List

Expand All @@ -10,6 +9,8 @@
from ... import utils
from ...exceptions import TestError
from ...foundation.cli.command.Command import Command
from ...manager.Kathara import Kathara
from ...model.Lab import Lab
from ...strings import strings, wiki_description
from ...test.BuiltinTest import BuiltInTest
from ...test.UserTest import UserTest
Expand Down Expand Up @@ -59,7 +60,7 @@ def __init__(self) -> None:
help='Compares current network scenario state with stored signature.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand All @@ -74,13 +75,15 @@ def run(self, current_path: str, argv: List[str]) -> None:
self.console.print(
f"[bold red]\u00d7 Signature for current network scenario already exists."
)
sys.exit(1)
return 1

# Tests run without terminals, no shared and /hosthome dirs.
new_argv = ["--noterminals", "--no-shared", "--no-hosthome"]

# Start the lab
lab = LstartCommand().run(lab_path, new_argv)
LstartCommand().run(lab_path, new_argv)
lab = Lab(name=None, path=lab_path)
Kathara.get_instance().update_lab_from_api(lab)

if args['wait']:
try:
Expand Down Expand Up @@ -129,4 +132,6 @@ def run(self, current_path: str, argv: List[str]) -> None:

if args['verify']:
if not builtin_test_passed or not user_test_passed:
sys.exit(1)
return 1

return 0
4 changes: 3 additions & 1 deletion src/Kathara/cli/command/SettingsCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@


class SettingsCommand(Command):
def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
menu_factory = SettingsMenuFactory()

menu = menu_factory.create_menu()

menu.show()

return 0
4 changes: 3 additions & 1 deletion src/Kathara/cli/command/VcleanCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def __init__(self) -> None:
help='The name of the device to clean.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand All @@ -44,3 +44,5 @@ def run(self, current_path: str, argv: List[str]) -> None:
)

Kathara.get_instance().undeploy_lab(lab_name=lab.name, selected_machines={args['name']})

return 0
4 changes: 3 additions & 1 deletion src/Kathara/cli/command/VconfigCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(self) -> None:
help='Specify the collision domain to remove.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand Down Expand Up @@ -85,3 +85,5 @@ def run(self, current_path: str, argv: List[str]) -> None:
link.api_object = Kathara.get_instance().get_link_api_object(cd_to_remove, lab_name=lab.name)

Kathara.get_instance().disconnect_machine_from_link(device, link)

return 0
7 changes: 4 additions & 3 deletions src/Kathara/cli/command/VstartCommand.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import argparse
import sys
from typing import List

from ..ui.utils import create_panel, interface_cd_mac
Expand Down Expand Up @@ -168,7 +167,7 @@ def __init__(self) -> None:
help='Set the shell (sh, bash, etc.) that should be used inside the device.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand All @@ -183,7 +182,7 @@ def run(self, current_path: str, argv: List[str]) -> None:

if args['dry_mode']:
self.console.print(f"[green]\u2713 [bold]{name}[/bold] configuration is correct.")
sys.exit(0)
return 0

Setting.get_instance().open_terminals = args['terminals'] if args['terminals'] is not None \
else Setting.get_instance().open_terminals
Expand Down Expand Up @@ -215,3 +214,5 @@ def run(self, current_path: str, argv: List[str]) -> None:
raise SyntaxError(f"Interface number in `--eth {iface_number}:{s}` is not a number.")

Kathara.get_instance().deploy_lab(lab)

return 0
4 changes: 3 additions & 1 deletion src/Kathara/cli/command/WipeCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def __init__(self) -> None:
help='Wipe all Kathara devices and collision domains of all users. MUST BE ROOT FOR THIS OPTION.'
)

def run(self, current_path: str, argv: List[str]) -> None:
def run(self, current_path: str, argv: List[str]) -> int:
self.parse_args(argv)
args = self.get_args()

Expand All @@ -66,3 +66,5 @@ def run(self, current_path: str, argv: List[str]) -> None:
raise PrivilegeError("You must be root in order to wipe all Kathara devices of all users.")

Kathara.get_instance().wipe(all_users=bool(args['all']))

return 0
2 changes: 1 addition & 1 deletion src/Kathara/foundation/cli/command/Command.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def __init__(self) -> None:
)

@abstractmethod
def run(self, current_path: str, argv: List[str]) -> Any:
def run(self, current_path: str, argv: List[str]) -> int:
raise NotImplementedError("You must implement `run` method.")

def parse_args(self, argv: List[str]) -> None:
Expand Down
18 changes: 10 additions & 8 deletions src/Kathara/foundation/manager/IManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from abc import ABC, abstractmethod
from typing import Dict, Set, Any, Generator, Tuple, List, Optional, Union

from .exec_stream.IExecStream import IExecStream
from .stats.ILinkStats import ILinkStats
from .stats.IMachineStats import IMachineStats
from ...model.Lab import Lab
Expand Down Expand Up @@ -214,7 +215,7 @@ def connect_tty_obj(self, machine: Machine, shell: str = None, logs: bool = Fals
@abstractmethod
def exec(self, machine_name: str, command: Union[List[str], str], lab_hash: Optional[str] = None,
lab_name: Optional[str] = None, lab: Optional[Lab] = None, wait: Union[bool, Tuple[int, float]] = False,
stream: bool = True) -> Union[Generator[Tuple[bytes, bytes], None, None], Tuple[bytes, bytes, int]]:
stream: bool = True) -> Union[IExecStream, Tuple[bytes, bytes, int]]:
"""Exec a command on a device in a running network scenario.
Args:
Expand All @@ -230,11 +231,12 @@ def exec(self, machine_name: str, command: Union[List[str], str], lab_hash: Opti
execution before executing the command. If a tuple is provided, the first value indicates the
number of retries before stopping waiting and the second value indicates the time interval to wait
for each retry. Default is False.
stream (bool): If True, return a generator object containing the command output. If False,
stream (bool): If True, return an IExecStream object. If False,
returns a tuple containing the complete stdout, the stderr, and the return code of the command.
Returns:
Union[Generator[Tuple[bytes, bytes]], Tuple[bytes, bytes, int]]: A generator of tuples containing the stdout
and stderr in bytes or a tuple containing the stdout, the stderr and the return code of the command.
Union[IExecStream, Tuple[bytes, bytes, int]]: An IExecStream object or
a tuple containing the stdout, the stderr and the return code of the command.
Raises:
InvocationError: If a running network scenario hash or name is not specified.
Expand All @@ -245,7 +247,7 @@ def exec(self, machine_name: str, command: Union[List[str], str], lab_hash: Opti

@abstractmethod
def exec_obj(self, machine: Machine, command: Union[List[str], str], wait: Union[bool, Tuple[int, float]] = False,
stream: bool = True) -> Union[Generator[Tuple[bytes, bytes], None, None], Tuple[bytes, bytes, int]]:
stream: bool = True) -> Union[IExecStream, Tuple[bytes, bytes, int]]:
"""Exec a command on a device in a running network scenario.
Args:
Expand All @@ -255,12 +257,12 @@ def exec_obj(self, machine: Machine, command: Union[List[str], str], wait: Union
execution before executing the command. If a tuple is provided, the first value indicates the
number of retries before stopping waiting and the second value indicates the time interval to wait
for each retry. Default is False.
stream (bool): If True, return a generator object containing the command output. If False,
stream (bool): If True, return an IExecStream object. If False,
returns a tuple containing the complete stdout, the stderr, and the return code of the command.
Returns:
Union[Generator[Tuple[bytes, bytes]], Tuple[bytes, bytes, int]]: A generator of tuples containing the stdout
and stderr in bytes or a tuple containing the stdout, the stderr and the return code of the command.
Union[IExecStream, Tuple[bytes, bytes, int]]: An IExecStream object or
a tuple containing the stdout, the stderr and the return code of the command.
Raises:
LabNotFoundError: If the specified device is not associated to any network scenario.
Expand Down
Loading

0 comments on commit c34c8db

Please sign in to comment.