diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..7972213 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: linuxserver diff --git a/.github/workflows/BuildImage.yml b/.github/workflows/BuildImage.yml new file mode 100644 index 0000000..f3cb65a --- /dev/null +++ b/.github/workflows/BuildImage.yml @@ -0,0 +1,53 @@ +name: Build Image + +on: [push, pull_request, workflow_dispatch] + +env: + ENDPOINT: "aptalca/restic" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4.1.6 + + - name: Versions + run: | + RESTIC_RELEASE=$(curl -sX GET "https://api.github.com/repos/restic/restic/releases/latest" \ + | jq -r '.tag_name' | sed 's|^v||') + AUTORESTIC_RELEASE=$(curl -sX GET "https://api.github.com/repos/cupcakearmy/autorestic/releases/latest" \ + | jq -r '.tag_name' | sed 's|^v||') + APP_VERSIONS="${RESTIC_RELEASE}-${AUTORESTIC_RELEASE}" + echo "APP_VERSIONS=${APP_VERSIONS}" >> $GITHUB_ENV + - name: Build image + run: | + docker build --no-cache --build-arg APP_VERSIONS=${APP_VERSIONS} -t ${{ github.sha }} . + - name: Tag image + if: ${{ github.ref == format('refs/heads/main') }} + run: | + docker tag ${{ github.sha }} ghcr.io/${ENDPOINT}:${{ github.sha }} + docker tag ${{ github.sha }} ghcr.io/${ENDPOINT}:${APP_VERSIONS} + docker tag ${{ github.sha }} ghcr.io/${ENDPOINT}:latest + docker tag ${{ github.sha }} ${ENDPOINT}:${{ github.sha }} + docker tag ${{ github.sha }} ${ENDPOINT}:${APP_VERSIONS} + docker tag ${{ github.sha }} ${ENDPOINT}:latest + - name: Login to GitHub Container Registry + if: ${{ github.ref == format('refs/heads/main') }} + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u aptalca --password-stdin + - name: Push tags to GitHub Container Registry + if: ${{ github.ref == format('refs/heads/main') }} + run: | + docker push ghcr.io/${ENDPOINT}:${{ github.sha }} + docker push ghcr.io/${ENDPOINT}:${APP_VERSIONS} + docker push ghcr.io/${ENDPOINT}:latest + - name: Login to DockerHub + if: ${{ github.ref == format('refs/heads/main') }} + run: | + echo ${{ secrets.DOCKERPASS }} | docker login -u aptalca --password-stdin + - name: Push tags to DockerHub + if: ${{ github.ref == format('refs/heads/main') }} + run: | + docker push ${ENDPOINT}:${{ github.sha }} + docker push ${ENDPOINT}:${APP_VERSIONS} + docker push ${ENDPOINT}:latest diff --git a/.github/workflows/permissions.yml b/.github/workflows/permissions.yml new file mode 100644 index 0000000..3d04963 --- /dev/null +++ b/.github/workflows/permissions.yml @@ -0,0 +1,10 @@ +name: Permission check +on: + pull_request: + paths: + - '**/run' + - '**/finish' + - '**/check' +jobs: + permission_check: + uses: linuxserver/github-workflows/.github/workflows/init-svc-executable-permissions.yml@v1 \ No newline at end of file diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml new file mode 100644 index 0000000..5f384ae --- /dev/null +++ b/.github/workflows/update.yml @@ -0,0 +1,100 @@ +name: Updater + +on: + schedule: + - cron: '30 1 * * *' + workflow_dispatch: + +env: + REPO: "restic" + +jobs: + base-updater: + runs-on: ubuntu-latest + steps: + - name: Check out repo + uses: actions/checkout@v3.1.0 + + - name: Check for updates and trigger + run: | + git config --local user.email "bot@aptalca.doot" + git config --local user.name "AptalcaBot" + DISTRO=$(cat Dockerfile | grep 'FROM' | sed 's|.*baseimage-\(.*\):.*|\1|') + TAG=$(cat Dockerfile | grep 'FROM' | sed 's|.*:\(.*\)|\1|') + token=$(curl -sX GET \ + "https://ghcr.io/token?scope=repository%3Alinuxserver%2Fbaseimage-${DISTRO}%3Apull" \ + | jq -r '.token') + multidigest=$(curl -s \ + --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + --header "Accept: application/vnd.oci.image.index.v1+json" \ + --header "Authorization: Bearer ${token}" \ + "https://ghcr.io/v2/linuxserver/baseimage-${DISTRO}/manifests/${TAG}") + multidigest=$(jq -r ".manifests[] | select(.platform.architecture == \"amd64\").digest?" <<< "${multidigest}") + EXTDIGEST=$(curl -s \ + --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + --header "Accept: application/vnd.oci.image.manifest.v1+json" \ + --header "Authorization: Bearer ${token}" \ + "https://ghcr.io/v2/linuxserver/baseimage-${DISTRO}/manifests/${multidigest}" \ + | jq -r '.config.digest') + if [ -z "${EXTDIGEST}" ]; then + echo "Unable to retrieve external digest. Skipping." + echo "Unable to retrieve external digest. Skipping." >> $GITHUB_STEP_SUMMARY + EXTDIGEST=$(cat baseimage-digest.txt) + else + echo "External digest retrieved: ${EXTDIGEST}" + echo "External digest retrieved: ${EXTDIGEST}" >> $GITHUB_STEP_SUMMARY + fi + LASTDIGEST=$(cat baseimage-digest.txt) + if [ "${LASTDIGEST}" != "${EXTDIGEST}" ]; then + echo "Last used baseimage digest: ${LASTDIGEST}" + echo "Baseimage seems to have been updated. Updating baseimage digest." + echo "Last used baseimage digest: ${LASTDIGEST}" >> $GITHUB_STEP_SUMMARY + echo "Baseimage seems to have been updated. Updating baseimage digest." >> $GITHUB_STEP_SUMMARY + echo -n "${EXTDIGEST}" > baseimage-digest.txt + BUILD_IMAGE="yes" + git add . || : + git commit -m '[bot] Updating baseimage digest' || : + git push || : + else + echo "Baseimage seems to be the same. Skipping." + fi + echo "Checking Restic/Autorestic for updates" + RESTIC_RELEASE=$(curl -sX GET "https://api.github.com/repos/restic/restic/releases/latest" \ + | jq -r '.tag_name' | sed 's|^v||') + AUTORESTIC_RELEASE=$(curl -sX GET "https://api.github.com/repos/cupcakearmy/autorestic/releases/latest" \ + | jq -r '.tag_name' | sed 's|^v||') + APP_VERSIONS="${RESTIC_RELEASE}-${AUTORESTIC_RELEASE}" + if [ -z "${APP_VERSIONS}" ] || [ "${APP_VERSIONS}" = "null" ]; then + echo "Unable to retrieve Restic/Autorestic versions. Skipping." + echo "Unable to retrieve Restic/Autorestic versions. Skipping." >> $GITHUB_STEP_SUMMARY + APP_VERSIONS=$(cat app_versions.txt) + else + echo "Restic/Autorestic versions retrieved: ${APP_VERSIONS}" + echo "Restic/Autorestic versions retrieved: ${APP_VERSIONS}" >> $GITHUB_STEP_SUMMARY + fi + APP_LAST_VERSIONS=$(cat app_versions.txt) + if [ "${APP_VERSIONS}" != "${APP_LAST_VERSIONS}" ]; then + echo "Last Restic/Autorestic versions: ${APP_LAST_VERSIONS}" + echo "Restic/Autorestic seem to have been updated. Updating versions." + echo "Last Restic/Autorestic versions: ${APP_LAST_VERSIONS}" >> $GITHUB_STEP_SUMMARY + echo "Restic/Autorestic seem to have been updated. Updating versions." >> $GITHUB_STEP_SUMMARY + echo -n "${APP_VERSIONS}" > app_versions.txt + BUILD_IMAGE="yes" + git add . || : + git commit -m '[bot] Updating Restic/Autorestic versions' || : + git push || : + else + echo "Restic/Autorestic versions seem to be the same. Skipping." + fi + if [ "${BUILD_IMAGE}" = "yes" ]; then + echo "Triggering new build!!" + echo "Triggering new build!!" >> $GITHUB_STEP_SUMMARY + curl -iX POST \ + -H "Authorization: token ${{ secrets.CR_PAT }}" \ + -H "Accept: application/vnd.github.v3+json" \ + -d "{\"ref\":\"refs/heads/main\"}" \ + https://api.github.com/repos/aptalca/${REPO}/actions/workflows/BuildImage.yml/dispatches + else + echo "No changes to either baseimage or Restic/Autorestic versions." + echo "No changes to either baseimage or Restic/Autorestic versions." >> $GITHUB_STEP_SUMMARY + fi diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9a5d969 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,37 @@ +FROM ghcr.io/linuxserver/baseimage-alpine:3.21 + +LABEL maintainer="aptalca" + +ARG APP_VERSIONS + +RUN \ + echo "**** install runtime packages ****" && \ + apk add --no-cache --upgrade \ + bzip2 \ + logrotate && \ + echo "**** install restic and autorestic ****" && \ + if [ -z "${APP_VERSIONS+x}" ]; then \ + RESTIC_RELEASE=$(curl -sX GET "https://api.github.com/repos/restic/restic/releases/latest" \ + | jq -r '.tag_name' | sed 's|^v||'); \ + AUTORESTIC_RELEASE=$(curl -sX GET "https://api.github.com/repos/cupcakearmy/autorestic/releases/latest" \ + | jq -r '.tag_name' | sed 's|^v||'); \ + else \ + RESTIC_RELEASE=$(echo "${APP_VERSIONS}" | sed 's|-.*||'); \ + AUTORESTIC_RELEASE=$(echo "${APP_VERSIONS}" | sed 's|.*-||'); \ + fi && \ + curl -fL "https://github.com/restic/restic/releases/download/v${RESTIC_RELEASE}/restic_${RESTIC_RELEASE}_linux_amd64.bz2" \ + | bzip2 -d > /usr/local/bin/restic && \ + curl -fL "https://github.com/cupcakearmy/autorestic/releases/download/v${AUTORESTIC_RELEASE}/autorestic_${AUTORESTIC_RELEASE}_linux_amd64.bz2" \ + | bzip2 -d > /usr/local/bin/autorestic && \ + chmod +x \ + /usr/local/bin/restic \ + /usr/local/bin/autorestic && \ + echo "**** fix logrotate ****" && \ + sed -i "s#/var/log/messages {}.*# #g" /etc/logrotate.conf && \ + sed -i 's,/usr/sbin/logrotate /etc/logrotate.conf,/usr/sbin/logrotate /etc/logrotate.conf -s /config/logrotate.status,g' \ + /etc/periodic/daily/logrotate && \ + rm -rf \ + /tmp/* + +# add local files +COPY /root / diff --git a/app-versions.txt b/app-versions.txt new file mode 100644 index 0000000..21ed525 --- /dev/null +++ b/app-versions.txt @@ -0,0 +1 @@ +1.1.1-1.1.1 \ No newline at end of file diff --git a/baseimage-digest.txt b/baseimage-digest.txt new file mode 100644 index 0000000..590d2ee --- /dev/null +++ b/baseimage-digest.txt @@ -0,0 +1 @@ +sha256:c8876cb1f6174d diff --git a/root/etc/crontabs/root b/root/etc/crontabs/root new file mode 100644 index 0000000..fca596b --- /dev/null +++ b/root/etc/crontabs/root @@ -0,0 +1,10 @@ +# do daily/weekly/monthly maintenance +# min hour day month weekday command +*/15 * * * * run-parts /etc/periodic/15min +0 * * * * run-parts /etc/periodic/hourly +0 2 * * * run-parts /etc/periodic/daily +0 3 * * 6 run-parts /etc/periodic/weekly +0 5 1 * * run-parts /etc/periodic/monthly +# autorestic +PATH="/usr/local/bin:/usr/bin:/bin" +#* * * * * autorestic -c /config/.autorestic.yml --ci cron --lean >> /config/logs/autorestic.log 2>&1 && chown abc:abc /config/logs/autorestic.log diff --git a/root/etc/logrotate.d/autoresticrotate b/root/etc/logrotate.d/autoresticrotate new file mode 100644 index 0000000..005e5f9 --- /dev/null +++ b/root/etc/logrotate.d/autoresticrotate @@ -0,0 +1,11 @@ +/config/logs/*.log { + weekly + rotate 52 + compress + delaycompress + nodateext + missingok + notifempty + sharedscripts + su abc abc +} diff --git a/root/etc/s6-overlay/s6-rc.d/init-adduser/branding b/root/etc/s6-overlay/s6-rc.d/init-adduser/branding new file mode 100644 index 0000000..04ba723 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/init-adduser/branding @@ -0,0 +1,17 @@ + +─────────────────────────────────────── +Brought to you by . . . + + _______ __ __ _______ ________ +| \| \ | \ \| \ +| ▓▓▓▓▓▓▓\ ▓▓ | ▓▓ ▓▓▓▓▓▓▓\ ▓▓▓▓▓▓▓▓ +| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓__ +| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ \ +| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓▓▓▓ +| ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓_____ +| ▓▓ ▓▓\▓▓ ▓▓ ▓▓ ▓▓ ▓▓ \ + \▓▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓▓ + + +Based on images from linuxserver.io +─────────────────────────────────────── diff --git a/root/etc/s6-overlay/s6-rc.d/init-config-end/dependencies.d/init-restic b/root/etc/s6-overlay/s6-rc.d/init-config-end/dependencies.d/init-restic new file mode 100644 index 0000000..e69de29 diff --git a/root/etc/s6-overlay/s6-rc.d/init-restic/dependencies.d/init-config b/root/etc/s6-overlay/s6-rc.d/init-restic/dependencies.d/init-config new file mode 100644 index 0000000..e69de29 diff --git a/root/etc/s6-overlay/s6-rc.d/init-restic/run b/root/etc/s6-overlay/s6-rc.d/init-restic/run new file mode 100755 index 0000000..a4ae9c9 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/init-restic/run @@ -0,0 +1,17 @@ +#!/usr/bin/with-contenv bash + +# create folders +mkdir -p \ + /config/{logs,crontabs} + +# copy default crontabs +[[ ! -f /config/crontabs/root ]] && \ + cp /etc/crontabs/root /config/crontabs/ + +# import user crontabs +rm /etc/crontabs/* +cp /config/crontabs/* /etc/crontabs/ + +# permissions +chown -R abc:abc \ + /config diff --git a/root/etc/s6-overlay/s6-rc.d/init-restic/type b/root/etc/s6-overlay/s6-rc.d/init-restic/type new file mode 100644 index 0000000..3d92b15 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/init-restic/type @@ -0,0 +1 @@ +oneshot \ No newline at end of file diff --git a/root/etc/s6-overlay/s6-rc.d/init-restic/up b/root/etc/s6-overlay/s6-rc.d/init-restic/up new file mode 100644 index 0000000..de089cc --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/init-restic/up @@ -0,0 +1 @@ +/etc/s6-overlay/s6-rc.d/init-restic/run \ No newline at end of file diff --git a/root/etc/s6-overlay/s6-rc.d/svc-cron/dependencies.d/init-services b/root/etc/s6-overlay/s6-rc.d/svc-cron/dependencies.d/init-services new file mode 100644 index 0000000..e69de29 diff --git a/root/etc/s6-overlay/s6-rc.d/svc-cron/run b/root/etc/s6-overlay/s6-rc.d/svc-cron/run new file mode 100755 index 0000000..29cd322 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/svc-cron/run @@ -0,0 +1,3 @@ +#!/usr/bin/with-contenv bash + +exec /usr/sbin/crond -f -S -l 5 -c /etc/crontabs diff --git a/root/etc/s6-overlay/s6-rc.d/svc-cron/type b/root/etc/s6-overlay/s6-rc.d/svc-cron/type new file mode 100644 index 0000000..1780f9f --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/svc-cron/type @@ -0,0 +1 @@ +longrun \ No newline at end of file diff --git a/root/etc/s6-overlay/s6-rc.d/user/contents.d/init-restic b/root/etc/s6-overlay/s6-rc.d/user/contents.d/init-restic new file mode 100644 index 0000000..e69de29 diff --git a/root/etc/s6-overlay/s6-rc.d/user/contents.d/svc-cron b/root/etc/s6-overlay/s6-rc.d/user/contents.d/svc-cron new file mode 100644 index 0000000..e69de29