<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Blog]]></title>
  <link href="http://zzamboni.org/blog.cf-learn.info/atom.xml" rel="self"/>
  <link href="http://zzamboni.org/blog.cf-learn.info/"/>
  <updated>2013-10-21T19:14:22-05:00</updated>
  <id>http://zzamboni.org/blog.cf-learn.info/</id>
  <author>
    <name><![CDATA[Diego Zamboni]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Third release of 'Learning CFEngine 3' is out!]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/third-release-of-learning-cfengine-3-is-out/"/>
    <updated>2013-10-21T14:44:00-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/third-release-of-learning-cfengine-3-is-out</id>
    <content type="html"><![CDATA[<p>I am delighted to announce that, after many months of work, the Third
Release of <a href="http://cf-learn.info/">Learning CFEngine 3</a> has been
released! You can get it
<a href="http://www.jdoqocy.com/click-7084911-11290546?sid=&amp;url=http%3A%2F%2Fshop.oreilly.com%2Fproduct%2F0636920022022.do%3Fcmp%3Daf-prog-books-video-product-cj_auwidget357_0636920022022_%25zp">directly from O&#8217;Reilly</a>
(affiliate link) or from any other of the usual places. If you
previously purchased the ebook version, you should see the update
already in your &#8220;Your products&#8221; page at
<a href="http://oreilly.com/">oreilly.com</a>, with options to download it or
sync it to Dropbox, Google Drive or Kindle.</p>

<p>There are many changes throughout, but here is a brief summary of the
most important ones:</p>

<ul>
<li>The book has been thoroughly updated for CFEngine 3.5.2. This
includes many new features, such as the new <code>edit_template</code>
mechanism, improved <code>services:</code> promises, lots of new functions, and
many others.</li>
<li>The brand-new Chapter 5 provides an overview of the CFEngine Design
Center. The Design Center had been mentioned in previous releases,
but now is a mature and capable resource including powerful tools
that allow you to use CFEngine in a completely new way, using
entirely data-driven configuration. This chapter will get you
started with the Design Center, and also provide pointers for you to
explore on your own and even to contribute to it!</li>
<li>Several new sections have been added, including &#8220;Dynamic Loading and
Execution&#8221;, &#8220;Using Vagrant with CFEngine&#8221;, &#8220;Service Management Using
CFEngine&#8221;, and others.</li>
<li>The brand-new Appendix C, contributed by
<a href="http://verticalsysadmin.com">Aleksey Tsalolikhin</a>, contains a
summary of all the attributes available for promises in agent
bundles. Just browsing through this Appendix will give you an
excellent overview of all the things you can do with CFEngine. In
the electronic version of this book, each attribute links to its
reference documentation in the CFEngine website, so you can look up
the full details in seconds.</li>
<li>Fixes to all known errata, typos, failures of clarity, and numerous
other things.</li>
</ul>


<p>In addition, many of the examples have been updated or improved,
additional emphasis has been placed on how to integrate your policies
into a running CFEngine installation, and numerous other improvements
have been made. All while maintaining the clarity, practicality and
usefulness you have come to expect from this book. As usual, in the
electronic versions, you will find that CFEngine keywords and concepts
are links to the corresponding sections of the documentation.</p>

<p><strong>I would like to thank YOU for reading the book, and for providing me
with so many useful ideas, suggestions and corrections through the
O&#8217;Reilly errata page, the CFEngine mailing list, IRC channel, and
directly by email. Your feedback has made this new release possible
and many times better. THANK YOU! (and please keep it coming)</strong></p>

<p>I&#8217;m extremely happy to bring you this release, and I&#8217;m confident you
will be happy with it as well. Please check it out!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CFEngine documentation index updated]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/cfengine-documentation-index-updated/"/>
    <updated>2013-08-08T01:37:00-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/cfengine-documentation-index-updated</id>
    <content type="html"><![CDATA[<p>Recently, the
<a href="https://cfengine.com/docs/3.5/index.html">CFEngine documentation site</a>
was completely overhauled, resulting in an easier-to-navigate,
easier-to-search experience (also easier to extend, since it&#8217;s all
hosted on GitHub now).</p>

<p>I have just updated the
<a href="http://blog.cf-learn.info/searching-cfengine-documentation/">CFEngine documentation index</a>
hosted on this site to point to the new documentation. The interface
is the same: you go to <code>http://cf-learn.info/ref/keyword</code>, replacing
<code>keyword</code> with your search term. This will automatically redirect you
to the appropriate section in the CFEngine documentation. If the term
matches more than one section, you will be given a list of potential
matches, and also a link to do a search for that term directly in the
documentation site.</p>

<p>Some examples:</p>

<ul>
<li><a href="http://cf-learn.info/ref/ifvarclass">http://cf-learn.info/ref/ifvarclass</a></li>
<li><a href="http://cf-learn.info/ref/classes">http://cf-learn.info/ref/classes</a></li>
<li><a href="http://cf-learn.info/ref/cf-sketch">http://cf-learn.info/ref/cf-sketch</a></li>
</ul>


<p>As part of the update, the index has been expanded to include
everything in the documentation site (before it only indexed the main
users&#8217; guide), so you can use it to find things not only in all the
<a href="https://cfengine.com/docs/3.5/reference.html">reference documents</a>,
but also in the <a href="https://cfengine.com/docs/3.5/manuals.html">manuals</a>
and even in the
<a href="https://cfengine.com/docs/3.5/examples.html">examples</a>.</p>

<p>As I&#8217;ve said before, I think the real power of this index is in its
use as a browser keyword search. The method for doing this varies from
browser to browser. With Safari on OS X I use the
<a href="http://www.macosxtips.co.uk/keysearch/">KeySearch extension</a>, so I
can just type &#8220;cf ifvarclass&#8221; on the Safari address bar, and go
directly to the documentation about <code>ifvarclass</code>.</p>

<p>Happy searching! And of course, please
<a href="http://cf-learn.info/contact.html">let me know</a> if you find anything
missing or broken.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Blog moving]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/blog-moving/"/>
    <updated>2013-04-28T00:00:00-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/blog-moving</id>
    <content type="html"><![CDATA[<p>This blog had so far been hosted on posterous.com, but Posterous was
acquired last year by Twitter, and will be closing down on April
30th. I have now migrated the blog to Octopress hosted on GitHub, the
same as the rest of the <a href="http://cf-learn.info/">cf-learn.info</a> site.</p>

<p>All the posts have been migrated, but there are still some rough
edges. Most notably, comments have not been migrated yet, and the
theme in the blog is different than the rest of the pages. Please bear
with me, and <a href="http://cf-learn.info/contact.html">let me know</a> if you find anything else broken.</p>

<p>BTW, if you are subscribed to the blog through its feedburner.com
feed, you should not need to do anything to migrate (if you are seeing
this post, it means you are already seeing the new site). Otherwise,
please subscribe to the feedburner.com feed at
<a href="http://feeds.feedburner.com/cf-learn">http://feeds.feedburner.com/cf-learn</a>.</p>

<p>Thank you for reading! More frequent posts coming soon.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA["Learning CFEngine 3" at LISA'12]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/learning-cfengine-3-at-lisa12"/>
    <updated>2012-12-17T16:46:03-06:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/learning-cfengine-3-at-lisa12</id>
    <content type="html"><![CDATA[<div>
<div>Last week I attended the Usenix <a href="https://www.usenix.org/conference/lisa12/">LISA&#8217;12</a> conference in San Diego, and the awesome people at O&#8217;Reilly organized a book signing while we were there. I&#8217;d like to share a couple of photos from the event. I had a great time!</div>
<p></p>
<div>The second release of the book has been out for a few weeks now. If you purchased the e-book from O&#8217;Reilly, make sure to check your &#8220;My books&#8221; page at <a href="http://oreilly.com">oreilly.com</a> to get the updated version!<p></p>
<p></p>
<br>
</div>
</div>
<br><p></p>
<div class="p_embed p_image_embed">
<a href="http://zzamboni.org/blog.cf-learn.info/images/2012/12/17/learning-cfengine-3-at-lisa12/46411484-LISA_2012_Diego_Zamboni.jpeg"><img alt="Lisa_2012_diego_zamboni" height="667" src="http://zzamboni.org/blog.cf-learn.info/images/2012/12/17/learning-cfengine-3-at-lisa12/46411484-LISA_2012_Diego_Zamboni.jpeg" width="500"></a>
<a href="http://zzamboni.org/blog.cf-learn.info/images/2012/12/17/learning-cfengine-3-at-lisa12/46411485-LISA_2012_Diego_Zamboni_Booksigning.jpeg"><img alt="Lisa_2012_diego_zamboni_booksi" height="667" src="http://zzamboni.org/blog.cf-learn.info/images/2012/12/17/learning-cfengine-3-at-lisa12/46411485-LISA_2012_Diego_Zamboni_Booksigning.jpeg" width="500"></a>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Second release of "Learning CFEngine 3"]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/second-release-of-learning-cfengine-3"/>
    <updated>2012-11-14T20:33:23-06:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/second-release-of-learning-cfengine-3</id>
    <content type="html"><![CDATA[I am happy to announce that as of today, the second release of &#8221;<a href="http://shop.oreilly.com/product/0636920022022.do">Learning CFEngine 3</a>&#8221; is available. If you have purchased the e-book version of the book you can get the new release from the &#8221;<a href="https://members.oreilly.com/account/emedia/index">Your Products</a>&#8221; page at <a href="http://oreilly.com">oreilly.com</a> (pro tip: set up Dropbox synchronization, and you will always have the latest version with you!). And if you haven&#8217;t purchased it, now it&#8217;s an excellent time to do it! You get all the fresh content, and all future releases for free.<p></p>
<div>These are the main updates in this release:</div>
<div>
<ul>
<li>The book has been updated to reflect changes introduced up to CFEngine 3.3.9 (the latest stable release as of this writing), including many features that were previously only available in CFEngine Enterprise, such as guest_environments promises, databases promises, and more.</li>
<li>The installation instructions now reflect the availability of binary package repositories for many Linux distributions, as well as the “Free 25” Enterprise packages that allow you to try CFEngine Enterprise for free, for up to 25 machines.</li>
<li>Vim fans rejoice! A new Appendix, contributed by Neil H. Watson, provides details on how to use Vim to edit CFEngine policy files.</li>
<li>This release fixes all known errata, including many typos, omissions, and other numerous miscellaneous things.</li>
</ul>
<div>I hope you enjoy this update! And if you have any feedback, please feel free to contact me.</div>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CFEngine tip #004: How to bootstrap a CFEngine client]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/cfengine-tip-004-how-to-bootstrap-a-cfengine"/>
    <updated>2012-09-25T17:13:00-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/cfengine-tip-004-how-to-bootstrap-a-cfengine</id>
    <content type="html"><![CDATA[<p>My apologies for the long delay since the last tip! Today we come back with a simple tip: how to bootstrap a CFEngine client.</p>

<h2>First, some background</h2>

<p>CFEngine is designed to operate in a fully distributed fashion – each CFEngine client (i.e. a machine running <code>cf-agent</code>) can operate fully autonomously, using only the policy files stored locally. For regular operation, <code>cf-agent</code> does not require any type of network connectivity.</p>

<p>In real deployments, of course, maintaining each machine’s policy independently would be impractical, so CFEngine has the concept of a <em>policy hub</em>. In CFEngine Community, the policy hub is simply a file server, a machine from which others can download policy files. This allows having a single point of distribution, so that changes made there can be distributed to a large number of clients. In CFEngine Enterprise, the hub has a more complex role, acting also as an aggregator of data from the clients, for the purposes of reporting and analysis.</p>

<p>All CFEngine clients will copy to their local <code>/var/cfengine/inputs/</code> directory the contents of <code>/var/cfengine/masterfiles/</code> in the policy hub, so that is where you should make any changes that you want distributed to all the machines.</p>

<h2>Bootstrapping</h2>

<p>When a new client is installed, it needs to be told which machine is the policy hub to which it should connect. This is done using the following command:</p>

<div class="CodeRay">
  <div class="code"><pre># cf-agent --bootstrap --policy-server=10.0.2.15</pre></div>
</div>


<p>You should, of course, replace 10.0.2.15 with the actual IP address of the hub to which you want to bootstrap. The first machine you install will be the policy hub itself, and it should bootstrap to itself. In this case, you have to use its own external IP address, and not “localhost” or 127.0.0.1.</p>

<p>When you issue this command on the policy hub, you will see a message like this, that indicates the host recognizes itself as a policy hub:</p>

<div class="CodeRay">
  <div class="code"><pre># cf-agent --bootstrap --policy-server=10.0.2.15
** CFEngine BOOTSTRAP probe initiated

   @@@     
   @@@      CFEngine

 @ @@@ @    CFEngine Core 3.3.5
 @ @@@ @   
 @ @@@ @   
 @     @   
   @@@     
   @ @     
   @ @     
   @ @     

Copyright (C) CFEngine AS 2008-2012
See Licensing at http://cfengine.com/3rdpartylicenses

 -&gt; This host is: precise32
 -&gt; Operating System Type is linux
 -&gt; Operating System Release is 3.2.0-23-generic-pae
 -&gt; Architecture = i686
 -&gt; Internal soft-class is linux
 -&gt; No previous policy has been cached on this host
 -&gt; Assuming the policy distribution point at: 10.0.2.15:/var/cfengine/masterfiles
 -&gt; Attempting to initiate promised autonomous services...

 ** This host recognizes itself as a CFEngine Policy Hub, with policy distribution and knowledge base.
 -&gt; The system is now converging. Full initialisation and self-analysis could take up to 30 minutes

R: This host assumes the role of policy distribution host
R:  -&gt; Updated local policy from policy server
R:  -&gt; Started the server
R:  -&gt; Started the scheduler
-&gt; Bootstrap to 10.0.2.15 completed successfully</pre></div>
</div>


<p>If you issue it on a client, you will see a similar message, but indicating that it is bootstrapping from a different machine.</p>

<p>Regardless of what you use, after bootstrap you should see <code>/var/cfengine/inputs/</code> populated with the default set of policy files, and both <code>cf-execd</code> and <code>cf-serverd</code>  should be running:</p>

<div class="CodeRay">
  <div class="code"><pre># ps axw | grep [c]f-
16099 ?        Ss     0:00 /var/cfengine/bin/cf-execd
16102 ?        Ss     0:00 /var/cfengine/bin/cf-serverd</pre></div>
</div>


<p>Once this has been done, CFEngine will start running every 5 minutes, updating its policy files from the hub, and executing them afterwards.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CFEngine tip #003: The distinction between bodies and bundles]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/cfengine-tip-003-the-distinction-between-bodi"/>
    <updated>2012-06-04T11:21:00-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/cfengine-tip-003-the-distinction-between-bodi</id>
    <content type="html"><![CDATA[<p>This is an extract from Chapter 3 of &#8220;Learning CFEngine 3&#8221;, where you can also find a much more comprehensive description of bodies and bundles in the CFEngine 3 policy language.</p>
<p>The distinction between bundles and bodies can be confusing at first. Remembering these points may help:</p>
<ul>
<li>
<p>Bodies are named groups of attributes, whereas bundles are collections of promises. Promises are the units that actually do something in CFEngine (for example, run a command or add a line to a file), whereas attributes specify characteristics of how things are done (for example, whether to run the command in a shell, or where in the file to add the line).</p>
</li>
<li>
<p>The value of an attribute can be a basic data type (string, integer, list, etc.), it can be the name of a body, or it can be the name of a bundle.</p>
</li>
<li>
<p>The type of an attribute’s value is fixed, and determined by the attribute itself (for example, the value of the depth_search attribute in a files: promise is always a body, and the value of an edit_line attribute is always a bundle).</p>
</li>
<li>
<p>For bodies and bundles, their type is always the name of the attribute to which they correspond. For example, bodies to be used with the depth_search attribute are always declared as “body depth_search xyz”, where xyz is an arbitrary name of your choosing. The same goes for bundles: bundles to be used with the edit_line attribute are always declared as “bundle edit_line xyz&#8221;.</p>
<p>There are only four types of “top level” bundles that are not used as arguments to attributes: agent, server, knowledge and monitor.</p>
</li>
<li>
<p>The promise types (sections) that can appear in a bundle are determined by the bundle type. For example, commands: promises can only appear in bundles of type agent. </p>
</li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CFEngine tip #002: How to pass arguments to bundles using arrays]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/cfengine-tip-002-how-to-pass-arguments-to-bun"/>
    <updated>2012-05-07T10:00:00-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/cfengine-tip-002-how-to-pass-arguments-to-bun</id>
    <content type="html"><![CDATA[<p>(This tip is based on a section from Chapter 5 of Learning CFEngine 3.)</p>

<p>Many system configuration tasks require groups of name-value pairs as arguments. For example:</p>

<ul>
<li>Editing configuration files in which parameters and their values need to be stored (ssh configuration files, Windows-style INI files, etc.)</li>
<li>Setting user parameters. In this case, sets of name-value pairs (home directory, full name, shell, etc.) are associated with a single user, identified by name.</li>
</ul>
<p>Having sets of related values in a single array has a number of advantages, since they can be manipulated by a single set of promises just by varying the indices used to access them. To make use of this array, you have to pass it as an argument to a bundle. One of the most useful functions in this technique is <a href="http://cf-learn.info/ref/getindices">getindices()</a>, which returns a list containing the indices of the given array, and can be used to produce an enumeration of the elements over which to iterate. The complementary function to get just the values is <a href="http://cf-learn.info/ref/getvalues">getvalues()</a>. For example, consider <a href="http://cf-learn.info/code/ch04/configfiles2.cf.html">this bundle</a>:</p>

<p><div><script src='https://gist.github.com/2605453.js?file=arguments1.cf'></script>
<noscript><pre><code>bundle agent configfiles
{
  vars:  
      # SSHD configuration to set
      &quot;sshd[Protocol]&quot;                                string =&gt; &quot;2&quot;;
      &quot;sshd[X11Forwarding]&quot;                           string =&gt; &quot;yes&quot;;
      &quot;sshd[UseDNS]&quot;                                  string =&gt; &quot;no&quot;;

  methods:
      &quot;sshd&quot;    usebundle =&gt; edit_sshd(&quot;configfiles.sshd&quot;);
}

bundle agent edit_sshd
{
  files:
      &quot;/etc/sshd/sshd_config&quot;
        handle =&gt; &quot;edit_sshd&quot;,
        comment =&gt; &quot;Set desired sshd_config parameters&quot;,
        edit_line =&gt; set_config_values(&quot;configfiles.sshd&quot;),
        classes =&gt; if_repaired(&quot;restart_sshd&quot;);
}
</code></pre></noscript></div>
</p>

<p>To pass arrays as arguments we must pass a string with the name of the array, and then dereference it inside the function. The argument we are passing to set_config_values() is “configfiles.sshd”, which refers to the sshd array defined in the configfiles() bundle.  The dereferencing happens in the <a href="https://github.com/cfengine/copbl/blob/master/cfengine_stdlib.cf#L278">set_config_values() bundle</a>:</p>

<p><div><script src='https://gist.github.com/2605453.js?file=set_config_values.cf'></script>
<noscript><pre><code>bundle edit_line set_config_values(v)
{
  vars:
      &quot;index&quot; slist =&gt; getindices(&quot;$(v)&quot;);
      &quot;cindex[$(index)]&quot; string =&gt; canonify(&quot;$(index)&quot;);

  replace_patterns:
      # If the line is there, maybe commented out, uncomment and replace with
      # the correct value
      &quot;^\s*($(index)\s+(?!$($(v)[$(index)])).*|# ?$(index)\s+.*)$&quot;
        replace_with =&gt; value(&quot;$(index) $($(v)[$(index)])&quot;),
        classes =&gt; always(&quot;replace_attempted_$(cindex[$(index)])&quot;);

  insert_lines:
      &quot;$(index) $($(v)[$(index)])&quot;
        ifvarclass =&gt; &quot;replace_attempted_$(cindex[$(index)])&quot;;
}
</code></pre></noscript></div>
</p>

<p>This bundle receives the name of the array as the “v” parameter, so we dereference the array and its values by using <code>$(v)</code> wherever we would normally use the array name. For example, to loop over the array elements using the indices stored in the <code>$(index)</code> list, we use <code>$($(v)[$(index)])</code> instead of <code>$(configfiles.sshd[$(index)])</code>.</p>

<p>To group name/value sets into named groups, we can use two-dimensional arrays, as in <a href="http://cf-learn.info/code/ch04/users_use.cf.html">this example</a>:</p>

<p><div><script src='https://gist.github.com/2605453.js?file=users_use.cf'></script>
<noscript><pre><code>bundle agent manage_users
{
  vars:
      # Users to create
      &quot;users[root][fullname]&quot;  string =&gt; &quot;System administrator&quot;;
      &quot;users[root][uid]&quot;       string =&gt; &quot;0&quot;;
      &quot;users[root][gid]&quot;       string =&gt; &quot;0&quot;;
      &quot;users[root][home]&quot;      string =&gt; &quot;/root&quot;;
      &quot;users[root][shell]&quot;     string =&gt; &quot;/bin/bash&quot;;
      &quot;users[root][flags]&quot;     string =&gt; &quot;-o -m&quot;;
      &quot;users[root][password]&quot;  string =&gt; &quot;FkDMzhB1WnOp2&quot;;

      &quot;users[zamboni][fullname]&quot;  string =&gt; &quot;Diego Zamboni&quot;;
      &quot;users[zamboni][uid]&quot;       string =&gt; &quot;501&quot;;
      &quot;users[zamboni][gid]&quot;       string =&gt; &quot;users&quot;;
      &quot;users[zamboni][home]&quot;      string =&gt; &quot;/home/zamboni&quot;;
      &quot;users[zamboni][shell]&quot;     string =&gt; &quot;/bin/bash&quot;;
      &quot;users[zamboni][flags]&quot;     string =&gt; &quot;-m&quot;;
      &quot;users[zamboni][password]&quot;  string =&gt; &quot;dk52ia209rfuh&quot;;

  methods:
      &quot;users&quot;   usebundle =&gt; create_users(&quot;manage_users.users&quot;);
}
</code></pre></noscript></div>
</p>

<p>In this case the dereferencing can get a little more complicated. For example, let us look at some of the code inside the <a href="http://cf-learn.info/code/ch04/sys_create_users.cf.html">create_users() bundle</a>:</p>

<p><div><script src='https://gist.github.com/2605453.js?file=sys_create_users.cf'></script>
<noscript><pre><code>bundle agent create_users(info)
{
  vars:
      &quot;user&quot;        slist =&gt; getindices(&quot;$(info)&quot;);

  classes:
      &quot;add_$(user)&quot; not =&gt; userexists(&quot;$(user)&quot;);

  commands:
    linux::
      &quot;/usr/sbin/useradd $($(info)[$(user)][flags]) -u $($(info)[$(user)][uid]) 
       -g $($(info)[$(user)][gid]) -d $($(info)[$(user)][home]) 
       -s $($(info)[$(user)][shell]) -c '$($(info)[$(user)][fullname])' $(user)&quot;
        ifvarclass =&gt; &quot;add_$(user)&quot;;
...</code></pre></noscript></div>
</p>

<p>This bundle is being called from the methods: section of the <code>manage_users()</code> bundle, with the string <code>"manage_users.users"</code> as the value of <code>$(info)</code>. We use getindices() directly on this value to get a list of the first-level indices of the array (the user names), which we store in <code>@(user)</code>. Then we use implicit looping over <code>@(user)</code> to cycle through all those values, and we use the following construction to access individual elements of each user’s data: <code>$($(info)[$(user)][field])</code>. This expands to <code>$(manage_users.users[$(user)][field])</code>, on which implicit looping is applied through the <code>$(user)</code> variable. Remember that parenthesis (or curly braces, they mean the same) are required around the whole expression, so that CFEngine recognizes it properly as a variable reference.</p>

<p>While the syntax looks complicated, this data structure allows great flexibility in passing around and using data structures to be used in configuration operations.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Get a free copy of "Learning CFEngine 3" in exchange for a review]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/get-a-free-copy-of-learning-cfengine-3-in-exc"/>
    <updated>2012-05-04T18:28:57-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/get-a-free-copy-of-learning-cfengine-3-in-exc</id>
    <content type="html"><![CDATA[<div>Are you a technical blogger? O&#8217;Reilly&#8217;s &#8221;<a href="http://oreilly.com/bloggers/">Blogger Review Program</a>&#8221; allows bloggers to get free ebooks and videos, in exchange for writing reviews of them.</div>
<p></p>
<div>I&#8217;d love to see more reviews of &#8220;Learning CFEngine 3&#8221;. If you have a technical blog, and would be interested in reviewing the book, I encourage you to visit <a href="http://oreilly.com/bloggers/">the program&#8217;s website</a> to find out more.</div>
<p></p>
<div>Plus, I&#8217;m sure you will enjoy the book, and I would love to read your review!</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Day Against DRM at O'Reilly: 50% discount on "Learning CFEngine 3" and all other ebooks]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/day-against-drm-at-oreilly-50-discount-on-lea"/>
    <updated>2012-05-04T00:16:00-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/day-against-drm-at-oreilly-50-discount-on-lea</id>
    <content type="html"><![CDATA[<p>Today, May 4th, 2012, O&#8217;Reilly Media is participating in support of the FSF&#8217;s <a href="http://www.fsf.org/news/may-4-day-against-drm">Day Against DRM</a>. All O&#8217;Reilly ebooks and videos are DRM-free, and to celebrate this, you can get 50% off on any purchase by using the code DRMFREE.</p>
<p></p>
<div>I&#8217;m proud to participate. <em>Learning CFEngine 3</em> is also available as a DRM-free ebook, and you can use this code to get it at half price.</div>
<p></p>
<div>Here&#8217;s the message from O&#8217;Reilly. Find out more at <a href="http://shop.oreilly.com/category/deals/day-against-drm.do">http://shop.oreilly.com/category/deals/day-against-drm.do</a>
</div>
<p></p>
<div>
<span style="color: #333333; font-family: Arial, Verdana, Geneva, Helvetica, sans-serif; font-size: 12px;"><span class="orm"> </span></span>
<div class="module ml" style="">
<div class="body no-border">
<div style="background: #ffd021;">
<h1 class="fwb" style=""><span style="font-size: x-large;"><strong><a href="http://shop.oreilly.com/category/deals/day-against-drm.do">In Celebration of *Day Against DRM*</a></strong></span></h1>
<h2 class="fsxl fwb mb" style="">Save 50% on ALL Ebooks &amp; Videos <span class="fsl" style="font-size: 16px;">– Use Code: <span style="color: #cc0000;">DRMFREE</span></span>
</h2>
<div style="">
<p class="mn fsl" style="">Having the ability to download files at your convenience, store them on all your devices, or share them with a friend or colleague as you would a print book, <span class="fwb" style="font-weight: bold;">is liberating, and is how it should be</span>. If you haven&#8217;t tried a DRM-free ebook or video, we encourage you to do so now. And if you&#8217;re already a fan, take advantage of our sale and add to your library. For one day only, you can save 50% on all <span class="fwb" style="font-weight: bold;">O&#8217;Reilly</span>, <span class="fwb" style="font-weight: bold;">No Starch</span>, and <span class="fwb" style="font-weight: bold;">Rocky Nook </span>ebooks and videos. <a href="http://www.fsf.org/news/may-4-day-against-drm" class="fc-dark" style="color: #222222; text-decoration: underline;">Learn more about Day Against DRM</a></p>
<p class="fsm mb" style="">Ebooks from oreilly.com are <span class="fwb" style="font-weight: bold;">DRM-free</span>. You get <span class="fwb" style="font-weight: bold;">free lifetime access, multiple file formats, free updates.</span> <br><span class="fsm fwn" style="font-size: 12px; font-weight: normal;">Deal expires May 4, 2012 at 11:59pm PT and cannot be combined with other offers.</span></p>
</div>
</div>
</div>
</div>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CFEngine talks at PICC'12 conference]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/cfengine-talks-at-picc12-conference"/>
    <updated>2012-04-27T09:04:53-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/cfengine-talks-at-picc12-conference</id>
    <content type="html"><![CDATA[There will be several CFEngine-related classes and talks at the <a href="http://www.picconf.org/">PICC&#8217;12 conference</a> (Professional IT Community Conference) on May 11-12th, in New Jersey. I will be talking about using CFEngine as part of your security infrastructure. My colleague Joe Netzel will be talking about migration from CFEngine 2 to CFEngine 3, so if you are using CF2 and have been considering (or dreading) the migration, make sure to come by! Aleksey Tsalolikhin will give an introductory class to CFEngine. And Mark Burgess will give a class not related to CFEngine, but to the perils and skills needed to survive as a technical person in the &#8220;business world&#8221;.<p></p>
<div>If you are coming to the conference, we look forward to seeing you there!<br><ul>
<li>Mark Burgess - <a href="http://www.picconf.org/picc12-training-classes/#f4">A Sysadmin’s Guide to Navigating the Business World</a>
</li>
<li>Diego Zamboni - <a href="http://www.picconf.org/picc-12-talkspapers/#18">CFEngine Configuration Management for Security</a>
</li>
<li>Joe Netzel - <a href="http://www.picconf.org/picc-12-talkspapers/#16">Successfully Migrating From CFEngine 2 to CFEngine 3</a>
</li>
<li>Aleksey Tsalolikhin - <a href="http://www.picconf.org/picc12-training-classes/#f10">Automating System Administration with CFEngine 3</a>
</li>
</ul>
<p></p>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A full shelf]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/a-full-shelf"/>
    <updated>2012-04-25T15:33:10-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/a-full-shelf</id>
    <content type="html"><![CDATA[I got this photo of a bookshelf at the CFEngine office in Palo Alto. Looks awesome, doesn&#8217;t it? :)<p></p>
<div>
<div class="p_embed p_image_embed">
<a href="http://zzamboni.org/blog.cf-learn.info/images/2012/04/25/a-full-shelf/40472230-photo.jpeg"><img alt="Photo" height="375" src="http://zzamboni.org/blog.cf-learn.info/images/2012/04/25/a-full-shelf/40472230-photo.jpeg" width="500"></a>
</div>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CFEngine tip #001: Modularize complex policies using methods: calls]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/cfengine-tip-001-modularize-complex-policies"/>
    <updated>2012-04-23T09:44:00-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/cfengine-tip-001-modularize-complex-policies</id>
    <content type="html"><![CDATA[<div>Welcome to the new &#8220;CFEngine tip&#8221; series. In this series of posts I will explore different tips, tricks and techniques for making better use of CFEngine. For now I will post weekly, but the frequency may change as time goes by. If you have any suggestions for topics that I should cover in this series, please <a href="http://cf-learn.info/contact.html">let me know</a>!</div>
<p></p>
<div>For our first installment, we will talk about methods: promises, and how they can be used to make policies both clearer and more extensible.</div>
<div>
<hr>
</div>
<p>As your CFEngine policies grow in complexity, they become harder to read if all your promises are in a single bundle, or if you split them among bundles, to have all those bundles listed in the <a href="http://cf-learn.info/ref/bundlesequence">bundlesequence</a> declaration.</p>
<div>Enter the <a href="http://cf-learn.info/ref/methods">methods:</a> promise type. Promises of this type allow you to call other bundles in sequence, passing arbitrary parameters. For example, consider the following example (from <a href="http://cf-learn.info/code/ch05/configfiles5.cf.html">Chapter 5</a> of &#8220;Learning CFEngine 3&#8221;):</div>
<p><div><script src='https://gist.github.com/2471468.js?file=methods_ex1.cf'></script>
<noscript><pre><code>bundle agent configfiles
{
  vars:  
      # Files to edit
      &quot;files[sysctlconf]&quot; string =&gt; &quot;/etc/sysctl.conf&quot;;
      &quot;files[sshdconfig]&quot; string =&gt; &quot;/etc/ssh/sshd_config&quot;;
      &quot;files[inittab]&quot;    string =&gt; &quot;/etc/inittab&quot;;
      # ...

  methods:
      # Pass the name of the array, not the array itself.
      &quot;backup&quot;  usebundle =&gt; backup_files(&quot;configfiles.files&quot;);
      &quot;sysctl&quot;  usebundle =&gt; edit_sysctl;
      &quot;sshd&quot;    usebundle =&gt; edit_sshd;
      &quot;inittab&quot; usebundle =&gt; edit_inittab;
      &quot;users&quot;   usebundle =&gt; manage_users(&quot;configfiles.users&quot;);
}
</code></pre></noscript></div>
</p>
<div>The methods: section makes it very easy to see the sequence of actions that will take place: backup some files, configure sysctl, sshd, inittab and users in sequence. This helps both in clarity and in code reusability: each bundle can perform logically different functionality, and they could potentially be reused in different settings and with different parameters. The promiser string in a methods: promise is an arbitrary string. The CFEngine documentation uses &#8220;any&#8221;, but you can also use it, as in this example, to indicate the purpose of the promise.</div>
<p></p>
<div>Furthermore, you can use CFEngine&#8217;s <a href="https://cfengine.com/manuals/cf3-reference#Loops-and-lists-in-CFEngine-3">implicit looping</a> to create generic promises that will call as many other bundles as necessary. Consider this <a href="http://cf-learn.info/code/ch05/configfiles7.cf.html">revised code</a>:</div>
<p><div><script src='https://gist.github.com/2471468.js?file=methods_ex2.cf'></script>
<noscript><pre><code>bundle agent configfiles
{
  vars:  
      # Files to edit
      &quot;files[sysctl]&quot;     string =&gt; &quot;/etc/sysctl.conf&quot;;
      &quot;files[sshd]&quot;       string =&gt; &quot;/etc/ssh/sshd_config&quot;;
      &quot;files[inittab]&quot;    string =&gt; &quot;/etc/inittab&quot;;
      # ...

      &quot;file_id&quot; slist =&gt; getindices(&quot;files&quot;);
      &quot;bundle_names&quot; slist =&gt; maplist(&quot;edit_$(this)&quot;, &quot;file_id&quot;);

  methods:
      &quot;backup&quot;  usebundle =&gt; backup_files(&quot;configfiles.files&quot;);
      &quot;$(bundle_names)&quot;  usebundle =&gt; $(bundle_names)(&quot;configfiles.files&quot;);
      &quot;users&quot;   usebundle =&gt; manage_users(&quot;configfiles.users&quot;);
}
</code></pre></noscript></div>
</p>
<div>Now the list of bundles to call (edit_sysctl, edit_sshd and edit_inittab) is being built on the fly from the contents of the files array, and used through implicit looping to call the bundles in the methods: promises. Note how you can even pass arguments to these calls. This makes it very easy to extend the functionality by simply adding new elements to the files array (and of course, defining the appropriate edit_* bundle).</div>
<p></p>
<div>Until next time!</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[New "reviews" page]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/new-reviews-page"/>
    <updated>2012-04-20T01:10:36-05:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/new-reviews-page</id>
    <content type="html"><![CDATA[I have started collecting some of the nice things I have read people say about the book, and put them in the <a href="http://cf-learn.info/reviews.html">Reviews</a> page. Check it out!
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The bird on the cover of "Learning CFEngine 3"]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/the-bird-on-the-cover-of-learning-cfengine-3"/>
    <updated>2012-03-26T22:17:06-06:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/the-bird-on-the-cover-of-learning-cfengine-3</id>
    <content type="html"><![CDATA[A lot of people have asked me about the bird on the cover of the book, and I had to admit I didn&#8217;t know. Unfortunately, the book (even in the print version) does not include a description of the cover in the Colophon, like most other O&#8217;Reilly books. But today I got the information directly from Karen Montgomery at O&#8217;Reilly, who designed the cover:<p></p>
<div>The bird is a <a href="http://en.wikipedia.org/wiki/Tui_(bird)">Tui</a>, a kind of bird that leaves in New Zealand, also known as a Parson Bird. Here&#8217;s a photo of a real Tui bird:</div>
<p></p>
<div>
<div class="p_embed p_image_embed">
<a href="http://zzamboni.org/blog.cf-learn.info/images/2012/03/26/the-bird-on-the-cover-of-learning-cfengine-3/39446356-Tui_on_flax.jpeg"><img alt="Tui_on_flax" height="333" src="http://zzamboni.org/blog.cf-learn.info/images/2012/03/26/the-bird-on-the-cover-of-learning-cfengine-3/39446356-Tui_on_flax.jpeg" width="500"></a>
</div>
</div>
<div>(photo by <a href="http://www.flickr.com/photos/69029168@N00">Matt Binns</a>, reused under the <a href="http://creativecommons.org/licenses/by/2.0/deed.en">Creative Commons Attribution 2.0 Generic</a> license)</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[My first batch of print books arrived]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/my-first-batch-of-print-books-arrived"/>
    <updated>2012-03-26T07:56:32-06:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/my-first-batch-of-print-books-arrived</id>
    <content type="html"><![CDATA[I&#8217;m visiting Purdue University today to give a talk and to visit old friends and colleagues. And the first box of books arrived here! It&#8217;s incredible to have the physical book in my hand.<p></p>
<div class="p_embed p_image_embed">
<img alt="Img_0515" height="640" src="http://zzamboni.org/blog.cf-learn.info/images/2012/03/26/my-first-batch-of-print-books-arrived/39422579-IMG_0515.jpeg" width="479">
</div>
<p>This is the building where I spent most of my grad school years.</p>
<p></p>
<div class="p_embed p_image_embed">
<a href="http://zzamboni.org/blog.cf-learn.info/images/2012/03/26/my-first-batch-of-print-books-arrived/39422580-IMG_0514.jpeg"><img alt="Img_0514" height="374" src="http://zzamboni.org/blog.cf-learn.info/images/2012/03/26/my-first-batch-of-print-books-arrived/39422580-IMG_0514.jpeg" width="500"></a>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CFEngine-related speaking engagements from March 26th-28th, 2012]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/cfengine-related-speaking-engagements-from-ma"/>
    <updated>2012-03-24T23:57:00-06:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/cfengine-related-speaking-engagements-from-ma</id>
    <content type="html"><![CDATA[<p>I will be giving three CFEngine related talks this week. I would love to see you at any one of them!</p>
<p></p>
<div>
<strong>March 26th</strong> - Purdue University, Lawson CS Building 3102, West Lafayette, IN, 1:30PM</div>
<p></p>
<div style="padding-left: 30px;">
<span style=""> </span>&#8220;CFEngine 3: Empowering the Next-Generation SysAdmin&#8221;</div>
<p></p>
<div>
<strong>March 27th</strong> - <a href="http://www.meetup.com/devops/events/51903632/">Chicago Devops Meetup, Morningstar, Chicaco, IL, 5:30PM</a>
</div>
<p></p>
<div style="padding-left: 30px;">
<span style=""> </span>&#8220;CFEngine 3: Empowering the Next-Generation SysAdmin&#8221;</div>
<p></p>
<div>
<strong>March 28th</strong> - <a href="http://campconferences.com/events/2012/iom.htm">CampIT conference on IT Infrastructure &amp; Operations Management, Chicago, IL, 9:00AM</a>
</div>
<p></p>
<div style="padding-left: 30px;">
<span style=""> </span>&#8220;Achieving IT Infrastructure and Operational Excellence&#8221;</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Book status: released!]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/book-status-released"/>
    <updated>2012-03-23T11:45:12-06:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/book-status-released</id>
    <content type="html"><![CDATA[<div><a href="http://shop.oreilly.com/product/0636920022022.do"><div class="p_embed p_image_embed">
<img alt="Cat" height="236" src="http://zzamboni.org/blog.cf-learn.info/images/2012/03/23/book-status-released/39333994-cat.gif" width="180">
</div>
</a></div>
<p></p>I am ecstatic to announce that the book is now officially released! You can get it here: <a href="http://shop.oreilly.com/product/0636920022022.do">http://shop.oreilly.com/product/0636920022022.do</a>. If you purchased the Early Release version, you should automatically be able to download the final version from your &#8220;Your products&#8221; page at <a href="http://oreilly.com">oreilly.com</a>.<p></p>
<div>It&#8217;s been an incredible ride, and it&#8217;s an incredible feeling to see it come to this big milestone (I won&#8217;t say &#8220;the end&#8221;, because I know this book will keep evolving).</div>
<p></p>
<div>There have been so many people who helped me through this process, including my editor (Andy Oram), all the staff at O&#8217;Reilly, who have been so professional and helpful, my very competent tech reviewers (Mark Burgess and Jesse Becker), all my colleagues at CFEngine AS, all the readers of intermediate and partial versions of the book, all the people who purchased the Early Release, and of course, my lovely wife and my two beautiful daughters, who were so patient while I worked on &#8220;the book&#8221;. Everyone gave me encouragement, incredible feedback, and tons of guidance and support. Thank you everyone!</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Syntax highlighting in "Learning CFEngine 3"]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/syntax-highlighting-in-learning-cfengine-3"/>
    <updated>2012-03-16T17:16:44-06:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/syntax-highlighting-in-learning-cfengine-3</id>
    <content type="html"><![CDATA[The electronic versions of the book contain full syntax highlighting and other useful features. I&#8217;m biased of course, but I think it is both functional and beautiful. Here&#8217;s a sample from Chapter 4:<p></p>
<blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div>
<div class="p_embed p_image_embed">
<a href="http://zzamboni.org/blog.cf-learn.info/images/2012/03/16/syntax-highlighting-in-learning-cfengine-3/39091981-final_web.pdf%20(page%20126%20of%20182)-1.jpg"><img alt="Final_web" height="527" src="http://zzamboni.org/blog.cf-learn.info/images/2012/03/16/syntax-highlighting-in-learning-cfengine-3/39091981-final_web.pdf%20(page%20126%20of%20182)-1.jpg" width="500"></a>
</div>
</div></blockquote>
<p></p>
<div>The syntax highlighting in my opinion greatly helps in reading the code. Additionally, each one of those numbered callouts in the code are in-document links that take you to the paragraph where that part of the code is described. Conversely, the callouts in the text take you back to the corresponding line in the code. And finally, most CFEngine keywords and concepts are links to the corresponding description in the CFEngine Reference Manual. In the PDF, clicking on that blue &#8220;files:&#8221; in the last paragraph will take you to <a href="http://cf-learn.info/ref/files">http://cf-learn.info/ref/files</a>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Book status: print-ready]]></title>
    <link href="http://zzamboni.org/blog.cf-learn.info/book-status-print-ready"/>
    <updated>2012-03-16T11:55:26-06:00</updated>
    <id>http://zzamboni.org/blog.cf-learn.info/book-status-print-ready</id>
    <content type="html"><![CDATA[I am very happy! I got the notification today that the final book draft has been produced and sent to the printer. This means that over the next few days the final version will be available for purchase, both as e-book and in print form. I will of course let you know when this happens. <p></p> For now, time to enjoy a relaxing weekend, the first with no book-related work in a long time :)
]]></content>
  </entry>
  
</feed>
