[Python-modules-commits] [python-hpilo] 01/05: Import python-hpilo_3.8.orig.tar.gz

Sandro Tosi morph at moszumanska.debian.org
Sat Jun 18 11:26:45 UTC 2016


This is an automated email from the git hooks/post-receive script.

morph pushed a commit to branch master
in repository python-hpilo.

commit eb2df79d9da6cb5a4039bd6e16c0bb71e185b4ad
Author: Sandro Tosi <morph at debian.org>
Date:   Fri Jun 17 22:48:59 2016 +0100

    Import python-hpilo_3.8.orig.tar.gz
---
 CHANGES                  |  10 +++++
 PKG-INFO                 |   2 +-
 docs/conf.py             |   4 +-
 docs/info.rst            |   1 +
 docs/python.rst          |  14 ++++++-
 docs/shell.rst           |   3 +-
 docs/troubleshooting.rst |  11 ++++++
 hpilo.py                 | 100 ++++++++++++++++++++++++++++++++++++-----------
 hpilo_cli                |  16 ++++++--
 setup.py                 |   2 +-
 10 files changed, 131 insertions(+), 32 deletions(-)

diff --git a/CHANGES b/CHANGES
index a1b398a..69b8a8e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,13 @@
+Version 3.8, 2016-04-26
+* Improved python 3 compatibility
+* More compact XML in delayed mode to make resets and changes more cooperative
+* More workarounds for iLO firmware bugs, this time around badly encoded data
+* Add the force_format command to help recover really broken iLOs
+
+Version 3.7, 2016-01-30
+* Support for TLSv1.1 and TLSv1.2
+* mod_dir_settings and set_host_power_saver now also accept non-numeric values
+
 Version 3.6, 2016-01-29
 * Actually fix mod_snmp_im_settings' cpability of setting ro/trap communities
 
diff --git a/PKG-INFO b/PKG-INFO
index e5ca713..0901091 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: python-hpilo
-Version: 3.6
+Version: 3.8
 Summary: iLO automation from python or shell
 Home-page: http://github.com/seveas/python-hpilo
 Author: Dennis Kaarsemaker
diff --git a/docs/conf.py b/docs/conf.py
index 58b1241..38e4887 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -50,9 +50,9 @@ copyright = u'2011-2016, Dennis Kaarsemaker'
 # built documents.
 #
 # The short X.Y version.
-version = '3.6'
+version = '3.8'
 # The full version, including alpha/beta/rc tags.
-release = '3.6'
+release = '3.8'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/docs/info.rst b/docs/info.rst
index fb4d99f..26bb860 100644
--- a/docs/info.rst
+++ b/docs/info.rst
@@ -12,6 +12,7 @@ authentication or power.
    :noindex:
 
    .. automethod:: factory_defaults
+   .. automethod:: force_format
    .. automethod:: get_product_name
    .. ilo_output:: get_product_name
    .. automethod:: get_fw_version
diff --git a/docs/python.rst b/docs/python.rst
index 48d0107..928838e 100644
--- a/docs/python.rst
+++ b/docs/python.rst
@@ -7,7 +7,7 @@ The :py:mod:`hpilo` module contains all you need to communicate with iLO
 devices, encapsulated in the :class:`Ilo` class and its methods. There are a
 few auxiliarry items in this module too.
 
-.. py:class:: Ilo(hostname, login=None, password=None, timeout=60, port=443, protocol=None, delayed=False)
+.. py:class:: Ilo(hostname, login=None, password=None, timeout=60, port=443, protocol=None, delayed=False, ssl_version=None)
 
    Represents an iLO management interface on a specific host.
 
@@ -25,6 +25,10 @@ few auxiliarry items in this module too.
                    for any method call you make and return a result. To save
                    roundtrip time costs, set this to :py:data:`False` and call
                    the :py:meth:`call_delayed` method manually.
+   :param ssl_version: By default, this library will use the TLSv1 protocol as
+                   security layer, falling back to SSLv3 if necessary. You can
+                   specify a different TLS version (use the constants from the
+                   ssl module) to use if necessary.
 
    .. py:method:: call_delayed
 
@@ -39,6 +43,11 @@ few auxiliarry items in this module too.
            'management_processor': 'iLO3'}
           >>> pprint(ilo.get_uid_status())
           'OFF'
+          >>> ilo = hpilo.Ilo('example-server.int.kaarsemaker.net', 'Administrator', 'PassW0rd', ssl_version=ssl.PROTOCOL_TLSv1_2)
+          {'firmware_date': 'Dec 02 2015',
+           'firmware_version': '2.40',
+           'license_type': 'iLO Standard',
+           'management_processor': 'iLO4'}
 
       and
 
@@ -59,6 +68,9 @@ few auxiliarry items in this module too.
       one HTTP connection. As this overhead is quite significant, it makes
       sense to do this when you need to make more than one API call.
 
+      When using the delayed mode, please be aware that methods that trigger a
+      reset may cause subsequent methods to not be called or cause errors to be
+      returned for these methods.
 
    All other methods of this class are API calls that mimic the methods
    available via XML. These are documented separately in further pages here and
diff --git a/docs/shell.rst b/docs/shell.rst
index cef7685..a755795 100644
--- a/docs/shell.rst
+++ b/docs/shell.rst
@@ -35,7 +35,8 @@ Options:
                           Use the specified protocol instead of autodetecting
     -d, --debug           Output debug information, repeat to see all XML data
     -o PORT, --port=PORT  SSL port to connect to
-    --untested            Allow untested methods
+    -s SSL_VERSION, --ssl=SSL_VERSION
+                          The SSL/TLS version to use for connecting to the iLO
     -h, --help            show this help message or help for a method
     -H, --help-methods    show all supported methods
 
diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst
index 1444cb9..38023ca 100644
--- a/docs/troubleshooting.rst
+++ b/docs/troubleshooting.rst
@@ -81,3 +81,14 @@ first update to 1.28 and then update to a later version::
 
   hpilo_cli example-server.int.kaarsemaker.net update_rib_firmware version=1.28
   hpilo_cli example-server.int.kaarsemaker.net update_rib_firmware version=latest
+
+`hpilo.IloError: Error reading configuration`
+---------------------------------------------
+This error might occur in delayed mode when one of the calls causes a reset of
+the iLO, such as changing network settings or reseting to factory defaults. All
+delayed calls called by the same `call_delayed` after this reset may then cause
+this error as the iLO is reseting. For example, when calling `hpilo_cli
+localhost factory_defaults + activate_license key=12345`, the
+`activate_license` call may fail with this error. If you hit this issue and you
+use calls that can cause a reset, make sure you either use them outside a
+delayed call or at the end of the delayed call.
diff --git a/hpilo.py b/hpilo.py
index 2292f7d..bb38343 100644
--- a/hpilo.py
+++ b/hpilo.py
@@ -1,8 +1,9 @@
 # (c) 2011-2016 Dennis Kaarsemaker <dennis at kaarsemaker.net>
 # see COPYING for license details
 
-__version__ = "3.6"
+__version__ = "3.8"
 
+import codecs
 import os
 import errno
 import platform
@@ -18,14 +19,16 @@ import hpilo_fw
 PY3 = sys.version_info[0] >= 3
 if PY3:
     import urllib.request as urllib2
-    import io as StringIO
+    import io
     b = lambda x: bytes(x, 'ascii')
     class Bogus(Exception): pass
     socket.sslerror = Bogus
     basestring = str
 else:
     import urllib2
-    import cStringIO as StringIO
+    import cStringIO as io
+    if not hasattr(io, 'BytesIO'):
+        io.BytesIO = io.StringIO
     b = lambda x: x
 
 try:
@@ -33,9 +36,11 @@ try:
 except ImportError:
     # Fallback for older python versions
     class ssl:
-        PROTOCOL_SSLv3 = 1
-        PROTOCOL_TLSv23 = 2
-        PROTOCOL_TLSv1 = 3
+        PROTOCOL_SSLv3   = 1
+        PROTOCOL_SSLv23  = 2
+        PROTOCOL_TLSv1   = 3
+        PROTOCOL_TLSv1_1 = 4
+        PROTOCOL_TLSv1_2 = 5
         @staticmethod
         def wrap_socket(sock, *args, **kwargs):
             return ssl(sock)
@@ -107,6 +112,22 @@ elif hasattr(etree.ElementTree, '_write'):
 else:
     raise RuntimeError("Don't know how to monkeypatch XML serializer workarounds. Please report a bug at https://github.com/seveas/python-hpilo")
 
+# We handle non-ascii characters in the returned XML by replacing them with XML
+# character references. This likely results in bogus data, but avoids crashes.
+# The iLO should never do this, but firmware bugs may cause it to do so.
+def iloxml_replace(error):
+    ret = ""
+    for pos in range(error.start, len(error.object)):
+        b = error.object[pos]
+        if not isinstance(b, int):
+            b = ord(b)
+        if b < 128:
+            break
+        ret += u'?'
+    warnings.warn("Invalid ascii data found: %s, replaced with %s" % (repr(error.object[error.start:pos]), ret), IloWarning)
+    return (ret, pos)
+codecs.register_error('iloxml_replace', iloxml_replace)
+
 # Which protocol to use
 ILO_RAW  = 1
 ILO_HTTP = 2
@@ -183,19 +204,20 @@ class Ilo(object):
     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 = 64 * 1024
 
-    def __init__(self, hostname, login=None, password=None, timeout=60, port=443, protocol=None, delayed=False):
+    def __init__(self, hostname, login=None, password=None, timeout=60, port=443, protocol=None, delayed=False, ssl_version=None):
         self.hostname = hostname
         self.login    = login or 'Administrator'
         self.password = password or 'Password'
         self.timeout  = timeout
         self.debug    = 0
         self.port     = port
+        self.ssl_version = ssl_version or ssl.PROTOCOL_TLSv1
+        self.ssl_fallback = ssl_version is None # Only fall back to SSLv3 if no protocol was specified
         self.protocol = protocol
         self.cookie   = None
         self.delayed  = delayed
         self._elements = None
         self._processors = []
-        self.ssl_version = ssl.PROTOCOL_TLSv1
         self.save_response = None
         self.read_response = None
         self.save_request = None
@@ -217,7 +239,7 @@ class Ilo(object):
 
     def _debug(self, level, message):
         if message.__class__.__name__ == 'bytes':
-            message = message.decode('latin-1')
+            message = message.decode('ascii')
         if self.debug >= level:
             if self._protect_passwords:
                 message = re.sub(r'PASSWORD=".*?"', 'PASSWORD="********"', message)
@@ -314,7 +336,7 @@ class Ilo(object):
         try:
             while True:
                 d = sock.read()
-                data += d.decode('latin-1')
+                data += d.decode('ascii')
                 if not d:
                     break
         except socket.sslerror: # Connection closed
@@ -339,13 +361,13 @@ class Ilo(object):
         if self.read_response or self.save_request:
             class FakeSocket(object):
                 def __init__(self, rfile=None, wfile=None):
-                    self.input = rfile and open(rfile) or StringIO.StringIO()
-                    self.output = wfile and open(wfile, 'a') or StringIO.StringIO()
+                    self.input = rfile and open(rfile, 'rb') or io.BytesIO()
+                    self.output = wfile and open(wfile, 'ab') or io.BytesIO()
                     self.read = self.input.read
                     self.write = self.output.write
                     data = self.input.read(4)
                     self.input.seek(0)
-                    self.protocol = data == 'HTTP' and ILO_HTTP or ILO_RAW
+                    self.protocol = data == b('HTTP') and ILO_HTTP or ILO_RAW
                 def close(self):
                     self.input.close()
                     self.output.close()
@@ -397,7 +419,7 @@ class Ilo(object):
             e = sys.exc_info()[1]
             msg = getattr(e, 'reason', None) or getattr(e, 'message', None) or str(e)
             # Some ancient iLO's don't support TLSv1, retry with SSLv3
