103 lines
4.5 KiB
Bash
Executable File
103 lines
4.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
namespace=asciinema
|
|
rook_namespace=rook-ceph
|
|
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
|
secret_name=asciinema-secrets
|
|
rook_secret=rook-ceph-object-user-my-store-asciinema
|
|
temp_dir=$(mktemp --directory)
|
|
trap 'rm -rf "${temp_dir}"' EXIT HUP INT TERM
|
|
chmod 0700 "${temp_dir}"
|
|
|
|
for command in kubectl jq openssl base64; do
|
|
if ! command -v "${command}" >/dev/null 2>&1; then
|
|
echo "Required command not found: ${command}" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
kubectl apply --filename "${script_dir}/namespace.yaml"
|
|
kubectl apply --filename "${script_dir}/ceph-object-user.yaml"
|
|
|
|
echo "Waiting for Rook to provision the asciinema S3 credentials..."
|
|
for _ in $(seq 1 60); do
|
|
if kubectl get secret "${rook_secret}" --namespace "${rook_namespace}" >/dev/null 2>&1; then
|
|
break
|
|
fi
|
|
sleep 2
|
|
done
|
|
kubectl get secret "${rook_secret}" --namespace "${rook_namespace}" >/dev/null
|
|
|
|
read_secret_file() {
|
|
local source_namespace=$1 source_secret=$2 source_key=$3 destination=$4
|
|
kubectl get secret "${source_secret}" --namespace "${source_namespace}" --output=json \
|
|
| jq --raw-output --join-output --arg key "${source_key}" '.data[$key]' \
|
|
| base64 --decode > "${destination}"
|
|
test -s "${destination}"
|
|
}
|
|
|
|
if kubectl get secret "${secret_name}" --namespace "${namespace}" >/dev/null 2>&1; then
|
|
read_secret_file "${namespace}" "${secret_name}" database-password "${temp_dir}/database-password"
|
|
read_secret_file "${namespace}" "${secret_name}" secret-key-base "${temp_dir}/secret-key-base"
|
|
read_secret_file "${namespace}" "${secret_name}" release-cookie "${temp_dir}/release-cookie"
|
|
else
|
|
openssl rand -hex 32 | tr -d '\r\n' > "${temp_dir}/database-password"
|
|
openssl rand -hex 64 | tr -d '\r\n' > "${temp_dir}/secret-key-base"
|
|
openssl rand -hex 32 | tr -d '\r\n' > "${temp_dir}/release-cookie"
|
|
fi
|
|
|
|
# Environment variables preserve newlines stored in Secret values, whereas
|
|
# command substitution below strips them. Normalize values created by older
|
|
# versions of this installer so the PostgreSQL container and DATABASE_URL see
|
|
# the exact same password.
|
|
for key in database-password secret-key-base release-cookie; do
|
|
value=$(<"${temp_dir}/${key}")
|
|
printf '%s' "${value}" > "${temp_dir}/${key}"
|
|
done
|
|
|
|
# Rook owns and may rotate these credentials. Refresh the namespaced copy on
|
|
# every installation while preserving the database and application secrets.
|
|
read_secret_file "${rook_namespace}" "${rook_secret}" AccessKey "${temp_dir}/s3-access-key-id"
|
|
read_secret_file "${rook_namespace}" "${rook_secret}" SecretKey "${temp_dir}/s3-secret-access-key"
|
|
database_password=$(<"${temp_dir}/database-password")
|
|
printf 'postgresql://asciinema:%s@postgresql.asciinema.svc.cluster.local:5432/asciinema?pool_size=5' \
|
|
"${database_password}" > "${temp_dir}/database-url"
|
|
|
|
kubectl create secret generic "${secret_name}" \
|
|
--namespace "${namespace}" \
|
|
--from-file="database-password=${temp_dir}/database-password" \
|
|
--from-file="database-url=${temp_dir}/database-url" \
|
|
--from-file="secret-key-base=${temp_dir}/secret-key-base" \
|
|
--from-file="release-cookie=${temp_dir}/release-cookie" \
|
|
--from-file="s3-access-key-id=${temp_dir}/s3-access-key-id" \
|
|
--from-file="s3-secret-access-key=${temp_dir}/s3-secret-access-key" \
|
|
--dry-run=client \
|
|
--output=yaml | kubectl apply --filename=-
|
|
|
|
kubectl apply --dry-run=server --filename "${script_dir}/infrastructure.yaml"
|
|
kubectl apply --filename "${script_dir}/infrastructure.yaml"
|
|
kubectl rollout status statefulset/postgresql --namespace "${namespace}" --timeout=10m
|
|
|
|
# Jobs are immutable and bucket bootstrap must be repeatable for restores.
|
|
# Only this exact, disposable Job is replaced.
|
|
kubectl delete job asciinema-bootstrap --namespace "${namespace}" --ignore-not-found
|
|
kubectl apply --filename "${script_dir}/bootstrap.yaml"
|
|
if ! kubectl wait --for=condition=complete job/asciinema-bootstrap \
|
|
--namespace "${namespace}" --timeout=5m; then
|
|
kubectl logs job/asciinema-bootstrap --namespace "${namespace}" --all-containers=true || true
|
|
exit 1
|
|
fi
|
|
|
|
kubectl apply --dry-run=server --filename "${script_dir}/asciinema.yaml"
|
|
kubectl apply --filename "${script_dir}/asciinema.yaml"
|
|
# envFrom values and Secret-backed environment variables are read only when a
|
|
# pod starts. Recreate the sole replica so config changes and rotated RGW keys
|
|
# take effect on every successful installer run.
|
|
kubectl rollout restart deployment/asciinema --namespace "${namespace}"
|
|
kubectl rollout status deployment/asciinema --namespace "${namespace}" --timeout=10m
|
|
|
|
echo
|
|
echo "asciinema is running for https://asciinema.brunner.ninja."
|