Merge pull request #133 from diginc/dev

Development version of v3.0.1 release
This commit is contained in:
Adam Hill 2017-05-22 17:34:03 -05:00 committed by GitHub
commit 4f8d7f4720
37 changed files with 606 additions and 192 deletions

1
.dockerignore Normal file
View File

@ -0,0 +1 @@
**/*.sw*

View File

@ -17,16 +17,24 @@ 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
# 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
docker run -d \
--name pihole \
-p 53:53/tcp -p 53:53/udp -p 80:80 \
-v </path/to/store/pihole>:/etc/pihole \
-v </path/to/store/dnsmasq.d>:/etc/dnsmasq.d \
-e ServerIP="${IP:-$(ip route get 8.8.8.8 | awk '{ print $NF; exit }')}" \
-e ServerIPv6="${IPv6:-$(ip -6 route get 2001:4860:4860::8888 | awk '{ print $10; exit }')}" \
--restart=always \
diginc/pi-hole
```
This is just an example and might need changing. As mentioned on line 2, the auto IP_LOOKUP variable may not work for VPN tunnel interfaces.
Volumes aren't required but are recommended for persisting data across docker re-creations for updating images. This is just an example and might need changing. As mentioned on line 2, the auto IP_LOOKUP variable may not work for VPN tunnel interfaces.
**Automatic Ad List Updates** - [docker-pi-hole.cron](https://github.com/diginc/docker-pi-hole/blob/master/docker-pi-hole.cron) is a modified version of upstream pi-hole's crontab entries using `docker exec` to run the same update scripts inside the docker container. The cron automatically updates pi-hole ad lists and cleans up pi-hole logs nightly. If you're not using the `docker run` with `--name pihole` from default container run command be sure to fill in your container's DOCKER_NAME into the variable in the cron file.
**Automatic Ad List Updates** - since 3.0+ release cron is baked into the container and will grab the newest versions of your lists and flush your logs. **Set TZ** environment variable to make sure the midnight log rotation syncs up with your timezone's midnight.
## Environment Variables
@ -34,12 +42,14 @@ In addition to the required environment variable you saw above (`-e ServerIP="$I
| Env Variable | Default | Description |
| ------------ | ------- | ----------- |
| ServerIP | REQUIRED! | Set to your server's external IP in order to override what Pi-Hole users. Pi-Hole auto discovers the unusable internal docker IP otherwise |
| WEBPASSWORD | <random> | Set this to your desired password or on first boot we'll randomly set one. `docker logs pihole` can tell you what it got set to. To change it check out the tips below |
| ServerIP | REQUIRED! | Set to your server's external IP in order to override what Pi-Hole users requests get sent to. This container is designed to fail when not set since it is pretty useless without it. |
| ServerIPv6 | optional | Where IPv6 ad requests end up, not required if you're not running ipv6 network |
| WEBPASSWORD | <random> | Recommended! Set this to your desired password or on first boot we'll randomly set one. `docker logs pihole` can tell you what it got set to. To change it check out the tips below |
| DNS1 | 8.8.8.8 | Primary upstream DNS for Pi-Hole's DNSMasq to use, defaults to google |
| DNS2 | 8.8.4.4 | Secondary upstream DNS for Pi-Hole's DNSMasq to use, defaults to google |
| VIRTUAL_HOST | Server_IP | What your web server 'virtual host' is, accessing admin through this Hostname/IP allows you to make changes to the whitelist / blacklists in addition to the default 'http://pi.hole/admin/' address |
| IPv6 | True | Allows forced disabling of IPv6 for docker setups that can't support it (like unraid) |
| TZ | UCT | Customize your container's timezone, useful if you use the cron for pihole updates |
*OPTIONAL Advanced* Environment Variables
@ -52,19 +62,19 @@ In addition to the required environment variable you saw above (`-e ServerIP="$I
* A good way to test things are working right is by loading this page: [http://pi.hole/admin/](http://pi.hole/admin/)
* [How do I set or reset the Web interface Password?](https://discourse.pi-hole.net/t/how-do-i-set-or-reset-the-web-interface-password/1328)
* `docker exec pihole_container_name pihole -a -p supersecurepassword`
* `docker exec pihole_container_name pihole -a -p supersecurepassword`
* Port conflicts? Stop your server's existing DNS / Web services.
* Ubuntu users especially may need to shutoff dnsmasq on your docker server so it can run in the container on port 53
* Don't forget to stop your services from auto-starting again after you reboot
* Ubuntu users especially may need to shutoff dnsmasq on your docker server so it can run in the container on port 53
* Don't forget to stop your services from auto-starting again after you reboot
* Port 80 is highly recommended because if you have another site/service using port 80 by default then the ads may not transform into blank ads correctly. To make sure docker-pi-hole plays nicely with an existing webserver you run you'll probably need a reverse proxy webserver config if you don't have one already. Pi-Hole has to be the default web app on said proxy e.g. if you goto your host by IP instead of domain then pi-hole is served out instead of any other sites hosted by the proxy. This is the '[default_server](http://nginx.org/en/docs/http/ngx_http_core_module.html#listen)' in nginx or ['_default_' virtual host](https://httpd.apache.org/docs/2.4/vhosts/examples.html#default) in Apache and is taken advantage of so any undefined ad domain can be directed to your webserver and get a 'blocked' response instead of ads.
* You can still map other ports to pi-hole port 80 using docker's port forwarding like this `-p 8080:80`, but again the ads won't render propertly. Changing the inner port 80 shouldn't be required unless you run docker host networking mode.
* [Here is an example of running with jwilder/proxy](https://github.com/diginc/docker-pi-hole/blob/master/jwilder-proxy-example-doco.yml) (an nginx auto-configuring docker reverse proxy for docker) on my port 80 with pihole on another port. Pi-hole needs to be `DEFAULT_HOST` env in jwilder/proxy and you need to set the matching `VIRTUAL_HOST` for the pihole's container. Please read jwilder/proxy readme for more info if you have trouble. I tested this basic example which is based off what I run.
* You can still map other ports to pi-hole port 80 using docker's port forwarding like this `-p 8080:80`, but again the ads won't render propertly. Changing the inner port 80 shouldn't be required unless you run docker host networking mode.
* [Here is an example of running with jwilder/proxy](https://github.com/diginc/docker-pi-hole/blob/master/jwilder-proxy-example-doco.yml) (an nginx auto-configuring docker reverse proxy for docker) on my port 80 with pihole on another port. Pi-hole needs to be `DEFAULT_HOST` env in jwilder/proxy and you need to set the matching `VIRTUAL_HOST` for the pihole's container. Please read jwilder/proxy readme for more info if you have trouble. I tested this basic example which is based off what I run.
## Volume Mounts
Here are some useful volume mount options to persist your history of stats in the admin interface, or add custom whitelists/blacklists. **Create these files on the docker host first or you'll get errors**:
* `docker run -v /var/log/pihole.log:/var/log/pihole.log ...` (plus all of the minimum options added)
* `touch /var/log/pihole.log` on your docker server first or you will end up with a directory there (silly docker!)
* `touch /var/log/pihole.log` on your docker server first or you will end up with a directory there (silly docker!)
* `docker run -v /etc/pihole/:/etc/pihole/ ...` (plus all of the minimum options added)
All of these options get really long when strung together in one command, which is why I'm not showing all the full `docker run` commands variations here. This is where [docker-compose](https://docs.docker.com/compose/install/) yml files come in handy for representing [really long docker commands in a readable file format](https://github.com/diginc/docker-pi-hole/blob/master/doco-example.yml).
@ -103,8 +113,8 @@ The standard pi-hole customization abilities apply to this docker, but with dock
1. Download the latest version of the image: `docker pull diginc/pi-hole`
2. Throw away your container: `docker rm -f pihole`
* **Warning** When removing your pihole container you may be stuck without DNS until step 3 - **docker pull** before you **docker rm -f** to avoid DNS inturruption **OR** always have a fallback DNS server configured in DHCP to avoid this problem all together.
* If you care about your data (logs/customizations), make sure you have it volume mapped or it will be deleted in this step
* **Warning** When removing your pihole container you may be stuck without DNS until step 3 - **docker pull** before you **docker rm -f** to avoid DNS inturruption **OR** always have a fallback DNS server configured in DHCP to avoid this problem all together.
* If you care about your data (logs/customizations), make sure you have it volume mapped or it will be deleted in this step
3. Start your container with the newer base image: `docker run <args> diginc/pi-hole` (`<args>` being your preferred run volumes and env vars)
Why is this style of upgrading good? A couple reasons: Everyone is starting from the same base image which has been tested to know it works. No worrying about upgrading from A to B, B to C, or A to C is required when rolling out updates, it reducing complexity, and simply allows a 'fresh start' every time while preserving customizations with volumes. Basically I'm encouraging [phoenix servers](https://www.google.com/?q=phoenix+servers) principles for your containers.

View File

@ -4,26 +4,22 @@ MAINTAINER adam@diginc.us <adam@diginc.us>
ENV IMAGE alpine
ENV PATH /opt/pihole:${PATH}
COPY install.sh /install.sh
COPY ./alpine/service /usr/local/bin/service
COPY install.sh /usr/local/bin/docker-install.sh
ENV setupVars /etc/pihole/setupVars.conf
ENV PIHOLE_INSTALL /tmp/ph_install.sh
ENV S6OVERLAY_RELEASE https://github.com/just-containers/s6-overlay/releases/download/v1.19.1.1/s6-overlay-amd64.tar.gz
ENV TINI_VERSION v0.13.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static /tini
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static.asc /tini.asc
# Tini and package requirements
RUN apk add --update 'gnupg<2.1.17-r0' && \
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0527A9B7 && \
gpg --verify /tini.asc && \
chmod +x /tini && \
apk add wget bash && \
/install.sh && \
RUN apk upgrade --update && \
apk add bind-tools wget curl bash libcap && \
curl -L -s $S6OVERLAY_RELEASE \
| tar xvzf - -C / && \
docker-install.sh && \
rm -rf /var/cache/apk/*
# Customized from submodules
COPY ./alpine/nginx.conf /etc/nginx/nginx.conf
ENTRYPOINT [ "/init" ]
ADD s6/alpine-root /
COPY s6/service /usr/local/bin/service
# Things installer did and fix alpine+nginx differences
ENV WEBLOGDIR /var/log/nginx
@ -35,29 +31,30 @@ 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 && \
chown dnsmasq:root /var/log/pihole.log && \
sed -i "s/@INT@/eth0/" /etc/dnsmasq.d/01-pihole.conf && \
setcap CAP_NET_BIND_SERVICE=+eip `which dnsmasq` && \
cp -f /usr/bin/list.sh /opt/pihole/list.sh && \
echo 'Done!'
#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 && \
#sed -i 's|www-data|nginx|g' /etc/sudoers.d/pihole && \
# php config start passes special ENVs into
ENV PHP_ENV_CONFIG '/etc/php5/fpm.d/envs.conf'
ENV PHP_ERROR_LOG '/var/log/nginx/error.log'
COPY ./start.sh /
COPY ./bash_functions.sh /
# IPV6 disable flag for networks/devices that do not support it
# IPv6 disable flag for networks/devices that do not support it
ENV IPv6 True
EXPOSE 53 53/udp
EXPOSE 80
ENV S6_LOGGING 0
ENV S6_KEEP_ENV 1
ENV S6_BEHAVIOUR_IF_STAGE2_FAILS 2
SHELL ["/bin/bash", "-c"]
ENTRYPOINT ["/tini", "--"]
CMD [ "/start.sh" ]

View File

@ -1,55 +0,0 @@
#!/bin/bash
# lazy cheap service script patch for alpine
dnsmasq_start() {
dnsmasq -7 /etc/dnsmasq.d
}
dnsmasq_stop() {
kill -9 $(pidof dnsmasq)
}
dnsmasq_restart() {
dnsmasq_stop; dnsmasq_start;
}
status() {
if pidof $service 2&>1 > /dev/null ; then
echo "$service running"
else
echo "$service not running"
fi;
}
nginx_start() {
nginx -t && \
nginx
}
nginx_stop() {
nginx -t && \
kill -9 $(pidof nginx)
}
nginx_restart() {
nginx_stop
nginx_start
}
dnsmasq_status() {
status
}
nginx_status() {
status
}
service="$1"
command="$2"
if [[ "$service" == 'lighttpd' ]] ; then
echo -e "Lighttpd replaced by nginx in diginc/pi-hole:alpine\nrunning service nginx $command instead";
service='nginx'
fi;
if [[ "$service" == 'dnsmasq' ]] || [[ "$service" == 'nginx' ]] ; then
${service}_${command} || echo "Unknown option $command"
else
echo "$service service wrapper not patched into alpine container"
exit 1
fi

View File

@ -2,6 +2,7 @@
. /opt/pihole/webpage.sh
setupVars="$setupVars"
ServerIP="$ServerIP"
ServerIPv6="$ServerIPv6"
IPv6="$IPv6"
prepare_setup_vars() {
@ -13,6 +14,32 @@ validate_env() {
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;
# Debian
nc_error='Name or service not known'
if [[ "$IMAGE" == 'alpine' ]] ; then
nc_error='bad address'
fi;
# Required ServerIP is a valid IP
if nc -w1 -z "$ServerIP" 53 2>&1 | grep -q "$nc_error" ; then
echo "ERROR: ServerIP Environment variable ($ServerIP) doesn't appear to be a valid IPv4 address"
exit 1
fi
# Optional IPv6 is a valid address
if [[ -n "$ServerIPv6" ]] ; then
if [[ "$ServerIPv6" == 'kernel' ]] ; then
echo "WARNING: You passed in IPv6 with a value of 'kernel', this maybe beacuse you do not have IPv6 enabled on your network"
unset ServerIPv6
return
fi
if nc -w 1 -z "$ServerIPv6" 53 2>&1 | grep -q "$nc_error" || ! ip route get "$ServerIPv6" ; then
echo "ERROR: ServerIPv6 Environment variable ($ServerIPv6) doesn't appear to be a valid IPv6 address"
echo " TIP: If your server is not IPv6 enabled just remove '-e ServerIPv6' from your docker container"
exit 1
fi
fi;
}
setup_dnsmasq_dns() {
@ -134,7 +161,13 @@ setup_web_password() {
WEBPASSWORD=$(tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 8)
echo "Assigning random password: $WEBPASSWORD"
fi;
pihole -a -p "$WEBPASSWORD"
set -x
if [[ "$WEBPASSWORD" == "" ]] ; then
echo "" | pihole -a -p
else
pihole -a -p "$WEBPASSWORD" "$WEBPASSWORD"
fi
{ set +x; } 2>/dev/null
}
setup_ipv4_ipv6() {
local ip_versions="IPv4 and IPv6"
@ -142,7 +175,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"
@ -178,7 +211,11 @@ 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
}
docker_main() {

View File

@ -6,22 +6,23 @@ RUN [ "cross-build-start" ]
ENV IMAGE debian
ENV PATH /opt/pihole:${PATH}
COPY install.sh /install.sh
COPY install.sh /usr/local/bin/docker-install.sh
ENV setupVars /etc/pihole/setupVars.conf
ENV PIHOLE_INSTALL /tmp/ph_install.sh
ENV S6OVERLAY_RELEASE https://github.com/just-containers/s6-overlay/releases/download/v1.19.1.1/s6-overlay-armhf.tar.gz
ENV TINI_VERSION v0.13.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-armhf /tini
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-armhf.asc /tini.asc
RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0527A9B7 && \
gpg --verify /tini.asc && \
chmod +x /tini && \
apt-get -q update && \
apt-get install -y wget net-tools && \
/install.sh && \
RUN apt-get update && \
apt-get install -y wget curl net-tools cron && \
curl -L -s $S6OVERLAY_RELEASE \
| tar xvzf - -C / && \
docker-install.sh && \
rm -rf /var/cache/apt/archives /var/lib/apt/lists/*
ENTRYPOINT [ "/init" ]
ADD s6/debian-root /
COPY s6/service /usr/local/bin/service
# 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'
@ -35,8 +36,10 @@ ENV IPv6 True
EXPOSE 53 53/udp
EXPOSE 80
SHELL ["/bin/bash", "-c"]
ENTRYPOINT ["/tini", "--"]
CMD [ "/start.sh" ]
ENV S6_LOGGING 0
ENV S6_KEEP_ENV 1
ENV S6_BEHAVIOUR_IF_STAGE2_FAILS 2
RUN [ "cross-build-end" ]
SHELL ["/bin/bash", "-c"]
RUN [ "cross-build-end" ]

View File

@ -4,22 +4,23 @@ MAINTAINER adam@diginc.us <adam@diginc.us>
ENV IMAGE debian
ENV PATH /opt/pihole:${PATH}
COPY install.sh /install.sh
COPY install.sh /usr/local/bin/docker-install.sh
ENV setupVars /etc/pihole/setupVars.conf
ENV PIHOLE_INSTALL /tmp/ph_install.sh
ENV S6OVERLAY_RELEASE https://github.com/just-containers/s6-overlay/releases/download/v1.19.1.1/s6-overlay-amd64.tar.gz
ENV TINI_VERSION v0.13.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini.asc /tini.asc
RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0527A9B7 && \
gpg --verify /tini.asc && \
chmod +x /tini && \
apt-get -q update && \
apt-get install -y wget net-tools && \
/install.sh && \
RUN apt-get update && \
apt-get install -y wget curl net-tools cron && \
curl -L -s $S6OVERLAY_RELEASE \
| tar xvzf - -C / && \
docker-install.sh && \
rm -rf /var/cache/apt/archives /var/lib/apt/lists/*
ENTRYPOINT [ "/init" ]
ADD s6/debian-root /
COPY s6/service /usr/local/bin/service
# 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'
@ -33,6 +34,8 @@ ENV IPv6 True
EXPOSE 53 53/udp
EXPOSE 80
ENV S6_LOGGING 0
ENV S6_KEEP_ENV 1
ENV S6_BEHAVIOUR_IF_STAGE2_FAILS 2
SHELL ["/bin/bash", "-c"]
ENTRYPOINT ["/tini", "--"]
CMD [ "/start.sh" ]

View File

@ -1,12 +1,21 @@
#!/bin/bash
IMAGE=${1:-'diginc/pi-hole:alpine'}
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
IPv6="${IPv6:-$IPv6_LOOKUP}" # use $IPv6, if set, otherwise IP_LOOKUP
echo "IP: ${IP} - IPv6: ${IPv6}"
# Default ports + daemonized docker container
docker run -p 53:53/tcp -p 53:53/udp -p 80:80 \
--cap-add=NET_ADMIN \
-e ServerIP="$IP" \
--name pihole \
--restart=always \
-d "$IMAGE"
docker run -d \
--name pihole \
-p 53:53/tcp -p 53:53/udp -p 80:80 \
-v /etc/volumes/pihole:/etc/pihole \
-v /etc/volumes/dnsmasq.d:/etc/dnsmasq.d \
-e ServerIP="${IP:-$(ip route get 8.8.8.8 | awk '{ print $NF; exit }')}" \
-e ServerIPv6="${IPv6:-$(ip -6 route get 2001:4860:4860::8888 | awk '{ print $10; exit }')}" \
--restart=always \
diginc/pi-hole
docker logs pihole 2> /dev/null | grep 'password:'

View File

@ -1,7 +1,8 @@
#!/bin/bash -x
#!/bin/bash -ex
mkdir -p /etc/pihole/
export CORE_TAG='v2.13.2'
export WEB_TAG='v2.5.2'
export CORE_TAG='v3.0.1'
export WEB_TAG='v3.0.1'
export FTL_TAG='v2.7'
# Make pihole scripts fail searching for `systemctl`,
# which fails pretty miserably in docker compared to `service`
@ -21,6 +22,11 @@ if [[ "$IMAGE" == 'alpine' ]] ; then
sed -i 's/www-data/nginx/g' "$PIHOLE_INSTALL"
sed -i '/LIGHTTPD_CFG/d' "${PIHOLE_INSTALL}"
sed -i '/etc\/cron.d\//d' "${PIHOLE_INSTALL}"
# 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
@ -36,13 +42,17 @@ if [[ "$IMAGE" == 'debian' ]] ; then
install_dependent_packages PIHOLE_DEPS[@]
install_dependent_packages PIHOLE_WEB_DEPS[@]
sed -i "/sleep 2/ d" /etc/init.d/dnsmasq # SLOW
# IPv6 support for nc openbsd better than traditional
apt-get install -y --force-yes netcat-openbsd
elif [[ "$IMAGE" == 'alpine' ]] ; then
apk add \
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
fi
piholeGitUrl="${piholeGitUrl}"
@ -64,9 +74,13 @@ tmpLog="${tmpLog}"
instalLogLoc="${instalLogLoc}"
installPihole | tee "${tmpLog}"
sed -i 's/readonly //g' /opt/pihole/webpage.sh
if [[ "$IMAGE" == 'alpine' ]] ; then
cp /etc/.pihole/advanced/pihole.cron /etc/crontabs/pihole
fi
mv "${tmpLog}" "${instalLogLoc}"
# Fix dnsmasq in docker
grep -q '^user=root' || echo -e '\nuser=root' >> /etc/dnsmasq.conf
echo 'done'
echo 'Docker install successful'

View File

@ -0,0 +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

View File

@ -0,0 +1 @@
/etc/resolv.conf false doesntexist,0:1000 0664 0664

View File

@ -12,8 +12,10 @@ 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;

View File

@ -0,0 +1,5 @@
#!/usr/bin/with-contenv bash
s6-echo "Starting crond"
exec -c
fdmove -c 2 1 /usr/sbin/crond -f -L /var/log/cron -l 0 -c /etc/crontabs

View File

@ -0,0 +1,3 @@
#!/usr/bin/with-contenv bash
kill -9 $(pgrep dnsmasq)

View File

@ -0,0 +1,5 @@
#!/usr/bin/with-contenv bash
s6-echo "Starting dnsmasq"
s6-setuidgid dnsmasq dnsmasq -7 /etc/dnsmasq.d --no-daemon

View File

@ -0,0 +1,6 @@
#!/usr/bin/with-contenv bash
s6-svwait -u -t 5000 /var/run/s6/services/php-fpm
s6-echo "Starting nginx"
nginx -g "daemon off;"

View File

@ -0,0 +1,5 @@
#!/usr/bin/with-contenv bash
s6-echo "Starting php-fpm"
php-fpm5 -d daemonize=no

View File

@ -0,0 +1,4 @@
#!/usr/bin/with-contenv bash
s6-echo "Starting pihole-FTL"
pihole-FTL no-daemon

10
s6/alpine-root/usr/bin/host-ip Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/with-contenv sh
#
# This script will determine the network IP of the container.
#
# Return format should be a single IP address.
#
# Default to using the value of the $HOSTNAME ENV variable.
getent hosts ${1:-$HOSTNAME} | awk '{print $1}'

235
s6/alpine-root/usr/bin/list.sh Executable file
View File

@ -0,0 +1,235 @@
#!/usr/bin/env bash
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# Whitelists and blacklists domains
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
#globals
basename=pihole
piholeDir=/etc/${basename}
whitelist=${piholeDir}/whitelist.txt
blacklist=${piholeDir}/blacklist.txt
readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
reload=false
addmode=true
verbose=true
domList=()
domToRemoveList=()
listMain=""
listAlt=""
helpFunc() {
if [[ ${listMain} == ${whitelist} ]]; then
letter="w"
word="white"
else
letter="b"
word="black"
fi
cat << EOM
::: Immediately ${word}lists one or more domains in the hosts file
:::
::: Usage: pihole -${letter} domain1 [domain2 ...]
:::
::: Options:
::: -d, --delmode Remove domains from the ${word}list
::: -nr, --noreload Update ${word}list without refreshing dnsmasq
::: -q, --quiet Output is less verbose
::: -h, --help Show this help dialog
::: -l, --list Display your ${word}listed domains
EOM
if [[ "${letter}" == "b" ]]; then
echo "::: -wild, --wildcard Add wildcard entry (only blacklist)"
fi
exit 0
}
EscapeRegexp() {
# This way we may safely insert an arbitrary
# string in our regular expressions
# Also remove leading "." if present
echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
}
HandleOther(){
# First, convert everything to lowercase
domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1")
#check validity of domain
validDomain=$(echo "${domain}" | perl -lne 'print if /(?!.*[^a-z0-9-\.].*)^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9-]+\.)*[a-z]{2,63}/')
if [ -z "${validDomain}" ]; then
echo "::: $1 is not a valid argument or domain name"
else
domList=("${domList[@]}" ${validDomain})
fi
}
PoplistFile() {
#check whitelist file exists, and if not, create it
if [[ ! -f ${whitelist} ]]; then
touch ${whitelist}
fi
for dom in "${domList[@]}"; do
# Logic : If addmode then add to desired list and remove from the other; if delmode then remove from desired list but do not add to the other
if ${addmode}; then
AddDomain "${dom}" "${listMain}"
RemoveDomain "${dom}" "${listAlt}"
if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then
RemoveDomain "${dom}" "${wildcardlist}"
fi
else
RemoveDomain "${dom}" "${listMain}"
fi
done
}
AddDomain() {
list="$2"
domain=$(EscapeRegexp "$1")
if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
bool=true
#Is the domain in the list we want to add it to?
grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
if [[ "${bool}" == false ]]; then
#domain not found in the whitelist file, add it!
if [[ "${verbose}" == true ]]; then
echo "::: Adding $1 to $list..."
fi
reload=true
# Add it to the list we want to add it to
echo "$1" >> "${list}"
else
if [[ "${verbose}" == true ]]; then
echo "::: ${1} already exists in ${list}, no need to add!"
fi
fi
elif [[ "${list}" == "${wildcardlist}" ]]; then
source "${piholeDir}/setupVars.conf"
#Remove the /* from the end of the IPv4addr.
IPV4_ADDRESS=${IPV4_ADDRESS%/*}
IPV6_ADDRESS=${IPV6_ADDRESS}
bool=true
#Is the domain in the list?
grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
if [[ "${bool}" == false ]]; then
if [[ "${verbose}" == true ]]; then
echo "::: Adding $1 to wildcard blacklist..."
fi
reload=true
echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}"
if [[ ${#IPV6_ADDRESS} > 0 ]] ; then
echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}"
fi
else
if [[ "${verbose}" == true ]]; then
echo "::: ${1} already exists in wildcard blacklist, no need to add!"
fi
fi
fi
}
RemoveDomain() {
list="$2"
domain=$(EscapeRegexp "$1")
if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
bool=true
#Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa
grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
if [[ "${bool}" == true ]]; then
# Remove it from the other one
echo "::: Removing $1 from $list..."
# Busybox sed compatible case-insensitive domain removal
sed -i "$(grep -in "^${domain}$" ${list} | awk -F':' '{print $1}' | tr '\n' ',' | sed 's/,$/\n/')d" ${list}
reload=true
else
if [[ "${verbose}" == true ]]; then
echo "::: ${1} does not exist in ${list}, no need to remove!"
fi
fi
elif [[ "${list}" == "${wildcardlist}" ]]; then
bool=true
#Is it in the list?
grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
if [[ "${bool}" == true ]]; then
# Remove it from the other one
echo "::: Removing $1 from $list..."
# Busybox sed compatible case-insensitive domain removal
sed -i "$(grep -in "/${domain}/" ${list} | awk -F':' '{print $1}' | tr '\n' ',' | sed 's/,$/\n/')d" ${list}
reload=true
else
if [[ "${verbose}" == true ]]; then
echo "::: ${1} does not exist in ${list}, no need to remove!"
fi
fi
fi
}
Reload() {
# Reload hosts file
pihole -g -sd
}
Displaylist() {
if [[ ${listMain} == ${whitelist} ]]; then
string="gravity resistant domains"
else
string="domains caught in the sinkhole"
fi
verbose=false
echo -e " Displaying $string \n"
count=1
while IFS= read -r RD; do
echo "${count}: ${RD}"
count=$((count+1))
done < "${listMain}"
exit 0;
}
for var in "$@"; do
case "${var}" in
"-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";;
"-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";;
"-wild" | "wildcard" ) listMain="${wildcardlist}";;
"-nr"| "--noreload" ) reload=false;;
"-d" | "--delmode" ) addmode=false;;
"-f" | "--force" ) force=true;;
"-q" | "--quiet" ) verbose=false;;
"-h" | "--help" ) helpFunc;;
"-l" | "--list" ) Displaylist;;
* ) HandleOther "${var}";;
esac
done
shift
if [[ $# = 0 ]]; then
helpFunc
fi
PoplistFile
if ${reload}; then
Reload
fi

View File

@ -0,0 +1,12 @@
#!/usr/bin/execlineb -S0
if { s6-test $# -eq 2 }
backtick -in FILENAME {
pipeline { s6-echo "${1}" }
tr "a-z" "A-Z"
}
import -u FILENAME
redirfd -w 1 /var/run/s6/container_environment/${FILENAME}
s6-echo -n -- ${2}

View File

@ -0,0 +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

View File

@ -0,0 +1 @@
/etc/resolv.conf false doesntexist,0:1000 0664 0664

View File

@ -0,0 +1,5 @@
#!/usr/bin/with-contenv bash
s6-echo "Starting crond"
exec -c
fdmove -c 2 1 /usr/sbin/cron -f

View File

@ -0,0 +1,3 @@
#!/usr/bin/with-contenv bash
kill -9 $(pgrep dnsmasq)

View File

@ -0,0 +1,5 @@
#!/usr/bin/with-contenv bash
s6-echo "Starting dnsmasq"
s6-setuidgid root dnsmasq -7 /etc/dnsmasq.d --no-daemon

View File

@ -0,0 +1,5 @@
#!/usr/bin/with-contenv bash
s6-echo "Starting lighttpd"
lighttpd -D -f /etc/lighttpd/lighttpd.conf

View File

@ -0,0 +1,4 @@
#!/usr/bin/with-contenv bash
s6-echo "Starting pihole-FTL"
pihole-FTL no-daemon

10
s6/debian-root/usr/bin/host-ip Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/with-contenv sh
#
# This script will determine the network IP of the container.
#
# Return format should be a single IP address.
#
# Default to using the value of the $HOSTNAME ENV variable.
getent hosts ${1:-$HOSTNAME} | awk '{print $1}'

View File

@ -0,0 +1,12 @@
#!/usr/bin/execlineb -S0
if { s6-test $# -eq 2 }
backtick -in FILENAME {
pipeline { s6-echo "${1}" }
tr "a-z" "A-Z"
}
import -u FILENAME
redirfd -w 1 /var/run/s6/container_environment/${FILENAME}
s6-echo -n -- ${2}

30
s6/service Executable file
View File

@ -0,0 +1,30 @@
#!/bin/bash
# This script patches all service commands into the appropriate s6- commands
# pi-hole upstream scripts need a 'service' interface. why not systemd? docker said so.
start() {
s6-svc -wU -u -T2500 /var/run/s6/services/$service
}
stop() {
s6-svc -wD -d -T2500 /var/run/s6/services/$service
}
restart() {
stop
start
#s6-svc -t -wR -T5000 /var/run/s6/services/$service
}
status() {
s6-svstat /var/run/s6/services/$service
}
service="$1"
command="$2"
if [[ ! -d "/var/run/s6/services/$service" ]] ; then
echo "s6 service not found for $service, exiting..."
exit
fi;
${command} "${service}"

View File

@ -16,7 +16,7 @@ export IPv6
. /bash_functions.sh
echo " ::: Starting docker specific setup for docker diginc/pi-hole"
validate_env
validate_env || exit 1
prepare_setup_vars
change_setting "IPV4_ADDRESS" "$ServerIP"
change_setting "IPV6_ADDRESS" "$ServerIPv6"
@ -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"
docker_main "$IMAGE"
# s6's init takes care of running services now, no more main start services function

View File

@ -10,12 +10,14 @@ 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 += " --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():
check_output("docker rm -f %s", docker_id)
check_output("docker logs {}".format(docker_id))
check_output("docker rm -f {}".format(docker_id))
request.addfinalizer(teardown)
docker_container = testinfra.get_backend("docker://" + docker_id)
@ -42,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)
@ -52,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):
@ -68,27 +70,27 @@ def image(request, tag):
@pytest.fixture()
def cmd(request):
return '/start.sh'
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 '/start.sh'
return 'tail -f /dev/null'
@pytest.fixture
def Slow():
@ -96,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:
@ -110,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 '''

View File

@ -1,28 +1,25 @@
import pytest
import re
# Override these docker command pieces to minimize parameter repititon
@pytest.fixture()
def cmd(request):
return 'tail -f /dev/null'
DEFAULTARGS = '-e ServerIP="127.0.0.1" '
@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 +50,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 +77,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

View File

@ -5,23 +5,20 @@ def start_cmd():
''' broken by default, required override '''
return None
START_DNS_STDOUT = {
'alpine': '',
'debian': 'Restarting DNS forwarder and DHCP server: dnsmasq.\n'
}
@pytest.fixture
def RunningPiHole(DockerPersist, Slow, persist_webserver, persist_tag, start_cmd):
''' Override the RunningPiHole to run and check for success of a
dnsmasq start based `pihole` script command '''
#print DockerPersist.run('ps -ef').stdout
Slow(lambda: DockerPersist.run('pgrep dnsmasq').rc == 0)
Slow(lambda: DockerPersist.run('pgrep {}'.format(persist_webserver) ).rc == 0)
Slow(lambda: DockerPersist.run('pgrep {}'.format(persist_webserver)).rc == 0)
oldpid = DockerPersist.run('pidof dnsmasq')
cmd = DockerPersist.run('pihole {}'.format(start_cmd))
Slow(lambda: DockerPersist.run('pgrep dnsmasq').rc == 0)
newpid = DockerPersist.run('pidof dnsmasq')
for pid in [oldpid, newpid]:
assert pid != ''
# ensure a new pid for dnsmasq appeared
# ensure a new pid for dnsmasq appeared due to service restart
assert oldpid != newpid
assert cmd.rc == 0
# Save out cmd result to check different stdout of start/enable/disable
@ -34,8 +31,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 '''
@ -43,5 +40,5 @@ def test_pihole_start_cmd(RunningPiHole, Dig, persist_tag, start_cmd, hostname,
lookup = RunningPiHole.dig.run(dig_cmd).stdout.rstrip('\n')
assert lookup == expected_ip
stdout = "::: Blocking has been {}d!\n{}".format(start_cmd, START_DNS_STDOUT[persist_tag])
stdout = "::: Blocking has been {}d!\n".format(start_cmd)
assert RunningPiHole.cmd.stdout == stdout

View File

@ -7,7 +7,7 @@ run_local = testinfra.get_backend(
def test_scripts_pass_shellcheck():
''' Make sure shellcheck does not find anything wrong with our shell scripts '''
shellcheck = "find . -name '*.sh' | while read file; do shellcheck $file; done;"
shellcheck = "find . -name '*.sh' -a ! ( -name 'list.sh' ) | while read file; do shellcheck -e SC1008 $file; done;"
results = run_local(shellcheck)
print results.stdout
assert '' == results.stdout

View File

@ -14,7 +14,6 @@ def test_pihole_default_run_command(Docker, tag):
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')
@ -22,8 +21,20 @@ def test_ServerIP_missing_triggers_start_error(Docker):
assert start.rc == 1
assert error_msg in start.stdout
@pytest.mark.parametrize('args,error_msg,expect_rc', [
('-e ServerIP="1.2.3.z"', "ServerIP Environment variable (1.2.3.z) doesn't appear to be a valid IPv4 address",1),
('-e ServerIP="1.2.3.4" -e ServerIPv6="1234:1234:1234:ZZZZ"', "Environment variable (1234:1234:1234:ZZZZ) doesn't appear to be a valid IPv6 address",1),
('-e ServerIP="1.2.3.4" -e ServerIPv6="kernel"', "WARNING: You passed in IPv6 with a value of 'kernel'",0),
])
def test_ServerIP_invalid_IPs_triggers_exit_error(Docker, error_msg, expect_rc):
''' When args to docker are empty start.sh exits saying ServerIP is required '''
start = Docker.run('/start.sh')
assert start.rc == expect_rc
assert 'ERROR' in start.stdout
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 +48,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