#!/bin/bash set -euo pipefail # Dropshell Run - Execute a service command on the remote server # # Usage: ds_run.sh SERVICE COMMAND [args...] # # Remote directory structure: # // |-- server_info.env # // |-- server.json # // |-- backups # // |-- temp_files # // |-- agent # // | |-- bb64 # // | |-- ds_run.sh (this script) # // | |-- common.sh # // | |-- (other agent files) # // |-- services # // |-- service name # // |-- config # // |-- service.env (actual service config) # // |-- template # // |-- (script files) # // |-- template_info.env # // |-- config # // |-- service.env (default service config) # // |-- (other template/example config files) # -- Determine paths -- SCRIPT_PATH="$(readlink -f "${BASH_SOURCE[0]}")" export AGENT_PATH="$(dirname "${SCRIPT_PATH}")" export DROPSHELL_DIR="$(dirname "${AGENT_PATH}")" # -- Source common functions first (needed for _die) -- if [[ ! -f "${AGENT_PATH}/common.sh" ]]; then echo "Error: common.sh not found at ${AGENT_PATH}/common.sh" >&2 exit 1 fi source "${AGENT_PATH}/common.sh" # -- Check agent hash (if AGENT_HASH is provided by dropshell) -- # Exit code 199 = agent mismatch (special code for dropshell to detect) if [[ -n "${AGENT_HASH:-}" ]]; then LOCAL_HASH_FILE="${AGENT_PATH}/agent.hash" if [[ -f "${LOCAL_HASH_FILE}" ]]; then LOCAL_HASH=$(cat "${LOCAL_HASH_FILE}" | tr -d '[:space:]') EXPECTED_HASH=$(echo "${AGENT_HASH}" | tr -d '[:space:]') if [[ "${LOCAL_HASH}" != "${EXPECTED_HASH}" ]]; then echo "AGENT_MISMATCH:${EXPECTED_HASH}:${LOCAL_HASH}" >&2 exit 199 fi else # No local hash file - agent is outdated (pre-hash version) echo "AGENT_MISMATCH:${AGENT_HASH}:no_hash_file" >&2 exit 199 fi fi # -- Validate arguments -- if [[ $# -lt 2 ]]; then echo "Usage: ds_run.sh SERVICE COMMAND [args...]" >&2 exit 1 fi export SERVICE="$1" export DSCOMMAND="$2" shift 2 # Suppress Docker CLI hints export DOCKER_CLI_HINTS=false # -- Set up paths -- export CONFIG_PATH="${DROPSHELL_DIR}/services/${SERVICE}/config" export TEMPLATE_PATH="${DROPSHELL_DIR}/services/${SERVICE}/template" # -- Validate service exists -- [[ -f "${DROPSHELL_DIR}/server_info.env" ]] || _die "Missing ${DROPSHELL_DIR}/server_info.env" [[ -d "${CONFIG_PATH}" ]] || _die "Service '${SERVICE}' does not exist on server (missing ${CONFIG_PATH})" # -- Load template info (template defaults, loaded first) -- export TEMPLATE_INFO_ENV="${TEMPLATE_PATH}/template_info.env" if [[ ! -f "${TEMPLATE_INFO_ENV}" ]]; then TEMPLATE_INFO_ENV="${TEMPLATE_PATH}/config/.template_info.env" fi [[ -f "${TEMPLATE_INFO_ENV}" ]] || _die "Missing template_info.env at ${TEMPLATE_INFO_ENV}" # -- Load service config (overrides template defaults) -- export SERVICE_ENV="${CONFIG_PATH}/service.env" [[ -f "${SERVICE_ENV}" ]] || _die "Missing service.env at ${SERVICE_ENV}" # -- Source env files with auto-export (set -a exports all assigned variables) -- set -a source "${DROPSHELL_DIR}/server_info.env" source "${TEMPLATE_INFO_ENV}" source "${SERVICE_ENV}" set +a # -- Locate and validate command script -- COMMAND_PATH="${TEMPLATE_PATH}" COMMAND_TO_RUN="${COMMAND_PATH}/${DSCOMMAND}" if [[ ! -f "${COMMAND_TO_RUN}" ]]; then COMMAND_TO_RUN="${COMMAND_TO_RUN}.sh" fi [[ -f "${COMMAND_TO_RUN}" ]] || _die "Command not found: ${DSCOMMAND} (looked for ${TEMPLATE_PATH}/${DSCOMMAND}[.sh])" # -- Execute the command with any remaining arguments -- cd "${COMMAND_PATH}" && exec "${COMMAND_TO_RUN}" "$@"