Skip to content

Commit 58c02ca

Browse files
authored
Merge pull request #1798 from docker/unlock_swarm_support
Unlock swarm support
2 parents 1d6b5b2 + 3bd053a commit 58c02ca

File tree

4 files changed

+70
-1
lines changed

4 files changed

+70
-1
lines changed

docker/api/swarm.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import logging
22
from six.moves import http_client
3+
from .. import errors
34
from .. import types
45
from .. import utils
6+
57
log = logging.getLogger(__name__)
68

79

@@ -68,6 +70,16 @@ def create_swarm_spec(self, *args, **kwargs):
6870
kwargs['external_cas'] = [ext_ca]
6971
return types.SwarmSpec(self._version, *args, **kwargs)
7072

73+
@utils.minimum_version('1.24')
74+
def get_unlock_key(self):
75+
"""
76+
Get the unlock key for this Swarm manager.
77+
78+
Returns:
79+
A ``dict`` containing an ``UnlockKey`` member
80+
"""
81+
return self._result(self._get(self._url('/swarm/unlockkey')), True)
82+
7183
@utils.minimum_version('1.24')
7284
def init_swarm(self, advertise_addr=None, listen_addr='0.0.0.0:2377',
7385
force_new_cluster=False, swarm_spec=None):
@@ -270,10 +282,46 @@ def remove_node(self, node_id, force=False):
270282
self._raise_for_status(res)
271283
return True
272284

285+
@utils.minimum_version('1.24')
286+
def unlock_swarm(self, key):
287+
"""
288+
Unlock a locked swarm.
289+
290+
Args:
291+
key (string): The unlock key as provided by
292+
:py:meth:`get_unlock_key`
293+
294+
Raises:
295+
:py:class:`docker.errors.InvalidArgument`
296+
If the key argument is in an incompatible format
297+
298+
:py:class:`docker.errors.APIError`
299+
If the server returns an error.
300+
301+
Returns:
302+
`True` if the request was successful.
303+
304+
Example:
305+
306+
>>> key = client.get_unlock_key()
307+
>>> client.unlock_node(key)
308+
309+
"""
310+
if isinstance(key, dict):
311+
if 'UnlockKey' not in key:
312+
raise errors.InvalidArgument('Invalid unlock key format')
313+
else:
314+
key = {'UnlockKey': key}
315+
316+
url = self._url('/swarm/unlock')
317+
res = self._post_json(url, data=key)
318+
self._raise_for_status(res)
319+
return True
320+
273321
@utils.minimum_version('1.24')
274322
def update_node(self, node_id, version, node_spec=None):
275323
"""
276-
Update the Node's configuration
324+
Update the node's configuration
277325
278326
Args:
279327

docker/models/swarm.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ def version(self):
2929
"""
3030
return self.attrs.get('Version').get('Index')
3131

32+
def get_unlock_key(self):
33+
return self.client.api.get_unlock_key()
34+
get_unlock_key.__doc__ = APIClient.get_unlock_key.__doc__
35+
3236
def init(self, advertise_addr=None, listen_addr='0.0.0.0:2377',
3337
force_new_cluster=False, **kwargs):
3438
"""
@@ -128,6 +132,10 @@ def reload(self):
128132
"""
129133
self.attrs = self.client.api.inspect_swarm()
130134

135+
def unlock(self, key):
136+
return self.client.api.unlock_swarm(key)
137+
unlock.__doc__ = APIClient.unlock_swarm.__doc__
138+
131139
def update(self, rotate_worker_token=False, rotate_manager_token=False,
132140
**kwargs):
133141
"""

docs/swarm.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ These methods are available on ``client.swarm``:
1212
.. rst-class:: hide-signature
1313
.. py:class:: Swarm
1414
15+
.. automethod:: get_unlock_key()
1516
.. automethod:: init()
1617
.. automethod:: join()
1718
.. automethod:: leave()
19+
.. automethod:: unlock()
1820
.. automethod:: update()
1921
.. automethod:: reload()
2022

tests/integration/api_swarm_test.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,16 @@ class SwarmTest(BaseAPIIntegrationTest):
1010
def setUp(self):
1111
super(SwarmTest, self).setUp()
1212
force_leave_swarm(self.client)
13+
self._unlock_key = None
1314

1415
def tearDown(self):
1516
super(SwarmTest, self).tearDown()
17+
try:
18+
if self._unlock_key:
19+
self.client.unlock_swarm(self._unlock_key)
20+
except docker.errors.APIError:
21+
pass
22+
1623
force_leave_swarm(self.client)
1724

1825
@requires_api_version('1.24')
@@ -64,12 +71,16 @@ def test_init_swarm_with_ca_config(self):
6471
def test_init_swarm_with_autolock_managers(self):
6572
spec = self.client.create_swarm_spec(autolock_managers=True)
6673
assert self.init_swarm(swarm_spec=spec)
74+
# save unlock key for tearDown
75+
self._unlock_key = self.client.get_unlock_key()
6776
swarm_info = self.client.inspect_swarm()
6877

6978
assert (
7079
swarm_info['Spec']['EncryptionConfig']['AutoLockManagers'] is True
7180
)
7281

82+
assert self._unlock_key.get('UnlockKey')
83+
7384
@requires_api_version('1.25')
7485
@pytest.mark.xfail(
7586
reason="This doesn't seem to be taken into account by the engine"

0 commit comments

Comments
 (0)