-            if 'wrong version number' in msg and self.sslversion == ssl.PROTOCOL_TLSv1:
+            if 'wrong version number' in msg and self.ssl_version >= ssl.PROTOCOL_TLSv1 and self.ssl_fallback:
                 self.ssl_version = ssl.PROTOCOL_SSLv3
                 return self._get_socket()
             raise IloCommunicationError("Cannot establish ssl session with %s:%d: %s" % (self.hostname, self.port, msg))
@@ -449,7 +471,7 @@ class Ilo(object):
         data = ''
         try:
             while True:
-                d = sock.read().decode('latin-1')
+                d = sock.read().decode('ascii', 'iloxml_replace')
                 data += d
                 if not d:
                     break
@@ -541,7 +563,10 @@ class Ilo(object):
                 root, login = self._elements
             else:
                 self._elements = (root, login)
-        element = etree.SubElement(login, element, **attrs)
+        if self.delayed and len(login) and login[-1].tag == element and login[-1].attrib == attrs:
+            element = login[-1]
+        else:
+            element = etree.SubElement(login, element, **attrs)
         return root, element
 
     def _parse_message(self, data, include_inform=False):
@@ -685,7 +710,7 @@ class Ilo(object):
         for t in tags[1:]:
             inner = etree.SubElement(inner, t[0], **t[1])
         header, message = self._request(root)
-        fd = StringIO.StringIO()
+        fd = io.BytesIO()
         etree.ElementTree(message).write(fd)
         ret = fd.getvalue()
         fd.close()
@@ -891,6 +916,11 @@ class Ilo(object):
         """Reset the iLO to factory default settings"""
         return self._control_tag('RIB_INFO', 'FACTORY_DEFAULTS')
 
+    def force_format(self):
+        """Forcefully format the iLO's internal NAND flash. Only use this when
+           the iLO is having severe problems and its self-test fails"""
+        return self._control_tag('RIB_INFO', 'FORCE_FORMAT', attrib={'VALUE': 'all'})
+
     def get_ahs_status(self):
         """Get active health system logging status"""
         return self._info_tag('RIB_INFO', 'GET_AHS_STATUS')
@@ -1439,15 +1469,39 @@ class Ilo(object):
         vars = dict(locals())
         del vars['self']
 
+        # The _priv thing is a comma-separated list of numbers, but other
+        # functions use names, and the iLO ssh interface shows different names.
+        # Support them all.
+        privmap = {
+            'login':         1,
+            'rc':            2,
+            'remote_cons':   2,
+            'vm':            3,
+            'virtual_media': 3,
+            'power':         4,
+            'reset_server':  4,
+            'config':        5,
+            'config_ilo':    5,
+            'admin':         6,
+        }
+
         # create special case for element with text inside
         if dir_kerberos_keytab:
             keytab_el = etree.Element('DIR_KERBEROS_KEYTAB')
             keytab_el.text = dir_kerberos_keytab
             del vars['dir_kerberos_keytab']
 
-        elements = [etree.Element(x.upper(), VALUE=str({True: 'Yes', \
-                False: 'No'}.get(vars[x], vars[x])))
-                    for x in vars if vars[x] is not None]
+        elements = []
+        for key, val in vars.iteritems():
+            if not val:
+                continue
+            if key.endswith('_priv'):
+                if isinstance(val, basestring):
+                    val = val.replace('oemhp_', '').replace('_priv', '').split(',')
+                val = ','.join([str(privmap.get(x,x)) for x in val])
+            else:
+                val = str({True: 'Yes', False: 'No'}.get(val, val))
+            elements.append(etree.Element(key.upper(), VALUE=val))
 
         if dir_kerberos_keytab:
             elements.append(keytab_el)
@@ -1652,7 +1706,9 @@ class Ilo(object):
 
     def set_host_power_saver(self, host_power_saver):
         """Set the configuration of the ProLiant power regulator"""
