summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/tests/baremetal/test_driver.py34
-rw-r--r--nova/tests/baremetal/test_ipmi.py15
-rwxr-xr-xnova/virt/baremetal/driver.py18
-rw-r--r--nova/virt/baremetal/ipmi.py50
4 files changed, 98 insertions, 19 deletions
diff --git a/nova/tests/baremetal/test_driver.py b/nova/tests/baremetal/test_driver.py
index f01725370..3b0295a92 100644
--- a/nova/tests/baremetal/test_driver.py
+++ b/nova/tests/baremetal/test_driver.py
@@ -22,6 +22,7 @@
from oslo.config import cfg
+from nova.compute import power_state
from nova import exception
from nova import test
from nova.tests.baremetal.db import base as bm_db_base
@@ -327,3 +328,36 @@ class BareMetalDriverWithDBTestCase(bm_db_base.BMDBTestCase):
self.driver.destroy(**node2['destroy_params'])
self.assertEqual([], self.driver.list_instances())
+
+ def test_get_info_no_such_node(self):
+ node = self._create_node()
+ self.assertRaises(exception.InstanceNotFound,
+ self.driver.get_info,
+ node['instance'])
+
+ def test_get_info_ok(self):
+ node = self._create_node()
+ db.bm_node_associate_and_update(self.context, node['node']['uuid'],
+ {'instance_uuid': node['instance']['uuid'],
+ 'instance_name': node['instance']['hostname'],
+ 'task_state': baremetal_states.ACTIVE})
+ res = self.driver.get_info(node['instance'])
+ self.assertEqual(res['state'], power_state.RUNNING)
+
+ def test_get_info_with_defunct_pm(self):
+ # test fix for bug 1178378
+ node = self._create_node()
+ db.bm_node_associate_and_update(self.context, node['node']['uuid'],
+ {'instance_uuid': node['instance']['uuid'],
+ 'instance_name': node['instance']['hostname'],
+ 'task_state': baremetal_states.ACTIVE})
+
+ # fake the power manager and don't get a power state
+ self.mox.StubOutWithMock(fake.FakePowerManager, 'is_power_on')
+ fake.FakePowerManager.is_power_on().AndReturn(None)
+ self.mox.ReplayAll()
+
+ res = self.driver.get_info(node['instance'])
+ # prior to the fix, returned power_state was SHUTDOWN
+ self.assertEqual(res['state'], power_state.NOSTATE)
+ self.mox.VerifyAll()
diff --git a/nova/tests/baremetal/test_ipmi.py b/nova/tests/baremetal/test_ipmi.py
index faf800a46..01bb58d8b 100644
--- a/nova/tests/baremetal/test_ipmi.py
+++ b/nova/tests/baremetal/test_ipmi.py
@@ -85,13 +85,24 @@ class BareMetalIPMITestCase(test.TestCase):
self.ipmi._exec_ipmitool('A B C')
self.mox.VerifyAll()
- def test_is_power(self):
+ def test_is_power_on_ok(self):
self.mox.StubOutWithMock(self.ipmi, '_exec_ipmitool')
self.ipmi._exec_ipmitool("power status").AndReturn(
["Chassis Power is on\n"])
self.mox.ReplayAll()
- self.ipmi._is_power("on")
+ res = self.ipmi.is_power_on()
+ self.assertEqual(res, True)
+ self.mox.VerifyAll()
+
+ def test_is_power_no_answer(self):
+ self.mox.StubOutWithMock(self.ipmi, '_exec_ipmitool')
+ self.ipmi._exec_ipmitool("power status").AndReturn(
+ ["Fake reply\n"])
+ self.mox.ReplayAll()
+
+ res = self.ipmi.is_power_on()
+ self.assertEqual(res, None)
self.mox.VerifyAll()
def test_power_already_on(self):
diff --git a/nova/virt/baremetal/driver.py b/nova/virt/baremetal/driver.py
index 736b511b9..376921360 100755
--- a/nova/virt/baremetal/driver.py
+++ b/nova/virt/baremetal/driver.py
@@ -354,15 +354,21 @@ class BareMetalDriver(driver.ComputeDriver):
instance_name, mountpoint)
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=node, instance=instance)
- ps = power_state.SHUTDOWN
- if pm.is_power_on():
- ps = power_state.RUNNING
- return {'state': ps,
+
+ # NOTE(deva): Power manager may not be able to determine power state
+ # in which case it may return "None" here.
+ ps = pm.is_power_on()
+ if ps:
+ pstate = power_state.RUNNING
+ elif ps is False:
+ pstate = power_state.SHUTDOWN
+ else:
+ pstate = power_state.NOSTATE
+
+ return {'state': pstate,
'max_mem': node['memory_mb'],
'mem': node['memory_mb'],
'num_cpu': node['cpus'],
diff --git a/nova/virt/baremetal/ipmi.py b/nova/virt/baremetal/ipmi.py
index d4377e6fa..5d4f2b0ed 100644
--- a/nova/virt/baremetal/ipmi.py
+++ b/nova/virt/baremetal/ipmi.py
@@ -138,17 +138,13 @@ class IPMI(base.PowerManager):
finally:
bm_utils.unlink_without_raise(pwfile)
- def _is_power(self, state):
- out_err = self._exec_ipmitool("power status")
- return out_err[0] == ("Chassis Power is %s\n" % state)
-
def _power_on(self):
"""Turn the power to this node ON."""
def _wait_for_power_on():
"""Called at an interval until the node's power is on."""
- if self._is_power("on"):
+ if self.is_power_on():
self.state = baremetal_states.ACTIVE
raise loopingcall.LoopingCallDone()
if self.retries > CONF.baremetal.ipmi_power_retry:
@@ -170,7 +166,7 @@ class IPMI(base.PowerManager):
def _wait_for_power_off():
"""Called at an interval until the node's power is off."""
- if self._is_power("off"):
+ if self.is_power_on() is False:
self.state = baremetal_states.DELETED
raise loopingcall.LoopingCallDone()
if self.retries > CONF.baremetal.ipmi_power_retry:
@@ -193,8 +189,15 @@ class IPMI(base.PowerManager):
LOG.exception(_("IPMI set next bootdev failed"))
def activate_node(self):
- """Turns the power to node ON."""
- if self._is_power("on") and self.state == baremetal_states.ACTIVE:
+ """Turns the power to node ON.
+
+ Sets node next-boot to PXE and turns the power on,
+ waiting up to ipmi_power_retry/2 seconds for confirmation
+ that the power is on.
+
+ :returns: One of baremetal_states.py, representing the new state.
+ """
+ if self.is_power_on() and self.state == baremetal_states.ACTIVE:
LOG.warning(_("Activate node called, but node %s "
"is already active") % self.address)
self._set_pxe_for_next_boot()
@@ -202,19 +205,44 @@ class IPMI(base.PowerManager):
return self.state
def reboot_node(self):
- """Cycles the power to a node."""
+ """Cycles the power to a node.
+
+ Turns the power off, sets next-boot to PXE, and turns the power on.
+ Each action waits up to ipmi_power_retry/2 seconds for confirmation
+ that the power state has changed.
+
+ :returns: One of baremetal_states.py, representing the new state.
+ """
self._power_off()
self._set_pxe_for_next_boot()
self._power_on()
return self.state
def deactivate_node(self):
- """Turns the power to node OFF, regardless of current state."""
+ """Turns the power to node OFF.
+
+ Turns the power off, and waits up to ipmi_power_retry/2 seconds
+ for confirmation that the power is off.
+
+ :returns: One of baremetal_states.py, representing the new state.
+ """
self._power_off()
return self.state
def is_power_on(self):
- return self._is_power("on")
+ """Check if the power is currently on.
+
+ :returns: True if on; False if off; None if unable to determine.
+ """
+ # NOTE(deva): string matching based on
+ # http://ipmitool.cvs.sourceforge.net/
+ # viewvc/ipmitool/ipmitool/lib/ipmi_chassis.c
+ res = self._exec_ipmitool("power status")[0]
+ if res == ("Chassis Power is on\n"):
+ return True
+ elif res == ("Chassis Power is off\n"):
+ return False
+ return None
def start_console(self):
if not self.port: