Skip to main content

INVESTIGATE: Old Deployment System & UIS Migration

Status: Completed Created: 2026-01-31 Completed: 2026-02-18 Related to: STATUS-service-migration


Summary

The old deployment system (provision-host/kubernetes/) used numbered shell scripts that ran automatically on boot. Moving a script to not-in-use/ disabled it. The new UIS system (provision-host/uis/) replaced this with metadata-only service scripts and a CLI orchestrator. Both systems use the same Ansible playbooks.


Old Deployment System

How It Worked

  1. Boot sequence: provision-kubernetes.sh ran all scripts in numbered category folders
  2. Activation: Script in main folder = runs on boot
  3. Deactivation: Move script to not-in-use/ = disabled
  4. Execution: Each script validated environment, then called an Ansible playbook

Category Folders

CategoryPurposeScripts (active / disabled)
01-coreNginx1 / 1
02-databasesPostgreSQL, MySQL, MongoDB, Qdrant0 / 8
03-queuesRedis, RabbitMQ0 / 4
04-searchElasticsearch0 / 2
05-apimGravitee0 / 1
06-managementpgAdmin, RedisInsight0 / 4
07-aiOpenWebUI, LiteLLM0 / 6
08-developmentArgoCD0 / 2
09-networkTailscale, Cloudflare tunnels0 / 6
10-datascienceSpark, JupyterHub, Unity Catalog0 / 6
11-monitoringPrometheus, Grafana, Loki, Tempo, OTEL0 / 14
12-authAuthentik0 / 2
99-testWhoami test service0 / 2
Total1 / 58

58 of 60 scripts have been moved to not-in-use/. Only 01-core/020-setup-nginx.sh remains active.

Script Pattern

Old scripts followed this pattern:

#!/bin/bash
# 1. Validate bash version
# 2. Check kubectl connection and context
# 3. Run Ansible playbook
# 4. Print summary

Each script was a wrapper around ansible-playbook with environment validation. The real logic was always in the Ansible playbook.


New UIS System

How It Works

  1. Host wrapper: ./uis script manages the Docker container and routes commands
  2. CLI: uis-cli.sh inside the container handles all commands
  3. Service discovery: service-scanner.sh finds all service-*.sh files and parses metadata
  4. Deployment: Reads metadata → runs Ansible playbook → verifies health

Architecture

Host machine
└─> ./uis deploy postgresql
└─> docker exec provision-host uis-cli.sh deploy postgresql
├─> service-scanner.sh finds service-postgresql.sh
├─> Loads metadata (SCRIPT_PLAYBOOK, SCRIPT_CHECK_COMMAND, etc.)
├─> ansible-playbook 040-database-postgresql.yml
└─> Runs health check

Service Metadata Scripts

24 services across 10 categories in provision-host/uis/services/:

# service-postgresql.sh — no executable logic, just variables
SCRIPT_ID="postgresql"
SCRIPT_NAME="PostgreSQL"
SCRIPT_CATEGORY="DATABASES"
SCRIPT_PLAYBOOK="040-database-postgresql.yml"
SCRIPT_REMOVE_PLAYBOOK="040-remove-database-postgresql.yml"
SCRIPT_CHECK_COMMAND="kubectl get pods -n default -l app.kubernetes.io/name=postgresql..."
SCRIPT_REQUIRES=""
SCRIPT_PRIORITY="30"
SCRIPT_DOCS="/docs/services/databases/postgresql"

Key Commands

./uis list                      # Show services and status
./uis deploy [service] # Deploy specific or all enabled services
./uis undeploy <service> # Remove service
./uis enable <service> # Add to autostart
./uis disable <service> # Remove from autostart
./uis stack install <stack> # Deploy service bundle
./uis status # Health check all deployed services
./uis provision # Legacy: runs old provision-kubernetes.sh

Library Modules (provision-host/uis/lib/)

LibraryPurpose
paths.shSingle source of truth for all paths
utilities.shCommon helpers, kubectl checks
logging.shConsistent colored output
service-scanner.shService discovery and metadata extraction
service-deployment.shDeployment orchestration
service-auto-enable.shEnable/disable management
categories.shService category organization
stacks.shPre-defined service bundles
first-run.shInitial configuration setup
secrets-management.shKubernetes secrets generation
tool-installation.shOptional cloud CLI tools
menu-helpers.shInteractive TUI support
uis-hosts.shMulti-node host configuration

Stacks (Pre-defined Bundles)

StackServices
observabilityprometheus, tempo, loki, grafana
ai-locallitellm, openwebui
datasciencespark, jupyterhub, unity-catalog

Configuration

LocationPurpose
.uis.extend/enabled-services.confWhich services to deploy
.uis.extend/cluster-config.shCluster type, domain, project
.uis.secrets/service-keys/API keys (Tailscale, Cloudflare, OpenAI)
.uis.secrets/generated/Generated Kubernetes secrets

Mapping: Old System → New System

Old SystemNew UIS SystemShared
provision-host/kubernetes/02-databases/05-setup-postgres.shprovision-host/uis/services/databases/service-postgresql.shansible/playbooks/040-database-postgresql.yml
provision-host/kubernetes/12-auth/01-setup-authentik.shprovision-host/uis/services/authentication/service-authentik.shansible/playbooks/070-setup-authentik.yml
provision-host/kubernetes/08-development/02-setup-argocd.shprovision-host/uis/services/management/service-argocd.shansible/playbooks/220-setup-argocd.yml

The old scripts and new service scripts are different interfaces to the same Ansible playbooks.


Remaining Issue

01-core/020-setup-nginx.sh is still in the active position (not in not-in-use/). It has a corresponding UIS service script (service-nginx.sh), so it could be moved to not-in-use/ to match the rest.


Key Design Differences

AspectOld SystemNew UIS System
ActivationFile position in folder./uis enable / enabled-services.conf
ExecutionAll scripts run on bootSelective: ./uis deploy <service>
Script contentValidation + Ansible callPure metadata (no logic)
DependenciesImplicit (number ordering)Explicit (SCRIPT_REQUIRES)
Health checksNoneSCRIPT_CHECK_COMMAND
OrganizationNumbered foldersNamed categories
RemovalSeparate remove scriptsSCRIPT_REMOVE_PLAYBOOK metadata