@@ -3,7 +3,11 @@ package devpod
33import (
44 "context"
55 "fmt"
6+ "github.com/mgutz/ansi"
67 "io"
8+ kerrors "k8s.io/apimachinery/pkg/api/errors"
9+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+ "k8s.io/apimachinery/pkg/util/wait"
711 "net/http"
812 "os"
913 syncpkg "sync"
@@ -64,13 +68,14 @@ func newDevPod() *devPod {
6468
6569func (d * devPod ) Start (ctx * devspacecontext.Context , devPodConfig * latest.DevPod , options Options ) error {
6670 d .m .Lock ()
67- defer d .m .Unlock ()
68-
6971 if d .cancel != nil {
72+ d .m .Unlock ()
7073 return errors .Errorf ("dev pod is already running, please stop it before starting" )
7174 }
75+
7276 d .cancelCtx , d .cancel = context .WithCancel (ctx .Context )
7377 ctx = ctx .WithContext (d .cancelCtx )
78+ d .m .Unlock ()
7479
7580 // log devpod to console if debug
7681 if ctx .Log .GetLevel () == logrus .DebugLevel {
@@ -83,8 +88,7 @@ func (d *devPod) Start(ctx *devspacecontext.Context, devPodConfig *latest.DevPod
8388 // start the dev pod
8489 err := d .startWithRetry (ctx , devPodConfig , options )
8590 if err != nil {
86- d .cancel ()
87- <- d .done
91+ d .Stop ()
8892 return err
8993 }
9094
@@ -104,57 +108,70 @@ func (d *devPod) Done() <-chan struct{} {
104108
105109func (d * devPod ) Stop () {
106110 d .m .Lock ()
107- defer d .m .Lock ()
108-
109111 if d .cancel != nil {
110112 d .cancel ()
111- <- d .done
112113 }
114+ d .m .Unlock ()
115+ <- d .done
113116}
114117
115118func (d * devPod ) startWithRetry (ctx * devspacecontext.Context , devPodConfig * latest.DevPod , options Options ) error {
116119 t := & tomb.Tomb {}
117120
118121 go func (ctx * devspacecontext.Context ) {
122+ // wait for parent context cancel
123+ // or that the DevPod is done
119124 select {
120125 case <- ctx .Context .Done ():
126+ case <- t .Dead ():
127+ }
128+
129+ if ctx .IsDone () {
121130 <- t .Dead ()
122131 close (d .done )
123132 return
124- case <- t .Dead ():
125- if ctx .IsDone () {
126- close (d .done )
127- return
128- }
129-
130- // try restarting the dev pod if it has stopped because of
131- // a lost connection
132- if _ , ok := t .Err ().(DevPodLostConnection ); ok {
133- for {
134- err := d .startWithRetry (ctx , devPodConfig , options )
135- if err != nil {
136- if ctx .IsDone () {
137- return
138- }
133+ }
139134
140- ctx .Log .Infof ("Restart dev %s because of: %v" , devPodConfig .Name , err )
141- select {
142- case <- ctx .Context .Done ():
143- return
144- case <- time .After (time .Second * 10 ):
145- continue
146- }
135+ // check if pod was terminated
136+ d .m .Lock ()
137+ selectedPod := d .selectedPod
138+ d .selectedPod = nil
139+ d .m .Unlock ()
140+
141+ // check if we need to restart
142+ if selectedPod != nil {
143+ shouldTerminate := false
144+ err := wait .PollImmediateUntil (time .Second , func () (bool , error ) {
145+ pod , err := ctx .KubeClient .KubeClient ().CoreV1 ().Pods (selectedPod .Pod .Namespace ).Get (ctx .Context , selectedPod .Pod .Name , metav1.GetOptions {})
146+ if err != nil {
147+ if kerrors .IsNotFound (err ) {
148+ d .restart (ctx , devPodConfig , options )
149+ return true , nil
147150 }
148151
149- return
152+ // this case means there might be problems with internet
153+ ctx .Log .Debugf ("error trying to retrieve pod: %v" , err )
154+ return false , nil
155+ } else if pod .DeletionTimestamp != nil {
156+ d .restart (ctx , devPodConfig , options )
157+ return true , nil
150158 }
151- } else {
152- d .m .Lock ()
153- d .err = t .Err ()
154- d .m .Unlock ()
155- close (d .done )
159+
160+ shouldTerminate = true
161+ return true , nil
162+ }, ctx .Context .Done ())
163+ if err != nil && err != context .Canceled {
164+ ctx .Log .Errorf ("error restarting dev: %v" , err )
165+ }
166+ if ! shouldTerminate {
167+ return
156168 }
157169 }
170+
171+ d .m .Lock ()
172+ d .err = t .Err ()
173+ d .m .Unlock ()
174+ close (d .done )
158175 }(ctx )
159176
160177 // Create a new tomb and run it
@@ -170,6 +187,27 @@ func (d *devPod) startWithRetry(ctx *devspacecontext.Context, devPodConfig *late
170187 return nil
171188}
172189
190+ func (d * devPod ) restart (ctx * devspacecontext.Context , devPodConfig * latest.DevPod , options Options ) {
191+ for {
192+ err := d .startWithRetry (ctx , devPodConfig , options )
193+ if err != nil {
194+ if ctx .IsDone () {
195+ return
196+ }
197+
198+ ctx .Log .Infof ("Restart dev %s because of: %v" , devPodConfig .Name , err )
199+ select {
200+ case <- ctx .Context .Done ():
201+ return
202+ case <- time .After (time .Second * 10 ):
203+ continue
204+ }
205+ }
206+
207+ return
208+ }
209+ }
210+
173211func (d * devPod ) start (ctx * devspacecontext.Context , devPodConfig * latest.DevPod , opts Options , parent * tomb.Tomb ) error {
174212 // check first if we need to replace the pod
175213 if ! opts .DisablePodReplace && needPodReplace (devPodConfig ) {
@@ -204,14 +242,20 @@ func (d *devPod) start(ctx *devspacecontext.Context, devPodConfig *latest.DevPod
204242 WithWaitingStrategy (targetselector .NewUntilNewestRunningWaitingStrategy (time .Millisecond * 500 )).
205243 WithSkipInitContainers (true )
206244 var err error
207- d . selectedPod , err = targetselector .NewTargetSelector (options ).SelectSingleContainer (ctx .Context , ctx .KubeClient , ctx .Log )
245+ selectedPod , err : = targetselector .NewTargetSelector (options ).SelectSingleContainer (ctx .Context , ctx .KubeClient , ctx .Log )
208246 if err != nil {
209247 return errors .Wrap (err , "waiting for pod to become ready" )
210248 }
211- ctx .Log .Debugf ("Selected pod:container %s:%s" , d .selectedPod .Pod .Name , d .selectedPod .Container .Name )
249+ ctx .Log .Infof ("Selected %s (%s)" , ansi .Color (fmt .Sprintf ("%s:%s" , selectedPod .Pod .Name , selectedPod .Container .Name ), "yellow+b" ), ansi .Color ("pod:container" , "white+b" ))
250+
251+ // set selected pod
252+ d .m .Lock ()
253+ d .selectedPod = selectedPod
254+ d .m .Unlock ()
212255
213256 // Run dev.open configs
214257 if ! opts .DisableOpen {
258+ ctx := ctx .WithLogger (ctx .Log .WithPrefixColor ("open " , "yellow+b" ))
215259 for _ , openConfig := range devPodConfig .Open {
216260 if openConfig .URL != "" {
217261 url := openConfig .URL
@@ -239,34 +283,35 @@ func (d *devPod) start(ctx *devspacecontext.Context, devPodConfig *latest.DevPod
239283 }
240284
241285 // start sync and port forwarding
242- err = d .startServices (ctx , devPodConfig , newTargetSelector (d . selectedPod .Pod .Name , d . selectedPod .Pod .Namespace , d . selectedPod .Container .Name , parent ), opts , parent )
286+ err = d .startServices (ctx , devPodConfig , newTargetSelector (selectedPod .Pod .Name , selectedPod .Pod .Namespace , selectedPod .Container .Name , parent ), opts , parent )
243287 if err != nil {
244288 return err
245289 }
246290
247291 // start logs
248292 terminalDevContainer := d .getTerminalDevContainer (devPodConfig )
249293 if terminalDevContainer != nil {
250- return d .startTerminal (ctx , terminalDevContainer , opts , parent )
294+ return d .startTerminal (ctx , terminalDevContainer , opts , selectedPod , parent )
251295 }
252296
253297 // start attach if defined
254298 attachDevContainer := d .getAttachDevContainer (devPodConfig )
255299 if attachDevContainer != nil {
256- return d .startAttach (ctx , attachDevContainer , opts , parent )
300+ return d .startAttach (ctx , attachDevContainer , opts , selectedPod , parent )
257301 }
258302
259- return d .startLogs (ctx , devPodConfig , parent )
303+ return d .startLogs (ctx , devPodConfig , selectedPod , parent )
260304}
261305
262- func (d * devPod ) startLogs (ctx * devspacecontext.Context , devPodConfig * latest.DevPod , parent * tomb.Tomb ) error {
306+ func (d * devPod ) startLogs (ctx * devspacecontext.Context , devPodConfig * latest.DevPod , selectedPod * selector.SelectedPodContainer , parent * tomb.Tomb ) error {
307+ ctx = ctx .WithLogger (ctx .Log .WithPrefixColor ("logs " , "yellow+b" ))
263308 loader .EachDevContainer (devPodConfig , func (devContainer * latest.DevContainer ) bool {
264309 if devContainer .Logs == nil || (devContainer .Logs .Enabled != nil && ! * devContainer .Logs .Enabled ) {
265310 return true
266311 }
267312
268313 parent .Go (func () error {
269- return logs .StartLogs (ctx , devContainer , newTargetSelector (d . selectedPod .Pod .Name , d . selectedPod .Pod .Namespace , d . selectedPod .Container .Name , parent ))
314+ return logs .StartLogs (ctx , devContainer , newTargetSelector (selectedPod .Pod .Name , selectedPod .Pod .Namespace , selectedPod .Container .Name , parent ))
270315 })
271316
272317 return true
@@ -303,7 +348,7 @@ func (d *devPod) getTerminalDevContainer(devPodConfig *latest.DevPod) *latest.De
303348 return devContainer
304349}
305350
306- func (d * devPod ) startAttach (ctx * devspacecontext.Context , devContainer * latest.DevContainer , opts Options , parent * tomb.Tomb ) error {
351+ func (d * devPod ) startAttach (ctx * devspacecontext.Context , devContainer * latest.DevContainer , opts Options , selectedPod * selector. SelectedPodContainer , parent * tomb.Tomb ) error {
307352 parent .Go (func () error {
308353 id , err := logpkg .AcquireGlobalSilence ()
309354 if err != nil {
@@ -312,10 +357,11 @@ func (d *devPod) startAttach(ctx *devspacecontext.Context, devContainer *latest.
312357 defer logpkg .ReleaseGlobalSilence (id )
313358
314359 // make sure the global log is silent
360+ ctx = ctx .WithLogger (ctx .Log .WithPrefixColor ("attach " , "yellow+b" ))
315361 err = attach .StartAttach (
316362 ctx ,
317363 devContainer ,
318- newTargetSelector (d . selectedPod .Pod .Name , d . selectedPod .Pod .Namespace , d . selectedPod .Container .Name , parent ),
364+ newTargetSelector (selectedPod .Pod .Name , selectedPod .Pod .Namespace , selectedPod .Container .Name , parent ),
319365 DefaultTerminalStdout ,
320366 DefaultTerminalStderr ,
321367 DefaultTerminalStdin ,
@@ -325,6 +371,11 @@ func (d *devPod) startAttach(ctx *devspacecontext.Context, devContainer *latest.
325371 return errors .Wrap (err , "error in attach" )
326372 }
327373
374+ // if context is done we just return
375+ if ctx .IsDone () {
376+ return nil
377+ }
378+
328379 // kill ourselves here
329380 if ! opts .ContinueOnTerminalExit && opts .KillApplication != nil {
330381 go opts .KillApplication ()
@@ -337,7 +388,7 @@ func (d *devPod) startAttach(ctx *devspacecontext.Context, devContainer *latest.
337388 return nil
338389}
339390
340- func (d * devPod ) startTerminal (ctx * devspacecontext.Context , devContainer * latest.DevContainer , opts Options , parent * tomb.Tomb ) error {
391+ func (d * devPod ) startTerminal (ctx * devspacecontext.Context , devContainer * latest.DevContainer , opts Options , selectedPod * selector. SelectedPodContainer , parent * tomb.Tomb ) error {
341392 parent .Go (func () error {
342393 id , err := logpkg .AcquireGlobalSilence ()
343394 if err != nil {
@@ -346,10 +397,11 @@ func (d *devPod) startTerminal(ctx *devspacecontext.Context, devContainer *lates
346397 defer logpkg .ReleaseGlobalSilence (id )
347398
348399 // make sure the global log is silent
400+ ctx = ctx .WithLogger (ctx .Log .WithPrefixColor ("term " , "yellow+b" ))
349401 err = terminal .StartTerminal (
350402 ctx ,
351403 devContainer ,
352- newTargetSelector (d . selectedPod .Pod .Name , d . selectedPod .Pod .Namespace , d . selectedPod .Container .Name , parent ),
404+ newTargetSelector (selectedPod .Pod .Name , selectedPod .Pod .Namespace , selectedPod .Container .Name , parent ),
353405 DefaultTerminalStdout ,
354406 DefaultTerminalStderr ,
355407 DefaultTerminalStdin ,
@@ -359,6 +411,11 @@ func (d *devPod) startTerminal(ctx *devspacecontext.Context, devContainer *lates
359411 return errors .Wrap (err , "error in terminal forwarding" )
360412 }
361413
414+ // if context is done we just return
415+ if ctx .IsDone () {
416+ return nil
417+ }
418+
362419 // kill ourselves here
363420 if ! opts .ContinueOnTerminalExit && opts .KillApplication != nil {
364421 go opts .KillApplication ()
@@ -383,10 +440,9 @@ func (d *devPod) startServices(ctx *devspacecontext.Context, devPod *latest.DevP
383440 return nil
384441 }
385442
443+ // add prefix
444+ ctx := ctx .WithLogger (ctx .Log .WithPrefixColor ("sync " , "yellow+b" ))
386445 err := sync .StartSync (ctx , devPod , selector , parent )
387- if err != nil {
388- fmt .Println (err )
389- }
390446 return err
391447 })
392448
@@ -396,16 +452,21 @@ func (d *devPod) startServices(ctx *devspacecontext.Context, devPod *latest.DevP
396452 return nil
397453 }
398454
455+ ctx := ctx .WithLogger (ctx .Log .WithPrefixColor ("ports " , "yellow+b" ))
399456 return portforwarding .StartPortForwarding (ctx , devPod , selector , parent )
400457 })
401458
402459 // Start SSH
403460 sshDone := parent .NotifyGo (func () error {
461+ // add ssh prefix
462+ ctx := ctx .WithLogger (ctx .Log .WithPrefixColor ("ssh " , "yellow+b" ))
404463 return ssh .StartSSH (ctx , devPod , selector , parent )
405464 })
406465
407466 // Start Reverse Commands
408467 reverseCommandsDone := parent .NotifyGo (func () error {
468+ // add proxy prefix
469+ ctx := ctx .WithLogger (ctx .Log .WithPrefixColor ("proxy " , "yellow+b" ))
409470 return proxycommands .StartProxyCommands (ctx , devPod , selector , parent )
410471 })
411472
0 commit comments