diff --git a/client/tests/mysql_test.yaml b/client/tests/mysql_test.yaml index ec30443..ad6398d 100644 --- a/client/tests/mysql_test.yaml +++ b/client/tests/mysql_test.yaml @@ -61,8 +61,18 @@ tests: path: spec.template.spec.containers[0].livenessProbe.failureThreshold value: 5 - - it: should reference the data-plane PriorityClass when enabled + - it: should NOT set priorityClassName by default (PriorityClass dropped) template: templates/mysql-deployment.yaml + asserts: + - notExists: + path: spec.template.spec.priorityClassName + + - it: should reference the PriorityClass when a name is set + template: templates/mysql-deployment.yaml + set: + priorityClass: + create: true + name: tracebloc-data-plane asserts: - equal: path: spec.template.spec.priorityClassName diff --git a/client/tests/priority_class_pdb_test.yaml b/client/tests/priority_class_pdb_test.yaml index 7a53699..33c4b56 100644 --- a/client/tests/priority_class_pdb_test.yaml +++ b/client/tests/priority_class_pdb_test.yaml @@ -7,8 +7,18 @@ set: clientId: "test-id" clientPassword: "test" tests: - - it: should create the data-plane PriorityClass by default + - it: should NOT render the PriorityClass by default (dropped) template: templates/priority-class.yaml + asserts: + - hasDocuments: + count: 0 + + - it: should render the PriorityClass when explicitly enabled + template: templates/priority-class.yaml + set: + priorityClass: + create: true + name: tracebloc-data-plane asserts: - isKind: of: PriorityClass diff --git a/client/values.yaml b/client/values.yaml index 4cf25c8..ad82ad4 100644 --- a/client/values.yaml +++ b/client/values.yaml @@ -313,22 +313,23 @@ resources: memory: "512Mi" # -- PriorityClass for the data-plane (mysql). -# Cluster-scoped resource. Created with helm.sh/resource-policy: keep so a -# release uninstall does not yank it from sibling releases that share it. -# Value 1,000,000 sits well above default (0) so the scheduler will preempt -# noisy training jobs to keep mysql scheduled, but well below -# system-cluster-critical (2,000,000,000). +# DROPPED BY DEFAULT (create: false, name: ""). mysql doesn't need it: its +# memory requests==limits (so it's among the last evicted under memory +# pressure), its data lives on a PVC (eviction = a transient restart, never +# data loss), and a PodDisruptionBudget guards voluntary disruptions. Dropping +# this cluster-scoped, fixed-name object also lets multiple tracebloc +# namespaces coexist in one cluster (BYO) and removes the one-client-per- +# cluster install collision. # -# create: false — chart does not template the PriorityClass; you (or your -# GitOps tool / shared platform) manage it out-of-band. -# The mysql pod still references `name`, so make sure the -# PriorityClass exists at install time. -# name: "" — disable the priorityClassName reference entirely. mysql -# falls back to the cluster default priority (0) and loses -# the OOM-protection this chart's mysql tuning relies on. +# Opt back in ONLY on a heavily-contended cluster where you want the scheduler +# to preempt noisy training jobs to keep mysql scheduled: +# create: true, name: , value: ~1000000 (above default 0, below +# system-cluster-critical 2,000,000,000). +# For a PriorityClass your platform manages out-of-band, use create: false + +# name: (mysql references it without the chart templating it). priorityClass: - create: true - name: tracebloc-data-plane + create: false + name: "" value: 1000000 # -- PodDisruptionBudgets. diff --git a/scripts/install-k8s.ps1 b/scripts/install-k8s.ps1 index 67dcfbb..c890bea 100644 --- a/scripts/install-k8s.ps1 +++ b/scripts/install-k8s.ps1 @@ -112,6 +112,15 @@ function ConvertTo-WorkspaceName { return $sanitized } +# Best-effort chart version of the installed client release (e.g. "1.4.4"); +# empty if not found / cluster unreachable. Greps helm's CHART column. +function Get-ChartVersion { + param([string]$Namespace = "tracebloc") + $out = (helm list -n $Namespace 2>$null) | Out-String + if ($out -match 'client-([0-9][^\s]*)') { return $Matches[1] } + return "" +} + # ============================================================================= # CONFIGURATION # ============================================================================= @@ -1006,7 +1015,6 @@ function Install-ClientHelm { } $valuesFile = Join-Path $HOST_DATA_DIR "values.yaml" - $defaultNamespace = "default" $defaultClientId = "" $defaultClientPassword = "" @@ -1027,21 +1035,15 @@ function Install-ClientHelm { } } - # -- Workspace name prompt -- - PromptHeader "Choose a workspace name" - Hint "This identifies your tracebloc client on this machine." - Write-Host "" - Hint "Examples: myteam, vision-lab, lukas" - Write-Host "" - $nsInput = Read-Host " Workspace name [$defaultNamespace]" - $rawName = if ($nsInput) { $nsInput } else { $defaultNamespace } - $TB_NAMESPACE = ConvertTo-WorkspaceName -Input_ $rawName + # -- Namespace (fixed; not prompted) -- + # The on-prem client is one-per-machine and is identified to the backend by + # its credentials (clientId), not by this name -- so we don't ask the user to + # invent one. It's just the local k8s namespace / Helm release name. + # Advanced / GitOps setups can override with TB_NAMESPACE=. + $rawNs = if ($env:TB_NAMESPACE) { $env:TB_NAMESPACE } else { "tracebloc" } + $TB_NAMESPACE = ConvertTo-WorkspaceName -Input_ $rawNs $script:TB_NAMESPACE = $TB_NAMESPACE # share with Wait-ForClientReady / Print-Summary - if ($TB_NAMESPACE -ne $rawName) { - Info "Using workspace: $TB_NAMESPACE" - } - # -- Step 4/4: Connect to tracebloc network -- Step 4 4 "Connect to tracebloc network" @@ -1101,6 +1103,43 @@ function Install-ClientHelm { $defaultClientId = ""; $defaultClientPassword = "" } + # -- One-client-per-machine guard -- + # A machine runs exactly one tracebloc client: it shares this cluster and the + # host's CPU/RAM/GPU, and the platform counts each client as separate + # capacity. If a DIFFERENT client is already installed here, a re-install + # would silently re-point the machine -- so we stop and let the operator + # decide. The same clientId is a normal re-run/upgrade and passes through. + # Check ANY namespace: a fresh install lands in 'tracebloc', but an install + # from an older installer version may be in a different namespace. Enumerate + # client-chart releases and read each clientId (ConvertFrom-Json -- no jq). + $existingId = ""; $existingNs = "" + $listJson = (helm list -A -o json 2>$null) | Out-String + if ($LASTEXITCODE -eq 0 -and $listJson.Trim()) { + try { + foreach ($rel in ($listJson | ConvertFrom-Json)) { + if ($rel.chart -and $rel.chart.StartsWith("client-")) { + $vals = (helm get values $rel.name -n $rel.namespace 2>$null) | Out-String + if ($vals -match 'clientId:\s*"([^"]+)"') { $existingId = $Matches[1].Trim(); $existingNs = $rel.namespace; break } + } + } + } catch { } + } + if ($existingId -and $existingId -ne $TB_CLIENT_ID) { + Write-Host "" + Warn "This machine already runs the tracebloc client '$existingId' (namespace '$existingNs')." + Hint "tracebloc runs one client per machine -- it shares this cluster and host" + Hint "resources, and the platform counts each client as separate capacity." + Write-Host "" + Hint "You entered a different Client ID ('$TB_CLIENT_ID'). Pick one:" + Hint " - Repair / update '$existingId' -> re-run with that same Client ID" + Hint " - Switch to '$TB_CLIENT_ID' -> remove the current client first:" + Hint " k3d cluster delete $CLUSTER_NAME (wipes this client + its local data)" + Hint " then re-run this installer" + Hint " - Run both clients -> install on a separate machine" + Write-Host "" + Err "Refusing to replace the existing client. See the options above." + } + $passwordEscaped = $TB_CLIENT_PASSWORD -replace "'", "''" $gpuVal = "" @@ -1257,6 +1296,8 @@ function Print-Summary { Write-Host " " -NoNewline; Write-Host "$([char]0x2714) Connected to tracebloc" -ForegroundColor Green Write-Host "" Write-Host " Workspace : " -NoNewline; Write-Host $ns -ForegroundColor Cyan + $cver = Get-ChartVersion -Namespace $ns; if (-not $cver) { $cver = "unknown" } + Write-Host " Version : " -NoNewline; Write-Host $cver -ForegroundColor Cyan Write-Host " Mode : " -NoNewline; Write-Host $mode -ForegroundColor Cyan Write-Host "" Write-Host " Your client is live. Confirm it shows as Online:" @@ -1460,8 +1501,6 @@ function Invoke-DiagnoseBundle { $d = Join-Path $work "tracebloc-diagnose-$ts" New-Item -ItemType Directory -Path (Join-Path $d "logs") -Force | Out-Null - Info "Collecting diagnostics -- this is safe; credentials are redacted before the file is written." - # Namespace discovery (TB_NAMESPACE isn't set on a standalone diagnose run). $ns = $TB_NAMESPACE if (-not $ns) { @@ -1470,9 +1509,14 @@ function Invoke-DiagnoseBundle { } if (-not $ns) { $ns = "default" } + # Surface the client version first -- the #1 thing support needs to know. + $cver = Get-ChartVersion -Namespace $ns; if (-not $cver) { $cver = "unknown" } + Info "tracebloc client version: $cver (namespace: $ns)" + Info "Collecting diagnostics -- this is safe; credentials are redacted before the file is written." + # host / versions $h = @("# tracebloc diagnose ($ts)", "OS: Windows ARCH: $(Get-WindowsArch)", - "CLIENT_ENV: $($env:CLIENT_ENV) CLUSTER_NAME: $cn NAMESPACE: $ns", "## versions", + "CLIENT_ENV: $($env:CLIENT_ENV) CLUSTER_NAME: $cn NAMESPACE: $ns", "CLIENT VERSION: $cver", "## versions", (k3d version 2>&1 | Out-String), (kubectl version --client 2>&1 | Out-String), (helm version --short 2>&1 | Out-String), (docker version 2>&1 | Out-String)) try { $cs = Get-CimInstance Win32_ComputerSystem -ErrorAction Stop; $h += "CPUs=$($cs.NumberOfLogicalProcessors) MemBytes=$($cs.TotalPhysicalMemory)" } catch {} diff --git a/scripts/install-k8s.sh b/scripts/install-k8s.sh index 615a701..804e535 100755 --- a/scripts/install-k8s.sh +++ b/scripts/install-k8s.sh @@ -15,6 +15,8 @@ # # Environment variable overrides (optional): # CLUSTER_NAME=myapp default: tracebloc +# TB_NAMESPACE=myns default: tracebloc (k8s namespace + local label; +# not prompted — the client is identified by its credentials) # SERVERS=1 default: 1 (control-plane nodes) # AGENTS=1 default: 1 (worker nodes) # K8S_VERSION=v1.29.4-k3s1 default: latest stable k3s diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh index 6a5a979..96d08c0 100755 --- a/scripts/lib/common.sh +++ b/scripts/lib/common.sh @@ -35,6 +35,15 @@ hint() { echo -e " ${DIM}$*${RESET}"; } # ── Utility ────────────────────────────────────────────────────────────────── has() { command -v "$1" &>/dev/null; } +# Best-effort chart version of the installed client release in namespace $1 +# (e.g. "1.4.4"); empty if not found / cluster unreachable. Greps helm's CHART +# column ("client-"), so it needs no jq. +_chart_version() { + local ns="${1:-${TB_NAMESPACE:-tracebloc}}" + has helm || return 0 + helm list -n "$ns" 2>/dev/null | grep -oE 'client-[0-9][^[:space:]]*' | head -1 | sed 's/^client-//' +} + # ── macOS: Docker Desktop architecture vs machine (for wrong-arch UX) ──────── # Call early on macOS to fail fast with clear instructions if Docker.app # is for the wrong architecture (e.g. Intel Docker on Apple Silicon). @@ -361,6 +370,7 @@ Commands: Advanced configuration (environment variables): CLUSTER_NAME Cluster name (default: tracebloc) + TB_NAMESPACE Namespace / workspace label (default: tracebloc) SERVERS Control-plane nodes (default: 1) AGENTS Worker nodes (default: 1) K8S_VERSION k3s image tag (default: v1.29.4-k3s1) diff --git a/scripts/lib/diagnose.sh b/scripts/lib/diagnose.sh index ed74adf..f64acee 100644 --- a/scripts/lib/diagnose.sh +++ b/scripts/lib/diagnose.sh @@ -49,8 +49,6 @@ run_diagnose() { if [[ -z "$outdir" || ! -d "$outdir" ]]; then echo " diagnose: cannot create a temp directory" >&2; return 1; fi d="$outdir/tracebloc-diagnose-$ts"; mkdir -p "$d/logs" - info "Collecting diagnostics — this is safe; credentials are redacted before the file is written." - # Namespace discovery — TB_NAMESPACE isn't set on a standalone diagnose run, # so find the namespace of the jobs-manager pod (falls back to "default"). ns="${TB_NAMESPACE:-}" @@ -59,12 +57,18 @@ run_diagnose() { fi [[ -z "$ns" ]] && ns="default" + # Surface the client version first — the #1 thing support needs to know. + local cver; cver="$(_chart_version "$ns")" + info "tracebloc client version: ${cver:-unknown} (namespace: $ns)" + info "Collecting diagnostics — this is safe; credentials are redacted before the file is written." + # ── host / versions ── { echo "# tracebloc diagnose ($ts)" echo "OS: $(uname -s) $(uname -r)" echo "ARCH: $(uname -m)" echo "CLIENT_ENV: ${CLIENT_ENV:-} CLUSTER_NAME: $cn NAMESPACE: $ns" + echo "CLIENT VERSION: ${cver:-unknown}" echo; echo "## versions" has k3d && k3d version has kubectl && kubectl version --client 2>/dev/null diff --git a/scripts/lib/install-client-helm.sh b/scripts/lib/install-client-helm.sh index 2ffd5e2..6cc95bc 100644 --- a/scripts/lib/install-client-helm.sh +++ b/scripts/lib/install-client-helm.sh @@ -153,13 +153,12 @@ install_client_helm() { if [[ -n "${TRACEBLOC_VALUES_FILE:-}" ]]; then [[ -f "$TRACEBLOC_VALUES_FILE" ]] || error "TRACEBLOC_VALUES_FILE not found: $TRACEBLOC_VALUES_FILE" values_file="$TRACEBLOC_VALUES_FILE" - TB_NAMESPACE="${TB_NAMESPACE:-default}" + TB_NAMESPACE="${TB_NAMESPACE:-tracebloc}" info "Dev mode: using caller-provided values file" log "Using values file: $values_file (namespace: $TB_NAMESPACE)" else local use_existing="" - local default_namespace="default" local default_client_id="" local default_client_password="" @@ -179,19 +178,12 @@ install_client_helm() { fi fi - # ── Workspace name prompt ──────────────────────────────────────────────── - prompt_header "Choose a workspace name" - hint "This identifies your tracebloc client on this machine." - echo "" - hint "Examples: berlin-team, vision-lab, ml-mardan" - echo "" - read -r -p " Workspace name [${default_namespace}]: " TB_NAMESPACE_INPUT - local raw_name="${TB_NAMESPACE_INPUT:-$default_namespace}" - TB_NAMESPACE=$(_sanitize_workspace_name "$raw_name") - - if [[ "$TB_NAMESPACE" != "$raw_name" ]]; then - info "Using workspace: ${BOLD}${TB_NAMESPACE}${RESET}" - fi + # ── Namespace (fixed; not prompted) ────────────────────────────────────── + # The on-prem client is one-per-machine and is identified to the backend by + # its credentials (clientId), not by this name — so we don't ask the user to + # invent one. It's just the local k8s namespace / Helm release name. + # Advanced / GitOps setups can override with TB_NAMESPACE=. + TB_NAMESPACE=$(_sanitize_workspace_name "${TB_NAMESPACE:-tracebloc}") # ── Step 4/4: Connect to tracebloc network ────────────────────────────── step 4 4 "Connect to tracebloc network" @@ -255,6 +247,46 @@ install_client_helm() { default_client_id=""; default_client_password="" done + # ── One-client-per-machine guard ───────────────────────────────────────── + # A machine runs exactly one tracebloc client: it shares this cluster and the + # host's CPU/RAM/GPU, and the platform counts each client as separate + # capacity. If a DIFFERENT client is already installed here, a re-install + # would silently re-point the machine — so we stop and let the operator + # decide. The same clientId is a normal re-run/upgrade and passes through. + # Check ANY namespace: a fresh install lands in `tracebloc`, but an install + # from an older installer version may be in a different namespace. Enumerate + # client-chart releases and read each clientId. jq is already used elsewhere + # in the installer; if it's somehow absent, fall back to the `tracebloc` ns. + local existing_id="" existing_ns="" _gvf _rel _ns _id + _gvf="$(mktemp)" + if has jq; then + while IFS=$'\t' read -r _rel _ns; do + [[ -z "$_rel" ]] && continue + if helm get values "$_rel" -n "$_ns" > "$_gvf" 2>/dev/null; then + _id="$(_extract_yaml_value "$_gvf" clientId)" + [[ -n "$_id" ]] && { existing_id="$_id"; existing_ns="$_ns"; break; } + fi + done < <(helm list -A -o json 2>/dev/null | jq -r '.[] | select((.chart // "") | startswith("client-")) | "\(.name)\t\(.namespace)"') + elif helm get values "$TB_NAMESPACE" -n "$TB_NAMESPACE" > "$_gvf" 2>/dev/null; then + existing_id="$(_extract_yaml_value "$_gvf" clientId)"; existing_ns="$TB_NAMESPACE" + fi + rm -f "$_gvf" + if [[ -n "$existing_id" && "$existing_id" != "$TB_CLIENT_ID" ]]; then + echo "" + warn "This machine already runs the tracebloc client '${existing_id}' (namespace '${existing_ns}')." + hint "tracebloc runs one client per machine — it shares this cluster and host" + hint "resources, and the platform counts each client as separate capacity." + echo "" + hint "You entered a different Client ID ('${TB_CLIENT_ID}'). Pick one:" + hint " • Repair / update '${existing_id}' → re-run with that same Client ID" + hint " • Switch to '${TB_CLIENT_ID}' → remove the current client first:" + hint " k3d cluster delete ${CLUSTER_NAME:-tracebloc} (wipes this client + its local data)" + hint " then re-run this installer" + hint " • Run both clients → install on a separate machine" + echo "" + error "Refusing to replace the existing client. See the options above." + fi + TB_CLIENT_PASSWORD_ESCAPED="${TB_CLIENT_PASSWORD//\'/\'\'}" # ── GPU limits ────────────────────────────────────────────────────────── diff --git a/scripts/lib/summary.sh b/scripts/lib/summary.sh index 3a501bb..ccf9f93 100755 --- a/scripts/lib/summary.sh +++ b/scripts/lib/summary.sh @@ -89,6 +89,7 @@ print_summary() { [[ "$GPU_VENDOR" == "nvidia" ]] && mode="NVIDIA GPU" [[ "$GPU_VENDOR" == "amd" ]] && mode="AMD GPU" local ns="${TB_NAMESPACE:-default}" + local cver; cver="$(_chart_version "$ns")" local line="━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" @@ -99,6 +100,7 @@ print_summary() { echo -e " ${BOLD}${GREEN}✔ Connected to tracebloc${RESET}" echo "" echo -e " ${BOLD}Workspace${RESET} : ${CYAN}${ns}${RESET}" + echo -e " ${BOLD}Version${RESET} : ${CYAN}${cver:-unknown}${RESET}" echo -e " ${BOLD}Mode${RESET} : ${CYAN}${mode}${RESET}" echo "" echo -e " Your client is live. Confirm it shows as ${BOLD}🟢 Online${RESET}:" diff --git a/scripts/tests/diagnose.bats b/scripts/tests/diagnose.bats index 93f4b97..0e6f533 100644 --- a/scripts/tests/diagnose.bats +++ b/scripts/tests/diagnose.bats @@ -104,3 +104,14 @@ setup() { # Finding 2 (security review): `helm get manifest` (base64 Secrets) is NOT collected ! tar -xzOf "$tgz" 2>/dev/null | grep -q 'get manifest' } + +@test "run_diagnose: surfaces + records the client version" { + has() { case "$1" in helm) return 0 ;; *) return 1 ;; esac; } # only helm present + helm() { echo "tracebloc tracebloc 1 now deployed client-1.4.4 1.4.4"; } + run run_diagnose + [ "$status" -eq 0 ] + [[ "$output" == *"client version: 1.4.4"* ]] + tgz="$(ls "$HOST_DATA_DIR"/tracebloc-diagnose-*.tgz 2>/dev/null | head -1)" + [ -n "$tgz" ] + tar -xzOf "$tgz" 2>/dev/null | grep -q 'CLIENT VERSION: 1.4.4' +} diff --git a/scripts/tests/install-client-helm.bats b/scripts/tests/install-client-helm.bats index 739a96d..e9565bc 100644 --- a/scripts/tests/install-client-helm.bats +++ b/scripts/tests/install-client-helm.bats @@ -126,13 +126,13 @@ setup() { _ensure_helm_runnable() { :; } helm() { record "helm $*"; return 0; } verify_credentials() { printf valid; } - run install_client_helm <<< $'myws\nmyid\nmypw' + run install_client_helm <<< $'myid\nmypw' [ "$status" -eq 0 ] [[ "$output" == *"Credentials verified"* ]] [[ "$output" == *"Connected to tracebloc"* ]] grep -q 'clientId: "myid"' "$HOST_DATA_DIR/values.yaml" grep -q "clientPassword: 'mypw'" "$HOST_DATA_DIR/values.yaml" - mock_calls | grep -q "helm upgrade --install myws" + mock_calls | grep -q "helm upgrade --install tracebloc" } @test "install_client_helm: re-prompts on invalid, then accepts valid" { @@ -145,7 +145,7 @@ setup() { local n; n=$(cat "$BATS_TEST_TMPDIR/n" 2>/dev/null || echo 0); n=$((n+1)); echo "$n" >"$BATS_TEST_TMPDIR/n" if [ "$n" -ge 2 ]; then printf valid; else printf invalid; fi } - run install_client_helm <<< $'myws\nbadid\nbadpw\ngoodid\ngoodpw' + run install_client_helm <<< $'badid\nbadpw\ngoodid\ngoodpw' [ "$status" -eq 0 ] [[ "$output" == *"rejected"* ]] [[ "$output" == *"Credentials verified"* ]] @@ -159,7 +159,7 @@ setup() { _ensure_helm_runnable() { :; } helm() { record "helm $*"; return 0; } verify_credentials() { printf inactive; } - run install_client_helm <<< $'myws\nmyid\nmypw' + run install_client_helm <<< $'myid\nmypw' [ "$status" -ne 0 ] [[ "$output" == *"not active"* ]] run mock_calls @@ -173,7 +173,7 @@ setup() { _ensure_helm_runnable() { :; } helm() { record "helm $*"; return 0; } verify_credentials() { printf unverified; } - run install_client_helm <<< $'myws\nmyid\nmypw' + run install_client_helm <<< $'myid\nmypw' [ "$status" -eq 0 ] [[ "$output" == *"Couldn't reach tracebloc"* ]] run mock_calls @@ -202,8 +202,8 @@ setup() { _ensure_helm_runnable() { :; } helm() { record "helm $*"; return 0; } verify_credentials() { printf valid; } - # use-previous=y, workspace=myws, ClientID=Enter(keep previd), password=Enter(keep prevpw) - run install_client_helm <<< $'y\nmyws\n\n\n' + # use-previous=y, ClientID=Enter(keep previd), password=Enter(keep prevpw) + run install_client_helm <<< $'y\n\n\n' [ "$status" -eq 0 ] grep -q 'clientId: "previd"' "$HOST_DATA_DIR/values.yaml" grep -q "clientPassword: 'prevpw'" "$HOST_DATA_DIR/values.yaml" @@ -216,9 +216,47 @@ setup() { _ensure_helm_runnable() { :; } helm() { record "helm $*"; return 0; } verify_credentials() { printf invalid; } - run install_client_helm <<< $'myws\ni1\np1\ni2\np2\ni3\np3\ni4\np4\ni5\np5' + run install_client_helm <<< $'i1\np1\ni2\np2\ni3\np3\ni4\np4\ni5\np5' [ "$status" -ne 0 ] [[ "$output" == *"Too many failed attempts"* ]] run mock_calls [[ "$output" != *"helm upgrade"* ]] } + +# ── One-client-per-machine guard ──────────────────────────────────────────── +@test "install_client_helm: blocks a DIFFERENT client already installed" { + HOST_DATA_DIR="$BATS_TEST_TMPDIR/data"; mkdir -p "$HOST_DATA_DIR" + _ensure_tracebloc_dirs() { :; } + _ensure_release_dirs() { :; } + _ensure_helm_runnable() { :; } + # an existing release reports a different clientId -> must block before upgrade + helm() { + if [ "$1" = list ]; then echo '[{"name":"oldrel","namespace":"default","chart":"client-1.4.3"}]'; return 0; fi + if [ "$1" = get ] && [ "$2" = values ]; then echo 'clientId: "otherclient"'; return 0; fi + record "helm $*"; return 0 + } + verify_credentials() { printf valid; } + run install_client_helm <<< $'newclient\nmypw' + [ "$status" -ne 0 ] + [[ "$output" == *"already runs the tracebloc client 'otherclient'"* ]] + [[ "$output" == *"one client per machine"* ]] + run mock_calls + [[ "$output" != *"helm upgrade"* ]] +} + +@test "install_client_helm: same client re-run is allowed (upgrade in place)" { + HOST_DATA_DIR="$BATS_TEST_TMPDIR/data"; mkdir -p "$HOST_DATA_DIR" + _ensure_tracebloc_dirs() { :; } + _ensure_release_dirs() { :; } + _ensure_helm_runnable() { :; } + helm() { + if [ "$1" = list ]; then echo '[{"name":"tracebloc","namespace":"tracebloc","chart":"client-1.4.3"}]'; return 0; fi + if [ "$1" = get ] && [ "$2" = values ]; then echo 'clientId: "sameid"'; return 0; fi + record "helm $*"; return 0 + } + verify_credentials() { printf valid; } + run install_client_helm <<< $'sameid\nmypw' + [ "$status" -eq 0 ] + run mock_calls + [[ "$output" == *"helm upgrade --install tracebloc"* ]] +} diff --git a/scripts/tests/install-k8s.Tests.ps1 b/scripts/tests/install-k8s.Tests.ps1 index ed3967c..fe39098 100644 --- a/scripts/tests/install-k8s.Tests.ps1 +++ b/scripts/tests/install-k8s.Tests.ps1 @@ -98,6 +98,13 @@ Describe "Print-Summary" { $out = Print-Summary 6>&1 | Out-String $out | Should -Match "crash loop" } + It "connected: shows the client version" { + $script:ClientState = "connected" + Mock helm { "tracebloc tracebloc 1 now deployed client-1.4.4 1.4.4" } + $out = Print-Summary 6>&1 | Out-String + $out | Should -Match "Version" + $out | Should -Match "1\.4\.4" + } } Describe "ConvertTo-WorkspaceName" { @@ -228,6 +235,39 @@ Describe "Install-ClientHelm" { Install-ClientHelm (Get-Content "$HOST_DATA_DIR/values.yaml" -Raw) | Should -Match 'clientId: "previd"' } + It "blocks a DIFFERENT client already installed" { + $HOST_DATA_DIR = "$TestDrive/d5" + Mock Err { throw "err" } + Mock Read-Host { + param([string]$Prompt, [switch]$AsSecureString) + if ($Prompt -match 'password') { return (ConvertTo-SecureString "pw" -AsPlainText -Force) } + return "newclient" + } + Mock Test-Credentials { "valid" } + Mock helm { + if ($args -contains "list") { '[{"name":"oldrel","namespace":"default","chart":"client-1.4.3"}]'; $global:LASTEXITCODE = 0; return } + if ($args -contains "get") { 'clientId: "otherclient"'; $global:LASTEXITCODE = 0; return } + $global:LASTEXITCODE = 0 + } + { Install-ClientHelm } | Should -Throw + Should -Not -Invoke helm -ParameterFilter { $args -contains "upgrade" } + } + It "same client re-run is allowed (upgrade in place)" { + $HOST_DATA_DIR = "$TestDrive/d6" + Mock Read-Host { + param([string]$Prompt, [switch]$AsSecureString) + if ($Prompt -match 'password') { return (ConvertTo-SecureString "pw" -AsPlainText -Force) } + return "sameid" + } + Mock Test-Credentials { "valid" } + Mock helm { + if ($args -contains "list") { '[{"name":"tracebloc","namespace":"tracebloc","chart":"client-1.4.3"}]'; $global:LASTEXITCODE = 0; return } + if ($args -contains "get") { 'clientId: "sameid"'; $global:LASTEXITCODE = 0; return } + $global:LASTEXITCODE = 0 + } + Install-ClientHelm + Should -Invoke helm -ParameterFilter { $args -contains "upgrade" } + } } Describe "Confirm-Cluster" { diff --git a/scripts/tests/summary.bats b/scripts/tests/summary.bats index 924080a..7f0b91f 100644 --- a/scripts/tests/summary.bats +++ b/scripts/tests/summary.bats @@ -64,6 +64,14 @@ setup() { [[ "$output" == *"data never leaves"* ]] } +@test "print_summary connected: shows the client version" { + CLIENT_STATE=connected + helm() { echo "tracebloc tracebloc 1 now deployed client-1.4.4 1.4.4"; } + run print_summary + [[ "$output" == *"Version"* ]] + [[ "$output" == *"1.4.4"* ]] +} + @test "print_summary starting: 'still starting', no trust claim" { CLIENT_STATE=starting run print_summary