mirror of https://github.com/docker/docker-py.git
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>
This commit is contained in:
parent
9fdc8d476d
commit
07563cfe3f
|
@ -4,38 +4,49 @@ log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SwarmApiMixin(object):
|
class SwarmApiMixin(object):
|
||||||
|
|
||||||
|
def create_swarm_spec(self, *args, **kwargs):
|
||||||
|
return utils.SwarmSpec(*args, **kwargs)
|
||||||
|
|
||||||
@utils.minimum_version('1.24')
|
@utils.minimum_version('1.24')
|
||||||
def swarm(self):
|
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_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_spec,
|
||||||
|
}
|
||||||
|
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')
|
url = self._url('/swarm')
|
||||||
return self._result(self._get(url), True)
|
return self._result(self._get(url), True)
|
||||||
|
|
||||||
@utils.minimum_version('1.24')
|
@utils.minimum_version('1.24')
|
||||||
def swarm_init(self, listen_addr, force_new_cluster=False,
|
def join_swarm(self, remote_addresses, listen_address=None,
|
||||||
swarm_opts=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')
|
|
||||||
data = {
|
|
||||||
'ListenAddr': listen_addr,
|
|
||||||
'ForceNewCluster': force_new_cluster,
|
|
||||||
'Spec': swarm_opts
|
|
||||||
}
|
|
||||||
return self._result(self._post_json(url, data=data), True)
|
|
||||||
|
|
||||||
@utils.minimum_version('1.24')
|
|
||||||
def swarm_join(self, remote_address, listen_address=None,
|
|
||||||
secret=None, ca_cert_hash=None, manager=False):
|
secret=None, ca_cert_hash=None, manager=False):
|
||||||
data = {
|
data = {
|
||||||
"RemoteAddr": remote_address,
|
"RemoteAddrs": remote_addresses,
|
||||||
"ListenAddr": listen_address,
|
"ListenAddr": listen_address,
|
||||||
"Secret": secret,
|
"Secret": secret,
|
||||||
"CACertHash": ca_cert_hash,
|
"CACertHash": ca_cert_hash,
|
||||||
"Manager": manager
|
"Manager": manager
|
||||||
}
|
}
|
||||||
url = self._url('/swarm/join', )
|
url = self._url('/swarm/join')
|
||||||
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')
|
@utils.minimum_version('1.24')
|
||||||
def swarm_leave(self):
|
def leave_swarm(self, force=False):
|
||||||
url = self._url('/swarm/leave')
|
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
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
from .version import version
|
from .version import version
|
||||||
|
|
||||||
DEFAULT_DOCKER_API_VERSION = '1.22'
|
DEFAULT_DOCKER_API_VERSION = '1.24'
|
||||||
DEFAULT_TIMEOUT_SECONDS = 60
|
DEFAULT_TIMEOUT_SECONDS = 60
|
||||||
STREAM_HEADER_SIZE_BYTES = 8
|
STREAM_HEADER_SIZE_BYTES = 8
|
||||||
CONTAINER_LIMITS_KEYS = [
|
CONTAINER_LIMITS_KEYS = [
|
||||||
|
|
|
@ -8,5 +8,8 @@ from .utils import (
|
||||||
create_ipam_config, create_ipam_pool, parse_devices, normalize_links,
|
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
|
from .decorators import check_resource, minimum_version, update_headers
|
||||||
|
|
|
@ -94,3 +94,52 @@ class Ulimit(DictType):
|
||||||
@hard.setter
|
@hard.setter
|
||||||
def hard(self, value):
|
def hard(self, value):
|
||||||
self['Hard'] = 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
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue