From 16be07d4b6b6d729d04864e8db61126065161c1d Mon Sep 17 00:00:00 2001 From: Yunohost-Bot <> Date: Thu, 13 May 2021 17:48:02 +0200 Subject: [PATCH 01/10] [autopatch] Update issue and PR templates --- .github/ISSUE_TEMPLATE.md | 55 ++++++++++++++++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 16 ++++++++++ 2 files changed, 71 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..2729a6b --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,55 @@ +--- +name: Bug report +about: When creating a bug report, please use the following template to provide all the relevant information and help debugging efficiently. + +--- + +**How to post a meaningful bug report** +1. *Read this whole template first.* +2. *Determine if you are on the right place:* + - *If you were performing an action on the app from the webadmin or the CLI (install, update, backup, restore, change_url...), you are on the right place!* + - *Otherwise, the issue may be due to the app itself. Refer to its documentation or repository for help.* + - *When in doubt, post here and we will figure it out together.* +3. *Delete the italic comments as you write over them below, and remove this guide.* +--- + +### Describe the bug + +*A clear and concise description of what the bug is.* + +### Context + +- Hardware: *VPS bought online / Old laptop or computer / Raspberry Pi at home / Internet Cube with VPN / Other ARM board / ...* +- YunoHost version: x.x.x +- I have access to my server: *Through SSH | through the webadmin | direct access via keyboard / screen | ...* +- Are you in a special context or did you perform some particular tweaking on your YunoHost instance?: *no / yes* + - If yes, please explain: +- Using, or trying to install package version/branch: +- If upgrading, current package version: *can be found in the admin, or with `yunohost app info $app_id`* + +### Steps to reproduce + +- *If you performed a command from the CLI, the command itself is enough. For example:* + ```sh + sudo yunohost app install the_app + ``` +- *If you used the webadmin, please perform the equivalent command from the CLI first.* +- *If the error occurs in your browser, explain what you did:* + 1. *Go to '...'* + 2. *Click on '...'* + 3. *Scroll down to '...'* + 4. *See error* + +### Expected behavior + +*A clear and concise description of what you expected to happen. You can remove this section if the command above is enough to understand your intent.* + +### Logs + +*When an operation fails, YunoHost provides a simple way to share the logs.* +- *In the webadmin, the error message contains a link to the relevant log page. On that page, you will be able to 'Share with Yunopaste'. If you missed it, the logs of previous operations are also available under Tools > Logs.* +- *In command line, the command to share the logs is displayed at the end of the operation and looks like `yunohost log display [log name] --share`. If you missed it, you can find the log ID of a previous operation using `yunohost log list`.* + +*After sharing the log, please copypaste directly the link provided by YunoHost (to help readability, no need to copypaste the entire content of the log here, just the link is enough...)* + +*If applicable and useful, add screenshots to help explain your problem.* diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ef70e18 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,16 @@ +## Problem + +- *Description of why you made this PR* + +## Solution + +- *And how do you fix that problem* + +## PR Status + +- [ ] Code finished and ready to be reviewed/tested +- [ ] The fix/enhancement were manually tested (if applicable) + +## Automatic tests + +Automatic tests can be triggered on https://ci-apps-dev.yunohost.org/ *after creating the PR*, by commenting "!testme", "!gogogadgetoci" or "By the power of systemd, I invoke The Great App CI to test this Pull Request!". (N.B. : for this to work you need to be a member of the Yunohost-Apps organization) From f6c69cfe97c4cc3be66d1a8e63eeed481c190c3f Mon Sep 17 00:00:00 2001 From: ericgaspar Date: Sat, 26 Jun 2021 23:10:27 +0200 Subject: [PATCH 02/10] Remove mapzen --- check_process | 20 ++------ conf/nginx.conf | 7 ++- manifest.json | 14 +----- scripts/_common.sh | 27 ++++------- scripts/backup | 50 ++++++++++++++----- scripts/install | 116 ++++++++++++++++++++++++++++++++++++++------- 6 files changed, 156 insertions(+), 78 deletions(-) diff --git a/check_process b/check_process index 755855f..b6f01b2 100644 --- a/check_process +++ b/check_process @@ -1,8 +1,8 @@ ;; Full test ; Manifest - domain="domain.tld" (DOMAIN) - path="/path" (PATH) - is_public=1 (PUBLIC|public=1|private=0) + domain="domain.tld" + path="/path" + is_public=1 ; Checks pkg_linter=1 setup_sub_dir=1 @@ -13,21 +13,7 @@ upgrade=1 backup_restore=1 multi_instance=0 - incorrect_path=1 - port_already_use=0 change_url=0 -;;; Levels - Level 1=auto - Level 2=auto - Level 3=auto - # There is no user concept in ihatemoney - Level 4=1 - Level 5=auto - Level 6=auto - Level 7=auto - Level 8=0 - Level 9=0 - Level 10=0 ;;; Options Email= Notification=change diff --git a/conf/nginx.conf b/conf/nginx.conf index 3d13167..7c7358e 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -1,7 +1,10 @@ -location PATHTOCHANGE/static/ { +location __PATH__/static/ { alias /opt/yunohost/ihatemoney/venv/lib/pythonPYTHON_VERSION/site-packages/ihatemoney/static/; } -location PATHTOCHANGE { + +#sub_path_only rewrite ^__PATH__$ __PATH__/ permanent; +location __PATH__/ { + # Force https. if ($scheme = http) { rewrite ^ https://$server_name$request_uri? permanent; diff --git a/manifest.json b/manifest.json index 5e1bd73..d672ea1 100644 --- a/manifest.json +++ b/manifest.json @@ -15,7 +15,7 @@ "url": "https://jocelyn.delalande.fr" }, "requirements": { - "yunohost": ">= 3.8" + "yunohost": ">= 4.2.4" }, "multi_instance": false, "services": ["nginx", "mysql", "postfix"], @@ -24,29 +24,17 @@ { "name": "domain", "type": "domain", - "ask": { - "en": "Choose a domain for ihatemoney", - "fr": "Choisir un domaine pour ihatemoney" - }, "example": "example.com" }, { "name": "path", "type": "path", - "ask": { - "en": "Choose a path for ihatemoney", - "fr": "Choisir un chemin pour ihatemoney" - }, "example": "/example", "default": "/ihatemoney" }, { "name": "is_public", "type": "boolean", - "ask": { - "en": "Is it a public website ? (even if service is public, each project is protected by a password)", - "fr": "Le service est-il public ? (même dans ce cas, chaque projet est protégé par un mot de passe)" - }, "default": true } ] diff --git a/scripts/_common.sh b/scripts/_common.sh index 8c54da6..8cc6629 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -1,3 +1,13 @@ +#================================================= +# COMMON VARIABLES +#================================================= + +# dependencies used by the app +pkg_dependencies="python3-dev python3-virtualenv libffi-dev libssl-dev supervisor virtualenv" + + + + ### Constants supervisor_conf_path="/etc/supervisor/conf.d/ihatemoney.conf" @@ -6,23 +16,6 @@ ihatemoney_conf_path="/etc/ihatemoney/ihatemoney.cfg" INSTALL_DIR="/opt/yunohost/ihatemoney" -### Functions - - -install_apt_dependencies() { - ynh_install_app_dependencies \ - python3-dev \ - python3-virtualenv \ - libffi-dev \ - libssl-dev \ - supervisor \ - virtualenv -} - -create_unix_user() { - mkdir -p /opt/yunohost - useradd ihatemoney -d /opt/yunohost/ihatemoney/ --create-home || ynh_die "User creation failed" -} create_system_dirs() { install -o ihatemoney -g ihatemoney -m 755 -d \ diff --git a/scripts/backup b/scripts/backup index 7c21e82..b1cfaf8 100644 --- a/scripts/backup +++ b/scripts/backup @@ -1,25 +1,39 @@ #!/bin/bash -# Source YunoHost helpers +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +# Keep this path for calling _common.sh inside the execution's context of backup and restore scripts source ../settings/scripts/_common.sh source /usr/share/yunohost/helpers +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_clean_setup () { + ### Remove this function if there's nothing to clean before calling the remove script. + true +} +# Exit if an error occurs during the execution of the script ynh_abort_if_errors -# Get multi-instances specific variables +#================================================= +# LOAD SETTINGS +#================================================= +ynh_print_info --message="Loading installation settings..." + app=$YNH_APP_INSTANCE_NAME -# Set app specific variables -dbname=$app -dbuser=$app +final_path=$(ynh_app_setting_get --app=$app --key=final_path) +domain=$(ynh_app_setting_get --app=$app --key=domain) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) INSTALL_DIR=/opt/yunohost/ihatemoney -# Retrieve app settings -domain=$(ynh_app_setting_get "$app" domain) -path=$(ynh_app_setting_get "$app" path) -dbpass=$(ynh_app_setting_get "$app" mysqlpwd) - # Backup conf files mkdir ./conf ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" @@ -27,8 +41,18 @@ ynh_backup "$gunicorn_conf_path" ynh_backup "$supervisor_conf_path" ynh_backup "$ihatemoney_conf_path" -# Dump the database -mysqldump -u "$dbuser" -p"$dbpass" --no-create-db "$dbname" > ./db.sql - # Backup code and venv ynh_backup "$INSTALL_DIR" "install_dir" + +#================================================= +# BACKUP THE MYSQL DATABASE +#================================================= +ynh_print_info --message="Backing up the MySQL database..." + +ynh_mysql_dump_db --database="$db_name" > db.sql + +#================================================= +# END OF SCRIPT +#================================================= + +ynh_print_info --message="Backup script completed for $app. (YunoHost will then actually copy those files to the archive)." diff --git a/scripts/install b/scripts/install index 8c1202c..4c389fd 100755 --- a/scripts/install +++ b/scripts/install @@ -1,14 +1,30 @@ #!/bin/bash -# Source YunoHost helpers +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + source _common.sh source /usr/share/yunohost/helpers +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_abort_if_errors + +#================================================= +# RETRIEVE ARGUMENTS FROM THE MANIFEST +#================================================= + # Retrieve arguments domain=$YNH_APP_ARG_DOMAIN path=$YNH_APP_ARG_PATH is_public=$YNH_APP_ARG_IS_PUBLIC -app=ihatemoney + +app=$YNH_APP_INSTANCE_NAME # Database settings db_pwd=$(ynh_string_random) @@ -20,12 +36,52 @@ secret_key=$(ynh_string_random --length 32) mails_sender="no-reply@${domain}" -ynh_abort_if_errors -ynh_webpath_register $app $domain $path +#================================================= +# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS +#================================================= +ynh_script_progression --message="Validating installation parameters..." --weight=1 + +final_path=/opt/yunohost/$app +test ! -e "$final_path" || ynh_die --message="This path already contains a folder" + +# Register (book) web path +ynh_webpath_register --app=$app --domain=$domain --path_url=$path_url + +#================================================= +# STORE SETTINGS FROM MANIFEST +#================================================= +ynh_script_progression --message="Storing installation settings..." --weight=1 + +ynh_app_setting_set --app=$app --key=domain --value=$domain +ynh_app_setting_set --app=$app --key=path --value=$path_url + +#================================================= +# INSTALL DEPENDENCIES +#================================================= +ynh_script_progression --message="Installing dependencies..." --weight=1 + +ynh_install_app_dependencies $pkg_dependencies + +#================================================= +# CREATE DEDICATED USER +#================================================= +ynh_script_progression --message="Configuring system user..." --weight=1 + +# Create a system user +ynh_system_user_create --username=$app --home_dir="$final_path" + +#================================================= +# CREATE A MYSQL DATABASE +#================================================= +ynh_script_progression --message="Creating a MySQL database..." --time --weight=1 + +db_name=$(ynh_sanitize_dbid --db_name=$app) +db_user=$db_name +ynh_app_setting_set --app=$app --key=db_name --value=$db_name +ynh_mysql_setup_db --db_user=$db_user --db_name=$db_name + -# Configure database -ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Save app settings ynh_app_setting_set "$app" mysqlpwd "$db_pwd" @@ -62,17 +118,23 @@ sed -i "/APPLICATION_ROOT='\/'/d" ../conf/ihatemoney.cfg install -o ihatemoney -g ihatemoney -m 640 \ ../conf/ihatemoney.cfg /etc/ihatemoney/ihatemoney.cfg -# If app is public, add url to SSOWat conf as skipped_uris -if [[ "$is_public" -ne 0 ]]; -then - ynh_app_setting_set $app unprotected_uris "/" -fi +#================================================= +# NGINX CONFIGURATION +#================================================= +ynh_script_progression --message="Configuring NGINX web server..." --weight=1 + +# Create a dedicated NGINX config +ynh_add_nginx_config + +#================================================= +# START SYSTEMD SERVICE +#================================================= +ynh_script_progression --message="Starting a systemd service..." --time --weight=1 + +# Start a systemd service +ynh_systemd_action --service_name=supervisor --action="start" --log_path="/var/log/$app/$app.log" -# Configure Nginx -configure_nginx "$domain" "$path" -# Start backend -systemctl start supervisor # Wait that gunicorn is ready to consider the install finished, that is to # avoid HTTP 502 right after installation @@ -85,4 +147,26 @@ done # If socket not ready after 2 minutes waiting, ihatemoney will not work. test -S /tmp/budget.gunicorn.sock || ynh_die -systemctl reload nginx +#================================================= +# SETUP SSOWAT +#================================================= +ynh_script_progression --message="Configuring permissions..." --weight=1 + +# Make app public if necessary +if [ $is_public -eq 1 ] +then + ynh_permission_update --permission="main" --add="visitors" +fi + +#================================================= +# RELOAD NGINX +#================================================= +ynh_script_progression --message="Reloading NGINX web server..." --weight=1 + +ynh_systemd_action --service_name=nginx --action=reload + +#================================================= +# END OF SCRIPT +#================================================= + +ynh_script_progression --message="Installation of $app completed" --last From 717424b28dd7d5037760bc862685409d6caf001b Mon Sep 17 00:00:00 2001 From: ericgaspar Date: Sat, 26 Jun 2021 23:16:47 +0200 Subject: [PATCH 03/10] Revert "Remove mapzen" This reverts commit f6c69cfe97c4cc3be66d1a8e63eeed481c190c3f. --- check_process | 20 ++++++-- conf/nginx.conf | 7 +-- manifest.json | 14 +++++- scripts/_common.sh | 27 +++++++---- scripts/backup | 50 +++++-------------- scripts/install | 116 +++++++-------------------------------------- 6 files changed, 78 insertions(+), 156 deletions(-) diff --git a/check_process b/check_process index b6f01b2..755855f 100644 --- a/check_process +++ b/check_process @@ -1,8 +1,8 @@ ;; Full test ; Manifest - domain="domain.tld" - path="/path" - is_public=1 + domain="domain.tld" (DOMAIN) + path="/path" (PATH) + is_public=1 (PUBLIC|public=1|private=0) ; Checks pkg_linter=1 setup_sub_dir=1 @@ -13,7 +13,21 @@ upgrade=1 backup_restore=1 multi_instance=0 + incorrect_path=1 + port_already_use=0 change_url=0 +;;; Levels + Level 1=auto + Level 2=auto + Level 3=auto + # There is no user concept in ihatemoney + Level 4=1 + Level 5=auto + Level 6=auto + Level 7=auto + Level 8=0 + Level 9=0 + Level 10=0 ;;; Options Email= Notification=change diff --git a/conf/nginx.conf b/conf/nginx.conf index 7c7358e..3d13167 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -1,10 +1,7 @@ -location __PATH__/static/ { +location PATHTOCHANGE/static/ { alias /opt/yunohost/ihatemoney/venv/lib/pythonPYTHON_VERSION/site-packages/ihatemoney/static/; } - -#sub_path_only rewrite ^__PATH__$ __PATH__/ permanent; -location __PATH__/ { - +location PATHTOCHANGE { # Force https. if ($scheme = http) { rewrite ^ https://$server_name$request_uri? permanent; diff --git a/manifest.json b/manifest.json index d672ea1..5e1bd73 100644 --- a/manifest.json +++ b/manifest.json @@ -15,7 +15,7 @@ "url": "https://jocelyn.delalande.fr" }, "requirements": { - "yunohost": ">= 4.2.4" + "yunohost": ">= 3.8" }, "multi_instance": false, "services": ["nginx", "mysql", "postfix"], @@ -24,17 +24,29 @@ { "name": "domain", "type": "domain", + "ask": { + "en": "Choose a domain for ihatemoney", + "fr": "Choisir un domaine pour ihatemoney" + }, "example": "example.com" }, { "name": "path", "type": "path", + "ask": { + "en": "Choose a path for ihatemoney", + "fr": "Choisir un chemin pour ihatemoney" + }, "example": "/example", "default": "/ihatemoney" }, { "name": "is_public", "type": "boolean", + "ask": { + "en": "Is it a public website ? (even if service is public, each project is protected by a password)", + "fr": "Le service est-il public ? (même dans ce cas, chaque projet est protégé par un mot de passe)" + }, "default": true } ] diff --git a/scripts/_common.sh b/scripts/_common.sh index 8cc6629..8c54da6 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -1,13 +1,3 @@ -#================================================= -# COMMON VARIABLES -#================================================= - -# dependencies used by the app -pkg_dependencies="python3-dev python3-virtualenv libffi-dev libssl-dev supervisor virtualenv" - - - - ### Constants supervisor_conf_path="/etc/supervisor/conf.d/ihatemoney.conf" @@ -16,6 +6,23 @@ ihatemoney_conf_path="/etc/ihatemoney/ihatemoney.cfg" INSTALL_DIR="/opt/yunohost/ihatemoney" +### Functions + + +install_apt_dependencies() { + ynh_install_app_dependencies \ + python3-dev \ + python3-virtualenv \ + libffi-dev \ + libssl-dev \ + supervisor \ + virtualenv +} + +create_unix_user() { + mkdir -p /opt/yunohost + useradd ihatemoney -d /opt/yunohost/ihatemoney/ --create-home || ynh_die "User creation failed" +} create_system_dirs() { install -o ihatemoney -g ihatemoney -m 755 -d \ diff --git a/scripts/backup b/scripts/backup index b1cfaf8..7c21e82 100644 --- a/scripts/backup +++ b/scripts/backup @@ -1,39 +1,25 @@ #!/bin/bash -#================================================= -# GENERIC START -#================================================= -# IMPORT GENERIC HELPERS -#================================================= - -# Keep this path for calling _common.sh inside the execution's context of backup and restore scripts +# Source YunoHost helpers source ../settings/scripts/_common.sh source /usr/share/yunohost/helpers -#================================================= -# MANAGE SCRIPT FAILURE -#================================================= - -ynh_clean_setup () { - ### Remove this function if there's nothing to clean before calling the remove script. - true -} -# Exit if an error occurs during the execution of the script ynh_abort_if_errors -#================================================= -# LOAD SETTINGS -#================================================= -ynh_print_info --message="Loading installation settings..." - +# Get multi-instances specific variables app=$YNH_APP_INSTANCE_NAME -final_path=$(ynh_app_setting_get --app=$app --key=final_path) -domain=$(ynh_app_setting_get --app=$app --key=domain) -db_name=$(ynh_app_setting_get --app=$app --key=db_name) +# Set app specific variables +dbname=$app +dbuser=$app INSTALL_DIR=/opt/yunohost/ihatemoney +# Retrieve app settings +domain=$(ynh_app_setting_get "$app" domain) +path=$(ynh_app_setting_get "$app" path) +dbpass=$(ynh_app_setting_get "$app" mysqlpwd) + # Backup conf files mkdir ./conf ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" @@ -41,18 +27,8 @@ ynh_backup "$gunicorn_conf_path" ynh_backup "$supervisor_conf_path" ynh_backup "$ihatemoney_conf_path" +# Dump the database +mysqldump -u "$dbuser" -p"$dbpass" --no-create-db "$dbname" > ./db.sql + # Backup code and venv ynh_backup "$INSTALL_DIR" "install_dir" - -#================================================= -# BACKUP THE MYSQL DATABASE -#================================================= -ynh_print_info --message="Backing up the MySQL database..." - -ynh_mysql_dump_db --database="$db_name" > db.sql - -#================================================= -# END OF SCRIPT -#================================================= - -ynh_print_info --message="Backup script completed for $app. (YunoHost will then actually copy those files to the archive)." diff --git a/scripts/install b/scripts/install index 4c389fd..8c1202c 100755 --- a/scripts/install +++ b/scripts/install @@ -1,30 +1,14 @@ #!/bin/bash -#================================================= -# GENERIC START -#================================================= -# IMPORT GENERIC HELPERS -#================================================= - +# Source YunoHost helpers source _common.sh source /usr/share/yunohost/helpers -#================================================= -# MANAGE SCRIPT FAILURE -#================================================= - -ynh_abort_if_errors - -#================================================= -# RETRIEVE ARGUMENTS FROM THE MANIFEST -#================================================= - # Retrieve arguments domain=$YNH_APP_ARG_DOMAIN path=$YNH_APP_ARG_PATH is_public=$YNH_APP_ARG_IS_PUBLIC - -app=$YNH_APP_INSTANCE_NAME +app=ihatemoney # Database settings db_pwd=$(ynh_string_random) @@ -36,52 +20,12 @@ secret_key=$(ynh_string_random --length 32) mails_sender="no-reply@${domain}" +ynh_abort_if_errors -#================================================= -# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS -#================================================= -ynh_script_progression --message="Validating installation parameters..." --weight=1 - -final_path=/opt/yunohost/$app -test ! -e "$final_path" || ynh_die --message="This path already contains a folder" - -# Register (book) web path -ynh_webpath_register --app=$app --domain=$domain --path_url=$path_url - -#================================================= -# STORE SETTINGS FROM MANIFEST -#================================================= -ynh_script_progression --message="Storing installation settings..." --weight=1 - -ynh_app_setting_set --app=$app --key=domain --value=$domain -ynh_app_setting_set --app=$app --key=path --value=$path_url - -#================================================= -# INSTALL DEPENDENCIES -#================================================= -ynh_script_progression --message="Installing dependencies..." --weight=1 - -ynh_install_app_dependencies $pkg_dependencies - -#================================================= -# CREATE DEDICATED USER -#================================================= -ynh_script_progression --message="Configuring system user..." --weight=1 - -# Create a system user -ynh_system_user_create --username=$app --home_dir="$final_path" - -#================================================= -# CREATE A MYSQL DATABASE -#================================================= -ynh_script_progression --message="Creating a MySQL database..." --time --weight=1 - -db_name=$(ynh_sanitize_dbid --db_name=$app) -db_user=$db_name -ynh_app_setting_set --app=$app --key=db_name --value=$db_name -ynh_mysql_setup_db --db_user=$db_user --db_name=$db_name - +ynh_webpath_register $app $domain $path +# Configure database +ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Save app settings ynh_app_setting_set "$app" mysqlpwd "$db_pwd" @@ -118,23 +62,17 @@ sed -i "/APPLICATION_ROOT='\/'/d" ../conf/ihatemoney.cfg install -o ihatemoney -g ihatemoney -m 640 \ ../conf/ihatemoney.cfg /etc/ihatemoney/ihatemoney.cfg -#================================================= -# NGINX CONFIGURATION -#================================================= -ynh_script_progression --message="Configuring NGINX web server..." --weight=1 - -# Create a dedicated NGINX config -ynh_add_nginx_config - -#================================================= -# START SYSTEMD SERVICE -#================================================= -ynh_script_progression --message="Starting a systemd service..." --time --weight=1 - -# Start a systemd service -ynh_systemd_action --service_name=supervisor --action="start" --log_path="/var/log/$app/$app.log" +# If app is public, add url to SSOWat conf as skipped_uris +if [[ "$is_public" -ne 0 ]]; +then + ynh_app_setting_set $app unprotected_uris "/" +fi +# Configure Nginx +configure_nginx "$domain" "$path" +# Start backend +systemctl start supervisor # Wait that gunicorn is ready to consider the install finished, that is to # avoid HTTP 502 right after installation @@ -147,26 +85,4 @@ done # If socket not ready after 2 minutes waiting, ihatemoney will not work. test -S /tmp/budget.gunicorn.sock || ynh_die -#================================================= -# SETUP SSOWAT -#================================================= -ynh_script_progression --message="Configuring permissions..." --weight=1 - -# Make app public if necessary -if [ $is_public -eq 1 ] -then - ynh_permission_update --permission="main" --add="visitors" -fi - -#================================================= -# RELOAD NGINX -#================================================= -ynh_script_progression --message="Reloading NGINX web server..." --weight=1 - -ynh_systemd_action --service_name=nginx --action=reload - -#================================================= -# END OF SCRIPT -#================================================= - -ynh_script_progression --message="Installation of $app completed" --last +systemctl reload nginx From ce58c792c734814e40988348276bce4e3a641284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Pi=C3=A9dallu?= Date: Fri, 21 May 2021 01:10:01 +0200 Subject: [PATCH 04/10] Full revamp of ihatemoney_ynh: * Use example_ynh as a template * Implement change_url * Use the new yunohost permissions system * Use a python3 venv * Use a systemd service + gunicorn * Allow multiple instances (stop installing in /opt/yunohost/ihatemoney) --- README.md | 79 +++-- README_fr.md | 59 ++++ check_process | 29 +- conf/gunicorn.conf.py | 4 +- conf/ihatemoney.cfg | 8 +- conf/nginx.conf | 11 +- conf/supervisord.conf | 6 - conf/systemd.service | 15 + doc/DISCLAIMER.md | 10 + doc/DISCLAIMER_fr.md | 10 + doc/screenshots/screenshot_1_global.webp | Bin 0 -> 13970 bytes .../screenshot_2_new_operation.webp | Bin 0 -> 11896 bytes manifest.json | 38 ++- scripts/_common.sh | 103 +++---- scripts/backup | 88 ++++-- scripts/change_url | 150 +++++++++ scripts/install | 229 ++++++++++---- scripts/remove | 120 ++++++-- scripts/restore | 157 +++++++--- scripts/upgrade | 286 ++++++++++++------ 20 files changed, 1013 insertions(+), 389 deletions(-) create mode 100644 README_fr.md delete mode 100644 conf/supervisord.conf create mode 100644 conf/systemd.service create mode 100644 doc/DISCLAIMER.md create mode 100644 doc/DISCLAIMER_fr.md create mode 100644 doc/screenshots/screenshot_1_global.webp create mode 100644 doc/screenshots/screenshot_2_new_operation.webp mode change 100644 => 100755 scripts/backup create mode 100644 scripts/change_url mode change 100644 => 100755 scripts/restore mode change 100755 => 100644 scripts/upgrade diff --git a/README.md b/README.md index 00a2308..fe1bca7 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,65 @@ -Yunohost app for « I hate money » budget web app -================================================ +--- -[![Install « I hate money » with YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=ihatemoney) + -- Supported Yunohost versions : 2.6.x, 2.7.x 3.x -- Tested Yunohost version : 3.3.1 +# I Hate Money for YunoHost -*NB: That means I'll try not to drop support for YunoHost 2.x too soon, and -accept patches to keep retro-compatibility, but I'll not test it myself against -YunoHost 2.x* +[![Integration level](https://dash.yunohost.org/integration/ihatemoney.svg)](https://dash.yunohost.org/appci/app/ihatemoney) ![](https://ci-apps.yunohost.org/ci/badges/ihatemoney.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/ihatemoney.maintain.svg) +[![Install I Hate Money with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=ihatemoney) -Backs on MySQL database, the identifiers are per-project, not per-user, so no -way to do advanced SSO integration with yunohost accounts. +*[Lire ce readme en français.](./README_fr.md)* -The behaviour is either: +> *This package allows you to install I Hate Money 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 + +I hate money is a web application made to ease shared budget management. It keeps track of who bought what, when, and for whom; and helps to settle the bills. + +**Shipped version:** 4.1.5~ynh2 + +## Screenshots + +![](./doc/screenshots/screenshot_1_global.webp) +![](./doc/screenshots/screenshot_2_new_operation.webp) + +## Disclaimers / important information + +* Is LDAP and HTTP authentication supported ? **No** + +The logins are per-project (not per-user) so it's not integrable in the Yunohost login system. + +The app can be public or not. The behaviour is either: - **non-public app**: - yunohost login required - per-project identifiers required - - any yunohost user with authorized access to the app can create a new - project). + - any yunohost user with access to the app can create a new project. - **public app** : - no yunohost login required - per-project identifiers required - any visitor can create a new project. -Update ------- +## Documentation and resources -To update the app, use: +* Official app website: https://github.com/spiral-project/ihatemoney +* Official admin documentation: https://ihatemoney.readthedocs.org/ +* Upstream app code repository: https://github.com/spiral-project/ihatemoney +* YunoHost documentation for this app: https://yunohost.org/app_ihatemoney +* Report a bug: https://github.com/YunoHost-Apps/ihatemoney_ynh/issues -`sudo yunohost app upgrade ihatemoney -u https://github.com/YunoHost-Apps/ihatemoney_ynh` - +## Developer info -Maintainer ----------- +Please send your pull request to the [testing branch](https://github.com/YunoHost-Apps/ihatemoney_ynh/tree/testing). -I rely on -[ihatemoney official releases](https://github.com/spiral-project/ihatemoney/releases) -(tarballs). Don't hesitate to pull-request this repo if I missed one :-). - - -Ihatemoney license ------------------- - -> The code is distributed under a BSD beerware derivative: if you meet the -> people in person and you want to pay them a craft beer, you are highly -> encouraged to do so. - -[Full license text](https://github.com/spiral-project/ihatemoney/blob/master/LICENSE) +To try the testing branch, please proceed like that. +``` +sudo yunohost app install https://github.com/YunoHost-Apps/ihatemoney_ynh/tree/testing --debug +or +sudo yunohost app upgrade ihatemoney -u https://github.com/YunoHost-Apps/ihatemoney_ynh/tree/testing --debug +``` +**More info regarding app packaging:** https://yunohost.org/packaging_apps diff --git a/README_fr.md b/README_fr.md new file mode 100644 index 0000000..2331937 --- /dev/null +++ b/README_fr.md @@ -0,0 +1,59 @@ +# I Hate Money pour YunoHost + +[![Niveau d'intégration](https://dash.yunohost.org/integration/ihatemoney.svg)](https://dash.yunohost.org/appci/app/ihatemoney) ![](https://ci-apps.yunohost.org/ci/badges/ihatemoney.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/ihatemoney.maintain.svg) +[![Installer I Hate Money avec YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=ihatemoney) + +*[Read this readme in english.](./README.md)* +*[Lire ce readme en français.](./README_fr.md)* + +> *Ce package vous permet d'installer I Hate Money rapidement et simplement sur un serveur YunoHost. +Si vous n'avez pas YunoHost, consultez [le guide](https://yunohost.org/#/install) pour apprendre comment l'installer.* + +## Vue d'ensemble + +Une application web de comptes partagés à plusieurs + +**Version incluse:** 4.1.5~ynh2 + +## Captures d'écran + +![](./doc/screenshots/screenshot_1_global.webp) +![](./doc/screenshots/screenshot_2_new_operation.webp) + +## Avertissements / informations importantes + +* L'authentification LDAP et HTTP est-elle prise en charge ? **Non** + +L'authentification est par projet (et non par utilisateur) donc ce n'est pas intégrable dans le système d'authentification de Yunohost. + +L'application peut néanmoins être configurée en public ou non : + +- **app non publique**: + - authentification Yunohost requise + - identifiants de projets requis + - Tout utilisateur Yunohost avec accès à l'app peut créer un nouveau projet. +- **app publique** : + - authentification Yunohost non requise + - identifiants de projets requis + - Tout visiteur peut créer un nouveau projet. + +## Documentations et ressources + +* Site officiel de l'app : https://github.com/spiral-project/ihatemoney +* Documentation officielle de l'admin: https://ihatemoney.readthedocs.org/ +* Dépôt de code officiel de l'app: https://github.com/spiral-project/ihatemoney +* Documentation YunoHost pour cette app: https://yunohost.org/app_ihatemoney +* Signaler un bug: https://github.com/YunoHost-Apps/ihatemoney_ynh/issues + +## Informations pour les développeurs + +Merci de faire vos pull request sur la [branche testing](https://github.com/YunoHost-Apps/ihatemoney_ynh/tree/testing). + +Pour essayer la branche testing, procédez comme suit. +``` +sudo yunohost app install https://github.com/YunoHost-Apps/ihatemoney_ynh/tree/testing --debug +or +sudo yunohost app upgrade ihatemoney -u https://github.com/YunoHost-Apps/ihatemoney_ynh/tree/testing --debug +``` + +**Plus d'infos sur le packaging d'applications:** https://yunohost.org/packaging_apps \ No newline at end of file diff --git a/check_process b/check_process index 755855f..461d489 100644 --- a/check_process +++ b/check_process @@ -1,8 +1,8 @@ ;; Full test ; Manifest - domain="domain.tld" (DOMAIN) - path="/path" (PATH) - is_public=1 (PUBLIC|public=1|private=0) + domain="domain.tld" + path="/path" + is_public=1 ; Checks pkg_linter=1 setup_sub_dir=1 @@ -11,23 +11,14 @@ setup_private=1 setup_public=1 upgrade=1 + upgrade=1 from_commit=0f904d99367cfec27ec5fe303941fbf1124a7571 backup_restore=1 - multi_instance=0 - incorrect_path=1 + multi_instance=1 port_already_use=0 - change_url=0 -;;; Levels - Level 1=auto - Level 2=auto - Level 3=auto - # There is no user concept in ihatemoney - Level 4=1 - Level 5=auto - Level 6=auto - Level 7=auto - Level 8=0 - Level 9=0 - Level 10=0 + change_url=1 ;;; Options Email= -Notification=change +Notification=none +;;; Upgrade options + ; commit=0f904d99367cfec27ec5fe303941fbf1124a7571 + name=Before refactoring yunohost package diff --git a/conf/gunicorn.conf.py b/conf/gunicorn.conf.py index 60fcdd1..f38b59a 100644 --- a/conf/gunicorn.conf.py +++ b/conf/gunicorn.conf.py @@ -2,6 +2,6 @@ backlog = 2048 daemon = False debug = True workers = 3 -logfile = "/var/log/ihatemoney/budget.gunicorn.log" +logfile = "/var/log/__APP__/budget.gunicorn.log" loglevel = "info" -bind = "unix:/tmp/budget.gunicorn.sock" +bind = "unix:/tmp/budget.gunicorn___APP__.sock" diff --git a/conf/ihatemoney.cfg b/conf/ihatemoney.cfg index f41f6ce..147c189 100644 --- a/conf/ihatemoney.cfg +++ b/conf/ihatemoney.cfg @@ -1,10 +1,10 @@ DEBUG = True -SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://ihatemoney:MY_MYSQL_PW@localhost/ihatemoney' +SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://__DB_USER__:__DB_PWD__@localhost/__DB_NAME__' SQLACHEMY_ECHO = DEBUG -SECRET_KEY = "MY_SECRET_KEY" +SECRET_KEY = "__SECRET_KEY__" -MAIL_DEFAULT_SENDER = ("Budget manager", "MY_EMAIL") -APPLICATION_ROOT='MY_PATH' +MAIL_DEFAULT_SENDER = ("Budget manager", "__MAILS_SENDER__") +__SUB_PATH_ONLY__APPLICATION_ROOT='__PATH__' try: from settings import * diff --git a/conf/nginx.conf b/conf/nginx.conf index 3d13167..e096719 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -1,8 +1,9 @@ -location PATHTOCHANGE/static/ { - alias /opt/yunohost/ihatemoney/venv/lib/pythonPYTHON_VERSION/site-packages/ihatemoney/static/; +#sub_path_only rewrite ^__PATH__$ __PATH__/ permanent; +location __PATH__/static/ { + alias __PYTHON_VENV_SITE_PACKAGES__/ihatemoney/static/; } -location PATHTOCHANGE { - # Force https. +location __PATH__/ { + # Force usage of https if ($scheme = http) { rewrite ^ https://$server_name$request_uri? permanent; } @@ -18,7 +19,7 @@ location PATHTOCHANGE { proxy_busy_buffers_size 32k; proxy_intercept_errors on; if (!-f $request_filename) { - proxy_pass http://unix:/tmp/budget.gunicorn.sock; + proxy_pass http://unix:/tmp/budget.gunicorn___APP__.sock; break; } diff --git a/conf/supervisord.conf b/conf/supervisord.conf deleted file mode 100644 index 86e36b3..0000000 --- a/conf/supervisord.conf +++ /dev/null @@ -1,6 +0,0 @@ -[program:budget] -command=/opt/yunohost/ihatemoney/venv/bin/gunicorn -c /etc/ihatemoney/gunicorn.conf.py ihatemoney.wsgi:application -user=ihatemoney -autostart=true -autorestart=true -redirect_stderr=true diff --git a/conf/systemd.service b/conf/systemd.service new file mode 100644 index 0000000..5803179 --- /dev/null +++ b/conf/systemd.service @@ -0,0 +1,15 @@ +[Unit] +Description=I hate money +Requires=network.target mysql.service +After=network.target mysql.service + +[Service] +Type=simple +User=__APP__ +Environment=IHATEMONEY_SETTINGS_FILE_PATH=__FINALPATH__/ihatemoney.cfg +ExecStart=__FINALPATH__/venv/bin/gunicorn -c __FINALPATH__/gunicorn.conf.py ihatemoney.wsgi:application +Restart=always +RestartSec=2 + +[Install] +WantedBy=multi-user.target diff --git a/doc/DISCLAIMER.md b/doc/DISCLAIMER.md new file mode 100644 index 0000000..37b4fcf --- /dev/null +++ b/doc/DISCLAIMER.md @@ -0,0 +1,10 @@ +* LDAP authentication and Single Sign-on is not supported. The login mechanism in IHateMoney is per-project (not per-user) and therefore can't be integrated in YunoHost. + +- **non-public app**: + - yunohost login required + - per-project identifiers required + - any yunohost user with access to the app can create a new project. +- **public app** : + - no yunohost login required + - per-project identifiers required + - any visitor can create a new project. diff --git a/doc/DISCLAIMER_fr.md b/doc/DISCLAIMER_fr.md new file mode 100644 index 0000000..5403414 --- /dev/null +++ b/doc/DISCLAIMER_fr.md @@ -0,0 +1,10 @@ +* L'authentification LDAP et login unifié (SSO) n'est pas supportée. Le mécanisme de connexion sur IHateMoney se fait par projet et ne peut donc pas être intégrée dans YunoHost + +- **app non publique**: + - authentification Yunohost requise + - identifiants de projets requis + - Tout utilisateur Yunohost avec accès à l'app peut créer un nouveau projet. +- **app publique** : + - authentification Yunohost non requise + - identifiants de projets requis + - Tout visiteur peut créer un nouveau projet. diff --git a/doc/screenshots/screenshot_1_global.webp b/doc/screenshots/screenshot_1_global.webp new file mode 100644 index 0000000000000000000000000000000000000000..e626c28034686bdaf425785f4d17886d85debe7e GIT binary patch literal 13970 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 z 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 U;;jUEZY>+ki;PDu{hKlV4_!O~^#A|> literal 0 HcmV?d00001 diff --git a/doc/screenshots/screenshot_2_new_operation.webp b/doc/screenshots/screenshot_2_new_operation.webp new file mode 100644 index 0000000000000000000000000000000000000000..d76564d4541d8ec7e34d0b3fdcc5bad157fc0555 GIT binary patch literal 11896 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 3.8" + "yunohost": ">= 4.1.0" }, - "multi_instance": false, + "multi_instance": true, "services": ["nginx", "mysql", "postfix"], "arguments": { "install" : [ { "name": "domain", - "type": "domain", - "ask": { - "en": "Choose a domain for ihatemoney", - "fr": "Choisir un domaine pour ihatemoney" - }, - "example": "example.com" + "type": "domain" }, { "name": "path", "type": "path", - "ask": { - "en": "Choose a path for ihatemoney", - "fr": "Choisir un chemin pour ihatemoney" - }, - "example": "/example", + "example": "/ihatemoney", "default": "/ihatemoney" }, { "name": "is_public", "type": "boolean", - "ask": { - "en": "Is it a public website ? (even if service is public, each project is protected by a password)", - "fr": "Le service est-il public ? (même dans ce cas, chaque projet est protégé par un mot de passe)" + "help": { + "en": "Each ihatemoney project is protected by a password anyways", + "fr": "Les projets ihatemoney sont protégés par un mot de passe dans tous les cas" }, "default": true } diff --git a/scripts/_common.sh b/scripts/_common.sh index 8c54da6..7ca836a 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -1,69 +1,56 @@ +#!/bin/bash + +#================================================= +# COMMON VARIABLES +#================================================= + +# dependencies used by the app +pkg_dependencies=( + python3-dev + python3-venv + libffi-dev + libssl-dev +) + +pip_dependencies=( + 'setuptools>=18.5' + 'gunicorn>=19.3.0' + 'PyMySQL>=0.9,<0.10' + 'SQLAlchemy<1.4' + 'ihatemoney>=4,<5' +) + ### Constants -supervisor_conf_path="/etc/supervisor/conf.d/ihatemoney.conf" -gunicorn_conf_path="/etc/ihatemoney/gunicorn.conf.py" -ihatemoney_conf_path="/etc/ihatemoney/ihatemoney.cfg" -INSTALL_DIR="/opt/yunohost/ihatemoney" +#================================================= +# PERSONAL HELPERS +#================================================= +__ynh_python_venv_setup() { + local -A args_array=( [d]=venv_dir= [p]=packages= ) + local venv_dir + local packages + ynh_handle_getopts_args "$@" -### Functions + python3 -m venv --system-site-packages "$venv_dir" - -install_apt_dependencies() { - ynh_install_app_dependencies \ - python3-dev \ - python3-virtualenv \ - libffi-dev \ - libssl-dev \ - supervisor \ - virtualenv + IFS=" " read -r -a pip_packages <<< "$packages" + "$venv_dir/bin/python3" -m pip install --upgrade pip "${pip_packages[@]}" } -create_unix_user() { - mkdir -p /opt/yunohost - useradd ihatemoney -d /opt/yunohost/ihatemoney/ --create-home || ynh_die "User creation failed" +__ynh_python_venv_get_site_packages_dir() { + local -A args_array=( [d]=venv_dir= ) + local venv_dir + ynh_handle_getopts_args "$@" + + "$venv_dir/bin/python3" -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])' } -create_system_dirs() { - install -o ihatemoney -g ihatemoney -m 755 -d \ - /var/log/ihatemoney \ - /etc/ihatemoney - mkdir -p /opt/yunohost -} -init_virtualenv () { - virtualenv /opt/yunohost/ihatemoney/venv --python /usr/bin/python3 +#================================================= +# EXPERIMENTAL HELPERS +#================================================= - # PyMySQL → cryptography → setuptools>=18.5 - # Required on Jessie, Stretch has setuptools>=18.5 - /opt/yunohost/ihatemoney/venv/bin/pip install 'setuptools>=18.5' -} - -pip_install () { - # SQLAlchemy requirement is workaround https://github.com/pallets/flask-sqlalchemy/issues/910 - # Might be removed later when IHM dependency set will no longer prevent working installation. - /opt/yunohost/ihatemoney/venv/bin/pip install --upgrade \ - 'gunicorn>=19.3.0' \ - 'PyMySQL>=0.9,<0.10' \ - 'ihatemoney>=4,<5' \ - 'SQLAlchemy<1.4' \ - -} - -configure_nginx () { - local domain=$1 - local path=$2 - local python_version="$(readlink /usr/bin/python3|sed s/.*python//)" - - ynh_replace_string "PATHTOCHANGE" "$path" ../conf/nginx.conf - ynh_replace_string "PYTHON_VERSION" "$python_version" ../conf/nginx.conf - # Fix double-slash for domain-root install - ynh_replace_string "location //" "location /" ../conf/nginx.conf - install -o root -g root -m644 \ - ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/ihatemoney.conf -} - -configure_supervisor () { - install -o root -g root -m 644 \ - ../conf/supervisord.conf /etc/supervisor/conf.d/ihatemoney.conf -} +#================================================= +# FUTURE OFFICIAL HELPERS +#================================================= diff --git a/scripts/backup b/scripts/backup old mode 100644 new mode 100755 index 7c21e82..030071d --- a/scripts/backup +++ b/scripts/backup @@ -1,34 +1,82 @@ #!/bin/bash -# Source YunoHost helpers +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +# Keep this path for calling _common.sh inside the execution's context of backup and restore scripts source ../settings/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 -# Get multi-instances specific variables +#================================================= +# LOAD SETTINGS +#================================================= +ynh_print_info --message="Loading installation settings..." + app=$YNH_APP_INSTANCE_NAME -# Set app specific variables -dbname=$app -dbuser=$app +final_path=$(ynh_app_setting_get --app=$app --key=final_path) +domain=$(ynh_app_setting_get --app=$app --key=domain) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) -INSTALL_DIR=/opt/yunohost/ihatemoney +#================================================= +# DECLARE DATA AND CONF FILES TO BACKUP +#================================================= +ynh_print_info --message="Declaring files to be backed up..." -# Retrieve app settings -domain=$(ynh_app_setting_get "$app" domain) -path=$(ynh_app_setting_get "$app" path) -dbpass=$(ynh_app_setting_get "$app" mysqlpwd) +### N.B. : the following 'ynh_backup' calls are only a *declaration* of what needs +### to be backuped and not an actual copy of any file. The actual backup that +### creates and fill the archive with the files happens in the core after this +### script is called. Hence ynh_backups calls takes basically 0 seconds to run. -# Backup conf files -mkdir ./conf -ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" -ynh_backup "$gunicorn_conf_path" -ynh_backup "$supervisor_conf_path" -ynh_backup "$ihatemoney_conf_path" +#================================================= +# BACKUP THE APP MAIN DIR +#================================================= -# Dump the database -mysqldump -u "$dbuser" -p"$dbpass" --no-create-db "$dbname" > ./db.sql +ynh_backup --src_path="$final_path" -# Backup code and venv -ynh_backup "$INSTALL_DIR" "install_dir" +#================================================= +# BACKUP THE NGINX CONFIGURATION +#================================================= + +ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf" + +#================================================= +# BACKUP FAIL2BAN CONFIGURATION +#================================================= + +# ynh_backup --src_path="/etc/fail2ban/jail.d/$app.conf" +# ynh_backup --src_path="/etc/fail2ban/filter.d/$app.conf" + +#================================================= +# SPECIFIC BACKUP +#================================================= +# BACKUP SYSTEMD +#================================================= + +ynh_backup --src_path="/etc/systemd/system/$app.service" + +#================================================= +# BACKUP THE MYSQL DATABASE +#================================================= +ynh_print_info --message="Backing up the MySQL database..." + +### (However, things like MySQL dumps *do* take some time to run, though the +### copy of the generated dump to the archive still happens later) + +ynh_mysql_dump_db --database="$db_name" > db.sql + +#================================================= +# END OF SCRIPT +#================================================= + +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 new file mode 100644 index 0000000..92e79e2 --- /dev/null +++ b/scripts/change_url @@ -0,0 +1,150 @@ +#!/bin/bash + +#================================================= +# GENERIC STARTING +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# RETRIEVE ARGUMENTS +#================================================= + +old_domain=$YNH_APP_OLD_DOMAIN +old_path=$YNH_APP_OLD_PATH + +new_domain=$YNH_APP_NEW_DOMAIN +new_path=$YNH_APP_NEW_PATH + +app=$YNH_APP_INSTANCE_NAME +db_name=$(ynh_app_setting_get --app=$app --key=db_name) +db_user=$db_name +db_pwd=$(ynh_app_setting_get --app=$app --key=mysqlpwd) + +#================================================= +# LOAD SETTINGS +#================================================= +ynh_script_progression --message="Loading installation settings..." --time --weight=1 + +# Needed for helper "ynh_add_nginx_config" +final_path=$(ynh_app_setting_get --app=$app --key=final_path) + +python_venv_site_packages=$(__ynh_python_venv_get_site_packages_dir -d "$final_path/venv") + +#================================================= +# BACKUP BEFORE CHANGE URL THEN ACTIVE TRAP +#================================================= +ynh_script_progression --message="Backing up the app before changing its URL (may take a while)..." --time --weight=1 + +# 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" + + # Restore it if the upgrade fails + ynh_restore_upgradebackup +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# CHECK WHICH PARTS SHOULD BE CHANGED +#================================================= + +change_domain=0 +if [ "$old_domain" != "$new_domain" ] +then + change_domain=1 +fi + +change_path=0 +if [ "$old_path" != "$new_path" ] +then + change_path=1 +fi + +#================================================= +# STANDARD MODIFICATIONS +#================================================= +# STOP SYSTEMD SERVICE +#================================================= +ynh_script_progression --message="Stopping a systemd service..." --time --weight=1 + +ynh_systemd_action --service_name=$app --action="stop" --log_path=systemd + +#================================================= +# MODIFY URL IN NGINX CONF +#================================================= +ynh_script_progression --message="Updating NGINX web server configuration..." --time --weight=1 + +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" + # Set global variables for NGINX helper + domain="$old_domain" + path_url="$new_path" + # 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 + # Store file checksum for the new config file location + ynh_store_file_checksum --file="/etc/nginx/conf.d/$new_domain.d/$app.conf" +fi + +#================================================= +# SPECIFIC MODIFICATIONS +#================================================= +# Setup ihatemoney.cfg +#================================================= + +path_url="$new_path" +domain="$new_domain" + +# Secret key for cookies encryption. +secret_key=$(ynh_string_random --length 32) +mails_sender="no-reply@$domain" +# Allows to comment some config lines if not using sub path +sub_path_only="$(if [[ "$path_url" == "/" ]]; then echo '# ' ; else echo ''; fi)" + +ynh_backup_if_checksum_is_different --file="$final_path/ihatemoney.cfg" +ynh_add_config --template ../conf/ihatemoney.cfg --destination "$final_path/ihatemoney.cfg" + +chmod 750 "$final_path" +chmod -R o-rwx "$final_path" +chown -R $app:www-data "$final_path" + +#================================================= +# GENERIC FINALISATION +#================================================= +# START SYSTEMD SERVICE +#================================================= +ynh_script_progression --message="Starting a systemd service..." --time --weight=1 + +ynh_systemd_action --service_name=$app --action="start" --log_path=systemd + +#================================================= +# RELOAD NGINX +#================================================= +ynh_script_progression --message="Reloading NGINX web server..." --time --weight=1 + +ynh_systemd_action --service_name=nginx --action=reload + +#================================================= +# END OF SCRIPT +#================================================= + +ynh_script_progression --message="Change of URL completed for $app" --time --last diff --git a/scripts/install b/scripts/install index 8c1202c..eb05f17 100755 --- a/scripts/install +++ b/scripts/install @@ -1,88 +1,191 @@ #!/bin/bash -# Source YunoHost helpers +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + source _common.sh source /usr/share/yunohost/helpers -# Retrieve arguments -domain=$YNH_APP_ARG_DOMAIN -path=$YNH_APP_ARG_PATH -is_public=$YNH_APP_ARG_IS_PUBLIC -app=ihatemoney - -# Database settings -db_pwd=$(ynh_string_random) -db_name=$app -db_user=$app - -# Constant arguments -secret_key=$(ynh_string_random --length 32) -mails_sender="no-reply@${domain}" - +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= +# Exit if an error occurs during the execution of the script ynh_abort_if_errors -ynh_webpath_register $app $domain $path +#================================================= +# RETRIEVE ARGUMENTS FROM THE MANIFEST +#================================================= -# Configure database -ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" +domain=$YNH_APP_ARG_DOMAIN +path_url=$YNH_APP_ARG_PATH +is_public=$YNH_APP_ARG_IS_PUBLIC +app=$YNH_APP_INSTANCE_NAME -# Save app settings -ynh_app_setting_set "$app" mysqlpwd "$db_pwd" -ynh_app_setting_set "$app" is_public "$is_public" +#================================================= +# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS +#================================================= +ynh_script_progression --message="Validating installation parameters..." --weight=1 -install_apt_dependencies +final_path=/var/www/$app +test ! -e "$final_path" || ynh_die --message="This path already contains a folder" -create_unix_user +# Register (book) web path +ynh_webpath_register --app=$app --domain=$domain --path_url=$path_url -# Prepare venv -init_virtualenv -pip_install +#================================================= +# STORE SETTINGS FROM MANIFEST +#================================================= +ynh_script_progression --message="Storing installation settings..." --weight=1 -create_system_dirs +ynh_app_setting_set --app=$app --key=domain --value=$domain +ynh_app_setting_set --app=$app --key=path --value=$path_url -# Configure gunicorn -install -o ihatemoney -g ihatemoney -m 644 \ - ../conf/gunicorn.conf.py /etc/ihatemoney/gunicorn.conf.py +#================================================= +# STANDARD MODIFICATIONS +#================================================= +# INSTALL DEPENDENCIES +#================================================= +ynh_script_progression --message="Installing dependencies..." --weight=3 -# Configure supervisor -configure_supervisor -# In case it was already installed before, -# so that it picks /etc/supervisor/conf.d/ihatemoney.conf: -supervisorctl update -yunohost service add supervisor +ynh_install_app_dependencies "${pkg_dependencies[@]}" -# Configure ihatemoney -ynh_replace_string "MY_SECRET_KEY" "$secret_key" ../conf/ihatemoney.cfg -ynh_replace_string "MY_EMAIL" "$mails_sender" ../conf/ihatemoney.cfg -ynh_replace_string "MY_MYSQL_PW" "$db_pwd" ../conf/ihatemoney.cfg -ynh_replace_string "MY_PATH" "$path" ../conf/ihatemoney.cfg -# Remove the conf directive if served at root -sed -i "/APPLICATION_ROOT='\/'/d" ../conf/ihatemoney.cfg -install -o ihatemoney -g ihatemoney -m 640 \ - ../conf/ihatemoney.cfg /etc/ihatemoney/ihatemoney.cfg +#================================================= +# CREATE DEDICATED USER +#================================================= +ynh_script_progression --message="Configuring system user..." --weight=1 -# If app is public, add url to SSOWat conf as skipped_uris -if [[ "$is_public" -ne 0 ]]; -then - ynh_app_setting_set $app unprotected_uris "/" -fi +# Create a system user +ynh_system_user_create --username=$app --home_dir="$final_path" -# Configure Nginx -configure_nginx "$domain" "$path" +#================================================= +# CREATE A MYSQL DATABASE +#================================================= +ynh_script_progression --message="Creating a MySQL database..." --weight=1 -# Start backend -systemctl start supervisor +db_name=$(ynh_sanitize_dbid --db_name=$app) +db_user=$db_name +ynh_app_setting_set --app=$app --key=db_name --value=$db_name +ynh_mysql_setup_db --db_user=$db_user --db_name=$db_name +# defines $db_pwd and setting mysqlpwd -# Wait that gunicorn is ready to consider the install finished, that is to -# avoid HTTP 502 right after installation -for i in `seq 1 120` -do - test -S /tmp/budget.gunicorn.sock && break +#================================================= +# SPECIFIC SETUP +#================================================= +# Init venv +#================================================= + +ynh_script_progression --message="Configuring the app's installation..." --weight=6 + +ynh_app_setting_set --app=$app --key=final_path --value=$final_path + +__ynh_python_venv_setup --venv_dir="$final_path/venv" --packages "${pip_dependencies[*]}" +python_venv_site_packages=$(__ynh_python_venv_get_site_packages_dir -d "$final_path/venv") + +#================================================= +# NGINX CONFIGURATION +#================================================= +ynh_script_progression --message="Configuring NGINX web server..." --weight=1 + +# Create a dedicated NGINX config +## Needs $python_venv_site_packages +ynh_add_nginx_config + +#================================================= +# Setup gunicorn +#================================================= + +ynh_add_config --template ../conf/gunicorn.conf.py --destination "$final_path/gunicorn.conf.py" +chmod 644 "$final_path/gunicorn.conf.py" + +#================================================= +# Setup ihatemoney +#================================================= + +# Secret key for cookies encryption. +secret_key=$(ynh_string_random --length 32) +mails_sender="no-reply@$domain" +# Allows to comment some config lines if not using sub path +sub_path_only="$(if [[ "$path_url" == "/" ]]; then echo '# ' ; else echo ''; fi)" + +ynh_add_config --template ../conf/ihatemoney.cfg --destination "$final_path/ihatemoney.cfg" +chmod 640 "$final_path/ihatemoney.cfg" + + +# FIXME: this should be managed by the core in the future +# Here, as a packager, you may have to tweak the ownerhsip/permissions +# such that the appropriate users (e.g. maybe www-data) can access +# files in some cases. +# But FOR THE LOVE OF GOD, do not allow r/x for "others" on the entire folder - +# this will be treated as a security issue. +chmod 750 "$final_path" +chmod -R o-rwx "$final_path" +chown -R $app:www-data "$final_path" + +#================================================= +# SETUP SYSTEMD +#================================================= +ynh_script_progression --message="Configuring a systemd service..." --weight=1 + +# Create a dedicated systemd config +ynh_add_systemd_config + +#================================================= +# GENERIC FINALIZATION +#================================================= +# INTEGRATE SERVICE IN YUNOHOST +#================================================= +ynh_script_progression --message="Integrating service in YunoHost..." --weight=1 + +yunohost service add $app --description="$app daemon for IHateMoney" --log_type=systemd + +#================================================= +# START SYSTEMD SERVICE +#================================================= +ynh_script_progression --message="Starting a systemd service..." --weight=1 + +# Start a systemd service +ynh_systemd_action --service_name=$app --action="start" --log_path="systemd" --line_match="Booting worker" --timeout 30 + +# line_match isn't enough because ihatemoney may stop if database upgrades +for _ in {1..20}; do + test -S /tmp/budget.gunicorn_$app.sock && break sleep 1 done -# If socket not ready after 2 minutes waiting, ihatemoney will not work. -test -S /tmp/budget.gunicorn.sock || ynh_die +#================================================= +# SETUP FAIL2BAN +#================================================= +# ynh_script_progression --message="Configuring Fail2Ban..." --weight=1 -systemctl reload nginx +# Create a dedicated Fail2Ban config +# ynh_add_fail2ban_config --logpath="/var/log/nginx/${domain}-error.log" --failregex="Regex to match into the log for a failed login" + +#================================================= +# SETUP SSOWAT +#================================================= +ynh_script_progression --message="Configuring permissions..." --weight=1 + +# Make app public if necessary +if [ $is_public -eq 1 ] +then + # Everyone can access the app. + # The "main" permission is automatically created before the install script. + ynh_permission_update --permission="main" --add="visitors" +fi + +#================================================= +# RELOAD NGINX +#================================================= +ynh_script_progression --message="Reloading NGINX web server..." --weight=1 + +ynh_systemd_action --service_name=nginx --action=reload + +#================================================= +# END OF SCRIPT +#================================================= + +ynh_script_progression --message="Installation of $app completed" --last diff --git a/scripts/remove b/scripts/remove index 5620f80..4685e83 100755 --- a/scripts/remove +++ b/scripts/remove @@ -1,37 +1,109 @@ #!/bin/bash -# Source YunoHost helpers +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh source /usr/share/yunohost/helpers -# supervisord and other Debian dependencies remain installed -# there is no way to know if they are used by other programs +#================================================= +# LOAD SETTINGS +#================================================= +ynh_script_progression --message="Loading installation settings..." --weight=1 -# Retrieve arguments -app=ihatemoney -domain=$(ynh_app_setting_get $app domain) -db_user=$app -db_name=$app +app=$YNH_APP_INSTANCE_NAME -# Stop service -supervisorctl stop budget +domain=$(ynh_app_setting_get --app=$app --key=domain) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) +db_user=$db_name +final_path=$(ynh_app_setting_get --app=$app --key=final_path) -# Drop database -ynh_mysql_drop_db $db_name -ynh_mysql_drop_user $db_user +#================================================= +# STANDARD REMOVE +#================================================= +# REMOVE SERVICE INTEGRATION IN YUNOHOST +#================================================= -# Remove src and venv -ynh_secure_remove /opt/yunohost/ihatemoney +# Remove the service from the list of services known by YunoHost (added from `yunohost service add`) +if ynh_exec_warn_less yunohost service status $app >/dev/null +then + ynh_script_progression --message="Removing $app service integration..." --weight=1 + yunohost service remove $app +fi -# Remove settings -ynh_secure_remove /etc/ihatemoney -ynh_secure_remove /etc/supervisor/conf.d/ihatemoney.conf -ynh_remove_nginx_config +#================================================= +# STOP AND REMOVE SERVICE +#================================================= +ynh_script_progression --message="Stopping and removing the systemd service..." --weight=1 -# Restart services -systemctl force-reload supervisor +# Remove the dedicated systemd config +ynh_remove_systemd_config -# Remove app dependencies +#================================================= +# REMOVE THE MYSQL DATABASE +#================================================= +ynh_script_progression --message="Removing the MySQL database..." --weight=1 + +# Remove a database if it exists, along with the associated user +ynh_mysql_remove_db --db_user=$db_user --db_name=$db_name + +#================================================= +# REMOVE DEPENDENCIES +#================================================= +ynh_script_progression --message="Removing dependencies..." --weight=2 + +# Remove metapackage and its dependencies ynh_remove_app_dependencies -# Delete user -userdel ihatemoney +#================================================= +# REMOVE APP MAIN DIR +#================================================= +ynh_script_progression --message="Removing app main directory..." --weight=1 + +# Remove the app directory securely +ynh_secure_remove --file="$final_path" + +#================================================= +# REMOVE NGINX CONFIGURATION +#================================================= +ynh_script_progression --message="Removing NGINX web server configuration..." --weight=1 + +# Remove the dedicated NGINX config +ynh_remove_nginx_config + +#================================================= +# REMOVE FAIL2BAN CONFIGURATION +#================================================= +# ynh_script_progression --message="Removing Fail2ban configuration..." --weight=1 + +# # Remove the dedicated Fail2Ban config +# ynh_remove_fail2ban_config + +#================================================= +# SPECIFIC REMOVE +#================================================= +# REMOVE VARIOUS FILES +#================================================= +ynh_script_progression --message="Removing configuration files..." --weight=1 + +# Remove the log files +ynh_secure_remove --file="/var/log/$app" + +#================================================= +# GENERIC FINALIZATION +#================================================= +# REMOVE DEDICATED USER +#================================================= +ynh_script_progression --message="Removing the dedicated system user..." --weight=1 + +# Delete a system user +ynh_system_user_delete --username=$app + +#================================================= +# END OF SCRIPT +#================================================= + +ynh_script_progression --message="Removal of $app completed" --last diff --git a/scripts/restore b/scripts/restore old mode 100644 new mode 100755 index 0912f3f..ede60f0 --- a/scripts/restore +++ b/scripts/restore @@ -1,58 +1,145 @@ #!/bin/bash -# Source app helpers +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +# Keep this path for calling _common.sh inside the execution's context of backup and restore scripts source ../settings/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 -# Get multi-instances specific variables +#================================================= +# LOAD SETTINGS +#================================================= +ynh_script_progression --message="Loading installation settings..." --weight=1 + app=$YNH_APP_INSTANCE_NAME -# Set app specific variables -dbname=$app -dbuser=$app +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) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) +db_user=$db_name +phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) -# Retrieve old app settings -domain=$(ynh_app_setting_get "$app" domain) -path=$(ynh_app_setting_get "$app" path) -dbpass=$(ynh_app_setting_get "$app" mysqlpwd) +#================================================= +# CHECK IF THE APP CAN BE RESTORED +#================================================= +ynh_script_progression --message="Validating restoration parameters..." --weight=1 +test ! -d $final_path \ + || ynh_die --message="There is already a directory: $final_path " -test -d $INSTALL_DIR && ynh_die \ -"The destination directory '$INSTALL_DIR' already exists.\ - You should safely delete it before restoring this app." +#================================================= +# STANDARD RESTORATION STEPS +#================================================= +# RESTORE THE NGINX CONFIGURATION +#================================================= +ynh_script_progression --message="Restoring the NGINX configuration..." --weight=1 -test -f $supervisor_conf_path && ynh_die \ -"The Supervisor configuration already exists at '${supervisor_conf_path}'. - You should safely delete it before restoring this app." +ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf" -test -f $gunicorn_conf_path && ynh_die \ -"The Gunicorn configuration already exists at '${gunicorn_conf_path}'. - You should safely delete it before restoring this app." +#================================================= +# RECREATE THE DEDICATED USER +#================================================= +ynh_script_progression --message="Recreating the dedicated system user..." --weight=1 -install_apt_dependencies +# Create the dedicated user (if not existing) +ynh_system_user_create --username=$app --home_dir="$final_path" -create_unix_user +#================================================= +# RESTORE THE APP MAIN DIR +#================================================= +ynh_script_progression --message="Restoring the app main directory..." --weight=1 -create_system_dirs +ynh_restore_file --origin_path="$final_path" -# Restore all backed-up files -ynh_restore +# FIXME: this should be managed by the core in the future +# Here, as a packager, you may have to tweak the ownerhsip/permissions +# such that the appropriate users (e.g. maybe www-data) can access +# files in some cases. +# But FOR THE LOVE OF GOD, do not allow r/x for "others" on the entire folder - +# this will be treated as a security issue. +chmod 750 "$final_path" +chmod -R o-rwx "$final_path" +chown -R $app:www-data "$final_path" -# Create and restore the database -ynh_mysql_create_db "$dbname" "$dbuser" "$dbpass" -ynh_mysql_connect_as "$dbuser" "$dbpass" "$dbname" < ./db.sql +#================================================= +# RESTORE FAIL2BAN CONFIGURATION +#================================================= +# ynh_script_progression --message="Restoring the Fail2Ban configuration..." --weight=1 -# Reload -systemctl reload nginx -systemctl restart supervisor -supervisorctl restart budget +# ynh_restore_file "/etc/fail2ban/jail.d/$app.conf" +# ynh_restore_file "/etc/fail2ban/filter.d/$app.conf" +# ynh_systemd_action --action=restart --service_name=fail2ban -# Wait that gunicorn is ready to consider the install finished, that is to -# avoid HTTP 502 right after installation -for i in `seq 1 120` -do - test -S /tmp/budget.gunicorn.sock && break +#================================================= +# SPECIFIC RESTORATION +#================================================= +# REINSTALL DEPENDENCIES +#================================================= +ynh_script_progression --message="Reinstalling dependencies..." --weight=4 + +# Define and install dependencies +ynh_install_app_dependencies "${pkg_dependencies[@]}" + +#================================================= +# RESTORE THE MYSQL DATABASE +#================================================= +ynh_script_progression --message="Restoring the MySQL database..." --weight=1 + +db_pwd=$(ynh_app_setting_get --app=$app --key=mysqlpwd) +ynh_mysql_setup_db --db_user=$db_user --db_name=$db_name --db_pwd=$db_pwd +ynh_mysql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./db.sql + +#================================================= +# RESTORE SYSTEMD +#================================================= +ynh_script_progression --message="Restoring the systemd configuration..." --weight=1 + +ynh_restore_file --origin_path="/etc/systemd/system/$app.service" +systemctl enable $app.service --quiet + +#================================================= +# INTEGRATE SERVICE IN YUNOHOST +#================================================= +ynh_script_progression --message="Integrating service in YunoHost..." --weight=1 + +yunohost service add $app --description="$app daemon for IHateMoney" --log_type=systemd + +#================================================= +# START SYSTEMD SERVICE +#================================================= +ynh_script_progression --message="Starting a systemd service..." --weight=1 + +ynh_systemd_action --service_name=$app --action="start" --log_path="systemd" --line_match="Booting worker" --timeout 30 + +# line_match isn't enough because ihatemoney may stop if database upgrades +for _ in {1..20}; do + test -S /tmp/budget.gunicorn_$app.sock && break sleep 1 done + +#================================================= +# GENERIC FINALIZATION +#================================================= +# RELOAD NGINX AND PHP-FPM +#================================================= +ynh_script_progression --message="Reloading NGINX web server..." --weight=1 + +ynh_systemd_action --service_name=nginx --action=reload + +#================================================= +# END OF SCRIPT +#================================================= + +ynh_script_progression --message="Restoration completed for $app" --last diff --git a/scripts/upgrade b/scripts/upgrade old mode 100755 new mode 100644 index ef98703..855d95f --- a/scripts/upgrade +++ b/scripts/upgrade @@ -1,141 +1,227 @@ #!/bin/bash + +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# LOAD SETTINGS +#================================================= +ynh_script_progression --message="Loading installation settings..." --weight=1 + app=$YNH_APP_INSTANCE_NAME +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) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) +db_user=$db_name +db_pwd=$(ynh_app_setting_get --app=$app --key=mysqlpwd) -# Installation paths -INSTALL_DIR=/opt/yunohost/ihatemoney +#================================================= +# CHECK VERSION +#================================================= -# Source YunoHost helpers -. /usr/share/yunohost/helpers +### This helper will compare the version of the currently installed app and the version of the upstream package. +### $upgrade_type can have 2 different values +### - UPGRADE_APP if the upstream app version has changed +### - UPGRADE_PACKAGE if only the YunoHost package has changed +### ynh_check_app_version_changed will stop the upgrade if the app is up to date. +### UPGRADE_APP should be used to upgrade the core app only if there's an upgrade to do. +upgrade_type=$(ynh_check_app_version_changed) -domain=$(ynh_app_setting_get $app domain) -path=$(ynh_app_setting_get $app path) -is_public=$(ynh_app_setting_get "$app" is_public) +if ynh_compare_current_package_version --comparison le --version "4.1.5~ynh2"; then + upgrade_from_opt=true +else + upgrade_from_opt=false +fi -VENV_PY_VERSION=$(echo ${INSTALL_DIR}/venv/bin/python*.*|sed 's/.*python//') -SYSTEM_PY_VERSION=$(readlink /usr/bin/python3|sed s/.*python//) - -# Source local utils -source _common.sh +#================================================= +# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP +#================================================= +ynh_script_progression --message="Backing up the app before upgrading (may take a while)..." --weight=3 +# Backup the current version of the app +ynh_backup_before_upgrade ynh_clean_setup () { - if [ -e /opt/yunohost/ihatemoney/venv-old ] - then - mv /opt/yunohost/ihatemoney/venv{-old,} - fi + # Restore it if the upgrade fails + ynh_restore_upgradebackup } - +# Exit if an error occurs during the execution of the script ynh_abort_if_errors +#================================================= +# STANDARD UPGRADE STEPS +#================================================= +# STOP SYSTEMD SERVICE +#================================================= -#----------------------------PRE-UPGRADE MIGRATIONS----------------------- +if [[ "$upgrade_from_opt" == "false" ]]; then + ynh_script_progression --message="Stopping a systemd service..." --weight=1 - - -# MIGRATION: upgrade arg to typed boolean form - -if (($is_public != 0)) && (($is_public != 1)) -then - if [ $is_public = "No" ]; - then - is_public=0 - else - is_public=1 - fi - ynh_app_setting_set "$app" is_public "$is_public" + ynh_systemd_action --service_name=$app --action="stop" --log_path=systemd fi +#================================================= +# ENSURE DOWNWARD COMPATIBILITY +#================================================= +ynh_script_progression --message="Ensuring downward compatibility..." --weight=1 +# Cleaning legacy permissions +if ynh_legacy_permissions_exists; then + ynh_legacy_permissions_delete_all -# MIGRATION: Switch to a python3 venv -if [[ "$VENV_PY_VERSION" == 2.7 ]] -then - install_apt_dependencies - # Trash py2 venv - mv ${INSTALL_DIR}/venv ${INSTALL_DIR}/venv-old - init_virtualenv - - # Clears all cookie-sessions, because py2 & py3 sessions are incompatible - # Relates https://github.com/lepture/flask-wtf/issues/279 (fix unreleased) - new_secret_key=$(ynh_string_random 32) - ynh_replace_string "SECRET_KEY = \".*\"" "SECRET_KEY = \"${new_secret_key}\"" /etc/ihatemoney/ihatemoney.cfg + ynh_app_setting_delete --app=$app --key=is_public fi +# MIGRATION: Remove old code (from pre-4.1.5 versions, not using venv) +if [[ "$upgrade_from_opt" == "true" ]]; then + # Remove legacy install dir + ynh_secure_remove /opt/yunohost/ihatemoney -# MIGRATION: minor Py version has changed ? rebuilt venv + # Remove legacy Supervisor config + rm -f /etc/supervisor/conf.d/ihatemoney.conf -# Useful for Py 3.4 → 3.5, Jessie → Stretch, ynh 2.x → 3.x -if [[ "$VENV_PY_VERSION" != '2.7' ]] && [[ "$VENV_PY_VERSION" != "$SYSTEM_PY_VERSION" ]] -then - mv ${INSTALL_DIR}/venv ${INSTALL_DIR}/venv-old - init_virtualenv + if [ -e /etc/ihatemoney/settings.py ]; then + # Strip out the no longer used part of the settings + python3 -c "d = open('/etc/ihatemoney/settings.py').read().replace('try:\n from settings import *\nexcept ImportError:\n pass\n', ''); open('/etc/ihatemoney/settings.py', 'w').write(d)" + # Rename + mv /etc/ihatemoney/settings.py "/etc/ihatemoney/ihatemoney.cfg" + fi - # the static path changed - configure_nginx "$domain" "$path" + for old_file in "/etc/ihatemoney/ihatemoney.cfg" "/etc/$app/gunicorn.conf.py"; do + ynh_backup_if_checksum_is_different --file="$old_file" + ynh_delete_file_checksum --file="$old_file" + done + + final_path=/var/www/$app + ynh_app_setting_set --app=$app --key=final_path --value=$final_path + + db_name=ihatemoney + db_user=$db_name + ynh_app_setting_set --app=$app --key=db_name --value=$db_name fi -#-------------------------------UPGRADE------------------------- +#================================================= +# CREATE DEDICATED USER +#================================================= +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 --home_dir="$final_path" + +#================================================= +# UPGRADE DEPENDENCIES +#================================================= +ynh_script_progression --message="Upgrading dependencies..." --weight=1 + +ynh_install_app_dependencies "${pkg_dependencies[@]}" + +#================================================= +# SPECIFIC UPGRADE +#================================================= +# Init venv +#================================================= +ynh_script_progression --message="Configuring the app's installation..." --weight=6 + +ynh_app_setting_set --app=$app --key=final_path --value=$final_path + +# MIGRATION: Upgrade venv +python3 -m venv --upgrade "$final_path/venv" +"$final_path/venv/bin/python3" -m pip install --upgrade pip "${pip_dependencies[@]}" +python_venv_site_packages=$(__ynh_python_venv_get_site_packages_dir -d "$final_path/venv") + +#================================================= +# NGINX CONFIGURATION +#================================================= +ynh_script_progression --message="Upgrading NGINX web server configuration..." --weight=1 + +# Create a dedicated NGINX config +## Needs $python_venv_site_packages +ynh_add_nginx_config "PYTHON_VERSION" + +#================================================= +# Setup gunicorn +#================================================= + +ynh_add_config --template ../conf/gunicorn.conf.py --destination "$final_path/gunicorn.conf.py" +chmod 600 "$final_path/gunicorn.conf.py" + +#================================================= +# Setup ihatemoney +#================================================= + +# Secret key for cookies encryption. +secret_key=$(ynh_string_random --length 32) +mails_sender="no-reply@$domain" +# Allows to comment some config lines if not using sub path +sub_path_only="$(if [[ "$path_url" == "/" ]]; then echo '# ' ; else echo ''; fi)" + +ynh_add_config --template ../conf/ihatemoney.cfg --destination "$final_path/ihatemoney.cfg" +chmod 600 "$final_path/ihatemoney.cfg" -# Upgrade code and dependencies -pip_install +# FIXME: this should be managed by the core in the future +# Here, as a packager, you may have to tweak the ownerhsip/permissions +# such that the appropriate users (e.g. maybe www-data) can access +# files in some cases. +# But FOR THE LOVE OF GOD, do not allow r/x for "others" on the entire folder - +# this will be treated as a security issue. +chmod 750 "$final_path" +chmod -R o-rwx "$final_path" +chown -R $app:www-data "$final_path" +#================================================= +# SETUP SYSTEMD +#================================================= +ynh_script_progression --message="Upgrading systemd configuration..." --weight=1 -#-----------------------POST-UPGRADE MIGRATIONS----------------- +# Create a dedicated systemd config +ynh_add_systemd_config +#================================================= +# GENERIC FINALIZATION +#================================================= +# INTEGRATE SERVICE IN YUNOHOST +#================================================= +ynh_script_progression --message="Integrating service in YunoHost..." --weight=1 +yunohost service add $app --description="$app daemon for IHateMoney" --log_type=systemd +#================================================= +# START SYSTEMD SERVICE +#================================================= +ynh_script_progression --message="Starting a systemd service..." --weight=1 -# Python-MySQL is no longer maintained and does not support Py3 -ynh_replace_string "'mysql://" "'mysql+pymysql://" ${ihatemoney_conf_path} +ynh_systemd_action --service_name=$app --action="start" --log_path="systemd" --line_match="Booting worker" --timeout 30 +# line_match isn't enough because ihatemoney may stop if database upgrades +# FIXME: We need to wait for the db to upgrade and gunicorn to restart! +sleep 3 +#================================================= +# UPGRADE FAIL2BAN +#================================================= +# ynh_script_progression --message="Reconfiguring Fail2Ban..." --weight=1 -# MIGRATION: Remove old code (from pre-2.x versions, not using pip) +# # Create a dedicated Fail2Ban config +# ynh_add_fail2ban_config --logpath="/var/log/nginx/${domain}-error.log" --failregex="Regex to match into the log for a failed login" -ynh_secure_remove ${INSTALL_DIR}/src +#================================================= +# RELOAD NGINX +#================================================= +ynh_script_progression --message="Reloading NGINX web server..." --weight=1 +ynh_systemd_action --service_name=nginx --action=reload +#================================================= +# END OF SCRIPT +#================================================= -# MIGRATION: change the static path (from pre-2.x versions, not using pip) - -if grep -q /opt/yunohost/ihatemoney/src/ /etc/nginx/conf.d/${domain}.d/ihatemoney.conf -then - # the static path changed - configure_nginx "$domain" "$path" - - # Supervisor no longer change its directory to src/ dir - configure_supervisor - supervisorctl update -fi - - -# MIGRATION: new-style settings - -if [ -e /etc/ihatemoney/settings.py ]; then - # Strip out the no longer used part of the settings - python3 -c "d = open('/etc/ihatemoney/settings.py').read().replace('try:\n from settings import *\nexcept ImportError:\n pass\n', ''); open('/etc/ihatemoney/settings.py', 'w').write(d)" - # Rename - mv /etc/ihatemoney/settings.py ${ihatemoney_conf_path} -fi - - - -# MIGRATION: Remove no longer used symlink - -# (ihatemoney now read its conf by default from /etc/ihatemoney/ihatemoney.cfg) -ynh_secure_remove ${INSTALL_DIR}/src/budget/settings.py - - - -#----------------------------FINALIZATION----------------------- - -# Everything went ok ? Let's keep this new venv. -ynh_secure_remove ${INSTALL_DIR}/venv-old - -# Restart backend -supervisorctl restart budget - -# Reload nginx conf -systemctl reload nginx +ynh_script_progression --message="Upgrade of $app completed" --last From c187a39fe1c4cea5a0d028f3d76e4bf83209cd43 Mon Sep 17 00:00:00 2001 From: Salamandar <6552989+Salamandar@users.noreply.github.com> Date: Thu, 16 Dec 2021 19:41:08 +0100 Subject: [PATCH 05/10] Update scripts/install log_type -> log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric Gaspar <46165813+ericgaspar@users.noreply.github.com> --- scripts/install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/install b/scripts/install index eb05f17..6a8713e 100755 --- a/scripts/install +++ b/scripts/install @@ -140,7 +140,7 @@ ynh_add_systemd_config #================================================= ynh_script_progression --message="Integrating service in YunoHost..." --weight=1 -yunohost service add $app --description="$app daemon for IHateMoney" --log_type=systemd +yunohost service add $app --description="$app daemon for IHateMoney" --log=systemd #================================================= # START SYSTEMD SERVICE From 5344aec40eeb533b64d3d2f202a3c90c40cbefe9 Mon Sep 17 00:00:00 2001 From: Salamandar <6552989+Salamandar@users.noreply.github.com> Date: Thu, 16 Dec 2021 19:41:34 +0100 Subject: [PATCH 06/10] Update scripts/restore log_type -> log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric Gaspar <46165813+ericgaspar@users.noreply.github.com> --- scripts/restore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/restore b/scripts/restore index ede60f0..30d8ce9 100755 --- a/scripts/restore +++ b/scripts/restore @@ -114,7 +114,7 @@ systemctl enable $app.service --quiet #================================================= ynh_script_progression --message="Integrating service in YunoHost..." --weight=1 -yunohost service add $app --description="$app daemon for IHateMoney" --log_type=systemd +yunohost service add $app --description="$app daemon for IHateMoney" --log=systemd #================================================= # START SYSTEMD SERVICE From 22274b3895def8ef52f27c50fd2f69d514ad0e49 Mon Sep 17 00:00:00 2001 From: Salamandar <6552989+Salamandar@users.noreply.github.com> Date: Thu, 16 Dec 2021 19:41:42 +0100 Subject: [PATCH 07/10] Update scripts/upgrade log_type -> log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric Gaspar <46165813+ericgaspar@users.noreply.github.com> --- scripts/upgrade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upgrade b/scripts/upgrade index 855d95f..5457ea3 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -192,7 +192,7 @@ ynh_add_systemd_config #================================================= ynh_script_progression --message="Integrating service in YunoHost..." --weight=1 -yunohost service add $app --description="$app daemon for IHateMoney" --log_type=systemd +yunohost service add $app --description="$app daemon for IHateMoney" --log=systemd #================================================= # START SYSTEMD SERVICE From 7189f08b28ac6e6c760e95fc47e7aa5e48012c03 Mon Sep 17 00:00:00 2001 From: Yunohost-Bot <> Date: Sat, 18 Dec 2021 11:39:08 +0000 Subject: [PATCH 08/10] Auto-update README --- README.md | 20 ++++++++------------ README_fr.md | 30 ++++++++++++++---------------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index fe1bca7..fcd4758 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ ---- -