From f8838d21abf7468c1987c1bec9a5abf380eef1d3 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Holcroft Date: Tue, 17 Apr 2018 00:02:25 +0200 Subject: [PATCH] First installation script, it doesn't work yet --- check_process | 37 ++++ conf/app.src | 6 + conf/env.prod | 87 ++++++++++ conf/funkwhale-server.service | 14 ++ conf/funkwhale-worker.service | 14 ++ conf/funkwhale.target | 3 + conf/nginx.conf | 80 +++++++++ manifest.json | 59 +++++++ scripts/_common.sh | 318 ++++++++++++++++++++++++++++++++++ scripts/install | 200 +++++++++++++++++++++ scripts/remove | 77 ++++++++ 11 files changed, 895 insertions(+) create mode 100644 check_process create mode 100644 conf/app.src create mode 100644 conf/env.prod create mode 100644 conf/funkwhale-server.service create mode 100644 conf/funkwhale-worker.service create mode 100644 conf/funkwhale.target create mode 100644 conf/nginx.conf create mode 100644 manifest.json create mode 100644 scripts/_common.sh create mode 100644 scripts/install create mode 100644 scripts/remove diff --git a/check_process b/check_process new file mode 100644 index 0000000..9131836 --- /dev/null +++ b/check_process @@ -0,0 +1,37 @@ +# See here for more informations +# https://github.com/YunoHost/package_check#syntax-check_process-file + +# Move this file from check_process.default to check_process when you have filled it. + +;; Test complet + ; Manifest + domain="domain.tld" (DOMAIN) + path="/path" (PATH) + admin="john" (USER) + is_public=1 (PUBLIC|public=1|private=0) + ; Checks + pkg_linter=1 + setup_sub_dir=0 + setup_root=1 + setup_nourl=0 + setup_private=1 + setup_public=1 + upgrade=0 + backup_restore=0 + multi_instance=0 + incorrect_path=0 + port_already_use=0 + change_url=0 +;;; Levels + Level 1=auto + Level 2=auto + Level 3=auto +# Level 4: + Level 4=0 +# Level 5: + Level 5=auto + Level 6=auto + Level 7=auto + Level 8=0 + Level 9=0 + Level 10=0 diff --git a/conf/app.src b/conf/app.src new file mode 100644 index 0000000..db0fd0c --- /dev/null +++ b/conf/app.src @@ -0,0 +1,6 @@ +SOURCE_URL=https://code.eliotberriot.com/funkwhale/funkwhale/repository/0.8/archive.tar.bz2 +SOURCE_SUM=c74287d46cd88880292fe5b5f1972a5bc393724e581bea015ff7808f13753bf4 +SOURCE_SUM_PRG=sha256sum +SOURCE_FORMAT=tar.bz2 +SOURCE_IN_SUBDIR=true +SOURCE_FILENAME= diff --git a/conf/env.prod b/conf/env.prod new file mode 100644 index 0000000..d2fc614 --- /dev/null +++ b/conf/env.prod @@ -0,0 +1,87 @@ +# If you're tweaking this file from the template, ensure you edit at least the +# following variables: +# - DJANGO_SECRET_KEY +# - DJANGO_ALLOWED_HOSTS +# - FUNKWHALE_URL + +# Additionaly, on non-docker setup **only**, you'll also have to tweak/uncomment those variables: +# - DATABASE_URL +# - CACHE_URL +# - STATIC_ROOT +# - MEDIA_ROOT +# +# You **don't** need to update those variables on pure docker setups. + +# Docker only +# ----------- + +# The tag of the image we should use +# (it will be interpolated in docker-compose file) +# You can comment or ignore this if you're not using docker +# FUNKWHALE_VERSION=latest + + +# General configuration +# --------------------- + +# Set this variables to bind the API server to another interface/port +# example: FUNKWHALE_API_IP=0.0.0.0 +# example: FUNKWHALE_API_PORT=5678 +FUNKWHALE_API_IP=127.0.0.1 +FUNKWHALE_API_PORT=__PORT__ + +# Replace this by the definitive, public domain you will use for +# your instance +FUNKWHALE_URL=__DOMAIN__ + +# API/Django configuration + +# Database configuration +# Examples: +# DATABASE_URL=postgresql://:@:/ +# DATABASE_URL=postgresql://funkwhale:passw0rd@localhost:5432/funkwhale_database +# Use the next one if you followed Debian installation guide +DATABASE_URL=postgresql://__DBUSER__:__DBPWD__@:5432/__DBNAME__ + +# Cache configuration +# Examples: +# CACHE_URL=redis://:/ +# CACHE_URL=redis://localhost:6379/0 +# Use the next one if you followed Debian installation guide +# CACHE_URL=redis://127.0.0.1:6379/0 + +# Where media files (such as album covers or audio tracks) should be stored +# on your system? +# (Ensure this directory actually exists) +MEDIA_ROOT=__FINALPATH__/data/media + +# Where static files (such as API css or icons) should be compiled +# on your system? +# (Ensure this directory actually exists) +STATIC_ROOT=__FINALPATH__/data/static + +# Update it to match the domain that will be used to reach your funkwhale +# instance +# Example: DJANGO_ALLOWED_HOSTS=funkwhale.yourdomain.com +DJANGO_ALLOWED_HOSTS=__DOMAIN__ + +# which settings module should django use? +# You don't have to touch this unless you really know what you're doing +DJANGO_SETTINGS_MODULE=config.settings.production + +# Generate one using `openssl rand -base64 45`, for example +DJANGO_SECRET_KEY="__KEY__" + +# You don't have to edit this, but you can put the admin on another URL if you +# want to +# DJANGO_ADMIN_URL=^api/admin/ + +# If True, unauthenticated users won't be able to query the API +API_AUTHENTICATION_REQUIRED=True + +# Sentry/Raven error reporting (server side) +# Enable Raven if you want to help improve funkwhale by +# automatically sending error reports our Sentry instance. +# This will help us detect and correct bugs +RAVEN_ENABLED=false +RAVEN_DSN=https://44332e9fdd3d42879c7d35bf8562c6a4:0062dc16a22b41679cd5765e5342f716@sentry.eliotberriot.com/5 diff --git a/conf/funkwhale-server.service b/conf/funkwhale-server.service new file mode 100644 index 0000000..7e2e93e --- /dev/null +++ b/conf/funkwhale-server.service @@ -0,0 +1,14 @@ +[Unit] +Description=Funkwhale (__APP__) application server +After=redis.service postgresql.service +PartOf=__APP__.target + +[Service] +User=__APP__ +# adapt this depending on the path of your funkwhale installation +WorkingDirectory=__FINALPATH__/api +EnvironmentFile=__FINALPATH__/config/.env +ExecStart=__FINALPATH__/virtualenv/bin/daphne -b ${FUNKWHALE_API_IP} -p ${FUNKWHALE_API_PORT} config.asgi:application + +[Install] +WantedBy=multi-user.target diff --git a/conf/funkwhale-worker.service b/conf/funkwhale-worker.service new file mode 100644 index 0000000..6c39057 --- /dev/null +++ b/conf/funkwhale-worker.service @@ -0,0 +1,14 @@ +[Unit] +Description=Funkwhale (__APP__) celery worker +After=redis.service postgresql.service +PartOf=__APP__.target + +[Service] +User=__APP__ +# adapt this depending on the path of your funkwhale installation +WorkingDirectory=__FINALPATH__/api +EnvironmentFile=__FINALPATH__/config/.env +ExecStart=__FINALPATH__/virtualenv/bin/celery -A funkwhale_api.taskapp worker -l INFO + +[Install] +WantedBy=multi-user.target diff --git a/conf/funkwhale.target b/conf/funkwhale.target new file mode 100644 index 0000000..f1eef7e --- /dev/null +++ b/conf/funkwhale.target @@ -0,0 +1,3 @@ +[Unit] +Description=Funkwhale (__APP__) +Wants=__APP__-server.service __APP__-worker.service diff --git a/conf/nginx.conf b/conf/nginx.conf new file mode 100644 index 0000000..a8e735f --- /dev/null +++ b/conf/nginx.conf @@ -0,0 +1,80 @@ +location / { + try_files $uri $uri/ @rewrites; +} + +location @rewrites { + rewrite ^(.+)$ /index.html last; +} + +location /api/ { + include __FINALPATH__/deploy/funkwhale_proxy.conf; + # this is needed if you have file import via upload enabled + client_max_body_size 30M; + proxy_pass http://127.0.0.1:__PORT__/api/; +} + +location /federation/ { + include __FINALPATH__/deploy/funkwhale_proxy.conf; + proxy_pass http://127.0.0.1:__PORT__/federation/; +} + +location /.well-known/webfinger { + include __FINALPATH__/deploy/funkwhale_proxy.conf; + proxy_pass http://127.0.0.1:__PORT__/.well-known/webfinger; +} + +location /media/ { + alias __FINALPATH__/data/media/; +} + +location __PATH__/_protected/media/ { + # this is an internal location that is used to serve + # audio files once correct permission / authentication + # has been checked on API side + internal; + alias __FINALPATH__/data/media/; +} + +# Transcoding logic and caching +# TODO: try to enable this +# https://code.eliotberriot.com/funkwhale/funkwhale/blob/0.8/deploy/nginx.conf#L4 +# https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache + +location = /transcode-auth { + include __FINALPATH__/deploy/funkwhale_proxy.conf; + # needed so we can authenticate transcode requests, but still + # cache the result + internal; + set $query ''; + # ensure we actually pass the jwt to the underlytin auth url + if ($request_uri ~* "[^\?]+\?(.*)$") { + set $query $1; + } + proxy_pass http://127.0.0.1:__PORT__/api/v1/trackfiles/viewable/?$query; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; +} + +location /api/v1/trackfiles/transcode/ { + include __FINALPATH__/deploy/funkwhale_proxy.conf; + # this block deals with authenticating and caching transcoding + # requests. Caching is heavily recommended as transcoding + # is a CPU intensive process. + auth_request /transcode-auth; + if ($args ~ (.*)jwt=[^&]*(.*)) { + set $cleaned_args $1$2; + } + proxy_cache_key "$scheme$request_method$host$uri$is_args$cleaned_args"; + proxy_cache transcode; + proxy_cache_valid 200 7d; + proxy_ignore_headers "Set-Cookie"; + proxy_hide_header "Set-Cookie"; + add_header X-Cache-Status $upstream_cache_status; + proxy_pass http://127.0.0.1:__PORT__; +} +# end of transcoding logic + +location /staticfiles/ { + # django static files + alias __FINALPATH__/data/static/; +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..18df728 --- /dev/null +++ b/manifest.json @@ -0,0 +1,59 @@ +{ + "name": "Funkwhale", + "id": "funkwhale", + "packaging_format": 1, + "requirements": { + "yunohost": ">= 2.7.10" + }, + "description": { + "en": "A translation platform using Git and Python" + }, + "version": "0.8.0-1", + "url": "https://funkwhale.audio", + "license": "BSD-3-Clause", + "maintainer": { + "name": "Jean-Baptiste Holcroft", + "email": "jean-baptiste@holcroft.fr" + }, + "multi_instance": false, + "services": [ + "nginx" + ], + "arguments": { + "install" : [ + { + "name": "domain", + "type": "domain", + "ask": { + "en": "Choose a domain for Weblate:" + }, + "example": "domain.org" + }, + { + "name": "path", + "type": "path", + "ask": { + "en": "Choose a path for Weblate:" + }, + "example": "/weblate", + "default": "/weblate" + }, + { + "name": "is_public", + "type": "boolean", + "ask": { + "en": "Should Weblate be public accessible?" + }, + "default": "0" + }, + { + "name": "admin", + "type": "user", + "ask": { + "en": "Choose an admin user for Funkwhale?" + }, + "example": "jean-baptiste" + } + ] + } +} diff --git a/scripts/_common.sh b/scripts/_common.sh new file mode 100644 index 0000000..e91494b --- /dev/null +++ b/scripts/_common.sh @@ -0,0 +1,318 @@ +#!/bin/bash + +current_version="2.20" + +ynh_check_global_uwsgi_config () { + uwsgi --version || ynh_die "You need to add uwsgi (and appropriate plugin) as a dependency" + + if [ -f /etc/systemd/system/uwsgi-app@.service ]; + then + echo "Uwsgi generic file is already installed" + else + cp ../conf/uwsgi-app@.socket /etc/systemd/system/uwsgi-app@.socket + cp ../conf/uwsgi-app@.service /etc/systemd/system/uwsgi-app@.service + fi + + # make sure the folder for sockets exists and set authorizations + mkdir -p /var/run/uwsgi/ + chown root:www-data /var/run/uwsgi/ + chmod -R 775 /var/run/uwsgi/ + + # make sure the folder for logs exists and set authorizations + mkdir -p /var/log/uwsgi/app/ + chown root:www-data /var/log/uwsgi/app/ + chmod -R 775 /var/log/uwsgi/app/ +} + +# Create a dedicated uwsgi ini file to use with generic uwsgi service +# It will install generic uwsgi.socket and +# +# This will use a template in ../conf/uwsgi.ini +# and will replace the following keywords with +# global variables that should be defined before calling +# this helper : +# +# __APP__ by $app +# __PATH__ by $path_url +# __FINALPATH__ by $final_path +# +# usage: ynh_add_systemd_config +# +# to interact with your service: `systemctl uwsgi-app@app` +ynh_add_uwsgi_service () { + ynh_check_global_uwsgi_config + + # www-data group is needed since it is this nginx who will start the service + usermod --append --groups www-data "$app" || ynh_die "It wasn't possible to add user $app to group www-data" + + finaluwsgiini="/etc/uwsgi/apps-available/$app.ini" + ynh_backup_if_checksum_is_different "$finaluwsgiini" + cp ../conf/uwsgi.ini "$finaluwsgiini" + + # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. + # Substitute in a nginx config file only if the variable is not empty + if test -n "${final_path:-}"; then + ynh_replace_string "__FINALPATH__" "$final_path" "$finaluwsgiini" + fi + if test -n "${path_url:-}"; then + ynh_replace_string "__PATH__" "$path_url" "$finaluwsgiini" + fi + if test -n "${app:-}"; then + ynh_replace_string "__APP__" "$app" "$finaluwsgiini" + fi + ynh_store_file_checksum "$finaluwsgiini" + + chown root: "$finaluwsgiini" + systemctl enable "uwsgi-app@$app.socket" + systemctl start "uwsgi-app@$app.socket" + systemctl daemon-reload + + # Add as a service + yunohost service add "uwsgi-app@$app.socket" --log "/var/log/uwsgi/app/$app" +} + +# Remove the dedicated uwsgi ini file +# +# usage: ynh_remove_systemd_config +ynh_remove_uwsgi_service () { + finaluwsgiini="/etc/uwsgi/apps-available/$app.ini" + if [ -e "$finaluwsgiini" ]; then + systemctl stop "uwsgi-app@$app.socket" + systemctl disable "uwsgi-app@$app.socket" + yunohost service remove "uwsgi-app@$app.socket" + + ynh_secure_remove "$finaluwsgiini" + ynh_secure_remove "/var/run/uwsgi/$app.socket" + ynh_secure_remove "/var/log/uwsgi/app/$app" + fi +} + + +weblate_fill_settings() { + settings="$1" + + ynh_replace_string "__NAME__" "$app" "$settings" + ynh_replace_string "__DB_PWD__" "$db_pwd" "$settings" + ynh_replace_string "__ADMIN__" "$admin" "$settings" + ynh_replace_string "__ADMINMAIL__" "$admin_mail" "$settings" + ynh_replace_string "__DOMAIN__" "$domain" "$settings" + ynh_replace_string "__KEY__" "$key" "$settings" + ynh_replace_string "__FINALPATH__" "$final_path" "$settings" + ynh_replace_string "__MEMCPORT__" "$memc_port" "$settings" + ynh_replace_string "__GITHUBUSER__" "$github_account" "$settings" + + # root install as an empty PATHURL to prevent '//static' + if [ "$path_url" == "/" ] + then + ynh_replace_string "__PATHURL__" "" "$settings" + else + ynh_replace_string "__PATHURL__" "$path_url" "$settings" + fi +} + +ynh_check_if_checksum_is_different() { + local file=$1 + local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_' + local checksum_value=$(ynh_app_setting_get $app $checksum_setting_name) + local check=0 + + if ! echo "$checksum_value $file" | md5sum -c --status + then # If the checksum is now different + check=1 + fi + + echo "$check" +} + +ynh_psql_test_if_first_run() { + if [ -f /etc/yunohost/psql ]; + then + echo "PostgreSQL is already installed, no need to create master password" + else + pgsql=$(ynh_string_random) + pg_hba="" + echo "$pgsql" >> /etc/yunohost/psql + + if [ -e /etc/postgresql/9.4/ ] + then + pg_hba=/etc/postgresql/9.4/main/pg_hba.conf + elif [ -e /etc/postgresql/9.6/ ] + then + pg_hba=/etc/postgresql/9.6/main/pg_hba.conf + else + ynh_die "postgresql shoud be 9.4 or 9.6" + fi + + systemctl start postgresql + su --command="psql -c\"ALTER user postgres WITH PASSWORD '${pgsql}'\"" postgres + # we can't use peer since YunoHost create users with nologin + sed -i '/local\s*all\s*all\s*peer/i \ + local all all password' "$pg_hba" + systemctl enable postgresql + systemctl reload postgresql + fi +} + +# Open a connection as a user +# +# example: ynh_psql_connect_as 'user' 'pass' <<< "UPDATE ...;" +# example: ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql +# +# usage: ynh_psql_connect_as user pwd [db] +# | arg: user - the user name to connect as +# | arg: pwd - the user password +# | arg: db - the database to connect to +ynh_psql_connect_as() { + user="$1" + pwd="$2" + db="$3" + su --command="PGUSER=\"${user}\" PGPASSWORD=\"${pwd}\" psql \"${db}\"" postgres +} + +# # Execute a command as root user +# +# usage: ynh_psql_execute_as_root sql [db] +# | arg: sql - the SQL command to execute +# | arg: db - the database to connect to +ynh_psql_execute_as_root () { + sql="$1" + su --command="psql" postgres <<< "$sql" +} + +# Execute a command from a file as root user +# +# usage: ynh_psql_execute_file_as_root file [db] +# | arg: file - the file containing SQL commands +# | arg: db - the database to connect to +ynh_psql_execute_file_as_root() { + file="$1" + db="$2" + su -c "psql $db" postgres < "$file" +} + +# Create a database, an user and its password. Then store the password in the app's config +# +# After executing this helper, the password of the created database will be available in $db_pwd +# It will also be stored as "psqlpwd" into the app settings. +# +# usage: ynh_psql_setup_db user name [pwd] +# | arg: user - Owner of the database +# | arg: name - Name of the database +# | arg: pwd - Password of the database. If not given, a password will be generated +ynh_psql_setup_db () { + db_user="$1" + app="$1" + db_name="$2" + new_db_pwd=$(ynh_string_random) # Generate a random password + # If $3 is not given, use new_db_pwd instead for db_pwd. + db_pwd="${3:-$new_db_pwd}" + ynh_psql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database + ynh_app_setting_set "$app" psqlpwd "$db_pwd" # Store the password in the app's config +} + +# Create a database and grant optionnaly privilegies to a user +# +# usage: ynh_psql_create_db db [user [pwd]] +# | arg: db - the database name to create +# | arg: user - the user to grant privilegies +# | arg: pwd - the user password +ynh_psql_create_db() { + db="$1" + user="$2" + pwd="$3" + ynh_psql_create_user "$user" "$pwd" + su --command="createdb --owner=\"${user}\" \"${db}\"" postgres +} + +# Drop a database +# +# usage: ynh_psql_drop_db db +# | arg: db - the database name to drop +# | arg: user - the user to drop +ynh_psql_remove_db() { + db="$1" + user="$2" + su --command="dropdb \"${db}\"" postgres + ynh_psql_drop_user "${user}" +} + +# Dump a database +# +# example: ynh_psql_dump_db 'roundcube' > ./dump.sql +# +# usage: ynh_psql_dump_db db +# | arg: db - the database name to dump +# | ret: the psqldump output +ynh_psql_dump_db() { + db="$1" + su --command="pg_dump \"${db}\"" postgres +} + + +# Create a user +# +# usage: ynh_psql_create_user user pwd [host] +# | arg: user - the user name to create +ynh_psql_create_user() { + user="$1" + pwd="$2" + su --command="psql -c\"CREATE USER ${user} WITH PASSWORD '${pwd}'\"" postgres +} + +# Drop a user +# +# usage: ynh_psql_drop_user user +# | arg: user - the user name to drop +ynh_psql_drop_user() { + user="$1" + su --command="dropuser \"${user}\"" postgres +} + +# Send an email to inform the administrator +# +# usage: ynh_send_readme_to_admin app_message [recipients] +# | arg: app_message - The message to send to the administrator. +# | arg: recipients - The recipients of this email. Use spaces to separate multiples recipients. - default: root +# example: "root admin@domain" +# If you give the name of a YunoHost user, ynh_send_readme_to_admin will find its email adress for you +# example: "root admin@domain user1 user2" +ynh_send_readme_to_admin() { + local app_message="${1:-...No specific informations...}" + local recipients="${2:-root}" + + # Retrieve the email of users + find_mails () { + local list_mails="$1" + local mail + local recipients=" " + # Read each mail in argument + for mail in $list_mails + do + # Keep root or a real email address as it is + if [ "$mail" = "root" ] || echo "$mail" | grep --quiet "@" + then + recipients="$recipients $mail" + else + # But replace an user name without a domain after by its email + if mail=$(ynh_user_get_info "$mail" "mail" 2> /dev/null) + then + recipients="$recipients $mail" + fi + fi + done + echo "$recipients" + } + recipients=$(find_mails "$recipients") + + local mail_subject="☁️🆈🅽🅷☁️: \`$app\` was just installed!" + + local mail_message="This is an automated message from your beloved YunoHost server. +Specific informations for the application $app. +$app_message +--- +Automatic diagnosis data from YunoHost +$(yunohost tools diagnosis | grep -B 100 "services:" | sed '/services:/d')" + + # Send the email to the recipients + echo "$mail_message" | mail -a "Content-Type: text/plain; charset=UTF-8" -s "$mail_subject" "$recipients" +} diff --git a/scripts/install b/scripts/install new file mode 100644 index 0000000..b4d176f --- /dev/null +++ b/scripts/install @@ -0,0 +1,200 @@ + +#!/bin/bash + +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _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 FROM THE MANIFEST +#================================================= + +domain=$YNH_APP_ARG_DOMAIN +path_url=$YNH_APP_ARG_PATH +is_public=$YNH_APP_ARG_IS_PUBLIC +admin=$YNH_APP_ARG_ADMIN +port=$(ynh_find_port 5000) + +app=$YNH_APP_INSTANCE_NAME + + +#================================================= +# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS +#================================================= + +final_path="/var/www/$app" +test ! -e "$final_path" || ynh_die "This path already contains a folder" + +# Normalize the url path syntax +path_url=$(ynh_normalize_url_path "$path_url") + +# Check web path availability +ynh_webpath_available "$domain" "$path_url" +# Register (book) web path +ynh_webpath_register "$app" "$domain" "$path_url" + +#================================================= +# STORE SETTINGS FROM MANIFEST +#================================================= + +ynh_app_setting_set "$app" domain "$domain" +ynh_app_setting_set "$app" path "$path_url" +ynh_app_setting_set "$app" is_public "$is_public" +ynh_app_setting_set "$app" admin "$admin" +ynh_app_setting_set "$app" port "$port" + +#================================================= +# STANDARD MODIFICATIONS +#================================================= + +# add backports (required to install ffmpeg) +echo "deb http://httpredir.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list +ynh_package_update + +ynh_install_app_dependencies build-essential curl ffmpeg \ + libjpeg-dev libmagic-dev libpq-dev postgresql python3-dev python3-venv + +#================================================= +# CREATE A PostgreSQL DATABASE +#================================================= + +ynh_psql_test_if_first_run + +db_name=$(ynh_sanitize_dbid "$app") +db_user_pwd=$(ynh_string_random) +# Initialize database and store postgres password for upgrade +ynh_psql_create_db "$db_name" "$app" "$db_user_pwd" +ynh_app_setting_set "$app" db_name "$db_name" +ynh_app_setting_set "$app" psqlpwd "$db_user_pwd" + +systemctl reload postgresql + +#================================================= +# DOWNLOAD, CHECK AND UNPACK SOURCE +#================================================= + +ynh_app_setting_set "$app" final_path "$final_path" +# Download, check integrity, uncompress and patch the source from app.src +ynh_setup_source "$final_path" + +( + cd "$final_path" + mkdir -p config api data/static data/media data/music front +) + +#================================================= +# NGINX CONFIGURATION +#================================================= + +# add proxy_cache and connection_upgrade at the beginning of the domain configuration +echo " + +proxy_cache_path /tmp/$app-transcode levels=1:2 keys_zone=transcode:10m max_size=1g inactive=7d; + +# required for websocket support +map \$http_upgrade \$connection_upgrade { + default upgrade; + '' close; +} +" | cat - "/etc/nginx/conf.d/$domain.conf" > temp && mv temp "/etc/nginx/conf.d/$domain.conf" + +# Create a dedicated nginx config +ynh_add_nginx_config + +#================================================= +# CREATE DEDICATED USER +#================================================= + +# Create a system user +ynh_system_user_create "$app" "$final_path" + +#================================================= +# SPECIFIC SETUP +#================================================= +# PYTHON DEPENDENCIES +#================================================= + +python3 -m venv "$final_path/virtualenv" +( + set +o nounset + source "${final_path}/virtualenv/bin/activate" + set -o nounset + pip install --upgrade pip + pip install --upgrade setuptools + pip install wheel + pip install -r "${final_path}/api/requirements.txt" +) + +#================================================= +# MODIFY THE CONFIG FILE +#================================================= + +configfile="$final_path/config/.env" + +cp ../conf/env.prod "$configfile" + +key=$(ynh_string_random 50) + +ynh_app_setting_set "$app" key "$key" + +ynh_replace_string "__PORT__" "$port" "$configfile" +ynh_replace_string "__DOMAIN__" "$domain" "$configfile" +ynh_replace_string "__DBUSER__" "$db_name" "$configfile" +ynh_replace_string "__DBPWD__" "$db_user_pwd" "$configfile" +ynh_replace_string "__DBNAME__" "$app" "$configfile" +ynh_replace_string "__FINALPATH__" "$final_path" "$configfile" +ynh_replace_string "__KEY__" "$key" "$configfile" + +cat > "$final_path/load_env" <<'EOL' +#!/bin/bash +export $(cat "$final_path/config/.env" | grep -v ^# | xargs) +EOL + +chmod +x "$final_path/load_env" + +#================================================= +# MODIFY THE CONFIG FILE +#================================================= + +admin_mail=$(ynh_user_get_info "$admin" "mail") +( + set +o nounset + source "${final_path}/virtualenv/bin/activate" + source "${final_path}/load_env" + set -o nounset + cd "$final_path" + python api/manage.py migrate + python api/manage.py createsuperuser \ + --username "$admin" \ + --email "$admin_mail" + python api/manage.py collectstatic +) + +#================================================= +# SETUP SYSTEMD +#================================================= + +# Create a dedicated systemd config +ynh_add_systemd_config "$app-server" "funkwhale-server" +ynh_add_systemd_config "$app-worker" "funkwhale-worker" + +cp ../conf/funkwhale.target "/etc/systemd/system/$app.target" + +#================================================= +# SETUP SYSTEMD +#================================================= + +systemctl daemon-reload +systemctl start "$app".target diff --git a/scripts/remove b/scripts/remove new file mode 100644 index 0000000..6149ad0 --- /dev/null +++ b/scripts/remove @@ -0,0 +1,77 @@ +#!/bin/bash + +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +ynh_die "!" +#================================================= +# LOAD SETTINGS +#================================================= + +app=$YNH_APP_INSTANCE_NAME + +domain=$(ynh_app_setting_get $app domain) +db_name=$(ynh_app_setting_get $app db_name) +db_user=$db_name +final_path=$(ynh_app_setting_get $app final_path) + +#================================================= +# STANDARD REMOVE +#================================================= +# STOP AND REMOVE SERVICE +#================================================= + +# Remove the dedicated systemd config +ynh_remove_systemd_config "$app-server" +ynh_remove_systemd_config "$app-worker" +ynh_secure_remove "/etc/systemd/system/$app.target" + +#================================================= +# REMOVE DEPENDENCIES +#================================================= + +# Remove metapackage and its dependencies +ynh_remove_app_dependencies + +#================================================= +# REMOVE THE PostgreSQL DATABASE +#================================================= + +# Remove a database if it exists, along with the associated user +ynh_psql_remove_db "$db_name" "$app" + +#================================================= +# REMOVE DEPENDENCIES +#================================================= + +# Remove metapackage and its dependencies +ynh_remove_app_dependencies + +#================================================= +# REMOVE APP MAIN DIR +#================================================= + +# Remove the app directory securely +ynh_secure_remove "$final_path" + +#================================================= +# REMOVE NGINX CONFIGURATION +#================================================= + +# Remove the dedicated nginx config +ynh_remove_nginx_config + +#================================================= +# GENERIC FINALIZATION +#================================================= +# REMOVE DEDICATED USER +#================================================= + +# Delete a system user +ynh_system_user_delete "$app"