From 460e8e5ecf6a342e7f1aa77e9d9179137dea4a75 Mon Sep 17 00:00:00 2001 From: Viktor Smagin Date: Sat, 14 Mar 2026 03:19:13 +0400 Subject: [PATCH] Initial commit --- .editorconfig | 32 +++ LICENSE | 21 ++ README.md | 530 +++++++++++++++++++++++++++++++++++++++++++++++ clear-registry | 159 ++++++++++++++ collect-registry | 199 ++++++++++++++++++ 5 files changed, 941 insertions(+) create mode 100644 .editorconfig create mode 100644 LICENSE create mode 100644 README.md create mode 100644 clear-registry create mode 100644 collect-registry diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b023b5d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,32 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# All files +[*] +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true + +# Bash, shell, sh +[*.{bash,sh}] +indent_style = space +indent_size = 2 +end_of_line = lf + +# JSON +[*.json] +indent_style = space +indent_size = 2 +end_of_line = lf + +# YAML +[*.{yaml,yml}] +indent_style = space +indent_size = 2 +end_of_line = lf + +# Markdown +[*.md] +trim_trailing_whitespace = false diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8e47450 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Diffteam + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..48bc99b --- /dev/null +++ b/README.md @@ -0,0 +1,530 @@ +# Clear Docker Registry v2 + +A comprehensive automation toolkit for managing and maintaining Docker registries. This project provides two powerful scripts for cleaning up unused container images and optimizing registry storage. + +## Overview + +Docker registries can accumulate many image versions over time, consuming significant disk space. This project offers automated solutions to: + +1. **Clean up old image tags** in remote registries +2. **Run garbage collection** on local Docker registry containers +3. **Free up storage space** by removing unused layers and manifests + +## Scripts + +### 1. `clear-registry` + +**Purpose**: Delete old image tags from a Docker registry while preserving recent versions. + +This script helps manage image versioning by automatically removing old tags, keeping only the latest N versions plus the `latest` tag. + +#### Features + +- Automatically detects and installs required dependencies +- Supports multiple Linux distributions (Debian, Ubuntu, Alpine, Arch, CentOS, Fedora, openSUSE) +- Preserves the `latest` tag automatically +- Provides detailed progress output with visual indicators +- Works with any Docker-compatible registry + +#### Requirements + +- **skopeo** - Tool for working with remote registries +- **jq** - JSON query processor +- **grep** - Text pattern matching +- **sort** - Text sorting +- **head** - Display file/input head + +The script automatically installs missing dependencies if your system's package manager is detected. + +#### Usage + +```bash +./clear-registry [number_of_tags] +``` + +**Arguments:** +- `` (required) - Docker repository URL or name + - Examples: `docker.io/library/alpine`, `myregistry.local:5000/myapp` +- `[number_of_tags]` (optional) - Number of recent tags to keep (default: 3) + +#### Examples + +```bash +# Keep 3 most recent tags of alpine image +./clear-registry docker.io/library/alpine + +# Keep 5 most recent tags from private registry +./clear-registry myregistry.local:5000/myapp 5 + +# Keep 10 versions of specific image +./clear-registry registry.example.com/project/image 10 +``` + +#### How It Works + +1. Validates input arguments +2. Checks and installs required utilities if needed +3. Fetches all tags from the specified repository using skopeo +4. Calculates which tags to delete (keeping N newest + latest) +5. Deletes old tags one by one with confirmation +6. Reports completion with summary + +#### Output Example + +``` +🔍 Fetching list of tags for docker.io/library/alpine... +📦 Will keep 3 recent tags (excluding latest) +📊 Total tags: 10 (including latest) +🗑️ Will be deleted: 6 tags + + ➜ Deleting: v1.0.0 + ✓ Successfully deleted + ➜ Deleting: v1.1.0 + ✓ Successfully deleted +... +✅ Done! +📝 Kept: 3 recent tags and latest +``` + +#### Error Handling + +- **Repository not specified**: Shows usage help and exits +- **Repository unreachable**: Reports connection error +- **Empty repository**: Informs user and exits safely +- **Invalid tag count**: Validates numeric input and provides error message +- **Missing dependencies**: Attempts automatic installation + +--- + +### 2. `collect-registry` + +**Purpose**: Run garbage collection on a Docker registry container to free up disk space. + +Docker registry containers accumulate unused layers and manifests. This script safely runs the built-in garbage collection tool and restarts the registry. + +#### Features + +- Comprehensive container validation (exists and running) +- Automatic configuration file detection with fallback search +- Interactive configuration selection +- Color-coded output for easy reading +- Container status verification after completion +- Support for custom configuration paths +- Handles permission requirements gracefully + +#### Requirements + +- **Docker** - Docker daemon must be running +- **Access** - Sufficient permissions to run `docker exec` and `docker restart` +- **Registry container** - Must have `registry garbage-collect` command available +- **Configuration file** - Must be accessible inside the container + +#### Usage + +```bash +./collect-registry [config_path] +``` + +**Arguments:** +- `` (required) - Name or ID of Docker registry container +- `[config_path]` (optional) - Path to configuration file inside container + +#### Default Configuration Paths + +The script searches for configuration in this order: +1. User-specified path (if provided) +2. `/etc/docker/registry/config.yml` +3. `/etc/distribution/config.yml` +4. Extended search through entire container (if allowed) + +#### Examples + +```bash +# Run GC on container named 'registry' +./collect-registry registry + +# Specify custom configuration path +./collect-registry my-registry-container /etc/distribution/config.yml + +# Use container ID from docker ps +./collect-registry $(docker ps -qf 'name=registry') + +# Custom path inside container +./collect-registry registry /custom/path/config.yml +``` + +#### How It Works + +1. **Validation Phase:** + - Verifies container name argument provided + - Checks container exists + - Verifies container is running + - Reports status and available containers if errors occur + +2. **Configuration Detection Phase:** + - Uses provided path if specified + - Searches standard registry paths + - Offers extended filesystem search if needed + - Allows manual path entry if multiple options found + +3. **Garbage Collection Phase:** + - Executes `registry garbage-collect` command + - Handles execution errors with troubleshooting hints + +4. **Restart Phase:** + - Safely restarts Docker container + - Verifies restart success + +5. **Verification Phase:** + - Shows container status + - Reports configuration file used + +#### Output Example + +``` +[Search] Looking for configuration file in container... + [OK] Configuration file found: /etc/docker/registry/config.yml +[OK] All checks passed +[Info] Using config: /etc/docker/registry/config.yml +[Start] Running garbage collector in container 'registry'... +[OK] Garbage collector executed successfully +[Restart] Restarting container... +[OK] Container successfully restarted +[OK] DONE! Garbage collector completed, container restarted +[Status] Current container status: +registry Up 2 seconds Up 2 seconds +[Info] Configuration file used: /etc/docker/registry/config.yml +``` + +#### Color-Coded Output + +- 🟢 **GREEN [OK]** - Successful operations +- 🔴 **RED [ERR]** - Errors requiring attention +- 🟡 **YELLOW [Warning/List]** - Warnings or information lists +- 🔵 **BLUE [Hint]** - Helpful suggestions + +#### Error Handling + +- **Container not specified**: Shows usage help +- **Container not found**: Lists available containers +- **Container not running**: Suggests starting the container +- **Configuration not found**: Offers extended search option +- **Garbage collection error**: Provides troubleshooting hints +- **Restart failure**: Reports error with next steps + +#### Permission Issues + +The script uses `sudo` for package installation but **NOT** for Docker operations. If you get permission errors: + +```bash +# Add user to docker group +sudo usermod -aG docker $USER + +# Apply new permissions +newgrp docker + +# Or run with sudo +sudo ./collect-registry registry +``` + +--- + +## Installation + +### Quick Start + +1. Clone or download the scripts: + +```bash +cd /path/to/ClearDockerRegistry_v2 +``` + +2. Make scripts executable: + +```bash +chmod +x clear-registry collect-registry +``` + +3. (Optional) Add to PATH: + +```bash +sudo cp clear-registry collect-registry /usr/local/bin/ +``` + +### System Requirements + +- Linux/macOS/WSL environment +- Bash shell (version 4+) +- Docker installed and running (for `collect-registry`) +- `sudo` access for package installation (first run only) + +### Supported Package Managers + +- **apt/apt-get** - Debian, Ubuntu, Linux Mint +- **pacman** - Arch Linux, Manjaro +- **apk** - Alpine Linux +- **yum** - CentOS 7, RHEL 7 +- **dnf** - Fedora, CentOS 8+, RHEL 8+ +- **zypper** - openSUSE + +--- + +## Usage Examples + +### Scenario 1: Clean Up Public Registry + +Clean up old Alpine image versions, keeping only 3 most recent: + +```bash +./clear-registry docker.io/library/alpine 3 +``` + +### Scenario 2: Maintain Private Registry Images + +Clean up multiple images in a private registry: + +```bash +# Keep 5 versions of web app +./clear-registry myregistry.local:5000/myapp/web 5 + +# Keep 10 versions of database +./clear-registry myregistry.local:5000/myapp/db 10 + +# Keep 2 versions of worker (aggressive cleanup) +./clear-registry myregistry.local:5000/myapp/worker 2 +``` + +### Scenario 3: Run Registry Garbage Collection + +After cleaning images, run garbage collection on the registry container: + +```bash +# Find registry container +docker ps | grep registry + +# Run garbage collection and restart +./collect-registry my-docker-registry + +# Or specify config path if non-standard +./collect-registry my-docker-registry /etc/registry/config.yml +``` + +### Scenario 4: Automated Cleanup (Cron Job) + +Add both scripts to cron for periodic maintenance: + +```bash +# Crontab entry - run at 2:00 AM daily +0 2 * * * /usr/local/bin/clear-registry docker.io/library/myapp 5 +5 2 * * * /usr/local/bin/collect-registry my-docker-registry +``` + +--- + +## Troubleshooting + +### clear-registry Issues + +#### Error: "Could not determine package manager" + +**Cause**: System uses an unsupported package manager. + +**Solution**: Install dependencies manually: + +```bash +# Install required packages (Ubuntu example) +sudo apt install -y skopeo jq coreutils +``` + +#### Error: "Could not fetch tag list or repository is empty" + +**Cause**: +- Repository URL is incorrect +- Registry is unreachable +- Repository doesn't exist + +**Solution**: +- Verify URL: `skopeo list-tags docker://your-repo` +- Check registry connectivity: `curl -I https://registry-url/v2/` + +#### Error: "permission denied" during deletion + +**Cause**: Insufficient permissions to delete tags. + +**Solution**: +- Verify registry credentials if using private registry +- Check registry permissions for your account + +### collect-registry Issues + +#### Error: "container not found" + +**Cause**: Container name doesn't match. + +**Solution**: +```bash +# List all containers +docker ps -a | grep registry + +# Use correct container name +./collect-registry correct_name +``` + +#### Error: "container not running" + +**Cause**: Registry container is stopped. + +**Solution**: +```bash +# Start container +docker start registry_name + +# Then run script +./collect-registry registry_name +``` + +#### Error: "Could not find configuration file" + +**Cause**: Registry config not in standard locations. + +**Solution**: +- When prompted, select "Yes" for extended search +- If that fails, find it manually: + +```bash +# Find config inside container +docker exec registry_name find / -name "config.yml" 2>/dev/null + +# Run script with explicit path +./collect-registry registry_name /path/to/config.yml +``` + +#### Error: "Error executing garbage collector" + +**Causes**: +- Insufficient container permissions +- Corrupted registry database +- Registry version incompatibility + +**Solution**: +```bash +# Check registry logs +docker logs registry_name | tail -100 + +# Verify registry health +docker exec registry_name registry --version + +# Try manual garbage collection +docker exec registry_name registry garbage-collect /etc/docker/registry/config.yml +``` + +#### Error: "Error restarting container" + +**Cause**: Docker daemon issues. + +**Solution**: +```bash +# Restart Docker daemon +sudo systemctl restart docker + +# Manually restart container +docker restart registry_name + +# Check container status +docker ps | grep registry_name +``` + +--- + +## Performance Considerations + +### clear-registry + +- **Speed**: Depends on registry size and network connectivity +- **Risk**: Deletion is permanent; deleted tags cannot be recovered +- **Recommendation**: Start with a higher keep count (e.g., 10) and adjust + +### collect-registry + +- **Duration**: Garbage collection time depends on registry size + - Small registries: 1-5 minutes + - Medium registries (10-100GB): 5-30 minutes + - Large registries (>100GB): 30+ minutes +- **Registry Availability**: Registry will be unavailable during restart (~10-30 seconds) +- **Disk Space**: GC may require temporary space equal to max blob size + +--- + +## Best Practices + +1. **Backup First**: Always back up registry data before running GC + +2. **Test on Small Registries**: Verify scripts work with non-critical registries first + +3. **Schedule Off-Peak**: Run garbage collection during low-traffic periods + +4. **Start Conservative**: Keep more tags initially, adjust based on storage trends + +5. **Monitor Logs**: Check container logs after GC completion + +6. **Version Control**: Keep builds/tags with proper versioning scheme to avoid confusion + +7. **Document Changes**: Log which images were cleaned and when + +--- + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +Permission is granted for personal and commercial use, modification, and distribution. + +## Support + +For issues or questions: +1. Check the Troubleshooting section above +2. Review script output for specific error messages +3. Check Docker and registry logs for additional context +4. Verify all prerequisites are installed and configured + +--- + +## Changelog + +### Version 2.0 +- Complete rewrite with improved error handling +- Added configuration validation and auto-detection +- Support for multiple Linux distributions +- Enhanced output with color coding and progress indicators +- Extended configuration search capability +- Better permission and error messaging + +--- + +## Related Commands + +Useful Docker registry commands: + +```bash +# List all running containers +docker ps + +# View registry logs +docker logs registry_name + +# Get container details +docker inspect registry_name + +# Verify registry health +curl https://registry-url/v2/ + +# List all images/tags in registry (using skopeo) +skopeo list-tags docker://registry/image + +# Manual garbage collection +docker exec registry_name registry garbage-collect /etc/docker/registry/config.yml +``` + +--- + +**Last Updated**: March 2026 diff --git a/clear-registry b/clear-registry new file mode 100644 index 0000000..f609a18 --- /dev/null +++ b/clear-registry @@ -0,0 +1,159 @@ +#!/bin/bash + +# Function to check and install required utilities +check_and_install_deps() { + local deps=("skopeo" "jq" "grep" "sort" "head") + local missing_deps=() + + # Check availability of each utility + for dep in "${deps[@]}"; do + if ! command -v "$dep" &> /dev/null; then + missing_deps+=("$dep") + fi + done + + # If all utilities are installed, exit + if [ ${#missing_deps[@]} -eq 0 ]; then + echo "✓ All required utilities are installed." + return 0 + fi + + echo "❌ The following utilities are missing: ${missing_deps[*]}" + echo "🔍 Attempting to install..." + + # Determine package manager and install missing utilities + if command -v apt &> /dev/null; then + # Debian/Ubuntu + sudo apt update + sudo apt install -y "${missing_deps[@]}" + elif command -v apt-get &> /dev/null; then + # Debian/Ubuntu (alternative) + sudo apt-get update + sudo apt-get install -y "${missing_deps[@]}" + elif command -v pacman &> /dev/null; then + # Arch Linux + for dep in "${missing_deps[@]}"; do + case $dep in + "skopeo") + sudo pacman -S --noconfirm skopeo + ;; + "jq") + sudo pacman -S --noconfirm jq + ;; + "grep"|"sort"|"head") + # These utilities are usually part of coreutils + sudo pacman -S --noconfirm coreutils + ;; + esac + done + elif command -v apk &> /dev/null; then + # Alpine Linux + sudo apk add "${missing_deps[@]}" + elif command -v yum &> /dev/null; then + # RHEL/CentOS 7 + sudo yum install -y epel-release + sudo yum install -y "${missing_deps[@]}" + elif command -v dnf &> /dev/null; then + # Fedora/RHEL 8+ + sudo dnf install -y "${missing_deps[@]}" + elif command -v zypper &> /dev/null; then + # openSUSE + sudo zypper install -y "${missing_deps[@]}" + else + echo "❌ Could not determine package manager. Install utilities manually: ${missing_deps[*]}" + exit 1 + fi + + # Check if utilities were installed successfully + local failed_deps=() + for dep in "${missing_deps[@]}"; do + if ! command -v "$dep" &> /dev/null; then + failed_deps+=("$dep") + fi + done + + if [ ${#failed_deps[@]} -gt 0 ]; then + echo "❌ Failed to install: ${failed_deps[*]}" + exit 1 + else + echo "✓ All missing utilities were successfully installed." + fi +} + +# Function to display help +show_help() { + echo "Usage: $0 [number_of_tags]" + echo "" + echo "Arguments:" + echo " - Docker repository URL or name (required)" + echo " [number_of_tags] - number of recent tags to keep (default: 3)" + echo "" + echo "Examples:" + echo " $0 docker.io/library/alpine" + echo " $0 myregistry.local:5000/myapp 5" + echo " $0 registry.example.com/project/image 10" +} + +# Check for the first argument +if [ -z "$1" ]; then + echo "❌ Error: repository not specified" + echo "" + show_help + exit 1 +fi + +# Check and install dependencies +check_and_install_deps + +# Set the number of tags to keep +KEEP_TAGS=${2:-3} + +# Check that the number of tags is a positive number +if ! [[ "$KEEP_TAGS" =~ ^[0-9]+$ ]] || [ "$KEEP_TAGS" -lt 1 ]; then + echo "❌ Error: number of tags must be a positive number" + exit 1 +fi + +echo "🔍 Fetching list of tags for $1..." +echo "📦 Will keep $KEEP_TAGS recent tags (excluding latest)" + +# Fetch all tags +allTags=$(skopeo list-tags docker://"$1" 2>/dev/null | jq -r '.Tags[]') + +if [ -z "$allTags" ]; then + echo "❌ Error: could not fetch tag list or repository is empty" + exit 1 +fi + +# Count total number of tags +totalTags=$(echo "$allTags" | wc -l) + +# Determine how many tags to delete +tagsToDelete=$((totalTags - KEEP_TAGS - 1)) # -1 for latest + +if [ "$tagsToDelete" -le 0 ]; then + echo "✓ Total tags: $totalTags (including latest)" + echo "✓ Nothing to delete, keeping all $totalTags tags" + exit 0 +fi + +# Get tags to delete (exclude latest and keep KEEP_TAGS recent ones) +oldTags=$(echo "$allTags" | grep -v "latest" | sort | head -n -"$KEEP_TAGS") + +echo "📊 Total tags: $totalTags (including latest)" +echo "🗑️ Will be deleted: $(echo "$oldTags" | wc -l) tags" +echo "" + +# Delete old tags +for tag in $oldTags; do + echo " ➜ Deleting: $tag" + if skopeo delete docker://"$1:$tag" 2>/dev/null; then + echo " ✓ Successfully deleted" + else + echo " ❌ Error deleting $tag" + fi +done + +echo "" +echo "✅ Done!" +echo "📝 Kept: $KEEP_TAGS recent tags and latest" diff --git a/collect-registry b/collect-registry new file mode 100644 index 0000000..cbca16e --- /dev/null +++ b/collect-registry @@ -0,0 +1,199 @@ +#!/bin/bash + +# Function to display help +show_help() { + echo "=== Usage: $0 [config_path] ===" + echo "" + echo "Description:" + echo " Runs garbage collector in Docker registry container and restarts it" + echo "" + echo "Arguments:" + echo " - name or ID of Docker registry container (required)" + echo " [config_path] - path to configuration file inside container (optional)" + echo "" + echo "If config path is not specified, script automatically searches in:" + echo " - /etc/docker/registry/config.yml" + echo " - /etc/distribution/config.yml" + echo "" + echo "Examples:" + echo " $0 registry" + echo " $0 my-registry-container" + echo " $0 registry /etc/distribution/config.yml" + echo " $0 \$(docker ps -qf 'name=registry') /custom/path/config.yml" +} + +# Function to find configuration file +find_config() { + local container="$1" + local config_paths=( + "/etc/docker/registry/config.yml" + "/etc/distribution/config.yml" + ) + + # Add custom path if specified + if [ -n "$2" ]; then + config_paths=("$2" "${config_paths[@]}") + fi + + echo "[Search] Looking for configuration file in container..." + + for path in "${config_paths[@]}"; do + if docker exec "$container" test -f "$path" 2>/dev/null; then + echo " [OK] Configuration file found: ${path}" + CONFIG_PATH="$path" + return 0 + else + echo " [-] Not found: ${path}" + fi + done + + return 1 +} + +# Function to find all possible configs +find_all_configs() { + local container="$1" + echo "[Search] Performing extended search for configuration files..." + + # Look for all .yml and .yaml files that could be registry configs + local configs=$(docker exec "$container" find / -type f \( -name "config.yml" -o -name "config.yaml" \) 2>/dev/null | grep -E "(registry|distribution|docker)" | head -10) + + if [ -n "$configs" ]; then + echo " [OK] Possible configuration files found:" + echo "$configs" | nl -w2 -s') ' + + # If exactly one file is found, offer it + local count=$(echo "$configs" | wc -l) + if [ "$count" -eq 1 ]; then + echo "[Question] Configuration file found. Use it?" + read -p "Use $(echo "$configs" | tr -d '\n')? (y/n) " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + CONFIG_PATH=$(echo "$configs" | head -1) + return 0 + fi + fi + + # If multiple files or user refused + echo "[Input] Please specify the path to the configuration file manually:" + read -p "Path to config: " user_path + if [ -n "$user_path" ]; then + if docker exec "$container" test -f "$user_path" 2>/dev/null; then + CONFIG_PATH="$user_path" + return 0 + else + echo " [ERR] File not found: ${user_path}" + fi + fi + fi + + return 1 +} + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Check for the first argument +if [ -z "$1" ]; then + echo -e "${RED}[ERR] Error: container name not specified${NC}" + echo "" + show_help + exit 1 +fi + +CONTAINER_NAME="$1" +CONFIG_PATH="" # Will be determined later + +# Check if container exists (in any state) +if ! docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + echo -e "${RED}[ERR] Error: container '${CONTAINER_NAME}' not found${NC}" + echo "" + echo -e "${YELLOW}[List] Available containers:${NC}" + docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" | head -10 + echo "" + show_help + exit 1 +fi + +# Check if container is running +CONTAINER_STATUS=$(docker inspect --format='{{.State.Status}}' "$CONTAINER_NAME" 2>/dev/null) + +if [ "$CONTAINER_STATUS" != "running" ]; then + echo -e "${RED}[ERR] Error: container '${CONTAINER_NAME}' not running${NC}" + echo -e "${YELLOW}[Status] Current status: ${CONTAINER_STATUS}${NC}" + echo "" + echo -e "${BLUE}[Hint] You can start the container with the command:${NC}" + echo " docker start $CONTAINER_NAME" + exit 1 +fi + +# Determine path to configuration file +if [ -n "$2" ]; then + # If path is specified explicitly, check it + echo "[Search] Checking specified path: ${2}" + if docker exec "$CONTAINER_NAME" test -f "$2" 2>/dev/null; then + CONFIG_PATH="$2" + echo " [OK] Configuration file found" + else + echo -e "${RED} [ERR] Specified file not found: ${2}${NC}" + echo -e "${YELLOW}[Warning] Trying to find automatically...${NC}" + fi +fi + +# If path is not determined, try to find automatically +if [ -z "$CONFIG_PATH" ]; then + if ! find_config "$CONTAINER_NAME" "$2"; then + echo -e "${YELLOW}[Warning] Could not find configuration file in standard paths${NC}" + + # Offer extended search + read -p "[Search] Perform extended search for configuration files? (y/n) " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + if ! find_all_configs "$CONTAINER_NAME"; then + echo -e "${RED}[ERR] Error: Could not find configuration file${NC}" + exit 1 + fi + else + echo -e "${RED}[ERR] Operation canceled${NC}" + exit 1 + fi + fi +fi + +echo -e "${GREEN}[OK] All checks passed${NC}" +echo "[Info] Using config: ${CONFIG_PATH}" +echo "[Start] Running garbage collector in container '${CONTAINER_NAME}'..." + +# Execute garbage collector +if docker exec "$CONTAINER_NAME" registry garbage-collect "$CONFIG_PATH"; then + echo -e "${GREEN}[OK] Garbage collector executed successfully${NC}" +else + echo -e "${RED}[ERR] Error executing garbage collector${NC}" + echo -e "${YELLOW}[Possible causes]:${NC}" + echo " - Insufficient permissions in container" + echo " - Incorrect path to configuration file" + echo " - Registry issues" + exit 1 +fi + +# Restart container +echo "[Restart] Restarting container..." +if docker restart "$CONTAINER_NAME"; then + echo -e "${GREEN}[OK] Container successfully restarted${NC}" +else + echo -e "${RED}[ERR] Error restarting container${NC}" + exit 1 +fi + +echo -e "${GREEN}[OK] DONE! Garbage collector completed, container restarted${NC}" + +# Show container status +echo "[Status] Current container status:" +docker ps --filter "name=$CONTAINER_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.RunningFor}}" | tail -n +2 + +# Show configuration file used +echo "[Info] Configuration file used: ${CONFIG_PATH}"