recipes-azure-device-update/azure-device-update/azure-device-update_git.bb (221 lines of code) (raw):
# Build and install our ADU sample code.
# Environment variables that can be used to configure the behavior of this recipe.
# ADUC_GIT_URL Changes the URL of github repository that ADU code is pulled from.
# Default: git://github.com/Azure/iot-hub-device-update
#
# ADUC_GIT_BRANCH Changes the branch that ADU code is pulled from.
# Default: develop
#
# ADU_GIT_COMMIT Changes to the commit from which to checkout the adu code.
#
# BUILD_TYPE Changes the type of build produced by this recipe.
# Valid values are Debug, Release, RelWithDebInfo, and MinRelSize.
# These values are the same as the CMAKE_BUILD_TYPE variable.
LICENSE = "CLOSED"
ADU_GIT_BRANCH ?= "develop"
ADU_SRC_URI ?= "git://github.com/Azure/iot-hub-device-update"
SRC_URI = "${ADU_SRC_URI};protocol=https;branch=${ADU_GIT_BRANCH}"
ADU_GIT_COMMIT ?= "60bb98ae3631419b393c528f7dc3cf0797b231e6"
SRCREV = "${ADU_GIT_COMMIT}"
PV = "1.0+git${SRCPV}"
S = "${WORKDIR}/git"
# ADUC depends on azure-iot-sdk-c, azure-sdk-for-cpp DO Agent SDK, and curl
DEPENDS = "azure-iot-sdk-c azure-sdk-for-cpp deliveryoptimization-agent deliveryoptimization-sdk curl"
inherit cmake useradd
#OpenSSL3.0 is not supported in all branches
# -- Ignore warnings for now...
TARGET_CFLAGS:append = " -Wno-error=deprecated-declarations"
TARGET_CPPFLAGS:append = " -Wno-error=deprecated-declarations"
TARGET_CXXFLAGS:append = " -Wno-error=deprecated-declarations"
BUILD_TYPE ?= "Debug"
EXTRA_OECMAKE += "-DCMAKE_BUILD_TYPE=${BUILD_TYPE}"
# Don't treat warnings as errors.
EXTRA_OECMAKE += "-DADUC_WARNINGS_AS_ERRORS=OFF"
# Build the non-simulator (real) version of the client.
EXTRA_OECMAKE += "-DADUC_PLATFORM_LAYER=linux"
# Integrate with SWUpdate as the installer
EXTRA_OECMAKE += "-DADUC_CONTENT_HANDLERS=microsoft/swupdate"
# Set the path to the manufacturer file
EXTRA_OECMAKE += "-DADUC_MANUFACTURER_FILE=${sysconfdir}/adu-manufacturer"
# Set the path to the model file
EXTRA_OECMAKE += "-DADUC_MODEL_FILE=${sysconfdir}/adu-model"
# Set the path to the version file
EXTRA_OECMAKE += "-DADUC_VERSION_FILE=${sysconfdir}/adu-version"
# Use zlog as the logging library.
EXTRA_OECMAKE += "-DADUC_LOGGING_LIBRARY=zlog"
# Change the log directory.
EXTRA_OECMAKE += "-DADUC_LOG_FOLDER=/adu/logs"
# Use /adu directory for configuration.
# The /adu directory is on a seperate partition and is not updated during an OTA update.
EXTRA_OECMAKE += "-DADUC_CONF_FOLDER=/adu"
# Don't install/configure the daemon, another bitbake recipe will do that.
EXTRA_OECMAKE += "-DADUC_INSTALL_DAEMON=OFF"
# cpprest installs its config.cmake file in a non-standard location.
# Tell cmake where to find it.
EXTRA_OECMAKE += "-Dcpprestsdk_DIR=${WORKDIR}/recipe-sysroot/usr/lib/cmake"
# Using the installed DO SDK include files.
EXTRA_OECMAKE += "-DDOSDK_INCLUDE_DIR=${WORKDIR}/recipe-sysroot/usr/include"
EXTRA_OECMAKE += "-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"
# bash - for running shell scripts for install.
# swupdate - to install update package.
# adu-pub-key - to install public key for update package verification.
# adu-log-dir - to create the temporary log directory in the image.
# deliveryoptimization-agent-service - to install the delivery optimization agent for downloads.
# curl - for running the diagnostics component
RDEPENDS:${PN} += "bash swupdate adu-pub-key adu-log-dir deliveryoptimization-agent-service azure-device-update-diffs curl openssl-bin nss ca-certificates"
ADUC_DATA_DIR ?= "/var/lib/adu"
ADUC_EXTENSIONS_DIR ?= "${ADUC_DATA_DIR}/extensions"
ADUC_EXTENSIONS_INSTALL_DIR ?= "${ADUC_EXTENSIONS_DIR}/sources"
ADUC_COMPONENT_ENUMERATOR_EXTENSION_DIR ?= "${ADUC_EXTENSIONS_DIR}/component_enumerator"
ADUC_CONTENT_DOWNLOADER_EXTENSION_DIR ?= "${ADUC_EXTENSIONS_DIR}/content_downloader"
ADUC_UPDATE_CONTENT_HANDLER_EXTENSION_DIR ?= "${ADUC_EXTENSIONS_DIR}/update_content_handlers"
ADUC_DOWNLOAD_HANDLER_EXTENSION_DIR ?= "${ADUC_EXTENSIONS_DIR}/download_handlers"
ADUC_DOWNLOADS_DIR ?= "${ADUC_DATA_DIR}/downloads"
ADUC_DOWNLOADS_FOLDER ?= "${ADUC_DOWNLOADS_DIR}"
ADUC_LOG_DIR ?= "/adu/logs"
ADUC_CONF_DIR ?= "/adu"
ADUUSER = "adu"
ADUGROUP = "adu"
DOUSER = "do"
DOGROUP = "do"
USERADD_PACKAGES = "${PN}"
GROUPADD_PARAM:${PN} = "\
--gid 800 --system adu ; \
--gid 801 --system do ; \
"
# USERADD_PARAM specifies command line options to pass to the
# useradd command. Multiple users can be created by separating
# the commands with a semicolon.
# Here we'll create 'adu' user, and 'do' user.
# To download the update payload file, 'adu' user must be a member of 'do' group.
# To save downloaded file into 'adu' downloads directory, 'do' user must be a member of 'adu' group.
USERADD_PARAM:${PN} = "\
--uid 800 --system -g ${ADUGROUP} -G ${DOGROUP} --no-create-home --shell /bin/false ${ADUUSER} ; \
--uid 801 --system -g ${DOGROUP} -G ${ADUGROUP} --no-create-home --shell /bin/false ${DOUSER} ; \
"
do_compile[depends] += "azure-iot-sdk-c:do_prepare_recipe_sysroot"
do_compile[depends] += "azure-sdk-for-cpp:do_prepare_recipe_sysroot"
do_install:append() {
#create ADUC_DATA_DIR
install -d ${D}${ADUC_DATA_DIR}
chgrp ${ADUGROUP} ${D}${ADUC_DATA_DIR}
chown ${ADUUSER}:${ADUGROUP} ${D}${ADUC_DATA_DIR}
chmod 0770 ${D}${ADUC_DATA_DIR}
#create ADUC_EXTENSIONS_DIR
install -d ${D}${ADUC_EXTENSIONS_DIR}
chgrp ${ADUGROUP} ${D}${ADUC_EXTENSIONS_DIR}
chmod 0770 ${D}${ADUC_EXTENSIONS_DIR}
#create ADUC_EXTENSIONS_INSTALL_DIR
install -d ${D}${ADUC_EXTENSIONS_INSTALL_DIR}
chgrp ${ADUGROUP} ${D}${ADUC_EXTENSIONS_INSTALL_DIR}
chmod 0770 ${D}${ADUC_EXTENSIONS_INSTALL_DIR}
#create ADUC_COMPONENT_ENUMERATOR_EXTENSION_DIR
install -d ${D}${ADUC_COMPONENT_ENUMERATOR_EXTENSION_DIR}
chgrp ${ADUGROUP} ${D}${ADUC_COMPONENT_ENUMERATOR_EXTENSION_DIR}
chmod 0770 ${D}${ADUC_COMPONENT_ENUMERATOR_EXTENSION_DIR}
#create ADUC_CONTENT_DOWNLOADER_EXTENSION_DIR
install -d ${D}${ADUC_CONTENT_DOWNLOADER_EXTENSION_DIR}
chgrp ${ADUGROUP} ${D}${ADUC_CONTENT_DOWNLOADER_EXTENSION_DIR}
chmod 0770 ${D}${ADUC_CONTENT_DOWNLOADER_EXTENSION_DIR}
#create ADUC_UPDATE_CONTENT_HANDLER_EXTENSION_DIR
install -d ${D}${ADUC_UPDATE_CONTENT_HANDLER_EXTENSION_DIR}
chgrp ${ADUGROUP} ${D}${ADUC_UPDATE_CONTENT_HANDLER_EXTENSION_DIR}
chmod 0770 ${D}${ADUC_UPDATE_CONTENT_HANDLER_EXTENSION_DIR}
#create ADUC_DOWNLOADS_DIR
install -d ${D}${ADUC_DOWNLOADS_DIR}
chown ${ADUUSER}:${ADUGROUP} ${D}${ADUC_DOWNLOADS_DIR}
chmod 0770 ${D}${ADUC_DOWNLOADS_DIR}
#create ADUC_CONF_DIR
install -d ${D}${ADUC_CONF_DIR}
chown root:${ADUGROUP} ${D}${ADUC_CONF_DIR}
chmod 0774 ${D}${ADUC_CONF_DIR}
#create ADUC_LOG_DIR
install -d ${D}${ADUC_LOG_DIR}
chown ${ADUUSER}:${ADUGROUP} ${D}${ADUC_LOG_DIR}
chmod 0774 ${D}${ADUC_LOG_DIR}
install -m 0550 ${S}/src/adu-shell/scripts/adu-swupdate.sh ${D}${bindir}
chown ${ADUUSER}:${ADUGROUP} ${D}${bindir}/adu-swupdate.sh
#set owner for adu-shell
chmod 0550 ${D}${bindir}/adu-shell
chown root:${ADUGROUP} ${D}${bindir}/adu-shell
#set S UID for adu-shell
chmod u+s ${D}${bindir}/adu-shell
}
#We don't want the library file hashes to change between do_image -> do_package,
#otherwise the stored json hashes will be incorrect
INHIBIT_PACKAGE_STRIP = "1"
INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
#
# A helper function that registers the required agent's extensions.
#
fakeroot python do_registerAgentExtensions() {
try:
workDir = d.getVar("D")
extensionInstallDir = d.getVar("ADUC_EXTENSIONS_INSTALL_DIR")
updateContentRegistrationDirectory = d.getVar("ADUC_UPDATE_CONTENT_HANDLER_EXTENSION_DIR")
contentDownloaderRegistrationDirectory = d.getVar("ADUC_CONTENT_DOWNLOADER_EXTENSION_DIR")
downloadHandlerRegistrationDirectory = d.getVar("ADUC_DOWNLOAD_HANDLER_EXTENSION_DIR")
register_content_handler("microsoft/swupdate:2", "{}/libmicrosoft_swupdate_2.so".format(extensionInstallDir), updateContentRegistrationDirectory, workDir)
register_content_handler("microsoft/update-manifest", "{}/libmicrosoft_steps_1.so".format(extensionInstallDir), updateContentRegistrationDirectory, workDir)
register_content_handler("microsoft/update-manifest:4", "{}/libmicrosoft_steps_1.so".format(extensionInstallDir), updateContentRegistrationDirectory, workDir)
register_content_handler("microsoft/update-manifest:5", "{}/libmicrosoft_steps_1.so".format(extensionInstallDir), updateContentRegistrationDirectory, workDir)
register_content_handler("microsoft/steps:1", "{}/libmicrosoft_steps_1.so".format(extensionInstallDir), updateContentRegistrationDirectory, workDir)
register_content_handler("microsoft/script:1", "{}/libmicrosoft_script_1.so".format(extensionInstallDir), updateContentRegistrationDirectory, workDir)
register_content_downloader("{}/libdeliveryoptimization_content_downloader.so".format(extensionInstallDir), contentDownloaderRegistrationDirectory, workDir)
register_download_handler("microsoft/delta:1", "{}/libmicrosoft_delta_download_handler.so".format(extensionInstallDir), downloadHandlerRegistrationDirectory, workDir)
except Exception as ex:
errorMessage = "Failed to create DU Agent extension registration. An exception of type {0} occurred with message:\n{1} and Arguments:\n{2!r}".format(type(ex).__name__, str(ex), ex.args)
bb.error(errorMessage)
}
do_registerAgentExtensions[depends] += "virtual/fakeroot-native:do_populate_sysroot"
addtask do_registerAgentExtensions after do_install before do_package
fakeroot do_registerAgentExtensions_permissions(){
chown -R ${ADUUSER}:${ADUGROUP} ${D}${ADUC_UPDATE_CONTENT_HANDLER_EXTENSION_DIR}
}
do_registerAgentExtensions[depends] += "virtual/fakeroot-native:do_populate_sysroot"
addtask do_registerAgentExtensions_permissions after do_registerAgentExtensions before do_package
FILES:${PN} += "${bindir}/AducIotAgent"
FILES:${PN} += "${bindir}/adu-shell"
FILES:${PN} += "${bindir}/adu-swupdate.sh"
FILES:${PN} += "${ADUC_DATA_DIR}/* ${ADUC_LOG_DIR}/* ${ADUC_CONF_DIR}/*"
FILES:${PN} += "${ADUC_EXTENSIONS_DIR}/* ${ADUC_EXTENSIONS_INSTALL_DIR}/* ${ADUC_DOWNLOADS_DIR}/*"
FILES:${PN} += "${ADUC_COMPONENT_ENUMERATOR_EXTENSION_DIR}/* ${ADUC_CONTENT_DOWNLOADER_EXTENSION_DIR}/* ${ADUC_UPDATE_CONTENT_HANDLER_EXTENSION_DIR}/* ${ADUC_DOWNLOAD_HANDLER_EXTENSION_DIR}/*"
def create_handlerRegistration(handlerId, handlerFileInstallPath, handlerExtensionDir, handlerRegistrationFileName, workDir):
import hashlib
import os
import io
import base64
import json
registrationProperties = {"fileName":handlerFileInstallPath}
handlerExtensionInstallDir = "{}{}".format(workDir, handlerExtensionDir)
handlerFileWorkingPath = "{}{}".format(workDir, handlerFileInstallPath)
handlerRegistrationOutputPath = os.path.join(handlerExtensionInstallDir, handlerRegistrationFileName)
if not os.path.isfile(handlerFileWorkingPath):
raise ValueError("Cannot generate ADU handler registration, the specified path does not exist: {}".format(handlerFileWorkingPath))
# Get the file size
registrationProperties["sizeInBytes"] = os.path.getsize(handlerFileWorkingPath)
# Calculate the file hash
with open(handlerFileWorkingPath, "rb") as handler:
data = handler.read()
sha256_hash = hashlib.sha256(data)
base64Hash = base64.b64encode(sha256_hash.digest()).decode("ascii")
registrationProperties["hashes"] = {"sha256":base64Hash}
# Add the handler Id if provided
if handlerId is not None:
registrationProperties["handlerId"] = handlerId
# Create any required directories and write the registration content to the registration file
registrationContent = json.dumps(registrationProperties, indent=4)
if not os.path.exists(handlerExtensionInstallDir):
os.makedirs(handlerExtensionInstallDir)
with open(handlerRegistrationOutputPath, "w") as registration:
registration.write(registrationContent)
def register_content_handler(handlerId, handlerFileInstallPath, handlerExtensionDir, workDir):
typedDirectoryName = handlerId.replace("/", "_").replace(":", "_")
typedHandlerExtensionDir = os.path.join(handlerExtensionDir, typedDirectoryName)
create_handlerRegistration(handlerId, handlerFileInstallPath, typedHandlerExtensionDir, "content_handler.json", workDir)
def register_content_downloader(handlerFileInstallPath, handlerExtensionDir, workDir):
create_handlerRegistration(None, handlerFileInstallPath, handlerExtensionDir, "extension.json", workDir)
def register_download_handler(handlerId, handlerFileInstallPath, handlerExtensionDir, workDir):
typedDirectoryName = handlerId.replace("/", "_").replace(":", "_")
typedHandlerExtensionDir = os.path.join(handlerExtensionDir, typedDirectoryName)
create_handlerRegistration(handlerId, handlerFileInstallPath, typedHandlerExtensionDir, "download_handler.json", workDir)