Verdad implements ``prototype-style multiple inheritance''. If you are not PARC Alumni, you'll need some help understanding what it is and why it's useful. This document is for you.
Here's an example of how inheritance works, and why it's useful.
There are two ways to look at any item in Verdad. One way
is the simple item. This is just the way it looks when you
check it in with the verdad ci
command. Here's a set of
simple items:
item pkg-production pkg = tellme-platform-20010101-0101 pkg = vim-5.6
item users-production user = jra user = mattd user = verber
item production is = ( pkg-production users-production )
item exsc4.tellme.com is = production
item p1.exsc4.tellme.com is = exsc4.tellme.com in-service = true
item tel01.p1.exsc4.tellme.com is = p1.exsc4.tellme.com
item tel02.p1.exsc4.tellme.com is = p1.exsc4.tellme.com
The other way to look at these items is in their complete form. The complete form of an item has all the tags contributed by all the items it inherits from collapsed into one big item. For instance, given the previous set of items, the complete form of the item ``tel01.p1.exsc4.tellme.com'' would be:
item tel01.p1.exsc4.tellme.com user = jra user = mattd user = verber pkg = tellme-platform-20010101-0101 pkg = vim-5.6 in-service = true
So, imagine a script that dynamically writes the configuration script for a monitoring system. That script might look something like this:
foreach item (where in-service is true) { add to monitoring config file }
By changing the in-service tag from true
to false
in the item named p1.exsc4.tellme.com
, we can quickly and
easily take every machine that is a p1.exsc4.tellme.com
out of the monitoring system config file.
This is the point, and the power of inheritance. Because several items inherit from one, a change made there will take effect in several places at once.
Verdad implements multiple inheritance to make it possible for
it to hold information about different kinds of data simultaneously.
See the production
item above for an example of multiple
inheritance.
For instance, taking a machine out of service should in no way effect the security policy related to which users are allowed to login to it. In our example above, it's easy to see that the complete form of the item remains unchanged with respect to the user tags.
What if you set up two parent items which both had the same tags in them? You'd have a conflict, and Verdad has several policies available to resolve them. You choose which one is appropriate based on the kind of data stored in a particular tag. Every tag can have a different inheritance policy.
The default inheritance policy is ``overlay''. The rule it implements is ``last wins''. This is best illustrated in the following example:
item mom eyes = blue hair = blond
item dad eyes = green
item kid is = ( mom dad )
In this case, the complete form of the item kid
is:
item kid eyes = green hair = blond
Because Verdad processed the is tag in order, the first value
eyes had was blue
. But it was immediately replaced by the
value green
when the second is, dad
, was processed.
Because the dad
was apparently bald, the child inherited the
hair
from the mother.
Sometimes it makes sense for all the ancestor items to contribute to a certain tag. In this case, the correct inheritance policy to choose is ``append''. It is denoted by using the ``+='' separator instead of the usual ``='' one.
For instance:
item module-vi pkg += vi
item module-emacs pkg += emacs
item production-pkgs is = ( module-vi module-emacs)
The complete form of the production-pkgs item is this:
item production-pkgs pkg = ( vi emacs ) is = ( module-vi module-emacs)
As you can see, the pkg tag had each of the values of the pkg tag from the ancestors added into it.
Sometimes it makes sense to keep track of where a tag came from by changing it's name. Here's an example of the ``rename'' inheritance policy:
item module-vi pkg += vi contact ~= jra
item production-pkgs is = module-vi
Here is the complete form of the production-pkgs item:
item production-pkgs pkg = vi module-vi-contact = jra is = module-vi
Rename will act different when the tag named ``type'' exists in the parent item. Instead of prepending the item name, both the value of the ``type'' tag and the item name get prepended.
If you want to put a tag in a parent item, but don't want that tag to appear in any children items, use the inheritance policy ``:''. For instance:
item hardware:rackable comment := "An item to hold hardware details about rackables." ram = "2 gigs"
item web01.p1.exsc4.tellme.com is = hardware:rackable
The comment tag from hardware:rackable does not end up in the complete item for web01.
Another type of inheritance policy is the ``don't inherit'' policy. It can be used to trim tags inherited at higher levels. The difference between this feature and the colon inheritance policy above is that this can be used in (some) children to prune inheritance. Colon is used in the parent to prevent the tag from ever being passed on to children at all.
Here are two simple items as they might appear in the database:
item parent tag1 = value tag2 = value
item child is = parent tag1 x= ''
The complete item named child would look like this:
item child is = parent tag2 = value
The ``x='' says ``as you incorporate this item's tags into the complete item, remove all previous tags named tag1''. Note that the value following the X= in this case is completely ignored. It is conventional to make it an empty string.
If you were to use ``X='' instead (i.e. tag X= ''), then all tags with ``tag'' as the prefix would be removed from the current item.
A very useful application of the ``last wins'' rule is to use an overlapping tag name to override a setting inherited from an ancestor. For instance, say the simple form of the child was changed to this:
item kid is = mom is = dad eyes = hazel
In this case, the complete item will look like this:
item kid eyes = hazel hair = blond
The eyes tag in the child item overrides the eyes passed on from the dad.
A common use for an override like this would be to take one
host out of service while all the others remained in service.
To do so, you'd temporarily add an in-service = false
line
to the host item. This would override the in-service
tag inherited from the p1.exsc4.tellme.com
tag, taking
the machine out of service.
Here's the algorithm to go from an item name to a complete item:
using a depth first search across all the is'es for this item, assemble an "is path"
the earliest is'es end up at the beginning of the "is path", and the latest one (the item itself) ends up at the end.
foreach item in the "is path" fetch the simple form of the ancestor, as well as the desired inheritance policy. Using the policy, make a new tag and value.
The result is a complete item for the given item name.
The depth-first-search is implemented with a stack, instead of recursion. It uses a hash of already-visited items to avoid falling into loops. The database stores all items in their simple form, and a table indicating which items inherit from which others, so that the ``is path'' can be quickly determined.
This table is one of the tables rebuilt using
the vdadm index
command. You should consider using it
if inheritance does not seem to be working correctly.
When an item is added with a forward reference to it's
parent item, the index will be inconsistent until
either the item is edited, or the index is rebuilt.
Jeff R. Allen <jra@nella.org>