@@ -2,13 +2,12 @@ package devpod
22
33import (
44 "context"
5+ "fmt"
56 "github.com/loft-sh/devspace/pkg/devspace/config/loader"
67 "github.com/loft-sh/devspace/pkg/devspace/kubectl/selector"
78 "github.com/loft-sh/devspace/pkg/devspace/services/logs"
89 "github.com/loft-sh/devspace/pkg/devspace/services/terminal"
9- "github.com/loft-sh/devspace/pkg/util/log"
1010 "github.com/loft-sh/devspace/pkg/util/tomb"
11- "github.com/sirupsen/logrus"
1211 "github.com/skratchdot/open-golang/open"
1312 "net/http"
1413 "os"
@@ -28,6 +27,9 @@ import (
2827
2928var (
3029 openMaxWait = 5 * time .Minute
30+
31+ terminalDevPodMutex syncpkg.Mutex
32+ terminalDevPod * devPod
3133)
3234
3335type devPod struct {
@@ -122,46 +124,29 @@ func (d *devPod) startWithRetry(ctx *devspacecontext.Context, devPodConfig *late
122124 // Create a new tomb and run it
123125 tombCtx := t .Context (ctx .Context )
124126 ctx = ctx .WithContext (tombCtx )
125- var (
126- hasTerminal bool
127- err error
128- )
129127 <- t .NotifyGo (func () error {
130- hasTerminal , err = d .start (ctx , devPodConfig , options , t )
131- return err
128+ return d .start (ctx , devPodConfig , options , t )
132129 })
133- if hasTerminal {
134- err = t .Wait ()
135- if err != nil {
136- // if we just lost connection we wait here until stopped
137- if _ , ok := t .Err ().(DevPodLostConnection ); ok {
138- <- d .done
139- return nil
140- }
141-
142- return err
143- }
144- return nil
145- } else if ! t .Alive () {
130+ if ! t .Alive () {
146131 return t .Err ()
147132 }
148133
149134 return nil
150135}
151136
152- func (d * devPod ) start (ctx * devspacecontext.Context , devPodConfig * latest.DevPod , opts Options , parent * tomb.Tomb ) ( hasTerminal bool , err error ) {
137+ func (d * devPod ) start (ctx * devspacecontext.Context , devPodConfig * latest.DevPod , opts Options , parent * tomb.Tomb ) error {
153138 // check first if we need to replace the pod
154139 if ! opts .DisablePodReplace && needPodReplace (devPodConfig ) {
155140 err := podreplace .NewPodReplacer ().ReplacePod (ctx , devPodConfig )
156141 if err != nil {
157- return false , errors .Wrap (err , "replace pod" )
142+ return errors .Wrap (err , "replace pod" )
158143 }
159144 } else {
160145 devPodCache , ok := ctx .Config .RemoteCache ().GetDevPod (devPodConfig .Name )
161- if ok && devPodCache .ReplicaSet != "" {
146+ if ok && devPodCache .Deployment != "" {
162147 _ , err := podreplace .NewPodReplacer ().RevertReplacePod (ctx , & devPodCache )
163148 if err != nil {
164- return false , errors .Wrap (err , "replace pod" )
149+ return errors .Wrap (err , "replace pod" )
165150 }
166151 }
167152 }
@@ -170,7 +155,7 @@ func (d *devPod) start(ctx *devspacecontext.Context, devPodConfig *latest.DevPod
170155 if devPodConfig .ImageSelector != "" {
171156 imageSelectorObject , err := runtimevar .NewRuntimeResolver (ctx .WorkingDir , true ).FillRuntimeVariablesAsImageSelector (ctx .Context , devPodConfig .ImageSelector , ctx .Config , ctx .Dependencies )
172157 if err != nil {
173- return false , err
158+ return err
174159 }
175160
176161 imageSelector = []string {imageSelectorObject .Image }
@@ -179,12 +164,13 @@ func (d *devPod) start(ctx *devspacecontext.Context, devPodConfig *latest.DevPod
179164 // wait for pod to be ready
180165 ctx .Log .Infof ("Waiting for pod to become ready..." )
181166 options := targetselector .NewEmptyOptions ().
182- ApplyConfigParameter ("" , devPodConfig .LabelSelector , imageSelector , devPodConfig .Namespace , "" ).
167+ ApplyConfigParameter ("" , devPodConfig .LabelSelector , imageSelector , devPodConfig .Namespace , devPodConfig . Pod ).
183168 WithWaitingStrategy (targetselector .NewUntilNewestRunningWaitingStrategy (time .Millisecond * 500 )).
184169 WithSkipInitContainers (true )
170+ var err error
185171 d .selectedPod , err = targetselector .NewTargetSelector (options ).SelectSingleContainer (ctx .Context , ctx .KubeClient , ctx .Log )
186172 if err != nil {
187- return false , errors .Wrap (err , "waiting for pod to become ready" )
173+ return errors .Wrap (err , "waiting for pod to become ready" )
188174 }
189175 ctx .Log .Debugf ("Selected pod:container %s:%s" , d .selectedPod .Pod .Name , d .selectedPod .Container .Name )
190176
@@ -217,17 +203,17 @@ func (d *devPod) start(ctx *devspacecontext.Context, devPodConfig *latest.DevPod
217203 // start sync and port forwarding
218204 err = d .startSyncAndPortForwarding (ctx , devPodConfig , newTargetSelector (d .selectedPod .Pod .Name , d .selectedPod .Pod .Namespace , d .selectedPod .Container .Name , parent ), opts , parent )
219205 if err != nil {
220- return false , err
206+ return err
221207 }
222208
223209 // start logs or terminal
224210 terminalDevContainer := d .getTerminalDevContainer (devPodConfig )
225211 if terminalDevContainer != nil {
226- return true , d .startTerminal (ctx , terminalDevContainer , parent )
212+ return d .startTerminal (ctx , terminalDevContainer , opts , parent )
227213 }
228214
229215 // TODO attach
230- return false , d .startLogs (ctx , devPodConfig , parent )
216+ return d .startLogs (ctx , devPodConfig , parent )
231217}
232218
233219func (d * devPod ) startLogs (ctx * devspacecontext.Context , devPodConfig * latest.DevPod , parent * tomb.Tomb ) error {
@@ -262,19 +248,28 @@ func (d *devPod) getTerminalDevContainer(devPodConfig *latest.DevPod) *latest.De
262248 return devContainer
263249}
264250
265- func (d * devPod ) startTerminal (ctx * devspacecontext.Context , devContainer * latest.DevContainer , parent * tomb.Tomb ) error {
251+ func (d * devPod ) startTerminal (ctx * devspacecontext.Context , devContainer * latest.DevContainer , opts Options , parent * tomb.Tomb ) error {
266252 parent .Go (func () error {
253+ err := setTerminalDevPod (d )
254+ if err != nil {
255+ return err
256+ }
257+
267258 // make sure the global log is silent
268- before := log . GetBaseInstance (). GetLevel ( )
269- log . GetBaseInstance (). SetLevel ( logrus . PanicLevel )
270- err := terminal . StartTerminal ( ctx , devContainer , newTargetSelector ( d . selectedPod . Pod . Name , d . selectedPod . Pod . Namespace , d . selectedPod . Container . Name , parent ), os . Stdout , os . Stderr , os . Stdin , parent )
271- log . GetBaseInstance (). SetLevel ( before )
259+ err = terminal . StartTerminal ( ctx , devContainer , newTargetSelector ( d . selectedPod . Pod . Name , d . selectedPod . Pod . Namespace , d . selectedPod . Container . Name , parent ), os . Stdout , os . Stderr , os . Stdin , parent )
260+ terminalDevPodMutex . Lock ( )
261+ terminalDevPod = nil
262+ terminalDevPodMutex . Unlock ( )
272263 if err != nil {
273264 return errors .Wrap (err , "error in terminal forwarding" )
274265 }
275266
276267 // kill ourselves here
277- parent .Kill (nil )
268+ if ! opts .ContinueOnTerminalExit && opts .KillApplication != nil {
269+ go opts .KillApplication ()
270+ } else {
271+ parent .Kill (nil )
272+ }
278273 return nil
279274 })
280275
@@ -345,6 +340,34 @@ func needPodReplaceContainer(devContainer *latest.DevContainer) bool {
345340 if devContainer .Terminal != nil && ! devContainer .Terminal .Disabled && ! devContainer .Terminal .DisableReplace {
346341 return true
347342 }
343+ if len (devContainer .Env ) > 0 {
344+ return true
345+ }
346+ if len (devContainer .Command ) > 0 {
347+ return true
348+ }
349+ if devContainer .Args != nil {
350+ return true
351+ }
352+ if ! devContainer .DisableRestartHelper {
353+ for _ , s := range devContainer .Sync {
354+ if s .OnUpload != nil && s .OnUpload .RestartContainer {
355+ return true
356+ }
357+ }
358+ }
348359
349360 return false
350361}
362+
363+ func setTerminalDevPod (devPod * devPod ) error {
364+ terminalDevPodMutex .Lock ()
365+ defer terminalDevPodMutex .Unlock ()
366+
367+ if terminalDevPod != nil {
368+ return fmt .Errorf ("error starting terminal as it is currently already used by another dev pod" )
369+ }
370+
371+ terminalDevPod = devPod
372+ return nil
373+ }
0 commit comments