CFEngine Language Fundamentals (Unix)


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

CFEngine Language Fundamentals

COMPLETE TABLE OF CONTENTS

Summary of contents


Next: , Previous: Top, Up: Top

1 Declarative language for Unix-like systems

CFEngine is a program meant to automate the job of system administrators. Instead of writing ad hoc custom scripts, cfengine gives you the easy way of expressing the solution with a simple and straight forward declarative language. The declarative language allows you to specify a policy for cfengine to implement. For example as a policy, an administrator may want tmp directory to be emptied every three days, may want the password file to always have the permission 644, ensure that Apache is up all the time etc. Policies such as these and many more can easily be written for cfengine to implement. A simple code such as:

     files:
      /etc/passwd  owner=root mode=644 checksum=md5 action=fixall

will enable cfengine to implement a password file policy without any complex script. CFEngine makes the policy implementation easy and simple.


Next: , Previous: Declarative language for Unix-like systems, Up: Declarative language for Unix-like systems

1.1 First Program for Unix


Previous: First Program for Unix, Up: First Program for Unix

1.1.1 CFEngine components

CFEngine has a number of components constituting the software. They are cfagent, cfexecd, cfservd, cfenvd, cfkey, cfshow, cfenvgraph and cfrun.

In this document we will first concentrate on how to use cfagent to implement simple policies.


Next: , Previous: First Program for Unix, Up: Declarative language for Unix-like systems

1.2 Installation on Unix

To install cfengine you need the following software packages

     # install

     Flex
     Bison
     Berkeley db
     CFEngine software

     # compile

     tar cfengine-2.2.8.tar
     cd cfengine-2.2.8
     ./configure
     make
     make install

By default cfengine executables are placed in /usr/local/sbin.


Next: , Previous: Installation on Unix, Up: Declarative language for Unix-like systems

1.3 The structure of cfengine declarative language

The general structure of cfengine's declarative language is given below:

     control:

      variable_1 = ( value1 value2 ... )
      variable_2 = ( value1 value2 ... )
      ...
      variable_n = ( value1 value2 ... )

     type_stanza_1:

       [condition or class]::

         target  attribute1=value1 attribue2=value2 ...

     type_stanza_2:

       [condition or class]::

         target attribute1=value1 attribue2=value2 ...

The control stanza is a special stanza where all the variables that will be used in the policy file are defined. The control is also used to specify the order of execution, access control etc. variable1, variable2 are variable names. Some variables are reserved or predefined and some are user-defined variables. The values of the variable are specified in the parentheses.

The stanzas defines the rule type, for example files rule type, disk rule type etc. Each stanza has an optional condition for which the policy should be implemented. The condition or class (in cfengine parlance) must be followed by double colon.

Within every stanza or rule type we have attributes or options and values. Usually, such attributes are defined by cfengine. However, one can also define new class attributes using the cfengine "defined" keyword. For example the simple files stanza can have the following attributes or options: owner, mode, checksum, action etc

The values of the attributes are either predefined or user defined. For example the value for the action attribute, fixall, is predefined but the value for the mode attribute 644 is user supplied.

We also have the target which specifies the object we want to apply the policy. A target is usually a file or a directory. The combination of target, options and value defines a policy.

In summary cfengine declarative language consist of


Next: , Previous: The structure of cfengine declarative language, Up: The structure of cfengine declarative language

1.3.1 Beginner example 1 (Unix)

We are going to test cfengine with simple files rule type example. We will check if a file has mode 644 if not we change it to 644

     #cf_ex1.conf

     control:
      actionsequence = ( files )

     files:
      /home/linux/cfengineDoc/testfile mode=644 action=fixall

     #end

This policy specification asks cfengine to check if the target (testfile) has permission 644, if not cfengine will change the permission to 644. This check can be done every minute, hour depending on what you want. It will automate the administrator's job.

We have to run cfagent to test if this policy will be implemented. We first have to create the file testfile and change the permission to maybe 777. i.e chmod 777 /home/linux/cfengineDoc/testfile.

Now create a file called cf_ex1.conf and type in the file the policy in example 1. Enter the directory that contains cf_ex1.conf and execute the following command.

     /usr/local/sbin/cfagent -vKf ./cf_ex1.conf

Thus after the policy is written the cfagent robot is used to implement or run the policy specifications.

