CFEngine 3 Solutions


Next: , Previous: (dir), Up: (dir)

CFEngine-Solutions

COMPLETE TABLE OF CONTENTS

Summary of contents


Next: , Previous: Top, Up: Top

1 Introduction

This document is under construction.


Next: , Previous: Introduction, Up: Top

2 Common issues


Next: , Previous: Common issues, Up: Common issues

2.1 Build an HPC cluster





Next: , Previous: Build an HPC cluster, Up: Common issues

2.2 Build a web farm





Next: , Previous: Build a web farm, Up: Common issues

2.3 Change detection

body common control

{
bundlesequence  => { "testbundle"  };
}

########################################################

body agent control

{
agentaccess => { "mark", "root" };
}

########################################################

bundle agent testbundle

{
files:

  "/home/mark/tmp" -> "me"

       changes      => tripwire,
       depth_search => recurse("inf"),
       action       => background;

  "/home/mark/LapTop/words" -> "you"

       changes      => tripwire,
       depth_search => recurse("inf");

}


#########################################################

body changes tripwire

{
hash           => "md5";
report_changes => "content";
update_hashes  => "true";
}

#########################################################

body action background

{
background => "true";
}

#########################################################

body depth_search recurse(d)

{
depth        => "$(d)";
}


Next: , Previous: Change detection, Up: Common issues

2.4 Garbage collection

bundle agent garbage_collection
{
files:

  "$(sys.workdir)/outputs"

    delete => tidy,
    file_select => days_old("3"),
    depth_search => recurse("inf");

}

#########################################################

body file_select days_old(days)

#
# we can build old "include", "exclude", and "ignore"
# from these as standard patterns - these bodies can
# form a library of standard patterns
#

{
mtime       => irange(ago(1,0,0,0,0,0),ago(0,0,$(days),0,0,0));
file_result => "mtime";
}

############################################

body depth_search recurse(d)

{
depth => "$(d)";
}

#########################################################

body delete tidy

{
dirlinks => "delete";          #keep/tidy/delete
rmdirs   => "true";             #none/all/sub
}


Next: , Previous: Garbage collection, Up: Common issues

2.5 Editing files

########################################################
#
# Simple test editfile
#
########################################################

#
# This assumes a file format like:
#
# [section 1]
#
# lines....
#
# [section 2]
#
# lines... etc


body common control

{
bundlesequence  => { "testbundle"  };
}

########################################################

bundle agent testbundle

{
vars:

 "1" string => "numerical backreference";

files:

  "/home/mark/tmp/cf3_test"

       create    => "true",
       edit_line => AppendIfNoLine("cfengine tcp 5308","second");


}

########################################################

bundle edit_line AppendIfNoLine(parameter,two)
  {
  vars:

    "list"        slist => { "1", "2", "3"  };
    "myscalar"   string => "hitccokckckc";

  insert_lines:

   "$(parameter) and $(two)-$(list)" location => "append";

   "NEW Special-insert!!!" select_region => MySection("New section");
   "set variable = value" select_region => MySection("New section");


   "/home/mark/tmp/insert"    insert_type => "file",
                           expand_scalars => "true",
                            select_region => MySection("New section");

  delete_lines:

    "l.*";
    "NEW.*" select_region => MySection("New section");

   # Delete LinesStarting in file

  }

########################################################

body location append

{
# If not line to match, applies to whole text body
before_after => "after";
}

########################################################

body location after(x)

{
# If not line to match, applies to whole text body
#select_line_matching => "$(x)";
before_after => "after";
}

########################################################

body select_region MySection(x)

{
select_start => "\[$(x)\]";
select_end => "\[.*\]";
}



Next: , Previous: Editing files, Up: Common issues

2.6 Editing tabular files

######################################################################
#
# File editing
#
# Normal ordering:
# - delete
# - replace | colum_edit
# - insert
# 
######################################################################


body common control

