diff --git a/README.md b/README.md index fc3d829..39416c1 100644 --- a/README.md +++ b/README.md @@ -321,6 +321,7 @@ a [`Stream`](https://github.com/reactphp/stream) instance instead: $stream = $client->imageCreateStream(); $stream = $client->imagePushStream(); $stream = $client->eventsStream(); +$stream = $client->containerStatsStream($container); ``` The resulting stream will emit the following events: diff --git a/examples/stats.php b/examples/stats.php new file mode 100644 index 0000000..505b42c --- /dev/null +++ b/examples/stats.php @@ -0,0 +1,35 @@ +containerStatsStream($container); + +$stream->on('data', function ($progress) { + //echo 'progress: '. json_encode($progress, JSON_PRETTY_PRINT) . PHP_EOL; + + $memory = $progress['memory_stats']['usage'] / $progress['memory_stats']['limit'] * 100; + $sent = $received = 0; + foreach ($progress['networks'] as $stats) { + $sent += $stats['tx_bytes']; + $received += $stats['rx_bytes']; + } + + echo round($memory, 3) . '% memory and ' . $received . '/' . $sent . ' bytes network I/O' . PHP_EOL; +}); +$stream->on('error', 'printf'); +$stream->on('close', function () { + echo 'stream closed' . PHP_EOL; +}); + +$loop->run(); diff --git a/src/Client.php b/src/Client.php index 1f90574..35d1b8f 100644 --- a/src/Client.php +++ b/src/Client.php @@ -344,6 +344,61 @@ public function containerExportStream($container) ); } + /** + * Returns a container’s resource usage statistics. + * + * This is a JSON API endpoint that resolves with a single stats info. + * + * If you want to monitor live stats events as they happen, you + * should consider using `imageStatsStream()` instead. + * + * @param string $container container ID + * @return PromiseInterface Promise JSON stats + * @link https://docs.docker.com/engine/api/v1.40/#operation/ContainerStats + * @since 0.3.0 Available as of Docker Engine API v1.19 (Docker v1.7), use `containerStatsStream()` on legacy versions + * @see self::containerStatsStream() + */ + public function containerStats($container) + { + return $this->browser->get( + $this->uri->expand( + '/containers/{container}/stats{?stream}', + array( + 'container' => $container, + 'stream' => 0 + ) + ) + )->then(array($this->parser, 'expectJson')); + } + + /** + * Returns a live stream of a container’s resource usage statistics. + * + * The resulting stream will emit the following events: + * - data: for *each* element in the stats stream + * - error: once if an error occurs, will close() stream then + * - close: once the stream ends (either finished or after "error") + * + * @param string $container container ID + * @return ReadableStreamInterface JSON stats stream + * @link https://docs.docker.com/engine/api/v1.40/#operation/ContainerStats + * @since 0.3.0 Available as of Docker Engine API v1.17 (Docker v1.5) + * @see self::containerStats() + */ + public function containerStatsStream($container) + { + return $this->streamingParser->parseJsonStream( + $this->browser->withOptions(array('streaming' => true))->get( + $this->uri->expand( + '/containers/{container}/stats', + array( + 'container' => $container + ) + ) + ) + ); + } + /** * Resize the TTY of container id * diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 79251ff..a1863d7 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -287,6 +287,23 @@ public function testContainerRemoveVolumeForce() $this->expectPromiseResolveWith('', $this->client->containerRemove(123, true, true)); } + public function testContainerStats() + { + $this->expectRequestFlow('GET', '/containers/123/stats?stream=0', $this->createResponse(), 'expectJson'); + + $this->expectPromiseResolveWith('', $this->client->containerStats(123)); + } + + public function testContainerStatsStream() + { + $stream = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock(); + + $this->expectRequest('GET', '/containers/123/stats', $this->createResponse('')); + $this->streamingParser->expects($this->once())->method('parseJsonStream')->will($this->returnValue($stream)); + + $this->assertSame($stream, $this->client->containerStatsStream('123')); + } + public function testContainerResize() { $this->expectRequestFlow('POST', '/containers/123/resize?w=800&h=600', $this->createResponse(), 'expectEmpty');