Skip to content

Commit 8f1ebb3

Browse files
committed
Add all image API commands
1 parent e392fd4 commit 8f1ebb3

3 files changed

Lines changed: 223 additions & 0 deletions

File tree

src/Client.php

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,120 @@ public function containerCopy($container, $config)
278278
return $this->postJson($this->url('/containers/%s/copy', $container), $config)->then(array($this->parser, 'expectPlain'));
279279
}
280280

281+
/**
282+
* List images
283+
*
284+
* @param boolean $all
285+
* @return Promise Promise<array> list of image objects
286+
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#list-images
287+
* @todo support $filters param
288+
*/
289+
public function imageList($all = false)
290+
{
291+
return $this->browser->get($this->url('/images/json?all=%u', $all))->then(array($this->parser, 'expectJson'));
292+
}
293+
294+
/**
295+
* Create an image, either by pulling it from the registry or by importing it
296+
*
297+
* @param string|null $fromImage name of the image to pull
298+
* @param string|null $fromSrc source to import, - means stdin
299+
* @param string|null $repo repository
300+
* @param string|null $tag (optional) (obsolete) tag, use $repo and $fromImage in the "name:tag" instead
301+
* @param string|null $registry the registry to pull from
302+
* @param array|null $registryAuth AuthConfig object (to send as X-Registry-Auth header)
303+
* @return Promise Promise<array> stream of message objects
304+
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#create-an-image
305+
*/
306+
public function imageCreate($fromImage = null, $fromSrc = null, $repo = null, $tag = null, $registry = null, $registryAuth = null)
307+
{
308+
return $this->browser->post(
309+
$this->url('/images/create?fromImage=%s&fromSrc=%s&repo=%s&tag=%s&registry=%s', $fromImage, $fromSrc, $repo, $tag, $registry),
310+
$this->authHeaders($registryAuth)
311+
)->then(array($this->parser, 'expectJson'));
312+
}
313+
314+
/**
315+
* Return low-level information on the image name
316+
*
317+
* @param string $image image ID
318+
* @return Promise Promise<array> image properties
319+
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#inspect-an-image
320+
*/
321+
public function imageInspect($image)
322+
{
323+
return $this->browser->get($this->url('/images/%s/json', $image))->then(array($this->parser, 'expectJson'));
324+
}
325+
326+
/**
327+
* Return the history of the image name
328+
*
329+
* @param string $image image ID
330+
* @return Promise Promise<array> list of image history objects
331+
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#get-the-history-of-an-image
332+
*/
333+
public function imageHistory($image)
334+
{
335+
return $this->browser->get($this->url('/images/%s/history', $image))->then(array($this->parser, 'expectJson'));
336+
}
337+
338+
/**
339+
* Push the image name on the registry
340+
*
341+
* @param string $image image ID
342+
* @param string|null $tag (optional) the tag to associate with the image on the registry
343+
* @param string|null $registry (optional) the registry to push to (e.g. `registry.acme.com:5000`)
344+
* @param array|null $registryAuth (optional) AuthConfig object (to send as X-Registry-Auth header)
345+
* @return Promise Promise<array> list of image push messages
346+
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#push-an-image-on-the-registry
347+
*/
348+
public function imagePush($image, $tag = null, $registry = null, $registryAuth = null)
349+
{
350+
$path = '/images' . ($registry === null ? '' : ('/' . $registry)) . '/%s/push?tag=%s';
351+
return $this->browser->post($this->url($path, $image, $tag), $this->authHeaders($registryAuth))->then(array($this->parser, 'expectJson'));
352+
}
353+
354+
/**
355+
* Tag the image name into a repository
356+
*
357+
* @param string $image image ID
358+
* @param string $repo The repository to tag in
359+
* @param string|null $tag The new tag name
360+
* @param boolean $force 1/True/true or 0/False/false, default false
361+
* @return Promise Promise<null>
362+
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#tag-an-image-into-a-repository
363+
*/
364+
public function imageTag($image, $repo, $tag = null, $force = false)
365+
{
366+
return $this->browser->post($this->url('/images/%s/tag?repo=%s&tag=%s&force=%u', $image, $repo, $tag, $force))->then(array($this->parser, 'expectEmpty'));
367+
}
368+
369+
/**
370+
* Remove the image name from the filesystem
371+
*
372+
* @param string $image image ID
373+
* @param boolean $force 1/True/true or 0/False/false, default false
374+
* @param boolean $noprune 1/True/true or 0/False/false, default false
375+
* @return Promise Promise<null>
376+
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#remove-an-image
377+
*/
378+
public function imageRemove($image, $force = false, $noprune = false)
379+
{
380+
return $this->browser->delete($this->url('/images/%s?force=%u&noprune=%u', $image, $force, $noprune))->then(array($this->parser, 'expectEmpty'));
381+
}
382+
383+
/**
384+
* Search for an image on Docker Hub.
385+
*
386+
* @param string $term term to search
387+
* @return Promise Promise<array> list of image search result objects
388+
* @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#search-images
389+
*/
390+
public function imageSearch($term)
391+
{
392+
return $this->browser->get($this->url('/images/search?term=%s', $term))->then(array($this->parser, 'expectJson'));
393+
}
394+
281395
/**
282396
* Sets up an exec instance in a running container id
283397
*
@@ -346,4 +460,14 @@ private function json($data)
346460
}
347461
return json_encode($data);
348462
}
463+
464+
private function authHeaders($registryAuth)
465+
{
466+
$headers = array();
467+
if ($registryAuth !== null) {
468+
$headers['X-Registry-Auth'] = base64_encode($this->json($registryAuth));
469+
}
470+
471+
return $headers;
472+
}
349473
}

tests/ClientTest.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ public function testContainerInspect()
5252
$this->expectPromiseResolveWith($json, $this->client->containerInspect(123));
5353
}
5454

55+
public function testContainerTop()
56+
{
57+
$json = array();
58+
$this->expectRequestFlow('get', '/containers/123/top?ps_args=', $this->createResponseJson($json), 'expectJson');
59+
60+
$this->expectPromiseResolveWith($json, $this->client->containerTop(123));
61+
}
62+
5563
public function testContainerTopArgs()
5664
{
5765
$json = array();
@@ -164,6 +172,78 @@ public function testContainerCopy()
164172
$this->expectPromiseResolveWith($data, $this->client->containerCopy('123', $config));
165173
}
166174

175+
public function testImageList()
176+
{
177+
$json = array();
178+
$this->expectRequestFlow('get', '/images/json?all=0', $this->createResponseJson($json), 'expectJson');
179+
180+
$this->expectPromiseResolveWith($json, $this->client->imageList());
181+
}
182+
183+
public function testImageCreate()
184+
{
185+
$json = array();
186+
$this->expectRequestFlow('post', '/images/create?fromImage=busybox&fromSrc=&repo=&tag=&registry=', $this->createResponseJson($json), 'expectJson');
187+
188+
$this->expectPromiseResolveWith($json, $this->client->imageCreate('busybox'));
189+
}
190+
191+
public function testImageInspect()
192+
{
193+
$json = array();
194+
$this->expectRequestFlow('get', '/images/123/json', $this->createResponseJson($json), 'expectJson');
195+
196+
$this->expectPromiseResolveWith($json, $this->client->imageInspect('123'));
197+
}
198+
199+
public function testImageHistory()
200+
{
201+
$json = array();
202+
$this->expectRequestFlow('get', '/images/123/history', $this->createResponseJson($json), 'expectJson');
203+
204+
$this->expectPromiseResolveWith($json, $this->client->imageHistory('123'));
205+
}
206+
207+
public function testImagePush()
208+
{
209+
$json = array();
210+
$this->expectRequestFlow('post', '/images/123/push?tag=', $this->createResponseJson($json), 'expectJson');
211+
212+
$this->expectPromiseResolveWith($json, $this->client->imagePush('123'));
213+
}
214+
215+
public function testImagePushCustomRegistry()
216+
{
217+
// TODO: verify headers
218+
$auth = array();
219+
$json = array();
220+
$this->expectRequestFlow('post', '/images/demo.acme.com:5000/123/push?tag=test', $this->createResponseJson($json), 'expectJson');
221+
222+
$this->expectPromiseResolveWith($json, $this->client->imagePush('123', 'test', 'demo.acme.com:5000', $auth));
223+
}
224+
225+
public function testImageTag()
226+
{
227+
$this->expectRequestFlow('post', '/images/123/tag?repo=test&tag=&force=0', $this->createResponse(), 'expectEmpty');
228+
229+
$this->expectPromiseResolveWith('', $this->client->imageTag('123', 'test'));
230+
}
231+
232+
public function testImageRemove()
233+
{
234+
$this->expectRequestFlow('delete', '/images/123?force=0&noprune=0', $this->createResponse(), 'expectEmpty');
235+
236+
$this->expectPromiseResolveWith('', $this->client->imageRemove('123', 'test'));
237+
}
238+
239+
public function testImageSearch()
240+
{
241+
$json = array();
242+
$this->expectRequestFlow('get', '/images/search?term=clue', $this->createResponseJson($json), 'expectJson');
243+
244+
$this->expectPromiseResolveWith($json, $this->client->imageSearch('clue'));
245+
}
246+
167247
public function testExecCreate()
168248
{
169249
$json = array();

tests/FunctionalClientTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,25 @@ public function testContainerRemoveInvalid()
6565
$this->waitFor($promise, $this->loop);
6666
}
6767

68+
public function testImageSearch()
69+
{
70+
$promise = $this->client->imageSearch('clue');
71+
$ret = $this->waitFor($promise, $this->loop);
72+
73+
$this->assertGreaterThan(10, count($ret));
74+
}
75+
76+
public function testImageTag()
77+
{
78+
// create new tag "bb:now" on "busybox:latest"
79+
$promise = $this->client->imageTag('busybox', 'bb', 'now');
80+
$ret = $this->waitFor($promise, $this->loop);
81+
82+
// delete tag "bb:now" again
83+
$promise = $this->client->imageRemove('bb:now');
84+
$ret = $this->waitFor($promise, $this->loop);
85+
}
86+
6887
public function testInfo()
6988
{
7089
$this->expectPromiseResolve($this->client->info());

0 commit comments

Comments
 (0)