* What is it?
Idempotent system configuration as code, written in glotawk. You write
how your system should be configured; lacrum's machinery moves the
actual configuration toward the goal. This is about the same idea as
cfengine 2, or early Puppet. Example:
#+begin_src lacrum
(use-this-host)
(add-line-to-file "/tmp/hosts" "ff02::1 ip6-allnodes" nil)
(replace-line-in-file "/etc/ssh/sshd_config"
"^PermitRootLogin\\>"
"PermitRootLogin prohibit-password")
(sysrc :set "ntpd_enable" "YES")
#+end_src
* What's it for?
I envision defining jails, and hosts that host those jails, using
this, like a Bastillefile but assuming less.
* All right, how do I use it then?
First build glotawk, in the parent directory. Then run ~make~ in this
directory. It will build an executable file called ~lacrum~, which is
in fact a copy of glotawk plus the additional functions defined in
this directory.
See below on the language understood by this interpreter.
** Enhancing and redistributing
As detailed in the ../LICENSE file, this software is made available to
you under the terms of the 2-clause BSD license.
* Contributing
For now, lacrum lives in the same Pijul repository as glotawk.
** Future goals
Right now, the functions that do the work do it directly: by calling
functions that check whether a change needs to be made, and then, if
necessary, effecting the change.
We could instead cause rules to be accumulated, analyzed for
dependencies, then executed. Instead of doing the changes directly, We
could compile a shell script that would find necessary facts and do
necessary changes, without worrying about how to quote everything
properly.
We could determine how to back out each change made, and compose an
undo script that would allow rolling back a set of changes quickly.
In order to support the use of string usernames and group names, we
execute the ~/usr/bin/getent~ of the target while building. This means
the build host has to be able to run target executables, so we can't
build an image for a target of a different architecture.
Integrate better with OccamBSD.
Support other operating systems.
* More odd stuff
https://j.agrue.info/, gemini://j.agrue.info
* What do I write?
The underlying Lisp is glotawk, so see its documentation for more
details. But here we add:
** Rules
These are how the intended configuration of the system is expressed.
(If you are reading this file as plain text, using a program that
doesn't understand Org markup syntax, you should know that the stars
and slashes below serve to denote *bold* words and /italic/ words;
they are not part of the Lisp syntax you should use.)
(*replace-line-in-file* /file-path/ /detect-regex/ /replace-line/)
Find any line in /file-path/ that matches /detect-regex/, and replace
the whole line with /replace-line/. (Make sure /detect-regex/ will
only match zero lines or one line, to avoid unintended changes.)
(*add-line-to-file* /file-path/ /line/ /detect-regex/)
In the file /file-path/, if there is no line matching /detect-regex/,
add /line/ to the end of the file. (Make sure /detect-regex/ matches
/line/, to maintain idempotence.)
(*delete-lines-matching* /file-path/ /regex/)
In the file /file-path/, delete any lines that match /regex/.
(*file-exists* /file-path/ /owner/ /group/ /mode/)
Make sure the plain file /file-path/ exists and has the given /owner/,
/group/ and /mode/. /owner/ and /group/ may be numbers or names;
/mode/ is an octal mode expressed as a string, for example ~"644"~.
(*file-does-not-exist* /file-path/)
Make sure plain file /file-path/ does not exist, by removing it if it
does.
(*dir-exists* /dir-path/ /owner/ /group/ /mode/)
Make sure directory /dir-path/ exists and has the given /owner/,
/group/ and /mode/. Compare *file-exists*, above.
(*file-has-immediate-contents* /file-path/ /contents/)
Make sure the plain file /file-path/ contains the exact /contents/,
given as a string.
Note Glotawk's string syntax: strings are text between a pair of
unescaped double-quotes "like this". If the second double quote is not
on the same line as the first, that's no problem. Unescaped newlines
are just part of the string. Backslash escapes do what you might
expect from awk strings (or C strings, which they imitate): a
backslash immediately before a newline allows continuation of the
string on the next line without inserting a newline into the string;
~\\~, ~\"~, ~\n~, ~\r~, in fact all the lettered escapes abfnrtv, act
as indicated in printf(3).
(*file-text-copied-from* /dest-file-path/ /src-file-path/)
Make sure the plain file /dest-file-path/ has the same contents as the
plain file /src-file-path/—this latter is reckoned relative to the
current directory, but the former relative to the root.
(*file-contents-from-m4-template* /dest/ /tmpl/ /vars/)
Make sure the plain file /dest/ contains the filled-in ~m4~ template
stored in the file /tmpl/, where m4 is run with ~-D~ (define) switches
for each of the /vars/, which should be of the shape ~(("name1"
"value1") ("name2" "value2")...)~. See m4(1). Make sure none of the
values can contain any of the names. m4 is not my favorite templating
language, but it's part of POSIX and of the FreeBSD base system.
(*file-exists-with-entire-contents* /file-path/ /o/ /g/ /m/ /desc/
/contents/)
This is *file-exists* plus *file-has-immediate-contents*.
(*local-user-exists* /user-name/ /additional-groups/)
Make sure the user /user-name/ exists and has a home directory, and is
in /additional-groups/ (a list of strings).
(*package-installed* /name/ /pkg-opts/)
Make sure the package /name/ is installed. /pkg-opts/ is a list of
strings, each of which will be handed as a command line argument to
~pkg~.
(*sysrc* /op/ /name/ /value/)
Set something in ~/etc/rc.conf~. /op/ must be one of the keywords
~:set~, ~:add~, or ~:remove~, corresponding with sysrc(8)'s ~=~, ~+=~,
or ~-=~ operators. /name/ and /value/ are strings.
* Colophon
Michael Dexter made [[https://github.com/michaeldexter/occambsd][OccamBSD]]. A simulacrum is an image or
representation of something. I built pared-down jail images with
OccamBSD, but then wanted to configure them at build time, and deploy
a new version by untarring it and restarting the jail, or some such.
The es scripts that did that were named occulacrum. This now is
simpler, and it's just a layer, a thin lacquer over glotawk, if you
will.