Skip to content
Browse files

hponcfg support

By specifying protocol=ILO_LOCAL (api) or -P local (cli) or using
hostname localhost, hpilo_cli will now use hponcfg as a backend. Useful
if you can't use the network or don't want to do so. It also helps when
resetting passwords.
  • Loading branch information...
1 parent 84ec60c commit 36e36a8872331aa729a605b8677f6fe9be785ec4 @seveas committed Aug 26, 2012
Showing with 67 additions and 25 deletions.
  1. +8 −0 docs/cli.rst
  2. +37 −8 hpilo.py
  3. +21 −17 hpilo_cli
  4. +1 −0 ilo.conf.example
View
8 docs/cli.rst
@@ -75,3 +75,11 @@ Setting a licence key defined in the config file::
ilo3_advanced = FAKEL-ICENS-EFORH-PILO3-XXXXX
$ hpilo_cli example-server.int.kaarsemaker.net activate_license key=$license.ilo3_advanced
+
+Using hponcfg to talk to the local iLO device to reset the password without knowing it::
+
+ $ hpilo_cli -P local localhost mod_user user_login=Administrator password=NewPassword
+
+-P local is optional when specifying localhost as hostname, so this works too::
+
+ $ hpilo_cli localhost mod_user user_login=Administrator password=NewPassword
View
45 hpilo.py
@@ -9,6 +9,7 @@
import cStringIO as StringIO
except ImportError:
import io as StringIO
+import subprocess
import sys
try:
import ssl
@@ -28,6 +29,7 @@ def wrap_socket(sock, *args, **kwargs):
# Which protocol to use
ILO_RAW = 1
ILO_HTTP = 2
+ILO_LOCAL = 3
_untested = []
@@ -53,22 +55,27 @@ class IloWarning(Warning):
class Ilo(object):
"""Represents an iLO/iLO2/iLO3/RILOE II management interface on a
- specific host. A new connection using the specified login, password
- and timeout will be made for each API call."""
+ specific host. A new connection using the specified login, password and
+ timeout will be made for each API call. The library will detect which
+ protocol to use, but you can override this by setting protocol to
+ ILO_RAW or ILO_HTTP. Use ILO_LOCAL to avoid using a network connection
+ and use hponcfg instead. Username and password are ignored for ILO_LOCAL
+ connections."""
XML_HEADER = '<?xml version="1.0"?>\r\n'
HTTP_HEADER = "POST /ribcl HTTP/1.1\r\nHost: localhost\r\nContent-Length: %d\r\nConnection: Close%s\r\n\r\n"
HTTP_UPLOAD_HEADER = "POST /cgi-bin/uploadRibclFiles HTTP/1.1\r\nHost: localhost\r\nConnection: Close\r\nContent-Length: %d\r\nContent-Type: multipart/form-data; boundary=%s\r\n\r\n"
BLOCK_SIZE = 4096
+ hponcfg = "/sbin/hponcfg"
- def __init__(self, hostname, login, password, timeout=60, port=443):
+ def __init__(self, hostname, login=None, password=None, timeout=60, port=443, protocol=None):
self.hostname = hostname
- self.login = login
- self.password = password
+ self.login = login or 'Administrator'
+ self.password = password or 'Password'
self.timeout = timeout
self.debug = 0
- self.protocol = None
self.port = port
+ self.protocol = protocol
self.cookie = None
def __str__(self):
@@ -120,6 +127,10 @@ def _request(self, xml, progress=None):
return header, messages
def _detect_protocol(self):
+ # Use hponcfg when 'connecting' to localhost
+ if self.hostname == 'localhost':
+ self.protocol = ILO_LOCAL
+ return
# Do a bogus request, using the HTTP protocol. If there is no
# header (see special case in communicate(), we should be using the
# raw protocol
@@ -184,7 +195,18 @@ def _upload_file(self, filename, progress):
self._debug(2, "Cookie: %s" % self.cookie)
def _get_socket(self):
- """Set up an https connection and do an HTTP/raw socket request"""
+ """Set up a subprocess or an https connection and do an HTTP/raw socket request"""
+ if self.protocol == ILO_LOCAL:
+ self._debug(1, "Launching hponcfg")
+ try:
+ sp = subprocess.Popen([self.hponcfg, '--input', '--xmlverbose'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None)
+ except OSError:
+ e = sys.exc_info()[1]
+ raise IloError("Cannot run %s: %s" % (self.hponcfg, str(e)))
+ sp.write = sp.stdin.write
+ sp.read = sp.stdout.read
+ return sp
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(self.timeout)
self._debug(1, "Connecting to %s:%d" % (self.hostname, self.port))
@@ -219,7 +241,8 @@ def _communicate(self, xml, protocol, progress=None):
self._debug(2, self.XML_HEADER + xml)
# XML header and data need to arrive in 2 distinct packets
- sock.write(self.XML_HEADER)
+ if self.protocol != ILO_LOCAL:
+ sock.write(self.XML_HEADER)
if '$EMBED' in xml:
pre, name, post = re.compile(r'(.*)\$EMBED:(.*)\$(.*)', re.DOTALL).match(xml).groups()
sock.write(pre)
@@ -243,6 +266,9 @@ def _communicate(self, xml, protocol, progress=None):
sock.write(xml)
# And grab the data
+ if self.protocol == ILO_LOCAL:
+ # hponcfg doesn't return data until stdin is closed
+ sock.stdin.close()
data = ''
try:
while True:
@@ -267,6 +293,9 @@ def _communicate(self, xml, protocol, progress=None):
self._debug(1, "Received %d bytes" % len(data))
+ # Stript out garbage from hponcfg
+ if self.protocol == ILO_LOCAL:
+ data = data[data.find('<'):data.rfind('>')+1]
# Do we have HTTP?
header_ = ''
if protocol == ILO_HTTP and data.startswith('HTTP/1.1 200'):
View
38 hpilo_cli
@@ -33,7 +33,7 @@ def main():
help="Timeout for iLO connections")
p.add_option("-j", "--json", dest="json", action="store_true", default=False,
help="Output a json document instead of a python dict")
- p.add_option("-P", "--protocol", dest="protocol", choices=("http","raw"), default=None,
+ p.add_option("-P", "--protocol", dest="protocol", choices=("http","raw","local"), default=None,
help="Use the specified protocol instead of autodetecting")
p.add_option("-d", "--debug", dest="debug", action="count", default=0,
help="Output debug information, repeat to see all XML data")
@@ -109,23 +109,27 @@ def main():
# Do we have login information
login = None
password = None
- if config.has_option('ilo', 'login'):
- login = config.get('ilo', 'login')
- if config.has_option('ilo', 'password'):
- password = config.get('ilo', 'password')
- if opts.login:
- login = opts.login
- if opts.password:
- password = opts.password
- if not login or not password:
- p.error("No login details provided")
-
- ilo = hpilo.Ilo(hostname, login, password, opts.timeout, opts.port)
+ if opts.protocol != 'local':
+ if config.has_option('ilo', 'login'):
+ login = config.get('ilo', 'login')
+ if config.has_option('ilo', 'password'):
+ password = config.get('ilo', 'password')
+ if opts.login:
+ login = opts.login
+ if opts.password:
+ password = opts.password
+ if not login or not password:
+ p.error("No login details provided")
+
+ opts.protocol = {
+ 'http': hpilo.ILO_HTTP,
+ 'raw': hpilo.ILO_RAW,
+ 'local': hpilo.ILO_LOCAL,
+ }.get(opts.protocol, None)
+ ilo = hpilo.Ilo(hostname, login, password, opts.timeout, opts.port, opts.protocol)
ilo.debug = opts.debug
- if opts.protocol == 'http':
- ilo.protocol = hpilo.ILO_HTTP
- elif opts.protocol == 'raw':
- ilo.protocol = hpilo.ILO_RAW
+ if config.has_option('ilo', 'hponcfg'):
+ ilo.hponcfg = config.get('ilo', 'hponcfg')
def _q(val):
if isinstance(val, basestring):
View
1 ilo.conf.example
@@ -1,6 +1,7 @@
[ilo]
login = Administrator
password = AdminPassword
+hponcfg = /usr/local/bin/hponcfg
[license]
ilo2_advanced = FAKEILO2LICENSEXXXXXXXXXX

0 comments on commit 36e36a8

Please sign in to comment.
Something went wrong with that request. Please try again.