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
missingConf.log
*.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
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/
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
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
@@ -27,7 +27,7 @@ Run folloing commands as root:
```
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
```
or
@@ -62,8 +62,8 @@ To make these changes active run the following commands. You don't need the last
```
unalias -a
source ~/.bashrc
source /opt/sequencer/sqnall-completion.bash
. ~/.bashrc
. /opt/sequencer/sqn-completion.bash
```
or simply logout from the current session and login again.

View File

@@ -1,66 +1,83 @@
#!/bin/bash
# shellcheck disable=SC1090 # dynamically sourced file
SEQGITURL="https://winklerfamilie.eu/git/efelon/shell_sequencer.git"
DEFAULT_DIR="/opt/sequencer"
DEFAULT_USER_SEQS="/opt/seqs"
SEQUENCER_DIR=
readonly sequencerGitUrl="https://winklerfamilie.eu/git/efelon/shell_sequencer.git"
defaultBranch="master"
readonly defaultDir="/opt/sequencer"
readonly defaultUserSeqs="/opt/seqs"
readonly sequencerBin="/usr/local/bin/sequencer.sh"
sequencerDir=
# 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
if [ -z "$SEQUENCER_DIR" ]; then
[ -w "$(dirname "$DEFAULT_DIR")" ] && SEQUENCER_DIR="$DEFAULT_DIR"
sequencerDir="${1:-}"
# Installation directory was not set by argument $1
if [ -z "${sequencerDir}" ]; then
[ -w "$(dirname -- "${defaultDir}")" ] && sequencerDir="${defaultDir}"
# Fallback to working directory
[ -z "$SEQUENCER_DIR" ] && SEQUENCER_DIR="${WDIR}/sequencer"
[ -z "${sequencerDir}" ] && sequencerDir="${workDir}/sequencer"
fi
# Check if already installed
if [ -d "$SEQUENCER_DIR" ]; then
echo " [E] Sequencer seems to be already installed at:"
echo " $SEQUENCER_DIR"
if [ -d "${sequencerDir}" ]; then
if [[ $(readlink -- "${sequencerBin}") != ${sequencerDir}/sequencer.sh ]] && [[ -e "${sequencerDir}/sequencer.sh" ]] ; then
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
fi
if [ ! -w "$(dirname "$SEQUENCER_DIR")" ]; then
echo " [E] Your user has no permission to write to $(dirname "$SEQUENCER_DIR")"
if [ ! -w "$(dirname -- "${sequencerDir}")" ]; then
echo " [e] Your user has no permission to write to $(dirname -- "${sequencerDir}")"
exit 2
fi
# Install git if neccessary
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
echo " [W] Cannot update apt repositories"
echo " [w] Cannot update apt repositories"
fi
if ! apt install git -y; then
echo " [E] Cannot install git via apt"
echo " [e] Cannot install git via apt"
exit 3
fi
fi
# Clone sequncer to target directory
if ! git clone $SEQGITURL "$SEQUENCER_DIR"; then
echo " [E] Error cloning git repository:"
echo " $SEQGITURL"
if ! git clone --branch "${defaultBranch}" "${sequencerGitUrl}" "$sequencerDir"; then
echo " [e] Error cloning git repository:"
echo " ${sequencerGitUrl}"
exit 4
fi
# 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
[ -z "$SEQUENCER_USER_SEQS" ] && SEQUENCER_USER_SEQS="$DEFAULT_USER_SEQS"
[ -z "${SEQUENCER_USER_SEQS}" ] && SEQUENCER_USER_SEQS="${defaultUserSeqs}"
# Install sequncer script
ln -s "${SEQUENCER_DIR}/sequencer/sequencer.sh" "/usr/local/bin"
if [ "$SEQUENCER_USER_SEQS" != "$SEQUENCER_DIR/seqs" ]; then
ln -sT "${SEQUENCER_DIR}/seqs" "${SEQUENCER_USER_SEQS}"
ln -s "${sequencerDir}/sequencer.sh" "/usr/local/bin"
if [ "${SEQUENCER_USER_SEQS}" != "${sequencerDir}/seqs" ]; then
ln -sT "${sequencerDir}/seqs" "${SEQUENCER_USER_SEQS}"
fi
echo " [I] Successfully installed shell sequencer"
echo " to: $SEQUENCER_DIR"
echo " [i] Successfully installed shell sequencer"
echo " to: ${sequencerDir}"

View File

