Some checks failed
deploy / deploy (push) Failing after 1m35s
Proof: first non-mocked tradeable loop for one pair using funded NEAR Intents inventory, Kafka, and PostgreSQL. Assumptions: solver-side execution is performed by signed token_diff quote responses over the Solver Relay; EURe is treated as 1:1 with EUR; k3s runtime uses unrip-dev.near as the named signer account. Still fake: signer key is not yet registered on intents.near, strategy and executor remain disarmed by default, and no live mainnet quote response has been submitted from this repo yet.
243 lines
7.9 KiB
Bash
Executable file
243 lines
7.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR=$(cd "$(dirname "$0")/../.." && pwd)
|
|
PLATFORM_REPO_DIR="${PLATFORM_REPO_DIR:-$ROOT_DIR/../unrip3}"
|
|
BOOTSTRAP_ENV_FILE="${BOOTSTRAP_ENV_FILE:-$PLATFORM_REPO_DIR/.state/hetzner/bootstrap-secrets.resolved.env}"
|
|
PLATFORM_APP_ENV_FILE="${PLATFORM_APP_ENV_FILE:-$PLATFORM_REPO_DIR/.env}"
|
|
APP_ENV_FILE="${APP_ENV_FILE:-$ROOT_DIR/.env}"
|
|
FORGEJO_REMOTE_NAME="${FORGEJO_REMOTE_NAME:-forgejo}"
|
|
|
|
PROJECT_NAME="${PROJECT_NAME:-unrip}"
|
|
PROJECT_NAMESPACE="${PROJECT_NAMESPACE:-$PROJECT_NAME}"
|
|
PROJECT_DEPLOYMENTS="${PROJECT_DEPLOYMENTS:-near-intents-ingest,market-reference-ingest,liquidity-manager,inventory-sync,history-writer,strategy-engine,trade-executor}"
|
|
PROJECT_REGISTRY_SECRET_NAME="${PROJECT_REGISTRY_SECRET_NAME:-${PROJECT_NAME}-registry-creds}"
|
|
APP_SECRET_NAME="${APP_SECRET_NAME:-${PROJECT_NAME}-secrets}"
|
|
SYNC_FORGEJO_REMOTE="${SYNC_FORGEJO_REMOTE:-1}"
|
|
|
|
require() {
|
|
command -v "$1" >/dev/null 2>&1 || {
|
|
echo "missing required command: $1" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
load_env_defaults() {
|
|
local file="$1"
|
|
[[ -f "$file" ]] || return 0
|
|
|
|
eval "$(
|
|
python3 - "$file" <<'PY'
|
|
import os
|
|
import shlex
|
|
import sys
|
|
|
|
for raw in open(sys.argv[1], 'r', encoding='utf-8'):
|
|
line = raw.strip()
|
|
if not line or line.startswith('#'):
|
|
continue
|
|
if line.startswith('export '):
|
|
line = line[len('export '):]
|
|
if '=' not in line:
|
|
continue
|
|
key, value = line.split('=', 1)
|
|
key = key.strip()
|
|
if key in os.environ:
|
|
continue
|
|
print(f'export {key}={shlex.quote(value)}')
|
|
PY
|
|
)"
|
|
}
|
|
|
|
require git
|
|
require kubectl
|
|
require python3
|
|
require base64
|
|
|
|
load_env_defaults "$BOOTSTRAP_ENV_FILE"
|
|
load_env_defaults "$PLATFORM_APP_ENV_FILE"
|
|
load_env_defaults "$APP_ENV_FILE"
|
|
|
|
REMOTE_URL="${FORGEJO_REMOTE_URL:-$(git -C "$ROOT_DIR" remote get-url "$FORGEJO_REMOTE_NAME")}"
|
|
eval "$(
|
|
python3 - "$REMOTE_URL" <<'PY'
|
|
import sys
|
|
from urllib.parse import urlparse
|
|
|
|
remote = sys.argv[1]
|
|
parsed = urlparse(remote)
|
|
if parsed.scheme not in {'http', 'https'}:
|
|
raise SystemExit('forgejo remote must use http(s) for automatic bootstrap')
|
|
|
|
path = parsed.path.rstrip('/')
|
|
if path.endswith('.git'):
|
|
path = path[:-4]
|
|
parts = [part for part in path.split('/') if part]
|
|
if len(parts) < 2:
|
|
raise SystemExit('could not parse repo owner/name from forgejo remote')
|
|
|
|
base_url = f'{parsed.scheme}://{parsed.hostname}'
|
|
if parsed.port:
|
|
base_url += f':{parsed.port}'
|
|
|
|
if parsed.username and parsed.password:
|
|
print(f'export FORGEJO_API_PASSWORD={parsed.password}')
|
|
|
|
if parsed.username:
|
|
print(f'export FORGEJO_API_USERNAME={parsed.username}')
|
|
|
|
print(f'export FORGEJO_URL={base_url}')
|
|
print(f'export FORGEJO_REPO_OWNER={parts[-2]}')
|
|
print(f'export FORGEJO_REPO_NAME={parts[-1]}')
|
|
PY
|
|
)"
|
|
|
|
: "${KUBECONFIG_PATH:=${KUBECONFIG:-$PLATFORM_REPO_DIR/.state/hetzner/kubeconfig.yaml}}"
|
|
: "${CI_KUBECONFIG_PATH:=$PLATFORM_REPO_DIR/.state/hetzner/kubeconfig.incluster.yaml}"
|
|
: "${FORGEJO_URL:?set FORGEJO_URL or configure a forgejo remote}"
|
|
: "${FORGEJO_REPO_OWNER:?set FORGEJO_REPO_OWNER}"
|
|
: "${FORGEJO_REPO_NAME:?set FORGEJO_REPO_NAME}"
|
|
: "${FORGEJO_ADMIN_USERNAME:=${FORGEJO_API_USERNAME:-}}"
|
|
|
|
if [[ -z "${FORGEJO_TOKEN:-}" ]]; then
|
|
: "${FORGEJO_ADMIN_USERNAME:=${FORGEJO_API_USERNAME:-}}"
|
|
: "${FORGEJO_ADMIN_USERNAME:?set FORGEJO_TOKEN or FORGEJO_ADMIN_USERNAME}"
|
|
: "${FORGEJO_ADMIN_PASSWORD:=${FORGEJO_API_PASSWORD:-}}"
|
|
: "${FORGEJO_ADMIN_PASSWORD:?set FORGEJO_TOKEN or FORGEJO_ADMIN_PASSWORD}"
|
|
fi
|
|
|
|
if [[ ! -f "$KUBECONFIG_PATH" ]]; then
|
|
echo "missing kubeconfig: $KUBECONFIG_PATH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "$CI_KUBECONFIG_PATH" ]]; then
|
|
echo "missing in-cluster kubeconfig: $CI_KUBECONFIG_PATH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
export KUBECONFIG="$KUBECONFIG_PATH"
|
|
|
|
if [[ -z "${REGISTRY_HOST:-}" ]]; then
|
|
REGISTRY_HOST="${REGISTRY_DOMAIN:-}"
|
|
fi
|
|
if [[ -z "${REGISTRY_HOST:-}" ]]; then
|
|
REGISTRY_HOST="$(kubectl get ingress -n registry registry -o jsonpath='{.spec.rules[0].host}' 2>/dev/null || true)"
|
|
fi
|
|
if [[ -z "${REGISTRY_USERNAME:-}" ]]; then
|
|
REGISTRY_USERNAME="$(kubectl get secret registry-secrets -n registry -o jsonpath='{.data.htpasswd}' 2>/dev/null | base64 -d | cut -d: -f1 || true)"
|
|
fi
|
|
|
|
: "${REGISTRY_HOST:?set REGISTRY_HOST or configure the registry ingress first}"
|
|
: "${REGISTRY_USERNAME:?set REGISTRY_USERNAME or bootstrap the shared registry first}"
|
|
: "${REGISTRY_PASSWORD:?set REGISTRY_PASSWORD}"
|
|
: "${NEAR_INTENTS_API_KEY:?set NEAR_INTENTS_API_KEY}"
|
|
: "${POSTGRES_PASSWORD:=}"
|
|
: "${POSTGRES_URL:=}"
|
|
: "${NEAR_INTENTS_SIGNER_PRIVATE_KEY:=}"
|
|
|
|
secret_value() {
|
|
local key="$1"
|
|
kubectl -n "$PROJECT_NAMESPACE" get secret "$APP_SECRET_NAME" -o "jsonpath={.data.${key}}" 2>/dev/null | base64 -d 2>/dev/null || true
|
|
}
|
|
|
|
if [[ -z "$POSTGRES_PASSWORD" ]]; then
|
|
POSTGRES_PASSWORD="$(secret_value POSTGRES_PASSWORD)"
|
|
fi
|
|
|
|
if [[ -z "$POSTGRES_URL" ]]; then
|
|
POSTGRES_URL="$(secret_value POSTGRES_URL)"
|
|
fi
|
|
|
|
if [[ -z "$NEAR_INTENTS_SIGNER_PRIVATE_KEY" ]]; then
|
|
NEAR_INTENTS_SIGNER_PRIVATE_KEY="$(secret_value NEAR_INTENTS_SIGNER_PRIVATE_KEY)"
|
|
fi
|
|
|
|
if [[ -z "$POSTGRES_PASSWORD" ]]; then
|
|
POSTGRES_PASSWORD="$(python3 - <<'PY'
|
|
import secrets
|
|
print(secrets.token_urlsafe(24))
|
|
PY
|
|
)"
|
|
fi
|
|
|
|
if [[ -z "$POSTGRES_URL" ]]; then
|
|
POSTGRES_URL="postgresql://unrip:${POSTGRES_PASSWORD}@postgres:5432/unrip"
|
|
fi
|
|
|
|
echo "bootstrapping namespace $PROJECT_NAMESPACE"
|
|
kubectl apply -f "$ROOT_DIR/deploy/k8s/base/namespace.yaml"
|
|
|
|
echo "upserting runtime secret $APP_SECRET_NAME"
|
|
secret_args=(
|
|
--from-literal=NEAR_INTENTS_API_KEY="$NEAR_INTENTS_API_KEY"
|
|
--from-literal=POSTGRES_PASSWORD="$POSTGRES_PASSWORD"
|
|
--from-literal=POSTGRES_URL="$POSTGRES_URL"
|
|
)
|
|
if [[ -n "$NEAR_INTENTS_SIGNER_PRIVATE_KEY" ]]; then
|
|
secret_args+=(--from-literal=NEAR_INTENTS_SIGNER_PRIVATE_KEY="$NEAR_INTENTS_SIGNER_PRIVATE_KEY")
|
|
fi
|
|
kubectl -n "$PROJECT_NAMESPACE" create secret generic "$APP_SECRET_NAME" \
|
|
"${secret_args[@]}" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
echo "upserting registry pull/push secret $PROJECT_REGISTRY_SECRET_NAME"
|
|
kubectl -n "$PROJECT_NAMESPACE" create secret docker-registry "$PROJECT_REGISTRY_SECRET_NAME" \
|
|
--docker-server="$REGISTRY_HOST" \
|
|
--docker-username="$REGISTRY_USERNAME" \
|
|
--docker-password="$REGISTRY_PASSWORD" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
echo "applying app manifests"
|
|
kubectl apply -k "$ROOT_DIR/deploy/k8s/base"
|
|
|
|
echo "upserting Forgejo repo settings"
|
|
forgejo_args=()
|
|
if [[ -n "${FORGEJO_TOKEN:-}" ]]; then
|
|
forgejo_args+=(--token "$FORGEJO_TOKEN")
|
|
fi
|
|
if [[ -n "${FORGEJO_ADMIN_USERNAME:-}" ]]; then
|
|
forgejo_args+=(--admin-username "$FORGEJO_ADMIN_USERNAME")
|
|
fi
|
|
if [[ -n "${FORGEJO_ADMIN_PASSWORD:-}" ]]; then
|
|
forgejo_args+=(--admin-password "$FORGEJO_ADMIN_PASSWORD")
|
|
fi
|
|
|
|
python3 "$ROOT_DIR/scripts/deploy/forgejo_repo_bootstrap.py" \
|
|
--forgejo-url "$FORGEJO_URL" \
|
|
--repo-owner "$FORGEJO_REPO_OWNER" \
|
|
--repo-name "$FORGEJO_REPO_NAME" \
|
|
--ci-kubeconfig "$CI_KUBECONFIG_PATH" \
|
|
--registry-host "$REGISTRY_HOST" \
|
|
--project-name "$PROJECT_NAME" \
|
|
--project-namespace "$PROJECT_NAMESPACE" \
|
|
--project-deployments "$PROJECT_DEPLOYMENTS" \
|
|
--project-registry-secret-name "$PROJECT_REGISTRY_SECRET_NAME" \
|
|
"${forgejo_args[@]}"
|
|
|
|
if [[ "$SYNC_FORGEJO_REMOTE" == "1" ]]; then
|
|
: "${FORGEJO_PUSH_USERNAME:=${FORGEJO_API_USERNAME:-$FORGEJO_REPO_OWNER}}"
|
|
: "${FORGEJO_PUSH_PASSWORD:=${FORGEJO_ADMIN_PASSWORD:-${FORGEJO_API_PASSWORD:-}}}"
|
|
|
|
if [[ -n "${FORGEJO_PUSH_USERNAME:-}" && -n "${FORGEJO_PUSH_PASSWORD:-}" ]]; then
|
|
push_url="$(
|
|
python3 - "$FORGEJO_URL" "$FORGEJO_REPO_OWNER" "$FORGEJO_REPO_NAME" "$FORGEJO_PUSH_USERNAME" "$FORGEJO_PUSH_PASSWORD" <<'PY'
|
|
import sys
|
|
from urllib.parse import quote
|
|
|
|
base_url, owner, repo, username, password = sys.argv[1:]
|
|
print(f"{base_url.rstrip('/')}".replace('://', f'://{quote(username, safe="")}:{quote(password, safe="")}@') + f'/{owner}/{repo}.git')
|
|
PY
|
|
)"
|
|
git -C "$ROOT_DIR" remote set-url "$FORGEJO_REMOTE_NAME" "$push_url"
|
|
echo "updated git remote $FORGEJO_REMOTE_NAME for HTTPS push auth"
|
|
fi
|
|
fi
|
|
|
|
cat <<EOF
|
|
bootstrap complete
|
|
|
|
next:
|
|
git commit -am "..."
|
|
git push $FORGEJO_REMOTE_NAME main
|
|
EOF
|