{
version => "1.2.3";
bundlesequence  => { "testbundle"  };
}

########################################################

bundle agent testbundle

{
vars:

 "userset" slist => { "one-x", "two-x", "three-x" };

files:

  # Make a copy of the password file

  "/home/mark/tmp/passwd"

       create    => "true",
       edit_line => SetUserParam("mark","6","/set/this/shell");

  "/home/mark/tmp/group"

       create    => "true",
       edit_line => AppendUserParam("root","4","@(userset)");

commands:

  "/bin/echo" args => "$(userset)";

}

########################################################

bundle edit_line SetUserParam(user,field,val)
  {
  field_edits:

   "$(user).*"

      # Set field of the file to parameter

      edit_field => col(":","$(field)","$(val)","set");
  }

########################################################

bundle edit_line AppendUserParam(user,field,allusers)
  {
  vars:

    "val" slist => { @(allusers) };

  field_edits:

   "$(user).*"

      # Set field of the file to parameter

      edit_field => col(":","$(field)","$(val)","alphanum");

  }

########################################
# Bodies
########################################

body edit_field col(split,col,newval,method)

{
field_separator => "$(split)";
select_field    => "$(col)";
value_separator  => ",";
field_value     => "$(newval)";
field_operation => "$(method)";
extend_fields => "true";
}



Next: , Previous: Editing tabular files, Up: Common issues

2.7 Distribute root passwords

######################################################################
#
# Root password distribution
# 
######################################################################

body common control

{
version => "1.2.3";
bundlesequence  => { "SetRootPassword" };
}

########################################################

bundle common g
{
vars:

  "secret_keys_dir" string => "/tmp";
}

########################################################

bundle agent SetRootPassword

{
files:

  "/var/cfengine/ppkeys/rootpw.txt"

      copy_from => scp("$(fqhost)-root.txt","master_host.example.org");

      # or $(pw_class)-root.txt

  # Test this on a copy

  "/tmp/shadow"

       edit_line => SetRootPw;

}

########################################################

bundle edit_line SetRootPw
  {
  vars:

   # Assume this file contains a single string of the form :passwdhash:
   # with : delimiters to avoid end of line/file problems

   "pw" int => readstringarray("rpw","$(sys.workdir)/ppkeys/rootpw.txt","#[^\n]*",":","1","200");

  field_edits:

   "root.*"

      # Set field of the file to parameter

      edit_field => col(":","2","$(rpw[2])","set");
  }

########################################################

bundle server passwords
{
vars:

  # Read a file of format
  #
  # classname: host1,host2,host4,IP-address,regex.*,etc
  #

       "pw_classes" int => readstringarray("acl","$(g.secret_keys_dir)/classes.txt","#[^\n]*",":","100","4000");  
  "each_pw_class" slist => getindices("acl");
 
access:

  "/secret/keys/$(each_pw_class)-root.txt"

        admit   => splitstring("$(acl[$(each_pw_class)][1])" , ":" , "100"),
    ifencrypted => "true";

}

########################################
# Bodies
########################################

body edit_field col(split,col,newval,method)

{
field_separator => "$(split)";
select_field    => "$(col)";
value_separator  => ",";
field_value     => "$(newval)";
field_operation => "$(method)";
extend_fields => "true";
}

########################################

body copy_from scp(from,server)

{
source      => "$(from)";
compare     => "digest";
encrypt     => "true";
verify      => "true";
}


Next: , Previous: Distribute root passwords, Up: Common issues

2.8 Integrate cfengine with jumpstart/kickstart





Next: , Previous: Integrate cfengine with jumpstart/kickstart, Up: Common issues

2.9 Laptop support configuration

Laptops do not need a lot of confguration support. IP addresses are set by DHCP and conditions are changeable. But you want to set your DNS search domains to familiar settings in spite of local DHCP configuration, and another useful trick is to keep a regular backup of disk changes on the local disk. This won't help against disk destruction, but it is a huge advantage when your user accidentally deletes files while travelling or offline.

