I have a setup at home where I keep a local git server running on a Raspberry Pi 3 which contains personal/work journal, dotfiles and a personal policy repository.
It was set up manually so before adding a new git repository for a family password store I set about retrofiting the configuration in CFEngine.
The goal in this blog is to ensure that what I have already is managed by CFEngine and that what I want to add, /srv/git/passwords.git
, is created.
My policy buddy, Nick Anderson, mentioned a strategy that he liked for working with CFEngine and policy: Inventory, Classify, then Promise.
Setup
For this setup I already had two physical servers: hub and git to work on.
In order to make the steps easier to reproduce and follow along I will use our Vagrant Environment and use the host001
VM provided as the git server.
After running vagrant up
you should have Mission Portal available with two hosts bootstrapped: hub
and host001
.
If you are impatient (and I suspect most of us are when playing around) you can shorten the feedback time for policy changes by configuring the agent schedule to every minute instead of the default of every 5 minutes.
In Augments (/var/cfengine/masterfiles/def.json
) on hub add the following:
{
"vars": {
"control_executor_splaytime": "1",
"control_executor_schedule": ["any::"],
"control_hub_hub_schedule": ["any::"]
}
}
The above is a complete and working augments file. If you have other customizations in there you will have to adjust accordingly.
After making this change, update the running policy as root with
/var/cfengine/bin/cf-agent -KIf update.cf
After installing and logging in to Mission Portal I visit the Policy Analyzer app tab on the lower-left and enable Policy Analyzer.
Then wait 1-2 minutes and refresh the page. You should see a tree of your policy similar to this:
I also need to setup my initial state on host001
with some directories.
This is what I already have on my real git server.
mkdir -p /srv/git/dotfiles.git
mkdir -p /srv/git/journal.git
mkdir -p /srv/git/personal-policy.git
Inventory
Lets write the policy to promise a set of sub-dirs in /srv/git
, or rather sort of “inventory” them the temporary way. :)
Find out what is on the system(s) that is interesting to me. In this case I want to know a few things about what I setup manually:
- Which repo directories are setup in
/srv/git
? - Is there a git user and group on the system?
- Are these directories owned by the git user and group?
- Are the permissions as I want them on
/srv/git
directories?
In some cases I just want to know for a while what is going on and not monitor it over time.
In this case I make promises for things and mark them as action_policy => "warn"
in an action body
so that I can see them as NOT KEPT in Policy Analyzer.
At a later date I can change them to actuate their effects after I am confident they will “do the right thing”.
Assuming you are using the Vagrant environment, let’s set up git version control. This allows us to track our changes, and revert (undo) if necessary.
cd /var/cfengine/masterfiles
git init
git add .
git commit -m initial
Now let’s set up a minimal def.json
to enable autorun services, the most common way to work on specific use cases in policy.
(This will also include the “update fast” bits we added earlier)
{
"classes": {
"services_autorun": ["any::"],
"cfengine_internal_purge_policies": ["any::"],
},
"vars": {
"control_executor_splaytime": "1",
"control_executor_schedule": ["any::"],
"control_hub_hub_schedule": ["any::"]
}
}
And add the git_server
policy at /var/cfengine/masterfiles/services/autorun/git_server.cf
:
bundle agent git_server
{
meta:
"tags" slist => { "autorun" };
vars:
"_repos" slist => {
"dotfiles",
"journal",
"personal-policy"
};
"_basedir" string => "/srv/git";
files:
"$(_basedir)$(const.dirsep)."
create => "true",
action => warn;
"$(_basedir)$(const.dirsep)$(_repos).git$(const.dirsep)."
create => "true",
action => warn;
}
body action warn
{
action_policy => "warn";
}
Wait for a few minutes for the policy to be updated both on hub
and host001
and refresh Policy Analyzer.
The red box with 5
indicates that there are 5 promises which are not kept (errors):
One not kept promise is the methods promise which calls the git_server
bundle.
Since we are only calling the git_server
bundle from this one methods promise we can ignore this not kept promise and focus on the underlying not kept promises in the git_server
bundle.
Another not kept promise is for the /srv/git/
and sub-directories not existing on the hub.
This is because so far we have not classified this policy to only apply to host001
our “git” server.
Classify
Now we will classify this policy so that it only applies to host001
by adding a class-guard to the meta promise which activates git_server
.
meta:
host001::
"tags" slist => { "autorun" };
Wait a few minutes and see that Policy Analyzer is once again clean and empty of not kept promises (no red warning counter box!).
Navigate to services/autorun/git_server.cf
and select the Kept checkbox at the top of Policy Analyzer to see which promises are kept.
The table shows what we expect for the current state of host001
:
Now let’s add “passwords” to our list of git repos:
"_repos" slist => {
"dotfiles",
"journal",
"personal-policy",
"passwords"
};
Save that and wait a minute or two and refresh Policy Analyzer to see that we have Not Kept promises again.
Navigate again to services/autorun/git_server.cf
in the tree.
The table shows the specific promises:
Promise
Now that we see clearly what is not kept and have checked that it’s what we want, we remove the action => warn
in our policy and let CFEngine fix the situation.
files:
"$(_basedir)$(const.dirsep)."
create => "true";
"$(_basedir)$(const.dirsep)$(_repos).git$(const.dirsep)."
create => "true";
Save that change, wait a few minutes (stand up! stretch! do a pushup or wiggle your ears!) and refresh Policy Analyzer.
Check the Repaired checkbox to see that the /srv/git/passwords.git
repo directory has been created.
To Review
Policy Analyzer is a handy tool you can use to visualize your policy alongside the current last outcome of each promise.
While developing policy you can add an action body to any type of promise to see what would be broken and where so you can classify your promises properly and only make changes where appropriate:
bundle agent main
{
files:
"/my/dir/."
create => "true",
action => warn;
}
body action warn
{
action_policy => "warn";
}
Try it!
Download CFEngine Enterprise free for up to 25 hosts and try out Policy Analyzer!
We’ll be working on more improvements as we go and would love to get your feedback as well.