@@ -1,21 +1,21 @@
#!/usr/bin/env bash
# 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() {
local SEQCOMP_LOC="${sq_dir}/sqn-completion.bash"
local SEQCOMP_LOADER="$HOME/.bashrc"
local SEQCOMP_SOURCE=". \"$SEQCOMP_LOC\""
local seqcomp_loc="${sq_dir}/sqn-completion.bash"
local seqcomp_loader="$HOME/.bashrc"
local seqcomp_source=". \"${seqcomp_loc}\""
if grep "$SEQCOMP_SOURCE" "$SEQCOMP_LOADER" >>/dev/null 2>&1; then
echo " [I] Completion already installed ($SEQCOMP_LOADER)"
if grep "${seqcomp_source}" "${seqcomp_loader}" >>/dev/null 2>&1; then
echo " [i] Completion already installed (${seqcomp_loader})"
else
echo "$SEQCOMP_SOURCE" >>"$SEQCOMP_LOADER"
echo " [I] Sequence bash-completion installed"
echo "${seqcomp_source}" >>"${seqcomp_loader}"
echo " [i] Sequence bash-completion installed"
fi
# shellcheck source=sqn-completion.bash
. "$SEQCOMP_LOC"
. "${seqcomp_loc}"
}
_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
# (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
SCRIPT_NAME=$(basename -- $0)
SCRIPT_NAME=${SCRIPT_NAME%%.*}
@@ -15,7 +15,7 @@ CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
aptOpt=
step_config() {
seq_config() {
#echo "Called once before executing steps."
## e.g. to source a config file manually:
#. "$CONFIG_FILE"
@@ -27,14 +27,14 @@ step_config() {
CONFIG=1
else
# End if no configuration file exists
[ $DRY -eq 0 ] && return 1
dry || return 1
fi
[ $QUIET -ne 0 ] && aptOpt="-y"
quiet && aptOpt="-y"
return 0
}
step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
exe apt install $toolDeps $aptOpt
@@ -54,11 +54,11 @@ ariaConfLoc="/etc/aria2/aria2.conf"
step_3_info() { echo "Create $toolName service"; }
step_3_alias() { ALIAS="service"; }
step_3_alias() { echo "service"; }
step_3() {
addConf -s "$ariaService" "$ariaServiceLoc"
exe systemctl daemon-reload
echoseq " [I] Serive not started or enabled"
info "Service not started or enabled"
}
ariaServiceLoc="/etc/systemd/system/aria2.service"
ariaService="[Unit]
@@ -76,10 +76,11 @@ Restart=on-failure
WantedBy=multi-user.target"
step_10_info() { echo "Add ufw rule for rpc port 6800"; }
step_10_alias() { ALIAS="ufw"; }
step_10_alias() { echo "ufw"; }
step_10() {
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

View File

@@ -3,10 +3,10 @@
# Backup sequence definitions
# A running debian needs at least the following runtime directories created to start up successfully:
## dev
## dev
## proc
## sys
## run
## run
BACKUP_TARGET="/backup"
# Exclude notation "directory/*" creates the directory but NOT its content

View File

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

View File

@@ -3,66 +3,67 @@
# Collection of simple setup tasks
# e.g. Ability to send mail (ssmtp)
# Get script working directory
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
WSUBDIR="${WDIR}/basics"
sc_configLoc="./basics"
#step_config() {
seq_config() {
# echo "Called once before executing steps."
# echo "e.g. to source a config file:"
# #. "$CONFIG_FILE"
#}
sc_configLoc="${seq_origin}/basics"
}
step_10_info() { echo "ssmtp installation"; }
step_10_alias() { ALIAS="ssmtp"; }
step_10_alias() { echo "ssmtp"; }
step_10() {
exe apt update && apt install "$SSMTP_DEPS"
endReturn -o $? "ssmtp installation failed"
exe apt update && apt install $SSMTP_DEPS
endReturn "ssmtp installation failed"
}
SSMTP_DEPS="ssmtp"
step_11_info() { echo "ssmtp setup"; }
step_11_alias() { ALIAS="ssmtpSetup"; }
step_11_alias() { echo "ssmtpSetup"; }
step_11() {
if [ ! -f "$CONFIG_FILE_SSMTP" ] ; then
echoerr " [E] User config ($CONFIG_FILE_SSMTP) not found"
echoerr " See $CONFIG_FILE_SSMTP_TEMPLATE"
error -e "User config ($CONFIG_FILE_SSMTP) not found"
error -e " See $CONFIG_FILE_SSMTP_TEMPLATE"
return 1
fi
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
echoerr " [W] User aliases ($CONFIG_FILE_SSMTP_AL) not found"
echoerr " See $CONFIG_FILE_SSMTP_TEMPLATE or modify $CONFIG_LOC_SSMTP_AL directly"
warning -e "User aliases ($CONFIG_FILE_SSMTP_AL) not found"
error -e " See $CONFIG_FILE_SSMTP_TEMPLATE or modify $CONFIG_LOC_SSMTP_AL directly"
return 1
fi
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_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_AL="$WSUBDIR/revaliases.cfg"
CONFIG_FILE_SSMTP_AL="$sc_configLoc/revaliases.cfg"
CONFIG_FILE_SSMTP_AL_TEMPLATE="${CONFIG_FILE_SSMTP}.example"
step_13_info() {
echo -n "Send test E-Mail to "
if [ -z $2 ] ; then echo "<MAILADDRESS>"; else echo "$2"; fi
}
step_13_alias() { ALIAS="ssmtpTest"; }
step_13() {
if [ ! -z "$2" ] || [ "$2" == "" ] ; then
echoerr " [E] No mailaddress provided"
step_13_info() {
echo -n "Send test E-Mail"
if [ -z "${2:-}" ] ; then
echo " to MAILADDRESS"
else
echo " to ${2}"
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_alias() { ALIAS="ssmtpHelp"; }
step_15_alias() { echo "ssmtpHelp"; }
step_15() {
echo " Configuration files expected by this seq:"
echo
@@ -77,5 +78,53 @@ step_15() {
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

View File

@@ -1,5 +1,5 @@
# sSMTP aliases
#
#
# Format: local_account:outgoing_address:mailhub
#
# Example: root:your_login@your.domain:mailhub.your.domain[:port]

View File

@@ -5,7 +5,7 @@
# Make this empty to disable rewriting.
root=postmaster
# The place where the mail goes. The actual machine name is required no
# The place where the mail goes. The actual machine name is required no
# MX records are consulted. Commonly mailhosts are named mail.domain.com
mailhub=host:port
#AuthUser=

View File

@@ -15,25 +15,25 @@ 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:
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
dry || return -1
fi
## 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 0
}
step_1_info() { echo "Install dependencies"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
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 usermod -aG users $CALWEB_USER
else
echoseq " [W] User $CALWEB_USER already exists"
warning "User $CALWEB_USER already exists"
fi
if [ ! -e "$CALWEB_VENV_ROOT/bin" ]; then
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"
else
echoseq " [W] Virtual env. $CALWEB_VENV_ROOT already exists"
warning "Virtual env. $CALWEB_VENV_ROOT already exists"
fi
}
@@ -61,7 +61,7 @@ step_3() {
exe ${CALWEB_VENV_ROOT}/bin/pip install $toolPipName
}
step_4_info() {
step_4_info() {
echo "Install $toolName features"
echoinfo ${toolFeatures[*]}
}
@@ -70,6 +70,8 @@ step_4() {
toolFeatures[$i]="$toolPipName[${toolFeatures[$i]}]"
done
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"; }
@@ -86,16 +88,16 @@ step_6() {
}
step_15_info() { echo "Upgrade python pip"; }
step_15_alias() { ALIAS="upgradepip"; }
step_15_alias() { echo "upgradepip"; }
step_15()
{
exe ${CALWEB_VENV_ROOT}/bin/pip install --upgrade pip
}
step_100_info() { echo "Setup notes"; }
step_100_alias() { ALIAS="notes"; }
step_100_alias() { echo "notes"; }
step_100() {
outColor green
color green
cat <<NOTES_END
# Default admin login:
@@ -127,5 +129,5 @@ proxy_set_header X-Script-Name /calibre; # IMPORTANT: path has NO trai
NOTES_END
}
VERSION_SEQREV=15
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -2,7 +2,7 @@
# Web root path where certbot will place the ACME challenge files
#
# A nginx example location which needs to placed in the server config listening on port 80
# A nginx example location which needs to placed in the server config listening on port 80
# for the first time and also in the config listeing on port 443 for renewals:
#
# location ^~ /.well-known/acme-challenge/ {

View File

@@ -3,65 +3,58 @@
# Certbot installation and creation supporting Raspbian and Ubuntu.
# Certificate can be created/updated as "certonly" only.
toolName=certbot
readonly toolName=certbot
# 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"
sq_aptOpt=
step_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
local confReturn=$?
if [ $confReturn -eq 0 ] ; then
CONFIG=1
seq_config() {
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 0
}
step_1_info() { echo "Install $toolName for letsencrypt"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
local osName=
local distName=
if [ "$(which lsb_release)" == "" ] ; then
echoerr " [W] Cannot detect OS. Assuming Ubuntu"
warning -e "Cannot detect OS. Assuming Ubuntu"
osName="Ubuntu"
else
else
osName=$(lsb_release -is)
distName=$(lsb_release -cs)
fi
if [ "$osName" == "" ] ; then
echoerr " [W] Error dedecting OS. Assuming Ubuntu"
warning -e "Error dedecting OS. Assuming Ubuntu"
osName="Ubuntu"
fi
echo " [I] Detected OS: $osName $distName"
local aptOption=
if [ $QUIET -ne 0 ] ; then
aptOption="-y"
else
aptOption=""
fi
info "Detected OS: $osName $distName"
if [ "$osName" == "Ubuntu" ] ; then
exe apt-get update
exe apt-get install software-properties-common $aptOption
exe apt-get install software-properties-common ${sq_aptOpt}
saveReturn $?
exe add-apt-repository universe $aptOption
exe add-apt-repository universe ${sq_aptOpt}
saveReturn $?
exe add-apt-repository ppa:certbot/certbot $aptOption
exe add-apt-repository ppa:certbot/certbot ${sq_aptOpt}
saveReturn $?
exe apt-get update
exe apt-get install $toolName $aptOption
exe apt-get install $toolName ${sq_aptOpt}
saveReturn $?
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 install certbot
endReturn "$toolName installation for $osName failed"
@@ -69,15 +62,23 @@ step_1() {
}
step_2_info() { echo "Create or update letsencrypt certificate"; }
step_2_alias() { ALIAS="update"; }
step_2_alias() { echo "update"; }
step_2() {
endCheckEmpty CERTBOT_DOMAINS "No domain list found. Check configuration"
endCheckEmpty CERTBOT_WEBROOT "Invalid web root. Check configuration"
endCheckEmpty CERTBOT_MAIL "Invalid mail address. Check configuration"
endIfEmpty CERTBOT_DOMAINS "No domain list found. Check configuration"
endIfEmpty CERTBOT_WEBROOT "Invalid web root. Check configuration"
endIfEmpty CERTBOT_MAIL "Invalid mail address. Check configuration"
exe certbot certonly --webroot -w "$CERTBOT_WEBROOT" --rsa-key-size 4096 --expand --agree-tos \
-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

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
toolName=coturn
toolDeps="coturn miniupnpc"
toolConf="/etc/turnserver.conf"
toolServiceName="coturn.service"
publicIpRetry=20
readonly toolName="coturn"
readonly toolDeps="coturn miniupnpc"
readonly toolConf="/etc/turnserver.conf"
readonly toolServiceName="coturn.service"
readonly publicIpRetry=20
# Get script working directory
# (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"
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"
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
}
step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
exe apt install $toolDeps $APTOPT
exe apt install $toolDeps ${sq_aptOpt:-}
}
step_10_info() {
@@ -47,64 +33,110 @@ step_10_info() {
echoinfo " -l : Always output update required and error information"
echoinfo " (even with -qq)"
}
step_10_alias() { ALIAS="updateip"; }
step_10_alias() { echo "updateip"; }
step_10() {
exitIfRunning
if running ; then
error "$toolName already running"
return 1
fi
shift
local retryCount=$publicIpRetry
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 dnsUrl="46.182.19.48" #digitalcourage.de/support/zensurfreier-dns-server
local dnsFallbackUrl="194.150.168.168" #dns.as250.net; Berlin/Frankfurt
local lecho="echoseq"
if [ "$1" == "-l" ]; then
lecho="echo"
shift
local lLevelSave=${LOG_LEVEL:?}
local lTimeSave=${LOG_TIME:-}
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
local pubIp
while [ $retryCount -gt 0 ]; do
pubIp=`"$(command -v upnpc)" -s | grep ^ExternalIPAddress | cut -c21-`
[ $? -eq 0 ] && ipUpdater="upnpc" && break || "$lecho" "[$(date)] [W] Upnpc failed"
pubIp=$(dig @$dnsUrl +short +timeout=1 cloud.imoff.de 2>>/dev/null)
[ $? -eq 0 ] && ipUpdater="DNS" && break || "$lecho" "[$(date) [W] DNS lookup to $dnsUrl failed"
pubIp=$(dig @$dnsFallbackUrl +short +timeout=1 cloud.imoff.de 2>>/dev/null)
[ $? -eq 0 ] && ipUpdater="DNS Fallback" && break || "$lecho" "[$(date)] [W] DNS lookup to $dnsFallbackUrl failed"
pubIp=$("$(command -v upnpc)" -s | grep ^ExternalIPAddress | cut -c21-)
[ $? -eq 0 ] && ipUpdater="upnpc" && break || error "Upnpc failed"
pubIp=$(dig @$dnsUrl +short +timeout=1 ${sc_turnDomain:?} 2>>/dev/null)
[ $? -eq 0 ] && ipUpdater="DNS" && break || error "DNS lookup to $dnsUrl failed"
pubIp=$(dig @$dnsFallbackUrl +short +timeout=1 ${sc_turnDomain:?} 2>>/dev/null)
[ $? -eq 0 ] && ipUpdater="DNS Fallback" && break || error "DNS lookup to $dnsFallbackUrl failed"
((retryCount--))
done
if [[ ! $pubIp =~ $ipRegex ]]; then
"$lecho" "[$(date)] [E] Couldn't aquire public IP. Giving up."
return 1
fi
warning "Couldn't aquire public IP for ${sc_turnDomain}. Giving up."
retval=1
local confIp=`cat "$toolConf" | grep "^external-ip" | cut -d'=' -f2`
if [ "$pubIp" != "$confIp" ]; then
$lecho "[$(date)] [I] Update required (via $ipUpdater). New public ip: $pubIp"
exe sed -i "s/^external-ip[[:space:]]*=.*/external-ip=${pubIp}/" "$toolConf"
exe sleep 1
$lecho "[$(date)] [I] Restarting $toolName"
exe /bin/systemctl restart $toolServiceName
else
echoseq "[$(date)] [I] No update required (via $ipUpdater). Current ip: $confIp"
local confIp=`cat "$toolConf" | grep "^external-ip" | cut -d'=' -f2`
if [ "$pubIp" != "$confIp" ]; then
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 sleep 1
exe /bin/systemctl restart $toolServiceName
elif (( ! lSilent )) ; then
info "No update required for ${sc_turnDomain} (via $ipUpdater). Current ip: $confIp"
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_alias() { ALIAS="cronip"; }
step_12_alias() { echo "cronip"; }
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"
}
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_alias() { ALIAS="notes"; }
step_100_alias() { echo "notes"; }
step_100_noconf=
step_100() {
outColor green
color green
cat <<COTURN_EOF
# Port forwarding
@@ -130,5 +162,7 @@ chmod g+r /etc/letsencrypt/archive/\$LOC_DOMAIN/privkey*
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

View File

@@ -14,27 +14,27 @@ 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 [ $? -eq 0 ] ; then
CONFIG=1
else
[ $DRY -eq 0 ] && return -1
dry || return -1
fi
[ $QUIET -ne 0 ] && APTOPT="-y"
quiet && APTOPT="-y"
return 0
}
step_1_info() {
step_1_info() {
echo "Install $toolName"
echoinfo "Default port: 5050"
}
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
exe apt install $toolDeps $APTOPT
exe pip install --upgrade pyopenssl
endReturn -o $? "Pip install pyopenssl failed"
endReturn "Pip install pyopenssl failed"
}
step_2_info() { echo "Clone git repository"; }
@@ -51,15 +51,15 @@ step_3() {
step_4_info() { echo "Create systemd service"; }
step_4() {
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
}
step_5_info() { echo "Add ufw rule for web interface"; }
step_5_alias() { ALIAS="ufw"; }
step_5_alias() { echo "ufw"; }
step_5() {
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

View File

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

View File

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

View File

@@ -19,7 +19,7 @@ EBU_SOURCE=
# Change the volume size to number MB. Default is 200MB.
#EBU_VOLSIZE=
# a command that runs duplicity e.g.
# a command that runs duplicity e.g.
# shape bandwidth use via trickle
# "trickle -s -u 640 -d 5120" # 5Mb up, 40Mb down"
#EBU_PRECMD=""
@@ -37,7 +37,7 @@ EBU_SOURCE=
#EBU_CRONTIME='1 2 * * *'
# Uncomment to save the output of the cron run to a logfile
# log file name will be "encBackup_profilename.log"
# log file name will be "encBackup_profilename.log"
#EBU_LOG_DIR='/var/log'
# Uncomment to log a message to syslog after

View File

@@ -1,42 +1,42 @@
#!/bin/bash
toolName=duplicity
readonly toolName=duplicity
readonly toolCronDir="/etc/cron.d"
readonly toolPrefix="encBackup_"
toolBin=
toolPpa="ppa:duplicity-team/duplicity-release-git"
toolCronDir="/etc/cron.d"
toolPrefix="encBackup_"
toolSyslogTag=
# 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_TEMPLATE="$WDIR/${SCRIPT_NAME}.cfg.example"
sq_aptOpt=
sq_config=0
step_config() {
initSeqConfig -p "$SCRIPT_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
seq_config() {
if initSeqConfig -p "${seq_fileName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
else
[ $DRY -eq 0 ] && return 1
dry || return 1
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 "
if [ $CONTEXT_HELP -ne 0 ] ; then
echo -n "selected profile"
if contextHelp ; then
echo "selected profile"
else
echo -n "profile: $SEQ_PROFILE_NAME"
echo "profile: $seq_profileName"
fi
echo " [OPTIONS] [full|incremental]"
echoinfo " [OPTIONS]"
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() {
shift
@@ -44,40 +44,43 @@ step_1() {
local retVal
local dupArgs
local purgeAfter=1
local lSourceMismatch=
for arg in "$@" ; do
case "$1" in
--no-purge|-n)
purgeAfter=0
shift
;;
shift ;;
--allow-source-mismatch|-a)
dupArgs+=("--allow-source-mismatch")
shift ;;
esac
done
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
fi
if [ ! -z "$1" ] && ( [ "$1" == "full" ] || [ "$1" == "incremental" ] ) ; then
if [ -n "${1:-}" ] && ( [ "$1" == "full" ] || [ "$1" == "incremental" ] ) ; then
dupArgs+=("$1")
elif [ ! -z "$1" ] ; then
echo " [W] $toolName command \"$1\" not recognized"
elif [ -n "${1:-}" ] ; then
warning "$toolName command \"$1\" not recognized"
return 1
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")
fi
if [ ! -z "$EBU_VOLSIZE" ] ; then
if [ -n "$EBU_VOLSIZE" ] ; then
dupArgs+=(--volsize "$EBU_VOLSIZE")
fi
checkInstalled
setPassphrase
exe $toolBin "${dupArgs[@]}" "$EBU_SOURCE" "$EBU_TARGET"
setPassphrase
exe $toolBin "${dupArgs[@]:-}" "${EBU_SOURCE:?}" "${EBU_TARGET:?}"
retVal=$?
unsetPassphrase
@@ -89,12 +92,12 @@ step_1() {
}
step_3_info() { echo "Verify selected backup"; }
step_3_alias() { ALIAS="verify"; }
step_3_alias() { echo "verify"; }
step_3() {
shift
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
fi
@@ -104,14 +107,15 @@ step_3() {
unsetPassphrase
}
step_5_info() {
echo "Restore [OPTIONS] <LOCAL TARGET> [TARGET]"
step_5_info() {
echo "Restore files from backup"
echoinfo " [OPTIONS]"
echoinfo " --file-to-restore, -f <RELPATH> : Relative path within backup"
echoinfo " (file or folder)"
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() {
shift
@@ -134,7 +138,7 @@ step_5() {
done
if [ -z "$1" ] ; then
echoerr " [E] No target provided"
error -e "No target provided"
return 1
fi
local ebuLocalTarget="$1"
@@ -144,95 +148,99 @@ step_5() {
fi
checkInstalled
setPassphrase
setPassphrase
exe $toolBin restore "${restoreOpt[@]}" "$EBU_TARGET" "$ebuLocalTarget"
unsetPassphrase
}
step_7_info() { echo "Purge old backups [TARGET]"; }
step_7_alias() { ALIAS="purge"; }
step_7_info() { echo "Purge old backups"; }
step_7_options() { echo '[TARGET]'; }
step_7_alias() { echo "purge"; }
step_7() {
shift
local ebuTarget="$EBU_TARGET"
local dupCommand=
if [ ! -z "$1" ] ; then
if [ -n "${1:-}" ] ; then
ebuTarget="$1"
fi
if [ ! -z "$EBU_MAX_AGE" ] ; then
dupCommand+="remove-older-than $EBU_MAX_AGE "
elif [ ! -z "$EBU_MAX_FULL_BACKUPS" ] ; then
elif [ ! -z "$EBU_MAX_FULL_BACKUPS" ] ; then
dupCommand+="remove-all-but-n-full $EBU_MAX_FULL_BACKUPS "
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 "
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
fi
checkInstalled
setPassphrase
setPassphrase
exe $toolBin $dupCommand --force "$ebuTarget"
unsetPassphrase
}
step_20_info() {
shift
local ebuTarget=$EBU_TARGET
[ ! -z "$1" ] && ebuTarget="$1"
if [ $CONTEXT_HELP -ne 0 ]; then
echo "Status of (profile) [TARGET]"
elif [ ! -z "$1" ]; then
local ebuTarget="${EBU_TARGET:-}"
[ ! -z "${1:-}" ] && ebuTarget="$1"
if contextHelp; then
echo "Status of (profile)"
elif [ -n "${1:-}" ]; then
echo "Status of target: $ebuTarget"
else
echo "Status of profile \"$SEQ_PROFILE_NAME\" target: $ebuTarget"
echo "Status of profile \"$seq_profileName\" target: $ebuTarget"
fi
}
step_20_alias() { ALIAS='status'; }
step_20_options() { echo '[TARGET]'; }
step_20_alias() { echo 'status'; }
step_20() {
shift
local ebuTarget="$EBU_TARGET"
if [ ! -z "$1" ] ; then
ebuTarget="$1"
fi
[[ -n "${1:-}" ]] && ebuTarget="$1"
checkInstalled
exe $toolBin collection-status "$ebuTarget"
}
step_22_info() { echo "List backup files [TARGET]"; }
step_22_alias() { ALIAS='list'; }
step_22_info() { echo "List backup files"; }
step_22_options() { echo '[TARGET]'; }
step_22_alias() { echo 'list'; }
step_22() {
shift
local ebuTarget="$EBU_TARGET"
if [ ! -z "$1" ] ; then
if [ -n "${1:-}" ] ; then
ebuTarget="$1"
fi
checkInstalled
setPassphrase
exe $toolBin list-current-files "$ebuTarget"
unsetPassphrase
}
step_70_info() {
step_70_info() {
echo -n "Manage cron file for "
if [ $CONTEXT_HELP -ne 0 ] ; then
if contextHelp ; then
echo -n "selected profile"
else
echo -n "profile: $SEQ_PROFILE_NAME"
echo -n "profile: $seq_profileName"
fi
echo " [OPTIONS]"
echoinfo " [OPTIONS]"
echoinfo " --remove, -r : remove cron file"
}
step_70_alias() { ALIAS='cron'; }
step_70_alias() { echo 'cron'; }
step_70_options() { echo '[OPTIONS]'; }
step_70() {
shift
local arg
local cronRemove=0
local cronScript="$toolCronDir/${toolPrefix}$SEQ_PROFILE_NAME"
local cronScript="$toolCronDir/${toolPrefix}$seq_profileName"
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
case "$1" in
@@ -244,7 +252,7 @@ step_70() {
done
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 chmod 600 "$cronLog"
fi
@@ -252,79 +260,75 @@ step_70() {
cronEntry+=" >$cronLog"
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"
else
checkFileHead "$cronScript" "$cronEntry"
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\""
syslogEntry "Cron file update complete [$EBU_CRONTIME]"
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
}
step_72_info() { echo "Update all profile cron files"; }
step_72_alias() { ALIAS="reload"; }
step_72_alias() { echo "reload"; }
step_72() {
for seq in "$SEQ_CONFIG_HOME/"* ; do
seq=$(basename ${seq})
$WDIR/$(basename -- $0) $SEQUENCER_ARGS -qq -p ${seq%%.*} cron
for seq in "$seq_configRoot/"* ; do
seq="$(basename -- "${seq}")"
exe "${seq_self}" -qq -p ${seq%%.*} cron
done
}
step_100_info() { echo "Install $toolName $toolPpa"; }
step_100_alias() { ALIAS="install"; }
step_100_info() { echo "Install $toolName"; }
step_100_alias() { echo "install"; }
step_100() {
local aptOpt=
if [ $QUIET -ne 0 ] ; then
aptOpt="-y"
fi
exe add-apt-repository $toolPpa $aptOpt
exe apt install $toolName $aptOpt
exe apt update
exe apt install $toolName ${sq_aptOpt}
}
setPassphrase() {
if [ -z $PASSPHRASE ] && [ ! -z $EBU_PASSPHRASE ] ; then
if [ -z "${PASSPHRASE:-}" ] && [ -n "${EBU_PASSPHRASE:-}" ] ; then
export PASSPHRASE="$EBU_PASSPHRASE"
fi
}
unsetPassphrase() {
unset PASSPHRASE
}
}
checkFileHead() {
local readChar
if [ ! -e "$1" ] ; then
echoerr " [E] File $1 not found"
if [ ! -e "${1:-}" ] ; then
error -e "File $1 not found"
return 1
fi
read -r -n ${#2} readChar < "$1"
if [ "$readChar" == "$2" ] ; then
if [ "$readChar" == "$2" ] ; then
return 0
fi
return 1
}
syslogEntry() {
if [ "$EBU_SYSLOG" == "true" ] ; then
if [[ "${EBU_SYSLOG:-}" == "true" ]] ; then
exe logger -t $toolSyslogTag "$@"
fi
}
checkInstalled() {
if [ -z "$toolBin" ] ; then
command -v $toolName >>/dev/null
if [ $? -ne 0 ] ; then
if ! command -v $toolName >>/dev/null ; then
step install
fi
toolBin="$EBU_PRECMD $(command -v $toolName)"
fi
toolBin="${EBU_PRECMD:-} $(escpath "$(command -v $toolName)")"
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

View File

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

View File

@@ -8,8 +8,8 @@ log_rate_limit: 100
hosts:
- "mydomain.eu"
listen:
-
listen:
-
port: 5222
ip: "::"
module: ejabberd_c2s
@@ -37,11 +37,11 @@ listen:
access: c2s
zlib: true
resend_on_timeout: if_offline
-
-
port: 5269
ip: "::"
module: ejabberd_s2s_in
-
-
port: 5280
ip: "::"
module: ejabberd_http
@@ -124,8 +124,8 @@ acl:
user:
- "myuser": "mydomain.eu"
#- "@localhost"
local:
local:
user_regexp: ""
loopback:
@@ -160,23 +160,23 @@ access_rules:
announce:
- allow: admin
## Only admins can use the configuration interface:
configure:
configure:
- allow: admin
## Only accounts of the local ejabberd server can create rooms:
muc_create:
muc_create:
- allow: local
## Only accounts on the local ejabberd server can create Pubsub nodes:
pubsub_createnode:
pubsub_createnode:
- allow: local
## In-band registration allows registration of any possible username.
## To disable in-band registration, replace 'allow' with 'deny'.
register:
- deny
register:
- deny
## Only allow to register from localhost
trusted_network:
trusted_network:
- allow: loopback
## Do not establish S2S connections with bad servers
s2s:
s2s:
## - deny:
## - ip: "XXX.XXX.XXX.XXX/32"
## - deny:
@@ -185,7 +185,7 @@ access_rules:
language: "en"
modules:
modules:
mod_adhoc: {}
mod_admin_extra: {}
mod_announce: # recommends mod_adhoc
@@ -216,7 +216,7 @@ modules:
## docroot: "/var/www"
## accesslog: "/var/log/ejabberd/access.log"
mod_last: {}
mod_muc:
mod_muc:
## host: "conference.@HOST@"
access:
- allow
@@ -227,7 +227,7 @@ modules:
## mod_muc_log: {}
mod_muc_admin: {}
## mod_multicast: {}
mod_offline:
mod_offline:
access_max_user_messages: max_user_offline_messages
mod_ping: {}
## mod_pres_counter:
@@ -236,7 +236,7 @@ modules:
mod_privacy: {}
mod_private: {}
## mod_proxy65: {}
mod_pubsub:
mod_pubsub:
access_createnode: pubsub_createnode
## reduces resource comsumption, but XEP incompliant
#ignore_pep_from_offline: true
@@ -246,7 +246,7 @@ modules:
max_items_node: 1000
default_node_config:
max_items: 1000
plugins:
plugins:
- "flat"
- "hometree"
- "pep" # pep requires mod_caps
@@ -283,7 +283,7 @@ modules:
##
## access_from: deny
## access: register
# No registration, but allow existing accounts to change password
access: none
mod_roster:

View File

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

View File

@@ -1,50 +1,59 @@
#!/bin/bash
#!/usr/bin/env bash
toolName=fail2ban
toolDeps="$toolName"
toolConfDir="/etc/fail2ban"
toolConfLoc="$toolConfDir/jail.local"
toolFilter="$toolConfDir/filter.d"
toolJails="$toolConfDir/jail.d"
readonly toolName=fail2ban
readonly toolDeps="$toolName"
readonly toolConfDir="/etc/fail2ban"
readonly toolConfLoc="$toolConfDir/jail.local"
readonly toolFilter="$toolConfDir/filter.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() {
# 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
#}
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
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_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
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_alias() { ALIAS="config"; }
step_2_alias() { echo "config"; }
step_2() {
echo " [I] Create local configuration";
addConf -f "$failConfLocal" "$toolConfLoc"
info "Create local configuration";
addConf -a "$failConfLocal" "$toolConfLoc"
exe service $toolName restart
}
failConfLocal="[DEFAULT]
@@ -54,20 +63,21 @@ banaction_multiport = ufw
ignoreip = 127.0.0.1/8 ::1"
step_3_info() { echo "Add basic ip-blacklist"; }
step_3_alias() { ALIAS="blacklist"; }
step_3_alias() { echo "blacklist"; }
step_3() {
echo " [I] Adding filter"
addConf -s -f "$ipBlackListFilter" "$toolFilter/$(basename $ipBlackListFilter)"
addConf -s -f "$ipBlackListJail" "$toolJails/$(basename $ipBlackListJail)"
addConf -s -f "$ipBlackList" "$toolConfDir/$(basename $ipBlackList)"
local ipBlackList="${sq_configDir}/ip.blacklist"
local ipBlackListJail="$sq_configJails/ip-blacklist.conf"
local ipBlackListFilter="$sq_configFilter/ip-blacklist.conf"
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
}
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_alias() { ALIAS="notes"; }
step_4_alias() { echo "notes"; }
step_4() {
cat <<NOTES_EOF
# 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_alias() { ALIAS="mail"; }
step_20_alias() { echo "mail"; }
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
}
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

View File

@@ -1,4 +1,4 @@
[Definition]
failregex = ^.*\"remoteAddr\":\"<HOST>\".*Trusted domain error.*$
^.*\"remoteAddr\":\"<HOST>\".*Login failed:.*$
^.*\"remoteAddr\":\"<HOST>\".*Login failed:.*$

View File

@@ -7,10 +7,10 @@ logpath = /etc/fail2ban/ip.blacklist
maxretry = 0
findtime = 600
# infinite ban
#bantime = -1
#bantime = -1
# 1 day ban
#bantime = 24h
#bantime = 24h
# 2 day ban
bantime = 48h
bantime = 48h
# 10 minute ban
#bantime = 10m

View File

@@ -4,4 +4,4 @@ logpath = /var/nc_data/nextcloud.log
port = http,https
filter = nextcloud
maxretry = 3
bantime = 24h
bantime = 24h

View File

@@ -1,13 +1,13 @@
#!/bin/bash
toolName="fhem"
toolUser="$toolName"
toolHome="/opt/fhem"
toolVersion="6.0"
toolDpkg="fhem-${toolVersion}.deb"
toolUrl="http://fhem.de/$toolDpkg"
readonly toolName="fhem"
readonly toolUser="$toolName"
readonly toolHome="/opt/fhem"
readonly toolVersion="6.1"
readonly toolDpkg="fhem-${toolVersion}.deb"
readonly toolUrl="http://fhem.de/${toolDpkg}"
# 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"
# for rounding operations e.g.:
# { 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
toolDeps2+=" libsoap-lite-perl libjson-xs-perl"
# for xmpp support (no special solution needed for raspbian buster)
toolDeps2+=" libnet-xmpp-perl libxml-stream-perl libnet-jabber-perl"
# 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"
toolDepsJabber=" libnet-xmpp-perl libxml-stream-perl libnet-jabber-perl"
aptOpt=
#step_config() {
# echo "Called once before executing steps."
@@ -32,43 +25,45 @@ WSUBDIR="${WDIR}/${toolName}"
#}
step_1_info() { echo "Install prerequisits for $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
local aptOpt=
if [ $QUIET != 0 ] ; then
if quiet ; then
aptOpt="-y"
fi
#exe apt update
exe apt install $toolDeps $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() {
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"
endReturn -o $? "Download of $toolName failed"
endReturn "Download of $toolName failed"
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"
step_3_info() { echo "Start $toolName service"; }
step_3() {
exe systemctl restart fhem.service
}
step_20_info() { echo "List $toolName prerequisits"; }
step_20_alias() { ALIAS="listdeps"; }
step_20_alias() { echo "listdeps"; }
step_20() {
echo " [I] $toolName prerequisits:"
info "$toolName prerequisits:"
echo "$toolDeps $toolDeps2"
}
step_30_info() { echo "Create user $toolUser"; }
step_30() {
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"; }
@@ -79,19 +74,19 @@ step_32() {
systemdConfigLoc="/etc/systemd/system"
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() {
if [ ! -f $libnetDown ]; then
exe wget "$libnetUrl" -O "$libnetDown"
endReturn -o $? "Download of $libnetUrl failed"
endReturn "Download of $libnetUrl failed"
fi
if [ ! -f $libxmlDown ]; then
exe wget "$libxmlUrl" -O "$libxmlDown"
endReturn -o $? "Download of $libxmlUrl failed"
endReturn "Download of $libxmlUrl failed"
fi
local aptOption=
if [ $QUIET -ne 0 ] ; then
if quiet ; then
aptOption="-y"
else
aptOption=""
@@ -109,7 +104,7 @@ step_34() {
saveReturn $?
exe dpkg -i "$libnetDown"
saveReturn $?
exe apt install libnet-jabber-perl $aptOption
exe apt install libnet-jabber-perl $aptOption
saveReturn $?
endReturn "Failed removing packages; Manual fix required"
@@ -129,14 +124,14 @@ step_35() {
aptPinFile="/etc/apt/preferences.d/00_FhemJabber"
aptPinXmpp="Package: libnet-xmpp-perl
Pin: version 1.02-3*
Pin-Priority: 1000
Pin-Priority: 1000
Package: libxml-stream-perl
Pin: version 1.23-2
Pin-Priority: 1000"
step_37_info() { echo "Download latest speedtest python script"; }
step_37_alias() { ALIAS="speedtestdownload"; }
step_37_alias() { echo "speedtestdownload"; }
step_37() {
local lSpeedPath="/usr/local/bin/speedtest-cli"
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_alias() { ALIAS="exe"; }
step_40_alias() { echo "exe"; }
step_40() {
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

View File

@@ -1,6 +1,6 @@
# Datei: /etc/udev/rules.d/20-FehmIf.rules
# Gerät CUL868 busware.de (homematic RF) an USB
SUBSYSTEM=="tty", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204b", SYMLINK+="tty_CUL868"
SUBSYSTEM=="tty", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204b", SYMLINK+="tty_CUL868"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0658", ATTRS{idProduct}=="0200", SYMLINK+="tty_Zwave"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A40352S9", SYMLINK+="ttyUSB_RS485"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A103R0XO", SYMLINK+="ttyUSB_LinkUSBi"

View File

@@ -13,55 +13,55 @@ 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 profile config file support:
initSeqConfig "$SCRIPT_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
echoseq " [I] Freeradius DB: $FRAD_DB_NAME"
echoseq " Daloradius home: $DRAD_HOME"
info "Freeradius DB: $FRAD_DB_NAME"
info " Daloradius home: $DRAD_HOME"
else
# End if no configuration file exists
[ $DRY -eq 0 ] && return -1
dry || return -1
fi
## 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 0
}
step_50_info() { echo "Init freeradius and daloradius database"; }
step_50_alias() { ALIAS="initdb"; }
step_50_alias() { echo "initdb"; }
step_50() {
local drDbInit="$DRAD_HOME/contrib/db/mysql-daloradius.sql"
local frDbSchema="$toolConfLoc/mods-config/sql/main/mysql/schema.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"
endReturn -o $? "Creating database failed"
endReturn "Creating database failed"
exep "mysql -uroot \"$FRAD_DB_NAME\" < $frDbSchema"
#exep "mysql -uroot \"$FRAD_DB_NAME\" < $frDbSetup"
exep "mysql -uroot \"$FRAD_DB_NAME\" < $drDbInit"
exep "mysql -uroot \"$FRAD_DB_NAME\" < $frDbSchema"
#exep "mysql -uroot \"$FRAD_DB_NAME\" < $frDbSetup"
exep "mysql -uroot \"$FRAD_DB_NAME\" < $drDbInit"
}
step_52_info() { echo "Reset freeradius and daloradius database"; }
step_52_alias() { ALIAS="resetdb"; }
step_52_alias() { echo "resetdb"; }
step_52() {
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
else
lAnswer=y
fi
case "$lAnswer" in
[yY])
echoseq -n " [I] Reseting DB...";;
sqr::echo -n " [I] Reseting DB...";;
*)
echoerr " [I] Abort reset"
info -e "Abort reset"
return 1;;
esac
@@ -69,5 +69,5 @@ step_52() {
step initdb
}
VERSION_SEQREV=13
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -1,98 +1,94 @@
#!/bin/bash
toolName=friendica
latestUrl="https://api.github.com/repos/friendica/friendica/releases/latest"
readonly toolName=friendica
readonly latestUrl="https://api.github.com/repos/friendica/friendica/releases/latest"
# 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"
sq_config=0
step_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
seq_config() {
initSeqConfig "${seq_configName}" "${seq_configTemplate}"
if [ $? -eq 0 ] ; then
CONFIG=1
sq_config=1
fi
}
step_20_info() {
shift
echoinfoArgs "[FRIENDICA ROOT]"
echo -n "Create a backup"
if [ $CONFIG -ne 0 ] ; then
if (( sq_config )) ; then
echo " at $FR_BACKUP"
else
echo
fi
}
step_20_alias() { ALIAS="backup"; }
step_20_options() { echo "[FRIENDICA ROOT]"; }
step_20_alias() { echo "backup"; }
step_20() {
shift
local tempRoot=
if [ $CONFIG -eq 0 ] ; then
echoerr " [E] No configuration file found"
if (( ! sq_config )) ; then
error -e "No configuration file found"
return 1
fi
if [ ! -z $FR_BACKUP ] ; then
if [ -n "$FR_BACKUP" ] ; then
exe mkdir -p "$FR_BACKUP"
fi
if [ ! -z "$1" ] ; then
if [ -n "${1:-}" ] ; then
tempRoot="$1"
else
tempRoot="$FR_LOC"
fi
exe $WDIR/mysql.sh -qq backup "$FR_DATABASE" "$FR_BACKUP"
endReturn -o $? "Backup mysql database failed"
exe "${seq_dir}/mysql.sh" -qq backup "$FR_DATABASE" "$FR_BACKUP"
endReturn "Backup mysql database failed"
[ ! -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 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 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 tar czf "$dataBackup" $(basename "$FR_LOC_DATA")
}
step_22_info() {
shift
if [ -z $1 ] ; then
if [ -z "${1:-}" ] ; then
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.*?(?=")')"
else
echo " [CUSTOM VERSION]"
echo
fi
else
echo "Get version $1 from github"
fi
}
step_22_alias() { ALIAS="upgrade"; }
step_22_options() { echo "[CUSTOM VERSION]"; }
step_22_alias() { echo "upgrade"; }
step_22() {
shift # don't need step number
local latestVersion=
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
latestVersion="$1"
else
latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "\K.*?(?=")')
fi
if [ -z $latestVersion ] ; then
echoerr " [E] Cannot determine latest version from github repository"
error -e "Cannot determine latest version from github repository"
return 1
elif [ $QUIET -eq 0 ] ; then
elif interactive ; then
echo
exe read -p "Install $latestVersion to $FR_LOC [n]o/(y)es? " answer
case $answer in
[yY])
;;
*)
echoerr " [I] Upgrade aborted"
info -e "Upgrade aborted"
return 1
;;
esac
@@ -100,7 +96,7 @@ step_22() {
local isInstalled=$(grep -E "Version $latestVersion" "${FR_LOC}/CHANGELOG" >>/dev/null && echo "1" || echo "0")
if [ $isInstalled -eq 1 ] ; then
echoerr " [E] Version $latestVersion is already installed"
error -e "Version $latestVersion is already installed"
return 2
fi
@@ -114,23 +110,23 @@ step_22() {
if [ ! -e "$tempExtract" ] ; then
exe mkdir -p "$tempDown"
exe wget -O "$tempLoc" $downUrl
endReturn -o $? "Download failed: $downUrl"
endReturn "Download failed: $downUrl"
exe cd "$tempDown"
exe tar -xf "$tempLoc"
endReturn -o $? "Extract failed: $tempLoc"
endReturn "Extract failed: $tempLoc"
else
echo " [I] Found existing download: $tempExtract"
info "Found existing download: $tempExtract"
fi
if [ ! -e "$tempExtractAddons" ] ; then
exe wget -O "$tempLocAddons" $downUrlAddons
endReturn -o $? "Download failed: $downUrlAddons"
endReturn "Download failed: $downUrlAddons"
exe cd "$tempDown"
exe mkdir -p "$tempExtractAddons"
exe tar -xC "${tempExtractAddons}" -f "$tempLocAddons"
endReturn -o $? "Extract failed: $tempLocAddons"
endReturn "Extract failed: $tempLocAddons"
else
echo " [I] Found existing download: $tempExtractAddons"
info "Found existing download: $tempExtractAddons"
fi
# Installation
@@ -138,15 +134,16 @@ step_22() {
local tempAddons="${FR_LOC}/addon"
exe mv "$FR_LOC" "$tempBu"
exe systemctl stop friendica.service
step backup "$tempBu"
endReturn -o $? "Backup failed; $FR_LOC renamed!"
echo " [I] Installing version $latestVersion to $FR_LOC"
endReturn "Backup failed; $FR_LOC renamed!"
info "Installing version $latestVersion to $FR_LOC"
exe mv "$tempExtract" "$FR_LOC"
exe mv "$tempExtractAddons" "$tempAddons"
exe mv "$tempExtractAddons/addon" "$tempAddons"
exe chown -R www-data: "$FR_LOC"
# Configuration
echo " [I] Copying configuration"
info "Copying configuration"
exe cp -ar "$tempBu/config/local.config.php" "$FR_LOC/config/"
if [ -f "$tempBu/config/addon.config.php" ]; then
exe cp -ar "$tempBu/config/addon.config.php" "$FR_LOC/config/"
@@ -156,17 +153,58 @@ step_22() {
exe cp -ar "$tempBu/home".* "$FR_LOC/"
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"
tempLoc="$tempDown/fr.tar.gz"
tempLocAddons="$tempDown/fradd.tar.gz"
step_24_info() { echo "Clean temporary files: $tempDown"; }
step_24_alias() { ALIAS="clean"; }
step_24_alias() { echo "clean"; }
step_24() {
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

View File

@@ -1,36 +1,7 @@
#!/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_alias() { ALIAS="alias"; }
step_1_alias() { echo "alias"; }
step_1() {
local brConf="branch \
--format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - \
@@ -48,5 +19,7 @@ step_1() {
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

View File

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

View File

@@ -8,36 +8,29 @@ readonly versionUrl="https://api.github.com/repos/grocy/grocy/releases/latest"
versionNew=
versionNow=
sc_grocyConf=
sc_grocyBackup="data/backup"
sc_grocyViewcache="data/viewcache"
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_grocyDownLoc="/tmp/grocy_latest.zip"
sq_aptOpt=
sq_config=0
step_config() {
initSeqConfig -p "$sq_scriptName" "$sq_configFileTemplate"
seq_config() {
initSeqConfig -p "$seq_fileName" "$seq_configTemplate"
if [ $? -eq 0 ] ; then
sq_config=1
else
# End if no configuration file exists
[ $DRY -eq 0 ] && return -1
dry || return 1
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
[ $QUIET -ne 0 ] && sq_aptOpt="-y"
quiet && sq_aptOpt="-y"
## Return of non zero value will abort the sequence
return 0
@@ -48,25 +41,25 @@ getVersions() {
versionNow=${versionNow:-$(grep -Po '"Version": "\K.*?(?=")' 2>/dev/null < "${sc_grocyDir}/version.json")}
}
step_1_info() {
step_1_info() {
echo "Check $toolName status"
echoinfo "Returns 1 if update is available"
}
step_1_alias() { ALIAS="status"; }
step_1_alias() { echo "status"; }
step_1() {
getVersions
if [ -e "${sc_grocyDir}" ] ; then
echo
echo "$toolName installed"
echo " at: ${sc_grocyDir}"
echo " version: ${versionNow}"
echo " config: ${sc_grocyConf}"
echo -n " update: "
info
info "$toolName installed"
info -a " at: ${sc_grocyDir}"
info -a " version: ${versionNow}"
info -a " config: ${sc_grocyConf}"
info -an " update: "
if [[ ! ${versionNow} = ${versionNew} ]] ; then
echo "available: ${versionNew}}"
info -d "available: ${versionNew}"
return 1
else
echo "already on latest"
info -d "already on latest"
return 0
fi
else
@@ -77,7 +70,7 @@ step_1() {
}
step_20_info() { echo "Backup ${toolName}"; }
step_20_alias() { ALIAS="backup"; }
step_20_alias() { echo "backup"; }
step_20() {
local lBu="${sc_grocyDir}/${sc_grocyBackup}/${toolName}_$(date +%Y%m%d-%H%M%S).tgz"
exe cd ${sc_grocyDir}/..
@@ -89,40 +82,40 @@ step_20() {
}
step_22_info() { echo "Install/upgrade ${toolName}"; }
step_22_alias() { ALIAS="install"; }
step_22_alias() { echo "install"; }
step_22() {
getVersions
if [[ ${versionNow} == ${versionNew} ]] ; then
endReturn -o 1 "Latest version ${versionNow} already installed"
else
if [ -n "${versionNow}" ] ; then
echoseq " [I] Upgrading $toolName from ${versionNow} to ${versionNew}"
info "Upgrading $toolName from ${versionNow} to ${versionNew}"
else
echoseq " [I] Installing $toolName version ${versionNew}"
info "Installing $toolName version ${versionNew}"
fi
fi
exe wget ${downUrl} -q -O "${grocyDownLoc}"
endReturn -o $? "Download failed"
exe wget ${downUrl} -q -O "${sq_grocyDownLoc}"
endReturn "Download failed"
if [ -e "${sc_grocyDir}" ] ; then
step backup
exe rm -rf "${sc_grocyDir}/${sc_grocyViewcache}"
fi
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"
# Populate first config
if [ ! -e "${sc_grocyConf}" ] ; then
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
echoseq " [I] Please check ${sc_grocyDir}/config-dist.php"
echoseq " for new configuration options"
info "Please check ${sc_grocyDir}/config-dist.php"
info " for new configuration options"
fi
}
step_30_alias() { ALIAS="notes"; }
step_30_alias() { echo "notes"; }
step_30() {
outColor green
color green
cat <<NOTES_END
# Behind reverse proxy as subfolder
@@ -130,7 +123,7 @@ step_30() {
* Proxy pass from a subdirectory (e.g. domain.me/grocy)
* [data/config.php]
Setting('BASE_PATH', '');
Setting('BASE_URL', 'https://domain.me/grocy');
Setting('BASE_URL', 'https://domain.me/grocy');
# Nginx config
server {
@@ -162,5 +155,5 @@ server {
NOTES_END
}
VERSION_SEQREV=15
readonly sqr_minVersion=16
. /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"
# 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_alias() { ALIAS="prepare"; }
step_1_alias() { echo "prepare"; }
step_1() {
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 \
@@ -47,10 +29,10 @@ step_4() {
}
step_5_info() { echo "Install nginx webserver"; }
step_5_alias() { ALIAS="webserver"; }
step_5_alias() { echo "webserver"; }
step_5() {
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-enabled
exe mkdir -p /etc/nginx/modules-enabled
@@ -58,15 +40,15 @@ step_5() {
}
step_6_info() { echo "Install ufw firewall"; }
step_6_alias() { ALIAS="firewall"; }
step_6_alias() { echo "firewall"; }
step_6() {
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() {
echo " [I] Configure ufw firewall"
info "Configure ufw firewall"
exe ufw allow 22/tcp
exe ufw allow 80/tcp
exe ufw allow 443/tcp
@@ -76,7 +58,7 @@ step_7() {
}
step_8_info() { echo "Install $toolName"; }
step_8_alias() { ALIAS="install"; }
step_8_alias() { echo "install"; }
step_8() {
exe read -p "Make sure SSL certificates are available. Enter to continue"
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/conf.d/default.conf /etc/nginx/sites-available
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() {
echo " [I] Tasks to be automated"
echo
echo " * Make jitsi installation password protected"
echo " (https://github.com/jitsi/jicofo#secure-domain)"
echo " Creating new rooms will require username and password"
echo
echo " ** /etc/prosody/conf.avail/[your-hostname].cfg.lua"
echo
echo " a) Enable authentication on your main domain:"
echo
echo " VirtualHost \"jitsi-meet.example.com\""
echo " authentication = \"internal_plain\""
echo
echo " b) Add new virtual host with anonymous login method for guests:"
echo
echo " VirtualHost \"guest.jitsi-meet.example.com\""
echo " authentication = \"anonymous\""
echo " c2s_require_encryption = false"
echo
echo " ** /etc/jitsi/meet/[your-hostname]-config.js"
echo
echo " var config = {"
echo " hosts: {"
echo " domain: 'jitsi-meet.example.com',"
echo " anonymousdomain: 'guest.jitsi-meet.example.com',"
echo " ..."
echo " },"
echo " ..."
echo " }"
echo
echo " ** /etc/jitsi/jicofo/sip-communicator.properties"
echo " add new line:"
echo
echo " org.jitsi.jicofo.auth.URL=XMPP:jitsi-meet.example.com"
echo
echo " ** Create prosody user(s):"
echo
echo " prosodyctl register <username> jitsi-meet.example.com <password>"
echo
echo " [I] Use step \"restart\" after these changes"
color green
cat << WIP_END
# Tasks to be automated
* Make jitsi installation password protected
(https://github.com/jitsi/jicofo#secure-domain)
Creating new rooms will require username and password
** /etc/prosody/conf.avail/[your-hostname].cfg.lua
a) Enable authentication on your main domain:
VirtualHost "jitsi-meet.example.com"
authentication = "internal_plain"
b) Add new virtual host with anonymous login method for guests:
VirtualHost "guest.jitsi-meet.example.com"
authentication = "anonymous"
c2s_require_encryption = false
** /etc/jitsi/meet/[your-hostname]-config.js
var config = {
hosts: {
domain: 'jitsi-meet.example.com',
anonymousdomain: 'guest.jitsi-meet.example.com',
...
},
...
}
** /etc/jitsi/jicofo/sip-communicator.properties
add new line:
org.jitsi.jicofo.auth.URL=XMPP:jitsi-meet.example.com
** Create prosody user(s):
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_alias() { ALIAS="restart"; }
step_20_alias() { echo "restart"; }
step_20() {
echo " [I] Restart jitsi-meet components"
info "Restart jitsi-meet components"
exep "service prosody restart&& service jicofo restart && service jitsi-videobridge2 restart"
}
VERSION_SEQREV=10
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -10,9 +10,9 @@ toolServiceFile="/etc/systemd/system/kodi.service"
toolProfileDir="/home/kodi/.kodi"
step_1_info() { echo "Install $toolName via apt"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
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"; }
@@ -37,14 +37,14 @@ step_3() {
--disabled-password \
--gecos "User to run $toolName Media Center" \
$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 $?
endReturn
echo "User $toolUser details:"
exe id $tooLuser
exe id $toolUser
}
step_4_info() { echo "Create systemd service"; }
step_4() {
addConf -c "$toolServiceContent" "$toolServiceFile"
@@ -60,8 +60,8 @@ step_4() {
}
toolServiceContent="\
[Unit]
Description = Kodi Media Center
[Unit]
Description = Kodi Media Center
# if you don't need the MySQL DB backend, this should be sufficient
After = systemd-user-sessions.service network.target sound.target
@@ -71,15 +71,17 @@ After = systemd-user-sessions.service network.target sound.target
# Wants = mysql.service
[Service]
User = kodi
Group = kodi
User = ${toolUser}
Group = ${toolUser}
Type = simple
ExecStart = /usr/bin/kodi-standalone
ExecStop = /usr/bin/kodi-send --action=\"Quit\"
ExecStopPost = sleep 15
Restart = always
RestartSec = 15
[Install]
WantedBy = multi-user.target"
WantedBy = multi-user.target"
step_5_info() { echo "Enable text input for USB keyboards within $toolName"; }
step_5() {
@@ -91,8 +93,7 @@ step_5() {
step_6_info() { echo "Increase raspberry pi GPU memory to 320"; }
step_6() {
exep "grep -e '^[ ]*gpu_mem' \"$bootConfigLoc\" >>/dev/null 2>&1"
if [ $? -ne 0 ] && [ -f "$bootConfigLoc" ] ; then
if ! exep "grep -e '^[ ]*gpu_mem' \"$bootConfigLoc\" >>/dev/null 2>&1" && [ -f "$bootConfigLoc" ] ; then
# attach settings to raspberry boot configuration
exe mount -o remount,rw /boot
addConf -a "$bootConfig" "$bootConfigLoc"
@@ -107,14 +108,14 @@ bootConfigLoc="/boot/config.txt"
bootConfig="
# Modifications for $toolName
start_x=1
gpu_mem=320"
gpu_mem=320"
step_7_info() { echo "Reboot is needed for all changes to take effect"; }
step_7() {
if [ $QUIET -eq "1" ] ; then
if quiet ; then
answer=n
else
read -p "Reboot now? y/n(default)" answer
read -r -p "Reboot now? y/n(default)" answer
fi
case $answer in
y|Y)
@@ -128,7 +129,7 @@ step_7() {
}
step_10_info() { echo "Send $toolName logs to syslog"; }
step_10_alias() { ALIAS="syslog"; }
step_10_alias() { echo "syslog"; }
step_10() {
addConf -s "$kodiSyslog" "$kodiSyslogLoc"
exe chmod -f +x "$kodiSyslogLoc"
@@ -136,20 +137,20 @@ step_10() {
kodiSyslogLoc="/usr/local/bin/kodisyslog"
kodiSyslog="#!/bin/bash
tail -f /home/kodi/.kodi/temp/kodi.log |
while read -r line
do
logger -t KODI \"\${line:37}\"
done"
while read -r line ; do
logger -t KODI \"\${line:37}\"
done"
# Using previously generated executable
step_11_info() { echo "Create systemd service for logging to syslog"; }
step_11() {
[ ! -f "$kodiSyslogLoc" ] && return 1
addConf -s "$kodiSyslogService" "$kodiSyslogServiceLoc"
echoseq " [I] Consider limiting systemd journal size"
echoseq " [/etc/systemd/journald.conf]"
echoseq " SystemMaxUse=50M"
info "Consider limiting systemd journal size"
info " [/etc/systemd/journald.conf]"
info " SystemMaxUse=50M"
}
kodiSyslogServiceLoc="/etc/systemd/system/kodisyslog.service"
kodiSyslogService="[Unit]
@@ -165,32 +166,65 @@ WantedBy=multi-user.target"
step_12_info() { echo "Enable and start kodisyslog service"; }
step_12() {
local kodiSyslogName="$(basename $kodiSyslogServiceLoc)"
local kodiSyslogName
kodiSyslogName="$(basename $kodiSyslogServiceLoc)"
exe systemctl daemon-reload
exe systemctl enable $kodiSyslogName
exe systemctl start $kodiSyslogName
exe systemctl enable "$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_alias() { ALIAS="resetmusic"; }
step_40_alias() { echo "resetmusic"; }
step_40() {
local i
local answer="y"
local musicDb=( "$toolProfileDir/userdata/Database/MyMusic"*.db )
echoseq " [W] Erasing:"
for i in ${musicDb[@]}; do
echoseq $i
warning "Erasing:"
for i in "${musicDb[@]}"; do
info "$i"
done
[ $QUIET -eq 0 ] && read -p "Are you sure? (y)/[n] " answer
case "$answer" in
interactive && read -r -p "Are you sure? (y)/[n] " answer
case "$answer" in
y|Y)
exe rm ${musicDb[@]};;
exe rm "${musicDb[@]}";;
*)
echoseq " [I] Abort reset"
info "Abort reset"
return 1;
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

View File

@@ -1,29 +1,29 @@
#!/bin/bash
toolName="ldap"
toolDaemon="slapd"
toolDeps="$toolDaemon ldap-utils"
toolUser="openldap"
readonly toolName="ldap"
readonly toolDaemon="slapd"
readonly toolDeps="$toolDaemon ldap-utils"
readonly toolUser="openldap"
# 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"
sq_aptOpt=
step_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
seq_config() {
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 0
}
step_1_info() { echo "$toolName installation"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
exe apt install $toolDeps
exe apt install $toolDeps ${sq_aptOpt}
}
step_2_info() { echo "Configuration of $toolName"; }
@@ -82,7 +82,7 @@ olcOverlay: {1}refint
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() {
variable2Ldif add "$ldapBase"
}
@@ -98,11 +98,11 @@ objectClass: organizationalUnit
step_8_info() { echo "Setup SSL secured ldaps:// access"; }
step_8() {
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
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
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\""`
exep "echo \"$tempLdif\" | ldapmodify -Y EXTERNAL -H ldapi:///"
@@ -136,10 +136,23 @@ step_20() {
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_alias() { ALIAS="notes"; }
step_80_alias() { echo "notes"; }
step_80() {
outColor green
color green
cat <<NOTES_EOF
# You can also check LDAP Base DN using the ldapsearch command as shown below
ldapsearch -H ldapi:/// -x -LLL -s base -b "" namingContexts
@@ -161,8 +174,9 @@ E0F
NOTES_EOF
}
step_100_info() { echo "Add group <GROUP NAME> <USER ID>"; }
step_100_alias() { ALIAS="addgroup"; }
step_100_info() { echo "Add group"; }
step_100_options() { echo "<GROUP NAME> <USER ID>"; }
step_100_alias() { echo "addgroup"; }
step_100() {
shift
local groupName=$1
@@ -177,8 +191,9 @@ description: Created by $0
member: \${memberDn}
"
step_102_info() { echo "Add user <USER ID> <USER NAME> <USER LASTNAME> <UIDNUMBER> <USER EMAIL> [USER GID]"; }
step_102_alias() { ALIAS="adduser"; }
step_102_info() { echo "Add user"; }
step_102_options() { echo "<USER ID> <USER NAME> <USER LASTNAME> <UIDNUMBER> <USER EMAIL> [USER GID]"; }
step_102_alias() { echo "adduser"; }
step_102() {
shift
userId="$1"
@@ -193,10 +208,10 @@ step_102() {
fi
variable2Ldif add "$addUser"
endReturn -o $? "Adding user failed"
endReturn "Adding user failed"
}
userId=
addUser="dn: uid=\$userId,\$LDAP_OU_USERS,\$LDAP_DC
addUser="dn: uid=\$userId,\$LDAP_OU_USERS,\$LDAP_DC
cn: \$userCn
givenName: \$givenName
sn: \$userSn
@@ -214,44 +229,46 @@ objectClass: person
loginShell: /bin/bash
"
step_103_info() { echo "(re)Set passwort for <USER>"; }
step_103_alias() { ALIAS="passwd"; }
step_103_info() { echo "(re)Set passwort for user"; }
step_103_options() { echo "<USER>"; }
step_103_alias() { echo "passwd"; }
step_103() {
shift
if [ ! -z $1 ] ; then
echo " [I] Password operation for $1"
if [ -n "${1:-}" ] ; then
info "Password operation for $1"
userId="$1"
elif [ ! -z $userId ] ; then
echo " [I] Password operation for $userId"
info "Password operation for $userId"
else
echoerr " [E] No user id provided"
error -e "No user id provided"
return 1
fi
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_alias() { ALIAS="user2group"; }
step_105_info() { echo "Adding user to existing group"; }
step_105_options() { echo "<USER ID> <GROUP NAME>"; }
step_105_alias() { echo "user2group"; }
step_105() {
shift
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
userId="$1"
echo " [I] User operation for $userId"
info "User operation for $userId"
elif [ ! -z $userId ] ; then
echo " [I] User operation for $userId"
info "User operation for $userId"
else
echoerr " [E] No user id provided"
error -e "No user id provided"
return 1
fi
if [ -z $2 ] ; then
echoerr " [E] No group name provided"
error -e "No group name provided"
return 2
fi
local groupName="$2"
variable2Ldif modify "$removeFromgroup"
variable2Ldif modify "$add2group"
endReturn -o $? "Adding user to group failed"
endReturn "Adding user to group failed"
}
#remove empty member
add2group="dn: cn=\$groupName,\$LDAP_OU_GROUPS,\$LDAP_DC
@@ -265,21 +282,22 @@ delete: member
member:
"
step_107_info() { echo "Removing <USER ID> from existing group <GROUP NAME>"; }
step_107_alias() { ALIAS="rmusergroup"; }
step_107_info() { echo "Removing user from existing group"; }
step_107_options() { echo "<USER ID> <GROUP NAME>"; }
step_107_alias() { echo "rmusergroup"; }
step_107() {
shift
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
userId="$1"
echo " [I] User operation for $userId"
info "User operation for $userId"
elif [ ! -z $userId ] ; then
echo " [I] User operation for $userId"
info "User operation for $userId"
else
echoerr " [E] No user id provided"
error -e "No user id provided"
return 1
fi
if [ -z $2 ] ; then
echoerr " [E] No group name provided"
error -e "No group name provided"
return 2
fi
local groupName="$2"
@@ -299,12 +317,13 @@ delete: member
member: uid=\$userId,\$LDAP_OU_USERS,\$LDAP_DC
"
step_110_info() { echo "Remove group <GROUP NAME>"; }
step_110_alias() { ALIAS="rmgroup"; }
step_110_info() { echo "Remove group"; }
step_110_options() { echo "<GROUP NAME>"; }
step_110_alias() { echo "rmgroup"; }
step_110() {
shift
if [ -z $1 ] ; then
echoerr " [E] No group name provided"
error -e "No group name provided"
return 1
fi
local groupName=$1
@@ -314,12 +333,13 @@ rmGroup="dn: cn=\${groupName},\${LDAP_OU_GROUPS},\${LDAP_DC}
changetype: delete
"
step_112_info() { echo "Remove user <USER ID>"; }
step_112_alias() { ALIAS="rmuser"; }
step_112_info() { echo "Remove user"; }
step_112_options() { echo "<USER ID>"; }
step_112_alias() { echo "rmuser"; }
step_112() {
shift
if [ -z $1 ] ; then
echoerr " [E] No user id provided"
error -e "No user id provided"
return 1
fi
local userName=$1
@@ -329,19 +349,21 @@ rmUser="dn: uid=\${userName},\${LDAP_OU_USERS},\${LDAP_DC}
changetype: delete
"
step_200_info() { echo "List available groups <ADDITONAL ATTRIBUTES...>"; }
step_200_alias() { ALIAS="listgroups"; }
step_200_info() { echo "List available groups"; }
step_200_options() { echo "<ADDITONAL ATTRIBUTES...>"; }
step_200_alias() { echo "listgroups"; }
step_200() {
shift
echo " [I] Available groups:"
info "Available groups:"
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_alias() { ALIAS="listusers"; }
step_202_info() { echo "List available users"; }
step_200_options() { echo "<ADDITONAL ATTRIBUTES...>"; }
step_202_alias() { echo "listusers"; }
step_202() {
shift
echo " [I] Available user:"
info "Available user:"
exe ldapsearch -x -LLL -H ldap:/// -b ${LDAP_OU_USERS},${LDAP_DC} dn uidNumber gidNumber $*
}
@@ -364,5 +386,7 @@ variable2LdifEcho() {
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

View File

@@ -3,69 +3,57 @@
#
## Installation and maintenance for LibreNMS
toolName="librenms"
toolUser="librenms"
readonly toolName="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=
libreDeps='acl curl composer fping git graphviz imagemagick mtr-tiny nmap rrdtool snmp snmpd whois python3-dotenv python3-pymysql python3-redis python3-setuptools'
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'
#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"
#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"
seq_config() {
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
info " Install: $LNMS_DIR"
info " Backup: $LNMS_BU_DIR"
else
[ $DRY -eq 0 ] && return 1
dry || return 1
fi
return 0
}
step_1_info() { echo "Updating apt"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
}
step_2_info() {
echo "Installing $toolname dependencies:"
step_2_info() {
echo "Installing $toolName dependencies:"
echoinfo "$libreDeps"
}
step_2() {
exe apt install $libreDeps
endReturn -o $? "Failed to install $toolName dependencies"
exe apt install $libreDeps ${sq_aptOpt}
endReturn "Failed to install $toolName dependencies"
}
step_3_info() {
echo "Installing PHP related packages:"
fetchPhpVersion
echoinfo `eval echo "$librePhpDeps"`
echoinfo "${librePhpDeps[@]/#/php${phpVersion}-}"
}
step_3() {
fetchPhpVersion
exe apt install `eval echo "$librePhpDeps"`
endReturn -o $? "Failed to install $toolName php dependencies"
exe apt install "${librePhpDeps[@]/#/php${phpVersion}-}" ${sq_aptOpt}
endReturn "Failed to install $toolName php dependencies"
}
step_4_info() { echo "Adding $toolName user ($toolUser)"; }
step_4() {
exe useradd $toolUser -d "$LNMS_DIR" -M -r -s "$(which bash)"
saveReturn $?
#exe usermod -a -G librenms www-data
#saveReturn $?
endReturn "Failed to create user $toolUser"
}
@@ -79,22 +67,22 @@ step_5() {
step_6_info() { echo "Installing $toolName using composer"; }
step_6() {
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() {
local libreDbOpt=
if [ ! -z "$LNMS_DB_NAME" ] ; then
if [ -n "$LNMS_DB_NAME" ] ; then
libreDbOpt="-d $LNMS_DB_NAME"
fi
exe ${WDIR}/mysql.sh -q createdb --charset utf8 $libreDbOpt
endReturn -o $? "Failed to create mysql database $LNMS_DB_NAME"
exe "${seq_origin}"/mysql.sh ${sqr_args} createdb --charset utf8 "$libreDbOpt"
endReturn "Failed to create mysql database $LNMS_DB_NAME"
}
step_11_info() { echo "MariaDB configuration"; }
step_11() {
outColor green
color green
cat << SQLCONF_END
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() {
outColor green
color green
fetchPhpVersion
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".
vi /etc/php/7.3/fpm/conf.d/90-custom_pi.ini
vi /etc/php/7.3/cli/conf.d/90-custom_pi.ini
vi /etc/php/${phpVersion}/fpm/conf.d/90-custom_pi.ini
vi /etc/php/${phpVersion}/cli/conf.d/90-custom_pi.ini
-------------------------------------------
date.timezone = Europe/Berlin
@@ -131,11 +120,11 @@ PHPCONF_END
step_13_info() { echo "PHP fpm configuration"; }
step_13() {
outColor green
color green
cat << FPMCONF_END
cp /etc/php/7.3/fpm/pool.d/www.conf /etc/php/7.3/fpm/pool.d/librenms.conf
vi /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/${phpVersion}/fpm/pool.d/librenms.conf
# Change [www] to [librenms]:
@@ -154,7 +143,7 @@ FPMCONF_END
step_14_info() { echo "Nginx configuration"; }
step_14() {
outColor green
color green
cat << NGINXCONF_END
server {
@@ -182,62 +171,63 @@ NGINXCONF_END
}
step_20_info() { echo "Create $toolName cron job"; }
step_20_alias() { ALIAS="cron"; }
step_20_alias() { echo "cron"; }
step_20() {
echoseq -n " [I] Creating $lnmsCronLoc ... "
exe cp "${LNMS_DIR}/librenms.nonroot.cron" "$lnmsCronLoc" && echoseq "Ok" || echoseq "Nok"
local lnmsCronLoc="/etc/cron.d/librenms"
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_alias() { ALIAS="cmdcompletion"; }
step_22_alias() { echo "cmdcompletion"; }
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 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_alias() { ALIAS="logrotate"; }
step_24_alias() { echo "logrotate"; }
step_24() {
echoseq -n " [I] Creating $lnmsLogrotLoc ... "
exe cp "${LNMS_DIR}/misc/librenms.logrotate" "$lnmsLogrotLoc" && echoseq "Ok" || echoseq "Nok"
local lnmsLogrotLoc="/etc/logrotate.d/librenms"
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_alias() { ALIAS="services"; }
step_26_alias() { echo "services"; }
step_26() {
exe apt install monitoring-plugins
echoseq
echoseq " [$LNMS_DIR/config.php]"
echoseq "\$config['show_services'] = 1;"
echoseq
echoseq " [/etc/cron.d/librenms]"
echoseq " */5 * * * * librenms /opt/librenms/services-wrapper.py 1"
info
info " [$LNMS_DIR/config.php]"
info -a " \$config['show_services'] = 1;"
info -a
info -a " [/etc/cron.d/librenms]"
info -a " */5 * * * * librenms /opt/librenms/services-wrapper.py 1"
}
step_30_info() { echo "Backup ${toolName} web direcotry"; }
step_30_alias() { ALIAS="backup"; }
step_30_alias() { echo "backup"; }
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"
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_alias() { ALIAS="backupdb"; }
step_31_info() { echo "Backup ${toolName} database"; }
step_31_options() { echo "[daily|monthly(default)]"; }
step_31_alias() { echo "backupdb"; }
step_31() {
case "$2" in
daily|Daily|DAILY)
echoseq " [I] Daily backup..."
exep "mysqldump --single-transaction -u root ${LNMS_DB_NAME} | bzip2 -c > \"${LNMS_BU_DIR}/${toolName}_daily.sql.bz2\""
case "${2:-}" in
daily | Daily | DAILY)
info "Daily backup..."
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"
echoseq " [I] Monthly backup..."
exep "mysqldump --single-transaction -u root ${LNMS_DB_NAME} | bzip2 -c > \"${LNMS_BU_DIR}/monthly/\`date +%Y%m%d\`_${toolName}.sql.bz2\""
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"
;;
esac
}
@@ -258,7 +248,7 @@ STABLE_EOF
}
step_42_info() { echo "Fix librenms permission"; }
step_42_alias() { ALIAS="fix"; }
step_42_alias() { echo "fix"; }
step_42() {
exe chown -R ${toolUser}: "$LNMS_DIR"
exe chmod 771 "${LNMS_DIR}"
@@ -266,14 +256,15 @@ step_42() {
exe setfacl -R -m g::rwx "${LNMS_DIR}/rrd" "${LNMS_DIR}/logs" "${LNMS_DIR}/bootstrap/cache/" "${LNMS_DIR}/storage/"
}
fetchPhpVersion() {
if [ ! -z $phpVersion ] ; then
return 0
fi
fetchPhpVersion() {
if [ -n "${phpVersion}" ] ; then
return 0
fi
phpVersion="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')"
phpVersion="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')"
}
# Sequence Revision
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

View File

@@ -2,20 +2,40 @@
# MAS = Mail Server
MAS_DOMAIN="mydomain.com"
MAS_RELAYHOST=
MAS_RELAYUSER=
MAS_RELAYPASS=
readonly MAS_DOMAIN="mydomain.com"
readonly MAS_RELAYHOST=
readonly MAS_RELAYUSER=
readonly MAS_RELAYPASS=
MAS_DBUSER='pfa'
MAS_DBPASS='pass'
MAS_DBNAME='pfa_db'
MAS_mysql_virtual_domains_maps="user = '\$MAS_DBUSER'
password = '\$MAS_DBPASS'
hosts = localhost
dbname = '\$MAS_DBNAME'
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
# Settings for virtualizing mailboxes and domains
readonly MAS_DBUSER='pfa'
readonly MAS_DBPASS='pass'
readonly MAS_DBNAME='pfa_db'
readonly MAS_DBHOST='localhost'
readonly MAS_VIRTUAL_USER='vmail'
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'
#optional query to use when relaying for backup MX
#query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'
#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)
# MUA = Mail User Agent (Mail program used by the user)
toolName=mailserver
mtaName=postfix
mtaUser=postfix
mtaDeps="$mtaName $mtaName-mysql"
mtaConfLoc="/etc/$mtaName"
mtaMysqlConfLoc="$mtaConfLoc/sql"
mdaName=dovecot
mdaConfLoc="/etc/$mdaName"
mdaConfDir="$mdaConfLoc/conf.d"
mdaDeps="dovecot-imapd dovecot-lmtpd dovecot-mysql dovecot-managesieved dovecot-sieve"
readonly toolName=mailserver
readonly mtaName=postfix
readonly mtaUser=postfix
readonly mtaDeps="$mtaName $mtaName-mysql"
readonly mtaConfLoc="/etc/$mtaName"
readonly mtaMysqlConfLoc="$mtaConfLoc/sql"
readonly mdaName=dovecot
readonly mdaConfLoc="/etc/$mdaName"
readonly mdaConfDir="$mdaConfLoc/conf.d"
readonly mdaDeps="dovecot-imapd dovecot-lmtpd dovecot-mysql dovecot-managesieved dovecot-sieve"
# 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"
sq_aptOpt=
sq_config=0
step_config() {
if [ $(id -u) -ne 0 ] ; then
endReturn -o 1 "No root"
fi
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
echoseq " Domain: $MAS_DOMAIN"
elif [ $? -eq 1 ] ; then
# Config $CONFIG_FILE_NAME created. Needs modification first
[ $DRY -eq 0 ] && return -1
seq_config() {
root || endReturn -o 1 "No root"
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
info " Domain: ${MAS_DOMAIN:-}"
else
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
return 0
}
step_1_info() { echo "Update apt repositories"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
}
step_2_info() { echo "Install $mtaName"; }
step_2() {
local aptOpt=
if [ $QUIET -ne 0 ];then
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
confirm -n -y "In the following dialog chose \"Internet site\" and enter $MAS_DOMAIN as your domain. Enter to continue..."
exe apt install $mtaDeps ${sq_aptOpt:-}
}
step_3_info() { echo "Enable $mtaName"; }
step_3() {
exe systemctl enable $mtaName
echo -e " [I] Printing $mtaName status\n"
info "Printing $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"; }
@@ -74,17 +67,18 @@ step_4() {
step_5_info() { echo "$mtaName enable submission service"; }
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 read -rep $'\nPress Enter to open the '$mtaConfLoc'/master.cf'
exe vi $mtaConfLoc/master.cf
exe echoseq
confirm -n -y "Press Enter to open the $mtaConfLoc/master.cf"
editor $mtaConfLoc/master.cf
info
exe cat "$mtaConfSmtps"
exe read -rep $'\nPress Enter to open the '$mtaConfLoc'/master.cf'
exe vi $mtaConfLoc/master.cf
confirm -n -y "Press Enter to open the $mtaConfLoc/master.cf"
editor $mtaConfLoc/master.cf
}
mtaConfSubmission="$WDIR/$toolName/submissionService"
mtaConfSmtps="$WDIR/$toolName/smtpsService"
step_6_info() { echo "Configure TLS"; }
step_6() {
@@ -97,7 +91,7 @@ step_6() {
exe postconf "smtp_tls_mandatory_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
}
@@ -111,15 +105,15 @@ step_7() {
step_8_info() { echo "Install $mdaName"; }
step_8() {
exe apt install $mdaDeps
echoseq -e "\n [I] Installed version: $(dovecot --version)"
exe apt install $mdaDeps ${sq_aptOpt}
info "Installed version: $(dovecot --version)"
}
step_9_info() {
echo "Configure $mdaName"
}
step_9() {
outColor green
color green
cat <<MDA_EOF
# Configuring Mailbox Location
[/etc/dovecot/conf.d/10-mail.conf]
@@ -201,24 +195,17 @@ step_9() {
MDA_EOF
}
step_20_info() {
step_20_info() {
echo "Install postfixadmin and create 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() {
local qOpt=
if [ $QUIET -ne 0 ] ; then
qOpt="-q"
fi
exe $WDIR/postfixadmin.sh ${qOpt} install
exe ${seq_origin:?}/postfixadmin.sh ${sqr_args} install
}
step_21_info() { echo "Create $mtaName mysql query files"; }
step_21() {
# eval needed to expand sourced configuration variables
local localMysqlUser=`eval "echo \"$MAS_VIRTUAL_USER_PART\""`
exe mkdir -p "$mtaMysqlConfLoc"
local mtaFile
@@ -232,11 +219,10 @@ step_21() {
"mysql_virtual_alias_domain_catchall_maps"\
)
for mtaFile in ${mtaMysqlFiles[@]}
do
eval 'mtaVar=$MAS_'${mtaFile}
echoseq " [I] creating ${mtaFile}.cf"
exe echo -e "$localMysqlUser\n$mtaVar" > "$mtaMysqlConfLoc/${mtaFile}.cf"
for mtaFile in ${mtaMysqlFiles[@]} ; do
mtaVar="MAS_${mtaFile}"
info "creating ${mtaFile}.cf"
exep echo -e "\"${MAS_VIRTUAL_USER_PART:?}\\n${!mtaVar:?}\"" \> \"$mtaMysqlConfLoc/${mtaFile}.cf\"
done
exe chown -R root:${mtaUser} "$mtaMysqlConfLoc"
@@ -250,7 +236,7 @@ step_22() {
exe postconf -e "virtual_alias_maps = proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf, proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf, proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf"
exe postconf -e "virtual_transport = lmtp:unix:private/dovecot-lmtp"
# Apex domain removed, it is handled as virtual domain now
# Apex domain removed, it is handled as virtual domain now
exe postconf -e "mydestination = \$myhostname, localhost.\$mydomain, localhost"
# Base location for the virtual maildirs
exe postconf -e "virtual_mailbox_base = $MAS_VIRTUAL_FOLDER_BASE"
@@ -259,7 +245,7 @@ step_22() {
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() {
exe mkdir -p "$MAS_VIRTUAL_FOLDER_BASE"
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 chmod -R 770 "$MAS_VIRTUAL_FOLDER_BASE"
echoseq " [I] Restarting $mtaName"
info "Restarting $mtaName"
exe service $mtaName restart
}
step_24_info() { echo "$mdaName virtualisation configuration instructions"; }
step_24() {
echo "# Configuring Mailbox Location"
echo " [/etc/dovecot/conf.d/10-mail.conf]"
echo " mail_location = maildir:~/Maildir"
echo " mail_home = ${MAS_VIRTUAL_FOLDER_BASE}/%d/%n"
echo
echo "# Configure authentication"
echo " [/etc/dovecot/conf.d/10-auth.conf]"
echo " # Username with domain"
echo " auth_username_format = %u"
echo " # Find and uncomment following line"
echo " !include auth-sql.conf.ext"
echo " # Comment following line to prevent local users from sending mail"
echo " # without having registered an email address"
echo " #!include auth-system.conf.ext"
echo " # Debug login issues in /var/log/maillog by adding:"
echo " auth_debug = yes"
echo " auth_debug_passwords = yes"
echo
echo "# Adding mysql login information"
echo " [/etc/dovecot/dovecot-sql.conf.ext]"
echo " driver = mysql"
echo " connect = host=$MAS_DBHOST dbname=$MAS_DBNAME user=$MAS_DBUSER password='${MAS_DBPASS}'"
echo " default_pass_scheme = MD5"
echo " password_query = SELECT username AS user,password FROM mailbox WHERE username = '%u' AND active='1'"
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'"
echo " iterate_query = SELECT username AS user FROM mailbox"
color green
cat <<END_STEP24
# Configuring Mailbox Location
[/etc/dovecot/conf.d/10-mail.conf]
mail_location = maildir:~/Maildir
mail_home = ${MAS_VIRTUAL_FOLDER_BASE}/%d/%n
# Configure authentication
[/etc/dovecot/conf.d/10-auth.conf]
# Username with domain
auth_username_format = %u
# Find and uncomment following line
!include auth-sql.conf.ext
# Comment following line to prevent local users from sending mail
# without having registered an email address
#!include auth-system.conf.ext
# Debug login issues in /var/log/maillog by adding:
auth_debug = yes
auth_debug_passwords = yes
# Adding mysql login information
[/etc/dovecot/dovecot-sql.conf.ext]
driver = mysql
connect = host=$MAS_DBHOST dbname=$MAS_DBNAME user=$MAS_DBUSER password='${MAS_DBPASS}'
default_pass_scheme = MD5
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() {
echo "Configure sieve for virtual users"
}
step_25() {
echo "# Sieve script configuration"
echo " [$mdaConfDir/90-sieve.conf]"
echo " sieve = file:/var/vmail/%d/%n/sieve;active=/var/vmail/%d/%n/.dovecot.sieve"
echo " sieve_extensions = +notify +imapflags +vnd.dovecot.execute"
echo " sieve_plugins = sieve_extprograms"
echo " sieve_user_log = file:/var/vmail/%d/%n/sieve/sieve.log"
echo
echo "# Enable sieve for lmtp"
echo " [$mdaConfDir/20-lmtp.conf]"
echo " postmaster_address = postmaster@$MAS_DOMAIN"
echo " mail_plugins = $mail_plugins sieve"
echo
echo "# Enable excution of external programs (e.g. to send xmpp messages on certain keywords)"
echo " [$mdaConfDir/90-sieve-extprograms.conf]"
echo " sieve_execute_bin_dir = /usr/lib/dovecot/sieve-execute"
echo
echo "# Notes on execution of scripts"
echo " * Scripts are executed with the $MAS_VIRTUAL_USER user"
echo " * Scripts must no be writeable by others"
echo " (chown root:$MAS_VIRTUAL_USER script; chmod 750 script)"
echo " * \$HOME is set to the virtual users home"
echo " (e.g. /var/vmail/$MAS_DOMAIN/max)"
echo
echo "# Notes about sendxmpp"
echo " * .sendxmpprc resides in every virtual users home"
echo " and must be owned by $MAS_VIRTUAL_USER"
echo " (chown $MAS_VIRTUAL_USER: .sendxmpprc; chmod 700 .sendxmpprc)"
color green
cat << END_STEP25
# Sieve script configuration
[$mdaConfDir/90-sieve.conf]
sieve = file:/var/vmail/%d/%n/sieve;active=/var/vmail/%d/%n/.dovecot.sieve
sieve_extensions = +notify +imapflags +vnd.dovecot.execute
sieve_plugins = sieve_extprograms
sieve_user_log = file:/var/vmail/%d/%n/sieve/sieve.log
# Enable sieve for lmtp
[$mdaConfDir/20-lmtp.conf]
postmaster_address = postmaster@$MAS_DOMAIN
mail_plugins = \$mail_plugins sieve
# Enable excution of external programs (e.g. to send xmpp messages on certain keywords)
[$mdaConfDir/90-sieve-extprograms.conf]
sieve_execute_bin_dir = /usr/lib/dovecot/sieve-execute
# Notes on execution of scripts
* Scripts are executed with the $MAS_VIRTUAL_USER user
* Scripts must no be writeable by others
(chown root:$MAS_VIRTUAL_USER script; chmod 750 script)
* \$HOME is set to the virtual users home
(e.g. /var/vmail/$MAS_DOMAIN/max)
# Notes about sendxmpp
* .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_alias() { ALIAS="default_relay"; }
step_50_alias() { echo "default_relay"; }
step_50() {
if [ ! -f "$saslPassFile" ] ; then
exe postconf -e "relayhost = $MAS_RELAYHOST"
@@ -343,53 +337,53 @@ step_50() {
exe postconf -e "smtp_sasl_password_maps = hash:$saslPassFile"
addConf -s "$MAS_RELAYHOST $MAS_RELAYUSER:$MAS_RELAYPASS" "$saslPassFile"
fi
echoseq " [I] Updating $saslPassFile"
info "Updating $saslPassFile"
exe postmap "$saslPassFile"
}
saslPassFile="$mtaConfLoc/sasl_password"
step_52_info() {
step_52_info() {
echo "Grant access for specific (local) hostnames"
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() {
if [ ! -f "$mtaClientAccessLoc" ] ; then
echo " [I] Generating $mtaClientAccessLoc"
exep "echo \"# myhost.lan OK\" > \"$mtaClientAccessLoc\""
echo " [I] Don't forget to add the following"
echo " [$mtaConfLoc/main.cf]"
echo " smtpd_relay_restrictions ="
echo " check_client_access hash:$mtaClientAccessLoc"
info "Generating $mtaClientAccessLoc"
exep echo "# myhost.lan OK" \> "$mtaClientAccessLoc"
info "Don't forget to add the following"
info -a "[$mtaConfLoc/main.cf]"
info -a " smtpd_relay_restrictions ="
info -a " check_client_access hash:$mtaClientAccessLoc"
fi
echoseq " [I] Updating $mtaClientAccessLoc"
info "Updating $mtaClientAccessLoc"
exe postmap "$mtaClientAccessLoc"
}
mtaClientAccessLoc="$mtaConfLoc/client_access"
step_54_info() {
step_54_info() {
echo "Deny recipient access for listed mail addresses"
}
step_54_alias() { ALIAS="recipient_access"; }
step_54_alias() { echo "recipient_access"; }
step_54() {
if [ ! -f "$mtaRecipientAccessLoc" ] ; then
echoseq " [I] Generating $mtaRecipientAccessLoc"
info "Generating $mtaRecipientAccessLoc"
exep "echo \"# unwanted@${MAS_DOMAIN} 550 No mailbox. Nothing to see here.\" > \"$mtaRecipientAccessLoc\""
echo " [I] Don't forget to add the following"
echo " [$mtaConfLoc/main.cf]"
echo " smtpd_recipient_restrictions ="
echo " check_recipient_access hash:$mtaRecipientAccessLoc"
info "Don't forget to add the following"
info -a "[$mtaConfLoc/main.cf]"
info -a " smtpd_recipient_restrictions ="
info -a " check_recipient_access hash:$mtaRecipientAccessLoc"
fi
echoseq " [I] Updating $mtaRecipientAccessLoc"
info "Updating $mtaRecipientAccessLoc"
exe postmap "$mtaRecipientAccessLoc"
}
mtaRecipientAccessLoc="$mtaConfLoc/recipient_access"
step_56_info() { echo "Add sender dependant relay with authentication"; }
step_56_alias() { ALIAS="sender_relay"; }
step_56_alias() { echo "sender_relay"; }
step_56() {
if [ ! -f "$mtaSenderRelayLoc" ] ; then
echoseq " [I] Generating $mtaSenderRelayLoc"
info "Generating $mtaSenderRelayLoc"
exep "echo \"# user@extern.com smtp:[mail.extern.com]:587\" > \"$mtaSenderRelayLoc\""
exe postconf -e "smtp_sender_dependent_authentication = yes"
exe postconf -e "sender_dependent_relayhost_maps = hash:$mtaSenderRelayLoc"
@@ -397,53 +391,48 @@ step_56() {
exe postconf -e "smtp_sasl_mechanism_filter = plain"
exe postconf -e "smtp_tls_security_level = encrypt"
exe postconf -e "smtp_tls_mandatory_ciphers = high"
echo " [I] Don't forget to add credentials for the new relay"
echo " [$saslPassFile]"
echo " user@extern.com username:passwort"
echo " postmap $saslPassFile"
info "Don't forget to add credentials for the new relay"
info -a "[$saslPassFile]"
info -a " user@extern.com username:passwort"
info -a "postmap $saslPassFile"
fi
echoseq " [I] Updating $mtaSenderRelayLoc"
info "Updating $mtaSenderRelayLoc"
exe postmap "$mtaSenderRelayLoc"
exe postmap "$saslPassFile"
}
mtaSenderRelayLoc="$mtaConfLoc/sender_relay"
step_100_info() {
step_100_info() {
echo "Send testmail [-u SYSTEMUSER | -f FROM] [TO]"
echoinfo "Send as current user to postmaster@\$MAS_DOMAIN by default"
}
step_100_alias() { ALIAS="test"; }
step_100_alias() { echo "test"; }
step_100() {
shift
local arg
local fromAdr
local toAdr="postmaster@$MAS_DOMAIN"
local asUser=
for arg in "$@" ; do
for _ in "$@" ; do
case "$1" in
-f)
shift
fromAdr="-f $1 "
shift
;;
fromAdr="-f ${1:-} "
shift ;;
-u)
shift
asUser="sudo -u $1 "
shift
;;
asUser="sudo -u ${1:-} "
shift ;;
*)
break
;;
break ;;
esac
done
if [ ! -z $1 ] ; then
toAdr="$1"
fi
exe ${asUser}sh -c "echo \"Subject: Test from Postfix\nIt is \$(date)\n\nGreetings \$(whoami)\" | sendmail ${fromAdr}$toAdr"
[ -n "${1:-}" ] && toAdr="$1"
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_alias() { ALIAS="showqueue"; }
step_102_alias() { echo "showqueue"; }
step_102() {
exe sendmail -bp
}
@@ -452,15 +441,15 @@ step_104_info() {
echo "Delete mail queue [ID]"
echoinfo "Delete all queued mails if [ID] is empty"
}
step_104_alias() { ALIAS="delqueue"; }
step_104_alias() { echo "delqueue"; }
step_104() {
shift
local msgId="ALL"
if [ ! -z $1 ] ; then
msgId="$1"
fi
[ -n "${1:-}" ] && msgId="$1"
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

View File

@@ -1,68 +1,56 @@
#!/bin/bash
toolName=matrix-commander
toolCloneUrl='https://github.com/8go/matrix-commander.git'
toolDeps="python3-pip python3-venv libolm-dev"
readonly toolName=matrix-commander
readonly toolCloneUrl='https://github.com/8go/matrix-commander.git'
readonly toolDeps="python3-pip python3-venv libolm-dev"
toolCredentialDir=
toolEncStoreDir=
# Get script working directory
# (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"
sq_aptOpt=
step_config() {
seq_config() {
## or to use sequencer api with global config file:
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
else
if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
# End if no configuration file exists
[ $DRY -eq 0 ] && return -1
dry || return -1
fi
toolCredentialDir="$MACO_BASE_DIR/.config/matrix-commander"
toolEncStoreDir="$MACO_BASE_DIR/.local/share/matrix-commander"
## 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 0
}
step_1_info() { echo "Run $toolName"; }
step_1_alias() { ALIAS="run"; }
step_1_alias() { echo "run"; }
step_1() {
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() {
echoinfoArgs "[MESSAGE] [MESSAGE] ..."
step_3_info() {
echo "Send 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() {
shift
step run -m "$@"
step run -m "$@"
}
step_50_info() { echo "Install $toolName dependencies"; }
step_50_alias() { ALIAS="install"; }
step_50_alias() { echo "install"; }
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() {
id $MACO_USER >/dev/null 2>&1
[ $? -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"
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 chown -R $MACO_USER: "$MACO_BASE_DIR"
@@ -91,15 +79,15 @@ dbus-python
notify2
NOTES_END
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
}
step_55_info() {
step_55_info() {
echo "Create systemd service for $toolName"
echoinfo "(Make sure to modify the service content in the step configuration)"
}
step_55_alias() { ALIAS="service"; }
step_55_alias() { echo "service"; }
step_55() {
local macommanderServiceLoc="/etc/systemd/system/matrix-commander.service"
addConf -s "$MACO_SERVICE" "$macommanderServiceLoc"
@@ -107,24 +95,24 @@ step_55() {
}
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() {
exe sudo -u "$MACO_USER" mkdir -p "$toolCredentialDir" "$toolEncStoreDir"
exe cd "$toolCredentialDir"
step run
[ -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() {
outColor green
color green
cat <<NOTES_EOF
# Verify matrix-commander "device"
For emoji verification to work, the matrix-commander user needs to be at least in one room.
Enter the room on Element and goto
Enter the room on Element and goto
* Room Info -> People -> select matrix commander user -> Security -> sessions -> matrix-commander session
* verify with emojis
@@ -134,11 +122,13 @@ Enter the room on Element and goto
matrix-commander expects the following files to be in place for the user to be able to
send/receive messages
credentials.json - $MACO_BASE_DIR/.config/matrix-commander/credentials.json
credentials.json - $MACO_BASE_DIR/.config/matrix-commander/credentials.json
store - $MACO_BASE_DIR/.local/share/matrix-commander/store
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

View File

@@ -14,36 +14,36 @@ 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:
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
dry || return -1
fi
## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && APTOPT="-y"
quiet && APTOPT="-y"
echoerr " [W] $SCRIPT_NAME is still in alpha stage"
echoerr " TODO: - systemd script"
echoerr " - initial config creation"
warning -e "$SCRIPT_NAME is still in alpha stage"
error -e " TODO: - systemd script"
error -e " - initial config creation"
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Install $toolName dependencies"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exep curl -sL https://deb.nodesource.com/setup_12.x \| bash -
exe apt install $toolAptDeps $APTOPT
}
step_2_info() { echo "Setup and build"; }
step_2_alias() { ALIAS="setup"; }
step_2_alias() { echo "setup"; }
step_2() {
if [ ! -e "$SEQ_DIMENSION_DIR" ]; then
exe mkdir -p "$SEQ_DIMENSION_DIR"
@@ -62,10 +62,10 @@ step_2() {
}
step_10_info() { echo "Start $toolName"; }
step_10_alias() { ALIAS="start"; }
step_10_alias() { echo "start"; }
step_10() {
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;
fi
exe cd "$SEQ_DIMENSION_DIR"
@@ -75,5 +75,5 @@ step_10() {
exep NODE_ENV=production node build/app/index.js
}
VERSION_SEQREV=15
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -1,14 +1,14 @@
#!/bin/bash
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+=" jq" # used as helper for api access
readonly toolName=synapse
toolDeps="build-essential python3-dev libffi-dev python3-pip python3-venv python3-setuptools postgresql libssl-dev libjpeg-dev libxslt1-dev libpq5 libpq-dev"
readonly toolDeps+=" jq" # used as helper for api access
toolDepsRaspi="libopenjp2-7 libtiff5"
toolUser="synapse"
toolGroup="synapse"
toolServiceName="matrix-synapse"
synapseHashTool="env/bin/hash_password"
toolUrlLocal="http://localhost:8008"
readonly toolUser="synapse"
readonly toolGroup="synapse"
readonly toolServiceName="matrix-synapse"
readonly synapseHashTool="venv/bin/hash_password"
readonly toolUrlLocal="http://localhost:8008"
# Filled by configuration
toolConfig=
toolUrl=
@@ -18,16 +18,12 @@ postgresDb=""
postgresUser=""
postgresPass=""
# 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="matrix.cfg"
CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
sq_aptOpt=
sq_config=0
step_config() {
seq_config() {
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"
else
osName=$(lsb_release -is)
@@ -35,51 +31,48 @@ step_config() {
fi
if [ "$osName" == "" ] ; then
echoerr " [W] Error dedecting OS. Assuming Raspberry Pi OS"
warning -e "Error dedecting OS. Assuming Raspberry Pi OS"
osName="Raspbian"
fi
echo " [I] Detected OS: $osName $distName"
info "Detected OS: $osName $distName"
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
toolConfig="${MATRIX_HOME}/homeserver.yaml"
toolUrl="https://$MATRIX_DOMAIN"
localHome="$MATRIX_HOME"
echo " $toolName home: $MATRIX_HOME"
echo " $toolName domain: $MATRIX_DOMAIN"
info -a "$toolName home: $MATRIX_HOME"
info -a "$toolName domain: $MATRIX_DOMAIN"
else
# End if no configuration file exists
dry || return 1
fi
## Apt cmdline option to suppress user interaction
interactive || sq_aptOpt="-y"
return 0
}
step_1_info() { echo "Installing $toolName dependencies"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
local aptOption=
exe apt update
endReturn -o $? "Updating apt repositories failed"
if [ $QUIET -ne 0 ] ; then
aptOption="-y"
else
aptOption=""
fi
endReturn "Updating apt repositories failed"
if [ "$osName" != "Raspbian" ] ; then
toolDepsRaspi=""
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_alias() { ALIAS="createdb"; }
step_2_alias() { echo "createdb"; }
step_2() {
readDatabaseInfos
exe cd ~postgres
exe cd ~postgres
exe su -c "psql -c \"CREATE USER ${postgresUser} WITH ENCRYPTED password '${postgresPass}';\"" - postgres
exe su -c "psql -c \"CREATE DATABASE ${postgresDb} ENCODING \"UTF8\" LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER ${postgresUser};\"" - postgres
exe su -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE \"${postgresDb}\" to ${postgresUser};\"" - postgres
@@ -92,19 +85,23 @@ step_3() {
}
step_4_info() { echo "Install $toolName"; }
step_4_alias() { ALIAS="virtualenv"; }
step_4_alias() { echo "virtualenv"; }
step_4() {
exe mkdir -p "$MATRIX_HOME"
exe virtualenv -p python3 "${MATRIX_HOME}/env"
exe python3 -m venv "${MATRIX_HOME}/venv"
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 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_alias() { ALIAS="defaultconfig"; }
step_5_alias() { echo "defaultconfig"; }
step_5() {
# Create default configuration
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_alias() { ALIAS="systemd"; }
step_7_alias() { echo "systemd"; }
step_7() {
# eval needed to expand sourced configuration variables
local localService=`eval "echo \"$toolService\""`
@@ -141,9 +138,9 @@ After=network.target postgresql.service
[Service]
Type=forking
WorkingDirectory=\${MATRIX_HOME}/
ExecStart=\${MATRIX_HOME}/env/bin/synctl start
ExecStop=\${MATRIX_HOME}/env/bin/synctl stop
ExecReload=\${MATRIX_HOME}/env/bin/synctl restart
ExecStart=\${MATRIX_HOME}/venv/bin/synctl start
ExecStop=\${MATRIX_HOME}/venv/bin/synctl stop
ExecReload=\${MATRIX_HOME}/venv/bin/synctl restart
User=\${toolUser}
Group=\${toolGroup}
Restart=always
@@ -154,48 +151,52 @@ SyslogIdentifier=synapse
[Install]
WantedBy=multi-user.target"
step_10_info() {
step_10_info() {
echo -n "Upgrade $toolName installation"
if [ $CONTEXT_HELP -eq 0 ] ; then
if ! contextHelp ; then
echo " at $MATRIX_HOME"
else
echo
fi
}
step_10_alias() { ALIAS="upgrade"; }
step_10_alias() { echo "upgrade"; }
step_10() {
echo " [I] Upgrading $toolName"
exe source "${MATRIX_HOME}/env/bin/activate"
if [[ -z "$(command -v rustc)" ]] ; then
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 matrix-synapse
saveReturn $?
exe deactivate
enableErrorCheck
endReturn "Error upgrading $toolName"
echo " [I] Restarting $toolName"
info "Restarting $toolName"
step restart
echo " [I] New Version:"
info "New Version:"
exe sleep 2
step version
}
step_12_info() { echo "Restart $toolName systemd service"; echo; }
step_12_alias() { ALIAS="restart"; }
step_12_alias() { echo "restart"; }
step_12() {
exe service ${toolServiceName} restart
}
step_14_info() {
echoinfoArgs "[IP]:8008"
step_14_info() {
echo "Show $toolName version"
}
step_14_alias() { ALIAS="version"; }
step_14_options() { echo "[IP]:8008"; }
step_14_alias() { echo "version"; }
step_14() {
local synapseIP=localhost
shift
if [ ! -z $1 ]; then
synapseIP="$1"
fi
[ -n "${1:-}" ] && synapseIP="$1"
local apiCall="http://${synapseIP}:8008/_synapse/admin/v1/server_version"
# -sS to suppress download progress of curl
@@ -203,21 +204,21 @@ step_14() {
}
step_16_info() {
echoinfoArgs "[OPTION] [IP]:8008"
echo "List all registered users"
echoinfo "[OPTION]"
echoinfo " -r : Raw json output"
}
step_16_alias() { ALIAS="listuser"; }
step_16_options() { echo "[OPTION] [IP]:8008"; }
step_16_alias() { echo "listuser"; }
step_16() {
adminTokenCheck
endReturn -o $? "Admin token needed. Check $SEQ_CONFIG_FILE"
endReturn "Admin token needed. Check $seq_configFile"
shift
local synapseIP=localhost
local grepOut=" | grep -E '(\"total\":|\"name\":)'"
for arg in "$@" ; do
for _ in "$@" ; do
case "$1" in
-r)
grepOut=""
@@ -229,39 +230,37 @@ step_16() {
esac
done
if [ ! -z $1 ]; then
synapseIP="$1"
fi
[ -n "${1:-}" ] && synapseIP="$1"
local apiCall="http://${synapseIP}:8008/_synapse/admin/v2/users"
exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \"$apiCall\" | python -m json.tool $grepOut"
}
step_18_info() { echo "Create new user"; }
step_18_alias() { ALIAS="adduser"; }
step_18_alias() { echo "adduser"; }
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
echoinfoArgs "[USER NAME]"
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() {
shift
local user=
if [ ! -z $1 ]; then
if [ -n "${1:-}" ]; then
user="$1"
else
exe read -p "User name: " user
fi
if [ -z $user ]; then
echoerr "No user name provided"
error -e "No user name provided"
return 1
fi
local pw="$("${MATRIX_HOME}/${synapseHashTool}")"
@@ -271,23 +270,23 @@ step_20() {
exep "echo \"$string\" | su postgres -c 'psql -d synapse -f -'"
}
step_22_info() {
echoinfoArgs "[OPTION] [IP]:8008"
step_22_info() {
echo "List all rooms"
echoinfo "[OPTION]"
echoinfo " -r : Raw json output"
}
step_22_alias() { ALIAS="listrooms"; }
step_22_options() { echo "[OPTION] [IP]:8008"; }
step_22_alias() { echo "listrooms"; }
step_22() {
adminTokenCheck
endReturn -o $? "Admin token needed. Check $SEQ_CONFIG_FILE"
endReturn "Admin token needed. Check $seq_configFile"
shift
local arg
local synapseIP=localhost
local grepOut=" | grep -E '(\"total\":|\"name\":|\"room_id\":)'"
for arg in "$@" ; do
for _ in "$@" ; do
case "$1" in
-r)
grepOut=""
@@ -299,31 +298,29 @@ step_22() {
esac
done
if [ ! -z $1 ]; then
synapseIP="$1"
fi
[ -n "${1:-}" ] && synapseIP="$1"
local apiCall="http://${synapseIP}:8008/_synapse/admin/v1/rooms"
exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \"$apiCall\" | python -m json.tool $grepOut"
}
step_24_info() {
echoinfoArgs "[OPTION] [ROOM ID] [IP]:8008"
step_24_info() {
echo "List all room members"
echoinfo "[OPTION]"
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() {
adminTokenCheck
endReturn -o $? "Admin token needed. Check $SEQ_CONFIG_FILE"
endReturn "Admin token needed. Check $seq_configFile"
shift
local roomId=""
local synapseIP=localhost
local grepOut=" | grep -E '(\"total\":|\"members\":|\"@)'"
for arg in "$@" ; do
for _ in "$@" ; do
case "$1" in
-r)
grepOut=""
@@ -335,37 +332,33 @@ step_24() {
esac
done
if [ ! -z $1 ]; then
if [ -n "${1:-}" ]; then
roomId="$1"
shift
fi
if [ ! -z $1 ]; then
synapseIP="$1"
fi
[ -n "${1:-}" ] && synapseIP="$1"
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"
}
step_26_info() {
echoinfoArgs "[IP]:8008"
step_26_info() {
echo "Delete rooms without local users"
echoinfo " [IP] : default is localhost"
}
step_26_alias() { ALIAS="purge"; }
step_26_options() { echo "[IP]:8008"; }
step_26_alias() { echo "purge"; }
step_26() {
adminTokenCheck
endReturn -o $? "Admin token needed. Check $SEQ_CONFIG_FILE"
endReturn "Admin token needed. Check $seq_configFile"
shift
local i
local arg
local synapseIP=localhost
if [ ! -z $1 ]; then
synapseIP="$1"
fi
[ -n "${1:-}" ] && synapseIP="$1"
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') )
@@ -380,31 +373,27 @@ step_26() {
}
step_28_info() {
echoinfoArgs "<ROOM ID> [IP]:8008"
echo "Delete room"
}
step_28_alias() { ALIAS="deleteroom"; }
step_28_info() { echo "Delete room"; }
step_28_options() { echo "<ROOM ID> [IP]:8008"; }
step_28_alias() { echo "deleteroom"; }
step_28() {
adminTokenCheck
endReturn -o $? "Admin token needed. Check $SEQ_CONFIG_FILE"
endReturn "Admin token needed. Check $seq_configFile"
shift
local roomId=""
local synapseIP=localhost
if [ ! -z $1 ]; then
if [ -n "${1:-}" ]; then
roomId="$1"
shift
else
endReturn -o 1 "No room ID specified"
fi
if [ ! -z $1 ]; then
synapseIP="$1"
fi
[ -n "${1:-}" ] && synapseIP="$1"
echo " [I] Deleting room with ID: $roomId"
info "Deleting room with ID: $roomId"
local apiCall="http://${synapseIP}:8008/_synapse/admin/v2/rooms/$roomId"
exep "curl -sS --header \"Authorization: Bearer $MATRIX_ACCESS\" \
@@ -429,29 +418,30 @@ postDataDeleteRoom()
EOF
}
step_30_info() { echoinfoArgs "[DATABASE]"; echo "Debloat postgres"; echo; }
step_30_alias() { ALIAS="debloat"; }
step_30_info() { echo "Debloat postgres"; echo; }
step_30_options() { echo "[DATABASE]"; }
step_30_alias() { echo "debloat"; }
step_30() {
shift
local pgVerboseReId=" (VERBOSE) "
local pgVerboseVac=" VERBOSE"
if [ $VERBOSE == 0 ]; then
if ! verbose; then
pgVerboseReId=" "
pgVerboseVac=""
fi
if [ -z $1 ]; then
if [ -z "${1:-}" ]; then
readDatabaseInfos
else
postgresDb="$1"
fi
echo " [I] Stopping ${toolServiceName}"
info "Stopping ${toolServiceName}"
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 -c \"VACUUM FULL${pgVerboseVac};\"" - postgres
@@ -460,91 +450,97 @@ step_30() {
}
step_50_info() { echo "Drop postgres database for $toolName"; }
step_50_alias() { ALIAS="dropdb"; }
step_50_alias() { echo "dropdb"; }
step_50() {
readDatabaseInfos
exe cd ~postgres
exe cd ~postgres
exe su -c "psql -c \"DROP DATABASE ${postgresDb};\"" - postgres
}
step_52_info() { echo "Backup postgres database"; }
step_52_alias() { ALIAS="backupdb"; }
step_52_alias() { echo "backupdb"; }
step_52() {
local DELYEAR=$(($(date +%Y)-2))
if [ ! -s ~/.pgpass ] ; then
echo " [I] For unattended backup please define ~/.pgpass containing credentials"
echo " e.g. localhost:5432:database:user:pass"
echo "Backup custom pg format with standard user / database: synapse / synapse"
info "For unattended backup please define ~/.pgpass containing credentials"
info -a " e.g. localhost:5432:database:user:pass"
info -a "Backup custom pg format with standard user / database: synapse / synapse"
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}*
}
toolDbBackupFolder=/root/backupdb
step_54_info() { echo "Postgres database restore"; }
step_54_alias() { ALIAS="restoredb"; }
step_54_alias() { echo "restoredb"; }
step_54() {
echo " [I] Postgres database restore procedure"
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 " e.g. psql -h 127.0.0.1 -U synapse -d synapse -W -f 2018-06-07_18-10-56.sql"
echo "or"
echo "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
echo "Available postgresql databases:"
info "Postgres database restore procedure"
cat <<RESTORE_END
1. Create a empty postgres database first (step 4)
2. psql -h <host> -U <database user> -d <database name> -W -f <sql dump file>
e.g. psql -h 127.0.0.1 -U synapse -d synapse -W -f 2018-06-07_18-10-56.sql
or
3. Custom postgres format dump restore:
pg_restore -h localhost -p 5432 -U synapse -d new_db -v "10.70.0.61.backup"
RESTORE_END
info "Available postgresql databases:"
exe cd ~postgres
exe su postgres -c "psql -c '\l'"
echo "Available postgresql user:"
info -a "Available postgresql user:"
exe su postgres -c "psql -c '\du'"
}
step_56_info() { echo "$toolName migration notes"; }
step_56_alias() { ALIAS="migrate"; }
step_56_alias() { echo "migrate"; }
step_56() {
echo " [I] Backup database"
echo " ./postgres.sh backupdb synapse"
echo
echo " [I] Backup virtual env folders except \"env\""
echo " cd ${MATRIX_HOME}"
echo " tar czf ../\`date +%Y-%m-%d\"_\"%H-%M-%S\`.synapse_bu.tar.gz --exclude=\"./env\" ."
echo
echo " [I] Transfer both backup files to target server"
echo
echo " [I] Install $toolName on the target server up to step \"virtualenv\""
echo " (Stop after first run and edit $SEQ_CONFIG_FILE)"
echo " ./matrix.sh install"
echo " cd ${MATRIX_HOME}"
echo " tar xf ...synapse_bu.tar.gz"
echo " Follow the instructions of:"
echo " ./matrix.sh restoredb"
echo " ./matrix.sh systemd"
echo
echo " [I] $toolName should be running. Now modify the reverse proxy configuration"
color green
cat <<MIGRATE_END
# Backup database
./postgres.sh backupdb synapse
# Backup virtual venv folders except "venv"
cd ${MATRIX_HOME}
tar czf ../\$(date +%Y-%m-%d"_"%H-%M-%S).synapse_bu.tar.gz --exclude="./venv" .
# Transfer both backup files to target server
# Install $toolName on the target server up to step "virtualenv"
(Stop after first run and edit $seq_configFile)
./matrix.sh install
cd ${MATRIX_HOME}
tar xf ...synapse_bu.tar.gz
Follow the instructions of:
./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
readDatabaseInfos() {
if [ "$postgresDb" == "" ] ; then
read -p "Enter postgres database name: " postgresDb
endCheckEmpty postgresDb "database"
endIfEmpty postgresDb "database"
fi
if [ "$postgresUser" == "" ] ; then
read -p "Enter postgres user name: " postgresUser
endCheckEmpty postgresUser "user name"
endIfEmpty postgresUser "user name"
fi
if [ "$postgresPass" == "" ] ; then
read -s -p "Enter postgres password: " postgresPass
endCheckEmpty postgresPass "password"
endIfEmpty postgresPass "password"
fi
echo
}
# Needs readDatabaseInfos() to execute some commands
toolScript() {
if [ ! -z "$1" ] ; then
if [ -n "${1:-}" ] ; then
readDatabaseInfos
fi
}
@@ -552,12 +548,14 @@ toolScript() {
# End step if no admin access token is configured
adminTokenCheck() {
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
[ -z "$MATRIX_ACCESS" ] && return 1
fi
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

View File

@@ -3,31 +3,28 @@
#
## Installation of chat bridge matterbridge
toolName="matterbridge"
repoName="42wim"
toolLatestUrl="https://api.github.com/repos/${repoName}/${toolName}/releases/latest"
toolVersion=$(curl --silent "$toolLatestUrl" | grep -Po '"tag_name": "v\K.*?(?=")')
toolDownload="https://github.com/${repoName}/${toolName}/releases/download/v${toolVersion}/${toolName}-${toolVersion}-linux-armv6"
toolDir="/usr/local/bin"
toolLoc="${toolDir}/${toolName}"
toolWdir="/opt/${toolName}"
toolConfig="${toolName}.toml"
toolConfigLoc="${toolWdir}/${toolConfig}"
toolService="[Unit]
readonly toolName="matterbridge"
readonly repoName="42wim"
readonly toolLatestUrl="https://api.github.com/repos/${repoName}/${toolName}/releases/latest"
readonly toolVersion=$(curl --silent "$toolLatestUrl" | grep -Po '"tag_name": "v\K.*?(?=")')
readonly toolDownload="https://github.com/${repoName}/${toolName}/releases/download/v${toolVersion}/${toolName}-${toolVersion}-linux-armv6"
readonly toolDir="/usr/local/bin"
readonly toolLoc="${toolDir}/${toolName}"
readonly toolWdir="/etc/${toolName}"
readonly toolConfig="${toolName}.toml"
readonly toolConfigLoc="${toolWdir}/${toolConfig}"
readonly toolUser='matterbridge'
readonly toolService="[Unit]
Description=${toolName}
After=network.target matrix-synapse.service
After=network-online.target matrix-synapse.service
[Service]
Type=simple
ExecStart=${toolLoc} -conf ${toolWdir}/matterbridge.toml
Restart=always
RestartSec=30
RestartSec=5s
WorkingDirectory=${toolWdir}
User=root
Group=root
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=${toolName}
User=${toolUser}
[Install]
WantedBy=multi-user.target"
@@ -36,20 +33,20 @@ toolServiceLoc="/etc/systemd/system/${toolName}.service"
readonly goDir="/usr/local/go"
readonly goDownLoc="/tmp/go.tar.gz"
step_config() {
if [ -z $toolVersion ] ; then
echoerr " [E] Couldn't determine latest version of $toolName"
seq_config() {
if [ -z "${toolVersion}" ] ; then
error -e "Couldn't determine latest version of $toolName"
fi
}
step_1_info() {
step_1_info() {
echo "Downloading $toolName version ${toolVersion} to ${toolLoc} from:"
echoinfo "$toolDownload"
}
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
step upgrade
endReturn -o $? "Download failed"
endReturn "Download failed"
}
step_2_info() { echo "Create required directory structure"; }
@@ -60,23 +57,28 @@ step_2() {
exe chmod +x ${toolLoc}
}
step_3_info() { echo "Creating systemd service"; }
step_3_info() { echo "Creating system user ${toolUser}"; }
step_3() {
addConf -s "$toolService" "$toolServiceLoc"
endReturn -o $? "Creating service failed"
exe adduser --system --group --home "${toolWdir}" "${toolUser}"
}
step_4_info() { echo "Enable $toolName service"; }
step_4_info() { echo "Creating systemd service"; }
step_4() {
addConf -s "$toolService" "$toolServiceLoc"
endReturn "Creating service failed"
}
step_5_info() { echo "Enable $toolName service"; }
step_5() {
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
}
step_5_info() { echo "Show configuration notes"; }
step_5_alias() { ALIAS="notes"; }
step_5() {
outColor green
step_6_info() { echo "Show configuration notes"; }
step_6_alias() { echo "notes"; }
step_6() {
color green
cat <<NOTES_END
# Sample configuration
@@ -87,26 +89,26 @@ NOTES_END
}
step_10_info() { echo "Backup existing executable"; }
step_10_alias() { ALIAS="backup"; }
step_10_alias() { echo "backup"; }
step_10() {
if [ -f "$toolLoc" ] ; then
local toolBackup=
if [ ! -z ${versionNow} ] ; then
if [ -n "${versionNow}" ] ; then
toolBackup="${toolDir}/${toolName}_${versionNow}"
else
toolBackup="${toolDir}/${toolName}_bu"
fi
exe service ${toolName} stop >>/dev/null 2>&1
echoseq -n " [I] Backing up existing executable to ${toolBackup}..."
exe cp -ar "$toolLoc" "$toolBackup" && echoseq "ok"
exep service ${toolName} stop '>>/dev/null 2>&1'
info -n "Backing up existing executable to ${toolBackup}..."
exe cp -ar "$toolLoc" "$toolBackup" && info -d "ok"
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() {
if [ ! -z $versionNow ] ; then
step_12_info() {
if [ -n "${versionNow}" ] ; then
if [ "$toolVersion" == "$versionNow" ] ; then
echo "No upgrade available. Already on latest: $versionNow"
echo "No upgrade available. Already on latest: $versionNow"
else
echo "Download new version $toolVersion to $toolDir"
echoinfo " - installed version: $versionNow -"
@@ -116,11 +118,11 @@ step_12_info() {
fi
echo
}
step_12_alias() { ALIAS="upgrade"; }
step_12_alias() { echo "upgrade"; }
step_12() {
step backup
exe wget -O "$toolLoc" $toolDownload
endReturn -o $? "Download failed"
exe wget -O "$toolLoc" "${toolDownload}"
endReturn "Download failed"
exe chmod +x "$toolLoc"
exe service ${toolName} restart >>/dev/null 2>&1
return 0
@@ -128,38 +130,40 @@ step_12() {
step_30_info() {
echoinfoArgs "[OPTIONS]"
echo "Download go"
echoinfo " [OPTIONS]"
echoinfo " --arch, -a : armhf(default), arm64"
echoinfo " CPU architecture for downloading go sources"
}
step_30_alias() { ALIAS="build"; }
step_30_options() { echo "[OPTIONS]"; }
step_30_alias() { echo "build"; }
step_30() {
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" |\
sed 's/.*\/\(go.*\)\.linux.*/\1/g')"
local goArch="armhf" #arm64"
case "${1}" in
case "${1:-}" in
--arch|-a)
goArch="${2}"
goArch="${2:-"armhf"}"
shift 2 ;;
esac
[[ "${goArch}" == "armhf" ]] && goArch="armv6l"
local goDownUrl="https://go.dev/dl/${goVer}.linux-${goArch}.tar.gz"
# Download latest go
if [ ! -e "${goDir}" ] ; then
echoseq "Download go${goVer}: ${goDownUrl}"
exe wget -O "${goDownLoc}" ${goDownUrl}
endReturn -o $? "Download ${goVer} failed"
info "Download go${goVer}: ${goDownUrl}"
exe wget -O "${goDownLoc}" "${goDownUrl}"
endReturn "Download ${goVer} failed"
exe tar -C "$(dirname -- "${goDir}")" -xzf "${goDownLoc}"
endReturn -o $? "Extraction ${goVer} failed"
endReturn "Extraction ${goVer} failed"
fi
}
step_31_info() { echo "Compile matterbridge"; }
step_31_alias() { echo 'compile'; }
step_31() {
local mabrTags="\
noapi,\
@@ -185,15 +189,16 @@ whatsappmulti"
exe "${goDir}/bin/go" install -tags ${mabrTags} github.com/42wim/matterbridge@master
step backup
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_alias() { echo "clean"; }
step_32() {
exe rm -f "${goDownLoc}"
}
# Sequence Revision
VERSION_SEQREV=15
# Path to sequencer
# 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,7 +1,6 @@
#!/bin/bash
toolName="Mayan EDMS"
toolVersion="4.2.1"
toolRoot="/opt/mayan-edms"
toolMediaFolder="/opt/mayan-edms/media"
@@ -20,28 +19,30 @@ 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:
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
postgresDb="$MAYAN_DB"
postgresUser="$MAYAN_DBUSER"
postgresPass="$MAYAN_DBPASS"
postgresDb="${MAYAN_DB:-}"
postgresUser="${MAYAN_DBUSER:-}"
postgresPass="${MAYAN_DBPASS:-}"
else
# End if no configuration file exists
[ $DRY -eq 0 ] && return -1
dry || return -1
fi
## 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 0
}
step_1_info() { echo "Install libreoffice without gui"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
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 \
poppler-utils postgresql python3-dev python3-pip python3-venv python3-virtualenv \
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 stop supervisor
@@ -64,16 +65,16 @@ step_3() {
exe adduser --disabled-password --disabled-login --no-create-home --gecos "" mayan
exe usermod -a -G users mayan
exe python3 -m venv ${toolRoot}
endReturn -o $? "Creating virtual environment failed"
endReturn "Creating virtual environment failed"
exe chown -R mayan:mayan ${toolRoot}
}
step_4_info() { echo "Create postgres database for $toolName"; }
step_4_alias() { ALIAS="createdb"; }
step_4_alias() { echo "createdb"; }
step_4() {
readDatabaseInfos
exe cd ~postgres
exe cd ~postgres
exe sudo -u postgres psql -c "CREATE USER ${postgresUser} WITH password '${postgresPass}';"
# -O owner : Specifies the database user who will own the new database.
exe sudo -u postgres createdb -O ${postgresUser} ${postgresDb}
@@ -84,14 +85,14 @@ step_5() {
# upgrade pip first
step upgradepip
exe sudo -u mayan ${toolRoot}/bin/pip install --no-cache-dir mayan-edms==$toolVersion
endReturn -o $? "pip install for $toolName failed"
exe sudo -u mayan ${toolRoot}/bin/pip install --no-cache-dir mayan-edms=="${toolVersion}"
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
endReturn -o $?
endReturn
}
step_6_info() { echo "Supervisord configuration for $toolName"; }
step_6_alias() { ALIAS="supervisorconf"; }
step_6_alias() { echo "supervisorconf"; }
step_6() {
addConf -c "" "$supervisordConfLoc"
toolScript "platformtemplate supervisord > ${supervisordConfLoc}"
@@ -120,25 +121,25 @@ save \"\"
databases 2"
step_10_info() {
echoinfoArgs "[OPTIONS]"
echo "Upgrade $toolName to $toolVersion"
echo "Upgrade $toolName to ${toolVersion:-"latest Version"}"
echoinfo " [OPTIONS]"
echoinfo " super : update also supervisor configuration"
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() {
shift # don't need the step number
step upgradepip
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"
endReturn -o $?
endReturn
exe systemctl stop supervisor
exe sudo -u mayan ${toolRoot}/bin/pip install --no-cache-dir mayan-edms==$toolVersion
endReturn -o $?
exe sudo -u mayan ${toolRoot}/bin/pip install --no-cache-dir mayan-edms=="${toolVersion}"
endReturn
toolScript performupgrade
#toolScript preparestatic --noinput # only < 3.4
case $1 in
case "${1:-}" in
"super")
# Generating new supervisor file
step supervisorconf ;;
@@ -149,15 +150,15 @@ uninstallRemovalsLoc="/tmp/removals.txt"
step_13_info() { echo "$toolName management script"; }
step_13_alias() { ALIAS="manage"; }
step_13_alias() { echo "manage"; }
step_13() {
shift
if [ -z "$1" ] || [ "$1" == "" ] ; then
if [ -z "${1:-}" ] || [ "${1:-}" == "" ] ; then
echo -n "Command (empty for help): "
if [ $DRY != 0 ]; then
if dry; then
echo " dryrun"
else
read command
read command
fi
else
command="$@"
@@ -166,18 +167,18 @@ step_13() {
}
step_15_info() { echo "Upgrade python pip"; }
step_15_alias() { ALIAS="upgradepip"; }
step_15_alias() { echo "upgradepip"; }
step_15()
{
exe ${toolRoot}/bin/pip install --upgrade pip
}
step_20_info() { echo "Backup postgres database to media folder"; }
step_20_alias() { ALIAS="backupdb"; }
step_20_alias() { echo "backupdb"; }
step_20() {
local DELYEAR=$(($(date +%Y)-2))
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 "Backup custom pg format with standard user / database: mayan / mayan"
fi
@@ -188,9 +189,9 @@ toolDbBackupFolder=${toolMediaFolder}/backupdb
step_22_info() { echo "Postgres database restore"; }
step_22_alias() { ALIAS="restoredb"; }
step_22_alias() { echo "restoredb"; }
step_22() {
echo " [I] Postgres database restore procedure"
info "Postgres database restore procedure"
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 " 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() {
if [ -z "$postgresDb" ] ; then
read -p "Enter postgres database name: " postgresDb
endCheckEmpty postgresDb "database"
endIfEmpty postgresDb "database"
fi
if [ -z "$postgresUser" ] ; then
read -p "Enter postgres user name: " postgresUser
endCheckEmpty postgresUser "user name"
endIfEmpty postgresUser "user name"
fi
if [ -z "$postgresPass" ] ; then
read -s -p "Enter postgres password: " postgresPass
endCheckEmpty postgresPass "password"
endIfEmpty postgresPass "password"
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
toolScript() {
if [ ! -z "$1" ] ; then
if [ -n "${1:-}" ] ; then
readDatabaseInfos
fi
@@ -233,5 +238,5 @@ toolScript() {
${toolRoot}/bin/mayan-edms.py $*"
}
VERSION_SEQREV=15
readonly sqr_minVersion=16
. /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_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() {
seq_config() {
## e.g. to source a config file manually:
#. "$CONFIG_FILE"
## or to use sequencer api:
@@ -27,7 +27,7 @@ step_config() {
# CONFIG=1
#fi
if [ "$(which lsb_release)" == "" ] ; then
echoerr " [W] Cannot detect OS. Assuming Ubuntu"
warning -e "Cannot detect OS. Assuming Ubuntu"
SEQ_OSNAME="Ubuntu"
else
SEQ_OSNAME=$(lsb_release -is)
@@ -35,28 +35,28 @@ step_config() {
fi
if [ "$SEQ_OSNAME" == "" ] ; then
echoerr " [W] Error dedecting OS. Assuming Ubuntu"
warning -e "Error dedecting OS. Assuming Ubuntu"
SEQ_OSNAME="Ubuntu"
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_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
local aptOption=
local pyVersion=$(python -V 2>&1)
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
fi
exe apt update
endReturn -o $? "Updating apt repositories failed"
endReturn "Updating apt repositories failed"
if [ $QUIET -ne 0 ] ; then
if quiet ; then
aptOption="-y"
else
aptOption=""
@@ -75,38 +75,38 @@ step_2() {
fi
if [ "$motionUrl" == "" ]; then
echo " [W] Unsupported OS"
warning "Unsupported OS"
return 1
fi
exe wget -O "$motionDownload" $motionUrl
endReturn -o $? "Download motion failed"
endReturn "Download motion failed"
}
motionDownload="/tmp/motion.deb"
step_3_info() { echo "Install downloaded motion version"; }
step_3() {
if [ ! -f "$motionDownload" ]; then
echo " [I] No downloaded motion found attempting download"
info "No downloaded motion found attempting download"
step 2
fi
exe dpkg -i "$motionDownload"
endReturn -o $? "Installing motion failed"
endReturn "Installing motion failed"
}
step_4_info() { echo "Upgrade python pip"; }
step_4_alias() { ALIAS="upgradepip"; }
step_4_alias() { echo "upgradepip"; }
step_4()
{
exe pip install --upgrade pip
endReturn -o $? "Upgrading pip failed"
endReturn "Upgrading pip failed"
}
step_5_info() { echo "Install $toolName"; }
step_5() {
exe pip install motioneye
endReturn -o $? "Installing $toolName failed"
endReturn "Installing $toolName failed"
}
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() {
exe cp "$motioneyeServiceSource" "$motioneyeServiceTarget"
endReturn -o $? "Creating service failed"
endReturn "Creating service failed"
exe systemctl daemon-reload
exe systemctl enable motioneye
exe systemctl start motioneye
@@ -138,13 +138,13 @@ motioneyeServiceSource="/usr/local/share/motioneye/extra/motioneye.systemd-unit-
motioneyeServiceTarget="/etc/systemd/system/motioneye.service"
step_20_info() { echo "Upgrade $toolName"; }
step_20_alias() { ALIAS="upgrade"; }
step_20_alias() { echo "upgrade"; }
step_20() {
step "upgradepip"
exe pip install motioneye --upgrade
endReturn -o $? "Upgrading $toolName failed"
endReturn "Upgrading $toolName failed"
exe systemctl restart motioneye
}
VERSION_SEQREV=11
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -9,25 +9,38 @@ dbUser=
dbRemote=localhost
dbPass=
step_1_info() {
echo "Installation of ${databaseName} packages:"
echoinfo "$databasePackages"
echoinfo "(Consider step \"latest\" first to setup official repository with the latest version)"
}
step_1_alias() { ALIAS=install; }
step_1_info() { echo "Status"; }
step_1_alias() { echo "status"; }
step_1() {
exe apt update
exe apt install $databasePackages
endReturn -o $? "Error instaling $databaseName"
exe apt policy mariadb-server
}
step_2_info() { echo "Secure ${databaseName} installation"; }
step_2() {
step_5_info() { echo "Setup ubuntu $databaseName repository"; }
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
}
step_3_info() { echo "${databaseName} configuration"; }
step_3() {
step_8_info() { echo "${databaseName} configuration"; }
step_8() {
addConf -c "$mariadbConfig" "$mariadbConfigLoc"
echo -n "Restarting mysql ... "
@@ -46,15 +59,7 @@ table_definition_cache=1400
#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() {
echoinfoArgs "[OPTIONS]"
echo "Create mysql database without specific characterset"
echoinfo " [OPTIONS]"
echoinfo " --charset,-c <utf8|utf8mb4> : character set and collate"
@@ -64,26 +69,27 @@ step_10_info() {
echoinfo " Manual password entry for non existing user"
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() {
local arg
local dbOption=
shift
for arg in "$@" ; do
case "$1" in
case "${1:-}" in
--charset|-c)
dbOption="$2"
dbOption="${2:-}"
shift 2;;
--database|-d)
dbName="$2"
dbName="${2:-}"
shift 2 ;;
--user|-u)
dbUser="$2"
dbUser="${2:-}"
shift 2 ;;
--remote|-r)
dbRemote="$2"
shift 2 ;;
dbRemote="${2:-}"
shift 2 ;;
*)
break ;;
esac
@@ -99,171 +105,171 @@ step_10() {
esac
if [ -z "$dbName" ] ; then
echo " [I] Existing mysql databases:"
info "Existing mysql databases:"
exe mysql -u root -e 'SHOW DATABASES;'
read -p "Enter database name: " dbName
fi
endCheckEmpty dbName "database name"
endIfEmpty dbName "database name"
exe mysql -u root -e 'CREATE DATABASE '$dbName' '"$dbOption"';'
endReturn -o $? "Cannot create database $dbName"
endReturn "Cannot create database $dbName"
}
step_11_info() {
echoinfoArgs "[OPTIONS]"
step_11_info() {
echo "Create mysql user"
echoinfo " [OPTIONS]"
echoinfo " --user, -u : user name"
echoinfo " with manual password entry for non existing user"
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() {
local arg
shift
for arg in "$@" ; do
case "$1" in
case "${1:-}" in
--charset|-c)
dbOption="$2"
dbOption="${2:-}"
shift 2;;
--database|-d)
dbName="$2"
dbName="${2:-}"
shift 2 ;;
--user|-u)
dbUser="$2"
dbUser="${2:-}"
shift 2 ;;
--remote|-r)
dbRemote="$2"
shift 2 ;;
dbRemote="${2:-}"
shift 2 ;;
*)
break ;;
esac
done
if [ -z "$dbUser" ] ; then
echo " [I] Existing mysql user:"
info "Existing mysql user:"
exe mysql -u root -e 'SELECT User, Host FROM mysql.user;'
read -p "Enter mysql user name: " dbUser
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
# User does not exist
if [ $DRY -eq 0 ]; then
if ! dry; then
read -s -p "Enter mysql user password: " dbPass
endCheckEmpty dbPass "password"
endIfEmpty dbPass "password"
else
echoseq "Enter mysql password: ...skipped..."
info "Enter mysql password: ...skipped..."
fi
exe mysql -u root -e 'CREATE USER '"'"$dbUser"'"'@'"'"$dbRemote"'"' IDENTIFIED BY '"'"$dbPass"'"';'
endReturn -o $? "Error creating mysql user"
endReturn "Error creating mysql user"
fi
}
step_12_info() {
echoinfoArgs "[OPTIONS]"
step_12_info() {
echo "Grant privileges"
echoinfo " [OPTIONS]"
echoinfo " --database, -d : 'database name'.*"
echoinfo " --user, -u : user name"
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() {
local arg
shift
for arg in "$@" ; do
case "$1" in
case "${1:-}" in
--charset|-c)
dbOption="$2"
dbOption="${2:-}"
shift 2;;
--database|-d)
dbName="$2"
dbName="${2:-}"
shift 2 ;;
--user|-u)
dbUser="$2"
dbUser="${2:-}"
shift 2 ;;
--remote|-r)
dbRemote="$2"
shift 2 ;;
dbRemote="${2:-}"
shift 2 ;;
*)
break ;;
esac
done
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;'
}
step_14_info() {
echoinfoArgs "[OPTIONS]"
step_14_info() {
echo "Revoke all granted privilegs"
echoinfo " [OPTIONS]"
echoinfo " --user, -u : user name"
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() {
local arg
shift
for arg in "$@" ; do
case "$1" in
case "${1:-}" in
--user|-u)
dbUser="$2"
dbUser="${2:-}"
shift 2 ;;
--remote|-r)
dbRemote="$2"
shift 2 ;;
dbRemote="${2:-}"
shift 2 ;;
*)
break ;;
esac
done
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;'
}
step_30_info() { echo "List mysql databases"; }
step_30_alias() { ALIAS="listdb"; }
step_30_alias() { echo "listdb"; }
step_30() {
exe mysql -u root -e 'SHOW DATABASES;'
echo -e "\nDrop userdb by: mysql -u root -e 'DROP DATABASE userdb;'"
}
step_32_info() { echo "List mysql user"; }
step_32_alias() { ALIAS="listuser"; }
step_32_alias() { echo "listuser"; }
step_32() {
exe mysql -u root -e 'SELECT User, Host FROM mysql.user;'
echo -e "\nDrop dbuser by: mysql -u root -e 'DROP USER dbuser@localhost;'"
}
step_34_info() {
echoinfoArgs "[OPTIONS]"
step_34_info() {
echo "Show privileges"
echoinfo " [OPTIONS]"
echoinfo " --user, -u : user name"
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() {
local arg
shift
for arg in "$@" ; do
case "$1" in
case "${1:-}" in
--user|-u)
dbUser="$2"
dbUser="${2:-}"
shift 2 ;;
--remote|-r)
dbRemote="$2"
shift 2 ;;
dbRemote="${2:-}"
shift 2 ;;
*)
break ;;
esac
@@ -272,50 +278,46 @@ step_34() {
exe mysql -u root -e 'SHOW GRANTS FOR '"'"$dbUser"'"'@'"'"$dbRemote"'"';'
}
step_36_info() {
echoinfoArgs "[DATABASE_NAME]"
echo "Size of database"
}
step_36_alias() { ALIAS="sizedb"; }
step_36_info() { echo "Size of database"; }
step_36_options() { echo "[DATABASE_NAME]"; }
step_36_alias() { echo "sizedb"; }
step_36() {
if [ -z "$2" ]; then
if [ -z "${2:-}" ]; then
echo "Please provide a database name. e.g. $0 sizedb mydb_db"
else
exe mysql -u root -e 'SELECT table_schema "DB Name",
ROUND(SUM(data_length + index_length) / 1024 / 1024, 1) "DB Size in MB"
FROM information_schema.tables
ROUND(SUM(data_length + index_length) / 1024 / 1024, 1) "DB Size in MB"
FROM information_schema.tables
WHERE table_schema="'$2'"
GROUP BY table_schema;'
fi
}
step_50_info() {
echoinfoArgs "<DATABASE NAME> <TARGET DIR>"
echo "Backup (dump) a mysql database"
}
step_50_alias() { ALIAS="backup"; }
step_50_info() { echo "Backup (dump) a mysql database"; }
step_50_options() { echo "<DATABASE NAME> <TARGET DIR>"; }
step_50_alias() { echo "backup"; }
step_50() {
shift # step number not used
if [ -z $1 ] ; then
echoerr " [E] No database name provided"
if [ -z "${1:-}" ] ; then
error -e "No database name provided"
return 1
fi
local dbName="$1"
local buTarget="$2"
if [ -z "$2" ] ; then
echoerr " [W] No target directory provided. Using home of current user"
local dbName="${1:-}"
local buTarget="${2:-}"
if [ -z "${2:-}" ] ; then
warning -e "No target directory provided. Using home of current user"
buTarget="$HOME"
elif [ ! -e "$2" ]; then
endReturn -o 1 -f "$2 does not exist"
elif [ ! -e "${2:-}" ]; then
endReturn -o 1 -f "${2:-} does not exist"
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\""
endReturn -o $? "Error creating $dbName backup"
endReturn "Error creating $dbName backup"
}
step_52_info() { echo "Restore a mysql database"; }
step_52_alias() { ALIAS="restore"; }
step_52_alias() { echo "restore"; }
step_52() {
echo "Restore with:"
echo " mysql -e \"DROP DATABASE nextcloud_db\""
@@ -327,18 +329,18 @@ step_52() {
readDatabaseInfos() {
if [ "$dbName" == "" ] ; then
read -p "Enter postgres database name: " dbName
endCheckEmpty dbName "database"
endIfEmpty dbName "database"
fi
if [ "$dbUser" == "" ] ; then
read -p "Enter postgres user name: " dbUser
endCheckEmpty dbUser "user name"
endIfEmpty dbUser "user name"
fi
if [ "$dbPass" == "" ] ; then
read -s -p "Enter postgres password: " dbPass
endCheckEmpty postgresPass "password"
endIfEmpty postgresPass "password"
fi
echo
}
VERSION_SEQREV=14
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -1,32 +1,22 @@
#!/usr/bin/env bash
# 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!")
# 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_configFileName="${toolName}.cfg"
sq_configFileTemplate="$sq_dir/${sq_configFileName}.example"
step_config() {
## or to use sequencer api:
initSeqConfig "$sq_configFileName" "$sq_configFileTemplate"
if [ $? -eq 0 ] ; then
seq_config() {
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
fi
localOcc=( sudo -u $sc_ncServerUser php "$(escpath "$sc_ncInstallDir/occ")" )
}
step_1_info() {
echoinfoArgs "[OCC ARGS]"
echo "Execute occ command"
}
step_1_alias() { ALIAS="occ"; }
step_1_info() { echo "Execute occ command"; }
step_1_options() { echo "[OCC ARGS]"; }
step_1_alias() { echo "occ"; }
step_1() {
shift
@@ -34,19 +24,30 @@ step_1() {
}
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() {
if [ $sq_config -eq 0 ] ; then
echoerr " [E] No configuration found to determine installation directory"
if (( ! sq_config )) ; then
error -e "No configuration found to determine installation directory"
return 1
fi
exe cd "$sc_ncInstallDir"
exe sudo -u www-data php "$ncInstaller"
exe sudo -u www-data php "$ncInstaller"
}
ncInstaller="updater/updater.phar"
step_102_info() { echoinfoArgs "<NC DATABASE> <IPV4 ADDRESS>"; echo "Delete IP from bruteforce table"; }
step_102_alias() { ALIAS="bruteforceRemoveIP"; }
step_21_info() { echo "Running recommended post upgrade procedure"; }
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() {
shift
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}$'
if [ -z $1 ] ; then
echoerr " [E] No database provided"
if [ -f "${sq_dir}/mysql.sh" ] ; then
echo " [I] Available mysql databases:"
"${sq_dir}/mysql.sh" -qq listdb
error -e "No database provided"
if [ -f "${seq_origin}/mysql.sh" ] ; then
info "Available mysql databases:"
"${seq_origin}/mysql.sh" -qq listdb
fi
return 1
else
@@ -67,38 +68,40 @@ step_102() {
if [[ "$2" =~ $ipregex ]] ; then
ip="$2"
else
echoerr " [E] No valid IP:PORT detected: $2"
error -e "No valid IP:PORT detected: $2"
return 1
fi
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_alias() { ALIAS="audioreset"; }
step_104_info() { echo "Reset and rescan the music library in the background for one user"; }
step_104_options() { echo "<USER>"; }
step_104_alias() { echo "audioreset"; }
step_104() {
shift
local ncUser=$1
if [ -z "$ncUser" ] ; then
echoerr " [E] Reset only for single user"
error -e "Reset only for single user"
return 1
fi
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 &"
}
step_106_info() { echoinfoArgs "<USER>"; echo "Scan the music library"; }
step_106_alias() { ALIAS="audioscan"; }
step_106_info() { echo "Scan the music library"; }
step_106_options() { echo "<USER>"; }
step_106_alias() { echo "audioscan"; }
step_106() {
shift
local ncUser=$1
local ncUser="${1:-}"
if [ -z "$ncUser" ] ; then
echoerr " [E] Reset only for single user"
error -e "Reset only for single user"
return 1
fi
@@ -106,22 +109,22 @@ step_106() {
}
step_110_info() { echo "Reset picture preview folder"; }
step_110_alias() { ALIAS="resetpreview"; }
step_110_alias() { echo "resetpreview"; }
step_110() {
if [ -e "${sc_ncDataDir}" ]; then
exe rm -rf "${sc_ncDataDir}/appdata_"*"/preview/"*
echoseq " [I] Rescan app data folder"
info "Rescan app data folder"
exep "${localOcc[@]} files:scan-app-data &"
else
echoerr " [E] Nextcloud data direcotry $sc_ncDataDir not found"
error -e "Nextcloud data direcotry $sc_ncDataDir not found"
return 1
fi
}
step_200_alias() { ALIAS="notes"; }
step_200_alias() { echo "notes"; }
step_200() {
outColor green
color green
cat<<NOTES_END
# Recommended preview settings
[$sc_ncInstallDir/config/config.php]
@@ -136,5 +139,7 @@ occ config:app:set preview jpeg_quality --value="60"
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

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_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() {
seq_config() {
## or to use sequencer api with global config file:
#initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
@@ -26,18 +26,18 @@ step_config() {
# CONFIG=1
#else
# # End if no configuration file exists
# [ $DRY -eq 0 ] && return -1
# dry || return -1
#fi
## 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 0
}
step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
downloadLatest
@@ -63,14 +63,14 @@ downloadLatest() {
if [ ! -e "$tempInstall" ] ; then
exe mkdir -p "$tempDown"
exe wget -O "$tempInstall" $downUrl
endReturn -o $? "Download failed: $downUrl"
endReturn "Download failed: $downUrl"
else
echo " [I] Found existing download: $tempInstall"
info "Found existing download: $tempInstall"
fi
}
tempDown="/tmp/olivetin"
tempInstall="$tempDown/olivetin.deb"
VERSION_SEQREV=13
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

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

View File

@@ -1,59 +1,39 @@
#!/bin/bash
toolName=openvpn
toolDeps=openvpn
toolDefaultConf="/etc/default/openvpn"
toolUserScriptsLoc="/usr/lib/openvpn"
readonly toolName=openvpn
readonly toolDeps=openvpn
readonly toolDefaultConf="/etc/default/openvpn"
readonly toolUserScriptsLoc="/usr/lib/openvpn"
# Get script working directory
# (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"
sq_aptOpt=
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"
seq_config() {
interactive || sq_aptOpt="-y"
return 0
}
step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
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() {
exep "mkdir \"$toolUserScriptsLoc\" 2>>/dev/null"
[ $? -ne 0 ] && \
echoseq " [W] $toolUserScriptsLoc already exists. Not overwriting existing files."
exe cp -n "$CONFIG_DIR"/* "$toolUserScriptsLoc"
warning "$toolUserScriptsLoc already exists. Not overwriting existing files."
exe cp -n "${seq_origin}/${seq_fileName}"/* "$toolUserScriptsLoc"
}
step_10_info() { echo "Open openvpn system start configuration"; }
step_10_alias() { ALIAS="default"; }
step_10_alias() { echo "default"; }
step_10() {
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

View File

@@ -8,7 +8,7 @@
verb 1
# Always add custom nameserver
#dhcp-option DNS 208.67.222.222
#dhcp-option DNS 208.67.222.222
#dhcp-option DNS 84.200.69.80
# Mute common false alarm on WiFi networks

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
step_1_info() { echo "Install python3"; }
step_1() {
exe apt update
exe apt install python3 python3-pip
}
readonly toolName="paperless-ngx"
readonly toolUser="paperless"
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"
step_2_info() { echo "Get paperless using git (checkout 2.7.0)"; }
step_2() {
exe git clone https://github.com/the-paperless-project/paperless.git /opt/paperless
exe cd /opt/paperless && git checkout 2.7.0
}
versionNew=
versionNow=
downUrl=
step_3_info() { echo "Install other dependcies"; }
step_3() {
exe apt install gnupg tesseract-ocr tesseract-ocr-deu imagemagick unpaper libpoppler-cpp-dev optipng
exe pip3 install --user --requirement /opt/paperless/requirements.txt
}
sq_paperlessDownLoc="/tmp/paperless_latest.tar.xz"
sq_aptOpt=
step_4_info() { echo "Paperless configuration file"; }
step_4() {
if [ ! -f /etc/paperless.conf ] ; then
cp -ar paperless.conf.example /etc/paperless.conf
seq_config() {
## or to use sequencer api with global config file:
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
sq_config=1
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
}
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

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
toolName="piwigo"
toolVersion="11.3.0"
# 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
else
[ $DRY -eq 0 ] && return 1
seq_config() {
if ! initSeqConfig "${seq_configName}" "${seq_configTemplate}" ; then
dry || return 1
fi
}
step_30_info() { echo "Backup ${toolName} web direcotry"; }
step_30_alias() { ALIAS="backup"; }
step_30_alias() { echo "backup"; }
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")\""
}
step_31_info() {
echoinfoArgs "[daily|monthly(default]"
echo "Backup ${toolName} database"
}
step_31_alias() { ALIAS="backupdb"; }
step_31_info() { echo "Backup ${toolName} database"; }
step_31_options() { echo "[daily|monthly(default)]"; }
step_31_alias() { echo "backupdb"; }
step_31() {
case "$2" in
case "${2:-}" in
daily|Daily|DAILY)
[ $QUIET -ne 2 ] && echo " [I] Daily backup..."
exep "mysqldump --single-transaction -u root ${PIWI_DB_NAME} | bzip2 -c > \"${PIWI_BU_DIR}/${toolName}_daily.sql.bz2\""
info "Daily backup..."
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..."
exep "mysqldump --single-transaction -u root ${PIWI_DB_NAME} | bzip2 -c > \"${PIWI_BU_DIR}/monthly/\`date +%Y%m%d\`_${toolName}.sql.bz2\""
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"
;;
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

View File

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

View File

@@ -2,97 +2,105 @@
toolName="pixelfed"
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"
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_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
}
step_2_info() { echo -e "Installing $toolName dependencies: $toolDeps"; }
step_2_info() { echo -e "Installing $toolName dependencies"; }
step_2() {
exe apt install $toolDeps -y
endReturn -o $? "Installing deps for $toolName failed"
exe service php7.3-fpm restart
endReturn -o $? "Problems starting $toolName"
exe apt install "${toolPhpDeps[@]/#/${sq_phpName}-}" $toolDeps ${sq_aptOpt}
endReturn "Installing deps for $toolName failed"
exe service ${sq_phpName}-fpm restart
endReturn "Problems starting $toolName"
}
step_3_info() { echo -e "Get $toolName using git"; }
step_3() {
exe git clone -b $toolTag https://github.com/pixelfed/pixelfed.git $toolPath
exe cd $toolPath
exe chown -R www-data:www-data . # change user/group to http user and http group
exe git clone -b $toolTag https://github.com/pixelfed/pixelfed.git "${toolPath:?}"
exe cd "${toolPath:?}"
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 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() {
local mysqlDatabase
local mysqlUser
local mysqlPass
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;'
exe cd "${toolPath:?}"
exe ${seq_origin:?}/composer.sh -qq install
exe sudo -u www-data ${sq_phpName:?} composer.phar install --no-ansi --no-interaction --optimize-autoloader
endReturn "Composer install error"
}
step_5_info() { echo "$toolName configuration"; }
step_5_info() { echo "Create mysql database for $toolName"; }
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 read -p "Edit database settings, hostname, email settings, IMAGE_DRIVER=imagick, etc... (Enter to continue)"
exe vi .env
exe php artisan key:generate
exe php artisan config:cache
exe php artisan storage:link
exe php artisan migrate --force
exe php artisan route:cache
exe ${sq_phpName:?} artisan key:generate
exe ${sq_phpName:?} artisan config:cache
exe ${sq_phpName:?} artisan storage:link
exe ${sq_phpName:?} artisan migrate --force
exe ${sq_phpName:?} artisan route:cache
# Needed for using oauth (app like pixeldroid)
# 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_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_info() { echo "Create admin user"; }
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}"
endReturn -o $? "Failed to add horizon service"
endReturn "Failed to add horizon service"
exe systemctl daemon-reload
exe systemctl enable pixelfed.service
exe service pixelfed start
exe service pixelfed start
}
horizonServiceLoc="/etc/systemd/system/pixelfed.service"
horizonService="\
@@ -117,28 +125,31 @@ RestartSec=2s
Type=simple
User=www-data
Group=www-data
WorkingDirectory=${toolPath}/
ExecStart=/usr/bin/php ${toolPath}/artisan horizon
WorkingDirectory=${toolPath:?}/
ExecStart=/usr/bin/php ${toolPath:?}/artisan horizon
Restart=always
Environment=
[Install]
WantedBy=multi-user.target"
step_8_info() { echo "Create scheduler cron job"; }
step_8_alias() { ALIAS="scheduler"; }
step_8() {
step_9_info() { echo "Create scheduler cron job"; }
step_9_alias() { echo "scheduler"; }
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"
}
schedulerCron="/etc/cron.d/pixelfedScheduler"
schedulerCmd="* * * * * cd ${toolPath} && php artisan schedule:run >>/dev/null 2>&1"
step_9_info() { echo "Nginx configuration"; }
step_9() {
addConf -c "$nginxConfig" "$nginxConfigLoc"
step_10_info() { echo "Nginx configuration"; }
step_10() {
lNginxConfig="$(eval echo "${nginxConfig}")"
addConf -c "$lNginxConfig" "$nginxConfigLoc"
exe ln -s "$nginxConfigLoc" "$nginxConfigEnable"
exe nginx -t
endReturn -o $? "Nginx configuration check error"
endReturn "Nginx configuration check error"
exe service nginx restart
}
@@ -146,7 +157,7 @@ nginxConfigLoc="/etc/nginx/sites-available/pixelfed"
nginxConfigEnable="/etc/nginx/sites-enabled/pixelfed"
nginxConfig="\
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 {
@@ -197,25 +208,25 @@ location ~ /\\.(?!well-known).* {
}"
step_20_info() { echo "Reload configuration (.env)"; }
step_20_alias() { ALIAS="newenv"; }
step_20_alias() { echo "newenv"; }
step_20() {
exe cd $toolPath
exe php artisan config:cache
exe cd ${toolPath:?}
exe sudo -u www-data ${sq_phpName:?} artisan config:cache
exe service pixelfed restart
}
step_22_info() { echo "Create new user"; }
step_22_alias() { ALIAS="createuser"; }
step_22_alias() { echo "createuser"; }
step_22() {
exe cd $toolPath
exe php artisan user:create
exe cd ${toolPath:?}
exe ${sq_phpName:?} artisan user:create
}
step_24_info() { echo "Checkout to dev branch. Losing local changes!"; }
step_24_alias() { ALIAS="forcedev"; }
step_24_alias() { echo "forcedev"; }
step_24() {
exe read -p "Are you sure: y/[n]? " answer
if [ $DRY -eq 0 ] ; then
if ! dry ; then
case $answer in
[yY])
;;
@@ -224,7 +235,7 @@ step_24() {
;;
esac
fi
exe cd $toolPath
exe cd ${toolPath:?}
exe git fetch --all
exe git reset --hard 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_alias() { ALIAS="upgrade"; }
step_100_alias() { echo "upgrade"; }
step_100() {
exe cd $toolPath
exe cd ${toolPath:?}
exe git pull origin $toolTag
endReturn -o $? "git pull failed"
endReturn "git pull failed"
exe git checkout $toolTag
endReturn -o $? "git checkout failed"
endReturn "git checkout failed"
}
step_101_info() { echo "Recommended post update procedure"; }
step_101_alias() { ALIAS="postupdate"; }
step_101_alias() { echo "postupdate"; }
step_101() {
exe cd $toolPath
exe composer install
exe php artisan config:cache
exe php artisan route:cache
exe php artisan view:cache
exe php artisan cache:clear
exe php artisan migrate --force
exe php artisan horizon:purge
exe php artisan horizon:publish
exe php artisan storage:link
exe php artisan instance:actor
exe cd ${toolPath:?}
exe sudo -u www-data ${sq_phpName:?} composer.phar install
exe sudo -u www-data ${sq_phpName:?} artisan config:cache
exe sudo -u www-data ${sq_phpName:?} artisan route:cache
exe sudo -u www-data ${sq_phpName:?} artisan view:cache
exe sudo -u www-data ${sq_phpName:?} artisan cache:clear
exe sudo -u www-data ${sq_phpName:?} artisan migrate --force
exe sudo -u www-data ${sq_phpName:?} artisan horizon:purge
exe sudo -u www-data ${sq_phpName:?} artisan horizon:publish
exe sudo -u www-data ${sq_phpName:?} artisan storage:link
exe sudo -u www-data ${sq_phpName:?} artisan instance:actor
echo -n " [I] Restarting pixelfed horzion service..."
exe service pixelfed restart && echo "ok"
}
# 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_alias() { ALIAS="fixhorizon"; }
step_102_alias() { echo "fixhorizon"; }
step_102() {
exe cd $toolPath
exe php artisan package:discover
exe php artisan horizon:install
exe php artisan route:cache
exe cd ${toolPath:?}
exe sudo -u www-data ${sq_phpName:?} artisan package:discover
exe sudo -u www-data ${sq_phpName:?} artisan horizon:install
exe sudo -u www-data ${sq_phpName:?} artisan route:cache
echo -n " [I] Restarting pixelfed horzion service..."
exe service pixelfed restart && echo "ok"
}
# Sequence Revision
VERSION_SEQREV=7
readonly sqr_minVersion=16
# Path to sequencer
. sequencer.sh

View File

@@ -6,4 +6,4 @@ PFA_SRV_LOC="/srv/postfixadmin"
PFA_WEB_LOC="/var/www/pfa"
PFA_DATABASE="pfa_db"
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
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'
toolConfName="config.local.php"
toolTemplates="templates_c"
toolTemplatesLoc="$PFA_SRV_LOC/$toolTemplates"
toolAdditionsLoc="$PFA_SRV_LOC/ADDITIONS"
latestUrl="https://api.github.com/repos/$toolName/$toolName/releases/latest"
fetchmailUser="fetchmail"
fetchmailDeps="fetchmail liblockfile-simple-perl"
readonly toolName=postfixadmin
# since php8.0 json is always available
readonly toolPhpDeps=(bz2 curl fpm gmp imap intl mbstring mysql xml zip)
readonly toolConfName="config.local.php"
readonly toolTemplates="templates_c"
readonly latestUrl="https://api.github.com/repos/$toolName/$toolName/releases/latest"
readonly fetchmailUser="fetchmail"
readonly fetchmailDeps="fetchmail liblockfile-simple-perl libdbd-mysql-perl"
# 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"
toolTemplatesLoc=
toolAdditionsLoc=
sq_aptOpt=
sq_config=0
step_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
echo " ${toolName} path: ${PFA_WEB_LOC}"
echo " ${toolName} backup: ${PFA_BACKUP}"
echo " php Version: ${PFA_PHP_VERSION}"
CONFIG=1
seq_config() {
if initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
info "${toolName} path: ${PFA_WEB_LOC:-}"
info -a "${toolName} backup: ${PFA_BACKUP:-}"
info -a " php Version: ${PFA_PHP_VERSION:-}"
sq_config=1
toolTemplatesLoc="$PFA_SRV_LOC/$toolTemplates"
toolAdditionsLoc="$PFA_SRV_LOC/ADDITIONS"
else
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_1_info() {
step_1_info() {
# eval needed to expand sourced configuration variables
local localDeps=`eval "echo \"$toolPhpDeps\""`
echo "Install $toolName dependencies:"
echoinfo "$localDeps"
echoinfo "${toolPhpDeps[@]/#/php${PFA_PHP_VERSION:-}-}"
}
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
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 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 upgrade
}
step_3_info() { echo "Install fetchmail"; }
step_3_alias() { ALIAS="install_fetchmail"; }
step_3_alias() { echo "install_fetchmail"; }
step_3() {
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
exe apt install $fetchmailDeps $aptOpt
endReturn -o $? "Failed to install fetchmail"
exe apt install $fetchmailDeps ${sq_aptOpt:-}
endReturn "Failed to install fetchmail"
exe systemctl stop fetchmail
exe systemctl disable fetchmail
}
@@ -66,7 +61,7 @@ step_3() {
step_4_info() { echo "Configure postfixadmin to use fetchmail"; }
step_4() {
echo "# Create mysql config"
echo " [$PFA_SRV_LOC/fetchmail.conf]"
echo " [/etc/mail/postfixadmin/fetchmail.conf]"
echo " # Follow instructions in $toolAdditionsLoc/fetchmail.pl"
echo " \$db_type = 'mysql';"
echo " \$run_dir=\"/var/lock\";"
@@ -74,14 +69,14 @@ step_4() {
echo " [$toolAdditionsLoc/fetchmail.pl]"
echo " # Change path to fetchmail.conf (see above)"
echo
echo " [I] Run step \"timer\" when configuration is done"
info "Run step \"timer\" when configuration is done"
}
step_6_info() {
echo "Create postfixadmin fetchmail systemd timer and reduce syslog entries"
echoinfo "Needs to start after the mysql service"
}
step_6_alias() { ALIAS="timer"; }
step_6_alias() { echo "timer"; }
step_6() {
# eval needed to expand sourced configuration variables
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"
step_7_info() { echo "Create separate log file for fetchmail using rsyslog"; }
step_7_alias() { ALIAS="newlog"; }
step_7_alias() { echo "newlog"; }
step_7() {
addConf -f "$fetchmailRsyslog" "$fetchmailRsyslogLoc"
addConf -f "$fetchmailRotate" "$fetchmailRotateLoc"
addConf -c "$fetchmailRsyslog" "$fetchmailRsyslogLoc"
addConf -c "$fetchmailRotate" "$fetchmailRotateLoc"
exe service rsyslog restart
}
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
& stop"
step_18_info() { echoinfoArgs "[NEW VERSION]"; echo "Check for updates"; }
step_18_alias() { ALIAS="updatecheck"; }
step_18_info() { echo "Check for updates"; }
step_18_options() { echo "[NEW VERSION]"; }
step_18_alias() { echo "updatecheck"; }
step_18() {
shift
local isInstalled=
local latestVersion=
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
latestVersion="$1"
else
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")
if [ $isInstalled -eq 1 ] ; then
echo " [I] Version $latestVersion is already installed"
info "Version $latestVersion is already installed"
return 1
else
echo " [I] Update to $latestVersion available"
info "Update to $latestVersion available"
fi
return 0
}
step_20_info() {
echoinfoArgs "[POSTFIXADMIN SRV ROOT]"
step_20_info() {
echo -n "Create a backup"
if [ $CONFIG -ne 0 ] ; then
if [ $sq_config -ne 0 ] ; then
echo " at $PFA_BACKUP"
else
echo
fi
}
step_20_alias() { ALIAS="backup"; }
step_20_options() { echo "[POSTFIXADMIN SRV ROOT]"; }
step_20_alias() { echo "backup"; }
step_20() {
shift
local tempRoot=
if [ $CONFIG -eq 0 ] ; then
echoerr " [E] No configuration file found"
if [ $sq_config -eq 0 ] ; then
error -e "No configuration file found"
return 1
fi
if [ ! -z $PFA_BACKUP ] ; then
exe mkdir -p "$PFA_BACKUP"
fi
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
tempRoot="$1"
else
tempRoot="$PFA_SRV_LOC"
fi
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 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() {
echoinfoArgs "[CUSTOM VERSION]"
shift
if [ $CONTEXT_EXE -ne 0 ]; then
if contextExe; then
echoinfo -n "Upgrade to version "
if [ -z "$1" ]; then
if [ -z "${1:-}" ]; then
echo -n "$(curl --silent "$latestUrl" | grep -Po '"tag_name": "postfixadmin-\K.*?(?=")')"
else
echo -n "$1"
@@ -215,27 +210,28 @@ step_22_info() {
echo "Upgrade to latest or a custom version from github"
fi
}
step_22_alias() { ALIAS="upgrade"; }
step_22_options() { echo "[CUSTOM VERSION]"; }
step_22_alias() { echo "upgrade"; }
step_22() {
shift # don't need step number
local latestVersion=
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
latestVersion="$1"
else
latestVersion=$(curl --silent "$latestUrl" | grep -Po '"tag_name": "postfixadmin-\K.*?(?=")')
fi
if [ -z $latestVersion ] ; then
echoerr " [E] Cannot determine latest version from github repository"
error -e "Cannot determine latest version from github repository"
return 1
elif [ $QUIET -eq 0 ] ; then
elif interactive ; then
echo
exe read -p "Install $latestVersion to $PFA_SRV_LOC [n]o/(y)es? " answer
case $answer in
[yY])
;;
*)
echoerr " [I] Upgrade aborted"
info -e "Upgrade aborted"
return 1
;;
esac
@@ -245,7 +241,7 @@ step_22() {
# 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")
if [ $isInstalled -eq 1 ] ; then
echoerr " [E] Version $latestVersion is already installed"
error -e "Version $latestVersion is already installed"
return 2
fi
@@ -256,12 +252,12 @@ step_22() {
if [ ! -e "$tempExtract" ] ; then
exe mkdir -p "$tempDown"
exe wget -O "$tempLoc" $downUrl
endReturn -o $? "Download failed: $downUrl"
endReturn "Download failed: $downUrl"
exe cd "$tempDown"
exe tar -xf "$tempLoc"
endReturn -o $? "Extract failed: $tempLoc"
endReturn "Extract failed: $tempLoc"
else
echo " [I] Found existing download: $tempExtract"
info "Found existing download: $tempExtract"
fi
# Installation
@@ -270,12 +266,12 @@ step_22() {
if [ -e "$PFA_SRV_LOC" ] ; then
exe mv "$PFA_SRV_LOC" "$tempBu"
step backup "$tempBu"
endReturn -o $? "Backup failed; $PFA_SRV_LOC renamed!"
endReturn "Backup failed; $PFA_SRV_LOC renamed!"
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 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"
# Setting file permissions
@@ -284,20 +280,20 @@ step_22() {
# Configuration
local webConf="$tempBu/$toolConfName"
if [ -e "$webConf" ] ; then
echo " [I] Copying configuration"
info "Copying configuration"
exe cp -ar "$webConf" "$PFA_SRV_LOC/"
else
echo " [I] Creating empty configuration file $PFA_SRV_LOC/$toolConfName"
exep "echo -e \"# Created gy $WDIR/$(basename $0)\\n\\n# Changeme\" > \"$PFA_SRV_LOC/$toolConfName\""
info "Creating empty configuration file $PFA_SRV_LOC/$toolConfName"
exep "echo -e \"# Created by ${seq_origin:?}/$(basename $0)\\n\\n# Changeme\" > \"$PFA_SRV_LOC/$toolConfName\""
fi
# Templates
local templatesLoc="$tempBu/$toolTemplates"
if [ -e "$templatesLoc" ] ; then
echo " [I] Copying $toolTemplates"
info "Copying $toolTemplates"
exe cp -ar "$templatesLoc" "$toolTemplatesLoc"
else
echo " [I] Creating empty directory $toolTemplatesLoc"
info "Creating empty directory $toolTemplatesLoc"
exe mkdir -p "$toolTemplatesLoc"
exe chown -R www-data: "$toolTemplatesLoc"
fi
@@ -308,21 +304,23 @@ tempDown="/tmp/${toolName}"
tempLoc="$tempDown/${toolName}.tar.gz"
step_23_info() { echo "Clean temporary files: $tempDown"; }
step_23_alias() { ALIAS="clean"; }
step_23_alias() { echo "clean"; }
step_23() {
exe rm -rf "$tempDown"
}
step_100_info() {
echoinfoArgs "[OPTIONS]"
step_100_info() {
echo "Execute $toolName client script"
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() {
shift
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

View File

@@ -1,62 +1,89 @@
#!/bin/bash
toolName=postgres
toolDeps=postgresql
toolUser=postgres
readonly toolName=postgres
readonly toolDeps=postgresql
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
postgresDb=""
postgresUser=""
postgresPass=""
# 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="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
seq_config() {
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 0
}
step_1_info() { echo "Installing $toolName dependencies"; }
step_1_alias() { ALIAS="install"; }
step_1_info() { echo "Status"; }
step_1_alias() { echo "status"; }
step_1() {
local aptOption=
exe apt update
endReturn -o $? "Updating apt repositories failed"
if [ $QUIET -ne 0 ] ; then
aptOption="-y"
else
aptOption=""
fi
exe apt install $toolDeps $aptOption
exe apt policy postgresql
}
step_2_info() { echo "Create postgres database"; }
step_2_alias() { ALIAS="createdb"; }
step_2() {
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 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
exe cd ~postgres
exe cd ~postgres
exe su ${toolUser} -c "psql -c \"CREATE USER ${postgresUser} WITH ENCRYPTED password '${postgresPass}';\""
exe su ${toolUser} -c "psql -c \"CREATE DATABASE ${postgresDb} ENCODING \"UTF8\" LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER ${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_4_alias() { ALIAS="dropdb"; }
step_4() {
step_22_info() { echo "Drop a postgres database"; }
step_22_options() { echo "[DATABASE]"; }
step_22_alias() { echo "dropdb"; }
step_22() {
shift
local dbname=$1
if [ -z $dbname ]; then
if [ -z "$dbname" ]; then
readDatabaseInfos
dbname=$postgresDb
fi
@@ -64,12 +91,13 @@ step_4() {
exe su ${toolUser} -c "psql -c \"DROP DATABASE ${dbname};\""
}
step_6_info() { echoinfoArgs "[DATABASE]"; echo "Size of a postgres database"; }
step_6_alias() { ALIAS="sizedb"; }
step_6() {
step_24_info() { echo "Size of a postgres database"; }
step_24_options() { echo "[DATABASE]"; }
step_24_alias() { echo "sizedb"; }
step_24() {
shift
local dbname=$1
if [ -z $dbname ]; then
if [ -z "$dbname" ]; then
readDatabaseInfos
dbname=$postgresDb
fi
@@ -77,19 +105,20 @@ step_6() {
exe su ${toolUser} -c "psql -c \"SELECT pg_size_pretty( pg_database_size('$dbname') );\""
}
step_8_info() { echo "List available databases"; }
step_8_alias() { ALIAS="listdb"; }
step_8() {
step_26_info() { echo "List available databases"; }
step_26_alias() { echo "listdb"; }
step_26() {
exe cd ~postgres
exe su ${toolUser} -c "psql -c '\l'"
}
step_10_info() { echoinfoArgs "[DATABASE]"; echo "List all tables of a postgres database"; }
step_10_alias() { ALIAS="listtables"; }
step_10() {
step_28_info() { echo "List all tables of a postgres database"; }
step_28_options() { echo "[DATABASE]"; }
step_28_alias() { echo "listtables"; }
step_28() {
shift
local dbname=$1
if [ -z $dbname ]; then
if [ -z "$dbname" ]; then
readDatabaseInfos
dbname=$postgresDb
fi
@@ -97,30 +126,31 @@ step_10() {
exe su ${toolUser} -c "psql -d $dbname -c \"\\dt\""
}
step_20_info() { echoinfoArgs "[DATABASE]"; echo "Backup ${toolName} database"; }
step_20_alias() { ALIAS="backupdb"; }
step_20() {
step_40_info() { echo "Backup ${toolName} database"; }
step_40_options() { echo "[DATABASE]"; }
step_40_alias() { echo "backupdb"; }
step_40() {
shift
local dbname=$1
if [ -z $dbname ]; then
local dbname="$1"
if [ -z "$dbname" ]; then
readDatabaseInfos
dbname=$postgresDb
dbname="$postgresDb"
fi
#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"
#fi
# -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"
exe mkdir -p "$POSTGRES_BACKUP_DIR"
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_22_alias() { ALIAS="restoredb"; }
step_22() {
echo " [I] Postgres database restore procedure"
step_42_info() { echo "Postgres database restore"; }
step_42_alias() { echo "restoredb"; }
step_42() {
info "Postgres database restore procedure"
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 " 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'"
}
step_24_info() {
step_44_info() {
local DELYEAR=$(($(date +%Y)-2))
echoinfoArgs "[DATABASE]"
echo "Clean all ${DELYEAR} backups of a database";
}
step_24_alias() { ALIAS="backupclean"; }
step_24() {
step_44_options() { echo "[DATABASE]"; }
step_44_alias() { echo "backupclean"; }
step_44() {
shift
local DELYEAR=$(($(date +%Y)-2))
local dbname=$1
if [ -z $dbname ]; then
if [ -z "$dbname" ]; then
readDatabaseInfos
dbname=$postgresDb
dbname="$postgresDb"
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
readDatabaseInfos() {
if [ "$postgresDb" == "" ] ; then
read -p "Enter postgres database name: " postgresDb
endCheckEmpty postgresDb "database"
postgresDb=$(ask "Enter postgres database name: ")
endIfEmpty postgresDb "database"
fi
if [ "$postgresUser" == "" ] ; then
read -p "Enter postgres user name: " postgresUser
endCheckEmpty postgresUser "user name"
postgresUser=$(ask "Enter postgres user name: ")
endIfEmpty postgresUser "user name"
fi
if [ "$postgresPass" == "" ] ; then
read -s -p "Enter postgres password: " postgresPass
endCheckEmpty postgresPass "password"
postgresPass=$(ask -s "Enter postgres password: "); echo
endIfEmpty postgresPass "password"
if [[ ! ${postgresPass} == "$(ask -s "Repeat postgres password: ")" ]] ; then
echo
fatal -e "Passwords don't match"
else
echo
fi
fi
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

View File

@@ -24,21 +24,21 @@ CONFIG_FILE_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
#}
step_1_info() { echo "Install $toolDeps"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
local aptOpt=
if [ $QUIET -ne 0 ];then
if quiet;then
aptOpt="-y"
fi
exe apt update
exe apt install "$toolDeps" $aptOpt
}
step_2_info() {
step_2_info() {
echo "Add cron to update whitelist_clients from"
echoinfo "$updateUrl"
}
step_2_alias() { ALIAS="cron"; }
step_2_alias() { echo "cron"; }
step_2() {
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"
step_3_info() { echo "Configuration notes"; }
step_3_alias() { ALIAS="notes"; }
step_3_alias() { echo "notes"; }
step_3() {
echo "$toolNotes"
}
@@ -71,10 +71,10 @@ toolNotes="
"
step_10_info() { echo "Restart $toolName"; }
step_10_alias() { ALIAS="restart"; }
step_10_alias() { echo "restart"; }
step_10() {
exe service $toolName restart
}
VERSION_SEQREV=11
readonly sqr_minVersion=16
. /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
toolName="pyload"
toolBranch="stable"
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 toolName="pyload"
readonly toolBranch="stable"
readonly toolDownload="https://github.com/pyload/pyload.git"
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
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 toolDepsDebian="sudo git python-crypto python-pycurl python-pil python-sleekxmpp tesseract-ocr zip unzip pyhton-openssl libmozjs-60-dev"
readonly toolBuildDeps="rar unrar-nonfree"
# Get script working directory
# (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"
sq_aptOpt=
step_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
CONFIG=1
else
seq_config() {
if ! initSeqConfig "${seq_configName:?}" "${seq_configTemplate:?}" ; then
# End if no configuration file exists
[ $DRY -eq 0 ] && return 1
dry || return 1
fi
[ $QUIET -ne 0 ] && APTOPT="-y"
interactive || sq_aptOpt="-y"
return 0
}
step_1_info() { echo "Apt sources.list check and update"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
echo "Make sure you have the \"deb-src\" entry active in your /etc/apt/sources.list"
echo "Especially check for \"non-free\""
@@ -41,38 +32,38 @@ step_1() {
step_2_info() { echo "Install unrar-nonfree from source"; }
step_2() {
exe apt-get build-dep ${toolBuildDeps} $APTOPT
exe apt-get build-dep ${toolBuildDeps} ${sq_aptOpt}
exe cd /tmp
exe apt-get source -b unrar-nonfree
saveReturn $?
endReturn
exe dpkg -i unrar_*_armhf.deb
exe dpkg -i unrar_*_arm64.deb
exe rm -rf unrar-*
}
step_3_info() {
echoinfoArgs "[TARGET]"
step_3_info() {
echo "Install dependencies"
echoinfo " [TARGET] (default: raspi)"
echoinfo " raspi: Raspberry Pi OS"
echoinfo " debian: Debian"
}
step_3_alias() { ALIAS="deps"; }
step_3_options() { echo "[TARGET]"; }
step_3_alias() { echo "deps"; }
step_3() {
shift
local lDeps="$toolDeps"
case "$1" in
case "${1:-}" in
debian)
lDeps="$toolDepsDebian";;
raspi);;
*)
echoerr " [E] Unrecognized target"
error -e "Unrecognized target"
return 1;;
esac
exe apt-get install ${lDeps} $APTOPT
exe apt-get install ${lDeps} ${sq_aptOpt}
saveReturn $?
endReturn
case "$1" in
case "${1:-}" in
raspi)
exe cd /usr/bin
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() {
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"
}
@@ -115,24 +106,26 @@ ExecStart=/usr/bin/python \${PYL_INSTALL_DIR}/pyLoadCore.py
WantedBy=multi-user.target"
step_7_info() { echo "Add ufw rules"; }
step_7_alias() { ALIAS="ufw"; }
step_7_alias() { echo "ufw"; }
step_7() {
echoseq " [I] Port 9666 needs to be forwarded to the target machine with ssh"
echoseq " ssh -L 9666:localhost:9666 user@host -N"
info "Port 9666 needs to be forwarded to the target machine with ssh"
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 7227 proto tcp comment "pyload remotes"
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_alias() { ALIAS="upgrade"; }
step_10_alias() { echo "upgrade"; }
step_10() {
exe service $toolName stop
exe cd "$PYL_INSTALL_DIR"
exe git pull
echo " [I] Service is not started automatically"
info "Service is not started automatically"
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

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=
RPI_BOOT_CONFIG="/boot/config.txt"
step_config() {
seq_config() {
# Shift away args
local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
# Set download url with specified CPU architecture
PIDOWNURL="https://downloads.raspberrypi.org/raspios_lite_${PIARCH}_latest"
if [ "$(which lsb_release)" == "" ] ; then
echoerr " [W] Cannot detect OS. Assuming Ubuntu"
warning -e "Cannot detect OS. Assuming Ubuntu"
osName="Ubuntu"
else
osName=$(lsb_release -is)
@@ -28,12 +28,12 @@ step_config() {
fi
if [ "$osName" == "" ] ; then
echoerr " [W] Error dedecting OS. Assuming Ubuntu"
warning -e "Error dedecting OS. Assuming Ubuntu"
osName="Ubuntu"
fi
echoseq " Detected OS: $osName $distName"
echoseq " Requested CPU Architecture: $PIARCH"
info " Detected OS: $osName $distName"
info " Requested CPU Architecture: $PIARCH"
return 0
}
@@ -55,10 +55,10 @@ HDSWAPPUUID=
evalArgs() {
local argCount=0
for arg in "$@"; do
case "$1" in
for _ in "$@"; do
case "${1:-}" in
-a|--arch)
if [ ! -z "$2" ]; then
if [ -n "${2:-}" ]; then
PIARCH="$2"
((argCount+=2))
else
@@ -74,20 +74,20 @@ evalArgs() {
return $argCount
}
step_1_info() {
step_1_info() {
# Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
echoinfoArgs "[OPTIONS] [SD CARD DEVICE] [HD DEVICE]"
echo "Download latest Raspberry Pi OS lite image $PIARCH"
if [ $CONTEXT_EXE -ne 0 ]; then
if contextExe; then
echoinfo "Download URL: $PIDOWNURL"
else
echoinfo " [OPTIONS]"
echoinfo " -a, --arch : armhf (default), arm64"
fi
}
step_1_alias() { ALIAS="setup"; }
step_1_options() { echo "[OPTIONS] [SD CARD DEVICE] [HD DEVICE]"; }
step_1_alias() { echo "setup"; }
step_1() {
# Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
@@ -97,51 +97,47 @@ step_1() {
echo -ne " [I] sha256 sum of download:\n "
exe sha256sum "$downLoc"
fi
downImgName="${downDir}/$(zipinfo -1 "$downLoc")"
if [ ! -f "$downImgName" ] ; then
exe unzip "$downLoc" -d "$downDir"
endReturn -o $? "Unzip raspios image $PIARCH failed"
if [ ! -f "$downImgLoc" ] ; then
exe unxz "$downLoc"
endReturn "Unzip raspios image $PIARCH failed"
fi
}
downImgName=""
downDay=$(date +%Y%m%d)
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; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
echoinfoArgs "[OPTIONS] [SD CARD DEVICE]"
echo "Write Raspberry Pi OS image to 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() {
# Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
if [ "$downImgName" == "" ] ; then
# called again to make sure $downImgName is populated
step setup
fi
if [ ! -f "$downImgName" ] ; then
endReturn -o 1 "No raspios image found"
if [ ! -f "$downImgLoc" ] ; then
endReturn -o 1 "Raspios image ${downImgLoc} not found"
fi
if [ $(id -u) -ne 0 ] ; then
endReturn -o 1 "No root"
fi
read_sd_dev "$1"
read_sd_dev "${1:-}"
# check if device was confirmed
if [ $? -ne 0 ] ; then
endReturn -o 1 "SD card device not found"
fi
# 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"
exe sync
@@ -151,26 +147,27 @@ step_2() {
SDROOT=""
# 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."
}
step_3_info() {
step_3_info() {
# Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
echoinfoArgs "[SD CARD DEVICE]"
echo "Prepare SD for first run"
if [ $CONTEXT_EXE -ne 0 ]; then
[ ! -z $1 ] && echoinfo " [SD CARD DEVICE]: $1"
if contextExe; then
[ -n "${1:-}" ] && echoinfo " [SD CARD DEVICE]: $1"
fi
}
step_3_options() { echo "[SD CARD DEVICE]"; }
step_3() {
# Shift away args
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"
else
exe lsblk -p "$SDDEV"
@@ -188,48 +185,60 @@ step_3() {
esac
fi
read_sd_dev "$1"
endReturn -o $? "SD card device not found"
read_sd_dev "${1:-}"
endReturn "SD card device not found"
if [ ! -w "$SDBOOT" ] ; then
echoerr " [E] SD card boot partion not writeable"
error -e "SD card boot partion not writeable"
return 1
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
echo " [I] Enable SSH access"
info "Enable SSH access"
exe touch "$SDBOOT"/ssh
# 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 "$SDROOT"/etc/fstab "$SDROOT"/etc/fstab.sd
}
step_4_info() {
step_4_info() {
# Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
echoinfoArgs "[SD CARD DEVICE] [HD DEVICE]"
echo "Prepare SD card to boot from hard disk"
if [ $CONTEXT_EXE -ne 0 ]; then
[ ! -z $1 ] && echoinfo " [SD CARD DEVICE]: $1"
[ ! -z $2 ] && echoinfo " [HD DEVICE]: $2"
if contextExe; then
[ -n "${1:-}" ] && echoinfo " [SD CARD DEVICE]: $1"
[ -n "${2:-}" ] && echoinfo " [HD DEVICE]: $2"
fi
}
step_4_alias() { ALIAS="hdboot"; }
step_4_options() { echo "[SD CARD DEVICE] [HD DEVICE]"; }
step_4_alias() { echo "hdboot"; }
step_4() {
# Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
read_sd_dev "$1"
endReturn -o $? "SD detection error $?"
read_hd_dev "$2"
endReturn -o $? "HD detection error"
echo " [I] SD: $SDDEV"
read_sd_dev "${1:-}"
endReturn "SD detection error $?"
read_hd_dev "${2:-}"
endReturn "HD detection error"
info "SD: $SDDEV"
echo " $SDBOOT [$SDBOOTPUUID]"
echo " $SDROOT [$SDROOTPUUID]"
echo " [I] HD: $HDDEV"
info "HD: $HDDEV"
echo " $HDROOT [$HDROOTPUUID]"
echo " $HDSWAP [$HDSWAPPUUID]"
echo
@@ -261,10 +270,10 @@ step_4() {
echo
# 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"
if [ $? -ne 0 ] ; then
echoerr " [W] Something seems to have failed during resize"
warning -e "Something seems to have failed during resize"
else
# Disable init script to resize SD
echo -n " [I] remove \"init=\" part from $SDBOOT/cmdline.txt.sd"
@@ -277,50 +286,50 @@ step_4() {
fi
}
step_5_info() {
step_5_info() {
# Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
echoinfoArgs "[SD CARD DEVICE] [HD DEVICE]"
echo "Prepare HD for boot (TODO)"
if [ $CONTEXT_EXE -ne 0 ]; then
[ ! -z $1 ] && echoinfo " [SD CARD DEVICE]: $1"
[ ! -z $2 ] && echoinfo " [HD DEVICE]: $2"
if contextExe; then
[ -n "${1:-}" ] && echoinfo " [SD CARD DEVICE]: $1"
[ -n "${2:-}" ] && echoinfo " [HD DEVICE]: $2"
fi
}
step_5_options() { echo "[SD CARD DEVICE] [HD DEVICE]"; }
step_5() {
# Shift away args
shift; local lArgs=( "$@" ); evalArgs "${lArgs[@]}"; shift $?
#TODO
echoerr " [E] Not ready yet...TODO"
error -e "Not ready yet...TODO"
#return 1
read_sd_dev "$1"
endReturn -o $? "SD detection error $?"
read_sd_dev "${1:-}"
endReturn "SD detection error $?"
read_hd_dev "$2"
endReturn -o $? "HD detection error"
echo " [I] SD: $SDDEV"
read_hd_dev "${2:-}"
endReturn "HD detection error"
info "SD: $SDDEV"
echo " $SDBOOT [$SDBOOTPUUID]"
echo " $SDROOT [$SDROOTPUUID]"
echo " [I] HD: $HDDEV"
info "HD: $HDDEV"
echo " $HDROOT [$HDROOTPUUID]"
echo " $HDSWAP [$HDSWAPPUUID]"
echo
# 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
# 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
# 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=$SDROOTPUUID /backup ext4 ro,defaults,noatime 0 2"
echo " PARTUUID=$HDROOTPUUID / ext4 defaults,noatime 0 1"
@@ -328,26 +337,26 @@ step_5() {
echo
# etc
echo " [I] modify $HDROOT/etc/dhcpcd.conf for static IPs"
info "modify $HDROOT/etc/dhcpcd.conf for static IPs"
}
read_sd_dev() {
local partExt=""
if [ ! -z "$1" ] ; then
if [ -n "${1:-}" ] ; then
SDBOOT=
SDROOT=
SDROOTDEV=
SDROOTPUUID=
SDBOOTPUUID=
SDDEV="$1"
elif [ -z $SDDEV ] || [ ! -b "$SDDEV" ] ; then
elif [ -z "${SDDEV:-}" ] || [ ! -b "$SDDEV" ] ; then
SDDEV=
SDBOOT=
SDROOT=
SDROOTDEV=
SDBOOTPUUID=
SDROOTPUUID=
echo " [I] Available devices:"
info "Available devices:"
echo
exe lsblk -p
echo
@@ -355,14 +364,14 @@ read_sd_dev() {
fi
if [ ! -b "$SDDEV" ] ; then
echoerr " [I] $SDDEV not a block device"
info -e "$SDDEV not a block device"
SDDEV=
return 1
fi
if [[ "$SDDEV" =~ .*blk.* ]] ; then
partExt="p"
fi
fi
if [ -z $SDBOOT ] ; then
SDBOOT=$(findmnt -no TARGET "${SDDEV}${partExt}${SDBOOTPARTNO}")
@@ -385,7 +394,7 @@ SDBOOTPARTNO=1
SDROOTPARTNO=2
read_hd_dev() {
if [ ! -z "$1" ] ; then
if [ -n "${1:-}" ] ; then
HDROOT=
HDROOTPUUID=
HDSWAPPUUID=
@@ -394,7 +403,7 @@ read_hd_dev() {
HDROOT=
HDROOTPUUID=
HDSWAPPUUID=
echo " [I] Available devices:"
info "Available devices:"
echo
exe lsblk -p
echo
@@ -423,17 +432,17 @@ read_hd_dev() {
}
step_20_info() { echo "Disable swap file and remove it"; }
step_20_alias() { ALIAS="disable_swap"; }
step_20_alias() { echo "disable_swap"; }
step_20() {
exe swapoff -a
exe systemctl disable dphys-swapfile
exe rm -rf "$rpiSwapFile"
echoerr " [W] Reboot to apply changes"
if [ $QUIET -eq 0 ] ; then
warning -e "Reboot to apply changes"
if interactive ; then
exe read -p " Reboot now ([n]/y)? " answer
case $answer in
[yY])
echoerr " [I] Rebooting now ..."
info -e "Rebooting now ..."
exe reboot
;;
*)
@@ -443,16 +452,17 @@ step_20() {
}
rpiSwapFile="/var/swap"
step_22_info() { echoinfoArgs "[SD CARD DEVICE]"; echo "Resize second SD card partition"; }
step_22_alias() { ALIAS="resizesd"; }
step_22_info() { echo "Resize second SD card partition"; }
step_22_options() { echo "[SD CARD DEVICE]"; }
step_22_alias() { echo "resizesd"; }
step_22() {
shift
read_sd_dev "$1"
read_sd_dev "${1:-}"
if [ -z $SDDEV ] || [ "$SDDEV" = "" ] || [ "$SDROOT" == "/" ] ; then
echoerr " [E] No SD found"
error -e "No SD found"
return 1
fi
echo " [I] Device to be resized: $SDROOTDEV"
info "Device to be resized: $SDROOTDEV"
exe umount -q "$SDROOT"
exe parted -s "$SDDEV" "resizepart $SDROOTPARTNO -1" quit
@@ -472,18 +482,18 @@ step_22() {
}
step_24_info() {
echoinfoArgs "[OPTION]"
echo "Turn off power LED"
echoinfo " [OPTION]"
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() {
exep "${ledOffCmd}"
if [ ! -z "$2" ] && [ "$2" == "-p" ] ; then
exep "grep \"$ledPowerBright\" $startScript >>/dev/null"
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"
return 1
fi
@@ -497,13 +507,13 @@ ledPowerBright="/sys/class/leds/led1/brightness"
ledOffCmd="sudo sh -c 'echo 0 > ${ledPowerBright}'"
step_26_info() { echo "Restart network without reboot"; }
step_26_alias() { ALIAS="netrestart"; }
step_26_alias() { echo "netrestart"; }
step_26() {
exep "sudo ip link set eth0 down && sudo ip link set eth0 up"
}
step_28_info() { echo "Disable bluetooth"; }
step_28_alias() { ALIAS="disable_bluetooth"; }
step_28_alias() { echo "disable_bluetooth"; }
step_28() {
checkBootConfig "$RPI_CONFIG_DTOVERLAY" "$RPI_CONF_DI_BLUETOOTH"
[ $? -eq 0 ] && endReturn -o 1 "Bluetooth already disabled"
@@ -520,26 +530,26 @@ step_29() {
exe systemctl disable bluealsa.service
exe systemctl disable bluetooth.service
echoseq " [I] Consider uninstalling bluetooth software:"
echoseq "apt purge --autoremove -y bluez"
echoseq
echoseq " [W] Reboot to make changes active"
info "Consider uninstalling bluetooth software:"
info "apt purge --autoremove -y bluez"
info
warning "Reboot to make changes active"
}
step_31_info() { echo "Disable Wifi"; }
step_31_alias() { ALIAS="disable_wifi"; }
step_31_alias() { echo "disable_wifi"; }
step_31() {
checkBootConfig "$RPI_CONFIG_DTOVERLAY" "$RPI_CONF_DI_WIFI"
[ $? -eq 0 ] && endReturn -o 1 "Wifi already disabled"
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_alias() { ALIAS="disable_hdmi"; }
step_33_alias() { echo "disable_hdmi"; }
step_33() {
checkBootConfig "$RPI_CONFIG_HDMI_BLANK" "$RPI_CONF_DI_HDMI"
[ $? -eq 0 ] && endReturn -o 1 "HDMI already disabled"
@@ -554,7 +564,7 @@ step_34() {
exe $tvserviceOffCmd
exep "grep \"$tvserviceBin\" $startScript >>/dev/null"
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"
return 1
fi
@@ -563,28 +573,29 @@ step_34() {
exep "echo \"${tvserviceOffCmd}\" >> $startScript"
exep "echo -e \"\nexit 0\" >> $startScript"
echoseq " [W] Reboot to make changes active"
warning "Reboot to make changes active"
}
tvserviceBin="/usr/bin/tvservice"
tvserviceOffCmd="${tvserviceBin} -o'"
# checkBootConfig <CONFIGNAME> [VALUE]
checkBootConfig() {
[ -z "$1" ] && return 1
[ -z "${1:-}" ] && return 1
local re_check="^[[:blank:]]*[^#]*${1}[[:blank:]]*=[[:blank:]]*$2"
grep -rqE "$re_check" "$RPI_BOOT_CONFIG"
return $?
return $?
}
step_100_alias() { ALIAS="notes"; }
step_100_alias() { echo "notes"; }
step_100() {
outColor green
color green
cat <<NOTES_EOF
# Initial configuration steps
* Set password for pi (\`passwd\`)
* Set password for a user (\`passwd\`)
* Add [\$HOME/.ssh/authorized_keys]
* Disable auto login (\`raspi-config\` -> System Options -> Boot / Auto Login))
* Set hostname (\`raspi-config\` -> System Options))
* Configure Timezone (\`raspi-confg\` -> Localisation Options)
* Set GPU memory (\`raspi-config\` -> Performance Options)
@@ -593,7 +604,7 @@ step_100() {
[/etc/fstab]
> \`PARTUUID=******-03 none swap sw 0 0\`
\`$SEQ_NAME disable_swap\`
\`$seq_name disable_swap\`
* Update system
@@ -608,11 +619,11 @@ step_100() {
* Configure vim to remember last position in a file
Uncomment the following in [/etc/vim/vimrc]
Uncomment the following in [/etc/vim/vimrc]
> \`au BufReadPost ...\`
NOTES_EOF
}
VERSION_SEQREV=15
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -1,38 +1,30 @@
#!/bin/bash
toolName=redis
toolDeps=redis-server
readonly toolName=redis
readonly toolDeps=redis-server
sq_aptOpt=
# 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
seq_config() {
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 0
}
step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
exe apt update
exe apt install $toolDeps $aptOpt
exe apt install $toolDeps $sq_aptOpt
}
step_2_info() { echo "Installation notes"; }
step_2_alias() { ALIAS="notes"; }
step_2_alias() { echo "notes"; }
step_2() {
cat <<NOTES_EOF
# For php applications make sure php-redis is installed
@@ -64,13 +56,13 @@ requirepass verystrongpassword
NOTES_EOF
}
step_10_info() {
echoinfoArgs "[CLI COMMAND]"
step_10_info() {
echo "Execute redis-cli commands"
echoinfo " [CLI COMMAND]"
echoinfo " e.g. info"
}
step_10_alias() { ALIAS="cli"; }
step_10_options() { echo "[CLI COMMAND]"; }
step_10_alias() { echo "cli"; }
step_10() {
shift
local cliCmd="$@"
@@ -82,5 +74,7 @@ step_10() {
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

View File

@@ -1,43 +1,42 @@
#!/bin/bash
toolName=roundcube
toolPhpDeps="php\${phpVersion}-gd php-imagick"
readonly toolName=roundcube
readonly toolPhpDeps=(curl gd intl ldap mbstring mysql xml zip)
readonly toolDeps="php-imagick"
#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=
tempExtract=
tempInstall=
phpVersion=
# 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"
sq_aptOpt=
sq_config=0
step_config() {
## use sequencer api:
initSeqConfig -t "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $CONFIG -eq 0 ] ; then
CONFIG=1
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"
# Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
downloadLatest
fetchPhpVersion
if [ ! -z $phpVersion ] ; then
if [ -n $phpVersion ] ; then
exe apt update
exe apt install `eval echo "$toolPhpDeps"` $aptOpt
exe apt install "${toolPhpDeps[@]/#/php${phpVersion:?}-}" ${toolDeps:?} ${sq_aptOpt:-}
fi
exe chown -R www-data: "$tempExtract"
@@ -53,7 +52,7 @@ step_2() {
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
then
echoerr ' [E] Invalid installer checksum'
error -e ' [E] Invalid installer checksum'
exe rm composer-setup.php
return 1
fi
@@ -65,22 +64,24 @@ step_2() {
}
step_3_info() { echo "Configure $toolName"; }
step_3_alias() { ALIAS="config"; }
step_3_alias() { echo "config"; }
step_3() {
echo " [I] Recommended composer packages to be added to \"require\" section:"
echo ' "melanie2/mobile": "*",'
echo ' "roundcube/carddav": "*",'
echo ' "alexandregz/twofactor_gauthenticator": "dev-master"'
info "Recommended composer packages to be added to \"require\" section:"
echo ' "alexandregz/twofactor_gauthenticator": "dev-master",'
echo ' "johndoh/contextmenu": "*",'
echo ' "kitist/html5_notifier": "*",'
echo ' "roundcube/carddav": "*"'
exe read -p "Copy the lines above and press Enter to continue."
exe vi "$RC_LOC/composer.json"
step postupgrade
echo " [I] Generating mysql database $RC_DATABASE"
info "Generating mysql database $RC_DATABASE"
echo
exe $WDIR/mysql.sh createdb -c utf8mb4
exe ${seq_origin:?}/mysql.sh createdb -c utf8mb4
echo
echo " [I] Now visit: http://url-to-roundcube/installer/"
info "Now visit: http://url-to-roundcube/installer/"
echo
echo " ! Check the database password in $RC_LOC/config/config.inc.php"
echo " afterwards, the installer may have corrupted some special character"
@@ -89,9 +90,10 @@ step_3() {
}
step_10_info() { echo "Configuration notes"; }
step_10_alias() { ALIAS="notes"; }
step_10_alias() { echo "notes"; }
step_10() {
outColor green
fetchPhpVersion
color green
cat <<NOTES_END
# smtp port if missing after installation
[$RC_LOC/config/config.inc.php]
@@ -101,20 +103,10 @@ step_10() {
# Enable two factor auth (installed with step config) for all user
[$RC_LOC/plugins/twofactor_gauthenticator/config.inc.php]
$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"
}
\$rcmail_config['users_allowed_2FA'] = array('.*');
# 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]
\$config['spellcheck_engine'] = 'pspell';
@@ -126,9 +118,9 @@ NOTES_END
}
step_12_info() { echo "Troubleshooting"; }
step_12_alias() { ALIAS="trouble"; }
step_12_alias() { echo "trouble"; }
step_12() {
outColor green
color green
cat <<TROUBLE_END
# On composer update errors.
@@ -140,49 +132,47 @@ I also installed 'php-pear' since one error indicated connection to it.
TROUBLE_END
}
step_20_info() {
step_20_info() {
echo -n "Create a backup"
if [ $CONFIG -ne 0 ] ; then
if (( ${sq_config} )) ; then
echo " at $RC_BACKUP"
else
echo
fi
}
step_20_alias() { ALIAS="backup"; }
step_20_alias() { echo "backup"; }
step_20() {
if [ $CONFIG -eq 0 ] ; then
echoerr " [E] No configuration file found"
if [ ${sq_config} -eq 0 ] ; then
error -e "No configuration file found"
return 1
fi
if [ ! -z $RC_BACKUP ] ; then
exe mkdir -p "$RC_BACKUP"
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"
echo " [I] Backing up webserver directory to $wwwBackup"
info "Backing up webserver directory to $wwwBackup"
exe cd "$RC_LOC/.."
exe tar czf "$wwwBackup" $(basename "$RC_LOC")
}
step_22_info() {
echoinfoArgs "[CUSTOM VERSION]"
echo "Upgrade installation to \"latest\" from github if [CUSTOM_VERSION] is empty"
}
step_22_alias() { ALIAS="upgrade"; }
step_22_info() { echo "Upgrade installation to \"latest\" from github if [CUSTOM_VERSION] is empty"; }
step_22_options() { echo "[CUSTOM VERSION]"; }
step_22_alias() { echo "upgrade"; }
step_22() {
shift # don't need step number
local currentVersion=
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
latestVersion="$1"
else
fetchLatestVersion
fi
if [ -z $latestVersion ] ; then
echoerr " [E] Cannot determine latest version from github repository"
error -e "Cannot determine latest version from github repository"
return 1
elif [ $QUIET -eq 0 ] ; then
elif interactive ; then
echo
currentVersion="$(grep -Po ' \| Version \K.*?(?= )' $RC_LOC/index.php)"
exe read -p "Install $latestVersion over $currentVersion to $RC_LOC [n]o/(y)es? " answer
@@ -190,7 +180,7 @@ step_22() {
[yY])
;;
*)
echoerr " [I] Upgrade aborted"
info -e "Upgrade aborted"
return 1
;;
esac
@@ -198,23 +188,23 @@ step_22() {
local isInstalled=$(grep -E "RELEASE $latestVersion" "${RC_LOC}/CHANGELOG" >>/dev/null && echo "1" || echo "0")
if [ $isInstalled -eq 1 ] ; then
echoerr " [E] Version $latestVersion is already installed"
error -e "Version $latestVersion is already installed"
return 2
fi
downloadLatest
step backup
echo " [I] Installing version $latestVersion to $RC_LOC"
info "Installing version $latestVersion to $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_alias() { ALIAS="postupgrade"; }
step_23_alias() { echo "postupgrade"; }
step_23() {
exe cd "$RC_LOC"
echo " [I] Starting post update procedure"
info "Starting post update procedure"
exe php composer.phar update --no-dev
}
@@ -243,16 +233,18 @@ downloadLatest() {
if [ ! -e "$tempExtract" ] ; then
exe mkdir -p "$tempDown"
exe wget -O "$tempLoc" $downUrl
endReturn -o $? "Download failed: $downUrl"
endReturn "Download failed: $downUrl"
exe cd "$tempDown"
exe tar -xf "$tempLoc"
endReturn -o $? "Extract failed: $tempLoc"
endReturn "Extract failed: $tempLoc"
else
echo " [I] Found existing download: $tempExtract"
info "Found existing download: $tempExtract"
fi
}
tempDown="/tmp/roundcube"
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

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:
# - https://selivan.github.io/2017/02/07/rsyslog-log-forward-save-filename-handle-multi-line-failover.html
toolName="rsyslog"
toolConfig="/etc/rsyslog.conf"
readonly toolName="rsyslog"
readonly toolConfig="/etc/rsyslog.conf"
# Get script working directory
# (when called from a different directory)
WDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
CONFIG_SNMP="$WDIR/${toolName}/10-snmp.conf"
CONFIG_CRON="$WDIR/${toolName}/10-cron.conf"
CONFIG_RNGD="$WDIR/${toolName}/10-rngd.conf"
CONFIG_REMOTE="$WDIR/${toolName}/90-remote.conf"
CONFIG_SNMP="${seq_origin}/${toolName}/10-snmp.conf"
CONFIG_CRON="${seq_origin}/${toolName}/10-cron.conf"
CONFIG_RNGD="${seq_origin}/${toolName}/10-rngd.conf"
CONFIG_REMOTE="${seq_origin}/${toolName}/90-remote.conf"
step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
exe apt install "$toolName"
}
step_2_info() { echo "Check configuration"; }
step_2_alias() { ALIAS="checkconf"; }
step_2_alias() { echo "checkconf"; }
step_2() {
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_alias() { ALIAS="snmpd"; }
step_10_alias() { echo "snmpd"; }
step_10() {
addConf -s -f "$CONFIG_SNMP" "$CONFIG_SNMP_DEST"
endReturn -o $?
endReturn
step checkconf
exe service rsyslog restart
@@ -42,10 +39,10 @@ step_10() {
CONFIG_SNMP_DEST="/etc/rsyslog.d/$(basename $CONFIG_SNMP)"
step_12_info() { echo "Reduce cron syslog messages"; }
step_12_alias() { ALIAS="cron"; }
step_12_alias() { echo "cron"; }
step_12() {
addConf -s -f "$CONFIG_CRON" "$CONFIG_CRON_DEST"
endReturn -o $?
endReturn
step checkconf
exe service rsyslog restart
@@ -53,35 +50,33 @@ step_12() {
CONFIG_CRON_DEST="/etc/rsyslog.d/$(basename $CONFIG_CRON)"
step_14_info() { echo "Reduce rngd syslog messages"; }
step_14_alias() { ALIAS="rngd"; }
step_14_alias() { echo "rngd"; }
step_14() {
addConf -s -f "$CONFIG_RNGD" "$CONFIG_RNGD_DEST"
endReturn -o $?
endReturn
step checkconf
exe service rsyslog restart
}
CONFIG_RNGD_DEST="/etc/rsyslog.d/$(basename $CONFIG_RNGD)"
step_16_info() {
echoinfoArgs "<REMOTE_IP:PORT>"
echo "Send syslog messages to remote syslog server"
}
step_16_alias() { ALIAS="remote"; }
step_16_info() { echo "Send syslog messages to remote syslog server"; }
step_16_options() { echo "<REMOTE_IP:PORT>"; }
step_16_alias() { echo "remote"; }
step_16() {
local rex='^[0-9\.]+\:[0-9]+$'
local remoteHost=""
# Check if string is a ipv4 address and port
# Check if string is a ipv4 address and port
if [[ "$2" =~ $rex ]] ; then
remoteHost=$2
else
echoerr " [E] No valid IP:PORT detected: $2"
error -e "No valid IP:PORT detected: $2"
return 1
fi
fi
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"
endReturn -o $? "Couldn't apply $remoteHost to $CONFIG_REMOTE_DEST"
endReturn "Couldn't apply $remoteHost to $CONFIG_REMOTE_DEST"
step checkconf
exe service rsyslog restart
@@ -89,15 +84,15 @@ step_16() {
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_alias() { ALIAS="ufw"; }
step_17_alias() { echo "ufw"; }
step_17() {
exe ufw allow out on eth0 to any port 514 proto tcp comment "syslog remote"
}
step_30_info() { echo "Activating syslog server"; }
step_30_alias() { ALIAS="server"; }
step_30_alias() { echo "server"; }
step_30() {
outColor green
color green
cat << SERVER_EOF
# Uncomment the chapter
@@ -106,5 +101,7 @@ step_30() {
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

View File

@@ -1,14 +1,15 @@
#!/bin/bash
seqDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >>/dev/null 2>&1 && pwd )"
toolName="snmpd"
toolConfigLoc="/etc/snmp"
toolConfig="${toolConfigLoc}/snmpd.conf"
toolSysUser="Debian-snmp"
readonly toolName="snmpd"
readonly toolConfigLoc="/etc/snmp"
readonly toolConfig="${toolConfigLoc}/snmpd.conf"
readonly toolSysUser="Debian-snmp"
step_config() {
sq_aptOpt=
seq_config() {
## 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 0
@@ -16,65 +17,65 @@ step_config() {
step_1_info() { echo "Install packages for $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
if [ $QUIET != 0 ]; then
if quiet; then
exe apt-get -qq install $toolName
else
exe apt install $toolName
fi
endReturn -o $? "$toolName installation failed"
endReturn "$toolName installation failed"
}
step_2_info() {
echoinfoArgs "[-s]"
step_2_info() {
echo "Setup snmp v3 access"
echoinfo " -s : Stop after creating authentication entry"
}
step_2_alias() { ALIAS="v3access"; }
step_2_options() { echo "[-s]"; }
step_2_alias() { echo "v3access"; }
step_2() {
#
## Create authentication entry
exep "cat \"$v3AuthLoc\" | grep -e '^\s*usmUser'"
if [ "$?" == "0" ]; then
echoseq
info
exe read -p "User entry found. Continue: y/n(default)? " answer
case $answer in
[yY])
echoseq
echoseq "Continuing installation..."
info
info "Continuing installation..."
;;
*)
echoseq
echoseq "Installation aborted"
return 1;
info
info "Installation aborted"
return 1;
;;
esac
esac
fi
read -p "SNMPv3 Username: " v3User
read -p "SNMPv3 Password: " v3Pass
echoseq
info
read -p "Repeat Password: " v3Pass2
if [ "$v3Pass" != "$v3Pass2" ] ; then
echoerr " [E] Password mismatch"
error -e "Password mismatch"
return 1
fi
echoseq
info
exe service snmpd stop
# this line will be replaced on start of snmpd with a line starting with:
# usmUser
v3AuthEntry="createUser ${v3User} SHA \"${v3Pass}\" DES"
v3AuthEntry="createUser ${v3User} SHA \"${v3Pass}\" DES"
addConf -a "$v3AuthEntry" "$v3AuthLoc"
shift
if [ ! -z $1 ] && [ "$1" == "-s" ] ; then
echoseq " [I] Stop after creating authentication config"
if [ -n "${1:-}" ] && [ "$1" == "-s" ] ; then
info "Stop after creating authentication config"
exe service snmpd start
return 0
fi
@@ -82,7 +83,7 @@ step_2() {
#
## Add custom base configuration
addConf -c "" "${toolConfig}"
exe cp "${seqDir}/snmpd.conf" "${toolConfig}"
exe cp "${seq_origin}/snmpd.conf" "${toolConfig}"
#
## Add username as rouser
@@ -101,24 +102,24 @@ step_2() {
v3AuthLoc="/var/lib/snmp/snmpd.conf"
step_5_info() {
echoinfoArgs "[INTERFACE]"
echo "Add ufw rules for port 161 udp"
echoinfo " [INTERFACE] (default: eth0)"
}
step_5_alias() { ALIAS="ufw"; }
step_5_options() { echo "[INTERFACE]"; }
step_5_alias() { echo "ufw"; }
step_5() {
shift
local lInterface="eth0"
[ ! -z "$1" ] && lInterface="$1"
[ -n "${1:-}" ] && lInterface="$1"
# Check if interface exists
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"
}
step_20_info() { echo "Extend $toolName for Raspberry Pi"; }
step_20_alias() { ALIAS="raspberry"; }
step_20_alias() { echo "raspberry"; }
step_20() {
checkExtend raspberry
if [ "$?" != "0" ]; then
@@ -126,7 +127,7 @@ step_20() {
fi
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"
addConf -a "extend raspberry /etc/snmp/raspberry.sh" "$toolConfig"
@@ -143,15 +144,15 @@ rpiSudoersLoc="/etc/sudoers.d/snmprpi"
rpiSudoersContent="${toolSysUser} ALL=(ALL) NOPASSWD: /etc/snmp/raspberry.sh, /usr/bin/vcgencmd*"
step_22_info() { echo "Extend $toolName with OS update availablity"; }
step_22_alias() { ALIAS="osupdate"; }
step_22_alias() { echo "osupdate"; }
step_22() {
checkExtend osupdate
checkExtend osupdate
if [ "$?" != "0" ]; then
return 1
fi
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"
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"
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() {
echo -e "\n [!] Please add the following to your default server:\n"
echo "$phpFpmStatusNginx"
echo
if [ $QUIET -ne 0 ] ; then
if quiet ; then
answer=n
else
exe read -p "Open new shell to configure y/[n]? " answer
fi
case $answer in
[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
echoseq " [I] Interactive shell ended. Continuing with $0."
info "Interactive shell ended. Continuing with $0."
exe nginx -t
endReturn -o $? "Nginx configuration error"
endReturn "Nginx configuration error"
exe service nginx restart
;;
@@ -192,7 +193,7 @@ step_25() {
esac
}
# 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
location ~ ^/(status|ping)\$ {
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_alias() { ALIAS="phpfpm_config"; }
step_26_alias() { echo "phpfpm_config"; }
step_26() {
exe sed -i "s/^;\(pm\.status_path\)/\1/" "$phpPoolConfigLoc"
exe php-fpm${phpVersionStr} -t
endReturn -o $? "Invalid php configuration"
endReturn "Invalid php configuration"
service php${phpVersionStr}-fpm restart
}
@@ -218,7 +219,7 @@ phpConfigDir="/etc/php/${phpVersionStr}"
phpPoolConfigLoc="${phpConfigDir}/fpm/pool.d/www.conf"
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() {
checkExtend phpfpmsp
if [ "$?" != "0" ]; then
@@ -226,7 +227,7 @@ step_27() {
fi
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"
addConf -a "extend phpfpmsp ${phpfpmExtendLoc}" "$toolConfig"
@@ -236,23 +237,23 @@ step_27() {
phpfpmExtendLoc="${toolConfigLoc}/phpfpmsp"
step_29_info() { echo "Prepare nginx to provide status to $toolName"; }
step_29_alias() { ALIAS="nginx"; }
step_29_alias() { echo "nginx"; }
step_29() {
echoseq -e "\n [!] Please add the following to your default server:\n"
echoseq "$nginxStatus"
echoseq
if [ $QUIET -ne 0 ] ; then
info -e "\n [!] Please add the following to your default server:\n"
sqr::echo "$nginxStatus"
info
if quiet ; then
answer=n
else
exe read -p "Open new shell to configure y/[n]? " answer
fi
case $answer in
[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
echoseq " [I] Interactive shell ended. Continuing with $0."
info "Interactive shell ended. Continuing with $0."
exe nginx -t
endReturn -o $? "Nginx configuration error"
endReturn "Nginx configuration error"
exe service nginx restart
;;
@@ -270,7 +271,7 @@ deny all;
}
"
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() {
checkExtend nginx
if [ "$?" != "0" ]; then
@@ -278,7 +279,7 @@ step_30() {
fi
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"
addConf -a "extend nginx ${nginxExtendLoc}" "$toolConfig"
@@ -289,22 +290,17 @@ nginxExtendLoc="${toolConfigLoc}/nginx"
# postfix
step_32_info() { echo "Extend for postfix detailed and queue"; }
step_32_alias() { ALIAS="postfix"; }
step_32_alias() { echo "postfix"; }
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}"
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}"
endReturn -o $? "Download postfixdetailed failed"
endReturn "Download postfixdetailed failed"
exe chmod +x "${postfixQueuesExtendLoc}"
exe chmod +x "${postfixScript}"
exe apt install $postfixDeps $aptOpt
exe apt install $postfixDeps ${sq_aptOpt}
}
postfixDeps="pflogsumm"
@@ -314,11 +310,11 @@ step_33() {
exe chown root:$toolSysUser "$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
echoseq " [I] Run /etc/snmp/postfixdetailed to create the initial cache file"
echoseq " so you don't end up with some crazy initial starting value."
info "Run /etc/snmp/postfixdetailed to create the initial cache file"
info " so you don't end up with some crazy initial starting value."
exe sudo -u $toolSysUser "$postfixScript"
}
postfixCacheLoc="/var/cache/postfixdetailed"
@@ -328,9 +324,9 @@ postfixQueuesExtendLoc="${toolConfigLoc}/postfix-queues"
step_34_info() { echo "Create sudoers file for postfix scripts"; }
step_34() {
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}"
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"
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() {
checkExtend postfix-queues
if [ $? -eq 0 ]; then
echoseq " [I] Create postfix-queues extend"
info "Create postfix-queues extend"
addConf -a "extend mailq ${postfixQueuesExtendLoc}" "$toolConfig"
fi
checkExtend postfixdetailed
if [ $? -eq 0 ]; then
echoseq " [I] Create postfixdetailed extend"
info "Create postfixdetailed extend"
addConf -a "extend postfixdetailed ${postfixScript}" "$toolConfig"
fi
@@ -353,25 +349,20 @@ step_35() {
#fail2ban
step_37_info() { echo "Extend for fail2ban jail information"; }
step_37_alias() { ALIAS="fail2ban"; }
step_37_alias() { echo "fail2ban"; }
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}"
endReturn -o $? "Download postfix failed"
endReturn "Download postfix failed"
exe chmod +x "$fail2banExtendLoc"
checkExtend fail2ban
if [ $? -eq 0 ]; then
echoseq " [I] Create fail2ban extend"
info "Create fail2ban extend"
addConf -a "extend fail2ban ${fail2banExtendLoc} -c" "$toolConfig"
fi
exe apt install $fail2banDeps $aptOpt
exe apt install $fail2banDeps ${sq_aptOpt}
}
fail2banDeps="libjson-perl"
fail2banExtendLoc="${toolConfigLoc}/fail2ban"
@@ -385,7 +376,7 @@ fail2banCron="# Update cache for faster fail2ban polling
*/3 * * * * root ${fail2banExtendLoc} -u"
step_40_info() { echo "Create linux distribution detection extend (distro)"; }
step_40_alias() { ALIAS="distro"; }
step_40_alias() { echo "distro"; }
step_40() {
checkExtend distro
if [ $? -ne 0 ]; then
@@ -393,10 +384,10 @@ step_40() {
fi
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"
echoseq " [I] Create distro extend"
info "Create distro extend"
addConf -a "extend distro ${distroExtendLoc}" "$toolConfig"
exe service snmpd restart
@@ -404,11 +395,11 @@ step_40() {
distroExtendLoc="${toolConfigLoc}/distro"
step_42_info() {
step_42_info() {
echo "Gather dhcp information from a dhcpd lease file"
echoinfo "pi-hole lease file not supported"
}
step_42_alias() { ALIAS="dhcp"; }
step_42_alias() { echo "dhcp"; }
step_42() {
local locExtName="dhcpstats"
local locExtUrl="https://github.com/librenms/librenms-agent/raw/master/snmp/dhcp.py"
@@ -417,27 +408,27 @@ step_42() {
checkExtend $locExtName
[ $? -ne 0 ] && return 0
exe apt install dhcpd-pools
endReturn -o $? "Install dhcpd-pools failed"
exe apt install dhcpd-pools ${sq_aptOpt}
endReturn "Install dhcpd-pools failed"
exe wget $locExtUrl -O "${locExtLoc}"
endReturn -o $? "Download $locExtName script failed"
endReturn "Download $locExtName script failed"
exe chmod +x "$locExtLoc"
echoseq " [I] Create extend for $locExtName"
info "Create extend for $locExtName"
addConf -a "extend $locExtName ${locExtLoc}" "$toolConfig"
echoseq " [I] Create config for $locExtName"
info "Create config for $locExtName"
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"
dhcpExtendConfig="{\"leasefile\": \"/var/lib/dhcp/dhcpd.leases\"
}"
step_44_info() { echo "Extend unbound stats"; }
step_44_alias() { ALIAS="unbound"; }
step_44_alias() { echo "unbound"; }
step_44() {
local locExtName="unbound"
local locExtUrl="https://github.com/librenms/librenms-agent/raw/master/snmp/unbound"
@@ -447,13 +438,13 @@ step_44() {
[ $? -ne 0 ] && return 0
exe wget $locExtUrl -O "${locExtLoc}"
endReturn -o $? "Download $locExtName script failed"
endReturn "Download $locExtName script failed"
exe chmod +x "$locExtLoc"
echoseq " [I] Create extend for $locExtName"
info "Create extend for $locExtName"
addConf -a "extend $locExtName /usr/bin/sudo ${locExtLoc}" "$toolConfig"
echoseq " [I] Create config for $locExtName"
info "Create config for $locExtName"
addConf -s "$unboundExtendConfig" "$unboundExtendConfigLoc"
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"
step_46_info() { echo "Extend pi-hole stats"; }
step_46_alias() { ALIAS="pihole"; }
step_46_alias() { echo "pihole"; }
step_46() {
local locExtName="pi-hole"
local locExtUrl="https://github.com/librenms/librenms-agent/raw/master/snmp/pi-hole"
@@ -489,25 +480,25 @@ step_46() {
checkExtend $locExtName
[ $? -ne 0 ] && return 0
exe apt install $piHoleDeps $APTOPT
exe apt install $piholeDeps ${sq_aptOpt}
exe wget $locExtUrl -O "${locExtLoc}"
endReturn -o $? "Download $locExtName script failed"
endReturn "Download $locExtName script failed"
exe chmod +x "$locExtLoc"
echoseq " [I] Create extend for $locExtName"
info "Create extend for $locExtName"
addConf -a "extend $locExtName ${locExtLoc}" "$toolConfig"
if [ $QUIET -ne 0 ]; then
outColor red
if quiet; then
color red
echo -e " [W] Check the following in the extend script and restart snmpd:\n"
else
echo " [I] Check the follwing in the extend script:"
info "Check the follwing in the extend script:"
fi
echo "(API_AUTH_KEY) Add your pi-hole API key"
echo " (API_URL) and check the API URL"
outColor
if [ $QUIET -eq 0 ]; then
color
if interactive; then
exe read -p "Hit Enter to continue..."
exe vi "$locExtLoc"
exe systemctl restart snmpd.service
@@ -516,9 +507,9 @@ step_46() {
piholeDeps="jq"
step_100_info() { echo "Notes"; }
step_100_alias() { ALIAS="notes"; }
step_100_alias() { echo "notes"; }
step_100() {
outColor green
color green
cat <<NOTES_END
# Reduce log level of snmpd
@@ -565,18 +556,20 @@ NOTES_END
checkExtend() {
# adding dry run output for clarification
if [ $DRY -ne 0 ] ; then
echoseq " [I] check if \"extend ${1}\" exists..dry-run"
if dry ; then
info "check if \"extend ${1}\" exists..dry-run"
fi
exep "cat \"$toolConfig\" | grep -e '^\s*extend\s\+${1}' >>/dev/null 2>&1"
# 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
fi
fi
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

View File

@@ -1,57 +1,57 @@
# AGENT BEHAVIOUR
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.25.1
# Full access from the local host
# Full access from the local host
#rocommunity public localhost
# Default access to basic system info
rocommunity public default -V systemonly
# rocommunity6 is for IPv6
rocommunity6 public default -V systemonly
# Default access to basic system info
rocommunity public default -V systemonly
# rocommunity6 is for IPv6
rocommunity6 public default -V systemonly
# Full read-only access for SNMPv3
rouser authOnlyUser
# Full read-only access for SNMPv3
rouser authOnlyUser
# SYSTEM INFORMATION
sysLocation Sitting on the Dock of the Bay
sysContact Me <me@example.org>
# Application + End-to-End layers
# Application + End-to-End layers
sysServices 72
# Process Monitoring
# At least one 'mountd' process
# At least one 'mountd' process
proc mountd
# No more than 4 'ntalkd' processes - 0 is OK
# No more than 4 'ntalkd' processes - 0 is OK
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
# 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 /var 5%
includeAllDisks 10%
# System Load
# Unacceptable 1-, 5-, and 15-minute load averages
# Unacceptable 1-, 5-, and 15-minute load averages
load 12 10 5
# ACTIVE MONITORING
# send SNMPv1 traps
trapsink localhost public
# send SNMPv1 traps
trapsink localhost public
# Event MIB - automatically generate alerts
# Remember to activate the 'createUser' lines above
iquerySecName internalUser
# Remember to activate the 'createUser' lines above
iquerySecName internalUser
rouser internalUser
# AgentX Sub-agents
# Run as an AgentX master agent
master agentx
# Run as an AgentX master agent
master agentx
#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.

View File

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

View File

@@ -9,30 +9,30 @@ aHost=""
aPort="22"
step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
exe apt install ssh
}
step_3_info() { echo "Create $toolName authentication keys"; }
step_3_alias() { ALIAS="create"; }
step_3_alias() { echo "create"; }
step_3() {
exep "ssh-keygen -l -f $toolIdentity 2>>/dev/null"
if [ $? -eq 0 ]; then
echo " [I] Using key found at $toolIdentity."
info "Using key found at $toolIdentity."
return 0
fi
exe ssh-keygen -b 4096 -t rsa -C "$(hostname)" -N "" -f $(realpath $toolIdentity)
}
step_5_info() {
echoinfoArgs "[OPTIONS] <USER@HOST> [PORT]"
echo "Send key to remote host"
echoinfo "[OPTIONS]"
echoinfo " -4 : Force Ipv4"
}
step_5_alias() { ALIAS="sendkey"; }
step_5_options() { echo "[OPTIONS] <USER@HOST> [PORT]"; }
step_5_alias() { echo "sendkey"; }
step_5() {
shift
local arg
@@ -53,7 +53,7 @@ step_5() {
done
if [ -z "$1" ] || [ "$1" == "" ] ; then
echoerr " [E] Host not provided."
error -e "Host not provided."
return 1
else
sshHost="$1"
@@ -70,18 +70,18 @@ step_5() {
exe ssh-copy-id -p ${sshPort} ${sshOption} ${sshHost}
}
step_10_info() {
echoinfoArgs "<CMDLIST> [USER:HOST] [PORT]"
step_10_info() {
echo "Send command(ssh)/file(scp) list to remote(s)"
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() {
shift
aList=$1
aHost=$2
aList=${1:-}
aHost=${2:-}
# Set port only if not empty
if [ ! -z "$3" ]; then
if [ -n "${3:-}" ]; then
aPort=$3
fi
parseList $aList
@@ -105,7 +105,7 @@ step_10() {
# STRING2 h - port
# f - destination file path
# c - not used
#
#
# OPTIONS h - not used
# f - Options passed to scp
# c - not used
@@ -113,13 +113,13 @@ step_10() {
parseList() {
local errorMsg=""
if [ -z "$1" ] || [ ! -f "$1" ]; then
if [ -z "$1" ]; then
echoerr " [E] No Command list found"
if [ -z "${1:-}" ] || [ ! -f "${1:-}" ]; then
if [ -z "${1:-}" ]; then
error -e "No Command list found"
else
echoerr " [E] Command list not found: $1"
error -e "Command list not found: $1"
fi
if [ ! -z "$1" ] && [ $DRY == 0 ] && [ $QUIET == 0 ] ; then
if [ -n "${1:-}" ] && dry || interactive ; then
read -p " Create template there y/[n]? " answer
case "$answer" in
y|Y)
@@ -132,7 +132,7 @@ parseList() {
return 1
fi
echoseq " [I] Parsing $(realpath $1) ..."
info "Parsing $(realpath -- "${1:-}") ..."
local line=1
# Working loop without ssh "stealing standard input" by
# https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while
@@ -160,7 +160,7 @@ parseList() {
if [ -z "$aHost" ]; then
errorMsg="No host found"
saveReturn 1
else
else
exe scp $lopt -P $aPort $lsrc ${aHost}:$ldst
saveReturn $?
errorMsg="scp to $aHost failed with $?"
@@ -184,15 +184,15 @@ parseList() {
esac
getReturn
if [ $? -ne 0 ] ; then
echoerr -e " [E] $line:$errorMsg"
if [ $QUIET -eq 0 ] ; then
error -e -e " [E] $line:$errorMsg"
if interactive ; then
endReturn -f "Stop on first error"
fi
fi
((line++))
done 3<"$1"
echoseq " [I] Parsed $((--line)) lines"
info "Parsed $((--line)) lines"
}
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
c|/destdir2/update.sh"
VERSION_SEQREV=14
readonly sqr_minVersion=16
. 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_TEMPLATE="$WDIR/${CONFIG_FILE_NAME}.example"
step_config() {
initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
if [ $? -eq 0 ] ; then
seq_config() {
if initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE" ; then
CONFIG=1
else
[ $DRY -eq 0 ] && return 1
dry || return 1
fi
toolConfigLoc=`eval echo "$TWXA_CONFIG_LOC"`
toolConfigLoc=`eval echo "${TWXA_CONFIG_LOC:-}"`
toolConfig="$toolConfigLoc/config_cache/$toolConfigName"
toolHtmlLoc=`eval echo "$TWXA_HTML_LOC"`
toolBackupLoc=`eval echo "$TWXA_BACKUP_LOC"`
toolGitLoc=`eval echo "$TWXA_GIT_LOC"`
gitLibLoc=`eval echo "$TWXA_GIT_LOC/var/lib/torrentwatch-xa"`
gitHtmlLoc=`eval echo "$TWXA_GIT_LOC/var/www/html/torrentwatch-xa"`
echo " git: $toolGitLoc"
echo " config: $toolConfig"
echo " html: $toolHtmlLoc"
echo " backup: $toolBackupLoc"
toolHtmlLoc=`eval echo "${TWXA_HTML_LOC:-}"`
toolBackupLoc=`eval echo "${TWXA_BACKUP_LOC:-}"`
toolGitLoc=`eval echo "${TWXA_GIT_LOC:-}"`
gitLibLoc=`eval echo "${TWXA_GIT_LOC:-}/var/lib/torrentwatch-xa"`
gitHtmlLoc=`eval echo "${TWXA_GIT_LOC:-}/var/www/html/torrentwatch-xa"`
info " git: $toolGitLoc"
info -a "config: $toolConfig"
info -a " html: $toolHtmlLoc"
info -a "backup: $toolBackupLoc"
}
step_1_info() { echo "Install $toolName [VERSION]"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
shift
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
toolVersion="$1"
fi
echo $toolConfig
}
step_2_info() { echo "Setup git repository at $toolGitLoc [VERSION e.g. 1.4.1]"; }
step_2_alias() { ALIAS="git"; }
step_2_info() { echo "Setup git repository at ${toolGitLoc:-} [VERSION e.g. 1.4.1]"; }
step_2_alias() { echo "git"; }
step_2() {
shift
if [ ! -e "$toolGitLoc/.git" ] ; then
@@ -60,23 +59,23 @@ step_2() {
exe cd "$toolGitLoc"
exe git pull
fi
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
toolVersion="$1"
fi
exe git checkout $toolVersion
}
step_20_info() { echo "Backup $toolName"; }
step_20_alias() { ALIAS="backup"; }
step_20_alias() { echo "backup"; }
step_20() {
shift
if [ ! -e "$toolConfigLoc" ] ; then
echoerr " [E] No installation found"
error -e "No installation found"
return 1
fi
local buType="all"
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
buType="$1"
fi
local buDate=`date +%Y%m%d-%H%M%S`
@@ -115,24 +114,24 @@ step_20() {
}
step_30_info() { echo "Upgrade $toolName [VERSION]"; }
step_30_alias() { ALIAS="upgrade"; }
step_30_alias() { echo "upgrade"; }
step_30() {
shift
if [ ! -z $1 ] ; then
if [ -n "${1:-}" ] ; then
toolVersion="$1"
fi
#step backup
if [ $? -ne 0 ]; then
echoerr " [E] Backup failed. Aborting upgrade."
error -e "Backup failed. Aborting upgrade."
return 1
fi
echo " [I] Upgrading data"
info "Upgrading data"
exe mv "$toolConfigLoc/lib" "$toolConfigLoc/lib_bu"
exe cp -ar "$gitLibLoc/lib" "$toolConfigLoc/"
echo " [I] Upgrading html"
info "Upgrading html"
exe mv "$toolHtmlLoc" "${toolHtmlLoc}_bu"
exe cp -ar "$gitHtmlLoc" "$toolHtmlLoc"
exe cp -arL "$toolBackupLoc/config.php" "$toolHtmlLoc"
@@ -143,5 +142,5 @@ step_30() {
exe chown -R www-data: "$toolConfigLoc/*_cache"
}
VERSION_SEQREV=11
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -17,20 +17,20 @@ 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 [ $? -eq 0 ] ; then
CONFIG=1
else
# End if no configuration file exists
[ $DRY -eq 0 ] && return 1
dry || return 1
fi
[ $QUIET -ne 0 ] && APTOPT="-y"
quiet && APTOPT="-y"
return 0
}
step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
exe apt install $toolDeps $APTOPT
@@ -42,7 +42,7 @@ step_1() {
}
step_10_info() { echo "Setup blocklist update cron job"; }
step_10_alias() { ALIAS="bllupdate"; }
step_10_alias() { echo "bllupdate"; }
step_10() {
addConf -s "$TRDA_REMOTE_AUTH" "$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_alias() { ALIAS="netrcauth"; }
step_11_alias() { echo "netrcauth"; }
step_11() {
local lRemoteAuth="$(realpath ~/.netrc)"
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_alias() { ALIAS="ufw"; }
step_12_alias() { echo "ufw"; }
step_12() {
local trdaRpcPort=9091
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_alias() { ALIAS="notes"; }
step_20_alias() { echo "notes"; }
step_20() {
outColor green
color green
cat <<NOTES_EOF
[I] Change rpc password
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_alias() { ALIAS="list"; }
step_50_alias() { echo "list"; }
step_50() {
step netrcauth
outColor green
color green
exe "$toolRemote" -l
}
step_52_info() { echoinfoArgs "<TORRENT ID>"; echo "List information about a torrent"; }
step_52_alias() { ALIAS="info"; }
step_52_info() { echo "List information about a torrent"; }
step_52_options() { echo "<TORRENT ID>"; }
step_52_alias() { echo "info"; }
step_52() {
shift
endCheckEmpty 1 "Id must not be empty"
endIfEmpty 1 "Id must not be empty"
step netrcauth
outColor green
color green
exep "\"$toolRemote\" -t$1 -i | less"
}
step_54_info() { echo "$toolName status"; }
step_54_alias() { ALIAS="status"; }
step_54_alias() { echo "status"; }
step_54() {
step netrcauth
outColor green
color green
exe "$toolRemote" -si
exe "$toolRemote" -st
}
VERSION_SEQREV=13
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -3,7 +3,7 @@
toolName="Tvheadend"
step_1_info() { echo "Apt - setup $toolName repository"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
local sourceList="/etc/apt/sources.list.d/tvheadend.list"
local sourceEntry="deb https://apt.tvheadend.org/stable raspbian-stretch main"
@@ -16,7 +16,7 @@ step_1() {
echo -n "Downloading tvheadend repository key ... "
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"
}
@@ -47,6 +47,6 @@ step_99() {
endReturn
}
VERSION_SEQREV=8
readonly sqr_minVersion=16
. sequencer.sh

View File

@@ -3,28 +3,31 @@
toolName=ufw
toolDeps=$toolName
# 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"
sq_aptOpt=
#sq_config=0
#step_config() {
# initSeqConfig "$CONFIG_FILE_NAME" "$CONFIG_FILE_TEMPLATE"
# if [ $? -eq 0 ] ; then
# CONFIG=1
# fi
#}
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
## Return of non zero value will abort the sequence
return 0
}
step_1_info() { echo "Install $toolName and allow ssh access"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
local aptOpt=
if [ $QUIET -ne 0 ];then
aptOpt="-y"
fi
exe apt install $toolDeps $aptOpt
exe apt install $toolDeps ${sq_aptOpt}
exe ufw allow ssh
}
@@ -34,7 +37,7 @@ step_2() {
}
step_20_info() { echo "Enable mail server essentials"; }
step_20_alias() { ALIAS="mailserver"; }
step_20_alias() { echo "mailserver"; }
step_20() {
exe ufw allow "Postfix"
exe ufw allow "Postfix SMTPS"
@@ -44,52 +47,60 @@ step_20() {
exe ufw allow 4190/tcp comment 'Managesieve'
}
step_22_info() { echoinfoArgs "[IP]"; echo "Deny multicast from gateway"; }
step_22_alias() { ALIAS="multicast"; }
step_22_info() { echo "Deny multicast from gateway and fritzbox webcheck"; }
step_22_options() { echo "[IP]"; }
step_22_alias() { echo "multicast"; }
step_22() {
shift
if [ -z $1 ] ; then
echoerr " [E] No [IP} specified"
if [ -z "${1:-}" ] ; then
error -e "No [IP} specified"
return 1
fi
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 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 any port 80 proto tcp comment 'Webcheck Fritzbox'
}
step_24_info() {
echoinfoArgs "<FILE SERVER IP|RANGE> [PORT]"
echo "Allow cifs mounts on eth0"
step_23_info() { echo "Deny IPv6 multicast"; }
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"
echoinfo " [PORT] (default 445)"
echoinfo " 139 : Cifs version 1.0"
echoinfo " 445 : Cifs version 2.0+"
}
step_24_alias() { ALIAS="cifs"; }
step_24() {
step_26_options() { echo "<FILE SERVER IP|RANGE> [PORT]"; }
step_26_alias() { echo "cifs"; }
step_26() {
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]*$'
endCheckEmpty destIp "No IP provided"
if [[ ! $1 =~ $ipregex ]]; then
echoseq " [E] No valid IP provided"
endIfEmpty destIp "No IP provided"
if [[ ! ${1:-} =~ $ipregex ]]; then
error "No valid IP provided"
return 1
fi
local destPort=445
case "$2" in
case "${2:-}" in
139|445)
destPort=$2;;
destPort="${2}";;
"");; # Set default
*)
echoerr " [E] Invalid port."
error -e "Invalid port."
return 1;;
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_26_alias() { ALIAS="vpn"; }
step_26() {
step_28_info() { echo "Basic secure VPN setup"; }
step_28_alias() { echo "vpn"; }
step_28() {
exe ufw --force reset
exe ufw allow in on eth0 to any port 22 comment "ssh"
exe ufw default deny incoming
@@ -107,5 +118,7 @@ step_26() {
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

View File

@@ -4,41 +4,24 @@ toolName=vim
indentDownUrl="https://www.vim.org/scripts/download_script.php?src_id=27565"
seqVimConfigLoc="$HOME/.vimrc"
# Get script working directory
# (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
sq_aptOpt=
seq_config() {
## 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 0
}
step_1_info() { echo "Install $toolName"; }
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt install vim $APTOPT
exe apt install vim ${sq_aptOpt}
}
step_2_info() { echo "Installing indentation script $seqVimIndentLoc"; }
step_2_alias() { ALIAS="setup"; }
step_2_alias() { echo "setup"; }
step_2() {
if [ ! -e "$seqVimIndentLoc" ]; then
exe mkdir -p $(dirname "$seqVimIndentLoc")
@@ -46,7 +29,7 @@ step_2() {
wget --content-disposition $indentDownUrl
fi
echoseq " [I] Installing indentation rules"
info "Installing indentation rules"
addConf -c "$seqVimConfigBasic" "$seqVimConfigLoc"
}
seqVimIndentLoc="$HOME/.vim/indent/sh.vim"
@@ -55,31 +38,38 @@ filetype plugin indent on
syntax on"
step_3_info() { echo "Install editorconfig as vim 8 plugin"; }
step_3_alias() { ALIAS="editorconfig"; }
step_3_alias() { echo "editorconfig"; }
step_3() {
local ecDir="$HOME/.vim/pack/editorconfig/start"
local ecUrl='https://github.com/editorconfig/editorconfig-vim.git'
if [ ! -e "$ecDir" ]; then
echoseq " [I] Installing editorconfig plugin"
exe mkdir -p "$ecDir"
info "Installing editorconfig plugin"
exe mkdir -p "$ecDir"
exe cd "$ecDir"
exe git clone "$ecUrl"
else
echoseq " [I] Upgrading editorconfig plugin"
info "Upgrading editorconfig plugin"
exe cd "$ecDir"
exe git pull
exe git pull
fi
}
step_10_info() { echo "Setup $HOME/.vimrc globaly to use spaces and indent 2"; }
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"
}
seqVimConfig="set expandtab
set tabstop=2
set softtabstop=2
set shiftwidth=2"
seqVimConfig="set expandtab shiftwidth=2 softtabstop=2 tabstop=2
set noro
set cindent cinkeys-=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

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

@@ -6,15 +6,15 @@ phpVersion="7.3"
phpName="php$phpVersion"
phpPackages="${phpName}-fpm ${phpName}-json ${phpName}-mysql ${phpName}-curl ${phpName}-intl ${phpName}-gd ${phpName}-zip ${phpName}-xml ${phpName}-mbstring php-imagick php-apcu"
step_1_info() {
step_1_info() {
echo "Installation of $serverName packages:"
echoinfo "$serverPackages"
}
step_1_alias() { ALIAS="install"; }
step_1_alias() { echo "install"; }
step_1() {
exe apt update
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"; }
@@ -31,12 +31,12 @@ step_2() {
exe apt install nginx
fi
# create webroot
# create webroot
exe mkdir -p "$siteLetsencryptWww"
echo -n " [I] Restarting Nginx ... "
exe service nginx restart && echo "ok"
endReturn -o $? "Nginx error during startup"
endReturn "Nginx error during startup"
}
snippetLetsencryptLoc="/etc/nginx/snippets/letsencrypt.conf"
siteLetsencryptWww="/var/www/letsencrypt"
@@ -49,7 +49,7 @@ siteDefaultLoc="/etc/nginx/sites-available/default"
siteDefaultIp4="server {
listen 80 default_server;
include ${snippetLetsencryptLoc};
include ${snippetLetsencryptLoc};
}"
step_3_info() {
@@ -58,7 +58,7 @@ step_3_info() {
}
step_3() {
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"
phpFpmConfig="\
@@ -88,9 +88,9 @@ step_4() {
echo -n "Restarting ${phpName} ..."
exe service ${phpName}-fpm restart
endReturn -o $? "$phpName error during restart"
endReturn "$phpName error during restart"
echo "ok"
}
VERSION_SEQREV=10
readonly sqr_minVersion=16
. /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

Some files were not shown because too many files have changed in this diff Show More