summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/lib/wic/plugins/source/otaimage.py32
-rw-r--r--scripts/qemucommand.py127
-rwxr-xr-xscripts/run-qemu-ota131
3 files changed, 149 insertions, 141 deletions
diff --git a/scripts/lib/wic/plugins/source/otaimage.py b/scripts/lib/wic/plugins/source/otaimage.py
index eef0bb4..26cfb10 100644
--- a/scripts/lib/wic/plugins/source/otaimage.py
+++ b/scripts/lib/wic/plugins/source/otaimage.py
@@ -19,10 +19,12 @@ import logging
19import os 19import os
20import sys 20import sys
21 21
22from wic.pluginbase import SourcePlugin 22from wic.plugins.source.rawcopy import RawCopyPlugin
23from wic.utils.misc import get_bitbake_var 23from wic.utils.misc import get_bitbake_var
24 24
25class OTAImagePlugin(SourcePlugin): 25logger = logging.getLogger('wic')
26
27class OTAImagePlugin(RawCopyPlugin):
26 """ 28 """
27 Add an already existing filesystem image to the partition layout. 29 Add an already existing filesystem image to the partition layout.
28 """ 30 """
@@ -30,25 +32,6 @@ class OTAImagePlugin(SourcePlugin):
30 name = 'otaimage' 32 name = 'otaimage'
31 33
32 @classmethod 34 @classmethod
33 def do_install_disk(cls, disk, disk_name, cr, workdir, oe_builddir,
34 bootimg_dir, kernel_dir, native_sysroot):
35 """
36 Called after all partitions have been prepared and assembled into a
37 disk image. Do nothing.
38 """
39 pass
40
41 @classmethod
42 def do_configure_partition(cls, part, source_params, cr, cr_workdir,
43 oe_builddir, bootimg_dir, kernel_dir,
44 native_sysroot):
45 """
46 Called before do_prepare_partition(). Possibly prepare
47 configuration files of some sort.
48 """
49 pass
50
51 @classmethod
52 def do_prepare_partition(cls, part, source_params, cr, cr_workdir, 35 def do_prepare_partition(cls, part, source_params, cr, cr_workdir,
53 oe_builddir, bootimg_dir, kernel_dir, 36 oe_builddir, bootimg_dir, kernel_dir,
54 rootfs_dir, native_sysroot): 37 rootfs_dir, native_sysroot):
@@ -65,5 +48,10 @@ class OTAImagePlugin(SourcePlugin):
65 src = bootimg_dir + "/" + get_bitbake_var("IMAGE_LINK_NAME") + ".otaimg" 48 src = bootimg_dir + "/" + get_bitbake_var("IMAGE_LINK_NAME") + ".otaimg"
66 49
67 logger.debug('Preparing partition using image %s' % (src)) 50 logger.debug('Preparing partition using image %s' % (src))
68 part.prepare_rootfs_from_fs_image(cr_workdir, src, "") 51 source_params['file'] = src
52
53 super(OTAImagePlugin, cls).do_prepare_partition(part, source_params,
54 cr, cr_workdir, oe_builddir,
55 bootimg_dir, kernel_dir,
56 rootfs_dir, native_sysroot)
69 57
diff --git a/scripts/qemucommand.py b/scripts/qemucommand.py
new file mode 100644
index 0000000..82a9540
--- /dev/null
+++ b/scripts/qemucommand.py
@@ -0,0 +1,127 @@
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 from %s" % 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 CalledProcessError:
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
85 def command_line(self):
86 netuser = 'user,hostfwd=tcp:0.0.0.0:%d-:22,restrict=off' % self.ssh_port
87 if self.gdb:
88 netuser += ',hostfwd=tcp:0.0.0.0:2159-:2159'
89 cmdline = [
90 "qemu-system-x86_64",
91 "-bios", self.bios
92 ]
93 if not self.overlay:
94 cmdline += ["-drive", "file=%s,if=ide,format=raw,snapshot=on" % self.image]
95 cmdline += [
96 "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port,
97 "-m", "1G",
98 "-usb",
99 "-usbdevice", "tablet",
100 "-show-cursor",
101 "-vga", "std",
102 "-net", netuser,
103 "-net", "nic,macaddr=%s" % self.mac_address
104 ]
105 if self.pcap:
106 cmdline += ['-net', 'dump,file=' + self.pcap]
107 if self.gui:
108 cmdline += ["-serial", "stdio"]
109 else:
110 cmdline.append('-nographic')
111 if self.kvm:
112 cmdline.append('-enable-kvm')
113 else:
114 cmdline += ['-cpu', 'Haswell']
115 if self.overlay:
116 cmdline.append(self.overlay)
117 return cmdline
118
119 def img_command_line(self):
120 cmdline = [
121 "qemu-img", "create",
122 "-o", "backing_file=%s" % self.image,
123 "-f", "qcow2",
124 self.overlay]
125 return cmdline
126
127
diff --git a/scripts/run-qemu-ota b/scripts/run-qemu-ota
index 5334814..56e4fbc 100755
--- a/scripts/run-qemu-ota
+++ b/scripts/run-qemu-ota
@@ -2,126 +2,12 @@
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 if exists(args.imagename):
64 image = args.imagename
65 else:
66 ext = EXTENSIONS.get(self.machine, 'wic')
67 image = join(args.dir, self.machine, '%s-%s.%s' % (args.imagename, self.machine, ext))
68 self.image = realpath(image)
69 if not exists(self.image):
70 raise ValueError("OS image %s does not exist" % self.image)
71 if args.mac:
72 self.mac_address = args.mac
73 else:
74 self.mac_address = random_mac()
75 self.serial_port = find_local_port(8990)
76 self.ssh_port = find_local_port(2222)
77 self.kvm = not args.no_kvm
78 self.gui = not args.no_gui
79 self.gdb = args.gdb
80 self.pcap = args.pcap
81 self.overlay = args.overlay
82
83 def command_line(self):
84 netuser = 'user,hostfwd=tcp:0.0.0.0:%d-:22,restrict=off' % self.ssh_port
85 if self.gdb:
86 netuser += ',hostfwd=tcp:0.0.0.0:2159-:2159'
87 cmdline = [
88 "qemu-system-x86_64",
89 "-bios", self.bios
90 ]
91 if not self.overlay:
92 cmdline += ["-drive", "file=%s,if=ide,format=raw,snapshot=on" % self.image]
93 cmdline += [
94 "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port,
95 "-m", "1G",
96 "-usb",
97 "-usbdevice", "tablet",
98 "-show-cursor",
99 "-vga", "std",
100 "-net", netuser,
101 "-net", "nic,macaddr=%s" % self.mac_address
102 ]
103 if self.pcap:
104 cmdline += ['-net', 'dump,file=' + self.pcap]
105 if self.gui:
106 cmdline += ["-serial", "stdio"]
107 else:
108 cmdline.append('-nographic')
109 if self.kvm:
110 cmdline.append('-enable-kvm')
111 else:
112 cmdline += ['-cpu', 'Haswell']
113 if self.overlay:
114 cmdline.append(self.overlay)
115 return cmdline
116
117 def img_command_line(self):
118 cmdline = [
119 "qemu-img", "create",
120 "-o", "backing_file=%s" % self.image,
121 "-f", "qcow2",
122 self.overlay]
123 return cmdline
124
125 11
126def main(): 12def main():
127 parser = ArgumentParser(description='Run meta-updater image in qemu') 13 parser = ArgumentParser(description='Run meta-updater image in qemu')
@@ -135,11 +21,18 @@ def main():
135 '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")',
136 action='store_true') 22 action='store_true')
137 parser.add_argument('--machine', default=None, help="Target MACHINE") 23 parser.add_argument('--machine', default=None, help="Target MACHINE")
138 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')
139 parser.add_argument('--no-gui', help='Disable GUI', action='store_true') 29 parser.add_argument('--no-gui', help='Disable GUI', action='store_true')
140 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')
141 parser.add_argument('--pcap', default=None, help='Dump all network traffic') 31 parser.add_argument('--pcap', default=None, help='Dump all network traffic')
142 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.')
143 parser.add_argument('-n', '--dry-run', help='Print qemu command line rather then run it', action='store_true') 36 parser.add_argument('-n', '--dry-run', help='Print qemu command line rather then run it', action='store_true')
144 args = parser.parse_args() 37 args = parser.parse_args()
145 try: 38 try:
@@ -161,7 +54,7 @@ def main():
161 if args.dry_run: 54 if args.dry_run:
162 print(" ".join(img_cmdline)) 55 print(" ".join(img_cmdline))
163 else: 56 else:
164 Popen(img_cmdline) 57 Popen(img_cmdline).wait()
165 58
166 if args.dry_run: 59 if args.dry_run:
167 print(" ".join(cmdline)) 60 print(" ".join(cmdline))