commit - 622e6949f90df00caf7d792a15f19f6b56d33125
commit + 8e44e3d49ed6238ddfe3dc214d2fa2015e6df797
blob - 49df62ba5478f1493bfdc4cc476e6f55e404812c
blob + 9728e84212cead97ddd44cd086e6b37ff4436204
--- Makefile
+++ Makefile
.POSIX:
PREFIX:=/usr/local
SHELLS=ksh93 ksh yash sh
-UTILITY_VERSION=0.1.6
+UTILITY_VERSION=0.2.0
UTILITY=$(PWD)/r7
# To use the test suite, please edit or use environment for SSH parameters
# SSH_ID=/path/to/.ssh/id_ed25519
# SSH_TEST_NODES=nodeA nodeB
-.DEFAULT: all
+.DEFAULT: all all: tests
-all: tests
-
release: r7.1
make tests
whoami
echo 'state_hello() { echo Hey! ; }' > groups/heyo && \
echo 'dummy_hello() { echo Heyo! ; }' >> groups/heyo && \
echo 'group heyo $(SSH_TEST_NODES)' >> site-config && export R7_DEBUG=yes && \
+ . $(UTILITY) && \
+ prefix install state doc dummy && \
digraph_host && \
- run_config && \
+ run_config && \
output_dump && \
output | grep Hey! && \
output && \
rm -fr testdir/workdir2/_run
cp testdir/source testdir/workdir2/groups/
mkdir testdir/workdir2/groups/source.dir
- echo : > testdir/workdir2/groups/source.dir/my-source
for node in $(SSH_TEST_NODES); do \
echo myvar=3333 > "testdir/workdir2/nodes/$$node/my-source" ; \
done
. $(UTILITY) && import "$$node"; \
done
cd testdir/workdir2/ && . $(UTILITY) && import notfound || :
- find testdir/workdir2/nodes | grep sshd_config
+ find testdir/workdir2/nodes | grep hosts
find testdir/workdir2/nodes
@echo _________________________________________________________
test -d testdir/workdir3
cd testdir/workdir3 && $R | wc -c | grep -q 0
cd testdir/workdir3 && \
- cp "$(SSH_ID)" .ssh/id_ed25519_r7 && \
- cp "$(SSH_ID).pub" .ssh/id_ed25519_r7.pub && \
+ cp .ssh/config .sshtmp && \
+ echo 'Host test-haiku-b5' > .ssh/config && \
+ echo ' User user' >> .ssh/config && \
+ echo >>.ssh/.config && \
+ cat .sshtmp >>.ssh/config && \
+ sleep 1 && \
+ cp -p "$(SSH_ID)" .ssh/id_ed25519_r7 && \
+ cp -p "$(SSH_ID).pub" .ssh/id_ed25519_r7.pub && \
. $(UTILITY) && for node in $(SSH_TEST_NODES); do \
mkdir "nodes/$$node" && \
ssh_accept_new "$$node"; \
blob - 39b3cd51e6bd3df38183f45f8f1afda3ed2bbdcd
blob + f0c090dcd606bced6e8e6289f315a43435b403f7
--- README.md
+++ README.md
### Introduction
R7 is a configuration management framework made to configure nodes with
-configuration files and related operations versionned in a central repository.
-To remain code versionning system agnostic, manual or automated versionning is
+configuration files and related operations versioned in a central repository.
+To remain code versioning system agnostic, manual or automated versioning is
left to the user, via makefiles or triggered from r7 `site-config` configuration
file _(See below)_.
containing the directives to install the configuration and potential
requirements.
-_Nodes sub-directories are hostnames understood by the ssh client and
+_Nodes sub-directories are host names understood by the ssh client and
configuration._
-_Currently, r7 requires valid ssh configuration and keyfiles in the repository
+_Currently, r7 requires valid ssh configuration and key files in the repository
`.ssh/` directory._
_Repositories can be initialized with `rset init` or `rset -w
summary
```
-There is an exemple of the deployment of that configuration within the r7
+There is an example of the deployment of that configuration within the r7
repository:
```
Any function managed by `r7` needs to be declared in the format `^PREFIX_NAME()`.
Group files names can't contain spaces, tabs or newlines, as well for nodes
-dirnames. _The ':' character is not recommanded as well as it may reduce
-lisibility of the interactive output._
+`dirnames`. _The ':' character is not recommended as well as it may reduce
+readability of the interactive output._
Called groups and node directories are copied to related nodes in `hostname:/tmp/r7/`:
(the default `R7_PREFIX`) in the respective declaration order they're found in the
related group file will be executed.
-Site confiurations are shell scripts sourced by r7 after it's environment is
+Site configurations are shell scripts sourced by r7 after it's environment is
initialized, so `prefix`, `group`, `output-dump`, `summary` are the functions or
aliases provided by r7 itself. This allow for scripting from the `site-config`
file. Here `output-dump`, and `summary` are called to output potential errors,
diffs and permissions changes at the end of the interactive output obtained by
-`r7 run-config`. If nothing catched happened, nothing is added to the output.
+`r7 run-config`. If nothing happened, nothing is added to the output.
### Errors during remote execution of groups
}
```
-And we re-run the configuration to see what's happenning.
+And we re-run the configuration to see what's happening.
```
$ r7 run-config
### Repository initialisation
-Using the `init` command, we can specify the current or a specifed
+Using the `init` command, we can specify the current or a specified
work directory to be created and act as an r7 repository.
-_Automated versionning of outputs are currently let to the user, a recommended
+_Automated versioning of outputs are currently let to the user, a recommended
place would be the end of the site configuration file._
This command initializes a new directory called `test.org`:
- Adjust the SSH client configuration file in the repository `.ssh/config`
-_Note that it is possible to import additionnal SSH configurations, like the user
+_Note that it is possible to import additional SSH configurations, like the user
one from the SSH configuration, but it is advised to keep them separate._
### SSH agent handling
-The function `unlock` can be used to set the SSH agent environement, this will
+The function `unlock` can be used to set the SSH agent environment, this will
be required for any automated operation later done by r7:
```sh
tmux || screen
```
-_***Warning:*** Unlock will terminate any running `ssh-agent` instances._
+#### Tmux configuration
+
+```
+set -g update-environment -r
+```
+
+#### Optional Shell configuration
+
+This is useful for handling multiple tmux sessions.
+
+```sh
+# Add this to the shell's rc
+if [ -z "$TMUX" ]; then
+ if [ -n "$SSH_TTY" ]; then
+ if [ -z "$SSH_AUTH_SOCK" ]; then
+ export SSH_AUTH_SOCK="$HOME/.ssh/.auth_socket"
+ fi
+ if [ ! -S "$SSH_AUTH_SOCK" ]; then
+ eval $(ssh-agent -a $SSH_AUTH_SOCK) >/dev/null 2>&1
+ echo $SSH_AGENT_PID >$HOME/.ssh/.auth_pid
+ fi
+ if [ -z $SSH_AGENT_PID ]; then
+ export SSH_AGENT_PID=$(cat $HOME/.ssh/.auth_pid)
+ fi
+ ssh-add "$SSH_ID" 2>/dev/null
+ fi
+fi
+```
+
+
### Adding new hosts
For adding a new host, the simplest way is to have pre-configured
### Importing hosts configurations
-_This feature currently only support OpenBSD._
-
Avoiding to import the configuration manually is possible with the `import`
command:
### Writing group files
-Group files collects fonctions related to the configuration of the operating
+Group files collects functions related to the configuration of the operating
system, networking, services, global and user configurations packages
installations and application deployments.
_**file**: `groups/example1`_
-With the default prefix, `install`, `state`, `doc`, the fonction that will be
+With the default prefix, `install`, `state`, `doc`, the function that will be
executed are `state_A` and `doc_A`. To test that group file with all the
functions inside we can call r7 the following way:
### Sourcing specific files
-Here's an example how to source additionnal shell from the deployed node
+Here's an example how to source additional shell from the deployed node
directory, or elsewhere:
```sh
https://cdn.openbsd.org/pub/OpenBSD
```
-_Note that the `output` function arguments are using shell's case globbing patterns._
+_Note that the `output` function arguments are using shell's case glob patterns._
### Active nodes
### nodename
***Description:***
-Returns the small hostname of the current host
+Returns the small host name of the current host
***Usage:***
```sh
### groupinstalldir
***Description:***
-Change directory to the current group directoy then call installdir
+Change directory to the current group directory then call installdir
***Usage:***
```sh
### nodeinstalldir
***Description:***
-Change directory to the current group directoy then call installdir
+Change directory to the current group directory then call installdir
***Usage:***
```sh
destination
```
-### source
+### fsource
***Description:***
Source a POSIX shell file in the current execution
***Usage:***
```sh
-source filename
+fsource filename
```
### groupsource
### ssh-ids-hosts
***Description:***
-Returns SSH IDs along with matching keyfile and hostname
+Returns SSH IDs along with matching key file and host name
***Usage:***
```sh
## Technical notes
-- Supported shells are ksh93, oksh, yash and bash.
-- Supported platforms are OpenBSD, FreeBSD, NetBSD and GNU/Linux.
-- Dependencies are awk, OpenSSH and column
-- Optional dependencies are openrsync, rsync, column, graphviz and pandoc.
-- Busybox support is planned.
-- The HTML output is a work in progress.
+- Supported shells are ksh93, oksh, yash and bash
+- Supported target platforms are POSIX compatible systems
+ - `/bin/sh` or compatible must be set for the user's shell (which is
+ usually the case by default)
+ - `/tmp` must be writable by the user
+- Supported control node platforms are supposed to be POSIX compatible systems
+ but currently limited to BSD's, Darwin and GNU/Linux
+ - Dependencies are awk, OpenSSH and column
+ - Optional dependencies are openrsync, rsync, column, graphviz and pandoc
+- The r7 importer supports the following platform:
+ - Alpine Linux
+ - Archlinux
+ - Crux
+ - Debian
+ - DragonFlyBSD
+ - FreeBSD
+ - Gentoo
+ - Guix
+ - Haiku
+ - Minix
+ - NetBSD
+ - Omnios
+ - OpenBSD
+ - OpenSUSE
+ - QNX
+ - Rocky Linux
+ - Salix
+ - Void Linux
---
## License
-The provided group library is shared as additionnal examples WITH NO WARRANTIES of the
+The provided group library is shared as additional examples WITH NO WARRANTIES of the
documentation and contain the following third-party files under the ISC License.
Copyright information are indicated in the LICENSE section of related files.
blob - 9f95a199b0e44884ab0abb31a98fb72849d7f9ff
blob + 09356f5a57f7039c794727aa88d5d7f9e89b5e44
--- r7
+++ r7
# Global configuration
# ====================
+: "${ZSH_VERSION:=}"
+R7_DEBUG=no
VERSION=0.2.0
+_init_pwd="$PWD"
# shellcheck disable=SC2031
_init_env() {
_debug _INIT_ENV
+ cd "$_init_pwd" || _fail "Unable to cd to '$_init_pwd'"
# Here is the default configuration
: "${R7_DEBUG:=no}"
: "${R7_PARALLEL:=no}"
: "${R7_PREFIX:=install state doc}"
: "${R7_SHOWOUTPUT:=no}"
- : "${R7_WORKDIR:=$PWD}"
+ : "${R7_WORKDIR:=$_init_pwd}"
: "${R7_SITE_CONFIG:=$R7_WORKDIR/site-config}"
: "${R7_OUTPUTDIR:=$R7_WORKDIR/_output}"
: "${SSH_CONFIG_DIR:=$R7_WORKDIR/.ssh}"
digraph_ssh_id_hosts
;;
html) html "$@" ;;
- '') info ;;
+ '') cd "$R7_WORKDIR" && info ;;
*)
case $0 in
-) exit 33 ;;
StrictHostKeyChecking yes
User root
UserKnownHostsFile $R7_WORKDIR/.ssh/known_hosts
-
-Host alpha
- Hostname 10.10.0.1
-
-Host beta
- Hostname 10.10.0.2
-
-Host gamma
- Hostname 10.10.0.3
eof
fi
touch "${SSH_IDENTITY_FILE}" "${SSH_IDENTITY_FILE}.pub"
alias ssh-debug=ssh_debug
ssh_debug() {
_debug "SSH $*"
- ssh -vvv "$@" :
+ ssh -vvv "$@"
}
alias ssh-known-hosts=ssh_known_hosts
alias ssh-accept-new=ssh_accept_new
ssh_accept_new() {
- ssh -o StrictHostKeyChecking=accept-new "$@" :
+ ssh -F "$SSH_CONFIG_FILE" -o StrictHostKeyChecking=accept-new "$@" :
}
alias ssh-control-master-clean=ssh_control_master_clean
}
unlock() {
- pkill ssh-agent
eval "$(ssh-agent)"
ssh-add "$SSH_IDENTITY_FILE"
}
_debug "COPY $1 $2 USE SCP"
dir=${dir:-/tmp/r7}
ssh "$node" rm -fr "$dir/$1" 2>/dev/null
- /usr/bin/scp "-oConnectTimeout=$SSH_CONNECT_TIMEOUT" -qF "$SSH_CONFIG_FILE" -r "$1" "$2"
+ scp "-oConnectTimeout=$SSH_CONNECT_TIMEOUT" -qF "$SSH_CONFIG_FILE" -r "$1" "$2" && return 0
+ _fail "Unable to copy '$1' to '$2'."
)
# Deployment functions
nodedir="nodes/$target"
test "$R7_DRYRUN" = yes || {
if test -d "$stem.dir"; then
- ssh "$target" 'test -d /tmp/r7 || { umask 027; mkdir -p /tmp/r7; }'
+ ssh "$target" /bin/sh -c 'umask 027; mkdir -p /tmp/r7'
copy "$stem.dir" "$target:/tmp/r7" || return 3
fi
if test -d "$nodedir"; then
test -f /tmp/r7/"$trace_id.$target" || {
- ssh "$target" 'test -d /tmp/r7 || { umask 027; mkdir -p /tmp/r7; }'
+ ssh "$target" /bin/sh -c 'umask 027; mkdir -p /tmp/r7'
copy "$nodedir" "$target:/tmp/r7" || return 3
}
fi
)
_payload() (
+ echo "hostname=$target"
echo "trace_id=$trace_id"
echo "groupname=$new_name"
echo "exitonerror=$R7_GROUP_EXITONERROR"
groupdir() (
echo "/tmp/r7/$groupname.dir"
)
- _presource() {
- test $# -gt 0 || {
- error missing source argument
- return 2
- }
- source "$(test -f "$1" && printf %s "$PWD/${1##"$PWD"}")"
- }
- nodesource() {
- node "$1" && cd "$(nodedir)" && _presource "$1"
- }
- groupsource() {
- cd "$(groupdir)" && _presource "$1"
- }
- source() {
+ _source() {
if sh -n "$1"; then
trace SOURCE "$1"
. "$1"
return 2
fi
}
+ fsource() {
+ test $# -gt 0 || {
+ error missing source argument
+ return 2
+ }
+ _source "$(test -f "$1" && printf %s "$PWD/${1##"$PWD"}")"
+ }
+ nodesource() {
+ node "$1" && cd "$(nodedir)" && fsource "$1"
+ }
+ groupsource() {
+ cd "$(groupdir)" && _fsource "$1"
+ }
install() ( cd /tmp/r7 && r7_install "$@" ; )
groupinstall() ( cd "$(groupdir)" && r7_install "$@" ; )
nodeinstall() ( cd "$(nodedir)" && r7_install "$@" ; )
done
shift $((OPTIND - 1))
set -a
- test -n "$source" && sh -n "$source" && . "./$source"
+ test -n "$source" && sh -n "$source" && set -a && . "./$source" && set +a
for file; do
sh > "${file%%.tpl}" <<-.
cat <<-..
nodedir=$(nodedir)
groupdir=$(groupdir)
trace CONNECTED $(date +%s)
+ exec 1>&2
eof
cat "$1"
_debug "PREFIX $R7_PREFIX"
# shellcheck disable=SC2086,SC2030
_collect() (
+ set +u
tee -a "$1" | while read -r line; do
set -- $line
case $line in
# Importers
# =========
-# TODO: WIP
import() {
cd "$R7_WORKDIR" || _fail "Unable to cd to '$R7_WORKDIR'"
target=$1
- etc_ssh_files_to_import='
- ssh/sshd_config
- ssh/ssh_config
- '
if test -n "$target"; then
echo >&2 "-> Importing target host: $target"
case $(ssh "$target" uname) in
FreeBSD) _FreeBSD_import ;;
NetBSD) _NetBSD_import ;;
DragonFly) _DragonFly_import ;;
+ Haiku) _Haiku_import ;;
+ QNX) _QNX_import ;;
+ Minix) _Minix_import ;;
*)
_error "Platform unsupported or host unavailable."
return 3
-a "$src" "$dst" && return 0
}
_debug "IMPORT $1 $2 USE SCP"
- scp -r "$target:$src" "$dst" && return 0
+ scp "-oConnectTimeout=$SSH_CONNECT_TIMEOUT" -qF "$SSH_CONFIG_FILE" -r "$src" "$dst" && return 0
_fail "IMPORT $1 $2 FAILED"
)
-_import_ssh_authorized_keys() {
+_import_ssh_authorized_keys_old() (
+ set +e
other_users=$(
ssh "$target" getent passwd | awk -F: '$3 >= 1000 { print $1 }' |
grep -v nobody
ssh "$target" test -f "$authorized_keys" || continue
mkdir -p "nodes/$target/ssh/"
echo >&2 "--> Importing $authorized_keys"
- #_import_copy "root@$target:$authorized_keys" "nodes/$target/ssh/authorized_keys_$user"
- scp "root@$target:$authorized_keys" "nodes/$target/ssh/authorized_keys_$user"
+ _import_copy "$target:$authorized_keys" "nodes/$target/ssh/authorized_keys_$user"
done
-}
+)
+_import_ssh_authorized_keys() (
+ set +e
+ other_users=$(
+ ssh "$target" cat /etc/passwd | awk -F: '$3 >= 1000 { print $1 }' | grep -v nobody
+ )
+ for user in root $other_users; do
+ home=$(
+ ssh "$target" cat /etc/passwd | awk -F: -v user="$user" '$1 == user { print $6 }'
+ )
+ authorized_keys="$home/.ssh/authorized_keys"
+ if ! ssh -n "$target" test -f "$authorized_keys"; then
+ continue
+ fi
+ mkdir -p "nodes/$target/ssh/"
+ echo >&2 "--> Importing $authorized_keys for user='$user'"
+ _import_copy "$target:$authorized_keys" "nodes/$target/ssh/authorized_keys_$user"
+ done
+)
+
_import_etc_if_exists() {
mkdir -p nodes/"$target"
echo >&2 "--> Importing /etc"
}
_import_etc_ssh_if_exists() {
- mkdir -p nodes/"$target"
+ etc_ssh_files_to_import='
+ ssh/sshd_config
+ ssh/ssh_config
+ '
+ mkdir -p nodes/"$target/ssh"
echo >&2 "--> Importing /etc/ssh"
for file in $etc_ssh_files_to_import; do
ssh "$target" test -f "'/etc/$file'" &&
}
_import_modprobe() {
- mkdir -p nodes/"$target"
- echo >&2 "--> Importing /etc/modprobe.d"
- for file in $etc_modprobe_files_to_import; do
- ssh "$target" test -f "'/etc/modprobe.d/$file'" &&
- _import_copy "$target:/etc/modprobe.d/$file" "nodes/$target/modprobe.d"
- done
+ if ssh "$target" test -d /etc/modprobe.d; then
+ _content=$(ssh "$target" ls -A /etc/modprobe.d/)
+ test -z "$_content" && return 0
+ echo >&2 "--> Importing /etc/modprobe.d"
+ mkdir -p nodes/"$target/modprobe.d"
+ _import_copy "$target:/etc/modprobe.d/*" "nodes/$target/modprobe.d"
+ fi
}
+_QNX_import() {
+ etc_files_to_import='
+ build.date
+ '
+ _import_etc_if_exists
+ echo >&2 "--> Importing /etc/settings"
+ mkdir -p "nodes/$target/settings"
+ _import_copy "$target:/etc/settings" "nodes/$target/settings"
+ echo >&2 "--> Importing /system/etc/ssh"
+ mkdir -p "nodes/$target/ssh"
+ _import_copy "$target:/system/etc/ssh/sshd_config" "nodes/$target/ssh"
+ _import_ssh_authorized_keys
+}
+
+_Minix_import() {
+ etc_files_to_import='
+ fstab
+ inet.conf
+ profile
+ resolv.conf
+ shells
+ rc.conf
+ '
+ _import_etc_if_exists
+ echo >&2 "--> Importing /usr/pkg/etc/ssh"
+ mkdir -p nodes/"$target/ssh"
+ _import_copy "$target:/usr/pkg/etc/ssh/sshd_config" "nodes/$target/ssh"
+ _import_copy "$target:/usr/pkg/etc/ssh/ssh_config" "nodes/$target/ssh"
+ echo >&2 "--> Importing /usr/pkg/etc/pkgin"
+ mkdir -p nodes/"$target/pkgin"
+ _import_copy "$target:/usr/pkg/etc/pkgin/repositories.conf" "nodes/$target/pkgin"
+}
+
+_Haiku_import() {
+ etc_files_to_import='
+ inputrc
+ profile
+ '
+ _import_etc_if_exists
+ _import_copy "$target:/boot/system/settings/network/hosts" "nodes/$target/"
+ _import_copy "$target:/boot/system/settings/network/resolv.conf" "nodes/$target/"
+ _import_copy "$target:/boot/system/settings/package-repositories" "nodes/$target/"
+ echo >&2 "--> Importing /boot/system/settings/ssh"
+ mkdir -p "nodes/$target/ssh"
+ _import_copy "$target:/boot/system/settings/ssh/sshd_config" "nodes/$target/ssh"
+ _import_copy "$target:/boot/system/settings/ssh/ssh_config" "nodes/$target/ssh"
+ _import_copy "$target:/boot/home/config/settings/ssh/authorized_keys" \
+ "nodes/$target/ssh/authorized_keys_user"
+}
+
_Linux_import() {
- etc_modprobe_files_to_import='
- modprobe.d/*.conf
- '
if _Linux_is_debian_based; then
_Linux_import_debian
elif _Linux_is_rhel_based; then
_Linux_import_rhel
+ elif _Linux_is_suse_based; then
+ _Linux_import_suse
elif _Linux_is_gentoo_based; then
_Linux_import_gentoo
+ elif _Linux_is_arch_based; then
+ _Linux_import_arch
+ elif _Linux_is_artix; then
+ _Linux_import_artix
elif ssh "$target" "grep -q 'ID=alpine' /etc/os-release"; then
_Linux_import_alpine
+ elif ssh "$target" "grep -q 'ID=crux' /etc/os-release"; then
+ _Linux_import_crux
+ elif ssh "$target" "grep -q 'ID=\"void\"' /etc/os-release"; then
+ _Linux_import_void
+ elif ssh "$target" "grep -q 'ID=guix' /etc/os-release"; then
+ _Linux_import_guix
else
echo >&2 "Unsupported Linux distribution."
fi
}
_Linux_is_debian_based() (
- ssh "$target" "grep -q 'ID=debian' /etc/os-release || grep -q 'ID_LIKE=.*debian' /etc/os-release || \
- grep -qiE 'Debian|Ubuntu|Linux Mint' /etc/issue || \
- test -f /etc/debian_version || test -d /etc/apt || command -v apt-get >/dev/null 2>&1"
+ ssh "$target" "grep -q 'ID=debian' /etc/os-release || \
+ grep -q 'ID_LIKE=.*debian' /etc/os-release || \
+ grep -qiE 'Debian|Ubuntu|Linux Mint' /etc/issue || \
+ test -f /etc/debian_version || test -d /etc/apt || command -v apt-get >/dev/null 2>&1" 2>/dev/null
)
_Linux_is_rhel_based() (
- ssh "$target" "grep -qE 'ID=\"?(rhel|fedora|centos|ol|scientific)\"?' /etc/os-release || \
- grep -qE 'ID_LIKE=\"?.*(rhel|fedora).*\"?' /etc/os-release || \
- grep -qiE 'Red Hat|CentOS|Fedora|Scientific Linux|Oracle Linux|openSUSE|SUSE' /etc/issue || \
- grep -qiE 'Red Hat|CentOS|Fedora|Scientific Linux|Oracle Linux|openSUSE|SUSE' /etc/redhat-release || \
- test -f /etc/redhat-release || test -f /etc/system-release || test -f /etc/centos-release || \
- test -f /etc/fedora-release || test -f /etc/oracle-release || \
- (test -f /etc/os-release && grep -qi 'rhel' /etc/os-release) || test -d /etc/yum.repos.d"
+ ssh "$target" "grep -qiE 'ID=\"?(rhel|fedora|centos|ol|scientific|rocky|eurolinux)\"?' /etc/os-release || \
+ grep -qiE 'ID_LIKE=\"?.*(rhel|fedora).*\"?' /etc/os-release || \
+ grep -qiE 'Red Hat|CentOS|Fedora|Scientific Linux|Oracle Linux' /etc/issue || \
+ test -f /etc/redhat-release || test -f /etc/system-release || test -f /etc/centos-release || \
+ test -f /etc/fedora-release || test -f /etc/oracle-release || \
+ (test -f /etc/os-release && grep -qi 'rhel' /etc/os-release) || test -d /etc/yum.repos.d" 2>/dev/null
)
_Linux_is_gentoo_based() (
ssh "$target" "test -f /etc/gentoo-release || \
- grep -q 'ID=gentoo' /etc/os-release || \
- grep -qi 'Gentoo' /etc/issue || \
- command -v emerge >/dev/null 2>&1"
+ grep -q 'ID=gentoo' /etc/os-release || \
+ grep -q 'ID=funtoo' /etc/os-release || \
+ grep -qi 'Gentoo' /etc/issue || \
+ command -v emerge >/dev/null 2>&1" 2>/dev/null
)
+_Linux_is_suse_based() (
+ ssh "$target" "test -f /etc/os-release && grep -Eqi \
+ 'suse|opensuse' /etc/os-release || \
+ command -v zypper >/dev/null || \
+ command -v yast2 >/dev/null" 2>/dev/null
+)
+
+_Linux_is_arch_based() (
+ ssh "$target" "test -f /etc/os-release && grep -Eqi \
+ 'arch|manjaro|endeavouros|arcolinux|parabola' /etc/os-release || \
+ command -v pacman >/dev/null || \
+ command -v makepkg >/dev/null" 2>/dev/null
+)
+
+_Linux_is_artix() (
+ ssh "$target" "test -f /etc/os-release && grep -Eqi \
+ 'artix|hyperbola' /etc/os-release || \
+ command -v pacman >/dev/null || \
+ command -v makepkg >/dev/null" 2>/dev/null
+)
+
_Linux_import_gentoo() {
etc_files_to_import='
crontab
nsswitch.conf
pam.conf
profile
- resolv.conf
shells
sudo.conf
sudoers
'
_import_etc_if_exists
_import_etc_ssh_if_exists
+ echo >&2 "--> Importing /etc/portage"
+ mkdir -p "nodes/$target/portage"
+ _import_copy "$target:/etc/portage/" "nodes/$target/portage/"
_import_ssh_authorized_keys
_import_modprobe
}
'
_import_etc_if_exists
_import_etc_ssh_if_exists
+ echo >&2 "--> Importing /etc/apk"
+ mkdir -p "nodes/$target/apk"
+ _import_copy "$target:/etc/apk/repositories" "nodes/$target/apk/"
_import_ssh_authorized_keys
_import_modprobe
}
'
_import_etc_if_exists
_import_etc_ssh_if_exists
+ echo >&2 "--> Importing /etc/yum.repos.d"
+ mkdir -p "nodes/$target/yum.repos.d"
+ _import_copy "$target:/etc/yum.repos.d/" "nodes/$target/yum.repos.d/"
_import_ssh_authorized_keys
_import_modprobe
}
issue
locale.gen
machine-id
- motd
nsswitch.conf
pam.conf
profile
sudoers
'
_import_etc_if_exists
+ echo >&2 "--> Importing /etc/apt"
+ mkdir -p "nodes/$target/apt"
+ _import_copy "$target:/etc/apt/sources.list" "nodes/$target/apt"
+ _import_copy "$target:/etc/apt/sources.list.d" "nodes/$target/apt"
+ echo >&2 "--> Importing /etc/network"
+ mkdir -p "nodes/$target/network/"
+ _import_copy "$target:/etc/network/interfaces" "nodes/$target/network/"
+ _import_copy "$target:/etc/network/interfaces.d" "nodes/$target/network/"
_import_etc_ssh_if_exists
_import_ssh_authorized_keys
_import_modprobe
+
}
+_Linux_import_suse() {
+ etc_files_to_import='
+ fstab
+ hosts
+ profile
+ sudo.conf
+ sudoers
+ sysctl.conf
+ environment
+ exports
+ chrony.conf
+ '
+ _import_etc_if_exists
+ _import_etc_ssh_if_exists
+ _import_ssh_authorized_keys
+ _import_modprobe
+}
+
+_Linux_import_arch() {
+ etc_files_to_import='
+ environment
+ hostname
+ profile
+ arch-release
+ issue
+ hosts
+ pacman.conf
+ sudo.conf
+ sudoers
+ fstab
+ '
+ _import_etc_if_exists
+ _import_etc_ssh_if_exists
+ _import_ssh_authorized_keys
+ _import_modprobe
+}
+
+_Linux_import_artix() {
+ _Linux_import_arch
+}
+
+_Linux_import_guix() {
+ etc_files_to_import='
+ config.scm
+ environment
+ fstab
+ hostname
+ hosts
+ issue
+ nsswitch.conf
+ profile
+ resolv.conf
+ shells
+ sudoers
+ '
+ _import_etc_if_exists
+ _import_etc_ssh_if_exists
+ _import_ssh_authorized_keys
+}
+
+_Linux_import_void() {
+ etc_files_to_import='\
+ fstab
+ dhcpcd.conf
+ environment
+ hosts
+ profile
+ rc.conf
+ nsswitch.conf
+ shells
+ sudoers
+ sudo.conf
+ sysctl.conf
+ resolv.conf
+ '
+ _import_etc_if_exists
+ _import_etc_ssh_if_exists
+ _import_ssh_authorized_keys
+ _import_modprobe
+}
+
+_Linux_import_crux() {
+ etc_files_to_import='
+ crontab
+ hosts
+ resolv.conf
+ environment
+ fstab
+ locale.gen
+ hosts
+ profile
+ rc.conf
+ rc.local
+ syslog.conf
+ sysctl.conf
+ '
+ _import_etc_if_exists
+ _import_etc_ssh_if_exists
+ _import_ssh_authorized_keys
+ _import_modprobe
+}
+
_SunOS_import() {
etc_files_to_import='
crontab
_import_ssh_authorized_keys
}
+_FreeBSD_import() {
+ etc_files_to_import='
+ crontab
+ fbtab
+ fstab
+ hostname
+ hosts
+ login.conf
+ nsswitch.conf
+ ntp.conf
+ profile
+ resolv.conf
+ shells
+ sysctl.conf
+ syslog.conf
+ '
+ _import_etc_if_exists
+ echo >&2 "--> Importing /etc/pkg"
+ _import_copy "$target:/etc/pkg" "nodes/$target/"
+ _import_etc_ssh_if_exists
+ _import_ssh_authorized_keys
+}
+
+_DragonFly_import() {
+ etc_files_to_import='
+ crontab
+ fstab
+ hosts
+ login.conf
+ pf.conf
+ resolv.conf
+ shells
+ sysctl.conf
+ syslog.conf
+ '
+ _import_etc_if_exists
+ _import_etc_ssh_if_exists
+ _import_ssh_authorized_keys
+}
+
+_NetBSD_import() {
+ etc_files_to_import='
+ fstab
+ hosts
+ locate.conf
+ pf.conf
+ resolv.conf
+ shells
+ sysctl.conf
+ syslog.conf
+ usermgmt.conf
+ wscons.conf
+ rc.local
+ '
+ _import_etc_if_exists
+ _import_etc_ssh_if_exists
+ _import_ssh_authorized_keys
+}
+
_OpenBSD_import() {
etc_files_to_import='
acme-client.conf
mygate
myname
newsyslog.conf
+ syslog.conf
ntpd.conf
pf.conf
resolv.conf
sysctl.conf
unwind.conf
usermgt.conf
+ rc.conf.local
'
- etc_mail_files_to_import='
- mail/aliases
- mail/smtpd.conf
- mail/spamd.conf
- '
etc_ssh_files_to_import='
ssh/sshd_config
ssh/ssh_config
}
_OpenBSD_import_etc_mail_if_exists() {
+ etc_mail_files_to_import='
+ mail/aliases
+ mail/smtpd.conf
+ mail/spamd.conf
+ '
mkdir -p nodes/"$target"
echo >&2 "--> Importing /etc/mail"
for file in $etc_mail_files_to_import; do
_OpenBSD_import_nsd_if_enabled() {
ssh "$target" rcctl check nsd >/dev/null && {
- echo >&2 "--> Import /var/nsd"
+ echo >&2 "--> Importing /var/nsd"
for file in $var_nsd_files; do
prefix=${file%%/*}
mkdir -p "nodes/$target/nsd/$prefix"
mkdir -p "nodes/$target/postgresql/$prefix"
_import_copy "$target:/var/postgresql/$file" "nodes/$target/postgresql/$prefix/"
done
- echo >&2 "-- Importing /etc/login.conf.d/postgresql"
+ echo >&2 "--> Importing /etc/login.conf.d/postgresql"
mkdir -p "nodes/$target/login.conf.d"
_import_copy "$target:/etc/login.conf.d/postgresql" "nodes/$target/login.conf.d/"
return 0
}
}
-_FreeBSD_import() {
- etc_files_to_import='
- crontab
- fbtab
- fstab
- hostname
- hosts
- login.conf
- nsswitch.conf
- ntp.conf
- profile
- resolv.conf
- shells
- sysctl.conf
- syslog.conf
- '
- _import_ssh_authorized_keys
- _import_etc_if_exists
- _import_etc_ssh_if_exists
-}
-
-_NetBSD_import() {
- etc_files_to_import='
- fstab
- hosts
- locate.conf
- pf.conf
- resolv.conf
- shells
- sysctl.conf
- syslog.conf
- usermgmt.conf
- wscons.conf
- '
- _import_ssh_authorized_keys
- _import_etc_if_exists
- _import_etc_ssh_if_exists
-}
-
-_DragonFly_import() {
- etc_files_to_import='
- crontab
- fstab
- hosts
- login.conf
- pf.conf
- resolv.conf
- shells
- sysctl.conf
- syslog.conf
- '
- _import_ssh_authorized_keys
- _import_etc_if_exists
- _import_etc_ssh_if_exists
-}
-
# Main
# ====
blob - 3e6d7688489b3ea53dcb1daaad648fe01cb119c3
blob + 61ca652ae438392a6480c60875b088254b303d5c
--- r7.1
+++ r7.1
'\" t
.\" Automatically generated by Pandoc 3.6.2
.\"
-.TH "R7" "1" "Tue Jun 3 2025" "v0.1.6" "User Manual"
+.TH "R7" "1" "Tue Jun 3 2025" "v0.2.0" "User Manual"
.SS Tutorial
.SS Introduction
R7 is a configuration management framework made to configure nodes with
-configuration files and related operations versionned in a central
+configuration files and related operations versioned in a central
repository.
-To remain code versionning system agnostic, manual or automated
-versionning is left to the user, via makefiles or triggered from r7
+To remain code versioning system agnostic, manual or automated
+versioning is left to the user, via makefiles or triggered from r7
\f[CR]site\-config\f[R] configuration file \f[I](See below)\f[R].
.PP
The idea is to store hosts configurations in \f[CR]nodes/hostname\f[R]
those hosts to configuration groups containing the directives to install
the configuration and potential requirements.
.PP
-\f[I]Nodes sub\-directories are hostnames understood by the ssh client
+\f[I]Nodes sub\-directories are host names understood by the ssh client
and configuration.\f[R]
.PP
-\f[I]Currently, r7 requires valid ssh configuration and keyfiles in the
+\f[I]Currently, r7 requires valid ssh configuration and key files in the
repository \f[CI].ssh/\f[I] directory.\f[R]
.PP
\f[I]Repositories can be initialized with \f[CI]rset init\f[I] or
summary
.EE
.PP
-There is an exemple of the deployment of that configuration within the
+There is an example of the deployment of that configuration within the
r7 repository:
.IP
.EX
\f[CR]\[ha]PREFIX_NAME()\f[R].
.PP
Group files names can\[cq]t contain spaces, tabs or newlines, as well
-for nodes dirnames.
-\f[I]The `:' character is not recommanded as well as it may reduce
-lisibility of the interactive output.\f[R]
+for nodes \f[CR]dirnames\f[R].
+\f[I]The `:' character is not recommended as well as it may reduce
+readability of the interactive output.\f[R]
.PP
Called groups and node directories are copied to related nodes in
\f[CR]hostname:/tmp/r7/\f[R]:
\f[CR]R7_PREFIX\f[R]) in the respective declaration order they\[cq]re
found in the related group file will be executed.
.PP
-Site confiurations are shell scripts sourced by r7 after it\[cq]s
+Site configurations are shell scripts sourced by r7 after it\[cq]s
environment is initialized, so \f[CR]prefix\f[R], \f[CR]group\f[R],
\f[CR]output\-dump\f[R], \f[CR]summary\f[R] are the functions or aliases
provided by r7 itself.
Here \f[CR]output\-dump\f[R], and \f[CR]summary\f[R] are called to
output potential errors, diffs and permissions changes at the end of the
interactive output obtained by \f[CR]r7 run\-config\f[R].
-If nothing catched happened, nothing is added to the output.
+If nothing happened, nothing is added to the output.
.SS Errors during remote execution of groups
In our previous example, we modify \f[CR]state_test\f[R] so the
\f[CR]test\f[R] fails.
\f[B]}\f[R]
.EE
.PP
-And we re\-run the configuration to see what\[cq]s happenning.
+And we re\-run the configuration to see what\[cq]s happening.
.IP
.EX
$ r7 run\-config
When they\[cq]re are detected, the captured related output is shown.
.SS Repository initialisation
Using the \f[CR]init\f[R] command, we can specify the current or a
-specifed work directory to be created and act as an r7 repository.
+specified work directory to be created and act as an r7 repository.
.PP
-\f[I]Automated versionning of outputs are currently let to the user, a
+\f[I]Automated versioning of outputs are currently let to the user, a
recommended place would be the end of the site configuration file.\f[R]
.PP
This command initializes a new directory called \f[CR]test.org\f[R]:
Adjust the SSH client configuration file in the repository
\f[CR].ssh/config\f[R]
.PP
-\f[I]Note that it is possible to import additionnal SSH configurations,
+\f[I]Note that it is possible to import additional SSH configurations,
like the user one from the SSH configuration, but it is advised to keep
them separate.\f[R]
.SS SSH agent handling
The function \f[CR]unlock\f[R] can be used to set the SSH agent
-environement, this will be required for any automated operation later
+environment, this will be required for any automated operation later
done by r7:
.IP
.EX
unlock
tmux \f[B]||\f[R] screen
.EE
-.PP
-\f[I]\f[BI]\f[B]Warning:\f[BI]\f[I] Unlock will terminate any running
-\f[CI]ssh\-agent\f[I] instances.\f[R]
+.SS Tmux configuration
+.IP
+.EX
+set \-g update\-environment \-r
+.EE
+.SS Optional Shell configuration
+This is useful for handling multiple tmux sessions.
+.IP
+.EX
+\f[I]# Add this to the shell\[aq]s rc\f[R]
+\f[B]if\f[R] [ \-z \[dq]$TMUX\[dq] ]\f[B];\f[R] \f[B]then\f[R]
+ \f[B]if\f[R] [ \-n \[dq]$SSH_TTY\[dq] ]\f[B];\f[R] \f[B]then\f[R]
+ \f[B]if\f[R] [ \-z \[dq]$SSH_AUTH_SOCK\[dq] ]\f[B];\f[R] \f[B]then\f[R]
+ export SSH_AUTH_SOCK=\[dq]$HOME/.ssh/.auth_socket\[dq]
+ \f[B]fi\f[R]
+ \f[B]if\f[R] [ ! \-S \[dq]$SSH_AUTH_SOCK\[dq] ]\f[B];\f[R] \f[B]then\f[R]
+ eval $(ssh\-agent \-a $SSH_AUTH_SOCK) >/dev/null 2>&1
+ echo $SSH_AGENT_PID >$HOME/.ssh/.auth_pid
+ \f[B]fi\f[R]
+ \f[B]if\f[R] [ \-z $SSH_AGENT_PID ]\f[B];\f[R] \f[B]then\f[R]
+ export SSH_AGENT_PID=$(cat $HOME/.ssh/.auth_pid)
+ \f[B]fi\f[R]
+ ssh\-add \[dq]$SSH_ID\[dq] 2>/dev/null
+ \f[B]fi\f[R]
+\f[B]fi\f[R]
+.EE
.SS Adding new hosts
For adding a new host, the simplest way is to have pre\-configured
\f[CR]authorized_keys\f[R] for the target user, it is then required to
Once the host is accepted in the \f[CR]known_hosts\f[R] file, it\[cq]s
possible to import it automatically.
.SS Importing hosts configurations
-\f[I]This feature currently only support OpenBSD.\f[R]
-.PP
Avoiding to import the configuration manually is possible with the
\f[CR]import\f[R] command:
.IP
Most common configuration files will be copied in a newly created
\f[CR]nodes/hostname\f[R] sub\-directory.
.SS Writing group files
-Group files collects fonctions related to the configuration of the
+Group files collects functions related to the configuration of the
operating system, networking, services, global and user configurations
packages installations and application deployments.
.PP
\f[I]\f[BI]file\f[I]: \f[CI]groups/example1\f[I]\f[R]
.PP
With the default prefix, \f[CR]install\f[R], \f[CR]state\f[R],
-\f[CR]doc\f[R], the fonction that will be executed are
+\f[CR]doc\f[R], the function that will be executed are
\f[CR]state_A\f[R] and \f[CR]doc_A\f[R].
To test that group file with all the functions inside we can call r7 the
following way:
kept by default, which is the system provided default
\f[CR]ntpd.conf\f[R].
.SS Sourcing specific files
-Here\[cq]s an example how to source additionnal shell from the deployed
+Here\[cq]s an example how to source additional shell from the deployed
node directory, or elsewhere:
.IP
.EX
.EE
.PP
\f[I]Note that the \f[CI]output\f[I] function arguments are using
-shell\[cq]s case globbing patterns.\f[R]
+shell\[cq]s case glob patterns.\f[R]
.SS Active nodes
A \f[CR]R7_WORKDIR/.active_nodes\f[R] file is automatically created when
r7 tries to connect to a list of hosts via the \f[CR]group\f[R] command
node [filename\f[B]|\f[R]dirname]
.EE
.SS nodename
-\f[B]\f[BI]Description:\f[B]\f[R] Returns the small hostname of the
+\f[B]\f[BI]Description:\f[B]\f[R] Returns the small host name of the
current host
.PP
\f[B]\f[BI]Usage:\f[B]\f[R]
.EE
.SS groupinstalldir
\f[B]\f[BI]Description:\f[B]\f[R] Change directory to the current group
-directoy then call installdir
+directory then call installdir
.PP
\f[B]\f[BI]Usage:\f[B]\f[R]
.IP
.EE
.SS nodeinstalldir
\f[B]\f[BI]Description:\f[B]\f[R] Change directory to the current group
-directoy then call installdir
+directory then call installdir
.PP
\f[B]\f[BI]Usage:\f[B]\f[R]
.IP
nodeinstalldir [\-o fileowner] [\-m filemode] [\-O dirowner] [\-O dirmode] source
destination
.EE
-.SS source
+.SS fsource
\f[B]\f[BI]Description:\f[B]\f[R] Source a POSIX shell file in the
current execution
.PP
\f[B]\f[BI]Usage:\f[B]\f[R]
.IP
.EX
-source filename
+fsource filename
.EE
.SS groupsource
\f[B]\f[BI]Description:\f[B]\f[R] Change directory to the current group
.EE
.SS ssh\-ids\-hosts
\f[B]\f[BI]Description:\f[B]\f[R] Returns SSH IDs along with matching
-keyfile and hostname
+key file and host name
.PP
\f[B]\f[BI]Usage:\f[B]\f[R]
.IP
* * * * *
.SS Technical notes
.IP \[bu] 2
-Supported shells are ksh93, oksh, yash and bash.
+Supported shells are ksh93, oksh, yash and bash
.IP \[bu] 2
-Supported platforms are OpenBSD, FreeBSD, NetBSD and GNU/Linux.
+Supported target platforms are POSIX compatible systems
+.RS 2
.IP \[bu] 2
+\f[CR]/bin/sh\f[R] or compatible must be set for the user\[cq]s shell
+(which is usually the case by default)
+.IP \[bu] 2
+\f[CR]/tmp\f[R] must be writable by the user
+.RE
+.IP \[bu] 2
+Supported control node platforms are supposed to be POSIX compatible
+systems but currently limited to BSD\[cq]s, Darwin and GNU/Linux
+.RS 2
+.IP \[bu] 2
Dependencies are awk, OpenSSH and column
.IP \[bu] 2
-Optional dependencies are openrsync, rsync, column, graphviz and pandoc.
+Optional dependencies are openrsync, rsync, column, graphviz and pandoc
+.RE
.IP \[bu] 2
-Busybox support is planned.
+The r7 importer supports the following platform:
+.RS 2
.IP \[bu] 2
-The HTML output is a work in progress.
+Alpine Linux
+.IP \[bu] 2
+Archlinux
+.IP \[bu] 2
+Crux
+.IP \[bu] 2
+Debian
+.IP \[bu] 2
+DragonFlyBSD
+.IP \[bu] 2
+FreeBSD
+.IP \[bu] 2
+Gentoo
+.IP \[bu] 2
+Guix
+.IP \[bu] 2
+Haiku
+.IP \[bu] 2
+Minix
+.IP \[bu] 2
+NetBSD
+.IP \[bu] 2
+Omnios
+.IP \[bu] 2
+OpenBSD
+.IP \[bu] 2
+OpenSUSE
+.IP \[bu] 2
+QNX
+.IP \[bu] 2
+Rocky Linux
+.IP \[bu] 2
+Salix
+.IP \[bu] 2
+Void Linux
+.RE
.PP
* * * * *
.SS License
-The provided group library is shared as additionnal examples WITH NO
+The provided group library is shared as additional examples WITH NO
WARRANTIES of the documentation and contain the following third\-party
files under the ISC License.
Copyright information are indicated in the LICENSE section of related