/usr/local/sbin/cfagent is where the cfengine agent is located and -v is for verbose output, -K is a command to force the immediate implementation of policy and -f is used to specify the file which contains the policy configuration. The policy configuration file is found in cf_ex1.conf. By default cfagent runs every 1 minute and if that time is not elapsed since the last run the current configuration will not be executed so K option is used to override this default behavior.

In example 1 the actionsequence variable (directive or command) has the value files. The value of the actionsequenece variable is placed in parentheses. There should a space before and after the variable value like this: ( files ).

The values of actionsequance represents the rule type and the sequence of execution. The sequence of execution is simply first come first serve. E.g actionsequenece = ( files shellcommands ) means the files command must be executed before the shellcommnds. The files stanza or rule type has the target testfile (the full path of the file should be specified) and attributes or options of the files are mode and action and the values are 644 and fixall respectively.


Previous: Beginner example 1 Unix, Up: The structure of cfengine declarative language

1.3.2 Beginner example 2 (Unix)

This example adds a shellcommand to example 1 and executes it from cfengine

     #cf_ex2.conf

     control:

      actionsequence = ( files shellcommands )

     files:

      /home/linux/cfengineDoc/testfile mode=u+rxw action=fixall

     shellcommands:

       "/bin/echo ...second cfengine script ..."

     #end


Next: , Previous: The structure of cfengine declarative language, Up: Declarative language for Unix-like systems

1.4 Sequenece vs ordering

The order in which you write the rule types in cfengine doesn't always affect the sequence of execution. For example, example 2 can be rewritten as

     #cf_ex2a.conf control: actionsequence = ( files shellcommands )
     shellcommands: "/bin/echo ...second cfengine script ..."  files:
     /home/linux/cfengineDoc/testfile mode=644 action=fixall #end

The results will be the same. The files rule type will be executed first followed by shellcommands since the actionsequence specifies so. So the bulk sequence is specified by the actionsequence but the order of rules does not matter.


Next: , Previous: Sequence vs Order Unix, Up: Declarative language for Unix-like systems

1.5 Using Variables in cfengine 2 (Unix)

Variables allow us to store data in memory for processing. Variables are declared in cfengine as follows:

      name = ( value1, value2 ... )

The name can be any name that follows the general programming standard. The name can also be a predefined name to set the value of a reserved control parameter. Example 3 shows how to work with cfengine variables.


Next: , Previous: Using Variables in cfengine 2 Unix, Up: Using Variables in cfengine 2 Unix

1.5.1 Beginner example 3 (Unix)

     #cf_ex3.conf

      control:

        actionsequence = ( shellcommands )

         hello = ( "hello cfengine " )  #hello variable

      shellcommands:

        "/bin/echo ..$(hello).."

This code declares the hello variable and assigns the value "hello cfengine". We then use shellcommands stanza to display the value of the variables. The code $(hello) shows how cfengine reference variable. There are two ways of referencing cfengine variables. We can reference a variable with parenthesis or curly braces. For example $(hello) can rewritten as ${hello}.


Previous: Beginner example 3 Unix, Up: Using Variables in cfengine 2 Unix

1.5.2 Beginner example 4 (Unix)

     #cf_ex4.conf

      control:

        actionsequence = ( shellcommands )

         hello = ( "hello cfengine " )  #hello variable

      shellcommands:

        "/bin/echo ..${hello}.."

Example 4 will produce the same result as example 3. The only difference is that the parenthesis is changed to a curly brace i.e. ${hello}.


Next: , Previous: Using Variables in cfengine 2 Unix, Up: Declarative language for Unix-like systems

1.6 Input-output (Unix)

The value of a variable can be specified in the cfengine configuration file or read from a file. Example 5 reads data from a file and stores it in a variable.


Previous: Input-output Unix, Up: Input-output Unix

1.6.1 Beginner example 5 (Unix)

     #cf_ex5.conf

      control:

        actionsequence = ( shellcommands )

        data = ( ReadFile(/home/linux/cfengineDoc/data.txt,100) )

      shellcommands:

       "/bin/echo ..$(data).."

This example reads data from the file data.txt using the cfengine ReadFile method. The output is stored in the variable data and the result displayed by shellcommands. The ReadFile() method has two parameters, the file name and the (maximum) number of characters to be read.


