From 8bbf6da0170fb62f9cf5166e783a4c00ea0bfe62 Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Mon, 5 Feb 2018 16:36:24 +0100 Subject: Remove manual installation of /usr/lib/sota/schemas As of 6c0dd6c87f4f4027e9b89f9a9e0dc12ef386d39d these are installed with a normal 'make install' (via cmake) --- recipes-sota/aktualizr/aktualizr_git.bb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 82da19c..d795790 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -21,7 +21,7 @@ SRC_URI = " \ file://aktualizr.service \ file://aktualizr-serialcan.service \ " -SRCREV = "23eb094a8b3faaac7c0b2a85f902c67804a7d3d3" +SRCREV = "d861896e7467e3e0cafdd7384ff87c62fe724640" BRANCH ?= "master" S = "${WORKDIR}/git" @@ -49,9 +49,6 @@ do_install_append_class-target () { install -d ${D}${systemd_unitdir}/system aktualizr_service=${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'serialcan', '${WORKDIR}/aktualizr-serialcan.service', '${WORKDIR}/aktualizr.service', d)} install -m 0644 ${aktualizr_service} ${D}${systemd_unitdir}/system/aktualizr.service - - install -d ${D}${libdir}/sota/schemas - install -m 0755 ${S}/config/storage/* ${D}${libdir}/sota/schemas } do_install_append_class-native () { rm -f ${D}${bindir}/aktualizr @@ -66,19 +63,22 @@ do_install_append_class-native () { install -m 0644 ${B}/src/sota_tools/garage-sign-prefix/src/garage-sign/lib/* ${D}${libdir} } +FILES_${PN}_append = " \ + ${libdir}/sota \ + " + FILES_${PN}_class-target = " \ ${bindir}/aktualizr \ ${bindir}/aktualizr-info \ ${systemd_unitdir}/system/aktualizr.service \ - ${libdir}/sota/schemas \ " + FILES_${PN}_append_class-target = " ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-example', ' ${bindir}/example-interface', '', d)} " FILES_${PN}_append_class-target = " ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-isotp-example', ' ${bindir}/isotp-test-interface', '', d)} " FILES_${PN}_class-native = " \ ${bindir}/aktualizr_implicit_writer \ ${bindir}/garage-deploy \ ${bindir}/garage-push \ - ${libdir}/sota/* \ " # vim:set ts=4 sw=4 sts=4 expandtab: -- cgit v1.2.3-54-g00ecf From e31637bc9eae5e94509bee74c082882e4095a177 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Fri, 9 Feb 2018 11:06:40 +0100 Subject: Bump aktualizr and fix some installation complaints. --- recipes-sota/aktualizr/aktualizr_git.bb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 768ec3d..bed656a 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -21,7 +21,7 @@ SRC_URI = " \ file://aktualizr.service \ file://aktualizr-serialcan.service \ " -SRCREV = "d861896e7467e3e0cafdd7384ff87c62fe724640" +SRCREV = "32a04532c1b7434b9cab89b78df389059ac45d40" BRANCH ?= "master" S = "${WORKDIR}/git" @@ -39,6 +39,7 @@ EXTRA_OECMAKE_append_class-native = " -DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF " do_install_append () { rm -f ${D}${bindir}/aktualizr_cert_provider + rm -fr ${D}${libdir}/systemd } do_install_append_class-target () { rm -f ${D}${bindir}/aktualizr_implicit_writer -- cgit v1.2.3-54-g00ecf From 87d1414e124b352417b080971fc4c4412ab29aa9 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Fri, 9 Feb 2018 11:06:40 +0100 Subject: Bump aktualizr and fix some installation complaints. --- recipes-sota/aktualizr/aktualizr_git.bb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index d795790..97db19a 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -21,7 +21,7 @@ SRC_URI = " \ file://aktualizr.service \ file://aktualizr-serialcan.service \ " -SRCREV = "d861896e7467e3e0cafdd7384ff87c62fe724640" +SRCREV = "32a04532c1b7434b9cab89b78df389059ac45d40" BRANCH ?= "master" S = "${WORKDIR}/git" @@ -39,6 +39,7 @@ EXTRA_OECMAKE_append_class-native = " -DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF " do_install_append () { rm -f ${D}${bindir}/aktualizr_cert_provider + rm -fr ${D}${libdir}/systemd } do_install_append_class-target () { rm -f ${D}${bindir}/aktualizr_implicit_writer -- cgit v1.2.3-54-g00ecf From 9f2bbe9bcbc4468029b04383279bb5c35963c8a4 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Thu, 18 Jan 2018 18:36:33 +0100 Subject: Fix flag deprecation warning. Partial cherry-pick of 84baa1c3d8f996f7daf2d8aa3d26197378218f21 from rocko. --- scripts/qemucommand.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qemucommand.py b/scripts/qemucommand.py index 9a893d8..7ae9381 100644 --- a/scripts/qemucommand.py +++ b/scripts/qemucommand.py @@ -96,7 +96,7 @@ class QemuCommand(object): "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port, "-m", "1G", "-usb", - "-usbdevice", "tablet", + "-device", "usb-tablet", "-show-cursor", "-vga", "std", "-net", netuser, -- cgit v1.2.3-54-g00ecf From c2e9fcc8744b6c1f1af5941fd7d4546273361a91 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Fri, 19 Jan 2018 14:12:22 +0100 Subject: Add a helpful hint for the oe-selftest grub problem. Partial cherry-pick of b605cf215ff4cef35c3f62fee0ec14e3c8d5ba22 from rocko. --- lib/oeqa/selftest/updater.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index f28349f..b435d1b 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -161,7 +161,8 @@ class GrubTests(oeSelfTest): # Strip off line ending. value_str = value.decode()[:-1] self.assertEqual(value_str, machine, - 'MACHINE does not match hostname: ' + machine + ', ' + value_str) + 'MACHINE does not match hostname: ' + machine + ', ' + value_str + + '\nIs tianocore ovmf installed?') print(value_str) -- cgit v1.2.3-54-g00ecf From 3a4bdbcae17b1b2f2197c61a0d188336767e1c60 Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Fri, 1 Dec 2017 11:56:51 +0100 Subject: Add tests for aktualizr-info. Cherry-pick of c64b399633975bc05856e5eded519c4f22adfe44 from rocko. --- lib/oeqa/selftest/updater.py | 56 +++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index b435d1b..0962cb7 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -1,8 +1,9 @@ -import unittest +# pylint: disable=C0111,C0325 import os import logging import subprocess -import time +import unittest +from time import sleep from oeqa.selftest.base import oeSelfTest from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars @@ -49,11 +50,11 @@ class GeneralTests(oeSelfTest): def test_feature_sota(self): result = get_bb_var('DISTRO_FEATURES').find('sota') - self.assertNotEqual(result, -1, 'Feature "sota" not set at DISTRO_FEATURES'); + self.assertNotEqual(result, -1, 'Feature "sota" not set at DISTRO_FEATURES') def test_feature_systemd(self): result = get_bb_var('DISTRO_FEATURES').find('systemd') - self.assertNotEqual(result, -1, 'Feature "systemd" not set at DISTRO_FEATURES'); + self.assertNotEqual(result, -1, 'Feature "systemd" not set at DISTRO_FEATURES') def test_credentials(self): bitbake('core-image-minimal') @@ -66,7 +67,8 @@ class GeneralTests(oeSelfTest): deploydir = get_bb_var('DEPLOY_DIR_IMAGE') imagename = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal') # Check if the credentials are included in the output image - result = runCmd('tar -jtvf %s/%s.tar.bz2 | grep sota_provisioning_credentials.zip' % (deploydir, imagename), ignore_status=True) + result = runCmd('tar -jtvf %s/%s.tar.bz2 | grep sota_provisioning_credentials.zip' % + (deploydir, imagename), ignore_status=True) self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) def test_java(self): @@ -99,7 +101,7 @@ class GeneralTests(oeSelfTest): self.assertEqual(result.output, 'ERROR: Unable to find any package producing path /usr/bin/man') path2 = os.path.realpath(image_path) size2 = os.path.getsize(path2) - logger.info('Second image %s has size %i' % (path2, size2)) + logger.info('Second image %s has size %i', path2, size2) self.assertNotEqual(path1, path2, "Image paths are identical; image was not rebuilt.") self.assertNotEqual(size1, size2, "Image sizes are identical; image was not rebuilt.") @@ -114,14 +116,17 @@ class QemuTests(oeSelfTest): def tearDownClass(cls): qemu_terminate(cls.s) + def run_command(self, command): + return qemu_send_command(self.qemu.ssh_port, command) + def test_hostname(self): print('') print('Checking machine name (hostname) of device:') - value, err = qemu_send_command(self.qemu.ssh_port, 'hostname') + stdout, stderr, retcode = self.run_command('hostname') machine = get_bb_var('MACHINE', 'core-image-minimal') - self.assertEqual(err, b'', 'Error: ' + err.decode()) + self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. - value_str = value.decode()[:-1] + value_str = stdout.decode()[:-1] self.assertEqual(value_str, machine, 'MACHINE does not match hostname: ' + machine + ', ' + value_str) print(value_str) @@ -129,9 +134,26 @@ class QemuTests(oeSelfTest): def test_var_sota(self): print('') print('Checking contents of /var/sota:') - value, err = qemu_send_command(self.qemu.ssh_port, 'ls /var/sota') - self.assertEqual(err, b'', 'Error: ' + err.decode()) - print(value.decode()) + stdout, stderr, retcode = self.run_command('ls /var/sota') + self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) + self.assertEqual(retcode, 0) + print(stdout.decode()) + + def test_aktualizr_info(self): + print('Checking output of aktualizr-info:') + ran_ok = False + for delay in [0, 1, 2, 5, 10, 15]: + sleep(delay) + try: + stdout, stderr, retcode = self.run_command('aktualizr-info') + if retcode == 0 and stderr == b'': + ran_ok = True + break + except IOError as e: + print(e) + if not ran_ok: + print(stdout.decode()) + print(stderr.decode()) class GrubTests(oeSelfTest): @@ -155,9 +177,10 @@ class GrubTests(oeSelfTest): def test_grub(self): print('') print('Checking machine name (hostname) of device:') - value, err = qemu_send_command(self.qemu.ssh_port, 'hostname') + value, err, retcode = qemu_send_command(self.qemu.ssh_port, 'hostname') machine = get_bb_var('MACHINE', 'core-image-minimal') self.assertEqual(err, b'', 'Error: ' + err.decode()) + self.assertEqual(retcode, 0) # Strip off line ending. value_str = value.decode()[:-1] self.assertEqual(value_str, machine, @@ -190,7 +213,7 @@ def qemu_launch(efi=False, machine=None): cmdline = qemu.command_line() print('Booting image with run-qemu-ota...') s = subprocess.Popen(cmdline) - time.sleep(10) + sleep(10) return qemu, s def qemu_terminate(s): @@ -203,6 +226,7 @@ def qemu_send_command(port, command): command = ['ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@localhost -p ' + str(port) + ' "' + command + '"'] s2 = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - value, err = s2.communicate() - return value, err + stdout, stderr = s2.communicate() + return stdout, stderr, s2.returncode +# vim:set ts=4 sw=4 sts=4 expandtab: -- cgit v1.2.3-54-g00ecf From 2dbeaf315ff9cf8cce1d0a3276fd561163db6237 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Tue, 13 Feb 2018 17:06:51 +0100 Subject: Fix minor ovmf compilation bug only present in pyro. This does not appear to be a problem on rocko, and it wasn't a problem for me on pyro when I last checked less than a month ago. It actually only broke the native build. This has been fixed upstream at some point, anyway. --- ...e-c-string-with-NULL-instead-of-a-literal.patch | 25 ++++++++++++++++++++++ recipes-core/ovmf/ovmf_%.bbappend | 3 +++ 2 files changed, 28 insertions(+) create mode 100644 recipes-core/ovmf/files/0001-Compare-c-string-with-NULL-instead-of-a-literal.patch create mode 100644 recipes-core/ovmf/ovmf_%.bbappend diff --git a/recipes-core/ovmf/files/0001-Compare-c-string-with-NULL-instead-of-a-literal.patch b/recipes-core/ovmf/files/0001-Compare-c-string-with-NULL-instead-of-a-literal.patch new file mode 100644 index 0000000..6bdaf7e --- /dev/null +++ b/recipes-core/ovmf/files/0001-Compare-c-string-with-NULL-instead-of-a-literal.patch @@ -0,0 +1,25 @@ +From 6c730f3da7490ffbba5ad17af29ca44ed167cbfc Mon Sep 17 00:00:00 2001 +From: Patrick Vacek +Date: Tue, 13 Feb 2018 16:38:15 +0100 +Subject: [PATCH] Compare c-string with NULL instead of a literal. + +--- + BaseTools/Source/C/VfrCompile/VfrUtilityLib.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/BaseTools/Source/C/VfrCompile/VfrUtilityLib.cpp b/BaseTools/Source/C/VfrCompile/VfrUtilityLib.cpp +index 3ca57ed741..4fa066dd9f 100644 +--- a/BaseTools/Source/C/VfrCompile/VfrUtilityLib.cpp ++++ b/BaseTools/Source/C/VfrCompile/VfrUtilityLib.cpp +@@ -3372,7 +3372,7 @@ CVfrStringDB::GetVarStoreNameFormStringId ( + UINT8 BlockType; + EFI_HII_STRING_PACKAGE_HDR *PkgHeader; + +- if (mStringFileName == '\0' ) { ++ if (mStringFileName == NULL ) { + return NULL; + } + +-- +2.14.1 + diff --git a/recipes-core/ovmf/ovmf_%.bbappend b/recipes-core/ovmf/ovmf_%.bbappend new file mode 100644 index 0000000..142fc53 --- /dev/null +++ b/recipes-core/ovmf/ovmf_%.bbappend @@ -0,0 +1,3 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI_append = "file://0001-Compare-c-string-with-NULL-instead-of-a-literal.patch" -- cgit v1.2.3-54-g00ecf From a9d8688a9e7849c70f448abd3c4c44cec9e16a69 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Mon, 12 Feb 2018 14:01:47 +0100 Subject: No longer require engine-pkcs11. It was merged into the libp11 package. Bump aktualizr to use the correct default path (and fix some various OSTree issues). Add opensc as it was previously a transitive dependency. --- recipes-sota/aktualizr/aktualizr_git.bb | 3 +-- recipes-support/libp11/libp11_0.4.7.bb | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 97db19a..0194dbb 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -10,7 +10,6 @@ DEPENDS_append_class-target = "jansson ostree ${@bb.utils.contains('SOTA_CLIENT_ DEPENDS_append_class-native = "glib-2.0-native " RDEPENDS_${PN}_class-target = "lshw " -RDEPENDS_${PN}_append_class-target = "${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'hsm', ' engine-pkcs11', '', d)} " RDEPENDS_${PN}_append_class-target = " ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'serialcan', ' slcand-start', '', d)} " PV = "1.0+git${SRCPV}" @@ -21,7 +20,7 @@ SRC_URI = " \ file://aktualizr.service \ file://aktualizr-serialcan.service \ " -SRCREV = "32a04532c1b7434b9cab89b78df389059ac45d40" +SRCREV = "715dfc3410d46670174ee2f55613e8d953fbb1ae" BRANCH ?= "master" S = "${WORKDIR}/git" diff --git a/recipes-support/libp11/libp11_0.4.7.bb b/recipes-support/libp11/libp11_0.4.7.bb index 7d77e90..877a57e 100644 --- a/recipes-support/libp11/libp11_0.4.7.bb +++ b/recipes-support/libp11/libp11_0.4.7.bb @@ -7,6 +7,7 @@ SECTION = "Development/Libraries" LICENSE = "LGPLv2+" LIC_FILES_CHKSUM = "file://COPYING;md5=fad9b3332be894bab9bc501572864b29" DEPENDS = "libtool openssl" +RDEPENDS_${PN} += " opensc" SRC_URI = "git://github.com/OpenSC/libp11.git" SRCREV = "da725ab727342083478150a203a3c80c4551feb4" -- cgit v1.2.3-54-g00ecf From 9a404b4e60c3a9166d98491fed778c64a67150bc Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Tue, 13 Feb 2018 17:23:08 +0100 Subject: Only expect credentials in the image if using autoprov. The credentials test was failing if any other provisioning recipe was specified. --- lib/oeqa/selftest/updater.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 0962cb7..7e8a615 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -57,6 +57,7 @@ class GeneralTests(oeSelfTest): self.assertNotEqual(result, -1, 'Feature "systemd" not set at DISTRO_FEATURES') def test_credentials(self): + self.write_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') bitbake('core-image-minimal') credentials = get_bb_var('SOTA_PACKED_CREDENTIALS') # skip the test if the variable SOTA_PACKED_CREDENTIALS is not set -- cgit v1.2.3-54-g00ecf From 7bcbb8046672ff66ca7aa0bdf48460d1a11000c3 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Wed, 14 Feb 2018 17:08:52 +0100 Subject: Test that implicit_writer and cert_provider work. This required setting the LD_LIBRARY_PATH to get some dependencies that are liable to conflict with the host's normal installation. I adapted that for the sota_tools tests as well for good measure. Also, we now actually install cert_provider in the native build. --- lib/oeqa/selftest/updater.py | 42 +++++++++++++++++++++++---------- recipes-sota/aktualizr/aktualizr_git.bb | 3 ++- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 7e8a615..9a3efee 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -19,24 +19,27 @@ class SotaToolsTests(oeSelfTest): bitbake('aktualizr-native') def test_push_help(self): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'aktualizr-native') - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "garage-push" + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') + l = bb_vars['libdir'] + p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/garage-push" self.assertTrue(os.path.isfile(p), msg = "No garage-push found (%s)" % p) - result = runCmd('%s --help' % p, ignore_status=True) + result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) def test_deploy_help(self): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'aktualizr-native') - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "garage-deploy" + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') + l = bb_vars['libdir'] + p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/garage-deploy" self.assertTrue(os.path.isfile(p), msg = "No garage-deploy found (%s)" % p) - result = runCmd('%s --help' % p, ignore_status=True) + result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) def test_garagesign_help(self): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'aktualizr-native') - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "garage-sign" + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') + l = bb_vars['libdir'] + p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/garage-sign" self.assertTrue(os.path.isfile(p), msg = "No garage-sign found (%s)" % p) - result = runCmd('%s --help' % p, ignore_status=True) + result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) class HsmTests(oeSelfTest): @@ -76,6 +79,22 @@ class GeneralTests(oeSelfTest): result = runCmd('which java', ignore_status=True) self.assertEqual(result.status, 0, "Java not found.") + def test_implicit_writer_help(self): + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') + l = bb_vars['libdir'] + p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_implicit_writer" + self.assertTrue(os.path.isfile(p), msg = "No aktualizr_implicit_writer found (%s)" % p) + result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) + self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + + def test_cert_provider_help(self): + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') + l = bb_vars['libdir'] + p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_cert_provider" + self.assertTrue(os.path.isfile(p), msg = "No aktualizr_cert_provider found (%s)" % p) + result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) + self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + def test_add_package(self): print('') deploydir = get_bb_var('DEPLOY_DIR_IMAGE') @@ -152,9 +171,8 @@ class QemuTests(oeSelfTest): break except IOError as e: print(e) - if not ran_ok: - print(stdout.decode()) - print(stderr.decode()) + self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stdout.decode() + stderr.decode()) + class GrubTests(oeSelfTest): diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 0194dbb..bcc1438 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -37,10 +37,10 @@ EXTRA_OECMAKE_append_class-target = " -DBUILD_OSTREE=ON -DBUILD_ISOTP=ON ${@bb.u EXTRA_OECMAKE_append_class-native = " -DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF " do_install_append () { - rm -f ${D}${bindir}/aktualizr_cert_provider rm -fr ${D}${libdir}/systemd } do_install_append_class-target () { + rm -f ${D}${bindir}/aktualizr_cert_provider rm -f ${D}${bindir}/aktualizr_implicit_writer rm -f ${D}${libdir}/sota/sota.toml ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-example', '', 'rm -f ${D}${bindir}/example-interface', d)} @@ -76,6 +76,7 @@ FILES_${PN}_class-target = " \ FILES_${PN}_append_class-target = " ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-example', ' ${bindir}/example-interface', '', d)} " FILES_${PN}_append_class-target = " ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-isotp-example', ' ${bindir}/isotp-test-interface', '', d)} " FILES_${PN}_class-native = " \ + ${bindir}/aktualizr_cert_provider \ ${bindir}/aktualizr_implicit_writer \ ${bindir}/garage-deploy \ ${bindir}/garage-push \ -- cgit v1.2.3-54-g00ecf From 9e4918cff53c6154b5bcee2e28deca08280aff75 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Thu, 15 Feb 2018 12:05:55 +0100 Subject: Add test_cert_provider_local_output. Improve some organization and logging. --- lib/oeqa/selftest/updater.py | 71 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 9a3efee..83febb1 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -60,6 +60,8 @@ class GeneralTests(oeSelfTest): self.assertNotEqual(result, -1, 'Feature "systemd" not set at DISTRO_FEATURES') def test_credentials(self): + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build core-image-minimal') self.write_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') bitbake('core-image-minimal') credentials = get_bb_var('SOTA_PACKED_CREDENTIALS') @@ -79,22 +81,6 @@ class GeneralTests(oeSelfTest): result = runCmd('which java', ignore_status=True) self.assertEqual(result.status, 0, "Java not found.") - def test_implicit_writer_help(self): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') - l = bb_vars['libdir'] - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_implicit_writer" - self.assertTrue(os.path.isfile(p), msg = "No aktualizr_implicit_writer found (%s)" % p) - result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) - - def test_cert_provider_help(self): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') - l = bb_vars['libdir'] - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_cert_provider" - self.assertTrue(os.path.isfile(p), msg = "No aktualizr_cert_provider found (%s)" % p) - result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) - def test_add_package(self): print('') deploydir = get_bb_var('DEPLOY_DIR_IMAGE') @@ -126,6 +112,59 @@ class GeneralTests(oeSelfTest): self.assertNotEqual(size1, size2, "Image sizes are identical; image was not rebuilt.") +class AktualizrToolsTests(oeSelfTest): + + @classmethod + def setUpClass(cls): + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build aktualizr-native tools') + bitbake('aktualizr-native') + + def test_implicit_writer_help(self): + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') + l = bb_vars['libdir'] + p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_implicit_writer" + self.assertTrue(os.path.isfile(p), msg = "No aktualizr_implicit_writer found (%s)" % p) + result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) + self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + + def test_cert_provider_help(self): + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') + l = bb_vars['libdir'] + p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_cert_provider" + self.assertTrue(os.path.isfile(p), msg = "No aktualizr_cert_provider found (%s)" % p) + result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) + self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + + def test_cert_provider_local_output(self): + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build aktualizr-implicit-prov') + bitbake('aktualizr-implicit-prov') + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir', + 'SOTA_PACKED_CREDENTIALS', 'T'], 'aktualizr-native') + l = bb_vars['libdir'] + p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_cert_provider" + creds = bb_vars['SOTA_PACKED_CREDENTIALS'] + temp_dir = bb_vars['T'] + bb_vars_prov = get_bb_vars(['STAGING_DIR_NATIVE', 'libdir'], 'aktualizr-implicit-prov') + config = bb_vars_prov['STAGING_DIR_NATIVE'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov.toml' + self.assertTrue(os.path.isfile(p), msg = "No aktualizr_cert_provider found (%s)" % p) + command = 'LD_LIBRARY_PATH=' + l + ' ' + p + ' -c ' + creds + ' -r -l ' + temp_dir + ' -g ' + config + # logger.info('Checking output of: ' + command) + result = runCmd(command, ignore_status=True) + self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + # Might be nice if these names weren't hardcoded. + cert_path = temp_dir + '/client.pem' + self.assertTrue(os.path.isfile(cert_path), "Client certificate not found at %s." % cert_path) + self.assertTrue(os.path.getsize(cert_path) > 0, "Client certificate at %s is empty." % cert_path) + pkey_path = temp_dir + '/pkey.pem' + self.assertTrue(os.path.isfile(pkey_path), "Private key not found at %s." % pkey_path) + self.assertTrue(os.path.getsize(pkey_path) > 0, "Private key at %s is empty." % pkey_path) + ca_path = temp_dir + '/root.crt' + self.assertTrue(os.path.isfile(ca_path), "Client certificate not found at %s." % ca_path) + self.assertTrue(os.path.getsize(ca_path) > 0, "Client certificate at %s is empty." % ca_path) + + class QemuTests(oeSelfTest): @classmethod -- cgit v1.2.3-54-g00ecf From 586394dc9f7b5e97c827ea982dd69692f3ca0c97 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Tue, 13 Feb 2018 18:08:39 +0100 Subject: Test provisioning with HSM. --- lib/oeqa/selftest/updater.py | 95 ++++++++++++++++++++++++++++++--- recipes-sota/aktualizr/aktualizr_git.bb | 2 +- 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 83febb1..8ee8378 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -42,12 +42,6 @@ class SotaToolsTests(oeSelfTest): result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) -class HsmTests(oeSelfTest): - - def test_hsm(self): - self.write_config('SOTA_CLIENT_FEATURES="hsm"') - bitbake('core-image-minimal') - class GeneralTests(oeSelfTest): @@ -210,7 +204,7 @@ class QemuTests(oeSelfTest): break except IOError as e: print(e) - self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stdout.decode() + stderr.decode()) + self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) class GrubTests(oeSelfTest): @@ -247,6 +241,93 @@ class GrubTests(oeSelfTest): print(value_str) +class HsmTests(oeSelfTest): + + def setUpLocal(self): + self.write_config('SOTA_CLIENT_PROV = " aktualizr-hsm-prov "') + self.write_config('SOTA_CLIENT_FEATURES="hsm"') + self.qemu, self.s = qemu_launch(machine='qemux86-64') + + def tearDownLocal(self): + qemu_terminate(self.s) + + def run_command(self, command): + return qemu_send_command(self.qemu.ssh_port, command) + + def test_provisioning(self): + print('') + ran_ok = False + for delay in [0, 1, 2, 5, 10, 15]: + stdout, stderr, retcode = self.run_command('aktualizr-info') + if retcode == 0 and stderr == b'': + ran_ok = True + break + self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) + # Verify that device has NOT yet provisioned. + self.assertIn(b'Couldn\'t load device ID', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + self.assertIn(b'Couldn\'t load ECU serials', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + self.assertIn(b'Provisioned on server: no', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + self.assertIn(b'Fetched metadata: no', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + + pkcs11_command = 'pkcs11-tool --module=/usr/lib/softhsm/libsofthsm2.so -O' + stdout, stderr, retcode = self.run_command(pkcs11_command) + self.assertNotEqual(retcode, 0, 'pkcs11-tool succeeded before initialization: ' + + stdout.decode() + stderr.decode()) + softhsm2_command = 'softhsm2-util --show-slots' + stdout, stderr, retcode = self.run_command(softhsm2_command) + self.assertNotEqual(retcode, 0, 'softhsm2-tool succeeded before initialization: ' + + stdout.decode() + stderr.decode()) + + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir', + 'SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') + l = bb_vars['libdir'] + p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_cert_provider" + creds = bb_vars['SOTA_PACKED_CREDENTIALS'] + bb_vars_prov = get_bb_vars(['STAGING_DIR_NATIVE', 'libdir'], 'aktualizr-hsm-prov') + config = bb_vars_prov['STAGING_DIR_NATIVE'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov.toml' + self.assertTrue(os.path.isfile(p), msg = "No aktualizr_cert_provider found (%s)" % p) + command = ('LD_LIBRARY_PATH=' + l + ' ' + p + ' -c ' + creds + ' -t root@localhost -p ' + + str(self.qemu.ssh_port) + ' -r -s -g ' + config) + logger = logging.getLogger("selftest") + # logger.info('Checking output of: ' + command) + result = runCmd(command, ignore_status=True) + self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + + ran_ok = False + for delay in [5, 5, 5, 5, 10]: + sleep(delay) + p11_out, p11_err, p11_ret = self.run_command(pkcs11_command) + hsm_out, hsm_err, hsm_ret = self.run_command(softhsm2_command) + if p11_ret == 0 and hsm_ret == 0 and hsm_err == b'': + ran_ok = True + break + self.assertTrue(ran_ok, 'pkcs11-tool or softhsm2-tool failed: ' + p11_err.decode() + + p11_out.decode() + hsm_err.decode() + hsm_out.decode()) + self.assertIn(b'present token', p11_err, 'pkcs11-tool failed: ' + p11_err.decode() + p11_out.decode()) + self.assertIn(b'X.509 cert', p11_out, 'pkcs11-tool failed: ' + p11_err.decode() + p11_out.decode()) + self.assertIn(b'Initialized: yes', hsm_out, 'softhsm2-tool failed: ' + + hsm_err.decode() + hsm_out.decode()) + self.assertIn(b'User PIN init.: yes', hsm_out, 'softhsm2-tool failed: ' + + hsm_err.decode() + hsm_out.decode()) + + # Verify that device HAS provisioned. + ran_ok = False + for delay in [5, 5, 5, 5, 10]: + sleep(delay) + stdout, stderr, retcode = self.run_command('aktualizr-info') + if retcode == 0 and stderr == b'' and stdout.decode().find('Provisioned on server: yes') >= 0: + ran_ok = True + break + self.assertIn(b'Device ID: ', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) + self.assertIn(b'Primary ecu hardware ID: qemux86-64', stdout, + 'Provisioning failed: ' + stderr.decode() + stdout.decode()) + self.assertIn(b'Fetched metadata: yes', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) + + def qemu_launch(efi=False, machine=None): logger = logging.getLogger("selftest") logger.info('Running bitbake to build core-image-minimal') diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index bcc1438..ab9a8dc 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -20,7 +20,7 @@ SRC_URI = " \ file://aktualizr.service \ file://aktualizr-serialcan.service \ " -SRCREV = "715dfc3410d46670174ee2f55613e8d953fbb1ae" +SRCREV = "abd0db4e503cbe647fbe3a6e70d28456c2ad7ea4" BRANCH ?= "master" S = "${WORKDIR}/git" -- cgit v1.2.3-54-g00ecf From 1f5d44911e608d809ac1e6987542c8909dfc464f Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Thu, 15 Feb 2018 17:20:35 +0100 Subject: Use some regex to get a little fancier. --- lib/oeqa/selftest/updater.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 8ee8378..690dae5 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -1,6 +1,7 @@ # pylint: disable=C0111,C0325 import os import logging +import re import subprocess import unittest from time import sleep @@ -273,6 +274,7 @@ class HsmTests(oeSelfTest): self.assertIn(b'Fetched metadata: no', stdout, 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + # Verify that HSM is not yet initialized. pkcs11_command = 'pkcs11-tool --module=/usr/lib/softhsm/libsofthsm2.so -O' stdout, stderr, retcode = self.run_command(pkcs11_command) self.assertNotEqual(retcode, 0, 'pkcs11-tool succeeded before initialization: ' + @@ -282,6 +284,7 @@ class HsmTests(oeSelfTest): self.assertNotEqual(retcode, 0, 'softhsm2-tool succeeded before initialization: ' + stdout.decode() + stderr.decode()) + # Run cert_provider. bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir', 'SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') l = bb_vars['libdir'] @@ -297,6 +300,7 @@ class HsmTests(oeSelfTest): result = runCmd(command, ignore_status=True) self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + # Verify that HSM is able to initialize. ran_ok = False for delay in [5, 5, 5, 5, 10]: sleep(delay) @@ -314,6 +318,20 @@ class HsmTests(oeSelfTest): self.assertIn(b'User PIN init.: yes', hsm_out, 'softhsm2-tool failed: ' + hsm_err.decode() + hsm_out.decode()) + # Check that pkcs11 output matches sofhsm output. + p11_p = re.compile(r'Using slot [0-9] with a present token \((0x[0-9a-f]*)\)\s') + p11_m = p11_p.search(p11_err.decode()) + self.assertTrue(p11_m, 'Slot number not found with pkcs11-tool: ' + p11_err.decode() + p11_out.decode()) + self.assertGreater(p11_m.lastindex, 0, 'Slot number not found with pkcs11-tool: ' + + p11_err.decode() + p11_out.decode()) + hsm_p = re.compile(r'Description:\s*SoftHSM slot ID (0x[0-9a-f]*)\s') + hsm_m = hsm_p.search(hsm_out.decode()) + self.assertTrue(hsm_m, 'Slot number not found with softhsm2-tool: ' + hsm_err.decode() + hsm_out.decode()) + self.assertGreater(hsm_m.lastindex, 0, 'Slot number not found with softhsm2-tool: ' + + hsm_err.decode() + hsm_out.decode()) + self.assertEqual(p11_m.group(1), hsm_m.group(1), 'Slot number does not match: ' + + p11_err.decode() + p11_out.decode() + hsm_err.decode() + hsm_out.decode()) + # Verify that device HAS provisioned. ran_ok = False for delay in [5, 5, 5, 5, 10]: @@ -326,6 +344,11 @@ class HsmTests(oeSelfTest): self.assertIn(b'Primary ecu hardware ID: qemux86-64', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) self.assertIn(b'Fetched metadata: yes', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) + p = re.compile(r'Device ID: ([a-z0-9-]*)\n') + m = p.search(stdout.decode()) + self.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) + self.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) + logger.info('Device successfully provisioned with ID: ' + m.group(1)) def qemu_launch(efi=False, machine=None): -- cgit v1.2.3-54-g00ecf From c6690b907a0a4525848dfed6cde2d89d8554b5f1 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Mon, 19 Feb 2018 14:10:16 +0100 Subject: Rename run_command to qemu_command. This helps distinguish it from runCmd, which is how you run commands in the shell. --- lib/oeqa/selftest/updater.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 690dae5..c8ec711 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -170,13 +170,13 @@ class QemuTests(oeSelfTest): def tearDownClass(cls): qemu_terminate(cls.s) - def run_command(self, command): + def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) def test_hostname(self): print('') print('Checking machine name (hostname) of device:') - stdout, stderr, retcode = self.run_command('hostname') + stdout, stderr, retcode = self.qemu_command('hostname') machine = get_bb_var('MACHINE', 'core-image-minimal') self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. @@ -188,7 +188,7 @@ class QemuTests(oeSelfTest): def test_var_sota(self): print('') print('Checking contents of /var/sota:') - stdout, stderr, retcode = self.run_command('ls /var/sota') + stdout, stderr, retcode = self.qemu_command('ls /var/sota') self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) self.assertEqual(retcode, 0) print(stdout.decode()) @@ -199,7 +199,7 @@ class QemuTests(oeSelfTest): for delay in [0, 1, 2, 5, 10, 15]: sleep(delay) try: - stdout, stderr, retcode = self.run_command('aktualizr-info') + stdout, stderr, retcode = self.qemu_command('aktualizr-info') if retcode == 0 and stderr == b'': ran_ok = True break @@ -252,14 +252,14 @@ class HsmTests(oeSelfTest): def tearDownLocal(self): qemu_terminate(self.s) - def run_command(self, command): + def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) def test_provisioning(self): print('') ran_ok = False for delay in [0, 1, 2, 5, 10, 15]: - stdout, stderr, retcode = self.run_command('aktualizr-info') + stdout, stderr, retcode = self.qemu_command('aktualizr-info') if retcode == 0 and stderr == b'': ran_ok = True break @@ -276,11 +276,11 @@ class HsmTests(oeSelfTest): # Verify that HSM is not yet initialized. pkcs11_command = 'pkcs11-tool --module=/usr/lib/softhsm/libsofthsm2.so -O' - stdout, stderr, retcode = self.run_command(pkcs11_command) + stdout, stderr, retcode = self.qemu_command(pkcs11_command) self.assertNotEqual(retcode, 0, 'pkcs11-tool succeeded before initialization: ' + stdout.decode() + stderr.decode()) softhsm2_command = 'softhsm2-util --show-slots' - stdout, stderr, retcode = self.run_command(softhsm2_command) + stdout, stderr, retcode = self.qemu_command(softhsm2_command) self.assertNotEqual(retcode, 0, 'softhsm2-tool succeeded before initialization: ' + stdout.decode() + stderr.decode()) @@ -304,8 +304,8 @@ class HsmTests(oeSelfTest): ran_ok = False for delay in [5, 5, 5, 5, 10]: sleep(delay) - p11_out, p11_err, p11_ret = self.run_command(pkcs11_command) - hsm_out, hsm_err, hsm_ret = self.run_command(softhsm2_command) + p11_out, p11_err, p11_ret = self.qemu_command(pkcs11_command) + hsm_out, hsm_err, hsm_ret = self.qemu_command(softhsm2_command) if p11_ret == 0 and hsm_ret == 0 and hsm_err == b'': ran_ok = True break @@ -336,7 +336,7 @@ class HsmTests(oeSelfTest): ran_ok = False for delay in [5, 5, 5, 5, 10]: sleep(delay) - stdout, stderr, retcode = self.run_command('aktualizr-info') + stdout, stderr, retcode = self.qemu_command('aktualizr-info') if retcode == 0 and stderr == b'' and stdout.decode().find('Provisioned on server: yes') >= 0: ran_ok = True break -- cgit v1.2.3-54-g00ecf From eb173b6cba56c5b97465a6506a9a69b2f1c858f7 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Mon, 19 Feb 2018 16:51:48 +0100 Subject: Better oe-selftest documentation. Also clean up some minor formatting. --- README.adoc | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/README.adoc b/README.adoc index fbd3239..e074913 100644 --- a/README.adoc +++ b/README.adoc @@ -17,10 +17,10 @@ If you don't already have a Yocto project that you want to add OTA to, you can u If you already have a Yocto-based project and you want to add atomic filesystem updates to it, you just need to do three things: 1. Clone the `meta-updater` layer and add it to your https://www.yoctoproject.org/docs/2.1/ref-manual/ref-manual.html#structure-build-conf-bblayers.conf[bblayers.conf]. -2. Clone BSP integration layer (meta-updater-$\{PLATFORM}, e.g. https://github.com/advancedtelematic/meta-updater-raspberrypi[meta-updater-raspberrypi]) and add it to your conf/bblayers.conf. If your board isn't supported yet, you could write a BSP integration for it yourself. See the <> section for the details. -3. Set up your https://www.yoctoproject.org/docs/2.1/ref-manual/ref-manual.html#var-DISTRO[distro]. If you are using "poky", the default distro in Yocto, you can change it in your conf/local.conf to "poky-sota". Alternatively, if you are using your own or third party distro configuration, you can add 'INHERIT += " sota"' to it, thus combining capabilities of your distro with meta-updater features. +2. Clone BSP integration layer (`meta-updater-$\{PLATFORM}`, e.g. https://github.com/advancedtelematic/meta-updater-raspberrypi[meta-updater-raspberrypi]) and add it to your `conf/bblayers.conf`. If your board isn't supported yet, you could write a BSP integration for it yourself. See the <> section for the details. +3. Set up your https://www.yoctoproject.org/docs/2.1/ref-manual/ref-manual.html#var-DISTRO[distro]. If you are using "poky", the default distro in Yocto, you can change it in your `conf/local.conf` to "poky-sota". Alternatively, if you are using your own or third party distro configuration, you can add `INHERIT += " sota"` to it, thus combining capabilities of your distro with meta-updater features. -You can then build your image as usual, with bitbake. After building the root file system, bitbake will then create an https://ostree.readthedocs.io/en/latest/manual/adapting-existing/[OSTree-enabled version] of it, commit it to your local OSTree repo and (optionally) push it to a remote server. Additionally, a live disk image will be created (normally named $\{IMAGE_NAME}.-sdimg-ota e.g. core-image-raspberrypi3.rpi-sdimg-ota). You can control this behaviour through <>. +You can then build your image as usual, with bitbake. After building the root file system, bitbake will then create an https://ostree.readthedocs.io/en/latest/manual/adapting-existing/[OSTree-enabled version] of it, commit it to your local OSTree repo and (optionally) push it to a remote server. Additionally, a live disk image will be created (normally named `$\{IMAGE_NAME}.-sdimg-ota` e.g. `core-image-raspberrypi3.rpi-sdimg-ota`). You can control this behaviour through <>. === Build in AGL @@ -30,19 +30,19 @@ With AGL you can just add agl-sota feature while configuring your build environm source meta-agl/scripts/aglsetup.sh -m porter agl-demo agl-appfw-smack agl-devel agl-sota .... -you can then run +You can then run: .... bitbake agl-demo-platform .... -and get as a result an "ostree_repo" folder in your images directory (tmp/deploy/images/$\{MACHINE}/ostree_repo). It will contain +and get as a result an `ostree_repo` folder in your images directory (`tmp/deploy/images/$\{MACHINE}/ostree_repo`). It will contain: * your OSTree repository, with the rootfs committed as an OSTree deployment, -* an 'otaimg' bootstrap image, which is an OSTree physical sysroot as a burnable filesystem image, and optionally -* some machine-dependent live images (e.g. '_.rpi-sdimg-ota' for Raspberry Pi or '_.porter-sdimg-ota' Renesas Porter board). +* an `otaimg` bootstrap image, which is an OSTree physical sysroot as a burnable filesystem image, and optionally +* some machine-dependent live images (e.g. `.rpi-sdimg-ota` for Raspberry Pi or `.porter-sdimg-ota` Renesas Porter board). -Although aglsetup.sh hooks provide reasonable defaults for SOTA-related variables, you may want to tune some of them. +Although `aglsetup.sh` hooks provide reasonable defaults for SOTA-related variables, you may want to tune some of them. == Supported boards @@ -63,7 +63,7 @@ You may take a look into https://github.com/advancedtelematic/meta-updater-minno Although we have used U-Boot so far, other boot loaders can be configured work with OSTree as well. -== SOTA-related variables in local.conf +== SOTA-related variables in `local.conf` * `OSTREE_REPO` - path to your OSTree repository. Defaults to `$\{DEPLOY_DIR_IMAGE}/ostree_repo` * `OSTREE_OSNAME` - OS deployment name on your target device. For more information about deployments and osnames see the https://ostree.readthedocs.io/en/latest/manual/deployment/[OSTree documentation]. Defaults to "poky". @@ -125,18 +125,32 @@ garage-push --repo=/path/to/ostree-repo --ref=mybranch --credentials=/path/to/cr You can set SOTA_PACKED_CREDENTIALS in your local.conf to make your build results be automatically synchronized with a remote server. Credentials are stored in the JSON format described in the https://github.com/advancedtelematic/aktualizr/blob/master/README.sotatools.adoc[garage-push README]. This JSON file can be optionally stored inside a zip file, although if it is stored this way, the JSON file must be named treehub.json. -=== QA +== QA with `oe-selftest` This layer relies on the test framework oe-selftest for quality assurance. Follow the steps below to run the tests: -* Append the line below to conf/local.conf +1. Append the line below to `conf/local.conf` to disable the warning about supported operating systems: ++ +``` +SANITY_TESTED_DISTROS = "" +``` +2. If your image does not already include an ssh daemon such as dropbear or openssh, add this line to `conf/local.conf` as well: ++ ``` -SANITY_TESTED_DISTROS="" +IMAGE_INSTALL_append = " dropbear " ``` -* Run oe-selftest: +3. To be able to build an image for the grub tests, you will need to install https://github.com/tianocore/tianocore.github.io/wiki/OVMF[TianoCore's ovmf] package on your host system. On Debian-like systems, you can do so with this command: ++ +``` +sudo apt install ovmf +``` +4. Run oe-selftest: ++ ``` oe-selftest --run-tests updater ``` + +For 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]. -- cgit v1.2.3-54-g00ecf From 5c141641e143883e06b815371dd69551dbf3d52a Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Mon, 19 Feb 2018 16:52:12 +0100 Subject: oe-selftest standardization and general improvement. --- lib/oeqa/selftest/updater.py | 72 ++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index c8ec711..0ef3e16 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -173,10 +173,11 @@ class QemuTests(oeSelfTest): def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) - def test_hostname(self): - print('') + def test_qemu(self): print('Checking machine name (hostname) of device:') stdout, stderr, retcode = self.qemu_command('hostname') + self.assertEqual(retcode, 0, "Unable to check hostname. " + + "Is an ssh daemon (such as dropbear or openssh) installed on the device?") machine = get_bb_var('MACHINE', 'core-image-minimal') self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. @@ -184,27 +185,14 @@ class QemuTests(oeSelfTest): self.assertEqual(value_str, machine, 'MACHINE does not match hostname: ' + machine + ', ' + value_str) print(value_str) - - def test_var_sota(self): - print('') - print('Checking contents of /var/sota:') - stdout, stderr, retcode = self.qemu_command('ls /var/sota') - self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) - self.assertEqual(retcode, 0) - print(stdout.decode()) - - def test_aktualizr_info(self): print('Checking output of aktualizr-info:') ran_ok = False for delay in [0, 1, 2, 5, 10, 15]: sleep(delay) - try: - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'': - ran_ok = True - break - except IOError as e: - print(e) + stdout, stderr, retcode = self.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'': + ran_ok = True + break self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) @@ -227,26 +215,39 @@ class GrubTests(oeSelfTest): runCmd('bitbake-layers remove-layer "%s"' % self.meta_intel, ignore_status=True) runCmd('bitbake-layers remove-layer "%s"' % self.meta_minnow, ignore_status=True) + def qemu_command(self, command): + return qemu_send_command(self.qemu.ssh_port, command) + def test_grub(self): print('') print('Checking machine name (hostname) of device:') - value, err, retcode = qemu_send_command(self.qemu.ssh_port, 'hostname') + stdout, stderr, retcode = self.qemu_command('hostname') + self.assertEqual(retcode, 0, "Unable to check hostname. " + + "Is an ssh daemon (such as dropbear or openssh) installed on the device?") machine = get_bb_var('MACHINE', 'core-image-minimal') - self.assertEqual(err, b'', 'Error: ' + err.decode()) - self.assertEqual(retcode, 0) + self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. - value_str = value.decode()[:-1] - self.assertEqual(value_str, machine, - 'MACHINE does not match hostname: ' + machine + ', ' + value_str + - '\nIs tianocore ovmf installed?') - print(value_str) + value = stdout.decode()[:-1] + self.assertEqual(value, machine, + 'MACHINE does not match hostname: ' + machine + ', ' + value + + '\nIs TianoCore ovmf installed?') + print(value) + print('Checking output of aktualizr-info:') + ran_ok = False + for delay in [0, 1, 2, 5, 10, 15]: + sleep(delay) + stdout, stderr, retcode = self.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'': + ran_ok = True + break + self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) class HsmTests(oeSelfTest): def setUpLocal(self): - self.write_config('SOTA_CLIENT_PROV = " aktualizr-hsm-prov "') - self.write_config('SOTA_CLIENT_FEATURES="hsm"') + self.write_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') + self.write_config('SOTA_CLIENT_FEATURES = "hsm"') self.qemu, self.s = qemu_launch(machine='qemux86-64') def tearDownLocal(self): @@ -256,7 +257,18 @@ class HsmTests(oeSelfTest): return qemu_send_command(self.qemu.ssh_port, command) def test_provisioning(self): - print('') + print('Checking machine name (hostname) of device:') + stdout, stderr, retcode = self.qemu_command('hostname') + self.assertEqual(retcode, 0, "Unable to check hostname. " + + "Is an ssh daemon (such as dropbear or openssh) installed on the device?") + machine = get_bb_var('MACHINE', 'core-image-minimal') + self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) + # Strip off line ending. + value_str = stdout.decode()[:-1] + self.assertEqual(value_str, machine, + 'MACHINE does not match hostname: ' + machine + ', ' + value_str) + print(value_str) + print('Checking output of aktualizr-info:') ran_ok = False for delay in [0, 1, 2, 5, 10, 15]: stdout, stderr, retcode = self.qemu_command('aktualizr-info') -- cgit v1.2.3-54-g00ecf From e77c7c7b6121ed9ad207d7fd1603a32e59540f00 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Tue, 20 Feb 2018 11:56:55 +0100 Subject: Replace write_config with append_config. Also fix a minor provisioning check ordering problem. --- lib/oeqa/selftest/updater.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 0ef3e16..703df91 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -57,7 +57,7 @@ class GeneralTests(oeSelfTest): def test_credentials(self): logger = logging.getLogger("selftest") logger.info('Running bitbake to build core-image-minimal') - self.write_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') + self.append_config('SOTA_CLIENT_PROV = "aktualizr-auto-prov"') bitbake('core-image-minimal') credentials = get_bb_var('SOTA_PACKED_CREDENTIALS') # skip the test if the variable SOTA_PACKED_CREDENTIALS is not set @@ -74,7 +74,8 @@ class GeneralTests(oeSelfTest): def test_java(self): result = runCmd('which java', ignore_status=True) - self.assertEqual(result.status, 0, "Java not found.") + self.assertEqual(result.status, 0, + "Java not found. Do you have a JDK installed on your host machine?") def test_add_package(self): print('') @@ -84,7 +85,7 @@ class GeneralTests(oeSelfTest): logger = logging.getLogger("selftest") logger.info('Running bitbake with man in the image package list') - self.write_config('IMAGE_INSTALL_append = " man "') + self.append_config('IMAGE_INSTALL_append = " man "') bitbake('-c cleanall man') bitbake('core-image-minimal') result = runCmd('oe-pkgdata-util find-path /usr/bin/man') @@ -94,7 +95,7 @@ class GeneralTests(oeSelfTest): logger.info('First image %s has size %i' % (path1, size1)) logger.info('Running bitbake without man in the image package list') - self.write_config('IMAGE_INSTALL_remove = " man "') + self.append_config('IMAGE_INSTALL_remove = " man "') bitbake('-c cleanall man') bitbake('core-image-minimal') result = runCmd('oe-pkgdata-util find-path /usr/bin/man', ignore_status=True) @@ -230,7 +231,7 @@ class GrubTests(oeSelfTest): value = stdout.decode()[:-1] self.assertEqual(value, machine, 'MACHINE does not match hostname: ' + machine + ', ' + value + - '\nIs TianoCore ovmf installed?') + '\nIs TianoCore ovmf installed on your host machine?') print(value) print('Checking output of aktualizr-info:') ran_ok = False @@ -246,8 +247,8 @@ class GrubTests(oeSelfTest): class HsmTests(oeSelfTest): def setUpLocal(self): - self.write_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') - self.write_config('SOTA_CLIENT_FEATURES = "hsm"') + self.append_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') + self.append_config('SOTA_CLIENT_FEATURES = "hsm"') self.qemu, self.s = qemu_launch(machine='qemux86-64') def tearDownLocal(self): @@ -349,7 +350,7 @@ class HsmTests(oeSelfTest): for delay in [5, 5, 5, 5, 10]: sleep(delay) stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'' and stdout.decode().find('Provisioned on server: yes') >= 0: + if retcode == 0 and stderr == b'' and stdout.decode().find('Fetched metadata: yes') >= 0: ran_ok = True break self.assertIn(b'Device ID: ', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) -- cgit v1.2.3-54-g00ecf From b9922d6eeda2f0fffadb660f80f13e4ae92ae1cd Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Tue, 20 Feb 2018 15:46:54 +0100 Subject: Bump aktualizr to fix a CMAKE_BUILD_TYPE bug. --- recipes-sota/aktualizr/aktualizr_git.bb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index ab9a8dc..a2a952e 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -20,7 +20,7 @@ SRC_URI = " \ file://aktualizr.service \ file://aktualizr-serialcan.service \ " -SRCREV = "abd0db4e503cbe647fbe3a6e70d28456c2ad7ea4" +SRCREV = "17aeb9dfef7beb02d148b0a72e17ed0d8f3b4042" BRANCH ?= "master" S = "${WORKDIR}/git" -- cgit v1.2.3-54-g00ecf From fc84de73eb3f04f1e7600a1c86061af7f856e8d4 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 20 Feb 2018 17:43:52 +0100 Subject: Refactor oe selftests Factorize the call of aktualizr-native commands in each testing class --- lib/oeqa/selftest/updater.py | 121 +++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 51 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 703df91..8563e3b 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -16,32 +16,32 @@ class SotaToolsTests(oeSelfTest): @classmethod def setUpClass(cls): logger = logging.getLogger("selftest") + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'], + 'aktualizr-native') + cls.sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix'] + cls.sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + cls.libdir = bb_vars['libdir'] + logger.info('Running bitbake to build aktualizr-native tools') bitbake('aktualizr-native') - def test_push_help(self): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') - l = bb_vars['libdir'] - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/garage-push" - self.assertTrue(os.path.isfile(p), msg = "No garage-push found (%s)" % p) - result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) + def runNativeCmd(self, cmd, **kwargs): + program, *_ = cmd.split(' ') + p = '{}/{}'.format(self.sysrootbin, program) + self.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p)) + env = dict(os.environ) + env['LD_LIBRARY_PATH'] = self.libdir + result = runCmd(cmd, env=env, native_sysroot=self.sysroot, ignore_status=True, **kwargs) self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + def test_push_help(self): + self.runNativeCmd('garage-push --help') + def test_deploy_help(self): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') - l = bb_vars['libdir'] - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/garage-deploy" - self.assertTrue(os.path.isfile(p), msg = "No garage-deploy found (%s)" % p) - result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + self.runNativeCmd('garage-deploy --help') def test_garagesign_help(self): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') - l = bb_vars['libdir'] - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/garage-sign" - self.assertTrue(os.path.isfile(p), msg = "No garage-sign found (%s)" % p) - result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + self.runNativeCmd('garage-sign --help') class GeneralTests(oeSelfTest): @@ -113,24 +113,29 @@ class AktualizrToolsTests(oeSelfTest): @classmethod def setUpClass(cls): logger = logging.getLogger("selftest") + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'], + 'aktualizr-native') + cls.sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix'] + cls.sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + cls.libdir = bb_vars['libdir'] + logger.info('Running bitbake to build aktualizr-native tools') bitbake('aktualizr-native') - def test_implicit_writer_help(self): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') - l = bb_vars['libdir'] - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_implicit_writer" - self.assertTrue(os.path.isfile(p), msg = "No aktualizr_implicit_writer found (%s)" % p) - result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) + def runNativeCmd(self, cmd, **kwargs): + program, *_ = cmd.split(' ') + p = '{}/{}'.format(self.sysrootbin, program) + self.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p)) + env = dict(os.environ) + env['LD_LIBRARY_PATH'] = self.libdir + result = runCmd(cmd, env=env, native_sysroot=self.sysroot, ignore_status=True, **kwargs) self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + def test_implicit_writer_help(self): + self.runNativeCmd('aktualizr_implicit_writer --help') + def test_cert_provider_help(self): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir'], 'aktualizr-native') - l = bb_vars['libdir'] - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_cert_provider" - self.assertTrue(os.path.isfile(p), msg = "No aktualizr_cert_provider found (%s)" % p) - result = runCmd('LD_LIBRARY_PATH=%s %s --help' % (l, p), ignore_status=True) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + self.runNativeCmd('aktualizr_cert_provider --help') def test_cert_provider_local_output(self): logger = logging.getLogger("selftest") @@ -138,17 +143,14 @@ class AktualizrToolsTests(oeSelfTest): bitbake('aktualizr-implicit-prov') bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir', 'SOTA_PACKED_CREDENTIALS', 'T'], 'aktualizr-native') - l = bb_vars['libdir'] - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_cert_provider" creds = bb_vars['SOTA_PACKED_CREDENTIALS'] temp_dir = bb_vars['T'] bb_vars_prov = get_bb_vars(['STAGING_DIR_NATIVE', 'libdir'], 'aktualizr-implicit-prov') config = bb_vars_prov['STAGING_DIR_NATIVE'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov.toml' - self.assertTrue(os.path.isfile(p), msg = "No aktualizr_cert_provider found (%s)" % p) - command = 'LD_LIBRARY_PATH=' + l + ' ' + p + ' -c ' + creds + ' -r -l ' + temp_dir + ' -g ' + config - # logger.info('Checking output of: ' + command) - result = runCmd(command, ignore_status=True) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + + self.runNativeCmd('aktualizr_cert_provider -c {creds} -r -l {temp} -g {config}' + .format(creds=creds, temp=temp_dir, config=config)) + # Might be nice if these names weren't hardcoded. cert_path = temp_dir + '/client.pem' self.assertTrue(os.path.isfile(cert_path), "Client certificate not found at %s." % cert_path) @@ -178,7 +180,7 @@ class QemuTests(oeSelfTest): print('Checking machine name (hostname) of device:') stdout, stderr, retcode = self.qemu_command('hostname') self.assertEqual(retcode, 0, "Unable to check hostname. " + - "Is an ssh daemon (such as dropbear or openssh) installed on the device?") + "Is an ssh daemon (such as dropbear or openssh) installed on the device?") machine = get_bb_var('MACHINE', 'core-image-minimal') self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. @@ -224,7 +226,7 @@ class GrubTests(oeSelfTest): print('Checking machine name (hostname) of device:') stdout, stderr, retcode = self.qemu_command('hostname') self.assertEqual(retcode, 0, "Unable to check hostname. " + - "Is an ssh daemon (such as dropbear or openssh) installed on the device?") + "Is an ssh daemon (such as dropbear or openssh) installed on the device?") machine = get_bb_var('MACHINE', 'core-image-minimal') self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. @@ -246,6 +248,18 @@ class GrubTests(oeSelfTest): class HsmTests(oeSelfTest): + @classmethod + def setUpClass(cls): + logger = logging.getLogger("selftest") + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'], + 'aktualizr-native') + cls.sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix'] + cls.sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + cls.libdir = bb_vars['libdir'] + + logger.info('Running bitbake to build aktualizr-native tools') + bitbake('aktualizr-native') + def setUpLocal(self): self.append_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') self.append_config('SOTA_CLIENT_FEATURES = "hsm"') @@ -254,6 +268,15 @@ class HsmTests(oeSelfTest): def tearDownLocal(self): qemu_terminate(self.s) + def runNativeCmd(self, cmd, **kwargs): + program, *_ = cmd.split(' ') + p = '{}/{}'.format(self.sysrootbin, program) + self.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p)) + env = dict(os.environ) + env['LD_LIBRARY_PATH'] = self.libdir + result = runCmd(cmd, env=env, native_sysroot=self.sysroot, ignore_status=True, **kwargs) + self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) @@ -261,7 +284,7 @@ class HsmTests(oeSelfTest): print('Checking machine name (hostname) of device:') stdout, stderr, retcode = self.qemu_command('hostname') self.assertEqual(retcode, 0, "Unable to check hostname. " + - "Is an ssh daemon (such as dropbear or openssh) installed on the device?") + "Is an ssh daemon (such as dropbear or openssh) installed on the device?") machine = get_bb_var('MACHINE', 'core-image-minimal') self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. @@ -291,7 +314,7 @@ class HsmTests(oeSelfTest): pkcs11_command = 'pkcs11-tool --module=/usr/lib/softhsm/libsofthsm2.so -O' stdout, stderr, retcode = self.qemu_command(pkcs11_command) self.assertNotEqual(retcode, 0, 'pkcs11-tool succeeded before initialization: ' + - stdout.decode() + stderr.decode()) + stdout.decode() + stderr.decode()) softhsm2_command = 'softhsm2-util --show-slots' stdout, stderr, retcode = self.qemu_command(softhsm2_command) self.assertNotEqual(retcode, 0, 'softhsm2-tool succeeded before initialization: ' + @@ -300,18 +323,12 @@ class HsmTests(oeSelfTest): # Run cert_provider. bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir', 'SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') - l = bb_vars['libdir'] - p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/aktualizr_cert_provider" creds = bb_vars['SOTA_PACKED_CREDENTIALS'] bb_vars_prov = get_bb_vars(['STAGING_DIR_NATIVE', 'libdir'], 'aktualizr-hsm-prov') config = bb_vars_prov['STAGING_DIR_NATIVE'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov.toml' - self.assertTrue(os.path.isfile(p), msg = "No aktualizr_cert_provider found (%s)" % p) - command = ('LD_LIBRARY_PATH=' + l + ' ' + p + ' -c ' + creds + ' -t root@localhost -p ' + - str(self.qemu.ssh_port) + ' -r -s -g ' + config) - logger = logging.getLogger("selftest") - # logger.info('Checking output of: ' + command) - result = runCmd(command, ignore_status=True) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + + self.runNativeCmd('aktualizr_cert_provider -c {creds} -t root@localhost -p {port} -r -s -g {config}' + .format(creds=creds, port=self.qemu.ssh_port, config=config)) # Verify that HSM is able to initialize. ran_ok = False @@ -361,7 +378,7 @@ class HsmTests(oeSelfTest): m = p.search(stdout.decode()) self.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) self.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) - logger.info('Device successfully provisioned with ID: ' + m.group(1)) + self.logger.info('Device successfully provisioned with ID: ' + m.group(1)) def qemu_launch(efi=False, machine=None): @@ -391,12 +408,14 @@ def qemu_launch(efi=False, machine=None): sleep(10) return qemu, s + def qemu_terminate(s): try: s.terminate() except KeyboardInterrupt: pass + def qemu_send_command(port, command): command = ['ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@localhost -p ' + str(port) + ' "' + command + '"'] -- cgit v1.2.3-54-g00ecf From 2023bfbbe31d5bb2df6da2af66ff828b2321b1e4 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Wed, 21 Feb 2018 08:56:38 +0100 Subject: Fix minor logging issue. No need for the extra bitbake of aktualizr-native. --- lib/oeqa/selftest/updater.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 8563e3b..1efbba9 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -250,16 +250,12 @@ class HsmTests(oeSelfTest): @classmethod def setUpClass(cls): - logger = logging.getLogger("selftest") bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'], 'aktualizr-native') cls.sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix'] cls.sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] cls.libdir = bb_vars['libdir'] - logger.info('Running bitbake to build aktualizr-native tools') - bitbake('aktualizr-native') - def setUpLocal(self): self.append_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') self.append_config('SOTA_CLIENT_FEATURES = "hsm"') @@ -378,7 +374,8 @@ class HsmTests(oeSelfTest): m = p.search(stdout.decode()) self.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) self.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) - self.logger.info('Device successfully provisioned with ID: ' + m.group(1)) + logger = logging.getLogger("selftest") + logger.info('Device successfully provisioned with ID: ' + m.group(1)) def qemu_launch(efi=False, machine=None): -- cgit v1.2.3-54-g00ecf From 38de2f4eeb74281784defe0ff6d9e3638e8fd583 Mon Sep 17 00:00:00 2001 From: Anton Gerasimov Date: Wed, 21 Feb 2018 16:54:09 +0100 Subject: Use FIT image on RPi --- classes/sota_raspberrypi.bbclass | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/classes/sota_raspberrypi.bbclass b/classes/sota_raspberrypi.bbclass index 2c69ea0..a5558b4 100644 --- a/classes/sota_raspberrypi.bbclass +++ b/classes/sota_raspberrypi.bbclass @@ -1,11 +1,20 @@ RPI_USE_U_BOOT_sota = "1" -KERNEL_IMAGETYPE_sota = "uImage" + +KERNEL_CLASSES_append_sota = " kernel-fitimage" +KERNEL_IMAGETYPE_sota = "fitImage" + PREFERRED_PROVIDER_virtual/bootloader_sota ?= "u-boot" -UBOOT_MACHINE_raspberrypi2_sota ?= "rpi_2_defconfig" -UBOOT_MACHINE_raspberrypi3_sota ?= "rpi_3_32b_defconfig" +UBOOT_ENTRYPOINT_sota ?= "0x00008000" IMAGE_FSTYPES_remove_sota = "rpi-sdimg" OSTREE_BOOTLOADER ?= "u-boot" # OSTree puts its own boot.scr to bcm2835-bootfiles -IMAGE_BOOT_FILES_remove_sota += "boot.scr" +IMAGE_BOOT_FILES_sota = "bcm2835-bootfiles/* u-boot.bin;${SDIMG_KERNELIMAGE}" + +# Just the overlays that will be used should be listed +KERNEL_DEVICETREE_raspberrypi2_sota ?= " bcm2709-rpi-2-b.dtb " +KERNEL_DEVICETREE_raspberrypi3_sota ?= " bcm2710-rpi-3-b.dtb overlays/vc4-kms-v3d.dtbo overlays/rpi-ft5406.dtbo" + +# Kernel args normally provided by RPi's internal bootloader. Non-updateable +OSTREE_KERNEL_ARGS_sota ?= " 8250.nr_uarts=1 bcm2708_fb.fbwidth=720 bcm2708_fb.fbheight=480 bcm2708_fb.fbswap=1 vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000 dwc_otg.lpm_enable=0 console=ttyS0,115200 usbhid.mousepoll=0 " -- cgit v1.2.3-54-g00ecf From 321509af3eb079dffd230d9417586dce11884be9 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Wed, 21 Feb 2018 15:10:39 +0100 Subject: Update patch to work with OPENSSL_VERSION_NUMBER 0x100020ef. --- .../files/0001-Workaround-for-a-buggy-version-of-openssl-1.0.2m.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes-support/libp11/files/0001-Workaround-for-a-buggy-version-of-openssl-1.0.2m.patch b/recipes-support/libp11/files/0001-Workaround-for-a-buggy-version-of-openssl-1.0.2m.patch index 0538eff..bd233ee 100644 --- a/recipes-support/libp11/files/0001-Workaround-for-a-buggy-version-of-openssl-1.0.2m.patch +++ b/recipes-support/libp11/files/0001-Workaround-for-a-buggy-version-of-openssl-1.0.2m.patch @@ -17,7 +17,7 @@ index 45d5ad3..75625e6 100644 -#if OPENSSL_VERSION_NUMBER < 0x100020d0L || defined(LIBRESSL_VERSION_NUMBER) -static void EVP_PKEY_meth_get_sign(EVP_PKEY_METHOD *pmeth, -+#if OPENSSL_VERSION_NUMBER <= 0x100020e0L || defined(LIBRESSL_VERSION_NUMBER) ++#if OPENSSL_VERSION_NUMBER < 0x100020f0L || defined(LIBRESSL_VERSION_NUMBER) + +# if (OPENSSL_VERSION_NUMBER & 0xFFFFFFF0) == 0x100020d0L +# undef EVP_PKEY_meth_get_sign -- cgit v1.2.3-54-g00ecf From 48d6d6f7508fd5ab373703af5b0bd99e7e1a20ff Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Wed, 21 Feb 2018 15:16:06 +0100 Subject: Update documentation and fix broken link. --- README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index 403e0f8..8246a31 100644 --- a/README.adoc +++ b/README.adoc @@ -133,7 +133,7 @@ The https://github.com/advancedtelematic/aktualizr[aktualizr repo] contains a to garage-push --repo=/path/to/ostree-repo --ref=mybranch --credentials=/path/to/credentials.zip .... -You can set SOTA_PACKED_CREDENTIALS in your local.conf to make your build results be automatically synchronized with a remote server. Credentials are stored in the JSON format described in the https://github.com/advancedtelematic/aktualizr/blob/master/README.sotatools.adoc[garage-push README]. This JSON file can be optionally stored inside a zip file, although if it is stored this way, the JSON file must be named treehub.json. +You can set `SOTA_PACKED_CREDENTIALS` in your `local.conf` to automatically synchronize your build results with a remote server. Credentials are stored in an archive as described in the https://github.com/advancedtelematic/aktualizr/blob/master/docs/credentials.adoc[aktualizr documentation]. === QA -- cgit v1.2.3-54-g00ecf From 1341019a478642913af159417099404bc3c9fd73 Mon Sep 17 00:00:00 2001 From: Anton Gerasimov Date: Mon, 26 Feb 2018 16:49:27 +0100 Subject: Pull new aktualizr with fixed fd leak --- recipes-sota/aktualizr/aktualizr_git.bb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index a2a952e..cba5f87 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -20,7 +20,7 @@ SRC_URI = " \ file://aktualizr.service \ file://aktualizr-serialcan.service \ " -SRCREV = "17aeb9dfef7beb02d148b0a72e17ed0d8f3b4042" +SRCREV = "1a6432175b9fb7326173e8db35d326cc1a1011a1" BRANCH ?= "master" S = "${WORKDIR}/git" -- cgit v1.2.3-54-g00ecf From ec13b957e2c4dd8804c871b82daed38ea309e0cb Mon Sep 17 00:00:00 2001 From: Anton Gerasimov Date: Mon, 26 Feb 2018 16:49:27 +0100 Subject: Pull new aktualizr with fixed fd leak --- recipes-sota/aktualizr/aktualizr_git.bb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index bed656a..5ce8b84 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -21,7 +21,7 @@ SRC_URI = " \ file://aktualizr.service \ file://aktualizr-serialcan.service \ " -SRCREV = "32a04532c1b7434b9cab89b78df389059ac45d40" +SRCREV = "1a6432175b9fb7326173e8db35d326cc1a1011a1" BRANCH ?= "master" S = "${WORKDIR}/git" -- cgit v1.2.3-54-g00ecf From 793f7c8baa1b8b232311d04d7eb1e604fdd82716 Mon Sep 17 00:00:00 2001 From: Anton Gerasimov Date: Thu, 15 Feb 2018 18:17:36 +0100 Subject: Add provisioning with CA --- .../aktualizr/aktualizr-ca-implicit-prov.bb | 72 ++++++++++++++++++++++ recipes-sota/aktualizr/aktualizr_git.bb | 4 +- recipes-sota/aktualizr/files/ca.cnf | 10 +++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb create mode 100644 recipes-sota/aktualizr/files/ca.cnf diff --git a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb new file mode 100644 index 0000000..51e313d --- /dev/null +++ b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb @@ -0,0 +1,72 @@ +SUMMARY = "Aktualizr configuration for implicit provisioning with CA" +DESCRIPTION = "Systemd service and configurations for implicitly provisioning Aktualizr using externally provided or generated CA" + +# WARNING: it is NOT a production solution. The secure way to provision devices is to create certificate request directly on the device +# (either with HSM/TPM or with software) and then sign it with a CA stored on a disconnected machine + +HOMEPAGE = "https://github.com/advancedtelematic/aktualizr" +SECTION = "base" +LICENSE = "MPL-2.0" +LIC_FILES_CHKSUM = "file://${WORKDIR}/LICENSE;md5=9741c346eef56131163e13b9db1241b3" + +DEPENDS = "aktualizr-native openssl-native" +RDEPENDS_${PN} = "aktualizr" + +SRC_URI = " \ + file://LICENSE \ + file://ca.cnf \ + " +PV = "1.0" +PR = "1" + +require environment.inc +require credentials.inc + +export SOTA_CACERT_PATH +export SOTA_CAKEY_PATH + +do_install() { + install -d ${D}${libdir}/sota + + if [ -z "${SOTA_PACKED_CREDENTIALS}" ]; then + bberror "SOTA_PACKED_CREDENTIALS are required for implicit provisioning" + fi + + if [ -z ${SOTA_CACERT_PATH} ]; then + SOTA_CACERT_PATH=${DEPLOY_DIR_IMAGE}/CA/cacert.pem + SOTA_CAKEY_PATH=${DEPLOY_DIR_IMAGE}/CA/ca.private.pem + mkdir -p ${DEPLOY_DIR_IMAGE}/CA + bbwarn "SOTA_CACERT_PATH is not specified, use default one at $SOTA_CACERT_PATH" + + if [ ! -f ${SOTA_CACERT_PATH} ]; then + bbwarn "${SOTA_CACERT_PATH} does not exist, generate a new CA" + SOTA_CACERT_DIR_PATH="$(dirname "$SOTA_CACERT_PATH")" + openssl genrsa -out ${SOTA_CACERT_DIR_PATH}/ca.private.pem 4096 + openssl req -key ${SOTA_CACERT_DIR_PATH}/ca.private.pem -new -x509 -days 7300 -out ${SOTA_CACERT_PATH} -subj "/C=DE/ST=Berlin/O=Reis und Kichererbsen e.V/commonName=meta-updater" -batch -config ${WORKDIR}/ca.cnf -extensions cacert + bbwarn "${SOTA_CACERT_PATH} has been created, you'll need to upload it to the server" + fi + fi + + if [ -z ${SOTA_CAKEY_PATH} ]; then + bberror "SOTA_CAKEY_PATH should be set when using implicit provisioning" + fi + + install -d ${D}${libdir}/sota + install -d ${D}${localstatedir}/sota + install -m 0644 ${STAGING_DIR_NATIVE}${libdir}/sota/sota_implicit_prov_ca.toml ${D}${libdir}/sota/sota.toml + aktualizr_cert_provider --credentials ${SOTA_PACKED_CREDENTIALS} \ + --device-ca ${SOTA_CACERT_PATH} \ + --device-ca-key ${SOTA_CAKEY_PATH} \ + --root-ca \ + --server-url \ + --local ${D}${localstatedir}/sota \ + --config ${D}${libdir}/sota/sota.toml +} + +FILES_${PN} = " \ + ${localstatedir}/sota/* \ + ${libdir}/sota/sota.toml \ + ${libdir}/sota/root.crt \ + " + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 5ce8b84..0aeac0f 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -38,12 +38,12 @@ EXTRA_OECMAKE_append_class-target = " -DBUILD_OSTREE=ON -DBUILD_ISOTP=ON ${@bb.u EXTRA_OECMAKE_append_class-native = " -DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF " do_install_append () { - rm -f ${D}${bindir}/aktualizr_cert_provider rm -fr ${D}${libdir}/systemd } do_install_append_class-target () { rm -f ${D}${bindir}/aktualizr_implicit_writer rm -f ${D}${libdir}/sota/sota.toml + rm -f ${D}${bindir}/aktualizr_cert_provider ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-example', '', 'rm -f ${D}${bindir}/example-interface', d)} ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-isotp-example', '', 'rm -f ${D}${bindir}/isotp-test-interface', d)} @@ -51,6 +51,7 @@ do_install_append_class-target () { aktualizr_service=${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'serialcan', '${WORKDIR}/aktualizr-serialcan.service', '${WORKDIR}/aktualizr.service', d)} install -m 0644 ${aktualizr_service} ${D}${systemd_unitdir}/system/aktualizr.service } + do_install_append_class-native () { rm -f ${D}${bindir}/aktualizr rm -f ${D}${bindir}/aktualizr-info @@ -59,6 +60,7 @@ do_install_append_class-native () { install -m 0644 ${S}/config/sota_autoprov.toml ${D}/${libdir}/sota/sota_autoprov.toml install -m 0644 ${S}/config/sota_hsm_prov.toml ${D}/${libdir}/sota/sota_hsm_prov.toml install -m 0644 ${S}/config/sota_implicit_prov.toml ${D}/${libdir}/sota/sota_implicit_prov.toml + install -m 0644 ${S}/config/sota_implicit_prov_ca.toml ${D}/${libdir}/sota/sota_implicit_prov_ca.toml install -m 0755 ${B}/src/sota_tools/garage-sign-prefix/src/garage-sign/bin/* ${D}${bindir} install -m 0644 ${B}/src/sota_tools/garage-sign-prefix/src/garage-sign/lib/* ${D}${libdir} diff --git a/recipes-sota/aktualizr/files/ca.cnf b/recipes-sota/aktualizr/files/ca.cnf new file mode 100644 index 0000000..352ec38 --- /dev/null +++ b/recipes-sota/aktualizr/files/ca.cnf @@ -0,0 +1,10 @@ +[req] +req_extensions = cacert +distinguished_name = req_distinguished_name + +[req_distinguished_name] + +[cacert] +basicConstraints = critical,CA:true +keyUsage = keyCertSign + -- cgit v1.2.3-54-g00ecf From 235826d067217aedf3e3e1819ee9c8f5ac0b60d3 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 20 Feb 2018 12:12:43 +0100 Subject: Test implicit provisioning with oe-selftest --- lib/oeqa/selftest/updater.py | 89 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 1efbba9..cad5b2a 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -246,6 +246,95 @@ class GrubTests(oeSelfTest): self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) +class ImplProvTests(oeSelfTest): + + @classmethod + def setUpClass(cls): + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'], + 'aktualizr-native') + cls.sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix'] + cls.sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + cls.libdir = bb_vars['libdir'] + + def setUpLocal(self): + self.append_config('SOTA_CLIENT_PROV = " aktualizr-implicit-prov "') + self.qemu, self.s = qemu_launch(machine='qemux86-64') + + def tearDownLocal(self): + qemu_terminate(self.s) + + def runNativeCmd(self, cmd, **kwargs): + program, *_ = cmd.split(' ') + p = '{}/{}'.format(self.sysrootbin, program) + self.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p)) + env = dict(os.environ) + env['LD_LIBRARY_PATH'] = self.libdir + result = runCmd(cmd, env=env, native_sysroot=self.sysroot, ignore_status=True, **kwargs) + self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + + def qemu_command(self, command): + return qemu_send_command(self.qemu.ssh_port, command) + + def test_provisioning(self): + print('Checking machine name (hostname) of device:') + stdout, stderr, retcode = self.qemu_command('hostname') + self.assertEqual(retcode, 0, "Unable to check hostname. " + + "Is an ssh daemon (such as dropbear or openssh) installed on the device?") + machine = get_bb_var('MACHINE', 'core-image-minimal') + self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) + # Strip off line ending. + value_str = stdout.decode()[:-1] + self.assertEqual(value_str, machine, + 'MACHINE does not match hostname: ' + machine + ', ' + value_str) + print(value_str) + print('Checking output of aktualizr-info:') + ran_ok = False + for delay in [0, 1, 2, 5, 10, 15]: + stdout, stderr, retcode = self.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'': + ran_ok = True + break + self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) + # Verify that device has NOT yet provisioned. + self.assertIn(b'Couldn\'t load device ID', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + self.assertIn(b'Couldn\'t load ECU serials', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + self.assertIn(b'Provisioned on server: no', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + self.assertIn(b'Fetched metadata: no', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + + # Run cert_provider. + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir', + 'SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') + creds = bb_vars['SOTA_PACKED_CREDENTIALS'] + bb_vars_prov = get_bb_vars(['STAGING_DIR_NATIVE', 'libdir'], 'aktualizr-implicit-prov') + config = bb_vars_prov['STAGING_DIR_NATIVE'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov.toml' + + self.runNativeCmd('aktualizr_cert_provider -c {creds} -t root@localhost -p {port} -s -g {config}' \ + .format(creds=creds, port=self.qemu.ssh_port, config=config)) + + # Verify that device HAS provisioned. + ran_ok = False + for delay in [5, 5, 5, 5, 10]: + sleep(delay) + stdout, stderr, retcode = self.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'' and stdout.decode().find('Fetched metadata: yes') >= 0: + ran_ok = True + break + self.assertIn(b'Device ID: ', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) + self.assertIn(b'Primary ecu hardware ID: qemux86-64', stdout, + 'Provisioning failed: ' + stderr.decode() + stdout.decode()) + self.assertIn(b'Fetched metadata: yes', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) + p = re.compile(r'Device ID: ([a-z0-9-]*)\n') + m = p.search(stdout.decode()) + self.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) + self.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) + logger = logging.getLogger("selftest") + logger.info('Device successfully provisioned with ID: ' + m.group(1)) + + class HsmTests(oeSelfTest): @classmethod -- cgit v1.2.3-54-g00ecf From 5c70505c127e58aa14c25599c6c7405e77e4c360 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 21 Feb 2018 12:10:01 +0100 Subject: Factorize aktualizr native helper in oe-selftest --- lib/oeqa/selftest/updater.py | 118 ++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 75 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index cad5b2a..f237364 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -16,32 +16,17 @@ class SotaToolsTests(oeSelfTest): @classmethod def setUpClass(cls): logger = logging.getLogger("selftest") - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'], - 'aktualizr-native') - cls.sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix'] - cls.sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] - cls.libdir = bb_vars['libdir'] - logger.info('Running bitbake to build aktualizr-native tools') bitbake('aktualizr-native') - def runNativeCmd(self, cmd, **kwargs): - program, *_ = cmd.split(' ') - p = '{}/{}'.format(self.sysrootbin, program) - self.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p)) - env = dict(os.environ) - env['LD_LIBRARY_PATH'] = self.libdir - result = runCmd(cmd, env=env, native_sysroot=self.sysroot, ignore_status=True, **kwargs) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) - def test_push_help(self): - self.runNativeCmd('garage-push --help') + akt_native_run(self, 'garage-push --help') def test_deploy_help(self): - self.runNativeCmd('garage-deploy --help') + akt_native_run(self, 'garage-deploy --help') def test_garagesign_help(self): - self.runNativeCmd('garage-sign --help') + akt_native_run(self, 'garage-sign --help') class GeneralTests(oeSelfTest): @@ -113,43 +98,27 @@ class AktualizrToolsTests(oeSelfTest): @classmethod def setUpClass(cls): logger = logging.getLogger("selftest") - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'], - 'aktualizr-native') - cls.sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix'] - cls.sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] - cls.libdir = bb_vars['libdir'] - logger.info('Running bitbake to build aktualizr-native tools') bitbake('aktualizr-native') - def runNativeCmd(self, cmd, **kwargs): - program, *_ = cmd.split(' ') - p = '{}/{}'.format(self.sysrootbin, program) - self.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p)) - env = dict(os.environ) - env['LD_LIBRARY_PATH'] = self.libdir - result = runCmd(cmd, env=env, native_sysroot=self.sysroot, ignore_status=True, **kwargs) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) - def test_implicit_writer_help(self): - self.runNativeCmd('aktualizr_implicit_writer --help') + akt_native_run(self, 'aktualizr_implicit_writer --help') def test_cert_provider_help(self): - self.runNativeCmd('aktualizr_cert_provider --help') + akt_native_run(self, 'aktualizr_cert_provider --help') def test_cert_provider_local_output(self): logger = logging.getLogger("selftest") logger.info('Running bitbake to build aktualizr-implicit-prov') bitbake('aktualizr-implicit-prov') - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir', - 'SOTA_PACKED_CREDENTIALS', 'T'], 'aktualizr-native') + bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS', 'T'], 'aktualizr-native') creds = bb_vars['SOTA_PACKED_CREDENTIALS'] temp_dir = bb_vars['T'] bb_vars_prov = get_bb_vars(['STAGING_DIR_NATIVE', 'libdir'], 'aktualizr-implicit-prov') config = bb_vars_prov['STAGING_DIR_NATIVE'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov.toml' - self.runNativeCmd('aktualizr_cert_provider -c {creds} -r -l {temp} -g {config}' - .format(creds=creds, temp=temp_dir, config=config)) + akt_native_run(self, 'aktualizr_cert_provider -c {creds} -r -l {temp} -g {config}' + .format(creds=creds, temp=temp_dir, config=config)) # Might be nice if these names weren't hardcoded. cert_path = temp_dir + '/client.pem' @@ -250,11 +219,9 @@ class ImplProvTests(oeSelfTest): @classmethod def setUpClass(cls): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'], - 'aktualizr-native') - cls.sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix'] - cls.sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] - cls.libdir = bb_vars['libdir'] + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build aktualizr-native tools') + bitbake('aktualizr-native') def setUpLocal(self): self.append_config('SOTA_CLIENT_PROV = " aktualizr-implicit-prov "') @@ -263,15 +230,6 @@ class ImplProvTests(oeSelfTest): def tearDownLocal(self): qemu_terminate(self.s) - def runNativeCmd(self, cmd, **kwargs): - program, *_ = cmd.split(' ') - p = '{}/{}'.format(self.sysrootbin, program) - self.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p)) - env = dict(os.environ) - env['LD_LIBRARY_PATH'] = self.libdir - result = runCmd(cmd, env=env, native_sysroot=self.sysroot, ignore_status=True, **kwargs) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) - def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) @@ -306,14 +264,13 @@ class ImplProvTests(oeSelfTest): 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) # Run cert_provider. - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir', - 'SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') + bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') creds = bb_vars['SOTA_PACKED_CREDENTIALS'] bb_vars_prov = get_bb_vars(['STAGING_DIR_NATIVE', 'libdir'], 'aktualizr-implicit-prov') config = bb_vars_prov['STAGING_DIR_NATIVE'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov.toml' - self.runNativeCmd('aktualizr_cert_provider -c {creds} -t root@localhost -p {port} -s -g {config}' \ - .format(creds=creds, port=self.qemu.ssh_port, config=config)) + akt_native_run(self, 'aktualizr_cert_provider -c {creds} -t root@localhost -p {port} -s -g {config}' + .format(creds=creds, port=self.qemu.ssh_port, config=config)) # Verify that device HAS provisioned. ran_ok = False @@ -339,11 +296,9 @@ class HsmTests(oeSelfTest): @classmethod def setUpClass(cls): - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'], - 'aktualizr-native') - cls.sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix'] - cls.sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] - cls.libdir = bb_vars['libdir'] + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build aktualizr-native tools') + bitbake('aktualizr-native') def setUpLocal(self): self.append_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') @@ -353,15 +308,6 @@ class HsmTests(oeSelfTest): def tearDownLocal(self): qemu_terminate(self.s) - def runNativeCmd(self, cmd, **kwargs): - program, *_ = cmd.split(' ') - p = '{}/{}'.format(self.sysrootbin, program) - self.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p)) - env = dict(os.environ) - env['LD_LIBRARY_PATH'] = self.libdir - result = runCmd(cmd, env=env, native_sysroot=self.sysroot, ignore_status=True, **kwargs) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) - def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) @@ -406,14 +352,13 @@ class HsmTests(oeSelfTest): stdout.decode() + stderr.decode()) # Run cert_provider. - bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir', 'libdir', - 'SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') + bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') creds = bb_vars['SOTA_PACKED_CREDENTIALS'] bb_vars_prov = get_bb_vars(['STAGING_DIR_NATIVE', 'libdir'], 'aktualizr-hsm-prov') config = bb_vars_prov['STAGING_DIR_NATIVE'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov.toml' - self.runNativeCmd('aktualizr_cert_provider -c {creds} -t root@localhost -p {port} -r -s -g {config}' - .format(creds=creds, port=self.qemu.ssh_port, config=config)) + akt_native_run(self, 'aktualizr_cert_provider -c {creds} -t root@localhost -p {port} -r -s -g {config}' + .format(creds=creds, port=self.qemu.ssh_port, config=config)) # Verify that HSM is able to initialize. ran_ok = False @@ -509,4 +454,27 @@ def qemu_send_command(port, command): stdout, stderr = s2.communicate() return stdout, stderr, s2.returncode + +def akt_native_run(testInst, cmd, **kwargs): + # run a command supplied by aktualizr-native and checks that: + # - the executable exists + # - the command runs without error + # NOTE: the base test class must have built aktualizr-native (in + # setUpClass, for example) + bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'base_prefix', 'libdir', 'bindir'], + 'aktualizr-native') + sysroot = bb_vars['SYSROOT_DESTDIR'] + bb_vars['base_prefix'] + sysrootbin = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + libdir = bb_vars['libdir'] + + program, *_ = cmd.split(' ') + p = '{}/{}'.format(sysrootbin, program) + testInst.assertTrue(os.path.isfile(p), msg="No {} found ({})".format(program, p)) + env = dict(os.environ) + env['LD_LIBRARY_PATH'] = libdir + result = runCmd(cmd, env=env, native_sysroot=sysroot, ignore_status=True, **kwargs) + testInst.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + + + # vim:set ts=4 sw=4 sts=4 expandtab: -- cgit v1.2.3-54-g00ecf From 372b3f72ae6113a450f40288f884e3a5b97c6206 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 21 Feb 2018 16:04:52 +0100 Subject: Less redundant bitbaking in oe-selftest --- lib/oeqa/selftest/updater.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index f237364..69d8eb7 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -217,14 +217,9 @@ class GrubTests(oeSelfTest): class ImplProvTests(oeSelfTest): - @classmethod - def setUpClass(cls): - logger = logging.getLogger("selftest") - logger.info('Running bitbake to build aktualizr-native tools') - bitbake('aktualizr-native') - def setUpLocal(self): self.append_config('SOTA_CLIENT_PROV = " aktualizr-implicit-prov "') + # note: this will build aktualizr-native as a side-effect self.qemu, self.s = qemu_launch(machine='qemux86-64') def tearDownLocal(self): @@ -294,15 +289,10 @@ class ImplProvTests(oeSelfTest): class HsmTests(oeSelfTest): - @classmethod - def setUpClass(cls): - logger = logging.getLogger("selftest") - logger.info('Running bitbake to build aktualizr-native tools') - bitbake('aktualizr-native') - def setUpLocal(self): self.append_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') self.append_config('SOTA_CLIENT_FEATURES = "hsm"') + # note: this will build aktualizr-native as a side-effect self.qemu, self.s = qemu_launch(machine='qemux86-64') def tearDownLocal(self): -- cgit v1.2.3-54-g00ecf From 0f55df2e10db67f33d5656c4569c8de40ca89fb5 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 21 Feb 2018 17:24:35 +0100 Subject: Fix typo in oe-selftest --- lib/oeqa/selftest/updater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py index 69d8eb7..8fbc857 100644 --- a/lib/oeqa/selftest/updater.py +++ b/lib/oeqa/selftest/updater.py @@ -345,7 +345,7 @@ class HsmTests(oeSelfTest): bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') creds = bb_vars['SOTA_PACKED_CREDENTIALS'] bb_vars_prov = get_bb_vars(['STAGING_DIR_NATIVE', 'libdir'], 'aktualizr-hsm-prov') - config = bb_vars_prov['STAGING_DIR_NATIVE'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov.toml' + config = bb_vars_prov['STAGING_DIR_NATIVE'] + bb_vars_prov['libdir'] + '/sota/sota_hsm_prov.toml' akt_native_run(self, 'aktualizr_cert_provider -c {creds} -t root@localhost -p {port} -r -s -g {config}' .format(creds=creds, port=self.qemu.ssh_port, config=config)) -- cgit v1.2.3-54-g00ecf From c9c54186bb714fb5952705a95ca72a39228b9353 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 27 Feb 2018 14:18:01 +0100 Subject: Remove aktualizr's jansson dependencies This was needed for GENIVI support, which got dropped recently --- recipes-sota/aktualizr/aktualizr_git.bb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 0aeac0f..a453ba2 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -6,7 +6,7 @@ LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=9741c346eef56131163e13b9db1241b3" DEPENDS = "boost curl openssl libarchive libsodium asn1c-native " -DEPENDS_append_class-target = "jansson ostree ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'hsm', ' libp11', '', d)} " +DEPENDS_append_class-target = "ostree ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'hsm', ' libp11', '', d)} " DEPENDS_append_class-native = "glib-2.0-native " RDEPENDS_${PN}_class-target = "lshw " -- cgit v1.2.3-54-g00ecf From c0d6f4c7949ddfc01977096b985c46c28aa8ed4f Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Wed, 28 Feb 2018 10:27:01 +0100 Subject: oe-selftest improvements. * Check successful provisioning with autoprov and grub. * Refactor provisioning check into an independent function. * Rename QemuTests to AutoProvTests since that's what it is now. * Be more explicit about MACHINE. --- lib/oeqa/selftest/cases/updater.py | 111 +++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 60 deletions(-) diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index b544762..fe18981 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -134,22 +134,20 @@ class AktualizrToolsTests(OESelftestTestCase): self.assertTrue(os.path.getsize(ca_path) > 0, "Client certificate at %s is empty." % ca_path) -class QemuTests(OESelftestTestCase): +class AutoProvTests(OESelftestTestCase): - @classmethod - def setUpClass(cls): - super(QemuTests, cls).setUpClass() - cls.qemu, cls.s = qemu_launch(machine='qemux86-64') + def setUpLocal(self): + self.append_config('MACHINE = "qemux86-64"') + self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') + self.qemu, self.s = qemu_launch(machine='qemux86-64') - @classmethod - def tearDownClass(cls): - qemu_terminate(cls.s) - super(QemuTests, cls).tearDownClass() + def tearDownLocal(self): + qemu_terminate(self.s) def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) - def test_qemu(self): + def test_provisioning(self): print('Checking machine name (hostname) of device:') stdout, stderr, retcode = self.qemu_command('hostname') self.assertEqual(retcode, 0, "Unable to check hostname. " + @@ -157,10 +155,10 @@ class QemuTests(OESelftestTestCase): machine = get_bb_var('MACHINE', 'core-image-minimal') self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. - value_str = stdout.decode()[:-1] - self.assertEqual(value_str, machine, - 'MACHINE does not match hostname: ' + machine + ', ' + value_str) - print(value_str) + value = stdout.decode()[:-1] + self.assertEqual(value, machine, + 'MACHINE does not match hostname: ' + machine + ', ' + value) + print(value) print('Checking output of aktualizr-info:') ran_ok = False for delay in [0, 1, 2, 5, 10, 15]: @@ -171,15 +169,18 @@ class QemuTests(OESelftestTestCase): break self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) + verifyProvisioned(self, machine) + class GrubTests(OESelftestTestCase): def setUpLocal(self): + self.append_config('MACHINE = "intel-corei7-64"') + self.append_config('OSTREE_BOOTLOADER = "grub"') + self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') # This is a bit of a hack but I can't see a better option. path = os.path.abspath(os.path.dirname(__file__)) metadir = path + "/../../../../../" - grub_config = 'OSTREE_BOOTLOADER = "grub"\nMACHINE = "intel-corei7-64"' - self.append_config(grub_config) self.meta_intel = metadir + "meta-intel" self.meta_minnow = metadir + "meta-updater-minnowboard" runCmd('bitbake-layers add-layer "%s"' % self.meta_intel) @@ -218,10 +219,13 @@ class GrubTests(OESelftestTestCase): break self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) + verifyProvisioned(self, machine) + class ImplProvTests(OESelftestTestCase): def setUpLocal(self): + self.append_config('MACHINE = "qemux86-64"') self.append_config('SOTA_CLIENT_PROV = " aktualizr-implicit-prov "') # note: this will build aktualizr-native as a side-effect self.qemu, self.s = qemu_launch(machine='qemux86-64') @@ -240,10 +244,10 @@ class ImplProvTests(OESelftestTestCase): machine = get_bb_var('MACHINE', 'core-image-minimal') self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. - value_str = stdout.decode()[:-1] - self.assertEqual(value_str, machine, - 'MACHINE does not match hostname: ' + machine + ', ' + value_str) - print(value_str) + value = stdout.decode()[:-1] + self.assertEqual(value, machine, + 'MACHINE does not match hostname: ' + machine + ', ' + value) + print(value) print('Checking output of aktualizr-info:') ran_ok = False for delay in [0, 1, 2, 5, 10, 15]: @@ -271,29 +275,13 @@ class ImplProvTests(OESelftestTestCase): akt_native_run(self, 'aktualizr_cert_provider -c {creds} -t root@localhost -p {port} -s -g {config}' .format(creds=creds, port=self.qemu.ssh_port, config=config)) - # Verify that device HAS provisioned. - ran_ok = False - for delay in [5, 5, 5, 5, 10]: - sleep(delay) - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'' and stdout.decode().find('Fetched metadata: yes') >= 0: - ran_ok = True - break - self.assertIn(b'Device ID: ', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) - self.assertIn(b'Primary ecu hardware ID: qemux86-64', stdout, - 'Provisioning failed: ' + stderr.decode() + stdout.decode()) - self.assertIn(b'Fetched metadata: yes', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) - p = re.compile(r'Device ID: ([a-z0-9-]*)\n') - m = p.search(stdout.decode()) - self.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) - self.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) - logger = logging.getLogger("selftest") - logger.info('Device successfully provisioned with ID: ' + m.group(1)) + verifyProvisioned(self, machine) class HsmTests(OESelftestTestCase): def setUpLocal(self): + self.append_config('MACHINE = "qemux86-64"') self.append_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') self.append_config('SOTA_CLIENT_FEATURES = "hsm"') # note: this will build aktualizr-native as a side-effect @@ -313,11 +301,11 @@ class HsmTests(OESelftestTestCase): machine = get_bb_var('MACHINE', 'core-image-minimal') self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) # Strip off line ending. - value_str = stdout.decode()[:-1] - self.assertEqual(value_str, machine, - 'MACHINE does not match hostname: ' + machine + ', ' + value_str + + value = stdout.decode()[:-1] + self.assertEqual(value, machine, + 'MACHINE does not match hostname: ' + machine + ', ' + value + '\nIs tianocore ovmf installed?') - print(value_str) + print(value) print('Checking output of aktualizr-info:') ran_ok = False for delay in [0, 1, 2, 5, 10, 15]: @@ -387,24 +375,7 @@ class HsmTests(OESelftestTestCase): self.assertEqual(p11_m.group(1), hsm_m.group(1), 'Slot number does not match: ' + p11_err.decode() + p11_out.decode() + hsm_err.decode() + hsm_out.decode()) - # Verify that device HAS provisioned. - ran_ok = False - for delay in [5, 5, 5, 5, 10]: - sleep(delay) - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'' and stdout.decode().find('Fetched metadata: yes') >= 0: - ran_ok = True - break - self.assertIn(b'Device ID: ', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) - self.assertIn(b'Primary ecu hardware ID: qemux86-64', stdout, - 'Provisioning failed: ' + stderr.decode() + stdout.decode()) - self.assertIn(b'Fetched metadata: yes', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) - p = re.compile(r'Device ID: ([a-z0-9-]*)\n') - m = p.search(stdout.decode()) - self.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) - self.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) - logger = logging.getLogger("selftest") - logger.info('Device successfully provisioned with ID: ' + m.group(1)) + verifyProvisioned(self, machine) def qemu_launch(efi=False, machine=None): @@ -471,5 +442,25 @@ def akt_native_run(testInst, cmd, **kwargs): testInst.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) +def verifyProvisioned(testInst, machine): + # Verify that device HAS provisioned. + ran_ok = False + for delay in [5, 5, 5, 5, 10]: + sleep(delay) + stdout, stderr, retcode = testInst.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'' and stdout.decode().find('Fetched metadata: yes') >= 0: + ran_ok = True + break + testInst.assertIn(b'Device ID: ', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) + testInst.assertIn(b'Primary ecu hardware ID: ' + machine.encode(), stdout, + 'Provisioning failed: ' + stderr.decode() + stdout.decode()) + testInst.assertIn(b'Fetched metadata: yes', stdout, 'Provisioning failed: ' + stderr.decode() + stdout.decode()) + p = re.compile(r'Device ID: ([a-z0-9-]*)\n') + m = p.search(stdout.decode()) + testInst.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) + testInst.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) + logger = logging.getLogger("selftest") + logger.info('Device successfully provisioned with ID: ' + m.group(1)) + # vim:set ts=4 sw=4 sts=4 expandtab: -- cgit v1.2.3-54-g00ecf From 0fb122d88290a7476d694547f4d05a15d5ec38d1 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Wed, 28 Feb 2018 11:23:07 +0100 Subject: Add qemu layer for qemu tests if not present. The layers required for the grub test are now also only added if not already present. This should make the tests runnable from an environment configured for raspberry pi. --- lib/oeqa/selftest/cases/updater.py | 61 +++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index fe18981..a9c3206 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -139,10 +139,22 @@ class AutoProvTests(OESelftestTestCase): def setUpLocal(self): self.append_config('MACHINE = "qemux86-64"') self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') + layer = "meta-updater-qemux86-64" + result = runCmd('bitbake-layers show-layers') + if re.search(layer, result.output) is None: + # This is a bit of a hack but I can't see a better option. + path = os.path.abspath(os.path.dirname(__file__)) + metadir = path + "/../../../../../" + self.meta_qemu = metadir + layer + runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu) + else: + self.meta_qemu = None self.qemu, self.s = qemu_launch(machine='qemux86-64') def tearDownLocal(self): qemu_terminate(self.s) + if self.meta_qemu: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_qemu, ignore_status=True) def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) @@ -178,19 +190,30 @@ class GrubTests(OESelftestTestCase): self.append_config('MACHINE = "intel-corei7-64"') self.append_config('OSTREE_BOOTLOADER = "grub"') self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') + layer_intel = "meta-intel" + layer_minnow = "meta-updater-minnowboard" + result = runCmd('bitbake-layers show-layers') # This is a bit of a hack but I can't see a better option. path = os.path.abspath(os.path.dirname(__file__)) metadir = path + "/../../../../../" - self.meta_intel = metadir + "meta-intel" - self.meta_minnow = metadir + "meta-updater-minnowboard" - runCmd('bitbake-layers add-layer "%s"' % self.meta_intel) - runCmd('bitbake-layers add-layer "%s"' % self.meta_minnow) + if re.search(layer_intel, result.output) is None: + self.meta_intel = metadir + layer_intel + runCmd('bitbake-layers add-layer "%s"' % self.meta_intel) + else: + self.meta_intel = None + if re.search(layer_minnow, result.output) is None: + self.meta_minnow = metadir + layer_minnow + runCmd('bitbake-layers add-layer "%s"' % self.meta_minnow) + else: + self.meta_minnow = None self.qemu, self.s = qemu_launch(efi=True, machine='intel-corei7-64') def tearDownLocal(self): qemu_terminate(self.s) - runCmd('bitbake-layers remove-layer "%s"' % self.meta_intel, ignore_status=True) - runCmd('bitbake-layers remove-layer "%s"' % self.meta_minnow, ignore_status=True) + if self.meta_intel: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_intel, ignore_status=True) + if self.meta_minnow: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_minnow, ignore_status=True) def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) @@ -227,11 +250,22 @@ class ImplProvTests(OESelftestTestCase): def setUpLocal(self): self.append_config('MACHINE = "qemux86-64"') self.append_config('SOTA_CLIENT_PROV = " aktualizr-implicit-prov "') - # note: this will build aktualizr-native as a side-effect + layer = "meta-updater-qemux86-64" + result = runCmd('bitbake-layers show-layers') + if re.search(layer, result.output) is None: + # This is a bit of a hack but I can't see a better option. + path = os.path.abspath(os.path.dirname(__file__)) + metadir = path + "/../../../../../" + self.meta_qemu = metadir + layer + runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu) + else: + self.meta_qemu = None self.qemu, self.s = qemu_launch(machine='qemux86-64') def tearDownLocal(self): qemu_terminate(self.s) + if self.meta_qemu: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_qemu, ignore_status=True) def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) @@ -284,11 +318,22 @@ class HsmTests(OESelftestTestCase): self.append_config('MACHINE = "qemux86-64"') self.append_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') self.append_config('SOTA_CLIENT_FEATURES = "hsm"') - # note: this will build aktualizr-native as a side-effect + layer = "meta-updater-qemux86-64" + result = runCmd('bitbake-layers show-layers') + if re.search(layer, result.output) is None: + # This is a bit of a hack but I can't see a better option. + path = os.path.abspath(os.path.dirname(__file__)) + metadir = path + "/../../../../../" + self.meta_qemu = metadir + layer + runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu) + else: + self.meta_qemu = None self.qemu, self.s = qemu_launch(machine='qemux86-64') def tearDownLocal(self): qemu_terminate(self.s) + if self.meta_qemu: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_qemu, ignore_status=True) def qemu_command(self, command): return qemu_send_command(self.qemu.ssh_port, command) -- cgit v1.2.3-54-g00ecf From 97ea268738bbacbe383d20f0ae9b1df7aff2b58a Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Thu, 1 Mar 2018 15:13:06 +0100 Subject: Mention SOTA_PACKED_CREDENTIALS in oe-selftest section of docs. Also fix a broken link. --- README.adoc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.adoc b/README.adoc index c87bd01..3562f52 100644 --- a/README.adoc +++ b/README.adoc @@ -20,7 +20,7 @@ If you already have a Yocto-based project and you want to add atomic filesystem 2. Clone BSP integration layer (`meta-updater-$\{PLATFORM}`, e.g. https://github.com/advancedtelematic/meta-updater-raspberrypi[meta-updater-raspberrypi]) and add it to your `conf/bblayers.conf`. If your board isn't supported yet, you could write a BSP integration for it yourself. See the <> section for the details. 3. Set up your https://www.yoctoproject.org/docs/2.1/ref-manual/ref-manual.html#var-DISTRO[distro]. If you are using "poky", the default distro in Yocto, you can change it in your `conf/local.conf` to "poky-sota". Alternatively, if you are using your own or third party distro configuration, you can add `INHERIT += " sota"` to it, thus combining capabilities of your distro with meta-updater features. -You can then build your image as usual, with bitbake. After building the root file system, bitbake will then create an https://ostree.readthedocs.io/en/latest/manual/adapting-existing/[OSTree-enabled version] of it, commit it to your local OSTree repo and (optionally) push it to a remote server. Additionally, a live disk image will be created (normally named `$\{IMAGE_NAME}.-sdimg-ota` e.g. `core-image-raspberrypi3.rpi-sdimg-ota`). You can control this behaviour through <>. +You can then build your image as usual, with bitbake. After building the root file system, bitbake will then create an https://ostree.readthedocs.io/en/latest/manual/adapting-existing/[OSTree-enabled version] of it, commit it to your local OSTree repo and (optionally) push it to a remote server. Additionally, a live disk image will be created (normally named `$\{IMAGE_NAME}.-sdimg-ota` e.g. `core-image-raspberrypi3.rpi-sdimg-ota`). You can control this behaviour through <>. === Build in AGL @@ -73,7 +73,7 @@ You may take a look into https://github.com/advancedtelematic/meta-updater-minno Although we have used U-Boot so far, other boot loaders can be configured work with OSTree as well. -== SOTA-related variables in `local.conf` +== SOTA-related variables in local.conf * `OSTREE_REPO` - path to your OSTree repository. Defaults to `$\{DEPLOY_DIR_IMAGE}/ostree_repo` * `OSTREE_OSNAME` - OS deployment name on your target device. For more information about deployments and osnames see the https://ostree.readthedocs.io/en/latest/manual/deployment/[OSTree documentation]. Defaults to "poky". @@ -151,13 +151,15 @@ SANITY_TESTED_DISTROS = "" IMAGE_INSTALL_append = " dropbear " ``` -3. To be able to build an image for the grub tests, you will need to install https://github.com/tianocore/tianocore.github.io/wiki/OVMF[TianoCore's ovmf] package on your host system. On Debian-like systems, you can do so with this command: +3. Some tests require that `SOTA_PACKED_CREDENTIALS` is set in your `conf/local.conf`. See the <> section. + +4. To be able to build an image for the grub tests, you will need to install https://github.com/tianocore/tianocore.github.io/wiki/OVMF[TianoCore's ovmf] package on your host system. On Debian-like systems, you can do so with this command: + ``` sudo apt install ovmf ``` -4. Run oe-selftest: +5. Run oe-selftest: + ``` oe-selftest --run-tests updater -- cgit v1.2.3-54-g00ecf From 81b2fa6bf0b5d7d68dc81c83ecc1ba15cba2ac9b Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Fri, 2 Mar 2018 09:39:39 +0100 Subject: Add a basic raspberry pi test. There's not much we can do, since booting the device via a test is not practical. Still, it's useful to make sure that we can build the image. If trying to build the image in an environment designed for qemu, this takes some trickery to set things up just right. Also consistently set up layers before setting the MACHINE, since the sanity checker sometimes complains otherwise. --- lib/oeqa/selftest/cases/updater.py | 114 +++++++++++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 16 deletions(-) diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index a9c3206..adb4061 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -64,7 +64,6 @@ class GeneralTests(OESelftestTestCase): "Java not found. Do you have a JDK installed on your host machine?") def test_add_package(self): - print('') deploydir = get_bb_var('DEPLOY_DIR_IMAGE') imagename = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal') image_path = deploydir + '/' + imagename + '.otaimg' @@ -137,18 +136,20 @@ class AktualizrToolsTests(OESelftestTestCase): class AutoProvTests(OESelftestTestCase): def setUpLocal(self): - self.append_config('MACHINE = "qemux86-64"') - self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') layer = "meta-updater-qemux86-64" result = runCmd('bitbake-layers show-layers') if re.search(layer, result.output) is None: - # This is a bit of a hack but I can't see a better option. + # Assume the directory layout for finding other layers. We could also + # make assumptions by using 'show-layers', but either way, if the + # layers we need aren't where we expect them, we are out of like. path = os.path.abspath(os.path.dirname(__file__)) metadir = path + "/../../../../../" self.meta_qemu = metadir + layer runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu) else: self.meta_qemu = None + self.append_config('MACHINE = "qemux86-64"') + self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') self.qemu, self.s = qemu_launch(machine='qemux86-64') def tearDownLocal(self): @@ -184,16 +185,91 @@ class AutoProvTests(OESelftestTestCase): verifyProvisioned(self, machine) -class GrubTests(OESelftestTestCase): +class RpiTests(OESelftestTestCase): def setUpLocal(self): - self.append_config('MACHINE = "intel-corei7-64"') - self.append_config('OSTREE_BOOTLOADER = "grub"') + # Add layers before changing the machine type, otherwise the sanity + # checker complains loudly. + layer_python = "meta-openembedded/meta-python" + layer_rpi = "meta-raspberrypi" + layer_upd_rpi = "meta-updater-raspberrypi" + result = runCmd('bitbake-layers show-layers') + # Assume the directory layout for finding other layers. We could also + # make assumptions by using 'show-layers', but either way, if the + # layers we need aren't where we expect them, we are out of like. + path = os.path.abspath(os.path.dirname(__file__)) + metadir = path + "/../../../../../" + if re.search(layer_python, result.output) is None: + self.meta_python = metadir + layer_python + runCmd('bitbake-layers add-layer "%s"' % self.meta_python) + else: + self.meta_python = None + if re.search(layer_rpi, result.output) is None: + self.meta_rpi = metadir + layer_rpi + runCmd('bitbake-layers add-layer "%s"' % self.meta_rpi) + else: + self.meta_rpi = None + if re.search(layer_upd_rpi, result.output) is None: + self.meta_upd_rpi = metadir + layer_upd_rpi + runCmd('bitbake-layers add-layer "%s"' % self.meta_upd_rpi) + else: + self.meta_upd_rpi = None + + # This is trickier that I would've thought. The fundamental problem is + # that the qemu layer changes the u-boot file extension to .rom, but + # raspberrypi still expects .bin. To prevent this, the qemu layer must + # be temporarily removed if it is present. It has to be removed by name + # without the complete path, but to add it back when we are done, we + # need the full path. + p = re.compile(r'meta-updater-qemux86-64\s*(\S*meta-updater-qemux86-64)\s') + m = p.search(result.output) + if m and m.lastindex > 0: + self.meta_qemu = m.group(1) + runCmd('bitbake-layers remove-layer meta-updater-qemux86-64') + else: + self.meta_qemu = None + + self.append_config('MACHINE = "raspberrypi3"') self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') + + def tearDownLocal(self): + if self.meta_qemu: + runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu, ignore_status=True) + if self.meta_upd_rpi: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_upd_rpi, ignore_status=True) + if self.meta_rpi: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_rpi, ignore_status=True) + if self.meta_python: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_python, ignore_status=True) + + def test_rpi(self): + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build rpi-basic-image') + self.append_config('SOTA_CLIENT_PROV = "aktualizr-auto-prov"') + bitbake('rpi-basic-image') + credentials = get_bb_var('SOTA_PACKED_CREDENTIALS') + # Skip the test if the variable SOTA_PACKED_CREDENTIALS is not set. + if credentials is None: + raise unittest.SkipTest("Variable 'SOTA_PACKED_CREDENTIALS' not set.") + # Check if the file exists. + self.assertTrue(os.path.isfile(credentials), "File %s does not exist" % credentials) + deploydir = get_bb_var('DEPLOY_DIR_IMAGE') + imagename = get_bb_var('IMAGE_LINK_NAME', 'rpi-basic-image') + # Check if the credentials are included in the output image. + result = runCmd('tar -jtvf %s/%s.tar.bz2 | grep sota_provisioning_credentials.zip' % + (deploydir, imagename), ignore_status=True) + self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + + +class GrubTests(OESelftestTestCase): + + def setUpLocal(self): layer_intel = "meta-intel" layer_minnow = "meta-updater-minnowboard" result = runCmd('bitbake-layers show-layers') - # This is a bit of a hack but I can't see a better option. + # Assume the directory layout for finding other layers. We could also + # make assumptions by using 'show-layers', but either way, if the + # layers we need aren't where we expect them, we are out of like. path = os.path.abspath(os.path.dirname(__file__)) metadir = path + "/../../../../../" if re.search(layer_intel, result.output) is None: @@ -206,6 +282,9 @@ class GrubTests(OESelftestTestCase): runCmd('bitbake-layers add-layer "%s"' % self.meta_minnow) else: self.meta_minnow = None + self.append_config('MACHINE = "intel-corei7-64"') + self.append_config('OSTREE_BOOTLOADER = "grub"') + self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') self.qemu, self.s = qemu_launch(efi=True, machine='intel-corei7-64') def tearDownLocal(self): @@ -219,7 +298,6 @@ class GrubTests(OESelftestTestCase): return qemu_send_command(self.qemu.ssh_port, command) def test_grub(self): - print('') print('Checking machine name (hostname) of device:') stdout, stderr, retcode = self.qemu_command('hostname') self.assertEqual(retcode, 0, "Unable to check hostname. " + @@ -248,18 +326,20 @@ class GrubTests(OESelftestTestCase): class ImplProvTests(OESelftestTestCase): def setUpLocal(self): - self.append_config('MACHINE = "qemux86-64"') - self.append_config('SOTA_CLIENT_PROV = " aktualizr-implicit-prov "') layer = "meta-updater-qemux86-64" result = runCmd('bitbake-layers show-layers') if re.search(layer, result.output) is None: - # This is a bit of a hack but I can't see a better option. + # Assume the directory layout for finding other layers. We could also + # make assumptions by using 'show-layers', but either way, if the + # layers we need aren't where we expect them, we are out of like. path = os.path.abspath(os.path.dirname(__file__)) metadir = path + "/../../../../../" self.meta_qemu = metadir + layer runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu) else: self.meta_qemu = None + self.append_config('MACHINE = "qemux86-64"') + self.append_config('SOTA_CLIENT_PROV = " aktualizr-implicit-prov "') self.qemu, self.s = qemu_launch(machine='qemux86-64') def tearDownLocal(self): @@ -315,19 +395,21 @@ class ImplProvTests(OESelftestTestCase): class HsmTests(OESelftestTestCase): def setUpLocal(self): - self.append_config('MACHINE = "qemux86-64"') - self.append_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') - self.append_config('SOTA_CLIENT_FEATURES = "hsm"') layer = "meta-updater-qemux86-64" result = runCmd('bitbake-layers show-layers') if re.search(layer, result.output) is None: - # This is a bit of a hack but I can't see a better option. + # Assume the directory layout for finding other layers. We could also + # make assumptions by using 'show-layers', but either way, if the + # layers we need aren't where we expect them, we are out of like. path = os.path.abspath(os.path.dirname(__file__)) metadir = path + "/../../../../../" self.meta_qemu = metadir + layer runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu) else: self.meta_qemu = None + self.append_config('MACHINE = "qemux86-64"') + self.append_config('SOTA_CLIENT_PROV = "aktualizr-hsm-prov"') + self.append_config('SOTA_CLIENT_FEATURES = "hsm"') self.qemu, self.s = qemu_launch(machine='qemux86-64') def tearDownLocal(self): -- cgit v1.2.3-54-g00ecf From 3d77f5a4ef4e312c07ddb513ff1e21c6b2fb1d42 Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Tue, 5 Dec 2017 13:53:29 +0100 Subject: Fix calculate_size in case $SIZE < $MIN calculate_size had a typo that made one of the cases fail. This patch fixes it. --- classes/image_types_ota.bbclass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/image_types_ota.bbclass b/classes/image_types_ota.bbclass index e753e0e..d21441d 100644 --- a/classes/image_types_ota.bbclass +++ b/classes/image_types_ota.bbclass @@ -32,7 +32,7 @@ calculate_size () { fi if [ "$SIZE" -lt "$MIN" ]; then - $SIZE=$MIN + SIZE=$MIN fi SIZE=`expr $SIZE \+ $EXTRA` -- cgit v1.2.3-54-g00ecf From bbce1809a921e627678947e9585ea15223b181d9 Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Wed, 14 Mar 2018 11:44:26 +0100 Subject: Add secondary-image to meta-updater This required splitting the aktualizr package into several components, in order to be able to either install the primary 'aktualzr' or the secondary 'aktualizr-secondary'. --- README.adoc | 4 +-- lib/oeqa/selftest/cases/updater.py | 45 +++++++++++++++++++++++++++++++-- recipes-sota/aktualizr/aktualizr_git.bb | 42 +++++++++++++++++------------- recipes-test/images/secondary-image.bb | 18 +++++++++++++ 4 files changed, 87 insertions(+), 22 deletions(-) create mode 100644 recipes-test/images/secondary-image.bb diff --git a/README.adoc b/README.adoc index 3562f52..980fa81 100644 --- a/README.adoc +++ b/README.adoc @@ -80,8 +80,8 @@ Although we have used U-Boot so far, other boot loaders can be configured work w * `OSTREE_INITRAMFS_IMAGE` - initramfs/initrd image that is used as a proxy while booting into OSTree deployment. Do not change this setting unless you are sure that your initramfs can serve as such a proxy. * `SOTA_PACKED_CREDENTIALS` - when set, your ostree commit will be pushed to a remote repo as a bitbake step. This should be the path to a zipped credentials file in https://github.com/advancedtelematic/aktualizr/blob/master/docs/credentials.adoc[the format accepted by garage-push]. * `SOTA_CLIENT_PROV` - which provisioning method to use. Valid options are https://github.com/advancedtelematic/aktualizr/blob/master/docs/automatic-provisioning.adoc[`aktualizr-auto-prov`], https://github.com/advancedtelematic/aktualizr/blob/master/docs/implicit-provisioning.adoc[`aktualizr-implicit-prov`], and `aktualizr-hsm-prov`. The default is `aktualizr-auto-prov`. This can also be set to an empty string to avoid using a provisioning recipe. -* `SOTA_CLIENT_FEATURES` - extensions to aktualizr. Multiple can be specified if separated by spaces. Valid options are `hsm` (to build with HSM support) and `secondary-example` (to install an example https://github.com/advancedtelematic/aktualizr/blob/master/docs/legacysecondary.adoc[legacy secondary interface] in the image). -* `SOTA_LEGACY_SECONDARY_INTERFACE` - path to a legacy secondary interface installed on the device. To use the example interface from the Aktualizr repo, use `/usr/bin/example-interface` and make sure `SOTA_CLIENT_FEATURES = "secondary-example"`. +* `SOTA_CLIENT_FEATURES` - extensions to aktualizr. The only valid option is `hsm` (to build with HSM support) +* `SOTA_LEGACY_SECONDARY_INTERFACE` - path to a https://github.com/advancedtelematic/aktualizr/blob/master/docs/legacysecondary.adoc[legacy secondary interface] installed on the device. To use the example interface from the Aktualizr repo, use `/usr/bin/example-interface` and make sure `IMAGE_INSTALL_append` includes `aktualizr-examples`. * `SOTA_SECONDARY_ECUS` - a list of paths separated by spaces of JSON configuration files for virtual secondaries on the host. These will be installed into `/var/sota/ecus` on the device. * `SOTA_VIRTUAL_SECONDARIES` - a list of paths separated by spaces of JSON configuration files for virtual secondaries installed on the device. If `SOTA_SECONDARY_ECUS` is used to install them, then you can expect them to be installed in `/var/sota/ecus`. diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index adb4061..a5072e8 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -504,14 +504,55 @@ class HsmTests(OESelftestTestCase): verifyProvisioned(self, machine) +class SecondaryTests(OESelftestTestCase): + @classmethod + def setUpClass(cls): + super(SecondaryTests, cls).setUpClass() + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build secondary-image') + bitbake('secondary-image') + + def setUpLocal(self): + layer = "meta-updater-qemux86-64" + result = runCmd('bitbake-layers show-layers') + if re.search(layer, result.output) is None: + # Assume the directory layout for finding other layers. We could also + # make assumptions by using 'show-layers', but either way, if the + # layers we need aren't where we expect them, we are out of like. + path = os.path.abspath(os.path.dirname(__file__)) + metadir = path + "/../../../../../" + self.meta_qemu = metadir + layer + runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu) + else: + self.meta_qemu = None + self.append_config('MACHINE = "qemux86-64"') + self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') + self.qemu, self.s = qemu_launch(machine='qemux86-64', imagename='secondary-image') + + def tearDownLocal(self): + qemu_terminate(self.s) + if self.meta_qemu: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_qemu, ignore_status=True) + + def qemu_command(self, command): + return qemu_send_command(self.qemu.ssh_port, command) + + def test_secondary_present(self): + print('Checking aktualizr-secondary is present') + stdout, stderr, retcode = self.qemu_command('aktualizr-secondary --help') + self.assertEqual(retcode, 0, "Unable to run aktualizr-secondary --help") + self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) -def qemu_launch(efi=False, machine=None): +def qemu_launch(efi=False, machine=None, imagename=None): logger = logging.getLogger("selftest") logger.info('Running bitbake to build core-image-minimal') bitbake('core-image-minimal') # Create empty object. args = type('', (), {})() - args.imagename = 'core-image-minimal' + if imagename: + args.imagename = imagename + else: + args.imagename = 'core-image-minimal' args.mac = None # Could use DEPLOY_DIR_IMAGE here but it's already in the machine # subdirectory. diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 4c4e975..ad06339 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -20,7 +20,7 @@ SRC_URI = " \ file://aktualizr.service \ file://aktualizr-serialcan.service \ " -SRCREV = "1a6432175b9fb7326173e8db35d326cc1a1011a1" +SRCREV = "dca6271f4ec06eb2272cc99b4b9cf76a9805f18d" BRANCH ?= "master" S = "${WORKDIR}/git" @@ -34,27 +34,19 @@ BBCLASSEXTEND =+ "native" EXTRA_OECMAKE = "-DWARNING_AS_ERROR=OFF -DCMAKE_BUILD_TYPE=Release -DAKTUALIZR_VERSION=${PV} " EXTRA_OECMAKE_append_class-target = " -DBUILD_OSTREE=ON -DBUILD_ISOTP=ON ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'hsm', '-DBUILD_P11=ON', '', d)} " -EXTRA_OECMAKE_append_class-native = " -DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF " +EXTRA_OECMAKE_append_class-native = " -DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF -DBUILD_SYSTEMD=OFF " do_install_append () { rm -fr ${D}${libdir}/systemd + rm -f ${D}${libdir}/sota/sota.toml # Only needed for the Debian package } do_install_append_class-target () { - rm -f ${D}${bindir}/aktualizr_cert_provider - rm -f ${D}${bindir}/aktualizr_implicit_writer - rm -f ${D}${libdir}/sota/sota.toml - ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-example', '', 'rm -f ${D}${bindir}/example-interface', d)} - ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-isotp-example', '', 'rm -f ${D}${bindir}/isotp-test-interface', d)} - install -d ${D}${systemd_unitdir}/system aktualizr_service=${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'serialcan', '${WORKDIR}/aktualizr-serialcan.service', '${WORKDIR}/aktualizr.service', d)} install -m 0644 ${aktualizr_service} ${D}${systemd_unitdir}/system/aktualizr.service } do_install_append_class-native () { - rm -f ${D}${bindir}/aktualizr - rm -f ${D}${bindir}/aktualizr-info - rm -f ${D}${bindir}/example-interface install -d ${D}${libdir}/sota install -m 0644 ${S}/config/sota_autoprov.toml ${D}/${libdir}/sota/sota_autoprov.toml install -m 0644 ${S}/config/sota_hsm_prov.toml ${D}/${libdir}/sota/sota_hsm_prov.toml @@ -65,23 +57,37 @@ do_install_append_class-native () { install -m 0644 ${B}/src/sota_tools/garage-sign-prefix/src/garage-sign/lib/* ${D}${libdir} } -FILES_${PN}_append = " \ - ${libdir}/sota \ - " +PACKAGES =+ " ${PN}-common ${PN}-examples ${PN}-host-tools ${PN}-secondary " -FILES_${PN}_class-target = " \ +FILES_${PN} = " \ ${bindir}/aktualizr \ ${bindir}/aktualizr-info \ ${systemd_unitdir}/system/aktualizr.service \ " -FILES_${PN}_append_class-target = " ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-example', ' ${bindir}/example-interface', '', d)} " -FILES_${PN}_append_class-target = " ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-isotp-example', ' ${bindir}/isotp-test-interface', '', d)} " -FILES_${PN}_class-native = " \ +FILES_${PN}-common = " \ + ${libdir}/sota/schemas \ + " + +FILES_${PN}-examples = " \ + ${libdir}/sota/demo_secondary.json \ + ${bindir}/example-interface \ + ${bindir}/isotp-test-interface \ + " + +FILES_${PN}-host-tools = " \ ${bindir}/aktualizr_cert_provider \ ${bindir}/aktualizr_implicit_writer \ ${bindir}/garage-deploy \ ${bindir}/garage-push \ " +FILES_${PN}-secondary = " \ + ${bindir}/aktualizr-secondary \ + " + +# Both primary and secondary need the SQL Schemas +RDEPENDS_${PN}_class-target =+ "${PN}-common" +RDEPENDS_${PN}-secondary_class-target =+ "${PN}-common" + # vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/recipes-test/images/secondary-image.bb b/recipes-test/images/secondary-image.bb new file mode 100644 index 0000000..c7a91db --- /dev/null +++ b/recipes-test/images/secondary-image.bb @@ -0,0 +1,18 @@ +include recipes-core/images/core-image-minimal.bb + +SUMMARY = "A minimal Uptane Secondary image running aktualizr-secondary" + +LICENSE = "MIT" + + +# Remove default aktualizr primary, and the provisioning configuration (which +# RDEPENDS on aktualizr) +IMAGE_INSTALL_remove = " \ + aktualizr \ + aktualizr-auto-prov \ + aktualizr-ca-implicit-prov \ + aktualizr-hsm-prov \ + aktualizr-implicit-prov \ + " + +IMAGE_INSTALL_append = " aktualizr-secondary " \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 66a4721d0b7885a18db952d69f7ee385a95b2f2b Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Wed, 14 Mar 2018 16:00:53 +0100 Subject: Add systemd socket activation for secondary --- lib/oeqa/selftest/cases/updater.py | 5 +++++ recipes-sota/aktualizr/aktualizr_git.bb | 15 ++++++++++++++- recipes-sota/aktualizr/files/aktualizr-secondary.service | 9 +++++++++ recipes-sota/aktualizr/files/aktualizr-secondary.socket | 5 +++++ 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 recipes-sota/aktualizr/files/aktualizr-secondary.service create mode 100644 recipes-sota/aktualizr/files/aktualizr-secondary.socket diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index a5072e8..1850d98 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -543,6 +543,11 @@ class SecondaryTests(OESelftestTestCase): self.assertEqual(retcode, 0, "Unable to run aktualizr-secondary --help") self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) + def test_secondary_listening(self): + print('Checking aktualizr-secondary is present') + stdout, stderr, retcode = self.qemu_command('echo test | nc localhost 9030') + self.assertEqual(retcode, 0, "Unable to connect to secondary") + def qemu_launch(efi=False, machine=None, imagename=None): logger = logging.getLogger("selftest") logger.info('Running bitbake to build core-image-minimal') diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index ad06339..5e683ac 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -18,9 +18,11 @@ PR = "7" SRC_URI = " \ gitsm://github.com/advancedtelematic/aktualizr;branch=${BRANCH} \ file://aktualizr.service \ + file://aktualizr-secondary.service \ + file://aktualizr-secondary.socket \ file://aktualizr-serialcan.service \ " -SRCREV = "dca6271f4ec06eb2272cc99b4b9cf76a9805f18d" +SRCREV = "fbb3404824c4eb239455c7fa1a794c26e2ea954d" BRANCH ?= "master" S = "${WORKDIR}/git" @@ -28,7 +30,10 @@ S = "${WORKDIR}/git" inherit cmake inherit systemd + +SYSTEMD_PACKAGES = "${PN} ${PN}-secondary" SYSTEMD_SERVICE_${PN} = "aktualizr.service" +SYSTEMD_SERVICE_${PN}-secondary = "aktualizr-secondary.socket" BBCLASSEXTEND =+ "native" @@ -39,6 +44,11 @@ EXTRA_OECMAKE_append_class-native = " -DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF - do_install_append () { rm -fr ${D}${libdir}/systemd rm -f ${D}${libdir}/sota/sota.toml # Only needed for the Debian package + install -d ${D}${libdir}/sota + install -m 0644 ${S}/config/sota_secondary.toml ${D}/${libdir}/sota/sota_secondary.toml + install -d ${D}${systemd_unitdir}/system + install -m 0644 ${WORKDIR}/aktualizr-secondary.socket ${D}${systemd_unitdir}/system/aktualizr-secondary.socket + install -m 0644 ${WORKDIR}/aktualizr-secondary.service ${D}${systemd_unitdir}/system/aktualizr-secondary.service } do_install_append_class-target () { install -d ${D}${systemd_unitdir}/system @@ -84,6 +94,9 @@ FILES_${PN}-host-tools = " \ FILES_${PN}-secondary = " \ ${bindir}/aktualizr-secondary \ + ${libdir}/sota/sota_secondary.toml \ + ${systemd_unitdir}/system/aktualizr-secondary.socket \ + ${systemd_unitdir}/system/aktualizr-secondary.service \ " # Both primary and secondary need the SQL Schemas diff --git a/recipes-sota/aktualizr/files/aktualizr-secondary.service b/recipes-sota/aktualizr/files/aktualizr-secondary.service new file mode 100644 index 0000000..a1e0e1b --- /dev/null +++ b/recipes-sota/aktualizr/files/aktualizr-secondary.service @@ -0,0 +1,9 @@ +[Unit] +Description=Aktualizr SOTA Client (UPTANE Secondary) + +[Service] +RestartSec=10 +Restart=always +EnvironmentFile=-/etc/sota/sota.env +ExecStart=/usr/bin/aktualizr-secondary --config /usr/lib/sota/sota_secondary.toml + diff --git a/recipes-sota/aktualizr/files/aktualizr-secondary.socket b/recipes-sota/aktualizr/files/aktualizr-secondary.socket new file mode 100644 index 0000000..1cb4269 --- /dev/null +++ b/recipes-sota/aktualizr/files/aktualizr-secondary.socket @@ -0,0 +1,5 @@ +[Socket] +ListenStream=9030 + +[Install] +WantedBy=sockets.target \ No newline at end of file -- cgit v1.2.3-54-g00ecf From fc8f9b4b1721a029a30bf41e6086cfbff085089d Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Mon, 19 Mar 2018 16:31:31 +0100 Subject: Add a --secondary-network option to run-qemu-ota This sets up a simulated 'in vehicle' network. Add support for a Primary node with a DHCP server and a secondary node with a DHCP client. --- .../demo-network-config/files/25-dhcp-server.network | 12 ++++++++++++ .../demo-network-config/files/26-dhcp-client.network | 6 ++++++ .../demo-network-config/primary-network-config.bb | 16 ++++++++++++++++ .../demo-network-config/secondary-network-config.bb | 16 ++++++++++++++++ recipes-test/images/primary-image.bb | 12 ++++++++++++ recipes-test/images/secondary-image.bb | 5 ++++- scripts/qemucommand.py | 6 ++++++ scripts/run-qemu-ota | 3 +++ 8 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 recipes-test/demo-network-config/files/25-dhcp-server.network create mode 100644 recipes-test/demo-network-config/files/26-dhcp-client.network create mode 100644 recipes-test/demo-network-config/primary-network-config.bb create mode 100644 recipes-test/demo-network-config/secondary-network-config.bb create mode 100644 recipes-test/images/primary-image.bb diff --git a/recipes-test/demo-network-config/files/25-dhcp-server.network b/recipes-test/demo-network-config/files/25-dhcp-server.network new file mode 100644 index 0000000..4766f9a --- /dev/null +++ b/recipes-test/demo-network-config/files/25-dhcp-server.network @@ -0,0 +1,12 @@ +[Match] +Name=enp0s4 + +[Network] +Description=Private internal network between aktualizr Primary and Secondary nodes +DHCPServer=yes +Address=10.0.3.1/24 +IPForward=yes +IPMasquerade=yes + +[DHCPServer] +PoolOffset=10 \ No newline at end of file diff --git a/recipes-test/demo-network-config/files/26-dhcp-client.network b/recipes-test/demo-network-config/files/26-dhcp-client.network new file mode 100644 index 0000000..319664f --- /dev/null +++ b/recipes-test/demo-network-config/files/26-dhcp-client.network @@ -0,0 +1,6 @@ +[Match] +Name=enp0s4 + +[Network] +Description=Private internal network between aktualizr Primary and Secondary nodes +DHCP=yes diff --git a/recipes-test/demo-network-config/primary-network-config.bb b/recipes-test/demo-network-config/primary-network-config.bb new file mode 100644 index 0000000..78678a2 --- /dev/null +++ b/recipes-test/demo-network-config/primary-network-config.bb @@ -0,0 +1,16 @@ +DESCRIPTION = "Sample network configuration for an Uptane Primary" +LICENSE = "CLOSED" + +inherit allarch + +SRC_URI = "file://25-dhcp-server.network" + + +FILES_${PN} = "/usr/lib/systemd/network" + +PR = "1" + +do_install() { + install -d ${D}/usr/lib/systemd/network + install -m 0644 ${WORKDIR}/25-dhcp-server.network ${D}/usr/lib/systemd/network/ +} diff --git a/recipes-test/demo-network-config/secondary-network-config.bb b/recipes-test/demo-network-config/secondary-network-config.bb new file mode 100644 index 0000000..492d3ca --- /dev/null +++ b/recipes-test/demo-network-config/secondary-network-config.bb @@ -0,0 +1,16 @@ +DESCRIPTION = "Sample network configuration for an Uptane Secondary" +LICENSE = "CLOSED" + +inherit allarch + +SRC_URI = "file://26-dhcp-client.network" + + +FILES_${PN} = "/usr/lib/systemd/network" + +PR = "1" + +do_install() { + install -d ${D}/usr/lib/systemd/network + install -m 0644 ${WORKDIR}/26-dhcp-client.network ${D}/usr/lib/systemd/network/ +} diff --git a/recipes-test/images/primary-image.bb b/recipes-test/images/primary-image.bb new file mode 100644 index 0000000..6c06527 --- /dev/null +++ b/recipes-test/images/primary-image.bb @@ -0,0 +1,12 @@ +include recipes-core/images/core-image-minimal.bb + +SUMMARY = "A minimal Uptane Primary image running aktualizr, for testing with a Linux secondary" + +LICENSE = "MIT" + +IMAGE_INSTALL_remove = " \ + " + +IMAGE_INSTALL_append = " \ + primary-network-config \ + " diff --git a/recipes-test/images/secondary-image.bb b/recipes-test/images/secondary-image.bb index c7a91db..c1ce57a 100644 --- a/recipes-test/images/secondary-image.bb +++ b/recipes-test/images/secondary-image.bb @@ -15,4 +15,7 @@ IMAGE_INSTALL_remove = " \ aktualizr-implicit-prov \ " -IMAGE_INSTALL_append = " aktualizr-secondary " \ No newline at end of file +IMAGE_INSTALL_append = " \ + aktualizr-secondary \ + secondary-network-config \ + " diff --git a/scripts/qemucommand.py b/scripts/qemucommand.py index 6b1106d..e209a07 100644 --- a/scripts/qemucommand.py +++ b/scripts/qemucommand.py @@ -81,6 +81,7 @@ class QemuCommand(object): self.gdb = args.gdb self.pcap = args.pcap self.overlay = args.overlay + self.secondary_network = args.secondary_network def command_line(self): netuser = 'user,hostfwd=tcp:0.0.0.0:%d-:22,restrict=off' % self.ssh_port @@ -104,6 +105,11 @@ class QemuCommand(object): ] if self.pcap: cmdline += ['-net', 'dump,file=' + self.pcap] + if self.secondary_network: + cmdline += [ + '-net', 'nic,vlan=1,macaddr='+random_mac(), + '-net', 'socket,vlan=1,mcast=230.0.0.1:1234', + ] if self.gui: cmdline += ["-serial", "stdio"] else: diff --git a/scripts/run-qemu-ota b/scripts/run-qemu-ota index 56e4fbc..b2f55e9 100755 --- a/scripts/run-qemu-ota +++ b/scripts/run-qemu-ota @@ -33,6 +33,9 @@ def main(): 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.') + parser.add_argument('--secondary-network', action='store_true', dest='secondary_network', + help='Give the image a second network card connected to a virtual network. ' + + 'This can be used to test Uptane Primary/Secondary communication.') parser.add_argument('-n', '--dry-run', help='Print qemu command line rather then run it', action='store_true') args = parser.parse_args() try: -- cgit v1.2.3-54-g00ecf From 046ac433f47b5a6cbacb95873e55f7d6c842a939 Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Tue, 20 Mar 2018 13:42:04 +0100 Subject: Fix up tests --- lib/oeqa/selftest/cases/updater.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index 1850d98..0e7c11b 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -570,6 +570,7 @@ def qemu_launch(efi=False, machine=None, imagename=None): args.pcap = None args.overlay = None args.dry_run = False + args.secondary_network = False qemu = QemuCommand(args) cmdline = qemu.command_line() -- cgit v1.2.3-54-g00ecf From 1804d9f6cfcae158fcf1e5c9da90fdf8cbc6fc18 Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Fri, 23 Mar 2018 11:56:15 +0100 Subject: UDP Socket activation for discovery service Also, timeout communication to the DUT after 60s. --- lib/oeqa/selftest/cases/updater.py | 4 ++-- recipes-sota/aktualizr/files/aktualizr-secondary.socket | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index 0e7c11b..06884e5 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -544,7 +544,7 @@ class SecondaryTests(OESelftestTestCase): self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) def test_secondary_listening(self): - print('Checking aktualizr-secondary is present') + print('Checking aktualizr-secondary service is listening') stdout, stderr, retcode = self.qemu_command('echo test | nc localhost 9030') self.assertEqual(retcode, 0, "Unable to connect to secondary") @@ -591,7 +591,7 @@ def qemu_send_command(port, command): command = ['ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@localhost -p ' + str(port) + ' "' + command + '"'] s2 = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = s2.communicate() + stdout, stderr = s2.communicate(timeout=60) return stdout, stderr, s2.returncode diff --git a/recipes-sota/aktualizr/files/aktualizr-secondary.socket b/recipes-sota/aktualizr/files/aktualizr-secondary.socket index 1cb4269..bda8cdb 100644 --- a/recipes-sota/aktualizr/files/aktualizr-secondary.socket +++ b/recipes-sota/aktualizr/files/aktualizr-secondary.socket @@ -1,5 +1,6 @@ [Socket] ListenStream=9030 +ListenDatagram=9030 [Install] WantedBy=sockets.target \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 5c3f802dc963d10ca370fb8bb66977095d044d9b Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Mon, 26 Mar 2018 13:07:38 +0200 Subject: Change port number to match default used elsewhere --- recipes-sota/aktualizr/files/aktualizr-secondary.socket | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes-sota/aktualizr/files/aktualizr-secondary.socket b/recipes-sota/aktualizr/files/aktualizr-secondary.socket index bda8cdb..da0ee44 100644 --- a/recipes-sota/aktualizr/files/aktualizr-secondary.socket +++ b/recipes-sota/aktualizr/files/aktualizr-secondary.socket @@ -1,6 +1,6 @@ [Socket] ListenStream=9030 -ListenDatagram=9030 +ListenDatagram=9031 [Install] WantedBy=sockets.target \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 313278d88fddcc9441f7eacf2e5578d3a19cf8ff Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Mon, 26 Mar 2018 13:38:07 +0200 Subject: Bump aktualizr version to get socket activation fixes Specifically, cc3a8927 "Fix socket activation when UDP enabled" is required. --- recipes-sota/aktualizr/aktualizr_git.bb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 5e683ac..79a89ef 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -22,7 +22,7 @@ SRC_URI = " \ file://aktualizr-secondary.socket \ file://aktualizr-serialcan.service \ " -SRCREV = "fbb3404824c4eb239455c7fa1a794c26e2ea954d" +SRCREV = "7d1d71a28a9ff0b14240b98600de3d541835b278" BRANCH ?= "master" S = "${WORKDIR}/git" -- cgit v1.2.3-54-g00ecf From de2b0f06546666aacf9dd2fce94e0134768c6a3b Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Tue, 27 Mar 2018 14:06:38 +0200 Subject: Add SOTA client feature to enable secondary network Also add a test for the 'primary-image' --- lib/oeqa/selftest/cases/updater.py | 41 ++++++++++++++++++++++ recipes-sota/aktualizr/aktualizr-auto-prov.bb | 4 ++- recipes-sota/aktualizr/aktualizr_git.bb | 3 +- .../files/27-dhcp-client-external.network | 6 ++++ .../secondary-network-config.bb | 6 +++- recipes-test/images/secondary-image.bb | 2 ++ 6 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 recipes-test/demo-network-config/files/27-dhcp-client-external.network diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index 06884e5..e459ffb 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -548,6 +548,47 @@ class SecondaryTests(OESelftestTestCase): stdout, stderr, retcode = self.qemu_command('echo test | nc localhost 9030') self.assertEqual(retcode, 0, "Unable to connect to secondary") + +class PrimaryTests(OESelftestTestCase): + @classmethod + def setUpClass(cls): + super(PrimaryTests, cls).setUpClass() + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build primary-image') + bitbake('primary-image') + + def setUpLocal(self): + layer = "meta-updater-qemux86-64" + result = runCmd('bitbake-layers show-layers') + if re.search(layer, result.output) is None: + # Assume the directory layout for finding other layers. We could also + # make assumptions by using 'show-layers', but either way, if the + # layers we need aren't where we expect them, we are out of like. + path = os.path.abspath(os.path.dirname(__file__)) + metadir = path + "/../../../../../" + self.meta_qemu = metadir + layer + runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu) + else: + self.meta_qemu = None + self.append_config('MACHINE = "qemux86-64"') + self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') + self.append_config('SOTA_CLIENT_FEATURES = "secondary-network"') + self.qemu, self.s = qemu_launch(machine='qemux86-64', imagename='primary-image') + + def tearDownLocal(self): + qemu_terminate(self.s) + if self.meta_qemu: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_qemu, ignore_status=True) + + def qemu_command(self, command): + return qemu_send_command(self.qemu.ssh_port, command) + + def test_aktualizr_present(self): + print('Checking aktualizr is present') + stdout, stderr, retcode = self.qemu_command('aktualizr --help') + self.assertEqual(retcode, 0, "Unable to run aktualizr --help") + self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) + def qemu_launch(efi=False, machine=None, imagename=None): logger = logging.getLogger("selftest") logger.info('Running bitbake to build core-image-minimal') diff --git a/recipes-sota/aktualizr/aktualizr-auto-prov.bb b/recipes-sota/aktualizr/aktualizr-auto-prov.bb index 2190512..07e5bb8 100644 --- a/recipes-sota/aktualizr/aktualizr-auto-prov.bb +++ b/recipes-sota/aktualizr/aktualizr-auto-prov.bb @@ -35,7 +35,9 @@ do_install() { install -d ${D}${libdir}/sota install -d ${D}${localstatedir}/sota if [ -n "${SOTA_PACKED_CREDENTIALS}" ]; then - install -m 0644 ${STAGING_DIR_NATIVE}${libdir}/sota/sota_autoprov.toml ${D}${libdir}/sota/sota.toml + aktualizr_toml=${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-network', 'sota_autoprov_primary.toml', 'sota_autoprov.toml', d)} + + install -m 0644 ${STAGING_DIR_NATIVE}${libdir}/sota/${aktualizr_toml} ${D}${libdir}/sota/sota.toml # deploy SOTA credentials if [ -e ${SOTA_PACKED_CREDENTIALS} ]; then diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 79a89ef..ba0a261 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -22,7 +22,7 @@ SRC_URI = " \ file://aktualizr-secondary.socket \ file://aktualizr-serialcan.service \ " -SRCREV = "7d1d71a28a9ff0b14240b98600de3d541835b278" +SRCREV = "3fc94e7ed20a486da0067f01906250e9d4868931" BRANCH ?= "master" S = "${WORKDIR}/git" @@ -59,6 +59,7 @@ do_install_append_class-target () { do_install_append_class-native () { install -d ${D}${libdir}/sota install -m 0644 ${S}/config/sota_autoprov.toml ${D}/${libdir}/sota/sota_autoprov.toml + install -m 0644 ${S}/config/sota_autoprov_primary.toml ${D}/${libdir}/sota/sota_autoprov_primary.toml install -m 0644 ${S}/config/sota_hsm_prov.toml ${D}/${libdir}/sota/sota_hsm_prov.toml install -m 0644 ${S}/config/sota_implicit_prov.toml ${D}/${libdir}/sota/sota_implicit_prov.toml install -m 0644 ${S}/config/sota_implicit_prov_ca.toml ${D}/${libdir}/sota/sota_implicit_prov_ca.toml diff --git a/recipes-test/demo-network-config/files/27-dhcp-client-external.network b/recipes-test/demo-network-config/files/27-dhcp-client-external.network new file mode 100644 index 0000000..ba49593 --- /dev/null +++ b/recipes-test/demo-network-config/files/27-dhcp-client-external.network @@ -0,0 +1,6 @@ +[Match] +Name=enp0s3 + +[Network] +Description=External network for secondary +DHCP=yes diff --git a/recipes-test/demo-network-config/secondary-network-config.bb b/recipes-test/demo-network-config/secondary-network-config.bb index 492d3ca..9091c65 100644 --- a/recipes-test/demo-network-config/secondary-network-config.bb +++ b/recipes-test/demo-network-config/secondary-network-config.bb @@ -3,7 +3,10 @@ LICENSE = "CLOSED" inherit allarch -SRC_URI = "file://26-dhcp-client.network" +SRC_URI = "\ + file://26-dhcp-client.network \ + file://27-dhcp-client-external.network \ + " FILES_${PN} = "/usr/lib/systemd/network" @@ -13,4 +16,5 @@ PR = "1" do_install() { install -d ${D}/usr/lib/systemd/network install -m 0644 ${WORKDIR}/26-dhcp-client.network ${D}/usr/lib/systemd/network/ + install -m 0644 ${WORKDIR}/27-dhcp-client-external.network ${D}/usr/lib/systemd/network/ } diff --git a/recipes-test/images/secondary-image.bb b/recipes-test/images/secondary-image.bb index c1ce57a..02153d0 100644 --- a/recipes-test/images/secondary-image.bb +++ b/recipes-test/images/secondary-image.bb @@ -13,6 +13,8 @@ IMAGE_INSTALL_remove = " \ aktualizr-ca-implicit-prov \ aktualizr-hsm-prov \ aktualizr-implicit-prov \ + connman \ + connman-client \ " IMAGE_INSTALL_append = " \ -- cgit v1.2.3-54-g00ecf From edae332ab5b66d0caf5b68926b23554aa5493040 Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Tue, 27 Mar 2018 14:08:24 +0200 Subject: Restrict secondary network to localhost --- scripts/qemucommand.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qemucommand.py b/scripts/qemucommand.py index e209a07..4918314 100644 --- a/scripts/qemucommand.py +++ b/scripts/qemucommand.py @@ -108,7 +108,7 @@ class QemuCommand(object): if self.secondary_network: cmdline += [ '-net', 'nic,vlan=1,macaddr='+random_mac(), - '-net', 'socket,vlan=1,mcast=230.0.0.1:1234', + '-net', 'socket,vlan=1,mcast=230.0.0.1:1234,localaddr=127.0.0.1', ] if self.gui: cmdline += ["-serial", "stdio"] -- cgit v1.2.3-54-g00ecf From fb74d00ac4e6739948f08184cd7e659a5f2e979e Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 28 Mar 2018 11:29:37 +0200 Subject: Add aktualizr-check-discovery to shipped files --- recipes-sota/aktualizr/aktualizr_git.bb | 1 + 1 file changed, 1 insertion(+) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index ba0a261..90ee6cf 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -73,6 +73,7 @@ PACKAGES =+ " ${PN}-common ${PN}-examples ${PN}-host-tools ${PN}-secondary " FILES_${PN} = " \ ${bindir}/aktualizr \ ${bindir}/aktualizr-info \ + ${bindir}/aktualizr-check-discovery \ ${systemd_unitdir}/system/aktualizr.service \ " -- cgit v1.2.3-54-g00ecf From 9746f46e6c70efaa7affaf8970573ac159ea4906 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 28 Mar 2018 11:36:02 +0200 Subject: Bump aktualizr Needed to work with the addition of aktualizr-check-discovery --- recipes-sota/aktualizr/aktualizr_git.bb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 90ee6cf..26ccd72 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -22,7 +22,7 @@ SRC_URI = " \ file://aktualizr-secondary.socket \ file://aktualizr-serialcan.service \ " -SRCREV = "3fc94e7ed20a486da0067f01906250e9d4868931" +SRCREV = "178ba9985e23d9c3938d87dd5f2cb39f48f61de6" BRANCH ?= "master" S = "${WORKDIR}/git" -- cgit v1.2.3-54-g00ecf From 71c528ab616a707f4125727c8c5a4e4da5a36c94 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Thu, 29 Mar 2018 13:51:03 +0200 Subject: Assorted minor cleanup and formatting. Includes the suggestion for using /etc/sota/sota.env if it exists as recommended by the discussion here: https://github.com/advancedtelematic/meta-updater/pull/275 --- classes/image_types_ostree.bbclass | 25 +++++++++++++++++++------ recipes-sota/aktualizr/aktualizr_git.bb | 3 ++- recipes-sota/aktualizr/environment.inc | 2 +- recipes-sota/aktualizr/files/aktualizr.service | 1 + recipes-test/images/primary-image.bb | 2 ++ recipes-test/images/secondary-image.bb | 2 ++ 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/classes/image_types_ostree.bbclass b/classes/image_types_ostree.bbclass index 5ebed81..dc14e4a 100644 --- a/classes/image_types_ostree.bbclass +++ b/classes/image_types_ostree.bbclass @@ -11,7 +11,6 @@ do_image_ostree[depends] += "ostree-native:do_populate_sysroot \ export OSTREE_REPO export OSTREE_BRANCHNAME - export GARAGE_TARGET_NAME RAMDISK_EXT ?= ".ext4.gz" @@ -198,7 +197,9 @@ IMAGE_CMD_garagesign () { fi rm -rf ${GARAGE_SIGN_REPO} - garage-sign init --repo tufrepo --home-dir ${GARAGE_SIGN_REPO} --credentials ${SOTA_PACKED_CREDENTIALS} + garage-sign init --repo tufrepo \ + --home-dir ${GARAGE_SIGN_REPO} \ + --credentials ${SOTA_PACKED_CREDENTIALS} ostree_target_hash=$(cat ${OSTREE_REPO}/refs/heads/${OSTREE_BRANCHNAME}) @@ -206,11 +207,23 @@ IMAGE_CMD_garagesign () { # in which case targets.json should be pulled again and the whole procedure repeated push_success=0 for push_retries in $( seq 3 ); do - garage-sign targets pull --repo tufrepo --home-dir ${GARAGE_SIGN_REPO} - garage-sign targets add --repo tufrepo --home-dir ${GARAGE_SIGN_REPO} --name ${GARAGE_TARGET_NAME} --format OSTREE --version ${ostree_target_hash} --length 0 --url "https://example.com/" --sha256 ${ostree_target_hash} --hardwareids ${MACHINE} - garage-sign targets sign --repo tufrepo --home-dir ${GARAGE_SIGN_REPO} --key-name=targets + garage-sign targets pull --repo tufrepo \ + --home-dir ${GARAGE_SIGN_REPO} + garage-sign targets add --repo tufrepo \ + --home-dir ${GARAGE_SIGN_REPO} \ + --name ${GARAGE_TARGET_NAME} \ + --format OSTREE \ + --version ${ostree_target_hash} \ + --length 0 \ + --url "https://example.com/" \ + --sha256 ${ostree_target_hash} \ + --hardwareids ${MACHINE} + garage-sign targets sign --repo tufrepo \ + --home-dir ${GARAGE_SIGN_REPO} \ + --key-name=targets errcode=0 - garage-sign targets push --repo tufrepo --home-dir ${GARAGE_SIGN_REPO} || errcode=$? + garage-sign targets push --repo tufrepo \ + --home-dir ${GARAGE_SIGN_REPO} || errcode=$? if [ "$errcode" -eq "0" ]; then push_success=1 break diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 26ccd72..2a803a8 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -22,7 +22,7 @@ SRC_URI = " \ file://aktualizr-secondary.socket \ file://aktualizr-serialcan.service \ " -SRCREV = "178ba9985e23d9c3938d87dd5f2cb39f48f61de6" +SRCREV = "930d8eef6eb584686654601c056d7c9c6fca3048" BRANCH ?= "master" S = "${WORKDIR}/git" @@ -50,6 +50,7 @@ do_install_append () { install -m 0644 ${WORKDIR}/aktualizr-secondary.socket ${D}${systemd_unitdir}/system/aktualizr-secondary.socket install -m 0644 ${WORKDIR}/aktualizr-secondary.service ${D}${systemd_unitdir}/system/aktualizr-secondary.service } + do_install_append_class-target () { install -d ${D}${systemd_unitdir}/system aktualizr_service=${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'serialcan', '${WORKDIR}/aktualizr-serialcan.service', '${WORKDIR}/aktualizr.service', d)} diff --git a/recipes-sota/aktualizr/environment.inc b/recipes-sota/aktualizr/environment.inc index cba77e7..09da6b7 100644 --- a/recipes-sota/aktualizr/environment.inc +++ b/recipes-sota/aktualizr/environment.inc @@ -3,7 +3,7 @@ export SOTA_VIRTUAL_SECONDARIES do_install_append() { if [ -n "${SOTA_LEGACY_SECONDARY_INTERFACE}" ]; then - AKTUALIZR_PARAMETERS_LEGACYSEC="--legacy-interface ${SOTA_LEGACY_SECONDARY_INTERFACE}"; + AKTUALIZR_PARAMETERS_LEGACYSEC="--legacy-interface ${SOTA_LEGACY_SECONDARY_INTERFACE}" fi AKTUALIZR_PARAMETERS_CONFIGFILE="--config /usr/lib/sota/sota.toml" diff --git a/recipes-sota/aktualizr/files/aktualizr.service b/recipes-sota/aktualizr/files/aktualizr.service index b6df9d7..1c2e1df 100644 --- a/recipes-sota/aktualizr/files/aktualizr.service +++ b/recipes-sota/aktualizr/files/aktualizr.service @@ -8,6 +8,7 @@ Requires=network-online.target RestartSec=10 Restart=always EnvironmentFile=/usr/lib/sota/sota.env +EnvironmentFile=-/etc/sota/sota.env ExecStart=/usr/bin/aktualizr $AKTUALIZR_CMDLINE_PARAMETERS [Install] diff --git a/recipes-test/images/primary-image.bb b/recipes-test/images/primary-image.bb index 6c06527..6d2df94 100644 --- a/recipes-test/images/primary-image.bb +++ b/recipes-test/images/primary-image.bb @@ -10,3 +10,5 @@ IMAGE_INSTALL_remove = " \ IMAGE_INSTALL_append = " \ primary-network-config \ " + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/recipes-test/images/secondary-image.bb b/recipes-test/images/secondary-image.bb index 02153d0..9adbdc5 100644 --- a/recipes-test/images/secondary-image.bb +++ b/recipes-test/images/secondary-image.bb @@ -21,3 +21,5 @@ IMAGE_INSTALL_append = " \ aktualizr-secondary \ secondary-network-config \ " + +# vim:set ts=4 sw=4 sts=4 expandtab: -- cgit v1.2.3-54-g00ecf