Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions .devcontainer/manage/dev-template-configure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ADDITIONS_DIR="$DEVCONTAINER_DIR/additions"

# Source libraries
source "$SCRIPT_DIR/lib/uis-bridge.sh"
source "$ADDITIONS_DIR/lib/git-identity.sh"

#------------------------------------------------------------------------------
# Script Metadata
Expand Down Expand Up @@ -337,6 +338,21 @@ _configure_service() {
local extra_args=()
[ -n "$database" ] && extra_args+=("--database" "$database")

# K8s namespace + secret name prefix (Phase 1, item 1.9 of
# INVESTIGATE-improve-template-docs-with-services).
#
# namespace: where the deployed app lives — uses subdomain (user-friendly app
# name) if set, otherwise app_name, otherwise the git repo name.
# secret_name_prefix: matches the deployment manifest's existing
# {{REPO_NAME}}-db convention. Always the git repo name.
#
# Both flags are passed only when GIT_REPO is set (i.e., the project has a
# git remote). Without it, UIS works in legacy mode (no K8s secret).
if [ -n "${GIT_REPO:-}" ]; then
local namespace="${PARAMS[subdomain]:-${PARAMS[app_name]:-$GIT_REPO}}"
extra_args+=("--namespace" "$namespace" "--secret-name-prefix" "$GIT_REPO")
fi

# Handle init file
if [ -n "$init_file" ]; then
local init_path="$CALLER_DIR/$init_file"
Expand Down Expand Up @@ -389,7 +405,7 @@ _configure_service() {
fi
succeeded_services+=("$service")

# Write connection details to .env
# Write local connection URL to .env (for local development)
if [ -n "$UIS_LOCAL_URL" ]; then
local env_key="$env_var"
# Append to .env (create if doesn't exist)
Expand All @@ -399,10 +415,16 @@ _configure_service() {
else
echo "${env_key}=${UIS_LOCAL_URL}" >> "$CALLER_DIR/.env"
fi
echo " → .env: ${env_key}=${UIS_LOCAL_URL}"
echo " → .env: ${env_key}=${UIS_LOCAL_URL} (local)"
fi

if [ -n "$UIS_CLUSTER_URL" ]; then
# Report the K8s Secret if UIS created one (cluster credentials live there,
# not in .env.cluster — the deployment manifest's secretKeyRef reads it).
if [ -n "${UIS_SECRET_NAME:-}" ] && [ -n "${UIS_SECRET_NAMESPACE:-}" ]; then
echo " → K8s Secret: ${UIS_SECRET_NAME} in namespace ${UIS_SECRET_NAMESPACE} (cluster)"
elif [ -n "$UIS_CLUSTER_URL" ]; then
# Legacy fallback: no secret created (e.g., older UIS or no GIT_REPO).
# Write to .env.cluster so callers that read it still work.
local env_key="$env_var"
if [ -f "$CALLER_DIR/.env.cluster" ] && grep -q "^${env_key}=" "$CALLER_DIR/.env.cluster"; then
sed -i "s|^${env_key}=.*|${env_key}=${UIS_CLUSTER_URL}|" "$CALLER_DIR/.env.cluster"
Expand Down Expand Up @@ -455,6 +477,11 @@ if ! uis_bridge_check; then
exit 1
fi

# Detect git identity for namespace + secret_name_prefix.
# Best-effort: if there's no git remote, GIT_REPO will be empty and we fall
# back to legacy mode (no K8s secret created).
detect_git_identity "$CALLER_DIR" 2>/dev/null || true

# Read template-info.yaml
YAML_FILE="$CALLER_DIR/template-info.yaml"
read_template_info_yaml "$YAML_FILE"
Expand Down
51 changes: 38 additions & 13 deletions .devcontainer/manage/lib/uis-bridge.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
#
# Functions:
# uis_bridge_check — verify Docker CLI and UIS container are available
# uis_bridge_run — run a command in UIS container
# uis_bridge_run — run a command in UIS container (no TTY, no stdin)
# uis_bridge_run_stdin — run a command piping stdin (for init files)
# uis_bridge_run_tty — run a command with TTY (for interactive commands)
# uis_bridge_configure — call uis configure, parse JSON response
#------------------------------------------------------------------------------

Expand All @@ -22,14 +23,13 @@ UIS_CONTAINER="uis-provision-host"
# Returns: 0 if ready, 1 if not (with error message)
#------------------------------------------------------------------------------
uis_bridge_check() {
# Check Docker CLI
# Check Docker CLI (provided by docker-outside-of-docker devcontainer feature)
if ! command -v docker >/dev/null 2>&1; then
echo "❌ Docker CLI is not installed."
echo "❌ Docker CLI is not available."
echo ""
echo " Install it with: dev-setup"
echo " (Select 'Docker CLI' from Infrastructure & Configuration)"
echo ""
echo " Or directly: bash .devcontainer/additions/install-tool-docker-cli.sh"
echo " This devcontainer should have it via the docker-outside-of-docker"
echo " feature. Check .devcontainer/devcontainer.json includes:"
echo ' "features": { "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {} }'
return 1
fi

Expand Down Expand Up @@ -76,6 +76,19 @@ uis_bridge_run_stdin() {
docker exec -i "$UIS_CONTAINER" uis "$@"
}

#------------------------------------------------------------------------------
# Run a command in UIS container with a TTY allocated (for interactive commands
# like `uis connect`, `uis status`, etc. that produce formatted/coloured output)
#
# Arguments:
# $@ — command and arguments
#
# Returns: exit code from docker exec
#------------------------------------------------------------------------------
uis_bridge_run_tty() {
docker exec -it "$UIS_CONTAINER" uis "$@"
}

#------------------------------------------------------------------------------
# Call uis configure and parse the JSON response
#
Expand All @@ -88,18 +101,26 @@ uis_bridge_run_stdin() {
#
# Returns: 0 on success, 1 on error
# Sets globals:
# UIS_RESPONSE — full JSON response
# UIS_STATUS — "ok" or "error"
# UIS_LOCAL_URL — local connection URL (e.g., DATABASE_URL for local dev)
# UIS_CLUSTER_URL — cluster connection URL (for K8s deployment)
# UIS_ERROR_PHASE — error phase if failed
# UIS_ERROR_DETAIL — error detail if failed
# UIS_RESPONSE — full JSON response
# UIS_STATUS — "ok", "already_configured", or "error"
# UIS_LOCAL_URL — local connection URL (e.g., DATABASE_URL for local dev)
# UIS_CLUSTER_URL — cluster connection URL (deprecated, kept for one cycle)
# UIS_SECRET_NAME — K8s secret name (set when --namespace + --secret-name-prefix passed)
# UIS_SECRET_NAMESPACE — K8s namespace where the secret lives
# UIS_SECRET_ENV_VAR — env var name in the K8s secret (e.g., DATABASE_URL)
# UIS_ERROR_PHASE — error phase if failed
# UIS_ERROR_DETAIL — error detail if failed
#------------------------------------------------------------------------------
uis_bridge_configure() {
local service="$1"
local app_name="$2"
shift 2

# Reset secret fields so callers never read stale values from a previous call
UIS_SECRET_NAME=""
UIS_SECRET_NAMESPACE=""
UIS_SECRET_ENV_VAR=""

local has_stdin=false
local args=("configure" "$service" "--app" "$app_name" "--json")

Expand Down Expand Up @@ -142,6 +163,10 @@ uis_bridge_configure() {
ok|already_configured)
UIS_LOCAL_URL=$(echo "$response" | jq -r '.local.database_url // .local.url // ""')
UIS_CLUSTER_URL=$(echo "$response" | jq -r '.cluster.database_url // .cluster.url // ""')
# K8s Secret fields (set when --namespace + --secret-name-prefix passed)
UIS_SECRET_NAME=$(echo "$response" | jq -r '.secret_name // ""')
UIS_SECRET_NAMESPACE=$(echo "$response" | jq -r '.secret_namespace // ""')
UIS_SECRET_ENV_VAR=$(echo "$response" | jq -r '.env_var // ""')
return 0
;;
*)
Expand Down
86 changes: 86 additions & 0 deletions .devcontainer/manage/uis.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/bin/bash
# File: .devcontainer/manage/uis.sh
# Symlinked to: /usr/local/bin/uis (so users can type bare `uis ...`)
#
# Purpose:
# Thin wrapper around the UIS CLI that lives inside the uis-provision-host
# container. Routes commands via docker exec with the right TTY/stdin mode.
#
# Why this exists:
# The UIS CLI is not installed in DCT — it lives inside the
# uis-provision-host container managed by urbalurba-infrastructure. Without
# this shim, users would have to type:
# docker exec uis-provision-host uis configure postgresql --app myapp ...
# With this shim:
# uis configure postgresql --app myapp ...
#
# Modes:
# Interactive TTY (terminal): docker exec -it (uis_bridge_run_tty)
# Piped stdin (cat foo | uis): docker exec -i (uis_bridge_run_stdin)
# Non-TTY no stdin (script): docker exec (uis_bridge_run)
# help/--help/-h/no args: bypass container check, show local help
#
# See: helpers-no/dev-templates → INVESTIGATE-improve-template-docs-with-services.md
# (Phase 1, item 1.8)

set -e

# Resolve script dir from symlink target
SCRIPT_REAL_PATH="$(readlink -f "${BASH_SOURCE[0]}")"
SCRIPT_DIR="$(dirname "$SCRIPT_REAL_PATH")"

# Source the bridge library
# shellcheck source=lib/uis-bridge.sh
source "$SCRIPT_DIR/lib/uis-bridge.sh"

# Fast path: help and no-args output is local-only.
# Don't require the UIS container to be running for help.
case "${1:-}" in
""|help|--help|-h)
# If UIS container is up, forward to real `uis help` for accurate info
if uis_bridge_check 2>/dev/null; then
uis_bridge_run_tty "$@"
exit $?
fi
# Container is not running — show local help
cat <<'EOF'
uis — UIS CLI (proxied from DCT via docker-outside-of-docker)

Usage: uis <command> [args]

This is a DCT shim that forwards commands to the uis-provision-host
container. UIS provides commands for managing data services, deployments,
templates, and more.

Common commands (require uis-provision-host running):
uis status Show status of all UIS components
uis status <service> Show status of one service
uis deploy <service> Deploy a service (postgresql, redis, ...)
uis configure <service> Configure a service for an app
uis connect <service> [db] Connect to a service (psql, redis-cli, ...)
uis template list List available UIS stack templates
uis template install <id> Install a UIS stack template
uis expose <service> Expose a service via port-forward

⚠️ uis-provision-host container is not running.
Start it from the urbalurba-infrastructure repo.
EOF
exit 0
;;
*)
# All other commands require the UIS container.
uis_bridge_check || exit 1

# Pick the right exec mode based on stdin/stdout state.
if [ -t 0 ] && [ -t 1 ]; then
# Interactive: terminal in and out — allocate TTY
uis_bridge_run_tty "$@"
elif [ ! -t 0 ]; then
# Stdin is piped (e.g., echo SQL | uis configure --init-file -)
uis_bridge_run_stdin "$@"
else
# Non-TTY no stdin (e.g., uis status > out.txt)
uis_bridge_run "$@"
fi
;;
esac
1 change: 1 addition & 0 deletions image/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ RUN sudo ln -sf /opt/devcontainer-toolbox/manage/dev-setup.sh /usr/local/bin/dev
sudo ln -sf /opt/devcontainer-toolbox/manage/dev-log.sh /usr/local/bin/dev-log && \
sudo ln -sf /opt/devcontainer-toolbox/manage/dev-tools.sh /usr/local/bin/dev-tools && \
sudo ln -sf /opt/devcontainer-toolbox/additions/config-host-info.sh /usr/local/bin/config-host-info && \
sudo ln -sf /opt/devcontainer-toolbox/manage/uis.sh /usr/local/bin/uis && \
# Make all scripts executable (files owned by vscode via --chown)
chmod +x /opt/devcontainer-toolbox/manage/*.sh && \
chmod +x /opt/devcontainer-toolbox/additions/*.sh 2>/dev/null || true && \
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.7.33
1.7.34
Loading
Loading