return True
-def run_shell_cmdline(args: MkosiArgs) -> List[str]:
+def run_shell_cmdline(args: MkosiArgs, pipe: bool = False, commands: Optional[Sequence[str]] = None) -> List[str]:
if args.output_format in (OutputFormat.directory, OutputFormat.subvolume):
target = f"--directory={args.output}"
else:
target = f"--image={args.output}"
- cmdline = ["systemd-nspawn", target]
+ cmdline = ["systemd-nspawn", "--quiet", target]
+
+ # Redirecting output correctly when not running directly from the terminal.
+ console_arg = f"--console={'interactive' if not pipe else 'pipe'}"
+ if nspawn_knows_arg(console_arg):
+ cmdline += [console_arg]
if args.read_only:
cmdline += ["--read-only"]
cmdline += ["--machine", virt_name(args)]
- if args.cmdline:
+ if commands or args.cmdline:
# If the verb is 'shell', args.cmdline contains the command to run.
# Otherwise, the verb is 'boot', and we assume args.cmdline contains nspawn arguments.
if args.verb == Verb.shell:
cmdline += ["--"]
- cmdline += args.cmdline
+ cmdline += commands or args.cmdline
return cmdline
def run_shell(args: MkosiArgs) -> None:
- run(run_shell_cmdline(args), stdout=sys.stdout, stderr=sys.stderr)
+ run(run_shell_cmdline(args, pipe=not sys.stdout.isatty()), stdout=sys.stdout, stderr=sys.stderr)
def find_qemu_binary() -> str:
def run_command_image(args: MkosiArgs, commands: Sequence[str], timeout: int, check: bool, stdout: _FILE = sys.stdout, stderr: _FILE = sys.stderr) -> CompletedProcess:
if args.verb == Verb.qemu:
return run_ssh(args, commands, check, stdout, stderr, timeout)
- else:
+ elif args.verb == Verb.boot:
cmdline = ["systemd-run", "--quiet", "--wait", "--pipe", "-M", virt_name(args), "/usr/bin/env", *commands]
return run(cmdline, check=check, stdout=stdout, stderr=stderr, text=True, timeout=timeout)
+ else:
+ return run(run_shell_cmdline(args, pipe=True, commands=commands), check=check, stdout=stdout, stderr=stderr, text=True, timeout=timeout)
def run_ssh_cmdline(args: MkosiArgs, commands: Optional[Sequence[str]] = None) -> Sequence[str]:
tmp.verb = Verb.boot
elif verb == Verb.qemu.name:
tmp.verb = Verb.qemu
+ elif verb == Verb.shell.name:
+ tmp.verb = Verb.shell
else:
die("No valid verb was entered.")
# Add the arguments in the machine class itself, rather than typing this for every testing function.
tmp.force = 1
tmp.autologin = True
+ tmp.ephemeral = True
if tmp.verb == Verb.qemu:
tmp.bootable = True
tmp.qemu_headless = True
tmp.hostonly_initrd = True
tmp.netdev = True
tmp.ssh = True
- elif tmp.verb == Verb.boot:
- pass
- else:
+ elif tmp.verb not in (Verb.shell, Verb.boot):
die("No valid verb was entered.")
self.args = load_args(tmp)
def _ensure_booted(self) -> None:
# Try to access the serial console which will raise an exception if the machine is not currently booted.
- assert self._serial is not None
+ assert self._serial is not None or self.args.verb == Verb.shell
def build(self) -> None:
if self.args.verb in MKOSI_COMMANDS_SUDO:
return self
def boot(self) -> None:
+ if self.args.verb == Verb.shell:
+ return
+
with contextlib.ExitStack() as stack:
prepend_to_environ_path(self.args.extra_search_paths)
@classmethod
def setUpClass(cls) -> None:
+ if os.getuid() != 0:
+ raise unittest.SkipTest("Must be invoked as root.")
+
cls.machine = Machine(cls.args)
verb = cls.machine.args.verb
cls.machine.build()
def setUp(self) -> None:
+ # Replacing underscores which makes name invalid.
+ # Necessary for shell otherwise racing conditions to the disk image will happen.
+ test_name = self.id().split(".")[3]
+ self.machine.args.hostname = test_name.replace("_", "-")
self.machine.boot()
def tearDown(self) -> None:
import pytest
+from mkosi.backend import Verb
from mkosi.machine import Machine, MkosiMachineTest
pytestmark = [
# Check = False to see if stderr and returncode have the expected values
result = self.machine.run(["NonExisting", "Command"], check=False)
- assert result.returncode in (203, 127)
+ assert result.returncode in (1, 127, 203)
result = self.machine.run(["ls", "-"], check=False)
assert result.returncode == 2
def test_before_boot() -> None:
m = Machine()
+ if m.args.verb == Verb.shell:
+ pytest.skip("Shell never boots the machine.")
with pytest.raises(AssertionError):
m.run(["ls"])
def test_after_shutdown() -> None:
with Machine() as m:
pass
-
+ if m.args.verb == Verb.shell:
+ pytest.skip("Shell never boots the machine.")
with pytest.raises(AssertionError):
m.run(["ls"])