summaryrefslogtreecommitdiffstats
path: root/nova/tests
diff options
context:
space:
mode:
authorMikyung Kang <mkkang@isi.edu>2012-11-07 19:10:56 +0900
committerArata Notsu <notsu@virtualtech.jp>2012-11-13 20:56:20 +0900
commit56fe4c7620ae358bcbebf2a50dc8bce955334660 (patch)
tree77ff677f5683232fb471b3a53fe93f911ff594e2 /nova/tests
parent3c9e48d1119b77428346680c2a009c44ff9bf2ce (diff)
Added separate bare-metal MySQL DB.
Part 2 of 6: blueprint general-bare-metal-provisioning-framework In baremetal provisioning, one nova-compute manages multiple bare-metal machines. A bare-metal machine does not run openstack at all. Previously, bare-metal provisioning used text files to store information of bare-metal machines. In this patch, a MySQL database is used to store the information. We target only MySQL database. The DB is designed to support PXE/non-PXE booting methods, heterogeneous hypervisor types, and architectures. Using a MySQL database makes maintenance and upgrades easier than using text files. The DB for bare-metal machines is implemented as a separate DB from the main Nova DB. The DB can be on any machines/places. The location of the DB and its server needs to be specified as a flag in the nova.conf file (as in the case of glance). There are a couple of reasons for this approach. First, the information needed for bare-metal machines is different from that for non-bare-metal machines. With a separate database for bare-metal machines, the database can be customized without affecting the main Nova DB. Second, fault tolerance can be embedded in nova-compute. Since one nova-compute manages multiple bare-metal machines, fault tolerance of a nova-compute node is very important. With a separate DB for bare-metal machines, fault-tolerance can be achieved independently from the main Nova DB. Replication of the bare-metal DB and implementation of fault-tolerance are not part of this patch. The implementation models nova and its DB as much as possible. The bare-metal driver must be upgraded to use this DB. Change-Id: I7b7ba1903a672a50c567f95fc6554d119463b0c5 Co-authored-by: Mikyung Kang <mkkang@isi.edu> Co-authored-by: David Kang <dkang@isi.edu> Co-authored-by: Ken Igarashi <igarashik@nttdocomo.co.jp> Co-authored-by: Arata Notsu <notsu@virtualtech.jp>
Diffstat (limited to 'nova/tests')
-rw-r--r--nova/tests/baremetal/db/__init__.py14
-rw-r--r--nova/tests/baremetal/db/base.py51
-rw-r--r--nova/tests/baremetal/db/test_bm_interface.py47
-rw-r--r--nova/tests/baremetal/db/test_bm_node.py140
-rw-r--r--nova/tests/baremetal/db/test_bm_pxe_ip.py93
-rw-r--r--nova/tests/baremetal/db/utils.py81
6 files changed, 426 insertions, 0 deletions
diff --git a/nova/tests/baremetal/db/__init__.py b/nova/tests/baremetal/db/__init__.py
new file mode 100644
index 000000000..19071662c
--- /dev/null
+++ b/nova/tests/baremetal/db/__init__.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2012 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.
diff --git a/nova/tests/baremetal/db/base.py b/nova/tests/baremetal/db/base.py
new file mode 100644
index 000000000..83abcb58e
--- /dev/null
+++ b/nova/tests/baremetal/db/base.py
@@ -0,0 +1,51 @@
+# Copyright (c) 2012 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.
+
+"""Bare-metal DB test base class."""
+
+from nova import config
+from nova import context as nova_context
+from nova import test
+from nova.virt.baremetal.db import migration as bm_migration
+from nova.virt.baremetal.db.sqlalchemy import session as bm_session
+
+_DB = None
+
+CONF = config.CONF
+CONF.import_opt('baremetal_sql_connection',
+ 'nova.virt.baremetal.db.sqlalchemy.session')
+
+
+def _reset_bmdb():
+ global _DB
+ engine = bm_session.get_engine()
+ engine.dispose()
+ conn = engine.connect()
+ if _DB is None:
+ if bm_migration.db_version() > bm_migration.INIT_VERSION:
+ return
+ bm_migration.db_sync()
+ _DB = "".join(line for line in conn.connection.iterdump())
+ else:
+ conn.connection.executescript(_DB)
+
+
+class BMDBTestCase(test.TestCase):
+
+ def setUp(self):
+ super(BMDBTestCase, self).setUp()
+ self.flags(baremetal_sql_connection='sqlite:///:memory:')
+ _reset_bmdb()
+ self.context = nova_context.get_admin_context()
diff --git a/nova/tests/baremetal/db/test_bm_interface.py b/nova/tests/baremetal/db/test_bm_interface.py
new file mode 100644
index 000000000..6aef437c1
--- /dev/null
+++ b/nova/tests/baremetal/db/test_bm_interface.py
@@ -0,0 +1,47 @@
+# Copyright (c) 2012 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.
+
+"""
+Bare-metal DB testcase for BareMetalInterface
+"""
+
+from nova import exception
+from nova.tests.baremetal.db import base
+from nova.virt.baremetal import db
+
+
+class BareMetalInterfaceTestCase(base.BMDBTestCase):
+
+ def test_unique_address(self):
+ pif1_id = db.bm_interface_create(self.context, 1, '11:11:11:11:11:11',
+ '0x1', 1)
+ self.assertRaises(exception.DBError,
+ db.bm_interface_create,
+ self.context, 2, '11:11:11:11:11:11', '0x2', 2)
+ # succeed after delete pif1
+ db.bm_interface_destroy(self.context, pif1_id)
+ pif2_id = db.bm_interface_create(self.context, 2, '11:11:11:11:11:11',
+ '0x2', 2)
+ self.assertTrue(pif2_id is not None)
+
+ def test_unique_vif_uuid(self):
+ pif1_id = db.bm_interface_create(self.context, 1, '11:11:11:11:11:11',
+ '0x1', 1)
+ pif2_id = db.bm_interface_create(self.context, 2, '22:22:22:22:22:22',
+ '0x2', 2)
+ db.bm_interface_set_vif_uuid(self.context, pif1_id, 'AAAA')
+ self.assertRaises(exception.DBError,
+ db.bm_interface_set_vif_uuid,
+ self.context, pif2_id, 'AAAA')
diff --git a/nova/tests/baremetal/db/test_bm_node.py b/nova/tests/baremetal/db/test_bm_node.py
new file mode 100644
index 000000000..062b209a6
--- /dev/null
+++ b/nova/tests/baremetal/db/test_bm_node.py
@@ -0,0 +1,140 @@
+# Copyright (c) 2012 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.
+
+"""
+Bare-Metal DB testcase for BareMetalNode
+"""
+
+from nova.tests.baremetal.db import base
+from nova.tests.baremetal.db import utils
+from nova.virt.baremetal import db
+
+
+class BareMetalNodesTestCase(base.BMDBTestCase):
+
+ def _create_nodes(self):
+ nodes = [
+ utils.new_bm_node(pm_address='0', service_host="host1",
+ memory_mb=100000, cpus=100, local_gb=10000),
+ utils.new_bm_node(pm_address='1', service_host="host2",
+ instance_uuid='A',
+ memory_mb=100000, cpus=100, local_gb=10000),
+ utils.new_bm_node(pm_address='2', service_host="host2",
+ memory_mb=1000, cpus=1, local_gb=1000),
+ utils.new_bm_node(pm_address='3', service_host="host2",
+ memory_mb=1000, cpus=2, local_gb=1000),
+ utils.new_bm_node(pm_address='4', service_host="host2",
+ memory_mb=2000, cpus=1, local_gb=1000),
+ utils.new_bm_node(pm_address='5', service_host="host2",
+ memory_mb=2000, cpus=2, local_gb=1000),
+ ]
+ self.ids = []
+ for n in nodes:
+ ref = db.bm_node_create(self.context, n)
+ self.ids.append(ref['id'])
+
+ def test_get_all0(self):
+ r = db.bm_node_get_all(self.context)
+ self.assertEquals(r, [])
+
+ def test_get_all(self):
+ r = db.bm_node_get_all(self.context)
+ self.assertEquals(r, [])
+
+ self._create_nodes()
+
+ r = db.bm_node_get_all(self.context)
+ self.assertEquals(len(r), 6)
+
+ def test_get(self):
+ self._create_nodes()
+
+ r = db.bm_node_get(self.context, self.ids[0])
+ self.assertEquals(r['pm_address'], '0')
+
+ r = db.bm_node_get(self.context, self.ids[1])
+ self.assertEquals(r['pm_address'], '1')
+
+ r = db.bm_node_get(self.context, -1)
+ self.assertTrue(r is None)
+
+ def test_get_by_service_host(self):
+ self._create_nodes()
+
+ r = db.bm_node_get_all(self.context, service_host=None)
+ self.assertEquals(len(r), 6)
+
+ r = db.bm_node_get_all(self.context, service_host="host1")
+ self.assertEquals(len(r), 1)
+ self.assertEquals(r[0]['pm_address'], '0')
+
+ r = db.bm_node_get_all(self.context, service_host="host2")
+ self.assertEquals(len(r), 5)
+ pmaddrs = [x['pm_address'] for x in r]
+ self.assertIn('1', pmaddrs)
+ self.assertIn('2', pmaddrs)
+ self.assertIn('3', pmaddrs)
+ self.assertIn('4', pmaddrs)
+ self.assertIn('5', pmaddrs)
+
+ r = db.bm_node_get_all(self.context, service_host="host3")
+ self.assertEquals(r, [])
+
+ def test_destroy(self):
+ self._create_nodes()
+
+ db.bm_node_destroy(self.context, self.ids[0])
+
+ r = db.bm_node_get(self.context, self.ids[0])
+ self.assertTrue(r is None)
+
+ r = db.bm_node_get_all(self.context)
+ self.assertEquals(len(r), 5)
+
+ def test_find_free(self):
+ self._create_nodes()
+ fn = db.bm_node_find_free(self.context, 'host2')
+ self.assertEqual(fn['pm_address'], '2')
+
+ fn = db.bm_node_find_free(self.context, 'host2',
+ memory_mb=500, cpus=2, local_gb=100)
+ self.assertEqual(fn['pm_address'], '3')
+
+ fn = db.bm_node_find_free(self.context, 'host2',
+ memory_mb=1001, cpus=1, local_gb=1000)
+ self.assertEqual(fn['pm_address'], '4')
+
+ fn = db.bm_node_find_free(self.context, 'host2',
+ memory_mb=2000, cpus=1, local_gb=1000)
+ self.assertEqual(fn['pm_address'], '4')
+
+ fn = db.bm_node_find_free(self.context, 'host2',
+ memory_mb=2000, cpus=2, local_gb=1000)
+ self.assertEqual(fn['pm_address'], '5')
+
+ # check memory_mb
+ fn = db.bm_node_find_free(self.context, 'host2',
+ memory_mb=2001, cpus=2, local_gb=1000)
+ self.assertTrue(fn is None)
+
+ # check cpus
+ fn = db.bm_node_find_free(self.context, 'host2',
+ memory_mb=2000, cpus=3, local_gb=1000)
+ self.assertTrue(fn is None)
+
+ # check local_gb
+ fn = db.bm_node_find_free(self.context, 'host2',
+ memory_mb=2000, cpus=2, local_gb=1001)
+ self.assertTrue(fn is None)
diff --git a/nova/tests/baremetal/db/test_bm_pxe_ip.py b/nova/tests/baremetal/db/test_bm_pxe_ip.py
new file mode 100644
index 000000000..9a93b46ad
--- /dev/null
+++ b/nova/tests/baremetal/db/test_bm_pxe_ip.py
@@ -0,0 +1,93 @@
+# Copyright (c) 2012 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.
+
+"""
+Bare-metal DB testcase for BareMetalPxeIp
+"""
+
+from nova import exception
+from nova.tests.baremetal.db import base
+from nova.tests.baremetal.db import utils
+from nova.virt.baremetal import db
+
+
+class BareMetalPxeIpTestCase(base.BMDBTestCase):
+
+ def _create_pxe_ip(self):
+ i1 = utils.new_bm_pxe_ip(address='10.1.1.1',
+ server_address='10.1.1.101')
+ i2 = utils.new_bm_pxe_ip(address='10.1.1.2',
+ server_address='10.1.1.102')
+
+ i1_ref = db.bm_pxe_ip_create_direct(self.context, i1)
+ self.assertTrue(i1_ref['id'] is not None)
+ self.assertEqual(i1_ref['address'], '10.1.1.1')
+ self.assertEqual(i1_ref['server_address'], '10.1.1.101')
+
+ i2_ref = db.bm_pxe_ip_create_direct(self.context, i2)
+ self.assertTrue(i2_ref['id'] is not None)
+ self.assertEqual(i2_ref['address'], '10.1.1.2')
+ self.assertEqual(i2_ref['server_address'], '10.1.1.102')
+
+ self.i1 = i1_ref
+ self.i2 = i2_ref
+
+ def test_unuque_address(self):
+ self._create_pxe_ip()
+
+ # address duplicates
+ i = utils.new_bm_pxe_ip(address='10.1.1.1',
+ server_address='10.1.1.201')
+ self.assertRaises(exception.DBError,
+ db.bm_pxe_ip_create_direct,
+ self.context, i)
+
+ # server_address duplicates
+ i = utils.new_bm_pxe_ip(address='10.1.1.3',
+ server_address='10.1.1.101')
+ self.assertRaises(exception.DBError,
+ db.bm_pxe_ip_create_direct,
+ self.context, i)
+
+ db.bm_pxe_ip_destroy(self.context, self.i1['id'])
+ i = utils.new_bm_pxe_ip(address='10.1.1.1',
+ server_address='10.1.1.101')
+ ref = db.bm_pxe_ip_create_direct(self.context, i)
+ self.assertTrue(ref is not None)
+
+ def test_bm_pxe_ip_associate(self):
+ self._create_pxe_ip()
+ node = db.bm_node_create(self.context, utils.new_bm_node())
+ ip_id = db.bm_pxe_ip_associate(self.context, node['id'])
+ ref = db.bm_pxe_ip_get(self.context, ip_id)
+ self.assertEqual(ref['bm_node_id'], node['id'])
+
+ def test_bm_pxe_ip_associate_raise(self):
+ self._create_pxe_ip()
+ node_id = 123
+ self.assertRaises(exception.NovaException,
+ db.bm_pxe_ip_associate,
+ self.context, node_id)
+
+ def test_delete_by_address(self):
+ self._create_pxe_ip()
+ db.bm_pxe_ip_destroy_by_address(self.context, '10.1.1.1')
+ del_ref = db.bm_pxe_ip_get(self.context, self.i1['id'])
+ self.assertTrue(del_ref is None)
+
+ def test_delete_by_address_not_exist(self):
+ self._create_pxe_ip()
+ del_ref = db.bm_pxe_ip_destroy_by_address(self.context, '10.11.12.13')
+ self.assertTrue(del_ref is None)
diff --git a/nova/tests/baremetal/db/utils.py b/nova/tests/baremetal/db/utils.py
new file mode 100644
index 000000000..800305402
--- /dev/null
+++ b/nova/tests/baremetal/db/utils.py
@@ -0,0 +1,81 @@
+# Copyright (c) 2012 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.
+
+"""Bare-metal test utils."""
+
+from nova import test
+from nova.virt.baremetal.db.sqlalchemy import models as bm_models
+
+
+def new_bm_node(**kwargs):
+ h = bm_models.BareMetalNode()
+ h.id = kwargs.pop('id', None)
+ h.service_host = kwargs.pop('service_host', None)
+ h.instance_uuid = kwargs.pop('instance_uuid', None)
+ h.cpus = kwargs.pop('cpus', 1)
+ h.memory_mb = kwargs.pop('memory_mb', 1024)
+ h.local_gb = kwargs.pop('local_gb', 64)
+ h.pm_address = kwargs.pop('pm_address', '192.168.1.1')
+ h.pm_user = kwargs.pop('pm_user', 'ipmi_user')
+ h.pm_password = kwargs.pop('pm_password', 'ipmi_password')
+ h.prov_mac_address = kwargs.pop('prov_mac_address', '12:34:56:78:90:ab')
+ h.registration_status = kwargs.pop('registration_status', 'done')
+ h.task_state = kwargs.pop('task_state', None)
+ h.prov_vlan_id = kwargs.pop('prov_vlan_id', None)
+ h.terminal_port = kwargs.pop('terminal_port', 8000)
+ if len(kwargs) > 0:
+ raise test.TestingException("unknown field: %s"
+ % ','.join(kwargs.keys()))
+ return h
+
+
+def new_bm_pxe_ip(**kwargs):
+ x = bm_models.BareMetalPxeIp()
+ x.id = kwargs.pop('id', None)
+ x.address = kwargs.pop('address', None)
+ x.server_address = kwargs.pop('server_address', None)
+ x.bm_node_id = kwargs.pop('bm_node_id', None)
+ if len(kwargs) > 0:
+ raise test.TestingException("unknown field: %s"
+ % ','.join(kwargs.keys()))
+ return x
+
+
+def new_bm_interface(**kwargs):
+ x = bm_models.BareMetalInterface()
+ x.id = kwargs.pop('id', None)
+ x.bm_node_id = kwargs.pop('bm_node_id', None)
+ x.address = kwargs.pop('address', None)
+ x.datapath_id = kwargs.pop('datapath_id', None)
+ x.port_no = kwargs.pop('port_no', None)
+ x.vif_uuid = kwargs.pop('vif_uuid', None)
+ if len(kwargs) > 0:
+ raise test.TestingException("unknown field: %s"
+ % ','.join(kwargs.keys()))
+ return x
+
+
+def new_bm_deployment(**kwargs):
+ x = bm_models.BareMetalDeployment()
+ x.id = kwargs.pop('id', None)
+ x.key = kwargs.pop('key', None)
+ x.image_path = kwargs.pop('image_path', None)
+ x.pxe_config_path = kwargs.pop('pxe_config_path', None)
+ x.root_mb = kwargs.pop('root_mb', None)
+ x.swap_mb = kwargs.pop('swap_mb', None)
+ if len(kwargs) > 0:
+ raise test.TestingException("unknown field: %s"
+ % ','.join(kwargs.keys()))
+ return x