Skip to content

Commit e4ac9e7

Browse files
committed
Handle guest logs
Fetch log content,save it to provided location or current dir
1 parent 9519817 commit e4ac9e7

File tree

8 files changed

+72
-0
lines changed

8 files changed

+72
-0
lines changed

tmt/steps/finish/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ def go(self, force: bool = False) -> None:
189189

190190
# Stop and remove provisioned guests
191191
for guest in self.plan.provision.guests():
192+
guest.handle_guest_logs(logs=guest.logs)
192193
guest.stop()
193194
guest.remove()
194195

tmt/steps/provision/__init__.py

+41
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,11 @@ def is_ready(self) -> bool:
625625

626626
raise NotImplementedError
627627

628+
@property
629+
def logs(self) -> list[str]:
630+
631+
raise NotImplementedError
632+
628633
@classmethod
629634
def options(cls, how: Optional[str] = None) -> list[tmt.options.ClickOptionDecoratorType]:
630635
""" Prepare command line options related to guests """
@@ -1103,6 +1108,42 @@ def requires(cls) -> list['tmt.base.Dependency']:
11031108
""" All requirements of the guest implementation """
11041109
return []
11051110

1111+
def acquire_log(self, log_name: str) -> Optional[str]:
1112+
"""fetch and return content of a requested log"""
1113+
raise NotImplementedError
1114+
1115+
def store_log(
1116+
self,
1117+
log_path: Path,
1118+
log_content: str,
1119+
log_name: Optional[str] = None) -> None:
1120+
"""save log content and return the path"""
1121+
if log_name:
1122+
# if log_path contains log file name
1123+
if log_path.is_dir():
1124+
log_path.write_text(log_content)
1125+
else:
1126+
(log_path / log_name).write_text(log_content)
1127+
else:
1128+
log_path.write_text(log_content)
1129+
1130+
def handle_guest_logs(self,
1131+
log_path: Optional[Path] = None,
1132+
logs: Optional[list[str]] = None) -> None:
1133+
"""get log content and save it to the workdir/provision/,
1134+
list the log dir in guests.yaml"""
1135+
logs = logs or []
1136+
log_path = log_path or self.workdir
1137+
for log_name in logs:
1138+
log_content = self.acquire_log(log_name)
1139+
if log_content:
1140+
if log_path:
1141+
self.store_log(log_path, log_content, log_name)
1142+
else:
1143+
self.store_log(Path.cwd(), log_content, log_name)
1144+
else:
1145+
self.debug(f'no content in {log_name}')
1146+
11061147

11071148
@dataclasses.dataclass
11081149
class GuestSshData(GuestData):

tmt/steps/provision/artemis.py

+4
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,10 @@ def is_ready(self) -> bool:
496496
# return True if self.guest is not None
497497
return self.guest is not None
498498

499+
@property
500+
def logs(self) -> list[str]:
501+
return []
502+
499503
def _create(self) -> None:
500504
environment: dict[str, Any] = {
501505
'hw': {

tmt/steps/provision/connect.py

+4
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ class GuestConnect(tmt.steps.provision.GuestSsh):
6969
soft_reboot: Optional[ShellScript]
7070
hard_reboot: Optional[ShellScript]
7171

72+
@property
73+
def logs(self) -> list[str]:
74+
return []
75+
7276
def reboot(
7377
self,
7478
hard: bool = False,

tmt/steps/provision/local.py

+10
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ def is_ready(self) -> bool:
2626
""" Local is always ready """
2727
return True
2828

29+
@property
30+
def logs(self) -> list[str]:
31+
return ['dmesg']
32+
2933
def _run_ansible(
3034
self,
3135
playbook: Path,
@@ -133,6 +137,12 @@ def pull(
133137
extend_options: Optional[list[str]] = None) -> None:
134138
""" Nothing to be done to pull workdir """
135139

140+
def acquire_log(self, log_name: str) -> Optional[str]:
141+
"""fetch and return content of a requested log"""
142+
if log_name == 'dmesg':
143+
return self.execute(Command('dmesg')).stdout
144+
return None
145+
136146

137147
@tmt.steps.provides_method('local')
138148
class ProvisionLocal(tmt.steps.provision.ProvisionPlugin[ProvisionLocalData]):

tmt/steps/provision/mrack.py

+4
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,10 @@ def is_ready(self) -> bool:
604604
except mrack.errors.MrackError:
605605
return False
606606

607+
@property
608+
def logs(self) -> list[str]:
609+
return []
610+
607611
def _create(self, tmt_name: str) -> None:
608612
""" Create beaker job xml request and submit it to Beaker hub """
609613

tmt/steps/provision/podman.py

+4
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ def is_ready(self) -> bool:
113113
))
114114
return str(cmd_output.stdout).strip() == 'true'
115115

116+
@property
117+
def logs(self) -> list[str]:
118+
return []
119+
116120
def wake(self) -> None:
117121
""" Wake up the guest """
118122
self.debug(

tmt/steps/provision/testcloud.py

+4
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,10 @@ def is_ready(self) -> bool:
361361
except libvirt.libvirtError:
362362
return False
363363

364+
@property
365+
def logs(self) -> list[str]:
366+
return []
367+
364368
def _get_url(self, url: str, message: str) -> requests.Response:
365369
""" Get url, retry when fails, return response """
366370

0 commit comments

Comments
 (0)