summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--scripts/qemucommand.py132
-rwxr-xr-xscripts/run-qemu-ota132
3 files changed, 149 insertions, 116 deletions
diff --git a/.gitignore b/.gitignore
index bee8a64..8d35cb3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
1__pycache__ 1__pycache__
2*.pyc
diff --git a/scripts/qemucommand.py b/scripts/qemucommand.py
new file mode 100644
index 0000000..86362f7
--- /dev/null
+++ b/scripts/qemucommand.py
@@ -0,0 +1,132 @@
1from os.path import exists, join, realpath, abspath
2from os import listdir
3import random
4import socket
5from subprocess import check_output, CalledProcessError
6
7EXTENSIONS = {
8 'intel-corei7-64': 'wic',
9 'qemux86-64': 'otaimg'
10}
11
12
13def find_local_port(start_port):
14 """"
15 Find the next free TCP port after 'start_port'.
16 """
17
18 for port in range(start_port, start_port + 10):
19 try:
20 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
21 s.bind(('', port))
22 return port
23 except socket.error:
24 print("Skipping port %d" % port)
25 finally:
26 s.close()
27 raise Exception("Could not find a free TCP port")
28
29
30def random_mac():
31 """Return a random Ethernet MAC address
32 @link https://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml#ethernet-numbers-2
33 """
34 head = "ca:fe:"
35 hex_digits = '0123456789abcdef'
36 tail = ':'.join([random.choice(hex_digits) + random.choice(hex_digits) for _ in range(4)])
37 return head + tail
38
39
40class QemuCommand(object):
41 def __init__(self, args):
42 if args.machine:
43 self.machine = args.machine
44 else:
45 machines = listdir(args.dir)
46 if len(machines) == 1:
47 self.machine = machines[0]
48 else:
49 raise ValueError("Could not autodetect machine type. More than one entry in %s. Maybe --machine qemux86-64?" % args.dir)
50 if args.efi:
51 self.bios = 'OVMF.fd'
52 else:
53 uboot = abspath(join(args.dir, self.machine, 'u-boot-qemux86-64.rom'))
54 if not exists(uboot):
55 raise ValueError("U-Boot image %s does not exist" % uboot)
56 self.bios = uboot
57 if exists(args.imagename):
58 image = args.imagename
59 else:
60 ext = EXTENSIONS.get(self.machine, 'wic')
61 image = join(args.dir, self.machine, '%s-%s.%s' % (args.imagename, self.machine, ext))
62 self.image = realpath(image)
63 if not exists(self.image):
64 raise ValueError("OS image %s does not exist" % self.image)
65 if args.mac:
66 self.mac_address = args.mac
67 else:
68 self.mac_address = random_mac()
69 self.serial_port = find_local_port(8990)
70 self.ssh_port = find_local_port(2222)
71 if args.kvm is None:
72 # Autodetect KVM using 'kvm-ok'
73 try:
74 check_output(['kvm-ok'])
75 self.kvm = True
76 except Exception:
77 self.kvm = False
78 else:
79 self.kvm = args.kvm
80 self.gui = not args.no_gui
81 self.gdb = args.gdb
82 self.pcap = args.pcap
83 self.overlay = args.overlay
84 self.secondary_network = args.secondary_network
85
86 def command_line(self):
87 netuser = 'user,hostfwd=tcp:0.0.0.0:%d-:22,restrict=off' % self.ssh_port
88 if self.gdb:
89 netuser += ',hostfwd=tcp:0.0.0.0:2159-:2159'
90 cmdline = [
91 "qemu-system-x86_64",
92 "-bios", self.bios
93 ]
94 if not self.overlay:
95 cmdline += ["-drive", "file=%s,if=ide,format=raw,snapshot=on" % self.image]
96 cmdline += [
97 "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port,
98 "-m", "1G",
99 "-usb",
100 "-device", "usb-tablet",
101 "-show-cursor",
102 "-vga", "std",
103 "-net", netuser,
104 "-net", "nic,macaddr=%s" % self.mac_address
105 ]
106 if self.pcap:
107 cmdline += ['-net', 'dump,file=' + self.pcap]
108 if self.secondary_network:
109 cmdline += [
110 '-net', 'nic,vlan=1,macaddr='+random_mac(),
111 '-net', 'socket,vlan=1,mcast=230.0.0.1:1234,localaddr=127.0.0.1',
112 ]
113 if self.gui:
114 cmdline += ["-serial", "stdio"]
115 else:
116 cmdline.append('-nographic')
117 if self.kvm:
118 cmdline += ['-enable-kvm', '-cpu', 'host']
119 else:
120 cmdline += ['-cpu', 'Haswell']
121 if self.overlay:
122 cmdline.append(self.overlay)
123 return cmdline
124
125 def img_command_line(self):
126 cmdline = [
127 "qemu-img", "create",
128 "-o", "backing_file=%s" % self.image,
129 "-f", "qcow2",
130 self.overlay]
131 return cmdline
132
diff --git a/scripts/run-qemu-ota b/scripts/run-qemu-ota
index 6a3586c..b2f55e9 100755
--- a/scripts/run-qemu-ota
+++ b/scripts/run-qemu-ota
@@ -2,127 +2,17 @@
2 2
3from argparse import ArgumentParser 3from argparse import ArgumentParser
4from subprocess import Popen 4from subprocess import Popen
5from os.path import exists, join, realpath 5from os.path import exists
6from os import listdir
7import random
8import sys 6import sys
9import socket 7from qemucommand import QemuCommand
10 8
11DEFAULT_DIR = 'tmp/deploy/images' 9DEFAULT_DIR = 'tmp/deploy/images'
12 10
13EXTENSIONS = {
14 'intel-corei7-64': 'wic',
15 'qemux86-64': 'otaimg'
16}
17
18
19def find_local_port(start_port):
20 """"
21 Find the next free TCP port after 'start_port'.
22 """
23
24 for port in range(start_port, start_port + 10):
25 try:
26 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
27 s.bind(('', port))
28 return port
29 except socket.error:
30 print("Skipping port %d" % port)
31 finally:
32 s.close()
33 raise Exception("Could not find a free TCP port")
34
35
36def random_mac():
37 """Return a random Ethernet MAC address
38 @link https://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml#ethernet-numbers-2
39 """
40 head = "ca:fe:"
41 hex_digits = '0123456789abcdef'
42 tail = ':'.join([random.choice(hex_digits) + random.choice(hex_digits) for _ in range(4)])
43 return head + tail
44
45
46class QemuCommand(object):
47 def __init__(self, args):
48 if args.machine:
49 self.machine = args.machine
50 else:
51 machines = listdir(args.dir)
52 if len(machines) == 1:
53 self.machine = machines[0]
54 else:
55 raise ValueError("Could not autodetect machine type from %s" % args.dir)
56 if args.efi:
57 self.bios = 'OVMF.fd'
58 else:
59 uboot = join(args.dir, self.machine, 'u-boot-qemux86-64.rom')
60 if not exists(uboot):
61 raise ValueError("U-Boot image %s does not exist" % uboot)
62 self.bios = uboot
63 ext = EXTENSIONS.get(self.machine, 'wic')
64 image = join(args.dir, self.machine, '%s-%s.%s' % (args.imagename, self.machine, ext))
65 self.image = realpath(image)
66 if not exists(self.image):
67 raise ValueError("OS image %s does not exist" % self.image)
68 if args.mac:
69 self.mac_address = args.mac
70 else:
71 self.mac_address = random_mac()
72 self.serial_port = find_local_port(8990)
73 self.ssh_port = find_local_port(2222)
74 self.kvm = not args.no_kvm
75 self.gui = not args.no_gui
76 self.gdb = args.gdb
77 self.pcap = args.pcap
78 self.overlay = args.overlay
79
80 def command_line(self):
81 netuser = 'user,hostfwd=tcp:0.0.0.0:%d-:22,restrict=off' % self.ssh_port
82 if self.gdb:
83 netuser += ',hostfwd=tcp:0.0.0.0:2159-:2159'
84 cmdline = [
85 "qemu-system-x86_64",
86 "-bios", self.bios
87 ]
88 if not self.overlay:
89 cmdline += ["-drive", "file=%s,if=ide,format=raw,snapshot=on" % self.image]
90 cmdline += [
91 "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port,
92 "-m", "1G",
93 "-usb",
94 "-usbdevice", "tablet",
95 "-show-cursor",
96 "-vga", "std",
97 "-net", netuser,
98 "-net", "nic,macaddr=%s" % self.mac_address
99 ]
100 if self.pcap:
101 cmdline += ['-net', 'dump,file=' + self.pcap]
102 if self.gui:
103 cmdline += ["-serial", "stdio"]
104 else:
105 cmdline.append('-nographic')
106 if self.kvm:
107 cmdline.append('-enable-kvm')
108 else:
109 cmdline += ['-cpu', 'Haswell']
110 if self.overlay:
111 cmdline.append(self.overlay)
112 return cmdline
113
114 def img_command_line(self):
115 cmdline = [
116 "qemu-img", "create",
117 "-o", "backing_file=%s" % self.image,
118 "-f", "qcow2",
119 self.overlay]
120 return cmdline
121
122 11
123def main(): 12def main():
124 parser = ArgumentParser(description='Run meta-updater image in qemu') 13 parser = ArgumentParser(description='Run meta-updater image in qemu')
125 parser.add_argument('imagename', default='core-image-minimal', nargs='?') 14 parser.add_argument('imagename', default='core-image-minimal', nargs='?',
15 help="Either the name of the bitbake image target, or a path to the image to run")
126 parser.add_argument('mac', default=None, nargs='?') 16 parser.add_argument('mac', default=None, nargs='?')
127 parser.add_argument('--dir', default=DEFAULT_DIR, 17 parser.add_argument('--dir', default=DEFAULT_DIR,
128 help='Path to build directory containing the image and u-boot-qemux86-64.rom') 18 help='Path to build directory containing the image and u-boot-qemux86-64.rom')
@@ -131,11 +21,21 @@ def main():
131 'OSTREE_BOOTLOADER = "grub" and OVMF.fd firmware to be installed (try "apt install ovmf")', 21 'OSTREE_BOOTLOADER = "grub" and OVMF.fd firmware to be installed (try "apt install ovmf")',
132 action='store_true') 22 action='store_true')
133 parser.add_argument('--machine', default=None, help="Target MACHINE") 23 parser.add_argument('--machine', default=None, help="Target MACHINE")
134 parser.add_argument('--no-kvm', help='Disable KVM in QEMU', action='store_true') 24 kvm_group = parser.add_argument_group()
25 kvm_group.add_argument('--force-kvm', help='Force use of KVM (default is to autodetect)',
26 dest='kvm', action='store_true', default=None)
27 kvm_group.add_argument('--no-kvm', help='Disable KVM in QEMU',
28 dest='kvm', action='store_false')
135 parser.add_argument('--no-gui', help='Disable GUI', action='store_true') 29 parser.add_argument('--no-gui', help='Disable GUI', action='store_true')
136 parser.add_argument('--gdb', help='Export gdbserver port 2159 from the image', action='store_true') 30 parser.add_argument('--gdb', help='Export gdbserver port 2159 from the image', action='store_true')
137 parser.add_argument('--pcap', default=None, help='Dump all network traffic') 31 parser.add_argument('--pcap', default=None, help='Dump all network traffic')
138 parser.add_argument('-o', '--overlay', type=str, metavar='file.cow', help='Use an overlay storage image file. Will be created if it does not exist. This option lets you have a persistent image without modifying the underlying image file, permitting multiple different persistent machines.') 32 parser.add_argument('-o', '--overlay', type=str, metavar='file.cow',
33 help='Use an overlay storage image file. Will be created if it does not exist. ' +
34 'This option lets you have a persistent image without modifying the underlying image ' +
35 'file, permitting multiple different persistent machines.')
36 parser.add_argument('--secondary-network', action='store_true', dest='secondary_network',
37 help='Give the image a second network card connected to a virtual network. ' +
38 'This can be used to test Uptane Primary/Secondary communication.')
139 parser.add_argument('-n', '--dry-run', help='Print qemu command line rather then run it', action='store_true') 39 parser.add_argument('-n', '--dry-run', help='Print qemu command line rather then run it', action='store_true')
140 args = parser.parse_args() 40 args = parser.parse_args()
141 try: 41 try: