Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add override option to service configuration for ports #6213

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion compose/config/config.py
Expand Up @@ -1061,7 +1061,12 @@ def merge_service_dicts(base, override, version):
md.merge_field(field, merge_list_or_string)

md.merge_field('logging', merge_logging, default={})
merge_ports(md, base, override)

if 'ports' in md.override.get('override', []):
md.merge_field('ports', merge_override_items_lists, default=[])
else:
merge_ports(md, base, override)

md.merge_field('blkio_config', merge_blkio_config, default={})
md.merge_field('healthcheck', merge_healthchecks, default={})
md.merge_field('deploy', merge_deploy, default={})
Expand Down Expand Up @@ -1220,6 +1225,10 @@ def merge_labels(base, override):
return labels


def merge_override_items_lists(base, override):
return sorted(set(override))


def split_kv(kvpair):
if '=' in kvpair:
return kvpair.split('=', 1)
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v2.0.json
Expand Up @@ -256,7 +256,8 @@
"volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"volume_driver": {"type": "string"},
"volumes_from": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},

"dependencies": {
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v2.1.json
Expand Up @@ -289,7 +289,8 @@
"volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"volume_driver": {"type": "string"},
"volumes_from": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},

"dependencies": {
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v2.2.json
Expand Up @@ -298,7 +298,8 @@
"volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"volume_driver": {"type": "string"},
"volumes_from": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},

"dependencies": {
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v2.3.json
Expand Up @@ -341,7 +341,8 @@
},
"volume_driver": {"type": "string"},
"volumes_from": {"$ref": "#/definitions/list_of_strings"},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},

"dependencies": {
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v2.4.json
Expand Up @@ -340,7 +340,8 @@
},
"volume_driver": {"type": "string"},
"volumes_from": {"$ref": "#/definitions/list_of_strings"},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},

"dependencies": {
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v3.0.json
Expand Up @@ -195,7 +195,8 @@
"user": {"type": "string"},
"userns_mode": {"type": "string"},
"volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},
"additionalProperties": false
},
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v3.1.json
Expand Up @@ -224,7 +224,8 @@
"user": {"type": "string"},
"userns_mode": {"type": "string"},
"volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},
"additionalProperties": false
},
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v3.2.json
Expand Up @@ -270,7 +270,8 @@
"uniqueItems": true
}
},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},
"additionalProperties": false
},
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v3.3.json
Expand Up @@ -303,7 +303,8 @@
"uniqueItems": true
}
},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},
"additionalProperties": false
},
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v3.4.json
Expand Up @@ -307,7 +307,8 @@
"uniqueItems": true
}
},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},
"additionalProperties": false
},
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v3.5.json
Expand Up @@ -308,7 +308,8 @@
"uniqueItems": true
}
},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},
"additionalProperties": false
},
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v3.6.json
Expand Up @@ -317,7 +317,8 @@
"uniqueItems": true
}
},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},
"additionalProperties": false
},
Expand Down
3 changes: 2 additions & 1 deletion compose/config/config_schema_v3.7.json
Expand Up @@ -318,7 +318,8 @@
"uniqueItems": true
}
},
"working_dir": {"type": "string"}
"working_dir": {"type": "string"},
"override": {"type": "array", "items": {"type": ["string"], "uniqueItems": true, "format": "override"}}
},
"patternProperties": {"^x-": {}},
"additionalProperties": false
Expand Down
13 changes: 12 additions & 1 deletion compose/config/validation.py
Expand Up @@ -69,6 +69,8 @@
$
""".format(IPV6_SEG=VALID_IPV6_SEG, IPV4_ADDR=VALID_IPV4_ADDR).split())

VALID_OVERRIDE_FORMAT = r'^(ports)$'


@FormatChecker.cls_checks(format="ports", raises=ValidationError)
def format_ports(instance):
Expand Down Expand Up @@ -99,6 +101,15 @@ def format_subnet_ip_address(instance):
return True


@FormatChecker.cls_checks(format="override", raises=ValidationError)
def format_override(instance):
if isinstance(instance, six.string_types):
if not re.match(VALID_OVERRIDE_FORMAT, instance):
raise ValidationError("should be of the format 'ports'")

return True


def match_named_volumes(service_dict, project_volumes):
service_volumes = service_dict.get('volumes', [])
for volume_spec in service_volumes:
Expand Down Expand Up @@ -426,7 +437,7 @@ def process_config_schema_errors(error):

def validate_against_config_schema(config_file):
schema = load_jsonschema(config_file)
format_checker = FormatChecker(["ports", "expose", "subnet_ip_address"])
format_checker = FormatChecker(["ports", "expose", "subnet_ip_address", "override"])
validator = Draft4Validator(
schema,
resolver=RefResolver(get_resolver_path(), schema),
Expand Down
52 changes: 52 additions & 0 deletions tests/unit/config/config_test.py
Expand Up @@ -1205,6 +1205,58 @@ def test_volume_mode_override(self):
svc_volumes = list(map(lambda v: v.repr(), service_dicts[0]['volumes']))
assert svc_volumes == ['/c:/b:ro']

def test_config_invalid_override_config(self):
with pytest.raises(ConfigurationError) as excinfo:
config.load(
build_config_details(
{
'version': str(V2_0),
'services': {
'web': {
'image': 'example/web',
'override': ["foo"]
}
},
},
filename='filename.yml',
)
)
assert 'services.web.override is invalid: should be of the format' in excinfo.exconly()

def test_override_mode_ports_override(self):
base_file = config.ConfigFile(
'base.yaml',
{
'version': str(V2_0),
'services': {
'web': {
'image': 'example/web',
'ports': ['80:80']
}
},
}
)

override_file = config.ConfigFile(
'override.yaml',
{
'version': '2',
'services': {
'web': {
'ports': ['8080:80'],
'override': ['ports'],
}
}
}
)
details = config.ConfigDetails('.', [base_file, override_file])
service_dicts = config.load(details).services
svc_ports = list(map(lambda v: v.repr(), service_dicts[0]['ports']))
assert svc_ports == [{
'published': 8080,
'target': 80,
}]

def test_undeclared_volume_v2(self):
base_file = config.ConfigFile(
'base.yaml',
Expand Down