Next: , Previous: Input-output Unix, Up: Declarative language for Unix-like systems

1.7 Escape Sequence

Special keys such as tab, newline etc, can also be represented in cfengine to format output. The following are the some of the escape sequence.


Previous: Escape sequence, Up: Escape sequence

1.7.1 Beginner xample 5a (UNix)

     #cf_ex5a.conf

      control:

        actionsequence = ( shellcommands )

      alerts:

        linux::

            "The car cost $(n) $(dollar)20,000 "

     The output will be:
     The car cost
     $20,000


Next: , Previous: Escape sequence, Up: Declarative language for Unix-like systems

1.8 Selection or Classes

Selection or classes allow a program to decide which code to execute. In cfengine such commands are called classes. There are no if statement in cfengine, only classes. By default cfengine classifies the system environment and used the results to make decisions. The classes are Boolean with true or false values. We can see the default or defined classes by running cfagent -vp command. You also see the defined classes when you run cfagent -vf ./filename.

     Defined Classes = ( 192_168_189 192_168_189_128 32_bit Day16 Hr10
     Hr10_Q2 July Min15_20 Min19 Q2 Wednesday Yr2008 any cfengine_2
     cfengine_2_2 cfengine_2_2_7 compiled_on_linux_gnu debian
     fe80__20c_29ff_fec4_f41c i686 ipv4_192 ipv4_192_168 ipv4_192_168_189
     ipv4_192_168_189_128 linux linux_2_6_24_19_generic linux_i686
     linux_i686_2_6_24_19_generic
     linux_i686_2_6_24_19_generic__1_SMP_Wed_Jun_18_14_43_41_UTC_2008
     linux_local lsb_compliant net_iface_eth0 ubuntu ubuntu_8 ubuntu_8_4
     ubuntu_hardy undefined_domain )

Users can also define their own classes to use for decision making.


Next: , Previous: Selection or Classes, Up: Selection or Classes

1.8.1 Beginner example 6 (Unix)

This example displays the message "...cfengine classes in action.." if the operating system of my system is Linux. CFEngine will check if linux is part of the defined classes and displays the message accordingly.

     #cf_ex6.conf

      control:

      alerts:

         linux::

            "..cfengine classes in action.."

We can have two or more classes as shown in example 7


Previous: Beginner example 6 Unix, Up: Selection or Classes

1.8.2 Example 7

     #cf_ex7.conf

      control:

      alerts:

        linux::
            "..cfengine classes in action..linux"

        SuSE::
             "..cfengine classes in action..suse"

CFEngine will display only the linux message since there is no SuSE class in the defined classes above.


Next: , Previous: Selection or Classes, Up: Declarative language for Unix-like systems

1.9 Logical Operators and classes (Unix)

Logical operators are use to combine conditional statements or classes. For example we can check if a distribution is either Ubuntu or SuSE, the distribution is SuSE and the time is quarter past two and so on. CFEngine has the following logical operators:


Next: , Previous: Logical Operators and classes Unix, Up: Logical Operators and classes Unix

1.9.1 Beginner example 8 (Unix)

     #cf_ex8.conf

      control:

      alerts:

         redhat.SuSE::

            "..cfengine classes in action.."

The output is nothing, as the condition can never be satisfied.

Example 8 shows the combination of two classes redhat and SuSE. redhat.SuSE means if the distribution is redhat and SuSE display the "cfengine classes in action". Since a distribution cannot be both redhat and SuSE the results is nothing.


Next: , Previous: Beginner example 8 Unix, Up: Logical Operators and classes Unix

1.9.2 Beginner example 9 (Unix)

      #cf_ex9.conf

      control:

      alerts:

        redhat|SuSE::

          "..cfengine classes in action.."

This means if the distribution is either redhat or SuSE display the message.


Previous: Beginner example 9 Unix, Up: Logical Operators and classes Unix

1.9.3 Beginner example 10 (Unix)

     #cf_ex10.conf

      control:

      alerts:

         !redhat|Hr10::

            "..cfengine classes in action.."

This means if distribution is not redhat or the hour is 10am display the results.


Next: , Previous: Logical Operators and classes Unix, Up: Declarative language for Unix-like systems

1.10 User Define Classes

