Merge "CloudStack: catch proper HTTP exceptions"

This commit is contained in:
Zuul 2019-12-03 09:23:39 +00:00 committed by Gerrit Code Review
commit 6e9f0f0286
2 changed files with 77 additions and 23 deletions

View File

@ -173,9 +173,16 @@ class CloudStack(base.BaseHTTPMetadataService):
for _ in range(CONF.retry_count): for _ in range(CONF.retry_count):
try: try:
content = self._password_client(headers=headers).strip() content = self._password_client(headers=headers).strip()
except http_client.HTTPConnection as exc: except urllib.error.HTTPError as exc:
LOG.error("Getting password failed: %s", exc) LOG.debug("Getting password failed: %s", exc.code)
continue continue
except OSError as exc:
if exc.errno == 10061:
# Connection error
LOG.debug("Getting password failed due to a "
"connection failure.")
continue
raise
if not content: if not content:
LOG.warning("The Password Server did not have any " LOG.warning("The Password Server did not have any "
@ -212,15 +219,22 @@ class CloudStack(base.BaseHTTPMetadataService):
for _ in range(CONF.retry_count): for _ in range(CONF.retry_count):
try: try:
content = self._password_client(headers=headers).strip() content = self._password_client(headers=headers).strip()
except http_client.HTTPConnection as exc: except urllib.error.HTTPError as exc:
LOG.error("Removing password failed: %s", exc) LOG.debug("Removing password failed: %s", exc.code)
continue continue
except OSError as exc:
if exc.errno == 10061:
# Connection error
LOG.debug("Removing password failed due to a "
"connection failure.")
continue
raise
if content != BAD_REQUEST: if content != BAD_REQUEST:
LOG.info("The password was removed from the Password Server.") LOG.info("The password was removed from the Password Server.")
break break
else: else:
LOG.warning("Fail to remove the password from the " LOG.error("Failed to remove the password from the "
"Password Server.") "Password Server.")
def get_admin_password(self): def get_admin_password(self):

View File

@ -198,7 +198,8 @@ class CloudStackTest(unittest.TestCase):
@mock.patch('cloudbaseinit.metadata.services.cloudstack.CloudStack' @mock.patch('cloudbaseinit.metadata.services.cloudstack.CloudStack'
'._password_client') '._password_client')
def test_get_password_fail(self, mock_password_client): def test_get_password_fail(self, mock_password_client):
mock_password_client.side_effect = ["", cloudstack.BAD_REQUEST, mock_password_client.side_effect = ["",
cloudstack.BAD_REQUEST,
cloudstack.SAVED_PASSWORD] cloudstack.SAVED_PASSWORD]
expected_output = [ expected_output = [
["Try to get password from the Password Server.", ["Try to get password from the Password Server.",
@ -222,27 +223,66 @@ class CloudStackTest(unittest.TestCase):
@mock.patch('cloudbaseinit.metadata.services.cloudstack.CloudStack' @mock.patch('cloudbaseinit.metadata.services.cloudstack.CloudStack'
'._password_client') '._password_client')
def test_delete_password(self, mock_password_client): def test_get_password_exception(self, mock_password_client):
mock_password_client.side_effect = [cloudstack.BAD_REQUEST, fake_http_error = urllib.error.HTTPError(url='127.0.0.1', code=404,
cloudstack.SAVED_PASSWORD] hdrs={}, fp=None,
msg='error')
fake_error = OSError(10061, "Connection error")
mock_password_client.side_effect = [fake_http_error, fake_error]
expected_output = [ expected_output = [
'Remove the password for this instance from the ' ["Try to get password from the Password Server.",
'Password Server.', "Getting password failed due to a connection failure."],
'Fail to remove the password from the Password Server.',
'Remove the password for this instance from the ' ["Try to get password from the Password Server.",
"Getting password failed: 404"],
]
for _ in range(2):
with testutils.LogSnatcher('cloudbaseinit.metadata.services.'
'cloudstack') as snatcher:
self.assertIsNone(self._service._get_password())
self.assertEqual(expected_output.pop(), snatcher.output)
self.assertEqual(2, mock_password_client.call_count)
@mock.patch('cloudbaseinit.metadata.services.cloudstack.CloudStack'
'._password_client')
def test_delete_password(self, mock_password_client):
fake_url_error = urllib.error.HTTPError(url='127.0.0.1', code=404,
hdrs={}, fp=None,
msg='error')
fake_connection_error = OSError(10061, "Connection error")
mock_password_client.side_effect = [cloudstack.SAVED_PASSWORD,
cloudstack.BAD_REQUEST,
fake_url_error,
fake_connection_error]
expected_output = [
['Remove the password for this instance from the '
'Password Server.', 'Password Server.',
'The password was removed from the Password Server', 'Removing password failed due to a connection failure.',
'Failed to remove the password from the Password Server.'],
['Remove the password for this instance from the '
'Password Server.',
'Removing password failed: 404',
'Failed to remove the password from the Password Server.'],
['Remove the password for this instance from the '
'Password Server.',
'Failed to remove the password from the Password Server.'],
['Remove the password for this instance from the '
'Password Server.',
'The password was removed from the Password Server.'],
] ]
expected_output_len = len(expected_output)
for _ in range(expected_output_len):
with testutils.LogSnatcher('cloudbaseinit.metadata.services.' with testutils.LogSnatcher('cloudbaseinit.metadata.services.'
'cloudstack') as snatcher: 'cloudstack') as snatcher:
self.assertIsNone(self._service._delete_password()) self.assertIsNone(self._service._delete_password())
self.assertIsNone(self._service._delete_password()) self.assertEqual(expected_output.pop(), snatcher.output)
self.assertEqual(2, mock_password_client.call_count)
for expected, output in zip(expected_output, snatcher.output): self.assertEqual(expected_output_len, mock_password_client.call_count)
self.assertTrue(output.startswith(expected))
@mock.patch('cloudbaseinit.metadata.services.cloudstack.CloudStack.' @mock.patch('cloudbaseinit.metadata.services.cloudstack.CloudStack.'
'_delete_password') '_delete_password')