From 58967b14bbab8dadcd4e6514bdb04dcf940461b3 Mon Sep 17 00:00:00 2001 From: Tzu-Mainn Chen Date: Fri, 17 Jan 2025 10:06:42 -0500 Subject: [PATCH] Adds esi node network show command --- esiclient/tests/unit/v1/test_node_network.py | 187 +++++++++++++++++++ esiclient/v1/node_network.py | 74 ++++++++ setup.cfg | 1 + 3 files changed, 262 insertions(+) diff --git a/esiclient/tests/unit/v1/test_node_network.py b/esiclient/tests/unit/v1/test_node_network.py index 910f520..3a58440 100644 --- a/esiclient/tests/unit/v1/test_node_network.py +++ b/esiclient/tests/unit/v1/test_node_network.py @@ -793,6 +793,193 @@ def test_take_action_long(self, mock_network_list, mock_get_network_display_name ) +class TestShow(base.TestCommand): + def setUp(self): + super(TestShow, self).setUp() + + self.port1 = utils.create_mock_object( + { + "id": "port_uuid_1", + "node_uuid": "11111111-2222-3333-4444-bbbbbbbbbbbb", + "address": "bb:bb:bb:bb:bb:bb", + "internal_info": {}, + } + ) + self.port2 = utils.create_mock_object( + { + "id": "port_uuid_2", + "node_uuid": "11111111-2222-3333-4444-bbbbbbbbbbbb", + "address": "ee:ee:ee:ee:ee:ee", + "internal_info": {"tenant_vif_port_id": "neutron_port_uuid"}, + } + ) + self.node = utils.create_mock_object( + {"id": "11111111-2222-3333-4444-bbbbbbbbbbbb", "name": "node2"} + ) + self.network1 = utils.create_mock_object( + { + "id": "network_uuid_1", + "name": "test_network_1", + "provider_segmentation_id": 100, + } + ) + self.network2 = utils.create_mock_object( + { + "id": "network_uuid_2", + "name": "test_network_2", + "provider_segmentation_id": 200, + } + ) + self.network3 = utils.create_mock_object( + { + "id": "network_uuid_3", + "name": "test_network_3", + "provider_segmentation_id": 300, + } + ) + self.neutron_port = utils.create_mock_object( + { + "id": "neutron_port_uuid", + "network_id": "network_uuid_3", + "name": "neutron_port_3", + "fixed_ips": [{"ip_address": "3.3.3.3"}], + "trunk_details": { + "trunk_id": "trunk_uuid", + "sub_ports": [ + {"port_id": "subport_uuid_1"}, + {"port_id": "subport_uuid_2"}, + ], + }, + } + ) + self.subport_1 = utils.create_mock_object( + { + "id": "subport_uuid_1", + "network_id": "network_uuid_1", + "name": "subport_1", + "fixed_ips": [{"ip_address": "4.4.4.4"}], + "trunk_details": None, + } + ) + self.subport_2 = utils.create_mock_object( + { + "id": "subport_uuid_2", + "network_id": "network_uuid_2", + "name": "subport_2", + "fixed_ips": [{"ip_address": "5.5.5.5"}], + "trunk_details": None, + } + ) + self.floating_network = utils.create_mock_object( + { + "id": "floating_network_id", + "name": "floating_network", + "provider_segmentation_id": 400, + } + ) + self.floating_ip = utils.create_mock_object( + { + "id": "floating_ip_uuid", + "floating_ip_address": "8.8.8.8", + "floating_network_id": "floating_network_id", + "port_id": "neutron_port_uuid", + } + ) + + self.cmd = node_network.Show(self.app, None) + + @mock.patch("esi.lib.nodes.network_list") + def test_take_action(self, mock_network_list): + mock_network_list.return_value = [ + { + "node": self.node, + "network_info": [ + { + "baremetal_port": self.port1, + "network_ports": [], + "networks": {"parent": None, "trunk": [], "floating": None}, + "floating_ip": None, + }, + { + "baremetal_port": self.port2, + "network_ports": [ + self.neutron_port, + self.subport_1, + self.subport_2, + ], + "networks": { + "parent": self.network3, + "trunk": [self.network1, self.network2], + "floating": self.floating_network, + }, + "floating_ip": self.floating_ip, + }, + ], + } + ] + + arglist = [self.node.name] + verifylist = [] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + results = self.cmd.take_action(parsed_args) + + expected = ( + [ + "Node", + "Node UUID", + "Node Ports", + ], + [ + "node2", + "11111111-2222-3333-4444-bbbbbbbbbbbb", + "[\n" + " {\n" + ' "mac_address": "bb:bb:bb:bb:bb:bb",\n' + ' "baremetal_port_uuid": "port_uuid_1"\n' + " },\n" + " {\n" + ' "mac_address": "ee:ee:ee:ee:ee:ee",\n' + ' "baremetal_port_uuid": "port_uuid_2",\n' + ' "network_port": {\n' + ' "name": "neutron_port_3",\n' + ' "uuid": "neutron_port_uuid",\n' + ' "fixed_ips": [\n' + ' "3.3.3.3"\n' + " ]\n" + " },\n" + ' "trunk_uuid": "trunk_uuid",\n' + ' "network": {\n' + ' "name": "test_network_3",\n' + ' "uuid": "network_uuid_3",\n' + ' "vlan_id": 300\n' + " },\n" + ' "floating_network": {\n' + ' "name": "floating_network",\n' + ' "uuid": "floating_network_id",\n' + ' "vlan_id": 400\n' + " },\n" + ' "trunk_networks": [\n' + " {\n" + ' "name": "test_network_1",\n' + ' "uuid": "network_uuid_1",\n' + ' "vlan_id": 100\n' + " },\n" + " {\n" + ' "name": "test_network_2",\n' + ' "uuid": "network_uuid_2",\n' + ' "vlan_id": 200\n' + " }\n" + " ]\n" + " }\n" + "]", + ], + ) + + mock_network_list.assert_called_once + self.assertEqual(expected, results) + + class TestAttach(base.TestCommand): def setUp(self): super(TestAttach, self).setUp() diff --git a/esiclient/v1/node_network.py b/esiclient/v1/node_network.py index 1fcd365..bcc4b68 100644 --- a/esiclient/v1/node_network.py +++ b/esiclient/v1/node_network.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import json import logging from osc_lib.command import command @@ -182,6 +183,79 @@ def take_action(self, parsed_args): return headers, data +class Show(command.ShowOne): + """Show network details for one node""" + + log = logging.getLogger(__name__ + ".Show") + + def get_parser(self, prog_name): + parser = super(Show, self).get_parser(prog_name) + parser.add_argument( + "node", metavar="", help=_("Name or UUID of the node") + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + node_networks = nodes.network_list( + self.app.client_manager.sdk_connection, parsed_args.node + ) + + node_network = node_networks[0] + node_ports = [] + for node_port in node_network["network_info"]: + node_port_info = { + "mac_address": node_port["baremetal_port"].address, + "baremetal_port_uuid": node_port["baremetal_port"].id, + } + if node_port["network_ports"]: + primary_port = node_port["network_ports"][0] + node_port_info["network_port"] = { + "name": primary_port.name, + "uuid": primary_port.id, + "fixed_ips": [ip["ip_address"] for ip in primary_port.fixed_ips], + } + if primary_port.trunk_details: + node_port_info["trunk_uuid"] = primary_port.trunk_details[ + "trunk_id" + ] + if node_port["networks"]["parent"]: + parent_network = node_port["networks"]["parent"] + node_port_info["network"] = { + "name": parent_network.name, + "uuid": parent_network.id, + "vlan_id": parent_network.provider_segmentation_id, + } + if node_port["networks"]["floating"]: + floating_network = node_port["networks"]["floating"] + node_port_info["floating_network"] = { + "name": floating_network.name, + "uuid": floating_network.id, + "vlan_id": floating_network.provider_segmentation_id, + } + trunk_network_list = [] + for trunk_network in node_port["networks"]["trunk"]: + trunk_network_list.append( + { + "name": trunk_network.name, + "uuid": trunk_network.id, + "vlan_id": trunk_network.provider_segmentation_id, + } + ) + if trunk_network_list: + node_port_info["trunk_networks"] = trunk_network_list + + node_ports.append(node_port_info) + + return ["Node", "Node UUID", "Node Ports"], [ + node_network["node"].name, + node_network["node"].id, + node_ports + if parsed_args.formatter != "table" + else json.dumps(node_ports, indent=2), + ] + + class Attach(command.ShowOne): """Attach network to node""" diff --git a/setup.cfg b/setup.cfg index 6efb0bc..1a285f1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -35,6 +35,7 @@ openstack.esiclient.v1 = esi_node_network_attach = esiclient.v1.node_network:Attach esi_node_network_detach = esiclient.v1.node_network:Detach esi_node_network_list = esiclient.v1.node_network:List + esi_node_network_show = esiclient.v1.node_network:Show esi_node_volume_attach = esiclient.v1.node_volume:Attach esi_cluster_list = esiclient.v1.cluster.cluster:List esi_cluster_orchestrate = esiclient.v1.cluster.cluster:Orchestrate