It is possible to define your own class using the define keyword or classes rule type.


Next: , Previous: User Defined Classes, Up: User Defined Classes

1.10.1 Example 11

     #cf_ex11.conf   User define classes and sequence

     control:

      classes:

         Check = ( FileExists(/home/linux/cf) )

     alerts:

        Check::

           "yes"

This example defines the class Check using the classes rule type. The method FileExists() is cfengine method which check whether or not a file exists. The value of the class Check is true if the file cf is found in /home/linux directory. The output of the policy will be `yes' if the file is found.


Next: , Previous: Example 11, Up: User Defined Classes

1.10.2 Beginner Example 12 (Unix)

Sometimes you may want cfengine to be aware of your user defined class before it is used. We do this by using the AddInstallable method.

     #cf_ex12.conf   User define classes and sequence

     control:

       #add class that might become define at run time
       AddInstallable = ( Check )

     classes:

       Check = ( FileExists(/home/linux/cf) )

     alerts:

        Check::
         "yes"


Next: , Previous: Beginner Example 12 Unix, Up: User Defined Classes

1.10.3 Beginner example 13 (Unix)

User defined classes can be define at runtime. Example 13 shows how this is done

     #cf_ex13.conf
     #User define classes and sequence

     control:
         actionsequence = ( files )
         #add class that might become define at run time
         #the order of usage is not important
         AddInstallable  = ( RCheck )

     files:
       RCheck::   #RCheck is true
         /home/linux/cfengineDoc/test mode=700 action=fixall

     files:
          #define stores the outcome of execution
          #if mode is not 777 then change to 777 and set RCheck to true

         /home/linux/cfengineDoc/test1 mode=777 action=fixall define=RCheck

This example uses the outcome of results in the second stanza (test1) to fix the file permission for the test file. The entire policy reads like this, if the file permission for test1 file is not 777 and the action is taken to change it to 777 then change the permission of the test file to 700. The order is not important; the right instruction will be executed.


Previous: Beginner example 13 Unix, Up: User Defined Classes

1.10.4 Beginner Example 14 (Unix)

     #User define classes
     control:
       #add class that might become define at run time
        actionsequence = ( files )
        AddInstallable = ( WinXP Indigo )

     files:

      Indigo::

        /usr/etc/resolv.conf owner=root action=warn

     classes:
       #list of classes of pcs
       WinXP  = ( pc121 pc122 linux )

       #-box2 and -box4 not part
       Indigo  = ( irix -box2 -box4 )

      #if file exist

       RCheck = ( FileExists(/home/linux/cfengineDoc/sequence) )

     files:

          RCheck.WinXP::
          /home/linux/cfengineDoc/test mode=600 action=fixall


Next: , Previous: User Defined Classes, Up: Declarative language for Unix-like systems

1.11 File and log rotation

An example of a useful maintenance procedure which prevents system failure is log rotation. We can do this task by using the disable stanza. Disabling a file means renaming it so that it becomes harmless. This feature is useful if you want to prevent certain dangerous files from being around, but you don't want to delete them — a deleted file cannot be examined later. The main syntax is

         disable:
            class::
               /filename
                  dest=filename
     	     type=plain/file/link/links
     	     rotate=empty/truncate/numerical-value
     	     size=numerical-value
     	     define=classlist

If a destination filename is specified, cfagent renames the source file to the destination, where possible (renaming across filesystems is not allowed). If no destination is given, cfagent renames a given file by appending the name of the file with the suffix .cfdisabled. Note that directories are only renamed if they have a specific destination specified.

A typical example of a file you would probably want to disable would be the /etc/hosts.equiv file which is often found with the ‘+’ symbol written in it, opening the system concerned to the entire NIS universe without password protection! Here is an example:


Previous: File and log rotation, Up: File and log rotation

1.11.1 Beginner Example 16 (Unix)

     	     disable:
     	           /etc/hosts.equiv
     	           /etc/nologin
     	           /usr/lib/sendmail.fc

                  sun4::
     	           /var/spool/cron/at.allow

Disabling a link deletes the link. If you wish you may use the optional syntax

     	     disable:
     	         /directory/name type=file

in order to specify that a file object should only be disabled if it is a plain file. The optional element type= can take the values plain, file, link or links. If one of these is specified, cfengine checks the type and only disables the object if there is a match. This allows you to disable a file and replace it by a link to another file for instance. NOTE that if you regularly disable a file which then gets recreated by some process, the disabled file filename. cfdisabled will be overwritten each time cfengine disables the file and therefore the contents of the original are lost each time. The rotate facility was created for just this contingency. The disable feature can be used to control the size of system log files, such as /var/adm/messages using a further option rotate. If the value rotate is set to 4, say,

     	      disable:
     	         filename  rotate=4

then cfengine renames the file concerned by appending `.1' to it and a new, empty file is created in its place with the same owner and permissions. The next time disable is executed `.1' is renamed to `.2' and the file is renamed `.1' and a new empty file is created with the same permissions. CFEngine continues to rotate the files like this keeping a maximum of four files. This is similar to the behaviour of syslog. If you simply want to empty the contents of a log file, without retaining a copy then you can use rotate=empty or rotate=truncate. For instance, to keep control of your World Wide Web server logs:

        disable:
            Sunday|Wednesday::
                /usr/local/httpd/logs/access_log  rotate=empty

