373 lines
9.8 KiB
Bash
Executable File
373 lines
9.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Silo Deployment Script
|
|
# Deploys silod to silo.kindred.internal via systemd
|
|
#
|
|
# Usage:
|
|
# ./scripts/deploy.sh [options]
|
|
#
|
|
# Options:
|
|
# --build-only Only build the binary, don't deploy
|
|
# --no-build Skip build, deploy existing binary
|
|
# --restart-only Only restart the service
|
|
# --dry-run Show what would be done without doing it
|
|
# --help Show this help message
|
|
#
|
|
# Environment variables:
|
|
# SILO_HOST Target host (default: silo.kindred.internal)
|
|
# SILO_USER SSH user (default: deploy)
|
|
# SILO_SSH_KEY Path to SSH private key (optional)
|
|
# BUILD_VERSION Version string for build (default: git describe)
|
|
|
|
set -euo pipefail
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Configuration
|
|
SILO_HOST="${SILO_HOST:-silo.kindred.internal}"
|
|
SILO_USER="${SILO_USER:-deploy}"
|
|
SILO_SSH_KEY="${SILO_SSH_KEY:-}"
|
|
BUILD_VERSION="${BUILD_VERSION:-$(git describe --tags --always --dirty 2>/dev/null || echo "dev")}"
|
|
|
|
# Paths
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
BUILD_DIR="${PROJECT_ROOT}/build/out"
|
|
BINARY_NAME="silod"
|
|
|
|
# Remote paths
|
|
REMOTE_BIN_DIR="/opt/silo/bin"
|
|
REMOTE_CONFIG_DIR="/etc/silo"
|
|
REMOTE_SCHEMAS_DIR="/etc/silo/schemas"
|
|
REMOTE_SERVICE="silod"
|
|
|
|
# Flags
|
|
BUILD=true
|
|
DEPLOY=true
|
|
DRY_RUN=false
|
|
|
|
# Functions
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $*"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[OK]${NC} $*"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $*"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $*" >&2
|
|
}
|
|
|
|
die() {
|
|
log_error "$*"
|
|
exit 1
|
|
}
|
|
|
|
show_help() {
|
|
head -20 "$0" | grep -E '^#' | sed 's/^# *//'
|
|
exit 0
|
|
}
|
|
|
|
ssh_cmd() {
|
|
local ssh_opts=(-o StrictHostKeyChecking=accept-new -o ConnectTimeout=10)
|
|
if [[ -n "${SILO_SSH_KEY}" ]]; then
|
|
ssh_opts+=(-i "${SILO_SSH_KEY}")
|
|
fi
|
|
|
|
if [[ "${DRY_RUN}" == "true" ]]; then
|
|
echo "[DRY-RUN] ssh ${ssh_opts[*]} ${SILO_USER}@${SILO_HOST} $*"
|
|
else
|
|
ssh "${ssh_opts[@]}" "${SILO_USER}@${SILO_HOST}" "$@"
|
|
fi
|
|
}
|
|
|
|
scp_cmd() {
|
|
local scp_opts=(-o StrictHostKeyChecking=accept-new -o ConnectTimeout=10)
|
|
if [[ -n "${SILO_SSH_KEY}" ]]; then
|
|
scp_opts+=(-i "${SILO_SSH_KEY}")
|
|
fi
|
|
|
|
if [[ "${DRY_RUN}" == "true" ]]; then
|
|
echo "[DRY-RUN] scp ${scp_opts[*]} $*"
|
|
else
|
|
scp "${scp_opts[@]}" "$@"
|
|
fi
|
|
}
|
|
|
|
check_dependencies() {
|
|
log_info "Checking dependencies..."
|
|
|
|
local missing=()
|
|
|
|
command -v go >/dev/null 2>&1 || missing+=("go")
|
|
command -v ssh >/dev/null 2>&1 || missing+=("ssh")
|
|
command -v scp >/dev/null 2>&1 || missing+=("scp")
|
|
command -v git >/dev/null 2>&1 || missing+=("git")
|
|
|
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
|
die "Missing required commands: ${missing[*]}"
|
|
fi
|
|
|
|
log_success "All dependencies available"
|
|
}
|
|
|
|
check_connectivity() {
|
|
log_info "Checking connectivity to ${SILO_HOST}..."
|
|
|
|
if [[ "${DRY_RUN}" == "true" ]]; then
|
|
log_info "[DRY-RUN] Would check SSH connectivity"
|
|
return 0
|
|
fi
|
|
|
|
if ! ssh_cmd "echo 'Connection successful'" >/dev/null 2>&1; then
|
|
die "Cannot connect to ${SILO_HOST} as ${SILO_USER}"
|
|
fi
|
|
|
|
log_success "SSH connection verified"
|
|
}
|
|
|
|
build_binary() {
|
|
log_info "Building ${BINARY_NAME} (version: ${BUILD_VERSION})..."
|
|
|
|
mkdir -p "${BUILD_DIR}"
|
|
|
|
local ldflags="-w -s -X main.Version=${BUILD_VERSION}"
|
|
|
|
if [[ "${DRY_RUN}" == "true" ]]; then
|
|
echo "[DRY-RUN] CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags=\"${ldflags}\" -o ${BUILD_DIR}/${BINARY_NAME} ./cmd/silod"
|
|
return 0
|
|
fi
|
|
|
|
cd "${PROJECT_ROOT}"
|
|
|
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
|
|
go build -ldflags="${ldflags}" \
|
|
-o "${BUILD_DIR}/${BINARY_NAME}" \
|
|
./cmd/silod
|
|
|
|
if [[ ! -f "${BUILD_DIR}/${BINARY_NAME}" ]]; then
|
|
die "Build failed: binary not found"
|
|
fi
|
|
|
|
local size
|
|
size=$(du -h "${BUILD_DIR}/${BINARY_NAME}" | cut -f1)
|
|
log_success "Built ${BINARY_NAME} (${size})"
|
|
}
|
|
|
|
deploy_binary() {
|
|
log_info "Deploying binary to ${SILO_HOST}..."
|
|
|
|
local binary="${BUILD_DIR}/${BINARY_NAME}"
|
|
|
|
if [[ ! -f "${binary}" ]] && [[ "${DRY_RUN}" != "true" ]]; then
|
|
die "Binary not found: ${binary}"
|
|
fi
|
|
|
|
# Upload to temp location first
|
|
scp_cmd "${binary}" "${SILO_USER}@${SILO_HOST}:/tmp/${BINARY_NAME}.new"
|
|
|
|
# Move to final location with sudo
|
|
ssh_cmd "sudo mv /tmp/${BINARY_NAME}.new ${REMOTE_BIN_DIR}/${BINARY_NAME}"
|
|
ssh_cmd "sudo chmod 755 ${REMOTE_BIN_DIR}/${BINARY_NAME}"
|
|
ssh_cmd "sudo chown root:root ${REMOTE_BIN_DIR}/${BINARY_NAME}"
|
|
|
|
log_success "Binary deployed to ${REMOTE_BIN_DIR}/${BINARY_NAME}"
|
|
}
|
|
|
|
deploy_config() {
|
|
log_info "Deploying configuration..."
|
|
|
|
local config_file="${PROJECT_ROOT}/deployments/config.prod.yaml"
|
|
|
|
if [[ ! -f "${config_file}" ]] && [[ "${DRY_RUN}" != "true" ]]; then
|
|
die "Config file not found: ${config_file}"
|
|
fi
|
|
|
|
scp_cmd "${config_file}" "${SILO_USER}@${SILO_HOST}:/tmp/config.yaml"
|
|
ssh_cmd "sudo mv /tmp/config.yaml ${REMOTE_CONFIG_DIR}/config.yaml"
|
|
ssh_cmd "sudo chmod 644 ${REMOTE_CONFIG_DIR}/config.yaml"
|
|
ssh_cmd "sudo chown root:silo ${REMOTE_CONFIG_DIR}/config.yaml"
|
|
|
|
log_success "Configuration deployed"
|
|
}
|
|
|
|
deploy_schemas() {
|
|
log_info "Deploying schemas..."
|
|
|
|
local schemas_dir="${PROJECT_ROOT}/schemas"
|
|
|
|
if [[ ! -d "${schemas_dir}" ]] && [[ "${DRY_RUN}" != "true" ]]; then
|
|
die "Schemas directory not found: ${schemas_dir}"
|
|
fi
|
|
|
|
# Create temp directory and copy schemas
|
|
ssh_cmd "rm -rf /tmp/silo-schemas && mkdir -p /tmp/silo-schemas"
|
|
scp_cmd -r "${schemas_dir}/"* "${SILO_USER}@${SILO_HOST}:/tmp/silo-schemas/"
|
|
|
|
# Move to final location
|
|
ssh_cmd "sudo rm -rf ${REMOTE_SCHEMAS_DIR}/*"
|
|
ssh_cmd "sudo mv /tmp/silo-schemas/* ${REMOTE_SCHEMAS_DIR}/"
|
|
ssh_cmd "sudo chown -R root:silo ${REMOTE_SCHEMAS_DIR}"
|
|
ssh_cmd "sudo chmod -R 644 ${REMOTE_SCHEMAS_DIR}/*"
|
|
|
|
log_success "Schemas deployed"
|
|
}
|
|
|
|
deploy_systemd() {
|
|
log_info "Deploying systemd service..."
|
|
|
|
local service_file="${PROJECT_ROOT}/deployments/systemd/silod.service"
|
|
|
|
if [[ ! -f "${service_file}" ]] && [[ "${DRY_RUN}" != "true" ]]; then
|
|
die "Service file not found: ${service_file}"
|
|
fi
|
|
|
|
scp_cmd "${service_file}" "${SILO_USER}@${SILO_HOST}:/tmp/silod.service"
|
|
ssh_cmd "sudo mv /tmp/silod.service /etc/systemd/system/silod.service"
|
|
ssh_cmd "sudo chmod 644 /etc/systemd/system/silod.service"
|
|
ssh_cmd "sudo systemctl daemon-reload"
|
|
|
|
log_success "Systemd service deployed"
|
|
}
|
|
|
|
restart_service() {
|
|
log_info "Restarting ${REMOTE_SERVICE} service..."
|
|
|
|
ssh_cmd "sudo systemctl restart ${REMOTE_SERVICE}"
|
|
|
|
# Wait for service to start
|
|
sleep 2
|
|
|
|
if [[ "${DRY_RUN}" != "true" ]]; then
|
|
if ssh_cmd "sudo systemctl is-active --quiet ${REMOTE_SERVICE}"; then
|
|
log_success "Service restarted successfully"
|
|
else
|
|
log_error "Service failed to start"
|
|
ssh_cmd "sudo journalctl -u ${REMOTE_SERVICE} -n 20 --no-pager" || true
|
|
die "Deployment failed: service not running"
|
|
fi
|
|
else
|
|
log_info "[DRY-RUN] Would verify service is running"
|
|
fi
|
|
}
|
|
|
|
verify_deployment() {
|
|
log_info "Verifying deployment..."
|
|
|
|
if [[ "${DRY_RUN}" == "true" ]]; then
|
|
log_info "[DRY-RUN] Would verify health endpoints"
|
|
return 0
|
|
fi
|
|
|
|
# Wait a moment for service to fully start
|
|
sleep 3
|
|
|
|
# Check health endpoint
|
|
local health_status
|
|
health_status=$(ssh_cmd "curl -sf http://localhost:8080/health" 2>/dev/null || echo "FAILED")
|
|
|
|
if [[ "${health_status}" == *"ok"* ]] || [[ "${health_status}" == *"healthy"* ]]; then
|
|
log_success "Health check passed"
|
|
else
|
|
log_warn "Health check returned: ${health_status}"
|
|
fi
|
|
|
|
# Check ready endpoint (includes DB and MinIO)
|
|
local ready_status
|
|
ready_status=$(ssh_cmd "curl -sf http://localhost:8080/ready" 2>/dev/null || echo "FAILED")
|
|
|
|
if [[ "${ready_status}" == *"ok"* ]] || [[ "${ready_status}" == *"ready"* ]]; then
|
|
log_success "Readiness check passed (DB and MinIO connected)"
|
|
else
|
|
log_warn "Readiness check returned: ${ready_status}"
|
|
log_warn "Service may still be starting or external services unavailable"
|
|
fi
|
|
|
|
# Show deployed version
|
|
local deployed_version
|
|
deployed_version=$(ssh_cmd "${REMOTE_BIN_DIR}/${BINARY_NAME} --version" 2>/dev/null || echo "unknown")
|
|
log_info "Deployed version: ${deployed_version}"
|
|
}
|
|
|
|
enable_service() {
|
|
log_info "Enabling ${REMOTE_SERVICE} service..."
|
|
ssh_cmd "sudo systemctl enable ${REMOTE_SERVICE}"
|
|
log_success "Service enabled for auto-start"
|
|
}
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--build-only)
|
|
DEPLOY=false
|
|
shift
|
|
;;
|
|
--no-build)
|
|
BUILD=false
|
|
shift
|
|
;;
|
|
--restart-only)
|
|
BUILD=false
|
|
DEPLOY=false
|
|
restart_service
|
|
exit 0
|
|
;;
|
|
--dry-run)
|
|
DRY_RUN=true
|
|
shift
|
|
;;
|
|
--help|-h)
|
|
show_help
|
|
;;
|
|
*)
|
|
die "Unknown option: $1"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Main execution
|
|
main() {
|
|
log_info "Silo Deployment Script"
|
|
log_info "======================"
|
|
log_info "Target: ${SILO_USER}@${SILO_HOST}"
|
|
log_info "Version: ${BUILD_VERSION}"
|
|
|
|
if [[ "${DRY_RUN}" == "true" ]]; then
|
|
log_warn "DRY-RUN MODE: No changes will be made"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
check_dependencies
|
|
|
|
if [[ "${BUILD}" == "true" ]]; then
|
|
build_binary
|
|
fi
|
|
|
|
if [[ "${DEPLOY}" == "true" ]]; then
|
|
check_connectivity
|
|
deploy_binary
|
|
deploy_config
|
|
deploy_schemas
|
|
deploy_systemd
|
|
enable_service
|
|
restart_service
|
|
verify_deployment
|
|
fi
|
|
|
|
echo ""
|
|
log_success "Deployment complete!"
|
|
}
|
|
|
|
main "$@"
|