diff --git a/nova/api/metadata/vendordata_dynamic.py b/nova/api/metadata/vendordata_dynamic.py index 5f979e4e0f1c..4f4b52144593 100644 --- a/nova/api/metadata/vendordata_dynamic.py +++ b/nova/api/metadata/vendordata_dynamic.py @@ -16,6 +16,8 @@ """Render vendordata as stored fetched from REST microservices.""" import requests +import six +import sys from keystoneauth1 import exceptions as ks_exceptions from keystoneauth1 import loading as ks_loading @@ -111,6 +113,9 @@ class DynamicVendorData(vendordata.VendorDataDriver): 'url': url, 'error': e}, instance=self.instance) + if CONF.api.vendordata_dynamic_failure_fatal: + six.reraise(type(e), e, sys.exc_info()[2]) + return {} def get(self): diff --git a/nova/conf/api.py b/nova/conf/api.py index 64efdd42f13f..0f4276d36d65 100644 --- a/nova/conf/api.py +++ b/nova/conf/api.py @@ -103,6 +103,7 @@ Related options: * vendordata_dynamic_ssl_certfile * vendordata_dynamic_connect_timeout * vendordata_dynamic_read_timeout +* vendordata_dynamic_failure_fatal """), cfg.ListOpt('vendordata_dynamic_targets', default=[], @@ -132,6 +133,7 @@ Related options: * vendordata_dynamic_targets * vendordata_dynamic_connect_timeout * vendordata_dynamic_read_timeout +* vendordata_dynamic_failure_fatal """), cfg.IntOpt('vendordata_dynamic_connect_timeout', default=5, @@ -152,6 +154,7 @@ Related options: * vendordata_dynamic_targets * vendordata_dynamic_ssl_certfile * vendordata_dynamic_read_timeout +* vendordata_dynamic_failure_fatal """), cfg.IntOpt('vendordata_dynamic_read_timeout', default=5, @@ -171,6 +174,20 @@ Related options: * vendordata_dynamic_targets * vendordata_dynamic_ssl_certfile * vendordata_dynamic_connect_timeout +* vendordata_dynamic_failure_fatal +"""), + cfg.BoolOpt('vendordata_dynamic_failure_fatal', + default=False, + help=""" +Should failures to fetch dynamic vendordata be fatal to instance boot? + +Related options: + +* vendordata_providers +* vendordata_dynamic_targets +* vendordata_dynamic_ssl_certfile +* vendordata_dynamic_connect_timeout +* vendordata_dynamic_read_timeout """), cfg.IntOpt("metadata_cache_expiration", default=15, diff --git a/nova/tests/unit/test_metadata.py b/nova/tests/unit/test_metadata.py index c25593ee6f50..fb4ab713a7b0 100644 --- a/nova/tests/unit/test_metadata.py +++ b/nova/tests/unit/test_metadata.py @@ -949,6 +949,16 @@ class OpenStackMetadataTestCase(test.TestCase): self._test_vendordata2_response_inner_exceptional( request_mock, log_mock, ks_exceptions.SSLError) + @mock.patch.object(vendordata_dynamic.LOG, 'warning') + @mock.patch.object(session.Session, 'request') + def test_vendor_data_response_vendordata2_ssl_error_fatal(self, + request_mock, + log_mock): + self.flags(vendordata_dynamic_failure_fatal=True, group='api') + self.assertRaises(ks_exceptions.SSLError, + self._test_vendordata2_response_inner_exceptional, + request_mock, log_mock, ks_exceptions.SSLError) + def test_network_data_presence(self): inst = self.instance.obj_clone() mdinst = fake_InstanceMetadata(self, inst) diff --git a/releasenotes/notes/vendordata-reboot-hard-failure-42beeb1044680a50.yaml b/releasenotes/notes/vendordata-reboot-hard-failure-42beeb1044680a50.yaml new file mode 100644 index 000000000000..79b06dddabd5 --- /dev/null +++ b/releasenotes/notes/vendordata-reboot-hard-failure-42beeb1044680a50.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + The vendordata metadata system now supports a hard failure mode. This can + be enabled using the ``api.vendordata_dynamic_failure_fatal`` configuration + option. When enabled, an instance will fail to start if the instance + cannot fetch dynamic vendordata.