This keeps a running log which is emptied each Sunday and Wednesday. The size= option in disable allows you to carry out a disable operation only if the size of the file is less than, equal to or greater than some specified size. Sizes are in bytes by default, but may also be quoted in kilobytes or megabytes using the notation:

     	     numberbytes
     	     numberkbytes
     	     numbermbytes

Only the first characters of these strings are significant, so they may be written however is convenient: e.g. 14kB, 14k, 14kilobytes etc. Examples are:

                     size=<400  # disable if file size is < 400 bytes
     	        size=400   # disable if file size is equal to 400 bytes
     	        size=>400  # disable if file size > 400 bytes

This options works with rotate or normal disabling; it is just an extra condition which must be satisfied. If a disable command results in action being taken by cfengine, an optional list of classes becomes can be switched on with the aid of a statement define=classlist in order to trigger knock-on actions. The repository declaration allows a local override of the Repository variable, on an item by item basis. If set to “off” or “none” it cancels the value of a global repository and leaves the disabled file in the same directory.


Next: , Previous: File and log rotation, Up: Declarative language for Unix-like systems

1.12 List and Array

CFEngine list allows you to specify a list of items which can be treated as a single variables. A list can be any set of names, file names etc. The example 22 shows how to create a list.


Next: , Previous: List and Array, Up: List and Array

1.12.1 Beginner example 22 (Unix)

      control:
        alist = ( "one:two:three:four:five" )

      alerts:
        linux::
          " $(alist)"

By default a list should be separated by colon. This can be change using the Split option.


Next: , Previous: Beginner example 22 Unix, Up: List and Array

1.12.2 Beginner example 23 (Unix)

     control:

        Split = ( , )

        alist = ( "one,two,three,four,five" )

     alerts:

      linux::

        " $(alist)"

The Split allows us to change the default colon to comma.

     control:

       Split = ( " " )
       mylist = ( "mark ricky bad-dude" )

     tidy:

       /mnt/home1/$(mylist) pattern=*.cfsaved age=1


Previous: Beginner example 23 Unix, Up: List and Array

1.12.3 Beginner example 23a (Unix)

     control:

       Split = ( , )
       alist = ( "one,two,three,four,five" )

     alerts:

      redhat::

        " $(alist)"

Example 23b:

     control:
        Split = ( " " )
        mylist = ( "mark ricky bad-dude" )
     tidy:
        /linux/home/$(mylist) pattern=*.cfsaved age=1

In this example cfengine will iterate and substitute mylist with each of the elements of in the list. It will then delete all .cfsaved file which is a day old in each of the directory.

The power of lists is made clear when supplied as a parameter to a method (see below).


Next: , Previous: List and Array, Up: Declarative language for Unix-like systems

1.13 Recursion

Recursion is used to iterate over a directory of files and subdirectories. The keyword for recursion is recurse (from the anonymous saying: to iterate is human, to recurse is divine). The value of recurse is from 0 to inf (infinity). Where 0 means only current directory container, 1 includes the files in the current directory and infinity means everything in the directory including subdirectories.


Previous: Recursion, Up: Recursion

1.13.1 Beginner example 23c (Unix)

     control:

      actionsequence = ( files )

     files:

      /home/linux/cfengineDoc mode=644 action=fixall recurse=inf