#######################################################
#
# Laptop
#
#######################################################

body common control

{
bundlesequence  => { 
                   "update",
                   "garbage_collection",
                   "main",
                   "backup",
                   };

inputs          => {
                   "update.cf",
                   "site.cf",
                   "library.cf" 
                   };
}

#######################################################

body agent control
{
# if default runtime is 5 mins we need this for long jobs
ifelapsed => "15";
}

#######################################################

body monitor control
{
forgetrate => "0.7";
histograms => "true";
}

#######################################################

body executor control

{
splaytime => "1";
mailto => "mark@iu.hio.no";
smtpserver => "localhost";
mailmaxlines => "30";

# Instead of a separate update script, now do this

exec_command => "$(sys.workdir)/bin/cf-agent -f failsafe.cf && $(sys.workdir)/bin/cf-agent";
}

#######################################################
# General site issues can be in bundles like this one
#######################################################

bundle agent main

{
vars:

  "component" slist => { "cf-monitord", "cf-serverd" };

 # - - - - - - - - - - - - - - - - - - - - - - - -

files:

  "$(sys.resolv)"  # test on "/tmp/resolv.conf" #

     create        => "true",
     edit_line     => resolver,
     edit_defaults => def;

processes:

  "$(component)" restart_class => canonify("start_$(component)");

 # - - - - - - - - - - - - - - - - - - - - - - - -

commands:

   "$(sys.workdir)/bin/$(component)"

       ifvarclass => canonify("start_$(component)");
}

#######################################################
# Backup
#######################################################

bundle agent backup
{
files:

  "/home/backup"

     copy_from => cp("/home/mark"),
  depth_search => recurse("inf"),
   file_select => exclude_files,
        action => longjob;

}

#######################################################
# Garbage collection issues
#######################################################

bundle agent garbage_collection
{
files:

  "$(sys.workdir)/outputs" 

    delete => tidy,
    file_select => days_old("3"),
    depth_search => recurse("inf");


}


Next: , Previous: Laptop support configuration, Up: Common issues

2.10 Log rotation

body common control
   {
   any::

      bundlesequence  => { 
                         "testbundle"
                         };
   }


############################################

bundle agent testbundle

{
files:

  "/home/mark/tmp/rotateme"

      rename => rotate("4");
}

############################################

body rename rotate(level)

{
rotate => "$(level)";
}


Next: , Previous: Log rotation, Up: Common issues

2.11 Mount NFS filesystem

#####################################################################
# Mount NFS
#####################################################################

body common control

{
bundlesequence => { "mounts" };
}

#####################################################################

bundle agent mounts

{
storage:

  # Assumes the filesystem has been exported

  "/mnt" mount  => nfs("server.example.org","/home");
}

######################################################################

body mount nfs(server,source)

{
mount_type => "nfs";
mount_source => "$(source)";
mount_server => "$(server)";
edit_fstab => "true";
}


Next: , Previous: Mount NFS filesystem, Up: Common issues

2.12 Ordering promises

This counts to five by default. If we change ‘/bin/echo one’ to ‘/bin/echox one’, then the command will fail, causing us to skip five and go to six instead.

This shows how dependencies can be chained in spite of the order of promises in the bundle.

Normally the order of promises in a bundle is followed, within each promise type, and the types are ordered according to normal ordering.

####################################################
#
# Counting by the numbers...
#
####################################################

body common control

{
bundlesequence => { "order" };
}

####################################################

bundle agent order

{
vars:

 "list" slist => { "three", "four" };

commands:

 ok_later::

   "/bin/echo five";

 otherthing::

   "/bin/echo six";

 any::

  "/bin/echo one"    classes => d("ok_later","otherthing");
  "/bin/echo two";
  "/bin/echo $(list)";

 preserved_class::

  "/bin/echo seven";

}

############################################

body classes d(if,else)

