Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-sushy for openSUSE:Factory 
checked in at 2023-01-05 15:00:35
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-sushy (Old)
 and      /work/SRC/openSUSE:Factory/.python-sushy.new.1563 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-sushy"

Thu Jan  5 15:00:35 2023 rev:11 rq:1055985 version:4.4.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-sushy/python-sushy.changes        
2022-10-03 13:47:18.845686280 +0200
+++ /work/SRC/openSUSE:Factory/.python-sushy.new.1563/python-sushy.changes      
2023-01-05 15:00:54.669038709 +0100
@@ -1,0 +2,13 @@
+Mon Jan  2 09:11:53 UTC 2023 - cloud-de...@suse.de
+
+- update to version 4.4.0
+  - Fix misuse of assertTrue
+  - Update master for stable/zed
+  - Improve resiliency of eTag handling
+  - Increase server side retries
+  - Fix misuse of assertIsNone
+  - Update release versions for yoga and zed
+  - Add Python3 antelope unit tests
+  - Make server connection retries configurable
+
+-------------------------------------------------------------------

Old:
----
  sushy-4.3.0.tar.gz

New:
----
  sushy-4.4.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-sushy.spec ++++++
--- /var/tmp/diff_new_pack.Rthm5i/_old  2023-01-05 15:00:55.245041746 +0100
+++ /var/tmp/diff_new_pack.Rthm5i/_new  2023-01-05 15:00:55.253041788 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-sushy
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,13 +17,13 @@
 
 
 Name:           python-sushy
-Version:        4.3.0
+Version:        4.4.0
 Release:        0
 Summary:        Python library to communicate with Redfish based systems
 License:        Apache-2.0
 Group:          Development/Languages/Python
 URL:            https://docs.openstack.org/sushy
-Source0:        
https://files.pythonhosted.org/packages/source/s/sushy/sushy-4.3.0.tar.gz
+Source0:        
https://files.pythonhosted.org/packages/source/s/sushy/sushy-4.4.0.tar.gz
 BuildRequires:  openstack-macros
 BuildRequires:  python3-oslotest
 BuildRequires:  python3-pbr >= 2.0.0
@@ -62,7 +62,7 @@
 This package contains the documentation.
 
 %prep
-%autosetup -p1 -n sushy-4.3.0
+%autosetup -p1 -n sushy-4.4.0
 %py_req_cleanup
 
 %build

++++++ sushy-4.3.0.tar.gz -> sushy-4.4.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/AUTHORS new/sushy-4.4.0/AUTHORS
--- old/sushy-4.3.0/AUTHORS     2022-08-26 19:56:31.000000000 +0200
+++ new/sushy-4.4.0/AUTHORS     2022-11-22 16:26:19.000000000 +0100
@@ -45,6 +45,7 @@
 Sean McGinnis <sean.mcgin...@gmail.com>
 Shivanand Tendulker <stendul...@gmail.com>
 Steve Baker <sba...@redhat.com>
+Takashi Natsume <takanat...@gmail.com>
 Thomas Goirand <z...@debian.org>
 Varsha <varsha.verma.ee...@itbhu.ac.in>
 Vu Cong Tuan <tua...@vn.fujitsu.com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/ChangeLog new/sushy-4.4.0/ChangeLog
--- old/sushy-4.3.0/ChangeLog   2022-08-26 19:56:31.000000000 +0200
+++ new/sushy-4.4.0/ChangeLog   2022-11-22 16:26:18.000000000 +0100
@@ -1,6 +1,18 @@
 CHANGES
 =======
 
+4.4.0
+-----
+
+* Make server connection retries configurable
+* Increase server side retries
+* Improve resiliency of eTag handling
+* Update release versions for yoga and zed
+* Fix misuse of assertTrue
+* Add Python3 antelope unit tests
+* Update master for stable/zed
+* Fix misuse of assertIsNone
+
 4.3.0
 -----
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/PKG-INFO new/sushy-4.4.0/PKG-INFO
--- old/sushy-4.3.0/PKG-INFO    2022-08-26 19:56:32.073955500 +0200
+++ new/sushy-4.4.0/PKG-INFO    2022-11-22 16:26:19.412175000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: sushy
-Version: 4.3.0
+Version: 4.4.0
 Summary: Sushy is a small Python library to communicate with Redfish based 
systems
 Home-page: https://docs.openstack.org/sushy/latest/
 Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sushy-4.3.0/releasenotes/notes/config-server-side-retries-d16824019bd709a2.yaml
 
new/sushy-4.4.0/releasenotes/notes/config-server-side-retries-d16824019bd709a2.yaml
--- 
old/sushy-4.3.0/releasenotes/notes/config-server-side-retries-d16824019bd709a2.yaml
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/sushy-4.4.0/releasenotes/notes/config-server-side-retries-d16824019bd709a2.yaml
 2022-11-22 16:25:52.000000000 +0100
@@ -0,0 +1,9 @@
+---
+features:
+  - |
+    Adds two new configuration options:
+    ``server_side_retries`` allows to set a custom value for the number of
+    times we should retry a GET request in case of a server error,
+    defaults to 10;
+    ``server_side_retries_delay`` allows to customize the time in seconds
+    between the request retries, defaults to 3.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sushy-4.3.0/releasenotes/notes/increase-server-retries-5f11edde8ee0b461.yaml
 
