diff options
Diffstat (limited to 'docker/api/container.py')
-rw-r--r-- | docker/api/container.py | 192 |
1 files changed, 121 insertions, 71 deletions
diff --git a/docker/api/container.py b/docker/api/container.py index d4f75f5..83fcd4f 100644 --- a/docker/api/container.py +++ b/docker/api/container.py @@ -1,19 +1,19 @@ -import six from datetime import datetime from .. import errors from .. import utils from ..constants import DEFAULT_DATA_CHUNK_SIZE -from ..types import ( - CancellableStream, ContainerConfig, EndpointConfig, HostConfig, - NetworkingConfig -) +from ..types import CancellableStream +from ..types import ContainerConfig +from ..types import EndpointConfig +from ..types import HostConfig +from ..types import NetworkingConfig -class ContainerApiMixin(object): +class ContainerApiMixin: @utils.check_resource('container') def attach(self, container, stdout=True, stderr=True, - stream=False, logs=False): + stream=False, logs=False, demux=False): """ Attach to a container. @@ -28,11 +28,15 @@ class ContainerApiMixin(object): stream (bool): Return container output progressively as an iterator of strings, rather than a single string. logs (bool): Include the container's previous output. + demux (bool): Keep stdout and stderr separate. Returns: - By default, the container's output as a single string. + By default, the container's output as a single string (two if + ``demux=True``: one for stdout and one for stderr). - If ``stream=True``, an iterator of output strings. + If ``stream=True``, an iterator of output strings. If + ``demux=True``, two iterators are returned: one for stdout and one + for stderr. Raises: :py:class:`docker.errors.APIError` @@ -54,8 +58,7 @@ class ContainerApiMixin(object): response = self._post(u, headers=headers, params=params, stream=True) output = self._read_from_socket( - response, stream, self._check_is_tty(container) - ) + response, stream, self._check_is_tty(container), demux=demux) if stream: return CancellableStream(output, response) @@ -169,7 +172,8 @@ class ContainerApiMixin(object): - `exited` (int): Only containers with specified exit code - `status` (str): One of ``restarting``, ``running``, ``paused``, ``exited`` - - `label` (str): format either ``"key"`` or ``"key=value"`` + - `label` (str|list): format either ``"key"``, ``"key=value"`` + or a list of such. - `id` (str): The id of the container. - `name` (str): The name of the container. - `ancestor` (str): Filter by container ancestor. Format of @@ -218,7 +222,8 @@ class ContainerApiMixin(object): working_dir=None, domainname=None, host_config=None, mac_address=None, labels=None, stop_signal=None, networking_config=None, healthcheck=None, - stop_timeout=None, runtime=None): + stop_timeout=None, runtime=None, + use_config_proxy=True): """ Creates a container. Parameters are similar to those for the ``docker run`` command except it doesn't support the attach options (``-a``). @@ -237,9 +242,9 @@ class ContainerApiMixin(object): .. code-block:: python - container_id = cli.create_container( + container_id = client.api.create_container( 'busybox', 'ls', ports=[1111, 2222], - host_config=cli.create_host_config(port_bindings={ + host_config=client.api.create_host_config(port_bindings={ 1111: 4567, 2222: None }) @@ -251,22 +256,22 @@ class ContainerApiMixin(object): .. code-block:: python - cli.create_host_config(port_bindings={1111: ('127.0.0.1', 4567)}) + client.api.create_host_config(port_bindings={1111: ('127.0.0.1', 4567)}) Or without host port assignment: .. code-block:: python - cli.create_host_config(port_bindings={1111: ('127.0.0.1',)}) + client.api.create_host_config(port_bindings={1111: ('127.0.0.1',)}) If you wish to use UDP instead of TCP (default), you need to declare ports as such in both the config and host config: .. code-block:: python - container_id = cli.create_container( + container_id = client.api.create_container( 'busybox', 'ls', ports=[(1111, 'udp'), 2222], - host_config=cli.create_host_config(port_bindings={ + host_config=client.api.create_host_config(port_bindings={ '1111/udp': 4567, 2222: None }) ) @@ -276,7 +281,7 @@ class ContainerApiMixin(object): .. code-block:: python - cli.create_host_config(port_bindings={ + client.api.create_host_config(port_bindings={ 1111: [1234, 4567] }) @@ -284,7 +289,7 @@ class ContainerApiMixin(object): .. code-block:: python - cli.create_host_config(port_bindings={ + client.api.create_host_config(port_bindings={ 1111: [ ('192.168.0.100', 1234), ('192.168.0.101', 1234) @@ -300,9 +305,9 @@ class ContainerApiMixin(object): .. code-block:: python - container_id = cli.create_container( + container_id = client.api.create_container( 'busybox', 'ls', volumes=['/mnt/vol1', '/mnt/vol2'], - host_config=cli.create_host_config(binds={ + host_config=client.api.create_host_config(binds={ '/home/user1/': { 'bind': '/mnt/vol2', 'mode': 'rw', @@ -319,9 +324,9 @@ class ContainerApiMixin(object): .. code-block:: python - container_id = cli.create_container( + container_id = client.api.create_container( 'busybox', 'ls', volumes=['/mnt/vol1', '/mnt/vol2'], - host_config=cli.create_host_config(binds=[ + host_config=client.api.create_host_config(binds=[ '/home/user1/:/mnt/vol2', '/var/www:/mnt/vol1:ro', ]) @@ -339,15 +344,15 @@ class ContainerApiMixin(object): .. code-block:: python - networking_config = docker_client.create_networking_config({ - 'network1': docker_client.create_endpoint_config( + networking_config = client.api.create_networking_config({ + 'network1': client.api.create_endpoint_config( ipv4_address='172.28.0.124', aliases=['foo', 'bar'], links=['container2'] ) }) - ctnr = docker_client.create_container( + ctnr = client.api.create_container( img, command, networking_config=networking_config ) @@ -387,6 +392,10 @@ class ContainerApiMixin(object): runtime (str): Runtime to use with this container. healthcheck (dict): Specify a test to perform to check that the container is healthy. + use_config_proxy (bool): If ``True``, and if the docker client + configuration file (``~/.docker/config.json`` by default) + contains a proxy configuration, the corresponding environment + variables will be set in the container being created. Returns: A dictionary with an image 'Id' key and a 'Warnings' key. @@ -397,9 +406,17 @@ class ContainerApiMixin(object): :py:class:`docker.errors.APIError` If the server returns an error. """ - if isinstance(volumes, six.string_types): + if isinstance(volumes, str): volumes = [volumes, ] + if isinstance(environment, dict): + environment = utils.utils.format_environment(environment) + + if use_config_proxy: + environment = self._proxy_configs.inject_proxy_environment( + environment + ) or None + config = self.create_container_config( image, command, hostname, user, detach, stdin_open, tty, ports, environment, volumes, @@ -461,34 +478,33 @@ class ContainerApiMixin(object): 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. dns (:py:class:`list`): Set custom DNS servers. dns_opt (:py:class:`list`): Additional options to be added to the container's ``resolv.conf`` file dns_search (:py:class:`list`): DNS search domains. - extra_hosts (dict): Addtional hostnames to resolve inside the + extra_hosts (dict): Additional hostnames to resolve inside the container, as a mapping of hostname to IP address. group_add (:py:class:`list`): List of additional group names and/or IDs that the container process will run as. init (bool): Run an init inside the container that forwards signals and reaps processes - init_path (str): Path to the docker-init binary ipc_mode (str): Set the IPC mode for the container. - isolation (str): Isolation technology to use. Default: `None`. - links (dict or list of tuples): Either a dictionary mapping name - to alias or as a list of ``(name, alias)`` tuples. - log_config (dict): Logging configuration, as a dictionary with - keys: - - - ``type`` The logging driver name. - - ``config`` A dictionary of configuration for the logging - driver. - + isolation (str): Isolation technology to use. Default: ``None``. + links (dict): Mapping of links using the + ``{'container': 'alias'}`` format. The alias is optional. + Containers declared in this dict will be linked to the new + container using the provided alias. Default: ``None``. + log_config (LogConfig): Logging configuration lxc_conf (dict): LXC config. 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 @@ -500,11 +516,13 @@ class ContainerApiMixin(object): network_mode (str): One of: - ``bridge`` Create a new network stack for the container on - on the bridge network. + the bridge network. - ``none`` No networking for this container. - ``container:<name|id>`` Reuse another container's network stack. - ``host`` Use the host network stack. + This mode is incompatible with ``port_bindings``. + oom_kill_disable (bool): Whether to disable OOM killer. oom_score_adj (int): An integer value containing the score given to the container in order to tune OOM killer preferences. @@ -513,7 +531,8 @@ class ContainerApiMixin(object): pids_limit (int): Tune a container's pids limit. Set ``-1`` for unlimited. port_bindings (dict): See :py:meth:`create_container` - for more information. + for more information. + Imcompatible with ``host`` in ``network_mode``. privileged (bool): Give extended privileges to this container. publish_all_ports (bool): Publish all ports to the host. read_only (bool): Mount the container's root filesystem as read @@ -543,10 +562,12 @@ class ContainerApiMixin(object): } ulimits (:py:class:`list`): Ulimits to set inside the container, - as a list of dicts. + as a list of :py:class:`docker.types.Ulimit` instances. userns_mode (str): Sets the user namespace mode for the container when user namespace remapping option is enabled. Supported values are: ``host`` + uts_mode (str): Sets the UTS namespace mode for the container. + Supported values are: ``host`` volumes_from (:py:class:`list`): List of container names or IDs to get volumes from. runtime (str): Runtime to use with this container. @@ -558,7 +579,7 @@ class ContainerApiMixin(object): Example: - >>> cli.create_host_config(privileged=True, cap_drop=['MKNOD'], + >>> client.api.create_host_config(privileged=True, cap_drop=['MKNOD'], volumes_from=['nostalgic_newton']) {'CapDrop': ['MKNOD'], 'LxcConf': None, 'Privileged': True, 'VolumesFrom': ['nostalgic_newton'], 'PublishAllPorts': False} @@ -589,11 +610,11 @@ class ContainerApiMixin(object): Example: - >>> docker_client.create_network('network1') - >>> networking_config = docker_client.create_networking_config({ - 'network1': docker_client.create_endpoint_config() + >>> client.api.create_network('network1') + >>> networking_config = client.api.create_networking_config({ + 'network1': client.api.create_endpoint_config() }) - >>> container = docker_client.create_container( + >>> container = client.api.create_container( img, command, networking_config=networking_config ) @@ -609,24 +630,27 @@ class ContainerApiMixin(object): aliases (:py:class:`list`): A list of aliases for this endpoint. Names in that list can be used within the network to reach the container. Defaults to ``None``. - links (:py:class:`list`): A list of links for this endpoint. - Containers declared in this list will be linked to this - container. Defaults to ``None``. + links (dict): Mapping of links for this endpoint using the + ``{'container': 'alias'}`` format. The alias is optional. + Containers declared in this dict will be linked to this + container using the provided alias. Defaults to ``None``. ipv4_address (str): The IP address of this container on the network, using the IPv4 protocol. Defaults to ``None``. ipv6_address (str): The IP address of this container on the network, using the IPv6 protocol. Defaults to ``None``. link_local_ips (:py:class:`list`): A list of link-local (IPv4/IPv6) addresses. + driver_opt (dict): A dictionary of options to provide to the + network driver. Defaults to ``None``. Returns: (dict) An endpoint config. Example: - >>> endpoint_config = client.create_endpoint_config( + >>> endpoint_config = client.api.create_endpoint_config( aliases=['web', 'app'], - links=['app_db'], + links={'app_db': 'db', 'another': None}, ipv4_address='132.65.0.123' ) @@ -676,7 +700,8 @@ class ContainerApiMixin(object): return self._stream_raw_result(res, chunk_size, False) @utils.check_resource('container') - def get_archive(self, container, path, chunk_size=DEFAULT_DATA_CHUNK_SIZE): + def get_archive(self, container, path, chunk_size=DEFAULT_DATA_CHUNK_SIZE, + encode_stream=False): """ Retrieve a file or folder from a container in the form of a tar archive. @@ -687,6 +712,8 @@ class ContainerApiMixin(object): chunk_size (int): The number of bytes returned by each iteration of the generator. If ``None``, data will be streamed as it is received. Default: 2 MB + encode_stream (bool): Determines if data should be encoded + (gzip-compressed) during transmission. Default: False Returns: (tuple): First element is a raw tar data stream. Second element is @@ -695,12 +722,29 @@ class ContainerApiMixin(object): Raises: :py:class:`docker.errors.APIError` If the server returns an error. + + Example: + + >>> c = docker.APIClient() + >>> f = open('./sh_bin.tar', 'wb') + >>> bits, stat = c.api.get_archive(container, '/bin/sh') + >>> print(stat) + {'name': 'sh', 'size': 1075464, 'mode': 493, + 'mtime': '2018-10-01T15:37:48-07:00', 'linkTarget': ''} + >>> for chunk in bits: + ... f.write(chunk) + >>> f.close() """ params = { 'path': path } + headers = { + "Accept-Encoding": "gzip, deflate" + } if encode_stream else { + "Accept-Encoding": "identity" + } url = self._url('/containers/{0}/archive', container) - res = self._get(url, params=params, stream=True) + res = self._get(url, params=params, stream=True, headers=headers) self._raise_for_status(res) encoded_stat = res.headers.get('x-docker-container-path-stat') return ( @@ -744,7 +788,7 @@ class ContainerApiMixin(object): url = self._url("/containers/{0}/kill", container) params = {} if signal is not None: - if not isinstance(signal, six.string_types): + if not isinstance(signal, str): signal = int(signal) params['signal'] = signal res = self._post(url, params=params) @@ -763,16 +807,16 @@ class ContainerApiMixin(object): Args: container (str): The container to get logs from - stdout (bool): Get ``STDOUT`` - stderr (bool): Get ``STDERR`` - stream (bool): Stream the response - timestamps (bool): Show timestamps + stdout (bool): Get ``STDOUT``. Default ``True`` + stderr (bool): Get ``STDERR``. Default ``True`` + stream (bool): Stream the response. Default ``False`` + timestamps (bool): Show timestamps. Default ``False`` tail (str or int): Output specified number of lines at the end of logs. Either an integer of number of lines or the string ``all``. Default ``all`` since (datetime or int): Show logs since a given datetime or integer epoch (in seconds) - follow (bool): Follow log output + follow (bool): Follow log output. Default ``False`` until (datetime or int): Show logs that occurred before the given datetime or integer epoch (in seconds) @@ -870,7 +914,7 @@ class ContainerApiMixin(object): .. code-block:: python - >>> cli.port('7174d6347063', 80) + >>> client.api.port('7174d6347063', 80) [{'HostIp': '0.0.0.0', 'HostPort': '80'}] """ res = self._get(self._url("/containers/{0}/json", container)) @@ -888,9 +932,10 @@ class ContainerApiMixin(object): if '/' in private_port: return port_settings.get(private_port) - h_ports = port_settings.get(private_port + '/tcp') - if h_ports is None: - h_ports = port_settings.get(private_port + '/udp') + for protocol in ['tcp', 'udp', 'sctp']: + h_ports = port_settings.get(private_port + '/' + protocol) + if h_ports: + break return h_ports @@ -1048,10 +1093,10 @@ class ContainerApiMixin(object): Example: - >>> container = cli.create_container( + >>> container = client.api.create_container( ... image='busybox:latest', ... command='/bin/sleep 30') - >>> cli.start(container=container.get('Id')) + >>> client.api.start(container=container.get('Id')) """ if args or kwargs: raise errors.DeprecatedMethod( @@ -1072,7 +1117,8 @@ class ContainerApiMixin(object): Args: container (str): The container to stream statistics from decode (bool): If set to true, stream will be decoded into dicts - on the fly. False by default. + on the fly. Only applicable if ``stream`` is True. + False by default. stream (bool): If set to false, only the current stats will be returned instead of a stream. True by default. @@ -1086,6 +1132,10 @@ class ContainerApiMixin(object): return self._stream_helper(self._get(url, stream=True), decode=decode) else: + if decode: + raise errors.InvalidArgument( + "decode is only available in conjunction with stream=True" + ) return self._result(self._get(url, params={'stream': False}), json=True) @@ -1170,8 +1220,8 @@ class ContainerApiMixin(object): 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 + mem_limit (float or str): Memory limit + mem_reservation (float or str): Memory soft limit memswap_limit (int or str): Total memory (memory + swap), -1 to disable swap kernel_memory (int or str): Kernel memory limit |