From 1f479081dc1cc0f5e6d565040bb188369b64ca31 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 27 Feb 2019 18:36:06 +0100 Subject: Move warning about insecure practise to the correct recipe When SOTA_DEPLOY_CREDENTIALS got introduced deployment of the provisioning credientials has been moved to aktualizr-ca-implicit-prov-creds. Move the warning accordingly. Signed-off-by: Stefan Agner --- recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb | 4 ++++ recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb index 7420983..b9bb1f6 100644 --- a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb +++ b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb @@ -3,6 +3,10 @@ SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" +# 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. + DEPENDS = "aktualizr aktualizr-native" ALLOW_EMPTY_${PN} = "1" diff --git a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb index 5893ed2..9a4166c 100644 --- a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb +++ b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb @@ -1,9 +1,6 @@ SUMMARY = "Aktualizr configuration for implicit provisioning with CA" DESCRIPTION = "Configuration 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" -- cgit v1.2.3-54-g00ecf From ee5e6eb71b12d38ba520a1451ab71a4fec994f1f Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Fri, 1 Mar 2019 12:49:38 +0100 Subject: Simplify garage-sign fetching for aktualizr Two modes: - `GARAGE_SIGN_AUTOVERSION=0`: use archive and version from aktualizr's recipe - `GARAGE_SIGN_AUTOVERSION=1`: let aktualizr fetching it automatically Signed-off-by: Laurent Bonnans --- recipes-sota/aktualizr/aktualizr_git.bb | 13 ++++++---- recipes-sota/aktualizr/garage-sign-version.inc | 36 -------------------------- 2 files changed, 8 insertions(+), 41 deletions(-) delete mode 100644 recipes-sota/aktualizr/garage-sign-version.inc diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index fef12b8..c4c0cec 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -5,8 +5,6 @@ SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=9741c346eef56131163e13b9db1241b3" -require garage-sign-version.inc - DEPENDS = "boost curl openssl libarchive libsodium sqlite3 asn1c-native" RDEPENDS_${PN}_class-target = "aktualizr-check-discovery aktualizr-configs lshw" RDEPENDS_${PN}-secondary = "aktualizr-check-discovery" @@ -15,14 +13,21 @@ RDEPENDS_${PN}-host-tools = "aktualizr aktualizr-repo aktualizr-cert-provider ${ PV = "1.0+git${SRCPV}" PR = "7" +GARAGE_SIGN_PV = "0.6.0-3-gc38b9f3" + SRC_URI = " \ gitsm://github.com/advancedtelematic/aktualizr;branch=${BRANCH} \ file://aktualizr.service \ file://aktualizr-secondary.service \ file://aktualizr-secondary.socket \ file://aktualizr-serialcan.service \ + ${@ d.expand("https://ats-tuf-cli-releases.s3-eu-central-1.amazonaws.com/cli-${GARAGE_SIGN_PV}.tgz;unpack=0") if d.getVar('GARAGE_SIGN_AUTOVERSION') != '1' else ''} \ " +# for garage-sign archive +SRC_URI[md5sum] = "30d7f0931e2236954679e75d1bae174f" +SRC_URI[sha256sum] = "46d8c6448ce14cbb9af6a93eba7e29d38579e566dcd6518d22f723a8da16cad5" + SRCREV = "c71ec0a320d85a3e75ba37bff7dc40ad02e9d655" BRANCH ?= "master" @@ -36,9 +41,7 @@ SYSTEMD_SERVICE_${PN}-secondary = "aktualizr-secondary.socket" EXTRA_OECMAKE = "-DCMAKE_BUILD_TYPE=Release -DAKTUALIZR_VERSION=${PV} -Dgtest_disable_pthreads=ON" -GARAGE_SIGN_OPS = "${@ '-DGARAGE_SIGN_VERSION=%s' % d.getVar('GARAGE_SIGN_VERSION') if d.getVar('GARAGE_SIGN_VERSION') is not None else ''} \ - ${@ '-DGARAGE_SIGN_SHA256=%s' % d.getVar('GARAGE_SIGN_SHA256') if d.getVar('GARAGE_SIGN_SHA256') is not None else ''} \ - " +GARAGE_SIGN_OPS = "${@ d.expand('-DGARAGE_SIGN_ARCHIVE=${WORKDIR}/cli-${GARAGE_SIGN_PV}.tgz') if d.getVar('GARAGE_SIGN_AUTOVERSION') != '1' else ''}" PACKAGECONFIG ?= "ostree ${@bb.utils.filter('DISTRO_FEATURES', 'systemd', d)} ${@bb.utils.filter('SOTA_CLIENT_FEATURES', 'hsm serialcan ubootenv', d)}" PACKAGECONFIG_class-native = "sota-tools" diff --git a/recipes-sota/aktualizr/garage-sign-version.inc b/recipes-sota/aktualizr/garage-sign-version.inc deleted file mode 100644 index 1b89a3d..0000000 --- a/recipes-sota/aktualizr/garage-sign-version.inc +++ /dev/null @@ -1,36 +0,0 @@ - -python () { - if d.getVar("GARAGE_SIGN_VERSION", True) or not d.getVar("SOTA_PACKED_CREDENTIALS", True): - return - import json - import urllib.request - import zipfile - with zipfile.ZipFile(d.getVar("SOTA_PACKED_CREDENTIALS", True), 'r') as zip_ref: - try: - with zip_ref.open('tufrepo.url', mode='r') as url_file: - url = url_file.read().decode().strip(' \t\n') + '/health/version' - except (KeyError, ValueError, RuntimeError): - return - connected = False - tries = 3 - for i in range(tries): - try: - r = urllib.request.urlopen(url) - if r.code == 200: - connected = True - break - else: - print('Bad return code from server ' + url + ': ' + str(r.code) + - ' (attempt ' + str(i + 1) + ' of ' + str(tries) + ')') - except urllib.error.URLError as e: - print('Error connecting to server ' + url + ': ' + str(e) + - ' (attempt ' + str(i + 1) + ' of ' + str(tries) + ')') - if not connected: - return - resp = r.read().decode('utf-8') - j = json.loads(resp) - version = 'cli-' + j['version'] + '.tgz' - d.setVar("GARAGE_SIGN_VERSION", version) -} - -# vim:set ts=4 sw=4 sts=4 expandtab: -- cgit v1.2.3-54-g00ecf From f4246436acada60efc00fbb0768195990fd1b256 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 5 Mar 2019 16:53:41 +0100 Subject: Remove connman* from base IMAGE_INSTALL_append No sense to force that if poky does not, let's move it to platform-specific for now. Signed-off-by: Laurent Bonnans --- classes/sota_am335x-evm-wifi.bbclass | 1 - classes/sota_m3ulcb.bbclass | 2 ++ classes/sota_minnowboard.bbclass | 1 + classes/sota_porter.bbclass | 1 + classes/sota_qemux86-64.bbclass | 2 ++ classes/sota_raspberrypi.bbclass | 2 ++ conf/distro/poky-sota-systemd.conf | 2 -- conf/distro/poky-sota.conf | 2 -- 8 files changed, 8 insertions(+), 5 deletions(-) diff --git a/classes/sota_am335x-evm-wifi.bbclass b/classes/sota_am335x-evm-wifi.bbclass index adefb47..1458d44 100644 --- a/classes/sota_am335x-evm-wifi.bbclass +++ b/classes/sota_am335x-evm-wifi.bbclass @@ -7,7 +7,6 @@ IMAGE_BOOT_FILES_sota = "bootfiles/*" OSTREE_KERNEL_ARGS ?= "ramdisk_size=16384 root=/dev/ram0 rw rootfstype=ext4 rootwait rootdelay=2 ostree_root=/dev/mmcblk0p2 console=ttyO0,115200n8l" IMAGE_INSTALL_append_sota = " uim iw wl18xx-calibrator wlconf wl18xx-fw hostapd wpa-supplicant" -IMAGE_INSTALL_remove_sota = " connman connman-client" PREFERRED_VERSION_linux-ti-staging_sota = "4.4.54+gitAUTOINC+ecd4eada6f" diff --git a/classes/sota_m3ulcb.bbclass b/classes/sota_m3ulcb.bbclass index 4ddcf9e..5c7b671 100644 --- a/classes/sota_m3ulcb.bbclass +++ b/classes/sota_m3ulcb.bbclass @@ -6,3 +6,5 @@ IMAGE_BOOT_FILES_sota += "renesas-ota-bootfiles/*" OSTREE_BOOTLOADER ?= "u-boot" UBOOT_MACHINE_sota = "m3ulcb_defconfig" + +IMAGE_INSTALL_append_sota = " connman connman-client" diff --git a/classes/sota_minnowboard.bbclass b/classes/sota_minnowboard.bbclass index 63510e3..0304ef3 100644 --- a/classes/sota_minnowboard.bbclass +++ b/classes/sota_minnowboard.bbclass @@ -7,4 +7,5 @@ IMAGE_BOOT_FILES_sota = "" IMAGE_FSTYPES_remove_sota = "live hddimg" OSTREE_KERNEL_ARGS ?= "ramdisk_size=16384 rw rootfstype=ext4 rootwait rootdelay=2 console=ttyS0,115200 console=tty0" +IMAGE_INSTALL_append_sota = " connman connman-client" IMAGE_INSTALL_append = " minnowboard-efi-startup" diff --git a/classes/sota_porter.bbclass b/classes/sota_porter.bbclass index 75ae579..9beea33 100644 --- a/classes/sota_porter.bbclass +++ b/classes/sota_porter.bbclass @@ -7,3 +7,4 @@ IMAGE_BOOT_FILES_sota += "porter-bootfiles/*" OSTREE_BOOTLOADER ?= "u-boot" UBOOT_MACHINE_sota = "porter_config" +IMAGE_INSTALL_append_sota = " connman connman-client" diff --git a/classes/sota_qemux86-64.bbclass b/classes/sota_qemux86-64.bbclass index 82efe52..5d82bde 100644 --- a/classes/sota_qemux86-64.bbclass +++ b/classes/sota_qemux86-64.bbclass @@ -12,3 +12,5 @@ IMAGE_ROOTFS_EXTRA_SPACE = "${@bb.utils.contains('DISTRO_FEATURES', 'sota', '655 # fix for u-boot/swig build issue HOSTTOOLS_NONFATAL += "x86_64-linux-gnu-gcc" + +IMAGE_INSTALL_append_sota = " connman connman-client" diff --git a/classes/sota_raspberrypi.bbclass b/classes/sota_raspberrypi.bbclass index 49aa298..73f36ee 100644 --- a/classes/sota_raspberrypi.bbclass +++ b/classes/sota_raspberrypi.bbclass @@ -3,6 +3,8 @@ RPI_USE_U_BOOT_sota = "1" KERNEL_CLASSES_append_sota = " kernel-fitimage" KERNEL_IMAGETYPE_sota = "fitImage" +IMAGE_INSTALL_append_sota = " connman connman-client" + PREFERRED_PROVIDER_virtual/bootloader_sota ?= "u-boot" UBOOT_ENTRYPOINT_sota ?= "0x00008000" diff --git a/conf/distro/poky-sota-systemd.conf b/conf/distro/poky-sota-systemd.conf index 7d008a9..3b7de35 100644 --- a/conf/distro/poky-sota-systemd.conf +++ b/conf/distro/poky-sota-systemd.conf @@ -9,5 +9,3 @@ DISTRO_CODENAME = "sota" DISTRO_FEATURES_append = " systemd" VIRTUAL-RUNTIME_init_manager = "systemd" - -IMAGE_INSTALL_append = " connman connman-client" diff --git a/conf/distro/poky-sota.conf b/conf/distro/poky-sota.conf index 2bbc62b..3fb1d20 100644 --- a/conf/distro/poky-sota.conf +++ b/conf/distro/poky-sota.conf @@ -5,5 +5,3 @@ DISTRO = "poky-sota" DISTRO_NAME = "OTA-enabled Linux" DISTRO_VERSION = "1.0" DISTRO_CODENAME = "sota" - -IMAGE_INSTALL_append = " connman connman-client" -- cgit v1.2.3-54-g00ecf From 065e0fab7390a8eaf28853e46897525a0181f57a Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 5 Mar 2019 18:02:10 +0100 Subject: Replace connman with systemd-networkd on qemux86-64 Signed-off-by: Laurent Bonnans --- classes/sota_qemux86-64.bbclass | 2 +- .../networkd-dhcp-conf/files/20-wired-dhcp.network | 5 +++++ .../networkd-dhcp-conf/networkd-dhcp-conf.bb | 23 ++++++++++++++++++++++ recipes-test/images/secondary-image.bb | 1 + 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 recipes-connectivity/networkd-dhcp-conf/files/20-wired-dhcp.network create mode 100644 recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb diff --git a/classes/sota_qemux86-64.bbclass b/classes/sota_qemux86-64.bbclass index 5d82bde..6b1ed94 100644 --- a/classes/sota_qemux86-64.bbclass +++ b/classes/sota_qemux86-64.bbclass @@ -13,4 +13,4 @@ IMAGE_ROOTFS_EXTRA_SPACE = "${@bb.utils.contains('DISTRO_FEATURES', 'sota', '655 # fix for u-boot/swig build issue HOSTTOOLS_NONFATAL += "x86_64-linux-gnu-gcc" -IMAGE_INSTALL_append_sota = " connman connman-client" +IMAGE_INSTALL_append_sota = " ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'networkd-dhcp-conf', '', d)} " diff --git a/recipes-connectivity/networkd-dhcp-conf/files/20-wired-dhcp.network b/recipes-connectivity/networkd-dhcp-conf/files/20-wired-dhcp.network new file mode 100644 index 0000000..aec1849 --- /dev/null +++ b/recipes-connectivity/networkd-dhcp-conf/files/20-wired-dhcp.network @@ -0,0 +1,5 @@ +[Match] +Name=en* + +[Network] +DHCP=yes diff --git a/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb b/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb new file mode 100644 index 0000000..60eae44 --- /dev/null +++ b/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb @@ -0,0 +1,23 @@ +SUMMARY = "systemd-networkd config to setup wired interface with dhcp" +DESCRIPTION = "Provides automatic dhcp network configuration for wired \ +interfaces through systemd-networkd" +LICENSE = "MPL-2.0" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" + +inherit systemd + +SRC_URI_append = " file://20-wired-dhcp.network" +PR = "r1" + +RDEPENDS_${PN} = "systemd" + +S = "${WORKDIR}" + +PACKAGE_ARCH = "${MACHINE_ARCH}" + +FILES_${PN} = "${systemd_unitdir}/network/*" + +do_install() { + install -d ${D}/${systemd_unitdir}/network + install -m 0644 ${WORKDIR}/20-wired-dhcp.network ${D}/${systemd_unitdir}/network +} diff --git a/recipes-test/images/secondary-image.bb b/recipes-test/images/secondary-image.bb index 1a41169..371d517 100644 --- a/recipes-test/images/secondary-image.bb +++ b/recipes-test/images/secondary-image.bb @@ -17,6 +17,7 @@ IMAGE_INSTALL_remove = " \ aktualizr-uboot-env-rollback \ connman \ connman-client \ + networkd-dhcp-conf \ " IMAGE_INSTALL_append = " \ -- cgit v1.2.3-54-g00ecf From a78f293e09a7c2d41de9575219a88909150c4e84 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 6 Mar 2019 10:58:00 +0100 Subject: Define virtual/network-configuration Now provided by connman and networkd-dhcp-conf, added to images in our supported platforms Signed-off-by: Laurent Bonnans --- classes/sota_m3ulcb.bbclass | 3 ++- classes/sota_minnowboard.bbclass | 5 +++-- classes/sota_porter.bbclass | 3 ++- classes/sota_qemux86-64.bbclass | 2 +- classes/sota_raspberrypi.bbclass | 3 ++- conf/distro/poky-sota-systemd.conf | 1 + recipes-connectivity/connman/connman_%.bbappend | 1 + recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb | 2 ++ recipes-test/images/secondary-image.bb | 4 +--- 9 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 recipes-connectivity/connman/connman_%.bbappend diff --git a/classes/sota_m3ulcb.bbclass b/classes/sota_m3ulcb.bbclass index 5c7b671..7c57ae5 100644 --- a/classes/sota_m3ulcb.bbclass +++ b/classes/sota_m3ulcb.bbclass @@ -7,4 +7,5 @@ IMAGE_BOOT_FILES_sota += "renesas-ota-bootfiles/*" OSTREE_BOOTLOADER ?= "u-boot" UBOOT_MACHINE_sota = "m3ulcb_defconfig" -IMAGE_INSTALL_append_sota = " connman connman-client" +PREFERRED_RPROVIDER_virtual/network-configuration ?= "connman" +IMAGE_INSTALL_append_sota = " virtual/network-configuration " diff --git a/classes/sota_minnowboard.bbclass b/classes/sota_minnowboard.bbclass index 0304ef3..a907217 100644 --- a/classes/sota_minnowboard.bbclass +++ b/classes/sota_minnowboard.bbclass @@ -6,6 +6,7 @@ IMAGE_BOOT_FILES_sota = "" IMAGE_FSTYPES_remove_sota = "live hddimg" OSTREE_KERNEL_ARGS ?= "ramdisk_size=16384 rw rootfstype=ext4 rootwait rootdelay=2 console=ttyS0,115200 console=tty0" - -IMAGE_INSTALL_append_sota = " connman connman-client" IMAGE_INSTALL_append = " minnowboard-efi-startup" + +PREFERRED_RPROVIDER_virtual/network-configuration ?= "connman" +IMAGE_INSTALL_append_sota = " virtual/network-configuration " diff --git a/classes/sota_porter.bbclass b/classes/sota_porter.bbclass index 9beea33..80062e1 100644 --- a/classes/sota_porter.bbclass +++ b/classes/sota_porter.bbclass @@ -7,4 +7,5 @@ IMAGE_BOOT_FILES_sota += "porter-bootfiles/*" OSTREE_BOOTLOADER ?= "u-boot" UBOOT_MACHINE_sota = "porter_config" -IMAGE_INSTALL_append_sota = " connman connman-client" +PREFERRED_RPROVIDER_virtual/network-configuration ?= "connman" +IMAGE_INSTALL_append_sota = " virtual/network-configuration " diff --git a/classes/sota_qemux86-64.bbclass b/classes/sota_qemux86-64.bbclass index 6b1ed94..8acb976 100644 --- a/classes/sota_qemux86-64.bbclass +++ b/classes/sota_qemux86-64.bbclass @@ -13,4 +13,4 @@ IMAGE_ROOTFS_EXTRA_SPACE = "${@bb.utils.contains('DISTRO_FEATURES', 'sota', '655 # fix for u-boot/swig build issue HOSTTOOLS_NONFATAL += "x86_64-linux-gnu-gcc" -IMAGE_INSTALL_append_sota = " ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'networkd-dhcp-conf', '', d)} " +IMAGE_INSTALL_append_sota = " virtual/network-configuration " diff --git a/classes/sota_raspberrypi.bbclass b/classes/sota_raspberrypi.bbclass index 73f36ee..78b8cab 100644 --- a/classes/sota_raspberrypi.bbclass +++ b/classes/sota_raspberrypi.bbclass @@ -3,7 +3,8 @@ RPI_USE_U_BOOT_sota = "1" KERNEL_CLASSES_append_sota = " kernel-fitimage" KERNEL_IMAGETYPE_sota = "fitImage" -IMAGE_INSTALL_append_sota = " connman connman-client" +PREFERRED_RPROVIDER_virtual/network-configuration ?= "connman" +IMAGE_INSTALL_append_sota = " virtual/network-configuration " PREFERRED_PROVIDER_virtual/bootloader_sota ?= "u-boot" UBOOT_ENTRYPOINT_sota ?= "0x00008000" diff --git a/conf/distro/poky-sota-systemd.conf b/conf/distro/poky-sota-systemd.conf index 3b7de35..b30b322 100644 --- a/conf/distro/poky-sota-systemd.conf +++ b/conf/distro/poky-sota-systemd.conf @@ -9,3 +9,4 @@ DISTRO_CODENAME = "sota" DISTRO_FEATURES_append = " systemd" VIRTUAL-RUNTIME_init_manager = "systemd" +PREFERRED_RPROVIDER_virtual/network-configuration ??= "networkd-dhcp-conf" diff --git a/recipes-connectivity/connman/connman_%.bbappend b/recipes-connectivity/connman/connman_%.bbappend new file mode 100644 index 0000000..b3633cc --- /dev/null +++ b/recipes-connectivity/connman/connman_%.bbappend @@ -0,0 +1 @@ +RPROVIDES_${PN} += "virtual/network-configuration" diff --git a/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb b/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb index 60eae44..39500c7 100644 --- a/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb +++ b/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb @@ -6,6 +6,8 @@ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7 inherit systemd +RPROVIDES_${PN} = "virtual/network-configuration" + SRC_URI_append = " file://20-wired-dhcp.network" PR = "r1" diff --git a/recipes-test/images/secondary-image.bb b/recipes-test/images/secondary-image.bb index 371d517..61df85b 100644 --- a/recipes-test/images/secondary-image.bb +++ b/recipes-test/images/secondary-image.bb @@ -15,9 +15,7 @@ IMAGE_INSTALL_remove = " \ aktualizr-ca-implicit-prov-creds \ aktualizr-hsm-prov \ aktualizr-uboot-env-rollback \ - connman \ - connman-client \ - networkd-dhcp-conf \ + virtual/network-configuration \ " IMAGE_INSTALL_append = " \ -- cgit v1.2.3-54-g00ecf From 329fffaa81b6db0caa117919b0c89a75c405d084 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 6 Mar 2019 12:43:33 +0100 Subject: Replace connman with systemd-networkd on raspberrypi Signed-off-by: Laurent Bonnans --- classes/sota_raspberrypi.bbclass | 2 +- recipes-connectivity/networkd-dhcp-conf/files/20-wired-dhcp.network | 2 +- recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/classes/sota_raspberrypi.bbclass b/classes/sota_raspberrypi.bbclass index 78b8cab..5cbf4c0 100644 --- a/classes/sota_raspberrypi.bbclass +++ b/classes/sota_raspberrypi.bbclass @@ -3,7 +3,7 @@ RPI_USE_U_BOOT_sota = "1" KERNEL_CLASSES_append_sota = " kernel-fitimage" KERNEL_IMAGETYPE_sota = "fitImage" -PREFERRED_RPROVIDER_virtual/network-configuration ?= "connman" +DEV_MATCH_DIRECTIVE_pn-networkd-dhcp-conf = "Driver=smsc95xx lan78xx" IMAGE_INSTALL_append_sota = " virtual/network-configuration " PREFERRED_PROVIDER_virtual/bootloader_sota ?= "u-boot" diff --git a/recipes-connectivity/networkd-dhcp-conf/files/20-wired-dhcp.network b/recipes-connectivity/networkd-dhcp-conf/files/20-wired-dhcp.network index aec1849..edb3678 100644 --- a/recipes-connectivity/networkd-dhcp-conf/files/20-wired-dhcp.network +++ b/recipes-connectivity/networkd-dhcp-conf/files/20-wired-dhcp.network @@ -1,5 +1,5 @@ [Match] -Name=en* +@MATCH_DIRECTIVE@ [Network] DHCP=yes diff --git a/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb b/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb index 39500c7..1a515a2 100644 --- a/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb +++ b/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb @@ -19,7 +19,10 @@ PACKAGE_ARCH = "${MACHINE_ARCH}" FILES_${PN} = "${systemd_unitdir}/network/*" +DEV_MATCH_DIRECTIVE ?= "Name=en*" + do_install() { install -d ${D}/${systemd_unitdir}/network install -m 0644 ${WORKDIR}/20-wired-dhcp.network ${D}/${systemd_unitdir}/network + sed -i -e 's|@MATCH_DIRECTIVE@|${DEV_MATCH_DIRECTIVE}|g' ${D}${systemd_unitdir}/network/20-wired-dhcp.network } -- cgit v1.2.3-54-g00ecf From 0775995a18576ca9614bdbe1e8544720435e934b Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 6 Mar 2019 16:40:50 +0100 Subject: Document necessary integration of network connectivity Signed-off-by: Laurent Bonnans --- README.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.adoc b/README.adoc index 9f7d485..54a5a8d 100644 --- a/README.adoc +++ b/README.adoc @@ -74,6 +74,8 @@ 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. +Your images will also need network connectivity to be able to reach an actual OTA backend. Our 'poky-sota' distribution does not mandate or install a default network manager but our supported platforms use the `virtual/network-configuration` recipe, which can be used as a starting example. + == SOTA-related variables in local.conf * `OSTREE_REPO` - path to your OSTree repository. Defaults to `$\{DEPLOY_DIR_IMAGE}/ostree_repo` -- cgit v1.2.3-54-g00ecf From 2b8434fc2a896a5c709d49f5b7dd98f4e030bad6 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Thu, 7 Mar 2019 12:13:35 +0100 Subject: Document GARAGE_SIGN_AUTOVERSION Signed-off-by: Laurent Bonnans --- README.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/README.adoc b/README.adoc index 54a5a8d..d1469a8 100644 --- a/README.adoc +++ b/README.adoc @@ -84,6 +84,7 @@ Your images will also need network connectivity to be able to reach an actual OT * `OSTREE_COMMIT_BODY` - Message attached to OSTree commit. Empty by default. * `OSTREE_COMMIT_SUBJECT` - Commit subject used by OSTree. Defaults to `Commit-id: ${IMAGE_NAME}` * `OSTREE_UPDATE_SUMMARY` - Set this to '1' to update summary of OSTree repository on each commit. '0' by default. +* `GARAGE_SIGN_AUTOVERSION` - Set this to '1' to automatically fetch the last version of the garage tools installed by the aktualizr-native. Otherwise use the fixed version specified in the recipe. * `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_DEPLOY_CREDENTIALS` - when set to '1' (default value), deploys credentials to the built image. Override it in `local.conf` to built a generic image that can be provisioned manually after the build. * `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-ca-implicit-prov`], and https://github.com/advancedtelematic/aktualizr/blob/master/docs/hsm-provisioning.adoc[`aktualizr-hsm-prov`]. The default is `aktualizr-auto-prov`. This can also be set to an empty string to avoid using a provisioning recipe. -- cgit v1.2.3-54-g00ecf From c9ed994ecd24a13b2177cfd7813490f90b004efb Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 9 Mar 2019 09:13:00 +0100 Subject: aktualizr: use echo -e when using escape sequences Some shell require the -e argument when using escape sequences in echo. This has been observed when building images on a Fedora machine, where the configuration files ended up including "\n" sequences instead of newlines. Signed-off-by: Stefan Agner --- recipes-sota/aktualizr/aktualizr_git.bb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index c4c0cec..7b450f5 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -69,14 +69,14 @@ do_install_append () { install -m 0700 -d ${D}${sysconfdir}/sota/conf.d if [ -n "${SOTA_HARDWARE_ID}" ]; then - echo "[provision]\nprimary_ecu_hardware_id = ${SOTA_HARDWARE_ID}\n" > ${D}${libdir}/sota/conf.d/40-hardware-id.toml + echo -e "[provision]\nprimary_ecu_hardware_id = ${SOTA_HARDWARE_ID}\n" > ${D}${libdir}/sota/conf.d/40-hardware-id.toml fi if [ -n "${SOTA_SECONDARY_CONFIG_DIR}" ]; then if [ -d "${SOTA_SECONDARY_CONFIG_DIR}" ]; then install -m 0700 -d ${D}${sysconfdir}/sota/ecus install -m 0644 "${SOTA_SECONDARY_CONFIG_DIR}"/* ${D}${sysconfdir}/sota/ecus/ - echo "[uptane]\nsecondary_configs_dir = /etc/sota/ecus/\n" > ${D}${libdir}/sota/conf.d/30-secondary-configs-dir.toml + echo -e "[uptane]\nsecondary_configs_dir = /etc/sota/ecus/\n" > ${D}${libdir}/sota/conf.d/30-secondary-configs-dir.toml else bbwarn "SOTA_SECONDARY_CONFIG_DIR is set to an invalid directory (${SOTA_SECONDARY_CONFIG_DIR})" fi -- cgit v1.2.3-54-g00ecf From 8da4dd635cf5284998d1770ddb18d98d2fe5b2dd Mon Sep 17 00:00:00 2001 From: Ming Liu Date: Tue, 12 Feb 2019 16:20:01 +0100 Subject: wic:plugins:otaimage.py: fix a potential issue do_image_wic task is a standalone task that depending on do_image_ota_ext4, so it's possible that do_image_wic runs (taskhash contaminated) but do_image_ota_ext4 does not (taskhash not contaminated), in which case, the otaimage would be in DEPLOY_DIR_IMAGE instead of in IMGDEPLOYDIR, so we need check both of them. Also, the logger.error is not supposed to raise a error, it just prints out a error message, so we should use WicError. And another typo is it checks IMGDEPLOYDIR but reports DEPLOY_DIR_IMAGE not exist, also fix that. Signed-off-by: Ming Liu --- scripts/lib/wic/plugins/source/otaimage.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/scripts/lib/wic/plugins/source/otaimage.py b/scripts/lib/wic/plugins/source/otaimage.py index ee8088b..e7f3e75 100644 --- a/scripts/lib/wic/plugins/source/otaimage.py +++ b/scripts/lib/wic/plugins/source/otaimage.py @@ -19,6 +19,7 @@ import logging import os import sys +from wic import WicError from wic.plugins.source.rawcopy import RawCopyPlugin from wic.misc import get_bitbake_var @@ -31,6 +32,18 @@ class OTAImagePlugin(RawCopyPlugin): name = 'otaimage' + @classmethod + def _get_src_file(cls, image_dir_var): + """ + Get OTA image file from image directory variable. + """ + image_dir = get_bitbake_var(image_dir_var) + if not image_dir: + raise WicError("Couldn't find %s, exiting" % image_dir_var) + + image_file = image_dir + "/" + get_bitbake_var("IMAGE_LINK_NAME") + ".otaimg" + return image_file if os.path.exists(image_file) else "" + @classmethod def do_prepare_partition(cls, part, source_params, cr, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, @@ -39,13 +52,12 @@ class OTAImagePlugin(RawCopyPlugin): Called to do the actual content population for a partition i.e. it 'prepares' the partition to be incorporated into the image. """ - bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") - if not bootimg_dir: - logger.error("Couldn't find DEPLOY_DIR_IMAGE, exiting\n") - - logger.debug('Bootimg dir: %s' % bootimg_dir) - src = bootimg_dir + "/" + get_bitbake_var("IMAGE_LINK_NAME") + ".otaimg" + src = cls._get_src_file("IMGDEPLOYDIR") + if not src: + src = cls._get_src_file("DEPLOY_DIR_IMAGE") + if not src: + raise WicError("Couldn't find ota image in IMGDEPLOYDIR or DEPLOY_DIR_IMAGE, exiting") logger.debug('Preparing partition using image %s' % (src)) source_params['file'] = src -- cgit v1.2.3-54-g00ecf From a3b2e71487684f205f6cd699bdf8ad30ebfc4a7f Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Mon, 11 Mar 2019 18:14:49 +0100 Subject: Use 'printf' instead of 'echo -e' Should be less surprising Signed-off-by: Laurent Bonnans --- recipes-sota/aktualizr/aktualizr_git.bb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 7b450f5..178d137 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -69,14 +69,14 @@ do_install_append () { install -m 0700 -d ${D}${sysconfdir}/sota/conf.d if [ -n "${SOTA_HARDWARE_ID}" ]; then - echo -e "[provision]\nprimary_ecu_hardware_id = ${SOTA_HARDWARE_ID}\n" > ${D}${libdir}/sota/conf.d/40-hardware-id.toml + printf "[provision]\nprimary_ecu_hardware_id = ${SOTA_HARDWARE_ID}\n" > ${D}${libdir}/sota/conf.d/40-hardware-id.toml fi if [ -n "${SOTA_SECONDARY_CONFIG_DIR}" ]; then if [ -d "${SOTA_SECONDARY_CONFIG_DIR}" ]; then install -m 0700 -d ${D}${sysconfdir}/sota/ecus install -m 0644 "${SOTA_SECONDARY_CONFIG_DIR}"/* ${D}${sysconfdir}/sota/ecus/ - echo -e "[uptane]\nsecondary_configs_dir = /etc/sota/ecus/\n" > ${D}${libdir}/sota/conf.d/30-secondary-configs-dir.toml + printf "[uptane]\nsecondary_configs_dir = /etc/sota/ecus/\n" > ${D}${libdir}/sota/conf.d/30-secondary-configs-dir.toml else bbwarn "SOTA_SECONDARY_CONFIG_DIR is set to an invalid directory (${SOTA_SECONDARY_CONFIG_DIR})" fi -- cgit v1.2.3-54-g00ecf From 51a72876331ec340ca1559597db5054ffe435cce Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Thu, 14 Feb 2019 15:46:33 +0100 Subject: aktualizr: draft of enabling ptest Original work from Patrick. Laurent: dropped a patch for a change in aktualizr we now support directly Signed-off-by: Patrick Vacek Signed-off-by: Laurent Bonnans --- recipes-sota/aktualizr/aktualizr_git.bb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 178d137..b97adeb 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -6,6 +6,7 @@ LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=9741c346eef56131163e13b9db1241b3" DEPENDS = "boost curl openssl libarchive libsodium sqlite3 asn1c-native" +DEPENDS_append = "${@bb.utils.contains('PTEST_ENABLED', '1', ' coreutils-native ostree-native aktualizr-native ', '', d)}" RDEPENDS_${PN}_class-target = "aktualizr-check-discovery aktualizr-configs lshw" RDEPENDS_${PN}-secondary = "aktualizr-check-discovery" RDEPENDS_${PN}-host-tools = "aktualizr aktualizr-repo aktualizr-cert-provider ${@bb.utils.contains('PACKAGECONFIG', 'sota-tools', 'garage-deploy garage-push', '', d)}" @@ -33,7 +34,7 @@ BRANCH ?= "master" S = "${WORKDIR}/git" -inherit pkgconfig cmake systemd +inherit cmake pkgconfig ptest systemd SYSTEMD_PACKAGES = "${PN} ${PN}-secondary" SYSTEMD_SERVICE_${PN} = "aktualizr.service" @@ -54,6 +55,10 @@ PACKAGECONFIG[load-tests] = "-DBUILD_LOAD_TESTS=ON,-DBUILD_LOAD_TESTS=OFF," PACKAGECONFIG[serialcan] = ",,,slcand-start" PACKAGECONFIG[ubootenv] = ",,,u-boot-fw-utils aktualizr-uboot-env-rollback" +do_compile_ptest() { + cmake_runcmake_build --target build_tests +} + do_install_append () { install -d ${D}${libdir}/sota install -m 0644 ${S}/config/sota_autoprov.toml ${D}/${libdir}/sota/sota_autoprov.toml -- cgit v1.2.3-54-g00ecf From 91fa436211da0a2cadf6eb29df26977e27ba1015 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Thu, 28 Feb 2019 14:51:08 +0100 Subject: Add working ptest suite for aktualizr Signed-off-by: Laurent Bonnans --- recipes-sota/aktualizr/aktualizr_git.bb | 18 +++++++++++++++++- recipes-sota/aktualizr/files/run-ptest | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100755 recipes-sota/aktualizr/files/run-ptest diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index b97adeb..2d9053b 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -11,6 +11,8 @@ RDEPENDS_${PN}_class-target = "aktualizr-check-discovery aktualizr-configs lshw" RDEPENDS_${PN}-secondary = "aktualizr-check-discovery" RDEPENDS_${PN}-host-tools = "aktualizr aktualizr-repo aktualizr-cert-provider ${@bb.utils.contains('PACKAGECONFIG', 'sota-tools', 'garage-deploy garage-push', '', d)}" +RDEPENDS_${PN}-ptest += "bash cmake python3-core python3-io python3-json python3-netserver sqlite3 valgrind" + PV = "1.0+git${SRCPV}" PR = "7" @@ -18,6 +20,7 @@ GARAGE_SIGN_PV = "0.6.0-3-gc38b9f3" SRC_URI = " \ gitsm://github.com/advancedtelematic/aktualizr;branch=${BRANCH} \ + file://run-ptest \ file://aktualizr.service \ file://aktualizr-secondary.service \ file://aktualizr-secondary.socket \ @@ -40,7 +43,7 @@ SYSTEMD_PACKAGES = "${PN} ${PN}-secondary" SYSTEMD_SERVICE_${PN} = "aktualizr.service" SYSTEMD_SERVICE_${PN}-secondary = "aktualizr-secondary.socket" -EXTRA_OECMAKE = "-DCMAKE_BUILD_TYPE=Release -DAKTUALIZR_VERSION=${PV} -Dgtest_disable_pthreads=ON" +EXTRA_OECMAKE = "-DCMAKE_BUILD_TYPE=Release -DAKTUALIZR_VERSION=${PV} -Dgtest_disable_pthreads=ON ${@bb.utils.contains('PTEST_ENABLED', '1', '-DTESTSUITE_VALGRIND=on', '', d)}" GARAGE_SIGN_OPS = "${@ d.expand('-DGARAGE_SIGN_ARCHIVE=${WORKDIR}/cli-${GARAGE_SIGN_PV}.tgz') if d.getVar('GARAGE_SIGN_AUTOVERSION') != '1' else ''}" @@ -59,6 +62,19 @@ do_compile_ptest() { cmake_runcmake_build --target build_tests } +do_install_ptest() { + # copy the complete source directory (contains build) + cp -r ${B}/ ${D}/${PTEST_PATH}/build + cp -r ${S}/ ${D}/${PTEST_PATH}/src + + # remove bogus elf file + rm ${D}/${PTEST_PATH}/src/partial/extern/RIOT/cpu/esp32/bin/bootloader.elf + + # fix the absolute paths + find ${D}/${PTEST_PATH}/build -name "CMakeFiles" | xargs rm -rf + find ${D}/${PTEST_PATH}/build -name "*.cmake" -or -name "DartConfiguration.tcl" -or -name "run-valgrind" | xargs sed -e "s|${S}|${PTEST_PATH}/src|g" -e "s|${B}|${PTEST_PATH}/build|g" -e "s|\"--gtest_output[^\"]*\"||g" -i +} + do_install_append () { install -d ${D}${libdir}/sota install -m 0644 ${S}/config/sota_autoprov.toml ${D}/${libdir}/sota/sota_autoprov.toml diff --git a/recipes-sota/aktualizr/files/run-ptest b/recipes-sota/aktualizr/files/run-ptest new file mode 100755 index 0000000..e5f0d56 --- /dev/null +++ b/recipes-sota/aktualizr/files/run-ptest @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e + +filter_logs() { + awk '/^.*Test[[:space:]]*#[[:digit:]]+:/ { + a = gensub(/^.*Test[[:space:]]*#[[:digit:]]+:[[:space:]]*([^[:space:]]+).*(Passed|Skipped|Not Run|Failed|Timeout|Exception)[[:space:]:].*$/, "\\2: \\1", "g"); + a = gensub(/^Passed/, "PASS", "g", a); + a = gensub(/^(Skipped|Disabled)/, "SKIP", "g", a); + a = gensub(/^(Not Run|Failed|Timeout|Exception)/, "FAIL", "g", a); + print a; + }' +} + +cd build +ctest -j 8 -O /tmp/aktualizr-ptest.log --output-on-failure -LE 'noptest' 2> /dev/null | filter_logs -- cgit v1.2.3-54-g00ecf From 709578d1b410dc4eb25c6c3f5060cc091470feee Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 5 Mar 2019 12:41:03 +0100 Subject: Disable ptest for aktualizr by default Signed-off-by: Laurent Bonnans --- recipes-sota/aktualizr/aktualizr_git.bb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 2d9053b..e2e0775 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -39,6 +39,10 @@ S = "${WORKDIR}/git" inherit cmake pkgconfig ptest systemd +# disable ptest by default as it slows down builds quite a lot +# can be enabled manually by setting 'PTEST_ENABLED_pn-aktualizr' to '1' in local.conf +PTEST_ENABLED = "0" + SYSTEMD_PACKAGES = "${PN} ${PN}-secondary" SYSTEMD_SERVICE_${PN} = "aktualizr.service" SYSTEMD_SERVICE_${PN}-secondary = "aktualizr-secondary.socket" -- cgit v1.2.3-54-g00ecf From a3c20bc2069ff587cd040f6248e42635694ad721 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Mon, 11 Mar 2019 11:20:47 +0100 Subject: Depend on python3-modules and curl for aktualizr-ptest For python: less headaches, it's already huge anyway. Curl is needed by some shell-backed tests. Signed-off-by: Laurent Bonnans --- 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 e2e0775..401042f 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -11,7 +11,7 @@ RDEPENDS_${PN}_class-target = "aktualizr-check-discovery aktualizr-configs lshw" RDEPENDS_${PN}-secondary = "aktualizr-check-discovery" RDEPENDS_${PN}-host-tools = "aktualizr aktualizr-repo aktualizr-cert-provider ${@bb.utils.contains('PACKAGECONFIG', 'sota-tools', 'garage-deploy garage-push', '', d)}" -RDEPENDS_${PN}-ptest += "bash cmake python3-core python3-io python3-json python3-netserver sqlite3 valgrind" +RDEPENDS_${PN}-ptest += "bash cmake curl python3-modules sqlite3 valgrind" PV = "1.0+git${SRCPV}" PR = "7" -- cgit v1.2.3-54-g00ecf From 21d36faa65421613990afdc6538da4d1cdcd8147 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Mon, 11 Mar 2019 15:31:09 +0100 Subject: Patch valgrind for rpi runs Signed-off-by: Laurent Bonnans --- .../files/bug344802-unhandled-0xec510f1e.patch | 250 +++++++++++++++++++++ recipes-devtools/valgrind/valgrind_%.bbappend | 4 + 2 files changed, 254 insertions(+) create mode 100644 recipes-devtools/valgrind/files/bug344802-unhandled-0xec510f1e.patch create mode 100644 recipes-devtools/valgrind/valgrind_%.bbappend diff --git a/recipes-devtools/valgrind/files/bug344802-unhandled-0xec510f1e.patch b/recipes-devtools/valgrind/files/bug344802-unhandled-0xec510f1e.patch new file mode 100644 index 0000000..a25f541 --- /dev/null +++ b/recipes-devtools/valgrind/files/bug344802-unhandled-0xec510f1e.patch @@ -0,0 +1,250 @@ +diff --git a/VEX/priv/guest_arm_defs.h b/VEX/priv/guest_arm_defs.h +index 2ccbe4398..90312fbd4 100644 +--- a/VEX/priv/guest_arm_defs.h ++++ b/VEX/priv/guest_arm_defs.h +@@ -350,6 +350,10 @@ typedef + } + ARMCondcode; + ++extern UInt arm_dirtyhelper_MRS_CNTFRQ ( void ); ++extern ULong arm_dirtyhelper_MRRS_CNTVCT ( void ); ++extern ULong arm_dirtyhelper_MRRS_CNTPCT ( void ); ++ + #endif /* ndef __VEX_GUEST_ARM_DEFS_H */ + + /*---------------------------------------------------------------*/ +diff --git a/VEX/priv/guest_arm_helpers.c b/VEX/priv/guest_arm_helpers.c +index 8a028736e..89b17ce7b 100644 +--- a/VEX/priv/guest_arm_helpers.c ++++ b/VEX/priv/guest_arm_helpers.c +@@ -1445,6 +1445,53 @@ VexGuestLayout + }; + + ++UInt arm_dirtyhelper_MRS_CNTFRQ ( void ) ++{ ++#if __ARM_ARCH_ISA_ARM //{ ++ UInt w = 0x55555555UL; /* overwritten */ ++ __asm__ __volatile__("mrc p15, 0, %0, c14, c0, 0" : "=r"(w)); ++ return w; ++#elif __ARM_ARCH_ISA_A64 //}{ ++ UInt w; ++ __asm__ __volatile__("mrs %0,cntfrq_el0": "=r"(w)); ++ return w; ++#else //}{ ++ return 0; ++#endif //} ++} ++ ++ULong arm_dirtyhelper_MRRS_CNTVCT ( void ) ++{ ++#if __ARM_ARCH_ISA_ARM //}{ ++ UInt w0; ++ UInt w1; ++ __asm__ __volatile__("mrrc p15, 1, %0, %1, c14" : "=r"(w0), "=r"(w1)); ++ return (((ULong)w1)<<32) | w0; ++#elif __ARM_ARCH_ISA_A64 //{ ++ ULong w; ++ __asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(w)); ++ return w; ++#else //}{ ++ return 0; ++#endif //} ++} ++ ++ULong arm_dirtyhelper_MRRS_CNTPCT ( void ) ++{ ++#if __ARM_ARCH_ISA_ARM //}{ ++ UInt w0; ++ UInt w1; ++ __asm__ __volatile__("mrrc p15, 0, %0, %1, c14" : "=r"(w0), "=r"(w1)); ++ return (((ULong)w1)<<32) | w0; ++#elif __ARM_ARCH_ISA_A64 //{ ++ ULong w; ++ __asm__ __volatile__("mrs %0, cntpct_el0" : "=r"(w)); ++ return w; ++#else //}{ ++ return 0; ++#endif //} ++} ++ + /*---------------------------------------------------------------*/ + /*--- end guest_arm_helpers.c ---*/ + /*---------------------------------------------------------------*/ +diff --git a/VEX/priv/guest_arm_toIR.c b/VEX/priv/guest_arm_toIR.c +index d858c85e0..f96af92c4 100644 +--- a/VEX/priv/guest_arm_toIR.c ++++ b/VEX/priv/guest_arm_toIR.c +@@ -18755,6 +18755,87 @@ DisResult disInstr_ARM_WRK ( + /* fall through */ + } + ++ /* CNTFRQ: mrc p15, 0, rX, c14, c0, 0 */ ++ if (0x0e1e0f10 == (insn & 0x0FFF0FFF)) { ++ UInt rD = INSN(15,12); ++ if (rD <= 14) { ++ /* skip r15, that's too stupid to handle */ ++ IRTemp val = newTemp(Ity_I32); ++ IRExpr** args = mkIRExprVec_0(); ++ IRDirty* d = unsafeIRDirty_1_N( ++ val, ++ 0/*regparms*/, ++ "arm_dirtyhelper_MRS_CNTFRQ", ++ &arm_dirtyhelper_MRS_CNTFRQ, ++ args ++ ); ++ /* execute the dirty call, dumping the result in val. */ ++ stmt( IRStmt_Dirty(d) ); ++ putIRegA(rD, mkexpr(val), condT, Ijk_Boring); ++ DIP("mrc%s p15, 0, r%u, c14, c0, 0\n", nCC(INSN_COND), rD); ++ goto decode_success; ++ } ++ /* fall through */ ++ } ++ ++ /* CNTPCT */ ++ if (0x0c500f0e == (insn & 0x0FF00FFF)) { ++ UInt rDhi = INSN(19,16); ++ UInt rDlo = INSN(15,12); ++ if (rDhi <= 14 && rDlo <= 14) { ++ /* skip r15, that's too stupid to handle */ ++ IRTemp resHi = newTemp(Ity_I32); ++ IRTemp resLo = newTemp(Ity_I32); ++ IRTemp val = newTemp(Ity_I64); ++ IRExpr** args = mkIRExprVec_0(); ++ IRDirty* d = unsafeIRDirty_1_N( ++ val, ++ 0/*regparms*/, ++ "arm_dirtyhelper_MRRS_CNTPCT", ++ &arm_dirtyhelper_MRRS_CNTPCT, ++ args ++ ); ++ /* execute the dirty call, dumping the result in val. */ ++ stmt( IRStmt_Dirty(d) ); ++ assign( resHi, unop(Iop_64HIto32, mkexpr(val)) ); ++ assign( resLo, unop(Iop_64to32, mkexpr(val)) ); ++ putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring ); ++ putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring ); ++ DIP("mrrc%s p15, 0, r%u, r%u, c14\n", nCC(INSN_COND), rDlo, rDhi); ++ goto decode_success; ++ } ++ /* fall through */ ++ } ++ ++ /* CNTVCT */ ++ if (0x0c500f1e == (insn & 0x0FF00FFF)) { ++ UInt rDhi = INSN(19,16); ++ UInt rDlo = INSN(15,12); ++ if (rDhi <= 14 && rDlo <= 14) { ++ /* skip r15, that's too stupid to handle */ ++ IRTemp resHi = newTemp(Ity_I32); ++ IRTemp resLo = newTemp(Ity_I32); ++ IRTemp val = newTemp(Ity_I64); ++ IRExpr** args = mkIRExprVec_0(); ++ IRDirty* d = unsafeIRDirty_1_N( ++ val, ++ 0/*regparms*/, ++ "arm_dirtyhelper_MRRS_CNTVCT", ++ &arm_dirtyhelper_MRRS_CNTVCT, ++ args ++ ); ++ /* execute the dirty call, dumping the result in val. */ ++ stmt( IRStmt_Dirty(d) ); ++ assign( resHi, unop(Iop_64HIto32, mkexpr(val)) ); ++ assign( resLo, unop(Iop_64to32, mkexpr(val)) ); ++ putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring ); ++ putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring ); ++ DIP("mrrc%s p15, 1, r%u, r%u, c14\n", nCC(INSN_COND), rDlo, rDhi); ++ goto decode_success; ++ } ++ /* fall through */ ++ } ++ + /* Handle various kinds of barriers. This is rather indiscriminate + in the sense that they are all turned into an IR Fence, which + means we don't know which they are, so the back end has to +@@ -23196,6 +23277,84 @@ DisResult disInstr_THUMB_WRK ( + /* fall through */ + } + ++ /* CNTFRQ: mrc p15, 0, rX, c14, c0, 0 */ ++ if ((INSN0(15,0) == 0xee1e) && (INSN1(11,0) == 0xf10)) { ++ UInt rD = INSN1(15,12); ++ if (!isBadRegT(rD)) { ++ IRTemp val = newTemp(Ity_I32); ++ IRExpr** args = mkIRExprVec_0(); ++ IRDirty* d = unsafeIRDirty_1_N( ++ val, ++ 0/*regparms*/, ++ "arm_dirtyhelper_MRS_CNTFRQ", ++ &arm_dirtyhelper_MRS_CNTFRQ, ++ args ++ ); ++ /* execute the dirty call, dumping the result in val. */ ++ stmt( IRStmt_Dirty(d) ); ++ putIRegT(rD, mkexpr(val), condT); ++ DIP("mrc p15, 0, r%u, c14, c0, 0\n", rD); ++ goto decode_success; ++ } ++ /* fall through */ ++ } ++ ++ /* CNTPCT */ ++ if ((INSN0(15,4) == 0xec5) && (INSN1(11,0) == 0xf0e)) { ++ UInt rDhi = INSN0(3,0); ++ UInt rDlo = INSN1(15,12); ++ if (!isBadRegT(rDhi) && !isBadRegT(rDlo)) { ++ IRTemp resHi = newTemp(Ity_I32); ++ IRTemp resLo = newTemp(Ity_I32); ++ IRTemp val = newTemp(Ity_I64); ++ IRExpr** args = mkIRExprVec_0(); ++ IRDirty* d = unsafeIRDirty_1_N( ++ val, ++ 0/*regparms*/, ++ "arm_dirtyhelper_MRRS_CNTPCT", ++ &arm_dirtyhelper_MRRS_CNTPCT, ++ args ++ ); ++ /* execute the dirty call, dumping the result in val. */ ++ stmt( IRStmt_Dirty(d) ); ++ assign( resHi, unop(Iop_64HIto32, mkexpr(val)) ); ++ assign( resLo, unop(Iop_64to32, mkexpr(val)) ); ++ putIRegT( rDhi, mkexpr(resHi), condT ); ++ putIRegT( rDlo, mkexpr(resLo), condT ); ++ DIP("mrrc p15, 0, r%u, r%u, c14\n", rDlo, rDhi); ++ goto decode_success; ++ } ++ /* fall through */ ++ } ++ ++ /* CNTVCT */ ++ if ((INSN0(15,4) == 0xec5) && (INSN1(11,0) == 0xf1e)) { ++ UInt rDhi = INSN0(3,0); ++ UInt rDlo = INSN1(15,12); ++ if (!isBadRegT(rDhi) && !isBadRegT(rDlo)) { ++ IRTemp resHi = newTemp(Ity_I32); ++ IRTemp resLo = newTemp(Ity_I32); ++ IRTemp val = newTemp(Ity_I64); ++ IRExpr** args = mkIRExprVec_0(); ++ IRDirty* d = unsafeIRDirty_1_N( ++ val, ++ 0/*regparms*/, ++ "arm_dirtyhelper_MRRS_CNTVCT", ++ &arm_dirtyhelper_MRRS_CNTVCT, ++ args ++ ); ++ /* execute the dirty call, dumping the result in val. */ ++ stmt( IRStmt_Dirty(d) ); ++ assign( resHi, unop(Iop_64HIto32, mkexpr(val)) ); ++ assign( resLo, unop(Iop_64to32, mkexpr(val)) ); ++ putIRegT( rDhi, mkexpr(resHi), condT ); ++ putIRegT( rDlo, mkexpr(resLo), condT ); ++ DIP("mrrc p15, 1, r%u, r%u, c14\n", rDlo, rDhi); ++ goto decode_success; ++ } ++ /* fall through */ ++ } ++ + /* ------------------- CLREX ------------------ */ + if (INSN0(15,0) == 0xF3BF && INSN1(15,0) == 0x8F2F) { + /* AFAICS, this simply cancels a (all?) reservations made by a diff --git a/recipes-devtools/valgrind/valgrind_%.bbappend b/recipes-devtools/valgrind/valgrind_%.bbappend new file mode 100644 index 0000000..c5f7c31 --- /dev/null +++ b/recipes-devtools/valgrind/valgrind_%.bbappend @@ -0,0 +1,4 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +# from https://bugs.kde.org/show_bug.cgi?id=344802 (John Reiser) +SRC_URI += "file://bug344802-unhandled-0xec510f1e.patch" -- cgit v1.2.3-54-g00ecf From 0da148c785a77e4f51fbf90078af12299f8480f2 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Tue, 12 Mar 2019 14:31:18 +0100 Subject: oe-selftest: look for expected error in stderr. The output was moved from stdout to stderr in a recent aktualizr commit. Signed-off-by: Patrick Vacek --- lib/oeqa/selftest/cases/updater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index 07232d7..c76a7ea 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -187,7 +187,7 @@ class ManualControlTests(OESelftestTestCase): """ sleep(20) stdout, stderr, retcode = self.qemu_command('aktualizr-info') - self.assertIn(b'Can\'t open database', stdout, + self.assertIn(b'Can\'t open database', stderr, 'Aktualizr should not have run yet' + stderr.decode() + stdout.decode()) stdout, stderr, retcode = self.qemu_command('aktualizr once') -- cgit v1.2.3-54-g00ecf From 6c73fd1caaea849c24ffb697a8f1d92e501551bf Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 12 Mar 2019 14:44:27 +0100 Subject: Document ptest for aktualizr Signed-off-by: Laurent Bonnans --- README.adoc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.adoc b/README.adoc index d1469a8..434c04c 100644 --- a/README.adoc +++ b/README.adoc @@ -215,6 +215,19 @@ 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]. +== Aktualizr test suite with ptest + +The meta-updater layer includes support for running parts of the aktualizr test suite on deployed devices through link:https://wiki.yoctoproject.org/wiki/Ptest[Yocto's ptest functionality]. Since it adds significant build time cost, it is currently disabled by default. To enable it, add the following to your `conf/local.conf`: + +``` +PTEST_ENABLED_pn-aktualizr = "1" +IMAGE_INSTALL_append += " aktualizr-ptest ptest-runner " +``` + +Be aware that it will add several hundreds of MB to the generated file system. + +The aktualizr tests will now be part of the deployed ptest suite, which can be run by calling `ptest-runner`. Alternatively, the required files and run script can be found in `/usr/lib/aktualizr/ptest`. + == Manual provisoning As described in <> section you can set `SOTA_DEPLOY_CREDENTIALS` to `0` to prevent deploying credentials to the built `wic` image. In this case you get a generic image that you can use e.g. on a production line to flash a series of devices. The cost of this approach is that this image is half-baked and should be provisioned before it can connect to the backend. -- cgit v1.2.3-54-g00ecf From 39ca95ca10fb27e87578b4051f1ae31298229c64 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 12 Mar 2019 15:41:44 +0100 Subject: Save space in deployed aktualizr ptest * remove whole RIOT repo * remove intermediary static libraries, only useful during build Should be around 500MB saving in total Signed-off-by: Laurent Bonnans --- recipes-sota/aktualizr/aktualizr_git.bb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 401042f..ca9d47b 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -71,8 +71,11 @@ do_install_ptest() { cp -r ${B}/ ${D}/${PTEST_PATH}/build cp -r ${S}/ ${D}/${PTEST_PATH}/src - # remove bogus elf file - rm ${D}/${PTEST_PATH}/src/partial/extern/RIOT/cpu/esp32/bin/bootloader.elf + # remove huge external unused repository + rm -rf ${D}/${PTEST_PATH}/src/partial/extern/RIOT + + # remove huge build artifacts + find ${D}/${PTEST_PATH}/build/src -name "*.a" -delete # fix the absolute paths find ${D}/${PTEST_PATH}/build -name "CMakeFiles" | xargs rm -rf -- cgit v1.2.3-54-g00ecf From 4c0dd1839ec0ec7a2b60cae4c55ca076e9395dde Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Mon, 11 Mar 2019 17:39:13 +0100 Subject: Set 'allarch' to aktualizr config recipes Signed-off-by: Laurent Bonnans --- recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb | 2 +- recipes-sota/aktualizr/aktualizr-auto-prov-creds.bb | 2 ++ recipes-sota/aktualizr/aktualizr-auto-prov.bb | 2 ++ recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb | 2 ++ recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb | 2 ++ recipes-sota/aktualizr/aktualizr-hsm-prov.bb | 2 ++ recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb | 3 +++ recipes-sota/config/aktualizr-auto-reboot.bb | 2 ++ recipes-sota/config/aktualizr-disable-send-ip.bb | 2 ++ recipes-sota/config/aktualizr-log-debug.bb | 2 ++ 10 files changed, 20 insertions(+), 1 deletion(-) diff --git a/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb b/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb index 1a515a2..0700ac6 100644 --- a/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb +++ b/recipes-connectivity/networkd-dhcp-conf/networkd-dhcp-conf.bb @@ -4,7 +4,7 @@ interfaces through systemd-networkd" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" -inherit systemd +inherit allarch systemd RPROVIDES_${PN} = "virtual/network-configuration" diff --git a/recipes-sota/aktualizr/aktualizr-auto-prov-creds.bb b/recipes-sota/aktualizr/aktualizr-auto-prov-creds.bb index 0628a61..6b2dd27 100644 --- a/recipes-sota/aktualizr/aktualizr-auto-prov-creds.bb +++ b/recipes-sota/aktualizr/aktualizr-auto-prov-creds.bb @@ -3,6 +3,8 @@ SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" +inherit allarch + DEPENDS = "aktualizr-native zip-native" ALLOW_EMPTY_${PN} = "1" diff --git a/recipes-sota/aktualizr/aktualizr-auto-prov.bb b/recipes-sota/aktualizr/aktualizr-auto-prov.bb index be12a59..3e4c208 100644 --- a/recipes-sota/aktualizr/aktualizr-auto-prov.bb +++ b/recipes-sota/aktualizr/aktualizr-auto-prov.bb @@ -5,6 +5,8 @@ SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" +inherit allarch + DEPENDS = "aktualizr-native zip-native" RDEPENDS_${PN}_append = "${@' aktualizr-auto-prov-creds' if d.getVar('SOTA_DEPLOY_CREDENTIALS', True) == '1' else ''}" PV = "1.0" diff --git a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb index b9bb1f6..da17d77 100644 --- a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb +++ b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov-creds.bb @@ -3,6 +3,8 @@ SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" +inherit allarch + # 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. diff --git a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb index 9a4166c..0d1c860 100644 --- a/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb +++ b/recipes-sota/aktualizr/aktualizr-ca-implicit-prov.bb @@ -6,6 +6,8 @@ SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" +inherit allarch + DEPENDS = "aktualizr aktualizr-native openssl-native" RDEPENDS_${PN}_append = "${@' aktualizr-ca-implicit-prov-creds' if d.getVar('SOTA_DEPLOY_CREDENTIALS', True) == '1' else ''}" diff --git a/recipes-sota/aktualizr/aktualizr-hsm-prov.bb b/recipes-sota/aktualizr/aktualizr-hsm-prov.bb index dfe397c..f738f3e 100644 --- a/recipes-sota/aktualizr/aktualizr-hsm-prov.bb +++ b/recipes-sota/aktualizr/aktualizr-hsm-prov.bb @@ -5,6 +5,8 @@ SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" +inherit allarch + DEPENDS = "aktualizr aktualizr-native" RDEPENDS_${PN}_append = "${@' aktualizr-ca-implicit-prov-creds softhsm-testtoken' if d.getVar('SOTA_DEPLOY_CREDENTIALS', True) == '1' else ''}" diff --git a/recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb b/recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb index 6702d29..ed1e3a8 100644 --- a/recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb +++ b/recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb @@ -3,6 +3,9 @@ HOMEPAGE = "https://github.com/advancedtelematic/aktualizr" SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" + +inherit allarch + DEPENDS = "aktualizr-native" RDEPENDS_${PN} = "aktualizr" diff --git a/recipes-sota/config/aktualizr-auto-reboot.bb b/recipes-sota/config/aktualizr-auto-reboot.bb index ad4d17c..f360d9e 100644 --- a/recipes-sota/config/aktualizr-auto-reboot.bb +++ b/recipes-sota/config/aktualizr-auto-reboot.bb @@ -5,6 +5,8 @@ SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" +inherit allarch + SRC_URI = " \ file://35-enable-auto-reboot.toml \ " diff --git a/recipes-sota/config/aktualizr-disable-send-ip.bb b/recipes-sota/config/aktualizr-disable-send-ip.bb index 8dd2647..07c12ca 100644 --- a/recipes-sota/config/aktualizr-disable-send-ip.bb +++ b/recipes-sota/config/aktualizr-disable-send-ip.bb @@ -5,6 +5,8 @@ SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" +inherit allarch + SRC_URI = " \ file://30-disable-send-ip.toml \ " diff --git a/recipes-sota/config/aktualizr-log-debug.bb b/recipes-sota/config/aktualizr-log-debug.bb index 098faf4..0c03786 100644 --- a/recipes-sota/config/aktualizr-log-debug.bb +++ b/recipes-sota/config/aktualizr-log-debug.bb @@ -5,6 +5,8 @@ SECTION = "base" LICENSE = "MPL-2.0" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" +inherit allarch + SRC_URI = " \ file://05-log-debug.toml \ " -- cgit v1.2.3-54-g00ecf From 07a1bd757035d31a10af4e2703e624f9a96bb881 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Mon, 11 Mar 2019 17:39:57 +0100 Subject: Add aktualizr-resource-control For controlling systemd cgroups configuration of the aktualizr daemon Signed-off-by: Laurent Bonnans --- recipes-sota/aktualizr/aktualizr_git.bb | 26 +++++++++++++++++++++- .../aktualizr/files/10-resource-control.conf | 6 +++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 recipes-sota/aktualizr/files/10-resource-control.conf diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index ca9d47b..bd1cfd1 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -25,6 +25,7 @@ SRC_URI = " \ file://aktualizr-secondary.service \ file://aktualizr-secondary.socket \ file://aktualizr-serialcan.service \ + file://10-resource-control.conf \ ${@ d.expand("https://ats-tuf-cli-releases.s3-eu-central-1.amazonaws.com/cli-${GARAGE_SIGN_PV}.tgz;unpack=0") if d.getVar('GARAGE_SIGN_AUTOVERSION') != '1' else ''} \ " @@ -62,6 +63,15 @@ PACKAGECONFIG[load-tests] = "-DBUILD_LOAD_TESTS=ON,-DBUILD_LOAD_TESTS=OFF," PACKAGECONFIG[serialcan] = ",,,slcand-start" PACKAGECONFIG[ubootenv] = ",,,u-boot-fw-utils aktualizr-uboot-env-rollback" +# can be overriden in configuration with `RESOURCE_xxx_pn-aktualizr` +# see `man systemd.resource-control` for details + +# can be used to lower aktualizr priority, default is 100 +RESOURCE_CPU_WEIGHT = "100" +# will be slowed down when it reaches 'high', killed when it reaches 'max' +RESOURCE_MEMORY_HIGH = "100M" +RESOURCE_MEMORY_MAX = "80%" + do_compile_ptest() { cmake_runcmake_build --target build_tests } @@ -118,6 +128,15 @@ do_install_append () { install -m 0755 ${B}/src/sota_tools/garage-sign/bin/* ${D}${bindir} install -m 0644 ${B}/src/sota_tools/garage-sign/lib/* ${D}${libdir} fi + + # resource control + install -d ${D}/${systemd_system_unitdir}/aktualizr.service.d + install -m 0644 ${WORKDIR}/10-resource-control.conf ${D}/${systemd_system_unitdir}/aktualizr.service.d + + sed -i -e 's|@CPU_WEIGHT@|${RESOURCE_CPU_WEIGHT}|g' \ + -e 's|@MEMORY_HIGH@|${RESOURCE_MEMORY_HIGH}|g' \ + -e 's|@MEMORY_MAX@|${RESOURCE_MEMORY_MAX}|g' \ + ${D}${systemd_system_unitdir}/aktualizr.service.d/10-resource-control.conf } PACKAGESPLITFUNCS_prepend = "split_hosttools_packages " @@ -132,7 +151,7 @@ python split_hosttools_packages () { PACKAGES_DYNAMIC = "^aktualizr-.* ^garage-.*" -PACKAGES =+ "${PN}-examples ${PN}-secondary ${PN}-configs ${PN}-host-tools" +PACKAGES =+ "${PN}-resource-control ${PN}-examples ${PN}-secondary ${PN}-configs ${PN}-host-tools" ALLOW_EMPTY_${PN}-host-tools = "1" @@ -142,6 +161,10 @@ FILES_${PN} = " \ ${systemd_unitdir}/system/aktualizr.service \ " +FILES_${PN}-resource-control = " \ + ${systemd_system_unitdir}/aktualizr.service.d/10-resource-control.conf \ + " + FILES_${PN}-configs = " \ ${sysconfdir}/sota/* \ ${libdir}/sota/* \ @@ -157,6 +180,7 @@ FILES_${PN}-secondary = " \ ${systemd_unitdir}/system/aktualizr-secondary.socket \ ${systemd_unitdir}/system/aktualizr-secondary.service \ " + BBCLASSEXTEND = "native" # vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/recipes-sota/aktualizr/files/10-resource-control.conf b/recipes-sota/aktualizr/files/10-resource-control.conf new file mode 100644 index 0000000..254713c --- /dev/null +++ b/recipes-sota/aktualizr/files/10-resource-control.conf @@ -0,0 +1,6 @@ +[Service] +CPUAccounting=true +CPUWeight=@CPU_WEIGHT@ +MemoryAccounting=true +MemoryHigh=@MEMORY_HIGH@ +MemoryMax=@MEMORY_MAX@ -- cgit v1.2.3-54-g00ecf From b8ada64b350335185cff6f4b42d6be990c7f725d Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 12 Mar 2019 11:29:04 +0100 Subject: Document aktualizr-resource-control Signed-off-by: Laurent Bonnans --- README.adoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.adoc b/README.adoc index 434c04c..01159a0 100644 --- a/README.adoc +++ b/README.adoc @@ -91,6 +91,7 @@ Your images will also need network connectivity to be able to reach an actual OT * `SOTA_CLIENT_FEATURES` - extensions to aktualizr. The only valid options are `hsm` (to build with HSM support) and `secondary-network` (to set up a simulated 'in-vehicle' network with support for a primary node with a DHCP server and a secondary node with a DHCP client). * `SOTA_SECONDARY_CONFIG_DIR` - a directory containing JSON configuration files for virtual secondaries on the host. These will be installed into `/etc/sota/ecus` on the device and automatically provided to aktualizr. * `SOTA_HARDWARE_ID` - a custom hardware ID that will be written to the aktualizr config. Defaults to MACHINE if not set. +* `RESOURCE_xxx_pn-aktualizr` - controls maximum resource usage of the aktualizr service, when `aktualizr-resource-control` is installed on the image. See <> for details. == Usage @@ -156,6 +157,19 @@ Second, you can write recipes to install additional config files with customized To use these recipes, you will need to add them to your image with a line such as `IMAGE_INSTALL_append = " aktualizr-log-debug "` in your `local.conf`. +=== aktualizr service resource control + +With systemd based images, it is possible to set resource policies for the aktualizr service. The main use case is to provide a safeguard against resource exhaustion during an unforeseen failure scenario. + +To enable it, install `aktualizr-resource-control` on the target image and optionally override the default resource limits set in link:recipes-sota/aktualizr/aktualizr_git.bb[aktualizr_git.bb], from your `local.conf`. + +For example: + +.... +IMAGE_INSTALL_append += " aktualizr-resource-control " +RESOURCE_CPU_WEIGHT_pn-aktualizr = "50" +.... + == Development configuration There are a few settings that can be controlled in `local.conf` to simplify the development process: -- cgit v1.2.3-54-g00ecf From 17bd7982758374b911647a33792eba4e2224f640 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 19 Mar 2019 16:45:34 +0100 Subject: Split oe-selftests by target machines To allow for more targeted testing Signed-off-by: Laurent Bonnans --- README.adoc | 2 +- lib/oeqa/selftest/cases/testutils.py | 103 ++++ lib/oeqa/selftest/cases/updater.py | 708 ------------------------- lib/oeqa/selftest/cases/updater_minnowboard.py | 71 +++ lib/oeqa/selftest/cases/updater_native.py | 43 ++ lib/oeqa/selftest/cases/updater_qemux86_64.py | 441 +++++++++++++++ lib/oeqa/selftest/cases/updater_raspberrypi.py | 86 +++ 7 files changed, 745 insertions(+), 709 deletions(-) create mode 100644 lib/oeqa/selftest/cases/testutils.py delete mode 100644 lib/oeqa/selftest/cases/updater.py create mode 100644 lib/oeqa/selftest/cases/updater_minnowboard.py create mode 100644 lib/oeqa/selftest/cases/updater_native.py create mode 100644 lib/oeqa/selftest/cases/updater_qemux86_64.py create mode 100644 lib/oeqa/selftest/cases/updater_raspberrypi.py diff --git a/README.adoc b/README.adoc index 01159a0..1aab7dc 100644 --- a/README.adoc +++ b/README.adoc @@ -224,7 +224,7 @@ sudo apt install ovmf 5. Run oe-selftest: + ``` -oe-selftest --run-tests updater +oe-selftest -r updater_native updater_qemux86_64 updater_minnowboard updater_raspberrypi ``` 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]. diff --git a/lib/oeqa/selftest/cases/testutils.py b/lib/oeqa/selftest/cases/testutils.py new file mode 100644 index 0000000..77bcad7 --- /dev/null +++ b/lib/oeqa/selftest/cases/testutils.py @@ -0,0 +1,103 @@ +import os +import logging +import re +import subprocess +from time import sleep + +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars +from qemucommand import QemuCommand + + +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('', (), {})() + 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. + args.dir = 'tmp/deploy/images' + args.efi = efi + args.machine = machine + qemu_use_kvm = get_bb_var("QEMU_USE_KVM") + if qemu_use_kvm and \ + (qemu_use_kvm == 'True' and 'x86' in machine or + get_bb_var('MACHINE') in qemu_use_kvm.split()): + args.kvm = True + else: + args.kvm = None # Autodetect + args.no_gui = True + args.gdb = False + args.pcap = None + args.overlay = None + args.dry_run = False + args.secondary_network = False + + qemu = QemuCommand(args) + cmdline = qemu.command_line() + print('Booting image with run-qemu-ota...') + s = subprocess.Popen(cmdline) + 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 + '"'] + s2 = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = s2.communicate(timeout=60) + 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) + + +def verifyProvisioned(testInst, machine): + # Verify that device HAS provisioned. + for delay in [5, 5, 5, 5, 10, 10, 10, 10]: + stdout, stderr, retcode = testInst.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'' and stdout.decode().find('Fetched metadata: yes') >= 0: + break + sleep(delay) + 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: diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py deleted file mode 100644 index c76a7ea..0000000 --- a/lib/oeqa/selftest/cases/updater.py +++ /dev/null @@ -1,708 +0,0 @@ -# pylint: disable=C0111,C0325 -import os -import logging -import re -import subprocess -import unittest -from time import sleep - -from oeqa.selftest.case import OESelftestTestCase -from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars -from qemucommand import QemuCommand - - -class SotaToolsTests(OESelftestTestCase): - - @classmethod - def setUpClass(cls): - super(SotaToolsTests, cls).setUpClass() - logger = logging.getLogger("selftest") - logger.info('Running bitbake to build aktualizr-native tools') - bitbake('aktualizr-native') - - def test_push_help(self): - akt_native_run(self, 'garage-push --help') - - def test_deploy_help(self): - akt_native_run(self, 'garage-deploy --help') - - def test_garagesign_help(self): - akt_native_run(self, 'garage-sign --help') - - -class GeneralTests(OESelftestTestCase): - - def test_feature_sota(self): - result = get_bb_var('DISTRO_FEATURES').find('sota') - 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') - - def test_credentials(self): - logger = logging.getLogger("selftest") - logger.info('Running bitbake to build core-image-minimal') - 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 - 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', '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) - self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) - - def test_java(self): - result = runCmd('which java', ignore_status=True) - self.assertEqual(result.status, 0, - "Java not found. Do you have a JDK installed on your host machine?") - - -class AktualizrToolsTests(OESelftestTestCase): - - @classmethod - def setUpClass(cls): - super(AktualizrToolsTests, cls).setUpClass() - logger = logging.getLogger("selftest") - logger.info('Running bitbake to build aktualizr-native tools') - bitbake('aktualizr-native') - - def test_cert_provider_help(self): - 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-ca-implicit-prov') - bitbake('aktualizr-ca-implicit-prov') - 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_HOST', 'libdir'], 'aktualizr-ca-implicit-prov') - config = bb_vars_prov['STAGING_DIR_HOST'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov_ca.toml' - - 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 + '/var/sota/import/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 + '/var/sota/import/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 + '/var/sota/import/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 AutoProvTests(OESelftestTestCase): - - 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 luck. - 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): - 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_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 = 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 [1, 2, 5, 10, 15]: - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'': - ran_ok = True - break - sleep(delay) - self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) - - verifyProvisioned(self, machine) - - -class ManualControlTests(OESelftestTestCase): - - 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('SYSTEMD_AUTO_ENABLE_aktualizr = "disable"') - 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) - - def test_manual_run_mode_once(self): - """ - Disable the systemd service then run aktualizr manually - """ - sleep(20) - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - self.assertIn(b'Can\'t open database', stderr, - 'Aktualizr should not have run yet' + stderr.decode() + stdout.decode()) - - stdout, stderr, retcode = self.qemu_command('aktualizr once') - - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - self.assertIn(b'Fetched metadata: yes', stdout, - 'Aktualizr should have run' + stderr.decode() + stdout.decode()) - - -class RpiTests(OESelftestTestCase): - - def setUpLocal(self): - # 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 luck. - 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') - # 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 luck. - path = os.path.abspath(os.path.dirname(__file__)) - metadir = path + "/../../../../../" - 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.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): - qemu_terminate(self.s) - 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) - - def test_grub(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 = stdout.decode()[:-1] - self.assertEqual(value, machine, - 'MACHINE does not match hostname: ' + machine + ', ' + value + - '\nIs TianoCore ovmf installed on your host machine?') - print(value) - print('Checking output of aktualizr-info:') - ran_ok = False - for delay in [1, 2, 5, 10, 15]: - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'': - ran_ok = True - break - sleep(delay) - self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) - - verifyProvisioned(self, machine) - - -class ImplProvTests(OESelftestTestCase): - - 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 luck. - 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-ca-implicit-prov "') - self.append_config('SOTA_DEPLOY_CREDENTIALS = "0"') - runCmd('bitbake -c cleanall aktualizr aktualizr-ca-implicit-prov') - 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) - - 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 = 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 [1, 2, 5, 10, 15]: - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'': - ran_ok = True - break - sleep(delay) - 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 aktualizr-cert-provider. - bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') - creds = bb_vars['SOTA_PACKED_CREDENTIALS'] - bb_vars_prov = get_bb_vars(['STAGING_DIR_HOST', 'libdir'], 'aktualizr-ca-implicit-prov') - config = bb_vars_prov['STAGING_DIR_HOST'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov_ca.toml' - - print('Provisining at root@localhost:%d' % self.qemu.ssh_port) - akt_native_run(self, 'aktualizr-cert-provider -c {creds} -t root@localhost -p {port} -s -u -r -g {config}' - .format(creds=creds, port=self.qemu.ssh_port, config=config)) - - verifyProvisioned(self, machine) - - -class HsmTests(OESelftestTestCase): - - 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 luck. - 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_DEPLOY_CREDENTIALS = "0"') - self.append_config('SOTA_CLIENT_FEATURES = "hsm"') - self.append_config('IMAGE_INSTALL_append = " softhsm-testtoken"') - runCmd('bitbake -c cleanall aktualizr aktualizr-hsm-prov') - 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) - - 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 = 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 [1, 2, 5, 10, 15]: - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'': - ran_ok = True - break - sleep(delay) - 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()) - - # Verify that HSM is not yet initialized. - 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()) - softhsm2_command = 'softhsm2-util --show-slots' - stdout, stderr, retcode = self.qemu_command(softhsm2_command) - self.assertNotEqual(retcode, 0, 'softhsm2-tool succeeded before initialization: ' + - stdout.decode() + stderr.decode()) - - # Run aktualizr-cert-provider. - 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_hsm_prov.toml' - - akt_native_run(self, 'aktualizr-cert-provider -c {creds} -t root@localhost -p {port} -r -s -u -g {config}' - .format(creds=creds, port=self.qemu.ssh_port, config=config)) - - # Verify that HSM is able to initialize. - ran_ok = False - for delay in [5, 5, 5, 5, 10]: - sleep(delay) - 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 - 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()) - - # 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()) - - 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 luck. - 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 test_secondary_listening(self): - print('Checking aktualizr-secondary service is listening') - stdout, stderr, retcode = self.qemu_command('aktualizr-check-discovery') - 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 luck. - 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') - bitbake('core-image-minimal') - # Create empty object. - args = type('', (), {})() - 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. - args.dir = 'tmp/deploy/images' - args.efi = efi - args.machine = machine - qemu_use_kvm = get_bb_var("QEMU_USE_KVM") - if qemu_use_kvm and \ - (qemu_use_kvm == 'True' and 'x86' in machine or \ - get_bb_var('MACHINE') in qemu_use_kvm.split()): - args.kvm = True - else: - args.kvm = None # Autodetect - args.no_gui = True - args.gdb = False - args.pcap = None - args.overlay = None - args.dry_run = False - args.secondary_network = False - - qemu = QemuCommand(args) - cmdline = qemu.command_line() - print('Booting image with run-qemu-ota...') - s = subprocess.Popen(cmdline) - 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 + '"'] - s2 = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = s2.communicate(timeout=60) - 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) - - -def verifyProvisioned(testInst, machine): - # Verify that device HAS provisioned. - ran_ok = False - for delay in [5, 5, 5, 5, 10, 10, 10, 10]: - 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 - sleep(delay) - 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: diff --git a/lib/oeqa/selftest/cases/updater_minnowboard.py b/lib/oeqa/selftest/cases/updater_minnowboard.py new file mode 100644 index 0000000..97b2a86 --- /dev/null +++ b/lib/oeqa/selftest/cases/updater_minnowboard.py @@ -0,0 +1,71 @@ +import os +import re +from time import sleep + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import runCmd, bitbake, get_bb_var +from testutils import qemu_launch, qemu_send_command, qemu_terminate, verifyProvisioned + + +class MinnowTests(OESelftestTestCase): + + def setUpLocal(self): + layer_intel = "meta-intel" + layer_minnow = "meta-updater-minnowboard" + 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 luck. + path = os.path.abspath(os.path.dirname(__file__)) + metadir = path + "/../../../../../" + 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.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): + qemu_terminate(self.s) + 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) + + 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 = stdout.decode()[:-1] + self.assertEqual(value, machine, + 'MACHINE does not match hostname: ' + machine + ', ' + value + + '\nIs TianoCore ovmf installed on your host machine?') + print(value) + print('Checking output of aktualizr-info:') + ran_ok = False + for delay in [1, 2, 5, 10, 15]: + stdout, stderr, retcode = self.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'': + ran_ok = True + break + sleep(delay) + self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) + + verifyProvisioned(self, machine) + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/lib/oeqa/selftest/cases/updater_native.py b/lib/oeqa/selftest/cases/updater_native.py new file mode 100644 index 0000000..de98a09 --- /dev/null +++ b/lib/oeqa/selftest/cases/updater_native.py @@ -0,0 +1,43 @@ +# pylint: disable=C0111,C0325 +import logging + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import runCmd, bitbake, get_bb_var +from testutils import akt_native_run + + +class SotaToolsTests(OESelftestTestCase): + + @classmethod + def setUpClass(cls): + super(SotaToolsTests, cls).setUpClass() + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build aktualizr-native tools') + bitbake('aktualizr-native') + + def test_push_help(self): + akt_native_run(self, 'garage-push --help') + + def test_deploy_help(self): + akt_native_run(self, 'garage-deploy --help') + + def test_garagesign_help(self): + akt_native_run(self, 'garage-sign --help') + + +class GeneralTests(OESelftestTestCase): + + def test_feature_sota(self): + result = get_bb_var('DISTRO_FEATURES').find('sota') + 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') + + def test_java(self): + result = runCmd('which java', ignore_status=True) + self.assertEqual(result.status, 0, + "Java not found. Do you have a JDK installed on your host machine?") + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64.py b/lib/oeqa/selftest/cases/updater_qemux86_64.py new file mode 100644 index 0000000..814e139 --- /dev/null +++ b/lib/oeqa/selftest/cases/updater_qemux86_64.py @@ -0,0 +1,441 @@ +# pylint: disable=C0111,C0325 +import os +import logging +import re +import unittest +from time import sleep + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars +from testutils import qemu_launch, qemu_send_command, qemu_terminate, \ + akt_native_run, verifyProvisioned + + +class GeneralTests(OESelftestTestCase): + def test_credentials(self): + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build core-image-minimal') + 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 + 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', '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) + self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) + + +class AktualizrToolsTests(OESelftestTestCase): + + @classmethod + def setUpClass(cls): + super(AktualizrToolsTests, cls).setUpClass() + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build aktualizr-native tools') + bitbake('aktualizr-native') + + def test_cert_provider_help(self): + 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-ca-implicit-prov') + bitbake('aktualizr-ca-implicit-prov') + 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_HOST', 'libdir'], 'aktualizr-ca-implicit-prov') + config = bb_vars_prov['STAGING_DIR_HOST'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov_ca.toml' + + 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 + '/var/sota/import/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 + '/var/sota/import/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 + '/var/sota/import/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 AutoProvTests(OESelftestTestCase): + + 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 luck. + 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): + 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_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 = 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 [1, 2, 5, 10, 15]: + stdout, stderr, retcode = self.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'': + ran_ok = True + break + sleep(delay) + self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) + + verifyProvisioned(self, machine) + + +class ManualControlTests(OESelftestTestCase): + + 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('SYSTEMD_AUTO_ENABLE_aktualizr = "disable"') + 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) + + def test_manual_run_mode_once(self): + """ + Disable the systemd service then run aktualizr manually + """ + sleep(20) + stdout, stderr, retcode = self.qemu_command('aktualizr-info') + self.assertIn(b'Can\'t open database', stderr, + 'Aktualizr should not have run yet' + stderr.decode() + stdout.decode()) + + stdout, stderr, retcode = self.qemu_command('aktualizr once') + + stdout, stderr, retcode = self.qemu_command('aktualizr-info') + self.assertIn(b'Fetched metadata: yes', stdout, + 'Aktualizr should have run' + stderr.decode() + stdout.decode()) + + +class ImplProvTests(OESelftestTestCase): + + 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 luck. + 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-ca-implicit-prov "') + self.append_config('SOTA_DEPLOY_CREDENTIALS = "0"') + runCmd('bitbake -c cleanall aktualizr aktualizr-ca-implicit-prov') + 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) + + 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 = 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 [1, 2, 5, 10, 15]: + stdout, stderr, retcode = self.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'': + ran_ok = True + break + sleep(delay) + 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 aktualizr-cert-provider. + bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') + creds = bb_vars['SOTA_PACKED_CREDENTIALS'] + bb_vars_prov = get_bb_vars(['STAGING_DIR_HOST', 'libdir'], 'aktualizr-ca-implicit-prov') + config = bb_vars_prov['STAGING_DIR_HOST'] + bb_vars_prov['libdir'] + '/sota/sota_implicit_prov_ca.toml' + + print('Provisining at root@localhost:%d' % self.qemu.ssh_port) + akt_native_run(self, 'aktualizr-cert-provider -c {creds} -t root@localhost -p {port} -s -u -r -g {config}' + .format(creds=creds, port=self.qemu.ssh_port, config=config)) + + verifyProvisioned(self, machine) + + +class HsmTests(OESelftestTestCase): + + 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 luck. + 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_DEPLOY_CREDENTIALS = "0"') + self.append_config('SOTA_CLIENT_FEATURES = "hsm"') + self.append_config('IMAGE_INSTALL_append = " softhsm-testtoken"') + runCmd('bitbake -c cleanall aktualizr aktualizr-hsm-prov') + 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) + + 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 = 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 [1, 2, 5, 10, 15]: + stdout, stderr, retcode = self.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'': + ran_ok = True + break + sleep(delay) + 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()) + + # Verify that HSM is not yet initialized. + 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()) + softhsm2_command = 'softhsm2-util --show-slots' + stdout, stderr, retcode = self.qemu_command(softhsm2_command) + self.assertNotEqual(retcode, 0, 'softhsm2-tool succeeded before initialization: ' + + stdout.decode() + stderr.decode()) + + # Run aktualizr-cert-provider. + 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_hsm_prov.toml' + + akt_native_run(self, 'aktualizr-cert-provider -c {creds} -t root@localhost -p {port} -r -s -u -g {config}' + .format(creds=creds, port=self.qemu.ssh_port, config=config)) + + # Verify that HSM is able to initialize. + ran_ok = False + for delay in [5, 5, 5, 5, 10]: + sleep(delay) + 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 + 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()) + + # 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()) + + 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 luck. + 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 test_secondary_listening(self): + print('Checking aktualizr-secondary service is listening') + stdout, stderr, retcode = self.qemu_command('aktualizr-check-discovery') + 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 luck. + 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()) + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/lib/oeqa/selftest/cases/updater_raspberrypi.py b/lib/oeqa/selftest/cases/updater_raspberrypi.py new file mode 100644 index 0000000..1cab2b8 --- /dev/null +++ b/lib/oeqa/selftest/cases/updater_raspberrypi.py @@ -0,0 +1,86 @@ +# pylint: disable=C0111,C0325 +import os +import logging +import re +import unittest + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import runCmd, bitbake, get_bb_var + + +class RpiTests(OESelftestTestCase): + + def setUpLocal(self): + # 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 luck. + 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_build(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) + +# vim:set ts=4 sw=4 sts=4 expandtab: -- cgit v1.2.3-54-g00ecf From 7c16c21bc29a841c58621ee0ef3f4d81083ef0e0 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 19 Mar 2019 17:30:05 +0100 Subject: Fix in oe-selftests/qemu_launch Should build `imagename` and not 'core-image-minimal' in all cases Signed-off-by: Laurent Bonnans --- lib/oeqa/selftest/cases/testutils.py | 11 +++++------ lib/oeqa/selftest/cases/updater_qemux86_64.py | 14 -------------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/lib/oeqa/selftest/cases/testutils.py b/lib/oeqa/selftest/cases/testutils.py index 77bcad7..d381d7d 100644 --- a/lib/oeqa/selftest/cases/testutils.py +++ b/lib/oeqa/selftest/cases/testutils.py @@ -10,14 +10,13 @@ from qemucommand import QemuCommand 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') + if imagename is None: + imagename = 'core-image-minimal' + logger.info('Running bitbake to build {}'.format(imagename)) + bitbake(imagename) # Create empty object. args = type('', (), {})() - if imagename: - args.imagename = imagename - else: - args.imagename = 'core-image-minimal' + args.imagename = imagename args.mac = None # Could use DEPLOY_DIR_IMAGE here but it's already in the machine # subdirectory. diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64.py b/lib/oeqa/selftest/cases/updater_qemux86_64.py index 814e139..95ae208 100644 --- a/lib/oeqa/selftest/cases/updater_qemux86_64.py +++ b/lib/oeqa/selftest/cases/updater_qemux86_64.py @@ -354,13 +354,6 @@ class HsmTests(OESelftestTestCase): 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') @@ -399,13 +392,6 @@ class SecondaryTests(OESelftestTestCase): 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') -- cgit v1.2.3-54-g00ecf From 54b7f9b8a18e80b384bd7551e90acccd9b53ec88 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 19 Mar 2019 17:28:07 +0100 Subject: Add resource control test Signed-off-by: Laurent Bonnans --- lib/oeqa/selftest/cases/updater_qemux86_64.py | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64.py b/lib/oeqa/selftest/cases/updater_qemux86_64.py index 95ae208..3c6a21a 100644 --- a/lib/oeqa/selftest/cases/updater_qemux86_64.py +++ b/lib/oeqa/selftest/cases/updater_qemux86_64.py @@ -424,4 +424,49 @@ class PrimaryTests(OESelftestTestCase): self.assertEqual(retcode, 0, "Unable to run aktualizr --help") self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) + +class ResourceControlTests(OESelftestTestCase): + 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 luck. + 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('IMAGE_INSTALL_append += " aktualizr-resource-control "') + self.append_config('RESOURCE_CPU_WEIGHT_pn-aktualizr = "1000"') + self.append_config('RESOURCE_MEMORY_HIGH_pn-aktualizr = "50M"') + self.append_config('RESOURCE_MEMORY_MAX_pn-aktualizr = "1M"') + 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) + + def test_aktualizr_resource_control(self): + print('Checking aktualizr was killed') + stdout, stderr, retcode = self.qemu_command('systemctl --no-pager show aktualizr') + self.assertIn(b'CPUWeight=1000', stdout, 'CPUWeight was not set correctly') + self.assertIn(b'MemoryHigh=52428800', stdout, 'MemoryHigh was not set correctly') + self.assertIn(b'MemoryMax=1048576', stdout, 'MemoryMax was not set correctly') + self.assertIn(b'ExecMainStatus=9', stdout, 'Aktualizr was not killed') + + self.qemu_command('systemctl --runtime set-property aktualizr MemoryMax=') + self.qemu_command('systemctl restart aktualizr') + + stdout, stderr, retcode = self.qemu_command('systemctl --no-pager show --property=ExecMainStatus aktualizr') + self.assertIn(b'ExecMainStatus=0', stdout, 'Aktualizr did not restart') + # vim:set ts=4 sw=4 sts=4 expandtab: -- cgit v1.2.3-54-g00ecf From f536a81902fcd110bb7b37f4a7eda171d5a60d2c Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 20 Mar 2019 12:09:53 +0100 Subject: Solve qemu long rng initialization problem Expose a fake hardware rng on the guest, linked to the host's /dev/urandom. Signed-off-by: Laurent Bonnans --- scripts/qemucommand.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/qemucommand.py b/scripts/qemucommand.py index 86362f7..9b21a66 100644 --- a/scripts/qemucommand.py +++ b/scripts/qemucommand.py @@ -97,6 +97,8 @@ class QemuCommand(object): "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port, "-m", "1G", "-usb", + "-object", "rng-random,id=rng0,filename=/dev/urandom", + "-device", "virtio-rng-pci,rng=rng0", "-device", "usb-tablet", "-show-cursor", "-vga", "std", -- cgit v1.2.3-54-g00ecf From 48fe68253536e72b2b374b83dfdc89a72185311e Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Thu, 21 Mar 2019 13:59:52 +0100 Subject: Cleanup (not) provisioned checks in oe-selftest Signed-off-by: Laurent Bonnans --- lib/oeqa/selftest/cases/testutils.py | 28 ++++++++++++- lib/oeqa/selftest/cases/updater_minnowboard.py | 13 +------ lib/oeqa/selftest/cases/updater_qemux86_64.py | 54 +++----------------------- 3 files changed, 33 insertions(+), 62 deletions(-) diff --git a/lib/oeqa/selftest/cases/testutils.py b/lib/oeqa/selftest/cases/testutils.py index d381d7d..90ba653 100644 --- a/lib/oeqa/selftest/cases/testutils.py +++ b/lib/oeqa/selftest/cases/testutils.py @@ -81,16 +81,42 @@ def akt_native_run(testInst, cmd, **kwargs): testInst.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) +def verifyNotProvisioned(testInst, machine): + print('Checking output of aktualizr-info:') + ran_ok = False + for delay in [5, 5, 5, 5, 10, 10, 10, 10]: + stdout, stderr, retcode = testInst.qemu_command('aktualizr-info') + if retcode == 0 and stderr == b'': + ran_ok = True + break + sleep(delay) + testInst.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) + + # Verify that device has NOT yet provisioned. + testInst.assertIn(b'Couldn\'t load device ID', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + testInst.assertIn(b'Couldn\'t load ECU serials', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + testInst.assertIn(b'Provisioned on server: no', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + testInst.assertIn(b'Fetched metadata: no', stdout, + 'Device already provisioned!? ' + stderr.decode() + stdout.decode()) + + def verifyProvisioned(testInst, machine): # Verify that device HAS provisioned. + ran_ok = False for delay in [5, 5, 5, 5, 10, 10, 10, 10]: 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 sleep(delay) + testInst.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) + 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()) + '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()) diff --git a/lib/oeqa/selftest/cases/updater_minnowboard.py b/lib/oeqa/selftest/cases/updater_minnowboard.py index 97b2a86..f5df584 100644 --- a/lib/oeqa/selftest/cases/updater_minnowboard.py +++ b/lib/oeqa/selftest/cases/updater_minnowboard.py @@ -1,9 +1,8 @@ import os import re -from time import sleep from oeqa.selftest.case import OESelftestTestCase -from oeqa.utils.commands import runCmd, bitbake, get_bb_var +from oeqa.utils.commands import runCmd, get_bb_var from testutils import qemu_launch, qemu_send_command, qemu_terminate, verifyProvisioned @@ -55,16 +54,6 @@ class MinnowTests(OESelftestTestCase): self.assertEqual(value, machine, 'MACHINE does not match hostname: ' + machine + ', ' + value + '\nIs TianoCore ovmf installed on your host machine?') - print(value) - print('Checking output of aktualizr-info:') - ran_ok = False - for delay in [1, 2, 5, 10, 15]: - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'': - ran_ok = True - break - sleep(delay) - self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) verifyProvisioned(self, machine) diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64.py b/lib/oeqa/selftest/cases/updater_qemux86_64.py index 3c6a21a..b711fa1 100644 --- a/lib/oeqa/selftest/cases/updater_qemux86_64.py +++ b/lib/oeqa/selftest/cases/updater_qemux86_64.py @@ -8,7 +8,7 @@ from time import sleep from oeqa.selftest.case import OESelftestTestCase from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars from testutils import qemu_launch, qemu_send_command, qemu_terminate, \ - akt_native_run, verifyProvisioned + akt_native_run, verifyNotProvisioned, verifyProvisioned class GeneralTests(OESelftestTestCase): @@ -106,16 +106,6 @@ class AutoProvTests(OESelftestTestCase): 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 [1, 2, 5, 10, 15]: - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'': - ran_ok = True - break - sleep(delay) - self.assertTrue(ran_ok, 'aktualizr-info failed: ' + stderr.decode() + stdout.decode()) verifyProvisioned(self, machine) @@ -204,25 +194,8 @@ class ImplProvTests(OESelftestTestCase): 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 [1, 2, 5, 10, 15]: - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'': - ran_ok = True - break - sleep(delay) - 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()) + + verifyNotProvisioned(self, machine) # Run aktualizr-cert-provider. bb_vars = get_bb_vars(['SOTA_PACKED_CREDENTIALS'], 'aktualizr-native') @@ -279,25 +252,8 @@ class HsmTests(OESelftestTestCase): 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 [1, 2, 5, 10, 15]: - stdout, stderr, retcode = self.qemu_command('aktualizr-info') - if retcode == 0 and stderr == b'': - ran_ok = True - break - sleep(delay) - 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()) + + verifyNotProvisioned(self, machine) # Verify that HSM is not yet initialized. pkcs11_command = 'pkcs11-tool --module=/usr/lib/softhsm/libsofthsm2.so -O' -- cgit v1.2.3-54-g00ecf From 8f34415079cabc543c4ce495f9fe8b441b164313 Mon Sep 17 00:00:00 2001 From: Mykhaylo Sul Date: Wed, 3 Apr 2019 20:39:01 +0200 Subject: OTA-2418: Remove example.com URL from automated garage-sign usage Signed-off-by: Mykhaylo Sul --- classes/image_types_ostree.bbclass | 7 ++++++- classes/sota.bbclass | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/classes/image_types_ostree.bbclass b/classes/image_types_ostree.bbclass index f3b1b33..134f5f5 100644 --- a/classes/image_types_ostree.bbclass +++ b/classes/image_types_ostree.bbclass @@ -224,6 +224,11 @@ IMAGE_CMD_garagesign () { # Push may fail due to race condition when multiple build machines try to push simultaneously # in which case targets.json should be pulled again and the whole procedure repeated push_success=0 + target_url="" + if [ -n "${GARAGE_TARGET_URL}" ]; then + target_url='--url ${GARAGE_TARGET_URL}' + fi + for push_retries in $( seq 3 ); do garage-sign targets pull --repo tufrepo \ --home-dir ${GARAGE_SIGN_REPO} @@ -233,7 +238,7 @@ IMAGE_CMD_garagesign () { --format OSTREE \ --version ${target_version} \ --length 0 \ - --url "${GARAGE_TARGET_URL}" \ + ${target_url} \ --sha256 ${ostree_target_hash} \ --hardwareids ${SOTA_HARDWARE_ID} garage-sign targets sign --repo tufrepo \ diff --git a/classes/sota.bbclass b/classes/sota.bbclass index 1517ceb..cb00a80 100644 --- a/classes/sota.bbclass +++ b/classes/sota.bbclass @@ -38,7 +38,7 @@ GARAGE_SIGN_REPO ?= "${DEPLOY_DIR_IMAGE}/garage_sign_repo" GARAGE_SIGN_KEYNAME ?= "garage-key" GARAGE_TARGET_NAME ?= "${OSTREE_BRANCHNAME}" GARAGE_TARGET_VERSION ?= "" -GARAGE_TARGET_URL ?= "https://example.com/" +GARAGE_TARGET_URL ?= "" SOTA_MACHINE ??="none" SOTA_MACHINE_rpi ?= "raspberrypi" -- cgit v1.2.3-54-g00ecf From 7fd15e54115e6483a20c05e045d8dfe1883522bf Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Thu, 21 Mar 2019 17:30:55 +0100 Subject: Add oe-selftest for aktualizr ptest run on qemu Signed-off-by: Laurent Bonnans --- lib/oeqa/selftest/cases/testutils.py | 4 +- .../selftest/cases/updater_qemux86_64_ptest.py | 52 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py diff --git a/lib/oeqa/selftest/cases/testutils.py b/lib/oeqa/selftest/cases/testutils.py index 90ba653..2ad99ad 100644 --- a/lib/oeqa/selftest/cases/testutils.py +++ b/lib/oeqa/selftest/cases/testutils.py @@ -52,11 +52,11 @@ def qemu_terminate(s): pass -def qemu_send_command(port, command): +def qemu_send_command(port, command, timeout=60): 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(timeout=60) + stdout, stderr = s2.communicate(timeout=timeout) return stdout, stderr, s2.returncode diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py b/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py new file mode 100644 index 0000000..8ac6443 --- /dev/null +++ b/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py @@ -0,0 +1,52 @@ +# pylint: disable=C0111,C0325 +import os +import re + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import runCmd +from testutils import qemu_launch, qemu_send_command, qemu_terminate + + +class PtestTests(OESelftestTestCase): + + 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('SYSTEMD_AUTO_ENABLE_aktualizr = "disable"') + self.append_config('PTEST_ENABLED_pn-aktualizr = "1"') + self.append_config('IMAGE_INSTALL_append += "aktualizr-ptest ptest-runner "') + 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, timeout=60): + return qemu_send_command(self.qemu.ssh_port, command, timeout=timeout) + + def test_run_ptests(self): + # logger = logging.getLogger("selftest") + stdout, stderr, retcode = self.qemu_command('ptest-runner', timeout=None) + output = stdout.decode() + print(output) + self.assertEqual(retcode, 0) + + has_failure = re.search('^FAIL', output, flags=re.MULTILINE) is not None + if has_failure: + print("Full test suite log:") + stdout, stderr, retcode = self.qemu_command('cat /tmp/aktualizr-ptest.log', timeout=None) + print(stdout.decode()) + + self.assertFalse(has_failure) -- cgit v1.2.3-54-g00ecf From eb6d5fdb82514b051d1e595b556f61602866696d Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 10 Apr 2019 10:23:06 +0200 Subject: Fix problem with lshw for aktualizr ptest lshw is installed in `/usr/sbin` which does not appear when a command is launched outside a non-login shell. Signed-off-by: Laurent Bonnans --- lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py b/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py index 8ac6443..a04032c 100644 --- a/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py +++ b/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py @@ -37,8 +37,8 @@ class PtestTests(OESelftestTestCase): return qemu_send_command(self.qemu.ssh_port, command, timeout=timeout) def test_run_ptests(self): - # logger = logging.getLogger("selftest") - stdout, stderr, retcode = self.qemu_command('ptest-runner', timeout=None) + # simulate a login shell, so that /usr/sbin is in $PATH (from /etc/profile) + stdout, stderr, retcode = self.qemu_command('sh -l -c ptest-runner', timeout=None) output = stdout.decode() print(output) self.assertEqual(retcode, 0) -- cgit v1.2.3-54-g00ecf From 3b95982792d4f8c0d47e543d84abaaaeef56c611 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 10 Apr 2019 10:14:45 +0200 Subject: Add openssl-bin as a aktualizr-ptest requirement Signed-off-by: Laurent Bonnans --- 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 bd1cfd1..850816f 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -11,7 +11,7 @@ RDEPENDS_${PN}_class-target = "aktualizr-check-discovery aktualizr-configs lshw" RDEPENDS_${PN}-secondary = "aktualizr-check-discovery" RDEPENDS_${PN}-host-tools = "aktualizr aktualizr-repo aktualizr-cert-provider ${@bb.utils.contains('PACKAGECONFIG', 'sota-tools', 'garage-deploy garage-push', '', d)}" -RDEPENDS_${PN}-ptest += "bash cmake curl python3-modules sqlite3 valgrind" +RDEPENDS_${PN}-ptest += "bash cmake curl python3-modules openssl-bin sqlite3 valgrind" PV = "1.0+git${SRCPV}" PR = "7" -- cgit v1.2.3-54-g00ecf From ae54ed1e3956545b9822a972481a494d2309b9bc Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 10 Apr 2019 10:15:08 +0200 Subject: Parametrizable AKTUALIZR_PTEST_PARALLEL_LEVEL Signed-off-by: Laurent Bonnans --- recipes-sota/aktualizr/files/run-ptest | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/recipes-sota/aktualizr/files/run-ptest b/recipes-sota/aktualizr/files/run-ptest index e5f0d56..ff441f9 100755 --- a/recipes-sota/aktualizr/files/run-ptest +++ b/recipes-sota/aktualizr/files/run-ptest @@ -1,6 +1,8 @@ #!/bin/sh -set -e +set -eu + +AKTUALIZR_PTEST_PARALLEL_LEVEL=${AKTUALIZR_PTEST_PARALLEL_LEVEL:-2} filter_logs() { awk '/^.*Test[[:space:]]*#[[:digit:]]+:/ { @@ -13,4 +15,4 @@ filter_logs() { } cd build -ctest -j 8 -O /tmp/aktualizr-ptest.log --output-on-failure -LE 'noptest' 2> /dev/null | filter_logs +ctest -j "$AKTUALIZR_PTEST_PARALLEL_LEVEL" -O /tmp/aktualizr-ptest.log --output-on-failure -LE 'noptest' 2> /dev/null | filter_logs -- cgit v1.2.3-54-g00ecf From d9b96a6c3b4f8a8d010d5e19e6fa96a36464c390 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 10 Apr 2019 14:42:13 +0200 Subject: Use PARALLEL_MAKE when building aktualizr-ptest The trick to add it in do_compile from cmake.bbclass does not work with do_compile_ptest_base Signed-off-by: Laurent Bonnans --- 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 850816f..3094146 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -73,7 +73,7 @@ RESOURCE_MEMORY_HIGH = "100M" RESOURCE_MEMORY_MAX = "80%" do_compile_ptest() { - cmake_runcmake_build --target build_tests + cmake_runcmake_build --target build_tests "${PARALLEL_MAKE}" } do_install_ptest() { -- cgit v1.2.3-54-g00ecf From b46b46035ed3892db9aec7a91b4a23a820a79c1b Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Mon, 15 Apr 2019 12:09:49 +0200 Subject: Bump aktualizr and garage tools Signed-off-by: Laurent Bonnans --- recipes-sota/aktualizr/aktualizr_git.bb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 3094146..77d6d22 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -16,7 +16,7 @@ RDEPENDS_${PN}-ptest += "bash cmake curl python3-modules openssl-bin sqlite3 val PV = "1.0+git${SRCPV}" PR = "7" -GARAGE_SIGN_PV = "0.6.0-3-gc38b9f3" +GARAGE_SIGN_PV = "0.6.0-18-g5b8b259" SRC_URI = " \ gitsm://github.com/advancedtelematic/aktualizr;branch=${BRANCH} \ @@ -30,10 +30,10 @@ SRC_URI = " \ " # for garage-sign archive -SRC_URI[md5sum] = "30d7f0931e2236954679e75d1bae174f" -SRC_URI[sha256sum] = "46d8c6448ce14cbb9af6a93eba7e29d38579e566dcd6518d22f723a8da16cad5" +SRC_URI[md5sum] = "c5e9968dfe78a7264ab9a8338c11725d" +SRC_URI[sha256sum] = "3a19258d7a1825a308aca0da82f7a337985bec05e8951355c4c95f0fcf2444f4" -SRCREV = "c71ec0a320d85a3e75ba37bff7dc40ad02e9d655" +SRCREV = "9c5ef10b7b91cc7d51cd22fc60446e734cf84690" BRANCH ?= "master" S = "${WORKDIR}/git" -- cgit v1.2.3-54-g00ecf From 19a39e622fcdea33ee07dad7dda3531cf409c4c9 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Mon, 29 Apr 2019 10:47:00 +0200 Subject: selftest: Remove test_secondary_listening. The secondary discovery mechanism is being overhauled and that tool no longer exists. Signed-off-by: Patrick Vacek --- lib/oeqa/selftest/cases/updater_qemux86_64.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64.py b/lib/oeqa/selftest/cases/updater_qemux86_64.py index b711fa1..a9f1cbf 100644 --- a/lib/oeqa/selftest/cases/updater_qemux86_64.py +++ b/lib/oeqa/selftest/cases/updater_qemux86_64.py @@ -341,11 +341,6 @@ 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 service is listening') - stdout, stderr, retcode = self.qemu_command('aktualizr-check-discovery') - self.assertEqual(retcode, 0, "Unable to connect to secondary") - class PrimaryTests(OESelftestTestCase): def setUpLocal(self): -- cgit v1.2.3-54-g00ecf From 712deb76bd02b6d9fe82a91532f7eb1b441e1c19 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Tue, 23 Apr 2019 17:20:49 +0200 Subject: aktualizr: Bump to latest for recovery fixes. Signed-off-by: Patrick Vacek --- 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 77d6d22..2881712 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -33,7 +33,7 @@ SRC_URI = " \ SRC_URI[md5sum] = "c5e9968dfe78a7264ab9a8338c11725d" SRC_URI[sha256sum] = "3a19258d7a1825a308aca0da82f7a337985bec05e8951355c4c95f0fcf2444f4" -SRCREV = "9c5ef10b7b91cc7d51cd22fc60446e734cf84690" +SRCREV = "c50feb37034eceb1254429d3e3ed38e5b8a0dc60" BRANCH ?= "master" S = "${WORKDIR}/git" -- cgit v1.2.3-54-g00ecf From 33c5f3d902d6b27b56f2b9afdd0509272f7dcdda Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Mon, 29 Apr 2019 11:21:42 +0200 Subject: aktualizr: Remove aktualizr-check-discovery dependency. It no longer exists. Signed-off-by: Patrick Vacek --- recipes-sota/aktualizr/aktualizr_git.bb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 2881712..ed08d7e 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -7,8 +7,7 @@ LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=9741c346eef56131163e13b9db1241b3" DEPENDS = "boost curl openssl libarchive libsodium sqlite3 asn1c-native" DEPENDS_append = "${@bb.utils.contains('PTEST_ENABLED', '1', ' coreutils-native ostree-native aktualizr-native ', '', d)}" -RDEPENDS_${PN}_class-target = "aktualizr-check-discovery aktualizr-configs lshw" -RDEPENDS_${PN}-secondary = "aktualizr-check-discovery" +RDEPENDS_${PN}_class-target = "aktualizr-configs lshw" RDEPENDS_${PN}-host-tools = "aktualizr aktualizr-repo aktualizr-cert-provider ${@bb.utils.contains('PACKAGECONFIG', 'sota-tools', 'garage-deploy garage-push', '', d)}" RDEPENDS_${PN}-ptest += "bash cmake curl python3-modules openssl-bin sqlite3 valgrind" -- cgit v1.2.3-54-g00ecf From bd0753b89d8495109659218d77cd2ac100820e20 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Tue, 30 Apr 2019 16:04:35 +0200 Subject: selftest: retry aktualizr failure check due to resource constraints. For some reason it now often fails if you don't briefly pause first, so just retry it if it fails a few times. Signed-off-by: Patrick Vacek --- lib/oeqa/selftest/cases/updater_qemux86_64.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64.py b/lib/oeqa/selftest/cases/updater_qemux86_64.py index a9f1cbf..bad7a87 100644 --- a/lib/oeqa/selftest/cases/updater_qemux86_64.py +++ b/lib/oeqa/selftest/cases/updater_qemux86_64.py @@ -408,11 +408,18 @@ class ResourceControlTests(OESelftestTestCase): def test_aktualizr_resource_control(self): print('Checking aktualizr was killed') - stdout, stderr, retcode = self.qemu_command('systemctl --no-pager show aktualizr') + ran_ok = False + for delay in [5, 5, 5, 5]: + sleep(delay) + stdout, stderr, retcode = self.qemu_command('systemctl --no-pager show aktualizr') + if retcode == 0 and b'ExecMainStatus=9' in stdout: + ran_ok = True + break + self.assertTrue(ran_ok, 'Aktualizr was not killed') + self.assertIn(b'CPUWeight=1000', stdout, 'CPUWeight was not set correctly') self.assertIn(b'MemoryHigh=52428800', stdout, 'MemoryHigh was not set correctly') self.assertIn(b'MemoryMax=1048576', stdout, 'MemoryMax was not set correctly') - self.assertIn(b'ExecMainStatus=9', stdout, 'Aktualizr was not killed') self.qemu_command('systemctl --runtime set-property aktualizr MemoryMax=') self.qemu_command('systemctl restart aktualizr') -- cgit v1.2.3-54-g00ecf From 0ac9924bf8b7e9ea4bcc054c1d0491149a0bb467 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Mon, 29 Apr 2019 14:43:21 +0200 Subject: aktualizr: do not require openssl-bin. Signed-off-by: Patrick Vacek --- 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 ed08d7e..e85a8cd 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -10,7 +10,7 @@ DEPENDS_append = "${@bb.utils.contains('PTEST_ENABLED', '1', ' coreutils-native RDEPENDS_${PN}_class-target = "aktualizr-configs lshw" RDEPENDS_${PN}-host-tools = "aktualizr aktualizr-repo aktualizr-cert-provider ${@bb.utils.contains('PACKAGECONFIG', 'sota-tools', 'garage-deploy garage-push', '', d)}" -RDEPENDS_${PN}-ptest += "bash cmake curl python3-modules openssl-bin sqlite3 valgrind" +RDEPENDS_${PN}-ptest += "bash cmake curl python3-modules sqlite3 valgrind" PV = "1.0+git${SRCPV}" PR = "7" -- cgit v1.2.3-54-g00ecf From 04eb26b60435a65cbd2918defcd861aa45bc7f74 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Mon, 29 Apr 2019 14:44:37 +0200 Subject: aktualizr: fix cmake compilation for ptest. The cmake recipe in rocko doesn't support the build function that later release branches use, and by default it just compiles the default target (instead of 'all'). This fix will compile everything the same way as is done in the later release branches, but we have to be much more explicit about it. Signed-off-by: Patrick Vacek --- 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 e85a8cd..6cdb27b 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -72,7 +72,8 @@ RESOURCE_MEMORY_HIGH = "100M" RESOURCE_MEMORY_MAX = "80%" do_compile_ptest() { - cmake_runcmake_build --target build_tests "${PARALLEL_MAKE}" + bbnote VERBOSE=1 cmake --build '${B}' --target build_tests -- ${EXTRA_OECMAKE_BUILD} ${PARALLEL_MAKE} + VERBOSE=1 cmake --build '${B}' --target build_tests -- ${EXTRA_OECMAKE_BUILD} ${PARALLEL_MAKE} } do_install_ptest() { -- cgit v1.2.3-54-g00ecf From 1266f5b5aa28952b9738456d8f61f1bd35cedaa7 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 7 May 2019 16:14:03 +0200 Subject: More robust aktualizr-ptest printing of errors If ctest is interrupted (e.g. timeout), its partial output will be in /tmp/aktualizr-ptest.log.tmp Signed-off-by: Laurent Bonnans --- lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py b/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py index a04032c..8783fe0 100644 --- a/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py +++ b/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py @@ -41,12 +41,12 @@ class PtestTests(OESelftestTestCase): stdout, stderr, retcode = self.qemu_command('sh -l -c ptest-runner', timeout=None) output = stdout.decode() print(output) - self.assertEqual(retcode, 0) has_failure = re.search('^FAIL', output, flags=re.MULTILINE) is not None if has_failure: print("Full test suite log:") - stdout, stderr, retcode = self.qemu_command('cat /tmp/aktualizr-ptest.log', timeout=None) + stdout, _, _ = self.qemu_command('sh -c "cat /tmp/aktualizr-ptest.log || cat /tmp/aktualizr-ptest.log.tmp"', timeout=None) print(stdout.decode()) + self.assertEqual(retcode, 0) self.assertFalse(has_failure) -- cgit v1.2.3-54-g00ecf From 23d297ede1230861da1c7caecf5ca682e07c7093 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Tue, 7 May 2019 17:13:51 +0200 Subject: Make aktualizr-ptest depend on python3-misc Some of our tests use pathlib which ends up in there... Signed-off-by: Laurent Bonnans --- 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 6cdb27b..a49095a 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -10,7 +10,7 @@ DEPENDS_append = "${@bb.utils.contains('PTEST_ENABLED', '1', ' coreutils-native RDEPENDS_${PN}_class-target = "aktualizr-configs lshw" RDEPENDS_${PN}-host-tools = "aktualizr aktualizr-repo aktualizr-cert-provider ${@bb.utils.contains('PACKAGECONFIG', 'sota-tools', 'garage-deploy garage-push', '', d)}" -RDEPENDS_${PN}-ptest += "bash cmake curl python3-modules sqlite3 valgrind" +RDEPENDS_${PN}-ptest += "bash cmake curl python3-misc python3-modules sqlite3 valgrind" PV = "1.0+git${SRCPV}" PR = "7" -- cgit v1.2.3-54-g00ecf From 96c83784087f145c7cada80cbbba16681a887c31 Mon Sep 17 00:00:00 2001 From: Laurent Bonnans Date: Wed, 8 May 2019 10:56:04 +0200 Subject: Fix bad ptest printing of failures Signed-off-by: Laurent Bonnans --- lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py b/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py index 8783fe0..0f0f491 100644 --- a/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py +++ b/lib/oeqa/selftest/cases/updater_qemux86_64_ptest.py @@ -45,7 +45,7 @@ class PtestTests(OESelftestTestCase): has_failure = re.search('^FAIL', output, flags=re.MULTILINE) is not None if has_failure: print("Full test suite log:") - stdout, _, _ = self.qemu_command('sh -c "cat /tmp/aktualizr-ptest.log || cat /tmp/aktualizr-ptest.log.tmp"', timeout=None) + stdout, _, _ = self.qemu_command('cat /tmp/aktualizr-ptest.log || cat /tmp/aktualizr-ptest.log.tmp', timeout=None) print(stdout.decode()) self.assertEqual(retcode, 0) -- cgit v1.2.3-54-g00ecf From 99992959999ce9f6ad5fdae5a96262a5e0e59b5e Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Fri, 17 May 2019 10:32:21 +0200 Subject: Mention oe-selftest usage of ptest. Despite that it is not fully supported in rocko/sumo because of valgrind/openssl and timeout issues. Signed-off-by: Patrick Vacek --- README.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.adoc b/README.adoc index 1aab7dc..01f1c85 100644 --- a/README.adoc +++ b/README.adoc @@ -242,6 +242,8 @@ Be aware that it will add several hundreds of MB to the generated file system. The aktualizr tests will now be part of the deployed ptest suite, which can be run by calling `ptest-runner`. Alternatively, the required files and run script can be found in `/usr/lib/aktualizr/ptest`. +The aktualizr ptests can be run via oe-selftest with `oe-selftest -r updater_qemux86_64_ptest`, but in the rocko and sumo branches, this is not fully supported due to valgrind issues with openssl 1.0.2 and issues with ptest timing out. + == Manual provisoning As described in <> section you can set `SOTA_DEPLOY_CREDENTIALS` to `0` to prevent deploying credentials to the built `wic` image. In this case you get a generic image that you can use e.g. on a production line to flash a series of devices. The cost of this approach is that this image is half-baked and should be provisioned before it can connect to the backend. -- cgit v1.2.3-54-g00ecf