cleanup compatibility and tests

Signed-off-by: aiordache <anca.iordache@docker.com>
This commit is contained in:
aiordache 2020-07-08 15:02:07 +02:00
parent b78c1ec193
commit c06b30548d
4 changed files with 29 additions and 88 deletions

View File

@ -66,7 +66,6 @@ def project_from_options(project_dir, options, additional_options=None):
context=context, context=context,
environment=environment, environment=environment,
override_dir=override_dir, override_dir=override_dir,
compatibility=compatibility_from_options(project_dir, options, environment),
interpolate=(not additional_options.get('--no-interpolate')), interpolate=(not additional_options.get('--no-interpolate')),
environment_file=environment_file environment_file=environment_file
) )
@ -98,7 +97,6 @@ def get_config_from_options(base_dir, options, additional_options=None):
) )
return config.load( return config.load(
config.find(base_dir, config_path, environment, override_dir), config.find(base_dir, config_path, environment, override_dir),
compatibility_from_options(config_path, options, environment),
not additional_options.get('--no-interpolate') not additional_options.get('--no-interpolate')
) )
@ -120,14 +118,14 @@ def get_config_path_from_options(base_dir, options, environment):
def get_project(project_dir, config_path=None, project_name=None, verbose=False, def get_project(project_dir, config_path=None, project_name=None, verbose=False,
context=None, environment=None, override_dir=None, context=None, environment=None, override_dir=None,
compatibility=False, interpolate=True, environment_file=None): interpolate=True, environment_file=None):
if not environment: if not environment:
environment = Environment.from_env_file(project_dir) environment = Environment.from_env_file(project_dir)
config_details = config.find(project_dir, config_path, environment, override_dir) config_details = config.find(project_dir, config_path, environment, override_dir)
project_name = get_project_name( project_name = get_project_name(
config_details.working_dir, project_name, environment config_details.working_dir, project_name, environment
) )
config_data = config.load(config_details, compatibility, interpolate) config_data = config.load(config_details, interpolate)
api_version = environment.get( api_version = environment.get(
'COMPOSE_API_VERSION', 'COMPOSE_API_VERSION',
@ -188,13 +186,3 @@ def get_project_name(working_dir, project_name=None, environment=None):
return normalize_name(project) return normalize_name(project)
return 'default' return 'default'
def compatibility_from_options(working_dir, options=None, environment=None):
"""Get compose v3 compatibility from --compatibility option
or from COMPOSE_COMPATIBILITY environment variable."""
compatibility_option = options.get('--compatibility')
compatibility_environment = environment.get_boolean('COMPOSE_COMPATIBILITY')
return compatibility_option or compatibility_environment

View File

@ -365,7 +365,7 @@ def find_candidates_in_parent_dirs(filenames, path):
return (candidates, path) return (candidates, path)
def check_swarm_only_config(service_dicts, compatibility=False): def check_swarm_only_config(service_dicts):
warning_template = ( warning_template = (
"Some services ({services}) use the '{key}' key, which will be ignored. " "Some services ({services}) use the '{key}' key, which will be ignored. "
"Compose does not support '{key}' configuration - use " "Compose does not support '{key}' configuration - use "
@ -386,7 +386,7 @@ def check_swarm_only_config(service_dicts, compatibility=False):
check_swarm_only_key(service_dicts, 'configs') check_swarm_only_key(service_dicts, 'configs')
def load(config_details, compatibility=False, interpolate=True): def load(config_details, interpolate=True):
"""Load the configuration from a working directory and a list of """Load the configuration from a working directory and a list of
configuration files. Files are loaded in order, and merged on top configuration files. Files are loaded in order, and merged on top
of each other to create the final configuration. of each other to create the final configuration.
@ -416,13 +416,13 @@ def load(config_details, compatibility=False, interpolate=True):
configs = load_mapping( configs = load_mapping(
config_details.config_files, 'get_configs', 'Config', config_details.working_dir config_details.config_files, 'get_configs', 'Config', config_details.working_dir
) )
service_dicts = load_services(config_details, main_file, compatibility, interpolate=interpolate) service_dicts = load_services(config_details, main_file, interpolate=interpolate)
if main_file.version != V1: if main_file.version != V1:
for service_dict in service_dicts: for service_dict in service_dicts:
match_named_volumes(service_dict, volumes) match_named_volumes(service_dict, volumes)
check_swarm_only_config(service_dicts, compatibility) check_swarm_only_config(service_dicts)
version = main_file.version version = main_file.version
@ -469,7 +469,7 @@ def validate_external(entity_type, name, config, version):
entity_type, name, ', '.join(k for k in config if k != 'external'))) entity_type, name, ', '.join(k for k in config if k != 'external')))
def load_services(config_details, config_file, compatibility=False, interpolate=True): def load_services(config_details, config_file, interpolate=True):
def build_service(service_name, service_dict, service_names): def build_service(service_name, service_dict, service_names):
service_config = ServiceConfig.with_abs_paths( service_config = ServiceConfig.with_abs_paths(
config_details.working_dir, config_details.working_dir,
@ -488,7 +488,6 @@ def load_services(config_details, config_file, compatibility=False, interpolate=
service_names, service_names,
config_file.version, config_file.version,
config_details.environment, config_details.environment,
compatibility,
interpolate interpolate
) )
return service_dict return service_dict
@ -887,7 +886,7 @@ def finalize_service_volumes(service_dict, environment):
return service_dict return service_dict
def finalize_service(service_config, service_names, version, environment, compatibility, def finalize_service(service_config, service_names, version, environment,
interpolate=True): interpolate=True):
service_dict = dict(service_config.config) service_dict = dict(service_config.config)
@ -929,17 +928,6 @@ def finalize_service(service_config, service_names, version, environment, compat
normalize_build(service_dict, service_config.working_dir, environment) normalize_build(service_dict, service_config.working_dir, environment)
if compatibility:
service_dict = translate_credential_spec_to_security_opt(service_dict)
service_dict, ignored_keys = translate_deploy_keys_to_container_config(
service_dict
)
if ignored_keys:
log.warning(
'The following deploy sub-keys are not supported in compatibility mode and have'
' been ignored: {}'.format(', '.join(ignored_keys))
)
service_dict['name'] = service_config.name service_dict['name'] = service_config.name
return normalize_v1_service_format(service_dict) return normalize_v1_service_format(service_dict)
@ -973,62 +961,6 @@ def convert_credential_spec_to_security_opt(credential_spec):
return 'registry://{registry}'.format(registry=credential_spec['registry']) return 'registry://{registry}'.format(registry=credential_spec['registry'])
def translate_credential_spec_to_security_opt(service_dict):
result = []
if 'credential_spec' in service_dict:
spec = convert_credential_spec_to_security_opt(service_dict['credential_spec'])
result.append('credentialspec={spec}'.format(spec=spec))
if result:
service_dict['security_opt'] = result
return service_dict
def translate_deploy_keys_to_container_config(service_dict):
if 'credential_spec' in service_dict:
del service_dict['credential_spec']
if 'configs' in service_dict:
del service_dict['configs']
if 'deploy' not in service_dict:
return service_dict, []
deploy_dict = service_dict['deploy']
ignored_keys = [
k for k in ['endpoint_mode', 'labels', 'update_config', 'rollback_config']
if k in deploy_dict
]
if 'replicas' in deploy_dict and deploy_dict.get('mode', 'replicated') == 'replicated':
scale = deploy_dict.get('replicas', 1)
max_replicas = deploy_dict.get('placement', {}).get('max_replicas_per_node', scale)
service_dict['scale'] = min(scale, max_replicas)
if max_replicas < scale:
log.warning("Scale is limited to {} ('max_replicas_per_node' field).".format(
max_replicas))
if 'restart_policy' in deploy_dict:
service_dict['restart'] = {
'Name': convert_restart_policy(deploy_dict['restart_policy'].get('condition', 'any')),
'MaximumRetryCount': deploy_dict['restart_policy'].get('max_attempts', 0)
}
for k in deploy_dict['restart_policy'].keys():
if k != 'condition' and k != 'max_attempts':
ignored_keys.append('restart_policy.{}'.format(k))
ignored_keys.extend(
translate_resource_keys_to_container_config(
deploy_dict.get('resources', {}), service_dict
)
)
del service_dict['deploy']
return service_dict, ignored_keys
def normalize_v1_service_format(service_dict): def normalize_v1_service_format(service_dict):
if 'log_driver' in service_dict or 'log_opt' in service_dict: if 'log_driver' in service_dict or 'log_opt' in service_dict:
if 'logging' not in service_dict: if 'logging' not in service_dict:

View File

@ -123,6 +123,8 @@ class Project(object):
service_dict.pop('secrets', None) or [], service_dict.pop('secrets', None) or [],
config_data.secrets) config_data.secrets)
service_dict['scale'] = project.get_service_scale(service_dict)
project.services.append( project.services.append(
Service( Service(
service_dict.pop('name'), service_dict.pop('name'),
@ -262,6 +264,23 @@ class Project(object):
return PidMode(pid_mode) return PidMode(pid_mode)
def get_service_scale(self, service_dict):
# service.scale for v2 and deploy.replicas for v3
scale = service_dict.get('scale', 1)
deploy_dict = service_dict.get('deploy', None)
if deploy_dict:
if deploy_dict.get('mode', 'replicated') == 'replicated':
scale = deploy_dict.get('replicas', scale)
# deploy may contain placement constraints introduced in v3.8
max_replicas = deploy_dict.get('placement', {}).get(
'max_replicas_per_node',
scale)
scale = min(scale, max_replicas)
if max_replicas < scale:
log.warning("Scale is limited to {} ('max_replicas_per_node' field).".format(
max_replicas))
return scale
def start(self, service_names=None, **options): def start(self, service_names=None, **options):
containers = [] containers = []

View File

@ -3655,6 +3655,7 @@ class InterpolationTest(unittest.TestCase):
assert 'BAR' in warnings[0] assert 'BAR' in warnings[0]
assert 'FOO' in warnings[1] assert 'FOO' in warnings[1]
@pytest.mark.skip(reason='compatibility mode was removed internally')
def test_compatibility_mode_warnings(self): def test_compatibility_mode_warnings(self):
config_details = build_config_details({ config_details = build_config_details({
'version': '3.5', 'version': '3.5',
@ -3693,6 +3694,7 @@ class InterpolationTest(unittest.TestCase):
assert 'restart_policy.delay' in warn_message assert 'restart_policy.delay' in warn_message
assert 'restart_policy.window' in warn_message assert 'restart_policy.window' in warn_message
@pytest.mark.skip(reason='compatibility mode was removed internally')
def test_compatibility_mode_load(self): def test_compatibility_mode_load(self):
config_details = build_config_details({ config_details = build_config_details({
'version': '3.5', 'version': '3.5',