Merge "Retry user load profile on Windows"

This commit is contained in:
Zuul 2022-12-07 15:17:29 +00:00 committed by Gerrit Code Review
commit 9198d0ba38
4 changed files with 32 additions and 7 deletions

View File

@ -71,3 +71,14 @@ class WindowsCloudbaseInitException(CloudbaseInitException):
except TypeError:
formatted_msg = msg
super(WindowsCloudbaseInitException, self).__init__(formatted_msg)
class LoadUserProfileCloudbaseInitException(WindowsCloudbaseInitException):
"""Windows cannot load the newly created user profile.
The load user profile can fail if the Windows subsystems responsible for
the action are not ready. This usually happens on laggy systems and should
be retried.
"""
pass

View File

@ -642,6 +642,9 @@ class WindowsUtils(base.BaseOSUtils):
# User not found
pass
@retry_decorator.retry_decorator(
max_retry_count=3,
exceptions=exception.LoadUserProfileCloudbaseInitException)
def create_user_logon_session(self, username, password, domain='.',
load_profile=True,
logon_type=LOGON32_LOGON_INTERACTIVE):
@ -666,7 +669,7 @@ class WindowsUtils(base.BaseOSUtils):
ret_val = userenv.LoadUserProfileW(token, ctypes.byref(pi))
if not ret_val:
kernel32.CloseHandle(token)
raise exception.WindowsCloudbaseInitException(
raise exception.LoadUserProfileCloudbaseInitException(
"Cannot load user profile: %r")
return token

View File

@ -452,7 +452,9 @@ class TestWindowsUtils(testutils.CloudbaseInitTestBase):
self._test_create_user(fail=True)
@mock.patch('cloudbaseinit.osutils.windows.Win32_PROFILEINFO')
def _test_create_user_logon_session(self, mock_Win32_PROFILEINFO, logon,
@mock.patch('time.sleep')
def _test_create_user_logon_session(self, mock_time_sleep,
mock_Win32_PROFILEINFO, logon,
loaduser, load_profile=True,
last_error=None):
self._wintypes_mock.HANDLE = mock.MagicMock()
@ -474,7 +476,9 @@ class TestWindowsUtils(testutils.CloudbaseInitTestBase):
userenv.LoadUserProfileW.return_value = None
kernel32.CloseHandle.return_value = None
with self.assert_raises_windows_message(
"Cannot load user profile: %r", last_error):
"Cannot load user profile: %r", last_error,
get_last_error_called_times=4,
format_error_called_times=4):
self._winutils.create_user_logon_session(
self._USERNAME, self._PASSWORD, domain='.',
load_profile=load_profile)

View File

@ -159,7 +159,9 @@ class CloudbaseInitTestBase(unittest.TestCase):
@contextlib.contextmanager
def assert_raises_windows_message(
self, expected_msg, error_code,
exc=exception.WindowsCloudbaseInitException):
exc=exception.WindowsCloudbaseInitException,
get_last_error_called_times=1,
format_error_called_times=1):
"""Helper method for testing raised error messages
This assert method is similar to :meth:`~assertRaises`, but
@ -188,11 +190,16 @@ class CloudbaseInitTestBase(unittest.TestCase):
# This can be called when the error code is not given,
# but we don't have control over that, so test that
# it's actually called only once.
mock_get_last_error.assert_called_once_with()
mock_format_error.assert_called_once_with(
mock_get_last_error.assert_called()
self.assertEqual(mock_get_last_error.call_count,
get_last_error_called_times)
mock_format_error.assert_called_with(
mock_get_last_error.return_value)
else:
mock_format_error.assert_called_once_with(error_code)
mock_format_error.assert_called_with(error_code)
self.assertEqual(mock_format_error.call_count,
format_error_called_times)
expected_msg = expected_msg % mock_format_error.return_value
self.assertEqual(expected_msg, cm.exception.args[0])