diff options
22 files changed, 431 insertions, 392 deletions
@@ -1 +1,2 @@ | |||
1 | __pycache__ | 1 | __pycache__ |
2 | *.pyc | ||
diff --git a/README.adoc b/README.adoc index 47c0a2b..b4608d5 100644 --- a/README.adoc +++ b/README.adoc | |||
@@ -122,3 +122,19 @@ garage-push --repo=/path/to/ostree-repo --ref=mybranch --credentials=/path/to/cr | |||
122 | .... | 122 | .... |
123 | 123 | ||
124 | You can set SOTA_PACKED_CREDENTIALS in your local.conf to make your build results be automatically synchronized with a remote server. Credentials are stored in the JSON format described in the https://github.com/advancedtelematic/aktualizr/blob/master/README.sotatools.adoc[garage-push README]. This JSON file can be optionally stored inside a zip file, although if it is stored this way, the JSON file must be named treehub.json. | 124 | You can set SOTA_PACKED_CREDENTIALS in your local.conf to make your build results be automatically synchronized with a remote server. Credentials are stored in the JSON format described in the https://github.com/advancedtelematic/aktualizr/blob/master/README.sotatools.adoc[garage-push README]. This JSON file can be optionally stored inside a zip file, although if it is stored this way, the JSON file must be named treehub.json. |
125 | |||
126 | === QA | ||
127 | |||
128 | This layer relies on the test framework oe-selftest for quality assurance. Follow the steps below to run the tests: | ||
129 | |||
130 | * Append the line below to conf/local.conf | ||
131 | |||
132 | ``` | ||
133 | SANITY_TESTED_DISTROS="" | ||
134 | ``` | ||
135 | |||
136 | * Run oe-selftest: | ||
137 | |||
138 | ``` | ||
139 | oe-selftest --run-tests updater | ||
140 | ``` | ||
diff --git a/classes/image_types_ostree.bbclass b/classes/image_types_ostree.bbclass index 1f8e195..172f2c8 100644 --- a/classes/image_types_ostree.bbclass +++ b/classes/image_types_ostree.bbclass | |||
@@ -5,6 +5,7 @@ inherit image | |||
5 | IMAGE_DEPENDS_ostree = "ostree-native:do_populate_sysroot \ | 5 | IMAGE_DEPENDS_ostree = "ostree-native:do_populate_sysroot \ |
6 | openssl-native:do_populate_sysroot \ | 6 | openssl-native:do_populate_sysroot \ |
7 | coreutils-native:do_populate_sysroot \ | 7 | coreutils-native:do_populate_sysroot \ |
8 | unzip-native:do_populate_sysroot \ | ||
8 | virtual/kernel:do_deploy \ | 9 | virtual/kernel:do_deploy \ |
9 | ${OSTREE_INITRAMFS_IMAGE}:do_image_complete" | 10 | ${OSTREE_INITRAMFS_IMAGE}:do_image_complete" |
10 | 11 | ||
@@ -104,6 +105,7 @@ IMAGE_CMD_ostree () { | |||
104 | if [ -d root ] && [ ! -L root ]; then | 105 | if [ -d root ] && [ ! -L root ]; then |
105 | if [ "$(ls -A root)" ]; then | 106 | if [ "$(ls -A root)" ]; then |
106 | bberror "Data in /root directory is not preserved by OSTree." | 107 | bberror "Data in /root directory is not preserved by OSTree." |
108 | exit 1 | ||
107 | fi | 109 | fi |
108 | 110 | ||
109 | if [ -n "$SYSTEMD_USED" ]; then | 111 | if [ -n "$SYSTEMD_USED" ]; then |
@@ -159,7 +161,7 @@ IMAGE_CMD_ostree () { | |||
159 | } | 161 | } |
160 | 162 | ||
161 | IMAGE_TYPEDEP_ostreepush = "ostree" | 163 | IMAGE_TYPEDEP_ostreepush = "ostree" |
162 | IMAGE_DEPENDS_ostreepush = "aktualizr-native:do_populate_sysroot" | 164 | IMAGE_DEPENDS_ostreepush = "aktualizr-native:do_populate_sysroot ca-certificates-native:do_populate_sysroot " |
163 | IMAGE_CMD_ostreepush () { | 165 | IMAGE_CMD_ostreepush () { |
164 | # Print warnings if credetials are not set or if the file has not been found. | 166 | # Print warnings if credetials are not set or if the file has not been found. |
165 | if [ -n "${SOTA_PACKED_CREDENTIALS}" ]; then | 167 | if [ -n "${SOTA_PACKED_CREDENTIALS}" ]; then |
@@ -176,4 +178,58 @@ IMAGE_CMD_ostreepush () { | |||
176 | fi | 178 | fi |
177 | } | 179 | } |
178 | 180 | ||
181 | IMAGE_TYPEDEP_garagesign = "ostreepush" | ||
182 | IMAGE_DEPENDS_garagesign = "garage-sign-native:do_populate_sysroot" | ||
183 | IMAGE_CMD_garagesign () { | ||
184 | if [ -n "${SOTA_PACKED_CREDENTIALS}" ]; then | ||
185 | # if credentials are issued by a server that doesn't support offline signing, exit silently | ||
186 | unzip -p ${SOTA_PACKED_CREDENTIALS} root.json targets.pub targets.sec 2>&1 >/dev/null || exit 0 | ||
187 | |||
188 | java_version=$( java -version 2>&1 | awk -F '"' '/version/ {print $2}' ) | ||
189 | if [ "${java_version}" = "" ]; then | ||
190 | bberror "Java is required for synchronization with update backend, but is not installed on the host machine" | ||
191 | exit 1 | ||
192 | elif [ "${java_version}" \< "1.8" ]; then | ||
193 | bberror "Java version >= 8 is required for synchronization with update backend" | ||
194 | exit 1 | ||
195 | fi | ||
196 | |||
197 | if [ ! -d "${GARAGE_SIGN_REPO}" ]; then | ||
198 | garage-sign init --repo ${GARAGE_SIGN_REPO} --home-dir ${GARAGE_SIGN_REPO} --credentials ${SOTA_PACKED_CREDENTIALS} | ||
199 | fi | ||
200 | |||
201 | if [ -n "${GARAGE_SIGN_REPOSERVER}" ]; then | ||
202 | reposerver_args="--reposerver ${GARAGE_SIGN_REPOSERVER}" | ||
203 | else | ||
204 | reposerver_args="" | ||
205 | fi | ||
206 | |||
207 | ostree_target_hash=$(cat ${OSTREE_REPO}/refs/heads/${OSTREE_BRANCHNAME}) | ||
208 | |||
209 | # Push may fail due to race condition when multiple build machines try to push simultaneously | ||
210 | # in which case targets.json should be pulled again and the whole procedure repeated | ||
211 | push_success=0 | ||
212 | for push_retries in $( seq 3 ); do | ||
213 | garage-sign targets pull --repo ${GARAGE_SIGN_REPO} --home-dir ${GARAGE_SIGN_REPO} ${reposerver_args} | ||
214 | garage-sign targets add --repo ${GARAGE_SIGN_REPO} --home-dir ${GARAGE_SIGN_REPO} --name ${OSTREE_BRANCHNAME} --format OSTREE --version ${OSTREE_BRANCHNAME} --length 0 --url "https://example.com/" --sha256 ${ostree_target_hash} --hardwareids ${MACHINE} | ||
215 | garage-sign targets sign --repo ${GARAGE_SIGN_REPO} --home-dir ${GARAGE_SIGN_REPO} --key-name=targets | ||
216 | errcode=0 | ||
217 | garage-sign targets push --repo ${GARAGE_SIGN_REPO} --home-dir ${GARAGE_SIGN_REPO} ${reposerver_args} || errcode=$? | ||
218 | if [ "$errcode" -eq "0" ]; then | ||
219 | push_success=1 | ||
220 | break | ||
221 | else | ||
222 | bbwarn "Push to garage repository has failed, retrying" | ||
223 | fi | ||
224 | done | ||
225 | |||
226 | if [ "$push_success" -ne "1" ]; then | ||
227 | bberror "Couldn't push to garage repository" | ||
228 | exit 1 | ||
229 | fi | ||
230 | else | ||
231 | bbwarn "SOTA_PACKED_CREDENTIALS not set. Please add SOTA_PACKED_CREDENTIALS." | ||
232 | fi | ||
233 | } | ||
234 | |||
179 | # vim:set ts=4 sw=4 sts=4 expandtab: | 235 | # vim:set ts=4 sw=4 sts=4 expandtab: |
diff --git a/classes/sdcard_image-rpi-ota.bbclass b/classes/sdcard_image-rpi-ota.bbclass deleted file mode 100644 index 9c859fe..0000000 --- a/classes/sdcard_image-rpi-ota.bbclass +++ /dev/null | |||
@@ -1,190 +0,0 @@ | |||
1 | inherit image_types | ||
2 | inherit linux-raspberrypi-base | ||
3 | |||
4 | # | ||
5 | # Create an image that can by written onto a SD card using dd. | ||
6 | # | ||
7 | # The disk layout used is: | ||
8 | # | ||
9 | # 0 -> IMAGE_ROOTFS_ALIGNMENT - reserved for other data | ||
10 | # IMAGE_ROOTFS_ALIGNMENT -> BOOT_SPACE - bootloader and kernel | ||
11 | # BOOT_SPACE -> SDIMG_OTA_SIZE - rootfs | ||
12 | # | ||
13 | |||
14 | # Default Free space = 1.3x | ||
15 | # Use IMAGE_OVERHEAD_FACTOR to add more space | ||
16 | # <---------> | ||
17 | # 4MiB 40MiB SDIMG_OTA_ROOTFS | ||
18 | # <-----------------------> <----------> <----------------------> | ||
19 | # ------------------------ ------------ ------------------------ | ||
20 | # | IMAGE_ROOTFS_ALIGNMENT | BOOT_SPACE | OTAROOT_SIZE | | ||
21 | # ------------------------ ------------ ------------------------ | ||
22 | # ^ ^ ^ ^ | ||
23 | # | | | | | ||
24 | # 0 4MiB 4MiB + 40MiB 4MiB + 40Mib + SDIMG_OTA_ROOTFS | ||
25 | |||
26 | # This image depends on the rootfs image | ||
27 | IMAGE_TYPEDEP_rpi-sdimg-ota = "${SDIMG_OTA_ROOTFS_TYPE}" | ||
28 | |||
29 | # Set kernel and boot loader | ||
30 | IMAGE_BOOTLOADER ?= "bcm2835-bootfiles" | ||
31 | |||
32 | # Set initramfs extension | ||
33 | KERNEL_INITRAMFS ?= "" | ||
34 | |||
35 | # Kernel image name | ||
36 | SDIMG_OTA_KERNELIMAGE_raspberrypi ?= "kernel.img" | ||
37 | SDIMG_OTA_KERNELIMAGE_raspberrypi2 ?= "kernel7.img" | ||
38 | SDIMG_OTA_KERNELIMAGE_raspberrypi3 ?= "kernel7.img" | ||
39 | |||
40 | # Boot partition volume id | ||
41 | BOOTDD_VOLUME_ID ?= "${MACHINE}" | ||
42 | |||
43 | # Boot partition size [in KiB] (will be rounded up to IMAGE_ROOTFS_ALIGNMENT) | ||
44 | BOOT_SPACE ?= "40960" | ||
45 | |||
46 | # Set alignment to 4MB [in KiB] | ||
47 | IMAGE_ROOTFS_ALIGNMENT = "4096" | ||
48 | |||
49 | # Use an uncompressed ext3 by default as rootfs | ||
50 | SDIMG_OTA_ROOTFS_TYPE ?= "otaimg" | ||
51 | SDIMG_OTA_ROOTFS = "${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.${SDIMG_OTA_ROOTFS_TYPE}" | ||
52 | |||
53 | IMAGE_DEPENDS_rpi-sdimg-ota = " \ | ||
54 | parted-native \ | ||
55 | mtools-native \ | ||
56 | dosfstools-native \ | ||
57 | virtual/kernel:do_deploy \ | ||
58 | ${IMAGE_BOOTLOADER} \ | ||
59 | u-boot \ | ||
60 | " | ||
61 | IMAGE_TYPEDEP_rpi-sdimg-ota = "otaimg" | ||
62 | |||
63 | # SD card image name | ||
64 | SDIMG_OTA = "${IMGDEPLOYDIR}/${IMAGE_NAME}.rootfs.rpi-sdimg-ota" | ||
65 | |||
66 | # Compression method to apply to SDIMG_OTA after it has been created. Supported | ||
67 | # compression formats are "gzip", "bzip2" or "xz". The original .rpi-sdimg-ota file | ||
68 | # is kept and a new compressed file is created if one of these compression | ||
69 | # formats is chosen. If SDIMG_OTA_COMPRESSION is set to any other value it is | ||
70 | # silently ignored. | ||
71 | #SDIMG_OTA_COMPRESSION ?= "" | ||
72 | |||
73 | # Additional files and/or directories to be copied into the vfat partition from the IMAGE_ROOTFS. | ||
74 | FATPAYLOAD ?= "" | ||
75 | |||
76 | IMAGE_CMD_rpi-sdimg-ota () { | ||
77 | |||
78 | # Align partitions | ||
79 | OTAROOT_SIZE=`du -Lb ${SDIMG_OTA_ROOTFS} | cut -f1` | ||
80 | OTAROOT_SIZE=$(expr ${OTAROOT_SIZE} / 1024 + 1) | ||
81 | BOOT_SPACE_ALIGNED=$(expr ${BOOT_SPACE} + ${IMAGE_ROOTFS_ALIGNMENT} - 1) | ||
82 | BOOT_SPACE_ALIGNED=$(expr ${BOOT_SPACE_ALIGNED} - ${BOOT_SPACE_ALIGNED} % ${IMAGE_ROOTFS_ALIGNMENT}) | ||
83 | SDIMG_OTA_SIZE=$(expr ${IMAGE_ROOTFS_ALIGNMENT} + ${BOOT_SPACE_ALIGNED} + $OTAROOT_SIZE) | ||
84 | |||
85 | echo "Creating filesystem with Boot partition ${BOOT_SPACE_ALIGNED} KiB and RootFS $OTAROOT_SIZE KiB" | ||
86 | |||
87 | # Check if we are building with device tree support | ||
88 | DTS="${@get_dts(d, None)}" | ||
89 | |||
90 | # Initialize sdcard image file | ||
91 | dd if=/dev/zero of=${SDIMG_OTA} bs=1024 count=0 seek=${SDIMG_OTA_SIZE} | ||
92 | |||
93 | # Create partition table | ||
94 | parted -s ${SDIMG_OTA} mklabel msdos | ||
95 | # Create boot partition and mark it as bootable | ||
96 | parted -s ${SDIMG_OTA} unit KiB mkpart primary fat32 ${IMAGE_ROOTFS_ALIGNMENT} $(expr ${BOOT_SPACE_ALIGNED} \+ ${IMAGE_ROOTFS_ALIGNMENT}) | ||
97 | parted -s ${SDIMG_OTA} set 1 boot on | ||
98 | # Create rootfs partition to the end of disk | ||
99 | parted -s ${SDIMG_OTA} -- unit KiB mkpart primary ext2 $(expr ${BOOT_SPACE_ALIGNED} \+ ${IMAGE_ROOTFS_ALIGNMENT}) -1s | ||
100 | parted ${SDIMG_OTA} print | ||
101 | |||
102 | # Create a vfat image with boot files | ||
103 | BOOT_BLOCKS=$(LC_ALL=C parted -s ${SDIMG_OTA} unit b print | awk '/ 1 / { print substr($4, 1, length($4 -1)) / 512 /2 }') | ||
104 | rm -f ${WORKDIR}/boot.img | ||
105 | mkfs.vfat -n "${BOOTDD_VOLUME_ID}" -S 512 -C ${WORKDIR}/boot.img $BOOT_BLOCKS | ||
106 | sync | ||
107 | |||
108 | mcopy -i ${WORKDIR}/boot.img -s ${DEPLOY_DIR_IMAGE}/bcm2835-bootfiles/* ::/ | ||
109 | |||
110 | if test -n "${DTS}"; then | ||
111 | # Device Tree Overlays are assumed to be suffixed by '-overlay.dtb' string and will be put in a dedicated folder | ||
112 | DT_OVERLAYS="${@split_overlays(d, 0)}" | ||
113 | DT_ROOT="${@split_overlays(d, 1)}" | ||
114 | |||
115 | # Copy board device trees to root folder | ||
116 | for DTB in ${DT_ROOT}; do | ||
117 | DTB_BASE_NAME=`basename ${DTB} .dtb` | ||
118 | |||
119 | mcopy -i ${WORKDIR}/boot.img -s ${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}-${DTB_BASE_NAME}.dtb ::${DTB_BASE_NAME}.dtb | ||
120 | done | ||
121 | |||
122 | # Copy device tree overlays to dedicated folder | ||
123 | mmd -i ${WORKDIR}/boot.img overlays | ||
124 | for DTB in ${DT_OVERLAYS}; do | ||
125 | DTB_EXT=${DTB##*.} | ||
126 | DTB_BASE_NAME=`basename ${DTB} ."${DTB_EXT}"` | ||
127 | |||
128 | mcopy -i ${WORKDIR}/boot.img -s ${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}-${DTB_BASE_NAME}.${DTB_EXT} ::overlays/${DTB_BASE_NAME}.${DTB_EXT} | ||
129 | done | ||
130 | fi | ||
131 | |||
132 | case "${KERNEL_IMAGETYPE}" in | ||
133 | "uImage") | ||
134 | mcopy -i ${WORKDIR}/boot.img -s ${DEPLOY_DIR_IMAGE}/u-boot.bin ::${SDIMG_OTA_KERNELIMAGE} | ||
135 | ;; | ||
136 | *) | ||
137 | bbfatal "Kernel uImage is required for OTA image. Please set KERNEL_IMAGETYPE to \"uImage\"" | ||
138 | ;; | ||
139 | esac | ||
140 | |||
141 | if [ -n ${FATPAYLOAD} ] ; then | ||
142 | echo "Copying payload into VFAT" | ||
143 | for entry in ${FATPAYLOAD} ; do | ||
144 | # add the || true to stop aborting on vfat issues like not supporting .~lock files | ||
145 | mcopy -i ${WORKDIR}/boot.img -s -v ${IMAGE_ROOTFS}$entry :: || true | ||
146 | done | ||
147 | fi | ||
148 | |||
149 | # Add stamp file | ||
150 | echo "${IMAGE_NAME}" > ${WORKDIR}/image-version-info | ||
151 | mcopy -i ${WORKDIR}/boot.img -v ${WORKDIR}//image-version-info :: | ||
152 | |||
153 | # Burn Partitions | ||
154 | sync | ||
155 | dd if=${WORKDIR}/boot.img of=${SDIMG_OTA} conv=notrunc seek=1 bs=$(expr ${IMAGE_ROOTFS_ALIGNMENT} \* 1024) && sync && sync | ||
156 | # If SDIMG_OTA_ROOTFS_TYPE is a .xz file use xzcat | ||
157 | if echo "${SDIMG_OTA_ROOTFS_TYPE}" | egrep -q "*\.xz" | ||
158 | then | ||
159 | xzcat ${SDIMG_OTA_ROOTFS} | dd of=${SDIMG_OTA} conv=notrunc seek=1 bs=$(expr 1024 \* ${BOOT_SPACE_ALIGNED} + ${IMAGE_ROOTFS_ALIGNMENT} \* 1024) && sync && sync | ||
160 | else | ||
161 | dd if=${SDIMG_OTA_ROOTFS} of=${SDIMG_OTA} conv=notrunc seek=1 bs=$(expr 1024 \* ${BOOT_SPACE_ALIGNED} + ${IMAGE_ROOTFS_ALIGNMENT} \* 1024) && sync && sync | ||
162 | fi | ||
163 | |||
164 | # Optionally apply compression | ||
165 | case "${SDIMG_OTA_COMPRESSION}" in | ||
166 | "gzip") | ||
167 | gzip -k9 "${SDIMG_OTA}" | ||
168 | ;; | ||
169 | "bzip2") | ||
170 | bzip2 -k9 "${SDIMG_OTA}" | ||
171 | ;; | ||
172 | "xz") | ||
173 | xz -k "${SDIMG_OTA}" | ||
174 | ;; | ||
175 | esac | ||
176 | } | ||
177 | |||
178 | ROOTFS_POSTPROCESS_COMMAND += " rpi_generate_sysctl_config ; " | ||
179 | |||
180 | rpi_generate_sysctl_config() { | ||
181 | # systemd sysctl config | ||
182 | test -d ${IMAGE_ROOTFS}${sysconfdir}/sysctl.d && \ | ||
183 | echo "vm.min_free_kbytes = 8192" > ${IMAGE_ROOTFS}${sysconfdir}/sysctl.d/rpi-vm.conf | ||
184 | |||
185 | # sysv sysctl config | ||
186 | IMAGE_SYSCTL_CONF="${IMAGE_ROOTFS}${sysconfdir}/sysctl.conf" | ||
187 | test -e ${IMAGE_ROOTFS}${sysconfdir}/sysctl.conf && \ | ||
188 | sed -e "/vm.min_free_kbytes/d" -i ${IMAGE_SYSCTL_CONF} | ||
189 | echo "" >> ${IMAGE_SYSCTL_CONF} && echo "vm.min_free_kbytes = 8192" >> ${IMAGE_SYSCTL_CONF} | ||
190 | } | ||
diff --git a/classes/sota.bbclass b/classes/sota.bbclass index 1865356..f5a42c1 100644 --- a/classes/sota.bbclass +++ b/classes/sota.bbclass | |||
@@ -5,11 +5,13 @@ python __anonymous() { | |||
5 | 5 | ||
6 | OVERRIDES .= "${@bb.utils.contains('DISTRO_FEATURES', 'sota', ':sota', '', d)}" | 6 | OVERRIDES .= "${@bb.utils.contains('DISTRO_FEATURES', 'sota', ':sota', '', d)}" |
7 | 7 | ||
8 | HOSTTOOLS_NONFATAL += "java" | ||
9 | |||
8 | SOTA_CLIENT ??= "aktualizr" | 10 | SOTA_CLIENT ??= "aktualizr" |
9 | SOTA_CLIENT_PROV ??= "aktualizr-auto-prov" | 11 | SOTA_CLIENT_PROV ??= "aktualizr-auto-prov" |
10 | IMAGE_INSTALL_append_sota = " ostree os-release ${SOTA_CLIENT} ${SOTA_CLIENT_PROV}" | 12 | IMAGE_INSTALL_append_sota = " ostree os-release ${SOTA_CLIENT} ${SOTA_CLIENT_PROV}" |
11 | IMAGE_CLASSES += " image_types_ostree image_types_ota" | 13 | IMAGE_CLASSES += " image_types_ostree image_types_ota" |
12 | IMAGE_FSTYPES += "${@bb.utils.contains('DISTRO_FEATURES', 'sota', 'ostreepush otaimg wic', ' ', d)}" | 14 | IMAGE_FSTYPES += "${@bb.utils.contains('DISTRO_FEATURES', 'sota', 'ostreepush garagesign otaimg wic', ' ', d)}" |
13 | 15 | ||
14 | PACKAGECONFIG_append_pn-curl = "${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'hsm', " ssl", " ", d)}" | 16 | PACKAGECONFIG_append_pn-curl = "${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'hsm', " ssl", " ", d)}" |
15 | PACKAGECONFIG_remove_pn-curl = "${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'hsm', " gnutls", " ", d)}" | 17 | PACKAGECONFIG_remove_pn-curl = "${@bb.utils.contains('SOTA_CLIENT_FEATURES', 'hsm', " gnutls", " ", d)}" |
@@ -25,6 +27,11 @@ OSTREE_BRANCHNAME ?= "${MACHINE}" | |||
25 | OSTREE_OSNAME ?= "poky" | 27 | OSTREE_OSNAME ?= "poky" |
26 | OSTREE_INITRAMFS_IMAGE ?= "initramfs-ostree-image" | 28 | OSTREE_INITRAMFS_IMAGE ?= "initramfs-ostree-image" |
27 | 29 | ||
30 | |||
31 | GARAGE_SIGN_REPO ?= "${DEPLOY_DIR_IMAGE}/garage_sign_repo" | ||
32 | GARAGE_SIGN_KEYNAME ?= "garage-key" | ||
33 | GARAGE_TARGET_NAME ?= "${OSTREE_BRANCHNAME}" | ||
34 | |||
28 | SOTA_MACHINE ??="none" | 35 | SOTA_MACHINE ??="none" |
29 | SOTA_MACHINE_raspberrypi2 ?= "raspberrypi" | 36 | SOTA_MACHINE_raspberrypi2 ?= "raspberrypi" |
30 | SOTA_MACHINE_raspberrypi3 ?= "raspberrypi" | 37 | SOTA_MACHINE_raspberrypi3 ?= "raspberrypi" |
diff --git a/classes/sota_am335x-evm-wifi.bbclass b/classes/sota_am335x-evm-wifi.bbclass index 821e8fb..adefb47 100644 --- a/classes/sota_am335x-evm-wifi.bbclass +++ b/classes/sota_am335x-evm-wifi.bbclass | |||
@@ -1,5 +1,3 @@ | |||
1 | IMAGE_CLASSES += "image_types_uboot" | ||
2 | |||
3 | KERNEL_IMAGETYPE_sota = "uImage" | 1 | KERNEL_IMAGETYPE_sota = "uImage" |
4 | 2 | ||
5 | OSTREE_BOOTLOADER ?= "u-boot" | 3 | OSTREE_BOOTLOADER ?= "u-boot" |
diff --git a/classes/sota_m3ulcb.bbclass b/classes/sota_m3ulcb.bbclass index 21d04ba..6b63af4 100644 --- a/classes/sota_m3ulcb.bbclass +++ b/classes/sota_m3ulcb.bbclass | |||
@@ -2,7 +2,6 @@ | |||
2 | OSTREE_KERNEL = "Image" | 2 | OSTREE_KERNEL = "Image" |
3 | 3 | ||
4 | EXTRA_IMAGEDEPENDS_append_sota = " m3ulcb-ota-bootfiles" | 4 | EXTRA_IMAGEDEPENDS_append_sota = " m3ulcb-ota-bootfiles" |
5 | IMAGE_CLASSES_append_sota = " image_types_uboot " | ||
6 | IMAGE_BOOT_FILES_sota += "m3ulcb-ota-bootfiles/*" | 5 | IMAGE_BOOT_FILES_sota += "m3ulcb-ota-bootfiles/*" |
7 | 6 | ||
8 | OSTREE_BOOTLOADER ?= "u-boot" | 7 | OSTREE_BOOTLOADER ?= "u-boot" |
diff --git a/classes/sota_porter.bbclass b/classes/sota_porter.bbclass index a8f5ba1..75ae579 100644 --- a/classes/sota_porter.bbclass +++ b/classes/sota_porter.bbclass | |||
@@ -2,7 +2,6 @@ | |||
2 | OSTREE_KERNEL = "uImage+dtb" | 2 | OSTREE_KERNEL = "uImage+dtb" |
3 | 3 | ||
4 | EXTRA_IMAGEDEPENDS_append_sota = " porter-bootfiles" | 4 | EXTRA_IMAGEDEPENDS_append_sota = " porter-bootfiles" |
5 | IMAGE_CLASSES_append_sota = " image_types_uboot " | ||
6 | IMAGE_BOOT_FILES_sota += "porter-bootfiles/*" | 5 | IMAGE_BOOT_FILES_sota += "porter-bootfiles/*" |
7 | 6 | ||
8 | OSTREE_BOOTLOADER ?= "u-boot" | 7 | OSTREE_BOOTLOADER ?= "u-boot" |
diff --git a/classes/sota_raspberrypi.bbclass b/classes/sota_raspberrypi.bbclass index cc6b666..51d07b2 100644 --- a/classes/sota_raspberrypi.bbclass +++ b/classes/sota_raspberrypi.bbclass | |||
@@ -1,11 +1,9 @@ | |||
1 | IMAGE_CLASSES += "${@bb.utils.contains('DISTRO_FEATURES', 'sota', 'image_types_uboot sdcard_image-rpi-ota', '', d)}" | ||
2 | IMAGE_FSTYPES += "${@bb.utils.contains('DISTRO_FEATURES', 'sota', 'rpi-sdimg-ota.xz', 'rpi-sdimg.xz', d)}" | ||
3 | |||
4 | IMAGE_FSTYPES_remove = "${@bb.utils.contains('DISTRO_FEATURES', 'sota', 'wic rpi-sdimg rpi-sdimg.xz', '', d)}" | ||
5 | |||
6 | KERNEL_IMAGETYPE_sota = "uImage" | 1 | KERNEL_IMAGETYPE_sota = "uImage" |
7 | PREFERRED_PROVIDER_virtual/bootloader_sota ?= "u-boot" | 2 | PREFERRED_PROVIDER_virtual/bootloader_sota ?= "u-boot" |
8 | UBOOT_MACHINE_raspberrypi2_sota ?= "rpi_2_defconfig" | 3 | UBOOT_MACHINE_raspberrypi2_sota ?= "rpi_2_defconfig" |
9 | UBOOT_MACHINE_raspberrypi3_sota ?= "rpi_3_32b_defconfig" | 4 | UBOOT_MACHINE_raspberrypi3_sota ?= "rpi_3_32b_defconfig" |
10 | 5 | ||
11 | OSTREE_BOOTLOADER ?= "u-boot" | 6 | OSTREE_BOOTLOADER ?= "u-boot" |
7 | |||
8 | # OSTree puts its own boot.scr to bcm2835-bootfiles | ||
9 | IMAGE_BOOT_FILES_remove_sota += "boot.scr" | ||
diff --git a/lib/oeqa/selftest/garage_push.py b/lib/oeqa/selftest/garage_push.py deleted file mode 100644 index 3490de5..0000000 --- a/lib/oeqa/selftest/garage_push.py +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | import unittest | ||
2 | import os | ||
3 | import logging | ||
4 | |||
5 | from oeqa.selftest.base import oeSelfTest | ||
6 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var | ||
7 | |||
8 | class GaragePushTests(oeSelfTest): | ||
9 | |||
10 | @classmethod | ||
11 | def setUpClass(cls): | ||
12 | # Ensure we have the right data in pkgdata | ||
13 | logger = logging.getLogger("selftest") | ||
14 | logger.info('Running bitbake to build aktualizr-native tools') | ||
15 | bitbake('aktualizr-native garage-sign-native') | ||
16 | |||
17 | def test_help(self): | ||
18 | image_dir = get_bb_var("D", "aktualizr-native") | ||
19 | bin_dir = get_bb_var("bindir", "aktualizr-native") | ||
20 | gp_path = os.path.join(image_dir, bin_dir[1:], 'garage-push') | ||
21 | result = runCmd('%s --help' % gp_path, ignore_status=True) | ||
22 | self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) | ||
23 | |||
24 | def test_java(self): | ||
25 | result = runCmd('which java', ignore_status=True) | ||
26 | self.assertEqual(result.status, 0, "Java not found.") | ||
27 | |||
28 | def test_sign(self): | ||
29 | image_dir = get_bb_var("D", "garage-sign-native") | ||
30 | bin_dir = get_bb_var("bindir", "garage-sign-native") | ||
31 | gs_path = os.path.join(image_dir, bin_dir[1:], 'garage-sign') | ||
32 | result = runCmd('%s --help' % gs_path, ignore_status=True) | ||
33 | self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) | ||
34 | |||
35 | def test_push(self): | ||
36 | bitbake('core-image-minimal') | ||
37 | self.write_config('IMAGE_INSTALL_append = " man "') | ||
38 | bitbake('core-image-minimal') | ||
39 | |||
diff --git a/lib/oeqa/selftest/qemucommand.py b/lib/oeqa/selftest/qemucommand.py new file mode 120000 index 0000000..bc06dde --- /dev/null +++ b/lib/oeqa/selftest/qemucommand.py | |||
@@ -0,0 +1 @@ | |||
../../../scripts/qemucommand.py \ No newline at end of file | |||
diff --git a/lib/oeqa/selftest/updater.py b/lib/oeqa/selftest/updater.py new file mode 100644 index 0000000..2723b4a --- /dev/null +++ b/lib/oeqa/selftest/updater.py | |||
@@ -0,0 +1,147 @@ | |||
1 | import unittest | ||
2 | import os | ||
3 | import logging | ||
4 | import subprocess | ||
5 | import time | ||
6 | |||
7 | from oeqa.selftest.base import oeSelfTest | ||
8 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars | ||
9 | from oeqa.selftest.qemucommand import QemuCommand | ||
10 | |||
11 | |||
12 | class SotaToolsTests(oeSelfTest): | ||
13 | |||
14 | @classmethod | ||
15 | def setUpClass(cls): | ||
16 | logger = logging.getLogger("selftest") | ||
17 | logger.info('Running bitbake to build aktualizr-native tools') | ||
18 | bitbake('aktualizr-native') | ||
19 | |||
20 | def test_push_help(self): | ||
21 | bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'aktualizr-native') | ||
22 | p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "garage-push" | ||
23 | self.assertTrue(os.path.isfile(p), msg = "No garage-push found (%s)" % p) | ||
24 | result = runCmd('%s --help' % p, ignore_status=True) | ||
25 | self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) | ||
26 | |||
27 | def test_deploy_help(self): | ||
28 | bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'aktualizr-native') | ||
29 | p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "garage-deploy" | ||
30 | self.assertTrue(os.path.isfile(p), msg = "No garage-deploy found (%s)" % p) | ||
31 | result = runCmd('%s --help' % p, ignore_status=True) | ||
32 | self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) | ||
33 | |||
34 | |||
35 | class GarageSignTests(oeSelfTest): | ||
36 | |||
37 | @classmethod | ||
38 | def setUpClass(cls): | ||
39 | logger = logging.getLogger("selftest") | ||
40 | logger.info('Running bitbake to build garage-sign-native') | ||
41 | bitbake('garage-sign-native') | ||
42 | |||
43 | def test_help(self): | ||
44 | bb_vars = get_bb_vars(['SYSROOT_DESTDIR', 'bindir'], 'garage-sign-native') | ||
45 | p = bb_vars['SYSROOT_DESTDIR'] + bb_vars['bindir'] + "/" + "garage-sign" | ||
46 | self.assertTrue(os.path.isfile(p), msg = "No garage-sign found (%s)" % p) | ||
47 | result = runCmd('%s --help' % p, ignore_status=True) | ||
48 | self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) | ||
49 | |||
50 | |||
51 | class HsmTests(oeSelfTest): | ||
52 | |||
53 | def test_hsm(self): | ||
54 | self.write_config('SOTA_CLIENT_FEATURES="hsm hsm-test"') | ||
55 | bitbake('core-image-minimal') | ||
56 | |||
57 | |||
58 | class GeneralTests(oeSelfTest): | ||
59 | |||
60 | def test_feature_sota(self): | ||
61 | result = get_bb_var('DISTRO_FEATURES').find('sota') | ||
62 | self.assertNotEqual(result, -1, 'Feature "sota" not set at DISTRO_FEATURES'); | ||
63 | |||
64 | def test_feature_systemd(self): | ||
65 | result = get_bb_var('DISTRO_FEATURES').find('systemd') | ||
66 | self.assertNotEqual(result, -1, 'Feature "systemd" not set at DISTRO_FEATURES'); | ||
67 | |||
68 | def test_credentials(self): | ||
69 | bitbake('core-image-minimal') | ||
70 | credentials = get_bb_var('SOTA_PACKED_CREDENTIALS') | ||
71 | # skip the test if the variable SOTA_PACKED_CREDENTIALS is not set | ||
72 | if credentials is None: | ||
73 | raise unittest.SkipTest("Variable 'SOTA_PACKED_CREDENTIALS' not set.") | ||
74 | # Check if the file exists | ||
75 | self.assertTrue(os.path.isfile(credentials), "File %s does not exist" % credentials) | ||
76 | deploydir = get_bb_var('DEPLOY_DIR_IMAGE') | ||
77 | imagename = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal') | ||
78 | # Check if the credentials are included in the output image | ||
79 | result = runCmd('tar -jtvf %s/%s.tar.bz2 | grep sota_provisioning_credentials.zip' % (deploydir, imagename), ignore_status=True) | ||
80 | self.assertEqual(result.status, 0, "Status not equal to 0. output: %s" % result.output) | ||
81 | |||
82 | def test_java(self): | ||
83 | result = runCmd('which java', ignore_status=True) | ||
84 | self.assertEqual(result.status, 0, "Java not found.") | ||
85 | |||
86 | def test_add_package(self): | ||
87 | print('') | ||
88 | deploydir = get_bb_var('DEPLOY_DIR_IMAGE') | ||
89 | imagename = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal') | ||
90 | image_path = deploydir + '/' + imagename + '.otaimg' | ||
91 | logger = logging.getLogger("selftest") | ||
92 | |||
93 | logger.info('Running bitbake with man in the image package list') | ||
94 | self.write_config('IMAGE_INSTALL_append = " man "') | ||
95 | bitbake('-c cleanall man') | ||
96 | bitbake('core-image-minimal') | ||
97 | result = runCmd('oe-pkgdata-util find-path /usr/bin/man') | ||
98 | self.assertEqual(result.output, 'man: /usr/bin/man') | ||
99 | path1 = os.path.realpath(image_path) | ||
100 | size1 = os.path.getsize(path1) | ||
101 | logger.info('First image %s has size %i' % (path1, size1)) | ||
102 | |||
103 | logger.info('Running bitbake without man in the image package list') | ||
104 | self.write_config('IMAGE_INSTALL_remove = " man "') | ||
105 | bitbake('-c cleanall man') | ||
106 | bitbake('core-image-minimal') | ||
107 | result = runCmd('oe-pkgdata-util find-path /usr/bin/man', ignore_status=True) | ||
108 | self.assertEqual(result.status, 1, "Status different than 1. output: %s" % result.output) | ||
109 | self.assertEqual(result.output, 'ERROR: Unable to find any package producing path /usr/bin/man') | ||
110 | path2 = os.path.realpath(image_path) | ||
111 | size2 = os.path.getsize(path2) | ||
112 | logger.info('Second image %s has size %i' % (path2, size2)) | ||
113 | self.assertNotEqual(path1, path2, "Image paths are identical; image was not rebuilt.") | ||
114 | self.assertNotEqual(size1, size2, "Image sizes are identical; image was not rebuilt.") | ||
115 | |||
116 | def test_qemu(self): | ||
117 | print('') | ||
118 | # Create empty object. | ||
119 | args = type('', (), {})() | ||
120 | args.imagename = 'core-image-minimal' | ||
121 | args.mac = None | ||
122 | # Could use DEPLOY_DIR_IMAGE here but it's already in the machine | ||
123 | # subdirectory. | ||
124 | args.dir = 'tmp/deploy/images' | ||
125 | args.efi = False | ||
126 | args.machine = None | ||
127 | args.kvm = None # Autodetect | ||
128 | args.no_gui = True | ||
129 | args.gdb = False | ||
130 | args.pcap = None | ||
131 | args.overlay = None | ||
132 | args.dry_run = False | ||
133 | |||
134 | qemu_command = QemuCommand(args) | ||
135 | cmdline = qemu_command.command_line() | ||
136 | print('Booting image with run-qemu-ota...') | ||
137 | s = subprocess.Popen(cmdline) | ||
138 | time.sleep(10) | ||
139 | print('Machine name (hostname) of device is:') | ||
140 | ssh_cmd = ['ssh', '-q', '-o', 'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no', 'root@localhost', '-p', str(qemu_command.ssh_port), 'hostname'] | ||
141 | s2 = subprocess.Popen(ssh_cmd) | ||
142 | time.sleep(5) | ||
143 | try: | ||
144 | s.terminate() | ||
145 | except KeyboardInterrupt: | ||
146 | pass | ||
147 | |||
diff --git a/recipes-core/images/initramfs-ostree-image.bb b/recipes-core/images/initramfs-ostree-image.bb index 4870579..4ab9da8 100644 --- a/recipes-core/images/initramfs-ostree-image.bb +++ b/recipes-core/images/initramfs-ostree-image.bb | |||
@@ -15,7 +15,6 @@ LICENSE = "MIT" | |||
15 | 15 | ||
16 | IMAGE_FSTYPES = "ext4.gz" | 16 | IMAGE_FSTYPES = "ext4.gz" |
17 | IMAGE_FSTYPES_append_arm = " ext4.gz.u-boot" | 17 | IMAGE_FSTYPES_append_arm = " ext4.gz.u-boot" |
18 | IMAGE_CLASSES_append_arm = " image_types_uboot" | ||
19 | 18 | ||
20 | inherit core-image | 19 | inherit core-image |
21 | 20 | ||
diff --git a/recipes-sota/aktualizr/aktualizr-hsm-test-prov.bb b/recipes-sota/aktualizr/aktualizr-hsm-test-prov.bb index 276c17e..c443c56 100644 --- a/recipes-sota/aktualizr/aktualizr-hsm-test-prov.bb +++ b/recipes-sota/aktualizr/aktualizr-hsm-test-prov.bb | |||
@@ -23,12 +23,12 @@ inherit systemd | |||
23 | do_install() { | 23 | do_install() { |
24 | install -d ${D}/${systemd_unitdir}/system | 24 | install -d ${D}/${systemd_unitdir}/system |
25 | install -m 0644 ${WORKDIR}/aktualizr-autoprovision.service ${D}/${systemd_unitdir}/system/aktualizr.service | 25 | install -m 0644 ${WORKDIR}/aktualizr-autoprovision.service ${D}/${systemd_unitdir}/system/aktualizr.service |
26 | install -d ${D}/usr/lib/sota | 26 | install -d ${D}${libdir}/sota |
27 | aktualizr_implicit_writer -c ${SOTA_PACKED_CREDENTIALS} --no-root-ca \ | 27 | aktualizr_implicit_writer -c ${SOTA_PACKED_CREDENTIALS} --no-root-ca \ |
28 | -i ${WORKDIR}/sota_hsm_test.toml -o ${D}/usr/lib/sota/sota.toml -p ${D} | 28 | -i ${WORKDIR}/sota_hsm_test.toml -o ${D}${libdir}/sota/sota.toml -p ${D} |
29 | } | 29 | } |
30 | 30 | ||
31 | FILES_${PN} = " \ | 31 | FILES_${PN} = " \ |
32 | ${systemd_unitdir}/system/aktualizr.service \ | 32 | ${systemd_unitdir}/system/aktualizr.service \ |
33 | /usr/lib/sota/sota.toml \ | 33 | ${libdir}/sota/sota.toml \ |
34 | " | 34 | " |
diff --git a/recipes-sota/aktualizr/aktualizr_git.bb b/recipes-sota/aktualizr/aktualizr_git.bb index 9a1a7a6..162065e 100644 --- a/recipes-sota/aktualizr/aktualizr_git.bb +++ b/recipes-sota/aktualizr/aktualizr_git.bb | |||
@@ -18,7 +18,7 @@ PR = "7" | |||
18 | SRC_URI = " \ | 18 | SRC_URI = " \ |
19 | git://github.com/advancedtelematic/aktualizr;branch=${BRANCH} \ | 19 | git://github.com/advancedtelematic/aktualizr;branch=${BRANCH} \ |
20 | " | 20 | " |
21 | SRCREV = "67c4f44c4136d16871726449502e3926098e8524" | 21 | SRCREV = "f043191ae622a96cf2f4d48f9073d5cfa9f16e3f" |
22 | BRANCH ?= "master" | 22 | BRANCH ?= "master" |
23 | 23 | ||
24 | S = "${WORKDIR}/git" | 24 | S = "${WORKDIR}/git" |
@@ -33,7 +33,6 @@ EXTRA_OECMAKE_append_class-native = "-DBUILD_SOTA_TOOLS=ON -DBUILD_OSTREE=OFF " | |||
33 | 33 | ||
34 | do_install_append () { | 34 | do_install_append () { |
35 | rm -f ${D}${bindir}/aktualizr_cert_provider | 35 | rm -f ${D}${bindir}/aktualizr_cert_provider |
36 | rm -f ${D}${bindir}/garage-deploy | ||
37 | } | 36 | } |
38 | do_install_append_class-target () { | 37 | do_install_append_class-target () { |
39 | rm -f ${D}${bindir}/aktualizr_implicit_writer | 38 | rm -f ${D}${bindir}/aktualizr_implicit_writer |
@@ -47,5 +46,6 @@ FILES_${PN}_class-target = " \ | |||
47 | " | 46 | " |
48 | FILES_${PN}_class-native = " \ | 47 | FILES_${PN}_class-native = " \ |
49 | ${bindir}/aktualizr_implicit_writer \ | 48 | ${bindir}/aktualizr_implicit_writer \ |
49 | ${bindir}/garage-deploy \ | ||
50 | ${bindir}/garage-push \ | 50 | ${bindir}/garage-push \ |
51 | " | 51 | " |
diff --git a/recipes-sota/aktualizr/files/sota_hsm_test.toml b/recipes-sota/aktualizr/files/sota_hsm_test.toml index 1317914..28aefc2 100644 --- a/recipes-sota/aktualizr/files/sota_hsm_test.toml +++ b/recipes-sota/aktualizr/files/sota_hsm_test.toml | |||
@@ -12,6 +12,7 @@ pass = "1234" | |||
12 | 12 | ||
13 | [uptane] | 13 | [uptane] |
14 | metadata_path = "/var/sota/metadata" | 14 | metadata_path = "/var/sota/metadata" |
15 | private_key_path = "ecukey.der" | 15 | key_source = "pkcs11" |
16 | public_key_path = "ecukey.pub" | 16 | private_key_path = "03" |
17 | public_key_path = "03" | ||
17 | 18 | ||
diff --git a/recipes-sota/garage-sign/garage-sign.bb b/recipes-sota/garage-sign/garage-sign.bb index ccd7299..d5388bc 100644 --- a/recipes-sota/garage-sign/garage-sign.bb +++ b/recipes-sota/garage-sign/garage-sign.bb | |||
@@ -6,14 +6,14 @@ LICENSE = "CLOSED" | |||
6 | LIC_FILES_CHKSUM = "file://${S}/docs/LICENSE;md5=3025e77db7bd3f1d616b3ffd11d54c94" | 6 | LIC_FILES_CHKSUM = "file://${S}/docs/LICENSE;md5=3025e77db7bd3f1d616b3ffd11d54c94" |
7 | DEPENDS = "" | 7 | DEPENDS = "" |
8 | 8 | ||
9 | PV = "0.2.0-6-g6af6ecd" | 9 | PV = "0.2.0-35-g0544c33" |
10 | 10 | ||
11 | SRC_URI = " \ | 11 | SRC_URI = " \ |
12 | https://ats-tuf-cli-releases.s3-eu-central-1.amazonaws.com/cli-${PV}.tgz \ | 12 | https://ats-tuf-cli-releases.s3-eu-central-1.amazonaws.com/cli-${PV}.tgz \ |
13 | " | 13 | " |
14 | 14 | ||
15 | SRC_URI[md5sum] = "39941607ddef3a93476e267ad7bf6280" | 15 | SRC_URI[md5sum] = "1546e06d1e747f67aee5ed7096bf1c74" |
16 | SRC_URI[sha256sum] = "fbd2ea56f21341146844b02837377b08e63a3e361079e2c65142c2ed881c3b5d" | 16 | SRC_URI[sha256sum] = "1432348bca8ca5ad75df1218f348f480d429d7509d6454deb6e16ff31c5e08fc" |
17 | 17 | ||
18 | S = "${WORKDIR}/${BPN}" | 18 | S = "${WORKDIR}/${BPN}" |
19 | 19 | ||
diff --git a/recipes-support/ca-certificates/ca-certificates_%.bbappend b/recipes-support/ca-certificates/ca-certificates_%.bbappend new file mode 100644 index 0000000..afaadfd --- /dev/null +++ b/recipes-support/ca-certificates/ca-certificates_%.bbappend | |||
@@ -0,0 +1 @@ | |||
SYSROOT_DIRS += "/etc" | |||
diff --git a/recipes-support/libp11/libp11_0.4.7.bb b/recipes-support/libp11/libp11_0.4.7.bb new file mode 100644 index 0000000..7d77e90 --- /dev/null +++ b/recipes-support/libp11/libp11_0.4.7.bb | |||
@@ -0,0 +1,37 @@ | |||
1 | SUMMARY = "Library for using PKCS" | ||
2 | DESCRIPTION = "\ | ||
3 | Libp11 is a library implementing a small layer on top of PKCS \ | ||
4 | make using PKCS" | ||
5 | HOMEPAGE = "http://www.opensc-project.org/libp11" | ||
6 | SECTION = "Development/Libraries" | ||
7 | LICENSE = "LGPLv2+" | ||
8 | LIC_FILES_CHKSUM = "file://COPYING;md5=fad9b3332be894bab9bc501572864b29" | ||
9 | DEPENDS = "libtool openssl" | ||
10 | |||
11 | SRC_URI = "git://github.com/OpenSC/libp11.git" | ||
12 | SRCREV = "da725ab727342083478150a203a3c80c4551feb4" | ||
13 | |||
14 | S = "${WORKDIR}/git" | ||
15 | |||
16 | inherit autotools pkgconfig | ||
17 | |||
18 | # Currently, Makefile dependencies are incorrectly defined which causes build errors | ||
19 | # The number of jobs is high | ||
20 | # See https://github.com/OpenSC/libp11/issues/94 | ||
21 | PARALLEL_MAKE = "" | ||
22 | EXTRA_OECONF = "--disable-static" | ||
23 | |||
24 | do_install_append () { | ||
25 | rm -rf ${D}${libdir}/*.la | ||
26 | rm -rf ${D}${docdir}/${BPN} | ||
27 | } | ||
28 | |||
29 | FILES_${PN} = "${libdir}/engines/pkcs11.so \ | ||
30 | ${libdir}/engines/libpkcs11${SOLIBS} \ | ||
31 | ${libdir}/libp11${SOLIBS}" | ||
32 | |||
33 | FILES_${PN}-dev = " \ | ||
34 | ${libdir}/engines/libpkcs11${SOLIBSDEV} \ | ||
35 | ${libdir}/libp11${SOLIBSDEV} \ | ||
36 | ${libdir}/pkgconfig/libp11.pc \ | ||
37 | /usr/include" | ||
diff --git a/scripts/lib/wic/plugins/source/otaimage.py b/scripts/lib/wic/plugins/source/otaimage.py index eef0bb4..26cfb10 100644 --- a/scripts/lib/wic/plugins/source/otaimage.py +++ b/scripts/lib/wic/plugins/source/otaimage.py | |||
@@ -19,10 +19,12 @@ import logging | |||
19 | import os | 19 | import os |
20 | import sys | 20 | import sys |
21 | 21 | ||
22 | from wic.pluginbase import SourcePlugin | 22 | from wic.plugins.source.rawcopy import RawCopyPlugin |
23 | from wic.utils.misc import get_bitbake_var | 23 | from wic.utils.misc import get_bitbake_var |
24 | 24 | ||
25 | class OTAImagePlugin(SourcePlugin): | 25 | logger = logging.getLogger('wic') |
26 | |||
27 | class OTAImagePlugin(RawCopyPlugin): | ||
26 | """ | 28 | """ |
27 | Add an already existing filesystem image to the partition layout. | 29 | Add an already existing filesystem image to the partition layout. |
28 | """ | 30 | """ |
@@ -30,25 +32,6 @@ class OTAImagePlugin(SourcePlugin): | |||
30 | name = 'otaimage' | 32 | name = 'otaimage' |
31 | 33 | ||
32 | @classmethod | 34 | @classmethod |
33 | def do_install_disk(cls, disk, disk_name, cr, workdir, oe_builddir, | ||
34 | bootimg_dir, kernel_dir, native_sysroot): | ||
35 | """ | ||
36 | Called after all partitions have been prepared and assembled into a | ||
37 | disk image. Do nothing. | ||
38 | """ | ||
39 | pass | ||
40 | |||
41 | @classmethod | ||
42 | def do_configure_partition(cls, part, source_params, cr, cr_workdir, | ||
43 | oe_builddir, bootimg_dir, kernel_dir, | ||
44 | native_sysroot): | ||
45 | """ | ||
46 | Called before do_prepare_partition(). Possibly prepare | ||
47 | configuration files of some sort. | ||
48 | """ | ||
49 | pass | ||
50 | |||
51 | @classmethod | ||
52 | def do_prepare_partition(cls, part, source_params, cr, cr_workdir, | 35 | def do_prepare_partition(cls, part, source_params, cr, cr_workdir, |
53 | oe_builddir, bootimg_dir, kernel_dir, | 36 | oe_builddir, bootimg_dir, kernel_dir, |
54 | rootfs_dir, native_sysroot): | 37 | rootfs_dir, native_sysroot): |
@@ -65,5 +48,10 @@ class OTAImagePlugin(SourcePlugin): | |||
65 | src = bootimg_dir + "/" + get_bitbake_var("IMAGE_LINK_NAME") + ".otaimg" | 48 | src = bootimg_dir + "/" + get_bitbake_var("IMAGE_LINK_NAME") + ".otaimg" |
66 | 49 | ||
67 | logger.debug('Preparing partition using image %s' % (src)) | 50 | logger.debug('Preparing partition using image %s' % (src)) |
68 | part.prepare_rootfs_from_fs_image(cr_workdir, src, "") | 51 | source_params['file'] = src |
52 | |||
53 | super(OTAImagePlugin, cls).do_prepare_partition(part, source_params, | ||
54 | cr, cr_workdir, oe_builddir, | ||
55 | bootimg_dir, kernel_dir, | ||
56 | rootfs_dir, native_sysroot) | ||
69 | 57 | ||
diff --git a/scripts/qemucommand.py b/scripts/qemucommand.py new file mode 100644 index 0000000..82a9540 --- /dev/null +++ b/scripts/qemucommand.py | |||
@@ -0,0 +1,127 @@ | |||
1 | from os.path import exists, join, realpath, abspath | ||
2 | from os import listdir | ||
3 | import random | ||
4 | import socket | ||
5 | from subprocess import check_output, CalledProcessError | ||
6 | |||
7 | EXTENSIONS = { | ||
8 | 'intel-corei7-64': 'wic', | ||
9 | 'qemux86-64': 'otaimg' | ||
10 | } | ||
11 | |||
12 | |||
13 | def find_local_port(start_port): | ||
14 | """" | ||
15 | Find the next free TCP port after 'start_port'. | ||
16 | """ | ||
17 | |||
18 | for port in range(start_port, start_port + 10): | ||
19 | try: | ||
20 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
21 | s.bind(('', port)) | ||
22 | return port | ||
23 | except socket.error: | ||
24 | print("Skipping port %d" % port) | ||
25 | finally: | ||
26 | s.close() | ||
27 | raise Exception("Could not find a free TCP port") | ||
28 | |||
29 | |||
30 | def random_mac(): | ||
31 | """Return a random Ethernet MAC address | ||
32 | @link https://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml#ethernet-numbers-2 | ||
33 | """ | ||
34 | head = "ca:fe:" | ||
35 | hex_digits = '0123456789abcdef' | ||
36 | tail = ':'.join([random.choice(hex_digits) + random.choice(hex_digits) for _ in range(4)]) | ||
37 | return head + tail | ||
38 | |||
39 | |||
40 | class QemuCommand(object): | ||
41 | def __init__(self, args): | ||
42 | if args.machine: | ||
43 | self.machine = args.machine | ||
44 | else: | ||
45 | machines = listdir(args.dir) | ||
46 | if len(machines) == 1: | ||
47 | self.machine = machines[0] | ||
48 | else: | ||
49 | raise ValueError("Could not autodetect machine type from %s" % args.dir) | ||
50 | if args.efi: | ||
51 | self.bios = 'OVMF.fd' | ||
52 | else: | ||
53 | uboot = abspath(join(args.dir, self.machine, 'u-boot-qemux86-64.rom')) | ||
54 | if not exists(uboot): | ||
55 | raise ValueError("U-Boot image %s does not exist" % uboot) | ||
56 | self.bios = uboot | ||
57 | if exists(args.imagename): | ||
58 | image = args.imagename | ||
59 | else: | ||
60 | ext = EXTENSIONS.get(self.machine, 'wic') | ||
61 | image = join(args.dir, self.machine, '%s-%s.%s' % (args.imagename, self.machine, ext)) | ||
62 | self.image = realpath(image) | ||
63 | if not exists(self.image): | ||
64 | raise ValueError("OS image %s does not exist" % self.image) | ||
65 | if args.mac: | ||
66 | self.mac_address = args.mac | ||
67 | else: | ||
68 | self.mac_address = random_mac() | ||
69 | self.serial_port = find_local_port(8990) | ||
70 | self.ssh_port = find_local_port(2222) | ||
71 | if args.kvm is None: | ||
72 | # Autodetect KVM using 'kvm-ok' | ||
73 | try: | ||
74 | check_output(['kvm-ok']) | ||
75 | self.kvm = True | ||
76 | except CalledProcessError: | ||
77 | self.kvm = False | ||
78 | else: | ||
79 | self.kvm = args.kvm | ||
80 | self.gui = not args.no_gui | ||
81 | self.gdb = args.gdb | ||
82 | self.pcap = args.pcap | ||
83 | self.overlay = args.overlay | ||
84 | |||
85 | def command_line(self): | ||
86 | netuser = 'user,hostfwd=tcp:0.0.0.0:%d-:22,restrict=off' % self.ssh_port | ||
87 | if self.gdb: | ||
88 | netuser += ',hostfwd=tcp:0.0.0.0:2159-:2159' | ||
89 | cmdline = [ | ||
90 | "qemu-system-x86_64", | ||
91 | "-bios", self.bios | ||
92 | ] | ||
93 | if not self.overlay: | ||
94 | cmdline += ["-drive", "file=%s,if=ide,format=raw,snapshot=on" % self.image] | ||
95 | cmdline += [ | ||
96 | "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port, | ||
97 | "-m", "1G", | ||
98 | "-usb", | ||
99 | "-usbdevice", "tablet", | ||
100 | "-show-cursor", | ||
101 | "-vga", "std", | ||
102 | "-net", netuser, | ||
103 | "-net", "nic,macaddr=%s" % self.mac_address | ||
104 | ] | ||
105 | if self.pcap: | ||
106 | cmdline += ['-net', 'dump,file=' + self.pcap] | ||
107 | if self.gui: | ||
108 | cmdline += ["-serial", "stdio"] | ||
109 | else: | ||
110 | cmdline.append('-nographic') | ||
111 | if self.kvm: | ||
112 | cmdline.append('-enable-kvm') | ||
113 | else: | ||
114 | cmdline += ['-cpu', 'Haswell'] | ||
115 | if self.overlay: | ||
116 | cmdline.append(self.overlay) | ||
117 | return cmdline | ||
118 | |||
119 | def img_command_line(self): | ||
120 | cmdline = [ | ||
121 | "qemu-img", "create", | ||
122 | "-o", "backing_file=%s" % self.image, | ||
123 | "-f", "qcow2", | ||
124 | self.overlay] | ||
125 | return cmdline | ||
126 | |||
127 | |||
diff --git a/scripts/run-qemu-ota b/scripts/run-qemu-ota index 5334814..56e4fbc 100755 --- a/scripts/run-qemu-ota +++ b/scripts/run-qemu-ota | |||
@@ -2,126 +2,12 @@ | |||
2 | 2 | ||
3 | from argparse import ArgumentParser | 3 | from argparse import ArgumentParser |
4 | from subprocess import Popen | 4 | from subprocess import Popen |
5 | from os.path import exists, join, realpath | 5 | from os.path import exists |
6 | from os import listdir | ||
7 | import random | ||
8 | import sys | 6 | import sys |
9 | import socket | 7 | from qemucommand import QemuCommand |
10 | 8 | ||
11 | DEFAULT_DIR = 'tmp/deploy/images' | 9 | DEFAULT_DIR = 'tmp/deploy/images' |
12 | 10 | ||
13 | EXTENSIONS = { | ||
14 | 'intel-corei7-64': 'wic', | ||
15 | 'qemux86-64': 'otaimg' | ||
16 | } | ||
17 | |||
18 | |||
19 | def find_local_port(start_port): | ||
20 | """" | ||
21 | Find the next free TCP port after 'start_port'. | ||
22 | """ | ||
23 | |||
24 | for port in range(start_port, start_port + 10): | ||
25 | try: | ||
26 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
27 | s.bind(('', port)) | ||
28 | return port | ||
29 | except socket.error: | ||
30 | print("Skipping port %d" % port) | ||
31 | finally: | ||
32 | s.close() | ||
33 | raise Exception("Could not find a free TCP port") | ||
34 | |||
35 | |||
36 | def random_mac(): | ||
37 | """Return a random Ethernet MAC address | ||
38 | @link https://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml#ethernet-numbers-2 | ||
39 | """ | ||
40 | head = "ca:fe:" | ||
41 | hex_digits = '0123456789abcdef' | ||
42 | tail = ':'.join([random.choice(hex_digits) + random.choice(hex_digits) for _ in range(4)]) | ||
43 | return head + tail | ||
44 | |||
45 | |||
46 | class QemuCommand(object): | ||
47 | def __init__(self, args): | ||
48 | if args.machine: | ||
49 | self.machine = args.machine | ||
50 | else: | ||
51 | machines = listdir(args.dir) | ||
52 | if len(machines) == 1: | ||
53 | self.machine = machines[0] | ||
54 | else: | ||
55 | raise ValueError("Could not autodetect machine type from %s" % args.dir) | ||
56 | if args.efi: | ||
57 | self.bios = 'OVMF.fd' | ||
58 | else: | ||
59 | uboot = join(args.dir, self.machine, 'u-boot-qemux86-64.rom') | ||
60 | if not exists(uboot): | ||
61 | raise ValueError("U-Boot image %s does not exist" % uboot) | ||
62 | self.bios = uboot | ||
63 | if exists(args.imagename): | ||
64 | image = args.imagename | ||
65 | else: | ||
66 | ext = EXTENSIONS.get(self.machine, 'wic') | ||
67 | image = join(args.dir, self.machine, '%s-%s.%s' % (args.imagename, self.machine, ext)) | ||
68 | self.image = realpath(image) | ||
69 | if not exists(self.image): | ||
70 | raise ValueError("OS image %s does not exist" % self.image) | ||
71 | if args.mac: | ||
72 | self.mac_address = args.mac | ||
73 | else: | ||
74 | self.mac_address = random_mac() | ||
75 | self.serial_port = find_local_port(8990) | ||
76 | self.ssh_port = find_local_port(2222) | ||
77 | self.kvm = not args.no_kvm | ||
78 | self.gui = not args.no_gui | ||
79 | self.gdb = args.gdb | ||
80 | self.pcap = args.pcap | ||
81 | self.overlay = args.overlay | ||
82 | |||
83 | def command_line(self): | ||
84 | netuser = 'user,hostfwd=tcp:0.0.0.0:%d-:22,restrict=off' % self.ssh_port | ||
85 | if self.gdb: | ||
86 | netuser += ',hostfwd=tcp:0.0.0.0:2159-:2159' | ||
87 | cmdline = [ | ||
88 | "qemu-system-x86_64", | ||
89 | "-bios", self.bios | ||
90 | ] | ||
91 | if not self.overlay: | ||
92 | cmdline += ["-drive", "file=%s,if=ide,format=raw,snapshot=on" % self.image] | ||
93 | cmdline += [ | ||
94 | "-serial", "tcp:127.0.0.1:%d,server,nowait" % self.serial_port, | ||
95 | "-m", "1G", | ||
96 | "-usb", | ||
97 | "-usbdevice", "tablet", | ||
98 | "-show-cursor", | ||
99 | "-vga", "std", | ||
100 | "-net", netuser, | ||
101 | "-net", "nic,macaddr=%s" % self.mac_address | ||
102 | ] | ||
103 | if self.pcap: | ||
104 | cmdline += ['-net', 'dump,file=' + self.pcap] | ||
105 | if self.gui: | ||
106 | cmdline += ["-serial", "stdio"] | ||
107 | else: | ||
108 | cmdline.append('-nographic') | ||
109 | if self.kvm: | ||
110 | cmdline.append('-enable-kvm') | ||
111 | else: | ||
112 | cmdline += ['-cpu', 'Haswell'] | ||
113 | if self.overlay: | ||
114 | cmdline.append(self.overlay) | ||
115 | return cmdline | ||
116 | |||
117 | def img_command_line(self): | ||
118 | cmdline = [ | ||
119 | "qemu-img", "create", | ||
120 | "-o", "backing_file=%s" % self.image, | ||
121 | "-f", "qcow2", | ||
122 | self.overlay] | ||
123 | return cmdline | ||
124 | |||
125 | 11 | ||
126 | def main(): | 12 | def main(): |
127 | parser = ArgumentParser(description='Run meta-updater image in qemu') | 13 | parser = ArgumentParser(description='Run meta-updater image in qemu') |
@@ -135,11 +21,18 @@ def main(): | |||
135 | 'OSTREE_BOOTLOADER = "grub" and OVMF.fd firmware to be installed (try "apt install ovmf")', | 21 | 'OSTREE_BOOTLOADER = "grub" and OVMF.fd firmware to be installed (try "apt install ovmf")', |
136 | action='store_true') | 22 | action='store_true') |
137 | parser.add_argument('--machine', default=None, help="Target MACHINE") | 23 | parser.add_argument('--machine', default=None, help="Target MACHINE") |
138 | parser.add_argument('--no-kvm', help='Disable KVM in QEMU', action='store_true') | 24 | kvm_group = parser.add_argument_group() |
25 | kvm_group.add_argument('--force-kvm', help='Force use of KVM (default is to autodetect)', | ||
26 | dest='kvm', action='store_true', default=None) | ||
27 | kvm_group.add_argument('--no-kvm', help='Disable KVM in QEMU', | ||
28 | dest='kvm', action='store_false') | ||
139 | parser.add_argument('--no-gui', help='Disable GUI', action='store_true') | 29 | parser.add_argument('--no-gui', help='Disable GUI', action='store_true') |
140 | parser.add_argument('--gdb', help='Export gdbserver port 2159 from the image', action='store_true') | 30 | parser.add_argument('--gdb', help='Export gdbserver port 2159 from the image', action='store_true') |
141 | parser.add_argument('--pcap', default=None, help='Dump all network traffic') | 31 | parser.add_argument('--pcap', default=None, help='Dump all network traffic') |
142 | parser.add_argument('-o', '--overlay', type=str, metavar='file.cow', help='Use an overlay storage image file. Will be created if it does not exist. This option lets you have a persistent image without modifying the underlying image file, permitting multiple different persistent machines.') | 32 | parser.add_argument('-o', '--overlay', type=str, metavar='file.cow', |
33 | help='Use an overlay storage image file. Will be created if it does not exist. ' + | ||
34 | 'This option lets you have a persistent image without modifying the underlying image ' + | ||
35 | 'file, permitting multiple different persistent machines.') | ||
143 | parser.add_argument('-n', '--dry-run', help='Print qemu command line rather then run it', action='store_true') | 36 | parser.add_argument('-n', '--dry-run', help='Print qemu command line rather then run it', action='store_true') |
144 | args = parser.parse_args() | 37 | args = parser.parse_args() |
145 | try: | 38 | try: |
@@ -161,7 +54,7 @@ def main(): | |||
161 | if args.dry_run: | 54 | if args.dry_run: |
162 | print(" ".join(img_cmdline)) | 55 | print(" ".join(img_cmdline)) |
163 | else: | 56 | else: |
164 | Popen(img_cmdline) | 57 | Popen(img_cmdline).wait() |
165 | 58 | ||
166 | if args.dry_run: | 59 | if args.dry_run: |
167 | print(" ".join(cmdline)) | 60 | print(" ".join(cmdline)) |