@@ -15,7 +15,6 @@ import (
15
15
"github.com/containers/common/pkg/resize"
16
16
"github.com/containers/podman/v5/libpod/define"
17
17
"github.com/containers/podman/v5/libpod/events"
18
- "github.com/containers/podman/v5/pkg/signal"
19
18
"github.com/containers/storage/pkg/archive"
20
19
spec "github.com/opencontainers/runtime-spec/specs-go"
21
20
"github.com/sirupsen/logrus"
@@ -142,13 +141,12 @@ func (c *Container) Update(resources *spec.LinuxResources, restartPolicy *string
142
141
return c .update (resources , restartPolicy , restartRetries )
143
142
}
144
143
145
- // StartAndAttach starts a container and attaches to it.
146
- // This acts as a combination of the Start and Attach APIs, ensuring proper
144
+ // Attach to a container.
145
+ // The last parameter "start" can be used to also start the container.
146
+ // This will then Start and Attach APIs, ensuring proper
147
147
// ordering of the two such that no output from the container is lost (e.g. the
148
148
// Attach call occurs before Start).
149
- // In overall functionality, it is identical to the Start call, with the added
150
- // side effect that an attach session will also be started.
151
- func (c * Container ) StartAndAttach (ctx context.Context , streams * define.AttachStreams , keys string , resize <- chan resize.TerminalSize , recursive bool ) (retChan <- chan error , finalErr error ) {
149
+ func (c * Container ) Attach (ctx context.Context , streams * define.AttachStreams , keys string , resize <- chan resize.TerminalSize , start bool ) (retChan <- chan error , finalErr error ) {
152
150
defer func () {
153
151
if finalErr != nil {
154
152
// Have to re-lock.
@@ -175,9 +173,27 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *define.AttachSt
175
173
}
176
174
}
177
175
178
- if err := c .prepareToStart (ctx , recursive ); err != nil {
179
- return nil , err
176
+ if c .state .State != define .ContainerStateRunning {
177
+ if ! start {
178
+ return nil , errors .New ("you can only attach to running containers" )
179
+ }
180
+
181
+ if err := c .prepareToStart (ctx , true ); err != nil {
182
+ return nil , err
183
+ }
184
+ }
185
+
186
+ if ! start {
187
+ // A bit awkward, technically passthrough never supports attach. We only pretend
188
+ // it does as we leak the stdio fds down into the container but that of course only
189
+ // works if we are the process that started conmon with the right fds.
190
+ if c .LogDriver () == define .PassthroughLogging {
191
+ return nil , fmt .Errorf ("this container is using the 'passthrough' log driver, cannot attach: %w" , define .ErrNoLogs )
192
+ } else if c .LogDriver () == define .PassthroughTTYLogging {
193
+ return nil , fmt .Errorf ("this container is using the 'passthrough-tty' log driver, cannot attach: %w" , define .ErrNoLogs )
194
+ }
180
195
}
196
+
181
197
attachChan := make (chan error )
182
198
183
199
// We need to ensure that we don't return until start() fired in attach.
@@ -194,7 +210,7 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *define.AttachSt
194
210
opts := new (AttachOptions )
195
211
opts .Streams = streams
196
212
opts .DetachKeys = & keys
197
- opts .Start = true
213
+ opts .Start = start
198
214
opts .Started = startedChan
199
215
200
216
// attach and start the container on a different thread. waitForHealthy must
@@ -213,7 +229,13 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *define.AttachSt
213
229
c .newContainerEvent (events .Attach )
214
230
}
215
231
216
- return attachChan , c .waitForHealthy (ctx )
232
+ if start {
233
+ if err := c .waitForHealthy (ctx ); err != nil {
234
+ return nil , err
235
+ }
236
+ }
237
+
238
+ return attachChan , nil
217
239
}
218
240
219
241
// RestartWithTimeout restarts a running container and takes a given timeout in uint
@@ -315,61 +337,6 @@ func (c *Container) Kill(signal uint) error {
315
337
return c .save ()
316
338
}
317
339
318
- // Attach attaches to a container.
319
- // This function returns when the attach finishes. It does not hold the lock for
320
- // the duration of its runtime, only using it at the beginning to verify state.
321
- func (c * Container ) Attach (streams * define.AttachStreams , keys string , resize <- chan resize.TerminalSize ) error {
322
- if c .LogDriver () == define .PassthroughLogging {
323
- return fmt .Errorf ("this container is using the 'passthrough' log driver, cannot attach: %w" , define .ErrNoLogs )
324
- }
325
- if c .LogDriver () == define .PassthroughTTYLogging {
326
- return fmt .Errorf ("this container is using the 'passthrough-tty' log driver, cannot attach: %w" , define .ErrNoLogs )
327
- }
328
- if ! c .batched {
329
- c .lock .Lock ()
330
- if err := c .syncContainer (); err != nil {
331
- c .lock .Unlock ()
332
- return err
333
- }
334
- // We are NOT holding the lock for the duration of the function.
335
- c .lock .Unlock ()
336
- }
337
-
338
- if ! c .ensureState (define .ContainerStateCreated , define .ContainerStateRunning ) {
339
- return fmt .Errorf ("can only attach to created or running containers: %w" , define .ErrCtrStateInvalid )
340
- }
341
-
342
- // HACK: This is really gross, but there isn't a better way without
343
- // splitting attach into separate versions for StartAndAttach and normal
344
- // attaching, and I really do not want to do that right now.
345
- // Send a SIGWINCH after attach succeeds so that most programs will
346
- // redraw the screen for the new attach session.
347
- attachRdy := make (chan bool , 1 )
348
- if c .Terminal () {
349
- go func () {
350
- <- attachRdy
351
- c .lock .Lock ()
352
- defer c .lock .Unlock ()
353
- if err := c .ociRuntime .KillContainer (c , uint (signal .SIGWINCH ), false ); err != nil {
354
- logrus .Warnf ("Unable to send SIGWINCH to container %s after attach: %v" , c .ID (), err )
355
- }
356
- }()
357
- }
358
-
359
- // Start resizing
360
- if c .LogDriver () != define .PassthroughLogging && c .LogDriver () != define .PassthroughTTYLogging {
361
- registerResizeFunc (resize , c .bundlePath ())
362
- }
363
-
364
- opts := new (AttachOptions )
365
- opts .Streams = streams
366
- opts .DetachKeys = & keys
367
- opts .AttachReady = attachRdy
368
-
369
- c .newContainerEvent (events .Attach )
370
- return c .ociRuntime .Attach (c , opts )
371
- }
372
-
373
340
// HTTPAttach forwards an attach session over a hijacked HTTP session.
374
341
// HTTPAttach will consume and close the included httpCon, which is expected to
375
342
// be sourced from a hijacked HTTP connection.
0 commit comments