This commit is too big, but it works
* Tests are passing, hopefully consistently * FTL pulling from official releases * thanks @DL6ER for the musl-libc build * Thanks middleagedman for the IPv6 fixes * Thanks everyone for patience while I get this release working!
This commit is contained in:
parent
8d0ea48ecd
commit
b9095bc123
|
@ -17,8 +17,10 @@ One crucial thing to know before starting is the docker-pi-hole container needs
|
|||
```
|
||||
IMAGE='diginc/pi-hole'
|
||||
IP_LOOKUP="$(ip route get 8.8.8.8 | awk '{ print $NF; exit }')" # May not work for VPN / tun0
|
||||
IPv6_LOOKUP="$(ip -6 route get 2001:4860:4860::8888 | awk '{ print $10; exit }')" # May not work for VPN / tun0
|
||||
IP="${IP:-$IP_LOOKUP}" # use $IP, if set, otherwise IP_LOOKUP
|
||||
docker run -p 53:53/tcp -p 53:53/udp -p 80:80 --cap-add=NET_ADMIN -e ServerIP="$IP" --restart=always --name pihole -d $IMAGE
|
||||
IPv6="${IPv6:-$IPv6_LOOKUP}" # use $IPv6, if set, otherwise IP_LOOKUP
|
||||
docker run -p 53:53/tcp -p 53:53/udp -p 80:80 --cap-add=NET_ADMIN -e ServerIP="$IP" -e ServerIPv6="$IPv6" --restart=always --name pihole -d $IMAGE
|
||||
|
||||
# Recommended auto ad list updates & log rotation:
|
||||
wget -O- https://raw.githubusercontent.com/diginc/docker-pi-hole/master/docker-pi-hole.cron | sudo tee /etc/cron.d/docker-pi-hole
|
||||
|
|
|
@ -20,7 +20,6 @@ ENTRYPOINT [ "/init" ]
|
|||
|
||||
ADD s6/alpine-root /
|
||||
COPY s6/service /usr/local/bin/service
|
||||
COPY pihole-FTL /usr/bin/pihole-FTL
|
||||
|
||||
# Things installer did and fix alpine+nginx differences
|
||||
ENV WEBLOGDIR /var/log/nginx
|
||||
|
@ -32,6 +31,7 @@ RUN mkdir -p /etc/pihole/ && \
|
|||
touch ${WEBLOGDIR}/access.log ${WEBLOGDIR}/error.log && \
|
||||
chown -R nginx:nginx ${WEBLOGDIR} && \
|
||||
sed -i 's|^user\s*=.*$|user = nginx|' $PHP_CONFIG && \
|
||||
sed -i '/^;pid/ s|^;||' $PHP_CONFIG && \
|
||||
chmod 775 /var/www/html && \
|
||||
touch /var/log/pihole.log && \
|
||||
chmod 644 /var/log/pihole.log && \
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
. /opt/pihole/webpage.sh
|
||||
setupVars="$setupVars"
|
||||
ServerIP="$ServerIP"
|
||||
ServerIPv6="$ServerIPv6"
|
||||
IPv6="$IPv6"
|
||||
|
||||
prepare_setup_vars() {
|
||||
|
@ -148,7 +149,7 @@ setup_ipv4_ipv6() {
|
|||
ip_versions="IPv4"
|
||||
case $IMAGE in
|
||||
"debian") sed -i '/use-ipv6.pl/ d' /etc/lighttpd/lighttpd.conf ;;
|
||||
"alpine") sed -i '/listen \[::\]:80;/ d' /etc/nginx/nginx.conf ;;
|
||||
"alpine") sed -i '/listen \[::\]:80/ d' /etc/nginx/nginx.conf ;;
|
||||
esac
|
||||
fi;
|
||||
echo "Using $ip_versions"
|
||||
|
@ -176,7 +177,7 @@ test_configs_alpine() {
|
|||
echo -n '::: Testing DNSmasq config: '
|
||||
dnsmasq --test -7 /etc/dnsmasq.d
|
||||
echo -n '::: Testing PHP-FPM config: '
|
||||
php-fpm -t
|
||||
php-fpm5 -t
|
||||
echo -n '::: Testing NGINX config: '
|
||||
nginx -t
|
||||
set +e
|
||||
|
@ -184,5 +185,9 @@ test_configs_alpine() {
|
|||
}
|
||||
|
||||
test_framework_stubbing() {
|
||||
if [ -n "$PYTEST" ] ; then sed -i 's/^gravity_spinup$/#gravity_spinup # DISABLED FOR PYTEST/g' "$(which gravity.sh)"; fi;
|
||||
if [ -n "$PYTEST" ] ; then
|
||||
echo ":::::: Tests are being ran - stub out ad list fetching and add a fake ad block"
|
||||
sed -i 's/^gravity_spinup$/#gravity_spinup # DISABLED FOR PYTEST/g' "$(which gravity.sh)"
|
||||
echo 'testblock.pi-hole.local' >> /etc/pihole/blacklist.txt
|
||||
fi
|
||||
}
|
||||
|
|
10
install.sh
10
install.sh
|
@ -1,8 +1,8 @@
|
|||
#!/bin/bash -x
|
||||
#!/bin/bash -ex
|
||||
mkdir -p /etc/pihole/
|
||||
export CORE_TAG='v3.0.1'
|
||||
export WEB_TAG='v3.0.1'
|
||||
export FTL_TAG='v2.6.2'
|
||||
export FTL_TAG='v2.7'
|
||||
|
||||
# Make pihole scripts fail searching for `systemctl`,
|
||||
# which fails pretty miserably in docker compared to `service`
|
||||
|
@ -25,6 +25,8 @@ if [[ "$IMAGE" == 'alpine' ]] ; then
|
|||
# For new FTL install lines
|
||||
sed -i 's/sha1sum --status --quiet/sha1sum -s/g' "${PIHOLE_INSTALL}"
|
||||
sed -i 's/install -T/install /g' "${PIHOLE_INSTALL}"
|
||||
# shellcheck disable=SC2016
|
||||
sed -i '/FTLinstall/ s/${binary}/pihole-FTL-musl-linux-x86_64/g' "${PIHOLE_INSTALL}"
|
||||
LIGHTTPD_USER="nginx" # shellcheck disable=SC2034
|
||||
LIGHTTPD_GROUP="nginx" # shellcheck disable=SC2034
|
||||
LIGHTTPD_CFG="lighttpd.conf.debian" # shellcheck disable=SC2034
|
||||
|
@ -45,7 +47,7 @@ elif [[ "$IMAGE" == 'alpine' ]] ; then
|
|||
dnsmasq \
|
||||
nginx \
|
||||
ca-certificates \
|
||||
php5-fpm php5-json php5-openssl php5-zip libxml2 \
|
||||
php5-fpm php5-json php5-openssl php5-zip php5-sockets libxml2 \
|
||||
bc bash curl perl sudo git
|
||||
# S6 service like to be blocking/foreground
|
||||
sed -i 's|^;daemonize = yes|daemonize = no|' /etc/php5/php-fpm.conf
|
||||
|
@ -75,4 +77,4 @@ mv "${tmpLog}" "${instalLogLoc}"
|
|||
|
||||
# Fix dnsmasq in docker
|
||||
grep -q '^user=root' || echo -e '\nuser=root' >> /etc/dnsmasq.conf
|
||||
echo 'done'
|
||||
echo 'Docker install successful'
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
#!/usr/bin/with-contenv bash
|
||||
|
||||
# Early DNS Startup for the gravity list process to use
|
||||
dnsmasq -7 /etc/dnsmasq.d
|
||||
|
||||
/start.sh
|
||||
gravity.sh
|
||||
|
||||
# Done with DNS, let s6 services start up properly configured dns now
|
||||
killall -9 dnsmasq
|
||||
|
|
|
@ -12,13 +12,15 @@ http {
|
|||
keepalive_timeout 65;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
# PHP SERVER_NAME is empty unless set, which can bug out ipv6less setups
|
||||
server_name dockerpi.hole;
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
root /var/www/html;
|
||||
index pihole/index.php index.php;
|
||||
error_page 404 =200 /pihole/index.php;
|
||||
|
||||
location ~ /(pihole|admin)/*.php$ {
|
||||
location ~ .php$ {
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_index index.php;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/with-contenv bash
|
||||
|
||||
s6-echo "Starting pihole-FTL"
|
||||
pihole-FTL no-daemon
|
|
@ -1,4 +1,10 @@
|
|||
#!/usr/bin/with-contenv bash
|
||||
|
||||
# Early DNS Startup for the gravity list process to use
|
||||
dnsmasq -7 /etc/dnsmasq.d
|
||||
|
||||
/start.sh
|
||||
gravity.sh
|
||||
|
||||
# Done with DNS, let s6 services start up properly configured dns now
|
||||
killall -9 dnsmasq
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/with-contenv bash
|
||||
|
||||
s6-echo "Starting pihole-FTL"
|
||||
pihole-FTL no-daemon
|
1
start.sh
1
start.sh
|
@ -27,5 +27,6 @@ setup_dnsmasq_hostnames "$ServerIP" "$ServerIPv6" "$HOSTNAME"
|
|||
setup_ipv4_ipv6
|
||||
test_configs
|
||||
test_framework_stubbing
|
||||
echo "::: Docker start setup complete - beginning s6 services"
|
||||
|
||||
# s6's init takes care of running services now, no more main start services function
|
||||
|
|
|
@ -10,9 +10,9 @@ check_output = testinfra.get_backend(
|
|||
def DockerGeneric(request, args, image, cmd):
|
||||
assert 'docker' in check_output('id'), "Are you in the docker group?"
|
||||
if 'diginc/pi-hole' in image:
|
||||
args += " -v /dev/null:/etc/pihole/adlists.default -e PYTEST=\"True\""
|
||||
#args += " -e PYTEST=\"True\""
|
||||
args += " --dns 127.0.0.1 -v /dev/null:/etc/.pihole/adlists.default -e PYTEST=\"True\""
|
||||
docker_run = "docker run -d {} {} {}".format(args, image, cmd)
|
||||
print docker_run
|
||||
docker_id = check_output(docker_run)
|
||||
|
||||
def teardown():
|
||||
|
@ -44,7 +44,7 @@ def Docker(request, args, image, cmd):
|
|||
''' One-off Docker container run '''
|
||||
return DockerGeneric(request, args, image, cmd)
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope='module')
|
||||
def DockerPersist(request, persist_args, persist_image, persist_cmd, Dig):
|
||||
''' Persistent Docker container for multiple tests '''
|
||||
persistent_container = DockerGeneric(request, persist_args, persist_image, persist_cmd)
|
||||
|
@ -54,7 +54,7 @@ def DockerPersist(request, persist_args, persist_image, persist_cmd, Dig):
|
|||
|
||||
@pytest.fixture()
|
||||
def args(request):
|
||||
return '-e ServerIP="192.168.100.2"'
|
||||
return '-e ServerIP="127.0.0.1" -e ServerIPv6="::1"'
|
||||
|
||||
@pytest.fixture(params=['alpine', 'debian'])
|
||||
def tag(request):
|
||||
|
@ -70,27 +70,27 @@ def image(request, tag):
|
|||
|
||||
@pytest.fixture()
|
||||
def cmd(request):
|
||||
return ''
|
||||
return 'tail -f /dev/null'
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope='module')
|
||||
def persist_args(request):
|
||||
return '-e ServerIP="192.168.100.2"'
|
||||
return '-e ServerIP="127.0.0.1" -e ServerIPv6="::1"'
|
||||
|
||||
@pytest.fixture(scope='session', params=['alpine', 'debian'])
|
||||
@pytest.fixture(scope='module', params=['alpine', 'debian'])
|
||||
def persist_tag(request):
|
||||
return request.param
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope='module')
|
||||
def persist_webserver(request, persist_tag):
|
||||
return WEB_SERVER[persist_tag]
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope='module')
|
||||
def persist_image(request, persist_tag):
|
||||
return 'diginc/pi-hole:{}'.format(persist_tag)
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope='module')
|
||||
def persist_cmd(request):
|
||||
return ''
|
||||
return 'tail -f /dev/null'
|
||||
|
||||
@pytest.fixture
|
||||
def Slow():
|
||||
|
@ -98,7 +98,7 @@ def Slow():
|
|||
Run a slow check, check if the state is correct for `timeout` seconds.
|
||||
"""
|
||||
import time
|
||||
def slow(check, timeout=5):
|
||||
def slow(check, timeout=20):
|
||||
timeout_at = time.time() + timeout
|
||||
while True:
|
||||
try:
|
||||
|
@ -112,7 +112,7 @@ def Slow():
|
|||
return
|
||||
return slow
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope='module')
|
||||
def Dig(request):
|
||||
''' separate container to link to pi-hole and perform lookups '''
|
||||
''' a docker pull is faster than running an install of dnsutils '''
|
||||
|
|
|
@ -1,28 +1,30 @@
|
|||
import pytest
|
||||
import re
|
||||
|
||||
DEFAULTARGS = '-e ServerIP="127.0.0.1" '
|
||||
|
||||
# Override these docker command pieces to minimize parameter repititon
|
||||
@pytest.fixture()
|
||||
def cmd(request):
|
||||
return 'tail -f /dev/null'
|
||||
|
||||
@pytest.mark.parametrize('args,expected_ipv6,expected_stdout', [
|
||||
('-e ServerIP="1.2.3.4"', True, 'IPv4 and IPv6'),
|
||||
('-e ServerIP="1.2.3.4" -e "IPv6=True"', True, 'IPv4 and IPv6'),
|
||||
('-e ServerIP="1.2.3.4" -e "IPv6=False"', False, 'IPv4'),
|
||||
('-e ServerIP="1.2.3.4" -e "IPv6=foobar"', False, 'IPv4'),
|
||||
(DEFAULTARGS, True, 'IPv4 and IPv6'),
|
||||
(DEFAULTARGS + '-e "IPv6=True"', True, 'IPv4 and IPv6'),
|
||||
(DEFAULTARGS + '-e "IPv6=False"', False, 'IPv4'),
|
||||
(DEFAULTARGS + '-e "IPv6=foobar"', False, 'IPv4'),
|
||||
])
|
||||
def test_IPv6_not_True_removes_ipv6(Docker, tag, args, expected_ipv6, expected_stdout):
|
||||
''' When a user overrides IPv6=True they only get IPv4 listening webservers '''
|
||||
IPV6_LINE = { 'alpine': 'listen \[::\]:80',
|
||||
IPV6_LINE = { 'alpine': 'listen [::]:80 default_server',
|
||||
'debian': 'use-ipv6.pl' }
|
||||
WEB_CONFIG = { 'alpine': '/etc/nginx/nginx.conf',
|
||||
'debian': '/etc/lighttpd/lighttpd.conf' }
|
||||
|
||||
function = Docker.run('. /bash_functions.sh ; setup_ipv4_ipv6')
|
||||
assert "Using {}".format(expected_stdout) in function.stdout
|
||||
ipv6 = Docker.run('grep -q \'{}\' {}'.format(IPV6_LINE[tag], WEB_CONFIG[tag])).rc == 0
|
||||
assert ipv6 == expected_ipv6
|
||||
config = Docker.run('cat {}'.format( WEB_CONFIG[tag])).stdout
|
||||
assert (IPV6_LINE[tag] in config) == expected_ipv6
|
||||
|
||||
@pytest.mark.parametrize('args, expected_stdout, dns1, dns2', [
|
||||
('-e ServerIP="1.2.3.4"', 'default DNS', '8.8.8.8', '8.8.4.4' ),
|
||||
|
@ -53,8 +55,8 @@ def test_DNS_interface_override_defaults(Docker, args, expected_stdout, expected
|
|||
assert expected_config_line + '\n' == docker_dns_interface
|
||||
|
||||
expected_debian_lines = [
|
||||
'"VIRTUAL_HOST" => "192.168.100.2"',
|
||||
'"ServerIP" => "192.168.100.2"',
|
||||
'"VIRTUAL_HOST" => "127.0.0.1"',
|
||||
'"ServerIP" => "127.0.0.1"',
|
||||
'"PHP_ERROR_LOG" => "/var/log/lighttpd/error.log"'
|
||||
]
|
||||
@pytest.mark.parametrize('tag,expected_lines,repeat_function', [
|
||||
|
@ -80,13 +82,13 @@ def test_webPassword_env_assigns_password_to_file(Docker, args, secure, setupVar
|
|||
''' When a user sets webPassword env the admin password gets set to that '''
|
||||
function = Docker.run('. /bash_functions.sh ; eval `grep setup_web_password /start.sh`')
|
||||
if secure and 'WEBPASSWORD' not in args:
|
||||
assert 'Assigning random password' in function.stdout
|
||||
assert 'assigning random password' in function.stdout.lower()
|
||||
else:
|
||||
assert 'Assigning random password' not in function.stdout
|
||||
assert 'assigning random password' not in function.stdout.lower()
|
||||
|
||||
if secure:
|
||||
assert 'New password set' in function.stdout
|
||||
assert 'new password set' in function.stdout.lower()
|
||||
assert Docker.run('grep -q \'{}\' {}'.format(setupVarsHash, '/etc/pihole/setupVars.conf')).rc == 0
|
||||
else:
|
||||
assert 'Password removed' in function.stdout
|
||||
assert 'password removed' in function.stdout.lower()
|
||||
assert Docker.run('grep -q \'^WEBPASSWORD=$\' /etc/pihole/setupVars.conf').rc == 0
|
||||
|
|
|
@ -33,8 +33,8 @@ def test_pihole_start_cmd(RunningPiHole, start_cmd, persist_tag):
|
|||
assert RunningPiHole.cmd.stdout == START_DNS_STDOUT[persist_tag]
|
||||
|
||||
@pytest.mark.parametrize('start_cmd,hostname,expected_ip', [
|
||||
('enable', 'pi.hole', '192.168.100.2'),
|
||||
('disable', 'pi.hole', '192.168.100.2'),
|
||||
('enable', 'pi.hole', '127.0.0.1'),
|
||||
('disable', 'pi.hole', '127.0.0.1'),
|
||||
])
|
||||
def test_pihole_start_cmd(RunningPiHole, Dig, persist_tag, start_cmd, hostname, expected_ip):
|
||||
''' the start_cmd tests are all built into the RunningPiHole fixture in this file '''
|
||||
|
|
|
@ -23,7 +23,7 @@ def test_ServerIP_missing_triggers_start_error(Docker):
|
|||
assert error_msg in start.stdout
|
||||
|
||||
@pytest.mark.parametrize('hostname,expected_ip', [
|
||||
('pi.hole', '192.168.100.2'),
|
||||
('pi.hole', '127.0.0.1'),
|
||||
('google-public-dns-a.google.com', '8.8.8.8'),
|
||||
('b.resolvers.Level3.net', '4.2.2.2')
|
||||
])
|
||||
|
@ -37,28 +37,32 @@ 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('ip', [ 'localhost', '[::]' ])
|
||||
@pytest.mark.parametrize('addr', [ 'testblock.pi-hole.local' ])
|
||||
@pytest.mark.parametrize('url', [ '/', '/index.html', '/any.html' ] )
|
||||
def test_html_index_requests_load_as_expected(RunningPiHole, ip, url):
|
||||
command = 'curl -s -o /tmp/curled_file -w "%{{http_code}}" http://{}{}'.format(ip, url)
|
||||
def test_html_index_requests_load_as_expected(RunningPiHole, Slow, addr, url):
|
||||
command = 'curl -s -o /tmp/curled_file -w "%{{http_code}}" http://{}{}'.format(addr, url)
|
||||
http_rc = RunningPiHole.run(command)
|
||||
assert RunningPiHole.run('grep -q "Access to the following site has been blocked" /tmp/curled_file ').rc == 0
|
||||
assert http_rc.rc == 0
|
||||
assert int(http_rc.stdout) == 200
|
||||
page_contents = RunningPiHole.run('cat /tmp/curled_file ').stdout
|
||||
assert 'blocked' in page_contents
|
||||
|
||||
@pytest.mark.parametrize('ip', [ '127.0.0.1', '[::]' ] )
|
||||
@pytest.mark.parametrize('addr', [ 'testblock.pi-hole.local' ])
|
||||
@pytest.mark.parametrize('url', [ '/index.js', '/any.js'] )
|
||||
def test_javascript_requests_load_as_expected(RunningPiHole, ip, url):
|
||||
command = 'curl -s -o /tmp/curled_file -w "%{{http_code}}" http://{}{}'.format(ip, url)
|
||||
def test_javascript_requests_load_as_expected(RunningPiHole, addr, url):
|
||||
command = 'curl -s -o /tmp/curled_file -w "%{{http_code}}" http://{}{}'.format(addr, url)
|
||||
http_rc = RunningPiHole.run(command)
|
||||
assert RunningPiHole.run('md5sum /tmp/curled_file /var/www/html/pihole/index.js').rc == 0
|
||||
assert http_rc.rc == 0
|
||||
assert int(http_rc.stdout) == 200
|
||||
assert RunningPiHole.run('md5sum /tmp/curled_file /var/www/html/pihole/index.js').rc == 0
|
||||
|
||||
# IPv6 checks aren't passing CORS, removed :(
|
||||
@pytest.mark.parametrize('ip', [ 'localhost' ] )
|
||||
@pytest.mark.parametrize('addr', [ 'localhost' ] )
|
||||
@pytest.mark.parametrize('url', [ '/admin/', '/admin/index.php' ] )
|
||||
def test_admin_requests_load_as_expected(RunningPiHole, ip, url):
|
||||
command = 'curl -s -o /tmp/curled_file -w "%{{http_code}}" http://{}{}'.format(ip, url)
|
||||
def test_admin_requests_load_as_expected(RunningPiHole, addr, url):
|
||||
command = 'curl -s -o /tmp/curled_file -w "%{{http_code}}" http://{}{}'.format(addr, url)
|
||||
http_rc = RunningPiHole.run(command)
|
||||
assert http_rc.rc == 0
|
||||
assert int(http_rc.stdout) == 200
|
||||
assert RunningPiHole.run('wc -l /tmp/curled_file ') > 10
|
||||
assert RunningPiHole.run('grep -q "Content-Security-Policy" /tmp/curled_file ').rc == 0
|
||||
|
|
Loading…
Reference in New Issue