From 696692729bcfa0299933d56f02b32aa43eab713a Mon Sep 17 00:00:00 2001 From: Jacob Daniel Bennett Date: Wed, 9 Sep 2020 11:40:51 -0400 Subject: [PATCH 01/18] Added __getFormattedDate function to return UTC formatted dates --- api/ECNQueue.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index e38cb70..41ba393 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -3,7 +3,8 @@ #------------------------------------------------------------------------------# # Imports #------------------------------------------------------------------------------# -import os, time, email, re +import os, time, email, re, datetime +from dateutil.parser import parse from typing import Union import json @@ -264,6 +265,22 @@ def __getAssignedTo(self) -> str: """ assignedTo = self.__getMostRecentHeaderByType("Assigned-To") return assignedTo + + def __getFormattedDate(self, date: str) -> str: + """Returns the date/time recieved properly formatted. + Returns empty string if the string argument passed to the function is not a datetime + + Returns: + str: Properly formatted date/time recieved or empty string. + """ + try: + objDateRecieved = parse(date) + except: + return "" + + formattedDateRecieved = objDateRecieved.strftime("%Y-%m-%dT%H:%M:%S%z") + + return formattedDateRecieved def toJson(self) -> dict: """Returns a JSON safe representation of the item. @@ -345,4 +362,4 @@ def getQueues() -> list: if isDirectory and isValid: queues.append(Queue(file)) - return queues \ No newline at end of file + return queues \ No newline at end of file From b522fe468826799ab5b3a9755947fcac11f065d7 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Wed, 9 Sep 2020 13:49:01 -0400 Subject: [PATCH 02/18] Parse dateReceived --- api/ECNQueue.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index 41ba393..2da3d1b 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -54,7 +54,7 @@ def __init__(self, queue: str, number: int) -> None: self.priority = self.__getMostRecentHeaderByType("Priority") self.department = self.__getMostRecentHeaderByType("Department") self.building = self.__getMostRecentHeaderByType("Building") - self.dateReceived = self.__getMostRecentHeaderByType("Date") + self.dateReceived = self.__getParsedDate(self.__getMostRecentHeaderByType("Date")) self.jsonData = { "queue": self.queue, @@ -274,13 +274,13 @@ def __getFormattedDate(self, date: str) -> str: str: Properly formatted date/time recieved or empty string. """ try: - objDateRecieved = parse(date) + parsedDate = parse(date) except: return "" - formattedDateRecieved = objDateRecieved.strftime("%Y-%m-%dT%H:%M:%S%z") + parsedDateString = parsedDate.strftime("%Y-%m-%dT%H:%M:%S%z") - return formattedDateRecieved + return parsedDateString def toJson(self) -> dict: """Returns a JSON safe representation of the item. @@ -362,4 +362,4 @@ def getQueues() -> list: if isDirectory and isValid: queues.append(Queue(file)) - return queues \ No newline at end of file + return queues \ No newline at end of file From e452fb0e09993d987de516b6593b86897c0cbeca Mon Sep 17 00:00:00 2001 From: Jacob Daniel Bennett Date: Thu, 10 Sep 2020 12:59:05 -0400 Subject: [PATCH 03/18] Added to pip requirements --- requirements.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..60a7d4a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,31 @@ +aniso8601==8.0.0 +astroid==2.4.2 +attrs==20.1.0 +click==7.1.2 +Flask==1.1.2 +Flask-RESTful==0.3.8 +gunicorn==20.0.4 +importlib-metadata==1.7.0 +iniconfig==1.0.1 +isort==4.3.21 +itsdangerous==1.1.0 +Jinja2==2.11.2 +lazy-object-proxy==1.4.3 +MarkupSafe==1.1.1 +mccabe==0.6.1 +more-itertools==8.5.0 +packaging==20.4 +pkg-resources==0.0.0 +pluggy==0.13.1 +py==1.9.0 +pylint==2.5.3 +pyparsing==2.4.7 +pytest==6.0.1 +python-dateutil==2.8.1 +pytz==2020.1 +six==1.15.0 +toml==0.10.1 +typed-ast==1.4.1 +Werkzeug==1.0.1 +wrapt==1.12.1 +zipp==3.1.0 From 95c3684841c5884c414cdc4a8937f56cd76f2715 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Mon, 14 Sep 2020 19:10:45 -0400 Subject: [PATCH 04/18] Add basic logging format and function --- utils/venv-manager.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 utils/venv-manager.py diff --git a/utils/venv-manager.py b/utils/venv-manager.py new file mode 100644 index 0000000..200a18f --- /dev/null +++ b/utils/venv-manager.py @@ -0,0 +1,43 @@ +"""Allows for creating, deleting and removing Python virtual environments in webqueue2 + +Examples: + Create a virtual environment: + $ venv-manager.py [-c | --create] + + Delete a virtual environment: + $ venv-manager.py [-d | --delete] + + Reset a virtual environment: + $ venv-manager.py [-r | --reset] +""" + +import logging + + +################################################################################ +# Configuration +################################################################################ + +# Configure the logger +logger = logging.getLogger("venv-manager") +logger.setLevel(logging.DEBUG) + +# See: https://docs.python.org/3/library/logging.html#logrecord-attributes +log_message_format = "%(asctime)s %(name)s : [%(levelname)s] %(message)s" +# See: https://docs.python.org/3.6/library/time.html#time.strftime +log_time_format = "%b %d %Y %H:%M:%S" +log_formatter = logging.Formatter(log_message_format, log_time_format) + +stream_handler = logging.StreamHandler() +stream_handler.setFormatter(log_formatter) +logger.addHandler(stream_handler) + + + +if __name__ == "__main__": + logger.debug("This is a debug message.") + logger.info("This is an info message.") + logger.warning("This is a warning message.") + logger.error("This is an error message.") + logger.critical("This is a critical message.") + \ No newline at end of file From 6393ef3f2a5c76d41d106c3af6ce2a91baa01f41 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Mon, 14 Sep 2020 19:21:32 -0400 Subject: [PATCH 05/18] Add file handler to logger --- .gitignore | 3 ++- utils/venv-manager.py | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index acc39b8..c518367 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,5 @@ yarn-error.log* # Python Files /api/venv -__pycache__/ \ No newline at end of file +__pycache__/ +venv-manager.log diff --git a/utils/venv-manager.py b/utils/venv-manager.py index 200a18f..e2c3737 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -19,7 +19,8 @@ ################################################################################ # Configure the logger -logger = logging.getLogger("venv-manager") +logger_name = "venv-manager" +logger = logging.getLogger(logger_name) logger.setLevel(logging.DEBUG) # See: https://docs.python.org/3/library/logging.html#logrecord-attributes @@ -30,8 +31,12 @@ stream_handler = logging.StreamHandler() stream_handler.setFormatter(log_formatter) -logger.addHandler(stream_handler) +file_handler = logging.FileHandler(f'{logger_name}.log') +file_handler.setFormatter(log_formatter) + +logger.addHandler(stream_handler) +logger.addHandler(file_handler) if __name__ == "__main__": From 0765139d08b38e605e1da92e52d1f42572ebfb08 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Tue, 15 Sep 2020 11:29:33 -0400 Subject: [PATCH 06/18] Update usage docs and implement fixed log file path --- utils/venv-manager.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/utils/venv-manager.py b/utils/venv-manager.py index e2c3737..deabfd2 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -2,22 +2,28 @@ Examples: Create a virtual environment: - $ venv-manager.py [-c | --create] + $ venv-manager.py create Delete a virtual environment: - $ venv-manager.py [-d | --delete] + $ venv-manager.py delete Reset a virtual environment: - $ venv-manager.py [-r | --reset] + $ venv-manager.py reset """ -import logging +import os, logging, argparse, pathlib ################################################################################ # Configuration ################################################################################ +# Set virtual environment path +WEBQUEUE2_DIR = pathlib.Path(__file__).parent.parent +API_DIR = pathlib.Path(WEBQUEUE2_DIR, "api") +VENV_DIR = pathlib.Path(API_DIR, 'venv') + + # Configure the logger logger_name = "venv-manager" logger = logging.getLogger(logger_name) @@ -32,7 +38,8 @@ stream_handler = logging.StreamHandler() stream_handler.setFormatter(log_formatter) -file_handler = logging.FileHandler(f'{logger_name}.log') +log_file_path = pathlib.Path(WEBQUEUE2_DIR, "utils", f'{logger_name}.log') +file_handler = logging.FileHandler(log_file_path) file_handler.setFormatter(log_formatter) logger.addHandler(stream_handler) From 2c856788bffa0c793e4ba7c04af2629841ec0c68 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Tue, 15 Sep 2020 11:31:05 -0400 Subject: [PATCH 07/18] Implement argument parsing --- utils/venv-manager.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/utils/venv-manager.py b/utils/venv-manager.py index deabfd2..f8f8c99 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -46,10 +46,26 @@ logger.addHandler(file_handler) +################################################################################ +# Functions +################################################################################ + + +def get_args() -> argparse.Namespace: + """Parses arguments and returns argparses's generated namespace. + + Returns: + argparse.Namespace: Argparses's generated namespace. + """ + parser = argparse.ArgumentParser() + parser.add_argument( + "action", + help="Action to perform.", + choices=("create", "delete", "reset") + ) + return parser.parse_args() + + if __name__ == "__main__": - logger.debug("This is a debug message.") - logger.info("This is an info message.") - logger.warning("This is a warning message.") - logger.error("This is an error message.") - logger.critical("This is a critical message.") - \ No newline at end of file + args = get_args() + action = args.action From 74653c48daea4a8af4609a9769e3f2654bbe8bdd Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Tue, 15 Sep 2020 16:31:49 -0400 Subject: [PATCH 08/18] Add run_logged_shell_subprocess to track subprocess output/errors --- utils/venv-manager.py | 76 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/utils/venv-manager.py b/utils/venv-manager.py index f8f8c99..ec2f452 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -11,7 +11,8 @@ $ venv-manager.py reset """ -import os, logging, argparse, pathlib +from pathlib import Path +import os, logging, argparse, subprocess ################################################################################ @@ -19,9 +20,10 @@ ################################################################################ # Set virtual environment path -WEBQUEUE2_DIR = pathlib.Path(__file__).parent.parent -API_DIR = pathlib.Path(WEBQUEUE2_DIR, "api") -VENV_DIR = pathlib.Path(API_DIR, 'venv') +WEBQUEUE2_DIR = Path(__file__).parent.parent +API_DIR = Path(WEBQUEUE2_DIR, "api") +VENV_NAME = "venv" +VENV_DIR = Path(API_DIR, VENV_NAME) # Configure the logger @@ -38,7 +40,7 @@ stream_handler = logging.StreamHandler() stream_handler.setFormatter(log_formatter) -log_file_path = pathlib.Path(WEBQUEUE2_DIR, "utils", f'{logger_name}.log') +log_file_path = Path(WEBQUEUE2_DIR, "utils", f'{logger_name}.log') file_handler = logging.FileHandler(log_file_path) file_handler.setFormatter(log_formatter) @@ -65,7 +67,71 @@ def get_args() -> argparse.Namespace: ) return parser.parse_args() +command = f"cd {API_DIR} && python3 -m venv {VENV_NAME}" +def run_logged_shell_subprocess(command: str, timeout: int = 10) -> int: + """Executes a shell command using subprocess with logging. + + stderr is redirected to stdout and stdout is pipped to logger. + If the subprocess raises an exception, the exception is logged as critical. + + Example: + Running a successful command: + run_logged_shell_subprocess(command="pwd") + Returns 0 + + Running an unsuccessful command with a 20 second timeout: + run_logged_shell_subprocess(command="pwd", timeout=20) + Returns 1 + + Args: + command (str): The command to run + timeout (int): The number of seconds to wait for a program before killing it + + Returns: + int: The return code of the subprocess + """ + logger.debug(f"Entering subprocess for '{command}'") + with subprocess.Popen(command,\ + stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True, text=True)\ + as logged_shell_process: + + subprocess_log_prefix = f"(PID: {logged_shell_process.pid})" + + try: + # Convert combined stdout and stderr stream to list of strings + process_output_stream, _ = logged_shell_process.communicate(timeout=timeout) + process_output_lines = process_output_stream.split("\n") + # Remove last entry in process_output_lines because it is always empty + process_output_lines.pop(-1) + + for line in process_output_lines: + logger.debug(f"{subprocess_log_prefix}: {line}") + except Exception as exception: + logger.critical(str(exception)) + return logged_shell_process.returncode + else: + if logged_shell_process.returncode != 0: + logger.debug(f"Subprocess exitied with a return code of {logged_shell_process.returncode}") + return logged_shell_process.returncode + elif logged_shell_process.returncode == 0: + logger.info(f"Subprocess for '{command}' completed successfuly") + return logged_shell_process.returncode + finally: + logger.debug(f"Exiting subprocess for '{command}''") + + + + if __name__ == "__main__": args = get_args() action = args.action + + if action == "create": + exit(create_environment()) + elif action == "delete": + exit(delete_environment()) + elif action == "reset": + exit(reset_environment()) + else: + logger.critical(f'Invalid argument {action}') \ No newline at end of file From 290ab8c760ec4f01e7b309d1bb4712c2588fde0e Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Wed, 16 Sep 2020 16:47:23 -0400 Subject: [PATCH 09/18] Refactor run_logged_subprocess to return a dict with returncode and output --- utils/venv-manager.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/utils/venv-manager.py b/utils/venv-manager.py index ec2f452..fbf01e6 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -13,6 +13,7 @@ from pathlib import Path import os, logging, argparse, subprocess +from typing import Union ################################################################################ @@ -67,8 +68,8 @@ def get_args() -> argparse.Namespace: ) return parser.parse_args() -command = f"cd {API_DIR} && python3 -m venv {VENV_NAME}" -def run_logged_shell_subprocess(command: str, timeout: int = 10) -> int: + +def run_logged_subprocess(command: Union[str, list], timeout: int = 10, shell: bool = False) -> list: """Executes a shell command using subprocess with logging. stderr is redirected to stdout and stdout is pipped to logger. @@ -76,23 +77,23 @@ def run_logged_shell_subprocess(command: str, timeout: int = 10) -> int: Example: Running a successful command: - run_logged_shell_subprocess(command="pwd") - Returns 0 + run_logged_subprocess(command=["git", "commit", "-m", "'Commit message.'"]) + Returns: {"returncode": 0, "output": []} - Running an unsuccessful command with a 20 second timeout: - run_logged_shell_subprocess(command="pwd", timeout=20) - Returns 1 + Running an unsuccessful shell command with a 20 second timeout: + run_logged_subprocess(command="cd test/", timeout=20, shell=True) + Returns: {"returncode": 1, "output": ["cd: test: No such file or directory"]} Args: - command (str): The command to run + command (Union): The command to run. If shell=False, pass a list with the first item being the command and the subsequent items being arguments. If shell=True, pass a string as you would type it into a shell. timeout (int): The number of seconds to wait for a program before killing it Returns: - int: The return code of the subprocess + dict: Containing subprocess return code and output. """ logger.debug(f"Entering subprocess for '{command}'") with subprocess.Popen(command,\ - stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True, text=True)\ + stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=shell, text=True)\ as logged_shell_process: subprocess_log_prefix = f"(PID: {logged_shell_process.pid})" @@ -108,16 +109,14 @@ def run_logged_shell_subprocess(command: str, timeout: int = 10) -> int: logger.debug(f"{subprocess_log_prefix}: {line}") except Exception as exception: logger.critical(str(exception)) - return logged_shell_process.returncode else: if logged_shell_process.returncode != 0: - logger.debug(f"Subprocess exitied with a return code of {logged_shell_process.returncode}") - return logged_shell_process.returncode + logger.debug(f"Something went wrong. '{command}' exited with return code {logged_shell_process.returncode}") elif logged_shell_process.returncode == 0: - logger.info(f"Subprocess for '{command}' completed successfuly") - return logged_shell_process.returncode + logger.debug(f"Subprocess for '{command}' completed successfuly") finally: - logger.debug(f"Exiting subprocess for '{command}''") + logger.debug(f"Exiting subprocess for '{command}'") + return {"returncode": logged_shell_process.returncode, "output": process_output_lines} From 79265dd9c04af89eb8ee704abe3ecae810488472 Mon Sep 17 00:00:00 2001 From: Justin Campbel Date: Wed, 16 Sep 2020 16:56:06 -0400 Subject: [PATCH 10/18] Test password auth --- testfile | 1 + 1 file changed, 1 insertion(+) create mode 100644 testfile diff --git a/testfile b/testfile new file mode 100644 index 0000000..2691857 --- /dev/null +++ b/testfile @@ -0,0 +1 @@ +testfile From 6a4c2b23f2cfebbe1eebc449bdf66fe0b5823c83 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 17 Sep 2020 00:22:26 -0400 Subject: [PATCH 11/18] Update run_logged_subprocess to return a tuple --- utils/venv-manager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/venv-manager.py b/utils/venv-manager.py index fbf01e6..5f484f5 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -69,7 +69,7 @@ def get_args() -> argparse.Namespace: return parser.parse_args() -def run_logged_subprocess(command: Union[str, list], timeout: int = 10, shell: bool = False) -> list: +def run_logged_subprocess(command: Union[str, list], timeout: int = 10, shell: bool = True) -> tuple: """Executes a shell command using subprocess with logging. stderr is redirected to stdout and stdout is pipped to logger. @@ -78,18 +78,18 @@ def run_logged_subprocess(command: Union[str, list], timeout: int = 10, shell: b Example: Running a successful command: run_logged_subprocess(command=["git", "commit", "-m", "'Commit message.'"]) - Returns: {"returncode": 0, "output": []} + Returns: (0, "") Running an unsuccessful shell command with a 20 second timeout: run_logged_subprocess(command="cd test/", timeout=20, shell=True) - Returns: {"returncode": 1, "output": ["cd: test: No such file or directory"]} + Returns: (1, "cd: test: No such file or directory\n") Args: command (Union): The command to run. If shell=False, pass a list with the first item being the command and the subsequent items being arguments. If shell=True, pass a string as you would type it into a shell. timeout (int): The number of seconds to wait for a program before killing it Returns: - dict: Containing subprocess return code and output. + tuple: With the first value being the return code and second being the combined stdout+stderr """ logger.debug(f"Entering subprocess for '{command}'") with subprocess.Popen(command,\ @@ -116,7 +116,7 @@ def run_logged_subprocess(command: Union[str, list], timeout: int = 10, shell: b logger.debug(f"Subprocess for '{command}' completed successfuly") finally: logger.debug(f"Exiting subprocess for '{command}'") - return {"returncode": logged_shell_process.returncode, "output": process_output_lines} + return (logged_shell_process.returncode, process_output_stream) From 8bf3836d66b65b1aa4c8d2415e2a9ddf6881c3b4 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 17 Sep 2020 00:24:07 -0400 Subject: [PATCH 12/18] Working venv creation --- utils/venv-manager.py | 61 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/utils/venv-manager.py b/utils/venv-manager.py index 5f484f5..51391b6 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -27,6 +27,10 @@ VENV_DIR = Path(API_DIR, VENV_NAME) +# Set minimum pip major version +TARGET_PIP_VERSION = 19 + + # Configure the logger logger_name = "venv-manager" logger = logging.getLogger(logger_name) @@ -119,7 +123,64 @@ def run_logged_subprocess(command: Union[str, list], timeout: int = 10, shell: b return (logged_shell_process.returncode, process_output_stream) +def create_environment() -> int: + """Creates a virtual environment for webqueue2] + + Exit Codes: + 0 = Success + 5 = VENV_DIR already exists + 10 = Could not create VENV_DIR + 15 = Could not install requirements + Returns: + int: Exit code + """ + + # Check for an existing virtual environment + try: + os.mkdir(VENV_DIR) + except FileExistsError: + logger.warning(f"The directory {VENV_DIR} already exists. Exiting") + return 5 + + # Create virtual environment + logger.info(f"Creating virtual environment {VENV_NAME} at {VENV_DIR}") + create_env_returncode, _ = run_logged_subprocess(f"cd {API_DIR} && python3 -m venv {VENV_NAME}", shell=True) + if create_env_returncode == 0: + logger.info(f"Virtual environment {VENV_NAME} created at {VENV_DIR}") + else: + logger.critical(f"Could not create virtual environment {VENV_NAME} at {VENV_DIR}. Exiting") + return 10 + + # Check pip version + logger.debug("Checking pip version") + check_pip_returncode, check_pip_output = run_logged_subprocess(f"{VENV_DIR}/bin/pip --version") + + if check_pip_returncode != 0: + logger.warning("Could not check pip version. Virtual environment dependencies may not install") + + pip_version_full = check_pip_output.split()[1] + logger.debug(f"pip version is {pip_version_full}") + + pip_version_major = pip_version_full.split(".")[0] + if int(pip_version_major) < 19: + logger.info(f"pip verion is {pip_version_major}.x (pip >= {TARGET_PIP_VERSION}.x needed.) Upgrading pip") + update_pip_returncode, update_pip_output = run_logged_subprocess(f"{VENV_DIR}/bin/pip install --upgrade pip") + + if update_pip_returncode == 0: + logger.info(update_pip_output.split("\n")[-2]) + else: + logger.warning("Failed to update pip. Virtual environment dependencies may not install") + + # Install requirements + logger.info("Installing requirements") + install_requirements_returncode, _ = run_logged_subprocess(f"{VENV_DIR}/bin/pip install -r {API_DIR}/requirements.txt") + if install_requirements_returncode == 0: + logger.info("Successfully installed requirements") + return 0 + else: + logger.critical("Failed to install requirements. Exiting") + return 15 if __name__ == "__main__": From 8b118299263d966cf6e90279417c2157432fcbc6 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 17 Sep 2020 01:08:54 -0400 Subject: [PATCH 13/18] Working venv deletion --- utils/venv-manager.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/utils/venv-manager.py b/utils/venv-manager.py index 51391b6..e15048d 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -183,6 +183,25 @@ def create_environment() -> int: return 15 +def delete_environment() -> int: + """Deletes a virtual environment for webqueue2] + + Exit Codes: + 0 = Success + 5 = Could not delete VENV_DIR + + Returns: + int: Exit code + """ + delete_venv_returncode, _ = run_logged_subprocess(f"rm -rf {VENV_DIR}") + if delete_venv_returncode == 0: + logger.info(f"Successfully deleted virtual environment {VENV_DIR} at {VENV_DIR}") + return 0 + else: + logger.critical(f"Failed to delete virtual environment {VENV_DIR} at {VENV_DIR}. Exiting") + return 5 + + if __name__ == "__main__": args = get_args() action = args.action From 9b5ff3a30e107881119c3174d338901ef4b25b13 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 17 Sep 2020 01:09:32 -0400 Subject: [PATCH 14/18] Fixed filepath bug for relative log/venv locations --- utils/venv-manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/venv-manager.py b/utils/venv-manager.py index e15048d..7e74b80 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -21,7 +21,7 @@ ################################################################################ # Set virtual environment path -WEBQUEUE2_DIR = Path(__file__).parent.parent +WEBQUEUE2_DIR = Path(os.path.abspath(__file__)).parent.parent API_DIR = Path(WEBQUEUE2_DIR, "api") VENV_NAME = "venv" VENV_DIR = Path(API_DIR, VENV_NAME) From 5d54475617d3654e64e455f029456937fcc951e4 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 17 Sep 2020 01:16:57 -0400 Subject: [PATCH 15/18] Working venv reset --- utils/venv-manager.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/utils/venv-manager.py b/utils/venv-manager.py index 7e74b80..a033b81 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -124,7 +124,7 @@ def run_logged_subprocess(command: Union[str, list], timeout: int = 10, shell: b def create_environment() -> int: - """Creates a virtual environment for webqueue2] + """Creates a virtual environment for webqueue2 Exit Codes: 0 = Success @@ -184,7 +184,7 @@ def create_environment() -> int: def delete_environment() -> int: - """Deletes a virtual environment for webqueue2] + """Deletes a virtual environment for webqueue2 Exit Codes: 0 = Success @@ -201,6 +201,29 @@ def delete_environment() -> int: logger.critical(f"Failed to delete virtual environment {VENV_DIR} at {VENV_DIR}. Exiting") return 5 +def reset_environment() -> int: + """Resets a virtual environment for webqueue2 + + Exit Codes: + 0 = Success + 5 = Could not delete VENV_DIR + 10 = Could not create VENV_DIR + + Returns: + int: Exit code + """ + delete_returncode = delete_environment() + if delete_returncode != 0: + logger.critical(f"Failed to reset virtual environment {VENV_DIR} at {VENV_DIR}. Exiting") + return 5 + + create_returncode = create_environment() + if create_returncode != 0: + logger.critical(f"Failed to reset virtual environment {VENV_DIR} at {VENV_DIR}. Exiting") + return 10 + + logger.info(f"Successfully reset virtual environment {VENV_DIR} at {VENV_DIR}. Exiting") + if __name__ == "__main__": args = get_args() From 745025398de10d5744c1f7a8048334fd48e0d8fe Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 17 Sep 2020 01:22:29 -0400 Subject: [PATCH 16/18] Changed default logging to INFO and added debug flag --- utils/venv-manager.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/utils/venv-manager.py b/utils/venv-manager.py index a033b81..d19da5c 100644 --- a/utils/venv-manager.py +++ b/utils/venv-manager.py @@ -34,7 +34,7 @@ # Configure the logger logger_name = "venv-manager" logger = logging.getLogger(logger_name) -logger.setLevel(logging.DEBUG) +logger.setLevel(logging.INFO) # See: https://docs.python.org/3/library/logging.html#logrecord-attributes log_message_format = "%(asctime)s %(name)s : [%(levelname)s] %(message)s" @@ -70,6 +70,11 @@ def get_args() -> argparse.Namespace: help="Action to perform.", choices=("create", "delete", "reset") ) + parser.add_argument( + "--debug", + help="Print debug logs", + action="store_true", + ) return parser.parse_args() @@ -229,6 +234,9 @@ def reset_environment() -> int: args = get_args() action = args.action + if args.debug: + logger.setLevel(logging.DEBUG) + if action == "create": exit(create_environment()) elif action == "delete": From 99cb9974bebc4391b77ad112f49c1702eea31eea Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 17 Sep 2020 12:04:47 -0400 Subject: [PATCH 17/18] Added venv-manager commands to npm scripts --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index b785b26..db88807 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,9 @@ "start:docs": "npx styleguidist server --open --config styleguidist/styleguide.config.js", "build:frontend": "react-scripts build", "build:docs": "npx styleguidist build --config styleguidist/styleguide.config.js", + "venv:create": "python3 utils/venv-manager.py create", + "venv:delete": "python3 utils/venv-manager.py delete", + "venv:reset": "python3 utils/venv-manager.py reset", "test": "react-scripts test", "eject": "react-scripts eject" }, From c342885d43401cd1c207d51f645b793d16af45fe Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 17 Sep 2020 13:59:03 -0400 Subject: [PATCH 18/18] Update docs for explicit date format --- api/ECNQueue.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index 2da3d1b..53c376c 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -267,8 +267,9 @@ def __getAssignedTo(self) -> str: return assignedTo def __getFormattedDate(self, date: str) -> str: - """Returns the date/time recieved properly formatted. - Returns empty string if the string argument passed to the function is not a datetime + """Returns the date/time formatted as RFC 8601 YYYY-MM-DDTHH:MM:SS+00:00. + Returns empty string if the string argument passed to the function is not a datetime. + See: https://en.wikipedia.org/wiki/ISO_8601 Returns: str: Properly formatted date/time recieved or empty string.