This example means change the mode of everything in the directory cfengineDoc to 644.

     control:

      actionsequence = ( files )

     files:

      /home/linux/cfengineDoc mode=644 action=fixall recurse=2

This example means change the mode of directory and subdirectory to 644.


Next: , Previous: Recursion, Up: Declarative language for Unix-like systems

1.14 Methods

A method is a set of instructions that achieve a specific task. It is possible to encapsulate tasks using cfengine methods. Methods in cfengine are defined as ordinary cfengine configuration files with some extra control information:

     control

      MethodName = ( name )
      MethodParameters = ( p1 p2 ... )

      method-body ...

The MethodName directive is use to specify the method name and the MethodParameters specifies the parameters. The number of parameters can zero or more. The method body is the usual cfengine policy code. It is not different from what we know so far. We begin with a simple method that displays a message.


Next: , Previous: Methods, Up: Methods

1.14.1 Beginner example 14 (Unix)

     #cf_ex14.conf   User define classes and sequence

     control:

       MethodName = ( UserClass )

     classes:

       Check = ( FileExists(/home/linux/cf) )

     alerts:

        Check::
         "Yes the cf exist"

       !Check::
          "No, cf does not exist"

This method checks if the file cf exist and display a message. The method is called UserClass and has no parameter. In cfengine it is required that a method is placed in a special directory called modules. The default location of this directory is /var/cfengine. So if you install cfengine with default dicrectory then you must copy the file cf_ex14.conf into it /var/cfengine/modules directory. The next step is to create a method call configuration file to make use of the method as in example 14.


Next: , Previous: Beginner example 14 Unix, Up: Methods

1.14.2 Beginner example 15 (Unix)

     #cf_ex15.conf

     control:

       actionsequence = ( methods )

     methods:

       UserClass(void)
         action=cf_ex14.conf #include the method here
         returnvars=null  #no return value
         server=localhost #run the method on local machine

Example 15 is the method call's configuration file. The method call has the methods rule type. It is used to call the method. Under methods rule type we call the method by name. Since our method has no parameters we supply void as parameter entry. The action directive now specifies which file contains the method. The returnvars allows the return value to be store and reuse it later. Our method has no return type so the value of return type is null. The server attribute or option allows you to specify which host will run the method. Here we chose localhost.

The next example shows how to use parameter in methods.


Next: , Previous: Beginner example 15 Unix, Up: Methods

1.14.3 Beginner example 16 (Unix)

     #cf_ex16.conf   User define classes and sequence

     control:

       MethodName = ( UserClass )
       MethodParameters = ( filename )
          #add class that might become define at run time
           AddInstallable = ( Check )
     classes:

       Check = ( FileExists("/home/linux/$(filename)") )

     alerts:

        Check::
         "Yes the cf exists"
       !Check::
          "No, cf does not exists"

This method performs the same task as example 15 however the file name will not be fix but vary. The name will now be supplied at method call. Example 17 is the method call for example 16. Note that the file path is in double quote.


Next: , Previous: Beginner example 16 Unix, Up: Methods

1.14.4 Beginner example 17 (Unix)

     control:

      actionsequence = ( methods )

     methods:

      UserClass(cf)

        action=cf_ex16.conf
        returnvars=null
        server=localhost

This example calls the method UserClass and supply the parameter cf. The cf will replace the variable or parameter filename so that the file path checked will be /home/linux/cf. As usual the action option specifies the file which contains the method. The method file must be located in the modules directory. Note that the method call configuration file should not be in the modules directory, but in the usual inputs directory.


Next: , Previous: Beginner example 17 Unix, Up: Methods

1.14.5 Method and return value

A method can return a value which could be used for further operation. In this case the return value will not be null. Example 18 illustrates how this could be done.


Next: , Previous: Method and return value, Up: Methods

1.14.6 Beginner example 18 (Unix)

     #cf_ex18.conf   User define classes and sequence

     control:

        MethodName = ( ReturnName )
       MethodParameters = ( filename )

     classes:
        every = ( any )

     alerts:
       every::
        ReturnVariables("$(filename)")

This method just accepts a file name and returns the same name. The alerts rule type is needed to return the results. The method call for example 18 is shown below.


