mirror of
https://github.com/docker/compose.git
synced 2025-07-25 14:44:29 +02:00
Merge pull request #6454 from rumpl/digest-distribution
Resolve digests without pulling image
This commit is contained in:
commit
718346f103
@ -95,19 +95,10 @@ def get_image_digest(service, allow_push=False):
|
|||||||
if separator == '@':
|
if separator == '@':
|
||||||
return service.options['image']
|
return service.options['image']
|
||||||
|
|
||||||
try:
|
digest = get_digest(service)
|
||||||
image = service.image()
|
|
||||||
except NoSuchImageError:
|
|
||||||
action = 'build' if 'build' in service.options else 'pull'
|
|
||||||
raise UserError(
|
|
||||||
"Image not found for service '{service}'. "
|
|
||||||
"You might need to run `docker-compose {action} {service}`."
|
|
||||||
.format(service=service.name, action=action))
|
|
||||||
|
|
||||||
if image['RepoDigests']:
|
if digest:
|
||||||
# TODO: pick a digest based on the image tag if there are multiple
|
return digest
|
||||||
# digests
|
|
||||||
return image['RepoDigests'][0]
|
|
||||||
|
|
||||||
if 'build' not in service.options:
|
if 'build' not in service.options:
|
||||||
raise NeedsPull(service.image_name, service.name)
|
raise NeedsPull(service.image_name, service.name)
|
||||||
@ -118,6 +109,32 @@ def get_image_digest(service, allow_push=False):
|
|||||||
return push_image(service)
|
return push_image(service)
|
||||||
|
|
||||||
|
|
||||||
|
def get_digest(service):
|
||||||
|
digest = None
|
||||||
|
try:
|
||||||
|
image = service.image()
|
||||||
|
# TODO: pick a digest based on the image tag if there are multiple
|
||||||
|
# digests
|
||||||
|
if image['RepoDigests']:
|
||||||
|
digest = image['RepoDigests'][0]
|
||||||
|
except NoSuchImageError:
|
||||||
|
try:
|
||||||
|
# Fetch the image digest from the registry
|
||||||
|
distribution = service.get_image_registry_data()
|
||||||
|
|
||||||
|
if distribution['Descriptor']['digest']:
|
||||||
|
digest = '{image_name}@{digest}'.format(
|
||||||
|
image_name=service.image_name,
|
||||||
|
digest=distribution['Descriptor']['digest']
|
||||||
|
)
|
||||||
|
except NoSuchImageError:
|
||||||
|
raise UserError(
|
||||||
|
"Digest not found for service '{service}'. "
|
||||||
|
"Repository does not exist or may require 'docker login'"
|
||||||
|
.format(service=service.name))
|
||||||
|
return digest
|
||||||
|
|
||||||
|
|
||||||
def push_image(service):
|
def push_image(service):
|
||||||
try:
|
try:
|
||||||
digest = service.push()
|
digest = service.push()
|
||||||
|
@ -363,6 +363,12 @@ class Service(object):
|
|||||||
"rebuild this image you must use `docker-compose build` or "
|
"rebuild this image you must use `docker-compose build` or "
|
||||||
"`docker-compose up --build`.".format(self.name))
|
"`docker-compose up --build`.".format(self.name))
|
||||||
|
|
||||||
|
def get_image_registry_data(self):
|
||||||
|
try:
|
||||||
|
return self.client.inspect_distribution(self.image_name)
|
||||||
|
except APIError:
|
||||||
|
raise NoSuchImageError("Image '{}' not found".format(self.image_name))
|
||||||
|
|
||||||
def image(self):
|
def image(self):
|
||||||
try:
|
try:
|
||||||
return self.client.inspect_image(self.image_name)
|
return self.client.inspect_image(self.image_name)
|
||||||
|
@ -10,6 +10,7 @@ from compose import service
|
|||||||
from compose.cli.errors import UserError
|
from compose.cli.errors import UserError
|
||||||
from compose.config.config import Config
|
from compose.config.config import Config
|
||||||
from compose.const import COMPOSEFILE_V2_0 as V2_0
|
from compose.const import COMPOSEFILE_V2_0 as V2_0
|
||||||
|
from compose.service import NoSuchImageError
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -35,6 +36,16 @@ def test_get_image_digest_image_uses_digest(mock_service):
|
|||||||
assert not mock_service.image.called
|
assert not mock_service.image.called
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_image_digest_from_repository(mock_service):
|
||||||
|
mock_service.options['image'] = 'abcd'
|
||||||
|
mock_service.image_name = 'abcd'
|
||||||
|
mock_service.image.side_effect = NoSuchImageError(None)
|
||||||
|
mock_service.get_image_registry_data.return_value = {'Descriptor': {'digest': 'digest'}}
|
||||||
|
|
||||||
|
digest = bundle.get_image_digest(mock_service)
|
||||||
|
assert digest == 'abcd@digest'
|
||||||
|
|
||||||
|
|
||||||
def test_get_image_digest_no_image(mock_service):
|
def test_get_image_digest_no_image(mock_service):
|
||||||
with pytest.raises(UserError) as exc:
|
with pytest.raises(UserError) as exc:
|
||||||
bundle.get_image_digest(service.Service(name='theservice'))
|
bundle.get_image_digest(service.Service(name='theservice'))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user