aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md61
-rw-r--r--Makefile18
-rw-r--r--lib/main.bash17
-rw-r--r--lib/subcommands/backup.bash4
-rw-r--r--lib/subcommands/del.bash6
-rw-r--r--lib/subcommands/pull.bash2
-rw-r--r--lib/subcommands/sysinfo.bash69
-rw-r--r--lib/subcommands/top.bash113
-rw-r--r--lib/subcommands/zap.bash37
-rw-r--r--lib/util.bash48
-rw-r--r--lib/util/config.bash34
-rw-r--r--lib/util/pkg.bash18
-rw-r--r--lib/util/svc.bash107
-rw-r--r--share/doc/bashtard.1.scd10
14 files changed, 486 insertions, 58 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 78cf85f..1680fac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,5 @@
<!--
-SPDX-FileCopyrightText: 2023 Patrick Spek <p.spek@tyil.nl>
+SPDX-FileCopyrightText: 2024 Patrick Spek <p.spek@tyil.nl>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
@@ -11,7 +11,57 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## [Unreleased]
+## [UNRELEASED]
+
+### Fixed
+
+- `config_subkeys` and `config_subkeys_for` should now leave off the `&` at the
+ end of a variable names which are references.
+
+## [2.1.0] - 2024-04-02
+
+### Added
+
+- Configuration variables can be assigned values of other variables with the
+ `&=` assignment. This allows a single value to be re-used dynamically, rather
+ than having to explicitly set the same value several times.
+- A `zap` command has been added to remove a playbook from the registry without
+ running the playbook's `playbook_del()` function. This is intended to easily
+ remove registry entries when a playbook itself has been deleted or is
+ otherwise broken in a way that the regular `del` subcommand cannot fix.
+
+### Changed
+
+- The `description.txt` is now allowed to be used without the `.txt` suffix.
+ Usage with the `.txt` suffix continues to be supported as well.
+
+### Fixed
+
+- Passing an empty string as default value to `config` should now properly
+ return an empty string without a warning about the configuration key not
+ existing.
+
+## [2.0.2] - 2024-02-28
+
+### Fixed
+
+- Configuration values with `=` in their value part should now work properly
+ with `file_template`. Keys with `=` in them are still *not supported*.
+
+## [2.0.1] - 2023-09-25
+
+### Added
+
+- A new `make` target has been added to build a .tar.gz distributable.
+
+### Changed
+
+- The `svc_` utils should now check which init service you're using when using a
+ linux system. The supported options are still only openrc and systemd.
+- The `pull` subcommand should now properly return with exit-code 0 if no
+ problem were encountered.
+
+## [2.0.0] - 2023-05-22
### Added
@@ -28,6 +78,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
GNU+Linux distributions.
- The `$BASHTARD_PLATFORM` variable now contains an additional entry, `init`, to
allow for handling different init systems on GNU+Linux in a cleaner fashion.
+- A `file_hash` utility function has been added. It currently uses `md5`, but is
+ written in such a fashion that this can easily be updated for the future. Its
+ intent is to encapsulate differences between naming and usage of hashing
+ utilities found on different systems.
- A `dir_hash` utility function has been added, which will give you a hash based
on the file contents of a directory. This function will find files
recursively, calculate a hash for each of them, and then calculate a hash
@@ -49,6 +103,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
which in turn should make re-using playbooks easier.
- A convenience function has been introduced, `playbook_path()`, which can give
you the absolute path to the playbook's base or data directory.
+- A `top` subcommand has been added to give some generic information of all
+ nodes known to Bashtard. It uses information from the `sysinfo` subcommand,
+ which it will pull in through an `ssh` invocation.
### Changed
diff --git a/Makefile b/Makefile
index 94bf25a..917c26c 100644
--- a/Makefile
+++ b/Makefile
@@ -9,9 +9,10 @@ ETCDIR=/etc
# Variables for building (binary) packages
PREFIX=
-PKG_VERSION=0.0.0
+PKG_VERSION=2.1.0
PKG_WORKDIR:=$(or $(PKG_WORKDIR),$(shell mktemp -d))
PKG_ROOT:=$(PKG_WORKDIR)/bashtard-$(PKG_VERSION)
+SOURCE_DATE_EPOCH:=$(shell git show -s --format=%ct)
rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
@@ -76,6 +77,21 @@ pkg-debian:
mkdir -pv -- "dist"
dpkg-deb -b "$(PKG_ROOT)" "dist/bashtard-$(PKG_VERSION).deb"
+pkg-targz:
+ mkdir -pv -- "dist"
+ tar \
+ --exclude dist \
+ --group=0 \
+ --mtime="@$(SOURCE_DATE_EPOCH)" \
+ --numeric-owner \
+ --owner=0 \
+ --pax-option="exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime" \
+ --sort=name \
+ --transform "s@^./@bashtard-$(PKG_VERSION)/@" \
+ --exclude-vcs \
+ --exclude-vcs-ignores \
+ -cvzf "dist/bashtard-$(PKG_VERSION).tar.gz" .
+
qa:
# Check licenses
reuse lint
diff --git a/lib/main.bash b/lib/main.bash
index db5832e..821c2d2 100644
--- a/lib/main.bash
+++ b/lib/main.bash
@@ -86,8 +86,10 @@ Usage:
$BASHTARD_NAME ssh <command>
$BASHTARD_NAME sync [playbook]
$BASHTARD_NAME sysinfo
+ $BASHTARD_NAME top
$BASHTARD_NAME var [-p <playbook>] <key>
$BASHTARD_NAME var [-s] <key> <value>
+ $BASHTARD_NAME zap <playbook>
Perform maintenance on your infra.
@@ -102,7 +104,10 @@ Commands:
sync Pull latest changes through git, and synchronize all added
playbooks.
sysinfo Show gathered information about this system.
+ top Show resource information about all known hosts.
var Show or set the value of a given configuration key.
+ zap Remove a playbook from the registry without attempting to run
+ the delete step from the playbook.
EOF
if [[ ! -d "$BASHTARD_ETCDIR/playbooks.d" ]]
@@ -133,9 +138,19 @@ EOF
# Render playbook descriptions
for playbook in "${playbooks[@]}"
do
+ local description=""
+
+ if [[ -f "$playbook/description.txt" ]]
+ then
+ description="$(cat "$playbook/description.txt")"
+ elif [[ -f "$playbook/description" ]]
+ then
+ description="$(cat "$playbook/description")"
+ fi
+
printf "\t%-${playbook_longest}s %s\n" \
"$(basename "$playbook")" \
- "$(cat "$playbook/description.txt")"
+ "$description"
done
}
diff --git a/lib/subcommands/backup.bash b/lib/subcommands/backup.bash
index 8048053..3d56539 100644
--- a/lib/subcommands/backup.bash
+++ b/lib/subcommands/backup.bash
@@ -72,7 +72,7 @@ backup_filesystem() {
"--keep-weekly" "$(config "bashtard.backup.keep.weekly")"
"--keep-monthly" "$(config "bashtard.backup.keep.monthly")"
"--keep-yearly" "$(config "bashtard.backup.keep.yearly")"
- "--prefix" "{fqdn}-"
+ "--glob-archives" "${BASHTARD_PLATFORM[fqdn]}-"
"--remote-path" "$remote"
"$repo/hostfs"
)
@@ -144,7 +144,7 @@ backup_database_postgresql() {
"--keep-weekly" "$(config "bashtard.backup.keep.weekly")"
"--keep-monthly" "$(config "bashtard.backup.keep.monthly")"
"--keep-yearly" "$(config "bashtard.backup.keep.yearly")"
- "--prefix" "$database-"
+ "--glob-archives" "$database-"
"--remote-path" "$remote"
"$repo/postgresql-$database"
)
diff --git a/lib/subcommands/del.bash b/lib/subcommands/del.bash
index 3649e69..293e401 100644
--- a/lib/subcommands/del.bash
+++ b/lib/subcommands/del.bash
@@ -24,7 +24,7 @@ subcommand()
# Make sure we only run add if the playbook is not in the registry yet
if ! grep -Fqx "$BASHTARD_PLAYBOOK" "$playbook_registry"
then
- crit "bashtard/add" "'$BASHTARD_PLAYBOOK' is not registered for ${BASHTARD_PLATFORM[fqdn]}"
+ crit "bashtard/del" "'$BASHTARD_PLAYBOOK' is not registered for ${BASHTARD_PLATFORM[fqdn]}"
return 3
fi
@@ -32,13 +32,13 @@ subcommand()
if [[ ! -d "$playbook_base" ]]
then
- emerg "bashtard/sync" "No such directory: $playbook_base"
+ emerg "bashtard/del" "No such directory: $playbook_base"
return 1
fi
if [[ ! -f "$playbook_base/playbook.bash" ]]
then
- emerg "bashtard/sync" "No such file: $playbook_base/playbook.bash"
+ emerg "bashtard/del" "No such file: $playbook_base/playbook.bash"
return 1
fi
diff --git a/lib/subcommands/pull.bash b/lib/subcommands/pull.bash
index 4f2ae99..8dfb48b 100644
--- a/lib/subcommands/pull.bash
+++ b/lib/subcommands/pull.bash
@@ -19,4 +19,6 @@ subcommand()
git -C "$BASHTARD_ETCDIR" pull origin master || return 4
git -C "$BASHTARD_ETCDIR" submodule update --init --recursive || return 4
[[ -n $dirty ]] && git -C "$BASHTARD_ETCDIR" stash pop
+
+ return 0
}
diff --git a/lib/subcommands/sysinfo.bash b/lib/subcommands/sysinfo.bash
index 8aa237e..4bceb42 100644
--- a/lib/subcommands/sysinfo.bash
+++ b/lib/subcommands/sysinfo.bash
@@ -5,12 +5,81 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
subcommand() {
+ local load_1
+ local load_5
+ local load_15
+ local memory_free
+ local memory_total
+ local memory_used
+ local storage_free
+ local storage_total
+ local storage_used
+ local uptime
+
+ # Set the variables which are compatible on every POSIX-compliant system
+ storage_used="$(df | awk '/[0-9]+/ { sum += $3 } END { print sum }')"
+ storage_free="$(df | awk '/[0-9]+/ { sum += $4 } END { print sum }')"
+ storage_total=$(( storage_used + storage_free ))
+
+ # And do platform-specific magic
+ case "${BASHTARD_PLATFORM[os]}" in
+ freebsd)
+ load_1="$(uptime | awk -F' *,? *' '{ print $(NF-2) }')"
+ load_5="$(uptime | awk -F' *,? *' '{ print $(NF-1) }')"
+ load_15="$(uptime | awk -F' *,? *' '{ print $NF }')"
+ memory_total=$(( $(sysctl -n hw.physmem) / 1024 ))
+ memory_used=$(( ( $(sysctl -n vm.stats.vm.v_active_count) * $(sysctl -n hw.pagesize) ) / 1024 ))
+ memory_free=$(( memory_total - memory_used))
+ uptime=$(( "$(date +%s)" - "$(sysctl -a | awk '/^kern.boottime/ { print substr($5, 0, length($5)-1) }')" ))
+ ;;
+ *)
+ load_1="$(awk '{ print $1 }' < /proc/loadavg)"
+ load_5="$(awk '{ print $2 }' < /proc/loadavg)"
+ load_15="$(awk '{ print $3 }' < /proc/loadavg)"
+ memory_total="$(awk '/MemTotal/ { print $2 }' < /proc/meminfo)"
+ memory_free="$(awk '/MemAvailable/ { print $2 }' < /proc/meminfo)"
+ memory_used=$(( memory_total - memory_free ))
+ uptime="$(awk -F. '{ print $1 }' < /proc/uptime)"
+ ;;
+ esac
+
+ # For any value that isn't set, just default to 0 to avoid all sorts of errors
+ [[ -z "$load_1" ]] && load_1=0
+ [[ -z "$load_5" ]] && load_5=0
+ [[ -z "$load_15" ]] && load_15=0
+ [[ -z "$memory_free" ]] && memory_free=0
+ [[ -z "$memory_total" ]] && memory_total=0
+ [[ -z "$memory_used" ]] && memory_used=0
+ [[ -z "$storage_free" ]] && storage_free=0
+ [[ -z "$storage_total" ]] && storage_total=0
+ [[ -z "$storage_used" ]] && storage_used=0
+ [[ -z "$uptime" ]] && uptime=0
+
+ # Print the values that can be set by package maintainers
printf "%-15s %s\n" "etcdir" "$BASHTARD_ETCDIR"
printf "%-15s %s\n" "libdir" "$BASHTARD_LIBDIR"
printf "%-15s %s\n" "sharedir" "$BASHTARD_SHAREDIR"
+ # Print all the discovered platform information
for key in "${!BASHTARD_PLATFORM[@]}"
do
printf "%-15s %s\n" "$key" "${BASHTARD_PLATFORM[$key]}"
done
+
+ # Print fun little extras
+ printf "%-15s %0.1fGi / %0.1fGi\n" "memory" \
+ "$(awk '{ print($1 / 1024 / 1024) }' <<< "$memory_used")" \
+ "$(awk '{ print($1 / 1024 / 1024) }' <<< "$memory_total")"
+ printf "%-15s %0.1fGb / %0.1fGb\n" "storage" \
+ "$(awk '{ print($1 / 1024 / 1024) }' <<< "$storage_used")" \
+ "$(awk '{ print($1 / 1024 / 1024) }' <<< "$storage_total")"
+ printf "%-15s %0.2f %0.2f %0.2f\n" "load" \
+ "$load_1" \
+ "$load_5" \
+ "$load_15"
+ printf "%-15s %dd %02dh %02dm %02ds\n" "uptime" \
+ "$(( uptime / 60 / 60 / 24 ))" \
+ "$(( uptime / 60 / 60 % 24 ))" \
+ "$(( uptime / 60 % 60 ))" \
+ "$(( uptime % 60 ))"
}
diff --git a/lib/subcommands/top.bash b/lib/subcommands/top.bash
new file mode 100644
index 0000000..d4a9b3f
--- /dev/null
+++ b/lib/subcommands/top.bash
@@ -0,0 +1,113 @@
+#!/usr/bin/env bash
+
+# SPDX-FileCopyrightText: 2023 Patrick Spek <p.spek@tyil.nl>
+#
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+subcommand()
+{
+ local results
+ local widths
+
+ declare -A results
+ declare -A widths=(
+ [load]=0
+ [memory]=0
+ [node]=0
+ [storage]=0
+ [uptime]=0
+ )
+
+ if [[ ! -d "$BASHTARD_ETCDIR/hosts.d" ]]
+ then
+ crit "$BASHTARD_NAME/ssh" "Could not find hosts file at $BASHTARD_ETCDIR/hosts.d"
+ return 3
+ fi
+
+ chgdir "$BASHTARD_ETCDIR/hosts.d"
+
+ for node in *
+ do
+ local user
+ local host
+
+ user="$(config_for "$node" "bashtard.ssh.user" "$USER")"
+ host="$(config_for "$node" "bashtard.ssh.host")"
+
+ if [[ -z "$host" ]]
+ then
+ crit "$BASHTARD_NAME/ssh" "bashtard.ssh.host is not configured for $node"
+ continue
+ fi
+
+ if [[ "$node" == "${BASHTARD_PLATFORM[fqdn]}" ]]
+ then
+ results+=(["$node"]="$("$BASHTARD_BIN" sysinfo)")
+ else
+ debug "$BASHTARD_NAME/ssh" "$user@$node ($host) > bashtard sysinfo"
+ # shellcheck disable=SC2029
+ results+=(["$node"]="$(ssh "$user@$host" "bashtard sysinfo" 2>/dev/null)")
+ fi
+
+ unset user
+ unset host
+ done
+
+ # Check widths
+ for node in "${!results[@]}"
+ do
+ node_load="$(grep '^load' <<< "${results["$node"]}" | sed 's/[^ ]* *//')"
+ node_memory="$(grep '^memory' <<< "${results["$node"]}" | sed 's/[^ ]* *//')"
+ node_storage="$(grep '^storage' <<< "${results["$node"]}" | sed 's/[^ ]* *//')"
+ node_uptime="$(grep '^uptime' <<< "${results["$node"]}" | sed 's/[^ ]* *//')"
+
+ width_load="$(wc -c <<< "$node_load")"
+ width_memory="$(wc -c <<< "$node_memory")"
+ width_node="$(wc -c <<< "$node")"
+ width_storage="$(wc -c <<< "$node_storage")"
+ width_uptime="$(wc -c <<< "$node_uptime")"
+
+ if (( widths[load] < width_load ))
+ then
+ widths[load]=$width_load
+ fi
+
+ if (( widths[memory] < width_memory ))
+ then
+ widths[memory]=$width_memory
+ fi
+
+ if (( widths[node] < width_node ))
+ then
+ widths[node]=$width_node
+ fi
+
+ if (( widths[storage] < width_storage ))
+ then
+ widths[storage]=$width_storage
+ fi
+
+ if (( widths[uptime] < width_uptime ))
+ then
+ widths[uptime]=$width_uptime
+ fi
+ done
+
+ # Print results
+ printf "$(tput bold)%-${widths[node]}s %-${widths[load]}s %-${widths[memory]}s %-${widths[storage]}s %-${widths[uptime]}s$(tput sgr0)\n" \
+ "Node" \
+ "Load" \
+ "Memory" \
+ "Storage" \
+ "Uptime"
+
+ for node in "${!results[@]}"
+ do
+ printf "%-${widths[node]}s %${widths[load]}s %${widths[memory]}s %${widths[storage]}s %${widths[uptime]}s\n" \
+ "$node" \
+ "$(grep '^load' <<< "${results["$node"]}" | sed 's/[^ ]* *//')" \
+ "$(grep '^memory' <<< "${results["$node"]}" | sed 's/[^ ]* *//')" \
+ "$(grep '^storage' <<< "${results["$node"]}" | sed 's/[^ ]* *//')" \
+ "$(grep '^uptime' <<< "${results["$node"]}" | sed 's/[^ ]* *//')"
+ done | sort
+}
diff --git a/lib/subcommands/zap.bash b/lib/subcommands/zap.bash
new file mode 100644
index 0000000..dcefffd
--- /dev/null
+++ b/lib/subcommands/zap.bash
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+
+# SPDX-FileCopyrightText: 2023 Patrick Spek <p.spek@tyil.nl>
+#
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+subcommand()
+{
+ local buffer
+ local playbook_registry
+
+ export BASHTARD_PLAYBOOK="$1" ; shift
+
+ if [[ -z "$BASHTARD_PLAYBOOK" ]]
+ then
+ crit "bashtard/zap" "No playbook name specified"
+ return
+ fi
+
+ playbook_registry="$BASHTARD_ETCDIR/registry.d/${BASHTARD_PLATFORM[fqdn]}"
+
+ # Make sure we only run add if the playbook is not in the registry yet
+ if ! grep -Fqx "$BASHTARD_PLAYBOOK" "$playbook_registry"
+ then
+ crit "bashtard/zap" "'$BASHTARD_PLAYBOOK' is not registered for ${BASHTARD_PLATFORM[fqdn]}"
+ return 3
+ fi
+
+ notice "bashtard/zap" "Removing playbook '$BASHTARD_PLAYBOOK' from '${BASHTARD_PLATFORM[fqdn]}'"
+
+ buffer="$(tmpfile)"
+
+ # Remove the playbook from the registry
+ cp -- "$playbook_registry" "$buffer"
+ grep -Fvx "$BASHTARD_PLAYBOOK" "$buffer" \
+ | sort > "$playbook_registry"
+}
diff --git a/lib/util.bash b/lib/util.bash
index 54ec562..ad84247 100644
--- a/lib/util.bash
+++ b/lib/util.bash
@@ -18,6 +18,11 @@ chgdir() {
cd -- "$1" || die "Failed to change directory to $1"
}
+# Removes whitespace surrounding a given text.
+chomp() {
+ awk '{$1=$1};1' <<< "$@"
+}
+
# Create a datetime stamp. This is a wrapper around the date utility, ensuring
# that the date being formatted is always in UTC and respect SOURCE_DATE_EPOCH,
# if it is set.
@@ -61,9 +66,19 @@ die() {
# in a directory. It can be used to check whether contents changed after
# templating files in a given directory.
dir_hash() {
- find "$1" -type f -exec sha1sum {} \; \
- | sha1sum \
- | awk '{ print $1 }'
+ local path
+
+ path="$1" ; shift
+
+ for entry in "$path"/*
+ do
+ if [[ -d "$entry" ]]
+ then
+ dir_hash "$entry"
+ fi
+
+ file_hash "$entry"
+ done | file_hash -
}
# Fetch a file from an URL. Using this function introduces a dependency on curl.
@@ -106,6 +121,25 @@ fetch_http_wget() {
wget --quiet --output-document "$2" "$1"
}
+# Hash a given file. This is a convenience function to work around different
+# systems calling their file hashing programs differently, and generating
+# different output. This function only expects 1 file as argument, and only
+# outputs the hash of this particular file.
+file_hash() {
+ file_hash_md5 "$@"
+}
+
+file_hash_md5() {
+ local file
+
+ file="$1" ; shift
+
+ case "${BASHTARD_PLATFORM[key]}" in
+ freebsd) md5 "$file" | awk '{ print $NF }' ;;
+ linux-*) md5sum "$file" | awk '{ print $1 }' ;;
+ esac
+}
+
# A very simple means of templating a file, using sed and awk. The template
# file is assumed to exist within the share directory of the current playbook.
# Variables are passed as key=value pairs to this function. Inside the
@@ -128,18 +162,18 @@ file_template()
do
debug "bashtard/template" "Adding $kv to sedfile at $sedfile"
- key="$(awk -F= '{ print $1 }' <<< "$kv")"
+ key="$(cut -d'=' -f -1 <<< "$kv")"
if [[ -z "$key" ]]
then
- crit "bashtard/template" "Empty key in '$kv' while rendering $file?"
+ crit "bashtard/template" "Empty key in '$kv' while rendering $file"
fi
- value="$(awk -F= '{ print $NF }' <<< "$kv")"
+ value="$(cut -d'=' -f 2- <<< "$kv")"
if [[ -z "$value" ]]
then
- crit "bashtard/template" "Empty key in '$kv' while rendering $file?"
+ crit "bashtard/template" "Empty key in '$kv' while rendering $file"
fi
# shellcheck disable=SC2016
diff --git a/lib/util/config.bash b/lib/util/config.bash
index 4727706..ff20bd0 100644
--- a/lib/util/config.bash
+++ b/lib/util/config.bash
@@ -17,7 +17,11 @@ config_subkeys() {
config_for() {
local host=$1 ; shift
local key=$1 ; shift
- local default=$1 ; shift
+
+ # Use a variable definition test to define default, in order to ensure
+ # it is _not_ defined if no argument for it was passed, but _is_
+ # defined even if an empty string was passed.
+ test -v 1 && { local default=$1 ; shift ; }
local default
local file
@@ -51,7 +55,26 @@ config_for() {
[[ ! -f $file ]] && continue
- value="$(awk -F= '$1 == "'"$key"'" { print $NF }' "$file")"
+ # Check if the lookup is a reference variable, defined by using
+ # &= instead of just a single = as seperator. If this exists,
+ # do a new config_for lookup, this time using the value as the
+ # key for the new lookup.
+ value="$(awk -F= '$1 == "'"$key"'&" { print $0 }' "$file" | cut -d'=' -f 2-)"
+
+ if [[ -n $value ]]
+ then
+ debug "bashtard/config_for" "Found reference for $key to $value in $file"
+
+ printf "%s" "$(config_for "$host" "$value")"
+ return
+ fi
+
+ # Use awk to find the right line, then use cut to get the
+ # actual value. Cutting it out with awk _is_ possible, but
+ # comes with whitespace issues or having to deal with values
+ # containing the seperator (=), so using cut is much simpler
+ # and easier to understand.
+ value="$(awk -F= '$1 == "'"$key"'" { print $0 }' "$file" | cut -d'=' -f 2-)"
if [[ -n $value ]]
then
@@ -62,8 +85,8 @@ config_for() {
fi
done
- # Return default value
- if [[ -n $default ]]
+ # Return default value, if one has been defined
+ if test -v default
then
printf "%s" "$default"
return
@@ -115,6 +138,9 @@ config_subkeys_for() {
subkey="$(awk -F. '{ print $1 }' <<< "${result#"$key."}")"
+ # Remove trailing ampersand if it exists
+ [[ "${subkey: -1}" == "&" ]] && subkey="${subkey:0:-1}"
+
debug "bashtard/config_subkeys" "Found '$subkey' as subkey of '$key' through '$result'"
results+=("$subkey")
done < <(grep "^$key\." "$file" | awk -F= '{ print $1 }')
diff --git a/lib/util/pkg.bash b/lib/util/pkg.bash
index 1538c3e..1433815 100644
--- a/lib/util/pkg.bash
+++ b/lib/util/pkg.bash
@@ -33,10 +33,11 @@ pkg_install() {
local app=$1 ; shift
case "${BASHTARD_PLATFORM[key]}" in
- freebsd) set -- /usr/sbin/pkg install -y "$app" ;;
- linux-debian*) set -- apt install -y "$app" ;;
- linux-gentoo) set -- emerge --ask=n --update "$app" ;;
- linux-ubuntu) set -- apt install -y "$app" ;;
+ freebsd) set -- /usr/sbin/pkg install -y "$app" ;;
+ linux-alpine_linux) set -- apk add --no-cache "$app" ;;
+ linux-debian*) set -- apt install -y "$app" ;;
+ linux-gentoo) set -- emerge --ask=n --update "$app" ;;
+ linux-ubuntu) set -- apt install -y "$app" ;;
*)
crit "$system" "No package manager configured for ${BASHTARD_PLATFORM[key]}"
return 1
@@ -54,10 +55,11 @@ pkg_uninstall() {
local app=$1 ; shift
case "${BASHTARD_PLATFORM[key]}" in
- freebsd) set -- /usr/sbin/pkg uninstall -y "$app" ;;
- linux-debian*) set -- apt remove -y "$app" ;;
- linux-gentoo) set -- emerge --ask=n --unmerge "$app" ;;
- linux-ubuntu) set -- apt remove -y "$app" ;;
+ freebsd) set -- /usr/sbin/pkg uninstall -y "$app" ;;
+ linux-alpine_linux) set -- apk del "$app" ;;
+ linux-debian*) set -- apt remove -y "$app" ;;
+ linux-gentoo) set -- emerge --ask=n --unmerge "$app" ;;
+ linux-ubuntu) set -- apt remove -y "$app" ;;
*)
crit "$system" "No package manager configured for ${BASHTARD_PLATFORM[key]}"
return 1
diff --git a/lib/util/svc.bash b/lib/util/svc.bash
index fd65e4c..1b1ecbc 100644
--- a/lib/util/svc.bash
+++ b/lib/util/svc.bash
@@ -34,11 +34,18 @@ svc_disable() {
local service=$1
- case "${BASHTARD_PLATFORM[key]}" in
- linux-gentoo) set -- /sbin/rc-update del "$service" ;;
- linux-*) set -- systemctl disable "$service" ;;
+ case "${BASHTARD_PLATFORM[os]}" in
+ linux)
+ case "${BASHTARD_PLATFORM[init]}" in
+ openrc) set -- /sbin/rc-update del "$service" ;;
+ systemd) set -- systemctl disable "$service" ;;
+ *)
+ crit "$system" "No service manager support to disable with ${BASHTARD_PLATFORM[init]}"
+ return 1
+ esac
+ ;;
*)
- crit "$system" "No service manager configured for ${BASHTARD_PLATFORM[key]}"
+ crit "$system" "No service manager support to enable for ${BASHTARD_PLATFORM[key]}"
return 1
esac
@@ -53,7 +60,16 @@ svc_enable() {
local service=$1
local rc
- case "${BASHTARD_PLATFORM[key]}" in
+ case "${BASHTARD_PLATFORM[os]}" in
+ linux)
+ case "${BASHTARD_PLATFORM[init]}" in
+ openrc) set -- /sbin/rc-update add "$service" ;;
+ systemd) set -- systemctl enable "$service" ;;
+ *)
+ crit "$system" "No service manager support to enable with ${BASHTARD_PLATFORM[init]}"
+ return 1
+ esac
+ ;;
freebsd)
rc="$(printf '%s_enable="YES"' "$service")"
@@ -63,12 +79,9 @@ svc_enable() {
fi
return 0
-
;;
- linux-gentoo) set -- /sbin/rc-update add "$service" ;;
- linux-*) set -- systemctl enable "$service" ;;
*)
- crit "$system" "No service manager configured for ${BASHTARD_PLATFORM[key]}"
+ crit "$system" "No service manager support to enable for ${BASHTARD_PLATFORM[key]}"
return 1
esac
@@ -82,12 +95,21 @@ svc_reload() {
local service=$1
- case "${BASHTARD_PLATFORM[key]}" in
- freebsd) set -- service "$service" reload ;;
- linux-gentoo) set -- /sbin/rc-service "$service" reload ;;
- linux-*) set -- systemctl reload "$service" ;;
+ case "${BASHTARD_PLATFORM[os]}" in
+ linux)
+ case "${BASHTARD_PLATFORM[init]}" in
+ openrc) set -- /sbin/rc-service "$service" reload ;;
+ systemd) set -- systemctl reload "$service" ;;
+ *)
+ crit "$system" "No service manager support to reload with ${BASHTARD_PLATFORM[init]}"
+ return 1
+ esac
+ ;;
+ freebsd)
+ set -- service "$service" reload
+ ;;
*)
- crit "$system" "No service manager configured for ${BASHTARD_PLATFORM[key]}"
+ crit "$system" "No service manager support to reload for ${BASHTARD_PLATFORM[key]}"
return 1
esac
@@ -101,12 +123,21 @@ svc_restart() {
local service=$1
- case "${BASHTARD_PLATFORM[key]}" in
- freebsd) set -- service "$service" restart ;;
- linux-gentoo) set -- /sbin/rc-service "$service" restart ;;
- linux-*) set -- systemctl restart "$service" ;;
+ case "${BASHTARD_PLATFORM[os]}" in
+ linux)
+ case "${BASHTARD_PLATFORM[init]}" in
+ openrc) set -- /sbin/rc-service "$service" restart ;;
+ systemd) set -- systemctl restart "$service" ;;
+ *)
+ crit "$system" "No service manager support to restart with ${BASHTARD_PLATFORM[init]}"
+ return 1
+ esac
+ ;;
+ freebsd)
+ set -- service "$service" restart
+ ;;
*)
- crit "$system" "No service manager configured for ${BASHTARD_PLATFORM[key]}"
+ crit "$system" "No service manager support to restart for ${BASHTARD_PLATFORM[key]}"
return 1
esac
@@ -120,12 +151,21 @@ svc_start() {
local service=$1
- case "${BASHTARD_PLATFORM[key]}" in
- freebsd) set -- service "$service" start ;;
- linux-gentoo) set -- /sbin/rc-service "$service" start ;;
- linux-*) set -- systemctl start "$service" ;;
+ case "${BASHTARD_PLATFORM[os]}" in
+ linux)
+ case "${BASHTARD_PLATFORM[init]}" in
+ openrc) set -- /sbin/rc-service "$service" start ;;
+ systemd) set -- systemctl start "$service" ;;
+ *)
+ crit "$system" "No service manager support to start with ${BASHTARD_PLATFORM[init]}"
+ return 1
+ esac
+ ;;
+ freebsd)
+ set -- service "$service" start
+ ;;
*)
- crit "$system" "No service manager configured for ${BASHTARD_PLATFORM[key]}"
+ crit "$system" "No service manager support to start for ${BASHTARD_PLATFORM[key]}"
return 1
esac
@@ -139,12 +179,21 @@ svc_stop() {
local service=$1
- case "${BASHTARD_PLATFORM[key]}" in
- freebsd) set -- service "$service" stop ;;
- linux-gentoo) set -- /sbin/rc-service "$service" stop ;;
- linux-*) set -- systemctl stop "$service" ;;
+ case "${BASHTARD_PLATFORM[os]}" in
+ linux)
+ case "${BASHTARD_PLATFORM[init]}" in
+ openrc) set -- /sbin/rc-service "$service" stop ;;
+ systemd) set -- systemctl stop "$service" ;;
+ *)
+ crit "$system" "No service manager support to stop with ${BASHTARD_PLATFORM[init]}"
+ return 1
+ esac
+ ;;
+ freebsd)
+ set -- service "$service" stop
+ ;;
*)
- crit "$system" "No service manager configured for ${BASHTARD_PLATFORM[key]}"
+ crit "$system" "No service manager support to stop for ${BASHTARD_PLATFORM[key]}"
return 1
esac
diff --git a/share/doc/bashtard.1.scd b/share/doc/bashtard.1.scd
index 8f6e4b4..1a681e0 100644
--- a/share/doc/bashtard.1.scd
+++ b/share/doc/bashtard.1.scd
@@ -1,6 +1,6 @@
bashtard(1)
-; SPDX-FileCopyrightText: 2023 Patrick Spek <p.spek@tyil.nl>
+; SPDX-FileCopyrightText: 2024 Patrick Spek <p.spek@tyil.nl>
; SPDX-License-Identifier: AGPL-3.0-or-later
# NAME
@@ -21,6 +21,7 @@ bashtard - A Bash-based configuration management utility
*bashtard* var [-p _playbook_] <_key_>++
*bashtard* var [-s] <_key_> <_value_>++
*bashtard* sysinfo
+*bashtard* zap <playbook>
# DESCRIPTION
@@ -91,6 +92,13 @@ configuration file. This variant accepts the *-s* option, to instead save it to
the *secrets* file, which should only be readable by the user maintaining the
system through *bashtard*.
+## zap
+
+Removes a playbook from the registry. Unlike *del*, this will not attempt to run
+the *del* function defined within the playbook. This functionality can be used
+to remove the entry of a misbehaving playbook, or to be able to re-run the *add*
+function on it.
+
# SEE ALSO
- _bashtard(3)_ -- Functions and variables exposed by *bashtard* for use in