@@ -25,11 +25,19 @@ import (
2525 apierrors "k8s.io/apimachinery/pkg/api/errors"
2626)
2727
28- const sessionHeartbeatInterval = 5 * time .Minute
29- const sshPort = 2222
30-
3128var invalidOwnerChars = regexp .MustCompile (`[^a-z0-9._-]` )
3229
30+ type sessionResolver func (* Options , * config.DevEnvironment , string ) (string , error )
31+
32+ type commandContext struct {
33+ opts * Options
34+ cfg * config.DevEnvironment
35+ cfgPath string
36+ namespace string
37+ sessionName string
38+ kube * kube.Client
39+ }
40+
3341func loadConfigAndNamespace (opts * Options ) (* config.DevEnvironment , string , error ) {
3442 path , err := config .ResolvePath (opts .ConfigPath )
3543 if err != nil {
@@ -56,6 +64,33 @@ func loadConfigAndNamespace(opts *Options) (*config.DevEnvironment, string, erro
5664 return cfg , ns , nil
5765}
5866
67+ func resolveCommandContext (opts * Options , resolver sessionResolver ) (* commandContext , error ) {
68+ cfg , namespace , err := loadConfigAndNamespace (opts )
69+ if err != nil {
70+ return nil , err
71+ }
72+ cfgPath , err := config .ResolvePath (opts .ConfigPath )
73+ if err != nil {
74+ return nil , err
75+ }
76+ cc := & commandContext {
77+ opts : opts ,
78+ cfg : cfg ,
79+ cfgPath : cfgPath ,
80+ namespace : namespace ,
81+ kube : newKubeClient (opts ),
82+ }
83+ if resolver == nil {
84+ return cc , nil
85+ }
86+ sessionName , err := resolver (opts , cfg , namespace )
87+ if err != nil {
88+ return nil , err
89+ }
90+ cc .sessionName = sessionName
91+ return cc , nil
92+ }
93+
5994func withQuietConfigAnnounce (fn func () error ) error {
6095 prevQuiet , hadQuiet := os .LookupEnv ("OKDEV_QUIET_CONFIG_ANNOUNCE" )
6196 _ = os .Setenv ("OKDEV_QUIET_CONFIG_ANNOUNCE" , "1" )
@@ -139,7 +174,7 @@ func newTransientStatusWithMode(w io.Writer, message string, interactive bool) *
139174 s .enabled = true
140175 s .stopCh = make (chan struct {})
141176 s .doneCh = make (chan struct {})
142- go s .run (120 * time . Millisecond )
177+ go s .run (statusSpinnerInterval )
143178 return s
144179}
145180
@@ -225,10 +260,6 @@ func resolveSessionName(opts *Options, cfg *config.DevEnvironment, namespace str
225260 return resolveSessionNameWithState (opts , cfg , namespace , true )
226261}
227262
228- func resolveSessionNameForUpDown (opts * Options , cfg * config.DevEnvironment , namespace string ) (string , error ) {
229- return resolveSessionNameWithState (opts , cfg , namespace , true )
230- }
231-
232263func resolveSessionNameWithState (opts * Options , cfg * config.DevEnvironment , namespace string , inferExisting bool ) (string , error ) {
233264 return resolveSessionNameWithReader (opts , cfg , namespace , inferExisting , newKubeClient (opts ))
234265}
@@ -251,7 +282,9 @@ func resolveSessionNameWithReader(opts *Options, cfg *config.DevEnvironment, nam
251282 if exists {
252283 return resolvedActive , nil
253284 }
254- _ = session .ClearActiveSession ()
285+ if clearErr := session .ClearActiveSession (); clearErr != nil {
286+ slog .Debug ("failed to clear stale active session" , "session" , resolvedActive , "error" , clearErr )
287+ }
255288 } else {
256289 slog .Debug ("failed to verify active session pod" , "session" , resolvedActive , "namespace" , namespace , "error" , existsErr )
257290 return resolvedActive , nil
@@ -270,7 +303,7 @@ func resolveSessionNameWithReader(opts *Options, cfg *config.DevEnvironment, nam
270303}
271304
272305func sessionPodExists (k sessionAccessReader , namespace , sessionName string ) (bool , error ) {
273- ctx , cancel := context .WithTimeout (context .Background (), 10 * time . Second )
306+ ctx , cancel := context .WithTimeout (context .Background (), sessionExistsTimeout )
274307 defer cancel ()
275308 pods , err := k .ListPods (ctx , namespace , false , "okdev.io/managed=true,okdev.io/session=" + sessionName )
276309 if err == nil {
@@ -303,7 +336,7 @@ func inferExistingSessionForRepo(opts *Options, cfg *config.DevEnvironment, name
303336 if strings .TrimSpace (cfg .Metadata .Name ) != "" {
304337 label = append (label , "okdev.io/name=" + cfg .Metadata .Name )
305338 }
306- ctx , cancel := context .WithTimeout (context .Background (), 10 * time . Second )
339+ ctx , cancel := context .WithTimeout (context .Background (), sessionExistsTimeout )
307340 defer cancel ()
308341 pods , err := newKubeClient (opts ).ListPods (ctx , namespace , false , strings .Join (label , "," ))
309342 if err != nil {
@@ -376,7 +409,7 @@ func newKubeClient(opts *Options) *kube.Client {
376409}
377410
378411func defaultContext () (context.Context , context.CancelFunc ) {
379- return context .WithTimeout (context .Background (), 5 * time . Minute )
412+ return context .WithTimeout (context .Background (), defaultContextTimeout )
380413}
381414
382415func interactiveContext () (context.Context , context.CancelFunc ) {
@@ -394,13 +427,11 @@ func runConnectWithClient(k *kube.Client, namespace string, target workload.Targ
394427 return connect .Run (ctx , k , namespace , target .PodName , command , tty , os .Stdin , os .Stdout , os .Stderr )
395428}
396429
397- func startSessionMaintenance (opts * Options , cfg * config. DevEnvironment , namespace , sessionName string , out io.Writer , renewLock bool , emitHeartbeat bool ) func () {
398- return startSessionMaintenanceWithClient (newKubeClient (opts ), cfg , namespace , sessionName , out , renewLock , emitHeartbeat )
430+ func startSessionMaintenance (opts * Options , namespace , sessionName string , out io.Writer , emitHeartbeat bool ) func () {
431+ return startSessionMaintenanceWithClient (newKubeClient (opts ), namespace , sessionName , out , emitHeartbeat )
399432}
400433
401- func startSessionMaintenanceWithClient (k * kube.Client , cfg * config.DevEnvironment , namespace , sessionName string , out io.Writer , renewLock bool , emitHeartbeat bool ) func () {
402- _ = cfg
403- _ = renewLock
434+ func startSessionMaintenanceWithClient (k * kube.Client , namespace , sessionName string , out io.Writer , emitHeartbeat bool ) func () {
404435 if ! emitHeartbeat {
405436 return func () {}
406437 }
@@ -410,13 +441,15 @@ func startSessionMaintenanceWithClient(k *kube.Client, cfg *config.DevEnvironmen
410441 pod = target .PodName
411442 }
412443 ctx , cancel := context .WithCancel (context .Background ())
444+ done := make (chan struct {})
413445
414446 go func () {
447+ defer close (done )
415448 heartbeatTicker := time .NewTicker (sessionHeartbeatInterval )
416449 defer heartbeatTicker .Stop ()
417450
418451 doHeartbeat := func () {
419- beatCtx , beatCancel := context .WithTimeout (context .Background (), 10 * time . Second )
452+ beatCtx , beatCancel := context .WithTimeout (context .Background (), heartbeatWriteTimeout )
420453 err := k .TouchPodActivity (beatCtx , namespace , pod )
421454 beatCancel ()
422455 if err != nil {
@@ -436,7 +469,10 @@ func startSessionMaintenanceWithClient(k *kube.Client, cfg *config.DevEnvironmen
436469 }
437470 }()
438471
439- return cancel
472+ return func () {
473+ cancel ()
474+ <- done
475+ }
440476}
441477
442478func currentOwner (opts * Options ) string {
@@ -487,7 +523,7 @@ type sessionAccessReader interface {
487523}
488524
489525func ensureSessionAccess (opts * Options , k sessionAccessReader , namespace , sessionName string , allowShareable bool , requireExisting bool ) error {
490- ctx , cancel := context .WithTimeout (context .Background (), 15 * time . Second )
526+ ctx , cancel := context .WithTimeout (context .Background (), sessionAccessTimeout )
491527 defer cancel ()
492528 pods , err := k .ListPods (ctx , namespace , false , "okdev.io/managed=true,okdev.io/session=" + sessionName )
493529 if err != nil {
0 commit comments