Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add events() and eventsStream() API endpoints #32

Merged
merged 1 commit into from
Apr 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ The following API endpoints take advantage of [JSON streaming](https://en.wikipe
```php
$client->imageCreate();
$client->imagePush();
$client->events();
```

What this means is that these endpoints actually emit any number of progress
Expand Down Expand Up @@ -271,6 +272,7 @@ a [`Stream`](https://github.com/reactphp/stream) instance instead:
```php
$stream = $client->imageCreateStream();
$stream = $client->imagePushStream();
$stream = $client->eventsStream();
```

The resulting stream will emit the following events:
Expand Down
31 changes: 31 additions & 0 deletions examples/events.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
// this simple example displays all docker events that happen in the next 10s.
// try starting / removing a container in the meantime to see some output.

require __DIR__ . '/../vendor/autoload.php';

use React\EventLoop\Factory as LoopFactory;
use Clue\React\Docker\Factory;

$loop = LoopFactory::create();

$factory = new Factory($loop);
$client = $factory->createClient();

// get a list of all events that happened up until this point
// expect this list to be limited to the last 64 (or so) events
// $events = $client->events(0, microtime(true));

// get a list of all events that happened in the last 10 seconds
// $events = $client->events(microtime(true) - 10, microtime(true));

// stream all events for 10 seconds
$stream = $client->eventsStream(null, microtime(true) + 10.0);

$stream->on('progress', function ($event) {
echo json_encode($event) . PHP_EOL;
});

$stream->on('error', 'printf');

$loop->run();
83 changes: 83 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,89 @@ public function version()
return $this->browser->get('/version')->then(array($this->parser, 'expectJson'));
}

/**
* Get container events from docker
*
* This is a JSON streaming API endpoint that resolves with an array of all
* individual progress events.
*
* If you need to access the individual progress events as they happen, you
* should consider using `eventsStream()` instead.
*
* Note that this method will buffer all events until the stream closes.
* This means that you SHOULD pass a timestamp for `$until` so that this
* method only polls the given time interval and then resolves.
*
* The optional `$filters` parameter can be used to only get events for
* certain event types, images and/or containers etc. like this:
* <code>
* $filters = array(
* 'image' => array('ubuntu', 'busybox'),
* 'event' => array('create')
* );
* </code>
*
* @param float|null $since timestamp used for polling
* @param float|null $until timestamp used for polling
* @param array $filters (optional) filters to apply (requires API v1.16+ / Docker v1.4+)
* @return PromiseInterface Promise<array> array of event objects
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#monitor-dockers-events
* @uses self::eventsStream()
* @see self::eventsStream()
*/
public function events($since = null, $until = null, $filters = array())
{
return $this->streamingParser->deferredStream(
$this->eventsStream($since, $until, $filters),
'progress'
);
}

/**
* Get container events from docker
*
* This is a JSON streaming API endpoint that returns a stream instance.
*
* The resulting stream will emit the following events:
* - progress: for *each* element in the update stream
* - error: once if an error occurs, will close() stream then
* - close: once the stream ends (either finished or after "error")
*
* Please note that the resulting stream does not emit any "data" events, so
* you will not be able to pipe() its events into another `WritableStream`.
*
* The optional `$filters` parameter can be used to only get events for
* certain event types, images and/or containers etc. like this:
* <code>
* $filters = array(
* 'image' => array('ubuntu', 'busybox'),
* 'event' => array('create')
* );
* </code>
*
* @param float|null $since timestamp used for polling
* @param float|null $until timestamp used for polling
* @param array $filters (optional) filters to apply (requires API v1.16+ / Docker v1.4+)
* @return ReadableStreamInterface stream of event objects
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#monitor-dockers-events
* @see self::events()
*/
public function eventsStream($since = null, $until = null, $filters = array())
{
return $this->streamingParser->parseJsonStream(
$this->browser->withOptions(array('streaming' => true))->get(
$this->uri->expand(
'/events{?since,until,filters}',
array(
'since' => $since,
'until' => $until,
'filters' => $filters ? json_encode($filters) : null
)
)
)
);
}

/**
* List containers
*
Expand Down
24 changes: 24 additions & 0 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,30 @@ public function testPing()
$this->expectPromiseResolveWith($body, $this->client->ping());
}

public function testEvents()
{
$json = array();
$stream = $this->getMock('React\Stream\ReadableStreamInterface');

$this->expectRequest('GET', '/events', $this->createResponseJsonStream($json));
$this->streamingParser->expects($this->once())->method('parseJsonStream')->will($this->returnValue($stream));
$this->streamingParser->expects($this->once())->method('deferredStream')->with($this->equalTo($stream), $this->equalTo('progress'))->will($this->returnPromise($json));

$this->expectPromiseResolveWith($json, $this->client->events());
}

public function testEventsArgs()
{
$json = array();
$stream = $this->getMock('React\Stream\ReadableStreamInterface');

$this->expectRequest('GET', '/events?since=10&until=20&filters=%7B%22image%22%3A%5B%22busybox%22%2C%22ubuntu%22%5D%7D', $this->createResponseJsonStream($json));
$this->streamingParser->expects($this->once())->method('parseJsonStream')->will($this->returnValue($stream));
$this->streamingParser->expects($this->once())->method('deferredStream')->with($this->equalTo($stream), $this->equalTo('progress'))->will($this->returnPromise($json));

$this->expectPromiseResolveWith($json, $this->client->events(10, 20, array('image' => array('busybox', 'ubuntu'))));
}

public function testContainerCreate()
{
$json = array();
Expand Down
15 changes: 15 additions & 0 deletions tests/FunctionalClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public function testCreateStartAndRemoveContainer()
$this->assertNotNull($container['Id']);
$this->assertNull($container['Warnings']);

$start = microtime(true);

$promise = $this->client->containerStart($container['Id']);
$ret = Block\await($promise, $this->loop);

Expand All @@ -55,6 +57,19 @@ public function testCreateStartAndRemoveContainer()
$ret = Block\await($promise, $this->loop);

$this->assertEquals('', $ret);

$end = microtime(true);

// get all events between starting and removing for this container
$promise = $this->client->events($start, $end, array('container' => array($container['Id'])));
$ret = Block\await($promise, $this->loop);

// expects "start", "kill", "die", "destroy" events
$this->assertEquals(4, count($ret));
$this->assertEquals('start', $ret[0]['status']);
$this->assertEquals('kill', $ret[1]['status']);
$this->assertEquals('die', $ret[2]['status']);
$this->assertEquals('destroy', $ret[3]['status']);
}

/**
Expand Down