Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Miscellaneous bug fixes #13

Merged
merged 14 commits into from
Jan 10, 2023
2 changes: 1 addition & 1 deletion run.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def main():

cli = JabberwockyCLI(stdin, stdout)
cli.container_manager = ContainerManagerClient()
inp = " ".join(argv[1:])
inp = argv[1:]
cli.parse_cmd(inp)


Expand Down
106 changes: 53 additions & 53 deletions src/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

import re
from sys import stdin, stdout
from typing import List
from pathlib import Path

from src.containers.install import install_container
from src.containers.container_manager_client import ContainerManagerClient

CONTAINER_NAME_REGEX = r"""\w+"""
Expand All @@ -24,7 +27,7 @@ def __init__(self, in_stream=stdin, out_stream=stdout) -> None:
self.in_stream = in_stream
self.out_stream = out_stream

def parse_cmd(self, cmd: str) -> None:
def parse_cmd(self, cmd: List[str]) -> None:
"""
Parses the cmd sent from script
"""
Expand All @@ -49,22 +52,19 @@ def parse_cmd(self, cmd: str) -> None:
"ssh-address": self.ssh_address,
}

cmd = cmd.strip()
cmd_list = cmd.split(None, 1)
if len(cmd_list) == 0:
if len(cmd) == 0:
command = "help"
rest = ""
elif len(cmd_list) == 1:
command = cmd_list[0]
rest = ""
rest = []
else:
command, rest = cmd_list
command = cmd[0]
rest = cmd[1:]

if command not in subcmd_dict:
self.out_stream.write(f"Command of '{command}' is not valid\n")
return
subcmd_dict[command](rest)

def help(self, cmd: str) -> None: # pylint: disable=unused-argument
def help(self, cmd: List[str]) -> None: # pylint: disable=unused-argument
"""
Prints the basic help menu for the CLI

Expand Down Expand Up @@ -112,82 +112,84 @@ def help(self, cmd: str) -> None: # pylint: disable=unused-argument
"""
self.out_stream.write(help_str)

def interact(self, cmd: str) -> None:
def interact(self, cmd: List[str]) -> None:
"""
Allows user to directly interact with shell

:param cmd: The rest of the command sent
"""
name = cmd[0]
comp = re.compile(CONTAINER_NAME_REGEX)
if not comp.match(cmd.strip()):
self.out_stream.write(f"'{cmd.strip()}' is not a valid container name\n")
if not comp.match(name):
self.out_stream.write(f"'{name}' is not a valid container name\n")
return
self.container_manager.run_shell(cmd.strip())
self.container_manager.run_shell(name)

def start(self, cmd: str) -> None:
def start(self, cmd: List[str]) -> None:
"""
Starts a container

:param cmd: The rest of the command sent
"""
name = cmd[0]
comp = re.compile(CONTAINER_NAME_REGEX)
if not comp.match(cmd.strip()):
self.out_stream.write(f"'{cmd.strip()}' is not a valid container name\n")
if not comp.match(name):
self.out_stream.write(f"'{name}' is not a valid container name\n")
return
self.container_manager.start(cmd)
self.container_manager.start(name)

def stop(self, cmd: str) -> None:
def stop(self, cmd: List[str]) -> None:
"""
Stops a container

:param cmd: The rest of the command sent
"""
name = cmd[0]
comp = re.compile(CONTAINER_NAME_REGEX)
if not comp.match(cmd.strip()):
self.out_stream.write(f"'{cmd.strip()}' is not a valid container name\n")
if not comp.match(name):
self.out_stream.write(f"'{name}' is not a valid container name\n")
return
self.container_manager.stop(cmd)
self.container_manager.stop(name)

def kill(self, cmd: str) -> None:
def kill(self, cmd: List[str]) -> None:
"""
Kills a container

:param cmd: The rest of the command sent
"""
name = cmd[0]
comp = re.compile(CONTAINER_NAME_REGEX)
if not comp.match(cmd.strip()):
self.out_stream.write(f"'{cmd.strip()}' is not a valid container name\n")
if not comp.match(name):
self.out_stream.write(f"'{name}' is not a valid container name\n")
return
self.container_manager.kill(cmd)
self.container_manager.kill(name)

