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>
This commit is contained in:
Mikyung Kang 2012-11-07 19:10:56 +09:00
parent 0416bd96a7
commit e0f10ea3be
19 changed files with 1514 additions and 0 deletions

View File

@ -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.

View File

@ -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()

View File

@ -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')

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,16 @@
# 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.
from nova.virt.baremetal.db.api import *

View File

@ -0,0 +1,175 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 NTT DOCOMO, INC.
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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.
"""Defines interface for DB access.
The underlying driver is loaded as a :class:`LazyPluggable`.
Functions in this module are imported into the nova.virt.baremetal.db
namespace. Call these functions from nova.virt.baremetal.db namespace, not
the nova.virt.baremetal.db.api namespace.
All functions in this module return objects that implement a dictionary-like
interface. Currently, many of these objects are sqlalchemy objects that
implement a dictionary interface. However, a future goal is to have all of
these objects be simple dictionaries.
**Related Flags**
:baremetal_db_backend: string to lookup in the list of LazyPluggable backends.
`sqlalchemy` is the only supported backend right now.
:baremetal_sql_connection: string specifying the sqlalchemy connection to use,
like: `sqlite:///var/lib/nova/nova.sqlite`.
"""
from nova import config
from nova.openstack.common import cfg
from nova import utils
db_opts = [
cfg.StrOpt('baremetal_db_backend',
default='sqlalchemy',
help='The backend to use for db'),
]
CONF = config.CONF
CONF.register_opts(db_opts)
IMPL = utils.LazyPluggable(
'baremetal_db_backend',
sqlalchemy='nova.virt.baremetal.db.sqlalchemy.api')
def bm_node_get_all(context, service_host=None):
return IMPL.bm_node_get_all(context,
service_host=service_host)
def bm_node_find_free(context, service_host=None,
memory_mb=None, cpus=None, local_gb=None):
return IMPL.bm_node_find_free(context,
service_host=service_host,
memory_mb=memory_mb,
cpus=cpus,
local_gb=local_gb)
def bm_node_get(context, bm_node_id):
return IMPL.bm_node_get(context, bm_node_id)
def bm_node_get_by_instance_uuid(context, instance_uuid):
return IMPL.bm_node_get_by_instance_uuid(context,
instance_uuid)
def bm_node_create(context, values):
return IMPL.bm_node_create(context, values)
def bm_node_destroy(context, bm_node_id):
return IMPL.bm_node_destroy(context, bm_node_id)
def bm_node_update(context, bm_node_id, values):
return IMPL.bm_node_update(context, bm_node_id, values)
def bm_pxe_ip_create(context, address, server_address):
return IMPL.bm_pxe_ip_create(context, address, server_address)
def bm_pxe_ip_create_direct(context, bm_pxe_ip):
return IMPL.bm_pxe_ip_create_direct(context, bm_pxe_ip)
def bm_pxe_ip_destroy(context, ip_id):
return IMPL.bm_pxe_ip_destroy(context, ip_id)
def bm_pxe_ip_destroy_by_address(context, address):
return IMPL.bm_pxe_ip_destroy_by_address(context, address)
def bm_pxe_ip_get_all(context):
return IMPL.bm_pxe_ip_get_all(context)
def bm_pxe_ip_get(context, ip_id):
return IMPL.bm_pxe_ip_get(context, ip_id)
def bm_pxe_ip_get_by_bm_node_id(context, bm_node_id):
return IMPL.bm_pxe_ip_get_by_bm_node_id(context, bm_node_id)
def bm_pxe_ip_associate(context, bm_node_id):
return IMPL.bm_pxe_ip_associate(context, bm_node_id)
def bm_pxe_ip_disassociate(context, bm_node_id):
return IMPL.bm_pxe_ip_disassociate(context, bm_node_id)
def bm_interface_get(context, if_id):
return IMPL.bm_interface_get(context, if_id)
def bm_interface_get_all(context):
return IMPL.bm_interface_get_all(context)
def bm_interface_destroy(context, if_id):
return IMPL.bm_interface_destroy(context, if_id)
def bm_interface_create(context, bm_node_id, address, datapath_id, port_no):
return IMPL.bm_interface_create(context, bm_node_id, address,
datapath_id, port_no)
def bm_interface_set_vif_uuid(context, if_id, vif_uuid):
return IMPL.bm_interface_set_vif_uuid(context, if_id, vif_uuid)
def bm_interface_get_by_vif_uuid(context, vif_uuid):
return IMPL.bm_interface_get_by_vif_uuid(context, vif_uuid)
def bm_interface_get_all_by_bm_node_id(context, bm_node_id):
return IMPL.bm_interface_get_all_by_bm_node_id(context, bm_node_id)
def bm_deployment_create(context, key, image_path, pxe_config_path, root_mb,
swap_mb):
return IMPL.bm_deployment_create(context, key, image_path,
pxe_config_path, root_mb, swap_mb)
def bm_deployment_get(context, dep_id):
return IMPL.bm_deployment_get(context, dep_id)
def bm_deployment_destroy(context, dep_id):
return IMPL.bm_deployment_destroy(context, dep_id)