{
promise_repaired => { "$(if)" };
repair_failed => { "$(else)" };
persist_time => "0";
}



Next: , Previous: Ordering promises, Up: Common issues

2.13 Postfix mail configuration

#######################################################
#
# Postfix
#
#######################################################

body common control

{
any::

  bundlesequence  => {
                     postfix
                     };   
}

#######################################################

bundle agent postfix

{
vars:

 "prefix"     string => "/etc";
 "smtpserver" string => "localhost";
 "mailrelay"  string => "mailx.example.org";

files:

  "$(prefix)/main.cf"     
          edit_line => prefix_postfix;

  "$(prefix)/sasl-passwd" 
          create    => "true",
          perms     => system("0600","root"),
          edit_line => AppendIfNSL("$(smtpserver) _$(fqhost):chmsxrcynz4etzefabj9frejizhs22");
}

#######################################################
# For the library
#######################################################

bundle edit_line prefix_postfix

{
#
# Value have the form NAME = "quoted space separated list"
#
vars:

  "ps[relayhost]"                  string => "[$(postfix.mailrelay)]:587";
  "ps[mydomain]"                   string => "iu.hio.no";
  "ps[smtp_sasl_auth_enable]"      string => "yes";
  "ps[smtp_sasl_password_maps]"    string => "hash:/etc/postfix/sasl-passwd";
  "ps[smtp_sasl_security_options]" string => "";
  "ps[smtp_use_tls]"               string => "yes";
  "ps[default_privs]"              string => "mailman";
  "ps[inet_protocols]"             string => "all";
  "ps[inet_interfaces]"            string => "127.0.0.1";

  "parameter_name" slist => getindices("ps");

delete_lines: 

  "$(parameter_name).*";

insert_lines:

  "$(parameter_name) = $(ps[$(parameter_name)])";

}

########################################################

bundle edit_line AppendIfNSL(parameter)
  {
  insert_lines:

    "$(parameter)"; # This is default
  }

########################################
# Library Bodies
########################################

body replace_with All(x)

{
replace_value => "$(x)";
occurrences => "all";
}

#########################################################

body perms system(x,owner)

{
mode  => "0640";
owners => { "$(owner)", "root" };
}



Next: , Previous: Postfix mail configuration, Up: Common issues

2.14 Set up a DNS server





Next: , Previous: Set up a DNS server, Up: Common issues

2.15 Set up name resolution

In cfengine 2 there is a separate action type for configuring the system resolver. In cfengine 3 this has been deprecated for this standard method using the basic functionality of cfengine. We write a reusable bundle using the editing features.

#######################################################
#
# Resolve conf
#
#######################################################

bundle common g # globals
{
vars:

 "searchlist"  slist => { 
                        "search iu.hio.no", 
                        "search cfengine.com" 
                        };

 "nameservers" slist => { 
                        "128.39.89.10", 
                        "128.39.74.16",
                        "192.168.1.103"
                        };
classes:

  # This sets a class if we are in the name server list

  "am_name_server" expression => reglist("@(nameservers)","$(sys.ipv4[eth1])");
}

#######################################################

body common control

{
any::

  bundlesequence  => {
                     "g",
                     resolver(@(g.searchlist),@(g.nameservers))
                     };   

}

#######################################################

bundle agent resolver(s,n)

{
files:

  # When passing parameters down, we have to refer to
  # a source context

  "$(sys.resolv)"  # test on "/tmp/resolv.conf" #

      create        => "true",
      edit_line     => doresolv("@(this.s)","@(this.n)"),
      edit_defaults => reconstruct;
 # or edit_defaults => modify
}

#######################################################
# For the library
#######################################################

bundle edit_line doresolv(s,n)

{
vars:

 "line" slist => { @(s), @(n) };

insert_lines:

  "$(line)";

}

#######################################################

body edit_defaults reconstruct
{
empty_file_before_editing => "true";
edit_backup => "false";
max_file_size => "100000";
}

#######################################################

