For the final post in the Feature Friday series I am here to tell you about something I use nearly hourly, ob-cfengine3 which extends Emacs Org Babel for executing CFEngine policy.
ob-cfengine3 has been around for a little over seven years now and it has saved me countless hours, seconds at a time. At it’s core it let’s you type a snippet of policy and execute it directly in your document, sort of like Jupyter.

By default it tries to include the standard library during execution so that you don’t have to manually in-line the common things for small examples. For this to work you will want to be sure and setup CFEngine for unprivileged execution which I talked about in Feature Friday #25: Unprivileged execution.
It’s easy to …
Specify the bundlesequence
#+BEGIN_SRC cfengine3 :bundlesequence one,two
bundle agent one
{
reports:
"Running bundle $(this.bundle)";
}
bundle agent two
{
reports:
"Running bundle $(this.bundle)";
}
#+END_SRC
#+RESULTS:
: R: Running bundle one
: R: Running bundle two
Define additional classes
#+BEGIN_SRC cfengine3 :define EXTRA,MORE
bundle agent main
{
reports:
EXTRA::
"EXTRA Class defined";
MORE::
"EVEN MORE";
}
#+END_SRC
#+RESULTS:
: R: EXTRA Class defined
: R: EVEN MORE
Specify additional arbitrary options to cf-agent
#+BEGIN_SRC cfengine3 :extra-opts --show-evaluated-vars=default:main
bundle agent main
{
vars:
"test" string => "test string";
}
#+END_SRC
#+RESULTS:
: Variable name Variable value Meta tags
: default:main.test test string source=promise
: default:maintain_key_values_meta.tags {"deprecated=3.6.0","deprecation-reason=Generic reimplementation","replaced-by=set_line_based"} source=promise
Change the output log level
#+BEGIN_SRC cfengine3 :log-level info
bundle agent example
{
commands:
"/bin/echo Hello World";
}
bundle agent __main__
{
methods:
"example";
}
#+END_SRC
#+RESULTS:
: info: Executing 'no timeout' ... '/bin/echo Hello World'
: notice: Q: ".../bin/echo Hello": Hello World
: info: Last 1 quoted lines were generated by promiser '/bin/echo Hello World'
: info: Completed execution of '/bin/echo Hello World'
Use a custom command for snippet execution
Here we are executing cf-agent from a docker image, this can be very useful if you are wanting to run a snippet against differing versions of CFEngine.
#+begin_src cfengine3 :command "docker run -v /tmp:/tmp zzamboni/cf-agent" :tmpdir /tmp
bundle agent main
{
reports:
"My hostname: $(sys.fqhost)";
}
#+end_src
#+RESULTS:
: R: My hostname: 5cd98f9265a8
Include command in the output
Especially when showing examples or working on documentation showing the command executed can be quite nice.
#+begin_src cfengine3 :command "docker run -v /tmp:/tmp zzamboni/cf-agent" :tmpdir /tmp :command-in-result t
bundle agent main
{
reports:
"Hello world!";
}
#+end_src
#+RESULTS:
: # docker run -v /tmp:/tmp zzamboni/cf-agent --no-lock --file /tmp/cfengine3-b7caCd
: R: Hello world!
Fun fact: This is how examples are handled in Learning CFEngine.
Execute partial snippets
#+begin_src cfengine3 :run-with-main yes
reports:
"Hello world!";
#+end_src
#+RESULTS:
: R: Hello world!
Getting it
In order to use this wonderful tool you will have to use Emacs. Learning Emacs might seem as steep a curve as CFEngine but I found Spacemacs got me going quickly and I didn’t have to leave any of my vi muscle memory behind. In fact, The agent is in - Episode 12 - Spacemacs for CFEngine covered getting set up.
Thanks
Thanks for coming along on this 42 part series as I celebrated CFEngine’s 30th anniversary, I hope you found some useful tidbits along the way.
One last time …
Happy Friday! 🎉
Checkout the rest of the posts in the series.