nosh version 1.9

Jonathan de Boyne Pollard J.deBoynePollard-newsgroups at NTLWorld.com
Fri Jan 15 09:42:04 UTC 2016


Jonathan de Boyne Pollard:
> nosh version 1.9 is out. [...]
> It's worth noting that OpenBSD 5.6 now specifies that 
> /etc/rc.conf{,.local} doesn't have shell expansions and isn't 
> necessarily sourced by a shell, [...]

Alfred Perlstein:
> Very cool.
>
> Wondering about the idea of /etc/rc.conf *not* being a shell script... 
> this is sort of bad imo as I can't see any other way to provide the 
> settings dynamically for the startup scripts at a glance.
>
> I'll give you an example... FreeNAS (and by extension the appliance we 
> are building at Norse) has /etc/rc.conf.local as a shell script that 
> pulls data from an sqlite database, this allows us to set various 
> services on/off based on the contents of that sqlite database file. 
> This in turn allows us to leverage most of the existing /etc/rc.d and 
> by extension the /usr/local/etc/rc.d files provided by ports.
>
> I'm wondering how one could still do that if /etc/rc.conf and 
> /etc/rc.conf.local were no longer scripts? 

Adrian Chadd:
> The same way /etc/rc.conf and /etc/rc.conf.local is pulled in - via 
> the little snippet of stuff at the end of /etc/defaults/rc.conf , and 
> this bit of config in that file:
>
> local_startup="/usr/local/etc/rc.d" # startup script dirs.
> script_name_sep=" " # Change if your startup scripts' names contain 
> spaces
> rc_conf_files="/etc/rc.conf /etc/rc.conf.local"
>
> So, we just need some method of pulling in environment variables in 
> whatever order we need from whatever place we need. (God, why do I 
> know this stuff? Then I remembered - 
> https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=17595 . God damnit.) 
> The tricky bit is trying to make it so we don't call sqlite like a 
> thousand times to pull out all of the environment variables for each 
> invocation of an rc script.

The Introduction to the nosh Guide (q.v.) states the maxim that 
bootstrap time is not build again and again time, and this is a good 
example of where that maxim should be put into action.  The time to run 
pwd_mkdb is not again and again whenever the password database is 
consulted, or at system bootstrap; it is after vipw has run the 
editor.   And if one is generating /etc/rc.conf{,.local} from some 
source, such as a database, then the same principle applies. 
/etc/rc.conf{,.local} should not contain shell code that is parsed and 
executed again and again.  The code to pull things out of an sqlite 
database and write out /etc/rc.conf{,.local} belongs at the end of the 
content update process, whatever that is (be it some TUI administrator 
settings tool or a daemon that provides an RPC interface for managing 
system settings to flashy GUI desktop widgets), for the sqlite database.

There are many good things that fall out of this approach.  Here are 
just some.

/etc/rc.conf{,.local} don't need to be on a writable filesystem until 
the sqlite database itself is modifiable.  The approach of making 
/etc/rc.freenas or /etc/rc.conf{,.local} or some other part of the 
bootstrap auto-update /etc/rc.conf{,.local} whenever it detects a 
database that is newer: does, however.  (And as M. Chadd points out, the 
alternative approach of not writing out /etc/rc.conf{,.local} and simply 
pulling shell variables straight from the database has the disadvantages 
of running the database client again and again, and of needing it in 
rescue and emergency modes.)

/etc/rc.conf{,.local} don't have to contain anything that requires a 
shell, just plain name=value assignments (with a small number of lexing 
rules for quoting) that can be parsed in perl, Python, C++, or a 
language of one's choice.

One can see this design used in nosh system management itself from nosh 
1.17 onwards.  /etc/system-control/convert/ contains a suite of redo 
scripts that do a similar form of settings import.  As you can see, it 
doesn't run over and over at bootstrap.  It's designed to be run at 
various points *when the system administrator is changing settings*, 
using redo to check whether source files have changed and update the 
relevant target files, and service bundle settings, when they have.

So running

 > rcctl get mdmfs at -tmp

which is  another way of saying

 > system-control print-service-env mdmfs at -tmp

one obtains (on one of my systems)

 > size="20m"
 > flags="-S"

These settings for the mdmfs at -tmp service, contained in the service 
bundle for that service, come directly from tmpsize and tmpmfs_flags in 
/etc/defaults/rc.conf (on that particular system).  They are not 
regenerated at bootstrap.  They aren't stored in shell script that is 
parsed and executed repeatedly.  They aren't surrounded by a large 
number of additional variables unrelated to that service bundle, that 
have to be parsed again and again only to be then thrown away.  They are 
in a daemontools-style envdir directory that is specific to the service 
bundle; and they are the only settings that that service bundle needs, 
and thus the only ones that get imported to that service bundle.

Interestingly, the nosh configuration import system could be extended to 
replacing that FreeNAS mechanism.  Notice that it already builds a 
hosts.conf from nsswitch.conf.  This is a similar sort of exercise.  I 
expect that the configuration import system could easily be extended, or 
copied, to build an rc.conf{,.local} from an sqlite database.  One would 
need little more than an rc.conf.do and an rc.conf.local.do that 
executed some sqlite SELECTs and massaged the results appropriately; 
code to do which, you already have from FreeNAS.  One wouldn't even need 
the current FreeNAS's hairy shell logic in rc.conf.local for repeatedly 
taking checksums of the database file(s) to see whether it has been 
modified since last time (even though the containing filesystems might 
be mounted read-only and there is no possibility of such a change).  
That comes free with the redo system.

Put another way: All of that stuff comes out of FreeNAS rc.conf.local, 
which goes back to being a plain data file containing nothing but 
variable=value settings, and (minus the parts that come for free with 
redo) goes into (say) /etc/system-control/convert/rc.conf.local.do .  
You lose the need for /var/tmp/rc.conf.freenas entirely.  You thus lose 
the need for a writable /var .  And the data import process doesn't run 
at bootstrap, again and again.  It runs from the system installer, from 
the flashy GUI tool that an administrator uses for adjusting the stuff 
on the sqlite database, from the humble TUI tools that do the same, or 
from (even) whatever DBus-speaking freenas-settings-d daemons you might 
care to dream up for speaking to the KDE and GNOME desktops and their ilk.


More information about the freebsd-hackers mailing list