new/sushy-4.4.0/releasenotes/notes/increase-server-retries-5f11edde8ee0b461.yaml
--- 
old/sushy-4.3.0/releasenotes/notes/increase-server-retries-5f11edde8ee0b461.yaml
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/sushy-4.4.0/releasenotes/notes/increase-server-retries-5f11edde8ee0b461.yaml
    2022-11-22 16:25:52.000000000 +0100
@@ -0,0 +1,6 @@
+fixes:
+  - |
+    To avoid timeouts with recent versions of firmwares we need to increase
+    the number of server side retries.
+    For example, in idrac firmware series 5.x the time gap between operations
+    is almost 20 seconds instead of the 10 seconds in the 4.x series.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sushy-4.3.0/releasenotes/notes/releasenote-d7138d1e1d414632.yaml 
new/sushy-4.4.0/releasenotes/notes/releasenote-d7138d1e1d414632.yaml
--- old/sushy-4.3.0/releasenotes/notes/releasenote-d7138d1e1d414632.yaml        
1970-01-01 01:00:00.000000000 +0100
+++ new/sushy-4.4.0/releasenotes/notes/releasenote-d7138d1e1d414632.yaml        
2022-11-22 16:25:52.000000000 +0100
@@ -0,0 +1,10 @@
+---
+fixes:
+  - |
+    Alters eTag handling in PATCH requests: First, the original eTag is used.
+    In case of a failure, if the eTag provided was weak, it is converted to
+    a strong format by removing the weak prefix. If this approach is not
+    applicable or fails, the final attempt is made omitting the eTag entirely.
+    By taking this approach, no workarounds are applied if BMC is handling
+    eTags as expected and in case of failures, known workarounds are
+    attempted, improving overall resiliency.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/releasenotes/source/index.rst 
new/sushy-4.4.0/releasenotes/source/index.rst
--- old/sushy-4.3.0/releasenotes/source/index.rst       2022-08-26 
19:55:50.000000000 +0200
+++ new/sushy-4.4.0/releasenotes/source/index.rst       2022-11-22 
16:25:52.000000000 +0100
@@ -6,6 +6,7 @@
    :maxdepth: 1
 
    unreleased
+   zed
    yoga
    xena
    wallaby
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/releasenotes/source/yoga.rst 
new/sushy-4.4.0/releasenotes/source/yoga.rst
--- old/sushy-4.3.0/releasenotes/source/yoga.rst        2022-08-26 
19:55:50.000000000 +0200
+++ new/sushy-4.4.0/releasenotes/source/yoga.rst        2022-11-22 
16:25:52.000000000 +0100
@@ -1,6 +1,6 @@
-=========================
-Yoga Series Release Notes
-=========================
+=========================================
+Yoga Series (4.0.0 - 4.1.x) Release Notes
+=========================================
 
 .. release-notes::
    :branch: stable/yoga
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/releasenotes/source/zed.rst 
new/sushy-4.4.0/releasenotes/source/zed.rst
--- old/sushy-4.3.0/releasenotes/source/zed.rst 1970-01-01 01:00:00.000000000 
+0100
+++ new/sushy-4.4.0/releasenotes/source/zed.rst 2022-11-22 16:25:52.000000000 
+0100
@@ -0,0 +1,6 @@
+========================================
+Zed Series (4.2.0 - 4.3.x) Release Notes
+========================================
+
+.. release-notes::
+   :branch: stable/zed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/sushy/connector.py 
new/sushy-4.4.0/sushy/connector.py
--- old/sushy-4.3.0/sushy/connector.py  2022-08-26 19:55:50.000000000 +0200
+++ new/sushy-4.4.0/sushy/connector.py  2022-11-22 16:25:52.000000000 +0100
@@ -13,7 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from http import client as http_client
 import logging
+import re
 import time
 from urllib import parse as urlparse
 
@@ -26,21 +28,20 @@
 LOG = logging.getLogger(__name__)
 
 
-_SERVER_SIDE_RETRIES = 5
-_SERVER_SIDE_RETRY_DELAY = 3
-
-
 class Connector(object):
 
     def __init__(
             self, url, username=None, password=None, verify=True,
-            response_callback=None):
+            response_callback=None, server_side_retries=0,
+            server_side_retries_delay=0):
         self._url = url
         self._verify = verify
         self._session = requests.Session()
         self._session.verify = self._verify
         self._response_callback = response_callback
         self._auth = None
+        self._server_side_retries = server_side_retries
+        self._server_side_retries_delay = server_side_retries_delay
 
         # NOTE(TheJulia): In order to help prevent recursive post operations
         # by allowing us to understand that we should stop authentication.
