_common.sh 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. #!/bin/bash
  2. #=================================================
  3. # BACKUP
  4. #=================================================
  5. HUMAN_SIZE () { # Transforme une taille en Ko en une taille lisible pour un humain
  6. human=$(numfmt --to=iec --from-unit=1K $1)
  7. echo $human
  8. }
  9. CHECK_SIZE () { # Vérifie avant chaque backup que l'espace est suffisant
  10. file_to_analyse=$1
  11. backup_size=$(du --summarize "$file_to_analyse" | cut -f1)
  12. free_space=$(df --output=avail "/home/yunohost.backup" | sed 1d)
  13. if [ $free_space -le $backup_size ]
  14. then
  15. ynh_print_err "Espace insuffisant pour sauvegarder $file_to_analyse."
  16. ynh_print_err "Espace disponible: $(HUMAN_SIZE $free_space)"
  17. ynh_die "Espace nécessaire: $(HUMAN_SIZE $backup_size)"
  18. fi
  19. }
  20. #=================================================
  21. # PACKAGE CHECK BYPASSING...
  22. #=================================================
  23. IS_PACKAGE_CHECK () {
  24. return $(env | grep -c container=lxc)
  25. }
  26. #=================================================
  27. # BOOLEAN CONVERTER
  28. #=================================================
  29. bool_to_01 () {
  30. local var="$1"
  31. [ "$var" = "true" ] && var=1
  32. [ "$var" = "false" ] && var=0
  33. echo "$var"
  34. }
  35. bool_to_true_false () {
  36. local var="$1"
  37. [ "$var" = "1" ] && var=true
  38. [ "$var" = "0" ] && var=false
  39. echo "$var"
  40. }
  41. #=================================================
  42. # FUTUR OFFICIAL HELPERS
  43. #=================================================
  44. # Install or update the main directory yunohost.multimedia
  45. #
  46. # usage: ynh_multimedia_build_main_dir
  47. ynh_multimedia_build_main_dir () {
  48. local ynh_media_release="v1.2"
  49. local checksum="806a827ba1902d6911095602a9221181"
  50. # Download yunohost.multimedia scripts
  51. wget -nv https://github.com/YunoHost-Apps/yunohost.multimedia/archive/${ynh_media_release}.tar.gz
  52. # Check the control sum
  53. echo "${checksum} ${ynh_media_release}.tar.gz" | md5sum -c --status \
  54. || ynh_die "Corrupt source"
  55. # Check if the package acl is installed. Or install it.
  56. ynh_package_is_installed 'acl' \
  57. || ynh_package_install acl
  58. # Extract
  59. mkdir yunohost.multimedia-master
  60. tar -xf ${ynh_media_release}.tar.gz -C yunohost.multimedia-master --strip-components 1
  61. ./yunohost.multimedia-master/script/ynh_media_build.sh
  62. }
  63. # Add a directory in yunohost.multimedia
  64. # This "directory" will be a symbolic link to a existing directory.
  65. #
  66. # usage: ynh_multimedia_addfolder "Source directory" "Destination directory"
  67. #
  68. # | arg: -s, --source_dir= - Source directory - The real directory which contains your medias.
  69. # | arg: -d, --dest_dir= - Destination directory - The name and the place of the symbolic link, relative to "/home/yunohost.multimedia"
  70. ynh_multimedia_addfolder () {
  71. # Declare an array to define the options of this helper.
  72. declare -Ar args_array=( [s]=source_dir= [d]=dest_dir= )
  73. local source_dir
  74. local dest_dir
  75. # Manage arguments with getopts
  76. ynh_handle_getopts_args "$@"
  77. ./yunohost.multimedia-master/script/ynh_media_addfolder.sh --source="$source_dir" --dest="$dest_dir"
  78. }
  79. # Move a directory in yunohost.multimedia, and replace by a symbolic link
  80. #
  81. # usage: ynh_multimedia_movefolder "Source directory" "Destination directory"
  82. #
  83. # | arg: -s, --source_dir= - Source directory - The real directory which contains your medias.
  84. # It will be moved to "Destination directory"
  85. # A symbolic link will replace it.
  86. # | arg: -d, --dest_dir= - Destination directory - The new name and place of the directory, relative to "/home/yunohost.multimedia"
  87. ynh_multimedia_movefolder () {
  88. # Declare an array to define the options of this helper.
  89. declare -Ar args_array=( [s]=source_dir= [d]=dest_dir= )
  90. local source_dir
  91. local dest_dir
  92. # Manage arguments with getopts
  93. ynh_handle_getopts_args "$@"
  94. ./yunohost.multimedia-master/script/ynh_media_addfolder.sh --inv --source="$source_dir" --dest="$dest_dir"
  95. }
  96. # Allow an user to have an write authorisation in multimedia directories
  97. #
  98. # usage: ynh_multimedia_addaccess user_name
  99. #
  100. # | arg: -u, --user_name= - The name of the user which gain this access.
  101. ynh_multimedia_addaccess () {
  102. # Declare an array to define the options of this helper.
  103. declare -Ar args_array=( [u]=user_name=)
  104. local user_name
  105. # Manage arguments with getopts
  106. ynh_handle_getopts_args "$@"
  107. groupadd -f multimedia
  108. usermod -a -G multimedia $user_name
  109. }
  110. #=================================================
  111. # Create a dedicated fail2ban config (jail and filter conf files)
  112. #
  113. # usage: ynh_add_fail2ban_config log_file filter [max_retry [ports]]
  114. # | arg: -l, --logpath= - Log file to be checked by fail2ban
  115. # | arg: -r, --failregex= - Failregex to be looked for by fail2ban
  116. # | arg: -m, --max_retry= - Maximum number of retries allowed before banning IP address - default: 3
  117. # | arg: -p, --ports= - Ports blocked for a banned IP address - default: http,https
  118. ynh_add_fail2ban_config () {
  119. # Declare an array to define the options of this helper.
  120. declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= )
  121. local logpath
  122. local failregex
  123. local max_retry
  124. local ports
  125. # Manage arguments with getopts
  126. ynh_handle_getopts_args "$@"
  127. max_retry=${max_retry:-3}
  128. ports=${ports:-http,https}
  129. test -n "$logpath" || ynh_die "ynh_add_fail2ban_config expects a logfile path as first argument and received nothing."
  130. test -n "$failregex" || ynh_die "ynh_add_fail2ban_config expects a failure regex as second argument and received nothing."
  131. finalfail2banjailconf="/etc/fail2ban/jail.d/$app.conf"
  132. finalfail2banfilterconf="/etc/fail2ban/filter.d/$app.conf"
  133. ynh_backup_if_checksum_is_different "$finalfail2banjailconf" 1
  134. ynh_backup_if_checksum_is_different "$finalfail2banfilterconf" 1
  135. tee $finalfail2banjailconf <<EOF
  136. [$app]
  137. enabled = true
  138. port = $ports
  139. filter = $app
  140. logpath = $logpath
  141. maxretry = $max_retry
  142. EOF
  143. tee $finalfail2banfilterconf <<EOF
  144. [INCLUDES]
  145. before = common.conf
  146. [Definition]
  147. failregex = $failregex
  148. ignoreregex =
  149. EOF
  150. ynh_store_file_checksum "$finalfail2banjailconf"
  151. ynh_store_file_checksum "$finalfail2banfilterconf"
  152. if [ "$(lsb_release --codename --short)" != "jessie" ]; then
  153. systemctl reload fail2ban
  154. else
  155. systemctl restart fail2ban
  156. fi
  157. local fail2ban_error="$(journalctl -u fail2ban | tail -n50 | grep "WARNING.*$app.*")"
  158. if [ -n "$fail2ban_error" ]
  159. then
  160. echo "[ERR] Fail2ban failed to load the jail for $app" >&2
  161. echo "WARNING${fail2ban_error#*WARNING}" >&2
  162. fi
  163. }
  164. # Remove the dedicated fail2ban config (jail and filter conf files)
  165. #
  166. # usage: ynh_remove_fail2ban_config
  167. ynh_remove_fail2ban_config () {
  168. ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf"
  169. ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf"
  170. if [ "$(lsb_release --codename --short)" != "jessie" ]; then
  171. systemctl reload fail2ban
  172. else
  173. systemctl restart fail2ban
  174. fi
  175. }
  176. #=================================================
  177. # Read the value of a key in a ynh manifest file
  178. #
  179. # usage: ynh_read_manifest manifest key
  180. # | arg: -m, --manifest= - Path of the manifest to read
  181. # | arg: -k, --key= - Name of the key to find
  182. ynh_read_manifest () {
  183. # Declare an array to define the options of this helper.
  184. declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
  185. local manifest
  186. local manifest_key
  187. # Manage arguments with getopts
  188. ynh_handle_getopts_args "$@"
  189. python3 -c "import sys, json;print(json.load(open('$manifest', encoding='utf-8'))['$manifest_key'])"
  190. }
  191. # Read the upstream version from the manifest
  192. # The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
  193. # For example : 4.3-2~ynh3
  194. # This include the number before ~ynh
  195. # In the last example it return 4.3-2
  196. #
  197. # usage: ynh_app_upstream_version [-m manifest]
  198. # | arg: -m, --manifest= - Path of the manifest to read
  199. ynh_app_upstream_version () {
  200. declare -Ar args_array=( [m]=manifest= )
  201. local manifest
  202. # Manage arguments with getopts
  203. ynh_handle_getopts_args "$@"
  204. manifest="${manifest:-../manifest.json}"
  205. if [ ! -e "$manifest" ]; then
  206. manifest="../settings/manifest.json" # Into the restore script, the manifest is not at the same place
  207. fi
  208. version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
  209. echo "${version_key/~ynh*/}"
  210. }
  211. # Read package version from the manifest
  212. # The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
  213. # For example : 4.3-2~ynh3
  214. # This include the number after ~ynh
  215. # In the last example it return 3
  216. #
  217. # usage: ynh_app_package_version [-m manifest]
  218. # | arg: -m, --manifest= - Path of the manifest to read
  219. ynh_app_package_version () {
  220. declare -Ar args_array=( [m]=manifest= )
  221. local manifest
  222. # Manage arguments with getopts
  223. ynh_handle_getopts_args "$@"
  224. manifest="${manifest:-../manifest.json}"
  225. if [ ! -e "$manifest" ]; then
  226. manifest="../settings/manifest.json" # Into the restore script, the manifest is not at the same place
  227. fi
  228. version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
  229. echo "${version_key/*~ynh/}"
  230. }
  231. # Checks the app version to upgrade with the existing app version and returns:
  232. # - UPGRADE_APP if the upstream app version has changed
  233. # - UPGRADE_PACKAGE if only the YunoHost package has changed
  234. #
  235. ## It stops the current script without error if the package is up-to-date
  236. #
  237. # This helper should be used to avoid an upgrade of an app, or the upstream part
  238. # of it, when it's not needed
  239. #
  240. # To force an upgrade, even if the package is up to date,
  241. # you have to set the variable YNH_FORCE_UPGRADE before.
  242. # example: sudo YNH_FORCE_UPGRADE=1 yunohost app upgrade MyApp
  243. #
  244. # usage: ynh_check_app_version_changed
  245. ynh_check_app_version_changed () {
  246. local force_upgrade=${YNH_FORCE_UPGRADE:-0}
  247. local package_check=${PACKAGE_CHECK_EXEC:-0}
  248. # By default, upstream app version has changed
  249. local return_value="UPGRADE_APP"
  250. local current_version=$(ynh_read_manifest --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json" --manifest_key="version" || echo 1.0)
  251. local current_upstream_version="$(ynh_app_upstream_version --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json")"
  252. local update_version=$(ynh_read_manifest --manifest="../manifest.json" --manifest_key="version" || echo 1.0)
  253. local update_upstream_version="$(ynh_app_upstream_version)"
  254. if [ "$current_version" == "$update_version" ] ; then
  255. # Complete versions are the same
  256. if [ "$force_upgrade" != "0" ]
  257. then
  258. echo "Upgrade forced by YNH_FORCE_UPGRADE." >&2
  259. unset YNH_FORCE_UPGRADE
  260. elif [ "$package_check" != "0" ]
  261. then
  262. echo "Upgrade forced for package check." >&2
  263. else
  264. ynh_die "Up-to-date, nothing to do" 0
  265. fi
  266. elif [ "$current_upstream_version" == "$update_upstream_version" ] ; then
  267. # Upstream versions are the same, only YunoHost package versions differ
  268. return_value="UPGRADE_PACKAGE"
  269. fi
  270. echo $return_value
  271. }
  272. #=================================================
  273. # Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
  274. #
  275. # usage: ynh_systemd_action [-n service_name] [-a action] [ [-l "line to match"] [-p log_path] [-t timeout] [-e length] ]
  276. # | arg: -n, --service_name= - Name of the service to reload. Default : $app
  277. # | arg: -a, --action= - Action to perform with systemctl. Default: start
  278. # | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot.
  279. # If not defined it don't wait until the service is completely started.
  280. # | arg: -p, --log_path= - Log file - Path to the log file. Default : /var/log/$app/$app.log
  281. # | arg: -t, --timeout= - Timeout - The maximum time to wait before ending the watching. Default : 300 seconds.
  282. # | arg: -e, --length= - Length of the error log : Default : 20
  283. ynh_systemd_action() {
  284. # Declare an array to define the options of this helper.
  285. declare -Ar args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= )
  286. local service_name
  287. local action
  288. local line_match
  289. local length
  290. local log_path
  291. local timeout
  292. # Manage arguments with getopts
  293. ynh_handle_getopts_args "$@"
  294. local service_name="${service_name:-$app}"
  295. local action=${action:-start}
  296. local log_path="${log_path:-/var/log/$service_name/$service_name.log}"
  297. local length=${length:-20}
  298. local timeout=${timeout:-300}
  299. # Start to read the log
  300. if [[ -n "${line_match:-}" ]]
  301. then
  302. local templog="$(mktemp)"
  303. # Following the starting of the app in its log
  304. if [ "$log_path" == "systemd" ] ; then
  305. # Read the systemd journal
  306. journalctl -u $service_name -f --since=-45 > "$templog" &
  307. else
  308. # Read the specified log file
  309. tail -F -n0 "$log_path" > "$templog" &
  310. fi
  311. # Get the PID of the tail command
  312. local pid_tail=$!
  313. fi
  314. echo "${action^} the service $service_name" >&2
  315. systemctl $action $service_name \
  316. || ( journalctl --lines=$length -u $service_name >&2 \
  317. ; test -n "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2 \
  318. ; false )
  319. # Start the timeout and try to find line_match
  320. if [[ -n "${line_match:-}" ]]
  321. then
  322. local i=0
  323. for i in $(seq 1 $timeout)
  324. do
  325. # Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
  326. if grep --quiet "$line_match" "$templog"
  327. then
  328. echo "The service $service_name has correctly started." >&2
  329. break
  330. fi
  331. echo -n "." >&2
  332. sleep 1
  333. done
  334. if [ $i -eq $timeout ]
  335. then
  336. echo "The service $service_name didn't fully started before the timeout." >&2
  337. echo "Please find here an extract of the end of the log of the service $service_name:"
  338. journalctl --lines=$length -u $service_name >&2
  339. test -n "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2
  340. fi
  341. echo ""
  342. ynh_clean_check_starting
  343. fi
  344. }
  345. # Clean temporary process and file used by ynh_check_starting
  346. # (usually used in ynh_clean_setup scripts)
  347. #
  348. # usage: ynh_clean_check_starting
  349. ynh_clean_check_starting () {
  350. # Stop the execution of tail.
  351. kill -s 15 $pid_tail 2>&1
  352. ynh_secure_remove "$templog" 2>&1
  353. }
  354. #=================================================
  355. # Print a message as INFO and show progression during an app script
  356. #
  357. # usage: ynh_script_progression --message=message [--weight=weight] [--time]
  358. # | arg: -m, --message= - The text to print
  359. # | arg: -w, --weight= - The weight for this progression. This value is 1 by default. Use a bigger value for a longer part of the script.
  360. # | arg: -t, --time= - Print the execution time since the last call to this helper. Especially usefull to define weights.
  361. # | arg: -l, --last= - Use for the last call of the helper, to fill te progression bar.
  362. increment_progression=0
  363. previous_weight=0
  364. # Define base_time when the file is sourced
  365. base_time=$(date +%s)
  366. ynh_script_progression () {
  367. # Declare an array to define the options of this helper.
  368. declare -Ar args_array=( [m]=message= [w]=weight= [t]=time [l]=last )
  369. local message
  370. local weight
  371. local time
  372. local last
  373. # Manage arguments with getopts
  374. ynh_handle_getopts_args "$@"
  375. weight=${weight:-1}
  376. time=${time:-0}
  377. last=${last:-0}
  378. # Get execution time since the last $base_time
  379. local exec_time=$(( $(date +%s) - $base_time ))
  380. base_time=$(date +%s)
  381. # Get the number of occurrences of 'ynh_script_progression' in the script. Except those are commented.
  382. local helper_calls="$(grep --count "^[^#]*ynh_script_progression" $0)"
  383. # Get the number of call with a weight value
  384. local weight_calls=$(grep --perl-regexp --count "^[^#]*ynh_script_progression.*(--weight|-w )" $0)
  385. # Get the weight of each occurrences of 'ynh_script_progression' in the script using --weight
  386. local weight_valuesA="$(grep --perl-regexp "^[^#]*ynh_script_progression.*--weight" $0 | sed 's/.*--weight[= ]\([[:digit:]].*\)/\1/g')"
  387. # Get the weight of each occurrences of 'ynh_script_progression' in the script using -w
  388. local weight_valuesB="$(grep --perl-regexp "^[^#]*ynh_script_progression.*-w " $0 | sed 's/.*-w[= ]\([[:digit:]].*\)/\1/g')"
  389. # Each value will be on a different line.
  390. # Remove each 'end of line' and replace it by a '+' to sum the values.
  391. local weight_values=$(( $(echo "$weight_valuesA" | tr '\n' '+') + $(echo "$weight_valuesB" | tr '\n' '+') 0 ))
  392. # max_progression is a total number of calls to this helper.
  393. # Less the number of calls with a weight value.
  394. # Plus the total of weight values
  395. local max_progression=$(( $helper_calls - $weight_calls + $weight_values ))
  396. # Increment each execution of ynh_script_progression in this script by the weight of the previous call.
  397. increment_progression=$(( $increment_progression + $previous_weight ))
  398. # Store the weight of the current call in $previous_weight for next call
  399. previous_weight=$weight
  400. # Set the scale of the progression bar
  401. local scale=20
  402. # progress_string(1,2) should have the size of the scale.
  403. local progress_string1="####################"
  404. local progress_string0="...................."
  405. # Reduce $increment_progression to the size of the scale
  406. if [ $last -eq 0 ]
  407. then
  408. local effective_progression=$(( $increment_progression * $scale / $max_progression ))
  409. # If last is specified, fill immediately the progression_bar
  410. else
  411. local effective_progression=$scale
  412. fi
  413. # Build $progression_bar from progress_string(1,2) according to $effective_progression
  414. local progression_bar="${progress_string1:0:$effective_progression}${progress_string0:0:$(( $scale - $effective_progression ))}"
  415. local print_exec_time=""
  416. if [ $time -eq 1 ]
  417. then
  418. print_exec_time=" [$(date +%Hh%Mm,%Ss --date="0 + $exec_time sec")]"
  419. fi
  420. ynh_print_info "[$progression_bar] > ${message}${print_exec_time}"
  421. }
  422. #=================================================
  423. # EXPERIMENTAL HELPERS
  424. #=================================================
  425. # Send an email to inform the administrator
  426. #
  427. # usage: ynh_send_readme_to_admin --app_message=app_message [--recipients=recipients] [--type=type]
  428. # | arg: -m --app_message= - The file with the content to send to the administrator.
  429. # | arg: -r, --recipients= - The recipients of this email. Use spaces to separate multiples recipients. - default: root
  430. # example: "root admin@domain"
  431. # If you give the name of a YunoHost user, ynh_send_readme_to_admin will find its email adress for you
  432. # example: "root admin@domain user1 user2"
  433. # | arg: -t, --type= - Type of mail, could be 'backup', 'change_url', 'install', 'remove', 'restore', 'upgrade'
  434. ynh_send_readme_to_admin() {
  435. # Declare an array to define the options of this helper.
  436. declare -Ar args_array=( [m]=app_message= [r]=recipients= [t]=type= )
  437. local app_message
  438. local recipients
  439. local type
  440. # Manage arguments with getopts
  441. ynh_handle_getopts_args "$@"
  442. app_message="${app_message:-}"
  443. recipients="${recipients:-root}"
  444. type="${type:-install}"
  445. # Get the value of admin_mail_html
  446. admin_mail_html=$(ynh_app_setting_get $app admin_mail_html)
  447. admin_mail_html="${admin_mail_html:-0}"
  448. # Retrieve the email of users
  449. find_mails () {
  450. local list_mails="$1"
  451. local mail
  452. local recipients=" "
  453. # Read each mail in argument
  454. for mail in $list_mails
  455. do
  456. # Keep root or a real email address as it is
  457. if [ "$mail" = "root" ] || echo "$mail" | grep --quiet "@"
  458. then
  459. recipients="$recipients $mail"
  460. else
  461. # But replace an user name without a domain after by its email
  462. if mail=$(ynh_user_get_info "$mail" "mail" 2> /dev/null)
  463. then
  464. recipients="$recipients $mail"
  465. fi
  466. fi
  467. done
  468. echo "$recipients"
  469. }
  470. recipients=$(find_mails "$recipients")
  471. # Subject base
  472. local mail_subject="☁️🆈🅽🅷☁️: \`$app\`"
  473. # Adapt the subject according to the type of mail required.
  474. if [ "$type" = "backup" ]; then
  475. mail_subject="$mail_subject has just been backup."
  476. elif [ "$type" = "change_url" ]; then
  477. mail_subject="$mail_subject has just been moved to a new URL!"
  478. elif [ "$type" = "remove" ]; then
  479. mail_subject="$mail_subject has just been removed!"
  480. elif [ "$type" = "restore" ]; then
  481. mail_subject="$mail_subject has just been restored!"
  482. elif [ "$type" = "upgrade" ]; then
  483. mail_subject="$mail_subject has just been upgraded!"
  484. else # install
  485. mail_subject="$mail_subject has just been installed!"
  486. fi
  487. local mail_message="This is an automated message from your beloved YunoHost server.
  488. Specific information for the application $app.
  489. $(if [ -n "$app_message" ]
  490. then
  491. cat "$app_message"
  492. else
  493. echo "...No specific information..."
  494. fi)
  495. ---
  496. Automatic diagnosis data from YunoHost
  497. __PRE_TAG1__$(yunohost tools diagnosis | grep -B 100 "services:" | sed '/services:/d')__PRE_TAG2__"
  498. # Store the message into a file for further modifications.
  499. echo "$mail_message" > mail_to_send
  500. # If a html email is required. Apply html tags to the message.
  501. if [ "$admin_mail_html" -eq 1 ]
  502. then
  503. # Insert 'br' tags at each ending of lines.
  504. ynh_replace_string "$" "<br>" mail_to_send
  505. # Insert starting HTML tags
  506. sed --in-place '1s@^@<!DOCTYPE html>\n<html>\n<head></head>\n<body>\n@' mail_to_send
  507. # Keep tabulations
  508. ynh_replace_string " " "\&#160;\&#160;" mail_to_send
  509. ynh_replace_string "\t" "\&#160;\&#160;" mail_to_send
  510. # Insert url links tags
  511. ynh_replace_string "__URL_TAG1__\(.*\)__URL_TAG2__\(.*\)__URL_TAG3__" "<a href=\"\2\">\1</a>" mail_to_send
  512. # Insert pre tags
  513. ynh_replace_string "__PRE_TAG1__" "<pre>" mail_to_send
  514. ynh_replace_string "__PRE_TAG2__" "<\pre>" mail_to_send
  515. # Insert finishing HTML tags
  516. echo -e "\n</body>\n</html>" >> mail_to_send
  517. # Otherwise, remove tags to keep a plain text.
  518. else
  519. # Remove URL tags
  520. ynh_replace_string "__URL_TAG[1,3]__" "" mail_to_send
  521. ynh_replace_string "__URL_TAG2__" ": " mail_to_send
  522. # Remove PRE tags
  523. ynh_replace_string "__PRE_TAG[1-2]__" "" mail_to_send
  524. fi
  525. # Define binary to use for mail command
  526. if [ -e /usr/bin/bsd-mailx ]
  527. then
  528. local mail_bin=/usr/bin/bsd-mailx
  529. else
  530. local mail_bin=/usr/bin/mail.mailutils
  531. fi
  532. if [ "$admin_mail_html" -eq 1 ]
  533. then
  534. content_type="text/html"
  535. else
  536. content_type="text/plain"
  537. fi
  538. # Send the email to the recipients
  539. cat mail_to_send | $mail_bin -a "Content-Type: $content_type; charset=UTF-8" -s "$mail_subject" "$recipients"
  540. }
  541. #=================================================
  542. ynh_debian_release () {
  543. lsb_release --codename --short
  544. }
  545. is_stretch () {
  546. if [ "$(ynh_debian_release)" == "stretch" ]
  547. then
  548. return 0
  549. else
  550. return 1
  551. fi
  552. }
  553. is_jessie () {
  554. if [ "$(ynh_debian_release)" == "jessie" ]
  555. then
  556. return 0
  557. else
  558. return 1
  559. fi
  560. }
  561. #=================================================
  562. ynh_maintenance_mode_ON () {
  563. # Load value of $path_url and $domain from the config if their not set
  564. if [ -z $path_url ]; then
  565. path_url=$(ynh_app_setting_get $app path)
  566. fi
  567. if [ -z $domain ]; then
  568. domain=$(ynh_app_setting_get $app domain)
  569. fi
  570. # Create an html to serve as maintenance notice
  571. echo "<!DOCTYPE html>
  572. <html>
  573. <head>
  574. <meta http-equiv="refresh" content="3">
  575. <title>Your app $app is currently under maintenance!</title>
  576. <style>
  577. body {
  578. width: 70em;
  579. margin: 0 auto;
  580. }
  581. </style>
  582. </head>
  583. <body>
  584. <h1>Your app $app is currently under maintenance!</h1>
  585. <p>This app has been put under maintenance by your administrator at $(date)</p>
  586. <p>Please wait until the maintenance operation is done. This page will be reloaded as soon as your app will be back.</p>
  587. </body>
  588. </html>" > "/var/www/html/maintenance.$app.html"
  589. # Create a new nginx config file to redirect all access to the app to the maintenance notice instead.
  590. echo "# All request to the app will be redirected to ${path_url}_maintenance and fall on the maintenance notice
  591. rewrite ^${path_url}/(.*)$ ${path_url}_maintenance/? redirect;
  592. # Use another location, to not be in conflict with the original config file
  593. location ${path_url}_maintenance/ {
  594. alias /var/www/html/ ;
  595. try_files maintenance.$app.html =503;
  596. # Include SSOWAT user panel.
  597. include conf.d/yunohost_panel.conf.inc;
  598. }" > "/etc/nginx/conf.d/$domain.d/maintenance.$app.conf"
  599. # The current config file will redirect all requests to the root of the app.
  600. # To keep the full path, we can use the following rewrite rule:
  601. # rewrite ^${path_url}/(.*)$ ${path_url}_maintenance/\$1? redirect;
  602. # The difference will be in the $1 at the end, which keep the following queries.
  603. # But, if it works perfectly for a html request, there's an issue with any php files.
  604. # This files are treated as simple files, and will be downloaded by the browser.
  605. # Would be really be nice to be able to fix that issue. So that, when the page is reloaded after the maintenance, the user will be redirected to the real page he was.
  606. systemctl reload nginx
  607. }
  608. ynh_maintenance_mode_OFF () {
  609. # Load value of $path_url and $domain from the config if their not set
  610. if [ -z $path_url ]; then
  611. path_url=$(ynh_app_setting_get $app path)
  612. fi
  613. if [ -z $domain ]; then
  614. domain=$(ynh_app_setting_get $app domain)
  615. fi
  616. # Rewrite the nginx config file to redirect from ${path_url}_maintenance to the real url of the app.
  617. echo "rewrite ^${path_url}_maintenance/(.*)$ ${path_url}/\$1 redirect;" > "/etc/nginx/conf.d/$domain.d/maintenance.$app.conf"
  618. systemctl reload nginx
  619. # Sleep 4 seconds to let the browser reload the pages and redirect the user to the app.
  620. sleep 4
  621. # Then remove the temporary files used for the maintenance.
  622. rm "/var/www/html/maintenance.$app.html"
  623. rm "/etc/nginx/conf.d/$domain.d/maintenance.$app.conf"
  624. systemctl reload nginx
  625. }
  626. #=================================================
  627. # Download and check integrity of a file from app.src_file
  628. #
  629. # The file conf/app.src_file need to contains:
  630. #
  631. # FILE_URL=Address to download the file
  632. # FILE_SUM=Control sum
  633. # # (Optional) Program to check the integrity (sha256sum, md5sum...)
  634. # # default: sha256
  635. # FILE_SUM_PRG=sha256
  636. # # (Optionnal) Name of the local archive (offline setup support)
  637. # # default: Name of the downloaded file.
  638. # FILENAME=example.deb
  639. #
  640. # usage: ynh_download_file --dest_dir="/destination/directory" [--source_id=myfile]
  641. # | arg: -d, --dest_dir= - Directory where to download the file
  642. # | arg: -s, --source_id= - Name of the source file 'app.src_file' if it isn't '$app'
  643. ynh_download_file () {
  644. # Declare an array to define the options of this helper.
  645. declare -Ar args_array=( [d]=dest_dir= [s]=source_id= )
  646. local dest_dir
  647. local source_id
  648. # Manage arguments with getopts
  649. ynh_handle_getopts_args "$@"
  650. source_id=${source_id:-app} # If the argument is not given, source_id equals "$app"
  651. # Load value from configuration file (see above for a small doc about this file
  652. # format)
  653. local src_file="$YNH_CWD/../conf/${source_id}.src_file"
  654. # If the src_file doesn't exist, use the backup path instead, with a "settings" directory
  655. if [ ! -e "$src_file" ]
  656. then
  657. src_file="$YNH_CWD/../settings/conf/${source_id}.src_file"
  658. fi
  659. local file_url=$(grep 'FILE_URL=' "$src_file" | cut -d= -f2-)
  660. local file_sum=$(grep 'FILE_SUM=' "$src_file" | cut -d= -f2-)
  661. local file_sumprg=$(grep 'FILE_SUM_PRG=' "$src_file" | cut -d= -f2-)
  662. local filename=$(grep 'FILENAME=' "$src_file" | cut -d= -f2-)
  663. # Default value
  664. file_sumprg=${file_sumprg:-sha256sum}
  665. if [ "$filename" = "" ] ; then
  666. filename="$(basename "$file_url")"
  667. fi
  668. local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${filename}"
  669. if test -e "$local_src"
  670. then # Use the local source file if it is present
  671. cp $local_src $filename
  672. else # If not, download the source
  673. local out=`wget -nv -O $filename $file_url 2>&1` || ynh_print_err $out
  674. fi
  675. # Check the control sum
  676. echo "${file_sum} ${filename}" | ${file_sumprg} -c --status \
  677. || ynh_die "Corrupt file"
  678. # Create the destination directory, if it's not already.
  679. mkdir -p "$dest_dir"
  680. # Move the file to its destination
  681. mv $filename $dest_dir
  682. }
  683. #=================================================
  684. # Create a changelog for an app after an upgrade.
  685. #
  686. # The changelog is printed into the file ./changelog for the time of the upgrade.
  687. #
  688. # In order to create a changelog, ynh_app_changelog will get info from /etc/yunohost/apps/$app/status.json
  689. # In order to find the current commit use by the app.
  690. # The remote repository, and the branch.
  691. # The changelog will be only the commits since the current revision.
  692. #
  693. # Because of the need of those info, ynh_app_changelog works only
  694. # with apps that have been installed from a list.
  695. #
  696. # usage: ynh_app_changelog
  697. ynh_app_changelog () {
  698. get_value_from_settings ()
  699. {
  700. local value="$1"
  701. # Extract a value from the status.json file of an installed app.
  702. grep "$value\": \"" /etc/yunohost/apps/$app/status.json | sed "s/.*$value\": \"\([^\"]*\).*/\1/"
  703. }
  704. local current_revision="$(get_value_from_settings revision)"
  705. local repo="$(get_value_from_settings url)"
  706. local branch="$(get_value_from_settings branch)"
  707. # ynh_app_changelog works only with an app installed from a list.
  708. if [ -z "$current_revision" ] || [ -z "$repo" ] || [ -z "$branch" ]
  709. then
  710. ynh_print_warn "Unable to build the changelog..."
  711. touch changelog
  712. return 0
  713. fi
  714. # Fetch the history of the repository, without cloning it
  715. mkdir git_history
  716. (cd git_history
  717. ynh_exec_warn_less git init
  718. ynh_exec_warn_less git remote add -f origin $repo
  719. # Get the line of the current commit of the installed app in the history.
  720. local line_to_head=$(git log origin/$branch --pretty=oneline | grep --line-number "$current_revision" | cut -d':' -f1)
  721. # Cut the history before the current commit, to keep only newer commits.
  722. # Then use sed to reorganise each lines and have a nice list of commits since the last upgrade.
  723. # This list is redirected into the file changelog
  724. git log origin/$branch --pretty=oneline | head --lines=$(($line_to_head-1)) | sed 's/^\([[:alnum:]]*\)\(.*\)/*(\1) -> \2/g' > ../changelog)
  725. # Remove 'Merge pull request' commits
  726. sed -i '/Merge pull request #[[:digit:]]* from/d' changelog
  727. # As well as conflict resolving commits
  728. sed -i '/Merge branch .* into/d' changelog
  729. # Get the value of admin_mail_html
  730. admin_mail_html=$(ynh_app_setting_get $app admin_mail_html)
  731. admin_mail_html="${admin_mail_html:-0}"
  732. # If a html email is required. Apply html to the changelog.
  733. if [ "$admin_mail_html" -eq 1 ]
  734. then
  735. sed -in-place "s@\*(\([[:alnum:]]*\)) -> \(.*\)@* __URL_TAG1__\2__URL_TAG2__${repo}/commit/\1__URL_TAG3__@g" changelog
  736. fi
  737. }