CFEngine Language Fundamentals (Windows)


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

CFEngine Language Fundamentals

COMPLETE TABLE OF CONTENTS

Summary of contents


Previous: Top, Up: Top

1 Declarative language

CFEngine is a program meant to automate the job of system administrators. Instead of writing adhoc custom scripts, cfengine gives you the easy way of expressing the solution with 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. The policies such as these and many more can easily be written for cfengine to implement. For example a simple code such as

     files:
      c:\filename  mode=644 checksum=md5 action=fixall

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


Next: , Previous: Declarative language, Up: Declarative language

1.1 CFEngine Components

As beginners we will first concentrate on how to use cfagent to implement simple policies since it is the most important component or agent of the cfengine configuration management software. Don’t rush to setup client/server configuration since it is not really needed to run cfengine except for pulling operations. The CFEngine client/server setup is only for update or copying or pulling of files from cfengine server to cfengine client. The actual configuration management is done by cfagent running on a host. By understanding how to run cfengine configuration script on your local host is more than 60% of what is required to implement cfengine network environment.


Next: , Previous: CFEngine Components, Up: Declarative language

1.2 Installation


Next: , Previous: Installation, Up: Declarative language

1.3 The structure of cfengine declarative language

The structure of cfengine declarative language is given below

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

      stanza1:

       [condition or class]::
        target  attribute1=value1, attribue2=value2 ...

      stanza2:

       [condition or class]::

         target attribute1=value1, attribue2=value2 ...  

The control stanza is a special stanza where all the global variables that will be used in the policy file are defined. The control could be used to specify the order of execution, access control etc.

variable1 ... are the variable names, they can be reserved or predefined variables or user defined variables. The values of the variable are specified in the parenthesis. The values can be a stanza or action type, a class or Boolean, a path or any appropriate user defined value. The stanzas define the rule type or action type, for example files rule type or action type, disk rule type or action type etc.

Each stanza consists of optional condition for which the policy should be implemented. The condition or class ( as called by cfengine ) must be followed by double colon. Within every stanza or rule type (action type) we have target, attributes or options, values and action. Usually, such attributes are defined by cfengine. However, one can define their own attribute using the cfengine "defined" keyword. For example the simple files stanza can have the following attributes or options: owner, mode, checksum.

The values of the attributes are either predefined or user defined. For example the value for the mode attribute 644 is user defined but the value for checksum is md5 which is predefined. The target defines the object to which cfengine will manage or operate on. A target can be a file, a directory, a process etc. action defines the operation we want cfengine to perform on a given target. We also have the target which specifies the object we want to apply the policy.

In summary cfengine declarative language consist of

Example 1

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

     #cf_ex1.conf
     control:
      actionsequence = ( files )
     files:
      /cygdrive/c:/cfengine/testfile.txt mode=000 action=fixall
     #end

This policy specification allows cfengine to check if the target (testfile.txt) has permission 000, if not cfengine will change the permission to 000. This check can be done every minute, hour depending on what you want. CFEngine will automate the administrator's job. The permission 000 means no one can read, write or execute the file.

We will run cfagent to test if this policy will be implemented. We first have to create the file testfile.txt and make it readable, writable and executable by all. To do that right click the file and go to properties -> security and change the permissions. Now create a file called cf_ex1.conf and type in the file policy in example 1. Save the file in c:\var\cfengine\inputs folder. CFEngine by default look for all the configurations files from c:\var\cfengine\inputs.

Type the following command for cfengine to implement the policy:

     c:\var\cfengine\bin>cfagent -vKf cf_ex1.conf

The directory c:\var\cfengine\bin is where the cfengine agent is located and -v is for verbose output, -K is a command to force the 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 option. In example 1 the actionsequence variable (directive or command) has the value files. The value of the actionsequenece variable is placed in parenthesis. There should be a space before and after the variable value ( files ). The values of actionsequance represent 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 testfiles.txt (the full path of the file should be specified) and attributes or options of the files are mode and action and the values are 000 and fixall respectively. The action is a special attribute. It is used to specify operation to be performed or action to be taken. The cygdrive is more reliable way of specifying cfengine path. The path /cygdrive/c/cfengine/testfile.txt will be interpreted as c:\cfengine\testfiles.txt in windows.

This example adds shell commands to example 1 and executes it from cfengine

     #cf_ex2.conf
     control:
      actionsequence = ( files shellcommands )
      files:
      /cygdrive/c/cfengine/testfile.txt mode=644 action=fixall

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

