This commit is contained in:
Stefan Agner 2023-09-01 14:04:34 -07:00 committed by GitHub
commit d93d52cd63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 419 additions and 229 deletions

View File

@ -8,6 +8,7 @@ from ..types import ContainerConfig
from ..types import EndpointConfig
from ..types import HostConfig
from ..types import NetworkingConfig
from ..types import HostResources
class ContainerApiMixin:
@ -615,6 +616,92 @@ class ContainerApiMixin:
kwargs['version'] = self._version
return HostConfig(*args, **kwargs)
def create_resources(self, *args, **kwargs):
"""
Create a dictionary for the ``resources`` argument to
:py:meth:`update_container`.
Args:
blkio_weight_device: Block IO weight (relative device weight) in
the form of: ``[{"Path": "device_path", "Weight": weight}]``.
blkio_weight: Block IO weight (relative weight), accepts a weight
value between 10 and 1000.
cgroup_parent (string): Path to `cgroups` under which the
container's `cgroup` is created. If the path is not absolute,
the path is considered to be relative to the `cgroups` path of
the init process. Cgroups are created if they do not already
exist.
cpu_period (int): The length of a CPU period in microseconds.
cpu_quota (int): Microseconds of CPU time that the container can
get in a CPU period.
cpu_rt_period (int): The length of a CPU real-time period in
microseconds. Set to 0 to allocate no time allocated to
real-time tasks.
cpu_rt_runtime (int): The length of a CPU real-time runtime in
microseconds. Set to 0 to allocate no time allocated to
real-time tasks.
cpu_shares (int): CPU shares (relative weight).
cpuset_cpus (str): CPUs in which to allow execution (``0-3``,
``0,1``).
cpuset_mems (str): Memory nodes (MEMs) in which to allow execution
(``0-3``, ``0,1``). Only effective on NUMA systems.
device_cgroup_rules (:py:class:`list`): A list of cgroup rules to
apply to the container.
device_read_bps: Limit read rate (bytes per second) from a device
in the form of: `[{"Path": "device_path", "Rate": rate}]`
device_read_iops: Limit read rate (IO per second) from a device.
device_write_bps: Limit write rate (bytes per second) from a
device.
device_write_iops: Limit write rate (IO per second) from a device.
devices (:py:class:`list`): Expose host devices to the container,
as a list of strings in the form
``<path_on_host>:<path_in_container>:<cgroup_permissions>``.
For example, ``/dev/sda:/dev/xvda:rwm`` allows the container
to have read-write access to the host's ``/dev/sda`` via a
node named ``/dev/xvda`` inside the container.
device_requests (:py:class:`list`): Expose host resources such as
GPUs to the container, as a list of
:py:class:`docker.types.DeviceRequest` instances.
kernel_memory (int or str): Kernel memory limit
mem_limit (float or str): Memory limit. Accepts float values
(which represent the memory limit of the created container in
bytes) or a string with a units identification char
(``100000b``, ``1000k``, ``128m``, ``1g``). If a string is
specified without a units character, bytes are assumed as an
mem_reservation (float or str): Memory soft limit.
mem_swappiness (int): Tune a container's memory swappiness
behavior. Accepts number between 0 and 100.
memswap_limit (str or int): Maximum amount of memory + swap a
container is allowed to consume.
nano_cpus (int): CPU quota in units of 10<sup>-9</sup> CPUs.
oom_kill_disable (bool): Whether to disable OOM killer.
pids_limit (int): Tune a container's pids limit. Set ``-1`` for
unlimited.
ulimits (:py:class:`list`): Ulimits to set inside the container,
as a list of :py:class:`docker.types.Ulimit` instances.
Returns:
(dict) A dictionary which can be passed to the ``resources``
argument to :py:meth:`update_container`.
Example:
>>> cli.create_resources(mem_limit='1g', cpuset_cpus='0-3')
{'MemLimit': '1g', 'CpusetCpus': '0-3'}
"""
if not kwargs:
kwargs = {}
if 'version' in kwargs:
raise TypeError(
"create_resources() got an unexpected "
"keyword argument 'version'"
)
kwargs['version'] = self._version
hres = HostResources(*args, **kwargs)
return hres
def create_networking_config(self, *args, **kwargs):
"""
Create a networking config dictionary to be used as the
@ -1277,28 +1364,25 @@ class ContainerApiMixin:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/containers/{0}/update', container)
data = {}
if blkio_weight:
data['BlkioWeight'] = blkio_weight
if cpu_period:
data['CpuPeriod'] = cpu_period
if cpu_shares:
data['CpuShares'] = cpu_shares
if cpu_quota:
data['CpuQuota'] = cpu_quota
if cpuset_cpus:
data['CpusetCpus'] = cpuset_cpus
if cpuset_mems:
data['CpusetMems'] = cpuset_mems
if mem_limit:
data['Memory'] = utils.parse_bytes(mem_limit)
if mem_reservation:
data['MemoryReservation'] = utils.parse_bytes(mem_reservation)
if memswap_limit:
data['MemorySwap'] = utils.parse_bytes(memswap_limit)
if kernel_memory:
data['KernelMemory'] = utils.parse_bytes(kernel_memory)
resources = self.create_resources(
blkio_weight=blkio_weight, cpu_period=cpu_period,
cpu_shares=cpu_shares, cpu_quota=cpu_quota,
cpuset_cpus=cpuset_cpus, cpuset_mems=cpuset_mems,
mem_limit=mem_limit, mem_reservation=mem_reservation,
memswap_limit=memswap_limit, kernel_memory=kernel_memory
)
return self.update_container_from_resources(
container, resources, restart_policy
)
@utils.minimum_version('1.22')
@utils.check_resource('container')
def update_container_from_resources(self, container, resources,
restart_policy):
u = self._url('/containers/{0}/update', container)
data = resources.copy()
if restart_policy:
if utils.version_lt(self._version, '1.23'):
raise errors.InvalidVersion(
@ -1306,8 +1390,7 @@ class ContainerApiMixin:
'for API version < 1.23'
)
data['RestartPolicy'] = restart_policy
res = self._post_json(url, data=data)
res = self._post_json(u, data=data)
return self._result(res, True)
@utils.check_resource('container')

View File

@ -9,6 +9,7 @@ from ..errors import (
NotFound, create_unexpected_kwargs_error
)
from ..types import HostConfig
from ..types import HostResources
from ..utils import version_gte
from .images import Image
from .resource import Collection, Model
@ -469,18 +470,66 @@ class Container(Model):
Update resource configuration of the containers.
Args:
blkio_weight (int): Block IO (relative weight), between 10 and 1000
cpu_period (int): Limit CPU CFS (Completely Fair Scheduler) period
cpu_quota (int): Limit CPU CFS (Completely Fair Scheduler) quota
cpu_shares (int): CPU shares (relative weight)
cpuset_cpus (str): CPUs in which to allow execution
cpuset_mems (str): MEMs in which to allow execution
mem_limit (int or str): Memory limit
mem_reservation (int or str): Memory soft limit
memswap_limit (int or str): Total memory (memory + swap), -1 to
disable swap
blkio_weight_device: Block IO weight (relative device weight) in
the form of: ``[{"Path": "device_path", "Weight": weight}]``.
blkio_weight: Block IO weight (relative weight), accepts a weight
value between 10 and 1000.
cgroup_parent (string): Path to `cgroups` under which the
container's `cgroup` is created. If the path is not absolute,
the path is considered to be relative to the `cgroups` path of
the init process. Cgroups are created if they do not already
exist.
cpu_period (int): The length of a CPU period in microseconds.
cpu_quota (int): Microseconds of CPU time that the container can
get in a CPU period.
cpu_rt_period (int): The length of a CPU real-time period in
microseconds. Set to 0 to allocate no time allocated to
real-time tasks.
cpu_rt_runtime (int): The length of a CPU real-time runtime in
microseconds. Set to 0 to allocate no time allocated to
real-time tasks.
cpu_shares (int): CPU shares (relative weight).
cpuset_cpus (str): CPUs in which to allow execution (``0-3``,
``0,1``).
cpuset_mems (str): Memory nodes (MEMs) in which to allow execution
(``0-3``, ``0,1``). Only effective on NUMA systems.
device_cgroup_rules (:py:class:`list`): A list of cgroup rules to
apply to the container.
device_read_bps: Limit read rate (bytes per second) from a device
in the form of: `[{"Path": "device_path", "Rate": rate}]`
device_read_iops: Limit read rate (IO per second) from a device.
device_write_bps: Limit write rate (bytes per second) from a
device.
device_write_iops: Limit write rate (IO per second) from a device.
devices (:py:class:`list`): Expose host devices to the container,
as a list of strings in the form
``<path_on_host>:<path_in_container>:<cgroup_permissions>``.
For example, ``/dev/sda:/dev/xvda:rwm`` allows the container
to have read-write access to the host's ``/dev/sda`` via a
node named ``/dev/xvda`` inside the container.
device_requests (:py:class:`list`): Expose host resources such as
GPUs to the container, as a list of
:py:class:`docker.types.DeviceRequest` instances.
kernel_memory (int or str): Kernel memory limit
mem_limit (float or str): Memory limit. Accepts float values
(which represent the memory limit of the created container in
bytes) or a string with a units identification char
(``100000b``, ``1000k``, ``128m``, ``1g``). If a string is
specified without a units character, bytes are assumed as an
mem_reservation (float or str): Memory soft limit.
mem_swappiness (int): Tune a container's memory swappiness
behavior. Accepts number between 0 and 100.
memswap_limit (str or int): Maximum amount of memory + swap a
container is allowed to consume.
nano_cpus (int): CPU quota in units of 10<sup>-9</sup> CPUs.
oom_kill_disable (bool): Whether to disable OOM killer.
pids_limit (int): Tune a container's pids limit. Set ``-1`` for
unlimited.
restart_policy (dict): Restart policy dictionary
ulimits (:py:class:`list`): Ulimits to set inside the container,
as a list of :py:class:`docker.types.Ulimit` instances.
Returns:
(dict): Dictionary containing a ``Warnings`` key.
@ -489,7 +538,14 @@ class Container(Model):
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
return self.client.api.update_container(self.id, **kwargs)
resources_kwargs = copy.copy(kwargs)
resources_kwargs.pop("restart_policy", None)
resources_kwargs['version'] = self.client.api._version
return self.client.api.update_container_from_resources(
self.id, resources=HostResources(**resources_kwargs),
restart_policy=kwargs.get("restart_policy", None)
)
def wait(self, **kwargs):
"""

