Merge pull request #5938 from docker/5931-ignore-default-platform

Ignore default platform if API version doesn't support platform param
This commit is contained in:
Joffrey F 2018-05-04 15:13:40 -07:00 committed by GitHub
commit 1cf1217ecb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 11 deletions

View File

@ -128,7 +128,8 @@ class Project(object):
volumes_from=volumes_from, volumes_from=volumes_from,
secrets=secrets, secrets=secrets,
pid_mode=pid_mode, pid_mode=pid_mode,
platform=service_dict.pop('platform', default_platform), platform=service_dict.pop('platform', None),
default_platform=default_platform,
**service_dict) **service_dict)
) )

View File

@ -172,6 +172,7 @@ class Service(object):
secrets=None, secrets=None,
scale=None, scale=None,
pid_mode=None, pid_mode=None,
default_platform=None,
**options **options
): ):
self.name = name self.name = name
@ -185,6 +186,7 @@ class Service(object):
self.networks = networks or {} self.networks = networks or {}
self.secrets = secrets or [] self.secrets = secrets or []
self.scale_num = scale or 1 self.scale_num = scale or 1
self.default_platform = default_platform
self.options = options self.options = options
def __repr__(self): def __repr__(self):
@ -358,6 +360,13 @@ class Service(object):
def image_name(self): def image_name(self):
return self.options.get('image', '{s.project}_{s.name}'.format(s=self)) return self.options.get('image', '{s.project}_{s.name}'.format(s=self))
@property
def platform(self):
platform = self.options.get('platform')
if not platform and version_gte(self.client.api_version, '1.35'):
platform = self.default_platform
return platform
def convergence_plan(self, strategy=ConvergenceStrategy.changed): def convergence_plan(self, strategy=ConvergenceStrategy.changed):
containers = self.containers(stopped=True) containers = self.containers(stopped=True)
@ -1018,8 +1027,7 @@ class Service(object):
if not six.PY3 and not IS_WINDOWS_PLATFORM: if not six.PY3 and not IS_WINDOWS_PLATFORM:
path = path.encode('utf8') path = path.encode('utf8')
platform = self.options.get('platform') if self.platform and version_lt(self.client.api_version, '1.35'):
if platform and version_lt(self.client.api_version, '1.35'):
raise OperationFailedError( raise OperationFailedError(
'Impossible to perform platform-targeted builds for API version < 1.35' 'Impossible to perform platform-targeted builds for API version < 1.35'
) )
@ -1044,7 +1052,7 @@ class Service(object):
}, },
gzip=gzip, gzip=gzip,
isolation=build_opts.get('isolation', self.options.get('isolation', None)), isolation=build_opts.get('isolation', self.options.get('isolation', None)),
platform=platform, platform=self.platform,
) )
try: try:
@ -1150,14 +1158,14 @@ class Service(object):
kwargs = { kwargs = {
'tag': tag or 'latest', 'tag': tag or 'latest',
'stream': True, 'stream': True,
'platform': self.options.get('platform'), 'platform': self.platform,
} }
if not silent: if not silent:
log.info('Pulling %s (%s%s%s)...' % (self.name, repo, separator, tag)) log.info('Pulling %s (%s%s%s)...' % (self.name, repo, separator, tag))
if kwargs['platform'] and version_lt(self.client.api_version, '1.35'): if kwargs['platform'] and version_lt(self.client.api_version, '1.35'):
raise OperationFailedError( raise OperationFailedError(
'Impossible to perform platform-targeted builds for API version < 1.35' 'Impossible to perform platform-targeted pulls for API version < 1.35'
) )
try: try:
output = self.client.pull(repo, **kwargs) output = self.client.pull(repo, **kwargs)

View File

