Blob


1 '\" t
2 .\" Automatically generated by Pandoc 3.6.2
3 .\"
4 .TH "R7" "1" "Tue Jun 3 2025" "v0.1.3" "User Manual"
5 .SS Tutorial
6 .SS Introduction
7 R7 is a configuration management framework made to configure nodes with
8 configuration files and related operations versionned in a central
9 repository.
10 To remain code versionning system agnostic, manual or automated
11 versionning is left to the user, via makefiles or triggered from r7
12 \f[CR]site\-config\f[R] configuration file \f[I](See below)\f[R].
13 .PP
14 The idea is to store hosts configurations in \f[CR]nodes/hostname\f[R]
15 directories that maps each host\[cq]s \f[CR]/etc\f[R] and to assign
16 those hosts to configuration groups containing the directives to install
17 the configuration and potential requirements.
18 .PP
19 \f[I]Nodes sub\-directories are hostnames understood by the ssh client
20 and configuration.\f[R]
21 .PP
22 \f[I]Currently, r7 requires valid ssh configuration and keyfiles in the
23 repository \f[CI].ssh/\f[I] directory.\f[R]
24 .PP
25 \f[I]Repositories can be initialized with \f[CI]rset init\f[I] or
26 \f[CI]rset \-w path/to/new\-repository init\f[I], the user will then
27 have to provide valid configurations and keys for \f[CI].ssh/\f[I] in
28 the newly created directory.\f[R]
29 .PP
30 \f[I]See Technical Notes for dependencies and supported platforms.\f[R]
31 .PP
32 There is an example of r7 repository:
33 .IP
34 .EX
35 \&./nodes/
36 \&./nodes/hostA
37 \&./nodes/hostB
38 \&./nodes/hostC
39 \&./groups/
40 \&./groups/common
41 \&./groups/test0
42 \&./groups/common.dir
43 \&./groups/test0.dir
44 \&./.ssh/
45 \&./.ssh/config
46 \&./.ssh/id_ed25519_r7
47 \&./.ssh/id_ed25519_r7.pub
48 \&./site\-config
49 .EE
50 .PP
51 There is an example of r7 site configuration (\f[CR]site\-config\f[R]
52 file):
53 .IP
54 .EX
55 prefix install state doc
56 group common \[aq].*\[aq]
57 group test0 hostB hostC
58 output\-dump
59 summary
60 .EE
61 .PP
62 There is an exemple of the deployment of that configuration within the
63 r7 repository:
64 .IP
65 .EX
66 $ r7 run\-config
67 \- (ok) hostA:common::install_nothing
68 \- (ok) hostA:common::state_uname
69 \- (ok) hostA:common::doc_tutorial
70 \- (ok) hostB:common::install_nothing
71 \- (ok) hostB:common::state_uname
72 \- (ok) hostB:common::doc_tutorial
73 \- (ok) hostC:common::install_nothing
74 \- (ok) hostC:common::state_uname
75 \- (ok) hostC:common::doc_tutorial
76 \- (ok) hostB:test0::state_test
77 \- (ok) hostC:test0::state_test
78 .EE
79 .PP
80 In this example, everything goes fine, groups are executed on each
81 related nodes, note the \f[CR]\[aq].*\[aq]\f[R] matching all hosts
82 present in \f[CR]./nodes\f[R].
83 Groups are POSIX shell scripts that are a collection of functions.
84 .PP
85 There is the \f[CR]common\f[R] group:
86 .IP
87 .EX
88 install_nothing() \f[B]{\f[R]
89 echo Nothing installed
90 \f[B]}\f[R]
92 state_uname() \f[B]{\f[R]
93 uname \-a
94 \f[B]}\f[R]
96 doc_tutorial() \f[B]{\f[R]
97 echo \[dq]## Welcome to the R7 tutorial!\[dq]
98 \f[B]}\f[R]
99 .EE
100 .PP
101 And there is the \f[CR]test0\f[R] group:
102 .IP
103 .EX
104 state_test() \f[B]{\f[R]
105 test 1 \-eq 1
106 \f[B]}\f[R]
107 .EE
108 .PP
109 Any function managed by \f[CR]r7\f[R] needs to be declared in the format
110 \f[CR]\[ha]PREFIX_NAME()\f[R].
111 .PP
112 Group files names can\[cq]t contain spaces, tabs or newlines, as well
113 for nodes dirnames.
114 \f[I]The `:' character is not recommanded as well as it may reduce
115 lisibility of the interactive output.\f[R]
116 .PP
117 Called groups and node directories are copied to related nodes in
118 \f[CR]hostname:/tmp/r7/\f[R]:
119 .IP
120 .EX
121 /tmp/r7/hostA/ # Contents of test.org/nodes/hostA/
122 /tmp/r7/common.dir # Contents of test.org/groups/common.dir/
123 /tmp/r7/test.dir # Contents of test.org/groups/test.dir
124 .EE
125 .PP
126 Groups may have no \f[CR].dir\f[R] directory, in this case, nothing is
127 copied.
128 .PP
129 Once the group copy is done, functions are executed in the order of the
130 defined prefix (part of the \f[CR]site\-config\f[R] file shown before):
131 .IP
132 .EX
133 prefix install state doc
134 .EE
135 .PP
136 This means the functions matching \f[CR]\[ha]install_.*()\f[R],
137 \f[CR]\[ha]state_.*()\f[R] and \f[CR]\[ha]doc_.*()\f[R] (the default
138 \f[CR]R7_PREFIX\f[R]) in the respective declaration order they\[cq]re
139 found in the related group file will be executed.
140 .PP
141 Site confiurations are shell scripts sourced by r7 after it\[cq]s
142 environment is initialized, so \f[CR]prefix\f[R], \f[CR]group\f[R],
143 \f[CR]output\-dump\f[R], \f[CR]summary\f[R] are the functions or aliases
144 provided by r7 itself.
145 This allow for scripting from the \f[CR]site\-config\f[R] file.
146 Here \f[CR]output\-dump\f[R], and \f[CR]summary\f[R] are called to
147 output potential errors, diffs and permissions changes at the end of the
148 interactive output obtained by \f[CR]r7 run\-config\f[R].
149 If nothing catched happened, nothing is added to the output.
150 .SS Errors during remote execution of groups
151 In our previous example, we modify \f[CR]state_test\f[R] so the
152 \f[CR]test\f[R] fails.
153 .IP
154 .EX
155 state_test() \f[B]{\f[R]
156 test 1 \-eq 2
157 \f[B]}\f[R]
158 .EE
159 .PP
160 And we re\-run the configuration to see what\[cq]s happenning.
161 .IP
162 .EX
163 $ r7 run\-config
164 \- (ok) hostA:common::install_nothing
165 \- (ok) hostA:common::state_uname
166 \- (ok) hostA:common::doc_tutorial
167 \- (ok) hostB:common::install_nothing
168 \- (ok) hostB:common::state_uname
169 \- (ok) hostB:common::doc_tutorial
170 \- (ok) hostC:common::install_nothing
171 \- (ok) hostC:common::state_uname
172 \- (ok) hostC:common::doc_tutorial
173 \- (error 1) hostB:test0::state_test
174 \- (error 1) hostC:test0::state_test
175 \- (error 1) \- in hostB test0 state_test (1748622980)
176 \- (error 1) \- in hostC test0 state_test (1748622980)
177 .EE
178 .PP
179 The last two lines are part of the \f[CR]summary\f[R] output.
180 .PP
181 Let\[cq]s modify the \f[CR]state_test\f[R] function again to add some
182 verbosity to it\[cq]s output.
183 .PP
184 \f[I]Note that we also change the return value.\f[R]
185 .IP
186 .EX
187 state_test() \f[B]{\f[R]
188 echo something
189 false \f[B]||\f[R] \f[B]{\f[R]
190 echo >&2 failed
191 \f[B]return\f[R] 22
192 \f[B]}\f[R]
193 \f[B]}\f[R]
194 .EE
195 .PP
196 This will produce the following summary:
197 .IP
198 .EX
199 \- (error 22) \- in hostB test0 state_test (1748622980)
201 something
202 failed
204 \- (error 22) \- in hostC test0 state_test (1748622980)
206 something
207 failed
208 .EE
209 .PP
210 Diffs and permissions changes are also displayed by the
211 \f[CR]summary\f[R] command.
212 When they\[cq]re are detected, the captured related output is shown.
213 .SS Repository initialisation
214 Using the \f[CR]init\f[R] command, we can specify the current or a
215 specifed work directory to be created and act as an r7 repository.
216 .PP
217 \f[I]Automated versionning of outputs are currently let to the user, a
218 recommended place would be the end of the site configuration file.\f[R]
219 .PP
220 This command initializes a new directory called \f[CR]test.org\f[R]:
221 .IP
222 .EX
223 r7 \-w test.org init
224 cd test.org
225 .EE
226 .PP
227 Once this step is done, it is required to:
228 .IP \[bu] 2
229 Copy or initialize the ssh key to the \f[CR].ssh\f[R] folder in the
230 repository created in \f[CR].ssh/id_ed25519\-r7\f[R] and
231 \f[CR]./ssh/id_ed25519\-r7.pub\f[R]
232 .IP \[bu] 2
233 Adjust the SSH client configuration file in the repository
234 \f[CR].ssh/config\f[R]
235 .PP
236 \f[I]Note that it is possible to import additionnal SSH configurations,
237 like the user one from the SSH configuration, but it is advised to keep
238 them separate.\f[R]
239 .SS SSH agent handling
240 The function \f[CR]unlock\f[R] can be used to set the SSH agent
241 environement, this will be required for any automated operation later
242 done by r7:
243 .IP
244 .EX
245 cd test.org
246 \&. $(command \-v r7) \f[I]# Sourcing r7\f[R]
247 unlock
248 tmux \f[B]||\f[R] screen
249 .EE
250 .PP
251 \f[I]\f[BI]\f[B]Warning:\f[BI]\f[I] Unlock will terminate any running
252 \f[CI]ssh\-agent\f[I] instances.\f[R]
253 .SS Adding new hosts
254 For adding a new host, the simplest way is to have pre\-configured
255 \f[CR]authorized_keys\f[R] for the target user, it is then required to
256 add it to the \f[CR]known_hosts\f[R] file.
257 For that, it is possible to use r7 SSH functions:
258 .IP
259 .EX
260 \&. $(command \-v r7) \f[I]# Sourcing r7\f[R]
261 ssh\-accept\-new hostname
262 .EE
263 .PP
264 If resetting the target\[cq]s user \f[CR]authorized_keys\f[R] file is
265 needed, the following function can be used:
266 .IP
267 .EX
268 \&. $(command \-v r7) \f[I]# Sourcing r7\f[R]
269 ssh\-authorized\-keys\-reset hostname
270 .EE
271 .PP
272 \f[I]\f[BI]Warning:\f[I] This will resets the SSH authorized_keys file
273 for the target user (root, by default) and put the
274 \f[CI].ssh/id_ed25519\-r7.pub\f[I] in place.\f[R]
275 .PP
276 Once the host is accepted in the \f[CR]known_hosts\f[R] file, it\[cq]s
277 possible to import it automatically.
278 .SS Importing hosts configurations
279 \f[I]This feature currently only support OpenBSD.\f[R]
280 .PP
281 Avoiding to import the configuration manually is possible with the
282 \f[CR]import\f[R] command:
283 .IP
284 .EX
285 r7 import hostname
286 .EE
287 .PP
288 Most common configuration files will be copied in a newly created
289 \f[CR]nodes/hostname\f[R] sub\-directory.
290 .SS Writing group files
291 Group files collects fonctions related to the configuration of the
292 operating system, networking, services, global and user configurations
293 packages installations and application deployments.
294 .PP
295 By specifying the execution prefix, the user determines the order of
296 execution of the functions declared in the group file.
297 .IP
298 .EX
299 service_A() \f[B]{\f[R]
300 service A enable
301 service A restart
302 \f[B]}\f[R]
304 service_B() \f[B]{\f[R]
305 service B enable
306 service B restart
307 \f[B]}\f[R]
309 state_A() \f[B]{\f[R]
310 service A status
311 \f[B]}\f[R]
313 doc_A() \f[B]{\f[R]
314 echo \[dq]## Service A\[dq]
315 echo
316 echo \[dq]\- [url](http://test.org/)\[dq]
317 echo
318 \f[B]}\f[R]
319 .EE
320 .PP
321 \f[I]\f[BI]file\f[I]: \f[CI]groups/example1\f[I]\f[R]
322 .PP
323 With the default prefix, \f[CR]install\f[R], \f[CR]state\f[R],
324 \f[CR]doc\f[R], the fonction that will be executed are
325 \f[CR]state_A\f[R] and \f[CR]doc_A\f[R].
326 To test that group file with all the functions inside we can call r7 the
327 following way:
328 .IP
329 .EX
330 r7 \-P \[aq]service state doc\[aq] group example1 hostname
331 .EE
332 .PP
333 Or using the \f[CR]\-a\f[R] flag which will create a prefix
334 automatically with all functions present in the group file:
335 .IP
336 .EX
337 r7 \-a group example1 hostname
338 .EE
339 .PP
340 In a real situation, this example will have failing functions because
341 the \f[CR]service\f[R] command may not be found or the services named
342 \f[CR]A\f[R] or \f[CR]B\f[R] does not exist.
343 .IP
344 .EX
345 ! (error 127) tools0:example1::service_A
346 ! (error 127) tools0:example1::service_B
347 ! (error 127) tools0:example1::state_A
348 \- (ok) tools0:example1::doc_A
349 .EE
350 .PP
351 We could force the group execution to stop using a combination of the
352 \f[CR]\-e\f[R] flag and the \f[CR]error\f[R] group function.
353 .IP
354 .EX
355 service_A() \f[B]{\f[R]
356 service A enable \f[B]&&\f[R]
357 service A restart \f[B]||\f[R]
358 error unable to setup service A
359 \f[B]}\f[R]
361 service_B() \f[B]{\f[R]
362 service B enable \f[B]&&\f[R]
363 service B restart \f[B]||\f[R]
364 error unable to setup service B
365 \f[B]}\f[R]
367 state_A() \f[B]{\f[R]
368 service A status
369 \f[B]}\f[R]
371 doc_A() \f[B]{\f[R]
372 echo \[dq]## Service A\[dq]
373 echo
374 echo \[dq]\- [url](http://test.org/)\[dq]
375 echo
376 \f[B]}\f[R]
377 .EE
378 .PP
379 \f[I]\f[BI]file:\f[I] \f[CI]groups/example2\f[I]\f[R]
380 .PP
381 Let\[cq]s run the updated example with the \f[CR]\-s\f[R] flag to
382 trigger the summary output.
383 .IP
384 .EX
385 rm \-fr _output
386 r7 \-sea group example2 hostname
387 .EE
388 .PP
389 This will produce something like the following:
390 .IP
391 .EX
392 ! (error) tools0:example2::service_A
393 ! (exit) tools0:example2::service_A
394 \- (error 127) \- in tools0 example2 service_A (1748791986)
396 /bin/sh: <stdin>[155]: service: not found
397 :: 1748791986 tools0 ERROR unable to setup service A
398 .EE
399 .SS Using the r7 install functions
400 The group library comes with the following functions that will allow
401 installation of files and triggering actions if necessary:
402 \f[CR]install\f[R], \f[CR]groupinstall\f[R], \f[CR]nodeinstall\f[R].
403 They are all shortcuts to an internal \f[CR]r7_install\f[R] function,
404 it\[cq]s just the wrappers changes directory to respectively
405 \f[CR]/tmp/r7\f[R], \f[CR]/tmp/r7/groupname.dir/\f[R] and
406 \f[CR]/tmp/r7/hostname/\f[R].
407 .PP
408 If we want to install files from the group directory we will use
409 something like:
410 .IP
411 .EX
412 install_program() \f[B]{\f[R]
413 groupinstall \-m 755 \-o root:bin my_program /usr/local/bin
414 \f[B]}\f[R]
415 .EE
416 .PP
417 \f[I]We are supposing to have the file
418 \f[CI]groups/example3.dir/my_program\f[I]\f[R]
419 .PP
420 And if it\[cq]s something from node, we should use:
421 .IP
422 .EX
423 install_program_config() \f[B]{\f[R]
424 nodeinstall \-m 644 \-o root:wheel my_config /etc
425 \f[B]}\f[R]
426 .EE
427 .PP
428 We can now chain the \f[CR]install\f[R] functions to configuration
429 checking and initialization of programs, services or network features
430 like in the following example, in which we install \f[CR]ntp.conf\f[R]
431 from the deployed node directory to \f[CR]/etc\f[R]:
432 .IP
433 .EX
434 service_ntpd() \f[B]{\f[R]
435 nodeinstall \-m 644 \-o root:wheel ntpd.conf /etc \f[B]&&\f[R]
436 ntpd \-n \f[B]&&\f[R]
437 rcctl enable ntpd \f[B]&&\f[R]
438 rcctl restart ntpd
439 \f[B]}\f[R]
440 .EE
441 .SS Using the r7 node function
442 We may want to avoid executing a function or parts of it if the node has
443 no related files before executing the installation and actions handling
444 parts.
445 This can be done with the help of the \f[CR]node\f[R] function.
446 .IP
447 .EX
448 service_ntpd() \f[B]{\f[R]
449 node ntpd.conf \f[B]&&\f[R]
450 nodeinstall \-m 644 \-o root:wheel ntpd.conf /etc \f[B]&&\f[R]
451 ntpd \-n \f[B]&&\f[R]
452 rcctl enable ntpd \f[B]&&\f[R]
453 rcctl restart ntpd
454 \f[B]}\f[R]
455 .EE
456 .PP
457 Here, \f[CR]node\f[R] will return \f[CR]31\f[R] if there is no file or
458 directory called \f[CR]ntpd.conf\f[R] inside the deployed node directory
459 (\f[CR]/tmp/r7/hostname\f[R]).
460 .PP
461 \f[CR]0\f[R], \f[CR]30\f[R] and \f[CR]31\f[R] exit codes are ignored
462 when r7 will search for execution errors.
463 This means \f[CR]30\f[R] and \f[CR]31\f[R] exit code are reserved to r7.
464 .PP
465 In other terms, this will update the NTP daemon configuration only if
466 \f[CR]ntpd.conf\f[R] is present in the node directory, otherwise it is
467 kept by default, which is the system provided default
468 \f[CR]ntpd.conf\f[R].
469 .SS Sourcing specific files
470 Here\[cq]s an example how to source additionnal shell from the deployed
471 node directory, or elsewhere:
472 .IP
473 .EX
474 service_sysrc() \f[B]{\f[R]
475 sysrc dumpdev=NO
476 sysrc kld_list=\[dq]vmm if_tuntap if_bridge nmdm\[dq]
477 sysrc microcode_update_enable=YES
478 sysrc mountd_enable=YES
479 sysrc nfs_server_enable=YES
480 sysrc ntpdate_enable=YES
481 sysrc powerd_enable=YES
482 sysrc rcshutdown_timeout=900
483 sysrc rpcbind_enable=YES
484 sysrc sshd_enable=YES
485 sysrc zfs_enable=YES
486 nodesource sysrc.local
487 \f[B]}\f[R]
488 .EE
489 .PP
490 In this FreeBSD example, we configure the system RC globally with
491 \f[CR]service_sysrc\f[R] which apply, if \f[CR]sysrc.local\f[R] is found
492 in the root of the node directory, it\[cq]s sourcing in the current
493 scope via the help of \f[CR]nodesource sysrc.local\f[R].
494 .PP
495 The file \f[CR]nodes/hostname/sysrcl.local\f[R] contains the following:
496 .IP
497 .EX
498 sysrc ifconfig_igb0=DHCP
499 sysrc ifconfig_igb1=up
500 .EE
501 .SS Other examples
502 Inside the r7 release, a small example groups library can be found in
503 the \f[CR]groups\f[R] directory, that can also be browsed in the \c
504 .UR https://got.inda.re/?action=summary&path=r7.git
505 repository
506 .UE \c
507 \&.
508 .SS System shell profile
509 Here we install the \f[CR]profile\f[R] file provided in the
510 \f[CR]groupname.dir\f[R] directory or the profile provided by the node
511 directory:
512 .IP
513 .EX
514 setup_profile() \f[B]{\f[R]
515 groupinstall \-m 644 \-o root:wheel profile /etc
516 node profile \f[B]&&\f[R]
517 nodeinstall \-m 644 \-o root:wheel profile /etc
518 \f[B]}\f[R]
519 .EE
520 .SS Users
521 Here we add new users:
522 .IP
523 .EX
524 setup_users() \f[B]{\f[R]
525 useradd user1 2>/dev/null \f[B]||\f[R] :
526 useradd user2 2>/dev/null \f[B]||\f[R] :
527 \f[B]}\f[R]
528 .EE
529 .SS Crontab
530 In the following example, we install a script and call it from a
531 dedicated user crontab.
532 .IP
533 .EX
534 mail_admins=admins\[at]test.org
536 install_myscript() \f[B]{\f[R]
537 groupinstall \-o root:bin \-m 755 myscript /usr/local/bin \f[B]&&\f[R]
538 useradd \-d /var/empty \-s /sbin/nologin _myscript
539 crontab \-u _myscript \- <<\-/
540 MAILTO=$mail_admins
541 */5 * * * * myscript
544 .EE
545 .SS Consulting the output
546 After the execution is done, the result are saved in the \f[CR]_run\f[R]
547 directory, \f[CR]output\-dump\f[R] needs to be called to produce the
548 current \f[CR]_output\f[R] structure.
549 .PP
550 The r7 \f[CR]output\f[R] command can then be used to show specific
551 output groups or functions:
552 .IP
553 .EX
554 r7 output
555 .EE
556 .PP
557 Will show the whole output of the latest groups deployments.
558 .PP
559 This format can be used to match specific host, group or function:
560 .IP
561 .EX
562 r7 output [hostname [groupname [funcname]]]
563 .EE
564 .PP
565 For example:
566 .IP
567 .EX
568 $ r7 output tools0 OpenBSD state_packages\[rs]*
569 \- tools0 OpenBSD state_packages_upgrades
571 quirks\-7.103 signed on 2025\-05\-30T01:12:03Z
573 \- tools0 OpenBSD state_packages_repository
575 https://cdn.openbsd.org/pub/OpenBSD
576 .EE
577 .PP
578 \f[I]Note that the \f[CI]output\f[I] function arguments are using
579 shell\[cq]s case globbing patterns.\f[R]
580 .SS r7 command line
581 \f[B]\f[BI]Usage:\f[B]\f[R]
582 .IP
583 .EX
584 r7 [options] [command [arguments...]]
585 .EE
586 .SS Options
587 .IP \[bu] 2
588 \f[B]\-h\f[R] Show usage and exit
589 .IP \[bu] 2
590 \f[B]\-d\f[R] Enable debug mode
591 .IP \[bu] 2
592 \f[B]\-i\f[R] Specify the SSH identity file
593 .IP \[bu] 2
594 \f[B]\-F\f[R] Specify the SSH client configuration file
595 .IP \[bu] 2
596 \f[B]\-w\f[R] Set the work directory where \f[CR]./nodes\f[R] and
597 \f[CR]./groups\f[R] can be found
598 .IP \[bu] 2
599 \f[B]\-r\f[R] Set the run directory (default: \f[CR]./_run\f[R])
600 .IP \[bu] 2
601 \f[B]\-o\f[R] Set the output directory (default: \f[CR]./_output\f[R])
602 .IP \[bu] 2
603 \f[B]\-c\f[R] Specify the site configuration file (default:
604 \f[CR]./site\-config\f[R])
605 .IP \[bu] 2
606 \f[B]\-n\f[R] Enable dry run mode; prevents any modification on hosts
607 .IP \[bu] 2
608 \f[B]\-e\f[R] Exit the group execution on the error function
609 .IP \[bu] 2
610 \f[B]\-p\f[R] Run each host in parallel per group call
611 .IP \[bu] 2
612 \f[B]\-O\f[R] Show output interactively
613 .IP \[bu] 2
614 \f[B]\-P\f[R] Specify a prefix
615 .IP \[bu] 2
616 \f[B]\-a\f[R] Select all available prefixes for a group command
617 .IP \[bu] 2
618 \f[B]\-s\f[R] Apply output\-dump and summary after a group command
619 .SS Commands
620 .PP
621 .TS
622 tab(@);
623 lw(18.7n) lw(51.3n).
624 T{
625 Name
626 T}@T{
627 Description
628 T}
630 T{
631 \f[B]run\-config\f[R]
632 T}@T{
633 Run the site configuration
634 T}
635 T{
636 \f[B]group\f[R]
637 T}@T{
638 Deploy specified group to hosts
639 T}
640 T{
641 \f[B]output\-dump\f[R]
642 T}@T{
643 Dump the run directory to the output directory
644 T}
645 T{
646 \f[B]output\f[R]
647 T}@T{
648 Consult the output
649 T}
650 T{
651 \f[B]summary\f[R]
652 T}@T{
653 Produce a summary of errors and changes
654 T}
655 T{
656 \f[B]digraph\-host\f[R]
657 T}@T{
658 Produce a dot digraph for hosts
659 T}
660 T{
661 \f[B]digraph\-ssh\f[R]
662 T}@T{
663 Produce a dot digraph of SSH ID\[cq]s, users and nodes relations
664 T}
665 T{
666 \f[B]import\f[R]
667 T}@T{
668 Import TARGET host in the current nodes directory
669 T}
670 T{
671 \f[B]info\f[R]
672 T}@T{
673 Default command showing active nodes and summary
674 T}
675 T{
676 \f[B]init\f[R]
677 T}@T{
678 Initialize a new work directory
679 T}
680 .TE
681 .SS Environment
682 .PP
683 .TS
684 tab(@);
685 lw(9.7n) lw(31.4n) lw(29.0n).
686 T{
687 Name
688 T}@T{
689 Default value
690 T}@T{
691 Description
692 T}
694 T{
695 R7_DEBUG
696 T}@T{
697 no
698 T}@T{
699 Enable debug mode
700 T}
701 T{
702 R7_DRYRUN
703 T}@T{
704 no
705 T}@T{
706 Enable dry\-run mode
707 T}
708 T{
709 R7_GROUP_ALLPREFIX
710 T}@T{
711 no
712 T}@T{
713 Group selects all available prefix
714 T}
715 T{
716 R7_GROUP_SUMMARY
717 T}@T{
718 no
719 T}@T{
720 Enable output\-dump and summary after group execution
721 T}
722 T{
723 R7_GROUP_EXITONERROR
724 T}@T{
725 no
726 T}@T{
727 Enable exit on error function
728 T}
729 T{
730 R7_PARALLEL
731 T}@T{
732 no
733 T}@T{
734 Enable group nodes parallel execution
735 T}
736 T{
737 R7_PREFIX
738 T}@T{
739 install state doc
740 T}@T{
741 Set the r7 group execution prefix
742 T}
743 T{
744 R7_SHOWOUTPUT
745 T}@T{
746 no
747 T}@T{
748 Show interactive output
749 T}
750 T{
751 R7_WORKDIR
752 T}@T{
753 PWD
754 T}@T{
755 Set the r7 repository path
756 T}
757 T{
758 R7_SITE_CONFIG
759 T}@T{
760 R7_WORKDIR/site\-config
761 T}@T{
762 Set the r7 \f[CR]site\-config\f[R] path
763 T}
764 T{
765 R7_OUTPUTDIR
766 T}@T{
767 R7_WORKDIR/_output
768 T}@T{
769 Set the r7 output directory path
770 T}
771 T{
772 SSH_CONFIG_DIR
773 T}@T{
774 R7_WORKDIR/.ssh
775 T}@T{
776 Set the SSH configuration directory path
777 T}
778 T{
779 SSH_CONFIG_FILE
780 T}@T{
781 R7_WORKDIR/.ssh/config
782 T}@T{
783 Set the SSH configuration file path
784 T}
785 T{
786 SSH_CONTROL_DIR
787 T}@T{
788 SSH_CONFIG_DIR/control
789 T}@T{
790 Set the SSH control dir path
791 T}
792 T{
793 SSH_IDENTITY_FILE
794 T}@T{
795 R7_WORKDIR/.ssh/id_ed25519_r7
796 T}@T{
797 Set the SSH identity file
798 T}
799 T{
800 SSH_KNOWN_HOSTS
801 T}@T{
802 R7_WORKDIR/.ssh/known_hosts
803 T}@T{
804 Set the SSH known hosts file
805 T}
806 T{
807 SSH_CONNECT_TIMEOUT
808 T}@T{
810 T}@T{
811 Set the SSH connect timeout
812 T}
813 .TE
814 .SS Group variables
815 Those variables are available during the execution of th group
816 file\[cq]s functions.
817 .PP
818 .TS
819 tab(@);
820 l l.
821 T{
822 Name
823 T}@T{
824 Description
825 T}
827 T{
828 trace_id
829 T}@T{
830 Current run trace ID
831 T}
832 T{
833 groupname
834 T}@T{
835 Current group name being executed
836 T}
837 T{
838 exitonerror
839 T}@T{
840 Cause the error function to exit if equals \f[CR]yes\f[R]
841 T}
842 T{
843 nodename
844 T}@T{
845 Contains the output of \f[CR]nodename\f[R]
846 T}
847 T{
848 nodedir
849 T}@T{
850 Contains the output of \f[CR]nodedir\f[R]
851 T}
852 T{
853 groupdir
854 T}@T{
855 Contains the output of \f[CR]groupdir\f[R]
856 T}
857 .TE
858 .SS Group functions
859 Those functions are accessible during the execution of the group
860 file\[cq]s functions.
861 Non documented functions are reserved for internal use.
862 .IP " 1." 4
863 trace
864 .IP " 2." 4
865 error
866 .IP " 3." 4
867 node
868 .IP " 4." 4
869 nodename
870 .IP " 5." 4
871 nodedir
872 .IP " 6." 4
873 groupdir
874 .IP " 7." 4
875 install
876 .IP " 8." 4
877 groupinstall
878 .IP " 9." 4
879 nodeinstall
880 .IP "10." 4
881 installdir
882 .IP "11." 4
883 groupinstalldir
884 .IP "12." 4
885 nodeinstalldir
886 .IP "13." 4
887 source
888 .IP "14." 4
889 groupsource
890 .IP "15." 4
891 nodesource
892 .PP
893 * * * * *
894 .SS trace
895 \f[B]\f[BI]Description:\f[B]\f[R] Append a trace containing the current
896 node name and \f[CR]trace_id\f[R]
897 .PP
898 \f[B]Usage:\f[R]
899 .IP
900 .EX
901 trace [string...]
902 .EE
903 .SS error
904 \f[B]\f[BI]Description:\f[B]\f[R] Trace an error message that will
905 inform the user of an event in the summary output, exit the group
906 execution if \f[CR]\-e\f[R] is set
907 .PP
908 \f[B]Usage:\f[R]
909 .IP
910 .EX
911 error [string...]
912 .EE
913 .SS node
914 \f[B]\f[BI]Description:\f[B]\f[R] Returns true if the argument is an
915 existing file or directory inside \f[CR]/tmp/r7/$(nodename)\f[R], else,
916 returns 31
917 .PP
918 \f[B]\f[BI]Usage:\f[B]\f[R]
919 .IP
920 .EX
921 node [filename\f[B]|\f[R]dirname]
922 .EE
923 .SS nodename
924 \f[B]\f[BI]Description:\f[B]\f[R] Returns the small hostname of the
925 current host
926 .PP
927 \f[B]\f[BI]Usage:\f[B]\f[R]
928 .IP
929 .EX
930 nodename
931 .EE
932 .SS nodedir
933 \f[B]\f[BI]Description:\f[B]\f[R] Returns \f[CR]/tmp/r7/$(nodename)\f[R]
934 .PP
935 \f[B]\f[BI]Usage:\f[B]\f[R]
936 .IP
937 .EX
938 nodename
939 .EE
940 .SS groupdir
941 \f[B]\f[BI]Description:\f[B]\f[R] Returns
942 \f[CR]/tmp/r7/$groupname.dir\f[R]
943 .PP
944 \f[B]\f[BI]Usage:\f[B]\f[R]
945 .IP
946 .EX
947 groupdir
948 .EE
949 .SS install
950 \f[B]\f[BI]Description:\f[B]\f[R] Change directory to \f[CR]/tmp/r7\f[R]
951 and install files if changed and sets mode and owner, returns true if
952 the file changed, otherwise returns 30
953 .PP
954 \f[B]\f[BI]Usage:\f[B]\f[R]
955 .IP
956 .EX
957 install [\-o owner] [\-m mode] source destintaion
958 .EE
959 .SS groupinstall
960 \f[B]\f[BI]Description:\f[B]\f[R] Change directory to the current group
961 \f[CR].dir\f[R] directory in \f[CR]/tmp/r7\f[R] then performs like
962 \f[CR]install\f[R]
963 .PP
964 \f[B]\f[BI]Usage:\f[B]\f[R]
965 .IP
966 .EX
967 groupinstall [\-o owner] [\-m mode] source destintaion
968 .EE
969 .SS nodeinstall
970 \f[B]\f[BI]Description:\f[B]\f[R] Change directory to the current node
971 directory in \f[CR]/tmp/r7\f[R] then performs like \f[CR]install\f[R]
972 .PP
973 \f[B]\f[BI]Usage:\f[B]\f[R]
974 .IP
975 .EX
976 nodeinstall [\-o owner] [\-m mode] source destintaion
977 .EE
978 .SS installdir
979 \f[B]\f[BI]Description:\f[B]\f[R] Install directory calling
980 \f[CR]install\f[R] for each file and checking for permissions changes.
981 .PP
982 \f[B]\f[BI]Usage:\f[B]\f[R]
983 .IP
984 .EX
985 installdir [\-o fileowner] [\-m filemode] [\-O dirowner] [\-O dirmode] source
986 destination
987 .EE
988 .SS groupinstalldir
989 \f[B]\f[BI]Description:\f[B]\f[R] Change directory to the current group
990 directoy then call installdir
991 .PP
992 \f[B]\f[BI]Usage:\f[B]\f[R]
993 .IP
994 .EX
995 groupinstalldir [\-o fileowner] [\-m filemode] [\-O dirowner] [\-O dirmode] source
996 destination
997 .EE
998 .SS nodeinstalldir
999 \f[B]\f[BI]Description:\f[B]\f[R] Change directory to the current group
1000 directoy then call installdir
1001 .PP
1002 \f[B]\f[BI]Usage:\f[B]\f[R]
1003 .IP
1004 .EX
1005 nodeinstalldir [\-o fileowner] [\-m filemode] [\-O dirowner] [\-O dirmode] source
1006 destination
1007 .EE
1008 .SS source
1009 \f[B]\f[BI]Description:\f[B]\f[R] Source a POSIX shell file in the
1010 current execution
1011 .PP
1012 \f[B]\f[BI]Usage:\f[B]\f[R]
1013 .IP
1014 .EX
1015 source filename
1016 .EE
1017 .SS groupsource
1018 \f[B]\f[BI]Description:\f[B]\f[R] Change directory to the current group
1019 directory then call source with the file name as argument, produces an
1020 error if filename is not found from the group directory
1021 .IP
1022 .EX
1023 groupsource filename
1024 .EE
1025 .SS nodesource
1026 \f[B]\f[BI]Description:\f[B]\f[R] Change directory to the current group
1027 directory then call node and source with the file name as argument
1028 without producing an error if the filename is not found
1029 .IP
1030 .EX
1031 nodesource filename
1032 .EE
1033 .SH r7 library
1034 Usable from the r7 \f[CR]site\-config\f[R] file or sourced in the
1035 current shell using:
1036 .IP
1037 .EX
1038 \&. $(command \-v r7)
1039 .EE
1040 .PP
1041 Each functions are declared with underscore names and aliased with
1042 dashes.
1043 Shorter aliases are also available, list all declared aliases with:
1044 .IP
1045 .EX
1046 alias
1047 .EE
1048 .PP
1049 Non documented functions are reserved for internal use.
1050 .SS Interface
1051 .IP "1." 3
1052 info
1053 .IP "2." 3
1054 usage
1055 .PP
1056 * * * * *
1057 .SS info
1058 \f[B]\f[BI]Description:\f[B]\f[R] Default command showing active nodes
1059 and summary, ran when sourced
1060 .PP
1061 \f[B]\f[BI]Usage:\f[B]\f[R]
1062 .IP
1063 .EX
1064 info
1065 .EE
1066 .SS usage
1067 \f[B]\f[BI]Description:\f[B]\f[R] Shows the command line help
1068 .PP
1069 \f[B]\f[BI]Usage:\f[B]\f[R]
1070 .IP
1071 .EX
1072 usage
1073 .EE
1074 .SS SSH functions
1075 .IP " 1." 4
1076 unlock
1077 .IP " 2." 4
1078 copy
1079 .IP " 3." 4
1080 ssh
1081 .IP " 4." 4
1082 ssh\-debug
1083 .IP " 5." 4
1084 ssh\-known\-hosts
1085 .IP " 6." 4
1086 ssh\-authorized\-keys\-reset
1087 .IP " 7." 4
1088 ssh\-accept\-new
1089 .IP " 8." 4
1090 ssh\-control\-master\-clean
1091 .IP " 9." 4
1092 ssh\-users
1093 .IP "10." 4
1094 ssh\-ids
1095 .IP "11." 4
1096 ssh\-authorized\-keys
1097 .IP "12." 4
1098 ssh\-ids\-hosts
1099 .PP
1100 * * * * *
1101 .SS unlock
1102 \f[B]\f[BI]Description:\f[B]\f[R] Resets the SSH agent environment and
1103 issues ssh\-add for SSH_IDENTITY_FILE
1104 .PP
1105 \f[B]\f[BI]Usage:\f[B]\f[R]
1106 .IP
1107 .EX
1108 unlock
1109 .EE
1110 .SS copy
1111 \f[B]\f[BI]Description:\f[B]\f[R] r7 openrsync, rsync, scp wrapper;
1112 selected in order of availability
1113 .PP
1114 \f[B]\f[BI]Usage:\f[B]\f[R]
1115 .IP
1116 .EX
1117 copy SRC DST
1118 .EE
1119 .SS ssh
1120 \f[B]\f[BI]Description:\f[B]\f[R] r7 SSH wrapper; behaves like the
1121 standard OpenSSH command
1122 .PP
1123 \f[B]\f[BI]Usage:\f[B]\f[R]
1124 .IP
1125 .EX
1126 ssh OPTION HOST
1127 .EE
1128 .SS ssh\-debug
1129 \f[B]\f[BI]Description:\f[B]\f[R] r7 SSH with debug connection mode for
1130 a specific HOST
1131 .PP
1132 \f[B]\f[BI]Usage:\f[B]\f[R]
1133 .IP
1134 .EX
1135 ssh\-debug HOST
1136 .EE
1137 .SS ssh\-known\-hosts
1138 \f[B]\f[BI]Description:\f[B]\f[R] Calls ssh\-keygen to dump the SSH
1139 known_hosts file
1140 .PP
1141 \f[B]\f[BI]Usage:\f[B]\f[R]
1142 .IP
1143 .EX
1144 ssh\-known\-hosts
1145 .EE
1146 .SS ssh\-authorized\-keys\-reset
1147 \f[B]\f[BI]Description:\f[B]\f[R] Resets SSH authorized_keys on the
1148 specified HOST
1149 .PP
1150 \f[B]\f[BI]Usage:\f[B]\f[R]
1151 .IP
1152 .EX
1153 ssh\-authorized\-keys\-reset HOST
1154 .EE
1155 .SS ssh\-accept\-new
1156 \f[B]\f[BI]Description:\f[B]\f[R] Adds a new host entry in the SSH
1157 known_hosts file
1158 .PP
1159 \f[B]\f[BI]Usage:\f[B]\f[R]
1160 .IP
1161 .EX
1162 ssh\-accept\-new HOST
1163 .EE
1164 .SS ssh\-control\-master\-clean
1165 \f[B]\f[BI]Description:\f[B]\f[R] Cleans the SSH control master
1166 directory
1167 .PP
1168 \f[B]\f[BI]Usage:\f[B]\f[R]
1169 .IP
1170 .EX
1171 ssh\-control\-master\-clean
1172 .EE
1173 .SS ssh\-users
1174 \f[B]\f[BI]Description:\f[B]\f[R] Searches nodes for authorized_keys_*
1175 and returns a list of users
1176 .PP
1177 \f[B]\f[BI]Usage:\f[B]\f[R]
1178 .IP
1179 .EX
1180 ssh\-users
1181 .EE
1182 .SS ssh\-ids
1183 \f[B]\f[BI]Description:\f[B]\f[R] Returns sorted SSH IDs
1184 .PP
1185 \f[B]\f[BI]Usage:\f[B]\f[R]
1186 .IP
1187 .EX
1188 ssh\-ids
1189 .EE
1190 .SS ssh\-authorized\-keys
1191 \f[B]\f[BI]Description:\f[B]\f[R] Returns the list of authorized_keys
1192 from nodes
1193 .PP
1194 \f[B]\f[BI]Usage:\f[B]\f[R]
1195 .IP
1196 .EX
1197 ssh\-authorized\-keys
1198 .EE
1199 .SS ssh\-ids\-hosts
1200 \f[B]\f[BI]Description:\f[B]\f[R] Returns SSH IDs along with matching
1201 keyfile and hostname
1202 .PP
1203 \f[B]\f[BI]Usage:\f[B]\f[R]
1204 .IP
1205 .EX
1206 ssh\-ids\-hosts
1207 .EE
1208 .SS Deployment functions
1209 .IP "1." 3
1210 nodes
1211 .IP "2." 3
1212 nodes\-active
1213 .IP "3." 3
1214 run\-config
1215 .IP "4." 3
1216 members
1217 .IP "5." 3
1218 group
1219 .IP "6." 3
1220 group\-functions
1221 .IP "7." 3
1222 prefix
1223 .PP
1224 * * * * *
1225 .SS nodes
1226 \f[B]\f[BI]Description:\f[B]\f[R] Returns a list of available nodes
1227 .PP
1228 \f[B]\f[BI]Usage:\f[B]\f[R]
1229 .IP
1230 .EX
1231 nodes
1232 .EE
1233 .SS nodes\-active
1234 \f[B]\f[BI]Description:\f[B]\f[R] Returns a list of active nodes by
1235 detecting SSH availability
1236 .PP
1237 \f[B]\f[BI]Usage:\f[B]\f[R]
1238 .IP
1239 .EX
1240 nodes\-active
1241 .EE
1242 .SS run\-config
1243 \f[B]\f[BI]Description:\f[B]\f[R] Executes \f[CR]R7_SITE_CONFIG\f[R] in
1244 the loaded environment
1245 .PP
1246 \f[B]\f[BI]Usage:\f[B]\f[R]
1247 .IP
1248 .EX
1249 run\-config
1250 .EE
1251 .SS members
1252 \f[B]\f[BI]Description:\f[B]\f[R] Returns a list of active nodes
1253 matching a list of grep REGEXES
1254 .PP
1255 \f[B]\f[BI]Usage:\f[B]\f[R]
1256 .IP
1257 .EX
1258 members REGEXES
1259 .EE
1260 .SS group
1261 \f[B]\f[BI]Description:\f[B]\f[R] Applies GROUPNAME functions (in prefix
1262 order) to the provided MEMBERS list
1263 .PP
1264 \f[B]\f[BI]Usage:\f[B]\f[R]
1265 .IP
1266 .EX
1267 group GROUPNAME MEMBERS
1268 .EE
1269 .SS group\-functions
1270 \f[B]\f[BI]Description:\f[B]\f[R] Returns a list of functions found in
1271 the specified GROUPNAME
1272 .PP
1273 \f[B]\f[BI]Usage:\f[B]\f[R]
1274 .IP
1275 .EX
1276 group\-functions GROUPNAME
1277 .EE
1278 .SS prefix
1279 \f[B]\f[BI]Description:\f[B]\f[R] Sets the current PREFIX for matching
1280 function names
1281 .PP
1282 \f[B]\f[BI]Usage:\f[B]\f[R]
1283 .IP
1284 .EX
1285 prefix PREFIX
1286 .EE
1287 .SS Text output functions
1288 .IP " 1." 4
1289 output\-dump
1290 .IP " 2." 4
1291 output\-latest
1292 .IP " 3." 4
1293 output\-status
1294 .IP " 4." 4
1295 output\-duration
1296 .IP " 5." 4
1297 output
1298 .IP " 6." 4
1299 output\-diffs
1300 .IP " 7." 4
1301 output\-permissions
1302 .IP " 8." 4
1303 output\-errors
1304 .IP " 9." 4
1305 summary
1306 .IP "10." 4
1307 trace\-id\-last
1308 .PP
1309 * * * * *
1310 .SS output\-dump
1311 \f[B]\f[BI]Description:\f[B]\f[R] Dumps R7_RUNDIR to R7_OUTPUTDIR
1312 .PP
1313 \f[B]\f[BI]Usage:\f[B]\f[R]
1314 .IP
1315 .EX
1316 output\-dump
1317 .EE
1318 .SS output\-latest
1319 \f[B]\f[BI]Description:\f[B]\f[R] Returns a list of outputs from the
1320 latest run
1321 .PP
1322 \f[B]\f[BI]Usage:\f[B]\f[R]
1323 .IP
1324 .EX
1325 output\-latest
1326 .EE
1327 .SS output\-status
1328 \f[B]\f[BI]Description:\f[B]\f[R] Returns a list of current dumped
1329 functions exit status codes
1330 .PP
1331 \f[B]\f[BI]Usage:\f[B]\f[R]
1332 .IP
1333 .EX
1334 output\-status
1335 .EE
1336 .SS output\-duration
1337 \f[B]\f[BI]Description:\f[B]\f[R] Returns a list of durations of
1338 executed groups
1339 .PP
1340 \f[B]\f[BI]Usage:\f[B]\f[R]
1341 .IP
1342 .EX
1343 output\-duration
1344 .EE
1345 .SS output
1346 \f[B]\f[BI]Description:\f[B]\f[R] Shows the dumped output matching HOST,
1347 GROUPNAME, and FUNCTION (or any if unspecified)
1348 .PP
1349 \f[B]\f[BI]Usage:\f[B]\f[R]
1350 .IP
1351 .EX
1352 output HOST GROUPNAME FUNCTION
1353 .EE
1354 .SS trace\-id\-last
1355 \f[B]\f[BI]Description:\f[B]\f[R] Returns the latest execution trace_id
1356 .PP
1357 \f[B]\f[BI]Usage:\f[B]\f[R]
1358 .IP
1359 .EX
1360 trace\-id\-last
1361 .EE
1362 .SS output\-diffs
1363 \f[B]\f[BI]Description:\f[B]\f[R] Returns the diffs from the latest
1364 execution
1365 .PP
1366 \f[B]\f[BI]Usage:\f[B]\f[R]
1367 .IP
1368 .EX
1369 output\-diffs
1370 .EE
1371 .SS output\-permissions
1372 \f[B]\f[BI]Description:\f[B]\f[R] Returns the latest permission changes
1373 .PP
1374 \f[B]\f[BI]Usage:\f[B]\f[R]
1375 .IP
1376 .EX
1377 output\-permissions
1378 .EE
1379 .SS output\-errors
1380 \f[B]\f[BI]Description:\f[B]\f[R] Returns the latest errors detected
1381 .PP
1382 \f[B]\f[BI]Usage:\f[B]\f[R]
1383 .IP
1384 .EX
1385 output\-errors
1386 .EE
1387 .SS summary
1388 \f[B]\f[BI]Description:\f[B]\f[R] Produces a summary of errors, diffs,
1389 and permission outputs
1390 .PP
1391 \f[B]\f[BI]Usage:\f[B]\f[R]
1392 .IP
1393 .EX
1394 summary
1395 .EE
1396 .SS Digraph output
1397 .IP "1." 3
1398 digraph\-host
1399 .IP "2." 3
1400 digraph\-ssh\-id\-hosts
1401 .PP
1402 * * * * *
1403 .SS digraph\-host
1404 \f[B]\f[BI]Description:\f[B]\f[R] Returns a directed graph (in DOT
1405 format) showing relations among groups, functions, and nodes
1406 .PP
1407 \f[B]\f[BI]Usage:\f[B]\f[R]
1408 .IP
1409 .EX
1410 digraph\-host
1411 .EE
1412 .SS digraph\-ssh\-id\-hosts
1413 \f[B]\f[BI]Description:\f[B]\f[R] Returns a directed graph (in DOT
1414 format) of relations between SSH IDs and hosts
1415 .PP
1416 \f[B]\f[BI]Usage:\f[B]\f[R]
1417 .IP
1418 .EX
1419 digraph\-ssh\-id\-hosts
1420 .EE
1421 .SS HTML output
1422 .IP "1." 3
1423 html
1424 .SS html
1425 \f[B]\f[BI]Description:\f[B]\f[R] Retunrs a report page with the content
1426 of \f[CR]README.md\f[R] in HTML format
1427 .PP
1428 \f[B]\f[BI]Usage:\f[B]\f[R]
1429 .IP
1430 .EX
1431 html
1432 .EE
1433 .PP
1434 * * * * *
1435 .SS Node importing
1436 .IP "1." 3
1437 import
1438 .SS import
1439 \f[B]\f[BI]Description:\f[B]\f[R] Import configuration files from a
1440 target host
1441 .PP
1442 \f[B]\f[BI]Usage:\f[B]\f[R]
1443 .IP
1444 .EX
1445 import HOST
1446 .EE
1447 .PP
1448 * * * * *
1449 .SS Technical notes
1450 .IP \[bu] 2
1451 Supported shells are ksh93, oksh, yash and bash.
1452 .IP \[bu] 2
1453 Supported platforms are OpenBSD, FreeBSD, NetBSD and GNU/Linux.
1454 .IP \[bu] 2
1455 Busybox support is planned.
1456 .IP \[bu] 2
1457 Optional dependencies are openrsync, rsync, column, graphviz and pandoc.
1458 .IP \[bu] 2
1459 The HTML output is a work in progress.
1460 .PP
1461 * * * * *
1462 .SS License
1463 The provided group library is shared as additionnal examples of the
1464 documentation and contain the following third\-party files under the ISC
1465 License.
1466 Copyright information are indicated in the LICENSE section of related
1467 files.
1468 .IP \[bu] 2
1469 \f[CR]pf\-badhost.sh\f[R]
1470 .IP \[bu] 2
1471 \f[CR]unbound\-adblock.sh\f[R]
1472 .IP \[bu] 2
1473 \f[CR]http\-ban.sh\f[R]
1474 .PP
1475 The project is shared under the terms of the ISC license.
1476 Any version previous \f[CR]0.1.0\f[R] needs to be considered obsolete
1477 and should not be redistributed.
1478 History in the GIT repository is kept for transparency purpose only.
1479 .PP
1480 Below is a copy of the applicable license:
1481 .IP
1482 .EX
1483 ISC License
1485 Copyright 2025 xs <xs\[at]inda.re>
1487 Permission to use, copy, modify, and/or distribute this software for any
1488 purpose with or without fee is hereby granted, provided that the above
1489 copyright notice and this permission notice appear in all copies.
1491 THE SOFTWARE IS PROVIDED \[dq]AS IS\[dq] AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1492 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
1493 FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1494 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1495 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1496 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1497 PERFORMANCE OF THIS SOFTWARE.
1498 .EE