View File

@ -1,5 +1,6 @@
from .containers import (
ContainerConfig, HostConfig, LogConfig, Ulimit, DeviceRequest
ContainerConfig, HostConfig, HostResources, LogConfig, Ulimit,
DeviceRequest
)
from .daemon import CancellableStream
from .healthcheck import Healthcheck

View File

@ -253,27 +253,17 @@ class DeviceRequest(DictType):
self['Options'] = value
class HostConfig(dict):
def __init__(self, version, binds=None, port_bindings=None,
lxc_conf=None, publish_all_ports=False, links=None,
privileged=False, dns=None, dns_search=None,
volumes_from=None, network_mode=None, restart_policy=None,
cap_add=None, cap_drop=None, devices=None, extra_hosts=None,
read_only=None, pid_mode=None, ipc_mode=None,
security_opt=None, ulimits=None, log_config=None,
class HostResources(dict):
def __init__(self, version, devices=None, ulimits=None,
mem_limit=None, memswap_limit=None, mem_reservation=None,
kernel_memory=None, mem_swappiness=None, cgroup_parent=None,
group_add=None, cpu_quota=None, cpu_period=None,
cpu_quota=None, cpu_period=None,
blkio_weight=None, blkio_weight_device=None,
device_read_bps=None, device_write_bps=None,
device_read_iops=None, device_write_iops=None,
oom_kill_disable=False, shm_size=None, sysctls=None,
tmpfs=None, oom_score_adj=None, dns_opt=None, cpu_shares=None,
cpuset_cpus=None, userns_mode=None, uts_mode=None,
pids_limit=None, isolation=None, auto_remove=False,
storage_opt=None, init=None, init_path=None,
volume_driver=None, cpu_count=None, cpu_percent=None,
nano_cpus=None, cpuset_mems=None, runtime=None, mounts=None,
oom_kill_disable=False, cpu_shares=None,
cpuset_cpus=None, pids_limit=None, cpu_count=None,
cpu_percent=None, nano_cpus=None, cpuset_mems=None,
cpu_rt_period=None, cpu_rt_runtime=None,
device_cgroup_rules=None, device_requests=None,
cgroupns=None):
@ -298,121 +288,12 @@ class HostConfig(dict):
self['MemorySwappiness'] = mem_swappiness
if shm_size is not None:
if isinstance(shm_size, str):
shm_size = parse_bytes(shm_size)
self['ShmSize'] = shm_size
if pid_mode:
if version_lt(version, '1.24') and pid_mode != 'host':
raise host_config_value_error('pid_mode', pid_mode)
self['PidMode'] = pid_mode
if ipc_mode:
self['IpcMode'] = ipc_mode
if privileged:
self['Privileged'] = privileged
if oom_kill_disable:
self['OomKillDisable'] = oom_kill_disable
if oom_score_adj:
if version_lt(version, '1.22'):
raise host_config_version_error('oom_score_adj', '1.22')
if not isinstance(oom_score_adj, int):
raise host_config_type_error(
'oom_score_adj', oom_score_adj, 'int'
)
self['OomScoreAdj'] = oom_score_adj
if publish_all_ports:
self['PublishAllPorts'] = publish_all_ports
if read_only is not None:
self['ReadonlyRootfs'] = read_only
if dns_search:
self['DnsSearch'] = dns_search
if network_mode == 'host' and port_bindings:
raise host_config_incompatible_error(
'network_mode', 'host', 'port_bindings'
)
self['NetworkMode'] = network_mode or 'default'
if restart_policy:
if not isinstance(restart_policy, dict):
raise host_config_type_error(
'restart_policy', restart_policy, 'dict'
)
self['RestartPolicy'] = restart_policy
if cap_add:
self['CapAdd'] = cap_add
if cap_drop:
self['CapDrop'] = cap_drop
if devices:
self['Devices'] = parse_devices(devices)
if group_add:
self['GroupAdd'] = [str(grp) for grp in group_add]
if dns is not None:
self['Dns'] = dns
if dns_opt is not None:
self['DnsOptions'] = dns_opt
if security_opt is not None:
if not isinstance(security_opt, list):
raise host_config_type_error(
'security_opt', security_opt, 'list'
)
self['SecurityOpt'] = security_opt
if sysctls:
if not isinstance(sysctls, dict):
raise host_config_type_error('sysctls', sysctls, 'dict')
self['Sysctls'] = {}
for k, v in sysctls.items():
self['Sysctls'][k] = str(v)
if volumes_from is not None:
if isinstance(volumes_from, str):
volumes_from = volumes_from.split(',')
self['VolumesFrom'] = volumes_from
if binds is not None:
self['Binds'] = convert_volume_binds(binds)
if port_bindings is not None:
self['PortBindings'] = convert_port_bindings(port_bindings)
if extra_hosts is not None:
if isinstance(extra_hosts, dict):
extra_hosts = format_extra_hosts(extra_hosts)
self['ExtraHosts'] = extra_hosts
if links is not None:
self['Links'] = normalize_links(links)
if isinstance(lxc_conf, dict):
formatted = []
for k, v in lxc_conf.items():
formatted.append({'Key': k, 'Value': str(v)})
lxc_conf = formatted
if lxc_conf is not None:
self['LxcConf'] = lxc_conf
if cgroup_parent is not None:
self['CgroupParent'] = cgroup_parent
@ -425,16 +306,6 @@ class HostConfig(dict):
lmt = Ulimit(**lmt)
self['Ulimits'].append(lmt)
if log_config is not None:
if not isinstance(log_config, LogConfig):
if not isinstance(log_config, dict):
raise host_config_type_error(
'log_config', log_config, 'LogConfig'
)
log_config = LogConfig(**log_config)
self['LogConfig'] = log_config
if cpu_quota:
if not isinstance(cpu_quota, int):
raise host_config_type_error('cpu_quota', cpu_quota, 'int')
@ -535,6 +406,224 @@ class HostConfig(dict):
raise host_config_version_error('device_write_iops', '1.22')
self["BlkioDeviceWriteIOps"] = device_write_iops
if pids_limit:
if not isinstance(pids_limit, int):
raise host_config_type_error('pids_limit', pids_limit, 'int')
if version_lt(version, '1.23'):
raise host_config_version_error('pids_limit', '1.23')
self["PidsLimit"] = pids_limit
if cpu_count:
if not isinstance(cpu_count, int):
raise host_config_type_error('cpu_count', cpu_count, 'int')
if version_lt(version, '1.25'):
raise host_config_version_error('cpu_count', '1.25')
self['CpuCount'] = cpu_count
if cpu_percent:
if not isinstance(cpu_percent, int):
raise host_config_type_error('cpu_percent', cpu_percent, 'int')
if version_lt(version, '1.25'):
raise host_config_version_error('cpu_percent', '1.25')
self['CpuPercent'] = cpu_percent
if nano_cpus:
if not isinstance(nano_cpus, int):
raise host_config_type_error('nano_cpus', nano_cpus, 'int')
if version_lt(version, '1.25'):
raise host_config_version_error('nano_cpus', '1.25')
self['NanoCpus'] = nano_cpus
if device_cgroup_rules is not None:
if version_lt(version, '1.28'):
raise host_config_version_error('device_cgroup_rules', '1.28')
if not isinstance(device_cgroup_rules, list):
raise host_config_type_error(
'device_cgroup_rules', device_cgroup_rules, 'list'
)
self['DeviceCgroupRules'] = device_cgroup_rules
if device_requests is not None:
if version_lt(version, '1.40'):
raise host_config_version_error('device_requests', '1.40')
if not isinstance(device_requests, list):
raise host_config_type_error(
'device_requests', device_requests, 'list'
)
self['DeviceRequests'] = []
for req in device_requests:
if not isinstance(req, DeviceRequest):
req = DeviceRequest(**req)
self['DeviceRequests'].append(req)
if cgroupns:
self['CgroupnsMode'] = cgroupns
class HostConfig(HostResources):
def __init__(self, version, binds=None, port_bindings=None,
lxc_conf=None, publish_all_ports=False, links=None,
privileged=False, dns=None, dns_search=None,
volumes_from=None, network_mode=None, restart_policy=None,
cap_add=None, cap_drop=None, devices=None, extra_hosts=None,
read_only=None, pid_mode=None, ipc_mode=None,
security_opt=None, ulimits=None, log_config=None,
mem_limit=None, memswap_limit=None, mem_reservation=None,
kernel_memory=None, mem_swappiness=None, cgroup_parent=None,
group_add=None, cpu_quota=None, cpu_period=None,
blkio_weight=None, blkio_weight_device=None,
device_read_bps=None, device_write_bps=None,
device_read_iops=None, device_write_iops=None,
oom_kill_disable=False, shm_size=None, sysctls=None,
tmpfs=None, oom_score_adj=None, dns_opt=None, cpu_shares=None,
cpuset_cpus=None, userns_mode=None, uts_mode=None,
pids_limit=None, isolation=None, auto_remove=False,
storage_opt=None, init=None, init_path=None,
volume_driver=None, cpu_count=None, cpu_percent=None,
nano_cpus=None, cpuset_mems=None, runtime=None, mounts=None,
cpu_rt_period=None, cpu_rt_runtime=None,
device_cgroup_rules=None, device_requests=None,
cgroupns=None):
super(HostConfig, self).__init__(
version, devices=devices, ulimits=ulimits,
mem_limit=mem_limit, memswap_limit=memswap_limit,
mem_reservation=mem_reservation, kernel_memory=kernel_memory,
mem_swappiness=mem_swappiness, cgroup_parent=cgroup_parent,
cpu_quota=cpu_quota, cpu_period=cpu_period,
blkio_weight=blkio_weight, blkio_weight_device=blkio_weight_device,
device_read_bps=device_read_bps, device_write_bps=device_write_bps,
device_read_iops=device_read_iops,
device_write_iops=device_write_iops,
oom_kill_disable=oom_kill_disable, cpu_shares=cpu_shares,
cpuset_cpus=cpuset_cpus, pids_limit=pids_limit,
cpu_count=cpu_count, cpu_percent=cpu_percent,
nano_cpus=nano_cpus, cpuset_mems=cpuset_mems,
cpu_rt_period=cpu_rt_period, cpu_rt_runtime=cpu_rt_runtime,
device_cgroup_rules=device_cgroup_rules,
device_requests=device_requests, cgroupns=cgroupns)
if shm_size is not None:
if isinstance(shm_size, str):
shm_size = parse_bytes(shm_size)
self['ShmSize'] = shm_size
if pid_mode:
if version_lt(version, '1.24') and pid_mode != 'host':
raise host_config_value_error('pid_mode', pid_mode)
self['PidMode'] = pid_mode
if ipc_mode:
self['IpcMode'] = ipc_mode
if privileged:
self['Privileged'] = privileged
if oom_score_adj:
if version_lt(version, '1.22'):
raise host_config_version_error('oom_score_adj', '1.22')
if not isinstance(oom_score_adj, int):
raise host_config_type_error(
'oom_score_adj', oom_score_adj, 'int'
)
self['OomScoreAdj'] = oom_score_adj
if publish_all_ports:
self['PublishAllPorts'] = publish_all_ports
if read_only is not None:
self['ReadonlyRootfs'] = read_only
if dns_search:
self['DnsSearch'] = dns_search
if network_mode == 'host' and port_bindings:
raise host_config_incompatible_error(
'network_mode', 'host', 'port_bindings'
)
self['NetworkMode'] = network_mode or 'default'
if restart_policy:
if not isinstance(restart_policy, dict):
raise host_config_type_error(
'restart_policy', restart_policy, 'dict'
)
self['RestartPolicy'] = restart_policy
if cap_add:
self['CapAdd'] = cap_add
if cap_drop:
self['CapDrop'] = cap_drop
if group_add:
self['GroupAdd'] = [str(grp) for grp in group_add]
if dns is not None:
self['Dns'] = dns
if dns_opt is not None:
self['DnsOptions'] = dns_opt
if security_opt is not None:
if not isinstance(security_opt, list):
raise host_config_type_error(
'security_opt', security_opt, 'list'
)
self['SecurityOpt'] = security_opt
if sysctls:
if not isinstance(sysctls, dict):
raise host_config_type_error('sysctls', sysctls, 'dict')
self['Sysctls'] = {}
for k, v in sysctls.items():
self['Sysctls'][k] = str(v)
if volumes_from is not None:
if isinstance(volumes_from, str):
volumes_from = volumes_from.split(',')
self['VolumesFrom'] = volumes_from
if binds is not None:
self['Binds'] = convert_volume_binds(binds)
if port_bindings is not None:
self['PortBindings'] = convert_port_bindings(port_bindings)
if extra_hosts is not None:
if isinstance(extra_hosts, dict):
extra_hosts = format_extra_hosts(extra_hosts)
self['ExtraHosts'] = extra_hosts
if links is not None:
self['Links'] = normalize_links(links)
if isinstance(lxc_conf, dict):
formatted = []
for k, v in lxc_conf.items():
formatted.append({'Key': k, 'Value': str(v)})
lxc_conf = formatted
if lxc_conf is not None:
self['LxcConf'] = lxc_conf
if log_config is not None:
if not isinstance(log_config, LogConfig):
if not isinstance(log_config, dict):
raise host_config_type_error(
'log_config', log_config, 'LogConfig'
)
log_config = LogConfig(**log_config)
self['LogConfig'] = log_config
if tmpfs:
if version_lt(version, '1.22'):
raise host_config_version_error('tmpfs', '1.22')
@ -553,13 +642,6 @@ class HostConfig(dict):
raise host_config_value_error("uts_mode", uts_mode)
self['UTSMode'] = uts_mode
if pids_limit:
if not isinstance(pids_limit, int):
raise host_config_type_error('pids_limit', pids_limit, 'int')
if version_lt(version, '1.23'):
raise host_config_version_error('pids_limit', '1.23')
self["PidsLimit"] = pids_limit
if isolation:
if not isinstance(isolation, str):
raise host_config_type_error('isolation', isolation, 'string')
@ -594,30 +676,6 @@ class HostConfig(dict):
if volume_driver is not None:
self['VolumeDriver'] = volume_driver
if cpu_count:
if not isinstance(cpu_count, int):
raise host_config_type_error('cpu_count', cpu_count, 'int')
if version_lt(version, '1.25'):
raise host_config_version_error('cpu_count', '1.25')
self['CpuCount'] = cpu_count
if cpu_percent:
if not isinstance(cpu_percent, int):
raise host_config_type_error('cpu_percent', cpu_percent, 'int')
if version_lt(version, '1.25'):
raise host_config_version_error('cpu_percent', '1.25')
self['CpuPercent'] = cpu_percent
if nano_cpus:
if not isinstance(nano_cpus, int):
raise host_config_type_error('nano_cpus', nano_cpus, 'int')
if version_lt(version, '1.25'):
raise host_config_version_error('nano_cpus', '1.25')
self['NanoCpus'] = nano_cpus
if runtime:
if version_lt(version, '1.25'):
raise host_config_version_error('runtime', '1.25')
@ -628,31 +686,6 @@ class HostConfig(dict):
raise host_config_version_error('mounts', '1.30')
self['Mounts'] = mounts
if device_cgroup_rules is not None:
if version_lt(version, '1.28'):
raise host_config_version_error('device_cgroup_rules', '1.28')
if not isinstance(device_cgroup_rules, list):
raise host_config_type_error(
'device_cgroup_rules', device_cgroup_rules, 'list'
)
self['DeviceCgroupRules'] = device_cgroup_rules
if device_requests is not None:
if version_lt(version, '1.40'):
raise host_config_version_error('device_requests', '1.40')
if not isinstance(device_requests, list):
raise host_config_type_error(
'device_requests', device_requests, 'list'
)
self['DeviceRequests'] = []
for req in device_requests:
if not isinstance(req, DeviceRequest):
req = DeviceRequest(**req)
self['DeviceRequests'].append(req)
if cgroupns:
self['CgroupnsMode'] = cgroupns
def host_config_type_error(param, param_value, expected):
return TypeError(

View File

@ -434,6 +434,20 @@ class ContainerTest(BaseIntegrationTest):
container.reload()
assert container.attrs['HostConfig']['CpuShares'] == 3
def test_update_device_cgroup_rules(self):
client = docker.from_env(version=TEST_API_VERSION)
container = client.containers.run("alpine", "sleep 60", detach=True,
device_cgroup_rules=["c 13:* rwm"])
self.tmp_containers.append(container.id)
device_cgrp_rules = container.attrs['HostConfig']['DeviceCgroupRules']
assert len(device_cgrp_rules) == 1
assert device_cgrp_rules[0] == "c 13:* rwm"
container.update(device_cgroup_rules=["c 13:* rw"])
container.reload()
device_cgrp_rules_new = container.attrs['HostConfig']['DeviceCgroupRules']
assert len(device_cgrp_rules_new) == 1
assert device_cgrp_rules_new[0] == "c 13:* rw"
def test_wait(self):
client = docker.from_env(version=TEST_API_VERSION)
container = client.containers.run("alpine", "sh -c 'exit 0'",

View File

@ -664,8 +664,11 @@ class ContainerTest(unittest.TestCase):
client = make_fake_client()
container = client.containers.get(FAKE_CONTAINER_ID)
container.update(cpu_shares=2)
client.api.update_container.assert_called_with(FAKE_CONTAINER_ID,
cpu_shares=2)
client.api.update_container_from_resources.assert_called_with(
FAKE_CONTAINER_ID,
resources={'CpuShares': 2},
restart_policy=None
)
def test_wait(self):
client = make_fake_client()