diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..714ed21 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# EditorConfig is awesome: https://editorconfig.org/ + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = tab +tab_width = 4 +charset = utf-8 +trim_trailing_whitespace = true + +[*.yml] +tab_width = 2 + +[*.md] +tab_width = 2 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index d867328..3838729 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -12,31 +12,31 @@ assignees: '' - -This is a: **FILL ME IN** +This is a: **FILL ME IN** ## Details ## Related Issues -- [ ] I have searched this repository/Pi-hole forums for existing issues and pull requests that look similar +- [ ] I have searched this repository/Pi-hole forums for existing issues and pull requests that look similar -## How to reproduce the issue +## How to reproduce the issue 1. Environment data * Operating System: **ENTER HERE** * Hardware: * Kernel Architecture: - * Docker Install Info and version: + * Docker Install Info and version: - Software source: - Supplimentary Software: * Hardware architecture: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 62d5533..519fc92 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -9,4 +9,4 @@ contact_links: - name: Documentation url: https://docs.pi-hole.net about: Documentation and guides. - + diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 09030cc..b375cf3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,7 +2,7 @@ version: 2 updates: # Maintain dependencies for GitHub Actions - package-ecosystem: "github-actions" - directories: + directories: - "/" schedule: interval: "weekly" diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index 4840265..b280d73 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -12,7 +12,7 @@ on: env: dockerhub: ${{ secrets.DOCKERHUB_NAMESPACE }}/pihole ghcr: ghcr.io/${{ github.repository_owner }}/pihole - components_branch: ${{ github.event_name == 'schedule' && 'development' || 'master' }} + components_branch: ${{ github.event_name == 'release' && 'master' || 'development' }} jobs: build: @@ -33,72 +33,77 @@ jobs: runner: ubuntu-24.04-arm - platform: linux/riscv64 runner: ubuntu-24.04-arm - + steps: - name: Prepare name for digest up/download run: | platform=${{ matrix.platform }} echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV - - name: Checkout Repo + - &checkout-repo + name: Checkout Repo if: github.event_name != 'schedule' - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0 - - name: Checkout dev branch if scheduled + - &checkout-dev + name: Checkout dev branch if scheduled if: github.event_name == 'schedule' - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0 with: ref: development - - name: Docker meta + - &docker-meta + name: Docker meta id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f #v5.8.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} images: | ${{ env.dockerhub }} - ${{ env.ghcr }} + ${{ env.ghcr }} flavor: | latest=${{ startsWith(github.ref, 'refs/tags/') }} tags: | type=schedule,pattern=nightly - type=ref,event=branch,enable=${{ github.event_name != 'schedule' }} + type=raw,value=nightly,enable=${{ github.event_name == 'push' }} type=ref,event=tag - - + - &login-dockerhub name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef #v3.6.0 with: registry: docker.io username: ${{ secrets.DOCKERHUB_USER }} password: ${{ secrets.DOCKERHUB_PASS }} - - + + - &login-ghcr name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef #v3.6.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 #v3.6.0 with: platforms: ${{ matrix.platform}} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - &setup-buildx + name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 #v3.11.1 - name: Build container and push by digest id: build - uses: docker/build-push-action@v6 + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 #v6.18.0 with: context: ./src/ platforms: ${{ matrix.platform }} build-args: | - PIHOLE_DOCKER_TAG=${{ steps.meta.outputs.version }} + PIHOLE_DOCKER_TAG=${{ steps.meta.outputs.version }} FTL_BRANCH=${{ env.components_branch }} CORE_BRANCH=${{ env.components_branch }} - WEB_BRANCH=${{ env.components_branch }} + WEB_BRANCH=${{ env.components_branch }} PADD_BRANCH=${{ env.components_branch }} labels: ${{ steps.meta.outputs.labels }} outputs: | @@ -111,7 +116,7 @@ jobs: touch "/tmp/digests/${digest_docker#sha256:}" - name: Upload digest - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 #v5.0.0 with: name: digests-${{ env.PLATFORM_PAIR }} path: /tmp/digests/* @@ -126,55 +131,20 @@ jobs: needs: - build steps: - - name: Checkout Repo - if: github.event_name != 'schedule' - uses: actions/checkout@v4 - - - name: Checkout dev branch if scheduled - if: github.event_name == 'schedule' - uses: actions/checkout@v4 - with: - ref: development + - *checkout-repo + - *checkout-dev - name: Download digests - uses: actions/download-artifact@v4 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 #v6.0.0 with: path: /tmp/digests pattern: digests-* merge-multiple: true - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - images: | - ${{ env.dockerhub }} - ${{ env.ghcr }} - flavor: | - latest=${{ startsWith(github.ref, 'refs/tags/') }} - tags: | - type=schedule,pattern=nightly - type=ref,event=branch,enable=${{ github.event_name != 'schedule' }} - type=ref,event=tag - - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - registry: docker.io - username: ${{ secrets.DOCKERHUB_USER }} - password: ${{ secrets.DOCKERHUB_PASS }} - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} + - *setup-buildx + - *docker-meta + - *login-dockerhub + - *login-ghcr - name: Create manifest list and push (DockerHub and GitHub Container Registry) working-directory: /tmp/digests @@ -187,4 +157,4 @@ jobs: - name: Inspect images run: | docker buildx imagetools inspect ${{ env.dockerhub }}:${{ steps.meta.outputs.version }} - docker buildx imagetools inspect ${{ env.ghcr }}:${{ steps.meta.outputs.version }} \ No newline at end of file + docker buildx imagetools inspect ${{ env.ghcr }}:${{ steps.meta.outputs.version }} diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index dd72189..7fea793 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -25,16 +25,16 @@ jobs: CI_ARCH: ${{ matrix.platform }} steps: - name: Checkout Repo - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0 - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 #v3.6.0 - name: Set up Python - uses: actions/setup-python@v5.6.0 + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c #v6.0.0 with: python-version: "3.13" - + - name: Run black formatter run: | pip install black diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 2f6e519..b40dab6 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -10,9 +10,9 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0 - name: Spell-Checking - uses: codespell-project/actions-codespell@master + uses: codespell-project/actions-codespell@406322ec52dd7b488e48c1c4b82e2a8b3a1bf630 #v2.1 with: ignore_words_file: .codespellignore diff --git a/.github/workflows/editorconfig.yml b/.github/workflows/editorconfig.yml new file mode 100644 index 0000000..33c2d5c --- /dev/null +++ b/.github/workflows/editorconfig.yml @@ -0,0 +1,18 @@ +name: Editorconfig-Checker +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +jobs: + editorconfig-checker: + if: github.event.pull_request.draft == false + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0 + + - name: Get editorconfig-checker + uses: editorconfig-checker/action-editorconfig-checker@4b6cd6190d435e7e084fb35e36a096e98506f7b9 # tag v2. is really out of date + + - name: Run editorconfig-checker + run: editorconfig-checker diff --git a/.github/workflows/housekeeping.yml b/.github/workflows/housekeeping.yml index 9090099..c2acdf7 100644 --- a/.github/workflows/housekeeping.yml +++ b/.github/workflows/housekeeping.yml @@ -1,6 +1,8 @@ -name: housekeeping +name: Remove untagged images from registry on: - workflow_dispatch: + workflow_dispatch: + schedule: + - cron: "0 0 * * *" jobs: housekeeping: @@ -8,11 +10,11 @@ jobs: steps: - name: Delete all containers from repository without tags - uses: Chizkiyahu/delete-untagged-ghcr-action@v6 + uses: Chizkiyahu/delete-untagged-ghcr-action@68758dd8caf1d9dbaed1fe9cc1a1f8fcea1c4cf0 #v6.1.0 with: token: ${{ secrets.PAT_TOKEN }} repository_owner: ${{ github.repository_owner }} repository: ${{ github.repository }} untagged_only: true owner_type: org # or user - except_untagged_multiplatform: true \ No newline at end of file + except_untagged_multiplatform: true diff --git a/.github/workflows/merge-conflict.yml b/.github/workflows/merge-conflict.yml index ea30b65..c7ceb93 100644 --- a/.github/workflows/merge-conflict.yml +++ b/.github/workflows/merge-conflict.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check if PRs are have merge conflicts - uses: eps1lon/actions-label-merge-conflict@v3.0.3 + uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 #v3.0.3 with: dirtyLabel: "Merge Conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index fb4d698..e01bf2c 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -17,7 +17,7 @@ jobs: issues: write steps: - - uses: actions/stale@v9.1.0 + - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 #v10.1.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 30 @@ -41,7 +41,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0 - name: Remove 'stale' label run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }} env: diff --git a/.github/workflows/stale_pr.yml b/.github/workflows/stale_pr.yml index 47986f9..bb13d67 100644 --- a/.github/workflows/stale_pr.yml +++ b/.github/workflows/stale_pr.yml @@ -17,7 +17,7 @@ jobs: pull-requests: write steps: - - uses: actions/stale@v9.1.0 + - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 #v10.1.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} # Do not automatically mark PR/issue as stale diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index 28dd1b5..67f993a 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'internal' env: diff --git a/.gitignore b/.gitignore index 0b0d977..3a9365f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,9 +13,11 @@ docker-compose.yml etc-dnsmasq.d/ etc-pihole/ var-log/ +.vscode/ +.pytest_cache/ # WIP/test stuff doco.yml # Ignore FTL Binary if it exists -src/pihole-FTL \ No newline at end of file +src/pihole-FTL diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index de794da..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "github-actions.workflows.pinned.workflows": [ - ".github/workflows/v6-alpine-play.yml" - ] -} \ No newline at end of file diff --git a/README.md b/README.md index 9e9b07e..73feb15 100644 --- a/README.md +++ b/README.md @@ -200,12 +200,11 @@ Release notes will always contain full details of changes in the container, incl | tag | description |---------------------|--------------------------------------------------------------------------------------------------------------------------------------------| -| `latest` | Always latest release | +| `latest` | Always the latest release | | `2022.04.0` | Date-based release | | `2022.04.1` | Second release in a given month | -| `development` | Similar to `latest`, but for the development branch (pushed occasionally) | | `*beta` | Early beta releases of upcoming versions - here be dragons | -| `nightly` | Like `development` but pushed every night and pulls from the latest `development` branches of the core Pi-hole components (Pi-hole, web, FTL) | +| `nightly` | Built and pushed whenever there are changes on the `development` branch and additionally produced by the scheduled nightly job. These are the most experimental development images and may change frequently | ## Upgrading, Persistence, and Customizations diff --git a/build.sh b/build.sh index 7f8d3cf..c79a674 100755 --- a/build.sh +++ b/build.sh @@ -5,7 +5,7 @@ usage() { echo "Usage: $0 [-l] [-f ] [-c ] [-w ] [-t ] [use_cache]" echo "Options:" echo " -f, --ftlbranch Specify FTL branch (cannot be used in conjunction with -l)" - echo " -c, --corebranch Specify Core branch" + echo " -c, --corebranch Specify Core branch" echo " -w, --webbranch Specify Web branch" echo " -p, --paddbranch Specify PADD branch" echo " -t, --tag Specify Docker image tag (default: pihole:local)" @@ -91,7 +91,7 @@ while [[ $# -gt 0 ]]; do DOCKER_BUILD_CMD+=" --build-arg CORE_BRANCH=$CORE_BRANCH" shift shift - ;; + ;; -w | --webbranch) WEB_BRANCH="$2" check_branch_exists "web" "$WEB_BRANCH" "$WEB_FORK" diff --git a/examples/docker-compose-caddy-proxy.yml b/examples/docker-compose-caddy-proxy.yml index 217f6be..1eabd67 100644 --- a/examples/docker-compose-caddy-proxy.yml +++ b/examples/docker-compose-caddy-proxy.yml @@ -34,13 +34,13 @@ services: # Set the appropriate timezone for your location (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones), e.g: TZ: 'Europe/London' # Set a password to access the web interface. Not setting one will result in a random password being assigned - FTLCONF_webserver_api_password: 'correct horse battery staple' + FTLCONF_webserver_api_password: 'correct horse battery staple' # Volumes store your data between container upgrades volumes: # For persisting Pi-hole's databases and common configuration file - './etc-pihole:/etc/pihole' # Uncomment the below if you have custom dnsmasq config files that you want to persist. Not needed for most. - #- './etc-dnsmasq.d:/etc/dnsmasq.d' + #- './etc-dnsmasq.d:/etc/dnsmasq.d' cap_add: # See https://github.com/pi-hole/docker-pi-hole#note-on-capabilities # Required if you are using Pi-hole as your DHCP server, else not needed diff --git a/src/Dockerfile b/src/Dockerfile index e42ba5d..cb7a061 100644 --- a/src/Dockerfile +++ b/src/Dockerfile @@ -59,9 +59,9 @@ COPY crontab.txt /crontab.txt # Add PADD to the container, too. ADD --chmod=0755 https://raw.githubusercontent.com/${PADD_FORK}/PADD/${PADD_BRANCH}/padd.sh /usr/local/bin/padd -# download a the main repos from github +# download a the main repos from github # if the branch is master we clone the latest tag as sometimes the master branch contains meta changes that have not been tagged -# (we need to create a new "master" branch to avoid the "detached HEAD" state for the version check to work correctly) +# (we need to create a new "master" branch to avoid the "detached HEAD" state for the version check to work correctly) RUN clone_repo() { \ FORK="$1"; \ @@ -90,7 +90,8 @@ RUN cd /etc/.pihole && \ install -Dm755 -d /var/log/pihole && \ install -Dm755 -d /var/lib/logrotate && \ install -Dm755 -t /usr/local/bin pihole && \ - install -Dm644 ./advanced/bash-completion/pihole /etc/bash_completion.d/pihole && \ + install -Dm644 ./advanced/bash-completion/pihole.bash /etc/bash_completion.d/pihole && \ + install -Dm644 ./advanced/bash-completion/pihole-ftl.bash /etc/bash_completion.d/pihole-FTL && \ install -T -m 0755 ./advanced/Templates/pihole-FTL-prestart.sh /opt/pihole/pihole-FTL-prestart.sh && \ install -T -m 0755 ./advanced/Templates/pihole-FTL-poststop.sh /opt/pihole/pihole-FTL-poststop.sh && \ addgroup -S pihole -g ${PIHOLE_GID} && adduser -S pihole -G pihole -u ${PIHOLE_UID} && \ diff --git a/src/bash_functions.sh b/src/bash_functions.sh index 6120c1b..607f982 100644 --- a/src/bash_functions.sh +++ b/src/bash_functions.sh @@ -104,11 +104,9 @@ migrate_gravity() { echo " [i] Gravity migration checks" gravityDBfile=$(getFTLConfigValue files.gravity) - if [[ -z "${PYTEST}" ]]; then - if [[ ! -f /etc/pihole/adlists.list ]]; then - echo " [i] No adlist file found, creating one with a default blocklist" - echo "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" >/etc/pihole/adlists.list - fi + if [[ ! -f /etc/pihole/adlists.list ]]; then + echo " [i] No adlist file found, creating one with a default blocklist" + echo "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" >/etc/pihole/adlists.list fi if [ ! -f "${gravityDBfile}" ]; then diff --git a/src/start.sh b/src/start.sh index cff4ffc..fe7724a 100644 --- a/src/start.sh +++ b/src/start.sh @@ -1,12 +1,12 @@ #!/bin/bash if [ ! -x /bin/sh ]; then - echo "Executable test for /bin/sh failed. Your Docker version is too old to run Alpine 3.14+ and Pi-hole. You must upgrade Docker."; - exit 1; + echo "Executable test for /bin/sh failed. Your Docker version is too old to run Alpine 3.14+ and Pi-hole. You must upgrade Docker."; + exit 1; fi if [ "${PH_VERBOSE:-0}" -gt 0 ]; then - set -x + set -x fi trap stop TERM INT QUIT HUP ERR @@ -16,140 +16,137 @@ TRAP_TRIGGERED=0 start() { - # The below functions are all contained in bash_functions.sh - # shellcheck source=/dev/null - . /usr/bin/bash_functions.sh + # The below functions are all contained in bash_functions.sh + # shellcheck source=/dev/null + . /usr/bin/bash_functions.sh - # If the file /etc/pihole/setupVars.conf exists, but /etc/pihole/pihole.toml does not, then we are migrating v5->v6 - # FTL Will handle the migration of the config files - if [[ -f /etc/pihole/setupVars.conf && ! -f /etc/pihole/pihole.toml ]]; then - echo " [i] v5 files detected that have not yet been migrated to v6" + # If the file /etc/pihole/setupVars.conf exists, but /etc/pihole/pihole.toml does not, then we are migrating v5->v6 + # FTL Will handle the migration of the config files + if [[ -f /etc/pihole/setupVars.conf && ! -f /etc/pihole/pihole.toml ]]; then + echo " [i] v5 files detected that have not yet been migrated to v6" + echo "" + migrate_v5_configs + fi + + # =========================== + # Initial checks + # =========================== + + # If PIHOLE_UID is set, modify the pihole user's id to match + set_uid_gid + + # Configure FTL with any environment variables if needed + echo " [i] Starting FTL configuration" + ftl_config + + # Install additional packages inside the container if requested + install_additional_packages + + # Start crond for scheduled scripts (logrotate, pihole flush, gravity update etc) + start_cron + + # Install the logrotate config file + install_logrotate + + #migrate Gravity Database if needed: + migrate_gravity + + echo " [i] pihole-FTL pre-start checks" + # Run the post stop script to cleanup any remaining artifacts from a previous run + sh /opt/pihole/pihole-FTL-poststop.sh + + fix_capabilities + sh /opt/pihole/pihole-FTL-prestart.sh + + echo " [i] Starting pihole-FTL ($FTL_CMD) as ${DNSMASQ_USER}" echo "" - migrate_v5_configs - fi - # =========================== - # Initial checks - # =========================== + capsh --user="${DNSMASQ_USER}" --keep=1 -- -c "/usr/bin/pihole-FTL $FTL_CMD >/dev/null" & + # Notes on above: + # - DNSMASQ_USER default of pihole is in Dockerfile & can be overwritten by runtime container env + # - /var/log/pihole/pihole*.log has FTL's output that no-daemon would normally print in FG too + # prevent duplicating it in docker logs by sending to dev null - # If PIHOLE_UID is set, modify the pihole user's id to match - set_uid_gid + # We need the PID of the capsh process so that we can wait for it to finish + CAPSH_PID=$! - # Configure FTL with any environment variables if needed - echo " [i] Starting FTL configuration" - ftl_config + # Wait until the log file exists before continuing + while [ ! -f /var/log/pihole/FTL.log ]; do + sleep 0.5 + done - # Install additional packages inside the container if requested - install_additional_packages + # Wait until the FTL log contains the "FTL started" message before continuing, timeout after 10 seconds + # exit if we do not find it + pihole-FTL wait-for '########## FTL started' /var/log/pihole/FTL.log 10 0 > /dev/null + if [ $? -ne 0 ]; then + echo " [✗] FTL did not start - stopping container" + exit 1 + fi - # Start crond for scheduled scripts (logrotate, pihole flush, gravity update etc) - start_cron + pihole updatechecker + local versionsOutput + versionsOutput=$(pihole -v) + echo " [i] Version info:" + printf "%b" "${versionsOutput}\\n" | sed 's/^/ /' + echo "" - # Install the logrotate config file - install_logrotate + if [ "${TAIL_FTL_LOG:-1}" -eq 1 ]; then + # Start tailing the FTL log from the most recent "FTL Started" message + # Get the line number + startFrom=$(grep -n '########## FTL started' /var/log/pihole/FTL.log | tail -1 | cut -d: -f1) + # Start the tail from the line number and background it + tail --follow=name -n +"${startFrom}" /var/log/pihole/FTL.log & + else + echo " [i] FTL log output is disabled. Remove the Environment variable TAIL_FTL_LOG, or set it to 1 to enable FTL log output." + fi - #migrate Gravity Database if needed: - migrate_gravity + # Wait for the capsh process (which spawned FTL) to finish + wait $CAPSH_PID + FTL_EXIT_CODE=$? - echo " [i] pihole-FTL pre-start checks" - # Run the post stop script to cleanup any remaining artifacts from a previous run - sh /opt/pihole/pihole-FTL-poststop.sh - fix_capabilities - sh /opt/pihole/pihole-FTL-prestart.sh - - echo " [i] Starting pihole-FTL ($FTL_CMD) as ${DNSMASQ_USER}" - echo "" - - capsh --user="${DNSMASQ_USER}" --keep=1 -- -c "/usr/bin/pihole-FTL $FTL_CMD >/dev/null" & - # Notes on above: - # - DNSMASQ_USER default of pihole is in Dockerfile & can be overwritten by runtime container env - # - /var/log/pihole/pihole*.log has FTL's output that no-daemon would normally print in FG too - # prevent duplicating it in docker logs by sending to dev null - - # We need the PID of the capsh process so that we can wait for it to finish - CAPSH_PID=$! - - # Wait until the log file exists before continuing - while [ ! -f /var/log/pihole/FTL.log ]; do - sleep 0.5 - done - - # Wait until the FTL log contains the "FTL started" message before continuing - while ! grep -q '########## FTL started' /var/log/pihole/FTL.log; do - sleep 0.5 - done - - pihole updatechecker - local versionsOutput - versionsOutput=$(pihole -v) - echo " [i] Version info:" - printf "%b" "${versionsOutput}\\n" | sed 's/^/ /' - echo "" - - if [ "${TAIL_FTL_LOG:-1}" -eq 1 ]; then - # Start tailing the FTL log from the most recent "FTL Started" message - # Get the line number - startFrom=$(grep -n '########## FTL started' /var/log/pihole/FTL.log | tail -1 | cut -d: -f1) - # Start the tail from the line number and background it - tail --follow=name -n +"${startFrom}" /var/log/pihole/FTL.log & - else - echo " [i] FTL log output is disabled. Remove the Environment variable TAIL_FTL_LOG, or set it to 1 to enable FTL log output." - fi - - # Wait for the capsh process (which spawned FTL) to finish - wait $CAPSH_PID - FTL_EXIT_CODE=$? - - - # If we are here, then FTL has exited. - # If the trap was triggered, then stop will have already been called - if [ $TRAP_TRIGGERED -eq 0 ]; then - # Pass the exit code through to the stop function - stop $FTL_EXIT_CODE - fi + # If we are here, then FTL has exited. + # If the trap was triggered, then stop will have already been called + if [ $TRAP_TRIGGERED -eq 0 ]; then + # Pass the exit code through to the stop function + stop $FTL_EXIT_CODE + fi } stop() { - local FTL_EXIT_CODE=$1 + local FTL_EXIT_CODE=$1 + + # if we have nothing in FTL_EXIT_CODE, then have been called by the trap. Close FTL and wait for the CAPSH_PID to finish + if [ -z "${FTL_EXIT_CODE}" ]; then + TRAP_TRIGGERED=1 + echo "" + echo " [i] Container stop requested..." + echo " [i] pihole-FTL is running - Attempting to shut it down cleanly" + echo "" + killall --signal 15 pihole-FTL + + wait $CAPSH_PID + FTL_EXIT_CODE=$? + fi + + # Wait for a few seconds to allow the FTL log tail to catch up before exiting the container + sleep 2 + + # ensure the exit code is an integer, if not set it to 1 + if ! [[ "${FTL_EXIT_CODE}" =~ ^[0-9]+$ ]]; then + FTL_EXIT_CODE=1 + fi + + sh /opt/pihole/pihole-FTL-poststop.sh - # if we have nothing in FTL_EXIT_CODE, then have been called by the trap. Close FTL and wait for the CAPSH_PID to finish - if [ -z "${FTL_EXIT_CODE}" ]; then - TRAP_TRIGGERED=1 echo "" - echo " [i] Container stop requested..." - echo " [i] pihole-FTL is running - Attempting to shut it down cleanly" + echo " [i] pihole-FTL exited with status $FTL_EXIT_CODE" + echo "" + echo " [i] Container will now stop or restart depending on your restart policy" + echo " https://docs.docker.com/engine/containers/start-containers-automatically/#use-a-restart-policy" echo "" - killall --signal 15 pihole-FTL - wait $CAPSH_PID - FTL_EXIT_CODE=$? - fi - - # Wait for a few seconds to allow the FTL log tail to catch up before exiting the container - sleep 2 - - # ensure the exit code is an integer, if not set it to 1 - if ! [[ "${FTL_EXIT_CODE}" =~ ^[0-9]+$ ]]; then - FTL_EXIT_CODE=1 - fi - - sh /opt/pihole/pihole-FTL-poststop.sh - - echo "" - echo " [i] pihole-FTL exited with status $FTL_EXIT_CODE" - echo "" - echo " [i] Container will now stop or restart depending on your restart policy" - echo " https://docs.docker.com/engine/containers/start-containers-automatically/#use-a-restart-policy" - echo "" - - # If we are running pytest, keep the container alive for a little longer - # to allow the tests to complete - if [[ ${PYTEST} ]]; then - sleep 10 - fi - - exit "${FTL_EXIT_CODE}" + exit "${FTL_EXIT_CODE}" } diff --git a/test/requirements.txt b/test/requirements.txt index 0cb6fa1..c3695c0 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -1,6 +1,6 @@ -pytest == 8.4.1 +pytest == 8.4.2 pytest-testinfra == 10.2.2 pytest-clarity == 1.0.1 -tox == 4.28.4 -# Not adding pytest-xdist as using pytest with n > 1 cores -# causes random issues with the emulated architectures \ No newline at end of file +tox == 4.32.0 +# Not adding pytest-xdist as using pytest with n > 1 cores +# causes random issues with the emulated architectures diff --git a/test/tests/conftest.py b/test/tests/conftest.py index e445f00..29ce56c 100644 --- a/test/tests/conftest.py +++ b/test/tests/conftest.py @@ -45,10 +45,6 @@ def docker(request): for env_var in env_vars: cmd.extend(["-e", env_var]) - # ensure PYTEST=1 is set - if not any("PYTEST=1" in arg for arg in cmd): - cmd.extend(["-e", "PYTEST=1"]) - # add default TZ if not already set if not any("TZ=" in arg for arg in cmd): cmd.extend(["-e", 'TZ="Europe/London"']) diff --git a/test/tests/test_general.py b/test/tests/test_general.py index d5fef0a..c08c3ae 100644 --- a/test/tests/test_general.py +++ b/test/tests/test_general.py @@ -49,19 +49,44 @@ def test_pihole_ftl_architecture(docker): assert platform in func.stdout -# Wait 5 seconds for startup, then kill the start.sh script -# Finally, grep the FTL log to see if it has been shut down cleanly -def test_pihole_ftl_clean_shutdown(docker): - func = docker.run( - """ - sleep 5 - killall --signal 15 start.sh - sleep 5 - grep 'terminated' /var/log/pihole/FTL.log - """ +# Wait for FTL to start up, then stop the container gracefully +# Finally, check the container logs to see if FTL was shut down cleanly +def test_pihole_ftl_starts_and_shuts_down_cleanly(docker): + import subprocess + import time + + # Get the container ID from the docker fixture + container_id = docker.backend.name + + # Wait for FTL to fully start up by checking logs + max_wait_time = 60 # Maximum wait time in seconds + start_time = time.time() + ftl_started = False + + while time.time() - start_time < max_wait_time: + result = subprocess.run( + ["docker", "logs", container_id], capture_output=True, text=True + ) + + if "########## FTL started" in result.stdout: + ftl_started = True + break + + time.sleep(1) # Check every second + + assert ftl_started, f"FTL did not start within {max_wait_time} seconds" + + # Stop the container gracefully (sends SIGTERM) + subprocess.run(["docker", "stop", container_id], check=True) + + # Get the container logs + result = subprocess.run( + ["docker", "logs", container_id], capture_output=True, text=True ) - assert "INFO: ########## FTL terminated after" in func.stdout - assert "(code 0)" in func.stdout + + # Check for clean shutdown messages in the logs + assert "INFO: ########## FTL terminated after" in result.stdout + assert "(code 0)" in result.stdout def test_cronfile_valid(docker): diff --git a/test/tox.ini b/test/tox.ini index 98e4cb8..5aa913d 100644 --- a/test/tox.ini +++ b/test/tox.ini @@ -7,10 +7,10 @@ deps = -rrequirements.txt passenv = CIPLATFORM setenv = COLUMNS=120 - PY_COLORS=1 + PY_COLORS=1 commands = # Build the Docker image for testing depending on the architecture, fall back to 'local' if not set # This allows us to run the tests on the host architecture if not on CI docker buildx build --load --platform={env:CIPLATFORM:local} --progress plain -f ../src/Dockerfile -t pihole:CI_container ../src/ # run the tests # # Not using > 1 cores as it causes random issues with the emulated architectures - pytest {posargs:-vv} ./tests/ \ No newline at end of file + pytest {posargs:-vv} ./tests/