Node labels support
This patch implement support for node custom attributes Filter nodes by specific labels: fuel2 node list --labels "label_key_1=label_val_1" [..] List all labels in system or only for specific nodes: fuel2 node label list --nodes 1 2 Set label(s) for all or only specific nodes: fuel2 node label set "label_key_1=label_val_1" [..] --nodes 1 2 Delete label(s) by key for all or only specific nodes: fuel2 node label delete "label_key_1" [..] --nodes 1 2 Implements: blueprint node-custom-attributes Change-Id: Iaa00219a8e4a9c5fa62df2ce4d59057ef17e89a0
This commit is contained in:
committed by
Sebastian Kalinowski
parent
f85a6eecbb
commit
fe289321ac
@@ -116,9 +116,10 @@ class BaseDeleteCommand(BaseCommand):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(BaseDeleteCommand, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument('id', type=int,
|
||||
help='Id of the {0} to '
|
||||
'delete.'.format(self.entity_name))
|
||||
parser.add_argument(
|
||||
'id',
|
||||
type=int,
|
||||
help='Id of the {0} to delete.'.format(self.entity_name))
|
||||
|
||||
return parser
|
||||
|
||||
@@ -127,5 +128,7 @@ class BaseDeleteCommand(BaseCommand):
|
||||
|
||||
msg = '{ent} with id {ent_id} was deleted\n'
|
||||
|
||||
self.app.stdout.write(msg.format(ent=self.entity_name.capitalize(),
|
||||
ent_id=parsed_args.id))
|
||||
self.app.stdout.write(
|
||||
msg.format(
|
||||
ent=self.entity_name.capitalize(),
|
||||
ent_id=parsed_args.id))
|
||||
|
||||
@@ -43,14 +43,19 @@ class NodeList(NodeMixIn, base.BaseListCommand):
|
||||
'-e',
|
||||
'--env',
|
||||
type=int,
|
||||
help='Show only nodes that are in the specified environment'
|
||||
)
|
||||
help='Show only nodes that are in the specified environment')
|
||||
|
||||
parser.add_argument(
|
||||
'-l',
|
||||
'--labels',
|
||||
nargs='+',
|
||||
help='Show only nodes that have specific labels')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
|
||||
data = self.client.get_all(environment_id=parsed_args.env)
|
||||
data = self.client.get_all(
|
||||
environment_id=parsed_args.env, labels=parsed_args.labels)
|
||||
data = data_utils.get_display_data_multi(self.columns, data)
|
||||
|
||||
return (self.columns, data)
|
||||
@@ -82,6 +87,37 @@ class NodeShow(NodeMixIn, base.BaseShowCommand):
|
||||
'manufacturer')
|
||||
|
||||
|
||||
class NodeUpdate(NodeMixIn, base.BaseShowCommand):
|
||||
"""Change given attributes for a node."""
|
||||
|
||||
columns = NodeShow.columns
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(NodeUpdate, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'-H',
|
||||
'--hostname',
|
||||
type=str,
|
||||
default=None,
|
||||
help='New hostname for node')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
updates = {}
|
||||
for attr in self.client._updatable_attributes:
|
||||
if getattr(parsed_args, attr, None):
|
||||
updates[attr] = getattr(parsed_args, attr)
|
||||
|
||||
updated_node = self.client.update(
|
||||
parsed_args.id, **updates)
|
||||
updated_node = data_utils.get_display_data_single(
|
||||
self.columns, updated_node)
|
||||
|
||||
return (self.columns, updated_node)
|
||||
|
||||
|
||||
class NodeVmsList(NodeMixIn, base.BaseShowCommand):
|
||||
"""Show list vms for node."""
|
||||
|
||||
@@ -118,31 +154,82 @@ class NodeCreateVMsConf(NodeMixIn, base.BaseCommand):
|
||||
self.app.stdout.write(msg)
|
||||
|
||||
|
||||
class NodeUpdate(NodeMixIn, base.BaseShowCommand):
|
||||
"""Change given attributes for a node."""
|
||||
class NodeLabelList(NodeMixIn, base.BaseListCommand):
|
||||
"""Show list of all labels."""
|
||||
|
||||
columns = NodeShow.columns
|
||||
columns = (
|
||||
'node_id',
|
||||
'label_name',
|
||||
'label_value')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(NodeUpdate, self).get_parser(prog_name)
|
||||
parser = super(NodeLabelList, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument('-H',
|
||||
'--hostname',
|
||||
type=str,
|
||||
default=None,
|
||||
help='New hostname for node')
|
||||
parser.add_argument(
|
||||
'-n',
|
||||
'--nodes',
|
||||
nargs='+',
|
||||
help='Show labels for specific nodes')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
updates = {}
|
||||
for attr in self.client._updatable_attributes:
|
||||
if getattr(parsed_args, attr, None):
|
||||
updates[attr] = getattr(parsed_args, attr)
|
||||
data = self.client.get_all_labels_for_nodes(
|
||||
node_ids=parsed_args.nodes)
|
||||
data = data_utils.get_display_data_multi(self.columns, data)
|
||||
|
||||
updated_node = self.client.update(parsed_args.id,
|
||||
updates)
|
||||
updated_node = data_utils.get_display_data_single(self.columns,
|
||||
updated_node)
|
||||
return (self.columns, data)
|
||||
|
||||
return (self.columns, updated_node)
|
||||
|
||||
class NodeLabelSet(NodeMixIn, base.BaseCommand):
|
||||
"""Create or update specifc labels on nodes."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(NodeLabelSet, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'labels',
|
||||
nargs='+',
|
||||
help='List of labels for create or update')
|
||||
|
||||
parser.add_argument(
|
||||
'-n',
|
||||
'--nodes',
|
||||
nargs='+',
|
||||
help='Create or update labels only for specific nodes')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
data = self.client.set_labels_for_nodes(
|
||||
labels=parsed_args.labels, node_ids=parsed_args.nodes)
|
||||
msg = "Labels have been updated on nodes: {0} \n".format(
|
||||
','.join(data))
|
||||
self.app.stdout.write(msg)
|
||||
|
||||
|
||||
class NodeLabelDelete(NodeMixIn, base.BaseCommand):
|
||||
"""Delete specific labels on nodes."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(NodeLabelDelete, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'labels_keys',
|
||||
nargs='+',
|
||||
help='List of labels keys for delete')
|
||||
|
||||
parser.add_argument(
|
||||
'-n',
|
||||
'--nodes',
|
||||
nargs='+',
|
||||
help='Delete labels only for specific nodes')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
data = self.client.delete_labels_for_nodes(
|
||||
labels_keys=parsed_args.labels_keys, node_ids=parsed_args.nodes)
|
||||
msg = "Labels have been deleted on nodes: {0} \n".format(
|
||||
','.join(data))
|
||||
self.app.stdout.write(msg)
|
||||
|
||||
@@ -57,6 +57,10 @@ class Node(BaseObject):
|
||||
data = self.get_fresh_data()
|
||||
return data["progress"]
|
||||
|
||||
@property
|
||||
def labels(self):
|
||||
return self.get_fresh_data().get('labels', {})
|
||||
|
||||
def get_attribute_default_url(self, attributes_type):
|
||||
url_path, default_url_path = self.attributes_urls[attributes_type]
|
||||
return "nodes/{0}/{1}/{2}".format(self.id, url_path, default_url_path)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
def get_fake_node(cluster=None, hostname=None, node_id=None, cpu_model=None,
|
||||
roles=None, mac=None, memory_b=None, os_platform=None,
|
||||
status=None, node_name=None, group_id=None):
|
||||
status=None, node_name=None, group_id=None, labels=None):
|
||||
"""Creates a fake node
|
||||
|
||||
Returns the serialized and parametrized representation of a dumped Fuel
|
||||
@@ -25,6 +25,11 @@ def get_fake_node(cluster=None, hostname=None, node_id=None, cpu_model=None,
|
||||
|
||||
"""
|
||||
host_name = hostname or 'fake-node-42'
|
||||
labels = labels or {
|
||||
'key_1': 'val_1',
|
||||
'key_2': None,
|
||||
'key_3': 'val_3'
|
||||
}
|
||||
|
||||
return {'name': node_name or host_name,
|
||||
'error_type': None,
|
||||
@@ -125,4 +130,5 @@ def get_fake_node(cluster=None, hostname=None, node_id=None, cpu_model=None,
|
||||
'vlan': None},
|
||||
|
||||
{'dev': 'eth0',
|
||||
'name': 'admin'}]}
|
||||
'name': 'admin'}],
|
||||
'labels': labels}
|
||||
|
||||
@@ -36,7 +36,8 @@ class TestNodeCommand(test_engine.BaseCLITest):
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.get_all.assert_called_once_with(environment_id=None)
|
||||
self.m_client.get_all.assert_called_once_with(
|
||||
environment_id=None, labels=None)
|
||||
|
||||
def test_node_list_with_env(self):
|
||||
env_id = 42
|
||||
@@ -45,7 +46,31 @@ class TestNodeCommand(test_engine.BaseCLITest):
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.get_all.assert_called_once_with(environment_id=env_id)
|
||||
self.m_client.get_all.assert_called_once_with(
|
||||
environment_id=env_id, labels=None)
|
||||
|
||||
def test_node_list_with_labels(self):
|
||||
labels = ['key_1=val_1', 'key_2=val_2']
|
||||
args = 'node list --labels {labels}'.format(
|
||||
labels=' '.join(labels))
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.get_all.assert_called_once_with(
|
||||
environment_id=None, labels=labels)
|
||||
|
||||
def test_node_list_with_env_and_labels(self):
|
||||
env_id = 42
|
||||
labels = ["key_1=val_1", "key_2=val_2"]
|
||||
args = 'node list --env {env} --labels {labels}'.format(
|
||||
env=env_id, labels=' '.join(labels))
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.get_all.assert_called_once_with(
|
||||
environment_id=env_id, labels=labels)
|
||||
|
||||
def test_node_show(self):
|
||||
node_id = 42
|
||||
@@ -97,4 +122,70 @@ class TestNodeCommand(test_engine.BaseCLITest):
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.update.assert_called_once_with(
|
||||
node_id, {"hostname": hostname})
|
||||
node_id, **{"hostname": hostname})
|
||||
|
||||
def test_node_label_list_for_all_nodes(self):
|
||||
args = 'node label list'
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.get_all_labels_for_nodes.assert_called_once_with(
|
||||
node_ids=None)
|
||||
|
||||
def test_node_label_list_for_specific_nodes(self):
|
||||
node_ids = ['42', '43']
|
||||
args = 'node label list --nodes {node_ids}'.format(
|
||||
node_ids=' '.join(node_ids))
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.get_all_labels_for_nodes.assert_called_once_with(
|
||||
node_ids=node_ids)
|
||||
|
||||
def test_node_label_set_for_all_nodes(self):
|
||||
labels = ['key_1=val_1', 'key_2=val_2']
|
||||
args = 'node label set {labels}'.format(
|
||||
labels=' '.join(labels))
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.set_labels_for_nodes.assert_called_once_with(
|
||||
labels=labels, node_ids=None)
|
||||
|
||||
def test_node_label_set_for_specific_nodes(self):
|
||||
labels = ['key_1=val_1', 'key_2=val_2']
|
||||
node_ids = ['42', '43']
|
||||
args = 'node label set {labels} --nodes {node_ids}'.format(
|
||||
labels=' '.join(labels), node_ids=' '.join(node_ids))
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.set_labels_for_nodes.assert_called_once_with(
|
||||
labels=labels, node_ids=node_ids)
|
||||
|
||||
def test_node_label_delete_for_all_nodes(self):
|
||||
labels_keys = ['key_1', 'key_2']
|
||||
args = 'node label delete {labels_keys}'.format(
|
||||
labels_keys=' '.join(labels_keys))
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.delete_labels_for_nodes.assert_called_once_with(
|
||||
labels_keys=labels_keys, node_ids=None)
|
||||
|
||||
def test_node_label_delete_for_specific_nodes(self):
|
||||
labels_keys = ['key_1', 'key_2']
|
||||
node_ids = ['42', '43']
|
||||
args = 'node label delete {labels_keys} --nodes {node_ids}'.format(
|
||||
labels_keys=' '.join(labels_keys), node_ids=' '.join(node_ids))
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('node', mock.ANY)
|
||||
self.m_client.delete_labels_for_nodes.assert_called_once_with(
|
||||
labels_keys=labels_keys, node_ids=node_ids)
|
||||
|
||||
@@ -87,3 +87,121 @@ class TestNodeFacade(test_api.BaseLibTest):
|
||||
|
||||
self.assertTrue(matcher.called)
|
||||
self.assertEqual(data, matcher.last_request.json())
|
||||
|
||||
def test_get_all_labels_for_all_nodes(self):
|
||||
matcher = self.m_request.get(self.res_uri, json=self.fake_nodes)
|
||||
self.client.get_all_labels_for_nodes()
|
||||
|
||||
self.assertTrue(matcher.called)
|
||||
|
||||
def test_set_labels_for_all_nodes(self):
|
||||
labels = ['key_1=val_1', 'key_2=val_2', 'key_3 = val_4']
|
||||
data = {'labels': {
|
||||
'key_1': 'val_1',
|
||||
'key_2': 'val_2',
|
||||
'key_3': 'val_4'
|
||||
}}
|
||||
|
||||
expected_uri = self.get_object_uri(self.res_uri, 42)
|
||||
|
||||
matcher_get = self.m_request.get(self.res_uri, json=self.fake_nodes)
|
||||
matcher_put = self.m_request.put(expected_uri, json=data)
|
||||
|
||||
self.client.set_labels_for_nodes(labels=labels)
|
||||
|
||||
self.assertTrue(matcher_get.called)
|
||||
self.assertTrue(matcher_put.called)
|
||||
self.assertEqual(data, matcher_put.last_request.json())
|
||||
|
||||
def test_set_labels_for_specific_nodes(self):
|
||||
labels = ['key_1=val_1', 'key_2=val_2', 'key_3 = val_4']
|
||||
node_ids = ['42']
|
||||
data = {'labels': {
|
||||
'key_1': 'val_1',
|
||||
'key_2': 'val_2',
|
||||
'key_3': 'val_4'
|
||||
}}
|
||||
expected_uri = self.get_object_uri(self.res_uri, 42)
|
||||
|
||||
matcher_get = self.m_request.get(expected_uri, json=self.fake_node)
|
||||
matcher_put = self.m_request.put(expected_uri, json=data)
|
||||
|
||||
self.client.set_labels_for_nodes(
|
||||
labels=labels, node_ids=node_ids)
|
||||
|
||||
self.assertTrue(matcher_get.called)
|
||||
self.assertTrue(matcher_put.called)
|
||||
self.assertEqual(data, matcher_put.last_request.json())
|
||||
|
||||
def test_delete_labels_for_all_nodes(self):
|
||||
labels_keys = ['key_1', ' key_3 ']
|
||||
data = {'labels': {'key_2': None}}
|
||||
expected_uri = self.get_object_uri(self.res_uri, 42)
|
||||
|
||||
matcher_get = self.m_request.get(self.res_uri, json=self.fake_nodes)
|
||||
matcher_put = self.m_request.put(expected_uri, json=data)
|
||||
|
||||
self.client.delete_labels_for_nodes(labels_keys=labels_keys)
|
||||
|
||||
self.assertTrue(matcher_get.called)
|
||||
self.assertTrue(matcher_put.called)
|
||||
self.assertEqual(data, matcher_put.last_request.json())
|
||||
|
||||
def test_delete_labels_for_specific_nodes(self):
|
||||
labels_keys = ['key_2']
|
||||
node_ids = ['42']
|
||||
data = {'labels': {'key_1': 'val_1', 'key_3': 'val_3'}}
|
||||
expected_uri = self.get_object_uri(self.res_uri, 42)
|
||||
|
||||
matcher_get = self.m_request.get(expected_uri, json=self.fake_node)
|
||||
matcher_put = self.m_request.put(expected_uri, json=data)
|
||||
|
||||
self.client.delete_labels_for_nodes(
|
||||
labels_keys=labels_keys, node_ids=node_ids)
|
||||
|
||||
self.assertTrue(matcher_get.called)
|
||||
self.assertTrue(matcher_put.called)
|
||||
self.assertEqual(data, matcher_put.last_request.json())
|
||||
|
||||
def test_get_name_and_value_from_labels(self):
|
||||
for label in (
|
||||
'key=value',
|
||||
' key =value',
|
||||
'key= value ',
|
||||
' key = value ',
|
||||
):
|
||||
name, value = self.client._split_label(label)
|
||||
self.assertEqual(name, 'key')
|
||||
self.assertEqual(value, 'value')
|
||||
|
||||
def test_get_name_and_empty_value_from_lables(self):
|
||||
for label in (
|
||||
'key=',
|
||||
' key =',
|
||||
'key= ',
|
||||
' key = ',
|
||||
):
|
||||
name, value = self.client._split_label(label)
|
||||
self.assertEqual(name, 'key')
|
||||
self.assertIsNone(value)
|
||||
|
||||
def test_labels_after_delete(self):
|
||||
all_labels = {
|
||||
'label_A': 'A',
|
||||
'label_B': None,
|
||||
'label_C': 'C',
|
||||
'label_D': None,
|
||||
}
|
||||
expected_labels = {
|
||||
'label_A': 'A',
|
||||
'label_D': None,
|
||||
}
|
||||
|
||||
for labels_to_delete in (
|
||||
('label_B', 'label_C'),
|
||||
(' label_B', 'label_C '),
|
||||
('label_B', 'label_C ', 'unknown_label'),
|
||||
):
|
||||
result = self.client._labels_after_delete(
|
||||
all_labels, labels_to_delete)
|
||||
self.assertEqual(result, expected_labels)
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
from functools import partial
|
||||
|
||||
import six
|
||||
|
||||
from fuelclient.cli import error
|
||||
@@ -21,14 +25,26 @@ from fuelclient.v1 import base_v1
|
||||
class NodeClient(base_v1.BaseV1Client):
|
||||
|
||||
_entity_wrapper = objects.Node
|
||||
_updatable_attributes = ('hostname',)
|
||||
_updatable_attributes = ('hostname', 'labels')
|
||||
|
||||
def get_all(self, environment_id=None):
|
||||
def get_all(self, environment_id=None, labels=None):
|
||||
"""Get nodes by specific environment or labels
|
||||
|
||||
:param environment_id: Id of specific environment(cluster)
|
||||
:type environment_id: int
|
||||
:param labels: List of string labels for filtering nodes
|
||||
:type labels: list
|
||||
:returns: list -- filtered list of nodes
|
||||
"""
|
||||
result = self._entity_wrapper.get_all_data()
|
||||
|
||||
if environment_id is not None:
|
||||
result = filter(lambda n: n['cluster'] == environment_id, result)
|
||||
|
||||
if labels:
|
||||
result = filter(
|
||||
partial(self._check_label, labels), result)
|
||||
|
||||
return result
|
||||
|
||||
def get_node_vms_conf(self, node_id):
|
||||
@@ -40,14 +56,139 @@ class NodeClient(base_v1.BaseV1Client):
|
||||
return node.node_vms_create(config)
|
||||
|
||||
def update(self, node_id, **updated_attributes):
|
||||
node = self._entity_wrapper(obj_id=node_id)
|
||||
|
||||
for attr in six.iterkeys(updated_attributes):
|
||||
if attr not in self._updatable_attributes:
|
||||
msg = 'Only {0} are updatable'.format(
|
||||
self._updatable_attributes)
|
||||
raise error.ArgumentException(msg)
|
||||
node = self._entity_wrapper(obj_id=node_id)
|
||||
|
||||
return node.set(updated_attributes)
|
||||
|
||||
def get_all_labels_for_nodes(self, node_ids=None):
|
||||
"""Get list of labels for specific nodes. If no node_ids then all
|
||||
labels should be returned
|
||||
|
||||
:param node_ids: List of node ids for filtering labels
|
||||
:type node_ids: list
|
||||
:returns: list -- filtered list of labels
|
||||
"""
|
||||
labels = []
|
||||
|
||||
result = self._entity_wrapper.get_all_data()
|
||||
|
||||
if node_ids:
|
||||
result = filter(lambda node: str(node['id']) in node_ids, result)
|
||||
|
||||
for node in result:
|
||||
for key, value in six.iteritems(node.get('labels', [])):
|
||||
labels.append({
|
||||
'node_id': node.get('id'),
|
||||
'label_name': key,
|
||||
'label_value': value
|
||||
})
|
||||
|
||||
labels = sorted(labels, key=lambda label: label.get('node_id'))
|
||||
|
||||
return labels
|
||||
|
||||
def set_labels_for_nodes(self, labels=None, node_ids=None):
|
||||
"""Update nodes labels attribute with new data. If node_ids
|
||||
are empty list then labels will be updated on all nodes
|
||||
|
||||
:param labels: List of string pairs `key=val` for labels
|
||||
:type labels: list
|
||||
:param node_ids: List of node ids where labels should be updated
|
||||
:type node_ids: list
|
||||
:return: list -- ids of nodes where labels were updated
|
||||
"""
|
||||
data_to_return = []
|
||||
labels_to_update = {}
|
||||
|
||||
for label in labels:
|
||||
key, val = self._split_label(label)
|
||||
labels_to_update[key] = val
|
||||
|
||||
if node_ids:
|
||||
for node_id in node_ids:
|
||||
node = self._entity_wrapper(obj_id=node_id)
|
||||
db_labels = copy.deepcopy(node.labels)
|
||||
db_labels.update(labels_to_update)
|
||||
|
||||
result = self.update(node_id, **{'labels': db_labels})
|
||||
data_to_return.append(str(result.get('id')))
|
||||
else:
|
||||
nodes = self._entity_wrapper.get_all_data()
|
||||
for node in nodes:
|
||||
db_labels = copy.deepcopy(node['labels'])
|
||||
db_labels.update(labels_to_update)
|
||||
|
||||
result = self.update(node['id'], **{'labels': db_labels})
|
||||
data_to_return.append(str(result.get('id')))
|
||||
|
||||
return data_to_return
|
||||
|
||||
def delete_labels_for_nodes(self, labels_keys=None, node_ids=None):
|
||||
"""Delete labels data from nodes labels. If node_ids are
|
||||
empty list then labels will be deleted on all nodes
|
||||
|
||||
:param labels: List of string label keys
|
||||
:type labels: list
|
||||
:param node_ids: List of node ids where labels should be deleted
|
||||
:type node_ids: list
|
||||
:returns: list -- ids of nodes where labels were deleted
|
||||
"""
|
||||
data_to_return = []
|
||||
|
||||
if node_ids:
|
||||
for node_id in node_ids:
|
||||
node = self._entity_wrapper(obj_id=node_id)
|
||||
updated_labels = self._labels_after_delete(
|
||||
node.labels, labels_keys)
|
||||
|
||||
result = self.update(node_id, **{'labels': updated_labels})
|
||||
data_to_return.append(str(result.get('id')))
|
||||
else:
|
||||
nodes = self._entity_wrapper.get_all_data()
|
||||
for node in nodes:
|
||||
updated_labels = self._labels_after_delete(
|
||||
node['labels'], labels_keys)
|
||||
|
||||
result = self.update(node['id'], **{'labels': updated_labels})
|
||||
data_to_return.append(str(result.get('id')))
|
||||
|
||||
return data_to_return
|
||||
|
||||
def _check_label(self, labels, item):
|
||||
checking_list = []
|
||||
|
||||
for label in labels:
|
||||
key, val = self._split_label(label)
|
||||
|
||||
if key in item.get('labels'):
|
||||
checking_val = item['labels'][key] == val
|
||||
checking_list.append(checking_val)
|
||||
|
||||
return True in checking_list
|
||||
|
||||
@staticmethod
|
||||
def _labels_after_delete(labels, labels_keys):
|
||||
db_labels = copy.deepcopy(labels)
|
||||
for label_key in labels_keys:
|
||||
label_key = label_key.strip()
|
||||
db_labels.pop(label_key, None)
|
||||
|
||||
return db_labels
|
||||
|
||||
@staticmethod
|
||||
def _split_label(label):
|
||||
name, value = label.split('=')
|
||||
name = name.strip()
|
||||
value = value.strip()
|
||||
value = None if value == '' else value
|
||||
return name, value
|
||||
|
||||
|
||||
def get_client():
|
||||
return NodeClient()
|
||||
|
||||
@@ -42,6 +42,9 @@ fuelclient =
|
||||
node_list-vms-conf=fuelclient.commands.node:NodeVmsList
|
||||
node_create-vms-conf=fuelclient.commands.node:NodeCreateVMsConf
|
||||
node_update=fuelclient.commands.node:NodeUpdate
|
||||
node_label_list=fuelclient.commands.node:NodeLabelList
|
||||
node_label_set=fuelclient.commands.node:NodeLabelSet
|
||||
node_label_delete=fuelclient.commands.node:NodeLabelDelete
|
||||
task_list=fuelclient.commands.task:TaskList
|
||||
task_show=fuelclient.commands.task:TaskShow
|
||||
fuel-version=fuelclient.commands.fuelversion:FuelVersion
|
||||
|
||||
Reference in New Issue
Block a user