@@ -672,6 +672,106 @@ public function containerUnpause($container)
672672 )->then (array ($ this ->parser , 'expectEmpty ' ));
673673 }
674674
675+ /**
676+ * Attach to a container to read its output.
677+ *
678+ * This resolves with a string containing the container output, i.e. STDOUT
679+ * and STDERR as requested.
680+ *
681+ * Keep in mind that this means the whole string has to be kept in memory.
682+ * For a larger container output it's usually a better idea to use a streaming
683+ * approach, see `containerAttachStream()` for more details.
684+ * In particular, the same also applies for the `$stream` flag. It can be used
685+ * to follow the container output as long as the container is running.
686+ *
687+ * Note that this endpoint internally has to check the `containerInspect()`
688+ * endpoint first in order to figure out the TTY settings to properly decode
689+ * the raw container output.
690+ *
691+ * @param string $container container ID
692+ * @param bool $logs replay previous logs before attaching. Default false
693+ * @param bool $stream continue streaming. Default false
694+ * @param bool $stdout attach to stdout. Default true
695+ * @param bool $stderr attach to stderr. Default true
696+ * @return PromiseInterface Promise<string> container output string
697+ * @link https://docs.docker.com/engine/api/v1.40/#operation/ContainerAttach
698+ * @uses self::containerAttachStream()
699+ * @see self::containerAttachStream()
700+ */
701+ public function containerAttach ($ container , $ logs = false , $ stream = false , $ stdout = true , $ stderr = true )
702+ {
703+ return $ this ->streamingParser ->bufferedStream (
704+ $ this ->containerAttachStream ($ container , $ logs , $ stream , $ stdout , $ stderr )
705+ );
706+ }
707+
708+ /**
709+ * Attach to a container to read its output.
710+ *
711+ * This is a streaming API endpoint that returns a readable stream instance
712+ * containing the container output, i.e. STDOUT and STDERR as requested.
713+ *
714+ * This works for container output of arbitrary sizes as only small chunks have to
715+ * be kept in memory.
716+ *
717+ * This is particularly useful for the `$stream` flag. It can be used to
718+ * follow the container output as long as the container is running. Either
719+ * the `$stream` or `$logs` parameter must be `true` for this endpoint to do
720+ * anything meaningful.
721+ *
722+ * Note that by default the output of both STDOUT and STDERR will be emitted
723+ * as normal "data" events. You can optionally pass a custom event name which
724+ * will be used to emit STDERR data so that it can be handled separately.
725+ * Note that the normal streaming primitives likely do not know about this
726+ * event, so special care may have to be taken.
727+ * Also note that this option has no effect if the container has been
728+ * created with a TTY.
729+ *
730+ * Note that this endpoint internally has to check the `containerInspect()`
731+ * endpoint first in order to figure out the TTY settings to properly decode
732+ * the raw container output.
733+ *
734+ * Note that this endpoint intentionally does not expose the `$stdin` flag.
735+ * Access to STDIN will be exposed as a dedicated API endpoint in a future
736+ * version.
737+ *
738+ * @param string $container container ID
739+ * @param bool $logs replay previous logs before attaching. Default false
740+ * @param bool $stream continue streaming. Default false
741+ * @param bool $stdout attach to stdout. Default true
742+ * @param bool $stderr attach to stderr. Default true
743+ * @param string $stderrEvent custom event to emit for STDERR data (otherwise emits as "data")
744+ * @return ReadableStreamInterface container output stream
745+ * @link https://docs.docker.com/engine/api/v1.40/#operation/ContainerAttach
746+ * @see self::containerAttach()
747+ */
748+ public function containerAttachStream ($ container , $ logs = false , $ stream = false , $ stdout = true , $ stderr = true , $ stderrEvent = null )
749+ {
750+ $ parser = $ this ->streamingParser ;
751+ $ browser = $ this ->browser ;
752+ $ url = $ this ->uri ->expand (
753+ '/containers/{container}/attach{?logs,stream,stdout,stderr} ' ,
754+ array (
755+ 'container ' => $ container ,
756+ 'logs ' => $ this ->boolArg ($ logs ),
757+ 'stream ' => $ this ->boolArg ($ stream ),
758+ 'stdout ' => $ this ->boolArg ($ stdout ),
759+ 'stderr ' => $ this ->boolArg ($ stderr )
760+ )
761+ );
762+
763+ // first inspect container to check TTY setting, then attach with appropriate log parser
764+ return \React \Promise \Stream \unwrapReadable ($ this ->containerInspect ($ container )->then (function ($ info ) use ($ url , $ browser , $ parser , $ stderrEvent ) {
765+ $ stream = $ parser ->parsePlainStream ($ browser ->withOptions (array ('streaming ' => true ))->post ($ url ));
766+
767+ if (!$ info ['Config ' ]['Tty ' ]) {
768+ $ stream = $ parser ->demultiplexStream ($ stream , $ stderrEvent );
769+ }
770+
771+ return $ stream ;
772+ }));
773+ }
774+
675775 /**
676776 * Block until container id stops, then returns the exit code
677777 *
0 commit comments