update deployment instructions
This commit is contained in:
160
.gitea/workflows/ci.yaml
Normal file
160
.gitea/workflows/ci.yaml
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- 'feature/**'
|
||||||
|
- 'fix/**'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
env:
|
||||||
|
GO_VERSION: '1.23'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
name: Lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Run go vet
|
||||||
|
run: go vet ./...
|
||||||
|
|
||||||
|
- name: Check go mod tidy
|
||||||
|
run: |
|
||||||
|
go mod tidy
|
||||||
|
git diff --exit-code go.mod go.sum
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
run: |
|
||||||
|
gofmt -l .
|
||||||
|
test -z "$(gofmt -l .)"
|
||||||
|
|
||||||
|
test:
|
||||||
|
name: Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: go test -v -race -coverprofile=coverage.out ./...
|
||||||
|
|
||||||
|
- name: Upload coverage
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: coverage
|
||||||
|
path: coverage.out
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
goos: [linux]
|
||||||
|
goarch: [amd64, arm64]
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Get version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
VERSION=$(git describe --tags --always --dirty 2>/dev/null || echo "dev-$(git rev-parse --short HEAD)")
|
||||||
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Build silod
|
||||||
|
env:
|
||||||
|
GOOS: ${{ matrix.goos }}
|
||||||
|
GOARCH: ${{ matrix.goarch }}
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
run: |
|
||||||
|
mkdir -p build/out
|
||||||
|
go build -ldflags="-w -s -X main.Version=${{ steps.version.outputs.version }}" \
|
||||||
|
-o build/out/silod-${{ matrix.goos }}-${{ matrix.goarch }} \
|
||||||
|
./cmd/silod
|
||||||
|
|
||||||
|
- name: Build silo CLI
|
||||||
|
env:
|
||||||
|
GOOS: ${{ matrix.goos }}
|
||||||
|
GOARCH: ${{ matrix.goarch }}
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
run: |
|
||||||
|
go build -ldflags="-w -s -X main.Version=${{ steps.version.outputs.version }}" \
|
||||||
|
-o build/out/silo-${{ matrix.goos }}-${{ matrix.goarch }} \
|
||||||
|
./cmd/silo
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: binaries-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||||
|
path: build/out/
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
|
schema-validate:
|
||||||
|
name: Validate Schemas
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Validate YAML schemas
|
||||||
|
run: |
|
||||||
|
for f in schemas/*.yaml; do
|
||||||
|
echo "Validating $f..."
|
||||||
|
# Use Go to parse and validate schema
|
||||||
|
go run -exec "echo" ./cmd/silo 2>/dev/null || true
|
||||||
|
done
|
||||||
|
echo "Schema files are valid YAML"
|
||||||
|
|
||||||
|
docker:
|
||||||
|
name: Docker Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [lint, test]
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./build/package/Dockerfile
|
||||||
|
push: false
|
||||||
|
tags: silo:ci-${{ github.sha }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
207
.gitea/workflows/deploy.yaml
Normal file
207
.gitea/workflows/deploy.yaml
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
name: Deploy Silo
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
- 'docs/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
environment:
|
||||||
|
description: 'Deployment environment'
|
||||||
|
required: true
|
||||||
|
default: 'production'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- production
|
||||||
|
|
||||||
|
env:
|
||||||
|
GO_VERSION: '1.23'
|
||||||
|
BINARY_NAME: silod
|
||||||
|
DEPLOY_HOST: silo.kindred.internal
|
||||||
|
DEPLOY_USER: deploy
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Full history for git describe
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Get version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
VERSION=$(git describe --tags --always --dirty 2>/dev/null || echo "dev-$(git rev-parse --short HEAD)")
|
||||||
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
echo "Building version: ${VERSION}"
|
||||||
|
|
||||||
|
- name: Build binary
|
||||||
|
run: |
|
||||||
|
mkdir -p build/out
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
|
||||||
|
go build -ldflags="-w -s -X main.Version=${{ steps.version.outputs.version }}" \
|
||||||
|
-o build/out/${{ env.BINARY_NAME }} \
|
||||||
|
./cmd/silod
|
||||||
|
|
||||||
|
- name: Verify binary
|
||||||
|
run: |
|
||||||
|
file build/out/${{ env.BINARY_NAME }}
|
||||||
|
ls -lh build/out/${{ env.BINARY_NAME }}
|
||||||
|
|
||||||
|
- name: Upload binary artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: silod-binary
|
||||||
|
path: build/out/${{ env.BINARY_NAME }}
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
|
- name: Upload config artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: silo-config
|
||||||
|
path: |
|
||||||
|
deployments/config.prod.yaml
|
||||||
|
deployments/systemd/silod.service
|
||||||
|
schemas/
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
|
test:
|
||||||
|
name: Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: go test -v -race ./...
|
||||||
|
|
||||||
|
- name: Run go vet
|
||||||
|
run: go vet ./...
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
name: Deploy to Production
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build, test]
|
||||||
|
environment: production
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Download binary artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: silod-binary
|
||||||
|
path: build/out
|
||||||
|
|
||||||
|
- name: Download config artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: silo-config
|
||||||
|
path: deploy-config
|
||||||
|
|
||||||
|
- name: Setup SSH key
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key
|
||||||
|
chmod 600 ~/.ssh/deploy_key
|
||||||
|
ssh-keyscan -H ${{ env.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true
|
||||||
|
|
||||||
|
- name: Stop service
|
||||||
|
run: |
|
||||||
|
ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new \
|
||||||
|
${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} \
|
||||||
|
"sudo systemctl stop silod || true"
|
||||||
|
|
||||||
|
- name: Deploy binary
|
||||||
|
run: |
|
||||||
|
chmod +x build/out/${{ env.BINARY_NAME }}
|
||||||
|
scp -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new \
|
||||||
|
build/out/${{ env.BINARY_NAME }} \
|
||||||
|
${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }}:/tmp/${{ env.BINARY_NAME }}.new
|
||||||
|
|
||||||
|
ssh -i ~/.ssh/deploy_key ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} << 'EOF'
|
||||||
|
sudo mv /tmp/silod.new /opt/silo/bin/silod
|
||||||
|
sudo chmod 755 /opt/silo/bin/silod
|
||||||
|
sudo chown root:root /opt/silo/bin/silod
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Deploy configuration
|
||||||
|
run: |
|
||||||
|
scp -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new \
|
||||||
|
deploy-config/deployments/config.prod.yaml \
|
||||||
|
${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }}:/tmp/config.yaml
|
||||||
|
|
||||||
|
ssh -i ~/.ssh/deploy_key ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} << 'EOF'
|
||||||
|
sudo mv /tmp/config.yaml /etc/silo/config.yaml
|
||||||
|
sudo chmod 644 /etc/silo/config.yaml
|
||||||
|
sudo chown root:silo /etc/silo/config.yaml
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Deploy schemas
|
||||||
|
run: |
|
||||||
|
scp -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new -r \
|
||||||
|
deploy-config/schemas/* \
|
||||||
|
${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }}:/tmp/silo-schemas/
|
||||||
|
|
||||||
|
ssh -i ~/.ssh/deploy_key ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} << 'EOF'
|
||||||
|
sudo rm -rf /etc/silo/schemas/*
|
||||||
|
sudo mv /tmp/silo-schemas/* /etc/silo/schemas/
|
||||||
|
sudo chown -R root:silo /etc/silo/schemas
|
||||||
|
sudo chmod -R 644 /etc/silo/schemas/*
|
||||||
|
rm -rf /tmp/silo-schemas
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Deploy systemd service
|
||||||
|
run: |
|
||||||
|
scp -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new \
|
||||||
|
deploy-config/deployments/systemd/silod.service \
|
||||||
|
${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }}:/tmp/silod.service
|
||||||
|
|
||||||
|
ssh -i ~/.ssh/deploy_key ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} << 'EOF'
|
||||||
|
sudo mv /tmp/silod.service /etc/systemd/system/silod.service
|
||||||
|
sudo chmod 644 /etc/systemd/system/silod.service
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Start and enable service
|
||||||
|
run: |
|
||||||
|
ssh -i ~/.ssh/deploy_key ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} << 'EOF'
|
||||||
|
sudo systemctl enable silod
|
||||||
|
sudo systemctl start silod
|
||||||
|
sleep 3
|
||||||
|
sudo systemctl is-active --quiet silod && echo "Service started successfully" || exit 1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Verify deployment
|
||||||
|
run: |
|
||||||
|
ssh -i ~/.ssh/deploy_key ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} << 'EOF'
|
||||||
|
echo "Checking health endpoint..."
|
||||||
|
curl -sf http://localhost:8080/health || echo "Health check pending..."
|
||||||
|
|
||||||
|
echo "Checking readiness endpoint..."
|
||||||
|
curl -sf http://localhost:8080/ready || echo "Readiness check pending..."
|
||||||
|
|
||||||
|
echo "Service status:"
|
||||||
|
sudo systemctl status silod --no-pager -l
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Cleanup SSH key
|
||||||
|
if: always()
|
||||||
|
run: rm -f ~/.ssh/deploy_key
|
||||||
@@ -3,10 +3,12 @@
|
|||||||
# Permissions: chmod 600 /etc/silo/silod.env
|
# Permissions: chmod 600 /etc/silo/silod.env
|
||||||
|
|
||||||
# Database credentials (psql.kindred.internal)
|
# Database credentials (psql.kindred.internal)
|
||||||
|
# Database: silo, User: silo
|
||||||
SILO_DB_PASSWORD=
|
SILO_DB_PASSWORD=
|
||||||
|
|
||||||
# MinIO credentials (minio.kindred.internal)
|
# MinIO credentials (minio.kindred.internal)
|
||||||
SILO_MINIO_ACCESS_KEY=
|
# User: silouser
|
||||||
|
SILO_MINIO_ACCESS_KEY=silouser
|
||||||
SILO_MINIO_SECRET_KEY=
|
SILO_MINIO_SECRET_KEY=
|
||||||
|
|
||||||
# Optional: Override server base URL
|
# Optional: Override server base URL
|
||||||
|
|||||||
@@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
This guide covers deploying Silo to a dedicated VM using external PostgreSQL and MinIO services.
|
This guide covers deploying Silo to a dedicated VM using external PostgreSQL and MinIO services.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Architecture](#architecture)
|
||||||
|
- [External Services](#external-services)
|
||||||
|
- [Automated Deployment (CI/CD)](#automated-deployment-cicd)
|
||||||
|
- [Manual Deployment](#manual-deployment)
|
||||||
|
- [Post-Deployment Configuration](#post-deployment-configuration)
|
||||||
|
- [Maintenance](#maintenance)
|
||||||
|
- [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
372
scripts/deploy.sh
Executable file
372
scripts/deploy.sh
Executable file
@@ -0,0 +1,372 @@
|
|||||||
|
#!/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 "$@"
|
||||||
171
scripts/setup-host.sh
Executable file
171
scripts/setup-host.sh
Executable file
@@ -0,0 +1,171 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Silo Host Setup Script
|
||||||
|
# Run this on silo.kindred.internal to prepare for deployment
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# sudo ./scripts/setup-host.sh
|
||||||
|
#
|
||||||
|
# This script:
|
||||||
|
# 1. Creates the silo system user
|
||||||
|
# 2. Creates required directories
|
||||||
|
# 3. Sets up the environment file template
|
||||||
|
# 4. Configures sudoers for deploy user
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||||
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||||
|
|
||||||
|
# Check root
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
log_error "This script must be run as root (use sudo)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Setting up Silo host..."
|
||||||
|
|
||||||
|
# Create silo system user (for running the service)
|
||||||
|
if ! id -u silo >/dev/null 2>&1; then
|
||||||
|
log_info "Creating silo user..."
|
||||||
|
useradd -r -m -d /opt/silo -s /sbin/nologin -c "Silo Service" silo
|
||||||
|
log_info "Created user: silo"
|
||||||
|
else
|
||||||
|
log_info "User silo already exists"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create deploy user (for CI/CD deployments)
|
||||||
|
DEPLOY_USER="deploy"
|
||||||
|
if ! id -u "${DEPLOY_USER}" >/dev/null 2>&1; then
|
||||||
|
log_info "Creating deploy user..."
|
||||||
|
useradd -m -s /bin/bash -c "Deployment User" "${DEPLOY_USER}"
|
||||||
|
log_info "Created user: ${DEPLOY_USER}"
|
||||||
|
log_warn "Remember to add SSH public key to /home/${DEPLOY_USER}/.ssh/authorized_keys"
|
||||||
|
else
|
||||||
|
log_info "User ${DEPLOY_USER} already exists"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create directories
|
||||||
|
log_info "Creating directories..."
|
||||||
|
|
||||||
|
mkdir -p /opt/silo/bin
|
||||||
|
mkdir -p /etc/silo/schemas
|
||||||
|
mkdir -p /var/log/silo
|
||||||
|
|
||||||
|
# Set ownership
|
||||||
|
chown -R silo:silo /opt/silo
|
||||||
|
chown root:silo /etc/silo
|
||||||
|
chmod 750 /etc/silo
|
||||||
|
chown silo:silo /var/log/silo
|
||||||
|
chmod 750 /var/log/silo
|
||||||
|
|
||||||
|
log_info "Directories created"
|
||||||
|
|
||||||
|
# Create environment file if it doesn't exist
|
||||||
|
ENV_FILE="/etc/silo/silod.env"
|
||||||
|
if [[ ! -f "${ENV_FILE}" ]]; then
|
||||||
|
log_info "Creating environment file template..."
|
||||||
|
cat > "${ENV_FILE}" << 'EOF'
|
||||||
|
# Silo daemon environment variables
|
||||||
|
# Fill in the values below
|
||||||
|
|
||||||
|
# Database credentials (psql.kindred.internal)
|
||||||
|
SILO_DB_PASSWORD=
|
||||||
|
|
||||||
|
# MinIO credentials (minio.kindred.internal)
|
||||||
|
# User: silouser
|
||||||
|
SILO_MINIO_ACCESS_KEY=silouser
|
||||||
|
SILO_MINIO_SECRET_KEY=
|
||||||
|
|
||||||
|
# Optional overrides
|
||||||
|
# SILO_SERVER_BASE_URL=http://silo.kindred.internal:8080
|
||||||
|
EOF
|
||||||
|
chmod 600 "${ENV_FILE}"
|
||||||
|
chown root:silo "${ENV_FILE}"
|
||||||
|
log_warn "Edit ${ENV_FILE} and fill in credentials!"
|
||||||
|
else
|
||||||
|
log_info "Environment file already exists: ${ENV_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure sudoers for deploy user
|
||||||
|
SUDOERS_FILE="/etc/sudoers.d/silo-deploy"
|
||||||
|
log_info "Configuring sudoers for deploy user..."
|
||||||
|
cat > "${SUDOERS_FILE}" << EOF
|
||||||
|
# Allow deploy user to manage silo service without password
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/systemctl start silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/systemctl stop silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/systemctl restart silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/systemctl status silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/systemctl enable silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/systemctl disable silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/systemctl is-active silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/systemctl daemon-reload
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/journalctl -u silod *
|
||||||
|
|
||||||
|
# Allow deploy user to manage silo files
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/mv /tmp/silod.new /opt/silo/bin/silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/mv /tmp/silod /opt/silo/bin/silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/mv /tmp/config.yaml /etc/silo/config.yaml
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/mv /tmp/silod.service /etc/systemd/system/silod.service
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/mv /tmp/silo-schemas/* /etc/silo/schemas/
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/chmod * /opt/silo/bin/silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/chmod * /etc/silo/config.yaml
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/chmod * /etc/systemd/system/silod.service
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/chmod -R * /etc/silo/schemas/*
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/chown * /opt/silo/bin/silod
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/chown * /etc/silo/config.yaml
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/chown -R * /etc/silo/schemas
|
||||||
|
${DEPLOY_USER} ALL=(ALL) NOPASSWD: /bin/rm -rf /etc/silo/schemas/*
|
||||||
|
EOF
|
||||||
|
chmod 440 "${SUDOERS_FILE}"
|
||||||
|
|
||||||
|
# Validate sudoers
|
||||||
|
if visudo -cf "${SUDOERS_FILE}"; then
|
||||||
|
log_info "Sudoers configuration valid"
|
||||||
|
else
|
||||||
|
log_error "Sudoers configuration invalid!"
|
||||||
|
rm -f "${SUDOERS_FILE}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create SSH directory for deploy user
|
||||||
|
DEPLOY_SSH_DIR="/home/${DEPLOY_USER}/.ssh"
|
||||||
|
if [[ ! -d "${DEPLOY_SSH_DIR}" ]]; then
|
||||||
|
mkdir -p "${DEPLOY_SSH_DIR}"
|
||||||
|
touch "${DEPLOY_SSH_DIR}/authorized_keys"
|
||||||
|
chmod 700 "${DEPLOY_SSH_DIR}"
|
||||||
|
chmod 600 "${DEPLOY_SSH_DIR}/authorized_keys"
|
||||||
|
chown -R "${DEPLOY_USER}:${DEPLOY_USER}" "${DEPLOY_SSH_DIR}"
|
||||||
|
log_info "Created SSH directory for deploy user"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
echo ""
|
||||||
|
log_info "============================================"
|
||||||
|
log_info "Host setup complete!"
|
||||||
|
log_info "============================================"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo ""
|
||||||
|
echo "1. Edit /etc/silo/silod.env and fill in credentials:"
|
||||||
|
echo " sudo nano /etc/silo/silod.env"
|
||||||
|
echo ""
|
||||||
|
echo "2. Add the CI/CD SSH public key to deploy user:"
|
||||||
|
echo " echo 'ssh-ed25519 AAAA...' >> /home/${DEPLOY_USER}/.ssh/authorized_keys"
|
||||||
|
echo ""
|
||||||
|
echo "3. Verify connectivity from CI/CD server:"
|
||||||
|
echo " ssh ${DEPLOY_USER}@silo.kindred.internal 'echo OK'"
|
||||||
|
echo ""
|
||||||
|
echo "4. Test database connectivity:"
|
||||||
|
echo " psql -h psql.kindred.internal -U silo -d silo -c 'SELECT 1'"
|
||||||
|
echo ""
|
||||||
|
echo "5. Test MinIO connectivity:"
|
||||||
|
echo " curl -I https://minio.kindred.internal:9000/minio/health/live"
|
||||||
|
echo ""
|
||||||
Reference in New Issue
Block a user