Forum: CFEngine Help
Subject: Re: downsizing a huge policy file, sensibly
Author: davidlee
Link to topic: https://cfengine.com/forum/read.php?3,24050,24053#msg-24053
Locally we have several cases where we want to apply different data in
different environments but in standard ways. These include setting up one or
more network interfaces, some of which may be bonded; ensuring that certain
users are in the passwd file on some (nota all) machines (and some of the
resulting entries may be stripped-down "+userx:..." for NIS compatibility), etc.
The overall scheme I have used is to separate out the very detailed "vars:"
data (which is also likely to have high-frequency maintenance) from the more
general-purpose other things, and to put those other things into a method
(which, once established, is likely to have low-frequency maintenance).
So whereas you suggest "I was considering to write a module that, depending on
hostname and location, would return a server list, a peer list, and a key
list", what I do is "write an appropriate set of '*.cf' caller files that set
up appropriate 'vars:' data and then do 'usemethod' to a bundle which does all
the 'files:', 'commands:', etc.".
In both our cases, the complexity lies in constructing our data within each
environment, that is, in getting a good 'vars:' structure. Having done that,
applying the data ('files:', 'commands:', etc.) can be as general purpose as
reasonably possible.
One technique I find very useful is to put my data into associative arrays in
the caller and then pass the name of that array as an argument into the method.
Overall something like:
----------
bundle agent caller_1
{
vars:
envir_a::
"user1" string => "username_1";
"user1" int => "111";
"user1" int => "1111";
"user2" string => "username_2";
"user2" int => "222";
"user2" int => "2222";
"userlist" slist => { "user1", "user2" };
envir_b::
### set up different users, say, user3, user4, user5
### ending with:
"userlist" slist => { "user3", "user4", "user5" };
any::
# possible algorithmic data, always applicable to the lists defined above:
"$(userlist)" string => "/users/$(userlist)";
methods:
# Now call a general-purpose bundle with our data.
# Note that we pass the fully-qualified name of our assoc. array.
possibly_general::
"any"
usebundle => action_user_promise("caller_1.$(userlist)");
}
### This is probably in a different pseudo-library ".cf" file.
# "arr" is an associative array
bundle agent action_user_promise(arr)
{
files:
### do some file business using vars from 'arr'.
commands:
### do some command business using vars from 'arr'.
}
----------
You can be more subtle. For instance, given the above example, where the
usernames are distinct, you could actually define their particular data under
an "any::" selector, and only apply the "envir_*::" selectors when building the
"userlist". This would allow you to build hybrid systems:
----------
vars:
any::
"user1" string => "username_1";
"user1" int => "111";
"user1" int => "1111";
### similarly always set up user2, user3, user4, user5
### Then construct per-environment lists of users:
envir_a::
"userlist" slist => { "user1", "user2" };
envir_b::
"userlist" slist => { "user3", "user4", "user5" };
envir_hybrid_145::
"userlist" slist => { "user1", "user4", "user5" };
envir_hybrid_23::
"userlist" slist => { "user2", "user3" };
----------
You can now imagine expanding that to more than one "caller_1" bundle. Each
constructs an associative array of data and calls the common method. So
"caller_N" does:
----------
bundle agent caller_N
{
vars:
# construct data ending with:
"userlist" slist => {...};
methods:
# Note that we pass the fully-qualified name of our assoc. array.
possibly_general::
"any"
usebundle => action_user_promise("caller_N.$(userlist)");
}
----------
Hope that helps.
_______________________________________________
Help-cfengine mailing list
[email protected]
https://cfengine.org/mailman/listinfo/help-cfengine