Add logging for RIS and RIBCL modules

This commit adds logging statement for some
common functions in RIBCL and RIS module.

Co-Authored-By: Debayan Ray <debayan.ray@gmail.com>
Implements: blueprint enable-logging
Change-Id: I9e4b18d1c5bea643e405b5d742c66426f54c2610
This commit is contained in:
Ramakrishnan G 2015-09-02 03:45:12 -07:00
parent afbe98dd09
commit 7a803799cb
6 changed files with 137 additions and 13 deletions

View File

@ -59,9 +59,10 @@ class IloClient(operations.IloOperations):
bios_password=bios_password,
cacert=cacert)
self.info = {'address': host, 'username': login, 'password': password}
self.host = host
self.model = self.ribcl.get_product_name()
LOG.debug("IloClient object created for host {} [model: {}]".format(
host, self.model))
LOG.debug(self._("IloClient object created. "
"Model: %(model)s"), {'model': self.model})
def _call_method(self, method_name, *args, **kwargs):
"""Call the corresponding method using either RIBCL or RIS."""
@ -70,9 +71,9 @@ class IloClient(operations.IloOperations):
the_operation_object = self.ris
method = getattr(the_operation_object, method_name)
LOG.debug("Calling {} method of {} for host {}".format(
method_name, type(the_operation_object).__name__,
the_operation_object.host))
LOG.debug(self._("Using %(class)s for method %(method)s."),
{'class': type(the_operation_object).__name__,
'method': method_name})
return method(*args, **kwargs)

View File

@ -25,6 +25,13 @@ class IloOperations(object):
python as described in HP iLO 4 Scripting and Command Line Guide.
"""
def _(self, msg):
"""Prepends host information if available to msg and returns it."""
try:
return "[iLO %s] %s" % (self.host, msg)
except AttributeError:
return "[iLO <unknown>] %s" % msg
def get_all_licenses(self):
"""Retrieve license type, key, installation date, etc."""
raise exception.IloCommandNotSupportedError(ERRMSG)

View File

@ -17,6 +17,7 @@
over RIBCL scripting language
"""
import copy
import re
import xml.etree.ElementTree as etree
@ -47,6 +48,22 @@ BOOT_MODE_CMDS = [
LOG = log.get_logger(__name__)
class MaskedRequestData(object):
def __init__(self, request_data):
self.request_data = request_data
def __str__(self):
request_data_copy = copy.deepcopy(self.request_data)
xml_data = request_data_copy.get('data')
if xml_data:
xml_data = re.sub(r'USER_LOGIN="(.*?)"', r'USER_LOGIN="*****"',
xml_data)
xml_data = re.sub(r'PASSWORD="(.*?)"', r'PASSWORD="*****"',
xml_data)
request_data_copy['data'] = xml_data
return str(request_data_copy)
class RIBCLOperations(operations.IloOperations):
"""iLO class for RIBCL interface for iLO.
@ -69,9 +86,6 @@ class RIBCLOperations(operations.IloOperations):
if self.cacert is None:
urllib3.disable_warnings(urllib3_exceptions.InsecureRequestWarning)
LOG.debug("RIBCLOperations object created for host {}".format(
self.host))
def _request_ilo(self, root):
"""Send RIBCL XML data to iLO.
@ -93,9 +107,15 @@ class RIBCLOperations(operations.IloOperations):
kwargs['verify'] = False
try:
LOG.debug(self._("POST %(url)s with request data: "
"%(request_data)s"),
{'url': urlstr,
'request_data': MaskedRequestData(kwargs)})
response = requests.post(urlstr, **kwargs)
response.raise_for_status()
except Exception as e:
LOG.exception(self._("An error occurred while "
"contacting iLO. Error: %s"), e)
raise exception.IloConnectionError(e)
return response.text
@ -253,13 +273,26 @@ class RIBCLOperations(operations.IloOperations):
platform = self.get_product_name()
msg = ("%(cmd)s is not supported on %(platform)s" %
{'cmd': cmd, 'platform': platform})
LOG.error(self._("Got invalid response with "
"message: '%(message)s'"),
{'message': msg})
raise (exception.IloCommandNotSupportedError
(msg, status))
else:
LOG.error(self._("Got invalid response with "
"message: '%(message)s'"),
{'message': msg})
raise exception.IloClientInternalError(msg, status)
if (status in exception.IloLoginFailError.statuses or
msg in exception.IloLoginFailError.messages):
LOG.error(self._("Got invalid response with "
"message: '%(message)s'"),
{'message': msg})
raise exception.IloLoginFailError(msg, status)
LOG.error(self._("Got invalid response with "
"message: '%(message)s'"),
{'message': msg})
raise exception.IloError(msg, status)
def _execute_command(self, create_command, tag_info, mode, dic={}):
@ -272,6 +305,7 @@ class RIBCLOperations(operations.IloOperations):
create_command, tag_info, mode, dic)
d = self._request_ilo(xml)
data = self._parse_output(d)
LOG.debug(self._("Received response data: %s"), data)
return data
def get_all_licenses(self):

