From 464e6e725d9739d0982dd04356a80a48e0aa4620 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 5b9aa5dc203f8ad4d67b7259bf02d37f06e2c457 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 a8f40d6..9a51681 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}" -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 c4855e5d6ed4778227444dcae1c03f0abb71c399 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 6b63af4..9bbd5c2 100644 --- a/classes/sota_m3ulcb.bbclass +++ b/classes/sota_m3ulcb.bbclass @@ -6,3 +6,5 @@ IMAGE_BOOT_FILES_sota += "m3ulcb-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 26d2a79bc74deacdc7d92206245538998caa1fa5 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 65e82c7b0cbcaf543c380082fcc2d172b7d0fb34 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 9bbd5c2..b93cc40 100644 --- a/classes/sota_m3ulcb.bbclass +++ b/classes/sota_m3ulcb.bbclass @@ -7,4 +7,5 @@ IMAGE_BOOT_FILES_sota += "m3ulcb-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 578a50086b99f8dfd3093094d216e58e60d7d1f1 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 5df4fa5596cdf3019f72e72934b32a48222211d2 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 b78e63f136aaa20f749bd1f81e776808a72af6bb 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 f5c5ac3e444b765bfcd48b1a6d2b63ef7aec54aa 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 9a51681..3c029d6 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 cf436b1582bf970bcebe901ecc791b9c6881d4c0 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 66071a177f1b08036fea69e63a5e6dfbe3a2cd6d 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 3c029d6..0cba9db 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 938d2b556a51148039521be825e604bb6f957d30 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 0cba9db..21271f8 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 4864f5913baccb567e768f647b41f58974283532 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 21271f8..f591c44 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}" +EXTRA_OECMAKE = "-DCMAKE_BUILD_TYPE=Release -DAKTUALIZR_VERSION=${PV} ${@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 5355f6882de1e07fbbf349c43ae2338a66314223 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 f591c44..62e3652 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 978d8d4c96a1277e69dd183cc9c74d0d3ce06058 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 62e3652..1754915 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 37a4ffee25eaf88cfeba9aa965b7e9b93952c3c0 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 2dc4ee2bb29ae9e46fc571daa29053ecef9ad0d3 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 008ba4b..bf2a737 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 bc184b1f4bb4c4bfecf68fd86edcc6a919c2d690 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 94bdba9397f63db917cc5b234e366ed7158920b4 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 1754915..5a3f304 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 736add8df3435b26afb45d6f625952a49a6eca38 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 | 4 +++- 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(+), 2 deletions(-) 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 f506cab..585fe71 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 7947edd..465b280 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 305b5e5..d962876 100644 --- a/recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb +++ b/recipes-sota/aktualizr/aktualizr-uboot-env-rollback.bb @@ -3,12 +3,14 @@ HOMEPAGE = "https://github.com/advancedtelematic/aktualizr" 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" SRC_URI = "" - do_install() { install -m 0700 -d ${D}${libdir}/sota/conf.d install -m 0644 ${STAGING_DIR_NATIVE}${libdir}/sota/sota_uboot_env.toml ${D}${libdir}/sota/conf.d/30-rollback.toml diff --git a/recipes-sota/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 552b0c69a4cae1a6d34655479adb0b150535b83d 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 5a3f304..99cb415 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 810fcdb167fc77309cc24c0ffb7786368dad5a57 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 15964bd366153a114b528411b7273d3876cbf896 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 bf2a737..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 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 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_HOST', 'libdir'], 'aktualizr-hsm-prov') - config = bb_vars_prov['STAGING_DIR_HOST'] + 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..9310841 --- /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_HOST', 'libdir'], 'aktualizr-hsm-prov') + config = bb_vars_prov['STAGING_DIR_HOST'] + 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..785d703 --- /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 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) + +# vim:set ts=4 sw=4 sts=4 expandtab: -- cgit v1.2.3-54-g00ecf From fb7662cf132302d029ac56a4a10e0d559d1cbeb7 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 9310841..08afbe6 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 6bf2c5bba9fd0216c6a8a341ddc4afc793d4f93d 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 08afbe6..0fac159 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 aad4f89a9f46a49fe99472207bc5be73c26f833a 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 2414cef43405698030db413821f76aef818219e0 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 0fac159..bef6cdc 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 743dd703312e5cebfbb4a48b18f84923ed7eac41 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 4ee4191..9799a0a 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 7c4e0f3720db92ed1190a403be097053100a531e 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 df697602f1c00a89e58588ea3b4d79306d9ea70b 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 4f4a0618070aab078b60789eede5caf408252f74 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 99cb415..e844893 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 9a09ca0dbe25c370e58ba2dd4cc20a4ee8b3fb28 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 24fbe083cef7a5b22d8f04ad06cfad523ced1517 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 e844893..675e9d4 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 604c1c908df346b05f0066205621633a2b14aad3 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 675e9d4..64382d8 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 08597f5df0c94020952b0016d7cb4e19135703d6 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 bef6cdc..c928093 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 12a4057aecd9f9d24b05907b42fa2b7fc95c9e46 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 64382d8..8928736 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 288ed5a90a8936ffeaad3821f0213a90ac9dd59d 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 8928736..c0e275d 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 4a2e5a6cb0e5e49229a9d34b80d512359729edb1 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 c928093..9f32bcf 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 0c71b9595bbc48d91a57fdb0d771c7bdc88fc67d 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 c0e275d..f7e9626 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 776dd1df3cf8f147a4848d7bb909eb8b8dbdcb9d Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Mon, 29 Apr 2019 14:44:37 +0200 Subject: aktualizr: fix syntax for make parallelization. Older release branches apparently require the -- to indicate flags passed from cmake to make. Newer branches apparently understand the intention with it. 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 f7e9626..1ee0457 100755 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -72,7 +72,7 @@ RESOURCE_MEMORY_HIGH = "100M" RESOURCE_MEMORY_MAX = "80%" do_compile_ptest() { - cmake_runcmake_build --target build_tests "${PARALLEL_MAKE}" + cmake_runcmake_build --target build_tests "-- ${PARALLEL_MAKE}" } do_install_ptest() { -- cgit v1.2.3-54-g00ecf From fbf974efd9b8b915b47e8dbfedb4a304afc8032f 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 4f3513c3a38172a95127f148d03c676e6de4020b 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 1ee0457..3759c39 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 613e64e3d0b2776be1ecec8019b6233229eb554d 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 64733cc59737ad606f42874c5a825df1e2b3b1ff 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