View File

@ -0,0 +1,38 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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.
"""Database setup and migration commands."""
from nova import utils
IMPL = utils.LazyPluggable(
'baremetal_db_backend',
sqlalchemy='nova.virt.baremetal.db.sqlalchemy.migration')
INIT_VERSION = 0
def db_sync(version=None):
"""Migrate the database to `version` or the most recent version."""
return IMPL.db_sync(version=version)
def db_version():
"""Display the current database version."""
return IMPL.db_version()

View File

@ -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.

View File

@ -0,0 +1,351 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 NTT DOCOMO, INC.
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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.
"""Implementation of SQLAlchemy backend."""
from sqlalchemy import and_
from sqlalchemy.exc import IntegrityError
from sqlalchemy import or_
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import joinedload_all
from sqlalchemy.sql.expression import asc
from sqlalchemy.sql.expression import desc
from sqlalchemy.sql.expression import literal_column
from sqlalchemy.sql import func
from nova.db.sqlalchemy.api import is_user_context
from nova.db.sqlalchemy.api import require_admin_context
from nova import exception
from nova.openstack.common import log as logging
from nova.openstack.common import timeutils
from nova.virt.baremetal.db.sqlalchemy import models
from nova.virt.baremetal.db.sqlalchemy.session import get_session
LOG = logging.getLogger(__name__)
def model_query(context, *args, **kwargs):
"""Query helper that accounts for context's `read_deleted` field.
:param context: context to query under
:param session: if present, the session to use
:param read_deleted: if present, overrides context's read_deleted field.
:param project_only: if present and context is user-type, then restrict
query to match the context's project_id.
"""
session = kwargs.get('session') or get_session()
read_deleted = kwargs.get('read_deleted') or context.read_deleted
project_only = kwargs.get('project_only')
query = session.query(*args)
if read_deleted == 'no':
query = query.filter_by(deleted=False)
elif read_deleted == 'yes':
pass # omit the filter to include deleted and active
elif read_deleted == 'only':
query = query.filter_by(deleted=True)
else:
raise Exception(
_("Unrecognized read_deleted value '%s'") % read_deleted)
if project_only and is_user_context(context):
query = query.filter_by(project_id=context.project_id)
return query
def _save(ref, session=None):
if not session:
session = get_session()
# We must not call ref.save() with session=None, otherwise NovaBase
# uses nova-db's session, which cannot access bm-db.
ref.save(session=session)
def _build_node_order_by(query):
query = query.order_by(asc(models.BareMetalNode.memory_mb))
query = query.order_by(asc(models.BareMetalNode.cpus))
query = query.order_by(asc(models.BareMetalNode.local_gb))
return query
@require_admin_context
def bm_node_get_all(context, service_host=None):
query = model_query(context, models.BareMetalNode, read_deleted="no")
if service_host:
query = query.filter_by(service_host=service_host)
return query.all()
@require_admin_context
def bm_node_find_free(context, service_host=None,
cpus=None, memory_mb=None, local_gb=None):
query = model_query(context, models.BareMetalNode, read_deleted="no")
query = query.filter(models.BareMetalNode.instance_uuid == None)
if service_host:
query = query.filter_by(service_host=service_host)
if cpus is not None:
query = query.filter(models.BareMetalNode.cpus >= cpus)
if memory_mb is not None:
query = query.filter(models.BareMetalNode.memory_mb >= memory_mb)
if local_gb is not None:
query = query.filter(models.BareMetalNode.local_gb >= local_gb)
query = _build_node_order_by(query)
return query.first()
@require_admin_context
def bm_node_get(context, bm_node_id):
result = model_query(context, models.BareMetalNode, read_deleted="no").\
filter_by(id=bm_node_id).\
first()
return result
@require_admin_context
def bm_node_get_by_instance_uuid(context, instance_uuid):
result = model_query(context, models.BareMetalNode, read_deleted="no").\
filter_by(instance_uuid=instance_uuid).\
first()
return result
@require_admin_context
def bm_node_create(context, values):
bm_node_ref = models.BareMetalNode()
bm_node_ref.update(values)
_save(bm_node_ref)
return bm_node_ref
@require_admin_context
def bm_node_update(context, bm_node_id, values, ):
model_query(context, models.BareMetalNode, read_deleted="no").\
filter_by(id=bm_node_id).\
update(values)
@require_admin_context
def bm_node_destroy(context, bm_node_id):
model_query(context, models.BareMetalNode).\
filter_by(id=bm_node_id).\
update({'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')})
@require_admin_context
def bm_pxe_ip_get_all(context, session=None):
query = model_query(context, models.BareMetalPxeIp, read_deleted="no")
return query.all()
@require_admin_context
def bm_pxe_ip_create(context, address, server_address):
ref = models.BareMetalPxeIp()
ref.address = address
ref.server_address = server_address
_save(ref)
return ref
@require_admin_context
def bm_pxe_ip_create_direct(context, bm_pxe_ip):
ref = bm_pxe_ip_create(context,
address=bm_pxe_ip['address'],
server_address=bm_pxe_ip['server_address'])
return ref
@require_admin_context
def bm_pxe_ip_destroy(context, ip_id):
# Delete physically since it has unique columns
model_query(context, models.BareMetalPxeIp, read_deleted="no").\
filter_by(id=ip_id).\
delete()
@require_admin_context
def bm_pxe_ip_destroy_by_address(context, address):
# Delete physically since it has unique columns
model_query(context, models.BareMetalPxeIp, read_deleted="no").\
filter_by(address=address).\
delete()
@require_admin_context
def bm_pxe_ip_get(context, ip_id):
ref = model_query(context, models.BareMetalPxeIp, read_deleted="no").\
filter_by(id=ip_id).\
first()
return ref
@require_admin_context
def bm_pxe_ip_get_by_bm_node_id(context, bm_node_id):
ref = model_query(context, models.BareMetalPxeIp, read_deleted="no").\
filter_by(bm_node_id=bm_node_id).\
first()
return ref
@require_admin_context
def bm_pxe_ip_associate(context, bm_node_id):
session = get_session()
with session.begin():
# Check if the node really exists
node_ref = model_query(context, models.BareMetalNode,
read_deleted="no", session=session).\
filter_by(id=bm_node_id).\
first()
if not node_ref:
raise exception.NovaException("bm_node %s not found" % bm_node_id)
# Check if the node already has a pxe_ip
ip_ref = model_query(context, models.BareMetalPxeIp,
read_deleted="no", session=session).\
filter_by(bm_node_id=bm_node_id).\
first()
if ip_ref:
return ip_ref.id
# with_lockmode('update') and filter_by(bm_node_id=None) will lock all
# records. It may cause a performance problem in high-concurrency
# environment.
ip_ref = model_query(context, models.BareMetalPxeIp,
read_deleted="no", session=session).\
filter_by(bm_node_id=None).\
with_lockmode('update').\
first()
if not ip_ref:
raise exception.NovaException("free bm_pxe_ip not found")
ip_ref.bm_node_id = bm_node_id
session.add(ip_ref)
return ip_ref.id
@require_admin_context
def bm_pxe_ip_disassociate(context, bm_node_id):
model_query(context, models.BareMetalPxeIp, read_deleted="no").\
filter_by(bm_node_id=bm_node_id).\
update({'bm_node_id': None})
@require_admin_context
def bm_interface_get(context, if_id):
result = model_query(context, models.BareMetalInterface,
read_deleted="no").\
filter_by(id=if_id).\
first()
return result
def bm_interface_get_all(context):
query = model_query(context, models.BareMetalInterface,
read_deleted="no")
return query.all()
@require_admin_context
def bm_interface_destroy(context, if_id):
# Delete physically since it has unique columns
model_query(context, models.BareMetalInterface, read_deleted="no").\
filter_by(id=if_id).\
delete()
@require_admin_context
def bm_interface_create(context, bm_node_id, address, datapath_id, port_no):
ref = models.BareMetalInterface()
ref.bm_node_id = bm_node_id
ref.address = address
ref.datapath_id = datapath_id
ref.port_no = port_no
_save(ref)
return ref.id
@require_admin_context
def bm_interface_set_vif_uuid(context, if_id, vif_uuid):
session = get_session()
with session.begin():
ref = model_query(context, models.BareMetalInterface,
read_deleted="no", session=session).\
filter_by(id=if_id).\
with_lockmode('update').\
first()
if not ref:
raise exception.NovaException('interface id=%s is not found' %
if_id)
ref.vif_uuid = vif_uuid
try:
session.add(ref)
session.flush()
except IntegrityError:
raise exception.NovaException('vif_uuid %s is already assigned' %
vif_uuid)
@require_admin_context
def bm_interface_get_by_vif_uuid(context, vif_uuid):
result = model_query(context, models.BareMetalInterface,
read_deleted="no").\
filter_by(vif_uuid=vif_uuid).\
first()
return result
@require_admin_context
def bm_interface_get_all_by_bm_node_id(context, bm_node_id):
result = model_query(context, models.BareMetalInterface,
read_deleted="no").\
filter_by(bm_node_id=bm_node_id).\
all()
return result
@require_admin_context
def bm_deployment_create(context, key, image_path, pxe_config_path, root_mb,
swap_mb):
ref = models.BareMetalDeployment()
ref.key = key
ref.image_path = image_path
ref.pxe_config_path = pxe_config_path
ref.root_mb = root_mb
ref.swap_mb = swap_mb
_save(ref)
return ref.id
@require_admin_context
def bm_deployment_get(context, dep_id):
result = model_query(context, models.BareMetalDeployment,
read_deleted="no").\
filter_by(id=dep_id).\
first()
return result
@require_admin_context
def bm_deployment_destroy(context, dep_id):
model_query(context, models.BareMetalDeployment).\
filter_by(id=dep_id).\
update({'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')})