View File

@ -64,9 +64,6 @@ class RISOperations(operations.IloOperations):
if self.cacert is None:
urllib3.disable_warnings(urllib3_exceptions.InsecureRequestWarning)
LOG.debug("RISOperations object created for host {}".format(
self.host))
def _rest_op(self, operation, suburi, request_headers, request_body):
"""Generic REST Operation handler."""
@ -74,6 +71,12 @@ class RISOperations(operations.IloOperations):
# Used for logging on redirection error.
start_url = url.geturl()
LOG.debug(self._("%(operation)s %(url)s "
"with headers '%(header)s' and body '%(body)s'"),
{'operation': operation, 'url': start_url,
'header': request_headers,
'body': request_body})
if request_headers is None:
request_headers = {}
@ -98,6 +101,8 @@ class RISOperations(operations.IloOperations):
try:
response = request_method(url.geturl(), **kwargs)
except Exception as e:
LOG.exception(self._("An error occurred while "
"contacting iLO. Error: %s"), e)
raise exception.IloConnectionError(e)
# NOTE:Do not assume every HTTP operation will return a JSON body.
@ -112,12 +117,15 @@ class RISOperations(operations.IloOperations):
if response.status_code == 301 and 'location' in response.headers:
url = urlparse.urlparse(response.headers['location'])
redir_count -= 1
LOG.debug(self._("Request redirected to %s."), url.geturl())
else:
break
else:
# Redirected for 5th time. Throw error
msg = ("URL Redirected 5 times continuously. "
"URL incorrect: %s" % start_url)
msg = (self._("URL Redirected 5 times continuously. "
"URL incorrect: %(start_url)s") %
{'start_url': start_url})
LOG.error(msg)
raise exception.IloConnectionError(msg)
response_body = {}
@ -134,11 +142,20 @@ class RISOperations(operations.IloOperations):
try:
gzipper = gzip.GzipFile(
fileobj=six.BytesIO(response.text))
LOG.debug(self._("Received compressed response "
"for url %(url)s."),
{'url': url.geturl()})
uncompressed_string = gzipper.read().decode('UTF-8')
response_body = json.loads(uncompressed_string)
except Exception as e:
LOG.error(self._("Got invalid response "
"'%(response)s' for url %(url)s."),
{'url': url.geturl(),
'response': response.text})
raise exception.IloError(e)
LOG.debug(self._("Received response %(response)s for url %(url)s."),
{'url': url.geturl(), 'response': response_body})
return response.status_code, response.headers, response_body
def _rest_get(self, suburi, request_headers=None):

View File

@ -0,0 +1,35 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# 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.
"""Test Class for Common Operations."""
import unittest
from proliantutils.ilo import operations
class IloOperationsTestCase(unittest.TestCase):
def setUp(self):
super(IloOperationsTestCase, self).setUp()
self.operations_object = operations.IloOperations()
def test__okay(self):
self.operations_object.host = '1.2.3.4'
self.assertEqual('[iLO 1.2.3.4] foo',
self.operations_object._('foo'))
def test__no_host(self):
self.assertEqual('[iLO <unknown>] foo',
self.operations_object._('foo'))

View File

@ -29,6 +29,36 @@ from proliantutils.ilo import ribcl
from proliantutils.tests.ilo import ribcl_sample_outputs as constants
class MaskedRequestDataTestCase(unittest.TestCase):
def setUp(self):
super(MaskedRequestDataTestCase, self).setUp()
self.maskedRequestData = ribcl.MaskedRequestData({})
def test___str__with_user_credential_present(self):
xml_data = (
'<RIBCL VERSION="2.0">'
'<LOGIN PASSWORD="password" USER_LOGIN="admin">'
'<RIB_INFO MODE="read">')
masked_xml_data = (
'\'<RIBCL VERSION="2.0">'
'<LOGIN PASSWORD="*****" USER_LOGIN="*****">'
'<RIB_INFO MODE="read">\'')
self.maskedRequestData.request_data = {'headers': 'some-headers',
'data': xml_data,
'verify': False}
self.assertIn(masked_xml_data, str(self.maskedRequestData))
def test___str__with_user_credential_not_present(self):
xml_data = (
'<RIBCL VERSION="2.0">'
'<RIB_INFO MODE="read">')
self.maskedRequestData.request_data = {'headers': 'some-headers',
'data': xml_data,
'verify': True}
self.assertIn(xml_data, str(self.maskedRequestData))
class IloRibclTestCaseInitTestCase(unittest.TestCase):
@mock.patch.object(urllib3, 'disable_warnings')