Introduction to LCFG : Part 3
The following examples assume you are using the virtual appliance described in
IntroductoryTutorial.
The LCFG Environment
The first step is to familiarise yourself with the LCFG environment. Typically a machine will just be running the LCFG client (rdxprof) but in the case of the teaching environment it's a self-contained self-hosting LCFG environment so there is also an LCFG server (mkxprof) running.
To check the status of these two services and monitor what they are doing you should check the logs in
/var/log/lcfg
. Start a couple of terminal windows and watch the files using the tail command like this:
tail -f /var/log/lcfg/server
and
tail -f /var/log/lcfg/client
Note, if you want to finish tailing a file you can just use ctrl-c to close the process.
When you make a change to any input file (profile, header or package list) the LCFG server will spot the modification, it has an internal database of dependencies for files which it uses to trigger rebuilds of all affected profiles. A change will first appear in the server log and then a few moments later in the client log.
Open a third terminal window and move to the
/var/lib/lcfg/conf/server
, listing that directory will show a number of sub-directories including:
cd /var/lib/lcfg/conf/server
ls
- defaults - schema files for the components
- include - headers for various options
- packages - package lists
- source - source profiles
In the source directory there is a single profile, named
lcfg-tutorial
, this is a plain text file which controls the configuration for the virtual machine. All the examples will be based around modifying that file. Look at the profile:
cat source/lcfg-tutorial
The profile should look like:
/* Basic example profile */
#include <local/os/ubuntu/minimal_focal.h>
#include <lcfg/hw/virtualbox.h>
#include <lcfg/options/desktop.h>
#include <lcfg/options/lcfg-server.h>
!profile.comment mSET(my first change)
/* eof */
This describes a machine which is using a
minimal lcfg configuration for a desktop running Ubuntu Focal Fossa in a Virtualbox environment. One extra option has been enabled to include the LCFG server service.
As an example the value for a single resource has been mutated.
All the included files can be found in the server
include
directory. The
local
directory has been added to make it easier to work through examples without messing with the standard lcfg headers. The
local/os/ubuntu/minimal_focal.h
we're using is a thin wrapper around the standard
lcfg/os/ubuntu/minimal_focal.h
header, this is how most sites will use the lcfg headers, for example in Informatics we have
dice/os/ubuntu/focal.h
. This OS header enables the
minimal environment and sets some ACLs which are required for the server to allow access to the client XML profile. Just ignore the
local/site.h
file, it's there to satisfy some requirements in the headers, we won't be exploring that file but every site will have one, for example in Informatics we have
dice/options/inf-site.h
The source profiles and headers use the C Pre Processor (cpp) to handle the inclusion of additional files. Anything between the
/*
and
*/
markers is a C-style comment, note that comments beginning with a
#
are NOT supported as that character is already used by cpp for its directives.
A
minimal LCFG environment means that it is not responsible for the management of the entire configuration of the system. There will only be a small number of LCFG components, in particular we will be looking at
sysinfo
,
client
and
file
components.
To see a full list of the components which are registered in the profile use the
qxprof
utility. This tool queries the components and resources stored in the LCFG client database.
qxprof profile.components
You can also try using the
-v
option to get more information:
qxprof -v profile.comment
profile.comment:
value=my first change
type=default
derive=/var/lib/lcfg/conf/server/source/lcfg-tutorial:8
You can see that the client knows the resource type and derivation information (file and line number) as well as the value.
You can see all possible resources for a component by just passing the name of the component to qxprof, for example:
qxprof sysinfo
If you have access to a standard LCFG environment then why not try this there as well? If it doesn't work then you are probably not in the
lcfg
group, add yourself to that group, logout and back in again and you should have access.
See the qxprof(8) manual page for further options which you may find useful.
Status Pages
The LCFG server provides a set of status web pages which are useful when debugging problems with profiles.
In the virtual appliance start a web browser (e.g. firefox) and go to
http://localhost/cgi/index.cgi
The index page lists all known profiles, where there is an error you will see a red bug icon. Following the link for the profile will give a status page which summarises the state of the components on the machine and shows various other information including a description of any errors.
First Change
To modify the source profile you will need a root shell, you can get that using sudo, like this:
sudo bash
Edit the file using your favourite editor (e.g. emacs), if you want you can install another editor using the
apt
tool.
Make a change to the text inside the brackets for the
profile.comment
resource, save the file and watch what happens in the server and client logs. Once the change has reached the client you should use
qxprof
to verify for yourself that the change really has happened.
If you're happy with that then you could go on to try a few other mutators instead of the
mSET
, what can you do with
mADD
,
mEXTRA
,
mSUBST
?
Note that it is strictly only necessary to mutate the value when it has already been set but since it's often quite hard to know whether or not a resource has previously been defined it's common to just always use mutators.
Order of resource changes
The LCFG server processes profiles and headers from top to bottom working through all of the files from the first
#include
statement, then the next in turn until the end of the profile is reached. Modifications which appear later in a file will override earlier settings.
Try a combination of a few mutations, something like:
!profile.comment mSET(one)
!profile.comment mEXTRA(two)
!profile.comment mADD(one)
!profile.comment mADD(two)
!profile.comment mREPLACE(two,four)
Save the file, watch the changes in the server and client logs and then use
qxprof
to query the result.
Resource references
One particular useful feature is that the value for a resource may contain a reference to another resource value. This avoids duplication of data and makes reuse of headers easier since an administrator only has to change one value for all related settings to be changed.
A reference is made using a pair of delimiters like
<%
and
%>
, note that the server does NOT allow spaces in the reference block. For example:
!profile.comment mSET(This machine is running <%sysinfo.platform%>)
Again save the file, watch the server and client logs and then query the resource using
qxprof
. You should see:
comment=This machine is running ubu2004
It is important to note that the reference is resolved as late as possible. This can occasionally have surprising results. What value is produced here?
!sysinfo.location mSET(AT-7.10)
!profile.comment mSET(This machine is located in <%sysinfo.location%>)
!sysinfo.location mSET(AT-7.12)
Usually this will be what you want but occasionally you will really need to store the current value, in that case use the
<%%
and
%%>
delimiters (note the double percent signs). These beasts are rare and hardly ever spotted in the wild.
Resource Validation
Some resources have
types which describe the valid values which may be specified. The standard ones are:
- integer
- boolean
- string with regular expression matching
- LCFG tag list
If you specify an invalid value the server will show an error in the log and it will NOT rebuild the profile.
Strings
For example, the
sysinfo.criticality
resource may only be set to one of the strings
low
,
medium
or
high
. Try setting it to an invalid value to see what happens:
!sysinfo.criticality mSET(ultra)
In the server log you will see there is an error but that does not give any hint as to what caused the problem. You can find that information from the
status web pages
Booleans
For boolean values you may use
true
,
false
,
yes
,
no
,
off
and
on
they will be translated to
yes
for a true value and the empty string for a false value.
One slightly surprising side-effect of false values being represented as an empty string is that
qxprof
does not show them when you list the resources for a component. To see all possible resources including those with no value use the
-a
option, for example:
qxprof -a client
The main benefit of it being an empty string for false is that the value is then easy to test as part of a conditional in programming languages like Perl and bash.
Tag lists
With an LCFG tag list you must only add tags which contain alphanumeric and underscore characters. For example
foo_bar
is acceptable but
foo-bar
is not. Try this example and see what you get in the logs:
!sysinfo.paths mADD(foo-bar)
You will see that the server does not throw an error (it should) but the client does, there is a slight inconsistency in the validation which will be rectified at some point...
Working with Tag Lists
One of the more confusing aspects of working with LCFG resources is
tag lists. These effectively allow for the creation of more complex data structures, you add a tag to the list and then specify a number of related sub-resources.
Here's a simple example which defines an additional system path in the sysinfo component:
!sysinfo.paths mADD(tmpdir)
sysinfo.path_tmpdir /tmp
Note that you have to mutate the
sysinfo.paths
resource but, since the
sysinfo.path_tmpdir
resource has not previously been defined, you do not need to use a mutator, any subsequent change would need a mutation though.
--
squinney - 2021-03-19