From 400166cbda4516bcb28f7200e805790aaa530de7 Mon Sep 17 00:00:00 2001 From: Vasyl Saienko Date: Wed, 11 Jan 2017 14:18:17 +0200 Subject: [PATCH] Extend VIF attach commands This patch update VIF attach commands to allow setting custom keys by using --vif-info option. Related-Bug: #1582188 Change-Id: I3b638693e981781d0ddcf6dd8fe75556ff24e428 --- ironicclient/osc/v1/baremetal_node.py | 12 ++++++++- .../tests/unit/osc/v1/test_baremetal_node.py | 12 +++++++++ ironicclient/tests/unit/v1/test_node.py | 25 +++++++++++++++++++ ironicclient/tests/unit/v1/test_node_shell.py | 10 ++++++++ ironicclient/v1/node.py | 8 +++++- ironicclient/v1/node_shell.py | 10 ++++++-- ...-vif-attach-commands-ef3a931413ddcee7.yaml | 6 +++++ 7 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/extend-vif-attach-commands-ef3a931413ddcee7.yaml diff --git a/ironicclient/osc/v1/baremetal_node.py b/ironicclient/osc/v1/baremetal_node.py index cd8f34500..b5a611f7a 100644 --- a/ironicclient/osc/v1/baremetal_node.py +++ b/ironicclient/osc/v1/baremetal_node.py @@ -1196,13 +1196,23 @@ class VifAttachBaremetalNode(command.Command): metavar='', help="Name or UUID of the VIF to attach to a node." ) + parser.add_argument( + '--vif-info', + metavar='', + action='append', + help="Record arbitrary key/value metadata. " + "Can be specified multiple times. The mandatory 'id' " + "parameter cannot be specified as a key.") return parser def take_action(self, parsed_args): self.log.debug("take_action(%s)", parsed_args) baremetal_client = self.app.client_manager.baremetal - baremetal_client.node.vif_attach(parsed_args.node, parsed_args.vif_id) + + fields = utils.key_value_pairs_to_dict(parsed_args.vif_info or []) + baremetal_client.node.vif_attach(parsed_args.node, parsed_args.vif_id, + **fields) class VifDetachBaremetalNode(command.Command): diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_node.py b/ironicclient/tests/unit/osc/v1/test_baremetal_node.py index 02e258810..e2ba9e791 100644 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_node.py +++ b/ironicclient/tests/unit/osc/v1/test_baremetal_node.py @@ -1777,6 +1777,18 @@ class TestVifAttach(TestBaremetal): self.baremetal_mock.node.vif_attach.assert_called_once_with( 'node_uuid', 'aaa-aaa') + def test_baremetal_vif_attach_custom_fields(self): + arglist = ['node_uuid', 'aaa-aaa', '--vif-info', 'foo=bar'] + verifylist = [('node', 'node_uuid'), + ('vif_id', 'aaa-aaa'), + ('vif_info', ['foo=bar'])] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.cmd.take_action(parsed_args) + + self.baremetal_mock.node.vif_attach.assert_called_once_with( + 'node_uuid', 'aaa-aaa', foo='bar') + class TestVifDetach(TestBaremetal): def setUp(self): diff --git a/ironicclient/tests/unit/v1/test_node.py b/ironicclient/tests/unit/v1/test_node.py index ed4af47d6..e14da3cf1 100644 --- a/ironicclient/tests/unit/v1/test_node.py +++ b/ironicclient/tests/unit/v1/test_node.py @@ -1113,6 +1113,31 @@ class NodeManagerTest(testtools.TestCase): update_mock.assert_called_once_with(final_path, {'id': 'vif_id'}, http_method="POST") + @mock.patch.object(node.NodeManager, 'update') + def test_vif_attach_custom_fields(self, update_mock): + kwargs = { + 'node_ident': NODE1['uuid'], + 'vif_id': 'vif_id', + 'foo': 'bar', + } + + final_path = '%s/vifs' % NODE1['uuid'] + self.mgr.vif_attach(**kwargs) + update_mock.assert_called_once_with( + final_path, {'id': 'vif_id', 'foo': 'bar'}, + http_method="POST") + + @mock.patch.object(node.NodeManager, 'update') + def test_vif_attach_custom_fields_id(self, update_mock): + kwargs = { + 'node_ident': NODE1['uuid'], + 'vif_id': 'vif_id', + 'id': 'bar', + } + self.assertRaises( + exc.InvalidAttribute, + self.mgr.vif_attach, **kwargs) + @mock.patch.object(node.NodeManager, 'delete') def test_vif_detach(self, delete_mock): kwargs = { diff --git a/ironicclient/tests/unit/v1/test_node_shell.py b/ironicclient/tests/unit/v1/test_node_shell.py index fc38cd362..55a6496d9 100644 --- a/ironicclient/tests/unit/v1/test_node_shell.py +++ b/ironicclient/tests/unit/v1/test_node_shell.py @@ -1145,6 +1145,16 @@ class NodeShellTest(utils.BaseTestCase): client_mock.node.vif_attach.assert_called_once_with( 'node_uuid', 'aaa-aaa') + def test_do_node_vif_attach_custom_fields(self): + client_mock = mock.MagicMock() + args = mock.MagicMock() + args.node = 'node_uuid' + args.vif_id = 'aaa-aaa' + args.vif_info = ['aaa=bbb', 'ccc=ddd'] + n_shell.do_node_vif_attach(client_mock, args) + client_mock.node.vif_attach.assert_called_once_with( + 'node_uuid', 'aaa-aaa', aaa='bbb', ccc='ddd') + def test_do_node_vif_detach(self): client_mock = mock.MagicMock() args = mock.MagicMock() diff --git a/ironicclient/v1/node.py b/ironicclient/v1/node.py index 9a6e051e9..c6af933c7 100644 --- a/ironicclient/v1/node.py +++ b/ironicclient/v1/node.py @@ -253,14 +253,20 @@ class NodeManager(base.CreateManager): return self._list(self._path(path), "vifs") - def vif_attach(self, node_ident, vif_id): + def vif_attach(self, node_ident, vif_id, **kwargs): """Attach VIF to a given node. param node_ident: The UUID or Name of the node. param vif_id: The UUID or Name of the VIF to attach. + :param kwargs: A dictionary containing the attributes of the resource + that will be created. """ path = "%s/vifs" % node_ident data = {"id": vif_id} + if 'id' in kwargs: + raise exc.InvalidAttribute("The attribute 'id' can't be " + "specified in vif-info") + data.update(kwargs) # TODO(vdrok): cleanup places doing custom path and http_method self.update(path, data, http_method="POST") diff --git a/ironicclient/v1/node_shell.py b/ironicclient/v1/node_shell.py index d94de004d..b43fe9e79 100644 --- a/ironicclient/v1/node_shell.py +++ b/ironicclient/v1/node_shell.py @@ -615,9 +615,15 @@ def do_node_vif_list(cc, args): @cliutils.arg('node', metavar='', help="Name or UUID of the node.") @cliutils.arg('vif_id', metavar='', help="Name or UUID of the VIF to attach to node.") +@cliutils.arg('--vif-info', metavar='', + action='append', + help="Record arbitrary key/value metadata. " + "Can be specified multiple times. The mandatory 'id' " + "parameter cannot be specified as a key.") def do_node_vif_attach(cc, args): - """Attach VIF to a given node.""" - cc.node.vif_attach(args.node, args.vif_id) + """List vifs for a given node.""" + fields = utils.key_value_pairs_to_dict(args.vif_info or []) + cc.node.vif_attach(args.node, args.vif_id, **fields) @cliutils.arg('node', metavar='', help="Name or UUID of the node.") diff --git a/releasenotes/notes/extend-vif-attach-commands-ef3a931413ddcee7.yaml b/releasenotes/notes/extend-vif-attach-commands-ef3a931413ddcee7.yaml new file mode 100644 index 000000000..01bc3ba94 --- /dev/null +++ b/releasenotes/notes/extend-vif-attach-commands-ef3a931413ddcee7.yaml @@ -0,0 +1,6 @@ +--- +features: + - Adds ability to set custom VIF information fields via the `--vif-info ` + option in the `ironic node-vif-attach` and `openstack baremetal node vif attach` + commands. +