def run(self, cmd: str) -> None:
def run(self, cmd: List[str]) -> None:
"""
Runs a command in the container

:param cmd: The rest of the command sent
"""
cmd_list = cmd.split(None, 1)
if len(cmd_list) != 2:
if len(cmd) < 2:
self.out_stream.write("Command requires two arguments\n")
return
container_name, command = (*cmd_list,)
container_name, command = cmd[0], cmd[1:]
comp = re.compile(CONTAINER_NAME_REGEX)
if not comp.match(container_name):
self.out_stream.write(f"'{container_name}' is not a valid container name\n")
return
self.container_manager.run_command(container_name, [command])
self.container_manager.run_command(container_name, command)

def send_file(self, cmd: str) -> None:
def send_file(self, cmd: List[str]) -> None:
"""
Sends a file to a container

:param cmd: The rest of the command sent
"""
cmd_list = cmd.split()
if len(cmd_list) != 3:
if len(cmd) < 3:
self.out_stream.write("Command requires three arguments\n")
return
container_name, local_file, remote_file = (*cmd_list,)
container_name, local_file, remote_file = cmd[0], cmd[1], cmd[2]
comp = re.compile(CONTAINER_NAME_REGEX)
if not comp.match(container_name):
self.out_stream.write(f"'{container_name}' is not a valid container name\n")
Expand All @@ -201,17 +203,16 @@ def send_file(self, cmd: str) -> None:
return
self.container_manager.put_file(container_name, local_file, remote_file)

def get_file(self, cmd: str) -> None:
def get_file(self, cmd: List[str]) -> None:
"""
Gets a file from a container

:param cmd: The rest of the command sent
"""
cmd_list = cmd.split()
if len(cmd_list) != 3:
if len(cmd) < 3:
self.out_stream.write("Command requires three arguments\n")
return
container_name, remote_file, local_file = (*cmd_list,)
container_name, remote_file, local_file = cmd[0], cmd[1], cmd[2]
comp = re.compile(CONTAINER_NAME_REGEX)
if not comp.match(container_name):
self.out_stream.write(f"'{container_name}' is not a valid container name\n")
Expand All @@ -225,93 +226,92 @@ def get_file(self, cmd: str) -> None:
return
self.container_manager.get_file(container_name, remote_file, local_file)

def install(self, cmd: str) -> None:
def install(self, cmd: List[str]) -> None:
"""
Installs a container from an archive

:param cmd: The rest of the command sent
"""
cmd_list = cmd.split()
if len(cmd_list) != 2:
if len(cmd) != 2:
self.out_stream.write("Command requires two arguments\n")
return
archive_path_str, container_name = (*cmd_list,)
archive_path_str, container_name = cmd[0], cmd[1]
comp = re.compile(CONTAINER_NAME_REGEX)
if not comp.match(container_name):
self.out_stream.write(f"'{container_name}' is not a valid container name\n")
return
self.container_manager.install(archive_path_str, container_name)

def delete(self, cmd: str) -> None:
def delete(self, cmd: List[str]) -> None:
"""
Deletes a container from the file system

:param cmd: The rest of the command sent
"""
container_name = cmd.strip()
container_name = cmd[0]
comp = re.compile(CONTAINER_NAME_REGEX)
if not comp.match(container_name):
self.out_stream.write(f"'{container_name}' is not a valid container name\n")
return
self.container_manager.delete(container_name)

def download(self, cmd: str) -> None: # pylint: disable=unused-argument
def download(self, cmd: List[str]) -> None: # pylint: disable=unused-argument
"""
Downloads a container from an archive

:param cmd: The rest of the command sent
"""
self.out_stream.write("Command not yet supported")