View File

@ -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.

View File

@ -0,0 +1,20 @@
[db_settings]
# Used to identify which repository this database is versioned under.
# You can use the name of your project.
repository_id=nova_bm
# The name of the database table used to track the schema version.
# This name shouldn't already be used by your project.
# If this is changed once a database is under version control, you'll need to
# change the table name in each database too.
version_table=migrate_version
# When committing a change script, Migrate will attempt to generate the
# sql for all supported databases; normally, if one of them fails - probably
# because you don't have that database installed - it is ignored and the
# commit continues, perhaps ending successfully.
# Databases in this list MUST compile successfully during a commit, or the
# entire commit will fail. List the databases your application will actually
# be using to ensure your updates to that database work properly.
# This must be a list; example: ['postgres','sqlite']
required_dbs=[]

View File

@ -0,0 +1,124 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# 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.
from migrate import ForeignKeyConstraint
from sqlalchemy import Boolean, BigInteger, Column, DateTime, Float, ForeignKey
from sqlalchemy import Index, Integer, MetaData, String, Table, Text
from nova.openstack.common import log as logging
LOG = logging.getLogger(__name__)
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
bm_nodes = Table('bm_nodes', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', Boolean),
Column('id', Integer, primary_key=True, nullable=False),
Column('cpus', Integer),
Column('memory_mb', Integer),
Column('local_gb', Integer),
Column('pm_address', String(length=255)),
Column('pm_user', String(length=255)),
Column('pm_password', String(length=255)),
Column('service_host', String(length=255)),
Column('prov_mac_address', String(length=255)),
Column('instance_uuid', String(length=36)),
Column('registration_status', String(length=16)),
Column('task_state', String(length=255)),
Column('prov_vlan_id', Integer),
Column('terminal_port', Integer),
mysql_engine='InnoDB',
#mysql_charset='utf8'
)
bm_interfaces = Table('bm_interfaces', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', Boolean),
Column('id', Integer, primary_key=True, nullable=False),
Column('bm_node_id', Integer),
Column('address', String(length=255), unique=True),
Column('datapath_id', String(length=255)),
Column('port_no', Integer),
Column('vif_uuid', String(length=36), unique=True),
mysql_engine='InnoDB',
#mysql_charset='utf8'
)
bm_pxe_ips = Table('bm_pxe_ips', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', Boolean),
Column('id', Integer, primary_key=True, nullable=False),
Column('address', String(length=255), unique=True),
Column('bm_node_id', Integer),
Column('server_address', String(length=255), unique=True),
mysql_engine='InnoDB',
#mysql_charset='utf8'
)
bm_deployments = Table('bm_deployments', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', Boolean),
Column('id', Integer, primary_key=True, nullable=False),
Column('bm_node_id', Integer),
Column('key', String(length=255)),
Column('image_path', String(length=255)),
Column('pxe_config_path', String(length=255)),
Column('root_mb', Integer),
Column('swap_mb', Integer),
mysql_engine='InnoDB',
#mysql_charset='utf8'
)
bm_nodes.create()
bm_interfaces.create()
bm_pxe_ips.create()
bm_deployments.create()
Index('idx_bm_nodes_service_host_deleted',
bm_nodes.c.service_host, bm_nodes.c.deleted)\
.create(migrate_engine)
Index('idx_bm_nodes_instance_uuid_deleted',
bm_nodes.c.instance_uuid, bm_nodes.c.deleted)\
.create(migrate_engine)
Index('idx_bm_nodes_hmcld',
bm_nodes.c.service_host, bm_nodes.c.memory_mb, bm_nodes.c.cpus,
bm_nodes.c.local_gb, bm_nodes.c.deleted)\
.create(migrate_engine)
Index('idx_bm_interfaces_bm_node_id_deleted',
bm_interfaces.c.bm_node_id, bm_interfaces.c.deleted)\
.create(migrate_engine)
Index('idx_bm_pxe_ips_bm_node_id_deleted',
bm_pxe_ips.c.bm_node_id, bm_pxe_ips.c.deleted)\
.create(migrate_engine)
def downgrade(migrate_engine):
pass

