feat: kompose hooks
This commit is contained in:
89
Projects/kompose/CHANGELOG.md
Normal file
89
Projects/kompose/CHANGELOG.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to Kompose will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- **Docker Compose Command Hooks**: Added comprehensive hook system for all Docker Compose commands
|
||||
- Pre and post hooks for: `up`, `down`, `start`, `stop`, `restart`, `build`, `pull`, `logs`, and more
|
||||
- Hooks receive full command arguments as parameters
|
||||
- Post-command hooks only execute on successful command execution
|
||||
- Consistent with existing database hooks pattern
|
||||
|
||||
- **Hook Template**: Added `hooks.sh.template` as a comprehensive reference for creating custom hooks
|
||||
- Includes all available hook types with examples
|
||||
- Provides utility functions and best practices
|
||||
- Serves as a starting point for new stacks
|
||||
|
||||
### Changed
|
||||
|
||||
- **Documentation**: Completely rewrote hooks documentation (`docs/content/3.guide/hooks.md`)
|
||||
- Added comprehensive examples for all hook types
|
||||
- Included real-world use cases (monitoring, backups, cache warming)
|
||||
- Added troubleshooting section
|
||||
- Added security considerations
|
||||
- Added best practices and advanced patterns
|
||||
|
||||
- **Core Script**: Enhanced `execute_stack_command()` function in `kompose.sh`
|
||||
- Added hook execution before and after Docker Compose commands
|
||||
- Improved error handling and exit code management
|
||||
- Hooks properly execute in dry-run mode
|
||||
|
||||
### Documentation Updates
|
||||
|
||||
- Updated CLI help text with complete list of Docker Compose command hooks
|
||||
- Added hook execution flow diagrams
|
||||
- Expanded examples section with practical use cases
|
||||
- Added advanced patterns for conditional execution and hook chaining
|
||||
|
||||
## Hook System
|
||||
|
||||
### Available Hooks
|
||||
|
||||
**Database Hooks:**
|
||||
- `hook_pre_db_export` - Before database export
|
||||
- `hook_post_db_export` - After database export (receives dump file path)
|
||||
- `hook_pre_db_import` - Before database import (receives dump file path)
|
||||
- `hook_post_db_import` - After database import (receives dump file path)
|
||||
|
||||
**Docker Compose Command Hooks:**
|
||||
- `hook_pre_<command>` - Before any Docker Compose command
|
||||
- `hook_post_<command>` - After any Docker Compose command (only on success)
|
||||
|
||||
Supported commands: `up`, `down`, `start`, `stop`, `restart`, `build`, `pull`, `logs`, `ps`, `exec`, `run`, `create`, `kill`, `pause`, `unpause`, `port`, `top`
|
||||
|
||||
### Usage Examples
|
||||
|
||||
```bash
|
||||
# Hooks execute automatically for supported commands
|
||||
./kompose.sh news up -d # Triggers pre_up and post_up hooks
|
||||
./kompose.sh blog restart # Triggers pre_restart and post_restart hooks
|
||||
./kompose.sh "*" down # Triggers pre_down and post_down hooks
|
||||
|
||||
# Test hooks in dry-run mode
|
||||
./kompose.sh news up -d --dry-run
|
||||
```
|
||||
|
||||
### Migration Guide
|
||||
|
||||
For existing stacks with `hooks.sh`:
|
||||
1. No changes required - existing database hooks continue to work
|
||||
2. Optionally add new Docker Compose command hooks as needed
|
||||
3. See `hooks.sh.template` for all available hooks
|
||||
4. Refer to updated documentation for examples and best practices
|
||||
|
||||
---
|
||||
|
||||
## Previous Versions
|
||||
|
||||
### [1.0.0] - Initial Release
|
||||
|
||||
- Basic Docker Compose stack management
|
||||
- Database import/export functionality
|
||||
- Database hooks (pre/post export/import)
|
||||
- Pattern-based stack selection
|
||||
- Environment variable management
|
||||
- Dry-run mode
|
||||
- Stack listing and filtering
|
||||
203
Projects/kompose/HOOKS_QUICKREF.md
Normal file
203
Projects/kompose/HOOKS_QUICKREF.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# Docker Compose Command Hooks - Quick Reference
|
||||
|
||||
## Overview
|
||||
|
||||
Kompose now supports hooks for all Docker Compose commands, similar to the existing database import/export hooks. This allows you to run custom logic before and after any `docker compose` command.
|
||||
|
||||
## What Changed
|
||||
|
||||
### Core Script (`kompose.sh`)
|
||||
- Enhanced `execute_stack_command()` to support pre/post hooks
|
||||
- Hooks automatically execute for supported Docker Compose commands
|
||||
- Post-hooks only run if the command succeeds
|
||||
|
||||
### Documentation
|
||||
- Completely rewritten hooks guide with comprehensive examples
|
||||
- Added template file `hooks.sh.template` for easy setup
|
||||
- Updated help text with complete hook reference
|
||||
|
||||
## Available Hooks
|
||||
|
||||
### Format
|
||||
```bash
|
||||
hook_pre_<command> # Before docker compose <command>
|
||||
hook_post_<command> # After docker compose <command> (only on success)
|
||||
```
|
||||
|
||||
### Supported Commands
|
||||
- **Lifecycle**: `up`, `down`, `start`, `stop`, `restart`
|
||||
- **Build**: `build`, `pull`, `create`
|
||||
- **Monitoring**: `logs`, `ps`, `top`, `port`
|
||||
- **Execution**: `exec`, `run`
|
||||
- **Control**: `kill`, `pause`, `unpause`
|
||||
|
||||
## Quick Examples
|
||||
|
||||
### Example 1: Health Check After Startup
|
||||
|
||||
```bash
|
||||
# In your stack's hooks.sh
|
||||
hook_post_up() {
|
||||
echo " Verifying services are healthy..."
|
||||
sleep 5
|
||||
docker compose ps --format json | jq '.[] | select(.Health == "healthy")'
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Backup Before Shutdown
|
||||
|
||||
```bash
|
||||
hook_pre_down() {
|
||||
echo " Creating backup before shutdown..."
|
||||
./backup.sh
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: Clear Cache Before Restart
|
||||
|
||||
```bash
|
||||
hook_pre_restart() {
|
||||
echo " Clearing application caches..."
|
||||
docker exec ${COMPOSE_PROJECT_NAME}_redis redis-cli FLUSHALL
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
### Example 4: Tag Images After Build
|
||||
|
||||
```bash
|
||||
hook_post_build() {
|
||||
local tag="$(date +%Y%m%d-%H%M%S)"
|
||||
echo " Tagging image with: $tag"
|
||||
docker tag ${COMPOSE_PROJECT_NAME}_app:latest ${COMPOSE_PROJECT_NAME}_app:$tag
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
### 1. Copy Template
|
||||
```bash
|
||||
cp hooks.sh.template your-stack/hooks.sh
|
||||
chmod +x your-stack/hooks.sh
|
||||
```
|
||||
|
||||
### 2. Uncomment Hooks You Need
|
||||
Edit `your-stack/hooks.sh` and uncomment the hooks you want to use.
|
||||
|
||||
### 3. Test in Dry-Run Mode
|
||||
```bash
|
||||
./kompose.sh your-stack up -d --dry-run
|
||||
```
|
||||
|
||||
### 4. Execute
|
||||
```bash
|
||||
./kompose.sh your-stack up -d
|
||||
```
|
||||
|
||||
## Accessing Command Arguments
|
||||
|
||||
Hooks receive the full command and arguments:
|
||||
|
||||
```bash
|
||||
hook_pre_up() {
|
||||
local -a args=("$@")
|
||||
echo " Command: ${args[0]}" # "up"
|
||||
echo " Arguments: ${args[*]}" # "up -d --build"
|
||||
|
||||
# Check for specific flags
|
||||
if [[ " ${args[*]} " =~ " --build " ]]; then
|
||||
echo " Build flag detected!"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Hooks have access to:
|
||||
- `$SCRIPT_DIR` - Root kompose directory
|
||||
- `$stack` - Current stack name
|
||||
- All variables from root and stack `.env` files
|
||||
- CLI overrides from `-e` flags
|
||||
|
||||
## Best Practices
|
||||
|
||||
✅ **DO:**
|
||||
- Return `0` for success, `1` for failure
|
||||
- Use indented output: `echo " Message"`
|
||||
- Check container status before `docker exec`
|
||||
- Test with `--dry-run` first
|
||||
- Make non-critical operations return `0`
|
||||
|
||||
❌ **DON'T:**
|
||||
- Assume containers are running
|
||||
- Use blocking operations without timeouts
|
||||
- Hardcode paths or credentials
|
||||
- Make hooks too complex
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Preview what would happen
|
||||
./kompose.sh news up -d --dry-run
|
||||
|
||||
# Check syntax
|
||||
bash -n your-stack/hooks.sh
|
||||
|
||||
# Debug mode (add to top of hook function)
|
||||
hook_pre_up() {
|
||||
set -x # Enable debug output
|
||||
# your code here
|
||||
set +x # Disable debug output
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
## Real-World Use Cases
|
||||
|
||||
1. **Automated Backups** - Before stopping/rebuilding
|
||||
2. **Health Monitoring** - After starting services
|
||||
3. **Cache Management** - Before/after restarts
|
||||
4. **Image Management** - Tag and push after builds
|
||||
5. **Notifications** - Alert on lifecycle events
|
||||
6. **Data Migration** - Run migrations after deployment
|
||||
7. **Log Rotation** - Before starting new logs
|
||||
8. **Secret Management** - Pull secrets before startup
|
||||
|
||||
## Migration from Old Version
|
||||
|
||||
If you already have `hooks.sh` with database hooks:
|
||||
1. ✅ No changes required - database hooks still work
|
||||
2. ✅ Just add new command hooks as needed
|
||||
3. ✅ All hooks can coexist in the same file
|
||||
|
||||
## Resources
|
||||
|
||||
- **Full Documentation**: `docs/content/3.guide/hooks.md`
|
||||
- **Template**: `hooks.sh.template`
|
||||
- **Example**: `sexy/hooks.sh` (Directus schema management)
|
||||
- **Help**: `./kompose.sh --help`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook not executing?
|
||||
1. Check file permissions: `chmod +x hooks.sh`
|
||||
2. Verify function names: `hook_pre_<command>` or `hook_post_<command>`
|
||||
3. Test with dry-run: `./kompose.sh stack command --dry-run`
|
||||
|
||||
### Hook failing?
|
||||
1. Check return codes: `return 0` for success
|
||||
2. Add debug output: `set -x` at start of function
|
||||
3. Verify container names and status
|
||||
4. Check environment variables are loaded
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
1. Check the documentation: `docs/content/3.guide/hooks.md`
|
||||
2. Review the template: `hooks.sh.template`
|
||||
3. Look at examples: `sexy/hooks.sh`
|
||||
@@ -3,9 +3,11 @@ title: Hooks System
|
||||
description: Extend Kompose with custom hooks
|
||||
---
|
||||
|
||||
Extend Kompose functionality with custom hooks for each stack.
|
||||
Extend Kompose functionality with custom hooks for each stack. Hooks allow you to run custom logic before and after Docker Compose commands and database operations.
|
||||
|
||||
### Available Hooks
|
||||
## Hook Types
|
||||
|
||||
### Database Hooks
|
||||
|
||||
| Hook | Timing | Arguments | Use Case |
|
||||
|------|--------|-----------|----------|
|
||||
@@ -14,76 +16,431 @@ Extend Kompose functionality with custom hooks for each stack.
|
||||
| `hook_pre_db_import` | Before DB import | `$1` = dump file path | Prepare environment, schema setup |
|
||||
| `hook_post_db_import` | After DB import | `$1` = dump file path | Restart services, clear caches |
|
||||
|
||||
### Creating Hooks
|
||||
### Docker Compose Command Hooks
|
||||
|
||||
Create `<stack>/hooks.sh`:
|
||||
All Docker Compose commands support pre and post hooks. The hooks receive the full command arguments.
|
||||
|
||||
| Hook | Timing | Arguments | Use Case |
|
||||
|------|--------|-----------|----------|
|
||||
| `hook_pre_up` | Before `docker compose up` | `$@` = command args | Pre-flight checks, setup |
|
||||
| `hook_post_up` | After `docker compose up` | `$@` = command args | Health checks, initialization |
|
||||
| `hook_pre_down` | Before `docker compose down` | `$@` = command args | Graceful shutdown, backups |
|
||||
| `hook_post_down` | After `docker compose down` | `$@` = command args | Cleanup, notifications |
|
||||
| `hook_pre_start` | Before `docker compose start` | `$@` = command args | Validate state |
|
||||
| `hook_post_start` | After `docker compose start` | `$@` = command args | Verify services |
|
||||
| `hook_pre_stop` | Before `docker compose stop` | `$@` = command args | Save state |
|
||||
| `hook_post_stop` | After `docker compose stop` | `$@` = command args | Cleanup |
|
||||
| `hook_pre_restart` | Before `docker compose restart` | `$@` = command args | Prepare for restart |
|
||||
| `hook_post_restart` | After `docker compose restart` | `$@` = command args | Verify restart |
|
||||
| `hook_pre_build` | Before `docker compose build` | `$@` = command args | Code generation |
|
||||
| `hook_post_build` | After `docker compose build` | `$@` = command args | Tag images, push to registry |
|
||||
| `hook_pre_pull` | Before `docker compose pull` | `$@` = command args | Check registry availability |
|
||||
| `hook_post_pull` | After `docker compose pull` | `$@` = command args | Verify images |
|
||||
| `hook_pre_logs` | Before `docker compose logs` | `$@` = command args | Setup log filters |
|
||||
| `hook_post_logs` | After `docker compose logs` | `$@` = command args | Process logs |
|
||||
|
||||
**Also supported:** `ps`, `exec`, `run`, `create`, `kill`, `pause`, `unpause`, `port`, `top`
|
||||
|
||||
::alert{type="info"}
|
||||
**Note:** Post-command hooks only execute if the Docker Compose command succeeds (exit code 0).
|
||||
::
|
||||
|
||||
## Creating Hooks
|
||||
|
||||
Create `<stack>/hooks.sh` in your stack directory:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Export schema before database export
|
||||
hook_pre_db_export() {
|
||||
echo " Exporting application schema..."
|
||||
docker exec sexy_api npx directus schema snapshot --yes ./schema.yaml
|
||||
# Hook naming convention:
|
||||
# - hook_pre_<command> - runs before the command
|
||||
# - hook_post_<command> - runs after the command (only on success)
|
||||
|
||||
# Example: Setup before starting containers
|
||||
hook_pre_up() {
|
||||
local -a args=("$@")
|
||||
echo " Running pre-flight checks..."
|
||||
|
||||
# Check if required directories exist
|
||||
if [[ ! -d "./uploads" ]]; then
|
||||
echo " Creating uploads directory..."
|
||||
mkdir -p ./uploads
|
||||
fi
|
||||
|
||||
return 0 # 0 = success, 1 = failure
|
||||
}
|
||||
|
||||
# Apply schema before database import
|
||||
hook_pre_db_import() {
|
||||
local dump_file="$1"
|
||||
echo " Applying schema snapshot..."
|
||||
docker exec sexy_api npx directus schema apply --yes ./schema.yaml
|
||||
# Example: Verify services after startup
|
||||
hook_post_up() {
|
||||
local -a args=("$@")
|
||||
echo " Waiting for services to be healthy..."
|
||||
|
||||
# Wait for health check
|
||||
sleep 5
|
||||
|
||||
if docker compose ps | grep -q "healthy"; then
|
||||
echo " ✓ Services are healthy"
|
||||
return 0
|
||||
else
|
||||
echo " ⚠ Warning: Some services may not be healthy"
|
||||
return 0 # Non-critical, don't fail
|
||||
fi
|
||||
}
|
||||
|
||||
# Example: Backup before shutdown
|
||||
hook_pre_down() {
|
||||
echo " Creating backup before shutdown..."
|
||||
./backup.sh
|
||||
return 0
|
||||
}
|
||||
|
||||
# Restart service after import
|
||||
hook_post_db_import() {
|
||||
local dump_file="$1"
|
||||
echo " Restarting application..."
|
||||
docker restart sexy_api
|
||||
# Example: Restart dependent services
|
||||
hook_post_restart() {
|
||||
echo " Restarting dependent services..."
|
||||
# Restart a related service that depends on this stack
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
### Real-World Example: Directus (sexy stack)
|
||||
## Real-World Examples
|
||||
|
||||
The `sexy` stack uses hooks for Directus schema management:
|
||||
### Example 1: Directus Schema Management (sexy stack)
|
||||
|
||||
**Export Flow:**
|
||||
1. `pre_db_export`: Export Directus schema snapshot
|
||||
2. Database export creates SQL dump
|
||||
3. Result: Both database dump + schema snapshot
|
||||
|
||||
**Import Flow:**
|
||||
1. `pre_db_import`: Apply Directus schema from snapshot
|
||||
2. Database import loads SQL dump
|
||||
3. `post_db_import`: Restart Directus container
|
||||
4. Result: Fully synchronized schema + data
|
||||
|
||||
### Testing Hooks
|
||||
The `sexy` stack uses hooks for Directus schema synchronization:
|
||||
|
||||
```bash
|
||||
# Preview hook execution
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Export Directus schema before database export
|
||||
hook_pre_db_export() {
|
||||
local timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local snapshot_file="directus_schema_${timestamp}.yaml"
|
||||
|
||||
echo " Exporting Directus schema snapshot..."
|
||||
|
||||
if docker exec sexy_api npx directus schema snapshot "$snapshot_file" > /dev/null 2>&1; then
|
||||
echo " Schema snapshot saved: $snapshot_file"
|
||||
return 0
|
||||
else
|
||||
echo " Warning: Could not export schema snapshot"
|
||||
return 0 # Don't fail the entire export
|
||||
fi
|
||||
}
|
||||
|
||||
# Import Directus schema before database import
|
||||
hook_pre_db_import() {
|
||||
local dump_file="$1"
|
||||
|
||||
# Find most recent schema snapshot
|
||||
local snapshot_file=$(ls -t directus_schema_*.yaml 2>/dev/null | head -1)
|
||||
|
||||
if [[ -z "$snapshot_file" ]]; then
|
||||
echo " No schema snapshot found, skipping"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo " Applying Directus schema from: $snapshot_file"
|
||||
|
||||
if docker exec sexy_api npx directus schema apply "$snapshot_file" > /dev/null 2>&1; then
|
||||
echo " Schema applied successfully"
|
||||
return 0
|
||||
else
|
||||
echo " Warning: Could not apply schema snapshot"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Reload Directus after import
|
||||
hook_post_db_import() {
|
||||
echo " Restarting Directus to apply changes..."
|
||||
docker restart sexy_api > /dev/null 2>&1
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Health Monitoring
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Send notification when services start
|
||||
hook_post_up() {
|
||||
local -a args=("$@")
|
||||
|
||||
echo " Notifying monitoring system..."
|
||||
|
||||
# Example: Send webhook
|
||||
curl -X POST https://monitoring.example.com/webhook \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"stack\": \"${stack}\", \"status\": \"up\"}" \
|
||||
2>/dev/null
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Alert on shutdown
|
||||
hook_post_down() {
|
||||
echo " Sending shutdown notification..."
|
||||
|
||||
curl -X POST https://monitoring.example.com/webhook \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"stack\": \"${stack}\", \"status\": \"down\"}" \
|
||||
2>/dev/null
|
||||
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: Automated Backups
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Backup volumes before rebuild
|
||||
hook_pre_build() {
|
||||
echo " Backing up volumes before rebuild..."
|
||||
|
||||
local backup_dir="./backups/$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$backup_dir"
|
||||
|
||||
# Backup volumes
|
||||
docker run --rm \
|
||||
-v app_data:/data \
|
||||
-v "$backup_dir:/backup" \
|
||||
alpine tar czf /backup/data.tar.gz -C /data .
|
||||
|
||||
echo " Backup saved to: $backup_dir"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Tag and push after successful build
|
||||
hook_post_build() {
|
||||
echo " Tagging and pushing image..."
|
||||
|
||||
local image="${COMPOSE_PROJECT_NAME}_app"
|
||||
local tag="$(date +%Y%m%d-%H%M%S)"
|
||||
|
||||
docker tag "$image:latest" "$image:$tag"
|
||||
docker push "$image:$tag"
|
||||
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
### Example 4: Cache Warming
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Warm caches after starting
|
||||
hook_post_up() {
|
||||
echo " Warming application caches..."
|
||||
|
||||
# Wait for app to be ready
|
||||
sleep 10
|
||||
|
||||
# Hit cache endpoints
|
||||
curl -s http://localhost:3000/api/cache/warm > /dev/null
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Clear caches before restart
|
||||
hook_pre_restart() {
|
||||
echo " Clearing application caches..."
|
||||
|
||||
docker exec app_container redis-cli FLUSHALL
|
||||
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Execution Flow
|
||||
|
||||
### Database Export Flow
|
||||
```
|
||||
1. hook_pre_db_export
|
||||
2. pg_dump (database export)
|
||||
3. hook_post_db_export (receives dump file path)
|
||||
```
|
||||
|
||||
### Database Import Flow
|
||||
```
|
||||
1. hook_pre_db_import (receives dump file path)
|
||||
2. Database drop & recreate
|
||||
3. psql (database import)
|
||||
4. hook_post_db_import (receives dump file path)
|
||||
```
|
||||
|
||||
### Docker Compose Command Flow
|
||||
```
|
||||
1. hook_pre_<command> (receives command args)
|
||||
2. docker compose <command>
|
||||
3. hook_post_<command> (only if command succeeds, receives command args)
|
||||
```
|
||||
|
||||
## Testing Hooks
|
||||
|
||||
```bash
|
||||
# Preview hook execution with dry-run
|
||||
./kompose.sh sexy db:export --dry-run
|
||||
./kompose.sh sexy up -d --dry-run
|
||||
|
||||
# Execute with hooks
|
||||
./kompose.sh sexy db:export
|
||||
./kompose.sh sexy up -d
|
||||
|
||||
# Import with hooks
|
||||
./kompose.sh sexy db:import
|
||||
# Test specific commands with hooks
|
||||
./kompose.sh news restart
|
||||
./kompose.sh blog build
|
||||
./kompose.sh "*" down
|
||||
```
|
||||
|
||||
### Hook Best Practices
|
||||
## Accessing Command Arguments
|
||||
|
||||
✅ **DO:**
|
||||
- Return 0 for success, 1 for failure
|
||||
- Use indented output: `echo " Message"`
|
||||
- Make non-critical operations return 0
|
||||
- Check container status before `docker exec`
|
||||
- Test in dry-run mode first
|
||||
Hooks receive the full command and its arguments:
|
||||
|
||||
❌ **DON'T:**
|
||||
- Assume containers are running
|
||||
- Use blocking operations without timeouts
|
||||
- Forget error handling
|
||||
- Hardcode paths or credentials
|
||||
```bash
|
||||
hook_pre_up() {
|
||||
local -a args=("$@")
|
||||
|
||||
# Access specific arguments
|
||||
echo " Command: ${args[0]}" # "up"
|
||||
echo " All args: ${args[*]}" # "up -d --build"
|
||||
|
||||
# Check for specific flags
|
||||
if [[ " ${args[*]} " =~ " --build " ]]; then
|
||||
echo " Build flag detected, running pre-build tasks..."
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Best Practices
|
||||
|
||||
### ✅ DO:
|
||||
|
||||
- **Return proper exit codes**: `0` for success, `1` for failure
|
||||
- **Use indented output**: `echo " Message"` for better readability
|
||||
- **Make non-critical operations non-blocking**: Return `0` even on minor failures
|
||||
- **Check container status** before using `docker exec`
|
||||
- **Test in dry-run mode** first: `./kompose.sh stack command --dry-run`
|
||||
- **Use environment variables** available from `.env` files
|
||||
- **Add timeouts** for long-running operations
|
||||
- **Document your hooks** with comments
|
||||
|
||||
### ❌ DON'T:
|
||||
|
||||
- **Assume containers are running** before executing commands
|
||||
- **Use blocking operations** without timeouts
|
||||
- **Forget error handling** for external commands
|
||||
- **Hardcode paths, credentials, or hostnames**
|
||||
- **Perform destructive operations** in `pre_*` hooks without confirmation
|
||||
- **Make hooks too complex** - consider separate scripts if needed
|
||||
- **Ignore exit codes** from important operations
|
||||
|
||||
## Available Environment Variables
|
||||
|
||||
Hooks have access to all environment variables from:
|
||||
- Root `.env` file
|
||||
- Stack-specific `.env` file
|
||||
- CLI overrides (`-e KEY=VALUE`)
|
||||
|
||||
Common variables:
|
||||
```bash
|
||||
$SCRIPT_DIR # Root kompose directory
|
||||
$stack # Current stack name
|
||||
$COMPOSE_PROJECT_NAME
|
||||
$DB_NAME
|
||||
$DB_HOST
|
||||
$DB_PORT
|
||||
$DB_USER
|
||||
$DB_PASSWORD
|
||||
# ... all variables from .env files
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook not executing
|
||||
1. Verify `hooks.sh` has execute permissions: `chmod +x <stack>/hooks.sh`
|
||||
2. Check function naming: `hook_pre_<command>` or `hook_post_<command>`
|
||||
3. Test with dry-run mode to see if hooks are detected
|
||||
4. Check for bash syntax errors: `bash -n <stack>/hooks.sh`
|
||||
|
||||
### Hook failing
|
||||
1. Add `set -x` at the top of your hook for debugging
|
||||
2. Check return codes: `return 0` for success
|
||||
3. Verify container names and states
|
||||
4. Check environment variables are loaded
|
||||
5. Look at Kompose output for error messages
|
||||
|
||||
### Best debugging approach
|
||||
```bash
|
||||
# Enable dry-run to see what would execute
|
||||
./kompose.sh stack command --dry-run
|
||||
|
||||
# Add debug output in your hook
|
||||
hook_pre_up() {
|
||||
echo " [DEBUG] Stack: $stack"
|
||||
echo " [DEBUG] Args: $*"
|
||||
echo " [DEBUG] Container: $(docker ps --filter name=$stack)"
|
||||
# ... your hook logic
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced Patterns
|
||||
|
||||
### Conditional Execution
|
||||
```bash
|
||||
hook_pre_up() {
|
||||
# Only run in production
|
||||
if [[ "${ENVIRONMENT}" == "production" ]]; then
|
||||
echo " Running production pre-flight checks..."
|
||||
./production-checks.sh
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
### Parallel Hook Execution
|
||||
```bash
|
||||
hook_post_up() {
|
||||
echo " Running parallel initialization tasks..."
|
||||
|
||||
# Background jobs
|
||||
(cache_warm) &
|
||||
(index_rebuild) &
|
||||
|
||||
# Wait for all background jobs
|
||||
wait
|
||||
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
### Hook Chaining
|
||||
```bash
|
||||
hook_post_restart() {
|
||||
# Call another stack's command
|
||||
echo " Restarting dependent services..."
|
||||
"${SCRIPT_DIR}/kompose.sh" dependent-stack restart
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Never log sensitive information (passwords, tokens)
|
||||
- Validate user input in hooks that accept parameters
|
||||
- Use quotes around variables to prevent injection
|
||||
- Restrict file permissions on `hooks.sh`: `chmod 750 hooks.sh`
|
||||
- Avoid executing user-supplied data without validation
|
||||
- Use absolute paths or `$SCRIPT_DIR` for file references
|
||||
|
||||
## Related
|
||||
|
||||
- [Database Operations](/guide/database) - Learn about database import/export
|
||||
- [Stack Management](/guide/stack-management) - Managing multiple stacks
|
||||
- [Configuration](/guide/configuration) - Environment variables and settings
|
||||
|
||||
340
Projects/kompose/hooks.sh.template
Normal file
340
Projects/kompose/hooks.sh.template
Normal file
@@ -0,0 +1,340 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Template hooks file for Kompose stacks
|
||||
# Copy this file to your stack directory and uncomment/modify the hooks you need
|
||||
#
|
||||
# Available hooks:
|
||||
# - Database: pre_db_export, post_db_export, pre_db_import, post_db_import
|
||||
# - Docker Compose: pre_<command>, post_<command> for any docker compose command
|
||||
#
|
||||
# Hooks receive command arguments as parameters: $1, $2, etc., or $@ for all args
|
||||
# Return 0 for success, 1 for failure
|
||||
# Post-command hooks only execute if the command succeeds
|
||||
|
||||
# ================================================================================
|
||||
# DATABASE HOOKS
|
||||
# ================================================================================
|
||||
|
||||
# Execute before database export
|
||||
# Use case: Export schemas, prepare data, stop write operations
|
||||
#hook_pre_db_export() {
|
||||
# echo " Running pre-export tasks..."
|
||||
# # Example: Export application schema
|
||||
# # docker exec ${COMPOSE_PROJECT_NAME}_app npm run schema:export
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute after database export
|
||||
# Arguments: $1 = path to the dump file
|
||||
# Use case: Compress dumps, upload to S3, send notifications
|
||||
#hook_post_db_export() {
|
||||
# local dump_file="$1"
|
||||
# echo " Running post-export tasks..."
|
||||
# echo " Dump file: $dump_file"
|
||||
# # Example: Compress dump
|
||||
# # gzip "$dump_file"
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute before database import
|
||||
# Arguments: $1 = path to the dump file
|
||||
# Use case: Prepare environment, load schemas, clear caches
|
||||
#hook_pre_db_import() {
|
||||
# local dump_file="$1"
|
||||
# echo " Running pre-import tasks..."
|
||||
# echo " Importing from: $dump_file"
|
||||
# # Example: Apply schema migrations
|
||||
# # docker exec ${COMPOSE_PROJECT_NAME}_app npm run schema:apply
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute after database import
|
||||
# Arguments: $1 = path to the dump file
|
||||
# Use case: Restart services, rebuild indexes, warm caches
|
||||
#hook_post_db_import() {
|
||||
# local dump_file="$1"
|
||||
# echo " Running post-import tasks..."
|
||||
# # Example: Restart application
|
||||
# # docker restart ${COMPOSE_PROJECT_NAME}_app
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# ================================================================================
|
||||
# DOCKER COMPOSE COMMAND HOOKS
|
||||
# ================================================================================
|
||||
|
||||
# Execute before 'docker compose up'
|
||||
# Arguments: $@ = command arguments (e.g., "up", "-d", "--build")
|
||||
# Use case: Pre-flight checks, create directories, pull secrets
|
||||
#hook_pre_up() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running pre-up checks..."
|
||||
#
|
||||
# # Example: Create required directories
|
||||
# if [[ ! -d "./uploads" ]]; then
|
||||
# echo " Creating uploads directory..."
|
||||
# mkdir -p ./uploads
|
||||
# fi
|
||||
#
|
||||
# # Example: Check for required environment variables
|
||||
# if [[ -z "${API_KEY}" ]]; then
|
||||
# echo " ERROR: API_KEY not set"
|
||||
# return 1
|
||||
# fi
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute after 'docker compose up'
|
||||
# Arguments: $@ = command arguments
|
||||
# Use case: Health checks, initialization, warm caches
|
||||
#hook_post_up() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running post-up tasks..."
|
||||
#
|
||||
# # Example: Wait for services to be healthy
|
||||
# echo " Waiting for services to be healthy..."
|
||||
# sleep 5
|
||||
#
|
||||
# # Example: Initialize application
|
||||
# # docker exec ${COMPOSE_PROJECT_NAME}_app npm run init
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute before 'docker compose down'
|
||||
# Arguments: $@ = command arguments
|
||||
# Use case: Graceful shutdown, backups, save state
|
||||
#hook_pre_down() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running pre-down tasks..."
|
||||
#
|
||||
# # Example: Create backup before shutdown
|
||||
# # ./backup.sh
|
||||
#
|
||||
# # Example: Check for --volumes flag
|
||||
# if [[ " ${args[*]} " =~ " --volumes " ]] || [[ " ${args[*]} " =~ " -v " ]]; then
|
||||
# echo " WARNING: Volumes will be removed!"
|
||||
# # You could add a confirmation prompt here
|
||||
# fi
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute after 'docker compose down'
|
||||
# Arguments: $@ = command arguments
|
||||
# Use case: Cleanup, notifications
|
||||
#hook_post_down() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running post-down tasks..."
|
||||
#
|
||||
# # Example: Send notification
|
||||
# # curl -X POST https://hooks.slack.com/... -d '{"text":"Stack stopped"}'
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute before 'docker compose start'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_pre_start() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running pre-start tasks..."
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute after 'docker compose start'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_post_start() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running post-start tasks..."
|
||||
#
|
||||
# # Example: Verify services are running
|
||||
# # docker compose ps
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute before 'docker compose stop'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_pre_stop() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running pre-stop tasks..."
|
||||
#
|
||||
# # Example: Flush pending writes
|
||||
# # docker exec ${COMPOSE_PROJECT_NAME}_app npm run flush
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute after 'docker compose stop'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_post_stop() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running post-stop tasks..."
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute before 'docker compose restart'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_pre_restart() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running pre-restart tasks..."
|
||||
#
|
||||
# # Example: Clear caches before restart
|
||||
# # docker exec ${COMPOSE_PROJECT_NAME}_redis redis-cli FLUSHALL
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute after 'docker compose restart'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_post_restart() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running post-restart tasks..."
|
||||
#
|
||||
# # Example: Verify services are healthy
|
||||
# # ./health-check.sh
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute before 'docker compose build'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_pre_build() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running pre-build tasks..."
|
||||
#
|
||||
# # Example: Run code generation
|
||||
# # npm run generate
|
||||
#
|
||||
# # Example: Backup current image
|
||||
# # docker tag ${COMPOSE_PROJECT_NAME}_app:latest ${COMPOSE_PROJECT_NAME}_app:backup
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute after 'docker compose build'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_post_build() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running post-build tasks..."
|
||||
#
|
||||
# # Example: Tag and push image
|
||||
# # local tag="$(date +%Y%m%d-%H%M%S)"
|
||||
# # docker tag ${COMPOSE_PROJECT_NAME}_app:latest registry.example.com/app:$tag
|
||||
# # docker push registry.example.com/app:$tag
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute before 'docker compose pull'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_pre_pull() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running pre-pull tasks..."
|
||||
#
|
||||
# # Example: Check registry availability
|
||||
# # curl -f https://registry.example.com/v2/ > /dev/null
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute after 'docker compose pull'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_post_pull() {
|
||||
# local -a args=("$@")
|
||||
# echo " Running post-pull tasks..."
|
||||
#
|
||||
# # Example: Verify pulled images
|
||||
# # docker images | grep ${COMPOSE_PROJECT_NAME}
|
||||
#
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute before 'docker compose logs'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_pre_logs() {
|
||||
# local -a args=("$@")
|
||||
# # Usually not needed, but available if you need it
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# Execute after 'docker compose logs'
|
||||
# Arguments: $@ = command arguments
|
||||
#hook_post_logs() {
|
||||
# local -a args=("$@")
|
||||
# # Usually not needed, but available if you need it
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# ================================================================================
|
||||
# OTHER DOCKER COMPOSE COMMANDS
|
||||
# ================================================================================
|
||||
# The following commands also support pre/post hooks:
|
||||
# - ps, exec, run, create, kill, pause, unpause, port, top
|
||||
#
|
||||
# Example:
|
||||
#hook_pre_ps() {
|
||||
# echo " Listing containers..."
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# ================================================================================
|
||||
# UTILITY FUNCTIONS (Optional)
|
||||
# ================================================================================
|
||||
|
||||
# Helper function to check if a container is running
|
||||
#is_container_running() {
|
||||
# local container_name="$1"
|
||||
# docker ps --format '{{.Names}}' | grep -q "^${container_name}$"
|
||||
#}
|
||||
|
||||
# Helper function to wait for a container to be healthy
|
||||
#wait_for_healthy() {
|
||||
# local container_name="$1"
|
||||
# local max_attempts="${2:-30}"
|
||||
# local attempt=0
|
||||
#
|
||||
# while [[ $attempt -lt $max_attempts ]]; do
|
||||
# if docker inspect --format='{{.State.Health.Status}}' "$container_name" 2>/dev/null | grep -q "healthy"; then
|
||||
# return 0
|
||||
# fi
|
||||
# sleep 1
|
||||
# ((attempt++))
|
||||
# done
|
||||
#
|
||||
# return 1
|
||||
#}
|
||||
|
||||
# Helper function to send notifications
|
||||
#send_notification() {
|
||||
# local message="$1"
|
||||
# # Implement your notification logic here (Slack, Discord, email, etc.)
|
||||
# # curl -X POST https://hooks.slack.com/... -d "{\"text\":\"$message\"}"
|
||||
# return 0
|
||||
#}
|
||||
|
||||
# ================================================================================
|
||||
# NOTES
|
||||
# ================================================================================
|
||||
#
|
||||
# Environment Variables Available:
|
||||
# - $SCRIPT_DIR: Root kompose directory
|
||||
# - $stack: Current stack name
|
||||
# - All variables from root .env and stack .env files
|
||||
# - CLI overrides from -e flags
|
||||
#
|
||||
# Best Practices:
|
||||
# - Return 0 for success, 1 for failure
|
||||
# - Use indented output: echo " Message"
|
||||
# - Make non-critical operations return 0
|
||||
# - Check container status before docker exec
|
||||
# - Test with --dry-run first
|
||||
# - Add timeouts for long operations
|
||||
# - Document your hooks with comments
|
||||
#
|
||||
# Testing:
|
||||
# - Dry run: ./kompose.sh stack command --dry-run
|
||||
# - Check syntax: bash -n hooks.sh
|
||||
# - Debug: Add 'set -x' at the top of your hook function
|
||||
#
|
||||
@@ -452,6 +452,22 @@ execute_stack_command() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract the main command (e.g., "up" from "up -d")
|
||||
local main_command="${cmd[0]}"
|
||||
local hook_name=""
|
||||
|
||||
# Map docker compose commands to hook names
|
||||
case "${main_command}" in
|
||||
up|down|start|stop|restart|pull|build|ps|logs|exec|run|create|kill|pause|unpause|port|top)
|
||||
hook_name="${main_command}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Execute pre-command hook if hook name is determined
|
||||
if [[ -n "${hook_name}" ]]; then
|
||||
execute_hook "${stack}" "pre_${hook_name}" "${cmd[@]}" || return 1
|
||||
fi
|
||||
|
||||
log_stack "${stack}" "Executing: docker compose ${cmd[*]}"
|
||||
|
||||
# Build environment args
|
||||
@@ -464,10 +480,17 @@ execute_stack_command() {
|
||||
fi
|
||||
log_dry_run "cd ${stack_dir} && docker compose${env_str} -f ${compose_file} ${cmd[*]}"
|
||||
log_stack "${stack}" "${CYAN}[DRY-RUN]${RESET} Command would be executed"
|
||||
|
||||
# Execute post-command hook in dry-run mode
|
||||
if [[ -n "${hook_name}" ]]; then
|
||||
execute_hook "${stack}" "post_${hook_name}" "${cmd[@]}" || return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Change to stack directory and execute command
|
||||
local exit_code=0
|
||||
(
|
||||
cd "${stack_dir}"
|
||||
if [[ ${#env_args[@]} -gt 0 ]]; then
|
||||
@@ -475,17 +498,25 @@ execute_stack_command() {
|
||||
log_stack "${stack}" "${GREEN}✓${RESET} Command completed successfully"
|
||||
else
|
||||
log_stack "${stack}" "${RED}✗${RESET} Command failed"
|
||||
return 1
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if docker compose -f "${compose_file}" "${cmd[@]}"; then
|
||||
log_stack "${stack}" "${GREEN}✓${RESET} Command completed successfully"
|
||||
else
|
||||
log_stack "${stack}" "${RED}✗${RESET} Command failed"
|
||||
return 1
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
)
|
||||
exit_code=$?
|
||||
|
||||
# Execute post-command hook if command succeeded and hook name is determined
|
||||
if [[ ${exit_code} -eq 0 ]] && [[ -n "${hook_name}" ]]; then
|
||||
execute_hook "${stack}" "post_${hook_name}" "${cmd[@]}" || return 1
|
||||
fi
|
||||
|
||||
return ${exit_code}
|
||||
}
|
||||
|
||||
# Display help message
|
||||
@@ -542,12 +573,37 @@ DATABASE OPERATIONS:
|
||||
Exports are saved as: <stack-dir>/<db-name>_<timestamp>.sql
|
||||
|
||||
HOOKS:
|
||||
Stacks can define custom hooks in hooks.sh:
|
||||
Stacks can define custom hooks in hooks.sh for lifecycle management.
|
||||
|
||||
Database Hooks:
|
||||
- hook_pre_db_export - Before database export
|
||||
- hook_post_db_export - After database export (receives dump file path)
|
||||
- hook_pre_db_import - Before database import (receives dump file path)
|
||||
- hook_post_db_import - After database import (receives dump file path)
|
||||
|
||||
Docker Compose Command Hooks:
|
||||
- hook_pre_up - Before 'docker compose up' (receives command args)
|
||||
- hook_post_up - After 'docker compose up' (receives command args)
|
||||
- hook_pre_down - Before 'docker compose down'
|
||||
- hook_post_down - After 'docker compose down'
|
||||
- hook_pre_start - Before 'docker compose start'
|
||||
- hook_post_start - After 'docker compose start'
|
||||
- hook_pre_stop - Before 'docker compose stop'
|
||||
- hook_post_stop - After 'docker compose stop'
|
||||
- hook_pre_restart - Before 'docker compose restart'
|
||||
- hook_post_restart - After 'docker compose restart'
|
||||
- hook_pre_logs - Before 'docker compose logs'
|
||||
- hook_post_logs - After 'docker compose logs'
|
||||
- hook_pre_build - Before 'docker compose build'
|
||||
- hook_post_build - After 'docker compose build'
|
||||
- hook_pre_pull - Before 'docker compose pull'
|
||||
- hook_post_pull - After 'docker compose pull'
|
||||
|
||||
And also: ps, exec, run, create, kill, pause, unpause, port, top
|
||||
|
||||
Hook functions receive the full command arguments as parameters.
|
||||
Post-command hooks only execute if the command succeeds.
|
||||
|
||||
Example: sexy stack uses hooks for Directus schema snapshots
|
||||
|
||||
EXAMPLES:
|
||||
|
||||
Reference in New Issue
Block a user