This example shows that cfengine configuration file may contain more than one action type. The files action type just fix the file permission of the testfile.txt and the shellcommands action type just echoes or displays a message `second cfengine script'.


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

1.4 Debugging CFEngine

This section helps us to understand some simple errors that we may encounter when creating cfengine configuration file. Whenever an error occurs in cfengine configuration files, cfengine will tell which line in the configuration contains the error. Using the –v option in cfagent execution helps us spot the error.

Example 2b

One of the common errors a beginner could make is the space around the actionsequence. In this example we try to remove the space around the action sequence value, files, and examine the response from cfengine.

     #cf_ex2b.conf
     control:
      actionsequence = (files)  #no space around the files rule type
     files:
      /cygdrive/c/cfengine/testfile.txt mode=000 action=fixall
     #end

Now run the following command c:\var\cfengine\bin>cfagent -vKf cf_ex1b.conf

The message you will see is: /var/cfengine/inputs/cf_ex1b.conf:2: syntax error

This means you should examine line 2 of the cf_ex1b.conf file. Usually fengine does not suggest the kind of error. As a general rule it is good to always run cfengine with the verbose option. Also any time you have an error cfengine will be able to tell the line number in which the error occurred.


Next: , Previous: Debugging CFEngine, Up: Declarative language

1.5 Sequence vrs order

The order in which you write the rule types in cfengine doesn't 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:
      /cygdrive/c/cfengine/testfile.txt 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 sequence is specified by the actionsequence but the order of rules does not matter.


Next: , Previous: Sequenece vrs order, Up: Declarative language

1.6 CFEngine Variables

Variables allow us to store data in memory for processing. It enable a programmer to reference a certain memory location. 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 predefined name. Values are either given or user supplied. A variable can hold one or more data. Example 3 shows how to work with cfengine variables.

     Example 3
     #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 references variables. There are two ways of referencing cfengine variables. We can reference a variable with parenthesis or curly bracket. For example $(hello) can be rewritten as ${hello}.

     #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 curly brace i.e. ${hello}.


Next: , Previous: CFEngine Variables, Up: Declarative language

1.7 Input/output

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

     Example 5
     #cf_ex5.conf
     control:
        actionsequence = ( shellcommands )
        data = ( ReadFile(/cygdrive/c/cfengine/data.txt,100) )  #reading from a file

      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 number of characters to be read.


Next: , Previous: Input/output, Up: Declarative language

1.8 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.

cr
Expands to the carriage-return character.
dblquote
Expands to a double quote "
dollar
Expands to `$'.
lf
Expands to a line-feed character
n
Expands to a newline character.
quote
Expands to a single quote '.
spc
Expands simply to a single space. This can be used to place spaces in filenames etc.
tab
Expands to a single tab character.

Example 5a

     #cf_ex5a.conf

     control:
        actionsequence = ( shellcommands )

     alerts:
        compiled_on_cygwin::

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

The output will be:

     The car cost
     $20,000

Write a sentence and put it in double quote


Next: , Previous: Escape sequence, Up: Declarative language

1.9 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. My system has the following define classes

     Defined Classes = ( 192_168_157 192_168_157_1 192_168_189 192_168_189_1 32_bit A
     ugust Day7 Hr11 Hr11_Q4 IBM Min55_00 Min58 Q4 Thursday Yr2008 any cfengine_2_2 c
     fengine_2_2_8 cfengine_2_2_8_pwin compiled_on_cygwin cygwin_nt_6_0_1_5_25_0_156_
     4_2_ cygwin_nt_6_0_i686 cygwin_nt_6_0_i686_1_5_25_0_156_4_2_ cygwin_nt_6_0_i686_
     1_5_25_0_156_4_2__2008_06_12_19_34 i686 ibm ipv4_192 ipv4_192_168 ipv4_192_168_1
     57 ipv4_192_168_157_1 ipv4_192_168_189 ipv4_192_168_189_1 net_iface_eth0 net_ifa
     ce_eth1 net_iface_lo nt undefined_domain )

This means I can use any of these values to make a decision. For example, this configuration

     files:
        August::
     /cygdrive/c/cfengine/testfile mode=644 action=fixall

Means the file operation should be performed if the month is August. Each of the names in the Defined Classes can be used to write a conditional statement. Thus they are meant for decision making.

Users can also define their own classes which can also be used for decision making.

Example 6 This example displays the message "...cfengine classes in action.." if the compiled_on_cygwin classes is found on your system. CFEngine will check if " compiled_on_cygwin" is part of the defined classes and displays the message accordingly.

     #cf_ex6.conf

     control:

     alerts:

        compiled_on_cygwin::

            "..cfengine classes in action.."

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

     #cf_ex7.conf

     control:

     alerts:
        compiled_on_cygwin::

            "..cfengine classes in action..windows"

        SuSe::

             "..cfengine classes in action..suse"

CFEngine will display only the first message since there is no SuSE classes in my defined classes above


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

1.10 Logical Operators and classes

Logical operators are used to combine conditional statements or classes. For example we can check if a our operating system is windows or linux, the operating system is windows and the time is quarter pass two and so on.

CFEngine has the following logical operators:

     Example 8
     #cf_ex8.conf
     control:

     alerts:

       redhat.SuSE::

            "..cfengine classes found.."