View File

@ -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.

View File

@ -0,0 +1,115 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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.
import distutils.version as dist_version
import migrate
from migrate.versioning import util as migrate_util
import os
import sqlalchemy
from nova import exception
from nova import flags
from nova.openstack.common import log as logging
from nova.virt.baremetal.db import migration
from nova.virt.baremetal.db.sqlalchemy.session import get_engine
LOG = logging.getLogger(__name__)
@migrate_util.decorator
def patched_with_engine(f, *a, **kw):
url = a[0]
engine = migrate_util.construct_engine(url, **kw)
try:
kw['engine'] = engine
return f(*a, **kw)
finally:
if isinstance(engine, migrate_util.Engine) and engine is not url:
migrate_util.log.debug('Disposing SQLAlchemy engine %s', engine)
engine.dispose()
# TODO(jkoelker) When migrate 0.7.3 is released and nova depends
# on that version or higher, this can be removed
MIN_PKG_VERSION = dist_version.StrictVersion('0.7.3')
if (not hasattr(migrate, '__version__') or
dist_version.StrictVersion(migrate.__version__) < MIN_PKG_VERSION):
migrate_util.with_engine = patched_with_engine
# NOTE(jkoelker) Delay importing migrate until we are patched
from migrate import exceptions as versioning_exceptions
from migrate.versioning import api as versioning_api
from migrate.versioning.repository import Repository
FLAGS = flags.FLAGS
_REPOSITORY = None
def db_sync(version=None):
if version is not None:
try:
version = int(version)
except ValueError:
raise exception.NovaException(_("version should be an integer"))
current_version = db_version()
repository = _find_migrate_repo()
if version is None or version > current_version:
return versioning_api.upgrade(get_engine(), repository, version)
else:
return versioning_api.downgrade(get_engine(), repository,
version)
def db_version():
repository = _find_migrate_repo()
try:
return versioning_api.db_version(get_engine(), repository)
except versioning_exceptions.DatabaseNotControlledError:
meta = sqlalchemy.MetaData()
engine = get_engine()
meta.reflect(bind=engine)
tables = meta.tables
if len(tables) == 0:
db_version_control(migration.INIT_VERSION)
return versioning_api.db_version(get_engine(), repository)
else:
# Some pre-Essex DB's may not be version controlled.
# Require them to upgrade using Essex first.
raise exception.NovaException(
_("Upgrade DB using Essex release first."))
def db_version_control(version=None):
repository = _find_migrate_repo()
versioning_api.version_control(get_engine(), repository, version)
return version
def _find_migrate_repo():
"""Get the path for the migrate repository."""
global _REPOSITORY
path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'migrate_repo')
assert os.path.exists(path)
if _REPOSITORY is None:
_REPOSITORY = Repository(path)
return _REPOSITORY

