# Copyright (c) 2013 NTT DOCOMO, INC. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from ironicclient import exc as ironic_exc import mock import six from webob import exc from nova.api.openstack.compute import baremetal_nodes \ as b_nodes_v21 from nova import context from nova import exception from nova import test from nova.tests.unit.api.openstack import fakes from nova.tests.unit.virt.ironic import utils as ironic_utils def fake_node(**updates): node = { 'id': 1, 'service_host': "host", 'cpus': 8, 'memory_mb': 8192, 'local_gb': 128, 'pm_address': "10.1.2.3", 'pm_user': "pm_user", 'pm_password': "pm_pass", 'terminal_port': 8000, 'interfaces': [], 'instance_uuid': 'fake-instance-uuid', } if updates: node.update(updates) return node def fake_node_ext_status(**updates): node = fake_node(uuid='fake-uuid', task_state='fake-task-state', updated_at='fake-updated-at', pxe_config_path='fake-pxe-config-path') if updates: node.update(updates) return node FAKE_IRONIC_CLIENT = ironic_utils.FakeClient() @mock.patch.object(b_nodes_v21, '_get_ironic_client', lambda *_: FAKE_IRONIC_CLIENT) class BareMetalNodesTestV21(test.NoDBTestCase): mod = b_nodes_v21 def setUp(self): super(BareMetalNodesTestV21, self).setUp() self._setup() self.context = context.get_admin_context() self.request = fakes.HTTPRequest.blank('', use_admin_context=True) def _setup(self): self.controller = b_nodes_v21.BareMetalNodeController() @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'list') def test_index_ironic(self, mock_list): properties = {'cpus': 2, 'memory_mb': 1024, 'local_gb': 20} node = ironic_utils.get_test_node(properties=properties) mock_list.return_value = [node] res_dict = self.controller.index(self.request) expected_output = {'nodes': [{'memory_mb': properties['memory_mb'], 'host': 'IRONIC MANAGED', 'disk_gb': properties['local_gb'], 'interfaces': [], 'task_state': None, 'id': node.uuid, 'cpus': properties['cpus']}]} self.assertEqual(expected_output, res_dict) mock_list.assert_called_once_with(detail=True) @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'list') def test_index_ironic_missing_properties(self, mock_list): properties = {'cpus': 2} node = ironic_utils.get_test_node(properties=properties) mock_list.return_value = [node] res_dict = self.controller.index(self.request) expected_output = {'nodes': [{'memory_mb': 0, 'host': 'IRONIC MANAGED', 'disk_gb': 0, 'interfaces': [], 'task_state': None, 'id': node.uuid, 'cpus': properties['cpus']}]} self.assertEqual(expected_output, res_dict) mock_list.assert_called_once_with(detail=True) def test_index_ironic_not_implemented(self): with mock.patch.object(self.mod, 'ironic_client', None): self.assertRaises(exc.HTTPNotImplemented, self.controller.index, self.request) @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'list_ports') @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'get') def test_show_ironic(self, mock_get, mock_list_ports): properties = {'cpus': 1, 'memory_mb': 512, 'local_gb': 10} node = ironic_utils.get_test_node(properties=properties) port = ironic_utils.get_test_port() mock_get.return_value = node mock_list_ports.return_value = [port] res_dict = self.controller.show(self.request, node.uuid) expected_output = {'node': {'memory_mb': properties['memory_mb'], 'instance_uuid': None, 'host': 'IRONIC MANAGED', 'disk_gb': properties['local_gb'], 'interfaces': [{'address': port.address}], 'task_state': None, 'id': node.uuid, 'cpus': properties['cpus']}} self.assertEqual(expected_output, res_dict) mock_get.assert_called_once_with(node.uuid) mock_list_ports.assert_called_once_with(node.uuid) @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'list_ports') @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'get') def test_show_ironic_no_properties(self, mock_get, mock_list_ports): properties = {} node = ironic_utils.get_test_node(properties=properties) port = ironic_utils.get_test_port() mock_get.return_value = node mock_list_ports.return_value = [port] res_dict = self.controller.show(self.request, node.uuid) expected_output = {'node': {'memory_mb': 0, 'instance_uuid': None, 'host': 'IRONIC MANAGED', 'disk_gb': 0, 'interfaces': [{'address': port.address}], 'task_state': None, 'id': node.uuid, 'cpus': 0}} self.assertEqual(expected_output, res_dict) mock_get.assert_called_once_with(node.uuid) mock_list_ports.assert_called_once_with(node.uuid) @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'list_ports') @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'get') def test_show_ironic_no_interfaces(self, mock_get, mock_list_ports): properties = {'cpus': 1, 'memory_mb': 512, 'local_gb': 10} node = ironic_utils.get_test_node(properties=properties) mock_get.return_value = node mock_list_ports.return_value = [] res_dict = self.controller.show(self.request, node.uuid) self.assertEqual([], res_dict['node']['interfaces']) mock_get.assert_called_once_with(node.uuid) mock_list_ports.assert_called_once_with(node.uuid) @mock.patch.object(FAKE_IRONIC_CLIENT.node, 'get', side_effect=ironic_exc.NotFound()) def test_show_ironic_node_not_found(self, mock_get): error = self.assertRaises(exc.HTTPNotFound, self.controller.show, self.request, 'fake-uuid') self.assertIn('fake-uuid', six.text_type(error)) def test_show_ironic_not_implemented(self): with mock.patch.object(self.mod, 'ironic_client', None): properties = {'cpus': 1, 'memory_mb': 512, 'local_gb': 10} node = ironic_utils.get_test_node(properties=properties) self.assertRaises(exc.HTTPNotImplemented, self.controller.show, self.request, node.uuid) def test_create_ironic_not_supported(self): self.assertRaises(exc.HTTPBadRequest, self.controller.create, self.request, {'node': object()}) def test_delete_ironic_not_supported(self): self.assertRaises(exc.HTTPBadRequest, self.controller.delete, self.request, 'fake-id') def test_add_interface_ironic_not_supported(self): self.assertRaises(exc.HTTPBadRequest, self.controller._add_interface, self.request, 'fake-id', 'fake-body') def test_remove_interface_ironic_not_supported(self): self.assertRaises(exc.HTTPBadRequest, self.controller._remove_interface, self.request, 'fake-id', 'fake-body') class BareMetalNodesTestDeprecation(test.NoDBTestCase): def setUp(self): super(BareMetalNodesTestDeprecation, self).setUp() self.controller = b_nodes_v21.BareMetalNodeController() self.req = fakes.HTTPRequest.blank('', version='2.36') def test_all_apis_return_not_found(self): self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.show, self.req, fakes.FAKE_UUID) self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.index, self.req) self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.create, self.req, {}) self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.delete, self.req, fakes.FAKE_UUID) self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller._add_interface, self.req, fakes.FAKE_UUID, {}) self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller._remove_interface, self.req, fakes.FAKE_UUID, {})