provisioning tool for building opinionated architecture
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

652 lines
20 KiB

7 months ago
  1. #!/bin/bash
  2. RED='\e[0;41m\e[1;37m'
  3. GREEN='\033[0;32m'
  4. YELLOW='\033[0;33m'
  5. PURPLE='\033[0;35m'
  6. DARK='\e[100m'
  7. NC='\033[0m' # No Color
  8. TO_BE_DEFINED="TO BE DEFINED"
  9. # BOLD='\033[1m'
  10. # DIM='\e[2m\e[0;90m'
  11. function echo() {
  12. [[ -n ${PREFIX:-} ]] && printf "${DARK}%25.25s${NC} " "${PREFIX}"
  13. builtin echo "$@"
  14. }
  15. function check_normal_user() {
  16. [[ $(id -u) -lt 1000 ]] && echoerr "normal user (>1000) expected, please connect as a normal user then call again!" && exit 100
  17. return 0
  18. }
  19. function sudo_required() {
  20. check_normal_user
  21. command -v sudo &>/dev/null &&
  22. id -G | grep -q sudo && echoerr "command <sudo> not found, please install as so: \`apt install -y sudo\`" && exit 1
  23. if ! sudo -n true &>/dev/null; then
  24. if [[ -n "${1:-}" ]]; then
  25. echowarnn "[sudo] requiring authorized access for: [ $1 ]"
  26. else
  27. echowarnn "[sudo] requiring authorized access for further processing"
  28. fi
  29. fi
  30. sudo -vp ' : '
  31. }
  32. # idempotent cargo install <package1 package2 ...>
  33. function idem_cargo_install() {
  34. for i in "$@"; do
  35. if [ ! -f ~/.cargo/bin/"$i" ]; then
  36. cargo install "$i"
  37. fi
  38. done
  39. }
  40. # display error in red
  41. function echoerr() {
  42. echo -e "${RED}$*${NC}" >&2
  43. }
  44. function echoerrn() {
  45. echo -en "${RED}$*${NC}" >&2
  46. }
  47. # display warn in yellow
  48. function echowarn() {
  49. echo -e "${YELLOW}$*${NC}" >&2
  50. }
  51. function echowarnn() {
  52. echo -en "${YELLOW}$*${NC}" >&2
  53. }
  54. # display error in green
  55. function echoinfo() {
  56. echo -e "${GREEN}$*${NC}" >&2
  57. }
  58. function echoinfon() {
  59. echo -en "${GREEN}$*${NC}" >&2
  60. }
  61. # test whether <ip> is a valid ipv4 address?
  62. function valid_ipv4() {
  63. local ip="$1"
  64. if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
  65. IFS='.' read -ra ADDR <<<"$ip"
  66. [[ ${ADDR[0]} -le 255 && ${ADDR[1]} -le 255 && ${ADDR[2]} -le 255 && ${ADDR[3]} -le 255 ]]
  67. return $?
  68. fi
  69. return 1
  70. }
  71. function enable_trace() {
  72. trap 'trap_error $? ${LINENO:-0} ${BASH_LINENO:-0} ${BASH_COMMAND:-empty} $(printf "::%s" ${FUNCNAME[@]})' ERR
  73. }
  74. function disable_trace() {
  75. trap - ERR
  76. }
  77. function prepare_nftables() {
  78. local PREFIX="miaou:nftables"
  79. if [[ ! -f /etc/nftables.rules.d/firewall.table ]]; then
  80. echo "installing nftables ..."
  81. sudo apt install -y nftables
  82. sudo cp -f "$MIAOU_BASEDIR/templates/hardened/nftables.conf" /etc/
  83. sudo mkdir -p /etc/nftables.rules.d
  84. sudo cp -f "$MIAOU_BASEDIR/templates/hardened/firewall.table" /etc/nftables.rules.d/
  85. sudo systemctl restart nftables
  86. sudo systemctl enable nftables
  87. echo "OK"
  88. else
  89. echo "nftables already installed!"
  90. fi
  91. }
  92. function miaou_init() {
  93. # shellcheck source=/dev/null
  94. [[ -f /opt/debian-bash/lib/functions.sh ]] && source /opt/debian-bash/lib/functions.sh
  95. # shellcheck source=/dev/null
  96. . "$MIAOU_BASEDIR/lib/functions.sh"
  97. export MIAOU_CONFIGDIR="$HOME/.config/miaou"
  98. set -Eeuo pipefail
  99. enable_trace
  100. trap 'ctrl_c $? ${LINENO:-0} ${BASH_LINENO:-0} ${BASH_COMMAND:-empty} $(printf "::%s" ${FUNCNAME[@]})' INT
  101. }
  102. function ctrl_c() {
  103. PREFIX="miaou:trap" echoerr "Ctrl + C happened, exiting!!! $*"
  104. exit 125
  105. }
  106. # extract source code error triggered on trap error <error_code> <error_line>
  107. function trap_error() {
  108. ERRORS_COUNT=0
  109. if [[ -f "$MIAOU_CONFIGDIR"/error_count ]]; then
  110. ERRORS_COUNT=$(cat "$MIAOU_CONFIGDIR"/error_count)
  111. else
  112. mkdir -p "$MIAOU_CONFIGDIR"
  113. printf 0 >"$MIAOU_CONFIGDIR"/error_count
  114. fi
  115. ERRORS_COUNT=$((ERRORS_COUNT + 1))
  116. printf '%s' $ERRORS_COUNT >"$MIAOU_CONFIGDIR"/error_count
  117. local PREFIX=""
  118. # local file="${0:-}"
  119. local err=$1 # error status
  120. local line=$2 # LINENO
  121. local linecallfunc=${3:-}
  122. local command="${4:-}"
  123. local funcstack="${5:-}"
  124. local caller
  125. caller=$(caller | cut -d' ' -f2)
  126. # echo >&2
  127. # if [ "$funcstack" != "::" ]; then
  128. # echo -e "${RED}ERROR <$err>, due to command <$command> at line $line from <$caller>, stack=${funcstack}${NC}" >&2
  129. # else
  130. # echo >&2 "ERROR DETECTED"
  131. # fi
  132. # echo
  133. # echo -e "${PURPLE}$caller:$line ${NC}EXIT ${RED}<$err>${NC}" >&2
  134. # echo -e "${PURPLE}------------------------------------------ ${NC}" >&2
  135. if [[ $ERRORS_COUNT == 1 ]]; then
  136. echo
  137. echo -e "${RED}ERROR <$err>, due to command <$command $funcstack>${NC}" >&2
  138. fi
  139. echo -e "${PURPLE}$ERRORS_COUNT: $caller:$line ${RED}$command $funcstack${NC}" >&2
  140. # echo -e "${PURPLE}----------------------------- ${PURPLE}EXIT CODE ${PURPLE}--------------${PURPLE} $err ${NC}" >&2
  141. # if [[ $line -gt 2 ]]; then
  142. # sed "$((line - 2))q;d" "$caller" >&2
  143. # sed "$((line - 1))q;d" "$caller" >&2
  144. # fi
  145. # echo -ne "${BOLD}" >&2
  146. # sed "${line}q;d" "$caller" >&2
  147. # echo -e "${PURPLE}------------------------------------------ ${NC}" >&2
  148. }
  149. # exist_command(cmd1, ...)
  150. # test all commands exist, else fail
  151. function exist_command() {
  152. for i in "$@"; do
  153. command -v "$i" &>/dev/null || return 50
  154. done
  155. }
  156. # test whether container <ct> is up and running?
  157. function container_running() {
  158. arg1_required "$@"
  159. container_exists "$1" && lxc list "$1" -c ns -f csv | head -n1 | grep -q "$1,RUNNING"
  160. lxc exec "$1" -- bash <<EOF
  161. set -Eeuo pipefail
  162. if [[ ! -f /root/cloud-status.json ]]; then
  163. cloud-init status --wait >/dev/null
  164. fi
  165. EOF
  166. }
  167. # test arg1 required
  168. function arg1_required() {
  169. [[ -z "${1:-}" ]] && echoerr "ERROR: arg#1 expected!" && return 125
  170. return 0
  171. }
  172. # test arg2 required
  173. function arg2_required() {
  174. [[ -z "${2:-}" ]] && echoerr "ERROR: arg#2 expected!" && return 125
  175. return 0
  176. }
  177. # test whether container <ct> exists yet?
  178. function container_exists() {
  179. arg1_required "$@"
  180. lxc list "$1" -c n -f csv | grep -q "^$1\$"
  181. }
  182. # build debian image with prebuild debian-bash and various useful settings
  183. # ARG1=release [bullseye, buster]
  184. function build_miaou_image() {
  185. local RELEASE="$1"
  186. local IMAGE_LABEL="$RELEASE-miaou"
  187. local PREFIX="miaou:image"
  188. local DEB_REPOSITORY
  189. DEB_REPOSITORY=$(grep ^deb /etc/apt/sources.list | head -n1 | cut -d ' ' -f2 | cut -d '/' -f3)
  190. if ! lxc image -cl list -f csv | grep -q "$IMAGE_LABEL"; then
  191. echo "building lxc image <$IMAGE_LABEL> ... "
  192. echo "image will reuse same local repository <$DEB_REPOSITORY>"
  193. creation_date=$(date +%s)
  194. sudo /opt/debian-bash/tools/idem_apt_install debootstrap
  195. cat <<EOF1 | sudo bash
  196. set -euo pipefail
  197. rm -rf /tmp/$IMAGE_LABEL{,-image}
  198. mkdir -p /tmp/$IMAGE_LABEL{,-image}
  199. debootstrap $RELEASE /tmp/$IMAGE_LABEL http://$DEB_REPOSITORY/debian
  200. echo
  201. echo "DEBOOTSTRAP ... OK"
  202. echo
  203. cat <<EOF2 | chroot /tmp/$IMAGE_LABEL
  204. set -euo pipefail
  205. echo "image prepare source.list from $DEB_REPOSITORY"
  206. if [[ "$RELEASE" == "buster" ]]; then
  207. cat <<EOF3 >/etc/apt/sources.list
  208. deb http://$DEB_REPOSITORY/debian $RELEASE main contrib
  209. deb http://$DEB_REPOSITORY/debian $RELEASE-updates main contrib
  210. deb http://$DEB_REPOSITORY/debian-security/ $RELEASE/updates main contrib
  211. EOF3
  212. else
  213. cat <<EOF3 >/etc/apt/sources.list
  214. deb http://$DEB_REPOSITORY/debian $RELEASE main contrib
  215. deb http://$DEB_REPOSITORY/debian $RELEASE-updates main contrib
  216. deb http://$DEB_REPOSITORY/debian-security/ $RELEASE-security main contrib
  217. EOF3
  218. fi
  219. echo APT UPDATE
  220. apt update && apt dist-upgrade -y
  221. apt install -y curl wget file git sudo bash-completion
  222. curl https://git.artcode.re/pvincent/debian-bash/raw/branch/master/install.sh | sudo bash -s -- --host
  223. ln -sf /usr/share/zoneinfo/Indian/Reunion /etc/localtime
  224. cat <<EOF3 >/etc/network/interfaces
  225. # This file describes the network interfaces available on your system
  226. # and how to activate them. For more information, see interfaces(5).
  227. # The loopback network interface
  228. auto lo
  229. iface lo inet loopback
  230. auto eth0
  231. iface eth0 inet dhcp
  232. source /etc/network/interfaces.d/*
  233. EOF3
  234. echo "deboostrap ready!"
  235. EOF2
  236. cd /tmp/$IMAGE_LABEL-image
  237. tar -czf rootfs.tar.gz -C /tmp/$IMAGE_LABEL .
  238. cat <<EOF2 >metadata.yaml
  239. architecture: "x86_64"
  240. creation_date: $creation_date
  241. properties:
  242. architecture: "x86_64"
  243. description: "Debian $RELEASE for miaou instances"
  244. os: "debian"
  245. release: "$RELEASE"
  246. EOF2
  247. tar -czf metadata.tar.gz metadata.yaml
  248. EOF1
  249. lxc image import "/tmp/$IMAGE_LABEL-image/metadata.tar.gz" "/tmp/$IMAGE_LABEL-image/rootfs.tar.gz" --alias "$IMAGE_LABEL"
  250. echo "image <$IMAGE_LABEL> successfully built!"
  251. echo DONE
  252. else
  253. echo "image <$IMAGE_LABEL> already built!"
  254. fi
  255. }
  256. # execute remote scripting onto one LXC container <CONTAINER> [COMMANDS, ...]
  257. # may use one command like: `lxc_exec ct1 uname -a`
  258. # or pipe like so: `
  259. # cat <<EOF | lxc_exec ct1
  260. # ls -l
  261. # uname -a
  262. # echo [\$0] [\$1] [\$2] # toto titi tata
  263. # EOF
  264. # `
  265. function lxc_exec() {
  266. arg1_required "$@"
  267. container="$1"
  268. shift
  269. declare -a ARGUMENTS
  270. ARGUMENTS=(toto titi tata) # might be overriden with interesting stuff!
  271. if ((${#} == 0)); then
  272. multiline=""
  273. while read -r line; do
  274. if [[ ! "$line" =~ ^\# ]] && [[ ! "$line" =~ ^[[:space:]]*$ ]]; then
  275. if [[ "$line" =~ .*\;$ ]] || [[ "$line" =~ do$ ]] || [[ "$line" =~ then$ ]] || [[ "$line" =~ else$ ]]; then
  276. multiline+="${line} " # append space in case of ending with either '; do then else'
  277. else
  278. multiline+="${line};" # append ; for multiple commands
  279. fi
  280. fi
  281. done
  282. # echo "DEBUG: multiline = [$multiline]"
  283. # echo DEBUG: lxc exec "$container" -- bash -lc "$multiline" "${ARGUMENTS[@]}"
  284. lxc exec "$container" -- bash -lc "$multiline" "${ARGUMENTS[@]}"
  285. else
  286. lxc exec "$container" -- bash -lc "$*" "${ARGUMENTS[@]}"
  287. fi
  288. }
  289. # check container exist and running
  290. function check_container() {
  291. arg1_required "$@"
  292. local CT="$1"
  293. container_exists "$CT"
  294. container_running "$CT"
  295. }
  296. function launch_container() {
  297. arg1_required "$@"
  298. local ct="$1"
  299. if ! container_exists "$ct"; then
  300. echo "container <$ct> about to be created ..."
  301. local extra_release="${2:-}"
  302. if [[ -n "$extra_release" ]] && ! lxc image info "${extra_release}-miaou" >/dev/null; then
  303. echoerrn "unknown extra_release <${extra_release}-miaou>!\nHINT : please add it into /etc/miaou/defaults.yaml, then re-install miaou!"
  304. exit 128
  305. fi
  306. if [[ -n "$extra_release" ]]; then
  307. echoerrn "FIXME: lxc-miaou-create -o release=bookworm should be implemented ...."
  308. lxc-miaou-create "$ct" "$extra_release"
  309. else
  310. lxc-miaou-create "$ct"
  311. fi
  312. echo "DONE"
  313. fi
  314. if ! container_running "$ct"; then
  315. echowarn "container <$ct> seems to be asleep, starting ..."
  316. lxc start "$ct"
  317. echowarn DONE
  318. fi
  319. }
  320. function load_yaml_from_expanded {
  321. arg1_required "$@"
  322. yaml_key="$1"
  323. yaml_file="$MIAOU_CONFIGDIR/miaou.expanded.yaml"
  324. yaml_value=$(yq ".$yaml_key" "$yaml_file")
  325. if [[ -n "$yaml_value" ]] && [[ "$yaml_value" != "null" ]] && [[ "$yaml_value" != "$TO_BE_DEFINED" ]]; then
  326. PREFIX="" echo "$yaml_value"
  327. else
  328. echoerr "undefined value for key: <$yaml_key> from file: <$yaml_file>"
  329. return 98
  330. fi
  331. }
  332. function check_yaml_defined_value {
  333. yaml_file="$1"
  334. yaml_key="$2"
  335. yaml_value=$(yq ".$yaml_key" "$yaml_file")
  336. if [[ -n "$yaml_value" ]] && [[ "$yaml_value" != "null" ]] && [[ "$yaml_value" != "$TO_BE_DEFINED" ]]; then
  337. return 0
  338. else
  339. echoerr "undefined value for key: <$yaml_key> from file: <$yaml_file>"
  340. return 99
  341. fi
  342. }
  343. # halt unless current user is root
  344. function root_required() {
  345. [[ $(id -u) == 0 ]] || (echoerr "root required" && return 1)
  346. }
  347. # arg#1: environment variable
  348. # read from environment or ask entry before exporting new variable
  349. function env_or_ask {
  350. if [[ -n ${1+x} ]]; then
  351. if printenv "$1" >/dev/null; then
  352. echo "value defined as $(printenv "$1")"
  353. else
  354. printf "Please define %20s: " "$1"
  355. read -r
  356. export "$1=\"$REPLY\"" >/dev/null
  357. fi
  358. else
  359. echoerr "env_or_ask requires one argument: <VARIABLE_NAME>" && exit 5
  360. fi
  361. }
  362. # install_debian_bash()
  363. # grab and install related project
  364. function install_debian_bash() {
  365. local PREFIX="debian-bash:install"
  366. if [[ ! -d /opt/debian-bash ]]; then
  367. echo "installing curl wget commands ..."
  368. apt install -y curl wget
  369. echo "installing debian-bash..."
  370. curl https://git.artcode.re/pvincent/debian-bash/raw/branch/master/install.sh | sudo bash -s -- --host
  371. export PATH=$PATH:/opt/debian-bash/tools/
  372. echo "OK"
  373. else
  374. # /opt/debian-bash/tools/debian_bash_upgrade
  375. echo "addon <debian-bash> already installed!"
  376. fi
  377. # shellcheck source=/dev/null
  378. source /etc/bash.bashrc
  379. sudo /opt/debian-bash/tools/idem_apt_install bash-completion
  380. }
  381. function add_toolbox_sudoers {
  382. local PREFIX="toolbox:sudoers"
  383. echo -n "creating sudoers file to allow sudo as command from /TOOLBOX... "
  384. sudo mkdir -p /etc/sudoers.d
  385. if [[ ! -f /etc/sudoers.d/add_TOOLBOX_to_PATH ]]; then
  386. sudo tee /etc/sudoers.d/add_TOOLBOX_to_PATH &>/dev/null <<EOF
  387. Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/TOOLBOX"
  388. EOF
  389. PREFIX="" echo "updated!"
  390. else
  391. PREFIX="" echo "already done!"
  392. fi
  393. }
  394. function prepare_toolbox() {
  395. local PREFIX="toolbox:prepare"
  396. sudo mkdir -p /TOOLBOX
  397. if ! command -v cargo &>/dev/null; then
  398. echo -n "installing <cargo> ... "
  399. curl -sSf https://sh.rustup.rs | sh -s -- -y
  400. # shellcheck source=/dev/null
  401. source "$HOME/.cargo/env"
  402. /opt/debian-bash/tools/append_or_replace "^PATH=\$PATH:\$HOME/\\.cargo/bin" "PATH=\$PATH:\$HOME/.cargo/bin" ~/.bashrc
  403. PREFIX="" echo "OK"
  404. else
  405. echo "command <cargo> already installed!"
  406. fi
  407. echo -n "installing <fd> ... "
  408. if [ ! -f "/TOOLBOX/fd" ]; then
  409. idem_cargo_install fd-find
  410. sudo cp "$HOME"/.cargo/bin/fd /TOOLBOX/fd
  411. PREFIX="" echo "successfully installed!"
  412. else
  413. PREFIX="" echo "already done!"
  414. fi
  415. echo -n "installing <viu> ... "
  416. if [ ! -f "/TOOLBOX/viu" ]; then
  417. idem_cargo_install viu
  418. sudo cp "$HOME"/.cargo/bin/viu /TOOLBOX/
  419. PREFIX="" echo "successfully installed!"
  420. else
  421. PREFIX="" echo "already done!"
  422. fi
  423. echo -n "installing <rg> alias <ripgrep> ... "
  424. if [ ! -f "/TOOLBOX/rg" ]; then
  425. sudo /opt/debian-bash/tools/idem_apt_install ripgrep
  426. sudo ln /usr/bin/rg /TOOLBOX/
  427. PREFIX="" echo "successfully installed"
  428. else
  429. PREFIX="" echo "already done!"
  430. fi
  431. echo -n "installing <ag> alias <silversearcher-ag> ... "
  432. if [ ! -f "/TOOLBOX/ag" ]; then
  433. sudo /opt/debian-bash/tools/idem_apt_install silversearcher-ag
  434. sudo ln /usr/bin/ag /TOOLBOX/
  435. PREFIX="" echo "successfully installed"
  436. else
  437. PREFIX="" echo "already done!"
  438. fi
  439. echo -n "installing <bandwhich> ... "
  440. if [ ! -f "/TOOLBOX/bandwhich" ]; then
  441. idem_cargo_install bandwhich
  442. sudo cp "$HOME"/.cargo/bin/bandwhich /TOOLBOX/bandwhich
  443. PREFIX="" echo "successfully installed"
  444. else
  445. PREFIX="" echo "already done!"
  446. fi
  447. echo -n "installing <btm> alias <bottom> ... "
  448. if [ ! -f "/TOOLBOX/btm" ]; then
  449. VERSION=$(wget_semver github ClementTsang/bottom)
  450. cd /tmp
  451. wget "https://github.com/ClementTsang/bottom/releases/download/$VERSION/bottom_x86_64-unknown-linux-musl.tar.gz"
  452. tar -xzvf bottom_x86_64-unknown-linux-musl.tar.gz
  453. sudo cp btm /usr/local/bin/
  454. sudo ln /usr/local/bin/btm /TOOLBOX/
  455. PREFIX="" echo "successfully installed"
  456. else
  457. PREFIX="" echo "already done!"
  458. fi
  459. echo -n "installing <micro> ... "
  460. if [ ! -f "/TOOLBOX/micro" ]; then
  461. cd /tmp || (echoerr "/tmp wrong permission" && exit 101)
  462. curl -q https://getmic.ro | GETMICRO_REGISTER=n sh
  463. sudo mv micro /TOOLBOX/micro
  464. sudo chown root:root /TOOLBOX/micro
  465. PREFIX="" echo "successfully installed"
  466. else
  467. PREFIX="" echo "already done!"
  468. fi
  469. echo -n "installing <ncdu> ... "
  470. if [ ! -f "/TOOLBOX/ncdu" ]; then
  471. sudo /opt/debian-bash/tools/idem_apt_install ncdu
  472. sudo cp /usr/bin/ncdu /TOOLBOX/ncdu
  473. PREFIX="" echo "successfully installed"
  474. else
  475. PREFIX="" echo "already done!"
  476. fi
  477. echo -n "installing <unzip> ... "
  478. if [ ! -f "/TOOLBOX/unzip" ]; then
  479. sudo /opt/debian-bash/tools/idem_apt_install unzip
  480. sudo cp /usr/bin/unzip /TOOLBOX/unzip
  481. PREFIX="" echo "successfully installed"
  482. else
  483. PREFIX="" echo "already done!"
  484. fi
  485. echo -n "installing <tree> ... "
  486. if [ ! -f "/TOOLBOX/tree" ]; then
  487. sudo /opt/debian-bash/tools/idem_apt_install tree
  488. sudo cp /bin/tree /TOOLBOX/tree
  489. PREFIX="" echo "successfully installed"
  490. else
  491. PREFIX="" echo "already done!"
  492. fi
  493. echo -n "installing <duf> ... "
  494. if [ ! -f "/TOOLBOX/duf" ]; then
  495. VERSION=$(/opt/debian-bash/tools/wget_semver github muesli/duf)
  496. VERSION_WITHOUT_V=${VERSION#v}
  497. wget -O /tmp/duf.deb "https://github.com/muesli/duf/releases/download/${VERSION}/duf_${VERSION_WITHOUT_V}_linux_amd64.deb"
  498. sudo dpkg -i /tmp/duf.deb
  499. sudo cp /bin/duf /TOOLBOX/duf
  500. PREFIX="" echo "successfully installed"
  501. else
  502. PREFIX="" echo "already done!"
  503. fi
  504. echo -n "installing <curl> ... "
  505. if [ ! -f "/TOOLBOX/curl" ]; then
  506. sudo wget -O /TOOLBOX/curl "https://github.com/moparisthebest/static-curl/releases/latest/download/curl-amd64"
  507. sudo chmod +x /TOOLBOX/curl
  508. PREFIX="" echo "successfully installed"
  509. else
  510. PREFIX="" echo "already done!"
  511. fi
  512. echo -n "installing <wget> ... "
  513. if [ ! -f "/TOOLBOX/wget" ]; then
  514. sudo ln -f /usr/bin/wget /TOOLBOX/wget
  515. PREFIX="" echo "successfully installed"
  516. else
  517. PREFIX="" echo "already done!"
  518. fi
  519. }
  520. # install_mandatory_commands
  521. function install_mandatory_commands() {
  522. local PREFIX="mandatory:commands"
  523. sudo /opt/debian-bash/tools/idem_apt_install dnsutils build-essential curl mariadb-client postgresql-client
  524. if ! exist_command tera; then
  525. echo "installing <tera> ..."
  526. local version=v0.2.4
  527. wget -q "https://github.com/chevdor/tera-cli/releases/download/${version}/tera-cli_linux_amd64.deb" -O /tmp/tera-cli_linux_amd64.deb
  528. sudo dpkg -i /tmp/tera-cli_linux_amd64.deb
  529. else
  530. echo "command <tera> already installed!"
  531. fi
  532. if ! exist_command yq; then
  533. local version binary
  534. version='v4.35.2'
  535. binary='yq_linux_amd64'
  536. sudo sh -c "wget https://github.com/mikefarah/yq/releases/download/${version}/${binary}.tar.gz -O - |\
  537. tar -xz ./${binary} && sudo mv ${binary} /usr/bin/yq"
  538. else
  539. echo "command <yq> already installed!"
  540. fi
  541. }
  542. # flatten array, aka remove duplicated elements in array
  543. # return: `mapfile -t OUTPUT_ARRAY < <(sort_array "${INPUT_ARRAY[@]}")`
  544. function flatten_array {
  545. declare -a array=("$@")
  546. IFS=" " read -r -a array <<<"$(tr ' ' '\n' <<<"${array[@]}" | sort -u | tr '\n' ' ')"
  547. printf '%s\n' "${array[@]}"
  548. }
  549. function prepare_nftables() {
  550. local PREFIX="miaou:firewall"
  551. if [[ ! -f /etc/nftables.rules.d/firewall.table ]]; then
  552. echo "installing nftables ..."
  553. sudo apt install -y nftables
  554. sudo cp -f "$MIAOU_BASEDIR/templates/hardened/nftables.conf" /etc/
  555. sudo mkdir -p /etc/nftables.rules.d
  556. sudo cp -f "$MIAOU_BASEDIR/templates/hardened/firewall.table" /etc/nftables.rules.d/
  557. sudo systemctl restart nftables
  558. sudo systemctl enable nftables
  559. echo "OK"
  560. else
  561. echo "nftables already installed!"
  562. fi
  563. }