Allow deleting node labels by their values

Usage for deleting node labels by value:
fuel2 node label delete (-n NODES [NODES ...] | --nodes-all)
(label | label=value) [(label | label=value)]

Change-Id: I119d137f3486c5692388a9ac08ae25df2f19ebee
Closes-Bug: #1477590
This commit is contained in:
Maciej Kwiek
2015-08-10 15:06:14 +02:00
parent 26fc025e0f
commit 0ef755c767
3 changed files with 72 additions and 15 deletions

View File

@@ -209,3 +209,28 @@ class TestNodeCommand(test_engine.BaseCLITest):
self.m_get_client.assert_called_once_with('node', mock.ANY)
self.m_client.delete_labels_for_nodes.assert_called_once_with(
labels=None, node_ids=node_ids)
def test_node_label_delete_by_value(self):
labels = ['key_1', 'key_2=value2']
node_ids = ['42', '43']
args = 'node label delete -l {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.delete_labels_for_nodes.assert_called_once_with(
labels=labels, node_ids=node_ids)
def test_node_label_delete_by_value_with_whitespace(self):
labels = ['key_1', "'key_2 =value2'"]
labels_expected = [x.strip("'") for x in labels]
node_ids = ['42', '43']
args = 'node label delete -l {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.delete_labels_for_nodes.assert_called_once_with(
labels=labels_expected, node_ids=node_ids)

View File

@@ -208,6 +208,36 @@ class TestNodeFacade(test_api.BaseLibTest):
self.assertTrue(matcher_put.called)
self.assertEqual(data, matcher_put.last_request.json())
def test_delete_labels_by_value(self):
labels = ['key_1=val_1', 'key_3=anothervalue', 'key_2']
node_ids = ['42']
result_labels = {'labels': {'key_3': 'val_3'}}
expected_uri = self.get_object_uri(self.res_uri, 42)
self.m_request.get(expected_uri, json=self.fake_node)
matcher_put = self.m_request.put(expected_uri, json=self.fake_node)
self.client.delete_labels_for_nodes(
labels=labels, node_ids=node_ids)
self.assertTrue(matcher_put.called)
self.assertEqual(result_labels, matcher_put.last_request.json())
def test_delete_labels_by_value_with_whitespace(self):
labels = ['key_1 =val_1', 'key_3= anothervalue', 'key_2']
node_ids = ['42']
result_labels = {'labels': {'key_3': 'val_3'}}
expected_uri = self.get_object_uri(self.res_uri, 42)
self.m_request.get(expected_uri, json=self.fake_node)
matcher_put = self.m_request.put(expected_uri, json=self.fake_node)
self.client.delete_labels_for_nodes(
labels=labels, node_ids=node_ids)
self.assertTrue(matcher_put.called)
self.assertEqual(result_labels, matcher_put.last_request.json())
def test_get_name_and_value_from_labels(self):
for label in (
'key=value',
@@ -265,6 +295,7 @@ class TestNodeFacade(test_api.BaseLibTest):
('label_B', 'label_C'),
(' label_B', 'label_C '),
('label_B', 'label_C ', 'unknown_label'),
('label_A = trololo', 'label_B=', 'label_C =C', 'label_D=value')
):
result = self.client._labels_after_delete(
all_labels, labels_to_delete)

View File

@@ -146,21 +146,17 @@ class NodeClient(base_v1.BaseV1Client):
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)
result = self.update(node_id, **{'labels': updated_labels})
data_to_return.append(str(result.get('id')))
nodes = (self._entity_wrapper(obj_id=n_id).data
for n_id in node_ids)
else:
nodes = self._entity_wrapper.get_all_data()
for node in nodes:
updated_labels = self._labels_after_delete(
node['labels'], labels)
result = self.update(node['id'], **{'labels': updated_labels})
data_to_return.append(str(result.get('id')))
for node in nodes:
updated_labels = self._labels_after_delete(
node['labels'], labels)
result = self.update(node['id'], **{'labels': updated_labels})
data_to_return.append(str(result.get('id')))
return data_to_return
@@ -178,15 +174,20 @@ class NodeClient(base_v1.BaseV1Client):
return any(checking_list)
@staticmethod
def _labels_after_delete(labels, labels_to_delete):
@classmethod
def _labels_after_delete(cls, labels, labels_to_delete):
if not labels_to_delete:
return {}
db_labels = copy.deepcopy(labels)
for label in labels_to_delete:
label = label.strip()
db_labels.pop(label, None)
sl = cls._split_label(label)
if sl.has_separator:
if sl.key in db_labels and db_labels[sl.key] == sl.value:
db_labels.pop(sl.key)
else:
db_labels.pop(sl.key, None)
return db_labels