summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcajun-rat <phil@advancedtelematic.com>2017-11-15 17:38:11 +0100
committerGitHub <noreply@github.com>2017-11-15 17:38:11 +0100
commitf64cbdb8deadacbece998636b7d3bc83e7ac2ec9 (patch)
tree364c02213fe9d16bdadc24d0e531e137eff1165b
parent71410bd31ec76e55247807551e68a2061e277b08 (diff)
parent9411b6039661f50832779d021f3d47b2d8516634 (diff)
downloadmeta-updater-f64cbdb8deadacbece998636b7d3bc83e7ac2ec9.tar.gz
Merge pull request #174 from advancedtelematic/feat/PRO-4199/oe-selftest-sota-tools
Feat/pro 4199/oe selftest sota tools
-rw-r--r--.gitignore1
-rw-r--r--README.adoc2
-rw-r--r--lib/oeqa/selftest/garage_push.py42
l---------lib/oeqa/selftest/qemucommand.py1
-rw-r--r--lib/oeqa/selftest/updater.py125
-rw-r--r--recipes-sota/aktualizr/aktualizr_git.bb1
-rw-r--r--scripts/qemucommand.py118
-rwxr-xr-xscripts/run-qemu-ota118
8 files changed, 249 insertions, 159 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/README.adoc b/README.adoc
index 0097670..b4608d5 100644
--- a/README.adoc
+++ b/README.adoc
@@ -136,5 +136,5 @@ SANITY_TESTED_DISTROS=""
136* Run oe-selftest: 136* Run oe-selftest:
137 137
138``` 138```
139oe-selftest --run-tests garage_push 139oe-selftest --run-tests updater
140``` 140```
diff --git a/lib/oeqa/selftest/garage_push.py b/lib/oeqa/selftest/garage_push.py
deleted file mode 100644
index 21bd1c1..0000000
--- a/lib/oeqa/selftest/garage_push.py
+++ /dev/null
@@ -1,42 +0,0 @@
1import unittest
2import os
3import logging
4
5from oeqa.selftest.base import oeSelfTest
6from oeqa.utils.commands import runCmd, bitbake, get_bb_var
7
8class GaragePushTests(oeSelfTest):
9
10 @classmethod
11 def setUpClass(cls):
12 # Ensure we have the right data in pkgdata
13 logger = logging.getLogger("selftest")
14 logger.info('Running bitbake to build aktualizr-native tools')
15 bitbake('aktualizr-native garage-sign-native')
16
17 def test_help(self):
18 image_dir = get_bb_var("D", "aktualizr-native")
19 bin_dir = get_bb_var("bindir", "aktualizr-native")
20 gp_path = os.path.join(image_dir, bin_dir[1:], 'garage-push')
21 result = runCmd('%s --help' % gp_path, ignore_status=True)
22 self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output)
23
24 def test_java(self):
25 result = runCmd('which java', ignore_status=True)
26 self.assertEqual(result.status, 0, "Java not found.")
27
28 def test_sign(self):
29 image_dir = get_bb_var("D", "garage-sign-native")
30 bin_dir = get_bb_var("bindir", "garage-sign-native")
31 gs_path = os.path.join(image_dir, bin_dir[1:], 'garage-sign')
32 result = runCmd('%s --help' % gs_path, ignore_status=True)
33 self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output)
34
35 def test_push(self):
36 bitbake('core-image-minimal')
37 self.write_config('IMAGE_INSTALL_append = " man "')
38 bitbake('core-image-minimal')
39
40 def test_hsm(self):
41 self.write_config('SOTA_CLIENT_FEATURES="hsm hsm-test"')
42 bitbake('core-image-minimal')
diff --git a/lib/oeqa/selftest/qemucommand.py b/lib/oeqa/selftest/qemucommand.py
new file mode 120000
index 0000000..bc06dde
--- /dev/null
+++ b/lib/oeqa/selftest/qemucommand.py
@@ -0,0 +1 @@
../../../scripts/qemucommand.py \ No newline at end of file
diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py
new file mode 100644
index 0000000..6339e6e
--- /dev/null
+++ b/lib/oeqa/selftest/updater.py
@@ -0,0 +1,125 @@
1import unittest
2import os
3import logging
4import subprocess
5import time
6
7from oeqa.selftest.base import oeSelfTest
8from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
9from oeqa.selftest.qemucommand import QemuCommand
10
11
12class SotaToolsTests(oeSelfTest):
13
14 @classmethod
15 def setUpClass(cls):
16 logger = logging.getLogger("selftest")
17 logger.info('Running bitbake to build aktualizr-native tools')
18 bitbake('aktualizr-native')
19
20 def test_push_help(self):
21 bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'aktualizr-native')
22 p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "garage-push"
23 self.assertTrue(os.path.isfile(p), msg = "No garage-push found (%s)" % p)
24 result = runCmd('%s --help' % p, ignore_status=True)
25 self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output)
26
27 def test_deploy_help(self):
28 bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'aktualizr-native')
29 p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "garage-deploy"
30 self.assertTrue(os.path.isfile(p), msg = "No garage-deploy found (%s)" % p)
31 result = runCmd('%s --help' % p, ignore_status=True)
32 self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output)
33
34
35class GarageSignTests(oeSelfTest):
36
37 @classmethod
38 def setUpClass(cls):
39 logger = logging.getLogger("selftest")
40 logger.info('Running bitbake to build garage-sign-native')
41 bitbake('garage-sign-native')
42
43 def test_help(self):
44 bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'garage-sign-native')
45 p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "garage-sign"
46 self.assertTrue(os.path.isfile(p), msg = "No garage-sign found (%s)" % p)
47 result = runCmd('%s --help' % p, ignore_status=True)
48 self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output)
49
50
51class HsmTests(oeSelfTest):
52
53 def test_hsm(self):
54 self.write_config('SOTA_CLIENT_FEATURES="hsm hsm-test"')
55 bitbake('core-image-minimal')
56
57
58class GeneralTests(oeSelfTest):
59
60 def test_java(self):
61 result = runCmd('which java', ignore_status=True)
62 self.assertEqual(result.status, 0, "Java not found.")
63
64 def test_add_package(self):
65 print('')
66 deploydir = get_bb_var('DEPLOY_DIR_IMAGE')
67 imagename = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal')
68 image_path = deploydir + '/' + imagename + '.otaimg'
69 logger = logging.getLogger("selftest")
70
71 logger.info('Running bitbake with man in the image package list')
72 self.write_config('IMAGE_INSTALL_append = " man "')
73 bitbake('-c cleanall man')
74 bitbake('core-image-minimal')
75 result = runCmd('oe-pkgdata-util find-path /usr/bin/man')
76 self.assertEqual(result.output, 'man: /usr/bin/man')
77 path1 = os.path.realpath(image_path)
78 size1 = os.path.getsize(path1)
79 logger.info('First image %s has size %i' % (path1, size1))
80
81 logger.info('Running bitbake without man in the image package list')
82 self.write_config('IMAGE_INSTALL_remove = " man "')
83 bitbake('-c cleanall man')
84 bitbake('core-image-minimal')
85 result = runCmd('oe-pkgdata-util find-path /usr/bin/man', ignore_status=True)
86 self.assertEqual(result.status, 1, "Status different than 1. output: %s" % result.output)
87 self.assertEqual(result.output, 'ERROR: Unable to find any package producing path /usr/bin/man')
88 path2 = os.path.realpath(image_path)
89 size2 = os.path.getsize(path2)
90 logger.info('Second image %s has size %i' % (path2, size2))
91 self.assertNotEqual(path1, path2, "Image paths are identical; image was not rebuilt.")
92 self.assertNotEqual(size1, size2, "Image sizes are identical; image was not rebuilt.")
93
94 def test_qemu(self):
95 print('')
96 # Create empty object.
97 args = type('', (), {})()
98 args.imagename = 'core-image-minimal'
99 args.mac = None
100 # Could use DEPLOY_DIR_IMAGE her but it's already in the machine
101 # subdirectory.
102 args.dir = 'tmp/deploy/images'
103 args.efi = False
104 args.machine = None
105 args.no_kvm = False
106 args.no_gui = True
107 args.gdb = False
108 args.pcap = None
109 args.overlay = None
110 args.dry_run = False
111
112 qemu_command = QemuCommand(args)
113 cmdline = qemu_command.command_line()
114 print('Booting image with run-qemu-ota...')
115 s = subprocess.Popen(cmdline)
116 time.sleep(10)
117 print('Machine name (hostname) of device is:')
118 ssh_cmd = ['ssh', '-q', '-o', 'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no', 'root@localhost', '-p', str(qemu_command.ssh_port), 'hostname']
119 s2 = subprocess.Popen(ssh_cmd)
120 time.sleep(5)
121 try:
122 s.terminate()
123 except KeyboardInterrupt:
124 pass
125
diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb
index c98027d..7af7c60 100644
--- a/recipes-sota/aktualizr/aktualizr_git.bb
+++ b/recipes-sota/aktualizr/aktualizr_git.bb
@@ -47,5 +47,6 @@ FILES_${PN}_class-target = " \
47 " 47 "
48FILES_${PN}_class-native = " \ 48FILES_${PN}_class-native = " \
49 ${bindir}/aktualizr_implicit_writer \ 49 ${bindir}/aktualizr_implicit_writer \
50 ${bindir}/garage-deploy \
50 ${bindir}/garage-push \ 51 ${bindir}/garage-push \
51 " 52 "
diff --git a/scripts/qemucommand.py b/scripts/qemucommand.py
new file mode 100644
index 0000000..a75ffb6
--- /dev/null
+++ b/scripts/qemucommand.py
@@ -0,0 +1,118 @@
1from os.path import exists, join, realpath, abspath
2from os import listdir
3import random
4import socket
5
6EXTENSIONS = {
7 'intel-corei7-64': 'wic',
8 'qemux86-64': 'otaimg'
9}
10
11
12def find_local_port(start_port):
13 """"
14 Find the next free TCP port after 'start_port'.
15 """
16
17 for port in range(start_port, start_port + 10):
18 try:
19 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
20 s.bind(('', port))
21 return port
22 except socket.error:
23 print("Skipping port %d" % port)
24 finally:
25 s.close()
26 raise Exception("Could not find a free TCP port")
27
28
29def random_mac():
30 """Return a random Ethernet MAC address
31 @link https://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml#ethernet-numbers-2
32 """
33 head = "ca:fe:"
34 hex_digits = '0123456789abcdef'
35 tail = ':'.join([random.choice(hex_digits) + random.choice(hex_digits) for _ in range(4)])
36 return head + tail
37
38
39class QemuCommand(object):
40 def __init__(self, args):
41 if args.machine:
42 self.machine = args.machine
43 else:
44 machines = listdir(args.dir)
45 if len(machines) == 1:
46 self.machine = machines[0]
47 else:
48 raise ValueError("Could not autodetect machine type from %s" % args.dir)
49 if args.efi:
50 self.bios = 'OVMF.fd'
51 else:
52 uboot = abspath(join(args.dir, self.machine, 'u-boot-qemux86-64.rom'))
53 if not exists(uboot):
54 raise ValueError("U-Boot image %s does not exist" % uboot)
55 self.bios = uboot
56 if exists(args.imagename):
57 image = args.imagename
58 else:
59 ext = EXTENSIONS.get(self.machine, 'wic')
60 image = join(args.dir, self.machine, '%s-%s.%s' % (args.imagename, self.machine, ext))
61 self.image = realpath(image)
62 if not exists(self.image):
63 raise ValueError("OS image %s does not exist" % self.image)
64 if args.mac:
65 self.mac_address = args.mac
66 else:
67 self.mac_address = random_mac()
68 self.serial_port = find_local_port(8990)
69 self.ssh_port = find_local_port(2222)
70 self.kvm = not args.no_kvm
71 self.gui = not args.no_gui
72 self.gdb = args.gdb
73 self.pcap = args.pcap
74 self.overlay = args.overlay
75
76 def command_line(self):
77 netuser = 'user,hostfwd=tcp:0.0.0.0:%d-:22,restrict=off' % self.ssh_port
78 if self.gdb:
79 netuser += ',hostfwd=tcp:0.0.0.0:2159-:2159'
80 cmdline = [
81 "qemu-system-x86_64",
82 "-bios", self.bios
83 ]
84 if not self.overlay:
85 cmdline += ["-drive", "file=%s,if=ide,format=raw,snapshot=on" % self.image]
86 cmdline += [
87 "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port,
88 "-m", "1G",
89 "-usb",
90 "-usbdevice", "tablet",
91 "-show-cursor",
92 "-vga", "std",
93 "-net", netuser,
94 "-net", "nic,macaddr=%s" % self.mac_address
95 ]
96 if self.pcap:
97 cmdline += ['-net', 'dump,file=' + self.pcap]
98 if self.gui:
99 cmdline += ["-serial", "stdio"]
100 else:
101 cmdline.append('-nographic')
102 if self.kvm:
103 cmdline.append('-enable-kvm')
104 else:
105 cmdline += ['-cpu', 'Haswell']
106 if self.overlay:
107 cmdline.append(self.overlay)
108 return cmdline
109
110 def img_command_line(self):
111 cmdline = [
112 "qemu-img", "create",
113 "-o", "backing_file=%s" % self.image,
114 "-f", "qcow2",
115 self.overlay]
116 return cmdline
117
118
diff --git a/scripts/run-qemu-ota b/scripts/run-qemu-ota
index 641296c..5f9cebe 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, join
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')