diff options
| author | Nathan Shirlberg <NShirlberg@LabattFood.com> | 2016-09-23 15:07:59 -0500 |
|---|---|---|
| committer | Nathan Shirlberg <NShirlberg@LabattFood.com> | 2016-09-27 11:26:26 -0500 |
| commit | 6ef14932d0f33583bd5de82affd64d639a6fd5e3 (patch) | |
| tree | 8a57da64a0b2b9c9ec120b38a1ed02e195fdeec0 | |
| parent | 803ff5030e1977e49bca7feea02d74afeabd6356 (diff) | |
| download | docker-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.py | 7 | ||||
| -rw-r--r-- | docs/api.md | 5 | ||||
| -rw-r--r-- | docs/swarm.md | 24 | ||||
| -rw-r--r-- | tests/integration/swarm_test.py | 24 | ||||
| -rw-r--r-- | tests/unit/fake_api.py | 9 | ||||
| -rw-r--r-- | tests/unit/swarm_test.py | 32 |
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' + ) |