@@ -85,8 +86,7 @@
         self._session.close()
 
     def _op(self, method, path='', data=None, headers=None, blocking=False,
-            timeout=60, server_side_retries=_SERVER_SIDE_RETRIES,
-            **extra_session_req_kwargs):
+            timeout=60, **extra_session_req_kwargs):
         """Generic RESTful request handler.
 
         :param method: The HTTP method to be used, e.g: GET, POST,
@@ -197,16 +197,16 @@
                               "%s", e.message)
                 raise
         except exceptions.ServerSideError as e:
-            if method.lower() != 'get' or server_side_retries <= 0:
+            if method.lower() != 'get' or self._server_side_retries <= 0:
                 raise
             else:
                 LOG.warning('Got server side error %s in response to a '
                             'GET request, retrying after %d seconds',
-                            e, _SERVER_SIDE_RETRY_DELAY)
-                time.sleep(_SERVER_SIDE_RETRY_DELAY)
+                            e, self._server_side_retries)
+                time.sleep(self._server_side_retries_delay)
+                self._server_side_retries -= 1
                 return self._op(method, path, data=data, headers=headers,
                                 blocking=blocking, timeout=timeout,
-                                server_side_retries=server_side_retries - 1,
                                 **extra_session_req_kwargs)
 
         if blocking and response.status_code == 202:
@@ -268,13 +268,93 @@
                         blocking=blocking, timeout=timeout,
                         **extra_session_req_kwargs)
 
-    def patch(self, path='', data=None, headers=None, blocking=False,
-              timeout=60, **extra_session_req_kwargs):
+    def _etag_handler(self, path='', data=None, headers=None, etag=None,
+                      blocking=False, timeout=60, **extra_session_req_kwargs):
+        """eTag handler containing workarounds for PATCH requests with eTags.
+
+        :param path: Optional sub-URI path to the resource.
+        :param data: Optional JSON data.
+        :param headers: Optional dictionary of headers.
+        :param etag: eTag string.
+        :param blocking: Whether to block for asynchronous operations.
+        :param timeout: Max time in seconds to wait for blocking async call.
+        :param extra_session_req_kwargs: Optional keyword argument to pass
+         requests library arguments which would pass on to requests session
+         object.
+        :returns: The response object from the requests library.
+        :raises: ConnectionError
+        :raises: HTTPError
+        """
+        if etag is not None:
+            if not headers:
+                headers = {}
+            headers['If-Match'] = etag
+        try:
+            response = self._op('PATCH', path, data=data,
+                                headers=headers,
+                                blocking=blocking, timeout=timeout,
+                                **extra_session_req_kwargs)
+        except exceptions.HTTPError as resp:
+            LOG.warning("Initial request with eTag failed: %s",
+                        resp)
+            if resp.status_code == http_client.PRECONDITION_FAILED:
+                # NOTE(janders) if there was no eTag provided AND the response
+                # is HTTP 412 Precondition Failed, raise the exception
+                if not etag:
+                    raise
+                # checking for weak eTag
+                pattern = re.compile(r'^(W\/)("\w*")$')
+                match = pattern.match(etag)
+                if match:
+                    LOG.info("Weak eTag provided with original request to "
+                             "%s. Attempting to conversion to strong eTag "
+                             "and re-trying.", path)
+                    # trying weak eTag converted to strong
+                    headers['If-Match'] = match.group(2)
+                    try:
+                        response = self._op('PATCH', path, data=data,
+                                            headers=headers,
+                                            blocking=blocking,
+                                            timeout=timeout,
+                                            **extra_session_req_kwargs)
+                    except exceptions.HTTPError as resp:
+                        if (resp.status_code == http_client.
+                           PRECONDITION_FAILED):
+                            LOG.warning("Request to %s with weak eTag "
+                                        "converted to strong eTag also "
+                                        "failed. Making the final attempt "
+                                        "with no eTag specified.", path)
+                        response = None
+                    if response:
+                        return response
+                else:
+                    # eTag is strong, if it failed the only other thing
+                    # to try is removing it entirely
+                    # info
+                    LOG.warning("Strong eTag provided - retrying request to "
+                                "%s with eTag removed.", path)
+                del headers['If-Match']
+                try:
+                    response = self._op('PATCH', path, data=data,
+                                        headers=headers,
+                                        blocking=blocking, timeout=timeout,
+                                        **extra_session_req_kwargs)
+                except exceptions.HTTPError as resp:
+                    LOG.error("Final re-try with eTag removed has failed, "
+                              "raising exception %s", resp)
+                    raise
+            else:
+                raise
+        return response
+
+    def patch(self, path='', data=None, headers=None, etag=None,
+              blocking=False, timeout=60, **extra_session_req_kwargs):
         """HTTP PATCH method.
 
         :param path: Optional sub-URI path to the resource.
         :param data: Optional JSON data.
         :param headers: Optional dictionary of headers.
+        :param etag: Optional eTag string.
         :param blocking: Whether to block for asynchronous operations.
         :param timeout: Max time in seconds to wait for blocking async call.
         :param extra_session_req_kwargs: Optional keyword argument to pass
@@ -284,9 +364,10 @@
         :raises: ConnectionError
         :raises: HTTPError
         """
-        return self._op('PATCH', path, data=data, headers=headers,
-                        blocking=blocking, timeout=timeout,
-                        **extra_session_req_kwargs)
+        return self._etag_handler(path, data,
+                                  headers, etag,
+                                  blocking, timeout,
+                                  **extra_session_req_kwargs)
 
     def put(self, path='', data=None, headers=None, blocking=False,
             timeout=60, **extra_session_req_kwargs):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/sushy/main.py 
new/sushy-4.4.0/sushy/main.py
--- old/sushy-4.3.0/sushy/main.py       2022-08-26 19:55:50.000000000 +0200
+++ new/sushy-4.4.0/sushy/main.py       2022-11-22 16:25:52.000000000 +0100
@@ -158,7 +158,8 @@
                  root_prefix='/redfish/v1/', verify=True,
                  auth=None, connector=None,
                  public_connector=None,
-                 language='en'):
+                 language='en', server_side_retries=10,
+                 server_side_retries_delay=3):
         """A class representing a RootService
 
         :param base_url: The base URL to the Redfish controller. It
