From bbce1809a921e627678947e9585ea15223b181d9 Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Wed, 14 Mar 2018 11:44:26 +0100 Subject: Add secondary-image to meta-updater This required splitting the aktualizr package into several components, in order to be able to either install the primary 'aktualzr' or the secondary 'aktualizr-secondary'. --- README.adoc | 4 +-- lib/oeqa/selftest/cases/updater.py | 45 +++++++++++++++++++++++++++++++-- recipes-sota/aktualizr/aktualizr_git.bb | 42 +++++++++++++++++------------- recipes-test/images/secondary-image.bb | 18 +++++++++++++ 4 files changed, 87 insertions(+), 22 deletions(-) create mode 100644 recipes-test/images/secondary-image.bb diff --git a/README.adoc b/README.adoc index 3562f52..980fa81 100644 --- a/README.adoc +++ b/README.adoc @@ -80,8 +80,8 @@ Although we have used U-Boot so far, other boot loaders can be configured work w * `OSTREE_INITRAMFS_IMAGE` - initramfs/initrd image that is used as a proxy while booting into OSTree deployment. Do not change this setting unless you are sure that your initramfs can serve as such a proxy. * `SOTA_PACKED_CREDENTIALS` - when set, your ostree commit will be pushed to a remote repo as a bitbake step. This should be the path to a zipped credentials file in https://github.com/advancedtelematic/aktualizr/blob/master/docs/credentials.adoc[the format accepted by garage-push]. * `SOTA_CLIENT_PROV` - which provisioning method to use. Valid options are https://github.com/advancedtelematic/aktualizr/blob/master/docs/automatic-provisioning.adoc[`aktualizr-auto-prov`], https://github.com/advancedtelematic/aktualizr/blob/master/docs/implicit-provisioning.adoc[`aktualizr-implicit-prov`], and `aktualizr-hsm-prov`. The default is `aktualizr-auto-prov`. This can also be set to an empty string to avoid using a provisioning recipe. -* `SOTA_CLIENT_FEATURES` - extensions to aktualizr. Multiple can be specified if separated by spaces. Valid options are `hsm` (to build with HSM support) and `secondary-example` (to install an example https://github.com/advancedtelematic/aktualizr/blob/master/docs/legacysecondary.adoc[legacy secondary interface] in the image). -* `SOTA_LEGACY_SECONDARY_INTERFACE` - path to a legacy secondary interface installed on the device. To use the example interface from the Aktualizr repo, use `/usr/bin/example-interface` and make sure `SOTA_CLIENT_FEATURES = "secondary-example"`. +* `SOTA_CLIENT_FEATURES` - extensions to aktualizr. The only valid option is `hsm` (to build with HSM support) +* `SOTA_LEGACY_SECONDARY_INTERFACE` - path to a https://github.com/advancedtelematic/aktualizr/blob/master/docs/legacysecondary.adoc[legacy secondary interface] installed on the device. To use the example interface from the Aktualizr repo, use `/usr/bin/example-interface` and make sure `IMAGE_INSTALL_append` includes `aktualizr-examples`. * `SOTA_SECONDARY_ECUS` - a list of paths separated by spaces of JSON configuration files for virtual secondaries on the host. These will be installed into `/var/sota/ecus` on the device. * `SOTA_VIRTUAL_SECONDARIES` - a list of paths separated by spaces of JSON configuration files for virtual secondaries installed on the device. If `SOTA_SECONDARY_ECUS` is used to install them, then you can expect them to be installed in `/var/sota/ecus`. diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index adb4061..a5072e8 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -504,14 +504,55 @@ class HsmTests(OESelftestTestCase): verifyProvisioned(self, machine) +class SecondaryTests(OESelftestTestCase): + @classmethod + def setUpClass(cls): + super(SecondaryTests, cls).setUpClass() + logger = logging.getLogger("selftest") + logger.info('Running bitbake to build secondary-image') + bitbake('secondary-image') + + def setUpLocal(self): + layer = "meta-updater-qemux86-64" + result = runCmd('bitbake-layers show-layers') + if re.search(layer, result.output) is None: + # Assume the directory layout for finding other layers. We could also + # make assumptions by using 'show-layers', but either way, if the + # layers we need aren't where we expect them, we are out of like. + path = os.path.abspath(os.path.dirname(__file__)) + metadir = path + "/../../../../../" + self.meta_qemu = metadir + layer + runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu) + else: + self.meta_qemu = None + self.append_config('MACHINE = "qemux86-64"') + self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') + self.qemu, self.s = qemu_launch(machine='qemux86-64', imagename='secondary-image') + + def tearDownLocal(self): + qemu_terminate(self.s) + if self.meta_qemu: + runCmd('bitbake-layers remove-layer "%s"' % self.meta_qemu, ignore_status=True) + + def qemu_command(self, command): + return qemu_send_command(self.qemu.ssh_port, command) + + def test_secondary_present(self): + print('Checking aktualizr-secondary is present') + stdout, stderr, retcode = self.qemu_command('aktualizr-secondary --help') + self.assertEqual(retcode, 0, "Unable to run aktualizr-secondary --help") + self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) -def qemu_launch(efi=False, machine=None): +def qemu_launch(efi=False, machine=None, imagename=None): logger = logging.getLogger("selftest") logger.info('Running bitbake to build core-image-minimal') bitbake('core-image-minimal') # Create empty object. args = type('', (), {})() - args.imagename = 'core-image-minimal' + if imagename: + args.imagename = imagename + else: + args.imagename = 'core-image-minimal' args.mac = None # Could use DEPLOY_DIR_IMAGE here but it's already in the machine # subdirectory. diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 4c4e975..ad06339 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -20,7 +20,7 @@ SRC_URI = " \ file://aktualizr.service \ file://aktualizr-serialcan.service \ " -SRCREV = "1a6432175b9fb7326173e8db35d326cc1a1011a1" +SRCREV = "dca6271f4ec06eb2272cc99b4b9cf76a9805f18d" BRANCH ?= "master" S = "${WORKDIR}/git" @@ -34,27 +34,19 @@ BBCLASSEXTEND =+ "native" EXTRA_OECMAKE = "-DWARNING_AS_ERROR=OFF -DCMAKE_BUILD_TYPE=Release -DAKTUALIZR_VERSION=${PV} " EXTRA_OECMAKE_append_class-target = " -DBUILD_OSTREE=ON -DBUILD_ISOTP=ON ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'hsm', '-DBUILD_P11=ON', '', d)} " -EXTRA_OECMAKE_append_class-native = " -DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF " +EXTRA_OECMAKE_append_class-native = " -DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF -DBUILD_SYSTEMD=OFF " do_install_append () { rm -fr ${D}${libdir}/systemd + rm -f ${D}${libdir}/sota/sota.toml # Only needed for the Debian package } do_install_append_class-target () { - rm -f ${D}${bindir}/aktualizr_cert_provider - rm -f ${D}${bindir}/aktualizr_implicit_writer - rm -f ${D}${libdir}/sota/sota.toml - ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-example', '', 'rm -f ${D}${bindir}/example-interface', d)} - ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-isotp-example', '', 'rm -f ${D}${bindir}/isotp-test-interface', d)} - install -d ${D}${systemd_unitdir}/system aktualizr_service=${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'serialcan', '${WORKDIR}/aktualizr-serialcan.service', '${WORKDIR}/aktualizr.service', d)} install -m 0644 ${aktualizr_service} ${D}${systemd_unitdir}/system/aktualizr.service } do_install_append_class-native () { - rm -f ${D}${bindir}/aktualizr - rm -f ${D}${bindir}/aktualizr-info - rm -f ${D}${bindir}/example-interface install -d ${D}${libdir}/sota install -m 0644 ${S}/config/sota_autoprov.toml ${D}/${libdir}/sota/sota_autoprov.toml install -m 0644 ${S}/config/sota_hsm_prov.toml ${D}/${libdir}/sota/sota_hsm_prov.toml @@ -65,23 +57,37 @@ do_install_append_class-native () { install -m 0644 ${B}/src/sota_tools/garage-sign-prefix/src/garage-sign/lib/* ${D}${libdir} } -FILES_${PN}_append = " \ - ${libdir}/sota \ - " +PACKAGES =+ " ${PN}-common ${PN}-examples ${PN}-host-tools ${PN}-secondary " -FILES_${PN}_class-target = " \ +FILES_${PN} = " \ ${bindir}/aktualizr \ ${bindir}/aktualizr-info \ ${systemd_unitdir}/system/aktualizr.service \ " -FILES_${PN}_append_class-target = " ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-example', ' ${bindir}/example-interface', '', d)} " -FILES_${PN}_append_class-target = " ${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'secondary-isotp-example', ' ${bindir}/isotp-test-interface', '', d)} " -FILES_${PN}_class-native = " \ +FILES_${PN}-common = " \ + ${libdir}/sota/schemas \ + " + +FILES_${PN}-examples = " \ + ${libdir}/sota/demo_secondary.json \ + ${bindir}/example-interface \ + ${bindir}/isotp-test-interface \ + " + +FILES_${PN}-host-tools = " \ ${bindir}/aktualizr_cert_provider \ ${bindir}/aktualizr_implicit_writer \ ${bindir}/garage-deploy \ ${bindir}/garage-push \ " +FILES_${PN}-secondary = " \ + ${bindir}/aktualizr-secondary \ + " + +# Both primary and secondary need the SQL Schemas +RDEPENDS_${PN}_class-target =+ "${PN}-common" +RDEPENDS_${PN}-secondary_class-target =+ "${PN}-common" + # vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/recipes-test/images/secondary-image.bb b/recipes-test/images/secondary-image.bb new file mode 100644 index 0000000..c7a91db --- /dev/null +++ b/recipes-test/images/secondary-image.bb @@ -0,0 +1,18 @@ +include recipes-core/images/core-image-minimal.bb + +SUMMARY = "A minimal Uptane Secondary image running aktualizr-secondary" + +LICENSE = "MIT" + + +# Remove default aktualizr primary, and the provisioning configuration (which +# RDEPENDS on aktualizr) +IMAGE_INSTALL_remove = " \ + aktualizr \ + aktualizr-auto-prov \ + aktualizr-ca-implicit-prov \ + aktualizr-hsm-prov \ + aktualizr-implicit-prov \ + " + +IMAGE_INSTALL_append = " aktualizr-secondary " \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 66a4721d0b7885a18db952d69f7ee385a95b2f2b Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Wed, 14 Mar 2018 16:00:53 +0100 Subject: Add systemd socket activation for secondary --- lib/oeqa/selftest/cases/updater.py | 5 +++++ recipes-sota/aktualizr/aktualizr_git.bb | 15 ++++++++++++++- recipes-sota/aktualizr/files/aktualizr-secondary.service | 9 +++++++++ recipes-sota/aktualizr/files/aktualizr-secondary.socket | 5 +++++ 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 recipes-sota/aktualizr/files/aktualizr-secondary.service create mode 100644 recipes-sota/aktualizr/files/aktualizr-secondary.socket diff --git a/lib/oeqa/selftest/cases/updater.py b/lib/oeqa/selftest/cases/updater.py index a5072e8..1850d98 100644 --- a/lib/oeqa/selftest/cases/updater.py +++ b/lib/oeqa/selftest/cases/updater.py @@ -543,6 +543,11 @@ class SecondaryTests(OESelftestTestCase): self.assertEqual(retcode, 0, "Unable to run aktualizr-secondary --help") self.assertEqual(stderr, b'', 'Error: ' + stderr.decode()) + def test_secondary_listening(self): + print('Checking aktualizr-secondary is present') + stdout, stderr, retcode = self.qemu_command('echo test | nc localhost 9030') + self.assertEqual(retcode, 0, "Unable to connect to secondary") + def qemu_launch(efi=False, machine=None, imagename=None): logger = logging.getLogger("selftest") logger.info('Running bitbake to build core-image-minimal') diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index ad06339..5e683ac 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb @@ -18,9 +18,11 @@ PR = "7" SRC_URI = " \ gitsm://github.com/advancedtelematic/aktualizr;branch=${BRANCH} \ file://aktualizr.service \ + file://aktualizr-secondary.service \ + file://aktualizr-secondary.socket \ file://aktualizr-serialcan.service \ " -SRCREV = "dca6271f4ec06eb2272cc99b4b9cf76a9805f18d" +SRCREV = "fbb3404824c4eb239455c7fa1a794c26e2ea954d" BRANCH ?= "master" S = "${WORKDIR}/git" @@ -28,7 +30,10 @@ S = "${WORKDIR}/git" inherit cmake inherit systemd + +SYSTEMD_PACKAGES = "${PN} ${PN}-secondary" SYSTEMD_SERVICE_${PN} = "aktualizr.service" +SYSTEMD_SERVICE_${PN}-secondary = "aktualizr-secondary.socket" BBCLASSEXTEND =+ "native" @@ -39,6 +44,11 @@ EXTRA_OECMAKE_append_class-native = " -DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF - do_install_append () { rm -fr ${D}${libdir}/systemd rm -f ${D}${libdir}/sota/sota.toml # Only needed for the Debian package + install -d ${D}${libdir}/sota + install -m 0644 ${S}/config/sota_secondary.toml ${D}/${libdir}/sota/sota_secondary.toml + install -d ${D}${systemd_unitdir}/system + install -m 0644 ${WORKDIR}/aktualizr-secondary.socket ${D}${systemd_unitdir}/system/aktualizr-secondary.socket + install -m 0644 ${WORKDIR}/aktualizr-secondary.service ${D}${systemd_unitdir}/system/aktualizr-secondary.service } do_install_append_class-target () { install -d ${D}${systemd_unitdir}/system @@ -84,6 +94,9 @@ FILES_${PN}-host-tools = " \ FILES_${PN}-secondary = " \ ${bindir}/aktualizr-secondary \ + ${libdir}/sota/sota_secondary.toml \ + ${systemd_unitdir}/system/aktualizr-secondary.socket \ + ${systemd_unitdir}/system/aktualizr-secondary.service \ " # Both primary and secondary need the SQL Schemas diff --git a/recipes-sota/aktualizr/files/aktualizr-secondary.service b/recipes-sota/aktualizr/files/aktualizr-secondary.service new file mode 100644 index 0000000..a1e0e1b --- /dev/null +++ b/recipes-sota/aktualizr/files/aktualizr-secondary.service @@ -0,0 +1,9 @@ +[Unit] +Description=Aktualizr SOTA Client (UPTANE Secondary) + +[Service] +RestartSec=10 +Restart=always +EnvironmentFile=-/etc/sota/sota.env +ExecStart=/usr/bin/aktualizr-secondary --config /usr/lib/sota/sota_secondary.toml + diff --git a/recipes-sota/aktualizr/files/aktualizr-secondary.socket b/recipes-sota/aktualizr/files/aktualizr-secondary.socket new file mode 100644 index 0000000..1cb4269 --- /dev/null +++ b/recipes-sota/aktualizr/files/aktualizr-secondary.socket @@ -0,0 +1,5 @@ +[Socket] +ListenStream=9030 + +[Install] +WantedBy=sockets.target \ No newline at end of file -- cgit v1.2.3-54-g00ecf