Skip to content

Commit

Permalink
Merge pull request #13 from Kippiii/dylan
Browse files Browse the repository at this point in the history
Miscellaneous bug fixes
  • Loading branch information
dmcdo authored Jan 10, 2023
2 parents 66c2e55 + 20011a4 commit 3139d40
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 59 deletions.
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
104 changes: 51 additions & 53 deletions src/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

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

from src.containers.container_manager_client import ContainerManagerClient

Expand All @@ -24,7 +25,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 +50,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 +110,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 +201,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 +224,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
15 changes: 13 additions & 2 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 @@ -287,7 +288,13 @@ def _send_select(self) -> None:
try:
while not self.recv_closed:
if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
self.sock.send(bytes(sys.stdin.readline(), "utf-8"))
buffer = bytes(sys.stdin.readline(), "utf-8")
while buffer:
msg = buffer[:255]
self.sock.send(bytes([len(msg)]) + msg)
buffer = buffer[255:]
else:
self.sock.send(b"\x00")
time.sleep(0.1)
except (ConnectionError, OSError):
pass
Expand All @@ -306,7 +313,11 @@ def _send_msvcrt(self) -> None:

if char == "\r":
print(end="\n")
self.sock.send(bytes(msg + "\n", "utf-8"))
buffer = bytes(msg + "\n", "utf-8")
while buffer:
msg = buffer[:255]
self.sock.send(bytes([len(msg)]) + msg)
buffer = buffer[255:]
msg = ""

elif char == "\b":
Expand Down
9 changes: 7 additions & 2 deletions src/containers/container_manager_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,11 @@ def send_and_recv(self):

def _recv(self):
try:
while msg := self.client_sock.recv(1024):
self.stdin.write(msg)
while msg := self.client_sock.recv(1 << 16):
while msg:
size = msg[0]
self.stdin.write(msg[1:size + 1])
msg = msg[size + 1:]
except (ConnectionError, OSError):
pass

Expand All @@ -411,6 +414,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 +426,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

0 comments on commit 3139d40

Please sign in to comment.