From 701e69917cf274cd576044d734db71c9e9c5f7fb Mon Sep 17 00:00:00 2001 From: askiiart Date: Thu, 15 Dec 2022 16:47:30 -0600 Subject: [PATCH 1/6] Add requirements.txt --- requirements.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..639ee54 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +os +subprocess +pprint \ No newline at end of file From 16632f933b2496c1cb4c35b218671f33144d59ca Mon Sep 17 00:00:00 2001 From: askiiart Date: Thu, 15 Dec 2022 17:14:48 -0600 Subject: [PATCH 2/6] Only compose if changed --- docker_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker_wrapper.py b/docker_wrapper.py index 41c9165..1bacada 100644 --- a/docker_wrapper.py +++ b/docker_wrapper.py @@ -129,7 +129,7 @@ class Docker: """ cwd = os.getcwd() os.chdir(dir) - status = getstatusoutput('docker compose up -d') + status = getstatusoutput('docker compose up -detach --build --remove-orphans') os.chdir(cwd) return status From 1e05dd2cd6a2f8ac75af8c4952cec00d8b02f3a5 Mon Sep 17 00:00:00 2001 From: askiiart Date: Thu, 15 Dec 2022 17:38:51 -0600 Subject: [PATCH 3/6] Major improvements in error handling, & small fix --- docker_wrapper.py | 54 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/docker_wrapper.py b/docker_wrapper.py index 1bacada..fbb1cc0 100644 --- a/docker_wrapper.py +++ b/docker_wrapper.py @@ -2,9 +2,11 @@ from subprocess import getoutput, getstatusoutput import pprint import os + class NoContainersError(Exception): pass + class Docker: @staticmethod def running_containers_info(): @@ -14,12 +16,13 @@ class Docker: """ raw_info = getoutput('docker ps') if '\n' not in raw_info: - raise(NoContainersError('A running Docker container is required to run this program. Please run a docker container and try again.')) + raise (NoContainersError( + 'A running Docker container is required to run this program. Please run a docker container and try again.')) # Header: "CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES" (with way more spaces) header = raw_info[:raw_info.find('\n')+1] header_indices = {'CONTAINER ID': header.find('CONTAINER ID'), 'IMAGE': header.find('IMAGE'), - 'COMMAND': header.find('COMMAND'), 'CREATED': header.find('CREATED'), 'STATUS': header.find('STATUS'), - 'PORTS': header.find('PORTS'), 'NAMES': header.find('NAMES')} + 'COMMAND': header.find('COMMAND'), 'CREATED': header.find('CREATED'), 'STATUS': header.find('STATUS'), + 'PORTS': header.find('PORTS'), 'NAMES': header.find('NAMES')} # Remove header (example above) raw_info = raw_info[raw_info.find('\n')+1:] @@ -44,8 +47,7 @@ class Docker: raw_info.split('\n')[i][start_i:end_i].strip() return info - - + @staticmethod def containers(): """ @@ -54,7 +56,8 @@ class Docker: """ raw_info = getoutput('docker container list') if '\n' not in raw_info: - raise(NoContainersError('A Docker container is required to run this program. Please create a docker container and try again.')) + raise (NoContainersError( + 'A Docker container is required to run this program. Please create a docker container and try again.')) # Remove header raw_info = raw_info[raw_info.find('\n')+1:] info = {} @@ -63,9 +66,9 @@ class Docker: containers = [] for line in raw_info.split('\n'): containers.append(line.strip()[line.strip().rfind(' ')+1:]) - + return containers - + @staticmethod def all_containers_info(): """ @@ -74,12 +77,13 @@ class Docker: """ raw_info = getoutput('docker ps -a') if '\n' not in raw_info: - raise(NoContainersError('A Docker container is required to run this program. Please create a docker container and try again.')) + raise (NoContainersError( + 'A Docker container is required to run this program. Please create a docker container and try again.')) # Header: "CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES" (with way more spaces) header = raw_info[:raw_info.find('\n')+1] header_indices = {'CONTAINER ID': header.find('CONTAINER ID'), 'IMAGE': header.find('IMAGE'), - 'COMMAND': header.find('COMMAND'), 'CREATED': header.find('CREATED'), 'STATUS': header.find('STATUS'), - 'PORTS': header.find('PORTS'), 'NAMES': header.find('NAMES')} + 'COMMAND': header.find('COMMAND'), 'CREATED': header.find('CREATED'), 'STATUS': header.find('STATUS'), + 'PORTS': header.find('PORTS'), 'NAMES': header.find('NAMES')} # Remove header (example above) raw_info = raw_info[raw_info.find('\n')+1:] @@ -116,7 +120,7 @@ class Docker: dict: The info about the container """ return Docker.all_containers_info()[container] - + @staticmethod def compose(dir): """ @@ -129,10 +133,10 @@ class Docker: """ cwd = os.getcwd() os.chdir(dir) - status = getstatusoutput('docker compose up -detach --build --remove-orphans') + status = getstatusoutput('docker compose up --detach --build --remove-orphans') os.chdir(cwd) return status - + @staticmethod def start(container): """ @@ -144,7 +148,7 @@ class Docker: int: The exit code of docker start """ return getstatusoutput(f'docker start {container}')[0] - + @staticmethod def stop(container): """ @@ -156,7 +160,7 @@ class Docker: int: The exit code of docker stop """ return getstatusoutput(f'docker stop {container}')[0] - + @staticmethod def rm(container): """ @@ -169,6 +173,24 @@ class Docker: """ return getstatusoutput(f'docker rm {container}')[0] + @staticmethod + def containers_exist(): + """ + Checks if any containers exist + :returns: + bool: True if containers exist, False otherwise + """ + return True if '\n' in getoutput('docker ps -a') else False + + +def aliens_exist(): + """ + Checks if aliens exist + :returns: + bool: Up all night long; And there's something very wrong + """ + return True if 'blink-182' in 'your playlist' else False + if __name__ == '__main__': try: From 43af3125f11fcdd7d5a73255f831694655685c0c Mon Sep 17 00:00:00 2001 From: askiiart Date: Thu, 15 Dec 2022 17:39:32 -0600 Subject: [PATCH 4/6] Fix error handling & add custom info printer --- basic_management.py | 156 +++++++++++++++++++++++++++----------------- 1 file changed, 97 insertions(+), 59 deletions(-) diff --git a/basic_management.py b/basic_management.py index 3cb1a0f..adcc2e5 100644 --- a/basic_management.py +++ b/basic_management.py @@ -1,69 +1,107 @@ -from docker_wrapper import Docker -from pprint import pprint +from docker_wrapper import Docker, NoContainersError +from subprocess import getoutput -while True: - # Main Menu - print('Select the container to manage:') - containers = Docker.containers() - for i in range(len(containers)): - print(f' {i} - {containers[i]}') - print(' q - quit') - - container_i = input() - print() - if container_i == 'q': - exit(0) - +def container_to_str(container): + """ + Returns info about a Docker container as a string + :parameters:f + container: The name of the container (str) + + :returns: + str: The container info as a string, formatted for printing + """ + # Header: "CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES" (with way more spaces) + info = Docker.container_info(container) + info_str = f'{container}\n' + info_str += f' CONTAINER ID: {info["CONTAINER ID"]}\n' + info_str += f' IMAGE: {info["IMAGE"]}\n' + info_str += f' COMMAND: {info["COMMAND"]}\n' + info_str += f' CREATED: {info["CREATED"]}\n' + info_str += f' STATUS: {info["STATUS"]}\n' + info_str += f' PORTS: {info["PORTS"]}\n' + info_str += f' NAMES: {info["NAMES"]}' + + return info_str + +try: while True: - # Container Menu - container = containers[int(container_i)] - print() - print(f'You selected {container}. What would you like to do with it?') - print(f' view - View container info - (docker ps -a)') - print(f' start - Starts the container (docker start {container})') - print(f' stop - Stops the container (docker stop {container}') - print(f' rm - Deletes the container (docker rm {container})') - print( ' menu - Back to the main menu') - - selection = input() + if not Docker.containers_exist(): + raise(NoContainersError('No containers exist! Please create a container and try again.')) + + # Main Menu + print('Select the container to manage:') + + containers = Docker.containers() + for i in range(len(containers)): + print(f' {i} - {containers[i]}') + print(' q - Quit') + + container_i = input() print() - if selection == 'menu': - break + if container_i == 'q': + exit(0) - elif selection == 'view': - pprint(Docker.container_info(container)) # TODO: Make better, custom printer + while True: + if not Docker.containers_exist(): + raise(NoContainersError('No containers exist! Please create a container and try again.')) + # Container Menu + container = containers[int(container_i)] + print() + print(f'You selected {container}. What would you like to do with it?') + print(f' view - View container info - (docker ps -a)') + print(f' start - Starts the container (docker start {container})') + print(f' stop - Stops the container (docker stop {container}') + print(f' rm - Deletes the container (docker rm {container})') + print( ' menu - Back to the main menu') - elif selection == 'start': - print('Starting...') - status = Docker.start(container) - - elif selection == 'stop': - print('Stopping...') - status = Docker.stop(container) - print('Done.') - - elif selection == 'rm': - break_later = False - while selection != 'y' and selection != 'n' and selection != 'Y' and selection != 'N': - print(f'WARNING! This will DELETE {container}!') - print(f'Are you absolutely sure you want to delete {container}? (y/N)') - selection = input() - if selection == 'y' or selection == 'Y': - print('Deleting...') - status = Docker.rm(container) - print('Done') - break_later = True - elif selection == 'n' or selection == 'N': - print(f'Operation cancelled, returning to {container} menu...') - if break_later: + selection = input() + print() + + if selection == 'menu': break - elif selection == 'menu': - print('Returning to main menu...') - break + elif selection == 'view': + print(container_to_str(container)) - else: - print('Selection invalid. Please try again.') - print() + elif selection == 'start': + print('Starting...') + Docker.start(container) + + elif selection == 'stop': + print('Stopping...') + Docker.stop(container) + print('Done') + + elif selection == 'rm': + break_later = False + while selection != 'y' and selection != 'n' and selection != 'Y' and selection != 'N': + print(f'WARNING! This will DELETE {container}!') + print( + f'Are you absolutely sure you want to delete {container}? (y/N)') + selection = input() + if selection == 'y' or selection == 'Y': + print('Stopping...') + Docker.stop(container) + print('Deleting...') + Docker.rm(container) + print('Done') + break_later = True + elif selection == 'n' or selection == 'N': + print(f'Operation cancelled, returning to {container} menu...') + if break_later: + print() + break + + elif selection == 'menu': + print('Returning to main menu...') + break + + else: + print('Selection invalid. Please try again.') + print() +except NoContainersError as e: + print('Error:', e) + print('No containers found. Exiting...') + exit() From bb37b7d37832231bbce87061f9ab3e25a32720b5 Mon Sep 17 00:00:00 2001 From: askiiart Date: Thu, 15 Dec 2022 17:39:41 -0600 Subject: [PATCH 5/6] Remove unnecessary code --- composer.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/composer.py b/composer.py index 1b80916..60e6587 100644 --- a/composer.py +++ b/composer.py @@ -1,5 +1,4 @@ import os -from subprocess import getoutput from docker_wrapper import Docker # Read config file and make variables @@ -32,6 +31,4 @@ for dir in compose_dirs: for i in range(len(compose_dirs)): dir = compose_dirs[i] container = containers[i] - status = Docker.stop(container) # Assigned to vars so I can see - status = Docker.rm(container) - status = Docker.compose(dir) + Docker.compose(dir) From a7c6ffcfee4e76296c3db7543b46524fd00b4dd3 Mon Sep 17 00:00:00 2001 From: askiiart Date: Thu, 15 Dec 2022 17:42:49 -0600 Subject: [PATCH 6/6] Update requirements.txt --- requirements.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 639ee54..fdb061b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ os -subprocess -pprint \ No newline at end of file +subprocess \ No newline at end of file