161 Commits
master ... dev

Author SHA1 Message Date
ba24f970d9 downloader - Install now sonarr from archive (as the rest); Some other small fixes 2025-08-25 17:28:26 +02:00
22dddfc987 pyload-ng - new sequence 2025-08-25 17:16:17 +02:00
c30446191f Small fixes 2025-08-25 17:14:29 +02:00
345de0c05f kodi - Adapt to new debian and kodi version 2024-05-12 13:23:02 +02:00
fe0d4ca751 coturn - Fix update function name and output nothing if no update is needed 2023-03-02 14:08:20 +01:00
5e4b7fbb07 matterbridge - Add alias for compile step 2023-03-02 13:34:12 +01:00
fea095b433 sequencer - fix sqr::log output not seen in additinal pipe output 2023-03-02 13:25:29 +01:00
36ddd606c8 synapse-admin - Fix extracted dir detection for installation 2023-02-27 16:25:01 +01:00
46bd695174 backup - use cp & rm instead of mv (if target is on another file system) 2023-02-27 16:24:16 +01:00
3aa2b471d6 fhem - use all arguments as string for step exe 2023-02-23 14:02:28 +01:00
dd3d5b8f7e backup - enhanced seq budir to support custom rsync flags (default is the same) 2023-02-22 12:43:17 +01:00
9ba4335bcc python - install python version to custom prefix or altinstall 2023-02-03 10:25:05 +01:00
655beece68 coturn - configurale function called when external ip is updated 2023-01-18 12:31:52 +01:00
76f82c0c86 friendica - stop service earlier 2023-01-18 11:24:42 +01:00
f5413da537 homeassistant (core) - first version to upgrade/change venv, pip and homeassistant itself 2023-01-15 17:50:05 +01:00
9e2a9ec594 paperless-venv - Add steps to compile jbig2enc 2023-01-04 15:13:36 +01:00
76bde5c63d ejabberd - Add dependency for mysql and modernize code 2023-01-04 15:07:23 +01:00
3c22d5729f refactoring changes from sequpgrade (endReturn, ...) and some modernizations 2023-01-03 15:49:08 +01:00
215135e8aa sequpgrade - more informational function replacemend (info, warning, ...)
shorter endReturn call in many cases

Delete trailing spaces
2023-01-03 15:24:23 +01:00
b9f8ee7599 sequencer - endReturn and saveReturn can read last return value ($?)
Reset return value before calling a step function
2023-01-03 15:22:31 +01:00
58bb04c672 friendica - stop service for upgrade and add notes 2022-12-31 09:01:51 +01:00
7b4403c84e paperless-venv - Step to install document classification model (nltk) 2022-12-26 16:19:46 +01:00
95501fcf10 vim - fix comments not intending correctly 2022-12-25 17:46:07 +01:00
ce7cc69b0d nginx - fix nginx user in lograte configuration 2022-12-25 17:45:11 +01:00
6729254288 Small fixes 2022-12-22 11:54:12 +01:00
6070a188fc ldap - new step to test ldaps connection as user 2022-12-22 11:53:51 +01:00
e26611c8ad snmp - modernize code 2022-12-22 11:52:57 +01:00
4bfb47f490 matterbridge - run as dedicated user 2022-12-22 11:51:29 +01:00
5863cccc86 matrix - refactor venv- usage and directory name 2022-12-22 11:50:14 +01:00
511b6145bb certbot - fix raspberrypi os 64bit detected as Debian 2022-12-22 11:47:50 +01:00
a703d98250 pihole - new seq for pi-hole installation and more 2022-12-22 11:45:42 +01:00
09fd9c9576 sequencer - fix if run by a user without home 2022-12-22 11:41:09 +01:00
8caab25964 ufw - extend fritzbox denials 2022-12-19 22:42:55 +01:00
36f510b60a postgres - step setup to install from repository
postgres - modernize and add simple status step
2022-12-19 22:41:50 +01:00
351a712d0e nginx - fix apt preference config without newlines 2022-12-19 22:31:01 +01:00
e032c925db mysql - add status and refactor setup step 2022-12-19 22:29:36 +01:00
2e598b01c9 basics - fix echoinfoArgs 2022-12-19 22:27:41 +01:00
423d95a6b3 element-web - retain only 10 old backups
element-web - modernize implementation, backup of config.json
2022-12-19 22:26:10 +01:00
f6a06a9696 sequencer - addConf support for backslash escapes
sequencer - new api function rmold to remove oldest files in a directory
2022-12-19 22:03:03 +01:00
aad6ded99b backup - fix toolBin and correct shellcheck warnings 2022-12-19 09:21:07 +01:00
a57fda8d3f sequencer - possiblity to skip seq_config for a single step (step_xx_noconf=) 2022-12-16 15:43:03 +01:00
69212c44b6 paperless - new prefered seq for paperless using a venv 2022-12-15 22:02:48 +01:00
89c36afb0d sequencer - fix ask getopts 2022-12-15 13:40:54 +01:00
e68a394e33 sequencer - fix missing getops argument 2022-12-15 11:10:42 +01:00
b54dc5f5c1 sequpgrade - remove echoinfoArgs 2022-12-15 10:26:24 +01:00
7391de1ddd modernize multiple seqs and fix deprecated use of endCheckEmpty 2022-12-12 16:42:25 +01:00
dbb8cac539 seqTemplate - addapt do later step options changes 2022-12-12 14:49:39 +01:00
2b301b176b ufw - remove test step 2022-12-12 11:17:21 +01:00
1f431daa16 Rework step options handling 2022-12-12 11:16:26 +01:00
44ae559918 sequencer - fix getopts case strings with - 2022-12-11 08:47:36 +01:00
ba4eae5ef2 sequencer - Attempt to reduce line amount without loosing readability 2022-12-11 00:34:43 +01:00
aeef3e89cd sequencer - make more use of getopts and sort helpApi alphabetically 2022-12-10 23:36:46 +01:00
f844160d02 sequencer - output only step help with -h and use less if output is longer than one line 2022-12-10 23:12:07 +01:00
960af0bbf1 basics - small enhancement to step 13 info 2022-12-10 17:17:27 +01:00
4affa8ff8a matrix - Check for rustc as dependency
modernize implementation
2022-12-08 11:24:20 +01:00
ee340cfc8c rspamd - steps to build rspamd from source
amd64 platform not working from custom repository
2022-12-07 15:31:44 +01:00
9388cf86a8 paperless - adapt to new version (1.10.x) of paperless (new service, different location to acquire current version) 2022-12-07 14:53:56 +01:00
cff7a8e167 snmpd - fix indentation 2022-12-04 23:40:46 +01:00
f50a235dae postfixadmin - new dependency and addConf option fix 2022-12-04 23:38:59 +01:00
38f39a51f7 sequencer - fix type
mailserver - fix escaping
2022-12-04 23:38:01 +01:00
770d1dd63c librenms - updated and modernized seq 2022-12-04 10:35:45 +01:00
5279eb7032 ebackup - modernize implementation 2022-11-29 21:09:48 +01:00
22d6de9fb0 rspamd - new step to add ufw rules for web ui 2022-11-29 21:09:18 +01:00
768b6fef2b sequencer - fix possible filename with space problem 2022-11-29 21:06:47 +01:00
17a1c0d6d3 fail2ban - modernize implementation slightly 2022-11-29 13:56:49 +01:00
755dfaf150 mailserver - modernize code and add missing config example parts 2022-11-28 23:06:58 +01:00
3bf94eb781 sequencer - fix uncought error in new col_off function
sequencer - add debug and dry-run to sqr_args
2022-11-28 23:02:35 +01:00
915f8cbf3f sequencer - rework color handling, adding option to have color codes within pipes
sequencer - helpApi now uses less by default
2022-11-28 14:24:25 +01:00
661f2ff550 pixelfed - use configurable php version and install composer locally 2022-11-27 18:23:35 +01:00
849c911954 composer - new seq to install composer locally or globally 2022-11-25 23:47:39 +01:00
0224e0027a coturn - configurable domain for nslookup (fixed domain bug)
Add ufw step to allow upnp port
2022-11-23 12:19:36 +01:00
5bd33d6a59 sequencer - fix -c opening config file twice if not existent before
LOG_TIME stamp in local time
2022-11-23 12:14:51 +01:00
e464c465a7 update and simplify 2022-11-22 21:59:38 +01:00
5b558ce224 webserver - split into seqs nginx and php and enhanced functionality 2022-11-22 21:58:09 +01:00
ffa8ec12f1 ebackup - Add allow-source-mismatch option 2022-11-20 07:42:50 +01:00
4b2cef091d rspamd - Very basic installation and notes seq
librenms - fix variable name
2022-11-13 18:38:29 +01:00
4deb8d68e7 paperless - Support version 1.9.0 (new requirement for mysql) 2022-09-26 21:40:06 +02:00
020ecc806a synapse-admin - seq to install and upgrade 2022-09-25 12:04:06 +02:00
13bd1aee4f matrix - fixed version for bcrypt and cryptography to prevent rust as dependency 2022-09-20 21:42:14 +02:00
034530e747 matrix - adding dependencies to venv 2022-09-20 18:25:09 +02:00
9229a11b5c postfixadmin - fix wrong template path during upgrade 2022-09-10 00:24:45 +02:00
35588dc713 roundcube - new dependcy php-ldap for version 1.6.0 2022-09-10 00:24:07 +02:00
472694c7aa mysql - further unbound variable fixes 2022-09-10 00:23:18 +02:00
6d2af2d866 basics - new steps to install msmtp (recommended replacement for ssmtp) 2022-09-06 23:46:01 +02:00
ed6815b0d6 matrix - disable error checks for activate; add additional dependency psycopg2 2022-09-04 22:09:42 +02:00
9a1e9de15c paperless - restart command for services 2022-09-04 22:06:24 +02:00
90312466b5 paperless - additional management steps: reindex, rename 2022-08-29 23:48:19 +02:00
c5f8514819 mysql - fix unbound variable errors 2022-08-29 14:49:46 +02:00
fa38b719f3 wallabag - New sequence to manage a bare metal wallabag installation 2022-08-29 14:49:12 +02:00
ac43b0b895 paperless - add nginx sample proxy configuration 2022-08-29 14:48:37 +02:00
28fc237fbb paperless - make configurable and add step for retagging 2022-08-29 00:55:53 +02:00
f2b759c72c paperless - Heavy rework to support paperless-ngx (not configurable yet) 2022-08-28 18:16:04 +02:00
c88f94e845 sequencer - add function die() to end seq anywhere 2022-08-28 18:15:26 +02:00
54850130ae fail2ban - Adapt to new sequencer functions 2022-08-18 17:05:28 +02:00
98486714c7 kodi - Step to add ufw rules for remote, jsonrpc and cli 2022-08-16 21:35:56 +02:00
5c82177ce8 kodi - WIP changes for kodi 19 on debian bullseye 2022-08-16 17:17:33 +02:00
ec3c35483f ufw - Adapt to new sequencer 2022-08-16 17:15:30 +02:00
3130670809 raspberry - Adapt to new raspberry pi OS image compressor
Adding creation of mandatory first user
2022-08-12 18:12:17 +02:00
0a01c9dd51 rsyslog - Update global variable according to new sequencer version 2022-08-12 18:07:20 +02:00
7206694105 snmp - Fix error when php is missing 2022-08-12 18:06:18 +02:00
e289f37be2 sequencer - addconf: allow empty source and fix printf missing newline 2022-08-12 18:05:33 +02:00
b97f880b2a sequpgrade - add execute option to help 2022-08-06 18:45:35 +02:00
04880624e8 pyload - fix unbound variable error 2022-08-06 18:15:43 +02:00
6f6d50d8ca nextcloud - fix unbound variable error 2022-08-05 18:04:10 +02:00
27a55e2623 ssh - fix unbound variable error 2022-07-04 11:46:48 +02:00
8d75b261f1 seqTemplate - fix more shellcheck warnings 2022-07-01 10:49:25 +02:00
808a87a3d2 mayan-edms - get latest version online 2022-07-01 10:48:31 +02:00
37f861fa80 piwigo - fix unbound variable error and adapt to sequencer 16 2022-07-01 10:47:48 +02:00
75b27b2dd1 whoogle - install and upgrade for whoogle search 2022-07-01 10:46:56 +02:00
c50b5fd647 sequencer - fix shellcheck warnings 2022-06-29 10:35:20 +02:00
d5058d31cc seqTemplate - shellcheck 2022-06-29 10:17:57 +02:00
43d57fa7db matterbridge - Fix unbound variable errors and performed shellcheck 2022-06-29 10:17:30 +02:00
638f3e53de gitea - output cosmetics 2022-06-26 22:07:54 +02:00
22c960caa7 mayan-edms - Bump to version 4.2.5 2022-06-14 11:11:51 +02:00
1116b6082c ebackup - Adapt to new sequencer options 2022-06-14 11:10:44 +02:00
26532b3fd3 friendica - Adapt to new sequencer options 2022-06-14 11:08:50 +02:00
43e0b61d1a seqTemplate - fix return value 2022-06-11 09:45:32 +02:00
54cfcef9f1 grocy - Adapt to new sequencer options 2022-06-11 09:45:18 +02:00
ad93a5eb9c sequencer - add more options to info,warning,... output 2022-06-11 09:43:53 +02:00
63169f3153 motioneye-dev - New seq to install motioneye from dev branch using python3 2022-06-08 17:24:02 +02:00
398036d48b fhem - separate step for jabber deps 2022-06-08 17:23:18 +02:00
0da95df9f4 seqTemplate - fix unbound variable error 2022-06-08 17:18:44 +02:00
4f8c1b5388 Fix unbound variable errors 2022-06-02 16:08:07 +02:00
a6eeccb417 sequencer - fix -pl failing when there is no step 1 2022-06-02 16:03:44 +02:00
13b620a224 sequencer - updating documentation 2022-06-02 13:05:14 +02:00
9a0860bb61 Fix unbound variable errors 2022-06-01 22:49:35 +02:00
53d3748dd9 sequencer.sh - add functions to disable and enable errorcheck 2022-06-01 22:44:49 +02:00
0f428a01d9 sequencer - fix missing newline for confirm() with one character when LOG_LEVEL=0 2022-06-01 15:08:07 +02:00
d2071090bc Fix unbound variable errors 2022-06-01 14:52:44 +02:00
4554625f5f sequencer - fix show profile * if no prfile directory exists 2022-06-01 14:35:54 +02:00
e4e909c946 sequpgrade - fix some variable rename regex statements 2022-06-01 14:27:28 +02:00
2ea45fd9fd matterbridge - restart service after compilation 2022-06-01 11:15:40 +02:00
02b108ac4e README.md - update documentation according to latest changes 2022-05-30 17:23:22 +02:00
ff48af2fa6 install.sh - repair existing symlink
Possibility to clone from a custom git branch (--branch)
2022-05-30 17:08:00 +02:00
27ed63996a matrix-commander - Update executable path after last git pull 2022-05-29 23:41:15 +02:00
89c9e43979 sequencer - update help api 2022-05-29 23:01:06 +02:00
55a9243b57 Replace exitIfRunning with running 2022-05-29 22:57:58 +02:00
cd0bffbb31 Mergeing master 2022-05-29 21:40:37 +02:00
11d9fd9e22 nextcloud - add post upgrade step 2022-05-29 21:27:39 +02:00
e014397076 Fix 'info -n' 2022-05-29 21:12:51 +02:00
c6e62725da matterbridge - update go download link 2022-05-29 21:12:20 +02:00
3a4e4b640e Ignore local tests directory 2022-05-29 21:01:01 +02:00
6214493c18 Used sequpgrade.sh to upgrade existing seqs 2022-05-29 20:58:23 +02:00
10ee4198f0 Upgrade seqs from before 16 2022-05-29 20:56:49 +02:00
8586867dbb WIP revert finished messag 2022-05-29 19:18:23 +02:00
9b8bcabd4e WIP development notes 2022-05-29 18:42:15 +02:00
110585875c WIP clean old sequencer 2022-05-29 18:40:32 +02:00
f295343814 WIP sqn alias in lower case, end output if no profiles or steps are found 2022-05-29 18:38:13 +02:00
7de1f7673f WIP some more variable refactoring 2022-05-29 18:36:42 +02:00
bf32e05725 WIP change to new sequencer location 2022-05-29 18:25:19 +02:00
552927d25f support profiles and step aliases with spaces 2022-05-29 12:42:26 +02:00
51e3d774bd full step execution support (selective or continous), profile support, addConf, seq template from own file
WIP helpApi, small refactoring of globals
2022-05-28 23:54:07 +02:00
373cc8e8b6 Refactor variables names 2022-05-25 18:22:35 +02:00
8bd247759b WIP profile-, seq config and edit config support 2022-05-23 22:43:22 +02:00
b11c7d2a3f WIP added help and related functions
Some refactoring and shellcheck; TODO: template
2022-05-18 18:42:12 +02:00
a67c92555d WIP additional functions, system text editor detection, fix listSteps output
Adding sequence template
2022-05-17 14:34:27 +02:00
ea6e85a020 Adding --liststeps and --version 2022-05-11 15:14:19 +02:00
b758adc513 removed testing code 2022-05-11 00:14:41 +02:00
5454b1ff7c sequencer - Log function able to write to stderr 2022-05-10 23:52:56 +02:00
a0f596eaa2 WIP - exe(p) and output color 2022-05-04 23:01:39 +02:00
522294208e WIP rewrite with bash best practices 2022-05-04 12:14:57 +02:00
105 changed files with 7512 additions and 4450 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
seqTemplateExample.sh seqTemplateExample.sh
missingConf.log missingConf.log
*.cfg *.cfg
/tests

41
DEVELOPMENT.md Normal file
View File

@@ -0,0 +1,41 @@
# Naming convention
- [ ] Sequencer internal variables which are only used inside sequencer
* lower case
* prefix `_sqr_`
- [ ] Sequencer "global" variables which can be also used in seqs
* lower case
* prefix `sqr_`
- [ ] Sequencer provides some global seq related variables
* lower case
* prefix `seq_` or internal use `_seq_`
For variables inside seqs it is recommended to be prefixed with `sq_[SEQ SHORT]`
e.g. for nextcloud.sh
`sq_ncinstallDir="/var/www/nextcloud"`
For seq configuration variables it is recommended to prefix them with `sc_[SEQ SHORT]`
e.g. for nextcloud.cfg(.example)
`sc_ncinstallDir="/var/www/nextcloud"`
# Indentation
Sequencer.sh and all seqs use the following indentation rules
* indent style: space
* indent size : 2
# Auto indentation
Please use the seq `vim.sh setup` to:
* configure vim for auto indentation
* install vim indent script for .sh files
* install [editorconfig](https://github.com/editorconfig/editorconfig-vim)

View File

@@ -6,18 +6,18 @@ The sequence script (**seq**) containing different steps is separated from the s
## sequencer.sh ## sequencer.sh
Main sequencer script to be included at the end of a seq. Main sequencer script to be sourced at the end of a seq.
## seqs/ ## seqs/
Contains sequences (seqs) for different tools, servers or occasions. Contains sequences (seqs) for different tools, servers or occasions.
Sequencer include working on sh and bash. Sequencer working on bash.
[...] [...]
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh
see seqTemplateExample.sh (which can be generated when calling sequencer.sh directly) see seqTemplate.sh (which can be generated when calling sequencer.sh directly)
## Installation recommendation ## Installation recommendation
@@ -27,7 +27,7 @@ Run folloing commands as root:
``` ```
git clone https://winklerfamilie.eu/git/efelon/shell_sequencer.git /opt/sequencer git clone https://winklerfamilie.eu/git/efelon/shell_sequencer.git /opt/sequencer
ln -s /opt/sequencer/sequencer/sequencer.sh /usr/local/bin ln -s /opt/sequencer/sequencer.sh /usr/local/bin
ln -s /opt/sequencer/seqs /opt ln -s /opt/sequencer/seqs /opt
``` ```
or or
@@ -62,8 +62,8 @@ To make these changes active run the following commands. You don't need the last
``` ```
unalias -a unalias -a
source ~/.bashrc . ~/.bashrc
source /opt/sequencer/sqnall-completion.bash . /opt/sequencer/sqn-completion.bash
``` ```
or simply logout from the current session and login again. or simply logout from the current session and login again.

View File

@@ -1,66 +1,83 @@
#!/bin/bash #!/bin/bash
# shellcheck disable=SC1090 # dynamically sourced file # shellcheck disable=SC1090 # dynamically sourced file
SEQGITURL="https://winklerfamilie.eu/git/efelon/shell_sequencer.git" readonly sequencerGitUrl="https://winklerfamilie.eu/git/efelon/shell_sequencer.git"
DEFAULT_DIR="/opt/sequencer" defaultBranch="master"
DEFAULT_USER_SEQS="/opt/seqs" readonly defaultDir="/opt/sequencer"
SEQUENCER_DIR= readonly defaultUserSeqs="/opt/seqs"
readonly sequencerBin="/usr/local/bin/sequencer.sh"
sequencerDir=
# Get script working directory # Get script working directory
WDIR="$(cd "$(dirname -- "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)" workDir="$(cd "$(dirname -- "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)"
SEQUENCER_DIR="$1" for _ in "$@"; do
case "${1:-}" in
--)
shift && break ;;
-b|--branch) # Clone a different branch than master
shift
defaultBranch="${1:-}"
shift ;;
esac
done
# Installation directory was not set by argument -d sequencerDir="${1:-}"
if [ -z "$SEQUENCER_DIR" ]; then
[ -w "$(dirname "$DEFAULT_DIR")" ] && SEQUENCER_DIR="$DEFAULT_DIR" # Installation directory was not set by argument $1
if [ -z "${sequencerDir}" ]; then
[ -w "$(dirname -- "${defaultDir}")" ] && sequencerDir="${defaultDir}"
# Fallback to working directory # Fallback to working directory
[ -z "$SEQUENCER_DIR" ] && SEQUENCER_DIR="${WDIR}/sequencer" [ -z "${sequencerDir}" ] && sequencerDir="${workDir}/sequencer"
fi fi
# Check if already installed # Check if already installed
if [ -d "$SEQUENCER_DIR" ]; then if [ -d "${sequencerDir}" ]; then
echo " [E] Sequencer seems to be already installed at:" if [[ $(readlink -- "${sequencerBin}") != ${sequencerDir}/sequencer.sh ]] && [[ -e "${sequencerDir}/sequencer.sh" ]] ; then
echo " $SEQUENCER_DIR" echo " [i] Repairing legacy symlink"
ln -fsT "${sequencerDir}/sequencer.sh" "${sequencerBin}"
fi
echo " [e] Sequencer seems to be already installed at:"
echo " ${sequencerDir}"
exit 1 exit 1
fi fi
if [ ! -w "$(dirname "$SEQUENCER_DIR")" ]; then if [ ! -w "$(dirname -- "${sequencerDir}")" ]; then
echo " [E] Your user has no permission to write to $(dirname "$SEQUENCER_DIR")" echo " [e] Your user has no permission to write to $(dirname -- "${sequencerDir}")"
exit 2 exit 2
fi fi
# Install git if neccessary # Install git if neccessary
if ! which git >>/dev/null 2>&1; then if ! which git >>/dev/null 2>&1; then
echo " [W] Git not found and will be installed" echo " [w] Git not found and will be installed"
if ! apt update; then if ! apt update; then
echo " [W] Cannot update apt repositories" echo " [w] Cannot update apt repositories"
fi fi
if ! apt install git -y; then if ! apt install git -y; then
echo " [E] Cannot install git via apt" echo " [e] Cannot install git via apt"
exit 3 exit 3
fi fi
fi fi
# Clone sequncer to target directory # Clone sequncer to target directory
if ! git clone $SEQGITURL "$SEQUENCER_DIR"; then if ! git clone --branch "${defaultBranch}" "${sequencerGitUrl}" "$sequencerDir"; then
echo " [E] Error cloning git repository:" echo " [e] Error cloning git repository:"
echo " $SEQGITURL" echo " ${sequencerGitUrl}"
exit 4 exit 4
fi fi
# If available use configuration # If available use configuration
. "${SEQUENCER_DIR}/sequencer.cfg" >/dev/null 2>&1 . "${sequencerDir}/sequencer.cfg" >/dev/null 2>&1
# Set to default if not configured # Set to default if not configured
[ -z "$SEQUENCER_USER_SEQS" ] && SEQUENCER_USER_SEQS="$DEFAULT_USER_SEQS" [ -z "${SEQUENCER_USER_SEQS}" ] && SEQUENCER_USER_SEQS="${defaultUserSeqs}"
# Install sequncer script # Install sequncer script
ln -s "${SEQUENCER_DIR}/sequencer/sequencer.sh" "/usr/local/bin" ln -s "${sequencerDir}/sequencer.sh" "/usr/local/bin"
if [ "$SEQUENCER_USER_SEQS" != "$SEQUENCER_DIR/seqs" ]; then if [ "${SEQUENCER_USER_SEQS}" != "${sequencerDir}/seqs" ]; then
ln -sT "${SEQUENCER_DIR}/seqs" "${SEQUENCER_USER_SEQS}" ln -sT "${sequencerDir}/seqs" "${SEQUENCER_USER_SEQS}"
fi fi
echo " [I] Successfully installed shell sequencer" echo " [i] Successfully installed shell sequencer"
echo " to: $SEQUENCER_DIR" echo " to: ${sequencerDir}"

View File

@@ -1,21 +1,21 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Get script working directory # Get script working directory
sq_dir="$(cd "$(dirname -- "$(realpath "${BASH_SOURCE[0]}")")" >>/dev/null 2>&1 && pwd)" sq_dir="$(cd "$(dirname -- "$(readlink -f -- "${BASH_SOURCE[0]}")")" >>/dev/null 2>&1 && pwd)"
_sequencerCompletion() { _sequencerCompletion() {
local SEQCOMP_LOC="${sq_dir}/sqn-completion.bash" local seqcomp_loc="${sq_dir}/sqn-completion.bash"
local SEQCOMP_LOADER="$HOME/.bashrc" local seqcomp_loader="$HOME/.bashrc"
local SEQCOMP_SOURCE=". \"$SEQCOMP_LOC\"" local seqcomp_source=". \"${seqcomp_loc}\""
if grep "$SEQCOMP_SOURCE" "$SEQCOMP_LOADER" >>/dev/null 2>&1; then if grep "${seqcomp_source}" "${seqcomp_loader}" >>/dev/null 2>&1; then
echo " [I] Completion already installed ($SEQCOMP_LOADER)" echo " [i] Completion already installed (${seqcomp_loader})"
else else
echo "$SEQCOMP_SOURCE" >>"$SEQCOMP_LOADER" echo "${seqcomp_source}" >>"${seqcomp_loader}"
echo " [I] Sequence bash-completion installed" echo " [i] Sequence bash-completion installed"
fi fi
# shellcheck source=sqn-completion.bash # shellcheck source=sqn-completion.bash
. "$SEQCOMP_LOC" . "${seqcomp_loc}"
} }
_sequencerCompletion _sequencerCompletion

54
seqTemplate.sh Executable file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/env bash
readonly toolName=mytool
# Already defined by sequencer.sh, but may be overwritten
#readonly seq_configName="${sq_scriptName:?}.cfg"
#readonly seq_configTemplate="${seq_origin:?}/${sq_configName:?}.example"
sq_aptOpt=
sq_config=0
seq_config() {
## Called once before executing steps.
## e.g. to source a config file manually:
#. "${seq_origin:?}/${seq_configName:?}"
## or to use sequencer api with profile config file support:
#if initSeqConfig -p "${seq_fileName:?}" "${seq_configTemplate:?}" ; then
## or to use sequencer api with global config file:
#if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
# sq_config=1
#else
# # End if no configuration file exists
# dry || return 1
#fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "My custom step"; }
step_1_options() { echo "[OPTIONS]"; }
step_1_alias() { echo "begin"; }
step_1() {
info "Doing something for step ${1:-} ..."
warning "Command line arguments starting with argument 2: $*"
# Use exe for regular command
# Use exep "command" for commands containing pipes or redirects
exe ls
exep "dmesg | head"
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -6,7 +6,7 @@ toolUser=aria2
# Get script working directory # Get script working directory
# (when called from a different directory) # (when called from a different directory)
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)" WDIR="$(cd "$(dirname -- "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)"
CONFIG=0 CONFIG=0
SCRIPT_NAME=$(basename -- $0) SCRIPT_NAME=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_NAME%%.*} SCRIPT_NAME=${SCRIPT_NAME%%.*}
@@ -15,7 +15,7 @@ CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
aptOpt= aptOpt=
step_config() { seq_config() {
#echo "Called once before executing steps." #echo "Called once before executing steps."
## e.g. to source a config file manually: ## e.g. to source a config file manually:
#. "$CONFIG_FILE" #. "$CONFIG_FILE"
@@ -27,14 +27,14 @@ step_config() {
CONFIG=1 CONFIG=1
else else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return 1 dry || return 1
fi fi
[ $QUIET -ne 0 ] && aptOpt="-y" quiet && aptOpt="-y"
return 0 return 0
} }
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install $toolDeps $aptOpt exe apt install $toolDeps $aptOpt
@@ -54,11 +54,11 @@ ariaConfLoc="/etc/aria2/aria2.conf"
step_3_info() { echo "Create $toolName service"; } step_3_info() { echo "Create $toolName service"; }
step_3_alias() { ALIAS="service"; } step_3_alias() { echo "service"; }
step_3() { step_3() {
addConf -s "$ariaService" "$ariaServiceLoc" addConf -s "$ariaService" "$ariaServiceLoc"
exe systemctl daemon-reload exe systemctl daemon-reload
echoseq " [I] Serive not started or enabled" info "Service not started or enabled"
} }
ariaServiceLoc="/etc/systemd/system/aria2.service" ariaServiceLoc="/etc/systemd/system/aria2.service"
ariaService="[Unit] ariaService="[Unit]
@@ -76,10 +76,11 @@ Restart=on-failure
WantedBy=multi-user.target" WantedBy=multi-user.target"
step_10_info() { echo "Add ufw rule for rpc port 6800"; } step_10_info() { echo "Add ufw rule for rpc port 6800"; }
step_10_alias() { ALIAS="ufw"; } step_10_alias() { echo "ufw"; }
step_10() { step_10() {
exe ufw allow in on eth0 to any port 6800 proto tcp comment "Aria2 rpc" exe ufw allow in on eth0 to any port 6800 proto tcp comment "Aria2 rpc"
} }
VERSION_SEQREV=12 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,42 +1,37 @@
#!/bin/bash #!/bin/bash
toolName=backup # shellcheck disable=SC2001 # See if you can use ${variable//search/replace} instead.
toolBin=rsync # It is more easy with sed to remove multiple trailing /
# Get script working directory sq_toolBin=rsync
# (when called from a different directory) sq_aptOpt=
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )" sq_config=0
APTOPT=
CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
initSeqConfig -t "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if initSeqConfig -t "${seq_configName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then sq_config=1
CONFIG=1
else else
echoerr " [E] Check output for errors" error -e "Check output for errors"
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return -1 dry || return 1
fi fi
[ $QUIET -ne 0 ] && APTOPT="-y" interactive || sq_aptOpt="-y"
return 0 return 0
} }
step_1_info() { step_1_info() {
echoinfoArgs "[ADDITIONAL_EXCLUDES...]"
echo "Backup root" echo "Backup root"
echoinfo "Essential excludes are provided in the configuration template." echoinfo "Essential excludes are provided in the configuration template."
echoinfo "($CONFIG_FILE_TEMPLATE)" echoinfo "(${seq_configTemplate})"
} }
step_1_alias() { ALIAS="buroot"; } step_1_options() { echo "[ADDITIONAL_EXCLUDES...]"; }
step_1_alias() { echo "buroot"; }
step_1() { step_1() {
local buTarget="/backup" local buTarget="/backup"
if [ $CONFIG -eq 0 ] ; then if (( ! sq_config )) ; then
echoerr " [E] Cannot backup root without properly configured excludes" error -e "Cannot backup root without properly configured excludes"
echoerr " (expected config: $SEQ_CONFIG_HOME/$CONFIG_FILE_NAME)" error -e " (expected config: ${seq_configFile:?})"
else else
buTarget="$BACKUP_TARGET" buTarget="$BACKUP_TARGET"
fi fi
@@ -49,91 +44,113 @@ step_1() {
step_3_info() { step_3_info() {
# Backup single directory recursively # Backup single directory recursively
local opt="[OPTION]" local opt=()
local dir="<DIRECTORY>" local dir='<SOURCE>'
local tar="<TARGET>" local tar='[TARGET]'
local exc="[EXCLUDES...]" local tarOpt=0
local exc=()
shift shift
if [ "$1" == "-t" ] ; then while [[ "${1:-}" =~ ^- ]] ; do
opt=" -t " case "${1}" in
tar= --)
shift shift && break;;
fi -f)
if [ ! -z "$1" ] ; then opt+=("${1:-}" "'${2:-}'")
shift 2;;
-t)
tarOpt=1
shift;;
-*)
opt+=("${1}")
shift ;;
esac
done
if [ -n "${1:-}" ] ; then
dir="$1" dir="$1"
shift shift
if [ ! -z $tar ] && [ ! -z "$1" ] ; then if (( tarOpt )) ; then
tar="$1"
shift
else
tar="$BACKUP_TARGET" tar="$BACKUP_TARGET"
fi
if [ ! -z "$1" ] ; then
exc="$@"
else else
exc="[NO EXCLUDES]" tar="${1:-}"
shift
fi fi
for arg in "$@" ; do
exc+=("'$arg'")
done
(( ${#exc[@]} )) || exc=("[NO EXCLUDES]")
fi fi
echo "Backup $opt $dir $tar $exc" echo "Backup ${opt[*]} '$dir' '$tar' ${exc[*]}"
echoinfo " -f : Replace default flags (can be used multiple times)"
echoinfo " (default: ${sq_rsyncFlags[*]})"
echoinfo " -n : No remount to rw"
echoinfo " -t : Using configuration value as TARGET" echoinfo " -t : Using configuration value as TARGET"
echoinfo " <DIRECTORY> [EXCLUDES...]" echoinfo " <DIRECTORY> [EXCLUDES...]"
echoinfo "EXCLUDES path notation starts within $dir" echoinfo "EXCLUDES path notation starts within $dir"
echoinfo "e.g. to exclude $dir/a:" echoinfo " e.g. to exclude $dir/a:"
echoinfo " $0 budir $dir $tar /a" echoinfo " $0 budir $dir $tar /a"
} }
step_3_alias() { ALIAS="budir"; } sq_rsyncFlags=("-avxHAX" "--delete")
step_3_options() { echo "[OPTION] <DIRECTORY> [TARGET] [EXCLUDES...]"; }
step_3_alias() { echo "budir"; }
step_3() { step_3() {
local arg
local configTarget=0 local configTarget=0
local noRemount=0 local remount=1
local buSource= local buSource=
local buTarget= local buTarget=
local buExcludes= local buExcludes=
local buLog= local buLog=
local customFlags=()
# don't use step number # don't use step number
shift shift
for arg in "$@"; do for _ in "$@"; do
case "$1" in case "$1" in
--)
shift && break;;
-t) -t)
configTarget=1 configTarget=1
shift;; shift;;
-n) -n)
noRemount=1 remount=0
shift;;
-f)
shift
customFlags+=("${1:-}")
shift;; shift;;
esac esac
done done
if [ -z "$1" ] ; then (( "${#customFlags[@]}" )) || customFlags=("${sq_rsyncFlags[@]}")
echoerr " [E] Nothing found to backup $1" if [ -z "${1:-}" ] ; then
error -e "Nothing found to backup $1"
exit 1 exit 1
fi fi
buLog=$(basename $1) buLog="$(basename -- "$1")"
if [ "$buLog" == "/" ] ; then if [ "$buLog" == "/" ] ; then
buLog="root" buLog="root"
buSource="$1" buSource="$1"
else else
# remove trailing slashes # remove trailing slashes
buSource=$(echo "$1" | sed 's:/*$::') buSource="$(echo "$1" | sed 's:/*$::')"
fi fi
buLog="backup_${buLog}" buLog="backup_${buLog}"
shift shift
if [ $configTarget -ne 0 ] && [ $CONFIG -ne 0 ] ; then if (( configTarget )) && (( sq_config )) ; then
# Taking target from config # Taking target from config
buTarget=$(echo "$BACKUP_TARGET" | sed 's:/*$::') buTarget="$(echo "$BACKUP_TARGET" | sed 's:/*$::')"
else else
if [ -z "$1" ] ; then if [ -z "$1" ] ; then
echoerr " [E] No valid target found" error -e "No valid target found"
exit 1 exit 1
fi fi
buTarget=$(echo "$1" | sed 's:/*$::') buTarget="$(echo "$1" | sed 's:/*$::')"
shift shift
fi fi
if [ ! -d "${buTarget}" ] && [ ! -L "${buTarget}" ] if [ ! -d "${buTarget}" ] && [ ! -L "${buTarget}" ]
then then
echoerr " [E] Backup target (${buTarget}) doesn't exist" error -e "Backup target (${buTarget}) doesn't exist"
exit 1 exit 1
fi fi
@@ -141,53 +158,59 @@ step_3() {
buExcludes+=("--exclude='$exclu'") buExcludes+=("--exclude='$exclu'")
done done
echoseq " [I] Source : $buSource" info "Source : $buSource"
echoseq " [I] Target : $buTarget" info "Target : $buTarget"
echoseq " [I] Excludes: $@" info "Excludes: $*"
#fix doubling trailing slash on verbose output when backing up root #fix doubling trailing slash on verbose output when backing up root
local tmpSource="$buSource/" local tmpSource="$buSource/"
local tmpTarget="${buTarget}/$(basename ${buSource})" local tmpTarget=
tmpTarget="${buTarget}/$(basename -- "${buSource}")"
if [ "$buSource" == "/" ] ; then if [ "$buSource" == "/" ] ; then
tmpSource="/" tmpSource="/"
tmpTarget="${buTarget}/" tmpTarget="${buTarget}/"
fi fi
if [ $noRemount -eq 0 ]; then if (( remount )) ; then
# remount target to be writable # remount target to be writable
exep "mount -o rw,remount '${buTarget}' >>/dev/null 2>&1" exep "mount -o rw,remount '${buTarget}' >>/dev/null 2>&1"
endReturn -o $? "Remount (${buTarget}) to be writable failed" endReturn "Remount (${buTarget}) to be writable failed"
fi fi
if [ ! -w "${buTarget}" ] ; then if [ ! -w "${buTarget}" ] ; then
echoerr " [E] Backup target (${buTarget}) is not writable" error -e "Backup target (${buTarget}) is not writable"
exit 1 exit 1
fi fi
checkInstalled checkInstalled
exep "mv -f ${buTarget}/${buLog}0.log /tmp/${buLog}1.log 2>/dev/null" exep "mv -f '${buTarget}/${buLog}0.log' '/tmp/${buLog}1.log' 2>/dev/null"
exep "$toolBin -avxHAX --delete --info=stats2 ${buExcludes[*]} ${tmpSource} ${tmpTarget} > /tmp/${buLog}0.log" exep "'${sq_toolBin}' ${customFlags[*]} --info=stats2 ${buExcludes[*]} '${tmpSource}' '${tmpTarget}' > '/tmp/${buLog}0.log'"
exe mv -f /tmp/${buLog}*.log ${buTarget} # mv is not the right tool moving files to a different file system
exe cp /tmp/"${buLog}"*.log "${buTarget}"
exe rm -rf /tmp/"${buLog}"*.log
exe sync exe sync
if (( remount )) ; then
exep "mount -o ro,remount '${buTarget}' >>/dev/null 2>&1" exep "mount -o ro,remount '${buTarget}' >>/dev/null 2>&1"
fi
} }
step_100_info() { echo "Install $toolBin"; } step_100_info() { echo "Install ${sq_toolBin}"; }
step_100_alias() { ALIAS="install"; } step_100_alias() { echo "install"; }
step_100() { step_100() {
exe apt update exe apt update
exe apt install $toolBin $APTOPT exe apt install ${sq_toolBin} ${sq_aptOpt}
} }
checkInstalled() { checkInstalled() {
command -v $toolBin >>/dev/null if ! command -v ${sq_toolBin} >>/dev/null ; then
if [ $? -ne 0 ] ; then
step install step install
fi fi
toolBin="$(command -v $toolBin)" sq_toolBin="$(command -v ${sq_toolBin})"
} }
VERSION_SEQREV=14 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -3,66 +3,67 @@
# Collection of simple setup tasks # Collection of simple setup tasks
# e.g. Ability to send mail (ssmtp) # e.g. Ability to send mail (ssmtp)
# Get script working directory sc_configLoc="./basics"
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
WSUBDIR="${WDIR}/basics"
#step_config() { seq_config() {
# echo "Called once before executing steps." # echo "Called once before executing steps."
# echo "e.g. to source a config file:" # echo "e.g. to source a config file:"
# #. "$CONFIG_FILE" # #. "$CONFIG_FILE"
#} sc_configLoc="${seq_origin}/basics"
}
step_10_info() { echo "ssmtp installation"; } step_10_info() { echo "ssmtp installation"; }
step_10_alias() { ALIAS="ssmtp"; } step_10_alias() { echo "ssmtp"; }
step_10() { step_10() {
exe apt update && apt install "$SSMTP_DEPS" exe apt update && apt install $SSMTP_DEPS
endReturn -o $? "ssmtp installation failed" endReturn "ssmtp installation failed"
} }
SSMTP_DEPS="ssmtp" SSMTP_DEPS="ssmtp"
step_11_info() { echo "ssmtp setup"; } step_11_info() { echo "ssmtp setup"; }
step_11_alias() { ALIAS="ssmtpSetup"; } step_11_alias() { echo "ssmtpSetup"; }
step_11() { step_11() {
if [ ! -f "$CONFIG_FILE_SSMTP" ] ; then if [ ! -f "$CONFIG_FILE_SSMTP" ] ; then
echoerr " [E] User config ($CONFIG_FILE_SSMTP) not found" error -e "User config ($CONFIG_FILE_SSMTP) not found"
echoerr " See $CONFIG_FILE_SSMTP_TEMPLATE" error -e " See $CONFIG_FILE_SSMTP_TEMPLATE"
return 1 return 1
fi fi
addConf -c -f "$CONFIG_FILE_SSMTP" "$CONFIG_LOC_SSMTP" addConf -c -f "$CONFIG_FILE_SSMTP" "$CONFIG_LOC_SSMTP"
endReturn -o $? "Could not write ssmtp configuration" endReturn "Could not write ssmtp configuration"
if [ ! -f "$CONFIG_FILE_SSMTP_AL" ] ; then if [ ! -f "$CONFIG_FILE_SSMTP_AL" ] ; then
echoerr " [W] User aliases ($CONFIG_FILE_SSMTP_AL) not found" warning -e "User aliases ($CONFIG_FILE_SSMTP_AL) not found"
echoerr " See $CONFIG_FILE_SSMTP_TEMPLATE or modify $CONFIG_LOC_SSMTP_AL directly" error -e " See $CONFIG_FILE_SSMTP_TEMPLATE or modify $CONFIG_LOC_SSMTP_AL directly"
return 1 return 1
fi fi
addConf -c -f "$CONFIG_FILE_SSMTP_AL" "$CONFIG_LOC_SSMTP_AL" addConf -c -f "$CONFIG_FILE_SSMTP_AL" "$CONFIG_LOC_SSMTP_AL"
endReturn -o $? "Could not write ssmtp aliases" endReturn "Could not write ssmtp aliases"
} }
CONFIG_LOC_SSMTP="/etc/ssmtp/ssmtp.conf" CONFIG_LOC_SSMTP="/etc/ssmtp/ssmtp.conf"
CONFIG_LOC_SSMTP_AL="/etc/ssmtp/revaliases" CONFIG_LOC_SSMTP_AL="/etc/ssmtp/revaliases"
CONFIG_FILE_SSMTP="$WSUBDIR/ssmtp.cfg" CONFIG_FILE_SSMTP="$sc_configLoc/ssmtp.cfg"
CONFIG_FILE_SSMTP_TEMPLATE="${CONFIG_FILE_SSMTP}.example" CONFIG_FILE_SSMTP_TEMPLATE="${CONFIG_FILE_SSMTP}.example"
CONFIG_FILE_SSMTP_AL="$WSUBDIR/revaliases.cfg" CONFIG_FILE_SSMTP_AL="$sc_configLoc/revaliases.cfg"
CONFIG_FILE_SSMTP_AL_TEMPLATE="${CONFIG_FILE_SSMTP}.example" CONFIG_FILE_SSMTP_AL_TEMPLATE="${CONFIG_FILE_SSMTP}.example"
step_13_info() { step_13_info() {
echo -n "Send test E-Mail to " echo -n "Send test E-Mail"
if [ -z $2 ] ; then echo "<MAILADDRESS>"; else echo "$2"; fi if [ -z "${2:-}" ] ; then
} echo " to MAILADDRESS"
step_13_alias() { ALIAS="ssmtpTest"; } else
step_13() { echo " to ${2}"
if [ ! -z "$2" ] || [ "$2" == "" ] ; then
echoerr " [E] No mailaddress provided"
fi fi
}
step_13_options() { echo "<MAILADDRESS>"; }
step_13_alias() { echo "smtpTest"; }
step_13() {
[[ -z "${2:-}" ]] && fatal -e "No mailaddress provided"
exep "echo \"Subject: sendmail test\" | sendmail -v $2" exep echo "Subject: sendmail test" \| sendmail -v "$2"
} }
step_15_info() { echo "ssmtp help"; } step_15_info() { echo "ssmtp help"; }
step_15_alias() { ALIAS="ssmtpHelp"; } step_15_alias() { echo "ssmtpHelp"; }
step_15() { step_15() {
echo " Configuration files expected by this seq:" echo " Configuration files expected by this seq:"
echo echo
@@ -77,5 +78,53 @@ step_15() {
echo " - $CONFIG_LOC_SSMTP_AL" echo " - $CONFIG_LOC_SSMTP_AL"
} }
VERSION_SEQREV=9 step_30_info() { echo "msmtp setup"; }
step_30_alias() { echo "msmtp"; }
step_30() {
exe apt update
exe apt install ${sq_msmtpDeps:?}
}
sq_msmtpDeps="msmtp msmtp-mta"
step_31_info() { echo "Init config"; }
step_31() {
if addConf -c "${sc_msmtpConfig}" "${sc_msmtpConfigLoc}" ; then
if confirm "Edit this file now?" "n" ; then
editor "${sc_msmtpConfigLoc}"
fi
else
fatal "Couldn't create msmtp system configuration file ${sc_msmtpConfigLoc}"
fi
}
sc_msmtpConfigLoc="/etc/msmtprc"
sc_msmtpConfig="# Example for a system wide configuration file
# A system wide configuration file is optional.
# If it exists, it usually defines a default account.
# This allows msmtp to be used like /usr/sbin/sendmail.
account default
# The SMTP smarthost (use FQDN from certificate if possible)
host mail
# Use TLS on port 465
port 25
tls on
tls_starttls on
# Usually not need on debian systems
#tls_trust_file /etc/ssl/certs/ca-certificates.crt
# Construct envelope-from addresses of the form \"user@oursite.example\"
#auto_from on
#maildomain oursite.example
# or set a static from address
#from noreply@yourdomain.com
# Syslog logging with facility LOG_MAIL instead of the default LOG_USER
syslog LOG_MAIL"
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -15,25 +15,25 @@ SCRIPT_NAME=${SCRIPT_FILE%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg" CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
## or to use sequencer api with global config file: ## or to use sequencer api with global config file:
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
CONFIG=1 CONFIG=1
else else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return -1 dry || return -1
fi fi
## Apt cmdline option to suppress user interaction ## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y" quiet && APTOPT="-y"
## Return of non zero value will abort the sequence ## Return of non zero value will abort the sequence
return 0 return 0
} }
step_1_info() { echo "Install dependencies"; } step_1_info() { echo "Install dependencies"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt install $toolDeps $APTOPT exe apt install $toolDeps $APTOPT
} }
@@ -44,14 +44,14 @@ step_2() {
exe adduser --disabled-password --disabled-login --home-dir "$CALWEB_USER_HOME" --gecos "" $CALWEB_USER exe adduser --disabled-password --disabled-login --home-dir "$CALWEB_USER_HOME" --gecos "" $CALWEB_USER
exe usermod -aG users $CALWEB_USER exe usermod -aG users $CALWEB_USER
else else
echoseq " [W] User $CALWEB_USER already exists" warning "User $CALWEB_USER already exists"
fi fi
if [ ! -e "$CALWEB_VENV_ROOT/bin" ]; then if [ ! -e "$CALWEB_VENV_ROOT/bin" ]; then
exe python3 -m venv "$CALWEB_VENV_ROOT" exe python3 -m venv "$CALWEB_VENV_ROOT"
endReturn -o $? "Creating virtual environment failed" endReturn "Creating virtual environment failed"
exe chown -R ${CALWEB_USER}: "$CALWEB_BASE" exe chown -R ${CALWEB_USER}: "$CALWEB_BASE"
else else
echoseq " [W] Virtual env. $CALWEB_VENV_ROOT already exists" warning "Virtual env. $CALWEB_VENV_ROOT already exists"
fi fi
} }
@@ -70,6 +70,8 @@ step_4() {
toolFeatures[$i]="$toolPipName[${toolFeatures[$i]}]" toolFeatures[$i]="$toolPipName[${toolFeatures[$i]}]"
done done
exe ${CALWEB_VENV_ROOT}/bin/pip install "${toolFeatures[@]}" exe ${CALWEB_VENV_ROOT}/bin/pip install "${toolFeatures[@]}"
# Needed for in-app update
exe chown -R "${CALWEB_USER}": "${CALWEB_VENV_ROOT}/lib/python*/site-packages/calibreweb"
} }
step_5_info() { echo "Install systemd service"; } step_5_info() { echo "Install systemd service"; }
@@ -86,16 +88,16 @@ step_6() {
} }
step_15_info() { echo "Upgrade python pip"; } step_15_info() { echo "Upgrade python pip"; }
step_15_alias() { ALIAS="upgradepip"; } step_15_alias() { echo "upgradepip"; }
step_15() step_15()
{ {
exe ${CALWEB_VENV_ROOT}/bin/pip install --upgrade pip exe ${CALWEB_VENV_ROOT}/bin/pip install --upgrade pip
} }
step_100_info() { echo "Setup notes"; } step_100_info() { echo "Setup notes"; }
step_100_alias() { ALIAS="notes"; } step_100_alias() { echo "notes"; }
step_100() { step_100() {
outColor green color green
cat <<NOTES_END cat <<NOTES_END
# Default admin login: # Default admin login:
@@ -127,5 +129,5 @@ proxy_set_header X-Script-Name /calibre; # IMPORTANT: path has NO trai
NOTES_END NOTES_END
} }
VERSION_SEQREV=15 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -3,31 +3,30 @@
# Certbot installation and creation supporting Raspbian and Ubuntu. # Certbot installation and creation supporting Raspbian and Ubuntu.
# Certificate can be created/updated as "certonly" only. # Certificate can be created/updated as "certonly" only.
toolName=certbot readonly toolName=certbot
# Get script working directory sq_aptOpt=
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
local confReturn=$? # End if no configuration file exists
if [ $confReturn -eq 0 ] ; then dry || return 1
CONFIG=1
fi fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
return 0
} }
step_1_info() { echo "Install $toolName for letsencrypt"; } step_1_info() { echo "Install $toolName for letsencrypt"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local osName= local osName=
local distName= local distName=
if [ "$(which lsb_release)" == "" ] ; then if [ "$(which lsb_release)" == "" ] ; then
echoerr " [W] Cannot detect OS. Assuming Ubuntu" warning -e "Cannot detect OS. Assuming Ubuntu"
osName="Ubuntu" osName="Ubuntu"
else else
osName=$(lsb_release -is) osName=$(lsb_release -is)
@@ -35,33 +34,27 @@ step_1() {
fi fi
if [ "$osName" == "" ] ; then if [ "$osName" == "" ] ; then
echoerr " [W] Error dedecting OS. Assuming Ubuntu" warning -e "Error dedecting OS. Assuming Ubuntu"
osName="Ubuntu" osName="Ubuntu"
fi fi
echo " [I] Detected OS: $osName $distName" info "Detected OS: $osName $distName"
local aptOption=
if [ $QUIET -ne 0 ] ; then
aptOption="-y"
else
aptOption=""
fi
if [ "$osName" == "Ubuntu" ] ; then if [ "$osName" == "Ubuntu" ] ; then
exe apt-get update exe apt-get update
exe apt-get install software-properties-common $aptOption exe apt-get install software-properties-common ${sq_aptOpt}
saveReturn $? saveReturn $?
exe add-apt-repository universe $aptOption exe add-apt-repository universe ${sq_aptOpt}
saveReturn $? saveReturn $?
exe add-apt-repository ppa:certbot/certbot $aptOption exe add-apt-repository ppa:certbot/certbot ${sq_aptOpt}
saveReturn $? saveReturn $?
exe apt-get update exe apt-get update
exe apt-get install $toolName $aptOption exe apt-get install $toolName ${sq_aptOpt}
saveReturn $? saveReturn $?
endReturn "$toolName installation for $osName failed" endReturn "$toolName installation for $osName failed"
elif [ "$osName" == "Raspbian" ] ; then elif [ "$osName" == "Raspbian" ] || [ "${osName}" == "Debian" ] ; then
info "Install ${toolName} from OS repository"
exe apt update exe apt update
exe apt install certbot exe apt install certbot
endReturn "$toolName installation for $osName failed" endReturn "$toolName installation for $osName failed"
@@ -69,15 +62,23 @@ step_1() {
} }
step_2_info() { echo "Create or update letsencrypt certificate"; } step_2_info() { echo "Create or update letsencrypt certificate"; }
step_2_alias() { ALIAS="update"; } step_2_alias() { echo "update"; }
step_2() { step_2() {
endCheckEmpty CERTBOT_DOMAINS "No domain list found. Check configuration" endIfEmpty CERTBOT_DOMAINS "No domain list found. Check configuration"
endCheckEmpty CERTBOT_WEBROOT "Invalid web root. Check configuration" endIfEmpty CERTBOT_WEBROOT "Invalid web root. Check configuration"
endCheckEmpty CERTBOT_MAIL "Invalid mail address. Check configuration" endIfEmpty CERTBOT_MAIL "Invalid mail address. Check configuration"
exe certbot certonly --webroot -w "$CERTBOT_WEBROOT" --rsa-key-size 4096 --expand --agree-tos \ exe certbot certonly --webroot -w "$CERTBOT_WEBROOT" --rsa-key-size 4096 --expand --agree-tos \
-m "$CERTBOT_MAIL" ${CERTBOT_DOMAINS[@]/#/-d } -m "$CERTBOT_MAIL" ${CERTBOT_DOMAINS[@]/#/-d }
} }
VERSION_SEQREV=11 step_10_info() { echo 'Print certificate information'; }
step_10_alias() { echo 'info'; }
step_10() {
exe openssl x509 -text -noout -in "/etc/letsencrypt/live/${CERTBOT_DOMAINS[0]}/cert.pem"
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

122
seqs/composer.sh Executable file
View File

@@ -0,0 +1,122 @@
#!/usr/bin/env bash
readonly toolName=composer
# Already defined by sequencer.sh, but may be overwritten
#readonly seq_configName="${sq_scriptName:?}.cfg"
#readonly seq_configTemplate="${seq_origin:?}/${sq_configName:?}.example"
sq_aptOpt=
sq_config=0
sq_composerBin=
seq_config() {
# Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
# Disable error checks if external scripts are used
# e.g. error on unbound variables
#disableErrorCheck
# Return of non zero value will abort the sequence
return 0
}
getComposer() {
local lLocalOnly=0
local lGlobalOnly=0
case "${1:-}" in
-l) lLocalOnly=1 ;;
-g) lGlobalOnly=1 ;;
esac
if [[ -n "${sq_composerBin:-}" ]] && [[ -z "${1:-}" ]] ; then
return 0
fi
local lComp=
if (( ! lGlobalOnly )) ; then
lComp="$(ls composer 2>>/dev/null)"
lComp="${lComp:-"$(ls composer.phar 2>>/dev/null)"}"
fi
if (( ! lLocalOnly )) ; then
lComp="${lComp:-"$(ls /usr/local/bin/composer 2>>/dev/null)"}"
fi
[[ -z "${lComp:-}" ]] && return 1
sq_composerBin="$(readlink -f -- "${lComp}")"
return 0
}
step_1_info() { echo "Determine status of ${toolName} in current directory or globally"; }
step_1_alias() { echo "status"; }
step_1() {
local lDir="$(pwd)"
local lComp
getComposer || die "No composer installed"
info "Composer found: ${sq_composerBin}"
info -a "$(COMPOSER_ALLOW_SUPERUSER=1 "${sq_composerBin}" --version)"
info "Available php versions:"
info -a "$(update-alternatives --list php)"
}
step_10_info() {
echo "Install ${toolName}"
echoinfo " [OPTIONS]"
echoinfo " -l: (default) install composer.phar to the current directory"
echoinfo " -g: install composer globally to /usr/local/bin"
echoinfo " [VERSION]"
echoinfo " Install this specific ${toolName} version"
}
step_10_options() { echo "[OPTIONS] [VERSION]"; }
step_10_alias() { echo "install"; }
step_10() {
shift
local lLocal=1
local lArgs=()
for _ in "${@}" ; do
case "${1:-}" in
-l) shift ;;
-g)
lLocal=0
lArgs+=(--install-dir="/usr/local/bin")
lArgs+=(--filename="composer")
shift ;;
--) shift && break ;;
-*) die "Unkown option ${1}" ;;
esac
done
local getArg="-l"
(( ! lLocal )) && getArg="-g"
getComposer ${getArg} && die "Composer already installed: ${sq_composerBin}"
[[ -n "${1:-}" ]] && lArgs+=(--version="${1}")
interactive || lArgs+=(--quiet)
info "Installing ${toolName}"
local checksum_expected="$(wget -q -O - https://composer.github.io/installer.sig)"
exe wget -O 'composer-setup.php' 'https://getcomposer.org/installer'
local checksum=($(sha384sum 'composer-setup.php'))
if [ "${checksum_expected}" != "${checksum}" ]
then
error -e 'Invalid installer checksum'
error -a "Sum: ${checksum}"
error -a "Exp: ${checksum_expected}"
exe rm composer-setup.php
return 1
fi
exe php composer-setup.php "${lArgs[@]}"
saveReturn $?
exe rm composer-setup.php
endReturn "Composer setup failed"
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

7
seqs/coturn.cfg.example Normal file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
sc_turnDomain="mydomain.com"
# sf_ipUpdate <NEW IP>
# Called when a new external IP is detected
sf_updateIp() { :; }

View File

@@ -1,44 +1,30 @@
#!/bin/bash #!/bin/bash
toolName=coturn readonly toolName="coturn"
toolDeps="coturn miniupnpc" readonly toolDeps="coturn miniupnpc"
toolConf="/etc/turnserver.conf" readonly toolConf="/etc/turnserver.conf"
toolServiceName="coturn.service" readonly toolServiceName="coturn.service"
publicIpRetry=20 readonly publicIpRetry=20
# Get script working directory seq_config() {
# (when called from a different directory) if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)" sq_config=1
APTOPT= else
CONFIG=0 # End if no configuration file exists
SCRIPT_FILE=$(basename -- $0) dry || return 1
SCRIPT_NAME=${SCRIPT_FILE%%.*} fi
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" # Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
step_config() {
#echo "Called once before executing steps."
## e.g. to source a config file manually:
#. "$CONFIG_FILE"
## or to use sequencer api with global config file:
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
## or to use sequencer api with profile config file support:
#initSeqConfig -p "$SCRIPT_NAME" "$CONFIG_FILE_TEMPLATE"
#if [ $? -eq 0 ] ; then
# CONFIG=1
#else
# # End if no configuration file exists
# [ $DRY -eq 0 ] && return -1
#fi
[ $QUIET -ne 0 ] && APTOPT="-y"
return 0 return 0
} }
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install $toolDeps $APTOPT exe apt install $toolDeps ${sq_aptOpt:-}
} }
step_10_info() { step_10_info() {
@@ -47,64 +33,110 @@ step_10_info() {
echoinfo " -l : Always output update required and error information" echoinfo " -l : Always output update required and error information"
echoinfo " (even with -qq)" echoinfo " (even with -qq)"
} }
step_10_alias() { ALIAS="updateip"; } step_10_alias() { echo "updateip"; }
step_10() { step_10() {
exitIfRunning if running ; then
error "$toolName already running"
return 1
fi
shift shift
local retryCount=$publicIpRetry local retryCount=$publicIpRetry
local ipUpdater local ipUpdater
local ipRegex='^[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\/*[0-9]*$' local ipRegex='^[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\/*[0-9]*$'
local dnsUrl="46.182.19.48" #digitalcourage.de/support/zensurfreier-dns-server local dnsUrl="46.182.19.48" #digitalcourage.de/support/zensurfreier-dns-server
local dnsFallbackUrl="194.150.168.168" #dns.as250.net; Berlin/Frankfurt local dnsFallbackUrl="194.150.168.168" #dns.as250.net; Berlin/Frankfurt
local lecho="echoseq"
if [ "$1" == "-l" ]; then local lLevelSave=${LOG_LEVEL:?}
lecho="echo" local lTimeSave=${LOG_TIME:-}
shift local retval=0
local lSilent=0
silent && lSilent=1
# Force a visible output level for this step
if [ "${1:-}" == "-l" ]; then
LOG_LEVEL=3
LOG_TIME=1
fi fi
local pubIp local pubIp
while [ $retryCount -gt 0 ]; do while [ $retryCount -gt 0 ]; do
pubIp=`"$(command -v upnpc)" -s | grep ^ExternalIPAddress | cut -c21-` pubIp=$("$(command -v upnpc)" -s | grep ^ExternalIPAddress | cut -c21-)
[ $? -eq 0 ] && ipUpdater="upnpc" && break || "$lecho" "[$(date)] [W] Upnpc failed" [ $? -eq 0 ] && ipUpdater="upnpc" && break || error "Upnpc failed"
pubIp=$(dig @$dnsUrl +short +timeout=1 cloud.imoff.de 2>>/dev/null) pubIp=$(dig @$dnsUrl +short +timeout=1 ${sc_turnDomain:?} 2>>/dev/null)
[ $? -eq 0 ] && ipUpdater="DNS" && break || "$lecho" "[$(date) [W] DNS lookup to $dnsUrl failed" [ $? -eq 0 ] && ipUpdater="DNS" && break || error "DNS lookup to $dnsUrl failed"
pubIp=$(dig @$dnsFallbackUrl +short +timeout=1 cloud.imoff.de 2>>/dev/null) pubIp=$(dig @$dnsFallbackUrl +short +timeout=1 ${sc_turnDomain:?} 2>>/dev/null)
[ $? -eq 0 ] && ipUpdater="DNS Fallback" && break || "$lecho" "[$(date)] [W] DNS lookup to $dnsFallbackUrl failed" [ $? -eq 0 ] && ipUpdater="DNS Fallback" && break || error "DNS lookup to $dnsFallbackUrl failed"
((retryCount--)) ((retryCount--))
done done
if [[ ! $pubIp =~ $ipRegex ]]; then if [[ ! $pubIp =~ $ipRegex ]]; then
"$lecho" "[$(date)] [E] Couldn't aquire public IP. Giving up." warning "Couldn't aquire public IP for ${sc_turnDomain}. Giving up."
return 1 retval=1
fi
else
local confIp=`cat "$toolConf" | grep "^external-ip" | cut -d'=' -f2` local confIp=`cat "$toolConf" | grep "^external-ip" | cut -d'=' -f2`
if [ "$pubIp" != "$confIp" ]; then if [ "$pubIp" != "$confIp" ]; then
$lecho "[$(date)] [I] Update required (via $ipUpdater). New public ip: $pubIp" exe sf_updateIp "${pubIp}"
info "Update required (via $ipUpdater). New public ip: $pubIp"
exe sed -i "s/^external-ip[[:space:]]*=.*/external-ip=${pubIp}/" "$toolConf" exe sed -i "s/^external-ip[[:space:]]*=.*/external-ip=${pubIp}/" "$toolConf"
exe sleep 1 exe sleep 1
$lecho "[$(date)] [I] Restarting $toolName"
exe /bin/systemctl restart $toolServiceName exe /bin/systemctl restart $toolServiceName
else elif (( ! lSilent )) ; then
echoseq "[$(date)] [I] No update required (via $ipUpdater). Current ip: $confIp" info "No update required for ${sc_turnDomain} (via $ipUpdater). Current ip: $confIp"
fi fi
fi
# Reset temporary log level change
if [ "${1:-}" == "-l" ]; then
LOG_LEVEL=${lLevelSave:?}
LOG_TIME=${lTimeSave:-0}
fi
return ${retval}
} }
step_12_info() { echo "Setup public ip update cron job every 5 minutes"; } step_12_info() { echo "Setup public ip update cron job every 5 minutes"; }
step_12_alias() { ALIAS="cronip"; } step_12_alias() { echo "cronip"; }
step_12() { step_12() {
echoseq " [I] Setup $ipCronLoc" local ipCronLoc="/etc/cron.d/update_public_ip"
local ipCron="*/5 * * * * root $(escpath ${seq_self:?}) -qq updateip"
info "Setup $ipCronLoc"
addConf -s "$ipCron" "$ipCronLoc" addConf -s "$ipCron" "$ipCronLoc"
} }
ipCronLoc="/etc/cron.d/update_public_ip"
ipCron="*/5 * * * * root $WDIR/$SCRIPT_FILE -qq updateip" step_14_info() { echo "Setup ufw rules to allow upnp, optionally from a sepcific SOURCE_IP"; }
step_14_options() { echo "[SOURCE_IP]"; }
step_14_alias() { echo "ufw"; }
step_14() {
shift
local rex4='^[0-9\.]+[/0-9]*$'
local rex6='^[0-9A-Fa-f\:]+[/0-9]*$'
local remoteIp=
local lPort=1900
# Check if string is a ipv4 or ipv6 address
if [[ "${1:-}" =~ $rex4 ]] || [[ "${1:-}" =~ $rex6 ]] ; then
remoteIp=${1}
fi
if [[ -z ${remoteIp:-} ]] ; then
exe ufw allow ${lPort:?}/udp comment "Allow upnp"
else
exe ufw allow from ${remoteIp:?} port ${lPort:?} proto udp comment "Allow upnp"
fi
}
step_100_info() { echo "Installation notes"; } step_100_info() { echo "Installation notes"; }
step_100_alias() { ALIAS="notes"; } step_100_alias() { echo "notes"; }
step_100_noconf=
step_100() { step_100() {
outColor green color green
cat <<COTURN_EOF cat <<COTURN_EOF
# Port forwarding # Port forwarding
@@ -130,5 +162,7 @@ chmod g+r /etc/letsencrypt/archive/\$LOC_DOMAIN/privkey*
COTURN_EOF COTURN_EOF
} }
VERSION_SEQREV=13 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -14,14 +14,14 @@ SCRIPT_NAME=${SCRIPT_NAME%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg" CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
CONFIG=1 CONFIG=1
else else
[ $DRY -eq 0 ] && return -1 dry || return -1
fi fi
[ $QUIET -ne 0 ] && APTOPT="-y" quiet && APTOPT="-y"
return 0 return 0
} }
@@ -29,12 +29,12 @@ step_1_info() {
echo "Install $toolName" echo "Install $toolName"
echoinfo "Default port: 5050" echoinfo "Default port: 5050"
} }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install $toolDeps $APTOPT exe apt install $toolDeps $APTOPT
exe pip install --upgrade pyopenssl exe pip install --upgrade pyopenssl
endReturn -o $? "Pip install pyopenssl failed" endReturn "Pip install pyopenssl failed"
} }
step_2_info() { echo "Clone git repository"; } step_2_info() { echo "Clone git repository"; }
@@ -51,15 +51,15 @@ step_3() {
step_4_info() { echo "Create systemd service"; } step_4_info() { echo "Create systemd service"; }
step_4() { step_4() {
exe cp "$CPO_INSTALL_DIR/init/couchpotato.service" "/etc/systemd/system" exe cp "$CPO_INSTALL_DIR/init/couchpotato.service" "/etc/systemd/system"
endReturn -o $? "Creating service file failed" endReturn "Creating service file failed"
exe systemctl daemon-reload exe systemctl daemon-reload
} }
step_5_info() { echo "Add ufw rule for web interface"; } step_5_info() { echo "Add ufw rule for web interface"; }
step_5_alias() { ALIAS="ufw"; } step_5_alias() { echo "ufw"; }
step_5() { step_5() {
exe ufw allow in on eth0 to any port 5050 proto tcp comment "couchpotato" exe ufw allow in on eth0 to any port 5050 proto tcp comment "couchpotato"
} }
VERSION_SEQREV=12 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,11 +1,11 @@
#!/bin/bash #!/bin/bash
#toolName=mytool #toolName=mytool
toolDownSite="https://raspi.debian.net/tested-images" readonly toolDownSite="https://raspi.debian.net/tested-images"
toolDownUrl= toolDownUrl=
toolDownFile= toolDownFile=
toolEssentialDeps="vim bash-completion man-db locales wget" readonly toolEssentialDeps="vim bash-completion man-db locales wget"
SDDEV= SDDEV=
SDBOOT= SDBOOT=
@@ -14,35 +14,28 @@ SDROOT=
SDROOTDEV= SDROOTDEV=
SDROOTPUUID= SDROOTPUUID=
# Get script working directory sq_aptOpt=
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
APTOPT=
CONFIG=0
SCRIPT_NAME=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_NAME%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
[ $QUIET -ne 0 ] && APTOPT="-y" interactive || sq_aptOpt="-y"
return 0 return 0
} }
step_1_info() { step_1_info() {
echo "Download latest xz-compressed image [IMAGE FILE URL] [SD CARD DEVICE]" echo "Download latest xz-compressed image"
echoinfo "$toolDownSite" echoinfo "$toolDownSite"
} }
step_1_alias() { ALIAS="install"; } step_1_options() { echo "[IMAGE FILE URL] [SD CARD DEVICE]"; }
step_1_alias() { echo "install"; }
step_1() { step_1() {
shift shift
SDDEV="$2" SDDEV="$2"
if [ -z "$1" ] && [ $QUIET -eq 0 ] ; then if [ -z "$1" ] && interactive ; then
read -p "Provide image download url from $toolDownSite: " toolDownUrl read -p "Provide image download url from $toolDownSite: " toolDownUrl
elif [ ! -z "$1" ] ; then elif [ -n "${1:-}" ] ; then
toolDownUrl="$1" toolDownUrl="$1"
else else
echoerr " [E] No image file provided for download" error -e "No image file provided for download"
exit 1 exit 1
fi fi
@@ -57,21 +50,22 @@ step_1() {
if [ ! -f "$downShaFile" ] ; then if [ ! -f "$downShaFile" ] ; then
exe wget -O "$downShaFile" "$downSha256" exe wget -O "$downShaFile" "$downSha256"
endReturn -o $? "Error downloading $downShaFile" endReturn "Error downloading $downShaFile"
fi fi
if [ ! -f "$toolDownFile" ] ; then if [ ! -f "$toolDownFile" ] ; then
exe wget -O "$toolDownFile" "$toolDownUrl" exe wget -O "$toolDownFile" "$toolDownUrl"
endReturn -o $? "Error downloading $downDownFile" endReturn "Error downloading $downDownFile"
fi fi
echoseq " [I] Checking SHA256 checksum" info "Checking SHA256 checksum"
exe cd $(dirname "$toolDownFile") exe cd $(dirname "$toolDownFile")
exe sha256sum -c "$downShaFile" >>/dev/null exe sha256sum -c "$downShaFile" >>/dev/null
endReturn -o $? "SHA256 checksum error" endReturn "SHA256 checksum error"
} }
step_2_info() { echo "Write image to device [DEVICE]"; } step_2_info() { echo "Write image to device"; }
step_2_options() { echo "[DEVICE]"; }
step_2() { step_2() {
shift shift
if [ -z "$SDDEV" ] ; then if [ -z "$SDDEV" ] ; then
@@ -79,16 +73,16 @@ step_2() {
fi fi
read_sd_dev "$SDDEV" read_sd_dev "$SDDEV"
# check if device was confirmed # check if device was confirmed
endReturn -o $? "SD card device not found" endReturn "SD card device not found"
echoseq " [I] Writing $(basename "$toolDownFile")" info "Writing $(basename "$toolDownFile")"
exep "xzcat \"$toolDownFile\" | dd of=$SDDEV bs=64k oflag=dsync status=progress" exep "xzcat \"$toolDownFile\" | dd of=$SDDEV bs=64k oflag=dsync status=progress"
exe sync exe sync
} }
step_3_info() { echo "Prepare SD card for first run"; } step_3_info() { echo "Prepare SD card for first run"; }
step_3() { step_3() {
outColor green color green
cat <<PREPARE_EOF cat <<PREPARE_EOF
[I] Setup static IP [I] Setup static IP
[etc/network/interfaces.d/eth0] [etc/network/interfaces.d/eth0]
@@ -122,16 +116,16 @@ PREPARE_EOF
} }
step_10_info() { echo "Essential debian setup"; } step_10_info() { echo "Essential debian setup"; }
step_10_alias() { ALIAS="setup"; } step_10_alias() { echo "setup"; }
step_10() { step_10() {
if [ -z "$(ls /etc/default | grep raspi)" ] ; then if [ -z "$(ls /etc/default | grep raspi)" ] ; then
echoerr " [E] Not on a Raspberry pi" error -e "Not on a Raspberry pi"
return 1 return 1
fi fi
exe apt update exe apt update
exe apt full-upgrade $APTOPT exe apt full-upgrade ${sq_aptOpt}
exe apt install $toolEssentialDeps $APTOPT exe apt install $toolEssentialDeps ${sq_aptOpt}
} }
step_11_info() { echo "Set timezone"; } step_11_info() { echo "Set timezone"; }
@@ -144,43 +138,44 @@ step_12() {
local localUs="en_US.UTF-8" local localUs="en_US.UTF-8"
local localUsDefault="$localUs UTF-8" local localUsDefault="$localUs UTF-8"
if [ ! -f "$localesConfigLoc" ] ; then if [ ! -f "$localesConfigLoc" ] ; then
echoerr " [E] Install packages locales first" error -e "Install packages locales first"
exit 1 exit 1
fi fi
exe sed -i "s/#[[:space:]]*\($localUsDefault\)/\1/" "$localesConfigLoc" exe sed -i "s/#[[:space:]]*\($localUsDefault\)/\1/" "$localesConfigLoc"
endReturn -o $? "Changing locales failed" endReturn "Changing locales failed"
exe locale-gen exe locale-gen
exe update-locale LANG=$localUs exe update-locale LANG=$localUs
echoseq " [I] Logout and login for changes to be active" info "Logout and login for changes to be active"
} }
localesConfigLoc="/etc/locale.gen" localesConfigLoc="/etc/locale.gen"
step_14_info() { echo "Change hostname [HOSTNAME]"; } step_14_info() { echo "Change hostname"; }
step_14_alias() { ALIAS="hostname"; } step_14_options() { echo "[HOSTNAME]"; }
step_14_alias() { echo "hostname"; }
step_14() { step_14() {
shift shift
local localHostname=$1 local localHostname=$1
endCheckEmpty localHostname "No hostname provided" endIfEmpty localHostname "No hostname provided"
if [ $(grep -r "$localHostname" "$hostsLoc">>/dev/null; echo $?) -eq 0 ] ; then if [ $(grep -r "$localHostname" "$hostsLoc">>/dev/null; echo $?) -eq 0 ] ; then
echoseq " [I] Hostname $localHostname already defined" info "Hostname $localHostname already defined"
return 0 return 0
fi fi
exe hostnamectl set-hostname "$localHostname" exe hostnamectl set-hostname "$localHostname"
endReturn -o $? "Couldn't set hostname" endReturn "Couldn't set hostname"
exe sed -i "s/^\(127\.0\.0\.1[[:space:]]*\)\(localhost.*\)/\1\2\n\1$localHostname/" "$hostsLoc" exe sed -i "s/^\(127\.0\.0\.1[[:space:]]*\)\(localhost.*\)/\1\2\n\1$localHostname/" "$hostsLoc"
} }
hostsLoc="/etc/hosts" hostsLoc="/etc/hosts"
step_16_info() { echo "Install cifs mounting requirements"; } step_16_info() { echo "Install cifs mounting requirements"; }
step_16_alias() { ALIAS="cifs"; } step_16_alias() { echo "cifs"; }
step_16() { step_16() {
exe apt install cifs-utils $APTOPT exe apt install cifs-utils ${sq_aptOpt}
} }
step_17_info() { echo "Cifs notes"; } step_17_info() { echo "Cifs notes"; }
step_17() { step_17() {
outColor green color green
cat <<CIFS_EOF cat <<CIFS_EOF
# Example fstab entry # Example fstab entry
[/etc/fstab] [/etc/fstab]
@@ -203,9 +198,9 @@ CIFS_EOF
} }
step_19_info() { echo "Setup notes"; } step_19_info() { echo "Setup notes"; }
step_19_alias() { ALIAS="setupnotes"; } step_19_alias() { echo "setupnotes"; }
step_19() { step_19() {
outColor green color green
cat <<SETUPNOTES_EOF cat <<SETUPNOTES_EOF
# Secure root with a password # Secure root with a password
passwd passwd
@@ -217,9 +212,9 @@ SETUPNOTES_EOF
} }
step_40_info() { echo "Boot from HD notes"; } step_40_info() { echo "Boot from HD notes"; }
step_40_alias() { ALIAS="hdboot"; } step_40_alias() { echo "hdboot"; }
step_40() { step_40() {
outColor green color green
cat <<HDBOOT_EOF cat <<HDBOOT_EOF
[I] Raspberry pi 4 boots from USB automatically if there is no SD available [I] Raspberry pi 4 boots from USB automatically if there is no SD available
(needs boot loader version September 3rd) (needs boot loader version September 3rd)
@@ -246,7 +241,7 @@ HDBOOT_EOF
read_sd_dev() { read_sd_dev() {
local partExt="" local partExt=""
if [ ! -z "$1" ] ; then if [ -n "${1:-}" ] ; then
SDBOOT= SDBOOT=
SDROOT= SDROOT=
SDROOTDEV= SDROOTDEV=
@@ -260,7 +255,7 @@ read_sd_dev() {
SDROOTDEV= SDROOTDEV=
SDBOOTPUUID= SDBOOTPUUID=
SDROOTPUUID= SDROOTPUUID=
echo " [I] Available devices:" info "Available devices:"
echo echo
exe lsblk -p exe lsblk -p
echo echo
@@ -268,7 +263,7 @@ read_sd_dev() {
fi fi
if [ ! -b "$SDDEV" ] ; then if [ ! -b "$SDDEV" ] ; then
echoerr " [I] $SDDEV not a block device" info -e "$SDDEV not a block device"
SDDEV= SDDEV=
return 1 return 1
fi fi
@@ -296,5 +291,8 @@ read_sd_dev() {
} }
SDBOOTPARTNO=1 SDBOOTPARTNO=1
SDROOTPARTNO=2 SDROOTPARTNO=2
VERSION_SEQREV=12
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,31 +1,23 @@
#!/bin/bash #!/bin/bash
# Get script working directory sq_aptOpt=
# (when called from a different directory)
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)"
APTOPT=
CONFIG=0
SCRIPT_NAME=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_NAME%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
checkVpn checkVpn
initSeqConfig -t "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if ! initSeqConfig -t "${seq_configName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then
CONFIG=1
else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return -1 dry || return 1
fi fi
[ $QUIET -ne 0 ] && APTOPT="-y"
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
return 0 return 0
} }
step_1_info() { echo "Install mono"; } step_1_info() { echo "Install mono"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt install apt-transport-https dirmngr gnupg ca-certificates exe apt install apt-transport-https dirmngr gnupg ca-certificates
exe apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF exe apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
@@ -58,15 +50,47 @@ step_4_info() {
echoinfo "Default port: 8989" echoinfo "Default port: 8989"
} }
step_4() { step_4() {
exe apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 2009837CBFFD68F45BC180471F4F90DE2A9B4BF8 local lService=`eval "echo \"$sonarrService\""`
exep "echo \"deb https://apt.sonarr.tv/debian buster main\" | tee /etc/apt/sources.list.d/sonarr.list" local appTar="/tmp/Sonarr.tgz"
exe apt update local appUrl="https://services.sonarr.tv/v1/download/main/latest?version=4&os=linux&arch=arm64"
exe apt install sonarr local appConf="${DLD_CONFDIR}/sonarr"
# Start of sonar must be managed by VPN service local appServiceLoc="/etc/systemd/system/sonarr.service"
exe service sonarr stop
exe systemctl disable sonarr [ ! -e "$appTar" ] && exe curl -sL "$appUrl" -o "$appTar"
exe tar xvzf "$appTar" -C "${DLD_DIR}"
exe mv "${DLD_DIR}/Sonarr" "${DLD_DIR}/sonarr"
exe chown -R ${DLD_USER}:${DLD_USER} "${DLD_DIR}/sonarr"
exe mkdir -p "$appConf"
exe chown -R ${DLD_USER}: "$appConf"
addConf -s "$lService" "$appServiceLoc"
exe systemctl daemon-reload
} }
sonarrService="[Unit]
Description=Sonarr Daemon
After=syslog.target network.target
Wants=transmission.service jackett.service nzbget.service
StartLimitIntervalSec=0
[Service]
User=\$DLD_USER
Group=\$DLD_USER
Type=simple
ExecStart=\${DLD_DIR}/sonarr/Sonarr -nobrowser -data=\${DLD_CONFDIR}/sonarr
TimeoutStopSec=20
KillMode=process
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Alias=sonarr.service"
step_5_info() { step_5_info() {
echo "Install radarr for arm64" echo "Install radarr for arm64"
echoinfo "Default port: 7878" echoinfo "Default port: 7878"
@@ -77,6 +101,7 @@ step_5() {
exe curl -sL "https://radarr.servarr.com/v1/update/master/updatefile?os=linux&runtime=netcore&arch=arm64" \ exe curl -sL "https://radarr.servarr.com/v1/update/master/updatefile?os=linux&runtime=netcore&arch=arm64" \
-o /tmp/Radarr.tgz -o /tmp/Radarr.tgz
exe mkdir -p "${DLD_DIR}"
exe tar xvzf /tmp/Radarr.tgz -C "${DLD_DIR}/" exe tar xvzf /tmp/Radarr.tgz -C "${DLD_DIR}/"
exe mv ${DLD_DIR}/Radarr "${DLD_DIR}/radarr" exe mv ${DLD_DIR}/Radarr "${DLD_DIR}/radarr"
exe chown -R ${DLD_USER}:${DLD_USER} "${DLD_DIR}/radarr" exe chown -R ${DLD_USER}:${DLD_USER} "${DLD_DIR}/radarr"
@@ -84,13 +109,14 @@ step_5() {
step_6_info() { echo "Create radarr service"; } step_6_info() { echo "Create radarr service"; }
step_6() { step_6() {
local lService=`eval "echo \"$radarrService\""`
local radarrConf="${DLD_CONFDIR}/radarr" local radarrConf="${DLD_CONFDIR}/radarr"
local radarrServiceLoc="/etc/systemd/system/radarr.service" local radarrServiceLoc="/etc/systemd/system/radarr.service"
exe mkdir -p "$radarrConf" exe mkdir -p "$radarrConf"
exe chown -R $DLD_USER: "$radarrConf" exe chown -R $DLD_USER: "$radarrConf"
addConf -s "$radarrService" "$radarrServiceLoc" addConf -s "$lService" "$radarrServiceLoc"
exe systemctl daemon-reload exe systemctl daemon-reload
} }
radarrService="[Unit] radarrService="[Unit]
@@ -100,12 +126,12 @@ Wants=transmission.service jackett.service nzbget.service
StartLimitIntervalSec=0 StartLimitIntervalSec=0
[Service] [Service]
User=\$DLD_USER User=\${DLD_USER}
Group=\$DLD_USER Group=\${DLD_USER}
Type=simple Type=simple
ExecStart=\${DLD_DIR}/radarr/Radarr -nobrowser -data=\$radarrConf ExecStart=\${DLD_DIR}/radarr/Radarr -nobrowser -data=\${DLD_CONFDIR}/radarr
TimeoutStopSec=20 TimeoutStopSec=20
KillMode=process KillMode=process
Restart=on-failure Restart=on-failure
@@ -227,7 +253,7 @@ step_11() {
exe curl -sL "$lidarrUrl" -o /tmp/Lidarr.tgz exe curl -sL "$lidarrUrl" -o /tmp/Lidarr.tgz
endReturn -o "Download failed" endReturn -o "Download failed"
exe apt install $lidarrDeps $APTOPT exe apt install $lidarrDeps ${sq_aptOpt}
exe tar xvzf /tmp/Lidarr.tgz -C "${DLD_DIR}/" exe tar xvzf /tmp/Lidarr.tgz -C "${DLD_DIR}/"
exe mv "${DLD_DIR}/Lidarr" "${DLD_DIR}/lidarr" exe mv "${DLD_DIR}/Lidarr" "${DLD_DIR}/lidarr"
@@ -273,7 +299,7 @@ step_13() {
local bazarrDeps="python3-pip python3-distutils python3-venv ffmpeg" local bazarrDeps="python3-pip python3-distutils python3-venv ffmpeg"
#local bazarrDeps+=" libxml2-dev libxslt1-dev python3-libxml2 python3-lxml libatlas-base-dev" #local bazarrDeps+=" libxml2-dev libxslt1-dev python3-libxml2 python3-lxml libatlas-base-dev"
exe apt install $bazarrDeps $APTOPT exe apt install $bazarrDeps ${sq_aptOpt}
} }
step_14_info() { echo "Install bazarr"; } step_14_info() { echo "Install bazarr"; }
@@ -286,7 +312,7 @@ step_14() {
local bazarrGitUrl="https://github.com/morpheus65535/bazarr.git" local bazarrGitUrl="https://github.com/morpheus65535/bazarr.git"
exe python3 -m venv "$bazarrVenv" exe python3 -m venv "$bazarrVenv"
endReturn -o $? "Creating virtual environment failed" endReturn "Creating virtual environment failed"
exe git clone $bazarrGitUrl "$bazarrDir" exe git clone $bazarrGitUrl "$bazarrDir"
exe chown -R $DLD_USER: "$bazarrVenv" exe chown -R $DLD_USER: "$bazarrVenv"
@@ -319,17 +345,17 @@ WantedBy=multi-user.target
Alias=bazarr.service" Alias=bazarr.service"
step_15_info() { echo "Create ufw rules for default ports"; } step_15_info() { echo "Create ufw rules for default ports"; }
step_15_alias() { ALIAS="ufw"; } step_15_alias() { echo "ufw"; }
step_15() { step_15() {
exe ufw allow in on eth0 to any port 6789 proto tcp comment "NZBGet" exe ufw allow in on eth0 to any port 6789 proto tcp comment "NZBGet"
exe ufw allow in on eth0 to any port 9117 proto tcp comment "Jackett. Rules for Sonarr und Radarr in /etc/ufw/rules.before" exe ufw allow in on eth0 to any port 9117 proto tcp comment "Jackett. Rules for Sonarr und Radarr in /etc/ufw/rules.before"
outColor red color red
echo echo
echo "[W] Add the following lines before \"# drop INVALID packets\"" echo "[W] Add the following lines before \"# drop INVALID packets\""
echo " [/etc/ufw/before.rules]" echo " [/etc/ufw/before.rules]"
echo echo
outColor green color green
echo "# Allow all packages to sonarr and radarr" echo "# Allow all packages to sonarr and radarr"
echo "# ufw thinks that nzb360 sends messages after socket is closed" echo "# ufw thinks that nzb360 sends messages after socket is closed"
echo "-A ufw-before-input -i eth0 -p tcp --dport 7878 -j ACCEPT" echo "-A ufw-before-input -i eth0 -p tcp --dport 7878 -j ACCEPT"
@@ -348,29 +374,29 @@ step_16() {
local buildPath="/tmp/unrarbuild" local buildPath="/tmp/unrarbuild"
cat /etc/apt/sources.list | grep -E "^deb-src" >>/dev/null 2>&1 cat /etc/apt/sources.list | grep -E "^deb-src" >>/dev/null 2>&1
endReturn -o $? "No deb-src entry found in /etc/apt/sources.list" endReturn "No deb-src entry found in /etc/apt/sources.list"
exe mkdir -p "$buildPath" exe mkdir -p "$buildPath"
exe cd "$buildPath" exe cd "$buildPath"
exe apt build-dep unrar-nonfree $APTOPT exe apt build-dep unrar-nonfree ${sq_aptOpt}
exe apt source -b unrar-nonfree $APTOPT exe apt source -b unrar-nonfree ${sq_aptOpt}
endReturn -o $? "unrar-nonfree build failed ($buildPath left untouched)" endReturn "unrar-nonfree build failed ($buildPath left untouched)"
exe dpkg -i unrar*.deb exe dpkg -i unrar*.deb
endReturn -o $? "unrar-nonfree install failed ($buildPath left untouched)" endReturn "unrar-nonfree install failed ($buildPath left untouched)"
exe rm -rf "$buildPath" exe rm -rf "$buildPath"
} }
step_17_info() { echo "Install danted socks proxy"; } step_17_info() { echo "Install danted socks proxy"; }
step_17_alias() { ALIAS="danted"; } step_17_alias() { echo "danted"; }
step_17() { step_17() {
systemctl status danted.service >>/dev/null 2>&1 systemctl status danted.service >>/dev/null 2>&1
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echoseq " [I] Danted already installed" info "Danted already installed"
return 0 return 0
fi fi
exe apt update exe apt update
exe apt install dante-server $APTOPT exe apt install dante-server ${sq_aptOpt}
exe systemctl stop danted.service exe systemctl stop danted.service
exe systemctl disable danted.service exe systemctl disable danted.service
} }
@@ -379,11 +405,15 @@ step_18_info() { echo "Danted installation notes"; }
step_18() { step_18() {
cat <<DANTED_EOF cat <<DANTED_EOF
[I] Debian fix systemd startup [I] Debian fix systemd startup
systemctl edit --full danted.service systemctl edit danted.service
# Change /lib64 to -/lib64 # Change /lib64 to -/lib64
ReadOnlyDirectories=/bin /etc /lib -/lib64 /sbin /usr /var ReadOnlyDirectories=/bin /etc /lib -/lib64 /sbin /usr /var
# Grant access to /var/log
[Service]
ReadWriteDirectories=/var/log
[I] Basic danted settings [I] Basic danted settings
* Restrict to local network * Restrict to local network
* Separate logfile * Separate logfile
@@ -419,7 +449,7 @@ DANTED_EOF
} }
step_19_info() { echo "Disable apt-daily activities"; } step_19_info() { echo "Disable apt-daily activities"; }
step_19_alias() { ALIAS="aptdaily"; } step_19_alias() { echo "aptdaily"; }
step_19() { step_19() {
exe /usr/bin/systemctl stop apt-daily-upgrade.timer exe /usr/bin/systemctl stop apt-daily-upgrade.timer
exe /usr/bin/systemctl stop apt-daily.timer exe /usr/bin/systemctl stop apt-daily.timer
@@ -430,22 +460,18 @@ step_19() {
} }
step_21_info() { step_21_info() {
local pInstallDir="${DLD_DIR}/prowlarr" local pInstallDir="${DLD_DIR:-}/prowlarr"
case $CONTEXT_HELP in if contextHelp ; then
0) echo -n "Install/Update "
if [ -e "$pInstallDir" ]; then elif [ -e "$pInstallDir" ]; then
echo -n "Upgrade " echo -n "Upgrade "
else else
echo -n "Install " echo -n "Install "
fi fi
;;
*)
echo -n "Install/Update ";;
esac
echo "prowlarr for arm64" echo "prowlarr for arm64"
echoinfo "Default port: 9696" echoinfo "Default port: 9696"
} }
step_21_alias() { ALIAS="prowlarr"; } step_21_alias() { echo "prowlarr"; }
step_21() { step_21() {
# local pDownDir="/tmp" # local pDownDir="/tmp"
local pInstallDir="${DLD_DIR}/prowlarr" local pInstallDir="${DLD_DIR}/prowlarr"
@@ -455,10 +481,10 @@ step_21() {
if [ -e "$pInstallDir" ]; then if [ -e "$pInstallDir" ]; then
prowlarrUpgrade=1 prowlarrUpgrade=1
echoseq " [I] Stopping prowlarr service" info "Stopping prowlarr service"
echoseq " Service will not be started automatically after update" info " Service will not be started automatically after update"
exe service prowlarr stop exe service prowlarr stop
echoseq " [I] Moving existing $pInstallDir as backup" info "Moving existing $pInstallDir as backup"
exe mv "$pInstallDir" "${pInstallDir}_bu_"`date +%Y%m%d-%H%M%S` exe mv "$pInstallDir" "${pInstallDir}_bu_"`date +%Y%m%d-%H%M%S`
fi fi
@@ -470,12 +496,12 @@ pTar="/tmp/Prowlarr.tgz"
prowlarrUpgrade=0 prowlarrUpgrade=0
step_22_info() { echo "Clean prowlarr download"; } step_22_info() { echo "Clean prowlarr download"; }
step_22_alias() { ALIAS="prowlarrclean"; } step_22_alias() { echo "prowlarrclean"; }
step_22() { step_22() {
exe rm -rf "$pTar" exe rm -rf "$pTar"
if [ $prowlarrUpgrade -ne 0 ]; then if [ $prowlarrUpgrade -ne 0 ]; then
echoseq " [I] Stopping sequence here." info "Stopping sequence here."
echoseq " Following steps only exected for fresh installation." info " Following steps only executed for fresh installation."
exit 0 exit 0
fi fi
} }
@@ -512,22 +538,18 @@ step_24() {
} }
step_30_info() { step_30_info() {
local pInstallDir="${DLD_DIR}/readarr" local pInstallDir="${DLD_DIR:-}/readarr"
case $CONTEXT_HELP in if contextHelp ; then
0) echo -n "Install/Update "
if [ -e "$pInstallDir" ]; then elif [ -e "$pInstallDir" ]; then
echo -n "Upgrade " echo -n "Upgrade "
else else
echo -n "Install " echo -n "Install "
fi fi
;;
*)
echo -n "Install/Update ";;
esac
echo "readarr for arm64" echo "readarr for arm64"
echoinfo "Default port: 8787" echoinfo "Default port: 8787"
} }
step_30_alias() { ALIAS="readarr"; } step_30_alias() { echo "readarr"; }
step_30() { step_30() {
# local pDownDir="/tmp" # local pDownDir="/tmp"
local lInstallDir="${DLD_DIR}/readarr" local lInstallDir="${DLD_DIR}/readarr"
@@ -537,10 +559,10 @@ step_30() {
if [ -e "$lInstallDir" ]; then if [ -e "$lInstallDir" ]; then
readarrUpgrade=1 readarrUpgrade=1
echoseq " [I] Stopping readarr service" info "Stopping readarr service"
echoseq " Service will not be started automatically after update" info " Service will not be started automatically after update"
exe service readarr stop exe service readarr stop
echoseq " [I] Moving existing $lInstallDir as backup" info "Moving existing $lInstallDir as backup"
exe mv "$lInstallDir" "${lInstallDir}_bu_"`date +%Y%m%d-%H%M%S` exe mv "$lInstallDir" "${lInstallDir}_bu_"`date +%Y%m%d-%H%M%S`
fi fi
@@ -552,12 +574,12 @@ readarrTar="/tmp/Readarr.tar.gz"
readarrUpgrade=0 readarrUpgrade=0
step_31_info() { echo "Clean readarr download"; } step_31_info() { echo "Clean readarr download"; }
step_31_alias() { ALIAS="readarrclean"; } step_31_alias() { echo "readarrclean"; }
step_31() { step_31() {
exe rm -rf "$readarrTar" exe rm -rf "$readarrTar"
if [ $readarrUpgrade -ne 0 ]; then if [ $readarrUpgrade -ne 0 ]; then
echoseq " [I] Stopping sequence here." info "Stopping sequence here."
echoseq " Following steps only exected for fresh installation." info " Following steps only executed for fresh installation."
exit 0 exit 0
fi fi
} }
@@ -595,7 +617,7 @@ step_33() {
} }
step_50_info() { echo "Upgrade bazarr"; } step_50_info() { echo "Upgrade bazarr"; }
step_50_alias() { ALIAS="upgradebazarr"; } step_50_alias() { echo "upgradebazarr"; }
step_50() { step_50() {
local bazarrServiceLoc="/etc/systemd/system/bazarr.service" local bazarrServiceLoc="/etc/systemd/system/bazarr.service"
local lService=`eval "echo \"$bazarrService\""` local lService=`eval "echo \"$bazarrService\""`
@@ -609,9 +631,12 @@ step_50() {
} }
checkVpn() { checkVpn() {
ip -br a | grep tun >>/dev/null 2>&1 if ip -br a | grep tun >>/dev/null 2>&1 ; then
[ $? -eq 0 ] && echoseq " [W] A VPN connection is possibly active. Consider deactivating it befor any apt operation." [ $? -eq 0 ] && warning "A VPN connection is possibly active. Consider deactivating it befor any apt operation."
fi
} }
VERSION_SEQREV=13 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,42 +1,42 @@
#!/bin/bash #!/bin/bash
toolName=duplicity readonly toolName=duplicity
readonly toolCronDir="/etc/cron.d"
readonly toolPrefix="encBackup_"
toolBin= toolBin=
toolPpa="ppa:duplicity-team/duplicity-release-git"
toolCronDir="/etc/cron.d"
toolPrefix="encBackup_"
toolSyslogTag= toolSyslogTag=
# Get script working directory sq_aptOpt=
# (when called from a different directory) sq_config=0
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd )"
CONFIG=0
SCRIPT_NAME=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_NAME%%.*}
CONFIG_FILE_TEMPLATE="$WDIR/${SCRIPT_NAME}.cfg.example"
step_config() { seq_config() {
initSeqConfig -p "$SCRIPT_NAME" "$CONFIG_FILE_TEMPLATE" if initSeqConfig -p "${seq_fileName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then sq_config=1
CONFIG=1
else else
[ $DRY -eq 0 ] && return 1 dry || return 1
fi fi
toolSyslogTag="${SCRIPT_NAME}-$SEQ_PROFILE_NAME"
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
toolSyslogTag="${seq_fileName:?}-$seq_profileName"
return 0
} }
step_1_info() { step_1_info() {
echo -n "Backup " echo -n "Backup "
if [ $CONTEXT_HELP -ne 0 ] ; then if contextHelp ; then
echo -n "selected profile" echo "selected profile"
else else
echo -n "profile: $SEQ_PROFILE_NAME" echo "profile: $seq_profileName"
fi fi
echo " [OPTIONS] [full|incremental]"
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " --no-purge, -n : Do not purge old backups after backup" echoinfo " --no-purge, -n : Do not purge old backups after backup"
echoinfo " --allow-source-mismatch, -a : see ${toolName:-} help"
} }
step_1_alias() { ALIAS="backup"; } step_1_options() { echo '[OPTIONS] [full|incremental]'; }
step_1_alias() { echo "backup"; }
step_1() { step_1() {
shift shift
@@ -44,40 +44,43 @@ step_1() {
local retVal local retVal
local dupArgs local dupArgs
local purgeAfter=1 local purgeAfter=1
local lSourceMismatch=
for arg in "$@" ; do for arg in "$@" ; do
case "$1" in case "$1" in
--no-purge|-n) --no-purge|-n)
purgeAfter=0 purgeAfter=0
shift shift ;;
;; --allow-source-mismatch|-a)
dupArgs+=("--allow-source-mismatch")
shift ;;
esac esac
done done
if [ -z $EBU_TARGET ] || [ -z $EBU_SOURCE ] ; then if [ -z $EBU_TARGET ] || [ -z $EBU_SOURCE ] ; then
echo " [I] Nothing to do. Check $SEQ_CONFIG_FILE" info "Nothing to do. Check $seq_configFile"
return 1 return 1
fi fi
if [ ! -z "$1" ] && ( [ "$1" == "full" ] || [ "$1" == "incremental" ] ) ; then if [ -n "${1:-}" ] && ( [ "$1" == "full" ] || [ "$1" == "incremental" ] ) ; then
dupArgs+=("$1") dupArgs+=("$1")
elif [ ! -z "$1" ] ; then elif [ -n "${1:-}" ] ; then
echo " [W] $toolName command \"$1\" not recognized" warning "$toolName command \"$1\" not recognized"
return 1 return 1
fi fi
echo " [I] Running backup profile [$SEQ_PROFILE_NAME]" info "Running backup profile [$seq_profileName]"
if [ "${dupArgs[0]}" != "full" ] && [ ! -z "$EBU_MAX_FULLBKP_AGE" ] ; then if [ "${dupArgs[0]:-}" != "full" ] && [ -n "$EBU_MAX_FULLBKP_AGE" ] ; then
dupArgs+=(--full-if-older-than "$EBU_MAX_FULLBKP_AGE") dupArgs+=(--full-if-older-than "$EBU_MAX_FULLBKP_AGE")
fi fi
if [ ! -z "$EBU_VOLSIZE" ] ; then if [ -n "$EBU_VOLSIZE" ] ; then
dupArgs+=(--volsize "$EBU_VOLSIZE") dupArgs+=(--volsize "$EBU_VOLSIZE")
fi fi
checkInstalled checkInstalled
setPassphrase setPassphrase
exe $toolBin "${dupArgs[@]}" "$EBU_SOURCE" "$EBU_TARGET" exe $toolBin "${dupArgs[@]:-}" "${EBU_SOURCE:?}" "${EBU_TARGET:?}"
retVal=$? retVal=$?
unsetPassphrase unsetPassphrase
@@ -89,12 +92,12 @@ step_1() {
} }
step_3_info() { echo "Verify selected backup"; } step_3_info() { echo "Verify selected backup"; }
step_3_alias() { ALIAS="verify"; } step_3_alias() { echo "verify"; }
step_3() { step_3() {
shift shift
if [ -z $EBU_TARGET ] || [ -z $EBU_SOURCE ] ; then if [ -z $EBU_TARGET ] || [ -z $EBU_SOURCE ] ; then
echo " [I] Nothing to do. Check $SEQ_CONFIG_FILE" info "Nothing to do. Check $seq_configFile"
return 1 return 1
fi fi
@@ -105,13 +108,14 @@ step_3() {
} }
step_5_info() { step_5_info() {
echo "Restore [OPTIONS] <LOCAL TARGET> [TARGET]" echo "Restore files from backup"
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " --file-to-restore, -f <RELPATH> : Relative path within backup" echoinfo " --file-to-restore, -f <RELPATH> : Relative path within backup"
echoinfo " (file or folder)" echoinfo " (file or folder)"
echoinfo " --time, -t <TIME> : Age of file to be restored" echoinfo " --time, -t <TIME> : Age of file to be restored"
} }
step_5_alias() { ALIAS="restore"; } step_5_options() { echo '[OPTIONS] <LOCAL TARGET> [TARGET]'; }
step_5_alias() { echo "restore"; }
step_5() { step_5() {
shift shift
@@ -134,7 +138,7 @@ step_5() {
done done
if [ -z "$1" ] ; then if [ -z "$1" ] ; then
echoerr " [E] No target provided" error -e "No target provided"
return 1 return 1
fi fi
local ebuLocalTarget="$1" local ebuLocalTarget="$1"
@@ -149,13 +153,14 @@ step_5() {
unsetPassphrase unsetPassphrase
} }
step_7_info() { echo "Purge old backups [TARGET]"; } step_7_info() { echo "Purge old backups"; }
step_7_alias() { ALIAS="purge"; } step_7_options() { echo '[TARGET]'; }
step_7_alias() { echo "purge"; }
step_7() { step_7() {
shift shift
local ebuTarget="$EBU_TARGET" local ebuTarget="$EBU_TARGET"
local dupCommand= local dupCommand=
if [ ! -z "$1" ] ; then if [ -n "${1:-}" ] ; then
ebuTarget="$1" ebuTarget="$1"
fi fi
@@ -166,7 +171,7 @@ step_7() {
elif [ ! -z "$EBU_MAX_FULLS_WITH_INCRS" ] ; then elif [ ! -z "$EBU_MAX_FULLS_WITH_INCRS" ] ; then
dupCommand+="remove-all-inc-of-but-n-full $EBU_MAX_FULLS_WITH_INCRS " dupCommand+="remove-all-inc-of-but-n-full $EBU_MAX_FULLS_WITH_INCRS "
else else
if [ $QUIET -eq 0 ] ; then echoerr " [W] No purge option configured" ; fi if interactive ; then warning -e "No purge option configured" ; fi
return 1 return 1
fi fi
@@ -178,61 +183,64 @@ step_7() {
step_20_info() { step_20_info() {
shift shift
local ebuTarget=$EBU_TARGET local ebuTarget="${EBU_TARGET:-}"
[ ! -z "$1" ] && ebuTarget="$1" [ ! -z "${1:-}" ] && ebuTarget="$1"
if [ $CONTEXT_HELP -ne 0 ]; then if contextHelp; then
echo "Status of (profile) [TARGET]" echo "Status of (profile)"
elif [ ! -z "$1" ]; then elif [ -n "${1:-}" ]; then
echo "Status of target: $ebuTarget" echo "Status of target: $ebuTarget"
else else
echo "Status of profile \"$SEQ_PROFILE_NAME\" target: $ebuTarget" echo "Status of profile \"$seq_profileName\" target: $ebuTarget"
fi fi
} }
step_20_alias() { ALIAS='status'; } step_20_options() { echo '[TARGET]'; }
step_20_alias() { echo 'status'; }
step_20() { step_20() {
shift shift
local ebuTarget="$EBU_TARGET" local ebuTarget="$EBU_TARGET"
if [ ! -z "$1" ] ; then [[ -n "${1:-}" ]] && ebuTarget="$1"
ebuTarget="$1"
fi
checkInstalled checkInstalled
exe $toolBin collection-status "$ebuTarget" exe $toolBin collection-status "$ebuTarget"
} }
step_22_info() { echo "List backup files [TARGET]"; } step_22_info() { echo "List backup files"; }
step_22_alias() { ALIAS='list'; } step_22_options() { echo '[TARGET]'; }
step_22_alias() { echo 'list'; }
step_22() { step_22() {
shift shift
local ebuTarget="$EBU_TARGET" local ebuTarget="$EBU_TARGET"
if [ ! -z "$1" ] ; then if [ -n "${1:-}" ] ; then
ebuTarget="$1" ebuTarget="$1"
fi fi
checkInstalled checkInstalled
setPassphrase
exe $toolBin list-current-files "$ebuTarget" exe $toolBin list-current-files "$ebuTarget"
unsetPassphrase
} }
step_70_info() { step_70_info() {
echo -n "Manage cron file for " echo -n "Manage cron file for "
if [ $CONTEXT_HELP -ne 0 ] ; then if contextHelp ; then
echo -n "selected profile" echo -n "selected profile"
else else
echo -n "profile: $SEQ_PROFILE_NAME" echo -n "profile: $seq_profileName"
fi fi
echo " [OPTIONS]" echo " [OPTIONS]"
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " --remove, -r : remove cron file" echoinfo " --remove, -r : remove cron file"
} }
step_70_alias() { ALIAS='cron'; } step_70_alias() { echo 'cron'; }
step_70_options() { echo '[OPTIONS]'; }
step_70() { step_70() {
shift shift
local arg local arg
local cronRemove=0 local cronRemove=0
local cronScript="$toolCronDir/${toolPrefix}$SEQ_PROFILE_NAME" local cronScript="$toolCronDir/${toolPrefix}$seq_profileName"
local cronLog='>/dev/null' local cronLog='>/dev/null'
local cronEntry="$EBU_CRONTIME $(whoami) $WDIR/$(basename -- $0) -qq -p $SEQ_PROFILE_NAME" local cronEntry="$EBU_CRONTIME $(whoami) ${seq_self:?} -qq -p $seq_profileName"
for arg in "$@" ; do for arg in "$@" ; do
case "$1" in case "$1" in
@@ -244,7 +252,7 @@ step_70() {
done done
if [ ! -z "$EBU_LOG_DIR" ] ; then if [ ! -z "$EBU_LOG_DIR" ] ; then
cronLog="$EBU_LOG_DIR/${toolPrefix}${SEQ_PROFILE_NAME}.log" cronLog="$EBU_LOG_DIR/${toolPrefix}${seq_profileName}.log"
exe touch "$cronLog" exe touch "$cronLog"
exe chmod 600 "$cronLog" exe chmod 600 "$cronLog"
fi fi
@@ -252,43 +260,38 @@ step_70() {
cronEntry+=" >$cronLog" cronEntry+=" >$cronLog"
if [ -z "$EBU_CRONTIME" ] || [ $cronRemove -ne 0 ] ; then if [ -z "$EBU_CRONTIME" ] || [ $cronRemove -ne 0 ] ; then
echo " [I] Removing cron for profile $SEQ_PROFILE_NAME" info "Removing cron for profile $seq_profileName"
exe rm -r "$cronScript" exe rm -r "$cronScript"
else else
checkFileHead "$cronScript" "$cronEntry" checkFileHead "$cronScript" "$cronEntry"
if [ $? -ne 0 ] ; then if [ $? -ne 0 ] ; then
echo " [I] Update cron for profile $SEQ_PROFILE_NAME" info "Update cron for profile $seq_profileName"
exep "sudo echo \"$cronEntry\" > \"$cronScript\"" exep "sudo echo \"$cronEntry\" > \"$cronScript\""
syslogEntry "Cron file update complete [$EBU_CRONTIME]" syslogEntry "Cron file update complete [$EBU_CRONTIME]"
else else
echo " [I] Cron for profile $SEQ_PROFILE_NAME is up to date" info "Cron for profile $seq_profileName is up to date"
fi fi
fi fi
} }
step_72_info() { echo "Update all profile cron files"; } step_72_info() { echo "Update all profile cron files"; }
step_72_alias() { ALIAS="reload"; } step_72_alias() { echo "reload"; }
step_72() { step_72() {
for seq in "$SEQ_CONFIG_HOME/"* ; do for seq in "$seq_configRoot/"* ; do
seq=$(basename ${seq}) seq="$(basename -- "${seq}")"
$WDIR/$(basename -- $0) $SEQUENCER_ARGS -qq -p ${seq%%.*} cron exe "${seq_self}" -qq -p ${seq%%.*} cron
done done
} }
step_100_info() { echo "Install $toolName $toolPpa"; } step_100_info() { echo "Install $toolName"; }
step_100_alias() { ALIAS="install"; } step_100_alias() { echo "install"; }
step_100() { step_100() {
local aptOpt= exe apt update
if [ $QUIET -ne 0 ] ; then exe apt install $toolName ${sq_aptOpt}
aptOpt="-y"
fi
exe add-apt-repository $toolPpa $aptOpt
exe apt install $toolName $aptOpt
} }
setPassphrase() { setPassphrase() {
if [ -z $PASSPHRASE ] && [ ! -z $EBU_PASSPHRASE ] ; then if [ -z "${PASSPHRASE:-}" ] && [ -n "${EBU_PASSPHRASE:-}" ] ; then
export PASSPHRASE="$EBU_PASSPHRASE" export PASSPHRASE="$EBU_PASSPHRASE"
fi fi
} }
@@ -299,8 +302,8 @@ unsetPassphrase() {
checkFileHead() { checkFileHead() {
local readChar local readChar
if [ ! -e "$1" ] ; then if [ ! -e "${1:-}" ] ; then
echoerr " [E] File $1 not found" error -e "File $1 not found"
return 1 return 1
fi fi
read -r -n ${#2} readChar < "$1" read -r -n ${#2} readChar < "$1"
@@ -311,20 +314,21 @@ checkFileHead() {
} }
syslogEntry() { syslogEntry() {
if [ "$EBU_SYSLOG" == "true" ] ; then if [[ "${EBU_SYSLOG:-}" == "true" ]] ; then
exe logger -t $toolSyslogTag "$@" exe logger -t $toolSyslogTag "$@"
fi fi
} }
checkInstalled() { checkInstalled() {
if [ -z "$toolBin" ] ; then if [ -z "$toolBin" ] ; then
command -v $toolName >>/dev/null if ! command -v $toolName >>/dev/null ; then
if [ $? -ne 0 ] ; then
step install step install
fi fi
toolBin="$EBU_PRECMD $(command -v $toolName)" toolBin="${EBU_PRECMD:-} $(escpath "$(command -v $toolName)")"
fi fi
} }
VERSION_SEQREV=12 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,22 +1,26 @@
#!/bin/bash #!/bin/bash
# shellcheck disable=SC2154 # Variable referenced but not assigned (seq_origin)
toolName=ejabberd readonly toolName=ejabberd
toolConfLoc="/etc/ejabberd/ejabberd.yml" readonly toolDeps=(ejabberd erlang-p1-mysql)
toolAdminConf="/etc/ejabberd/ejabberdctl.cfg" readonly toolConfLoc="/etc/ejabberd/ejabberd.yml"
readonly toolAdminConf="/etc/ejabberd/ejabberdctl.cfg"
# for http upload # for http upload
toolStorageLoc="/var/ejabberd" readonly toolStorageLoc="/var/ejabberd"
certRoot="/etc/letsencrypt" readonly certRoot="/etc/letsencrypt"
# needed for different steps # needed for different steps
myDomain= myDomain=
myUser= myUser=
myPass= myPass=
seq_trapExit() { unset myPass; }
step_1_info() { echo "Install $toolName via apt"; } step_1_info() { echo "Install $toolName via apt"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install -y $toolName exe apt install -y "${toolDeps[@]}"
exe systemctl stop $toolName exe systemctl stop $toolName
} }
@@ -45,13 +49,13 @@ step_2() {
step_3_info() { echo "Create basic configuration"; } step_3_info() { echo "Create basic configuration"; }
step_3() { step_3() {
if [ ! -f $SEQDIR/ejabberd.yml ] ; then if [ ! -f "${seq_origin}/ejabberd.yml" ] ; then
addConf -m "$MissingConfEntry" "$toolConfLoc" addConf -m "$MissingConfEntry" "$toolConfLoc"
else else
readDomain readDomain
echo -e "\nThis user will be the admin:" echo -e "\nThis user will be the admin:"
readUser readUser
addConf -c "$(cat $SEQDIR/ejabberd.yml)" "$toolConfLoc" addConf -cf "${seq_origin}/ejabberd.yml" "$toolConfLoc"
# modify configuration # modify configuration
exe sed -i "s/mydomain\.eu/${myDomain}/" "$toolConfLoc" exe sed -i "s/mydomain\.eu/${myDomain}/" "$toolConfLoc"
exe sed -i "s/myuser/${myUser}/" "$toolConfLoc" exe sed -i "s/myuser/${myUser}/" "$toolConfLoc"
@@ -64,7 +68,7 @@ step_3() {
exe sed -i "s/#\(INET_DIST_INTERFACE=127\.0\.0\.1\)/\1/" "$toolAdminConf" exe sed -i "s/#\(INET_DIST_INTERFACE=127\.0\.0\.1\)/\1/" "$toolAdminConf"
} }
MissingConfEntry="Seq's basic configuration file \"$SEQDIR/ejabberd.yml\" missing. MissingConfEntry="Seq's basic configuration file \"${seq_origin}/ejabberd.yml\" missing.
Backup $toolConfLoc and create a configuration manually. Backup $toolConfLoc and create a configuration manually.
Some essential settings needed: Some essential settings needed:
@@ -72,76 +76,79 @@ Some essential settings needed:
- Admin User" - Admin User"
step_4_info() { echo "Restart $toolName"; } step_4_info() { echo "Restart $toolName"; }
step_4_alias() { ALIAS="restart"; } step_4_alias() { echo "restart"; }
step_4() { step_4() {
exe service ejabberd restart exe service ejabberd restart
} }
step_5_info() { echo "Create new user"; } step_5_info() { echo "Create new user"; }
step_5_alias() { ALIAS="adduser"; } step_5_alias() { echo "adduser"; }
step_5() { step_5() {
readDomain readDomain
readUser readUser
readUserPass readUserPass
exe ejabberdctl register $myUser $myDomain $myPass exe ejabberdctl register "${myUser}" "${myDomain}" "${myPass}"
} }
step_10_info() { echo "List existing user"; } step_10_info() { echo "List existing user"; }
step_10_alias() { ALIAS="listuser"; } step_10_alias() { echo "listuser"; }
step_10() { step_10() {
readDomain readDomain
exe ejabberdctl registered_users $myDomain exe ejabberdctl registered_users "${myDomain}"
} }
step_12_info() { echo "Change password for existing user"; } step_12_info() { echo "Change password for existing user"; }
step_12_alias() { ALIAS="passwd"; } step_12_alias() { echo "passwd"; }
step_12() { step_12() {
readDomain readDomain
readUser readUser
readUserPass readUserPass
exe ejabberdctl change_password $myUser $myDomain $myPass exe ejabberdctl change_password "${myUser}" "${myDomain}" "${myPass}"
} }
step_14_info() { echo "Remove registered user"; } step_14_info() { echo "Remove registered user"; }
step_14_alias() { ALIAS="deluser"; } step_14_alias() { echo "deluser"; }
step_14() { step_14() {
readDomain readDomain
readUser readUser
readUserPass readUserPass
exe ejabberdctl unregister $myUser $myDomain $myPass exe ejabberdctl unregister "${myUser}" "${myDomain}" "${myPass}"
} }
readDomain() { readDomain() {
if [ "$myDomain" == "" ] ; then if [ "$myDomain" == "" ] ; then
read -p "Enter your domain: " myDomain myDomain=$(ask "Enter your domain: ")
endCheckEmpty myDomain "$toolName domain" endIfEmpty myDomain "$toolName domain"
fi fi
} }
readUser() { readUser() {
echo -e "\nDon't use spaces in user name!" sqr::echo -e "\nDon't use spaces in user name!"
if [ "$myUser" == "" ] ; then if [ "$myUser" == "" ] ; then
read -p "Enter user name: " myUser myUser=$(ask "Enter user name: ")
echo sqr::echo
endCheckEmpty myUser "$toolName user name" endIfEmpty myUser "$toolName user name"
fi fi
} }
readUserPass() { readUserPass() {
echo -e "\nDon't use spaces in user password!" local myPass2=
if [ "$myPass" == "" ] ; then sqr::echo -e "\nDon't use spaces in user password!"
read -s -p "Enter user password: " myPass if [ -z "$myPass" ] ; then
echo myPass=$(ask -s "Enter user password: "); echo
read -s -p "Enter user password again: " myPass2 sqr::echo
echo myPass2=$(ask -s "Enter user password again: "); echo
sqr::echo
if [ "$myPass" != "$myPass2" ] ; then if [ "$myPass" != "$myPass2" ] ; then
echo "[ERROR] Passwords don't match" error "Passwords don't match"
return 1; return 1;
fi fi
endCheckEmpty myPass "$toolName user password" unset myPass2
endIfEmpty myPass "$toolName user password"
fi fi
} }
SEQDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )" # shellcheck disable=SC2034 # Appears unused
VERSION_SEQREV=4 readonly sqr_minVersion=16
. sequencer.sh # shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -1,119 +1,111 @@
#!/bin/bash #!/bin/bash
toolName=element-web readonly toolName=element-web
latestUrl="https://api.github.com/repos/vector-im/element-web/releases/latest" readonly latestUrl="https://api.github.com/repos/vector-im/element-web/releases/latest"
# Get script working directory sq_config=0
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then
echo " ${toolName} path: ${ELEMENT_WEB_LOC}" echo " ${toolName} path: ${ELEMENT_WEB_LOC}"
echo " ${toolName} backup: ${ELEMENT_WEB_BACKUP}" echo " ${toolName} backup: ${ELEMENT_WEB_BACKUP}"
CONFIG=1 sq_config=1
fi fi
} }
step_18_info() { echo "Check for updates"; } step_1_info() { echo "Check for updates"; }
step_18_alias() { ALIAS="updatecheck"; } step_1_alias() { echo "updatecheck"; }
step_18() { step_1() {
shift shift
local latestVersion= local latestVersion=
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
latestVersion="$1" latestVersion="$1"
else else
latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "v\K.*?(?=")') latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "v\K.*?(?=")')
fi fi
local isInstalled=$(grep -E "${latestVersion}" "${ELEMENT_WEB_LOC}/version" >>/dev/null && echo "1" || echo "0") if grep -E "${latestVersion}" "${ELEMENT_WEB_LOC:-}/version" >>/dev/null 2>&1 ; then
if [ $isInstalled -eq 1 ] ; then info "Version $latestVersion is already installed"
echo " [I] Version $latestVersion is already installed"
return 1 return 1
else else
echo " [I] Update to $latestVersion available" info "Update to $latestVersion available"
fi fi
return 0 return 0
} }
step_20_info() { step_20_info() {
echo -n "Create a backup [ELEMENT WEB ROOT]" echo -n "Create a backup"
if [ $CONFIG -ne 0 ] ; then if (( sq_config )) ; then
echo " at $ELEMENT_WEB_BACKUP" echo " at $ELEMENT_WEB_BACKUP"
else else
echo echo
fi fi
} }
step_20_alias() { ALIAS="backup"; } step_20_options() { echo "[ELEMENT WEB ROOT]"; }
step_20_alias() { echo "backup"; }
step_20() { step_20() {
shift shift
local tempRoot= local tempRoot=
if [ $CONFIG -eq 0 ] ; then if (( ! sq_config )) ; then
echoerr " [E] No configuration file found" error -e "No configuration file found"
return 1 return 1
fi fi
if [ ! -z $ELEMENT_WEB_BACKUP ] ; then if [ -n "$ELEMENT_WEB_BACKUP" ] ; then
exe mkdir -p "$ELEMENT_WEB_BACKUP" exe mkdir -p "$ELEMENT_WEB_BACKUP"
fi fi
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
tempRoot="$1" tempRoot="$1"
else else
tempRoot="$ELEMENT_WEB_LOC" tempRoot="$ELEMENT_WEB_LOC"
fi fi
local wwwBackup="$ELEMENT_WEB_BACKUP/${toolName}_www_`date +%Y%m%d-%H%M%S`.tar.gz" # Clear old backups
echo " [I] Backing up webserver directory to $wwwBackup" rmold -r 10 "${ELEMENT_WEB_BACKUP}" || true
local wwwBackup
wwwBackup="$ELEMENT_WEB_BACKUP/${toolName}_www_$(date +%Y%m%d-%H%M%S).tar.gz"
info "Backing up webserver directory to $wwwBackup"
exe cd "$tempRoot/.." exe cd "$tempRoot/.."
exe tar czf "$wwwBackup" $(basename "$tempRoot") exe tar czf "$wwwBackup" "$(basename -- "$tempRoot")"
} }
step_22_info() { step_22_info() {
shift shift
if [ -z $1 ] ; then if [ -z "${1:-}" ] ; then
echo -n "Get latest version from github" echo -n "Get latest version from github"
if [ $CONTEXT_HELP -eq 0 ] ; then if ! contextHelp ; then
echo ": $(curl --silent "$latestUrl" | grep -Po '"tag_name": "\K.*?(?=")')" echo ": $(curl --silent "$latestUrl" | grep -Po '"tag_name": "v\K.*?(?=")')"
else else
echo " [CUSTOM VERSION]" echo
fi fi
else else
echo "Get version $1 from github" echo "Get version $1 from github"
fi fi
} }
step_22_alias() { ALIAS="upgrade"; } step_22_options() { echo "[CUSTOM VERSION]"; }
step_22_alias() { echo "upgrade"; }
step_22() { step_22() {
shift # don't need step number shift # don't need step number
local latestVersion= local latestVersion=
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
latestVersion="$1" latestVersion="$1"
else else
latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "v\K.*?(?=")') latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "v\K.*?(?=")')
fi fi
if [ -z $latestVersion ] ; then if [ -z "$latestVersion" ] ; then
echoerr " [E] Cannot determine latest version from github repository" error -e "Cannot determine latest version from github repository"
return 1 return 1
elif [ $QUIET -eq 0 ] ; then elif interactive ; then
echo echo
exe read -p "Install $latestVersion to $ELEMENT_WEB_LOC [n]o/(y)es? " answer if ! confirm "Install $latestVersion to $ELEMENT_WEB_LOC" ; then
case $answer in info -e "Upgrade aborted"
[yY])
;;
*)
echoerr " [I] Upgrade aborted"
return 1 return 1
;; fi
esac
fi fi
local isInstalled=$(grep -E "${latestVersion}" "${ELEMENT_WEB_LOC}/version" >>/dev/null && echo "1" || echo "0") if grep -E "${latestVersion}" "${ELEMENT_WEB_LOC}/version" >>/dev/null 2>&1 ; then
if [ $isInstalled -eq 1 ] ; then info "Version $latestVersion is already installed"
echo " [I] Version $latestVersion is already installed"
return 0 return 0
fi fi
@@ -123,29 +115,30 @@ step_22() {
if [ ! -e "$tempExtract" ] ; then if [ ! -e "$tempExtract" ] ; then
exe mkdir -p "$tempDown" exe mkdir -p "$tempDown"
exe wget -O "$tempLoc" $downUrl exe wget -O "$tempLoc" "$downUrl"
endReturn -o $? "Download failed: $downUrl" endReturn "Download failed: $downUrl"
exe cd "$tempDown" exe cd "$tempDown"
exe tar -xf "$tempLoc" exe tar -xf "$tempLoc"
endReturn -o $? "Extract failed: $tempLoc" endReturn "Extract failed: $tempLoc"
else else
echo " [I] Found existing download: $tempExtract" info "Found existing download: $tempExtract"
fi fi
# Installation # Installation
local tempBu="${ELEMENT_WEB_LOC}_bu_`date +%Y%m%d-%H%M%S`" local tempBu
tempBu="${ELEMENT_WEB_LOC}_bu_$(date +%Y%m%d-%H%M%S)"
exe mv "$ELEMENT_WEB_LOC" "$tempBu" exe mv "$ELEMENT_WEB_LOC" "$tempBu"
step backup "$tempBu" step backup "$tempBu"
endReturn -o $? "Backup failed; $ELEMENT_WEB_LOC renamed!" endReturn "Backup failed; $ELEMENT_WEB_LOC renamed!"
echo " [I] Installing version $latestVersion to $ELEMENT_WEB_LOC" info "Installing version $latestVersion to $ELEMENT_WEB_LOC"
exe mv "$tempExtract" "$ELEMENT_WEB_LOC" exe mv "$tempExtract" "$ELEMENT_WEB_LOC"
exe chown -R www-data: "$ELEMENT_WEB_LOC" exe chown -R www-data: "$ELEMENT_WEB_LOC"
# Configuration # Configuration
echo " [I] Copying configuration" info "Copying configuration"
exe cp -ar "$tempBu/config.json" "$ELEMENT_WEB_LOC/" addConf -c -f "$tempBu/config.json" "$ELEMENT_WEB_LOC/config.json"
echo " [I] Copying login background" info "Copying login background"
exe cp -ar "$tempBu/$tempBackImg/"* "$ELEMENT_WEB_LOC/$tempBackImg/" exe cp -ar "$tempBu/$tempBackImg/"* "$ELEMENT_WEB_LOC/$tempBackImg/"
exe rm -rf "$tempBu" exe rm -rf "$tempBu"
@@ -155,10 +148,12 @@ tempDown="/tmp/${toolName}"
tempLoc="$tempDown/${toolName}.tar.gz" tempLoc="$tempDown/${toolName}.tar.gz"
step_24_info() { echo "Clean temporary files: $tempDown"; } step_24_info() { echo "Clean temporary files: $tempDown"; }
step_24_alias() { ALIAS="clean"; } step_24_alias() { echo "clean"; }
step_24() { step_24() {
exe rm -rf "$tempDown" exe rm -rf "$tempDown"
} }
VERSION_SEQREV=11 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,50 +1,59 @@
#!/bin/bash #!/usr/bin/env bash
toolName=fail2ban readonly toolName=fail2ban
toolDeps="$toolName" readonly toolDeps="$toolName"
toolConfDir="/etc/fail2ban" readonly toolConfDir="/etc/fail2ban"
toolConfLoc="$toolConfDir/jail.local" readonly toolConfLoc="$toolConfDir/jail.local"
toolFilter="$toolConfDir/filter.d" readonly toolFilter="$toolConfDir/filter.d"
toolJails="$toolConfDir/jail.d" readonly toolJails="$toolConfDir/jail.d"
# Get script working directory
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
CONFIG_DIR="$WDIR/fail2ban"
CONFIG_FILTER="$CONFIG_DIR/filter.d"
CONFIG_JAILS="$CONFIG_DIR/jail.d"
#step_config() { sq_aptOpt=
# echo "Called once before executing steps." #sq_config=0
# ## e.g. to source a config file manually:
# #. "$CONFIG_FILE" seq_config() {
# ## or to use sequencer api: ## Called once before executing steps.
# #initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" ## e.g. to source a config file manually:
# #if [ $? -eq 0 ] ; then #. "${seq_origin:?}/${seq_configName:?}"
# # CONFIG=1
# #fi ## or to use sequencer api with profile config file support:
#} #if initSeqConfig -p "${seq_fileName:?}" "${seq_configTemplate:?}" ; then
## or to use sequencer api with global config file:
#if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
# sq_config=1
#else
# # End if no configuration file exists
# dry || return 1
#fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
sq_configDir="${seq_origin:?}/${toolName:?}"
sq_configFilter="${sq_configDir}/filter.d"
sq_configJails="${sq_configDir}/jail.d"
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
exe apt update exe apt update
exe apt install $toolDeps $aptOpt exe apt install ${toolDeps} ${sq_aptOpt}
} }
step_2_info() { echo "Base jail configuration to use ufw"; } step_2_info() { echo "Base jail configuration to use ufw"; }
step_2_alias() { ALIAS="config"; } step_2_alias() { echo "config"; }
step_2() { step_2() {
echo " [I] Create local configuration"; info "Create local configuration";
addConf -f "$failConfLocal" "$toolConfLoc" addConf -a "$failConfLocal" "$toolConfLoc"
exe service $toolName restart exe service $toolName restart
} }
failConfLocal="[DEFAULT] failConfLocal="[DEFAULT]
@@ -54,20 +63,21 @@ banaction_multiport = ufw
ignoreip = 127.0.0.1/8 ::1" ignoreip = 127.0.0.1/8 ::1"
step_3_info() { echo "Add basic ip-blacklist"; } step_3_info() { echo "Add basic ip-blacklist"; }
step_3_alias() { ALIAS="blacklist"; } step_3_alias() { echo "blacklist"; }
step_3() { step_3() {
echo " [I] Adding filter" local ipBlackList="${sq_configDir}/ip.blacklist"
addConf -s -f "$ipBlackListFilter" "$toolFilter/$(basename $ipBlackListFilter)" local ipBlackListJail="$sq_configJails/ip-blacklist.conf"
addConf -s -f "$ipBlackListJail" "$toolJails/$(basename $ipBlackListJail)" local ipBlackListFilter="$sq_configFilter/ip-blacklist.conf"
addConf -s -f "$ipBlackList" "$toolConfDir/$(basename $ipBlackList)"
info "Adding filter"
addConf -s -f "$ipBlackListFilter" "$toolFilter/$(basename -- "$ipBlackListFilter")"
addConf -s -f "$ipBlackListJail" "$toolJails/$(basename -- "$ipBlackListJail")"
addConf -s -f "$ipBlackList" "$toolConfDir/$(basename -- "$ipBlackList")"
exe service $toolName restart exe service $toolName restart
} }
ipBlackList="$CONFIG_DIR/ip.blacklist"
ipBlackListJail="$CONFIG_JAILS/ip-blacklist.conf"
ipBlackListFilter="$CONFIG_FILTER/ip-blacklist.conf"
step_4_info() { echo "$toolName notes"; } step_4_info() { echo "$toolName notes"; }
step_4_alias() { ALIAS="notes"; } step_4_alias() { echo "notes"; }
step_4() { step_4() {
cat <<NOTES_EOF cat <<NOTES_EOF
# Syslog not readable by librenms (https://github.com/fail2ban/fail2ban/issues/2734) # Syslog not readable by librenms (https://github.com/fail2ban/fail2ban/issues/2734)
@@ -78,12 +88,14 @@ NOTES_EOF
} }
step_20_info() { echo "Install mailserver jail"; } step_20_info() { echo "Install mailserver jail"; }
step_20_alias() { ALIAS="mail"; } step_20_alias() { echo "mail"; }
step_20() { step_20() {
addConf -s -f "$mailJail" "$toolJails/$(basename $mailJail)" local mailJail="$sq_configJails/mail.conf"
addConf -s -f "$mailJail" "$toolJails/$(basename -- "$mailJail")"
exe service $toolName restart exe service $toolName restart
} }
mailJail="$CONFIG_JAILS/mail.conf"
VERSION_SEQREV=11 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,13 +1,13 @@
#!/bin/bash #!/bin/bash
toolName="fhem" readonly toolName="fhem"
toolUser="$toolName" readonly toolUser="$toolName"
toolHome="/opt/fhem" readonly toolHome="/opt/fhem"
toolVersion="6.0" readonly toolVersion="6.1"
toolDpkg="fhem-${toolVersion}.deb" readonly toolDpkg="fhem-${toolVersion}.deb"
toolUrl="http://fhem.de/$toolDpkg" readonly toolUrl="http://fhem.de/${toolDpkg}"
# default deps listed at https://debian.fhem.de/ # default deps listed at https://debian.fhem.de/
toolDeps="perl-base libdevice-serialport-perl libwww-perl libio-socket-ssl-perl libcgi-pm-perl libjson-perl sqlite3 libdbd-sqlite3-perl libtext-diff-perl libtimedate-perl libmail-imapclient-perl libgd-graph-perl libtext-csv-perl libxml-simple-perl liblist-moreutils-perl fonts-liberation2 libimage-librsvg-perl libgd-text-perl libsocket6-perl libio-socket-inet6-perl libmime-base64-urlsafe-perl libimage-info-perl libusb-1.0-0-dev libnet-server-perl" readonly toolDeps="perl-base libdevice-serialport-perl libwww-perl libio-socket-ssl-perl libcgi-pm-perl libjson-perl sqlite3 libdbd-sqlite3-perl libtext-diff-perl libtimedate-perl libmail-imapclient-perl libgd-graph-perl libtext-csv-perl libxml-simple-perl liblist-moreutils-perl fonts-liberation2 libimage-librsvg-perl libgd-text-perl libsocket6-perl libio-socket-inet6-perl libmime-base64-urlsafe-perl libimage-info-perl libusb-1.0-0-dev libnet-server-perl"
toolDeps2="libdate-manip-perl libhtml-treebuilder-xpath-perl libmojolicious-perl libxml-bare-perl libauthen-oath-perl libconvert-base32-perl libmodule-pluggable-perl libnet-bonjour-perl libcrypt-urandom-perl" toolDeps2="libdate-manip-perl libhtml-treebuilder-xpath-perl libmojolicious-perl libxml-bare-perl libauthen-oath-perl libconvert-base32-perl libmodule-pluggable-perl libnet-bonjour-perl libcrypt-urandom-perl"
# for rounding operations e.g.: # for rounding operations e.g.:
# { use Math::Round qw/nearest/;; nearest('0.01',ReadingsVal("1WT_28_5728E9070000", "temperature", 0)-1.1);; } # { use Math::Round qw/nearest/;; nearest('0.01',ReadingsVal("1WT_28_5728E9070000", "temperature", 0)-1.1);; }
@@ -15,15 +15,8 @@ toolDeps2+=" libmath-round-perl"
# for fritzbox connection # for fritzbox connection
toolDeps2+=" libsoap-lite-perl libjson-xs-perl" toolDeps2+=" libsoap-lite-perl libjson-xs-perl"
# for xmpp support (no special solution needed for raspbian buster) # for xmpp support (no special solution needed for raspbian buster)
toolDeps2+=" libnet-xmpp-perl libxml-stream-perl libnet-jabber-perl" toolDepsJabber=" libnet-xmpp-perl libxml-stream-perl libnet-jabber-perl"
aptOpt=
# Get script working directory
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
WSUBDIR="${WDIR}/${toolName}"
#CONFIG_FILE="$WDIR/${toolName}.cfg"
#CONFIG_FILE_DEFAULT="${CONFIG_FILE}.example"
#step_config() { #step_config() {
# echo "Called once before executing steps." # echo "Called once before executing steps."
@@ -32,43 +25,45 @@ WSUBDIR="${WDIR}/${toolName}"
#} #}
step_1_info() { echo "Install prerequisits for $toolName"; } step_1_info() { echo "Install prerequisits for $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local aptOpt= local aptOpt=
if [ $QUIET != 0 ] ; then if quiet ; then
aptOpt="-y" aptOpt="-y"
fi fi
#exe apt update #exe apt update
exe apt install $toolDeps $toolDeps2 "$aptOpt" exe apt install $toolDeps $toolDeps2 "$aptOpt"
#exe apt install "$toolDeps2" "$aptOpt" #exe apt install "$toolDeps2" "$aptOpt"
endReturn -o $? "Installation of prerequisits failed" endReturn "Installation of prerequisits failed"
} }
step_2_info() { echo "Download and install $toolName version $toolVersion"; } step_2_info() { echo "Install jabber prerequisits"; echoinfo "(May be skipped)"; }
step_2() { step_2() {
exe apt install $toolDepsJabber "$aptOpt"
endReturn "Installation of prerequisits for jabber failed"
}
step_3_info() { echo "Download and install $toolName version $toolVersion"; }
step_3() {
exe wget "$toolUrl" -O "$downPath" exe wget "$toolUrl" -O "$downPath"
endReturn -o $? "Download of $toolName failed" endReturn "Download of $toolName failed"
exe dpkg -i "$downPath" exe dpkg -i "$downPath"
endReturn -o $? "Installation of $toolName failed" endReturn "Installation of $toolName failed"
info "$toolName is now running on http://$(hostname -I | cut -d " " -f 1):8083"
} }
downPath="/tmp/$toolDpkg" downPath="/tmp/$toolDpkg"
step_3_info() { echo "Start $toolName service"; }
step_3() {
exe systemctl restart fhem.service
}
step_20_info() { echo "List $toolName prerequisits"; } step_20_info() { echo "List $toolName prerequisits"; }
step_20_alias() { ALIAS="listdeps"; } step_20_alias() { echo "listdeps"; }
step_20() { step_20() {
echo " [I] $toolName prerequisits:" info "$toolName prerequisits:"
echo "$toolDeps $toolDeps2" echo "$toolDeps $toolDeps2"
} }
step_30_info() { echo "Create user $toolUser"; } step_30_info() { echo "Create user $toolUser"; }
step_30() { step_30() {
exe useradd --system --home "$toolHome" --gid dialout --shell /bin/false "$toolUser" exe useradd --system --home "$toolHome" --gid dialout --shell /bin/false "$toolUser"
endReturn -o $? "Creating user $toolUser failed" endReturn "Creating user $toolUser failed"
} }
step_32_info() { echo "Create $toolName systemd service"; } step_32_info() { echo "Create $toolName systemd service"; }
@@ -79,19 +74,19 @@ step_32() {
systemdConfigLoc="/etc/systemd/system" systemdConfigLoc="/etc/systemd/system"
step_34_info() { echo "Downgrade $toolName jabber dependencies (callbackIQ -> FHEM crash)"; } step_34_info() { echo "Downgrade $toolName jabber dependencies (callbackIQ -> FHEM crash)"; }
step_34_alias() { ALIAS="downgrade_xmpp"; } step_34_alias() { echo "downgrade_xmpp"; }
step_34() { step_34() {
if [ ! -f $libnetDown ]; then if [ ! -f $libnetDown ]; then
exe wget "$libnetUrl" -O "$libnetDown" exe wget "$libnetUrl" -O "$libnetDown"
endReturn -o $? "Download of $libnetUrl failed" endReturn "Download of $libnetUrl failed"
fi fi
if [ ! -f $libxmlDown ]; then if [ ! -f $libxmlDown ]; then
exe wget "$libxmlUrl" -O "$libxmlDown" exe wget "$libxmlUrl" -O "$libxmlDown"
endReturn -o $? "Download of $libxmlUrl failed" endReturn "Download of $libxmlUrl failed"
fi fi
local aptOption= local aptOption=
if [ $QUIET -ne 0 ] ; then if quiet ; then
aptOption="-y" aptOption="-y"
else else
aptOption="" aptOption=""
@@ -136,7 +131,7 @@ Pin: version 1.23-2
Pin-Priority: 1000" Pin-Priority: 1000"
step_37_info() { echo "Download latest speedtest python script"; } step_37_info() { echo "Download latest speedtest python script"; }
step_37_alias() { ALIAS="speedtestdownload"; } step_37_alias() { echo "speedtestdownload"; }
step_37() { step_37() {
local lSpeedPath="/usr/local/bin/speedtest-cli" local lSpeedPath="/usr/local/bin/speedtest-cli"
exe wget -O "$lSpeedPath" https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py exe wget -O "$lSpeedPath" https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py
@@ -144,11 +139,11 @@ step_37() {
} }
step_40_info() { echo "Execute fhem [COMMAND]"; } step_40_info() { echo "Execute fhem [COMMAND]"; }
step_40_alias() { ALIAS="exe"; } step_40_alias() { echo "exe"; }
step_40() { step_40() {
shift shift
exe perl "${toolHome}/fhem.pl" 7072 "$1" exe perl "${toolHome}/fhem.pl" 7072 "$*"
} }
VERSION_SEQREV=11 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -13,33 +13,33 @@ SCRIPT_NAME=${SCRIPT_FILE%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg" CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
## or to use sequencer api with profile config file support: ## or to use sequencer api with profile config file support:
initSeqConfig "$SCRIPT_NAME" "$CONFIG_FILE_TEMPLATE" initSeqConfig "$SCRIPT_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
CONFIG=1 CONFIG=1
echoseq " [I] Freeradius DB: $FRAD_DB_NAME" info "Freeradius DB: $FRAD_DB_NAME"
echoseq " Daloradius home: $DRAD_HOME" info " Daloradius home: $DRAD_HOME"
else else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return -1 dry || return -1
fi fi
## Apt cmdline option to suppress user interaction ## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y" quiet && APTOPT="-y"
## Return of non zero value will abort the sequence ## Return of non zero value will abort the sequence
return 0 return 0
} }
step_50_info() { echo "Init freeradius and daloradius database"; } step_50_info() { echo "Init freeradius and daloradius database"; }
step_50_alias() { ALIAS="initdb"; } step_50_alias() { echo "initdb"; }
step_50() { step_50() {
local drDbInit="$DRAD_HOME/contrib/db/mysql-daloradius.sql" local drDbInit="$DRAD_HOME/contrib/db/mysql-daloradius.sql"
local frDbSchema="$toolConfLoc/mods-config/sql/main/mysql/schema.sql" local frDbSchema="$toolConfLoc/mods-config/sql/main/mysql/schema.sql"
local frDbSetup="$toolConfLoc/mods-config/sql/main/mysql/setup.sql" local frDbSetup="$toolConfLoc/mods-config/sql/main/mysql/setup.sql"
exe "$WDIR"/mysql.sh createdb -c utf8 -d "$FRAD_DB_NAME" -u "$FRAD_DB_USER" exe "$WDIR"/mysql.sh createdb -c utf8 -d "$FRAD_DB_NAME" -u "$FRAD_DB_USER"
endReturn -o $? "Creating database failed" endReturn "Creating database failed"
exep "mysql -uroot \"$FRAD_DB_NAME\" < $frDbSchema" exep "mysql -uroot \"$FRAD_DB_NAME\" < $frDbSchema"
#exep "mysql -uroot \"$FRAD_DB_NAME\" < $frDbSetup" #exep "mysql -uroot \"$FRAD_DB_NAME\" < $frDbSetup"
@@ -48,20 +48,20 @@ step_50() {
step_52_info() { echo "Reset freeradius and daloradius database"; } step_52_info() { echo "Reset freeradius and daloradius database"; }
step_52_alias() { ALIAS="resetdb"; } step_52_alias() { echo "resetdb"; }
step_52() { step_52() {
local lAnswer local lAnswer
if [ $QUIET -eq 0 ]; then if interactive; then
read -p "Do you really want to reset the database $FRAD_DB_NAME y/[n]? " lAnswer read -p "Do you really want to reset the database $FRAD_DB_NAME y/[n]? " lAnswer
else else
lAnswer=y lAnswer=y
fi fi
case "$lAnswer" in case "$lAnswer" in
[yY]) [yY])
echoseq -n " [I] Reseting DB...";; sqr::echo -n " [I] Reseting DB...";;
*) *)
echoerr " [I] Abort reset" info -e "Abort reset"
return 1;; return 1;;
esac esac
@@ -69,5 +69,5 @@ step_52() {
step initdb step initdb
} }
VERSION_SEQREV=13 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,98 +1,94 @@
#!/bin/bash #!/bin/bash
toolName=friendica readonly toolName=friendica
latestUrl="https://api.github.com/repos/friendica/friendica/releases/latest" readonly latestUrl="https://api.github.com/repos/friendica/friendica/releases/latest"
# Get script working directory sq_config=0
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" initSeqConfig "${seq_configName}" "${seq_configTemplate}"
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
CONFIG=1 sq_config=1
fi fi
} }
step_20_info() { step_20_info() {
shift shift
echoinfoArgs "[FRIENDICA ROOT]"
echo -n "Create a backup" echo -n "Create a backup"
if [ $CONFIG -ne 0 ] ; then if (( sq_config )) ; then
echo " at $FR_BACKUP" echo " at $FR_BACKUP"
else else
echo echo
fi fi
} }
step_20_alias() { ALIAS="backup"; } step_20_options() { echo "[FRIENDICA ROOT]"; }
step_20_alias() { echo "backup"; }
step_20() { step_20() {
shift shift
local tempRoot= local tempRoot=
if [ $CONFIG -eq 0 ] ; then if (( ! sq_config )) ; then
echoerr " [E] No configuration file found" error -e "No configuration file found"
return 1 return 1
fi fi
if [ ! -z $FR_BACKUP ] ; then if [ -n "$FR_BACKUP" ] ; then
exe mkdir -p "$FR_BACKUP" exe mkdir -p "$FR_BACKUP"
fi fi
if [ ! -z "$1" ] ; then if [ -n "${1:-}" ] ; then
tempRoot="$1" tempRoot="$1"
else else
tempRoot="$FR_LOC" tempRoot="$FR_LOC"
fi fi
exe $WDIR/mysql.sh -qq backup "$FR_DATABASE" "$FR_BACKUP" exe "${seq_dir}/mysql.sh" -qq backup "$FR_DATABASE" "$FR_BACKUP"
endReturn -o $? "Backup mysql database failed" endReturn "Backup mysql database failed"
[ ! -e "$tempRoot" ] && endReturn -o 1 -f "Friendica root $tempRoot not found" [ ! -e "$tempRoot" ] && endReturn -o 1 -f "Friendica root $tempRoot not found"
local wwwBackup="$FR_BACKUP/${toolName}_www_`date +%Y%m%d-%H%M%S`.tar.gz" local wwwBackup="$FR_BACKUP/${toolName}_www_`date +%Y%m%d-%H%M%S`.tar.gz"
local dataBackup="$FR_BACKUP/${toolName}_data_`date +%Y%m%d-%H%M%S`.tar.gz" local dataBackup="$FR_BACKUP/${toolName}_data_`date +%Y%m%d-%H%M%S`.tar.gz"
echo " [I] Backing up webserver directory to $wwwBackup" info "Backing up webserver directory to $wwwBackup"
exe cd "$tempRoot/.." exe cd "$tempRoot/.."
exe tar czf "$wwwBackup" $(basename "$tempRoot") exe tar czf "$wwwBackup" $(basename "$tempRoot")
echo " [I] Backing up data directory to $dataBackup" info "Backing up data directory to $dataBackup"
exe cd "$FR_LOC_DATA/.." exe cd "$FR_LOC_DATA/.."
exe tar czf "$dataBackup" $(basename "$FR_LOC_DATA") exe tar czf "$dataBackup" $(basename "$FR_LOC_DATA")
} }
step_22_info() { step_22_info() {
shift shift
if [ -z $1 ] ; then if [ -z "${1:-}" ] ; then
echo -n "Get latest version from github" echo -n "Get latest version from github"
if [ $CONTEXT_HELP -eq 0 ] ; then if ! contextHelp ; then
echo ": $(curl --silent "$latestUrl" | grep -Po '"tag_name": "\K.*?(?=")')" echo ": $(curl --silent "$latestUrl" | grep -Po '"tag_name": "\K.*?(?=")')"
else else
echo " [CUSTOM VERSION]" echo
fi fi
else else
echo "Get version $1 from github" echo "Get version $1 from github"
fi fi
} }
step_22_alias() { ALIAS="upgrade"; } step_22_options() { echo "[CUSTOM VERSION]"; }
step_22_alias() { echo "upgrade"; }
step_22() { step_22() {
shift # don't need step number shift # don't need step number
local latestVersion= local latestVersion=
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
latestVersion="$1" latestVersion="$1"
else else
latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "\K.*?(?=")') latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "\K.*?(?=")')
fi fi
if [ -z $latestVersion ] ; then if [ -z $latestVersion ] ; then
echoerr " [E] Cannot determine latest version from github repository" error -e "Cannot determine latest version from github repository"
return 1 return 1
elif [ $QUIET -eq 0 ] ; then elif interactive ; then
echo echo
exe read -p "Install $latestVersion to $FR_LOC [n]o/(y)es? " answer exe read -p "Install $latestVersion to $FR_LOC [n]o/(y)es? " answer
case $answer in case $answer in
[yY]) [yY])
;; ;;
*) *)
echoerr " [I] Upgrade aborted" info -e "Upgrade aborted"
return 1 return 1
;; ;;
esac esac
@@ -100,7 +96,7 @@ step_22() {
local isInstalled=$(grep -E "Version $latestVersion" "${FR_LOC}/CHANGELOG" >>/dev/null && echo "1" || echo "0") local isInstalled=$(grep -E "Version $latestVersion" "${FR_LOC}/CHANGELOG" >>/dev/null && echo "1" || echo "0")
if [ $isInstalled -eq 1 ] ; then if [ $isInstalled -eq 1 ] ; then
echoerr " [E] Version $latestVersion is already installed" error -e "Version $latestVersion is already installed"
return 2 return 2
fi fi
@@ -114,23 +110,23 @@ step_22() {
if [ ! -e "$tempExtract" ] ; then if [ ! -e "$tempExtract" ] ; then
exe mkdir -p "$tempDown" exe mkdir -p "$tempDown"
exe wget -O "$tempLoc" $downUrl exe wget -O "$tempLoc" $downUrl
endReturn -o $? "Download failed: $downUrl" endReturn "Download failed: $downUrl"
exe cd "$tempDown" exe cd "$tempDown"
exe tar -xf "$tempLoc" exe tar -xf "$tempLoc"
endReturn -o $? "Extract failed: $tempLoc" endReturn "Extract failed: $tempLoc"
else else
echo " [I] Found existing download: $tempExtract" info "Found existing download: $tempExtract"
fi fi
if [ ! -e "$tempExtractAddons" ] ; then if [ ! -e "$tempExtractAddons" ] ; then
exe wget -O "$tempLocAddons" $downUrlAddons exe wget -O "$tempLocAddons" $downUrlAddons
endReturn -o $? "Download failed: $downUrlAddons" endReturn "Download failed: $downUrlAddons"
exe cd "$tempDown" exe cd "$tempDown"
exe mkdir -p "$tempExtractAddons" exe mkdir -p "$tempExtractAddons"
exe tar -xC "${tempExtractAddons}" -f "$tempLocAddons" exe tar -xC "${tempExtractAddons}" -f "$tempLocAddons"
endReturn -o $? "Extract failed: $tempLocAddons" endReturn "Extract failed: $tempLocAddons"
else else
echo " [I] Found existing download: $tempExtractAddons" info "Found existing download: $tempExtractAddons"
fi fi
# Installation # Installation
@@ -138,15 +134,16 @@ step_22() {
local tempAddons="${FR_LOC}/addon" local tempAddons="${FR_LOC}/addon"
exe mv "$FR_LOC" "$tempBu" exe mv "$FR_LOC" "$tempBu"
exe systemctl stop friendica.service
step backup "$tempBu" step backup "$tempBu"
endReturn -o $? "Backup failed; $FR_LOC renamed!" endReturn "Backup failed; $FR_LOC renamed!"
echo " [I] Installing version $latestVersion to $FR_LOC" info "Installing version $latestVersion to $FR_LOC"
exe mv "$tempExtract" "$FR_LOC" exe mv "$tempExtract" "$FR_LOC"
exe mv "$tempExtractAddons" "$tempAddons" exe mv "$tempExtractAddons/addon" "$tempAddons"
exe chown -R www-data: "$FR_LOC" exe chown -R www-data: "$FR_LOC"
# Configuration # Configuration
echo " [I] Copying configuration" info "Copying configuration"
exe cp -ar "$tempBu/config/local.config.php" "$FR_LOC/config/" exe cp -ar "$tempBu/config/local.config.php" "$FR_LOC/config/"
if [ -f "$tempBu/config/addon.config.php" ]; then if [ -f "$tempBu/config/addon.config.php" ]; then
exe cp -ar "$tempBu/config/addon.config.php" "$FR_LOC/config/" exe cp -ar "$tempBu/config/addon.config.php" "$FR_LOC/config/"
@@ -156,17 +153,58 @@ step_22() {
exe cp -ar "$tempBu/home".* "$FR_LOC/" exe cp -ar "$tempBu/home".* "$FR_LOC/"
fi fi
echo " [I] Don't forget to \"clean\" if everything is working as expected" exe systemctl start friendica.service
info "Don't forget to \"clean\" if everything is working as expected"
} }
tempDown="/tmp/friendica" tempDown="/tmp/friendica"
tempLoc="$tempDown/fr.tar.gz" tempLoc="$tempDown/fr.tar.gz"
tempLocAddons="$tempDown/fradd.tar.gz" tempLocAddons="$tempDown/fradd.tar.gz"
step_24_info() { echo "Clean temporary files: $tempDown"; } step_24_info() { echo "Clean temporary files: $tempDown"; }
step_24_alias() { ALIAS="clean"; } step_24_alias() { echo "clean"; }
step_24() { step_24() {
exe rm -rf "$tempDown" exe rm -rf "$tempDown"
} }
VERSION_SEQREV=14 step_40_info() { echo 'Notes'; }
step_40_alias() { echo 'notes'; }
step_40() {
color green
cat <<NOTES_END
* Disable cron setup
* Add configuration to local.config.php
'system' => [
[...]
'pidfile' => '/run/friendica/daemon.pid',
],
* Install Service file
[Unit]
Description=Friendica Worker Daemon
After=network.target mariadb.service
[Service]
Type=simple
Restart=always
User=www-data
Group=www-data
RuntimeDirectory=friendica
WorkingDirectory=${FR_LOC}
ExecStart=/usr/bin/php ./bin/daemon.php start
ExecStop=/usr/bin/php ./bin/daemon.php stop
PIDFile=friendica/daemon.pid
[Install]
WantedBy=multi-user.target
* RuntimeDirectory: creates a folder below \`/run\`
NOTES_END
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,36 +1,7 @@
#!/bin/bash #!/bin/bash
toolName=git
# Get script working directory
# (when called from a different directory and even when called via symlink)
WDIR="$(cd "$(dirname -- "$(realpath ${BASH_SOURCE[0]})")" >>/dev/null 2>&1 && pwd)"
APTOPT=
CONFIG=0
SCRIPT_FILE=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_FILE%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() {
## or to use sequencer api with global config file:
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
#if [ $? -eq 0 ] ; then
# CONFIG=1
#else
# # End if no configuration file exists
# [ $DRY -eq 0 ] && return -1
#fi
## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y"
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Setup global git aliases"; } step_1_info() { echo "Setup global git aliases"; }
step_1_alias() { ALIAS="alias"; } step_1_alias() { echo "alias"; }
step_1() { step_1() {
local brConf="branch \ local brConf="branch \
--format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - \ --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - \
@@ -48,5 +19,7 @@ step_1() {
exe git config --global alias.ll 'log' exe git config --global alias.ll 'log'
} }
VERSION_SEQREV=15 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -3,86 +3,70 @@
# #
## Installation of self hosted git service Gitea ## Installation of self hosted git service Gitea
toolName="gitea" readonly toolName="gitea"
# Get script working directory readonly giteaLatestUrl="https://api.github.com/repos/go-gitea/gitea/releases/latest"
# (when called from a different directory) readonly giteaVersion=$(curl --silent "$giteaLatestUrl" | grep -Po '"tag_name": "v\K.*?(?=")')
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)" readonly giteaDir="/usr/local/bin"
APTOPT= readonly giteaServiceLoc="/etc/systemd/system/gitea.service"
CONFIG=0 readonly giteaLogDir="/var/log/gitea"
SCRIPT_FILE=$(basename -- $0) readonly giteaDownFile="/tmp/giteaDown"
SCRIPT_NAME=${SCRIPT_FILE%%.*} readonly giteaUser="git"
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
giteaLatestUrl="https://api.github.com/repos/go-gitea/gitea/releases/latest"
giteaVersion=$(curl --silent "$giteaLatestUrl" | grep -Po '"tag_name": "v\K.*?(?=")')
giteaArch= giteaArch=
giteaDownloadEval='https://dl.gitea.io/gitea/${giteaVersion}/gitea-${giteaVersion}-linux-${giteaArch}' giteaDownloadEval='https://dl.gitea.io/gitea/${giteaVersion}/gitea-${giteaVersion}-linux-${giteaArch}'
giteaDownload=$(eval echo $giteaDownloadEval) giteaDownload=$(eval echo $giteaDownloadEval)
giteaDir="/usr/local/bin"
giteaServiceLoc="/etc/systemd/system/gitea.service"
giteaLogDir="/var/log/gitea"
giteaIniLoc= giteaIniLoc=
giteaDownFile="/tmp/giteaDown"
giteaUser="git"
versionNow= versionNow=
step_config() { seq_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then
CONFIG=1
else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return -1 dry || return 1
fi fi
## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y"
if [ -z $giteaVersion ] ; then if [ -z $giteaVersion ] ; then
echoerr " [E] Couldn't determine latest version of $toolName" error -e "Couldn't determine latest version of $toolName"
fi fi
[ ! -z "$(command -v gitea)" ] && versionNow=$(gitea --version | sed 's/.*version \([0-9.]\+\).*/\1/') [ ! -z "$(command -v gitea)" ] && versionNow=$(gitea --version | sed 's/.*version \([0-9.]\+\).*/\1/')
checkArchitecture checkArchitecture
giteaIniLoc="${SEQ_GITEA_CONF_DIR}/app.ini" giteaIniLoc="${SEQ_GITEA_CONF_DIR}/app.ini"
echoseq " [I] Gitea work: $SEQ_GITEA_WORK_DIR" info "Gitea work: $SEQ_GITEA_WORK_DIR"
echoseq " Gitea config: $SEQ_GITEA_CONF_DIR" info -a "Gitea config: $SEQ_GITEA_CONF_DIR"
echoseq " Git user home: $SEQ_GITEA_HOME_DIR" info -a "Git user home: $SEQ_GITEA_HOME_DIR"
echoseq info
outColor yellow color yellow
echoseq " [W] Don't forget to adapt $SEQ_GITEA_CONF_DIR/app.ini" warning "Don't forget to adapt $SEQ_GITEA_CONF_DIR/app.ini"
outColor color
## Return of non zero value will abort the sequence ## Return of non zero value will abort the sequence
return 0 return 0
} }
checkArchitecture() { checkArchitecture() {
[ -n "$giteaArch" ] && return 0
[ ! -z "$(command -v dpkg)" ] && giteaArch=$(dpkg --print-architecture) [ ! -z "$(command -v dpkg)" ] && giteaArch=$(dpkg --print-architecture)
case $giteaArch in case $giteaArch in
armhf) armhf)
giteaArch="arm-6";; giteaArch="arm-6";;
esac esac
giteaDownload=$(eval echo $giteaDownloadEval) giteaDownload="$(eval echo $giteaDownloadEval)"
} }
step_1_info() { echo "Updating apt"; } step_1_info() { echo "Updating apt"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
} }
step_2_info() { step_2_info() {
[ -z "$giteaArch" ] && checkArchitecture checkArchitecture
echo "Downloading $toolName to user home from:" echo "Downloading $toolName to user home from:"
echoinfo "$giteaDownload" echoinfo "$giteaDownload"
} }
step_2() { step_2() {
exe wget -O "$giteaDownFile" $giteaDownload exe wget -O "$giteaDownFile" $giteaDownload
saveReturn $?
endReturn
} }
step_3_info() { echo "Adding user for $toolName ($giteaUser)"; } step_3_info() { echo "Adding user for $toolName ($giteaUser)"; }
@@ -95,8 +79,6 @@ step_3() {
--disabled-password \ --disabled-password \
--home "$SEQ_GITEA_HOME_DIR" \ --home "$SEQ_GITEA_HOME_DIR" \
"$SEQ_GITEA_USER" "$SEQ_GITEA_USER"
saveReturn $?
endReturn
} }
step_4_info() { echo "Create required directory structure"; } step_4_info() { echo "Create required directory structure"; }
@@ -106,10 +88,10 @@ step_4() {
"$SEQ_GITEA_HOME_DIR" "$SEQ_GITEA_WORK_DIR"/{custom,data,log} "$SEQ_GITEA_HOME_DIR" "$SEQ_GITEA_WORK_DIR"/{custom,data,log}
exe chown root:$SEQ_GITEA_USER "$SEQ_GITEA_CONF_DIR" exe chown root:$SEQ_GITEA_USER "$SEQ_GITEA_CONF_DIR"
exe chmod 770 $SEQ_GITEA_CONF_DIR exe chmod 770 $SEQ_GITEA_CONF_DIR
echoseq "Creating $giteaLogDir" info "Creating $giteaLogDir"
exe install -g $SEQ_GITEA_USER -m 770 -d "$giteaLogDir" exe install -g $SEQ_GITEA_USER -m 770 -d "$giteaLogDir"
echoseq -n "Copying gitea to global location and making it executable..." info -n "Copying gitea to global location and making it executable..."
exe install -b -m 755 -T "$giteaDownFile" "$SEQ_GITEA_BIN_LOC" && echo "ok" exe install -b -m 755 -T "$giteaDownFile" "$SEQ_GITEA_BIN_LOC" && info -d "ok"
endReturn "Failed to install $SEQ_GITEA_BIN_LOC" endReturn "Failed to install $SEQ_GITEA_BIN_LOC"
} }
@@ -121,17 +103,17 @@ step_5() {
step_6_info() { echo "Starting $toolName service"; } step_6_info() { echo "Starting $toolName service"; }
step_6() { step_6() {
exe systemctl enable gitea --now exe systemctl enable gitea --now
echoseq "Before proceeding to installation you may need to create a database first with step 10" info "Before proceeding to installation you may need to create a database first with step 10"
echoseq info
echoseq "Goto http://[yourip]:3000/install and complete installation" info "Goto http://[yourip]:3000/install and complete installation"
echoseq info
echoseq "Afterwards please execute step 20 to secure configuration" info "Afterwards please execute step 20 to secure configuration"
} }
step_7_info() { echo "Show configuration notes"; } step_7_info() { echo "Show configuration notes"; }
step_7_alias() { ALIAS="notes"; } step_7_alias() { echo "notes"; }
step_7() { step_7() {
outColor green color green
cat <<NOTES_END cat <<NOTES_END
Final configuration notes for $giteaIniLoc: Final configuration notes for $giteaIniLoc:
@@ -158,7 +140,7 @@ NOTES_END
step_10_info() { echo "Create mysql database for $toolName"; } step_10_info() { echo "Create mysql database for $toolName"; }
step_10() { step_10() {
exe "$WDIR/mysql.sh" -qq createdb --charset utf8mb4 exe "${seq_origin}/mysql.sh" -qq createdb --charset utf8mb4
} }
step_12_info() { step_12_info() {
@@ -173,22 +155,22 @@ step_12_info() {
echo "Upgrade existing $toolName installation" echo "Upgrade existing $toolName installation"
fi fi
} }
step_12_alias() { ALIAS="upgrade"; } step_12_alias() { echo "upgrade"; }
step_12() { step_12() {
endCheckEmpty versionNow "Please install $toolName first" endIfEmpty versionNow "Please install $toolName first"
exe wget -O "$giteaDownFile" $giteaDownload exe wget -O "$giteaDownFile" $giteaDownload
endReturn -o $? "Download failed" endReturn "Download failed"
if [ -f "$SEQ_GITEA_BIN_LOC" ] ; then if [ -f "$SEQ_GITEA_BIN_LOC" ] ; then
local toolBackup="${SEQ_GITEA_BACKUP_DIR}/gitea_${versionNow}" local toolBackup="${SEQ_GITEA_BACKUP_DIR}/gitea_${versionNow}"
exe service gitea stop exe service gitea stop
saveReturn $? saveReturn $?
endReturn endReturn
echoseq -n "Backing up existing executable to ${toolBackup}..." sqr::echo -n "Backing up existing executable to ${toolBackup}..."
exe cp -ar "$SEQ_GITEA_BIN_LOC" "$toolBackup" && echoseq "ok" || echoseq "nok" exe cp -ar "$SEQ_GITEA_BIN_LOC" "$toolBackup" && sqr::echo "ok" || sqr::echo "nok"
fi fi
exe install --backup=none -m 755 -T "$giteaDownFile" "$SEQ_GITEA_BIN_LOC" exe install --backup=none -m 755 -T "$giteaDownFile" "$SEQ_GITEA_BIN_LOC"
endReturn -o $? "Upgrade failed" endReturn "Upgrade failed"
exe service gitea start exe service gitea start
} }
@@ -199,10 +181,12 @@ step_20() {
} }
step_22_info() { echo "Open $toolName config file"; } step_22_info() { echo "Open $toolName config file"; }
step_22_alias() { ALIAS="config"; } step_22_alias() { echo "config"; }
step_22() { step_22() {
exe vi "$giteaIniLoc" exe vi "$giteaIniLoc"
} }
VERSION_SEQREV=14 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -13,31 +13,24 @@ sc_grocyConf=
sc_grocyBackup="data/backup" sc_grocyBackup="data/backup"
sc_grocyViewcache="data/viewcache" sc_grocyViewcache="data/viewcache"
grocyDownLoc="/tmp/grocy_latest.zip" sq_grocyDownLoc="/tmp/grocy_latest.zip"
# Get script working directory
# (when called from a different directory and even when called via symlink)
readonly sq_dir="$(cd "$(dirname -- "$(realpath ${BASH_SOURCE[0]})")" >>/dev/null 2>&1 && pwd)"
readonly sq_scriptFile=$(basename -- $0)
readonly sq_scriptName=${sq_scriptFile%%.*}
readonly sq_configFileName="${sq_scriptName}.cfg"
readonly sq_configFileTemplate="$sq_dir/${sq_configFileName}.example"
sq_aptOpt= sq_aptOpt=
sq_config=0 sq_config=0
step_config() { seq_config() {
initSeqConfig -p "$sq_scriptName" "$sq_configFileTemplate" initSeqConfig -p "$seq_fileName" "$seq_configTemplate"
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
sq_config=1 sq_config=1
else else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return -1 dry || return 1
fi fi
sc_grocyConf="${sc_grocyDir}/data/config.php" # config not sourced if only profiles should be listed
sc_grocyConf="${sc_grocyDir:-}/data/config.php"
## Apt cmdline option to suppress user interaction ## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && sq_aptOpt="-y" quiet && sq_aptOpt="-y"
## Return of non zero value will abort the sequence ## Return of non zero value will abort the sequence
return 0 return 0
@@ -52,21 +45,21 @@ step_1_info() {
echo "Check $toolName status" echo "Check $toolName status"
echoinfo "Returns 1 if update is available" echoinfo "Returns 1 if update is available"
} }
step_1_alias() { ALIAS="status"; } step_1_alias() { echo "status"; }
step_1() { step_1() {
getVersions getVersions
if [ -e "${sc_grocyDir}" ] ; then if [ -e "${sc_grocyDir}" ] ; then
echo info
echo "$toolName installed" info "$toolName installed"
echo " at: ${sc_grocyDir}" info -a " at: ${sc_grocyDir}"
echo " version: ${versionNow}" info -a " version: ${versionNow}"
echo " config: ${sc_grocyConf}" info -a " config: ${sc_grocyConf}"
echo -n " update: " info -an " update: "
if [[ ! ${versionNow} = ${versionNew} ]] ; then if [[ ! ${versionNow} = ${versionNew} ]] ; then
echo "available: ${versionNew}}" info -d "available: ${versionNew}"
return 1 return 1
else else
echo "already on latest" info -d "already on latest"
return 0 return 0
fi fi
else else
@@ -77,7 +70,7 @@ step_1() {
} }
step_20_info() { echo "Backup ${toolName}"; } step_20_info() { echo "Backup ${toolName}"; }
step_20_alias() { ALIAS="backup"; } step_20_alias() { echo "backup"; }
step_20() { step_20() {
local lBu="${sc_grocyDir}/${sc_grocyBackup}/${toolName}_$(date +%Y%m%d-%H%M%S).tgz" local lBu="${sc_grocyDir}/${sc_grocyBackup}/${toolName}_$(date +%Y%m%d-%H%M%S).tgz"
exe cd ${sc_grocyDir}/.. exe cd ${sc_grocyDir}/..
@@ -89,40 +82,40 @@ step_20() {
} }
step_22_info() { echo "Install/upgrade ${toolName}"; } step_22_info() { echo "Install/upgrade ${toolName}"; }
step_22_alias() { ALIAS="install"; } step_22_alias() { echo "install"; }
step_22() { step_22() {
getVersions getVersions
if [[ ${versionNow} == ${versionNew} ]] ; then if [[ ${versionNow} == ${versionNew} ]] ; then
endReturn -o 1 "Latest version ${versionNow} already installed" endReturn -o 1 "Latest version ${versionNow} already installed"
else else
if [ -n "${versionNow}" ] ; then if [ -n "${versionNow}" ] ; then
echoseq " [I] Upgrading $toolName from ${versionNow} to ${versionNew}" info "Upgrading $toolName from ${versionNow} to ${versionNew}"
else else
echoseq " [I] Installing $toolName version ${versionNew}" info "Installing $toolName version ${versionNew}"
fi fi
fi fi
exe wget ${downUrl} -q -O "${grocyDownLoc}" exe wget ${downUrl} -q -O "${sq_grocyDownLoc}"
endReturn -o $? "Download failed" endReturn "Download failed"
if [ -e "${sc_grocyDir}" ] ; then if [ -e "${sc_grocyDir}" ] ; then
step backup step backup
exe rm -rf "${sc_grocyDir}/${sc_grocyViewcache}" exe rm -rf "${sc_grocyDir}/${sc_grocyViewcache}"
fi fi
exe rm -rf "${sc_grocyDir}/"!(data) exe rm -rf "${sc_grocyDir}/"!(data)
exe unzip -o -qq "${grocyDownLoc}" -d "${sc_grocyDir}" exe unzip -o -qq "${sq_grocyDownLoc}" -d "${sc_grocyDir}"
exe chown -R www-data: "${sc_grocyDir}/public" "${sc_grocyDir}/data" exe chown -R www-data: "${sc_grocyDir}/public" "${sc_grocyDir}/data"
# Populate first config # Populate first config
if [ ! -e "${sc_grocyConf}" ] ; then if [ ! -e "${sc_grocyConf}" ] ; then
exe cp "${sc_grocyDir}/config-dist.php" "${sc_grocyConf}" exe cp "${sc_grocyDir}/config-dist.php" "${sc_grocyConf}"
echoseq " [I] Please adjust the config: ${sc_grocyConf}" info "Please adjust the config: ${sc_grocyConf}"
else else
echoseq " [I] Please check ${sc_grocyDir}/config-dist.php" info "Please check ${sc_grocyDir}/config-dist.php"
echoseq " for new configuration options" info " for new configuration options"
fi fi
} }
step_30_alias() { ALIAS="notes"; } step_30_alias() { echo "notes"; }
step_30() { step_30() {
outColor green color green
cat <<NOTES_END cat <<NOTES_END
# Behind reverse proxy as subfolder # Behind reverse proxy as subfolder
@@ -162,5 +155,5 @@ server {
NOTES_END NOTES_END
} }
VERSION_SEQREV=15 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
readonly sc_haUser="homeassistant"
readonly sc_haVenv="/srv/homeassistant"
# Additional pip packages (homeassistant already included)
readonly sc_haDeps=()

137
seqs/homeassistant.sh Executable file
View File

@@ -0,0 +1,137 @@
#!/usr/bin/env bash
# Homeassistant core
readonly toolName="homeassistant"
readonly toolService="home-assistant"
# Already defined by sequencer.sh, but may be overwritten
#readonly seq_configName="${sq_scriptName:?}.cfg"
#readonly seq_configTemplate="${seq_origin:?}/${sq_configName:?}.example"
sq_aptOpt=
sq_config=0
seq_config() {
## or to use sequencer api with global config file:
if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
# End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Return of non zero value will abort the sequence
return 0
}
step_4_info() { echo 'Create home-assistant venv'; }
step_4_alias() { echo 'venv'; }
step_4_options() { echo '[PYTHON BINARY]'; }
step_4() {
shift
local pyBin="python3"
[ -d "${sc_haVenv}" ] && die "${toolName} venv already exists"
[ -f "${1:-}" ] && pyBin="${1}"
exe mkdir -p "${sc_haVenv:?}"
exe chown "${sc_haUser}:" "${sc_haVenv}"
runAsHa createVenv "${pyBin}" "${sc_haVenv}"
}
# createVenv <PYTHON BINARY> <VENV LOCATION>
createVenv() {
cd "${2:?}" && "${1:?}" -m venv .
}
step_20_info() { echo "Upgrade pip"; }
step_20_alias() { echo 'upgradepip'; }
step_20() {
runAsHa updatePy "${sc_haVenv}" pip
endReturn "Could not upgrade pip"
}
step_21_info() { echo "Upgrade $toolName core installation"; }
step_21_alias() { echo "upgrade"; }
step_21() {
exe service "${toolService}" stop
endReturn "Could not stop ${toolName}"
runAsHa updatePy "${sc_haVenv}" homeassistant "${sc_haDeps[@]}"
endReturn "Could not upgrade ${toolName}"
exe service "${toolService}" start
}
# updateHa <HA VENV ROOT> [OPTIONAL PIP PACKAGE ...]
updatePy() {
source "${1:?}/bin/activate"
shift
pip3 install --upgrade "$@"
}
step_30_info() { echo 'Upgrade venv to new python version'; }
step_30_options() { echo '<PYTHON VERSION>'; }
step_30_alias() { echo 'upgradevenv'; }
step_30() {
shift
local pyVer="${1:-}"
local buDate="$(date +%Y%m%d-%H%M%S)"
endIfEmpty pyVer "No python version given"
exe service "${toolService}" stop
endReturn "Could not stop ${toolName}"
exe mv "${sc_haVenv}" "${sc_haVenv}_bu_${buDate}" 2>/dev/null || true
local pyBin="$(command -v "python${pyVer}")"
step venv "${pyBin}"
}
step_31_info() { echo "Install ${toolName} in venv"; }
step_31() {
runAsHa installHa "${sc_haVenv}" "${sc_haDeps[@]}"
}
installHa() {
cd "${1:?}" && source "bin/activate" || return 1
shift
python3 -m pip install wheel
pip3 install homeassistant "$@"
}
step_32_info() { echo "Start $toolName in new venv"; }
step_32() {
exe service "${toolService}" start
}
# runAsHa <FUNCTION> [ARGS...]
# Run given function as home-assistant user inside the virtual environment
runAsHa() {
local func="${1:?}"
shift
exe sudo -Hu "${sc_haUser}" bash -c "$(declare -f "${func}"); ${func} "'"$@"' "" "$@"
}
step_50_alias() { echo 'notes'; }
step_50() {
color green
cat <<NOTES_END
# Systemd service example
[Unit]
Description=Home Assistant
After=network-online.target
[Service]
Type=simple
User=homeassistant
WorkingDirectory=/home/homeassistant/.homeassistant
ExecStart=${sc_haVenv:-"/srv/homeassistant"}/bin/hass -c "/home/homeassistant/.homeassistant"
RestartForceExitStatus=100
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
NOTES_END
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -2,26 +2,8 @@
toolName="jitsi-meet" toolName="jitsi-meet"
# Get script working directory
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
#CONFIG=0
#CONFIG_FILE_NAME="${toolName}.cfg"
#CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
#step_config() {
#echo "Called once before executing steps."
## e.g. to source a config file manually:
#. "$CONFIG_FILE"
## or to use sequencer api:
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
#if [ $? -eq 0 ] ; then
# CONFIG=1
#fi
#}
step_1_info() { echo "Installation of prerequisits"; } step_1_info() { echo "Installation of prerequisits"; }
step_1_alias() { ALIAS="prepare"; } step_1_alias() { echo "prepare"; }
step_1() { step_1() {
exe apt install gnupg2 git lsb-release ssl-cert ca-certificates apt-transport-https \ exe apt install gnupg2 git lsb-release ssl-cert ca-certificates apt-transport-https \
tree locate software-properties-common dirmngr screen htop nano net-tools zip unzip \ tree locate software-properties-common dirmngr screen htop nano net-tools zip unzip \
@@ -47,10 +29,10 @@ step_4() {
} }
step_5_info() { echo "Install nginx webserver"; } step_5_info() { echo "Install nginx webserver"; }
step_5_alias() { ALIAS="webserver"; } step_5_alias() { echo "webserver"; }
step_5() { step_5() {
exe apt install nginx exe apt install nginx
endReturn -o $? "Installation of webserver nginx failed" endReturn "Installation of webserver nginx failed"
exe mkdir -p /etc/nginx/sites-available exe mkdir -p /etc/nginx/sites-available
exe mkdir -p /etc/nginx/sites-enabled exe mkdir -p /etc/nginx/sites-enabled
exe mkdir -p /etc/nginx/modules-enabled exe mkdir -p /etc/nginx/modules-enabled
@@ -58,15 +40,15 @@ step_5() {
} }
step_6_info() { echo "Install ufw firewall"; } step_6_info() { echo "Install ufw firewall"; }
step_6_alias() { ALIAS="firewall"; } step_6_alias() { echo "firewall"; }
step_6() { step_6() {
exe apt install ufw exe apt install ufw
endReturn -o $? "Installation of firewall ufw failed" endReturn "Installation of firewall ufw failed"
} }
step_7_info() { echo "Setup ufw firewall to run $toolName"; } step_7_info() { echo "Setup ufw firewall to run $toolName"; }
step_7() { step_7() {
echo " [I] Configure ufw firewall" info "Configure ufw firewall"
exe ufw allow 22/tcp exe ufw allow 22/tcp
exe ufw allow 80/tcp exe ufw allow 80/tcp
exe ufw allow 443/tcp exe ufw allow 443/tcp
@@ -76,7 +58,7 @@ step_7() {
} }
step_8_info() { echo "Install $toolName"; } step_8_info() { echo "Install $toolName"; }
step_8_alias() { ALIAS="install"; } step_8_alias() { echo "install"; }
step_8() { step_8() {
exe read -p "Make sure SSL certificates are available. Enter to continue" exe read -p "Make sure SSL certificates are available. Enter to continue"
exe apt install jitsi-meet -y exe apt install jitsi-meet -y
@@ -87,59 +69,63 @@ step_9() {
exe mv /etc/nginx/sites-available/*.conf /etc/nginx/conf.d exe mv /etc/nginx/sites-available/*.conf /etc/nginx/conf.d
exe mv /etc/nginx/conf.d/default.conf /etc/nginx/sites-available exe mv /etc/nginx/conf.d/default.conf /etc/nginx/sites-available
exe service nginx restart exe service nginx restart
echo " [I] Check /etc/nginx/conf.d for unwanted configurations" info "Check /etc/nginx/conf.d for unwanted configurations"
} }
step_10_info() { echo "WIP post-install tasks"; } step_10_info() { echo "WIP post-install tasks"; }
step_10() { step_10() {
echo " [I] Tasks to be automated" color green
echo cat << WIP_END
echo " * Make jitsi installation password protected" # Tasks to be automated
echo " (https://github.com/jitsi/jicofo#secure-domain)"
echo " Creating new rooms will require username and password" * Make jitsi installation password protected
echo (https://github.com/jitsi/jicofo#secure-domain)
echo " ** /etc/prosody/conf.avail/[your-hostname].cfg.lua" Creating new rooms will require username and password
echo
echo " a) Enable authentication on your main domain:" ** /etc/prosody/conf.avail/[your-hostname].cfg.lua
echo
echo " VirtualHost \"jitsi-meet.example.com\"" a) Enable authentication on your main domain:
echo " authentication = \"internal_plain\""
echo VirtualHost "jitsi-meet.example.com"
echo " b) Add new virtual host with anonymous login method for guests:" authentication = "internal_plain"
echo
echo " VirtualHost \"guest.jitsi-meet.example.com\"" b) Add new virtual host with anonymous login method for guests:
echo " authentication = \"anonymous\""
echo " c2s_require_encryption = false" VirtualHost "guest.jitsi-meet.example.com"
echo authentication = "anonymous"
echo " ** /etc/jitsi/meet/[your-hostname]-config.js" c2s_require_encryption = false
echo
echo " var config = {" ** /etc/jitsi/meet/[your-hostname]-config.js
echo " hosts: {"
echo " domain: 'jitsi-meet.example.com'," var config = {
echo " anonymousdomain: 'guest.jitsi-meet.example.com'," hosts: {
echo " ..." domain: 'jitsi-meet.example.com',
echo " }," anonymousdomain: 'guest.jitsi-meet.example.com',
echo " ..." ...
echo " }" },
echo ...
echo " ** /etc/jitsi/jicofo/sip-communicator.properties" }
echo " add new line:"
echo ** /etc/jitsi/jicofo/sip-communicator.properties
echo " org.jitsi.jicofo.auth.URL=XMPP:jitsi-meet.example.com" add new line:
echo
echo " ** Create prosody user(s):" org.jitsi.jicofo.auth.URL=XMPP:jitsi-meet.example.com
echo
echo " prosodyctl register <username> jitsi-meet.example.com <password>" ** Create prosody user(s):
echo
echo " [I] Use step \"restart\" after these changes" prosodyctl register <username> jitsi-meet.example.com <password>
WIP_END
color none
info "Use step \"restart\" after these changes"
} }
step_20_info() { echo "Restart all $toolName components"; } step_20_info() { echo "Restart all $toolName components"; }
step_20_alias() { ALIAS="restart"; } step_20_alias() { echo "restart"; }
step_20() { step_20() {
echo " [I] Restart jitsi-meet components" info "Restart jitsi-meet components"
exep "service prosody restart&& service jicofo restart && service jitsi-videobridge2 restart" exep "service prosody restart&& service jicofo restart && service jitsi-videobridge2 restart"
} }
VERSION_SEQREV=10 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -10,9 +10,9 @@ toolServiceFile="/etc/systemd/system/kodi.service"
toolProfileDir="/home/kodi/.kodi" toolProfileDir="/home/kodi/.kodi"
step_1_info() { echo "Install $toolName via apt"; } step_1_info() { echo "Install $toolName via apt"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update && apt install kodi exe apt update && apt install kodi kodi-inputstream-adaptive kodi-eventclients-kodi-send
} }
step_2_info() { echo "Set localisation and keyboard layout"; } step_2_info() { echo "Set localisation and keyboard layout"; }
@@ -37,14 +37,14 @@ step_3() {
--disabled-password \ --disabled-password \
--gecos "User to run $toolName Media Center" \ --gecos "User to run $toolName Media Center" \
$toolUser $toolUser
exe usermod -a -G audio,video,plugdev,input,tty $toolUser
exe usermod -a -G audio,video,input,dialout,plugdev,netdev,users,cdrom,tty $toolUser
saveReturn $? saveReturn $?
endReturn endReturn
echo "User $toolUser details:" echo "User $toolUser details:"
exe id $tooLuser exe id $toolUser
} }
step_4_info() { echo "Create systemd service"; } step_4_info() { echo "Create systemd service"; }
step_4() { step_4() {
addConf -c "$toolServiceContent" "$toolServiceFile" addConf -c "$toolServiceContent" "$toolServiceFile"
@@ -60,8 +60,8 @@ step_4() {
} }
toolServiceContent="\ toolServiceContent="\
[Unit] [Unit]
Description = Kodi Media Center Description = Kodi Media Center
# if you don't need the MySQL DB backend, this should be sufficient # if you don't need the MySQL DB backend, this should be sufficient
After = systemd-user-sessions.service network.target sound.target After = systemd-user-sessions.service network.target sound.target
@@ -71,10 +71,12 @@ After = systemd-user-sessions.service network.target sound.target
# Wants = mysql.service # Wants = mysql.service
[Service] [Service]
User = kodi User = ${toolUser}
Group = kodi Group = ${toolUser}
Type = simple Type = simple
ExecStart = /usr/bin/kodi-standalone ExecStart = /usr/bin/kodi-standalone
ExecStop = /usr/bin/kodi-send --action=\"Quit\"
ExecStopPost = sleep 15
Restart = always Restart = always
RestartSec = 15 RestartSec = 15
@@ -91,8 +93,7 @@ step_5() {
step_6_info() { echo "Increase raspberry pi GPU memory to 320"; } step_6_info() { echo "Increase raspberry pi GPU memory to 320"; }
step_6() { step_6() {
exep "grep -e '^[ ]*gpu_mem' \"$bootConfigLoc\" >>/dev/null 2>&1" if ! exep "grep -e '^[ ]*gpu_mem' \"$bootConfigLoc\" >>/dev/null 2>&1" && [ -f "$bootConfigLoc" ] ; then
if [ $? -ne 0 ] && [ -f "$bootConfigLoc" ] ; then
# attach settings to raspberry boot configuration # attach settings to raspberry boot configuration
exe mount -o remount,rw /boot exe mount -o remount,rw /boot
addConf -a "$bootConfig" "$bootConfigLoc" addConf -a "$bootConfig" "$bootConfigLoc"
@@ -111,10 +112,10 @@ gpu_mem=320"
step_7_info() { echo "Reboot is needed for all changes to take effect"; } step_7_info() { echo "Reboot is needed for all changes to take effect"; }
step_7() { step_7() {
if [ $QUIET -eq "1" ] ; then if quiet ; then
answer=n answer=n
else else
read -p "Reboot now? y/n(default)" answer read -r -p "Reboot now? y/n(default)" answer
fi fi
case $answer in case $answer in
y|Y) y|Y)
@@ -128,7 +129,7 @@ step_7() {
} }
step_10_info() { echo "Send $toolName logs to syslog"; } step_10_info() { echo "Send $toolName logs to syslog"; }
step_10_alias() { ALIAS="syslog"; } step_10_alias() { echo "syslog"; }
step_10() { step_10() {
addConf -s "$kodiSyslog" "$kodiSyslogLoc" addConf -s "$kodiSyslog" "$kodiSyslogLoc"
exe chmod -f +x "$kodiSyslogLoc" exe chmod -f +x "$kodiSyslogLoc"
@@ -136,20 +137,20 @@ step_10() {
kodiSyslogLoc="/usr/local/bin/kodisyslog" kodiSyslogLoc="/usr/local/bin/kodisyslog"
kodiSyslog="#!/bin/bash kodiSyslog="#!/bin/bash
tail -f /home/kodi/.kodi/temp/kodi.log | tail -f /home/kodi/.kodi/temp/kodi.log |
while read -r line while read -r line ; do
do
logger -t KODI \"\${line:37}\" logger -t KODI \"\${line:37}\"
done" done"
# Using previously generated executable
step_11_info() { echo "Create systemd service for logging to syslog"; } step_11_info() { echo "Create systemd service for logging to syslog"; }
step_11() { step_11() {
[ ! -f "$kodiSyslogLoc" ] && return 1 [ ! -f "$kodiSyslogLoc" ] && return 1
addConf -s "$kodiSyslogService" "$kodiSyslogServiceLoc" addConf -s "$kodiSyslogService" "$kodiSyslogServiceLoc"
echoseq " [I] Consider limiting systemd journal size" info "Consider limiting systemd journal size"
echoseq " [/etc/systemd/journald.conf]" info " [/etc/systemd/journald.conf]"
echoseq " SystemMaxUse=50M" info " SystemMaxUse=50M"
} }
kodiSyslogServiceLoc="/etc/systemd/system/kodisyslog.service" kodiSyslogServiceLoc="/etc/systemd/system/kodisyslog.service"
kodiSyslogService="[Unit] kodiSyslogService="[Unit]
@@ -165,32 +166,65 @@ WantedBy=multi-user.target"
step_12_info() { echo "Enable and start kodisyslog service"; } step_12_info() { echo "Enable and start kodisyslog service"; }
step_12() { step_12() {
local kodiSyslogName="$(basename $kodiSyslogServiceLoc)" local kodiSyslogName
kodiSyslogName="$(basename $kodiSyslogServiceLoc)"
exe systemctl daemon-reload exe systemctl daemon-reload
exe systemctl enable $kodiSyslogName exe systemctl enable "$kodiSyslogName"
exe systemctl start $kodiSyslogName exe systemctl start "$kodiSyslogName"
}
step_14_info() { echo "Add ufw rules for kodi"; }
step_14_alias() { echo "ufw"; }
step_14() {
exe ufw allow in on eth0 to any proto tcp port 8080 comment "kodi remote"
exe ufw allow in on eth0 to any proto tcp port 9090 comment "kodi jsonrpc"
exe ufw allow in on eth0 to any proto udp port 9777 comment "kodi event client"
} }
step_40_info() { echo "Reset music database"; } step_40_info() { echo "Reset music database"; }
step_40_alias() { ALIAS="resetmusic"; } step_40_alias() { echo "resetmusic"; }
step_40() { step_40() {
local i local i
local answer="y" local answer="y"
local musicDb=( "$toolProfileDir/userdata/Database/MyMusic"*.db ) local musicDb=( "$toolProfileDir/userdata/Database/MyMusic"*.db )
echoseq " [W] Erasing:" warning "Erasing:"
for i in ${musicDb[@]}; do for i in "${musicDb[@]}"; do
echoseq $i info "$i"
done done
[ $QUIET -eq 0 ] && read -p "Are you sure? (y)/[n] " answer interactive && read -r -p "Are you sure? (y)/[n] " answer
case "$answer" in case "$answer" in
y|Y) y|Y)
exe rm ${musicDb[@]};; exe rm "${musicDb[@]}";;
*) *)
echoseq " [I] Abort reset" info "Abort reset"
return 1; return 1;
esac esac
} }
VERSION_SEQREV=12 step_100_info() { echo "Notes"; }
step_100_alias() { echo "notes"; }
step_100() {
cat <<NOTES_EOF
# Install additional packages
kodi-inputstream-adaptive - needed for Youtube plugin
kodi-eventclients-kodi-send - recommended way to stop kodi gracefully
# Sudoers change for Kodi Matrix
\`\`\`
Cmnd_Alias KODI_VT = /bin/fgconsole, /bin/chvt *
Cmnd_Alias KODI_VT2 = /bin/openvt
%video ALL = (root) NOPASSWD: KODI_VT
%video ALL = (root) NOPASSWD: KODI_VT2
\`\`\`
NOTES_EOF
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,29 +1,29 @@
#!/bin/bash #!/bin/bash
toolName="ldap" readonly toolName="ldap"
toolDaemon="slapd" readonly toolDaemon="slapd"
toolDeps="$toolDaemon ldap-utils" readonly toolDeps="$toolDaemon ldap-utils"
toolUser="openldap" readonly toolUser="openldap"
# Get script working directory sq_aptOpt=
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then # End if no configuration file exists
CONFIG=1 dry || return 1
fi fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
return 0
} }
step_1_info() { echo "$toolName installation"; } step_1_info() { echo "$toolName installation"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install $toolDeps exe apt install $toolDeps ${sq_aptOpt}
} }
step_2_info() { echo "Configuration of $toolName"; } step_2_info() { echo "Configuration of $toolName"; }
@@ -82,7 +82,7 @@ olcOverlay: {1}refint
olcRefintAttribute: memberof member manager owner olcRefintAttribute: memberof member manager owner
" "
step_7_info() { echo "Create base DNs for users ($LDAP_OU_USERS) and groups ($LDAP_OU_GROUPS)"; } step_7_info() { echo "Create base DNs for users (${LDAP_OU_USERS:-}) and groups (${LDAP_OU_GROUPS:-})"; }
step_7() { step_7() {
variable2Ldif add "$ldapBase" variable2Ldif add "$ldapBase"
} }
@@ -98,11 +98,11 @@ objectClass: organizationalUnit
step_8_info() { echo "Setup SSL secured ldaps:// access"; } step_8_info() { echo "Setup SSL secured ldaps:// access"; }
step_8() { step_8() {
sudo -u $toolUser test -r "$LDAP_CERT_KEY" >>/dev/null 2>&1 sudo -u $toolUser test -r "$LDAP_CERT_KEY" >>/dev/null 2>&1
endReturn -o $? "$toolUser cannot access certificate key file: $LDAP_CERT_KEY" endReturn "$toolUser cannot access certificate key file: $LDAP_CERT_KEY"
sudo -u $toolUser test -r "$LDAP_CERT" >>/dev/null 2>&1 sudo -u $toolUser test -r "$LDAP_CERT" >>/dev/null 2>&1
endReturn -o $? "$toolUser cannot access certificate file: $LDAP_CERT" endReturn "$toolUser cannot access certificate file: $LDAP_CERT"
sudo -u $toolUser test -r "$LDAP_CERT_CA" >>/dev/null 2>&1 sudo -u $toolUser test -r "$LDAP_CERT_CA" >>/dev/null 2>&1
endReturn -o $? "$toolUser cannot access CA certificate file: $LDAP_CERT_CA" endReturn "$toolUser cannot access CA certificate file: $LDAP_CERT_CA"
local tempLdif=`eval "echo \"$sslSetup\""` local tempLdif=`eval "echo \"$sslSetup\""`
exep "echo \"$tempLdif\" | ldapmodify -Y EXTERNAL -H ldapi:///" exep "echo \"$tempLdif\" | ldapmodify -Y EXTERNAL -H ldapi:///"
@@ -136,10 +136,23 @@ step_20() {
exe ldapwhoami -H ldapi:/// -x exe ldapwhoami -H ldapi:/// -x
} }
step_22_info() { echo 'Test ldaps connection with user access'; }
step_22_options() { echo '<LDAP DOMAIN> <USERID>'; }
step_22_alias() { echo 'testldaps'; }
step_22() {
shift
local domain="${1:-}"
local user="${2:-}"
[[ -z "${domain}" ]] && domain=$(ask "LDAP server domain: ")
[[ -z "${user}" ]] && user=$(ask "LDAP user: ")
exe ldapsearch -x -D "uid=${user},ou=Users,${LDAP_DC}" -W\
-H "ldaps://${domain}" -b "ou=Users,${LDAP_DC}" -s sub "uid=${user}"
}
step_80_info() { echo -e "Some ldap command notes\n"; } step_80_info() { echo -e "Some ldap command notes\n"; }
step_80_alias() { ALIAS="notes"; } step_80_alias() { echo "notes"; }
step_80() { step_80() {
outColor green color green
cat <<NOTES_EOF cat <<NOTES_EOF
# You can also check LDAP Base DN using the ldapsearch command as shown below # You can also check LDAP Base DN using the ldapsearch command as shown below
ldapsearch -H ldapi:/// -x -LLL -s base -b "" namingContexts ldapsearch -H ldapi:/// -x -LLL -s base -b "" namingContexts
@@ -161,8 +174,9 @@ E0F
NOTES_EOF NOTES_EOF
} }
step_100_info() { echo "Add group <GROUP NAME> <USER ID>"; } step_100_info() { echo "Add group"; }
step_100_alias() { ALIAS="addgroup"; } step_100_options() { echo "<GROUP NAME> <USER ID>"; }
step_100_alias() { echo "addgroup"; }
step_100() { step_100() {
shift shift
local groupName=$1 local groupName=$1
@@ -177,8 +191,9 @@ description: Created by $0
member: \${memberDn} member: \${memberDn}
" "
step_102_info() { echo "Add user <USER ID> <USER NAME> <USER LASTNAME> <UIDNUMBER> <USER EMAIL> [USER GID]"; } step_102_info() { echo "Add user"; }
step_102_alias() { ALIAS="adduser"; } step_102_options() { echo "<USER ID> <USER NAME> <USER LASTNAME> <UIDNUMBER> <USER EMAIL> [USER GID]"; }
step_102_alias() { echo "adduser"; }
step_102() { step_102() {
shift shift
userId="$1" userId="$1"
@@ -193,7 +208,7 @@ step_102() {
fi fi
variable2Ldif add "$addUser" variable2Ldif add "$addUser"
endReturn -o $? "Adding user failed" endReturn "Adding user failed"
} }
userId= userId=
addUser="dn: uid=\$userId,\$LDAP_OU_USERS,\$LDAP_DC addUser="dn: uid=\$userId,\$LDAP_OU_USERS,\$LDAP_DC
@@ -214,44 +229,46 @@ objectClass: person
loginShell: /bin/bash loginShell: /bin/bash
" "
step_103_info() { echo "(re)Set passwort for <USER>"; } step_103_info() { echo "(re)Set passwort for user"; }
step_103_alias() { ALIAS="passwd"; } step_103_options() { echo "<USER>"; }
step_103_alias() { echo "passwd"; }
step_103() { step_103() {
shift shift
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
echo " [I] Password operation for $1" info "Password operation for $1"
userId="$1" userId="$1"
elif [ ! -z $userId ] ; then elif [ ! -z $userId ] ; then
echo " [I] Password operation for $userId" info "Password operation for $userId"
else else
echoerr " [E] No user id provided" error -e "No user id provided"
return 1 return 1
fi fi
exe ldappasswd -H ldapi:/// -x -D "cn=admin,$LDAP_DC" -W -S "uid=$userId,$LDAP_OU_USERS,$LDAP_DC" exe ldappasswd -H ldapi:/// -x -D "cn=admin,$LDAP_DC" -W -S "uid=$userId,$LDAP_OU_USERS,$LDAP_DC"
} }
step_105_info() { echo "Adding <USER ID> to existing group <GROUP NAME>"; } step_105_info() { echo "Adding user to existing group"; }
step_105_alias() { ALIAS="user2group"; } step_105_options() { echo "<USER ID> <GROUP NAME>"; }
step_105_alias() { echo "user2group"; }
step_105() { step_105() {
shift shift
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
userId="$1" userId="$1"
echo " [I] User operation for $userId" info "User operation for $userId"
elif [ ! -z $userId ] ; then elif [ ! -z $userId ] ; then
echo " [I] User operation for $userId" info "User operation for $userId"
else else
echoerr " [E] No user id provided" error -e "No user id provided"
return 1 return 1
fi fi
if [ -z $2 ] ; then if [ -z $2 ] ; then
echoerr " [E] No group name provided" error -e "No group name provided"
return 2 return 2
fi fi
local groupName="$2" local groupName="$2"
variable2Ldif modify "$removeFromgroup" variable2Ldif modify "$removeFromgroup"
variable2Ldif modify "$add2group" variable2Ldif modify "$add2group"
endReturn -o $? "Adding user to group failed" endReturn "Adding user to group failed"
} }
#remove empty member #remove empty member
add2group="dn: cn=\$groupName,\$LDAP_OU_GROUPS,\$LDAP_DC add2group="dn: cn=\$groupName,\$LDAP_OU_GROUPS,\$LDAP_DC
@@ -265,21 +282,22 @@ delete: member
member: member:
" "
step_107_info() { echo "Removing <USER ID> from existing group <GROUP NAME>"; } step_107_info() { echo "Removing user from existing group"; }
step_107_alias() { ALIAS="rmusergroup"; } step_107_options() { echo "<USER ID> <GROUP NAME>"; }
step_107_alias() { echo "rmusergroup"; }
step_107() { step_107() {
shift shift
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
userId="$1" userId="$1"
echo " [I] User operation for $userId" info "User operation for $userId"
elif [ ! -z $userId ] ; then elif [ ! -z $userId ] ; then
echo " [I] User operation for $userId" info "User operation for $userId"
else else
echoerr " [E] No user id provided" error -e "No user id provided"
return 1 return 1
fi fi
if [ -z $2 ] ; then if [ -z $2 ] ; then
echoerr " [E] No group name provided" error -e "No group name provided"
return 2 return 2
fi fi
local groupName="$2" local groupName="$2"
@@ -299,12 +317,13 @@ delete: member
member: uid=\$userId,\$LDAP_OU_USERS,\$LDAP_DC member: uid=\$userId,\$LDAP_OU_USERS,\$LDAP_DC
" "
step_110_info() { echo "Remove group <GROUP NAME>"; } step_110_info() { echo "Remove group"; }
step_110_alias() { ALIAS="rmgroup"; } step_110_options() { echo "<GROUP NAME>"; }
step_110_alias() { echo "rmgroup"; }
step_110() { step_110() {
shift shift
if [ -z $1 ] ; then if [ -z $1 ] ; then
echoerr " [E] No group name provided" error -e "No group name provided"
return 1 return 1
fi fi
local groupName=$1 local groupName=$1
@@ -314,12 +333,13 @@ rmGroup="dn: cn=\${groupName},\${LDAP_OU_GROUPS},\${LDAP_DC}
changetype: delete changetype: delete
" "
step_112_info() { echo "Remove user <USER ID>"; } step_112_info() { echo "Remove user"; }
step_112_alias() { ALIAS="rmuser"; } step_112_options() { echo "<USER ID>"; }
step_112_alias() { echo "rmuser"; }
step_112() { step_112() {
shift shift
if [ -z $1 ] ; then if [ -z $1 ] ; then
echoerr " [E] No user id provided" error -e "No user id provided"
return 1 return 1
fi fi
local userName=$1 local userName=$1
@@ -329,19 +349,21 @@ rmUser="dn: uid=\${userName},\${LDAP_OU_USERS},\${LDAP_DC}
changetype: delete changetype: delete
" "
step_200_info() { echo "List available groups <ADDITONAL ATTRIBUTES...>"; } step_200_info() { echo "List available groups"; }
step_200_alias() { ALIAS="listgroups"; } step_200_options() { echo "<ADDITONAL ATTRIBUTES...>"; }
step_200_alias() { echo "listgroups"; }
step_200() { step_200() {
shift shift
echo " [I] Available groups:" info "Available groups:"
exe ldapsearch -x -LLL -H ldap:/// -b ${LDAP_OU_GROUPS},${LDAP_DC} dn gidNumber $* exe ldapsearch -x -LLL -H ldap:/// -b ${LDAP_OU_GROUPS},${LDAP_DC} dn gidNumber $*
} }
step_202_info() { echo "List available users <ADDITONAL ATTRIBUTES...>"; } step_202_info() { echo "List available users"; }
step_202_alias() { ALIAS="listusers"; } step_200_options() { echo "<ADDITONAL ATTRIBUTES...>"; }
step_202_alias() { echo "listusers"; }
step_202() { step_202() {
shift shift
echo " [I] Available user:" info "Available user:"
exe ldapsearch -x -LLL -H ldap:/// -b ${LDAP_OU_USERS},${LDAP_DC} dn uidNumber gidNumber $* exe ldapsearch -x -LLL -H ldap:/// -b ${LDAP_OU_USERS},${LDAP_DC} dn uidNumber gidNumber $*
} }
@@ -364,5 +386,7 @@ variable2LdifEcho() {
echo "$tempLdif" echo "$tempLdif"
} }
VERSION_SEQREV=10 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -3,69 +3,57 @@
# #
## Installation and maintenance for LibreNMS ## Installation and maintenance for LibreNMS
toolName="librenms" readonly toolName="librenms"
toolUser="librenms" readonly toolUser="librenms"
libreDeps='acl curl fping git graphviz imagemagick mtr-tiny nmap python3-dotenv python3-pymysql python3-redis python3-setuptools python3-systemd python3-pip rrdtool snmp snmpd whois'
librePhpDeps=(cli curl fpm gd gmp mbstring mysql snmp xml zip)
sq_aptOpt=
phpVersion= phpVersion=
libreDeps='acl curl composer fping git graphviz imagemagick mtr-tiny nmap rrdtool snmp snmpd whois python3-dotenv python3-pymysql python3-redis python3-setuptools' seq_config() {
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
librePhpDeps='php${phpVersion}-cli php${phpVersion}-curl php${phpVersion}-fpm php${phpVersion}-gd php${phpVersion}-json php${phpVersion}-mbstring php${phpVersion}-mysql php${phpVersion}-snmp php${phpVersion}-xml php${phpVersion}-zip' if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
info " Install: $LNMS_DIR"
#librePhpDeps="composer php-cli-prompt php-composer-ca-bundle php-composer-semver php-composer-spdx-licenses php-json-schema php-psr-log php-symfony-console php-symfony-filesystem php-symfony-finder php-symfony-polyfill-mbstring php-symfony-process" info " Backup: $LNMS_BU_DIR"
#librePackages="fping git graphviz imagemagick mtr-tiny nmap python-memcache python-mysqldb rrdtool snmp snmpd whoisi nagios-plugins"
# Get script working directory
# (when called from a different directory)
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd )"
CONFIG=0
SCRIPT_NAME=$(basename -- "$0")
SCRIPT_NAME=${SCRIPT_NAME%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
echoseq " Install: $LNMS_DIR"
echoseq " Backup: $LNMS_BU_DIR"
else else
[ $DRY -eq 0 ] && return 1 dry || return 1
fi fi
return 0
} }
step_1_info() { echo "Updating apt"; } step_1_info() { echo "Updating apt"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
} }
step_2_info() { step_2_info() {
echo "Installing $toolname dependencies:" echo "Installing $toolName dependencies:"
echoinfo "$libreDeps" echoinfo "$libreDeps"
} }
step_2() { step_2() {
exe apt install $libreDeps exe apt install $libreDeps ${sq_aptOpt}
endReturn -o $? "Failed to install $toolName dependencies" endReturn "Failed to install $toolName dependencies"
} }
step_3_info() { step_3_info() {
echo "Installing PHP related packages:" echo "Installing PHP related packages:"
fetchPhpVersion fetchPhpVersion
echoinfo `eval echo "$librePhpDeps"` echoinfo "${librePhpDeps[@]/#/php${phpVersion}-}"
} }
step_3() { step_3() {
fetchPhpVersion fetchPhpVersion
exe apt install `eval echo "$librePhpDeps"` exe apt install "${librePhpDeps[@]/#/php${phpVersion}-}" ${sq_aptOpt}
endReturn -o $? "Failed to install $toolName php dependencies" endReturn "Failed to install $toolName php dependencies"
} }
step_4_info() { echo "Adding $toolName user ($toolUser)"; } step_4_info() { echo "Adding $toolName user ($toolUser)"; }
step_4() { step_4() {
exe useradd $toolUser -d "$LNMS_DIR" -M -r -s "$(which bash)" exe useradd $toolUser -d "$LNMS_DIR" -M -r -s "$(which bash)"
saveReturn $? saveReturn $?
#exe usermod -a -G librenms www-data
#saveReturn $?
endReturn "Failed to create user $toolUser" endReturn "Failed to create user $toolUser"
} }
@@ -79,22 +67,22 @@ step_5() {
step_6_info() { echo "Installing $toolName using composer"; } step_6_info() { echo "Installing $toolName using composer"; }
step_6() { step_6() {
exe sudo -u librenms "${LNMS_DIR}/scripts/composer_wrapper.php" install --no-dev exe sudo -u librenms "${LNMS_DIR}/scripts/composer_wrapper.php" install --no-dev
endReturn -o $? "Failed to install php dependencies" endReturn "Failed to install php dependencies"
} }
step_10_info() { echo "Create mysql database for $toolName"; } step_10_info() { echo "Create mysql database for $toolName"; }
step_10() { step_10() {
local libreDbOpt= local libreDbOpt=
if [ ! -z "$LNMS_DB_NAME" ] ; then if [ -n "$LNMS_DB_NAME" ] ; then
libreDbOpt="-d $LNMS_DB_NAME" libreDbOpt="-d $LNMS_DB_NAME"
fi fi
exe ${WDIR}/mysql.sh -q createdb --charset utf8 $libreDbOpt exe "${seq_origin}"/mysql.sh ${sqr_args} createdb --charset utf8 "$libreDbOpt"
endReturn -o $? "Failed to create mysql database $LNMS_DB_NAME" endReturn "Failed to create mysql database $LNMS_DB_NAME"
} }
step_11_info() { echo "MariaDB configuration"; } step_11_info() { echo "MariaDB configuration"; }
step_11() { step_11() {
outColor green color green
cat << SQLCONF_END cat << SQLCONF_END
Edit or create /etc/mysql/mariadb.conf.d/90-myconfig.cnf and add: Edit or create /etc/mysql/mariadb.conf.d/90-myconfig.cnf and add:
@@ -112,13 +100,14 @@ SQLCONF_END
step_12_info() { echo "PHP fpm/cli timezone configuration"; } step_12_info() { echo "PHP fpm/cli timezone configuration"; }
step_12() { step_12() {
outColor green color green
fetchPhpVersion
cat << PHPCONF_END cat << PHPCONF_END
Ensure date.timezone is set in php.ini to your preferred time zone. See http://php.net/manual/en/timezones.php for a list of supported timezones. Valid examples are: "America/New_York", "Europe/Berlin", "Etc/UTC". Ensure date.timezone is set in php.ini to your preferred time zone. See http://php.net/manual/en/timezones.php for a list of supported timezones. Valid examples are: "America/New_York", "Europe/Berlin", "Etc/UTC".
vi /etc/php/7.3/fpm/conf.d/90-custom_pi.ini vi /etc/php/${phpVersion}/fpm/conf.d/90-custom_pi.ini
vi /etc/php/7.3/cli/conf.d/90-custom_pi.ini vi /etc/php/${phpVersion}/cli/conf.d/90-custom_pi.ini
------------------------------------------- -------------------------------------------
date.timezone = Europe/Berlin date.timezone = Europe/Berlin
@@ -131,11 +120,11 @@ PHPCONF_END
step_13_info() { echo "PHP fpm configuration"; } step_13_info() { echo "PHP fpm configuration"; }
step_13() { step_13() {
outColor green color green
cat << FPMCONF_END cat << FPMCONF_END
cp /etc/php/7.3/fpm/pool.d/www.conf /etc/php/7.3/fpm/pool.d/librenms.conf cp /etc/php/${phpVersion}/fpm/pool.d/www.conf /etc/php/${phpVersion}/fpm/pool.d/librenms.conf
vi /etc/php/7.3/fpm/pool.d/librenms.conf vi /etc/php/${phpVersion}/fpm/pool.d/librenms.conf
# Change [www] to [librenms]: # Change [www] to [librenms]:
@@ -154,7 +143,7 @@ FPMCONF_END
step_14_info() { echo "Nginx configuration"; } step_14_info() { echo "Nginx configuration"; }
step_14() { step_14() {
outColor green color green
cat << NGINXCONF_END cat << NGINXCONF_END
server { server {
@@ -182,62 +171,63 @@ NGINXCONF_END
} }
step_20_info() { echo "Create $toolName cron job"; } step_20_info() { echo "Create $toolName cron job"; }
step_20_alias() { ALIAS="cron"; } step_20_alias() { echo "cron"; }
step_20() { step_20() {
echoseq -n " [I] Creating $lnmsCronLoc ... " local lnmsCronLoc="/etc/cron.d/librenms"
exe cp "${LNMS_DIR}/librenms.nonroot.cron" "$lnmsCronLoc" && echoseq "Ok" || echoseq "Nok" info -n "Creating $lnmsCronLoc ... "
exe cp "${LNMS_DIR}/librenms.nonroot.cron" "$lnmsCronLoc" && info -d "Ok" || info -d "Nok"
} }
lnmsCronLoc="/etc/cron.d/librenms"
step_22_info() { echo "Enable lnms command completion"; } step_22_info() { echo "Enable lnms command completion"; }
step_22_alias() { ALIAS="cmdcompletion"; } step_22_alias() { echo "cmdcompletion"; }
step_22() { step_22() {
exep 'echo -e "#!/bin/bash\nsudo -u '$toolUser' \"'$LNMS_DIR'/lnms\" \"\$@\"" > '"$lnmsLocalBin" local lnmsLocalBin="/usr/local/bin/lnms"
exep echo -e '"#!/usr/bin/env bash\nsudo -u '$toolUser' \"'$LNMS_DIR'/lnms\" \"\$@\""' \> "$lnmsLocalBin"
exe chmod 744 "$lnmsLocalBin" exe chmod 744 "$lnmsLocalBin"
exe cp "${LNMS_DIR}/misc/lnms-completion.bash" /etc/bash_completion.d/ exe cp "${LNMS_DIR}/misc/lnms-completion.bash" /etc/bash_completion.d/
} }
lnmsLocalBin="/usr/local/bin/lnms"
step_24_info() { echo "Copy logrotate config"; } step_24_info() { echo "Copy logrotate config"; }
step_24_alias() { ALIAS="logrotate"; } step_24_alias() { echo "logrotate"; }
step_24() { step_24() {
echoseq -n " [I] Creating $lnmsLogrotLoc ... " local lnmsLogrotLoc="/etc/logrotate.d/librenms"
exe cp "${LNMS_DIR}/misc/librenms.logrotate" "$lnmsLogrotLoc" && echoseq "Ok" || echoseq "Nok" info -n "Creating $lnmsLogrotLoc ... "
exe cp "${LNMS_DIR}/misc/librenms.logrotate" "$lnmsLogrotLoc" && info -d "Ok" || info -d "Nok"
} }
lnmsLogrotLoc="/etc/logrotate.d/librenms"
step_26_info() { echo "Install nagios plugin to enable services"; } step_26_info() { echo "Install nagios plugin to enable services"; }
step_26_alias() { ALIAS="services"; } step_26_alias() { echo "services"; }
step_26() { step_26() {
exe apt install monitoring-plugins exe apt install monitoring-plugins
echoseq info
echoseq " [$LNMS_DIR/config.php]" info " [$LNMS_DIR/config.php]"
echoseq "\$config['show_services'] = 1;" info -a " \$config['show_services'] = 1;"
echoseq info -a
echoseq " [/etc/cron.d/librenms]" info -a " [/etc/cron.d/librenms]"
echoseq " */5 * * * * librenms /opt/librenms/services-wrapper.py 1" info -a " */5 * * * * librenms /opt/librenms/services-wrapper.py 1"
} }
step_30_info() { echo "Backup ${toolName} web direcotry"; } step_30_info() { echo "Backup ${toolName} web direcotry"; }
step_30_alias() { ALIAS="backup"; } step_30_alias() { echo "backup"; }
step_30() { step_30() {
echoseq " [I] Backup install directory to ${LNMS_BU_DIR}" info "Backup install directory to ${LNMS_BU_DIR}"
exe mkdir -p "$LNMS_BU_DIR" exe mkdir -p "$LNMS_BU_DIR"
exep "cd \"${LNMS_DIR}\"/.. && tar czf \"${LNMS_BU_DIR}/\`date +%Y%m%d\`_${toolName}_web.tar.gz\" \"$(basename "$LNMS_DIR")\"" exep cd "${LNMS_DIR}"/.. "&&" tar czf "${LNMS_BU_DIR}/$(date +%Y%m%d)_${toolName}_web.tar.gz" "$(basename "$LNMS_DIR")"
} }
step_31_info() { echo "Backup ${toolName} database [daily|monthly(default)]"; } step_31_info() { echo "Backup ${toolName} database"; }
step_31_alias() { ALIAS="backupdb"; } step_31_options() { echo "[daily|monthly(default)]"; }
step_31_alias() { echo "backupdb"; }
step_31() { step_31() {
case "$2" in case "${2:-}" in
daily|Daily|DAILY) daily | Daily | DAILY)
echoseq " [I] Daily backup..." info "Daily backup..."
exep "mysqldump --single-transaction -u root ${LNMS_DB_NAME} | bzip2 -c > \"${LNMS_BU_DIR}/${toolName}_daily.sql.bz2\"" exep mysqldump --single-transaction -u root "${LNMS_DB_NAME}" \| bzip2 -c \> "${LNMS_BU_DIR}/${toolName}_daily.sql.bz2"
;; ;;
*) *)
exe mkdir -p "$LNMS_BU_DIR/monthly" exe mkdir -p "$LNMS_BU_DIR/monthly"
echoseq " [I] Monthly backup..." info "Monthly backup..."
exep "mysqldump --single-transaction -u root ${LNMS_DB_NAME} | bzip2 -c > \"${LNMS_BU_DIR}/monthly/\`date +%Y%m%d\`_${toolName}.sql.bz2\"" exep mysqldump --single-transaction -u root "${LNMS_DB_NAME}" \| bzip2 -c \> "${LNMS_BU_DIR}/monthly/$(date +%Y%m%d)_${toolName}.sql.bz2"
;; ;;
esac esac
} }
@@ -258,7 +248,7 @@ STABLE_EOF
} }
step_42_info() { echo "Fix librenms permission"; } step_42_info() { echo "Fix librenms permission"; }
step_42_alias() { ALIAS="fix"; } step_42_alias() { echo "fix"; }
step_42() { step_42() {
exe chown -R ${toolUser}: "$LNMS_DIR" exe chown -R ${toolUser}: "$LNMS_DIR"
exe chmod 771 "${LNMS_DIR}" exe chmod 771 "${LNMS_DIR}"
@@ -267,13 +257,14 @@ step_42() {
} }
fetchPhpVersion() { fetchPhpVersion() {
if [ ! -z $phpVersion ] ; then if [ -n "${phpVersion}" ] ; then
return 0 return 0
fi fi
phpVersion="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')" phpVersion="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')"
} }
# Sequence Revision # shellcheck disable=SC2034 # Appears unused
VERSION_SEQREV=12 readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -2,20 +2,40 @@
# MAS = Mail Server # MAS = Mail Server
MAS_DOMAIN="mydomain.com" readonly MAS_DOMAIN="mydomain.com"
MAS_RELAYHOST= readonly MAS_RELAYHOST=
MAS_RELAYUSER= readonly MAS_RELAYUSER=
MAS_RELAYPASS= readonly MAS_RELAYPASS=
MAS_DBUSER='pfa' # Settings for virtualizing mailboxes and domains
MAS_DBPASS='pass'
MAS_DBNAME='pfa_db' readonly MAS_DBUSER='pfa'
MAS_mysql_virtual_domains_maps="user = '\$MAS_DBUSER' readonly MAS_DBPASS='pass'
password = '\$MAS_DBPASS' readonly MAS_DBNAME='pfa_db'
hosts = localhost readonly MAS_DBHOST='localhost'
dbname = '\$MAS_DBNAME' readonly MAS_VIRTUAL_USER='vmail'
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1' readonly MAS_VIRTUAL_USER_ID='5000'
readonly MAS_VIRTUAL_FOLDER_BASE='/var/vmail'
readonly MAS_VIRTUAL_USER_PART="user=$MAS_DBUSER
password=$MAS_DBPASS
hosts=$MAS_DBHOST
dbname=$MAS_DBNAME"
MAS_mysql_virtual_domains_maps="query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
#query = SELECT domain FROM domain WHERE domain='%s' #query = SELECT domain FROM domain WHERE domain='%s'
#optional query to use when relaying for backup MX #optional query to use when relaying for backup MX
#query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1' #query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'
#expansion_limit = 100" #expansion_limit = 100"
MAS_mysql_virtual_mailbox_maps="query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
#expansion_limit = 100"
MAS_mysql_virtual_alias_domain_mailbox_maps="query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1'"
MAS_mysql_virtual_alias_maps="query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
#expansion_limit = 100"
MAS_mysql_virtual_alias_domain_maps="query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'"
MAS_mysql_virtual_alias_domain_catchall_maps="# handles catch-all settings of target-domain
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'"

View File

@@ -6,62 +6,55 @@
# MDA = Mail Delivery Agent (dovecot) # MDA = Mail Delivery Agent (dovecot)
# MUA = Mail User Agent (Mail program used by the user) # MUA = Mail User Agent (Mail program used by the user)
toolName=mailserver readonly toolName=mailserver
mtaName=postfix readonly mtaName=postfix
mtaUser=postfix readonly mtaUser=postfix
mtaDeps="$mtaName $mtaName-mysql" readonly mtaDeps="$mtaName $mtaName-mysql"
mtaConfLoc="/etc/$mtaName" readonly mtaConfLoc="/etc/$mtaName"
mtaMysqlConfLoc="$mtaConfLoc/sql" readonly mtaMysqlConfLoc="$mtaConfLoc/sql"
mdaName=dovecot readonly mdaName=dovecot
mdaConfLoc="/etc/$mdaName" readonly mdaConfLoc="/etc/$mdaName"
mdaConfDir="$mdaConfLoc/conf.d" readonly mdaConfDir="$mdaConfLoc/conf.d"
mdaDeps="dovecot-imapd dovecot-lmtpd dovecot-mysql dovecot-managesieved dovecot-sieve" readonly mdaDeps="dovecot-imapd dovecot-lmtpd dovecot-mysql dovecot-managesieved dovecot-sieve"
# Get script working directory sq_aptOpt=
# (when called from a different directory) sq_config=0
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
if [ $(id -u) -ne 0 ] ; then root || endReturn -o 1 "No root"
endReturn -o 1 "No root"
fi #initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then sq_config=1
CONFIG=1 info " Domain: ${MAS_DOMAIN:-}"
echoseq " Domain: $MAS_DOMAIN" else
elif [ $? -eq 1 ] ; then dry || return 1
# Config $CONFIG_FILE_NAME created. Needs modification first
[ $DRY -eq 0 ] && return -1
fi fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
return 0 return 0
} }
step_1_info() { echo "Update apt repositories"; } step_1_info() { echo "Update apt repositories"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
} }
step_2_info() { echo "Install $mtaName"; } step_2_info() { echo "Install $mtaName"; }
step_2() { step_2() {
local aptOpt= confirm -n -y "In the following dialog chose \"Internet site\" and enter $MAS_DOMAIN as your domain. Enter to continue..."
if [ $QUIET -ne 0 ];then exe apt install $mtaDeps ${sq_aptOpt:-}
aptOpt="-y"
else
read -p "In the following dialog chose \"Internet site\" and enter $MAS_DOMAIN as your domain. Enter to continue..."
fi
exe apt install $mtaDeps $aptOpt
} }
step_3_info() { echo "Enable $mtaName"; } step_3_info() { echo "Enable $mtaName"; }
step_3() { step_3() {
exe systemctl enable $mtaName exe systemctl enable $mtaName
echo -e " [I] Printing $mtaName status\n" info "Printing $mtaName status"
exe service $mtaName status exe service $mtaName status
echo -e "\n [I] Installed postfix version: $(postconf mail_version)" info "Installed postfix version: $(postconf mail_version)"
} }
step_4_info() { echo "$mtaName basic domain configuration"; } step_4_info() { echo "$mtaName basic domain configuration"; }
@@ -74,17 +67,18 @@ step_4() {
step_5_info() { echo "$mtaName enable submission service"; } step_5_info() { echo "$mtaName enable submission service"; }
step_5() { step_5() {
echoseq -e " [I] Copy following lines...\n" local mtaConfSubmission="${seq_origin:?}/$toolName/submissionService"
local mtaConfSmtps="${seq_origin:?}/$toolName/smtpsService"
info "Copy following lines..."
exe cat "$mtaConfSubmission" exe cat "$mtaConfSubmission"
exe read -rep $'\nPress Enter to open the '$mtaConfLoc'/master.cf' confirm -n -y "Press Enter to open the $mtaConfLoc/master.cf"
exe vi $mtaConfLoc/master.cf editor $mtaConfLoc/master.cf
exe echoseq info
exe cat "$mtaConfSmtps" exe cat "$mtaConfSmtps"
exe read -rep $'\nPress Enter to open the '$mtaConfLoc'/master.cf' confirm -n -y "Press Enter to open the $mtaConfLoc/master.cf"
exe vi $mtaConfLoc/master.cf editor $mtaConfLoc/master.cf
} }
mtaConfSubmission="$WDIR/$toolName/submissionService"
mtaConfSmtps="$WDIR/$toolName/smtpsService"
step_6_info() { echo "Configure TLS"; } step_6_info() { echo "Configure TLS"; }
step_6() { step_6() {
@@ -97,7 +91,7 @@ step_6() {
exe postconf "smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1" exe postconf "smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1"
exe postconf "smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1" exe postconf "smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1"
echoseq " [I] Restarting $mtaName" info "Restarting $mtaName"
exe service $mtaName restart exe service $mtaName restart
} }
@@ -111,15 +105,15 @@ step_7() {
step_8_info() { echo "Install $mdaName"; } step_8_info() { echo "Install $mdaName"; }
step_8() { step_8() {
exe apt install $mdaDeps exe apt install $mdaDeps ${sq_aptOpt}
echoseq -e "\n [I] Installed version: $(dovecot --version)" info "Installed version: $(dovecot --version)"
} }
step_9_info() { step_9_info() {
echo "Configure $mdaName" echo "Configure $mdaName"
} }
step_9() { step_9() {
outColor green color green
cat <<MDA_EOF cat <<MDA_EOF
# Configuring Mailbox Location # Configuring Mailbox Location
[/etc/dovecot/conf.d/10-mail.conf] [/etc/dovecot/conf.d/10-mail.conf]
@@ -205,20 +199,13 @@ step_20_info() {
echo "Install postfixadmin and create mysql database" echo "Install postfixadmin and create mysql database"
echoinfo "Virtualize mailboxes, domains and aliases by using a mysql database" echoinfo "Virtualize mailboxes, domains and aliases by using a mysql database"
} }
step_20_alias() { ALIAS="virtual"; } step_20_alias() { echo "virtual"; }
step_20() { step_20() {
local qOpt= exe ${seq_origin:?}/postfixadmin.sh ${sqr_args} install
if [ $QUIET -ne 0 ] ; then
qOpt="-q"
fi
exe $WDIR/postfixadmin.sh ${qOpt} install
} }
step_21_info() { echo "Create $mtaName mysql query files"; } step_21_info() { echo "Create $mtaName mysql query files"; }
step_21() { step_21() {
# eval needed to expand sourced configuration variables
local localMysqlUser=`eval "echo \"$MAS_VIRTUAL_USER_PART\""`
exe mkdir -p "$mtaMysqlConfLoc" exe mkdir -p "$mtaMysqlConfLoc"
local mtaFile local mtaFile
@@ -232,11 +219,10 @@ step_21() {
"mysql_virtual_alias_domain_catchall_maps"\ "mysql_virtual_alias_domain_catchall_maps"\
) )
for mtaFile in ${mtaMysqlFiles[@]} for mtaFile in ${mtaMysqlFiles[@]} ; do
do mtaVar="MAS_${mtaFile}"
eval 'mtaVar=$MAS_'${mtaFile} info "creating ${mtaFile}.cf"
echoseq " [I] creating ${mtaFile}.cf" exep echo -e "\"${MAS_VIRTUAL_USER_PART:?}\\n${!mtaVar:?}\"" \> \"$mtaMysqlConfLoc/${mtaFile}.cf\"
exe echo -e "$localMysqlUser\n$mtaVar" > "$mtaMysqlConfLoc/${mtaFile}.cf"
done done
exe chown -R root:${mtaUser} "$mtaMysqlConfLoc" exe chown -R root:${mtaUser} "$mtaMysqlConfLoc"
@@ -259,7 +245,7 @@ step_22() {
exe postconf -e "virtual_gid_maps = static:$MAS_VIRTUAL_USER_ID" exe postconf -e "virtual_gid_maps = static:$MAS_VIRTUAL_USER_ID"
} }
step_23_info() { echo "Create virtual user $MAS_VIRTUAL_USER and folder $MAS_VIRTUAL_FOLDER_BASE"; } step_23_info() { echo "Create virtual user ${MAS_VIRTUAL_USER:-} and folder ${MAS_VIRTUAL_FOLDER_BASE:-}"; }
step_23() { step_23() {
exe mkdir -p "$MAS_VIRTUAL_FOLDER_BASE" exe mkdir -p "$MAS_VIRTUAL_FOLDER_BASE"
exe groupadd --gid $MAS_VIRTUAL_USER_ID $MAS_VIRTUAL_USER exe groupadd --gid $MAS_VIRTUAL_USER_ID $MAS_VIRTUAL_USER
@@ -267,75 +253,83 @@ step_23() {
exe chown -R ${MAS_VIRTUAL_USER}: "$MAS_VIRTUAL_FOLDER_BASE" exe chown -R ${MAS_VIRTUAL_USER}: "$MAS_VIRTUAL_FOLDER_BASE"
exe chmod -R 770 "$MAS_VIRTUAL_FOLDER_BASE" exe chmod -R 770 "$MAS_VIRTUAL_FOLDER_BASE"
echoseq " [I] Restarting $mtaName" info "Restarting $mtaName"
exe service $mtaName restart exe service $mtaName restart
} }
step_24_info() { echo "$mdaName virtualisation configuration instructions"; } step_24_info() { echo "$mdaName virtualisation configuration instructions"; }
step_24() { step_24() {
echo "# Configuring Mailbox Location" color green
echo " [/etc/dovecot/conf.d/10-mail.conf]" cat <<END_STEP24
echo " mail_location = maildir:~/Maildir" # Configuring Mailbox Location
echo " mail_home = ${MAS_VIRTUAL_FOLDER_BASE}/%d/%n" [/etc/dovecot/conf.d/10-mail.conf]
echo mail_location = maildir:~/Maildir
echo "# Configure authentication" mail_home = ${MAS_VIRTUAL_FOLDER_BASE}/%d/%n
echo " [/etc/dovecot/conf.d/10-auth.conf]"
echo " # Username with domain" # Configure authentication
echo " auth_username_format = %u" [/etc/dovecot/conf.d/10-auth.conf]
echo " # Find and uncomment following line" # Username with domain
echo " !include auth-sql.conf.ext" auth_username_format = %u
echo " # Comment following line to prevent local users from sending mail" # Find and uncomment following line
echo " # without having registered an email address" !include auth-sql.conf.ext
echo " #!include auth-system.conf.ext" # Comment following line to prevent local users from sending mail
echo " # Debug login issues in /var/log/maillog by adding:" # without having registered an email address
echo " auth_debug = yes" #!include auth-system.conf.ext
echo " auth_debug_passwords = yes" # Debug login issues in /var/log/maillog by adding:
echo auth_debug = yes
echo "# Adding mysql login information" auth_debug_passwords = yes
echo " [/etc/dovecot/dovecot-sql.conf.ext]"
echo " driver = mysql" # Adding mysql login information
echo " connect = host=$MAS_DBHOST dbname=$MAS_DBNAME user=$MAS_DBUSER password='${MAS_DBPASS}'" [/etc/dovecot/dovecot-sql.conf.ext]
echo " default_pass_scheme = MD5" driver = mysql
echo " password_query = SELECT username AS user,password FROM mailbox WHERE username = '%u' AND active='1'" connect = host=$MAS_DBHOST dbname=$MAS_DBNAME user=$MAS_DBUSER password='${MAS_DBPASS}'
echo " user_query = SELECT maildir, $MAS_VIRTUAL_USER_ID AS uid, $MAS_VIRTUAL_USER_ID AS gid FROM mailbox WHERE username = '%u' AND active='1'" default_pass_scheme = MD5
echo " iterate_query = SELECT username AS user FROM mailbox" password_query = SELECT username AS user,password FROM mailbox WHERE username = '%u' AND active='1'
user_query = SELECT maildir, $MAS_VIRTUAL_USER_ID AS uid, $MAS_VIRTUAL_USER_ID AS gid FROM mailbox WHERE username = '%u' AND active='1'
iterate_query = SELECT username AS user FROM mailbox
END_STEP24
} }
step_25_info() { step_25_info() {
echo "Configure sieve for virtual users" echo "Configure sieve for virtual users"
} }
step_25() { step_25() {
echo "# Sieve script configuration" color green
echo " [$mdaConfDir/90-sieve.conf]" cat << END_STEP25
echo " sieve = file:/var/vmail/%d/%n/sieve;active=/var/vmail/%d/%n/.dovecot.sieve" # Sieve script configuration
echo " sieve_extensions = +notify +imapflags +vnd.dovecot.execute" [$mdaConfDir/90-sieve.conf]
echo " sieve_plugins = sieve_extprograms" sieve = file:/var/vmail/%d/%n/sieve;active=/var/vmail/%d/%n/.dovecot.sieve
echo " sieve_user_log = file:/var/vmail/%d/%n/sieve/sieve.log" sieve_extensions = +notify +imapflags +vnd.dovecot.execute
echo sieve_plugins = sieve_extprograms
echo "# Enable sieve for lmtp" sieve_user_log = file:/var/vmail/%d/%n/sieve/sieve.log
echo " [$mdaConfDir/20-lmtp.conf]"
echo " postmaster_address = postmaster@$MAS_DOMAIN" # Enable sieve for lmtp
echo " mail_plugins = $mail_plugins sieve" [$mdaConfDir/20-lmtp.conf]
echo postmaster_address = postmaster@$MAS_DOMAIN
echo "# Enable excution of external programs (e.g. to send xmpp messages on certain keywords)" mail_plugins = \$mail_plugins sieve
echo " [$mdaConfDir/90-sieve-extprograms.conf]"
echo " sieve_execute_bin_dir = /usr/lib/dovecot/sieve-execute" # Enable excution of external programs (e.g. to send xmpp messages on certain keywords)
echo [$mdaConfDir/90-sieve-extprograms.conf]
echo "# Notes on execution of scripts" sieve_execute_bin_dir = /usr/lib/dovecot/sieve-execute
echo " * Scripts are executed with the $MAS_VIRTUAL_USER user"
echo " * Scripts must no be writeable by others" # Notes on execution of scripts
echo " (chown root:$MAS_VIRTUAL_USER script; chmod 750 script)" * Scripts are executed with the $MAS_VIRTUAL_USER user
echo " * \$HOME is set to the virtual users home" * Scripts must no be writeable by others
echo " (e.g. /var/vmail/$MAS_DOMAIN/max)" (chown root:$MAS_VIRTUAL_USER script; chmod 750 script)
echo * \$HOME is set to the virtual users home
echo "# Notes about sendxmpp" (e.g. /var/vmail/$MAS_DOMAIN/max)
echo " * .sendxmpprc resides in every virtual users home"
echo " and must be owned by $MAS_VIRTUAL_USER" # Notes about sendxmpp
echo " (chown $MAS_VIRTUAL_USER: .sendxmpprc; chmod 700 .sendxmpprc)" * .sendxmpprc resides in every virtual users home
and must be owned by $MAS_VIRTUAL_USER
(chown $MAS_VIRTUAL_USER: .sendxmpprc; chmod 700 .sendxmpprc)
END_STEP25
} }
step_50_info() { echo "Adding default relay host for sending mails"; } step_50_info() { echo "Adding default relay host for sending mails"; }
step_50_alias() { ALIAS="default_relay"; } step_50_alias() { echo "default_relay"; }
step_50() { step_50() {
if [ ! -f "$saslPassFile" ] ; then if [ ! -f "$saslPassFile" ] ; then
exe postconf -e "relayhost = $MAS_RELAYHOST" exe postconf -e "relayhost = $MAS_RELAYHOST"
@@ -343,7 +337,7 @@ step_50() {
exe postconf -e "smtp_sasl_password_maps = hash:$saslPassFile" exe postconf -e "smtp_sasl_password_maps = hash:$saslPassFile"
addConf -s "$MAS_RELAYHOST $MAS_RELAYUSER:$MAS_RELAYPASS" "$saslPassFile" addConf -s "$MAS_RELAYHOST $MAS_RELAYUSER:$MAS_RELAYPASS" "$saslPassFile"
fi fi
echoseq " [I] Updating $saslPassFile" info "Updating $saslPassFile"
exe postmap "$saslPassFile" exe postmap "$saslPassFile"
} }
saslPassFile="$mtaConfLoc/sasl_password" saslPassFile="$mtaConfLoc/sasl_password"
@@ -352,17 +346,17 @@ step_52_info() {
echo "Grant access for specific (local) hostnames" echo "Grant access for specific (local) hostnames"
echoinfo "Workaround when local clients connect to 25 with different ips (v6)" echoinfo "Workaround when local clients connect to 25 with different ips (v6)"
} }
step_52_alias() { ALIAS="client_access"; } step_52_alias() { echo "client_access"; }
step_52() { step_52() {
if [ ! -f "$mtaClientAccessLoc" ] ; then if [ ! -f "$mtaClientAccessLoc" ] ; then
echo " [I] Generating $mtaClientAccessLoc" info "Generating $mtaClientAccessLoc"
exep "echo \"# myhost.lan OK\" > \"$mtaClientAccessLoc\"" exep echo "# myhost.lan OK" \> "$mtaClientAccessLoc"
echo " [I] Don't forget to add the following" info "Don't forget to add the following"
echo " [$mtaConfLoc/main.cf]" info -a "[$mtaConfLoc/main.cf]"
echo " smtpd_relay_restrictions =" info -a " smtpd_relay_restrictions ="
echo " check_client_access hash:$mtaClientAccessLoc" info -a " check_client_access hash:$mtaClientAccessLoc"
fi fi
echoseq " [I] Updating $mtaClientAccessLoc" info "Updating $mtaClientAccessLoc"
exe postmap "$mtaClientAccessLoc" exe postmap "$mtaClientAccessLoc"
} }
mtaClientAccessLoc="$mtaConfLoc/client_access" mtaClientAccessLoc="$mtaConfLoc/client_access"
@@ -370,26 +364,26 @@ mtaClientAccessLoc="$mtaConfLoc/client_access"
step_54_info() { step_54_info() {
echo "Deny recipient access for listed mail addresses" echo "Deny recipient access for listed mail addresses"
} }
step_54_alias() { ALIAS="recipient_access"; } step_54_alias() { echo "recipient_access"; }
step_54() { step_54() {
if [ ! -f "$mtaRecipientAccessLoc" ] ; then if [ ! -f "$mtaRecipientAccessLoc" ] ; then
echoseq " [I] Generating $mtaRecipientAccessLoc" info "Generating $mtaRecipientAccessLoc"
exep "echo \"# unwanted@${MAS_DOMAIN} 550 No mailbox. Nothing to see here.\" > \"$mtaRecipientAccessLoc\"" exep "echo \"# unwanted@${MAS_DOMAIN} 550 No mailbox. Nothing to see here.\" > \"$mtaRecipientAccessLoc\""
echo " [I] Don't forget to add the following" info "Don't forget to add the following"
echo " [$mtaConfLoc/main.cf]" info -a "[$mtaConfLoc/main.cf]"
echo " smtpd_recipient_restrictions =" info -a " smtpd_recipient_restrictions ="
echo " check_recipient_access hash:$mtaRecipientAccessLoc" info -a " check_recipient_access hash:$mtaRecipientAccessLoc"
fi fi
echoseq " [I] Updating $mtaRecipientAccessLoc" info "Updating $mtaRecipientAccessLoc"
exe postmap "$mtaRecipientAccessLoc" exe postmap "$mtaRecipientAccessLoc"
} }
mtaRecipientAccessLoc="$mtaConfLoc/recipient_access" mtaRecipientAccessLoc="$mtaConfLoc/recipient_access"
step_56_info() { echo "Add sender dependant relay with authentication"; } step_56_info() { echo "Add sender dependant relay with authentication"; }
step_56_alias() { ALIAS="sender_relay"; } step_56_alias() { echo "sender_relay"; }
step_56() { step_56() {
if [ ! -f "$mtaSenderRelayLoc" ] ; then if [ ! -f "$mtaSenderRelayLoc" ] ; then
echoseq " [I] Generating $mtaSenderRelayLoc" info "Generating $mtaSenderRelayLoc"
exep "echo \"# user@extern.com smtp:[mail.extern.com]:587\" > \"$mtaSenderRelayLoc\"" exep "echo \"# user@extern.com smtp:[mail.extern.com]:587\" > \"$mtaSenderRelayLoc\""
exe postconf -e "smtp_sender_dependent_authentication = yes" exe postconf -e "smtp_sender_dependent_authentication = yes"
exe postconf -e "sender_dependent_relayhost_maps = hash:$mtaSenderRelayLoc" exe postconf -e "sender_dependent_relayhost_maps = hash:$mtaSenderRelayLoc"
@@ -397,12 +391,12 @@ step_56() {
exe postconf -e "smtp_sasl_mechanism_filter = plain" exe postconf -e "smtp_sasl_mechanism_filter = plain"
exe postconf -e "smtp_tls_security_level = encrypt" exe postconf -e "smtp_tls_security_level = encrypt"
exe postconf -e "smtp_tls_mandatory_ciphers = high" exe postconf -e "smtp_tls_mandatory_ciphers = high"
echo " [I] Don't forget to add credentials for the new relay" info "Don't forget to add credentials for the new relay"
echo " [$saslPassFile]" info -a "[$saslPassFile]"
echo " user@extern.com username:passwort" info -a " user@extern.com username:passwort"
echo " postmap $saslPassFile" info -a "postmap $saslPassFile"
fi fi
echoseq " [I] Updating $mtaSenderRelayLoc" info "Updating $mtaSenderRelayLoc"
exe postmap "$mtaSenderRelayLoc" exe postmap "$mtaSenderRelayLoc"
exe postmap "$saslPassFile" exe postmap "$saslPassFile"
} }
@@ -412,38 +406,33 @@ step_100_info() {
echo "Send testmail [-u SYSTEMUSER | -f FROM] [TO]" echo "Send testmail [-u SYSTEMUSER | -f FROM] [TO]"
echoinfo "Send as current user to postmaster@\$MAS_DOMAIN by default" echoinfo "Send as current user to postmaster@\$MAS_DOMAIN by default"
} }
step_100_alias() { ALIAS="test"; } step_100_alias() { echo "test"; }
step_100() { step_100() {
shift shift
local arg
local fromAdr local fromAdr
local toAdr="postmaster@$MAS_DOMAIN" local toAdr="postmaster@$MAS_DOMAIN"
local asUser= local asUser=
for arg in "$@" ; do for _ in "$@" ; do
case "$1" in case "$1" in
-f) -f)
shift shift
fromAdr="-f $1 " fromAdr="-f ${1:-} "
shift shift ;;
;;
-u) -u)
shift shift
asUser="sudo -u $1 " asUser="sudo -u ${1:-} "
shift shift ;;
;;
*) *)
break break ;;
;;
esac esac
done done
if [ ! -z $1 ] ; then [ -n "${1:-}" ] && toAdr="$1"
toAdr="$1"
fi exe ${asUser}sh -c "echo \"Subject: Test from Postfix\nIt is \$(date)\n\nGreetings \$(whoami)\" | sendmail ${fromAdr:-}${toAdr}"
exe ${asUser}sh -c "echo \"Subject: Test from Postfix\nIt is \$(date)\n\nGreetings \$(whoami)\" | sendmail ${fromAdr}$toAdr"
} }
step_102_info() { echo "Show mail queue"; } step_102_info() { echo "Show mail queue"; }
step_102_alias() { ALIAS="showqueue"; } step_102_alias() { echo "showqueue"; }
step_102() { step_102() {
exe sendmail -bp exe sendmail -bp
} }
@@ -452,15 +441,15 @@ step_104_info() {
echo "Delete mail queue [ID]" echo "Delete mail queue [ID]"
echoinfo "Delete all queued mails if [ID] is empty" echoinfo "Delete all queued mails if [ID] is empty"
} }
step_104_alias() { ALIAS="delqueue"; } step_104_alias() { echo "delqueue"; }
step_104() { step_104() {
shift shift
local msgId="ALL" local msgId="ALL"
if [ ! -z $1 ] ; then [ -n "${1:-}" ] && msgId="$1"
msgId="$1"
fi
exe postsuper -d "$msgId" exe postsuper -d "$msgId"
} }
VERSION_SEQREV=12 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,68 +1,56 @@
#!/bin/bash #!/bin/bash
toolName=matrix-commander readonly toolName=matrix-commander
toolCloneUrl='https://github.com/8go/matrix-commander.git' readonly toolCloneUrl='https://github.com/8go/matrix-commander.git'
toolDeps="python3-pip python3-venv libolm-dev" readonly toolDeps="python3-pip python3-venv libolm-dev"
toolCredentialDir= toolCredentialDir=
toolEncStoreDir= toolEncStoreDir=
# Get script working directory sq_aptOpt=
# (when called from a different directory)
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)"
APTOPT=
CONFIG=0
SCRIPT_FILE=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_FILE%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
## or to use sequencer api with global config file: ## or to use sequencer api with global config file:
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then
CONFIG=1
else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return -1 dry || return -1
fi fi
toolCredentialDir="$MACO_BASE_DIR/.config/matrix-commander" toolCredentialDir="$MACO_BASE_DIR/.config/matrix-commander"
toolEncStoreDir="$MACO_BASE_DIR/.local/share/matrix-commander" toolEncStoreDir="$MACO_BASE_DIR/.local/share/matrix-commander"
## Apt cmdline option to suppress user interaction ## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y" quiet && sq_aptOpt="-y"
## Return of non zero value will abort the sequence ## Return of non zero value will abort the sequence
return 0 return 0
} }
step_1_info() { echo "Run $toolName"; } step_1_info() { echo "Run $toolName"; }
step_1_alias() { ALIAS="run"; } step_1_alias() { echo "run"; }
step_1() { step_1() {
shift shift
exe "$MACO_BASE_DIR/bin/python3" "$MACO_DIR/matrix-commander.py" "$@" exe "$MACO_BASE_DIR/bin/python3" "$MACO_DIR/matrix_commander/matrix_commander.py" "$@"
} }
step_3_info() { step_3_info() {
echoinfoArgs "[MESSAGE] [MESSAGE] ..."
echo "Send message" echo "Send message"
echoinfo "Each string ([MESSAGE]) is send as separate message" echoinfo "Each string ([MESSAGE]) is send as separate message"
} }
step_3_alias() { ALIAS="message"; } step_3_options() { echo "[MESSAGE] [MESSAGE] ..."; }
step_3_alias() { echo "message"; }
step_3() { step_3() {
shift shift
step run -m "$@" step run -m "$@"
} }
step_50_info() { echo "Install $toolName dependencies"; } step_50_info() { echo "Install $toolName dependencies"; }
step_50_alias() { ALIAS="install"; } step_50_alias() { echo "install"; }
step_50() { step_50() {
apt install $toolDeps $APTOPT apt install $toolDeps $sq_aptOpt
} }
step_51_info() { echo "Add system user $MACO_USER"; } step_51_info() { echo "Add system user ${MACO_USER:-}"; }
step_51() { step_51() {
id $MACO_USER >/dev/null 2>&1 id $MACO_USER >/dev/null 2>&1
[ $? -eq 0 ] && endReturn -o 1 "User $MACO_USER already exists" [ $? -eq 0 ] && endReturn -o 1 "User $MACO_USER already exists"
@@ -75,7 +63,7 @@ step_52() {
[ -e "$MACO_BASE_DIR" ] && endReturn -o 1 "$toolName already installed" [ -e "$MACO_BASE_DIR" ] && endReturn -o 1 "$toolName already installed"
exe python3 -m venv "$MACO_BASE_DIR" exe python3 -m venv "$MACO_BASE_DIR"
endReturn -o $? "Creating virtual environment failed" endReturn "Creating virtual environment failed"
exe git clone $toolCloneUrl "$MACO_DIR" exe git clone $toolCloneUrl "$MACO_DIR"
exe chown -R $MACO_USER: "$MACO_BASE_DIR" exe chown -R $MACO_USER: "$MACO_BASE_DIR"
@@ -91,7 +79,7 @@ dbus-python
notify2 notify2
NOTES_END NOTES_END
exe read -p "Enter to continue..." exe read -p "Enter to continue..."
exe "$DEFAULT_EDITOR_SYSTEM" "$MACO_DIR/requirements.txt" exe editor "$MACO_DIR/requirements.txt"
exe sudo -u $MACO_USER ${MACO_BASE_DIR}/bin/pip install -r ${MACO_DIR}/requirements.txt exe sudo -u $MACO_USER ${MACO_BASE_DIR}/bin/pip install -r ${MACO_DIR}/requirements.txt
} }
@@ -99,7 +87,7 @@ step_55_info() {
echo "Create systemd service for $toolName" echo "Create systemd service for $toolName"
echoinfo "(Make sure to modify the service content in the step configuration)" echoinfo "(Make sure to modify the service content in the step configuration)"
} }
step_55_alias() { ALIAS="service"; } step_55_alias() { echo "service"; }
step_55() { step_55() {
local macommanderServiceLoc="/etc/systemd/system/matrix-commander.service" local macommanderServiceLoc="/etc/systemd/system/matrix-commander.service"
addConf -s "$MACO_SERVICE" "$macommanderServiceLoc" addConf -s "$MACO_SERVICE" "$macommanderServiceLoc"
@@ -107,19 +95,19 @@ step_55() {
} }
step_57_info() { echo "First run to create credential file and encryption store"; } step_57_info() { echo "First run to create credential file and encryption store"; }
step_57_alias() { ALIAS="firstrun"; } step_57_alias() { echo "firstrun"; }
step_57() { step_57() {
exe sudo -u "$MACO_USER" mkdir -p "$toolCredentialDir" "$toolEncStoreDir" exe sudo -u "$MACO_USER" mkdir -p "$toolCredentialDir" "$toolEncStoreDir"
exe cd "$toolCredentialDir" exe cd "$toolCredentialDir"
step run step run
[ -e ./store ] && exe mv store "$toolEncStoreDir" [ -e ./store ] && exe mv store "$toolEncStoreDir"
echoseq " [I] use \"$SEQ_NAME run --verify\" to verify against an existing session (like Element)" info "use \"$SEQ_NAME run --verify\" to verify against an existing session (like Element)"
} }
step_60_alias() { ALIAS="notes"; } step_60_alias() { echo "notes"; }
step_60() { step_60() {
outColor green color green
cat <<NOTES_EOF cat <<NOTES_EOF
# Verify matrix-commander "device" # Verify matrix-commander "device"
@@ -140,5 +128,7 @@ credentials.json - $MACO_BASE_DIR/.config/matrix-commander/credentials.json
NOTES_EOF NOTES_EOF
} }
VERSION_SEQREV=15 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -14,36 +14,36 @@ SCRIPT_NAME=${SCRIPT_FILE%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg" CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
## or to use sequencer api with global config file: ## or to use sequencer api with global config file:
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
CONFIG=1 CONFIG=1
else else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return -1 dry || return -1
fi fi
## Apt cmdline option to suppress user interaction ## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y" quiet && APTOPT="-y"
echoerr " [W] $SCRIPT_NAME is still in alpha stage" warning -e "$SCRIPT_NAME is still in alpha stage"
echoerr " TODO: - systemd script" error -e " TODO: - systemd script"
echoerr " - initial config creation" error -e " - initial config creation"
## Return of non zero value will abort the sequence ## Return of non zero value will abort the sequence
return 0 return 0
} }
step_1_info() { echo "Install $toolName dependencies"; } step_1_info() { echo "Install $toolName dependencies"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exep curl -sL https://deb.nodesource.com/setup_12.x \| bash - exep curl -sL https://deb.nodesource.com/setup_12.x \| bash -
exe apt install $toolAptDeps $APTOPT exe apt install $toolAptDeps $APTOPT
} }
step_2_info() { echo "Setup and build"; } step_2_info() { echo "Setup and build"; }
step_2_alias() { ALIAS="setup"; } step_2_alias() { echo "setup"; }
step_2() { step_2() {
if [ ! -e "$SEQ_DIMENSION_DIR" ]; then if [ ! -e "$SEQ_DIMENSION_DIR" ]; then
exe mkdir -p "$SEQ_DIMENSION_DIR" exe mkdir -p "$SEQ_DIMENSION_DIR"
@@ -62,10 +62,10 @@ step_2() {
} }
step_10_info() { echo "Start $toolName"; } step_10_info() { echo "Start $toolName"; }
step_10_alias() { ALIAS="start"; } step_10_alias() { echo "start"; }
step_10() { step_10() {
if [ ! -e "$SEQ_DIMENSION_DIR" ]; then if [ ! -e "$SEQ_DIMENSION_DIR" ]; then
echoerr " [E] $toolName not found ad $SEQ_DIMENSION_DIR" error -e "$toolName not found ad $SEQ_DIMENSION_DIR"
return 1; return 1;
fi fi
exe cd "$SEQ_DIMENSION_DIR" exe cd "$SEQ_DIMENSION_DIR"
@@ -75,5 +75,5 @@ step_10() {
exep NODE_ENV=production node build/app/index.js exep NODE_ENV=production node build/app/index.js
} }
VERSION_SEQREV=15 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,14 +1,14 @@
#!/bin/bash #!/bin/bash
toolName=synapse readonly toolName=synapse
toolDeps="build-essential python3-dev libffi-dev python3-pip python3-setuptools postgresql libssl-dev virtualenv libjpeg-dev libxslt1-dev libpq5 libpq-dev" toolDeps="build-essential python3-dev libffi-dev python3-pip python3-venv python3-setuptools postgresql libssl-dev libjpeg-dev libxslt1-dev libpq5 libpq-dev"
toolDeps+=" jq" # used as helper for api access readonly toolDeps+=" jq" # used as helper for api access
toolDepsRaspi="libopenjp2-7 libtiff5" toolDepsRaspi="libopenjp2-7 libtiff5"
toolUser="synapse" readonly toolUser="synapse"
toolGroup="synapse" readonly toolGroup="synapse"
toolServiceName="matrix-synapse" readonly toolServiceName="matrix-synapse"
synapseHashTool="env/bin/hash_password" readonly synapseHashTool="venv/bin/hash_password"
toolUrlLocal="http://localhost:8008" readonly toolUrlLocal="http://localhost:8008"
# Filled by configuration # Filled by configuration
toolConfig= toolConfig=
toolUrl= toolUrl=
@@ -18,16 +18,12 @@ postgresDb=""
postgresUser="" postgresUser=""
postgresPass="" postgresPass=""
# Get script working directory sq_aptOpt=
# (when called from a different directory) sq_config=0
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG=0
CONFIG_FILE_NAME="matrix.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
if [ "$(which lsb_release)" == "" ] ; then if [ "$(which lsb_release)" == "" ] ; then
echoerr " [W] Cannot detect OS. Assuming Raspberry Pi OS" warning -e "Cannot detect OS. Assuming Raspberry Pi OS"
osName="Raspbian" osName="Raspbian"
else else
osName=$(lsb_release -is) osName=$(lsb_release -is)
@@ -35,47 +31,44 @@ step_config() {
fi fi
if [ "$osName" == "" ] ; then if [ "$osName" == "" ] ; then
echoerr " [W] Error dedecting OS. Assuming Raspberry Pi OS" warning -e "Error dedecting OS. Assuming Raspberry Pi OS"
osName="Raspbian" osName="Raspbian"
fi fi
echo " [I] Detected OS: $osName $distName" info "Detected OS: $osName $distName"
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then sq_config=1
CONFIG=1
toolConfig="${MATRIX_HOME}/homeserver.yaml" toolConfig="${MATRIX_HOME}/homeserver.yaml"
toolUrl="https://$MATRIX_DOMAIN" toolUrl="https://$MATRIX_DOMAIN"
localHome="$MATRIX_HOME" localHome="$MATRIX_HOME"
echo " $toolName home: $MATRIX_HOME" info -a "$toolName home: $MATRIX_HOME"
echo " $toolName domain: $MATRIX_DOMAIN" info -a "$toolName domain: $MATRIX_DOMAIN"
else
# End if no configuration file exists
dry || return 1
fi fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
return 0 return 0
} }
step_1_info() { echo "Installing $toolName dependencies"; } step_1_info() { echo "Installing $toolName dependencies"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local aptOption=
exe apt update exe apt update
endReturn -o $? "Updating apt repositories failed" endReturn "Updating apt repositories failed"
if [ $QUIET -ne 0 ] ; then
aptOption="-y"
else
aptOption=""
fi
if [ "$osName" != "Raspbian" ] ; then if [ "$osName" != "Raspbian" ] ; then
toolDepsRaspi="" toolDepsRaspi=""
fi fi
exe apt install $toolDeps $toolDepsRaspi $aptOption exe apt install $toolDeps $toolDepsRaspi ${sq_aptOpt}
} }
step_2_info() { echo "Create postgres database for $toolName"; } step_2_info() { echo "Create postgres database for $toolName"; }
step_2_alias() { ALIAS="createdb"; } step_2_alias() { echo "createdb"; }
step_2() { step_2() {
readDatabaseInfos readDatabaseInfos
@@ -92,19 +85,23 @@ step_3() {
} }
step_4_info() { echo "Install $toolName"; } step_4_info() { echo "Install $toolName"; }
step_4_alias() { ALIAS="virtualenv"; } step_4_alias() { echo "virtualenv"; }
step_4() { step_4() {
exe mkdir -p "$MATRIX_HOME" exe mkdir -p "$MATRIX_HOME"
exe virtualenv -p python3 "${MATRIX_HOME}/env" exe python3 -m venv "${MATRIX_HOME}/venv"
exe cd "$MATRIX_HOME" exe cd "$MATRIX_HOME"
exe source "${MATRIX_HOME}/env/bin/activate" disableErrorCheck
exe source "${MATRIX_HOME}/venv/bin/activate"
enableErrorCheck
exe pip install --upgrade pip exe pip install --upgrade pip
exe pip install --upgrade setuptools exe pip install --upgrade setuptools
exe pip install matrix-synapse[postgres] lxml # bcrypt and cryptography last version before requiring rust to compile
# hiredis and txredisapi needed by redis
exe pip install matrix-synapse[postgres] lxml psycopg2 hiredis txredisapi
} }
step_5_info() { echo "Create default configuration and folder structure"; } step_5_info() { echo "Create default configuration and folder structure"; }
step_5_alias() { ALIAS="defaultconfig"; } step_5_alias() { echo "defaultconfig"; }
step_5() { step_5() {
# Create default configuration # Create default configuration
exe python3 -m synapse.app.homeserver --server-name "$MATRIX_DOMAIN" --config-path homeserver.yaml --generate-config --report-stats=no exe python3 -m synapse.app.homeserver --server-name "$MATRIX_DOMAIN" --config-path homeserver.yaml --generate-config --report-stats=no
@@ -124,7 +121,7 @@ step_6() {
} }
step_7_info() { echo "Create $toolName systemd service"; } step_7_info() { echo "Create $toolName systemd service"; }
step_7_alias() { ALIAS="systemd"; } step_7_alias() { echo "systemd"; }
step_7() { step_7() {
# eval needed to expand sourced configuration variables # eval needed to expand sourced configuration variables
local localService=`eval "echo \"$toolService\""` local localService=`eval "echo \"$toolService\""`
@@ -141,9 +138,9 @@ After=network.target postgresql.service
[Service] [Service]
Type=forking Type=forking
WorkingDirectory=\${MATRIX_HOME}/ WorkingDirectory=\${MATRIX_HOME}/
ExecStart=\${MATRIX_HOME}/env/bin/synctl start ExecStart=\${MATRIX_HOME}/venv/bin/synctl start
ExecStop=\${MATRIX_HOME}/env/bin/synctl stop ExecStop=\${MATRIX_HOME}/venv/bin/synctl stop
ExecReload=\${MATRIX_HOME}/env/bin/synctl restart ExecReload=\${MATRIX_HOME}/venv/bin/synctl restart
User=\${toolUser} User=\${toolUser}
Group=\${toolGroup} Group=\${toolGroup}
Restart=always Restart=always
@@ -156,46 +153,50 @@ WantedBy=multi-user.target"
step_10_info() { step_10_info() {
echo -n "Upgrade $toolName installation" echo -n "Upgrade $toolName installation"
if [ $CONTEXT_HELP -eq 0 ] ; then if ! contextHelp ; then
echo " at $MATRIX_HOME" echo " at $MATRIX_HOME"
else else
echo echo
fi fi
} }
step_10_alias() { ALIAS="upgrade"; } step_10_alias() { echo "upgrade"; }
step_10() { step_10() {
echo " [I] Upgrading $toolName" if [[ -z "$(command -v rustc)" ]] ; then
exe source "${MATRIX_HOME}/env/bin/activate" info "Rust compiler not found an might be needed."
confirm "Continue without Rust?" || return 1
fi
info "Upgrading $toolName"
disableErrorCheck
exe source "${MATRIX_HOME}/venv/bin/activate"
exe pip install --upgrade pip exe pip install --upgrade pip
exe pip install --upgrade matrix-synapse exe pip install --upgrade matrix-synapse
saveReturn $? saveReturn $?
exe deactivate exe deactivate
enableErrorCheck
endReturn "Error upgrading $toolName" endReturn "Error upgrading $toolName"
echo " [I] Restarting $toolName" info "Restarting $toolName"
step restart step restart
echo " [I] New Version:" info "New Version:"
exe sleep 2 exe sleep 2
step version step version
} }
step_12_info() { echo "Restart $toolName systemd service"; echo; } step_12_info() { echo "Restart $toolName systemd service"; echo; }
step_12_alias() { ALIAS="restart"; } step_12_alias() { echo "restart"; }
step_12() { step_12() {
exe service ${toolServiceName} restart exe service ${toolServiceName} restart
} }
step_14_info() { step_14_info() {
echoinfoArgs "[IP]:8008"
echo "Show $toolName version" echo "Show $toolName version"
} }
step_14_alias() { ALIAS="version"; } step_14_options() { echo "[IP]:8008"; }
step_14_alias() { echo "version"; }
step_14() { step_14() {
local synapseIP=localhost local synapseIP=localhost
shift shift
if [ ! -z $1 ]; then [ -n "${1:-}" ] && synapseIP="$1"
synapseIP="$1"
fi
local apiCall="http://${synapseIP}:8008/_synapse/admin/v1/server_version" local apiCall="http://${synapseIP}:8008/_synapse/admin/v1/server_version"
# -sS to suppress download progress of curl # -sS to suppress download progress of curl
@@ -203,21 +204,21 @@ step_14() {
} }
step_16_info() { step_16_info() {
echoinfoArgs "[OPTION] [IP]:8008"
echo "List all registered users" echo "List all registered users"
echoinfo "[OPTION]" echoinfo "[OPTION]"
echoinfo " -r : Raw json output" echoinfo " -r : Raw json output"
} }
step_16_alias() { ALIAS="listuser"; } step_16_options() { echo "[OPTION] [IP]:8008"; }
step_16_alias() { echo "listuser"; }
step_16() { step_16() {
adminTokenCheck adminTokenCheck
endReturn -o $? "Admin token needed. Check $SEQ_CONFIG_FILE" endReturn "Admin token needed. Check $seq_configFile"
shift shift
local synapseIP=localhost local synapseIP=localhost
local grepOut=" | grep -E '(\"total\":|\"name\":)'" local grepOut=" | grep -E '(\"total\":|\"name\":)'"
for arg in "$@" ; do for _ in "$@" ; do
case "$1" in case "$1" in
-r) -r)
grepOut="" grepOut=""
@@ -229,39 +230,37 @@ step_16() {
esac esac
done done
if [ ! -z $1 ]; then [ -n "${1:-}" ] && synapseIP="$1"
synapseIP="$1"
fi
local apiCall="http://${synapseIP}:8008/_synapse/admin/v2/users" local apiCall="http://${synapseIP}:8008/_synapse/admin/v2/users"
exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \"$apiCall\" | python -m json.tool $grepOut" exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \"$apiCall\" | python -m json.tool $grepOut"
} }
step_18_info() { echo "Create new user"; } step_18_info() { echo "Create new user"; }
step_18_alias() { ALIAS="adduser"; } step_18_alias() { echo "adduser"; }
step_18() { step_18() {
exe /opt/synapse/env/bin/register_new_matrix_user -c "$MATRIX_HOME/homeserver.yaml" $toolUrlLocal exe /opt/synapse/venv/bin/register_new_matrix_user -c "$MATRIX_HOME/homeserver.yaml" $toolUrlLocal
} }
step_20_info() { step_20_info() {
shift shift
echoinfoArgs "[USER NAME]"
echo -n "Reset user password" echo -n "Reset user password"
[ $CONTEXT_EXE -ne 0 ] && echoinfo " for $1" || echo contextExe && echoinfo " for ${1:-}" || echo
} }
step_20_alias() { ALIAS="resetpw"; } step_20_options() { echo "[USER NAME]"; }
step_20_alias() { echo "resetpw"; }
step_20() { step_20() {
shift shift
local user= local user=
if [ ! -z $1 ]; then if [ -n "${1:-}" ]; then
user="$1" user="$1"
else else
exe read -p "User name: " user exe read -p "User name: " user
fi fi
if [ -z $user ]; then if [ -z $user ]; then
echoerr "No user name provided" error -e "No user name provided"
return 1 return 1
fi fi
local pw="$("${MATRIX_HOME}/${synapseHashTool}")" local pw="$("${MATRIX_HOME}/${synapseHashTool}")"
@@ -272,22 +271,22 @@ step_20() {
} }
step_22_info() { step_22_info() {
echoinfoArgs "[OPTION] [IP]:8008"
echo "List all rooms" echo "List all rooms"
echoinfo "[OPTION]" echoinfo "[OPTION]"
echoinfo " -r : Raw json output" echoinfo " -r : Raw json output"
} }
step_22_alias() { ALIAS="listrooms"; } step_22_options() { echo "[OPTION] [IP]:8008"; }
step_22_alias() { echo "listrooms"; }
step_22() { step_22() {
adminTokenCheck adminTokenCheck
endReturn -o $? "Admin token needed. Check $SEQ_CONFIG_FILE" endReturn "Admin token needed. Check $seq_configFile"
shift shift
local arg local arg
local synapseIP=localhost local synapseIP=localhost
local grepOut=" | grep -E '(\"total\":|\"name\":|\"room_id\":)'" local grepOut=" | grep -E '(\"total\":|\"name\":|\"room_id\":)'"
for arg in "$@" ; do for _ in "$@" ; do
case "$1" in case "$1" in
-r) -r)
grepOut="" grepOut=""
@@ -299,31 +298,29 @@ step_22() {
esac esac
done done
if [ ! -z $1 ]; then [ -n "${1:-}" ] && synapseIP="$1"
synapseIP="$1"
fi
local apiCall="http://${synapseIP}:8008/_synapse/admin/v1/rooms" local apiCall="http://${synapseIP}:8008/_synapse/admin/v1/rooms"
exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \"$apiCall\" | python -m json.tool $grepOut" exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \"$apiCall\" | python -m json.tool $grepOut"
} }
step_24_info() { step_24_info() {
echoinfoArgs "[OPTION] [ROOM ID] [IP]:8008"
echo "List all room members" echo "List all room members"
echoinfo "[OPTION]" echoinfo "[OPTION]"
echoinfo " -r : Raw json output" echoinfo " -r : Raw json output"
} }
step_24_alias() { ALIAS="listmember"; } step_24_options() { echo "[OPTION] [ROOM ID] [IP]:8008"; }
step_24_alias() { echo "listmember"; }
step_24() { step_24() {
adminTokenCheck adminTokenCheck
endReturn -o $? "Admin token needed. Check $SEQ_CONFIG_FILE" endReturn "Admin token needed. Check $seq_configFile"
shift shift
local roomId="" local roomId=""
local synapseIP=localhost local synapseIP=localhost
local grepOut=" | grep -E '(\"total\":|\"members\":|\"@)'" local grepOut=" | grep -E '(\"total\":|\"members\":|\"@)'"
for arg in "$@" ; do for _ in "$@" ; do
case "$1" in case "$1" in
-r) -r)
grepOut="" grepOut=""
@@ -335,37 +332,33 @@ step_24() {
esac esac
done done
if [ ! -z $1 ]; then if [ -n "${1:-}" ]; then
roomId="$1" roomId="$1"
shift shift
fi fi
if [ ! -z $1 ]; then [ -n "${1:-}" ] && synapseIP="$1"
synapseIP="$1"
fi
local apiCall="http://${synapseIP}:8008/_synapse/admin/v1/rooms/$roomId/members" local apiCall="http://${synapseIP}:8008/_synapse/admin/v1/rooms/$roomId/members"
exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \"$apiCall\" | python -m json.tool $grepOut" exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \"$apiCall\" | python -m json.tool $grepOut"
} }
step_26_info() { step_26_info() {
echoinfoArgs "[IP]:8008"
echo "Delete rooms without local users" echo "Delete rooms without local users"
echoinfo " [IP] : default is localhost" echoinfo " [IP] : default is localhost"
} }
step_26_alias() { ALIAS="purge"; } step_26_options() { echo "[IP]:8008"; }
step_26_alias() { echo "purge"; }
step_26() { step_26() {
adminTokenCheck adminTokenCheck
endReturn -o $? "Admin token needed. Check $SEQ_CONFIG_FILE" endReturn "Admin token needed. Check $seq_configFile"
shift shift
local i local i
local arg local arg
local synapseIP=localhost local synapseIP=localhost
if [ ! -z $1 ]; then [ -n "${1:-}" ] && synapseIP="$1"
synapseIP="$1"
fi
local apiCall="http://${synapseIP}:8008/_synapse/admin/v1/rooms" local apiCall="http://${synapseIP}:8008/_synapse/admin/v1/rooms"
local arrRoom=( $(curl -sS --header "Authorization: Bearer $MATRIX_ACCESS" "$apiCall" | jq '.rooms[] | select(.joined_local_members == 0) | .room_id') ) local arrRoom=( $(curl -sS --header "Authorization: Bearer $MATRIX_ACCESS" "$apiCall" | jq '.rooms[] | select(.joined_local_members == 0) | .room_id') )
@@ -380,31 +373,27 @@ step_26() {
} }
step_28_info() { step_28_info() { echo "Delete room"; }
echoinfoArgs "<ROOM ID> [IP]:8008" step_28_options() { echo "<ROOM ID> [IP]:8008"; }
echo "Delete room" step_28_alias() { echo "deleteroom"; }
}
step_28_alias() { ALIAS="deleteroom"; }
step_28() { step_28() {
adminTokenCheck adminTokenCheck
endReturn -o $? "Admin token needed. Check $SEQ_CONFIG_FILE" endReturn "Admin token needed. Check $seq_configFile"
shift shift
local roomId="" local roomId=""
local synapseIP=localhost local synapseIP=localhost
if [ ! -z $1 ]; then if [ -n "${1:-}" ]; then
roomId="$1" roomId="$1"
shift shift
else else
endReturn -o 1 "No room ID specified" endReturn -o 1 "No room ID specified"
fi fi
if [ ! -z $1 ]; then [ -n "${1:-}" ] && synapseIP="$1"
synapseIP="$1"
fi
echo " [I] Deleting room with ID: $roomId" info "Deleting room with ID: $roomId"
local apiCall="http://${synapseIP}:8008/_synapse/admin/v2/rooms/$roomId" local apiCall="http://${synapseIP}:8008/_synapse/admin/v2/rooms/$roomId"
exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \ exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \
@@ -429,27 +418,28 @@ postDataDeleteRoom()
EOF EOF
} }
step_30_info() { echoinfoArgs "[DATABASE]"; echo "Debloat postgres"; echo; } step_30_info() { echo "Debloat postgres"; echo; }
step_30_alias() { ALIAS="debloat"; } step_30_options() { echo "[DATABASE]"; }
step_30_alias() { echo "debloat"; }
step_30() { step_30() {
shift shift
local pgVerboseReId=" (VERBOSE) " local pgVerboseReId=" (VERBOSE) "
local pgVerboseVac=" VERBOSE" local pgVerboseVac=" VERBOSE"
if [ $VERBOSE == 0 ]; then if ! verbose; then
pgVerboseReId=" " pgVerboseReId=" "
pgVerboseVac="" pgVerboseVac=""
fi fi
if [ -z $1 ]; then if [ -z "${1:-}" ]; then
readDatabaseInfos readDatabaseInfos
else else
postgresDb="$1" postgresDb="$1"
fi fi
echo " [I] Stopping ${toolServiceName}" info "Stopping ${toolServiceName}"
exe service ${toolServiceName} stop exe service ${toolServiceName} stop
endReturn -o $? "Couldn't stop ${toolServiceName}. Stopping debloat." endReturn "Couldn't stop ${toolServiceName}. Stopping debloat."
exe cd ~postgres exe cd ~postgres
exe su -c "psql -d ${postgresDb} -c \"REINDEX${pgVerboseReId}DATABASE ${postgresDb};\"" - postgres exe su -c "psql -d ${postgresDb} -c \"REINDEX${pgVerboseReId}DATABASE ${postgresDb};\"" - postgres
@@ -460,7 +450,7 @@ step_30() {
} }
step_50_info() { echo "Drop postgres database for $toolName"; } step_50_info() { echo "Drop postgres database for $toolName"; }
step_50_alias() { ALIAS="dropdb"; } step_50_alias() { echo "dropdb"; }
step_50() { step_50() {
readDatabaseInfos readDatabaseInfos
@@ -469,82 +459,88 @@ step_50() {
} }
step_52_info() { echo "Backup postgres database"; } step_52_info() { echo "Backup postgres database"; }
step_52_alias() { ALIAS="backupdb"; } step_52_alias() { echo "backupdb"; }
step_52() { step_52() {
local DELYEAR=$(($(date +%Y)-2)) local DELYEAR=$(($(date +%Y)-2))
if [ ! -s ~/.pgpass ] ; then if [ ! -s ~/.pgpass ] ; then
echo " [I] For unattended backup please define ~/.pgpass containing credentials" info "For unattended backup please define ~/.pgpass containing credentials"
echo " e.g. localhost:5432:database:user:pass" info -a " e.g. localhost:5432:database:user:pass"
echo "Backup custom pg format with standard user / database: synapse / synapse" info -a "Backup custom pg format with standard user / database: synapse / synapse"
fi fi
exep "pg_dump -h 127.0.0.1 -U synapse -Fc synapse | bzip2 -c > ${toolDbBackupFolder}/`date +%Y-%m-%d\"_\"%H-%M-%S`.backup.bz2" exep "pg_dump -h 127.0.0.1 -U synapse -Fc synapse | bzip2 -c > ${toolDbBackupFolder}/$(date +%Y-%m-%d\"_\"%H-%M-%S).backup.bz2"
exe rm -f ${toolDbBackupFolder}/${DELYEAR}* exe rm -f ${toolDbBackupFolder}/${DELYEAR}*
} }
toolDbBackupFolder=/root/backupdb toolDbBackupFolder=/root/backupdb
step_54_info() { echo "Postgres database restore"; } step_54_info() { echo "Postgres database restore"; }
step_54_alias() { ALIAS="restoredb"; } step_54_alias() { echo "restoredb"; }
step_54() { step_54() {
echo " [I] Postgres database restore procedure" info "Postgres database restore procedure"
echo "1. Create a empty postgres database first (step 4)" cat <<RESTORE_END
echo "2. psql -h <host> -U <database user> -d <database name> -W -f <sql dump file>" 1. Create a empty postgres database first (step 4)
echo " e.g. psql -h 127.0.0.1 -U synapse -d synapse -W -f 2018-06-07_18-10-56.sql" 2. psql -h <host> -U <database user> -d <database name> -W -f <sql dump file>
echo "or" e.g. psql -h 127.0.0.1 -U synapse -d synapse -W -f 2018-06-07_18-10-56.sql
echo "3. Custom postgres format dump restore:" or
echo " pg_restore -h localhost -p 5432 -U synapse -d new_db -v \"10.70.0.61.backup\"" 3. Custom postgres format dump restore:
echo pg_restore -h localhost -p 5432 -U synapse -d new_db -v "10.70.0.61.backup"
echo "Available postgresql databases:"
RESTORE_END
info "Available postgresql databases:"
exe cd ~postgres exe cd ~postgres
exe su postgres -c "psql -c '\l'" exe su postgres -c "psql -c '\l'"
echo "Available postgresql user:" info -a "Available postgresql user:"
exe su postgres -c "psql -c '\du'" exe su postgres -c "psql -c '\du'"
} }
step_56_info() { echo "$toolName migration notes"; } step_56_info() { echo "$toolName migration notes"; }
step_56_alias() { ALIAS="migrate"; } step_56_alias() { echo "migrate"; }
step_56() { step_56() {
echo " [I] Backup database" color green
echo " ./postgres.sh backupdb synapse" cat <<MIGRATE_END
echo
echo " [I] Backup virtual env folders except \"env\"" # Backup database
echo " cd ${MATRIX_HOME}" ./postgres.sh backupdb synapse
echo " tar czf ../\`date +%Y-%m-%d\"_\"%H-%M-%S\`.synapse_bu.tar.gz --exclude=\"./env\" ."
echo # Backup virtual venv folders except "venv"
echo " [I] Transfer both backup files to target server" cd ${MATRIX_HOME}
echo tar czf ../\$(date +%Y-%m-%d"_"%H-%M-%S).synapse_bu.tar.gz --exclude="./venv" .
echo " [I] Install $toolName on the target server up to step \"virtualenv\""
echo " (Stop after first run and edit $SEQ_CONFIG_FILE)" # Transfer both backup files to target server
echo " ./matrix.sh install"
echo " cd ${MATRIX_HOME}" # Install $toolName on the target server up to step "virtualenv"
echo " tar xf ...synapse_bu.tar.gz" (Stop after first run and edit $seq_configFile)
echo " Follow the instructions of:" ./matrix.sh install
echo " ./matrix.sh restoredb" cd ${MATRIX_HOME}
echo " ./matrix.sh systemd" tar xf ...synapse_bu.tar.gz
echo Follow the instructions of:
echo " [I] $toolName should be running. Now modify the reverse proxy configuration" ./matrix.sh restoredb
./matrix.sh systemd
# $toolName should be running. Now modify the reverse proxy configuration
MIGRATE_END
} }
# Read postgres database information dbname/user/pass if empty # Read postgres database information dbname/user/pass if empty
readDatabaseInfos() { readDatabaseInfos() {
if [ "$postgresDb" == "" ] ; then if [ "$postgresDb" == "" ] ; then
read -p "Enter postgres database name: " postgresDb read -p "Enter postgres database name: " postgresDb
endCheckEmpty postgresDb "database" endIfEmpty postgresDb "database"
fi fi
if [ "$postgresUser" == "" ] ; then if [ "$postgresUser" == "" ] ; then
read -p "Enter postgres user name: " postgresUser read -p "Enter postgres user name: " postgresUser
endCheckEmpty postgresUser "user name" endIfEmpty postgresUser "user name"
fi fi
if [ "$postgresPass" == "" ] ; then if [ "$postgresPass" == "" ] ; then
read -s -p "Enter postgres password: " postgresPass read -s -p "Enter postgres password: " postgresPass
endCheckEmpty postgresPass "password" endIfEmpty postgresPass "password"
fi fi
echo echo
} }
# Needs readDatabaseInfos() to execute some commands # Needs readDatabaseInfos() to execute some commands
toolScript() { toolScript() {
if [ ! -z "$1" ] ; then if [ -n "${1:-}" ] ; then
readDatabaseInfos readDatabaseInfos
fi fi
} }
@@ -552,12 +548,14 @@ toolScript() {
# End step if no admin access token is configured # End step if no admin access token is configured
adminTokenCheck() { adminTokenCheck() {
if [ -z "$MATRIX_ACCESS" ] ; then if [ -z "$MATRIX_ACCESS" ] ; then
[ $QUIET -eq 0 ] && read -s -p "Please enter admin access tocken: " MATRIX_ACCESS interactive && read -s -p "Please enter admin access tocken: " MATRIX_ACCESS
# return 1 if it is still empty # return 1 if it is still empty
[ -z "$MATRIX_ACCESS" ] && return 1 [ -z "$MATRIX_ACCESS" ] && return 1
fi fi
return 0 return 0
} }
VERSION_SEQREV=15 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -3,31 +3,28 @@
# #
## Installation of chat bridge matterbridge ## Installation of chat bridge matterbridge
toolName="matterbridge" readonly toolName="matterbridge"
repoName="42wim" readonly repoName="42wim"
toolLatestUrl="https://api.github.com/repos/${repoName}/${toolName}/releases/latest" readonly toolLatestUrl="https://api.github.com/repos/${repoName}/${toolName}/releases/latest"
toolVersion=$(curl --silent "$toolLatestUrl" | grep -Po '"tag_name": "v\K.*?(?=")') readonly toolVersion=$(curl --silent "$toolLatestUrl" | grep -Po '"tag_name": "v\K.*?(?=")')
toolDownload="https://github.com/${repoName}/${toolName}/releases/download/v${toolVersion}/${toolName}-${toolVersion}-linux-armv6" readonly toolDownload="https://github.com/${repoName}/${toolName}/releases/download/v${toolVersion}/${toolName}-${toolVersion}-linux-armv6"
toolDir="/usr/local/bin" readonly toolDir="/usr/local/bin"
toolLoc="${toolDir}/${toolName}" readonly toolLoc="${toolDir}/${toolName}"
toolWdir="/opt/${toolName}" readonly toolWdir="/etc/${toolName}"
toolConfig="${toolName}.toml" readonly toolConfig="${toolName}.toml"
toolConfigLoc="${toolWdir}/${toolConfig}" readonly toolConfigLoc="${toolWdir}/${toolConfig}"
toolService="[Unit] readonly toolUser='matterbridge'
readonly toolService="[Unit]
Description=${toolName} Description=${toolName}
After=network.target matrix-synapse.service After=network-online.target matrix-synapse.service
[Service] [Service]
Type=simple Type=simple
ExecStart=${toolLoc} -conf ${toolWdir}/matterbridge.toml ExecStart=${toolLoc} -conf ${toolWdir}/matterbridge.toml
Restart=always Restart=always
RestartSec=30 RestartSec=5s
WorkingDirectory=${toolWdir} WorkingDirectory=${toolWdir}
User=root User=${toolUser}
Group=root
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=${toolName}
[Install] [Install]
WantedBy=multi-user.target" WantedBy=multi-user.target"
@@ -36,9 +33,9 @@ toolServiceLoc="/etc/systemd/system/${toolName}.service"
readonly goDir="/usr/local/go" readonly goDir="/usr/local/go"
readonly goDownLoc="/tmp/go.tar.gz" readonly goDownLoc="/tmp/go.tar.gz"
step_config() { seq_config() {
if [ -z $toolVersion ] ; then if [ -z "${toolVersion}" ] ; then
echoerr " [E] Couldn't determine latest version of $toolName" error -e "Couldn't determine latest version of $toolName"
fi fi
} }
@@ -46,10 +43,10 @@ step_1_info() {
echo "Downloading $toolName version ${toolVersion} to ${toolLoc} from:" echo "Downloading $toolName version ${toolVersion} to ${toolLoc} from:"
echoinfo "$toolDownload" echoinfo "$toolDownload"
} }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
step upgrade step upgrade
endReturn -o $? "Download failed" endReturn "Download failed"
} }
step_2_info() { echo "Create required directory structure"; } step_2_info() { echo "Create required directory structure"; }
@@ -60,23 +57,28 @@ step_2() {
exe chmod +x ${toolLoc} exe chmod +x ${toolLoc}
} }
step_3_info() { echo "Creating systemd service"; } step_3_info() { echo "Creating system user ${toolUser}"; }
step_3() { step_3() {
addConf -s "$toolService" "$toolServiceLoc" exe adduser --system --group --home "${toolWdir}" "${toolUser}"
endReturn -o $? "Creating service failed"
} }
step_4_info() { echo "Enable $toolName service"; } step_4_info() { echo "Creating systemd service"; }
step_4() { step_4() {
addConf -s "$toolService" "$toolServiceLoc"
endReturn "Creating service failed"
}
step_5_info() { echo "Enable $toolName service"; }
step_5() {
exe systemctl enable ${toolName} exe systemctl enable ${toolName}
echo " [I] Before proceeding to run ${toolName} you need to modify ${toolConfigLoc} first" info "Before proceeding to run ${toolName} you need to modify ${toolConfigLoc} first"
echo echo
} }
step_5_info() { echo "Show configuration notes"; } step_6_info() { echo "Show configuration notes"; }
step_5_alias() { ALIAS="notes"; } step_6_alias() { echo "notes"; }
step_5() { step_6() {
outColor green color green
cat <<NOTES_END cat <<NOTES_END
# Sample configuration # Sample configuration
@@ -87,24 +89,24 @@ NOTES_END
} }
step_10_info() { echo "Backup existing executable"; } step_10_info() { echo "Backup existing executable"; }
step_10_alias() { ALIAS="backup"; } step_10_alias() { echo "backup"; }
step_10() { step_10() {
if [ -f "$toolLoc" ] ; then if [ -f "$toolLoc" ] ; then
local toolBackup= local toolBackup=
if [ ! -z ${versionNow} ] ; then if [ -n "${versionNow}" ] ; then
toolBackup="${toolDir}/${toolName}_${versionNow}" toolBackup="${toolDir}/${toolName}_${versionNow}"
else else
toolBackup="${toolDir}/${toolName}_bu" toolBackup="${toolDir}/${toolName}_bu"
fi fi
exe service ${toolName} stop >>/dev/null 2>&1 exep service ${toolName} stop '>>/dev/null 2>&1'
echoseq -n " [I] Backing up existing executable to ${toolBackup}..." info -n "Backing up existing executable to ${toolBackup}..."
exe cp -ar "$toolLoc" "$toolBackup" && echoseq "ok" exe cp -ar "$toolLoc" "$toolBackup" && info -d "ok"
fi fi
} }
versionNow=$([ ! -z $(which ${toolName}) ] && ${toolName} --version | sed 's/.*version: \([0-9.]\+\).*/\1/') versionNow=$([ -n "$(command -v ${toolName})" ] && ${toolName} --version | sed 's/.*version: \([0-9.]\+\).*/\1/')
step_12_info() { step_12_info() {
if [ ! -z $versionNow ] ; then if [ -n "${versionNow}" ] ; then
if [ "$toolVersion" == "$versionNow" ] ; then if [ "$toolVersion" == "$versionNow" ] ; then
echo "No upgrade available. Already on latest: $versionNow" echo "No upgrade available. Already on latest: $versionNow"
else else
@@ -116,11 +118,11 @@ step_12_info() {
fi fi
echo echo
} }
step_12_alias() { ALIAS="upgrade"; } step_12_alias() { echo "upgrade"; }
step_12() { step_12() {
step backup step backup
exe wget -O "$toolLoc" $toolDownload exe wget -O "$toolLoc" "${toolDownload}"
endReturn -o $? "Download failed" endReturn "Download failed"
exe chmod +x "$toolLoc" exe chmod +x "$toolLoc"
exe service ${toolName} restart >>/dev/null 2>&1 exe service ${toolName} restart >>/dev/null 2>&1
return 0 return 0
@@ -128,22 +130,23 @@ step_12() {
step_30_info() { step_30_info() {
echoinfoArgs "[OPTIONS]"
echo "Download go" echo "Download go"
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " --arch, -a : armhf(default), arm64" echoinfo " --arch, -a : armhf(default), arm64"
echoinfo " CPU architecture for downloading go sources" echoinfo " CPU architecture for downloading go sources"
} }
step_30_alias() { ALIAS="build"; } step_30_options() { echo "[OPTIONS]"; }
step_30_alias() { echo "build"; }
step_30() { step_30() {
shift shift
local goVer="$(curl --silent -L https://go.dev/dl | \ local goVer
goVer="$(curl --silent -L https://go.dev/dl | \
grep --max-count 1 -E "go[[:digit:]\.]{3,}.*\.tar\.gz" |\ grep --max-count 1 -E "go[[:digit:]\.]{3,}.*\.tar\.gz" |\
sed 's/.*\/\(go.*\)\.linux.*/\1/g')" sed 's/.*\/\(go.*\)\.linux.*/\1/g')"
local goArch="armhf" #arm64" local goArch="armhf" #arm64"
case "${1}" in case "${1:-}" in
--arch|-a) --arch|-a)
goArch="${2}" goArch="${2:-"armhf"}"
shift 2 ;; shift 2 ;;
esac esac
[[ "${goArch}" == "armhf" ]] && goArch="armv6l" [[ "${goArch}" == "armhf" ]] && goArch="armv6l"
@@ -151,15 +154,16 @@ step_30() {
# Download latest go # Download latest go
if [ ! -e "${goDir}" ] ; then if [ ! -e "${goDir}" ] ; then
echoseq "Download go${goVer}: ${goDownUrl}" info "Download go${goVer}: ${goDownUrl}"
exe wget -O "${goDownLoc}" ${goDownUrl} exe wget -O "${goDownLoc}" "${goDownUrl}"
endReturn -o $? "Download ${goVer} failed" endReturn "Download ${goVer} failed"
exe tar -C "$(dirname -- "${goDir}")" -xzf "${goDownLoc}" exe tar -C "$(dirname -- "${goDir}")" -xzf "${goDownLoc}"
endReturn -o $? "Extraction ${goVer} failed" endReturn "Extraction ${goVer} failed"
fi fi
} }
step_31_info() { echo "Compile matterbridge"; } step_31_info() { echo "Compile matterbridge"; }
step_31_alias() { echo 'compile'; }
step_31() { step_31() {
local mabrTags="\ local mabrTags="\
noapi,\ noapi,\
@@ -185,15 +189,16 @@ whatsappmulti"
exe "${goDir}/bin/go" install -tags ${mabrTags} github.com/42wim/matterbridge@master exe "${goDir}/bin/go" install -tags ${mabrTags} github.com/42wim/matterbridge@master
step backup step backup
exe cp -ar "${HOME}/go/bin/matterbridge" "${toolDir}" exe cp -ar "${HOME}/go/bin/matterbridge" "${toolDir}"
exep service ${toolName} restart '>>/dev/null 2>&1'
} }
step_32_info() { echo "Clean temporary files"; } step_32_info() { echo "Clean temporary files"; }
step_32_alias() { echo "clean"; }
step_32() { step_32() {
exe rm -f "${goDownLoc}" exe rm -f "${goDownLoc}"
} }
# Sequence Revision # shellcheck disable=SC2034 # Appears unused
VERSION_SEQREV=15 readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
# Path to sequencer
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
toolName="Mayan EDMS" toolName="Mayan EDMS"
toolVersion="4.2.1"
toolRoot="/opt/mayan-edms" toolRoot="/opt/mayan-edms"
toolMediaFolder="/opt/mayan-edms/media" toolMediaFolder="/opt/mayan-edms/media"
@@ -20,28 +19,30 @@ SCRIPT_NAME=${SCRIPT_FILE%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg" CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
## or to use sequencer api with global config file: ## or to use sequencer api with global config file:
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
CONFIG=1 CONFIG=1
postgresDb="$MAYAN_DB" postgresDb="${MAYAN_DB:-}"
postgresUser="$MAYAN_DBUSER" postgresUser="${MAYAN_DBUSER:-}"
postgresPass="$MAYAN_DBPASS" postgresPass="${MAYAN_DBPASS:-}"
else else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return -1 dry || return -1
fi fi
## Apt cmdline option to suppress user interaction ## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y" quiet && APTOPT="-y"
toolVersion="$(getLatestVersion)"
## Return of non zero value will abort the sequence ## Return of non zero value will abort the sequence
return 0 return 0
} }
step_1_info() { echo "Install libreoffice without gui"; } step_1_info() { echo "Install libreoffice without gui"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt --no-install-recommends install libreoffice -y exe apt --no-install-recommends install libreoffice -y
@@ -53,7 +54,7 @@ step_2() {
graphviz libfuse2 libjpeg-dev libmagic1 libpq-dev libpng-dev libtiff-dev libldap2-dev libsasl2-dev \ graphviz libfuse2 libjpeg-dev libmagic1 libpq-dev libpng-dev libtiff-dev libldap2-dev libsasl2-dev \
poppler-utils postgresql python3-dev python3-pip python3-venv python3-virtualenv \ poppler-utils postgresql python3-dev python3-pip python3-venv python3-virtualenv \
redis-server sane-utils supervisor tesseract-ocr tesseract-ocr-deu zlib1g-dev -y redis-server sane-utils supervisor tesseract-ocr tesseract-ocr-deu zlib1g-dev -y
endReturn -o $? "Binary dependencies installation failed" endReturn "Binary dependencies installation failed"
exe systemctl enable supervisor exe systemctl enable supervisor
exe systemctl stop supervisor exe systemctl stop supervisor
@@ -64,12 +65,12 @@ step_3() {
exe adduser --disabled-password --disabled-login --no-create-home --gecos "" mayan exe adduser --disabled-password --disabled-login --no-create-home --gecos "" mayan
exe usermod -a -G users mayan exe usermod -a -G users mayan
exe python3 -m venv ${toolRoot} exe python3 -m venv ${toolRoot}
endReturn -o $? "Creating virtual environment failed" endReturn "Creating virtual environment failed"
exe chown -R mayan:mayan ${toolRoot} exe chown -R mayan:mayan ${toolRoot}
} }
step_4_info() { echo "Create postgres database for $toolName"; } step_4_info() { echo "Create postgres database for $toolName"; }
step_4_alias() { ALIAS="createdb"; } step_4_alias() { echo "createdb"; }
step_4() { step_4() {
readDatabaseInfos readDatabaseInfos
@@ -84,14 +85,14 @@ step_5() {
# upgrade pip first # upgrade pip first
step upgradepip step upgradepip
exe sudo -u mayan ${toolRoot}/bin/pip install --no-cache-dir mayan-edms==$toolVersion exe sudo -u mayan ${toolRoot}/bin/pip install --no-cache-dir mayan-edms=="${toolVersion}"
endReturn -o $? "pip install for $toolName failed" endReturn "pip install for $toolName failed"
exe sudo -u mayan ${toolRoot}/bin/pip install --no-cache-dir psycopg2==2.8.4 redis==3.4.1 exe sudo -u mayan ${toolRoot}/bin/pip install --no-cache-dir psycopg2==2.8.4 redis==3.4.1
endReturn -o $? endReturn
} }
step_6_info() { echo "Supervisord configuration for $toolName"; } step_6_info() { echo "Supervisord configuration for $toolName"; }
step_6_alias() { ALIAS="supervisorconf"; } step_6_alias() { echo "supervisorconf"; }
step_6() { step_6() {
addConf -c "" "$supervisordConfLoc" addConf -c "" "$supervisordConfLoc"
toolScript "platformtemplate supervisord > ${supervisordConfLoc}" toolScript "platformtemplate supervisord > ${supervisordConfLoc}"
@@ -120,25 +121,25 @@ save \"\"
databases 2" databases 2"
step_10_info() { step_10_info() {
echoinfoArgs "[OPTIONS]" echo "Upgrade $toolName to ${toolVersion:-"latest Version"}"
echo "Upgrade $toolName to $toolVersion"
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " super : update also supervisor configuration" echoinfo " super : update also supervisor configuration"
echoinfo " (manual redis password update may be needed)" echoinfo " (manual redis password update may be needed)"
} }
step_10_alias() { ALIAS="upgrade"; } step_10_options() { echo "[OPTIONS]"; }
step_10_alias() { echo "upgrade"; }
step_10() { step_10() {
shift # don't need the step number shift # don't need the step number
step upgradepip step upgradepip
exe curl -o "$uninstallRemovalsLoc" https://gitlab.com/mayan-edms/mayan-edms/raw/master/removals.txt exe curl -o "$uninstallRemovalsLoc" https://gitlab.com/mayan-edms/mayan-edms/raw/master/removals.txt
exe sudo -u mayan ${toolRoot}/bin/pip uninstall -r "$uninstallRemovalsLoc" exe sudo -u mayan ${toolRoot}/bin/pip uninstall -r "$uninstallRemovalsLoc"
endReturn -o $? endReturn
exe systemctl stop supervisor exe systemctl stop supervisor
exe sudo -u mayan ${toolRoot}/bin/pip install --no-cache-dir mayan-edms==$toolVersion exe sudo -u mayan ${toolRoot}/bin/pip install --no-cache-dir mayan-edms=="${toolVersion}"
endReturn -o $? endReturn
toolScript performupgrade toolScript performupgrade
#toolScript preparestatic --noinput # only < 3.4 #toolScript preparestatic --noinput # only < 3.4
case $1 in case "${1:-}" in
"super") "super")
# Generating new supervisor file # Generating new supervisor file
step supervisorconf ;; step supervisorconf ;;
@@ -149,12 +150,12 @@ uninstallRemovalsLoc="/tmp/removals.txt"
step_13_info() { echo "$toolName management script"; } step_13_info() { echo "$toolName management script"; }
step_13_alias() { ALIAS="manage"; } step_13_alias() { echo "manage"; }
step_13() { step_13() {
shift shift
if [ -z "$1" ] || [ "$1" == "" ] ; then if [ -z "${1:-}" ] || [ "${1:-}" == "" ] ; then
echo -n "Command (empty for help): " echo -n "Command (empty for help): "
if [ $DRY != 0 ]; then if dry; then
echo " dryrun" echo " dryrun"
else else
read command read command
@@ -166,18 +167,18 @@ step_13() {
} }
step_15_info() { echo "Upgrade python pip"; } step_15_info() { echo "Upgrade python pip"; }
step_15_alias() { ALIAS="upgradepip"; } step_15_alias() { echo "upgradepip"; }
step_15() step_15()
{ {
exe ${toolRoot}/bin/pip install --upgrade pip exe ${toolRoot}/bin/pip install --upgrade pip
} }
step_20_info() { echo "Backup postgres database to media folder"; } step_20_info() { echo "Backup postgres database to media folder"; }
step_20_alias() { ALIAS="backupdb"; } step_20_alias() { echo "backupdb"; }
step_20() { step_20() {
local DELYEAR=$(($(date +%Y)-2)) local DELYEAR=$(($(date +%Y)-2))
if [ ! -s ~/.pgpass ] ; then if [ ! -s ~/.pgpass ] ; then
echo " [I] For unattended backup please define ~/.pgpass containing credentials for user mayan" info "For unattended backup please define ~/.pgpass containing credentials for user mayan"
echo " e.g. localhost:5432:mayan:mayan:pass4mayan" echo " e.g. localhost:5432:mayan:mayan:pass4mayan"
echo "Backup custom pg format with standard user / database: mayan / mayan" echo "Backup custom pg format with standard user / database: mayan / mayan"
fi fi
@@ -188,9 +189,9 @@ toolDbBackupFolder=${toolMediaFolder}/backupdb
step_22_info() { echo "Postgres database restore"; } step_22_info() { echo "Postgres database restore"; }
step_22_alias() { ALIAS="restoredb"; } step_22_alias() { echo "restoredb"; }
step_22() { step_22() {
echo " [I] Postgres database restore procedure" info "Postgres database restore procedure"
echo "1. Create a empty postgres database first (step 4)" echo "1. Create a empty postgres database first (step 4)"
echo "2. psql -h <host> -U <database user> -d <database name> -W -f <sql dump file>" echo "2. psql -h <host> -U <database user> -d <database name> -W -f <sql dump file>"
echo " e.g. psql -h 127.0.0.1 -U mayan -d mayan -W -f 2018-06-07_18-10-56.sql" echo " e.g. psql -h 127.0.0.1 -U mayan -d mayan -W -f 2018-06-07_18-10-56.sql"
@@ -208,22 +209,26 @@ step_22() {
readDatabaseInfos() { readDatabaseInfos() {
if [ -z "$postgresDb" ] ; then if [ -z "$postgresDb" ] ; then
read -p "Enter postgres database name: " postgresDb read -p "Enter postgres database name: " postgresDb
endCheckEmpty postgresDb "database" endIfEmpty postgresDb "database"
fi fi
if [ -z "$postgresUser" ] ; then if [ -z "$postgresUser" ] ; then
read -p "Enter postgres user name: " postgresUser read -p "Enter postgres user name: " postgresUser
endCheckEmpty postgresUser "user name" endIfEmpty postgresUser "user name"
fi fi
if [ -z "$postgresPass" ] ; then if [ -z "$postgresPass" ] ; then
read -s -p "Enter postgres password: " postgresPass read -s -p "Enter postgres password: " postgresPass
endCheckEmpty postgresPass "password" endIfEmpty postgresPass "password"
fi fi
echoseq info
}
getLatestVersion() {
curl --silent -L https://docs.mayan-edms.com/releases/index.html | sed -n 's/.*Version \([0-9.]\+\).*/\1/p' | head -1
} }
# Needs readDatabaseInfos() to execute some commands # Needs readDatabaseInfos() to execute some commands
toolScript() { toolScript() {
if [ ! -z "$1" ] ; then if [ -n "${1:-}" ] ; then
readDatabaseInfos readDatabaseInfos
fi fi
@@ -233,5 +238,5 @@ toolScript() {
${toolRoot}/bin/mayan-edms.py $*" ${toolRoot}/bin/mayan-edms.py $*"
} }
VERSION_SEQREV=15 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

116
seqs/motioneye-dev.sh Executable file
View File

@@ -0,0 +1,116 @@
#!/usr/bin/env bash
readonly toolName=motioneye
readonly sq_meUrl='https://github.com/motioneye-project/motioneye/archive/dev.tar.gz'
# Already defined by sequencer.sh, but may be overwritten
#readonly seq_configName="${sq_scriptName}.cfg"
#readonly seq_configTemplate="${seq_origin}/${sq_configName}.example"
sq_aptOpt=
sq_config=0
seq_config() {
## Called once before executing steps.
## e.g. to source a config file manually:
#. "${seq_origin}/${seq_configName}"
## or to use sequencer api with profile config file support:
#if initSeqConfig -p "${seq_fileName}" "${seq_configTemplate}" ; then
## or to use sequencer api with global config file:
#if initSeqConfig "${seq_configName}" "${seq_configTemplate}" ; then
# sq_config=1
#else
# # End if no configuration file exists
# dry || return -1
#fi
dry || root || fatal "Needs to be root"
# Since RasperryPi OS bullseye motion is provided with expected version 4.3.2-1
lsb_release -c | grep bullseye >/dev/null 2>&1 || fatal "Only debian bullseye supported to install motion directly"
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Show status"; }
step_1_alias() { echo "status"; }
step_1() {
info "Status of $toolName .."
exe service motioneye status
}
step_20_info() { echo "Install motioneye dependencies"; }
step_20_alias() { echo "install"; }
step_20() {
exe apt update
exe apt --no-install-recommends install ca-certificates curl python3 python3-dev python3-pip python3-venv libcurl4-openssl-dev gcc libssl-dev ${sq_aptOpt}
exep DEBIAN_FRONTEND="noninteractive" apt-get -y --no-install-recommends install motion v4l-utils ffmpeg curl
info "Disable motion service"
info -a "(Will be started by motioneye)"
exe systemctl disable --now motion
}
step_21_info() { echo "Create virtual environment"; }
step_21() {
[[ -d "${sc_meVenvHome}" ]] && fatal "$tooName already installed"
exe python3 -m venv "${sc_meVenvHome}"
}
sc_meVenvHome="/opt/motioneye"
sc_mePip="${sc_meVenvHome}/bin/pip"
step_22_info() { echo "Install $toolName in venv"; }
step_22() {
exe "${sc_mePip}" install "${sq_meUrl}"
}
step_23_info() { echo "Setup $toolName service and config"; }
step_23() {
local lMeConfDir="$(dirname -- "${sc_meConfigFile}")"
if [[ ! -d "${lMeConfDir}" ]] ; then
exe mkdir -p "${lMeConfDir}"
addConf -s -f "${sc_meConfigExample}" "${sc_meConfigFile}"
exe chown -R motion: "${lMeConfDir}"
fi
addConf -s "${sc_meSystemd}" "${sc_meServiceFile}"
exe systemctl daemon-reload
exe systemctl enable --now motioneye
}
sc_meConfigFile="/etc/motioneye/motioneye.conf"
sc_meConfigExample="${sc_meVenvHome}/lib/python3.9/site-packages/motioneye/extra/motioneye.conf.sample"
sc_meServiceFile="/etc/systemd/system/motioneye.service"
sc_meSystemd="[Unit]
Description=motionEye Server
After=network.target local-fs.target remote-fs.target
[Service]
User=motion
RuntimeDirectory=motioneye
LogsDirectory=motioneye
StateDirectory=motioneye
ExecStart=${sc_meVenvHome}/bin/meyectl startserver -c /etc/motioneye/motioneye.conf
Restart=on-abort
[Install]
WantedBy=multi-user.target"
step_25_info() { echo "Upgrade $toolName"; }
step_25_alias() { echo "upgrade"; }
step_25() {
exe service motioneye stop
exe "${sc_mePip}" install --upgrade --force-reinstall --no-deps "${sq_meUrl}"
exe service motioneye start
}
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -18,7 +18,7 @@ CONFIG=0
#CONFIG_FILE_NAME="${toolName}.cfg" #CONFIG_FILE_NAME="${toolName}.cfg"
#CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" #CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
## e.g. to source a config file manually: ## e.g. to source a config file manually:
#. "$CONFIG_FILE" #. "$CONFIG_FILE"
## or to use sequencer api: ## or to use sequencer api:
@@ -27,7 +27,7 @@ step_config() {
# CONFIG=1 # CONFIG=1
#fi #fi
if [ "$(which lsb_release)" == "" ] ; then if [ "$(which lsb_release)" == "" ] ; then
echoerr " [W] Cannot detect OS. Assuming Ubuntu" warning -e "Cannot detect OS. Assuming Ubuntu"
SEQ_OSNAME="Ubuntu" SEQ_OSNAME="Ubuntu"
else else
SEQ_OSNAME=$(lsb_release -is) SEQ_OSNAME=$(lsb_release -is)
@@ -35,28 +35,28 @@ step_config() {
fi fi
if [ "$SEQ_OSNAME" == "" ] ; then if [ "$SEQ_OSNAME" == "" ] ; then
echoerr " [W] Error dedecting OS. Assuming Ubuntu" warning -e "Error dedecting OS. Assuming Ubuntu"
SEQ_OSNAME="Ubuntu" SEQ_OSNAME="Ubuntu"
fi fi
echo " [I] Detected OS: $SEQ_OSNAME $SEQ_DISTNAME" info "Detected OS: $SEQ_OSNAME $SEQ_DISTNAME"
} }
step_1_info() { echo "Install $toolName dependencies"; } step_1_info() { echo "Install $toolName dependencies"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local aptOption= local aptOption=
local pyVersion=$(python -V 2>&1) local pyVersion=$(python -V 2>&1)
if [[ ! "$pyVersion" =~ \ 2\.[7-9]+ ]] ; then if [[ ! "$pyVersion" =~ \ 2\.[7-9]+ ]] ; then
echoerr " [E] Motioneye requires python version 2.7 but $pyVersion was found." error -e "Motioneye requires python version 2.7 but $pyVersion was found."
return 1 return 1
fi fi
exe apt update exe apt update
endReturn -o $? "Updating apt repositories failed" endReturn "Updating apt repositories failed"
if [ $QUIET -ne 0 ] ; then if quiet ; then
aptOption="-y" aptOption="-y"
else else
aptOption="" aptOption=""
@@ -75,38 +75,38 @@ step_2() {
fi fi
if [ "$motionUrl" == "" ]; then if [ "$motionUrl" == "" ]; then
echo " [W] Unsupported OS" warning "Unsupported OS"
return 1 return 1
fi fi
exe wget -O "$motionDownload" $motionUrl exe wget -O "$motionDownload" $motionUrl
endReturn -o $? "Download motion failed" endReturn "Download motion failed"
} }
motionDownload="/tmp/motion.deb" motionDownload="/tmp/motion.deb"
step_3_info() { echo "Install downloaded motion version"; } step_3_info() { echo "Install downloaded motion version"; }
step_3() { step_3() {
if [ ! -f "$motionDownload" ]; then if [ ! -f "$motionDownload" ]; then
echo " [I] No downloaded motion found attempting download" info "No downloaded motion found attempting download"
step 2 step 2
fi fi
exe dpkg -i "$motionDownload" exe dpkg -i "$motionDownload"
endReturn -o $? "Installing motion failed" endReturn "Installing motion failed"
} }
step_4_info() { echo "Upgrade python pip"; } step_4_info() { echo "Upgrade python pip"; }
step_4_alias() { ALIAS="upgradepip"; } step_4_alias() { echo "upgradepip"; }
step_4() step_4()
{ {
exe pip install --upgrade pip exe pip install --upgrade pip
endReturn -o $? "Upgrading pip failed" endReturn "Upgrading pip failed"
} }
step_5_info() { echo "Install $toolName"; } step_5_info() { echo "Install $toolName"; }
step_5() { step_5() {
exe pip install motioneye exe pip install motioneye
endReturn -o $? "Installing $toolName failed" endReturn "Installing $toolName failed"
} }
step_6_info() { echo "Prepare configuration directory $toolCfgDir"; } step_6_info() { echo "Prepare configuration directory $toolCfgDir"; }
@@ -129,7 +129,7 @@ motioneyeMediaDir="/var/lib/motioneye"
step_8_info() { echo "Create $toolName service"; } step_8_info() { echo "Create $toolName service"; }
step_8() { step_8() {
exe cp "$motioneyeServiceSource" "$motioneyeServiceTarget" exe cp "$motioneyeServiceSource" "$motioneyeServiceTarget"
endReturn -o $? "Creating service failed" endReturn "Creating service failed"
exe systemctl daemon-reload exe systemctl daemon-reload
exe systemctl enable motioneye exe systemctl enable motioneye
exe systemctl start motioneye exe systemctl start motioneye
@@ -138,13 +138,13 @@ motioneyeServiceSource="/usr/local/share/motioneye/extra/motioneye.systemd-unit-
motioneyeServiceTarget="/etc/systemd/system/motioneye.service" motioneyeServiceTarget="/etc/systemd/system/motioneye.service"
step_20_info() { echo "Upgrade $toolName"; } step_20_info() { echo "Upgrade $toolName"; }
step_20_alias() { ALIAS="upgrade"; } step_20_alias() { echo "upgrade"; }
step_20() { step_20() {
step "upgradepip" step "upgradepip"
exe pip install motioneye --upgrade exe pip install motioneye --upgrade
endReturn -o $? "Upgrading $toolName failed" endReturn "Upgrading $toolName failed"
exe systemctl restart motioneye exe systemctl restart motioneye
} }
VERSION_SEQREV=11 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -9,25 +9,38 @@ dbUser=
dbRemote=localhost dbRemote=localhost
dbPass= dbPass=
step_1_info() { step_1_info() { echo "Status"; }
echo "Installation of ${databaseName} packages:" step_1_alias() { echo "status"; }
echoinfo "$databasePackages"
echoinfo "(Consider step \"latest\" first to setup official repository with the latest version)"
}
step_1_alias() { ALIAS=install; }
step_1() { step_1() {
exe apt update exe apt policy mariadb-server
exe apt install $databasePackages
endReturn -o $? "Error instaling $databaseName"
} }
step_2_info() { echo "Secure ${databaseName} installation"; } step_5_info() { echo "Setup ubuntu $databaseName repository"; }
step_2() { step_5_alias() { echo "setup"; }
step_5() {
exe apt install curl
exep "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --skip-maxscale --skip-tools"
}
step_6_info() {
echo "Installation of ${databaseName} packages:"
echoinfo "$databasePackages"
echoinfo "(Consider step \"setup\" first)"
}
step_6_alias() { echo install; }
step_6() {
exe apt update
exe apt install $databasePackages
endReturn "Error instaling $databaseName"
}
step_7_info() { echo "Secure ${databaseName} installation"; }
step_7() {
exe mysql_secure_installation exe mysql_secure_installation
} }
step_3_info() { echo "${databaseName} configuration"; } step_8_info() { echo "${databaseName} configuration"; }
step_3() { step_8() {
addConf -c "$mariadbConfig" "$mariadbConfigLoc" addConf -c "$mariadbConfig" "$mariadbConfigLoc"
echo -n "Restarting mysql ... " echo -n "Restarting mysql ... "
@@ -46,15 +59,7 @@ table_definition_cache=1400
#innodb_force_recovery=6" #innodb_force_recovery=6"
step_8_info() { echo "Setup ubuntu $databaseName repository"; }
step_8_alias() { ALIAS="latest"; }
step_8() {
exe apt install curl
exep "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --skip-maxscale --skip-tools"
}
step_10_info() { step_10_info() {
echoinfoArgs "[OPTIONS]"
echo "Create mysql database without specific characterset" echo "Create mysql database without specific characterset"
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " --charset,-c <utf8|utf8mb4> : character set and collate" echoinfo " --charset,-c <utf8|utf8mb4> : character set and collate"
@@ -64,25 +69,26 @@ step_10_info() {
echoinfo " Manual password entry for non existing user" echoinfo " Manual password entry for non existing user"
echoinfo " --remote, -r : ip of allowed remote host" echoinfo " --remote, -r : ip of allowed remote host"
} }
step_10_alias() { ALIAS="createdb"; } step_10_options() { echo "[OPTIONS]"; }
step_10_alias() { echo "createdb"; }
step_10() { step_10() {
local arg local arg
local dbOption= local dbOption=
shift shift
for arg in "$@" ; do for arg in "$@" ; do
case "$1" in case "${1:-}" in
--charset|-c) --charset|-c)
dbOption="$2" dbOption="${2:-}"
shift 2;; shift 2;;
--database|-d) --database|-d)
dbName="$2" dbName="${2:-}"
shift 2 ;; shift 2 ;;
--user|-u) --user|-u)
dbUser="$2" dbUser="${2:-}"
shift 2 ;; shift 2 ;;
--remote|-r) --remote|-r)
dbRemote="$2" dbRemote="${2:-}"
shift 2 ;; shift 2 ;;
*) *)
break ;; break ;;
@@ -99,42 +105,42 @@ step_10() {
esac esac
if [ -z "$dbName" ] ; then if [ -z "$dbName" ] ; then
echo " [I] Existing mysql databases:" info "Existing mysql databases:"
exe mysql -u root -e 'SHOW DATABASES;' exe mysql -u root -e 'SHOW DATABASES;'
read -p "Enter database name: " dbName read -p "Enter database name: " dbName
fi fi
endCheckEmpty dbName "database name" endIfEmpty dbName "database name"
exe mysql -u root -e 'CREATE DATABASE '$dbName' '"$dbOption"';' exe mysql -u root -e 'CREATE DATABASE '$dbName' '"$dbOption"';'
endReturn -o $? "Cannot create database $dbName" endReturn "Cannot create database $dbName"
} }
step_11_info() { step_11_info() {
echoinfoArgs "[OPTIONS]"
echo "Create mysql user" echo "Create mysql user"
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " --user, -u : user name" echoinfo " --user, -u : user name"
echoinfo " with manual password entry for non existing user" echoinfo " with manual password entry for non existing user"
echoinfo " --remote, -r : ip of allowed remote host" echoinfo " --remote, -r : ip of allowed remote host"
} }
step_11_alias() { ALIAS="createuser"; } step_11_options() { echo "[OPTIONS]"; }
step_11_alias() { echo "createuser"; }
step_11() { step_11() {
local arg local arg
shift shift
for arg in "$@" ; do for arg in "$@" ; do
case "$1" in case "${1:-}" in
--charset|-c) --charset|-c)
dbOption="$2" dbOption="${2:-}"
shift 2;; shift 2;;
--database|-d) --database|-d)
dbName="$2" dbName="${2:-}"
shift 2 ;; shift 2 ;;
--user|-u) --user|-u)
dbUser="$2" dbUser="${2:-}"
shift 2 ;; shift 2 ;;
--remote|-r) --remote|-r)
dbRemote="$2" dbRemote="${2:-}"
shift 2 ;; shift 2 ;;
*) *)
break ;; break ;;
@@ -142,51 +148,51 @@ step_11() {
done done
if [ -z "$dbUser" ] ; then if [ -z "$dbUser" ] ; then
echo " [I] Existing mysql user:" info "Existing mysql user:"
exe mysql -u root -e 'SELECT User, Host FROM mysql.user;' exe mysql -u root -e 'SELECT User, Host FROM mysql.user;'
read -p "Enter mysql user name: " dbUser read -p "Enter mysql user name: " dbUser
fi fi
endCheckEmpty dbUser "user name" endIfEmpty dbUser "user name"
if ! echo "SELECT COUNT(*) FROM mysql.user WHERE user = '$dbUser' AND host = '$dbRemote';" | mysql | grep 1 &>/dev/null; then if ! echo "SELECT COUNT(*) FROM mysql.user WHERE user = '$dbUser' AND host = '$dbRemote';" | mysql | grep 1 &>/dev/null; then
# User does not exist # User does not exist
if [ $DRY -eq 0 ]; then if ! dry; then
read -s -p "Enter mysql user password: " dbPass read -s -p "Enter mysql user password: " dbPass
endCheckEmpty dbPass "password" endIfEmpty dbPass "password"
else else
echoseq "Enter mysql password: ...skipped..." info "Enter mysql password: ...skipped..."
fi fi
exe mysql -u root -e 'CREATE USER '"'"$dbUser"'"'@'"'"$dbRemote"'"' IDENTIFIED BY '"'"$dbPass"'"';' exe mysql -u root -e 'CREATE USER '"'"$dbUser"'"'@'"'"$dbRemote"'"' IDENTIFIED BY '"'"$dbPass"'"';'
endReturn -o $? "Error creating mysql user" endReturn "Error creating mysql user"
fi fi
} }
step_12_info() { step_12_info() {
echoinfoArgs "[OPTIONS]"
echo "Grant privileges" echo "Grant privileges"
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " --database, -d : 'database name'.*" echoinfo " --database, -d : 'database name'.*"
echoinfo " --user, -u : user name" echoinfo " --user, -u : user name"
echoinfo " --remote, -r : ip of allowed remote host" echoinfo " --remote, -r : ip of allowed remote host"
} }
step_12_alias() { ALIAS="grant"; } step_12_options() { echo "[OPTIONS]"; }
step_12_alias() { echo "grant"; }
step_12() { step_12() {
local arg local arg
shift shift
for arg in "$@" ; do for arg in "$@" ; do
case "$1" in case "${1:-}" in
--charset|-c) --charset|-c)
dbOption="$2" dbOption="${2:-}"
shift 2;; shift 2;;
--database|-d) --database|-d)
dbName="$2" dbName="${2:-}"
shift 2 ;; shift 2 ;;
--user|-u) --user|-u)
dbUser="$2" dbUser="${2:-}"
shift 2 ;; shift 2 ;;
--remote|-r) --remote|-r)
dbRemote="$2" dbRemote="${2:-}"
shift 2 ;; shift 2 ;;
*) *)
break ;; break ;;
@@ -194,30 +200,30 @@ step_12() {
done done
exe mysql -u root -e 'GRANT ALL PRIVILEGES ON '$dbName'.* TO '"'"$dbUser"'"'@'"'"$dbRemote"'"';' exe mysql -u root -e 'GRANT ALL PRIVILEGES ON '$dbName'.* TO '"'"$dbUser"'"'@'"'"$dbRemote"'"';'
endReturn -o $? "Error assigning privileges on database" endReturn "Error assigning privileges on database"
exe mysql -u root -e 'FLUSH PRIVILEGES;' exe mysql -u root -e 'FLUSH PRIVILEGES;'
} }
step_14_info() { step_14_info() {
echoinfoArgs "[OPTIONS]"
echo "Revoke all granted privilegs" echo "Revoke all granted privilegs"
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " --user, -u : user name" echoinfo " --user, -u : user name"
echoinfo " --remote, -r : ip of allowed remote host" echoinfo " --remote, -r : ip of allowed remote host"
} }
step_14_alias() { ALIAS="revokeall"; } step_14_options() { echo "[OPTIONS]"; }
step_14_alias() { echo "revokeall"; }
step_14() { step_14() {
local arg local arg
shift shift
for arg in "$@" ; do for arg in "$@" ; do
case "$1" in case "${1:-}" in
--user|-u) --user|-u)
dbUser="$2" dbUser="${2:-}"
shift 2 ;; shift 2 ;;
--remote|-r) --remote|-r)
dbRemote="$2" dbRemote="${2:-}"
shift 2 ;; shift 2 ;;
*) *)
break ;; break ;;
@@ -225,44 +231,44 @@ step_14() {
done done
exe mysql -u root -e 'REVOKE ALL, GRANT OPTION FROM '"'"$dbUser"'"'@'"'"$dbRemote"'"';' exe mysql -u root -e 'REVOKE ALL, GRANT OPTION FROM '"'"$dbUser"'"'@'"'"$dbRemote"'"';'
endReturn -o $? "Error revoking privileges for user $dbUser" endReturn "Error revoking privileges for user $dbUser"
exe mysql -u root -e 'FLUSH PRIVILEGES;' exe mysql -u root -e 'FLUSH PRIVILEGES;'
} }
step_30_info() { echo "List mysql databases"; } step_30_info() { echo "List mysql databases"; }
step_30_alias() { ALIAS="listdb"; } step_30_alias() { echo "listdb"; }
step_30() { step_30() {
exe mysql -u root -e 'SHOW DATABASES;' exe mysql -u root -e 'SHOW DATABASES;'
echo -e "\nDrop userdb by: mysql -u root -e 'DROP DATABASE userdb;'" echo -e "\nDrop userdb by: mysql -u root -e 'DROP DATABASE userdb;'"
} }
step_32_info() { echo "List mysql user"; } step_32_info() { echo "List mysql user"; }
step_32_alias() { ALIAS="listuser"; } step_32_alias() { echo "listuser"; }
step_32() { step_32() {
exe mysql -u root -e 'SELECT User, Host FROM mysql.user;' exe mysql -u root -e 'SELECT User, Host FROM mysql.user;'
echo -e "\nDrop dbuser by: mysql -u root -e 'DROP USER dbuser@localhost;'" echo -e "\nDrop dbuser by: mysql -u root -e 'DROP USER dbuser@localhost;'"
} }
step_34_info() { step_34_info() {
echoinfoArgs "[OPTIONS]"
echo "Show privileges" echo "Show privileges"
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " --user, -u : user name" echoinfo " --user, -u : user name"
echoinfo " --remote, -r : ip of allowed remote host" echoinfo " --remote, -r : ip of allowed remote host"
} }
step_34_alias() { ALIAS="listprivileges"; } step_34_options() { echo "[OPTIONS]"; }
step_34_alias() { echo "listprivileges"; }
step_34() { step_34() {
local arg local arg
shift shift
for arg in "$@" ; do for arg in "$@" ; do
case "$1" in case "${1:-}" in
--user|-u) --user|-u)
dbUser="$2" dbUser="${2:-}"
shift 2 ;; shift 2 ;;
--remote|-r) --remote|-r)
dbRemote="$2" dbRemote="${2:-}"
shift 2 ;; shift 2 ;;
*) *)
break ;; break ;;
@@ -272,13 +278,11 @@ step_34() {
exe mysql -u root -e 'SHOW GRANTS FOR '"'"$dbUser"'"'@'"'"$dbRemote"'"';' exe mysql -u root -e 'SHOW GRANTS FOR '"'"$dbUser"'"'@'"'"$dbRemote"'"';'
} }
step_36_info() { step_36_info() { echo "Size of database"; }
echoinfoArgs "[DATABASE_NAME]" step_36_options() { echo "[DATABASE_NAME]"; }
echo "Size of database" step_36_alias() { echo "sizedb"; }
}
step_36_alias() { ALIAS="sizedb"; }
step_36() { step_36() {
if [ -z "$2" ]; then if [ -z "${2:-}" ]; then
echo "Please provide a database name. e.g. $0 sizedb mydb_db" echo "Please provide a database name. e.g. $0 sizedb mydb_db"
else else
exe mysql -u root -e 'SELECT table_schema "DB Name", exe mysql -u root -e 'SELECT table_schema "DB Name",
@@ -289,33 +293,31 @@ step_36() {
fi fi
} }
step_50_info() { step_50_info() { echo "Backup (dump) a mysql database"; }
echoinfoArgs "<DATABASE NAME> <TARGET DIR>" step_50_options() { echo "<DATABASE NAME> <TARGET DIR>"; }
echo "Backup (dump) a mysql database" step_50_alias() { echo "backup"; }
}
step_50_alias() { ALIAS="backup"; }
step_50() { step_50() {
shift # step number not used shift # step number not used
if [ -z $1 ] ; then if [ -z "${1:-}" ] ; then
echoerr " [E] No database name provided" error -e "No database name provided"
return 1 return 1
fi fi
local dbName="$1" local dbName="${1:-}"
local buTarget="$2" local buTarget="${2:-}"
if [ -z "$2" ] ; then if [ -z "${2:-}" ] ; then
echoerr " [W] No target directory provided. Using home of current user" warning -e "No target directory provided. Using home of current user"
buTarget="$HOME" buTarget="$HOME"
elif [ ! -e "$2" ]; then elif [ ! -e "${2:-}" ]; then
endReturn -o 1 -f "$2 does not exist" endReturn -o 1 -f "${2:-} does not exist"
fi fi
echo " [I] Dumping database $dbName to $buTarget" info "Dumping database $dbName to $buTarget"
exep "mysqldump --single-transaction $dbName > \"$(realpath $buTarget)/${dbName}_backup_$(date +%Y%m%d-%H%M%S).sql\"" exep "mysqldump --single-transaction $dbName > \"$(realpath $buTarget)/${dbName}_backup_$(date +%Y%m%d-%H%M%S).sql\""
endReturn -o $? "Error creating $dbName backup" endReturn "Error creating $dbName backup"
} }
step_52_info() { echo "Restore a mysql database"; } step_52_info() { echo "Restore a mysql database"; }
step_52_alias() { ALIAS="restore"; } step_52_alias() { echo "restore"; }
step_52() { step_52() {
echo "Restore with:" echo "Restore with:"
echo " mysql -e \"DROP DATABASE nextcloud_db\"" echo " mysql -e \"DROP DATABASE nextcloud_db\""
@@ -327,18 +329,18 @@ step_52() {
readDatabaseInfos() { readDatabaseInfos() {
if [ "$dbName" == "" ] ; then if [ "$dbName" == "" ] ; then
read -p "Enter postgres database name: " dbName read -p "Enter postgres database name: " dbName
endCheckEmpty dbName "database" endIfEmpty dbName "database"
fi fi
if [ "$dbUser" == "" ] ; then if [ "$dbUser" == "" ] ; then
read -p "Enter postgres user name: " dbUser read -p "Enter postgres user name: " dbUser
endCheckEmpty dbUser "user name" endIfEmpty dbUser "user name"
fi fi
if [ "$dbPass" == "" ] ; then if [ "$dbPass" == "" ] ; then
read -s -p "Enter postgres password: " dbPass read -s -p "Enter postgres password: " dbPass
endCheckEmpty postgresPass "password" endIfEmpty postgresPass "password"
fi fi
echo echo
} }
VERSION_SEQREV=14 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -3,30 +3,20 @@
# Dependency to other seqs # Dependency to other seqs
# - mysql.sh (soft; Missing informational output) # - mysql.sh (soft; Missing informational output)
toolName="nextcloud" readonly toolName="nextcloud"
localOcc=("echo" "occ not found!") localOcc=("echo" "occ not found!")
# Get script working directory
# (when called from a different directory)
sq_dir="$( cd "$( dirname -- "$(realpath "${BASH_SOURCE[0]}")")" >>/dev/null 2>&1 && pwd )"
sq_config=0 sq_config=0
sq_configFileName="${toolName}.cfg"
sq_configFileTemplate="$sq_dir/${sq_configFileName}.example"
step_config() { seq_config() {
## or to use sequencer api: if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
initSeqConfig "$sq_configFileName" "$sq_configFileTemplate"
if [ $? -eq 0 ] ; then
sq_config=1 sq_config=1
fi fi
localOcc=( sudo -u $sc_ncServerUser php "$(escpath "$sc_ncInstallDir/occ")" ) localOcc=( sudo -u $sc_ncServerUser php "$(escpath "$sc_ncInstallDir/occ")" )
} }
step_1_info() { step_1_info() { echo "Execute occ command"; }
echoinfoArgs "[OCC ARGS]" step_1_options() { echo "[OCC ARGS]"; }
echo "Execute occ command" step_1_alias() { echo "occ"; }
}
step_1_alias() { ALIAS="occ"; }
step_1() { step_1() {
shift shift
@@ -34,10 +24,10 @@ step_1() {
} }
step_20_info() { echo "Upgrade $toolName on command line to latest version of selected release channel"; } step_20_info() { echo "Upgrade $toolName on command line to latest version of selected release channel"; }
step_20_alias() { ALIAS="upgrade"; } step_20_alias() { echo "upgrade"; }
step_20() { step_20() {
if [ $sq_config -eq 0 ] ; then if (( ! sq_config )) ; then
echoerr " [E] No configuration found to determine installation directory" error -e "No configuration found to determine installation directory"
return 1 return 1
fi fi
exe cd "$sc_ncInstallDir" exe cd "$sc_ncInstallDir"
@@ -45,8 +35,19 @@ step_20() {
} }
ncInstaller="updater/updater.phar" ncInstaller="updater/updater.phar"
step_102_info() { echoinfoArgs "<NC DATABASE> <IPV4 ADDRESS>"; echo "Delete IP from bruteforce table"; } step_21_info() { echo "Running recommended post upgrade procedure"; }
step_102_alias() { ALIAS="bruteforceRemoveIP"; } step_21_alias() { echo "postupgrade"; }
step_21() {
step occ db:convert-filecache-bigint
step occ db:add-missing-indices
step occ db:add-missing-columns
step occ db:add-missing-primary-keys
step occ app:update --all
}
step_102_info() { echo "Delete IP from bruteforce table"; }
step_102_options() { echo "<NC DATABASE> <IPV4 ADDRESS>"; }
step_102_alias() { echo "bruteforceRemoveIP"; }
step_102() { step_102() {
shift shift
local ncdb= local ncdb=
@@ -54,10 +55,10 @@ step_102() {
local ipregex='^[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}$' local ipregex='^[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}$'
if [ -z $1 ] ; then if [ -z $1 ] ; then
echoerr " [E] No database provided" error -e "No database provided"
if [ -f "${sq_dir}/mysql.sh" ] ; then if [ -f "${seq_origin}/mysql.sh" ] ; then
echo " [I] Available mysql databases:" info "Available mysql databases:"
"${sq_dir}/mysql.sh" -qq listdb "${seq_origin}/mysql.sh" -qq listdb
fi fi
return 1 return 1
else else
@@ -67,38 +68,40 @@ step_102() {
if [[ "$2" =~ $ipregex ]] ; then if [[ "$2" =~ $ipregex ]] ; then
ip="$2" ip="$2"
else else
echoerr " [E] No valid IP:PORT detected: $2" error -e "No valid IP:PORT detected: $2"
return 1 return 1
fi fi
exe mysql -u root -D ${ncdb} -e 'delete FROM oc_bruteforce_attempts WHERE IP="'${ip}'";' exe mysql -u root -D ${ncdb} -e 'delete FROM oc_bruteforce_attempts WHERE IP="'${ip}'";'
endReturn -o $? "Error deleting ip $ip" endReturn "Error deleting ip $ip"
} }
step_104_info() { echoinfoArgs "<USER>"; echo "Reset and rescan the music library in the background for one user"; } step_104_info() { echo "Reset and rescan the music library in the background for one user"; }
step_104_alias() { ALIAS="audioreset"; } step_104_options() { echo "<USER>"; }
step_104_alias() { echo "audioreset"; }
step_104() { step_104() {
shift shift
local ncUser=$1 local ncUser=$1
if [ -z "$ncUser" ] ; then if [ -z "$ncUser" ] ; then
echoerr " [E] Reset only for single user" error -e "Reset only for single user"
return 1 return 1
fi fi
exep "${localOcc[@]} audioplayer:reset $ncUser > /var/log/ncAudioRescan.log" exep "${localOcc[@]} audioplayer:reset $ncUser > /var/log/ncAudioRescan.log"
echoseq " [I] Rescan audioplayer database for user $ncUser" info "Rescan audioplayer database for user $ncUser"
exep "${localOcc[@]} audioplayer:scan -vvvv $ncUser >> /var/log/ncAudioRescan.log &" exep "${localOcc[@]} audioplayer:scan -vvvv $ncUser >> /var/log/ncAudioRescan.log &"
} }
step_106_info() { echoinfoArgs "<USER>"; echo "Scan the music library"; } step_106_info() { echo "Scan the music library"; }
step_106_alias() { ALIAS="audioscan"; } step_106_options() { echo "<USER>"; }
step_106_alias() { echo "audioscan"; }
step_106() { step_106() {
shift shift
local ncUser=$1 local ncUser="${1:-}"
if [ -z "$ncUser" ] ; then if [ -z "$ncUser" ] ; then
echoerr " [E] Reset only for single user" error -e "Reset only for single user"
return 1 return 1
fi fi
@@ -106,22 +109,22 @@ step_106() {
} }
step_110_info() { echo "Reset picture preview folder"; } step_110_info() { echo "Reset picture preview folder"; }
step_110_alias() { ALIAS="resetpreview"; } step_110_alias() { echo "resetpreview"; }
step_110() { step_110() {
if [ -e "${sc_ncDataDir}" ]; then if [ -e "${sc_ncDataDir}" ]; then
exe rm -rf "${sc_ncDataDir}/appdata_"*"/preview/"* exe rm -rf "${sc_ncDataDir}/appdata_"*"/preview/"*
echoseq " [I] Rescan app data folder" info "Rescan app data folder"
exep "${localOcc[@]} files:scan-app-data &" exep "${localOcc[@]} files:scan-app-data &"
else else
echoerr " [E] Nextcloud data direcotry $sc_ncDataDir not found" error -e "Nextcloud data direcotry $sc_ncDataDir not found"
return 1 return 1
fi fi
} }
step_200_alias() { ALIAS="notes"; } step_200_alias() { echo "notes"; }
step_200() { step_200() {
outColor green color green
cat<<NOTES_END cat<<NOTES_END
# Recommended preview settings # Recommended preview settings
[$sc_ncInstallDir/config/config.php] [$sc_ncInstallDir/config/config.php]
@@ -136,5 +139,7 @@ occ config:app:set preview jpeg_quality --value="60"
NOTES_END NOTES_END
} }
VERSION_SEQREV=15 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

164
seqs/nginx.sh Executable file
View File

@@ -0,0 +1,164 @@
#!/bin/bash
toolName="nginx"
sq_toolDeps="nginx"
sq_repoUrl="https://nginx.org/packages/debian"
sq_keyUrl="https://nginx.org/keys"
sq_toolConfig="/etc/nginx/nginx.conf"
sq_toolLogConfig="/etc/logrotate.d/nginx"
sq_aptOpt=
seq_config() {
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "${toolName} status"; }
step_1_alias() { echo "status"; }
step_1() {
if ! command -v nginx >/dev/null ; then
exe apt-cache policy nginx
return 1
fi
exe nginx --version
exe systemctl status nginx
}
step_10_info() {
echo "Setup latest apt source list for ${toolName}:"
echoinfo "$sq_repoUrl"
}
step_10_alias() { echo "setup"; }
step_10() {
local lArch=
case $(uname -m) in
aarch64)
lArch=arm64;;
esac
if [[ -n ${lArch:-} ]] ; then
info "Detected processor architecture: ${lArch}"
lArch="[arch=${lArch}]"
fi
info "Installing custom repository prerequisites:"
exe apt update
exe apt install apt-transport-https lsb-release ca-certificates curl ${sq_aptOpt}
info "Setup php repository including gpg key"
exep curl -fsSL ${sq_keyUrl:?}/nginx_signing.key "|" gpg --dearmor -o "/etc/apt/trusted.gpg.d/nginx-keyring.gpg"
addConf -c "deb ${lArch:-} ${sq_repoUrl:?} $(lsb_release -sc) nginx" "/etc/apt/sources.list.d/nginx.list"
addConf -es "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900" \
/etc/apt/preferences.d/99nginx
exe apt update
}
step_11_info() {
echo "Installation of ${toolName} packages:"
echoinfo "${sq_toolDeps}"
}
step_11_alias() { echo "install"; }
step_11() {
exe apt update
exe apt install ${sq_toolDeps} ${sq_aptOpt:-}
endReturn "Failed to install ${toolName}"
}
step_12_info() {
echo "Adapt default ${toolName} configuration"
echoinfo "Use Debian default web user \"www-data\" instead of \"nginx\"."
}
step_12() {
if ! grep -E "user\s*nginx;" "${sq_toolConfig}" >>/dev/null ; then
info "Nothing to do."
return 0
fi
exe systemctl stop nginx
info "Installation from nginx.org repository detected."
info -a "Fixing nginx user in ${sq_toolConfig}..."
exe sed -i "s|user\(\s*\)nginx;|user\1www-data;|g" "${sq_toolConfig}"
info -a "Fixing nginx user in ${sq_toolLogConfig}..."
exe sed -i "s|create\(.*\)nginx adm|create\1www-data adm|g" "${sq_toolLogConfig}"
local lQuiet=
interactive || lQuiet="-q"
info "Removing user nginx"
exe deluser ${lQuiet} nginx || true # allowed to fail if non existent
if [[ ! -e "/var/www" ]] ; then
info "Create default web server directory."
exe mkdir "/var/www"
exe chown www-data: "/var/www"
fi
}
step_13_info() { echo "Basic nginx configuration for initial letsencrypt certificate creation"; }
step_13_alias() { echo "initconf"; }
step_13() {
exe mkdir -p "$(dirname -- "$snippetLetsencryptLoc")"
# Writing acme-challenge code snipped for certbot web root authentication
addConf -c "$snippetLetsencrypt" "$snippetLetsencryptLoc"
# Writing minimal default (see below)
addConf -c "$siteDefaultIp4" "$siteDefaultLoc"
# try fix errors on first install attempt
# (possible missing ipv6 support on system)
if [ $ERNO -ne 0 ] ; then
exe apt install ${sq_toolDeps} ${sq_aptOpt:-}
fi
# create webroot
exe mkdir -p "$siteLetsencryptWww"
info -n "Restarting Nginx..."
if exe service nginx restart ; then
info "ok"
else
info "failed"
endReturn -o 1 "Failed to install ${toolName}"
fi
}
snippetLetsencryptLoc="/etc/nginx/snippets/letsencrypt.conf"
siteLetsencryptWww="/var/www/letsencrypt"
snippetLetsencrypt="\
location ^~ /.well-known/acme-challenge/ {
default_type \"text/plain\";
root ${siteLetsencryptWww};
}"
siteDefaultLoc="/etc/nginx/conf.d/default"
siteDefaultIp4="server {
listen 80 default_server;
include ${snippetLetsencryptLoc};
}"
step_20_info() { echo "Installation notes"; }
step_20_alias() { echo "notes"; }
step_20() {
color green
cat <<NOTES_EOF
# Set user to www-data on debian and tune performance a bit
[/etc/nginx/nginx.conf]
user www-data;
worker_processes 1;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
NOTES_EOF
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -16,7 +16,7 @@ SCRIPT_NAME=${SCRIPT_FILE%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg" CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
## or to use sequencer api with global config file: ## or to use sequencer api with global config file:
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" #initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
@@ -26,18 +26,18 @@ step_config() {
# CONFIG=1 # CONFIG=1
#else #else
# # End if no configuration file exists # # End if no configuration file exists
# [ $DRY -eq 0 ] && return -1 # dry || return -1
#fi #fi
## Apt cmdline option to suppress user interaction ## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y" quiet && APTOPT="-y"
## Return of non zero value will abort the sequence ## Return of non zero value will abort the sequence
return 0 return 0
} }
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
downloadLatest downloadLatest
@@ -63,14 +63,14 @@ downloadLatest() {
if [ ! -e "$tempInstall" ] ; then if [ ! -e "$tempInstall" ] ; then
exe mkdir -p "$tempDown" exe mkdir -p "$tempDown"
exe wget -O "$tempInstall" $downUrl exe wget -O "$tempInstall" $downUrl
endReturn -o $? "Download failed: $downUrl" endReturn "Download failed: $downUrl"
else else
echo " [I] Found existing download: $tempInstall" info "Found existing download: $tempInstall"
fi fi
} }
tempDown="/tmp/olivetin" tempDown="/tmp/olivetin"
tempInstall="$tempDown/olivetin.deb" tempInstall="$tempDown/olivetin.deb"
VERSION_SEQREV=13 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -25,7 +25,7 @@ SCRIPT_NAME=${SCRIPT_FILE%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg" CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
## Called once before executing steps. ## Called once before executing steps.
## e.g. to source a config file manually: ## e.g. to source a config file manually:
#. "$CONFIG_FILE" #. "$CONFIG_FILE"
@@ -39,11 +39,11 @@ step_config() {
CONFIG=1 CONFIG=1
else else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return -1 dry || return -1
fi fi
## Apt cmdline option to suppress user interaction ## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y" quiet && APTOPT="-y"
dockerDnsEntry="DOCKER_OPTS=\"--dns $dockerDns1 --dns $dockerDns2\"" dockerDnsEntry="DOCKER_OPTS=\"--dns $dockerDns1 --dns $dockerDns2\""
@@ -52,11 +52,11 @@ step_config() {
} }
step_1_info() { echo "Install Docker dependencies"; } step_1_info() { echo "Install Docker dependencies"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install $dockerDeps $APTOPT exe apt install $dockerDeps $APTOPT
endReturn -o $? "Docker dependencies installation failed" endReturn "Docker dependencies installation failed"
} }
step_2_info() { echo "Install Docker repository"; } step_2_info() { echo "Install Docker repository"; }
@@ -66,22 +66,22 @@ step_2() {
# Add stable repository # Add stable repository
exe add-apt-repository "deb [arch=amd64] ${dockerRepoUrl} $(lsb_release -cs) stable" exe add-apt-repository "deb [arch=amd64] ${dockerRepoUrl} $(lsb_release -cs) stable"
endReturn -o $? "Failed to add Docker repository" endReturn "Failed to add Docker repository"
exe apt update exe apt update
endReturn -o $? "Docker repository not available" endReturn "Docker repository not available"
} }
step_3_info() { echo "Install latest Docker version"; } step_3_info() { echo "Install latest Docker version"; }
step_3() { step_3() {
# Install the latest version # Install the latest version
if [ $QUIET -ne 0 ] ; then if quiet ; then
aptOption="-y" aptOption="-y"
else else
aptOption="" aptOption=""
fi fi
exe apt install $dockerPackages $aptOption exe apt install $dockerPackages $aptOption
echo " [I] You may test the installation by running:" info "You may test the installation by running:"
echo " sudo docker run hello-world" echo " sudo docker run hello-world"
} }
@@ -90,17 +90,17 @@ step_4() {
exe sed -i "s/\(^#DOCKER_OPTS=.*\)$/#\1\n${dockerDnsEntry}/" "$dockerDefaultConf" exe sed -i "s/\(^#DOCKER_OPTS=.*\)$/#\1\n${dockerDnsEntry}/" "$dockerDefaultConf"
exep "grep \"${dockerDns1}\" \"$dockerDefaultConf\" >>/dev/null" exep "grep \"${dockerDns1}\" \"$dockerDefaultConf\" >>/dev/null"
if [ $? -ne 0 ] ; then if [ $? -ne 0 ] ; then
echoerr " [W] Docker dns entry could not be changed" warning -e "Docker dns entry could not be changed"
fi fi
} }
step_5_info() { step_5_info() {
echoinfoArgs "[SECRET]"
echo "Install/start onlyoffice docker container" echo "Install/start onlyoffice docker container"
echoinfo "If [SECRET] is empty, user input will be available if not run --quiet." echoinfo "If [SECRET] is empty, user input will be available if not run --quiet."
echoinfo "$toolName will be run unsecured if no secret was provied." echoinfo "$toolName will be run unsecured if no secret was provied."
} }
step_5_alias() { ALIAS="startoo"; } step_5_options() { echo "[SECRET]"; }
step_5_alias() { echo "startoo"; }
step_5() { step_5() {
local options= local options=
local secret= local secret=
@@ -109,7 +109,7 @@ step_5() {
secret="$2" secret="$2"
elif [ ! -z "$dockerSecret" ]; then elif [ ! -z "$dockerSecret" ]; then
secret="$dockerSecret" secret="$dockerSecret"
elif [ $QUIET -eq 0 ] ; then elif interactive ; then
exe read -s -p "JWT Secret: " secret exe read -s -p "JWT Secret: " secret
fi fi
@@ -124,7 +124,7 @@ step_5() {
-v /app/onlyoffice/DocumentServer/lib:/var/lib/onlyoffice \ -v /app/onlyoffice/DocumentServer/lib:/var/lib/onlyoffice \
-v /app/onlyoffice/DocumentServer/db:/var/lib/postgresql "${dockerImageName}" -v /app/onlyoffice/DocumentServer/db:/var/lib/postgresql "${dockerImageName}"
else else
echoerr " [W] Running $toolName without JWT (JSON Web Tokens)" warning -e "Running $toolName without JWT (JSON Web Tokens)"
exe docker run -i -t -d -p ${onlyOfficePort}:80 --restart=always "${dockerImageName}" exe docker run -i -t -d -p ${onlyOfficePort}:80 --restart=always "${dockerImageName}"
fi fi
@@ -132,7 +132,7 @@ step_5() {
} }
step_7_info() { echo "Upgrade $toolName to latest version"; } step_7_info() { echo "Upgrade $toolName to latest version"; }
step_7_alias() { ALIAS="upgrade"; } step_7_alias() { echo "upgrade"; }
step_7() { step_7() {
# get container ID # get container ID
local containerId=$(docker ps -aqf ancestor="$dockerImageName") local containerId=$(docker ps -aqf ancestor="$dockerImageName")
@@ -140,20 +140,20 @@ step_7() {
exe docker stop $containerId exe docker stop $containerId
exe docker rm $containerId exe docker rm $containerId
else else
echoerr " [W] No $toolName Docker container found" warning -e "No $toolName Docker container found"
fi fi
exe docker pull $dockerImageName exe docker pull $dockerImageName
endReturn -o $? "Error getting $toolName Docker update" endReturn "Error getting $toolName Docker update"
step startoo step startoo
} }
step_10_info() { echo "List running Docker container"; } step_10_info() { echo "List running Docker container"; }
step_10_alias() { ALIAS="ls"; } step_10_alias() { echo "ls"; }
step_10() { step_10() {
exe docker container ls exe docker container ls
echo echo
echo " [I] To stop a container run:" info "To stop a container run:"
echo " docker stop [CONTAINER ID]" echo " docker stop [CONTAINER ID]"
echo " e.g.: docker stop 70f1c5c81be2" echo " e.g.: docker stop 70f1c5c81be2"
} }
@@ -162,7 +162,7 @@ step_12_info() {
echo "Clean unused Docker data" echo "Clean unused Docker data"
echoinfo "(unused containers, dangling images, networks, build cache and volumes)" echoinfo "(unused containers, dangling images, networks, build cache and volumes)"
} }
step_12_alias() { ALIAS="prune"; } step_12_alias() { echo "prune"; }
step_12() { step_12() {
exe docker system df exe docker system df
exe docker system prune exe docker system prune
@@ -170,13 +170,13 @@ step_12() {
} }
step_100_info() { echo "Uninstall Docker"; } step_100_info() { echo "Uninstall Docker"; }
step_100_alias() { ALIAS="uninstall"; } step_100_alias() { echo "uninstall"; }
step_100() { step_100() {
exe apt-get purge docker-ce exe apt-get purge docker-ce
} }
step_102_info() { echo "Purge images, containers, volumes, or customized configuration files"; } step_102_info() { echo "Purge images, containers, volumes, or customized configuration files"; }
step_102_alias() { ALIAS="purge"; } step_102_alias() { echo "purge"; }
step_102() { step_102() {
exe read -p "Are you sure y/[n]? " answer exe read -p "Are you sure y/[n]? " answer
case $answer in case $answer in
@@ -190,5 +190,5 @@ step_102() {
esac esac
} }
VERSION_SEQREV=15 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,59 +1,39 @@
#!/bin/bash #!/bin/bash
toolName=openvpn readonly toolName=openvpn
toolDeps=openvpn readonly toolDeps=openvpn
toolDefaultConf="/etc/default/openvpn" readonly toolDefaultConf="/etc/default/openvpn"
toolUserScriptsLoc="/usr/lib/openvpn" readonly toolUserScriptsLoc="/usr/lib/openvpn"
# Get script working directory sq_aptOpt=
# (when called from a different directory)
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)"
APTOPT=
CONFIG=0
SCRIPT_FILE=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_FILE%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
CONFIG_DIR="$WDIR/$SCRIPT_NAME"
step_config() { seq_config() {
#echo "Called once before executing steps." interactive || sq_aptOpt="-y"
## e.g. to source a config file manually:
#. "$CONFIG_FILE"
## or to use sequencer api with global config file:
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
## or to use sequencer api with profile config file support:
#initSeqConfig -p "$SCRIPT_NAME" "$CONFIG_FILE_TEMPLATE"
#if [ $? -eq 0 ] ; then
# CONFIG=1
#else
# # End if no configuration file exists
# [ $DRY -eq 0 ] && return -1
#fi
[ $QUIET -ne 0 ] && APTOPT="-y"
return 0 return 0
} }
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install $toolDeps $APTOPT exe apt install $toolDeps $sq_aptOpt
} }
step_2_info() { echo "Install customized helper scripts to $toolUserScriptsLoc"; } step_2_info() { echo "Install customized helper scripts to $toolUserScriptsLoc"; }
step_2() { step_2() {
exep "mkdir \"$toolUserScriptsLoc\" 2>>/dev/null" exep "mkdir \"$toolUserScriptsLoc\" 2>>/dev/null"
[ $? -ne 0 ] && \ [ $? -ne 0 ] && \
echoseq " [W] $toolUserScriptsLoc already exists. Not overwriting existing files." warning "$toolUserScriptsLoc already exists. Not overwriting existing files."
exe cp -n "$CONFIG_DIR"/* "$toolUserScriptsLoc" exe cp -n "${seq_origin}/${seq_fileName}"/* "$toolUserScriptsLoc"
} }
step_10_info() { echo "Open openvpn system start configuration"; } step_10_info() { echo "Open openvpn system start configuration"; }
step_10_alias() { ALIAS="default"; } step_10_alias() { echo "default"; }
step_10() { step_10() {
exe vi "$toolDefaultConf" exe vi "$toolDefaultConf"
} }
VERSION_SEQREV=12 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
sc_paperlessHome="/opt/paperless"
sc_paperlessVenv="${sc_paperlessHome}/venv"
sc_paperlessDir="${sc_paperlessHome}/paperless-ngx"
sc_paperlessBackupDir="${HOME}/backup"
sc_paperlessPython="python3"
sc_paperlessUser="paperless"

382
seqs/paperless-venv.sh Executable file
View File

@@ -0,0 +1,382 @@
#!/bin/bash
readonly toolName="paperless-ngx"
readonly toolDeps="python3 python3-pip python3-dev default-libmysqlclient-dev imagemagick fonts-liberation gnupg libpq-dev libmagic-dev mime-support libzbar0 poppler-utils redis-server"
readonly toolDepsOcr="unpaper ghostscript icc-profiles-free qpdf liblept5 libxml2 pngquant zlib1g tesseract-ocr"
readonly versionUrl="https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest"
versionNew=
versionNow=
downUrl=
sq_paperlessDownLoc="/tmp/paperless_latest.tar.xz"
sq_aptOpt=
seq_config() {
## or to use sequencer api with global config file:
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
else
# End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
getVersions() {
versionNew="${versionNew:-$(curl --silent "$versionUrl" | grep -Po '"tag_name": "v\K.*?(?=")')}"
versionNow="${versionNow:-$(grep -Po '"Paperless-ngx",version:"\K.*?(?=")' 2>/dev/null < "${sc_paperlessDir}/static/frontend/de-DE/main.js")}"
downUrl="${downUrl:-"https://github.com/paperless-ngx/paperless-ngx/releases/download/v${versionNew:?}/paperless-ngx-v${versionNew:?}.tar.xz"}"
}
step_1_info() { echo "Status of ${toolName}"; }
step_1_alias() { echo "status"; }
step_1() {
getVersions
info -n "${toolName} "
if [[ -n "${versionNow}" ]] ; then
color green
info -d "version ${versionNow} installed"
if [[ ! ${versionNow:-} == ${versionNew} ]] ; then
info -a "Update available to version ${versionNew} from:"
info -a "${downUrl}"
fi
color none
step service
else
color yellow
info -d "not installed"
info -a "Version ${versionNew} available for installation from:"
info -a "${downUrl}"
fi
}
step_3_info() { echo "Manage ${toolName} services"; }
step_3_options() { echo "[status|start|stop|restart]"; }
step_3_alias() { echo "service"; }
step_3() {
shift
local serviceCommand="is-active"
case "${1:-"status"}" in
start)
serviceCommand="${1}" ;;
stop)
serviceCommand="${1}" ;;
restart)
serviceCommand="${1}" ;;
status)
serviceCommand="is-active"
info -n "paperless-webserver: "
exe systemctl "${serviceCommand:?}" paperless-webserver
info -na "paperless-scheduler: "
exe systemctl "${serviceCommand:?}" paperless-scheduler
info -na "paperless-consumer : "
exe systemctl "${serviceCommand:?}" paperless-consumer
info -na "paperless-task-queue: "
exe systemctl "${serviceCommand:?}" paperless-task-queue.service
return 0 ;;
"")
;;
*)
error "Unknown command ${1:-"-"}"
return 1 ;;
esac
exe systemctl "${serviceCommand:?}" paperless-webserver
exe systemctl "${serviceCommand:?}" paperless-scheduler
exe systemctl "${serviceCommand:?}" paperless-consumer
exe systemctl "${serviceCommand:?}" paperless-task-queue
}
step_10_info() { echo "Install python3"; }
step_10_alias() { echo "install"; }
step_10() {
exe apt update
exe apt install ${toolDeps} ${aptOpt:-}
exe apt install ${toolDepsOcr} ${aptOpt:-}
}
step_11_info() { echo "Add system user"; }
step_11() {
if id "${sc_paperlessUser}" >/dev/null 2>&1 ; then
endReturn -o 1 "User ${sc_paperlessUser} already exists"
fi
exe adduser --disabled-password --disabled-login --gecos "" --home "${sc_paperlessHome}" "${sc_paperlessUser:?}"
}
step_12_info() { echo "Install/upgrade ${toolName}"; }
step_12_alias() { echo "upgrade"; }
step_12() {
local toolUpgrade=0
getVersions
if [[ ${versionNow:-} == ${versionNew} ]] ; then
endReturn -o 1 "Latest version ${versionNow} already installed"
else
if [ -n "${versionNow:-}" ] ; then
info "Upgrading $toolName from ${versionNow} to ${versionNew}"
else
info "Installing $toolName version ${versionNew}"
fi
fi
exe wget ${downUrl} -q -O "${sq_paperlessDownLoc}"
endReturn "Download failed"
if [ -e "${sc_paperlessDir}" ] ; then
if step backup --nostart; then
info "Backup successful"
else
endReturn -o 1 "Backup failed."
fi
toolUpgrade=1
exe mv "${sc_paperlessDir}" "${sc_paperlessDir}_bu"
fi
exe mkdir -p "${sc_paperlessHome}"
exe tar -xf "${sq_paperlessDownLoc}" -C "${sc_paperlessHome}"
exe chown -R "${sc_paperlessUser}": "${sc_paperlessHome}"
if ((toolUpgrade)) ; then
info "Moving over ${toolName} and gunicorn configuration"
addConf -c -f "${sc_paperlessDir}_bu/paperless.conf" "${sc_paperlessDir}/paperless.conf"
saveReturn $?
addConf -c -f "${sc_paperlessDir}_bu/gunicorn.conf.py" "${sc_paperlessDir}/gunicorn.conf.py"
saveReturn $?
endReturn "${toolName} configuration could not be transferred. ${sc_paperlessDir}_bu not deleted."
exe rm -rf "${sc_paperlessDir}_bu"
info "Starting post upgrade procedure"
step postupgrade
step service start
die "Upgrade finished"
fi
}
step_13_info() { echo "Install venv"; }
step_13_alias() { echo "venv"; }
step_13() {
exe "${sc_paperlessPython}" -m venv "${sc_paperlessVenv}"
}
step_14_info() { echo "Install other requirements"; }
step_14_alias() { echo "requirements"; }
step_14() {
exe cd "${sc_paperlessHome}"
exe "${sc_paperlessVenv}/bin/pip3" install --upgrade pip
exe "${sc_paperlessVenv}/bin/pip3" install --requirement "${sc_paperlessDir}/requirements.txt"
}
step_15_info() { echo "Initialization"; }
step_15() {
exe install --owner="${sc_paperlessUser}" --group="${sc_paperlessUser}" -d "${sc_paperlessHome}/"{consume,data,media}
exe cd "${sc_paperlessDir}/src"
exe "${sc_paperlessVenv}/bin/python3" manage.py migrate
exe "${sc_paperlessVenv}/bin/python3" manage.py createsuperuser
exe chown -R "${sc_paperlessUser}": "${sc_paperless}"{consume,data,media}
}
step_17_info() { echo "Post upgrade steps"; }
step_17_alias() { echo "postupgrade"; }
step_17() {
step requirements
exe cd "${sc_paperlessDir}/src"
exe "${sc_paperlessVenv}/bin/python3" manage.py migrate
}
step_19_info() { echo "Install document classification model (nltk)"; }
step_19_alias() { echo 'nltk'; }
step_19() {
info 'Installing nltk'
exe "${sc_paperlessVenv}/bin/pip3" install -U nltk
endReturn "Failed to install nlkt"
exe cd "${sc_paperlessHome}/data"
exe mkdir -p "nltk"
exe "${sc_paperlessVenv}/bin/python3" -m nltk.downloader -d ./nltk/ snowball_data stopwords punkt
endReturn "Failed to install nlkt modules snowball stopwords punkt"
step service restart
}
step_21_info() { echo 'Setup dependecies to compile jbig2'; }
step_21_alias() { echo 'setup_jbig2'; }
step_21() {
exe apt install libtool libleptonica-dev ${sq_aptOpt}
}
sq_jbig2build="/tmp/jbig2build"
step_22_info() { echo 'Compile jbig2'; }
step_22_alias() { echo 'make_jbig2'; }
step_22() {
exe mkdir -p "${sq_jbig2build}"
exe cd "${sq_jbig2build}"
exe git clone https://github.com/agl/jbig2enc
exe cd jbig2enc
exe ./autogen.sh
exep ./configure "&&" make
}
step_23_info() { echo 'Install compiled jbig2'; }
step_23_alias() { echo 'install_jbig2'; }
step_23() {
[[ ! -d "${sq_jbig2build}" ]] && die "Compile jbi2 first"
exe cd "${sq_jbig2build}/jbig2enc"
exe make install
}
step_30_info() {
echo "Retag existing documents"
echoinfo "OPTIONS"
echoinfo " -c, --correspondent"
echoinfo " -T, --tags"
echoinfo " -t, --document_type"
echoinfo " -i, --inbox-only"
echoinfo " --use-first"
echoinfo " -f, --overwrite"
}
step_30_options() { echo "[OPTIONS]"; }
step_30_alias() { echo "retag"; }
step_30() {
shift
exe cd "${sc_paperlessDir}/src"
exe sudo -u "${sc_paperlessUser}" "${sc_paperlessVenv}/bin/python3" manage.py document_retagger "$@"
}
step_32_info() {
echo "Manage document search index"
echoinfo " reindex - (default) create index from scratch"
echoinfo " optimize - updates index to increase search speed and"
echoinfo " ensures autocompletion"
}
step_32_options() { echo "[reindex|optimize]"; }
step_32_alias() { echo "reindex"; }
step_32() {
shift
local command="${1:-"reindex"}"
case "${1:-}" in
reindex) ;;
optimize) ;;
"") ;;
*) fatal "Unkown argument ${1}" ;;
esac
exe cd "${sc_paperlessDir}/src"
exe sudo -u "${sc_paperlessUser}" "${sc_paperlessVenv}/bin/python3" manage.py document_index "${command}"
}
step_34_info() {
echo "Rename (apply storage paths) to existing documents"
echoinfo "Be aware that this command moves files on the file system."
echoinfo "Consider creating a backup before execution."
}
step_34_alias() { echo "rename"; }
step_34() {
exe cd "${sc_paperlessDir}/src"
exe sudo -u "${sc_paperlessUser}" "${sc_paperlessVenv}/bin/python3" manage.py document_renamer
}
step_40_info() { echo "Backup ${toolName}"; }
step_40_options() { echo "[--nostart]"; }
step_40_alias() { echo "backup"; }
step_40() {
shift
info "Doing backup..."
step service stop
exe cd "$(dirname -- "${sc_paperlessHome}")"
exe tar czf "${sc_paperlessBackupDir:-"${HOME}/backup"}/paperless_backup_$(date +%Y%m%d-%H%M%S).tar.gz" \
"$(basename -- "${sc_paperlessHome}")"
#--exclude="$(basename -- "${sc_paperlessHome}")/.local" \
#--exclude="$(basename -- "${sc_paperlessHome}")/.cache" \
if [[ ${1:-} == "--nostart" ]] ; then
info "Not starting ${toolName} services after backup"
else
step service start
fi
}
step_100_info() { echo "Notes"; }
step_100_alias() { echo "notes"; }
step_100() {
color green
cat <<EOF_NOTES
# Custom installations
* tesseract-ocr-[LANG]
[LANG] = eng,deu,...
# Config modifications
* paperless.conf
* redis password
redis://:password@localhost:6379
* consume,data,media direcotries (${sc_paperlessHome}/...)
../../{consume,data,media}
* To allow access directly via ip address
PAPERLESS_ALLOWED_HOSTS=$(hostname -I | awk '{print $1;}')
* recommended settings
PAPERLESS_FILENAME_FORMAT={created_year}/{title}
PAPERLESS_SECRET_KEY=change-me
PAPERLESS_OCR_LANGUAGE=deu+eng
PAPERLESS_TIME_ZONE=Europe/Berlin
* service files
* templates ${sc_paperlessDir}/scripts :
$(cd "${sc_paperlessDir}"/scripts 2>/dev/null && for f in *.service; do echo " $f"; done)
* Modifications:
* WorkingDirectory=/opt/paperless/paperless-ngx/src
* path to celery: ${sc_paperlessHome}/venv/bin/celery
* service files webserver
* Environment="PAPERLESS_BIND_ADDR=0.0.0.0"
Environment="PAPERLESS_PORT=8084"
To chose a custom listen address and port for gunicorn
(default address: [..], default port: 8000)
* /etc/ImageMagick-x/policy.xml
* enable access to pdfs
<policy domain="coder" rights="read|write" pattern="PDF" />
# Nginx proxy
---
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name mydomain.com;
access_log off; #/var/log/nginx/paperless.log;
error_log /var/log/nginx/paperless_error.log;
include /etc/nginx/ssl.conf;
error_page 497 https://\$host:\$server_port\$request_uri;
fastcgi_read_timeout 300s;
proxy_read_timeout 65s;
client_max_body_size 20M;
location / {
proxy_pass http://10.0.0.10/;
# These configuration options are required for WebSockets to work.
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header Host \$http_host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
}
---
EOF_NOTES
color none
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
sc_paperlessHome="/opt/paperless"
sc_paperlessDir="${sc_paperlessHome}/paperless-ngx"
sc_paperlessBackupDir="${HOME}/backup"

View File

@@ -1,32 +1,334 @@
#!/bin/bash #!/bin/bash
step_1_info() { echo "Install python3"; } readonly toolName="paperless-ngx"
step_1() { readonly toolUser="paperless"
exe apt update readonly toolDeps="python3 python3-pip python3-dev default-libmysqlclient-dev imagemagick fonts-liberation gnupg libpq-dev libmagic-dev mime-support libzbar0 poppler-utils redis-server"
exe apt install python3 python3-pip readonly toolDepsOcr="unpaper ghostscript icc-profiles-free qpdf liblept5 libxml2 pngquant zlib1g tesseract-ocr"
} readonly versionUrl="https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest"
step_2_info() { echo "Get paperless using git (checkout 2.7.0)"; } versionNew=
step_2() { versionNow=
exe git clone https://github.com/the-paperless-project/paperless.git /opt/paperless downUrl=
exe cd /opt/paperless && git checkout 2.7.0
}
step_3_info() { echo "Install other dependcies"; } sq_paperlessDownLoc="/tmp/paperless_latest.tar.xz"
step_3() { sq_aptOpt=
exe apt install gnupg tesseract-ocr tesseract-ocr-deu imagemagick unpaper libpoppler-cpp-dev optipng
exe pip3 install --user --requirement /opt/paperless/requirements.txt
}
step_4_info() { echo "Paperless configuration file"; } seq_config() {
step_4() { ## or to use sequencer api with global config file:
if [ ! -f /etc/paperless.conf ] ; then if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
cp -ar paperless.conf.example /etc/paperless.conf sq_config=1
else else
echo "[ WARN ] Configuration already exists. Doing nothing" # End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
getVersions() {
versionNew="${versionNew:-$(curl --silent "$versionUrl" | grep -Po '"tag_name": "v\K.*?(?=")')}"
versionNow="${versionNow:-$(grep -Po '"Paperless-ngx",version:"\K.*?(?=")' 2>/dev/null < "${sc_paperlessDir}/static/frontend/de-DE/main.js")}"
downUrl="${downUrl:-"https://github.com/paperless-ngx/paperless-ngx/releases/download/v${versionNew:?}/paperless-ngx-v${versionNew:?}.tar.xz"}"
}
step_1_info() { echo "Status of ${toolName}"; }
step_1_alias() { echo "status"; }
step_1() {
getVersions
info -n "${toolName} "
if [[ -n "${versionNow}" ]] ; then
color green
info -d "version ${versionNow} installed"
if [[ ! ${versionNow:-} == ${versionNew} ]] ; then
info -a "Update available to version ${versionNew} from:"
info -a "${downUrl}"
fi
else
color yellow
info -d "not installed"
info -a "Version ${versionNew} available for installation from:"
info -a "${downUrl}"
fi fi
} }
VERSION_SEQREV=3 step_3_info() { echo "Manage ${toolName} services"; }
step_3_options() { echo "[status|start|stop|restart]"; }
step_3_alias() { echo "service"; }
step_3() {
shift
local serviceCommand="is-active"
case "${1:-"status"}" in
start)
serviceCommand="${1}" ;;
stop)
serviceCommand="${1}" ;;
restart)
serviceCommand="${1}" ;;
status)
serviceCommand="is-active"
info -n " paperless-webserver: "
exe systemctl "${serviceCommand:?}" paperless-webserver
info -na " paperless-scheduler: "
exe systemctl "${serviceCommand:?}" paperless-scheduler
info -na " paperless-consumer: "
exe systemctl "${serviceCommand:?}" paperless-consumer
info -na "paperless-task-queue: "
exe systemctl "${serviceCommand:?}" paperless-task-queue.service
return 0 ;;
"")
;;
*)
error "Unknown command ${1:-"-"}"
return 1 ;;
esac
exe systemctl "${serviceCommand:?}" paperless-webserver
exe systemctl "${serviceCommand:?}" paperless-scheduler
exe systemctl "${serviceCommand:?}" paperless-consumer
exe systemctl "${serviceCommand:?}" paperless-task-queue
}
step_10_info() { echo "Install python3"; }
step_10_alias() { echo "install"; }
step_10() {
exe apt update
exe apt install ${toolDeps} ${aptOpt:-}
exe apt install ${toolDepsOcr} ${aptOpt:-}
}
step_11_info() { echo "Add system user"; }
step_11() {
if id "${toolUser}" >/dev/null 2>&1 ; then
endReturn -o 1 "User ${toolUser} already exists"
fi
exe adduser "${toolUser}" --system --group --home "${sc_paperlessHome}"
}
step_12_info() { echo "Install/upgrade ${toolName}"; }
step_12_alias() { echo "upgrade"; }
step_12() {
local toolUpgrade=0
getVersions
if [[ ${versionNow:-} == ${versionNew} ]] ; then
endReturn -o 1 "Latest version ${versionNow} already installed"
else
if [ -n "${versionNow:-}" ] ; then
info "Upgrading $toolName from ${versionNow} to ${versionNew}"
else
info "Installing $toolName version ${versionNew}"
fi
fi
exe wget ${downUrl} -q -O "${sq_paperlessDownLoc}"
endReturn "Download failed"
if [ -e "${sc_paperlessDir}" ] ; then
if step backup --nostart; then
info "Backup successful"
else
endReturn -o 1 "Backup failed."
fi
toolUpgrade=1
exe mv "${sc_paperlessDir}" "${sc_paperlessDir}_bu"
fi
exe tar -xf "${sq_paperlessDownLoc}" -C "${sc_paperlessHome}"
exe chown -R "${toolUser}": "${sc_paperlessDir}"
if ((toolUpgrade)) ; then
info "Moving over ${toolName} and gunicorn configuration"
addConf -c -f "${sc_paperlessDir}_bu/paperless.conf" "${sc_paperlessDir}/paperless.conf"
saveReturn $?
addConf -c -f "${sc_paperlessDir}_bu/gunicorn.conf.py" "${sc_paperlessDir}/gunicorn.conf.py"
saveReturn $?
endReturn "${toolName} configuration could not be transferred. ${sc_paperlessDir}_bu not deleted."
exe rm -rf "${sc_paperlessDir}_bu"
info "Starting post upgrade procedure"
step postupgrade
step service start
die "Upgrade finished"
fi
}
step_13_info() { echo "Install other dependcies"; }
step_13_alias() { echo "requirements"; }
step_13() {
exe cd "${sc_paperlessHome}"
exe sudo -Hu paperless pip3 install --upgrade pip
exe sudo -Hu paperless pip3 install --requirement "${sc_paperlessDir}/requirements.txt"
}
step_14_info() { echo "Initialization"; }
step_14() {
exe install --owner="${toolUser}" --group="${toolUser}" -d "${sc_paperlessHome}/"{consume,data,media}
exe cd "${sc_paperlessDir}/src"
exe sudo -Hu paperless python3 manage.py migrate
exe sudo -Hu paperless python3 manage.py createsuperuser
}
step_16_info() { echo "Post upgrade steps"; }
step_16_alias() { echo "postupgrade"; }
step_16() {
step requirements
exe cd "${sc_paperlessDir}/src"
exe sudo -Hu paperless python3 manage.py migrate
}
step_18_info() {
echo "Retag existing documents"
echoinfo "OPTIONS"
echoinfo " -c, --correspondent"
echoinfo " -T, --tags"
echoinfo " -t, --document_type"
echoinfo " -i, --inbox-only"
echoinfo " --use-first"
echoinfo " -f, --overwrite"
}
step_18_options() { echo "[OPTIONS]"; }
step_18_alias() { echo "retag"; }
step_18() {
shift
exe cd "${sc_paperlessDir}/src"
exe sudo -Hu paperless python3 manage.py document_retagger "$@"
}
step_20_info() {
echo "Manage document search index"
echoinfo " reindex - (default) create index from scratch"
echoinfo " optimize - updates index to increase search speed and"
echoinfo " ensures autocompletion"
}
step_20_options() { echo "[reindex|optimize]"; }
step_20_alias() { echo "reindex"; }
step_20() {
shift
local command="${1:-"reindex"}"
case "${1:-}" in
reindex)
;;
optimize)
;;
"")
;;
*)
fatal "Unkown argument ${1}"
;;
esac
exe cd "${sc_paperlessDir}/src"
exe sudo -Hu paperless python3 manage.py document_index "${command}"
}
step_22_info() {
echo "Rename (apply storage paths) to existing documents"
echoinfo "Be aware that this command moves files on the file system."
echoinfo "Consider creating a backup before execution."
}
step_22_alias() { echo "rename"; }
step_22() {
exe cd "${sc_paperlessDir}/src"
exe sudo -Hu paperless python3 manage.py document_renamer
}
step_30_info() { echo "Backup ${toolName}"; }
step_30_options() { echo "[--nostart]"; }
step_30_alias() { echo "backup"; }
step_30() {
shift
info "Doing backup..."
step service stop
exe cd "$(dirname -- "${sc_paperlessHome}")"
exe tar czf "${sc_paperlessBackupDir:-"${HOME}/backup"}/paperless_backup_$(date +%Y%m%d-%H%M%S).tar.gz" \
"$(basename -- "${sc_paperlessHome}")"
#--exclude="$(basename -- "${sc_paperlessHome}")/.local" \
#--exclude="$(basename -- "${sc_paperlessHome}")/.cache" \
if [[ ${1:-} == "--nostart" ]] ; then
info "Not starting ${toolName} services after backup"
else
step service start
fi
}
step_100_info() { echo "Notes"; }
step_100_alias() { echo "notes"; }
step_100() {
color green
cat <<EOF_NOTES
# Custom installations
* tesseract-ocr-[LANG]
[LANG] = eng,deu,...
# Config modifications
* paperless.conf
* redis password
redis://:password@localhost:6379
* consume,data,media direcotries (${sc_paperlessHome}/...)
../../{consume,data,media}
* recommended settings
PAPERLESS_FILENAME_FORMAT={created_year}/{title}
PAPERLESS_SECRET_KEY=change-me
PAPERLESS_OCR_LANGUAGE=deu+eng
PAPERLESS_TIME_ZONE=Europe/Berlin
* service files
* templates ${sc_paperlessDir}/scripts :
$(cd "${sc_paperlessDir}"/scripts && for f in *.service; do echo " $f"; done)
* Modifications:
* WorkingDirectory=/opt/paperless/paperless-ngx/src
* path to celery: ${sc_paperlessHome}/.local/bin/celery
* service files webserver
* Environment="PAPERLESS_PORT=8084"
To chose a custom listen port for gunicorn
* gunicorn.conf.py
* bind = f'0.0.0.0:{os.getenv("PAPERLESS_PORT", 8000)}'
If IPv6 is disabled/not avilable the first start takes very long
* /etc/ImageMagick-x/policy.xml
* enable access to pdfs
<policy domain="coder" rights="read|write" pattern="PDF" />
# Nginx proxy
---
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name mydomain.com;
access_log off; #/var/log/nginx/paperless.log;
error_log /var/log/nginx/paperless_error.log;
include /etc/nginx/ssl.conf;
error_page 497 https://\$host:\$server_port\$request_uri;
fastcgi_read_timeout 300s;
proxy_read_timeout 65s;
client_max_body_size 20M;
location / {
proxy_pass http://10.0.0.10/;
# These configuration options are required for WebSockets to work.
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header Host \$http_host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
}
---
EOF_NOTES
color none
}
readonly sqr_minVersion=16
. sequencer.sh . sequencer.sh

5
seqs/php.cfg.example Normal file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
sc_phpVersion="8.0"
# Add packages to be installed alongside the default (fpm cli)
sc_phpPackages=(zip bz2)

185
seqs/php.sh Executable file
View File

@@ -0,0 +1,185 @@
#!/usr/bin/env bash
readonly toolName=php
readonly sq_repoUrl="https://packages.sury.org/php"
# Already defined by sequencer.sh, but may be overwritten
#readonly seq_configName="${sq_scriptName:?}.cfg"
#readonly seq_configTemplate="${seq_origin:?}/${sq_configName:?}.example"
sq_aptOpt=
sq_config=0
sq_phpName=php
sq_FpmConfig=
sq_CliConfig=
sq_PoolConfig=
sq_FpmIni=
seq_config() {
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
else
# End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
sq_phpName="php${sc_phpVersion:?}"
# Default dependencies for this seq
sc_phpPackages+=(fpm cli)
# Prepare php packages to be installed
sq_phpPackages="${sc_phpPackages[@]/#/${sq_phpName}-}"
sq_FpmConfig="/etc/php/${sc_phpVersion:?}/fpm/conf.d/90-custom_pi.ini"
sq_CliConfig="/etc/php/${sc_phpVersion:?}/cli/conf.d/90-custom_pi.ini"
sq_PoolConfig="/etc/php/${sc_phpVersion:?}/fpm/pool.d/www.conf"
sq_FpmIni="/etc/php/${sc_phpVersion:?}/fpm/php-fpm.conf"
## Return of non zero value will abort the sequence
return 0
}
getPhpVersion() {
local lPhp=
if ! lPhp="$(command -v php >>/dev/null && php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')"; then
return 1
fi
echo ${lPhp}
}
step_1_info() { echo "Installation status"; }
step_1_alias() { echo "status"; }
step_1() {
exe apt-cache policy ${sq_phpName}-common
}
step_3_info() { echo "Get installed PHP version"; }
step_3_alias() { echo "version"; }
step_3(){
if ! lPhp="$(getPhpVersion)" ; then
warning "PHP not yet installed"
return 1
fi
echo "$lPhp"
}
step_5_info() { echo "Install ${toolName:-'-'} packages prepending the correct version"; }
step_5_options() { echo "[PHP_PACKAGE_NAME ...]"; }
step_5_alias() { echo "add"; }
step_5() {
shift
local packages=("$@")
(( ${#packages[@]} )) || fatal "No packages provided"
exe apt install "${packages[@]/#/${sq_phpName}-}" ${sq_aptOpt:-}
}
step_10_info() { echo "Setup debian ${toolName:-'-'} repository"; }
step_10_alias() { echo "setup"; }
step_10() {
local lArch=
case $(uname -m) in
aarch64)
lArch=arm64;;
esac
if [[ -n ${lArch:-} ]] ; then
info "Detected processor architecture: ${lArch}"
lArch="[arch=${lArch}]"
fi
info "Installing custom repository prerequisites:"
exe apt update
exe apt install apt-transport-https lsb-release ca-certificates curl ${sq_aptOpt:-}
info "Setup ${toolName:-'-'} repository including gpg key"
exep curl -fsSL ${sq_repoUrl:?}/apt.gpg "|" gpg --dearmor -o /etc/apt/trusted.gpg.d/sury-keyring.gpg
addConf -c "deb ${lArch:-} ${sq_repoUrl:?} $(lsb_release -sc) main" "/etc/apt/sources.list.d/php.list"
exe apt-get update
}
step_11_info() {
echo "Installation of ${toolName:-'-'} packages:"
echoinfo "${sq_phpPackages:-"(customize with '${seq_name} -c')"}"
}
step_11_alias() { echo "install"; }
step_11() {
exe apt install ${sq_phpPackages} ${sq_aptOpt}
}
phpFpmConfig="date.timezone = Europe/Berlin
max_execution_time = 600
memory_limit = 1024M
output_buffering = Off
session.cookie_secure = True
upload_max_filesize = 1024M"
phpCliConfig="date.timezone = Europe/Berlin
output_buffering = Off"
step_20_info() { echo "Configuration of ${sq_phpName} fpm and cli"; }
step_20_alias() { echo "conf_fpm_cli"; }
step_20() {
addConf -s "$phpFpmConfig" "$sq_FpmConfig"
addConf -s "$phpCliConfig" "$sq_CliConfig"
restart_php
}
step_22_info() { echo "Configure ${toolName} pool ondemand"; }
step_22_alias() { echo "conf_pool_ondemand"; }
step_22() {
info "Setting ${toolName} pool to 'ondemand'"
addConf -a "" "$sq_FpmIni"
exe sed -i "s/^[;[:space:]]*pm =.*/pm = ondemand/" "$sq_PoolConfig"
restart_php
}
step_24_info() { echo "Configure ${toolName} pool dynamic"; }
step_24_alias() { echo "conf_pool_dynamic"; }
step_24() {
local AvailableRAM=$(awk '/MemAvailable/ {printf "%d", $2/1024}' /proc/meminfo)
local AverageFPM=$(ps --no-headers -o 'rss,cmd' -C php-fpm${sc_phpVersion} | awk '{ sum+=$1 } END { printf ("%d\n", sum/NR/1024,"M") }')
local FPMS=$((AvailableRAM/AverageFPM))
local PMaxSS=$((FPMS*2/3))
local PMinSS=$((PMaxSS/2))
local PStartS=$(((PMaxSS+PMinSS)/2))
addConf -a "" "$sq_FpmIni"
exe sed -i "s|;emergency_restart_threshold.*|emergency_restart_threshold = 10|g" "$sq_FpmIni"
exe sed -i "s|;emergency_restart_interval.*|emergency_restart_interval = 1m|g" "$sq_FpmIni"
exe sed -i "s|;process_control_timeout.*|process_control_timeout = 10|g" "$sq_FpmIni"
addConf -a "" "$sq_PoolConfig"
exe sed -i "s/;env\[HOSTNAME\] = /env[HOSTNAME] = /" "$sq_PoolConfig"
exe sed -i "s/;env\[TMP\] = /env[TMP] = /" "$sq_PoolConfig"
exe sed -i "s/;env\[TMPDIR\] = /env[TMPDIR] = /" "$sq_PoolConfig"
exe sed -i "s/;env\[TEMP\] = /env[TEMP] = /" "$sq_PoolConfig"
exe sed -i "s/;env\[PATH\] = /env[PATH] = /" "$sq_PoolConfig"
exe sed -i "s/^[;[:space:]]*pm =.*/pm = dynamic/" "$sq_PoolConfig"
exe sed -i 's/pm.max_children =.*/pm.max_children = '$FPMS'/' "$sq_PoolConfig"
exe sed -i 's/pm.start_servers =.*/pm.start_servers = '$PStartS'/' "$sq_PoolConfig"
exe sed -i 's/pm.min_spare_servers =.*/pm.min_spare_servers = '$PMinSS'/' "$sq_PoolConfig"
exe sed -i 's/pm.max_spare_servers =.*/pm.max_spare_servers = '$PMaxSS'/' "$sq_PoolConfig"
exe sed -i "s/;pm.max_requests =.*/pm.max_requests = 1000/" "$sq_PoolConfig"
restart_php
}
restart_php() {
info -n "Restarting ${sq_phpName} fpm ... "
exe service ${sq_phpName}-fpm restart && info -d "ok" || info -d "nok"
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

70
seqs/pihole.sh Executable file
View File

@@ -0,0 +1,70 @@
#!/usr/bin/env bash
readonly toolName=pi-hole
step_1_info() { echo "${toolName} statue"; }
step_1_alias() { echo "status"; }
step_1() {
local piholeCmd=
if ! piholeCmd="$(command -v pihole)" ; then
warning "${toolName} not installed"
return 1
fi
exe "${piholeCmd}" status
}
step_3_alias() { echo "restart"; }
step_3() {
exe service pihole-FTL restart
exe pihole restartdns
}
step_10_info() {
echo "Install ${toolName} using the offical installer"
echoinfo "https://install.pi-hole.net"
}
step_10_alias() { echo "install"; }
step_10() {
exep curl -sSL https://install.pi-hole.net \| bash
}
step_11_info() { echo 'Notes'; }
step_11_alias() { echo 'notes'; }
step_11() {
color green
cat <<NOTES_END
[/etc/dnsmasq.d/10-owndhcp.conf]
expand-hosts
local=/lan/
# define custom gateway for dhcp clients
#dhcp-option=3,192.168.0.1
# define dns server for dhcp clients
dhcp-option=6,192.168.0.20,192.168.0.29
# define ntp server for dhcp clients
dhcp-option=42,192.168.0.20
# push static route to vpn network
#dhcp-option=121,10.8.0.0/24,192.168.0.10,0.0.0.0/0,192.168.0.1
[/etc/dnsmasq.d/10-owndomain.conf]
address=/mydomain.com/192.168.0.20
address=/mydomain.com/fd::20
# Use together with unbound
(https://docs.pi-hole.net/guides/dns/unbound)
[/etc/dnsmasq.d/99-edns.conf]
edns-packet-max=1232
NOTES_END
}
step_20_info() { echo "List ${toolName} enabled adlist sources"; }
step_20_alias() { echo 'adlists'; }
step_20() {
exe sqlite3 /etc/pihole/gravity.db 'SELECT address FROM adlist WHERE enabled = 1;'
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -4,49 +4,36 @@
## Installation and management of piwigo gallery ## Installation and management of piwigo gallery
toolName="piwigo" toolName="piwigo"
toolVersion="11.3.0"
# Get script working directory seq_config() {
# (when called from a different directory) if ! initSeqConfig "${seq_configName}" "${seq_configTemplate}" ; then
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd )" dry || return 1
CONFIG=0
SCRIPT_NAME=$(basename -- "$0")
SCRIPT_NAME=${SCRIPT_NAME%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
else
[ $DRY -eq 0 ] && return 1
fi fi
} }
step_30_info() { echo "Backup ${toolName} web direcotry"; } step_30_info() { echo "Backup ${toolName} web direcotry"; }
step_30_alias() { ALIAS="backup"; } step_30_alias() { echo "backup"; }
step_30() { step_30() {
exep "cd \"${PIWI_DIR}\"/.. && tar czf \"${PIWI_BU_DIR}/\`date +%Y%m%d\`_${toolName}_web.tar.gz\" --exclude=\"${toolName}/network/*\" --exclude=\"${toolName}/_data/i/*\" \"$(basename "$PIWI_DIR")\"" exep "cd \"${PIWI_DIR}\"/.. && tar czf \"${PIWI_BU_DIR}/\`date +%Y%m%d\`_${toolName}_web.tar.gz\" --exclude=\"${toolName}/network/*\" --exclude=\"${toolName}/_data/i/*\" \"$(basename "$PIWI_DIR")\""
} }
step_31_info() { step_31_info() { echo "Backup ${toolName} database"; }
echoinfoArgs "[daily|monthly(default]" step_31_options() { echo "[daily|monthly(default)]"; }
echo "Backup ${toolName} database" step_31_alias() { echo "backupdb"; }
}
step_31_alias() { ALIAS="backupdb"; }
step_31() { step_31() {
case "$2" in case "${2:-}" in
daily|Daily|DAILY) daily|Daily|DAILY)
[ $QUIET -ne 2 ] && echo " [I] Daily backup..." info "Daily backup..."
exep "mysqldump --single-transaction -u root ${PIWI_DB_NAME} | bzip2 -c > \"${PIWI_BU_DIR}/${toolName}_daily.sql.bz2\"" exep mysqldump --single-transaction -u root "${PIWI_DB_NAME}" '|' bzip2 -c '>' "${PIWI_BU_DIR}/${toolName}_daily.sql.bz2"
;; ;;
*) *)
[ $QUIET -ne 2 ] && echo " [I] Monthly backup..." info "Monthly backup..."
exep "mysqldump --single-transaction -u root ${PIWI_DB_NAME} | bzip2 -c > \"${PIWI_BU_DIR}/monthly/\`date +%Y%m%d\`_${toolName}.sql.bz2\"" exep mysqldump --single-transaction -u root "${PIWI_DB_NAME}" '|' bzip2 -c '>' "${PIWI_BU_DIR}/monthly/$(date +%Y%m%d)_${toolName}.sql.bz2"
;; ;;
esac esac
} }
VERSION_SEQREV=14 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
sc_phpVersion="8.1"

View File

@@ -2,94 +2,102 @@
toolName="pixelfed" toolName="pixelfed"
toolTag="dev" toolTag="dev"
toolDeps="composer jpegoptim php7.3-bcmath php-imagick" toolPhpDeps=(bcmath ctype curl exif gd iconv intl mbstring redis tokenizer xml zip)
toolDeps="jpegoptim php-imagick"
toolPath="/var/www/pixelfed" toolPath="/var/www/pixelfed"
sq_aptOpt=
sq_config=0
sq_phpName=php
sq_PoolConfig=
seq_config() {
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
else
# End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
sq_phpName="php${sc_phpVersion:?}"
sq_PoolConfig="/etc/php/${sc_phpVersion:?}/fpm/pool.d/www.conf"
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Updating apt"; } step_1_info() { echo "Updating apt"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
} }
step_2_info() { echo -e "Installing $toolName dependencies: $toolDeps"; } step_2_info() { echo -e "Installing $toolName dependencies"; }
step_2() { step_2() {
exe apt install $toolDeps -y exe apt install "${toolPhpDeps[@]/#/${sq_phpName}-}" $toolDeps ${sq_aptOpt}
endReturn -o $? "Installing deps for $toolName failed" endReturn "Installing deps for $toolName failed"
exe service php7.3-fpm restart exe service ${sq_phpName}-fpm restart
endReturn -o $? "Problems starting $toolName" endReturn "Problems starting $toolName"
} }
step_3_info() { echo -e "Get $toolName using git"; } step_3_info() { echo -e "Get $toolName using git"; }
step_3() { step_3() {
exe git clone -b $toolTag https://github.com/pixelfed/pixelfed.git $toolPath exe git clone -b $toolTag https://github.com/pixelfed/pixelfed.git "${toolPath:?}"
exe cd $toolPath exe cd "${toolPath:?}"
exe chown -R www-data:www-data . # change user/group to http user and http group exe chown -R www-data:www-data "${toolPath:?}" # change user/group to http user and http group
exe find . -type d -exec chmod 755 {} \; # set all directories to rwx by user/group exe find . -type d -exec chmod 755 {} \; # set all directories to rwx by user/group
exe find . -type f -exec chmod 644 {} \; # set all files to rw by user/group exe find . -type f -exec chmod 644 {} \; # set all files to rw by user/group
exe composer install --no-ansi --no-interaction --optimize-autoloader
endReturn -o $? "Composer install error"
} }
step_4_info() { echo "Create mysql database for $toolName"; } step_4_info() { echo "Install composer and ${toolName} dependencies"; }
step_4() { step_4() {
local mysqlDatabase exe cd "${toolPath:?}"
local mysqlUser exe ${seq_origin:?}/composer.sh -qq install
local mysqlPass exe sudo -u www-data ${sq_phpName:?} composer.phar install --no-ansi --no-interaction --optimize-autoloader
endReturn "Composer install error"
echo "Existing mysql databases:"
exe mysql -u root -e 'SHOW DATABASES;'
echo -en "Enter database name: "
exe read mysqlDatabase
endCheckEmpty mysqlDatabase "database name"
exe mysql -u root -e 'CREATE DATABASE '$mysqlDatabase' CHARACTER SET utf8mb4;'
endReturn -o $? "Creating database failed"
echo "Existing mysql user:"
exe mysql -u root -e 'SELECT User, Host FROM mysql.user;'
echo -en "Enter mysql user name: "
read mysqlUser
endCheckEmpty mysqlDatabase "user name"
echo -en "Enter mysql user password: "
read -s mysqlPass
endCheckEmpty mysqlPass "password"
exe mysql -u root -e 'CREATE USER '"'"$mysqlUser"'"'@'"'"'localhost'"'"' IDENTIFIED BY '"'"$mysqlPass"'"';'
endReturn -o $? "Creating database user \"${mysqlUser}\" failed";
exe mysql -u root -e 'GRANT ALL PRIVILEGES ON '$mysqlDatabase'.* TO '"'"$mysqlUser"'"'@'"'"'localhost'"'"';'
endReturn -o $? "Granting privileges for user \"${mysqlUser}\" failed";
exe mysql -u root -e 'FLUSH PRIVILEGES;'
} }
step_5_info() { echo "$toolName configuration"; } step_5_info() { echo "Create mysql database for $toolName"; }
step_5() { step_5() {
exe cd $toolPath exe ${seq_origin:?}/mysql.sh createdb -c utf8mb4
}
step_6_info() { echo "$toolName configuration"; }
step_6() {
exe cd "${toolPath:?}"
exe cp .env.example .env exe cp .env.example .env
exe read -p "Edit database settings, hostname, email settings, IMAGE_DRIVER=imagick, etc... (Enter to continue)" exe read -p "Edit database settings, hostname, email settings, IMAGE_DRIVER=imagick, etc... (Enter to continue)"
exe vi .env exe vi .env
exe php artisan key:generate exe ${sq_phpName:?} artisan key:generate
exe php artisan config:cache exe ${sq_phpName:?} artisan config:cache
exe php artisan storage:link exe ${sq_phpName:?} artisan storage:link
exe php artisan migrate --force exe ${sq_phpName:?} artisan migrate --force
exe php artisan route:cache exe ${sq_phpName:?} artisan route:cache
# Needed for using oauth (app like pixeldroid) # Needed for using oauth (app like pixeldroid)
# https://github.com/pixelfed/pixelfed/issues/2654 # https://github.com/pixelfed/pixelfed/issues/2654
exe php artisan passport:install exe ${sq_phpName:?} artisan passport:install
} }
step_6_info() { echo "Create admin user"; } step_7_info() { echo "Create admin user"; }
step_6() {
exe cd $toolPath
exe read -p "Create admin user. (Enter to continue)"
exe php artisan user:create
}
step_7_info() { echo "Create pixelfed (horzion) service"; }
step_7() { step_7() {
exe cd "${toolPath:?}"
exe read -p "Create admin user. (Enter to continue)"
exe ${sq_phpName:?} artisan user:create
}
step_8_info() { echo "Create pixelfed (horzion) service"; }
step_8() {
addConf -c "${horizonService}" "${horizonServiceLoc}" addConf -c "${horizonService}" "${horizonServiceLoc}"
endReturn -o $? "Failed to add horizon service" endReturn "Failed to add horizon service"
exe systemctl daemon-reload exe systemctl daemon-reload
exe systemctl enable pixelfed.service exe systemctl enable pixelfed.service
exe service pixelfed start exe service pixelfed start
@@ -117,28 +125,31 @@ RestartSec=2s
Type=simple Type=simple
User=www-data User=www-data
Group=www-data Group=www-data
WorkingDirectory=${toolPath}/ WorkingDirectory=${toolPath:?}/
ExecStart=/usr/bin/php ${toolPath}/artisan horizon ExecStart=/usr/bin/php ${toolPath:?}/artisan horizon
Restart=always Restart=always
Environment= Environment=
[Install] [Install]
WantedBy=multi-user.target" WantedBy=multi-user.target"
step_8_info() { echo "Create scheduler cron job"; } step_9_info() { echo "Create scheduler cron job"; }
step_8_alias() { ALIAS="scheduler"; } step_9_alias() { echo "scheduler"; }
step_8() { step_9() {
local schedulerCron="/etc/cron.d/pixelfedScheduler"
local schedulerCmd="* * * * * cd $(escpath ${toolPath}) && ${sq_phpName:?} artisan schedule:run >>/dev/null 2>&1"
addConf -s "$schedulerCmd" "$schedulerCron" addConf -s "$schedulerCmd" "$schedulerCron"
} }
schedulerCron="/etc/cron.d/pixelfedScheduler"
schedulerCmd="* * * * * cd ${toolPath} && php artisan schedule:run >>/dev/null 2>&1"
step_9_info() { echo "Nginx configuration"; } step_10_info() { echo "Nginx configuration"; }
step_9() { step_10() {
addConf -c "$nginxConfig" "$nginxConfigLoc" lNginxConfig="$(eval echo "${nginxConfig}")"
addConf -c "$lNginxConfig" "$nginxConfigLoc"
exe ln -s "$nginxConfigLoc" "$nginxConfigEnable" exe ln -s "$nginxConfigLoc" "$nginxConfigEnable"
exe nginx -t exe nginx -t
endReturn -o $? "Nginx configuration check error" endReturn "Nginx configuration check error"
exe service nginx restart exe service nginx restart
} }
@@ -146,7 +157,7 @@ nginxConfigLoc="/etc/nginx/sites-available/pixelfed"
nginxConfigEnable="/etc/nginx/sites-enabled/pixelfed" nginxConfigEnable="/etc/nginx/sites-enabled/pixelfed"
nginxConfig="\ nginxConfig="\
upstream php-handler-pixel { upstream php-handler-pixel {
server unix:/var/run/php/php7.3-fpm.sock; server unix:/var/run/php/${sq_phpName:?}-fpm.sock;
} }
map \$http_x_forwarded_proto \$proxy_https { map \$http_x_forwarded_proto \$proxy_https {
@@ -197,25 +208,25 @@ location ~ /\\.(?!well-known).* {
}" }"
step_20_info() { echo "Reload configuration (.env)"; } step_20_info() { echo "Reload configuration (.env)"; }
step_20_alias() { ALIAS="newenv"; } step_20_alias() { echo "newenv"; }
step_20() { step_20() {
exe cd $toolPath exe cd ${toolPath:?}
exe php artisan config:cache exe sudo -u www-data ${sq_phpName:?} artisan config:cache
exe service pixelfed restart exe service pixelfed restart
} }
step_22_info() { echo "Create new user"; } step_22_info() { echo "Create new user"; }
step_22_alias() { ALIAS="createuser"; } step_22_alias() { echo "createuser"; }
step_22() { step_22() {
exe cd $toolPath exe cd ${toolPath:?}
exe php artisan user:create exe ${sq_phpName:?} artisan user:create
} }
step_24_info() { echo "Checkout to dev branch. Losing local changes!"; } step_24_info() { echo "Checkout to dev branch. Losing local changes!"; }
step_24_alias() { ALIAS="forcedev"; } step_24_alias() { echo "forcedev"; }
step_24() { step_24() {
exe read -p "Are you sure: y/[n]? " answer exe read -p "Are you sure: y/[n]? " answer
if [ $DRY -eq 0 ] ; then if ! dry ; then
case $answer in case $answer in
[yY]) [yY])
;; ;;
@@ -224,7 +235,7 @@ step_24() {
;; ;;
esac esac
fi fi
exe cd $toolPath exe cd ${toolPath:?}
exe git fetch --all exe git fetch --all
exe git reset --hard origin/dev exe git reset --hard origin/dev
exe git pull origin dev exe git pull origin dev
@@ -232,47 +243,47 @@ step_24() {
} }
step_100_info() { echo "Upgrade \"${toolPath}\" to supported tag $toolTag"; } step_100_info() { echo "Upgrade \"${toolPath}\" to supported tag $toolTag"; }
step_100_alias() { ALIAS="upgrade"; } step_100_alias() { echo "upgrade"; }
step_100() { step_100() {
exe cd $toolPath exe cd ${toolPath:?}
exe git pull origin $toolTag exe git pull origin $toolTag
endReturn -o $? "git pull failed" endReturn "git pull failed"
exe git checkout $toolTag exe git checkout $toolTag
endReturn -o $? "git checkout failed" endReturn "git checkout failed"
} }
step_101_info() { echo "Recommended post update procedure"; } step_101_info() { echo "Recommended post update procedure"; }
step_101_alias() { ALIAS="postupdate"; } step_101_alias() { echo "postupdate"; }
step_101() { step_101() {
exe cd $toolPath exe cd ${toolPath:?}
exe composer install exe sudo -u www-data ${sq_phpName:?} composer.phar install
exe php artisan config:cache exe sudo -u www-data ${sq_phpName:?} artisan config:cache
exe php artisan route:cache exe sudo -u www-data ${sq_phpName:?} artisan route:cache
exe php artisan view:cache exe sudo -u www-data ${sq_phpName:?} artisan view:cache
exe php artisan cache:clear exe sudo -u www-data ${sq_phpName:?} artisan cache:clear
exe php artisan migrate --force exe sudo -u www-data ${sq_phpName:?} artisan migrate --force
exe php artisan horizon:purge exe sudo -u www-data ${sq_phpName:?} artisan horizon:purge
exe php artisan horizon:publish exe sudo -u www-data ${sq_phpName:?} artisan horizon:publish
exe php artisan storage:link exe sudo -u www-data ${sq_phpName:?} artisan storage:link
exe php artisan instance:actor exe sudo -u www-data ${sq_phpName:?} artisan instance:actor
echo -n " [I] Restarting pixelfed horzion service..." echo -n " [I] Restarting pixelfed horzion service..."
exe service pixelfed restart && echo "ok" exe service pixelfed restart && echo "ok"
} }
# Src: https://docs.pixelfed.org/running-pixelfed/troubleshooting.html # Src: https://docs.pixelfed.org/running-pixelfed/troubleshooting.html
step_102_info() { echo "Fix if horizon services is running but not showing the administration interface"; } step_102_info() { echo "Fix if horizon services is running but not showing the administration interface"; }
step_102_alias() { ALIAS="fixhorizon"; } step_102_alias() { echo "fixhorizon"; }
step_102() { step_102() {
exe cd $toolPath exe cd ${toolPath:?}
exe php artisan package:discover exe sudo -u www-data ${sq_phpName:?} artisan package:discover
exe php artisan horizon:install exe sudo -u www-data ${sq_phpName:?} artisan horizon:install
exe php artisan route:cache exe sudo -u www-data ${sq_phpName:?} artisan route:cache
echo -n " [I] Restarting pixelfed horzion service..." echo -n " [I] Restarting pixelfed horzion service..."
exe service pixelfed restart && echo "ok" exe service pixelfed restart && echo "ok"
} }
# Sequence Revision # Sequence Revision
VERSION_SEQREV=7 readonly sqr_minVersion=16
# Path to sequencer # Path to sequencer
. sequencer.sh . sequencer.sh

View File

@@ -6,4 +6,4 @@ PFA_SRV_LOC="/srv/postfixadmin"
PFA_WEB_LOC="/var/www/pfa" PFA_WEB_LOC="/var/www/pfa"
PFA_DATABASE="pfa_db" PFA_DATABASE="pfa_db"
PFA_BACKUP="/root/backup/pfa" PFA_BACKUP="/root/backup/pfa"
PFA_PHP_VERSION="7.3" PFA_PHP_VERSION="8.1"

View File

@@ -1,64 +1,59 @@
#!/bin/bash #!/usr/bin/env bash
toolName=postfixadmin readonly toolName=postfixadmin
toolPhpDeps='php${PFA_PHP_VERSION}-fpm php${PFA_PHP_VERSION}-imap php${PFA_PHP_VERSION}-mbstring php${PFA_PHP_VERSION}-mysql php${PFA_PHP_VERSION}-json php${PFA_PHP_VERSION}-curl php${PFA_PHP_VERSION}-zip php${PFA_PHP_VERSION}-xml php${PFA_PHP_VERSION}-bz2 php${PFA_PHP_VERSION}-intl php${PFA_PHP_VERSION}-gmp' # since php8.0 json is always available
toolConfName="config.local.php" readonly toolPhpDeps=(bz2 curl fpm gmp imap intl mbstring mysql xml zip)
toolTemplates="templates_c" readonly toolConfName="config.local.php"
toolTemplatesLoc="$PFA_SRV_LOC/$toolTemplates" readonly toolTemplates="templates_c"
toolAdditionsLoc="$PFA_SRV_LOC/ADDITIONS" readonly latestUrl="https://api.github.com/repos/$toolName/$toolName/releases/latest"
latestUrl="https://api.github.com/repos/$toolName/$toolName/releases/latest" readonly fetchmailUser="fetchmail"
fetchmailUser="fetchmail" readonly fetchmailDeps="fetchmail liblockfile-simple-perl libdbd-mysql-perl"
fetchmailDeps="fetchmail liblockfile-simple-perl"
# Get script working directory toolTemplatesLoc=
# (when called from a different directory) toolAdditionsLoc=
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )" sq_aptOpt=
CONFIG=0 sq_config=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then info "${toolName} path: ${PFA_WEB_LOC:-}"
echo " ${toolName} path: ${PFA_WEB_LOC}" info -a "${toolName} backup: ${PFA_BACKUP:-}"
echo " ${toolName} backup: ${PFA_BACKUP}" info -a " php Version: ${PFA_PHP_VERSION:-}"
echo " php Version: ${PFA_PHP_VERSION}" sq_config=1
CONFIG=1 toolTemplatesLoc="$PFA_SRV_LOC/$toolTemplates"
toolAdditionsLoc="$PFA_SRV_LOC/ADDITIONS"
else
dry || return 1
fi fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Return of non zero value will abort the sequence
return 0
} }
step_1_info() { step_1_info() {
# eval needed to expand sourced configuration variables # eval needed to expand sourced configuration variables
local localDeps=`eval "echo \"$toolPhpDeps\""`
echo "Install $toolName dependencies:" echo "Install $toolName dependencies:"
echoinfo "$localDeps" echoinfo "${toolPhpDeps[@]/#/php${PFA_PHP_VERSION:-}-}"
} }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
# eval needed to expand sourced configuration variables
local localDeps=`eval "echo \"$toolPhpDeps\""`
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
exe apt update exe apt update
exe apt install $localDeps $aptOpt exe apt install "${toolPhpDeps[@]/#/php${PFA_PHP_VERSION:?}-}" ${sq_aptOpt:-}
} }
step_2_info() { echo "Install $toolName to $PFA_SRV_LOC"; } step_2_info() { echo "Install $toolName to ${PFA_SRV_LOC:-}"; }
step_2() { step_2() {
step upgrade step upgrade
} }
step_3_info() { echo "Install fetchmail"; } step_3_info() { echo "Install fetchmail"; }
step_3_alias() { ALIAS="install_fetchmail"; } step_3_alias() { echo "install_fetchmail"; }
step_3() { step_3() {
local aptOpt= exe apt install $fetchmailDeps ${sq_aptOpt:-}
if [ $QUIET -ne 0 ];then endReturn "Failed to install fetchmail"
aptOpt="-y"
fi
exe apt install $fetchmailDeps $aptOpt
endReturn -o $? "Failed to install fetchmail"
exe systemctl stop fetchmail exe systemctl stop fetchmail
exe systemctl disable fetchmail exe systemctl disable fetchmail
} }
@@ -66,7 +61,7 @@ step_3() {
step_4_info() { echo "Configure postfixadmin to use fetchmail"; } step_4_info() { echo "Configure postfixadmin to use fetchmail"; }
step_4() { step_4() {
echo "# Create mysql config" echo "# Create mysql config"
echo " [$PFA_SRV_LOC/fetchmail.conf]" echo " [/etc/mail/postfixadmin/fetchmail.conf]"
echo " # Follow instructions in $toolAdditionsLoc/fetchmail.pl" echo " # Follow instructions in $toolAdditionsLoc/fetchmail.pl"
echo " \$db_type = 'mysql';" echo " \$db_type = 'mysql';"
echo " \$run_dir=\"/var/lock\";" echo " \$run_dir=\"/var/lock\";"
@@ -74,14 +69,14 @@ step_4() {
echo " [$toolAdditionsLoc/fetchmail.pl]" echo " [$toolAdditionsLoc/fetchmail.pl]"
echo " # Change path to fetchmail.conf (see above)" echo " # Change path to fetchmail.conf (see above)"
echo echo
echo " [I] Run step \"timer\" when configuration is done" info "Run step \"timer\" when configuration is done"
} }
step_6_info() { step_6_info() {
echo "Create postfixadmin fetchmail systemd timer and reduce syslog entries" echo "Create postfixadmin fetchmail systemd timer and reduce syslog entries"
echoinfo "Needs to start after the mysql service" echoinfo "Needs to start after the mysql service"
} }
step_6_alias() { ALIAS="timer"; } step_6_alias() { echo "timer"; }
step_6() { step_6() {
# eval needed to expand sourced configuration variables # eval needed to expand sourced configuration variables
local localService=`eval "echo \"$fetchPluginService\""` local localService=`eval "echo \"$fetchPluginService\""`
@@ -123,10 +118,10 @@ fetchPluginRsyslog="if \$programname == 'systemd' and re_match(\$msg, \"Started.
if \$programname == 'systemd' and re_match(\$msg, \"fetchmail.*Succeeded\") then stop" if \$programname == 'systemd' and re_match(\$msg, \"fetchmail.*Succeeded\") then stop"
step_7_info() { echo "Create separate log file for fetchmail using rsyslog"; } step_7_info() { echo "Create separate log file for fetchmail using rsyslog"; }
step_7_alias() { ALIAS="newlog"; } step_7_alias() { echo "newlog"; }
step_7() { step_7() {
addConf -f "$fetchmailRsyslog" "$fetchmailRsyslogLoc" addConf -c "$fetchmailRsyslog" "$fetchmailRsyslogLoc"
addConf -f "$fetchmailRotate" "$fetchmailRotateLoc" addConf -c "$fetchmailRotate" "$fetchmailRotateLoc"
exe service rsyslog restart exe service rsyslog restart
} }
fetchmailLogLoc="/var/log/fetchmail.log" fetchmailLogLoc="/var/log/fetchmail.log"
@@ -143,13 +138,14 @@ fetchmailRsyslogLoc="/etc/rsyslog.d/30-fetchmail.conf"
fetchmailRsyslog="if \$programname == 'fetchmail' or \$programname == 'fetchmail-all' then $fetchmailLogLoc fetchmailRsyslog="if \$programname == 'fetchmail' or \$programname == 'fetchmail-all' then $fetchmailLogLoc
& stop" & stop"
step_18_info() { echoinfoArgs "[NEW VERSION]"; echo "Check for updates"; } step_18_info() { echo "Check for updates"; }
step_18_alias() { ALIAS="updatecheck"; } step_18_options() { echo "[NEW VERSION]"; }
step_18_alias() { echo "updatecheck"; }
step_18() { step_18() {
shift shift
local isInstalled= local isInstalled=
local latestVersion= local latestVersion=
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
latestVersion="$1" latestVersion="$1"
else else
latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "postfixadmin-\K.*?(?=")') latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "postfixadmin-\K.*?(?=")')
@@ -157,55 +153,54 @@ step_18() {
isInstalled=$(grep -E "${latestVersion}" "${PFA_WEB_LOC}/version" >>/dev/null 2>&1 && echo "1" || echo "0") isInstalled=$(grep -E "${latestVersion}" "${PFA_WEB_LOC}/version" >>/dev/null 2>&1 && echo "1" || echo "0")
if [ $isInstalled -eq 1 ] ; then if [ $isInstalled -eq 1 ] ; then
echo " [I] Version $latestVersion is already installed" info "Version $latestVersion is already installed"
return 1 return 1
else else
echo " [I] Update to $latestVersion available" info "Update to $latestVersion available"
fi fi
return 0 return 0
} }
step_20_info() { step_20_info() {
echoinfoArgs "[POSTFIXADMIN SRV ROOT]"
echo -n "Create a backup" echo -n "Create a backup"
if [ $CONFIG -ne 0 ] ; then if [ $sq_config -ne 0 ] ; then
echo " at $PFA_BACKUP" echo " at $PFA_BACKUP"
else else
echo echo
fi fi
} }
step_20_alias() { ALIAS="backup"; } step_20_options() { echo "[POSTFIXADMIN SRV ROOT]"; }
step_20_alias() { echo "backup"; }
step_20() { step_20() {
shift shift
local tempRoot= local tempRoot=
if [ $CONFIG -eq 0 ] ; then if [ $sq_config -eq 0 ] ; then
echoerr " [E] No configuration file found" error -e "No configuration file found"
return 1 return 1
fi fi
if [ ! -z $PFA_BACKUP ] ; then if [ ! -z $PFA_BACKUP ] ; then
exe mkdir -p "$PFA_BACKUP" exe mkdir -p "$PFA_BACKUP"
fi fi
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
tempRoot="$1" tempRoot="$1"
else else
tempRoot="$PFA_SRV_LOC" tempRoot="$PFA_SRV_LOC"
fi fi
local srvBackup="$PFA_BACKUP/${toolName}_`date +%Y%m%d-%H%M%S`.tar.gz" local srvBackup="$PFA_BACKUP/${toolName}_`date +%Y%m%d-%H%M%S`.tar.gz"
echo " [I] Backing up server directory to $srvBackup" info "Backing up server directory to $srvBackup"
exe cd "$tempRoot/.." exe cd "$tempRoot/.."
exe tar czf "$srvBackup" $(basename "$tempRoot") exe tar czf "$srvBackup" $(basename "$tempRoot")
exe $WDIR/mysql.sh -qq backup "$PFA_DATABASE" "$PFA_BACKUP" exe ${seq_origin:?}/mysql.sh -qq backup "$PFA_DATABASE" "$PFA_BACKUP"
} }
step_22_info() { step_22_info() {
echoinfoArgs "[CUSTOM VERSION]"
shift shift
if [ $CONTEXT_EXE -ne 0 ]; then if contextExe; then
echoinfo -n "Upgrade to version " echoinfo -n "Upgrade to version "
if [ -z "$1" ]; then if [ -z "${1:-}" ]; then
echo -n "$(curl --silent "$latestUrl" | grep -Po '"tag_name": "postfixadmin-\K.*?(?=")')" echo -n "$(curl --silent "$latestUrl" | grep -Po '"tag_name": "postfixadmin-\K.*?(?=")')"
else else
echo -n "$1" echo -n "$1"
@@ -215,27 +210,28 @@ step_22_info() {
echo "Upgrade to latest or a custom version from github" echo "Upgrade to latest or a custom version from github"
fi fi
} }
step_22_alias() { ALIAS="upgrade"; } step_22_options() { echo "[CUSTOM VERSION]"; }
step_22_alias() { echo "upgrade"; }
step_22() { step_22() {
shift # don't need step number shift # don't need step number
local latestVersion= local latestVersion=
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
latestVersion="$1" latestVersion="$1"
else else
latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "postfixadmin-\K.*?(?=")') latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "postfixadmin-\K.*?(?=")')
fi fi
if [ -z $latestVersion ] ; then if [ -z $latestVersion ] ; then
echoerr " [E] Cannot determine latest version from github repository" error -e "Cannot determine latest version from github repository"
return 1 return 1
elif [ $QUIET -eq 0 ] ; then elif interactive ; then
echo echo
exe read -p "Install $latestVersion to $PFA_SRV_LOC [n]o/(y)es? " answer exe read -p "Install $latestVersion to $PFA_SRV_LOC [n]o/(y)es? " answer
case $answer in case $answer in
[yY]) [yY])
;; ;;
*) *)
echoerr " [I] Upgrade aborted" info -e "Upgrade aborted"
return 1 return 1
;; ;;
esac esac
@@ -245,7 +241,7 @@ step_22() {
# Trailing ".0" is removed if exists # Trailing ".0" is removed if exists
local isInstalled=$(grep -E "Version ${latestVersion%.0} " "${PFA_SRV_LOC}/CHANGELOG.TXT" >>/dev/null 2>&1 && echo "1" || echo "0") local isInstalled=$(grep -E "Version ${latestVersion%.0} " "${PFA_SRV_LOC}/CHANGELOG.TXT" >>/dev/null 2>&1 && echo "1" || echo "0")
if [ $isInstalled -eq 1 ] ; then if [ $isInstalled -eq 1 ] ; then
echoerr " [E] Version $latestVersion is already installed" error -e "Version $latestVersion is already installed"
return 2 return 2
fi fi
@@ -256,12 +252,12 @@ step_22() {
if [ ! -e "$tempExtract" ] ; then if [ ! -e "$tempExtract" ] ; then
exe mkdir -p "$tempDown" exe mkdir -p "$tempDown"
exe wget -O "$tempLoc" $downUrl exe wget -O "$tempLoc" $downUrl
endReturn -o $? "Download failed: $downUrl" endReturn "Download failed: $downUrl"
exe cd "$tempDown" exe cd "$tempDown"
exe tar -xf "$tempLoc" exe tar -xf "$tempLoc"
endReturn -o $? "Extract failed: $tempLoc" endReturn "Extract failed: $tempLoc"
else else
echo " [I] Found existing download: $tempExtract" info "Found existing download: $tempExtract"
fi fi
# Installation # Installation
@@ -270,12 +266,12 @@ step_22() {
if [ -e "$PFA_SRV_LOC" ] ; then if [ -e "$PFA_SRV_LOC" ] ; then
exe mv "$PFA_SRV_LOC" "$tempBu" exe mv "$PFA_SRV_LOC" "$tempBu"
step backup "$tempBu" step backup "$tempBu"
endReturn -o $? "Backup failed; $PFA_SRV_LOC renamed!" endReturn "Backup failed; $PFA_SRV_LOC renamed!"
fi fi
echo " [I] Installing version $latestVersion to $PFA_SRV_LOC" info "Installing version $latestVersion to $PFA_SRV_LOC"
exe cp -ar "$tempExtract" "$PFA_SRV_LOC" exe cp -ar "$tempExtract" "$PFA_SRV_LOC"
exe mkdir -p $(dirname "$PFA_WEB_LOC") exe mkdir -p $(dirname "$PFA_WEB_LOC")
echo " [I] Create symlink to $PFA_WEB_LOC" info "Create symlink to $PFA_WEB_LOC"
exe ln -fs "$PFA_SRV_LOC/public" "$PFA_WEB_LOC" exe ln -fs "$PFA_SRV_LOC/public" "$PFA_WEB_LOC"
# Setting file permissions # Setting file permissions
@@ -284,20 +280,20 @@ step_22() {
# Configuration # Configuration
local webConf="$tempBu/$toolConfName" local webConf="$tempBu/$toolConfName"
if [ -e "$webConf" ] ; then if [ -e "$webConf" ] ; then
echo " [I] Copying configuration" info "Copying configuration"
exe cp -ar "$webConf" "$PFA_SRV_LOC/" exe cp -ar "$webConf" "$PFA_SRV_LOC/"
else else
echo " [I] Creating empty configuration file $PFA_SRV_LOC/$toolConfName" info "Creating empty configuration file $PFA_SRV_LOC/$toolConfName"
exep "echo -e \"# Created gy $WDIR/$(basename $0)\\n\\n# Changeme\" > \"$PFA_SRV_LOC/$toolConfName\"" exep "echo -e \"# Created by ${seq_origin:?}/$(basename $0)\\n\\n# Changeme\" > \"$PFA_SRV_LOC/$toolConfName\""
fi fi
# Templates # Templates
local templatesLoc="$tempBu/$toolTemplates" local templatesLoc="$tempBu/$toolTemplates"
if [ -e "$templatesLoc" ] ; then if [ -e "$templatesLoc" ] ; then
echo " [I] Copying $toolTemplates" info "Copying $toolTemplates"
exe cp -ar "$templatesLoc" "$toolTemplatesLoc" exe cp -ar "$templatesLoc" "$toolTemplatesLoc"
else else
echo " [I] Creating empty directory $toolTemplatesLoc" info "Creating empty directory $toolTemplatesLoc"
exe mkdir -p "$toolTemplatesLoc" exe mkdir -p "$toolTemplatesLoc"
exe chown -R www-data: "$toolTemplatesLoc" exe chown -R www-data: "$toolTemplatesLoc"
fi fi
@@ -308,21 +304,23 @@ tempDown="/tmp/${toolName}"
tempLoc="$tempDown/${toolName}.tar.gz" tempLoc="$tempDown/${toolName}.tar.gz"
step_23_info() { echo "Clean temporary files: $tempDown"; } step_23_info() { echo "Clean temporary files: $tempDown"; }
step_23_alias() { ALIAS="clean"; } step_23_alias() { echo "clean"; }
step_23() { step_23() {
exe rm -rf "$tempDown" exe rm -rf "$tempDown"
} }
step_100_info() { step_100_info() {
echoinfoArgs "[OPTIONS]"
echo "Execute $toolName client script" echo "Execute $toolName client script"
echoinfo "[OPTIONS] are passed on to $toolName-cli unmodified" echoinfo "[OPTIONS] are passed on to $toolName-cli unmodified"
} }
step_100_alias() { ALIAS="cli"; } step_100_options() { echo "[OPTIONS]"; }
step_100_alias() { echo "cli"; }
step_100() { step_100() {
shift shift
exe ${PFA_SRV_LOC}/scripts/$toolName-cli $@ exe ${PFA_SRV_LOC}/scripts/$toolName-cli $@
} }
VERSION_SEQREV=14 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,48 +1,74 @@
#!/bin/bash #!/bin/bash
toolName=postgres readonly toolName=postgres
toolDeps=postgresql readonly toolDeps=postgresql
toolUser=postgres readonly toolUser=postgres
sq_repoUrl="http://apt.postgresql.org/pub/repos/apt"
sq_keyUrl="https://www.postgresql.org/media/keys/ACCC4CF8.asc"
sq_aptOpt=
# Needed for different steps # Needed for different steps
postgresDb="" postgresDb=""
postgresUser="" postgresUser=""
postgresPass="" postgresPass=""
# Get script working directory seq_config() {
# (when called from a different directory) if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )" # End if no configuration file exists
CONFIG=0 dry || return 1
CONFIG_FILE_NAME="postgres.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
fi fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
return 0
} }
step_1_info() { echo "Installing $toolName dependencies"; } step_1_info() { echo "Status"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "status"; }
step_1() { step_1() {
local aptOption= exe apt policy postgresql
exe apt update
endReturn -o $? "Updating apt repositories failed"
if [ $QUIET -ne 0 ] ; then
aptOption="-y"
else
aptOption=""
fi
exe apt install $toolDeps $aptOption
} }
step_2_info() { echo "Create postgres database"; } step_10_info() {
step_2_alias() { ALIAS="createdb"; } echo "Setup latest apt source list for ${toolName}:"
step_2() { echoinfo "$sq_repoUrl"
}
step_10_alias() { echo "setup"; }
step_10() {
local lArch=
case $(uname -m) in
aarch64)
lArch=arm64;;
esac
if [[ -n ${lArch:-} ]] ; then
info "Detected processor architecture: ${lArch}"
lArch="[arch=${lArch}]"
fi
info "Installing custom repository prerequisites:"
exe apt update
exe apt install apt-transport-https lsb-release ca-certificates curl ${sq_aptOpt}
info "Setup postgresql repository including gpg key"
exep curl -fsSL ${sq_keyUrl:?} "|" gpg --dearmor -o "/etc/apt/trusted.gpg.d/postgresql-keyring.gpg"
addConf -c "deb ${lArch:-} ${sq_repoUrl:?} $(lsb_release -cs)-pgdg main" "/etc/apt/sources.list.d/postgresql.list"
addConf -es "Package: *\nPin: origin apt.postgresql.org\nPin: release c=main\nPin-Priority: 900" \
/etc/apt/preferences.d/99postgresql
exe apt update
}
step_11_info() { echo "Installing $toolName dependencies"; }
step_11_alias() { echo "install"; }
step_11() {
exe apt update
endReturn "Updating apt repositories failed"
exe apt install $toolDeps ${sq_aptOpt}
}
step_20_info() { echo "Create postgres database"; }
step_20_alias() { echo "createdb"; }
step_20() {
readDatabaseInfos readDatabaseInfos
exe cd ~postgres exe cd ~postgres
@@ -51,12 +77,13 @@ step_2() {
exe su ${toolUser} -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE \"${postgresDb}\" to ${postgresUser};\"" exe su ${toolUser} -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE \"${postgresDb}\" to ${postgresUser};\""
} }
step_4_info() { echoinfoArgs "[DATABASE]"; echo "Drop a postgres database"; } step_22_info() { echo "Drop a postgres database"; }
step_4_alias() { ALIAS="dropdb"; } step_22_options() { echo "[DATABASE]"; }
step_4() { step_22_alias() { echo "dropdb"; }
step_22() {
shift shift
local dbname=$1 local dbname=$1
if [ -z $dbname ]; then if [ -z "$dbname" ]; then
readDatabaseInfos readDatabaseInfos
dbname=$postgresDb dbname=$postgresDb
fi fi
@@ -64,12 +91,13 @@ step_4() {
exe su ${toolUser} -c "psql -c \"DROP DATABASE ${dbname};\"" exe su ${toolUser} -c "psql -c \"DROP DATABASE ${dbname};\""
} }
step_6_info() { echoinfoArgs "[DATABASE]"; echo "Size of a postgres database"; } step_24_info() { echo "Size of a postgres database"; }
step_6_alias() { ALIAS="sizedb"; } step_24_options() { echo "[DATABASE]"; }
step_6() { step_24_alias() { echo "sizedb"; }
step_24() {
shift shift
local dbname=$1 local dbname=$1
if [ -z $dbname ]; then if [ -z "$dbname" ]; then
readDatabaseInfos readDatabaseInfos
dbname=$postgresDb dbname=$postgresDb
fi fi
@@ -77,19 +105,20 @@ step_6() {
exe su ${toolUser} -c "psql -c \"SELECT pg_size_pretty( pg_database_size('$dbname') );\"" exe su ${toolUser} -c "psql -c \"SELECT pg_size_pretty( pg_database_size('$dbname') );\""
} }
step_8_info() { echo "List available databases"; } step_26_info() { echo "List available databases"; }
step_8_alias() { ALIAS="listdb"; } step_26_alias() { echo "listdb"; }
step_8() { step_26() {
exe cd ~postgres exe cd ~postgres
exe su ${toolUser} -c "psql -c '\l'" exe su ${toolUser} -c "psql -c '\l'"
} }
step_10_info() { echoinfoArgs "[DATABASE]"; echo "List all tables of a postgres database"; } step_28_info() { echo "List all tables of a postgres database"; }
step_10_alias() { ALIAS="listtables"; } step_28_options() { echo "[DATABASE]"; }
step_10() { step_28_alias() { echo "listtables"; }
step_28() {
shift shift
local dbname=$1 local dbname=$1
if [ -z $dbname ]; then if [ -z "$dbname" ]; then
readDatabaseInfos readDatabaseInfos
dbname=$postgresDb dbname=$postgresDb
fi fi
@@ -97,30 +126,31 @@ step_10() {
exe su ${toolUser} -c "psql -d $dbname -c \"\\dt\"" exe su ${toolUser} -c "psql -d $dbname -c \"\\dt\""
} }
step_20_info() { echoinfoArgs "[DATABASE]"; echo "Backup ${toolName} database"; } step_40_info() { echo "Backup ${toolName} database"; }
step_20_alias() { ALIAS="backupdb"; } step_40_options() { echo "[DATABASE]"; }
step_20() { step_40_alias() { echo "backupdb"; }
step_40() {
shift shift
local dbname=$1 local dbname="$1"
if [ -z $dbname ]; then if [ -z "$dbname" ]; then
readDatabaseInfos readDatabaseInfos
dbname=$postgresDb dbname="$postgresDb"
fi fi
#if [ ! -s ~/.pgpass ] ; then #if [ ! -s ~/.pgpass ] ; then
# echo " [I] For unattended backup please define ~/.pgpass containing credentials" # info "For unattended backup please define ~/.pgpass containing credentials"
# echo " e.g. localhost:5432:database:user:pass" # echo " e.g. localhost:5432:database:user:pass"
#fi #fi
# -Fc custom format # -Fc custom format
#exep "pg_dump -h 127.0.0.1 -U ${postgresUser} -Fc synapse | bzip2 -c > ${toolDbBackupFolder}/`date +%Y-%m-%d\"_\"%H-%M-%S`.backup.bz2" #exep "pg_dump -h 127.0.0.1 -U ${postgresUser} -Fc synapse | bzip2 -c > ${toolDbBackupFolder}/`date +%Y-%m-%d\"_\"%H-%M-%S`.backup.bz2"
exe mkdir -p "$POSTGRES_BACKUP_DIR" exe mkdir -p "$POSTGRES_BACKUP_DIR"
exe cd ~postgres exe cd ~postgres
exep "su ${toolUser} -c \"pg_dump -Fc $dbname\" | bzip2 -c > ${POSTGRES_BACKUP_DIR}/`date +%Y-%m-%d\"_\"%H-%M-%S`_${dbname}.backup.bz2" exep "su ${toolUser} -c \"pg_dump -Fc $dbname\" | bzip2 -c > ${POSTGRES_BACKUP_DIR}/$(date +%Y-%m-%d\"_\"%H-%M-%S)_${dbname}.backup.bz2"
} }
step_22_info() { echo "Postgres database restore"; } step_42_info() { echo "Postgres database restore"; }
step_22_alias() { ALIAS="restoredb"; } step_42_alias() { echo "restoredb"; }
step_22() { step_42() {
echo " [I] Postgres database restore procedure" info "Postgres database restore procedure"
echo "1. Create a empty postgres database first (step 4)" echo "1. Create a empty postgres database first (step 4)"
echo "2. psql -h <host> -U <database user> -d <database name> -W -f <sql dump file>" echo "2. psql -h <host> -U <database user> -d <database name> -W -f <sql dump file>"
echo " e.g. psql -h 127.0.0.1 -U synapse -d synapse -W -f 2018-06-07_18-10-56.sql" echo " e.g. psql -h 127.0.0.1 -U synapse -d synapse -W -f 2018-06-07_18-10-56.sql"
@@ -135,39 +165,47 @@ step_22() {
exe su ${toolUser} -c "psql -c '\du'" exe su ${toolUser} -c "psql -c '\du'"
} }
step_24_info() { step_44_info() {
local DELYEAR=$(($(date +%Y)-2)) local DELYEAR=$(($(date +%Y)-2))
echoinfoArgs "[DATABASE]"
echo "Clean all ${DELYEAR} backups of a database"; echo "Clean all ${DELYEAR} backups of a database";
} }
step_24_alias() { ALIAS="backupclean"; } step_44_options() { echo "[DATABASE]"; }
step_24() { step_44_alias() { echo "backupclean"; }
step_44() {
shift shift
local DELYEAR=$(($(date +%Y)-2)) local DELYEAR=$(($(date +%Y)-2))
local dbname=$1 local dbname=$1
if [ -z $dbname ]; then if [ -z "$dbname" ]; then
readDatabaseInfos readDatabaseInfos
dbname=$postgresDb dbname="$postgresDb"
fi fi
exe rm -f ${POSTGRES_BACKUP_DIR}/${DELYEAR}*${dbname}* exe rm -f "${POSTGRES_BACKUP_DIR}"/"${DELYEAR}"*"${dbname}"*
} }
# Read postgres database information dbname/user/pass if empty # Read postgres database information dbname/user/pass if empty
readDatabaseInfos() { readDatabaseInfos() {
if [ "$postgresDb" == "" ] ; then if [ "$postgresDb" == "" ] ; then
read -p "Enter postgres database name: " postgresDb postgresDb=$(ask "Enter postgres database name: ")
endCheckEmpty postgresDb "database" endIfEmpty postgresDb "database"
fi fi
if [ "$postgresUser" == "" ] ; then if [ "$postgresUser" == "" ] ; then
read -p "Enter postgres user name: " postgresUser postgresUser=$(ask "Enter postgres user name: ")
endCheckEmpty postgresUser "user name" endIfEmpty postgresUser "user name"
fi fi
if [ "$postgresPass" == "" ] ; then if [ "$postgresPass" == "" ] ; then
read -s -p "Enter postgres password: " postgresPass postgresPass=$(ask -s "Enter postgres password: "); echo
endCheckEmpty postgresPass "password" endIfEmpty postgresPass "password"
if [[ ! ${postgresPass} == "$(ask -s "Repeat postgres password: ")" ]] ; then
echo
fatal -e "Passwords don't match"
else
echo
fi
fi fi
echo echo
} }
VERSION_SEQREV=14 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -24,10 +24,10 @@ CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
#} #}
step_1_info() { echo "Install $toolDeps"; } step_1_info() { echo "Install $toolDeps"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local aptOpt= local aptOpt=
if [ $QUIET -ne 0 ];then if quiet;then
aptOpt="-y" aptOpt="-y"
fi fi
exe apt update exe apt update
@@ -38,7 +38,7 @@ step_2_info() {
echo "Add cron to update whitelist_clients from" echo "Add cron to update whitelist_clients from"
echoinfo "$updateUrl" echoinfo "$updateUrl"
} }
step_2_alias() { ALIAS="cron"; } step_2_alias() { echo "cron"; }
step_2() { step_2() {
addConf -s "$postCron" "$postCronLoc" addConf -s "$postCron" "$postCronLoc"
} }
@@ -47,7 +47,7 @@ postCron="# -q quiet -N timestamping (overwrite existing file) -O target file
01 23 5 * * root /usr/bin/wget -qNO \"$toolWhitelistLoc\" $updateUrl && /usr/sbin/service postgrey restart" 01 23 5 * * root /usr/bin/wget -qNO \"$toolWhitelistLoc\" $updateUrl && /usr/sbin/service postgrey restart"
step_3_info() { echo "Configuration notes"; } step_3_info() { echo "Configuration notes"; }
step_3_alias() { ALIAS="notes"; } step_3_alias() { echo "notes"; }
step_3() { step_3() {
echo "$toolNotes" echo "$toolNotes"
} }
@@ -71,10 +71,10 @@ toolNotes="
" "
step_10_info() { echo "Restart $toolName"; } step_10_info() { echo "Restart $toolName"; }
step_10_alias() { ALIAS="restart"; } step_10_alias() { echo "restart"; }
step_10() { step_10() {
exe service $toolName restart exe service $toolName restart
} }
VERSION_SEQREV=11 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
sc_pyloadUser="pyload"
sc_pyloadHome="/home/pyload"
sc_pyloadDir="/opt/pyload" # Place for the venv

110
seqs/pyload-ng.sh Executable file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/env bash
readonly toolName=pyload
readonly toolDeps=(python3 python3-pip python3-pil python3-openssl libcurl4-openssl-dev libssl-dev p7zip ffmpeg tesseract-ocr)
sq_aptOpt=
sq_config=0
seq_config() {
checkVpn
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
else
# End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Show status"; }
step_1_alias() { echo "status"; }
step_1() {
local version=$(${sc_pyloadDir}/bin/pip list | grep pyload)
info "Status of ${toolName}-ng ${version##p* }"
exe systemctl -n0 status ${toolName}
}
step_10_info() {
echo "Install apt dependencies:";
echoinfo "${toolDeps[@]}";
}
#step_10_options() { echo "[OPTIONS]"; }
step_10_alias() { echo "install"; }
step_10() {
exe apt install "${toolDeps[@]}" ${sq_aptOpt}
}
step_11_info() {
echo "Create virtual python environment.";
}
step_11() {
if [ ! -e "$sc_pyloadDir/bin" ]; then
exe python3 -m venv ${sc_pyloadDir}
endReturn "Creating virtual environment failed"
else
warning "Virtual env. ${sc_pyloadDir} already exists"
fi
exe ${sc_pyloadDir}/bin/pip install --pre pyload-ng[all]
}
step_12_info() { echo "Create system user ${sc_pyloadUser:-'pyload'}"; }
step_12() {
if ! id ${sc_pyloadUser} &>/dev/null; then
exe adduser --home "${sc_pyloadHome:?}" --disabled-password --disabled-login --gecos "" "${sc_pyloadUser:?}"
info "Granting write access to network folder"
exe usermod -aG debian-transmission pyload
else
warning "User ${sc_pyloadUser} already exists"
fi
}
step_13_info() { echo "Create systemd service: ${toolServiceLoc##*/}"; }
step_13() {
local lService=`eval "echo \"$toolService\""`
addConf -c "$lService" "$toolServiceLoc"
exe systemctl daemon-reload
exe systemctl disable "${toolServiceLoc##*/}"
}
toolServiceLoc="/etc/systemd/system/pyload.service"
toolService="[Unit]
Description=Python Downloader
After=network-online.target nss-lookup.target local-fs.target remote-fs.target
[Service]
User=pyload
ExecStart=\${sc_pyloadDir}/bin/pyload
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target"
step_20_info() { echo "Upgrade ${toolName}"; }
step_20_alias() { echo "upgrade"; }
step_20() {
exe service ${toolName} stop
exe ${sc_pyloadDir}/bin/pip install --upgrade pip
exe ${sc_pyloadDir}/bin/pip install --pre pyload-ng[all] -U
}
checkVpn() {
if ip -br a | grep tun >>/dev/null 2>&1 ; then
[ $? -eq 0 ] && warning "A VPN connection is possibly active. Consider deactivating it befor any apt operation."
fi
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -1,36 +1,27 @@
#!/bin/bash #!/bin/bash
toolName="pyload" readonly toolName="pyload"
toolBranch="stable" readonly toolBranch="stable"
toolDownload="https://github.com/pyload/pyload.git" readonly toolDownload="https://github.com/pyload/pyload.git"
toolDeps="git liblept5 python python-crypto python-pycurl python-imaging python-sleekxmpp tesseract-ocr zip unzip python-openssl libmozjs-24-bin" readonly toolDeps="git liblept5 python python-crypto python-pycurl python-imaging python-sleekxmpp tesseract-ocr zip unzip python-openssl libmozjs-24-bin"
# python-cryptography shall be implemented in future releases and replace pyhton-crypto # python-cryptography shall be implemented in future releases and replace pyhton-crypto
toolDepsDebian="sudo git python-crypto python-pycurl python-pil python-sleekxmpp tesseract-ocr zip unzip pyhton-openssl libmozjs-60-dev" readonly toolDepsDebian="sudo git python-crypto python-pycurl python-pil python-sleekxmpp tesseract-ocr zip unzip pyhton-openssl libmozjs-60-dev"
toolBuildDeps="rar unrar-nonfree" readonly toolBuildDeps="rar unrar-nonfree"
# Get script working directory sq_aptOpt=
# (when called from a different directory)
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)"
APTOPT=
CONFIG=0
SCRIPT_NAME=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_NAME%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
if [ $? -eq 0 ] ; then
CONFIG=1
else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return 1 dry || return 1
fi fi
[ $QUIET -ne 0 ] && APTOPT="-y"
interactive || sq_aptOpt="-y"
return 0 return 0
} }
step_1_info() { echo "Apt sources.list check and update"; } step_1_info() { echo "Apt sources.list check and update"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
echo "Make sure you have the \"deb-src\" entry active in your /etc/apt/sources.list" echo "Make sure you have the \"deb-src\" entry active in your /etc/apt/sources.list"
echo "Especially check for \"non-free\"" echo "Especially check for \"non-free\""
@@ -41,38 +32,38 @@ step_1() {
step_2_info() { echo "Install unrar-nonfree from source"; } step_2_info() { echo "Install unrar-nonfree from source"; }
step_2() { step_2() {
exe apt-get build-dep ${toolBuildDeps} $APTOPT exe apt-get build-dep ${toolBuildDeps} ${sq_aptOpt}
exe cd /tmp exe cd /tmp
exe apt-get source -b unrar-nonfree exe apt-get source -b unrar-nonfree
saveReturn $? saveReturn $?
endReturn endReturn
exe dpkg -i unrar_*_armhf.deb exe dpkg -i unrar_*_arm64.deb
exe rm -rf unrar-* exe rm -rf unrar-*
} }
step_3_info() { step_3_info() {
echoinfoArgs "[TARGET]"
echo "Install dependencies" echo "Install dependencies"
echoinfo " [TARGET] (default: raspi)" echoinfo " [TARGET] (default: raspi)"
echoinfo " raspi: Raspberry Pi OS" echoinfo " raspi: Raspberry Pi OS"
echoinfo " debian: Debian" echoinfo " debian: Debian"
} }
step_3_alias() { ALIAS="deps"; } step_3_options() { echo "[TARGET]"; }
step_3_alias() { echo "deps"; }
step_3() { step_3() {
shift shift
local lDeps="$toolDeps" local lDeps="$toolDeps"
case "$1" in case "${1:-}" in
debian) debian)
lDeps="$toolDepsDebian";; lDeps="$toolDepsDebian";;
raspi);; raspi);;
*) *)
echoerr " [E] Unrecognized target" error -e "Unrecognized target"
return 1;; return 1;;
esac esac
exe apt-get install ${lDeps} $APTOPT exe apt-get install ${lDeps} ${sq_aptOpt}
saveReturn $? saveReturn $?
endReturn endReturn
case "$1" in case "${1:-}" in
raspi) raspi)
exe cd /usr/bin exe cd /usr/bin
exe ln -s js24 js;; exe ln -s js24 js;;
@@ -85,7 +76,7 @@ step_3() {
step_4_info() { echo "Get $toolName from $toolDownload and create dedicated user"; } step_4_info() { echo "Get $toolName from $toolDownload and create dedicated user"; }
step_4() { step_4() {
exe git clone -b $toolBranch $toolDownload "$PYL_INSTALL_DIR" exe git clone -b $toolBranch $toolDownload "$PYL_INSTALL_DIR"
endReturn -o $? "Git clone failed" endReturn "Git clone failed"
exe adduser --system --home "$PYL_CONFIG_DIR" "$PYL_USER" exe adduser --system --home "$PYL_CONFIG_DIR" "$PYL_USER"
} }
@@ -115,24 +106,26 @@ ExecStart=/usr/bin/python \${PYL_INSTALL_DIR}/pyLoadCore.py
WantedBy=multi-user.target" WantedBy=multi-user.target"
step_7_info() { echo "Add ufw rules"; } step_7_info() { echo "Add ufw rules"; }
step_7_alias() { ALIAS="ufw"; } step_7_alias() { echo "ufw"; }
step_7() { step_7() {
echoseq " [I] Port 9666 needs to be forwarded to the target machine with ssh" info "Port 9666 needs to be forwarded to the target machine with ssh"
echoseq " ssh -L 9666:localhost:9666 user@host -N" info " ssh -L 9666:localhost:9666 user@host -N"
exe ufw allow in on eth0 to any port 8000 proto tcp comment "pyload webinterface" exe ufw allow in on eth0 to any port 8000 proto tcp comment "pyload webinterface"
exe ufw allow in on eth0 to any port 7227 proto tcp comment "pyload remotes" exe ufw allow in on eth0 to any port 7227 proto tcp comment "pyload remotes"
exe ufw allow out on eth0 to 192.168.23.20 port 5222 proto tcp comment "XMPP Connection" exe ufw allow out on eth0 to 192.168.23.20 port 5222 proto tcp comment "XMPP Connection"
} }
step_10_info() { echo "Upgrade to latest version of branch $toolBranch"; } step_10_info() { echo "Upgrade to latest version of branch $toolBranch"; }
step_10_alias() { ALIAS="upgrade"; } step_10_alias() { echo "upgrade"; }
step_10() { step_10() {
exe service $toolName stop exe service $toolName stop
exe cd "$PYL_INSTALL_DIR" exe cd "$PYL_INSTALL_DIR"
exe git pull exe git pull
echo " [I] Service is not started automatically" info "Service is not started automatically"
echo " Do so manually with: service $toolName start" echo " Do so manually with: service $toolName start"
} }
VERSION_SEQREV=14 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

5
seqs/python.cfg.example Normal file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
readonly sc_pyVersion=3.10
# If empty, configure (for altinstall) uses default value (/usr/local)
readonly sc_pyPrefix= #todo

123
seqs/python.sh Executable file
View File

@@ -0,0 +1,123 @@
#!/usr/bin/env bash
readonly toolName=python
readonly buildDeps=(build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget libbz2-dev)
readonly buildHome="/tmp/pythonbuild"
readonly buildTgz="${buildHome}/py.tgz"
# Already defined by sequencer.sh, but may be overwritten
#readonly seq_configName="${sq_scriptName:?}.cfg"
#readonly seq_configTemplate="${seq_origin:?}/${sq_configName:?}.example"
sq_aptOpt=
sq_config=0
req_pyVersion=
sq_pyVersion=
seq_config() {
## or to use sequencer api with global config file:
if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
# End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo 'Status'; }
step_1_alias() { echo 'status'; }
step_1() {
local pyPath=
if pyPath=$(which "python${sc_pyVersion}") ; then
info "$(python${sc_pyVersion} --version) installed"
info -a "at ($pyPath)"
else
info "${toolName} version ${sc_pyVersion} not installed"
fi
}
step_10_info() { echo 'Setup build environment'; }
step_10_alias() { echo 'buildsetup'; }
step_10() {
exe apt update
exe apt install "${buildDeps[@]}" ${sq_aptOpt}
}
step_11_info() { echo "(Alt)install given version"; }
step_11_options() { echo "[VERSION]"; }
step_11_alias() { echo "altinstall"; }
step_11() {
shift
local downUrl=
local version="${sc_pyVersion:?}"
[ -f "${buildTgz}" ] && return 0
[ -n "${1:-}" ] && version="${1}"
if ! downUrl="$(getSourceUrl "${version}")" ; then
fatal "Could not determine download link for version ${1:-}"
fi
info "Downloading $sq_pyVersion from $downUrl"
exe mkdir -p "${buildHome}"
exe wget -O "${buildTgz}" "${downUrl}"
}
step_12() {
local lPrefix=
[ -z "${sq_pyVersion}" ] && getSourceUrl "${sc_pyVersion}" >>/dev/null
exe cd "${buildHome}"
exe tar xf "${buildTgz}"
exe cd "Python-${sq_pyVersion}"
if [ -n "${sc_pyPrefix}" ] ; then
exe mkdir -p "${sc_pyPrefix}"
endReturn "Couldn't create prefix directory ${sc_pyPrefix}"
lPrefix="--prefix=${sc_pyPrefix}"
fi
exe ./configure --enable-optimizations "${lPrefix}"
}
step_13() {
[ -z "${sq_pyVersion}" ] && getSourceUrl "${sc_pyVersion}" >>/dev/null
exe cd "${buildHome}/Python-${sq_pyVersion}"
# Leave one processor for other tasks
exe make -j 3
}
step_14() {
local lInstall="altinstall"
[ -z "${sq_pyVersion}" ] && getSourceUrl "${sc_pyVersion}" >>/dev/null
exe cd "${buildHome}/Python-${sq_pyVersion}"
[ -n "${sc_pyPrefix}" ] && lInstall="install"
exe make "${lInstall}"
}
# getSourceUrl <VERSION>
# <VERSION> : can be only the major version or more specific
#
# Get the download URL for the latest .tgz file for the given version.
#
# Examples (all valid):
# getSourceUrl 3
# getSourceUrl 3.10
# getSourceUrl 3.10.8
getSourceUrl() {
[[ ${1:-} =~ ^[0-9\.]+$ ]] || return 1
local downUrl=
downUrl="$(curl --silent -L "https://www.python.org/downloads/source/" | \
grep --max-count 1 -Po "href=\"\K.*Python-${1//./\\.}.*?(?=\")")"
[[ -z "${downUrl}" ]] && return 1
sq_pyVersion="$(grep -Po "python/\K.*?(?=/)" <<<"${downUrl}")"
echo "${downUrl}"
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -13,14 +13,14 @@ osName=
distName= distName=
RPI_BOOT_CONFIG="/boot/config.txt" RPI_BOOT_CONFIG="/boot/config.txt"
step_config() { seq_config() {
# Shift away args # Shift away args
local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
# Set download url with specified CPU architecture # Set download url with specified CPU architecture
PIDOWNURL="https://downloads.raspberrypi.org/raspios_lite_${PIARCH}_latest" PIDOWNURL="https://downloads.raspberrypi.org/raspios_lite_${PIARCH}_latest"
if [ "$(which lsb_release)" == "" ] ; then if [ "$(which lsb_release)" == "" ] ; then
echoerr " [W] Cannot detect OS. Assuming Ubuntu" warning -e "Cannot detect OS. Assuming Ubuntu"
osName="Ubuntu" osName="Ubuntu"
else else
osName=$(lsb_release -is) osName=$(lsb_release -is)
@@ -28,12 +28,12 @@ step_config() {
fi fi
if [ "$osName" == "" ] ; then if [ "$osName" == "" ] ; then
echoerr " [W] Error dedecting OS. Assuming Ubuntu" warning -e "Error dedecting OS. Assuming Ubuntu"
osName="Ubuntu" osName="Ubuntu"
fi fi
echoseq " Detected OS: $osName $distName" info " Detected OS: $osName $distName"
echoseq " Requested CPU Architecture: $PIARCH" info " Requested CPU Architecture: $PIARCH"
return 0 return 0
} }
@@ -55,10 +55,10 @@ HDSWAPPUUID=
evalArgs() { evalArgs() {
local argCount=0 local argCount=0
for arg in "$@"; do for _ in "$@"; do
case "$1" in case "${1:-}" in
-a|--arch) -a|--arch)
if [ ! -z "$2" ]; then if [ -n "${2:-}" ]; then
PIARCH="$2" PIARCH="$2"
((argCount+=2)) ((argCount+=2))
else else
@@ -78,16 +78,16 @@ step_1_info() {
# Shift away args # Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
echoinfoArgs "[OPTIONS] [SD CARD DEVICE] [HD DEVICE]"
echo "Download latest Raspberry Pi OS lite image $PIARCH" echo "Download latest Raspberry Pi OS lite image $PIARCH"
if [ $CONTEXT_EXE -ne 0 ]; then if contextExe; then
echoinfo "Download URL: $PIDOWNURL" echoinfo "Download URL: $PIDOWNURL"
else else
echoinfo " [OPTIONS]" echoinfo " [OPTIONS]"
echoinfo " -a, --arch : armhf (default), arm64" echoinfo " -a, --arch : armhf (default), arm64"
fi fi
} }
step_1_alias() { ALIAS="setup"; } step_1_options() { echo "[OPTIONS] [SD CARD DEVICE] [HD DEVICE]"; }
step_1_alias() { echo "setup"; }
step_1() { step_1() {
# Shift away args # Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
@@ -97,51 +97,47 @@ step_1() {
echo -ne " [I] sha256 sum of download:\n " echo -ne " [I] sha256 sum of download:\n "
exe sha256sum "$downLoc" exe sha256sum "$downLoc"
fi fi
downImgName="${downDir}/$(zipinfo -1 "$downLoc")" if [ ! -f "$downImgLoc" ] ; then
if [ ! -f "$downImgName" ] ; then exe unxz "$downLoc"
exe unzip "$downLoc" -d "$downDir" endReturn "Unzip raspios image $PIARCH failed"
endReturn -o $? "Unzip raspios image $PIARCH failed"
fi fi
} }
downImgName=""
downDay=$(date +%Y%m%d) downDay=$(date +%Y%m%d)
downDir="/tmp" downDir="/tmp"
downLoc="${downDir}/raspios_$downDay.zip" downImgName="raspios_${downDay}.img"
downImgLoc="${downDir}/${downImgName}"
downLoc="${downDir}/${downImgName}.xz"
step_2_info() { step_2_info() {
# Shift away args # Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
echoinfoArgs "[OPTIONS] [SD CARD DEVICE]"
echo "Write Raspberry Pi OS image to SD card" echo "Write Raspberry Pi OS image to SD card"
echoinfo "This operation will delete all data previously on the SD card!" echoinfo "This operation will delete all data previously on the SD card!"
[ $CONTEXT_EXE -ne 0 ] && [ ! -z $1 ] && echoinfo " [SD CARD DEVICE]: $1" contextExe && [ -n "${1:-}" ] && echoinfo " [SD CARD DEVICE]: $1"
} }
step_2_alias() { ALIAS="writesd"; } step_2_options() { echo "[OPTIONS] [SD CARD DEVICE]"; }
step_2_alias() { echo "writesd"; }
step_2() { step_2() {
# Shift away args # Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
if [ "$downImgName" == "" ] ; then if [ ! -f "$downImgLoc" ] ; then
# called again to make sure $downImgName is populated endReturn -o 1 "Raspios image ${downImgLoc} not found"
step setup
fi
if [ ! -f "$downImgName" ] ; then
endReturn -o 1 "No raspios image found"
fi fi
if [ $(id -u) -ne 0 ] ; then if [ $(id -u) -ne 0 ] ; then
endReturn -o 1 "No root" endReturn -o 1 "No root"
fi fi
read_sd_dev "$1" read_sd_dev "${1:-}"
# check if device was confirmed # check if device was confirmed
if [ $? -ne 0 ] ; then if [ $? -ne 0 ] ; then
endReturn -o 1 "SD card device not found" endReturn -o 1 "SD card device not found"
fi fi
# write image # write image
exe dd bs=8M if="$downImgName" of="$SDDEV" conv=fsync exe dd bs=8M if="$downImgLoc" of="$SDDEV" conv=fsync
endReturn -o "$?" "Writing image to $SDDEV failed" endReturn -o "$?" "Writing image to $SDDEV failed"
exe sync exe sync
@@ -151,7 +147,7 @@ step_2() {
SDROOT="" SDROOT=""
# TODO ? automatic remount # TODO ? automatic remount
echoerr " [W] Please remove SD now and plug it back in." warning -e "Please remove SD now and plug it back in."
exe read -p " Press enter to contiue." exe read -p " Press enter to contiue."
} }
@@ -159,18 +155,19 @@ step_3_info() {
# Shift away args # Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
echoinfoArgs "[SD CARD DEVICE]"
echo "Prepare SD for first run" echo "Prepare SD for first run"
if [ $CONTEXT_EXE -ne 0 ]; then if contextExe; then
[ ! -z $1 ] && echoinfo " [SD CARD DEVICE]: $1" [ -n "${1:-}" ] && echoinfo " [SD CARD DEVICE]: $1"
fi fi
} }
step_3_options() { echo "[SD CARD DEVICE]"; }
step_3() { step_3() {
# Shift away args # Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
if [ -z $1 ] && [ ! -z $SDDEV ] ; then
if [ $QUIET -ne 0 ] ; then if [ -z "${1:-}" ] && [ -n "${SDDEV:-}" ] ; then
if quiet ; then
answer="n" answer="n"
else else
exe lsblk -p "$SDDEV" exe lsblk -p "$SDDEV"
@@ -188,20 +185,32 @@ step_3() {
esac esac
fi fi
read_sd_dev "$1" read_sd_dev "${1:-}"
endReturn -o $? "SD card device not found" endReturn "SD card device not found"
if [ ! -w "$SDBOOT" ] ; then if [ ! -w "$SDBOOT" ] ; then
echoerr " [E] SD card boot partion not writeable" error -e "SD card boot partion not writeable"
return 1 return 1
fi fi
# setup initial user
local lUser="$(ask -- "Username:")"
local lPass
lPass="$(ask -s -- "Password:")"; echo
if ! [[ ${lPass} == "$(ask -s -- "Repeat Password:")" ]] ; then
sqr::echo
fatal "Password missmatch"
fi
local lPass="$(echo "${lPass}" | openssl passwd -6 -stdin)"; echo
addConf -c "${lUser}:${lPass}" "${SDBOOT}/userconf"
unset "lUser" "lPass"
# enable systemd ssh service # enable systemd ssh service
echo " [I] Enable SSH access" info "Enable SSH access"
exe touch "$SDBOOT"/ssh exe touch "$SDBOOT"/ssh
# save SD boot settings for easy emergency start from SD # save SD boot settings for easy emergency start from SD
echo " [I] Save SD card boot information for later use" info "Save SD card boot information for later use"
exe cp -ar "$SDBOOT"/cmdline.txt "$SDBOOT"/cmdline.txt.sd exe cp -ar "$SDBOOT"/cmdline.txt "$SDBOOT"/cmdline.txt.sd
exe cp -ar "$SDROOT"/etc/fstab "$SDROOT"/etc/fstab.sd exe cp -ar "$SDROOT"/etc/fstab "$SDROOT"/etc/fstab.sd
} }
@@ -210,26 +219,26 @@ step_4_info() {
# Shift away args # Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
echoinfoArgs "[SD CARD DEVICE] [HD DEVICE]"
echo "Prepare SD card to boot from hard disk" echo "Prepare SD card to boot from hard disk"
if [ $CONTEXT_EXE -ne 0 ]; then if contextExe; then
[ ! -z $1 ] && echoinfo " [SD CARD DEVICE]: $1" [ -n "${1:-}" ] && echoinfo " [SD CARD DEVICE]: $1"
[ ! -z $2 ] && echoinfo " [HD DEVICE]: $2" [ -n "${2:-}" ] && echoinfo " [HD DEVICE]: $2"
fi fi
} }
step_4_alias() { ALIAS="hdboot"; } step_4_options() { echo "[SD CARD DEVICE] [HD DEVICE]"; }
step_4_alias() { echo "hdboot"; }
step_4() { step_4() {
# Shift away args # Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
read_sd_dev "$1" read_sd_dev "${1:-}"
endReturn -o $? "SD detection error $?" endReturn "SD detection error $?"
read_hd_dev "$2" read_hd_dev "${2:-}"
endReturn -o $? "HD detection error" endReturn "HD detection error"
echo " [I] SD: $SDDEV" info "SD: $SDDEV"
echo " $SDBOOT [$SDBOOTPUUID]" echo " $SDBOOT [$SDBOOTPUUID]"
echo " $SDROOT [$SDROOTPUUID]" echo " $SDROOT [$SDROOTPUUID]"
echo " [I] HD: $HDDEV" info "HD: $HDDEV"
echo " $HDROOT [$HDROOTPUUID]" echo " $HDROOT [$HDROOTPUUID]"
echo " $HDSWAP [$HDSWAPPUUID]" echo " $HDSWAP [$HDSWAPPUUID]"
echo echo
@@ -261,10 +270,10 @@ step_4() {
echo echo
# Resize second partition of SD to max. possible size # Resize second partition of SD to max. possible size
echo " [I] Resize root partion of SD: ${SDROOT} " info "Resize root partion of SD: ${SDROOT} "
step resizesd "$SDDEV" step resizesd "$SDDEV"
if [ $? -ne 0 ] ; then if [ $? -ne 0 ] ; then
echoerr " [W] Something seems to have failed during resize" warning -e "Something seems to have failed during resize"
else else
# Disable init script to resize SD # Disable init script to resize SD
echo -n " [I] remove \"init=\" part from $SDBOOT/cmdline.txt.sd" echo -n " [I] remove \"init=\" part from $SDBOOT/cmdline.txt.sd"
@@ -281,46 +290,46 @@ step_5_info() {
# Shift away args # Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
echoinfoArgs "[SD CARD DEVICE] [HD DEVICE]"
echo "Prepare HD for boot (TODO)" echo "Prepare HD for boot (TODO)"
if [ $CONTEXT_EXE -ne 0 ]; then if contextExe; then
[ ! -z $1 ] && echoinfo " [SD CARD DEVICE]: $1" [ -n "${1:-}" ] && echoinfo " [SD CARD DEVICE]: $1"
[ ! -z $2 ] && echoinfo " [HD DEVICE]: $2" [ -n "${2:-}" ] && echoinfo " [HD DEVICE]: $2"
fi fi
} }
step_5_options() { echo "[SD CARD DEVICE] [HD DEVICE]"; }
step_5() { step_5() {
# Shift away args # Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $? shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
#TODO #TODO
echoerr " [E] Not ready yet...TODO" error -e "Not ready yet...TODO"
#return 1 #return 1
read_sd_dev "$1" read_sd_dev "${1:-}"
endReturn -o $? "SD detection error $?" endReturn "SD detection error $?"
read_hd_dev "$2" read_hd_dev "${2:-}"
endReturn -o $? "HD detection error" endReturn "HD detection error"
echo " [I] SD: $SDDEV" info "SD: $SDDEV"
echo " $SDBOOT [$SDBOOTPUUID]" echo " $SDBOOT [$SDBOOTPUUID]"
echo " $SDROOT [$SDROOTPUUID]" echo " $SDROOT [$SDROOTPUUID]"
echo " [I] HD: $HDDEV" info "HD: $HDDEV"
echo " $HDROOT [$HDROOTPUUID]" echo " $HDROOT [$HDROOTPUUID]"
echo " $HDSWAP [$HDSWAPPUUID]" echo " $HDSWAP [$HDSWAPPUUID]"
echo echo
# TODO how to partition HD # TODO how to partition HD
echo " [I] $HDDEV is expected to be partitioned with root and swap" info "$HDDEV is expected to be partitioned with root and swap"
echo " TODO create a step for partitioning script support?!" echo " TODO create a step for partitioning script support?!"
echo echo
# Initial rsync of system to HD # Initial rsync of system to HD
echo " [I] Clone SD root to HD root:" info "Clone SD root to HD root:"
echo " rsync -avxHAX --numeric-ids --info=stats2 $SDROOT/ $HDROOT/" echo " rsync -avxHAX --numeric-ids --info=stats2 $SDROOT/ $HDROOT/"
echo echo
# Modify fstab on HD for root and swap on HD # Modify fstab on HD for root and swap on HD
echo " [I] modify $HDROOT/etc/fstab" info "modify $HDROOT/etc/fstab"
echo " PARTUUID=$SDBOOTPUUID /boot vfat ro,defaults 0 2" echo " PARTUUID=$SDBOOTPUUID /boot vfat ro,defaults 0 2"
echo " PARTUUID=$SDROOTPUUID /backup ext4 ro,defaults,noatime 0 2" echo " PARTUUID=$SDROOTPUUID /backup ext4 ro,defaults,noatime 0 2"
echo " PARTUUID=$HDROOTPUUID / ext4 defaults,noatime 0 1" echo " PARTUUID=$HDROOTPUUID / ext4 defaults,noatime 0 1"
@@ -328,26 +337,26 @@ step_5() {
echo echo
# etc # etc
echo " [I] modify $HDROOT/etc/dhcpcd.conf for static IPs" info "modify $HDROOT/etc/dhcpcd.conf for static IPs"
} }
read_sd_dev() { read_sd_dev() {
local partExt="" local partExt=""
if [ ! -z "$1" ] ; then if [ -n "${1:-}" ] ; then
SDBOOT= SDBOOT=
SDROOT= SDROOT=
SDROOTDEV= SDROOTDEV=
SDROOTPUUID= SDROOTPUUID=
SDBOOTPUUID= SDBOOTPUUID=
SDDEV="$1" SDDEV="$1"
elif [ -z $SDDEV ] || [ ! -b "$SDDEV" ] ; then elif [ -z "${SDDEV:-}" ] || [ ! -b "$SDDEV" ] ; then
SDDEV= SDDEV=
SDBOOT= SDBOOT=
SDROOT= SDROOT=
SDROOTDEV= SDROOTDEV=
SDBOOTPUUID= SDBOOTPUUID=
SDROOTPUUID= SDROOTPUUID=
echo " [I] Available devices:" info "Available devices:"
echo echo
exe lsblk -p exe lsblk -p
echo echo
@@ -355,7 +364,7 @@ read_sd_dev() {
fi fi
if [ ! -b "$SDDEV" ] ; then if [ ! -b "$SDDEV" ] ; then
echoerr " [I] $SDDEV not a block device" info -e "$SDDEV not a block device"
SDDEV= SDDEV=
return 1 return 1
fi fi
@@ -385,7 +394,7 @@ SDBOOTPARTNO=1
SDROOTPARTNO=2 SDROOTPARTNO=2
read_hd_dev() { read_hd_dev() {
if [ ! -z "$1" ] ; then if [ -n "${1:-}" ] ; then
HDROOT= HDROOT=
HDROOTPUUID= HDROOTPUUID=
HDSWAPPUUID= HDSWAPPUUID=
@@ -394,7 +403,7 @@ read_hd_dev() {
HDROOT= HDROOT=
HDROOTPUUID= HDROOTPUUID=
HDSWAPPUUID= HDSWAPPUUID=
echo " [I] Available devices:" info "Available devices:"
echo echo
exe lsblk -p exe lsblk -p
echo echo
@@ -423,17 +432,17 @@ read_hd_dev() {
} }
step_20_info() { echo "Disable swap file and remove it"; } step_20_info() { echo "Disable swap file and remove it"; }
step_20_alias() { ALIAS="disable_swap"; } step_20_alias() { echo "disable_swap"; }
step_20() { step_20() {
exe swapoff -a exe swapoff -a
exe systemctl disable dphys-swapfile exe systemctl disable dphys-swapfile
exe rm -rf "$rpiSwapFile" exe rm -rf "$rpiSwapFile"
echoerr " [W] Reboot to apply changes" warning -e "Reboot to apply changes"
if [ $QUIET -eq 0 ] ; then if interactive ; then
exe read -p " Reboot now ([n]/y)? " answer exe read -p " Reboot now ([n]/y)? " answer
case $answer in case $answer in
[yY]) [yY])
echoerr " [I] Rebooting now ..." info -e "Rebooting now ..."
exe reboot exe reboot
;; ;;
*) *)
@@ -443,16 +452,17 @@ step_20() {
} }
rpiSwapFile="/var/swap" rpiSwapFile="/var/swap"
step_22_info() { echoinfoArgs "[SD CARD DEVICE]"; echo "Resize second SD card partition"; } step_22_info() { echo "Resize second SD card partition"; }
step_22_alias() { ALIAS="resizesd"; } step_22_options() { echo "[SD CARD DEVICE]"; }
step_22_alias() { echo "resizesd"; }
step_22() { step_22() {
shift shift
read_sd_dev "$1" read_sd_dev "${1:-}"
if [ -z $SDDEV ] || [ "$SDDEV" = "" ] || [ "$SDROOT" == "/" ] ; then if [ -z $SDDEV ] || [ "$SDDEV" = "" ] || [ "$SDROOT" == "/" ] ; then
echoerr " [E] No SD found" error -e "No SD found"
return 1 return 1
fi fi
echo " [I] Device to be resized: $SDROOTDEV" info "Device to be resized: $SDROOTDEV"
exe umount -q "$SDROOT" exe umount -q "$SDROOT"
exe parted -s "$SDDEV" "resizepart $SDROOTPARTNO -1" quit exe parted -s "$SDDEV" "resizepart $SDROOTPARTNO -1" quit
@@ -472,18 +482,18 @@ step_22() {
} }
step_24_info() { step_24_info() {
echoinfoArgs "[OPTION]"
echo "Turn off power LED" echo "Turn off power LED"
echoinfo " [OPTION]" echoinfo " [OPTION]"
echoinfo " -p : Turn off permanentely (/etc/rc.local)" echoinfo " -p : Turn off permanentely (/etc/rc.local)"
} }
step_24_alias() { ALIAS="disable_powerled"; } step_24_options() { echo "[OPTION]"; }
step_24_alias() { echo "disable_powerled"; }
step_24() { step_24() {
exep "${ledOffCmd}" exep "${ledOffCmd}"
if [ ! -z "$2" ] && [ "$2" == "-p" ] ; then if [ ! -z "$2" ] && [ "$2" == "-p" ] ; then
exep "grep \"$ledPowerBright\" $startScript >>/dev/null" exep "grep \"$ledPowerBright\" $startScript >>/dev/null"
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
echo " [I] Power LED brightness already used. Please check $startScript manually for:" info "Power LED brightness already used. Please check $startScript manually for:"
echo " $ledOffCmd" echo " $ledOffCmd"
return 1 return 1
fi fi
@@ -497,13 +507,13 @@ ledPowerBright="/sys/class/leds/led1/brightness"
ledOffCmd="sudo sh -c 'echo 0 > ${ledPowerBright}'" ledOffCmd="sudo sh -c 'echo 0 > ${ledPowerBright}'"
step_26_info() { echo "Restart network without reboot"; } step_26_info() { echo "Restart network without reboot"; }
step_26_alias() { ALIAS="netrestart"; } step_26_alias() { echo "netrestart"; }
step_26() { step_26() {
exep "sudo ip link set eth0 down && sudo ip link set eth0 up" exep "sudo ip link set eth0 down && sudo ip link set eth0 up"
} }
step_28_info() { echo "Disable bluetooth"; } step_28_info() { echo "Disable bluetooth"; }
step_28_alias() { ALIAS="disable_bluetooth"; } step_28_alias() { echo "disable_bluetooth"; }
step_28() { step_28() {
checkBootConfig "$RPI_CONFIG_DTOVERLAY" "$RPI_CONF_DI_BLUETOOTH" checkBootConfig "$RPI_CONFIG_DTOVERLAY" "$RPI_CONF_DI_BLUETOOTH"
[ $? -eq 0 ] && endReturn -o 1 "Bluetooth already disabled" [ $? -eq 0 ] && endReturn -o 1 "Bluetooth already disabled"
@@ -520,26 +530,26 @@ step_29() {
exe systemctl disable bluealsa.service exe systemctl disable bluealsa.service
exe systemctl disable bluetooth.service exe systemctl disable bluetooth.service
echoseq " [I] Consider uninstalling bluetooth software:" info "Consider uninstalling bluetooth software:"
echoseq "apt purge --autoremove -y bluez" info "apt purge --autoremove -y bluez"
echoseq info
echoseq " [W] Reboot to make changes active" warning "Reboot to make changes active"
} }
step_31_info() { echo "Disable Wifi"; } step_31_info() { echo "Disable Wifi"; }
step_31_alias() { ALIAS="disable_wifi"; } step_31_alias() { echo "disable_wifi"; }
step_31() { step_31() {
checkBootConfig "$RPI_CONFIG_DTOVERLAY" "$RPI_CONF_DI_WIFI" checkBootConfig "$RPI_CONFIG_DTOVERLAY" "$RPI_CONF_DI_WIFI"
[ $? -eq 0 ] && endReturn -o 1 "Wifi already disabled" [ $? -eq 0 ] && endReturn -o 1 "Wifi already disabled"
addConf -a "${RPI_CONFIG_DTOVERLAY}=$RPI_CONF_DI_WIFI" "$RPI_BOOT_CONFIG" addConf -a "${RPI_CONFIG_DTOVERLAY}=$RPI_CONF_DI_WIFI" "$RPI_BOOT_CONFIG"
echoseq " [W] Reboot to make changes active" warning "Reboot to make changes active"
} }
step_33_info() { echo "Disable HDMI"; } step_33_info() { echo "Disable HDMI"; }
step_33_alias() { ALIAS="disable_hdmi"; } step_33_alias() { echo "disable_hdmi"; }
step_33() { step_33() {
checkBootConfig "$RPI_CONFIG_HDMI_BLANK" "$RPI_CONF_DI_HDMI" checkBootConfig "$RPI_CONFIG_HDMI_BLANK" "$RPI_CONF_DI_HDMI"
[ $? -eq 0 ] && endReturn -o 1 "HDMI already disabled" [ $? -eq 0 ] && endReturn -o 1 "HDMI already disabled"
@@ -554,7 +564,7 @@ step_34() {
exe $tvserviceOffCmd exe $tvserviceOffCmd
exep "grep \"$tvserviceBin\" $startScript >>/dev/null" exep "grep \"$tvserviceBin\" $startScript >>/dev/null"
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
echo " [I] Tvservice already used. Please check $startScript manually for:" info "Tvservice already used. Please check $startScript manually for:"
echo " $tvserviceOffCmd" echo " $tvserviceOffCmd"
return 1 return 1
fi fi
@@ -563,28 +573,29 @@ step_34() {
exep "echo \"${tvserviceOffCmd}\" >> $startScript" exep "echo \"${tvserviceOffCmd}\" >> $startScript"
exep "echo -e \"\nexit 0\" >> $startScript" exep "echo -e \"\nexit 0\" >> $startScript"
echoseq " [W] Reboot to make changes active" warning "Reboot to make changes active"
} }
tvserviceBin="/usr/bin/tvservice" tvserviceBin="/usr/bin/tvservice"
tvserviceOffCmd="${tvserviceBin} -o'" tvserviceOffCmd="${tvserviceBin} -o'"
# checkBootConfig <CONFIGNAME> [VALUE] # checkBootConfig <CONFIGNAME> [VALUE]
checkBootConfig() { checkBootConfig() {
[ -z "$1" ] && return 1 [ -z "${1:-}" ] && return 1
local re_check="^[[:blank:]]*[^#]*${1}[[:blank:]]*=[[:blank:]]*$2" local re_check="^[[:blank:]]*[^#]*${1}[[:blank:]]*=[[:blank:]]*$2"
grep -rqE "$re_check" "$RPI_BOOT_CONFIG" grep -rqE "$re_check" "$RPI_BOOT_CONFIG"
return $? return $?
} }
step_100_alias() { ALIAS="notes"; } step_100_alias() { echo "notes"; }
step_100() { step_100() {
outColor green color green
cat <<NOTES_EOF cat <<NOTES_EOF
# Initial configuration steps # Initial configuration steps
* Set password for pi (\`passwd\`) * Set password for a user (\`passwd\`)
* Add [\$HOME/.ssh/authorized_keys] * Add [\$HOME/.ssh/authorized_keys]
* Disable auto login (\`raspi-config\` -> System Options -> Boot / Auto Login))
* Set hostname (\`raspi-config\` -> System Options)) * Set hostname (\`raspi-config\` -> System Options))
* Configure Timezone (\`raspi-confg\` -> Localisation Options) * Configure Timezone (\`raspi-confg\` -> Localisation Options)
* Set GPU memory (\`raspi-config\` -> Performance Options) * Set GPU memory (\`raspi-config\` -> Performance Options)
@@ -593,7 +604,7 @@ step_100() {
[/etc/fstab] [/etc/fstab]
> \`PARTUUID=******-03 none swap sw 0 0\` > \`PARTUUID=******-03 none swap sw 0 0\`
\`$SEQ_NAME disable_swap\` \`$seq_name disable_swap\`
* Update system * Update system
@@ -614,5 +625,5 @@ step_100() {
NOTES_EOF NOTES_EOF
} }
VERSION_SEQREV=15 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,38 +1,30 @@
#!/bin/bash #!/bin/bash
toolName=redis readonly toolName=redis
toolDeps=redis-server readonly toolDeps=redis-server
sq_aptOpt=
# Get script working directory seq_config() {
# (when called from a different directory) if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)" # End if no configuration file exists
CONFIG=0 dry || return 1
SCRIPT_NAME=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_NAME%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
fi fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
return 0
} }
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
exe apt update exe apt update
exe apt install $toolDeps $aptOpt exe apt install $toolDeps $sq_aptOpt
} }
step_2_info() { echo "Installation notes"; } step_2_info() { echo "Installation notes"; }
step_2_alias() { ALIAS="notes"; } step_2_alias() { echo "notes"; }
step_2() { step_2() {
cat <<NOTES_EOF cat <<NOTES_EOF
# For php applications make sure php-redis is installed # For php applications make sure php-redis is installed
@@ -65,12 +57,12 @@ NOTES_EOF
} }
step_10_info() { step_10_info() {
echoinfoArgs "[CLI COMMAND]"
echo "Execute redis-cli commands" echo "Execute redis-cli commands"
echoinfo " [CLI COMMAND]" echoinfo " [CLI COMMAND]"
echoinfo " e.g. info" echoinfo " e.g. info"
} }
step_10_alias() { ALIAS="cli"; } step_10_options() { echo "[CLI COMMAND]"; }
step_10_alias() { echo "cli"; }
step_10() { step_10() {
shift shift
local cliCmd="$@" local cliCmd="$@"
@@ -82,5 +74,7 @@ step_10() {
fi fi
} }
VERSION_SEQREV=14 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,43 +1,42 @@
#!/bin/bash #!/bin/bash
toolName=roundcube readonly toolName=roundcube
toolPhpDeps="php\${phpVersion}-gd php-imagick" readonly toolPhpDeps=(curl gd intl ldap mbstring mysql xml zip)
readonly toolDeps="php-imagick"
#https://github.com/roundcube/roundcubemail/releases/latest #https://github.com/roundcube/roundcubemail/releases/latest
latestUrl="https://api.github.com/repos/roundcube/roundcubemail/releases/latest" readonly latestUrl="https://api.github.com/repos/roundcube/roundcubemail/releases/latest"
latestVersion= latestVersion=
tempExtract= tempExtract=
tempInstall= tempInstall=
phpVersion= phpVersion=
# Get script working directory sq_aptOpt=
# (when called from a different directory) sq_config=0
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
## use sequencer api: if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
initSeqConfig -t "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" sq_config=1
if [ $CONFIG -eq 0 ] ; then else
CONFIG=1 # End if no configuration file exists
dry || return 1
fi fi
# Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
# Return of non zero value will abort the sequence
return 0
} }
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
downloadLatest downloadLatest
fetchPhpVersion fetchPhpVersion
if [ ! -z $phpVersion ] ; then if [ -n $phpVersion ] ; then
exe apt update exe apt update
exe apt install `eval echo "$toolPhpDeps"` $aptOpt exe apt install "${toolPhpDeps[@]/#/php${phpVersion:?}-}" ${toolDeps:?} ${sq_aptOpt:-}
fi fi
exe chown -R www-data: "$tempExtract" exe chown -R www-data: "$tempExtract"
@@ -53,7 +52,7 @@ step_2() {
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ] if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
then then
echoerr ' [E] Invalid installer checksum' error -e ' [E] Invalid installer checksum'
exe rm composer-setup.php exe rm composer-setup.php
return 1 return 1
fi fi
@@ -65,22 +64,24 @@ step_2() {
} }
step_3_info() { echo "Configure $toolName"; } step_3_info() { echo "Configure $toolName"; }
step_3_alias() { ALIAS="config"; } step_3_alias() { echo "config"; }
step_3() { step_3() {
echo " [I] Recommended composer packages to be added to \"require\" section:" info "Recommended composer packages to be added to \"require\" section:"
echo ' "melanie2/mobile": "*",' echo ' "alexandregz/twofactor_gauthenticator": "dev-master",'
echo ' "roundcube/carddav": "*",' echo ' "johndoh/contextmenu": "*",'
echo ' "alexandregz/twofactor_gauthenticator": "dev-master"' echo ' "kitist/html5_notifier": "*",'
echo ' "roundcube/carddav": "*"'
exe read -p "Copy the lines above and press Enter to continue." exe read -p "Copy the lines above and press Enter to continue."
exe vi "$RC_LOC/composer.json" exe vi "$RC_LOC/composer.json"
step postupgrade step postupgrade
echo " [I] Generating mysql database $RC_DATABASE" info "Generating mysql database $RC_DATABASE"
echo echo
exe $WDIR/mysql.sh createdb -c utf8mb4 exe ${seq_origin:?}/mysql.sh createdb -c utf8mb4
echo echo
echo " [I] Now visit: http://url-to-roundcube/installer/" info "Now visit: http://url-to-roundcube/installer/"
echo echo
echo " ! Check the database password in $RC_LOC/config/config.inc.php" echo " ! Check the database password in $RC_LOC/config/config.inc.php"
echo " afterwards, the installer may have corrupted some special character" echo " afterwards, the installer may have corrupted some special character"
@@ -89,9 +90,10 @@ step_3() {
} }
step_10_info() { echo "Configuration notes"; } step_10_info() { echo "Configuration notes"; }
step_10_alias() { ALIAS="notes"; } step_10_alias() { echo "notes"; }
step_10() { step_10() {
outColor green fetchPhpVersion
color green
cat <<NOTES_END cat <<NOTES_END
# smtp port if missing after installation # smtp port if missing after installation
[$RC_LOC/config/config.inc.php] [$RC_LOC/config/config.inc.php]
@@ -101,20 +103,10 @@ step_10() {
# Enable two factor auth (installed with step config) for all user # Enable two factor auth (installed with step config) for all user
[$RC_LOC/plugins/twofactor_gauthenticator/config.inc.php] [$RC_LOC/plugins/twofactor_gauthenticator/config.inc.php]
$rcmail_config['users_allowed_2FA'] = array('.*'); \$rcmail_config['users_allowed_2FA'] = array('.*');
# Add mobile skin to roundcube and run step 'postupgrade'.
Don't forget to activate plugins if asked for.
[$RC_LOC/composer.json]
"require": {
...
"mobiledetect/mobiledetectlib": "^2.8",
"roundcube/elastic4mobile": "dev-master"
}
# Install pspell and aspell spell check engine # Install pspell and aspell spell check engine
apt install php7.x-pspell aspell-en aspell-de apt install php${phpVersion}-pspell aspell-en aspell-de
[$RC_LOC/config/config.inc.php] [$RC_LOC/config/config.inc.php]
\$config['spellcheck_engine'] = 'pspell'; \$config['spellcheck_engine'] = 'pspell';
@@ -126,9 +118,9 @@ NOTES_END
} }
step_12_info() { echo "Troubleshooting"; } step_12_info() { echo "Troubleshooting"; }
step_12_alias() { ALIAS="trouble"; } step_12_alias() { echo "trouble"; }
step_12() { step_12() {
outColor green color green
cat <<TROUBLE_END cat <<TROUBLE_END
# On composer update errors. # On composer update errors.
@@ -142,47 +134,45 @@ TROUBLE_END
step_20_info() { step_20_info() {
echo -n "Create a backup" echo -n "Create a backup"
if [ $CONFIG -ne 0 ] ; then if (( ${sq_config} )) ; then
echo " at $RC_BACKUP" echo " at $RC_BACKUP"
else else
echo echo
fi fi
} }
step_20_alias() { ALIAS="backup"; } step_20_alias() { echo "backup"; }
step_20() { step_20() {
if [ $CONFIG -eq 0 ] ; then if [ ${sq_config} -eq 0 ] ; then
echoerr " [E] No configuration file found" error -e "No configuration file found"
return 1 return 1
fi fi
if [ ! -z $RC_BACKUP ] ; then if [ ! -z $RC_BACKUP ] ; then
exe mkdir -p "$RC_BACKUP" exe mkdir -p "$RC_BACKUP"
fi fi
exe $WDIR/mysql.sh -qq backup "$RC_DATABASE" "$RC_BACKUP" exe ${seq_origin:?}/mysql.sh -qq backup "$RC_DATABASE" "$RC_BACKUP"
local wwwBackup="$RC_BACKUP/${toolName}_www_`date +%Y%m%d-%H%M%S`.tar.gz" local wwwBackup="$RC_BACKUP/${toolName}_www_`date +%Y%m%d-%H%M%S`.tar.gz"
echo " [I] Backing up webserver directory to $wwwBackup" info "Backing up webserver directory to $wwwBackup"
exe cd "$RC_LOC/.." exe cd "$RC_LOC/.."
exe tar czf "$wwwBackup" $(basename "$RC_LOC") exe tar czf "$wwwBackup" $(basename "$RC_LOC")
} }
step_22_info() { step_22_info() { echo "Upgrade installation to \"latest\" from github if [CUSTOM_VERSION] is empty"; }
echoinfoArgs "[CUSTOM VERSION]" step_22_options() { echo "[CUSTOM VERSION]"; }
echo "Upgrade installation to \"latest\" from github if [CUSTOM_VERSION] is empty" step_22_alias() { echo "upgrade"; }
}
step_22_alias() { ALIAS="upgrade"; }
step_22() { step_22() {
shift # don't need step number shift # don't need step number
local currentVersion= local currentVersion=
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
latestVersion="$1" latestVersion="$1"
else else
fetchLatestVersion fetchLatestVersion
fi fi
if [ -z $latestVersion ] ; then if [ -z $latestVersion ] ; then
echoerr " [E] Cannot determine latest version from github repository" error -e "Cannot determine latest version from github repository"
return 1 return 1
elif [ $QUIET -eq 0 ] ; then elif interactive ; then
echo echo
currentVersion="$(grep -Po ' \| Version \K.*?(?= )' $RC_LOC/index.php)" currentVersion="$(grep -Po ' \| Version \K.*?(?= )' $RC_LOC/index.php)"
exe read -p "Install $latestVersion over $currentVersion to $RC_LOC [n]o/(y)es? " answer exe read -p "Install $latestVersion over $currentVersion to $RC_LOC [n]o/(y)es? " answer
@@ -190,7 +180,7 @@ step_22() {
[yY]) [yY])
;; ;;
*) *)
echoerr " [I] Upgrade aborted" info -e "Upgrade aborted"
return 1 return 1
;; ;;
esac esac
@@ -198,23 +188,23 @@ step_22() {
local isInstalled=$(grep -E "RELEASE $latestVersion" "${RC_LOC}/CHANGELOG" >>/dev/null && echo "1" || echo "0") local isInstalled=$(grep -E "RELEASE $latestVersion" "${RC_LOC}/CHANGELOG" >>/dev/null && echo "1" || echo "0")
if [ $isInstalled -eq 1 ] ; then if [ $isInstalled -eq 1 ] ; then
echoerr " [E] Version $latestVersion is already installed" error -e "Version $latestVersion is already installed"
return 2 return 2
fi fi
downloadLatest downloadLatest
step backup step backup
echo " [I] Installing version $latestVersion to $RC_LOC" info "Installing version $latestVersion to $RC_LOC"
exe "$tempInstall" "$RC_LOC" exe "$tempInstall" "$RC_LOC"
echo " [I] Make sure to check composer.json-dist file for upstream changes" info "Make sure to check composer.json-dist file for upstream changes"
} }
step_23_info() { echo "Post upgrade procedure"; } step_23_info() { echo "Post upgrade procedure"; }
step_23_alias() { ALIAS="postupgrade"; } step_23_alias() { echo "postupgrade"; }
step_23() { step_23() {
exe cd "$RC_LOC" exe cd "$RC_LOC"
echo " [I] Starting post update procedure" info "Starting post update procedure"
exe php composer.phar update --no-dev exe php composer.phar update --no-dev
} }
@@ -243,16 +233,18 @@ downloadLatest() {
if [ ! -e "$tempExtract" ] ; then if [ ! -e "$tempExtract" ] ; then
exe mkdir -p "$tempDown" exe mkdir -p "$tempDown"
exe wget -O "$tempLoc" $downUrl exe wget -O "$tempLoc" $downUrl
endReturn -o $? "Download failed: $downUrl" endReturn "Download failed: $downUrl"
exe cd "$tempDown" exe cd "$tempDown"
exe tar -xf "$tempLoc" exe tar -xf "$tempLoc"
endReturn -o $? "Extract failed: $tempLoc" endReturn "Extract failed: $tempLoc"
else else
echo " [I] Found existing download: $tempExtract" info "Found existing download: $tempExtract"
fi fi
} }
tempDown="/tmp/roundcube" tempDown="/tmp/roundcube"
tempLoc="$tempDown/rc.tar.gz" tempLoc="$tempDown/rc.tar.gz"
VERSION_SEQREV=14 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

341
seqs/rspamd.sh Executable file
View File

@@ -0,0 +1,341 @@
#!/usr/bin/env bash
readonly toolName=rspamd
readonly knownVersion="3.4"
readonly toolGit="https://github.com/vstakhov/rspamd.git"
# Already defined by sequencer.sh, but may be overwritten
#readonly seq_configName="${sq_scriptName:?}.cfg"
#readonly seq_configTemplate="${seq_origin:?}/${sq_configName:?}.example"
sq_aptOpt=
sq_config=0
seq_config() {
## Called once before executing steps.
## e.g. to source a config file manually:
#. "${seq_origin:?}/${seq_configName:?}"
## or to use sequencer api with profile config file support:
#if initSeqConfig -p "${seq_fileName:?}" "${seq_configTemplate:?}" ; then
## or to use sequencer api with global config file:
#if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
# sq_config=1
#else
# # End if no configuration file exists
# dry || return 1
#fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Setup custom repository for raspberry pi OS"; }
step_1_alias() { echo "install"; }
step_1() {
local lRaspbianRelease="Raspbian_$(lsb_release -sr)"
local lFileName="home_susenerf_rspamd-exotic-debian"
local lRepoUrl="http://download.opensuse.org/repositories/home:/susenerf:/rspamd-exotic-debian"
exep echo "deb ${lRepoUrl}/${lRaspbianRelease}/ /" "|" sudo tee /etc/apt/sources.list.d/${lFileName}.list
exep curl -fsSL "${lRepoUrl}/${lRaspbianRelease}/Release.key" "|" gpg --dearmor "|" sudo tee /etc/apt/trusted.gpg.d/${lFileName}.gpg ">" /dev/null
exe apt update
}
step_2_info() { echo "Install ${toolName} with apt"; }
step_2() {
exe apt install rspamd redis-server
}
step_10_info() { echo "Add ufw rule for WebUI (11334)"; }
step_10_alias() { echo "ufw"; }
step_10() {
exe ufw allow 11334/tcp comment "rspamd WebUI"
}
step_50_info() { echo "Notes"; }
step_50_alias() { echo "notes"; }
step_50() {
color green
cat <<NOTES_END
# Configuration
First generate a new encrypted password string to be used
with the web UI of ${toolName}
rspamadm pw
and insert the result into:
[/etc/rspamd/local.d/worker-controller.inc]
bind_socket = "*:11334";
password = <Result of rspamadm pw>
enable_password = <Result of rspamadm pw>
[/etc/rspamd/local.d/redis.conf]
server = "127.0.0.1";
timeout = 3s;
[/etc/rspamd/local.d/classifier-bayes.conf]
backend = "redis";
autolearn = true;
[/etc/rspamd/local.d/dkim_signing.conf]
enabled = false;
[/etc/rspamd/local.d/milter_headers.conf]
authenticated_headers = ["authentication-results"];
use = ["x-spamd-result","x-spam-level","x-spamd-bar", "my-x-spam-score","x-spam-status", "authentication-results"];
# add X-Spam-Score header (like SA does)
# Source: https://groups.google.com/forum/#!topic/rspamd/fEdbnG0J18I
custom {
my-x-spam-score = <<EOD
return function(task, common_meta)
local sc = common_meta['metric_score'] or task:get_metric_score()
-- return no error
return nil,
-- header(s) to add
{['X-Spam-Score'] = string.format('%.2f', sc[1])},
-- header(s) to remove
{['X-Spam-Score'] = 1},
-- metadata to store
{}
end
EOD;
}
[/etc/rspamd/local.d/phishing.conf]
openphish_enabled = true;
phishtank_enabled = true;
[/etc/rspamd/local.d/greylist.conf]
enabled = true;
timeout = 1min;
[/etc/rspamd/local.d/mx_check.conf]
enabled = true;
timeout = 5.0;
# A map of specific domains that should be excluded from MX check
exclude_domains = [
"https://maps.rspamd.com/freemail/disposable.txt.zst",
"https://maps.rspamd.com/freemail/free.txt.zst",
"\${CONFDIR}/maps.d/maillist.inc",
"\${CONFDIR}/maps.d/redirectors.inc",
"\${CONFDIR}/maps.d/dmarc_whitelist.inc",
"\${CONFDIR}/maps.d/surbl-whitelist.inc",
"\${CONFDIR}/maps.d/spf_dkim_whitelist.inc",
];
## Don't check mails send from local network
[/etc/rspamd/local.d/multimap.conf]
IP_WHITELIST {
type = "ip";
prefilter = true;
map = "/\${LOCAL_CONFDIR}/local.d/ip_whitelist.map";
action = "accept";
description = "Accept mails from local network"
}
#WHITELIST_SENDER_DOMAIN {
# type = "from";
# filter = "email:domain";
# map = "/etc/rspamd/local.d/whitelist.sender.domain.map";
# score = -6.0
#}
[/etc/rspamd/local.d/ip_whitelist.map]
fd00::/8
192.168.0.0/16
10.0.0.0/8
# Configuring Postfix
[/etc/postfix/main.cf]
# Invoke rspamd to check for spam
smtpd_milters = inet:localhost:11332
# skip mail without checks if something goes wrong
milter_default_action = accept
# Global sieve script for spam to junk
* If sieve before is a folder all scripts inside are executed
[/etc/dovecot/conf.d/90-sieve.conf]
sieve_before = /var/lib/dovecot/sieve.d/
* The global sieve script needs to be compiled with sievec
and changed group to vmail for access permissions
(chown root:vmail script; chmod 750 script)
[/var/lib/dovecot/sieve.d/spam-global.sieve]
require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
fileinto "Junk";
}
# Configure sieve as replacement for deprecated plugin dovecot-antispam
https://doc.dovecot.org/configuration_manual/howto/antispam_with_sieve/
[/etc/dovecot/conf.d/20-imap.conf]
mail_plugins = \$mail_plugins imap_sieve
[/etc/dovecot/conf.d/90-sieve.conf]
sieve_plugins = sieve_imapsieve sieve_extprograms
# From elsewhere to Spam folder
imapsieve_mailbox1_name = Spam
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_before = file:/usr/lib/dovecot/sieve-pipe/report-spam.sieve
# From Spam folder to elsewhere
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = Spam
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/usr/lib/dovecot/sieve-pipe/report-ham.sieve
sieve_extensions = +notify +imapflags +vnd.dovecot.execute
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
[/etc/dovecot/conf.d/90-sieve-extprograms.conf
sieve_pipe_bin_dir = /usr/lib/dovecot/sieve-pipe
sieve_execute_bin_dir = /usr/lib/dovecot/sieve-execute
[/usr/lib/dovecot/sieve-pipe/report-spam.sieve]
require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
if environment :matches "imap.user" "*" {
set "username" "\${1}";
pipe :copy "rspamd-learn-spam.sh" [ "\${username}" ];
[/usr/lib/dovecot/sieve-pipe/report-ham.sieve]
require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
if environment :matches "imap.mailbox" "*" {
set "mailbox" "\${1}";
}
if string "\${mailbox}" "Trash" {
stop;
}
if environment :matches "imap.user" "*" {
set "username" "\${1}";
}
pipe :copy "rspamd-learn-ham.sh" [ "\${username}" ];
[/usr/lib/dovecot/sieve-pipe/rspamd-learn-spam.sh]
#!/bin/sh
# rspamc learn is used in parallel. Be aware of system resources when
# moving multiple messages at the same time
rspamdNewSpam=\$(cat);( echo "\$rspamdNewSpam" | /usr/bin/rspamc learn_spam ) &
[/usr/lib/dovecot/sieve-pipe/rspamd-learn-ham.sh]
#!/bin/sh
# rspamc learn is used in parallel. Be aware of system resources when
# moving multiple messages at the same time
rspamdNewHam=\$(cat);( echo "\$rspamdNewHam" | /usr/bin/rspamc learn_ham ) &
NOTES_END
}
step_60_info() { echo "Build and install from source"; }
step_60_options() { echo "[VERSION]"; }
step_60_alias() { echo "buildlocal"; }
step_60() {
shift
local version="${1:-"${knownVersion}"}"
local buildHome="${HOME}/build"
local cloneDir="${buildHome}/rspamd"
local buildDir="${buildHome}/rspamd.build"
info "Building version ${version} in ${buildDir}"
exe mkdir -p "${buildHome}"
exe cd "${buildHome}"
exe git clone --recursive "${toolGit}"
info "Checkout version ${version}"
exe cd "${cloneDir}"
exe git checkout tags/${version} # check for latest tag
exe ./setVersion.sh "${version}" # check for latest tag
confirm -f -y -n "remove arm64 from ENABLE_LUAJIT ifneq"
exe editor debian/rules
confirm -f -y -n "enable WANT_SYSTEMD_UNITS, disable ENABLE_LUAJIT"
exe editor CMakeLists.txt
exe mkdir -p "${buildDir}"
exe cd "${buildDir}"
exe cmake "${cloneDir}" -DENABLE_HYPERSCAN=OFF
exe make
exe make install
exe install -g _rspamd -m 770 -d '/var/log/rspamd'
info "Change pathes in systemd file"
info -a "systemctl edit --full rspamd.service"
info
info "config: ${rbuild_confDir}"
}
readonly rbuild_confDir="/usr/local/etc/rspamd"
step_62_info() { echo "Uninstall local build (revert make install)"; }
step_62_alias() { echo "uninstall"; }
step_62() {
confirm "Are you sure to remove ${toolName}?" || return 1
if confirm "Backup config directory" ; then
info "Backing up ..."
exe cd "$(dirname -- "${rbuild_confDir}")"
exe tar czf "${HOME}/rspamd_config_build.tar.gz" "$(basename -- "${rbuild_confDir}")"
fi
info "Removing files and folder..."
exep systemctl stop rspamd \>/dev/null
exe rm -rf "${rbuild_confDir}"
exe rm -rf "/usr/local/share/rspamd"
exe rm -rf "/usr/local/lib/rspamd"
exe rm -rf "/usr/local/lib/systemd/system/rspamd.service"
exe rm -rf "/usr/local/share/man"/man*/rspam[dca]*.*
# rspamadm, rspamc, rspamd
exe rm -rf "/usr/local/bin/rspam"[adc]*
exe systemctl daemon-reload
}
step_64_info() { echo "Install build dependencies for .deb build"; }
step_64_options() { echo "[VERSION]"; }
step_64_alias() { echo "builddeb"; }
step_64() {
exe apt install cmake ragel pkg-config libglib2.0-dev libsqlite3-dev libicu-dev libmagic-dev libssl-dev libsodium-dev redis libjemalloc-dev libcurl4-openssl-dev liblua5.1-0-dev libunwind-dev liblua5.1-0-dev
}
step_65_info() { echo "Build .deb from source"; }
step_65_options() { echo "[VERSION]"; }
step_65() {
shift
local version="${1:-"${knownVersion}"}"
local buildHome="${HOME}/build"
local cloneDir="${buildHome}/rspamd"
local buildDir="${buildHome}/rspamd.dist"
local distDir="${buildDir}/rspamd.deb"
local tarball="rspamd.deb.tar.xz"
info "Building version ${version} in ${buildDir}"
exe mkdir -p "${buildHome}"
exe cd "${buildHome}"
exe git clone --recursive "${toolGit}"
info "Checkout version ${version}"
exe cd "${cloneDir}"
exe git checkout tags/${version} # check for latest tag
exe ./dist.sh "${buildDir}/${tarball}"
exe cd "${buildDir}"
exe tar xf "${tarball}"
exe cd "${distDir}"
exe ./setVersion.sh "${version}" # check for latest tag
exe editor debian/rules # remove arm64 from ENABLE_LUAJIT ifneq
# dpkg-source: -i[regex], --diff-ignore[=regex]
# dpkg-buildpackage: -b Equivalent to --build=binary or --build=any,all.
exe debuild -i --unsigned-source --unsigned-changes -b
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -5,36 +5,33 @@
# source: # source:
# - https://selivan.github.io/2017/02/07/rsyslog-log-forward-save-filename-handle-multi-line-failover.html # - https://selivan.github.io/2017/02/07/rsyslog-log-forward-save-filename-handle-multi-line-failover.html
toolName="rsyslog" readonly toolName="rsyslog"
toolConfig="/etc/rsyslog.conf" readonly toolConfig="/etc/rsyslog.conf"
# Get script working directory CONFIG_SNMP="${seq_origin}/${toolName}/10-snmp.conf"
# (when called from a different directory) CONFIG_CRON="${seq_origin}/${toolName}/10-cron.conf"
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )" CONFIG_RNGD="${seq_origin}/${toolName}/10-rngd.conf"
CONFIG_SNMP="$WDIR/${toolName}/10-snmp.conf" CONFIG_REMOTE="${seq_origin}/${toolName}/90-remote.conf"
CONFIG_CRON="$WDIR/${toolName}/10-cron.conf"
CONFIG_RNGD="$WDIR/${toolName}/10-rngd.conf"
CONFIG_REMOTE="$WDIR/${toolName}/90-remote.conf"
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install "$toolName" exe apt install "$toolName"
} }
step_2_info() { echo "Check configuration"; } step_2_info() { echo "Check configuration"; }
step_2_alias() { ALIAS="checkconf"; } step_2_alias() { echo "checkconf"; }
step_2() { step_2() {
exe rsyslogd -N 1 -f "$toolConfig" exe rsyslogd -N 1 -f "$toolConfig"
endReturn -o $? "Invalid $toolName configuration" endReturn "Invalid $toolName configuration"
} }
step_10_info() { echo "Reduce snmpd syslog messages"; } step_10_info() { echo "Reduce snmpd syslog messages"; }
step_10_alias() { ALIAS="snmpd"; } step_10_alias() { echo "snmpd"; }
step_10() { step_10() {
addConf -s -f "$CONFIG_SNMP" "$CONFIG_SNMP_DEST" addConf -s -f "$CONFIG_SNMP" "$CONFIG_SNMP_DEST"
endReturn -o $? endReturn
step checkconf step checkconf
exe service rsyslog restart exe service rsyslog restart
@@ -42,10 +39,10 @@ step_10() {
CONFIG_SNMP_DEST="/etc/rsyslog.d/$(basename $CONFIG_SNMP)" CONFIG_SNMP_DEST="/etc/rsyslog.d/$(basename $CONFIG_SNMP)"
step_12_info() { echo "Reduce cron syslog messages"; } step_12_info() { echo "Reduce cron syslog messages"; }
step_12_alias() { ALIAS="cron"; } step_12_alias() { echo "cron"; }
step_12() { step_12() {
addConf -s -f "$CONFIG_CRON" "$CONFIG_CRON_DEST" addConf -s -f "$CONFIG_CRON" "$CONFIG_CRON_DEST"
endReturn -o $? endReturn
step checkconf step checkconf
exe service rsyslog restart exe service rsyslog restart
@@ -53,21 +50,19 @@ step_12() {
CONFIG_CRON_DEST="/etc/rsyslog.d/$(basename $CONFIG_CRON)" CONFIG_CRON_DEST="/etc/rsyslog.d/$(basename $CONFIG_CRON)"
step_14_info() { echo "Reduce rngd syslog messages"; } step_14_info() { echo "Reduce rngd syslog messages"; }
step_14_alias() { ALIAS="rngd"; } step_14_alias() { echo "rngd"; }
step_14() { step_14() {
addConf -s -f "$CONFIG_RNGD" "$CONFIG_RNGD_DEST" addConf -s -f "$CONFIG_RNGD" "$CONFIG_RNGD_DEST"
endReturn -o $? endReturn
step checkconf step checkconf
exe service rsyslog restart exe service rsyslog restart
} }
CONFIG_RNGD_DEST="/etc/rsyslog.d/$(basename $CONFIG_RNGD)" CONFIG_RNGD_DEST="/etc/rsyslog.d/$(basename $CONFIG_RNGD)"
step_16_info() { step_16_info() { echo "Send syslog messages to remote syslog server"; }
echoinfoArgs "<REMOTE_IP:PORT>" step_16_options() { echo "<REMOTE_IP:PORT>"; }
echo "Send syslog messages to remote syslog server" step_16_alias() { echo "remote"; }
}
step_16_alias() { ALIAS="remote"; }
step_16() { step_16() {
local rex='^[0-9\.]+\:[0-9]+$' local rex='^[0-9\.]+\:[0-9]+$'
local remoteHost="" local remoteHost=""
@@ -75,13 +70,13 @@ step_16() {
if [[ "$2" =~ $rex ]] ; then if [[ "$2" =~ $rex ]] ; then
remoteHost=$2 remoteHost=$2
else else
echoerr " [E] No valid IP:PORT detected: $2" error -e "No valid IP:PORT detected: $2"
return 1 return 1
fi fi
addConf -s -f "$CONFIG_REMOTE" "$CONFIG_REMOTE_DEST" addConf -s -f "$CONFIG_REMOTE" "$CONFIG_REMOTE_DEST"
endReturn -o $? "Custom remote host $remoteHost not applied to destination or $MISSING_CONF" endReturn "Custom remote host $remoteHost not applied to destination or check ${sqr_missingConf:-}"
exe sed -i "s/12\.34\.56\.78\:514/${remoteHost}/" "$CONFIG_REMOTE_DEST" exe sed -i "s/12\.34\.56\.78\:514/${remoteHost}/" "$CONFIG_REMOTE_DEST"
endReturn -o $? "Couldn't apply $remoteHost to $CONFIG_REMOTE_DEST" endReturn "Couldn't apply $remoteHost to $CONFIG_REMOTE_DEST"
step checkconf step checkconf
exe service rsyslog restart exe service rsyslog restart
@@ -89,15 +84,15 @@ step_16() {
CONFIG_REMOTE_DEST="/etc/rsyslog.d/$(basename $CONFIG_REMOTE)" CONFIG_REMOTE_DEST="/etc/rsyslog.d/$(basename $CONFIG_REMOTE)"
step_17_info() { echo "Add ufw rules for sending to remote syslog. Port 514/tcp"; } step_17_info() { echo "Add ufw rules for sending to remote syslog. Port 514/tcp"; }
step_17_alias() { ALIAS="ufw"; } step_17_alias() { echo "ufw"; }
step_17() { step_17() {
exe ufw allow out on eth0 to any port 514 proto tcp comment "syslog remote" exe ufw allow out on eth0 to any port 514 proto tcp comment "syslog remote"
} }
step_30_info() { echo "Activating syslog server"; } step_30_info() { echo "Activating syslog server"; }
step_30_alias() { ALIAS="server"; } step_30_alias() { echo "server"; }
step_30() { step_30() {
outColor green color green
cat << SERVER_EOF cat << SERVER_EOF
# Uncomment the chapter # Uncomment the chapter
@@ -106,5 +101,7 @@ step_30() {
SERVER_EOF SERVER_EOF
} }
VERSION_SEQREV=14 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,14 +1,15 @@
#!/bin/bash #!/bin/bash
seqDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )" readonly toolName="snmpd"
toolName="snmpd" readonly toolConfigLoc="/etc/snmp"
toolConfigLoc="/etc/snmp" readonly toolConfig="${toolConfigLoc}/snmpd.conf"
toolConfig="${toolConfigLoc}/snmpd.conf" readonly toolSysUser="Debian-snmp"
toolSysUser="Debian-snmp"
step_config() { sq_aptOpt=
seq_config() {
## Apt cmdline option to suppress user interaction ## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y" interactive || sq_aptOpt="-y"
## Return of non zero value will abort the sequence ## Return of non zero value will abort the sequence
return 0 return 0
@@ -16,39 +17,39 @@ step_config() {
step_1_info() { echo "Install packages for $toolName"; } step_1_info() { echo "Install packages for $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
if [ $QUIET != 0 ]; then if quiet; then
exe apt-get -qq install $toolName exe apt-get -qq install $toolName
else else
exe apt install $toolName exe apt install $toolName
fi fi
endReturn -o $? "$toolName installation failed" endReturn "$toolName installation failed"
} }
step_2_info() { step_2_info() {
echoinfoArgs "[-s]"
echo "Setup snmp v3 access" echo "Setup snmp v3 access"
echoinfo " -s : Stop after creating authentication entry" echoinfo " -s : Stop after creating authentication entry"
} }
step_2_alias() { ALIAS="v3access"; } step_2_options() { echo "[-s]"; }
step_2_alias() { echo "v3access"; }
step_2() { step_2() {
# #
## Create authentication entry ## Create authentication entry
exep "cat \"$v3AuthLoc\" | grep -e '^\s*usmUser'" exep "cat \"$v3AuthLoc\" | grep -e '^\s*usmUser'"
if [ "$?" == "0" ]; then if [ "$?" == "0" ]; then
echoseq info
exe read -p "User entry found. Continue: y/n(default)? " answer exe read -p "User entry found. Continue: y/n(default)? " answer
case $answer in case $answer in
[yY]) [yY])
echoseq info
echoseq "Continuing installation..." info "Continuing installation..."
;; ;;
*) *)
echoseq info
echoseq "Installation aborted" info "Installation aborted"
return 1; return 1;
;; ;;
esac esac
@@ -56,14 +57,14 @@ step_2() {
read -p "SNMPv3 Username: " v3User read -p "SNMPv3 Username: " v3User
read -p "SNMPv3 Password: " v3Pass read -p "SNMPv3 Password: " v3Pass
echoseq info
read -p "Repeat Password: " v3Pass2 read -p "Repeat Password: " v3Pass2
if [ "$v3Pass" != "$v3Pass2" ] ; then if [ "$v3Pass" != "$v3Pass2" ] ; then
echoerr " [E] Password mismatch" error -e "Password mismatch"
return 1 return 1
fi fi
echoseq info
exe service snmpd stop exe service snmpd stop
@@ -73,8 +74,8 @@ step_2() {
addConf -a "$v3AuthEntry" "$v3AuthLoc" addConf -a "$v3AuthEntry" "$v3AuthLoc"
shift shift
if [ ! -z $1 ] && [ "$1" == "-s" ] ; then if [ -n "${1:-}" ] && [ "$1" == "-s" ] ; then
echoseq " [I] Stop after creating authentication config" info "Stop after creating authentication config"
exe service snmpd start exe service snmpd start
return 0 return 0
fi fi
@@ -82,7 +83,7 @@ step_2() {
# #
## Add custom base configuration ## Add custom base configuration
addConf -c "" "${toolConfig}" addConf -c "" "${toolConfig}"
exe cp "${seqDir}/snmpd.conf" "${toolConfig}" exe cp "${seq_origin}/snmpd.conf" "${toolConfig}"
# #
## Add username as rouser ## Add username as rouser
@@ -101,24 +102,24 @@ step_2() {
v3AuthLoc="/var/lib/snmp/snmpd.conf" v3AuthLoc="/var/lib/snmp/snmpd.conf"
step_5_info() { step_5_info() {
echoinfoArgs "[INTERFACE]"
echo "Add ufw rules for port 161 udp" echo "Add ufw rules for port 161 udp"
echoinfo " [INTERFACE] (default: eth0)" echoinfo " [INTERFACE] (default: eth0)"
} }
step_5_alias() { ALIAS="ufw"; } step_5_options() { echo "[INTERFACE]"; }
step_5_alias() { echo "ufw"; }
step_5() { step_5() {
shift shift
local lInterface="eth0" local lInterface="eth0"
[ ! -z "$1" ] && lInterface="$1" [ -n "${1:-}" ] && lInterface="$1"
# Check if interface exists # Check if interface exists
ip -br a | grep -E "^$lInterface" >>/dev/null 2>&1 ip -br a | grep -E "^$lInterface" >>/dev/null 2>&1
endReturn -o $? "Interface $lInterface does not exist" endReturn "Interface $lInterface does not exist"
exe ufw allow in on $lInterface to any port 161 proto udp comment "snmp" exe ufw allow in on $lInterface to any port 161 proto udp comment "snmp"
} }
step_20_info() { echo "Extend $toolName for Raspberry Pi"; } step_20_info() { echo "Extend $toolName for Raspberry Pi"; }
step_20_alias() { ALIAS="raspberry"; } step_20_alias() { echo "raspberry"; }
step_20() { step_20() {
checkExtend raspberry checkExtend raspberry
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
@@ -126,7 +127,7 @@ step_20() {
fi fi
exe wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/raspberry.sh -O "${rpiExtendLoc}" exe wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/raspberry.sh -O "${rpiExtendLoc}"
endReturn -o $? "Download failed" endReturn "Download failed"
exe chmod +x "$rpiExtendLoc" exe chmod +x "$rpiExtendLoc"
addConf -a "extend raspberry /etc/snmp/raspberry.sh" "$toolConfig" addConf -a "extend raspberry /etc/snmp/raspberry.sh" "$toolConfig"
@@ -143,7 +144,7 @@ rpiSudoersLoc="/etc/sudoers.d/snmprpi"
rpiSudoersContent="${toolSysUser} ALL=(ALL) NOPASSWD: /etc/snmp/raspberry.sh, /usr/bin/vcgencmd*" rpiSudoersContent="${toolSysUser} ALL=(ALL) NOPASSWD: /etc/snmp/raspberry.sh, /usr/bin/vcgencmd*"
step_22_info() { echo "Extend $toolName with OS update availablity"; } step_22_info() { echo "Extend $toolName with OS update availablity"; }
step_22_alias() { ALIAS="osupdate"; } step_22_alias() { echo "osupdate"; }
step_22() { step_22() {
checkExtend osupdate checkExtend osupdate
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
@@ -151,7 +152,7 @@ step_22() {
fi fi
exe wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/osupdate -O "${osUpdateExtendLoc}" exe wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/osupdate -O "${osUpdateExtendLoc}"
endReturn -o $? "Download failed" endReturn "Download failed"
exe chmod +x "$osUpdateExtendLoc" exe chmod +x "$osUpdateExtendLoc"
addConf -a "extend osupdate $osUpdateExtendLoc" "$toolConfig" addConf -a "extend osupdate $osUpdateExtendLoc" "$toolConfig"
@@ -167,23 +168,23 @@ osUpdateCron="/etc/cron.d/aptUpdate"
osUpdateCronContent="22 */6 * * * root /usr/bin/apt-get -qq update" osUpdateCronContent="22 */6 * * * root /usr/bin/apt-get -qq update"
step_25_info() { echo "Prepare nginx to provide php-fpm status to $toolName"; } step_25_info() { echo "Prepare nginx to provide php-fpm status to $toolName"; }
step_25_alias() { ALIAS="phpfpm"; } step_25_alias() { echo "phpfpm"; }
step_25() { step_25() {
echo -e "\n [!] Please add the following to your default server:\n" echo -e "\n [!] Please add the following to your default server:\n"
echo "$phpFpmStatusNginx" echo "$phpFpmStatusNginx"
echo echo
if [ $QUIET -ne 0 ] ; then if quiet ; then
answer=n answer=n
else else
exe read -p "Open new shell to configure y/[n]? " answer exe read -p "Open new shell to configure y/[n]? " answer
fi fi
case $answer in case $answer in
[yY]) [yY])
echoseq " [I] Opening interactive shell. Type \"exit\" to return to this script." info "Opening interactive shell. Type \"exit\" to return to this script."
exe bash -i exe bash -i
echoseq " [I] Interactive shell ended. Continuing with $0." info "Interactive shell ended. Continuing with $0."
exe nginx -t exe nginx -t
endReturn -o $? "Nginx configuration error" endReturn "Nginx configuration error"
exe service nginx restart exe service nginx restart
;; ;;
@@ -192,7 +193,7 @@ step_25() {
esac esac
} }
# TODO error when no php is installed # TODO error when no php is installed
phpVersionStr="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')" phpVersionStr="$(command -v php >>/dev/null && php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')"
phpFpmStatusNginx="# Provide php-fpm status phpFpmStatusNginx="# Provide php-fpm status
location ~ ^/(status|ping)\$ { location ~ ^/(status|ping)\$ {
access_log off; access_log off;
@@ -206,11 +207,11 @@ fastcgi_pass unix:/var/run/php/php${phpVersionStr}-fpm.sock;
}" }"
step_26_info() { echo "Prepare php config for php-fpm status"; } step_26_info() { echo "Prepare php config for php-fpm status"; }
step_26_alias() { ALIAS="phpfpm_config"; } step_26_alias() { echo "phpfpm_config"; }
step_26() { step_26() {
exe sed -i "s/^;\(pm\.status_path\)/\1/" "$phpPoolConfigLoc" exe sed -i "s/^;\(pm\.status_path\)/\1/" "$phpPoolConfigLoc"
exe php-fpm${phpVersionStr} -t exe php-fpm${phpVersionStr} -t
endReturn -o $? "Invalid php configuration" endReturn "Invalid php configuration"
service php${phpVersionStr}-fpm restart service php${phpVersionStr}-fpm restart
} }
@@ -218,7 +219,7 @@ phpConfigDir="/etc/php/${phpVersionStr}"
phpPoolConfigLoc="${phpConfigDir}/fpm/pool.d/www.conf" phpPoolConfigLoc="${phpConfigDir}/fpm/pool.d/www.conf"
step_27_info() { echo "Extend $toolName with parsing of php-fpm status"; } step_27_info() { echo "Extend $toolName with parsing of php-fpm status"; }
step_27_alias() { ALIAS="phpfpm_extend"; } step_27_alias() { echo "phpfpm_extend"; }
step_27() { step_27() {
checkExtend phpfpmsp checkExtend phpfpmsp
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
@@ -226,7 +227,7 @@ step_27() {
fi fi
exe wget https://github.com/librenms/librenms-agent/raw/master/snmp/phpfpmsp -O "${phpfpmExtendLoc}" exe wget https://github.com/librenms/librenms-agent/raw/master/snmp/phpfpmsp -O "${phpfpmExtendLoc}"
endReturn -o $? "Download failed" endReturn "Download failed"
exe chmod +x "$phpfpmExtendLoc" exe chmod +x "$phpfpmExtendLoc"
addConf -a "extend phpfpmsp ${phpfpmExtendLoc}" "$toolConfig" addConf -a "extend phpfpmsp ${phpfpmExtendLoc}" "$toolConfig"
@@ -236,23 +237,23 @@ step_27() {
phpfpmExtendLoc="${toolConfigLoc}/phpfpmsp" phpfpmExtendLoc="${toolConfigLoc}/phpfpmsp"
step_29_info() { echo "Prepare nginx to provide status to $toolName"; } step_29_info() { echo "Prepare nginx to provide status to $toolName"; }
step_29_alias() { ALIAS="nginx"; } step_29_alias() { echo "nginx"; }
step_29() { step_29() {
echoseq -e "\n [!] Please add the following to your default server:\n" info -e "\n [!] Please add the following to your default server:\n"
echoseq "$nginxStatus" sqr::echo "$nginxStatus"
echoseq info
if [ $QUIET -ne 0 ] ; then if quiet ; then
answer=n answer=n
else else
exe read -p "Open new shell to configure y/[n]? " answer exe read -p "Open new shell to configure y/[n]? " answer
fi fi
case $answer in case $answer in
[yY]) [yY])
echoseq " [I] Opening interactive shell. Type \"exit\" to return to this script." info "Opening interactive shell. Type \"exit\" to return to this script."
exe bash -i exe bash -i
echoseq " [I] Interactive shell ended. Continuing with $0." info "Interactive shell ended. Continuing with $0."
exe nginx -t exe nginx -t
endReturn -o $? "Nginx configuration error" endReturn "Nginx configuration error"
exe service nginx restart exe service nginx restart
;; ;;
@@ -270,7 +271,7 @@ deny all;
} }
" "
step_30_info() { echo "Extend $toolName with parsing of nginx status"; } step_30_info() { echo "Extend $toolName with parsing of nginx status"; }
step_30_alias() { ALIAS="nginx_extend"; } step_30_alias() { echo "nginx_extend"; }
step_30() { step_30() {
checkExtend nginx checkExtend nginx
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
@@ -278,7 +279,7 @@ step_30() {
fi fi
exe wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/nginx -O "${nginxExtendLoc}" exe wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/nginx -O "${nginxExtendLoc}"
endReturn -o $? "Download failed" endReturn "Download failed"
exe chmod +x "$nginxExtendLoc" exe chmod +x "$nginxExtendLoc"
addConf -a "extend nginx ${nginxExtendLoc}" "$toolConfig" addConf -a "extend nginx ${nginxExtendLoc}" "$toolConfig"
@@ -289,22 +290,17 @@ nginxExtendLoc="${toolConfigLoc}/nginx"
# postfix # postfix
step_32_info() { echo "Extend for postfix detailed and queue"; } step_32_info() { echo "Extend for postfix detailed and queue"; }
step_32_alias() { ALIAS="postfix"; } step_32_alias() { echo "postfix"; }
step_32() { step_32() {
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
exe wget https://github.com/librenms/librenms-agent/raw/master/snmp/postfix-queues -O "${postfixQueuesExtendLoc}" exe wget https://github.com/librenms/librenms-agent/raw/master/snmp/postfix-queues -O "${postfixQueuesExtendLoc}"
endReturn -o $? "Download postfix-queues failed" endReturn "Download postfix-queues failed"
exe wget https://github.com/librenms/librenms-agent/raw/master/snmp/postfixdetailed -O "${postfixScript}" exe wget https://github.com/librenms/librenms-agent/raw/master/snmp/postfixdetailed -O "${postfixScript}"
endReturn -o $? "Download postfixdetailed failed" endReturn "Download postfixdetailed failed"
exe chmod +x "${postfixQueuesExtendLoc}" exe chmod +x "${postfixQueuesExtendLoc}"
exe chmod +x "${postfixScript}" exe chmod +x "${postfixScript}"
exe apt install $postfixDeps $aptOpt exe apt install $postfixDeps ${sq_aptOpt}
} }
postfixDeps="pflogsumm" postfixDeps="pflogsumm"
@@ -314,11 +310,11 @@ step_33() {
exe chown root:$toolSysUser "$postfixCacheLoc" exe chown root:$toolSysUser "$postfixCacheLoc"
exe chmod 770 "$postfixCacheLoc" exe chmod 770 "$postfixCacheLoc"
echoseq " [I] Create symlink /var/log/maillog which is used by postfixdetailed" info "Create symlink /var/log/maillog which is used by postfixdetailed"
exe ln -fs /var/log/mail.log /var/log/maillog exe ln -fs /var/log/mail.log /var/log/maillog
echoseq " [I] Run /etc/snmp/postfixdetailed to create the initial cache file" info "Run /etc/snmp/postfixdetailed to create the initial cache file"
echoseq " so you don't end up with some crazy initial starting value." info " so you don't end up with some crazy initial starting value."
exe sudo -u $toolSysUser "$postfixScript" exe sudo -u $toolSysUser "$postfixScript"
} }
postfixCacheLoc="/var/cache/postfixdetailed" postfixCacheLoc="/var/cache/postfixdetailed"
@@ -328,9 +324,9 @@ postfixQueuesExtendLoc="${toolConfigLoc}/postfix-queues"
step_34_info() { echo "Create sudoers file for postfix scripts"; } step_34_info() { echo "Create sudoers file for postfix scripts"; }
step_34() { step_34() {
addConf -s "$postfixSudoersContent" "$postfixSudoersLoc" addConf -s "$postfixSudoersContent" "$postfixSudoersLoc"
echoseq " [I] Changing ${postfixQueuesExtendLoc} to add sudo for qshape" info "Changing ${postfixQueuesExtendLoc} to add sudo for qshape"
exe sed -i -E "s/\`qshape/\`sudo qshape/" "${postfixQueuesExtendLoc}" exe sed -i -E "s/\`qshape/\`sudo qshape/" "${postfixQueuesExtendLoc}"
echoseq " [W] Reboot may be required to make these changes active" warning "Reboot may be required to make these changes active"
} }
postfixSudoersLoc="/etc/sudoers.d/snmppostfix" postfixSudoersLoc="/etc/sudoers.d/snmppostfix"
postfixSudoersContent="${toolSysUser} ALL=(ALL) NOPASSWD: /usr/sbin/qshape" postfixSudoersContent="${toolSysUser} ALL=(ALL) NOPASSWD: /usr/sbin/qshape"
@@ -339,12 +335,12 @@ step_35_info() { echo "Create postfix extends (postfixdetailed and postfix-queue
step_35() { step_35() {
checkExtend postfix-queues checkExtend postfix-queues
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echoseq " [I] Create postfix-queues extend" info "Create postfix-queues extend"
addConf -a "extend mailq ${postfixQueuesExtendLoc}" "$toolConfig" addConf -a "extend mailq ${postfixQueuesExtendLoc}" "$toolConfig"
fi fi
checkExtend postfixdetailed checkExtend postfixdetailed
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echoseq " [I] Create postfixdetailed extend" info "Create postfixdetailed extend"
addConf -a "extend postfixdetailed ${postfixScript}" "$toolConfig" addConf -a "extend postfixdetailed ${postfixScript}" "$toolConfig"
fi fi
@@ -353,25 +349,20 @@ step_35() {
#fail2ban #fail2ban
step_37_info() { echo "Extend for fail2ban jail information"; } step_37_info() { echo "Extend for fail2ban jail information"; }
step_37_alias() { ALIAS="fail2ban"; } step_37_alias() { echo "fail2ban"; }
step_37(){ step_37(){
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
exe wget https://github.com/librenms/librenms-agent/raw/master/snmp/fail2ban -O "${fail2banExtendLoc}" exe wget https://github.com/librenms/librenms-agent/raw/master/snmp/fail2ban -O "${fail2banExtendLoc}"
endReturn -o $? "Download postfix failed" endReturn "Download postfix failed"
exe chmod +x "$fail2banExtendLoc" exe chmod +x "$fail2banExtendLoc"
checkExtend fail2ban checkExtend fail2ban
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echoseq " [I] Create fail2ban extend" info "Create fail2ban extend"
addConf -a "extend fail2ban ${fail2banExtendLoc} -c" "$toolConfig" addConf -a "extend fail2ban ${fail2banExtendLoc} -c" "$toolConfig"
fi fi
exe apt install $fail2banDeps $aptOpt exe apt install $fail2banDeps ${sq_aptOpt}
} }
fail2banDeps="libjson-perl" fail2banDeps="libjson-perl"
fail2banExtendLoc="${toolConfigLoc}/fail2ban" fail2banExtendLoc="${toolConfigLoc}/fail2ban"
@@ -385,7 +376,7 @@ fail2banCron="# Update cache for faster fail2ban polling
*/3 * * * * root ${fail2banExtendLoc} -u" */3 * * * * root ${fail2banExtendLoc} -u"
step_40_info() { echo "Create linux distribution detection extend (distro)"; } step_40_info() { echo "Create linux distribution detection extend (distro)"; }
step_40_alias() { ALIAS="distro"; } step_40_alias() { echo "distro"; }
step_40() { step_40() {
checkExtend distro checkExtend distro
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
@@ -393,10 +384,10 @@ step_40() {
fi fi
exe wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/distro -O "${distroExtendLoc}" exe wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/distro -O "${distroExtendLoc}"
endReturn -o $? "Download distro detection script failed" endReturn "Download distro detection script failed"
exe chmod +x "$distroExtendLoc" exe chmod +x "$distroExtendLoc"
echoseq " [I] Create distro extend" info "Create distro extend"
addConf -a "extend distro ${distroExtendLoc}" "$toolConfig" addConf -a "extend distro ${distroExtendLoc}" "$toolConfig"
exe service snmpd restart exe service snmpd restart
@@ -408,7 +399,7 @@ step_42_info() {
echo "Gather dhcp information from a dhcpd lease file" echo "Gather dhcp information from a dhcpd lease file"
echoinfo "pi-hole lease file not supported" echoinfo "pi-hole lease file not supported"
} }
step_42_alias() { ALIAS="dhcp"; } step_42_alias() { echo "dhcp"; }
step_42() { step_42() {
local locExtName="dhcpstats" local locExtName="dhcpstats"
local locExtUrl="https://github.com/librenms/librenms-agent/raw/master/snmp/dhcp.py" local locExtUrl="https://github.com/librenms/librenms-agent/raw/master/snmp/dhcp.py"
@@ -417,27 +408,27 @@ step_42() {
checkExtend $locExtName checkExtend $locExtName
[ $? -ne 0 ] && return 0 [ $? -ne 0 ] && return 0
exe apt install dhcpd-pools exe apt install dhcpd-pools ${sq_aptOpt}
endReturn -o $? "Install dhcpd-pools failed" endReturn "Install dhcpd-pools failed"
exe wget $locExtUrl -O "${locExtLoc}" exe wget $locExtUrl -O "${locExtLoc}"
endReturn -o $? "Download $locExtName script failed" endReturn "Download $locExtName script failed"
exe chmod +x "$locExtLoc" exe chmod +x "$locExtLoc"
echoseq " [I] Create extend for $locExtName" info "Create extend for $locExtName"
addConf -a "extend $locExtName ${locExtLoc}" "$toolConfig" addConf -a "extend $locExtName ${locExtLoc}" "$toolConfig"
echoseq " [I] Create config for $locExtName" info "Create config for $locExtName"
addConf -s "$dhcpExtendConfig" "$dhcpExtendConfigLoc" addConf -s "$dhcpExtendConfig" "$dhcpExtendConfigLoc"
echo " [W] Adapt config $dhcpExtendConfigLoc manually and restart snmpd" warning "Adapt config $dhcpExtendConfigLoc manually and restart snmpd"
} }
dhcpExtendConfigLoc="${toolConfigLoc}/dhcp.json" dhcpExtendConfigLoc="${toolConfigLoc}/dhcp.json"
dhcpExtendConfig="{\"leasefile\": \"/var/lib/dhcp/dhcpd.leases\" dhcpExtendConfig="{\"leasefile\": \"/var/lib/dhcp/dhcpd.leases\"
}" }"
step_44_info() { echo "Extend unbound stats"; } step_44_info() { echo "Extend unbound stats"; }
step_44_alias() { ALIAS="unbound"; } step_44_alias() { echo "unbound"; }
step_44() { step_44() {
local locExtName="unbound" local locExtName="unbound"
local locExtUrl="https://github.com/librenms/librenms-agent/raw/master/snmp/unbound" local locExtUrl="https://github.com/librenms/librenms-agent/raw/master/snmp/unbound"
@@ -447,13 +438,13 @@ step_44() {
[ $? -ne 0 ] && return 0 [ $? -ne 0 ] && return 0
exe wget $locExtUrl -O "${locExtLoc}" exe wget $locExtUrl -O "${locExtLoc}"
endReturn -o $? "Download $locExtName script failed" endReturn "Download $locExtName script failed"
exe chmod +x "$locExtLoc" exe chmod +x "$locExtLoc"
echoseq " [I] Create extend for $locExtName" info "Create extend for $locExtName"
addConf -a "extend $locExtName /usr/bin/sudo ${locExtLoc}" "$toolConfig" addConf -a "extend $locExtName /usr/bin/sudo ${locExtLoc}" "$toolConfig"
echoseq " [I] Create config for $locExtName" info "Create config for $locExtName"
addConf -s "$unboundExtendConfig" "$unboundExtendConfigLoc" addConf -s "$unboundExtendConfig" "$unboundExtendConfigLoc"
exe systemctl restart unbound.service exe systemctl restart unbound.service
@@ -480,7 +471,7 @@ unboundSudoerLoc="/etc/sudoers.d/snmpunbound"
unboundSudoer="Debian-snmp ALL=(ALL) NOPASSWD: /usr/sbin/unbound-control, ${toolConfigLoc}/unbound" unboundSudoer="Debian-snmp ALL=(ALL) NOPASSWD: /usr/sbin/unbound-control, ${toolConfigLoc}/unbound"
step_46_info() { echo "Extend pi-hole stats"; } step_46_info() { echo "Extend pi-hole stats"; }
step_46_alias() { ALIAS="pihole"; } step_46_alias() { echo "pihole"; }
step_46() { step_46() {
local locExtName="pi-hole" local locExtName="pi-hole"
local locExtUrl="https://github.com/librenms/librenms-agent/raw/master/snmp/pi-hole" local locExtUrl="https://github.com/librenms/librenms-agent/raw/master/snmp/pi-hole"
@@ -489,25 +480,25 @@ step_46() {
checkExtend $locExtName checkExtend $locExtName
[ $? -ne 0 ] && return 0 [ $? -ne 0 ] && return 0
exe apt install $piHoleDeps $APTOPT exe apt install $piholeDeps ${sq_aptOpt}
exe wget $locExtUrl -O "${locExtLoc}" exe wget $locExtUrl -O "${locExtLoc}"
endReturn -o $? "Download $locExtName script failed" endReturn "Download $locExtName script failed"
exe chmod +x "$locExtLoc" exe chmod +x "$locExtLoc"
echoseq " [I] Create extend for $locExtName" info "Create extend for $locExtName"
addConf -a "extend $locExtName ${locExtLoc}" "$toolConfig" addConf -a "extend $locExtName ${locExtLoc}" "$toolConfig"
if [ $QUIET -ne 0 ]; then if quiet; then
outColor red color red
echo -e " [W] Check the following in the extend script and restart snmpd:\n" echo -e " [W] Check the following in the extend script and restart snmpd:\n"
else else
echo " [I] Check the follwing in the extend script:" info "Check the follwing in the extend script:"
fi fi
echo "(API_AUTH_KEY) Add your pi-hole API key" echo "(API_AUTH_KEY) Add your pi-hole API key"
echo " (API_URL) and check the API URL" echo " (API_URL) and check the API URL"
outColor color
if [ $QUIET -eq 0 ]; then if interactive; then
exe read -p "Hit Enter to continue..." exe read -p "Hit Enter to continue..."
exe vi "$locExtLoc" exe vi "$locExtLoc"
exe systemctl restart snmpd.service exe systemctl restart snmpd.service
@@ -516,9 +507,9 @@ step_46() {
piholeDeps="jq" piholeDeps="jq"
step_100_info() { echo "Notes"; } step_100_info() { echo "Notes"; }
step_100_alias() { ALIAS="notes"; } step_100_alias() { echo "notes"; }
step_100() { step_100() {
outColor green color green
cat <<NOTES_END cat <<NOTES_END
# Reduce log level of snmpd # Reduce log level of snmpd
@@ -565,18 +556,20 @@ NOTES_END
checkExtend() { checkExtend() {
# adding dry run output for clarification # adding dry run output for clarification
if [ $DRY -ne 0 ] ; then if dry ; then
echoseq " [I] check if \"extend ${1}\" exists..dry-run" info "check if \"extend ${1}\" exists..dry-run"
fi fi
exep "cat \"$toolConfig\" | grep -e '^\s*extend\s\+${1}' >>/dev/null 2>&1" exep "cat \"$toolConfig\" | grep -e '^\s*extend\s\+${1}' >>/dev/null 2>&1"
# Only warn if entry exists and dry-run is not seleted # Only warn if entry exists and dry-run is not seleted
if [ $? -eq 0 ] && [ $DRY -eq 0 ] ; then if [ $? -eq 0 ] && ! dry ; then
return 1 return 1
fi fi
return 0 return 0
} }
VERSION_SEQREV=15 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -1,57 +1,57 @@
# AGENT BEHAVIOUR # AGENT BEHAVIOUR
agentAddress udp:161,udp6:[::1]:161 agentAddress udp:161,udp6:[::1]:161
# system + hrSystem groups only # system + hrSystem groups only
view systemonly included .1.3.6.1.2.1.1 view systemonly included .1.3.6.1.2.1.1
view systemonly included .1.3.6.1.2.1.25.1 view systemonly included .1.3.6.1.2.1.25.1
# Full access from the local host # Full access from the local host
#rocommunity public localhost #rocommunity public localhost
# Default access to basic system info # Default access to basic system info
rocommunity public default -V systemonly rocommunity public default -V systemonly
# rocommunity6 is for IPv6 # rocommunity6 is for IPv6
rocommunity6 public default -V systemonly rocommunity6 public default -V systemonly
# Full read-only access for SNMPv3 # Full read-only access for SNMPv3
rouser authOnlyUser rouser authOnlyUser
# SYSTEM INFORMATION # SYSTEM INFORMATION
sysLocation Sitting on the Dock of the Bay sysLocation Sitting on the Dock of the Bay
sysContact Me <me@example.org> sysContact Me <me@example.org>
# Application + End-to-End layers # Application + End-to-End layers
sysServices 72 sysServices 72
# Process Monitoring # Process Monitoring
# At least one 'mountd' process # At least one 'mountd' process
proc mountd proc mountd
# No more than 4 'ntalkd' processes - 0 is OK # No more than 4 'ntalkd' processes - 0 is OK
proc ntalkd 4 proc ntalkd 4
# At least one 'sendmail' process, but no more than 10 # At least one 'sendmail' process, but no more than 10
proc sendmail 10 1 proc sendmail 10 1
# Disk Monitoring # Disk Monitoring
# 10MBs required on root disk, 5% free on /var, 10% free on all other disks # 10MBs required on root disk, 5% free on /var, 10% free on all other disks
disk / 10000 disk / 10000
disk /var 5% disk /var 5%
includeAllDisks 10% includeAllDisks 10%
# System Load # System Load
# Unacceptable 1-, 5-, and 15-minute load averages # Unacceptable 1-, 5-, and 15-minute load averages
load 12 10 5 load 12 10 5
# ACTIVE MONITORING # ACTIVE MONITORING
# send SNMPv1 traps # send SNMPv1 traps
trapsink localhost public trapsink localhost public
# Event MIB - automatically generate alerts # Event MIB - automatically generate alerts
# Remember to activate the 'createUser' lines above # Remember to activate the 'createUser' lines above
iquerySecName internalUser iquerySecName internalUser
rouser internalUser rouser internalUser
# AgentX Sub-agents # AgentX Sub-agents
# Run as an AgentX master agent # Run as an AgentX master agent
master agentx master agentx
#If the snmpd was compiled with TCP Wrapper support, it logs every connection made to the agent. This setting disables the #If the snmpd was compiled with TCP Wrapper support, it logs every connection made to the agent. This setting disables the
#log messages for accepted connections. Denied connections will still be logged. #log messages for accepted connections. Denied connections will still be logged.

View File

@@ -26,10 +26,10 @@ step_1_info() {
echo "Install packages: $toolDeps" echo "Install packages: $toolDeps"
echoinfo "May take a long time" echoinfo "May take a long time"
} }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local aptOpt= local aptOpt=
if [ $QUIET -ne 0 ];then if quiet;then
aptOpt="-y" aptOpt="-y"
fi fi
exe apt update exe apt update
@@ -37,16 +37,16 @@ step_1() {
} }
step_20_info() { echo "List spam/ham counts"; } step_20_info() { echo "List spam/ham counts"; }
step_20_alias() { ALIAS="list"; } step_20_alias() { echo "list"; }
step_20() { step_20() {
exe mysql -D $SA_BAYES_DBNAME -e 'select username,spam_count,ham_count from bayes_vars;' exe mysql -D $SA_BAYES_DBNAME -e 'select username,spam_count,ham_count from bayes_vars;'
} }
SA_BAYES_DBNAME='spambayes_db' SA_BAYES_DBNAME='spambayes_db'
step_50_info() { echo "Notes"; } step_50_info() { echo "Notes"; }
step_50_alias() { ALIAS="notes"; } step_50_alias() { echo "notes"; }
step_50() { step_50() {
outColor green color green
echo "$notes" echo "$notes"
} }
notes=' notes='
@@ -150,5 +150,5 @@ notes='
saNewHam=$(cat);( echo "$saNewHam" | /usr/bin/sa-learn -u ${1} --ham ) & saNewHam=$(cat);( echo "$saNewHam" | /usr/bin/sa-learn -u ${1} --ham ) &
' '
VERSION_SEQREV=14 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -9,30 +9,30 @@ aHost=""
aPort="22" aPort="22"
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install ssh exe apt install ssh
} }
step_3_info() { echo "Create $toolName authentication keys"; } step_3_info() { echo "Create $toolName authentication keys"; }
step_3_alias() { ALIAS="create"; } step_3_alias() { echo "create"; }
step_3() { step_3() {
exep "ssh-keygen -l -f $toolIdentity 2>>/dev/null" exep "ssh-keygen -l -f $toolIdentity 2>>/dev/null"
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo " [I] Using key found at $toolIdentity." info "Using key found at $toolIdentity."
return 0 return 0
fi fi
exe ssh-keygen -b 4096 -t rsa -C "$(hostname)" -N "" -f $(realpath $toolIdentity) exe ssh-keygen -b 4096 -t rsa -C "$(hostname)" -N "" -f $(realpath $toolIdentity)
} }
step_5_info() { step_5_info() {
echoinfoArgs "[OPTIONS] <USER@HOST> [PORT]"
echo "Send key to remote host" echo "Send key to remote host"
echoinfo "[OPTIONS]" echoinfo "[OPTIONS]"
echoinfo " -4 : Force Ipv4" echoinfo " -4 : Force Ipv4"
} }
step_5_alias() { ALIAS="sendkey"; } step_5_options() { echo "[OPTIONS] <USER@HOST> [PORT]"; }
step_5_alias() { echo "sendkey"; }
step_5() { step_5() {
shift shift
local arg local arg
@@ -53,7 +53,7 @@ step_5() {
done done
if [ -z "$1" ] || [ "$1" == "" ] ; then if [ -z "$1" ] || [ "$1" == "" ] ; then
echoerr " [E] Host not provided." error -e "Host not provided."
return 1 return 1
else else
sshHost="$1" sshHost="$1"
@@ -71,17 +71,17 @@ step_5() {
} }
step_10_info() { step_10_info() {
echoinfoArgs "<CMDLIST> [USER:HOST] [PORT]"
echo "Send command(ssh)/file(scp) list to remote(s)" echo "Send command(ssh)/file(scp) list to remote(s)"
echoinfo "[USER:HOST] and [PORT] are overwritten by \"host\" command from <CMDLIST>" echoinfo "[USER:HOST] and [PORT] are overwritten by \"host\" command from <CMDLIST>"
} }
step_10_alias() { ALIAS="sendlist"; } step_10_options() { echo "<CMDLIST> [USER:HOST] [PORT]"; }
step_10_alias() { echo "sendlist"; }
step_10() { step_10() {
shift shift
aList=$1 aList=${1:-}
aHost=$2 aHost=${2:-}
# Set port only if not empty # Set port only if not empty
if [ ! -z "$3" ]; then if [ -n "${3:-}" ]; then
aPort=$3 aPort=$3
fi fi
parseList $aList parseList $aList
@@ -113,13 +113,13 @@ step_10() {
parseList() { parseList() {
local errorMsg="" local errorMsg=""
if [ -z "$1" ] || [ ! -f "$1" ]; then if [ -z "${1:-}" ] || [ ! -f "${1:-}" ]; then
if [ -z "$1" ]; then if [ -z "${1:-}" ]; then
echoerr " [E] No Command list found" error -e "No Command list found"
else else
echoerr " [E] Command list not found: $1" error -e "Command list not found: $1"
fi fi
if [ ! -z "$1" ] && [ $DRY == 0 ] && [ $QUIET == 0 ] ; then if [ -n "${1:-}" ] && dry || interactive ; then
read -p " Create template there y/[n]? " answer read -p " Create template there y/[n]? " answer
case "$answer" in case "$answer" in
y|Y) y|Y)
@@ -132,7 +132,7 @@ parseList() {
return 1 return 1
fi fi
echoseq " [I] Parsing $(realpath $1) ..." info "Parsing $(realpath -- "${1:-}") ..."
local line=1 local line=1
# Working loop without ssh "stealing standard input" by # Working loop without ssh "stealing standard input" by
# https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while # https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while
@@ -184,15 +184,15 @@ parseList() {
esac esac
getReturn getReturn
if [ $? -ne 0 ] ; then if [ $? -ne 0 ] ; then
echoerr -e " [E] $line:$errorMsg" error -e -e " [E] $line:$errorMsg"
if [ $QUIET -eq 0 ] ; then if interactive ; then
endReturn -f "Stop on first error" endReturn -f "Stop on first error"
fi fi
fi fi
((line++)) ((line++))
done 3<"$1" done 3<"$1"
echoseq " [I] Parsed $((--line)) lines" info "Parsed $((--line)) lines"
} }
listFileTemplate="# following files are send to host given on command line listFileTemplate="# following files are send to host given on command line
@@ -210,5 +210,5 @@ f|/sourcedir/sourcefile|/destdir/destfile
f|/sourcedir/sourcefile|/destdir/destfile f|/sourcedir/sourcefile|/destdir/destfile
c|/destdir2/update.sh" c|/destdir2/update.sh"
VERSION_SEQREV=14 readonly sqr_minVersion=16
. sequencer.sh . sequencer.sh

View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
readonly sc_synadmLoc="/var/www/synapse-admin"

120
seqs/synapse-admin.sh Executable file
View File

@@ -0,0 +1,120 @@
#!/usr/bin/env bash
readonly toolName=synapse-admin
readonly versionUrl="https://api.github.com/repos/Awesome-Technologies/synapse-admin/releases/latest"
downUrl=
versionNew=
versionNow=
sq_aptOpt=
sq_config=0
seq_config() {
## or to use sequencer api with global config file:
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
else
# End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
getVersions() {
versionNew=${versionNew:-$(curl --silent "$versionUrl" | grep -Po '"tag_name": "\K.*?(?=")')}
downUrl=${downUrl:-$(curl --silent "$versionUrl" | grep -Po '"browser_download_url": "\K.*?(?=")')}
versionNow=${versionNow:-$(grep -Po 'REACT_APP_VERSION:"\K.*?(?=")' 2>/dev/null < "${sc_synadmLoc}/static/js/"main.*.js | head -1)}
}
step_1_info() { echo "Status"; }
step_1_alias() { echo "status"; }
step_1() {
getVersions
if [[ -z "${versionNow}" ]] ; then
info "Version ${versionNew} available to install"
elif [[ ${versionNew} == ${versionNow} ]] ; then
color green
info "Latest version ${versionNew} already installed"
else
color yellow
info "Update to: ${versionNew} available"
fi
}
step_10_info() { echo "Install"; }
step_10_alias() { echo "install"; }
step_10() {
local loBackup="${sc_synadmLoc}.bu"
local loTemp="/tmp/${toolName}.tar.gz"
# get download URL
getVersions
if [[ -e "${sc_synadmLoc}" ]]; then
exe mv "${sc_synadmLoc}" "${loBackup}"
fi
if ! exe wget -O "${loTemp}" "${downUrl}" ; then
info "Download failed"
exe mv "${loBackup}" "${sc_synadmLoc}" 2>/dev/null
else
exe tar -xf "${loTemp}" -C "$(dirname -- "${sc_synadmLoc}")"
endReturn "Extraction failed"
exe mv "$(dirname -- "${sc_synadmLoc}")/${toolName}-${versionNew}"* "${sc_synadmLoc}"
exe chown -R root: "${sc_synadmLoc}"
info "Downloaded to ${sc_synadmLoc}"
exe rm -rf "${loBackup}" "${loTemp}"
fi
}
step_20_info() { echo "Notes"; }
step_20_alias() { echo "notes"; }
step_20() {
color green
cat <<NOTES_EOF
# Nginx example
server {
listen 8084 ssl http2;
listen [::]:8084 ssl http2;
server_name _;
access_log /var/log/nginx/synapse_admin_access.log;
error_log /var/log/nginx/synapse_admin_error.log;
include /etc/nginx/ssl.conf;
error_page 497 https://\$host:\$server_port\$request_uri;
root ${sc_synadmLoc};
index index.html;
location / {
try_files \$uri \$uri/ =404;
}
location ~* ^(\/_matrix|\/_synapse\/admin) {
allow 192.168.0.0/24;
deny all;
proxy_pass http://localhost:8008;
proxy_set_header X-Forwarded-For \$remote_addr;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header Host \$host;
}
}
NOTES_EOF
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -18,38 +18,37 @@ CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg" CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" if initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" ; then
if [ $? -eq 0 ] ; then
CONFIG=1 CONFIG=1
else else
[ $DRY -eq 0 ] && return 1 dry || return 1
fi fi
toolConfigLoc=`eval echo "$TWXA_CONFIG_LOC"` toolConfigLoc=`eval echo "${TWXA_CONFIG_LOC:-}"`
toolConfig="$toolConfigLoc/config_cache/$toolConfigName" toolConfig="$toolConfigLoc/config_cache/$toolConfigName"
toolHtmlLoc=`eval echo "$TWXA_HTML_LOC"` toolHtmlLoc=`eval echo "${TWXA_HTML_LOC:-}"`
toolBackupLoc=`eval echo "$TWXA_BACKUP_LOC"` toolBackupLoc=`eval echo "${TWXA_BACKUP_LOC:-}"`
toolGitLoc=`eval echo "$TWXA_GIT_LOC"` toolGitLoc=`eval echo "${TWXA_GIT_LOC:-}"`
gitLibLoc=`eval echo "$TWXA_GIT_LOC/var/lib/torrentwatch-xa"` gitLibLoc=`eval echo "${TWXA_GIT_LOC:-}/var/lib/torrentwatch-xa"`
gitHtmlLoc=`eval echo "$TWXA_GIT_LOC/var/www/html/torrentwatch-xa"` gitHtmlLoc=`eval echo "${TWXA_GIT_LOC:-}/var/www/html/torrentwatch-xa"`
echo " git: $toolGitLoc" info " git: $toolGitLoc"
echo " config: $toolConfig" info -a "config: $toolConfig"
echo " html: $toolHtmlLoc" info -a " html: $toolHtmlLoc"
echo " backup: $toolBackupLoc" info -a "backup: $toolBackupLoc"
} }
step_1_info() { echo "Install $toolName [VERSION]"; } step_1_info() { echo "Install $toolName [VERSION]"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
shift shift
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
toolVersion="$1" toolVersion="$1"
fi fi
echo $toolConfig echo $toolConfig
} }
step_2_info() { echo "Setup git repository at $toolGitLoc [VERSION e.g. 1.4.1]"; } step_2_info() { echo "Setup git repository at ${toolGitLoc:-} [VERSION e.g. 1.4.1]"; }
step_2_alias() { ALIAS="git"; } step_2_alias() { echo "git"; }
step_2() { step_2() {
shift shift
if [ ! -e "$toolGitLoc/.git" ] ; then if [ ! -e "$toolGitLoc/.git" ] ; then
@@ -60,23 +59,23 @@ step_2() {
exe cd "$toolGitLoc" exe cd "$toolGitLoc"
exe git pull exe git pull
fi fi
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
toolVersion="$1" toolVersion="$1"
fi fi
exe git checkout $toolVersion exe git checkout $toolVersion
} }
step_20_info() { echo "Backup $toolName"; } step_20_info() { echo "Backup $toolName"; }
step_20_alias() { ALIAS="backup"; } step_20_alias() { echo "backup"; }
step_20() { step_20() {
shift shift
if [ ! -e "$toolConfigLoc" ] ; then if [ ! -e "$toolConfigLoc" ] ; then
echoerr " [E] No installation found" error -e "No installation found"
return 1 return 1
fi fi
local buType="all" local buType="all"
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
buType="$1" buType="$1"
fi fi
local buDate=`date +%Y%m%d-%H%M%S` local buDate=`date +%Y%m%d-%H%M%S`
@@ -115,24 +114,24 @@ step_20() {
} }
step_30_info() { echo "Upgrade $toolName [VERSION]"; } step_30_info() { echo "Upgrade $toolName [VERSION]"; }
step_30_alias() { ALIAS="upgrade"; } step_30_alias() { echo "upgrade"; }
step_30() { step_30() {
shift shift
if [ ! -z $1 ] ; then if [ -n "${1:-}" ] ; then
toolVersion="$1" toolVersion="$1"
fi fi
#step backup #step backup
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echoerr " [E] Backup failed. Aborting upgrade." error -e "Backup failed. Aborting upgrade."
return 1 return 1
fi fi
echo " [I] Upgrading data" info "Upgrading data"
exe mv "$toolConfigLoc/lib" "$toolConfigLoc/lib_bu" exe mv "$toolConfigLoc/lib" "$toolConfigLoc/lib_bu"
exe cp -ar "$gitLibLoc/lib" "$toolConfigLoc/" exe cp -ar "$gitLibLoc/lib" "$toolConfigLoc/"
echo " [I] Upgrading html" info "Upgrading html"
exe mv "$toolHtmlLoc" "${toolHtmlLoc}_bu" exe mv "$toolHtmlLoc" "${toolHtmlLoc}_bu"
exe cp -ar "$gitHtmlLoc" "$toolHtmlLoc" exe cp -ar "$gitHtmlLoc" "$toolHtmlLoc"
exe cp -arL "$toolBackupLoc/config.php" "$toolHtmlLoc" exe cp -arL "$toolBackupLoc/config.php" "$toolHtmlLoc"
@@ -143,5 +142,5 @@ step_30() {
exe chown -R www-data: "$toolConfigLoc/*_cache" exe chown -R www-data: "$toolConfigLoc/*_cache"
} }
VERSION_SEQREV=11 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -17,20 +17,20 @@ SCRIPT_NAME=${SCRIPT_NAME%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg" CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example" CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() { seq_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
CONFIG=1 CONFIG=1
else else
# End if no configuration file exists # End if no configuration file exists
[ $DRY -eq 0 ] && return 1 dry || return 1
fi fi
[ $QUIET -ne 0 ] && APTOPT="-y" quiet && APTOPT="-y"
return 0 return 0
} }
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install $toolDeps $APTOPT exe apt install $toolDeps $APTOPT
@@ -42,7 +42,7 @@ step_1() {
} }
step_10_info() { echo "Setup blocklist update cron job"; } step_10_info() { echo "Setup blocklist update cron job"; }
step_10_alias() { ALIAS="bllupdate"; } step_10_alias() { echo "bllupdate"; }
step_10() { step_10() {
addConf -s "$TRDA_REMOTE_AUTH" "$TRDA_REMOTE_AUTH_LOC" addConf -s "$TRDA_REMOTE_AUTH" "$TRDA_REMOTE_AUTH_LOC"
[ $? -eq 0 ] && exe chmod 600 "$TRDA_REMOTE_AUTH_LOC" [ $? -eq 0 ] && exe chmod 600 "$TRDA_REMOTE_AUTH_LOC"
@@ -51,7 +51,7 @@ step_10() {
} }
step_11_info() { echo "Setup remote authentication for current user (~/.netrc)"; } step_11_info() { echo "Setup remote authentication for current user (~/.netrc)"; }
step_11_alias() { ALIAS="netrcauth"; } step_11_alias() { echo "netrcauth"; }
step_11() { step_11() {
local lRemoteAuth="$(realpath ~/.netrc)" local lRemoteAuth="$(realpath ~/.netrc)"
if [ ! -f "$lRemoteAuth" ]; then if [ ! -f "$lRemoteAuth" ]; then
@@ -61,7 +61,7 @@ step_11() {
} }
step_12_info() { echo "Add ufw rules for rpc and peer port (default 9091 and 51413)"; } step_12_info() { echo "Add ufw rules for rpc and peer port (default 9091 and 51413)"; }
step_12_alias() { ALIAS="ufw"; } step_12_alias() { echo "ufw"; }
step_12() { step_12() {
local trdaRpcPort=9091 local trdaRpcPort=9091
exe ufw allow in on eth0 to any port $trdaRpcPort proto tcp comment "Transmission rpc" exe ufw allow in on eth0 to any port $trdaRpcPort proto tcp comment "Transmission rpc"
@@ -70,9 +70,9 @@ step_12() {
} }
step_20_info() { echo "Configuration notes"; } step_20_info() { echo "Configuration notes"; }
step_20_alias() { ALIAS="notes"; } step_20_alias() { echo "notes"; }
step_20() { step_20() {
outColor green color green
cat <<NOTES_EOF cat <<NOTES_EOF
[I] Change rpc password [I] Change rpc password
1) Make sure $toolName service is stopped before editing the configuration file. 1) Make sure $toolName service is stopped before editing the configuration file.
@@ -112,32 +112,33 @@ NOTES_EOF
} }
step_50_info() { echo "List all available torrents"; } step_50_info() { echo "List all available torrents"; }
step_50_alias() { ALIAS="list"; } step_50_alias() { echo "list"; }
step_50() { step_50() {
step netrcauth step netrcauth
outColor green color green
exe "$toolRemote" -l exe "$toolRemote" -l
} }
step_52_info() { echoinfoArgs "<TORRENT ID>"; echo "List information about a torrent"; } step_52_info() { echo "List information about a torrent"; }
step_52_alias() { ALIAS="info"; } step_52_options() { echo "<TORRENT ID>"; }
step_52_alias() { echo "info"; }
step_52() { step_52() {
shift shift
endCheckEmpty 1 "Id must not be empty" endIfEmpty 1 "Id must not be empty"
step netrcauth step netrcauth
outColor green color green
exep "\"$toolRemote\" -t$1 -i | less" exep "\"$toolRemote\" -t$1 -i | less"
} }
step_54_info() { echo "$toolName status"; } step_54_info() { echo "$toolName status"; }
step_54_alias() { ALIAS="status"; } step_54_alias() { echo "status"; }
step_54() { step_54() {
step netrcauth step netrcauth
outColor green color green
exe "$toolRemote" -si exe "$toolRemote" -si
exe "$toolRemote" -st exe "$toolRemote" -st
} }
VERSION_SEQREV=13 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -3,7 +3,7 @@
toolName="Tvheadend" toolName="Tvheadend"
step_1_info() { echo "Apt - setup $toolName repository"; } step_1_info() { echo "Apt - setup $toolName repository"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local sourceList="/etc/apt/sources.list.d/tvheadend.list" local sourceList="/etc/apt/sources.list.d/tvheadend.list"
local sourceEntry="deb https://apt.tvheadend.org/stable raspbian-stretch main" local sourceEntry="deb https://apt.tvheadend.org/stable raspbian-stretch main"
@@ -16,7 +16,7 @@ step_1() {
echo -n "Downloading tvheadend repository key ... " echo -n "Downloading tvheadend repository key ... "
exe wget -qO- https://doozer.io/keys/tvheadend/tvheadend/pgp | sudo apt-key add - exe wget -qO- https://doozer.io/keys/tvheadend/tvheadend/pgp | sudo apt-key add -
endReturn -o $? "Download of repository key failed" endReturn "Download of repository key failed"
addConf -c "$sourceEntry" "$sourceList" addConf -c "$sourceEntry" "$sourceList"
} }
@@ -47,6 +47,6 @@ step_99() {
endReturn endReturn
} }
VERSION_SEQREV=8 readonly sqr_minVersion=16
. sequencer.sh . sequencer.sh

View File

@@ -3,28 +3,31 @@
toolName=ufw toolName=ufw
toolDeps=$toolName toolDeps=$toolName
# Get script working directory sq_aptOpt=
# (when called from a different directory) #sq_config=0
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
#step_config() { seq_config() {
# initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" #if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?} ; then
# if [ $? -eq 0 ] ; then # sq_config=1
# CONFIG=1 #else
# fi # # End if no configuration file exists
#} # dry || return 1
#fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Install $toolName and allow ssh access"; } step_1_info() { echo "Install $toolName and allow ssh access"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
local aptOpt= exe apt install $toolDeps ${sq_aptOpt}
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
exe apt install $toolDeps $aptOpt
exe ufw allow ssh exe ufw allow ssh
} }
@@ -34,7 +37,7 @@ step_2() {
} }
step_20_info() { echo "Enable mail server essentials"; } step_20_info() { echo "Enable mail server essentials"; }
step_20_alias() { ALIAS="mailserver"; } step_20_alias() { echo "mailserver"; }
step_20() { step_20() {
exe ufw allow "Postfix" exe ufw allow "Postfix"
exe ufw allow "Postfix SMTPS" exe ufw allow "Postfix SMTPS"
@@ -44,52 +47,60 @@ step_20() {
exe ufw allow 4190/tcp comment 'Managesieve' exe ufw allow 4190/tcp comment 'Managesieve'
} }
step_22_info() { echoinfoArgs "[IP]"; echo "Deny multicast from gateway"; } step_22_info() { echo "Deny multicast from gateway and fritzbox webcheck"; }
step_22_alias() { ALIAS="multicast"; } step_22_options() { echo "[IP]"; }
step_22_alias() { echo "multicast"; }
step_22() { step_22() {
shift shift
if [ -z $1 ] ; then if [ -z "${1:-}" ] ; then
echoerr " [E] No [IP} specified" error -e "No [IP} specified"
return 1 return 1
fi fi
exe ufw deny in from $1 to 224.0.0.0/4 comment 'Broadcast Fritzbox' exe ufw deny in from "${1}" to 224.0.0.0/4 comment 'Broadcast Fritzbox'
exe ufw deny in from $1 to 239.0.0.0/8 comment 'Broadcast Fritzbox' exe ufw deny in from "${1}" to 239.0.0.0/8 comment 'Broadcast Fritzbox'
exe ufw deny in from "${1}" to any port 80 proto tcp comment 'Webcheck Fritzbox'
} }
step_24_info() { step_23_info() { echo "Deny IPv6 multicast"; }
echoinfoArgs "<FILE SERVER IP|RANGE> [PORT]" step_23_alias() { echo "multicast6"; }
step_23() {
exe ufw deny in from any to ff02::/16 port 53805 proto udp comment 'Multicast link local'
}
step_26_info() {
echo "Allow cifs mounts on eth0" echo "Allow cifs mounts on eth0"
echoinfo " [PORT] (default 445)" echoinfo " [PORT] (default 445)"
echoinfo " 139 : Cifs version 1.0" echoinfo " 139 : Cifs version 1.0"
echoinfo " 445 : Cifs version 2.0+" echoinfo " 445 : Cifs version 2.0+"
} }
step_24_alias() { ALIAS="cifs"; } step_26_options() { echo "<FILE SERVER IP|RANGE> [PORT]"; }
step_24() { step_26_alias() { echo "cifs"; }
step_26() {
shift shift
local destIp=$1 local destIp=${1:-}
local ipregex='^[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\/*[0-9]*$' local ipregex='^[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\.[0-2]*[0-9]{1,2}\/*[0-9]*$'
endCheckEmpty destIp "No IP provided" endIfEmpty destIp "No IP provided"
if [[ ! $1 =~ $ipregex ]]; then if [[ ! ${1:-} =~ $ipregex ]]; then
echoseq " [E] No valid IP provided" error "No valid IP provided"
return 1 return 1
fi fi
local destPort=445 local destPort=445
case "$2" in case "${2:-}" in
139|445) 139|445)
destPort=$2;; destPort="${2}";;
"");; # Set default "");; # Set default
*) *)
echoerr " [E] Invalid port." error -e "Invalid port."
return 1;; return 1;;
esac esac
exe ufw allow out on eth0 to $destIp port $destPort proto tcp comment "samba/cifs" exe ufw allow out on eth0 to "${destIp}" port "${destPort}" proto tcp comment "samba/cifs"
} }
step_26_info() { echo "Basic secure VPN setup"; } step_28_info() { echo "Basic secure VPN setup"; }
step_26_alias() { ALIAS="vpn"; } step_28_alias() { echo "vpn"; }
step_26() { step_28() {
exe ufw --force reset exe ufw --force reset
exe ufw allow in on eth0 to any port 22 comment "ssh" exe ufw allow in on eth0 to any port 22 comment "ssh"
exe ufw default deny incoming exe ufw default deny incoming
@@ -107,5 +118,7 @@ step_26() {
exe ufw status verbose exe ufw status verbose
} }
VERSION_SEQREV=14 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -4,41 +4,24 @@ toolName=vim
indentDownUrl="https://www.vim.org/scripts/download_script.php?src_id=27565" indentDownUrl="https://www.vim.org/scripts/download_script.php?src_id=27565"
seqVimConfigLoc="$HOME/.vimrc" seqVimConfigLoc="$HOME/.vimrc"
# Get script working directory sq_aptOpt=
# (when called from a different directory)
WDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >>/dev/null 2>&1 && pwd)"
APTOPT=
CONFIG=0
SCRIPT_FILE=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_FILE%%.*}
CONFIG_FILE_NAME="${SCRIPT_NAME}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() {
## or to use sequencer api with global config file:
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
#if [ $? -eq 0 ] ; then
# CONFIG=1
#else
# # End if no configuration file exists
# [ $DRY -eq 0 ] && return -1
#fi
seq_config() {
## Apt cmdline option to suppress user interaction ## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y" interactive || sq_aptOpt="-y"
## Return of non zero value will abort the sequence ## Return of non zero value will abort the sequence
return 0 return 0
} }
step_1_info() { echo "Install $toolName"; } step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt install vim $APTOPT exe apt install vim ${sq_aptOpt}
} }
step_2_info() { echo "Installing indentation script $seqVimIndentLoc"; } step_2_info() { echo "Installing indentation script $seqVimIndentLoc"; }
step_2_alias() { ALIAS="setup"; } step_2_alias() { echo "setup"; }
step_2() { step_2() {
if [ ! -e "$seqVimIndentLoc" ]; then if [ ! -e "$seqVimIndentLoc" ]; then
exe mkdir -p $(dirname "$seqVimIndentLoc") exe mkdir -p $(dirname "$seqVimIndentLoc")
@@ -46,7 +29,7 @@ step_2() {
wget --content-disposition $indentDownUrl wget --content-disposition $indentDownUrl
fi fi
echoseq " [I] Installing indentation rules" info "Installing indentation rules"
addConf -c "$seqVimConfigBasic" "$seqVimConfigLoc" addConf -c "$seqVimConfigBasic" "$seqVimConfigLoc"
} }
seqVimIndentLoc="$HOME/.vim/indent/sh.vim" seqVimIndentLoc="$HOME/.vim/indent/sh.vim"
@@ -55,17 +38,17 @@ filetype plugin indent on
syntax on" syntax on"
step_3_info() { echo "Install editorconfig as vim 8 plugin"; } step_3_info() { echo "Install editorconfig as vim 8 plugin"; }
step_3_alias() { ALIAS="editorconfig"; } step_3_alias() { echo "editorconfig"; }
step_3() { step_3() {
local ecDir="$HOME/.vim/pack/editorconfig/start" local ecDir="$HOME/.vim/pack/editorconfig/start"
local ecUrl='https://github.com/editorconfig/editorconfig-vim.git' local ecUrl='https://github.com/editorconfig/editorconfig-vim.git'
if [ ! -e "$ecDir" ]; then if [ ! -e "$ecDir" ]; then
echoseq " [I] Installing editorconfig plugin" info "Installing editorconfig plugin"
exe mkdir -p "$ecDir" exe mkdir -p "$ecDir"
exe cd "$ecDir" exe cd "$ecDir"
exe git clone "$ecUrl" exe git clone "$ecUrl"
else else
echoseq " [I] Upgrading editorconfig plugin" info "Upgrading editorconfig plugin"
exe cd "$ecDir" exe cd "$ecDir"
exe git pull exe git pull
fi fi
@@ -73,13 +56,20 @@ step_3() {
step_10_info() { echo "Setup $HOME/.vimrc globaly to use spaces and indent 2"; } step_10_info() { echo "Setup $HOME/.vimrc globaly to use spaces and indent 2"; }
step_10() { step_10() {
echoseq " [I] Installing formating rules" info "Installing formating rules"
info -a " 'set expandtab shiftwidth=2 softtabstop=2 tabstop=2'"
info -a " Indent by 2 spaces"
info -a " 'set noro'"
info -a " Don't set files read only for vimdiff"
info -a " 'cindent cinkeys-=0#'"
info -a " Don't remove leading spaces for comments"
addConf -a "$seqVimConfig" "$seqVimConfigLoc" addConf -a "$seqVimConfig" "$seqVimConfigLoc"
} }
seqVimConfig="set expandtab seqVimConfig="set expandtab shiftwidth=2 softtabstop=2 tabstop=2
set tabstop=2 set noro
set softtabstop=2 set cindent cinkeys-=0#"
set shiftwidth=2"
VERSION_SEQREV=15 # shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
sc_wallabagDir="/var/www/wallabag"
sc_wallabagBackupDir="/root/backup"
sc_wallabagDb="wallabag_db"
sc_wallabagDbUser="wallabag"
sc_wallabagUser="www-data" # user running the webserver

176
seqs/wallabag.sh Executable file
View File

@@ -0,0 +1,176 @@
#!/usr/bin/env bash
readonly toolName=wallabag
readonly toolComposerVersion="2.2.18"
readonly toolDeps="make"
readonly toolRepo="https://github.com/wallabag/wallabag.git"
# Already defined by sequencer.sh, but may be overwritten
#readonly seq_configName="${sq_scriptName:?}.cfg"
#readonly seq_configTemplate="${seq_origin:?}/${sq_configName:?}.example"
sq_aptOpt=
sq_config=0
seq_config() {
## or to use sequencer api with global config file:
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
else
# End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "${toolName} installation status"; }
step_1_alias() { echo "status"; }
step_1() {
if [[ -e "${sc_wallabagDir}" ]] ; then
color green
info "${toolName} installed"
else
color red
info "${toolName} not installed"
return 1
fi
}
step_10_info() {
echo -n "Install ${toolName}"
[[ -n "${sc_wallabagDir:-}" ]] && echo " to ${sc_wallabagDir}" || echo " to configured folder"
}
step_10_alias() { echo "install"; }
step_10() {
if [[ -e "${sc_wallabagDir}" ]] ; then
error "${toolName} already installed"
return 1
fi
exe apt update
exe apt install ${toolDeps} "${sq_aptOpt}"
}
step_11_info() { echo "Clone and prepare repository"; }
step_11() {
exe git clone "${toolRepo}" "${sc_wallabagDir}"
exe mkdir "${sc_wallabagDir}/vendor"
step postupgrade
}
step_12_info() { echo "Get supported composer version"; }
step_12() {
local result=1
local composerSetup="composer-setup.php"
local expected_checksum="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
exe cd "${sc_wallabagDir}"
exe php -r "copy('https://getcomposer.org/installer', '${composerSetup}');"
local actual_checksum="$(php -r "echo hash_file('sha384', '${composerSetup}');")"
if [ "$expected_checksum" != "$actual_checksum" ]
then
error 'Invalid installer checksum'
exe rm "${composerSetup}"
return 1
fi
exe php "${composerSetup}" --quiet --version="${toolComposerVersion}"
result="$?"
exe rm "${composerSetup}"
return "${result}"
}
step_13_info() { echo "Create mysql database for wallabag"; }
step_13() {
exe "${seq_origin}/mysql.sh" -q createdb -c utf8mb4 -d "${sc_wallabagDb:-"wallabag_db"}" -u "${sc_wallabagDbUser:-"wallabag"}"
}
step_14_info() { echo "Start ${toolName} installation procedure"; }
step_14() {
exe cd "${sc_wallabagDir}"
exe sudo -u "${sc_wallabagUser}" make install
}
step_20_info() { echo "Backup ${toolName}"; }
step_20_alias() { echo "backup"; }
step_20() {
info "Backing up configuration..."
exe cd "${sc_wallabagDir}"
exe tar czf "${sc_wallabagBackupDir:?}/wallabag_conf_$(date +%Y%m%d-%H%M%S).tar.gz" "app/config"
exe "${seq_origin}/mysql.sh" -qq backup "${sc_wallabagDb}" "${sc_wallabagBackupDir:?}"
}
step_22_info() { echo "Upgrade ${toolName}"; }
step_22_alias() { echo "upgrade"; }
step_22() {
step backup
exe cd "${sc_wallabagDir}"
exe sudo -u "${sc_wallabagUser}" make update
}
step_23_info() { echo "Post upgrade steps"; }
step_23_alias() { echo "postupgrade"; }
step_23() {
# Upgrade using user www-data is only successfull like this:
exe chown -R "${sc_wallabagUser}": "${sc_wallabagDir}"
}
step_100_alias() { echo "notes"; }
step_100() {
color green
cat <<NOTES_EOF
# Nginx - ${toolName} in subfolder /pocket
To be used with a reverse proxy for https.
---
upstream php-handler-wallabag {
server unix:/var/run/php/php7.4-fpm.sock;
}
server {
listen 80;
access_log off; #/var/log/nginx/wallabag_access.log;
error_log /var/log/nginx/wallabag_error.log;
# Set the root folder in a variable (optional)
set \$frontRoot ${sc_wallabagDir};
set \$sfApp app.php; # Change to app_dev.php for dev
set_real_ip_from 10.0.0.0/24;
real_ip_header X-Real-IP;
real_ip_recursive on;
# wallabag is Symfony 2 app
location /pocket/ { # Static files
root \$frontRoot;
rewrite ^/pocket/(.*)\$ /\$1 break;
try_files \$uri @sfFront;
}
location @sfFront {
fastcgi_pass php-handler-wallabag;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME \$frontRoot/\$sfApp;
fastcgi_param SCRIPT_NAME /pocket/\$sfApp;
fastcgi_param REQUEST_URI /pocket\$uri?\$args;
fastcgi_param HTTPS on;
}
}
---
NOTES_EOF
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -1,183 +0,0 @@
#!/bin/bash
serverName="nginx"
serverPackages="nginx"
serverSourceUrl="https://nginx.org/packages/debian/"
phpVersion="7.3"
phpName="php${phpVersion}"
phpPackages="${phpName}-{fpm,gd,mysql,curl,xml,zip,intl,mbstring,bz2,ldap,apcu,bcmath,gmp,imagick,igbinary,redis,smbclient,cli,common,opcache,readline} imagemagick"
aptOpt=
step_config() {
if [ $QUIET -ne 0 ] ; then
aptOpt="-y"
fi
}
step_1_info() {
echoinfoArgs "[DEBIAN RELEASE]"
echo "Setup latest apt source list for $serverName"
echoinfo "$serverSourceUrl"
}
step_1_alias() { ALIAS="setup"; }
step_1() {
shift
local osRelease=$1
endCheckEmpty osRelease "Debian release not provided"
echoseq " [I] Setup apt source for $serverName $serverSourceUrl"
local srvSource="deb $serverSourceUrl $osRelease nginx"
addConf -s "$srvSource" "$serverSourceLoc"
if [ $? -eq 0 ] ; then
echoseq " [I] Get repository key for $serverSourceUrl"Y
exe apt install gnupg $aptOpt
exe apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ABF5BD827BD9BF62
fi
}
serverSourceLoc="/etc/apt/sources.list.d/nginx.list"
step_2_info() {
echo "Installation of $serverName packages:"
echoinfo "$serverPackages"
}
step_2_alias() { ALIAS=install; }
step_2() {
exe apt update
exe apt install $serverPackages $aptOpt
endReturn -o $? "Failed to install $serverName"
}
step_3_info() { echo "Basic nginx configuration for initial letsencrypt certificate creation"; }
step_3() {
# Writing acme-challenge code snipped for certbot web root authentication
addConf -c "$snippetLetsencrypt" "$snippetLetsencryptLoc"
# Writing minimal default (see below)
addConf -c "$siteDefaultIp4" "$siteDefaultLoc"
# try fix errors on first install attempt
# (possible missing ipv6 support on system)
if [ $ERNO -ne 0 ] ; then
exe apt install nginx $aptOpt
fi
# create webroot
exe mkdir -p "$siteLetsencryptWww"
echoseq -n "Restarting Nginx..."
exe service nginx restart && echoseq "ok"
endReturn -o $? "Failed to install $serverName"
}
snippetLetsencryptLoc="/etc/nginx/snippets/letsencrypt.conf"
siteLetsencryptWww="/var/www/letsencrypt"
snippetLetsencrypt="\
location ^~ /.well-known/acme-challenge/ {
default_type \"text/plain\";
root ${siteLetsencryptWww};
}"
siteDefaultLoc="/etc/nginx/sites-available/default"
siteDefaultIp4="server {
listen 80 default_server;
include ${snippetLetsencryptLoc};
}"
step_4_info() {
echo "Installation of $phpName packages:"
echoinfo "$phpPackages"
}
step_4_alias() { ALIAS="php"; }
step_4() {
exe apt install $(eval echo $phpPackages) $aptOpt
}
phpFpmConfigLocation="/etc/php/${phpVersion}/fpm/conf.d/90-custom_pi.ini"
phpFpmConfig="memory_limit = 1024M
apc.enable_cli=1
output_buffering = Off
max_execution_time = 3600
max_input_time = 3600
post_max_size = 10240M
upload_max_filesize = 10240M
date.timezone = Europe/Berlin
session.cookie_secure = True
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=1
opcache.save_comments=1
allow_url_fopen = 1"
phpFpmConfigBu="register_argc_argv=on"
phpCliConfigLocation="/etc/php/${phpVersion}/cli/conf.d/90-custom_pi.ini"
phpCliConfig="\
apc.enable_cli=1
output_buffering = Off
max_execution_time = 3600
max_input_time = 3600
post_max_size = 10240M
upload_max_filesize = 10240M
date.timezone = Europe/Berlin"
phpPoolConfigLocation="/etc/php/${phpVersion}/fpm/pool.d/www.conf"
phpFpmIniLocation="/etc/php/${phpVersion}/fpm/php-fpm.conf"
step_5_info() { echo "Configuration of ${phpName} fpm and cli"; }
step_5() {
local AvailableRAM=$(awk '/MemAvailable/ {printf "%d", $2/1024}' /proc/meminfo)
local AverageFPM=$(ps --no-headers -o 'rss,cmd' -C php-fpm$phpVersion | awk '{ sum+=$1 } END { printf ("%d\n", sum/NR/1024,"M") }')
echo $AvailableRAM
echo $AverageFPM
local FPMS=$((AvailableRAM/AverageFPM))
local PMaxSS=$((FPMS*2/3))
local PMinSS=$((PMaxSS/2))
local PStartS=$(((PMaxSS+PMinSS)/2))
addConf -c "$phpFpmConfig" "$phpFpmConfigLocation"
addConf -c "$phpCliConfig" "$phpCliConfigLocation"
addConf -a "" "$phpFpmIniLocation"
exe sed -i "s|;emergency_restart_threshold.*|emergency_restart_threshold = 10|g" "$phpFpmIniLocation"
exe sed -i "s|;emergency_restart_interval.*|emergency_restart_interval = 1m|g" "$phpFpmIniLocation"
exe sed -i "s|;process_control_timeout.*|process_control_timeout = 10|g" "$phpFpmIniLocation"
addConf -a "" "$phpPoolConfigLocation"
exe sed -i "s/;env\[HOSTNAME\] = /env[HOSTNAME] = /" "$phpPoolConfigLocation"
exe sed -i "s/;env\[TMP\] = /env[TMP] = /" "$phpPoolConfigLocation"
exe sed -i "s/;env\[TMPDIR\] = /env[TMPDIR] = /" "$phpPoolConfigLocation"
exe sed -i "s/;env\[TEMP\] = /env[TEMP] = /" "$phpPoolConfigLocation"
exe sed -i "s/;env\[PATH\] = /env[PATH] = /" "$phpPoolConfigLocation"
exe sed -i 's/pm.max_children =.*/pm.max_children = '$FPMS'/' "$phpPoolConfigLocation"
exe sed -i 's/pm.start_servers =.*/pm.start_servers = '$PStartS'/' "$phpPoolConfigLocation"
exe sed -i 's/pm.min_spare_servers =.*/pm.min_spare_servers = '$PMinSS'/' "$phpPoolConfigLocation"
exe sed -i 's/pm.max_spare_servers =.*/pm.max_spare_servers = '$PMaxSS'/' "$phpPoolConfigLocation"
exe sed -i "s/;pm.max_requests =.*/pm.max_requests = 1000/" "$phpPoolConfigLocation"
echoseq -n "Restarting ${phpName} ... "
exe service ${phpName}-fpm restart && echoseq "ok"
}
step_6_info() { echo "Installation notes"; }
step_6_alias() { ALIAS="notes"; }
step_6() {
cat <<NOTES_EOF
# Set user to www-data on debian an tune performance a bit
[/etc/nginx/nginx.conf]
user www-data;
worker_processes 1;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
NOTES_EOF
}
VERSION_SEQREV=14
. /usr/local/bin/sequencer.sh

View File

@@ -10,11 +10,11 @@ step_1_info() {
echo "Installation of $serverName packages:" echo "Installation of $serverName packages:"
echoinfo "$serverPackages" echoinfo "$serverPackages"
} }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "install"; }
step_1() { step_1() {
exe apt update exe apt update
exe apt install $serverPackages exe apt install $serverPackages
endReturn -o $? "Server package installation error" endReturn "Server package installation error"
} }
step_2_info() { echo "Basic nginx configuration for initial letsencrypt certificate creation"; } step_2_info() { echo "Basic nginx configuration for initial letsencrypt certificate creation"; }
@@ -36,7 +36,7 @@ step_2() {
echo -n " [I] Restarting Nginx ... " echo -n " [I] Restarting Nginx ... "
exe service nginx restart && echo "ok" exe service nginx restart && echo "ok"
endReturn -o $? "Nginx error during startup" endReturn "Nginx error during startup"
} }
snippetLetsencryptLoc="/etc/nginx/snippets/letsencrypt.conf" snippetLetsencryptLoc="/etc/nginx/snippets/letsencrypt.conf"
siteLetsencryptWww="/var/www/letsencrypt" siteLetsencryptWww="/var/www/letsencrypt"
@@ -58,7 +58,7 @@ step_3_info() {
} }
step_3() { step_3() {
exe apt install $phpPackages exe apt install $phpPackages
endReturn -o $? "$phpName error during startup" endReturn "$phpName error during startup"
} }
phpFpmConfigLocation="/etc/php/${phpVersion}/fpm/conf.d/90-custom_pi.ini" phpFpmConfigLocation="/etc/php/${phpVersion}/fpm/conf.d/90-custom_pi.ini"
phpFpmConfig="\ phpFpmConfig="\
@@ -88,9 +88,9 @@ step_4() {
echo -n "Restarting ${phpName} ..." echo -n "Restarting ${phpName} ..."
exe service ${phpName}-fpm restart exe service ${phpName}-fpm restart
endReturn -o $? "$phpName error during restart" endReturn "$phpName error during restart"
echo "ok" echo "ok"
} }
VERSION_SEQREV=10 readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

7
seqs/whoogle.cfg.example Normal file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
readonly sc_whoogleDir="/opt/whoogle-search"
readonly sc_whoogleUser="whoogle"
readonly sc_whoogleHost="0.0.0.0"
readonly sc_whooglePort="5000"

108
seqs/whoogle.sh Executable file
View File

@@ -0,0 +1,108 @@
#!/usr/bin/env bash
readonly toolName=whoogle
readonly toolDeps=(libcurl4-openssl-dev libssl-dev)
sq_aptOpt=
readonly sq_gitUrl="https://github.com/benbusby/whoogle-search.git"
seq_config() {
## or to use sequencer api with global config file:
if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
# End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
## Disable error checks if external scripts are used
## e.g. error on unbound variables
#disableErrorCheck
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Show status of ${toolName}"; }
step_1_alias() { echo "status"; }
step_1() {
exep service whoogle status '2>/dev/null' || error "${toolName}" not installed
}
step_20_info() {
echo "Git clone ${toolName} and use as python venv"
echoinfo "(${sq_gitUrl})"
}
step_20_alias() { echo "install"; }
step_20() {
info "Installing dependencies"
exe apt-get install "${toolDeps[@]}" ${sq_aptOpt}
info "Installing ${toolName} from ${sq_gitUrl}"
exe git clone "${sq_gitUrl}" "${sc_whoogleDir:?}"
endReturn "Cloning ${toolName} failed"
exe cd "${sc_whoogleDir:?}"
exe python3 -m venv venv
#exe source venv/bin/activate
step postupgrade
}
step_21_info() { echo "Create system user ${sc_whoogleUser:-'whoogle'}"; }
step_21() {
exe adduser --disabled-password --disabled-login --no-create-home --gecos "" "${sc_whoogleUser:?}"
}
step_22_info() { echo "Create systemd service"; }
step_22() {
addConf -s "${sc_whoogleService}" "${sc_whoogleServiceLoc}"
exe systemctl daemon-reload
exe systemctl enable --now "${toolName}.service"
}
sc_whoogleServiceLoc="/etc/systemd/system/whoogle.service"
sc_whoogleService="[Unit]
Description=Whoogle
[Service]
# Load values from dotenv only
Environment=WHOOGLE_DOTENV=1
Type=simple
User=${sc_whoogleUser}
WorkingDirectory=${sc_whoogleDir}
ExecStart=${sc_whoogleDir}/venv/bin/python3 -um app --host ${sc_whoogleHost:-"0.0.0.0"} --port ${sc_whooglePort:-"5000"}
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=3
SyslogIdentifier=whoogle
[Install]
WantedBy=multi-user.target"
step_30_info() { echo "Upgrade installation using git"; }
step_30_alias() { echo "upgrade"; }
step_30() {
exe cd "${sc_whoogleDir:?}"
endReturn "${toolName} doesn't seam to be installed"
exe service "${toolName}" stop
exe git pull
}
step_31_info() { echo "Post upgrade steps"; }
step_31_alias() { echo "postupgrade"; }
step_31() {
exe "${sc_whoogleDir:?}/venv/bin/pip" install -r "${sc_whoogleDir:?}/requirements.txt"
exe chown "${sc_whoogleUser:?}": "${sc_whoogleDir:?}" -R
}
step_32_info() { echo "Restart ${toolName} service"; }
step_32_alias() { echo "restart"; }
step_32() {
exe service "${toolName}" restart
}
# shellcheck disable=SC2034 # Appears unused
readonly sqr_minVersion=16
# shellcheck disable=SC1091 # Don't follow this source
. /usr/local/bin/sequencer.sh

View File

@@ -1,33 +1,14 @@
#!/bin/bash #!/bin/bash
toolName=wireguard readonly toolName=wireguard
toolBin=wg readonly toolDefaultConf=wg0
toolDefaultConf=wg0 readonly toolService=wg-quick@$toolDefaultConf
toolService=wg-quick@$toolDefaultConf
# Get script working directory
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG=0
CONFIG_FILE_NAME="${toolName}.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
#step_config() {
#echo "Called once before executing steps."
## e.g. to source a config file manually:
#. "$CONFIG_FILE"
## or to use sequencer api:
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
#if [ $? -eq 0 ] ; then
# CONFIG=1
#fi
#}
step_1_info() { echo "Prepare installation of $toolName"; } step_1_info() { echo "Prepare installation of $toolName"; }
step_1_alias() { ALIAS="install"; } step_1_alias() { echo "setup"; }
step_1() { step_1() {
exe apt install raspberrypi-kernel-headers exe apt install raspberrypi-kernel-headers
endReturn -o $? "Installation of kernel headers failed" endReturn "Installation of kernel headers failed"
addConf -s "deb http://deb.debian.org/debian/ unstable main" "/etc/apt/sources.list.d/unstable.list" addConf -s "deb http://deb.debian.org/debian/ unstable main" "/etc/apt/sources.list.d/unstable.list"
exep "wget -O - https://ftp-master.debian.org/keys/archive-key-$(lsb_release -sr).asc | sudo apt-key add -" exep "wget -O - https://ftp-master.debian.org/keys/archive-key-$(lsb_release -sr).asc | sudo apt-key add -"
addConf -s "$pinEntry" "/etc/apt/preferences.d/limit-unstable" addConf -s "$pinEntry" "/etc/apt/preferences.d/limit-unstable"
@@ -38,9 +19,10 @@ Pin: release a=unstable
Pin-Priority: 150" Pin-Priority: 150"
step_2_info() { echo "Installing $toolName"; } step_2_info() { echo "Installing $toolName"; }
step_2_alias() { echo "install"; }
step_2() { step_2() {
local aptOpt="" local aptOpt=""
if [ $QUIET -ne 0 ] ; then if quiet ; then
aptOpt="-y" aptOpt="-y"
fi fi
exe apt install $toolName $aptOpt exe apt install $toolName $aptOpt
@@ -50,7 +32,7 @@ step_3_info() {
echo "Enable ipv4 forwarding to allow local access via VPN" echo "Enable ipv4 forwarding to allow local access via VPN"
echoinfo "(may be skipped)" echoinfo "(may be skipped)"
} }
step_3_alias() { ALIAS="ipv4"; } step_3_alias() { echo "ipv4"; }
step_3() { step_3() {
exe perl -pi -e 's/#{1,}?net.ipv4.ip_forward ?= ?(0|1)/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf exe perl -pi -e 's/#{1,}?net.ipv4.ip_forward ?= ?(0|1)/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf
} }
@@ -61,19 +43,19 @@ step_4() {
} }
step_10_info() { echo "Start default configuration $toolDefaultConf"; } step_10_info() { echo "Start default configuration $toolDefaultConf"; }
step_10_alias() { ALIAS="start"; } step_10_alias() { echo "start"; }
step_10() { step_10() {
exe wg-quick up wg0 exe wg-quick up wg0
} }
step_12_info() { echo "Stop default configuration $toolDefaultConf"; } step_12_info() { echo "Stop default configuration $toolDefaultConf"; }
step_12_alias() { ALIAS="stop"; } step_12_alias() { echo "stop"; }
step_12() { step_12() {
exe wg-quick down wg0 exe wg-quick down wg0
} }
step_14_info() { echo "Enable default configuration $defaultConfLoc"; } step_14_info() { echo "Enable default configuration $defaultConfLoc"; }
step_14_alias() { ALIAS="enable"; } step_14_alias() { echo "enable"; }
step_14() { step_14() {
if [ ! -r "$defaultConfLoc" ] ; then if [ ! -r "$defaultConfLoc" ] ; then
endReturn -o 1 "Default configuration \"$defaultConfLoc\" not found" endReturn -o 1 "Default configuration \"$defaultConfLoc\" not found"
@@ -82,12 +64,7 @@ step_14() {
} }
defaultConfLoc="/etc/$toolName/$toolDefaultConf.conf" defaultConfLoc="/etc/$toolName/$toolDefaultConf.conf"
# shellcheck disable=SC2034 # Appears unused
step_20_info() { echo "Usage notes"; } readonly sqr_minVersion=16
step_20() { # shellcheck disable=SC1091 # Don't follow this source
echo " [I] Some usage Notes"
}
VERSION_SEQREV=11
. /usr/local/bin/sequencer.sh . /usr/local/bin/sequencer.sh

1734
sequencer.sh Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

104
sequpgrade.sh Executable file
View File

@@ -0,0 +1,104 @@
#!/usr/bin/env bash
# Upgrade existing seqs (<16) to be compatible with sequencer 16
# Please review the changes especially for informational output
# Holds all files which should be upgraded
sq_files=()
step_1_info() { echo "Check or upgrade files"; }
step_1_options() { echo "[--execute] [FILE ...]"; }
step_1_alias() { echo "upgrade"; }
step_1() {
local file=
local execute=
shift
if [[ "${1:-}" == --execute ]] ; then
execute="${1}"
shift
fi
for file in "$@" ; do
if [ ! -w "${file}" ] ; then
error "No permission to write ${file}"
return 1
elif [ ! -d "${file}" ] ; then
sq_files+=("${file}")
fi
done
exe makechanges ${execute}
}
makechanges() {
local file=
local inplace="-n"
local sedprint="gp"
if [[ "${1:-}" == --execute ]] ; then
info "Executing..."
inplace="-i"
sedprint="g"
fi
for file in "${sq_files[@]}" ; do
echo "Update: ${file}"
exe sed ${inplace} 's/\[* ${*DRY}* \(-eq\|==\) 0 \]* &&/dry ||/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*DRY}* \(-eq\|==\) 0 \]*/! dry/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*DRY}* \(-ne\|!=\) 0 \]*/dry/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*QUIET}* \(-ne\|!=\) 0 \]*/quiet/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*QUIET}* \(-eq\|==\) 0 \]*/interactive/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*QUIET}* \(-ne\|!=\) 2 \]* &&/silent ||/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*QUIET}* \(-ne\|!=\) 2 \]*/! silent/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*VERBOSE}* \(-eq\|==\) 0 \]*/! verbose/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*CONTEXT_HELP}* \(-eq\|==\) 0 \]* &&/contextHelp ||/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*CONTEXT_HELP}* \(-eq\|==\) 0 \]*/! contextHelp/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*CONTEXT_HELP}* \(-ne\|!=\) 0 \]*/contextHelp/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*CONTEXT_EXE}* \(-eq\|==\) 0 \]* &&/contextExe ||/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*CONTEXT_EXE}* \(-eq\|==\) 0 \]*/! contextExe/'${sedprint} "${file}"
exe sed ${inplace} 's/\[* ${*CONTEXT_EXE}* \(-ne\|!=\) 0 \]*/contextExe/'${sedprint} "${file}"
exe sed ${inplace} 's/echoseq " \[I\] /info "/'${sedprint} "${file}"
exe sed ${inplace} 's/echoseq " \[W\] /warning "/'${sedprint} "${file}"
exe sed ${inplace} 's/echoseq " \[E\] /error "/'${sedprint} "${file}"
exe sed ${inplace} 's/echoseq/info/'${sedprint} "${file}"
exe sed ${inplace} 's/echoerr " \[I\] /info -e "/'${sedprint} "${file}"
exe sed ${inplace} 's/echoerr " \[W\] /warning -e "/'${sedprint} "${file}"
exe sed ${inplace} 's/echoerr " \[E\] /error -e "/'${sedprint} "${file}"
exe sed ${inplace} 's/echoerr/error -e/'${sedprint} "${file}"
exe sed ${inplace} 's/echo " \[I\] /info "/'${sedprint} "${file}"
exe sed ${inplace} 's/echo " \[W\] /warning "/'${sedprint} "${file}"
exe sed ${inplace} 's/echo " \[E\] /error "/'${sedprint} "${file}"
exe sed ${inplace} 's/outColor/color/'${sedprint} "${file}"
exe sed ${inplace} 's/endReturn -o \$?/endReturn/'${sedprint} "${file}"
exe sed ${inplace} 's/"*${*DEFAULT_EDITOR_SYSTEM}*"*/editor/'${sedprint} "${file}"
exe sed ${inplace} 's/endCheckEmpty/endIfEmpty/'${sedprint} "${file}"
exe sed ${inplace} 's/^[[:space:]]*step_config/seq_config/'${sedprint} "${file}"
exe sed ${inplace} 's/^\(step_.*_alias\)()[[:space:]]*{[[:space:]]*ALIAS=/\1() { echo /'${sedprint} "${file}"
exe sed ${inplace} 's/SEQUENCER_ARGS/sqr_args/'${sedprint} "${file}"
exe sed ${inplace} 's/STEP_ARGS/seq_args/'${sedprint} "${file}"
exe sed ${inplace} 's/SEQ_CONFIG_HOME/seq_configRoot/'${sedprint} "${file}"
exe sed ${inplace} 's/SEQ_CONFIG_FILE/seq_configFile/'${sedprint} "${file}"
exe sed ${inplace} 's/SEQ_PROFILE_NAME/seq_profileName/'${sedprint} "${file}"
exe sed ${inplace} 's/^VERSION_SEQREV.*/readonly sqr_minVersion=16/'${sedprint} "${file}"
exe sed ${inplace} 's/echoinfoArgs[[:space:]]\+"\([^"]\+\)"\([^;]\|$\)/# todo: manual intervention\nstep_xx_options() { echo "\1"; }/'${sedprint} "${file}"
exe sed ${inplace} \
's/^\(step_\([0-9]\+\)_info().*\)echoinfoArgs[[:space:]]\+"\([^"]\+\)"\;[[:space:]]*\(.*\)/\1\4\nstep_\2_options() { echo "\3"; }/'${sedprint}\
"${file}"
# Remove trailing spaces
exe sed ${inplace} 's/[[:space:]]\+$//'${sedprint} "${file}"
done
}
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -3,12 +3,13 @@
_sqn_completions() _sqn_completions()
{ {
local tempreply=()
# Current search string # Current search string
local cur=${COMP_WORDS[COMP_CWORD]} local cur=${COMP_WORDS[COMP_CWORD]}
# Extract alias command with buildins same as: # Extract alias command with buildins same as:
# local curCmd="$(alias $1 | sed "s/^alias.*\" \"\(.*\)\"'$/\1/")" # local curCmd="$(alias $1 | sed "s/^alias.*\" \"\(.*\)\"'$/\1/")"
local curCmd= local curCmd=
curCmd="$(alias "$1")" curCmd="$(alias "${1:-}")"
curCmd="${curCmd##*\" \"}" curCmd="${curCmd##*\" \"}"
curCmd="${curCmd%\"\'*}" curCmd="${curCmd%\"\'*}"
COMPREPLY=() COMPREPLY=()
@@ -35,7 +36,12 @@ _sqn_completions()
# provide completion for option with parameter # provide completion for option with parameter
-p|--profile) -p|--profile)
# sequencer.sh provides creation of a profile list with search functionality # sequencer.sh provides creation of a profile list with search functionality
read -r -a COMPREPLY <<<"$( "$curCmd" -pl "${cur}" 2>/dev/null)" IFS=$'\n' read -r -d '' -a tempreply <<<"$( "$curCmd" -pl "${cur}" 2>/dev/null)"
for comp in "${tempreply[@]}" ; do
# Support for profile names with spaces
COMPREPLY+=("$(printf '%q' "${comp}")")
done
[[ ${#COMPREPLY[@]} == 0 ]] && COMPREPLY=( "-- No profiles found --" " " )
;; ;;
*) *)
# Stop after step selection (last argument which is not an option (starting with "-|+") # Stop after step selection (last argument which is not an option (starting with "-|+")
@@ -50,7 +56,13 @@ _sqn_completions()
esac esac
fi fi
# sequencer.sh provides creation of a step list with search functionality # sequencer.sh provides creation of a step list with search functionality
read -r -a COMPREPLY <<<"$( "$curCmd" -ls "$cur" )" #read -r -a COMPREPLY <<<"$( "$curCmd" -ls "$cur" )"
IFS=$'\n' read -r -d '' -a tempreply <<<"$( "$curCmd" -ls "$cur" )"
for comp in "${tempreply[@]}" ; do
# Support for aliases with spaces
COMPREPLY+=("$(printf '%q' "${comp}")")
done
[[ ${#COMPREPLY[@]} == 0 ]] && COMPREPLY=( "-- No steps found --" " " )
;; ;;
esac esac
;; ;;
@@ -66,24 +78,25 @@ installCompletion() {
. "${script_dir}/sequencer.cfg" >/dev/null 2>&1 . "${script_dir}/sequencer.cfg" >/dev/null 2>&1
local SEQBASE="${script_dir}/seqs" local seq_base="${script_dir}/seqs"
local SEQPREFIX="sqn_" local seq_prefix="sqn_"
local SEQSHORT=() local seq_short=()
local seq_list=()
# Check for user selected sequences # Check for user selected sequences
[ -e "$SEQUENCER_USER_SEQS" ] && SEQBASE="$SEQUENCER_USER_SEQS" [ -e "$SEQUENCER_USER_SEQS" ] && seq_base="$SEQUENCER_USER_SEQS"
# Create aliases and command (alias) list for "complete" command" # Create aliases and command (alias) list for "complete" command"
IFS=$'\n' read -r -d '' -a SEQLIST < <(ls -1 "$SEQBASE/${cur}"*.sh) IFS=$'\n' read -r -d '' -a seq_list < <(ls -1 "${seq_base}/${cur}"*.sh)
for i in "${!SEQLIST[@]}"; do for i in "${!seq_list[@]}"; do
SEQLIST[$i]="${SEQLIST[$i]##*/}" seq_list[$i]="${seq_list[$i]##*/}"
SEQLIST[$i]="${SEQLIST[$i]%.*}" seq_list[$i]="${seq_list[$i]%.*}"
SEQSHORT[$i]="${SEQPREFIX}${SEQLIST[$i]/[[:blank:]]/_}" seq_short[$i]="${seq_prefix}${seq_list[$i]/[[:blank:]]/_}"
# shellcheck disable=SC2139,SC2086 # shellcheck disable=SC2139,SC2086
# alias should be expanded when defined # alias should be expanded when defined
alias ${SEQSHORT[$i]}="_SQN_ALIAS=\"${SEQSHORT[$i]}\" \"$SEQBASE/${SEQLIST[$i]}.sh\"" alias ${seq_short[$i]}="_sqn_alias=\"${seq_short[$i]}\" \"${seq_base}/${seq_list[$i]}.sh\""
done done
complete -o nosort -o bashdefault -o default -F _sqn_completions "${SEQSHORT[@]}" complete -o nosort -o bashdefault -o default -F _sqn_completions "${seq_short[@]}"
} }
installCompletion installCompletion