Add node attributes commannds to CLI v2

Add commands that allow to download and upload node attributes
for specified nodes:
    fuel node attributes-download [--dir DIR] NODE_ID
    fuel node attributes-upload [--dir DIR] NODE_ID

Change-Id: I347f3bc201926784e453d25bffe898090ba82e49
Implements: blueprint support-numa-cpu-pinning
This commit is contained in:
Alexander Saprykin
2016-02-16 11:20:40 +02:00
parent 36ab43141c
commit ab72c654e2
5 changed files with 118 additions and 0 deletions

View File

@@ -263,3 +263,44 @@ class NodeLabelDelete(NodeMixIn, base.BaseCommand):
msg = "Labels have been deleted on nodes: {0} \n".format(
','.join(data))
self.app.stdout.write(msg)
class NodeAttributesDownload(NodeMixIn, base.BaseCommand):
"""Download node attributes."""
def get_parser(self, prog_name):
parser = super(NodeAttributesDownload, self).get_parser(prog_name)
parser.add_argument(
'id', type=int, help='Node ID')
parser.add_argument(
'--dir', type=str, help='Directory to save attributes')
return parser
def take_action(self, parsed_args):
file_path = self.client.download_attributes(
parsed_args.id, parsed_args.dir)
self.app.stdout.write(
"Attributes for node {0} were written to {1}"
.format(parsed_args.id, file_path))
class NodeAttributesUpload(NodeMixIn, base.BaseCommand):
"""Upload node attributes."""
def get_parser(self, prog_name):
parser = super(NodeAttributesUpload, self).get_parser(prog_name)
parser.add_argument(
'id', type=int, help='Node ID')
parser.add_argument(
'--dir', type=str, help='Directory to read attributes from')
return parser
def take_action(self, parsed_args):
self.client.upload_attributes(parsed_args.id, parsed_args.dir)
self.app.stdout.write(
"Attributes for node {0} were uploaded."
.format(parsed_args.id))

View File

@@ -270,3 +270,19 @@ 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=labels_expected, node_ids=node_ids)
def test_node_attributes_download(self):
args = 'node attributes-download 42'
self.exec_command(args)
self.m_get_client.assert_called_once_with('node', mock.ANY)
self.m_client.download_attributes.assert_called_once_with(42, None)
def test_node_attributes_upload(self):
args = 'node attributes-upload 42'
self.exec_command(args)
self.m_get_client.assert_called_once_with('node', mock.ANY)
self.m_client.upload_attributes.assert_called_once_with(42, None)

View File

@@ -15,9 +15,11 @@
# under the License.
import mock
import yaml
import fuelclient
from fuelclient.cli import error
from fuelclient.cli import serializers
from fuelclient.objects import base as base_object
from fuelclient.tests.unit.v2.lib import test_api
from fuelclient.tests import utils
@@ -334,3 +336,49 @@ class TestNodeFacade(test_api.BaseLibTest):
node_id = 42
self.assertRaises(error.BadDataException,
self.client.update, node_id, status=42)
@mock.patch('fuelclient.objects.node.os.mkdir', mock.Mock())
def test_node_attributes_download(self):
node_id = 42
expected_uri = self.get_object_uri(
self.res_uri, node_id, '/attributes/')
fake_attributes = {
'attribute_name': 'attribute_value'
}
m_get = self.m_request.get(expected_uri, json=fake_attributes)
m_open = mock.mock_open()
with mock.patch('fuelclient.cli.serializers.open',
m_open, create=True):
self.client.download_attributes(node_id, directory='/fake/dir')
self.assertTrue(m_get.called)
m_open.assert_called_once_with(
'/fake/dir/node_{0}/attributes.yaml'.format(node_id), mock.ANY)
serializer = serializers.Serializer()
m_open().write.assert_called_once_with(
serializer.serialize(fake_attributes))
@mock.patch('fuelclient.objects.node.os.path.exists',
mock.Mock(return_value=True))
def test_node_attribute_upload(self):
node_id = 42
expected_uri = self.get_object_uri(
self.res_uri, node_id, '/attributes/')
fake_attributes = {
'attribute_name': 'attribute_value'
}
m_put = self.m_request.put(expected_uri, json=fake_attributes)
m_open = mock.mock_open(read_data=yaml.safe_dump(fake_attributes))
with mock.patch('fuelclient.cli.serializers.open',
m_open, create=True):
self.client.upload_attributes(node_id, directory='/fake/dir')
self.assertTrue(m_put.called)
m_open.assert_called_once_with(
'/fake/dir/node_{0}/attributes.yaml'.format(node_id), mock.ANY)
self.assertEqual(m_put.last_request.json(), fake_attributes)
m_open().read.assert_called_once_with()

View File

@@ -162,6 +162,17 @@ class NodeClient(base_v1.BaseV1Client):
return data_to_return
def download_attributes(self, node_id, directory=None):
node = self._entity_wrapper(node_id)
attributes = node.get_node_attributes()
return node.write_attribute(
'attributes', attributes, directory=directory)
def upload_attributes(self, node_id, directory=None):
node = self._entity_wrapper(node_id)
attributes = node.read_attribute('attributes', directory=directory)
node.update_node_attributes(attributes)
def _check_label(self, labels, item):
checking_list = []

View File

@@ -47,6 +47,8 @@ fuelclient =
network-template_delete=fuelclient.commands.network_template:NetworkTemplateDelete
network-template_download=fuelclient.commands.network_template:NetworkTemplateDownload
network-template_upload=fuelclient.commands.network_template:NetworkTemplateUpload
node_attributes-download=fuelclient.commands.node:NodeAttributesDownload
node_attributes-upload=fuelclient.commands.node:NodeAttributesUpload
node_create-vms-conf=fuelclient.commands.node:NodeCreateVMsConf
node_label_delete=fuelclient.commands.node:NodeLabelDelete
node_label_list=fuelclient.commands.node:NodeLabelList