diff --git a/pm-task b/pm-task index 84b7dd6..4ae6e98 100755 --- a/pm-task +++ b/pm-task @@ -1,352 +1,256 @@ #!/bin/bash -# -# Pod Management Task Script for Docker or Podman. -# -# Do not run `./pm-task` directly, since the `cd` command will not work in this -# way. Instead, run in `source pm-task` pattern. There is already an alias for -# this in the `startup.sh` script, after running that script, simply run 'pm' to -# use this script. -# -# To work with Podman, simply make `docker` an aliase to the `podman` command. -# Image building with docker compose. -function subBuild() { +# Container Management Tasks Script (Docker/Podman) +# Usage: pm-task-v3 [task] +# Tasks: (none), restart, start, stop - if [ -f compose.yaml ] || [ -f docker-compose.yml ] || [ -f container-compose.yml ]; then +CONFIG_FILE="$HOME/.config/pm-task.conf" +WORKSPACE="" - ls -lah - - export RANDOM_UUID=`uuid` - docker compose build - - read -ei Y -p "Restart container(s)? " confirm - if [[ $confirm =~ ^[Yy]$ ]]; then - docker compose down && docker compose up -d - fi - - # read -e -p "Restart nginx service in container? " confirm - # if [[ $confirm =~ ^[Yy]$ ]]; then - # docker exec -d nginx service nginx reload - # fi - - # Assume nginx is always in place. - docker exec -d nginx service nginx reload - - else - echo 'Cannot build (niether compose.yaml, docker-compose.yml nor container-compose.yml is found).' - fi -} - -# Get config file path -function getConfigFile() { - echo "$HOME/.config/pmtask.conf" -} - -# Read docker-workspace from config file, or return empty string -function getWorkspaceFromConfig() { - config_file=$(getConfigFile) - if [ -f "$config_file" ]; then - # Parse INI file for docker-workspace option (skip comments and sections) - while IFS= read -r line || [ -n "$line" ]; do - # Skip empty lines, comments, and section headers - case "$line" in - ''|'#'*|'['*) continue ;; - esac - # Parse key=value - key=$(echo "$line" | cut -d'=' -f1 | tr -d ' ') - value=$(echo "$line" | cut -d'=' -f2- | tr -d ' ') - if [ "$key" = "docker-workspace" ]; then - echo "$value" - return 0 - fi - done < "$config_file" - fi - return 1 -} - -# Save workspace to config file -function saveWorkspaceToConfig() { - config_file=$(getConfigFile) - config_dir=$(dirname "$config_file") - - # Create config directory if it doesn't exist - if [ ! -d "$config_dir" ]; then - mkdir -p "$config_dir" - fi - - # Check if config file exists and has docker-workspace - if [ -f "$config_file" ]; then - # Update existing entry - temp_file=$(mktemp) - found=0 - while IFS= read -r line || [ -n "$line" ]; do - case "$line" in - docker-workspace=*) - echo "docker-workspace=$1" - found=1 - ;; - *) - echo "$line" - ;; - esac - done < "$config_file" > "$temp_file" - - # Append if not found - if [ "$found" -eq 0 ]; then - echo "docker-workspace=$1" >> "$temp_file" - fi - - mv "$temp_file" "$config_file" - else - echo "docker-workspace=$1" > "$config_file" - fi -} - -# List available projects in a workspace and let user choose one. -# Sets PROJECT_LIST (newline-separated) and PROJECT_COUNT globals -function subListProjects() { - workspace="$1" - PROJECT_LIST="" - PROJECT_COUNT=0 - - # Get list of subdirectories (excluding special dirs) - if [ -d "$workspace" ]; then - for dir in "$workspace"/*/; do - [ -d "$dir" ] || continue - bname=$(basename "$dir") - # Skip hidden dirs and README* dirs - case "$bname" in - '.'|'..'|'#'*|''|' '*) continue ;; - README*) continue ;; - esac - PROJECT_COUNT=$((PROJECT_COUNT + 1)) - if [ -z "$PROJECT_LIST" ]; then - PROJECT_LIST="$bname" - else - PROJECT_LIST="$PROJECT_LIST -$bname" - fi - done - fi -} - -function subGotoWorkspace() { - workspace="" - - # If no argument provided, list projects and let user choose - if [ -z "$1" ]; then - # Get workspace from config or prompt user - workspace=$(getWorkspaceFromConfig) - - if [ -z "$workspace" ]; then - # No config, prompt user for workspace - echo "No workspace configured." - echo "Enter workspace path (e.g., $HOME/docker or /mnt/workspace/podman): " - read -r workspace - - if [ -z "$workspace" ]; then - echo "Workspace path cannot be empty." - exit 1 - fi - - # Save to config - saveWorkspaceToConfig "$workspace" - fi - - # Validate workspace exists - if [ ! -d "$workspace" ]; then - echo "Workspace directory does not exist: $workspace" - exit 1 - fi - - PROJECT_LIST="" - PROJECT_COUNT=0 - subListProjects "$workspace" - - if [ "$PROJECT_COUNT" -eq 0 ]; then - echo "No projects found in $workspace" - cd "$workspace" - return 0 - fi - - echo "Available projects in $workspace:" - count=1 - echo "$PROJECT_LIST" | while read -r project; do - echo " [$count] $project" - count=$((count + 1)) - done - echo " [0] Cancel" - - read -r choice - case "$choice" in - ''|*[!0-9]*) - echo "Invalid choice. Canceling." - cd "$workspace" - return 0 - ;; - esac - - if [ "$choice" -eq 0 ]; then - echo "Canceled." - cd "$workspace" - return 0 - fi - - if [ "$choice" -gt "$PROJECT_COUNT" ]; then - echo "Invalid choice. Canceling." - cd "$workspace" - return 0 - fi - - # Get the selected project - selected=$(echo "$PROJECT_LIST" | sed -n "${choice}p") - workspace="$workspace/$selected" - else - # Workspace provided via config, append project name - workspace=$(getWorkspaceFromConfig) - - if [ -z "$workspace" ]; then - # No config, prompt user - echo "No workspace configured." - echo "Enter workspace path: " - read -r workspace - saveWorkspaceToConfig "$workspace" - fi - - workspace="$workspace/$1" - fi - - cd "$workspace" -} - -# Application logs streaming (single log). -function subLogs() { - docker logs -f $POD - # # $1 is $2 of the script. - # if [ $1 ]; then - # # ELABORATE - # docker exec -it $1 tail -s 5 -f /var/www/app/storage/logs/laravel.log - # else - # docker exec -it $POD tail -s 5 -f /var/www/app/storage/logs/laravel.log - # fi -} - -# Application logs streaming (daily log). -function subLogsDaily() { - # $1 is $2 of the script. - if [ $1 ]; then - # ELABORATE - docker exec -it $1 tail -s 5 -f /var/www/app/storage/logs/laravel-$TODAY.log - else - docker exec -it $POD tail -s 5 -f /var/www/app/storage/logs/laravel-$TODAY.log - fi -} - -# Reload service in container (hard-coded, limited usage). -function subReload() { - case $POD in - nginx) - docker exec -it $POD service nginx reload - ;; - *) - # docker exec -it $POD service apache2 reload # No longer using Apache. - docker exec -it $POD service nginx reload - ;; - esac -} - -function subRestart() { - docker compose down && docker compose up -d -} - -# Container shell access. -function subShell() { - # $1 is $2 of the script. - if [ $1 ]; then - docker exec -it $1 bash - else - docker exec -it $POD bash - fi -} - -# Help messages (keep at bottom). ---------------------------------------------- -function subHelp() { - echo "Usage: pm-task [...]" - echo "Commands:" - echo " build, rebuild Build the Docker Compose project." - echo " daily, today Stream daily logs for the current project." - echo " down, stop Stop and remove containers." - echo " logs, log Stream logs for the current project." - echo " ps Watch container stats." - echo " reload Reload the service in the current project." - echo " restart Restart the Docker Compose project." - echo " stats Display container resource usage statistics." - echo " up, start Start the Docker Compose project." - echo " bash|rsh|sh Access a shell in the running container." - echo " (no command) List available projects and choose one to navigate to." -} - -# Task -if [ $1 ]; then - - # Assume the host is running podman when alias docket='podman' exists. - if [ $(type -t docker) == "alias" ]; then - COMMAND='podman' - fi - - # Assumed container is named after the directory name. - TASK=$1 - TODAY=$(date +%Y-%m-%d) - POD=${PWD##*/} - - case $TASK in - bash|rsh|sh) - subShell $2 - ;; - build|rebuild) - subBuild - ;; - daily|today) - subLogsDaily $2 - ;; - down|stop) - docker compose down - ;; - logs|log) - subLogs $2 - ;; - ps) - # Because `watch` has no idea of the alias. - eval "watch -n 10 $COMMAND ps" - ;; - reload) - subReload - ;; - restart) - if [ $2 ]; then - subGotoWorkspace $2 - fi - subRestart $2 - ;; - stats) - docker stats - ;; - up|start) - docker compose up -d - ;; - upgrade) - docker compose pull && docker compose up -d --remove-orphans --force-recreate - ;; - --help) - subHelp - ;; - *) - subGotoWorkspace $TASK - esac - -# Go to the workspace when no argument is provided. -else - echo "Usage: pm-task [...]" - echo "Run 'pm-task --help' for more information." - subGotoWorkspace +# Check if docker command exists +if ! command -v docker &> /dev/null; then + echo "Error: docker command not found." + echo "Please install Docker or configure podman as an alias (or install podman-docker)." + return 1 fi + +# Function to load configuration +load_config() { + if [ ! -f "$CONFIG_FILE" ]; then + echo "Config file not found. Creating new config..." + mkdir -p "$(dirname "$CONFIG_FILE")" + echo "# Configuration file for pm-task" > "$CONFIG_FILE" + echo "# workspace=" >> "$CONFIG_FILE" + fi + + # Source the config file + if [ -f "$CONFIG_FILE" ]; then + # Extract workspace value if it exists + WORKSPACE=$(grep "^workspace=" "$CONFIG_FILE" | cut -d'=' -f2 | tr -d '"') + fi + + # If workspace is not set, ask user + if [ -z "$WORKSPACE" ]; then + echo "Workspace directory not configured." + read -p "Enter your Docker/Podman projects workspace directory: " WORKSPACE + # Save to config file + echo "workspace=$WORKSPACE" >> "$CONFIG_FILE" + echo "Configuration saved to $CONFIG_FILE" + fi +} + +# Function to check for compose file +check_compose_file() { + if [ -f "compose.yaml" ]; then + COMPOSE_FILE="compose.yaml" + elif [ -f "docker-compose.yml" ]; then + COMPOSE_FILE="docker-compose.yml" + elif [ -f "docker-compose.yaml" ]; then + COMPOSE_FILE="docker-compose.yaml" + else + echo "Error: No compose file found in $(basename $PWD)" + echo "Expected one of: compose.yaml, docker-compose.yml, docker-compose.yaml" + return 1 + fi +} + +# Function to build containers +build_containers() { + if [ -f "compose.yaml" ] || [ -f "docker-compose.yml" ] || [ -f "docker-compose.yaml" ]; then + ls -lah + + docker compose build + + read -e -i Y -p "Restart container(s)? " confirm + if [[ $confirm =~ ^[Yy]$ ]]; then + docker compose -f "$COMPOSE_FILE" down && docker compose -f "$COMPOSE_FILE" up -d + fi + + # Check if nginx container is running before reloading + if docker ps --format '{{.Names}}' | grep -q '^nginx$'; then + docker exec -d nginx service nginx reload + else + echo "Warning: nginx container is not running, skipping reload" + fi + else + echo "Error: Cannot build (neither compose.yaml, docker-compose.yml nor docker-compose.yaml is found)." + return 1 + fi +} + +# Function to show menu and select directory +show_menu() { + echo "" + echo "=== Container Management Tasks ===" + echo "Workspace: $WORKSPACE" + echo "" + + # Validate workspace directory exists + if [ ! -d "$WORKSPACE" ]; then + echo "Error: Workspace directory '$WORKSPACE' does not exist." + return 1 + fi + + # Get list of subdirectories (excluding dot directories) + mapfile -t dirs < <(find "$WORKSPACE" -mindepth 1 -maxdepth 1 -type d ! -name '.*' 2>/dev/null | sort) + + if [ ${#dirs[@]} -eq 0 ]; then + echo "No subdirectories found in $WORKSPACE" + return 1 + fi + + echo "Available projects:" + for i in "${!dirs[@]}"; do + echo " $((i+1)). $(basename "${dirs[$i]}")" + done + echo "" + + read -p "Select a project (1-${#dirs[@]}): " choice + + # If user pressed Enter without selection, show workspace contents + if [ -z "$choice" ]; then + echo "Entering Docker/Podman Projects Workspace" + cd "$WORKSPACE" || return 1 + ls -lah "$WORKSPACE" + return 0 + fi + + selected_dir="${dirs[$((choice-1))]}" + + if [ -z "$selected_dir" ] || [ ! -d "$selected_dir" ]; then + echo "Invalid selection" + return 1 + fi + + echo "" + echo "=== Contents of $(basename "$selected_dir") ===" + ls -lah "$selected_dir" +} + +# Function to restart containers +restart_containers() { + echo "Restarting containers in $WORKSPACE..." + cd "$WORKSPACE" || return 1 + + check_compose_file || return 1 + + echo "Stopping containers..." + docker compose -f "$COMPOSE_FILE" down + + echo "Waiting 1 second..." + sleep 1 + + echo "Starting containers..." + docker compose -f "$COMPOSE_FILE" up + + echo "Done!" +} + +# Function to start containers +start_containers() { + echo "Starting containers in $WORKSPACE..." + cd "$WORKSPACE" || return 1 + + check_compose_file || return 1 + + echo "Starting containers..." + docker compose -f "$COMPOSE_FILE" up + echo "Done!" +} + +# Function to stop containers +stop_containers() { + echo "Stopping containers in $WORKSPACE..." + cd "$WORKSPACE" || return 1 + + check_compose_file || return 1 + + echo "Stopping containers..." + docker compose -f "$COMPOSE_FILE" down + echo "Done!" +} + +# Function to run watch docker ps +watch_ps() { + echo "Running 'watch docker ps'..." + watch docker ps +} + +# Function to run docker stats +run_stats() { + echo "Running 'docker stats'..." + docker stats +} + +# Function to run docker logs +run_logs() { + echo "Running 'docker logs -f $(basename $PWD)'..." + docker logs -f "$(basename $PWD)" +} + +# Function to run docker exec bash +run_shell() { + echo "Running 'docker exec -it $(basename $PWD) bash'..." + docker exec -it "$(basename $PWD)" bash +} + +# Main script +main() { + load_config + + task="${1:-}" + + # Handle --help flag + if [ "$task" = "--help" ]; then + echo "Usage: $0 [task]" + echo "Tasks:" + echo " (none) - Show menu and list container projects" + echo " restart - Restart container(s)" + echo " start - Start container(s)" + echo " stop - Stop container(s)" + echo " ps - Watch running containers" + echo " stats - Container statistics" + echo " logs/log - Follow container logs" + echo " sh/bash/shell - Exec into container bash shell" + echo " build/rebuild - Build containers and reload nginx" + return 0 + fi + + case "$task" in + restart) + restart_containers + ;; + start) + start_containers + ;; + stop) + stop_containers + ;; + ps) + watch_ps + ;; + stats) + run_stats + ;; + build|rebuild) + build_containers + ;; + logs|log) + run_logs + ;; + sh|bash|shell) + run_shell + ;; + "") + show_menu + ;; + *) + echo "Unknown task: $task" + echo "Usage: $0 [task]" + echo "Run '$0 --help' for available tasks." + return 1 + ;; + esac +} + +main "$@" diff --git a/pm-task.md b/pm-task.md new file mode 100644 index 0000000..0656946 --- /dev/null +++ b/pm-task.md @@ -0,0 +1,26 @@ +# Container Management Tasks Docker or Podman + +## Purpose + +To work with Podman, simply make `docker` an alias to the `podman` command. + +## Configuration + +- Config file: `$HOME/.config/pm-task.conf` + - Config key `workspace` stores Docker/Podman projects workspace directory + - Prompts user for input if not set, creates config file if it doesn't exist + +## Tasks + +Tasks are defined in the first argument. + +- `(none)` : Shows a numbered list menu of all subdirectories under the workspace directory, navigates to the selected directory, and runs `ls -lah` +- `restart` : Runs `docker compose down`, `sleep 1`, and `docker compose up` commands +- `start` : Runs `docker compose up` command +- `stop` : Runs `docker compose down` command +- `ps` : Runs `watch docker ps` to monitor running containers +- `stats` : Runs `docker stats` to monitor container resource usage +- `logs` / `log` : Runs `docker logs -f ` to follow container logs +- `sh` / `bash` / `shell` : Runs `docker exec -it bash` to access container shell +- `build` / `rebuild` : Builds containers with `docker compose build`, optionally restarts containers, and reloads nginx +- `--help` : Displays available tasks and usage information \ No newline at end of file diff --git a/pm-task-old b/pm1 similarity index 100% rename from pm-task-old rename to pm1 diff --git a/pm2 b/pm2 new file mode 100755 index 0000000..2a828c8 --- /dev/null +++ b/pm2 @@ -0,0 +1,219 @@ +#!/bin/bash +# +# Pod Management Task Script for Docker or Podman. +# +# Do not run `./pm-task` directly, since the `cd` command will not work in this +# way. Instead, run in `source pm-task` pattern. There is already an alias for +# this in the `startup.sh` script, after running that script, simply run 'pm' to +# use this script. +# +# To work with Podman, simply make `docker` an aliase to the `podman` command. + +# Image building with docker compose. +function subBuild() { + + if [ -f compose.yaml ] || [ -f docker-compose.yml ] || [ -f container-compose.yml ]; then + + ls -lah + + export RANDOM_UUID=`uuid` + docker compose build + + read -ei Y -p "Restart container(s)? " confirm + if [[ $confirm =~ ^[Yy]$ ]]; then + docker compose down && docker compose up -d + fi + + # read -e -p "Restart nginx service in container? " confirm + # if [[ $confirm =~ ^[Yy]$ ]]; then + # docker exec -d nginx service nginx reload + # fi + + # Assume nginx is always in place. + docker exec -d nginx service nginx reload + + else + echo 'Cannot build (niether compose.yaml, docker-compose.yml nor container-compose.yml is found).' + fi +} + +function subGotoWorkspace() { + case $HOSTNAME in + Eighty) + if [ $1 ]; then + cd $HOME/docker/$1 + else + cd $HOME/docker + fi + ;; + HiveDC) + if [ $1 ]; then + cd /mnt/workspace/docker/$1 + else + cd /mnt/workspace/docker + fi + ;; + hivegcp) + if [ $1 ]; then + cd $HOME/docker/$1 + else + cd $HOME/docker + fi + ;; + Podman) + if [ $1 ]; then + cd /mnt/workspace/podman/$1 + else + cd /mnt/workspace/podman + fi + ;; + HivePM) + if [ $1 ]; then + cd /mnt/workspace/podman/$1 + else + cd /mnt/workspace/podman + fi + ;; + libpodman) + if [ $1 ]; then + cd /podman/$1 + else + cd /podman + fi + ;; + *) + echo Unrecognized host: $HOSTNAME + ;; + esac +} + +# Application logs streaming (single log). +function subLogs() { + docker logs -f $POD + # # $1 is $2 of the script. + # if [ $1 ]; then + # # ELABORATE + # docker exec -it $1 tail -s 5 -f /var/www/app/storage/logs/laravel.log + # else + # docker exec -it $POD tail -s 5 -f /var/www/app/storage/logs/laravel.log + # fi +} + +# Application logs streaming (daily log). +function subLogsDaily() { + # $1 is $2 of the script. + if [ $1 ]; then + # ELABORATE + docker exec -it $1 tail -s 5 -f /var/www/app/storage/logs/laravel-$TODAY.log + else + docker exec -it $POD tail -s 5 -f /var/www/app/storage/logs/laravel-$TODAY.log + fi +} + +# Reload service in container (hard-coded, limited usage). +function subReload() { + case $POD in + nginx) + docker exec -it $POD service nginx reload + ;; + *) + # docker exec -it $POD service apache2 reload # No longer using Apache. + docker exec -it $POD service nginx reload + ;; + esac +} + +function subRestart() { + docker compose down && docker compose up -d +} + +# Container shell access. +function subShell() { + # $1 is $2 of the script. + if [ $1 ]; then + docker exec -it $1 bash + else + docker exec -it $POD bash + fi +} + +# Help messages (keep at bottom). ---------------------------------------------- +function subHelp() { + echo "Usage: pm-task [...]" + echo "Commands:" + echo " build, rebuild Build the Docker Compose project." + echo " daily, today Stream daily logs for the current project." + echo " down, stop Stop and remove containers." + echo " logs, log Stream logs for the current project." + echo " ps Watch container stats." + echo " reload Reload the service in the current project." + echo " restart Restart the Docker Compose project." + echo " stats Display container resource usage statistics." + echo " up, start Start the Docker Compose project." + echo " bash|rsh|sh Access a shell in the running container." +} + +# Task +if [ $1 ]; then + + # Assume the host is running podman when alias docket='podman' exists. + if [ $(type -t docker) == "alias" ]; then + COMMAND='podman' + fi + + # Assumed container is named after the directory name. + TASK=$1 + TODAY=$(date +%Y-%m-%d) + POD=${PWD##*/} + + case $TASK in + bash|rsh|sh) + subShell $2 + ;; + build|rebuild) + subBuild + ;; + daily|today) + subLogsDaily $2 + ;; + down|stop) + docker compose down + ;; + logs|log) + subLogs $2 + ;; + ps) + # Because `watch` has no idea of the alias. + eval "watch -n 10 $COMMAND ps" + ;; + reload) + subReload + ;; + restart) + if [ $2 ]; then + subGotoWorkspace $2 + fi + subRestart $2 + ;; + stats) + docker stats + ;; + up|start) + docker compose up -d + ;; + upgrade) + docker compose pull && docker compose up -d --remove-orphans --force-recreate + ;; + --help) + subHelp + ;; + *) + subGotoWorkspace $TASK + esac + +# Go to the workspace when no argument is provided. +else + echo "Usage: pm-task [...]" + echo "Run 'pm-task --help' for more information." + subGotoWorkspace +fi