diff --git a/.gitmodules b/.gitmodules index 4ac310c..a808b3a 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/pi-hole/AdminLTE.git + url = https://github.com/diginc/AdminLTE.git diff --git a/.travis.yml b/.travis.yml index 655f84e..46b023b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,12 @@ sudo: required + services: - docker -language: python -python: - - "2.7" -install: - - pip install -r requirements.txt -script: py.test -v +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 . diff --git a/AdminLTE b/AdminLTE index fa5f2fc..246599a 160000 --- a/AdminLTE +++ b/AdminLTE @@ -1 +1 @@ -Subproject commit fa5f2fcaf000a9343985dffc9e7382ae1c99b85b +Subproject commit 246599a0ba46f2f63659ba231341b03472ecf9ea diff --git a/AdminLTE_version.txt b/AdminLTE_version.txt index b1f7421..b056e35 100644 --- a/AdminLTE_version.txt +++ b/AdminLTE_version.txt @@ -1 +1 @@ -v1.4 +vDev diff --git a/alpine.docker b/alpine.docker index 065fab1..b39248c 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* /var/www/html/pihole/ +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/ diff --git a/alpine/gravity.sh b/alpine/gravity.sh index 483bd1a..3221939 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 [ -x "$(command -v sudo)" ];then + if [[ $(dpkg-query -s 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 -L $cmd_ext $heisenbergCompensator -A "$agent" $url > $patternBuffer + curl -s $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 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36' + agent='Mozilla/5.0 (X11; Linux x86_64; rv:30.0) Gecko/20100101 Firefox/30.0' cmd_ext="-e http://forum.xda-developers.com/" ;; diff --git a/alpine/nginx.conf b/alpine/nginx.conf index d111585..a80b8ca 100644 --- a/alpine/nginx.conf +++ b/alpine/nginx.conf @@ -15,16 +15,12 @@ http { listen 80; listen [::]:80; root /var/www/html; - index /pihole/index.html; - error_page 404 =200 /pihole/index.html; + index index.php index.html index.nginx-debian.html; - location / { - add_header X-Pi-hole "A black hole for Internet advertisements." always; - } + error_page 404 /pihole/index.html; 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; @@ -34,6 +30,9 @@ http { } } + location / { + add_header X-Pi-hole "A black hole for Internet advertisements." always; + } } } diff --git a/alpine/start.sh b/alpine/start.sh index 703d11a..ea83d51 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,9 +34,7 @@ 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 deleted file mode 100755 index 3747cc0..0000000 --- a/autotest +++ /dev/null @@ -1 +0,0 @@ -py.test -v -f test/ diff --git a/debian-armhf.docker b/debian-armhf.docker deleted file mode 100644 index c47c19e..0000000 --- a/debian-armhf.docker +++ /dev/null @@ -1,60 +0,0 @@ -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 deleted file mode 100755 index 9e1d517..0000000 --- a/debian-armhf/start.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/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 diff --git a/debian.docker b/debian.docker index 71fd761..5fae7c2 100644 --- a/debian.docker +++ b/debian.docker @@ -26,8 +26,7 @@ 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* /var/www/html/pihole/ -RUN rm /var/www/html/index.lighttpd.html +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/ diff --git a/debian/start.sh b/debian/start.sh index 02797cb..9e1d517 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,9 +31,7 @@ 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/__init__.py b/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/conftest.py b/test/conftest.py index aa51807..fadb839 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,92 +1,53 @@ import pytest import testinfra -DEBUG = [] - +# Use testinfra to get a handy function to run commands locally 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) + +@pytest.fixture +def TestinfraBackend(request): + docker_run = "docker run -d {}".format(request.param) + print docker_run + 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) def teardown(): - check_output("docker stop %s", docker_id) - check_output("docker rm %s", docker_id) - request.addfinalizer(teardown) + check_output("docker rm -f %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) +def pytest_generate_tests(metafunc): + if "TestinfraBackend" in metafunc.fixturenames: -@pytest.fixture() -def args(request): - return '-e ServerIP="192.168.100.2"' + mark_args = getattr(metafunc.function, "docker_args", None) + docker_args = [] + if mark_args is not None: + docker_args = docker_args + list(mark_args.args) -@pytest.fixture(params=['alpine', 'debian']) -def tag(request): - return request.param + 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 -@pytest.fixture -@pytest.mark.parametrize('tag,webserver', [ ( 'alpine', 'nginx' ), ( 'debian', 'lighttpd' ) ]) -def webserver(request, tag): - return webserver + mark_cmd = getattr(metafunc.function, "docker_cmd", None) + command = 'tail -f /dev/null' + if mark_cmd is not None: + command = " ".join(mark_cmd.args) -@pytest.fixture() -def image(request, tag): - return 'diginc/pi-hole:{}'.format(tag) + 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" -@pytest.fixture() -def cmd(request): - return '/start.sh' - -@pytest.fixture(scope='session') -def persist_args(request): - return '-e ServerIP="192.168.100.2"' - -@pytest.fixture(scope='session', params=['alpine', 'debian']) -def persist_tag(request): - return request.param - -@pytest.fixture(scope='session') -def persist_webserver(request, persist_tag): - web_dict = { 'alpine': 'nginx', 'debian': 'lighttpd' } - return web_dict[persist_tag] - -@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(): - """ - Run a slow check, check if the state is correct for `timeout` seconds. - """ - import time - def slow(check, timeout=5): - timeout_at = time.time() + timeout - while True: - try: - assert check() - except AssertionError, e: - if time.time() < timeout_at: - time.sleep(1) - else: - raise e - else: - return - return slow + metafunc.parametrize( + "TestinfraBackend", docker_run_args, indirect=True, scope=scope) diff --git a/test/test_000_build_containers.py b/test/test_000_build_containers.py deleted file mode 100644 index ac9ae85..0000000 --- a/test/test_000_build_containers.py +++ /dev/null @@ -1,18 +0,0 @@ -''' 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 diff --git a/test/test_start.py b/test/test_start.py index 8cdefd3..6d20b07 100644 --- a/test/test_start.py +++ b/test/test_start.py @@ -1,52 +1,12 @@ import pytest -import time -''' 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_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') +def test_ServerIP_missing_env_triggers_error(Command): + start = Command.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.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', [ '/', '/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', '/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 +@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