View File

@ -0,0 +1,80 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# 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.
"""
SQLAlchemy models for baremetal data.
"""
from sqlalchemy.orm import relationship, backref, object_mapper
from sqlalchemy import Column, Integer, BigInteger, String, schema
from sqlalchemy import ForeignKey, DateTime, Boolean, Text, Float, Index
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.schema import ForeignKeyConstraint
from nova.db.sqlalchemy import models
BASE = declarative_base()
class BareMetalNode(BASE, models.NovaBase):
"""Represents a bare metal node."""
__tablename__ = 'bm_nodes'
id = Column(Integer, primary_key=True)
service_host = Column(String(255))
instance_uuid = Column(String(36), nullable=True)
cpus = Column(Integer)
memory_mb = Column(Integer)
local_gb = Column(Integer)
pm_address = Column(Text)
pm_user = Column(Text)
pm_password = Column(Text)
prov_mac_address = Column(Text)
registration_status = Column(String(16))
task_state = Column(String(255))
prov_vlan_id = Column(Integer)
terminal_port = Column(Integer)
class BareMetalPxeIp(BASE, models.NovaBase):
__tablename__ = 'bm_pxe_ips'
id = Column(Integer, primary_key=True)
address = Column(String(255), unique=True)
server_address = Column(String(255), unique=True)
bm_node_id = Column(Integer, ForeignKey('bm_nodes.id'), nullable=True)
class BareMetalInterface(BASE, models.NovaBase):
__tablename__ = 'bm_interfaces'
id = Column(Integer, primary_key=True)
bm_node_id = Column(Integer, ForeignKey('bm_nodes.id'), nullable=True)
address = Column(String(255), unique=True)
datapath_id = Column(String(255))
port_no = Column(Integer)
vif_uuid = Column(String(36), unique=True)
class BareMetalDeployment(BASE, models.NovaBase):
__tablename__ = 'bm_deployments'
id = Column(Integer, primary_key=True)
key = Column(String(255))
image_path = Column(String(255))
pxe_config_path = Column(String(255))
root_mb = Column(Integer)
swap_mb = Column(Integer)

