PICA manualMiguel Armas del Río* |
Abstract: This manual tries to show the basic PICA usage, as well as describe its inner workings (just the necessary to make PICA do what it can do at all). It was initially based in an article from SysAdmin. This version applies to the PICA 0.4.x series.
At the ULPGC’s Network Division we administer several servers that run the critical network services such as DNS, DHCP, Network monitoring, etc. Because these services are critical, we run a number of scripts on every server that check the sanity of these services and try to fix basic error situations.
We needed a way to distribute all these scripts and the important services’ configuration files from a centralized location with little differences to adapt them to each host. We also needed a way to register any change on the configuration files, to be able to detect when a particular error was introduced (and who did it ;-)). We also wanted to centralize all network incident notifications and alarm management.
To meet all these needs, we developed PICA. With PICA we have a central repository of configuration files and alarm scripts. This repository is managed using CVS, so we can recover old versions, see changelogs, and let various admins to work concurrently. Actually, every sysadmin has a local copy of the working tree, and CVS does all the dirty work.
In this scenario PICA is used to distribute the configuration files and alarm scripts to the various servers. PICA uses SSH to establish secure connections to the remote servers, which is very convenient, since we where already using SSH with RSA authentication to access all remote servers.
The alarm scripts send incident notifications and service status reports to our central NetSaint server using asynchronous checks (see netsaint documentation). If a critical error is detected, an alarm is also sent via e-mail and as a SMS message to the sysadmin mobile phone.
PICA relies on several important concepts:
If one refers to a group, the action affects all the objects in that group. You can think of alarm dependencies as implicit groups, only that the group is an object per se. There is one important difference between host groups and object groups: one host can belong to an arbitrary number of groups, but an object belongs to one group or to none at all.
Attributes are properties associated with objects (both files and alarms). They are used to define local and remote paths to the objects, permissions to be set on installing, and so on. They are not to be confused with local variables (rather different concept). The difference is that attributes are for pica to know about them and behave accordingly, while local variables are used-defined variables to substitute into the installed objects, or to make conditionals or other references in Perl code.
Definitions are very useful for changing little things (or big, for that matter) at command line. They are defined with the +D flag. One can define (the existence of) a variable, or assign it some value. The syntax is +D myvariable for the former or +D myvariable=myvalue for the latter.
There are currently three configuration files, parsed in that order: pica.conf, hosts.conf and objects.conf. All of them are placed in the /etc/pica directory. The first is a configuration file to control behaviour of the pica main script; the second, a description of the hosts PICA will work on; the last, a description of the objects to process.
All the configuration files share a common syntax, similar to that of the DNS config files. Before being read, they are parsed by the Perl PreProcessor. Generally speaking, there are properties and constants, assigned to those properties. The properties must match the following regex:
(\w|/|\.|-)+
That is, letters, slashes, dots and hyphens, in whatever order you want. Note that there are some reserved words, that vary between configuration files.
On the other hand, constants come in three flavours:
Please note that the difference between single and double quotes is purely aesthetic. Just a last note: everything is case-sensitive in every configuration file!
This PICA component is the one that reads your files first, to transform them into what PICA will really read. In fact, is a Perl sub (well, two), not an independent program or CPAN module or something. The idea is being able to change (in a general and efficient way) the configuration files, depending on variables (yes, local variables) and some other checks. All of that, using arbitrary Perl expressions, that can not only return boolean values for conditions, but also generate part of the configuration or distribution files.
As the preprocessor is used on every PICA configuration and distribution file, the results become terribly dynamic. Imagine generating a configuration file for your servers, based on the name of the host, the name of the final file to be installed, the time of the day or some other external file or condition! You have all the power of Perl in your hands!
The directives recognized by PPP are:
To support your nifty conditions, there are sub definitions (actually, only two, ingroup and members) and some variables ($picahost and $picaobject, only defined for objects.conf; more on that later). Subs are defined in user.pm, a special module to put all of that stuff, placed in the PICA directory, usually /var/lib/pica. The user is supposed to modify that file if he wants to add a new function. The current list of defined subs is:
To add a function, you have to write it in user.pm and add it to the EXPORT and EXPORT_OK variables. Moreover, if you want to access a new variable, you’ll have to make a glob to see it and be able to modify it’s value. You can copy and paste the current subs and globs.
This configuration file defines some paths needed by PICA. It’s a defaults environment with some definitions. There is one special definition, protecteddirs, with a list of directories never to be deleted, under any circumstances (this list is checked every time PICA is about to delete some directory recursively). Here’s a pica.conf sample file:
defaults { picaroot = /var/lib/pica; # config files picatmp = /var/lib/pica/tmp; picasrc = /var/lib/pica/src; # distribution files picainclude = /usr/lib/pica/include; sshpath = '/usr/local/bin/ssh '; # ssh binary diffpath = '/usr/bin/diff'; # diff binary for -f command tarpath = '/bin/tar'; # tar binary rsyncpath = '/usr/local/bin/rsync'; protecteddirs { /, /bin, /usr/bin, /lib, /usr/lib, /var/lib/pica } }
I hope all of this is self-explanatory.
It is used to configure the hosts that should be administered using PICA. We can organize the hosts in different, possibly overlapped, groups that can be later used in conditions, so we could install a given file only in hosts belonging to a given group. We can also define variables for a given host and use them later. We also can specify different values for an object variable depending on the group we are working on by calling the ingroup sub.
Note that every host should be “declared” for PICA to know about it. It’s a way to try to prevent you from shooting yourself in the foot.
A simple example of the hosts.conf file could be the following:
defaults { vars { ## ---- User defined variables ---- docdir = '/home/httpsd/html/red'; } } ## ## Hosts Definitions ## host machine3; host machine2 { vars { var = 'this variable sucks'; } } host machine1; host machine4; host machine5; host machine6; host machine7; host machine8 { fqdn = machine8.otherdomain.net; } ########################### # Host Group Definitions # ########################### ## ## Group Definitions ## ## Servers hostgroup servers { members { machine2, machine1, machine4, machine7, machine5, machine6 } } ## RedHat Linux Servers hostgroup redhat { members { machine2, machine1, machine4, machine5, machine6 } } ## Debian Linux Servers hostgroup debian { members { machine8 } } ##################### # Mail servers ##################### ## No relay hostgroup mailmaster { members { machine2, machine1, machine4 } } ## Mailing lists servers hostgroup listservers { members { machine4 } } ## Main domain server hostgroup ulpgcmaster { members { machine4 } } ################ ## DNS Servers ################ hostgroup dnsservers { members { machine2, machine1, machine4, machine5, machine6 } } hostgroup dnsmaster { members { machine5, machine6 } } ################ ## NTP Service ################ ## Stratum-2 hostgroup stratum2 { members { machine2, machine1, machine4, machine5, machine6, machine7 } } ## ## GSM server ## hostgroup sms { members { machine5 } } ################ ## Misc services ################ hostgroup imapservers { members { machine4 } } hostgroup popservers { members { machine4 } } hostgroup simapservers { members { machine4 } } hostgroup tftpservers { members { machine4 } } hostgroup ftpservers { members { machine4 } } ####################### ## Some networks ####################### hostgroup net1 { members { machine2, machine4, machine7 } } hostgroup net2 { members { machine1 } } hostgroup net3 { members { machine5, machine6 } } ######################################### ## Documentation hosts ######################################### hostgroup doc { members { machine5, machine6 } }
Whoa! What a giant file. Well, perhaps you have noticed under all this mess that hosts (not hostgroups) can have attributes, such as “fqdn”. This way we can specify host information such as the name PICA will use to create the secure connection. The list of possible host attributes is:
One very important thing to note here is that there are some special values in the hosts.conf defaults environment. These variables point to important directories in the remote machines1. We would like them to change in a per-host basis, but, by now, they are “global”. Of course, chances are this will change sometime in the future.
The list of special values is:
Just one last note: it is possible to specify hostgroups in the “members” attribute of a hostgroup, so you can build hostgroup hierarchies. It’s very useful if you have a group like “DNS servers” and subgroups like “Windows DNS servers” and “Linux DNS servers” (i.e.: perhaps you want to treat all DNS servers at once for some things, and separately for other things).
This one defines all the objects that will be distributed using PICA, and depends on the current host. In general, one can include or generate dynamically parts of it, depending on evaluations of previously defined variables. The variables available at this time for the PPP will be:
The latter, of course, have preference in case of multiple definition. We also can use the internal variable $picahost to get the name of the current host. Because of that, the possibilities explode here: we can write entire Perl scripts (or in other languages, as far as we call them from Perl) to dynamically generate out configuration files on the fly, depending on defined variables, the day of the week, or whathever condition we can imagine. And here resides the power of PICA.
The mandatory and optional attributes for the two types of objects are:
For any of these attributes we can define default values in the “defaults” environment (see example).
A simple objects.conf file could be:
## Default values defaults { uid = 0; gid = 0; perms = 644; verbatim = 0; vars { globalvar1 = 'value1'; } } file motd { path = '/etc/motd'; source = 'Services/Info/motd'; } ################################## # Configuration for Service: NTP # ################################## group NTP { file ntp.conf { path = '/etc/ntp.conf'; source = 'Services/NTP/ntp_conf.cfg'; } file step-tickers { path = '/etc/ntp/step-tickers'; source = 'Services/NTP/step-tickers.cfg'; } ## ## Documentation for this Service ## #if (ingroup('doc')) file README.ntp { path = '<#$docdir#>/Services/NTP/README'; source = '<#$picasrc#>/Services/NTP/README'; } #fi } ################################## # Configuration for Service: DNS # ################################## #if (ingroup('dnsservers')) group DNS { file named.conf { path = '/etc/named.conf'; source = 'Services/DNS/named_conf.cfg'; } ## ## Documentation for this Service ## # if (ingroup('doc')) file README.dns { path = '<#$docdir#>/Services/DNS/README'; source = 'Services/DNS/README'; } # fi #fi } ## DNS check alarm DNSChkUrgent { priority = 'Urgent'; source = 'alarms/DNSChk'; perms = '755'; uses { file dnschk.conf { source = 'alarms/conf/dnschk.conf'; path = '<#picaobj#>/conf/dnschk.conf'; } } }
We also have a defaults section that will be seen from any object, and we can also define variables that will only be seen by the object they are defined in.
Anytime PICA operates with an object, it will build a namespace containing all the variables seen by that object in the host it is working on. Of course, the most specific definition has precedence. That is, if we define a variable in an object, and that object belongs to a group where the same variable is also defined, the value used is the one given in the object definition. In addition to these variables, we always have available $picahost and $picaobject, which hold the current host and object we are processing.
As a side note, since pica 0.3.6, files that happen to be directories are copied recursively, but treated verbatim (that is, no preprocessing is done on any file).
Once we have built our hosts and objects definitions, we can start using PICA to do something useful. Basically, PICA always does “something” to a list of objects on each of the given hosts. As the the help option “-h” states, PICA has the following command line syntax:
(PICA) Perl Installation and Configuration Agent Version: 0.3.4 Usage: ../pica -[ixtflh] [-n] [-v] [--with-picaconf newpica.conf] [--with-hostsconf newhosts.conf] [--with-objectsconf newobjects.conf] +D defines +|-F objects +|-H hosts -i : Install objects -x : Execute object/command -t : Delete object -f : Diff object -l : List objects -h : Shows this help -n : Debug. Do not install/delete things, just testing -v : Be verbose --with-picaconf : Changes pica.conf path --with-hostsconf : Changes hosts.conf path --with-objectsconf : Changes objects.conf path +D : Build defines list +|-F : Build object list +|-H : Build hosts list
The command line has three different mandatory parts:
Moreover, there is an environment variable, called PICAARGS, that will be pasted at the end of the command line (useful for having some parameters fixed at the end of every PICA call).
The object and host list on which we want to operate is built with +F/-F and +H/-H. With +H/-H we add/delete hosts or groups to the hosts list in the same order they are entered. For example, the expression:
+H dnsservers solaris -H deimos
will result in the host list “fobos mercurio sar” since PICA will add the members in groups dnsservers and solaris and delete host deimos2. Note that you can specify hosts not defined in hosts.conf. Those hosts will belong to no group, and connections will be made to that name. Moreover, only “common” objects will be seen. But it’s a start.
One more feature you will want to know of is the “automatic exclusion”. Before doing the actual host count, an implicit -H sysdown is added at the end of the list. This allows the sysadmin to automatically delete some hosts that can be down at a given time.
The object list is built the same way using +F/-F, but the object arithmetic is evaluated for every host, since the objects available for every host can be different because we can use conditionals in the objects file. For example, in the objects file above, all documentation objects will only be seen by members of the group “doc”.
Since we always need at least one host and object, options +F and +H are mandatory. If after doing the host/object arithmetic PICA gets an empty list (either objects or groups) it gives an error message and aborts execution.
Implicit groups are groups defined automatically by PICA to ease host and group arithmetic. Currently, there are only two implicit groups defined:
Moreover, if sysdown is not defined, PICA will define it automatically (to a empty list, of course).
We can also use +D/-D to build an optional list of definitions that can be used to preprocess files and as variables in object definitions, as if they where defined in the “defaults” environment of the hosts.conf file. Actually there is a little but very important difference, since they are defined before reading the hosts.conf file, these are the only variables that can be used to conditionally preprocess this file.
Right now PICA supports five different internal commands, but more could be added in the near future since we are still adding new features.
With each of these commands we can use the -v option for verbosity, and -n for debug (as with make, it does nothing, simply print information and "simulate" it’s working). Option -n gives a lot of output and doesn’t really do anything, just prints what it would do.
All these commands are executed using SSH connections to the remote hosts. Right now PICA doesn’t have any access control system, and will probably never have one. We like SSH and it gives us everything we need to access remote servers securely, so we used it for PICA. You know, as they say: KISS3.
Just one suggestion, if you are willing to use PICA, you better configure properly the RSA authentication, or be ready to type a lot of passwords... One nice trick is to distribute the SSH’s RSA authentication files using PICA as explained in one of the real life examples described later.
This command will install the given objects in each of the given hosts. The install command first generates the objects it will install in a local dir ($picaroot/tmp/$picahost), and then install them in the remote host.
PICA supports three different methods for remote file installation:
To change the installation method, set the attribute “method” per machine, in hosts.conf (you can set it globally or individually, distinct for each machine). To use methods tar and rsync, you must also set the binary path to this utils with the attributes “tar” and “rsync”.
The command:
pica -iv +F NTP -F step-tickers +H all -H deimos
Will install all objects in the group NTP except step-tickers in all servers except deimos.
This command will execute the given list of commands in each of the given hosts. If PICA finds an object with the given name, it will read its path attribute and use it for remote execution. This way we don’t have to remember the location of the script. If it doesn’t find an object with that name, PICA assumes it’s a Unix command and tries to run it.
For example, the command
pica -xv +F DNSChkUrgent +H servers
will execute /var/lib/pica/alarms/Urgent/DNSChkUrgent in all servers, since the object DNSChkUrgent exists and PICA can build the remote path using the object’s attributes.
On the other hand, the command
pica -xv +F "ndc reload" +H dnsservers
will run the command “ndc reload” in each member of the dnsservers group. Since PICA can’t find an object named ndc, it assumes it’s a Unix command and tries to execute.
This command lists the given objects. It basically executes “ls -l” for every object’s path. It can be used to see if an object is installed, and if the uid/gid and file permissions for that object are correct.
This command deletes the given objects in each of the given hosts.
The diff command finds differences between the object that should be installed in a host, and the one really installed. It basically generates the object for that host, and makes a “diff -u” between this object and the one installed in the remote host.
It’s very useful to see if a host has the latest version of an object.
The design of the PIFIA floats around the following concepts:
Alarms are a special type of object: we will normally want to execute it and it can depend on some files (regular files, not other alarms). So, it needs one more attribute (priority), has an additional optional attribute, and a special additional environment to support dependencies. But, as the rest of the objects, it’s installed in the appropriate hosts, so we will always have the possibility of execute any alarm by hand, even if the “central” host is down or unreachable.
The basic idea is that there is a program, the scheduler, that is executed by cron (a pifia.cron file is in the PIFIA distribution). Each time it’s run, it looks for alarm scripts to be executed…and executes them. Alarms have a priority, that defines in which directory will they reside. This lets the scheduler treat at different time intervals (defined in pifia.cron, of course) alarms of different priorities. By default, the defined priorities are:
By default, alarms are searched in $picasrc/alarms, but you can specify an absolute path to override this. They get installed in $picaalarms/priority in the remote machine. Because one can pass arbitrary (yes, we love that word) parameters to the alarm, it’s not called directly, but through a script, called “alarmname-picacaller”. This also lets us use scripts not designed originally for PICA. The only thing one needs is to define the calling convention (it’s one of the alarm optional attributes). In its definition we can take advantage of the many features of the preprocessor, as variable substitution or Perl on-the-fly code generation. It describes the parameters the alarm will be called with. For example, we could define an alarm like this:
alarm DNSChkUrgent { priority = 'Urgent'; source = 'DNSChk'; perms = '755'; calling-convention = '-w 1 -c $threshold'; vars { threshold = 8; } }
Supposing $picaalarms points to /var/lib/pica/alarms, DNSChkUrgent would get installed in
-rwxr-xr-x zoso zoso /var/lib/pica/alarms/Urgent/DNSChkUrgent
(note that we haven’t specified any uid or gid) and the contents of DNSChkUrgent-picacaller would be this:
#!/bin/sh /var/lib/pica/alarms/Urgent/DNSChkUrgent -w 1 -c 8 "$@"
Cool, uh? The last "$@" lets you add more parameters if you want to call it by hand.
We have a “scheduler” script that is run periodically from crond. The cron file is looks more or less like this (I probably won’t bother changing this every time I change that file):
## ## PIFIA crontab entry ## From this crontab entry we will run the PIFIA scheduler periodically for ## each priority ## # Emergency (every 10 minutes) */10 * * * * root <#$picabin#>/scheduler Emergency # Urgent (every 2 hours) 15 */2 * * * root <#$picabin#>/scheduler Urgent # Warning (once a day) 20 1 * * * root <#$picabin#>/scheduler Warning
Cron runs the scheduler for every priority, and the scheduler runs every alarm in a given priority, using the -picacaller file, gets every alarm output and generates a report that is sent via e-mail (or whatever command you specify). Right now each alarm has to manage it’s own variable persistency. All of this will be solved as the time goes by, by the PIFIA lib.
By now you should have realized that we like Perl and we have used it throughout PICA. Well, for better integration with the program, the alarms are also written in Perl, of course, and the facilities are a bunch of Perl subs in a package. As you have probably guessed, the package is pifia, and is distributed with PICA (no recursive dependency here, no alarms are used to install a file).
The most important feature of the alarms package is the environment perseval (persistent eval, it’s not that we like Arturic legends and we can’t write the name of the knight of Galles). It looks like this:
perseval { if ($lastnotify - time() > $timebetweennots && some_other_condition()) { print "Heck, some other condition, and I haven't notified you since ", "$lastnotify\n"; } @down = check_hosts(); foreach my $host (@down) { print "New host down: $host" unless grep { $_ eq $host } @downhosts; } $attrs{'something'} = calculate_something(); } preserve '$lastnotify', '@downhosts', '%attrs';
As you’ve probably noticed here, the perseval environment lets you write code with persistent variables. Those are specified in the preserve clause, after the program. Run the program, check whatever you want, and the variables you specify will have the same value the had the last time you ran the program. Really useful. All of this is implemented with the MLDBM package, so you need it installed in your system for this this to work.
PICA is built up from several components. There is a central executable, pica, a Perl preprocessor, and an alarm manager and Perl library (PIFIA). The central executable reads the supplied command line arguments and does the job; the Perl preprocessor is used for every configuration and non-verbatim distribution file before processing (obviously); and the alarm manager is used to setup and install alarms, and comes with a handy Perl library.
As we already said when describing the configuration files, the PICA central executable begins by preprocessing and reading pica.conf. After that, hosts.conf is parsed. Here, the program finds out about the machines, their attributes, variables and such. Then, and once for each host, PICA preprocess and reads objects.conf. Obviously, as the file is preprocessed once for each machine, the result can be different, because the preprocessor namespace is, in general, distinct. That way, we can define different distribution files, or in different ways, for each machine. Thus, we can:
Understanding this is very important to understand PICA behaviour. Once you get the hang of it, you will know how to make PICA do what you want.
PIFIA is a collection of files and conventions to get your servers look at themselves and act if they see something wrong (trying to fix it, telling you, or both). To make this easy to handle, there is a file to be included in your objects.conf file (with #include <pifia.conf>, yes). A pifia.conf file looks like this (yes, usual disclaimers about content updating apply):
############################################### # PIFIA (PICA Framework for Integrated Alarms # ############################################### group pifia { # Scheduler executable file scheduler { path = '<#$picabin#>/scheduler'; source = 'alarms/scheduler'; perms = '755'; vars { # Where to send mail notifications notifymail = 'kuko@ulpgc.es,zoso@ulpgc.es'; # How to send mail notifications mailcmd = '/usr/sbin/sendmail $notifymail'; # Where to send pager (or sms) notifications notifypager = 'kukom@airtel.net'; # How to send pager notifications pagercmd = '/usr/sbin/sendmail $notifypager'; #pagercmd = 'cat'; } } # Cron file file pifia.cron { path = '/etc/cron.d/pifia.cron'; source = 'alarms/pifia.cron'; perms = '644'; } # PIFIA lib (Perl package) file pifia.pm { path = '/usr/local/lib/site_perl/pifia.pm'; source = 'alarms/pifia.pm'; perms = '644'; } # README file (forces the creation of the persitence files dir, so leave it # here) file README { path = '<#$picaalarms#>/persistence/README'; source = 'alarms/README'; perms = '644'; } }
Here are some real life examples of PICA distribution files explained. With PICA comes a tiny (not-so-real-life) example which will make you understand how the Perl PreProcessor can be used. The file is called pica-rules.
Let’s begin with an example for distributing two files from the same source. At the Network Division we run the University’s primary nameservers. But we also give support to people that run secondary servers. In one of our primary servers, we also wanted to publish the configuration file needed to run a secondary server. We wanted to use the same source to keep both files consistent. This apparently simple task has created a lot of problems with other tools we have used. With PICA the solution is simple:
In the case of the masters, we have to install one version for production (the master server file) and one for documentation (the slave DNS server file). Thus, we defined, in hosts.conf, the following:
hostgroup dnsservers { members { fobos, deimos, mercurio, ulpnet, ulpnet2 } } hostgroup dnsmaster { members { ulpnet, ulpnet2 } } hostgroup doc { members { ulpnet, ulpnet2 } }
This way we can differentiate between documentation, DNS master and DNS slave servers. Thus, in objects.conf, we can define the relevant files as:
#if (ingroup('dnsservers')) group DNS { file named.conf { path = '/etc/named.conf'; source = "DNS/named_conf.cfg"; } ## Documentation for this Service # if (ingroup('doc')) # ... file named.conf.sample { path = '<#$docdir#>/Servicios/DNS/named.conf.sample'; source = 'DNS/named_conf.cfg'; } # fi } #fi
The only thing left to do is defining the named.conf file contents. The trick is checking the name of the object: if it ends with “.sample”, it’s a slave sample file; it not, then it’s a master file.
# ... zone "ulpgc.es" { #if ((ingroup('dnsmaster')) && ($picaobject !~ /\.sample$/)) type master; file "mydb.db"; also-notify { # ... }; #else type slave; file "mydb.db.bak"; masters { # ... }; #fi }; # ...
This shows the power of using arbitrary perl code in PICA conditions.
When you start administering a new server with PICA, one of the first things you should do is configuring SSH’s RSA authentication, to be able to access that server without typing any password.
This task can be simplified by distributing the needed files using PICA. We use SSHv2, so we will assume this version of SSH. First of all, every sysadmin needs to have their private/public key pair. Let’s say we are two sysadmins and our public keys are in SSHv2 format in the files sysadm1.pub and sysadm2.pub. We will add the following entries to the objects.conf file:
# SSH RSA authentication files group RSAAuth { # SSHv2 authorization file file ssh_auth { path = '/root/.ssh2/authorization'; source = "SSH/authorization.cfg"; } file sysadm1.pub { path = '/root/.ssh2/sysadm1.pub'; source = "SSH/sysadm1.pub"; } file sysadm2.pub { path = '/root/.ssh2/sysadm2.pub'; source = "SSH/sysadm2.pub"; } }
Different versions of SSH (SSHv2 or SSHv1) can be used in different hosts and use conditionals in the previous entries. This is left as an exercise to the challenged student ;-).
We could even generate the authorization file on-the-fly with the needed Key entries with the following code snippet:
#perl my @return; # Get key files reading group members and skipping 'ssh_auth' my @keys=grep(/\.pub$/,members('SSHAuth')); foreach my $key (@keys) { push @return,"Key $key\n"; } # Return the array (will be printed) @return; #lrep
This code will generate one “Key file.pub” entry for each public key file we define in the group, thus allowing access to the server with that key. This is really outside the scope of this article, but is a good example of what can be done with the #perl/#lrep environment.
With this configuration, after adding the new host to the hosts.conf file you could run the command:
pica -iv +F SSHAuth +H new_server
You will then have to type the server’s password only this time, because after installing this files both sysadmins will be able to access the server without typing any password (assuming they are running ssh-agent).
Here at Network Division, we have a very handy script to restart critical services via Web, just in case SSH is down on a given server. Of course, it has a secret password to allow access only to authorized administrators.
Before PICA, we had to manually create the password’s MD5 hash using the crypt perl function, and include the hash in the source file. Now, we can resort to something as elegant as this:
$passwd='<# crypt('secret-key-that-you-wont-ever-figure-out','salt') #>';
This way, just before sending the data, the command is executed and the encrypted key is put automagically in the distributed file. This saves time and work, and is a perfect example of the inmense power of PICA (and Perl, of course).
This document was translated from LATEX by HEVEA.