Jump to: navigation, search

We have standardized on cfengine version 2. Cfengine 3 is slowly gaining acceptance, and we will start looking at it after every platform we support has native packages. Until then

Repo layout and usage

Central git repository is at /afs/bx.psu.edu/service/cfengine/bxcfe.git

There is a top-level Makefile, with the following targets (others as well, but these are the only ones you need to worry about):

  • prod: does a git pull, syntax check, and releases the volume with afs-control, so you don't have to be admin
  • check: Does a syntax check by doing a cfagent -pqv against the working directory. Pass cfargs="-Dfoo" to define additional classes.

To make a change:

  • If you don't already have a clone of bxcfe.git, git clone /afs/bx.psu.edu/service/cfengine/bxcfe.git
  • Make your changes
  • Run make check cfargs="-Dfoo" to test your changes
  • git add <files you have changed> followed by git commit, or git commit <files you have changed>
  • git push. If this fails due to non fast-forward changes, git pull first, then git push
  • make prod

TODO: add a "test suite" for iterating through multiple class definitions.

  • bxcfe.git/
    • Makefile
    • inputs/
      • cfagent.conf.in (see version target in Makefile)
      • cf.site
      • cf.applications
      • cf.classes
      • cf.profiles
      • cf.app_*
      • cf.profile_*
      • update.conf
    • masterfiles/
      • misc/
      • apps/
        • foo/


The first pass performed by cfagent uses inputs/update.conf. This file should NEVER be changed without extensively testing. If this file breaks, you will have to manually fix the clients that have broken as a result!

Site-specific settings are in inputs/cf.site. This includes the actionsequence, which should be looked at to know in which order actions will be taken. Any changes to actionsequence should be discussed with everyone before changing it!

Remember, think stateful, not procedural! Define the state you wish to be in and allow the machine to converge to that state. Don't define the steps you need to get to a state, only the final state itself. If you find yourself depending on the order of actions, then you're going about it the wrong way.

If absolutely necessary, external scripts can be used to accomplish more complex tasks. These script should be short and sweet, and be copied to $(cfdir)/scripts.


Classes/groups are in inputs/cf.classes. After a particular change is defined through cfengine, applying that change to clients should involve simply editing inputs/cf.classes.

There are also host groups, named whatever you like. Host groups could then be included in profiles. Profiles and host groups should be included in role_foo and app_foo definitions.

Classes within each app, role, or profile should be prefixed with the current class namespace to avoid collision. For example, if we only want the nvidia package to be installed, we could use a ReturnsZeroShell() to define profile_workstations_has_nvidia. This is the only case where this type of state dependence should be necessary!


Applications definitions are in inputs/cf.applications, which include the appropriate inputs/cf.app_foo if the app_foo class is defined. Applications could be things like ntp, kerberos, pam, apache, etc.

Roles are defined within each app, named role_foo_client, for example.

In general, there should be at least one role defined for a particular app. Every role for an app should then be used to define the app_foo class. For example:

role_ntp_server = ( river simon jayne )
role_ntp_client = ( any -role_ntp_server )
app_ntp = ( role_ntp_server role_ntp_client )


Profiles are included in inputs/cf.profiles, which include the appropriate inputs/cf.profile_foo if the profile_foo class is defined. Profiles could be things like workstations, persephone_cnode, etc.