@@ -181,6 +182,10 @@
             on the Internet, e.g., for Message Registries. Defaults to None.
         :param language: RFC 5646 language code for Message Registries.
             Defaults to 'en'.
+        :param server_side_retries: Number of times to retry GET requests in
+            case of server side errors. Defaults to 10.
+        :param server_side_retries_delay: Time in seconds between retries of
+            GET requests in case of server side errors. Defaults to 3.
         """
         self._root_prefix = root_prefix
         if (auth is not None and (password is not None
@@ -194,7 +199,10 @@
         self._auth = auth
 
         super(Sushy, self).__init__(
-            connector or sushy_connector.Connector(base_url, verify=verify),
+            connector or sushy_connector.Connector(
+                base_url, verify=verify,
+                server_side_retries=server_side_retries,
+                server_side_retries_delay=server_side_retries_delay),
             path=self._root_prefix)
         self._public_connector = public_connector or requests
         self._language = language
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/sushy/resources/base.py 
new/sushy-4.4.0/sushy/resources/base.py
--- old/sushy-4.3.0/sushy/resources/base.py     2022-08-26 19:55:50.000000000 
+0200
+++ new/sushy-4.4.0/sushy/resources/base.py     2022-11-22 16:25:52.000000000 
+0100
@@ -20,7 +20,6 @@
 import io
 import json
 import logging
-import re
 import zipfile
 
 import pkg_resources
@@ -638,21 +637,7 @@
 
         :returns ETag or None
         """
