Merge "Update wait_for_cloud_init_status function"

This commit is contained in:
Zuul 2021-12-14 15:31:21 +00:00 committed by Gerrit Code Review
commit 4868078e14
1 changed files with 51 additions and 59 deletions

View File

@ -14,7 +14,6 @@
from __future__ import absolute_import
import collections
import contextlib
import typing
from oslo_log import log
@ -187,76 +186,69 @@ def wait_for_cloud_init_status(
timeout: tobiko.Seconds = None,
sleep_interval: tobiko.Seconds = None) \
-> str:
hostname = getattr(ssh_client, 'hostname', None)
hostname = sh.get_hostname(ssh_client=ssh_client,
timeout=timeout)
if transient_states is None:
transient_states = list()
for status in expected_states:
transient_states += CLOUD_INIT_TRANSIENT_STATES.get(status, [])
with open_output_file(filename=CLOUD_INIT_LOG_FILE,
timeout=timeout,
ssh_client=ssh_client) as log_file, \
open_output_file(filename=CLOUD_INIT_OUTPUT_FILE,
timeout=timeout,
ssh_client=ssh_client) as output_file:
for attempt in tobiko.retry(timeout=timeout,
interval=sleep_interval,
default_timeout=1200.,
default_interval=5.):
actual_status = get_cloud_init_status(ssh_client=ssh_client,
timeout=attempt.time_left)
if actual_status in expected_states:
return actual_status
def _read_file(filename: str, tail=False) -> str:
return read_file(filename=filename,
ssh_client=ssh_client,
timeout=timeout,
tail=tail)
log_file.readall()
output_file.readall()
if actual_status not in transient_states:
raise InvalidCloudInitStatusError(
hostname=hostname,
actual_status=actual_status,
expected_states=expected_states,
log_file=str(log_file),
output_file=str(output_file))
for attempt in tobiko.retry(timeout=timeout,
interval=sleep_interval,
default_timeout=1200.,
default_interval=5.):
actual_status = get_cloud_init_status(ssh_client=ssh_client,
timeout=attempt.time_left)
if actual_status in expected_states:
break
try:
attempt.check_limits()
except tobiko.RetryTimeLimitError as ex:
raise WaitForCloudInitTimeoutError(
timeout=attempt.timeout,
hostname=hostname,
actual_status=actual_status,
expected_states=expected_states,
log_file=str(log_file),
output_file=str(output_file)) from ex
if attempt.is_last:
raise WaitForCloudInitTimeoutError(
timeout=attempt.timeout,
hostname=hostname,
actual_status=actual_status,
expected_states=expected_states,
log_file=_read_file(CLOUD_INIT_LOG_FILE),
output_file=_read_file(CLOUD_INIT_OUTPUT_FILE))
# show only the last log line
try:
last_log_line = str(log_file).splitlines()[-1]
except IndexError:
last_log_line = ""
elif actual_status in transient_states:
last_log_lines = _read_file(CLOUD_INIT_LOG_FILE, tail=True)
LOG.debug(f"Waiting cloud-init status on host '{hostname}' to "
f"switch from '{actual_status}' to any of expected "
f"states ({', '.join(expected_states)}):\n\n"
f"--- {CLOUD_INIT_LOG_FILE} ---\n"
f"{last_log_line}\n\n")
f"{last_log_lines}\n\n")
else:
raise InvalidCloudInitStatusError(
hostname=hostname,
actual_status=actual_status,
expected_states=expected_states,
log_file=_read_file(CLOUD_INIT_LOG_FILE),
output_file=_read_file(CLOUD_INIT_OUTPUT_FILE))
raise RuntimeError("Retry loop ended himself")
else:
raise RuntimeError('Broken retry loop')
return actual_status
@contextlib.contextmanager
def open_output_file(filename: str = CLOUD_INIT_OUTPUT_FILE,
tail=False,
follow=False,
**process_params) \
-> typing.Generator[sh.ShellStdout, None, None]:
command = ['tail']
if not tail:
# Start from the begin of the file
command += ['-c', '+0']
if follow:
command += ['-F']
command += [filename]
process = sh.process(command, **process_params)
with process:
yield process.stdout
def read_file(filename: str,
tail=False,
ssh_client: ssh.SSHClientType = None,
timeout: tobiko.Seconds = None):
if tail:
command = 'tail'
else:
command = 'cat'
try:
return sh.execute(f'{command} "{filename}"',
timeout=timeout,
ssh_client=ssh_client).stdout
except sh.ShellCommandFailed:
LOG.exception(f"Error reading file '{filename}'")
return ""