mirror of
https://github.com/pi-hole/pi-hole
synced 2025-01-08 23:20:56 +00:00
commit
1b809e4e8e
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -36,10 +36,10 @@ jobs:
|
|||||||
name: Checkout repository
|
name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
-
|
-
|
||||||
name: Set up Python 3.7
|
name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.8
|
||||||
-
|
-
|
||||||
name: Install dependencies
|
name: Install dependencies
|
||||||
run: pip install -r test/requirements.txt
|
run: pip install -r test/requirements.txt
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,3 +9,4 @@ __pycache__
|
|||||||
*.egg-info
|
*.egg-info
|
||||||
.idea/
|
.idea/
|
||||||
*.iml
|
*.iml
|
||||||
|
.vscode/
|
||||||
|
107
CONTRIBUTING.md
107
CONTRIBUTING.md
@ -2,111 +2,6 @@
|
|||||||
|
|
||||||
Please read and understand the contribution guide before creating an issue or pull request.
|
Please read and understand the contribution guide before creating an issue or pull request.
|
||||||
|
|
||||||
## Etiquette
|
The guide can be found here: [https://docs.pi-hole.net/guides/github/contributing/](https://docs.pi-hole.net/guides/github/contributing/)
|
||||||
|
|
||||||
- Our goal for Pi-hole is **stability before features**. This means we focus on squashing critical bugs before adding new features. Often, we can do both in tandem, but bugs will take priority over a new feature.
|
|
||||||
- Pi-hole is open source and [powered by donations](https://pi-hole.net/donate/), and as such, we give our **free time** to build, maintain, and **provide user support** for this project. It would be extremely unfair for us to suffer abuse or anger for our hard work, so please take a moment to consider that.
|
|
||||||
- Please be considerate towards the developers and other users when raising issues or presenting pull requests.
|
|
||||||
- Respect our decision(s), and do not be upset or abusive if your submission is not used.
|
|
||||||
|
|
||||||
## Viability
|
|
||||||
|
|
||||||
When requesting or submitting new features, first consider whether it might be useful to others. Open source projects are used by many people, who may have entirely different needs to your own. Think about whether or not your feature is likely to be used by other users of the project.
|
|
||||||
|
|
||||||
## Procedure
|
|
||||||
|
|
||||||
**Before filing an issue:**
|
|
||||||
|
|
||||||
- Attempt to replicate and **document** the problem, to ensure that it wasn't a coincidental incident.
|
|
||||||
- Check to make sure your feature suggestion isn't already present within the project.
|
|
||||||
- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
|
|
||||||
- Check the pull requests tab to ensure that the feature isn't already in progress.
|
|
||||||
|
|
||||||
**Before submitting a pull request:**
|
|
||||||
|
|
||||||
- Check the codebase to ensure that your feature doesn't already exist.
|
|
||||||
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
|
|
||||||
- Read and understand the [DCO guidelines](https://docs.pi-hole.net/guides/github/contributing/) for the project.
|
|
||||||
|
|
||||||
## Technical Requirements
|
|
||||||
|
|
||||||
- Submit Pull Requests to the **development branch only**.
|
|
||||||
- Before Submitting your Pull Request, merge `development` with your new branch and fix any conflicts. (Make sure you don't break anything in development!)
|
|
||||||
- Please use the [Google Style Guide for Shell](https://google.github.io/styleguide/shell.xml) for your code submission styles.
|
|
||||||
- Commit Unix line endings.
|
|
||||||
- Please use the Pi-hole brand: **Pi-hole** (Take a special look at the capitalized 'P' and a low 'h' with a hyphen)
|
|
||||||
- (Optional fun) keep to the theme of Star Trek/black holes/gravity.
|
|
||||||
|
|
||||||
## Forking and Cloning from GitHub to GitHub
|
|
||||||
|
|
||||||
1. Fork <https://github.com/pi-hole/pi-hole/> to a repo under a namespace you control, or have permission to use, for example: `https://github.com/<your_namespace>/<your_repo_name>/`. You can do this from the github.com website.
|
|
||||||
2. Clone `https://github.com/<your_namespace>/<your_repo_name>/` with the tool of you choice.
|
|
||||||
3. To keep your fork in sync with our repo, add an upstream remote for pi-hole/pi-hole to your repo.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git remote add upstream https://github.com/pi-hole/pi-hole.git
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Checkout the `development` branch from your fork `https://github.com/<your_namespace>/<your_repo_name>/`.
|
|
||||||
5. Create a topic/branch, based on the `development` branch code. *Bonus fun to keep to the theme of Star Trek/black holes/gravity.*
|
|
||||||
6. Make your changes and commit to your topic branch in your repo.
|
|
||||||
7. Rebase your commits and squash any insignificant commits. See the notes below for an example.
|
|
||||||
8. Merge `development` your branch and fix any conflicts.
|
|
||||||
9. Open a Pull Request to merge your topic branch into our repo's `development` branch.
|
|
||||||
|
|
||||||
- Keep in mind the technical requirements from above.
|
|
||||||
|
|
||||||
## Forking and Cloning from GitHub to other code hosting sites
|
|
||||||
|
|
||||||
- Forking is a GitHub concept and cannot be done from GitHub to other git-based code hosting sites. However, those sites may be able to mirror a GitHub repo.
|
|
||||||
|
|
||||||
1. To contribute from another code hosting site, you must first complete the steps above to fork our repo to a GitHub namespace you have permission to use, for example: `https://github.com/<your_namespace>/<your_repo_name>/`.
|
|
||||||
2. Create a repo in your code hosting site, for example: `https://gitlab.com/<your_namespace>/<your_repo_name>/`
|
|
||||||
3. Follow the instructions from your code hosting site to create a mirror between `https://github.com/<your_namespace>/<your_repo_name>/` and `https://gitlab.com/<your_namespace>/<your_repo_name>/`.
|
|
||||||
4. When you are ready to create a Pull Request (PR), follow the steps `(starting at step #6)` from [Forking and Cloning from GitHub to GitHub](#forking-and-cloning-from-github-to-github) and create the PR from `https://github.com/<your_namespace>/<your_repo_name>/`.
|
|
||||||
|
|
||||||
## Notes for squashing commits with rebase
|
|
||||||
|
|
||||||
- To rebase your commits and squash previous commits, you can use:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rebase -i your_topic_branch~(number of commits to combine)
|
|
||||||
```
|
|
||||||
|
|
||||||
- For more details visit [gitready.com](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html)
|
|
||||||
|
|
||||||
1. The following would combine the last four commits in the branch `mytopic`.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rebase -i mytopic~4
|
|
||||||
```
|
|
||||||
|
|
||||||
2. An editor window opens with the most recent commits indicated: (edit the commands to the left of the commit ID)
|
|
||||||
|
|
||||||
```gitattributes
|
|
||||||
pick 9dff55b2 existing commit comments
|
|
||||||
squash ebb1a730 existing commit comments
|
|
||||||
squash 07cc5b50 existing commit comments
|
|
||||||
reword 9dff55b2 existing commit comments
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Save and close the editor. The next editor window opens: (edit the new commit message). *If you select reword for a commit, an additional editor window will open for you to edit the comment.*
|
|
||||||
|
|
||||||
```bash
|
|
||||||
new commit comments
|
|
||||||
Signed-off-by: yourname <your email address>
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Save and close the editor for the rebase process to execute. The terminal output should say something like the following:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
Successfully rebased and updated refs/heads/mytopic.
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Once you have a successful rebase, and before you sync your local clone, you have to force push origin to update your repo:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git push -f origin
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Continue on from step #7 from [Forking and Cloning from GitHub to GitHub](#forking-and-cloning-from-github-to-github)
|
|
||||||
|
@ -25,11 +25,12 @@ server=/localhost/
|
|||||||
server=/invalid/
|
server=/invalid/
|
||||||
|
|
||||||
# The same RFC requests something similar for
|
# The same RFC requests something similar for
|
||||||
# 16.172.in-addr.arpa. 22.172.in-addr.arpa. 27.172.in-addr.arpa.
|
# 10.in-addr.arpa. 21.172.in-addr.arpa. 27.172.in-addr.arpa.
|
||||||
# 17.172.in-addr.arpa. 30.172.in-addr.arpa. 28.172.in-addr.arpa.
|
# 16.172.in-addr.arpa. 22.172.in-addr.arpa. 28.172.in-addr.arpa.
|
||||||
# 18.172.in-addr.arpa. 23.172.in-addr.arpa. 29.172.in-addr.arpa.
|
# 17.172.in-addr.arpa. 23.172.in-addr.arpa. 29.172.in-addr.arpa.
|
||||||
# 19.172.in-addr.arpa. 24.172.in-addr.arpa. 31.172.in-addr.arpa.
|
# 18.172.in-addr.arpa. 24.172.in-addr.arpa. 30.172.in-addr.arpa.
|
||||||
# 20.172.in-addr.arpa. 25.172.in-addr.arpa. 168.192.in-addr.arpa.
|
# 19.172.in-addr.arpa. 25.172.in-addr.arpa. 31.172.in-addr.arpa.
|
||||||
|
# 20.172.in-addr.arpa. 26.172.in-addr.arpa. 168.192.in-addr.arpa.
|
||||||
# Pi-hole implements this via the dnsmasq option "bogus-priv" (see
|
# Pi-hole implements this via the dnsmasq option "bogus-priv" (see
|
||||||
# 01-pihole.conf) because this also covers IPv6.
|
# 01-pihole.conf) because this also covers IPv6.
|
||||||
|
|
||||||
|
@ -91,7 +91,8 @@ Options:
|
|||||||
-q, --quiet Make output less verbose
|
-q, --quiet Make output less verbose
|
||||||
-h, --help Show this help dialog
|
-h, --help Show this help dialog
|
||||||
-l, --list Display all your ${listname}listed domains
|
-l, --list Display all your ${listname}listed domains
|
||||||
--nuke Removes all entries in a list"
|
--nuke Removes all entries in a list
|
||||||
|
--comment \"text\" Add a comment to the domain. If adding multiple domains the same comment will be used for all"
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,7 @@ PIHOLE_LOCAL_HOSTS_FILE="${PIHOLE_DIRECTORY}/local.list"
|
|||||||
PIHOLE_LOGROTATE_FILE="${PIHOLE_DIRECTORY}/logrotate"
|
PIHOLE_LOGROTATE_FILE="${PIHOLE_DIRECTORY}/logrotate"
|
||||||
PIHOLE_SETUP_VARS_FILE="${PIHOLE_DIRECTORY}/setupVars.conf"
|
PIHOLE_SETUP_VARS_FILE="${PIHOLE_DIRECTORY}/setupVars.conf"
|
||||||
PIHOLE_FTL_CONF_FILE="${PIHOLE_DIRECTORY}/pihole-FTL.conf"
|
PIHOLE_FTL_CONF_FILE="${PIHOLE_DIRECTORY}/pihole-FTL.conf"
|
||||||
|
PIHOLE_CUSTOM_HOSTS_FILE="${PIHOLE_DIRECTORY}/custom.list"
|
||||||
|
|
||||||
# Read the value of an FTL config key. The value is printed to stdout.
|
# Read the value of an FTL config key. The value is printed to stdout.
|
||||||
#
|
#
|
||||||
@ -179,7 +180,8 @@ REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
|
|||||||
"${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}"
|
"${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}"
|
||||||
"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}"
|
"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}"
|
||||||
"${RESOLVCONF}"
|
"${RESOLVCONF}"
|
||||||
"${DNSMASQ_CONF}")
|
"${DNSMASQ_CONF}"
|
||||||
|
"${PIHOLE_CUSTOM_HOSTS_FILE}")
|
||||||
|
|
||||||
DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net.
|
DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net.
|
||||||
|
|
||||||
|
@ -35,13 +35,23 @@ source "/opt/pihole/COL_TABLE"
|
|||||||
|
|
||||||
GitCheckUpdateAvail() {
|
GitCheckUpdateAvail() {
|
||||||
local directory
|
local directory
|
||||||
|
local curBranch
|
||||||
directory="${1}"
|
directory="${1}"
|
||||||
curdir=$PWD
|
curdir=$PWD
|
||||||
cd "${directory}" || return
|
cd "${directory}" || return
|
||||||
|
|
||||||
# Fetch latest changes in this repo
|
# Fetch latest changes in this repo
|
||||||
git fetch --quiet origin
|
git fetch --tags --quiet origin
|
||||||
|
|
||||||
|
# Check current branch. If it is master, then check for the latest available tag instead of latest commit.
|
||||||
|
curBranch=$(git rev-parse --abbrev-ref HEAD)
|
||||||
|
if [[ "${curBranch}" == "master" ]]; then
|
||||||
|
# get the latest local tag
|
||||||
|
LOCAL=$(git describe --abbrev=0 --tags master)
|
||||||
|
# get the latest tag from remote
|
||||||
|
REMOTE=$(git describe --abbrev=0 --tags origin/master)
|
||||||
|
|
||||||
|
else
|
||||||
# @ alone is a shortcut for HEAD. Older versions of git
|
# @ alone is a shortcut for HEAD. Older versions of git
|
||||||
# need @{0}
|
# need @{0}
|
||||||
LOCAL="$(git rev-parse "@{0}")"
|
LOCAL="$(git rev-parse "@{0}")"
|
||||||
@ -54,6 +64,8 @@ GitCheckUpdateAvail() {
|
|||||||
# branch.<name>.merge). A missing branchname
|
# branch.<name>.merge). A missing branchname
|
||||||
# defaults to the current one.
|
# defaults to the current one.
|
||||||
REMOTE="$(git rev-parse "@{upstream}")"
|
REMOTE="$(git rev-parse "@{upstream}")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [[ "${#LOCAL}" == 0 ]]; then
|
if [[ "${#LOCAL}" == 0 ]]; then
|
||||||
echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support"
|
echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support"
|
||||||
|
@ -13,6 +13,10 @@ DEFAULT="-1"
|
|||||||
COREGITDIR="/etc/.pihole/"
|
COREGITDIR="/etc/.pihole/"
|
||||||
WEBGITDIR="/var/www/html/admin/"
|
WEBGITDIR="/var/www/html/admin/"
|
||||||
|
|
||||||
|
# Source the setupvars config file
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source /etc/pihole/setupVars.conf
|
||||||
|
|
||||||
getLocalVersion() {
|
getLocalVersion() {
|
||||||
# FTL requires a different method
|
# FTL requires a different method
|
||||||
if [[ "$1" == "FTL" ]]; then
|
if [[ "$1" == "FTL" ]]; then
|
||||||
@ -91,10 +95,11 @@ getRemoteVersion(){
|
|||||||
#If the above file exists, then we can read from that. Prevents overuse of GitHub API
|
#If the above file exists, then we can read from that. Prevents overuse of GitHub API
|
||||||
if [[ -f "$cachedVersions" ]]; then
|
if [[ -f "$cachedVersions" ]]; then
|
||||||
IFS=' ' read -r -a arrCache < "$cachedVersions"
|
IFS=' ' read -r -a arrCache < "$cachedVersions"
|
||||||
|
|
||||||
case $daemon in
|
case $daemon in
|
||||||
"pi-hole" ) echo "${arrCache[0]}";;
|
"pi-hole" ) echo "${arrCache[0]}";;
|
||||||
"AdminLTE" ) echo "${arrCache[1]}";;
|
"AdminLTE" ) [[ "${INSTALL_WEB_INTERFACE}" == true ]] && echo "${arrCache[1]}";;
|
||||||
"FTL" ) echo "${arrCache[2]}";;
|
"FTL" ) [[ "${INSTALL_WEB_INTERFACE}" == true ]] && echo "${arrCache[2]}" || echo "${arrCache[1]}";;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
@ -140,6 +145,11 @@ getLocalBranch(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
versionOutput() {
|
versionOutput() {
|
||||||
|
if [[ "$1" == "AdminLTE" && "${INSTALL_WEB_INTERFACE}" != true ]]; then
|
||||||
|
echo " WebAdmin not installed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
[[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
|
[[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
|
||||||
[[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
|
[[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
|
||||||
[[ "$1" == "FTL" ]] && GITDIR="FTL"
|
[[ "$1" == "FTL" ]] && GITDIR="FTL"
|
||||||
@ -166,6 +176,7 @@ versionOutput() {
|
|||||||
output="Latest ${1^} hash is $latHash"
|
output="Latest ${1^} hash is $latHash"
|
||||||
else
|
else
|
||||||
errorOutput
|
errorOutput
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ -n "$output" ]] && echo " $output"
|
[[ -n "$output" ]] && echo " $output"
|
||||||
@ -177,10 +188,6 @@ errorOutput() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultOutput() {
|
defaultOutput() {
|
||||||
# Source the setupvars config file
|
|
||||||
# shellcheck disable=SC1091
|
|
||||||
source /etc/pihole/setupVars.conf
|
|
||||||
|
|
||||||
versionOutput "pi-hole" "$@"
|
versionOutput "pi-hole" "$@"
|
||||||
|
|
||||||
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
|
@ -199,6 +199,8 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
|
|||||||
# Setup interface listening behavior of dnsmasq
|
# Setup interface listening behavior of dnsmasq
|
||||||
delete_dnsmasq_setting "interface"
|
delete_dnsmasq_setting "interface"
|
||||||
delete_dnsmasq_setting "local-service"
|
delete_dnsmasq_setting "local-service"
|
||||||
|
delete_dnsmasq_setting "except-interface"
|
||||||
|
delete_dnsmasq_setting "bind-interfaces"
|
||||||
|
|
||||||
if [[ "${DNSMASQ_LISTENING}" == "all" ]]; then
|
if [[ "${DNSMASQ_LISTENING}" == "all" ]]; then
|
||||||
# Listen on all interfaces, permit all origins
|
# Listen on all interfaces, permit all origins
|
||||||
@ -207,6 +209,7 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
|
|||||||
# Listen only on all interfaces, but only local subnets
|
# Listen only on all interfaces, but only local subnets
|
||||||
add_dnsmasq_setting "local-service"
|
add_dnsmasq_setting "local-service"
|
||||||
else
|
else
|
||||||
|
# Options "bind" and "single"
|
||||||
# Listen only on one interface
|
# Listen only on one interface
|
||||||
# Use eth0 as fallback interface if interface is missing in setupVars.conf
|
# Use eth0 as fallback interface if interface is missing in setupVars.conf
|
||||||
if [ -z "${PIHOLE_INTERFACE}" ]; then
|
if [ -z "${PIHOLE_INTERFACE}" ]; then
|
||||||
@ -214,6 +217,11 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
|
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
|
||||||
|
|
||||||
|
if [[ "${DNSMASQ_LISTENING}" == "bind" ]]; then
|
||||||
|
# Really bind to interface
|
||||||
|
add_dnsmasq_setting "bind-interfaces"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
|
if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
|
||||||
@ -532,25 +540,6 @@ CustomizeAdLists() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
SetPrivacyMode() {
|
|
||||||
if [[ "${args[2]}" == "true" ]]; then
|
|
||||||
change_setting "API_PRIVACY_MODE" "true"
|
|
||||||
else
|
|
||||||
change_setting "API_PRIVACY_MODE" "false"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
ResolutionSettings() {
|
|
||||||
typ="${args[2]}"
|
|
||||||
state="${args[3]}"
|
|
||||||
|
|
||||||
if [[ "${typ}" == "forward" ]]; then
|
|
||||||
change_setting "API_GET_UPSTREAM_DNS_HOSTNAME" "${state}"
|
|
||||||
elif [[ "${typ}" == "clients" ]]; then
|
|
||||||
change_setting "API_GET_CLIENT_HOSTNAME" "${state}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
AddDHCPStaticAddress() {
|
AddDHCPStaticAddress() {
|
||||||
mac="${args[2]}"
|
mac="${args[2]}"
|
||||||
ip="${args[3]}"
|
ip="${args[3]}"
|
||||||
@ -619,9 +608,10 @@ Example: 'pihole -a -i local'
|
|||||||
Specify dnsmasq's network interface listening behavior
|
Specify dnsmasq's network interface listening behavior
|
||||||
|
|
||||||
Interfaces:
|
Interfaces:
|
||||||
local Listen on all interfaces, but only allow queries from
|
local Only respond to queries from devices that
|
||||||
devices that are at most one hop away (local devices)
|
are at most one hop away (local devices)
|
||||||
single Listen only on ${PIHOLE_INTERFACE} interface
|
single Respond only on interface ${PIHOLE_INTERFACE}
|
||||||
|
bind Bind only on interface ${PIHOLE_INTERFACE}
|
||||||
all Listen on all interfaces, permit all origins"
|
all Listen on all interfaces, permit all origins"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@ -632,6 +622,9 @@ Interfaces:
|
|||||||
elif [[ "${args[2]}" == "local" ]]; then
|
elif [[ "${args[2]}" == "local" ]]; then
|
||||||
echo -e " ${INFO} Listening on all interfaces, permitting origins from one hop away (LAN)"
|
echo -e " ${INFO} Listening on all interfaces, permitting origins from one hop away (LAN)"
|
||||||
change_setting "DNSMASQ_LISTENING" "local"
|
change_setting "DNSMASQ_LISTENING" "local"
|
||||||
|
elif [[ "${args[2]}" == "bind" ]]; then
|
||||||
|
echo -e " ${INFO} Binding on interface ${PIHOLE_INTERFACE}"
|
||||||
|
change_setting "DNSMASQ_LISTENING" "bind"
|
||||||
else
|
else
|
||||||
echo -e " ${INFO} Listening only on interface ${PIHOLE_INTERFACE}"
|
echo -e " ${INFO} Listening only on interface ${PIHOLE_INTERFACE}"
|
||||||
change_setting "DNSMASQ_LISTENING" "single"
|
change_setting "DNSMASQ_LISTENING" "single"
|
||||||
@ -829,8 +822,6 @@ main() {
|
|||||||
"layout" ) SetWebUILayout;;
|
"layout" ) SetWebUILayout;;
|
||||||
"theme" ) SetWebUITheme;;
|
"theme" ) SetWebUITheme;;
|
||||||
"-h" | "--help" ) helpFunc;;
|
"-h" | "--help" ) helpFunc;;
|
||||||
"privacymode" ) SetPrivacyMode;;
|
|
||||||
"resolve" ) ResolutionSettings;;
|
|
||||||
"addstaticdhcp" ) AddDHCPStaticAddress;;
|
"addstaticdhcp" ) AddDHCPStaticAddress;;
|
||||||
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
|
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
|
||||||
"-e" | "email" ) SetAdminEmail "$3";;
|
"-e" | "email" ) SetAdminEmail "$3";;
|
||||||
|
@ -85,8 +85,8 @@ $HTTP["url"] =~ "^/admin/\.(.*)" {
|
|||||||
url.access-deny = ("")
|
url.access-deny = ("")
|
||||||
}
|
}
|
||||||
|
|
||||||
# allow teleporter iframe on settings page
|
# allow teleporter and API qr code iframe on settings page
|
||||||
$HTTP["url"] =~ "/teleporter\.php$" {
|
$HTTP["url"] =~ "/(teleporter|api_token)\.php$" {
|
||||||
$HTTP["referer"] =~ "/admin/settings\.php" {
|
$HTTP["referer"] =~ "/admin/settings\.php" {
|
||||||
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
||||||
}
|
}
|
||||||
|
@ -93,8 +93,8 @@ $HTTP["url"] =~ "^/admin/\.(.*)" {
|
|||||||
url.access-deny = ("")
|
url.access-deny = ("")
|
||||||
}
|
}
|
||||||
|
|
||||||
# allow teleporter iframe on settings page
|
# allow teleporter and API qr code iframe on settings page
|
||||||
$HTTP["url"] =~ "/teleporter\.php$" {
|
$HTTP["url"] =~ "/(teleporter|api_token)\.php$" {
|
||||||
$HTTP["referer"] =~ "/admin/settings\.php" {
|
$HTTP["referer"] =~ "/admin/settings\.php" {
|
||||||
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
|
|
||||||
# Pi-hole: A black hole for Internet advertisements
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
# (c) 2017-2018 Pi-hole, LLC (https://pi-hole.net)
|
# (c) 2017-2021 Pi-hole, LLC (https://pi-hole.net)
|
||||||
# Network-wide ad blocking via your own hardware.
|
# Network-wide ad blocking via your own hardware.
|
||||||
#
|
#
|
||||||
# Installs and Updates Pi-hole
|
# Installs and Updates Pi-hole
|
||||||
@ -172,7 +172,7 @@ os_check() {
|
|||||||
local remote_os_domain valid_os valid_version valid_response detected_os detected_version display_warning cmdResult digReturnCode response
|
local remote_os_domain valid_os valid_version valid_response detected_os detected_version display_warning cmdResult digReturnCode response
|
||||||
remote_os_domain=${OS_CHECK_DOMAIN_NAME:-"versions.pi-hole.net"}
|
remote_os_domain=${OS_CHECK_DOMAIN_NAME:-"versions.pi-hole.net"}
|
||||||
|
|
||||||
detected_os=$(grep "\bID\b" /etc/os-release | cut -d '=' -f2 | tr -d '"')
|
detected_os=$(grep '^ID=' /etc/os-release | cut -d '=' -f2 | tr -d '"')
|
||||||
detected_version=$(grep VERSION_ID /etc/os-release | cut -d '=' -f2 | tr -d '"')
|
detected_version=$(grep VERSION_ID /etc/os-release | cut -d '=' -f2 | tr -d '"')
|
||||||
|
|
||||||
cmdResult="$(dig +short -t txt "${remote_os_domain}" @ns1.pi-hole.net 2>&1; echo $?)"
|
cmdResult="$(dig +short -t txt "${remote_os_domain}" @ns1.pi-hole.net 2>&1; echo $?)"
|
||||||
@ -674,7 +674,7 @@ chooseInterface() {
|
|||||||
# Feed the available interfaces into this while loop
|
# Feed the available interfaces into this while loop
|
||||||
done <<< "${availableInterfaces}"
|
done <<< "${availableInterfaces}"
|
||||||
# The whiptail command that will be run, stored in a variable
|
# The whiptail command that will be run, stored in a variable
|
||||||
chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to toggle selection)" "${r}" "${c}" "${interfaceCount}")
|
chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to toggle selection)" "${r}" "${c}" 6)
|
||||||
# Now run the command using the interfaces saved into the array
|
# Now run the command using the interfaces saved into the array
|
||||||
chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) || \
|
chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) || \
|
||||||
# If the user chooses Cancel, exit
|
# If the user chooses Cancel, exit
|
||||||
@ -761,7 +761,6 @@ collect_v4andv6_information() {
|
|||||||
if [[ -f "/etc/dhcpcd.conf" ]]; then
|
if [[ -f "/etc/dhcpcd.conf" ]]; then
|
||||||
# configure networking via dhcpcd
|
# configure networking via dhcpcd
|
||||||
getStaticIPv4Settings
|
getStaticIPv4Settings
|
||||||
setDHCPCD
|
|
||||||
fi
|
fi
|
||||||
find_IPv6_information
|
find_IPv6_information
|
||||||
printf " %b IPv6 address: %s\\n" "${INFO}" "${IPV6_ADDRESS}"
|
printf " %b IPv6 address: %s\\n" "${INFO}" "${IPV6_ADDRESS}"
|
||||||
@ -770,17 +769,28 @@ collect_v4andv6_information() {
|
|||||||
getStaticIPv4Settings() {
|
getStaticIPv4Settings() {
|
||||||
# Local, named variables
|
# Local, named variables
|
||||||
local ipSettingsCorrect
|
local ipSettingsCorrect
|
||||||
|
local DHCPChoice
|
||||||
# Ask if the user wants to use DHCP settings as their static IP
|
# Ask if the user wants to use DHCP settings as their static IP
|
||||||
# This is useful for users that are using DHCP reservations; then we can just use the information gathered via our functions
|
# This is useful for users that are using DHCP reservations; then we can just use the information gathered via our functions
|
||||||
if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Do you want to use your current network settings as a static address?
|
DHCPChoice=$(whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --menu --separate-output "Do you want to use your current network settings as a static address? \\n
|
||||||
IP address: ${IPV4_ADDRESS}
|
IP address: ${IPV4_ADDRESS} \\n
|
||||||
Gateway: ${IPv4gw}" "${r}" "${c}"; then
|
Gateway: ${IPv4gw} \\n" "${r}" "${c}" 3\
|
||||||
|
"Yes" "Set static IP using current values" \
|
||||||
|
"No" "Set static IP using custom values" \
|
||||||
|
"Skip" "I will set a static IP later, or have already done so" 3>&2 2>&1 1>&3) || \
|
||||||
|
{ printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
|
||||||
|
|
||||||
|
case ${DHCPChoice} in
|
||||||
|
"Yes")
|
||||||
# If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
|
# If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
|
||||||
whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that.
|
whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that.
|
||||||
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
|
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
|
||||||
It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." "${r}" "${c}"
|
It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." "${r}" "${c}"
|
||||||
# Nothing else to do since the variables are already set above
|
# Nothing else to do since the variables are already set above
|
||||||
else
|
setDHCPCD
|
||||||
|
;;
|
||||||
|
|
||||||
|
"No")
|
||||||
# Otherwise, we need to ask the user to input their desired settings.
|
# Otherwise, we need to ask the user to input their desired settings.
|
||||||
# Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
|
# Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
|
||||||
# Start a loop to let the user enter their information with the chance to go back and edit it if necessary
|
# Start a loop to let the user enter their information with the chance to go back and edit it if necessary
|
||||||
@ -809,8 +819,9 @@ It is also possible to use a DHCP reservation, but if you are going to do that,
|
|||||||
ipSettingsCorrect=False
|
ipSettingsCorrect=False
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
# End the if statement for DHCP vs. static
|
setDHCPCD
|
||||||
fi
|
;;
|
||||||
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
# Configure networking via dhcpcd
|
# Configure networking via dhcpcd
|
||||||
@ -845,7 +856,7 @@ valid_ip() {
|
|||||||
# Regex matching an optional port (starting with '#') range of 1-65536
|
# Regex matching an optional port (starting with '#') range of 1-65536
|
||||||
local portelem="(#(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))?";
|
local portelem="(#(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))?";
|
||||||
# Build a full IPv4 regex from the above subexpressions
|
# Build a full IPv4 regex from the above subexpressions
|
||||||
local regex="^${ipv4elem}\.${ipv4elem}\.${ipv4elem}\.${ipv4elem}${portelem}$"
|
local regex="^${ipv4elem}\\.${ipv4elem}\\.${ipv4elem}\\.${ipv4elem}${portelem}$"
|
||||||
|
|
||||||
# Evaluate the regex, and return the result
|
# Evaluate the regex, and return the result
|
||||||
[[ $ip =~ ${regex} ]]
|
[[ $ip =~ ${regex} ]]
|
||||||
@ -1481,8 +1492,14 @@ update_package_cache() {
|
|||||||
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
|
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
|
||||||
else
|
else
|
||||||
# Otherwise, show an error and exit
|
# Otherwise, show an error and exit
|
||||||
|
|
||||||
|
# In case we used apt-get and apt is also available, we use this as recommendation as we have seen it
|
||||||
|
# gives more user-friendly (interactive) advice
|
||||||
|
if [[ ${PKG_MANAGER} == "apt-get" ]] && is_command apt ; then
|
||||||
|
UPDATE_PKG_CACHE="apt update"
|
||||||
|
fi
|
||||||
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
|
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
|
||||||
printf " %bError: Unable to update package cache. Please try \"%s\"%b" "${COL_LIGHT_RED}" "sudo ${UPDATE_PKG_CACHE}" "${COL_NC}"
|
printf " %bError: Unable to update package cache. Please try \"%s\"%b\\n" "${COL_LIGHT_RED}" "sudo ${UPDATE_PKG_CACHE}" "${COL_NC}"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -1845,7 +1862,7 @@ checkSelinux() {
|
|||||||
local CURRENT_SELINUX
|
local CURRENT_SELINUX
|
||||||
local SELINUX_ENFORCING=0
|
local SELINUX_ENFORCING=0
|
||||||
# Check for SELinux configuration file and getenforce command
|
# Check for SELinux configuration file and getenforce command
|
||||||
if [[ -f /etc/selinux/config ]] && command -v getenforce &> /dev/null; then
|
if [[ -f /etc/selinux/config ]] && is_command getenforce; then
|
||||||
# Check the default SELinux mode
|
# Check the default SELinux mode
|
||||||
DEFAULT_SELINUX=$(awk -F= '/^SELINUX=/ {print $2}' /etc/selinux/config)
|
DEFAULT_SELINUX=$(awk -F= '/^SELINUX=/ {print $2}' /etc/selinux/config)
|
||||||
case "${DEFAULT_SELINUX,,}" in
|
case "${DEFAULT_SELINUX,,}" in
|
||||||
@ -2077,7 +2094,6 @@ clone_or_update_repos() {
|
|||||||
# shellcheck disable=SC2120
|
# shellcheck disable=SC2120
|
||||||
FTLinstall() {
|
FTLinstall() {
|
||||||
# Local, named variables
|
# Local, named variables
|
||||||
local latesttag
|
|
||||||
local str="Downloading and Installing FTL"
|
local str="Downloading and Installing FTL"
|
||||||
printf " %b %s..." "${INFO}" "${str}"
|
printf " %b %s..." "${INFO}" "${str}"
|
||||||
|
|
||||||
@ -2148,7 +2164,7 @@ FTLinstall() {
|
|||||||
|
|
||||||
disable_dnsmasq() {
|
disable_dnsmasq() {
|
||||||
# dnsmasq can now be stopped and disabled if it exists
|
# dnsmasq can now be stopped and disabled if it exists
|
||||||
if which dnsmasq &> /dev/null; then
|
if is_command dnsmasq; then
|
||||||
if check_service_active "dnsmasq";then
|
if check_service_active "dnsmasq";then
|
||||||
printf " %b FTL can now resolve DNS Queries without dnsmasq running separately\\n" "${INFO}"
|
printf " %b FTL can now resolve DNS Queries without dnsmasq running separately\\n" "${INFO}"
|
||||||
stop_service dnsmasq
|
stop_service dnsmasq
|
||||||
@ -2278,7 +2294,7 @@ FTLcheckUpdate() {
|
|||||||
local localSha1
|
local localSha1
|
||||||
|
|
||||||
# if dnsmasq exists and is running at this point, force reinstall of FTL Binary
|
# if dnsmasq exists and is running at this point, force reinstall of FTL Binary
|
||||||
if which dnsmasq &> /dev/null; then
|
if is_command dnsmasq; then
|
||||||
if check_service_active "dnsmasq";then
|
if check_service_active "dnsmasq";then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@ -2469,12 +2485,12 @@ main() {
|
|||||||
get_available_interfaces
|
get_available_interfaces
|
||||||
# Find interfaces and let the user choose one
|
# Find interfaces and let the user choose one
|
||||||
chooseInterface
|
chooseInterface
|
||||||
|
# find IPv4 and IPv6 information of the device
|
||||||
|
collect_v4andv6_information
|
||||||
# Decide what upstream DNS Servers to use
|
# Decide what upstream DNS Servers to use
|
||||||
setDNS
|
setDNS
|
||||||
# Give the user a choice of blocklists to include in their install. Or not.
|
# Give the user a choice of blocklists to include in their install. Or not.
|
||||||
chooseBlocklists
|
chooseBlocklists
|
||||||
# find IPv4 and IPv6 information of the device
|
|
||||||
collect_v4andv6_information
|
|
||||||
# Let the user decide if they want the web interface to be installed automatically
|
# Let the user decide if they want the web interface to be installed automatically
|
||||||
setAdminFlag
|
setAdminFlag
|
||||||
# Let the user decide if they want query logging enabled...
|
# Let the user decide if they want query logging enabled...
|
||||||
|
139
gravity.sh
139
gravity.sh
@ -75,7 +75,12 @@ fi
|
|||||||
|
|
||||||
# Generate new sqlite3 file from schema template
|
# Generate new sqlite3 file from schema template
|
||||||
generate_gravity_database() {
|
generate_gravity_database() {
|
||||||
sqlite3 "${1}" < "${gravityDBschema}"
|
if ! sqlite3 "${gravityDBfile}" < "${gravityDBschema}"; then
|
||||||
|
echo -e " ${CROSS} Unable to create ${gravityDBfile}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
chown pihole:pihole "${gravityDBfile}"
|
||||||
|
chmod g+w "${piholeDir}" "${gravityDBfile}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Copy data from old to new database file and swap them
|
# Copy data from old to new database file and swap them
|
||||||
@ -248,7 +253,7 @@ database_adlist_number() {
|
|||||||
return;
|
return;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
output=$( { printf ".timeout 30000\\nUPDATE adlist SET number = %i, invalid_domains = %i WHERE id = %i;\\n" "${num_lines}" "${num_invalid}" "${1}" | sqlite3 "${gravityDBfile}"; } 2>&1 )
|
output=$( { printf ".timeout 30000\\nUPDATE adlist SET number = %i, invalid_domains = %i WHERE id = %i;\\n" "${num_source_lines}" "${num_invalid}" "${1}" | sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||||
status="$?"
|
status="$?"
|
||||||
|
|
||||||
if [[ "${status}" -ne 0 ]]; then
|
if [[ "${status}" -ne 0 ]]; then
|
||||||
@ -279,7 +284,10 @@ migrate_to_database() {
|
|||||||
if [ ! -e "${gravityDBfile}" ]; then
|
if [ ! -e "${gravityDBfile}" ]; then
|
||||||
# Create new database file - note that this will be created in version 1
|
# Create new database file - note that this will be created in version 1
|
||||||
echo -e " ${INFO} Creating new gravity database"
|
echo -e " ${INFO} Creating new gravity database"
|
||||||
generate_gravity_database "${gravityDBfile}"
|
if ! generate_gravity_database; then
|
||||||
|
echo -e " ${CROSS} Error creating new gravity database. Please contact support."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Check if gravity database needs to be updated
|
# Check if gravity database needs to be updated
|
||||||
upgrade_gravityDB "${gravityDBfile}" "${piholeDir}"
|
upgrade_gravityDB "${gravityDBfile}" "${piholeDir}"
|
||||||
@ -503,8 +511,9 @@ gravity_DownloadBlocklists() {
|
|||||||
gravity_Blackbody=true
|
gravity_Blackbody=true
|
||||||
}
|
}
|
||||||
|
|
||||||
total_num=0
|
# num_target_lines does increase for every correctly added domain in pareseList()
|
||||||
num_lines=0
|
num_target_lines=0
|
||||||
|
num_source_lines=0
|
||||||
num_invalid=0
|
num_invalid=0
|
||||||
parseList() {
|
parseList() {
|
||||||
local adlistID="${1}" src="${2}" target="${3}" incorrect_lines
|
local adlistID="${1}" src="${2}" target="${3}" incorrect_lines
|
||||||
@ -516,18 +525,20 @@ parseList() {
|
|||||||
# Find (up to) five domains containing invalid characters (see above)
|
# Find (up to) five domains containing invalid characters (see above)
|
||||||
incorrect_lines="$(sed -e "/[^a-zA-Z0-9.\_-]/!d" "${src}" | head -n 5)"
|
incorrect_lines="$(sed -e "/[^a-zA-Z0-9.\_-]/!d" "${src}" | head -n 5)"
|
||||||
|
|
||||||
local num_target_lines num_correct_lines num_invalid
|
local num_target_lines_new num_correct_lines
|
||||||
# Get number of lines in source file
|
# Get number of lines in source file
|
||||||
num_lines="$(grep -c "^" "${src}")"
|
num_source_lines="$(grep -c "^" "${src}")"
|
||||||
# Get number of lines in destination file
|
# Get the new number of lines in destination file
|
||||||
num_target_lines="$(grep -c "^" "${target}")"
|
num_target_lines_new="$(grep -c "^" "${target}")"
|
||||||
num_correct_lines="$(( num_target_lines-total_num ))"
|
# Number of new correctly added lines
|
||||||
total_num="$num_target_lines"
|
num_correct_lines="$(( num_target_lines_new-num_target_lines ))"
|
||||||
num_invalid="$(( num_lines-num_correct_lines ))"
|
# Upate number of lines in target file
|
||||||
|
num_target_lines="$num_target_lines_new"
|
||||||
|
num_invalid="$(( num_source_lines-num_correct_lines ))"
|
||||||
if [[ "${num_invalid}" -eq 0 ]]; then
|
if [[ "${num_invalid}" -eq 0 ]]; then
|
||||||
echo " ${INFO} Analyzed ${num_lines} domains"
|
echo " ${INFO} Analyzed ${num_source_lines} domains"
|
||||||
else
|
else
|
||||||
echo " ${INFO} Analyzed ${num_lines} domains, ${num_invalid} domains invalid!"
|
echo " ${INFO} Analyzed ${num_source_lines} domains, ${num_invalid} domains invalid!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Display sample of invalid lines if we found some
|
# Display sample of invalid lines if we found some
|
||||||
@ -593,6 +604,10 @@ gravity_DownloadBlocklistFromUrl() {
|
|||||||
if [[ $(dig "${domain}" | grep "NXDOMAIN" -c) -ge 1 ]]; then
|
if [[ $(dig "${domain}" | grep "NXDOMAIN" -c) -ge 1 ]]; then
|
||||||
blocked=true
|
blocked=true
|
||||||
fi;;
|
fi;;
|
||||||
|
"NODATA")
|
||||||
|
if [[ $(dig "${domain}" | grep "NOERROR" -c) -ge 1 ]] && [[ -z $(dig +short "${domain}") ]]; then
|
||||||
|
blocked=true
|
||||||
|
fi;;
|
||||||
"NULL"|*)
|
"NULL"|*)
|
||||||
if [[ $(dig "${domain}" +short | grep "0.0.0.0" -c) -ge 1 ]]; then
|
if [[ $(dig "${domain}" +short | grep "0.0.0.0" -c) -ge 1 ]]; then
|
||||||
blocked=true
|
blocked=true
|
||||||
@ -686,7 +701,7 @@ gravity_DownloadBlocklistFromUrl() {
|
|||||||
else
|
else
|
||||||
echo -e " ${CROSS} List download failed: ${COL_LIGHT_RED}no cached list available${COL_NC}"
|
echo -e " ${CROSS} List download failed: ${COL_LIGHT_RED}no cached list available${COL_NC}"
|
||||||
# Manually reset these two numbers because we do not call parseList here
|
# Manually reset these two numbers because we do not call parseList here
|
||||||
num_lines=0
|
num_source_lines=0
|
||||||
num_invalid=0
|
num_invalid=0
|
||||||
database_adlist_number "${adlistID}"
|
database_adlist_number "${adlistID}"
|
||||||
database_adlist_status "${adlistID}" "4"
|
database_adlist_status "${adlistID}" "4"
|
||||||
@ -845,6 +860,49 @@ gravity_Cleanup() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
database_recovery() {
|
||||||
|
local result
|
||||||
|
local str="Checking integrity of existing gravity database"
|
||||||
|
local option="${1}"
|
||||||
|
echo -ne " ${INFO} ${str}..."
|
||||||
|
if result="$(pihole-FTL sqlite3 "${gravityDBfile}" "PRAGMA integrity_check" 2>&1)"; then
|
||||||
|
echo -e "${OVER} ${TICK} ${str} - no errors found"
|
||||||
|
|
||||||
|
str="Checking foreign keys of existing gravity database"
|
||||||
|
echo -ne " ${INFO} ${str}..."
|
||||||
|
if result="$(pihole-FTL sqlite3 "${gravityDBfile}" "PRAGMA foreign_key_check" 2>&1)"; then
|
||||||
|
echo -e "${OVER} ${TICK} ${str} - no errors found"
|
||||||
|
if [[ "${option}" != "force" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${OVER} ${CROSS} ${str} - errors found:"
|
||||||
|
while IFS= read -r line ; do echo " - $line"; done <<< "$result"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${OVER} ${CROSS} ${str} - errors found:"
|
||||||
|
while IFS= read -r line ; do echo " - $line"; done <<< "$result"
|
||||||
|
fi
|
||||||
|
|
||||||
|
str="Trying to recover existing gravity database"
|
||||||
|
echo -ne " ${INFO} ${str}..."
|
||||||
|
# We have to remove any possibly existing recovery database or this will fail
|
||||||
|
rm -f "${gravityDBfile}.recovered" > /dev/null 2>&1
|
||||||
|
if result="$(pihole-FTL sqlite3 "${gravityDBfile}" ".recover" | pihole-FTL sqlite3 "${gravityDBfile}.recovered" 2>&1)"; then
|
||||||
|
echo -e "${OVER} ${TICK} ${str} - success"
|
||||||
|
mv "${gravityDBfile}" "${gravityDBfile}.old"
|
||||||
|
mv "${gravityDBfile}.recovered" "${gravityDBfile}"
|
||||||
|
echo -ne " ${INFO} ${gravityDBfile} has been recovered"
|
||||||
|
echo -ne " ${INFO} The old ${gravityDBfile} has been moved to ${gravityDBfile}.old"
|
||||||
|
else
|
||||||
|
echo -e "${OVER} ${CROSS} ${str} - the following errors happened:"
|
||||||
|
while IFS= read -r line ; do echo " - $line"; done <<< "$result"
|
||||||
|
echo -e " ${CROSS} Recovery failed. Try \"pihole -r recreate\" instead."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
helpFunc() {
|
helpFunc() {
|
||||||
echo "Usage: pihole -g
|
echo "Usage: pihole -g
|
||||||
Update domains from blocklists specified in adlists.list
|
Update domains from blocklists specified in adlists.list
|
||||||
@ -855,10 +913,37 @@ Options:
|
|||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repairSelector() {
|
||||||
|
case "$1" in
|
||||||
|
"recover") recover_database=true;;
|
||||||
|
"recreate") recreate_database=true;;
|
||||||
|
*) echo "Usage: pihole -g -r {recover,recreate}
|
||||||
|
Attempt to repair gravity database
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
pihole -g -r recover Try to recover a damaged gravity database file.
|
||||||
|
Pi-hole tries to restore as much as possible
|
||||||
|
from a corrupted gravity database.
|
||||||
|
|
||||||
|
pihole -g -r recover force Pi-hole will run the recovery process even when
|
||||||
|
no damage is detected. This option is meant to be
|
||||||
|
a last resort. Recovery is a fragile task
|
||||||
|
consuming a lot of resources and shouldn't be
|
||||||
|
performed unnecessarily.
|
||||||
|
|
||||||
|
pihole -g -r recreate Create a new gravity database file from scratch.
|
||||||
|
This will remove your existing gravity database
|
||||||
|
and create a new file from scratch. If you still
|
||||||
|
have the migration backup created when migrating
|
||||||
|
to Pi-hole v5.0, Pi-hole will import these files."
|
||||||
|
exit 0;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
for var in "$@"; do
|
for var in "$@"; do
|
||||||
case "${var}" in
|
case "${var}" in
|
||||||
"-f" | "--force" ) forceDelete=true;;
|
"-f" | "--force" ) forceDelete=true;;
|
||||||
"-r" | "--recreate" ) recreate_database=true;;
|
"-r" | "--repair" ) repairSelector "$3";;
|
||||||
"-h" | "--help" ) helpFunc;;
|
"-h" | "--help" ) helpFunc;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@ -872,7 +957,7 @@ fi
|
|||||||
gravity_Trap
|
gravity_Trap
|
||||||
|
|
||||||
if [[ "${recreate_database:-}" == true ]]; then
|
if [[ "${recreate_database:-}" == true ]]; then
|
||||||
str="Restoring from migration backup"
|
str="Recreating gravity database from migration backup"
|
||||||
echo -ne "${INFO} ${str}..."
|
echo -ne "${INFO} ${str}..."
|
||||||
rm "${gravityDBfile}"
|
rm "${gravityDBfile}"
|
||||||
pushd "${piholeDir}" > /dev/null || exit
|
pushd "${piholeDir}" > /dev/null || exit
|
||||||
@ -881,8 +966,15 @@ if [[ "${recreate_database:-}" == true ]]; then
|
|||||||
echo -e "${OVER} ${TICK} ${str}"
|
echo -e "${OVER} ${TICK} ${str}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "${recover_database:-}" == true ]]; then
|
||||||
|
database_recovery "$4"
|
||||||
|
fi
|
||||||
|
|
||||||
# Move possibly existing legacy files to the gravity database
|
# Move possibly existing legacy files to the gravity database
|
||||||
migrate_to_database
|
if ! migrate_to_database; then
|
||||||
|
echo -e " ${CROSS} Unable to migrate to database. Please contact support."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "${forceDelete:-}" == true ]]; then
|
if [[ "${forceDelete:-}" == true ]]; then
|
||||||
str="Deleting existing list cache"
|
str="Deleting existing list cache"
|
||||||
@ -893,14 +985,21 @@ if [[ "${forceDelete:-}" == true ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Gravity downloads blocklists next
|
# Gravity downloads blocklists next
|
||||||
gravity_CheckDNSResolutionAvailable
|
if ! gravity_CheckDNSResolutionAvailable; then
|
||||||
|
echo -e " ${CROSS} Can not complete gravity update, no DNS is available. Please contact support."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
gravity_DownloadBlocklists
|
gravity_DownloadBlocklists
|
||||||
|
|
||||||
# Create local.list
|
# Create local.list
|
||||||
gravity_generateLocalList
|
gravity_generateLocalList
|
||||||
|
|
||||||
# Migrate rest of the data from old to new database
|
# Migrate rest of the data from old to new database
|
||||||
gravity_swap_databases
|
if ! gravity_swap_databases; then
|
||||||
|
echo -e " ${CROSS} Unable to create database. Please contact support."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Update gravity timestamp
|
# Update gravity timestamp
|
||||||
update_gravity_timestamp
|
update_gravity_timestamp
|
||||||
|
6
pihole
6
pihole
@ -71,8 +71,7 @@ reconfigurePiholeFunc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateGravityFunc() {
|
updateGravityFunc() {
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/gravity.sh "$@"
|
exec "${PI_HOLE_SCRIPT_DIR}"/gravity.sh "$@"
|
||||||
exit $?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queryFunc() {
|
queryFunc() {
|
||||||
@ -95,8 +94,7 @@ uninstallFunc() {
|
|||||||
|
|
||||||
versionFunc() {
|
versionFunc() {
|
||||||
shift
|
shift
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/version.sh "$@"
|
exec "${PI_HOLE_SCRIPT_DIR}"/version.sh "$@"
|
||||||
exit 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get PID of main pihole-FTL process
|
# Get PID of main pihole-FTL process
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
FROM centos:7
|
FROM centos:7
|
||||||
|
RUN yum install -y git
|
||||||
|
|
||||||
ENV GITDIR /etc/.pihole
|
ENV GITDIR /etc/.pihole
|
||||||
ENV SCRIPTDIR /opt/pihole
|
ENV SCRIPTDIR /opt/pihole
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
FROM centos:8
|
FROM centos:8
|
||||||
|
RUN yum install -y git
|
||||||
|
|
||||||
ENV GITDIR /etc/.pihole
|
ENV GITDIR /etc/.pihole
|
||||||
ENV SCRIPTDIR /opt/pihole
|
ENV SCRIPTDIR /opt/pihole
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
FROM fedora:33
|
FROM fedora:33
|
||||||
|
RUN dnf install -y git
|
||||||
|
|
||||||
ENV GITDIR /etc/.pihole
|
ENV GITDIR /etc/.pihole
|
||||||
ENV SCRIPTDIR /opt/pihole
|
ENV SCRIPTDIR /opt/pihole
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
FROM fedora:34
|
FROM fedora:34
|
||||||
|
RUN dnf install -y git
|
||||||
|
|
||||||
ENV GITDIR /etc/.pihole
|
ENV GITDIR /etc/.pihole
|
||||||
ENV SCRIPTDIR /opt/pihole
|
ENV SCRIPTDIR /opt/pihole
|
||||||
|
150
test/conftest.py
150
test/conftest.py
@ -1,10 +1,9 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import testinfra
|
import testinfra
|
||||||
|
import testinfra.backend.docker
|
||||||
|
import subprocess
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
check_output = testinfra.get_backend(
|
|
||||||
"local://"
|
|
||||||
).get_module("Command").check_output
|
|
||||||
|
|
||||||
SETUPVARS = {
|
SETUPVARS = {
|
||||||
'PIHOLE_INTERFACE': 'eth99',
|
'PIHOLE_INTERFACE': 'eth99',
|
||||||
@ -12,85 +11,42 @@ SETUPVARS = {
|
|||||||
'PIHOLE_DNS_2': '4.2.2.2'
|
'PIHOLE_DNS_2': '4.2.2.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IMAGE = 'pytest_pihole:test_container'
|
||||||
|
|
||||||
tick_box = "[\x1b[1;32m\u2713\x1b[0m]"
|
tick_box = "[\x1b[1;32m\u2713\x1b[0m]"
|
||||||
cross_box = "[\x1b[1;31m\u2717\x1b[0m]"
|
cross_box = "[\x1b[1;31m\u2717\x1b[0m]"
|
||||||
info_box = "[i]"
|
info_box = "[i]"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
# Monkeypatch sh to bash, if they ever support non hard code /bin/sh this can go away
|
||||||
def Pihole(Docker):
|
# https://github.com/pytest-dev/pytest-testinfra/blob/master/testinfra/backend/docker.py
|
||||||
'''
|
|
||||||
used to contain some script stubbing, now pretty much an alias.
|
|
||||||
Also provides bash as the default run function shell
|
|
||||||
'''
|
|
||||||
def run_bash(self, command, *args, **kwargs):
|
def run_bash(self, command, *args, **kwargs):
|
||||||
cmd = self.get_command(command, *args)
|
cmd = self.get_command(command, *args)
|
||||||
if self.user is not None:
|
if self.user is not None:
|
||||||
out = self.run_local(
|
out = self.run_local(
|
||||||
"docker exec -u %s %s /bin/bash -c %s",
|
"docker exec -u %s %s /bin/bash -c %s", self.user, self.name, cmd
|
||||||
self.user, self.name, cmd)
|
)
|
||||||
else:
|
else:
|
||||||
out = self.run_local(
|
out = self.run_local("docker exec %s /bin/bash -c %s", self.name, cmd)
|
||||||
"docker exec %s /bin/bash -c %s", self.name, cmd)
|
|
||||||
out.command = self.encode(cmd)
|
out.command = self.encode(cmd)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
funcType = type(Docker.run)
|
|
||||||
Docker.run = funcType(run_bash, Docker)
|
testinfra.backend.docker.DockerBackend.run = run_bash
|
||||||
return Docker
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def Docker(request, args, image, cmd):
|
def host():
|
||||||
'''
|
# run a container
|
||||||
combine our fixtures into a docker run command and setup finalizer to
|
docker_id = subprocess.check_output(
|
||||||
cleanup
|
['docker', 'run', '-t', '-d', '--cap-add=ALL', IMAGE]).decode().strip()
|
||||||
'''
|
|
||||||
assert 'docker' in check_output('id'), "Are you in the docker group?"
|
|
||||||
docker_run = "docker run {} {} {}".format(args, image, cmd)
|
|
||||||
docker_id = check_output(docker_run)
|
|
||||||
|
|
||||||
def teardown():
|
# return a testinfra connection to the container
|
||||||
check_output("docker rm -f %s", docker_id)
|
docker_host = testinfra.get_host("docker://" + docker_id)
|
||||||
request.addfinalizer(teardown)
|
|
||||||
|
|
||||||
docker_container = testinfra.get_backend("docker://" + docker_id)
|
yield docker_host
|
||||||
docker_container.id = docker_id
|
# at the end of the test suite, destroy the container
|
||||||
return docker_container
|
subprocess.check_call(['docker', 'rm', '-f', docker_id])
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def args(request):
|
|
||||||
'''
|
|
||||||
-t became required when tput began being used
|
|
||||||
'''
|
|
||||||
return '-t -d'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=[
|
|
||||||
'test_container'
|
|
||||||
])
|
|
||||||
def tag(request):
|
|
||||||
'''
|
|
||||||
consumed by image to make the test matrix
|
|
||||||
'''
|
|
||||||
return request.param
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def image(request, tag):
|
|
||||||
'''
|
|
||||||
built by test_000_build_containers.py
|
|
||||||
'''
|
|
||||||
return 'pytest_pihole:{}'.format(tag)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def cmd(request):
|
|
||||||
'''
|
|
||||||
default to doing nothing by tailing null, but don't exit
|
|
||||||
'''
|
|
||||||
return 'tail -f /dev/null'
|
|
||||||
|
|
||||||
|
|
||||||
# Helper functions
|
# Helper functions
|
||||||
@ -100,7 +56,7 @@ def mock_command(script, args, container):
|
|||||||
in unit tests
|
in unit tests
|
||||||
'''
|
'''
|
||||||
full_script_path = '/usr/local/bin/{}'.format(script)
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||||
mock_script = dedent('''\
|
mock_script = dedent(r'''\
|
||||||
#!/bin/bash -e
|
#!/bin/bash -e
|
||||||
echo "\$0 \$@" >> /var/log/{script}
|
echo "\$0 \$@" >> /var/log/{script}
|
||||||
case "\$1" in'''.format(script=script))
|
case "\$1" in'''.format(script=script))
|
||||||
@ -121,13 +77,75 @@ def mock_command(script, args, container):
|
|||||||
scriptlog=script))
|
scriptlog=script))
|
||||||
|
|
||||||
|
|
||||||
|
def mock_command_passthrough(script, args, container):
|
||||||
|
'''
|
||||||
|
Per other mock_command* functions, allows intercepting of commands we don't want to run for real
|
||||||
|
in unit tests, however also allows only specific arguments to be mocked. Anything not defined will
|
||||||
|
be passed through to the actual command.
|
||||||
|
|
||||||
|
Example use-case: mocking `git pull` but still allowing `git clone` to work as intended
|
||||||
|
'''
|
||||||
|
orig_script_path = container.check_output('command -v {}'.format(script))
|
||||||
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||||
|
mock_script = dedent(r'''\
|
||||||
|
#!/bin/bash -e
|
||||||
|
echo "\$0 \$@" >> /var/log/{script}
|
||||||
|
case "\$1" in'''.format(script=script))
|
||||||
|
for k, v in args.items():
|
||||||
|
case = dedent('''
|
||||||
|
{arg})
|
||||||
|
echo {res}
|
||||||
|
exit {retcode}
|
||||||
|
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
||||||
|
mock_script += case
|
||||||
|
mock_script += dedent(r'''
|
||||||
|
*)
|
||||||
|
{orig_script_path} "\$@"
|
||||||
|
;;'''.format(orig_script_path=orig_script_path))
|
||||||
|
mock_script += dedent('''
|
||||||
|
esac''')
|
||||||
|
container.run('''
|
||||||
|
cat <<EOF> {script}\n{content}\nEOF
|
||||||
|
chmod +x {script}
|
||||||
|
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
||||||
|
content=mock_script,
|
||||||
|
scriptlog=script))
|
||||||
|
|
||||||
|
|
||||||
|
def mock_command_run(script, args, container):
|
||||||
|
'''
|
||||||
|
Allows for setup of commands we don't really want to have to run for real
|
||||||
|
in unit tests
|
||||||
|
'''
|
||||||
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||||
|
mock_script = dedent(r'''\
|
||||||
|
#!/bin/bash -e
|
||||||
|
echo "\$0 \$@" >> /var/log/{script}
|
||||||
|
case "\$1 \$2" in'''.format(script=script))
|
||||||
|
for k, v in args.items():
|
||||||
|
case = dedent('''
|
||||||
|
\"{arg}\")
|
||||||
|
echo {res}
|
||||||
|
exit {retcode}
|
||||||
|
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
||||||
|
mock_script += case
|
||||||
|
mock_script += dedent('''
|
||||||
|
esac''')
|
||||||
|
container.run('''
|
||||||
|
cat <<EOF> {script}\n{content}\nEOF
|
||||||
|
chmod +x {script}
|
||||||
|
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
||||||
|
content=mock_script,
|
||||||
|
scriptlog=script))
|
||||||
|
|
||||||
|
|
||||||
def mock_command_2(script, args, container):
|
def mock_command_2(script, args, container):
|
||||||
'''
|
'''
|
||||||
Allows for setup of commands we don't really want to have to run for real
|
Allows for setup of commands we don't really want to have to run for real
|
||||||
in unit tests
|
in unit tests
|
||||||
'''
|
'''
|
||||||
full_script_path = '/usr/local/bin/{}'.format(script)
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||||
mock_script = dedent('''\
|
mock_script = dedent(r'''\
|
||||||
#!/bin/bash -e
|
#!/bin/bash -e
|
||||||
echo "\$0 \$@" >> /var/log/{script}
|
echo "\$0 \$@" >> /var/log/{script}
|
||||||
case "\$1 \$2" in'''.format(script=script))
|
case "\$1 \$2" in'''.format(script=script))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
docker-compose==1.23.2
|
docker-compose
|
||||||
pytest==4.3.0
|
pytest
|
||||||
pytest-xdist==1.26.1
|
pytest-xdist
|
||||||
pytest-cov==2.6.1
|
pytest-cov
|
||||||
testinfra==1.19.0
|
pytest-testinfra
|
||||||
tox==3.7.0
|
tox
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -5,11 +5,11 @@ from .conftest import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_php_upgrade_default_optout_centos_eq_7(Pihole):
|
def test_php_upgrade_default_optout_centos_eq_7(host):
|
||||||
'''
|
'''
|
||||||
confirms the default behavior to opt-out of installing PHP7 from REMI
|
confirms the default behavior to opt-out of installing PHP7 from REMI
|
||||||
'''
|
'''
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -17,18 +17,18 @@ def test_php_upgrade_default_optout_centos_eq_7(Pihole):
|
|||||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
'Deprecated PHP may be in use.')
|
'Deprecated PHP may be in use.')
|
||||||
assert expected_stdout in package_manager_detect.stdout
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
remi_package = Pihole.package('remi-release')
|
remi_package = host.package('remi-release')
|
||||||
assert not remi_package.is_installed
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
def test_php_upgrade_user_optout_centos_eq_7(Pihole):
|
def test_php_upgrade_user_optout_centos_eq_7(host):
|
||||||
'''
|
'''
|
||||||
confirms installer behavior when user opt-out of installing PHP7 from REMI
|
confirms installer behavior when user opt-out of installing PHP7 from REMI
|
||||||
(php not currently installed)
|
(php not currently installed)
|
||||||
'''
|
'''
|
||||||
# Whiptail dialog returns Cancel for user prompt
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
mock_command('whiptail', {'*': ('', '1')}, Pihole)
|
mock_command('whiptail', {'*': ('', '1')}, host)
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -36,18 +36,18 @@ def test_php_upgrade_user_optout_centos_eq_7(Pihole):
|
|||||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
'Deprecated PHP may be in use.')
|
'Deprecated PHP may be in use.')
|
||||||
assert expected_stdout in package_manager_detect.stdout
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
remi_package = Pihole.package('remi-release')
|
remi_package = host.package('remi-release')
|
||||||
assert not remi_package.is_installed
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
def test_php_upgrade_user_optin_centos_eq_7(Pihole):
|
def test_php_upgrade_user_optin_centos_eq_7(host):
|
||||||
'''
|
'''
|
||||||
confirms installer behavior when user opt-in to installing PHP7 from REMI
|
confirms installer behavior when user opt-in to installing PHP7 from REMI
|
||||||
(php not currently installed)
|
(php not currently installed)
|
||||||
'''
|
'''
|
||||||
# Whiptail dialog returns Continue for user prompt
|
# Whiptail dialog returns Continue for user prompt
|
||||||
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
mock_command('whiptail', {'*': ('', '0')}, host)
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -59,5 +59,5 @@ def test_php_upgrade_user_optin_centos_eq_7(Pihole):
|
|||||||
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||||
'been enabled for PHP7')
|
'been enabled for PHP7')
|
||||||
assert expected_stdout in package_manager_detect.stdout
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
remi_package = Pihole.package('remi-release')
|
remi_package = host.package('remi-release')
|
||||||
assert remi_package.is_installed
|
assert remi_package.is_installed
|
||||||
|
@ -5,12 +5,12 @@ from .conftest import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_php_upgrade_default_continue_centos_gte_8(Pihole):
|
def test_php_upgrade_default_continue_centos_gte_8(host):
|
||||||
'''
|
'''
|
||||||
confirms the latest version of CentOS continues / does not optout
|
confirms the latest version of CentOS continues / does not optout
|
||||||
(should trigger on CentOS7 only)
|
(should trigger on CentOS7 only)
|
||||||
'''
|
'''
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -19,19 +19,19 @@ def test_php_upgrade_default_continue_centos_gte_8(Pihole):
|
|||||||
' Deprecated PHP may be in use.')
|
' Deprecated PHP may be in use.')
|
||||||
assert unexpected_stdout not in package_manager_detect.stdout
|
assert unexpected_stdout not in package_manager_detect.stdout
|
||||||
# ensure remi was not installed on latest CentOS
|
# ensure remi was not installed on latest CentOS
|
||||||
remi_package = Pihole.package('remi-release')
|
remi_package = host.package('remi-release')
|
||||||
assert not remi_package.is_installed
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
def test_php_upgrade_user_optout_skipped_centos_gte_8(Pihole):
|
def test_php_upgrade_user_optout_skipped_centos_gte_8(host):
|
||||||
'''
|
'''
|
||||||
confirms installer skips user opt-out of installing PHP7 from REMI on
|
confirms installer skips user opt-out of installing PHP7 from REMI on
|
||||||
latest CentOS (should trigger on CentOS7 only)
|
latest CentOS (should trigger on CentOS7 only)
|
||||||
(php not currently installed)
|
(php not currently installed)
|
||||||
'''
|
'''
|
||||||
# Whiptail dialog returns Cancel for user prompt
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
mock_command('whiptail', {'*': ('', '1')}, Pihole)
|
mock_command('whiptail', {'*': ('', '1')}, host)
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -40,19 +40,19 @@ def test_php_upgrade_user_optout_skipped_centos_gte_8(Pihole):
|
|||||||
' Deprecated PHP may be in use.')
|
' Deprecated PHP may be in use.')
|
||||||
assert unexpected_stdout not in package_manager_detect.stdout
|
assert unexpected_stdout not in package_manager_detect.stdout
|
||||||
# ensure remi was not installed on latest CentOS
|
# ensure remi was not installed on latest CentOS
|
||||||
remi_package = Pihole.package('remi-release')
|
remi_package = host.package('remi-release')
|
||||||
assert not remi_package.is_installed
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
def test_php_upgrade_user_optin_skipped_centos_gte_8(Pihole):
|
def test_php_upgrade_user_optin_skipped_centos_gte_8(host):
|
||||||
'''
|
'''
|
||||||
confirms installer skips user opt-in to installing PHP7 from REMI on
|
confirms installer skips user opt-in to installing PHP7 from REMI on
|
||||||
latest CentOS (should trigger on CentOS7 only)
|
latest CentOS (should trigger on CentOS7 only)
|
||||||
(php not currently installed)
|
(php not currently installed)
|
||||||
'''
|
'''
|
||||||
# Whiptail dialog returns Continue for user prompt
|
# Whiptail dialog returns Continue for user prompt
|
||||||
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
mock_command('whiptail', {'*': ('', '0')}, host)
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -64,5 +64,5 @@ def test_php_upgrade_user_optin_skipped_centos_gte_8(Pihole):
|
|||||||
unexpected_stdout = tick_box + (' Remi\'s RPM repository has '
|
unexpected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||||
'been enabled for PHP7')
|
'been enabled for PHP7')
|
||||||
assert unexpected_stdout not in package_manager_detect.stdout
|
assert unexpected_stdout not in package_manager_detect.stdout
|
||||||
remi_package = Pihole.package('remi-release')
|
remi_package = host.package('remi-release')
|
||||||
assert not remi_package.is_installed
|
assert not remi_package.is_installed
|
||||||
|
@ -7,13 +7,13 @@ from .conftest import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_release_supported_version_check_centos(Pihole):
|
def test_release_supported_version_check_centos(host):
|
||||||
'''
|
'''
|
||||||
confirms installer exits on unsupported releases of CentOS
|
confirms installer exits on unsupported releases of CentOS
|
||||||
'''
|
'''
|
||||||
# modify /etc/redhat-release to mock an unsupported CentOS release
|
# modify /etc/redhat-release to mock an unsupported CentOS release
|
||||||
Pihole.run('echo "CentOS Linux release 6.9" > /etc/redhat-release')
|
host.run('echo "CentOS Linux release 6.9" > /etc/redhat-release')
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -24,11 +24,11 @@ def test_release_supported_version_check_centos(Pihole):
|
|||||||
assert expected_stdout in package_manager_detect.stdout
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_enable_epel_repository_centos(Pihole):
|
def test_enable_epel_repository_centos(host):
|
||||||
'''
|
'''
|
||||||
confirms the EPEL package repository is enabled when installed on CentOS
|
confirms the EPEL package repository is enabled when installed on CentOS
|
||||||
'''
|
'''
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -38,22 +38,22 @@ def test_enable_epel_repository_centos(Pihole):
|
|||||||
assert expected_stdout in package_manager_detect.stdout
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
expected_stdout = tick_box + ' Installed epel-release'
|
expected_stdout = tick_box + ' Installed epel-release'
|
||||||
assert expected_stdout in package_manager_detect.stdout
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
epel_package = Pihole.package('epel-release')
|
epel_package = host.package('epel-release')
|
||||||
assert epel_package.is_installed
|
assert epel_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
def test_php_version_lt_7_detected_upgrade_default_optout_centos(Pihole):
|
def test_php_version_lt_7_detected_upgrade_default_optout_centos(host):
|
||||||
'''
|
'''
|
||||||
confirms the default behavior to opt-out of upgrading to PHP7 from REMI
|
confirms the default behavior to opt-out of upgrading to PHP7 from REMI
|
||||||
'''
|
'''
|
||||||
# first we will install the default php version to test installer behavior
|
# first we will install the default php version to test installer behavior
|
||||||
php_install = Pihole.run('yum install -y php')
|
php_install = host.run('yum install -y php')
|
||||||
assert php_install.rc == 0
|
assert php_install.rc == 0
|
||||||
php_package = Pihole.package('php')
|
php_package = host.package('php')
|
||||||
default_centos_php_version = php_package.version.split('.')[0]
|
default_centos_php_version = php_package.version.split('.')[0]
|
||||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -61,24 +61,24 @@ def test_php_version_lt_7_detected_upgrade_default_optout_centos(Pihole):
|
|||||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
'Deprecated PHP may be in use.')
|
'Deprecated PHP may be in use.')
|
||||||
assert expected_stdout in package_manager_detect.stdout
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
remi_package = Pihole.package('remi-release')
|
remi_package = host.package('remi-release')
|
||||||
assert not remi_package.is_installed
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
def test_php_version_lt_7_detected_upgrade_user_optout_centos(Pihole):
|
def test_php_version_lt_7_detected_upgrade_user_optout_centos(host):
|
||||||
'''
|
'''
|
||||||
confirms installer behavior when user opt-out to upgrade to PHP7 via REMI
|
confirms installer behavior when user opt-out to upgrade to PHP7 via REMI
|
||||||
'''
|
'''
|
||||||
# first we will install the default php version to test installer behavior
|
# first we will install the default php version to test installer behavior
|
||||||
php_install = Pihole.run('yum install -y php')
|
php_install = host.run('yum install -y php')
|
||||||
assert php_install.rc == 0
|
assert php_install.rc == 0
|
||||||
php_package = Pihole.package('php')
|
php_package = host.package('php')
|
||||||
default_centos_php_version = php_package.version.split('.')[0]
|
default_centos_php_version = php_package.version.split('.')[0]
|
||||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||||
# Whiptail dialog returns Cancel for user prompt
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
mock_command('whiptail', {'*': ('', '1')}, Pihole)
|
mock_command('whiptail', {'*': ('', '1')}, host)
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -86,24 +86,24 @@ def test_php_version_lt_7_detected_upgrade_user_optout_centos(Pihole):
|
|||||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
'Deprecated PHP may be in use.')
|
'Deprecated PHP may be in use.')
|
||||||
assert expected_stdout in package_manager_detect.stdout
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
remi_package = Pihole.package('remi-release')
|
remi_package = host.package('remi-release')
|
||||||
assert not remi_package.is_installed
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
def test_php_version_lt_7_detected_upgrade_user_optin_centos(Pihole):
|
def test_php_version_lt_7_detected_upgrade_user_optin_centos(host):
|
||||||
'''
|
'''
|
||||||
confirms installer behavior when user opt-in to upgrade to PHP7 via REMI
|
confirms installer behavior when user opt-in to upgrade to PHP7 via REMI
|
||||||
'''
|
'''
|
||||||
# first we will install the default php version to test installer behavior
|
# first we will install the default php version to test installer behavior
|
||||||
php_install = Pihole.run('yum install -y php')
|
php_install = host.run('yum install -y php')
|
||||||
assert php_install.rc == 0
|
assert php_install.rc == 0
|
||||||
php_package = Pihole.package('php')
|
php_package = host.package('php')
|
||||||
default_centos_php_version = php_package.version.split('.')[0]
|
default_centos_php_version = php_package.version.split('.')[0]
|
||||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||||
# Whiptail dialog returns Continue for user prompt
|
# Whiptail dialog returns Continue for user prompt
|
||||||
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
mock_command('whiptail', {'*': ('', '0')}, host)
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
@ -118,8 +118,8 @@ def test_php_version_lt_7_detected_upgrade_user_optin_centos(Pihole):
|
|||||||
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||||
'been enabled for PHP7')
|
'been enabled for PHP7')
|
||||||
assert expected_stdout in package_manager_detect.stdout
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
remi_package = Pihole.package('remi-release')
|
remi_package = host.package('remi-release')
|
||||||
assert remi_package.is_installed
|
assert remi_package.is_installed
|
||||||
updated_php_package = Pihole.package('php')
|
updated_php_package = host.package('php')
|
||||||
updated_php_version = updated_php_package.version.split('.')[0]
|
updated_php_version = updated_php_package.version.split('.')[0]
|
||||||
assert int(updated_php_version) == 7
|
assert int(updated_php_version) == 7
|
||||||
|
@ -5,7 +5,7 @@ from .conftest import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def mock_selinux_config(state, Pihole):
|
def mock_selinux_config(state, host):
|
||||||
'''
|
'''
|
||||||
Creates a mock SELinux config file with expected content
|
Creates a mock SELinux config file with expected content
|
||||||
'''
|
'''
|
||||||
@ -13,20 +13,20 @@ def mock_selinux_config(state, Pihole):
|
|||||||
valid_states = ['enforcing', 'permissive', 'disabled']
|
valid_states = ['enforcing', 'permissive', 'disabled']
|
||||||
assert state in valid_states
|
assert state in valid_states
|
||||||
# getenforce returns the running state of SELinux
|
# getenforce returns the running state of SELinux
|
||||||
mock_command('getenforce', {'*': (state.capitalize(), '0')}, Pihole)
|
mock_command('getenforce', {'*': (state.capitalize(), '0')}, host)
|
||||||
# create mock configuration with desired content
|
# create mock configuration with desired content
|
||||||
Pihole.run('''
|
host.run('''
|
||||||
mkdir /etc/selinux
|
mkdir /etc/selinux
|
||||||
echo "SELINUX={state}" > /etc/selinux/config
|
echo "SELINUX={state}" > /etc/selinux/config
|
||||||
'''.format(state=state.lower()))
|
'''.format(state=state.lower()))
|
||||||
|
|
||||||
|
|
||||||
def test_selinux_enforcing_exit(Pihole):
|
def test_selinux_enforcing_exit(host):
|
||||||
'''
|
'''
|
||||||
confirms installer prompts to exit when SELinux is Enforcing by default
|
confirms installer prompts to exit when SELinux is Enforcing by default
|
||||||
'''
|
'''
|
||||||
mock_selinux_config("enforcing", Pihole)
|
mock_selinux_config("enforcing", host)
|
||||||
check_selinux = Pihole.run('''
|
check_selinux = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
checkSelinux
|
checkSelinux
|
||||||
''')
|
''')
|
||||||
@ -37,12 +37,12 @@ def test_selinux_enforcing_exit(Pihole):
|
|||||||
assert check_selinux.rc == 1
|
assert check_selinux.rc == 1
|
||||||
|
|
||||||
|
|
||||||
def test_selinux_permissive(Pihole):
|
def test_selinux_permissive(host):
|
||||||
'''
|
'''
|
||||||
confirms installer continues when SELinux is Permissive
|
confirms installer continues when SELinux is Permissive
|
||||||
'''
|
'''
|
||||||
mock_selinux_config("permissive", Pihole)
|
mock_selinux_config("permissive", host)
|
||||||
check_selinux = Pihole.run('''
|
check_selinux = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
checkSelinux
|
checkSelinux
|
||||||
''')
|
''')
|
||||||
@ -51,12 +51,12 @@ def test_selinux_permissive(Pihole):
|
|||||||
assert check_selinux.rc == 0
|
assert check_selinux.rc == 0
|
||||||
|
|
||||||
|
|
||||||
def test_selinux_disabled(Pihole):
|
def test_selinux_disabled(host):
|
||||||
'''
|
'''
|
||||||
confirms installer continues when SELinux is Disabled
|
confirms installer continues when SELinux is Disabled
|
||||||
'''
|
'''
|
||||||
mock_selinux_config("disabled", Pihole)
|
mock_selinux_config("disabled", host)
|
||||||
check_selinux = Pihole.run('''
|
check_selinux = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
checkSelinux
|
checkSelinux
|
||||||
''')
|
''')
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
def test_epel_and_remi_not_installed_fedora(Pihole):
|
def test_epel_and_remi_not_installed_fedora(host):
|
||||||
'''
|
'''
|
||||||
confirms installer does not attempt to install EPEL/REMI repositories
|
confirms installer does not attempt to install EPEL/REMI repositories
|
||||||
on Fedora
|
on Fedora
|
||||||
'''
|
'''
|
||||||
package_manager_detect = Pihole.run('''
|
package_manager_detect = host.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
package_manager_detect
|
package_manager_detect
|
||||||
select_rpm_php
|
select_rpm_php
|
||||||
''')
|
''')
|
||||||
assert package_manager_detect.stdout == ''
|
assert package_manager_detect.stdout == ''
|
||||||
|
|
||||||
epel_package = Pihole.package('epel-release')
|
epel_package = host.package('epel-release')
|
||||||
assert not epel_package.is_installed
|
assert not epel_package.is_installed
|
||||||
remi_package = Pihole.package('remi-release')
|
remi_package = host.package('remi-release')
|
||||||
assert not remi_package.is_installed
|
assert not remi_package.is_installed
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py37
|
envlist = py38
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = docker
|
whitelist_externals = docker
|
||||||
|
Loading…
Reference in New Issue
Block a user