def archive(self, cmd: str) -> None: # pylint: disable=unused-argument
def archive(self, cmd: List[str]) -> None: # pylint: disable=unused-argument
"""
Sends a container to an archive

:param cmd: The rest of the command sent
"""
self.out_stream.write("Command not yet supported")

def add_repo(self, cmd: str) -> None: # pylint: disable=unused-argument
def add_repo(self, cmd: List[str]) -> None: # pylint: disable=unused-argument
"""
Adds an archive to the system

:param cmd: The rest of the command sent
"""
self.out_stream.write("Command not yet supported")

def update_repo(self, cmd: str) -> None: # pylint: disable=unused-argument
def update_repo(self, cmd: List[str]) -> None: # pylint: disable=unused-argument
"""
Updates an archive

:param cmd: The rest of the command sent
"""
self.out_stream.write("Command not yet supported")

def create(self, cmd: str) -> None: # pylint: disable=unused-argument
def create(self, cmd: List[str]) -> None: # pylint: disable=unused-argument
"""
Runs the container creation wizard

:param cmd: The rest of the command sent
"""
self.out_stream.write("Command not yet supported")

def server_halt(self, cmd: str) -> None: # pylint: disable=unused-argument
def server_halt(self, cmd: List[str]) -> None: # pylint: disable=unused-argument
"""
Tells the server to halt

:param cmd: The rest of the command sent
"""
self.container_manager.server_halt()

def ping(self, cmd: str) -> None: # pylint: disable=unused-argument
def ping(self, cmd: List[str]) -> None: # pylint: disable=unused-argument
"""
Pings the server

:param cmd: The rest of the command sent
"""
self.container_manager.ping()

def ssh_address(self, cmd: str) -> None: # pylint: disable=unused-argument
def ssh_address(self, cmd: List[str]) -> None: # pylint: disable=unused-argument
"""
Prints the information necessary to SSH into the container's shell

Expand Down
3 changes: 3 additions & 0 deletions src/containers/container_manager_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def start(self, container_name: str) -> None:
sock.send(bytes(container_name, "utf-8"))
self._recv_expect(sock, 1024, b"OK")
sock.close()
self.run_command(container_name, ["cat /etc/motd"])

def stop(self, container_name: str) -> None:
"""
Expand Down Expand Up @@ -288,6 +289,8 @@ def _send_select(self) -> None:
while not self.recv_closed:
if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
self.sock.send(bytes(sys.stdin.readline(), "utf-8"))
else:
self.sock.send(b"\x00")
time.sleep(0.1)
except (ConnectionError, OSError):
pass
Expand Down
4 changes: 3 additions & 1 deletion src/containers/container_manager_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ def send_and_recv(self):
def _recv(self):
try:
while msg := self.client_sock.recv(1024):
self.stdin.write(msg)
self.stdin.write(bytes(filter(lambda b: b, msg)))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But like, why?

except (ConnectionError, OSError):
pass

Expand All @@ -411,6 +411,7 @@ def _send_stdout(self):
finally:
self.stdout_closed = True
if self.stderr_closed:
time.sleep(0.25)
self.client_sock.close()

def _send_stderr(self):
Expand All @@ -422,4 +423,5 @@ def _send_stderr(self):
finally:
self.stderr_closed = True
if self.stdout_closed:
time.sleep(0.25)
self.client_sock.close()
7 changes: 7 additions & 0 deletions src/containers/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,10 @@ class FailedToAuthorizeKeyError(RuntimeError):
"""
Raised during failure to authorize keys
"""


class ContainerAlreadyExistsError(RuntimeError):
"""
Raised during container installation when a
container of the desired name already exists
"""
2 changes: 1 addition & 1 deletion src/system/syspath.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def install_container(archive_path: Path, container_name: str) -> None:
:param archive_path: The path to the archive
"""
if not tarfile.is_tarfile(str(archive_path)):
raise FileNotFoundError(str(archive_path))
raise TypeError(f"'{archive_path}' is not a tar archive")
with tarfile.open(str(archive_path)) as tar:
tar.extractall(path=get_container_dir(container_name))
# TODO Sanity check this extraction
Expand Down