Kaydet (Commit) 6ef14932 authored tarafından Nathan Shirlberg's avatar Nathan Shirlberg

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: 's avatarNathan Shirlberg <nshirlberg@labattfood.com>
üst 803ff503
...@@ -69,6 +69,13 @@ class SwarmApiMixin(object): ...@@ -69,6 +69,13 @@ class SwarmApiMixin(object):
return self._result(self._get(url, params=params), True) 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') @utils.minimum_version('1.24')
def update_swarm(self, version, swarm_spec=None, rotate_worker_token=False, def update_swarm(self, version, swarm_spec=None, rotate_worker_token=False,
rotate_manager_token=False): rotate_manager_token=False):
......
...@@ -1129,6 +1129,11 @@ Update resource configs of one or more containers. ...@@ -1129,6 +1129,11 @@ Update resource configs of one or more containers.
**Returns** (dict): Dictionary containing a `Warnings` key. **Returns** (dict): Dictionary containing a `Warnings` key.
## update_node
Update a node.
See the [Swarm documentation](swarm.md#clientupdate_node).
## update_service ## update_service
Update a service, similar to the `docker service update` command. See the Update a service, similar to the `docker service update` command. See the
......
...@@ -232,6 +232,30 @@ List Swarm nodes ...@@ -232,6 +232,30 @@ List Swarm nodes
**Returns:** A list of dictionaries containing data about each swarm node. **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 ### Client.update_swarm
Update the Swarm's configuration Update the Swarm's configuration
......
import copy
import docker import docker
import pytest import pytest
...@@ -138,3 +139,26 @@ class SwarmTest(helpers.BaseTestCase): ...@@ -138,3 +139,26 @@ class SwarmTest(helpers.BaseTestCase):
node_data = self.client.inspect_node(node['ID']) node_data = self.client.inspect_node(node['ID'])
assert node['ID'] == node_data['ID'] assert node['ID'] == node_data['ID']
assert node['Version'] == node_data['Version'] 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']
...@@ -14,6 +14,7 @@ FAKE_FILE_NAME = 'file' ...@@ -14,6 +14,7 @@ FAKE_FILE_NAME = 'file'
FAKE_URL = 'myurl' FAKE_URL = 'myurl'
FAKE_PATH = '/path' FAKE_PATH = '/path'
FAKE_VOLUME_NAME = 'perfectcherryblossom' FAKE_VOLUME_NAME = 'perfectcherryblossom'
FAKE_NODE_ID = '24ifsmvkjbyhk'
# Each method is prefixed with HTTP method (get, post...) # Each method is prefixed with HTTP method (get, post...)
# for clarity and readability # for clarity and readability
...@@ -406,6 +407,10 @@ def post_fake_update_container(): ...@@ -406,6 +407,10 @@ def post_fake_update_container():
return 200, {'Warnings': []} return 200, {'Warnings': []}
def post_fake_update_node():
return 200, None
# Maps real api url to fake response callback # Maps real api url to fake response callback
prefix = 'http+docker://localunixsocket' prefix = 'http+docker://localunixsocket'
fake_responses = { fake_responses = {
...@@ -504,4 +509,8 @@ fake_responses = { ...@@ -504,4 +509,8 @@ fake_responses = {
CURRENT_VERSION, prefix, FAKE_VOLUME_NAME CURRENT_VERSION, prefix, FAKE_VOLUME_NAME
), 'DELETE'): ), 'DELETE'):
fake_remove_volume, fake_remove_volume,
('{1}/{0}/nodes/{2}/update?version=1'.format(
CURRENT_VERSION, prefix, FAKE_NODE_ID
), 'POST'):
post_fake_update_node,
} }
# -*- 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'
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment