This is the third and final installment of a three-post series. In the first post, “git repository and deployment procedures for CFEngine policies”, I explained how we have structured our repository to efficiently manage many projects in one branch and share common policies across projects. In the second post, “cf-deploy: easier deployment of CFEngine policies“, I illustrated the script that we use to deploy the policies on our policy hubs and to preview the changes that would be applied to the policies themselves. In this final post I’ll illustrate yet another tool that helped us simplify the way we run the agent by hand on a node. Although one doesn’t need very often to run the agent by hand on production nodes, that is much more needed on test nodes and when debugging policies, and we do that often enough that it made sense to optimize the process. The principle is the same as the other script, cf-deploy: a makefile does the hard work, and we provide a convenient front-end to run make.
The problem
If you think at what are the actions that you commonly do when you run the agent by hand, they are at least two: update the policies at the latest version available (usually with cf-agent -KI -f update.cf
) and force an agent run (usually with cf-agent -KI
). Most of the time, the two things are combined in one single command line, like cf-agent -KI -f update.cf && cf-agent -KI
. Such command line is long enough to deserve a shorter alias.
Then another thing is to enable/disable the agent on a node, what someone in the community calls the “cowboy mode“. As many others, we have implemented a policy that checks for a flag file: if the file is present, the agent aborts. The flag file can be created and removed by hand with common commands like touch
and rm
, or the agent can disable itself when run with the disable_cfengine
class activated, re-enable itself when the enable_cfengine
class is activated, or force a run when disabled when the class force_run
is active. These are also good candidates for makefile targets.
It’s time for some sugar: when the policies are already updated and all you need is to run the agent several times to check something, it may be convenient to not waste time and CPU cycles on both the hub and the client and just run the policies: a “fast” run mode is yet another good candidate, as well as a fast-and-forced run mode.
And, last but not least: in our policies the agent collects information about itself and the system, along with contact details for the first-line engineers, and writes all in a text file that can be inspected in a crisis. A shortcut to display that file wherever it is on the filesystem is our last candidate for automation.
The Makefile solution
All these actions are easily codified in a Makefile:
CF_DIR=/var/cfengine INFO_DIR=/etc/cfengine HOSTINFO=$(INFO_DIR)/host-info AGENT=$(CF_DIR)/bin/cf-agent BASE_OPTS=-KI UPDATE_OPTS=$(BASE_OPTS) -f update.cf RUN_UPDATE=$(AGENT) $(UPDATE_OPTS) RUN_AGENT=/usr/bin/env LC_ALL=C $(AGENT) $(BASE_OPTS) .PHONY: info disable enable run fast force ff fastforce help help: echo "Supported actions:" echo " info: display system information" echo " run: update the policies and run the CFEngine agent" echo " fast: run the CFEngine agent, don't update" echo " enable: re-enable CFEngine on this node and run" echo " disable: disable CFEngine on this node" echo " force: update the policies and force an agent run even if disabled" echo " ff: (fastforce) force an agent run even if disabled, don't update" echo " help: show this help" echo "Default action: help" echo "" info: $(HOSTINFO) cat $(HOSTINFO) disable: $(AGENT) $(RUN_AGENT) -Ddisable_cfengine enable: $(AGENT) $(RUN_AGENT) -Denable_cfengine run: $(AGENT) $(RUN_UPDATE) && $(RUN_AGENT) fast: $(AGENT) $(RUN_AGENT) force: $(AGENT) $(RUN_UPDATE) && $(RUN_AGENT) -Dforce_run ff fastforce: $(AGENT) $(RUN_AGENT) -Dforce_run
The frontend
The most convenient way to shortcut a long make command is, in this case, a simple shell alias that we called cfe
:
alias cfe="make -s -C /var/cfengine/inputs/tools/host-info"
and the most convenient way to have this alias deployed for all users is to add a “fragment” shell script in /etc/profile.d/
(or equivalent) on all the systems that support it. Both the makefile and the shell alias can be deployed via simple CFEngine promises and, done that, one would use cfe run
to update the policies and run the agent, or cfe fast
to just run the agent, or cfe ff
to force a fast run of a disabled agent and so forth. And, when in doubt, one can run cfe
alone to get a list of all possible actions:
bronto@murray:~$ cfe Supported actions: info: display system information run: update the policies and run the CFEngine agent fast: run the CFEngine agent, don't update enable: re-enable CFEngine on this node and run disable: disable CFEngine on this node force: update the policies and force an agent run even if disabled ff: (fastforce) force an agent run even if disabled, don't update help: show this help Default action: help
Conclusions
This small system is so convenient that I always get disappointed when I hit a system where, for some reason, this facility is not implemented. And, guess what? One of the goals in the short term is to make it available everywhere 🙂 I hope you enjoy cfe
the same way I do. Cheers!