Browse Source

Merge "Replace oslo's loopingcall with tenacity"

changes/98/745598/4
Zuul 1 week ago
committed by Gerrit Code Review
parent
commit
a3b10db95a
4 changed files with 53 additions and 35 deletions
  1. +13
    -15
      ironic_python_agent/ironic_api_client.py
  2. +38
    -20
      ironic_python_agent/tests/unit/test_ironic_api_client.py
  3. +1
    -0
      lower-constraints.txt
  4. +1
    -0
      requirements.txt

+ 13
- 15
ironic_python_agent/ironic_api_client.py View File

@@ -18,8 +18,8 @@ from distutils.version import StrictVersion
from oslo_config import cfg
from oslo_log import log
from oslo_serialization import jsonutils
from oslo_service import loopingcall
import requests
import tenacity

from ironic_python_agent import encoding
from ironic_python_agent import errors
@@ -138,24 +138,22 @@ class APIClient(object):
raise errors.HeartbeatError(msg)

def lookup_node(self, hardware_info, timeout, starting_interval,
node_uuid=None):
timer = loopingcall.BackOffLoopingCall(
self._do_lookup,
hardware_info=hardware_info,
node_uuid=node_uuid)
node_uuid=None, max_interval=30):
retry = tenacity.retry(
retry=tenacity.retry_if_result(lambda r: r is False),
stop=tenacity.stop_after_delay(timeout),
wait=tenacity.wait_random_exponential(min=starting_interval,
max=max_interval),
reraise=True)
try:
node_content = timer.start(starting_interval=starting_interval,
timeout=timeout).wait()
except loopingcall.LoopingCallTimeOut:
return retry(self._do_lookup)(hardware_info=hardware_info,
node_uuid=node_uuid)
except tenacity.RetryError:
raise errors.LookupNodeError('Could not look up node info. Check '
'logs for details.')
return node_content

def _do_lookup(self, hardware_info, node_uuid):
"""The actual call to lookup a node.

Should be called as a `loopingcall.BackOffLoopingCall`.
"""
"""The actual call to lookup a node."""
params = {
'addresses': ','.join(iface.mac_address
for iface in hardware_info['interfaces']
@@ -241,7 +239,7 @@ class APIClient(object):
return False

# Got valid content
raise loopingcall.LoopingCallDone(retvalue=content)
return content

def _get_agent_url(self, advertise_address, advertise_protocol='http'):
return '{}://{}:{}'.format(advertise_protocol,


+ 38
- 20
ironic_python_agent/tests/unit/test_ironic_api_client.py View File

@@ -15,7 +15,6 @@
from unittest import mock

from oslo_serialization import jsonutils
from oslo_service import loopingcall
import requests

from ironic_python_agent import errors
@@ -244,7 +243,7 @@ class TestBaseIronicPythonAgent(base.IronicAgentTest):
uuid='meow',
advertise_address=('192.0.2.1', '9999'))

@mock.patch('eventlet.greenthread.sleep', autospec=True)
@mock.patch('time.sleep', autospec=True)
@mock.patch('ironic_python_agent.ironic_api_client.APIClient._do_lookup',
autospec=True)
def test_lookup_node(self, lookup_mock, sleep_mock):
@@ -256,8 +255,7 @@ class TestBaseIronicPythonAgent(base.IronicAgentTest):
'heartbeat_timeout': 300
}
}
lookup_mock.side_effect = loopingcall.LoopingCallDone(
retvalue=content)
lookup_mock.return_value = content
returned_content = self.api_client.lookup_node(
hardware_info=self.hardware_info,
timeout=300,
@@ -265,34 +263,54 @@ class TestBaseIronicPythonAgent(base.IronicAgentTest):

self.assertEqual(content, returned_content)

@mock.patch('eventlet.greenthread.sleep', autospec=True)
@mock.patch('time.sleep', autospec=True)
@mock.patch('ironic_python_agent.ironic_api_client.APIClient._do_lookup',
autospec=True)
def test_lookup_node_retries(self, lookup_mock, sleep_mock):
content = {
'node': {
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
},
'config': {
'heartbeat_timeout': 300
}
}
lookup_mock.side_effect = [False, content]
returned_content = self.api_client.lookup_node(
hardware_info=self.hardware_info,
timeout=300,
starting_interval=0.001)

self.assertEqual(content, returned_content)

@mock.patch('time.sleep', autospec=True)
@mock.patch('ironic_python_agent.ironic_api_client.APIClient._do_lookup',
autospec=True)
def test_lookup_timeout(self, lookup_mock, sleep_mock):
lookup_mock.side_effect = loopingcall.LoopingCallTimeOut()
lookup_mock.return_value = False
self.assertRaises(errors.LookupNodeError,
self.api_client.lookup_node,
hardware_info=self.hardware_info,
timeout=300,
starting_interval=1)
timeout=0.1,
starting_interval=0.001)

def test_do_lookup(self):
response = FakeResponse(status_code=200, content={
content = {
'node': {
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
},
'config': {
'heartbeat_timeout': 300
}
})
}
response = FakeResponse(status_code=200, content=content)

self.api_client.session.request = mock.Mock()
self.api_client.session.request.return_value = response

self.assertRaises(loopingcall.LoopingCallDone,
self.api_client._do_lookup,
hardware_info=self.hardware_info,
node_uuid=None)
self.assertEqual(content, self.api_client._do_lookup(
hardware_info=self.hardware_info,
node_uuid=None))

url = '{api_url}v1/lookup'.format(api_url=API_URL)
request_args = self.api_client.session.request.call_args[0]
@@ -303,22 +321,22 @@ class TestBaseIronicPythonAgent(base.IronicAgentTest):
params)

def test_do_lookup_with_uuid(self):
response = FakeResponse(status_code=200, content={
content = {
'node': {
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
},
'config': {
'heartbeat_timeout': 300
}
})
}
response = FakeResponse(status_code=200, content=content)

self.api_client.session.request = mock.Mock()
self.api_client.session.request.return_value = response

self.assertRaises(loopingcall.LoopingCallDone,
self.api_client._do_lookup,
hardware_info=self.hardware_info,
node_uuid='someuuid')
self.assertEqual(content, self.api_client._do_lookup(
hardware_info=self.hardware_info,
node_uuid='someuuid'))

url = '{api_url}v1/lookup'.format(api_url=API_URL)
request_args = self.api_client.session.request.call_args[0]


+ 1
- 0
lower-constraints.txt View File

@@ -78,6 +78,7 @@ Sphinx==2.0.0
sphinxcontrib-websupport==1.0.1
stestr==1.0.0
stevedore==1.20.0
tenacity==6.2.0
testrepository==0.0.20
testtools==2.2.0
traceback2==1.4.0


+ 1
- 0
requirements.txt View File

@@ -16,5 +16,6 @@ pyudev>=0.18 # LGPLv2.1+
requests>=2.14.2 # Apache-2.0
rtslib-fb>=2.1.65 # Apache-2.0
stevedore>=1.20.0 # Apache-2.0
tenacity>=6.2.0 # Apache-2.0
ironic-lib>=4.1.0 # Apache-2.0
Werkzeug>=1.0.1 # BSD License

Loading…
Cancel
Save