The output is nothing.

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 found". Since a distribution cannot be both redhat and suse or the two classes are not found in the defined classes above nothing is displayed.

      #cf_ex9.conf
      control:
        alerts:
          compile_on_cygwin|SuSe::
            "..at least on class is found.."

This means if either of the classes compile_on_cygwin or SuSE if found on the system, display the message.

     #cf_ex10.conf

     control:

     alerts:

       !redhat|Hr10::

            "..cfengine classes in action.."

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


Next: , Previous: Logical Operators and classes, Up: Declarative language

1.11 User Defined Classes

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

     #cf_ex11.conf   User define classes and sequence

     control:

     classes:

       Check = ( FileExists(/cygdrive/c/cfengine/cf.txt) )

     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.txt is found c:\cfengine in directory. The output of the policy will be yes if the file is found.

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

     control:
          #add class that might become define at run time
           AddInstallable = ( Check )
     classes:
       Check = ( FileExists(/cygdrive/c/cfengine/cf.txt) )

     alerts:
        Check::
         "yes"

User defined classes can be define at runtime.

     #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

          /cygdrive/c/cfengine/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

           /cygdrive/c/cfengine/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.


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

1.12 Multiple Classes

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

     classes:

       #list of classes of pcs
       WinXP  = ( pc121 pc122 linux )
       #-box2 and -box4 not part
       Indigo  = ( irix -box2 -box4 )
      #if file exist

       RCheck = ( FileExists(/cygdrive/c/cfengine/sequence.txt) )

     files:

       RCheck.WinXP::   #RCheck and pc121 or RCheck and p122 or RCheck and linux is true

         /cygdrive/c/cfengine/test.txt mode=600 action=fixall


Next: , Previous: Multiple Classes, Up: Declarative language

1.13 List

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

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

     alerts:

      compiled_on_cygwin::

       " $(alist)"

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

     control:

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

     alerts:

      compiled_on_cygwin::
       " $(alist)"

The Split method allows us to change the default colon to comma. The power of a list is made clear when it is supplied as a parameter to a method.

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

     tidy:
             /cygdrive/c/$(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.


Next: , Previous: List, Up: Declarative language

1.14 Recursion

Recursion is used to iterate a directory of files and subdirectories. The keyword for recursion is recurse. The value of recurse is from 0 to inf (infinity). Where 0 means stay in the current directory and infinity means everything in the current directory including subdirectories.

     control:
      actionsequence = ( files )

     files:
      /cygdrive/c/cfengineDoc mode=644 action=fixall recurse=inf

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

     control:
      actionsequence = ( files )

     files:

       /cygdrive/c/cfengineDoc mode=644 action=fixall recurse=1

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


Next: , Previous: Recursion, Up: Declarative language

1.15 Methods

A method is a set of instructions that achieve a specific task. It is possible to perform a task using cfengine method. Methods in cfengine is given by

     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.

     #cf_ex26.conf   User define classes and sequence
     control:

       MethodName = ( UserClass )

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

     classes:
       Check = ( FileExists(/cygdrive/c/cfengine/cf.txt) )

     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 c:\var\cfengine\modules. You should copy the cf_ex26.conf file into the modules folder. The next step is to create a method call configuration file to make use of the method as in example 27.

     #cf_ex27.conf

     control:
      actionsequence = ( methods )

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

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. In this example the local host will run the method.

The next example shows how to use parameter in methods.

Example 28

     #cf_ex28.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("/cygdrive/c/cfengine/$(filename)") )

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

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

     control:
      actionsequence = ( methods )

     methods:
      UserClass(cf)
      action=cf_ex28.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 will c:\cfengine\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.


Next: , Previous: Methods, Up: Declarative language

1.16 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 30 illustrates how this could be done.

     #cf_ex30.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 name of the file. The alerts rule type is needed to return the results. The method call for example 30 is shown below.

     control:
      actionsequence = ( methods )

     methods:
      ReturnName(cf)
      action=cf_ex30.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. Example 32 This example shows how to use more than one parameters in cfengine method.

     #cf_ex32.conf User define classes and sequence

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

     editfiles:

      {  /cygdrive/c/cfengine/$(filename)
         AppendIfNoSuchLine
          "$(data)"
      }

     classes:
        every = ( any )

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

Example 33 calls the method in example 32.

Example 33

     control:
      actionsequence = ( methods )
     methods:
      EditMethod(cf,"insert data here")
      action=cf_ex32.conf
      returnvars=results
      server=localhost
     classes:
      every = ( any )
     alerts:
           every::
            "The file name is $(EditMethod.results)"


Next: , Previous: Method and return value, Up: Declarative language

1.17 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.
     Example

     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: 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. 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. 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. 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

1.18 List and methods

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

Example 34

     #cf_ex34.conf

     control:

       MethodName = ( ReturnName )
       MethodParameters = ( filename )

     classes:
        every = ( any )

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

We call the above method with example 35

Example 35

     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)"

Table of Contents