Rename ipmi driver to ipmitool

To make naming more consistent with other ipmi drivers that
will be introduced later, the module name for ipmi driver
that uses the ipmitool is renamed from ipmi to ipmitool.

Change-Id: I8ec0d4beb29a06af7b27d3ff0620fab5446579b1
This commit is contained in:
linggao
2013-09-09 20:52:18 +00:00
parent 1332226918
commit 772a6df3d4
2 changed files with 2 additions and 258 deletions

View File

@@ -1,256 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# coding=utf-8
# Copyright 2012 Hewlett-Packard Development Company, L.P.
# 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.
"""
Ironic IPMI power manager.
"""
import contextlib
import os
import stat
import tempfile
from oslo.config import cfg
from ironic.common import exception
from ironic.common import paths
from ironic.common import states
from ironic.common import utils
from ironic.conductor import task_manager
from ironic.drivers import base
from ironic.openstack.common import excutils
from ironic.openstack.common import jsonutils as json
from ironic.openstack.common import log as logging
from ironic.openstack.common import loopingcall
opts = [
cfg.StrOpt('terminal',
default='shellinaboxd',
help='path to baremetal terminal program'),
cfg.StrOpt('terminal_cert_dir',
default=None,
help='path to baremetal terminal SSL cert(PEM)'),
cfg.StrOpt('terminal_pid_dir',
default=paths.state_path_def('baremetal/console'),
help='path to directory stores pidfiles of baremetal_terminal'),
cfg.IntOpt('ipmi_power_retry',
default=5,
help='Maximum seconds to retry IPMI operations'),
]
CONF = cfg.CONF
CONF.register_opts(opts)
LOG = logging.getLogger(__name__)
VALID_BOOT_DEVICES = ['pxe', 'disk', 'safe', 'cdrom', 'bios']
@contextlib.contextmanager
def _make_password_file(password):
try:
fd, path = tempfile.mkstemp()
os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR)
with os.fdopen(fd, "w") as f:
f.write(password)
yield path
utils.delete_if_exists(path)
except Exception:
with excutils.save_and_reraise_exception():
utils.delete_if_exists(path)
def _parse_driver_info(node):
driver_info = json.loads(node.get('driver_info', ''))
ipmi_info = driver_info.get('ipmi')
address = ipmi_info.get('address', None)
username = ipmi_info.get('username', None)
password = ipmi_info.get('password', None)
port = ipmi_info.get('terminal_port', None)
if not address or not username or not password:
raise exception.InvalidParameterValue(_(
"IPMI credentials not supplied to IPMI driver."))
return {
'address': address,
'username': username,
'password': password,
'port': port,
'uuid': node.get('uuid')
}
def _exec_ipmitool(driver_info, command):
args = ['ipmitool',
'-I',
'lanplus',
'-H',
driver_info['address'],
'-U',
driver_info['username'],
'-f']
with _make_password_file(driver_info['password']) as pw_file:
args.append(pw_file)
args.extend(command.split(" "))
out, err = utils.execute(*args, attempts=3)
LOG.debug(_("ipmitool stdout: '%(out)s', stderr: '%(err)s'"),
locals())
return out, err
def _power_on(driver_info):
"""Turn the power to this node ON."""
# use mutable objects so the looped method can change them
state = [None]
retries = [0]
def _wait_for_power_on(state, retries):
"""Called at an interval until the node's power is on."""
state[0] = _power_status(driver_info)
if state[0] == states.POWER_ON:
raise loopingcall.LoopingCallDone()
if retries[0] > CONF.ipmi_power_retry:
state[0] = states.ERROR
raise loopingcall.LoopingCallDone()
try:
retries[0] += 1
_exec_ipmitool(driver_info, "power on")
except Exception:
# Log failures but keep trying
LOG.warning(_("IPMI power on failed for node %s.")
% driver_info['uuid'])
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_power_on,
state, retries)
timer.start(interval=1).wait()
return state[0]
def _power_off(driver_info):
"""Turn the power to this node OFF."""
# use mutable objects so the looped method can change them
state = [None]
retries = [0]
def _wait_for_power_off(state, retries):
"""Called at an interval until the node's power is off."""
state[0] = _power_status(driver_info)
if state[0] == states.POWER_OFF:
raise loopingcall.LoopingCallDone()
if retries[0] > CONF.ipmi_power_retry:
state[0] = states.ERROR
raise loopingcall.LoopingCallDone()
try:
retries[0] += 1
_exec_ipmitool(driver_info, "power off")
except Exception:
# Log failures but keep trying
LOG.warning(_("IPMI power off failed for node %s.")
% driver_info['uuid'])
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_power_off,
state=state, retries=retries)
timer.start(interval=1).wait()
return state[0]
def _power_status(driver_info):
out_err = _exec_ipmitool(driver_info, "power status")
if out_err[0] == "Chassis Power is on\n":
return states.POWER_ON
elif out_err[0] == "Chassis Power is off\n":
return states.POWER_OFF
else:
return states.ERROR
class IPMIPower(base.PowerInterface):
def validate(self, node):
"""Check that node['driver_info'] contains IPMI credentials.
:param node: Single node object.
:raises: InvalidParameterValue
"""
_parse_driver_info(node)
def get_power_state(self, task, node):
"""Get the current power state."""
driver_info = _parse_driver_info(node)
return _power_status(driver_info)
@task_manager.require_exclusive_lock
def set_power_state(self, task, node, pstate):
"""Turn the power on or off."""
driver_info = _parse_driver_info(node)
if pstate == states.POWER_ON:
state = _power_on(driver_info)
elif pstate == states.POWER_OFF:
state = _power_off(driver_info)
else:
raise exception.IronicException(_(
"set_power_state called with invalid power state."))
if state != pstate:
raise exception.PowerStateFailure(pstate=pstate)
@task_manager.require_exclusive_lock
def reboot(self, task, node):
"""Cycles the power to a node."""
driver_info = _parse_driver_info(node)
_power_off(driver_info)
state = _power_on(driver_info)
if state != states.POWER_ON:
raise exception.PowerStateFailure(pstate=states.POWER_ON)
@task_manager.require_exclusive_lock
def _set_boot_device(self, task, node, device, persistent=False):
"""Set the boot device for a node.
:param task: a TaskManager instance.
:param node: The Node.
:param device: Boot device. One of [pxe, disk, cdrom, safe, bios].
:param persistent: Whether to set next-boot, or make the change
permanent. Default: False.
:raises: InvalidParameterValue if an invalid boot device is specified.
:raises: IPMIFailure on an error from ipmitool.
"""
if device not in VALID_BOOT_DEVICES:
raise exception.InvalidParameterValue(_(
"Invalid boot device %s specified.") % device)
cmd = "chassis bootdev %s" % device
if persistent:
cmd = cmd + " options=persistent"
driver_info = _parse_driver_info(node)
try:
out, err = _exec_ipmitool(driver_info, cmd)
# TODO(deva): validate (out, err) and add unit test for failure
except Exception:
raise exception.IPMIFailure(cmd=cmd)

View File

@@ -35,10 +35,10 @@ console_scripts =
ironic.drivers =
fake = ironic.drivers.fake:FakeDriver
fake_ipmi = ironic.drivers.fake:FakeIPMIDriver
fake_ipmitool = ironic.drivers.fake:FakeIPMIToolDriver
fake_ssh = ironic.drivers.fake:FakeSSHDriver
fake_pxe = ironic.drivers.fake:FakePXEDriver
pxe_ipmi = ironic.drivers.pxe:PXEAndIPMIDriver
pxe_ipmitool = ironic.drivers.pxe:PXEAndIPMIToolDriver
pxe_ssh = ironic.drivers.pxe:PXEAndSSHDriver
[pbr]