summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoffrey F <joffrey@docker.com>2016-08-01 13:59:52 -0700
committerJoffrey F <joffrey@docker.com>2016-08-03 16:58:26 -0700
commit07563cfe3f565b57b955455d2ce2b350ed34883b (patch)
tree7927de42b8fa276ff6ef275e94135e2b76fa9ab3
parent9fdc8d476dfad2dad20ded9a1a471a225dc398aa (diff)
downloaddocker-py-07563cfe3f565b57b955455d2ce2b350ed34883b.tar.gz
Update swarm methods to include newly added parameters
Rename swarm methods to be more explicit Utility methods / types to create swarm spec objects Integration tests Signed-off-by: Joffrey F <joffrey@docker.com>
-rw-r--r--docker/api/swarm.py43
-rw-r--r--docker/constants.py2
-rw-r--r--docker/utils/__init__.py5
-rw-r--r--docker/utils/types.py49
-rw-r--r--tests/integration/swarm_test.py55
5 files changed, 136 insertions, 18 deletions
diff --git a/docker/api/swarm.py b/docker/api/swarm.py
index be3eae4..bc2179c 100644
--- a/docker/api/swarm.py
+++ b/docker/api/swarm.py
@@ -4,38 +4,49 @@ log = logging.getLogger(__name__)
class SwarmApiMixin(object):
- @utils.minimum_version('1.24')
- def swarm(self):
- url = self._url('/swarm')
- return self._result(self._get(url), True)
+
+ def create_swarm_spec(self, *args, **kwargs):
+ return utils.SwarmSpec(*args, **kwargs)
@utils.minimum_version('1.24')
- def swarm_init(self, listen_addr, force_new_cluster=False,
- swarm_opts=None):
+ def init_swarm(self, advertise_addr, listen_addr='0.0.0.0:2377',
+ force_new_cluster=False, swarm_spec=None):
url = self._url('/swarm/init')
- if swarm_opts is not None and not isinstance(swarm_opts, dict):
- raise TypeError('swarm_opts must be a dictionary')
+ if swarm_spec is not None and not isinstance(swarm_spec, dict):
+ raise TypeError('swarm_spec must be a dictionary')
data = {
+ 'AdvertiseAddr': advertise_addr,
'ListenAddr': listen_addr,
'ForceNewCluster': force_new_cluster,
- 'Spec': swarm_opts
+ 'Spec': swarm_spec,
}
- return self._result(self._post_json(url, data=data), True)
+ response = self._post_json(url, data=data)
+ self._raise_for_status(response)
+ return True
+
+ @utils.minimum_version('1.24')
+ def inspect_swarm(self):
+ url = self._url('/swarm')
+ return self._result(self._get(url), True)
@utils.minimum_version('1.24')
- def swarm_join(self, remote_address, listen_address=None,
+ def join_swarm(self, remote_addresses, listen_address=None,
secret=None, ca_cert_hash=None, manager=False):
data = {
- "RemoteAddr": remote_address,
+ "RemoteAddrs": remote_addresses,
"ListenAddr": listen_address,
"Secret": secret,
"CACertHash": ca_cert_hash,
"Manager": manager
}
- url = self._url('/swarm/join', )
- return self._result(self._post_json(url, data=data), True)
+ url = self._url('/swarm/join')
+ response = self._post_json(url, data=data)
+ self._raise_for_status(response)
+ return True
@utils.minimum_version('1.24')
- def swarm_leave(self):
+ def leave_swarm(self, force=False):
url = self._url('/swarm/leave')
- return self._result(self._post(url))
+ response = self._post(url, params={'force': force})
+ self._raise_for_status(response)
+ return True
diff --git a/docker/constants.py b/docker/constants.py
index 904d50e..cf5a39a 100644
--- a/docker/constants.py
+++ b/docker/constants.py
@@ -1,7 +1,7 @@
import sys
from .version import version
-DEFAULT_DOCKER_API_VERSION = '1.22'
+DEFAULT_DOCKER_API_VERSION = '1.24'
DEFAULT_TIMEOUT_SECONDS = 60
STREAM_HEADER_SIZE_BYTES = 8
CONTAINER_LIMITS_KEYS = [
diff --git a/docker/utils/__init__.py b/docker/utils/__init__.py
index 41df004..c02adea 100644
--- a/docker/utils/__init__.py
+++ b/docker/utils/__init__.py
@@ -8,5 +8,8 @@ from .utils import (
create_ipam_config, create_ipam_pool, parse_devices, normalize_links,
)
-from .types import Ulimit, LogConfig
+from .types import LogConfig, Ulimit
+from .types import (
+ SwarmAcceptancePolicy, SwarmExternalCA, SwarmSpec,
+)
from .decorators import check_resource, minimum_version, update_headers
diff --git a/docker/utils/types.py b/docker/utils/types.py
index ea9f06d..b970114 100644
--- a/docker/utils/types.py
+++ b/docker/utils/types.py
@@ -94,3 +94,52 @@ class Ulimit(DictType):
@hard.setter
def hard(self, value):
self['Hard'] = value
+
+
+class SwarmSpec(DictType):
+ def __init__(self, policies=None, 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):
+ if policies is not None:
+ self['AcceptancePolicy'] = {'Policies': policies}
+ 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
+ }
+
+
+class SwarmAcceptancePolicy(DictType):
+ def __init__(self, role, auto_accept=False, secret=None):
+ self['Role'] = role.upper()
+ self['Autoaccept'] = auto_accept
+ if secret is not None:
+ self['Secret'] = secret
+
+
+class SwarmExternalCA(DictType):
+ def __init__(self, url, protocol=None, options=None):
+ self['URL'] = url
+ self['Protocol'] = protocol
+ self['Options'] = options
diff --git a/tests/integration/swarm_test.py b/tests/integration/swarm_test.py
new file mode 100644
index 0000000..734d470
--- /dev/null
+++ b/tests/integration/swarm_test.py
@@ -0,0 +1,55 @@
+import docker
+import pytest
+
+from ..base import requires_api_version
+from .. import helpers
+
+
+BUSYBOX = helpers.BUSYBOX
+
+
+class SwarmTest(helpers.BaseTestCase):
+ def setUp(self):
+ super(SwarmTest, self).setUp()
+ try:
+ self.client.leave_swarm(force=True)
+ except docker.errors.APIError:
+ pass
+
+ def tearDown(self):
+ super(SwarmTest, self).tearDown()
+ try:
+ self.client.leave_swarm(force=True)
+ except docker.errors.APIError:
+ pass
+
+ @requires_api_version('1.24')
+ def test_init_swarm_simple(self):
+ assert self.client.init_swarm('eth0')
+
+ @requires_api_version('1.24')
+ def test_init_swarm_force_new_cluster(self):
+ pytest.skip('Test stalls the engine on 1.12')
+
+ assert self.client.init_swarm('eth0')
+ version_1 = self.client.inspect_swarm()['Version']['Index']
+ assert self.client.init_swarm('eth0', force_new_cluster=True)
+ version_2 = self.client.inspect_swarm()['Version']['Index']
+ assert version_2 != version_1
+
+ @requires_api_version('1.24')
+ def test_init_already_in_cluster(self):
+ assert self.client.init_swarm('eth0')
+ with pytest.raises(docker.errors.APIError):
+ self.client.init_swarm('eth0')
+
+ @requires_api_version('1.24')
+ def test_leave_swarm(self):
+ assert self.client.init_swarm('eth0')
+ with pytest.raises(docker.errors.APIError) as exc_info:
+ self.client.leave_swarm()
+ exc_info.value.response.status_code == 500
+ assert self.client.leave_swarm(force=True)
+ with pytest.raises(docker.errors.APIError) as exc_info:
+ self.client.inspect_swarm()
+ exc_info.value.response.status_code == 406