From b41dd1bf8c66c7fbeff25cf7f10093ef7f6aece1 Mon Sep 17 00:00:00 2001 From: diginc Date: Mon, 18 Jul 2016 10:44:55 -0500 Subject: [PATCH 1/7] py.test now builds containers, travis py.test * Instead of using the docker_dev, py.test builds and runs containers * Travis-CI hopefully can run these same tests on PR/Merges now --- .travis.yml | 24 +++++++++++++----------- autotest | 1 + test/__init__.py | 0 test/conftest.py | 14 +++++++------- test/test_000_build_containers.py | 18 ++++++++++++++++++ 5 files changed, 39 insertions(+), 18 deletions(-) create mode 100755 autotest create mode 100644 test/__init__.py create mode 100644 test/test_000_build_containers.py diff --git a/.travis.yml b/.travis.yml index 46b023b..4890cb0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,14 @@ -sudo: required +language: python +python: + - "2.7" + - "3.2" + - "3.3" + - "3.4" + # does not have headers provided, please ask https://launchpad.net/~pypy/+archive/ppa + # maintainers to fix their pypy-dev package. + - "pypy" +# command to install dependencies +install: + - pip install -r requirements.txt -services: - - docker - -before_install: - - docker pull diginc/pi-hole:alpine - - docker pull diginc/pi-hole:debian - -script: - - docker build -f alpine.docker . - - docker build -f debian.docker . +script: py.test diff --git a/autotest b/autotest new file mode 100755 index 0000000..6ce3ed5 --- /dev/null +++ b/autotest @@ -0,0 +1 @@ +py.test -f test/ diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/conftest.py b/test/conftest.py index fadb839..749926f 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -17,7 +17,7 @@ def TestinfraBackend(request): def teardown(): check_output("docker rm -f %s", docker_id) - request.addfinalizer(teardown) + request.addfinalizer(teardown) return testinfra.get_backend("docker://" + docker_id) @@ -26,7 +26,7 @@ def pytest_generate_tests(metafunc): if "TestinfraBackend" in metafunc.fixturenames: mark_args = getattr(metafunc.function, "docker_args", None) - docker_args = [] + docker_args = [] if mark_args is not None: docker_args = docker_args + list(mark_args.args) @@ -36,14 +36,14 @@ def pytest_generate_tests(metafunc): images = mark_images.args mark_cmd = getattr(metafunc.function, "docker_cmd", None) - command = 'tail -f /dev/null' + command = 'tail -f /dev/null' if mark_cmd is not None: command = " ".join(mark_cmd.args) - docker_run_args = [] - for img in images: - docker_run_args.append('{} {} {}'.format(" ".join(docker_args), - img, command)) + docker_run_args = [] + for img in images: + docker_run_args.append('{} {} {}'.format(" ".join(docker_args), + img, command)) if getattr(metafunc.function, "persistent", None) is not None: scope = "session" else: diff --git a/test/test_000_build_containers.py b/test/test_000_build_containers.py new file mode 100644 index 0000000..ac9ae85 --- /dev/null +++ b/test/test_000_build_containers.py @@ -0,0 +1,18 @@ +''' This file starts with 000 to make it run first ''' +import pytest +import testinfra + +run_local = testinfra.get_backend( + "local://" +).get_module("Command").run + +@pytest.mark.parametrize("image,tag", [ + ( 'alpine.docker', 'diginc/pi-hole:alpine' ), + ( 'debian.docker', 'diginc/pi-hole:debian' ), +]) +def test_build_pihole_image(image, tag): + build_cmd = run_local('docker build -f {} -t {} .'.format(image, tag)) + if build_cmd.rc != 0: + print build_cmd.stdout + print build_cmd.stderr + assert build_cmd.rc == 0 From 1e5a8a276273627f29aa9bb7e27bba62078f293d Mon Sep 17 00:00:00 2001 From: diginc Date: Mon, 18 Jul 2016 11:17:50 -0500 Subject: [PATCH 2/7] can I mix docker with python? --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4890cb0..314cbc7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,6 @@ +sudo: required +services: + - docker language: python python: - "2.7" From e801bfb5bad0583dc3d21c556426b063220c39d0 Mon Sep 17 00:00:00 2001 From: diginc Date: Mon, 18 Jul 2016 12:12:25 -0500 Subject: [PATCH 3/7] probably only need python 2.7 --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 314cbc7..bcfe610 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,13 +4,6 @@ services: language: python python: - "2.7" - - "3.2" - - "3.3" - - "3.4" - # does not have headers provided, please ask https://launchpad.net/~pypy/+archive/ppa - # maintainers to fix their pypy-dev package. - - "pypy" -# command to install dependencies install: - pip install -r requirements.txt From d40ee186896df5369516b0ffe93677cafd68b85f Mon Sep 17 00:00:00 2001 From: diginc Date: Tue, 2 Aug 2016 22:29:52 -0500 Subject: [PATCH 4/7] Refactor testinfra docker to support parametrize This accomplishes the same thing as the previous tests, without using testinfra docker's boilerplate example, which had some drawbacks: Adding @parametrize to the previous version didn't allow overriding the pytest.mark docker arg, image:tag, or cmd with a parametrized test containing different expected results associated with either the alpine/debian tag. Isntead it'd run all the parameters against both tags...e.g. nginx and lighttpd test would run agains both alpine and docker when parametizing on the test level. --- AdminLTE | 2 +- test/conftest.py | 84 ++++++++++++++++++++++++---------------------- test/test_start.py | 32 ++++++++++++++---- 3 files changed, 70 insertions(+), 48 deletions(-) diff --git a/AdminLTE b/AdminLTE index 246599a..2e02fc4 160000 --- a/AdminLTE +++ b/AdminLTE @@ -1 +1 @@ -Subproject commit 246599a0ba46f2f63659ba231341b03472ecf9ea +Subproject commit 2e02fc412ab95a55b835aa5777283ad59a4e3458 diff --git a/test/conftest.py b/test/conftest.py index 749926f..d49a236 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,53 +1,55 @@ import pytest import testinfra -# Use testinfra to get a handy function to run commands locally -check_output = testinfra.get_backend( - "local://" -).get_module("Command").check_output +@pytest.fixture() +def args(request): + return '-e ServerIP="192.168.100.2"' +@pytest.fixture(params=['alpine', 'debian']) +def tag(request): + return request.param -@pytest.fixture -def TestinfraBackend(request): - docker_run = "docker run -d {}".format(request.param) - print docker_run +@pytest.fixture() +def image(request, tag): + return 'diginc/pi-hole:{}'.format(tag) - docker_id = check_output(docker_run) - check_output("docker exec %s sed -i 's/^gravity_spinup/#donotcurl/g' /usr/local/bin/gravity.sh", docker_id) +@pytest.fixture() +def cmd(request): + return '/start.sh' + +DEBUG = [] + +@pytest.fixture() +def Docker(request, LocalCommand, args, image, cmd): + assert 'docker' in LocalCommand.check_output('id'), "Are you in the docker group?" + docker_run = "docker run -d {} {} {}".format(args, image, cmd) + if 'run' in DEBUG: + assert docker_run == 'docker run -d -e ServerIP="192.168.100.2" diginc/pi-hole:alpine /start.sh' + docker_id = LocalCommand.check_output(docker_run) + LocalCommand.check_output("docker exec %s sed -i 's/^gravity_spinup/#donotcurl/g' /usr/local/bin/gravity.sh", docker_id) def teardown(): - check_output("docker rm -f %s", docker_id) + LocalCommand.check_output("docker rm -f %s", docker_id) request.addfinalizer(teardown) return testinfra.get_backend("docker://" + docker_id) - -def pytest_generate_tests(metafunc): - if "TestinfraBackend" in metafunc.fixturenames: - - mark_args = getattr(metafunc.function, "docker_args", None) - docker_args = [] - if mark_args is not None: - docker_args = docker_args + list(mark_args.args) - - mark_images = getattr(metafunc.function, "docker_images", None) - images = ['diginc/pi-hole:alpine', 'diginc/pi-hole:debian'] - if mark_images is not None: - images = mark_images.args - - mark_cmd = getattr(metafunc.function, "docker_cmd", None) - command = 'tail -f /dev/null' - if mark_cmd is not None: - command = " ".join(mark_cmd.args) - - docker_run_args = [] - for img in images: - docker_run_args.append('{} {} {}'.format(" ".join(docker_args), - img, command)) - if getattr(metafunc.function, "persistent", None) is not None: - scope = "session" - else: - scope = "function" - - metafunc.parametrize( - "TestinfraBackend", docker_run_args, indirect=True, scope=scope) +@pytest.fixture +def Slow(): + """ + Run a slow check, check if the state is correct for `timeout` seconds. + """ + import time + def slow(check, timeout=30): + timeout_at = time.time() + timeout + while True: + try: + assert check() + except AssertionError, e: + if timeout_at < time.time(): + time.sleep(1) + else: + raise e + else: + return + return slow diff --git a/test/test_start.py b/test/test_start.py index 6d20b07..3c9ce8d 100644 --- a/test/test_start.py +++ b/test/test_start.py @@ -1,12 +1,32 @@ import pytest +''' conftest.py provides the defaults through fixtures ''' +''' Note, testinfra builtins don't seem fully compatible with + docker containers (esp. alpine) stripped down nature ''' -def test_ServerIP_missing_env_triggers_error(Command): - start = Command.run('/start.sh') +def test_pihole_default_run_command(Docker): + expected_proc = '/sbin/tini -- /start.sh' + pgrep = 'pgrep -f "{}" | wc -l || echo 0'.format(expected_proc) + find_proc = Docker.run(pgrep).stdout + if int(find_proc) < 1: + print Docker.run('ps -ef') + print "{} : {}".format(pgrep, find_proc) + assert False, '{}: Couldn\'t find proc {}'.format(tag, expected_proc) + +@pytest.mark.parametrize('args', [ '' ]) +@pytest.mark.parametrize('cmd', [ 'tail -f /dev/null' ]) +def test_ServerIP_missing_triggers_start_error(Docker): + ''' When args to docker are empty start.sh exits saying ServerIP is required ''' + start = Docker.run('/start.sh') error_msg = "ERROR: To function correctly you must pass an environment variables of 'ServerIP' into the docker container" assert start.rc == 1 assert error_msg in start.stdout -@pytest.mark.docker_args('-e ServerIP="192.168.1.2"') -@pytest.mark.docker_cmd('/start.sh') -def test_ServerIP_allows_normal_startup(Command): - assert Command.run('pgrep -f /start.sh | wc') != 0 +@pytest.mark.parametrize('tag,webserver', [ + ( 'alpine', 'nginx' ), + ( 'debian', 'lighttpd' ) +]) +def test_start_launches_dns_and_a_webserver(Docker, webserver, Slow): + ''' after we wait for start to finish ''' + import time + Socket = Docker.get_module("Socket") + Slow(lambda: Docker.run( 'ps -ef | grep -q "{}"'.format(webserver) ).rc == 0) From c6bcc0f87e25153b1f47c06833b97125f4e23ff8 Mon Sep 17 00:00:00 2001 From: name Date: Sat, 27 Aug 2016 21:07:04 +0300 Subject: [PATCH 5/7] armhf support --- debian-armhf.docker | 60 +++++++++++++++++++++++++++++++++++++++++++ debian-armhf/start.sh | 38 +++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 debian-armhf.docker create mode 100755 debian-armhf/start.sh diff --git a/debian-armhf.docker b/debian-armhf.docker new file mode 100644 index 0000000..c47c19e --- /dev/null +++ b/debian-armhf.docker @@ -0,0 +1,60 @@ +FROM resin/armv7hf-debian:jessie +MAINTAINER adam@diginc.us + +# Requirements +RUN apt-get -q update && \ + apt-get install -y \ + bash \ + dnsmasq \ + lighttpd \ + php5-common php5-cgi php5 \ + bc curl unzip wget sudo && \ + rm -rf /var/cache/apt/archives + +# Original upstream pihole code being used +COPY ./pi-hole/gravity.sh /usr/local/bin/ +COPY ./pi-hole/adlists.default /etc/pihole/ +COPY ./pi-hole/pihole /usr/local/bin/ +COPY ./pi-hole/advanced/Scripts/* /usr/local/bin/ +RUN mkdir -p /opt/ && ln -s /usr/local/bin /opt/pihole +COPY ./pi-hole/advanced/lighttpd.conf.debian /etc/lighttpd/lighttpd.conf +COPY ./pi-hole/advanced/dnsmasq.conf.original /etc/dnsmasq.conf +COPY ./pi-hole/advanced/01-pihole.conf /etc/dnsmasq.d/ +COPY ./pi-hole/advanced/index.html /var/www/html/pihole/index.html +COPY ./pi-hole/advanced/pihole.sudo /etc/sudoers.d/pihole +COPY ./AdminLTE /var/www/html/admin +COPY ./AdminLTE_version.txt /etc/ +COPY ./pi-hole_version.txt /etc/ + +ENV WEBLOGDIR /var/log/lighttpd +RUN mkdir -p /etc/pihole/ && \ + mkdir -p /var/www/html/pihole && \ + mkdir -p /var/www/html/admin/ && \ + chown www-data:www-data /var/www/html && \ + touch ${WEBLOGDIR}/access.log ${WEBLOGDIR}/error.log && \ + chown -R www-data.www-data ${WEBLOGDIR} && \ + chmod 775 /var/www/html && \ + lighty-enable-mod fastcgi fastcgi-php || true && \ + touch /var/log/pihole.log && \ + chmod 644 /var/log/pihole.log && \ + chown dnsmasq:root /var/log/pihole.log && \ + sed -i "s/@INT@/eth0/" /etc/dnsmasq.d/01-pihole.conf && \ + sed -i 's|"cd /etc/.pihole/ && git describe --tags --abbrev=0"|"cat /etc/pi-hole_version.txt"|g' /var/www/html/admin/footer.php && \ + sed -i 's|"git describe --tags --abbrev=0"|"cat /etc/AdminLTE_version.txt"|g' /var/www/html/admin/footer.php + +# This chould be eliminated if all (upstream) files were +x in git +RUN chmod +x /usr/local/bin/*.sh + +# Fix dnsmasq in docker +RUN grep -q '^user=root' || echo 'user=root' >> /etc/dnsmasq.conf + +# php config start passes special ENVs into +ENV PHP_ENV_CONFIG '/etc/lighttpd/conf-enabled/15-fastcgi-php.conf' +ENV PHP_ERROR_LOG '/var/log/lighttpd/error.log' +COPY ./debian-armhf/start.sh / + +EXPOSE 53 53/udp +EXPOSE 80 + +ENTRYPOINT ["/bash", "-c"] +CMD /start.sh diff --git a/debian-armhf/start.sh b/debian-armhf/start.sh new file mode 100755 index 0000000..9e1d517 --- /dev/null +++ b/debian-armhf/start.sh @@ -0,0 +1,38 @@ +#!/bin/sh +if [ -z "$ServerIP" ] ; then + echo "ERROR: To function correctly you must pass an environment variables of 'ServerIP' into the docker container with the IP of your docker host from which you are passing web (80) and dns (53) ports from" + exit 1 +fi; + +# /tmp/piholeIP is the current override of auto-lookup in gravity.sh +echo "$ServerIP" > /etc/pihole/piholeIP; +sed -i "/bin-environment/ a\\\t\t\t\"ServerIP\" => \"${ServerIP}\"," $PHP_ENV_CONFIG +sed -i "/bin-environment/ a\\\t\t\t\"PHP_ERROR_LOG\" => \"${PHP_ERROR_LOG}\"," $PHP_ENV_CONFIG + +if [ -n "$VIRTUAL_HOST" ] ; then + sed -i "/bin-environment/ a\\\t\t\t\"VIRTUAL_HOST\" => \"${VIRTUAL_HOST}\"," $PHP_ENV_CONFIG +else + sed -i "/bin-environment/ a\\\t\t\t\"VIRTUAL_HOST\" => \"${ServerIP}\"," $PHP_ENV_CONFIG +fi; + +echo "Added ENV to php:" +grep -E '(VIRTUAL_HOST|ServerIP)' $PHP_ENV_CONFIG + +dnsType='default' +DNS1=${DNS1:-'8.8.8.8'} +DNS2=${DNS2:-'8.8.4.4'} +if [ "$DNS1" != '8.8.8.8' ] || [ "$DNS2" != '8.8.4.4' ] ; then + dnsType='custom' +fi; + +echo "Using $dnsType DNS servers: $DNS1 & $DNS2" +sed -i "s/@DNS1@/$DNS1/" /etc/dnsmasq.d/01-pihole.conf && \ +sed -i "s/@DNS2@/$DNS2/" /etc/dnsmasq.d/01-pihole.conf && \ + +dnsmasq --test -7 /etc/dnsmasq.d || exit 1 +lighttpd -t -f /etc/lighttpd/lighttpd.conf || exit 1 + +gravity.sh # dnsmasq start included +service lighttpd start + +tail -F /var/log/lighttpd/*.log /var/log/pihole.log From 3b74e8d3e3ad1e51ba598f87611d74e4d9449b1b Mon Sep 17 00:00:00 2001 From: diginc Date: Sun, 28 Aug 2016 00:43:21 -0500 Subject: [PATCH 6/7] Tests working again, along with persistent tests with an actual running pi-hole container --- .gitmodules | 2 +- .travis.yml | 2 +- AdminLTE | 2 +- AdminLTE_version.txt | 2 +- alpine.docker | 2 +- alpine/gravity.sh | 6 ++-- alpine/nginx.conf | 2 +- alpine/start.sh | 6 ++-- autotest | 2 +- debian.docker | 3 +- debian/start.sh | 6 ++-- test/conftest.py | 73 +++++++++++++++++++++++++++++++++----------- test/test_start.py | 42 +++++++++++++++++++------ 13 files changed, 107 insertions(+), 43 deletions(-) diff --git a/.gitmodules b/.gitmodules index a808b3a..4ac310c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/pi-hole/pi-hole.git [submodule "AdminLTE"] path = AdminLTE - url = https://github.com/diginc/AdminLTE.git + url = https://github.com/pi-hole/AdminLTE.git diff --git a/.travis.yml b/.travis.yml index bcfe610..655f84e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,4 +7,4 @@ python: install: - pip install -r requirements.txt -script: py.test +script: py.test -v diff --git a/AdminLTE b/AdminLTE index 2e02fc4..fa5f2fc 160000 --- a/AdminLTE +++ b/AdminLTE @@ -1 +1 @@ -Subproject commit 2e02fc412ab95a55b835aa5777283ad59a4e3458 +Subproject commit fa5f2fcaf000a9343985dffc9e7382ae1c99b85b diff --git a/AdminLTE_version.txt b/AdminLTE_version.txt index b056e35..b1f7421 100644 --- a/AdminLTE_version.txt +++ b/AdminLTE_version.txt @@ -1 +1 @@ -vDev +v1.4 diff --git a/alpine.docker b/alpine.docker index b39248c..065fab1 100644 --- a/alpine.docker +++ b/alpine.docker @@ -20,7 +20,7 @@ COPY ./pi-hole/advanced/Scripts/* /usr/local/bin/ RUN mkdir -p /opt/ && ln -s /usr/local/bin /opt/pihole COPY ./pi-hole/advanced/dnsmasq.conf.original /etc/dnsmasq.conf COPY ./pi-hole/advanced/01-pihole.conf /etc/dnsmasq.d/ -COPY ./pi-hole/advanced/index.html /var/www/html/pihole/index.html +COPY ./pi-hole/advanced/index* /var/www/html/pihole/ COPY ./pi-hole/advanced/pihole.sudo /etc/sudoers.d/pihole COPY ./AdminLTE /var/www/html/admin COPY ./AdminLTE_version.txt /etc/ diff --git a/alpine/gravity.sh b/alpine/gravity.sh index 3221939..483bd1a 100755 --- a/alpine/gravity.sh +++ b/alpine/gravity.sh @@ -19,7 +19,7 @@ else echo "::: sudo will be used." # Check if it is actually installed # If it isn't, exit because the install cannot complete - if [[ $(dpkg-query -s sudo) ]];then + if [ -x "$(command -v sudo)" ];then export SUDO="sudo" else echo "::: Please install sudo or run this script as root." @@ -152,7 +152,7 @@ function gravity_transport() { fi # Silently curl url - curl -s $cmd_ext $heisenbergCompensator -A "$agent" $url > $patternBuffer + curl -s -L $cmd_ext $heisenbergCompensator -A "$agent" $url > $patternBuffer # Check for list updates gravity_patternCheck "$patternBuffer" # Cleanup @@ -181,7 +181,7 @@ function gravity_spinup() { # to complete properly and reset the user agent when required case "$domain" in "adblock.mahakala.is") - agent='Mozilla/5.0 (X11; Linux x86_64; rv:30.0) Gecko/20100101 Firefox/30.0' + agent='Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36' cmd_ext="-e http://forum.xda-developers.com/" ;; diff --git a/alpine/nginx.conf b/alpine/nginx.conf index a80b8ca..70c0183 100644 --- a/alpine/nginx.conf +++ b/alpine/nginx.conf @@ -14,7 +14,7 @@ http { server { listen 80; listen [::]:80; - root /var/www/html; + root /var/www/html/pihole; index index.php index.html index.nginx-debian.html; error_page 404 /pihole/index.html; diff --git a/alpine/start.sh b/alpine/start.sh index ea83d51..703d11a 100755 --- a/alpine/start.sh +++ b/alpine/start.sh @@ -13,7 +13,7 @@ echo "env[ServerIP] = ${ServerIP}" >> $PHP_ENV_CONFIG; if [ -n "$VIRTUAL_HOST" ] ; then echo "env[VIRTUAL_HOST] = ${VIRTUAL_HOST}" >> $PHP_ENV_CONFIG; -else +else echo "env[VIRTUAL_HOST] = ${ServerIP}" >> $PHP_ENV_CONFIG; fi; @@ -23,7 +23,7 @@ cat $PHP_ENV_CONFIG dnsType='default' DNS1=${DNS1:-'8.8.8.8'} DNS2=${DNS2:-'8.8.4.4'} -if [ "$DNS1" != '8.8.8.8' ] || [ "$DNS2" != '8.8.4.4' ] ; then +if [ "$DNS1" != '8.8.8.8' ] || [ "$DNS2" != '8.8.4.4' ] ; then dnsType='custom' fi; @@ -34,7 +34,9 @@ sed -i "s/@DNS2@/$DNS2/" /etc/dnsmasq.d/01-pihole.conf && \ dnsmasq --test -7 /etc/dnsmasq.d || exit 1 php-fpm -t || exit 1 nginx -t || exit 1 +echo " :: All config checks passed, starting ..." +if [ -n "$PYTEST" ] ; then sed -i 's/^gravity_spinup/#donotcurl/g' `which gravity.sh`; fi; gravity.sh dnsmasq -7 /etc/dnsmasq.d php-fpm diff --git a/autotest b/autotest index 6ce3ed5..3747cc0 100755 --- a/autotest +++ b/autotest @@ -1 +1 @@ -py.test -f test/ +py.test -v -f test/ diff --git a/debian.docker b/debian.docker index 5fae7c2..71fd761 100644 --- a/debian.docker +++ b/debian.docker @@ -26,7 +26,8 @@ RUN mkdir -p /opt/ && ln -s /usr/local/bin /opt/pihole COPY ./pi-hole/advanced/lighttpd.conf.debian /etc/lighttpd/lighttpd.conf COPY ./pi-hole/advanced/dnsmasq.conf.original /etc/dnsmasq.conf COPY ./pi-hole/advanced/01-pihole.conf /etc/dnsmasq.d/ -COPY ./pi-hole/advanced/index.html /var/www/html/pihole/index.html +COPY ./pi-hole/advanced/index* /var/www/html/pihole/ +RUN rm /var/www/html/index.lighttpd.html COPY ./pi-hole/advanced/pihole.sudo /etc/sudoers.d/pihole COPY ./AdminLTE /var/www/html/admin COPY ./AdminLTE_version.txt /etc/ diff --git a/debian/start.sh b/debian/start.sh index 9e1d517..02797cb 100755 --- a/debian/start.sh +++ b/debian/start.sh @@ -11,7 +11,7 @@ sed -i "/bin-environment/ a\\\t\t\t\"PHP_ERROR_LOG\" => \"${PHP_ERROR_LOG}\"," $ if [ -n "$VIRTUAL_HOST" ] ; then sed -i "/bin-environment/ a\\\t\t\t\"VIRTUAL_HOST\" => \"${VIRTUAL_HOST}\"," $PHP_ENV_CONFIG -else +else sed -i "/bin-environment/ a\\\t\t\t\"VIRTUAL_HOST\" => \"${ServerIP}\"," $PHP_ENV_CONFIG fi; @@ -21,7 +21,7 @@ grep -E '(VIRTUAL_HOST|ServerIP)' $PHP_ENV_CONFIG dnsType='default' DNS1=${DNS1:-'8.8.8.8'} DNS2=${DNS2:-'8.8.4.4'} -if [ "$DNS1" != '8.8.8.8' ] || [ "$DNS2" != '8.8.4.4' ] ; then +if [ "$DNS1" != '8.8.8.8' ] || [ "$DNS2" != '8.8.4.4' ] ; then dnsType='custom' fi; @@ -31,7 +31,9 @@ sed -i "s/@DNS2@/$DNS2/" /etc/dnsmasq.d/01-pihole.conf && \ dnsmasq --test -7 /etc/dnsmasq.d || exit 1 lighttpd -t -f /etc/lighttpd/lighttpd.conf || exit 1 +echo " :: All config checks passed, starting ..." +if [ -n "$PYTEST" ] ; then sed -i 's/^gravity_spinup/#donotcurl/g' `which gravity.sh`; fi; gravity.sh # dnsmasq start included service lighttpd start diff --git a/test/conftest.py b/test/conftest.py index d49a236..01c3330 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,38 +1,75 @@ import pytest import testinfra +DEBUG = [] + +check_output = testinfra.get_backend( + "local://" +).get_module("Command").check_output + +def DockerGeneric(request, args, image, cmd): + assert 'docker' in check_output('id'), "Are you in the docker group?" + docker_run = "docker run -d -e PYTEST=\"True\" {} {} {}".format(args, image, cmd) + docker_id = check_output(docker_run) + + def teardown(): + check_output("docker stop %s", docker_id) + check_output("docker rm %s", docker_id) + request.addfinalizer(teardown) + + return testinfra.get_backend("docker://" + docker_id) + +@pytest.fixture +def Docker(request, args, image, cmd): + ''' One-off Docker container run ''' + return DockerGeneric(request, args, image, cmd) + +@pytest.fixture(scope='session') +def DockerPersist(request, persist_args, persist_image, persist_cmd): + ''' Persistent Docker container for multiple tests ''' + return DockerGeneric(request, persist_args, persist_image, persist_cmd) + @pytest.fixture() -def args(request): +def args(request): return '-e ServerIP="192.168.100.2"' @pytest.fixture(params=['alpine', 'debian']) def tag(request): return request.param +@pytest.fixture +@pytest.mark.parametrize('tag,webserver', [ ( 'alpine', 'nginx' ), ( 'debian', 'lighttpd' ) ]) +def webserver(request, tag): + return webserver + @pytest.fixture() -def image(request, tag): +def image(request, tag): return 'diginc/pi-hole:{}'.format(tag) @pytest.fixture() -def cmd(request): +def cmd(request): return '/start.sh' -DEBUG = [] +@pytest.fixture(scope='session') +def persist_args(request): + return '-e ServerIP="192.168.100.2"' -@pytest.fixture() -def Docker(request, LocalCommand, args, image, cmd): - assert 'docker' in LocalCommand.check_output('id'), "Are you in the docker group?" - docker_run = "docker run -d {} {} {}".format(args, image, cmd) - if 'run' in DEBUG: - assert docker_run == 'docker run -d -e ServerIP="192.168.100.2" diginc/pi-hole:alpine /start.sh' - docker_id = LocalCommand.check_output(docker_run) - LocalCommand.check_output("docker exec %s sed -i 's/^gravity_spinup/#donotcurl/g' /usr/local/bin/gravity.sh", docker_id) +@pytest.fixture(scope='session', params=['alpine', 'debian']) +def persist_tag(request): + return request.param - def teardown(): - LocalCommand.check_output("docker rm -f %s", docker_id) - request.addfinalizer(teardown) +@pytest.fixture(scope='session') +def persist_webserver(request, persist_tag): + web_dict = { 'alpine': 'nginx', 'debian': 'lighttpd' } + return web_dict[persist_tag] - return testinfra.get_backend("docker://" + docker_id) +@pytest.fixture(scope='session') +def persist_image(request, persist_tag): + return 'diginc/pi-hole:{}'.format(persist_tag) + +@pytest.fixture(scope='session') +def persist_cmd(request): + return '/start.sh' @pytest.fixture def Slow(): @@ -40,13 +77,13 @@ def Slow(): Run a slow check, check if the state is correct for `timeout` seconds. """ import time - def slow(check, timeout=30): + def slow(check, timeout=15): timeout_at = time.time() + timeout while True: try: assert check() except AssertionError, e: - if timeout_at < time.time(): + if time.time() < timeout_at: time.sleep(1) else: raise e diff --git a/test/test_start.py b/test/test_start.py index 3c9ce8d..b3798d1 100644 --- a/test/test_start.py +++ b/test/test_start.py @@ -1,6 +1,7 @@ import pytest +import time ''' conftest.py provides the defaults through fixtures ''' -''' Note, testinfra builtins don't seem fully compatible with +''' Note, testinfra builtins don't seem fully compatible with docker containers (esp. alpine) stripped down nature ''' def test_pihole_default_run_command(Docker): @@ -21,12 +22,33 @@ def test_ServerIP_missing_triggers_start_error(Docker): assert start.rc == 1 assert error_msg in start.stdout -@pytest.mark.parametrize('tag,webserver', [ - ( 'alpine', 'nginx' ), - ( 'debian', 'lighttpd' ) -]) -def test_start_launches_dns_and_a_webserver(Docker, webserver, Slow): - ''' after we wait for start to finish ''' - import time - Socket = Docker.get_module("Socket") - Slow(lambda: Docker.run( 'ps -ef | grep -q "{}"'.format(webserver) ).rc == 0) +@pytest.fixture +def RunningPiHole(DockerPersist, Slow, persist_webserver): + ''' Persist a docker and provide some parameterized data for re-use ''' + Slow(lambda: DockerPersist.run( 'pgrep {}'.format(persist_webserver) ).rc == 0) + return DockerPersist + +def test_indecies_are_present(RunningPiHole): + File = RunningPiHole.get_module('File') + File('/var/www/html/pihole/index.html').exists + File('/var/www/html/pihole/index.js').exists + +@pytest.mark.parametrize('url', [ '/' ] ) +#@pytest.mark.parametrize('url', [ '/', '/index.html', 'any.html' ] ) +def test_html_index_requests_load_as_expected(RunningPiHole, url): + command = 'curl -s -o /tmp/curled_file -w "%{{http_code}}" http://127.0.0.1{}'.format(url) + print command + http_rc = RunningPiHole.run(command) + print RunningPiHole.run('ls -lat /tmp/curled_file').stdout + print RunningPiHole.run('cat /tmp/curled_file').stdout + assert RunningPiHole.run('md5sum /tmp/curled_file /var/www/html/pihole/index.html').rc == 0 + assert int(http_rc.stdout) == 200 + +@pytest.mark.parametrize('url', [ '/index.js' ] ) +#@pytest.mark.parametrize('url', [ '/index.js', '/any.js'] ) +def test_javascript_requests_load_as_expected(RunningPiHole, url): + command = 'curl -s -o /tmp/curled_file -w "%{{http_code}}" http://127.0.0.1{}'.format(url) + print command + http_rc = RunningPiHole.run(command) + assert RunningPiHole.run('md5sum /tmp/curled_file /var/www/html/pihole/index.js').rc == 0 + assert int(http_rc.stdout) == 200 From 30fe0a3353926edf4d66c72d245a8b691f0e6da2 Mon Sep 17 00:00:00 2001 From: diginc Date: Sun, 28 Aug 2016 01:11:55 -0500 Subject: [PATCH 7/7] Added more http endpoint tests Forgot to uncomment these, revealed a flaw in the nginx config nginx now has parity with lighttpd for pages it returns and return codes --- alpine/nginx.conf | 13 +++++++------ test/conftest.py | 2 +- test/test_start.py | 6 ++---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/alpine/nginx.conf b/alpine/nginx.conf index 70c0183..d111585 100644 --- a/alpine/nginx.conf +++ b/alpine/nginx.conf @@ -14,13 +14,17 @@ http { server { listen 80; listen [::]:80; - root /var/www/html/pihole; - index index.php index.html index.nginx-debian.html; + root /var/www/html; + index /pihole/index.html; + error_page 404 =200 /pihole/index.html; - error_page 404 /pihole/index.html; + location / { + add_header X-Pi-hole "A black hole for Internet advertisements." always; + } location ~ ^/admin/ { add_header X-Pi-hole "The Pi-hole Web interface is working!"; + add_header X-Frame-Options "DENY" always; location ~ .php$ { fastcgi_pass 127.0.0.1:9000; @@ -30,9 +34,6 @@ http { } } - location / { - add_header X-Pi-hole "A black hole for Internet advertisements." always; - } } } diff --git a/test/conftest.py b/test/conftest.py index 01c3330..aa51807 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -77,7 +77,7 @@ def Slow(): Run a slow check, check if the state is correct for `timeout` seconds. """ import time - def slow(check, timeout=15): + def slow(check, timeout=5): timeout_at = time.time() + timeout while True: try: diff --git a/test/test_start.py b/test/test_start.py index b3798d1..8cdefd3 100644 --- a/test/test_start.py +++ b/test/test_start.py @@ -33,8 +33,7 @@ def test_indecies_are_present(RunningPiHole): File('/var/www/html/pihole/index.html').exists File('/var/www/html/pihole/index.js').exists -@pytest.mark.parametrize('url', [ '/' ] ) -#@pytest.mark.parametrize('url', [ '/', '/index.html', 'any.html' ] ) +@pytest.mark.parametrize('url', [ '/', '/index.html', '/any.html' ] ) def test_html_index_requests_load_as_expected(RunningPiHole, url): command = 'curl -s -o /tmp/curled_file -w "%{{http_code}}" http://127.0.0.1{}'.format(url) print command @@ -44,8 +43,7 @@ def test_html_index_requests_load_as_expected(RunningPiHole, url): assert RunningPiHole.run('md5sum /tmp/curled_file /var/www/html/pihole/index.html').rc == 0 assert int(http_rc.stdout) == 200 -@pytest.mark.parametrize('url', [ '/index.js' ] ) -#@pytest.mark.parametrize('url', [ '/index.js', '/any.js'] ) +@pytest.mark.parametrize('url', [ '/index.js', '/any.js'] ) def test_javascript_requests_load_as_expected(RunningPiHole, url): command = 'curl -s -o /tmp/curled_file -w "%{{http_code}}" http://127.0.0.1{}'.format(url) print command