Next: , Previous: Beginner example 18 Unix, Up: Methods

1.14.7 Beginner example 19 (Unix)

     control:

       actionsequence = ( methods )

     methods:

       ReturnName(cf)
         action=cf_ex18.conf
         returnvars=results
         server=localhost

     classes:
        every = ( any )

     alerts:

       every::

        "The file name is $(ReturnName.results)"

Here the returnvars value is results. This means the file name being returned by the method will be stored in the variable results. We then use the alerts command to display the file name. The results variable is accessed using the name of the method name.


Previous: Beginner example 19 Unix, Up: Methods

1.14.8 Beginner example 20 (Unix)

This example shows how to use more than one parameters in cfengine method.

     #cf_ex20.conf   User define classes and sequence

     control:

       actionsequence = ( editfiles )
       MethodName = ( EditMethod )
       MethodParameters = ( filename data )

     editfiles:

      { /home/linux/$(filename)

      AppendIfNoSuchLine "$(data)"
      }

     classes:
        every = ( any )

     alerts:
       every::
        ReturnVariables("The file name is $(filename) and was editted with $(data)")

Example 21 calls the method in example 20.

     #Example 21

     control:
      actionsequence = ( methods )

     methods:

      EditMethod(cf,"insert data here")
        action=cf_ex20.conf
        returnvars=results
        server=localhost

     classes:
        every = ( any )

     alerts:
        every::
          "The file name is $(EditMethod.results)"


Next: , Previous: Methods, Up: Declarative language for Unix-like systems

1.15 CFEngine built in methods

CFEngine provides a number of built-in functions for evaluating classes, based on file tests and perform other functions. Using these built-in functions is quicker than calling the shell test function.

AccessedBefore(f1,f2)
True if file 1 was accessed more recently than file 2 (UNIX atime)
ChangedBefore(f1,f2)
True if file 1's attributes were changed in any way more recently than file 2's (UNIX ctime)
ClassMatch(regexp)
True if the quoted regular expression matches one of the currently defined classes. It is wise to place ClassMatch at the end of your parsing in order to capture as many of the user-defined classes as possible. classes: userdef = ( ClassMatch(.*linux.*) )
FileExists(file)
True if the named file object (file/directory or link) exists.
GroupExists(groupname|gid)
True if the groupname or group id is registered on the system.
HostRange(basename,start-stop)
True if the current relative domain name begins with basename and ends with an integer between start and stop. Note well: matching is case insensitive (both hostname and basename are converted to all lower case for comparison.)
IsDefined(variable-id)
True if the named variable is defined. Note well: use the variable name, not its contents (that is, IsDefined(var), and not IsDefined(${var}))
IsDir(f)
True if the file f is a directory
IsLink(f)
True if the file f is a symbolic link
IsPlain(f)
True if the file f is a plain file
IsNewerThan(f1,f2)
True if file 2 was modified more recently than file 1 (UNIX mtime)
IPRange(address-range)
True if the current host lies within the specified IP range
PrepModule(module,arg1 arg2...)
True if the named module exists and can be executed. The module is assumed to follow the standard programming interface for modules (see Writing plugin modules in tutorial). Unlike actionsequence modules, these modules are evaluated immediately on parsing. Note that the module should be specified relative to the authorized module directory.
Regcmp(regexp,string or list separated string)
True if the string matched the regular expression regexp. ReturnsZero(command) True if the named shell command returns with exit code zero (success). The command is executed without a shell wrapper.
ReturnsZeroShell(command)
True if the named shell command returns with exit code zero (success) when executed in the environment of a shell wrapper.
Strcmp(s1,s2)
True if the string s1 exactly matches s2
UserExists(username|uid)
True if the username or user id is registered on the system (this does not imply that the user can log in or has a home directory).
IsGreaterThan(s1,s2)
Returns true if the value of s1 is greater than the value of s2. Note that, if the strings have numerical values, a numerical comparison is performed, otherwise a string comparison is used.
IsLessThan(s1,s2)
Returns true if the value of s1 is less than the value of s2. Note that, if the strings have numerical values, a numerical comparison is performed, otherwise a string comparison is used.


Previous: CFEngine built in methods, Up: CFEngine built in methods

