########################################################################### # Copyright (C) Cfengine AS # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License LGPL as published by the # Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # To the extent this program is licensed as part of the Enterprise # versions of Cfengine, the applicable Commerical Open Source License # (COSL) may apply to this file if you as a licensee so wish it. See # included file COSL.txt. ########################################################################### # # Cfengine Community Open Promise-Body Library # # This initiative started by Cfengine promotes a # standardized set of names and promise specifications # for template functionality within Cfengine 3. # # The aim is to promote an industry standard for # naming of configuration patterns, leading to a # de facto middleware of standardized syntax. # # Names should be intuitive and parameters should be # minimal to assist readability and comprehensibility. # Contributions to this file are voluntarily given to # the cfengine community, and are moderated by Cfengine. # No liability or warranty for misuse is implied. # # If you add to this file, please try to make the # contributions "self-documenting". Comments made # after the bundle/body statement are retained in # the online docs # # Subversion : $Rev: 110 $ # For Cfengine Core: 3.1.0 ################################################### # If you find Cfengine useful, please consider # # purchasing a commercial version of the software.# ################################################### ################################################### # edit_line bundles ################################################### bundle edit_line insert_lines(lines) { insert_lines: "$(lines)" comment => "Append lines if they don't exist"; } ## bundle edit_line insert_file(templatefile) { insert_lines: "$(templatefile)" comment => "Insert the template file into the file being edited", insert_type => "file"; } ## bundle edit_line comment_lines_matching(regex,comment) # Comment lines of a file matching a regex { replace_patterns: "^($(regex))$" replace_with => comment("$(comment)"), comment => "Search and replace string"; } ## bundle edit_line uncomment_lines_matching(regex,comment) # Uncomment lines of a file where the regex matches # the text after the comment string { replace_patterns: "^$(comment)\s?($(regex))$" replace_with => uncomment, comment => "Uncomment lines matching a regular expression"; } ## bundle edit_line comment_lines_containing(regex,comment) # Comment lines of a file containing a regex { replace_patterns: "^(.*$(regex).*)$" replace_with => comment("$(comment)"), comment => "Comment out lines in a file"; } ## bundle edit_line uncomment_lines_containing(regex,comment) # Uncomment lines of a file where the regex matches # the text after the comment string { replace_patterns: "^$(comment)\s?(.*$(regex).*)$" replace_with => uncomment, comment => "Uncomment a line containing a fragment"; } ## bundle edit_line delete_lines_matching(regex) { delete_lines: "$(regex)" comment => "Delete lines matching regular expressions"; } ## bundle edit_line warn_lines_matching(regex) { delete_lines: "$(regex)" comment => "Warn about lines in a file", action => warn_only; } ## bundle edit_line append_if_no_line(str) { insert_lines: "$(str)" comment => "Append a line to the file if it doesn't already exist"; } ## bundle edit_line append_if_no_lines(list) { insert_lines: "$(list)" comment => "Append lines to the file if they don't already exist"; } ## bundle edit_line replace_line_end(start,end) # # Lines starting with "$(start)" will get 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" { field_edits: "\s*$(start)\s.*" edit_field => line("(^|\s)$(start)\s*", "2", "$(end)","set"); } ## bundle edit_line append_to_line_end(start,end) # # Lines starting with "$(start)" and not ending with "$(end)" # will get appended 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 resume=/dev/sda9 vga=791" # # WARNING: Be careful not to have multiple promises matching the same line, # which would result in the line growing indefinetively. { field_edits: "\s*$(start)\s.*" edit_field => line("(^|\s)$(start)\s*", "2", "$(end)","append"); } ## bundle edit_line resolvconf(search,list) # search is the search domains with space # list is an slist of nameserver addresses { 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"; } ## bundle edit_line set_variable_values(v) # Sets the RHS of variables in the file of the form # LHS = RHS # Adds a new line if no LHS exists, repairs RHS values if one does exist # # To use: # 1) Define an array, where the keys are the LHS and the values are the RHS # "stuff[lhs-1]" string => "rhs1"; # "stuff[lhs-2]" string => "rhs2"; # 2) The parameter passed to the edit_line promise is the fully qualified # name of the array (i.e., "bundlename.stuff") WITHOUT any "$" or "@" { vars: "index" slist => getindices("$(v)"); # Be careful if the index string contains funny chars "cindex[$(index)]" string => canonify("$(index)"); field_edits: # match a line starting like the key = something "\s*$(index)\s*=.*" edit_field => col("=","2","$($(v)[$(index)])","set"), classes => if_ok("$(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"; } bundle edit_line set_config_values(v) # 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. # The argument is the fully-qualified name of an associative array containing v[LHS]="rhs" { vars: "index" slist => getindices("$(v)"); # 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+.*)$" replace_with => value("$(index) $($(v)[$(index)])"), classes => always("replace_attempted_$(cindex[$(index)])"); insert_lines: "$(index) $($(v)[$(index)])" ifvarclass => "replace_attempted_$(cindex[$(index)])"; } ## bundle edit_line set_variable_values2(file,v) # # Another implementation of set_variable_values. # The input and output should be exactly the same (except the file name), # but in some Cfengine versions there are bugs, # so this bundle can be used as a workaround. # { vars: "index" slist => getindices("$(v)"); # Be careful if the index string contains funny chars "cindex[$(index)]" string => canonify("$(index)"); "fieldc_$(cindex[$(index)])" int => getfields("$(index).*","$(file)","=","FIELD_$(cindex[$(index)])"); classes: "$(cindex[$(index)])_in_file" expression => strcmp("$(index)=$($(v)[$(index)])", "$(FIELD_$(index)[1])=$(FIELD_$(index)[2])"); delete_lines: # delete any lhs when no match "$(index)=.*", ifvarclass => "!$(cindex[$(index)])_in_file"; insert_lines: "$(index)=$($(v)[$(index)])", comment => "Insert a variable definition", ifvarclass => "!$(cindex[$(index)])_in_file"; } ## bundle edit_line append_users_starting(v) # For adding to /etc/passwd or etc/shadow, needs # an array v[username] string => "line..." { vars: "index" slist => getindices("$(v)"); classes: "add_$(index)" not => userexists("$(index)"); insert_lines: "$($(v)[$(index)])", comment => "Append users into a password file format", ifvarclass => "add_$(index)"; } ## bundle edit_line append_groups_starting(v) # For adding groups to /etc/group, needs # an array v[groupname] string => "line..." { vars: "index" slist => getindices("$(v)"); classes: "add_$(index)" not => groupexists("$(index)"); insert_lines: "$($(v)[$(index)])", comment => "Append users into a group file format", ifvarclass => "add_$(index)"; } ## bundle edit_line set_user_field(user,field,val) # Set the value of field number "field" in # a :-field formatted file like /etc/passwd { field_edits: "$(user):.*" comment => "Edit a user attribute in the password file", edit_field => col(":","$(field)","$(val)","set"); } ## bundle edit_line append_user_field(group,field,allusers) # For adding users to to a file like /etc/group # at field position "field", comma separated subfields { vars: "val" slist => { @(allusers) }; field_edits: "$(group):.*" comment => "Append users into a password file format", edit_field => col(":","$(field)","$(val)","alphanum"); } ## bundle edit_line expand_template(templatefile) # Read in the named text file and expand $(var) # inside the file { insert_lines: "$(templatefile)" insert_type => "file", comment => "Expand variables in the template file", expand_scalars => "true"; } bundle edit_line replace_or_add(pattern,line) # Replace a pattern in a file with a single line. # If the pattern is not found, add the line to the file. # The pattern must match the whole line (it is automatically # anchored to the start and end of the line) to avoid # ambiguity. { vars: "cline" string => canonify("$(line)"); replace_patterns: "^(?!$(line))$(pattern)$" replace_with => value("$(line)"), classes => always("replace_done_$(cline)"); insert_lines: "$(line)" ifvarclass => "replace_done_$(cline)"; } ## bundle agent cronjob(commands,user,hours,mins) # For adding lines to crontab for a user # methods: # "cron" usebundle => cronjob("/bin/ls","mark","*","5,10"); { vars: SuSE:: "crontab" string => "/var/spool/cron/tabs"; redhat|fedora:: "crontab" string => "/var/spool/cron"; !(SuSE|redhat|fedora):: "crontab" string => "/var/spool/cron/crontabs"; files: !windows:: "$(crontab)/$(user)" comment => "A user's regular batch jobs are added to this file", create => "true", edit_line => append_if_no_line("$(mins) $(hours) * * * $(commands)"), perms => mo("644","$(user)"), classes => if_repaired("changed_crontab"); processes: changed_crontab:: "cron" comment => "Most crons need to be huped after file changes", signals => { "hup" }; } ## ## editing bodies ## 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"; } ## 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"; } ## 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"; } ## body replace_with value(x) { replace_value => "$(x)"; occurrences => "all"; } ## body select_region INI_section(x) { select_start => "\[$(x)\]\s*"; select_end => "\[.*\]\s*"; } ## ## edit_defaults ## body edit_defaults std_defs { empty_file_before_editing => "false"; edit_backup => "false"; max_file_size => "300000"; } ## body edit_defaults empty { empty_file_before_editing => "true"; edit_backup => "false"; max_file_size => "300000"; } ## body edit_defaults no_backup { edit_backup => "false"; } ## ## location ## body location start { before_after => "before"; } ## body location after(str) { before_after => "after"; select_line_matching => "$(str)"; } ## ## replace_with ## ## body replace_with comment(c) { replace_value => "$(c) $(match.1)"; occurrences => "all"; } ## body replace_with uncomment { replace_value => "$(match.1)"; occurrences => "all"; } #################################################### ## agent bodyparts #################################################### ## ## action ## body action if_elapsed(x) { ifelapsed => "$(x)"; expireafter => "$(x)"; } ## body action measure_performance(x) { measurement_class => "Detect changes in $(this.promiser)"; ifelapsed => "$(x)"; expireafter => "$(x)"; } ## body action warn_only { action_policy => "warn"; ifelapsed => "60"; } ## body action bg(elapsed,expire) { ifelapsed => "$(elapsed)"; expireafter => "$(expire)"; background => "true"; } ## body action ifwin_bg { windows:: background => "true"; } ## body action immediate { ifelapsed => "0"; } ## body action policy(p) { action_policy => "$(p)"; } ## # Log a message to log=[/file|stdout] body action log_repaired(log,message) { log_string => "$(sys.date), $(message)"; log_repaired => "$(log)"; } ### body action log_verbose { log_level => "verbose"; } ## ## contain ## body contain silent { no_output => "true"; } ## body contain in_dir(s) { chdir => "$(s)"; } ## body contain in_dir_shell(s) { chdir => "$(s)"; useshell => "true"; } ## body contain silent_in_dir(s) { chdir => "$(s)"; no_output => "true"; } ## body contain in_shell { useshell => "true"; } ## body contain in_shell_bg { useshell => "true"; background => "true"; } ## body contain in_shell_and_silent { useshell => "true"; no_output => "true"; } ## body contain setuid(x) { exec_owner => "$(x)"; useshell => "false"; } ## body contain setuid_sh(x) { exec_owner => "$(x)"; useshell => "true"; } ## body contain setuidgid_sh(owner,group) { exec_owner => "$(owner)"; exec_group => "$(group)"; useshell => "true"; } ## body contain jail(owner,root,dir) { exec_owner => "$(owner)"; useshell => "true"; chdir => "$(dir)"; chroot => "$(root)"; } ## ## classes ## body classes if_repaired(x) { promise_repaired => { "$(x)" }; } ## body classes if_else(yes,no) { promise_kept => { "$(yes)" }; promise_repaired => { "$(yes)" }; repair_failed => { "$(no)" }; repair_denied => { "$(no)" }; repair_timeout => { "$(no)" }; } ## body classes cf2_if_else(yes,no) # meant to match cf2 semantics { promise_repaired => { "$(yes)" }; repair_failed => { "$(no)" }; repair_denied => { "$(no)" }; repair_timeout => { "$(no)" }; } ## body classes if_notkept(x) { repair_failed => { "$(x)" }; repair_denied => { "$(x)" }; repair_timeout => { "$(x)" }; } ## body classes if_ok(x) { promise_repaired => { "$(x)" }; promise_kept => { "$(x)" }; } ## body classes cmd_repair(code,cl) { repaired_returncodes => { "$(code)" }; promise_repaired => { "$(cl)" }; } ## ## Persistent classes ## body classes state_repaired(x) { promise_repaired => { "$(x)" }; persist_time => "10"; } ## body classes enumerate(x) # # This is used by commercial editions to count # instances of jobs in a cluster # { promise_repaired => { "mXC_$(x)" }; promise_kept => { "mXC_$(x)" }; persist_time => "15"; } ## body classes always(x) # Define a class no matter what the outcome of the promise is { promise_repaired => { "$(x)" }; promise_kept => { "$(x)" }; repair_failed => { "$(x)" }; repair_denied => { "$(x)" }; repair_timeout => { "$(x)" }; } ################################################### # agent bundles ################################################### ##.................................................. ## files promises ##.................................................. ## ## copy_from ## body copy_from secure_cp(from,server) { source => "$(from)"; servers => { "$(server)" }; compare => "digest"; encrypt => "true"; verify => "true"; } ## body copy_from remote_cp(from,server) { servers => { "$(server)" }; source => "$(from)"; compare => "mtime"; } ## body copy_from remote_dcp(from,server) { servers => { "$(server)" }; source => "$(from)"; compare => "digest"; } ## body copy_from local_cp(from) { source => "$(from)"; } ## body copy_from local_dcp(from) { source => "$(from)"; compare => "digest"; } ## body copy_from perms_cp(from) { source => "$(from)"; preserve => "true"; } body copy_from backup_local_cp(from) # Local copy, keeping a backup of old versions { source => "$(from)"; copy_backup => "timestamp"; } ## # Copy only if the file does not already exist, i.e. seed the placement body copy_from seed_cp(from) { source => "$(from)"; compare => "exists"; } ## body copy_from sync_cp(from,server) { servers => { "$(server)" }; source => "$(from)"; purge => "true"; preserve => "true"; type_check => "false"; } ## body copy_from no_backup_cp(from) { source => "$(from)"; copy_backup => "false"; } ## body copy_from no_backup_dcp(from) { source => "$(from)"; copy_backup => "false"; compare => "digest"; } ## body copy_from no_backup_rcp(from,server) { servers => { "$(server)" }; source => "$(from)"; compare => "mtime"; copy_backup => "false"; } ## ## link_from ## body link_from ln_s(x) { link_type => "symlink"; source => "$(x)"; when_no_source => "force"; } ## 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"; } ## ## perms ## body perms m(mode) { mode => "$(mode)"; } ## body perms mo(mode,user) { owners => { "$(user)" }; mode => "$(mode)"; } ## body perms mog(mode,user,group) { owners => { "$(user)" }; groups => { "$(group)" }; mode => "$(mode)"; } ## body perms og(u,g) { owners => { "$(u)" }; groups => { "$(g)" }; } ## body perms owner(user) { owners => { "$(user)" }; } ## ## ACLS (extended Unix perms) ## body acl access_generic(acl) # default/inherited ACLs are left unchanged, # applicable for both files and directories on all platforms { acl_method => "overwrite"; aces => { "@(acl)" }; windows:: acl_type => "ntfs"; !windows:: acl_type => "posix"; } ## body acl ntfs(acl) { acl_type => "ntfs"; acl_method => "overwrite"; aces => { "@(acl)" }; } ## body acl strict # NOTE: May need to take ownership of file/dir # to be sure no-one else is allowed access { acl_method => "overwrite"; windows:: aces => { "user:Administrator:rwx" }; !windows:: aces => { "user:root:rwx" }; } ## ## depth_search ## body depth_search recurse(d) { depth => "$(d)"; xdev => "true"; } ## body depth_search recurse_ignore(d,list) { depth => "$(d)"; exclude_dirs => { @(list) }; } ## body depth_search include_base { include_basedir => "true"; } ## ## delete ## body delete tidy { dirlinks => "delete"; rmdirs => "true"; } ## ## rename ## body rename disable { disable => "true"; } ## body rename rotate(level) { rotate => "$(level)"; } ## body rename to(file) { newname => "$(file)"; } ## ## file_select ## 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"; } ## body file_select days_old(days) { mtime => irange(0,ago(0,0,"$(days)",0,0,0)); file_result => "mtime"; } ## body file_select size_range(from,to) { search_size => irange("$(from)","$(to)"); file_result => "size"; } ## body file_select exclude(name) { leaf_name => { "$(name)"}; file_result => "!leaf_name"; } ## body file_select plain { file_types => { "plain" }; file_result => "file_types"; } body file_select dirs { file_types => { "dir" }; file_result => "file_types"; } ## body file_select by_name(names) { leaf_name => { @(names)}; file_result => "leaf_name"; } ## body file_select ex_list(names) { leaf_name => { @(names)}; file_result => "!leaf_name"; } ## ## changes ## body changes detect_all_change # This is fierce, and will cost disk cycles { hash => "best"; report_changes => "all"; update_hashes => "yes"; } ## body changes detect_content # This is a cheaper alternative { hash => "md5"; report_changes => "content"; update_hashes => "yes"; } ## body changes noupdate # Use on (small) files that should never change { hash => "sha256"; report_changes => "content"; update_hashes => "no"; } ## body changes diff # Generates diff report (Nova and above) { hash => "sha256"; report_changes => "content"; report_diffs => "true"; update_hashes => "yes"; } ## body changes diff_noupdate { hash => "sha256"; report_changes => "content"; report_diffs => "true"; update_hashes => "no"; } ##-------------------------------------------------------------- ## Packages promises ##-------------------------------------------------------------- body package_method zypper { package_changes => "bulk"; package_list_command => "/bin/rpm -qa --queryformat \"i | repos | %{name} | %{version}-%{release} | %{arch}\n\""; # set it to "0" to avoid caching of list during upgrade package_list_update_ifelapsed => "240"; package_patch_list_command => "/usr/bin/zypper patches"; package_installed_regex => "i.*"; package_list_name_regex => "[^|]+\|[^|]+\|\s+([^\s]+).*"; package_list_version_regex => "[^|]+\|[^|]+\|[^|]+\|\s+([^\s]+).*"; package_list_arch_regex => "[^|]+\|[^|]+\|[^|]+\|[^|]+\|\s+([^\s]+).*"; package_patch_installed_regex => ".*Installed.*|.*Not Applicable.*"; package_patch_name_regex => "[^|]+\|\s+([^\s]+).*"; package_patch_version_regex => "[^|]+\|[^|]+\|\s+([^\s]+).*"; package_name_convention => "$(name)"; package_add_command => "/usr/bin/zypper --non-interactive install"; package_delete_command => "/usr/bin/zypper --non-interactive remove --force-resolution"; package_update_command => "/usr/bin/zypper --non-interactive update"; package_patch_command => "/usr/bin/zypper --non-interactive patch$"; # $ means no args package_verify_command => "/usr/bin/zypper --non-interactive verify$"; } ## body package_method apt { package_changes => "bulk"; package_list_command => "/usr/bin/dpkg -l"; package_list_name_regex => "ii\s+([^\s]+).*"; package_list_version_regex => "ii\s+[^\s]+\s+([^\s]+).*"; package_installed_regex => ".*"; # all reported are installed package_name_convention => "$(name)"; # set it to "0" to avoid caching of list during upgrade package_list_update_ifelapsed => "240"; have_aptitude:: package_add_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/aptitude -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --assume-yes install"; package_list_update_command => "/usr/bin/aptitude update"; package_delete_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/aptitude -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --assume-yes -q remove"; package_update_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/aptitude -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --assume-yes install"; package_verify_command => "/usr/bin/aptitude show"; package_noverify_regex => "(State: not installed|E: Unable to locate package .*)"; !have_aptitude:: package_add_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/apt-get -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --yes install"; package_list_update_command => "/usr/bin/apt-get update"; package_delete_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/apt-get -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --yes -q remove"; package_update_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/apt-get -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --yes install"; package_verify_command => "/usr/bin/dpkg -s"; package_noverify_returncode => "1"; } ## body package_method dpkg_version(repo) { package_changes => "individual"; package_list_command => "/usr/bin/dpkg -l"; # set it to "0" to avoid caching of list during upgrade package_list_update_ifelapsed => "240"; package_list_name_regex => "ii\s+([^\s]+).*"; package_list_version_regex => "ii\s+[^\s]+\s+([^\s]+).*"; package_installed_regex => ".*"; # all reported are installed package_file_repositories => { "$(repo)" }; debian.x86_64:: package_name_convention => "$(name)_$(version)_amd64.deb"; debian.i686:: package_name_convention => "$(name)_$(version)_i386.deb"; debian:: package_add_command => "/usr/bin/dpkg --install"; package_delete_command => "/usr/bin/dpkg --purge"; package_update_command => "/usr/bin/dpkg --install"; } ## body package_method rpm_version(repo) { package_changes => "individual"; package_list_command => "/bin/rpm -qa --queryformat \"i | repos | %{name} | %{version}-%{release} | %{arch}\n\""; # set it to "0" to avoid caching of list during upgrade package_list_update_ifelapsed => "240"; package_list_name_regex => "[^|]+\|[^|]+\|\s+([^\s|]+).*"; package_list_version_regex => "[^|]+\|[^|]+\|[^|]+\|\s+([^\s|]+).*"; package_list_arch_regex => "[^|]+\|[^|]+\|[^|]+\|[^|]+\|\s+([^\s]+).*"; package_installed_regex => "i.*"; package_file_repositories => { "$(repo)" }; package_name_convention => "$(name)-$(version).$(arch).rpm"; package_add_command => "/bin/rpm -ivh "; package_update_command => "/bin/rpm -Uvh "; package_delete_command => "/bin/rpm -e --nodeps"; package_noverify_regex => ".*[^\s].*"; } ## body package_method msi_implicit(repo) # Use whole file name as promiser, e.g. "7-Zip-4.50-x86_64.msi", # the name, version and arch is then deduced from the promiser { package_changes => "individual"; package_file_repositories => { "$(repo)" }; package_installed_regex => ".*"; package_name_convention => "$(name)-$(version)-$(arch).msi"; package_delete_convention => "$(firstrepo)$(name)-$(version)-$(arch).msi"; package_name_regex => "^(\S+)-(\d+\.?)+"; package_version_regex => "^\S+-((\d+\.?)+)"; package_arch_regex => "^\S+-[\d\.]+-(.*).msi"; package_add_command => "\"$(sys.winsysdir)\msiexec.exe\" /qn /i"; package_update_command => "\"$(sys.winsysdir)\msiexec.exe\" /qn /i"; package_delete_command => "\"$(sys.winsysdir)\msiexec.exe\" /qn /x"; } ## body package_method msi_explicit(repo) # use software name as promiser, e.g. "7-Zip", and explicitly # specify any package_version and package_arch { package_changes => "individual"; package_file_repositories => { "$(repo)" }; package_installed_regex => ".*"; package_name_convention => "$(name)-$(version)-$(arch).msi"; package_delete_convention => "$(firstrepo)$(name)-$(version)-$(arch).msi"; package_add_command => "\"$(sys.winsysdir)\msiexec.exe\" /qn /i"; package_update_command => "\"$(sys.winsysdir)\msiexec.exe\" /qn /i"; package_delete_command => "\"$(sys.winsysdir)\msiexec.exe\" /qn /x"; } ## body package_method yum { package_changes => "bulk"; package_list_command => "/usr/bin/yum list installed"; package_patch_list_command => "/usr/bin/yum check-update"; # Remember to escape special characters like | package_list_name_regex => "([^.]+).*"; package_list_version_regex => "[^\s]\s+([^\s]+).*"; package_list_arch_regex => "[^.]+\.([^\s]+).*"; package_installed_regex => ".*(installed|\s+@).*"; package_name_convention => "$(name).$(arch)"; # set it to "0" to avoid caching of list during upgrade package_list_update_ifelapsed => "240"; package_patch_installed_regex => "^\s.*"; package_patch_name_regex => "([^.]+).*"; package_patch_version_regex => "[^\s]\s+([^\s]+).*"; package_patch_arch_regex => "[^.]+\.([^\s]+).*"; package_add_command => "/usr/bin/yum -y install"; package_update_command => "/usr/bin/yum -y update"; package_delete_command => "/bin/rpm -e --nodeps"; package_verify_command => "/bin/rpm -V"; } ## body package_method yum_rpm # Contributed by Trond Hasle Amundsen # More efficient package method for RedHat - uses rpm to list instead of yum # Notes: # - using $(name).$(arch) instead of $(name) for package_name_convention # causes uninstallation to fail. # - using allmatches to remove for all architectures # { package_changes => "bulk"; package_list_command => "/bin/rpm -qa --qf '%{name} %{version}-%{release} %{arch}\n'"; package_patch_list_command => "/usr/bin/yum check-update"; package_list_name_regex => "^(\S+?)\s\S+?\s\S+$"; package_list_version_regex => "^\S+?\s(\S+?)\s\S+$"; package_list_arch_regex => "^\S+?\s\S+?\s(\S+)$"; package_installed_regex => ".*"; package_name_convention => "$(name)"; package_patch_installed_regex => "^\s.*"; package_patch_name_regex => "([^.]+).*"; package_patch_version_regex => "[^\s]\s+([^\s]+).*"; package_patch_arch_regex => "[^.]+\.([^\s]+).*"; package_add_command => "/usr/bin/yum -y install"; package_update_command => "/usr/bin/yum -y update"; package_delete_command => "/bin/rpm -e --nodeps --allmatches"; package_verify_command => "/bin/rpm -V"; } ## # The solaris package system is poorly designed, with too many different # names to track. See the example in tests/units/unit_package_solaris.cf # to see how to use this body package_method solaris (pkgname, spoolfile, adminfile) { package_changes => "individual"; package_list_command => "/usr/bin/pkginfo -l"; package_multiline_start => "\s*PKGINST:\s+[^\s]+.*"; package_list_name_regex => "\s*PKGINST:\s+([^\s]+).*"; package_list_version_regex => "\s*VERSION:\s+([^\s]+).*"; package_list_arch_regex => "\s*ARCH:\s+([^\s]+)"; package_installed_regex => "\s*STATUS:\s*(completely|partially)\s+installed.*"; package_name_convention => "$(name)"; package_add_command => "/usr/sbin/pkgadd -n -a /tmp/$(adminfile) -d /tmp/$(spoolfile)"; package_delete_command => "/usr/sbin/pkgrm -n -a /tmp/$(adminfile)"; } ## # # The following bundle is part of a package setup for solaris, see unit examples # bundle edit_line create_solaris_admin_file { insert_lines: "mail= instance=unique partial=nocheck runlevel=nocheck idepend=nocheck rdepend=nocheck space=nocheck setuid=nocheck conflict=nocheck action=nocheck networktimeout=60 networkretries=3 authentication=quit keystore=/var/sadm/security proxy= basedir=default"; } ## body package_method freebsd { package_changes => "individual"; # Could use rpm for this package_list_command => "/usr/sbin/pkg_info"; # Remember to escape special characters like | package_list_name_regex => "([^\s]+)-.*"; package_list_version_regex => "[^\s]+-([^\s]+).*"; package_name_regex => "([^\s]+)-.*"; package_version_regex => "[^\s]+-([^\s]+).*"; package_installed_regex => ".*"; package_name_convention => "$(name)-$(version)"; package_add_command => "/usr/sbin/pkg_add -r"; package_delete_command => "/usr/sbin/pkg_delete"; } ## # Single bundle for all the similar managers simplifies promises body package_method generic { SuSE:: package_changes => "bulk"; package_list_command => "/usr/bin/zypper packages"; package_patch_list_command => "/usr/bin/zypper patches"; package_installed_regex => "i.*"; package_list_name_regex => "[^|]+\|[^|]+\|\s+([^\s]+).*"; package_list_version_regex => "[^|]+\|[^|]+\|[^|]+\|\s+([^\s]+).*"; package_list_arch_regex => "[^|]+\|[^|]+\|[^|]+\|[^|]+\|\s+([^\s]+).*"; package_patch_installed_regex => ".*Installed.*|.*Not Applicable.*"; package_patch_name_regex => "[^|]+\|\s+([^\s]+).*"; package_patch_version_regex => "[^|]+\|[^|]+\|\s+([^\s]+).*"; package_name_convention => "$(name)"; package_add_command => "/usr/bin/zypper --non-interactive install"; package_delete_command => "/usr/bin/zypper --non-interactive remove --force-resolution"; package_update_command => "/usr/bin/zypper --non-interactive update"; package_patch_command => "/usr/bin/zypper --non-interactive patch$"; # $ means no args package_verify_command => "/usr/bin/zypper --non-interactive verify$"; redhat:: package_changes => "bulk"; package_list_command => "/bin/rpm -qa --qf '%{name} %{version}-%{release} %{arch}\n'"; package_patch_list_command => "/usr/bin/yum check-update"; package_list_name_regex => "^(\S+?)\s\S+?\s\S+$"; package_list_version_regex => "^\S+?\s(\S+?)\s\S+$"; package_list_arch_regex => "^\S+?\s\S+?\s(\S+)$"; package_installed_regex => ".*"; package_name_convention => "$(name)"; package_list_update_ifelapsed => "0"; # sometimes, caching is pretty disturbing package_patch_installed_regex => "^\s.*"; package_patch_name_regex => "([^.]+).*"; package_patch_version_regex => "[^\s]\s+([^\s]+).*"; package_patch_arch_regex => "[^.]+\.([^\s]+).*"; package_add_command => "/usr/bin/yum -y install"; package_update_command => "/usr/bin/yum -y update"; package_delete_command => "/bin/rpm -e --nodeps --allmatches"; package_verify_command => "/bin/rpm -V"; # package_changes => "bulk"; # package_list_command => "/usr/bin/yum list installed"; # package_patch_list_command => "/usr/bin/yum check-update"; # package_list_name_regex => "([^.]+).*"; # package_list_version_regex => "[^\s]\s+([^\s]+).*"; # package_list_arch_regex => "[^.]+\.([^\s]+).*"; # package_installed_regex => ".*(installed|\s+@).*"; # package_name_convention => "$(name).$(arch)"; # package_list_update_ifelapsed => "240"; # package_patch_installed_regex => "^\s.*"; # package_patch_name_regex => "([^.]+).*"; # package_patch_version_regex => "[^\s]\s+([^\s]+).*"; # package_patch_arch_regex => "[^.]+\.([^\s]+).*"; # package_add_command => "/usr/bin/yum -y install"; # package_delete_command => "/bin/rpm -e --nodeps"; # package_verify_command => "/bin/rpm -V"; debian:: package_changes => "bulk"; package_list_command => "/usr/bin/dpkg -l"; package_list_name_regex => "ii\s+([^\s]+).*"; package_list_version_regex => "ii\s+[^\s]+\s+([^\s]+).*"; package_installed_regex => ".*"; # all reported are installed package_name_convention => "$(name)"; package_list_update_ifelapsed => "240"; # 4 hours debian.have_aptitude:: package_add_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/aptitude -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --assume-yes install"; package_list_update_command => "/usr/bin/aptitude update"; package_delete_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/aptitude -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --assume-yes remove"; package_update_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/aptitude -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --assume-yes install"; package_verify_command => "/usr/bin/aptitude show"; package_noverify_regex => "(State: not installed|E: Unable to locate package .*)"; debian.!have_aptitude:: package_add_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/apt-get -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --yes install"; package_list_update_command => "/usr/bin/apt-get update"; package_delete_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/apt-get -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --yes remove"; package_update_command => "/usr/bin/env DEBIAN_FRONTEND=noninteractive LC_ALL=C /usr/bin/apt-get -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --yes install"; package_verify_command => "/usr/bin/dpkg -s"; package_noverify_returncode => "1"; freebsd:: package_changes => "individual"; package_list_command => "/usr/sbin/pkg_info"; package_list_name_regex => "([^\s]+)-.*"; package_list_version_regex => "[^\s]+-([^\s]+).*"; package_name_regex => "([^\s]+)-.*"; package_version_regex => "[^\s]+-([^\s]+).*"; package_installed_regex => ".*"; package_name_convention => "$(name)-$(version)"; package_add_command => "/usr/sbin/pkg_add -r"; package_delete_command => "/usr/sbin/pkg_delete"; } ## ##------------------------------------------------------- ## storage promises ##------------------------------------------------------- body volume min_free_space(free) { check_foreign => "false"; freespace => "$(free)"; sensible_size => "10000"; sensible_count => "2"; } ## body mount nfs(server,source) { mount_type => "nfs"; mount_source => "$(source)"; mount_server => "$(server)"; edit_fstab => "true"; } ## body mount nfs_p(server,source,perm) { mount_type => "nfs"; mount_source => "$(source)"; mount_server => "$(server)"; mount_options => {"$(perm)"}; edit_fstab => "true"; } ## body mount unmount { mount_type => "nfs"; edit_fstab => "true"; unmount => "true"; } ##------------------------------------------------------- ## process promises ##------------------------------------------------------- body process_select exclude_procs(x) { command => "$(x)"; process_result => "!command"; } ## body process_select days_older_than(d) { stime_range => irange(ago(0,0,"$(d)",0,0,0),now); process_result => "stime"; } ## body process_count any_count(cl) { match_range => "0,0"; out_of_range_define => { "$(cl)" }; } ## body process_count check_range(name,lower,upper) { match_range => irange("$(lower)","$(upper)"); out_of_range_define => { "$(name)_out_of_range" }; } ## ## service promises ## body service_method bootstart { service_autostart_policy => "boot_time"; service_dependence_chain => "start_parent_services"; windows:: service_type => "windows"; } ## body service_method force_deps { service_dependence_chain => "all_related"; windows:: service_type => "windows"; } #################################################### ## monitor bodyparts #################################################### body match_value scan_log(line) { select_line_matching => "$(line)"; track_growing_file => "true"; } ## body match_value scan_changing_file(line) { select_line_matching => "$(line)"; track_growing_file => "false"; } ## body action sample_rate(x) { ifelapsed => "$(x)"; expireafter => "10"; }