body edit_defaults modify
{
empty_file_before_editing => "false";
edit_backup => "false";
max_file_size => "100000";
}


Next: , Previous: Set up name resolution, Up: Common issues

2.16 Set up a PXE boot server





Next: , Previous: Set up a PXE boot server, Up: Common issues

2.17 Set up a web server





Next: , Previous: Set up a web server, Up: Common issues

2.18 Tidying garbage files

Emulating the `tidy' feature of cfengine 2.

#######################################################
#
# Deleting files, like cf2 tidy age=0 r=inf
#
#######################################################

body common control

{
 any::

  bundlesequence  => { "testbundle" };   
}

############################################

bundle agent testbundle

{
files:

  "/tmp/test" 

    delete => tidyfiles,
    file_select => zero_age,
    depth_search => recurse("inf");
}

#########################################################

body depth_search recurse(d)

{
#include_basedir => "true";
depth => "$(d)";
}

#########################################################

body delete tidy

{
dirlinks => "delete";
rmdirs   => "false"; 
}

#########################################################

body file_select zero_age

#
# we can build old "include", "exclude", and "ignore" 
# from these as standard patterns - these bodies can
# form a library of standard patterns
#

{
mtime     => irange(ago(1,0,0,0,0,0),now);  
file_result => "mtime"; 
}


Next: , Previous: Tidying garbage files, Up: Common issues

2.19 Unmount NFS filesystem

#####################################################################
# Mount NFS
#####################################################################

body common control

{
bundlesequence => { "mounts" };
}

#####################################################################

bundle agent mounts

{
storage:

  # Assumes the filesystem has been exported

  "/mnt" mount  => nfs("server.example.org","/home");
}

######################################################################

body mount nfs(server,source)

{
mount_type => "nfs";
mount_source => "$(source)";
mount_server => "$(server)";
edit_fstab => "true";
unmount => "true";
}


Previous: Unmount NFS filesystem, Up: Common issues

2.20 Web server modules

The problem of editing the correct modules into the list of standard modules for the Apache web server. This example is based on the standard configuration deployment of SuSE Linux. Simply provide the list of modules you want and another list that you don't want.

#######################################################
#
# Apache 2 reconfig - modelled on SuSE
#
#######################################################

body common control

{
any::

  bundlesequence  => {
                     apache
                     };   
}

#######################################################

bundle agent apache

{
files:

 SuSE::

  "/etc/sysconfig/apache2" 

     edit_line => fixapache;
}

#######################################################
# For the library
#######################################################

bundle edit_line fixapache

{ 
vars:

 "add_modules"     slist => { 
                            "dav", 
                            "dav_fs", 
                            "ssl", 
                            "php5", 
                            "dav_svn",
                            "xyz",
                            "superduper"
                            };

 "del_modules"     slist => { 
                            "php3",
                            "jk",
                            "userdir",
                            "imagemap",
                            "alias"
                            };

insert_lines:

 "APACHE_CONF_INCLUDE_FILES=\"/site/masterfiles/local-http.conf\"";

field_edits:

 #####################################################################
 # APACHE_MODULES="authz_host actions alias ..."
 #####################################################################

    # Values have the form NAME = "quoted space separated list"

   "APACHE_MODULES=.*"

      # Insert module "columns" between the quoted RHS 
      # using space separators

      edit_field => quotedvar("$(add_modules)","append");

   "APACHE_MODULES=.*"

      # Delte module "columns" between the quoted RHS 
      # using space separators

      edit_field => quotedvar("$(del_modules)","delete");

   # if this line already exists, edit it  

}

########################################
# Bodies
########################################

body edit_field quotedvar(newval,method)

{
field_separator => "\"";
select_field    => "2";
value_separator  => " ";
field_value     => "$(newval)";
field_operation => "$(method)";
extend_fields => "false";
allow_blank_fields => "true";
}


Previous: Common issues, Up: Top

3 Best practice

Table of Contents