summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick Vacek <patrickvacek@gmail.com>2019-03-21 15:28:55 +0100
committerGitHub <noreply@github.com>2019-03-21 15:28:55 +0100
commitd39d8b167797243fcf067c6faa6b4220d697c71c (patch)
treed4aca54f1e8ff8e2a3409c2df2506f1f17152d3e
parent1e569e4def74e8b161833c4874888a7e514b67b1 (diff)
parente1867d7a7bd52d79fa3d051bb7b16f50934b88e6 (diff)
downloadmeta-updater-d39d8b167797243fcf067c6faa6b4220d697c71c.tar.gz
Merge pull request #507 from advancedtelematic/feat/OTA-2142/aktualizr-resource-control
aktualizr resource control
-rw-r--r--README.adoc16
-rw-r--r--lib/oeqa/selftest/cases/testutils.py128
-rw-r--r--lib/oeqa/selftest/cases/updater_minnowboard.py60
-rw-r--r--lib/oeqa/selftest/cases/updater_native.py47
-rw-r--r--lib/oeqa/selftest/cases/updater_qemux86_64.py (renamed from lib/oeqa/selftest/cases/updater.py)374
-rw-r--r--lib/oeqa/selftest/cases/updater_raspberrypi.py78
-rw-r--r--recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb2
-rw-r--r--recipes-sota/aktualizr/aktualizr-auto-prov-creds.bb2
-rw-r--r--recipes-sota/aktualizr/aktualizr-auto-prov.bb2
-rw-r--r--recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb2
-rw-r--r--recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb2
-rw-r--r--recipes-sota/aktualizr/aktualizr-hsm-prov.bb2
-rw-r--r--recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb4
-rwxr-xr-xrecipes-sota/aktualizr/aktualizr_git.bb26
-rw-r--r--recipes-sota/aktualizr/files/10-resource-control.conf6
-rw-r--r--recipes-sota/config/aktualizr-auto-reboot.bb2
-rw-r--r--recipes-sota/config/aktualizr-disable-send-ip.bb2
-rw-r--r--recipes-sota/config/aktualizr-log-debug.bb2
-rw-r--r--scripts/qemucommand.py2
19 files changed, 430 insertions, 329 deletions
diff --git a/README.adoc b/README.adoc
index f3aef45..cc01612 100644
--- a/README.adoc
+++ b/README.adoc
@@ -95,6 +95,7 @@ Your images will also need network connectivity to be able to reach an actual OT
95* `SOTA_MAIN_DTB` - base device tree to use with the kernel. Used together with FIT images. You can change it, and the device tree will also be changed after the update. 95* `SOTA_MAIN_DTB` - base device tree to use with the kernel. Used together with FIT images. You can change it, and the device tree will also be changed after the update.
96* `SOTA_DT_OVERLAYS` - whitespace-separated list of used device tree overlays for FIT image. This list is OSTree-updateable as well. 96* `SOTA_DT_OVERLAYS` - whitespace-separated list of used device tree overlays for FIT image. This list is OSTree-updateable as well.
97* `SOTA_EXTRA_CONF_FRAGS` - extra https://lxr.missinglinkelectronics.com/uboot/doc/uImage.FIT/overlay-fdt-boot.txt[configuration fragments] for FIT image. 97* `SOTA_EXTRA_CONF_FRAGS` - extra https://lxr.missinglinkelectronics.com/uboot/doc/uImage.FIT/overlay-fdt-boot.txt[configuration fragments] for FIT image.
98* `RESOURCE_xxx_pn-aktualizr` - controls maximum resource usage of the aktualizr service, when `aktualizr-resource-control` is installed on the image. See <<aktualizr service resource control>> for details.
98 99
99== Usage 100== Usage
100 101
@@ -160,6 +161,19 @@ Second, you can write recipes to install additional config files with customized
160 161
161To use these recipes, you will need to add them to your image with a line such as `IMAGE_INSTALL_append = " aktualizr-log-debug "` in your `local.conf`. 162To use these recipes, you will need to add them to your image with a line such as `IMAGE_INSTALL_append = " aktualizr-log-debug "` in your `local.conf`.
162 163
164=== aktualizr service resource control
165
166With systemd based images, it is possible to set resource policies for the aktualizr service. The main use case is to provide a safeguard against resource exhaustion during an unforeseen failure scenario.
167
168To enable it, install `aktualizr-resource-control` on the target image and optionally override the default resource limits set in link:recipes-sota/aktualizr/aktualizr_git.bb[aktualizr_git.bb], from your `local.conf`.
169
170For example:
171
172....
173IMAGE_INSTALL_append += " aktualizr-resource-control "
174RESOURCE_CPU_WEIGHT_pn-aktualizr = "50"
175....
176
163== Development configuration 177== Development configuration
164 178
165There are a few settings that can be controlled in `local.conf` to simplify the development process: 179There are a few settings that can be controlled in `local.conf` to simplify the development process:
@@ -214,7 +228,7 @@ sudo apt install ovmf
2145. Run oe-selftest: 2285. Run oe-selftest:
215+ 229+
216``` 230```
217oe-selftest --run-tests updater 231oe-selftest -r updater_native updater_qemux86_64 updater_minnowboard updater_raspberrypi
218``` 232```
219 233
220For more information about oe-selftest, including details about how to run individual test modules or classes, please refer to the https://wiki.yoctoproject.org/wiki/Oe-selftest[Yocto Project wiki]. 234For more information about oe-selftest, including details about how to run individual test modules or classes, please refer to the https://wiki.yoctoproject.org/wiki/Oe-selftest[Yocto Project wiki].
diff --git a/lib/oeqa/selftest/cases/testutils.py b/lib/oeqa/selftest/cases/testutils.py
new file mode 100644
index 0000000..90ba653
--- /dev/null
+++ b/lib/oeqa/selftest/cases/testutils.py
@@ -0,0 +1,128 @@
1import os
2import logging
3import re
4import subprocess
5from time import sleep
6
7from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
8from qemucommand import QemuCommand
9
10
11def qemu_launch(efi=False, machine=None, imagename=None):
12 logger = logging.getLogger("selftest")
13 if imagename is None:
14 imagename = 'core-image-minimal'
15 logger.info('Running bitbake to build {}'.format(imagename))
16 bitbake(imagename)
17 # Create empty object.
18 args = type('', (), {})()
19 args.imagename = imagename
20 args.mac = None
21 # Could use DEPLOY_DIR_IMAGE here but it's already in the machine
22 # subdirectory.
23 args.dir = 'tmp/deploy/images'
24 args.efi = efi
25 args.machine = machine
26 qemu_use_kvm = get_bb_var("QEMU_USE_KVM")
27 if qemu_use_kvm and \
28 (qemu_use_kvm == 'True' and 'x86' in machine or
29 get_bb_var('MACHINE') in qemu_use_kvm.split()):
30 args.kvm = True
31 else:
32 args.kvm = None # Autodetect
33 args.no_gui = True
34 args.gdb = False
35 args.pcap = None
36 args.overlay = None
37 args.dry_run = False
38 args.secondary_network = False
39
40 qemu = QemuCommand(args)
41 cmdline = qemu.command_line()
42 print('Booting image with run-qemu-ota...')
43 s = subprocess.Popen(cmdline)
44 sleep(10)
45 return qemu, s
46
47
48def qemu_terminate(s):
49 try:
50 s.terminate()
51 except KeyboardInterrupt:
52 pass
53
54
55def qemu_send_command(port, command):
56 command = ['ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@localhost -p ' +
57 str(port) + ' "' + command + '"']
58 s2 = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
59 stdout, stderr = s2.communicate(timeout=60)
60 return stdout, stderr, s2.returncode
61
62
63def akt_native_run(testInst, cmd, **kwargs):
64 # run a command supplied by aktualizr-native and checks that:
65 # - the executable exists
66 # - the command runs without error
67 # NOTE: the base test class must have built aktualizr-native (in
68 # setUpClass, for example)
69 bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'],
70 'aktualizr-native')
71 sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix']
72 sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir']
73 libdir = bb_vars['libdir']
74
75 program, *_ = cmd.split(' ')
76 p = '{}/{}'.format(sysrootbin, program)
77 testInst.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p))
78 env = dict(os.environ)
79 env['LD_LIBRARY_PATH'] = libdir
80 result = runCmd(cmd, env=env, native_sysroot=sysroot, ignore_status=True, **kwargs)
81 testInst.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output)
82
83
84def verifyNotProvisioned(testInst, machine):
85 print('Checking output of aktualizr-info:')
86 ran_ok = False
87 for delay in [5, 5, 5, 5, 10, 10, 10, 10]:
88 stdout, stderr, retcode = testInst.qemu_command('aktualizr-info')
89 if retcode == 0 and stderr == b'':
90 ran_ok = True
91 break
92 sleep(delay)
93 testInst.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode())
94
95 # Verify that device has NOT yet provisioned.
96 testInst.assertIn(b'Couldn\'t load device ID', stdout,
97 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
98 testInst.assertIn(b'Couldn\'t load ECU serials', stdout,
99 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
100 testInst.assertIn(b'Provisioned on server: no', stdout,
101 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
102 testInst.assertIn(b'Fetched metadata: no', stdout,
103 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
104
105
106def verifyProvisioned(testInst, machine):
107 # Verify that device HAS provisioned.
108 ran_ok = False
109 for delay in [5, 5, 5, 5, 10, 10, 10, 10]:
110 stdout, stderr, retcode = testInst.qemu_command('aktualizr-info')
111 if retcode == 0 and stderr == b'' and stdout.decode().find('Fetched metadata: yes') >= 0:
112 ran_ok = True
113 break
114 sleep(delay)
115 testInst.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode())
116
117 testInst.assertIn(b'Device ID: ', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode())
118 testInst.assertIn(b'Primary ecu hardware ID: ' + machine.encode(), stdout,
119 'Provisioning failed: ' + stderr.decode() + stdout.decode())
120 testInst.assertIn(b'Fetched metadata: yes', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode())
121 p = re.compile(r'Device ID: ([a-z0-9-]*)\n')
122 m = p.search(stdout.decode())
123 testInst.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode())
124 testInst.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode())
125 logger = logging.getLogger("selftest")
126 logger.info('Device successfully provisioned with ID: ' + m.group(1))
127
128# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/oeqa/selftest/cases/updater_minnowboard.py b/lib/oeqa/selftest/cases/updater_minnowboard.py
new file mode 100644
index 0000000..f5df584
--- /dev/null
+++ b/lib/oeqa/selftest/cases/updater_minnowboard.py
@@ -0,0 +1,60 @@
1import os
2import re
3
4from oeqa.selftest.case import OESelftestTestCase
5from oeqa.utils.commands import runCmd, get_bb_var
6from testutils import qemu_launch, qemu_send_command, qemu_terminate, verifyProvisioned
7
8
9class MinnowTests(OESelftestTestCase):
10
11 def setUpLocal(self):
12 layer_intel = "meta-intel"
13 layer_minnow = "meta-updater-minnowboard"
14 result = runCmd('bitbake-layers show-layers')
15 # Assume the directory layout for finding other layers. We could also
16 # make assumptions by using 'show-layers', but either way, if the
17 # layers we need aren't where we expect them, we are out of luck.
18 path = os.path.abspath(os.path.dirname(__file__))
19 metadir = path + "/../../../../../"
20 if re.search(layer_intel, result.output) is None:
21 self.meta_intel = metadir + layer_intel
22 runCmd('bitbake-layers add-layer "%s"' % self.meta_intel)
23 else:
24 self.meta_intel = None
25 if re.search(layer_minnow, result.output) is None:
26 self.meta_minnow = metadir + layer_minnow
27 runCmd('bitbake-layers add-layer "%s"' % self.meta_minnow)
28 else:
29 self.meta_minnow = None
30 self.append_config('MACHINE = "intel-corei7-64"')
31 self.append_config('OSTREE_BOOTLOADER = "grub"')
32 self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "')
33 self.qemu, self.s = qemu_launch(efi=True, machine='intel-corei7-64')
34
35 def tearDownLocal(self):
36 qemu_terminate(self.s)
37 if self.meta_intel:
38 runCmd('bitbake-layers remove-layer "%s"' % self.meta_intel, ignore_status=True)
39 if self.meta_minnow:
40 runCmd('bitbake-layers remove-layer "%s"' % self.meta_minnow, ignore_status=True)
41
42 def qemu_command(self, command):
43 return qemu_send_command(self.qemu.ssh_port, command)
44
45 def test_provisioning(self):
46 print('Checking machine name (hostname) of device:')
47 stdout, stderr, retcode = self.qemu_command('hostname')
48 self.assertEqual(retcode, 0, "Unable to check hostname. " +
49 "Is an ssh daemon (such as dropbear or openssh) installed on the device?")
50 machine = get_bb_var('MACHINE', 'core-image-minimal')
51 self.assertEqual(stderr, b'', 'Error: ' + stderr.decode())
52 # Strip off line ending.
53 value = stdout.decode()[:-1]
54 self.assertEqual(value, machine,
55 'MACHINE does not match hostname: ' + machine + ', ' + value +
56 '\nIs TianoCore ovmf installed on your host machine?')
57
58 verifyProvisioned(self, machine)
59
60# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/oeqa/selftest/cases/updater_native.py b/lib/oeqa/selftest/cases/updater_native.py
new file mode 100644
index 0000000..1fc9cb8
--- /dev/null
+++ b/lib/oeqa/selftest/cases/updater_native.py
@@ -0,0 +1,47 @@
1# pylint: disable=C0111,C0325
2import logging
3
4from oeqa.selftest.case import OESelftestTestCase
5from oeqa.utils.commands import runCmd, bitbake, get_bb_var
6from testutils import akt_native_run
7
8
9class SotaToolsTests(OESelftestTestCase):
10
11 @classmethod
12 def setUpClass(cls):
13 super(SotaToolsTests, cls).setUpClass()
14 logger = logging.getLogger("selftest")
15 logger.info('Running bitbake to build aktualizr-native tools')
16 bitbake('aktualizr-native')
17
18 def test_push_help(self):
19 akt_native_run(self, 'garage-push --help')
20
21 def test_deploy_help(self):
22 akt_native_run(self, 'garage-deploy --help')
23
24 def test_garagesign_help(self):
25 akt_native_run(self, 'garage-sign --help')
26
27
28class GeneralTests(OESelftestTestCase):
29
30 def test_feature_sota(self):
31 result = get_bb_var('DISTRO_FEATURES').find('sota')
32 self.assertNotEqual(result, -1, 'Feature "sota" not set at DISTRO_FEATURES')
33
34 def test_feature_usrmerge(self):
35 result = get_bb_var('DISTRO_FEATURES').find('usrmerge')
36 self.assertNotEqual(result, -1, 'Feature "sota" not set at DISTRO_FEATURES')
37
38 def test_feature_systemd(self):
39 result = get_bb_var('DISTRO_FEATURES').find('systemd')
40 self.assertNotEqual(result, -1, 'Feature "systemd" not set at DISTRO_FEATURES')
41
42 def test_java(self):
43 result = runCmd('which java', ignore_status=True)
44 self.assertEqual(result.status, 0,
45 "Java not found. Do you have a JDK installed on your host machine?")
46
47# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater_qemux86_64.py
index 473b2a8..bef6cdc 100644
--- a/lib/oeqa/selftest/cases/updater.py
+++ b/lib/oeqa/selftest/cases/updater_qemux86_64.py
@@ -2,48 +2,16 @@
2import os 2import os
3import logging 3import logging
4import re 4import re
5import subprocess
6import unittest 5import unittest
7from time import sleep 6from time import sleep
8 7
9from oeqa.selftest.case import OESelftestTestCase 8from oeqa.selftest.case import OESelftestTestCase
10from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars 9from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
11from qemucommand import QemuCommand 10from testutils import qemu_launch, qemu_send_command, qemu_terminate, \
12 11 akt_native_run, verifyNotProvisioned, verifyProvisioned
13
14class SotaToolsTests(OESelftestTestCase):
15
16 @classmethod
17 def setUpClass(cls):
18 super(SotaToolsTests, cls).setUpClass()
19 logger = logging.getLogger("selftest")
20 logger.info('Running bitbake to build aktualizr-native tools')
21 bitbake('aktualizr-native')
22
23 def test_push_help(self):
24 akt_native_run(self, 'garage-push --help')
25
26 def test_deploy_help(self):
27 akt_native_run(self, 'garage-deploy --help')
28
29 def test_garagesign_help(self):
30 akt_native_run(self, 'garage-sign --help')
31 12
32 13
33class GeneralTests(OESelftestTestCase): 14class GeneralTests(OESelftestTestCase):
34
35 def test_feature_sota(self):
36 result = get_bb_var('DISTRO_FEATURES').find('sota')
37 self.assertNotEqual(result, -1, 'Feature "sota" not set at DISTRO_FEATURES')
38
39 def test_feature_usrmerge(self):
40 result = get_bb_var('DISTRO_FEATURES').find('usrmerge')
41 self.assertNotEqual(result, -1, 'Feature "sota" not set at DISTRO_FEATURES')
42
43 def test_feature_systemd(self):
44 result = get_bb_var('DISTRO_FEATURES').find('systemd')
45 self.assertNotEqual(result, -1, 'Feature "systemd" not set at DISTRO_FEATURES')
46
47 def test_credentials(self): 15 def test_credentials(self):
48 logger = logging.getLogger("selftest") 16 logger = logging.getLogger("selftest")
49 logger.info('Running bitbake to build core-image-minimal') 17 logger.info('Running bitbake to build core-image-minimal')
@@ -62,11 +30,6 @@ class GeneralTests(OESelftestTestCase):
62 (deploydir, imagename), ignore_status=True) 30 (deploydir, imagename), ignore_status=True)
63 self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) 31 self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output)
64 32
65 def test_java(self):
66 result = runCmd('which java', ignore_status=True)
67 self.assertEqual(result.status, 0,
68 "Java not found. Do you have a JDK installed on your host machine?")
69
70 33
71class AktualizrToolsTests(OESelftestTestCase): 34class AktualizrToolsTests(OESelftestTestCase):
72 35
@@ -143,16 +106,6 @@ class AutoProvTests(OESelftestTestCase):
143 value = stdout.decode()[:-1] 106 value = stdout.decode()[:-1]
144 self.assertEqual(value, machine, 107 self.assertEqual(value, machine,
145 'MACHINE does not match hostname: ' + machine + ', ' + value) 108 'MACHINE does not match hostname: ' + machine + ', ' + value)
146 print(value)
147 print('Checking output of aktualizr-info:')
148 ran_ok = False
149 for delay in [1, 2, 5, 10, 15]:
150 stdout, stderr, retcode = self.qemu_command('aktualizr-info')
151 if retcode == 0 and stderr == b'':
152 ran_ok = True
153 break
154 sleep(delay)
155 self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode())
156 109
157 verifyProvisioned(self, machine) 110 verifyProvisioned(self, machine)
158 111
@@ -201,136 +154,6 @@ class ManualControlTests(OESelftestTestCase):
201 'Aktualizr should have run' + stderr.decode() + stdout.decode()) 154 'Aktualizr should have run' + stderr.decode() + stdout.decode())
202 155
203 156
204class RpiTests(OESelftestTestCase):
205
206 def setUpLocal(self):
207 # Add layers before changing the machine type, otherwise the sanity
208 # checker complains loudly.
209 layer_rpi = "meta-raspberrypi"
210 layer_upd_rpi = "meta-updater-raspberrypi"
211 result = runCmd('bitbake-layers show-layers')
212 # Assume the directory layout for finding other layers. We could also
213 # make assumptions by using 'show-layers', but either way, if the
214 # layers we need aren't where we expect them, we are out of luck.
215 path = os.path.abspath(os.path.dirname(__file__))
216 metadir = path + "/../../../../../"
217 if re.search(layer_rpi, result.output) is None:
218 self.meta_rpi = metadir + layer_rpi
219 runCmd('bitbake-layers add-layer "%s"' % self.meta_rpi)
220 else:
221 self.meta_rpi = None
222 if re.search(layer_upd_rpi, result.output) is None:
223 self.meta_upd_rpi = metadir + layer_upd_rpi
224 runCmd('bitbake-layers add-layer "%s"' % self.meta_upd_rpi)
225 else:
226 self.meta_upd_rpi = None
227
228 # This is trickier that I would've thought. The fundamental problem is
229 # that the qemu layer changes the u-boot file extension to .rom, but
230 # raspberrypi still expects .bin. To prevent this, the qemu layer must
231 # be temporarily removed if it is present. It has to be removed by name
232 # without the complete path, but to add it back when we are done, we
233 # need the full path.
234 p = re.compile(r'meta-updater-qemux86-64\s*(\S*meta-updater-qemux86-64)\s')
235 m = p.search(result.output)
236 if m and m.lastindex > 0:
237 self.meta_qemu = m.group(1)
238 runCmd('bitbake-layers remove-layer meta-updater-qemux86-64')
239 else:
240 self.meta_qemu = None
241
242 self.append_config('MACHINE = "raspberrypi3"')
243 self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "')
244
245 def tearDownLocal(self):
246 if self.meta_qemu:
247 runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu, ignore_status=True)
248 if self.meta_upd_rpi:
249 runCmd('bitbake-layers remove-layer "%s"' % self.meta_upd_rpi, ignore_status=True)
250 if self.meta_rpi:
251 runCmd('bitbake-layers remove-layer "%s"' % self.meta_rpi, ignore_status=True)
252
253 def test_rpi(self):
254 logger = logging.getLogger("selftest")
255 logger.info('Running bitbake to build core-image-minimal')
256 self.append_config('SOTA_CLIENT_PROV = "aktualizr-auto-prov"')
257 bitbake('core-image-minimal')
258 credentials = get_bb_var('SOTA_PACKED_CREDENTIALS')
259 # Skip the test if the variable SOTA_PACKED_CREDENTIALS is not set.
260 if credentials is None:
261 raise unittest.SkipTest("Variable 'SOTA_PACKED_CREDENTIALS' not set.")
262 # Check if the file exists.
263 self.assertTrue(os.path.isfile(credentials), "File %s does not exist" % credentials)
264 deploydir = get_bb_var('DEPLOY_DIR_IMAGE')
265 imagename = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal')
266 # Check if the credentials are included in the output image.
267 result = runCmd('tar -jtvf %s/%s.tar.bz2 | grep sota_provisioning_credentials.zip' %
268 (deploydir, imagename), ignore_status=True)
269 self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output)
270
271
272class GrubTests(OESelftestTestCase):
273
274 def setUpLocal(self):
275 layer_intel = "meta-intel"
276 layer_minnow = "meta-updater-minnowboard"
277 result = runCmd('bitbake-layers show-layers')
278 # Assume the directory layout for finding other layers. We could also
279 # make assumptions by using 'show-layers', but either way, if the
280 # layers we need aren't where we expect them, we are out of luck.
281 path = os.path.abspath(os.path.dirname(__file__))
282 metadir = path + "/../../../../../"
283 if re.search(layer_intel, result.output) is None:
284 self.meta_intel = metadir + layer_intel
285 runCmd('bitbake-layers add-layer "%s"' % self.meta_intel)
286 else:
287 self.meta_intel = None
288 if re.search(layer_minnow, result.output) is None:
289 self.meta_minnow = metadir + layer_minnow
290 runCmd('bitbake-layers add-layer "%s"' % self.meta_minnow)
291 else:
292 self.meta_minnow = None
293 self.append_config('MACHINE = "intel-corei7-64"')
294 self.append_config('OSTREE_BOOTLOADER = "grub"')
295 self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "')
296 self.qemu, self.s = qemu_launch(efi=True, machine='intel-corei7-64')
297
298 def tearDownLocal(self):
299 qemu_terminate(self.s)
300 if self.meta_intel:
301 runCmd('bitbake-layers remove-layer "%s"' % self.meta_intel, ignore_status=True)
302 if self.meta_minnow:
303 runCmd('bitbake-layers remove-layer "%s"' % self.meta_minnow, ignore_status=True)
304
305 def qemu_command(self, command):
306 return qemu_send_command(self.qemu.ssh_port, command)
307
308 def test_grub(self):
309 print('Checking machine name (hostname) of device:')
310 stdout, stderr, retcode = self.qemu_command('hostname')
311 self.assertEqual(retcode, 0, "Unable to check hostname. " +
312 "Is an ssh daemon (such as dropbear or openssh) installed on the device?")
313 machine = get_bb_var('MACHINE', 'core-image-minimal')
314 self.assertEqual(stderr, b'', 'Error: ' + stderr.decode())
315 # Strip off line ending.
316 value = stdout.decode()[:-1]
317 self.assertEqual(value, machine,
318 'MACHINE does not match hostname: ' + machine + ', ' + value +
319 '\nIs TianoCore ovmf installed on your host machine?')
320 print(value)
321 print('Checking output of aktualizr-info:')
322 ran_ok = False
323 for delay in [1, 2, 5, 10, 15]:
324 stdout, stderr, retcode = self.qemu_command('aktualizr-info')
325 if retcode == 0 and stderr == b'':
326 ran_ok = True
327 break
328 sleep(delay)
329 self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode())
330
331 verifyProvisioned(self, machine)
332
333
334class ImplProvTests(OESelftestTestCase): 157class ImplProvTests(OESelftestTestCase):
335 158
336 def setUpLocal(self): 159 def setUpLocal(self):
@@ -371,25 +194,8 @@ class ImplProvTests(OESelftestTestCase):
371 value = stdout.decode()[:-1] 194 value = stdout.decode()[:-1]
372 self.assertEqual(value, machine, 195 self.assertEqual(value, machine,
373 'MACHINE does not match hostname: ' + machine + ', ' + value) 196 'MACHINE does not match hostname: ' + machine + ', ' + value)
374 print(value) 197
375 print('Checking output of aktualizr-info:') 198 verifyNotProvisioned(self, machine)
376 ran_ok = False
377 for delay in [1, 2, 5, 10, 15]:
378 stdout, stderr, retcode = self.qemu_command('aktualizr-info')
379 if retcode == 0 and stderr == b'':
380 ran_ok = True
381 break
382 sleep(delay)
383 self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode())
384 # Verify that device has NOT yet provisioned.
385 self.assertIn(b'Couldn\'t load device ID', stdout,
386 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
387 self.assertIn(b'Couldn\'t load ECU serials', stdout,
388 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
389 self.assertIn(b'Provisioned on server: no', stdout,
390 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
391 self.assertIn(b'Fetched metadata: no', stdout,
392 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
393 199
394 # Run aktualizr-cert-provider. 200 # Run aktualizr-cert-provider.
395 bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') 201 bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native')
@@ -446,25 +252,8 @@ class HsmTests(OESelftestTestCase):
446 value = stdout.decode()[:-1] 252 value = stdout.decode()[:-1]
447 self.assertEqual(value, machine, 253 self.assertEqual(value, machine,
448 'MACHINE does not match hostname: ' + machine + ', ' + value) 254 'MACHINE does not match hostname: ' + machine + ', ' + value)
449 print(value) 255
450 print('Checking output of aktualizr-info:') 256 verifyNotProvisioned(self, machine)
451 ran_ok = False
452 for delay in [1, 2, 5, 10, 15]:
453 stdout, stderr, retcode = self.qemu_command('aktualizr-info')
454 if retcode == 0 and stderr == b'':
455 ran_ok = True
456 break
457 sleep(delay)
458 self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode())
459 # Verify that device has NOT yet provisioned.
460 self.assertIn(b'Couldn\'t load device ID', stdout,
461 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
462 self.assertIn(b'Couldn\'t load ECU serials', stdout,
463 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
464 self.assertIn(b'Provisioned on server: no', stdout,
465 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
466 self.assertIn(b'Fetched metadata: no', stdout,
467 'Device already provisioned!? ' + stderr.decode() + stdout.decode())
468 257
469 # Verify that HSM is not yet initialized. 258 # Verify that HSM is not yet initialized.
470 pkcs11_command = 'pkcs11-tool --module=/usr/lib/softhsm/libsofthsm2.so -O' 259 pkcs11_command = 'pkcs11-tool --module=/usr/lib/softhsm/libsofthsm2.so -O'
@@ -474,7 +263,7 @@ class HsmTests(OESelftestTestCase):
474 softhsm2_command = 'softhsm2-util --show-slots' 263 softhsm2_command = 'softhsm2-util --show-slots'
475 stdout, stderr, retcode = self.qemu_command(softhsm2_command) 264 stdout, stderr, retcode = self.qemu_command(softhsm2_command)
476 self.assertNotEqual(retcode, 0, 'softhsm2-tool succeeded before initialization: ' + 265 self.assertNotEqual(retcode, 0, 'softhsm2-tool succeeded before initialization: ' +
477 stdout.decode() + stderr.decode()) 266 stdout.decode() + stderr.decode())
478 267
479 # Run aktualizr-cert-provider. 268 # Run aktualizr-cert-provider.
480 bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') 269 bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native')
@@ -521,13 +310,6 @@ class HsmTests(OESelftestTestCase):
521 310
522 311
523class SecondaryTests(OESelftestTestCase): 312class SecondaryTests(OESelftestTestCase):
524 @classmethod
525 def setUpClass(cls):
526 super(SecondaryTests, cls).setUpClass()
527 logger = logging.getLogger("selftest")
528 logger.info('Running bitbake to build secondary-image')
529 bitbake('secondary-image')
530
531 def setUpLocal(self): 313 def setUpLocal(self):
532 layer = "meta-updater-qemux86-64" 314 layer = "meta-updater-qemux86-64"
533 result = runCmd('bitbake-layers show-layers') 315 result = runCmd('bitbake-layers show-layers')
@@ -566,13 +348,6 @@ class SecondaryTests(OESelftestTestCase):
566 348
567 349
568class PrimaryTests(OESelftestTestCase): 350class PrimaryTests(OESelftestTestCase):
569 @classmethod
570 def setUpClass(cls):
571 super(PrimaryTests, cls).setUpClass()
572 logger = logging.getLogger("selftest")
573 logger.info('Running bitbake to build primary-image')
574 bitbake('primary-image')
575
576 def setUpLocal(self): 351 def setUpLocal(self):
577 layer = "meta-updater-qemux86-64" 352 layer = "meta-updater-qemux86-64"
578 result = runCmd('bitbake-layers show-layers') 353 result = runCmd('bitbake-layers show-layers')
@@ -606,99 +381,48 @@ class PrimaryTests(OESelftestTestCase):
606 self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) 381 self.assertEqual(stderr, b'', 'Error: ' + stderr.decode())
607 382
608 383
609def qemu_launch(efi=False, machine=None, imagename=None): 384class ResourceControlTests(OESelftestTestCase):
610 logger = logging.getLogger("selftest") 385 def setUpLocal(self):
611 logger.info('Running bitbake to build core-image-minimal') 386 layer = "meta-updater-qemux86-64"
612 bitbake('core-image-minimal') 387 result = runCmd('bitbake-layers show-layers')
613 # Create empty object. 388 if re.search(layer, result.output) is None:
614 args = type('', (), {})() 389 # Assume the directory layout for finding other layers. We could also
615 if imagename: 390 # make assumptions by using 'show-layers', but either way, if the
616 args.imagename = imagename 391 # layers we need aren't where we expect them, we are out of luck.
617 else: 392 path = os.path.abspath(os.path.dirname(__file__))
618 args.imagename = 'core-image-minimal' 393 metadir = path + "/../../../../../"
619 args.mac = None 394 self.meta_qemu = metadir + layer
620 # Could use DEPLOY_DIR_IMAGE here but it's already in the machine 395 runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu)
621 # subdirectory. 396 else:
622 args.dir = 'tmp/deploy/images' 397 self.meta_qemu = None
623 args.efi = efi 398 self.append_config('MACHINE = "qemux86-64"')
624 args.machine = machine 399 self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "')
625 qemu_use_kvm = get_bb_var("QEMU_USE_KVM") 400 self.append_config('IMAGE_INSTALL_append += " aktualizr-resource-control "')
626 if qemu_use_kvm and \ 401 self.append_config('RESOURCE_CPU_WEIGHT_pn-aktualizr = "1000"')
627 (qemu_use_kvm == 'True' and 'x86' in machine or \ 402 self.append_config('RESOURCE_MEMORY_HIGH_pn-aktualizr = "50M"')
628 get_bb_var('MACHINE') in qemu_use_kvm.split()): 403 self.append_config('RESOURCE_MEMORY_MAX_pn-aktualizr = "1M"')
629 args.kvm = True 404 self.qemu, self.s = qemu_launch(machine='qemux86-64')
630 else: 405
631 args.kvm = None # Autodetect 406 def tearDownLocal(self):
632 args.no_gui = True 407 qemu_terminate(self.s)
633 args.gdb = False 408 if self.meta_qemu:
634 args.pcap = None 409 runCmd('bitbake-layers remove-layer "%s"' % self.meta_qemu, ignore_status=True)
635 args.overlay = None 410
636 args.dry_run = False 411 def qemu_command(self, command):
637 args.secondary_network = False 412 return qemu_send_command(self.qemu.ssh_port, command)
638 413
639 qemu = QemuCommand(args) 414 def test_aktualizr_resource_control(self):
640 cmdline = qemu.command_line() 415 print('Checking aktualizr was killed')
641 print('Booting image with run-qemu-ota...') 416 stdout, stderr, retcode = self.qemu_command('systemctl --no-pager show aktualizr')
642 s = subprocess.Popen(cmdline) 417 self.assertIn(b'CPUWeight=1000', stdout, 'CPUWeight was not set correctly')
643 sleep(10) 418 self.assertIn(b'MemoryHigh=52428800', stdout, 'MemoryHigh was not set correctly')
644 return qemu, s 419 self.assertIn(b'MemoryMax=1048576', stdout, 'MemoryMax was not set correctly')
645 420 self.assertIn(b'ExecMainStatus=9', stdout, 'Aktualizr was not killed')
646 421
647def qemu_terminate(s): 422 self.qemu_command('systemctl --runtime set-property aktualizr MemoryMax=')
648 try: 423 self.qemu_command('systemctl restart aktualizr')
649 s.terminate()
650 except KeyboardInterrupt:
651 pass
652
653
654def qemu_send_command(port, command):
655 command = ['ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@localhost -p ' +
656 str(port) + ' "' + command + '"']
657 s2 = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
658 stdout, stderr = s2.communicate(timeout=60)
659 return stdout, stderr, s2.returncode
660
661
662def akt_native_run(testInst, cmd, **kwargs):
663 # run a command supplied by aktualizr-native and checks that:
664 # - the executable exists
665 # - the command runs without error
666 # NOTE: the base test class must have built aktualizr-native (in
667 # setUpClass, for example)
668 bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'],
669 'aktualizr-native')
670 sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix']
671 sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir']
672 libdir = bb_vars['libdir']
673
674 program, *_ = cmd.split(' ')
675 p = '{}/{}'.format(sysrootbin, program)
676 testInst.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p))
677 env = dict(os.environ)
678 env['LD_LIBRARY_PATH'] = libdir
679 result = runCmd(cmd, env=env, native_sysroot=sysroot, ignore_status=True, **kwargs)
680 testInst.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output)
681
682
683def verifyProvisioned(testInst, machine):
684 # Verify that device HAS provisioned.
685 ran_ok = False
686 for delay in [5, 5, 5, 5, 10, 10, 10, 10]:
687 stdout, stderr, retcode = testInst.qemu_command('aktualizr-info')
688 if retcode == 0 and stderr == b'' and stdout.decode().find('Fetched metadata: yes') >= 0:
689 ran_ok = True
690 break
691 sleep(delay)
692 testInst.assertIn(b'Device ID: ', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode())
693 testInst.assertIn(b'Primary ecu hardware ID: ' + machine.encode(), stdout,
694 'Provisioning failed: ' + stderr.decode() + stdout.decode())
695 testInst.assertIn(b'Fetched metadata: yes', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode())
696 p = re.compile(r'Device ID: ([a-z0-9-]*)\n')
697 m = p.search(stdout.decode())
698 testInst.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode())
699 testInst.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode())
700 logger = logging.getLogger("selftest")
701 logger.info('Device successfully provisioned with ID: ' + m.group(1))
702 424
425 stdout, stderr, retcode = self.qemu_command('systemctl --no-pager show --property=ExecMainStatus aktualizr')
426 self.assertIn(b'ExecMainStatus=0', stdout, 'Aktualizr did not restart')
703 427
704# vim:set ts=4 sw=4 sts=4 expandtab: 428# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/oeqa/selftest/cases/updater_raspberrypi.py b/lib/oeqa/selftest/cases/updater_raspberrypi.py
new file mode 100644
index 0000000..bb7cfa3
--- /dev/null
+++ b/lib/oeqa/selftest/cases/updater_raspberrypi.py
@@ -0,0 +1,78 @@
1# pylint: disable=C0111,C0325
2import os
3import logging
4import re
5import unittest
6
7from oeqa.selftest.case import OESelftestTestCase
8from oeqa.utils.commands import runCmd, bitbake, get_bb_var
9
10
11class RpiTests(OESelftestTestCase):
12
13 def setUpLocal(self):
14 # Add layers before changing the machine type, otherwise the sanity
15 # checker complains loudly.
16 layer_rpi = "meta-raspberrypi"
17 layer_upd_rpi = "meta-updater-raspberrypi"
18 result = runCmd('bitbake-layers show-layers')
19 # Assume the directory layout for finding other layers. We could also
20 # make assumptions by using 'show-layers', but either way, if the
21 # layers we need aren't where we expect them, we are out of luck.
22 path = os.path.abspath(os.path.dirname(__file__))
23 metadir = path + "/../../../../../"
24 if re.search(layer_rpi, result.output) is None:
25 self.meta_rpi = metadir + layer_rpi
26 runCmd('bitbake-layers add-layer "%s"' % self.meta_rpi)
27 else:
28 self.meta_rpi = None
29 if re.search(layer_upd_rpi, result.output) is None:
30 self.meta_upd_rpi = metadir + layer_upd_rpi
31 runCmd('bitbake-layers add-layer "%s"' % self.meta_upd_rpi)
32 else:
33 self.meta_upd_rpi = None
34
35 # This is trickier that I would've thought. The fundamental problem is
36 # that the qemu layer changes the u-boot file extension to .rom, but
37 # raspberrypi still expects .bin. To prevent this, the qemu layer must
38 # be temporarily removed if it is present. It has to be removed by name
39 # without the complete path, but to add it back when we are done, we
40 # need the full path.
41 p = re.compile(r'meta-updater-qemux86-64\s*(\S*meta-updater-qemux86-64)\s')
42 m = p.search(result.output)
43 if m and m.lastindex > 0:
44 self.meta_qemu = m.group(1)
45 runCmd('bitbake-layers remove-layer meta-updater-qemux86-64')
46 else:
47 self.meta_qemu = None
48
49 self.append_config('MACHINE = "raspberrypi3"')
50 self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "')
51
52 def tearDownLocal(self):
53 if self.meta_qemu:
54 runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu, ignore_status=True)
55 if self.meta_upd_rpi:
56 runCmd('bitbake-layers remove-layer "%s"' % self.meta_upd_rpi, ignore_status=True)
57 if self.meta_rpi:
58 runCmd('bitbake-layers remove-layer "%s"' % self.meta_rpi, ignore_status=True)
59
60 def test_build(self):
61 logger = logging.getLogger("selftest")
62 logger.info('Running bitbake to build core-image-minimal')
63 self.append_config('SOTA_CLIENT_PROV = "aktualizr-auto-prov"')
64 bitbake('core-image-minimal')
65 credentials = get_bb_var('SOTA_PACKED_CREDENTIALS')
66 # Skip the test if the variable SOTA_PACKED_CREDENTIALS is not set.
67 if credentials is None:
68 raise unittest.SkipTest("Variable 'SOTA_PACKED_CREDENTIALS' not set.")
69 # Check if the file exists.
70 self.assertTrue(os.path.isfile(credentials), "File %s does not exist" % credentials)
71 deploydir = get_bb_var('DEPLOY_DIR_IMAGE')
72 imagename = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal')
73 # Check if the credentials are included in the output image.
74 result = runCmd('tar -jtvf %s/%s.tar.bz2 | grep sota_provisioning_credentials.zip' %
75 (deploydir, imagename), ignore_status=True)
76 self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output)
77
78# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb b/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb
index 1a515a2..0700ac6 100644
--- a/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb
+++ b/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb
@@ -4,7 +4,7 @@ interfaces through systemd-networkd"
4LICENSE = "MPL-2.0" 4LICENSE = "MPL-2.0"
5LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" 5LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad"
6 6
7inherit systemd 7inherit allarch systemd
8 8
9RPROVIDES_${PN} = "virtual/network-configuration" 9RPROVIDES_${PN} = "virtual/network-configuration"
10 10
diff --git a/recipes-sota/aktualizr/aktualizr-auto-prov-creds.bb b/recipes-sota/aktualizr/aktualizr-auto-prov-creds.bb
index 0628a61..6b2dd27 100644
--- a/recipes-sota/aktualizr/aktualizr-auto-prov-creds.bb
+++ b/recipes-sota/aktualizr/aktualizr-auto-prov-creds.bb
@@ -3,6 +3,8 @@ SECTION = "base"
3LICENSE = "MPL-2.0" 3LICENSE = "MPL-2.0"
4LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" 4LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad"
5 5
6inherit allarch
7
6DEPENDS = "aktualizr-native zip-native" 8DEPENDS = "aktualizr-native zip-native"
7ALLOW_EMPTY_${PN} = "1" 9ALLOW_EMPTY_${PN} = "1"
8 10
diff --git a/recipes-sota/aktualizr/aktualizr-auto-prov.bb b/recipes-sota/aktualizr/aktualizr-auto-prov.bb
index 308f552..4b68491 100644
--- a/recipes-sota/aktualizr/aktualizr-auto-prov.bb
+++ b/recipes-sota/aktualizr/aktualizr-auto-prov.bb
@@ -5,6 +5,8 @@ SECTION = "base"
5LICENSE = "MPL-2.0" 5LICENSE = "MPL-2.0"
6LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" 6LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad"
7 7
8inherit allarch
9
8DEPENDS = "aktualizr-native zip-native" 10DEPENDS = "aktualizr-native zip-native"
9RDEPENDS_${PN}_append = "${@' aktualizr-auto-prov-creds' if d.getVar('SOTA_DEPLOY_CREDENTIALS') == '1' else ''}" 11RDEPENDS_${PN}_append = "${@' aktualizr-auto-prov-creds' if d.getVar('SOTA_DEPLOY_CREDENTIALS') == '1' else ''}"
10PV = "1.0" 12PV = "1.0"
diff --git a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb
index b9bb1f6..da17d77 100644
--- a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb
+++ b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb
@@ -3,6 +3,8 @@ SECTION = "base"
3LICENSE = "MPL-2.0" 3LICENSE = "MPL-2.0"
4LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" 4LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad"
5 5
6inherit allarch
7
6# WARNING: it is NOT a production solution. The secure way to provision devices 8# WARNING: it is NOT a production solution. The secure way to provision devices
7# is to create certificate request directly on the device (either with HSM/TPM 9# is to create certificate request directly on the device (either with HSM/TPM
8# or with software) and then sign it with a CA stored on a disconnected machine. 10# or with software) and then sign it with a CA stored on a disconnected machine.
diff --git a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb
index a932475..414cb5e 100644
--- a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb
+++ b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb
@@ -6,6 +6,8 @@ SECTION = "base"
6LICENSE = "MPL-2.0" 6LICENSE = "MPL-2.0"
7LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" 7LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad"
8 8
9inherit allarch
10
9DEPENDS = "aktualizr aktualizr-native openssl-native" 11DEPENDS = "aktualizr aktualizr-native openssl-native"
10RDEPENDS_${PN}_append = "${@' aktualizr-ca-implicit-prov-creds' if d.getVar('SOTA_DEPLOY_CREDENTIALS') == '1' else ''}" 12RDEPENDS_${PN}_append = "${@' aktualizr-ca-implicit-prov-creds' if d.getVar('SOTA_DEPLOY_CREDENTIALS') == '1' else ''}"
11 13
diff --git a/recipes-sota/aktualizr/aktualizr-hsm-prov.bb b/recipes-sota/aktualizr/aktualizr-hsm-prov.bb
index 27aba0f..77c6720 100644
--- a/recipes-sota/aktualizr/aktualizr-hsm-prov.bb
+++ b/recipes-sota/aktualizr/aktualizr-hsm-prov.bb
@@ -5,6 +5,8 @@ SECTION = "base"
5LICENSE = "MPL-2.0" 5LICENSE = "MPL-2.0"
6LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" 6LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad"
7 7
8inherit allarch
9
8DEPENDS = "aktualizr aktualizr-native" 10DEPENDS = "aktualizr aktualizr-native"
9RDEPENDS_${PN}_append = "${@' aktualizr-ca-implicit-prov-creds softhsm-testtoken' if d.getVar('SOTA_DEPLOY_CREDENTIALS') == '1' else ''}" 11RDEPENDS_${PN}_append = "${@' aktualizr-ca-implicit-prov-creds softhsm-testtoken' if d.getVar('SOTA_DEPLOY_CREDENTIALS') == '1' else ''}"
10 12
diff --git a/recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb b/recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb
index 305b5e5..d962876 100644
--- a/recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb
+++ b/recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb
@@ -3,12 +3,14 @@ HOMEPAGE = "https://github.com/advancedtelematic/aktualizr"
3SECTION = "base" 3SECTION = "base"
4LICENSE = "MPL-2.0" 4LICENSE = "MPL-2.0"
5LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" 5LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad"
6
7inherit allarch
8
6DEPENDS = "aktualizr-native" 9DEPENDS = "aktualizr-native"
7RDEPENDS_${PN} = "aktualizr" 10RDEPENDS_${PN} = "aktualizr"
8 11
9SRC_URI = "" 12SRC_URI = ""
10 13
11
12do_install() { 14do_install() {
13 install -m 0700 -d ${D}${libdir}/sota/conf.d 15 install -m 0700 -d ${D}${libdir}/sota/conf.d
14 install -m 0644 ${STAGING_DIR_NATIVE}${libdir}/sota/sota_uboot_env.toml ${D}${libdir}/sota/conf.d/30-rollback.toml 16 install -m 0644 ${STAGING_DIR_NATIVE}${libdir}/sota/sota_uboot_env.toml ${D}${libdir}/sota/conf.d/30-rollback.toml
diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb
index 49c4e5e..f2f62b5 100755
--- a/recipes-sota/aktualizr/aktualizr_git.bb
+++ b/recipes-sota/aktualizr/aktualizr_git.bb
@@ -25,6 +25,7 @@ SRC_URI = " \
25 file://aktualizr-secondary.service \ 25 file://aktualizr-secondary.service \
26 file://aktualizr-secondary.socket \ 26 file://aktualizr-secondary.socket \
27 file://aktualizr-serialcan.service \ 27 file://aktualizr-serialcan.service \
28 file://10-resource-control.conf \
28 ${@ d.expand("https://ats-tuf-cli-releases.s3-eu-central-1.amazonaws.com/cli-${GARAGE_SIGN_PV}.tgz;unpack=0") if d.getVar('GARAGE_SIGN_AUTOVERSION') != '1' else ''} \ 29 ${@ d.expand("https://ats-tuf-cli-releases.s3-eu-central-1.amazonaws.com/cli-${GARAGE_SIGN_PV}.tgz;unpack=0") if d.getVar('GARAGE_SIGN_AUTOVERSION') != '1' else ''} \
29 " 30 "
30 31
@@ -62,6 +63,15 @@ PACKAGECONFIG[load-tests] = "-DBUILD_LOAD_TESTS=ON,-DBUILD_LOAD_TESTS=OFF,"
62PACKAGECONFIG[serialcan] = ",,,slcand-start" 63PACKAGECONFIG[serialcan] = ",,,slcand-start"
63PACKAGECONFIG[ubootenv] = ",,,u-boot-fw-utils aktualizr-uboot-env-rollback" 64PACKAGECONFIG[ubootenv] = ",,,u-boot-fw-utils aktualizr-uboot-env-rollback"
64 65
66# can be overriden in configuration with `RESOURCE_xxx_pn-aktualizr`
67# see `man systemd.resource-control` for details
68
69# can be used to lower aktualizr priority, default is 100
70RESOURCE_CPU_WEIGHT = "100"
71# will be slowed down when it reaches 'high', killed when it reaches 'max'
72RESOURCE_MEMORY_HIGH = "100M"
73RESOURCE_MEMORY_MAX = "80%"
74
65do_compile_ptest() { 75do_compile_ptest() {
66 cmake_runcmake_build --target build_tests 76 cmake_runcmake_build --target build_tests
67} 77}
@@ -118,6 +128,15 @@ do_install_append () {
118 install -m 0755 ${B}/src/sota_tools/garage-sign/bin/* ${D}${bindir} 128 install -m 0755 ${B}/src/sota_tools/garage-sign/bin/* ${D}${bindir}
119 install -m 0644 ${B}/src/sota_tools/garage-sign/lib/* ${D}${libdir} 129 install -m 0644 ${B}/src/sota_tools/garage-sign/lib/* ${D}${libdir}
120 fi 130 fi
131
132 # resource control
133 install -d ${D}/${systemd_system_unitdir}/aktualizr.service.d
134 install -m 0644 ${WORKDIR}/10-resource-control.conf ${D}/${systemd_system_unitdir}/aktualizr.service.d
135
136 sed -i -e 's|@CPU_WEIGHT@|${RESOURCE_CPU_WEIGHT}|g' \
137 -e 's|@MEMORY_HIGH@|${RESOURCE_MEMORY_HIGH}|g' \
138 -e 's|@MEMORY_MAX@|${RESOURCE_MEMORY_MAX}|g' \
139 ${D}${systemd_system_unitdir}/aktualizr.service.d/10-resource-control.conf
121} 140}
122 141
123PACKAGESPLITFUNCS_prepend = "split_hosttools_packages " 142PACKAGESPLITFUNCS_prepend = "split_hosttools_packages "
@@ -132,7 +151,7 @@ python split_hosttools_packages () {
132 151
133PACKAGES_DYNAMIC = "^aktualizr-.* ^garage-.*" 152PACKAGES_DYNAMIC = "^aktualizr-.* ^garage-.*"
134 153
135PACKAGES =+ "${PN}-examples ${PN}-secondary ${PN}-configs ${PN}-host-tools" 154PACKAGES =+ "${PN}-resource-control ${PN}-examples ${PN}-secondary ${PN}-configs ${PN}-host-tools"
136 155
137ALLOW_EMPTY_${PN}-host-tools = "1" 156ALLOW_EMPTY_${PN}-host-tools = "1"
138 157
@@ -142,6 +161,10 @@ FILES_${PN} = " \
142 ${systemd_unitdir}/system/aktualizr.service \ 161 ${systemd_unitdir}/system/aktualizr.service \
143 " 162 "
144 163
164FILES_${PN}-resource-control = " \
165 ${systemd_system_unitdir}/aktualizr.service.d/10-resource-control.conf \
166 "
167
145FILES_${PN}-configs = " \ 168FILES_${PN}-configs = " \
146 ${sysconfdir}/sota/* \ 169 ${sysconfdir}/sota/* \
147 ${libdir}/sota/* \ 170 ${libdir}/sota/* \
@@ -157,6 +180,7 @@ FILES_${PN}-secondary = " \
157 ${systemd_unitdir}/system/aktualizr-secondary.socket \ 180 ${systemd_unitdir}/system/aktualizr-secondary.socket \
158 ${systemd_unitdir}/system/aktualizr-secondary.service \ 181 ${systemd_unitdir}/system/aktualizr-secondary.service \
159 " 182 "
183
160BBCLASSEXTEND = "native" 184BBCLASSEXTEND = "native"
161 185
162# vim:set ts=4 sw=4 sts=4 expandtab: 186# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/recipes-sota/aktualizr/files/10-resource-control.conf b/recipes-sota/aktualizr/files/10-resource-control.conf
new file mode 100644
index 0000000..254713c
--- /dev/null
+++ b/recipes-sota/aktualizr/files/10-resource-control.conf
@@ -0,0 +1,6 @@
1[Service]
2CPUAccounting=true
3CPUWeight=@CPU_WEIGHT@
4MemoryAccounting=true
5MemoryHigh=@MEMORY_HIGH@
6MemoryMax=@MEMORY_MAX@
diff --git a/recipes-sota/config/aktualizr-auto-reboot.bb b/recipes-sota/config/aktualizr-auto-reboot.bb
index ad4d17c..f360d9e 100644
--- a/recipes-sota/config/aktualizr-auto-reboot.bb
+++ b/recipes-sota/config/aktualizr-auto-reboot.bb
@@ -5,6 +5,8 @@ SECTION = "base"
5LICENSE = "MPL-2.0" 5LICENSE = "MPL-2.0"
6LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" 6LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad"
7 7
8inherit allarch
9
8SRC_URI = " \ 10SRC_URI = " \
9 file://35-enable-auto-reboot.toml \ 11 file://35-enable-auto-reboot.toml \
10 " 12 "
diff --git a/recipes-sota/config/aktualizr-disable-send-ip.bb b/recipes-sota/config/aktualizr-disable-send-ip.bb
index 8dd2647..07c12ca 100644
--- a/recipes-sota/config/aktualizr-disable-send-ip.bb
+++ b/recipes-sota/config/aktualizr-disable-send-ip.bb
@@ -5,6 +5,8 @@ SECTION = "base"
5LICENSE = "MPL-2.0" 5LICENSE = "MPL-2.0"
6LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" 6LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad"
7 7
8inherit allarch
9
8SRC_URI = " \ 10SRC_URI = " \
9 file://30-disable-send-ip.toml \ 11 file://30-disable-send-ip.toml \
10 " 12 "
diff --git a/recipes-sota/config/aktualizr-log-debug.bb b/recipes-sota/config/aktualizr-log-debug.bb
index 098faf4..0c03786 100644
--- a/recipes-sota/config/aktualizr-log-debug.bb
+++ b/recipes-sota/config/aktualizr-log-debug.bb
@@ -5,6 +5,8 @@ SECTION = "base"
5LICENSE = "MPL-2.0" 5LICENSE = "MPL-2.0"
6LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" 6LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad"
7 7
8inherit allarch
9
8SRC_URI = " \ 10SRC_URI = " \
9 file://05-log-debug.toml \ 11 file://05-log-debug.toml \
10 " 12 "
diff --git a/scripts/qemucommand.py b/scripts/qemucommand.py
index 4abfd4e..cafab6d 100644
--- a/scripts/qemucommand.py
+++ b/scripts/qemucommand.py
@@ -97,6 +97,8 @@ class QemuCommand(object):
97 "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port, 97 "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port,
98 "-m", "1G", 98 "-m", "1G",
99 "-usb", 99 "-usb",
100 "-object", "rng-random,id=rng0,filename=/dev/urandom",
101 "-device", "virtio-rng-pci,rng=rng0",
100 "-device", "usb-tablet", 102 "-device", "usb-tablet",
101 "-show-cursor", 103 "-show-cursor",
102 "-vga", "std", 104 "-vga", "std",