From 2beb564e7cbf118d41991f40c6a7031412319f6a Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Wed, 22 Apr 2020 15:01:46 +0200 Subject: [PATCH 01/20] Start to work on an upgrade to 4.x --- conf/{FTL.src => FTL_3.src} | 0 conf/FTL_last.src | 6 + conf/adlists.default | 19 ++++ ...in_dashboard.src => admin_dashboard_3.src} | 0 conf/admin_dashboard_last.src | 6 + conf/{app.src => app_3.src} | 0 conf/app_last.src | 6 + manifest.json | 14 +++ scripts/_variables | 2 +- scripts/install | 105 ++++++++++++++---- scripts/remove | 27 ++++- 11 files changed, 156 insertions(+), 29 deletions(-) rename conf/{FTL.src => FTL_3.src} (100%) create mode 100644 conf/FTL_last.src create mode 100644 conf/adlists.default rename conf/{admin_dashboard.src => admin_dashboard_3.src} (100%) create mode 100644 conf/admin_dashboard_last.src rename conf/{app.src => app_3.src} (100%) create mode 100644 conf/app_last.src diff --git a/conf/FTL.src b/conf/FTL_3.src similarity index 100% rename from conf/FTL.src rename to conf/FTL_3.src diff --git a/conf/FTL_last.src b/conf/FTL_last.src new file mode 100644 index 0000000..60342ce --- /dev/null +++ b/conf/FTL_last.src @@ -0,0 +1,6 @@ +SOURCE_URL=https://github.com/pi-hole/FTL/archive/v4.3.1.tar.gz +SOURCE_SUM=1c0df5fa42e7f7b89c7e704fdc1b5154 +SOURCE_SUM_PRG=md5sum +SOURCE_FORMAT=tar.gz +SOURCE_IN_SUBDIR=true +SOURCE_FILENAME= diff --git a/conf/adlists.default b/conf/adlists.default new file mode 100644 index 0000000..d1b7ecd --- /dev/null +++ b/conf/adlists.default @@ -0,0 +1,19 @@ +# The below list amalgamates several lists we used previously. +# See `https://github.com/StevenBlack/hosts` for details +##StevenBlack's list +https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts + +##MalwareDomains +https://mirror1.malwaredomains.com/files/justdomains + +##Cameleon +http://sysctl.org/cameleon/hosts + +##Disconnect.me Tracking +https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt + +##Disconnect.me Ads +https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt + +##Hosts-file.net +https://hosts-file.net/ad_servers.txt diff --git a/conf/admin_dashboard.src b/conf/admin_dashboard_3.src similarity index 100% rename from conf/admin_dashboard.src rename to conf/admin_dashboard_3.src diff --git a/conf/admin_dashboard_last.src b/conf/admin_dashboard_last.src new file mode 100644 index 0000000..ee04744 --- /dev/null +++ b/conf/admin_dashboard_last.src @@ -0,0 +1,6 @@ +SOURCE_URL=https://github.com/pi-hole/AdminLTE/archive/v4.3.3.tar.gz +SOURCE_SUM=3f9da0e1f9134393758b7a1425ca66f6 +SOURCE_SUM_PRG=md5sum +SOURCE_FORMAT=tar.gz +SOURCE_IN_SUBDIR=true +SOURCE_FILENAME= diff --git a/conf/app.src b/conf/app_3.src similarity index 100% rename from conf/app.src rename to conf/app_3.src diff --git a/conf/app_last.src b/conf/app_last.src new file mode 100644 index 0000000..3e7c2a8 --- /dev/null +++ b/conf/app_last.src @@ -0,0 +1,6 @@ +SOURCE_URL=https://github.com/pi-hole/pi-hole/archive/v4.4.tar.gz +SOURCE_SUM=970013bf8e273b868dd184ac2ffb1348 +SOURCE_SUM_PRG=md5sum +SOURCE_FORMAT=tar.gz +SOURCE_IN_SUBDIR=true +SOURCE_FILENAME= diff --git a/manifest.json b/manifest.json index 7f92313..7a603d8 100644 --- a/manifest.json +++ b/manifest.json @@ -76,6 +76,20 @@ "fr": "Si vous voulez faire ça, vous devez vraiment lire cela avant !" }, "default": false + }, + { + "name": "pihole_version", + "type": "string", + "ask": { + "en": "Which version of Pi-Hole do you want to install ?", + "fr": "Quelle version de Pi-Hole voulez-vous installer ?" + }, + "help": { + "en": "The last 3.X version is the last version available with the Debian version of dnsmasq.", + "fr": "The last available version will replace the Debian version of dnsmasq by FTLDNS.
See the readme for more information." + }, + "choices" : ["Last 3.X","Last available"], + "default": "Last 3.X" } ] } diff --git a/scripts/_variables b/scripts/_variables index 1016b09..02834a9 100644 --- a/scripts/_variables +++ b/scripts/_variables @@ -1,4 +1,4 @@ #!/bin/bash # Dependencies -app_depencencies="sqlite idn2 php7.0-sqlite3" +app_depencencies="sqlite idn2 php7.0-sqlite3 nettle-dev libcap2-bin" diff --git a/scripts/install b/scripts/install index f1b05fb..8e045dd 100644 --- a/scripts/install +++ b/scripts/install @@ -28,6 +28,7 @@ path_url=$YNH_APP_ARG_PATH admin=$YNH_APP_ARG_ADMIN query_logging=$YNH_APP_ARG_QUERY_LOGGING enable_dhcp=$YNH_APP_ARG_ENABLE_DHCP +pihole_version="$YNH_APP_ARG_PIHOLE_VERSION" app=$YNH_APP_INSTANCE_NAME @@ -52,6 +53,7 @@ ynh_app_setting_set --app=$app --key=path --value=$path_url ynh_app_setting_set --app=$app --key=admin --value=$admin ynh_app_setting_set --app=$app --key=query_logging --value=$query_logging ynh_app_setting_set --app=$app --key=enable_dhcp --value=$enable_dhcp +ynh_app_setting_set --app=$app --key=pihole_version --value="$pihole_version" ynh_app_setting_set --app=$app --key=overwrite_setupvars --value=1 ynh_app_setting_set --app=$app --key=overwrite_ftl --value=1 @@ -95,9 +97,18 @@ ynh_script_progression --message="Setting up source files..." --weight=4 ynh_app_setting_set --app=$app --key=final_path --value=$final_path # Make a copy of local pihole repository (for Gravity) pihole_local_repo="/etc/.pihole" -ynh_setup_source --dest_dir="$pihole_local_repo" -# Install admin dashboard -ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard +if [ "$pihole_version" == "Last 3.X" ] +then + # Install the version 3.3.1 + ynh_setup_source --dest_dir="$pihole_local_repo" --source_id=app_3 + # Install admin dashboard + ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard_3 +else + # Install the last version available + ynh_setup_source --dest_dir="$pihole_local_repo" --source_id=app_last + # Install admin dashboard + ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard_last +fi #================================================= # NGINX CONFIGURATION @@ -166,7 +177,12 @@ chown $dnsmasq_user:root /var/log/pihole.log #================================================= # This sudoers config allow pihole to execute /usr/local/bin/pihole as root without password. Nothing more. -cp "$pihole_local_repo/advanced/pihole.sudo" /etc/sudoers.d/pihole +if [ "$pihole_version" == "Last 3.X" ] +then + cp "$pihole_local_repo/advanced/pihole.sudo" /etc/sudoers.d/pihole +else + cp "$pihole_local_repo/advanced/Templates/pihole.sudo" /etc/sudoers.d/pihole +fi echo "$app ALL=NOPASSWD: /usr/local/bin/pihole" >> /etc/sudoers.d/pihole # echo "Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin" >> /etc/sudoers.d/pihole chmod 0440 /etc/sudoers.d/pihole @@ -175,7 +191,12 @@ chmod 0440 /etc/sudoers.d/pihole # INSTALL LOGROTATE SCRIPT FOR PI-HOLE #================================================= -cp "$pihole_local_repo/advanced/logrotate" "$pihole_storage/logrotate" +if [ "$pihole_version" == "Last 3.X" ] +then + cp "$pihole_local_repo/advanced/logrotate" "$pihole_storage/logrotate" +else + cp "$pihole_local_repo/advanced/Templates/logrotate" "$pihole_storage/logrotate" +fi sed -i "/# su #/d;" "$pihole_storage/logrotate" #================================================= @@ -185,7 +206,14 @@ ynh_script_progression --message="Installing PiHole-FTL..." --weight=30 # Get the source of Pi-Hole-FTL FTL_temp_path=$(mktemp -d) -ynh_setup_source --dest_dir="$FTL_temp_path" --source_id=FTL +if [ "$pihole_version" == "Last 3.X" ] +then + # Install the version 3.3.1 + ynh_setup_source --dest_dir="$FTL_temp_path" --source_id=FTL_3 +else + # Install the last version available + ynh_setup_source --dest_dir="$FTL_temp_path" --source_id=FTL_last +fi # Instead of downloading a binary file, we're going to compile it ( cd "$FTL_temp_path" @@ -197,9 +225,24 @@ cp "../conf/pihole-FTL.conf" "$pihole_storage" # Calculate and store the config file checksum into the app settings ynh_store_file_checksum --file="$pihole_storage/pihole-FTL.conf" -cp -a $pihole_local_repo/advanced/pihole-FTL.service /etc/init.d/pihole-FTL -chmod +x /etc/init.d/pihole-FTL -ynh_exec_warn_less systemctl enable pihole-FTL +if [ "$pihole_version" == "Last 3.X" ] +then + # Version 3.3.1 + cp -a $pihole_local_repo/advanced/pihole-FTL.service /etc/init.d/pihole-FTL + chmod +x /etc/init.d/q + ynh_exec_warn_less systemctl enable pihole-FTL +else + # Last version available + # Stopped dnsmasq to replace it by pihole-FTL + ynh_systemd_action --action=stop --service_name=dnsmasq + # Move dnsmasq to preserve the current version + mv /usr/sbin/dnsmasq /usr/sbin/dnsmasq.backup_by_pihole + # Replace dnsmasq by pihole-FTL + # NOTE: pihole-FTL is actually a modified version of dnsmasq + # https://github.com/pi-hole/FTL/tree/master/dnsmasq + update-alternatives --install /usr/sbin/dnsmasq dnsmasq /usr/bin/pihole-FTL 50 + update-alternatives --install /usr/sbin/dnsmasq dnsmasq /usr/sbin/dnsmasq.backup_by_pihole 40 +fi #================================================= # BUILD VARIABLES FILE @@ -312,6 +355,20 @@ fi # Open the UDP port 67 for dhcp ynh_exec_fully_quiet yunohost firewall allow UDP 67 --no-upnp +#================================================= +# INSTALL CRON JOB +#================================================= + +if [ "$pihole_version" == "Last 3.X" ] +then + cp $pihole_local_repo/advanced/pihole.cron /etc/cron.d/pihole +else + cp $pihole_local_repo/advanced/Templates/pihole.cron /etc/cron.d/pihole +fi + +# Remove git usage for version. Which fails because we use here a release instead of master. +ynh_replace_string --match_string=".*updatechecker.*" --replace_string="#&" --target_file=/etc/cron.d/pihole + #================================================= # RESTART DNSMASQ #================================================= @@ -320,28 +377,29 @@ ynh_script_progression --message="Restarting Dnsmasq..." --weight=2 ynh_systemd_action --action=restart --service_name=dnsmasq #================================================= -# INSTALL CRON JOB +# START PIHOLE-FTL #================================================= -cp $pihole_local_repo/advanced/pihole.cron /etc/cron.d/pihole -# Remove git usage for version. Which fails because we use here a release instead of master. -ynh_replace_string --match_string=".*updatechecker.*" --replace_string="#&" --target_file=/etc/cron.d/pihole +if [ "$pihole_version" == "Last 3.X" ] +then + ynh_script_progression --message="Restarting PiHole-FTL..." --weight=2 + + ynh_systemd_action --action=restart --service_name=pihole-FTL +fi #================================================= # BUILD THE LISTS WITH GRAVITY #================================================= ynh_script_progression --message="Building the lists with Gravity..." --weight=7 -cp "$pihole_local_repo/adlists.default" "$pihole_storage/adlists.default" +if [ "$pihole_version" == "Last 3.X" ] +then + cp "$pihole_local_repo/adlists.default" "$pihole_storage/adlists.default" +else + cp "../conf/adlists.default" "$pihole_storage/adlists.list" +fi ynh_exec_warn_less /opt/pihole/gravity.sh -#================================================= -# START PIHOLE-FTL -#================================================= -ynh_script_progression --message="Restarting PiHole-FTL..." --weight=2 - -ynh_systemd_action --action=restart --service_name=pihole-FTL - #================================================= # SET UP CONF_REGEN HOOK #================================================= @@ -354,7 +412,10 @@ cp ../conf/dnsmasq_regenconf_hook /usr/share/yunohost/hooks/conf_regen/50-dnsmas # ADVERTISE SERVICE IN ADMIN PANEL #================================================= -yunohost service add pihole-FTL --description "PiHole backend service" --log "/var/log/pihole-FTL.log" +if [ "$pihole_version" == "Last 3.X" ] +then + yunohost service add pihole-FTL --description "PiHole backend service" --log "/var/log/pihole-FTL.log" +fi #================================================= # RESTRAIN THE ACCESS TO THE ADMIN ONLY diff --git a/scripts/remove b/scripts/remove index 928cb91..a0e0d67 100755 --- a/scripts/remove +++ b/scripts/remove @@ -18,6 +18,7 @@ app=$YNH_APP_INSTANCE_NAME domain=$(ynh_app_setting_get --app=$app --key=domain) port=$(ynh_app_setting_get --app=$app --key=port) +pihole_version="$(ynh_app_setting_get --app=$app --key=pihole_version)" #================================================= # STANDARD REMOVE @@ -25,11 +26,14 @@ port=$(ynh_app_setting_get --app=$app --key=port) # REMOVE SERVICE FROM ADMIN PANEL #================================================= -# Check if the service is declared in YunoHost -if ynh_exec_fully_quiet yunohost service status pihole-FTL +if [ "$pihole_version" == "Last 3.X" ] then - ynh_script_progression --message="Removing pihole-FTL service..." --weight=2 - yunohost service remove pihole-FTL + # Check if the service is declared in YunoHost + if ynh_exec_fully_quiet yunohost service status pihole-FTL + then + ynh_script_progression --message="Removing pihole-FTL service..." --weight=2 + yunohost service remove pihole-FTL + fi fi #================================================= @@ -37,8 +41,19 @@ fi #================================================= ynh_script_progression --message="Stop and remove the service" -ynh_systemd_action --action=stop --service_name=pihole-FTL -ynh_exec_warn_less systemctl disable pihole-FTL +if [ "$pihole_version" == "Last 3.X" ] +then + ynh_systemd_action --action=stop --service_name=pihole-FTL + ynh_exec_warn_less systemctl disable pihole-FTL +else + ynh_systemd_action --action=stop --service_name=dnsmasq + # Restore dnsmasq as main DNS resolver + # Remove alternatives + update-alternatives --remove dnsmasq /usr/bin/pihole-FTL + update-alternatives --remove dnsmasq /usr/sbin/dnsmasq.backup_by_pihole + # Move dnsmasq back to its original place + mv /usr/sbin/dnsmasq.backup_by_pihole /usr/sbin/dnsmasq +fi rm -f "/etc/init.d/pihole-FTL" "/usr/bin/pihole-FTL" "/var/run/pihole-FTL.pid" "/var/run/pihole-FTL.port" #================================================= From f2f174413dc25156516914aae564fb69c115d749 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Thu, 23 Apr 2020 01:42:03 +0200 Subject: [PATCH 02/20] Ongoing work for 4.x --- conf/FTL_last.src | 10 +++++++--- scripts/install | 48 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/conf/FTL_last.src b/conf/FTL_last.src index 60342ce..fa244a6 100644 --- a/conf/FTL_last.src +++ b/conf/FTL_last.src @@ -1,6 +1,10 @@ -SOURCE_URL=https://github.com/pi-hole/FTL/archive/v4.3.1.tar.gz -SOURCE_SUM=1c0df5fa42e7f7b89c7e704fdc1b5154 +SOURCE_URL=https://github.com/pi-hole/FTL/archive/894a3c74a8e17b92c68a986e990d5f7f3c127ae2.zip +SOURCE_SUM=e7a75a792fdc836389b71808165bca18 SOURCE_SUM_PRG=md5sum -SOURCE_FORMAT=tar.gz +SOURCE_FORMAT=zip SOURCE_IN_SUBDIR=true SOURCE_FILENAME= + +#SOURCE_old_URL=https://github.com/pi-hole/FTL/archive/v4.3.1.tar.gz +#SOURCE_old_SUM=1c0df5fa42e7f7b89c7e704fdc1b5154 +#SOURCE_old_FORMAT=tar.gz diff --git a/scripts/install b/scripts/install index 8e045dd..82ffe81 100644 --- a/scripts/install +++ b/scripts/install @@ -229,12 +229,22 @@ if [ "$pihole_version" == "Last 3.X" ] then # Version 3.3.1 cp -a $pihole_local_repo/advanced/pihole-FTL.service /etc/init.d/pihole-FTL - chmod +x /etc/init.d/q + chmod +x /etc/init.d/pihole-FTL ynh_exec_warn_less systemctl enable pihole-FTL else # Last version available # Stopped dnsmasq to replace it by pihole-FTL ynh_systemd_action --action=stop --service_name=dnsmasq + +systemctl disable dnsmasq +# rm /lib/systemd/system/dnsmasq.service +mv /lib/systemd/system/dnsmasq.service /lib/systemd/system/.dnsmasq.service +# rm /etc/init.d/dnsmasq +mv /etc/init.d/dnsmasq /etc/init.d/.dnsmasq + + cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL + chmod +x /etc/init.d/pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL # Move dnsmasq to preserve the current version mv /usr/sbin/dnsmasq /usr/sbin/dnsmasq.backup_by_pihole # Replace dnsmasq by pihole-FTL @@ -242,6 +252,36 @@ else # https://github.com/pi-hole/FTL/tree/master/dnsmasq update-alternatives --install /usr/sbin/dnsmasq dnsmasq /usr/bin/pihole-FTL 50 update-alternatives --install /usr/sbin/dnsmasq dnsmasq /usr/sbin/dnsmasq.backup_by_pihole 40 + +# cp /etc/init.d/pihole-FTL /etc/init.d/dnsmasq +# systemctl enable dnsmasq + +# ln --symbolic /run/pihole-FTL.pid /run/dnsmasq/dnsmasq.pid + +# lrwxrwxrwx 1 root root 35 Jun 22 2018 /etc/systemd/system/multi-user.target.wants/dnsmasq.service -> /lib/systemd/system/dnsmasq.service +# /run/systemd/generator.late/pihole-FTL.service +sudo ln -s /run/systemd/generator.late/pihole-FTL.service /etc/systemd/system/multi-user.target.wants/dnsmasq.service +sudo systemctl daemon-reload + +# sudo yunohost app install github/pihole_ynh/ --args "admin=mcrudelis&pihole_version=Last available&" -f -n + +# >>> It does work, as we have both dnsmasq and pihole-FTL as the same. +# But no more dns resolution... + +# sudo systemctl daemon-reload + +# /lib/systemd/system/dnsmasq.service +# /etc/init.d/dnsmasq + +# systemctl stop dnsmasq +# systemctl disable dnsmasq +# If I remove /lib/systemd/system/dnsmasq.service and /etc/init.d/dnsmasq, it works. +# sudo systemctl daemon-reload + +# But we don't have dnsmasq anymore... +# Duplicating /etc/init.d/pihole-FTL in /etc/init.d/dnsmasq does work + + fi #================================================= @@ -273,7 +313,7 @@ ynh_store_file_checksum --file="$setupVars" #================================================= ynh_script_progression --message="Setting up Dnsmasq config..." --weight=2 -ynh_systemd_action --action=stop --service_name=dnsmasq +# ynh_systemd_action --action=stop --service_name=dnsmasq pihole_dnsmasq_config="/etc/dnsmasq.d/01-pihole.conf" cp "$pihole_local_repo/advanced/01-pihole.conf" $pihole_dnsmasq_config @@ -374,7 +414,7 @@ ynh_replace_string --match_string=".*updatechecker.*" --replace_string="#&" --ta #================================================= ynh_script_progression --message="Restarting Dnsmasq..." --weight=2 -ynh_systemd_action --action=restart --service_name=dnsmasq +# ynh_systemd_action --action=restart --service_name=dnsmasq #================================================= # START PIHOLE-FTL @@ -387,6 +427,8 @@ then ynh_systemd_action --action=restart --service_name=pihole-FTL fi +sleep 5 + #================================================= # BUILD THE LISTS WITH GRAVITY #================================================= From 445dcfec6a1485ea5c3702f9329479fead390cdb Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 24 Apr 2020 01:36:19 +0200 Subject: [PATCH 03/20] Working install/remove for 4.X --- conf/FTL_last.src | 10 +- scripts/install | 77 ++++------ scripts/remove | 38 +++-- sources/patches/.gitignore | 2 + .../patches/FTL_last-dns_replacement.patch | 131 ++++++++++++++++++ 5 files changed, 187 insertions(+), 71 deletions(-) create mode 100644 sources/patches/.gitignore create mode 100644 sources/patches/FTL_last-dns_replacement.patch diff --git a/conf/FTL_last.src b/conf/FTL_last.src index fa244a6..60342ce 100644 --- a/conf/FTL_last.src +++ b/conf/FTL_last.src @@ -1,10 +1,6 @@ -SOURCE_URL=https://github.com/pi-hole/FTL/archive/894a3c74a8e17b92c68a986e990d5f7f3c127ae2.zip -SOURCE_SUM=e7a75a792fdc836389b71808165bca18 +SOURCE_URL=https://github.com/pi-hole/FTL/archive/v4.3.1.tar.gz +SOURCE_SUM=1c0df5fa42e7f7b89c7e704fdc1b5154 SOURCE_SUM_PRG=md5sum -SOURCE_FORMAT=zip +SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true SOURCE_FILENAME= - -#SOURCE_old_URL=https://github.com/pi-hole/FTL/archive/v4.3.1.tar.gz -#SOURCE_old_SUM=1c0df5fa42e7f7b89c7e704fdc1b5154 -#SOURCE_old_FORMAT=tar.gz diff --git a/scripts/install b/scripts/install index 82ffe81..9d93e60 100644 --- a/scripts/install +++ b/scripts/install @@ -236,52 +236,30 @@ else # Stopped dnsmasq to replace it by pihole-FTL ynh_systemd_action --action=stop --service_name=dnsmasq -systemctl disable dnsmasq -# rm /lib/systemd/system/dnsmasq.service -mv /lib/systemd/system/dnsmasq.service /lib/systemd/system/.dnsmasq.service -# rm /etc/init.d/dnsmasq -mv /etc/init.d/dnsmasq /etc/init.d/.dnsmasq + # Disable the real dnsmasq service + ynh_exec_warn_less systemctl disable dnsmasq - cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL - chmod +x /etc/init.d/pihole-FTL - ynh_exec_warn_less systemctl enable pihole-FTL - # Move dnsmasq to preserve the current version + # And move the files that make the service available in systemd to really disable it + mv /lib/systemd/system/dnsmasq.service /lib/systemd/system/.dnsmasq.service.backup_by_pihole + mv /etc/init.d/dnsmasq /etc/init.d/.dnsmasq.backup_by_pihole + + # Move dnsmasq to preserve the current binary mv /usr/sbin/dnsmasq /usr/sbin/dnsmasq.backup_by_pihole # Replace dnsmasq by pihole-FTL # NOTE: pihole-FTL is actually a modified version of dnsmasq # https://github.com/pi-hole/FTL/tree/master/dnsmasq - update-alternatives --install /usr/sbin/dnsmasq dnsmasq /usr/bin/pihole-FTL 50 - update-alternatives --install /usr/sbin/dnsmasq dnsmasq /usr/sbin/dnsmasq.backup_by_pihole 40 + ln -s /usr/bin/pihole-FTL /usr/sbin/dnsmasq -# cp /etc/init.d/pihole-FTL /etc/init.d/dnsmasq -# systemctl enable dnsmasq - -# ln --symbolic /run/pihole-FTL.pid /run/dnsmasq/dnsmasq.pid - -# lrwxrwxrwx 1 root root 35 Jun 22 2018 /etc/systemd/system/multi-user.target.wants/dnsmasq.service -> /lib/systemd/system/dnsmasq.service -# /run/systemd/generator.late/pihole-FTL.service -sudo ln -s /run/systemd/generator.late/pihole-FTL.service /etc/systemd/system/multi-user.target.wants/dnsmasq.service -sudo systemctl daemon-reload - -# sudo yunohost app install github/pihole_ynh/ --args "admin=mcrudelis&pihole_version=Last available&" -f -n - -# >>> It does work, as we have both dnsmasq and pihole-FTL as the same. -# But no more dns resolution... - -# sudo systemctl daemon-reload - -# /lib/systemd/system/dnsmasq.service -# /etc/init.d/dnsmasq - -# systemctl stop dnsmasq -# systemctl disable dnsmasq -# If I remove /lib/systemd/system/dnsmasq.service and /etc/init.d/dnsmasq, it works. -# sudo systemctl daemon-reload - -# But we don't have dnsmasq anymore... -# Duplicating /etc/init.d/pihole-FTL in /etc/init.d/dnsmasq does work + cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL + chmod +x /etc/init.d/pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL + # Replace the service dnsmasq by pihole-FTL + # That way, YunoHost can continue to use dnsmasq by actually using pihole-FTL + ln -s /run/systemd/generator.late/pihole-FTL.service /etc/systemd/system/multi-user.target.wants/dnsmasq.service + # Reload systemd config + systemctl daemon-reload fi #================================================= @@ -412,22 +390,22 @@ ynh_replace_string --match_string=".*updatechecker.*" --replace_string="#&" --ta #================================================= # RESTART DNSMASQ #================================================= -ynh_script_progression --message="Restarting Dnsmasq..." --weight=2 -# ynh_systemd_action --action=restart --service_name=dnsmasq +# Restart dnsmasq only for the version 3.X, otherwise we're going to restart it twice. +if [ "$pihole_version" == "Last 3.X" ] +then + ynh_script_progression --message="Restarting Dnsmasq..." --weight=2 + + ynh_systemd_action --action=restart --service_name=dnsmasq +fi #================================================= # START PIHOLE-FTL #================================================= -if [ "$pihole_version" == "Last 3.X" ] -then - ynh_script_progression --message="Restarting PiHole-FTL..." --weight=2 +ynh_script_progression --message="Restarting PiHole-FTL..." --weight=2 - ynh_systemd_action --action=restart --service_name=pihole-FTL -fi - -sleep 5 +ynh_systemd_action --action=restart --service_name=pihole-FTL #================================================= # BUILD THE LISTS WITH GRAVITY @@ -454,10 +432,7 @@ cp ../conf/dnsmasq_regenconf_hook /usr/share/yunohost/hooks/conf_regen/50-dnsmas # ADVERTISE SERVICE IN ADMIN PANEL #================================================= -if [ "$pihole_version" == "Last 3.X" ] -then - yunohost service add pihole-FTL --description "PiHole backend service" --log "/var/log/pihole-FTL.log" -fi +yunohost service add pihole-FTL --description "PiHole backend service" --log "/var/log/pihole-FTL.log" #================================================= # RESTRAIN THE ACCESS TO THE ADMIN ONLY diff --git a/scripts/remove b/scripts/remove index a0e0d67..7b3a87b 100755 --- a/scripts/remove +++ b/scripts/remove @@ -26,14 +26,11 @@ pihole_version="$(ynh_app_setting_get --app=$app --key=pihole_version)" # REMOVE SERVICE FROM ADMIN PANEL #================================================= -if [ "$pihole_version" == "Last 3.X" ] +# Check if the service is declared in YunoHost +if ynh_exec_fully_quiet yunohost service status pihole-FTL then - # Check if the service is declared in YunoHost - if ynh_exec_fully_quiet yunohost service status pihole-FTL - then - ynh_script_progression --message="Removing pihole-FTL service..." --weight=2 - yunohost service remove pihole-FTL - fi + ynh_script_progression --message="Removing pihole-FTL service..." --weight=2 + yunohost service remove pihole-FTL fi #================================================= @@ -46,15 +43,30 @@ then ynh_systemd_action --action=stop --service_name=pihole-FTL ynh_exec_warn_less systemctl disable pihole-FTL else - ynh_systemd_action --action=stop --service_name=dnsmasq + ynh_systemd_action --action=stop --service_name=pihole-FTL + # Restore dnsmasq as main DNS resolver - # Remove alternatives - update-alternatives --remove dnsmasq /usr/bin/pihole-FTL - update-alternatives --remove dnsmasq /usr/sbin/dnsmasq.backup_by_pihole # Move dnsmasq back to its original place - mv /usr/sbin/dnsmasq.backup_by_pihole /usr/sbin/dnsmasq + if [ -e "/usr/sbin/dnsmasq.backup_by_pihole" ] + then # Remove dnsmasq only if we have its backup + ynh_secure_remove --file="/usr/sbin/dnsmasq" + mv /usr/sbin/dnsmasq.backup_by_pihole /usr/sbin/dnsmasq + fi + + # Move back the service configuration for dnsmasq + ynh_secure_remove --file="/etc/systemd/system/multi-user.target.wants/dnsmasq.service" + mv /lib/systemd/system/.dnsmasq.service.backup_by_pihole /lib/systemd/system/dnsmasq.service + mv /etc/init.d/.dnsmasq.backup_by_pihole /etc/init.d/dnsmasq + + ynh_exec_warn_less systemctl enable dnsmasq + # Reload systemd config + systemctl daemon-reload fi -rm -f "/etc/init.d/pihole-FTL" "/usr/bin/pihole-FTL" "/var/run/pihole-FTL.pid" "/var/run/pihole-FTL.port" + +ynh_secure_remove --file="/etc/init.d/pihole-FTL" +ynh_secure_remove --file="/usr/bin/pihole-FTL" +ynh_secure_remove --file="/var/run/pihole-FTL.pid" +ynh_secure_remove --file="/var/run/pihole-FTL.port" #================================================= # REMOVE DEPENDENCIES diff --git a/sources/patches/.gitignore b/sources/patches/.gitignore new file mode 100644 index 0000000..d38c149 --- /dev/null +++ b/sources/patches/.gitignore @@ -0,0 +1,2 @@ +*.swp +*~ diff --git a/sources/patches/FTL_last-dns_replacement.patch b/sources/patches/FTL_last-dns_replacement.patch new file mode 100644 index 0000000..9f24389 --- /dev/null +++ b/sources/patches/FTL_last-dns_replacement.patch @@ -0,0 +1,131 @@ +--- a/args.c 2019-05-25 21:37:26.000000000 +0200 ++++ b/args.c 2020-04-24 00:32:27.000000000 +0200 +@@ -17,20 +17,88 @@ + int argc_dnsmasq = 0; + const char** argv_dnsmasq = NULL; + ++static inline bool strEndsWith(const char *input, const char *end){ ++ return strcmp(input + strlen(input) - strlen(end), end) == 0; ++} ++ + void parse_args(int argc, char* argv[]) + { +- int i; +- + // Regardless of any arguments, we always pass "-k" (nofork) to dnsmasq + argc_dnsmasq = 2; + argv_dnsmasq = calloc(argc_dnsmasq, sizeof(char*)); + argv_dnsmasq[0] = ""; + argv_dnsmasq[1] = "-k"; + +- // start from 1, as argv[0] is the executable name "pihole-FTL" +- for(i=1; i < argc; i++) ++ bool consume_for_dnsmasq = false; ++ // If the binary name is "dnsmasq" (e.g., symlink /usr/bin/dnsmasq -> /usr/bin/pihole-FTL), ++ // we operate in drop-in mode and consume all arguments for the embedded dnsmasq core ++ if(strEndsWith(argv[0], "dnsmasq")) ++ consume_for_dnsmasq = true; ++ ++ // start from 1, as argv[0] is the executable name ++ for(int i = 1; i < argc; i++) + { + bool ok = false; ++ ++ // Implement dnsmasq's test function, no need to prepare the entire FTL ++ // environment (initialize shared memory, lead queries from long-term ++ // database, ...) when the task is a simple (dnsmasq) syntax check ++ if(strcmp(argv[i], "dnsmasq-test") == 0 || ++ strcmp(argv[i], "--test") == 0) ++ { ++ const char *arg[2]; ++ arg[0] = ""; ++ arg[1] = "--test"; ++ main_dnsmasq(2, arg); ++ ok = true; ++ } ++ ++ // If we find "--" we collect everything behind that for dnsmasq ++ if(strcmp(argv[i], "--") == 0) ++ { ++ // Remember that the rest is for dnsmasq ... ++ consume_for_dnsmasq = true; ++ ++ // ... and skip the current argument ("--") ++ continue; ++ } ++ ++ // If consume_for_dnsmasq is true, we collect all remaining options for ++ // dnsmasq ++ if(consume_for_dnsmasq) ++ { ++ argc_dnsmasq = argc - i + 2; ++ if(argv_dnsmasq != NULL) ++ free(argv_dnsmasq); ++ ++ argv_dnsmasq = calloc(argc_dnsmasq, sizeof(const char*)); ++ argv_dnsmasq[0] = ""; ++ ++ if(debug) ++ argv_dnsmasq[1] = "-d"; ++ else ++ argv_dnsmasq[1] = "-k"; ++ ++ if(debug) ++ { ++ printf("dnsmasq options: [0]: %s\n", argv_dnsmasq[0]); ++ printf("dnsmasq options: [1]: %s\n", argv_dnsmasq[1]); ++ } ++ ++ int j = 2; ++ while(i < argc) ++ { ++ argv_dnsmasq[j++] = strdup(argv[i++]); ++ if(debug) ++ printf("dnsmasq options: [%i]: %s\n", j-1, argv_dnsmasq[j-1]); ++ } ++ ++ // Return early: We have consumes all available command line arguments ++ return; ++ } ++ ++ // What follows beyond this point are FTL internal command line arguments ++ + if(strcmp(argv[i], "d") == 0 || + strcmp(argv[i], "debug") == 0) + { +@@ -97,35 +165,6 @@ + ok = true; + } + +- // Implement dnsmasq's test function +- if(strcmp(argv[i], "dnsmasq-test") == 0) +- { +- const char *arg[2]; +- arg[0] = ""; +- arg[1] = "--test"; +- main_dnsmasq(2, arg); +- ok = true; +- } +- +- // If we find "--" we collect everything behind that for dnsmasq +- if(strcmp(argv[i], "--") == 0) +- { +- int j; +- argc_dnsmasq = argc - i + 1; +- if(argv_dnsmasq != NULL) free(argv_dnsmasq); +- argv_dnsmasq = calloc(argc_dnsmasq + 2,sizeof(const char*)); +- argv_dnsmasq[0] = ""; +- if(debug) argv_dnsmasq[1] = "-d"; +- else argv_dnsmasq[1] = "-k"; +- +- for(j=2; j < argc_dnsmasq; j++) +- { +- argv_dnsmasq[j] = strdup(argv[i+j-1]); +- if(debug) logg("dnsmasq options: [%i]: %s",j,argv_dnsmasq[j]); +- } +- return; +- } +- + // List of implemented arguments + if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "help") == 0 || strcmp(argv[i], "--help") == 0) + { From 0c0316a44383997838246d99f34c63a13b78ea4d Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Wed, 17 Jun 2020 21:54:05 +0200 Subject: [PATCH 04/20] Work in progress... --- README.md | 6 +- README_fr.md | 6 +- actions.toml | 38 +++ check_process | 74 +++-- conf/FTL_3.src | 7 +- conf/FTL_last.src | 4 +- conf/admin_dashboard_last.src | 4 +- conf/app_last.src | 4 +- conf/dns-servers.conf | 10 + conf/dnsmasq_regenconf_hook | 64 ++-- conf/pihole-FTL.conf | 28 +- config_panel.toml | 6 + manifest.json | 188 +++++------ scripts/_common.sh | 293 +----------------- scripts/_variables | 11 + scripts/_ynh_add_fpm_config | 132 -------- scripts/actions/reset_default_app | 256 +++++++++++++++ scripts/actions/reset_default_config | 77 +++-- scripts/actions/reset_default_system | 64 ++++ scripts/backup | 19 +- scripts/change_url | 36 +-- scripts/config | 77 +++-- scripts/install | 93 +++--- scripts/remove | 14 +- scripts/restore | 93 ++++-- scripts/upgrade | 214 ++++++++----- sources/patches/.gitignore | 2 - .../patches/FTL_last-dns_replacement.patch | 131 -------- 28 files changed, 1000 insertions(+), 951 deletions(-) create mode 100644 conf/dns-servers.conf delete mode 100644 scripts/_ynh_add_fpm_config create mode 100755 scripts/actions/reset_default_app create mode 100755 scripts/actions/reset_default_system delete mode 100644 sources/patches/.gitignore delete mode 100644 sources/patches/FTL_last-dns_replacement.patch diff --git a/README.md b/README.md index ce6f798..d461fbb 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ If you don't have YunoHost, please see [here](https://yunohost.org/#/install) to ## Overview Network-wide ad blocking via your own Linux hardware -**Shipped version:** 3.3.1 +**Shipped version:** 3.3.1 or 5.0 ## Screenshots @@ -41,7 +41,7 @@ Use the admin panel of your Pi-hole to configure this app. You may also need to * x86-64b - [![](https://ci-apps.yunohost.org/ci/logs/pihole%20%28Apps%29.svg)](https://ci-apps.yunohost.org/ci/apps/pihole/) * ARMv8-A - [![](https://ci-apps-arm.yunohost.org/ci/logs/pihole%20%28Apps%29.svg)](https://ci-apps-arm.yunohost.org/ci/apps/pihole/) -* Jessie x86-64b - [![](https://ci-stretch.nohost.me/ci/logs/pihole%20%28Apps%29.svg)](https://ci-stretch.nohost.me/ci/apps/pihole/) +* Buster x86-64b - [![](https://ci-buster.nohost.me/ci/logs/pihole%20%28Apps%29.svg)](https://ci-buster.nohost.me/ci/apps/pihole/) ## Limitations @@ -66,7 +66,7 @@ Please do your pull request to the [testing branch](https://github.com/YunoHost- To try the testing branch, please do the following: ``` -sudo yunohost app install https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --debug +sudo yunohost app install https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --force --debug or sudo yunohost app upgrade pihole -u https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --debug ``` diff --git a/README_fr.md b/README_fr.md index f7838b9..636f57f 100644 --- a/README_fr.md +++ b/README_fr.md @@ -11,7 +11,7 @@ Si vous n'avez pas YunoHost, merci de regarder [ici](https://yunohost.org/#/inst ## Résumé Blocage des publicités sur l'ensemble du réseau via votre propre matériel Linux -**Version embarquée:** 3.3.1 +**Version embarquée:** 3.3.1 ou 5.0 ## Captures d'écran @@ -42,7 +42,7 @@ Utiliser le panneau d'administration de votre Pi-hole pour configurer cette appl * x86-64b - [![](https://ci-apps.yunohost.org/ci/logs/pihole%20%28Apps%29.svg)](https://ci-apps.yunohost.org/ci/apps/pihole/) * ARMv8-A - [![](https://ci-apps-arm.yunohost.org/ci/logs/pihole%20%28Apps%29.svg)](https://ci-apps-arm.yunohost.org/ci/apps/pihole/) -* Jessie x86-64b - [![](https://ci-stretch.nohost.me/ci/logs/pihole%20%28Apps%29.svg)](https://ci-stretch.nohost.me/ci/apps/pihole/) +* Buster x86-64b - [![](https://ci-buster.nohost.me/ci/logs/pihole%20%28Apps%29.svg)](https://ci-buster.nohost.me/ci/apps/pihole/) ## Limitations @@ -67,7 +67,7 @@ Merci de faire vos pull request sur la [branche testing](https://github.com/Yuno Pour tester la branche testing, merci de procéder ainsi. ``` -sudo yunohost app install https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --debug +sudo yunohost app install https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --force --debug ou sudo yunohost app upgrade pihole -u https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --debug ``` diff --git a/actions.toml b/actions.toml index 5aff36a..fc7f8aa 100644 --- a/actions.toml +++ b/actions.toml @@ -15,3 +15,41 @@ command = "/bin/bash scripts/actions/reset_default_config \"pihole-FTL.conf\"" # accepted_return_codes = [0, 1, 2, 3] # optional accepted_return_codes = [0] description = "Reset the config file pihole-FTL.conf." + +[reset_default_dnsmasq] +name = "Reset the config file and restore a default one." +command = "/bin/bash scripts/actions/reset_default_config \"01-pihole.conf\"" +# user = "root" # optional +# cwd = "/" # optional +# accepted_return_codes = [0, 1, 2, 3] # optional +accepted_return_codes = [0] +description = "Reset the config file dnsmasq.d/01-pihole.conf." + + +[reset_default_nginx] +name = "Reset the nginx config for this app." +command = "/bin/bash scripts/actions/reset_default_system nginx" +# user = "root" # optional +# cwd = "/" # optional +# accepted_return_codes = [0, 1, 2, 3] # optional +accepted_return_codes = [0] +description = "Reset the nginx config for this app." + +[reset_default_phpfpm] +name = "Reset the php-fpm config for this app." +command = "/bin/bash scripts/actions/reset_default_system phpfpm" +# user = "root" # optional +# cwd = "/" # optional +# accepted_return_codes = [0, 1, 2, 3] # optional +accepted_return_codes = [0] +description = "Reset the php-fpm config for this app." + + +[reset_default_app] +name = "Reset the app with a default configuration." +command = "/bin/bash scripts/actions/reset_default_app" +# user = "root" # optional +# cwd = "/" # optional +# accepted_return_codes = [0, 1, 2, 3] # optional +accepted_return_codes = [0] +description = "Reset the app to its default configuration to try to fix potential issues.
This action won't remove any data added to the app.
However, if you have modified any configuration, it will be overwritten." diff --git a/check_process b/check_process index b255fb0..96ed247 100644 --- a/check_process +++ b/check_process @@ -1,28 +1,56 @@ -;; Test complet - ; Manifest - domain="domain.tld" (DOMAIN) - path="/path" (PATH) - admin="john" (USER) - query_logging="1" - ; Checks - pkg_linter=1 - setup_sub_dir=1 - setup_root=1 - setup_nourl=0 - setup_private=1 - setup_public=0 - upgrade=1 - upgrade=1 from_commit=d79ec131b3038ff4695c3317b5d3ee4eda9c8932 - backup_restore=1 - multi_instance=0 - port_already_use=1 (4711) - change_url=1 +;; Test version last version + ; Manifest + domain="domain.tld" (DOMAIN) + path="/path" (PATH) + admin="john" (USER) + query_logging=1 + enable_dhcp=0 + pihole_version="Last available" + ; Config_panel + main.overwrite_files.overwrite_setupvars=0|1 + main.overwrite_files.overwrite_ftl=0|1 + main.overwrite_files.overwrite_nginx=0|1 + main.overwrite_files.overwrite_phpfpm=0|1 + main.global_config.email_type=0|1 + main.php_fpm_config.footprint=low|medium|high + main.php_fpm_config.free_footprint=20 + main.php_fpm_config.usage=low|medium|high + main.php_fpm_config.force_max_children=20|0 + ; Checks + pkg_linter=1 + setup_sub_dir=1 + setup_root=1 + setup_nourl=0 + setup_private=1 + setup_public=0 + upgrade=1 + backup_restore=1 + multi_instance=0 + port_already_use=1 (4711) + change_url=1 + actions=1 + config_panel=1 +;; Test version 3 + ; Manifest + domain="domain.tld" (DOMAIN) + path="/path" (PATH) + admin="john" (USER) + query_logging=1 + enable_dhcp=0 + pihole_version="Last 3.X" + ; Checks + setup_sub_dir=1 + setup_root=0 + upgrade=1 + upgrade=1 from_commit=d79ec131b3038ff4695c3317b5d3ee4eda9c8932 + backup_restore=1 + actions=1 ;;; Levels - Level 5=auto + Level 5=auto ;;; Options Email= Notification=change ;;; Upgrade options - ; commit=d79ec131b3038ff4695c3317b5d3ee4eda9c8932 - name= Stretch fix - manifest_arg=domain=DOMAIN&path=PATH&admin=USER&query_logging=1& + ; commit=d79ec131b3038ff4695c3317b5d3ee4eda9c8932 + name= Stretch fix + manifest_arg=domain=DOMAIN&path=PATH&admin=USER&query_logging=1& diff --git a/conf/FTL_3.src b/conf/FTL_3.src index 31d1e65..c08c993 100644 --- a/conf/FTL_3.src +++ b/conf/FTL_3.src @@ -1,9 +1,6 @@ -SOURCE_URL=https://github.com/pi-hole/FTL/archive/v2.13.2.tar.gz -SOURCE_SUM=07383d2b3de1ef31526b090603e783b3 +SOURCE_URL=https://github.com/pi-hole/FTL/archive/v3.0.tar.gz +SOURCE_SUM=45fd33e4498b2ab9403d96e1251abb8c SOURCE_SUM_PRG=md5sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true SOURCE_FILENAME= - -# Be carrefull, the version 3.0 isn't compatible with the version of dnsmasq available on Jessie. -# So, we need to stay stick on the version 2.13.2. diff --git a/conf/FTL_last.src b/conf/FTL_last.src index 60342ce..f6e3f41 100644 --- a/conf/FTL_last.src +++ b/conf/FTL_last.src @@ -1,5 +1,5 @@ -SOURCE_URL=https://github.com/pi-hole/FTL/archive/v4.3.1.tar.gz -SOURCE_SUM=1c0df5fa42e7f7b89c7e704fdc1b5154 +SOURCE_URL=https://github.com/pi-hole/FTL/archive/v5.0.tar.gz +SOURCE_SUM=a405fee9a924324eefe6bfb832180c3d SOURCE_SUM_PRG=md5sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true diff --git a/conf/admin_dashboard_last.src b/conf/admin_dashboard_last.src index ee04744..25b95ff 100644 --- a/conf/admin_dashboard_last.src +++ b/conf/admin_dashboard_last.src @@ -1,5 +1,5 @@ -SOURCE_URL=https://github.com/pi-hole/AdminLTE/archive/v4.3.3.tar.gz -SOURCE_SUM=3f9da0e1f9134393758b7a1425ca66f6 +SOURCE_URL=https://github.com/pi-hole/AdminLTE/archive/v5.0.tar.gz +SOURCE_SUM=9402041b365e78a02a95942bdd3c3c05 SOURCE_SUM_PRG=md5sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true diff --git a/conf/app_last.src b/conf/app_last.src index 3e7c2a8..4836f9a 100644 --- a/conf/app_last.src +++ b/conf/app_last.src @@ -1,5 +1,5 @@ -SOURCE_URL=https://github.com/pi-hole/pi-hole/archive/v4.4.tar.gz -SOURCE_SUM=970013bf8e273b868dd184ac2ffb1348 +SOURCE_URL=https://github.com/pi-hole/pi-hole/archive/v5.0.tar.gz +SOURCE_SUM=0f19aeefad3063c44f421de1ad21b233 SOURCE_SUM_PRG=md5sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true diff --git a/conf/dns-servers.conf b/conf/dns-servers.conf new file mode 100644 index 0000000..cbe97e3 --- /dev/null +++ b/conf/dns-servers.conf @@ -0,0 +1,10 @@ +(FR) FDN;80.67.169.12;80.67.169.40;2001:910:800::12;2001:910:800::40 +(FR) LDN;80.67.188.188;2001:913::8 +(FR) ARN;89.234.141.66;2a00:5881:8100:1000::3 +(FR) Aquilenet;185.233.100.100;185.233.100.101;2a0c:e300::100;2a0c:e300::101 +(FR) gozmail / grifon;80.67.190.200;80.67.190.200;2a00:5884:8218::1;2a00:5884:8218::1 +(DE) FoeBud / Digital Courage;85.214.20.141;85.214.20.141 +(DE) CCC Berlin;195.160.173.53;195.160.173.53 +(DE) AS250;194.150.168.168;194.150.168.168;2001:4ce8::53;2001:4ce8::53 +(DE) Ideal-Hosting;84.200.69.80;84.200.70.40;2001:1608:10:25::1c04:b12f;2001:1608:10:25::9249:d69b +(DK) censurfridns;91.239.100.100;89.233.43.71;2001:67c:28a4::;2a01:3a0:53:53:: diff --git a/conf/dnsmasq_regenconf_hook b/conf/dnsmasq_regenconf_hook index 0212f09..0e4c2ef 100755 --- a/conf/dnsmasq_regenconf_hook +++ b/conf/dnsmasq_regenconf_hook @@ -7,47 +7,47 @@ pending_conf=$4 # Path of the pending conf file temp_dir=/tmp/pi-hole.bck do_pre_regen() { - if [ $dryrun -eq 0 ] - then - # Créer une sauvegarde des config dnsmasq de pi-hole. Que la regen-conf va sauvagement supprimer - mkdir $temp_dir - cp -a "/etc/dnsmasq.d/01-pihole.conf" "$temp_dir" - test -e "/etc/dnsmasq.d/02-pihole-dhcp.conf" && cp -a "/etc/dnsmasq.d/02-pihole-dhcp.conf" "$temp_dir" - test -e "/etc/dnsmasq.d/03-pihole-wildcard.conf" && cp -a "/etc/dnsmasq.d/03-pihole-wildcard.conf" "$temp_dir" + if [ $dryrun -eq 0 ] + then + # Créer une sauvegarde des config dnsmasq de pi-hole. Que la regen-conf va sauvagement supprimer + mkdir $temp_dir + cp -a "/etc/dnsmasq.d/01-pihole.conf" "$temp_dir" + test -e "/etc/dnsmasq.d/02-pihole-dhcp.conf" && cp -a "/etc/dnsmasq.d/02-pihole-dhcp.conf" "$temp_dir" + test -e "/etc/dnsmasq.d/03-pihole-wildcard.conf" && cp -a "/etc/dnsmasq.d/03-pihole-wildcard.conf" "$temp_dir" - # Décommente le cache-size de la config par défaut - sed --in-place "s/^#pihole# cache-size=/cache-size=/g" /etc/dnsmasq.conf - # Et commente celui de pi-hole - sed --in-place "s/^cache-size=/#cache-size=/g" /etc/dnsmasq.d/01-pihole.conf - fi + # Décommente le cache-size de la config par défaut + sed --in-place "s/^#pihole# cache-size=/cache-size=/g" /etc/dnsmasq.conf + # Et commente celui de pi-hole + sed --in-place "s/^cache-size=/#cache-size=/g" /etc/dnsmasq.d/01-pihole.conf + fi } do_post_regen() { - # Restaure la config dnsmasq de pi-hole - cp -a "$temp_dir/01-pihole.conf" "/etc/dnsmasq.d/" - test -e "$temp_dir/02-pihole-dhcp.conf" && cp -a "$temp_dir/02-pihole-dhcp.conf" "/etc/dnsmasq.d/" - test -e "$temp_dir/03-pihole-wildcard.conf" && cp -a "$temp_dir/03-pihole-wildcard.conf" "/etc/dnsmasq.d/" - # Supprime le dossier temporaire - test -n $temp_dir && rm -r $temp_dir + # Restaure la config dnsmasq de pi-hole + cp -a "$temp_dir/01-pihole.conf" "/etc/dnsmasq.d/" + test -e "$temp_dir/02-pihole-dhcp.conf" && cp -a "$temp_dir/02-pihole-dhcp.conf" "/etc/dnsmasq.d/" + test -e "$temp_dir/03-pihole-wildcard.conf" && cp -a "$temp_dir/03-pihole-wildcard.conf" "/etc/dnsmasq.d/" + # Supprime le dossier temporaire + test -n $temp_dir && rm -r $temp_dir - # Commente le cache-size de la config par défaut - sed --in-place "s/^cache-size=/#pihole# cache-size=/g" /etc/dnsmasq.conf + # Commente le cache-size de la config par défaut + sed --in-place "s/^cache-size=/#pihole# cache-size=/g" /etc/dnsmasq.conf - # Reload dnsmasq - systemctl reload dnsmasq + # Reload dnsmasq + systemctl reload dnsmasq } case "$1" in - pre) - do_pre_regen - ;; - post) - do_post_regen - ;; - *) - echo "Hook called with unknown argument \`$1'" >&2 - exit 1 - ;; + pre) + do_pre_regen + ;; + post) + do_post_regen + ;; + *) + echo "Hook called with unknown argument \`$1'" >&2 + exit 1 + ;; esac exit 0 diff --git a/conf/pihole-FTL.conf b/conf/pihole-FTL.conf index b9b8dca..869f50c 100644 --- a/conf/pihole-FTL.conf +++ b/conf/pihole-FTL.conf @@ -1,31 +1,31 @@ -# Listen only for local socket connections or permit all connections -# localonly|all +; Listen only for local socket connections or permit all connections +; localonly|all SOCKET_LISTENING=localonly -# Display all queries? Set to no to hide query display -# yes|no +; Display all queries? Set to no to hide query display +; yes|no QUERY_DISPLAY=yes -# Allow FTL to analyze AAAA queries from pihole.log? -# yes|no +; Allow FTL to analyze AAAA queries from pihole.log? +; yes|no AAAA_QUERY_ANALYSIS=yes -# How long should queries be stored in the database? Setting this to 0 disables the database altogether +; How long should queries be stored in the database? Setting this to 0 disables the database altogether MAXDBDAYS=365 -# Should FTL try to resolve IPv6 addresses to host names? -# yes|no +; Should FTL try to resolve IPv6 addresses to host names? +; yes|no RESOLVE_IPV6=yes -# Should FTL try to resolve IPv4 addresses to host names? -# yes|no +; Should FTL try to resolve IPv4 addresses to host names? +; yes|no RESOLVE_IPV4=yes -# How often do we store queries in FTL's database [minutes]? +; How often do we store queries in FTL's database [minutes]? DBINTERVAL=1.0 -# Specify path and filename of FTL's SQLite long-term database. Setting this to DBFILE= disables the database altogether +; Specify path and filename of FTL's SQLite long-term database. Setting this to DBFILE= disables the database altogether DBFILE=/etc/pihole/pihole-FTL.db -# Up to how many hours of queries should be imported from the database and logs? Maximum is 744 (31 days) +; Up to how many hours of queries should be imported from the database and logs? Maximum is 744 (31 days) MAXLOGAGE=24.0 diff --git a/config_panel.toml b/config_panel.toml index 338ee26..9721f5e 100644 --- a/config_panel.toml +++ b/config_panel.toml @@ -62,3 +62,9 @@ name = "PiHole configuration" choices = ["low", "medium", "high"] default = "low" help = "low: Personal usage, behind the sso. No RAM footprint when not used, but the impact on the processor can be high if many users are using the service.
medium: Low usage, few people or/and publicly accessible. Low RAM footprint, medium processor footprint when used.
high: High usage, frequently visited website. High RAM footprint, but lower on processor usage and quickly responding." + + [main.php_fpm_config.force_max_children] + ask = "Force the value of pm.max_children ?" + type = "number" + default = "0" + help = "Do not change this value unless you're sure about what you're doing !
pm.max_children is automatically defined by this formula: $max_ram / 2 / $footprint
You can force that value, and ignore the formula by changing the value here.
To reset to the default value, set to 0." diff --git a/manifest.json b/manifest.json index 7a603d8..b561183 100644 --- a/manifest.json +++ b/manifest.json @@ -1,96 +1,96 @@ { - "name": "Pi-hole", - "id": "pihole", - "packaging_format": 1, - "description": { - "en": "Network-wide ad blocking via your own DNS server.", - "fr": "Filtrage publicitaire sur l'ensemble du réseau via votre propre serveur DNS." - }, - "version": "3.3.1~ynh6", - "url": "https://pi-hole.net/", - "license": "EUPL-1.2", - "maintainer": { - "name": "Maniack Crudelis", - "email": "maniackc_dev@crudelis.fr" - }, - "requirements": { - "yunohost": ">= 3.6" - }, - "multi_instance": false, - "services": [ - "nginx", - "php7.0-fpm" - ], - "arguments": { - "install" : [ - { - "name": "domain", - "type": "domain", - "ask": { - "en": "Choose a domain for the admin interface of Pi-hole", - "fr": "Choisissez un domaine pour l'interface admin de Pi-hole" - }, - "example": "domain.org" - }, - { - "name": "path", - "type": "path", - "ask": { - "en": "Choose a path for the admin interface of Pi-hole", - "fr": "Choisissez un chemin pour l'interface admin de Pi-hole" - }, - "example": "/pihole", - "default": "/pihole" - }, - { - "name": "admin", - "type": "user", - "ask": { - "en": "Choose the Pi-hole administrator (must be an existing YunoHost user)", - "fr": "Administrateur de Pi-hole (doit être un utilisateur YunoHost existant)" - }, - "example": "john" - }, - { - "name": "query_logging", - "type": "boolean", - "ask": { - "en": "Do you want to log queries ?", - "fr": "Voulez-vous enregistrer les requêtes dns ?" - }, - "help": { - "en": "Keeping this option deactivate will render graphs on the admin page useless. But will respect the privacy of the other users.", - "fr": "Garder cette option désactivée rendra les graphiques sur la page d'administration inutiles. Mais respectera la vie privée des autres utilisateurs." - }, - "default": false - }, - { - "name": "enable_dhcp", - "type": "boolean", - "ask": { - "en": "Do you want to set Pi-hole as your DHCP server ?", - "fr": "Voulez-vous utiliser Pi-hole an tant que serveur DHCP ?" - }, - "help": { - "en": "If you want to do that, you really have to read this before !", - "fr": "Si vous voulez faire ça, vous devez vraiment lire cela avant !" - }, - "default": false - }, - { - "name": "pihole_version", - "type": "string", - "ask": { - "en": "Which version of Pi-Hole do you want to install ?", - "fr": "Quelle version de Pi-Hole voulez-vous installer ?" - }, - "help": { - "en": "The last 3.X version is the last version available with the Debian version of dnsmasq.", - "fr": "The last available version will replace the Debian version of dnsmasq by FTLDNS.
See the readme for more information." - }, - "choices" : ["Last 3.X","Last available"], - "default": "Last 3.X" - } - ] - } + "name": "Pi-hole", + "id": "pihole", + "packaging_format": 1, + "description": { + "en": "Network-wide ad blocking via your own DNS server.", + "fr": "Filtrage publicitaire sur l'ensemble du réseau via votre propre serveur DNS." + }, + "version": "5.0~ynh1", + "url": "https://pi-hole.net/", + "license": "EUPL-1.2", + "maintainer": { + "name": "Maniack Crudelis", + "email": "maniackc_dev@crudelis.fr" + }, + "requirements": { + "yunohost": ">= 3.8" + }, + "multi_instance": false, + "services": [ + "nginx", + "php7.0-fpm" + ], + "arguments": { + "install" : [ + { + "name": "domain", + "type": "domain", + "ask": { + "en": "Choose a domain for the admin interface of Pi-hole", + "fr": "Choisissez un domaine pour l'interface admin de Pi-hole" + }, + "example": "domain.org" + }, + { + "name": "path", + "type": "path", + "ask": { + "en": "Choose a path for the admin interface of Pi-hole", + "fr": "Choisissez un chemin pour l'interface admin de Pi-hole" + }, + "example": "/pihole", + "default": "/pihole" + }, + { + "name": "admin", + "type": "user", + "ask": { + "en": "Choose the Pi-hole administrator (must be an existing YunoHost user)", + "fr": "Administrateur de Pi-hole (doit être un utilisateur YunoHost existant)" + }, + "example": "john" + }, + { + "name": "query_logging", + "type": "boolean", + "ask": { + "en": "Do you want to log queries ?", + "fr": "Voulez-vous enregistrer les requêtes dns ?" + }, + "help": { + "en": "Keeping this option deactivate will render graphs on the admin page useless. But will respect the privacy of the other users.", + "fr": "Garder cette option désactivée rendra les graphiques sur la page d'administration inutiles. Mais respectera la vie privée des autres utilisateurs." + }, + "default": false + }, + { + "name": "enable_dhcp", + "type": "boolean", + "ask": { + "en": "Do you want to set Pi-hole as your DHCP server ?", + "fr": "Voulez-vous utiliser Pi-hole an tant que serveur DHCP ?" + }, + "help": { + "en": "If you want to do that, you really have to read this before !", + "fr": "Si vous voulez faire ça, vous devez vraiment lire cela avant !" + }, + "default": false + }, + { + "name": "pihole_version", + "type": "string", + "ask": { + "en": "Which version of Pi-Hole do you want to install ?", + "fr": "Quelle version de Pi-Hole voulez-vous installer ?" + }, + "help": { + "en": "The last 3.X version is the last version available with the Debian version of dnsmasq.", + "fr": "The last available version will replace the Debian version of dnsmasq by FTLDNS.
See the readme for more information." + }, + "choices": ["Last 3.X","Last available"], + "default": "Last 3.X" + } + ] + } } diff --git a/scripts/_common.sh b/scripts/_common.sh index 3770c0f..5c8cf50 100755 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -1,44 +1,5 @@ #!/bin/bash -#================================================= -# PERSONAL HELPERS -#================================================= - -#================================================= -# BACKUP -#================================================= - -HUMAN_SIZE () { # Transforme une taille en Ko en une taille lisible pour un humain - human=$(numfmt --to=iec --from-unit=1K $1) - echo $human -} - -CHECK_SIZE () { # Vérifie avant chaque backup que l'espace est suffisant - file_to_analyse=$1 - backup_size=$(du --summarize "$file_to_analyse" | cut -f1) - free_space=$(df --output=avail "/home/yunohost.backup" | sed 1d) - - if [ $free_space -le $backup_size ] - then - ynh_print_err "Espace insuffisant pour sauvegarder $file_to_analyse." - ynh_print_err "Espace disponible: $(HUMAN_SIZE $free_space)" - ynh_die "Espace nécessaire: $(HUMAN_SIZE $backup_size)" - fi -} - -#================================================= -# PACKAGE CHECK BYPASSING... -#================================================= - -IS_PACKAGE_CHECK () { - if [ ${PACKAGE_CHECK_EXEC:-0} -eq 1 ] - then - return 0 - else - return 1 - fi -} - #================================================= # FUTUR OFFICIAL HELPERS #================================================= @@ -265,30 +226,6 @@ __PRE_TAG1__$(yunohost tools diagnosis | grep -B 100 "services:" | sed '/service #================================================= -ynh_debian_release () { - lsb_release --codename --short -} - -is_stretch () { - if [ "$(ynh_debian_release)" == "stretch" ] - then - return 0 - else - return 1 - fi -} - -is_jessie () { - if [ "$(ynh_debian_release)" == "jessie" ] - then - return 0 - else - return 1 - fi -} - -#================================================= - ynh_maintenance_mode_ON () { # Load value of $path_url and $domain from the config if their not set if [ -z $path_url ]; then @@ -508,237 +445,9 @@ ynh_app_changelog () { #================================================= -# Check the amount of available RAM -# -# usage: ynh_check_ram [--required=RAM required in Mb] [--no_swap|--only_swap] [--free_ram] -# | arg: -r, --required= - Amount of RAM required in Mb. The helper will return 0 is there's enough RAM, or 1 otherwise. -# If --required isn't set, the helper will print the amount of RAM, in Mb. -# | arg: -s, --no_swap - Ignore swap -# | arg: -o, --only_swap - Ignore real RAM, consider only swap. -# | arg: -f, --free_ram - Count only free RAM, not the total amount of RAM available. -ynh_check_ram () { - # Declare an array to define the options of this helper. - declare -Ar args_array=( [r]=required= [s]=no_swap [o]=only_swap [f]=free_ram ) - local required - local no_swap - local only_swap - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - required=${required:-} - no_swap=${no_swap:-0} - only_swap=${only_swap:-0} - - local total_ram=$(vmstat --stats --unit M | grep "total memory" | awk '{print $1}') - local total_swap=$(vmstat --stats --unit M | grep "total swap" | awk '{print $1}') - local total_ram_swap=$(( total_ram + total_swap )) - - local free_ram=$(vmstat --stats --unit M | grep "free memory" | awk '{print $1}') - local free_swap=$(vmstat --stats --unit M | grep "free swap" | awk '{print $1}') - local free_ram_swap=$(( free_ram + free_swap )) - - # Use the total amount of ram - local ram=$total_ram_swap - if [ $free_ram -eq 1 ] - then - # Use the total amount of free ram - ram=$free_ram_swap - if [ $no_swap -eq 1 ] - then - # Use only the amount of free ram - ram=$free_ram - elif [ $only_swap -eq 1 ] - then - # Use only the amount of free swap - ram=$free_swap - fi - else - if [ $no_swap -eq 1 ] - then - # Use only the amount of free ram - ram=$total_ram - elif [ $only_swap -eq 1 ] - then - # Use only the amount of free swap - ram=$total_swap - fi - fi - - if [ -n "$required" ] - then - # Return 1 if the amount of ram isn't enough. - if [ $ram -lt $required ] - then - return 1 - else - return 0 - fi - - # If no RAM is required, return the amount of available ram. - else - echo $ram - fi -} - -#================================================= - -# Define the values to configure php-fpm -# -# usage: ynh_get_scalable_phpfpm --usage=usage --footprint=footprint [--print] -# | arg: -f, --footprint - Memory footprint of the service (low/medium/high). -# low - Less than 20Mb of ram by pool. -# medium - Between 20Mb and 40Mb of ram by pool. -# high - More than 40Mb of ram by pool. -# Or specify exactly the footprint, the load of the service as Mb by pool instead of having a standard value. -# To have this value, use the following command and stress the service. -# watch -n0.5 ps -o user,cmd,%cpu,rss -u APP -# -# | arg: -u, --usage - Expected usage of the service (low/medium/high). -# low - Personal usage, behind the sso. -# medium - Low usage, few people or/and publicly accessible. -# high - High usage, frequently visited website. -# -# | arg: -p, --print - Print the result -# -# -# -# The footprint of the service will be used to defined the maximum footprint we can allow, which is half the maximum RAM. -# So it will be used to defined 'pm.max_children' -# A lower value for the footprint will allow more children for 'pm.max_children'. And so for -# 'pm.start_servers', 'pm.min_spare_servers' and 'pm.max_spare_servers' which are defined from the -# value of 'pm.max_children' -# NOTE: 'pm.max_children' can't exceed 4 times the number of processor's cores. -# -# The usage value will defined the way php will handle the children for the pool. -# A value set as 'low' will set the process manager to 'ondemand'. Children will start only if the -# service is used, otherwise no child will stay alive. This config gives the lower footprint when the -# service is idle. But will use more proc since it has to start a child as soon it's used. -# Set as 'medium', the process manager will be at dynamic. If the service is idle, a number of children -# equal to pm.min_spare_servers will stay alive. So the service can be quick to answer to any request. -# The number of children can grow if needed. The footprint can stay low if the service is idle, but -# not null. The impact on the proc is a little bit less than 'ondemand' as there's always a few -# children already available. -# Set as 'high', the process manager will be set at 'static'. There will be always as many children as -# 'pm.max_children', the footprint is important (but will be set as maximum a quarter of the maximum -# RAM) but the impact on the proc is lower. The service will be quick to answer as there's always many -# children ready to answer. -ynh_get_scalable_phpfpm () { - local legacy_args=ufp - # Declare an array to define the options of this helper. - declare -Ar args_array=( [u]=usage= [f]=footprint= [p]=print ) - local usage - local footprint - local print - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - # Set all characters as lowercase - footprint=${footprint,,} - usage=${usage,,} - print=${print:-0} - - if [ "$footprint" = "low" ] - then - footprint=20 - elif [ "$footprint" = "medium" ] - then - footprint=35 - elif [ "$footprint" = "high" ] - then - footprint=50 - fi - - # Define the way the process manager handle child processes. - if [ "$usage" = "low" ] - then - php_pm=ondemand - elif [ "$usage" = "medium" ] - then - php_pm=dynamic - elif [ "$usage" = "high" ] - then - php_pm=static - else - ynh_die --message="Does not recognize '$usage' as an usage value." - fi - - # Get the total of RAM available, except swap. - local max_ram=$(ynh_check_ram --no_swap) - - less0() { - # Do not allow value below 1 - if [ $1 -le 0 ] - then - echo 1 - else - echo $1 - fi - } - - # Define pm.max_children - # The value of pm.max_children is the total amount of ram divide by 2 and divide again by the footprint of a pool for this app. - # So if php-fpm start the maximum of children, it won't exceed half of the ram. - php_max_children=$(( $max_ram / 2 / $footprint )) - # If process manager is set as static, use half less children. - # Used as static, there's always as many children as the value of pm.max_children - if [ "$php_pm" = "static" ] - then - php_max_children=$(( $php_max_children / 2 )) - fi - php_max_children=$(less0 $php_max_children) - - # To not overload the proc, limit the number of children to 4 times the number of cores. - local core_number=$(nproc) - local max_proc=$(( $core_number * 4 )) - if [ $php_max_children -gt $max_proc ] - then - php_max_children=$max_proc - fi - - if [ "$php_pm" = "dynamic" ] - then - # Define pm.start_servers, pm.min_spare_servers and pm.max_spare_servers for a dynamic process manager - php_min_spare_servers=$(( $php_max_children / 8 )) - php_min_spare_servers=$(less0 $php_min_spare_servers) - - php_max_spare_servers=$(( $php_max_children / 2 )) - php_max_spare_servers=$(less0 $php_max_spare_servers) - - php_start_servers=$(( $php_min_spare_servers + ( $php_max_spare_servers - $php_min_spare_servers ) /2 )) - php_start_servers=$(less0 $php_start_servers) - else - php_min_spare_servers=0 - php_max_spare_servers=0 - php_start_servers=0 - fi - - if [ $print -eq 1 ] - then - ynh_debug --message="Footprint=${footprint}Mb by pool." - ynh_debug --message="Process manager=$php_pm" - ynh_debug --message="Max RAM=${max_ram}Mb" - if [ "$php_pm" != "static" ]; then - ynh_debug --message="\nMax estimated footprint=$(( $php_max_children * $footprint ))" - ynh_debug --message="Min estimated footprint=$(( $php_min_spare_servers * $footprint ))" - fi - if [ "$php_pm" = "dynamic" ]; then - ynh_debug --message="Estimated average footprint=$(( $php_max_spare_servers * $footprint ))" - elif [ "$php_pm" = "static" ]; then - ynh_debug --message="Estimated footprint=$(( $php_max_children * $footprint ))" - fi - ynh_debug --message="\nRaw php-fpm values:" - ynh_debug --message="pm.max_children = $php_max_children" - if [ "$php_pm" = "dynamic" ]; then - ynh_debug --message="pm.start_servers = $php_start_servers" - ynh_debug --message="pm.min_spare_servers = $php_min_spare_servers" - ynh_debug --message="pm.max_spare_servers = $php_max_spare_servers" - fi - fi -} - -#================================================= - # Execute a command as another user # usage: exec_as USER COMMAND [ARG ...] -exec_as() { +ynh_exec_as() { local USER=$1 shift 1 diff --git a/scripts/_variables b/scripts/_variables index 02834a9..331ded1 100644 --- a/scripts/_variables +++ b/scripts/_variables @@ -2,3 +2,14 @@ # Dependencies app_depencencies="sqlite idn2 php7.0-sqlite3 nettle-dev libcap2-bin" + +if [ "$YNH_APP_ARG_PIHOLE_VERSION" == "Last 3.X" ] +then + pihole_core_version=3.3.1 + dashboard_version=3.3 + FTL_version=3.0 +else + pihole_core_version=5.0 + dashboard_version=5.0 + FTL_version=5.0 +fi diff --git a/scripts/_ynh_add_fpm_config b/scripts/_ynh_add_fpm_config deleted file mode 100644 index 8d36834..0000000 --- a/scripts/_ynh_add_fpm_config +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash - -# Create a dedicated php-fpm config -# -# usage 1: ynh_add_fpm_config [--phpversion=7.X] [--use_template] -# | arg: -v, --phpversion - Version of php to use. -# | arg: -t, --use_template - Use this helper in template mode. -# -# ----------------------------------------------------------------------------- -# -# usage 2: ynh_add_fpm_config [--phpversion=7.X] --usage=usage --footprint=footprint -# | arg: -v, --phpversion - Version of php to use.# -# | arg: -f, --footprint - Memory footprint of the service (low/medium/high). -# low - Less than 20Mb of ram by pool. -# medium - Between 20Mb and 40Mb of ram by pool. -# high - More than 40Mb of ram by pool. -# Or specify exactly the footprint, the load of the service as Mb by pool instead of having a standard value. -# To have this value, use the following command and stress the service. -# watch -n0.5 ps -o user,cmd,%cpu,rss -u APP -# -# | arg: -u, --usage - Expected usage of the service (low/medium/high). -# low - Personal usage, behind the sso. -# medium - Low usage, few people or/and publicly accessible. -# high - High usage, frequently visited website. -# -# Requires YunoHost version 2.7.2 or higher. -ynh_add_fpm_config () { - # Declare an array to define the options of this helper. - local legacy_args=vtuf - declare -Ar args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= ) - local phpversion - local use_template - local usage - local footprint - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - # The default behaviour is to use the template. - use_template="${use_template:-1}" - usage="${usage:-}" - footprint="${footprint:-}" - if [ -n "$usage" ] || [ -n "$footprint" ]; then - use_template=0 - fi - - # Configure PHP-FPM 7.0 by default - phpversion="${phpversion:-7.0}" - - local fpm_config_dir="/etc/php/$phpversion/fpm" - local fpm_service="php${phpversion}-fpm" - # Configure PHP-FPM 5 on Debian Jessie - if [ "$(ynh_get_debian_release)" == "jessie" ]; then - fpm_config_dir="/etc/php5/fpm" - fpm_service="php5-fpm" - fi - ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir" - ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" - finalphpconf="$fpm_config_dir/pool.d/$app.conf" - ynh_backup_if_checksum_is_different --file="$finalphpconf" - - if [ $use_template -eq 1 ] - then - # Usage 1, use the template in ../conf/php-fpm.conf - sudo cp ../conf/php-fpm.conf "$finalphpconf" - ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf" - ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf" - ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf" - ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf" - - else - # Store settings - ynh_app_setting_set --app=$app --key=fpm_footprint --value=$footprint - ynh_app_setting_set --app=$app --key=fpm_usage --value=$usage - - # Usage 2, generate a php-fpm config file with ynh_get_scalable_phpfpm - ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint - - # Copy the default file - sudo cp "$fpm_config_dir/pool.d/www.conf" "$finalphpconf" - - # Replace standard variables into the default file - ynh_replace_string --match_string="^\[www\]" --replace_string="[$app]" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*listen = .*" --replace_string="listen = /var/run/php/php7.0-fpm-$app.sock" --target_file="$finalphpconf" - ynh_replace_string --match_string="^user = .*" --replace_string="user = $app" --target_file="$finalphpconf" - ynh_replace_string --match_string="^group = .*" --replace_string="group = $app" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*chdir = .*" --replace_string="chdir = $final_path" --target_file="$finalphpconf" - - # Configure fpm children - ynh_replace_string --match_string=".*pm = .*" --replace_string="pm = $php_pm" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*pm.max_children = .*" --replace_string="pm.max_children = $php_max_children" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*pm.max_requests = .*" --replace_string="pm.max_requests = 500" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*request_terminate_timeout = .*" --replace_string="request_terminate_timeout = 1d" --target_file="$finalphpconf" - if [ "$php_pm" = "dynamic" ] - then - ynh_replace_string --match_string=".*pm.start_servers = .*" --replace_string="pm.start_servers = $php_start_servers" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*pm.min_spare_servers = .*" --replace_string="pm.min_spare_servers = $php_min_spare_servers" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*pm.max_spare_servers = .*" --replace_string="pm.max_spare_servers = $php_max_spare_servers" --target_file="$finalphpconf" - elif [ "$php_pm" = "ondemand" ] - then - ynh_replace_string --match_string=".*pm.process_idle_timeout = .*" --replace_string="pm.process_idle_timeout = 10s" --target_file="$finalphpconf" - fi - - # Comment unused parameters - if [ "$php_pm" != "dynamic" ] - then - ynh_replace_string --match_string=".*\(pm.start_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*\(pm.min_spare_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*\(pm.max_spare_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" - fi - if [ "$php_pm" != "ondemand" ] - then - ynh_replace_string --match_string=".*\(pm.process_idle_timeout = .*\)" --replace_string=";\1" --target_file="$finalphpconf" - fi - - # Concatene the extra config. - if [ -e ../conf/extra_php-fpm.conf ]; then - cat ../conf/extra_php-fpm.conf >> "$finalphpconf" - fi - fi - sudo chown root: "$finalphpconf" - ynh_store_file_checksum --file="$finalphpconf" - - if [ -e "../conf/php-fpm.ini" ] - then - echo "Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." >&2 - finalphpini="$fpm_config_dir/conf.d/20-$app.ini" - ynh_backup_if_checksum_is_different "$finalphpini" - sudo cp ../conf/php-fpm.ini "$finalphpini" - sudo chown root: "$finalphpini" - ynh_store_file_checksum "$finalphpini" - fi - ynh_systemd_action --service_name=$fpm_service --action=reload -} diff --git a/scripts/actions/reset_default_app b/scripts/actions/reset_default_app new file mode 100755 index 0000000..5cc74fc --- /dev/null +++ b/scripts/actions/reset_default_app @@ -0,0 +1,256 @@ +#!/bin/bash + +#================================================= +# GENERIC STARTING +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +# Load common variables for all scripts. +source scripts/_variables + +source scripts/_common.sh +source /usr/share/yunohost/helpers + +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_clean_setup () { +# Clean installation remaining that are not handle by the remove script. + ynh_clean_check_starting +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# RETRIEVE ARGUMENTS +#================================================= + +app=$YNH_APP_INSTANCE_NAME + +path_url=$(ynh_app_setting_get --app=$app --key=path) +domain=$(ynh_app_setting_get --app=$app --key=domain) +pihole_version="$(ynh_app_setting_get --app=$app --key=pihole_version)" + +#================================================= +# SPECIFIC ACTION +#================================================= +# ACTIVATE MAINTENANCE MODE +#================================================= +ynh_script_progression --message="Activating maintenance mode..." --time --weight=1 + +ynh_maintenance_mode_ON + +#================================================= +# DOWNLOAD, CHECK AND UNPACK SOURCE +#================================================= +ynh_script_progression --message="Resetting source files..." --time --weight=1 + +# Download, check integrity, uncompress and patch the source from app.src +pihole_local_repo="/etc/.pihole" +(cd scripts +if [ "$pihole_version" == "Last 3.X" ] +then + # Overwrite the version 3.3.1 + YNH_CWD=$PWD ynh_setup_source --dest_dir="$pihole_local_repo" --source_id=app_3 + # Overwrite admin dashboard + YNH_CWD=$PWD ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard_3 +else + # Overwrite the last version available + YNH_CWD=$PWD ynh_setup_source --dest_dir="$pihole_local_repo" --source_id=app_last + # Overwrite admin dashboard + YNH_CWD=$PWD ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard_last +fi +) + +#================================================= +# NGINX CONFIGURATION +#================================================= +ynh_script_progression --message="Resetting nginx web server configuration..." --time --weight=1 + +# Create a dedicated nginx config +yunohost app action run $app reset_default_nginx + +#================================================= +# CREATE DEDICATED USER +#================================================= +ynh_script_progression --message="Making sure dedicated system user exists..." --time --weight=1 + +# Create a dedicated user (if not existing) +ynh_system_user_create --username=$app + +#================================================= +# PHP-FPM CONFIGURATION +#================================================= +ynh_script_progression --message="Resetting php-fpm configuration..." --time --weight=1 + +# Create a dedicated php-fpm config +yunohost app action run $app reset_default_phpfpm + +#================================================= +# RECREATE DIRECTORIES +#================================================= +ynh_script_progression --message="Recreating and populating directories..." --time --weight=1 + +pihole_storage="/etc/pihole" +mkdir -p "$pihole_storage" +chown $app: -R "$pihole_storage" + +pihole_dir="/opt/pihole" +mkdir -p "$pihole_dir" + +# Make a copy of Pi-Hole scripts +cp -a "$pihole_local_repo/gravity.sh" "$pihole_dir/" +cp -a $pihole_local_repo/advanced/Scripts/*.sh "$pihole_dir/" + +# And copy this fucking COL_TABLE file... +cp -a "$pihole_local_repo/advanced/Scripts/COL_TABLE" "$pihole_dir/" + +#================================================= +# COPY PI-HOLE MAIN SCRIPT +#================================================= +ynh_script_progression --message="Copying Pi-Hole main script..." + +cp -a "$pihole_local_repo/pihole" /usr/local/bin/ +cp -a "$pihole_local_repo/advanced/bash-completion/pihole" /etc/bash_completion.d/pihole + +#================================================= +# RECREATE LOG FILES +#================================================= + +touch /var/log/{pihole,pihole-FTL}.log +chmod 644 /var/log/{pihole,pihole-FTL}.log +dnsmasq_user=$(grep DNSMASQ_USER= /etc/init.d/dnsmasq | cut -d'"' -f2) +chown $dnsmasq_user:root /var/log/{pihole,pihole-FTL}.log + +#================================================= +# RECREATE SUDOER FILE +#================================================= + +# This sudoers config allow pihole to execute /usr/local/bin/pihole as root without password. Nothing more. +if [ "$pihole_version" == "Last 3.X" ] +then + cp "$pihole_local_repo/advanced/pihole.sudo" /etc/sudoers.d/pihole +else + cp "$pihole_local_repo/advanced/Templates/pihole.sudo" /etc/sudoers.d/pihole +fi +echo "$app ALL=NOPASSWD: /usr/local/bin/pihole" >> /etc/sudoers.d/pihole +# echo "Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin" >> /etc/sudoers.d/pihole +chmod 0440 /etc/sudoers.d/pihole + +#================================================= +# REINSTALL LOGROTATE SCRIPT FOR PI-HOLE +#================================================= + +if [ "$pihole_version" == "Last 3.X" ] +then + cp "$pihole_local_repo/advanced/logrotate" "$pihole_storage/logrotate" +else + cp "$pihole_local_repo/advanced/Templates/logrotate" "$pihole_storage/logrotate" +fi +sed -i "/# su #/d;" "$pihole_storage/logrotate" + +#================================================= +# REINSTALLATION OF PIHOLE-FTL +#================================================= +ynh_script_progression --message="Reinstalling PiHole-FTL..." --weight=30 + +# Get the source of Pi-Hole-FTL +FTL_temp_path=$(mktemp -d) +if [ "$pihole_version" == "Last 3.X" ] +then + # Install the version 3.3.1 + ynh_setup_source --dest_dir="$FTL_temp_path" --source_id=FTL_3 +else + # Install the last version available + ynh_setup_source --dest_dir="$FTL_temp_path" --source_id=FTL_last +fi + +# Instead of downloading a binary file, we're going to compile it +( cd "$FTL_temp_path" +ynh_exec_warn_less make +ynh_exec_warn_less make install ) +ynh_secure_remove --file="$FTL_temp_path" + +cp "../conf/dns-servers.conf" "$pihole_storage" + +# Restore the default pihole-FTL.conf +yunohost app action run $app reset_default_ftl + +if [ "$pihole_version" == "Last 3.X" ] +then + # Version 3.3.1 + cp -a $pihole_local_repo/advanced/pihole-FTL.service /etc/init.d/pihole-FTL + chmod +x /etc/init.d/pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL +else + cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL + chmod +x /etc/init.d/pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL + + # Reload systemd config + systemctl daemon-reload +fi + +#================================================= +# RESET THE VARIABLES FILE +#================================================= + +# Restore the default setupVars.conf +yunohost app action run $app reset_default_setupvars + +#================================================= +# RESET DNSMASQ CONFIG +#================================================= + +# Restore the default setupVars.conf +yunohost app action run $app reset_default_dnsmasq + +#================================================= +# REINSTALL CRON JOB +#================================================= + +if [ "$pihole_version" == "Last 3.X" ] +then + cp $pihole_local_repo/advanced/pihole.cron /etc/cron.d/pihole +else + cp $pihole_local_repo/advanced/Templates/pihole.cron /etc/cron.d/pihole +fi + +# Remove git usage for version. Which fails because we use here a release instead of master. +ynh_replace_string --match_string=".*updatechecker.*" --replace_string="#&" --target_file=/etc/cron.d/pihole + +#================================================= +# REINSTALL CONF_REGEN HOOK +#================================================= + +(cd scripts; cp ../conf/dnsmasq_regenconf_hook /usr/share/yunohost/hooks/conf_regen/50-dnsmasq_$app) + +#================================================= +# RESTART PIHOLE-FTL +#================================================= + +ynh_script_progression --message="Restarting PiHole-FTL..." --weight=2 + +ynh_systemd_action --action=restart --service_name=pihole-FTL + +#================================================= +# RELOAD NGINX +#================================================= +ynh_script_progression --message="Reloading nginx web server..." --time --weight=1 + +ynh_systemd_action --service_name=nginx --action=reload + +#================================================= +# DEACTIVE MAINTENANCE MODE +#================================================= +ynh_script_progression --message="Disabling maintenance mode..." --time --weight=1 + +ynh_maintenance_mode_OFF + +#================================================= +# END OF SCRIPT +#================================================= + +ynh_script_progression --message="Execution completed" --time --last diff --git a/scripts/actions/reset_default_config b/scripts/actions/reset_default_config index 1272710..24faea7 100755 --- a/scripts/actions/reset_default_config +++ b/scripts/actions/reset_default_config @@ -9,11 +9,18 @@ source scripts/_common.sh source /usr/share/yunohost/helpers +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + #================================================= # RETRIEVE ARGUMENTS #================================================= -app=${YNH_APP_INSTANCE_NAME:-$YNH_APP_ID} +app=$YNH_APP_INSTANCE_NAME query_logging=$(ynh_app_setting_get --app=$app --key=query_logging) @@ -24,9 +31,11 @@ query_logging=$(ynh_app_setting_get --app=$app --key=query_logging) file="$1" if [ "$file" = "setupVars.conf" ]; then - config_file="/etc/pihole/setupVars.conf" + config_file="/etc/pihole/setupVars.conf" elif [ "$file" = "pihole-FTL.conf" ]; then - config_file="/etc/pihole/pihole-FTL.conf" + config_file="/etc/pihole/pihole-FTL.conf" +elif [ "$file" = "01-pihole.conf" ]; then + config_file="/etc/dnsmasq.d/01-pihole.conf" fi #================================================= @@ -39,33 +48,55 @@ ynh_script_progression --message="Resetting the config file $config_file..." --w # Verify the checksum and backup the file if it's different ynh_backup_if_checksum_is_different --file="$config_file" +main_iface=$(ip route | grep --max-count=1 default | awk '{print $5;}') + if [ "$file" = "setupVars.conf" ] then - # Recreate the default config - # Trouve l'interface réseau par défaut - main_iface=$(ip route | grep --max-count=1 default | awk '{print $5;}') - echo "PIHOLE_INTERFACE=$main_iface" > "$config_file" - echo "IPV4_ADDRESS=127.0.0.1" >> "$config_file" - echo "IPV6_ADDRESS=::1" >> "$config_file" - echo "PIHOLE_DNS_1=" >> "$config_file" - echo "PIHOLE_DNS_2=" >> "$config_file" - if [ $query_logging -eq 1 ]; then - query_logging=true - else - query_logging=false - fi - echo "QUERY_LOGGING=$query_logging" >> "$config_file" - echo "INSTALL_WEB=true" >> "$config_file" + # Recreate the default config + # Trouve l'interface réseau par défaut + echo "PIHOLE_INTERFACE=$main_iface" > "$config_file" + echo "IPV4_ADDRESS=127.0.0.1" >> "$config_file" + echo "IPV6_ADDRESS=::1" >> "$config_file" + echo "PIHOLE_DNS_1=" >> "$config_file" + echo "PIHOLE_DNS_2=" >> "$config_file" + if [ $query_logging -eq 1 ]; then + query_logging=true + else + query_logging=false + fi + echo "QUERY_LOGGING=$query_logging" >> "$config_file" + echo "INSTALL_WEB=true" >> "$config_file" elif [ "$file" = "pihole-FTL.conf" ] then - # Get the default file and overwrite the current config - cp /etc/yunohost/apps/$app/conf/pihole-FTL.conf "$config_file" + # Get the default file and overwrite the current config + cp /etc/yunohost/apps/$app/conf/pihole-FTL.conf "$config_file" - ynh_script_progression --message="Restarting PiHole..." --weight=2 + ynh_script_progression --message="Restarting PiHole..." --weight=2 - # Restart pihole-FTL - ynh_systemd_action --action=restart --service_name=pihole-FTL + # Restart pihole-FTL + ynh_systemd_action --action=restart --service_name=pihole-FTL + +elif [ "$file" = "01-pihole.conf" ] +then + cp "$pihole_local_repo/advanced/01-pihole.conf" $config_file + # Use dns from /etc/resolv.dnsmasq.conf + ynh_replace_string --match_string="@DNS1@" --replace_string="" --target_file=$config_file + ynh_replace_string --match_string="@DNS2@" --replace_string="" --target_file=$config_file + ynh_replace_string --match_string="^no-resolv" --replace_string="#no-resolv" --target_file=$config_file + + ynh_replace_string --match_string="@INT@" --replace_string="$main_iface" --target_file=$config_file + if [ "$query_logging" = "true" ]; then + ynh_replace_string --match_string="^#log-queries" --replace_string="log-queries" --target_file=$config_file + else + ynh_replace_string --match_string="^log-queries" --replace_string="#log-queries" --target_file=$config_file + fi + + # Fix a too recent option for our dnsmasq version. + ynh_replace_string --match_string="log-queries=extra" --replace_string="log-queries" --target_file=$config_file + + # To prevent any conflict with the original dnsmasq config, comment cache-size in the original config. + ynh_replace_string --match_string="^cache-size=" --replace_string="#pihole# cache-size=" --target_file=/etc/dnsmasq.conf fi # Calculate and store the config file checksum into the app settings diff --git a/scripts/actions/reset_default_system b/scripts/actions/reset_default_system new file mode 100755 index 0000000..c760535 --- /dev/null +++ b/scripts/actions/reset_default_system @@ -0,0 +1,64 @@ +#!/bin/bash + +#================================================= +# GENERIC STARTING +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source scripts/_common.sh +source /usr/share/yunohost/helpers + +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_clean_setup () { +# Clean installation remaining that are not handle by the remove script. + ynh_clean_check_starting +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# RETRIEVE ARGUMENTS +#================================================= + +app=$YNH_APP_INSTANCE_NAME + +type=$1 + +domain=$(ynh_app_setting_get --app=$app --key=domain) +path_url=$(ynh_app_setting_get --app=$app --key=path) +final_path=$(ynh_app_setting_get --app=$app --key=final_path) + +#================================================= +# SPECIFIC ACTION +#================================================= +# RESET THE CONFIG FILE +#================================================= + +if [ $type == nginx ]; then + name=Nginx +elif [ $type == phpfpm ]; then + name=PHP-FPM +else + ynh_die --message="The type $type is not recognized" +fi + +ynh_script_progression --message="Resetting the specific configuration of $name for the app $app..." --weight=3 + +if [ $type == nginx ] +then + (cd scripts; ynh_add_nginx_config) + +elif [ $type == phpfpm ] +then + (cd scripts; ynh_add_fpm_config --usage=low --footprint=low --dedicated_service) +fi + +#================================================= +# END OF SCRIPT +#================================================= + +ynh_script_progression --message="Execution completed" --last diff --git a/scripts/backup b/scripts/backup index 51aeb6e..1913355 100644 --- a/scripts/backup +++ b/scripts/backup @@ -27,6 +27,9 @@ final_path=$(ynh_app_setting_get --app=$app --key=final_path) path_url=$(ynh_app_setting_get --app=$app --key=path) domain=$(ynh_app_setting_get --app=$app --key=domain) +# Get variable from ynh_add_fpm_config +fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) + #================================================= # STANDARD BACKUP STEPS #================================================= @@ -34,16 +37,9 @@ domain=$(ynh_app_setting_get --app=$app --key=domain) #================================================= ynh_script_progression --message="Backing up the main app directory..." --weight=5 -CHECK_SIZE "$final_path" ynh_backup --src_path="$final_path" - -CHECK_SIZE "/etc/.pihole" ynh_backup --src_path="/etc/.pihole" - -CHECK_SIZE "/etc/pihole" ynh_backup --src_path="/etc/pihole" - -CHECK_SIZE "/opt/pihole" ynh_backup --src_path="/opt/pihole" #================================================= @@ -58,7 +54,8 @@ ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf" #================================================= ynh_script_progression --message="Backing up php-fpm configuration..." -ynh_backup --src_path="/etc/php/7.0/fpm/pool.d/$app.conf" +ynh_backup --src_path="$fpm_config_dir/php-fpm-$app.conf" +ynh_backup --src_path="$fpm_config_dir/pool.d/$app.conf" #================================================= # SPECIFIC BACKUP @@ -84,13 +81,13 @@ ynh_backup --src_path="/usr/bin/pihole-FTL" ynh_backup --src_path="/etc/dnsmasq.d/01-pihole.conf" if test -e "/etc/dnsmasq.d/02-pihole-dhcp.conf"; then - ynh_backup --src_path="/etc/dnsmasq.d/02-pihole-dhcp.conf" + ynh_backup --src_path="/etc/dnsmasq.d/02-pihole-dhcp.conf" fi if test -e "/etc/dnsmasq.d/03-pihole-wildcard.conf"; then - ynh_backup --src_path="/etc/dnsmasq.d/03-pihole-wildcard.conf" + ynh_backup --src_path="/etc/dnsmasq.d/03-pihole-wildcard.conf" fi if test -e "/etc/dnsmasq.d/04-pihole-static-dhcp.conf"; then - ynh_backup --src_path="/etc/dnsmasq.d/04-pihole-static-dhcp.conf" + ynh_backup --src_path="/etc/dnsmasq.d/04-pihole-static-dhcp.conf" fi ynh_backup --src_path="/usr/share/yunohost/hooks/conf_regen/50-dnsmasq_$app" diff --git a/scripts/change_url b/scripts/change_url index c7fe581..1afb28e 100644 --- a/scripts/change_url +++ b/scripts/change_url @@ -36,11 +36,11 @@ ynh_script_progression --message="Backing up the app before changing its url (ma # Backup the current version of the app ynh_backup_before_upgrade ynh_clean_setup () { - # Remove the new domain config file, the remove script won't do it as it doesn't know yet its location. - ynh_secure_remove --file="/etc/nginx/conf.d/$new_domain.d/$app.conf" + # Remove the new domain config file, the remove script won't do it as it doesn't know yet its location. + ynh_secure_remove --file="/etc/nginx/conf.d/$new_domain.d/$app.conf" - # restore it if the upgrade fails - ynh_restore_upgradebackup + # restore it if the upgrade fails + ynh_restore_upgradebackup } # Exit if an error occurs during the execution of the script ynh_abort_if_errors @@ -61,13 +61,13 @@ ynh_maintenance_mode_ON change_domain=0 if [ "$old_domain" != "$new_domain" ] then - change_domain=1 + change_domain=1 fi change_path=0 if [ "$old_path" != "$new_path" ] then - change_path=1 + change_path=1 fi #================================================= @@ -82,26 +82,26 @@ nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf # Change the path in the nginx config file if [ $change_path -eq 1 ] then - # Make a backup of the original nginx config file if modified - ynh_backup_if_checksum_is_different --file="$nginx_conf_path" + # Make a backup of the original nginx config file if modified + ynh_backup_if_checksum_is_different --file="$nginx_conf_path" - # Set global variables for nginx helper - domain="$old_domain" - path_url="$new_path" + # Set global variables for nginx helper + domain="$old_domain" + path_url="$new_path" - # Create a dedicated nginx config - ynh_add_nginx_config + # Create a dedicated nginx config + ynh_add_nginx_config fi # Change the domain for nginx if [ $change_domain -eq 1 ] then - # Delete file checksum for the old conf file location - ynh_delete_file_checksum --file="$nginx_conf_path" - mv $nginx_conf_path /etc/nginx/conf.d/$new_domain.d/$app.conf + # Delete file checksum for the old conf file location + ynh_delete_file_checksum --file="$nginx_conf_path" + mv $nginx_conf_path /etc/nginx/conf.d/$new_domain.d/$app.conf - # Store file checksum for the new config file location - ynh_store_file_checksum --file="/etc/nginx/conf.d/$new_domain.d/$app.conf" + # Store file checksum for the new config file location + ynh_store_file_checksum --file="/etc/nginx/conf.d/$new_domain.d/$app.conf" fi #================================================= diff --git a/scripts/config b/scripts/config index 8772ea0..02a2d40 100644 --- a/scripts/config +++ b/scripts/config @@ -8,13 +8,14 @@ source _common.sh source /usr/share/yunohost/helpers -source _ynh_add_fpm_config #================================================= # RETRIEVE ARGUMENTS #================================================= -app=${YNH_APP_INSTANCE_NAME:-$YNH_APP_ID} +app=$YNH_APP_INSTANCE_NAME + +fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) #================================================= # SPECIFIC CODE @@ -69,24 +70,33 @@ free_footprint="${YNH_CONFIG_MAIN_PHP_FPM_CONFIG_FREE_FOOTPRINT:-$old_free_footp old_fpm_usage="$(ynh_app_setting_get --app=$app --key=fpm_usage)" fpm_usage="${YNH_CONFIG_MAIN_PHP_FPM_CONFIG_USAGE:-$old_fpm_usage}" +# php_forced_max_children for php-fpm +old_php_forced_max_children="$(ynh_app_setting_get --app=$app --key=php_forced_max_children)" +# If php_forced_max_children isn't into settings.yml, get the current value from the fpm config +if [ -z "$old_php_forced_max_children" ]; then + old_php_forced_max_children="$(grep "^pm.max_children" "$fpm_config_dir/pool.d/$app.conf" | awk '{print $3}')" +fi +php_forced_max_children="${YNH_CONFIG_MAIN_PHP_FPM_CONFIG_FORCE_MAX_CHILDREN:-$old_php_forced_max_children}" + #================================================= # SHOW_CONFIG FUNCTION FOR 'SHOW' COMMAND #================================================= show_config() { - # here you are supposed to read some config file/database/other then print the values - # ynh_return "YNH_CONFIG_${PANEL_ID}_${SECTION_ID}_${OPTION_ID}=value" + # here you are supposed to read some config file/database/other then print the values + # ynh_return "YNH_CONFIG_${PANEL_ID}_${SECTION_ID}_${OPTION_ID}=value" - ynh_return "YNH_CONFIG_MAIN_OVERWRITE_FILES_OVERWRITE_SETUPVARS=$overwrite_setupvars" - ynh_return "YNH_CONFIG_MAIN_OVERWRITE_FILES_OVERWRITE_FTL=$overwrite_ftl" - ynh_return "YNH_CONFIG_MAIN_OVERWRITE_FILES_OVERWRITE_NGINX=$overwrite_nginx" - ynh_return "YNH_CONFIG_MAIN_OVERWRITE_FILES_OVERWRITE_PHPFPM=$overwrite_phpfpm" + ynh_return "YNH_CONFIG_MAIN_OVERWRITE_FILES_OVERWRITE_SETUPVARS=$overwrite_setupvars" + ynh_return "YNH_CONFIG_MAIN_OVERWRITE_FILES_OVERWRITE_FTL=$overwrite_ftl" + ynh_return "YNH_CONFIG_MAIN_OVERWRITE_FILES_OVERWRITE_NGINX=$overwrite_nginx" + ynh_return "YNH_CONFIG_MAIN_OVERWRITE_FILES_OVERWRITE_PHPFPM=$overwrite_phpfpm" - ynh_return "YNH_CONFIG_MAIN_GLOBAL_CONFIG_EMAIL_TYPE=$admin_mail_html" + ynh_return "YNH_CONFIG_MAIN_GLOBAL_CONFIG_EMAIL_TYPE=$admin_mail_html" - ynh_return "YNH_CONFIG_MAIN_PHP_FPM_CONFIG_FOOTPRINT=$fpm_footprint" - ynh_return "YNH_CONFIG_MAIN_PHP_FPM_CONFIG_FREE_FOOTPRINT=$free_footprint" - ynh_return "YNH_CONFIG_MAIN_PHP_FPM_CONFIG_USAGE=$fpm_usage" + ynh_return "YNH_CONFIG_MAIN_PHP_FPM_CONFIG_FOOTPRINT=$fpm_footprint" + ynh_return "YNH_CONFIG_MAIN_PHP_FPM_CONFIG_FREE_FOOTPRINT=$free_footprint" + ynh_return "YNH_CONFIG_MAIN_PHP_FPM_CONFIG_USAGE=$fpm_usage" + ynh_return "YNH_CONFIG_MAIN_PHP_FPM_CONFIG_FORCE_MAX_CHILDREN=$php_forced_max_children" } #================================================= @@ -99,27 +109,30 @@ apply_config() { # MODIFY OVERWRITTING SETTINGS #================================================= - # Set overwrite_setupvars - ynh_app_setting_set --app=$app --key=overwrite_setupvars --value="$overwrite_setupvars" - # Set overwrite_ftl - ynh_app_setting_set --app=$app --key=overwrite_ftl --value="$overwrite_ftl" - # Set overwrite_nginx - ynh_app_setting_set --app=$app --key=overwrite_nginx --value="$overwrite_nginx" - # Set overwrite_phpfpm - ynh_app_setting_set --app=$app --key=overwrite_phpfpm --value="$overwrite_phpfpm" + # Set overwrite_setupvars + ynh_app_setting_set --app=$app --key=overwrite_setupvars --value="$overwrite_setupvars" + # Set overwrite_ftl + ynh_app_setting_set --app=$app --key=overwrite_ftl --value="$overwrite_ftl" + # Set overwrite_nginx + ynh_app_setting_set --app=$app --key=overwrite_nginx --value="$overwrite_nginx" + # Set overwrite_phpfpm + ynh_app_setting_set --app=$app --key=overwrite_phpfpm --value="$overwrite_phpfpm" #================================================= # MODIFY EMAIL SETTING #================================================= - # Set admin_mail_html - ynh_app_setting_set --app=$app --key=admin_mail_html --value="$admin_mail_html" + # Set admin_mail_html + ynh_app_setting_set --app=$app --key=admin_mail_html --value="$admin_mail_html" #================================================= # RECONFIGURE PHP-FPM #================================================= - if [ "$fpm_usage" != "$old_fpm_usage" ] || [ "$fpm_footprint" != "$old_fpm_footprint" ] || [ "$free_footprint" != "$old_free_footprint" ] + if [ "$fpm_usage" != "$old_fpm_usage" ] || \ + [ "$fpm_footprint" != "$old_fpm_footprint" ] || \ + [ "$free_footprint" != "$old_free_footprint" ] || \ + [ "$php_forced_max_children" != "$old_php_forced_max_children" ] then # If fpm_footprint is set to 'specific', use $free_footprint value. if [ "$fpm_footprint" = "specific" ] @@ -127,9 +140,21 @@ apply_config() { fpm_footprint=$free_footprint fi + if [ "$php_forced_max_children" != "$old_php_forced_max_children" ] + then + # Set php_forced_max_children + if [ $php_forced_max_children -ne 0 ] + then + ynh_app_setting_set --app=$app --key=php_forced_max_children --value="$php_forced_max_children" + else + # If the value is set to 0, remove the setting + ynh_app_setting_delete --app=$app --key=php_forced_max_children + fi + fi + if [ "$fpm_footprint" != "0" ] then - ynh_add_fpm_config --usage=$fpm_usage --footprint=$fpm_footprint + ynh_add_fpm_config --usage=$fpm_usage --footprint=$fpm_footprint --dedicated_service else ynh_print_err --message="When selecting 'specific', you have to set a footprint value into the field below." fi @@ -143,6 +168,6 @@ apply_config() { #================================================= case $1 in - show) show_config;; - apply) apply_config;; + show) show_config;; + apply) apply_config;; esac diff --git a/scripts/install b/scripts/install index 9d93e60..4f17c8d 100644 --- a/scripts/install +++ b/scripts/install @@ -6,12 +6,12 @@ # IMPORT GENERIC HELPERS #================================================= -source _common.sh -source /usr/share/yunohost/helpers -source _ynh_add_fpm_config # Load common variables for all scripts. source _variables +source _common.sh +source /usr/share/yunohost/helpers + #================================================= # MANAGE FAILURE OF THE SCRIPT #================================================= @@ -72,7 +72,7 @@ ynh_script_progression --message="Configuring firewall..." --weight=12 port=$(ynh_find_port --port=4711) if [ $port -gt 4720 ] then - ynh_die --message="The ports 4711 to 4720 are already in use. Pi-hole can't works on another port. Please try to free one of this ports." + ynh_die --message="The ports 4711 to 4720 are already in use. Pi-hole can't works on another port. Please try to free one of this ports." fi # Open this port ynh_exec_fully_quiet yunohost firewall allow --no-upnp TCP $port @@ -132,7 +132,7 @@ ynh_system_user_create --username=$app ynh_script_progression --message="Configuring php-fpm..." --weight=2 # Create a dedicated php-fpm config -ynh_add_fpm_config --usage=low --footprint=low +ynh_add_fpm_config --usage=low --footprint=low --dedicated_service #================================================= # SPECIFIC SETUP @@ -167,10 +167,10 @@ cp -a "$pihole_local_repo/advanced/bash-completion/pihole" /etc/bash_completion. # CREATE LOG FILES #================================================= -touch /var/log/pihole.log -chmod 644 /var/log/pihole.log +touch /var/log/{pihole,pihole-FTL}.log +chmod 644 /var/log/{pihole,pihole-FTL}.log dnsmasq_user=$(grep DNSMASQ_USER= /etc/init.d/dnsmasq | cut -d'"' -f2) -chown $dnsmasq_user:root /var/log/pihole.log +chown $dnsmasq_user:root /var/log/{pihole,pihole-FTL}.log #================================================= # CREATE SUDOER FILE @@ -221,7 +221,9 @@ ynh_exec_warn_less make ynh_exec_warn_less make install ) ynh_secure_remove --file="$FTL_temp_path" +cp "../conf/dns-servers.conf" "$pihole_storage" cp "../conf/pihole-FTL.conf" "$pihole_storage" + # Calculate and store the config file checksum into the app settings ynh_store_file_checksum --file="$pihole_storage/pihole-FTL.conf" @@ -276,9 +278,9 @@ echo "IPV6_ADDRESS=::1" >> $setupVars echo "PIHOLE_DNS_1=" >> $setupVars echo "PIHOLE_DNS_2=" >> $setupVars if [ $query_logging -eq 1 ]; then - query_logging=true + query_logging=true else - query_logging=false + query_logging=false fi echo "QUERY_LOGGING=$query_logging" >> $setupVars echo "INSTALL_WEB=true" >> $setupVars @@ -302,9 +304,9 @@ ynh_replace_string --match_string="^no-resolv" --replace_string="#no-resolv" --t ynh_replace_string --match_string="@INT@" --replace_string="$main_iface" --target_file=$pihole_dnsmasq_config if [ "$query_logging" = "true" ]; then - ynh_replace_string --match_string="^#log-queries" --replace_string="log-queries" --target_file=$pihole_dnsmasq_config + ynh_replace_string --match_string="^#log-queries" --replace_string="log-queries" --target_file=$pihole_dnsmasq_config else - ynh_replace_string --match_string="^log-queries" --replace_string="#log-queries" --target_file=$pihole_dnsmasq_config + ynh_replace_string --match_string="^log-queries" --replace_string="#log-queries" --target_file=$pihole_dnsmasq_config fi # Fix a too recent option for our dnsmasq version. @@ -327,12 +329,12 @@ localipv4=$(ip address | grep "${main_iface}\$" | awk '{print $2;}' | cut -d/ -f # List all YunoHost domains while read perdomain do - # Comment domain resolution in /etc/hosts on 127.0.0.1, because they can interfere with the local network resolution. - ynh_replace_string --match_string="^127.0.0.1.*$perdomain" --replace_string="#Commented by pihole# &" --target_file=/etc/hosts + # Comment domain resolution in /etc/hosts on 127.0.0.1, because they can interfere with the local network resolution. + ynh_replace_string --match_string="^127.0.0.1.*$perdomain" --replace_string="#Commented by pihole# &" --target_file=/etc/hosts - # And add a resolution on the local IP instead - grep -q "^$localipv4.*$perdomain" /etc/hosts || \ - echo "$localipv4 $perdomain #Added by pihole#" >> /etc/hosts + # And add a resolution on the local IP instead + grep -q "^$localipv4.*$perdomain" /etc/hosts || \ + echo "$localipv4 $perdomain #Added by pihole#" >> /etc/hosts done <<< "$(yunohost domain list | grep "\." | sed 's/.*: \|.*- //')" #================================================= @@ -341,38 +343,45 @@ done <<< "$(yunohost domain list | grep "\." | sed 's/.*: \|.*- //')" if [ $enable_dhcp -eq 1 ] then - ynh_script_progression --message="Enabling dhcp server..." - max_dhcp_range=250 - dhcp_range=100 - # Define the dhcp range from the current ip - ip_beginning_part=$(echo "$localipv4" | cut -d. -f1-3) - ip_fourth_part=$(echo "$localipv4" | cut -d. -f4) - b_range=$(( $ip_fourth_part + $dhcp_range )) - if [ $b_range -gt $max_dhcp_range ]; then - b_range=$max_dhcp_range - fi - a_range=$(( $b_range - $dhcp_range )) + ynh_script_progression --message="Enabling dhcp server..." + max_dhcp_range=250 + dhcp_range=100 + # Define the dhcp range from the current ip + ip_beginning_part=$(echo "$localipv4" | cut -d. -f1-3) + ip_fourth_part=$(echo "$localipv4" | cut -d. -f4) + b_range=$(( $ip_fourth_part + $dhcp_range )) + if [ $b_range -gt $max_dhcp_range ]; then + b_range=$max_dhcp_range + fi + a_range=$(( $b_range - $dhcp_range )) - # Get the gateway - gateway=$(ip route | grep default | awk '{print $3;}') - # And the mac adress - hw_adress=$(ip link | grep -A1 "$main_iface" | tail -n1 | awk '{print $2;}') + # Get the gateway + gateway=$(ip route | grep default | awk '{print $3;}') + # And the mac adress + hw_adress=$(ip link | grep -A1 "$main_iface" | tail -n1 | awk '{print $2;}') - # Copy the config file - cp "../conf/02-pihole-dhcp.conf" "/etc/dnsmasq.d/" + # Copy the config file + cp "../conf/02-pihole-dhcp.conf" "/etc/dnsmasq.d/" - # And set the config - ynh_replace_string --match_string="__A_RANGE__" --replace_string="$ip_beginning_part.$a_range" --target_file="/etc/dnsmasq.d/02-pihole-dhcp.conf" - ynh_replace_string --match_string="__B_RANGE__" --replace_string="$ip_beginning_part.$b_range" --target_file="/etc/dnsmasq.d/02-pihole-dhcp.conf" - ynh_replace_string --match_string="__GATEWAY__" --replace_string="$gateway" --target_file="/etc/dnsmasq.d/02-pihole-dhcp.conf" + # And set the config + ynh_replace_string --match_string="__A_RANGE__" --replace_string="$ip_beginning_part.$a_range" --target_file="/etc/dnsmasq.d/02-pihole-dhcp.conf" + ynh_replace_string --match_string="__B_RANGE__" --replace_string="$ip_beginning_part.$b_range" --target_file="/etc/dnsmasq.d/02-pihole-dhcp.conf" + ynh_replace_string --match_string="__GATEWAY__" --replace_string="$gateway" --target_file="/etc/dnsmasq.d/02-pihole-dhcp.conf" - # Set a static ip for the server. - echo "dhcp-host=$hw_adress,$localipv4" > "/etc/dnsmasq.d/04-pihole-static-dhcp.conf" + # Set a static ip for the server. + echo "dhcp-host=$hw_adress,$localipv4" > "/etc/dnsmasq.d/04-pihole-static-dhcp.conf" fi # Open the UDP port 67 for dhcp ynh_exec_fully_quiet yunohost firewall allow UDP 67 --no-upnp +#================================================= +# SET VERSIONS FOR THE FOOTER OF THE WEB INTERFACE +#================================================= + +echo "master master master" > $pihole_storage/localbranches +echo "$pihole_core_version $dashboard_version $FTL_version" | tee $pihole_storage/{GitHubVersions,localversions} > /dev/null + #================================================= # INSTALL CRON JOB #================================================= @@ -457,12 +466,12 @@ admin_panel="https://$(grep portal_domain /etc/ssowat/conf.json | cut -d'"' -f4) if [ $enable_dhcp -eq 1 ] then - dhcp_alert="You asked to use the internal DHCP server of dnsmasq with PiHole. + dhcp_alert="You asked to use the internal DHCP server of dnsmasq with PiHole. You should really read the __URL_TAG1__documentation about that__URL_TAG2__https://github.com/YunoHost-Apps/pihole_ynh/blob/master/dhcp.md__URL_TAG3__ " else - dhcp_alert="" + dhcp_alert="" fi echo "${dhcp_alert}You can configure this app easily by using the experimental __URL_TAG1__config-panel feature__URL_TAG2__$admin_panel/config-panel__URL_TAG3__. diff --git a/scripts/remove b/scripts/remove index 7b3a87b..2da2bf2 100755 --- a/scripts/remove +++ b/scripts/remove @@ -113,14 +113,14 @@ ynh_script_progression --message="Closing port $port et 67..." --weight=13 if yunohost firewall list | grep -q "\- $port$" then - ynh_print_info "Close port $port" - ynh_exec_quiet yunohost firewall disallow TCP $port + ynh_print_info "Close port $port" + ynh_exec_quiet yunohost firewall disallow TCP $port fi if yunohost firewall list | grep -q "\- 67$" then - ynh_print_info "Close port 67" - ynh_exec_quiet yunohost firewall disallow UDP 67 + ynh_print_info "Close port 67" + ynh_exec_quiet yunohost firewall disallow UDP 67 fi #================================================= @@ -175,6 +175,12 @@ sed -i "/#Added by pihole#/d" /etc/hosts #================================================= ynh_script_progression --message="Restarting Dnsmasq..." +if [ "$pihole_version" == "Last available" ] +then + # Quietly start dnsmasq a first time, because it usually doesn't start correctly the first time. + ynh_exec_fully_quiet systemctl start dnsmasq + sleep 1 +fi ynh_systemd_action --action=restart --service_name=dnsmasq #================================================= diff --git a/scripts/restore b/scripts/restore index 92f8a9b..d2a3c99 100644 --- a/scripts/restore +++ b/scripts/restore @@ -6,11 +6,12 @@ # IMPORT GENERIC HELPERS #================================================= -source ../settings/scripts/_common.sh -source /usr/share/yunohost/helpers # Load common variables for all scripts. source ../settings/scripts/_variables +source ../settings/scripts/_common.sh +source /usr/share/yunohost/helpers + #================================================= # MANAGE SCRIPT FAILURE #================================================= @@ -30,6 +31,13 @@ path_url=$(ynh_app_setting_get --app=$app --key=path) final_path=$(ynh_app_setting_get --app=$app --key=final_path) enable_dhcp=$(ynh_app_setting_get --app=$app --key=enable_dhcp) admin=$(ynh_app_setting_get --app=$app --key=admin) +pihole_version="$(ynh_app_setting_get --app=$app --key=pihole_version)" + +# Get variables from ynh_add_fpm_config +fpm_footprint=$(ynh_app_setting_get --app=$app --key=fpm_footprint) +fpm_usage=$(ynh_app_setting_get --app=$app --key=fpm_usage) +fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) +fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service) #================================================= # CHECK IF THE APP CAN BE RESTORED @@ -37,9 +45,9 @@ admin=$(ynh_app_setting_get --app=$app --key=admin) ynh_script_progression --message="Validating restoration parameters..." ynh_webpath_available --domain=$domain --path_url=$path_url \ - || ynh_die --message="Path not available: ${domain}${path_url}" + || ynh_die --message="Path not available: ${domain}${path_url}" test ! -d $final_path \ - || ynh_die --message="There is already a directory: $final_path " + || ynh_die --message="There is already a directory: $final_path " #================================================= # ACTIVATE MAINTENANCE MODE @@ -89,8 +97,14 @@ chown root: -R "/etc/pihole/logrotate" #================================================= # RESTORE THE PHP-FPM CONFIGURATION #================================================= +ynh_script_progression --message="Reconfiguring php-fpm..." --weight=7 -ynh_restore_file --origin_path="/etc/php/7.0/fpm/pool.d/$app.conf" +# Restore the file first, so it can have a backup if different +ynh_restore_file --origin_path="$fpm_config_dir/php-fpm-$app.conf" +ynh_restore_file --origin_path="$fpm_config_dir/pool.d/$app.conf" + +# Recreate a dedicated php-fpm config +ynh_add_fpm_config --usage=$fpm_usage --footprint=$fpm_footprint --dedicated_service #================================================= # SPECIFIC RESTORE @@ -137,6 +151,42 @@ ynh_restore_file --origin_path="/usr/bin/pihole-FTL" ynh_restore_file --origin_path="/usr/share/yunohost/hooks/conf_regen/50-dnsmasq_$app" +#================================================= +# REPLACE THE DEFAULT DNSMASQ BY PIHOLE-FTL +#================================================= + +if [ "$pihole_version" == "Last available" ] +then + # Last version available + # Stopped dnsmasq to replace it by pihole-FTL + ynh_systemd_action --action=stop --service_name=dnsmasq + + # Disable the real dnsmasq service + ynh_exec_warn_less systemctl disable dnsmasq + + # And move the files that make the service available in systemd to really disable it + mv /lib/systemd/system/dnsmasq.service /lib/systemd/system/.dnsmasq.service.backup_by_pihole + mv /etc/init.d/dnsmasq /etc/init.d/.dnsmasq.backup_by_pihole + + # Move dnsmasq to preserve the current binary + mv /usr/sbin/dnsmasq /usr/sbin/dnsmasq.backup_by_pihole + # Replace dnsmasq by pihole-FTL + # NOTE: pihole-FTL is actually a modified version of dnsmasq + # https://github.com/pi-hole/FTL/tree/master/dnsmasq + ln -s /usr/bin/pihole-FTL /usr/sbin/dnsmasq + + cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL + chmod +x /etc/init.d/pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL + + # Replace the service dnsmasq by pihole-FTL + # That way, YunoHost can continue to use dnsmasq by actually using pihole-FTL + ln -s /run/systemd/generator.late/pihole-FTL.service /etc/systemd/system/multi-user.target.wants/dnsmasq.service + + # Reload systemd config + systemctl daemon-reload +fi + #================================================= # RESTORE DNSMASQ CONFIG #================================================= @@ -146,11 +196,11 @@ ynh_systemd_action --action=stop --service_name=dnsmasq ynh_restore_file --origin_path="/etc/dnsmasq.d/01-pihole.conf" test -e "${YNH_APP_BACKUP_DIR}/etc/dnsmasq.d/02-pihole-dhcp.conf" && \ - ynh_restore_file --origin_path="/etc/dnsmasq.d/02-pihole-dhcp.conf" + ynh_restore_file --origin_path="/etc/dnsmasq.d/02-pihole-dhcp.conf" test -e "${YNH_APP_BACKUP_DIR}/etc/dnsmasq.d/03-pihole-wildcard.conf" && \ - ynh_restore_file --origin_path="/etc/dnsmasq.d/03-pihole-wildcard.conf" + ynh_restore_file --origin_path="/etc/dnsmasq.d/03-pihole-wildcard.conf" test -e "${YNH_APP_BACKUP_DIR}/etc/dnsmasq.d/04-pihole-static-dhcp.conf" && \ - ynh_restore_file --origin_path="/etc/dnsmasq.d/04-pihole-static-dhcp.conf" + ynh_restore_file --origin_path="/etc/dnsmasq.d/04-pihole-static-dhcp.conf" # To prevent any conflict with the original dnsmasq config, comment cache-size in the original config. ynh_replace_string --match_string="^cache-size=" --replace_string="#pihole# cache-size=" --target_file=/etc/dnsmasq.conf @@ -168,20 +218,25 @@ localipv4=$(ip address | grep "${main_iface}\$" | awk '{print $2;}' | cut -d/ -f # List all YunoHost domains while read perdomain do - # Comment domain resolution in /etc/hosts on 127.0.0.1, because they can interfere with the local network resolution. - ynh_replace_string --match_string="^127.0.0.1.*$perdomain" --replace_string="#Commented by pihole# &" --target_file=/etc/hosts + # Comment domain resolution in /etc/hosts on 127.0.0.1, because they can interfere with the local network resolution. + ynh_replace_string --match_string="^127.0.0.1.*$perdomain" --replace_string="#Commented by pihole# &" --target_file=/etc/hosts - # And add a resolution on the local IP instead - grep -q "^$localipv4.*$perdomain" /etc/hosts || \ - echo "$localipv4 $perdomain #Added by pihole#" >> /etc/hosts + # And add a resolution on the local IP instead + grep -q "^$localipv4.*$perdomain" /etc/hosts || \ + echo "$localipv4 $perdomain #Added by pihole#" >> /etc/hosts done <<< "$(yunohost domain list | grep "\." | sed 's/.*: \|.*- //')" #================================================= # RESTART DNSMASQ #================================================= -ynh_script_progression --message="Restarting Dnsmasq..." -ynh_systemd_action --action=restart --service_name=dnsmasq +# Restart dnsmasq only for the version 3.X, otherwise we're going to restart it twice. +if [ "$pihole_version" == "Last 3.X" ] +then + ynh_script_progression --message="Restarting Dnsmasq..." + + ynh_systemd_action --action=restart --service_name=dnsmasq +fi #================================================= # UPDATE VARIABLES FILE @@ -211,8 +266,8 @@ ynh_systemd_action --action=restart --service_name=pihole-FTL #================================================= ynh_script_progression --message="Reloading nginx web server and php-fpm..." -ynh_systemd_action --action=reload --service_name=php7.0-fpm -ynh_systemd_action --action=reload --service_name=nginx +ynh_systemd_action --service_name=$fpm_service --action=reload +ynh_systemd_action --service_name=nginx --action=reload #================================================= # DEACTIVE MAINTENANCE MODE @@ -230,12 +285,12 @@ admin_panel="https://$(grep portal_domain /etc/ssowat/conf.json | cut -d'"' -f4) if [ $enable_dhcp -eq 1 ] then - dhcp_alert="You asked to use the internal DHCP server of dnsmasq with PiHole. + dhcp_alert="You asked to use the internal DHCP server of dnsmasq with PiHole. You should really read the __URL_TAG1__documentation about that__URL_TAG2__https://github.com/YunoHost-Apps/pihole_ynh/blob/master/dhcp.md__URL_TAG3__ " else - dhcp_alert="" + dhcp_alert="" fi echo "${dhcp_alert}You can configure this app easily by using the experimental __URL_TAG1__config-panel feature__URL_TAG2__$admin_panel/config-panel__URL_TAG3__. diff --git a/scripts/upgrade b/scripts/upgrade index c2a9e82..d1e393e 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -6,12 +6,12 @@ # IMPORT GENERIC HELPERS #================================================= -source _common.sh -source /usr/share/yunohost/helpers -source _ynh_add_fpm_config # Load common variables for all scripts. source _variables +source _common.sh +source /usr/share/yunohost/helpers + #================================================= # LOAD SETTINGS #================================================= @@ -26,6 +26,7 @@ query_logging=$(ynh_app_setting_get --app=$app --key=query_logging) final_path=$(ynh_app_setting_get --app=$app --key=final_path) enable_dhcp=$(ynh_app_setting_get --app=$app --key=enable_dhcp) port=$(ynh_app_setting_get --app=$app --key=port) +pihole_version="$(ynh_app_setting_get --app=$app --key=pihole_version)" overwrite_setupvars=$(ynh_app_setting_get --app=$app --key=overwrite_setupvars) overwrite_ftl=$(ynh_app_setting_get --app=$app --key=overwrite_ftl) @@ -48,38 +49,50 @@ ynh_script_progression --message="Ensuring downward compatibility..." # If overwrite_setupvars doesn't exist, create it if [ -z "$overwrite_setupvars" ]; then - overwrite_setupvars=1 - ynh_app_setting_set --app=$app --key=overwrite_setupvars --value=$overwrite_setupvars + overwrite_setupvars=1 + ynh_app_setting_set --app=$app --key=overwrite_setupvars --value=$overwrite_setupvars fi # If overwrite_ftl doesn't exist, create it if [ -z "$overwrite_ftl" ]; then - overwrite_ftl=1 - ynh_app_setting_set --app=$app --key=overwrite_ftl --value=$overwrite_ftl + overwrite_ftl=1 + ynh_app_setting_set --app=$app --key=overwrite_ftl --value=$overwrite_ftl fi # If overwrite_nginx doesn't exist, create it if [ -z "$overwrite_nginx" ]; then - overwrite_nginx=1 - ynh_app_setting_set --app=$app --key=overwrite_nginx --value=$overwrite_nginx + overwrite_nginx=1 + ynh_app_setting_set --app=$app --key=overwrite_nginx --value=$overwrite_nginx fi # If overwrite_phpfpm doesn't exist, create it if [ -z "$overwrite_phpfpm" ]; then - overwrite_phpfpm=1 - ynh_app_setting_set --app=$app --key=overwrite_phpfpm --value=$overwrite_phpfpm + overwrite_phpfpm=1 + ynh_app_setting_set --app=$app --key=overwrite_phpfpm --value=$overwrite_phpfpm +fi + +# If admin_mail_html doesn't exist, create it +if [ -z "$admin_mail_html" ]; then + admin_mail_html=1 + ynh_app_setting_set --app=$app --key=admin_mail_html --value=$admin_mail_html fi # If fpm_footprint doesn't exist, create it if [ -z "$fpm_footprint" ]; then - fpm_footprint=low - ynh_app_setting_set --app=$app --key=fpm_footprint --value=$fpm_footprint + fpm_footprint=low + ynh_app_setting_set --app=$app --key=fpm_footprint --value=$fpm_footprint fi # If fpm_usage doesn't exist, create it if [ -z "$fpm_usage" ]; then - fpm_usage=low - ynh_app_setting_set --app=$app --key=fpm_usage --value=$fpm_usage + fpm_usage=low + ynh_app_setting_set --app=$app --key=fpm_usage --value=$fpm_usage +fi + +# If pihole_version doesn't exist, create it +if [ -z "$pihole_version" ]; then + pihole_version="Last 3.X" + ynh_app_setting_set --app=$app --key=pihole_version --value="$pihole_version" fi #================================================= @@ -90,8 +103,8 @@ ynh_script_progression --message="Backing up the app before upgrading (may take # Backup the current version of the app ynh_backup_before_upgrade ynh_clean_setup () { - # restore it if the upgrade fails - ynh_restore_upgradebackup + # restore it if the upgrade fails + ynh_restore_upgradebackup } # Exit if an error occurs during the execution of the script ynh_abort_if_errors @@ -126,11 +139,19 @@ ynh_install_app_dependencies $app_depencencies pihole_local_repo="/etc/.pihole" if [ "$upgrade_type" == "UPGRADE_APP" ] then - ynh_script_progression --message="Upgrading source files..." --weight=4 - # Update the local copy pihole repository (for Gravity) - ynh_setup_source --dest_dir="$pihole_local_repo" - # Update admin dashboard - ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard + ynh_script_progression --message="Upgrading source files..." --weight=4 + if [ "$pihole_version" == "Last 3.X" ] + then + # Update the version 3.X + ynh_setup_source --dest_dir="$pihole_local_repo" --source_id=app_3 + # Update admin dashboard + ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard_3 + else + # Update the last version available + ynh_setup_source --dest_dir="$pihole_local_repo" --source_id=app_last + # Update admin dashboard + ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard_last + fi fi #================================================= @@ -140,9 +161,9 @@ fi # Overwrite the nginx configuration only if it's allowed if [ $overwrite_nginx -eq 1 ] then - ynh_script_progression --message="Upgrading nginx web server configuration..." --weight=2 - # Create a dedicated nginx config - ynh_add_nginx_config + ynh_script_progression --message="Upgrading nginx web server configuration..." --weight=2 + # Create a dedicated nginx config + ynh_add_nginx_config fi #================================================= @@ -160,9 +181,9 @@ ynh_system_user_create --username=$app # Overwrite the php-fpm configuration only if it's allowed if [ $overwrite_phpfpm -eq 1 ] then - ynh_script_progression --message="Upgrading php-fpm configuration..." --weight=3 - # Create a dedicated php-fpm config - ynh_add_fpm_config --usage=$fpm_usage --footprint=$fpm_footprint + ynh_script_progression --message="Upgrading php-fpm configuration..." --weight=3 + # Create a dedicated php-fpm config + ynh_add_fpm_config --usage=$fpm_usage --footprint=$fpm_footprint --dedicated_service fi #================================================= @@ -191,7 +212,12 @@ cp -a "$pihole_local_repo/advanced/bash-completion/pihole" /etc/bash_completion. #================================================= # This sudoers config allow pihole to execute /usr/local/bin/pihole as root without password. Nothing more. -cp "$pihole_local_repo/advanced/pihole.sudo" /etc/sudoers.d/pihole +if [ "$pihole_version" == "Last 3.X" ] +then + cp "$pihole_local_repo/advanced/pihole.sudo" /etc/sudoers.d/pihole +else + cp "$pihole_local_repo/advanced/Templates/pihole.sudo" /etc/sudoers.d/pihole +fi echo "$app ALL=NOPASSWD: /usr/local/bin/pihole" >> /etc/sudoers.d/pihole chmod 0440 /etc/sudoers.d/pihole @@ -200,7 +226,12 @@ chmod 0440 /etc/sudoers.d/pihole #================================================= pihole_storage="/etc/pihole" -cp "$pihole_local_repo/advanced/logrotate" "$pihole_storage/logrotate" +if [ "$pihole_version" == "Last 3.X" ] +then + cp "$pihole_local_repo/advanced/logrotate" "$pihole_storage/logrotate" +else + cp "$pihole_local_repo/advanced/Templates/logrotate" "$pihole_storage/logrotate" +fi dnsmasq_user=$(grep DNSMASQ_USER= /etc/init.d/dnsmasq | cut -d'"' -f2) sed -i "/# su #/d;" "$pihole_storage/logrotate" @@ -213,30 +244,70 @@ ynh_systemd_action --action=stop --service_name=pihole-FTL if [ "$upgrade_type" == "UPGRADE_APP" ] then - # Get the source of Pi-Hole-FTL - FTL_temp_path=$(mktemp -d) - ynh_setup_source --dest_dir="$FTL_temp_path" --source_id=FTL + # Get the source of Pi-Hole-FTL + FTL_temp_path=$(mktemp -d) + if [ "$pihole_version" == "Last 3.X" ] + then + # Install the version 3.3.1 + ynh_setup_source --dest_dir="$FTL_temp_path" --source_id=FTL_3 + else + # Install the last version available + ynh_setup_source --dest_dir="$FTL_temp_path" --source_id=FTL_last + fi - # Instead of downloading a binary file, we're going to compile it - ( cd "$FTL_temp_path" - ynh_exec_warn_less make - ynh_exec_warn_less make install ) - ynh_secure_remove --file="$FTL_temp_path" + # Instead of downloading a binary file, we're going to compile it + ( cd "$FTL_temp_path" + ynh_exec_warn_less make + ynh_exec_warn_less make install ) + ynh_secure_remove --file="$FTL_temp_path" fi # Overwrite pihole-FTL config file only if it's allowed if [ $overwrite_ftl -eq 1 ] then - # Verify the checksum of a file, stored by `ynh_store_file_checksum` in the install script. - ynh_backup_if_checksum_is_different --file="$pihole_storage/pihole-FTL.conf" - cp "../conf/pihole-FTL.conf" "$pihole_storage" - # Recalculate and store the checksum of the file for the next upgrade. - ynh_store_file_checksum --file="$pihole_storage/pihole-FTL.conf" + # Verify the checksum of a file, stored by `ynh_store_file_checksum` in the install script. + ynh_backup_if_checksum_is_different --file="$pihole_storage/pihole-FTL.conf" + cp "../conf/pihole-FTL.conf" "$pihole_storage" + # Recalculate and store the checksum of the file for the next upgrade. + ynh_store_file_checksum --file="$pihole_storage/pihole-FTL.conf" fi -cp -a $pihole_local_repo/advanced/pihole-FTL.service /etc/init.d/pihole-FTL -chmod +x /etc/init.d/pihole-FTL -ynh_exec_warn_less systemctl enable pihole-FTL +if [ "$pihole_version" == "Last 3.X" ] +then + # Version 3.3.1 + cp -a $pihole_local_repo/advanced/pihole-FTL.service /etc/init.d/pihole-FTL + chmod +x /etc/init.d/pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL +else + # Last version available + # Stopped dnsmasq to replace it by pihole-FTL + ynh_systemd_action --action=stop --service_name=dnsmasq + + # Disable the real dnsmasq service + ynh_exec_warn_less systemctl disable dnsmasq + + # And move the files that make the service available in systemd to really disable it + mv /lib/systemd/system/dnsmasq.service /lib/systemd/system/.dnsmasq.service.backup_by_pihole + mv /etc/init.d/dnsmasq /etc/init.d/.dnsmasq.backup_by_pihole + + # Move dnsmasq to preserve the current binary + mv /usr/sbin/dnsmasq /usr/sbin/dnsmasq.backup_by_pihole + # Replace dnsmasq by pihole-FTL + # NOTE: pihole-FTL is actually a modified version of dnsmasq + # https://github.com/pi-hole/FTL/tree/master/dnsmasq + ln -s /usr/bin/pihole-FTL /usr/sbin/dnsmasq + + cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL + chmod +x /etc/init.d/pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL + + # Replace the service dnsmasq by pihole-FTL + # That way, YunoHost can continue to use dnsmasq by actually using pihole-FTL + ln -s /run/systemd/generator.late/pihole-FTL.service /etc/systemd/system/multi-user.target.wants/dnsmasq.service + + # Reload systemd config + systemctl daemon-reload +fi #================================================= # BUILD VARIABLES FILE @@ -247,33 +318,38 @@ setupVars="$pihole_storage/setupVars.conf" # Overwrite the setupVars config file only if it's allowed if [ $overwrite_setupvars -eq 1 ] then - # Verify the checksum of a file, stored by `ynh_store_file_checksum` in the install script. - ynh_backup_if_checksum_is_different --file="$setupVars" + # Verify the checksum of a file, stored by `ynh_store_file_checksum` in the install script. + ynh_backup_if_checksum_is_different --file="$setupVars" - # Get the default network interface - main_iface=$(ip route | grep --max-count=1 default | awk '{print $5;}') - echo "PIHOLE_INTERFACE=$main_iface" > $setupVars - echo "IPV4_ADDRESS=127.0.0.1" >> $setupVars - echo "IPV6_ADDRESS=::1" >> $setupVars - echo "PIHOLE_DNS_1=" >> $setupVars - echo "PIHOLE_DNS_2=" >> $setupVars - if [ $query_logging -eq 1 ]; then - query_logging=true - else - query_logging=false - fi - echo "QUERY_LOGGING=$query_logging" >> $setupVars - echo "INSTALL_WEB=true" >> $setupVars + # Get the default network interface + main_iface=$(ip route | grep --max-count=1 default | awk '{print $5;}') + echo "PIHOLE_INTERFACE=$main_iface" > $setupVars + echo "IPV4_ADDRESS=127.0.0.1" >> $setupVars + echo "IPV6_ADDRESS=::1" >> $setupVars + echo "PIHOLE_DNS_1=" >> $setupVars + echo "PIHOLE_DNS_2=" >> $setupVars + if [ $query_logging -eq 1 ]; then + query_logging=true + else + query_logging=false + fi + echo "QUERY_LOGGING=$query_logging" >> $setupVars + echo "INSTALL_WEB=true" >> $setupVars - # Recalculate and store the checksum of the file for the next upgrade. - ynh_store_file_checksum --file="$setupVars" + # Recalculate and store the checksum of the file for the next upgrade. + ynh_store_file_checksum --file="$setupVars" fi #================================================= # UPDATE CRON JOB #================================================= -cp $pihole_local_repo/advanced/pihole.cron /etc/cron.d/pihole +if [ "$pihole_version" == "Last 3.X" ] +then + cp $pihole_local_repo/advanced/pihole.cron /etc/cron.d/pihole +else + cp $pihole_local_repo/advanced/Templates/pihole.cron /etc/cron.d/pihole +fi # Remove git usage for version. Which fails because we use here a release instead of master. ynh_replace_string --match_string=".*updatechecker.*" --replace_string="#&" --target_file=/etc/cron.d/pihole @@ -311,10 +387,6 @@ ynh_maintenance_mode_OFF # Get main domain and buid the url of the admin panel of the app. admin_panel="https://$(grep portal_domain /etc/ssowat/conf.json | cut -d'"' -f4)/yunohost/admin/#/apps/$app" -# Build the changelog -# Get the value of admin_mail_html -admin_mail_html=$(ynh_app_setting_get $app admin_mail_html) -admin_mail_html="${admin_mail_html:-0}" # If a html email is required. Apply html to the changelog. if [ "$admin_mail_html" -eq 1 ]; then format=html @@ -325,12 +397,12 @@ ynh_app_changelog --format=$format if [ $enable_dhcp -eq 1 ] then - dhcp_alert="You asked to use the internal DHCP server of dnsmasq with PiHole. + dhcp_alert="You asked to use the internal DHCP server of dnsmasq with PiHole. You should really read the documentation about that, https://github.com/YunoHost-Apps/pihole_ynh/blob/master/dhcp.md " else - dhcp_alert="" + dhcp_alert="" fi echo "${dhcp_alert}You can configure this app easily by using the experimental __URL_TAG1__config-panel feature__URL_TAG2__$admin_panel/config-panel__URL_TAG3__. diff --git a/sources/patches/.gitignore b/sources/patches/.gitignore deleted file mode 100644 index d38c149..0000000 --- a/sources/patches/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.swp -*~ diff --git a/sources/patches/FTL_last-dns_replacement.patch b/sources/patches/FTL_last-dns_replacement.patch deleted file mode 100644 index 9f24389..0000000 --- a/sources/patches/FTL_last-dns_replacement.patch +++ /dev/null @@ -1,131 +0,0 @@ ---- a/args.c 2019-05-25 21:37:26.000000000 +0200 -+++ b/args.c 2020-04-24 00:32:27.000000000 +0200 -@@ -17,20 +17,88 @@ - int argc_dnsmasq = 0; - const char** argv_dnsmasq = NULL; - -+static inline bool strEndsWith(const char *input, const char *end){ -+ return strcmp(input + strlen(input) - strlen(end), end) == 0; -+} -+ - void parse_args(int argc, char* argv[]) - { -- int i; -- - // Regardless of any arguments, we always pass "-k" (nofork) to dnsmasq - argc_dnsmasq = 2; - argv_dnsmasq = calloc(argc_dnsmasq, sizeof(char*)); - argv_dnsmasq[0] = ""; - argv_dnsmasq[1] = "-k"; - -- // start from 1, as argv[0] is the executable name "pihole-FTL" -- for(i=1; i < argc; i++) -+ bool consume_for_dnsmasq = false; -+ // If the binary name is "dnsmasq" (e.g., symlink /usr/bin/dnsmasq -> /usr/bin/pihole-FTL), -+ // we operate in drop-in mode and consume all arguments for the embedded dnsmasq core -+ if(strEndsWith(argv[0], "dnsmasq")) -+ consume_for_dnsmasq = true; -+ -+ // start from 1, as argv[0] is the executable name -+ for(int i = 1; i < argc; i++) - { - bool ok = false; -+ -+ // Implement dnsmasq's test function, no need to prepare the entire FTL -+ // environment (initialize shared memory, lead queries from long-term -+ // database, ...) when the task is a simple (dnsmasq) syntax check -+ if(strcmp(argv[i], "dnsmasq-test") == 0 || -+ strcmp(argv[i], "--test") == 0) -+ { -+ const char *arg[2]; -+ arg[0] = ""; -+ arg[1] = "--test"; -+ main_dnsmasq(2, arg); -+ ok = true; -+ } -+ -+ // If we find "--" we collect everything behind that for dnsmasq -+ if(strcmp(argv[i], "--") == 0) -+ { -+ // Remember that the rest is for dnsmasq ... -+ consume_for_dnsmasq = true; -+ -+ // ... and skip the current argument ("--") -+ continue; -+ } -+ -+ // If consume_for_dnsmasq is true, we collect all remaining options for -+ // dnsmasq -+ if(consume_for_dnsmasq) -+ { -+ argc_dnsmasq = argc - i + 2; -+ if(argv_dnsmasq != NULL) -+ free(argv_dnsmasq); -+ -+ argv_dnsmasq = calloc(argc_dnsmasq, sizeof(const char*)); -+ argv_dnsmasq[0] = ""; -+ -+ if(debug) -+ argv_dnsmasq[1] = "-d"; -+ else -+ argv_dnsmasq[1] = "-k"; -+ -+ if(debug) -+ { -+ printf("dnsmasq options: [0]: %s\n", argv_dnsmasq[0]); -+ printf("dnsmasq options: [1]: %s\n", argv_dnsmasq[1]); -+ } -+ -+ int j = 2; -+ while(i < argc) -+ { -+ argv_dnsmasq[j++] = strdup(argv[i++]); -+ if(debug) -+ printf("dnsmasq options: [%i]: %s\n", j-1, argv_dnsmasq[j-1]); -+ } -+ -+ // Return early: We have consumes all available command line arguments -+ return; -+ } -+ -+ // What follows beyond this point are FTL internal command line arguments -+ - if(strcmp(argv[i], "d") == 0 || - strcmp(argv[i], "debug") == 0) - { -@@ -97,35 +165,6 @@ - ok = true; - } - -- // Implement dnsmasq's test function -- if(strcmp(argv[i], "dnsmasq-test") == 0) -- { -- const char *arg[2]; -- arg[0] = ""; -- arg[1] = "--test"; -- main_dnsmasq(2, arg); -- ok = true; -- } -- -- // If we find "--" we collect everything behind that for dnsmasq -- if(strcmp(argv[i], "--") == 0) -- { -- int j; -- argc_dnsmasq = argc - i + 1; -- if(argv_dnsmasq != NULL) free(argv_dnsmasq); -- argv_dnsmasq = calloc(argc_dnsmasq + 2,sizeof(const char*)); -- argv_dnsmasq[0] = ""; -- if(debug) argv_dnsmasq[1] = "-d"; -- else argv_dnsmasq[1] = "-k"; -- -- for(j=2; j < argc_dnsmasq; j++) -- { -- argv_dnsmasq[j] = strdup(argv[i+j-1]); -- if(debug) logg("dnsmasq options: [%i]: %s",j,argv_dnsmasq[j]); -- } -- return; -- } -- - // List of implemented arguments - if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "help") == 0 || strcmp(argv[i], "--help") == 0) - { From 08545d256b1d9ac2ad296d713e7ff67e25fca239 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 30 Jun 2021 18:04:29 +0200 Subject: [PATCH 05/20] Upgrade to 5.3.1 --- README.md | 2 +- README_fr.md | 2 +- conf/FTL_3.src | 4 ++-- conf/FTL_last.src | 6 +++--- conf/admin_dashboard_3.src | 4 ++-- conf/admin_dashboard_last.src | 6 +++--- conf/app_3.src | 4 ++-- conf/app_last.src | 6 +++--- conf/nginx.conf | 2 +- manifest.json | 6 +++--- scripts/_variables | 8 ++++---- scripts/install | 1 + scripts/upgrade | 1 + 13 files changed, 27 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index d461fbb..bb33777 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ If you don't have YunoHost, please see [here](https://yunohost.org/#/install) to ## Overview Network-wide ad blocking via your own Linux hardware -**Shipped version:** 3.3.1 or 5.0 +**Shipped version:** 3.3.1 or 5.3.1 ## Screenshots diff --git a/README_fr.md b/README_fr.md index 636f57f..23c754c 100644 --- a/README_fr.md +++ b/README_fr.md @@ -11,7 +11,7 @@ Si vous n'avez pas YunoHost, merci de regarder [ici](https://yunohost.org/#/inst ## Résumé Blocage des publicités sur l'ensemble du réseau via votre propre matériel Linux -**Version embarquée:** 3.3.1 ou 5.0 +**Version embarquée:** 3.3.1 ou 5.3.1 ## Captures d'écran diff --git a/conf/FTL_3.src b/conf/FTL_3.src index c08c993..a9e335c 100644 --- a/conf/FTL_3.src +++ b/conf/FTL_3.src @@ -1,6 +1,6 @@ SOURCE_URL=https://github.com/pi-hole/FTL/archive/v3.0.tar.gz -SOURCE_SUM=45fd33e4498b2ab9403d96e1251abb8c -SOURCE_SUM_PRG=md5sum +SOURCE_SUM=8c3d55eb3054698172e59ae81b8562ce235d73da461389840da62d90b32f0057 +SOURCE_SUM_PRG=sha256sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true SOURCE_FILENAME= diff --git a/conf/FTL_last.src b/conf/FTL_last.src index f6e3f41..463dd0c 100644 --- a/conf/FTL_last.src +++ b/conf/FTL_last.src @@ -1,6 +1,6 @@ -SOURCE_URL=https://github.com/pi-hole/FTL/archive/v5.0.tar.gz -SOURCE_SUM=a405fee9a924324eefe6bfb832180c3d -SOURCE_SUM_PRG=md5sum +SOURCE_URL=https://github.com/pi-hole/FTL/archive/v5.8.1.tar.gz +SOURCE_SUM=6177f775a8d0be703b235741befe90b6192bdc0baab5a6e028019a9af00a44ae +SOURCE_SUM_PRG=sha256sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true SOURCE_FILENAME= diff --git a/conf/admin_dashboard_3.src b/conf/admin_dashboard_3.src index 410936c..8f65ffe 100644 --- a/conf/admin_dashboard_3.src +++ b/conf/admin_dashboard_3.src @@ -1,6 +1,6 @@ SOURCE_URL=https://github.com/pi-hole/AdminLTE/archive/v3.3.tar.gz -SOURCE_SUM=23368537fa576480e45f625b5e1a7cd7 -SOURCE_SUM_PRG=md5sum +SOURCE_SUM=caba2129fe8753b0c7aaf611b7c7b2146ff1ac56d5ac58987053b1553d09c49f +SOURCE_SUM_PRG=sha256sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true SOURCE_FILENAME= diff --git a/conf/admin_dashboard_last.src b/conf/admin_dashboard_last.src index 25b95ff..0e3c61c 100644 --- a/conf/admin_dashboard_last.src +++ b/conf/admin_dashboard_last.src @@ -1,6 +1,6 @@ -SOURCE_URL=https://github.com/pi-hole/AdminLTE/archive/v5.0.tar.gz -SOURCE_SUM=9402041b365e78a02a95942bdd3c3c05 -SOURCE_SUM_PRG=md5sum +SOURCE_URL=https://github.com/pi-hole/AdminLTE/archive/v5.5.tar.gz +SOURCE_SUM=39340eeb115732db7cf96166dfa9c7240afb0843b4f49defc42e704b751cf278 +SOURCE_SUM_PRG=sha256sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true SOURCE_FILENAME= diff --git a/conf/app_3.src b/conf/app_3.src index 74230e9..ac08837 100644 --- a/conf/app_3.src +++ b/conf/app_3.src @@ -1,6 +1,6 @@ SOURCE_URL=https://github.com/pi-hole/pi-hole/archive/v3.3.1.tar.gz -SOURCE_SUM=ea4f64bdf88620f59a1b01c19253e4e3 -SOURCE_SUM_PRG=md5sum +SOURCE_SUM=6a80e4b6b38fc65df83459fe52f3a61623763709a077645f25ac9e29247e6d6d +SOURCE_SUM_PRG=sha256sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true SOURCE_FILENAME= diff --git a/conf/app_last.src b/conf/app_last.src index 4836f9a..efeaefa 100644 --- a/conf/app_last.src +++ b/conf/app_last.src @@ -1,6 +1,6 @@ -SOURCE_URL=https://github.com/pi-hole/pi-hole/archive/v5.0.tar.gz -SOURCE_SUM=0f19aeefad3063c44f421de1ad21b233 -SOURCE_SUM_PRG=md5sum +SOURCE_URL=https://github.com/pi-hole/pi-hole/archive/v5.3.1.tar.gz +SOURCE_SUM=19c856584f180b2ed5b3d0500cd3567f00e37fa9c493282bc119be8276cdddd9 +SOURCE_SUM_PRG=sha256sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true SOURCE_FILENAME= diff --git a/conf/nginx.conf b/conf/nginx.conf index 166d57b..647da87 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -14,7 +14,7 @@ location __PATH__/ { try_files $uri $uri/ index.php; location ~ [^/]\.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; - fastcgi_pass unix:/var/run/php/php7.0-fpm-__NAME__.sock; + fastcgi_pass unix:/var/run/php/php7.3-fpm-__NAME__.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param REMOTE_USER $remote_user; diff --git a/manifest.json b/manifest.json index b561183..f811709 100644 --- a/manifest.json +++ b/manifest.json @@ -6,7 +6,7 @@ "en": "Network-wide ad blocking via your own DNS server.", "fr": "Filtrage publicitaire sur l'ensemble du réseau via votre propre serveur DNS." }, - "version": "5.0~ynh1", + "version": "5.3.1~ynh1", "url": "https://pi-hole.net/", "license": "EUPL-1.2", "maintainer": { @@ -14,12 +14,12 @@ "email": "maniackc_dev@crudelis.fr" }, "requirements": { - "yunohost": ">= 3.8" + "yunohost": ">= 4.2" }, "multi_instance": false, "services": [ "nginx", - "php7.0-fpm" + "php7.3-fpm" ], "arguments": { "install" : [ diff --git a/scripts/_variables b/scripts/_variables index 331ded1..a08ca42 100644 --- a/scripts/_variables +++ b/scripts/_variables @@ -1,7 +1,7 @@ #!/bin/bash # Dependencies -app_depencencies="sqlite idn2 php7.0-sqlite3 nettle-dev libcap2-bin" +app_depencencies="sqlite3 idn2 php7.3-sqlite3 nettle-dev libcap2-bin build-essential libgmp-dev m4 cmake libidn11-dev libreadline-dev xxd" if [ "$YNH_APP_ARG_PIHOLE_VERSION" == "Last 3.X" ] then @@ -9,7 +9,7 @@ then dashboard_version=3.3 FTL_version=3.0 else - pihole_core_version=5.0 - dashboard_version=5.0 - FTL_version=5.0 + pihole_core_version=5.3.1 + dashboard_version=5.5 + FTL_version=5.8.1 fi diff --git a/scripts/install b/scripts/install index 4f17c8d..39cc6e7 100644 --- a/scripts/install +++ b/scripts/install @@ -217,6 +217,7 @@ fi # Instead of downloading a binary file, we're going to compile it ( cd "$FTL_temp_path" +ynh_exec_warn_less cmake . ynh_exec_warn_less make ynh_exec_warn_less make install ) ynh_secure_remove --file="$FTL_temp_path" diff --git a/scripts/upgrade b/scripts/upgrade index d1e393e..7918816 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -257,6 +257,7 @@ then # Instead of downloading a binary file, we're going to compile it ( cd "$FTL_temp_path" + ynh_exec_warn_less cmake . ynh_exec_warn_less make ynh_exec_warn_less make install ) ynh_secure_remove --file="$FTL_temp_path" From 3ca5858000fcf1e7a3e5e46f3e2e66b086b46773 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 30 Jun 2021 18:04:43 +0200 Subject: [PATCH 06/20] patch ynh_add_fpm_config --- scripts/_ynh_add_fpm_config.sh | 203 +++++++++++++++++++++++++++ scripts/actions/reset_default_system | 1 + scripts/config | 1 + scripts/install | 1 + scripts/restore | 1 + scripts/upgrade | 1 + 6 files changed, 208 insertions(+) create mode 100644 scripts/_ynh_add_fpm_config.sh diff --git a/scripts/_ynh_add_fpm_config.sh b/scripts/_ynh_add_fpm_config.sh new file mode 100644 index 0000000..c0aa0aa --- /dev/null +++ b/scripts/_ynh_add_fpm_config.sh @@ -0,0 +1,203 @@ +#!/bin/bash + +# To be removed after the 4.3 + +ynh_add_fpm_config () { + # Declare an array to define the options of this helper. + local legacy_args=vtufpd + local -A args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service ) + local phpversion + local use_template + local usage + local footprint + local package + local dedicated_service + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + package=${package:-} + + # The default behaviour is to use the template. + use_template="${use_template:-1}" + usage="${usage:-}" + footprint="${footprint:-}" + if [ -n "$usage" ] || [ -n "$footprint" ]; then + use_template=0 + fi + # Do not use a dedicated service by default + dedicated_service=${dedicated_service:-0} + + # Set the default PHP-FPM version by default + phpversion="${phpversion:-$YNH_PHP_VERSION}" + + local old_phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) + + # If the PHP version changed, remove the old fpm conf + if [ -n "$old_phpversion" ] && [ "$old_phpversion" != "$phpversion" ] + then + local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) + local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf" + + ynh_backup_if_checksum_is_different --file="$old_php_finalphpconf" + + ynh_remove_fpm_config + fi + + # If the requested PHP version is not the default version for YunoHost + if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] + then + # If the argument --package is used, add the packages to ynh_install_php to install them from sury + if [ -n "$package" ] + then + local additionnal_packages="--package=$package" + else + local additionnal_packages="" + fi + # Install this specific version of PHP. + ynh_install_php --phpversion="$phpversion" "$additionnal_packages" + elif [ -n "$package" ] + then + # Install the additionnal packages from the default repository + ynh_add_app_dependencies --package="$package" + fi + + if [ $dedicated_service -eq 1 ] + then + local fpm_service="${app}-phpfpm" + local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm" + else + local fpm_service="php${phpversion}-fpm" + local fpm_config_dir="/etc/php/$phpversion/fpm" + fi + + # Create the directory for FPM pools + mkdir --parents "$fpm_config_dir/pool.d" + + ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir" + ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" + ynh_app_setting_set --app=$app --key=fpm_dedicated_service --value="$dedicated_service" + ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion + + # Migrate from mutual PHP service to dedicated one. + if [ $dedicated_service -eq 1 ] + then + local old_fpm_config_dir="/etc/php/$phpversion/fpm" + # If a config file exist in the common pool, move it. + if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ] + then + ynh_print_info --message="Migrate to a dedicated php-fpm service for $app." + # Create a backup of the old file before migration + ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf" + # Remove the old PHP config file + ynh_secure_remove --file="$old_fpm_config_dir/pool.d/$app.conf" + # Reload PHP to release the socket and allow the dedicated service to use it + ynh_systemd_action --service_name=php${phpversion}-fpm --action=reload + fi + fi + + if [ $use_template -eq 1 ] + then + # Usage 1, use the template in conf/php-fpm.conf + local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf" + # Make sure now that the template indeed exists + [ -e "$phpfpm_path" ] || ynh_die --message="Unable to find template to configure PHP-FPM." + else + # Usage 2, generate a PHP-FPM config file with ynh_get_scalable_phpfpm + + # Store settings + ynh_app_setting_set --app=$app --key=fpm_footprint --value=$footprint + ynh_app_setting_set --app=$app --key=fpm_usage --value=$usage + + # Define the values to use for the configuration of PHP. + ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint + + local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf" + echo " +[__APP__] +user = __APP__ +group = __APP__ +chdir = __FINALPATH__ +listen = /var/run/php/php__PHPVERSION__-fpm-__APP__.sock +listen.owner = www-data +listen.group = www-data +pm = __PHP_PM__ +pm.max_children = __PHP_MAX_CHILDREN__ +pm.max_requests = 500 +request_terminate_timeout = 1d +" > $phpfpm_path + + if [ "$php_pm" = "dynamic" ] + then + echo " +pm.start_servers = __PHP_START_SERVERS__ +pm.min_spare_servers = __PHP_MIN_SPARE_SERVERS__ +pm.max_spare_servers = __PHP_MAX_SPARE_SERVERS__ +" >> $phpfpm_path + + elif [ "$php_pm" = "ondemand" ] + then + echo " +pm.process_idle_timeout = 10s +" >> $phpfpm_path + fi + + # Concatene the extra config. + if [ -e $YNH_APP_BASEDIR/conf/extra_php-fpm.conf ]; then + cat $YNH_APP_BASEDIR/conf/extra_php-fpm.conf >> "$phpfpm_path" + fi + fi + + local finalphpconf="$fpm_config_dir/pool.d/$app.conf" + ynh_add_config --template="$phpfpm_path" --destination="$finalphpconf" + + if [ -e "$YNH_APP_BASEDIR/conf/php-fpm.ini" ] + then + ynh_print_warn --message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." + ynh_add_config --template="$YNH_APP_BASEDIR/conf/php-fpm.ini" --destination="$fpm_config_dir/conf.d/20-$app.ini" + fi + + if [ $dedicated_service -eq 1 ] + then + # Create a dedicated php-fpm.conf for the service + local globalphpconf=$fpm_config_dir/php-fpm-$app.conf + +echo "[global] +pid = /run/php/php__PHPVERSION__-fpm-__APP__.pid +error_log = /var/log/php/fpm-php.__APP__.log +syslog.ident = php-fpm-__APP__ +include = __FINALPHPCONF__ +" > $YNH_APP_BASEDIR/conf/php-fpm-$app.conf + + ynh_add_config --template="$YNH_APP_BASEDIR/conf/php-fpm-$app.conf" --destination="$globalphpconf" + + # Create a config for a dedicated PHP-FPM service for the app + echo "[Unit] +Description=PHP __PHPVERSION__ FastCGI Process Manager for __APP__ +After=network.target +[Service] +Type=notify +PIDFile=/run/php/php__PHPVERSION__-fpm-__APP__.pid +ExecStart=/usr/sbin/php-fpm__PHPVERSION__ --nodaemonize --fpm-config __GLOBALPHPCONF__ +ExecReload=/bin/kill -USR2 \$MAINPID +[Install] +WantedBy=multi-user.target +" > $YNH_APP_BASEDIR/conf/$fpm_service + + # Create this dedicated PHP-FPM service + ynh_add_systemd_config --service=$fpm_service --template=$fpm_service + # Integrate the service in YunoHost admin panel + yunohost service add $fpm_service --log /var/log/php/fpm-php.$app.log --description "Php-fpm dedicated to $app" + # Configure log rotate + ynh_use_logrotate --logfile=/var/log/php + # Restart the service, as this service is either stopped or only for this app + ynh_systemd_action --service_name=$fpm_service --action=restart + else + # Validate that the new php conf doesn't break php-fpm entirely + if ! php-fpm${phpversion} --test 2>/dev/null + then + php-fpm${phpversion} --test || true + ynh_secure_remove --file="$finalphpconf" + ynh_die --message="The new configuration broke php-fpm?" + fi + ynh_systemd_action --service_name=$fpm_service --action=reload + fi +} \ No newline at end of file diff --git a/scripts/actions/reset_default_system b/scripts/actions/reset_default_system index c760535..98c719c 100755 --- a/scripts/actions/reset_default_system +++ b/scripts/actions/reset_default_system @@ -8,6 +8,7 @@ source scripts/_common.sh source /usr/share/yunohost/helpers +source _ynh_add_fpm_config.sh #================================================= # MANAGE SCRIPT FAILURE diff --git a/scripts/config b/scripts/config index 02a2d40..25f01d3 100644 --- a/scripts/config +++ b/scripts/config @@ -8,6 +8,7 @@ source _common.sh source /usr/share/yunohost/helpers +source _ynh_add_fpm_config.sh #================================================= # RETRIEVE ARGUMENTS diff --git a/scripts/install b/scripts/install index 39cc6e7..159716d 100644 --- a/scripts/install +++ b/scripts/install @@ -11,6 +11,7 @@ source _variables source _common.sh source /usr/share/yunohost/helpers +source _ynh_add_fpm_config.sh #================================================= # MANAGE FAILURE OF THE SCRIPT diff --git a/scripts/restore b/scripts/restore index d2a3c99..6afc7c4 100644 --- a/scripts/restore +++ b/scripts/restore @@ -11,6 +11,7 @@ source ../settings/scripts/_variables source ../settings/scripts/_common.sh source /usr/share/yunohost/helpers +source ../settings/scripts/_ynh_add_fpm_config.sh #================================================= # MANAGE SCRIPT FAILURE diff --git a/scripts/upgrade b/scripts/upgrade index 7918816..20a9d1b 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -11,6 +11,7 @@ source _variables source _common.sh source /usr/share/yunohost/helpers +source _ynh_add_fpm_config.sh #================================================= # LOAD SETTINGS From 5efb292a9ac9ae7a0286545f8caa9be752ab0926 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 30 Jun 2021 18:44:50 +0200 Subject: [PATCH 07/20] fix files permissions --- scripts/actions/reset_default_app | 19 +++++++++++-------- scripts/install | 18 ++++++++++-------- scripts/upgrade | 18 ++++++++++-------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/scripts/actions/reset_default_app b/scripts/actions/reset_default_app index 5cc74fc..3f44058 100755 --- a/scripts/actions/reset_default_app +++ b/scripts/actions/reset_default_app @@ -42,6 +42,14 @@ ynh_script_progression --message="Activating maintenance mode..." --time --weigh ynh_maintenance_mode_ON +#================================================= +# CREATE DEDICATED USER +#================================================= +ynh_script_progression --message="Making sure dedicated system user exists..." --time --weight=1 + +# Create a dedicated user (if not existing) +ynh_system_user_create --username=$app + #================================================= # DOWNLOAD, CHECK AND UNPACK SOURCE #================================================= @@ -62,6 +70,9 @@ else # Overwrite admin dashboard YNH_CWD=$PWD ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard_last fi + +chown -R $app:www-data "$final_path" + ) #================================================= @@ -72,14 +83,6 @@ ynh_script_progression --message="Resetting nginx web server configuration..." - # Create a dedicated nginx config yunohost app action run $app reset_default_nginx -#================================================= -# CREATE DEDICATED USER -#================================================= -ynh_script_progression --message="Making sure dedicated system user exists..." --time --weight=1 - -# Create a dedicated user (if not existing) -ynh_system_user_create --username=$app - #================================================= # PHP-FPM CONFIGURATION #================================================= diff --git a/scripts/install b/scripts/install index 159716d..0e2725b 100644 --- a/scripts/install +++ b/scripts/install @@ -90,6 +90,14 @@ ynh_script_progression --message="Installing dependencies..." --weight=12 ynh_install_app_dependencies $app_depencencies +#================================================= +# CREATE DEDICATED USER +#================================================= +ynh_script_progression --message="Configuring system user..." --weight=2 + +# Create a dedicated system user +ynh_system_user_create --username=$app + #================================================= # DOWNLOAD, CHECK AND UNPACK SOURCE #================================================= @@ -111,6 +119,8 @@ else ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard_last fi +chown -R $app:www-data "$final_path" + #================================================= # NGINX CONFIGURATION #================================================= @@ -119,14 +129,6 @@ ynh_script_progression --message="Configuring nginx web server..." --weight=2 # Create a dedicated nginx config ynh_add_nginx_config -#================================================= -# CREATE DEDICATED USER -#================================================= -ynh_script_progression --message="Configuring system user..." --weight=2 - -# Create a dedicated system user -ynh_system_user_create --username=$app - #================================================= # PHP-FPM CONFIGURATION #================================================= diff --git a/scripts/upgrade b/scripts/upgrade index 20a9d1b..83ca487 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -133,6 +133,14 @@ ynh_script_progression --message="Upgrading dependencies..." --weight=6 ynh_install_app_dependencies $app_depencencies +#================================================= +# CREATE DEDICATED USER +#================================================= +ynh_script_progression --message="Making sure dedicated system user exists..." + +# Create a dedicated user (if not existing) +ynh_system_user_create --username=$app + #================================================= # DOWNLOAD, CHECK AND UNPACK SOURCE #================================================= @@ -155,6 +163,8 @@ then fi fi +chown -R $app:www-data "$final_path" + #================================================= # NGINX CONFIGURATION #================================================= @@ -167,14 +177,6 @@ then ynh_add_nginx_config fi -#================================================= -# CREATE DEDICATED USER -#================================================= -ynh_script_progression --message="Making sure dedicated system user exists..." - -# Create a dedicated user (if not existing) -ynh_system_user_create --username=$app - #================================================= # PHP-FPM CONFIGURATION #================================================= From 1f04e5b1389bcd9b7ec93f86ea168b227b176b64 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Thu, 1 Jul 2021 01:48:47 +0200 Subject: [PATCH 08/20] fix upgrade/restore scripts --- scripts/actions/reset_default_app | 2 +- scripts/install | 7 +++++-- scripts/restore | 1 + scripts/upgrade | 7 +++++-- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/scripts/actions/reset_default_app b/scripts/actions/reset_default_app index 3f44058..ea606ed 100755 --- a/scripts/actions/reset_default_app +++ b/scripts/actions/reset_default_app @@ -71,7 +71,7 @@ else YNH_CWD=$PWD ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard_last fi -chown -R $app:www-data "$final_path" +chown $app:www-data "$final_path" ) diff --git a/scripts/install b/scripts/install index 0e2725b..a545390 100644 --- a/scripts/install +++ b/scripts/install @@ -119,7 +119,7 @@ else ynh_setup_source --dest_dir="$final_path" --source_id=admin_dashboard_last fi -chown -R $app:www-data "$final_path" +chown $app:www-data "$final_path" #================================================= # NGINX CONFIGURATION @@ -220,7 +220,10 @@ fi # Instead of downloading a binary file, we're going to compile it ( cd "$FTL_temp_path" -ynh_exec_warn_less cmake . +if [ "$pihole_version" == "Last available" ] +then + ynh_exec_warn_less cmake . +fi ynh_exec_warn_less make ynh_exec_warn_less make install ) ynh_secure_remove --file="$FTL_temp_path" diff --git a/scripts/restore b/scripts/restore index 6afc7c4..d76a18c 100644 --- a/scripts/restore +++ b/scripts/restore @@ -176,6 +176,7 @@ then # https://github.com/pi-hole/FTL/tree/master/dnsmasq ln -s /usr/bin/pihole-FTL /usr/sbin/dnsmasq + pihole_local_repo="/etc/.pihole" cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL chmod +x /etc/init.d/pihole-FTL ynh_exec_warn_less systemctl enable pihole-FTL diff --git a/scripts/upgrade b/scripts/upgrade index 83ca487..e0426df 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -163,7 +163,7 @@ then fi fi -chown -R $app:www-data "$final_path" +chown $app:www-data "$final_path" #================================================= # NGINX CONFIGURATION @@ -260,7 +260,10 @@ then # Instead of downloading a binary file, we're going to compile it ( cd "$FTL_temp_path" - ynh_exec_warn_less cmake . + if [ "$pihole_version" == "Last available" ] + then + ynh_exec_warn_less cmake . + fi ynh_exec_warn_less make ynh_exec_warn_less make install ) ynh_secure_remove --file="$FTL_temp_path" From 4446f8750b6b23854a1db5525effcdb17d2a93dd Mon Sep 17 00:00:00 2001 From: Kay0u Date: Fri, 2 Jul 2021 16:58:08 +0200 Subject: [PATCH 09/20] fix upgrade and config --- scripts/config | 1 + scripts/upgrade | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/config b/scripts/config index 25f01d3..4a29c5b 100644 --- a/scripts/config +++ b/scripts/config @@ -17,6 +17,7 @@ source _ynh_add_fpm_config.sh app=$YNH_APP_INSTANCE_NAME fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) +final_path=$(ynh_app_setting_get --app=$app --key=final_path) #================================================= # SPECIFIC CODE diff --git a/scripts/upgrade b/scripts/upgrade index e0426df..6b05774 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -232,10 +232,11 @@ pihole_storage="/etc/pihole" if [ "$pihole_version" == "Last 3.X" ] then cp "$pihole_local_repo/advanced/logrotate" "$pihole_storage/logrotate" + dnsmasq_user=$(grep DNSMASQ_USER= /etc/init.d/dnsmasq | cut -d'"' -f2) else cp "$pihole_local_repo/advanced/Templates/logrotate" "$pihole_storage/logrotate" + dnsmasq_user=$(grep FTLUSER= /etc/init.d/pihole-FTL | cut -d'=' -f2) fi -dnsmasq_user=$(grep DNSMASQ_USER= /etc/init.d/dnsmasq | cut -d'"' -f2) sed -i "/# su #/d;" "$pihole_storage/logrotate" #================================================= From 13fec5955ec9c0efa6357e580c18b56eaf57f75b Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 7 Jul 2021 12:08:04 +0200 Subject: [PATCH 10/20] remove some warnings --- check_process | 2 +- scripts/_common.sh | 94 +--------------------------------------------- scripts/install | 2 +- scripts/upgrade | 18 +++++++-- 4 files changed, 18 insertions(+), 98 deletions(-) diff --git a/check_process b/check_process index 96ed247..40e8bbc 100644 --- a/check_process +++ b/check_process @@ -40,7 +40,7 @@ pihole_version="Last 3.X" ; Checks setup_sub_dir=1 - setup_root=0 + setup_root=1 upgrade=1 upgrade=1 from_commit=d79ec131b3038ff4695c3317b5d3ee4eda9c8932 backup_restore=1 diff --git a/scripts/_common.sh b/scripts/_common.sh index 5c8cf50..8d3534c 100755 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -4,83 +4,6 @@ # FUTUR OFFICIAL HELPERS #================================================= -# Install or update the main directory yunohost.multimedia -# -# usage: ynh_multimedia_build_main_dir -ynh_multimedia_build_main_dir () { - local ynh_media_release="v1.2" - local checksum="806a827ba1902d6911095602a9221181" - - # Download yunohost.multimedia scripts - wget -nv https://github.com/YunoHost-Apps/yunohost.multimedia/archive/${ynh_media_release}.tar.gz - - # Check the control sum - echo "${checksum} ${ynh_media_release}.tar.gz" | md5sum -c --status \ - || ynh_die "Corrupt source" - - # Check if the package acl is installed. Or install it. - ynh_package_is_installed 'acl' \ - || ynh_package_install acl - - # Extract - mkdir yunohost.multimedia-master - tar -xf ${ynh_media_release}.tar.gz -C yunohost.multimedia-master --strip-components 1 - ./yunohost.multimedia-master/script/ynh_media_build.sh -} - -# Add a directory in yunohost.multimedia -# This "directory" will be a symbolic link to a existing directory. -# -# usage: ynh_multimedia_addfolder "Source directory" "Destination directory" -# -# | arg: -s, --source_dir= - Source directory - The real directory which contains your medias. -# | arg: -d, --dest_dir= - Destination directory - The name and the place of the symbolic link, relative to "/home/yunohost.multimedia" -ynh_multimedia_addfolder () { - # Declare an array to define the options of this helper. - declare -Ar args_array=( [s]=source_dir= [d]=dest_dir= ) - local source_dir - local dest_dir - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - - ./yunohost.multimedia-master/script/ynh_media_addfolder.sh --source="$source_dir" --dest="$dest_dir" -} - -# Move a directory in yunohost.multimedia, and replace by a symbolic link -# -# usage: ynh_multimedia_movefolder "Source directory" "Destination directory" -# -# | arg: -s, --source_dir= - Source directory - The real directory which contains your medias. -# It will be moved to "Destination directory" -# A symbolic link will replace it. -# | arg: -d, --dest_dir= - Destination directory - The new name and place of the directory, relative to "/home/yunohost.multimedia" -ynh_multimedia_movefolder () { - # Declare an array to define the options of this helper. - declare -Ar args_array=( [s]=source_dir= [d]=dest_dir= ) - local source_dir - local dest_dir - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - - ./yunohost.multimedia-master/script/ynh_media_addfolder.sh --inv --source="$source_dir" --dest="$dest_dir" -} - -# Allow an user to have an write authorisation in multimedia directories -# -# usage: ynh_multimedia_addaccess user_name -# -# | arg: -u, --user_name= - The name of the user which gain this access. -ynh_multimedia_addaccess () { - # Declare an array to define the options of this helper. - declare -Ar args_array=( [u]=user_name=) - local user_name - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - - groupadd -f multimedia - usermod -a -G multimedia $user_name -} - #================================================= # EXPERIMENTAL HELPERS #================================================= @@ -441,19 +364,4 @@ ynh_app_changelog () { then echo "No significative changes from the changelog..." > "${final_changelog}_lite" fi -} - -#================================================= - -# Execute a command as another user -# usage: exec_as USER COMMAND [ARG ...] -ynh_exec_as() { - local USER=$1 - shift 1 - - if [[ $USER = $(whoami) ]]; then - eval "$@" - else - sudo -u "$USER" "$@" - fi -} +} \ No newline at end of file diff --git a/scripts/install b/scripts/install index a545390..620da12 100644 --- a/scripts/install +++ b/scripts/install @@ -455,7 +455,7 @@ yunohost service add pihole-FTL --description "PiHole backend service" --log "/v #================================================= ynh_script_progression --message="Restraining the access to the admin only..." --weight=2 -yunohost app addaccess --users=$admin $app +ynh_permission_update --permission="main" --add="$admin" --remove="all_users" #================================================= # RELOAD NGINX diff --git a/scripts/upgrade b/scripts/upgrade index 6b05774..2d5b20a 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -295,11 +295,17 @@ else ynh_exec_warn_less systemctl disable dnsmasq # And move the files that make the service available in systemd to really disable it - mv /lib/systemd/system/dnsmasq.service /lib/systemd/system/.dnsmasq.service.backup_by_pihole - mv /etc/init.d/dnsmasq /etc/init.d/.dnsmasq.backup_by_pihole + if [ ! -e "/lib/systemd/system/.dnsmasq.service.backup_by_pihole" ]; then + mv /lib/systemd/system/dnsmasq.service /lib/systemd/system/.dnsmasq.service.backup_by_pihole + fi + if [ ! -e "/etc/init.d/.dnsmasq.backup_by_pihole" ]; then + mv /etc/init.d/dnsmasq /etc/init.d/.dnsmasq.backup_by_pihole + fi # Move dnsmasq to preserve the current binary - mv /usr/sbin/dnsmasq /usr/sbin/dnsmasq.backup_by_pihole + if [ ! -e "/usr/sbin/dnsmasq.backup_by_pihole" ]; then + mv /usr/sbin/dnsmasq /usr/sbin/dnsmasq.backup_by_pihole + fi # Replace dnsmasq by pihole-FTL # NOTE: pihole-FTL is actually a modified version of dnsmasq # https://github.com/pi-hole/FTL/tree/master/dnsmasq @@ -368,6 +374,12 @@ ynh_script_progression --message="Restarting PiHole-FTL..." --weight=2 ynh_systemd_action --action=restart --service_name=pihole-FTL +#================================================= +# ADVERTISE SERVICE IN ADMIN PANEL +#================================================= + +yunohost service add pihole-FTL --description "PiHole backend service" --log "/var/log/pihole-FTL.log" + #================================================= # UPDATE CONF_REGEN HOOK #================================================= From d768b4789171ee69e9d12fff0ea632d6bab1f596 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Tue, 20 Jul 2021 15:32:50 +0200 Subject: [PATCH 11/20] fix upgrade, again --- scripts/upgrade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/upgrade b/scripts/upgrade index 2d5b20a..f7989cc 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -309,7 +309,7 @@ else # Replace dnsmasq by pihole-FTL # NOTE: pihole-FTL is actually a modified version of dnsmasq # https://github.com/pi-hole/FTL/tree/master/dnsmasq - ln -s /usr/bin/pihole-FTL /usr/sbin/dnsmasq + ln -sf /usr/bin/pihole-FTL /usr/sbin/dnsmasq cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL chmod +x /etc/init.d/pihole-FTL @@ -317,7 +317,7 @@ else # Replace the service dnsmasq by pihole-FTL # That way, YunoHost can continue to use dnsmasq by actually using pihole-FTL - ln -s /run/systemd/generator.late/pihole-FTL.service /etc/systemd/system/multi-user.target.wants/dnsmasq.service + ln -sf /run/systemd/generator.late/pihole-FTL.service /etc/systemd/system/multi-user.target.wants/dnsmasq.service # Reload systemd config systemctl daemon-reload From 5cc36704402d1ce815fe288a82bc0e64425cba32 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Mon, 9 Aug 2021 17:46:59 +0200 Subject: [PATCH 12/20] Remove temp fix, bump ynh requirement --- manifest.json | 2 +- scripts/actions/reset_default_system | 1 - scripts/config | 1 - scripts/install | 1 - scripts/restore | 1 - scripts/upgrade | 1 - 6 files changed, 1 insertion(+), 6 deletions(-) diff --git a/manifest.json b/manifest.json index bc8dd25..8da8fb2 100644 --- a/manifest.json +++ b/manifest.json @@ -18,7 +18,7 @@ "email": "maniackc_dev@crudelis.fr" }], "requirements": { - "yunohost": ">= 4.2" + "yunohost": ">= 4.2.7" }, "multi_instance": false, "services": [ diff --git a/scripts/actions/reset_default_system b/scripts/actions/reset_default_system index 98c719c..c760535 100755 --- a/scripts/actions/reset_default_system +++ b/scripts/actions/reset_default_system @@ -8,7 +8,6 @@ source scripts/_common.sh source /usr/share/yunohost/helpers -source _ynh_add_fpm_config.sh #================================================= # MANAGE SCRIPT FAILURE diff --git a/scripts/config b/scripts/config index 4a29c5b..fef8388 100644 --- a/scripts/config +++ b/scripts/config @@ -8,7 +8,6 @@ source _common.sh source /usr/share/yunohost/helpers -source _ynh_add_fpm_config.sh #================================================= # RETRIEVE ARGUMENTS diff --git a/scripts/install b/scripts/install index 620da12..6beb5fa 100644 --- a/scripts/install +++ b/scripts/install @@ -11,7 +11,6 @@ source _variables source _common.sh source /usr/share/yunohost/helpers -source _ynh_add_fpm_config.sh #================================================= # MANAGE FAILURE OF THE SCRIPT diff --git a/scripts/restore b/scripts/restore index d76a18c..2d7391d 100644 --- a/scripts/restore +++ b/scripts/restore @@ -11,7 +11,6 @@ source ../settings/scripts/_variables source ../settings/scripts/_common.sh source /usr/share/yunohost/helpers -source ../settings/scripts/_ynh_add_fpm_config.sh #================================================= # MANAGE SCRIPT FAILURE diff --git a/scripts/upgrade b/scripts/upgrade index f7989cc..b31b189 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -11,7 +11,6 @@ source _variables source _common.sh source /usr/share/yunohost/helpers -source _ynh_add_fpm_config.sh #================================================= # LOAD SETTINGS From 3c22639cae34462e5bcb6ce308c771c845ecb4e5 Mon Sep 17 00:00:00 2001 From: ericgaspar Date: Mon, 9 Aug 2021 20:10:55 +0200 Subject: [PATCH 13/20] Fix --- scripts/backup | 14 ++++++-------- scripts/change_url | 6 +++--- scripts/install | 16 +++++++++------- scripts/remove | 10 +++++----- scripts/restore | 6 +++--- scripts/upgrade | 19 ++++++------------- 6 files changed, 32 insertions(+), 39 deletions(-) diff --git a/scripts/backup b/scripts/backup index 1913355..2202c71 100644 --- a/scripts/backup +++ b/scripts/backup @@ -19,7 +19,7 @@ ynh_abort_if_errors #================================================= # LOAD SETTINGS #================================================= -ynh_script_progression --message="Loading installation settings..." --weight=2 +ynh_print_info --message="Loading installation settings..." app=$YNH_APP_INSTANCE_NAME @@ -31,11 +31,13 @@ domain=$(ynh_app_setting_get --app=$app --key=domain) fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) #================================================= -# STANDARD BACKUP STEPS +# DECLARE DATA AND CONF FILES TO BACKUP +#================================================= +ynh_print_info --message="Declaring files to be backed up..." + #================================================= # BACKUP THE MAIN APP DIRECTORIES #================================================= -ynh_script_progression --message="Backing up the main app directory..." --weight=5 ynh_backup --src_path="$final_path" ynh_backup --src_path="/etc/.pihole" @@ -45,14 +47,12 @@ ynh_backup --src_path="/opt/pihole" #================================================= # BACKUP NGINX CONFIGURATION #================================================= -ynh_script_progression --message="Backing up nginx web server configuration..." ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf" #================================================= # BACKUP PHP-FPM CONFIGURATION #================================================= -ynh_script_progression --message="Backing up php-fpm configuration..." ynh_backup --src_path="$fpm_config_dir/php-fpm-$app.conf" ynh_backup --src_path="$fpm_config_dir/pool.d/$app.conf" @@ -62,14 +62,12 @@ ynh_backup --src_path="$fpm_config_dir/pool.d/$app.conf" #================================================= # BACKUP CRON FILE #================================================= -ynh_script_progression --message="Backing up cron file..." ynh_backup --src_path="/etc/cron.d/pihole" #================================================= # BACKUP SPECIFIC FILES #================================================= -ynh_script_progression --message="Backing specific files..." ynh_backup --src_path="/usr/local/bin/pihole" ynh_backup --src_path="/etc/bash_completion.d/pihole" @@ -96,4 +94,4 @@ ynh_backup --src_path="/usr/share/yunohost/hooks/conf_regen/50-dnsmasq_$app" # END OF SCRIPT #================================================= -ynh_script_progression --message="Backup script completed for $app. (YunoHost will then actually copy those files to the archive)." --last +ynh_print_info --message="Backup script completed for $app. (YunoHost will then actually copy those files to the archive)." diff --git a/scripts/change_url b/scripts/change_url index 1afb28e..b6adf0b 100644 --- a/scripts/change_url +++ b/scripts/change_url @@ -31,7 +31,7 @@ final_path=$(ynh_app_setting_get --app=$app --key=final_path) #================================================= # BACKUP BEFORE UPGRADE THEN ACTIVE TRAP #================================================= -ynh_script_progression --message="Backing up the app before changing its url (may take a while)..." --weight=11 +ynh_script_progression --message="Backing up the app before changing its URL (may take a while)..." --weight=11 # Backup the current version of the app ynh_backup_before_upgrade @@ -75,7 +75,7 @@ fi #================================================= # MODIFY URL IN NGINX CONF #================================================= -ynh_script_progression --message="Updating nginx web server configuration..." --weight=4 +ynh_script_progression --message="Updating NGINX web server configuration..." --weight=4 nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf @@ -109,7 +109,7 @@ fi #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." +ynh_script_progression --message="Reloading NGINX web server..." ynh_systemd_action --service_name=nginx --action=reload diff --git a/scripts/install b/scripts/install index 6beb5fa..614fc69 100644 --- a/scripts/install +++ b/scripts/install @@ -66,14 +66,16 @@ ynh_app_setting_set --app=$app --key=admin_mail_html --value=1 #================================================= # FIND AND OPEN A PORT #================================================= -ynh_script_progression --message="Configuring firewall..." --weight=12 +ynh_script_progression --message="Finding an available port..." --weight=12 # Find a free port port=$(ynh_find_port --port=4711) if [ $port -gt 4720 ] then - ynh_die --message="The ports 4711 to 4720 are already in use. Pi-hole can't works on another port. Please try to free one of this ports." + ynh_die --message="The ports 4711 to 4720 are already in use. Pi-hole can't work on another port. Please try to free one of these ports." fi + +ynh_script_progression --message="Configuring firewall..." --weight=1 # Open this port ynh_exec_fully_quiet yunohost firewall allow --no-upnp TCP $port ynh_app_setting_set --app=$app --key=port --value=$port @@ -238,14 +240,14 @@ then # Version 3.3.1 cp -a $pihole_local_repo/advanced/pihole-FTL.service /etc/init.d/pihole-FTL chmod +x /etc/init.d/pihole-FTL - ynh_exec_warn_less systemctl enable pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL --quiet else # Last version available # Stopped dnsmasq to replace it by pihole-FTL ynh_systemd_action --action=stop --service_name=dnsmasq # Disable the real dnsmasq service - ynh_exec_warn_less systemctl disable dnsmasq + ynh_exec_warn_less systemctl disable dnsmasq --quiet # And move the files that make the service available in systemd to really disable it mv /lib/systemd/system/dnsmasq.service /lib/systemd/system/.dnsmasq.service.backup_by_pihole @@ -260,7 +262,7 @@ else cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL chmod +x /etc/init.d/pihole-FTL - ynh_exec_warn_less systemctl enable pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL --quiet # Replace the service dnsmasq by pihole-FTL # That way, YunoHost can continue to use dnsmasq by actually using pihole-FTL @@ -447,7 +449,7 @@ cp ../conf/dnsmasq_regenconf_hook /usr/share/yunohost/hooks/conf_regen/50-dnsmas # ADVERTISE SERVICE IN ADMIN PANEL #================================================= -yunohost service add pihole-FTL --description "PiHole backend service" --log "/var/log/pihole-FTL.log" +yunohost service add pihole-FTL --description="PiHole backend service" --log="/var/log/pihole-FTL.log" --needs_exposed_ports="$port" #================================================= # RESTRAIN THE ACCESS TO THE ADMIN ONLY @@ -459,7 +461,7 @@ ynh_permission_update --permission="main" --add="$admin" --remove="all_users" #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." --weight=3 +ynh_script_progression --message="Reloading NGINX web server..." --weight=3 ynh_systemd_action --service_name=nginx --action=reload diff --git a/scripts/remove b/scripts/remove index 2da2bf2..fc85080 100755 --- a/scripts/remove +++ b/scripts/remove @@ -41,7 +41,7 @@ ynh_script_progression --message="Stop and remove the service" if [ "$pihole_version" == "Last 3.X" ] then ynh_systemd_action --action=stop --service_name=pihole-FTL - ynh_exec_warn_less systemctl disable pihole-FTL + ynh_exec_warn_less systemctl disable pihole-FTL --quiet else ynh_systemd_action --action=stop --service_name=pihole-FTL @@ -58,7 +58,7 @@ else mv /lib/systemd/system/.dnsmasq.service.backup_by_pihole /lib/systemd/system/dnsmasq.service mv /etc/init.d/.dnsmasq.backup_by_pihole /etc/init.d/dnsmasq - ynh_exec_warn_less systemctl enable dnsmasq + ynh_exec_warn_less systemctl enable dnsmasq --quiet # Reload systemd config systemctl daemon-reload fi @@ -93,7 +93,7 @@ ynh_secure_remove --file="/etc/.pihole" #================================================= # REMOVE NGINX CONFIGURATION #================================================= -ynh_script_progression --message="Removing nginx web server configuration..." +ynh_script_progression --message="Removing NGINX web server configuration..." # Remove the dedicated nginx config ynh_remove_nginx_config @@ -101,7 +101,7 @@ ynh_remove_nginx_config #================================================= # REMOVE PHP-FPM CONFIGURATION #================================================= -ynh_script_progression --message="Removing php-fpm configuration..." --weight=2 +ynh_script_progression --message="Removing PHP-FPM configuration..." --weight=2 # Remove the dedicated php-fpm config ynh_remove_fpm_config @@ -109,7 +109,7 @@ ynh_remove_fpm_config #================================================= # CLOSE PORTS #================================================= -ynh_script_progression --message="Closing port $port et 67..." --weight=13 +ynh_script_progression --message="Closing ports $port et 67..." --weight=13 if yunohost firewall list | grep -q "\- $port$" then diff --git a/scripts/restore b/scripts/restore index 2d7391d..a6e1bb9 100644 --- a/scripts/restore +++ b/scripts/restore @@ -97,7 +97,7 @@ chown root: -R "/etc/pihole/logrotate" #================================================= # RESTORE THE PHP-FPM CONFIGURATION #================================================= -ynh_script_progression --message="Reconfiguring php-fpm..." --weight=7 +ynh_script_progression --message="Reconfiguring PHP-FPM..." --weight=7 # Restore the file first, so it can have a backup if different ynh_restore_file --origin_path="$fpm_config_dir/php-fpm-$app.conf" @@ -265,7 +265,7 @@ ynh_systemd_action --action=restart --service_name=pihole-FTL #================================================= # RELOAD NGINX AND PHP-FPM #================================================= -ynh_script_progression --message="Reloading nginx web server and php-fpm..." +ynh_script_progression --message="Reloading NGINX web server and PHP-FPM..." ynh_systemd_action --service_name=$fpm_service --action=reload ynh_systemd_action --service_name=nginx --action=reload @@ -286,7 +286,7 @@ admin_panel="https://$(grep portal_domain /etc/ssowat/conf.json | cut -d'"' -f4) if [ $enable_dhcp -eq 1 ] then - dhcp_alert="You asked to use the internal DHCP server of dnsmasq with PiHole. + dhcp_alert="You asked to use the internal DHCP server of Dnsmasq with PiHole. You should really read the __URL_TAG1__documentation about that__URL_TAG2__https://github.com/YunoHost-Apps/pihole_ynh/blob/master/dhcp.md__URL_TAG3__ " diff --git a/scripts/upgrade b/scripts/upgrade index b31b189..f9e8151 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -109,13 +109,6 @@ ynh_clean_setup () { # Exit if an error occurs during the execution of the script ynh_abort_if_errors -#================================================= -# CHECK THE PATH -#================================================= - -# Normalize the URL path syntax -path_url=$(ynh_normalize_url_path --path_url=$path_url) - #================================================= # ACTIVATE MAINTENANCE MODE #================================================= @@ -171,7 +164,7 @@ chown $app:www-data "$final_path" # Overwrite the nginx configuration only if it's allowed if [ $overwrite_nginx -eq 1 ] then - ynh_script_progression --message="Upgrading nginx web server configuration..." --weight=2 + ynh_script_progression --message="Upgrading NGINX web server configuration..." --weight=2 # Create a dedicated nginx config ynh_add_nginx_config fi @@ -183,7 +176,7 @@ fi # Overwrite the php-fpm configuration only if it's allowed if [ $overwrite_phpfpm -eq 1 ] then - ynh_script_progression --message="Upgrading php-fpm configuration..." --weight=3 + ynh_script_progression --message="Upgrading PHP-FPM configuration..." --weight=3 # Create a dedicated php-fpm config ynh_add_fpm_config --usage=$fpm_usage --footprint=$fpm_footprint --dedicated_service fi @@ -284,14 +277,14 @@ then # Version 3.3.1 cp -a $pihole_local_repo/advanced/pihole-FTL.service /etc/init.d/pihole-FTL chmod +x /etc/init.d/pihole-FTL - ynh_exec_warn_less systemctl enable pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL --quiet else # Last version available # Stopped dnsmasq to replace it by pihole-FTL ynh_systemd_action --action=stop --service_name=dnsmasq # Disable the real dnsmasq service - ynh_exec_warn_less systemctl disable dnsmasq + ynh_exec_warn_less systemctl disable dnsmasq --quiet # And move the files that make the service available in systemd to really disable it if [ ! -e "/lib/systemd/system/.dnsmasq.service.backup_by_pihole" ]; then @@ -377,7 +370,7 @@ ynh_systemd_action --action=restart --service_name=pihole-FTL # ADVERTISE SERVICE IN ADMIN PANEL #================================================= -yunohost service add pihole-FTL --description "PiHole backend service" --log "/var/log/pihole-FTL.log" +yunohost service add pihole-FTL --description="PiHole backend service" --log="/var/log/pihole-FTL.log" --needs_exposed_ports="$port" #================================================= # UPDATE CONF_REGEN HOOK @@ -388,7 +381,7 @@ cp ../conf/dnsmasq_regenconf_hook /usr/share/yunohost/hooks/conf_regen/50-dnsmas #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." +ynh_script_progression --message="Reloading NGINX web server..." ynh_systemd_action --action=reload --service_name=nginx From 3a3c84b90d059b88db0d6d7f51ed855faf186303 Mon Sep 17 00:00:00 2001 From: ericgaspar Date: Tue, 10 Aug 2021 09:47:23 +0200 Subject: [PATCH 14/20] Add templates --- doc/.DS_Store | Bin 0 -> 6148 bytes doc/DISCLAIMER.md | 8 ++++++++ doc/DISCLAIMER_fr.md | 8 ++++++++ doc/screenshots/dashboard.png | Bin 0 -> 269041 bytes manifest.json | 18 ++++++------------ scripts/restore | 8 ++++---- scripts/upgrade | 2 +- 7 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 doc/.DS_Store create mode 100644 doc/DISCLAIMER.md create mode 100644 doc/DISCLAIMER_fr.md create mode 100644 doc/screenshots/dashboard.png diff --git a/doc/.DS_Store b/doc/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..fc7b8a40949f5488c93362acd831b939baeb97b0 GIT binary patch literal 6148 zcmeHK%}(4f5FRhvHZG_NQV$?;u*9L4J#4kxa*ejYsS>C`a479IX{>If$VN$)J*-xW z`T%`^a_!H1ls*J6!kro0TZFb;QK>x9_?wJp#>wZ%jsbuT#@Ta#5C8&H!WPHoFGBsK z3(|5PLS|}6P*A}LG}H^x-tjLoKy$Z@bM_HRka%6sUzJX(leEw&MqH*RMPAk2?geWt zwI4iu6!6D!gC&TdRE3N7zSF$wqY>nfiTxEJP&|{TVCf*e{_I^^2unymhWMi1+0Uw5I z(`m2wq9c0!{;VUWTU*_Z==WaEW;_VipY6VRKmPpX>)E&OKYso?H(9{&(>1c{a1OuG zxP_Y2xKxE!pD<#cJVBNAwJM2JV&tS|0=|VdSu}XqFCa z==YKO+k_-&(^-O0IE)-N7O@9~*;GWE%G?oy*>v;^7Z*8fEZTHnW@N16MrQ7W!p!LC z7bYB7WYM>t0nflq2A1q?Nc;cJ?dSiSN&e0=;2HR@7+~$~czb}a=^gL=TGp5im6P#xroI3|s*i)MY*Z literal 0 HcmV?d00001 diff --git a/doc/DISCLAIMER.md b/doc/DISCLAIMER.md new file mode 100644 index 0000000..4efcc1e --- /dev/null +++ b/doc/DISCLAIMER.md @@ -0,0 +1,8 @@ +## Configuration + +Use the admin panel of your Pi-hole to configure this app. You may also need to follow the [post-install guide](https://docs.pi-hole.net/main/post-install/) to setup Pi-hole either as a *DNS server* or a *DHCP server*. + +## Limitations + +* Activate DHCP with Pi-hole needs manual configuration of your router. +* Pi-Hole can't be updated beyond version 3.3.1, because higher versions use an integrated version of dnsmasq. This would require disabling the version of dnsmasq used by YunoHost. diff --git a/doc/DISCLAIMER_fr.md b/doc/DISCLAIMER_fr.md new file mode 100644 index 0000000..ceb9a25 --- /dev/null +++ b/doc/DISCLAIMER_fr.md @@ -0,0 +1,8 @@ +## Configuration + +Utiliser le panneau d'administration de votre Pi-hole pour configurer cette application. Vous devrez peut-être aussi suivre le [guide de post-installation] (https://docs.pi-hole.net/main/post-install/) pour configurer Pi-hole en tant que *serveur DNS* ou *serveur DHCP*. + +## Limitations + +* Activer DHCP avec Pi-hole nécessite une configuration manuelle de votre routeur. +* Pi-Hole ne peut pas être mis à jour au-delà de la version 3.3.1, car les versions supérieures utilisent une version intégrée de dnsmasq. Ce qui oblige a désactiver la version de dnsmasq utilisée par YunoHost. diff --git a/doc/screenshots/dashboard.png b/doc/screenshots/dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..f12fdbcb81ff0922bf6c401de7a763c91367ea51 GIT binary patch literal 269041 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 yU8%oH2pM=XJbB`H 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

    cxJ+y5*U8?<387nD5oR|C*uE)cH3Cj& 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

    P5ps05D7Q`sfWF9-mvDm;?b~3-$W*tS(eCW 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 literal 0 HcmV?d00001 diff --git a/manifest.json b/manifest.json index 8da8fb2..218ce8e 100644 --- a/manifest.json +++ b/manifest.json @@ -8,6 +8,12 @@ }, "version": "5.3.1~ynh1", "url": "https://pi-hole.net/", + "upstream": { + "license": "EUPL-1.2", + "website": "https://pi-hole.net/", + "admindoc": "https://docs.pi-hole.net", + "code": "https://github.com/pi-hole/pi-hole/" + }, "license": "EUPL-1.2", "maintainer": { "name": "", @@ -30,29 +36,17 @@ { "name": "domain", "type": "domain", - "ask": { - "en": "Choose a domain for the admin interface of Pi-hole", - "fr": "Choisissez un domaine pour l'interface admin de Pi-hole" - }, "example": "domain.org" }, { "name": "path", "type": "path", - "ask": { - "en": "Choose a path for the admin interface of Pi-hole", - "fr": "Choisissez un chemin pour l'interface admin de Pi-hole" - }, "example": "/pihole", "default": "/pihole" }, { "name": "admin", "type": "user", - "ask": { - "en": "Choose the Pi-hole administrator (must be an existing YunoHost user)", - "fr": "Administrateur de Pi-hole (doit être un utilisateur YunoHost existant)" - }, "example": "john" }, { diff --git a/scripts/restore b/scripts/restore index a6e1bb9..3b485fa 100644 --- a/scripts/restore +++ b/scripts/restore @@ -119,7 +119,7 @@ ynh_install_app_dependencies $app_depencencies # ADVERTISE SERVICE IN ADMIN PANEL #================================================= -yunohost service add pihole-FTL --description "PiHole backend service" --log "/var/log/pihole-FTL.log" +yunohost service add pihole-FTL --description="PiHole backend service" --log="/var/log/pihole-FTL.log" --needs_exposed_ports=$port #================================================= # RESTORE THE CRON FILE @@ -162,7 +162,7 @@ then ynh_systemd_action --action=stop --service_name=dnsmasq # Disable the real dnsmasq service - ynh_exec_warn_less systemctl disable dnsmasq + ynh_exec_warn_less systemctl disable dnsmasq --quiet # And move the files that make the service available in systemd to really disable it mv /lib/systemd/system/dnsmasq.service /lib/systemd/system/.dnsmasq.service.backup_by_pihole @@ -178,7 +178,7 @@ then pihole_local_repo="/etc/.pihole" cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL chmod +x /etc/init.d/pihole-FTL - ynh_exec_warn_less systemctl enable pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL --quiet # Replace the service dnsmasq by pihole-FTL # That way, YunoHost can continue to use dnsmasq by actually using pihole-FTL @@ -257,7 +257,7 @@ ynh_store_file_checksum --file="$setupVars" #================================================= ynh_script_progression --message="Restarting PiHole-FTL..." --weight=2 -ynh_exec_warn_less systemctl enable pihole-FTL +ynh_exec_warn_less systemctl enable pihole-FTL --quiet ynh_systemd_action --action=restart --service_name=pihole-FTL #================================================= diff --git a/scripts/upgrade b/scripts/upgrade index f9e8151..0634918 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -305,7 +305,7 @@ else cp -a $pihole_local_repo/advanced/Templates/pihole-FTL.service /etc/init.d/pihole-FTL chmod +x /etc/init.d/pihole-FTL - ynh_exec_warn_less systemctl enable pihole-FTL + ynh_exec_warn_less systemctl enable pihole-FTL --quiet # Replace the service dnsmasq by pihole-FTL # That way, YunoHost can continue to use dnsmasq by actually using pihole-FTL From db787452c23863602f21c030eb297f85839c9688 Mon Sep 17 00:00:00 2001 From: Yunohost-Bot <> Date: Tue, 10 Aug 2021 07:47:35 +0000 Subject: [PATCH 15/20] Auto-update README --- README.md | 68 +++++++++++++++++++++------------------------------- README_fr.md | 63 +++++++++++++++++------------------------------- 2 files changed, 49 insertions(+), 82 deletions(-) diff --git a/README.md b/README.md index bb33777..4eedd45 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,58 @@ + + # Pi-hole for YunoHost [![Integration level](https://dash.yunohost.org/integration/pihole.svg)](https://dash.yunohost.org/appci/app/pihole) ![](https://ci-apps.yunohost.org/ci/badges/pihole.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/pihole.maintain.svg) -[![Install Pi-hole with YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=pihole) +[![Install Pi-hole with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=pihole) *[Lire ce readme en français.](./README_fr.md)* -> *This package allow you to install Pi-hole quickly and easily on a YunoHost server. -If you don't have YunoHost, please see [here](https://yunohost.org/#/install) to learn how to install and enjoy it.* +> *This package allows you to install Pi-hole quickly and simply on a YunoHost server. +If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/install) to learn how to install it.* ## Overview -Network-wide ad blocking via your own Linux hardware -**Shipped version:** 3.3.1 or 5.3.1 +Network-wide ad blocking via your own DNS server. + +**Shipped version:** 5.3.1~ynh1 + + ## Screenshots -![](https://i0.wp.com/pi-hole.net/wp-content/uploads/2016/12/dashboard212.png) +![](./doc/screenshots/dashboard.png) -## Demo - -No demo available. +## Disclaimers / important information ## Configuration Use the admin panel of your Pi-hole to configure this app. You may also need to follow the [post-install guide](https://docs.pi-hole.net/main/post-install/) to setup Pi-hole either as a *DNS server* or a *DHCP server*. -## Documentation - -* Official documentation: https://docs.pi-hole.net/ -* Pi-hole as a DHCP server: [dhcp.md](./dhcp.md) -* YunoHost documentation: There is no other documentation. Feel free to contribute! - -## YunoHost specific features - -* Private access to the admin panel. - -#### Multi-users support - -#### Supported architectures - -* x86-64b - [![](https://ci-apps.yunohost.org/ci/logs/pihole%20%28Apps%29.svg)](https://ci-apps.yunohost.org/ci/apps/pihole/) -* ARMv8-A - [![](https://ci-apps-arm.yunohost.org/ci/logs/pihole%20%28Apps%29.svg)](https://ci-apps-arm.yunohost.org/ci/apps/pihole/) -* Buster x86-64b - [![](https://ci-buster.nohost.me/ci/logs/pihole%20%28Apps%29.svg)](https://ci-buster.nohost.me/ci/apps/pihole/) - ## Limitations * Activate DHCP with Pi-hole needs manual configuration of your router. * Pi-Hole can't be updated beyond version 3.3.1, because higher versions use an integrated version of dnsmasq. This would require disabling the version of dnsmasq used by YunoHost. -## Additionnal informations +## Documentation and resources -## Links +* Official app website: https://pi-hole.net/ +* Official admin documentation: https://docs.pi-hole.net +* Upstream app code repository: https://github.com/pi-hole/pi-hole/ +* YunoHost documentation for this app: https://yunohost.org/app_pihole +* Report a bug: https://github.com/YunoHost-Apps/pihole_ynh/issues - * Report a bug: https://github.com/YunoHost-Apps/pihole_ynh/issues - * Pi-hole website: https://pi-hole.net/ - * Pi-hole repository: https://github.com/pi-hole/pi-hole/ - * YunoHost website: https://yunohost.org/ +## Developer info ---- +Please send your pull request to the [testing branch](https://github.com/YunoHost-Apps/pihole_ynh/tree/testing). -Developers infos ----------------- - -Please do your pull request to the [testing branch](https://github.com/YunoHost-Apps/pihole_ynh/tree/testing). - -To try the testing branch, please do the following: +To try the testing branch, please proceed like that. ``` -sudo yunohost app install https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --force --debug +sudo yunohost app install https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --debug or sudo yunohost app upgrade pihole -u https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --debug ``` + +**More info regarding app packaging:** https://yunohost.org/packaging_apps \ No newline at end of file diff --git a/README_fr.md b/README_fr.md index 23c754c..c0cdccc 100644 --- a/README_fr.md +++ b/README_fr.md @@ -1,73 +1,54 @@ # Pi-hole pour YunoHost [![Niveau d'intégration](https://dash.yunohost.org/integration/pihole.svg)](https://dash.yunohost.org/appci/app/pihole) ![](https://ci-apps.yunohost.org/ci/badges/pihole.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/pihole.maintain.svg) -[![Installer Pi-hole avec YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=pihole) +[![Installer Pi-hole avec YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=pihole) *[Read this readme in english.](./README.md)* +*[Lire ce readme en français.](./README_fr.md)* -> *Ce package vous permet d'installer Pi-hole rapidement et simplement sur un serveur YunoHost. -Si vous n'avez pas YunoHost, merci de regarder [ici](https://yunohost.org/#/install_fr) pour savoir comment l'installer et en profiter.* +> *Ce package vous permet d'installer Pi-hole rapidement et simplement sur un serveur YunoHost. +Si vous n'avez pas YunoHost, regardez [ici](https://yunohost.org/#/install) pour savoir comment l'installer et en profiter.* -## Résumé -Blocage des publicités sur l'ensemble du réseau via votre propre matériel Linux +## Vue d'ensemble + +Filtrage publicitaire sur l'ensemble du réseau via votre propre serveur DNS. + +**Version incluse :** 5.3.1~ynh1 -**Version embarquée:** 3.3.1 ou 5.3.1 ## Captures d'écran -![](https://i0.wp.com/pi-hole.net/wp-content/uploads/2016/12/dashboard212.png) +![](./doc/screenshots/dashboard.png) -## Démo - -Aucune démo pour cette application. +## Avertissements / informations importantes ## Configuration Utiliser le panneau d'administration de votre Pi-hole pour configurer cette application. Vous devrez peut-être aussi suivre le [guide de post-installation] (https://docs.pi-hole.net/main/post-install/) pour configurer Pi-hole en tant que *serveur DNS* ou *serveur DHCP*. -## Documentation - -* Documentation officielle: https://docs.pi-hole.net/ -* Pi-hole en tant que serveur DHCP: [dhcp.md](./dhcp.md) -* Documentation YunoHost: Il n'y a pas d'autre documentation, n'hésitez pas à contribuer. - -## Fonctionnalités spécifiques à YunoHost - -* Accès privé au panneau d'administration. - -#### Support multi-utilisateurs - -#### Architectures supportées. - -* x86-64b - [![](https://ci-apps.yunohost.org/ci/logs/pihole%20%28Apps%29.svg)](https://ci-apps.yunohost.org/ci/apps/pihole/) -* ARMv8-A - [![](https://ci-apps-arm.yunohost.org/ci/logs/pihole%20%28Apps%29.svg)](https://ci-apps-arm.yunohost.org/ci/apps/pihole/) -* Buster x86-64b - [![](https://ci-buster.nohost.me/ci/logs/pihole%20%28Apps%29.svg)](https://ci-buster.nohost.me/ci/apps/pihole/) - ## Limitations * Activer DHCP avec Pi-hole nécessite une configuration manuelle de votre routeur. * Pi-Hole ne peut pas être mis à jour au-delà de la version 3.3.1, car les versions supérieures utilisent une version intégrée de dnsmasq. Ce qui oblige a désactiver la version de dnsmasq utilisée par YunoHost. -## Informations additionnelles +## Documentations et ressources -## Liens +* Site officiel de l'app : https://pi-hole.net/ +* Documentation officielle de l'admin : https://docs.pi-hole.net +* Dépôt de code officiel de l'app : https://github.com/pi-hole/pi-hole/ +* Documentation YunoHost pour cette app : https://yunohost.org/app_pihole +* Signaler un bug : https://github.com/YunoHost-Apps/pihole_ynh/issues - * Reporter un bug: https://github.com/YunoHost-Apps/pihole_ynh/issues - * Site de Pi-hole: https://pi-hole.net/ - * Dépôt de Pi-hole: https://github.com/pi-hole/pi-hole/ - * Site de YunoHost: https://yunohost.org/ - ---- - -Informations à l'intention des développeurs ----------------- +## Informations pour les développeurs Merci de faire vos pull request sur la [branche testing](https://github.com/YunoHost-Apps/pihole_ynh/tree/testing). -Pour tester la branche testing, merci de procéder ainsi. +Pour essayer la branche testing, procédez comme suit. ``` -sudo yunohost app install https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --force --debug +sudo yunohost app install https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --debug ou sudo yunohost app upgrade pihole -u https://github.com/YunoHost-Apps/pihole_ynh/tree/testing --debug ``` + +**Plus d'infos sur le packaging d'applications :** https://yunohost.org/packaging_apps \ No newline at end of file From 84e718804927fc7ae8932a6959b575606aea08a0 Mon Sep 17 00:00:00 2001 From: ericgaspar Date: Tue, 10 Aug 2021 09:48:57 +0200 Subject: [PATCH 16/20] fix --- doc/DISCLAIMER.md | 56 ++++++++++++++++++++++++++++++++++++++++++++ doc/DISCLAIMER_fr.md | 56 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/doc/DISCLAIMER.md b/doc/DISCLAIMER.md index 4efcc1e..96e7479 100644 --- a/doc/DISCLAIMER.md +++ b/doc/DISCLAIMER.md @@ -6,3 +6,59 @@ Use the admin panel of your Pi-hole to configure this app. You may also need to * Activate DHCP with Pi-hole needs manual configuration of your router. * Pi-Hole can't be updated beyond version 3.3.1, because higher versions use an integrated version of dnsmasq. This would require disabling the version of dnsmasq used by YunoHost. + + +Using Pi-hole as your DHCP server +================== + +> **Be careful, you should considering that playing with your DHCP may break your network. +In case your server is down, you will lose your dns resolution and ip address. +So, you will lose any internet connection and even the connection to your router.** + +> **If you encounter this kind of problem, please see "How to restore my network" at the end of this document.** + +### How to configure Pi-hole + +There're two ways to configure Pi-hole to be used as your DHCP server. +- Either you can choose to use it when you install the app. +- Or you can activate the DHCP server afterwards in the "Settings" tab, "Pi-hole DHCP Server" part. +In this second case, it can be better to set the ip of the server to a static address + +### How to configure my router + +Your personal router or ISP's router has a DHCP server enabled by default. +If you keep this DHCP, along with Pi-hole's one, you will have transparent conflicts between them. +The first DHCP to respond will distribute its own ip and settings. +So you have to turn off the DHCP of your router to let Pi-hole managed your network. + +#### Why should I use only the DHCP of Pi-hole ? + +By using the DHCP of Pi-hole, you allow Pi-hole to give at each of your client its dns configuration. This way every requests will be filtered by Pi-hole. + +Another use case of using Pi-hole's DHCP is if you have hairpinning problems (You can't connect to your server because its IP is your public IP, and your router doesn't allow that). +In this case, using Pi-hole's dns will allow you to connect to your server by its local address instead of its public one. + +### How to restore my network + +> Oh crap ! +Your Pi-hole server is down, and you don't have a DHCP anymore. +Don't panic, We'll get through it. \o/ + +Use your favorite terminal on your desktop computer. +And first, get your main interface (usually `eth0`). +``` bash +sudo ifconfig +``` + +Then, set your ip as a static ip. +``` bash +sudo ifconfig eth0 192.168.1.100 +``` + +Now, you can connect to your router and turn on its DHCP server to use it again. +You can now reset your ip and get a dynamic address. +``` bash +sudo ifconfig eth0 0.0.0.0 && sudo dhclient eth0 +``` + +> Don't forget to turn off the DHCP of your router if your server is working again. \ No newline at end of file diff --git a/doc/DISCLAIMER_fr.md b/doc/DISCLAIMER_fr.md index ceb9a25..f076dca 100644 --- a/doc/DISCLAIMER_fr.md +++ b/doc/DISCLAIMER_fr.md @@ -6,3 +6,59 @@ Utiliser le panneau d'administration de votre Pi-hole pour configurer cette appl * Activer DHCP avec Pi-hole nécessite une configuration manuelle de votre routeur. * Pi-Hole ne peut pas être mis à jour au-delà de la version 3.3.1, car les versions supérieures utilisent une version intégrée de dnsmasq. Ce qui oblige a désactiver la version de dnsmasq utilisée par YunoHost. + + +Faire de Pi-hole votre serveur DHCP +================== + +> **Attention, vous devez savoir que toucher à votre DHCP pourrait casser votre réseau. +Dans le cas où votre serveur serait inaccessible, vous perdriez votre résolution dns et votre adresse IP. +Ainsi, vous perdriez toute connexion à internet et même la connexion à votre routeur.** + +> **Si vous rencontrez ce genre de problèmes, merci de lire la section "Comment restaurer mon réseau" à la fin de ce document.** + +### Comment configurer Pi-hole + +Il y a 2 manière de configurer Pi-hole pour qu'il soit utilisé comme votre serveur DHCP. +- Soit vous pouvez choisir de l'utiliser lorsque vous installez l'application. +- Soit vous pouvez activer le serveur DHCP par la suite dans l'onglet "Settings", partie "Pi-hole DHCP Server". +Dans ce second cas, il peut être préférable de forcer l'ip du serveur à une adresse statique. + +### Comment configurer mon routeur + +Votre routeur ou celui de votre FAI dispose d'un serveur DHCP activé par défaut. +Si vous gardez ce DHCP, en même temps que celui de Pi-hole, vous allez avoir des conflits transparents entre eux. +Le premier serveur DHCP à répondre va distribuer ses propres ip et paramètres. +Donc vous devez éteindre le serveur DHCP de votre routeur et laisser Pi-hole gérer votre réseau. + +#### Pourquoi je devrais utiliser le DHCP de Pi-hole ? + +En utilisant le DHCP de Pi-hole, vous lui permettez de donner sa configuration dns à chacun de vos clients. De cette manière, chaque requête sera filtrée par Pi-hole. + +Un autre cas d'usage du DHCP de Pi-hole est le cas où vous rencontrez des problèmes de hairpinning (Vous ne pouvez pas vous connecter à votre serveur parce que son ip est votre ip publique, et votre routeur n'autorise pas cela). +Dans ce cas, utilisez le dns de Pi-hole va vous permettre de vous connecter à votre serveur par son adresse locale plutôt que son adresse publique. + +### Comment restaurer mon réseau + +> Oups ! +Votre serveur Pi-hole est tombé, et vous n'avez plus de DHCP. +Ne paniquez pas, on va surmonter ça \o/ + +Utilisez votre terminal favori sur votre ordinateur de bureau. +Et tout d'abord, récupérer votre interface réseau (Le plus souvent `eth0`). +``` bash +sudo ifconfig +``` + +Ensuite, changer votre ip pour une ip statique. +``` bash +sudo ifconfig eth0 192.168.1.100 +``` + +Maintenant, vous pouvez vous connecter à votre routeur et rallumer son serveur DHCP pour l'utiliser à nouveau. +Vous pouvez maintenant retirer votre ip statique et réobtenir une ip dynamique. +``` bash +sudo ifconfig eth0 0.0.0.0 && sudo dhclient eth0 +``` + +> N'oubliez pas d'éteindre le DHCP de votre routeur si votre serveur fonctionne à nouveau. From d2ab7d3ced3d3e1732d98de7930e124be962e620 Mon Sep 17 00:00:00 2001 From: ericgaspar Date: Tue, 10 Aug 2021 09:57:29 +0200 Subject: [PATCH 17/20] Fix --- check_process | 16 +++++++--------- config_panel.toml | 18 +++++++++--------- manifest.json | 20 ++++++++++---------- scripts/actions/reset_default_app | 18 +++++++++--------- scripts/actions/reset_default_config | 2 +- 5 files changed, 36 insertions(+), 38 deletions(-) diff --git a/check_process b/check_process index 40e8bbc..0931364 100644 --- a/check_process +++ b/check_process @@ -1,8 +1,8 @@ ;; Test version last version ; Manifest - domain="domain.tld" (DOMAIN) - path="/path" (PATH) - admin="john" (USER) + domain="domain.tld" + path="/path" + admin="john" query_logging=1 enable_dhcp=0 pihole_version="Last available" @@ -26,15 +26,15 @@ upgrade=1 backup_restore=1 multi_instance=0 - port_already_use=1 (4711) + port_already_use=1 change_url=1 actions=1 config_panel=1 ;; Test version 3 ; Manifest - domain="domain.tld" (DOMAIN) - path="/path" (PATH) - admin="john" (USER) + domain="domain.tld" + path="/path" + admin="john" query_logging=1 enable_dhcp=0 pihole_version="Last 3.X" @@ -45,8 +45,6 @@ upgrade=1 from_commit=d79ec131b3038ff4695c3317b5d3ee4eda9c8932 backup_restore=1 actions=1 -;;; Levels - Level 5=auto ;;; Options Email= Notification=change diff --git a/config_panel.toml b/config_panel.toml index 9721f5e..d8518a1 100644 --- a/config_panel.toml +++ b/config_panel.toml @@ -8,25 +8,25 @@ name = "PiHole configuration" name = "Overwriting config files" [main.overwrite_files.overwrite_setupvars] - ask = "Overwrite the config file setupVars.conf ?" + ask = "Overwrite the config file setupVars.conf?" type = "boolean" default = true help = "If the file is overwritten, a backup will be created." [main.overwrite_files.overwrite_ftl] - ask = "Overwrite the config file pihole-FTL.conf ?" + ask = "Overwrite the config file pihole-FTL.conf?" type = "boolean" default = true help = "If the file is overwritten, a backup will be created." [main.overwrite_files.overwrite_nginx] - ask = "Overwrite the nginx config file ?" + ask = "Overwrite the nginx config file?" type = "boolean" default = true help = "If the file is overwritten, a backup will be created." [main.overwrite_files.overwrite_phpfpm] - ask = "Overwrite the php-fpm config file ?" + ask = "Overwrite the php-fpm config file?" type = "boolean" default = true help = "If the file is overwritten, a backup will be created." @@ -36,7 +36,7 @@ name = "PiHole configuration" name = "Global configuration" [main.global_config.email_type] - ask = "Send HTML email to admin ?" + ask = "Send HTML email to admin?" type = "boolean" default = true help = "Allow app scripts to send HTML mails instead of plain text." @@ -46,25 +46,25 @@ name = "PiHole configuration" name = "PHP-FPM configuration" [main.php_fpm_config.footprint] - ask = "Memory footprint of the service ?" + ask = "Memory footprint of the service?" choices = ["low", "medium", "high", "specific"] default = "low" help = "low <= 20Mb per pool. medium between 20Mb and 40Mb per pool. high > 40Mb per pool.
    Use specific to set a value with the following option." [main.php_fpm_config.free_footprint] - ask = "Memory footprint of the service ?" + ask = "Memory footprint of the service?" type = "number" default = "0" help = "Free field to specify exactly the footprint in Mb if you don't want to use one of the three previous values." [main.php_fpm_config.usage] - ask = "Expected usage of the service ?" + ask = "Expected usage of the service?" choices = ["low", "medium", "high"] default = "low" help = "low: Personal usage, behind the sso. No RAM footprint when not used, but the impact on the processor can be high if many users are using the service.
    medium: Low usage, few people or/and publicly accessible. Low RAM footprint, medium processor footprint when used.
    high: High usage, frequently visited website. High RAM footprint, but lower on processor usage and quickly responding." [main.php_fpm_config.force_max_children] - ask = "Force the value of pm.max_children ?" + ask = "Force the value of pm.max_children?" type = "number" default = "0" help = "Do not change this value unless you're sure about what you're doing !
    pm.max_children is automatically defined by this formula: $max_ram / 2 / $footprint
    You can force that value, and ignore the formula by changing the value here.
    To reset to the default value, set to 0." diff --git a/manifest.json b/manifest.json index 218ce8e..3e07f5d 100644 --- a/manifest.json +++ b/manifest.json @@ -3,8 +3,8 @@ "id": "pihole", "packaging_format": 1, "description": { - "en": "Network-wide ad blocking via your own DNS server.", - "fr": "Filtrage publicitaire sur l'ensemble du réseau via votre propre serveur DNS." + "en": "Network-wide ad blocking via your own DNS server", + "fr": "Filtrage publicitaire via votre propre serveur DNS" }, "version": "5.3.1~ynh1", "url": "https://pi-hole.net/", @@ -53,8 +53,8 @@ "name": "query_logging", "type": "boolean", "ask": { - "en": "Do you want to log queries ?", - "fr": "Voulez-vous enregistrer les requêtes dns ?" + "en": "Do you want to log DNS queries?", + "fr": "Voulez-vous enregistrer les requêtes DNS ?" }, "help": { "en": "Keeping this option deactivate will render graphs on the admin page useless. But will respect the privacy of the other users.", @@ -66,11 +66,11 @@ "name": "enable_dhcp", "type": "boolean", "ask": { - "en": "Do you want to set Pi-hole as your DHCP server ?", - "fr": "Voulez-vous utiliser Pi-hole an tant que serveur DHCP ?" + "en": "Do you want to set Pi-Hole as your DHCP server?", + "fr": "Voulez-vous utiliser Pi-Hole an tant que serveur DHCP ?" }, "help": { - "en": "If you want to do that,
    you really have to read this before !", + "en": "If you want to do that, you really have to read this before!", "fr": "Si vous voulez faire ça, vous devez vraiment lire cela avant !" }, "default": false @@ -79,12 +79,12 @@ "name": "pihole_version", "type": "string", "ask": { - "en": "Which version of Pi-Hole do you want to install ?", + "en": "Which version of Pi-Hole do you want to install?", "fr": "Quelle version de Pi-Hole voulez-vous installer ?" }, "help": { - "en": "The last 3.X version is the last version available with the Debian version of dnsmasq.", - "fr": "The last available version will replace the Debian version of dnsmasq by FTLDNS.
    See the readme for more information." + "en": "The last 3.X version is the last version available with the Debian version of dnsmasq. The last available version will replace the Debian version of dnsmasq by FTLDNS.
    See the readme for more information.", + "fr": "La dernière version 3.X est la dernière version disponible avec la version Debian de dnsmasq. La dernière version disponible remplacera la version Debian de dnsmasq par FTLDNS.
    Voir le readme pour plus d'informations." }, "choices": ["Last 3.X","Last available"], "default": "Last 3.X" diff --git a/scripts/actions/reset_default_app b/scripts/actions/reset_default_app index ea606ed..8e3fba5 100755 --- a/scripts/actions/reset_default_app +++ b/scripts/actions/reset_default_app @@ -38,14 +38,14 @@ pihole_version="$(ynh_app_setting_get --app=$app --key=pihole_version)" #================================================= # ACTIVATE MAINTENANCE MODE #================================================= -ynh_script_progression --message="Activating maintenance mode..." --time --weight=1 +ynh_script_progression --message="Activating maintenance mode..." --weight=1 ynh_maintenance_mode_ON #================================================= # CREATE DEDICATED USER #================================================= -ynh_script_progression --message="Making sure dedicated system user exists..." --time --weight=1 +ynh_script_progression --message="Making sure dedicated system user exists..." --weight=1 # Create a dedicated user (if not existing) ynh_system_user_create --username=$app @@ -53,7 +53,7 @@ ynh_system_user_create --username=$app #================================================= # DOWNLOAD, CHECK AND UNPACK SOURCE #================================================= -ynh_script_progression --message="Resetting source files..." --time --weight=1 +ynh_script_progression --message="Resetting source files..." --weight=1 # Download, check integrity, uncompress and patch the source from app.src pihole_local_repo="/etc/.pihole" @@ -78,7 +78,7 @@ chown $app:www-data "$final_path" #================================================= # NGINX CONFIGURATION #================================================= -ynh_script_progression --message="Resetting nginx web server configuration..." --time --weight=1 +ynh_script_progression --message="Resetting NGINX web server configuration..." --weight=1 # Create a dedicated nginx config yunohost app action run $app reset_default_nginx @@ -86,7 +86,7 @@ yunohost app action run $app reset_default_nginx #================================================= # PHP-FPM CONFIGURATION #================================================= -ynh_script_progression --message="Resetting php-fpm configuration..." --time --weight=1 +ynh_script_progression --message="Resetting PHP-FPM configuration..." --weight=1 # Create a dedicated php-fpm config yunohost app action run $app reset_default_phpfpm @@ -94,7 +94,7 @@ yunohost app action run $app reset_default_phpfpm #================================================= # RECREATE DIRECTORIES #================================================= -ynh_script_progression --message="Recreating and populating directories..." --time --weight=1 +ynh_script_progression --message="Recreating and populating directories..." --weight=1 pihole_storage="/etc/pihole" mkdir -p "$pihole_storage" @@ -241,14 +241,14 @@ ynh_systemd_action --action=restart --service_name=pihole-FTL #================================================= # RELOAD NGINX #================================================= -ynh_script_progression --message="Reloading nginx web server..." --time --weight=1 +ynh_script_progression --message="Reloading NGINX web server..." --weight=1 ynh_systemd_action --service_name=nginx --action=reload #================================================= # DEACTIVE MAINTENANCE MODE #================================================= -ynh_script_progression --message="Disabling maintenance mode..." --time --weight=1 +ynh_script_progression --message="Disabling maintenance mode..." --weight=1 ynh_maintenance_mode_OFF @@ -256,4 +256,4 @@ ynh_maintenance_mode_OFF # END OF SCRIPT #================================================= -ynh_script_progression --message="Execution completed" --time --last +ynh_script_progression --message="Execution completed" --last diff --git a/scripts/actions/reset_default_config b/scripts/actions/reset_default_config index 24faea7..058d735 100755 --- a/scripts/actions/reset_default_config +++ b/scripts/actions/reset_default_config @@ -72,7 +72,7 @@ then # Get the default file and overwrite the current config cp /etc/yunohost/apps/$app/conf/pihole-FTL.conf "$config_file" - ynh_script_progression --message="Restarting PiHole..." --weight=2 + ynh_script_progression --message="Restarting Pi-Hole..." --weight=2 # Restart pihole-FTL ynh_systemd_action --action=restart --service_name=pihole-FTL From 0bb203ff5192b56cd22776a7f14c21b8ddea8272 Mon Sep 17 00:00:00 2001 From: Yunohost-Bot <> Date: Tue, 10 Aug 2021 07:57:37 +0000 Subject: [PATCH 18/20] Auto-update README --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++- README_fr.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4eedd45..a5a7c61 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/in ## Overview -Network-wide ad blocking via your own DNS server. +Network-wide ad blocking via your own DNS server **Shipped version:** 5.3.1~ynh1 @@ -36,6 +36,61 @@ Use the admin panel of your Pi-hole to configure this app. You may also need to * Activate DHCP with Pi-hole needs manual configuration of your router. * Pi-Hole can't be updated beyond version 3.3.1, because higher versions use an integrated version of dnsmasq. This would require disabling the version of dnsmasq used by YunoHost. + +Using Pi-hole as your DHCP server +================== + +> **Be careful, you should considering that playing with your DHCP may break your network. +In case your server is down, you will lose your dns resolution and ip address. +So, you will lose any internet connection and even the connection to your router.** + +> **If you encounter this kind of problem, please see "How to restore my network" at the end of this document.** + +### How to configure Pi-hole + +There're two ways to configure Pi-hole to be used as your DHCP server. +- Either you can choose to use it when you install the app. +- Or you can activate the DHCP server afterwards in the "Settings" tab, "Pi-hole DHCP Server" part. +In this second case, it can be better to set the ip of the server to a static address + +### How to configure my router + +Your personal router or ISP's router has a DHCP server enabled by default. +If you keep this DHCP, along with Pi-hole's one, you will have transparent conflicts between them. +The first DHCP to respond will distribute its own ip and settings. +So you have to turn off the DHCP of your router to let Pi-hole managed your network. + +#### Why should I use only the DHCP of Pi-hole ? + +By using the DHCP of Pi-hole, you allow Pi-hole to give at each of your client its dns configuration. This way every requests will be filtered by Pi-hole. + +Another use case of using Pi-hole's DHCP is if you have hairpinning problems (You can't connect to your server because its IP is your public IP, and your router doesn't allow that). +In this case, using Pi-hole's dns will allow you to connect to your server by its local address instead of its public one. + +### How to restore my network + +> Oh crap ! +Your Pi-hole server is down, and you don't have a DHCP anymore. +Don't panic, We'll get through it. \o/ + +Use your favorite terminal on your desktop computer. +And first, get your main interface (usually `eth0`). +``` bash +sudo ifconfig +``` + +Then, set your ip as a static ip. +``` bash +sudo ifconfig eth0 192.168.1.100 +``` + +Now, you can connect to your router and turn on its DHCP server to use it again. +You can now reset your ip and get a dynamic address. +``` bash +sudo ifconfig eth0 0.0.0.0 && sudo dhclient eth0 +``` + +> Don't forget to turn off the DHCP of your router if your server is working again. ## Documentation and resources * Official app website: https://pi-hole.net/ diff --git a/README_fr.md b/README_fr.md index c0cdccc..e59c023 100644 --- a/README_fr.md +++ b/README_fr.md @@ -11,7 +11,7 @@ Si vous n'avez pas YunoHost, regardez [ici](https://yunohost.org/#/install) pour ## Vue d'ensemble -Filtrage publicitaire sur l'ensemble du réseau via votre propre serveur DNS. +Filtrage publicitaire via votre propre serveur DNS **Version incluse :** 5.3.1~ynh1 @@ -32,6 +32,62 @@ Utiliser le panneau d'administration de votre Pi-hole pour configurer cette appl * Activer DHCP avec Pi-hole nécessite une configuration manuelle de votre routeur. * Pi-Hole ne peut pas être mis à jour au-delà de la version 3.3.1, car les versions supérieures utilisent une version intégrée de dnsmasq. Ce qui oblige a désactiver la version de dnsmasq utilisée par YunoHost. + +Faire de Pi-hole votre serveur DHCP +================== + +> **Attention, vous devez savoir que toucher à votre DHCP pourrait casser votre réseau. +Dans le cas où votre serveur serait inaccessible, vous perdriez votre résolution dns et votre adresse IP. +Ainsi, vous perdriez toute connexion à internet et même la connexion à votre routeur.** + +> **Si vous rencontrez ce genre de problèmes, merci de lire la section "Comment restaurer mon réseau" à la fin de ce document.** + +### Comment configurer Pi-hole + +Il y a 2 manière de configurer Pi-hole pour qu'il soit utilisé comme votre serveur DHCP. +- Soit vous pouvez choisir de l'utiliser lorsque vous installez l'application. +- Soit vous pouvez activer le serveur DHCP par la suite dans l'onglet "Settings", partie "Pi-hole DHCP Server". +Dans ce second cas, il peut être préférable de forcer l'ip du serveur à une adresse statique. + +### Comment configurer mon routeur + +Votre routeur ou celui de votre FAI dispose d'un serveur DHCP activé par défaut. +Si vous gardez ce DHCP, en même temps que celui de Pi-hole, vous allez avoir des conflits transparents entre eux. +Le premier serveur DHCP à répondre va distribuer ses propres ip et paramètres. +Donc vous devez éteindre le serveur DHCP de votre routeur et laisser Pi-hole gérer votre réseau. + +#### Pourquoi je devrais utiliser le DHCP de Pi-hole ? + +En utilisant le DHCP de Pi-hole, vous lui permettez de donner sa configuration dns à chacun de vos clients. De cette manière, chaque requête sera filtrée par Pi-hole. + +Un autre cas d'usage du DHCP de Pi-hole est le cas où vous rencontrez des problèmes de hairpinning (Vous ne pouvez pas vous connecter à votre serveur parce que son ip est votre ip publique, et votre routeur n'autorise pas cela). +Dans ce cas, utilisez le dns de Pi-hole va vous permettre de vous connecter à votre serveur par son adresse locale plutôt que son adresse publique. + +### Comment restaurer mon réseau + +> Oups ! +Votre serveur Pi-hole est tombé, et vous n'avez plus de DHCP. +Ne paniquez pas, on va surmonter ça \o/ + +Utilisez votre terminal favori sur votre ordinateur de bureau. +Et tout d'abord, récupérer votre interface réseau (Le plus souvent `eth0`). +``` bash +sudo ifconfig +``` + +Ensuite, changer votre ip pour une ip statique. +``` bash +sudo ifconfig eth0 192.168.1.100 +``` + +Maintenant, vous pouvez vous connecter à votre routeur et rallumer son serveur DHCP pour l'utiliser à nouveau. +Vous pouvez maintenant retirer votre ip statique et réobtenir une ip dynamique. +``` bash +sudo ifconfig eth0 0.0.0.0 && sudo dhclient eth0 +``` + +> N'oubliez pas d'éteindre le DHCP de votre routeur si votre serveur fonctionne à nouveau. + ## Documentations et ressources * Site officiel de l'app : https://pi-hole.net/ From 84c3f786d576c0851d08e50aec0f0dfc3f00181d Mon Sep 17 00:00:00 2001 From: ericgaspar Date: Tue, 10 Aug 2021 14:03:47 +0200 Subject: [PATCH 19/20] Remove exposed port --- scripts/install | 2 +- scripts/restore | 2 +- scripts/upgrade | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/install b/scripts/install index 614fc69..dd93984 100644 --- a/scripts/install +++ b/scripts/install @@ -449,7 +449,7 @@ cp ../conf/dnsmasq_regenconf_hook /usr/share/yunohost/hooks/conf_regen/50-dnsmas # ADVERTISE SERVICE IN ADMIN PANEL #================================================= -yunohost service add pihole-FTL --description="PiHole backend service" --log="/var/log/pihole-FTL.log" --needs_exposed_ports="$port" +yunohost service add pihole-FTL --description="PiHole backend service" --log="/var/log/pihole-FTL.log" #================================================= # RESTRAIN THE ACCESS TO THE ADMIN ONLY diff --git a/scripts/restore b/scripts/restore index 3b485fa..2cf05da 100644 --- a/scripts/restore +++ b/scripts/restore @@ -119,7 +119,7 @@ ynh_install_app_dependencies $app_depencencies # ADVERTISE SERVICE IN ADMIN PANEL #================================================= -yunohost service add pihole-FTL --description="PiHole backend service" --log="/var/log/pihole-FTL.log" --needs_exposed_ports=$port +yunohost service add pihole-FTL --description="PiHole backend service" --log="/var/log/pihole-FTL.log" #================================================= # RESTORE THE CRON FILE diff --git a/scripts/upgrade b/scripts/upgrade index 0634918..1a63b65 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -370,7 +370,7 @@ ynh_systemd_action --action=restart --service_name=pihole-FTL # ADVERTISE SERVICE IN ADMIN PANEL #================================================= -yunohost service add pihole-FTL --description="PiHole backend service" --log="/var/log/pihole-FTL.log" --needs_exposed_ports="$port" +yunohost service add pihole-FTL --description="PiHole backend service" --log="/var/log/pihole-FTL.log" #================================================= # UPDATE CONF_REGEN HOOK From 994419c68ebcb6b198016a24cb52cf50374a7096 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 11 Aug 2021 17:53:08 +0200 Subject: [PATCH 20/20] Use the FTL port, do not open it --- conf/pihole-FTL.conf | 3 +++ scripts/actions/reset_default_config | 3 ++- scripts/install | 8 +------- scripts/remove | 2 +- scripts/upgrade | 6 +----- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/conf/pihole-FTL.conf b/conf/pihole-FTL.conf index 869f50c..473ca7f 100644 --- a/conf/pihole-FTL.conf +++ b/conf/pihole-FTL.conf @@ -2,6 +2,9 @@ ; localonly|all SOCKET_LISTENING=localonly +; On which port should FTL be listening? +FTLPORT=__PORT__ + ; Display all queries? Set to no to hide query display ; yes|no QUERY_DISPLAY=yes diff --git a/scripts/actions/reset_default_config b/scripts/actions/reset_default_config index 058d735..fcec8b7 100755 --- a/scripts/actions/reset_default_config +++ b/scripts/actions/reset_default_config @@ -70,7 +70,8 @@ then elif [ "$file" = "pihole-FTL.conf" ] then # Get the default file and overwrite the current config - cp /etc/yunohost/apps/$app/conf/pihole-FTL.conf "$config_file" + port=$(ynh_app_setting_get --app=$app --key=port) + ynh_add_config --template="/etc/yunohost/apps/$app/conf/pihole-FTL.conf" --destination="$config_file" ynh_script_progression --message="Restarting Pi-Hole..." --weight=2 diff --git a/scripts/install b/scripts/install index dd93984..9c3c494 100644 --- a/scripts/install +++ b/scripts/install @@ -74,10 +74,6 @@ if [ $port -gt 4720 ] then ynh_die --message="The ports 4711 to 4720 are already in use. Pi-hole can't work on another port. Please try to free one of these ports." fi - -ynh_script_progression --message="Configuring firewall..." --weight=1 -# Open this port -ynh_exec_fully_quiet yunohost firewall allow --no-upnp TCP $port ynh_app_setting_set --app=$app --key=port --value=$port # Disable the port 53 for upnp @@ -230,10 +226,8 @@ ynh_exec_warn_less make install ) ynh_secure_remove --file="$FTL_temp_path" cp "../conf/dns-servers.conf" "$pihole_storage" -cp "../conf/pihole-FTL.conf" "$pihole_storage" -# Calculate and store the config file checksum into the app settings -ynh_store_file_checksum --file="$pihole_storage/pihole-FTL.conf" +ynh_add_config --template="../conf/pihole-FTL.conf" --destination="$pihole_storage/pihole-FTL.conf" if [ "$pihole_version" == "Last 3.X" ] then diff --git a/scripts/remove b/scripts/remove index fc85080..b9e9537 100755 --- a/scripts/remove +++ b/scripts/remove @@ -109,7 +109,7 @@ ynh_remove_fpm_config #================================================= # CLOSE PORTS #================================================= -ynh_script_progression --message="Closing ports $port et 67..." --weight=13 +ynh_script_progression --message="Closing ports $port and 67..." --weight=13 if yunohost firewall list | grep -q "\- $port$" then diff --git a/scripts/upgrade b/scripts/upgrade index 1a63b65..eea787a 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -265,11 +265,7 @@ fi # Overwrite pihole-FTL config file only if it's allowed if [ $overwrite_ftl -eq 1 ] then - # Verify the checksum of a file, stored by `ynh_store_file_checksum` in the install script. - ynh_backup_if_checksum_is_different --file="$pihole_storage/pihole-FTL.conf" - cp "../conf/pihole-FTL.conf" "$pihole_storage" - # Recalculate and store the checksum of the file for the next upgrade. - ynh_store_file_checksum --file="$pihole_storage/pihole-FTL.conf" + ynh_add_config --template="../conf/pihole-FTL.conf" --destination="$pihole_storage/pihole-FTL.conf" fi if [ "$pihole_version" == "Last 3.X" ]