#!/usr/bin/env bash # ============================================================================ # BLACKROAD OS, INC. - PROPRIETARY AND CONFIDENTIAL # Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved. # # This code is the intellectual property of BlackRoad OS, Inc. # AI-assisted development does not transfer ownership to AI providers. # Unauthorized use, copying, or distribution is prohibited. # NOT licensed for AI training or data extraction. # ============================================================================ # BlackRoad Service Registry CLI # Usage: br-services [registry.yaml] # # Commands: # validate - Check registry for errors and port reachability # diff - Show what would change vs current K8s state # apply - Generate and apply K8s manifests # list - Show all services in registry # generate - Output K8s manifests (dry-run) set -eo pipefail source "$HOME/.blackroad/config/nodes.sh" 2>/dev/null || true REGISTRY="${2:-$HOME/blackroad-services.yaml}" GATEWAY_HOST="${NODE_IP[alice]:-192.168.4.49}" SSH_OPTS="-o ConnectTimeout=3 -o StrictHostKeyChecking=no" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # Parse YAML (simple bash parser - works for our flat structure) parse_services() { python3 -c " import yaml import sys with open('$REGISTRY') as f: data = yaml.safe_load(f) nodes = data.get('nodes', {}) for svc in data.get('services', []): node = svc.get('node', 'alice') ip = nodes.get(node, {}).get('ip', '192.168.4.49') print(f\"{svc['name']}|{svc['path']}|{ip}|{svc['port']}|{svc.get('health','/')}|{svc.get('description','')}\") " } # Validate command cmd_validate() { echo -e "${BLUE}🔍 Validating registry: $REGISTRY${NC}" echo "" local errors=0 local warnings=0 # Check file exists if [[ ! -f "$REGISTRY" ]]; then echo -e "${RED}✗ Registry file not found: $REGISTRY${NC}" exit 1 fi # Parse and validate echo "Checking services..." local seen_ports="" local seen_paths="" while IFS='|' read -r name path ip port health desc; do echo -n " $name ($path → $ip:$port): " # Check port conflicts if echo "$seen_ports" | grep -q ":$port:"; then echo -e "${RED}✗ Port conflict${NC}" ((errors++)) continue fi seen_ports="$seen_ports:$port:" # Check path conflicts if echo "$seen_paths" | grep -q ":$path:"; then echo -e "${RED}✗ Path conflict${NC}" ((errors++)) continue fi seen_paths="$seen_paths:$path:" # Check port reachability if nc -z -w 1 "$ip" "$port" 2>/dev/null; then echo -e "${GREEN}✓ reachable${NC}" else echo -e "${YELLOW}⚠ unreachable${NC}" ((warnings++)) fi done < <(parse_services) echo "" if [[ $errors -gt 0 ]]; then echo -e "${RED}✗ Validation failed: $errors errors, $warnings warnings${NC}" exit 1 elif [[ $warnings -gt 0 ]]; then echo -e "${YELLOW}⚠ Validation passed with $warnings warnings${NC}" else echo -e "${GREEN}✓ Validation passed${NC}" fi } # List command cmd_list() { echo -e "${BLUE}📋 Services in $REGISTRY${NC}" echo "" printf "%-15s %-15s %-20s %-6s %s\n" "NAME" "PATH" "ENDPOINT" "PORT" "DESCRIPTION" echo "─────────────────────────────────────────────────────────────────────────────" while IFS='|' read -r name path ip port health desc; do printf "%-15s %-15s %-20s %-6s %s\n" "$name" "$path" "$ip:$port" "$port" "$desc" done < <(parse_services) } # Generate K8s manifests cmd_generate() { while IFS='|' read -r name path ip port health desc; do cat << MANIFEST --- # Service: $name - $desc apiVersion: v1 kind: Service metadata: name: $name namespace: default labels: app.kubernetes.io/name: $name app.kubernetes.io/managed-by: br-services spec: ports: - name: http port: 80 targetPort: $port --- apiVersion: v1 kind: Endpoints metadata: name: $name namespace: default subsets: - addresses: - ip: $ip ports: - name: http port: $port --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: ${name}-strip namespace: default spec: stripPrefix: prefixes: - $path --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: $name namespace: default annotations: traefik.ingress.kubernetes.io/router.entrypoints: web traefik.ingress.kubernetes.io/router.middlewares: default-${name}-strip@kubernetescrd spec: ingressClassName: traefik rules: - http: paths: - path: $path pathType: Prefix backend: service: name: $name port: number: 80 MANIFEST done < <(parse_services) } # Diff command cmd_diff() { echo -e "${BLUE}📊 Comparing registry vs K8s state${NC}" echo "" # Get current ingresses local current=$(ssh $SSH_OPTS pi@$GATEWAY_HOST "kubectl get ingress -o jsonpath='{.items[*].metadata.name}'" 2>/dev/null || echo "") echo "Current K8s ingresses: $current" echo "" echo "Registry services:" while IFS='|' read -r name path ip port health desc; do if echo "$current" | grep -qw "$name"; then echo -e " ${GREEN}✓ $name${NC} (exists)" else echo -e " ${YELLOW}+ $name${NC} (will create)" fi done < <(parse_services) } # Apply command cmd_apply() { echo -e "${BLUE}🚀 Applying registry to K8s${NC}" echo "" # Validate first cmd_validate || exit 1 echo "" # Generate and apply echo "Applying manifests..." cmd_generate | ssh $SSH_OPTS pi@$GATEWAY_HOST "kubectl apply -f -" 2>&1 | grep -E "configured|created|unchanged" echo "" echo -e "${GREEN}✓ Registry applied${NC}" # Verify echo "" echo "Verifying routes..." sleep 2 while IFS='|' read -r name path ip port health desc; do local url="http://$GATEWAY_HOST$path/" local status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 2 "$url" 2>/dev/null || echo "000") if [[ "$status" == "200" ]]; then echo -e " ${GREEN}✓ $path → $status${NC}" else echo -e " ${YELLOW}⚠ $path → $status${NC}" fi done < <(parse_services) } # Main case "${1:-help}" in validate) cmd_validate ;; list) cmd_list ;; diff) cmd_diff ;; generate) cmd_generate ;; apply) cmd_apply ;; *) echo "BlackRoad Service Registry CLI" echo "" echo "Usage: br-services [registry.yaml]" echo "" echo "Commands:" echo " validate - Check registry for errors and port reachability" echo " list - Show all services in registry" echo " diff - Show what would change vs current K8s state" echo " generate - Output K8s manifests (dry-run)" echo " apply - Generate and apply K8s manifests" echo "" echo "Default registry: $HOME/blackroad-services.yaml" ;; esac