-        etag = self._get_headers().get('ETag')
-        if not etag:
-            return None
-
-        # Note (arne_wiebalck): in case there is a weak Etag,
-        # return it with and without the qualifier to handle
-        # vendor implementations which may require one or the
-        # other (but should actually not use weak tags in the
-        # first place).
-        pattern = re.compile(r'^(W\/)("\w*")$')
-        match = pattern.match(etag)
-        if match:
-            return etag + ',' + match.group(2)
-
-        return etag
+        return self._get_headers().get('ETag')
 
     def _get_headers(self):
         """Returns the HTTP headers of the request for the resource.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/sushy/resources/system/system.py 
new/sushy-4.4.0/sushy/resources/system/system.py
--- old/sushy-4.3.0/sushy/resources/system/system.py    2022-08-26 
19:55:50.000000000 +0200
+++ new/sushy-4.4.0/sushy/resources/system/system.py    2022-11-22 
16:25:52.000000000 +0100
@@ -276,7 +276,6 @@
 
             data['Boot']['BootSourceOverrideMode'] = fishy_mode
 
-        headers = None
         etag = self._get_etag()
         path = self.path
 
@@ -290,9 +289,7 @@
 
         # TODO(lucasagomes): Check the return code and response body ?
         #                    Probably we should call refresh() as well.
-        if etag is not None:
-            headers = {'If-Match': etag}
-        self._conn.patch(path, data=data, headers=headers)
+        self._conn.patch(path, data=data, etag=etag)
 
     # TODO(etingof): we should remove this method, eventually
     def set_system_boot_source(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sushy-4.3.0/sushy/tests/unit/resources/compositionservice/test_compositionservice.py
 
new/sushy-4.4.0/sushy/tests/unit/resources/compositionservice/test_compositionservice.py
--- 
old/sushy-4.3.0/sushy/tests/unit/resources/compositionservice/test_compositionservice.py
    2022-08-26 19:55:50.000000000 +0200
+++ 
new/sushy-4.4.0/sushy/tests/unit/resources/compositionservice/test_compositionservice.py
    2022-11-22 16:25:52.000000000 +0100
@@ -41,7 +41,7 @@
         self.comp_ser._parse_attributes(self.json_doc)
         self.assertFalse(self.comp_ser.allow_overprovisioning)
         self.assertTrue(self.comp_ser.allow_zone_affinity)
-        self.assertTrue(self.comp_ser.description, 'CompositionService1')
+        self.assertEqual('CompositionService1', self.comp_ser.description)
         self.assertEqual(
             'CompositionService',
             self.comp_ser.identity)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sushy-4.3.0/sushy/tests/unit/resources/manager/test_virtual_media.py 
new/sushy-4.4.0/sushy/tests/unit/resources/manager/test_virtual_media.py
--- old/sushy-4.3.0/sushy/tests/unit/resources/manager/test_virtual_media.py    
2022-08-26 19:55:50.000000000 +0200
+++ new/sushy-4.4.0/sushy/tests/unit/resources/manager/test_virtual_media.py    
2022-11-22 16:25:52.000000000 +0100
@@ -175,7 +175,7 @@
             ("/redfish/v1/Managers/BMC/VirtualMedia/Floppy1"),
             data={"Image": "https://www.dmtf.org/freeImages/Sardine.img";,
                   "Inserted": True, "WriteProtected": False},
-            headers={"If-Match": 'W/"3d7b8a7360bf2941d","3d7b8a7360bf2941d"'})
+            headers={"If-Match": 'W/"3d7b8a7360bf2941d"'})
         self.assertTrue(self.sys_virtual_media._is_stale)
 
     @mock.patch.object(requests, 'post', autospec=True)
@@ -239,7 +239,7 @@
         self.sys_virtual_media._conn.patch.assert_called_once_with(
             ("/redfish/v1/Managers/BMC/VirtualMedia/Floppy1"),
             data={"Image": None, "Inserted": False},
-            headers={"If-Match": 'W/"3d7b8a7360bf2941d","3d7b8a7360bf2941d"'})
+            headers={"If-Match": 'W/"3d7b8a7360bf2941d"'})
         self.assertTrue(self.sys_virtual_media._is_stale)
 
     def test_eject_media_pass_empty_dict_415(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sushy-4.3.0/sushy/tests/unit/resources/system/test_system.py 
new/sushy-4.4.0/sushy/tests/unit/resources/system/test_system.py
--- old/sushy-4.3.0/sushy/tests/unit/resources/system/test_system.py    
2022-08-26 19:55:50.000000000 +0200
+++ new/sushy-4.4.0/sushy/tests/unit/resources/system/test_system.py    
2022-11-22 16:25:52.000000000 +0100
@@ -283,7 +283,7 @@
             data={'Boot': {'BootSourceOverrideEnabled': 'Continuous',
                            'BootSourceOverrideTarget': 'Pxe',
                            'BootSourceOverrideMode': 'UEFI'}},
-            headers=None)
+            etag=None)
 
     def test_set_system_boot_options_no_mode_specified(self):
         self.sys_inst.set_system_boot_options(
@@ -293,7 +293,7 @@
             '/redfish/v1/Systems/437XR1138R2',
             data={'Boot': {'BootSourceOverrideEnabled': 'Once',
                            'BootSourceOverrideTarget': 'Hdd'}},
-            headers=None)
+            etag=None)
 
     def test_set_system_boot_options_no_target_specified(self):
         self.sys_inst.set_system_boot_options(
@@ -303,7 +303,7 @@
             '/redfish/v1/Systems/437XR1138R2',
             data={'Boot': {'BootSourceOverrideEnabled': 'Continuous',
                            'BootSourceOverrideMode': 'UEFI'}},
-            headers=None)
+            etag=None)
 
     def test_set_system_boot_options_no_freq_specified(self):
         self.sys_inst.set_system_boot_options(
@@ -313,13 +313,13 @@
             '/redfish/v1/Systems/437XR1138R2',
             data={'Boot': {'BootSourceOverrideTarget': 'Pxe',
                            'BootSourceOverrideMode': 'UEFI'}},
-            headers=None)
+            etag=None)
 
     def test_set_system_boot_options_nothing_specified(self):
         self.sys_inst.set_system_boot_options()
         self.sys_inst._conn.patch.assert_called_once_with(
             '/redfish/v1/Systems/437XR1138R2', data={},
-            headers=None)
+            etag=None)
 
     def test_set_system_boot_options_invalid_target(self):
         self.assertRaises(exceptions.InvalidParameterValueError,
@@ -350,7 +350,7 @@
             '/redfish/v1/Systems/437XR1138R2',
             data={'Boot': {'BootSourceOverrideEnabled': 'Once',
                            'BootSourceOverrideTarget': 'UsbCd'}},
-            headers=None)
+            etag=None)
 
     def test_set_system_boot_options_supermicro_no_usb_cd_boot(self):
 
@@ -363,7 +363,7 @@
             '/redfish/v1/Systems/437XR1138R2',
             data={'Boot': {'BootSourceOverrideEnabled': 'Once',
                            'BootSourceOverrideTarget': 'Cd'}},
-            headers=None)
+            etag=None)
 
     def test_set_system_boot_options_settings_resource_nokia(self):
         self.conn.get.return_value.headers = {'ETag': '"3d7b838291941d"'}
@@ -381,7 +381,7 @@
             '/redfish/v1/Systems/Self/SD',
             data={'Boot': {'BootSourceOverrideEnabled': 'Once',
                            'BootSourceOverrideTarget': 'Cd'}},
-            headers={'If-Match': '"3d7b838291941d"'})
+            etag='"3d7b838291941d"')
 
     def test_set_system_boot_options_settings_resource(self):
         self.conn.get.return_value.headers = {'ETag': '"3d7b838291941d"'}
@@ -399,7 +399,7 @@
             '/redfish/v1/Systems/437XR1138R2/BIOS/Settings',
             data={'Boot': {'BootSourceOverrideEnabled': 'Once',
                            'BootSourceOverrideTarget': 'Cd'}},
-            headers={'If-Match': '"3d7b838291941d"'})
+            etag='"3d7b838291941d"')
 
     def test_set_system_boot_source(self):
         self.sys_inst.set_system_boot_source(
@@ -411,7 +411,7 @@
             data={'Boot': {'BootSourceOverrideEnabled': 'Continuous',
                            'BootSourceOverrideTarget': 'Pxe',
                            'BootSourceOverrideMode': 'UEFI'}},
-            headers=None)
+            etag=None)
 
     def test_set_system_boot_source_with_etag(self):
         self.conn.get.return_value.headers = {'ETag': '"3d7b838291941d"'}
@@ -424,7 +424,7 @@
             data={'Boot': {'BootSourceOverrideEnabled': 'Continuous',
                            'BootSourceOverrideTarget': 'Pxe',
                            'BootSourceOverrideMode': 'UEFI'}},
-            headers={'If-Match': '"3d7b838291941d"'})
+            etag='"3d7b838291941d"')
 
     def test_set_system_boot_source_no_mode_specified(self):
         self.sys_inst.set_system_boot_source(
@@ -434,7 +434,7 @@
             '/redfish/v1/Systems/437XR1138R2',
             data={'Boot': {'BootSourceOverrideEnabled': 'Once',
                            'BootSourceOverrideTarget': 'Hdd'}},
-            headers=None)
+            etag=None)
 
     def test_set_system_boot_source_invalid_target(self):
         self.assertRaises(exceptions.InvalidParameterValueError,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/sushy/tests/unit/test_connector.py 
new/sushy-4.4.0/sushy/tests/unit/test_connector.py
--- old/sushy-4.3.0/sushy/tests/unit/test_connector.py  2022-08-26 
19:55:50.000000000 +0200
+++ new/sushy-4.4.0/sushy/tests/unit/test_connector.py  2022-11-22 
16:25:52.000000000 +0100
@@ -164,7 +164,8 @@
         self.auth = mock_auth
         super(ConnectorOpTestCase, self).setUp()
         self.conn = connector.Connector(
-            'http://foo.bar:1234', verify=True)
+            'http://foo.bar:1234', verify=True,
+            server_side_retries=10, server_side_retries_delay=3)
         self.conn._auth = mock_auth
         self.data = {'fake': 'data'}
         self.headers = {'X-Fake': 'header'}
@@ -401,8 +402,8 @@
             self.conn._op('GET', 'http://foo.bar')
         exc = cm.exception
         self.assertEqual(http_client.INTERNAL_SERVER_ERROR, exc.status_code)
-        self.assertEqual(5, mock_sleep.call_count)
-        self.assertEqual(6, self.request.call_count)
+        self.assertEqual(10, mock_sleep.call_count)
+        self.assertEqual(11, self.request.call_count)
 
     def test_access_error(self):
         self.conn._auth = None
@@ -577,3 +578,175 @@
                               'POST',
                               'http://foo.bar',
                               blocking=True)
+
+    @mock.patch.object(connector.Connector, '_op', autospec=True)
+    def test_etag_handler_strong_etag_ok(self, mock__op):
+        self.headers['If-Match'] = '"3d7b8a7360bf2941d"'
+        response = mock.MagicMock(spec=requests.Response)
+        response.status_code = http_client.OK
+        data = {'Boot': {'BootSourceOverrideTarget': 'Cd',
+                         'BootSourceOverrideEnabled': 'Once'}}
+        mock__op.return_value = response
+        self.conn._etag_handler(path='/redfish/v1/Systems/1',
+                                headers=self.headers, data=data,
+                                etag=self.headers['If-Match'],
+                                blocking=False, timeout=60)
+        mock__op.assert_called_once_with(
+            self.conn,
+            "PATCH",
+            '/redfish/v1/Systems/1',
+            data={'Boot': {'BootSourceOverrideTarget': 'Cd',
+                           'BootSourceOverrideEnabled': 'Once'}},
+            headers={'X-Fake': 'header',
+                     'If-Match': '"3d7b8a7360bf2941d"'},
+            blocking=False,
+            timeout=60)
+
+    @mock.patch.object(connector.Connector, '_op', autospec=True)
+    def test_etag_handler_weak_etag_ok(self, mock__op):
+        self.headers['If-Match'] = 'W/"3d7b8a7360bf2941d"'
+        response = mock.MagicMock(spec=requests.Response)
+        response.status_code = http_client.OK
+        data = {'Boot': {'BootSourceOverrideTarget': 'Cd',
+                         'BootSourceOverrideEnabled': 'Once'}}
+        mock__op.return_value = response
+        self.conn._etag_handler(path='/redfish/v1/Systems/1',
+                                headers=self.headers, data=data,
+                                etag=self.headers['If-Match'],
+                                blocking=False, timeout=60)
+        mock__op.assert_called_once_with(
+            self.conn,
+            "PATCH",
+            '/redfish/v1/Systems/1',
+            data={'Boot': {'BootSourceOverrideTarget': 'Cd',
+                           'BootSourceOverrideEnabled': 'Once'}},
+            headers={'X-Fake': 'header',
+                     'If-Match': 'W/"3d7b8a7360bf2941d"'},
+            blocking=False,
+            timeout=60)
+
+    @mock.patch.object(connector.Connector, '_op', autospec=True)
+    def test_etag_handler_no_etag_ok(self, mock__op):
+        response = mock.MagicMock(spec=requests.Response)
+        response.status_code = http_client.OK
+        data = {'Boot': {'BootSourceOverrideTarget': 'Cd',
+                         'BootSourceOverrideEnabled': 'Once'}}
+        mock__op.return_value = response
+        self.conn._etag_handler(path='/redfish/v1/Systems/1',
+                                headers=self.headers, data=data,
+                                blocking=False, timeout=60)
+        mock__op.assert_called_once_with(
+            self.conn,
+            "PATCH",
+            '/redfish/v1/Systems/1',
+            data={'Boot': {'BootSourceOverrideTarget': 'Cd',
+                           'BootSourceOverrideEnabled': 'Once'}},
+            headers={'X-Fake': 'header'},
+            blocking=False,
+            timeout=60)
+
+    @mock.patch.object(connector.Connector, '_op', autospec=True)
+    def test_etag_handler_weak_etag_fallback_to_strong(self, mock__op):
+        self.headers['If-Match'] = 'W/"3d7b8a7360bf2941d"'
+        target_uri = '/redfish/v1/Systems/1'
+        response_412 = mock.MagicMock(spec=requests.Response)
+        response_412.status_code = http_client.PRECONDITION_FAILED
+        response_200 = mock.MagicMock(spec=requests.Response)
+        response_200.status_code = http_client.OK
+        mock__op.side_effect = [
+            exceptions.HTTPError(method='PATCH', url=target_uri,
+                                 response=response_412),
+            response_200]
+
+        data = {'Boot': {'BootSourceOverrideTarget': 'Cd',
+                         'BootSourceOverrideEnabled': 'Once'}}
+        self.conn._etag_handler(path=target_uri, headers=self.headers,
+                                data=data, etag=self.headers['If-Match'],
+                                blocking=False, timeout=60)
+        mock__op.assert_called_with(
+            self.conn,
+            "PATCH",
+            '/redfish/v1/Systems/1',
+            data={'Boot': {'BootSourceOverrideTarget': 'Cd',
+                           'BootSourceOverrideEnabled': 'Once'}},
+            headers={'X-Fake': 'header',
+                     'If-Match': '"3d7b8a7360bf2941d"'},
+            blocking=False,
+            timeout=60)
+
+    @mock.patch.object(connector.Connector, '_op', autospec=True)
+    def test_etag_handler_weak_etag_fallback_to_no_etag(self, mock__op):
+        self.headers['If-Match'] = 'W/"3d7b8a7360bf2941d"'
+        target_uri = '/redfish/v1/Systems/1'
+        response_412 = mock.MagicMock(spec=requests.Response)
+        response_412.status_code = http_client.PRECONDITION_FAILED
+        response_200 = mock.MagicMock(spec=requests.Response)
+        response_200.status_code = http_client.OK
+        mock__op.side_effect = [
+            exceptions.HTTPError(method='PATCH', url=target_uri,
+                                 response=response_412),
+            exceptions.HTTPError(method='PATCH', url=target_uri,
+                                 response=response_412),
+            response_200]
+
+        data = {'Boot': {'BootSourceOverrideTarget': 'Cd',
+                         'BootSourceOverrideEnabled': 'Once'}}
+        self.conn._etag_handler(path=target_uri, headers=self.headers,
+                                data=data, etag=self.headers['If-Match'],
+                                blocking=False, timeout=60)
+        mock__op.assert_called_with(
+            self.conn,
+            "PATCH",
+            '/redfish/v1/Systems/1',
+            data={'Boot': {'BootSourceOverrideTarget': 'Cd',
+                           'BootSourceOverrideEnabled': 'Once'}},
+            headers={'X-Fake': 'header'},
+            blocking=False,
+            timeout=60)
+
+    @mock.patch.object(connector.Connector, '_op', autospec=True)
+    def test_etag_handler_strong_etag_fallback_to_no_etag(self, mock__op):
+        self.headers['If-Match'] = '"3d7b8a7360bf2941d"'
+        target_uri = '/redfish/v1/Systems/1'
+        response_412 = mock.MagicMock(spec=requests.Response)
+        response_412.status_code = http_client.PRECONDITION_FAILED
+        response_200 = mock.MagicMock(spec=requests.Response)
+        response_200.status_code = http_client.OK
+        mock__op.side_effect = [
+            exceptions.HTTPError(method='PATCH', url=target_uri,
+                                 response=response_412),
+            response_200]
+
+        data = {'Boot': {'BootSourceOverrideTarget': 'Cd',
+                         'BootSourceOverrideEnabled': 'Once'}}
+        self.conn._etag_handler(path=target_uri, headers=self.headers,
+                                data=data, etag=self.headers['If-Match'],
+                                blocking=False, timeout=60)
+        mock__op.assert_called_with(
+            self.conn,
+            "PATCH",
+            '/redfish/v1/Systems/1',
+            data={'Boot': {'BootSourceOverrideTarget': 'Cd',
+                           'BootSourceOverrideEnabled': 'Once'}},
+            headers={'X-Fake': 'header'},
+            blocking=False,
+            timeout=60)
+
+    @mock.patch.object(connector.Connector, '_op', autospec=True)
+    def test_etag_handler_fail_other_exception(self, mock__op):
+        self.headers['If-Match'] = 'W/"3d7b8a7360bf2941d"'
+        target_uri = '/redfish/v1/Systems/1'
+        data = {'Boot': {'BootSourceOverrideTarget': 'Cd',
+                         'BootSourceOverrideEnabled': 'Once'}}
+        response = mock.MagicMock(spec=requests.Response)
+        response.status_code = http_client.FORBIDDEN
+        response.message = "boom"
+        mock__op.return_value = response
+        mock__op.side_effect = \
+            exceptions.HTTPError(method='PATCH',
+                                 url=target_uri,
+                                 response=response)
+        self.assertRaises(exceptions.HTTPError, self.conn._etag_handler,
+                          'PATCH', target_uri, data,
+                          self.headers,
+                          blocking=False, timeout=60)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/sushy/tests/unit/test_main.py 
new/sushy-4.4.0/sushy/tests/unit/test_main.py
--- old/sushy-4.3.0/sushy/tests/unit/test_main.py       2022-08-26 
19:55:50.000000000 +0200
+++ new/sushy-4.4.0/sushy/tests/unit/test_main.py       2022-11-22 
16:25:52.000000000 +0100
@@ -53,7 +53,8 @@
         self.root = main.Sushy('http://foo.bar:1234',
                                verify=True, auth=mock_auth)
         mock_connector.assert_called_once_with(
-            'http://foo.bar:1234', verify=True)
+            'http://foo.bar:1234', verify=True, server_side_retries=10,
+            server_side_retries_delay=3)
 
     def test__parse_attributes(self):
         self.root._parse_attributes(self.json_doc)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/sushy/tests/unit/test_utils.py 
new/sushy-4.4.0/sushy/tests/unit/test_utils.py
--- old/sushy-4.3.0/sushy/tests/unit/test_utils.py      2022-08-26 
19:55:50.000000000 +0200
+++ new/sushy-4.4.0/sushy/tests/unit/test_utils.py      2022-11-22 
16:25:52.000000000 +0100
@@ -43,7 +43,7 @@
 
     def test_int_or_none(self):
         self.assertEqual(1, utils.int_or_none('1'))
-        self.assertIsNone(None, utils.int_or_none(None))
+        self.assertIsNone(utils.int_or_none(None))
 
     def test_bool_or_none_none(self):
         self.assertIsNone(utils.bool_or_none(None))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/sushy.egg-info/PKG-INFO 
new/sushy-4.4.0/sushy.egg-info/PKG-INFO
--- old/sushy-4.3.0/sushy.egg-info/PKG-INFO     2022-08-26 19:56:31.000000000 
+0200
+++ new/sushy-4.4.0/sushy.egg-info/PKG-INFO     2022-11-22 16:26:19.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: sushy
-Version: 4.3.0
+Version: 4.4.0
 Summary: Sushy is a small Python library to communicate with Redfish based 
systems
 Home-page: https://docs.openstack.org/sushy/latest/
 Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/sushy.egg-info/SOURCES.txt 
new/sushy-4.4.0/sushy.egg-info/SOURCES.txt
--- old/sushy-4.3.0/sushy.egg-info/SOURCES.txt  2022-08-26 19:56:31.000000000 
+0200
+++ new/sushy-4.4.0/sushy.egg-info/SOURCES.txt  2022-11-22 16:26:19.000000000 
+0100
@@ -67,6 +67,7 @@
 releasenotes/notes/certificate-collection-acc67488c240274c.yaml
 releasenotes/notes/change-bootdev-smc-ab30317eaf5c37d9.yaml
 releasenotes/notes/change-vmedia-write-protected-attr-586370a552288801.yaml
+releasenotes/notes/config-server-side-retries-d16824019bd709a2.yaml
 releasenotes/notes/decouple-boot-params-c75e80f5951abb12.yaml
 releasenotes/notes/deprecate-system-leds-f1a72422c53d281e.yaml
 releasenotes/notes/disable-conn-pooling-3456782afe56ac94.yaml
@@ -101,6 +102,7 @@
 releasenotes/notes/get-retry-9ca311caf8a0b7bb.yaml
 releasenotes/notes/handle-basic-auth-access-errors-393b368b31f5cad2.yaml
 releasenotes/notes/health_literals_change-0e3fc0c439b765e3.yaml
+releasenotes/notes/increase-server-retries-5f11edde8ee0b461.yaml
 releasenotes/notes/indicator-led-mappings-e7b34da03f6abb06.yaml
 releasenotes/notes/lazily-load-registries-0e9441e435c2471d.yaml
 releasenotes/notes/make-leds-settable-c82cb513de0171f5.yaml
@@ -113,6 +115,7 @@
 
releasenotes/notes/reauthentication-session-fallback-failure-fixes-4f0dcfdad1afd2d7.yaml
 releasenotes/notes/redfish-response-log-294f3f10b770e356.yaml
 releasenotes/notes/refactor-taskmonitor-update-volume-ba99380188395852.yaml
+releasenotes/notes/releasenote-d7138d1e1d414632.yaml
 releasenotes/notes/remove-deprecated-task-monitors-58c505d43e1fa6a7.yaml
 releasenotes/notes/retry-if-transferprototype-missing-9cae57f3ecf470a9.yaml
 releasenotes/notes/secure-boot-76c5b80371ea85d1.yaml
@@ -142,6 +145,7 @@
 releasenotes/source/wallaby.rst
 releasenotes/source/xena.rst
 releasenotes/source/yoga.rst
+releasenotes/source/zed.rst
 releasenotes/source/_static/.placeholder
 releasenotes/source/_templates/.placeholder
 sushy/__init__.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/sushy.egg-info/pbr.json 
new/sushy-4.4.0/sushy.egg-info/pbr.json
--- old/sushy-4.3.0/sushy.egg-info/pbr.json     2022-08-26 19:56:31.000000000 
+0200
+++ new/sushy-4.4.0/sushy.egg-info/pbr.json     2022-11-22 16:26:19.000000000 
+0100
@@ -1 +1 @@
-{"git_version": "2c96ab8", "is_release": true}
\ No newline at end of file
+{"git_version": "56efdee", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sushy-4.3.0/zuul.d/project.yaml 
new/sushy-4.4.0/zuul.d/project.yaml
--- old/sushy-4.3.0/zuul.d/project.yaml 2022-08-26 19:55:50.000000000 +0200
+++ new/sushy-4.4.0/zuul.d/project.yaml 2022-11-22 16:25:52.000000000 +0100
@@ -2,7 +2,7 @@
     templates:
       - check-requirements
       - openstack-cover-jobs
-      - openstack-python3-zed-jobs
+      - openstack-python3-antelope-jobs
       - publish-openstack-docs-pti
       - release-notes-jobs-python3
     check:

Reply via email to