mirror of https://github.com/docker/compose.git
Add support for blkio config keys
Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
7882f1fb06
commit
6361d907f6
|
@ -16,6 +16,7 @@ from . import types
|
||||||
from .. import const
|
from .. import const
|
||||||
from ..const import COMPOSEFILE_V1 as V1
|
from ..const import COMPOSEFILE_V1 as V1
|
||||||
from ..utils import build_string_dict
|
from ..utils import build_string_dict
|
||||||
|
from ..utils import parse_bytes
|
||||||
from ..utils import parse_nanoseconds_int
|
from ..utils import parse_nanoseconds_int
|
||||||
from ..utils import splitdrive
|
from ..utils import splitdrive
|
||||||
from ..version import ComposeVersion
|
from ..version import ComposeVersion
|
||||||
|
@ -108,6 +109,7 @@ DOCKER_CONFIG_KEYS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
ALLOWED_KEYS = DOCKER_CONFIG_KEYS + [
|
ALLOWED_KEYS = DOCKER_CONFIG_KEYS + [
|
||||||
|
'blkio_config',
|
||||||
'build',
|
'build',
|
||||||
'container_name',
|
'container_name',
|
||||||
'credential_spec',
|
'credential_spec',
|
||||||
|
@ -726,8 +728,9 @@ def process_service(service_config):
|
||||||
if field in service_dict:
|
if field in service_dict:
|
||||||
service_dict[field] = to_list(service_dict[field])
|
service_dict[field] = to_list(service_dict[field])
|
||||||
|
|
||||||
service_dict = process_healthcheck(service_dict, service_config.name)
|
service_dict = process_blkio_config(process_ports(
|
||||||
service_dict = process_ports(service_dict)
|
process_healthcheck(service_dict, service_config.name)
|
||||||
|
))
|
||||||
|
|
||||||
return service_dict
|
return service_dict
|
||||||
|
|
||||||
|
@ -754,6 +757,28 @@ def process_depends_on(service_dict):
|
||||||
return service_dict
|
return service_dict
|
||||||
|
|
||||||
|
|
||||||
|
def process_blkio_config(service_dict):
|
||||||
|
if not service_dict.get('blkio_config'):
|
||||||
|
return service_dict
|
||||||
|
|
||||||
|
for field in ['device_read_bps', 'device_write_bps']:
|
||||||
|
if field in service_dict['blkio_config']:
|
||||||
|
for v in service_dict['blkio_config'].get(field, []):
|
||||||
|
v['rate'] = parse_bytes(v.get('rate', 0))
|
||||||
|
|
||||||
|
for field in ['device_read_iops', 'device_write_iops']:
|
||||||
|
if field in service_dict['blkio_config']:
|
||||||
|
for v in service_dict['blkio_config'].get(field, []):
|
||||||
|
try:
|
||||||
|
v['rate'] = int(v.get('rate', 0))
|
||||||
|
except ValueError:
|
||||||
|
raise ConfigurationError(
|
||||||
|
'Invalid IOPS value: "{}". Must be a positive integer.'.format(v.get('rate'))
|
||||||
|
)
|
||||||
|
|
||||||
|
return service_dict
|
||||||
|
|
||||||
|
|
||||||
def process_healthcheck(service_dict, service_name):
|
def process_healthcheck(service_dict, service_name):
|
||||||
if 'healthcheck' not in service_dict:
|
if 'healthcheck' not in service_dict:
|
||||||
return service_dict
|
return service_dict
|
||||||
|
@ -940,6 +965,7 @@ def merge_service_dicts(base, override, version):
|
||||||
|
|
||||||
md.merge_field('logging', merge_logging, default={})
|
md.merge_field('logging', merge_logging, default={})
|
||||||
merge_ports(md, base, override)
|
merge_ports(md, base, override)
|
||||||
|
md.merge_field('blkio_config', merge_blkio_config, default={})
|
||||||
|
|
||||||
for field in set(ALLOWED_KEYS) - set(md):
|
for field in set(ALLOWED_KEYS) - set(md):
|
||||||
md.merge_scalar(field)
|
md.merge_scalar(field)
|
||||||
|
@ -993,6 +1019,26 @@ def merge_build(output, base, override):
|
||||||
return dict(md)
|
return dict(md)
|
||||||
|
|
||||||
|
|
||||||
|
def merge_blkio_config(base, override):
|
||||||
|
md = MergeDict(base, override)
|
||||||
|
md.merge_scalar('weight')
|
||||||
|
|
||||||
|
def merge_blkio_limits(base, override):
|
||||||
|
index = dict((b['path'], b) for b in base)
|
||||||
|
for o in override:
|
||||||
|
index[o['path']] = o
|
||||||
|
|
||||||
|
return sorted(list(index.values()), key=lambda x: x['path'])
|
||||||
|
|
||||||
|
for field in [
|
||||||
|
"device_read_bps", "device_read_iops", "device_write_bps",
|
||||||
|
"device_write_iops", "weight_device",
|
||||||
|
]:
|
||||||
|
md.merge_field(field, merge_blkio_limits, default=[])
|
||||||
|
|
||||||
|
return dict(md)
|
||||||
|
|
||||||
|
|
||||||
def merge_logging(base, override):
|
def merge_logging(base, override):
|
||||||
md = MergeDict(base, override)
|
md = MergeDict(base, override)
|
||||||
md.merge_scalar('driver')
|
md.merge_scalar('driver')
|
||||||
|
|
|
@ -50,6 +50,33 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"blkio_config": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"device_read_bps": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_read_iops": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_write_bps": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_write_iops": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"weight": {"type": "integer"},
|
||||||
|
"weight_device": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_weight"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{"type": "string"},
|
{"type": "string"},
|
||||||
|
@ -326,6 +353,23 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"blkio_limit": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"path": {"type": "string"},
|
||||||
|
"rate": {"type": ["integer", "string"]}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"blkio_weight": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"path": {"type": "string"},
|
||||||
|
"weight": {"type": "integer"}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
|
||||||
"constraints": {
|
"constraints": {
|
||||||
"service": {
|
"service": {
|
||||||
"id": "#/definitions/constraints/service",
|
"id": "#/definitions/constraints/service",
|
||||||
|
|
|
@ -50,6 +50,34 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"blkio_config": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"device_read_bps": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_read_iops": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_write_bps": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_write_iops": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"weight": {"type": "integer"},
|
||||||
|
"weight_device": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_weight"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
|
||||||
"build": {
|
"build": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{"type": "string"},
|
{"type": "string"},
|
||||||
|
@ -376,6 +404,23 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"blkio_limit": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"path": {"type": "string"},
|
||||||
|
"rate": {"type": ["integer", "string"]}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"blkio_weight": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"path": {"type": "string"},
|
||||||
|
"weight": {"type": "integer"}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
|
||||||
"constraints": {
|
"constraints": {
|
||||||
"service": {
|
"service": {
|
||||||
"id": "#/definitions/constraints/service",
|
"id": "#/definitions/constraints/service",
|
||||||
|
|
|
@ -50,6 +50,34 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"blkio_config": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"device_read_bps": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_read_iops": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_write_bps": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_write_iops": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"weight": {"type": "integer"},
|
||||||
|
"weight_device": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_weight"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
|
||||||
"build": {
|
"build": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{"type": "string"},
|
{"type": "string"},
|
||||||
|
@ -383,6 +411,23 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"blkio_limit": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"path": {"type": "string"},
|
||||||
|
"rate": {"type": ["integer", "string"]}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"blkio_weight": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"path": {"type": "string"},
|
||||||
|
"weight": {"type": "integer"}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
|
||||||
"constraints": {
|
"constraints": {
|
||||||
"service": {
|
"service": {
|
||||||
"id": "#/definitions/constraints/service",
|
"id": "#/definitions/constraints/service",
|
||||||
|
|
|
@ -50,6 +50,34 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"blkio_config": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"device_read_bps": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_read_iops": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_write_bps": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"device_write_iops": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||||
|
},
|
||||||
|
"weight": {"type": "integer"},
|
||||||
|
"weight_device": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/blkio_weight"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
|
||||||
"build": {
|
"build": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{"type": "string"},
|
{"type": "string"},
|
||||||
|
@ -384,6 +412,23 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"blkio_limit": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"path": {"type": "string"},
|
||||||
|
"rate": {"type": ["integer", "string"]}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"blkio_weight": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"path": {"type": "string"},
|
||||||
|
"weight": {"type": "integer"}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
|
||||||
"constraints": {
|
"constraints": {
|
||||||
"service": {
|
"service": {
|
||||||
"id": "#/definitions/constraints/service",
|
"id": "#/definitions/constraints/service",
|
||||||
|
|
|
@ -813,6 +813,7 @@ class Service(object):
|
||||||
options = dict(self.options, **override_options)
|
options = dict(self.options, **override_options)
|
||||||
|
|
||||||
logging_dict = options.get('logging', None)
|
logging_dict = options.get('logging', None)
|
||||||
|
blkio_config = convert_blkio_config(options.get('blkio_config', None))
|
||||||
log_config = get_log_config(logging_dict)
|
log_config = get_log_config(logging_dict)
|
||||||
init_path = None
|
init_path = None
|
||||||
if isinstance(options.get('init'), six.string_types):
|
if isinstance(options.get('init'), six.string_types):
|
||||||
|
@ -869,6 +870,12 @@ class Service(object):
|
||||||
cpuset_cpus=options.get('cpuset'),
|
cpuset_cpus=options.get('cpuset'),
|
||||||
cpu_shares=options.get('cpu_shares'),
|
cpu_shares=options.get('cpu_shares'),
|
||||||
storage_opt=options.get('storage_opt'),
|
storage_opt=options.get('storage_opt'),
|
||||||
|
blkio_weight=blkio_config.get('weight'),
|
||||||
|
blkio_weight_device=blkio_config.get('weight_device'),
|
||||||
|
device_read_bps=blkio_config.get('device_read_bps'),
|
||||||
|
device_read_iops=blkio_config.get('device_read_iops'),
|
||||||
|
device_write_bps=blkio_config.get('device_write_bps'),
|
||||||
|
device_write_iops=blkio_config.get('device_write_iops'),
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_secret_volumes(self):
|
def get_secret_volumes(self):
|
||||||
|
@ -1395,3 +1402,22 @@ def build_container_ports(container_ports, options):
|
||||||
port = tuple(port.split('/'))
|
port = tuple(port.split('/'))
|
||||||
ports.append(port)
|
ports.append(port)
|
||||||
return ports
|
return ports
|
||||||
|
|
||||||
|
|
||||||
|
def convert_blkio_config(blkio_config):
|
||||||
|
result = {}
|
||||||
|
if blkio_config is None:
|
||||||
|
return result
|
||||||
|
|
||||||
|
result['weight'] = blkio_config.get('weight')
|
||||||
|
for field in [
|
||||||
|
"device_read_bps", "device_read_iops", "device_write_bps",
|
||||||
|
"device_write_iops", "weight_device",
|
||||||
|
]:
|
||||||
|
if field not in blkio_config:
|
||||||
|
continue
|
||||||
|
arr = []
|
||||||
|
for item in blkio_config[field]:
|
||||||
|
arr.append(dict([(k.capitalize(), v) for k, v in item.items()]))
|
||||||
|
result[field] = arr
|
||||||
|
return result
|
||||||
|
|
|
@ -9,7 +9,10 @@ import logging
|
||||||
import ntpath
|
import ntpath
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
from docker.errors import DockerException
|
||||||
|
from docker.utils import parse_bytes as sdk_parse_bytes
|
||||||
|
|
||||||
|
from .config.errors import ConfigurationError
|
||||||
from .errors import StreamParseError
|
from .errors import StreamParseError
|
||||||
from .timeparse import timeparse
|
from .timeparse import timeparse
|
||||||
|
|
||||||
|
@ -133,3 +136,10 @@ def splitdrive(path):
|
||||||
if path[0] in ['.', '\\', '/', '~']:
|
if path[0] in ['.', '\\', '/', '~']:
|
||||||
return ('', path)
|
return ('', path)
|
||||||
return ntpath.splitdrive(path)
|
return ntpath.splitdrive(path)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_bytes(n):
|
||||||
|
try:
|
||||||
|
return sdk_parse_bytes(n)
|
||||||
|
except DockerException:
|
||||||
|
raise ConfigurationError('Invalid format for bytes value: {}'.format(n))
|
||||||
|
|
|
@ -203,6 +203,34 @@ class ServiceTest(DockerClientTestCase):
|
||||||
service.start_container(container)
|
service.start_container(container)
|
||||||
assert container.get('HostConfig.ReadonlyRootfs') == read_only
|
assert container.get('HostConfig.ReadonlyRootfs') == read_only
|
||||||
|
|
||||||
|
def test_create_container_with_blkio_config(self):
|
||||||
|
blkio_config = {
|
||||||
|
'weight': 300,
|
||||||
|
'weight_device': [{'path': '/dev/sda', 'weight': 200}],
|
||||||
|
'device_read_bps': [{'path': '/dev/sda', 'rate': 1024 * 1024 * 100}],
|
||||||
|
'device_read_iops': [{'path': '/dev/sda', 'rate': 1000}],
|
||||||
|
'device_write_bps': [{'path': '/dev/sda', 'rate': 1024 * 1024}],
|
||||||
|
'device_write_iops': [{'path': '/dev/sda', 'rate': 800}]
|
||||||
|
}
|
||||||
|
service = self.create_service('web', blkio_config=blkio_config)
|
||||||
|
container = service.create_container()
|
||||||
|
assert container.get('HostConfig.BlkioWeight') == 300
|
||||||
|
assert container.get('HostConfig.BlkioWeightDevice') == [{
|
||||||
|
'Path': '/dev/sda', 'Weight': 200
|
||||||
|
}]
|
||||||
|
assert container.get('HostConfig.BlkioDeviceReadBps') == [{
|
||||||
|
'Path': '/dev/sda', 'Rate': 1024 * 1024 * 100
|
||||||
|
}]
|
||||||
|
assert container.get('HostConfig.BlkioDeviceWriteBps') == [{
|
||||||
|
'Path': '/dev/sda', 'Rate': 1024 * 1024
|
||||||
|
}]
|
||||||
|
assert container.get('HostConfig.BlkioDeviceReadIOps') == [{
|
||||||
|
'Path': '/dev/sda', 'Rate': 1000
|
||||||
|
}]
|
||||||
|
assert container.get('HostConfig.BlkioDeviceWriteIOps') == [{
|
||||||
|
'Path': '/dev/sda', 'Rate': 800
|
||||||
|
}]
|
||||||
|
|
||||||
def test_create_container_with_security_opt(self):
|
def test_create_container_with_security_opt(self):
|
||||||
security_opt = ['label:disable']
|
security_opt = ['label:disable']
|
||||||
service = self.create_service('db', security_opt=security_opt)
|
service = self.create_service('db', security_opt=security_opt)
|
||||||
|
|
|
@ -2151,6 +2151,53 @@ class ConfigTest(unittest.TestCase):
|
||||||
actual = config.merge_service_dicts(base, override, V2_2)
|
actual = config.merge_service_dicts(base, override, V2_2)
|
||||||
assert actual == {'image': 'bar', 'scale': 4}
|
assert actual == {'image': 'bar', 'scale': 4}
|
||||||
|
|
||||||
|
def test_merge_blkio_config(self):
|
||||||
|
base = {
|
||||||
|
'image': 'bar',
|
||||||
|
'blkio_config': {
|
||||||
|
'weight': 300,
|
||||||
|
'weight_device': [
|
||||||
|
{'path': '/dev/sda1', 'weight': 200}
|
||||||
|
],
|
||||||
|
'device_read_iops': [
|
||||||
|
{'path': '/dev/sda1', 'rate': 300}
|
||||||
|
],
|
||||||
|
'device_write_iops': [
|
||||||
|
{'path': '/dev/sda1', 'rate': 1000}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override = {
|
||||||
|
'blkio_config': {
|
||||||
|
'weight': 450,
|
||||||
|
'weight_device': [
|
||||||
|
{'path': '/dev/sda2', 'weight': 400}
|
||||||
|
],
|
||||||
|
'device_read_iops': [
|
||||||
|
{'path': '/dev/sda1', 'rate': 2000}
|
||||||
|
],
|
||||||
|
'device_read_bps': [
|
||||||
|
{'path': '/dev/sda1', 'rate': 1024}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual = config.merge_service_dicts(base, override, V2_2)
|
||||||
|
assert actual == {
|
||||||
|
'image': 'bar',
|
||||||
|
'blkio_config': {
|
||||||
|
'weight': override['blkio_config']['weight'],
|
||||||
|
'weight_device': (
|
||||||
|
base['blkio_config']['weight_device'] +
|
||||||
|
override['blkio_config']['weight_device']
|
||||||
|
),
|
||||||
|
'device_read_iops': override['blkio_config']['device_read_iops'],
|
||||||
|
'device_read_bps': override['blkio_config']['device_read_bps'],
|
||||||
|
'device_write_iops': base['blkio_config']['device_write_iops']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def test_external_volume_config(self):
|
def test_external_volume_config(self):
|
||||||
config_details = build_config_details({
|
config_details = build_config_details({
|
||||||
'version': '2',
|
'version': '2',
|
||||||
|
|
Loading…
Reference in New Issue