Add reporting provisioning status to the metadata service
Add support for reporting the provisioning status to the metadata service. The following config options have been added: - metadata_report_provisioning_started: Reports to the metadata service that provisioning has started type=bool, default=False - metadata_report_provisioning_completed: Reports to the metadata service that provisioning completed or failed type=bool, default=False Change-Id: I23a5a8e5473dd103ce5e0acd0c4647cdec86f97f Implements: blueprint add-reporting-provisioning-status-to-metadata-service Co-Authored-By: Paula Madalina Crismaru <pcrismaru@cloudbasesolutions.com>
This commit is contained in:
parent
18f4b25972
commit
834f19058c
@ -271,6 +271,14 @@ class GlobalOptions(conf_base.Options):
|
||||
'enable_automatic_updates', default=None,
|
||||
help='If set, enables or disables automatic operating '
|
||||
'system updates.'),
|
||||
cfg.BoolOpt(
|
||||
'metadata_report_provisioning_started', default=False,
|
||||
help='Reports to the metadata service that provisioning has '
|
||||
'started'),
|
||||
cfg.BoolOpt(
|
||||
'metadata_report_provisioning_completed', default=False,
|
||||
help='Reports to the metadata service that provisioning '
|
||||
'completed successfully or failed'),
|
||||
]
|
||||
|
||||
self._cli_options = [
|
||||
|
@ -52,6 +52,8 @@ class InitManager(object):
|
||||
def _exec_plugin(self, osutils, service, plugin, instance_id, shared_data):
|
||||
plugin_name = plugin.get_name()
|
||||
|
||||
reboot_required = None
|
||||
success = True
|
||||
status = None
|
||||
if instance_id is not None:
|
||||
status = self._get_plugin_status(osutils, instance_id, plugin_name)
|
||||
@ -66,11 +68,12 @@ class InitManager(object):
|
||||
if instance_id is not None:
|
||||
self._set_plugin_status(osutils, instance_id, plugin_name,
|
||||
status)
|
||||
return reboot_required
|
||||
except Exception as ex:
|
||||
LOG.error('plugin \'%(plugin_name)s\' failed with error '
|
||||
'\'%(ex)s\'', {'plugin_name': plugin_name, 'ex': ex})
|
||||
LOG.exception(ex)
|
||||
success = False
|
||||
return success, reboot_required
|
||||
|
||||
def _check_plugin_os_requirements(self, osutils, plugin):
|
||||
supported = False
|
||||
@ -102,19 +105,22 @@ class InitManager(object):
|
||||
def _handle_plugins_stage(self, osutils, service, instance_id, stage):
|
||||
plugins_shared_data = {}
|
||||
reboot_required = False
|
||||
stage_success = True
|
||||
plugins = plugins_factory.load_plugins(stage)
|
||||
|
||||
LOG.info('Executing plugins for stage %r:', stage)
|
||||
|
||||
for plugin in plugins:
|
||||
if self._check_plugin_os_requirements(osutils, plugin):
|
||||
if self._exec_plugin(osutils, service, plugin,
|
||||
instance_id, plugins_shared_data):
|
||||
reboot_required = True
|
||||
if CONF.allow_reboot:
|
||||
success, reboot_required = self._exec_plugin(
|
||||
osutils, service, plugin, instance_id,
|
||||
plugins_shared_data)
|
||||
if not success:
|
||||
stage_success = False
|
||||
if reboot_required and CONF.allow_reboot:
|
||||
break
|
||||
|
||||
return reboot_required
|
||||
return stage_success, reboot_required
|
||||
|
||||
@staticmethod
|
||||
def _reset_service_password_and_respawn(osutils):
|
||||
@ -168,14 +174,14 @@ class InitManager(object):
|
||||
LOG.info('Cloudbase-Init version: %s', version.get_version())
|
||||
osutils.wait_for_boot_completion()
|
||||
|
||||
reboot_required = self._handle_plugins_stage(
|
||||
stage_success, reboot_required = self._handle_plugins_stage(
|
||||
osutils, None, None,
|
||||
plugins_base.PLUGIN_STAGE_PRE_NETWORKING)
|
||||
|
||||
self._check_latest_version()
|
||||
|
||||
if not (reboot_required and CONF.allow_reboot):
|
||||
reboot_required = self._handle_plugins_stage(
|
||||
stage_success, reboot_required = self._handle_plugins_stage(
|
||||
osutils, None, None,
|
||||
plugins_base.PLUGIN_STAGE_PRE_METADATA_DISCOVERY)
|
||||
|
||||
@ -188,16 +194,28 @@ class InitManager(object):
|
||||
LOG.info('Metadata service loaded: \'%s\'' %
|
||||
service.get_name())
|
||||
|
||||
if CONF.metadata_report_provisioning_started:
|
||||
LOG.info("Reporting provisioning started")
|
||||
service.provisioning_started()
|
||||
|
||||
instance_id = service.get_instance_id()
|
||||
LOG.debug('Instance id: %s', instance_id)
|
||||
|
||||
try:
|
||||
reboot_required = self._handle_plugins_stage(
|
||||
stage_success, reboot_required = self._handle_plugins_stage(
|
||||
osutils, service, instance_id,
|
||||
plugins_base.PLUGIN_STAGE_MAIN)
|
||||
finally:
|
||||
service.cleanup()
|
||||
|
||||
if (CONF.metadata_report_provisioning_completed and
|
||||
not stage_success):
|
||||
try:
|
||||
LOG.info("Reporting provisioning failed")
|
||||
service.provisioning_failed()
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
||||
if reboot_required and CONF.allow_reboot:
|
||||
try:
|
||||
LOG.info("Rebooting")
|
||||
@ -206,6 +224,15 @@ class InitManager(object):
|
||||
LOG.error('reboot failed with error \'%s\'' % ex)
|
||||
else:
|
||||
LOG.info("Plugins execution done")
|
||||
|
||||
if (service and CONF.metadata_report_provisioning_completed and
|
||||
stage_success):
|
||||
try:
|
||||
LOG.info("Reporting provisioning completed")
|
||||
service.provisioning_completed()
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
||||
if CONF.stop_service_on_exit:
|
||||
LOG.info("Stopping Cloudbase-Init service")
|
||||
osutils.terminate()
|
||||
|
@ -189,6 +189,15 @@ class BaseMetadataService(object):
|
||||
"""
|
||||
return False
|
||||
|
||||
def provisioning_started(self):
|
||||
pass
|
||||
|
||||
def provisioning_completed(self):
|
||||
pass
|
||||
|
||||
def provisioning_failed(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def can_post_rdp_cert_thumbprint(self):
|
||||
return False
|
||||
|
@ -186,12 +186,13 @@ class TestInitManager(unittest.TestCase):
|
||||
def _test_handle_plugins_stage(self, mock_load_plugins,
|
||||
mock_check_plugin_os_requirements,
|
||||
mock_exec_plugin,
|
||||
reboot=True, fast_reboot=True):
|
||||
reboot=True, fast_reboot=True,
|
||||
success=True):
|
||||
stage = "fake stage"
|
||||
service, instance_id = mock.Mock(), mock.Mock()
|
||||
plugins = [mock.Mock() for _ in range(3)]
|
||||
mock_check_plugin_os_requirements.return_value = True
|
||||
mock_exec_plugin.return_value = reboot
|
||||
mock_exec_plugin.return_value = success, reboot
|
||||
mock_load_plugins.return_value = plugins
|
||||
requirements_calls = [mock.call(self.osutils, plugin)
|
||||
for plugin in plugins]
|
||||
@ -210,7 +211,7 @@ class TestInitManager(unittest.TestCase):
|
||||
mock_check_plugin_os_requirements.assert_has_calls(
|
||||
requirements_calls[:idx])
|
||||
mock_exec_plugin.assert_has_calls(exec_plugin_calls[:idx])
|
||||
self.assertEqual(reboot, response)
|
||||
self.assertEqual((success, reboot), response)
|
||||
|
||||
def test_handle_plugins_stage(self):
|
||||
self._test_handle_plugins_stage()
|
||||
@ -222,6 +223,9 @@ class TestInitManager(unittest.TestCase):
|
||||
def test_handle_plugins_stage_no_fast_reboot(self):
|
||||
self._test_handle_plugins_stage(fast_reboot=False)
|
||||
|
||||
def test_handle_plugins_stage_stage_fails(self):
|
||||
self._test_handle_plugins_stage(success=False)
|
||||
|
||||
@mock.patch('cloudbaseinit.init.InitManager.'
|
||||
'_reset_service_password_and_respawn')
|
||||
@mock.patch('cloudbaseinit.init.InitManager'
|
||||
@ -236,7 +240,8 @@ class TestInitManager(unittest.TestCase):
|
||||
mock_get_version, mock_check_latest_version,
|
||||
mock_handle_plugins_stage, mock_reset_service,
|
||||
expected_logging,
|
||||
version, name, instance_id, reboot=True):
|
||||
version, name, instance_id, reboot=True,
|
||||
last_stage=False):
|
||||
sys.platform = 'win32'
|
||||
mock_get_version.return_value = version
|
||||
fake_service = mock.MagicMock()
|
||||
@ -246,7 +251,8 @@ class TestInitManager(unittest.TestCase):
|
||||
mock_get_metadata_service.return_value = fake_service
|
||||
fake_service.get_name.return_value = name
|
||||
fake_service.get_instance_id.return_value = instance_id
|
||||
mock_handle_plugins_stage.side_effect = [False, False, True]
|
||||
mock_handle_plugins_stage.side_effect = [(True, False), (True, False),
|
||||
(last_stage, True)]
|
||||
stages = [
|
||||
base.PLUGIN_STAGE_PRE_NETWORKING,
|
||||
base.PLUGIN_STAGE_PRE_METADATA_DISCOVERY,
|
||||
@ -256,13 +262,14 @@ class TestInitManager(unittest.TestCase):
|
||||
stage_calls_list[2][1] = fake_service
|
||||
stage_calls_list[2][2] = instance_id
|
||||
stage_calls = [mock.call(*args) for args in stage_calls_list]
|
||||
|
||||
with testutils.LogSnatcher('cloudbaseinit.init') as snatcher:
|
||||
self._init.configure_host()
|
||||
self.assertEqual(expected_logging, snatcher.output)
|
||||
mock_check_latest_version.assert_called_once_with()
|
||||
if CONF.reset_service_password:
|
||||
mock_reset_service.assert_called_once_with(self.osutils)
|
||||
if last_stage:
|
||||
fake_service.provisioning_completed.assert_called_once_with()
|
||||
|
||||
self.osutils.wait_for_boot_completion.assert_called_once_with()
|
||||
mock_get_metadata_service.assert_called_once_with()
|
||||
@ -275,7 +282,8 @@ class TestInitManager(unittest.TestCase):
|
||||
else:
|
||||
self.assertFalse(self.osutils.reboot.called)
|
||||
|
||||
def _test_configure_host_with_logging(self, extra_logging, reboot=True):
|
||||
def _test_configure_host_with_logging(self, extra_logging, reboot=True,
|
||||
last_stage=False):
|
||||
instance_id = 'fake id'
|
||||
name = 'fake name'
|
||||
version = 'version'
|
||||
@ -284,17 +292,23 @@ class TestInitManager(unittest.TestCase):
|
||||
'Metadata service loaded: %r' % name,
|
||||
'Instance id: %s' % instance_id,
|
||||
]
|
||||
if CONF.metadata_report_provisioning_started:
|
||||
expected_logging.insert(2, 'Reporting provisioning started')
|
||||
|
||||
self._test_configure_host(
|
||||
expected_logging=expected_logging + extra_logging,
|
||||
version=version, name=name, instance_id=instance_id,
|
||||
reboot=reboot)
|
||||
reboot=reboot, last_stage=last_stage)
|
||||
|
||||
@testutils.ConfPatcher('metadata_report_provisioning_completed', True)
|
||||
@testutils.ConfPatcher('allow_reboot', False)
|
||||
@testutils.ConfPatcher('stop_service_on_exit', False)
|
||||
def test_configure_host_no_reboot_no_service_stopping(self):
|
||||
def test_configure_host_no_reboot_no_service_stopping_reporting_done(self):
|
||||
self._test_configure_host_with_logging(
|
||||
reboot=False,
|
||||
extra_logging=['Plugins execution done'])
|
||||
extra_logging=['Plugins execution done',
|
||||
'Reporting provisioning completed'],
|
||||
last_stage=True)
|
||||
|
||||
@testutils.ConfPatcher('allow_reboot', False)
|
||||
@testutils.ConfPatcher('stop_service_on_exit', True)
|
||||
@ -305,10 +319,11 @@ class TestInitManager(unittest.TestCase):
|
||||
'Stopping Cloudbase-Init service'])
|
||||
self.osutils.terminate.assert_called_once_with()
|
||||
|
||||
@testutils.ConfPatcher('metadata_report_provisioning_completed', True)
|
||||
@testutils.ConfPatcher('allow_reboot', True)
|
||||
def test_configure_host_reboot(self):
|
||||
def test_configure_host_reboot_reporting_started_and_failed(self):
|
||||
self._test_configure_host_with_logging(
|
||||
extra_logging=['Rebooting'])
|
||||
extra_logging=['Reporting provisioning failed', 'Rebooting'])
|
||||
|
||||
@testutils.ConfPatcher('check_latest_version', False)
|
||||
@mock.patch('cloudbaseinit.version.check_latest_version')
|
||||
|
Loading…
x
Reference in New Issue
Block a user