From d7de2e7d057cbf98b58300b02f08ac00e5a26cfd Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Mon, 30 Oct 2023 16:33:28 -0600 Subject: [PATCH 1/5] continuous deployment --- .github/workflows/startos-iso.yaml | 43 +++++++++++++++++++++ Makefile | 3 ++ basename.sh | 2 +- build/registry/downloadIndexActionResult | 45 ++++++++++++++++++++++ build/registry/resync.cgi | 22 +++++++++++ build/registry/resyncRsyncRegistry | 8 ++-- build/registry/setOsCommitHash | 39 +++++++++++++++++++ build/registry/upload.cgi | 48 ++++++++++++++++++++++++ upload-ota.sh | 34 +++++++++++++++++ 9 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 build/registry/downloadIndexActionResult create mode 100644 build/registry/resync.cgi create mode 100644 build/registry/setOsCommitHash create mode 100644 build/registry/upload.cgi create mode 100755 upload-ota.sh diff --git a/.github/workflows/startos-iso.yaml b/.github/workflows/startos-iso.yaml index 6873b29cb..73bb9df59 100644 --- a/.github/workflows/startos-iso.yaml +++ b/.github/workflows/startos-iso.yaml @@ -31,6 +31,13 @@ on: - aarch64 - aarch64-nonfree - raspberrypi + deploy: + type: choice + description: Deploy + options: + - NONE + - alpha + - beta push: branches: - master @@ -191,3 +198,39 @@ jobs: name: ${{ matrix.platform }}.img path: results/*.img if: ${{ matrix.platform == 'raspberrypi' }} + + - name: Upload OTA to registry + run: >- + PLATFORM=${{ matrix.platform }} make upload-ota TARGET="${{ + fromJson('{ + "alpha": "alpha-registry-x.start9.com", + "beta": "beta-registry.start9.com", + }')[github.event.inputs.deploy] + }}" KEY="${{ + fromJson( + format('{ + "alpha": "{0}", + "beta": "{1}", + }', secrets.ALPHA_INDEX_KEY, secrets.BETA_INDEX_KEY) + )[github.event.inputs.deploy] + }}" + if: ${{ github.event.inputs.deploy != '' && github.event.inputs.deploy != 'NONE' }} + + index: + if: ${{ github.event.inputs.deploy != '' && github.event.inputs.deploy != 'NONE' }} + needs: [image] + steps: + - run: >- + curl "https://${{ + fromJson('{ + "alpha": "alpha-registry-x.start9.com", + "beta": "beta-registry.start9.com", + }')[github.event.inputs.deploy] + }}:8443/resync.cgi?key=${{ + fromJson( + format('{ + "alpha": "{0}", + "beta": "{1}", + }', secrets.ALPHA_INDEX_KEY, secrets.BETA_INDEX_KEY) + )[github.event.inputs.deploy] + }}" diff --git a/Makefile b/Makefile index 07a18aadb..583231f1b 100644 --- a/Makefile +++ b/Makefile @@ -158,6 +158,9 @@ emulate-reflash: $(ALL_TARGETS) $(MAKE) install REMOTE=$(REMOTE) SSHPASS=$(SSHPASS) DESTDIR=/media/embassy/next PLATFORM=$(PLATFORM) $(call ssh,"sudo touch /media/embassy/config/upgrade && sudo rm -f /media/embassy/config/disk.guid && sudo sync && sudo reboot") +upload-ota: results/$(BASENAME).squashfs + TARGET=$(TARGET) KEY=$(KEY) ./upload-ota.sh + build/lib/depends build/lib/conflicts: build/dpkg-deps/* build/dpkg-deps/generate.sh diff --git a/basename.sh b/basename.sh index 17eb62623..679faa5bc 100755 --- a/basename.sh +++ b/basename.sh @@ -2,7 +2,7 @@ cd "$(dirname "${BASH_SOURCE[0]}")" -PLATFORM=$(if [ -f ./PLATFORM.txt ]; then cat ./PLATFORM.txt; else echo unknown; fi) +PLATFORM="$(if [ -f ./PLATFORM.txt ]; then cat ./PLATFORM.txt; else echo unknown; fi)" VERSION="$(cat ./VERSION.txt)" GIT_HASH="$(cat ./GIT_HASH.txt)" if [[ "$GIT_HASH" =~ ^@ ]]; then diff --git a/build/registry/downloadIndexActionResult b/build/registry/downloadIndexActionResult new file mode 100644 index 000000000..4bda4c6b8 --- /dev/null +++ b/build/registry/downloadIndexActionResult @@ -0,0 +1,45 @@ +#!/bin/bash + +set -e + +RUN_ID=$1 + +if [ -z "$RUN_ID" ]; then + >&2 echo usage: $0 '' + exit 1 +fi + +TMP_DIR=/var/tmp/action-run-results/$RUN_ID + +rm -rf $TMP_DIR +mkdir -p $TMP_DIR + +cd $TMP_DIR + +for arch in x86_64 x86_64-nonfree aarch64 aarch64-nonfree raspberrypi; do + gh run download -R Start9Labs/start-os $RUN_ID -n $arch.squashfs +done + +VERSION= +HASH= +for file in $(ls *.squashfs); do + if [[ $file =~ ^startos-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?)-([a-f0-9]{7}(~[a-z-]+)?|unknown)_([a-z0-9_-]+).squashfs$ ]]; then + if [ -n "$VERSION" ] && [ "$VERSION" != "${BASH_REMATCH[1]}" ]; then + >&2 echo "VERSION MISMATCH: expected $VERSION got ${BASH_REMATCH[1]}" + exit 2 + fi + if [ -n "$HASH" ] && [ "$HASH" != "${BASH_REMATCH[3]}" ]; then + >&2 echo "HASH MISMATCH: expected $HASH got ${BASH_REMATCH[3]}" + exit 3 + fi + VERSION="${BASH_REMATCH[1]}" + HASH="${BASH_REMATCH[3]}" + fi +done + +mkdir -p /root/resources/eos/$VERSION +rm -rf /root/resources/eos/$VERSION/$HASH +mv $TMP_DIR /root/resources/eos/$VERSION/$HASH + +cd /root/resources/eos/$VERSION +setOsCommitHash $HASH \ No newline at end of file diff --git a/build/registry/resync.cgi b/build/registry/resync.cgi new file mode 100644 index 000000000..f8479824f --- /dev/null +++ b/build/registry/resync.cgi @@ -0,0 +1,22 @@ +#!/bin/bash + +declare -A params +while IFS='=' read -r -d '&' key value && [[ -n "$key" ]]; do + params["$key"]=$value +done <<<"${QUERY_STRING}&" + +index_key="${params['key']}" +if [ -z "$index_key" ] || [ "$index_key" != "$(cat /var/www/index_key.txt)" ]; then + echo "HTTP/1.1 401 UNAUTHORIZED" + echo "Content-Type: text/html" + echo + echo "UNAUTHORIZED" + exit +fi + +touch /tmp/resync + +echo "HTTP/1.1 200 OK" +echo "Content-Type: text/html" +echo +echo "OK: Upload successful" \ No newline at end of file diff --git a/build/registry/resyncRsyncRegistry b/build/registry/resyncRsyncRegistry index f3e803ff7..2f5aba510 100755 --- a/build/registry/resyncRsyncRegistry +++ b/build/registry/resyncRsyncRegistry @@ -6,12 +6,14 @@ # Then we are going to make sure that each of these files is then put on the rsyncd server # so the embassies can pull them down +date >> /var/log/resyncRsyncRegistry.runlog + cat > /etc/rsyncd.conf << RD uid = root gid = root use chroot = yes -max connections = 50 +max connections = 4 pid file = /var/run/rsyncd.pid exclude = lost+found/ timeout = 900 @@ -27,7 +29,7 @@ do filename=${dir##*/} version=$(echo $directory | sed -r 's/.*\///') version_dir="/srv/rsync/$version" - type=$(echo "$filename" | sed -r "s/^.*?\.(\w+)\.squashfs$/\1/") + type=$(echo "$filename" | sed -r "s/^.*?\.([a-z0-9_-]+)\.squashfs$/\1/") new_dir="$version_dir/$type" @@ -51,4 +53,4 @@ INSERTING done echo "Created rsyncd.conf file, restarting service" -systemctl restart rsync +systemctl restart rsync \ No newline at end of file diff --git a/build/registry/setOsCommitHash b/build/registry/setOsCommitHash new file mode 100644 index 000000000..8da761200 --- /dev/null +++ b/build/registry/setOsCommitHash @@ -0,0 +1,39 @@ +#!/bin/bash + +# Get the current directory +PWD=$(pwd) +HASH=$1 + +if [ -z "$HASH" ]; then + >&2 echo "usage: setOsCommitHash " + exit 1 +fi + +# Define the expected pattern for the directory +pattern="/root/resources/eos/" + +# Check if the current directory matches the pattern +if [[ $PWD =~ ^$pattern([0-9.]+)$ ]]; then + # Extract the version number from the directory path + version="${BASH_REMATCH[1]}" +else + >&2 echo "MUST BE IN OS VERSION DIRECTORY" + exit 1 +fi + +if ! [ -d "$HASH" ]; then + >&2 echo "$HASH: No such directory" + exit 1 +fi + +for file in $(ls $HASH/startos-$version-${HASH}_*.squashfs); do + if [[ $file =~ ^$HASH/startos-$version-${HASH}_([a-z0-9_-]+).squashfs$ ]]; then + arch="${BASH_REMATCH[1]}" + echo "Found arch $arch" + umount /srv/rsync/$version/$arch + rm eos.$arch.squashfs + ln -s $file eos.$arch.squashfs + fi +done + +resyncRsyncRegistry \ No newline at end of file diff --git a/build/registry/upload.cgi b/build/registry/upload.cgi new file mode 100644 index 000000000..b5dd79a82 --- /dev/null +++ b/build/registry/upload.cgi @@ -0,0 +1,48 @@ +#!/bin/bash + +declare -A params +while IFS='=' read -r -d '&' key value && [[ -n "$key" ]]; do + params["$key"]=$value +done <<<"${QUERY_STRING}&" + +index_key="${params['key']}" +if [ -z "$index_key" ] || [ "$index_key" != "$(cat /var/www/index_key.txt)" ]; then + echo "HTTP/1.1 401 UNAUTHORIZED" + echo "Content-Type: text/html" + echo + echo "UNAUTHORIZED" + exit +fi + +git_hash="${params['gitHash']}" +version="${params['version']}" +platform="${params['platform']}" +shasum="${params['shasum']}" +if [ -z "$git_hash" ] || [ -z "$version" ] || [ -z "$platform" ] || [ -z "$shasum" ]; then + echo "HTTP/1.1 400 BAD REQUEST" + echo "Content-Type: text/html" + echo + echo "BAD REQUEST: missing param" + exit +fi + +tmp_file=$(mktemp /var/tmp/tmp.XXXXXXXXXX.squashfs) +cat > $tmp_file + +if ! sha256sum $tmp_file | grep "$shasum"; then + rm $tmp_file + echo "HTTP/1.1 400 BAD REQUEST" + echo "Content-Type: text/html" + echo + echo "BAD REQUEST: shasum mismatch" +fi + +mkdir -p /var/www/resources/eos/${version}/${git_hash} +mv $tmp_file /var/www/resources/eos/${version}/${git_hash}/startos-${version}-${git_hash}_${platform}.squashfs +rm /var/www/resources/eos/${version}/eos.${platform}.squashfs +ln -rs /var/www/resources/eos/${version}/${git_hash}/startos-${version}-${git_hash}_${platform}.squashfs /var/www/resources/eos/${version}/eos.${platform}.squashfs + +echo "HTTP/1.1 200 OK" +echo "Content-Type: text/html" +echo +echo "OK: Upload successful" \ No newline at end of file diff --git a/upload-ota.sh b/upload-ota.sh new file mode 100755 index 000000000..7fe2dc9b1 --- /dev/null +++ b/upload-ota.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +set -e + +cd "$(dirname "${BASH_SOURCE[0]}")" + +if [ -z "$TARGET" ]; then + >&2 echo "TARGET is required" + exit 1 +fi + +if [ -z "$KEY" ]; then + >&2 echo "KEY is required" + exit 1 +fi + +PLATFORM="$(cat ./PLATFORM.txt)" +VERSION="$(cat ./VERSION.txt)" +GIT_HASH="$(cat ./GIT_HASH.txt)" +if [[ "$GIT_HASH" =~ ^@ ]]; then + GIT_HASH=unknown +else + GIT_HASH="$(echo -n "$GIT_HASH" | head -c 7)" +fi +STARTOS_ENV="$(cat ./ENVIRONMENT.txt)" +if [ -n "$STARTOS_ENV" ]; then + GIT_HASH="$GIT_HASH~${STARTOS_ENV}" +fi + +BASENAME="startos-${VERSION}-${GIT_HASH}_${PLATFORM}" + +SHASUM=$(sha256sum results/$BASENAME.squashfs | awk '{print $1}') + +curl -T results/$(BASENAME).squashfs "https://${TARGET}:8443/upload.cgi?key=${KEY}&gitHash=${GIT_HASH}&version=${VERSION}&platform=${PLATFORM}&shasum=${SHASUM}" \ No newline at end of file From 6626707d735d3b33b0afb16e845edee05fe22815 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Mon, 30 Oct 2023 16:36:29 -0600 Subject: [PATCH 2/5] fix --- .github/workflows/startos-iso.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/startos-iso.yaml b/.github/workflows/startos-iso.yaml index 73bb9df59..642576abf 100644 --- a/.github/workflows/startos-iso.yaml +++ b/.github/workflows/startos-iso.yaml @@ -219,6 +219,7 @@ jobs: index: if: ${{ github.event.inputs.deploy != '' && github.event.inputs.deploy != 'NONE' }} needs: [image] + runs-on: ubuntu-22.04 steps: - run: >- curl "https://${{ From e74aaf8dc016333cb19e7fb1971858748b509912 Mon Sep 17 00:00:00 2001 From: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com> Date: Tue, 31 Oct 2023 08:35:06 -0600 Subject: [PATCH 3/5] escape braces in format string --- .github/workflows/startos-iso.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/startos-iso.yaml b/.github/workflows/startos-iso.yaml index 642576abf..ecf15a54f 100644 --- a/.github/workflows/startos-iso.yaml +++ b/.github/workflows/startos-iso.yaml @@ -208,10 +208,10 @@ jobs: }')[github.event.inputs.deploy] }}" KEY="${{ fromJson( - format('{ + format('{{ "alpha": "{0}", "beta": "{1}", - }', secrets.ALPHA_INDEX_KEY, secrets.BETA_INDEX_KEY) + }}', secrets.ALPHA_INDEX_KEY, secrets.BETA_INDEX_KEY) )[github.event.inputs.deploy] }}" if: ${{ github.event.inputs.deploy != '' && github.event.inputs.deploy != 'NONE' }} @@ -229,9 +229,9 @@ jobs: }')[github.event.inputs.deploy] }}:8443/resync.cgi?key=${{ fromJson( - format('{ + format('{{ "alpha": "{0}", "beta": "{1}", - }', secrets.ALPHA_INDEX_KEY, secrets.BETA_INDEX_KEY) + }}', secrets.ALPHA_INDEX_KEY, secrets.BETA_INDEX_KEY) )[github.event.inputs.deploy] }}" From 3ac1e4ed2e22675a56e69ed7e41db007a739fa44 Mon Sep 17 00:00:00 2001 From: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:16:34 -0600 Subject: [PATCH 4/5] Update upload-ota.sh --- upload-ota.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upload-ota.sh b/upload-ota.sh index 7fe2dc9b1..9eafac033 100755 --- a/upload-ota.sh +++ b/upload-ota.sh @@ -31,4 +31,4 @@ BASENAME="startos-${VERSION}-${GIT_HASH}_${PLATFORM}" SHASUM=$(sha256sum results/$BASENAME.squashfs | awk '{print $1}') -curl -T results/$(BASENAME).squashfs "https://${TARGET}:8443/upload.cgi?key=${KEY}&gitHash=${GIT_HASH}&version=${VERSION}&platform=${PLATFORM}&shasum=${SHASUM}" \ No newline at end of file +curl -T results/${BASENAME}.squashfs "https://${TARGET}:8443/upload.cgi?key=${KEY}&gitHash=${GIT_HASH}&version=${VERSION}&platform=${PLATFORM}&shasum=${SHASUM}" \ No newline at end of file From 67f316b9e2659c7321b16b5ea9e81c76ec97c9f7 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Wed, 1 Nov 2023 11:17:41 -0600 Subject: [PATCH 5/5] curl fail on http error --- upload-ota.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upload-ota.sh b/upload-ota.sh index 9eafac033..7204486df 100755 --- a/upload-ota.sh +++ b/upload-ota.sh @@ -31,4 +31,4 @@ BASENAME="startos-${VERSION}-${GIT_HASH}_${PLATFORM}" SHASUM=$(sha256sum results/$BASENAME.squashfs | awk '{print $1}') -curl -T results/${BASENAME}.squashfs "https://${TARGET}:8443/upload.cgi?key=${KEY}&gitHash=${GIT_HASH}&version=${VERSION}&platform=${PLATFORM}&shasum=${SHASUM}" \ No newline at end of file +curl --fail-with-body -T results/${BASENAME}.squashfs "https://${TARGET}:8443/upload.cgi?key=${KEY}&gitHash=${GIT_HASH}&version=${VERSION}&platform=${PLATFORM}&shasum=${SHASUM}" \ No newline at end of file