View File

@ -0,0 +1,58 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 NTT DOCOMO, INC.
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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.
"""Session Handling for SQLAlchemy backend."""
from nova import config
from nova.db.sqlalchemy import session as nova_session
from nova.openstack.common import cfg
opts = [
cfg.StrOpt('baremetal_sql_connection',
default='sqlite:///$state_path/baremetal_$sqlite_db',
help='The SQLAlchemy connection string used to connect to the '
'bare-metal database'),
]
CONF = config.CONF
CONF.register_opts(opts)
_ENGINE = None
_MAKER = None
def get_session(autocommit=True, expire_on_commit=False):
"""Return a SQLAlchemy session."""
global _MAKER
if _MAKER is None:
engine = get_engine()
_MAKER = nova_session.get_maker(engine, autocommit, expire_on_commit)
session = _MAKER()
session = nova_session.wrap_session(session)
return session
def get_engine():
"""Return a SQLAlchemy engine."""
global _ENGINE
if _ENGINE is None:
_ENGINE = nova_session.create_engine(CONF.baremetal_sql_connection)
return _ENGINE

View File

@ -0,0 +1,69 @@
General Bare-metal Provisioning README
======================================
:Authors:
[USC/ISI] Mikyung Kang <mkkang@isi.edu>, David Kang <dkang@isi.edu>
[NTT DOCOMO] Ken Igarashi <igarashik@nttdocomo.co.jp>
[VirtualTech Japan Inc.] Arata Notsu <notsu@virtualtech.jp>
:Date: 2012-08-02
:Version: 2012.8
:Wiki: http://wiki.openstack.org/GeneralBareMetalProvisioningFramework
Code changes
------------
::
nova/nova/virt/baremetal/*
nova/nova/virt/driver.py
nova/nova/tests/baremetal/*
nova/nova/tests/compute/test_compute.py
nova/nova/compute/manager.py
nova/nova/compute/resource_tracker.py
nova/nova/manager.py
nova/nova/scheduler/driver.py
nova/nova/scheduler/filter_scheduler.py
nova/nova/scheduler/host_manager.py
nova/nova/scheduler/baremetal_host_manager.py
nova/bin/bm_deploy_server
nova/bin/nova-bm-manage
Additional setting for bare-metal provisioning [nova.conf]
----------------------------------------------------------
::
# baremetal database connection
baremetal_sql_connection = mysql://$ID:$Password@$IP/nova_bm
# baremetal compute driver
compute_driver = nova.virt.baremetal.driver.BareMetalDriver
baremetal_driver = {nova.virt.baremetal.tilera.TILERA | nova.virt.baremetal.pxe.PXE}
power_manager = {nova.virt.baremetal.tilera_pdu.Pdu | nova.virt.baremetal.ipmi.Ipmi}
# instance_type_extra_specs this baremetal compute
instanse_type_extra_specs = cpu_arch:{tilepro64 | x86_64 | arm}
# TFTP root
baremetal_tftp_root = /tftpboot
# baremetal scheduler host manager
scheduler_host_manager = nova.scheduler.baremetal_host_manager.BaremetalHostManager
Non-PXE (Tilera) Bare-metal Provisioning
----------------------------------------
1. tilera-bm-instance-creation.rst
2. tilera-bm-installation.rst
PXE Bare-metal Provisioning
---------------------------
1. pxe-bm-instance-creation.rst
2. pxe-bm-installation.rst