@@ -7,12 +7,14 @@ import (
77 "log/slog"
88 "os"
99 "strconv"
10+ "strings"
1011 "time"
1112
1213 "github.com/acmore/okdev/internal/config"
1314 "github.com/acmore/okdev/internal/kube"
1415 "github.com/acmore/okdev/internal/session"
1516 "github.com/spf13/cobra"
17+ apierrors "k8s.io/apimachinery/pkg/api/errors"
1618)
1719
1820func newUpCmd (opts * Options ) * cobra.Command {
@@ -61,6 +63,16 @@ func newUpCmd(opts *Options) *cobra.Command {
6163 if warnErr := warnIfConfigNewerThanSession (opts , k , ns , sn , pod , cmd .ErrOrStderr ()); warnErr != nil {
6264 slog .Debug ("skip config drift warning" , "error" , warnErr )
6365 }
66+ existingRunningReady := false
67+ {
68+ ctxCheck , cancelCheck := context .WithTimeout (context .Background (), 10 * time .Second )
69+ defer cancelCheck ()
70+ if ps , perr := k .GetPodSummary (ctxCheck , ns , pod ); perr == nil {
71+ existingRunningReady = strings .EqualFold (ps .Phase , "Running" ) && podReadyFromSummary (ps .Ready )
72+ } else if ! apierrors .IsNotFound (perr ) {
73+ return perr
74+ }
75+ }
6476
6577 ctx , cancel := defaultContext ()
6678 defer cancel ()
@@ -75,36 +87,40 @@ func newUpCmd(opts *Options) *cobra.Command {
7587 }
7688 }
7789
78- preparedSpec , err := kube .PreparePodSpec (
90+ preparedSpec , err := kube .PreparePodSpecWithSSH (
7991 cfg .Spec .PodTemplate .Spec ,
8092 pvc ,
8193 cfg .Spec .Workspace .MountPath ,
8294 cfg .Spec .Sync .Engine == "syncthing" ,
8395 cfg .Spec .Sync .Syncthing .Image ,
96+ strings .EqualFold (cfg .Spec .SSH .Mode , "sidecar" ),
97+ cfg .Spec .SSH .SidecarImage ,
8498 )
8599 if err != nil {
86100 return err
87101 }
88102
89- podManifest , err := kube .BuildPodManifest (ns , pod , labels , annotations , preparedSpec )
90- if err != nil {
91- return err
92- }
93- if err := k .Apply (ctx , ns , podManifest ); err != nil {
94- return err
95- }
96- progressPrinter := func (p kube.PodReadinessProgress ) {
97- fmt .Fprintf (cmd .OutOrStdout (), "Waiting for pod/%s: phase=%s ready=%d/%d reason=%s\n " , pod , p .Phase , p .ReadyContainers , p .TotalContainers , p .Reason )
98- }
99- if err := k .WaitReadyWithProgress (ctx , ns , pod , waitTimeout , progressPrinter ); err != nil {
100- hints := fmt .Sprintf ("next steps:\n - run `okdev status --session %s`\n - run `kubectl -n %s describe pod %s`" , sn , ns , pod )
101- diag , derr := k .DescribePod (ctx , ns , pod )
102- if derr == nil {
103- fmt .Fprintf (cmd .ErrOrStderr (), "pod diagnostics:\n %s\n \n %s\n " , diag , hints )
103+ if ! existingRunningReady {
104+ podManifest , err := kube .BuildPodManifest (ns , pod , labels , annotations , preparedSpec )
105+ if err != nil {
106+ return err
107+ }
108+ if err := k .Apply (ctx , ns , podManifest ); err != nil {
109+ return err
110+ }
111+ progressPrinter := func (p kube.PodReadinessProgress ) {
112+ fmt .Fprintf (cmd .OutOrStdout (), "Waiting for pod/%s: phase=%s ready=%d/%d reason=%s\n " , pod , p .Phase , p .ReadyContainers , p .TotalContainers , p .Reason )
113+ }
114+ if err := k .WaitReadyWithProgress (ctx , ns , pod , waitTimeout , progressPrinter ); err != nil {
115+ hints := fmt .Sprintf ("next steps:\n - run `okdev status --session %s`\n - run `kubectl -n %s describe pod %s`" , sn , ns , pod )
116+ diag , derr := k .DescribePod (ctx , ns , pod )
117+ if derr == nil {
118+ fmt .Fprintf (cmd .ErrOrStderr (), "pod diagnostics:\n %s\n \n %s\n " , diag , hints )
119+ return fmt .Errorf ("wait for pod/%s readiness failed: %w" , pod , err )
120+ }
121+ fmt .Fprintln (cmd .ErrOrStderr (), hints )
104122 return fmt .Errorf ("wait for pod/%s readiness failed: %w" , pod , err )
105123 }
106- fmt .Fprintln (cmd .ErrOrStderr (), hints )
107- return fmt .Errorf ("wait for pod/%s readiness failed: %w" , pod , err )
108124 }
109125
110126 if err := session .SaveActiveSession (sn ); err != nil {
@@ -132,29 +148,34 @@ func newUpCmd(opts *Options) *cobra.Command {
132148 forwards = append (forwards , strconv .Itoa (p .Local )+ ":" + strconv .Itoa (p .Remote ))
133149 }
134150 if len (forwards ) > 0 {
135- cancelPF , err := startManagedPortForwardWithClient (k , ns , pod , forwards )
151+ cancelPF , err := startManagedPortForwardNoProbeWithClient (k , ns , pod , forwards )
136152 if err != nil {
137- return fmt .Errorf ("start background port-forward: %w" , err )
153+ fmt .Fprintf (cmd .ErrOrStderr (), "warning: failed to start background port-forward: %v\n " , err )
154+ } else {
155+ stopBackgrounds = append (stopBackgrounds , cancelPF )
156+ fmt .Fprintf (cmd .OutOrStdout (), "Background port-forward active: %v\n " , forwards )
138157 }
139- stopBackgrounds = append (stopBackgrounds , cancelPF )
140- fmt .Fprintf (cmd .OutOrStdout (), "Background port-forward active: %v\n " , forwards )
141158 }
142159 }
143160 if cfg .Spec .SSH .LocalPort > 0 && cfg .Spec .SSH .RemotePort > 0 {
144161 keyPath , keyErr := defaultSSHKeyPath (cfg )
145162 if keyErr != nil {
146163 fmt .Fprintf (cmd .ErrOrStderr (), "warning: failed to resolve SSH key path: %v\n " , keyErr )
147164 } else {
148- if err := ensureSSHKeyOnPod (opts , ns , pod , keyPath ); err != nil {
165+ if err := ensureSSHKeyOnPod (opts , cfg , ns , pod , keyPath ); err != nil {
149166 fmt .Fprintf (cmd .ErrOrStderr (), "warning: failed to setup SSH key in pod: %v\n " , err )
150167 } else {
151168 sshForward := []string {strconv .Itoa (cfg .Spec .SSH .LocalPort ) + ":" + strconv .Itoa (cfg .Spec .SSH .RemotePort )}
152- cancelSSH , err := startManagedPortForwardWithClient (k , ns , pod , sshForward )
169+ cancelSSH , err := startManagedPortForwardNoProbeWithClient (k , ns , pod , sshForward )
153170 if err != nil {
154171 fmt .Fprintf (cmd .ErrOrStderr (), "warning: failed to start SSH port-forward %v: %v\n " , sshForward , err )
155172 } else {
156173 stopBackgrounds = append (stopBackgrounds , cancelSSH )
157- fmt .Fprintf (cmd .OutOrStdout (), "Background SSH tunnel active: ssh -p %d -i %s %s@127.0.0.1\n " , cfg .Spec .SSH .LocalPort , keyPath , cfg .Spec .SSH .User )
174+ alias := sshHostAlias (sn )
175+ if cfgErr := ensureSSHConfigEntry (alias , cfg .Spec .SSH .User , cfg .Spec .SSH .LocalPort , keyPath ); cfgErr != nil {
176+ fmt .Fprintf (cmd .ErrOrStderr (), "warning: failed to update ~/.ssh/config: %v\n " , cfgErr )
177+ }
178+ fmt .Fprintf (cmd .OutOrStdout (), "Background SSH tunnel active: ssh %s\n " , alias )
158179 }
159180 }
160181 }
@@ -206,3 +227,11 @@ func warnIfConfigNewerThanSession(opts *Options, k *kube.Client, namespace, sess
206227 }
207228 return nil
208229}
230+
231+ func podReadyFromSummary (ready string ) bool {
232+ parts := strings .Split (strings .TrimSpace (ready ), "/" )
233+ if len (parts ) != 2 {
234+ return false
235+ }
236+ return parts [0 ] == parts [1 ] && parts [0 ] != "0"
237+ }
0 commit comments