From f677ded850054cd9ba71b895aba6e3f7c4d9b694 Mon Sep 17 00:00:00 2001 From: Mikyung Kang Date: Mon, 7 Nov 2011 14:32:22 -0500 Subject: [PATCH] Implements blueprint heterogeneous-tilera-architecture-support Change-Id: Iad8f66af18eb396f4737cd4ea168edcc77481ee6 --- Authors | 2 + nova/tests/baremetal/__init__.py | 0 nova/tests/baremetal/test_proxy_bare_metal.py | 292 ++++++++++++++++++ nova/tests/baremetal/test_tilera.py | 88 ++++++ 4 files changed, 382 insertions(+) create mode 100644 nova/tests/baremetal/__init__.py create mode 100644 nova/tests/baremetal/test_proxy_bare_metal.py create mode 100644 nova/tests/baremetal/test_tilera.py diff --git a/Authors b/Authors index ef89231c..815bbe7c 100644 --- a/Authors +++ b/Authors @@ -46,6 +46,7 @@ Derek Higgins Devendra Modium Devin Carlen Donal Lafferty +Dong-In David Kang Duncan McGreggor Ed Leafe Edouard Thuleau @@ -115,6 +116,7 @@ Michael Gundlach Michael Still Mike Lundy Mike Scherbakov +Mikyung Kang Mohammed Naser Monsyne Dragon Monty Taylor diff --git a/nova/tests/baremetal/__init__.py b/nova/tests/baremetal/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nova/tests/baremetal/test_proxy_bare_metal.py b/nova/tests/baremetal/test_proxy_bare_metal.py new file mode 100644 index 00000000..ad41a85c --- /dev/null +++ b/nova/tests/baremetal/test_proxy_bare_metal.py @@ -0,0 +1,292 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 University of Southern California +# 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. + +import __builtin__ + +import functools +import mox +import StringIO +import stubout + +from nova import flags +from nova import utils +from nova import test +from nova.compute import power_state +from nova import context +from nova.tests import fake_utils +from nova import exception + +from nova.virt.baremetal import proxy +from nova.virt.baremetal import dom + +FLAGS = flags.FLAGS + + +# Same fake_domains is used by different classes, +# but different fake_file is used by different classes for unit test. +fake_domains = [{'status': 1, 'name': 'instance-00000001', + 'memory_kb': 16777216, 'kernel_id': '1896115634', + 'ramdisk_id': '', 'image_id': '1552326678', + 'vcpus': 1, 'node_id': 6, + 'mac_address': '02:16:3e:01:4e:c9', + 'ip_address': '10.5.1.2'}] + + +class DomainReadWriteTestCase(test.TestCase): + + def setUp(self): + self.flags(baremetal_driver='fake') + super(DomainReadWriteTestCase, self).setUp() + + def test_read_domain_with_empty_list(self): + """Read a file that contains no domains""" + + self.mox.StubOutWithMock(__builtin__, 'open') + try: + fake_file = StringIO.StringIO('[]') + open('/tftpboot/test_fake_dom_file', 'r').AndReturn(fake_file) + + self.mox.ReplayAll() + + domains = dom.read_domains('/tftpboot/test_fake_dom_file') + + self.assertEqual(domains, []) + + finally: + self.mox.UnsetStubs() + + def test_read_domain(self): + """Read a file that contains at least one domain""" + fake_file = StringIO.StringIO('''[{"status": 1, + "image_id": "1552326678", "vcpus": 1, "node_id": 6, + "name": "instance-00000001", "memory_kb": 16777216, + "mac_address": "02:16:3e:01:4e:c9", "kernel_id": "1896115634", + "ramdisk_id": "", "ip_address": "10.5.1.2"}]''') + + self.mox.StubOutWithMock(__builtin__, 'open') + try: + open('/tftpboot/test_fake_dom_file', 'r').AndReturn(fake_file) + + self.mox.ReplayAll() + + domains = dom.read_domains('/tftpboot/test_fake_dom_file') + + self.assertEqual(domains, fake_domains) + + finally: + self.mox.UnsetStubs() + + def test_read_no_file(self): + """Try to read when the file does not exist + + This should through and IO exception""" + + self.mox.StubOutWithMock(__builtin__, 'open') + try: + open('/tftpboot/test_fake_dom_file', 'r').AndRaise(\ + IOError(2, 'No such file or directory', + '/tftpboot/test_fake_dom_file')) + + self.mox.ReplayAll() + + self.assertRaises(exception.NotFound, dom.read_domains, + '/tftpboot/test_fake_dom_file') + + finally: + self.mox.UnsetStubs() + + def assertJSONEquals(self, x, y): + """Check if two json strings represent the equivalent Python object""" + self.assertEquals(utils.loads(x), utils.loads(y)) + return utils.loads(x) == utils.loads(y) + + def test_write_domain(self): + """Write the domain to file""" + self.mox.StubOutWithMock(__builtin__, 'open') + mock_file = self.mox.CreateMock(file) + expected_json = '''[{"status": 1, + "image_id": "1552326678", "vcpus": 1, "node_id": 6, + "name": "instance-00000001", "memory_kb": 16777216, + "mac_address": "02:16:3e:01:4e:c9", "kernel_id": "1896115634", + "ramdisk_id": "", "ip_address": "10.5.1.2"}]''' + try: + open('/tftpboot/test_fake_dom_file', 'w').AndReturn(mock_file) + + # Check if the argument to file.write() represents the same + # Python object as expected_json + # We can't do an exact string comparison + # because of ordering and whitespace + mock_file.write(mox.Func(functools.partial(self.assertJSONEquals,\ + expected_json))) + mock_file.close() + + self.mox.ReplayAll() + + dom.write_domains('/tftpboot/test_fake_dom_file', fake_domains) + + finally: + self.mox.UnsetStubs() + + +class BareMetalDomTestCase(test.TestCase): + + def setUp(self): + self.flags(baremetal_driver='fake') + super(BareMetalDomTestCase, self).setUp() + # Stub out utils.execute + self.stubs = stubout.StubOutForTesting() + fake_utils.stub_out_utils_execute(self.stubs) + + def tearDown(self): + self.stubs.UnsetAll() + super(BareMetalDomTestCase, self).tearDown() + + # Reset the singleton state + dom.BareMetalDom._instance = None + dom.BareMetalDom._is_init = False + + def test_read_domain_only_once(self): + """Confirm that the domain is read from a file only once, + even if the object is instantiated multiple times""" + self.mox.StubOutWithMock(dom, 'read_domains') + self.mox.StubOutWithMock(dom, 'write_domains') + + dom.read_domains('/tftpboot/test_fake_dom_file').AndReturn([]) + dom.write_domains('/tftpboot/test_fake_dom_file', []) + + self.mox.ReplayAll() + + # Instantiate multiple instances + x = dom.BareMetalDom() + x = dom.BareMetalDom() + x = dom.BareMetalDom() + + def test_init_no_domains(self): + + # Create the mock objects + self.mox.StubOutWithMock(dom, 'read_domains') + self.mox.StubOutWithMock(dom, 'write_domains') + + dom.read_domains('/tftpboot/test_fake_dom_file').AndReturn([]) + dom.write_domains('/tftpboot/test_fake_dom_file', []) + + self.mox.ReplayAll() + + # Code under test + bmdom = dom.BareMetalDom() + + # Expectd values + self.assertEqual(bmdom.fake_dom_nums, 0) + + def test_init_remove_non_running_domain(self): + """Check to see that all entries in the domain list are removed + except for the one that is in the running state""" + + fake_file = StringIO.StringIO() + + domains = [dict(node_id=1, name='i-00000001', + status=power_state.NOSTATE), + dict(node_id=2, name='i-00000002', status=power_state.RUNNING), + dict(node_id=3, name='i-00000003', status=power_state.BLOCKED), + dict(node_id=4, name='i-00000004', status=power_state.PAUSED), + dict(node_id=5, name='i-00000005', status=power_state.SHUTDOWN), + dict(node_id=6, name='i-00000006', status=power_state.SHUTOFF), + dict(node_id=7, name='i-00000007', status=power_state.CRASHED), + dict(node_id=8, name='i-00000008', status=power_state.SUSPENDED), + dict(node_id=9, name='i-00000009', status=power_state.FAILED)] + + # Create the mock objects + self.mox.StubOutWithMock(dom, 'read_domains') + self.mox.StubOutWithMock(dom, 'write_domains') + dom.read_domains('/tftpboot/test_fake_dom_file').AndReturn(domains) + dom.write_domains('/tftpboot/test_fake_dom_file', domains) + + self.mox.ReplayAll() + + # Code under test + bmdom = dom.BareMetalDom() + + self.assertEqual(bmdom.domains, [{'node_id': 2, + 'name': 'i-00000002', + 'status': power_state.RUNNING}]) + self.assertEqual(bmdom.fake_dom_nums, 1) + + def test_find_domain(self): + domain = {'status': 1, 'name': 'instance-00000001', + 'memory_kb': 16777216, 'kernel_id': '1896115634', + 'ramdisk_id': '', 'image_id': '1552326678', + 'vcpus': 1, 'node_id': 6, + 'mac_address': '02:16:3e:01:4e:c9', + 'ip_address': '10.5.1.2'} + + # Create the mock objects + self.mox.StubOutWithMock(dom, 'read_domains') + self.mox.StubOutWithMock(dom, 'write_domains') + + # Expected calls + dom.read_domains('/tftpboot/test_fake_dom_file')\ + .AndReturn(fake_domains) + dom.write_domains('/tftpboot/test_fake_dom_file', fake_domains) + + self.mox.ReplayAll() + + # Code under test + bmdom = dom.BareMetalDom() + + # Expected values + self.assertEquals(bmdom.find_domain('instance-00000001'), domain) + + +class ProxyBareMetalTestCase(test.TestCase): + + test_ip = '10.11.12.13' + test_instance = {'memory_kb': '1024000', + 'basepath': '/some/path', + 'bridge_name': 'br100', + 'mac_address': '02:12:34:46:56:67', + 'vcpus': 2, + 'project_id': 'fake', + 'bridge': 'br101', + 'image_ref': '123456', + 'instance_type_id': '5'} # m1.small + + def setUp(self): + self.flags(baremetal_driver='fake') + super(ProxyBareMetalTestCase, self).setUp() + self.context = context.get_admin_context() + fake_utils.stub_out_utils_execute(self.stubs) + + def test_get_info(self): + # Create the mock objects + self.mox.StubOutWithMock(dom, 'read_domains') + self.mox.StubOutWithMock(dom, 'write_domains') + + # Expected calls + dom.read_domains('/tftpboot/test_fake_dom_file')\ + .AndReturn(fake_domains) + dom.write_domains('/tftpboot/test_fake_dom_file', fake_domains) + + self.mox.ReplayAll() + + # Code under test + conn = proxy.get_connection(True) + info = conn.get_info('instance-00000001') + + # Expected values + self.assertEquals(info['mem'], 16777216) + self.assertEquals(info['state'], 1) + self.assertEquals(info['num_cpu'], 1) + self.assertEquals(info['cpu_time'], 100) + self.assertEquals(info['max_mem'], 16777216) diff --git a/nova/tests/baremetal/test_tilera.py b/nova/tests/baremetal/test_tilera.py new file mode 100644 index 00000000..7b58282e --- /dev/null +++ b/nova/tests/baremetal/test_tilera.py @@ -0,0 +1,88 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 University of Southern California +# +# 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. +# + +import __builtin__ +import StringIO + +from nova import test +from nova.virt.baremetal import tilera + + +class TileraBareMetalNodesTestCase(test.TestCase): + + def setUp(self): + super(TileraBareMetalNodesTestCase, self).setUp() + self.board_info = """\ +# board_id ip_address mac_address 00:1A:CA:00:57:90 \ +00:1A:CA:00:58:98 00:1A:CA:00:58:50 +6 10.0.2.7 00:1A:CA:00:58:5C 10 16218 917 476 1 tilera_hv 1 \ +{"vendor":"tilera","model":"TILEmpower","arch":"TILEPro64","features":\ +["8x8Grid","32bVLIW","5.6MBCache","443BOPS","37TbMesh","700MHz-866MHz",\ +"4DDR2","2XAUIMAC/PHY","2GbEMAC"],"topology":{"cores":"64"}} +7 10.0.2.8 00:1A:CA:00:58:A4 10 16218 917 476 1 tilera_hv 1 \ +{"vendor":"tilera","model":"TILEmpower","arch":"TILEPro64","features":\ +["8x8Grid","32bVLIW","5.6MBCache","443BOPS","37TbMesh","700MHz-866MHz",\ +"4DDR2","2XAUIMAC/PHY","2GbEMAC"],"topology":{"cores":"64"}} +8 10.0.2.9 00:1A:CA:00:58:1A 10 16218 917 476 1 tilera_hv 1 \ +{"vendor":"tilera","model":"TILEmpower","arch":"TILEPro64","features":\ +["8x8Grid","32bVLIW","5.6MBCache","443BOPS","37TbMesh","700MHz-866MHz",\ +"4DDR2","2XAUIMAC/PHY","2GbEMAC"],"topology":{"cores":"64"}} +9 10.0.2.10 00:1A:CA:00:58:38 10 16385 1000 0 0 tilera_hv 1 \ +{"vendor":"tilera","model":"TILEmpower","arch":"TILEPro64","features":\ +["8x8Grid","32bVLIW","5.6MBCache","443BOPS","37TbMesh","700MHz-866MHz",\ +"4DDR2","2XAUIMAC/PHY","2GbEMAC"],"topology":{"cores":"64"}} +""" + + def tearDown(self): + super(TileraBareMetalNodesTestCase, self).tearDown() + + # Reset the singleton state + tilera.BareMetalNodes._instance = None + tilera.BareMetalNodes._is_init = False + + def test_singleton(self): + """Confirm that the object acts like a singleton. + + In this case, we check that it only loads the config file once, + even though it has been instantiated multiple times""" + + try: + self.mox.StubOutWithMock(__builtin__, 'open') + + open("/tftpboot/tilera_boards", "r").AndReturn(\ + StringIO.StringIO(self.board_info)) + + self.mox.ReplayAll() + + nodes = tilera.BareMetalNodes("/tftpboot/tilera_boards") + nodes = tilera.BareMetalNodes("/tftpboot/tilera_boards") + finally: + self.mox.UnsetStubs() + + def test_get_hw_info(self): + try: + + self.mox.StubOutWithMock(__builtin__, 'open') + + open("/tftpboot/tilera_boards", "r").AndReturn(\ + StringIO.StringIO(self.board_info)) + + self.mox.ReplayAll() + nodes = tilera.BareMetalNodes() + self.assertEqual(nodes.get_hw_info('vcpus'), 10) + finally: + self.mox.UnsetStubs()