From d160bfbc7ef8e1d1ef8281a35b9261aa27a568fa Mon Sep 17 00:00:00 2001 From: Mark Syms Date: Mon, 9 Dec 2024 10:41:57 +0000 Subject: [PATCH] CP-52852: add handler for xmlrpc ProtocolError It is possible that a XenAPI call to xapi will result in an xmlrpc ProtocolError being returned, typically a 500 Internal Error. As it is not practical to wrap all the calls to xapi via the xenapi session in a specific exception handler add one into the outer run method to ensure that it is converted to an error code and not an unknown error. Signed-off-by: Mark Syms --- drivers/SRCommand.py | 10 ++++++++++ drivers/XE_SR_ERRORCODES.xml | 5 +++++ tests/test_SRCommand.py | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/drivers/SRCommand.py b/drivers/SRCommand.py index 4476c6af..6afbdfbd 100755 --- a/drivers/SRCommand.py +++ b/drivers/SRCommand.py @@ -17,11 +17,13 @@ # # SRCommand: parse SR command-line objects # +import traceback import XenAPI # pylint: disable=import-error import sys import xs_errors import xmlrpc.client +from xmlrpc.client import ProtocolError import SR import util import blktap2 @@ -390,6 +392,14 @@ def run(driver, driver_info): else: print(ret) + except ProtocolError: + # xs_errors.XenError.__new__ returns a different class + # pylint: disable-msg=E1101 + exception_trace = traceback.format_exc() + util.SMlog(f'XenAPI Protocol error {exception_trace}') + print(xs_errors.XenError( + 'APIProtocolError', + opterr=exception_trace).toxml()) except (Exception, xs_errors.SRException) as e: try: util.logException(driver_info['name']) diff --git a/drivers/XE_SR_ERRORCODES.xml b/drivers/XE_SR_ERRORCODES.xml index 725d14fe..47fefd83 100755 --- a/drivers/XE_SR_ERRORCODES.xml +++ b/drivers/XE_SR_ERRORCODES.xml @@ -534,6 +534,11 @@ A Failure occurred accessing an API object 153 + + APIProtocolError + A protocol error was received when accessing the API + 154 + diff --git a/tests/test_SRCommand.py b/tests/test_SRCommand.py index e3262359..af89e54b 100644 --- a/tests/test_SRCommand.py +++ b/tests/test_SRCommand.py @@ -1,6 +1,9 @@ import unittest import unittest.mock as mock +import uuid +import xmlrpc.client +import SR import SRCommand @@ -123,6 +126,39 @@ def test_run_wrapped_if_not_SRException( SRCommand.run(mock_driver, DRIVER_INFO) + @mock.patch("sys.exit", autospec=True) + @mock.patch('util.logException', autospec=True) + @mock.patch('SRCommand.SRCommand', autospec=True) + def test_run_reports_protocol_error( + self, + mock_sr_command, + mock_logException, + mock_exit): + + """ + If XenAPI raises a protocol error convert to error code + """ + from DummySR import DRIVER_INFO + + def raise_error(sr): + raise xmlrpc.client.ProtocolError( + 'XapiUrl', 500, + 'Internal Error', {}) + + # Create function to raise exception in SRCommand.run() + mock_cmd = mock.MagicMock() + mock_cmd.run.side_effect = raise_error + mock_cmd.sr_uuid = str(uuid.uuid4()) + mock_sr_command.return_value = mock_cmd + + mock_driver = mock.MagicMock(autospec=SR.SR) + + with mock.patch('builtins.print') as mock_print: + SRCommand.run(mock_driver, DRIVER_INFO) + + self.assertIn('154', + mock_print.call_args[0][0]) + @mock.patch("os.fsencode", new=lambda s: s.encode("ascii", "surrogateescape")) @mock.patch("os.fsdecode",