Lazy wrote:
Sorry about my previous post, probably gmail did something nasty to it.
Hi,
I'm trying to get my head around OpenIPMI python bindings. And it
isn't going well so far. I want to monitor servers threw lan.
openipmigui.py is complicated, and I failed
to google any other python examples.
Maybe someone here wrote something similar and can share a peace of code ?
Any help will be appreciated.
Yeah, I really need some examples. I'm attaching a small program that
plugs into a management system; the plugin resets and controls power on
IPMI targets. It should be useful for you as an example, though it
doesn't work stand-alone. You still have to know how the basic library
works, the Python binding are a relatively thin binding over C. It also
has a bunch of daemon-handling that is useful.
If you get a working program, I would love it if it was something that
could be included as an example in the OpenIPMI package.
-corey
"""mvtrm_ipmi_resetter - External resource manager plugin for resetting
via IPMI
:version: 1.0.0
:author: Corey Minyard <[EMAIL PROTECTED]>
:organization: MontaVista Software
:copyright: Copyright 2007 MontaVista Software, Inc. All rights reserved.
:requires:
- `Python 2.2+ <http://www.python.org>`__
"""
import traceback
from StringIO import StringIO
import mvtrm
import mvtrm.client
import OpenIPMI
import sys
import selector
import threading
ipmi_to_log_level_map = {
"INFO" : mvtrm.LOG_INFO,
"WARN" : mvtrm.LOG_WARNING,
"SEVR" : mvtrm.LOG_SEVERE,
"FATL" : mvtrm.LOG_FATAL,
"EINF" : mvtrm.LOG_INFO,
"DEBG" : mvtrm.LOG_DEBUG
}
domains = { }
class DomainInfo:
def __init__(self, name, args, handler):
self.name = name
self.args = args
# Turn off stuff we don't need
self.args.insert(0, '-nofrus')
self.args.insert(0, '-nosel')
self.args.insert(0, '-nosetseltime')
self.first_connect = True
self.controls = { }
self.control_handlers = [ handler ]
self.domain_id = OpenIPMI.open_domain2(name, self.args, self)
if self.domain_id == None:
raise RuntimeError("Invalid domain arguments")
domains[name] = self
return
def AddControlHandler(self, handler):
self.control_handlers.append(handler)
for c,i in self.controls.items():
handler.NewControl(c, i)
pass
return
def IterateControls(self, handler):
for c,i in self.controls.items():
handler.NewControl(c, i)
pass
return
def RemoveControlHandler(self, handler):
self.control_handler.remove(handler)
if len(self.control_handlers) == 0:
del domains[self.name]
self.domain_id.to_domain(self)
pass
return
def domain_cb(self, domain):
domain.close(self)
return
def domain_close_done_cb(self):
return
def entity_update_cb(self, op, domain, entity):
if (op == "added"):
entity.add_control_update_handler(self)
for c in self.control_handlers:
c.NewEntity(entity.get_name(),
entity.get_id())
pass
pass
elif op == "deleted":
for c in self.control_handlers:
c.RemoveEntity(entity.get_name(),
entity.get_id())
pass
pass
return
def entity_control_update_cb(self, op, entity, control):
if (op == "added"):
self.controls[control.get_name()] = control.get_id()
for c in self.control_handlers:
c.NewControl(control.get_name(),
control.get_id())
pass
pass
elif (op == "deleted"):
del self.controls[control.get_name()]
for c in self.control_handlers:
c.RemoveControl(control.get_name(),
control.get_id())
pass
pass
return
def conn_change_cb(self, domain, err, conn_num, port_num, connected):
if self.first_connect:
self.first_connect = False
domain.add_entity_update_handler(self)
pass
return
pass
class IPMIResetInfo:
def __init__(self, client, resource, resetinfo):
self.client = client
self.resource = resource
args = mvtrm.client.lex_split(resetinfo)
self.domain = args[0]
del args[0]
self.__setvalues(args)
if self.domain not in domains:
DomainInfo(self.domain, args, self)
pass
else:
domains[self.domain].AddControlHandler(self)
pass
return
def __setvalues(self, args):
self.reset_control = None
self.power_control = None
self.power_entity = None
i = args[0].find(":")
while i >= 0:
t,v = args[0].split(":", 1)
if (t == "reset"):
self.reset_control = v
pass
elif (t == "power"):
self.power_control = v
pass
elif (t == "powent"):
self.power_entity = v
pass
else:
raise ValueError("Invalid control: " + t)
del args[0]
if len(args) == 0:
break
i = args[0].find(":")
pass
self.reset_control_id = None
self.power_control_id = None
self.power_entity_id = None
return
def close(self):
domains[self.domain].RemoveControlHandler(self)
return
def NewControl(self, name, id):
if self.reset_control == name:
self.client.ErrorHandler(mvtrm.LOG_INFO,
"Found reset control " + name)
self.reset_control_id = id
pass
elif self.power_control == name:
self.client.ErrorHandler(mvtrm.LOG_INFO,
"Found power control " + name)
self.power_control_id = id
pass
return
def RemoveControl(self, name, id):
if self.reset_control == name:
self.client.ErrorHandler(mvtrm.LOG_INFO,
"Removed reset control "
+ name)
self.reset_control_id = None
pass
elif self.power_control == name:
self.client.ErrorHandler(mvtrm.LOG_INFO,
"Removed power control "
+ name)
self.power_control_id = None
pass
return
def NewEntity(self, name, id):
if self.power_entity == name:
self.client.ErrorHandler(mvtrm.LOG_INFO,
"Found power entity " + name)
self.power_entity_id = id
pass
return
def RemoveEntity(self, name, id):
if self.power_entity == name:
self.client.ErrorHandler(mvtrm.LOG_INFO,
"Removed power entity "
+ name)
self.power_entity_id = None
pass
return
def UpdateResetInfo(self, resetinfo):
args = mvtrm.client.lex_split(resetinfo)
domain = args[0]
del args[0]
if domain != self.domain:
domains[self.domain].RemoveControlHandler(self)
self.domain = domain
self.__setvalues(args)
if self.domain not in domains:
DomainInfo(self.domain, args, self)
pass
else:
domains[self.domain].AddControlHandler(self)
pass
pass
else:
self.__setvalues(args)
domains[self.domain].IterateControls(self)
pass
return
def HandleMsg(self, msg, response):
try:
mt = msg.GetAttr("msgtype")
if mt == "IPMIReset":
self.Reset()
else:
v = int(msg['value'])
self.Power(v)
pass
pass
except Exception, err:
so = StringIO()
traceback.print_exc(None, so)
response.SetAttr('error', so.getvalue())
pass
self.client.send(response)
return
def Reset(self):
if self.reset_control_id is None:
raise RuntimeError("Control %s has not been found"
% (str(self.reset_control)))
return
self.op = "reset"
self.rv = 0
rv = self.reset_control_id.to_control(self)
if rv == 0:
rv = self.rv
if rv != 0:
raise RuntimeError("Error resetting device: "
+ OpenIPMI.get_error_string(rv))
return
def Power(self, value=0):
if self.power_control_id is not None:
self.value = int(value)
self.op = "power"
self.rv = 0
rv = self.power_control_id.to_control(self)
if rv == 0:
rv = self.rv
pass
pass
elif self.power_entity_id is not None:
self.value = int(value)
self.op = "power"
self.rv = 0
rv = self.power_entity_id.to_entity(self)
if rv == 0:
rv = self.rv
pass
pass
elif self.power_control:
raise RuntimeError("Control %s has not been found"
% (self.power_control))
else:
raise RuntimeError("Entity %s has not been found"
% (self.power_entity))
return
if rv != 0:
raise RuntimeError("Error powering device: "
+ OpenIPMI.get_error_string(rv))
elif self.value == 0:
self.client.ResourceAttributeSet(self.resource,
{ "State" : "off" })
pass
else:
self.client.ResourceAttributeSet(self.resource,
{ "State" : "on" })
pass
return
def control_cb(self, control):
if self.op == "reset":
self.client.ErrorHandler(
mvtrm.LOG_INFO,
"reset " + control.get_name())
self.rv = control.set_val([1])
elif self.op == "power":
self.client.ErrorHandler(
mvtrm.LOG_INFO,
"power(%s) %s" % (str(self.value),
control.get_name()))
self.rv = control.set_val([self.value])
return
def entity_cb(self, entity):
if self.value:
# power on
self.client.ErrorHandler(
mvtrm.LOG_INFO,
"activate " + entity.get_name())
self.rv = entity.set_activation_requested()
if self.rv:
self.rv = entity.activate()
pass
else:
# power off
self.client.ErrorHandler(
mvtrm.LOG_INFO,
"deactivate " + entity.get_name())
self.rv = entity.deactivate()
pass
return
pass
class IPMIResetClient(mvtrm.client.Client):
def __init__(self, host='localhost', port=None, adminpw="",
log=None, sel=None):
mvtrm.client.Client.__init__(self, host=host, port=port,
log=log, sel=sel)
OpenIPMI.set_log_handler(self)
OpenIPMI.init()
self.infos = { }
self.AdminEnable(adminpw)
self.initializing = True
self.initinfoq = [ ]
self.initmsgq = [ ]
self.PluginAdd("IPMIReset")
self.PluginAdd("IPMIPower")
# Find all the resources that have IPMIResetInfo set in
# them and configure them.
mylist = self.ResourceList(('re',
("$", ("string", "IPMIResetInfo")),
("string", ".*")))
for resource in mylist:
a = self.ResourceAttributeGet(resource,
["IPMIResetInfo"])
self.__new_rsrc(resource, a['IPMIResetInfo'])
pass
# Play back everything that we received while initializing.
self.initializing = False
for m in self.initinfoq:
self.InfoHandler(m)
pass
for m in self.initmsgq:
self.RequestHandler(m)
del self.initinfoq
del self.initmsgq
return
# OpenIPMI log handler
def log(self, level, log):
self.ErrorHandler(ipmi_to_log_level_map[level], log)
return
def __new_rsrc(self, resource, attrs):
try:
self.infos[resource] = IPMIResetInfo(self, resource, attrs)
pass
except Exception, err:
so = StringIO()
traceback.print_exc(None, so)
self.ErrorHandler(mvtrm.LOG_SEVERE,
"Error setting up reset for "
+ resource + " (" + str(attrs)
+ "): " + so.getvalue())
pass
return
def __rsrc_change(self, resource, attrs):
try:
self.infos[resource].UpdateResetInfo(attrs)
pass
except Exception, err:
so = StringIO()
traceback.print_exc(None, so)
self.ErrorHandler(mvtrm.LOG_SEVERE,
"Error changing reset info for"
+ resource + " (" + str(attrs)
+ "): " + so.getvalue())
pass
return
def InfoHandler(self, msg):
if self.initializing:
self.initinfoq.append(msg)
return
# Watch for messages that modify IPMIResetInfo
mt = msg.GetAttr("msgtype")
if mt == "ResourceRemove":
r = msg['resource']
if r in self.infos:
v = self.infos[r]
del self.infos[r]
v.close()
pass
pass
elif mt == "ResourceAdd":
a = msg['initattr']
if "IPMIResetInfo" in a:
r = msg['resource']
v = a['IPMIResetInfo']
self.__new_rsrc(r, v)
pass
pass
elif mt == "ResourceAttributeSet":
a = msg['attributes']
if "IPMIResetInfo" in a:
r = msg['resource']
v = a['IPMIResetInfo']
if r in self.infos:
try:
self.__rsrc_change(r, v)
pass
except Exception, err:
pass
pass
else:
self.__new_rsrc(r, v)
pass
pass
pass
# Ignore everything else.
return
def RequestHandler(self, msg):
if self.initializing:
self.initmsgq.append(msg)
return
mt = msg.GetAttr("msgtype")
response = mvtrm.GetRMMsg(msgclass="Response", msgtype=mt)
response.SetAttr('msgid', msg.GetAttr('msgid'))
response['plugin_seq'] = msg['plugin_seq']
try:
if ((mt == "IPMIReset") or (mt == "IPMIPower")):
rs = msg["resources"]
o = msg['plugin_resources_isowner']
r = rs[0]
if not msg['plugin_isadmin'] and not o[r]:
raise RuntimeError(
("resource %s not "
+ "owned by client.")
% (r))
if r not in self.infos:
raise RuntimeError(
("resource %s does "
+ "not support IPMI "
+ "reset/power.")
% (r))
t = threading.Thread(
target=self.infos[r].HandleMsg,
args=(msg, response))
t.start()
pass
else:
raise ValueError("Invalid message type: " + mt)
pass
except Exception, err:
so = StringIO()
traceback.print_exc(None, so)
response.SetAttr('error', so.getvalue())
self.send(response)
pass
return
pass
DEFAULT_HOST = "localhost"
DEFAULT_PIDFILE = "/var/run/mvtrm_ipmi_resetter.pid"
DEFAULT_PWFILE = "/etc/mvtrm/adminpw"
def usage(argv):
print ("%s [--port <port>] [--host <host>] [--daemon]"
% argv[0])
print " [--pwf <file> ] [--user <user>] [--group <group>]"
print " [--pidfile <file>] [--syslog] [--savepid]"
print " Start the IPMI reset daemon. This connects to the"
print " resource manager, reads information about IPMI resetting"
print " from the targets, and sets up to reset/power control the"
print " targets. Options are:"
print " --port <port> - Connect to the resource maanger using the"
print (" given port. If the port is not specified use %d."
% (mvtrm.RESMGR_PORT))
print " --host <host> - Connect to the resource manager on the given"
print (" host. If the host is not specified, use %s."
% (DEFAULT_HOST))
print " --daemon - run the process as a daemon, double forking,"
print " sending the logs to syslog, and storing the pid in the"
print " pidfile."
print " --pwf <file> - Read the admin password from the given file."
print " Only the first line is read. If not specified, use"
print (" %s. If that file does not exist, use an empty password."
% (DEFAULT_PWFILE))
print " --user <user> - Switch to the given user after startup."
print " --group <group> - Switch to the given group after startup."
print " --syslog - Send logs to the syslog."
print " --savepid - Save the pid in the pidfile."
print " --pidfile <file> - Use the given pidfile instead of"
print " %s." % (DEFAULT_PIDFILE)
return
import os, errno, signal
gotsig = None
def sighandler(sig, frame):
global gotsig
gotsig = sig
return
def idfromname(fn, name):
"""Read a name's id from a group or password file."""
rid = None
try:
f = open(fn, "r")
s = f.readline()
while s:
try:
vname, x, vid, rest = s.split(":", 3)
if name == vname:
rid = int(vid)
break
pass
except Exception, err:
pass
s = f.readline()
pass
pass
except:
pass
return rid
def startup(argv):
global gotsig
i = 1
port = None
host = DEFAULT_HOST
daemon = False
log = None
user = None
group = None
savepid = False
pidfile = DEFAULT_PIDFILE
pwfile = DEFAULT_PWFILE
pw = ""
do_syslog = False
while i < len(argv):
if argv[i] == "--port" or argv[i] == '-p':
i += 1
if i >= len(argv):
print "port not given with " + argv[i-1]
usage(argv)
return 1
try:
port = int(argv[i])
except:
print "Port not an integer: " + argv[i]
usage(argv)
return 1
pass
elif argv[i] == "--host" or argv[i] == '-h':
i += 1
if i >= len(argv):
print "host not given with " + argv[i-1]
usage(argv)
return 1
host = argv[i]
pass
elif argv[i] == "--pwf" or argv[i] == '-a':
i += 1
if i >= len(argv):
print "file not given with " + argv[i-1]
usage(argv)
return 1
f = open(argv[1], "r")
pw = f.readline()
f.close()
pw = pw.rstrip("\n")
pwfile = None
pass
elif argv[i] == "--user" or argv[i] == '-u':
i += 1
if i >= len(argv):
print "user not given with " + argv[i-1]
usage(argv)
return 1
user = argv[i]
pass
elif argv[i] == "--group" or argv[i] == '-g':
i += 1
if i >= len(argv):
print "group not given with " + argv[i-1]
usage(argv)
return 1
group = argv[i]
pass
elif argv[i] == "--pidfile" or argv[i] == '-m':
i += 1
if i >= len(argv):
print "file not given with " + argv[i-1]
usage(argv)
return 1
pidfile = argv[i]
pass
elif argv[i] == "--savepid":
savepid = True
elif argv[i] == "--syslog":
do_syslog = True
elif argv[i] == "--daemon":
daemon = True
do_syslog = True
savepid = True
elif argv[i] == "--help" or argv[i] == '-?':
usage(argv)
return 0
else:
print "Invalid parameter: " + argv[i]
usage(argv)
return 1
pass
i += 1
pass
if pwfile:
# No password file specified, try to read it from the
# default file. Don't care if it fails.
try:
f = open(pwfile, "r")
try:
pw = f.readline()
except:
pass
f.close()
pw = pw.rstrip("\n")
pass
except:
pass
pass
pf = None
if savepid:
pid = None
try:
pf = open(pidfile, "r")
try:
pid = int(pf.readline())
except ValueError:
print ("Warning, pidfile has invalid data,"
+ " ignoring")
pass
pf.close()
except IOError, err:
if err.errno != errno.ENOENT:
raise
pass
if pid is not None:
# Pulled the pid from the pidfile, make sure it is not
# already running.
try:
os.kill(pid, 0)
print ("Daemon is already running as pid %d"
% (pid))
sys.exit(2)
pass
except OSError, err:
if err.errno != errno.ESRCH:
raise
print "Warning, process appears to have died."
pass
pass
pf = open(pidfile, "w")
pass
sel_logger = None
if do_syslog:
import syslog
class logger:
def __init__(self):
self.logmap = { }
self.logmap[mvtrm.LOG_FATAL] = syslog.LOG_CRIT
self.logmap[mvtrm.LOG_SEVERE] = syslog.LOG_ERR
self.logmap[mvtrm.LOG_WARNING] = syslog.LOG_WARNING
self.logmap[mvtrm.LOG_INFO] = syslog.LOG_INFO
return
def log(self, level, err):
level = self.logmap[level]
syslog.syslog(level, str(err))
return
def selector_log(self, err):
syslog.syslog(syslog.LOG_CRIT, err)
return
pass
syslog.openlog("mvtrm_ipmi_resetter", 0, syslog.LOG_DAEMON)
log = logger()
sel_logger = log.selector_log
pass
# Here we have all the files that root would need, go ahead and
# set the user and group
orig_uid = None
if user:
orig_uid = os.getuid()
uid = idfromname("/etc/passwd", user)
if uid is None:
try:
uid = int(user)
except:
print "Invalid user specified: " + user
sys.exit(1)
pass
pass
os.setreuid(uid, orig_uid)
pass
orig_gid = None
if group:
orig_gid = os.getgid()
gid = idfromname("/etc/group", group)
if gid is None:
try:
gid = int(group)
except:
print "Invalid group specified: " + group
sys.exit(1)
pass
pass
os.setregid(gid, orig_gid)
pass
sel = selector.Selector(logger=sel_logger)
client = IPMIResetClient(host=host, port=port, log=log, adminpw=pw,
sel=sel)
client.ErrorHandler(mvtrm.LOG_INFO,
"Starting resource manager IPMI resetter")
# Don't daemonize until we get evertying started up.
if daemon:
# First stop the selector, multiple threads do not survive
# a fork.
sel.stop()
# double-fork magic
pid = os.fork()
if pid > 0:
# parent, exit
sys.exit(0)
pass
os.chdir('/')
# create a new SID
os.setsid()
# do second fork to not be session leader
pid = os.fork()
if pid > 0:
sys.exit(0)
pass
# redirect standard pipes
if hasattr(os,'devnull'):
redirect=os.devnull
else:
redirect='/dev/null'
pass
# first close underlining C streams also
os.close(0)
os.close(1)
os.close(2)
# open with the lowest descriptor, which is 0 (stdin),
# closed above
os.open(redirect, os.O_RDWR)
# now duplicate to stdout and stderr
os.dup2(0,1)
os.dup2(0,2)
sel.start() # Fork is done, restart the selector thread.
pass
if pf:
pf.write(str(os.getpid()))
pf.close()
pass
signal.signal(signal.SIGTERM, sighandler)
# Wait until time to stop.
try:
while not gotsig:
OpenIPMI.wait_io(1000)
pass
pass
except KeyboardInterrupt:
pass
except StandardError, err:
so = StringIO()
traceback.print_exc(None, so)
client.ErrorHandler(mvtrm.LOG_FATAL, so.getvalue())
except Exception:
# Let the exit go through
pass
if savepid:
# We may not be able to remove the pidfile as the original
# user. So set the user back.
if orig_uid is not None:
os.setuid(orig_uid)
pass
if orig_gid is not None:
os.setuid(orig_gid)
pass
try:
os.remove(pidfile)
except:
pass
pass
client.ErrorHandler(mvtrm.LOG_INFO,
"Quitting resource manager IPMI resetter")
return
if __name__ == "__main__":
startup(sys.argv)
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Openipmi-developer mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openipmi-developer