-        return self._control_tag('SERVER_INFO', 'SET_HOST_POWER_SAVER', attrib={'HOST_POWER_SAVER': str(host_power_saver)})
+        mapping = {'off': 1, 'min': 2, 'auto': 3, 'max': 4}
+        host_power_saver = str(mapping.get(str(host_power_saver).lower(), host_power_saver))
+        return self._control_tag('SERVER_INFO', 'SET_HOST_POWER_SAVER', attrib={'HOST_POWER_SAVER': host_power_saver})
 
     def set_one_time_boot(self, device):
         """Set one time boot device, device should be one of normal, floppy,
@@ -1855,7 +1911,7 @@ class Ilo(object):
                 opener = urllib2.build_opener(urllib2.ProxyHandler({}))
             req = opener.open(url, None, self.timeout)
             data = req.read()
-            self._debug(1, str(req.headers).rstrip() + "\n\n" + data.decode('utf-8', 'replace'))
+            self._debug(1, str(req.headers).rstrip() + "\n\n" + data.decode('ascii', 'iloxml_replace'))
         if self.save_response:
             fd = open(self.save_response, 'a')
             fd.write(data)
diff --git a/hpilo_cli b/hpilo_cli
index 8e30e28..cc8873d 100755
--- a/hpilo_cli
+++ b/hpilo_cli
@@ -22,7 +22,10 @@ import optparse
 import os
 from pprint import pprint
 import sys
-import urllib2
+try:
+    from urllib.error import HTTPError
+except ImportError:
+    from urllib2 import HTTPError
 
 ilo_methods = sorted([x for x in dir(hpilo.Ilo) if not x.startswith('_') and x.islower()])
 
@@ -52,6 +55,9 @@ def main():
                  help="Output debug information, repeat to see all XML data")
     p.add_option("-o", "--port", dest="port", type="int", default=443,
                  help="SSL port to connect to")
+    p.add_option('-s', '--ssl', dest="ssl_version", default="tlsv1",
+                 choices=('sslv3', 'sslv23', 'tlsv1', 'tlsv1_1', 'tlsv1_2'),
+                 help="The SSL/TLS version to use for connecting to the iLO")
     p.add_option("-h", "--help", action="callback", callback=hpilo_help,
                  help="show this help message or help for a method")
     p.add_option("-H", "--help-methods", action="callback", callback=hpilo_help_methods,
@@ -179,7 +185,9 @@ def main():
         'raw':   hpilo.ILO_RAW,
         'local': hpilo.ILO_LOCAL,
     }.get(opts.protocol, None)
-    ilo = hpilo.Ilo(hostname, login, password, opts.timeout, opts.port, opts.protocol, len(calls) > 1)
+    opts.ssl_version = getattr(hpilo.ssl, 'PROTOCOL_' + opts.ssl_version.upper().replace('V','v'))
+
+    ilo = hpilo.Ilo(hostname, login, password, opts.timeout, opts.port, opts.protocol, len(calls) > 1, opts.ssl_version)
     ilo.debug = opts.debug
     ilo.save_response = opts.save_response
     ilo.read_response = opts.read_response
@@ -306,14 +314,14 @@ def download(ilotype, versions):
 
 def _download(config, key):
     if key not in config:
-        sys.stderr.write("Unkown ilo/firmware version: %s\n" % key)
+        sys.stderr.write("Unknown ilo/firmware version: %s\n" % key)
         sys.exit(1)
     try:
         if hpilo_fw.download(key, progress=print_progress):
             print("")
         else:
             print("%s firmware version %s was already downloaded" % (key.split()[0], config[key]['version']))
-    except urllib2.HTTPError:
+    except HTTPError:
         e = sys.exc_info()[1]
         print("\n%s" % str(e))
 
diff --git a/setup.py b/setup.py
index d41c8b9..ff514ac 100755
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
 from distutils.core import setup
 
 setup(name = "python-hpilo",
-      version = "3.6",
+      version = "3.8",
       author = "Dennis Kaarsemaker",
       author_email = "dennis at kaarsemaker.net",
       url = "http://github.com/seveas/python-hpilo",

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-hpilo.git



More information about the Python-modules-commits mailing list