(Much of this discussion is Solaris- and NIS-specific, but the purpose of this posting is to describe techniques that you can apply to other situations on any operating system.)
Yesterday, we finally replaced our aging NIS master server with a newer, faster NIS master. Among the things that went wrong were a half dozen or more NIS clients that went haywire when we killed ypserv on the retiring NIS master.
The problem traced to the fact that on these problem machines, we had run 'ypinit -c', explicitly setting the NIS servers. (On all other systems, we had not run ypinit, effectively having those systems run ypbind with the -broadcast option.)
So, on one of the problem machines, the file /var/yp/binding/egbdf.uppity.edu/ypservers was as follows:
munich paris calais
Unfortunately, the first server, munich, was the NIS master we had just retired, and the other two servers were slaves retired long ago. When we killed the ypserv on munich, that broke the problem machine's ypbind'ing, effectively locking up that system.
As a fix, we decided to clear out the NIS ypservers file on all systems, then run 'ypinit -c' everywhere to set the current set of NIS ypservers explicitly.
So now, the approved ypservers file is as follows:
We want to ensure that this file remains accurate. How to do that? Why, another PIKT script, of course!
Here is a script we have added to our Warning alerts:
#if nisclient & solaris YPServersChkWarning init status active level warning task "Report errors in the =ypservers file" input file "=ypservers" rule // note current server =incr(#nisservers[$inlin]) rule // report bogus servers if $inlin !~ $substitute("=nisserver", " ", "|") output mail "bogus server?: $inlin" fi end if #innum() == 0 // this reports if the ypservers file // is empty; if the file is missing, // that would generate a stat() error // in the alert log file output mail "=ypservers empty!" else // report missing servers set #ns = #split("=nisserver") for #i=1 #i<=#ns #i+=1 if ! #defined(#nisservers[$[#i]]) output mail "missing server?: $[#i]" fi endfor fi #endif // nisclient & solaris
Here is the relevant portion of our macros.cfg, where we define =ypservers and =nisserver:
nismaster nantes nisserver #include <systems/nisserver_systems.cfg> domain_name egbdf.uppity.edu // so as not to conflict with // =domainname def in // unixcmds_*_macros.cfg file ypservers /var/yp/binding/=domain_name/ypservers
Here are the contents of the nisserver_systems.cfg #include file:
nantes madrid // former nis servers: // munich // paris // calais
As you know, PIKT preprocessing strips .cfg files of comments. Also, config file layout is free-form, so the above specification works just fine for specifying the nisserver hostgroup in systems.cfg:
nisserver members #include <systems/nisserver_systems.cfg>
What you might not know is that, when referenced in a Pikt alarm script (or anywhere else in the PIKT configuration, for that matter), the =nissever macro resolves to
that is, the string "nantes madrid".
In the second rule of the YPServersChkWarning script, we want to test whether the current ypservers input line, e.g.,
doesn't match any of the approved NIS servers.
This would not work
if $inlin !~ "=nisserver"
for after preprocessing, the client-side target script would read
if $inlin !~ "nantes madrid"
No, what we want is
if $inlin !~ "nantes|madrid"
and to achieve that, we have to replace all instances of " " in the =nisserver string with "|" using the Pikt $substitute() function:
if $inlin !~ $substitute("=nisserver", " ", "|")
The point here is that we want to specify the nisserver group just once, and be able to reference it as a hostgroup and in any other context later on in the configuration files. By isolating the nisserver specification in the nisserver_systems.cfg #include file, we have our "just-once", single specification.
We reference it via
in both systems.cfg and macros.cfg. We might conceivably reference it in objects.cfg as well.
In the YPServersChkWarning script, we use $substitute("=nisserver", " ", "|") to munge "nantes madrid" into exactly the form we want. We might use other Pikt functions for munging to a suitable form in other contexts.
#include files--the ability to munge them, and rewrite them automatically--are among the most powerful, and currently under-exploited features of PIKT.
We have downsys defined in systems.cfg as follows:
downsys // set '-H downsys' for these members #include <systems/downsys_systems.cfg>
It makes perfect sense to have an automated procedure (a Pikt Admin script?) poll all systems and rewrite downsys_systems.cfg automatically and routinely.
More than that, we can extend this principle to just about every osgroup and hostgroup specification in systems.cfg:
solaris hosts #include <systems/solaris_systems.cfg> // a script polls/ // determines all solaris // systems and rewrites // this file automatically ... nfsserver members #include <systems/nfsserver_systems.cfg> // ditto ... nisserver members #include <systems/niserver_systems.cfg> // ditto ...
In our own configuration, we have just begun to exploit this feature. In the configs_samples, check how we auto-rewrite objects/pikthosts_objects.cfg and objects/piktfiles_objects.cfg #include files using the MakePiktHostsObjectsAdmin and MakePiktFilesOjbectsAdmin scripts. See also MakeSudoPartimersAdmin for how we auto-rewrite the files/sudo_parttimers_files.cfg. These are just a beginning. Auto-rewriting an objects/userdirs_objects.cfg immediately comes to mind as another possibility.
The more complex your configuration, the harder it is to manage, in particular, to keep it all up-to-date. Auto-rewriting #include files is one solution. Now, if only I had more time to develop auto-rewrite examples! Or, if only you (pikt-users) were so bold to share your own solutions!
Earlier this morning, I redid the code for making "non" hostgroups allowing you to reference those groups directly within systems.cfg. (Before, you could only reference "nonlinux", for example, outside of systems.cfg.) For instance, it is now possible (well, in the next release) to do this in systems.cfg:
cssys // computing services shared systems; all other // systems are private faculty desktop and/or // research systems members vienna berlin ... ... facsys members noncssys /* the above replaces an explicit listing of facsys: facsys // private faculty workstations (explicitly specified) members rheims danzig ... */
Just one more tweak to make managing the PIKT configuration a little bit
For more examples, see Developer's Notes.