Merge "Replace oslo's loopingcall with tenacity"
This commit is contained in:
commit
a3b10db95a
|
@ -18,8 +18,8 @@ from distutils.version import StrictVersion
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
from oslo_service import loopingcall
|
|
||||||
import requests
|
import requests
|
||||||
|
import tenacity
|
||||||
|
|
||||||
from ironic_python_agent import encoding
|
from ironic_python_agent import encoding
|
||||||
from ironic_python_agent import errors
|
from ironic_python_agent import errors
|
||||||
|
@ -138,24 +138,22 @@ class APIClient(object):
|
||||||
raise errors.HeartbeatError(msg)
|
raise errors.HeartbeatError(msg)
|
||||||
|
|
||||||
def lookup_node(self, hardware_info, timeout, starting_interval,
|
def lookup_node(self, hardware_info, timeout, starting_interval,
|
||||||
node_uuid=None):
|
node_uuid=None, max_interval=30):
|
||||||
timer = loopingcall.BackOffLoopingCall(
|
retry = tenacity.retry(
|
||||||
self._do_lookup,
|
retry=tenacity.retry_if_result(lambda r: r is False),
|
||||||
hardware_info=hardware_info,
|
stop=tenacity.stop_after_delay(timeout),
|
||||||
node_uuid=node_uuid)
|
wait=tenacity.wait_random_exponential(min=starting_interval,
|
||||||
|
max=max_interval),
|
||||||
|
reraise=True)
|
||||||
try:
|
try:
|
||||||
node_content = timer.start(starting_interval=starting_interval,
|
return retry(self._do_lookup)(hardware_info=hardware_info,
|
||||||
timeout=timeout).wait()
|
node_uuid=node_uuid)
|
||||||
except loopingcall.LoopingCallTimeOut:
|
except tenacity.RetryError:
|
||||||
raise errors.LookupNodeError('Could not look up node info. Check '
|
raise errors.LookupNodeError('Could not look up node info. Check '
|
||||||
'logs for details.')
|
'logs for details.')
|
||||||
return node_content
|
|
||||||
|
|
||||||
def _do_lookup(self, hardware_info, node_uuid):
|
def _do_lookup(self, hardware_info, node_uuid):
|
||||||
"""The actual call to lookup a node.
|
"""The actual call to lookup a node."""
|
||||||
|
|
||||||
Should be called as a `loopingcall.BackOffLoopingCall`.
|
|
||||||
"""
|
|
||||||
params = {
|
params = {
|
||||||
'addresses': ','.join(iface.mac_address
|
'addresses': ','.join(iface.mac_address
|
||||||
for iface in hardware_info['interfaces']
|
for iface in hardware_info['interfaces']
|
||||||
|
@ -241,7 +239,7 @@ class APIClient(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Got valid content
|
# Got valid content
|
||||||
raise loopingcall.LoopingCallDone(retvalue=content)
|
return content
|
||||||
|
|
||||||
def _get_agent_url(self, advertise_address, advertise_protocol='http'):
|
def _get_agent_url(self, advertise_address, advertise_protocol='http'):
|
||||||
return '{}://{}:{}'.format(advertise_protocol,
|
return '{}://{}:{}'.format(advertise_protocol,
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
from oslo_service import loopingcall
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from ironic_python_agent import errors
|
from ironic_python_agent import errors
|
||||||
|
@ -244,7 +243,7 @@ class TestBaseIronicPythonAgent(base.IronicAgentTest):
|
||||||
uuid='meow',
|
uuid='meow',
|
||||||
advertise_address=('192.0.2.1', '9999'))
|
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',
|
@mock.patch('ironic_python_agent.ironic_api_client.APIClient._do_lookup',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
def test_lookup_node(self, lookup_mock, sleep_mock):
|
def test_lookup_node(self, lookup_mock, sleep_mock):
|
||||||
|
@ -256,8 +255,7 @@ class TestBaseIronicPythonAgent(base.IronicAgentTest):
|
||||||
'heartbeat_timeout': 300
|
'heartbeat_timeout': 300
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lookup_mock.side_effect = loopingcall.LoopingCallDone(
|
lookup_mock.return_value = content
|
||||||
retvalue=content)
|
|
||||||
returned_content = self.api_client.lookup_node(
|
returned_content = self.api_client.lookup_node(
|
||||||
hardware_info=self.hardware_info,
|
hardware_info=self.hardware_info,
|
||||||
timeout=300,
|
timeout=300,
|
||||||
|
@ -265,34 +263,54 @@ class TestBaseIronicPythonAgent(base.IronicAgentTest):
|
||||||
|
|
||||||
self.assertEqual(content, returned_content)
|
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',
|
@mock.patch('ironic_python_agent.ironic_api_client.APIClient._do_lookup',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
def test_lookup_timeout(self, lookup_mock, sleep_mock):
|
def test_lookup_node_retries(self, lookup_mock, sleep_mock):
|
||||||
lookup_mock.side_effect = loopingcall.LoopingCallTimeOut()
|
content = {
|
||||||
self.assertRaises(errors.LookupNodeError,
|
|
||||||
self.api_client.lookup_node,
|
|
||||||
hardware_info=self.hardware_info,
|
|
||||||
timeout=300,
|
|
||||||
starting_interval=1)
|
|
||||||
|
|
||||||
def test_do_lookup(self):
|
|
||||||
response = FakeResponse(status_code=200, content={
|
|
||||||
'node': {
|
'node': {
|
||||||
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
|
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
|
||||||
},
|
},
|
||||||
'config': {
|
'config': {
|
||||||
'heartbeat_timeout': 300
|
'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.return_value = False
|
||||||
|
self.assertRaises(errors.LookupNodeError,
|
||||||
|
self.api_client.lookup_node,
|
||||||
|
hardware_info=self.hardware_info,
|
||||||
|
timeout=0.1,
|
||||||
|
starting_interval=0.001)
|
||||||
|
|
||||||
|
def test_do_lookup(self):
|
||||||
|
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 = mock.Mock()
|
||||||
self.api_client.session.request.return_value = response
|
self.api_client.session.request.return_value = response
|
||||||
|
|
||||||
self.assertRaises(loopingcall.LoopingCallDone,
|
self.assertEqual(content, self.api_client._do_lookup(
|
||||||
self.api_client._do_lookup,
|
hardware_info=self.hardware_info,
|
||||||
hardware_info=self.hardware_info,
|
node_uuid=None))
|
||||||
node_uuid=None)
|
|
||||||
|
|
||||||
url = '{api_url}v1/lookup'.format(api_url=API_URL)
|
url = '{api_url}v1/lookup'.format(api_url=API_URL)
|
||||||
request_args = self.api_client.session.request.call_args[0]
|
request_args = self.api_client.session.request.call_args[0]
|
||||||
|
@ -303,22 +321,22 @@ class TestBaseIronicPythonAgent(base.IronicAgentTest):
|
||||||
params)
|
params)
|
||||||
|
|
||||||
def test_do_lookup_with_uuid(self):
|
def test_do_lookup_with_uuid(self):
|
||||||
response = FakeResponse(status_code=200, content={
|
content = {
|
||||||
'node': {
|
'node': {
|
||||||
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
|
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
|
||||||
},
|
},
|
||||||
'config': {
|
'config': {
|
||||||
'heartbeat_timeout': 300
|
'heartbeat_timeout': 300
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
response = FakeResponse(status_code=200, content=content)
|
||||||
|
|
||||||
self.api_client.session.request = mock.Mock()
|
self.api_client.session.request = mock.Mock()
|
||||||
self.api_client.session.request.return_value = response
|
self.api_client.session.request.return_value = response
|
||||||
|
|
||||||
self.assertRaises(loopingcall.LoopingCallDone,
|
self.assertEqual(content, self.api_client._do_lookup(
|
||||||
self.api_client._do_lookup,
|
hardware_info=self.hardware_info,
|
||||||
hardware_info=self.hardware_info,
|
node_uuid='someuuid'))
|
||||||
node_uuid='someuuid')
|
|
||||||
|
|
||||||
url = '{api_url}v1/lookup'.format(api_url=API_URL)
|
url = '{api_url}v1/lookup'.format(api_url=API_URL)
|
||||||
request_args = self.api_client.session.request.call_args[0]
|
request_args = self.api_client.session.request.call_args[0]
|
||||||
|
|
|
@ -78,6 +78,7 @@ Sphinx==2.0.0
|
||||||
sphinxcontrib-websupport==1.0.1
|
sphinxcontrib-websupport==1.0.1
|
||||||
stestr==1.0.0
|
stestr==1.0.0
|
||||||
stevedore==1.20.0
|
stevedore==1.20.0
|
||||||
|
tenacity==6.2.0
|
||||||
testrepository==0.0.20
|
testrepository==0.0.20
|
||||||
testtools==2.2.0
|
testtools==2.2.0
|
||||||
traceback2==1.4.0
|
traceback2==1.4.0
|
||||||
|
|
|
@ -16,5 +16,6 @@ pyudev>=0.18 # LGPLv2.1+
|
||||||
requests>=2.14.2 # Apache-2.0
|
requests>=2.14.2 # Apache-2.0
|
||||||
rtslib-fb>=2.1.65 # Apache-2.0
|
rtslib-fb>=2.1.65 # Apache-2.0
|
||||||
stevedore>=1.20.0 # 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
|
ironic-lib>=4.1.0 # Apache-2.0
|
||||||
Werkzeug>=1.0.1 # BSD License
|
Werkzeug>=1.0.1 # BSD License
|
||||||
|
|
Loading…
Reference in New Issue