Module pandare.qcows
Module to simplify PANDA command line usage. Use python3 -m pandare.qcows to fetch files necessary to run various generic VMs and generate command lines to start them. Also supports deleting previously-fetched files.
Most of the interesting logic for this is contained in qcows_internal.py.
Expand source code
#!/usr/bin/env python3
'''
Module to simplify PANDA command line usage. Use python3 -m pandare.qcows to
fetch files necessary to run various generic VMs and generate command lines to start them.
Also supports deleting previously-fetched files.
Most of the interesting logic for this is contained in qcows_internal.py.
'''
from os import path, remove
from shlex import split as shlex_split
from sys import exit, stderr
from .utils import find_build_dir
from .panda import Panda
from os import environ
from .qcows_internal import Qcows, SUPPORTED_IMAGES
VM_DIR = path.join(path.expanduser("~"), ".panda")
class Qcows_cli():
@staticmethod
def _find_build_dir(arch):
try:
build_dir = find_build_dir(arch, find_executable=True)
except RuntimeError as e:
# Couldn't find this arch - can we find any?
try:
build_dir = find_build_dir(None, find_executable=True)
print(f"WARNING: You do not appear to have panda-system-{arch}, please build it then try again\n",
file=None if stdout.isatty() else stderr)
except RuntimeError as e2:
print(f"ERROR: Cannot find any version of PANDA on your system, please build and then try again\n",
file=None if stdout.isatty() else stderr)
raise e
return build_dir
@staticmethod
def remove_image(target):
try:
qcow = Qcows.get_qcow(target, download=False, _is_tty=stdout.isatty())
except ValueError:
# No QCOW, we're good!
return
try:
image_data = SUPPORTED_IMAGES[target]
except ValueError:
# Not a valid image? I guess we're good
return
qc = image_data.qcow
if not qc: # Default, get name from url
qc = image_data.url.split("/")[-1]
qcow_path = path.join(VM_DIR, qc)
if path.isfile(qcow_path):
print(f"Deleting {qcow_path}")
remove(qcow_path)
for extra_file in image_data.extra_files or []:
extra_file_path = path.join(VM_DIR, extra_file)
if path.isfile(extra_file_path):
print(f"Deleting {extra_file_path}")
remove(extra_file_path)
@staticmethod
def cli(target):
q = Qcows.get_qcow_info(target)
qcow = Qcows.get_qcow(target, _is_tty=stdout.isatty())
arch = q.arch
# User needs to have the specified arch in order to run the command.
# But if they just want to download/delete files and we find another arch
# we can fetch/delete the files print a warning about how the generatd command won't work.
build_dir = Qcows_cli._find_build_dir(arch) # will set find_executable
panda_args = [path.join(build_dir, f"panda-system-{arch}")]
biospath = path.realpath(path.join(build_dir, "pc-bios"))
panda_args.extend(["-L", biospath])
panda_args.extend(["-os", q.os])
if arch == 'mips64':
panda_args.extend(["-drive", f"file={qcow},if=virtio"])
else:
panda_args.append(qcow)
panda_args.extend(['-m', q.default_mem])
if q.extra_args:
extra_args = shlex_split(q.extra_args)
for x in extra_args:
if " " in x:
panda_args.append(repr(x))
else:
panda_args.append(x)
panda_args.extend(['-loadvm', q.snapshot])
ret = " ".join(panda_args)
if "-display none" in ret:
ret = ret.replace("-display none", "-nographic")
# Replace /home/username with ~ when we can (TTYs)
if stdout.isatty() and 'HOME' in environ:
ret = ret.replace(environ['HOME'], '~')
return ret
if __name__ == "__main__":
from sys import argv, stdout
valid_names = "\n * ".join(SUPPORTED_IMAGES.keys())
delete_mode = False
if len(argv) == 3 and argv[1] == 'delete':
delete_mode = True
argv.pop(1)
if len(argv) != 2 or argv[1] not in SUPPORTED_IMAGES:
print("\n" + f"USAGE: {argv[0]} [target_images]\n" +
f" or: {argv[0]} delete [target_image]\n\n" +
"The required files for the specified images will be downloaded and the PANDA command line to emulate that guest will be printed.\n" +
"If the \"delete\" argument is passed, any files related to the image will be deleted and no command line will be printed"
f"Where target_images is one of:\n * {valid_names}\n")
exit(1)
if delete_mode:
Qcows_cli.remove_image(argv[1])
else:
cmd = Qcows_cli.cli(argv[1])
if stdout.isatty():
print(f"Run the generic {argv[1]} PANDA guest interactively with the following command:\n{cmd}")
else:
print(cmd)
Classes
class Qcows_cli
-
Expand source code
class Qcows_cli(): @staticmethod def _find_build_dir(arch): try: build_dir = find_build_dir(arch, find_executable=True) except RuntimeError as e: # Couldn't find this arch - can we find any? try: build_dir = find_build_dir(None, find_executable=True) print(f"WARNING: You do not appear to have panda-system-{arch}, please build it then try again\n", file=None if stdout.isatty() else stderr) except RuntimeError as e2: print(f"ERROR: Cannot find any version of PANDA on your system, please build and then try again\n", file=None if stdout.isatty() else stderr) raise e return build_dir @staticmethod def remove_image(target): try: qcow = Qcows.get_qcow(target, download=False, _is_tty=stdout.isatty()) except ValueError: # No QCOW, we're good! return try: image_data = SUPPORTED_IMAGES[target] except ValueError: # Not a valid image? I guess we're good return qc = image_data.qcow if not qc: # Default, get name from url qc = image_data.url.split("/")[-1] qcow_path = path.join(VM_DIR, qc) if path.isfile(qcow_path): print(f"Deleting {qcow_path}") remove(qcow_path) for extra_file in image_data.extra_files or []: extra_file_path = path.join(VM_DIR, extra_file) if path.isfile(extra_file_path): print(f"Deleting {extra_file_path}") remove(extra_file_path) @staticmethod def cli(target): q = Qcows.get_qcow_info(target) qcow = Qcows.get_qcow(target, _is_tty=stdout.isatty()) arch = q.arch # User needs to have the specified arch in order to run the command. # But if they just want to download/delete files and we find another arch # we can fetch/delete the files print a warning about how the generatd command won't work. build_dir = Qcows_cli._find_build_dir(arch) # will set find_executable panda_args = [path.join(build_dir, f"panda-system-{arch}")] biospath = path.realpath(path.join(build_dir, "pc-bios")) panda_args.extend(["-L", biospath]) panda_args.extend(["-os", q.os]) if arch == 'mips64': panda_args.extend(["-drive", f"file={qcow},if=virtio"]) else: panda_args.append(qcow) panda_args.extend(['-m', q.default_mem]) if q.extra_args: extra_args = shlex_split(q.extra_args) for x in extra_args: if " " in x: panda_args.append(repr(x)) else: panda_args.append(x) panda_args.extend(['-loadvm', q.snapshot]) ret = " ".join(panda_args) if "-display none" in ret: ret = ret.replace("-display none", "-nographic") # Replace /home/username with ~ when we can (TTYs) if stdout.isatty() and 'HOME' in environ: ret = ret.replace(environ['HOME'], '~') return ret
Static methods
def cli(target)
-
Expand source code
@staticmethod def cli(target): q = Qcows.get_qcow_info(target) qcow = Qcows.get_qcow(target, _is_tty=stdout.isatty()) arch = q.arch # User needs to have the specified arch in order to run the command. # But if they just want to download/delete files and we find another arch # we can fetch/delete the files print a warning about how the generatd command won't work. build_dir = Qcows_cli._find_build_dir(arch) # will set find_executable panda_args = [path.join(build_dir, f"panda-system-{arch}")] biospath = path.realpath(path.join(build_dir, "pc-bios")) panda_args.extend(["-L", biospath]) panda_args.extend(["-os", q.os]) if arch == 'mips64': panda_args.extend(["-drive", f"file={qcow},if=virtio"]) else: panda_args.append(qcow) panda_args.extend(['-m', q.default_mem]) if q.extra_args: extra_args = shlex_split(q.extra_args) for x in extra_args: if " " in x: panda_args.append(repr(x)) else: panda_args.append(x) panda_args.extend(['-loadvm', q.snapshot]) ret = " ".join(panda_args) if "-display none" in ret: ret = ret.replace("-display none", "-nographic") # Replace /home/username with ~ when we can (TTYs) if stdout.isatty() and 'HOME' in environ: ret = ret.replace(environ['HOME'], '~') return ret
def remove_image(target)
-
Expand source code
@staticmethod def remove_image(target): try: qcow = Qcows.get_qcow(target, download=False, _is_tty=stdout.isatty()) except ValueError: # No QCOW, we're good! return try: image_data = SUPPORTED_IMAGES[target] except ValueError: # Not a valid image? I guess we're good return qc = image_data.qcow if not qc: # Default, get name from url qc = image_data.url.split("/")[-1] qcow_path = path.join(VM_DIR, qc) if path.isfile(qcow_path): print(f"Deleting {qcow_path}") remove(qcow_path) for extra_file in image_data.extra_files or []: extra_file_path = path.join(VM_DIR, extra_file) if path.isfile(extra_file_path): print(f"Deleting {extra_file_path}") remove(extra_file_path)