diff --git a/TEMPLATES.md b/TEMPLATES.md new file mode 100644 index 0000000..9103526 --- /dev/null +++ b/TEMPLATES.md @@ -0,0 +1,358 @@ +# Dropshell Template Guide + +This guide explains how to create templates for Dropshell - a system management tool for deploying and managing services on remote servers via Docker containers. + +## Template Structure + +Every template must follow this directory structure: + +``` +template-name/ +├── config/ +│ ├── .template_info.env # REQUIRED: Template metadata +│ └── service.env # REQUIRED: Default service configuration +├── install.sh # REQUIRED: Installation script +├── uninstall.sh # REQUIRED: Uninstallation script +├── start.sh # OPTIONAL: Start the service +├── stop.sh # OPTIONAL: Stop the service +├── status.sh # OPTIONAL: Check service status +├── logs.sh # OPTIONAL: View service logs +├── backup.sh # OPTIONAL: Backup service data +├── restore.sh # OPTIONAL: Restore service data +├── destroy.sh # OPTIONAL: Destroy service and data +├── ssh.sh # OPTIONAL: SSH into service container +├── ports.sh # OPTIONAL: List exposed ports +└── README.txt # OPTIONAL: Template documentation +``` + +## Essential Files + +### 1. config/.template_info.env + +Template metadata file that defines the template and its requirements: + +```bash +# Template identifier - MUST match the directory name +TEMPLATE=template-name + +# Requirements +REQUIRES_HOST_ROOT=false # Whether root access on host is needed +REQUIRES_DOCKER=true # Whether Docker is required +REQUIRES_DOCKER_ROOT=false # Whether Docker root privileges are needed + +# Docker image settings +IMAGE_REGISTRY="docker.io" +IMAGE_REPO="vendor/image" +IMAGE_TAG="latest" + +# Volume definitions (if needed) +DATA_VOLUME="${CONTAINER_NAME}_data" +CONFIG_VOLUME="${CONTAINER_NAME}_config" +``` + +### 2. config/service.env + +Default service configuration that can be overridden per deployment: + +```bash +# Service-specific settings +CONTAINER_NAME=service-name +IMAGE_TAG="latest" + +# Server settings +SSH_USER="root" + +# Service-specific variables +# (Add any configuration specific to your service) +``` + +### 3. install.sh + +Installation script that sets up the service: + +```bash +#!/bin/bash +source "${AGENT_PATH}/common.sh" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Check required environment variables +_check_required_env_vars "CONTAINER_NAME" "IMAGE_REGISTRY" "IMAGE_REPO" "IMAGE_TAG" + +# Check Docker is available +_check_docker_installed || _die "Docker test failed" + +# Pull the Docker image +docker pull "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" || _die "Failed to pull image" + +# Stop any existing container +bash ./stop.sh || _die "Failed to stop container" + +# Remove old container +_remove_container "$CONTAINER_NAME" || _die "Failed to remove container" + +# Start the new container +bash ./start.sh || _die "Failed to start container" + +echo "Installation of ${CONTAINER_NAME} complete" +``` + +### 4. uninstall.sh + +Uninstallation script to remove the service: + +```bash +#!/bin/bash +source "${AGENT_PATH}/common.sh" +_check_required_env_vars "CONTAINER_NAME" + +# Stop the container +bash ./stop.sh || _die "Failed to stop container" + +# Remove the container +_remove_container "$CONTAINER_NAME" || _die "Failed to remove container" + +# Optionally remove volumes (with confirmation) +# _remove_volume "$DATA_VOLUME" + +echo "Uninstallation of ${CONTAINER_NAME} complete" +``` + +## Optional Command Scripts + +### start.sh +Starts the Docker container with appropriate configuration: + +```bash +#!/bin/bash +source "${AGENT_PATH}/common.sh" +_check_required_env_vars "CONTAINER_NAME" "IMAGE_REGISTRY" "IMAGE_REPO" "IMAGE_TAG" + +docker run -d \ + --name "$CONTAINER_NAME" \ + --restart unless-stopped \ + -v "$DATA_VOLUME:/data" \ + "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" +``` + +### stop.sh +Stops the running container: + +```bash +#!/bin/bash +source "${AGENT_PATH}/common.sh" +_check_required_env_vars "CONTAINER_NAME" + +docker stop "$CONTAINER_NAME" 2>/dev/null || true +``` + +### status.sh +Reports the service status: + +```bash +#!/bin/bash +source "${AGENT_PATH}/common.sh" +_check_required_env_vars "CONTAINER_NAME" + +if docker ps --format "table {{.Names}}" | grep -q "^${CONTAINER_NAME}$"; then + echo "Running" +else + echo "Stopped" +fi +``` + +### logs.sh +Shows container logs: + +```bash +#!/bin/bash +source "${AGENT_PATH}/common.sh" +_check_required_env_vars "CONTAINER_NAME" + +docker logs "$CONTAINER_NAME" "$@" +``` + +### backup.sh / restore.sh +Handle data backup and restoration for services with persistent data. + +## Common Functions (from common.sh) + +Templates have access to these utility functions: + +- `_check_required_env_vars VAR1 VAR2 ...` - Verify required variables are set +- `_die "message"` - Exit with error message +- `_check_docker_installed` - Verify Docker is available +- `_remove_container NAME` - Safely remove a container +- `create_items ITEM1 ITEM2 ...` - Create volumes or networks +- `_remove_volume NAME` - Remove a Docker volume + +## Environment Variables + +Templates receive these variables at runtime: + +- `AGENT_PATH` - Path to the Dropshell agent directory +- `CONFIG_PATH` - Path to the service configuration directory +- `SCRIPT_DIR` - Directory containing the template scripts +- All variables from `.template_info.env` and `service.env` + +## Validation Requirements + +Templates must pass these validation checks: + +1. **Required files exist**: `config/.template_info.env`, `config/service.env`, `install.sh`, `uninstall.sh` +2. **Scripts are executable**: All `.sh` files must have execute permissions +3. **TEMPLATE variable matches**: The `TEMPLATE` variable in `.template_info.env` must match the directory name +4. **Valid environment files**: Both `.env` files must be parseable + +## Best Practices + +1. **Always use `_check_required_env_vars`** at the start of scripts to validate inputs +2. **Handle errors gracefully** with `|| _die "Error message"` +3. **Use Docker volumes** for persistent data that survives container recreation +4. **Document configuration** in README.txt for users +5. **Support idempotency** - scripts should handle being run multiple times +6. **Clean up properly** in uninstall/destroy scripts +7. **Use standard naming** - volumes as `${CONTAINER_NAME}_data`, configs as `${CONTAINER_NAME}_config` +8. **Test thoroughly** - use `dropshell test-template ` to validate + +## Examples + +### Example 1: Basic Web Server (Nginx) + +A minimal template for deploying an Nginx web server: + +``` +nginx-server/ +├── config/ +│ ├── .template_info.env +│ └── service.env +├── install.sh +├── uninstall.sh +├── start.sh +├── stop.sh +└── logs.sh +``` + +`.template_info.env`: +```bash +TEMPLATE=nginx-server +REQUIRES_DOCKER=true +REQUIRES_DOCKER_ROOT=false +IMAGE_REGISTRY="docker.io" +IMAGE_REPO="nginx" +CONTENT_VOLUME="${CONTAINER_NAME}_content" +``` + +`service.env`: +```bash +CONTAINER_NAME=nginx-server +IMAGE_TAG="alpine" +HTTP_PORT=8080 +``` + +`start.sh`: +```bash +#!/bin/bash +source "${AGENT_PATH}/common.sh" +_check_required_env_vars "CONTAINER_NAME" "IMAGE_REGISTRY" "IMAGE_REPO" "IMAGE_TAG" "HTTP_PORT" + +docker run -d \ + --name "$CONTAINER_NAME" \ + --restart unless-stopped \ + -p "${HTTP_PORT}:80" \ + -v "${CONTENT_VOLUME}:/usr/share/nginx/html:ro" \ + "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" +``` + +### Example 2: Stateful Application with Persistent Storage + +A more complex template for a database or application requiring data persistence, configuration files, and network settings: + +``` +postgres-db/ +├── config/ +│ ├── .template_info.env +│ ├── service.env +│ └── postgres.conf # Additional config files +├── install.sh +├── uninstall.sh +├── start.sh +├── stop.sh +├── status.sh +├── backup.sh # Data backup +├── restore.sh # Data restoration +├── destroy.sh # Complete cleanup including volumes +├── logs.sh +└── README.txt +``` + +`.template_info.env`: +```bash +TEMPLATE=postgres-db +REQUIRES_DOCKER=true +REQUIRES_DOCKER_ROOT=true # Needed for volume management +IMAGE_REGISTRY="docker.io" +IMAGE_REPO="postgres" + +# Multiple volumes for different purposes +DATA_VOLUME="${CONTAINER_NAME}_data" +BACKUP_VOLUME="${CONTAINER_NAME}_backup" +CONFIG_VOLUME="${CONTAINER_NAME}_config" +``` + +`service.env`: +```bash +CONTAINER_NAME=postgres-db +IMAGE_TAG="15-alpine" +DB_PORT=5432 +POSTGRES_PASSWORD="changeme" +POSTGRES_USER="admin" +POSTGRES_DB="myapp" +``` + +`backup.sh`: +```bash +#!/bin/bash +source "${AGENT_PATH}/common.sh" +_check_required_env_vars "CONTAINER_NAME" "BACKUP_VOLUME" "POSTGRES_USER" "POSTGRES_DB" + +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +BACKUP_FILE="backup_${TIMESTAMP}.sql" + +echo "Creating backup ${BACKUP_FILE}..." +docker exec "$CONTAINER_NAME" pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" > "/tmp/${BACKUP_FILE}" +docker cp "/tmp/${BACKUP_FILE}" "${CONTAINER_NAME}:/${BACKUP_VOLUME}/${BACKUP_FILE}" +rm "/tmp/${BACKUP_FILE}" + +echo "Backup completed: ${BACKUP_FILE}" +``` + +`destroy.sh`: +```bash +#!/bin/bash +source "${AGENT_PATH}/common.sh" +_check_required_env_vars "CONTAINER_NAME" "DATA_VOLUME" "BACKUP_VOLUME" "CONFIG_VOLUME" + +echo "WARNING: This will destroy all data for ${CONTAINER_NAME}" +read -p "Are you sure? (yes/no): " confirm + +if [ "$confirm" = "yes" ]; then + bash ./stop.sh + _remove_container "$CONTAINER_NAME" + _remove_volume "$DATA_VOLUME" + _remove_volume "$BACKUP_VOLUME" + _remove_volume "$CONFIG_VOLUME" + echo "Service and all data destroyed" +else + echo "Cancelled" +fi +``` + +## Testing Templates + +After creating a template, validate it: + +```bash +dropshell test-template /path/to/template +``` + +This checks all requirements and reports any issues. \ No newline at end of file