Add batch_get_image support for ECR (#1406)
* Add batch_get_image for ECR * Add tests for batch_get_image * Add tests for batch_get_image * Undo local commits * Undo local commits * Adding object representation for batch_get_image * Update responses. Add a couple more tests.
This commit is contained in:
parent
84f2ec5e04
commit
b855fee2e4
@ -1,14 +1,14 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
# from datetime import datetime
|
|
||||||
|
import hashlib
|
||||||
|
from copy import copy
|
||||||
from random import random
|
from random import random
|
||||||
|
|
||||||
from moto.core import BaseBackend, BaseModel
|
from moto.core import BaseBackend, BaseModel
|
||||||
from moto.ec2 import ec2_backends
|
from moto.ec2 import ec2_backends
|
||||||
from copy import copy
|
|
||||||
import hashlib
|
|
||||||
|
|
||||||
from moto.ecr.exceptions import ImageNotFoundException, RepositoryNotFoundException
|
from moto.ecr.exceptions import ImageNotFoundException, RepositoryNotFoundException
|
||||||
|
|
||||||
|
from botocore.exceptions import ParamValidationError
|
||||||
|
|
||||||
DEFAULT_REGISTRY_ID = '012345678910'
|
DEFAULT_REGISTRY_ID = '012345678910'
|
||||||
|
|
||||||
@ -145,6 +145,17 @@ class Image(BaseObject):
|
|||||||
response_object['imagePushedAt'] = '2017-05-09'
|
response_object['imagePushedAt'] = '2017-05-09'
|
||||||
return response_object
|
return response_object
|
||||||
|
|
||||||
|
@property
|
||||||
|
def response_batch_get_image(self):
|
||||||
|
response_object = {}
|
||||||
|
response_object['imageId'] = {}
|
||||||
|
response_object['imageId']['imageTag'] = self.image_tag
|
||||||
|
response_object['imageId']['imageDigest'] = self.get_image_digest()
|
||||||
|
response_object['imageManifest'] = self.image_manifest
|
||||||
|
response_object['repositoryName'] = self.repository
|
||||||
|
response_object['registryId'] = self.registry_id
|
||||||
|
return response_object
|
||||||
|
|
||||||
|
|
||||||
class ECRBackend(BaseBackend):
|
class ECRBackend(BaseBackend):
|
||||||
|
|
||||||
@ -245,6 +256,39 @@ class ECRBackend(BaseBackend):
|
|||||||
repository.images.append(image)
|
repository.images.append(image)
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
def batch_get_image(self, repository_name, registry_id=None, image_ids=None, accepted_media_types=None):
|
||||||
|
if repository_name in self.repositories:
|
||||||
|
repository = self.repositories[repository_name]
|
||||||
|
else:
|
||||||
|
raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)
|
||||||
|
|
||||||
|
if not image_ids:
|
||||||
|
raise ParamValidationError(msg='Missing required parameter in input: "imageIds"')
|
||||||
|
|
||||||
|
response = {
|
||||||
|
'images': [],
|
||||||
|
'failures': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
for image_id in image_ids:
|
||||||
|
found = False
|
||||||
|
for image in repository.images:
|
||||||
|
if (('imageDigest' in image_id and image.get_image_digest() == image_id['imageDigest']) or
|
||||||
|
('imageTag' in image_id and image.image_tag == image_id['imageTag'])):
|
||||||
|
found = True
|
||||||
|
response['images'].append(image.response_batch_get_image)
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
response['failures'].append({
|
||||||
|
'imageId': {
|
||||||
|
'imageTag': image_id.get('imageTag', 'null')
|
||||||
|
},
|
||||||
|
'failureCode': 'ImageNotFound',
|
||||||
|
'failureReason': 'Requested image not found'
|
||||||
|
})
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
ecr_backends = {}
|
ecr_backends = {}
|
||||||
for region, ec2_backend in ec2_backends.items():
|
for region, ec2_backend in ec2_backends.items():
|
||||||
|
@ -89,9 +89,13 @@ class ECRResponse(BaseResponse):
|
|||||||
'ECR.batch_delete_image is not yet implemented')
|
'ECR.batch_delete_image is not yet implemented')
|
||||||
|
|
||||||
def batch_get_image(self):
|
def batch_get_image(self):
|
||||||
if self.is_not_dryrun('BatchGetImage'):
|
repository_str = self._get_param('repositoryName')
|
||||||
raise NotImplementedError(
|
registry_id = self._get_param('registryId')
|
||||||
'ECR.batch_get_image is not yet implemented')
|
image_ids = self._get_param('imageIds')
|
||||||
|
accepted_media_types = self._get_param('acceptedMediaTypes')
|
||||||
|
|
||||||
|
response = self.ecr_backend.batch_get_image(repository_str, registry_id, image_ids, accepted_media_types)
|
||||||
|
return json.dumps(response)
|
||||||
|
|
||||||
def can_paginate(self):
|
def can_paginate(self):
|
||||||
if self.is_not_dryrun('CanPaginate'):
|
if self.is_not_dryrun('CanPaginate'):
|
||||||
|
@ -9,7 +9,7 @@ import re
|
|||||||
import sure # noqa
|
import sure # noqa
|
||||||
|
|
||||||
import boto3
|
import boto3
|
||||||
from botocore.exceptions import ClientError
|
from botocore.exceptions import ClientError, ParamValidationError
|
||||||
from dateutil.tz import tzlocal
|
from dateutil.tz import tzlocal
|
||||||
|
|
||||||
from moto import mock_ecr
|
from moto import mock_ecr
|
||||||
@ -445,3 +445,117 @@ def test_get_authorization_token_explicit_regions():
|
|||||||
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecr
|
||||||
|
def test_batch_get_image():
|
||||||
|
client = boto3.client('ecr', region_name='us-east-1')
|
||||||
|
_ = client.create_repository(
|
||||||
|
repositoryName='test_repository'
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = client.put_image(
|
||||||
|
repositoryName='test_repository',
|
||||||
|
imageManifest=json.dumps(_create_image_manifest()),
|
||||||
|
imageTag='latest'
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = client.put_image(
|
||||||
|
repositoryName='test_repository',
|
||||||
|
imageManifest=json.dumps(_create_image_manifest()),
|
||||||
|
imageTag='v1'
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = client.put_image(
|
||||||
|
repositoryName='test_repository',
|
||||||
|
imageManifest=json.dumps(_create_image_manifest()),
|
||||||
|
imageTag='v2'
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.batch_get_image(
|
||||||
|
repositoryName='test_repository',
|
||||||
|
imageIds=[
|
||||||
|
{
|
||||||
|
'imageTag': 'v2'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
type(response['images']).should.be(list)
|
||||||
|
len(response['images']).should.be(1)
|
||||||
|
|
||||||
|
response['images'][0]['imageManifest'].should.contain("vnd.docker.distribution.manifest.v2+json")
|
||||||
|
response['images'][0]['registryId'].should.equal("012345678910")
|
||||||
|
response['images'][0]['repositoryName'].should.equal("test_repository")
|
||||||
|
|
||||||
|
response['images'][0]['imageId']['imageTag'].should.equal("v2")
|
||||||
|
response['images'][0]['imageId']['imageDigest'].should.contain("sha")
|
||||||
|
|
||||||
|
type(response['failures']).should.be(list)
|
||||||
|
len(response['failures']).should.be(0)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecr
|
||||||
|
def test_batch_get_image_that_doesnt_exist():
|
||||||
|
client = boto3.client('ecr', region_name='us-east-1')
|
||||||
|
_ = client.create_repository(
|
||||||
|
repositoryName='test_repository'
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = client.put_image(
|
||||||
|
repositoryName='test_repository',
|
||||||
|
imageManifest=json.dumps(_create_image_manifest()),
|
||||||
|
imageTag='latest'
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = client.put_image(
|
||||||
|
repositoryName='test_repository',
|
||||||
|
imageManifest=json.dumps(_create_image_manifest()),
|
||||||
|
imageTag='v1'
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = client.put_image(
|
||||||
|
repositoryName='test_repository',
|
||||||
|
imageManifest=json.dumps(_create_image_manifest()),
|
||||||
|
imageTag='v2'
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.batch_get_image(
|
||||||
|
repositoryName='test_repository',
|
||||||
|
imageIds=[
|
||||||
|
{
|
||||||
|
'imageTag': 'v5'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
type(response['images']).should.be(list)
|
||||||
|
len(response['images']).should.be(0)
|
||||||
|
|
||||||
|
type(response['failures']).should.be(list)
|
||||||
|
len(response['failures']).should.be(1)
|
||||||
|
response['failures'][0]['failureReason'].should.equal("Requested image not found")
|
||||||
|
response['failures'][0]['failureCode'].should.equal("ImageNotFound")
|
||||||
|
response['failures'][0]['imageId']['imageTag'].should.equal("v5")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecr
|
||||||
|
def test_batch_get_image_no_tags():
|
||||||
|
client = boto3.client('ecr', region_name='us-east-1')
|
||||||
|
_ = client.create_repository(
|
||||||
|
repositoryName='test_repository'
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = client.put_image(
|
||||||
|
repositoryName='test_repository',
|
||||||
|
imageManifest=json.dumps(_create_image_manifest()),
|
||||||
|
imageTag='latest'
|
||||||
|
)
|
||||||
|
|
||||||
|
error_msg = re.compile(
|
||||||
|
r".*Missing required parameter in input: \"imageIds\".*",
|
||||||
|
re.MULTILINE)
|
||||||
|
|
||||||
|
client.batch_get_image.when.called_with(
|
||||||
|
repositoryName='test_repository').should.throw(
|
||||||
|
ParamValidationError, error_msg)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user