diff --git a/ironic_python_agent/agent.py b/ironic_python_agent/agent.py index fc0238fa9..1716edac1 100644 --- a/ironic_python_agent/agent.py +++ b/ironic_python_agent/agent.py @@ -118,6 +118,10 @@ class IronicPythonAgentHeartbeater(threading.Thread): ) self.error_delay = self.initial_delay LOG.info('heartbeat successful') + except errors.HeartbeatConflictError: + LOG.warning('conflict error sending heartbeat') + self.error_delay = min(self.error_delay * self.backoff_factor, + self.max_delay) except Exception: LOG.exception('error sending heartbeat') self.error_delay = min(self.error_delay * self.backoff_factor, diff --git a/ironic_python_agent/errors.py b/ironic_python_agent/errors.py index eb4c9c6eb..6fae45857 100644 --- a/ironic_python_agent/errors.py +++ b/ironic_python_agent/errors.py @@ -109,6 +109,15 @@ class HeartbeatError(IronicAPIError): super(HeartbeatError, self).__init__(details) +class HeartbeatConflictError(IronicAPIError): + """ConflictError raised when a heartbeat to the agent API fails.""" + + message = 'ConflictError heartbeating to agent API' + + def __init__(self, details): + super(HeartbeatConflictError, self).__init__(details) + + class LookupNodeError(IronicAPIError): """Error raised when the node lookup to the Ironic API fails.""" diff --git a/ironic_python_agent/ironic_api_client.py b/ironic_python_agent/ironic_api_client.py index 5017776ca..7b9a8ebc8 100644 --- a/ironic_python_agent/ironic_api_client.py +++ b/ironic_python_agent/ironic_api_client.py @@ -72,7 +72,10 @@ class APIClient(object): except Exception as e: raise errors.HeartbeatError(str(e)) - if response.status_code != requests.codes.ACCEPTED: + if response.status_code == requests.codes.CONFLICT: + data = response.json + raise errors.HeartbeatConflictError(data.get('faultstring')) + elif response.status_code != requests.codes.ACCEPTED: msg = 'Invalid status code: {0}'.format(response.status_code) raise errors.HeartbeatError(msg) diff --git a/ironic_python_agent/tests/unit/test_ironic_api_client.py b/ironic_python_agent/tests/unit/test_ironic_api_client.py index bad882d69..bad8fe456 100644 --- a/ironic_python_agent/tests/unit/test_ironic_api_client.py +++ b/ironic_python_agent/tests/unit/test_ironic_api_client.py @@ -89,6 +89,17 @@ class TestBaseIronicPythonAgent(test_base.BaseTestCase): uuid='deadbeef-dabb-ad00-b105-f00d00bab10c', advertise_address=('192.0.2.1', '9999')) + def test_heartbeat_409_status_code(self): + response = mock.Mock() + response.status_code = 409 + self.api_client.session.request = mock.Mock() + self.api_client.session.request.return_value = response + + self.assertRaises(errors.HeartbeatConflictError, + self.api_client.heartbeat, + uuid='deadbeef-dabb-ad00-b105-f00d00bab10c', + advertise_address=('192.0.2.1', '9999')) + @mock.patch('eventlet.greenthread.sleep') @mock.patch('ironic_python_agent.ironic_api_client.APIClient._do_lookup') def test_lookup_node(self, lookup_mock, sleep_mock):