Forum: Cfengine Help
Subject: Re: I'm exploiting usemodule. There has got to be a better way to
define global classes?
Author: [email protected]
Link to topic: https://cfengine.com/forum/read.php?3,18623,18688#msg-18688
I spent 3 days trying to get this to work. This policy will execute within
Cfengine, but something is maintaining state within the loop... If you can get
this to work, then you are a true Cfengine Ninja and I owe you a beer.
It seems on the first pass through the policy, policy1:CoreGuppyMachines is
defined correctly. On the 2nd pass, when it is looking at policy2, it doesn't
descend into bundle agent define_guppied_class.
We also define the wrong global classes for policy3.
The only other way I could think of getting this policy to work correctly is in
promises.cf to execute
process_single_bundle(policy1)
process_single_bundle(policy2)
...
......
And instead of looping through a text file, I would explicitly require it to be
called in promises.cf. I'd rather not do that if its possible to only call it
once and define all the global classes I need. I just couldn't get it to work.
This policy is the first in my bundlesequence. The global is to parse a file,
central_guppy_config.txt, to determine if it should be executing as designed by
defining global class (policy)_weapons_free, or if it should be restricted by
defining global class (policy_guppy
$ cat central_guppy_config.txt
# This file is split by policyname:filename. The filename is assumed to live
under /var/cfengine/inputs and contains a list of machines
# which we want to define for the guppy class of that specific policy.
# To define "WeaponsFree" means to apply the policy to all hosts.
policy1:CoreGuppyMachines
policy2:CoreGuppyMachines
policy3:WeaponsFree
policy4:WeaponsFree
$ cat bundle_guppy_test.cf
bundle agent bundle_guppy_test
{
vars:
# array_length -- the total amount of policies we found in
central_guppy_config.txt
# we really dont use array length, but the
readstringarray function which populates
# policy_guppies (which we need) returns an int, so this
variable is more or less a throw away.
# policy_guppies -- an array of strings that contain :
# specific_policy -- the index of policy_guppies. This contains the
actual policy names so something like
# cfengine_automated_execution gets defined here, which
is a reference to a line in
# central_guppy_config.txt.. like saying policy_guppies
to refer to a line.
# $(policy_guppies[$(policies_defined)][1] -- the 2nd value of the
line. These are separated by colons. This is the
# text file which contain the list of hostnames that we
want to define as guppies for this policy.
# We pass all this crap to another bundle below. This is how cfengine
handles loops. Refering to this as a single
# variable using $ instead of an array of @ loops through every policy
in the file central_guppy_config.txt...
"array_length" int =>
readstringarray("policy_guppies","/var/cfengine/inputs/central_guppy_config.txt","#[^\n]*",":",99999999,99999999);
"specific_policy" slist =>
getindices("policy_guppies");
methods:
# This descends to the bundle below passing the policy name and the
filename of the policy which contains
# all the hosts the policy should be applied on. If the filename is
the phrase "WeaponsFree" then we
# define a global class for normal operation and stop processing. If
we find a filename, we decend further.
"any" usebundle =>
process_single_bundle("$(specific_policy)","$(policy_guppies[$(specific_policy)][1])");
}
##############################################
bundle agent process_single_bundle(policy_name,
hostlist_guppy_file_for_this_policy)
{
classes:
"weapons_free" expression =>
strcmp("WeaponsFree","$(hostlist_guppy_file_for_this_policy)");
methods:
# If we've defined weapons free for this policy, then define the global
class and exit.
# Example class that would be defined:
cfengine_automated_execution_weapons_free.
# In the policy cfengine_automated_execution, then write that specific
policy using the class to determine if we are
# restricted. The policies themselves have to be written to take
advantage of this. We also abort execution
# of the policy if we dont find _weapons_free or _guppy defined.
!weapons_free::
"any" usebundle =>
define_guppied_class;
weapons_free::
"any" usebundle =>
add_global_class("$(policy_name)_weapons_free");
reports:
!weapons_free::
"The policy $(policy_name) has been guppied.";
weapons_free::
"The policy $(policy_name) is weapons free.";
}
#######################################################################################################
bundle agent define_guppied_class
{
vars:
# Pull the policy name we are operating on for local scope.
"policy_name_to_make_guppied_global" string =>
"$(process_single_bundle.policy_name)";
# Pull in the file for the policy. We know this isn't weapons free.
"restricted_policy_hostlist_file" string =>
"$(process_single_bundle.hostlist_guppy_file_for_this_policy)";
# Populate slist arrays with the contents of the 3 files.
"core_guppy_machines" slist =>
{
readstringlist("/var/cfengine/inputs/CoreGuppyMachines","#[^\n]*","[\n]",99999999,99999999)
};
"db_guppy_machines" slist =>
{
readstringlist("/var/cfengine/inputs/DBGuppyMachines","#[^\n]*","[\n]",99999999,99999999)
};
"app_guppy_machines" slist =>
{
readstringlist("/var/cfengine/inputs/AppGuppyMachines","#[^\n]*","[\n]",99999999,99999999)
};
classes:
# Interate over the list and look for my hostname. If I find my
hostname in the list, then I belong in
# the guppy class for this policy.
"core_guppy" expression =>
strcmp("$(restricted_policy_hostlist_file)","CoreGuppyMachines");
"db_guppy" expression =>
strcmp("$(restricted_policy_hostlist_file)","DBGuppyMachines");
"app_guppy" expression =>
strcmp("$(restricted_policy_hostlist_file)","AppGuppyMachines");
"core_guppy_me" expression =>
reglist("@(core_guppy_machines)","$(sys.host)");
"db_guppy_me" expression =>
reglist("@(db_guppy_machines)","$(sys.host)");
"app_guppy_me" expression =>
reglist("@(app_guppy_machines)","$(sys.host)");
methods:
# Since we determined that I am a guppy for this policy, we define a
global class with the
# _guppy which we then key off of during execution of the policy itself.
any::
"any" usebundle =>
remove_global_class("weapons_free");
core_guppy.core_guppy_me::
"any" usebundle =>
add_global_class("$(policy_name_to_make_guppied_global)_guppy");
db_guppy.db_guppy_me::
"any" usebundle =>
add_global_class("$(policy_name_to_make_guppied_global)_guppy");
app_guppy.app_guppy_me::
"any" usebundle =>
add_global_class("$(policy_name_to_make_guppied_global)_guppy");
reports:
# Report back that I've been included as a guppy in this policy.
((core_guppy.core_guppy_me)|(db_guppy.db_guppy_me)|(app_guppy.app_guppy_me))::
"This host $(sys.host) has been included as a guppy in
$(policy_name_to_make_guppied_global) in
$(global.inputs)/$(process_single_bundle.hostlist_guppy_file_for_this_policy)";
}
Execution of the policy shows the following below. Policy1 and policy2 should
have contained the host in CoreGuppyMachines. Policy3 and policy4 should have
been weapons free.
$ /var/cfengine/bin/cf-agent -I -K
R: The policy policy4 is weapons free.
R: This host testmachine has been included as a guppy in policy2 in
/var/cfengine/inputs/CoreGuppyMachines
R: The policy policy2 has been guppied.
R: The policy policy3 has been guppied.
R: The policy policy1 has been guppied.
_______________________________________________
Help-cfengine mailing list
[email protected]
https://cfengine.org/mailman/listinfo/help-cfengine