Kaydet (Commit) 2ff7371a authored tarafından Aanand Prasad's avatar Aanand Prasad Kaydeden (comit) GitHub

Merge pull request #1294 from aanand/add-healthcheck

Add support for passing healthcheck to create_container
...@@ -115,7 +115,8 @@ class ContainerApiMixin(object): ...@@ -115,7 +115,8 @@ class ContainerApiMixin(object):
cpu_shares=None, working_dir=None, domainname=None, cpu_shares=None, working_dir=None, domainname=None,
memswap_limit=None, cpuset=None, host_config=None, memswap_limit=None, cpuset=None, host_config=None,
mac_address=None, labels=None, volume_driver=None, mac_address=None, labels=None, volume_driver=None,
stop_signal=None, networking_config=None): stop_signal=None, networking_config=None,
healthcheck=None):
if isinstance(volumes, six.string_types): if isinstance(volumes, six.string_types):
volumes = [volumes, ] volumes = [volumes, ]
...@@ -130,7 +131,7 @@ class ContainerApiMixin(object): ...@@ -130,7 +131,7 @@ class ContainerApiMixin(object):
tty, mem_limit, ports, environment, dns, volumes, volumes_from, tty, mem_limit, ports, environment, dns, volumes, volumes_from,
network_disabled, entrypoint, cpu_shares, working_dir, domainname, network_disabled, entrypoint, cpu_shares, working_dir, domainname,
memswap_limit, cpuset, host_config, mac_address, labels, memswap_limit, cpuset, host_config, mac_address, labels,
volume_driver, stop_signal, networking_config, volume_driver, stop_signal, networking_config, healthcheck,
) )
return self.create_container_from_config(config, name) return self.create_container_from_config(config, name)
...@@ -365,7 +366,7 @@ class ContainerApiMixin(object): ...@@ -365,7 +366,7 @@ class ContainerApiMixin(object):
cap_drop=cap_drop, volumes_from=volumes_from, devices=devices, cap_drop=cap_drop, volumes_from=volumes_from, devices=devices,
network_mode=network_mode, restart_policy=restart_policy, network_mode=network_mode, restart_policy=restart_policy,
extra_hosts=extra_hosts, read_only=read_only, pid_mode=pid_mode, extra_hosts=extra_hosts, read_only=read_only, pid_mode=pid_mode,
ipc_mode=ipc_mode, security_opt=security_opt, ulimits=ulimits ipc_mode=ipc_mode, security_opt=security_opt, ulimits=ulimits,
) )
start_config = None start_config = None
......
...@@ -4,4 +4,5 @@ from .services import ( ...@@ -4,4 +4,5 @@ from .services import (
ContainerSpec, DriverConfig, EndpointSpec, Mount, Resources, RestartPolicy, ContainerSpec, DriverConfig, EndpointSpec, Mount, Resources, RestartPolicy,
TaskTemplate, UpdateConfig TaskTemplate, UpdateConfig
) )
from .healthcheck import Healthcheck
from .swarm import SwarmSpec, SwarmExternalCA from .swarm import SwarmSpec, SwarmExternalCA
from .base import DictType
import six
class Healthcheck(DictType):
def __init__(self, **kwargs):
test = kwargs.get('test', kwargs.get('Test'))
if isinstance(test, six.string_types):
test = ["CMD-SHELL", test]
interval = kwargs.get('interval', kwargs.get('Interval'))
timeout = kwargs.get('timeout', kwargs.get('Timeout'))
retries = kwargs.get('retries', kwargs.get('Retries'))
super(Healthcheck, self).__init__({
'Test': test,
'Interval': interval,
'Timeout': timeout,
'Retries': retries
})
@property
def test(self):
return self['Test']
@test.setter
def test(self, value):
self['Test'] = value
@property
def interval(self):
return self['Interval']
@interval.setter
def interval(self, value):
self['Interval'] = value
@property
def timeout(self):
return self['Timeout']
@timeout.setter
def timeout(self, value):
self['Timeout'] = value
@property
def retries(self):
return self['Retries']
@retries.setter
def retries(self, value):
self['Retries'] = value
...@@ -18,7 +18,7 @@ import six ...@@ -18,7 +18,7 @@ import six
from .. import constants from .. import constants
from .. import errors from .. import errors
from .. import tls from .. import tls
from ..types import Ulimit, LogConfig from ..types import Ulimit, LogConfig, Healthcheck
if six.PY2: if six.PY2:
from urllib import splitnport from urllib import splitnport
...@@ -1029,6 +1029,7 @@ def create_container_config( ...@@ -1029,6 +1029,7 @@ def create_container_config(
entrypoint=None, cpu_shares=None, working_dir=None, domainname=None, entrypoint=None, cpu_shares=None, working_dir=None, domainname=None,
memswap_limit=None, cpuset=None, host_config=None, mac_address=None, memswap_limit=None, cpuset=None, host_config=None, mac_address=None,
labels=None, volume_driver=None, stop_signal=None, networking_config=None, labels=None, volume_driver=None, stop_signal=None, networking_config=None,
healthcheck=None,
): ):
if isinstance(command, six.string_types): if isinstance(command, six.string_types):
command = split_command(command) command = split_command(command)
...@@ -1057,6 +1058,11 @@ def create_container_config( ...@@ -1057,6 +1058,11 @@ def create_container_config(
'stop_signal was only introduced in API version 1.21' 'stop_signal was only introduced in API version 1.21'
) )
if healthcheck is not None and version_lt(version, '1.24'):
raise errors.InvalidVersion(
'Health options were only introduced in API version 1.24'
)
if compare_version('1.19', version) < 0: if compare_version('1.19', version) < 0:
if volume_driver is not None: if volume_driver is not None:
raise errors.InvalidVersion( raise errors.InvalidVersion(
...@@ -1113,6 +1119,9 @@ def create_container_config( ...@@ -1113,6 +1119,9 @@ def create_container_config(
# Force None, an empty list or dict causes client.start to fail # Force None, an empty list or dict causes client.start to fail
volumes_from = None volumes_from = None
if healthcheck and isinstance(healthcheck, dict):
healthcheck = Healthcheck(**healthcheck)
attach_stdin = False attach_stdin = False
attach_stdout = False attach_stdout = False
attach_stderr = False attach_stderr = False
...@@ -1164,5 +1173,6 @@ def create_container_config( ...@@ -1164,5 +1173,6 @@ def create_container_config(
'MacAddress': mac_address, 'MacAddress': mac_address,
'Labels': labels, 'Labels': labels,
'VolumeDriver': volume_driver, 'VolumeDriver': volume_driver,
'StopSignal': stop_signal 'StopSignal': stop_signal,
'Healthcheck': healthcheck,
} }
...@@ -2,6 +2,7 @@ import os ...@@ -2,6 +2,7 @@ import os
import os.path import os.path
import tarfile import tarfile
import tempfile import tempfile
import time
import docker import docker
import pytest import pytest
...@@ -47,3 +48,11 @@ def requires_api_version(version): ...@@ -47,3 +48,11 @@ def requires_api_version(version):
), ),
reason="API version is too low (< {0})".format(version) reason="API version is too low (< {0})".format(version)
) )
def wait_on_condition(condition, delay=0.1, timeout=40):
start_time = time.time()
while not condition():
if time.time() - start_time > timeout:
raise AssertionError("Timeout: %s" % condition)
time.sleep(delay)
from .base import BaseIntegrationTest
from .base import BUSYBOX
from .. import helpers
SECOND = 1000000000
def wait_on_health_status(client, container, status):
def condition():
res = client.inspect_container(container)
return res['State']['Health']['Status'] == status
return helpers.wait_on_condition(condition)
class HealthcheckTest(BaseIntegrationTest):
@helpers.requires_api_version('1.24')
def test_healthcheck_shell_command(self):
container = self.client.create_container(
BUSYBOX, 'top', healthcheck=dict(test='echo "hello world"'))
self.tmp_containers.append(container)
res = self.client.inspect_container(container)
assert res['Config']['Healthcheck']['Test'] == \
['CMD-SHELL', 'echo "hello world"']
@helpers.requires_api_version('1.24')
def test_healthcheck_passes(self):
container = self.client.create_container(
BUSYBOX, 'top', healthcheck=dict(
test="true",
interval=1*SECOND,
timeout=1*SECOND,
retries=1,
))
self.tmp_containers.append(container)
self.client.start(container)
wait_on_health_status(self.client, container, "healthy")
@helpers.requires_api_version('1.24')
def test_healthcheck_fails(self):
container = self.client.create_container(
BUSYBOX, 'top', healthcheck=dict(
test="false",
interval=1*SECOND,
timeout=1*SECOND,
retries=1,
))
self.tmp_containers.append(container)
self.client.start(container)
wait_on_health_status(self.client, container, "unhealthy")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment