Skip to content

Commit 1016826

Browse files
committed
fix(ssh): improve embedded tmux readiness
1 parent f424ae0 commit 1016826

10 files changed

Lines changed: 68 additions & 22 deletions

File tree

cmd/okdev-sshd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ func buildInteractiveLoginScript(sessionEnv map[string]string, shell, workspace,
152152
func embeddedTmuxBootstrapScript() string {
153153
return strings.Join([]string{
154154
`if [ "${TERM:-}" = "xterm-ghostty" ]; then export TERM=xterm-256color; fi`,
155-
`if command -v tmux >/dev/null 2>&1; then exec tmux new-session -A -s okdev; fi`,
155+
`if command -v tmux >/dev/null 2>&1; then if [ -f /var/okdev/embedded.tmux.conf ]; then exec tmux -f /var/okdev/embedded.tmux.conf new-session -A -s okdev; fi; exec tmux new-session -A -s okdev; fi`,
156156
`echo 'warning: tmux not available in dev container; continuing without tmux' >&2`,
157157
}, "; ")
158158
}

cmd/okdev-sshd/main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ func TestBuildInteractiveLoginScriptIncludesEmbeddedTmuxBootstrap(t *testing.T)
1010

1111
for _, want := range []string{
1212
"/workspace/.okdev/post-attach.sh",
13+
"/var/okdev/embedded.tmux.conf",
1314
"exec tmux new-session -A -s okdev",
1415
} {
1516
if !strings.Contains(script, want) {

infra/sidecar/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ COPY --from=builder /okdev-sshd /usr/local/bin/okdev-sshd
3535

3636
COPY infra/sidecar/sshd_config /etc/ssh/sshd_config
3737
COPY infra/sidecar/tmux.conf /root/.tmux.conf
38+
COPY infra/sidecar/embedded-tmux.conf /etc/okdev-embedded.tmux.conf
3839
COPY infra/sidecar/entrypoint.sh /entrypoint.sh
3940
RUN chmod +x /entrypoint.sh
4041

infra/sidecar/embedded-tmux.conf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# okdev default tmux profile for embedded SSH sessions in the dev container.
2+
3+
set -g history-limit 200000
4+
set -g mouse on
5+
set -g renumber-windows on
6+
set -g base-index 1
7+
setw -g pane-base-index 1
8+
set -g detach-on-destroy off
9+
10+
set -g escape-time 0
11+
set -g focus-events on
12+
set -g set-clipboard on
13+
set -g default-terminal "tmux-256color"
14+
15+
setw -g mode-keys vi
16+
17+
set -g status-position bottom
18+
set -g status-interval 5
19+
set -g status-left-length 40
20+
set -g status-right-length 120
21+
set -g status-left "#[fg=cyan,bold]#S "
22+
set -g status-right "#[fg=colour245]#{pane_current_path} #[fg=cyan]%Y-%m-%d %H:%M"

infra/sidecar/entrypoint.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ if [ "$OKDEV_SSH_MODE" = "embedded" ]; then
186186
mkdir -p /var/okdev
187187
cp /usr/local/bin/okdev-sshd /var/okdev/okdev-sshd
188188
chmod +x /var/okdev/okdev-sshd
189+
cp /etc/okdev-embedded.tmux.conf /var/okdev/embedded.tmux.conf
190+
chmod 644 /var/okdev/embedded.tmux.conf
189191
fi
190192

191193
# Start syncthing in background (run as root for workspace access)

internal/cli/ssh.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,8 @@ fi
370370
if ps | grep '[o]kdev-sshd' >/dev/null 2>&1; then
371371
exit 0
372372
fi
373+
export OKDEV_WORKSPACE="${OKDEV_WORKSPACE:-/workspace}"
374+
export OKDEV_TMUX="${OKDEV_TMUX:-0}"
373375
nohup /var/okdev/okdev-sshd --port 2222 --authorized-keys "$HOME/.ssh/authorized_keys" >/var/okdev/okdev-sshd.log 2>&1 </dev/null &
374376
`
375377

internal/cli/ssh_embedded_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ func TestEnsureEmbeddedSSHDRunning(t *testing.T) {
1919
for _, want := range []string{
2020
"/var/okdev/okdev-sshd",
2121
"$HOME/.ssh/authorized_keys",
22+
`export OKDEV_TMUX="${OKDEV_TMUX:-0}"`,
23+
`export OKDEV_WORKSPACE="${OKDEV_WORKSPACE:-/workspace}"`,
2224
"nohup /var/okdev/okdev-sshd",
2325
} {
2426
if !strings.Contains(fake.lastScript, want) {

internal/cli/up.go

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -175,41 +175,28 @@ func newUpCmd(opts *Options) *cobra.Command {
175175
}
176176
ui.stepDone("pod readiness", "ready")
177177

178-
if err := session.SaveActiveSession(sn); err != nil {
179-
return err
180-
}
181-
ui.stepDone("active session", sn)
182-
if err := session.ClearShutdownRequest(sn); err != nil {
183-
ui.warnf("failed to clear prior shutdown request: %v", err)
184-
}
185-
186178
ui.section("Setup")
187179
sshSummary := "disabled"
188180
effectiveSSHPort := sshRemotePortForMode(cfg, sshMode)
189181
if effectiveSSHPort > 0 {
190182
keyPath, keyErr := defaultSSHKeyPath(cfg)
191183
if keyErr != nil {
192-
ui.warnf("failed to resolve SSH key path: %v", keyErr)
193-
sshSummary = "degraded (key path error)"
184+
return fmt.Errorf("resolve SSH key path: %w", keyErr)
194185
} else {
195186
if err := ensureSSHKeyOnPod(opts, cfg, ns, pod, keyPath, sshMode); err != nil {
196-
ui.warnf("failed to setup SSH key in pod: %v", err)
197-
sshSummary = "degraded (key setup failed)"
187+
return fmt.Errorf("setup SSH key in pod: %w", err)
198188
}
199-
if err := waitForSSHDReady(opts, cfg, ns, pod, sshMode, 20*time.Second); err != nil {
200-
ui.warnf("sshd not ready yet: %v", err)
201-
sshSummary = "degraded (sshd not ready)"
189+
if err := waitForSSHDReady(opts, cfg, ns, pod, sshMode, waitTimeout); err != nil {
190+
return fmt.Errorf("wait for SSH service: %w", err)
202191
}
203192
alias := sshHostAlias(sn)
204193
if _, cfgErr := ensureSSHConfigEntry(alias, sn, ns, cfg.Spec.SSH.User, effectiveSSHPort, keyPath, cfgPath, cfg.Spec.Ports); cfgErr != nil {
205-
ui.warnf("failed to update ~/.ssh/config: %v", cfgErr)
206-
sshSummary = "degraded (ssh config update failed)"
194+
return fmt.Errorf("update ~/.ssh/config: %w", cfgErr)
207195
} else {
208196
// Force-refresh managed master so forward rules are always current after `okdev up`.
209197
_ = stopManagedSSHForward(alias)
210198
if err := startManagedSSHForwardWithForwards(alias, cfg.Spec.Ports, cfg.Spec.SSH); err != nil {
211-
ui.warnf("failed to start managed SSH/port-forwards: %v", err)
212-
sshSummary = "degraded (managed forward failed)"
199+
return fmt.Errorf("start managed SSH/port-forwards: %w", err)
213200
} else {
214201
sshSummary = "ssh " + alias
215202
ui.stepDone("ssh", sshSummary)
@@ -223,8 +210,7 @@ func newUpCmd(opts *Options) *cobra.Command {
223210
if cfg.Spec.Sync.Engine == "" || cfg.Spec.Sync.Engine == "syncthing" {
224211
logPath, started, err := startDetachedSyncthingSync(opts, upDefaultSyncMode, sn, ns, cfgPath)
225212
if err != nil {
226-
ui.warnf("failed to start syncthing background sync: %v", err)
227-
syncSummary = "degraded (start failed)"
213+
return fmt.Errorf("start syncthing background sync: %w", err)
228214
} else {
229215
syncModeSymbol = modeSymbol(upDefaultSyncMode)
230216
syncPathSummary := syncPairsSummary(syncPairs, syncModeSymbol)
@@ -289,6 +275,13 @@ func newUpCmd(opts *Options) *cobra.Command {
289275
}
290276
}
291277
}
278+
if err := session.SaveActiveSession(sn); err != nil {
279+
return err
280+
}
281+
ui.stepDone("active session", sn)
282+
if err := session.ClearShutdownRequest(sn); err != nil {
283+
ui.warnf("failed to clear prior shutdown request: %v", err)
284+
}
292285

293286
ui.printWarnings()
294287
ui.printReadyCard(sn, ns, pod, sshSummary, syncSummary, cfg.Spec.Ports, syncPairs, syncModeSymbol)

internal/kube/podspec.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ func PreparePodSpec(podSpec corev1.PodSpec, volumes []corev1.Volume, workspaceMo
6363
Name: "OKDEV_CONTAINER_ROLE",
6464
Value: "dev",
6565
})
66+
if tmux {
67+
spec.Containers[i].Env = ensureEnvVar(spec.Containers[i].Env, corev1.EnvVar{
68+
Name: "OKDEV_TMUX",
69+
Value: "1",
70+
})
71+
}
6672
}
6773
}
6874

internal/kube/podspec_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,20 @@ func TestPreparePodSpecEmbeddedSSHMode(t *testing.T) {
174174
}
175175
})
176176
}
177+
178+
func TestPreparePodSpecSetsDevTmuxEnvWhenEnabled(t *testing.T) {
179+
spec, err := PreparePodSpec(corev1.PodSpec{}, nil, "/workspace", "ghcr.io/acmore/okdev-sidecar:edge", true, true, "")
180+
if err != nil {
181+
t.Fatal(err)
182+
}
183+
dev := findContainer(spec.Containers, "dev")
184+
if dev == nil {
185+
t.Fatal("dev container not found")
186+
}
187+
for _, env := range dev.Env {
188+
if env.Name == "OKDEV_TMUX" && env.Value == "1" {
189+
return
190+
}
191+
}
192+
t.Fatal("expected OKDEV_TMUX=1 on dev container when tmux is enabled")
193+
}

0 commit comments

Comments
 (0)