diff --git a/etc/init_1password.sh b/etc/init_1password.sh index 88a2d74..dfd79ab 100755 --- a/etc/init_1password.sh +++ b/etc/init_1password.sh @@ -38,6 +38,11 @@ _info "op CLI found: $(op --version)" # ── sign in ──────────────────────────────────────────────────────────────── if ! op whoami >/dev/null 2>&1; then + # If running non-interactively (no TTY), skip rather than hang. + if [[ ! -t 0 ]]; then + _warn "No active 1Password session and no TTY — skipping 1Password preflight." + exit 0 + fi _info "No active 1Password session. Signing in..." op signin fi diff --git a/etc/knoe_cfg.sh b/etc/knoe_cfg.sh index b3c157c..0e3e188 100644 --- a/etc/knoe_cfg.sh +++ b/etc/knoe_cfg.sh @@ -163,6 +163,10 @@ _knoe_cfg_set_default() { _knoe_read_cfg() { local cfg="$1" line key value + # In k3s mode the kubeconfig current-context is authoritative; never set + # KUBECTL_CONTEXT / KUBE_CONTEXT_NAME / KUBECONTEXT from cfg file entries. + local _knoe_read_cfg_mode + _knoe_read_cfg_mode=$(knoe_normalize_mode "${DEPLOYMENT_MODE:-${KNOE_MODE:-${CLUSTER_ENV:-${knoe_mode:-}}}}" 2>/dev/null || true) while IFS= read -r line || [[ -n "$line" ]]; do line="$(_knoe_trim "$line")" [[ -z "$line" ]] && continue @@ -178,6 +182,12 @@ _knoe_read_cfg() { # Normalize to a valid shell variable key for safe export. key="$(_knoe_cfg_normalize_key "$key")" [[ -z "$key" ]] && continue + # k3s: kubeconfig current-context is authoritative; skip context overrides from cfg. + if [[ "$_knoe_read_cfg_mode" == "k3s" ]]; then + case "$key" in + KUBECTL_CONTEXT|KUBE_CONTEXT_NAME|KUBECONTEXT) continue ;; + esac + fi value="$(_knoe_cfg_expand "$value")" _knoe_cfg_set_default "$key" "$value" fi @@ -790,7 +800,7 @@ if [[ -n "$_knoe_cfg_file" ]]; then ;; esac fi - if [[ $_override_runtime_ctx -eq 1 ]]; then + if [[ $_override_runtime_ctx -eq 1 && "$_cfg_mode_hint" != "k3s" ]]; then export KUBE_CONTEXT_NAME="$_cfg_ctx" export KUBECTL_CONTEXT="$_cfg_ctx" export KUBECONTEXT="$_cfg_ctx" diff --git a/knoe/core/milestones.py b/knoe/core/milestones.py index 6d6b819..08d4351 100644 --- a/knoe/core/milestones.py +++ b/knoe/core/milestones.py @@ -1862,6 +1862,21 @@ class KerberosMilestone(Milestone): if progress: progress("Initializing Kerberos...", 0.4) + # For k3s and k3d modes, deploy the KDC pod (authority-knoe-auth) via + # init_kdc.sh before running init_kerberos.sh. init_kerberos.sh only + # calls init_kdc.sh when PROLE_KDC_STANDALONE=1; we invoke it directly + # here so the pod is always present regardless of that flag. + if mode in ("k3s", "k3d"): + kdc_args = ["--mode", mode, "start"] if mode else ["start"] + self.logger.info("Deploying KDC pod via init_kdc.sh start ...") + rc_kdc = state.controller.run_script( + "init_kdc.sh", args=kdc_args, env=env, on_line=_stream_line + ) + if rc_kdc != 0: + msg = f"init_kdc.sh start failed (code {rc_kdc})" + self.logger.error(msg) + raise Exception(msg) + rc = state.controller.run_script( "init_kerberos.sh", args=args, env=env, on_line=_stream_line ) diff --git a/knoe/core/onepassword.py b/knoe/core/onepassword.py index 1ab48e0..b5436c7 100644 --- a/knoe/core/onepassword.py +++ b/knoe/core/onepassword.py @@ -41,7 +41,14 @@ def _op(*args: str, check: bool = True, timeout: int = 15) -> subprocess.Complet def ensure_op_signed_in() -> None: - """Ensure the op CLI has an active session; trigger sign-in if not.""" + """Ensure the op CLI has an active session; trigger sign-in if not. + + When running non-interactively (no TTY on stdin) and no session exists, + skip rather than hang or crash — the installer can proceed without 1Password + for k3s/k3d modes where secrets are managed separately. + """ + import sys + if not op_available(): raise RuntimeError( "1Password CLI (op) not found. Install: brew install 1password-cli" @@ -52,6 +59,12 @@ def ensure_op_signed_in() -> None: text=True, ) if result.returncode != 0: + if not sys.stdin.isatty(): + print( + "[WARN] No active 1Password session and no TTY — skipping op signin.", + flush=True, + ) + return subprocess.run(["op", "signin"], check=True) diff --git a/knoe/milestone.py b/knoe/milestone.py index da9e08c..3565403 100644 --- a/knoe/milestone.py +++ b/knoe/milestone.py @@ -169,9 +169,11 @@ class Milestone(ABC): env["KUBECONFIG"] = str(_kc) break # k3s kubeconfig's current-context is authoritative (typically "default"). - # Clear any stale KUBECONTEXT written from a different machine's config so - # kubectl uses KUBECONFIG without a --context override. + # Clear any stale KUBECONTEXT/KUBECTL_CONTEXT written from a different + # machine's config so kubectl uses KUBECONFIG without a --context override. env.pop("KUBECONTEXT", None) + env.pop("KUBECTL_CONTEXT", None) + env.pop("KUBE_CONTEXT_NAME", None) elif mode == "k3d": # Ensure k3d dev clusters have a resolvable KUBECONFIG. # The cluster may already be running from a previous session;