mirror of https://github.com/docker/docker-py.git
New docker.types subpackage containing advanced config dictionary types
Tests and docs updated to match docker.utils.types has been moved to docker.types Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
02e99e4967
commit
97094e4ea3
|
@ -5,9 +5,6 @@ from .daemon import DaemonApiMixin
|
|||
from .exec_api import ExecApiMixin
|
||||
from .image import ImageApiMixin
|
||||
from .network import NetworkApiMixin
|
||||
from .service import (
|
||||
ServiceApiMixin, TaskTemplate, ContainerSpec, Mount, Resources,
|
||||
RestartPolicy, UpdateConfig
|
||||
)
|
||||
from .service import ServiceApiMixin
|
||||
from .swarm import SwarmApiMixin
|
||||
from .volume import VolumeApiMixin
|
||||
|
|
|
@ -1,28 +1,17 @@
|
|||
import six
|
||||
|
||||
from .. import errors
|
||||
from .. import utils
|
||||
|
||||
|
||||
class ServiceApiMixin(object):
|
||||
@utils.minimum_version('1.24')
|
||||
def services(self, filters=None):
|
||||
params = {
|
||||
'filters': utils.convert_filters(filters) if filters else None
|
||||
}
|
||||
url = self._url('/services')
|
||||
return self._result(self._get(url, params=params), True)
|
||||
|
||||
@utils.minimum_version('1.24')
|
||||
def create_service(
|
||||
self, task_config, name=None, labels=None, mode=None,
|
||||
self, task_template, name=None, labels=None, mode=None,
|
||||
update_config=None, networks=None, endpoint_config=None
|
||||
):
|
||||
url = self._url('/services/create')
|
||||
data = {
|
||||
'Name': name,
|
||||
'Labels': labels,
|
||||
'TaskTemplate': task_config,
|
||||
'TaskTemplate': task_template,
|
||||
'Mode': mode,
|
||||
'UpdateConfig': update_config,
|
||||
'Networks': networks,
|
||||
|
@ -44,6 +33,14 @@ class ServiceApiMixin(object):
|
|||
self._raise_for_status(resp)
|
||||
return True
|
||||
|
||||
@utils.minimum_version('1.24')
|
||||
def services(self, filters=None):
|
||||
params = {
|
||||
'filters': utils.convert_filters(filters) if filters else None
|
||||
}
|
||||
url = self._url('/services')
|
||||
return self._result(self._get(url, params=params), True)
|
||||
|
||||
@utils.minimum_version('1.24')
|
||||
@utils.check_resource
|
||||
def update_service(self, service, version, task_template=None, name=None,
|
||||
|
@ -69,167 +66,3 @@ class ServiceApiMixin(object):
|
|||
resp = self._post_json(url, data=data, params={'version': version})
|
||||
self._raise_for_status(resp)
|
||||
return True
|
||||
|
||||
|
||||
class TaskTemplate(dict):
|
||||
def __init__(self, container_spec, resources=None, restart_policy=None,
|
||||
placement=None, log_driver=None):
|
||||
self['ContainerSpec'] = container_spec
|
||||
if resources:
|
||||
self['Resources'] = resources
|
||||
if restart_policy:
|
||||
self['RestartPolicy'] = restart_policy
|
||||
if placement:
|
||||
self['Placement'] = placement
|
||||
if log_driver:
|
||||
self['LogDriver'] = log_driver
|
||||
|
||||
@property
|
||||
def container_spec(self):
|
||||
return self.get('ContainerSpec')
|
||||
|
||||
@property
|
||||
def resources(self):
|
||||
return self.get('Resources')
|
||||
|
||||
@property
|
||||
def restart_policy(self):
|
||||
return self.get('RestartPolicy')
|
||||
|
||||
@property
|
||||
def placement(self):
|
||||
return self.get('Placement')
|
||||
|
||||
|
||||
class ContainerSpec(dict):
|
||||
def __init__(self, image, command=None, args=None, env=None, workdir=None,
|
||||
user=None, labels=None, mounts=None, stop_grace_period=None):
|
||||
self['Image'] = image
|
||||
self['Command'] = command
|
||||
self['Args'] = args
|
||||
|
||||
if env is not None:
|
||||
self['Env'] = env
|
||||
if workdir is not None:
|
||||
self['Dir'] = workdir
|
||||
if user is not None:
|
||||
self['User'] = user
|
||||
if labels is not None:
|
||||
self['Labels'] = labels
|
||||
if mounts is not None:
|
||||
for mount in mounts:
|
||||
if isinstance(mount, six.string_types):
|
||||
mounts.append(Mount.parse_mount_string(mount))
|
||||
mounts.remove(mount)
|
||||
self['Mounts'] = mounts
|
||||
if stop_grace_period is not None:
|
||||
self['StopGracePeriod'] = stop_grace_period
|
||||
|
||||
|
||||
class Mount(dict):
|
||||
def __init__(self, target, source, type='volume', read_only=False,
|
||||
propagation=None, no_copy=False, labels=None,
|
||||
driver_config=None):
|
||||
self['Target'] = target
|
||||
self['Source'] = source
|
||||
if type not in ('bind', 'volume'):
|
||||
raise errors.DockerError(
|
||||
'Only acceptable mount types are `bind` and `volume`.'
|
||||
)
|
||||
self['Type'] = type
|
||||
|
||||
if type == 'bind':
|
||||
if propagation is not None:
|
||||
self['BindOptions'] = {
|
||||
'Propagation': propagation
|
||||
}
|
||||
if any(labels, driver_config, no_copy):
|
||||
raise errors.DockerError(
|
||||
'Mount type is binding but volume options have been '
|
||||
'provided.'
|
||||
)
|
||||
else:
|
||||
volume_opts = {}
|
||||
if no_copy:
|
||||
volume_opts['NoCopy'] = True
|
||||
if labels:
|
||||
volume_opts['Labels'] = labels
|
||||
if driver_config:
|
||||
volume_opts['driver_config'] = driver_config
|
||||
if volume_opts:
|
||||
self['VolumeOptions'] = volume_opts
|
||||
if propagation:
|
||||
raise errors.DockerError(
|
||||
'Mount type is volume but `propagation` argument has been '
|
||||
'provided.'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def parse_mount_string(cls, string):
|
||||
parts = string.split(':')
|
||||
if len(parts) > 3:
|
||||
raise errors.DockerError(
|
||||
'Invalid mount format "{0}"'.format(string)
|
||||
)
|
||||
if len(parts) == 1:
|
||||
return cls(target=parts[0])
|
||||
else:
|
||||
target = parts[1]
|
||||
source = parts[0]
|
||||
read_only = not (len(parts) == 3 or parts[2] == 'ro')
|
||||
return cls(target, source, read_only=read_only)
|
||||
|
||||
|
||||
class Resources(dict):
|
||||
def __init__(self, cpu_limit=None, mem_limit=None, cpu_reservation=None,
|
||||
mem_reservation=None):
|
||||
limits = {}
|
||||
reservation = {}
|
||||
if cpu_limit is not None:
|
||||
limits['NanoCPUs'] = cpu_limit
|
||||
if mem_limit is not None:
|
||||
limits['MemoryBytes'] = mem_limit
|
||||
if cpu_reservation is not None:
|
||||
reservation['NanoCPUs'] = cpu_reservation
|
||||
if mem_reservation is not None:
|
||||
reservation['MemoryBytes'] = mem_reservation
|
||||
|
||||
self['Limits'] = limits
|
||||
self['Reservation'] = reservation
|
||||
|
||||
|
||||
class UpdateConfig(dict):
|
||||
def __init__(self, parallelism=0, delay=None, failure_action='continue'):
|
||||
self['Parallelism'] = parallelism
|
||||
if delay is not None:
|
||||
self['Delay'] = delay
|
||||
if failure_action not in ('pause', 'continue'):
|
||||
raise errors.DockerError(
|
||||
'failure_action must be either `pause` or `continue`.'
|
||||
)
|
||||
self['FailureAction'] = failure_action
|
||||
|
||||
|
||||
class RestartConditionTypesEnum(object):
|
||||
_values = (
|
||||
'none',
|
||||
'on_failure',
|
||||
'any',
|
||||
)
|
||||
NONE, ON_FAILURE, ANY = _values
|
||||
|
||||
|
||||
class RestartPolicy(dict):
|
||||
condition_types = RestartConditionTypesEnum
|
||||
|
||||
def __init__(self, condition=RestartConditionTypesEnum.NONE, delay=0,
|
||||
attempts=0, window=0):
|
||||
if condition not in self.condition_types._values:
|
||||
raise TypeError(
|
||||
'Invalid RestartPolicy condition {0}'.format(condition)
|
||||
)
|
||||
|
||||
self['Condition'] = condition
|
||||
self['Delay'] = delay
|
||||
self['Attempts'] = attempts
|
||||
self['Window'] = window
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# flake8: noqa
|
||||
from .containers import LogConfig, Ulimit
|
||||
from .services import (
|
||||
ContainerSpec, LogDriver, Mount, Resources, RestartPolicy, TaskTemplate,
|
||||
UpdateConfig
|
||||
)
|
||||
from .swarm import SwarmSpec, SwarmExternalCA
|
|
@ -0,0 +1,7 @@
|
|||
import six
|
||||
|
||||
|
||||
class DictType(dict):
|
||||
def __init__(self, init):
|
||||
for k, v in six.iteritems(init):
|
||||
self[k] = v
|
|
@ -1,5 +1,7 @@
|
|||
import six
|
||||
|
||||
from .base import DictType
|
||||
|
||||
|
||||
class LogConfigTypesEnum(object):
|
||||
_values = (
|
||||
|
@ -13,12 +15,6 @@ class LogConfigTypesEnum(object):
|
|||
JSON, SYSLOG, JOURNALD, GELF, FLUENTD, NONE = _values
|
||||
|
||||
|
||||
class DictType(dict):
|
||||
def __init__(self, init):
|
||||
for k, v in six.iteritems(init):
|
||||
self[k] = v
|
||||
|
||||
|
||||
class LogConfig(DictType):
|
||||
types = LogConfigTypesEnum
|
||||
|
||||
|
@ -94,45 +90,3 @@ class Ulimit(DictType):
|
|||
@hard.setter
|
||||
def hard(self, value):
|
||||
self['Hard'] = value
|
||||
|
||||
|
||||
class SwarmSpec(DictType):
|
||||
def __init__(self, task_history_retention_limit=None,
|
||||
snapshot_interval=None, keep_old_snapshots=None,
|
||||
log_entries_for_slow_followers=None, heartbeat_tick=None,
|
||||
election_tick=None, dispatcher_heartbeat_period=None,
|
||||
node_cert_expiry=None, external_ca=None, name=None):
|
||||
if task_history_retention_limit is not None:
|
||||
self['Orchestration'] = {
|
||||
'TaskHistoryRetentionLimit': task_history_retention_limit
|
||||
}
|
||||
if any([snapshot_interval, keep_old_snapshots,
|
||||
log_entries_for_slow_followers, heartbeat_tick, election_tick]):
|
||||
self['Raft'] = {
|
||||
'SnapshotInterval': snapshot_interval,
|
||||
'KeepOldSnapshots': keep_old_snapshots,
|
||||
'LogEntriesForSlowFollowers': log_entries_for_slow_followers,
|
||||
'HeartbeatTick': heartbeat_tick,
|
||||
'ElectionTick': election_tick
|
||||
}
|
||||
|
||||
if dispatcher_heartbeat_period:
|
||||
self['Dispatcher'] = {
|
||||
'HeartbeatPeriod': dispatcher_heartbeat_period
|
||||
}
|
||||
|
||||
if node_cert_expiry or external_ca:
|
||||
self['CAConfig'] = {
|
||||
'NodeCertExpiry': node_cert_expiry,
|
||||
'ExternalCA': external_ca
|
||||
}
|
||||
|
||||
if name is not None:
|
||||
self['Name'] = name
|
||||
|
||||
|
||||
class SwarmExternalCA(DictType):
|
||||
def __init__(self, url, protocol=None, options=None):
|
||||
self['URL'] = url
|
||||
self['Protocol'] = protocol
|
||||
self['Options'] = options
|
|
@ -0,0 +1,176 @@
|
|||
import six
|
||||
|
||||
from .. import errors
|
||||
|
||||
|
||||
class TaskTemplate(dict):
|
||||
def __init__(self, container_spec, resources=None, restart_policy=None,
|
||||
placement=None, log_driver=None):
|
||||
self['ContainerSpec'] = container_spec
|
||||
if resources:
|
||||
self['Resources'] = resources
|
||||
if restart_policy:
|
||||
self['RestartPolicy'] = restart_policy
|
||||
if placement:
|
||||
self['Placement'] = placement
|
||||
if log_driver:
|
||||
self['LogDriver'] = log_driver
|
||||
|
||||
@property
|
||||
def container_spec(self):
|
||||
return self.get('ContainerSpec')
|
||||
|
||||
@property
|
||||
def resources(self):
|
||||
return self.get('Resources')
|
||||
|
||||
@property
|
||||
def restart_policy(self):
|
||||
return self.get('RestartPolicy')
|
||||
|
||||
@property
|
||||
def placement(self):
|
||||
return self.get('Placement')
|
||||
|
||||
|
||||
class ContainerSpec(dict):
|
||||
def __init__(self, image, command=None, args=None, env=None, workdir=None,
|
||||
user=None, labels=None, mounts=None, stop_grace_period=None):
|
||||
self['Image'] = image
|
||||
self['Command'] = command
|
||||
self['Args'] = args
|
||||
|
||||
if env is not None:
|
||||
self['Env'] = env
|
||||
if workdir is not None:
|
||||
self['Dir'] = workdir
|
||||
if user is not None:
|
||||
self['User'] = user
|
||||
if labels is not None:
|
||||
self['Labels'] = labels
|
||||
if mounts is not None:
|
||||
for mount in mounts:
|
||||
if isinstance(mount, six.string_types):
|
||||
mounts.append(Mount.parse_mount_string(mount))
|
||||
mounts.remove(mount)
|
||||
self['Mounts'] = mounts
|
||||
if stop_grace_period is not None:
|
||||
self['StopGracePeriod'] = stop_grace_period
|
||||
|
||||
|
||||
class Mount(dict):
|
||||
def __init__(self, target, source, type='volume', read_only=False,
|
||||
propagation=None, no_copy=False, labels=None,
|
||||
driver_config=None):
|
||||
self['Target'] = target
|
||||
self['Source'] = source
|
||||
if type not in ('bind', 'volume'):
|
||||
raise errors.DockerError(
|
||||
'Only acceptable mount types are `bind` and `volume`.'
|
||||
)
|
||||
self['Type'] = type
|
||||
|
||||
if type == 'bind':
|
||||
if propagation is not None:
|
||||
self['BindOptions'] = {
|
||||
'Propagation': propagation
|
||||
}
|
||||
if any(labels, driver_config, no_copy):
|
||||
raise errors.DockerError(
|
||||
'Mount type is binding but volume options have been '
|
||||
'provided.'
|
||||
)
|
||||
else:
|
||||
volume_opts = {}
|
||||
if no_copy:
|
||||
volume_opts['NoCopy'] = True
|
||||
if labels:
|
||||
volume_opts['Labels'] = labels
|
||||
if driver_config:
|
||||
volume_opts['driver_config'] = driver_config
|
||||
if volume_opts:
|
||||
self['VolumeOptions'] = volume_opts
|
||||
if propagation:
|
||||
raise errors.DockerError(
|
||||
'Mount type is volume but `propagation` argument has been '
|
||||
'provided.'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def parse_mount_string(cls, string):
|
||||
parts = string.split(':')
|
||||
if len(parts) > 3:
|
||||
raise errors.DockerError(
|
||||
'Invalid mount format "{0}"'.format(string)
|
||||
)
|
||||
if len(parts) == 1:
|
||||
return cls(target=parts[0])
|
||||
else:
|
||||
target = parts[1]
|
||||
source = parts[0]
|
||||
read_only = not (len(parts) == 3 or parts[2] == 'ro')
|
||||
return cls(target, source, read_only=read_only)
|
||||
|
||||
|
||||
class Resources(dict):
|
||||
def __init__(self, cpu_limit=None, mem_limit=None, cpu_reservation=None,
|
||||
mem_reservation=None):
|
||||
limits = {}
|
||||
reservation = {}
|
||||
if cpu_limit is not None:
|
||||
limits['NanoCPUs'] = cpu_limit
|
||||
if mem_limit is not None:
|
||||
limits['MemoryBytes'] = mem_limit
|
||||
if cpu_reservation is not None:
|
||||
reservation['NanoCPUs'] = cpu_reservation
|
||||
if mem_reservation is not None:
|
||||
reservation['MemoryBytes'] = mem_reservation
|
||||
|
||||
if limits:
|
||||
self['Limits'] = limits
|
||||
if reservation:
|
||||
self['Reservations'] = reservation
|
||||
|
||||
|
||||
class UpdateConfig(dict):
|
||||
def __init__(self, parallelism=0, delay=None, failure_action='continue'):
|
||||
self['Parallelism'] = parallelism
|
||||
if delay is not None:
|
||||
self['Delay'] = delay
|
||||
if failure_action not in ('pause', 'continue'):
|
||||
raise errors.DockerError(
|
||||
'failure_action must be either `pause` or `continue`.'
|
||||
)
|
||||
self['FailureAction'] = failure_action
|
||||
|
||||
|
||||
class RestartConditionTypesEnum(object):
|
||||
_values = (
|
||||
'none',
|
||||
'on_failure',
|
||||
'any',
|
||||
)
|
||||
NONE, ON_FAILURE, ANY = _values
|
||||
|
||||
|
||||
class RestartPolicy(dict):
|
||||
condition_types = RestartConditionTypesEnum
|
||||
|
||||
def __init__(self, condition=RestartConditionTypesEnum.NONE, delay=0,
|
||||
max_attempts=0, window=0):
|
||||
if condition not in self.condition_types._values:
|
||||
raise TypeError(
|
||||
'Invalid RestartPolicy condition {0}'.format(condition)
|
||||
)
|
||||
|
||||
self['Condition'] = condition
|
||||
self['Delay'] = delay
|
||||
self['MaxAttempts'] = max_attempts
|
||||
self['Window'] = window
|
||||
|
||||
|
||||
class LogDriver(dict):
|
||||
def __init__(self, name, options=None):
|
||||
self['Name'] = name
|
||||
if options:
|
||||
self['Options'] = options
|
|
@ -0,0 +1,40 @@
|
|||
class SwarmSpec(dict):
|
||||
def __init__(self, task_history_retention_limit=None,
|
||||
snapshot_interval=None, keep_old_snapshots=None,
|
||||
log_entries_for_slow_followers=None, heartbeat_tick=None,
|
||||
election_tick=None, dispatcher_heartbeat_period=None,
|
||||
node_cert_expiry=None, external_ca=None, name=None):
|
||||
if task_history_retention_limit is not None:
|
||||
self['Orchestration'] = {
|
||||
'TaskHistoryRetentionLimit': task_history_retention_limit
|
||||
}
|
||||
if any([snapshot_interval, keep_old_snapshots,
|
||||
log_entries_for_slow_followers, heartbeat_tick, election_tick]):
|
||||
self['Raft'] = {
|
||||
'SnapshotInterval': snapshot_interval,
|
||||
'KeepOldSnapshots': keep_old_snapshots,
|
||||
'LogEntriesForSlowFollowers': log_entries_for_slow_followers,
|
||||
'HeartbeatTick': heartbeat_tick,
|
||||
'ElectionTick': election_tick
|
||||
}
|
||||
|
||||
if dispatcher_heartbeat_period:
|
||||
self['Dispatcher'] = {
|
||||
'HeartbeatPeriod': dispatcher_heartbeat_period
|
||||
}
|
||||
|
||||
if node_cert_expiry or external_ca:
|
||||
self['CAConfig'] = {
|
||||
'NodeCertExpiry': node_cert_expiry,
|
||||
'ExternalCA': external_ca
|
||||
}
|
||||
|
||||
if name is not None:
|
||||
self['Name'] = name
|
||||
|
||||
|
||||
class SwarmExternalCA(dict):
|
||||
def __init__(self, url, protocol=None, options=None):
|
||||
self['URL'] = url
|
||||
self['Protocol'] = protocol
|
||||
self['Options'] = options
|
|
@ -8,8 +8,6 @@ from .utils import (
|
|||
create_ipam_config, create_ipam_pool, parse_devices, normalize_links,
|
||||
)
|
||||
|
||||
from .types import LogConfig, Ulimit
|
||||
from .types import (
|
||||
SwarmExternalCA, SwarmSpec,
|
||||
)
|
||||
from ..types import LogConfig, Ulimit
|
||||
from ..types import SwarmExternalCA, SwarmSpec
|
||||
from .decorators import check_resource, minimum_version, update_headers
|
||||
|
|
|
@ -31,7 +31,7 @@ import six
|
|||
from .. import constants
|
||||
from .. import errors
|
||||
from .. import tls
|
||||
from .types import Ulimit, LogConfig
|
||||
from ..types import Ulimit, LogConfig
|
||||
|
||||
if six.PY2:
|
||||
from urllib import splitnport
|
||||
|
|
|
@ -95,7 +95,7 @@ Initialize a new Swarm using the current connected engine as the first node.
|
|||
|
||||
#### Client.create_swarm_spec
|
||||
|
||||
Create a `docker.utils.SwarmSpec` instance that can be used as the `swarm_spec`
|
||||
Create a `docker.types.SwarmSpec` instance that can be used as the `swarm_spec`
|
||||
argument in `Client.init_swarm`.
|
||||
|
||||
**Params:**
|
||||
|
@ -113,12 +113,12 @@ argument in `Client.init_swarm`.
|
|||
heartbeat to the dispatcher.
|
||||
* node_cert_expiry (int): Automatic expiry for nodes certificates.
|
||||
* external_ca (dict): Configuration for forwarding signing requests to an
|
||||
external certificate authority. Use `docker.utils.SwarmExternalCA`.
|
||||
external certificate authority. Use `docker.types.SwarmExternalCA`.
|
||||
* name (string): Swarm's name
|
||||
|
||||
**Returns:** `docker.utils.SwarmSpec` instance.
|
||||
**Returns:** `docker.types.SwarmSpec` instance.
|
||||
|
||||
#### docker.utils.SwarmExternalCA
|
||||
#### docker.types.SwarmExternalCA
|
||||
|
||||
Create a configuration dictionary for the `external_ca` argument in a
|
||||
`SwarmSpec`.
|
||||
|
|
3
setup.py
3
setup.py
|
@ -36,7 +36,8 @@ setup(
|
|||
url='https://github.com/docker/docker-py/',
|
||||
packages=[
|
||||
'docker', 'docker.api', 'docker.auth', 'docker.transport',
|
||||
'docker.utils', 'docker.utils.ports', 'docker.ssladapter'
|
||||
'docker.utils', 'docker.utils.ports', 'docker.ssladapter',
|
||||
'docker.types',
|
||||
],
|
||||
install_requires=requirements,
|
||||
tests_require=test_requirements,
|
||||
|
|
|
@ -40,8 +40,10 @@ class ServiceTest(helpers.BaseTestCase):
|
|||
else:
|
||||
name = self.get_service_name()
|
||||
|
||||
container_spec = docker.api.ContainerSpec('busybox', ['echo', 'hello'])
|
||||
task_tmpl = docker.api.TaskTemplate(container_spec)
|
||||
container_spec = docker.types.ContainerSpec(
|
||||
'busybox', ['echo', 'hello']
|
||||
)
|
||||
task_tmpl = docker.types.TaskTemplate(container_spec)
|
||||
return name, self.client.create_service(task_tmpl, name=name)
|
||||
|
||||
@requires_api_version('1.24')
|
||||
|
@ -74,7 +76,7 @@ class ServiceTest(helpers.BaseTestCase):
|
|||
test_services = self.client.services(filters={'name': 'dockerpytest_'})
|
||||
assert len(test_services) == 0
|
||||
|
||||
def test_rempve_service_by_name(self):
|
||||
def test_remove_service_by_name(self):
|
||||
svc_name, svc_id = self.create_simple_service()
|
||||
assert self.client.remove_service(svc_name)
|
||||
test_services = self.client.services(filters={'name': 'dockerpytest_'})
|
||||
|
@ -87,6 +89,94 @@ class ServiceTest(helpers.BaseTestCase):
|
|||
assert len(services) == 1
|
||||
assert services[0]['ID'] == svc_id['ID']
|
||||
|
||||
def test_create_service_custom_log_driver(self):
|
||||
container_spec = docker.types.ContainerSpec(
|
||||
'busybox', ['echo', 'hello']
|
||||
)
|
||||
log_cfg = docker.types.LogDriver('none')
|
||||
task_tmpl = docker.types.TaskTemplate(
|
||||
container_spec, log_driver=log_cfg
|
||||
)
|
||||
name = self.get_service_name()
|
||||
svc_id = self.client.create_service(task_tmpl, name=name)
|
||||
svc_info = self.client.inspect_service(svc_id)
|
||||
assert 'TaskTemplate' in svc_info['Spec']
|
||||
res_template = svc_info['Spec']['TaskTemplate']
|
||||
assert 'LogDriver' in res_template
|
||||
assert 'Name' in res_template['LogDriver']
|
||||
assert res_template['LogDriver']['Name'] == 'none'
|
||||
|
||||
def test_create_service_with_volume_mount(self):
|
||||
vol_name = self.get_service_name()
|
||||
container_spec = docker.types.ContainerSpec(
|
||||
'busybox', ['ls'],
|
||||
mounts=[
|
||||
docker.types.Mount(target='/test', source=vol_name)
|
||||
]
|
||||
)
|
||||
self.tmp_volumes.append(vol_name)
|
||||
task_tmpl = docker.types.TaskTemplate(container_spec)
|
||||
name = self.get_service_name()
|
||||
svc_id = self.client.create_service(task_tmpl, name=name)
|
||||
svc_info = self.client.inspect_service(svc_id)
|
||||
assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate']
|
||||
cspec = svc_info['Spec']['TaskTemplate']['ContainerSpec']
|
||||
assert 'Mounts' in cspec
|
||||
assert len(cspec['Mounts']) == 1
|
||||
mount = cspec['Mounts'][0]
|
||||
assert mount['Target'] == '/test'
|
||||
assert mount['Source'] == vol_name
|
||||
assert mount['Type'] == 'volume'
|
||||
|
||||
def test_create_service_with_resources_constraints(self):
|
||||
container_spec = docker.types.ContainerSpec('busybox', ['true'])
|
||||
resources = docker.types.Resources(
|
||||
cpu_limit=4000000, mem_limit=3 * 1024 * 1024 * 1024,
|
||||
cpu_reservation=3500000, mem_reservation=2 * 1024 * 1024 * 1024
|
||||
)
|
||||
task_tmpl = docker.types.TaskTemplate(
|
||||
container_spec, resources=resources
|
||||
)
|
||||
name = self.get_service_name()
|
||||
svc_id = self.client.create_service(task_tmpl, name=name)
|
||||
svc_info = self.client.inspect_service(svc_id)
|
||||
assert 'TaskTemplate' in svc_info['Spec']
|
||||
res_template = svc_info['Spec']['TaskTemplate']
|
||||
assert 'Resources' in res_template
|
||||
assert res_template['Resources']['Limits'] == resources['Limits']
|
||||
assert res_template['Resources']['Reservations'] == resources[
|
||||
'Reservations'
|
||||
]
|
||||
|
||||
def test_create_service_with_update_config(self):
|
||||
container_spec = docker.types.ContainerSpec('busybox', ['true'])
|
||||
task_tmpl = docker.types.TaskTemplate(container_spec)
|
||||
update_config = docker.types.UpdateConfig(
|
||||
parallelism=10, delay=5, failure_action='pause'
|
||||
)
|
||||
name = self.get_service_name()
|
||||
svc_id = self.client.create_service(
|
||||
task_tmpl, update_config=update_config, name=name
|
||||
)
|
||||
svc_info = self.client.inspect_service(svc_id)
|
||||
assert 'UpdateConfig' in svc_info['Spec']
|
||||
assert update_config == svc_info['Spec']['UpdateConfig']
|
||||
|
||||
def test_create_service_with_restart_policy(self):
|
||||
container_spec = docker.types.ContainerSpec('busybox', ['true'])
|
||||
policy = docker.types.RestartPolicy(
|
||||
docker.types.RestartPolicy.condition_types.ANY,
|
||||
delay=5, max_attempts=5
|
||||
)
|
||||
task_tmpl = docker.types.TaskTemplate(
|
||||
container_spec, restart_policy=policy
|
||||
)
|
||||
name = self.get_service_name()
|
||||
svc_id = self.client.create_service(task_tmpl, name=name)
|
||||
svc_info = self.client.inspect_service(svc_id)
|
||||
assert 'RestartPolicy' in svc_info['Spec']['TaskTemplate']
|
||||
assert policy == svc_info['Spec']['TaskTemplate']['RestartPolicy']
|
||||
|
||||
def test_update_service_name(self):
|
||||
name, svc_id = self.create_simple_service()
|
||||
svc_info = self.client.inspect_service(svc_id)
|
||||
|
|
Loading…
Reference in New Issue