@ -29,6 +29,7 @@ class ProjectTest(unittest.TestCase):
def setUp(self): def setUp(self):
self.mock_client = mock.create_autospec(docker.APIClient) self.mock_client = mock.create_autospec(docker.APIClient)
self.mock_client._general_configs = {} self.mock_client._general_configs = {}
self.mock_client.api_version = docker.constants.DEFAULT_DOCKER_API_VERSION
def test_from_config_v1(self): def test_from_config_v1(self):
config = Config( config = Config(
@ -578,21 +579,21 @@ class ProjectTest(unittest.TestCase):
) )
project = Project.from_config(name='test', client=self.mock_client, config_data=config_data) project = Project.from_config(name='test', client=self.mock_client, config_data=config_data)
assert project.get_service('web').options.get('platform') is None assert project.get_service('web').platform is None
project = Project.from_config( project = Project.from_config(
name='test', client=self.mock_client, config_data=config_data, default_platform='windows' name='test', client=self.mock_client, config_data=config_data, default_platform='windows'
) )
assert project.get_service('web').options.get('platform') == 'windows' assert project.get_service('web').platform == 'windows'
service_config['platform'] = 'linux/s390x' service_config['platform'] = 'linux/s390x'
project = Project.from_config(name='test', client=self.mock_client, config_data=config_data) project = Project.from_config(name='test', client=self.mock_client, config_data=config_data)
assert project.get_service('web').options.get('platform') == 'linux/s390x' assert project.get_service('web').platform == 'linux/s390x'
project = Project.from_config( project = Project.from_config(
name='test', client=self.mock_client, config_data=config_data, default_platform='windows' name='test', client=self.mock_client, config_data=config_data, default_platform='windows'
) )
assert project.get_service('web').options.get('platform') == 'linux/s390x' assert project.get_service('web').platform == 'linux/s390x'
@mock.patch('compose.parallel.ParallelStreamWriter._write_noansi') @mock.patch('compose.parallel.ParallelStreamWriter._write_noansi')
def test_error_parallel_pull(self, mock_write): def test_error_parallel_pull(self, mock_write):

View File

@ -446,6 +446,20 @@ class ServiceTest(unittest.TestCase):
with pytest.raises(OperationFailedError): with pytest.raises(OperationFailedError):
service.pull() service.pull()
def test_pull_image_with_default_platform(self):
self.mock_client.api_version = '1.35'
service = Service(
'foo', client=self.mock_client, image='someimage:sometag',
default_platform='linux'
)
assert service.platform == 'linux'
service.pull()
assert self.mock_client.pull.call_count == 1
call_args = self.mock_client.pull.call_args
assert call_args[1]['platform'] == 'linux'
@mock.patch('compose.service.Container', autospec=True) @mock.patch('compose.service.Container', autospec=True)
def test_recreate_container(self, _): def test_recreate_container(self, _):
mock_container = mock.create_autospec(Container) mock_container = mock.create_autospec(Container)
@ -538,7 +552,7 @@ class ServiceTest(unittest.TestCase):
assert self.mock_client.build.call_count == 1 assert self.mock_client.build.call_count == 1
assert not self.mock_client.build.call_args[1]['pull'] assert not self.mock_client.build.call_args[1]['pull']
def test_build_does_with_platform(self): def test_build_with_platform(self):
self.mock_client.api_version = '1.35' self.mock_client.api_version = '1.35'
self.mock_client.build.return_value = [ self.mock_client.build.return_value = [
b'{"stream": "Successfully built 12345"}', b'{"stream": "Successfully built 12345"}',
@ -551,6 +565,47 @@ class ServiceTest(unittest.TestCase):
call_args = self.mock_client.build.call_args call_args = self.mock_client.build.call_args
assert call_args[1]['platform'] == 'linux' assert call_args[1]['platform'] == 'linux'
def test_build_with_default_platform(self):
self.mock_client.api_version = '1.35'
self.mock_client.build.return_value = [
b'{"stream": "Successfully built 12345"}',
]
service = Service(
'foo', client=self.mock_client, build={'context': '.'},
default_platform='linux'
)
assert service.platform == 'linux'
service.build()
assert self.mock_client.build.call_count == 1
call_args = self.mock_client.build.call_args
assert call_args[1]['platform'] == 'linux'
def test_service_platform_precedence(self):
self.mock_client.api_version = '1.35'
service = Service(
'foo', client=self.mock_client, platform='linux/arm',
default_platform='osx'
)
assert service.platform == 'linux/arm'
def test_service_ignore_default_platform_with_unsupported_api(self):
self.mock_client.api_version = '1.32'
self.mock_client.build.return_value = [
b'{"stream": "Successfully built 12345"}',
]
service = Service(
'foo', client=self.mock_client, default_platform='windows', build={'context': '.'}
)
assert service.platform is None
service.build()
assert self.mock_client.build.call_count == 1
call_args = self.mock_client.build.call_args
assert call_args[1]['platform'] is None
def test_build_with_override_build_args(self): def test_build_with_override_build_args(self):
self.mock_client.build.return_value = [ self.mock_client.build.return_value = [
b'{"stream": "Successfully built 12345"}', b'{"stream": "Successfully built 12345"}',