summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-12-20 19:23:30 +0000
committerGerrit Code Review <review@openstack.org>2012-12-20 19:23:30 +0000
commit6085602f1b266d31d08b4a4b5bd33f7768d53a81 (patch)
treed9ffc4ee1d47f5c80d7e7ba18fe98a5cf1c34907
parente979dbce43bf13bedff6264c4b4302cf7a9126a4 (diff)
parentc846477f4bf9a615b251b0038163fe1a5d088880 (diff)
downloadnova-6085602f1b266d31d08b4a4b5bd33f7768d53a81.tar.gz
nova-6085602f1b266d31d08b4a4b5bd33f7768d53a81.tar.xz
nova-6085602f1b266d31d08b4a4b5bd33f7768d53a81.zip
Merge "New Baremetal provisioning framework."
-rw-r--r--etc/nova/rootwrap.d/compute.filters3
-rw-r--r--nova/tests/baremetal/__init__.py2
-rw-r--r--nova/tests/baremetal/db/__init__.py1
-rw-r--r--nova/tests/baremetal/db/test_bm_interface.py17
-rw-r--r--nova/tests/baremetal/db/utils.py1
-rw-r--r--nova/tests/baremetal/test_driver.py173
-rw-r--r--nova/virt/baremetal/__init__.py1
-rw-r--r--nova/virt/baremetal/baremetal_states.py32
-rw-r--r--nova/virt/baremetal/base.py75
-rw-r--r--nova/virt/baremetal/db/api.py8
-rw-r--r--nova/virt/baremetal/db/sqlalchemy/api.py40
-rw-r--r--nova/virt/baremetal/driver.py368
-rw-r--r--nova/virt/baremetal/fake.py75
-rw-r--r--nova/virt/baremetal/interfaces.template31
-rw-r--r--nova/virt/baremetal/utils.py37
15 files changed, 797 insertions, 67 deletions
diff --git a/etc/nova/rootwrap.d/compute.filters b/etc/nova/rootwrap.d/compute.filters
index cb7ad7487..baf4f1c92 100644
--- a/etc/nova/rootwrap.d/compute.filters
+++ b/etc/nova/rootwrap.d/compute.filters
@@ -166,3 +166,6 @@ lvs: CommandFilter, /sbin/lvs, root
# nova/virt/libvirt/utils.py:
vgs: CommandFilter, /sbin/vgs, root
+
+# nova/virt/baremetal/volume_driver.py: 'tgtadm', '--lld', 'iscsi', ...
+tgtadm: CommandFilter, /usr/sbin/tgtadm, root
diff --git a/nova/tests/baremetal/__init__.py b/nova/tests/baremetal/__init__.py
index eef64faeb..f15d84efc 100644
--- a/nova/tests/baremetal/__init__.py
+++ b/nova/tests/baremetal/__init__.py
@@ -12,4 +12,4 @@
# 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.tests import *
+from nova.tests.baremetal import *
diff --git a/nova/tests/baremetal/db/__init__.py b/nova/tests/baremetal/db/__init__.py
index 19071662c..543dfc1ae 100644
--- a/nova/tests/baremetal/db/__init__.py
+++ b/nova/tests/baremetal/db/__init__.py
@@ -12,3 +12,4 @@
# 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.tests.baremetal.db import *
diff --git a/nova/tests/baremetal/db/test_bm_interface.py b/nova/tests/baremetal/db/test_bm_interface.py
index 9f051ac9b..a9168bff6 100644
--- a/nova/tests/baremetal/db/test_bm_interface.py
+++ b/nova/tests/baremetal/db/test_bm_interface.py
@@ -35,20 +35,3 @@ class BareMetalInterfaceTestCase(base.BMDBTestCase):
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.NovaException,
- db.bm_interface_set_vif_uuid,
- self.context, pif2_id, 'AAAA')
-
- def test_vif_not_found(self):
- pif_id = db.bm_interface_create(self.context, 1, '11:11:11:11:11:11',
- '0x1', 1)
- self.assertRaises(exception.NovaException,
- db.bm_interface_set_vif_uuid,
- self.context, pif_id + 1, 'AAAA')
diff --git a/nova/tests/baremetal/db/utils.py b/nova/tests/baremetal/db/utils.py
index 800305402..034f2f25a 100644
--- a/nova/tests/baremetal/db/utils.py
+++ b/nova/tests/baremetal/db/utils.py
@@ -60,7 +60,6 @@ def new_bm_interface(**kwargs):
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()))
diff --git a/nova/tests/baremetal/test_driver.py b/nova/tests/baremetal/test_driver.py
new file mode 100644
index 000000000..117520e94
--- /dev/null
+++ b/nova/tests/baremetal/test_driver.py
@@ -0,0 +1,173 @@
+# Copyright (c) 2012 NTT DOCOMO, INC.
+# Copyright (c) 2011 University of Southern California / ISI
+# 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.
+
+"""
+Tests for baremetal driver.
+"""
+
+import mox
+
+from nova import exception
+from nova.openstack.common import cfg
+from nova import test
+from nova.tests.baremetal.db import base
+from nova.tests.baremetal.db import utils
+from nova.tests.image import fake as fake_image
+from nova.tests import test_virt_drivers
+from nova.tests import utils as test_utils
+from nova.virt.baremetal import baremetal_states
+from nova.virt.baremetal import db
+from nova.virt.baremetal import driver as bm_driver
+from nova.virt.firewall import NoopFirewallDriver
+
+
+CONF = cfg.CONF
+
+
+FakeFirewallDriver = NoopFirewallDriver
+
+
+NODE = utils.new_bm_node(cpus=2, memory_mb=4096, service_host="host1")
+NICS = [
+ {'address': '01:23:45:67:89:01', 'datapath_id': '0x1', 'port_no': 1, },
+ {'address': '01:23:45:67:89:02', 'datapath_id': '0x2', 'port_no': 2, },
+ ]
+
+
+def class_path(class_):
+ return class_.__module__ + '.' + class_.__name__
+
+
+COMMON_FLAGS = dict(
+ baremetal_sql_connection='sqlite:///:memory:',
+ baremetal_driver='nova.virt.baremetal.fake.Fake',
+ power_manager='nova.virt.baremetal.fake.FakePowerManager',
+ firewall_driver=class_path(FakeFirewallDriver),
+ instance_type_extra_specs=['cpu_arch:test'],
+ host=NODE['service_host'],
+)
+
+
+def _create_baremetal_stuff():
+ context = test_utils.get_test_admin_context()
+ node = db.bm_node_create(context, NODE)
+ for nic in NICS:
+ db.bm_interface_create(context,
+ node['id'],
+ nic['address'],
+ nic['datapath_id'],
+ nic['port_no'])
+ return node
+
+
+class BaremetalDriverSpawnTestCase(base.Database):
+
+ def setUp(self):
+ super(BaremetalDriverSpawnTestCase, self).setUp()
+ self.flags(**COMMON_FLAGS)
+ fake_image.stub_out_image_service(self.stubs)
+
+ self.node = _create_baremetal_stuff()
+ self.node_id = self.node['id']
+
+ self.context = test_utils.get_test_admin_context()
+ self.instance = test_utils.get_test_instance()
+ self.network_info = test_utils.get_test_network_info()
+ self.block_device_info = None
+ self.image_meta = test_utils.get_test_image_info(None, self.instance)
+ self.driver = bm_driver.BareMetalDriver(None)
+ self.kwargs = dict(
+ context=self.context,
+ instance=self.instance,
+ image_meta=self.image_meta,
+ injected_files=[('/foo', 'bar'), ('/abc', 'xyz')],
+ admin_password='testpass',
+ network_info=self.network_info,
+ block_device_info=self.block_device_info)
+ self.addCleanup(fake_image.FakeImageService_reset)
+
+ def test_ok(self):
+ self.instance['node'] = str(self.node_id)
+ self.driver.spawn(**self.kwargs)
+ node = db.bm_node_get(self.context, self.node_id)
+ self.assertEqual(node['instance_uuid'], self.instance['uuid'])
+ self.assertEqual(node['task_state'], baremetal_states.ACTIVE)
+
+ def test_without_node(self):
+ self.assertRaises(
+ exception.NovaException,
+ self.driver.spawn,
+ **self.kwargs)
+
+ def test_node_not_found(self):
+ self.instance['node'] = "123456789"
+ self.assertRaises(
+ exception.InstanceNotFound,
+ self.driver.spawn,
+ **self.kwargs)
+
+ def test_node_in_use(self):
+ self.instance['node'] = str(self.node_id)
+ db.bm_node_update(self.context, self.node_id,
+ {'instance_uuid': 'something'})
+ self.assertRaises(
+ exception.NovaException,
+ self.driver.spawn,
+ **self.kwargs)
+
+
+class BaremetalDriverTestCase(test_virt_drivers._VirtDriverTestCase,
+ base.Database):
+
+ def setUp(self):
+ super(BaremetalDriverTestCase, self).setUp()
+ self.driver_module = 'nova.virt.baremetal.BareMetalDriver'
+ self.flags(**COMMON_FLAGS)
+ self.node = _create_baremetal_stuff()
+ self.node_id = self.node['id']
+ fake_image.stub_out_image_service(self.stubs)
+ self.addCleanup(fake_image.FakeImageService_reset)
+
+ def _get_running_instance(self):
+ instance_ref = test_utils.get_test_instance()
+ instance_ref['node'] = str(self.node_id)
+ network_info = test_utils.get_test_network_info()
+ image_info = test_utils.get_test_image_info(None, instance_ref)
+ self.connection.spawn(self.ctxt, instance_ref, image_info,
+ [], 'herp', network_info=network_info)
+ return instance_ref, network_info
+
+ def test_loading_baremetal_drivers(self):
+ from nova.virt.baremetal import fake
+ drv = bm_driver.BareMetalDriver(None)
+ self.assertTrue(isinstance(drv.baremetal_nodes, fake.Fake))
+ self.assertTrue(isinstance(drv._firewall_driver, FakeFirewallDriver))
+
+ def test_get_host_stats(self):
+ self.flags(instance_type_extra_specs=['cpu_arch:x86_64',
+ 'x:123',
+ 'y:456', ])
+ drv = bm_driver.BareMetalDriver(None)
+ cap_list = drv.get_host_stats()
+ self.assertTrue(isinstance(cap_list, list))
+ self.assertEqual(len(cap_list), 1)
+ cap = cap_list[0]
+ self.assertEqual(cap['cpu_arch'], 'x86_64')
+ self.assertEqual(cap['x'], '123')
+ self.assertEqual(cap['y'], '456')
+ self.assertEqual(cap['hypervisor_type'], 'baremetal')
+ self.assertEqual(cap['baremetal_driver'],
+ 'nova.virt.baremetal.fake.Fake')
diff --git a/nova/virt/baremetal/__init__.py b/nova/virt/baremetal/__init__.py
index 19071662c..e3ecef821 100644
--- a/nova/virt/baremetal/__init__.py
+++ b/nova/virt/baremetal/__init__.py
@@ -12,3 +12,4 @@
# 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.driver import BareMetalDriver
diff --git a/nova/virt/baremetal/baremetal_states.py b/nova/virt/baremetal/baremetal_states.py
new file mode 100644
index 000000000..28a41ab47
--- /dev/null
+++ b/nova/virt/baremetal/baremetal_states.py
@@ -0,0 +1,32 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2012 NTT DOCOMO, INC.
+# Copyright 2010 OpenStack LLC.
+# 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.
+
+"""
+Possible baremetal node states for instances.
+
+Compute instance baremetal states represent the state of an instance as it
+pertains to a user or administrator. When combined with task states
+(task_states.py), a better picture can be formed regarding the instance's
+health.
+
+"""
+
+ACTIVE = 'active'
+BUILDING = 'building'
+DELETED = 'deleted'
+ERROR = 'error'
diff --git a/nova/virt/baremetal/base.py b/nova/virt/baremetal/base.py
new file mode 100644
index 000000000..4b0640885
--- /dev/null
+++ b/nova/virt/baremetal/base.py
@@ -0,0 +1,75 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2012 NTT DOCOMO, INC.
+# Copyright (c) 2011 University of Southern California / ISI
+# 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 import baremetal_states
+
+
+class NodeDriver(object):
+
+ def define_vars(self, instance, network_info, block_device_info):
+ raise NotImplementedError()
+
+ def create_image(self, var, context, image_meta, node, instance,
+ injected_files=None, admin_password=None):
+ raise NotImplementedError()
+
+ def destroy_images(self, var, context, node, instance):
+ raise NotImplementedError()
+
+ def activate_bootloader(self, var, context, node, instance, image_meta):
+ raise NotImplementedError()
+
+ def deactivate_bootloader(self, var, context, node, instance):
+ raise NotImplementedError()
+
+ def activate_node(self, var, context, node, instance):
+ """For operations after power on."""
+ raise NotImplementedError()
+
+ def deactivate_node(self, var, context, node, instance):
+ """For operations before power off."""
+ raise NotImplementedError()
+
+ def get_console_output(self, node, instance):
+ raise NotImplementedError()
+
+
+class PowerManager(object):
+
+ def __init__(self, node):
+ pass
+
+ def activate_node(self):
+ return baremetal_states.ACTIVE
+
+ def reboot_node(self):
+ return baremetal_states.ACTIVE
+
+ def deactivate_node(self):
+ return baremetal_states.DELETED
+
+ def is_power_on(self):
+ """Returns True or False according as the node's power state"""
+ return True
+
+ # TODO(NTTdocomo): split out console methods to its own class
+ def start_console(self):
+ pass
+
+ def stop_console(self):
+ pass
diff --git a/nova/virt/baremetal/db/api.py b/nova/virt/baremetal/db/api.py
index 0b8cf781c..15d50dd66 100644
--- a/nova/virt/baremetal/db/api.py
+++ b/nova/virt/baremetal/db/api.py
@@ -148,14 +148,6 @@ def bm_interface_create(context, bm_node_id, address, datapath_id, port_no):
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)
diff --git a/nova/virt/baremetal/db/sqlalchemy/api.py b/nova/virt/baremetal/db/sqlalchemy/api.py
index 48606ac44..bb85d677f 100644
--- a/nova/virt/baremetal/db/sqlalchemy/api.py
+++ b/nova/virt/baremetal/db/sqlalchemy/api.py
@@ -311,46 +311,6 @@ def bm_interface_create(context, bm_node_id, address, datapath_id, port_no):
@require_admin_context
-def bm_interface_set_vif_uuid(context, if_id, vif_uuid):
- session = get_session()
- with session.begin():
- bm_interface = model_query(context, models.BareMetalInterface,
- read_deleted="no", session=session).\
- filter_by(id=if_id).\
- with_lockmode('update').\
- first()
- if not bm_interface:
- raise exception.NovaException(_("Baremetal interface %s "
- "not found") % if_id)
-
- bm_interface.vif_uuid = vif_uuid
- try:
- session.add(bm_interface)
- session.flush()
- except exception.DBError, e:
- # TODO(deva): clean up when db layer raises DuplicateKeyError
- if str(e).find('IntegrityError') != -1:
- raise exception.NovaException(_("Baremetal interface %s "
- "already in use") % vif_uuid)
- else:
- raise e
-
-
-@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()
-
- if not result:
- raise exception.NovaException(_("Baremetal virtual interface %s "
- "not found") % vif_uuid)
-
- 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").\
diff --git a/nova/virt/baremetal/driver.py b/nova/virt/baremetal/driver.py
new file mode 100644
index 000000000..043fba421
--- /dev/null
+++ b/nova/virt/baremetal/driver.py
@@ -0,0 +1,368 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# coding=utf-8
+#
+# Copyright (c) 2012 NTT DOCOMO, INC
+# Copyright (c) 2011 University of Southern California / ISI
+# 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.
+
+"""
+A driver for Bare-metal platform.
+"""
+
+from nova.compute import power_state
+from nova import context as nova_context
+from nova import exception
+from nova.openstack.common import cfg
+from nova.openstack.common import importutils
+from nova.openstack.common import log as logging
+from nova.virt.baremetal import baremetal_states
+from nova.virt.baremetal import db as bmdb
+from nova.virt import driver
+from nova.virt import firewall
+from nova.virt.libvirt import imagecache
+
+opts = [
+ cfg.BoolOpt('baremetal_inject_password',
+ default=True,
+ help='Whether baremetal compute injects password or not'),
+ cfg.StrOpt('baremetal_injected_network_template',
+ default='$pybasedir/nova/virt/baremetal/interfaces.template',
+ help='Template file for injected network'),
+ cfg.ListOpt('instance_type_extra_specs',
+ default=[],
+ help='a list of additional capabilities corresponding to '
+ 'instance_type_extra_specs for this compute '
+ 'host to advertise. Valid entries are name=value, pairs '
+ 'For example, "key1:val1, key2:val2"'),
+ cfg.StrOpt('baremetal_driver',
+ default='nova.virt.baremetal.pxe.PXE',
+ help='Baremetal driver back-end (pxe or tilera)'),
+ cfg.StrOpt('power_manager',
+ default='nova.virt.baremetal.ipmi.Ipmi',
+ help='Baremetal power management method'),
+ cfg.StrOpt('baremetal_tftp_root',
+ default='/tftpboot',
+ help='Baremetal compute node\'s tftp root path'),
+ ]
+
+
+LOG = logging.getLogger(__name__)
+
+CONF = cfg.CONF
+CONF.register_opts(opts)
+
+DEFAULT_FIREWALL_DRIVER = "%s.%s" % (
+ firewall.__name__,
+ firewall.NoopFirewallDriver.__name__)
+
+
+def _get_baremetal_nodes(context):
+ nodes = bmdb.bm_node_get_all(context, service_host=CONF.host)
+ return nodes
+
+
+def _get_baremetal_node_by_instance_uuid(instance_uuid):
+ ctx = nova_context.get_admin_context()
+ node = bmdb.bm_node_get_by_instance_uuid(ctx, instance_uuid)
+ if node['service_host'] != CONF.host:
+ LOG.error(_("Request for baremetal node %s "
+ "sent to wrong service host") % instance_uuid)
+ raise exception.InstanceNotFound(instance_id=instance_uuid)
+ return node
+
+
+def _update_baremetal_state(context, node, instance, state):
+ instance_uuid = None
+ if instance:
+ instance_uuid = instance['uuid']
+ bmdb.bm_node_update(context, node['id'],
+ {'instance_uuid': instance_uuid,
+ 'task_state': state,
+ })
+
+
+def get_power_manager(node, **kwargs):
+ cls = importutils.import_class(CONF.power_manager)
+ return cls(node, **kwargs)
+
+
+class BareMetalDriver(driver.ComputeDriver):
+ """BareMetal hypervisor driver."""
+
+ capabilities = {
+ "has_imagecache": True,
+ }
+
+ def __init__(self, virtapi, read_only=False):
+ super(BareMetalDriver, self).__init__(virtapi)
+
+ self.baremetal_nodes = importutils.import_object(
+ CONF.baremetal_driver)
+ self._firewall_driver = firewall.load_driver(
+ default=DEFAULT_FIREWALL_DRIVER)
+ self._image_cache_manager = imagecache.ImageCacheManager()
+
+ extra_specs = {}
+ extra_specs["baremetal_driver"] = CONF.baremetal_driver
+ for pair in CONF.instance_type_extra_specs:
+ keyval = pair.split(':', 1)
+ keyval[0] = keyval[0].strip()
+ keyval[1] = keyval[1].strip()
+ extra_specs[keyval[0]] = keyval[1]
+ if not 'cpu_arch' in extra_specs:
+ LOG.warning(
+ _('cpu_arch is not found in instance_type_extra_specs'))
+ extra_specs['cpu_arch'] = ''
+ self._extra_specs = extra_specs
+
+ self._supported_instances = [
+ (extra_specs['cpu_arch'], 'baremetal', 'baremetal'),
+ ]
+
+ @classmethod
+ def instance(cls):
+ if not hasattr(cls, '_instance'):
+ cls._instance = cls()
+ return cls._instance
+
+ def init_host(self, host):
+ return
+
+ def get_hypervisor_type(self):
+ return 'baremetal'
+
+ def get_hypervisor_version(self):
+ # TODO(deva): define the version properly elsewhere
+ return 1
+
+ def list_instances(self):
+ l = []
+ ctx = nova_context.get_admin_context()
+ for node in _get_baremetal_nodes(ctx):
+ if node['instance_uuid']:
+ inst = self.virtapi.instance_get_by_uuid(ctx,
+ node['instance_uuid'])
+ if inst:
+ l.append(inst['name'])
+ return l
+
+ def spawn(self, context, instance, image_meta, injected_files,
+ admin_password, network_info=None, block_device_info=None):
+ nodename = instance.get('node')
+ if not nodename:
+ raise exception.NovaException(_("Baremetal node id not supplied"
+ " to driver"))
+ node = bmdb.bm_node_get(context, nodename)
+ if node['instance_uuid']:
+ raise exception.NovaException(_("Baremetal node %s already"
+ " in use") % nodename)
+
+ # TODO(deva): split this huge try: block into manageable parts
+ try:
+ _update_baremetal_state(context, node, instance,
+ baremetal_states.BUILDING)
+
+ var = self.baremetal_nodes.define_vars(instance, network_info,
+ block_device_info)
+
+ self._firewall_driver.setup_basic_filtering(instance, network_info)
+ self._firewall_driver.prepare_instance_filter(instance,
+ network_info)
+
+ self.baremetal_nodes.create_image(var, context, image_meta, node,
+ instance,
+ injected_files=injected_files,
+ admin_password=admin_password)
+ self.baremetal_nodes.activate_bootloader(var, context, node,
+ instance, image_meta)
+ pm = get_power_manager(node)
+ state = pm.activate_node()
+
+ _update_baremetal_state(context, node, instance, state)
+
+ self.baremetal_nodes.activate_node(var, context, node, instance)
+ self._firewall_driver.apply_instance_filter(instance, network_info)
+
+ pm.start_console()
+
+ except Exception, e:
+ # TODO(deva): add tooling that can revert a failed spawn
+ _update_baremetal_state(context, node, instance,
+ baremetal_states.ERROR)
+ raise e
+
+ def reboot(self, instance, network_info, reboot_type,
+ block_device_info=None):
+ node = _get_baremetal_node_by_instance_uuid(instance['uuid'])
+ ctx = nova_context.get_admin_context()
+ pm = get_power_manager(node)
+ state = pm.reboot_node()
+ _update_baremetal_state(ctx, node, instance, state)
+
+ def destroy(self, instance, network_info, block_device_info=None):
+ ctx = nova_context.get_admin_context()
+
+ try:
+ node = _get_baremetal_node_by_instance_uuid(instance['uuid'])
+ except exception.InstanceNotFound:
+ # TODO(deva): refactor so that dangling files can be cleaned
+ # up even after a failed boot or delete
+ LOG.warning(_("Delete called on non-existing instance %s")
+ % instance['uuid'])
+ return
+
+ var = self.baremetal_nodes.define_vars(instance, network_info,
+ block_device_info)
+
+ self.baremetal_nodes.deactivate_node(var, ctx, node, instance)
+
+ pm = get_power_manager(node)
+
+ pm.stop_console()
+
+ ## power off the node
+ state = pm.deactivate_node()
+
+ self.baremetal_nodes.deactivate_bootloader(var, ctx, node, instance)
+
+ self.baremetal_nodes.destroy_images(var, ctx, node, instance)
+
+ # stop firewall
+ self._firewall_driver.unfilter_instance(instance,
+ network_info=network_info)
+
+ _update_baremetal_state(ctx, node, None, state)
+
+ def power_off(self, instance):
+ """Power off the specified instance."""
+ node = _get_baremetal_node_by_instance_uuid(instance['uuid'])
+ pm = get_power_manager(node)
+ pm.deactivate_node()
+
+ def power_on(self, instance):
+ """Power on the specified instance"""
+ node = _get_baremetal_node_by_instance_uuid(instance['uuid'])
+ pm = get_power_manager(node)
+ pm.activate_node()
+
+ def get_info(self, instance):
+ # NOTE(deva): compute/manager.py expects to get NotFound exception
+ # so we convert from InstanceNotFound
+ inst_uuid = instance.get('uuid')
+ node = _get_baremetal_node_by_instance_uuid(inst_uuid)
+ pm = get_power_manager(node)
+ ps = power_state.SHUTDOWN
+ if pm.is_power_on():
+ ps = power_state.RUNNING
+ return {'state': ps,
+ 'max_mem': node['memory_mb'],
+ 'mem': node['memory_mb'],
+ 'num_cpu': node['cpus'],
+ 'cpu_time': 0}
+
+ def refresh_security_group_rules(self, security_group_id):
+ self._firewall_driver.refresh_security_group_rules(security_group_id)
+ return True
+
+ def refresh_security_group_members(self, security_group_id):
+ self._firewall_driver.refresh_security_group_members(security_group_id)
+ return True
+
+ def refresh_provider_fw_rules(self):
+ self._firewall_driver.refresh_provider_fw_rules()
+
+ def _node_resource(self, node):
+ vcpus_used = 0
+ memory_mb_used = 0
+ local_gb_used = 0
+
+ vcpus = node['cpus']
+ memory_mb = node['memory_mb']
+ local_gb = node['local_gb']
+ if node['registration_status'] != 'done' or node['instance_uuid']:
+ vcpus_used = node['cpus']
+ memory_mb_used = node['memory_mb']
+ local_gb_used = node['local_gb']
+
+ dic = {'vcpus': vcpus,
+ 'memory_mb': memory_mb,
+ 'local_gb': local_gb,
+ 'vcpus_used': vcpus_used,
+ 'memory_mb_used': memory_mb_used,
+ 'local_gb_used': local_gb_used,
+ 'hypervisor_type': self.get_hypervisor_type(),
+ 'hypervisor_version': self.get_hypervisor_version(),
+ 'hypervisor_hostname': str(node['id']),
+ 'cpu_info': 'baremetal cpu',
+ }
+ return dic
+
+ def refresh_instance_security_rules(self, instance):
+ self._firewall_driver.refresh_instance_security_rules(instance)
+
+ def get_available_resource(self, nodename):
+ context = nova_context.get_admin_context()
+ node = bmdb.bm_node_get(context, nodename)
+ dic = self._node_resource(node)
+ return dic
+
+ def ensure_filtering_rules_for_instance(self, instance_ref, network_info):
+ self._firewall_driver.setup_basic_filtering(instance_ref, network_info)
+ self._firewall_driver.prepare_instance_filter(instance_ref,
+ network_info)
+
+ def unfilter_instance(self, instance_ref, network_info):
+ self._firewall_driver.unfilter_instance(instance_ref,
+ network_info=network_info)
+
+ def get_host_stats(self, refresh=False):
+ caps = []
+ context = nova_context.get_admin_context()
+ nodes = bmdb.bm_node_get_all(context,
+ service_host=CONF.host)
+ for node in nodes:
+ res = self._node_resource(node)
+ nodename = str(node['id'])
+ data = {}
+ data['vcpus'] = res['vcpus']
+ data['vcpus_used'] = res['vcpus_used']
+ data['cpu_info'] = res['cpu_info']
+ data['disk_total'] = res['local_gb']
+ data['disk_used'] = res['local_gb_used']
+ data['disk_available'] = res['local_gb'] - res['local_gb_used']
+ data['host_memory_total'] = res['memory_mb']
+ data['host_memory_free'] = res['memory_mb'] - res['memory_mb_used']
+ data['hypervisor_type'] = res['hypervisor_type']
+ data['hypervisor_version'] = res['hypervisor_version']
+ data['hypervisor_hostname'] = nodename
+ data['supported_instances'] = self._supported_instances
+ data.update(self._extra_specs)
+ data['host'] = CONF.host
+ data['node'] = nodename
+ # TODO(NTTdocomo): put node's extra specs here
+ caps.append(data)
+ return caps
+
+ def manage_image_cache(self, context, all_instances):
+ """Manage the local cache of images."""
+ self._image_cache_manager.verify_base_images(context, all_instances)
+
+ def get_console_output(self, instance):
+ node = _get_baremetal_node_by_instance_uuid(instance['uuid'])
+ return self.baremetal_nodes.get_console_output(node, instance)
+
+ def get_available_nodes(self):
+ context = nova_context.get_admin_context()
+ return [str(n['id']) for n in _get_baremetal_nodes(context)]
diff --git a/nova/virt/baremetal/fake.py b/nova/virt/baremetal/fake.py
new file mode 100644
index 000000000..9df964c39
--- /dev/null
+++ b/nova/virt/baremetal/fake.py
@@ -0,0 +1,75 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2012 NTT DOCOMO, INC.
+# Copyright (c) 2011 University of Southern California / ISI
+# 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 import baremetal_states
+from nova.virt.baremetal import base
+
+
+def get_baremetal_nodes():
+ return Fake()
+
+
+class Fake(base.NodeDriver):
+
+ def define_vars(self, instance, network_info, block_device_info):
+ return {}
+
+ def create_image(self, var, context, image_meta, node, instance,
+ injected_files=None, admin_password=None):
+ pass
+
+ def destroy_images(self, var, context, node, instance):
+ pass
+
+ def activate_bootloader(self, var, context, node, instance, image_meta):
+ pass
+
+ def deactivate_bootloader(self, var, context, node, instance):
+ pass
+
+ def activate_node(self, var, context, node, instance):
+ """For operations after power on."""
+ pass
+
+ def deactivate_node(self, var, context, node, instance):
+ """For operations before power off."""
+ pass
+
+ def get_console_output(self, node, instance):
+ return 'fake\nconsole\noutput for instance %s' % instance['id']
+
+
+class FakePowerManager(base.PowerManager):
+
+ def activate_node(self):
+ return baremetal_states.ACTIVE
+
+ def reboot_node(self):
+ return baremetal_states.ACTIVE
+
+ def deactivate_node(self):
+ return baremetal_states.DELETED
+
+ def is_power_on(self):
+ return True
+
+ def start_console(self):
+ pass
+
+ def stop_console(self):
+ pass
diff --git a/nova/virt/baremetal/interfaces.template b/nova/virt/baremetal/interfaces.template
new file mode 100644
index 000000000..94776ed49
--- /dev/null
+++ b/nova/virt/baremetal/interfaces.template
@@ -0,0 +1,31 @@
+# Injected by Nova on instance boot
+#
+# This file describes the network interfaces available on your system
+# and how to activate them. For more information, see interfaces(5).
+
+# The loopback network interface
+auto lo
+iface lo inet loopback
+
+#for $ifc in $interfaces
+auto ${ifc.name}
+iface ${ifc.name} inet static
+ address ${ifc.address}
+ netmask ${ifc.netmask}
+ broadcast ${ifc.broadcast}
+ gateway ${ifc.gateway}
+#if $ifc.dns
+ dns-nameservers ${ifc.dns}
+#end if
+#if $ifc.hwaddress
+ hwaddress ether ${ifc.hwaddress}
+#end if
+
+#if $use_ipv6
+iface ${ifc.name} inet6 static
+ address ${ifc.address_v6}
+ netmask ${ifc.netmask_v6}
+ gateway ${ifc.gateway_v6}
+#end if
+
+#end for
diff --git a/nova/virt/baremetal/utils.py b/nova/virt/baremetal/utils.py
new file mode 100644
index 000000000..e34ca60f3
--- /dev/null
+++ b/nova/virt/baremetal/utils.py
@@ -0,0 +1,37 @@
+# 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.
+
+import os
+
+from nova.openstack.common import log as logging
+from nova.virt.libvirt import utils as libvirt_utils
+
+
+LOG = logging.getLogger(__name__)
+
+
+def cache_image(context, target, image_id, user_id, project_id):
+ if not os.path.exists(target):
+ libvirt_utils.fetch_image(context, target, image_id,
+ user_id, project_id)
+
+
+def unlink_without_raise(path):
+ try:
+ libvirt_utils.file_delete(path)
+ except OSError:
+ LOG.exception(_("failed to unlink %s") % path)