summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Shirlberg <NShirlberg@LabattFood.com>2016-09-23 15:07:59 -0500
committerNathan Shirlberg <NShirlberg@LabattFood.com>2016-09-27 11:26:26 -0500
commit6ef14932d0f33583bd5de82affd64d639a6fd5e3 (patch)
tree8a57da64a0b2b9c9ec120b38a1ed02e195fdeec0
parent803ff5030e1977e49bca7feea02d74afeabd6356 (diff)
downloaddocker-py-6ef14932d0f33583bd5de82affd64d639a6fd5e3.tar.gz
enable setting of node labels #1225
Added update_node function to enable setting labels on nodes. This exposes the Update a Node function from the Docker API and should enable promoting/demoting manager nodes inside a swarm. Signed-off-by: Nathan Shirlberg <nshirlberg@labattfood.com>
-rw-r--r--docker/api/swarm.py7
-rw-r--r--docs/api.md5
-rw-r--r--docs/swarm.md24
-rw-r--r--tests/integration/swarm_test.py24
-rw-r--r--tests/unit/fake_api.py9
-rw-r--r--tests/unit/swarm_test.py32
6 files changed, 101 insertions, 0 deletions
diff --git a/docker/api/swarm.py b/docker/api/swarm.py
index 7481c67..2fc8774 100644
--- a/docker/api/swarm.py
+++ b/docker/api/swarm.py
@@ -70,6 +70,13 @@ class SwarmApiMixin(object):
return self._result(self._get(url, params=params), True)
@utils.minimum_version('1.24')
+ def update_node(self, node_id, version, node_spec=None):
+ url = self._url('/nodes/{0}/update?version={1}', node_id, str(version))
+ res = self._post_json(url, data=node_spec)
+ self._raise_for_status(res)
+ return True
+
+ @utils.minimum_version('1.24')
def update_swarm(self, version, swarm_spec=None, rotate_worker_token=False,
rotate_manager_token=False):
url = self._url('/swarm/update')
diff --git a/docs/api.md b/docs/api.md
index 1699344..5cadb83 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -1129,6 +1129,11 @@ Update resource configs of one or more containers.
**Returns** (dict): Dictionary containing a `Warnings` key.
+## update_node
+
+Update a node.
+See the [Swarm documentation](swarm.md#clientupdate_node).
+
## update_service
Update a service, similar to the `docker service update` command. See the
diff --git a/docs/swarm.md b/docs/swarm.md
index 3cc44f8..20c3945 100644
--- a/docs/swarm.md
+++ b/docs/swarm.md
@@ -232,6 +232,30 @@ List Swarm nodes
**Returns:** A list of dictionaries containing data about each swarm node.
+### Client.update_node
+
+Update the Node's configuration
+
+**Params:**
+
+* version (int): The version number of the node object being updated. This
+ is required to avoid conflicting writes.
+* node_spec (dict): Configuration settings to update. Any values not provided
+ will be removed. See the official [Docker API documentation](https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/update-a-node) for more details.
+ Default: `None`.
+
+**Returns:** `True` if the request went through. Raises an `APIError` if it
+ fails.
+
+```python
+node_spec = {'Availability': 'active',
+ 'Name': 'node-name',
+ 'Role': 'manager',
+ 'Labels': {'foo': 'bar'}
+ }
+client.update_node(node_id='24ifsmvkjbyhk', version=8, node_spec=node_spec)
+```
+
### Client.update_swarm
Update the Swarm's configuration
diff --git a/tests/integration/swarm_test.py b/tests/integration/swarm_test.py
index 8c62f2e..7f02c71 100644
--- a/tests/integration/swarm_test.py
+++ b/tests/integration/swarm_test.py
@@ -1,3 +1,4 @@
+import copy
import docker
import pytest
@@ -138,3 +139,26 @@ class SwarmTest(helpers.BaseTestCase):
node_data = self.client.inspect_node(node['ID'])
assert node['ID'] == node_data['ID']
assert node['Version'] == node_data['Version']
+
+ @requires_api_version('1.24')
+ def test_update_node(self):
+ assert self.client.init_swarm('eth0')
+ nodes_list = self.client.nodes()
+ node = nodes_list[0]
+ orig_spec = node['Spec']
+
+ # add a new label
+ new_spec = copy.deepcopy(orig_spec)
+ new_spec['Labels'] = {'new.label': 'new value'}
+ self.client.update_node(node_id=node['ID'],
+ version=node['Version']['Index'],
+ node_spec=new_spec)
+ updated_node = self.client.inspect_node(node['ID'])
+ assert new_spec == updated_node['Spec']
+
+ # Revert the changes
+ self.client.update_node(node_id=node['ID'],
+ version=updated_node['Version']['Index'],
+ node_spec=orig_spec)
+ reverted_node = self.client.inspect_node(node['ID'])
+ assert orig_spec == reverted_node['Spec']
diff --git a/tests/unit/fake_api.py b/tests/unit/fake_api.py
index 1e9d318..cfe6ef7 100644
--- a/tests/unit/fake_api.py
+++ b/tests/unit/fake_api.py
@@ -14,6 +14,7 @@ FAKE_FILE_NAME = 'file'
FAKE_URL = 'myurl'
FAKE_PATH = '/path'
FAKE_VOLUME_NAME = 'perfectcherryblossom'
+FAKE_NODE_ID = '24ifsmvkjbyhk'
# Each method is prefixed with HTTP method (get, post...)
# for clarity and readability
@@ -406,6 +407,10 @@ def post_fake_update_container():
return 200, {'Warnings': []}
+def post_fake_update_node():
+ return 200, None
+
+
# Maps real api url to fake response callback
prefix = 'http+docker://localunixsocket'
fake_responses = {
@@ -504,4 +509,8 @@ fake_responses = {
CURRENT_VERSION, prefix, FAKE_VOLUME_NAME
), 'DELETE'):
fake_remove_volume,
+ ('{1}/{0}/nodes/{2}/update?version=1'.format(
+ CURRENT_VERSION, prefix, FAKE_NODE_ID
+ ), 'POST'):
+ post_fake_update_node,
}
diff --git a/tests/unit/swarm_test.py b/tests/unit/swarm_test.py
new file mode 100644
index 0000000..5580383
--- /dev/null
+++ b/tests/unit/swarm_test.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+
+import json
+
+from . import fake_api
+from ..base import requires_api_version
+from .api_test import (DockerClientTest, url_prefix, fake_request)
+
+
+class SwarmTest(DockerClientTest):
+ @requires_api_version('1.24')
+ def test_node_update(self):
+ node_spec = {
+ 'Availability': 'active',
+ 'Name': 'node-name',
+ 'Role': 'manager',
+ 'Labels': {'foo': 'bar'}
+ }
+
+ self.client.update_node(
+ node_id=fake_api.FAKE_NODE_ID, version=1, node_spec=node_spec
+ )
+ args = fake_request.call_args
+ self.assertEqual(
+ args[0][1], url_prefix + 'nodes/24ifsmvkjbyhk/update?version=1'
+ )
+ self.assertEqual(
+ json.loads(args[1]['data']), node_spec
+ )
+ self.assertEqual(
+ args[1]['headers']['Content-Type'], 'application/json'
+ )