1.15.1 Beginner example 21 (Unix)

      control:
       actionsequence = ( files )
       a = ( 2.12 )
       b = ( 2.11 )

     classes:

       lt = ( IsLessThan(${a},${b}) )
       gt = ( IsGreaterThan(${a},${b}) )

     alerts:

       lt:: "$(a) LESS THAN $(b)"
       gt:: "$(a) GREATER THAN $(b)"

ExecResult(command)
Executes the named command without a shell-wrapper and inserts the output into the variable. Note that, when this is used in cfengine built-in list variables, any spaces are interpreted as list separators. In other lists, normal rules for iteration apply.
ExecShellResult(command)
Executes the named command with a shell-wrapper and inserts the output into the variable. Note that, when this is used in cfengine built-in list variables, any spaces are interpreted as list separators. In other lists, normal rules for iteration apply.
RandomInt(a,b)
Generate a random integer between a and b.
ReadArray(filename,fileformat,separator,comment,Max number of bytes)
Reads up to a maximum number of bytes from a properly formatted file into a one-dimensional associated array. File formats are: (i) ‘autokey’ If this format is specified, ReadArray tries to interpret the file as a table of items separated with the separator character. Blank lines and comments (to end of line) are ignored. Items are keyed numerically starting from 1 to the maximum number in the file. The newline $(n) is always considered to be a separator, no matter what the current separator is. (ii) ‘textkey’ If this format is specified, ReadArray tries to interpret the file as a list of lines of the form: key,value
ReadFile(filename,Max number of bytes)
Read a maximum number of bytes from a file.
ReadTable(filename,fileformat,separator,comment,Max number of bytes)
Reads up to a maximum number of bytes from a properly formatted file into a two-dimensional associated array. (i) ‘autokey’ If this format is specified, ReadArray tries to interpret the file as a table of items separated with the separator character. Blank lines and comments (to end of line) are ignored. Items are keyed numerically starting from 1 to the maximum number in the file. Any lines that do not contain the correct number of separators cause the function to fail without making any assignment. (ii) ‘textkey’ If this format is specified, ReadArray tries to interpret the file as a list of lines of the form:
                       key1,key2,value1
                       key3,key4,value2

This variable would then be references as $(table[key1][key2]).

ReadList(filename,fileformat,comment,Max number of bytes)
Reads up to a maximum number of bytes from a properly formatted file into a listvariable. File formats are: lines If this format is specified, ReadList tries to interpret the file as a list of items on separate lines. The value returned is a list formatted by the Split character.
                          hosts = ( ReadList(/var/cfengine/inputs/datafile,lines,#,1000) )

ReadTCP(host/IP,portnumber,send string,Max number of bytes)
Reads up to a maximum number of bytes from a TCP service. Can be used to test whether certain services are responding to queries. It is recommended that this be used primarily to check services running on localhost. Bear in mind that this clause, executed on 100 hosts will produce the effect of a distributed denial of service attack, so the probe should be restricted to a single representative tester-host. For example:


Previous: CFEngine built in methods, Up: Declarative language for Unix-like systems

1.16 List and Methods

What makes cfengine method powerful is the iteration. It is possible iterate over a list using method. When a list is pass to a method cfengine will automatically iterate over the list.


Next: , Previous: List and methods, Up: List and methods

1.16.1 Beginner example 24 (Unix)

     #cf_ex24.conf

     control:

       MethodName = ( ReturnName )
       MethodParameters = ( filename )

     classes:
        every = ( any )

     alerts:

       every::
         ReturnVariables("$(filename)")

We call the above method with example 25


Previous: Beginner example 24 Unix, Up: List and methods

1.16.2 Beginner example 25 (Unix)

     control:

       actionsequence = ( methods )
       alist = ( one:two:three:four:five )

     methods:

       ReturnName($(alist))
       action=cf_ex24.conf
       returnvars=results
       server=localhost

     classes:
       every = ( any )

     alerts:
           every::
            "The file name is $(ReturnName.results)"


Previous: Declarative language for Unix-like systems, Up: Top

2 Beginners self-test

  • What do we use cfengine classes for
  • Name any four rule type
  • Explain how cfexecd functions
  • Name and explain various cfengine components
  • Explain why CFEngine is convergent, scalable, secure, voluntary.
  • Outline cfengine centralized infrastructure setup

Table of Contents