summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ironic/common/glance_service/image_service.py3
-rw-r--r--ironic/common/utils.py15
-rw-r--r--ironic/conf/glance.py1
-rw-r--r--ironic/tests/unit/common/test_glance_service.py27
4 files changed, 30 insertions, 16 deletions
diff --git a/ironic/common/glance_service/image_service.py b/ironic/common/glance_service/image_service.py
index 0a32eaf0a..1d9d6d4bc 100644
--- a/ironic/common/glance_service/image_service.py
+++ b/ironic/common/glance_service/image_service.py
@@ -33,6 +33,7 @@ from ironic.common.glance_service import service_utils
from ironic.common.i18n import _
from ironic.common import keystone
from ironic.common import swift
+from ironic.common import utils
from ironic.conf import CONF
TempUrlCacheElement = collections.namedtuple('TempUrlCacheElement',
@@ -114,7 +115,7 @@ class GlanceImageService(object):
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
exception.GlanceConnectionFailed),
- stop=tenacity.stop_after_attempt(CONF.glance.num_retries + 1),
+ stop=utils.stop_after_retries('num_retries', group='glance'),
wait=tenacity.wait_fixed(1),
reraise=True
)
diff --git a/ironic/common/utils.py b/ironic/common/utils.py
index e4d83c9b6..9ae88d4d6 100644
--- a/ironic/common/utils.py
+++ b/ironic/common/utils.py
@@ -681,3 +681,18 @@ def is_fips_enabled():
except Exception:
pass
return False
+
+
+def stop_after_retries(option, group=None):
+ """A tenacity retry helper that stops after retries specified in conf."""
+ # NOTE(dtantsur): fetch the option inside of the nested call, otherwise it
+ # cannot be changed in runtime.
+ def should_stop(retry_state):
+ if group:
+ conf = getattr(CONF, group)
+ else:
+ conf = CONF
+ num_retries = getattr(conf, option)
+ return retry_state.attempt_number >= num_retries + 1
+
+ return should_stop
diff --git a/ironic/conf/glance.py b/ironic/conf/glance.py
index a3286b1eb..317f213bc 100644
--- a/ironic/conf/glance.py
+++ b/ironic/conf/glance.py
@@ -114,6 +114,7 @@ opts = [
'will determine how many containers are created.')),
cfg.IntOpt('num_retries',
default=0,
+ mutable=True,
help=_('Number of retries when downloading an image from '
'glance.')),
]
diff --git a/ironic/tests/unit/common/test_glance_service.py b/ironic/tests/unit/common/test_glance_service.py
index 327125a81..f9e713e91 100644
--- a/ironic/tests/unit/common/test_glance_service.py
+++ b/ironic/tests/unit/common/test_glance_service.py
@@ -24,7 +24,6 @@ from glanceclient import exc as glance_exc
from keystoneauth1 import loading as ks_loading
from oslo_config import cfg
from oslo_utils import uuidutils
-import tenacity
import testtools
from ironic.common import context
@@ -202,20 +201,18 @@ class TestGlanceImageService(base.TestCase):
image_id = uuidutils.generate_uuid()
writer = NullWriter()
- with mock.patch.object(tenacity, 'retry', autospec=True) as mock_retry:
- # When retries are disabled, we should get an exception
- self.config(num_retries=0, group='glance')
- self.assertRaises(exception.GlanceConnectionFailed,
- stub_service.download, image_id, writer)
-
- # Now lets enable retries. No exception should happen now.
- self.config(num_retries=1, group='glance')
- importlib.reload(image_service)
- stub_service = image_service.GlanceImageService(stub_client,
- stub_context)
- tries = [0]
- stub_service.download(image_id, writer)
- mock_retry.assert_called_once()
+ # When retries are disabled, we should get an exception
+ self.config(num_retries=0, group='glance')
+ self.assertRaises(exception.GlanceConnectionFailed,
+ stub_service.download, image_id, writer)
+
+ # Now lets enable retries. No exception should happen now.
+ self.config(num_retries=1, group='glance')
+ importlib.reload(image_service)
+ stub_service = image_service.GlanceImageService(stub_client,
+ stub_context)
+ tries = [0]
+ stub_service.download(image_id, writer)
def test_download_no_data(self):
self.client.fake_wrapped = None