summaryrefslogtreecommitdiffstats
path: root/meta-sota
diff options
context:
space:
mode:
Diffstat (limited to 'meta-sota')
-rw-r--r--meta-sota/classes/image_types_ostree.bbclass10
-rw-r--r--meta-sota/classes/image_types_ota.bbclass36
-rw-r--r--meta-sota/recipes-sota/ostree/ostree_git.bb14
-rw-r--r--meta-sota/recipes-sota/rvi-sota-client/rvi-sota-client_git.bb162
-rw-r--r--meta-sota/recipes-sota/sota-tools/sota-tools_git.bb2
-rw-r--r--meta-sota/recipes-support/python-canonicaljson/python-canonicaljson.bb18
-rw-r--r--meta-sota/recipes-support/python-frozendict/python-frozendict.bb12
7 files changed, 191 insertions, 63 deletions
diff --git a/meta-sota/classes/image_types_ostree.bbclass b/meta-sota/classes/image_types_ostree.bbclass
index 04aeae8..1bbeb2d 100644
--- a/meta-sota/classes/image_types_ostree.bbclass
+++ b/meta-sota/classes/image_types_ostree.bbclass
@@ -58,6 +58,10 @@ IMAGE_CMD_ostree () {
echo "d /var/rootdirs 0755 root root -" >>${tmpfiles_conf}
echo "L /var/rootdirs/home - - - - /sysroot/home" >>${tmpfiles_conf}
+
+ # Preserve OSTREE_BRANCHNAME for future information
+ mkdir -p usr/share/sota/
+ echo -n "${OSTREE_BRANCHNAME}" > usr/share/sota/branchname
# Preserve data in /home to be later copied to /sysroot/home by
# sysroot generating procedure
mkdir -p usr/homedirs
@@ -100,6 +104,9 @@ IMAGE_CMD_ostree () {
cp ${DEPLOY_DIR_IMAGE}/${OSTREE_KERNEL} boot/vmlinuz-${checksum}
cp ${DEPLOY_DIR_IMAGE}/${OSTREE_INITRAMFS_IMAGE}-${MACHINE}${RAMDISK_EXT} boot/initramfs-${checksum}
+ # Copy image manifest
+ cat ${IMAGE_MANIFEST} | cut -d " " -f1,3 > usr/package.manifest
+
cd ${WORKDIR}
# Create a tarball that can be then commited to OSTree repo
@@ -130,6 +137,7 @@ IMAGE_CMD_ostreepush () {
if [ ${OSTREE_PUSH_CREDENTIALS} ]; then
garage-push --repo=${OSTREE_REPO} \
--ref=${OSTREE_BRANCHNAME} \
- --credentials=${OSTREE_PUSH_CREDENTIALS}
+ --credentials=${OSTREE_PUSH_CREDENTIALS} \
+ --cacert=${STAGING_ETCDIR_NATIVE}/ssl/certs/ca-certificates.crt
fi
}
diff --git a/meta-sota/classes/image_types_ota.bbclass b/meta-sota/classes/image_types_ota.bbclass
index 253d862..58bc7f0 100644
--- a/meta-sota/classes/image_types_ota.bbclass
+++ b/meta-sota/classes/image_types_ota.bbclass
@@ -9,11 +9,9 @@
inherit image
-IMAGE_DEPENDS_otaimg = "e2fsprogs-native:do_populate_sysroot"
-
-# For qemux86 u-boot is not included in any live image and is built separately
-IMAGE_DEPENDS_otaimg_append_qemux86 = " virtual/bootloader:do_deploy"
-IMAGE_DEPENDS_otaimg_append_qemux86-64 = " virtual/bootloader:do_deploy"
+IMAGE_DEPENDS_otaimg = "e2fsprogs-native:do_populate_sysroot \
+ ${@'grub:do_populate_sysroot' if d.getVar('OSTREE_BOOTLOADER', True) == 'grub' else ''} \
+ ${@'virtual/bootloader:do_deploy' if d.getVar('OSTREE_BOOTLOADER', True) == 'u-boot' else ''}"
calculate_size () {
BASE=$1
@@ -51,6 +49,7 @@ calculate_size () {
export OSTREE_OSNAME
export OSTREE_BRANCHNAME
export OSTREE_REPO
+export OSTREE_BOOTLOADER
IMAGE_CMD_otaimg () {
if ${@bb.utils.contains('IMAGE_FSTYPES', 'otaimg', 'true', 'false', d)}; then
@@ -75,15 +74,29 @@ IMAGE_CMD_otaimg () {
mkdir -p ${PHYS_SYSROOT}/boot/loader.0
ln -s loader.0 ${PHYS_SYSROOT}/boot/loader
- touch ${PHYS_SYSROOT}/boot/loader/uEnv.txt
+ if [ "${OSTREE_BOOTLOADER}" = "grub" ]; then
+ mkdir -p ${PHYS_SYSROOT}/boot/grub2
+ touch ${PHYS_SYSROOT}/boot/grub2/grub.cfg
+ elif [ "${OSTREE_BOOTLOADER}" = "u-boot" ]; then
+ touch ${PHYS_SYSROOT}/boot/loader/uEnv.txt
+ else
+ bberror "Invalid bootloader: ${OSTREE_BOOTLOADER}"
+ fi;
ostree --repo=${PHYS_SYSROOT}/ostree/repo pull-local --remote=${OSTREE_OSNAME} ${OSTREE_REPO} ${OSTREE_BRANCHNAME}
- ostree admin --sysroot=${PHYS_SYSROOT} deploy --os=${OSTREE_OSNAME} ${OSTREE_OSNAME}:${OSTREE_BRANCHNAME}
-
- # Copy deployment /home to sysroot
+ export OSTREE_BOOT_PARTITION="/boot"
+ kargs_list=""
+ for arg in ${OSTREE_KERNEL_ARGS}; do
+ kargs_list="${kargs_list} --karg-append=$arg"
+ done
+
+ ostree admin --sysroot=${PHYS_SYSROOT} deploy ${kargs_list} --os=${OSTREE_OSNAME} ${OSTREE_OSNAME}:${OSTREE_BRANCHNAME}
+
+ # Copy deployment /home and /var/sota to sysroot
HOME_TMP=`mktemp -d ${WORKDIR}/home-tmp-XXXXX`
- tar --xattrs --xattrs-include='*' -C ${HOME_TMP} -xf ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.rootfs.ostree.tar.bz2 ./usr/homedirs
+ tar --xattrs --xattrs-include='*' -C ${HOME_TMP} -xf ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.rootfs.ostree.tar.bz2 ./usr/homedirs ./var/sota || true
mv ${HOME_TMP}/usr/homedirs/home ${PHYS_SYSROOT}/
+ mv ${HOME_TMP}/var/sota ${PHYS_SYSROOT}/ostree/deploy/${OSTREE_OSNAME}/var/ || true
rm -rf ${HOME_TMP}
OTA_ROOTFS_SIZE=$(calculate_size `du -ks $PHYS_SYSROOT | cut -f 1` "${IMAGE_OVERHEAD_FACTOR}" "${IMAGE_ROOTFS_SIZE}" "${IMAGE_ROOTFS_MAXSIZE}" `expr ${IMAGE_ROOTFS_EXTRA_SPACE}` "${IMAGE_ROOTFS_ALIGNMENT}")
@@ -100,7 +113,8 @@ IMAGE_CMD_otaimg () {
rm -rf ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.otaimg
sync
dd if=/dev/zero of=${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.otaimg seek=$OTA_ROOTFS_SIZE count=$COUNT bs=1024
- mkfs.ext4 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.otaimg -d ${PHYS_SYSROOT}
+ mkfs.ext4 -O ^64bit ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.otaimg -d ${PHYS_SYSROOT}
+
rm -rf ${PHYS_SYSROOT}
rm -f ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.otaimg
diff --git a/meta-sota/recipes-sota/ostree/ostree_git.bb b/meta-sota/recipes-sota/ostree/ostree_git.bb
index f917f8a..674c379 100644
--- a/meta-sota/recipes-sota/ostree/ostree_git.bb
+++ b/meta-sota/recipes-sota/ostree/ostree_git.bb
@@ -8,7 +8,9 @@ INHERIT_remove_class-native = "systemd"
SRC_URI = "gitsm://github.com/ostreedev/ostree.git;branch=master"
-SRCREV="0817be61a17cc8b770cad54196182ac9c3109caf"
+SRCREV="3b09620c2738bce4ed45e099cf2e4c5df7671d39"
+
+PV = "2017.3-31-g3b09620c"
S = "${WORKDIR}/git"
@@ -17,12 +19,18 @@ BBCLASSEXTEND = "native"
DEPENDS += "attr libarchive glib-2.0 pkgconfig gpgme libgsystem fuse libsoup-2.4 e2fsprogs systemd gtk-doc-native"
DEPENDS_remove_class-native = "systemd-native"
-RDEPENDS_${PN} = "python util-linux-libuuid util-linux-libblkid util-linux-libmount libcap xz"
+RDEPENDS_${PN} = "python util-linux-libuuid util-linux-libblkid util-linux-libmount libcap xz bash"
RDEPENDS_${PN}_remove_class-native = "python-native"
-EXTRA_OECONF = "--with-libarchive --disable-gtk-doc --disable-gtk-doc-html --disable-gtk-doc-pdf --disable-man --with-smack"
+EXTRA_OECONF = "--with-libarchive --disable-gtk-doc --disable-gtk-doc-html --disable-gtk-doc-pdf --disable-man --with-smack --with-builtin-grub2-mkconfig"
EXTRA_OECONF_append_class-native = " --enable-wrpseudo-compat"
+# Path to ${prefix}/lib/ostree/ostree-grub-generator is hardcoded on the
+# do_configure stage so we do depend on it
+SYSROOT_DIR = "${STAGING_DIR_TARGET}"
+SYSROOT_DIR_class-native = "${STAGING_DIR_NATIVE}"
+do_configure[vardeps] += "SYSROOT_DIR"
+
SYSTEMD_REQUIRED = "${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}"
SYSTEMD_REQUIRED_class-native = ""
diff --git a/meta-sota/recipes-sota/rvi-sota-client/rvi-sota-client_git.bb b/meta-sota/recipes-sota/rvi-sota-client/rvi-sota-client_git.bb
index 4d10b47..1fe2331 100644
--- a/meta-sota/recipes-sota/rvi-sota-client/rvi-sota-client_git.bb
+++ b/meta-sota/recipes-sota/rvi-sota-client/rvi-sota-client_git.bb
@@ -8,109 +8,155 @@ inherit cargo systemd
S = "${WORKDIR}/git"
-SRCREV = "022cf8501f9eb84bf334a2490e6e0c67842882ab"
+# When changing this, don't forget to:
+# 1) Update PV
+# 2) Check that Cargo.lock hasn't changed with git diff old..new Cargo.lock
+SRCREV = "878aa386e61bc253e4fae624ae62507710cd23f3"
# Generate with:
# git describe --tags | cut -b2-
-PV = "0.2.30-2-g022cf85"
+# or from the rvi_sota_client repo:
+# make package-version
+PV = "0.2.32-131-g878aa38"
BBCLASSEXTEND = "native"
FILES_${PN} = " \
+ /lib64 \
+ ${bindir}/canonical_json.py \
${bindir}/sota_client \
${bindir}/sota_sysinfo.sh \
${bindir}/system_info.sh \
- ${bindir}/sota_ostree.sh \
+ ${bindir}/sota_ostree.sh \
+ ${bindir}/sota_prov.sh \
${sysconfdir}/sota_client.version \
${sysconfdir}/sota_certificates \
+ /var/sota/sota_provisioning_credentials.p12 \
+ /var/sota/sota_provisioning_url.env \
+ ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${systemd_unitdir}/system/sota_client_autoprovision.service', '', d)} \
${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${systemd_unitdir}/system/sota_client.service', '', d)} \
"
+# list of dependencies can be generated from Cargo.lock by running
+# cat Cargo.lock | sed -e '1,/metadata/ d' Cargo.lock | awk '{print "crate://crates.io/"$2 "/" $3" \\"}'
SRC_URI = " \
crate://crates.io/aho-corasick/0.5.3 \
-crate://crates.io/bit-set/0.2.0 \
+crate://crates.io/aho-corasick/0.6.3 \
+crate://crates.io/base64/0.4.1 \
+crate://crates.io/bit-set/0.4.0 \
crate://crates.io/bit-vec/0.4.3 \
-crate://crates.io/bitflags/0.4.0 \
crate://crates.io/bitflags/0.7.0 \
-crate://crates.io/bytes/0.3.0 \
+crate://crates.io/byteorder/1.0.0 \
+crate://crates.io/bytes/0.4.1 \
crate://crates.io/cfg-if/0.1.0 \
-crate://crates.io/chan-signal/0.1.7 \
-crate://crates.io/chan/0.1.18 \
-crate://crates.io/cookie/0.2.5 \
+crate://crates.io/chan/0.1.19 \
+crate://crates.io/chan-signal/0.2.0 \
+crate://crates.io/chrono/0.3.0 \
crate://crates.io/crossbeam/0.2.10 \
-crate://crates.io/dbus/0.4.1 \
-crate://crates.io/env_logger/0.3.5 \
-crate://crates.io/gcc/0.3.40 \
+crate://crates.io/dbus/0.5.2 \
+crate://crates.io/deque/0.3.1 \
+crate://crates.io/dtoa/0.4.1 \
+crate://crates.io/env_logger/0.4.2 \
+crate://crates.io/error-chain/0.7.2 \
+crate://crates.io/foreign-types/0.2.0 \
+crate://crates.io/gcc/0.3.45 \
crate://crates.io/gdi32-sys/0.2.0 \
crate://crates.io/getopts/0.2.14 \
-crate://crates.io/hpack/0.2.0 \
crate://crates.io/httparse/1.2.1 \
-crate://crates.io/hyper/0.9.14 \
+crate://crates.io/hyper/0.10.5 \
crate://crates.io/idna/0.1.0 \
+crate://crates.io/iovec/0.1.0 \
+crate://crates.io/itoa/0.3.1 \
crate://crates.io/kernel32-sys/0.2.2 \
crate://crates.io/language-tags/0.2.2 \
-crate://crates.io/lazy_static/0.1.16 \
-crate://crates.io/lazy_static/0.2.2 \
-crate://crates.io/lazycell/0.4.0 \
-crate://crates.io/libc/0.2.18 \
-crate://crates.io/log/0.3.6 \
+crate://crates.io/lazy_static/0.2.5 \
+crate://crates.io/libc/0.2.21 \
+crate://crates.io/log/0.3.7 \
crate://crates.io/matches/0.1.4 \
crate://crates.io/memchr/0.1.11 \
-crate://crates.io/mime/0.2.2 \
-crate://crates.io/mio/0.6.1 \
-crate://crates.io/miow/0.1.4 \
-crate://crates.io/net2/0.2.26 \
-crate://crates.io/nix/0.7.0 \
+crate://crates.io/memchr/1.0.1 \
+crate://crates.io/metadeps/1.1.1 \
+crate://crates.io/mime/0.2.3 \
crate://crates.io/nom/1.2.4 \
-crate://crates.io/num_cpus/1.2.0 \
-crate://crates.io/openssl-sys/0.9.3 \
-crate://crates.io/openssl/0.9.3 \
-crate://crates.io/pkg-config/0.3.8 \
+crate://crates.io/num/0.1.37 \
+crate://crates.io/num-integer/0.1.33 \
+crate://crates.io/num-iter/0.1.33 \
+crate://crates.io/num-traits/0.1.37 \
+crate://crates.io/num_cpus/1.3.0 \
+crate://crates.io/openssl/0.9.10 \
+crate://crates.io/openssl-sys/0.9.10 \
+crate://crates.io/pem/0.2.0 \
+crate://crates.io/pkg-config/0.3.9 \
+crate://crates.io/quote/0.3.15 \
crate://crates.io/rand/0.3.15 \
-crate://crates.io/regex-syntax/0.3.9 \
+crate://crates.io/rayon/0.6.0 \
+crate://crates.io/redox_syscall/0.1.17 \
crate://crates.io/regex/0.1.80 \
+crate://crates.io/regex/0.2.1 \
+crate://crates.io/regex-syntax/0.3.9 \
+crate://crates.io/regex-syntax/0.4.0 \
+crate://crates.io/ring/0.7.1 \
crate://crates.io/rust-crypto/0.2.36 \
-crate://crates.io/rustc-serialize/0.3.22 \
+crate://crates.io/rustc-serialize/0.3.23 \
crate://crates.io/rustc_version/0.1.7 \
crate://crates.io/semver/0.1.20 \
+crate://crates.io/serde/0.9.11 \
+crate://crates.io/serde_codegen_internals/0.14.1 \
+crate://crates.io/serde_derive/0.9.11 \
+crate://crates.io/serde_json/0.9.9 \
crate://crates.io/sha1/0.2.0 \
-crate://crates.io/slab/0.3.0 \
-crate://crates.io/solicit/0.4.4 \
+crate://crates.io/syn/0.11.9 \
+crate://crates.io/synom/0.11.3 \
crate://crates.io/thread-id/2.0.0 \
+crate://crates.io/thread-id/3.0.0 \
crate://crates.io/thread_local/0.2.7 \
-crate://crates.io/time/0.1.35 \
+crate://crates.io/thread_local/0.3.3 \
+crate://crates.io/time/0.1.36 \
crate://crates.io/toml/0.2.1 \
-crate://crates.io/traitobject/0.0.1 \
+crate://crates.io/toml/0.3.1 \
+crate://crates.io/traitobject/0.1.0 \
+crate://crates.io/tungstenite/0.1.1 \
crate://crates.io/typeable/0.1.2 \
crate://crates.io/unicase/1.4.0 \
-crate://crates.io/unicode-bidi/0.2.3 \
-crate://crates.io/unicode-normalization/0.1.2 \
+crate://crates.io/unicode-bidi/0.2.5 \
+crate://crates.io/unicode-normalization/0.1.4 \
+crate://crates.io/unicode-xid/0.0.4 \
crate://crates.io/unix_socket/0.5.0 \
-crate://crates.io/url/1.2.3 \
+crate://crates.io/unreachable/0.1.1 \
+crate://crates.io/untrusted/0.3.2 \
+crate://crates.io/url/1.4.0 \
crate://crates.io/user32-sys/0.2.0 \
+crate://crates.io/utf-8/0.7.0 \
crate://crates.io/utf8-ranges/0.1.3 \
+crate://crates.io/utf8-ranges/1.0.0 \
+crate://crates.io/uuid/0.4.0 \
crate://crates.io/void/1.0.2 \
-crate://crates.io/winapi-build/0.1.1 \
crate://crates.io/winapi/0.2.8 \
-crate://crates.io/ws/0.5.3 \
-crate://crates.io/ws2_32-sys/0.2.1 \
+crate://crates.io/winapi-build/0.1.1 \
git://github.com/advancedtelematic/rvi_sota_client \
-crate-index://crates.io/213b1a455d9270888c03a42c8d29975369102caa \
"
+
SRC_URI[index.md5sum] = "79f10f436dbf26737cc80445746f16b4"
SRC_URI[index.sha256sum] = "86114b93f1f51aaf0aec3af0751d214b351f4ff9839ba031315c1b19dcbb1913"
-SYSTEMD_SERVICE_${PN} = "sota_client.service"
+SYSTEMD_SERVICE_${PN} = "sota_client.service sota_client_autoprovision.service"
-DEPENDS += " openssl "
+DEPENDS += " openssl openssl-native dbus "
RDEPENDS_${PN} = " libcrypto \
libssl \
dbus \
bash \
lshw \
jq \
+ curl \
+ python \
+ python-canonicaljson \
+ python-json \
"
+export SOTA_AUTOPROVISION_CREDENTIALS
+export SOTA_AUTOPROVISION_URL
+
do_compile_prepend() {
export SOTA_VERSION=$(make sota-version)
}
@@ -118,16 +164,38 @@ do_compile_prepend() {
do_install() {
install -d ${D}${bindir}
install -m 0755 target/${TARGET_SYS}/release/sota_client ${D}${bindir}
- install -m 0755 run/sota_sysinfo.sh ${D}${bindir}
+ install -m 0755 ${S}/run/sota_sysinfo.sh ${D}${bindir}
ln -fs ${bindir}/sota_sysinfo.sh ${D}${bindir}/system_info.sh # For compatibilty with old sota.toml files
- install -m 0755 run/sota_ostree.sh ${D}${bindir}
+ install -m 0755 ${S}/run/sota_ostree.sh ${D}${bindir}
+ install -m 0755 ${S}/run/sota_prov.sh ${D}${bindir}
+ install -m 0755 ${S}/run/canonical_json.py ${D}${bindir}
if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then
- install -d ${D}${systemd_unitdir}/system
- install -c ${S}/run/sota_client_ostree.service ${D}${systemd_unitdir}/system/sota_client.service
+ install -d ${D}/${systemd_unitdir}/system
+ if [ -n "$SOTA_AUTOPROVISION_CREDENTIALS" ]; then
+ install -c ${S}/run/sota_client_uptane_auto.service ${D}${systemd_unitdir}/system/sota_client.service
+ else
+ install -c ${S}/run/sota_client_ostree.service ${D}${systemd_unitdir}/system/sota_client.service
+ fi
+ install -c ${S}/run/sota_client_autoprovision.service ${D}${systemd_unitdir}/system/sota_client_autoprovision.service
fi
install -d ${D}${sysconfdir}
echo `git log -1 --pretty=format:%H` > ${D}${sysconfdir}/sota_client.version
install -c ${S}/run/sota_certificates ${D}${sysconfdir}
+ ln -fs /lib ${D}/lib64
+
+ if [ -n "$SOTA_AUTOPROVISION_CREDENTIALS" ]; then
+ EXPDATE=`openssl pkcs12 -in $SOTA_AUTOPROVISION_CREDENTIALS -password "pass:" -nodes 2>/dev/null | openssl x509 -noout -enddate | cut -f2 -d "="`
+
+ if [ `date +%s` -ge `date -d "${EXPDATE}" +%s` ]; then
+ bberror "Certificate ${SOTA_AUTOPROVISION_CREDENTIALS} has expired on ${EXPDATE}"
+ fi
+
+ install -d ${D}/var
+ install -d ${D}/var/sota
+ install -m 0655 $SOTA_AUTOPROVISION_CREDENTIALS ${D}/var/sota/sota_provisioning_credentials.p12
+ echo "SOTA_GATEWAY_URI=$SOTA_AUTOPROVISION_URL" > ${D}/var/sota/sota_provisioning_url.env
+ fi
+
}
diff --git a/meta-sota/recipes-sota/sota-tools/sota-tools_git.bb b/meta-sota/recipes-sota/sota-tools/sota-tools_git.bb
index e472ff8..326ff20 100644
--- a/meta-sota/recipes-sota/sota-tools/sota-tools_git.bb
+++ b/meta-sota/recipes-sota/sota-tools/sota-tools_git.bb
@@ -6,7 +6,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=65d26fcc2f35ea6a181ac777e42db1ea"
S = "${WORKDIR}/git"
SRC_URI = "gitsm://github.com/advancedtelematic/sota-tools.git;branch=master"
-SRCREV = "c6ecec3e86c423dd6caaa362a5ff0a1a6f4072a8"
+SRCREV = "4d7f22f50ab43be5bee61ad3e96cd9db4ef3a372"
inherit cmake
diff --git a/meta-sota/recipes-support/python-canonicaljson/python-canonicaljson.bb b/meta-sota/recipes-support/python-canonicaljson/python-canonicaljson.bb
new file mode 100644
index 0000000..d8a0728
--- /dev/null
+++ b/meta-sota/recipes-support/python-canonicaljson/python-canonicaljson.bb
@@ -0,0 +1,18 @@
+DESCRIPTION = "python-canonicaljson recipe"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=2ee41112a44fe7014dce33e26468ba93"
+
+SRCREV = "92e2c06871cc275c2a8b8e3e899141a212aae0e8"
+SRC_URI = "git://github.com/matrix-org/python-canonicaljson.git"
+S = "${WORKDIR}/git"
+
+# Generate with:
+# git describe --tags | cut -b2-
+PV = "1.0.0"
+inherit setuptools
+
+RDEPENDS_${PN} = "\
+ python-simplejson \
+ python-frozendict \
+ "
diff --git a/meta-sota/recipes-support/python-frozendict/python-frozendict.bb b/meta-sota/recipes-support/python-frozendict/python-frozendict.bb
new file mode 100644
index 0000000..79fe5c8
--- /dev/null
+++ b/meta-sota/recipes-support/python-frozendict/python-frozendict.bb
@@ -0,0 +1,12 @@
+DESCRIPTION = "python-frozendict recipe"
+
+LICENSE = "BSD"
+LIC_FILES_CHKSUM = "file://${S}/LICENSE.txt;md5=f4da037a49c09b456fdbbc7a5bd36132"
+
+SRCREV = "c5d16bafcca7b72ff3e8f40d3a9081e4c9233f1b"
+SRC_URI = "git://github.com/slezica/python-frozendict.git"
+S = "${WORKDIR}/git"
+
+PV = "1.2"
+inherit setuptools
+