Blob


1 ## Tutorial
3 ### Introduction
5 R7 is a configuration management framework made to configure nodes with
6 configuration files and related operations versioned in a central repository.
7 To remain code versioning system agnostic, manual or automated versioning is
8 left to the user, via makefiles or triggered from r7 `site-config` configuration
9 file _(See below)_.
11 The idea is to store hosts configurations in `nodes/hostname` directories that
12 maps each host's `/etc` and to assign those hosts to configuration groups
13 containing the directives to install the configuration and potential
14 requirements.
16 _Nodes sub-directories are host names understood by the ssh client and
17 configuration._
19 _Currently, r7 requires valid ssh configuration and key files in the repository
20 `.ssh/` directory._
22 _Repositories can be initialized with `rset init` or `rset -w
23 path/to/new-repository init`, the user will then have to provide valid
24 configurations and keys for `.ssh/` in the newly created directory._
26 _See [Technical Notes](#technical-notes) for dependencies and supported
27 platforms._
29 There is an example of r7 repository:
31 ./nodes/
32 ./nodes/hostA
33 ./nodes/hostB
34 ./nodes/hostC
35 ./groups/
36 ./groups/common
37 ./groups/test0
38 ./groups/common.dir
39 ./groups/test0.dir
40 ./.ssh/
41 ./.ssh/config
42 ./.ssh/id_ed25519_r7
43 ./.ssh/id_ed25519_r7.pub
44 ./site-config
46 There is an example of r7 site configuration (`site-config` file):
48 ```sh
49 prefix install state doc
50 group common '.*'
51 group test0 hostB hostC
52 output-dump
53 summary
54 ```
56 There is an example of the deployment of that configuration within the r7
57 repository:
59 ```
60 $ r7 run-config
61 - (ok) hostA:common::install_nothing
62 - (ok) hostA:common::state_uname
63 - (ok) hostA:common::doc_tutorial
64 - (ok) hostB:common::install_nothing
65 - (ok) hostB:common::state_uname
66 - (ok) hostB:common::doc_tutorial
67 - (ok) hostC:common::install_nothing
68 - (ok) hostC:common::state_uname
69 - (ok) hostC:common::doc_tutorial
70 - (ok) hostB:test0::state_test
71 - (ok) hostC:test0::state_test
72 ```
74 In this example, everything goes fine, groups are executed on each related
75 nodes, note the `'.*'` matching all hosts present in `./nodes`. Groups are POSIX
76 shell scripts that are a collection of functions.
78 There is the `common` group:
80 ```sh
81 install_nothing() {
82 echo Nothing installed
83 }
85 state_uname() {
86 uname -a
87 }
89 doc_tutorial() {
90 echo "## Welcome to the R7 tutorial!"
91 }
92 ```
94 And there is the `test0` group:
96 ```sh
97 state_test() {
98 test 1 -eq 1
99 }
100 ```
102 Any function managed by `r7` needs to be declared in the format `^PREFIX_NAME()`.
104 Group files names can't contain spaces, tabs or newlines, as well for nodes
105 `dirnames`. _The ':' character is not recommended as well as it may reduce
106 readability of the interactive output._
108 Called groups and node directories are copied to related nodes in `hostname:/tmp/r7/`:
110 /tmp/r7/hostA/ # Contents of test.org/nodes/hostA/
111 /tmp/r7/common.dir # Contents of test.org/groups/common.dir/
112 /tmp/r7/test.dir # Contents of test.org/groups/test.dir
114 Groups may have no `.dir` directory, in this case, nothing is copied.
116 Once the group copy is done, functions are executed in the order of the defined
117 prefix (part of the `site-config` file shown before):
119 prefix install state doc
121 This means the functions matching `^install.*()`, `^state.*()` and `^doc.*()`
122 (the default `R7_PREFIX`) in the respective declaration order they're found in the
123 related group file will be executed.
125 Site configurations are shell scripts sourced by r7 after it's environment is
126 initialized, so `prefix`, `group`, `output-dump`, `summary` are the functions or
127 aliases provided by r7 itself. This allow for scripting from the `site-config`
128 file. Here `output-dump`, and `summary` are called to output potential errors,
129 diffs and permissions changes at the end of the interactive output obtained by
130 `r7 run-config`. If nothing happened, nothing is added to the output.
132 ### Errors during remote execution of groups
134 In our previous example, we modify `state_test` so the `test` fails.
136 ```sh
137 state_test() {
138 test 1 -eq 2
140 ```
142 And we re-run the configuration to see what's happening.
144 ```
145 $ r7 run-config
146 - (ok) hostA:common::install_nothing
147 - (ok) hostA:common::state_uname
148 - (ok) hostA:common::doc_tutorial
149 - (ok) hostB:common::install_nothing
150 - (ok) hostB:common::state_uname
151 - (ok) hostB:common::doc_tutorial
152 - (ok) hostC:common::install_nothing
153 - (ok) hostC:common::state_uname
154 - (ok) hostC:common::doc_tutorial
155 - (error 1) hostB:test0::state_test
156 - (error 1) hostC:test0::state_test
157 - (error 1) - in hostB test0 state_test (1748622980)
158 - (error 1) - in hostC test0 state_test (1748622980)
159 ```
162 The last two lines are part of the `summary` output.
164 Let's modify the `state_test` function again to add some verbosity to it's
165 output.
167 _Note that we also change the return value._
169 ```sh
170 state_test() {
171 echo something
172 false || {
173 echo >&2 failed
174 return 22
177 ```
179 This will produce the following summary:
181 ```
182 - (error 22) - in hostB test0 state_test (1748622980)
184 something
185 failed
187 - (error 22) - in hostC test0 state_test (1748622980)
189 something
190 failed
191 ```
193 Diffs and permissions changes are also displayed by the `summary` command. When
194 they're are detected, the captured related output is shown.
196 ### Repository initialisation
198 Using the `init` command, we can specify the current or a specified
199 work directory to be created and act as an r7 repository.
201 _Automated versioning of outputs are currently let to the user, a recommended
202 place would be the end of the site configuration file._
204 This command initializes a new directory called `test.org`:
206 ```sh
207 r7 -w test.org init
208 cd test.org
209 ```
211 Once this step is done, it is required to:
213 - Copy or initialize the ssh key to the `.ssh` folder in the repository created
214 in `.ssh/id_ed25519-r7` and `./ssh/id_ed25519-r7.pub`
216 - Adjust the SSH client configuration file in the repository `.ssh/config`
218 _Note that it is possible to import additional SSH configurations, like the user
219 one from the SSH configuration, but it is advised to keep them separate._
221 ### SSH agent handling
223 The function `unlock` can be used to set the SSH agent environment, this will
224 be required for any automated operation later done by r7:
226 ```sh
227 cd test.org
228 . $(command -v r7) # Sourcing r7
229 unlock
230 tmux || screen
231 ```
234 #### Tmux configuration
236 ```
237 set -g update-environment -r
238 ```
240 #### Optional Shell configuration
242 This is useful for handling multiple tmux sessions.
244 ```sh
245 # Add this to the shell's rc
246 if [ -z "$TMUX" ]; then
247 if [ -n "$SSH_TTY" ]; then
248 if [ -z "$SSH_AUTH_SOCK" ]; then
249 export SSH_AUTH_SOCK="$HOME/.ssh/.auth_socket"
250 fi
251 if [ ! -S "$SSH_AUTH_SOCK" ]; then
252 eval $(ssh-agent -a $SSH_AUTH_SOCK) >/dev/null 2>&1
253 echo $SSH_AGENT_PID >$HOME/.ssh/.auth_pid
254 fi
255 if [ -z $SSH_AGENT_PID ]; then
256 export SSH_AGENT_PID=$(cat $HOME/.ssh/.auth_pid)
257 fi
258 ssh-add "$SSH_ID" 2>/dev/null
259 fi
260 fi
261 ```
264 ### Adding new hosts
266 For adding a new host, the simplest way is to have pre-configured
267 `authorized_keys` for the target user, it is then required to add it to the
268 `known_hosts` file. For that, it is possible to use r7 SSH functions:
270 ```sh
271 . $(command -v r7) # Sourcing r7
272 ssh-accept-new hostname
274 ```
276 If resetting the target's user `authorized_keys` file is needed, the following
277 function can be used:
279 ```sh
280 . $(command -v r7) # Sourcing r7
281 ssh-authorized-keys-reset hostname
282 ```
284 _**Warning:** This will resets the SSH authorized_keys file for the target user
285 (root, by default) and put the `.ssh/id_ed25519-r7.pub` in place._
288 Once the host is accepted in the `known_hosts` file, it's possible to import it
289 automatically.
291 ### Importing hosts configurations
293 Avoiding to import the configuration manually is possible with the `import`
294 command:
296 ```sh
297 r7 import hostname
298 ```
300 Most common configuration files will be copied in a newly created
301 `nodes/hostname` sub-directory.
303 ### Writing group files
305 Group files collects functions related to the configuration of the operating
306 system, networking, services, global and user configurations packages
307 installations and application deployments.
309 By specifying the execution prefix, the user determines the order of execution
310 of the functions declared in the group file.
312 ```sh
313 service_A() {
314 service A enable
315 service A restart
318 service_B() {
319 service B enable
320 service B restart
323 state_A() {
324 service A status
327 doc_A() {
328 echo "## Service A"
329 echo
330 echo "- [url](http://test.org/)"
331 echo
333 ```
335 _**file**: `groups/example1`_
337 With the default prefix, `install`, `state`, `doc`, the function that will be
338 executed are `state_A` and `doc_A`. To test that group file with all the
339 functions inside we can call r7 the following way:
341 ```sh
342 r7 -P 'service state doc' group example1 hostname
343 ```
345 Or using the `-a` flag which will create a prefix automatically with all
346 functions present in the group file:
348 ```sh
349 r7 -a group example1 hostname
350 ```
352 In a real situation, this example will have failing functions because the
353 `service` command may not be found or the services named `A` or `B` does not
354 exist.
356 ```
357 ! (error 127) tools0:example1::service_A
358 ! (error 127) tools0:example1::service_B
359 ! (error 127) tools0:example1::state_A
360 - (ok) tools0:example1::doc_A
361 ```
363 We could force the group execution to stop using a combination of the `-e` flag
364 and the `error` group function.
366 ```sh
367 service_A() {
368 service A enable &&
369 service A restart ||
370 error unable to setup service A
373 service_B() {
374 service B enable &&
375 service B restart ||
376 error unable to setup service B
379 state_A() {
380 service A status
383 doc_A() {
384 echo "## Service A"
385 echo
386 echo "- [url](http://test.org/)"
387 echo
389 ```
391 _**file:** `groups/example2`_
393 Let's run the updated example with the `-s` flag to trigger the summary output.
395 ```sh
396 rm -fr _output
397 r7 -sea group example2 hostname
398 ```
400 This will produce something like the following:
402 ```
403 ! (error) tools0:example2::service_A
404 ! (exit) tools0:example2::service_A
405 - (error 127) - in tools0 example2 service_A (1748791986)
407 /bin/sh: <stdin>[155]: service: not found
408 :: 1748791986 tools0 ERROR unable to setup service A
410 ```
412 ### Cleaning functions
414 To remove a function from a group, we need to ensure that this function returned
415 0 for the last execution.
417 ```sh
418 state_function_to_remove() {
419 # old code
420 # not used anymore
423 ```
425 This would prevent for seeing potential past errors caused by this function in
426 the summary output.
428 ### Using the r7 install functions
430 The group library comes with the following functions that will allow
431 installation of files and triggering actions if necessary: `install`,
432 `groupinstall`, `nodeinstall`. They are all shortcuts to an internal
433 `r7_install` function, it's just the wrappers changes directory to respectively
434 `/tmp/r7`, `/tmp/r7/groupname.dir/` and `/tmp/r7/hostname/`.
436 If we want to install files from the group directory we will use something like:
439 ```sh
440 install_program() {
441 groupinstall -m 755 -o root:bin my_program /usr/local/bin
443 ```
445 _We are supposing to have the file `groups/example3.dir/my_program`_
447 And if it's something from node, we should use:
449 ```sh
450 install_program_config() {
451 nodeinstall -m 644 -o root:wheel my_config /etc
453 ```
455 We can now chain the `install` functions to configuration checking and
456 initialization of programs, services or network features like in the following
457 example, in which we install `ntp.conf` from the deployed node directory to
458 `/etc`:
460 ```sh
461 service_ntpd() {
462 nodeinstall -m 644 -o root:wheel ntpd.conf /etc &&
463 ntpd -n &&
464 rcctl enable ntpd &&
465 rcctl restart ntpd
467 ```
469 ### Using the r7 node function
471 We may want to avoid executing a function or parts of it if the node has no
472 related files before executing the installation and actions handling parts. This
473 can be done with the help of the `node` function.
475 ```sh
476 service_ntpd() {
477 node ntpd.conf &&
478 nodeinstall -m 644 -o root:wheel ntpd.conf /etc &&
479 ntpd -n &&
480 rcctl enable ntpd &&
481 rcctl restart ntpd
483 ```
485 Here, `node` will return `31` if there is no file or directory called
486 `ntpd.conf` inside the deployed node directory (`/tmp/r7/hostname`).
488 `0`, `30` and `31` exit codes are ignored when r7 will search for execution
489 errors. This means `30` and `31` exit code are reserved to r7.
491 In other terms, this will update the NTP daemon configuration only if
492 `ntpd.conf` is present in the node directory, otherwise it is kept by default,
493 which is the system provided default `ntpd.conf`.
495 ### Sourcing specific files
497 Here's an example how to source additional shell from the deployed node
498 directory, or elsewhere:
500 ```sh
501 service_sysrc() {
502 sysrc dumpdev=NO
503 sysrc kld_list="vmm if_tuntap if_bridge nmdm"
504 sysrc microcode_update_enable=YES
505 sysrc mountd_enable=YES
506 sysrc nfs_server_enable=YES
507 sysrc ntpdate_enable=YES
508 sysrc powerd_enable=YES
509 sysrc rcshutdown_timeout=900
510 sysrc rpcbind_enable=YES
511 sysrc sshd_enable=YES
512 sysrc zfs_enable=YES
513 nodesource sysrc.local
516 ```
518 In this FreeBSD example, we configure the system RC globally with
519 `service_sysrc` which apply, if `sysrc.local` is found in the root of the node
520 directory, it's sourcing in the current scope via the help of `nodesource
521 sysrc.local`.
523 The file `nodes/hostname/sysrcl.local` contains the following:
525 ```sh
526 sysrc ifconfig_igb0=DHCP
527 sysrc ifconfig_igb1=up
528 ```
530 ### Other examples
532 Inside the r7 release, a small example groups library can be found in the
533 `groups` directory, that can also be browsed in the
534 [repository](https://got.inda.re/?action=summary&path=r7.git).
536 #### System shell profile
538 Here we install the `profile` file provided in the `groupname.dir` directory or
539 the profile provided by the node directory:
541 ```sh
542 setup_profile() {
543 groupinstall -m 644 -o root:wheel profile /etc
544 node profile &&
545 nodeinstall -m 644 -o root:wheel profile /etc
547 ```
549 #### Users
551 Here we add new users:
553 ```sh
554 setup_users() {
555 useradd user1 2>/dev/null || :
556 useradd user2 2>/dev/null || :
558 ```
560 #### Crontab
562 In the following example, we install a script and call it from a dedicated user crontab.
564 ```sh
565 mail_admins=admins@test.org
567 install_myscript() {
568 groupinstall -o root:bin -m 755 myscript /usr/local/bin &&
569 useradd -d /var/empty -s /sbin/nologin _myscript
570 crontab -u _myscript - <<-/
571 MAILTO=$mail_admins
572 */5 * * * * myscript
575 ```
577 ### Consulting the output
579 After the execution is done, the result are saved in the `_run` directory,
580 `output-dump` needs to be called to produce the current `_output` structure.
582 The r7 `output` command can then be used to show specific output groups or functions:
584 ```sh
585 r7 output
586 ```
588 Will show the whole output of the latest groups deployments.
590 This format can be used to match specific host, group or function:
592 ```sh
593 r7 output [hostname [groupname [funcname]]]
594 ```
596 For example:
598 ```sh
599 $ r7 output tools0 OpenBSD state_packages\*
600 - tools0 OpenBSD state_packages_upgrades
602 quirks-7.103 signed on 2025-05-30T01:12:03Z
604 - tools0 OpenBSD state_packages_repository
606 https://cdn.openbsd.org/pub/OpenBSD
607 ```
609 _Note that the `output` function arguments are using shell's case glob patterns._
611 ### Active nodes
613 A `R7_WORKDIR/.active_nodes` file is automatically created when r7 tries to
614 connect to a list of hosts via the `group` command or function. This serves as a
615 cache of available hosts reachable via SSH login (the username is specified in
616 the SSH configuration file).
618 To add a previously non-available host, simply remove the file and use `group`
619 (here via `run-config`):
621 ```sh
622 rm .active_nodes
623 r7 run-config
624 ```
626 ## r7 command line
628 ***Usage:***
629 ```sh
630 r7 [options] [command [arguments...]]
631 ```
633 ### Options
635 - **-h**
636 Show usage and exit
638 - **-d**
639 Enable debug mode
641 - **-i**
642 Specify the SSH identity file
644 - **-F**
645 Specify the SSH client configuration file
647 - **-w**
648 Set the work directory where `./nodes` and `./groups` can be found
650 - **-r**
651 Set the run directory (default: `./_run`)
653 - **-o**
654 Set the output directory (default: `./_output`)
656 - **-c**
657 Specify the site configuration file (default: `./site-config`)
659 - **-n**
660 Enable dry run mode; prevents any modification on hosts
662 - **-e**
663 Exit the group execution on the error function
665 - **-p**
666 Run each host in parallel per group call
668 - **-O**
669 Show output interactively
671 - **-P**
672 Specify a prefix, can contain whole function names
674 - **-a**
675 Select all available prefixes for a group command
677 - **-s**
678 Apply output-dump and summary after a group command
680 ### Commands
682 | Name | Description |
683 | ---- | ----------- |
684 | **run-config** | Run the site configuration |
685 | **group** | Deploy specified group to hosts |
686 | **output-dump** | Dump the run directory to the output directory |
687 | **output** | Consult the output |
688 | **summary** | Produce a summary of errors and changes |
689 | **digraph-host** | Produce a dot digraph for hosts |
690 | **digraph-ssh** | Produce a dot digraph of SSH ID's, users and nodes relations |
691 | **import** | Import TARGET host in the current nodes directory |
692 | **info** | Default command showing active nodes and summary |
693 | **init** | Initialize a new work directory |
695 ## Environment
697 | Name | Default value | Description |
698 | ---- | ------------- | ------------|
699 | R7_DEBUG | no | Enable debug mode |
700 | R7_DRYRUN | no | Enable dry-run mode |
701 | R7_GROUP_ALLPREFIX | no | Group selects all available prefix |
702 | R7_GROUP_SUMMARY | no | Enable output-dump and summary after group execution |
703 | R7_GROUP_EXITONERROR | no | Enable exit on error function |
704 | R7_PARALLEL | no | Enable group nodes parallel execution |
705 | R7_PREFIX | install state doc | Set the r7 group execution prefix |
706 | R7_SHOWOUTPUT | no | Show interactive output |
707 | R7_WORKDIR | PWD | Set the r7 repository path |
708 | R7_SITE_CONFIG | R7_WORKDIR/site-config | Set the r7 `site-config` path |
709 | R7_OUTPUTDIR | R7_WORKDIR/_output | Set the r7 output directory path |
710 | SSH_CONFIG_DIR | R7_WORKDIR/.ssh | Set the SSH configuration directory path |
711 | SSH_CONFIG_FILE | R7_WORKDIR/.ssh/config | Set the SSH configuration file path |
712 | SSH_CONTROL_DIR | SSH_CONFIG_DIR/control | Set the SSH control dir path |
713 | SSH_IDENTITY_FILE | R7_WORKDIR/.ssh/id_ed25519_r7 | Set the SSH identity file |
714 | SSH_KNOWN_HOSTS | R7_WORKDIR/.ssh/known_hosts | Set the SSH known hosts file |
715 | SSH_CONNECT_TIMEOUT | 3 | Set the SSH connect timeout |
718 ## Group variables
720 Those variables are available during the execution of th group file's functions.
722 | Name | Description |
723 | ---- | ----------- |
724 | trace_id | Current run trace ID |
725 | groupname | Current group name being executed |
726 | exitonerror | Cause the error function to exit if equals `yes` |
727 | nodename | Contains the output of `nodename` |
728 | nodedir | Contains the output of `nodedir` |
729 | groupdir | Contains the output of `groupdir` |
732 ## Group functions
734 Those functions are accessible during the execution of the group file's functions.
735 Non documented functions are reserved for internal use.
737 1. [trace](#trace)
738 2. [error](#error)
739 3. [node](#node)
740 4. [nodename](#nodename)
741 5. [nodedir](#nodedir)
742 6. [groupdir](#groupdir)
743 7. [install](#install)
744 8. [groupinstall](#groupinstall)
745 9. [nodeinstall](#nodeinstall)
746 10. [installdir](#installdir)
747 11. [groupinstalldir](#groupinstalldir)
748 12. [nodeinstalldir](#nodeinstalldir)
749 13. [source](#source)
750 14. [groupsource](#groupsource)
751 15. [nodesource](#groupsource)
752 16. [template](#template)
753 17. [grouptemplate](#grouptemplate)
754 18. [nodetemplate](#nodetemplate)
756 ---
758 ### trace
760 ***Description:***
761 Append a trace containing the current node name and `trace_id`
763 **Usage:**
764 ```sh
765 trace [string...]
766 ```
768 ### error
770 ***Description:***
771 Trace an error message that will inform the user of an event in the summary
772 output, exit the group execution if `-e` is set
774 **Usage:**
775 ```sh
776 error [string...]
777 ```
779 ### node
781 ***Description:***
782 Returns true if the argument is an existing file or directory inside `/tmp/r7/$(nodename)`, else, returns 31
784 ***Usage:***
785 ```sh
786 node [filename|dirname]
787 ```
789 ### nodename
791 ***Description:***
792 Returns the small host name of the current host
794 ***Usage:***
795 ```sh
796 nodename
797 ```
799 ### nodedir
801 ***Description:***
802 Returns `/tmp/r7/$(nodename)`
804 ***Usage:***
805 ```sh
806 nodename
807 ```
809 ### groupdir
811 ***Description:***
812 Returns `/tmp/r7/$groupname.dir`
814 ***Usage:***
815 ```sh
816 groupdir
817 ```
819 ### install
821 ***Description:***
822 Change directory to `/tmp/r7` and install files if changed and sets mode and
823 owner, returns true if the file changed, otherwise returns 30
825 ***Usage:***
826 ```sh
827 install [-o owner] [-m mode] source destintaion
828 ```
830 ### groupinstall
832 ***Description:***
833 Change directory to the current group `.dir` directory in `/tmp/r7` then
834 performs like `install`
836 ***Usage:***
837 ```sh
838 groupinstall [-o owner] [-m mode] source destintaion
839 ```
841 ### nodeinstall
843 ***Description:***
844 Change directory to the current node directory in `/tmp/r7` then
845 performs like `install`
847 ***Usage:***
848 ```sh
849 nodeinstall [-o owner] [-m mode] source destintaion
850 ```
852 ### installdir
854 ***Description:***
855 Install directory calling `install` for each file and checking for permissions
856 changes.
858 ***Usage:***
859 ```sh
860 installdir [-o fileowner] [-m filemode] [-O dirowner] [-O dirmode] source
861 destination
862 ```
864 ### groupinstalldir
866 ***Description:***
867 Change directory to the current group directory then call installdir
869 ***Usage:***
870 ```sh
871 groupinstalldir [-o fileowner] [-m filemode] [-O dirowner] [-O dirmode] source
872 destination
873 ```
875 ### nodeinstalldir
877 ***Description:***
878 Change directory to the current group directory then call installdir
880 ***Usage:***
881 ```sh
882 nodeinstalldir [-o fileowner] [-m filemode] [-O dirowner] [-O dirmode] source
883 destination
884 ```
886 ### fsource
888 ***Description:***
889 Source a POSIX shell file in the current execution
891 ***Usage:***
893 ```sh
894 fsource filename
895 ```
897 ### groupsource
899 ***Description:***
900 Change directory to the current group directory then call fsource with the file
901 name as argument, produces an error if filename is not found from the group
902 directory
904 ***Usage:***
905 ```sh
906 groupsource filename
907 ```
909 ### nodesource
911 ***Description:***
912 Change directory to the current group directory then call node and fsource with the file
913 name as argument without producing an error if the filename is not found
915 ***Usage:***
916 ```sh
917 nodesource filename
918 ```
920 ### template
922 ***Description:***
923 Template the files passed as arguments with the current environment or by
924 sourcing a specified file
926 ***Usage:***
927 ```sh
928 template [-s sourcefile] [file...]
929 ```
931 ### grouptemplate
933 ***Description:***
934 Change directory to the current group directory before calling template
936 ***Usage:***
937 ```sh
938 grouptemplate [-s sourcefile] [file...]
939 ```
941 ### nodetemplate
943 ***Description:***
944 Change directory to the current node directory before calling template
946 ***Usage:***
947 ```sh
948 nodetemplate [-s sourcefile] [file...]
949 ```
951 # r7 library
953 Usable from the r7 `site-config` file or sourced in the current shell using:
955 ```sh
956 . $(command -v r7)
957 ```
959 Each functions are declared with underscore names and aliased with dashes.
960 Shorter aliases are also available, list all declared aliases with:
962 ```sh
963 alias
964 ```
966 Non documented functions are reserved for internal use.
968 ## Interface
970 1. [info](#info)
971 2. [usage](#usage)
973 ---
975 ### info
977 ***Description:***
978 Default command showing active nodes and summary, ran when sourced
980 ***Usage:***
981 ```sh
982 info
983 ```
985 ### usage
987 ***Description:***
988 Shows the command line help
990 ***Usage:***
991 ```sh
992 usage
993 ```
995 ## SSH functions
997 1. [unlock](#unlock)
998 2. [copy](#copy)
999 3. [ssh](#ssh)
1000 4. [ssh-debug](#ssh-debug)
1001 5. [ssh-known-hosts](#ssh-known-hosts)
1002 6. [ssh-authorized-keys-reset](#ssh-authorized-keys-reset)
1003 7. [ssh-accept-new](#ssh-accept-new)
1004 8. [ssh-control-master-clean](#ssh-control-master-clean)
1005 9. [ssh-users](#ssh-users)
1006 10. [ssh-ids](#ssh-ids)
1007 11. [ssh-authorized-keys](#ssh-authorized-keys)
1008 12. [ssh-ids-hosts](#ssh-ids-hosts)
1010 ---
1012 ### unlock
1014 ***Description:***
1015 Resets the SSH agent environment and issues ssh-add for SSH_IDENTITY_FILE
1017 ***Usage:***
1018 ```sh
1019 unlock
1020 ```
1022 ### copy
1024 ***Description:***
1025 r7 openrsync, rsync, scp wrapper; selected in order of availability
1027 ***Usage:***
1028 ```sh
1029 copy SRC DST
1030 ```
1032 ### ssh
1034 ***Description:***
1035 r7 SSH wrapper; behaves like the standard OpenSSH command
1037 ***Usage:***
1038 ```sh
1039 ssh OPTION HOST
1040 ```
1042 ### ssh-debug
1044 ***Description:***
1045 r7 SSH with debug connection mode for a specific HOST
1047 ***Usage:***
1048 ```sh
1049 ssh-debug HOST
1050 ```
1052 ### ssh-known-hosts
1054 ***Description:***
1055 Calls ssh-keygen to dump the SSH known_hosts file
1057 ***Usage:***
1058 ```sh
1059 ssh-known-hosts
1060 ```
1062 ### ssh-authorized-keys-reset
1064 ***Description:***
1065 Resets SSH authorized_keys on the specified HOST
1067 ***Usage:***
1068 ```sh
1069 ssh-authorized-keys-reset HOST
1070 ```
1072 ### ssh-accept-new
1074 ***Description:***
1075 Adds a new host entry in the SSH known_hosts file
1077 ***Usage:***
1078 ```sh
1079 ssh-accept-new HOST
1080 ```
1082 ### ssh-control-master-clean
1084 ***Description:***
1085 Cleans the SSH control master directory
1087 ***Usage:***
1088 ```sh
1089 ssh-control-master-clean
1090 ```
1092 ### ssh-users
1094 ***Description:***
1095 Searches nodes for authorized_keys_* and returns a list of users
1097 ***Usage:***
1098 ```sh
1099 ssh-users
1100 ```
1102 ### ssh-ids
1104 ***Description:***
1105 Returns sorted SSH IDs
1107 ***Usage:***
1108 ```sh
1109 ssh-ids
1110 ```
1112 ### ssh-authorized-keys
1114 ***Description:***
1115 Returns the list of authorized_keys from nodes
1117 ***Usage:***
1118 ```sh
1119 ssh-authorized-keys
1120 ```
1122 ### ssh-ids-hosts
1124 ***Description:***
1125 Returns SSH IDs along with matching key file and host name
1127 ***Usage:***
1128 ```sh
1129 ssh-ids-hosts
1130 ```
1132 ## Deployment functions
1134 1. [nodes](#nodes)
1135 2. [nodes-active](#nodes-active)
1136 3. [run-config](#run-config)
1137 4. [members](#members)
1138 5. [group](#group)
1139 6. [group-functions](#group-functions)
1140 7. [group-functions-all](#group-functions-all)
1141 8. [prefix](#prefix)
1143 ---
1145 ### nodes
1147 ***Description:***
1148 Returns a list of available nodes
1150 ***Usage:***
1151 ```sh
1152 nodes
1153 ```
1155 ### nodes-active
1157 ***Description:***
1158 Returns a list of active nodes by detecting SSH availability (a login is done), writes
1159 `R7_WORKDIR/.active_nodes` containing the available hosts
1161 ***Usage:***
1162 ```sh
1163 nodes-active
1164 ```
1166 ### run-config
1168 ***Description:***
1169 Executes `R7_SITE_CONFIG` in the loaded environment
1171 ***Usage:***
1172 ```sh
1173 run-config
1174 ```
1176 ### members
1178 ***Description:***
1179 Returns a list of active nodes matching a list of grep REGEXES
1181 ***Usage:***
1182 ```sh
1183 members REGEXES
1184 ```
1186 ### group
1188 ***Description:***
1189 Applies GROUPNAME functions (in prefix order) to the provided MEMBERS list
1191 ***Usage:***
1192 ```sh
1193 group GROUPNAME MEMBERS
1194 ```
1196 ### group-functions
1198 ***Description:***
1199 Returns a list of functions found in the specified GROUPNAME
1201 ***Usage:***
1202 ```sh
1203 group-functions GROUPNAME
1204 ```
1206 ### group-functions-all
1208 ***Description:***
1209 Returns a list of all group functions found in the current `R7_WORKDIR/groups`
1210 directory with the `group_name::function_name` format
1212 ***Usage:***
1214 ```sh
1215 group-functions-all
1216 ```
1219 ### prefix
1221 ***Description:***
1222 Sets the current PREFIX for matching function names, can match for the whole
1223 unique name in the group, for executing one specified function only
1225 ***Usage:***
1226 ```sh
1227 prefix PREFIX
1228 ```
1230 ## Text output functions
1232 1. [output-dump](#output-dump)
1233 2. [output-latest](#output-latest)
1234 3. [output-status](#output-status)
1235 4. [output-duration](#output-duration)
1236 5. [output](#output)
1237 6. [output-diffs](#output-diffs)
1238 7. [output-permissions](#output-permissions)
1239 8. [output-errors](#output-errors)
1240 9. [summary](#summary)
1241 10. [trace-id-last](#trace-id-last)
1243 ---
1245 ### output-dump
1247 ***Description:***
1248 Dumps R7_RUNDIR to R7_OUTPUTDIR
1250 ***Usage:***
1251 ```sh
1252 output-dump
1253 ```
1255 ### output-latest
1257 ***Description:***
1258 Returns a list of outputs from the latest run
1260 ***Usage:***
1261 ```sh
1262 output-latest
1263 ```
1265 ### output-status
1267 ***Description:***
1268 Returns a list of current dumped functions exit status codes
1270 ***Usage:***
1271 ```sh
1272 output-status
1273 ```
1275 ### output-duration
1277 ***Description:***
1278 Returns a list of durations of executed groups
1280 ***Usage:***
1281 ```sh
1282 output-duration
1283 ```
1285 ### output
1287 ***Description:***
1288 Shows the dumped output matching HOST, GROUPNAME, and FUNCTION (or any if unspecified)
1290 ***Usage:***
1291 ```sh
1292 output HOST GROUPNAME FUNCTION
1293 ```
1295 ### trace-id-last
1297 ***Description:***
1298 Returns the latest execution trace_id
1300 ***Usage:***
1301 ```sh
1302 trace-id-last
1303 ```
1305 ### output-diffs
1307 ***Description:***
1308 Returns the diffs from the latest execution
1310 ***Usage:***
1311 ```sh
1312 output-diffs
1313 ```
1315 ### output-permissions
1317 ***Description:***
1318 Returns the latest permission changes
1320 ***Usage:***
1321 ```sh
1322 output-permissions
1323 ```
1325 ### output-errors
1327 ***Description:***
1328 Returns the latest errors detected
1330 ***Usage:***
1331 ```sh
1332 output-errors
1333 ```
1335 ### summary
1337 ***Description:***
1338 Produces a summary of errors, diffs, and permission outputs
1340 ***Usage:***
1341 ```sh
1342 summary
1343 ```
1345 ## Digraph output
1347 1. [digraph-host](#digraph-host)
1348 2. [digraph-ssh-id-hosts](#digraph-ssh-id-hosts)
1350 ---
1352 ### digraph-host
1354 ***Description:***
1355 Returns a directed graph (in DOT format) showing relations among groups, functions, and nodes
1357 ***Usage:***
1358 ```sh
1359 digraph-host
1360 ```
1362 ### digraph-ssh-id-hosts
1364 ***Description:***
1365 Returns a directed graph (in DOT format) of relations between SSH IDs and hosts
1367 ***Usage:***
1368 ```sh
1369 digraph-ssh-id-hosts
1370 ```
1372 ## HTML output
1374 1. [html](#html)
1376 ### html
1378 ***Description:***
1379 Retunrs a report page with the content of `README.md` in HTML format
1381 ***Usage:***
1382 ```sh
1383 html
1384 ```
1386 ---
1388 ## Node importing
1390 1. [import](#import)
1392 ### import
1394 ***Description:***
1395 Import configuration files from a target host
1397 ***Usage:***
1398 ```sh
1399 import HOST
1400 ```
1402 ---
1404 ## Technical notes
1406 - Supported shells are ksh93, oksh, yash and bash
1407 - Supported target platforms are POSIX compatible systems
1408 - `/bin/sh` or compatible must be set for the user's shell (which is
1409 usually the case by default)
1410 - `/tmp` must be writable by the user
1411 - Supported control node platforms are supposed to be POSIX compatible systems
1412 but currently limited to BSD's, Darwin and GNU/Linux
1413 - Dependencies are awk, OpenSSH and column
1414 - Optional dependencies are openrsync, rsync, column, graphviz and pandoc
1415 - The r7 importer supports the following platforms:
1416 - Alpine Linux
1417 - Archlinux
1418 - Crux
1419 - Debian
1420 - DragonFlyBSD
1421 - FreeBSD
1422 - Gentoo
1423 - Guix
1424 - Haiku
1425 - Minix
1426 - NetBSD
1427 - Omnios
1428 - OpenBSD
1429 - OpenSUSE
1430 - QNX
1431 - Rocky Linux
1432 - Salix
1433 - Void Linux
1435 ---
1437 ## License
1439 The provided group library is shared as additional examples WITH NO WARRANTIES of the
1440 documentation and contain the following third-party files under the ISC License.
1441 Copyright information are indicated in the LICENSE section of related files.
1443 - `pf-badhost.sh`
1444 - `unbound-adblock.sh`
1445 - `http-ban.sh`
1447 The project is shared under the terms of the ISC license. Any version previous
1448 `0.1.0` needs to be considered obsolete and should not be redistributed. History
1449 in the GIT repository is kept for transparency purpose only.
1451 Below is a copy of the applicable license:
1453 ISC License
1455 Copyright 2025 xs <xs@inda.re>
1457 Permission to use, copy, modify, and/or distribute this software for any
1458 purpose with or without fee is hereby granted, provided that the above
1459 copyright notice and this permission notice appear in all copies.
1461 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1462 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
1463 FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1464 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1465 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1466 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1467 PERFORMANCE OF THIS SOFTWARE.