diff --git a/esi/lease/v1/node.py b/esi/lease/v1/node.py index f58d939..5020fc5 100644 --- a/esi/lease/v1/node.py +++ b/esi/lease/v1/node.py @@ -41,6 +41,9 @@ class Node(resource.Resource): owner = resource.Body("owner") lessee = resource.Body("lessee") provision_state = resource.Body("provision_state") + target_provision_state = resource.Body("target_provision_state") + power_state = resource.Body("power_state") + target_power_state = resource.Body("target_power_state") maintenance = resource.Body("maintenance") offer_uuid = resource.Body("offer_uuid") lease_uuid = resource.Body("lease_uuid") diff --git a/esi/lib/nodes.py b/esi/lib/nodes.py index 358c031..9ac12f1 100644 --- a/esi/lib/nodes.py +++ b/esi/lib/nodes.py @@ -171,7 +171,7 @@ def network_attach(connection, node, attach_info): mac_address = attach_info.get('mac_address') if (network and port) or (network and trunk) or (port and trunk): - raise exceptions.InvalidRequest('Specify only one of network, port or trunk') + raise exceptions.InvalidRequest('Specify only one of network, port, or trunk') if not network and not port and not trunk: raise exceptions.InvalidRequest('You must specify either network, port, or trunk') diff --git a/esi/tests/unit/lib/test_nodes.py b/esi/tests/unit/lib/test_nodes.py index e4fca1d..833dd4b 100644 --- a/esi/tests/unit/lib/test_nodes.py +++ b/esi/tests/unit/lib/test_nodes.py @@ -13,6 +13,8 @@ import mock from unittest import TestCase +from openstack import exceptions + from esi.lib import nodes from esi.tests.unit import utils @@ -550,6 +552,11 @@ def setUp(self): "name": "node1", "provision_state": "active" }) + self.node2 = utils.create_mock_object({ + "id": "node_uuid_2", + "name": "node2", + "provision_state": "active" + }) self.node_available = utils.create_mock_object({ "uuid": "node_uuid_1", "name": "node1", @@ -616,16 +623,16 @@ def setUp(self): return_value = [] self.connection.network.find_trunk.\ return_value = self.trunk - self.connection.baremetal.get_node.\ - return_value = self.node def mock_baremetal_ports(details=False, node=None, address=None): if node is None or node == 'node1' or node == 'node_uuid_1': + if address is None: + return [self.port1, self.port2] if address == "aa:aa:aa:aa:aa:aa": return [self.port1] if address == "bb:bb:bb:bb:bb:bb": return [self.port2] - return [self.port1, self.port2] + return [] return [] self.connection.baremetal.ports.side_effect = mock_baremetal_ports @@ -637,6 +644,14 @@ def mock_find_port(port, ignore_missing=True): return None self.connection.network.find_port.side_effect = mock_find_port + def mock_get_node(node): + if node == 'node1' or node == 'node_uuid_1': + return self.node + if node == 'node2' or node == 'node_uuid_2': + return self.node2 + return None + self.connection.baremetal.get_node.side_effect = mock_get_node + @mock.patch('esi.lib.networks.get_networks_from_port') def test_network_attach_network(self, mock_gnfp): mock_gnfp.return_value = (self.network, [], [], None) @@ -741,3 +756,76 @@ def test_network_attach_trunk(self, mock_gnfp): self.connection.session.post.assert_called_once_with('endpoint/v1/nodes/node_uuid_1/vifs', json={'id': 'neutron_port_uuid_3'}, headers={'X-OpenStack-Ironic-API-Version': '1.69'}) self.connection.network.find_port.assert_any_call('neutron_port_uuid_3', ignore_missing=False) self.assertEqual(expected, actual) + + def test_network_attach_invalid_request(self): + attach_info = { + 'network': 'test_network', + 'port': 'node1-port1' + } + self.assertRaisesRegex( + exceptions.InvalidRequest, + 'Specify only one of network, port, or trunk', + nodes.network_attach, + self.connection, + 'node1', + attach_info) + + attach_info = { + 'network': 'test_network', + 'trunk': 'test_trunk' + } + self.assertRaisesRegex( + exceptions.InvalidRequest, + 'Specify only one of network, port, or trunk', + nodes.network_attach, + self.connection, + 'node1', + attach_info) + + attach_info = { + 'port': 'node1-port1', + 'trunk': 'test_trunk' + } + self.assertRaisesRegex( + exceptions.InvalidRequest, + 'Specify only one of network, port, or trunk', + nodes.network_attach, + self.connection, + 'node1', + attach_info) + + attach_info = {} + self.assertRaisesRegex( + exceptions.InvalidRequest, + 'You must specify either network, port, or trunk', + nodes.network_attach, + self.connection, + 'node1', + attach_info) + + def test_network_attach_mac_address_dne(self): + attach_info = { + 'network': 'test_network', + 'mac_address': 'does_not_exist' + } + + self.assertRaisesRegex( + exceptions.ResourceFailure, + 'MAC address does_not_exist does not exist on node node1', + nodes.network_attach, + self.connection, + 'node1', + attach_info) + + def test_network_attach_no_free_ports(self): + attach_info = { + 'network': 'test_network', + } + + self.assertRaisesRegex( + exceptions.ResourceFailure, + 'Node node2 has no free ports', + nodes.network_attach, + self.connection, + 'node2', + attach_info)