Files Bundles and Bodies
See the files
promises and edit_line
bundles
documentation for a comprehensive reference on
the bundles, body types, and attributes used here.
To use these bodies and bundles, add the following to your policy:
body file control
{
inputs => { "files.cf" }
}
edit_line bundles
insert_before_if_no_line
Prototype: insert_before_if_no_line(before, string)
Description: Insert string
before before
if string
is not found in the file
Arguments:
before
: The regular expression matching the line whichstring
will be inserted beforestring
: The string to be prepended
Implementation:
bundle edit_line insert_before_if_no_line(before, string)
{
insert_lines:
"$(string)"
location => before($(before)),
comment => "Prepend a line to the file if it doesn't already exist";
}
insert_lines
Prototype: insert_lines(lines)
Description: Append lines
if they don't exist in the file
Arguments:
lines
: The lines to be appended
See also: insert_lines
in
edit_line
Implementation:
bundle edit_line insert_lines(lines)
{
insert_lines:
"$(lines)"
comment => "Append lines if they don't exist";
}
insert_file
Prototype: insert_file(templatefile)
Description: Reads the lines from templatefile
and inserts those into the
file being edited.
Arguments:
templatefile
: The name of the file from which to import lines.
Implementation:
bundle edit_line insert_file(templatefile)
{
insert_lines:
"$(templatefile)"
comment => "Insert the template file into the file being edited",
insert_type => "file";
}
comment_lines_matching
Prototype: comment_lines_matching(regex, comment)
Description: Comment lines in the file that matching an anchored regex
Arguments:
regex
: Anchored regex that the entire line needs to matchcomment
: A string that is prepended to matching lines
Implementation:
bundle edit_line comment_lines_matching(regex,comment)
{
replace_patterns:
"^($(regex))$"
replace_with => comment("$(comment)"),
comment => "Search and replace string";
}
uncomment_lines_matching
Prototype: uncomment_lines_matching(regex, comment)
Description: Uncomment lines of the file where the regex matches the entire text after the comment string
Arguments:
regex
: The regex that lines need to match aftercomment
comment
: The prefix of the line that is removed
Implementation:
bundle edit_line uncomment_lines_matching(regex,comment)
{
replace_patterns:
"^$(comment)\s?($(regex))$"
replace_with => uncomment,
comment => "Uncomment lines matching a regular expression";
}
comment_lines_containing
Prototype: comment_lines_containing(regex, comment)
Description: Comment lines of the file matching a regex
Arguments:
regex
: A regex that a part of the line needs to matchcomment
: A string that is prepended to matching lines
Implementation:
bundle edit_line comment_lines_containing(regex,comment)
{
replace_patterns:
"^((?!$(comment)).*$(regex).*)$"
replace_with => comment("$(comment)"),
comment => "Comment out lines in a file";
}
uncomment_lines_containing
Prototype: uncomment_lines_containing(regex, comment)
Description: Uncomment lines of the file where the regex matches parts of the text after the comment string
Arguments:
regex
: The regex that lines need to match aftercomment
comment
: The prefix of the line that is removed
Implementation:
bundle edit_line uncomment_lines_containing(regex,comment)
{
replace_patterns:
"^$(comment)\s?(.*$(regex).*)$"
replace_with => uncomment,
comment => "Uncomment a line containing a fragment";
}
delete_lines_matching
Prototype: delete_lines_matching(regex)
Description: Delete lines matching a regular expression
Arguments:
regex
: The regular expression that the lines need to match
Implementation:
bundle edit_line delete_lines_matching(regex)
{
delete_lines:
"$(regex)"
comment => "Delete lines matching regular expressions";
}
warn_lines_matching
Prototype: warn_lines_matching(regex)
Description: Warn about lines matching a regular expression
Arguments:
regex
: The regular expression that the lines need to match
Implementation:
bundle edit_line warn_lines_matching(regex)
{
delete_lines:
"$(regex)"
comment => "Warn about lines in a file",
action => warn_only;
}
prepend_if_no_line
Prototype: prepend_if_no_line(string)
Description: Prepend string
if it doesn't exist in the file
Arguments:
string
: The string to be prepended
See also: insert_lines
in
edit_line
Implementation:
bundle edit_line prepend_if_no_line(string)
{
insert_lines:
"$(string)"
location => start,
comment => "Prepend a line to the file if it doesn't already exist";
}
replace_line_end
Prototype: replace_line_end(start, end)
Description: Give lines starting with start
the ending given in end
Whitespaces will be left unmodified. For example,
replace_line_end("ftp", "2121/tcp")
would replace
"ftp 21/tcp"
with
"ftp 2121/tcp"
Arguments:
start
: The string lines have to start withend
: The string lines should end with
Implementation:
bundle edit_line replace_line_end(start,end)
{
field_edits:
"\s*$(start)\s.*"
comment => "Replace lines with $(this.start) and $(this.end)",
edit_field => line("(^|\s)$(start)\s*", "2", "$(end)","set");
}
append_to_line_end
Prototype: append_to_line_end(start, end)
Description: Append end
to any lines beginning with start
end
will be appended to all lines starting with start
and not
already ending with end
. Whitespaces will be left unmodified.
For example, append_to_line_end("kernel", "vga=791")
would replace
kernel /boot/vmlinuz root=/dev/sda7
with
kernel /boot/vmlinuz root=/dev/sda7 vga=791
WARNING: Be careful not to have multiple promises matching the same line, which would result in the line growing indefinitely.
Arguments:
start
: pattern to match lines of interestend
: string to append to matched lines
Example:
files:
"/tmp/boot-options" edit_line => append_to_line_end("kernel", "vga=791");
Implementation:
bundle edit_line append_to_line_end(start,end)
{
field_edits:
"\s*$(start)\s.*"
comment => "Append lines with $(this.start) and $(this.end)",
edit_field => line("(^|\s)$(start)\s*", "2", "$(end)","append");
}
regex_replace
Prototype: regex_replace(find, replace)
Description: Find exactly a regular expression and replace exactly the match with a string. You can think of this like a PCRE powered sed.
Arguments:
find
: The regular expressionreplace
: The replacement string
Implementation:
bundle edit_line regex_replace(find,replace)
{
replace_patterns:
"$(find)"
replace_with => value("$(replace)"),
comment => "Search and replace string";
}
resolvconf
Prototype: resolvconf(search, list)
Description: Adds search domains and name servers to the system resolver configuration.
Use this bundle to modify resolv.conf
. Existing entries for
search
and nameserver
are replaced.
Arguments:
search
: The search domains with spacelist
: An slist of nameserver addresses
Implementation:
bundle edit_line resolvconf(search,list)
{
delete_lines:
"search.*" comment => "Reset search lines from resolver";
"nameserver.*" comment => "Reset nameservers in resolver";
insert_lines:
"search $(search)" comment => "Add search domains to resolver";
"nameserver $(list)" comment => "Add name servers to resolver";
}
resolvconf_o
Prototype: resolvconf_o(search, list, options)
Description: Adds search domains, name servers and options to the system resolver configuration.
Use this bundle to modify resolv.conf
. Existing entries for
search
, nameserver
and options
are replaced.
Arguments:
search
: The search domains with spacelist
: An slist of nameserver addressesoptions
: is an slist of variables to modify the resolver
Implementation:
bundle edit_line resolvconf_o(search,list,options)
{
delete_lines:
"search.*" comment => "Reset search lines from resolver";
"nameserver.*" comment => "Reset nameservers in resolver";
"options.*" comment => "Reset options in resolver";
insert_lines:
"search $(search)" comment => "Add search domains to resolver";
"nameserver $(list)" comment => "Add name servers to resolver";
"options $(options)" comment => "Add options to resolver";
}
manage_variable_values_ini
Prototype: manage_variable_values_ini(tab, sectionName)
Description: Sets the RHS of configuration items in the file of the form
LHS=RHS
If the line is commented out with #
, it gets uncommented first.
Adds a new line if none exists.
Removes any variable value pairs not defined for the ini section.
Arguments:
tab
: An associative array containingtab[sectionName][LHS]="RHS"
. The value is not changed when theRHS
is "dontchange"sectionName
: The section in the file within which values should be modified
See also: set_variable_values_ini()
Implementation:
bundle edit_line manage_variable_values_ini(tab, sectionName)
{
vars:
"index" slist => getindices("$(tab)[$(sectionName)]");
# Be careful if the index string contains funny chars
"cindex[$(index)]" string => canonify("$(index)");
classes:
"edit_$(cindex[$(index)])" not => strcmp("$($(tab)[$(sectionName)][$(index)])","dontchange"),
comment => "Create conditions to make changes";
field_edits:
# If the line is there, but commented out, first uncomment it
"#+\s*$(index)\s*=.*"
select_region => INI_section("$(sectionName)"),
edit_field => col("=","1","$(index)","set"),
ifvarclass => "edit_$(cindex[$(index)])";
# match a line starting like the key something
"$(index)\s*=.*"
edit_field => col("=","2","$($(tab)[$(sectionName)][$(index)])","set"),
select_region => INI_section("$(sectionName)"),
classes => results("bundle", "manage_variable_values_ini_not_$(cindex[$(index)])"),
ifvarclass => "edit_$(cindex[$(index)])";
delete_lines:
".*"
select_region => INI_section("$(sectionName)"),
comment => "Remove all entries in the region so there are no extra entries";
insert_lines:
"[$(sectionName)]"
location => start,
comment => "Insert lines";
"$(index)=$($(tab)[$(sectionName)][$(index)])"
select_region => INI_section("$(sectionName)"),
ifvarclass => "!(manage_variable_values_ini_not_$(cindex[$(index)])_kept|manage_variable_values_ini_not_$(cindex[$(index)])_repaired).edit_$(cindex[$(index)])";
}
set_variable_values_ini
Prototype: set_variable_values_ini(tab, sectionName)
Description: Sets the RHS of configuration items in the file of the form
LHS=RHS
If the line is commented out with #
, it gets uncommented first.
Adds a new line if none exists.
Arguments:
tab
: An associative array containingtab[sectionName][LHS]="RHS"
. The value is not changed when theRHS
is "dontchange"sectionName
: The section in the file within which values should be modified
See also: manage_variable_values_ini()
Implementation:
bundle edit_line set_variable_values_ini(tab, sectionName)
{
vars:
"index" slist => getindices("$(tab)[$(sectionName)]");
# Be careful if the index string contains funny chars
"cindex[$(index)]" string => canonify("$(index)");
classes:
"edit_$(cindex[$(index)])" not => strcmp("$($(tab)[$(sectionName)][$(index)])","dontchange"),
comment => "Create conditions to make changes";
field_edits:
# If the line is there, but commented out, first uncomment it
"#+\s*$(index)\s*=.*"
select_region => INI_section("$(sectionName)"),
edit_field => col("=","1","$(index)","set"),
ifvarclass => "edit_$(cindex[$(index)])";
# match a line starting like the key something
"$(index)\s*=.*"
edit_field => col("=","2","$($(tab)[$(sectionName)][$(index)])","set"),
select_region => INI_section("$(sectionName)"),
classes => results("bundle", "set_variable_values_ini_not_$(cindex[$(index)])"),
ifvarclass => "edit_$(cindex[$(index)])";
insert_lines:
"[$(sectionName)]"
location => start,
comment => "Insert lines";
"$(index)=$($(tab)[$(sectionName)][$(index)])"
select_region => INI_section("$(sectionName)"),
ifvarclass => "!(set_variable_values_ini_not_$(cindex[$(index)])_kept|set_variable_values_ini_not_$(cindex[$(index)])_repaired).edit_$(cindex[$(index)])";
}
insert_ini_section
Prototype: insert_ini_section(name, config)
Description: Inserts a INI section with content
# given an array "barray"
files:
"myfile.ini" edit_line => insert_innit_section("foo", "barray");
Inserts a section in an INI file with the given configuration
key-values from the array config
.
Arguments:
name
: the name of the INI sectionconfig
: The fully-qualified name of an associative array containingv[LHS]="rhs"
Implementation:
bundle edit_line insert_ini_section(name, config)
{
vars:
"k" slist => getindices($(config));
insert_lines:
"[$(name)]"
location => start,
comment => "Insert an ini section with values if not present";
"$(k)=$($(config)[$(k)])"
location => after("[$(name)]");
}
set_quoted_values
Prototype: set_quoted_values(v)
Description: Sets the RHS of variables in shell-like files of the form:
LHS="RHS"
Adds a new line if no LHS exists, and replaces RHS values if one does exist. If the line is commented out with #, it gets uncommented first.
Arguments:
v
: The fully-qualified name of an associative array containingv[LHS]="rhs"
Example:
vars:
"stuff[lhs-1]" string => "rhs1";
"stuff[lhs-2]" string => "rhs2";
files:
"myfile"
edit_line => set_quoted_values(stuff)
See also: set_variable_values()
Implementation:
bundle edit_line set_quoted_values(v)
{
meta:
"tags"
slist =>
{
"deprecated=3.6.0",
"deprecation-reason=Generic reimplementation",
"replaced-by=set_line_based"
};
vars:
"index" slist => getindices("$(v)");
# Be careful if the index string contains funny chars
"cindex[$(index)]" string => canonify("$(index)");
field_edits:
# If the line is there, but commented out, first uncomment it
"#+\s*$(index)\s*=.*"
edit_field => col("=","1","$(index)","set");
# match a line starting like the key = something
"\s*$(index)\s*=.*"
edit_field => col("=","2",'"$($(v)[$(index)])"',"set"),
classes => results("bundle", "$(cindex[$(index)])_in_file"),
comment => "Match a line starting like key = something";
insert_lines:
'$(index)="$($(v)[$(index)])"'
comment => "Insert a variable definition",
ifvarclass => "!($(cindex[$(index)])_in_file_kept|$(cindex[$(index)])_in_file_repaired)";
}
set_variable_values
Prototype: set_variable_values(v)
Description: Sets the RHS of variables in files of the form:
LHS=RHS
Adds a new line if no LHS exists, and replaces RHS values if one does exist. If the line is commented out with #, it gets uncommented first.
Arguments:
v
: The fully-qualified name of an associative array containingv[LHS]="rhs"
Example:
vars:
"stuff[lhs-1]" string => "rhs1";
"stuff[lhs-2]" string => "rhs2";
files:
"myfile"
edit_line => set_variable_values(stuff)
See also: set_quoted_values()
Implementation:
bundle edit_line set_variable_values(v)
{
meta:
"tags"
slist =>
{
"deprecated=3.6.0",
"deprecation-reason=Generic reimplementation",
"replaced-by=set_line_based"
};
vars:
"index" slist => getindices("$(v)");
# Be careful if the index string contains funny chars
"cindex[$(index)]" string => canonify("$(index)");
"cv" string => canonify("$(v)");
field_edits:
# match a line starting like the key = something
"\s*$(index)\s*=.*"
edit_field => col("\s*$(index)\s*=","2","$($(v)[$(index)])","set"),
classes => results("bundle", "$(cv)_$(cindex[$(index)])_in_file"),
comment => "Match a line starting like key = something";
insert_lines:
"$(index)=$($(v)[$(index)])"
comment => "Insert a variable definition",
ifvarclass => "!($(cv)_$(cindex[$(index)])_in_file_kept|$(cv)_$(cindex[$(index)])_in_file_repaired)";
}
set_config_values
Prototype: set_config_values(v)
Description: Sets the RHS of configuration items in the file of the form:
LHS RHS
If the line is commented out with #
, it gets uncommented first.
Adds a new line if none exists.
Arguments:
v
: The fully-qualified name of an associative array containingv[LHS]="rhs"
Implementation:
bundle edit_line set_config_values(v)
{
meta:
"tags"
slist =>
{
"deprecated=3.6.0",
"deprecation-reason=Generic reimplementation",
"replaced-by=set_line_based"
};
vars:
"index" slist => getindices("$(v)");
# Be careful if the index string contains funny chars
"cindex[$(index)]" string => canonify("$(index)");
# Escape the value (had a problem with special characters and regex's)
"ev[$(index)]" string => escape("$($(v)[$(index)])");
# Do we have more than one line commented out?
"index_comment_matches_$(cindex[$(index)])" int => countlinesmatching("^\s*#\s*($(index)\s+.*|$(index))$","$(edit.filename)");
classes:
# Check to see if this line exists
"line_exists_$(cindex[$(index)])" expression => regline("^\s*($(index)\s.*|$(index))$","$(edit.filename)");
# if there's more than one comment, just add new (don't know who to use)
"multiple_comments_$(cindex[$(index)])" expression => isgreaterthan("$(index_comment_matches_$(cindex[$(index)]))","1");
replace_patterns:
# If the line is commented out, uncomment and replace with
# the correct value
"^\s*#\s*($(index)\s+.*|$(index))$"
comment => "Uncommented the value $(index)",
replace_with => value("$(index) $($(v)[$(index)])"),
ifvarclass => "!line_exists_$(cindex[$(index)]).!replace_attempted_$(cindex[$(index)])_reached.!multiple_comments_$(cindex[$(index)])",
classes => results("bundle", "uncommented_$(cindex[$(index)])");
# If the line is there with the wrong value, replace with
# the correct value
"^\s*($(index)\s+(?!$(ev[$(index)])$).*|$(index))$"
comment => "Correct the value $(index)",
replace_with => value("$(index) $($(v)[$(index)])"),
classes => results("bundle", "replace_attempted_$(cindex[$(index)])");
insert_lines:
# If the line doesn't exist, or there is more than one occurance
# of the LHS commented out, insert a new line and try to place it
# after the commented LHS (keep new line with old comments)
"$(index) $($(v)[$(index)])"
comment => "Insert the value, marker exists $(index)",
location => after("^\s*#\s*($(index)\s+.*|$(index))$"),
ifvarclass => "replace_attempted_$(cindex[$(index)])_reached.multiple_comments_$(cindex[$(index)])";
# If the line doesn't exist and there are no occurrences
# of the LHS commented out, insert a new line at the eof
"$(index) $($(v)[$(index)])"
comment => "Insert the value, marker doesn't exist $(index)",
ifvarclass => "replace_attempted_$(cindex[$(index)])_reached.!multiple_comments_$(cindex[$(index)])";
}
set_line_based
Prototype: set_line_based(v, sep, bp, kp, cp)
Description: Sets the RHS of configuration items in the file of the form:
LHS$(sep)RHS
Example usage for x=y
lines (e.g. rsyncd.conf):
"myfile"
edit_line => set_line_based("test.config", "=", "\s*=\s*", ".*", "\s*#\s*");
Example usage for x y
lines (e.g. sshd_config):
"myfile"
edit_line => set_line_based("test.config", " ", "\s+", ".*", "\s*#\s*");
If the line is commented out with $(cp)
, it gets uncommented first.
Adds a new line if none exists or if more than one commented-out possible matches exist.
Originally set_config_values
by Ed King.
Arguments:
v
: The fully-qualified name of an associative array containingv[LHS]="rhs"
sep
: The separator to insert, e.g.for space-separated
bp
: The key-value separation regex, e.g.\s+
for space-separatedkp
: The keys to select from v, use.*
for allcp
: The comment pattern from line-start, e.g.\s*#\s*
Implementation:
bundle edit_line set_line_based(v, sep, bp, kp, cp)
{
meta:
"tags"
slist =>
{
"replaces=set_config_values",
"replaces=set_config_values_matching",
"replaces=set_variable_values",
"replaces=set_quoted_values",
"replaces=maintain_key_values",
};
vars:
"vkeys" slist => getindices("$(v)");
"i" slist => grep($(kp), vkeys);
# Be careful if the index string contains funny chars
"ci[$(i)]" string => canonify("$(i)");
# Escape the value (had a problem with special characters and regex's)
"ev[$(i)]" string => escape("$($(v)[$(i)])");
# Do we have more than one line commented out?
"comment_matches_$(ci[$(i)])"
int => countlinesmatching("^$(cp)($(i)$(bp).*|$(i))$",
$(edit.filename));
classes:
# Check to see if this line exists
"exists_$(ci[$(i)])"
expression => regline("^\s*($(i)$(bp).*|$(i))$",
$(edit.filename));
# if there's more than one comment, just add new (don't know who to use)
"multiple_comments_$(ci[$(i)])"
expression => isgreaterthan("$(comment_matches_$(ci[$(i)]))",
"1");
replace_patterns:
# If the line is commented out, uncomment and replace with
# the correct value
"^$(cp)($(i)$(bp).*|$(i))$"
comment => "Uncommented the value '$(i)'",
replace_with => value("$(i)$(sep)$($(v)[$(i)])"),
ifvarclass => "!exists_$(ci[$(i)]).!replace_attempted_$(ci[$(i)])_reached.!multiple_comments_$(ci[$(i)])",
classes => results("bundle", "uncommented_$(ci[$(i)])");
# If the line is there with the wrong value, replace with
# the correct value
"^\s*($(i)$(bp)(?!$(ev[$(i)])$).*|$(i))$"
comment => "Correct the value '$(i)'",
replace_with => value("$(i)$(sep)$($(v)[$(i)])"),
classes => results("bundle", "replace_attempted_$(ci[$(i)])");
insert_lines:
# If the line doesn't exist, or there is more than one occurrence
# of the LHS commented out, insert a new line and try to place it
# after the commented LHS (keep new line with old comments)
"$(i)$(sep)$($(v)[$(i)])"
comment => "Insert the value, marker '$(i)' exists",
location => after("^$(cp)($(i)$(bp).*|$(i))$"),
ifvarclass => "replace_attempted_$(ci[$(i)])_reached.multiple_comments_$(ci[$(i)])";
# If the line doesn't exist and there are no occurrences
# of the LHS commented out, insert a new line at the eof
"$(i)$(sep)$($(v)[$(i)])"
comment => "Insert the value, marker '$(i)' doesn't exist",
ifvarclass => "replace_attempted_$(ci[$(i)])_reached.!multiple_comments_$(ci[$(i)]).!exists_$(ci[$(i)])";
reports:
verbose_mode|EXTRA::
"$(this.bundle): Line for '$(i)' exists" ifvarclass => "exists_$(ci[$(i)])";
"$(this.bundle): Line for '$(i)' does not exist" ifvarclass => "!exists_$(ci[$(i)])";
}
set_config_values_matching
Prototype: set_config_values_matching(v, pat)
Description: Sets the RHS of configuration items in the file of the form
LHS RHS
If the line is commented out with #
, it gets uncommented first.
Adds a new line if none exists.
Arguments:
v
: the fully-qualified name of an associative array containing v[LHS]="rhs"pat
: Only elements ofv
that match the regexpat
are use
Implementation:
bundle edit_line set_config_values_matching(v,pat)
{
meta:
"tags"
slist =>
{
"deprecated=3.6.0",
"deprecation-reason=Generic reimplementation",
"replaced-by=set_line_based"
};
vars:
"allparams" slist => getindices("$(v)");
"index" slist => grep("$(pat)", "allparams");
# Be careful if the index string contains funny chars
"cindex[$(index)]" string => canonify("$(index)");
replace_patterns:
# If the line is there, maybe commented out, uncomment and replace with
# the correct value
"^\s*($(index)\s+(?!$($(v)[$(index)])).*|# ?$(index)\s+.*)$"
comment => "Correct the value",
replace_with => value("$(index) $($(v)[$(index)])"),
classes => results("bundle", "replace_attempted_$(cindex[$(index)])");
insert_lines:
"$(index) $($(v)[$(index)])"
ifvarclass => "replace_attempted_$(cindex[$(index)])_reached";
}
append_users_starting
Prototype: append_users_starting(v)
Description: For adding to /etc/passwd
or etc/shadow
Arguments:
v
: An arrayv[username] string => "line..."
Note: To manage local users with CFEngine 3.6 and later,
consider making users
promises instead of modifying system files.
Implementation:
bundle edit_line append_users_starting(v)
{
vars:
"index" slist => getindices("$(v)");
classes:
"add_$(index)" not => userexists("$(index)"),
comment => "Class created if user does not exist";
insert_lines:
"$($(v)[$(index)])"
comment => "Append users into a password file format",
ifvarclass => "add_$(index)";
}
append_groups_starting
Prototype: append_groups_starting(v)
Description: For adding groups to /etc/group
Arguments:
v
: An arrayv[groupname] string => "line..."
Note: To manage local users with CFEngine 3.6 and later,
consider making users
promises instead of modifying system files.
Implementation:
bundle edit_line append_groups_starting(v)
{
vars:
"index" slist => getindices("$(v)");
classes:
"add_$(index)" not => groupexists("$(index)"),
comment => "Class created if group does not exist";
insert_lines:
"$($(v)[$(index)])"
comment => "Append users into a group file format",
ifvarclass => "add_$(index)";
}
set_colon_field
Prototype: set_colon_field(key, field, val)
Description: Set the value of field number field
of the line whose
first field is key
to the value val
, in a colon-separated file.
Arguments:
key
: The value the first field has to matchfield
: The field to be modifiedval
: The new value offield
Implementation:
bundle edit_line set_colon_field(key,field,val)
{
field_edits:
"$(key):.*"
comment => "Edit a colon-separated file, using the first field as a key",
edit_field => col(":","$(field)","$(val)","set");
}
set_user_field
Prototype: set_user_field(user, field, val)
Description: Set the value of field number "field" in a :-field
formatted file like /etc/passwd
Arguments:
user
: The user to be modifiedfield
: The field that should be modifiedval
: The value forfield
Note: To manage local users with CFEngine 3.6 and later,
consider making users
promises instead of modifying system files.
Implementation:
bundle edit_line set_user_field(user,field,val)
{
field_edits:
"$(user):.*"
comment => "Edit a user attribute in the password file",
edit_field => col(":","$(field)","$(val)","set");
}
append_user_field
Prototype: append_user_field(group, field, allusers)
Description: For adding users to to a file like /etc/group
at field position field
, comma separated subfields
Arguments:
group
: The group to be modifiedfield
: The field where users should be addedallusers
: The list of users to add tofield
Note: To manage local users with CFEngine 3.6 and later,
consider making users
promises instead of modifying system files.
Implementation:
bundle edit_line append_user_field(group,field,allusers)
{
vars:
"val" slist => { @(allusers) };
field_edits:
"$(group):.*"
comment => "Append users into a password file format",
edit_field => col(":","$(field)","$(val)","alphanum");
}
expand_template
Prototype: expand_template(templatefile)
Description: Read in the named text file and expand $(var)
inside the file
Arguments:
templatefile
: The name of the file
Implementation:
bundle edit_line expand_template(templatefile)
{
insert_lines:
"$(templatefile)"
insert_type => "file",
comment => "Expand variables in the template file",
expand_scalars => "true";
}
replace_or_add
Prototype: replace_or_add(pattern, line)
Description: Replace a pattern in a file with a single line.
If the pattern is not found, add the line to the file.
Arguments:
pattern
: The pattern that should be replaced The pattern must match the whole line (it is automatically anchored to the start and end of the line) to avoid ambiguity.line
: The line with which to replace matches ofpattern
Implementation:
bundle edit_line replace_or_add(pattern,line)
{
vars:
"cline" string => canonify("$(line)");
"eline" string => escape("$(line)");
replace_patterns:
"^(?!$(eline)$)$(pattern)$"
comment => "Replace a pattern here",
replace_with => value("$(line)"),
classes => results("bundle", "replace_$(cline)");
insert_lines:
"$(line)"
ifvarclass => "replace_$(cline)_reached";
}
converge
Prototype: converge(marker, lines)
Description: Converge lines
marked with marker
Any content marked with marker
is removed, then lines
are
inserted. Every line
should contain marker
.
Arguments:
marker
: The marker (not a regular expression; will be escaped)lines
: The lines to insert; all must containmarker
Implementation:
bundle edit_line converge(marker, lines)
{
vars:
"regex" string => escape($(marker));
delete_lines:
"$(regex)" comment => "Delete lines matching the marker";
insert_lines:
"$(lines)" comment => "Insert the given lines";
}
fstab_option_editor
Prototype: fstab_option_editor(method, mount, option)
Description: Add or remove /etc/fstab
options for a mount
This bundle edits the options field of a mount. The method
is a
field_operation
which can be append
, prepend
, set
, delete
,
or alphanum
. The option is OS-specific.
Arguments:
method
:field_operation
to applymount
: the mount pointoption
: the option to add or remove
Example:
files:
"/etc/fstab" edit_line => fstab_option_editor("delete", "/", "acl");
"/etc/fstab" edit_line => fstab_option_editor("append", "/", "acl");
Implementation:
bundle edit_line fstab_option_editor(method, mount, option)
{
field_edits:
"(?!#)\S+\s+$(mount)\s.+"
edit_field => fstab_options($(option), $(method));
}
agent bundles
file_mustache
Prototype: file_mustache(mustache_file, json_file, target_file)
Description: Make a file from a Mustache template and a JSON file
Arguments:
mustache_file
: the file with the Mustache templatejson_file
: a file with JSON datatarget_file
: the target file to write
Example:
methods:
"m" usebundle => file_mustache("x.mustache", "y.json", "z.txt");
Implementation:
bundle agent file_mustache(mustache_file, json_file, target_file)
{
files:
"$(target_file)"
create => "true",
edit_template => $(mustache_file),
template_data => readjson($(json_file), "100k"),
template_method => "mustache";
}
file_mustache_jsonstring
Prototype: file_mustache_jsonstring(mustache_file, json_string, target_file)
Description: Make a file from a Mustache template and a JSON string
Arguments:
mustache_file
: the file with the Mustache templatejson_string
: a string with JSON datatarget_file
: the target file to write
Example:
methods:
"m" usebundle => file_mustache_jsonstring("x.mustache", '{ "x": "y" }', "z.txt");
Implementation:
bundle agent file_mustache_jsonstring(mustache_file, json_string, target_file)
{
files:
"$(target_file)"
create => "true",
edit_template => $(mustache_file),
template_data => parsejson($(json_string)),
template_method => "mustache";
}
file_tidy
Prototype: file_tidy(file)
Description: Remove a file
Arguments:
file
: to remove
Example:
methods:
"" usebundle => file_tidy("/tmp/z.txt");
Implementation:
bundle agent file_tidy(file)
{
files:
"$(file)" delete => tidy;
reports:
"DEBUG|DEBUG_$(this.bundle)"::
"DEBUG $(this.bundle): deleting $(file) with delete => tidy";
}
dir_sync
Prototype: dir_sync(from, to)
Description: Synchronize a directory entire, deleting unknown files
Arguments:
from
: source directoryto
: destination directory
Example:
methods:
"" usebundle => dir_sync("/tmp", "/var/tmp");
Implementation:
bundle agent dir_sync(from, to)
{
files:
"$(to)/."
create => "true",
depth_search => recurse("inf"),
copy_from => copyfrom_sync($(from));
reports:
"DEBUG|DEBUG_$(this.bundle)"::
"DEBUG $(this.bundle): copying directory $(from) to $(to)";
}
file_copy
Prototype: file_copy(from, to)
Description: Copy a file
Arguments:
from
: source fileto
: destination file
Example:
methods:
"" usebundle => file_copy("/tmp/z.txt", "/var/tmp/y.txt");
Implementation:
bundle agent file_copy(from, to)
{
files:
"$(to)"
copy_from => copyfrom_sync($(from));
reports:
"DEBUG|DEBUG_$(this.bundle)"::
"DEBUG $(this.bundle): copying file $(from) to $(to)";
}
file_make
Prototype: file_make(file, str)
Description: Make a file from a string
Arguments:
file
: targetstr
: the string data
Example:
methods:
"" usebundle => file_make("/tmp/z.txt", "Some text
and some more text here");
Implementation:
bundle agent file_make(file, str)
{
vars:
"len" int => string_length($(str));
summarize::
"summary" string => format("%s...%s",
string_head($(str), 18),
string_tail($(str), 18));
classes:
"summarize" expression => isgreaterthan($(len), 40);
files:
"$(file)"
create => "true",
edit_line => insert_lines($(str)),
edit_defaults => empty;
reports:
"DEBUG|DEBUG_$(this.bundle)"::
"DEBUG $(this.bundle): creating $(file) with contents '$(str)'"
ifvarclass => "!summarize";
"DEBUG $(this.bundle): creating $(file) with contents '$(summary)'"
ifvarclass => "summarize";
}
file_make_mog
Prototype: file_make_mog(file, str, mode, owner, group)
Description: Make a file from a string with mode, owner, group
Arguments:
file
: targetstr
: the string datamode
: the file permissions in octalowner
: the file owner as a name or UIDgroup
: the file group as a name or GID
Example:
methods:
"" usebundle => file_make_mog("/tmp/z.txt", "Some text
and some more text here", "0644", "root", "root");
Implementation:
bundle agent file_make_mog(file, str, mode, owner, group)
{
vars:
"len" int => string_length($(str));
summarize::
"summary" string => format("%s...%s",
string_head($(str), 18),
string_tail($(str), 18));
classes:
"summarize" expression => isgreaterthan($(len), 40);
files:
"$(file)"
create => "true",
edit_line => insert_lines($(str)),
perms => mog($(mode), $(owner), $(group)),
edit_defaults => empty;
reports:
"DEBUG|DEBUG_$(this.bundle)"::
"DEBUG $(this.bundle): creating $(file) with contents '$(str)', mode '$(mode)', owner '$(owner)' and group '$(group)'"
ifvarclass => "!summarize";
"DEBUG $(this.bundle): creating $(file) with contents '$(summary)', mode '$(mode)', owner '$(owner)' and group '$(group)'"
ifvarclass => "summarize";
}
file_empty
Prototype: file_empty(file)
Description: Make an empty file
Arguments:
file
: target
Example:
methods:
"" usebundle => file_empty("/tmp/z.txt");
Implementation:
bundle agent file_empty(file)
{
files:
"$(file)"
create => "true",
edit_defaults => empty;
reports:
"DEBUG|DEBUG_$(this.bundle)"::
"DEBUG $(this.bundle): creating empty $(file) with 0 size";
}
file_hardlink
Prototype: file_hardlink(target, link)
Description: Make a hard link to a file
Arguments:
target
: of linklink
: the hard link's location
Example:
methods:
"" usebundle => file_hardlink("/tmp/z.txt", "/tmp/z.link");
Implementation:
bundle agent file_hardlink(target, link)
{
files:
"$(link)"
move_obstructions => "true",
link_from => linkfrom($(target), "hardlink");
reports:
"DEBUG|DEBUG_$(this.bundle)"::
"DEBUG $(this.bundle): $(link) will be a hard link to $(target)";
}
file_link
Prototype: file_link(target, link)
Description: Make a symlink to a file
Arguments:
target
: of symlinklink
: the symlink's location
Example:
methods:
"" usebundle => file_link("/tmp/z.txt", "/tmp/z.link");
Implementation:
bundle agent file_link(target, link)
{
files:
"$(link)"
move_obstructions => "true",
link_from => linkfrom($(target), "symlink");
reports:
"DEBUG|DEBUG_$(this.bundle)"::
"DEBUG $(this.bundle): $(link) will be a symlink to $(target)";
}
edit_field bodies
fstab_options
Prototype: fstab_options(newval, method)
Description: Edit the options field in a fstab format
Arguments:
newval
: the new optionmethod
:field_operation
to apply
This body edits the options field in the fstab file format. The
method
is a field_operation
which can be append
, prepend
,
set
, delete
, or alphanum
. The newval
option is OS-specific.
Example:
# from the `fstab_options_editor`
field_edits:
"(?!#)\S+\s+$(mount)\s.+"
edit_field => fstab_options($(option), $(method));
Implementation:
body edit_field fstab_options(newval, method)
{
field_separator => "\s+";
select_field => "4";
value_separator => ",";
field_value => "$(newval)";
field_operation => "$(method)";
}
quoted_var
Prototype: quoted_var(newval, method)
Description: Edit the quoted value of the matching line
Arguments:
newval
: The new valuemethod
: The method by which to edit the field
Implementation:
body edit_field quoted_var(newval,method)
{
field_separator => "\"";
select_field => "2";
value_separator => " ";
field_value => "$(newval)";
field_operation => "$(method)";
extend_fields => "false";
allow_blank_fields => "true";
}
col
Prototype: col(split, col, newval, method)
Description: Edit tabluar data with comma-separated sub-values
Arguments:
split
: The separator that defines columnscol
: The (1-based) index of the value to changenewval
: The new valuemethod
: The method by which to edit the field
Implementation:
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";
allow_blank_fields => "true";
}
line
Prototype: line(split, col, newval, method)
Description: Edit tabular data with space-separated sub-values
Arguments:
split
: The separator that defines columnscol
: The (1-based) index of the value to changenewval
: The new valuemethod
: The method by which to edit the field
Implementation:
body edit_field line(split,col,newval,method)
{
field_separator => "$(split)";
select_field => "$(col)";
value_separator => " ";
field_value => "$(newval)";
field_operation => "$(method)";
extend_fields => "true";
allow_blank_fields => "true";
}
replace_with bodies
value
Prototype: value(x)
Description: Replace matching lines
Arguments:
x
: The replacement string
Implementation:
body replace_with value(x)
{
replace_value => "$(x)";
occurrences => "all";
}
select_region bodies
INI_section
Prototype: INI_section(x)
Description: Restrict the edit_line
promise to the lines in section [x]
Arguments:
x
: The name of the section in an INI-like configuration file
Implementation:
body select_region INI_section(x)
{
select_start => "\[$(x)\]\s*";
select_end => "\[.*\]\s*";
}
edit_defaults bodies
std_defs
Prototype: std_defs
Description: Standard definitions for edit_defaults
Don't empty the file before editing starts and don't make a backup.
Implementation:
body edit_defaults std_defs
{
empty_file_before_editing => "false";
edit_backup => "false";
#max_file_size => "300000";
}
empty
Prototype: empty
Description: Empty the file before editing
No backup is made
Implementation:
body edit_defaults empty
{
empty_file_before_editing => "true";
edit_backup => "false";
#max_file_size => "300000";
}
no_backup
Prototype: no_backup
Description: Don't make a backup of the file before editing
Implementation:
body edit_defaults no_backup
{
edit_backup => "false";
}
backup_timestamp
Prototype: backup_timestamp
Description: Make a timestamped backup of the file before editing
Implementation:
body edit_defaults backup_timestamp
{
empty_file_before_editing => "false";
edit_backup => "timestamp";
#max_file_size => "300000";
}
location bodies
start
Prototype: start
Description: Editing occurs before the matched line
Implementation:
body location start
{
before_after => "before";
}
after
Prototype: after(str)
Description: Editing occurs after the line matching str
Arguments:
str
: Regular expression matching the file line location
Implementation:
body location after(str)
{
before_after => "after";
select_line_matching => "$(str)";
}
before
Prototype: before(str)
Description: Editing occurs before the line matching str
Arguments:
str
: Regular expression matching the file line location
Implementation:
body location before(str)
{
before_after => "before";
select_line_matching => "$(str)";
}
replace_with bodies
comment
Prototype: comment(c)
Description: Comment all lines matching the pattern by preprending c
Arguments:
c
: The prefix that comments out lines
Implementation:
body replace_with comment(c)
{
replace_value => "$(c) $(match.1)";
occurrences => "all";
}
uncomment
Prototype: uncomment
Description: Uncomment all lines matching the pattern by removing anything outside the matching string
Implementation:
body replace_with uncomment
{
replace_value => "$(match.1)";
occurrences => "all";
}
copy_from bodies
secure_cp
Prototype: secure_cp(from, server)
Description: Download a file from a remote server over an encrypted channel
Only copy the file if it is different from the local copy, and verify that the copy is correct.
Arguments:
from
: The location of the file on the remote serverserver
: The hostname or IP of the server from which to download
Implementation:
body copy_from secure_cp(from,server)
{
source => "$(from)";
servers => { "$(server)" };
compare => "digest";
encrypt => "true";
verify => "true";
}
remote_cp
Prototype: remote_cp(from, server)
Description: Download a file from a remote server.
Arguments:
from
: The location of the file on the remote serverserver
: The hostname or IP of the server from which to download
Implementation:
body copy_from remote_cp(from,server)
{
servers => { "$(server)" };
source => "$(from)";
compare => "mtime";
}
remote_dcp
Prototype: remote_dcp(from, server)
Description: Download a file from a remote server if it is different from the local copy.
Arguments:
from
: The location of the file on the remote serverserver
: The hostname or IP of the server from which to download
See Also: local_dcp()
Implementation:
body copy_from remote_dcp(from,server)
{
servers => { "$(server)" };
source => "$(from)";
compare => "digest";
}
local_cp
Prototype: local_cp(from)
Description: Copy a file if the modification time or creation time of the source file is newer (the default comparison mechanism).
Arguments:
from
: The path to the source file.
Example:
bundle agent example
{
files:
"/tmp/file.bak"
copy_from => local_cp("/tmp/file");
}
See Also: local_dcp()
Implementation:
body copy_from local_cp(from)
{
source => "$(from)";
}
local_dcp
Prototype: local_dcp(from)
Description: Copy a local file if the hash on the source file differs.
Arguments:
from
: The path to the source file.
Example:
bundle agent example
{
files:
"/tmp/file.bak"
copy_from => local_dcp("/tmp/file");
}
See Also: local_cp()
, remote_dcp()
Implementation:
body copy_from local_dcp(from)
{
source => "$(from)";
compare => "digest";
}
perms_cp
Prototype: perms_cp(from)
Description: Copy a local file and preserve file permissions on the local copy.
Arguments:
from
: The path to the source file.
Implementation:
body copy_from perms_cp(from)
{
source => "$(from)";
preserve => "true";
}
perms_dcp
Prototype: perms_dcp(from)
Description: Copy a local file if it is different from the existing copy and preserve file permissions on the local copy.
Arguments:
from
: The path to the source file.
Implementation:
body copy_from perms_dcp(from)
{
source => "$(from)";
preserve => "true";
compare => "digest";
}
backup_local_cp
Prototype: backup_local_cp(from)
Description: Copy a local file and keep a backup of old versions.
Arguments:
from
: The path to the source file.
Implementation:
body copy_from backup_local_cp(from)
{
source => "$(from)";
copy_backup => "timestamp";
}
seed_cp
Prototype: seed_cp(from)
Description: Copy a local file if the file does not already exist, i.e. seed the placement
Arguments:
from
: The path to the source file.
Example:
bundle agent home_dir_init
{
files:
"/home/mark.burgess/."
copy_from => seed_cp("/etc/skel"),
depth_search => recurse(inf),
file_select => all,
comment => "We want to be sure that the home directory has files that are
present in the skeleton.";
}
Implementation:
body copy_from seed_cp(from)
{
source => "$(from)";
compare => "exists";
}
sync_cp
Prototype: sync_cp(from, server)
Description: Synchronize a file with a remote server.
- If the file does not exist on the remote server then it should be purged.
- Allow types to change (directories to files and vice versa).
- The mode of the remote file should be preserved.
- Files are compared using the default comparison (mtime or ctime).
Arguments:
from
: The location of the file on the remote serverserver
: The hostname or IP of the server from which to download
Example:
files:
"/tmp/masterfiles/."
copy_from => sync_cp( "/var/cfengine/masterfiles", $(sys.policy_server) ),
depth_search => recurse(inf),
file_select => all,
comment => "Mirror masterfiles from the hub to a temporary directory";
See Also: dir_sync()
, copyfrom_sync()
Implementation:
body copy_from sync_cp(from,server)
{
servers => { "$(server)" };
source => "$(from)";
purge => "true";
preserve => "true";
type_check => "false";
}
no_backup_cp
Prototype: no_backup_cp(from)
Description: Copy a local file and don't make any backup of the previous version
Arguments:
from
: The path to the source file.
Implementation:
body copy_from no_backup_cp(from)
{
source => "$(from)";
copy_backup => "false";
}
no_backup_dcp
Prototype: no_backup_dcp(from)
Description: Copy a local file if contents have changed, and don't make any backup of the previous version
Arguments:
from
: The path to the source file.
Implementation:
body copy_from no_backup_dcp(from)
{
source => "$(from)";
copy_backup => "false";
compare => "digest";
}
no_backup_rcp
Prototype: no_backup_rcp(from, server)
Description: Download a file if it's newer than the local copy, and don't make any backup of the previous version
Arguments:
from
: The location of the file on the remote serverserver
: The hostname or IP of the server from which to download
Implementation:
body copy_from no_backup_rcp(from,server)
{
servers => { "$(server)" };
source => "$(from)";
compare => "mtime";
copy_backup => "false";
}
link_from bodies
ln_s
Prototype: ln_s(x)
Description: Create a symbolink link to x
The link is created even if the source of the link does not exist.
Arguments:
x
: The source of the link
Implementation:
body link_from ln_s(x)
{
link_type => "symlink";
source => "$(x)";
when_no_source => "force";
}
linkchildren
Prototype: linkchildren(tofile)
Description: Create a symbolink link to tofile
If the promiser is a directory, children are linked to the source, unless
entries with identical names already exist.
The link is created even if the source of the link does not exist.
Arguments:
tofile
: The source of the link
Implementation:
body link_from linkchildren(tofile)
{
source => "$(tofile)";
link_type => "symlink";
when_no_source => "force";
link_children => "true";
when_linking_children => "if_no_such_file"; # "override_file";
}
linkfrom
Prototype: linkfrom(source, type)
Description: Make any kind of link to a file
Arguments:
source
: link to thistype
: the link's type (symlink
orhardlink
)
Implementation:
body link_from linkfrom(source, type)
{
source => $(source);
link_type => $(type);
}
perms bodies
m
Prototype: m(mode)
Description: Set the file mode
Arguments:
mode
: The new mode
Implementation:
body perms m(mode)
{
mode => "$(mode)";
}
mo
Prototype: mo(mode, user)
Description: Set the file's mode and owners
Arguments:
mode
: The new modeuser
: The username of the new owner
Implementation:
body perms mo(mode,user)
{
owners => { "$(user)" };
mode => "$(mode)";
}
mog
Prototype: mog(mode, user, group)
Description: Set the file's mode, owner and group
Arguments:
mode
: The new modeuser
: The username of the new ownergroup
: The group name
Implementation:
body perms mog(mode,user,group)
{
owners => { "$(user)" };
groups => { "$(group)" };
mode => "$(mode)";
}
og
Prototype: og(u, g)
Description: Set the file's owner and group
Arguments:
u
: The username of the new ownerg
: The group name
Implementation:
body perms og(u,g)
{
owners => { "$(u)" };
groups => { "$(g)" };
}
owner
Prototype: owner(user)
Description: Set the file's owner
Arguments:
user
: The username of the new owner
Implementation:
body perms owner(user)
{
owners => { "$(user)" };
}
system_owned
Prototype: system_owned(mode)
Description: Set the file owner and group to the system default
Arguments:
mode
: the access permission in octal format
Example:
files:
"/etc/passwd" perms => system_owned("0644");
Implementation:
body perms system_owned(mode)
{
mode => "$(mode)";
owners => { "root" };
freebsd|openbsd|netbsd|darwin::
groups => { "wheel" };
linux::
groups => { "root" };
solaris::
groups => { "sys" };
}
acl bodies
access_generic
Prototype: access_generic(acl)
Description: Set the aces
of the access control as specified
Default/inherited ACLs are left unchanged. This body is applicable for both files and directories on all platforms.
Arguments:
acl
: The aces to be set
Implementation:
body acl access_generic(acl)
{
acl_method => "overwrite";
aces => { "@(acl)" };
windows::
acl_type => "ntfs";
!windows::
acl_type => "posix";
}
ntfs
Prototype: ntfs(acl)
Description: Set the aces
on NTFS file systems, and overwrite
existing ACLs.
This body requires CFEngine Enterprise.
Arguments:
acl
: The aces to be set
Implementation:
body acl ntfs(acl)
{
acl_type => "ntfs";
acl_method => "overwrite";
aces => { "@(acl)" };
}
strict
Prototype: strict
Description: Limit file access via ACLs to users with administrator privileges, overwriting existing ACLs.
Note: May need to take ownership of file/dir to be sure no-one else is allowed access.
Implementation:
body acl strict
{
acl_method => "overwrite";
windows::
aces => { "user:Administrator:rwx" };
!windows::
aces => { "user:root:rwx" };
}
depth_search bodies
recurse
Prototype: recurse(d)
Description: Search files and direcories recursively, up to the specified depth Directories on different devices are included.
Arguments:
d
: The maximum search depth
Implementation:
body depth_search recurse(d)
{
depth => "$(d)";
xdev => "true";
}
recurse_ignore
Prototype: recurse_ignore(d, list)
Description: Search files and directories recursively, but don't recurse into the specified directories
Arguments:
d
: The maximum search depthlist
: The list of directories to be excluded
Implementation:
body depth_search recurse_ignore(d,list)
{
depth => "$(d)";
exclude_dirs => { @(list) };
}
include_base
Prototype: include_base
Description: Search files and directories recursively, starting from the base directory.
Implementation:
body depth_search include_base
{
include_basedir => "true";
}
recurse_with_base
Prototype: recurse_with_base(d)
Description: Search files and directories recursively up to the specified depth, starting from the base directory and including directories on other devices.
Arguments:
d
: The maximum search depth
Implementation:
body depth_search recurse_with_base(d)
{
depth => "$(d)";
xdev => "true";
include_basedir => "true";
}
delete bodies
tidy
Prototype: tidy
Description: Delete the file and remove empty directories and links to directories
Implementation:
body delete tidy
{
dirlinks => "delete";
rmdirs => "true";
}
rename bodies
disable
Prototype: disable
Description: Disable the file
Implementation:
body rename disable
{
disable => "true";
}
rotate
Prototype: rotate(level)
Description: Rotate and store up to level
backups of the file
Arguments:
level
: The number of backups to store
Implementation:
body rename rotate(level)
{
rotate => "$(level)";
}
to
Prototype: to(file)
Description: Rename the file to file
Arguments:
file
: The new name of the file
Implementation:
body rename to(file)
{
newname => "$(file)";
}
file_select bodies
name_age
Prototype: name_age(name, days)
Description: Select files that have a matching name
and have not been modified for at least days
Arguments:
name
: A regex that matches the file namedays
: Number of days
Implementation:
body file_select name_age(name,days)
{
leaf_name => { "$(name)" };
mtime => irange(0,ago(0,0,"$(days)",0,0,0));
file_result => "mtime.leaf_name";
}
days_old
Prototype: days_old(days)
Description: Select files that have not been modified for at least days
Arguments:
days
: Number of days
Implementation:
body file_select days_old(days)
{
mtime => irange(0,ago(0,0,"$(days)",0,0,0));
file_result => "mtime";
}
size_range
Prototype: size_range(from, to)
Description: Select files that have a size within the specified range
Arguments:
from
: The lower bound of the allowed file sizeto
: The upper bound of the allowed file size
Implementation:
body file_select size_range(from,to)
{
search_size => irange("$(from)","$(to)");
file_result => "size";
}
bigger_than
Prototype: bigger_than(size)
Description: Select files that are above a given size
Arguments:
size
: The number of bytes files have
Implementation:
body file_select bigger_than(size)
{
search_size => irange("0","$(size)");
file_result => "!size";
}
exclude
Prototype: exclude(name)
Description: Select all files except those that match name
Arguments:
name
: A regular expression
Implementation:
body file_select exclude(name)
{
leaf_name => { "$(name)"};
file_result => "!leaf_name";
}
plain
Prototype: plain
Description: Select plain, regular files
Implementation:
body file_select plain
{
file_types => { "plain" };
file_result => "file_types";
}
dirs
Prototype: dirs
Description: Select directories
Implementation:
body file_select dirs
{
file_types => { "dir" };
file_result => "file_types";
}
by_name
Prototype: by_name(names)
Description: Select files that match names
Arguments:
names
: A regular expression
Implementation:
body file_select by_name(names)
{
leaf_name => { @(names)};
file_result => "leaf_name";
}
ex_list
Prototype: ex_list(names)
Description: Select all files except those that match names
Arguments:
names
: A list of regular expressions
Implementation:
body file_select ex_list(names)
{
leaf_name => { @(names)};
file_result => "!leaf_name";
}
all
Prototype: all
Description: Select all file system entries
Implementation:
body file_select all
{
leaf_name => { ".*" };
file_result => "leaf_name";
}
older_than
Prototype: older_than(years, months, days, hours, minutes, seconds)
Description: Select files older than the date-time specified
Arguments:
years
: Number of yearsmonths
: Number of monthsdays
: Number of dayshours
: Number of hoursminutes
: Number of minutesseconds
: Number of seconds
Generic older_than selection body, aimed to have a common definition handy for every case possible.
Implementation:
body file_select older_than(years, months, days, hours, minutes, seconds)
{
mtime => irange(0,ago("$(years)","$(months)","$(days)","$(hours)","$(minutes)","$(seconds)"));
file_result => "mtime";
}
filetype_older_than
Prototype: filetype_older_than(filetype, days)
Description: Select files of specified type older than specified number of days
Arguments:
filetype
: File type to selectdays
: Number of days
This body only takes a single filetype, see filetypes_older_than()
if you want to select more than one type of file.
Implementation:
body file_select filetype_older_than(filetype, days)
{
file_types => { "$(filetype)" };
mtime => irange(0,ago(0,0,"$(days)",0,0,0));
file_result => "file_types.mtime";
}
filetypes_older_than
Prototype: filetypes_older_than(filetypes, days)
Description: Select files of specified types older than specified number of days
This body only takes a list of filetypes
Arguments:
filetypes
: A list of file typesdays
: Number of days
See also: filetype_older_than()
Implementation:
body file_select filetypes_older_than(filetypes, days)
{
file_types => { @(filetypes) };
mtime => irange(0,ago(0,0,"$(days)",0,0,0));
file_result => "file_types.mtime";
}
symlinked_to
Prototype: symlinked_to(target)
Description: Select symlinks that point to $(target)
Arguments:
target
: The file the symlink should point to in order to be selected
Implementation:
body file_select symlinked_to(target)
{
file_types => { "symlink" };
issymlinkto => { "$(target)" };
file_result => "issymlinkto";
}
changes bodies
detect_all_change
Prototype: detect_all_change
Description: Detect all file changes using the best hash method
This is fierce, and will cost disk cycles
Implementation:
body changes detect_all_change
{
hash => "best";
report_changes => "all";
update_hashes => "yes";
}
detect_all_change_using
Prototype: detect_all_change_using(hash)
Description: Detect all file changes using a given hash method
Detect all changes using a configurable hashing algorithm for times when you care about both content and file stats e.g. mtime
Arguments:
hash
: supported hashing algorithm (md5, sha1, sha224, sha256, sha384, sha512, best)
Implementation:
body changes detect_all_change_using(hash)
{
hash => "$(hash)";
report_changes => "all";
update_hashes => "yes";
}
detect_content
Prototype: detect_content
Description: Detect file content changes using md5
This is a cheaper alternative
Implementation:
body changes detect_content
{
hash => "md5";
report_changes => "content";
update_hashes => "yes";
}
detect_content_using
Prototype: detect_content_using(hash)
Description: Detect file content changes using a given hash algorithm.
For times when you only care about content, not file stats e.g. mtime
Arguments:
hash
: - supported hashing algorithm (md5, sha1, sha224, sha256, sha384, sha512, best)
Implementation:
body changes detect_content_using(hash)
{
hash => "$(hash)";
report_changes => "content";
update_hashes => "yes";
}
noupdate
Prototype: noupdate
Description: Detect content changes in (small) files that should never change
Implementation:
body changes noupdate
{
hash => "sha256";
report_changes => "content";
update_hashes => "no";
}
diff
Prototype: diff
Description: Detect file content changes using sha256 and report the diff to CFEngine Enterprise
Implementation:
body changes diff
{
hash => "sha256";
report_changes => "content";
report_diffs => "true";
update_hashes => "yes";
}
all_changes
Prototype: all_changes
Description: Detect all file changes using sha256 and report the diff to CFEngine Enterprise
Implementation:
body changes all_changes
{
hash => "sha256";
report_changes => "all";
report_diffs => "true";
update_hashes => "yes";
}
diff_noupdate
Prototype: diff_noupdate
Description: Detect content changes in (small) files and report the diff to CFEngine Enterprise
Implementation:
body changes diff_noupdate
{
hash => "sha256";
report_changes => "content";
report_diffs => "true";
update_hashes => "no";
}
copy_from bodies
copyfrom_sync
Prototype: copyfrom_sync(f)
Description: Copy a directory or file with digest checksums, preserving attributes and purging leftovers
Arguments:
f
: the file or directory
Implementation:
body copy_from copyfrom_sync(f)
{
source => "$(f)";
purge => "true";
preserve => "true";
type_check => "false";
compare => "digest";
}