Redfish: Adds HPEConnector to proliantutils

Implements HPEConnector class that overrides the '_op' instance method
from sushy's Connector class to include retrying logic. The retrying
logic tries for MAX_RETRY_ATTEMPTS attempts waiting for MAX_TIME_BEFORE_RETRY
time after each retry. Also adds constructor to HPESushy class that bypasses
the initialization of the Sushy class and initialize the ResourceBase class
with customized HPE specific connector subtype.

Change-Id: Ic11552ed12195206717e9fcfaffa4c6d20bc6543
Closes-Bug: #1710071
This commit is contained in:
vmud213 2017-08-11 12:26:48 +05:30
parent 4d58e21184
commit 26241533dc
4 changed files with 149 additions and 3 deletions

View File

@ -0,0 +1,47 @@
# Copyright 2017 Hewlett Packard Enterprise Development LP
#
# 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.
__author__ = 'HPE'
import retrying
from sushy import connector
from sushy import exceptions
class HPEConnector(connector.Connector):
"""Class that extends base Sushy Connector class
This class extends the Sushy's Connector class to override certain methods
required to customize the functionality of the http operations.
"""
MAX_RETRY_ATTEMPTS = 3 # Maximum number of attempts to be retried
MAX_TIME_BEFORE_RETRY = 2 * 1000 # wait time in milliseconds before retry
@retrying.retry(
retry_on_exception=(
lambda e: isinstance(e, exceptions.ConnectionError)),
stop_max_attempt_number=MAX_RETRY_ATTEMPTS,
wait_fixed=MAX_TIME_BEFORE_RETRY)
def _op(self, method, path='', data=None, headers=None):
"""Overrides the base method to support retrying the operation.
:param method: The HTTP method to be used, e.g: GET, POST,
PUT, PATCH, etc...
:param path: The sub-URI path to the resource.
:param data: Optional JSON data.
:param headers: Optional dictionary of headers.
:returns: The response from the connector.Connector's _op method.
"""
return super(HPEConnector, self)._op(method, path, data, headers)

View File

@ -16,6 +16,7 @@ __author__ = 'HPE'
import sushy
from proliantutils.redfish import connector
from proliantutils.redfish.resources.account_service import account_service
from proliantutils.redfish.resources.manager import manager
from proliantutils.redfish.resources.system import system
@ -27,9 +28,35 @@ class HPESushy(sushy.Sushy):
"""Class that extends base Sushy class
This class extends the Sushy class to override certain methods
required to customize the functionality of different resources
required to customize the functionality of different resources.
It bypasses the initialization of the Sushy class and initializes
the ResourceBase class with customized HPE specific connector subtype.
"""
def __init__(self, base_url, username=None, password=None,
root_prefix='/redfish/v1/', verify=True):
"""Initializes HPE specific sushy object.
:param base_url: The base URL to the Redfish controller. It
should include scheme and authority portion of the URL. For
example: https://mgmt.vendor.com
:param username: User account with admin/server-profile access
privilege
:param password: User account password
:param root_prefix: The default URL prefix. This part includes
the root service and version. Defaults to /redfish/v1
:param verify: Either a boolean value, a path to a CA_BUNDLE
file or directory with certificates of trusted CAs. If set to
True the driver will verify the host certificates; if False
the driver will ignore verifying the SSL certificate; if it's
a path the driver will use the specified certificate or one of
the certificates in the directory. Defaults to True.
"""
self._root_prefix = root_prefix
super(sushy.Sushy, self).__init__(
connector.HPEConnector(base_url, username, password, verify),
path=self._root_prefix)
def get_system_collection_path(self):
return utils.get_subresource_path_by(self, 'Systems')

View File

@ -0,0 +1,72 @@
# Copyright 2017 Hewlett Packard Enterprise Development LP
# 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.
import mock
from sushy import connector
from sushy import exceptions
import testtools
from proliantutils.redfish import connector as hpe_connector
class HPEConnectorTestCase(testtools.TestCase):
def setUp(self):
super(HPEConnectorTestCase, self).setUp()
@mock.patch.object(connector.Connector, '_op', autospec=True)
def test__op_no_exception(self, conn_mock):
conn_mock.side_effect = ["Hello", exceptions.ConnectionError,
"Hello", "World"]
hpe_conn = hpe_connector.HPEConnector(
'http://foo.bar:1234', username='user',
password='pass', verify=True)
headers = {'X-Fake': 'header'}
hpe_conn._op('GET', path='fake/path', data=None, headers=headers)
conn_mock.assert_called_once_with(hpe_conn, 'GET', path='fake/path',
data=None, headers=headers)
self.assertEqual(1, conn_mock.call_count)
@mock.patch.object(connector.Connector, '_op', autospec=True)
def test__op_with_exception(self, conn_mock):
conn_mock.side_effect = [exceptions.ConnectionError,
exceptions.ConnectionError, "Hello", "World"]
hpe_conn = hpe_connector.HPEConnector(
'http://foo.bar:1234', username='user',
password='pass', verify=True)
headers = {'X-Fake': 'header'}
lval = hpe_conn._op('GET', path='fake/path', data=None,
headers=headers)
self.assertEqual(3, conn_mock.call_count)
self.assertEqual(lval, "Hello")
@mock.patch.object(connector.Connector, '_op', autospec=True)
def test__op_all_exception(self, conn_mock):
conn_mock.side_effect = [
exceptions.ConnectionError] * (
hpe_connector.HPEConnector.MAX_RETRY_ATTEMPTS) + (
["Hello", "World"])
hpe_conn = hpe_connector.HPEConnector(
'http://foo.bar:1234', username='user',
password='pass', verify=True)
headers = {'X-Fake': 'header'}
self.assertRaises(
exceptions.ConnectionError, hpe_conn._op,
'GET', path='fake/path', data=None, headers=headers)
self.assertEqual(hpe_connector.HPEConnector.MAX_RETRY_ATTEMPTS,
conn_mock.call_count)

View File

@ -16,10 +16,10 @@
import json
import mock
from sushy import connector
import testtools
from proliantutils import exception
from proliantutils.redfish import connector
from proliantutils.redfish import main
from proliantutils.redfish.resources.account_service import account_service
from proliantutils.redfish.resources.manager import manager
@ -29,7 +29,7 @@ from proliantutils.redfish.resources import update_service
class HPESushyTestCase(testtools.TestCase):
@mock.patch.object(connector, 'Connector', autospec=True)
@mock.patch.object(connector, 'HPEConnector', autospec=True)
def setUp(self, connector_mock):
super(HPESushyTestCase, self).setUp()
with open('proliantutils/tests/redfish/'