3 fef9b495 2025-05-31 xs ### Introduction
5 688c9bfd 2025-06-03 xs R7 is a configuration management framework made to configure nodes with
6 688c9bfd 2025-06-03 xs configuration files and related operations versionned in a central repository.
7 688c9bfd 2025-06-03 xs To remain code versionning system agnostic, manual or automated versionning is
8 688c9bfd 2025-06-03 xs left to the user, via makefiles or triggered from r7 `site-config` configuration
9 688c9bfd 2025-06-03 xs file _(See below)_.
11 688c9bfd 2025-06-03 xs The idea is to store hosts configurations in `nodes/hostname` directories that
12 35f45d45 2025-06-04 xs maps each host's `/etc` and to assign those hosts to configuration groups
13 35f45d45 2025-06-04 xs containing the directives to install the configuration and potential
16 688c9bfd 2025-06-03 xs _Nodes sub-directories are hostnames understood by the ssh client and
17 688c9bfd 2025-06-03 xs configuration._
19 688c9bfd 2025-06-03 xs _Currently, r7 requires valid ssh configuration and keyfiles in the repository
20 688c9bfd 2025-06-03 xs `.ssh/` directory._
22 688c9bfd 2025-06-03 xs _Repositories can be initialized with `rset init` or `rset -w
23 688c9bfd 2025-06-03 xs path/to/new-repository init`, the user will then have to provide valid
24 688c9bfd 2025-06-03 xs configurations and keys for `.ssh/` in the newly created directory._
26 688c9bfd 2025-06-03 xs _See [Technical Notes](#technical-notes) for dependencies and supported
29 fef9b495 2025-05-31 xs There is an example of r7 repository:
36 fef9b495 2025-05-31 xs ./groups/common
37 fef9b495 2025-05-31 xs ./groups/test0
38 fef9b495 2025-05-31 xs ./groups/common.dir
39 fef9b495 2025-05-31 xs ./groups/test0.dir
42 fef9b495 2025-05-31 xs ./.ssh/id_ed25519_r7
43 fef9b495 2025-05-31 xs ./.ssh/id_ed25519_r7.pub
46 fef9b495 2025-05-31 xs There is an example of r7 site configuration (`site-config` file):
49 fef9b495 2025-05-31 xs prefix install state doc
50 fef9b495 2025-05-31 xs group common '.*'
51 fef9b495 2025-05-31 xs group test0 hostB hostC
56 fef9b495 2025-05-31 xs There is an exemple of the deployment of that configuration within the r7
60 730e151b 2025-06-02 xs $ r7 run-config
61 730e151b 2025-06-02 xs - (ok) hostA:common::install_nothing
62 730e151b 2025-06-02 xs - (ok) hostA:common::state_uname
63 730e151b 2025-06-02 xs - (ok) hostA:common::doc_tutorial
64 730e151b 2025-06-02 xs - (ok) hostB:common::install_nothing
65 730e151b 2025-06-02 xs - (ok) hostB:common::state_uname
66 730e151b 2025-06-02 xs - (ok) hostB:common::doc_tutorial
67 730e151b 2025-06-02 xs - (ok) hostC:common::install_nothing
68 730e151b 2025-06-02 xs - (ok) hostC:common::state_uname
69 730e151b 2025-06-02 xs - (ok) hostC:common::doc_tutorial
70 730e151b 2025-06-02 xs - (ok) hostB:test0::state_test
71 730e151b 2025-06-02 xs - (ok) hostC:test0::state_test
74 fef9b495 2025-05-31 xs In this example, everything goes fine, groups are executed on each related
75 fef9b495 2025-05-31 xs nodes, note the `'.*'` matching all hosts present in `./nodes`. Groups are POSIX
76 fef9b495 2025-05-31 xs shell scripts that are a collection of functions.
78 fef9b495 2025-05-31 xs There is the `common` group:
81 fef9b495 2025-05-31 xs install_nothing() {
82 fef9b495 2025-05-31 xs echo Nothing installed
85 fef9b495 2025-05-31 xs state_uname() {
89 fef9b495 2025-05-31 xs doc_tutorial() {
90 fef9b495 2025-05-31 xs echo "## Welcome to the R7 tutorial!"
94 fef9b495 2025-05-31 xs And there is the `test0` group:
97 fef9b495 2025-05-31 xs state_test() {
102 730e151b 2025-06-02 xs Any function managed by `r7` needs to be declared in the format `^PREFIX_NAME()`.
104 fef9b495 2025-05-31 xs Group files names can't contain spaces, tabs or newlines, as well for nodes
105 fef9b495 2025-05-31 xs dirnames. _The ':' character is not recommanded as well as it may reduce
106 fef9b495 2025-05-31 xs lisibility of the interactive output._
108 fef9b495 2025-05-31 xs Called groups and node directories are copied to related nodes in `hostname:/tmp/r7/`:
110 fef9b495 2025-05-31 xs /tmp/r7/hostA/ # Contents of test.org/nodes/hostA/
111 fef9b495 2025-05-31 xs /tmp/r7/common.dir # Contents of test.org/groups/common.dir/
112 fef9b495 2025-05-31 xs /tmp/r7/test.dir # Contents of test.org/groups/test.dir
114 fef9b495 2025-05-31 xs Groups may have no `.dir` directory, in this case, nothing is copied.
116 fef9b495 2025-05-31 xs Once the group copy is done, functions are executed in the order of the defined
117 730e151b 2025-06-02 xs prefix (part of the `site-config` file shown before):
119 fef9b495 2025-05-31 xs prefix install state doc
121 fef9b495 2025-05-31 xs This means the functions matching `^install_.*()`, `^state_.*()` and `^doc_.*()`
122 730e151b 2025-06-02 xs (the default `R7_PREFIX`) in the respective declaration order they're found in the
123 fef9b495 2025-05-31 xs related group file will be executed.
125 fef9b495 2025-05-31 xs Site confiurations are shell scripts sourced by r7 after it's environment is
126 fef9b495 2025-05-31 xs initialized, so `prefix`, `group`, `output-dump`, `summary` are the functions or
127 fef9b495 2025-05-31 xs aliases provided by r7 itself. This allow for scripting from the `site-config`
128 fef9b495 2025-05-31 xs file. Here `output-dump`, and `summary` are called to output potential errors,
129 fef9b495 2025-05-31 xs diffs and permissions changes at the end of the interactive output obtained by
130 fef9b495 2025-05-31 xs `r7 run-config`. If nothing catched happened, nothing is added to the output.
132 fef9b495 2025-05-31 xs ### Errors during remote execution of groups
134 fef9b495 2025-05-31 xs In our previous example, we modify `state_test` so the `test` fails.
137 fef9b495 2025-05-31 xs state_test() {
142 fef9b495 2025-05-31 xs And we re-run the configuration to see what's happenning.
145 730e151b 2025-06-02 xs $ r7 run-config
146 730e151b 2025-06-02 xs - (ok) hostA:common::install_nothing
147 730e151b 2025-06-02 xs - (ok) hostA:common::state_uname
148 730e151b 2025-06-02 xs - (ok) hostA:common::doc_tutorial
149 730e151b 2025-06-02 xs - (ok) hostB:common::install_nothing
150 730e151b 2025-06-02 xs - (ok) hostB:common::state_uname
151 730e151b 2025-06-02 xs - (ok) hostB:common::doc_tutorial
152 730e151b 2025-06-02 xs - (ok) hostC:common::install_nothing
153 730e151b 2025-06-02 xs - (ok) hostC:common::state_uname
154 730e151b 2025-06-02 xs - (ok) hostC:common::doc_tutorial
155 730e151b 2025-06-02 xs - (error 1) hostB:test0::state_test
156 730e151b 2025-06-02 xs - (error 1) hostC:test0::state_test
157 730e151b 2025-06-02 xs - (error 1) - in hostB test0 state_test (1748622980)
158 730e151b 2025-06-02 xs - (error 1) - in hostC test0 state_test (1748622980)
162 fef9b495 2025-05-31 xs The last two lines are part of the `summary` output.
164 fef9b495 2025-05-31 xs Let's modify the `state_test` function again to add some verbosity to it's
167 fef9b495 2025-05-31 xs _Note that we also change the return value._
170 fef9b495 2025-05-31 xs state_test() {
171 fef9b495 2025-05-31 xs echo something
173 fef9b495 2025-05-31 xs echo >&2 failed
179 fef9b495 2025-05-31 xs This will produce the following summary:
182 730e151b 2025-06-02 xs - (error 22) - in hostB test0 state_test (1748622980)
187 730e151b 2025-06-02 xs - (error 22) - in hostC test0 state_test (1748622980)
193 fef9b495 2025-05-31 xs Diffs and permissions changes are also displayed by the `summary` command. When
194 fef9b495 2025-05-31 xs they're are detected, the captured related output is shown.
196 730e151b 2025-06-02 xs ### Repository initialisation
198 730e151b 2025-06-02 xs Using the `init` command, we can specify the current or a specifed
199 730e151b 2025-06-02 xs work directory to be created and act as an r7 repository.
201 730e151b 2025-06-02 xs _Automated versionning of outputs are currently let to the user, a recommended
202 730e151b 2025-06-02 xs place would be the end of the site configuration file._
204 730e151b 2025-06-02 xs This command initializes a new directory called `test.org`:
207 730e151b 2025-06-02 xs r7 -w test.org init
211 730e151b 2025-06-02 xs Once this step is done, it is required to:
213 730e151b 2025-06-02 xs - Copy or initialize the ssh key to the `.ssh` folder in the repository created
214 730e151b 2025-06-02 xs in `.ssh/id_ed25519-r7` and `./ssh/id_ed25519-r7.pub`
216 730e151b 2025-06-02 xs - Adjust the SSH client configuration file in the repository `.ssh/config`
218 730e151b 2025-06-02 xs _Note that it is possible to import additionnal SSH configurations, like the user
219 730e151b 2025-06-02 xs one from the SSH configuration, but it is advised to keep them separate._
221 730e151b 2025-06-02 xs ### SSH agent handling
223 730e151b 2025-06-02 xs The function `unlock` can be used to set the SSH agent environement, this will
224 730e151b 2025-06-02 xs be required for any automated operation later done by r7:
228 730e151b 2025-06-02 xs . $(command -v r7) # Sourcing r7
230 730e151b 2025-06-02 xs tmux || screen
233 3aa5672d 2025-06-04 xs _***Warning:*** Unlock will terminate any running `ssh-agent` instances._
235 730e151b 2025-06-02 xs ### Adding new hosts
237 730e151b 2025-06-02 xs For adding a new host, the simplest way is to have pre-configured
238 730e151b 2025-06-02 xs `authorized_keys` for the target user, it is then required to add it to the
239 730e151b 2025-06-02 xs `known_hosts` file. For that, it is possible to use r7 SSH functions:
242 730e151b 2025-06-02 xs . $(command -v r7) # Sourcing r7
243 730e151b 2025-06-02 xs ssh-accept-new hostname
247 730e151b 2025-06-02 xs If resetting the target's user `authorized_keys` file is needed, the following
248 730e151b 2025-06-02 xs function can be used:
251 730e151b 2025-06-02 xs . $(command -v r7) # Sourcing r7
252 730e151b 2025-06-02 xs ssh-authorized-keys-reset hostname
255 730e151b 2025-06-02 xs _**Warning:** This will resets the SSH authorized_keys file for the target user
256 730e151b 2025-06-02 xs (root, by default) and put the `.ssh/id_ed25519-r7.pub` in place._
259 730e151b 2025-06-02 xs Once the host is accepted in the `known_hosts` file, it's possible to import it
260 730e151b 2025-06-02 xs automatically.
262 730e151b 2025-06-02 xs ### Importing hosts configurations
264 730e151b 2025-06-02 xs _This feature currently only support OpenBSD._
266 730e151b 2025-06-02 xs Avoiding to import the configuration manually is possible with the `import`
270 730e151b 2025-06-02 xs r7 import hostname
273 730e151b 2025-06-02 xs Most common configuration files will be copied in a newly created
274 730e151b 2025-06-02 xs `nodes/hostname` sub-directory.
276 730e151b 2025-06-02 xs ### Writing group files
278 730e151b 2025-06-02 xs Group files collects fonctions related to the configuration of the operating
279 730e151b 2025-06-02 xs system, networking, services, global and user configurations packages
280 730e151b 2025-06-02 xs installations and application deployments.
282 730e151b 2025-06-02 xs By specifying the execution prefix, the user determines the order of execution
283 730e151b 2025-06-02 xs of the functions declared in the group file.
286 730e151b 2025-06-02 xs service_A() {
287 730e151b 2025-06-02 xs service A enable
288 730e151b 2025-06-02 xs service A restart
291 730e151b 2025-06-02 xs service_B() {
292 730e151b 2025-06-02 xs service B enable
293 730e151b 2025-06-02 xs service B restart
297 730e151b 2025-06-02 xs service A status
301 730e151b 2025-06-02 xs echo "## Service A"
303 730e151b 2025-06-02 xs echo "- [url](http://test.org/)"
308 730e151b 2025-06-02 xs _**file**: `groups/example1`_
310 730e151b 2025-06-02 xs With the default prefix, `install`, `state`, `doc`, the fonction that will be
311 730e151b 2025-06-02 xs executed are `state_A` and `doc_A`. To test that group file with all the
312 730e151b 2025-06-02 xs functions inside we can call r7 the following way:
315 730e151b 2025-06-02 xs r7 -P 'service state doc' group example1 hostname
318 730e151b 2025-06-02 xs Or using the `-a` flag which will create a prefix automatically with all
319 730e151b 2025-06-02 xs functions present in the group file:
322 730e151b 2025-06-02 xs r7 -a group example1 hostname
325 730e151b 2025-06-02 xs In a real situation, this example will have failing functions because the
326 730e151b 2025-06-02 xs `service` command may not be found or the services named `A` or `B` does not
330 730e151b 2025-06-02 xs ! (error 127) tools0:example1::service_A
331 730e151b 2025-06-02 xs ! (error 127) tools0:example1::service_B
332 730e151b 2025-06-02 xs ! (error 127) tools0:example1::state_A
333 730e151b 2025-06-02 xs - (ok) tools0:example1::doc_A
336 730e151b 2025-06-02 xs We could force the group execution to stop using a combination of the `-e` flag
337 730e151b 2025-06-02 xs and the `error` group function.
340 730e151b 2025-06-02 xs service_A() {
341 730e151b 2025-06-02 xs service A enable &&
342 730e151b 2025-06-02 xs service A restart ||
343 730e151b 2025-06-02 xs error unable to setup service A
346 730e151b 2025-06-02 xs service_B() {
347 730e151b 2025-06-02 xs service B enable &&
348 730e151b 2025-06-02 xs service B restart ||
349 730e151b 2025-06-02 xs error unable to setup service B
353 730e151b 2025-06-02 xs service A status
357 730e151b 2025-06-02 xs echo "## Service A"
359 730e151b 2025-06-02 xs echo "- [url](http://test.org/)"
364 730e151b 2025-06-02 xs _**file:** `groups/example2`_
366 730e151b 2025-06-02 xs Let's run the updated example with the `-s` flag to trigger the summary output.
369 730e151b 2025-06-02 xs rm -fr _output
370 730e151b 2025-06-02 xs r7 -sea group example2 hostname
373 730e151b 2025-06-02 xs This will produce something like the following:
376 730e151b 2025-06-02 xs ! (error) tools0:example2::service_A
377 730e151b 2025-06-02 xs ! (exit) tools0:example2::service_A
378 730e151b 2025-06-02 xs - (error 127) - in tools0 example2 service_A (1748791986)
380 730e151b 2025-06-02 xs /bin/sh: <stdin>[155]: service: not found
381 688c9bfd 2025-06-03 xs :: 1748791986 tools0 ERROR unable to setup service A
385 730e151b 2025-06-02 xs ### Using the r7 install functions
387 730e151b 2025-06-02 xs The group library comes with the following functions that will allow
388 730e151b 2025-06-02 xs installation of files and triggering actions if necessary: `install`,
389 730e151b 2025-06-02 xs `groupinstall`, `nodeinstall`. They are all shortcuts to an internal
390 730e151b 2025-06-02 xs `r7_install` function, it's just the wrappers changes directory to respectively
391 730e151b 2025-06-02 xs `/tmp/r7`, `/tmp/r7/groupname.dir/` and `/tmp/r7/hostname/`.
393 730e151b 2025-06-02 xs If we want to install files from the group directory we will use something like:
397 730e151b 2025-06-02 xs install_program() {
398 730e151b 2025-06-02 xs groupinstall -m 755 -o root:bin my_program /usr/local/bin
402 730e151b 2025-06-02 xs _We are supposing to have the file `groups/example3.dir/my_program`_
404 730e151b 2025-06-02 xs And if it's something from node, we should use:
407 730e151b 2025-06-02 xs install_program_config() {
408 730e151b 2025-06-02 xs nodeinstall -m 644 -o root:wheel my_config /etc
412 730e151b 2025-06-02 xs We can now chain the `install` functions to configuration checking and
413 730e151b 2025-06-02 xs initialization of programs, services or network features like in the following
414 730e151b 2025-06-02 xs example, in which we install `ntp.conf` from the deployed node directory to
418 730e151b 2025-06-02 xs service_ntpd() {
419 730e151b 2025-06-02 xs nodeinstall -m 644 -o root:wheel ntpd.conf /etc &&
421 730e151b 2025-06-02 xs rcctl enable ntpd &&
422 730e151b 2025-06-02 xs rcctl restart ntpd
426 730e151b 2025-06-02 xs ### Using the r7 node function
428 730e151b 2025-06-02 xs We may want to avoid executing a function or parts of it if the node has no
429 730e151b 2025-06-02 xs related files before executing the installation and actions handling parts. This
430 730e151b 2025-06-02 xs can be done with the help of the `node` function.
433 730e151b 2025-06-02 xs service_ntpd() {
434 730e151b 2025-06-02 xs node ntpd.conf &&
435 730e151b 2025-06-02 xs nodeinstall -m 644 -o root:wheel ntpd.conf /etc &&
437 730e151b 2025-06-02 xs rcctl enable ntpd &&
438 730e151b 2025-06-02 xs rcctl restart ntpd
442 730e151b 2025-06-02 xs Here, `node` will return `31` if there is no file or directory called
443 730e151b 2025-06-02 xs `ntpd.conf` inside the deployed node directory (`/tmp/r7/hostname`).
445 730e151b 2025-06-02 xs `0`, `30` and `31` exit codes are ignored when r7 will search for execution
446 730e151b 2025-06-02 xs errors. This means `30` and `31` exit code are reserved to r7.
448 730e151b 2025-06-02 xs In other terms, this will update the NTP daemon configuration only if
449 730e151b 2025-06-02 xs `ntpd.conf` is present in the node directory, otherwise it is kept by default,
450 730e151b 2025-06-02 xs which is the system provided default `ntpd.conf`.
452 730e151b 2025-06-02 xs ### Sourcing specific files
454 730e151b 2025-06-02 xs Here's an example how to source additionnal shell from the deployed node
455 730e151b 2025-06-02 xs directory, or elsewhere:
458 730e151b 2025-06-02 xs service_sysrc() {
459 730e151b 2025-06-02 xs sysrc dumpdev=NO
460 730e151b 2025-06-02 xs sysrc kld_list="vmm if_tuntap if_bridge nmdm"
461 730e151b 2025-06-02 xs sysrc microcode_update_enable=YES
462 730e151b 2025-06-02 xs sysrc mountd_enable=YES
463 730e151b 2025-06-02 xs sysrc nfs_server_enable=YES
464 730e151b 2025-06-02 xs sysrc ntpdate_enable=YES
465 730e151b 2025-06-02 xs sysrc powerd_enable=YES
466 730e151b 2025-06-02 xs sysrc rcshutdown_timeout=900
467 730e151b 2025-06-02 xs sysrc rpcbind_enable=YES
468 730e151b 2025-06-02 xs sysrc sshd_enable=YES
469 730e151b 2025-06-02 xs sysrc zfs_enable=YES
470 0b6ecfa4 2025-06-03 xs nodesource sysrc.local
475 730e151b 2025-06-02 xs In this FreeBSD example, we configure the system RC globally with
476 730e151b 2025-06-02 xs `service_sysrc` which apply, if `sysrc.local` is found in the root of the node
477 730e151b 2025-06-02 xs directory, it's sourcing in the current scope via the help of `nodesource
478 730e151b 2025-06-02 xs sysrc.local`.
480 730e151b 2025-06-02 xs The file `nodes/hostname/sysrcl.local` contains the following:
483 730e151b 2025-06-02 xs sysrc ifconfig_igb0=DHCP
484 730e151b 2025-06-02 xs sysrc ifconfig_igb1=up
487 730e151b 2025-06-02 xs ### Other examples
489 35f45d45 2025-06-04 xs Inside the r7 release, a small example groups library can be found in the
490 35f45d45 2025-06-04 xs `groups` directory, that can also be browsed in the
491 35f45d45 2025-06-04 xs [repository](https://got.inda.re/?action=summary&path=r7.git).
493 730e151b 2025-06-02 xs #### System shell profile
495 730e151b 2025-06-02 xs Here we install the `profile` file provided in the `groupname.dir` directory or
496 730e151b 2025-06-02 xs the profile provided by the node directory:
499 730e151b 2025-06-02 xs setup_profile() {
500 730e151b 2025-06-02 xs groupinstall -m 644 -o root:wheel profile /etc
501 730e151b 2025-06-02 xs node profile &&
502 730e151b 2025-06-02 xs nodeinstall -m 644 -o root:wheel profile /etc
508 730e151b 2025-06-02 xs Here we add new users:
511 730e151b 2025-06-02 xs setup_users() {
512 688c9bfd 2025-06-03 xs useradd user1 2>/dev/null || :
513 688c9bfd 2025-06-03 xs useradd user2 2>/dev/null || :
519 730e151b 2025-06-02 xs In the following example, we install a script and call it from a dedicated user crontab.
522 730e151b 2025-06-02 xs mail_admins=admins@test.org
524 730e151b 2025-06-02 xs install_myscript() {
525 730e151b 2025-06-02 xs groupinstall -o root:bin -m 755 myscript /usr/local/bin &&
526 730e151b 2025-06-02 xs useradd -d /var/empty -s /sbin/nologin _myscript
527 730e151b 2025-06-02 xs crontab -u _myscript - <<-/
528 730e151b 2025-06-02 xs MAILTO=$mail_admins
529 730e151b 2025-06-02 xs */5 * * * * myscript
534 730e151b 2025-06-02 xs ### Consulting the output
536 730e151b 2025-06-02 xs After the execution is done, the result are saved in the `_run` directory,
537 730e151b 2025-06-02 xs `output-dump` needs to be called to produce the current `_output` structure.
539 730e151b 2025-06-02 xs The r7 `output` command can then be used to show specific output groups or functions:
545 730e151b 2025-06-02 xs Will show the whole output of the latest groups deployments.
547 730e151b 2025-06-02 xs This format can be used to match specific host, group or function:
550 730e151b 2025-06-02 xs r7 output [hostname [groupname [funcname]]]
556 730e151b 2025-06-02 xs $ r7 output tools0 OpenBSD state_packages\*
557 730e151b 2025-06-02 xs - tools0 OpenBSD state_packages_upgrades
559 730e151b 2025-06-02 xs quirks-7.103 signed on 2025-05-30T01:12:03Z
561 730e151b 2025-06-02 xs - tools0 OpenBSD state_packages_repository
563 730e151b 2025-06-02 xs https://cdn.openbsd.org/pub/OpenBSD
566 730e151b 2025-06-02 xs _Note that the `output` function arguments are using shell's case globbing patterns._
568 fef9b495 2025-05-31 xs ## r7 command line
572 fef9b495 2025-05-31 xs r7 [options] [command [arguments...]]
578 fef9b495 2025-05-31 xs Show usage and exit
581 fef9b495 2025-05-31 xs Enable debug mode
584 fef9b495 2025-05-31 xs Specify the SSH identity file
587 fef9b495 2025-05-31 xs Specify the SSH client configuration file
590 fef9b495 2025-05-31 xs Set the work directory where `./nodes` and `./groups` can be found
593 fef9b495 2025-05-31 xs Set the run directory (default: `./_run`)
596 fef9b495 2025-05-31 xs Set the output directory (default: `./_output`)
599 fef9b495 2025-05-31 xs Specify the site configuration file (default: `./site-config`)
602 fef9b495 2025-05-31 xs Enable dry run mode; prevents any modification on hosts
605 730e151b 2025-06-02 xs Exit the group execution on the error function
608 fef9b495 2025-05-31 xs Run each host in parallel per group call
611 fef9b495 2025-05-31 xs Show output interactively
614 fef9b495 2025-05-31 xs Specify a prefix
617 fef9b495 2025-05-31 xs Select all available prefixes for a group command
620 fef9b495 2025-05-31 xs Apply output-dump and summary after a group command
624 f6bdfddc 2025-06-03 xs | Name | Description |
625 f6bdfddc 2025-06-03 xs | ---- | ----------- |
626 f6bdfddc 2025-06-03 xs | **run-config** | Run the site configuration |
627 f6bdfddc 2025-06-03 xs | **group** | Deploy specified group to hosts |
628 f6bdfddc 2025-06-03 xs | **output-dump** | Dump the run directory to the output directory |
629 f6bdfddc 2025-06-03 xs | **output** | Consult the output |
630 f6bdfddc 2025-06-03 xs | **summary** | Produce a summary of errors and changes |
631 f6bdfddc 2025-06-03 xs | **digraph-host** | Produce a dot digraph for hosts |
632 f6bdfddc 2025-06-03 xs | **digraph-ssh** | Produce a dot digraph of SSH ID's, users and nodes relations |
633 f6bdfddc 2025-06-03 xs | **import** | Import TARGET host in the current nodes directory |
634 f6bdfddc 2025-06-03 xs | **info** | Default command showing active nodes and summary |
635 f6bdfddc 2025-06-03 xs | **init** | Initialize a new work directory |
637 688c9bfd 2025-06-03 xs ## Environment
639 f6bdfddc 2025-06-03 xs | Name | Default value | Description |
640 f6bdfddc 2025-06-03 xs | ---- | ------------- | ------------|
641 f6bdfddc 2025-06-03 xs | R7_DEBUG | no | Enable debug mode |
642 f6bdfddc 2025-06-03 xs | R7_DRYRUN | no | Enable dry-run mode |
643 f6bdfddc 2025-06-03 xs | R7_GROUP_ALLPREFIX | no | Group selects all available prefix |
644 f6bdfddc 2025-06-03 xs | R7_GROUP_SUMMARY | no | Enable output-dump and summary after group execution |
645 f6bdfddc 2025-06-03 xs | R7_GROUP_EXITONERROR | no | Enable exit on error function |
646 f6bdfddc 2025-06-03 xs | R7_PARALLEL | no | Enable group nodes parallel execution |
647 f6bdfddc 2025-06-03 xs | R7_PREFIX | install state doc | Set the r7 group execution prefix |
648 f6bdfddc 2025-06-03 xs | R7_SHOWOUTPUT | no | Show interactive output |
649 f6bdfddc 2025-06-03 xs | R7_WORKDIR | PWD | Set the r7 repository path |
650 f6bdfddc 2025-06-03 xs | R7_SITE_CONFIG | R7_WORKDIR/site-config | Set the r7 `site-config` path |
651 f6bdfddc 2025-06-03 xs | R7_OUTPUTDIR | R7_WORKDIR/_output | Set the r7 output directory path |
652 f6bdfddc 2025-06-03 xs | SSH_CONFIG_DIR | R7_WORKDIR/.ssh | Set the SSH configuration directory path |
653 f6bdfddc 2025-06-03 xs | SSH_CONFIG_FILE | R7_WORKDIR/.ssh/config | Set the SSH configuration file path |
654 f6bdfddc 2025-06-03 xs | SSH_CONTROL_DIR | SSH_CONFIG_DIR/control | Set the SSH control dir path |
655 f6bdfddc 2025-06-03 xs | SSH_IDENTITY_FILE | R7_WORKDIR/.ssh/id_ed25519_r7 | Set the SSH identity file |
656 f6bdfddc 2025-06-03 xs | SSH_KNOWN_HOSTS | R7_WORKDIR/.ssh/known_hosts | Set the SSH known hosts file |
657 f6bdfddc 2025-06-03 xs | SSH_CONNECT_TIMEOUT | 3 | Set the SSH connect timeout |
660 688c9bfd 2025-06-03 xs ## Group variables
662 688c9bfd 2025-06-03 xs Those variables are available during the execution of th group file's functions.
664 688c9bfd 2025-06-03 xs | Name | Description |
665 688c9bfd 2025-06-03 xs | ---- | ----------- |
666 688c9bfd 2025-06-03 xs | trace_id | Current run trace ID |
667 688c9bfd 2025-06-03 xs | groupname | Current group name being executed |
668 688c9bfd 2025-06-03 xs | exitonerror | Cause the error function to exit if equals `yes` |
669 688c9bfd 2025-06-03 xs | nodename | Contains the output of `nodename` |
670 688c9bfd 2025-06-03 xs | nodedir | Contains the output of `nodedir` |
671 688c9bfd 2025-06-03 xs | groupdir | Contains the output of `groupdir` |
674 730e151b 2025-06-02 xs ## Group functions
676 730e151b 2025-06-02 xs Those functions are accessible during the execution of the group file's functions.
677 22b54c5e 2025-06-04 xs Non documented functions are reserved for internal use.
679 730e151b 2025-06-02 xs 1. [trace](#trace)
680 730e151b 2025-06-02 xs 2. [error](#error)
681 730e151b 2025-06-02 xs 3. [node](#node)
682 730e151b 2025-06-02 xs 4. [nodename](#nodename)
683 730e151b 2025-06-02 xs 5. [nodedir](#nodedir)
684 730e151b 2025-06-02 xs 6. [groupdir](#groupdir)
685 730e151b 2025-06-02 xs 7. [install](#install)
686 730e151b 2025-06-02 xs 8. [groupinstall](#groupinstall)
687 730e151b 2025-06-02 xs 9. [nodeinstall](#nodeinstall)
688 3aa5672d 2025-06-04 xs 10. [installdir](#installdir)
689 3aa5672d 2025-06-04 xs 11. [groupinstalldir](#groupinstalldir)
690 3aa5672d 2025-06-04 xs 12. [nodeinstalldir](#nodeinstalldir)
691 3aa5672d 2025-06-04 xs 13. [source](#source)
692 3aa5672d 2025-06-04 xs 14. [groupsource](#groupsource)
693 3aa5672d 2025-06-04 xs 15. [nodesource](#groupsource)
699 730e151b 2025-06-02 xs ***Description:***
700 f6bdfddc 2025-06-03 xs Append a trace containing the current node name and `trace_id`
704 730e151b 2025-06-02 xs trace [string...]
709 730e151b 2025-06-02 xs ***Description:***
710 730e151b 2025-06-02 xs Trace an error message that will inform the user of an event in the summary
711 730e151b 2025-06-02 xs output, exit the group execution if `-e` is set
715 730e151b 2025-06-02 xs error [string...]
720 730e151b 2025-06-02 xs ***Description:***
721 f6bdfddc 2025-06-03 xs Returns true if the argument is an existing file or directory inside `/tmp/r7/$(nodename)`, else, returns 31
725 730e151b 2025-06-02 xs node [filename|dirname]
730 730e151b 2025-06-02 xs ***Description:***
731 730e151b 2025-06-02 xs Returns the small hostname of the current host
740 730e151b 2025-06-02 xs ***Description:***
741 730e151b 2025-06-02 xs Returns `/tmp/r7/$(nodename)`
750 730e151b 2025-06-02 xs ***Description:***
751 730e151b 2025-06-02 xs Returns `/tmp/r7/$groupname.dir`
760 730e151b 2025-06-02 xs ***Description:***
761 730e151b 2025-06-02 xs Change directory to `/tmp/r7` and install files if changed and sets mode and
762 f6bdfddc 2025-06-03 xs owner, returns true if the file changed, otherwise returns 30
766 730e151b 2025-06-02 xs install [-o owner] [-m mode] source destintaion
769 730e151b 2025-06-02 xs ### groupinstall
771 730e151b 2025-06-02 xs ***Description:***
772 730e151b 2025-06-02 xs Change directory to the current group `.dir` directory in `/tmp/r7` then
773 730e151b 2025-06-02 xs performs like `install`
777 730e151b 2025-06-02 xs groupinstall [-o owner] [-m mode] source destintaion
780 730e151b 2025-06-02 xs ### nodeinstall
782 730e151b 2025-06-02 xs ***Description:***
783 730e151b 2025-06-02 xs Change directory to the current node directory in `/tmp/r7` then
784 730e151b 2025-06-02 xs performs like `install`
788 730e151b 2025-06-02 xs nodeinstall [-o owner] [-m mode] source destintaion
791 3aa5672d 2025-06-04 xs ### installdir
793 3aa5672d 2025-06-04 xs ***Description:***
794 3aa5672d 2025-06-04 xs Install directory calling `install` for each file and checking for permissions
799 3aa5672d 2025-06-04 xs installdir [-o fileowner] [-m filemode] [-O dirowner] [-O dirmode] source
803 3aa5672d 2025-06-04 xs ### groupinstalldir
805 3aa5672d 2025-06-04 xs ***Description:***
806 3aa5672d 2025-06-04 xs Change directory to the current group directoy then call installdir
810 3aa5672d 2025-06-04 xs groupinstalldir [-o fileowner] [-m filemode] [-O dirowner] [-O dirmode] source
814 3aa5672d 2025-06-04 xs ### nodeinstalldir
816 3aa5672d 2025-06-04 xs ***Description:***
817 3aa5672d 2025-06-04 xs Change directory to the current group directoy then call installdir
821 3aa5672d 2025-06-04 xs nodeinstalldir [-o fileowner] [-m filemode] [-O dirowner] [-O dirmode] source
827 730e151b 2025-06-02 xs ***Description:***
828 730e151b 2025-06-02 xs Source a POSIX shell file in the current execution
833 730e151b 2025-06-02 xs source filename
836 730e151b 2025-06-02 xs ### groupsource
838 730e151b 2025-06-02 xs ***Description:***
839 730e151b 2025-06-02 xs Change directory to the current group directory then call source with the file
840 730e151b 2025-06-02 xs name as argument, produces an error if filename is not found from the group
844 730e151b 2025-06-02 xs groupsource filename
847 730e151b 2025-06-02 xs ### nodesource
849 730e151b 2025-06-02 xs ***Description:***
850 730e151b 2025-06-02 xs Change directory to the current group directory then call node and source with the file
851 730e151b 2025-06-02 xs name as argument without producing an error if the filename is not found
854 730e151b 2025-06-02 xs nodesource filename
859 688c9bfd 2025-06-03 xs Usable from the r7 `site-config` file or sourced in the current shell using:
862 688c9bfd 2025-06-03 xs . $(command -v r7)
865 688c9bfd 2025-06-03 xs Each functions are declared with underscore names and aliased with dashes.
866 688c9bfd 2025-06-03 xs Shorter aliases are also available, list all declared aliases with:
872 22b54c5e 2025-06-04 xs Non documented functions are reserved for internal use.
876 fef9b495 2025-05-31 xs 1. [info](#info)
877 fef9b495 2025-05-31 xs 2. [usage](#usage)
883 fef9b495 2025-05-31 xs ***Description:***
884 fef9b495 2025-05-31 xs Default command showing active nodes and summary, ran when sourced
893 fef9b495 2025-05-31 xs ***Description:***
894 fef9b495 2025-05-31 xs Shows the command line help
901 fef9b495 2025-05-31 xs ## SSH functions
903 fef9b495 2025-05-31 xs 1. [unlock](#unlock)
904 fef9b495 2025-05-31 xs 2. [copy](#copy)
905 fef9b495 2025-05-31 xs 3. [ssh](#ssh)
906 fef9b495 2025-05-31 xs 4. [ssh-debug](#ssh-debug)
907 fef9b495 2025-05-31 xs 5. [ssh-known-hosts](#ssh-known-hosts)
908 fef9b495 2025-05-31 xs 6. [ssh-authorized-keys-reset](#ssh-authorized-keys-reset)
909 fef9b495 2025-05-31 xs 7. [ssh-accept-new](#ssh-accept-new)
910 fef9b495 2025-05-31 xs 8. [ssh-control-master-clean](#ssh-control-master-clean)
911 fef9b495 2025-05-31 xs 9. [ssh-users](#ssh-users)
912 fef9b495 2025-05-31 xs 10. [ssh-ids](#ssh-ids)
913 fef9b495 2025-05-31 xs 11. [ssh-authorized-keys](#ssh-authorized-keys)
914 fef9b495 2025-05-31 xs 12. [ssh-ids-hosts](#ssh-ids-hosts)
920 fef9b495 2025-05-31 xs ***Description:***
921 fef9b495 2025-05-31 xs Resets the SSH agent environment and issues ssh-add for SSH_IDENTITY_FILE
930 fef9b495 2025-05-31 xs ***Description:***
931 fef9b495 2025-05-31 xs r7 openrsync, rsync, scp wrapper; selected in order of availability
940 fef9b495 2025-05-31 xs ***Description:***
941 fef9b495 2025-05-31 xs r7 SSH wrapper; behaves like the standard OpenSSH command
945 fef9b495 2025-05-31 xs ssh OPTION HOST
948 fef9b495 2025-05-31 xs ### ssh-debug
950 fef9b495 2025-05-31 xs ***Description:***
951 fef9b495 2025-05-31 xs r7 SSH with debug connection mode for a specific HOST
955 fef9b495 2025-05-31 xs ssh-debug HOST
958 fef9b495 2025-05-31 xs ### ssh-known-hosts
960 fef9b495 2025-05-31 xs ***Description:***
961 fef9b495 2025-05-31 xs Calls ssh-keygen to dump the SSH known_hosts file
965 fef9b495 2025-05-31 xs ssh-known-hosts
968 fef9b495 2025-05-31 xs ### ssh-authorized-keys-reset
970 fef9b495 2025-05-31 xs ***Description:***
971 fef9b495 2025-05-31 xs Resets SSH authorized_keys on the specified HOST
975 fef9b495 2025-05-31 xs ssh-authorized-keys-reset HOST
978 fef9b495 2025-05-31 xs ### ssh-accept-new
980 fef9b495 2025-05-31 xs ***Description:***
981 fef9b495 2025-05-31 xs Adds a new host entry in the SSH known_hosts file
985 fef9b495 2025-05-31 xs ssh-accept-new HOST
988 fef9b495 2025-05-31 xs ### ssh-control-master-clean
990 fef9b495 2025-05-31 xs ***Description:***
991 fef9b495 2025-05-31 xs Cleans the SSH control master directory
995 fef9b495 2025-05-31 xs ssh-control-master-clean
998 fef9b495 2025-05-31 xs ### ssh-users
1000 fef9b495 2025-05-31 xs ***Description:***
1001 fef9b495 2025-05-31 xs Searches nodes for authorized_keys_* and returns a list of users
1003 fef9b495 2025-05-31 xs ***Usage:***
1010 fef9b495 2025-05-31 xs ***Description:***
1011 fef9b495 2025-05-31 xs Returns sorted SSH IDs
1013 fef9b495 2025-05-31 xs ***Usage:***
1018 fef9b495 2025-05-31 xs ### ssh-authorized-keys
1020 fef9b495 2025-05-31 xs ***Description:***
1021 fef9b495 2025-05-31 xs Returns the list of authorized_keys from nodes
1023 fef9b495 2025-05-31 xs ***Usage:***
1025 fef9b495 2025-05-31 xs ssh-authorized-keys
1028 fef9b495 2025-05-31 xs ### ssh-ids-hosts
1030 fef9b495 2025-05-31 xs ***Description:***
1031 fef9b495 2025-05-31 xs Returns SSH IDs along with matching keyfile and hostname
1033 fef9b495 2025-05-31 xs ***Usage:***
1035 fef9b495 2025-05-31 xs ssh-ids-hosts
1038 fef9b495 2025-05-31 xs ## Deployment functions
1040 fef9b495 2025-05-31 xs 1. [nodes](#nodes)
1041 fef9b495 2025-05-31 xs 2. [nodes-active](#nodes-active)
1042 fef9b495 2025-05-31 xs 3. [run-config](#run-config)
1043 fef9b495 2025-05-31 xs 4. [members](#members)
1044 fef9b495 2025-05-31 xs 5. [group](#group)
1045 fef9b495 2025-05-31 xs 6. [group-functions](#group-functions)
1046 fef9b495 2025-05-31 xs 7. [prefix](#prefix)
1052 fef9b495 2025-05-31 xs ***Description:***
1053 fef9b495 2025-05-31 xs Returns a list of available nodes
1055 fef9b495 2025-05-31 xs ***Usage:***
1060 fef9b495 2025-05-31 xs ### nodes-active
1062 fef9b495 2025-05-31 xs ***Description:***
1063 fef9b495 2025-05-31 xs Returns a list of active nodes by detecting SSH availability
1065 fef9b495 2025-05-31 xs ***Usage:***
1067 fef9b495 2025-05-31 xs nodes-active
1070 fef9b495 2025-05-31 xs ### run-config
1072 fef9b495 2025-05-31 xs ***Description:***
1073 f6bdfddc 2025-06-03 xs Executes `R7_SITE_CONFIG` in the loaded environment
1075 fef9b495 2025-05-31 xs ***Usage:***
1082 fef9b495 2025-05-31 xs ***Description:***
1083 f6bdfddc 2025-06-03 xs Returns a list of active nodes matching a list of grep REGEXES
1085 fef9b495 2025-05-31 xs ***Usage:***
1087 fef9b495 2025-05-31 xs members REGEXES
1092 fef9b495 2025-05-31 xs ***Description:***
1093 fef9b495 2025-05-31 xs Applies GROUPNAME functions (in prefix order) to the provided MEMBERS list
1095 fef9b495 2025-05-31 xs ***Usage:***
1097 fef9b495 2025-05-31 xs group GROUPNAME MEMBERS
1100 fef9b495 2025-05-31 xs ### group-functions
1102 fef9b495 2025-05-31 xs ***Description:***
1103 fef9b495 2025-05-31 xs Returns a list of functions found in the specified GROUPNAME
1105 fef9b495 2025-05-31 xs ***Usage:***
1107 fef9b495 2025-05-31 xs group-functions GROUPNAME
1112 fef9b495 2025-05-31 xs ***Description:***
1113 fef9b495 2025-05-31 xs Sets the current PREFIX for matching function names
1115 fef9b495 2025-05-31 xs ***Usage:***
1117 fef9b495 2025-05-31 xs prefix PREFIX
1120 fef9b495 2025-05-31 xs ## Text output functions
1122 fef9b495 2025-05-31 xs 1. [output-dump](#output-dump)
1123 fef9b495 2025-05-31 xs 2. [output-latest](#output-latest)
1124 fef9b495 2025-05-31 xs 3. [output-status](#output-status)
1125 fef9b495 2025-05-31 xs 4. [output-duration](#output-duration)
1126 fef9b495 2025-05-31 xs 5. [output](#output)
1127 730e151b 2025-06-02 xs 6. [output-diffs](#output-diffs)
1128 730e151b 2025-06-02 xs 7. [output-permissions](#output-permissions)
1129 730e151b 2025-06-02 xs 8. [output-errors](#output-errors)
1130 730e151b 2025-06-02 xs 9. [summary](#summary)
1131 730e151b 2025-06-02 xs 10. [trace-id-last](#trace-id-last)
1135 fef9b495 2025-05-31 xs ### output-dump
1137 fef9b495 2025-05-31 xs ***Description:***
1138 fef9b495 2025-05-31 xs Dumps R7_RUNDIR to R7_OUTPUTDIR
1140 fef9b495 2025-05-31 xs ***Usage:***
1145 fef9b495 2025-05-31 xs ### output-latest
1147 fef9b495 2025-05-31 xs ***Description:***
1148 fef9b495 2025-05-31 xs Returns a list of outputs from the latest run
1150 fef9b495 2025-05-31 xs ***Usage:***
1152 fef9b495 2025-05-31 xs output-latest
1155 fef9b495 2025-05-31 xs ### output-status
1157 fef9b495 2025-05-31 xs ***Description:***
1158 fef9b495 2025-05-31 xs Returns a list of current dumped functions exit status codes
1160 fef9b495 2025-05-31 xs ***Usage:***
1162 fef9b495 2025-05-31 xs output-status
1165 fef9b495 2025-05-31 xs ### output-duration
1167 fef9b495 2025-05-31 xs ***Description:***
1168 fef9b495 2025-05-31 xs Returns a list of durations of executed groups
1170 fef9b495 2025-05-31 xs ***Usage:***
1172 fef9b495 2025-05-31 xs output-duration
1177 fef9b495 2025-05-31 xs ***Description:***
1178 fef9b495 2025-05-31 xs Shows the dumped output matching HOST, GROUPNAME, and FUNCTION (or any if unspecified)
1180 fef9b495 2025-05-31 xs ***Usage:***
1182 fef9b495 2025-05-31 xs output HOST GROUPNAME FUNCTION
1185 fef9b495 2025-05-31 xs ### trace-id-last
1187 fef9b495 2025-05-31 xs ***Description:***
1188 fef9b495 2025-05-31 xs Returns the latest execution trace_id
1190 fef9b495 2025-05-31 xs ***Usage:***
1192 fef9b495 2025-05-31 xs trace-id-last
1195 fef9b495 2025-05-31 xs ### output-diffs
1197 fef9b495 2025-05-31 xs ***Description:***
1198 fef9b495 2025-05-31 xs Returns the diffs from the latest execution
1200 fef9b495 2025-05-31 xs ***Usage:***
1202 fef9b495 2025-05-31 xs output-diffs
1205 fef9b495 2025-05-31 xs ### output-permissions
1207 fef9b495 2025-05-31 xs ***Description:***
1208 fef9b495 2025-05-31 xs Returns the latest permission changes
1210 fef9b495 2025-05-31 xs ***Usage:***
1212 fef9b495 2025-05-31 xs output-permissions
1215 fef9b495 2025-05-31 xs ### output-errors
1217 fef9b495 2025-05-31 xs ***Description:***
1218 fef9b495 2025-05-31 xs Returns the latest errors detected
1220 fef9b495 2025-05-31 xs ***Usage:***
1222 fef9b495 2025-05-31 xs output-errors
1227 fef9b495 2025-05-31 xs ***Description:***
1228 fef9b495 2025-05-31 xs Produces a summary of errors, diffs, and permission outputs
1230 fef9b495 2025-05-31 xs ***Usage:***
1235 fef9b495 2025-05-31 xs ## Digraph output
1237 fef9b495 2025-05-31 xs 1. [digraph-host](#digraph-host)
1238 fef9b495 2025-05-31 xs 2. [digraph-ssh-id-hosts](#digraph-ssh-id-hosts)
1242 fef9b495 2025-05-31 xs ### digraph-host
1244 fef9b495 2025-05-31 xs ***Description:***
1245 fef9b495 2025-05-31 xs Returns a directed graph (in DOT format) showing relations among groups, functions, and nodes
1247 fef9b495 2025-05-31 xs ***Usage:***
1249 fef9b495 2025-05-31 xs digraph-host
1252 fef9b495 2025-05-31 xs ### digraph-ssh-id-hosts
1254 fef9b495 2025-05-31 xs ***Description:***
1255 fef9b495 2025-05-31 xs Returns a directed graph (in DOT format) of relations between SSH IDs and hosts
1257 fef9b495 2025-05-31 xs ***Usage:***
1259 fef9b495 2025-05-31 xs digraph-ssh-id-hosts
1262 730e151b 2025-06-02 xs ## HTML output
1264 730e151b 2025-06-02 xs 1. [html](#html)
1268 730e151b 2025-06-02 xs ***Description:***
1269 f6bdfddc 2025-06-03 xs Retunrs a report page with the content of `README.md` in HTML format
1271 730e151b 2025-06-02 xs ***Usage:***
1278 3aa5672d 2025-06-04 xs ## Node importing
1280 3aa5672d 2025-06-04 xs 1. [import](#import)
1284 3aa5672d 2025-06-04 xs ***Description:***
1285 3aa5672d 2025-06-04 xs Import configuration files from a target host
1287 3aa5672d 2025-06-04 xs ***Usage:***
1294 688c9bfd 2025-06-03 xs ## Technical notes
1296 688c9bfd 2025-06-03 xs - Supported shells are ksh93, oksh, yash and bash.
1298 688c9bfd 2025-06-03 xs - Supported platforms are OpenBSD, FreeBSD, NetBSD and GNU/Linux.
1300 688c9bfd 2025-06-03 xs - Busybox support is planned.
1302 688c9bfd 2025-06-03 xs - Optional dependencies are openrsync, rsync, column, graphviz and pandoc.
1304 688c9bfd 2025-06-03 xs - The HTML output is a work in progress.
1310 f976c0b3 2025-06-05 xs The provided group library is shared as additionnal examples of the
1311 f976c0b3 2025-06-05 xs documentation and contain the following third-party files under the ISC License.
1312 f976c0b3 2025-06-05 xs Copyright information are indicated in the LICENSE section of related files.
1314 f976c0b3 2025-06-05 xs - `pf-badhost.sh`
1315 f976c0b3 2025-06-05 xs - `unbound-adblock.sh`
1316 f976c0b3 2025-06-05 xs - `http-ban.sh`
1318 8b145b67 2025-06-04 xs The project is shared under the terms of the ISC license. Any version previous
1319 8b145b67 2025-06-04 xs `0.1.0` needs to be considered obsolete and should not be redistributed. History
1320 8b145b67 2025-06-04 xs in the GIT repository is kept for transparency purpose only.
1322 8b145b67 2025-06-04 xs Below is a copy of the applicable license:
1326 8b145b67 2025-06-04 xs Copyright 2025 xs <xs@inda.re>
1328 8b145b67 2025-06-04 xs Permission to use, copy, modify, and/or distribute this software for any
1329 8b145b67 2025-06-04 xs purpose with or without fee is hereby granted, provided that the above
1330 8b145b67 2025-06-04 xs copyright notice and this permission notice appear in all copies.
1332 8b145b67 2025-06-04 xs THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1333 8b145b67 2025-06-04 xs REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
1334 8b145b67 2025-06-04 xs FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1335 8b145b67 2025-06-04 xs INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1336 8b145b67 2025-06-04 xs LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1337 8b145b67 2025-06-04 xs OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1338 8b145b67 2025-06-04 xs PERFORMANCE OF THIS SOFTWARE.