diff --git a/esiclient/tests/unit/v1/test_node_network.py b/esiclient/tests/unit/v1/test_node_network.py index 3d603e7..7ca6f9e 100644 --- a/esiclient/tests/unit/v1/test_node_network.py +++ b/esiclient/tests/unit/v1/test_node_network.py @@ -13,7 +13,7 @@ import mock -from osc_lib import exceptions +from openstack import exceptions from esiclient.tests.unit import base from esiclient.tests.unit import utils @@ -650,30 +650,13 @@ def setUp(self): "name": "test_trunk" }) - self.app.client_manager.network.find_network.\ - return_value = self.network - self.app.client_manager.network.get_network.\ - return_value = self.network - self.app.client_manager.network.create_port.\ - return_value = self.neutron_port - self.app.client_manager.network.find_port.\ - return_value = self.neutron_port - self.app.client_manager.network.get_port.\ - return_value = self.neutron_port - self.app.client_manager.network.ports.\ - return_value = [] - self.app.client_manager.network.find_trunk.\ - return_value = self.trunk - - @mock.patch('esiclient.utils.get_full_network_info_from_port', - return_value=(["test_network"], ["node1-port"], - ["2.2.2.2"]), - autospec=True) + @mock.patch('esi.lib.nodes.network_attach') def test_take_action_network(self, mock_gfnifp): - self.app.client_manager.baremetal.node.get.\ - return_value = self.node - self.app.client_manager.baremetal.port.list.\ - return_value = [self.port1, self.port2] + mock_gfnifp.return_value = { + 'node': self.node, + 'ports': [self.neutron_port], + 'networks': [self.network] + } arglist = ['node1', '--network', 'test_network'] verifylist = [] @@ -681,57 +664,53 @@ def test_take_action_network(self, mock_gfnifp): parsed_args = self.check_parser(self.cmd, arglist, verifylist) results = self.cmd.take_action(parsed_args) + expected = ( ["Node", "MAC Address", "Port", "Network", "Fixed IP"], ["node1", "bb:bb:bb:bb:bb:bb", "node1-port", "test_network", "2.2.2.2"] ) + + mock_gfnifp.assert_called_once_with( + self.app.client_manager.sdk_connection, + 'node1', + {'network': 'test_network'}) self.assertEqual(expected, results) - self.app.client_manager.network.create_port.\ - assert_called_once_with(name='esi-node1-test_network', - network_id=self.network.id, - device_owner='baremetal:none') - self.app.client_manager.baremetal.node.vif_attach.\ - assert_called_once_with('node1', self.neutron_port.id) - mock_gfnifp.assert_called_once - - @mock.patch('esiclient.utils.get_full_network_info_from_port', - return_value=(["test_network"], ["node1-port"], - ["2.2.2.2"]), - autospec=True) + + @mock.patch('esi.lib.nodes.network_attach') def test_take_action_port(self, mock_gfnifp): - self.app.client_manager.baremetal.node.get.\ - return_value = self.node - self.app.client_manager.baremetal.port.list.\ - return_value = [self.port1, self.port2] + mock_gfnifp.return_value = { + 'node': self.node, + 'ports': [self.neutron_port], + 'networks': [self.network] + } - arglist = ['node1', '--port', 'node1-port'] + arglist = ['node_uuid_1', '--port', 'node1-port'] verifylist = [] parsed_args = self.check_parser(self.cmd, arglist, verifylist) results = self.cmd.take_action(parsed_args) + expected = ( ["Node", "MAC Address", "Port", "Network", "Fixed IP"], ["node1", "bb:bb:bb:bb:bb:bb", "node1-port", "test_network", "2.2.2.2"] ) + + mock_gfnifp.assert_called_once_with( + self.app.client_manager.sdk_connection, + 'node_uuid_1', + {'port': 'node1-port'}) self.assertEqual(expected, results) - self.app.client_manager.network.find_port.\ - assert_called_once_with("node1-port") - self.app.client_manager.baremetal.node.vif_attach.\ - assert_called_once_with('node1', self.neutron_port.id) - mock_gfnifp.assert_called_once - - @mock.patch('esiclient.utils.get_full_network_info_from_port', - return_value=(["test_network"], ["node1-port"], - ["2.2.2.2"]), - autospec=True) + + @mock.patch('esi.lib.nodes.network_attach') def test_take_action_port_and_mac_address(self, mock_gfnifp): - self.app.client_manager.baremetal.node.get.\ - return_value = self.node - self.app.client_manager.baremetal.port.get_by_address.\ - return_value = self.port2 + mock_gfnifp.return_value = { + 'node': self.node, + 'ports': [self.neutron_port], + 'networks': [self.network] + } arglist = ['node1', '--port', 'node1-port', '--mac-address', 'bb:bb:bb:bb:bb:bb'] @@ -740,30 +719,27 @@ def test_take_action_port_and_mac_address(self, mock_gfnifp): parsed_args = self.check_parser(self.cmd, arglist, verifylist) results = self.cmd.take_action(parsed_args) + expected = ( ["Node", "MAC Address", "Port", "Network", "Fixed IP"], ["node1", "bb:bb:bb:bb:bb:bb", "node1-port", "test_network", "2.2.2.2"] ) + + mock_gfnifp.assert_called_once_with( + self.app.client_manager.sdk_connection, + 'node1', + {'port': 'node1-port', 'mac_address': 'bb:bb:bb:bb:bb:bb'} + ) self.assertEqual(expected, results) - self.app.client_manager.network.find_port.\ - assert_called_once_with("node1-port") - self.app.client_manager.baremetal.port.get_by_address.\ - assert_called_once_with('bb:bb:bb:bb:bb:bb') - self.app.client_manager.baremetal.node.vif_attach.\ - assert_called_once_with('node1', self.neutron_port.id, - port_uuid='port_uuid_2') - mock_gfnifp.assert_called_once - - @mock.patch('esiclient.utils.get_full_network_info_from_port', - return_value=(["test_network"], ["node1-port"], - ["2.2.2.2"]), - autospec=True) + + @mock.patch('esi.lib.nodes.network_attach') def test_take_action_trunk(self, mock_gfnifp): - self.app.client_manager.baremetal.node.get.\ - return_value = self.node - self.app.client_manager.baremetal.port.list.\ - return_value = [self.port1, self.port2] + mock_gfnifp.return_value = { + 'node': self.node, + 'ports': [self.neutron_port], + 'networks': [self.network] + } arglist = ['node1', '--trunk', 'test_trunk'] verifylist = [] @@ -771,92 +747,59 @@ def test_take_action_trunk(self, mock_gfnifp): parsed_args = self.check_parser(self.cmd, arglist, verifylist) results = self.cmd.take_action(parsed_args) + expected = ( ["Node", "MAC Address", "Port", "Network", "Fixed IP"], ["node1", "bb:bb:bb:bb:bb:bb", "node1-port", "test_network", "2.2.2.2"] ) + + mock_gfnifp.assert_called_once_with( + self.app.client_manager.sdk_connection, + 'node1', + {'trunk': 'test_trunk'} + ) self.assertEqual(expected, results) - self.app.client_manager.network.find_trunk.\ - assert_called_once_with("test_trunk") - self.app.client_manager.baremetal.node.vif_attach.\ - assert_called_once_with('node1', self.neutron_port.id) - mock_gfnifp.assert_called_once def test_take_action_port_network_and_trunk_exception(self): arglist1 = ['node1', '--network', 'test_network', '--port', 'node1'] arglist2 = ['node1', '--network', 'test_network', '--trunk', 'trunk'] arglist3 = ['node1', '--port', 'node1', '--trunk', 'trunk'] - arglist4 = ['node1', '--network', 'test_network', '--port', 'node1', - '--trunk', 'trunk'] verifylist = [] parsed_args1 = self.check_parser(self.cmd, arglist1, verifylist) parsed_args2 = self.check_parser(self.cmd, arglist2, verifylist) parsed_args3 = self.check_parser(self.cmd, arglist3, verifylist) - parsed_args4 = self.check_parser(self.cmd, arglist4, verifylist) self.assertRaisesRegex( - exceptions.CommandError, - 'ERROR: Specify only one of network, port or trunk', - self.cmd.take_action, parsed_args1) - self.assertRaisesRegex( - exceptions.CommandError, - 'ERROR: Specify only one of network, port or trunk', - self.cmd.take_action, parsed_args2) - self.assertRaisesRegex( - exceptions.CommandError, - 'ERROR: Specify only one of network, port or trunk', - self.cmd.take_action, parsed_args3) - self.assertRaisesRegex( - exceptions.CommandError, - 'ERROR: Specify only one of network, port or trunk', - self.cmd.take_action, parsed_args4) - - def test_take_action_no_port_or_network_or_trunk_exception(self): - arglist = ['node1'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) + exceptions.InvalidRequest, + 'Specify only one of network, port, or trunk', + self.cmd.take_action, + parsed_args1) self.assertRaisesRegex( - exceptions.CommandError, - 'ERROR: You must specify either network, port, or trunk', - self.cmd.take_action, parsed_args) - - def test_take_action_invalid_network_exception(self): - self.app.client_manager.baremetal.node.get.\ - return_value = self.node - self.app.client_manager.baremetal.port.list.\ - return_value = [self.port1] - self.app.client_manager.network.find_network.\ - return_value = None - - arglist = ['node1', '--network', 'test_network_invalid'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) + exceptions.InvalidRequest, + 'Specify only one of network, port, or trunk', + self.cmd.take_action, + parsed_args2) self.assertRaisesRegex( - exceptions.CommandError, - 'ERROR: Unknown network', - self.cmd.take_action, parsed_args) - - def test_take_action_port_free_exception(self): - self.app.client_manager.baremetal.node.get.\ - return_value = self.node - self.app.client_manager.baremetal.port.list.\ - return_value = [self.port1] + exceptions.InvalidRequest, + 'Specify only one of network, port, or trunk', + self.cmd.take_action, + parsed_args3) - arglist = ['node1', '--network', 'test_network'] + def test_take_action_no_port_or_network_or_trunk_exception(self): + arglist = ['node1'] verifylist = [] parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.assertRaisesRegex( - exceptions.CommandError, - 'ERROR: Node node1 has no free ports', - self.cmd.take_action, parsed_args) + exceptions.InvalidRequest, + 'You must specify either network, port, or trunk', + self.cmd.take_action, + parsed_args) class TestDetach(base.TestCommand): @@ -873,102 +816,38 @@ def setUp(self): self.neutron_port1 = utils.create_mock_object({ "id": "neutron_port_uuid_1", "network_id": "network_uuid", - "name": "node1", + "name": "neutron_port_1", "mac_address": "bb:bb:bb:bb:bb:bb", "fixed_ips": [{"ip_address": "2.2.2.2"}], "trunk_details": None }) - self.neutron_port2 = utils.create_mock_object({ - "id": "neutron_port_uuid_2", - "network_id": "network_uuid", - "name": "node1", - "mac_address": "cc:cc:cc:cc:cc:cc", - "fixed_ips": [{"ip_address": "3.3.3.3"}], - "trunk_details": None - }) - self.port1 = utils.create_mock_object({ - "uuid": "port_uuid_1", - "node_uuid": "node_uuid_1", - "address": "aa:aa:aa:aa:aa:aa", - "internal_info": {'tenant_vif_port_id': 'neutron_port_uuid_1'} - }) - self.port2 = utils.create_mock_object({ - "uuid": "port_uuid_2", - "node_uuid": "node_uuid_1", - "address": "bb:bb:bb:bb:bb:bb", - "internal_info": {} - }) - self.port3 = utils.create_mock_object({ - "uuid": "port_uuid_3", - "node_uuid": "node_uuid_1", - "address": "cc:cc:cc:cc:cc:cc", - "internal_info": {'tenant_vif_port_id': 'neutron_port_uuid_2'} - }) - - self.app.client_manager.baremetal.node.get.\ - return_value = self.node - - def test_take_action(self): - self.app.client_manager.network.find_port.\ - return_value = self.neutron_port1 - self.app.client_manager.baremetal.port.list.\ - return_value = [self.port1] + @mock.patch('esi.lib.nodes.network_detach', + return_value=True) + def test_take_action(self, mock_network_detach): arglist = ['node1'] verifylist = [] parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.cmd.take_action(parsed_args) - self.app.client_manager.baremetal.node.vif_detach.\ - assert_called_once_with('node1', self.neutron_port1.id) - def test_take_multiple_port_action(self): - self.app.client_manager.network.find_port.\ - return_value = self.neutron_port1 - self.app.client_manager.baremetal.port.list.\ - return_value = [self.port1, self.port2] + mock_network_detach.assert_called_once_with( + self.app.client_manager.sdk_connection, + 'node1', + None) - arglist = ['node1', '--port', 'port_uuid_1'] + @mock.patch('esi.lib.nodes.network_detach', + return_value=True) + def test_take_action_port(self, mock_network_detach): + arglist = ['node_uuid_1', '--port', 'neutron_port_1'] verifylist = [] parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.cmd.take_action(parsed_args) - self.app.client_manager.baremetal.node.vif_detach.\ - assert_called_once_with('node1', self.neutron_port1.id) - - def test_take_action_port_exception(self): - self.app.client_manager.network.find_port.\ - return_value = None - self.app.client_manager.baremetal.port.list.\ - return_value = [self.port1, self.port2] - - arglist = ['node1', '--port', 'bad-port'] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.assertRaisesRegex( - exceptions.CommandError, - 'ERROR: Port bad-port not attached to node node1', - self.cmd.take_action, parsed_args - ) - - def test_take_action_mutiple_port_exception(self): - self.app.client_manager.network.find_port.\ - return_value = None - self.app.client_manager.baremetal.port.list.\ - return_value = [self.port1, self.port2, self.port3] - - arglist = ['node1'] - verifylist = [] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.assertRaisesRegex( - exceptions.CommandError, - 'ERROR: Node node1 is associated with multiple ports.\ - Port must be specified with --port', - self.cmd.take_action, parsed_args - ) + mock_network_detach.assert_called_once_with( + self.app.client_manager.sdk_connection, + 'node_uuid_1', + 'neutron_port_1') diff --git a/esiclient/v1/node_network.py b/esiclient/v1/node_network.py index 54ba666..4714dbe 100644 --- a/esiclient/v1/node_network.py +++ b/esiclient/v1/node_network.py @@ -13,7 +13,6 @@ import logging from osc_lib.command import command -from osc_lib import exceptions from osc_lib.i18n import _ from esi.lib import nodes @@ -147,87 +146,29 @@ def get_parser(self, prog_name): def take_action(self, parsed_args): self.log.debug("take_action(%s)", parsed_args) - node_uuid = parsed_args.node - if (parsed_args.network and parsed_args.port) \ - or (parsed_args.network and parsed_args.trunk) \ - or (parsed_args.port and parsed_args.trunk): - raise exceptions.CommandError( - "ERROR: Specify only one of network, port or trunk") - if not parsed_args.network and not parsed_args.port \ - and not parsed_args.trunk: - raise exceptions.CommandError( - "ERROR: You must specify either network, port, or trunk") - - ironic_client = self.app.client_manager.baremetal - neutron_client = self.app.client_manager.network + attach_info = {} if parsed_args.network: - network = neutron_client.find_network(parsed_args.network) - port = None - if network is None: - raise exceptions.CommandError( - "ERROR: Unknown network") - elif parsed_args.port: - port = neutron_client.find_port(parsed_args.port) - if port is None: - raise exceptions.CommandError( - "ERROR: This is not a port name or UUID") - elif parsed_args.trunk: - trunk = neutron_client.find_trunk(parsed_args.trunk) - port = None - if trunk is None: - raise exceptions.CommandError( - "ERROR: no trunk named {0}".format(parsed_args.name)) - - node = ironic_client.node.get(node_uuid) - + attach_info['network'] = parsed_args.network + if parsed_args.port: + attach_info['port'] = parsed_args.port + if parsed_args.trunk: + attach_info['trunk'] = parsed_args.trunk if parsed_args.mac_address: - bp = ironic_client.port.get_by_address(parsed_args.mac_address) - vif_info = {'port_uuid': bp.uuid} - mac_string = " on {0}".format(parsed_args.mac_address) - else: - vif_info = {} - mac_string = "" - - baremetal_ports = ironic_client.port.list( - node=node_uuid, detail=True) - has_free_port = False - for bp in baremetal_ports: - if 'tenant_vif_port_id' not in bp.internal_info: - has_free_port = True - break - - if not has_free_port: - raise exceptions.CommandError( - "ERROR: Node {0} has no free ports".format(node.name)) - - if port: - print("Attaching port {1} to node {0}{2}".format( - node.name, port.name, mac_string)) - ironic_client.node.vif_attach(node_uuid, port.id, **vif_info) - elif parsed_args.network: - print("Attaching network {1} to node {0}{2}".format( - node.name, network.name, mac_string)) - port_name = utils.get_port_name(network.name, prefix=node.name) - port = utils.get_or_create_port(port_name, network, - neutron_client) - ironic_client.node.vif_attach(node_uuid, port.id, **vif_info) - port = neutron_client.get_port(port.id) - elif parsed_args.trunk: - print("Attaching trunk {1} to node {0}{2}".format( - node.name, trunk.name, mac_string)) - port = neutron_client.get_port(trunk.port_id) - ironic_client.node.vif_attach(node_uuid, port.id, **vif_info) - - network_names, port_names, fixed_ips \ - = utils.get_full_network_info_from_port( - port, neutron_client) + attach_info['mac_address'] = parsed_args.mac_address + + result = nodes.network_attach( + self.app.client_manager.sdk_connection, + parsed_args.node, + attach_info + ) return ["Node", "MAC Address", "Port", "Network", "Fixed IP"], \ - [node.name, port.mac_address, - "\n".join(port_names), - "\n".join(network_names), - "\n".join(fixed_ips)] + [result['node'].name, result['ports'][0].mac_address, + '\n'.join([port.name for port in result['ports']]), + '\n'.join([network.name for network in result['networks']]), + '\n'.join([ip['ip_address'] for port in result['ports'] + for ip in port.fixed_ips])] class Detach(command.Command): @@ -251,41 +192,8 @@ def get_parser(self, prog_name): def take_action(self, parsed_args): self.log.debug("take_action(%s)", parsed_args) - node_uuid = parsed_args.node - port_uuid = parsed_args.port - - ironic_client = self.app.client_manager.baremetal - neutron_client = self.app.client_manager.network - - node = ironic_client.node.get(node_uuid) - - if port_uuid: - port = neutron_client.find_port(port_uuid) - if not port: - raise exceptions.CommandError( - "ERROR: Port {1} not attached to node {0}".format( - node.name, port_uuid)) - else: - bm_ports = ironic_client.port.list(node=node_uuid, detail=True) - - mapped_node_port_list = [] - for bm_port in bm_ports: - if bm_port.internal_info.get("tenant_vif_port_id"): - mapped_node_port_list.append(bm_port) - if(len(mapped_node_port_list) == 0): - raise exceptions.CommandError( - "ERROR: Node {0} is not associated with any port".format( - node.name)) - elif(len(mapped_node_port_list) > 1): - raise exceptions.CommandError( - "ERROR: Node {0} is associated with multiple ports.\ - Port must be specified with --port".format(node.name)) - elif(len(mapped_node_port_list) == 1): - port_uuid = mapped_node_port_list[0].internal_info[ - "tenant_vif_port_id"] - port = neutron_client.find_port(port_uuid) - - print("Detaching node {0} from port {1}".format( - node.name, port.name)) - - ironic_client.node.vif_detach(node_uuid, port.id) + nodes.network_detach( + self.app.client_manager.sdk_connection, + parsed_args.node, + parsed_args.port + ) diff --git a/requirements.txt b/requirements.txt index fcdb573..54c54eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ pbr!=2.1.0,>=2.0.0 # Apache-2.0 Babel!=2.4.0,>=2.3.4 # BSD -esisdk>=0.4.0 # Apache 2.0 +esisdk>=0.5.0 # Apache 2.0 metalsmith>=2.0.0 openstacksdk<1.3.0 oslo.utils>=4.5.0 # Apache-2.0