Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Noble 24.04 minor improvements #272

Merged
merged 2 commits into from
Nov 15, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 77 additions & 20 deletions tests/lib/Qemu.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import tempfile
import time
import sys
import stat

import util

Expand Down Expand Up @@ -73,6 +74,17 @@ def args(self):
return ['-nographic']
return []

class QemuSerial():
def __init__(self, serial_file : str = None):
self.serial_file = serial_file
def args(self):
if self.serial_file:
return [
'-chardev', f'file,id=c1,path={self.serial_file},signal=off',
'-device', 'isa-serial,chardev=c1'
]
return ['-serial', 'stdio']

class QemuUserConfig:
def __init__(self):
self.nodefaults = True
Expand Down Expand Up @@ -229,6 +241,7 @@ def __init__(
'config': QemuUserConfig(),
'memory': QemuMemory(memory),
'ovmf' : QemuOvmf(machine),
'serial' : QemuSerial(f'{self.workdir}/serial.log'),
'machine' : QemuMachineType(machine)}
self.command = ['-pidfile', f'{self.workdir}/qemu.pid']

Expand All @@ -238,13 +251,6 @@ def get_command(self):
_args.extend(p.args())
return _args + self.command

def add_serial_to_file(self):
# serial to file
self.command = self.command + [
'-chardev', f'file,id=c1,path={self.workdir}/serial.log,signal=off',
'-device', 'isa-serial,chardev=c1'
]

def add_qemu_run_log(self):
# serial to file
self.command = self.command + [
Expand Down Expand Up @@ -346,6 +352,9 @@ def wait_for_state(self, s, retries=5):
def wakeup(self):
self.send_command("system_wakeup")

def powerdown(self):
self.send_command("system_powerdown")

def __del__(self):
if self.socket is not None:
self.socket.close()
Expand Down Expand Up @@ -467,6 +476,15 @@ class QemuMachineService:
QEMU_MACHINE_MONITOR = enum.auto()
QEMU_MACHINE_QMP = enum.auto()

# run script to run the guest
# this is used for debugging purpose and allow users
# to run the guest manually
qemu_run_script = """
#!/bin/bash
echo "To connect to the VM : ssh -p {fwd_port} root@localhost"
{cmd_str}
"""

class QemuMachine:
debug_enabled = False
# hold all qemu instances
Expand Down Expand Up @@ -498,7 +516,6 @@ def __init__(self,
self.fwd_port = util.tcp_port_available()
self.qcmd.add_port_forward(self.fwd_port)
self.qcmd.add_qemu_run_log()
self.qcmd.add_serial_to_file()

self.proc = None
self.out = None
Expand Down Expand Up @@ -572,6 +589,8 @@ def run(self):
"""
cmd = self.qcmd.get_command()
print(' '.join(cmd))
script=f'{self.workdir_name}/run.sh'
self.write_cmd_to_file(script)
self.proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
Expand All @@ -580,11 +599,7 @@ def run_and_wait(self):
"""
Run qemu and wait for its start (by waiting for monitor file's availability)
"""
cmd = self.qcmd.get_command()
print(' '.join(cmd))
self.proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.run()
QemuMonitor(self)

def communicate(self):
Expand All @@ -602,13 +617,28 @@ def stop(self):
"""
if self.proc is None:
return
# self.proc.returncode== None -> not yet terminated
if self.proc.returncode is None:
try:
self.proc.terminate()
self.communicate()
except Exception as e:
print(f'Exception {e}')
if self.proc.returncode is not None:
return

# self.proc.returncode == None -> not yet terminated

# try to shutdown the VM properly, this is important to avoid
# rootfs corruption if we want to run the guest again
mon = QemuMonitor(self)
mon.powerdown()
try:
self.communicate()
return
except Exception as e:
pass

print('Qemu process did not shutdown properly, terminate it ...')
# terminate qemu process (SIGTERM)
try:
self.proc.terminate()
self.communicate()
except Exception as e:
print(f'Exception {e}')

def reboot(self):
"""
Expand All @@ -623,6 +653,33 @@ def reboot(self):
# run the VM again
self.run()

def write_cmd_to_file(self, fname : str):
"""
Write the qemu command to a executable bash script
"""
# force -serial to stdio to be able to have the console on stdio
cur_serial = self.qcmd.plugins['serial']
self.qcmd.plugins['serial'] = QemuSerial()

cmd = self.qcmd.get_command()
with open(fname, 'w+') as run_script:
cmd_str=''
for el in cmd:
# escape qemu object with quotes
# for example : -object "{'qom-type': 'tdx-guest', 'id': 'tdx'}"
if el.startswith('{') and el.endswith('}'):
cmd_str += f'\"{el}\" '
else:
cmd_str += f'{el} '
script_contents = qemu_run_script.format(fwd_port=self.fwd_port,
cmd_str=cmd_str)
run_script.write(script_contents)
f = pathlib.Path(fname)
f.chmod(f.stat().st_mode | stat.S_IEXEC)

# restore serial config
self.qcmd.plugins['serial'] = cur_serial

def __del__(self):
"""
Make sure we stop the qemu process if it is still running
Expand Down