from docker_wrapper import Docker, NoContainersError from typing import Dict, List import sys from dataclasses import dataclass from enum import Enum, auto class MenuOption(Enum): VIEW = auto() START = auto() STOP = auto() REMOVE = auto() MENU = auto() QUIT = auto() @dataclass class ContainerInfo: container_id: str image: str command: str created: str status: str ports: str names: str def __str__(self) -> str: return ( f"Container Information:\n" f" CONTAINER ID: {self.container_id}\n" f" IMAGE: {self.image}\n" f" COMMAND: {self.command}\n" f" CREATED: {self.created}\n" f" STATUS: {self.status}\n" f" PORTS: {self.ports}\n" f" NAMES: {self.names}" ) class DockerManager: def __init__(self): self.docker = Docker self._menu_options = { 'view': (MenuOption.VIEW, 'View container info'), 'start': (MenuOption.START, 'Starts the container'), 'stop': (MenuOption.STOP, 'Stops the container'), 'rm': (MenuOption.REMOVE, 'Deletes the container'), 'menu': (MenuOption.MENU, 'Back to the main menu'), 'q': (MenuOption.QUIT, 'Quit the application') } def get_container_info(self, container: str) -> ContainerInfo: """ Retrieves and formats container information. Args: container: Name of the container Returns: ContainerInfo: Structured container information """ info = self.docker.container_info(container) return ContainerInfo( container_id=info["CONTAINER ID"], image=info["IMAGE"], command=info["COMMAND"], created=info["CREATED"], status=info["STATUS"], ports=info["PORTS"], names=info["NAMES"] ) def display_main_menu(self, containers: List[str]) -> None: """Displays the main container selection menu.""" print('\nSelect the container to manage:') for idx, container in enumerate(containers): print(f' {idx} - {container}') print(' q - Quit') def display_container_menu(self, container: str) -> None: """Displays the container management menu.""" print(f'\nContainer: {container}\nAvailable actions:') for cmd, (_, description) in self._menu_options.items(): if cmd not in ['q']: # Exclude quit option from container menu print(f' {cmd} - {description}') def handle_container_removal(self, container: str) -> bool: """ Handles the container removal process with confirmation. Returns: bool: True if container was removed, False otherwise """ while True: confirmation = input( f'\nWARNING! This will DELETE {container}!\n' f'Are you absolutely sure you want to delete {container}? (y/N): ' ).lower() if confirmation in ['y', 'yes']: print('Stopping container...') self.docker.stop(container) print('Deleting container...') self.docker.rm(container) print('Container deleted successfully') return True elif confirmation in ['n', 'no', '']: print(f'Operation cancelled, returning to {container} menu...') return False else: print('Invalid input. Please enter y/N') def validate_container_selection(self, selection: str, containers: List[str]) -> int: """ Validates the container selection input. Returns: int: Valid container index Raises: ValueError: If selection is invalid """ try: index = int(selection) if 0 <= index < len(containers): return index raise ValueError except ValueError: raise ValueError("Invalid container selection") def run(self) -> None: """Main application loop.""" try: while True: if not self.docker.containers_exist(): raise NoContainersError('No containers exist! Please create a container and try again.') containers = self.docker.containers() self.display_main_menu(containers) selection = input().strip() if selection == 'q': print("\nExiting application...") sys.exit(0) try: container_index = self.validate_container_selection(selection, containers) except ValueError: print("Invalid selection. Please try again.") continue container = containers[container_index] while True: self.display_container_menu(container) action = input().strip().lower() if action not in self._menu_options: print('Invalid selection. Please try again.') continue option = self._menu_options[action][0] if option == MenuOption.MENU: break elif option == MenuOption.VIEW: print(self.get_container_info(container)) elif option == MenuOption.START: print('Starting container...') self.docker.start(container) print('Container started successfully') elif option == MenuOption.STOP: print('Stopping container...') self.docker.stop(container) print('Container stopped successfully') elif option == MenuOption.REMOVE: if self.handle_container_removal(container): break elif option == MenuOption.QUIT: print("\nExiting application...") sys.exit(0) except NoContainersError as e: print(f'Error: {e}') print('No containers found. Exiting...') sys.exit(1) except KeyboardInterrupt: print("\nOperation cancelled by user. Exiting...") sys.exit(0) except Exception as e: print(f"An unexpected error occurred: {e}") sys.exit(1) if __name__ == "__main__": manager = DockerManager() manager.run()