Skip to content

Instantly share code, notes, and snippets.

@peckpeck
Created January 14, 2015 16:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peckpeck/b39e85efa5a237f1758f to your computer and use it in GitHub Desktop.
Save peckpeck/b39e85efa5a237f1758f to your computer and use it in GitHub Desktop.
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#
# Configure the reverse proxy entries used by Apache.
#
bundle edit_line insert_proxy_entries(entries)
{
insert_lines:
"<IfModule mod_proxy.c>
${entries}</IfModule>";
}
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent rudder_reverse_proxy_apache_installation(service_name, internal_name, params) {
vars:
redhat::
"apache_package_name" string => "httpd";
!redhat::
"apache_package_name" string => "apache2";
classes:
"rudder_reverse_proxy_apache_install_package" expression => strcmp("${${params}[package_install]}", "true");
packages:
# Too bad SuSE 10 uses a different bundle, things would be so simple if it was not the case...
SuSE_10.rudder_reverse_proxy_apache_install_package::
"${apache_package_name}"
package_policy => "add",
package_method => rudder_rug,
classes => rudder_common_classes("rudder_reverse_proxy_apache_package"),
comment => "Installing apache using the rug interface";
!SuSE_10.rudder_reverse_proxy_apache_install_package::
"${apache_package_name}"
package_policy => "add",
package_method => generic,
classes => rudder_common_classes("rudder_reverse_proxy_apache_package"),
comment => "Installing apache using generic interface";
}
# The reporting is made on separate bundles to abstract the complexity
# inherent to the normal ordering.
bundle agent rudder_reverse_proxy_apache_installation_reporting(service_name, internal_name, params) {
classes:
"rudder_reverse_proxy_apache_install_package" expression => strcmp("${${params}[package_install]}", "true");
methods:
"any" usebundle => rudder_common_reports_generic("${internal_name}", "rudder_reverse_proxy_apache_package", "${${params}[tracking_key]}", "Installation parameters", "None", "The ${service_name} package installation");
# Special case if no installation is needed
"any"
usebundle => rudder_common_report("${internal_name}", "result_success", "${${params}[tracking_key]}", "Installation parameters", "None", "${service_name} installation is not required. Skipping..."),
ifvarclass => "!rudder_reverse_proxy_apache_install_package";
}
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#####################################################################################
# This Technique installs and configures Apache HTTPd to act as a reverse proxy
# server.. See metadata.xml for more details.
#####################################################################################
bundle agent rudder_reverse_proxy_apache
{
vars:
# Common declarations
"rudder_reverse_proxy_apache_service_name"
string => "Apache (as a reverse proxy)";
"rudder_reverse_proxy_apache_internal_name"
string => "apacheReverseProxy";
# Parameters
"rudder_reverse_proxy_params[package_install]"
string => "&APACHE_REVERSE_PROXY_INSTALL&";
"rudder_reverse_proxy_params[proxies]"
string => "&APACHE_REVERSE_PROXY_URL_SRC,APACHE_REVERSE_PROXY_URL_DST,APACHE_REVERSE_PROXY_TIMEOUT:{src, dst, timeout|ProxyPass &src& &dst& connectiontimeout=5 timeout=&timeout&${const.n}ProxyPassReverse &src& &dst&
}&";
"rudder_reverse_proxy_params[selinux]"
string => "&APACHE_REVERSE_PROXY_ADJUST_SELINUX&";
"rudder_reverse_proxy_params[tracking_key]"
string => "&TRACKINGKEY&";
methods:
# Note:
# The reporting is made on separate bundles to abstract the complexity
# inherent to the normal ordering.
"any" usebundle => rudder_reverse_proxy_apache_installation("${rudder_reverse_proxy_apache_service_name}", "${rudder_reverse_proxy_apache_internal_name}", "rudder_reverse_proxy_apache.rudder_reverse_proxy_params");
"any" usebundle => rudder_reverse_proxy_apache_installation_reporting("${rudder_reverse_proxy_apache_service_name}", "${rudder_reverse_proxy_apache_internal_name}", "rudder_reverse_proxy_apache.rudder_reverse_proxy_params");
"any" usebundle => rudder_reverse_proxy_apache_configuration("${rudder_reverse_proxy_apache_service_name}", "${rudder_reverse_proxy_apache_internal_name}", "rudder_reverse_proxy_apache.rudder_reverse_proxy_params");
"any" usebundle => rudder_reverse_proxy_apache_configuration_reporting("${rudder_reverse_proxy_apache_service_name}", "${rudder_reverse_proxy_apache_internal_name}", "rudder_reverse_proxy_apache.rudder_reverse_proxy_params");
}
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent rudder_reverse_proxy_apache_configuration(service_name, internal_name, params) {
vars:
"rudder_reverse_proxy_apache_proxies" string => "${${params}[proxies]}";
debian::
"rudder_reverse_proxy_apache_debian_modules" slist => { "proxy", "proxy_http" };
SuSE::
"rudder_reverse_proxy_apache_binary_name" string => "/usr/sbin/httpd2-(prefork|worker)";
redhat::
"reverse_proxy_configuration_file" string => "/etc/httpd/conf.d/rudder-reverse-proxy.conf";
"rudder_reverse_proxy_apache_binary_name" string => "/usr/sbin/httpd";
"rudder_reverse_proxy_apache_restart_command" string => "/etc/init.d/httpd";
!redhat::
"reverse_proxy_configuration_file" string => "/etc/apache2/conf.d/rudder-reverse-proxy.conf";
"rudder_reverse_proxy_apache_restart_command" string => "/etc/init.d/apache2";
!SuSE.!redhat::
"rudder_reverse_proxy_apache_binary_name" string => "/usr/sbin/apache2";
classes:
# Adjust SELinux ?
"rudder_reverse_proxy_apache_selinux_adjust" expression => strcmp("${${params}[selinux]}","true");
# What is the current SELinux http proxying policy ?
"rudder_reverse_proxy_apache_selinux_proxy_policy" expression => returnszero("/usr/sbin/getsebool httpd_can_network_relay | grep -q on", "useshell");
"rudder_reverse_proxy_apache_mod_${rudder_reverse_proxy_apache_debian_modules}_loaded" expression => fileexists("/etc/apache2/mods-enabled/${rudder_reverse_proxy_apache_debian_modules}.load");
files:
"${reverse_proxy_configuration_file}"
create => "true",
edit_defaults => empty_backup,
edit_line => insert_proxy_entries("${rudder_reverse_proxy_apache_proxies}"),
classes => rudder_common_classes("rudder_reverse_proxy_apache_configuration"),
comment => "Edit the Apache reverse proxy file";
# Class visibility forces us to use these bundles here.
methods:
# Modules edition
"any"
usebundle => rudder_common_report("${internal_name}", "result_success", "${${params}[tracking_key]}", "Module parameters", "None", "No ${service_name} modules edition needed"),
ifvarclass => "!debian|(rudder_reverse_proxy_apache_mod_proxy_loaded.rudder_reverse_proxy_apache_mod_proxy_http_loaded)";
# SELinux edition
"any"
usebundle => rudder_common_report("${internal_name}", "result_success", "${${params}[tracking_key]}", "SELinux parameters", "None", "No ${service_name} SELinux modification needed"),
ifvarclass => "!rudder_reverse_proxy_apache_selinux_adjust|rudder_reverse_proxy_apache_selinux_proxy_policy";
# Apache restart/reload
"any"
usebundle => rudder_common_report("${internal_name}", "log_info", "${${params}[tracking_key]}", "Daemon status", "None", "${service_name} has been restarted or reloaded"),
ifvarclass => "rudder_reverse_proxy_apache_restart_repaired|rudder_reverse_proxy_apache_reload_repaired";
"any"
usebundle => rudder_common_report("${internal_name}", "result_error", "${${params}[tracking_key]}", "Daemon status", "None", "Unable to restart or reload ${service_name}"),
ifvarclass => "rudder_reverse_proxy_apache_restart_error|rudder_reverse_proxy_apache_reload_error";
processes:
"${rudder_reverse_proxy_apache_binary_name}"
restart_class => "rudder_reverse_proxy_apache_process_down",
comment => "Ensuring apache is up";
commands:
debian::
"/usr/sbin/a2enmod ${rudder_reverse_proxy_apache_debian_modules}"
classes => rudder_common_classes("rudder_reverse_proxy_apache_modules"),
ifvarclass => "!rudder_reverse_proxy_apache_mod_${rudder_reverse_proxy_apache_debian_modules}_loaded",
comment => "Enable Apache modules on Debian";
rudder_reverse_proxy_apache_selinux_adjust.!rudder_reverse_proxy_apache_selinux_proxy_policy::
"/usr/sbin/setsebool httpd_can_network_relay on"
classes => rudder_common_classes("rudder_reverse_proxy_apache_selinux"),
comment => "Enable SELinux Apache entry to let Apache proxy entries";
rudder_reverse_proxy_apache_configuration_repaired::
"${rudder_reverse_proxy_apache_restart_command} reload"
classes => rudder_common_classes("rudder_reverse_proxy_apache_reload"),
comment => "reloading apache";
(rudder_reverse_proxy_apache_process_down|rudder_reverse_proxy_apache_modules_repaired)::
"${rudder_reverse_proxy_apache_restart_command} restart"
classes => rudder_common_classes("rudder_reverse_proxy_apache_restart"),
comment => "restarting apache";
}
# The reporting is made on separate bundles to abstract the complexity
# inherent to the normal ordering.
bundle agent rudder_reverse_proxy_apache_configuration_reporting(service_name, internal_name, params)
{
methods:
# Modules edition
"any" usebundle => rudder_common_reports_generic("${internal_name}", "rudder_reverse_proxy_apache_modules", "${${params}[tracking_key]}", "Module parameters", "None", "The ${service_name} modules");
# SELinux edition
"any" usebundle => rudder_common_reports_generic("${internal_name}", "rudder_reverse_proxy_apache_selinux", "${${params}[tracking_key]}", "SELinux parameters", "None", "The ${service_name} SELinux configuration");
# Apache configuration
"any" usebundle => rudder_common_reports_generic("${internal_name}", "rudder_reverse_proxy_apache_configuration", "${${params}[tracking_key]}", "Reverse proxy parameters", "None", "The ${service_name} reverse proxy configuration");
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
####################
# Installs Apache #
####################
bundle agent check_apache_installation
{
packages:
linux.!SuSE_10.!redhat::
"apache2"
package_policy => "add",
package_method => generic,
classes => kept_if_else("apache_here", "apache_installed", "cant_install_apache"),
comment => "Installing apache using generic interface";
SuSE_10::
"apache2"
package_policy => "add",
package_method => rudder_rug,
classes => kept_if_else("apache_here", "apache_installed", "cant_install_apache"),
comment => "Installing apache using the rug interface";
redhat::
"httpd"
package_policy => "add",
package_method => generic,
classes => kept_if_else("apache_here", "apache_installed", "cant_install_apache"),
comment => "Installing apache using generic interface";
reports:
apache_here.!apache_installed.!cant_install_apache::
"@@apacheServerConfiguration@@result_success@@&TRACKINGKEY&@@Apache2 installation@@None@@${g.execRun}##${g.uuid}@#Apache already installed";
apache_installed.!cant_install_apache::
"@@apacheServerConfiguration@@result_repaired@@&TRACKINGKEY&@@Apache2 installation@@None@@${g.execRun}##${g.uuid}@#Apache installed";
cant_install_apache::
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@Apache2 installation@@None@@${g.execRun}##${g.uuid}@#Can't install Apache";
!linux::
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@Apache2 installation@@None@@${g.execRun}##${g.uuid}@#Support to check if Apache is installed not available on this platform";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent check_apache_configuration
{
vars:
# Ports
"apache_ports" slist => {&APACHE_PORTS: { "&it&" };separator=", "&};
# List of all the files to permit on the vhost directory
"vhosts_files" slist => { "ports.conf", "security.conf", &APACHE_VHOST_FQDN: { "vhost-&it&.conf" };separator=", "&};
# Security config
"apache_security[ServerTokens]" string => "&APACHE_SERVERTOKENS&";
"apache_security[ServerSignature]" string => "&APACHE_SERVERSIGNATURE&";
"apache_security[TraceEnable]" string => "&APACHE_TRACEENABLE&";
# Virtual Hosts
&APACHE_VHOST_FQDN:{fqdn |"apache_vhost_fqdn[&i&]" string => "&fqdn&";
}&
&APACHE_VHOST_PORT:{port |"apache_vhost_port[&i&]" string => "&port&";
}&
&APACHE_VHOST_ROOT:{root |"apache_vhost_root[&i&]" string => "&root&";
}&
&APACHE_VHOST_EXPIRES:{expires |"apache_vhost_expires[&i&]" string => "&expires&";
}&
&APACHE_VHOST_EXPIRES_TTL:{expires_ttl |"apache_vhost_expires_ttl[&i&]" string => "&expires_ttl&";
}&
&APACHE_VHOST_ALIAS_ONE_SRC:{alias_one_src |"apache_vhost_alias_one_src[&i&]" string => "&alias_one_src&";
}&
&APACHE_VHOST_ALIAS_ONE_DST:{alias_one_dst |"apache_vhost_alias_one_dst[&i&]" string => "&alias_one_dst&";
}&
&APACHE_VHOST_ALIAS_TWO_SRC:{alias_two_src |"apache_vhost_alias_two_src[&i&]" string => "&alias_two_src&";
}&
&APACHE_VHOST_ALIAS_TWO_DST:{alias_two_dst |"apache_vhost_alias_two_dst[&i&]" string => "&alias_two_dst&";
}&
&APACHE_VHOST_ALIAS_THREE_SRC:{alias_three_src |"apache_vhost_alias_three_src[&i&]" string => "&alias_three_src&";
}&
&APACHE_VHOST_ALIAS_THREE_DST:{alias_three_dst |"apache_vhost_alias_three_dst[&i&]" string => "&alias_three_dst&";
}&
"apache_vhost_index" slist => getindices("apache_vhost_fqdn");
# For reporting reason, we need to have the exact list of specified modules to check
"apache_modules_defined" slist => { &APACHE_MODULES: { "&it&" };separator=", "& };
# Modules that are installed by default
"apache_modules" slist => { "expires", "alias", @{apache_modules_defined} },
policy => "ifdefined";
classes:
!redhat.!SuSE::
# Security : if not there, Apache too, so don't bother anymore
"apache_bin_present" expression => fileexists("/usr/sbin/apache2");
redhat::
"apache_bin_present" expression => fileexists("/usr/sbin/httpd");
SuSE::
"apache_bin_worker" expression => fileexists("/usr/sbin/httpd2-worker");
"apache_bin_prefork" expression => fileexists("/usr/sbin/httpd2-prefork");
"apache_bin_present" expression => "apache_bin_prefork|apache_bin_worker";
any::
# Autostart ?
"apache_autostart" expression => strcmp("&APACHE_AUTOSTART&","true");
# Adjust SELinux ?
"apache_selinux_adjust" expression => strcmp("&APACHE_SELINUX&","true");
# Is the SELinux binary "chcon" present ?
"selinux_bin_present" expression => fileexists("/usr/bin/chcon");
# Define if the list of module to verify has been specified by the user
"apache_modules_nok" expression => strcmp("&APACHE_MODULES&","none");
"apache_modules_ok" not => strcmp("&APACHE_MODULES&","none");
# Check if the variable apache_modules is defined so that they can be managed
"apache_module_list_defined" expression => isvariable("apache_modules");
files:
debian::
"/etc/rc2.d/S.*apache2.*"
create => "true",
#depth_search => recurse("0"),
#file_select => apache_startlink,
action => WarnOnly,
classes => if_else("apache_bootstarted", "apache_unbootstarted");
"/etc/apache2/ports.conf"
create => "true",
perms => m("644"),
edit_defaults => noempty_backup,
edit_line => set_apache_config_ports("@{check_apache_configuration.apache_ports}"),
classes => kept_if_else_hook("apache_ports_kept", "apache_ports_repaired", "apache_ports_failed", "apache_change");
"/etc/apache2/conf.d/security"
create => "true",
perms => m("644"),
edit_defaults => empty_backup,
edit_line => set_apache_config_security("check_apache_configuration.apache_security"),
classes => kept_if_else_hook("apache_security_kept", "apache_security_repaired", "apache_security_failed", "apache_change");
"/etc/httpd/sites-enabled"
delete => tidy,
classes => if_repaired("apache_change"),
file_select => ex_list("@{vhosts_files}"),
depth_search => recurse("inf");
"/etc/apache2/sites-enabled/vhost-${apache_vhost_fqdn[${apache_vhost_index}]}.conf"
create => "true",
perms => m("644"),
edit_defaults => empty_backup,
edit_line => set_apache_config_vhost("${apache_vhost_fqdn[${apache_vhost_index}]}", "${apache_vhost_port[${apache_vhost_index}]}", "${apache_vhost_root[${apache_vhost_index}]}", "${apache_vhost_expires[${apache_vhost_index}]}", "${apache_vhost_expires_ttl[${apache_vhost_index}]}", "${apache_vhost_alias_one_src[${apache_vhost_index}]}", "${apache_vhost_alias_one_dst[${apache_vhost_index}]}", "${apache_vhost_alias_two_src[${apache_vhost_index}]}", "${apache_vhost_alias_two_dst[${apache_vhost_index}]}", "${apache_vhost_alias_three_src[${apache_vhost_index}]}", "${apache_vhost_alias_three_dst[${apache_vhost_index}]}", "${g.rudder_tools}/apache-vhost.tpl"),
classes => kept_if_else_hook("apache_vhost_${apache_vhost_index}_kept", "apache_vhost_${apache_vhost_index}_repaired", "apache_vhost_${apache_vhost_index}_failed", "apache_change");
redhat::
"/etc/rc2.d/S.*httpd.*"
create => "true",
#depth_search => recurse("0"),
#file_select => apache_startlink,
action => WarnOnly,
classes => if_else("apache_bootstarted", "apache_unbootstarted");
"/etc/httpd/rudder.conf.d"
delete => tidy,
classes => if_repaired("apache_change"),
file_select => ex_list("@{vhosts_files}"),
depth_search => recurse("inf");
"/etc/httpd/conf.d/welcome.conf"
rename => disable,
comment => "Disable an annoying file";
"/etc/httpd/conf/httpd.conf"
create => "true",
perms => m("644"),
edit_defaults => noempty_backup,
edit_line => cleanup_redhat_apache("check_apache_configuration.apache_security"),
classes => kept_if_else_hook("apache_ports_kept", "apache_ports_repaired", "apache_ports_failed", "apache_change");
"/etc/httpd/rudder.conf.d/."
perms => mog("755", "root", "root"),
create => "true",
comment => "Make sure the rudder configuration directory exists";
"/etc/httpd/rudder.conf.d/ports.conf"
create => "true",
perms => m("644"),
edit_defaults => noempty_backup,
edit_line => set_apache_config_ports("@{check_apache_configuration.apache_ports}"),
classes => kept_if_else_hook("apache_ports_kept", "apache_ports_repaired", "apache_ports_failed", "apache_change");
"/etc/httpd/rudder.conf.d/security.conf"
create => "true",
perms => m("644"),
edit_defaults => noempty_backup,
edit_line => set_apache_config_security("check_apache_configuration.apache_security"),
classes => kept_if_else_hook("apache_security_kept", "apache_security_repaired", "apache_security_failed", "apache_change");
"/etc/httpd/rudder.conf.d/vhost-${apache_vhost_fqdn[${apache_vhost_index}]}.conf"
create => "true",
perms => m("644"),
edit_defaults => empty_backup,
edit_line => set_apache_config_vhost("${apache_vhost_fqdn[${apache_vhost_index}]}", "${apache_vhost_port[${apache_vhost_index}]}", "${apache_vhost_root[${apache_vhost_index}]}", "${apache_vhost_expires[${apache_vhost_index}]}", "${apache_vhost_expires_ttl[${apache_vhost_index}]}", "${apache_vhost_alias_one_src[${apache_vhost_index}]}", "${apache_vhost_alias_one_dst[${apache_vhost_index}]}", "${apache_vhost_alias_two_src[${apache_vhost_index}]}", "${apache_vhost_alias_two_dst[${apache_vhost_index}]}", "${apache_vhost_alias_three_src[${apache_vhost_index}]}", "${apache_vhost_alias_three_dst[${apache_vhost_index}]}", "${g.rudder_tools}/apache-vhost.tpl"),
classes => kept_if_else_hook("apache_vhost_${apache_vhost_index}_kept", "apache_vhost_${apache_vhost_index}_repaired", "apache_vhost_${apache_vhost_index}_failed", "apache_change");
SuSE::
"/etc/rc.d/rc3.d/S.*apache2.*"
create => "true",
#depth_search => recurse("0"),
#file_select => apache_startlink,
action => WarnOnly,
classes => if_else("apache_bootstarted", "apache_unbootstarted");
"/etc/apache2/rudder.conf.d"
delete => tidy,
classes => if_repaired("apache_change"),
file_select => ex_list("@{vhosts_files}"),
depth_search => recurse("inf");
"/etc/apache2/httpd.conf"
create => "true",
perms => m("644"),
edit_defaults => noempty_backup,
edit_line => cleanup_redhat_apache("check_apache_configuration.apache_security"),
classes => kept_if_else_hook("apache_ports_kept", "apache_ports_repaired", "apache_ports_failed", "apache_change");
"/etc/apache2/rudder.conf.d/."
perms => mog("755", "root", "root"),
create => "true",
comment => "Make sure the rudder configuration directory exists";
"/etc/apache2/listen.conf"
create => "true",
perms => m("644"),
edit_defaults => noempty_backup,
edit_line => set_apache_config_ports("@{check_apache_configuration.apache_ports}"),
classes => kept_if_else_hook("apache_ports_kept", "apache_ports_repaired", "apache_ports_failed", "apache_change");
"/etc/apache2/rudder.conf.d/security.conf"
create => "true",
perms => m("644"),
edit_defaults => noempty_backup,
edit_line => set_apache_config_security("check_apache_configuration.apache_security"),
classes => kept_if_else_hook("apache_security_kept", "apache_security_repaired", "apache_security_failed", "apache_change");
"/etc/apache2/rudder.conf.d/vhost-${apache_vhost_fqdn[${apache_vhost_index}]}.conf"
create => "true",
perms => m("644"),
edit_defaults => empty_backup,
edit_line => set_apache_config_vhost("${apache_vhost_fqdn[${apache_vhost_index}]}", "${apache_vhost_port[${apache_vhost_index}]}", "${apache_vhost_root[${apache_vhost_index}]}", "${apache_vhost_expires[${apache_vhost_index}]}", "${apache_vhost_expires_ttl[${apache_vhost_index}]}", "${apache_vhost_alias_one_src[${apache_vhost_index}]}", "${apache_vhost_alias_one_dst[${apache_vhost_index}]}", "${apache_vhost_alias_two_src[${apache_vhost_index}]}", "${apache_vhost_alias_two_dst[${apache_vhost_index}]}", "${apache_vhost_alias_three_src[${apache_vhost_index}]}", "${apache_vhost_alias_three_dst[${apache_vhost_index}]}", "${g.rudder_tools}/apache-vhost.tpl"),
classes => kept_if_else_hook("apache_vhost_${apache_vhost_index}_kept", "apache_vhost_${apache_vhost_index}_repaired", "apache_vhost_${apache_vhost_index}_failed", "apache_change");
any::
"${apache_vhost_root[${apache_vhost_index}]}/."
perms => mog("755", "root", "root"),
create => "true",
classes => if_repaired("root_${apache_vhost_root[${apache_vhost_index}]}_created"),
comment => "Make sure the root directory exists";
processes:
!redhat.!SuSE.apache_autostart::
"/usr/sbin/apache2"
restart_class => "apache_down",
comment => "Ensuring apache is up";
redhat.apache_autostart::
"/usr/sbin/httpd"
restart_class => "apache_down",
comment => "Ensuring apache is up";
SuSE.apache_bin_prefork.apache_autostart::
"/usr/sbin/httpd2-prefork"
restart_class => "apache_down",
comment => "Ensuring apache is up";
SuSE.!apache_bin_prefork.apache_autostart::
"/usr/sbin/httpd2-worker"
restart_class => "apache_down",
comment => "Ensuring apache is up";
commands:
debian.apache_module_list_defined::
"/usr/sbin/a2enmod"
args => "${apache_modules}",
classes => cf2_if_else("apache_module_${apache_modules}_enabled", "apache_module_${apache_vhost_index}_not_apache_modules"),
comment => "Enable Apache modules on Debian";
apache_selinux_adjust.selinux_bin_present::
"/usr/bin/chcon"
args => "-R --type=httpd_sys_content_t \"${apache_vhost_root[${apache_vhost_index}]}\"",
classes => cf2_if_else("apache_selinux_${apache_vhost_index}_adjusted", "apache_selinux_${apache_vhost_index}_not_adjusted"),
comment => "Set SELinux context for Apache VHosts";
!redhat.(apache_down|apache_change)::
"/etc/init.d/apache2"
args => "restart",
classes => cf2_if_else("apache_restarted", "cant_restart_apache"),
comment => "restarting apache";
redhat.(apache_down|apache_change)::
"/etc/init.d/httpd"
args => "restart",
classes => cf2_if_else("apache_restarted", "cant_restart_apache"),
comment => "restarting apache";
(debian.apache_unbootstarted).apache_bin_present::
"/usr/sbin/update-rc.d"
args => "apache2 defaults",
classes => cf2_if_else("apache_bootstarted_ok", "apache_still_unbootstarted"),
comment => "adding apache to the startup scripts";
(redhat.apache_unbootstarted).apache_bin_present::
"/sbin/chkconfig"
args => "--add httpd",
classes => cf2_if_else("apache_bootstarted_ok", "apache_still_unbootstarted"),
comment => "adding apache to the startup scripts";
(SuSE.apache_unbootstarted).apache_bin_present::
"/sbin/chkconfig"
args => "--add apache2",
classes => cf2_if_else("apache_bootstarted_ok", "apache_still_unbootstarted"),
comment => "adding apache to the startup scripts";
reports:
# if the list is not defined, there is nothing to report !
apache_modules_nok::
"@@apacheServerConfiguration@@result_success@@&TRACKINGKEY&@@Module settings@@none@@${g.execRun}##${g.uuid}@#No Apache modules configured to be enabled, no changes made";
# if the list if defined by the user, we report on each element of this list
debian.apache_module_list_defined.apache_modules_ok::
"@@apacheServerConfiguration@@result_success@@&TRACKINGKEY&@@Module settings@@${apache_modules_defined}@@${g.execRun}##${g.uuid}@#The Apache module ${apache_modules_defined} was successfully enabled"
ifvarclass => canonify("apache_module_${apache_modules_defined}_enabled");
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@Module settings@@${apache_modules_defined}@@${g.execRun}##${g.uuid}@#Could not enable apache module ${apache_modules_defined} !"
ifvarclass => canonify("apache_module_${apache_modules_defined}_not_enabled");
!debian.apache_modules_ok::
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@Module settings@@${apache_modules_defined}@@${g.execRun}##${g.uuid}@#The module verification only applies on Debian systems !";
apache_selinux_adjust.selinux_bin_present::
"@@apacheServerConfiguration@@result_success@@&TRACKINGKEY&@@SELinux context@@${apache_vhost_fqdn[${apache_vhost_index}]}@@${g.execRun}##${g.uuid}@#The SELinux context definition was successful for directory ${apache_vhost_root[${apache_vhost_index}]}"
ifvarclass => canonify("apache_selinux_${apache_vhost_index}_adjusted");
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@SELinux context@@${apache_vhost_fqdn[${apache_vhost_index}]}@@${g.execRun}##${g.uuid}@#The SELinux context definition for directory ${apache_vhost_root[${apache_vhost_index}]} has failed !"
ifvarclass => canonify("apache_selinux_${apache_vhost_index}_not_adjusted");
apache_selinux_adjust.!selinux_bin_present::
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@SELinux context@@${apache_vhost_fqdn[${apache_vhost_index}]}@@${g.execRun}##${g.uuid}@#The automatic SELinux context definition was enabled but SELinux binaries";
!apache_selinux_adjust::
"@@apacheServerConfiguration@@result_success@@&TRACKINGKEY&@@SELinux context@@${apache_vhost_fqdn[${apache_vhost_index}]}@@${g.execRun}##${g.uuid}@#No SELinux context definition required for ${apache_vhost_root[${apache_vhost_index}]}";
apache_ports_kept.!apache_ports_repaired.!apache_ports_failed::
"@@apacheServerConfiguration@@result_success@@&TRACKINGKEY&@@Port settings edition@@None@@${g.execRun}##${g.uuid}@#Apache HTTPD port settings OK";
apache_ports_repaired.!apache_ports_failed::
"@@apacheServerConfiguration@@result_repaired@@&TRACKINGKEY&@@Port settings edition@@None@@${g.execRun}##${g.uuid}@#Apache HTTPD port settings reset";
apache_ports_failed::
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@Port settings edition@@None@@${g.execRun}##${g.uuid}@#Apache HTTPD port settings could not be set !";
apache_security_kept.!apache_security_repaired.!apache_security_failed::
"@@apacheServerConfiguration@@result_success@@&TRACKINGKEY&@@Security settings edition@@None@@${g.execRun}##${g.uuid}@#Apache HTTPD security settings OK";
apache_security_repaired.!apache_security_failed::
"@@apacheServerConfiguration@@result_repaired@@&TRACKINGKEY&@@Security settings edition@@None@@${g.execRun}##${g.uuid}@#Apache HTTPD security settings reset";
apache_security_failed::
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@Security settings edition@@None@@${g.execRun}##${g.uuid}@#Apache HTTPD security settings could not be set !";
cfengine::
"@@apacheServerConfiguration@@result_success@@&TRACKINGKEY&@@Virtual host settings@@${apache_vhost_fqdn[${apache_vhost_index}]}@@${g.execRun}##${g.uuid}@#Apache HTTPD virtualhost ${apache_vhost_fqdn[${apache_vhost_index}]} already set"
ifvarclass => "apache_vhost_${apache_vhost_index}_kept.!apache_vhost_${apache_vhost_index}_repaired.!apache_vhost_${apache_vhost_index}_failed";
"@@apacheServerConfiguration@@result_repaired@@&TRACKINGKEY&@@Virtual host settings@@${apache_vhost_fqdn[${apache_vhost_index}]}@@${g.execRun}##${g.uuid}@#Apache HTTPD virtualhost ${apache_vhost_fqdn[${apache_vhost_index}]} reset"
ifvarclass => "apache_vhost_${apache_vhost_index}_repaired.!apache_vhost_${apache_vhost_index}_failed";
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@Virtual host settings@@${apache_vhost_fqdn[${apache_vhost_index}]}@@${g.execRun}##${g.uuid}@#Apache HTTPD virtualhost ${apache_vhost_fqdn[${apache_vhost_index}]} could not be set !"
ifvarclass => "apache_vhost_${apache_vhost_index}_failed";
"@@apacheServerConfiguration@@log_info@@&TRACKINGKEY&@@Virtual host settings@@${apache_vhost_fqdn[${apache_vhost_index}]}@@${g.execRun}##${g.uuid}@#The root directory ${apache_vhost_root[${apache_vhost_index}]} was created"
ifvarclass => canonify("root_${apache_vhost_root[${apache_vhost_index}]}_created");
apache_autostart.apache_bootstarted.!apache_unboostarted::
"@@apacheServerConfiguration@@result_success@@&TRACKINGKEY&@@Apache bootstart@@None@@${g.execRun}##${g.uuid}@#Apache HTTPD is correctly set to start on boot";
apache_autostart.apache_unboostarted.apache_bootstarted_ok.!apache_still_unbootstarted::
"@@apacheServerConfiguration@@result_repaired@@&TRACKINGKEY&@@Apache bootstart@@None@@${g.execRun}##${g.uuid}@#Apache HTTPD is now starting on boot";
apache_autostart.apache_still_unbootstarted.apache_still_unbootstarted::
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@Apache bootstart@@None@@${g.execRun}##${g.uuid}@#Apache HTTPD could not be set to start on boot";
!apache_autostart::
"@@apacheServerConfiguration@@result_success@@&TRACKINGKEY&@@Apache bootstart@@None@@${g.execRun}##${g.uuid}@#Don't have to check if Apache HTTPD should be started automatically";
apache_restarted::
"@@apacheServerConfiguration@@log_info@@&TRACKINGKEY&@@apacheServer@@None@@${g.execRun}##${g.uuid}@#Apache HTTPD restarted";
cant_restart_apache::
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@apacheServer@@None@@${g.execRun}##${g.uuid}@#Could not restart Apache HTTPD";
!apache_bin_present::
"@@apacheServerConfiguration@@result_error@@&TRACKINGKEY&@@Apache2 installation@@None@@${g.execRun}##${g.uuid}@#Apache binary is not present. Something is wrong (installation failure ?)";
}
bundle edit_line cleanup_redhat_apache(tab)
# 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 an associative array containing v[LHS]="rhs"
# Based on set_variable_values from cfengine_stdlib.cf, modified to
# use whitespace as separator, and to handle commented-out lines.
{
vars:
"index" slist => getindices("${tab}");
delete_lines:
"^.*${index}.*$";
"^NameVirtualHost.*((?!443).)*$";
"^Listen.*((?!443).)*$";
insert_lines:
redhat::
"Include /etc/httpd/rudder.conf.d/*.conf";
(debian|SuSE)::
"Include /etc/apache2/rudder.conf.d/*.conf";
}
bundle edit_line set_apache_config_ports(ports)
{
delete_lines:
"^NameVirtualHost.*((?!443).)*$";
"^Listen.*((?!443).)*$";
insert_lines:
"NameVirtualHost *:${ports}";
"Listen ${ports}";
}
bundle edit_line set_apache_config_security(tab)
# 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 an associative array containing v[LHS]="rhs"
# Based on set_variable_values from cfengine_stdlib.cf, modified to
# use whitespace as separator, and to handle commented-out lines.
{
vars:
"index" slist => getindices("${tab}");
# Be careful if the index string contains funny chars
"cindex[${index}]" string => canonify("${index}");
delete_lines:
"^.*${index}.*$";
field_edits:
# If the line is there, but commented out, first uncomment it
"#+${index}\s+.*"
edit_field => col("\s+","1","${index}","set");
# match a line starting like the key something
"${index}\s+.*"
edit_field => col("\s+","2","${${tab}[${index}]}","set"),
classes => if_ok("not_${cindex[${index}]}");
insert_lines:
"${index} ${${tab}[${index}]}"
ifvarclass => "!not_${cindex[${index}]}";
}
bundle edit_line set_apache_config_vhost(fqdn, port, root, exp, exp_ttl, alias_one_src, alias_one_dst, alias_two_src, alias_two_dst, alias_three_src, alias_three_dst, template)
{
vars:
mylock1::
"mylock" string => "mylock",
policy => "overridable";
set_expires::
"finexpire" string => "On",
policy => "overridable";
unset_expires::
"finexpire" string => "Off",
policy => "overridable";
set_alias_one::
"finalias_one" string => "Alias ${alias_one_src} \"${alias_one_dst}\"",
policy => "overridable";
set_alias_two::
"finalias_two" string => "Alias ${alias_two_src} \"${alias_two_dst}\"",
policy => "overridable";
set_alias_three::
"finalias_three" string => "Alias ${alias_three_src} \"${alias_three_dst}\"",
policy => "overridable";
unset_alias_one::
"finalias_one" string => "# Alias 1 disabled",
policy => "overridable";
unset_alias_two::
"finalias_two" string => "# Alias 2 disabled",
policy => "overridable";
unset_alias_three::
"finalias_three" string => "# Alias 3 disabled",
policy => "overridable";
classes:
"set_expires" expression => strcmp("${exp}","true");
"unset_expires" expression => strcmp("${exp}","false");
"set_alias_one" not => strcmp("${alias_one_src}","Disabled");
"set_alias_two" not => strcmp("${alias_two_src}","Disabled");
"set_alias_three" not => strcmp("${alias_three_src}","Disabled");
"unset_alias_one" expression => strcmp("${alias_one_src}","Disabled");
"unset_alias_two" expression => strcmp("${alias_two_src}","Disabled");
"unset_alias_three" expression => strcmp("${alias_three_src}","Disabled");
"mylock1" expression => "any";
"mylock" expression => strcmp("mylock", "${mylock}");
insert_lines:
mylock::
"${template}"
insert_type => "file",
expand_scalars => "true";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
##########################################################################
# Installs requested packages by OS #
# #
# - APT_PACKAGE_DEBLIST --> The OS dependant packages to install #
# #
# - APT_PACKAGE_DEBACTION --> The action to be made on these packages #
# #
##########################################################################
bundle agent check_apt_package_installation
{
vars:
&APT_PACKAGE_DEBLIST:{name |"apt_package[&i&]" string => "&name&";
}&
&APT_PACKAGE_DEBACTION:{action |"apt_action[&i&]" string => "&action&";
}&
&APT_PACKAGE_ALLOW_UNTRUSTED:{untrusted |"apt_allow_untrusted[&i&]" string => "&untrusted&";
}&
&APT_PACKAGE_VERSION_DEFINITION:{definition |"apt_version_definition[&i&]" string => "&definition&";
}&
&APT_PACKAGE_VERSION_CRITERION:{version_criterion |"apt_version_criterion[&i&]" string => "&version_criterion&";
}&
&APT_PACKAGE_VERSION:{version |"apt_version[&i&]" string => "&version&";
}&
&TRACKINGKEY:{piuuid |"apt_policy_instance_uuid[&i&]" string => "&piuuid&";
}&
# "debian_packagelist" slist => {&APT_PACKAGE_DEBLIST: { "&it&" };separator=", "&};
"index_aptpkg" slist => getindices("apt_package");
classes:
"${index_aptpkg}_package_version_defined" not => strcmp("${apt_version_definition[${index_aptpkg}]}", "default");
packages:
debian::
"${apt_package[${index_aptpkg}]}"
package_policy => "${apt_action[${index_aptpkg}]}",
package_method => apt_nobulk("30", "${apt_allow_untrusted[${index_aptpkg}]}"),
classes => kept_if_else("debian_install_kept_${apt_package[${index_aptpkg}]}", "debian_installed_${apt_package[${index_aptpkg}]}", "debian_install_failed_${apt_package[${index_aptpkg}]}"),
ifvarclass => "!${index_aptpkg}_package_version_defined",
comment => "Handling ${apt_package[${index_aptpkg}]} using apt_nobulk, policy : ${apt_action[${index_aptpkg}]}";
"${apt_package[${index_aptpkg}]}"
package_policy => "${apt_action[${index_aptpkg}]}",
package_method => apt_nobulk("30", "${apt_allow_untrusted[${index_aptpkg}]}"),
package_select => "${apt_version_criterion[${index_aptpkg}]}",
package_version => "${apt_version[${index_aptpkg}]}",
classes => kept_if_else("debian_install_kept_${apt_package[${index_aptpkg}]}", "debian_installed_${apt_package[${index_aptpkg}]}", "debian_install_failed_${apt_package[${index_aptpkg}]}"),
ifvarclass => "${index_aptpkg}_package_version_defined",
comment => "Handling ${apt_package[${index_aptpkg}]} using apt_nobulk, policy : ${apt_action[${index_aptpkg}]}";
reports:
debian::
"@@packageInstallation@@result_repaired@@${apt_policy_instance_uuid[${index_aptpkg}]}@@Debian/Ubuntu packages@@${apt_package[${index_aptpkg}]}@@${g.execRun}##${g.uuid}@#Performed repair action for deb package ${apt_package[${index_aptpkg}]} with policy: ${apt_action[${index_aptpkg}]}"
ifvarclass => canonify("debian_installed_${apt_package[${index_aptpkg}]}");
"@@packageInstallation@@result_error@@${apt_policy_instance_uuid[${index_aptpkg}]}@@Debian/Ubuntu packages@@${apt_package[${index_aptpkg}]}@@${g.execRun}##${g.uuid}@#Error taking action for deb package ${apt_package[${index_aptpkg}]} with policy: ${apt_action[${index_aptpkg}]}"
ifvarclass => canonify("debian_install_failed_${apt_package[${index_aptpkg}]}");
"@@packageInstallation@@result_success@@${apt_policy_instance_uuid[${index_aptpkg}]}@@Debian/Ubuntu packages@@${apt_package[${index_aptpkg}]}@@${g.execRun}##${g.uuid}@#No action required for deb package ${apt_package[${index_aptpkg}]} with policy: ${apt_action[${index_aptpkg}]}"
ifvarclass => canonify("debian_install_kept_${apt_package[${index_aptpkg}]}");
}
body package_method apt_nobulk(apt_pkg_timeout, allow_untrusted)
{
any::
# make correct version comparisons
package_version_less_command => "${rudder_debian_knowledge.dpkg_compare_less}";
package_version_equal_command => "${rudder_debian_knowledge.dpkg_compare_equal}";
debian::
package_changes => "individual";
package_list_update_ifelapsed => "${apt_pkg_timeout}";
package_list_command => "/usr/bin/dpkg -l";
package_list_name_regex => ".i\s+([^\s:]+).*";
package_list_version_regex => ".i\s+[^\s]+\s+([^\s]+).*";
package_installed_regex => ".i.*"; # packages that have been uninstalled may be listed
package_name_convention => "${name}";
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 -o APT::Get::AutomaticRemove=false -o Apt::Get::AllowUnauthenticated=${allow_untrusted} --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 -o APT::Get::AutomaticRemove=false --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 -o APT::Get::AutomaticRemove=false -o Apt::Get::AllowUnauthenticated=${allow_untrusted} --yes install";
package_verify_command => "/usr/bin/dpkg -s";
package_noverify_returncode => "1";
}
#####################################################################################
# Copyright 2011-2012 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
######################################################
# Configures the APT Package Manager #
######################################################
bundle agent check_apt_settings
{
vars:
debian_4::
"apt_detected_distro" string => "etch";
debian_5::
"apt_detected_distro" string => "lenny";
debian_6::
"apt_detected_distro" string => "squeeze";
debian_7::
"apt_detected_distro" string => "wheezy";
debian_8::
"apt_detected_distro" string => "jessie";
ubuntu_karmic::
"apt_detected_distro" string => "karmic";
ubuntu_lucid::
"apt_detected_distro" string => "lucid";
ubuntu_maverick::
"apt_detected_distro" string => "maverick";
ubuntu_natty::
"apt_detected_distro" string => "natty";
ubuntu_oneiric::
"apt_detected_distro" string => "oneiric";
ubuntu_precise::
"apt_detected_distro" string => "precise";
ubuntu_quantal::
"apt_detected_distro" string => "quantal";
ubuntu_raring::
"apt_detected_distro" string => "raring";
apt_installrecommends_edit::
"aptconf[APT::Install-Recommends]" string => "&APT_INSTALLRECOMMENDS&";
apt_installsuggests_edit::
"aptconf[APT::Install-Suggests]" string => "&APT_INSTALLSUGGESTS&";
any::
&if (APT_HTTPPROXY_URL)&
"aptconf[Acquire::http::Proxy]" string => "\"&APT_HTTPPROXY_URL&\";";
&endif&
&if (APT_FTPPROXY_URL)&
"aptconf[Acquire::ftp::Proxy]" string => "\"&APT_FTPPROXY_URL&\";";
&endif&
&APT_URL:{apt_url |"apt_url[&i&]" string => "&apt_url&";
}&
&APT_COMPONENT_MAIN, APT_COMPONENT_CONTRIB, APT_COMPONENT_NON_FREE, APT_COMPONENT_RESTRICTED, APT_COMPONENT_UNIVERSE, APT_COMPONENT_MULTIVERSE:{main, contrib, nonfree, restricted, universe, multiverse |"apt_components[&i&]" string => "&main& &contrib& &nonfree& &restricted& &universe& &multiverse&";
}&
&APT_DISTRIBUTION, APT_DISTRO_AUTODETECT:{apt_distro, apt_autodetect |"apt_distro[&i&]" string => "&if (apt_autodetect)&${apt_detected_distro}&else&&apt_distro&&endif&";
}&
classes:
# Repositories edition ?
"apt_repositories_edit" not => strcmp("&APT_ADDREPOSITORIES&","false");
# Disable repositories ?
"apt_disablerepositories" not => strcmp("&APT_DISABLEREPOSITORIES&","false");
# InstallRecommends edition ?
"apt_installrecommends_edit" not => strcmp("&APT_INSTALLRECOMMENDS&","dontchange");
# InstallSuggests edition ?
"apt_installsuggests_edit" not => strcmp("&APT_INSTALLSUGGESTS&","dontchange");
files:
debian.apt_repositories_edit::
"/etc/apt/sources.list.d/rudder-apt.list"
create => "true",
perms => m("644"),
edit_line => set_apt_config_values_tier1("check_apt_settings.apt_url", "check_apt_settings.apt_distro", "check_apt_settings.apt_components"),
edit_defaults => empty_backup,
classes => kept_if_else("apt_tier1_kept", "apt_tier1_validated", "apt_tier1_failed");
debian::
"/etc/apt/apt.conf.d/99rudder"
create => "true",
perms => m("644"),
edit_defaults => empty_backup,
edit_line => set_apt_config_values_tier2("check_apt_settings.aptconf"),
classes => kept_if_else("apt_tier2_kept", "apt_tier2_validated", "apt_tier2_failed");
debian.apt_disablerepositories.(apt_tier1_validated|apt_tier1_kept)::
"/etc/apt/sources.list"
create => "true",
perms => m("644"),
edit_defaults => noempty_backup,
edit_line => comment_lines_matching("^[^#].*$","#"),
classes => kept_if_else("apt_disabled_kept", "apt_disabled_validated", "apt_disabled_failed");
"/etc/apt/sources.list.d/.*"
edit_line => comment_lines_matching("^[^#].*$","#"),
edit_defaults => noempty_backup,
file_select => not_rudderaptlist,
classes => kept_if_else("apt_disabled_kept", "apt_disabled_validated", "apt_disabled_failed");
reports:
# SUCCESS if:
## Do not need to edit repositories or repositories good = ((apt_tier1_kept|!apt_repositories_edit).!apt_tier1_validated)
## and
## APT Config good = (apt_tier2_kept.!apt_tier2_validated)
## and
## No need to disable other repositories (not require or already disabled) = ((!apt_disablerepositories|(apt_disabled_kept|!apt_repositories_edit)).!apt_disabled_validated)
## and
## No error = !(apt_tier1_failed|apt_tier2_failed|apt_disabled_failed)
((apt_tier1_kept|!apt_repositories_edit).!apt_tier1_validated).(apt_tier2_kept.!apt_tier2_validated).((!apt_disablerepositories|(apt_disabled_kept|!apt_repositories_edit)).!apt_disabled_validated).!(apt_tier1_failed|apt_tier2_failed|apt_disabled_failed)::
"@@aptPackageManagerSettings@@result_success@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT settings were all already correct";
# REPAIRED if:
## Need to edit repositories and no error= apt_tier1_validated
## or
## Need to edit APT config and no error = apt_tier2_validated
## or
## Need to disable other repositories and no error= apt_disabled_validated
## and
## No error = !(apt_tier1_failed|apt_tier2_failed|apt_disabled_failed)
(apt_tier1_validated|apt_tier2_validated|apt_disabled_validated).(!apt_tier1_failed|!apt_tier2_failed|!apt_disabled_failed)::
"@@aptPackageManagerSettings@@result_repaired@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#Some APT settings were reset";
apt_tier1_kept::
"@@aptPackageManagerSettings@@log_info@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT repositories already correct";
apt_tier2_kept::
"@@aptPackageManagerSettings@@log_info@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT configuration parameters already correct";
apt_tier1_validated::
"@@aptPackageManagerSettings@@log_repaired@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT repositories have been reset";
apt_tier2_validated::
"@@aptPackageManagerSettings@@log_repaired@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT configuration parameters have been reset";
apt_tier1_failed::
"@@aptPackageManagerSettings@@result_error@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT repositories could not be edited";
apt_tier2_failed::
"@@aptPackageManagerSettings@@result_error@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT configuration could not be set";
apt_disablerepositories::
"@@aptPackageManagerSettings@@log_info@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT repository purge has been requested";
apt_disabled_validated::
"@@aptPackageManagerSettings@@log_repaired@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT repositories deactivation is done";
apt_disabled_failed::
"@@aptPackageManagerSettings@@result_error@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT repositories deactivation is failed";
!debian::
"@@aptPackageManagerSettings@@result_error@@&TRACKINGKEY&@@aptPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#APT cannot be configured on non Debian OSes";
}
bundle edit_line set_apt_config_values_tier1(apt_url, apt_distro, apt_components)
{
vars:
"apt_index" slist => getindices("${apt_url}");
insert_lines:
"${rudder_parameters.rudder_file_edit_header}"
location => start,
insert_type => "preserve_block";
"deb ${${apt_url}[${apt_index}]} ${${apt_distro}[${apt_index}]} ${${apt_components}[${apt_index}]}";
}
bundle edit_line set_apt_config_values_tier2(tab)
# 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 an associative array containing v[LHS]="rhs"
# Based on set_variable_values from cfengine_stdlib.cf, modified to
# use whitespace as separator, and to handle commented-out lines.
{
vars:
"index" slist => getindices("${tab}");
# 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
"#+${index}\s+.*"
edit_field => col("\s+","1","${index}","set");
# match a line starting like the key something
"${index}\s+.*"
edit_field => col("\s+","2","${${tab}[${index}]}","set"),
classes => if_ok("not_${cindex[${index}]}");
insert_lines:
"// ### File managed by Rudder, edit with care ###"
location => start;
"${index} ${${tab}[${index}]}"
ifvarclass => "!not_${cindex[${index}]}";
}
body file_select not_rudderaptlist
{
leaf_name => { "^[^rudder.*?\.list].*" };
file_result => "leaf_name";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
####################
# Installs OpenVPN #
####################
bundle agent check_openvpn_installation
{
classes:
"openvpn_present" expression => fileexists("/etc/init.d/openvpn");
packages:
linux.!SuSE::
"openvpn"
package_policy => "add",
package_method => generic,
classes => kept_if_else("openvpn_here", "openvpn_installed", "cant_install_openvpn"),
comment => "Installing openvpn using generic interface";
commands:
SuSE.!openvpn_present.64_bit::
"/bin/rpm"
args => "-Uvh ${g.rudder_var}/tools/openvpn-2.2.1-1.x86_64.rpm",
classes => kept_if_else("openvpn_here", "openvpn_installed", "cant_install_openvpn"),
comment => "Installing openvpn using plain RPM";
SuSE.!openvpn_present.32_bit::
"/bin/rpm"
args => "-Uvh ${g.rudder_var}/tools/openvpn-2.2.1-1.i686.rpm",
classes => kept_if_else("openvpn_here", "openvpn_installed", "cant_install_openvpn"),
comment => "Installing openvpn using plain RPM";
reports:
(openvpn_here|openvpn_present)::
"@@openvpnConfiguration@@result_success@@&TRACKINGKEY&@@OpenVPN install@@None@@${g.execRun}##${g.uuid}@#openvpn already installed";
openvpn_installed::
"@@openvpnConfiguration@@result_repaired@@&TRACKINGKEY&@@OpenVPN install@@None@@${g.execRun}##${g.uuid}@#openvpn installed";
cant_install_openvpn::
"@@openvpnConfiguration@@result_error@@&TRACKINGKEY&@@OpenVPN install@@None@@${g.execRun}##${g.uuid}@#Can't install openvpn";
!linux::
"@@openvpnConfiguration@@result_success@@&TRACKINGKEY&@@OpenVPN install@@None@@${g.execRun}##${g.uuid}@#Support to check if openvpn is installed not available on this platform";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent check_openvpn_client_configuration
{
vars:
&OVPN_CLIENT_REMOTE_SERVER, OVPN_CLIENT_REMOTE_PORT:{server, port |"ovpn_client_remote[&i&]" string => "&server& &port&";
}&
"ovpn_client[dev]" string => "&OVPN_CLIENT_TUNTAP&";
"ovpn_client[proto]" string => "&OVPN_CLIENT_REMOTE_PROTOCOL&";
"ovpn_client[script-security]" string => "2";
"ovpn_client[verb]" string => "&OVPN_CLIENT_LOGGING_VERBOSITY&";
ovpn_client_pskmode::
"ovpn_client[secret]" string => "&OVPN_CLIENT_PSKFILE&";
ovpn_client_randomize::
"ovpn_client[remote-random]" string => "";
ovpn_client_pwauth::
"ovpn_client[auth-user-pass]" string => "/etc/openvpn/keyring.pwd";
ovpn_client_keepretrying::
"ovpn_client[resolv-retry]" string => "infinite";
ovpn_client_logtofile.ovpn_client_appendfile::
"ovpn_client[log-append]" string => "&OVPN_CLIENT_LOGGING_FILE&";
ovpn_client_logtofile.!ovpn_client_appendfile::
"ovpn_client[log]" string => "&OVPN_CLIENT_LOGGING_FILE&";
classes:
# Security : if not there, OpenVPN too, so don't bother anymore
"openvpn_bin_present" expression => fileexists("/usr/sbin/openvpn");
# Autostart ?
"ovpn_client_autostart" expression => strcmp("&OVPN_CLIENT_AUTOSTART&","true");
# PSK mode ?
"ovpn_client_pskmode" expression => strcmp("&OVPN_CLIENT_KEYMODE&","psk");
# Randomize remotes ?
"ovpn_client_randomize" expression => strcmp("&OVPN_CLIENT_REMOTE_RANDOMIZE&","true");
# Use user/password ?
"ovpn_client_pwauth" expression => strcmp("&OVPN_CLIENT_REMOTE_AUTH&","true");
# Do not use user/password ?
"ovpn_client_nopwauth" expression => strcmp("&OVPN_CLIENT_REMOTE_AUTH&","false");
# Log to file ?
"ovpn_client_logtofile" expression => strcmp("&OVPN_CLIENT_LOGGING_TARGET&","file");
# Append logs ?
"ovpn_client_appendfile" expression => strcmp("&OVPN_CLIENT_LOGGING_BEHAVIOR&","true");
# Keep retrying connection ?
"ovpn_client_keepretrying" expression => strcmp("&OVPN_CLIENT_REMOTE_KEEPTRYING&","true");
files:
(debian|redhat|SuSE)::
"/etc/rc2.d/S.*openvpn.*"
create => "true",
#depth_search => recurse("0"),
#file_select => openvpn_startlink,
action => WarnOnly,
classes => if_else("openvpn_bootstarted", "openvpn_unbootstarted");
"/etc/openvpn/rudder.conf"
create => "true",
perms => m("644"),
edit_line => set_openvpn_config_values_tier1("check_openvpn_client_configuration.ovpn_client_remote"),
edit_defaults => noempty_backup,
classes => kept_if_else("openvpn_tier1_kept", "openvpn_tier1_validated", "openvpn_tier1_failed");
"/etc/openvpn/rudder.conf"
create => "true",
perms => m("644"),
edit_line => set_openvpn_config_values_tier2("check_openvpn_client_configuration.ovpn_client"),
edit_defaults => noempty_backup,
classes => kept_if_else("openvpn_tier2_kept", "openvpn_tier2_validated", "openvpn_tier2_failed");
ovpn_client_pwauth::
"/etc/openvpn/keyring.pwd"
create => "true",
edit_defaults => noempty_backup,
perms => mog("600", "root", "root"),
edit_line => set_openvpn_config_values_keyring("&OVPN_CLIENT_REMOTE_USER&", "&OVPN_CLIENT_REMOTE_PASS&"),
edit_defaults => noempty_backup,
classes => kept_if_else("openvpn_keyring_kept", "openvpn_keyring_validated", "openvpn_keyring_failed");
processes:
ovpn_client_autostart::
"/usr/sbin/openvpn"
restart_class => "openvpn_down",
comment => "Ensuring openvpn is up";
commands:
(openvpn_tier1_validated|openvpn_tier2_validated|openvpn_keyring_validated|openvpn_down).ovpn_client_autostart::
"/etc/init.d/openvpn"
args => "restart",
classes => cf2_if_else("openvpn_restarted", "cant_restart_openvpn"),
comment => "restarting openvpn";
(debian.openvpn_unbootstarted).openvpn_bin_present::
"/usr/sbin/update-rc.d"
args => "openvpn defaults",
classes => cf2_if_else("openvpn_bootstarted_ok", "openvpn_still_unbootstarted"),
comment => "adding openvpn to the startup scripts";
(redhat.openvpn_unbootstarted).openvpn_bin_present::
"/sbin/chkconfig"
args => "--add openvpn",
classes => cf2_if_else("openvpn_bootstarted_ok", "openvpn_still_unbootstarted"),
comment => "adding openvpn to the startup scripts";
# YES I know this isn't DRY but CF3 does not support nested parenthesis yet
(SuSE.openvpn_unbootstarted).openvpn_bin_present::
"/sbin/chkconfig"
args => "--add openvpn",
classes => cf2_if_else("openvpn_bootstarted_ok", "openvpn_still_unbootstarted"),
comment => "adding openvpn to the startup scripts";
reports:
openvpn_tier1_kept::
"@@openvpnClientConfiguration@@log_info@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN remotes list edition not needed";
openvpn_tier2_kept::
"@@openvpnClientConfiguration@@log_info@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN general configuration is OK";
openvpn_keyring_kept::
"@@openvpnClientConfiguration@@log_info@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN password keyring present";
openvpn_tier1_validated::
"@@openvpnClientConfiguration@@log_repaired@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN remotes list edition done";
openvpn_tier2_validated::
"@@openvpnClientConfiguration@@log_repaired@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN general configuration done";
openvpn_keyring_validated::
"@@openvpnClientConfiguration@@log_repaired@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN keyring written";
openvpn_tier1_failed::
"@@openvpnClientConfiguration@@result_error@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN remotes list edition failed";
openvpn_tier2_failed::
"@@openvpnClientConfiguration@@result_error@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN general configuration failed";
openvpn_keyring_failed::
"@@openvpnClientConfiguration@@result_error@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN keyring could not be written";
ovpn_client_nopwauth.((openvpn_tier1_validated.openvpn_tier2_validated)|(openvpn_tier1_kept.openvpn_tier2_kept))::
"@@openvpnClientConfiguration@@result_success@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN configuration is set correctly";
ovpn_client_pwauth.((openvpn_tier1_validated.openvpn_tier2_validated.openvpn_keyring_validated)|(openvpn_tier1_kept.openvpn_tier2_kept.openvpn_keyring_kept))::
"@@openvpnClientConfiguration@@result_success@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN configuration is set correctly";
(openvpn_tier1_validated.openvpn_tier2_validated.openvpn_keyring_validated)|(openvpn_tier1_kept.openvpn_tier2_kept.openvpn_keyring_kept)::
"@@openvpnClientConfiguration@@result_success@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN configuration is set correctly"
ifvarclass => canonify("ovpn_client_pwauth");
ovpn_client_autostart.openvpn_bootstarted_ok::
"@@openvpnClientConfiguration@@result_repaired@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN is now starting on boot";
ovpn_client_autostart.openvpn_still_unbootstarted::
"@@openvpnClientConfiguration@@result_error@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN could not be set to start on boot";
ovpn_client_autostart.openvpn_bootstarted::
"@@openvpnClientConfiguration@@log_info@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN already set to start on boot";
openvpn_restarted::
"@@openvpnClientConfiguration@@log_repaired@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN restarted";
cant_restart_openvpn::
"@@openvpnClientConfiguration@@result_error@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#Could not restart OpenVPN";
!openvpn_bin_present::
"@@openvpnClientConfiguration@@result_error@@&TRACKINGKEY&@@OpenVPN configuration@@None@@${g.execRun}##${g.uuid}@#OpenVPN binary is not present. Something is wrong (installation failure?)";
}
bundle edit_line set_openvpn_config_values_tier1(remotes)
{
vars:
"remotes_index" slist => getindices("${remotes}");
delete_lines:
"remote\ .*";
insert_lines:
"remote ${${remotes}[${remotes_index}]}";
}
bundle edit_line set_openvpn_config_values_tier2(tab)
# 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 an associative array containing v[LHS]="rhs"
# Based on set_variable_values from cfengine_stdlib.cf, modified to
# use whitespace as separator, and to handle commented-out lines.
{
vars:
"index" slist => getindices("${tab}");
# 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
"#+${index}\s+.*"
edit_field => col("\s+","1","${index}","set");
# match a line starting like the key something
"${index}\s+.*"
edit_field => col("\s+","2","${${tab}[${index}]}","set"),
classes => if_ok("not_${cindex[${index}]}");
insert_lines:
"${rudder_parameters.rudder_file_edit_header}"
location => start,
insert_type => "preserve_block";
"${index} ${${tab}[${index}]}"
ifvarclass => "!not_${cindex[${index}]}";
}
bundle edit_line set_openvpn_config_values_keyring(user, pass)
{
insert_lines:
"${user}";
"${pass}";
}
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# List of packages to manage
# Format of the file
# action:version_definition:version_comparaison:trackingkey
& RPM_PACKAGE_REDACTION, RPM_PACKAGE_VERSION_DEFINITION, RPM_PACKAGE_VERSION_CRITERION, TRACKINGKEY:{action, definition, version_criterion, trackingkey | &action&:&definition&:&version_criterion&:&trackingkey&
}&
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
##########################################################################
# Installs requested packages by OS #
# #
# - RPM_PACKAGE_REDLIST --> The OS dependant packages to install #
# #
# - RPM_PACKAGE_REDACTION --> The action to be made on these packages #
# #
# - RPM_PACKAGE_VERSION --> The optionnal package version #
# #
##########################################################################
bundle agent check_rpm_package_installation {
vars:
&RPM_PACKAGE_CHECK_INTERVAL:{check_interval |"rpm_package_check_interval" string => "&check_interval&";
}&
"package_number" int => readstringarrayidx("rpm_data","${sys.workdir}/inputs/rpmPackageInstallation/6.1/rpmPackageInstallationData", "#[^\n]*",":",9000,1600000);
&! We need to use the i0 notation to have indexes starting at 0, as in readstringarrayidx !&
&RPM_PACKAGE_REDLIST:{name |"rpm_package[&i0&]" string => "&name&";
}&
&RPM_PACKAGE_VERSION:{version |"rpm_version[&i0&]" string => "&version&";
}&
&RPM_PACKAGE_POST_HOOK_COMMAND:{command |"rpm_posthook[&i0&]" string => "&command&";
}&
"index_rpmpkg" slist => getindices("rpm_package");
# File containing the list of available packages to install
"available_updates_file" string => "${sys.workdir}/state/software_available_updates.csv";
redhat::
"available_updates_command" string => "/usr/bin/yum --quiet check-update | ${paths.path[sed]} 's%[0-9]\+:%%g' > ${available_updates_file}";
zypper_version_ok::
"available_updates_command" string => "/usr/bin/zypper list-updates -a | ${paths.path[grep]} '|' | ${paths.path[awk]} -F '|' '{print $3 $5}' | ${paths.path[sed]} 's%[0-9]\+:%%g' > ${available_updates_file}";
# If the promises have been updated, we need to remove previously
# defined persistent classes (by setting there persistence to 1 minutes)
# and cancelling also the classes for this run
rudder_promises_generated_repaired::
"zmd_classes_to_cancel_on_update" slist => { "zmd_kept", "zmd_restarted", "could_not_restart_zmd" };
"unpersist_rpm_kept_classes_${index_rpmpkg}"
string => "undefine",
classes => rudder_always_classes_persist("rpm_package_install_kept_${index_rpmpkg}", "1");
"rpm_kept_classes_purged_${index_rpmpkg}"
string => "undefine",
classes => cancel_all_classes("rpm_package_install_kept_${index_rpmpkg}");
"unpersist_rpm_repaired_classes_${index_rpmpkg}"
string => "undefine",
classes => rudder_always_classes_persist("rpm_package_installed_${index_rpmpkg}", "1");
"rpm_repaired_classes_purged_${index_rpmpkg}"
string => "undefine",
classes => cancel_all_classes("rpm_package_installed_${index_rpmpkg}");
"unpersist_rpm_error_classes_${index_rpmpkg}"
string => "undefine",
classes => rudder_always_classes_persist("rpm_package_install_failed_${index_rpmpkg}", "1");
"rpm_error_classes_purged_${index_rpmpkg}"
string => "undefine",
classes => cancel_all_classes("rpm_package_install_failed_${index_rpmpkg}");
"unpersist_${zmd_classes_to_cancel_on_update}"
string => "undefine",
classes => rudder_always_classes_persist("${zmd_classes_to_cancel_on_update}", "1");
"${zmd_classes_to_cancel_on_update}_purged"
string => "undefine",
classes => cancel_all_classes("${zmd_classes_to_cancel_on_update}");
# Generate the list of avalable package if it has been done more than xx minutes ago, or if the file is not there
# Do it on redhat, or if the version of zypper is valid
(redhat|zypper_version_ok).first_pass::
"get_update_list" string => execresult("${available_updates_command}", "useshell"),
classes => rudder_common_classes_persist("rpm_package_installation_updated_available_packages", "${rpm_package_check_interval}"),
ifvarclass => "!(rpm_package_installation_updated_available_packages_repaired|rpm_package_installation_updated_available_packages_kept)|!update_file_exists";
# If the update file exist, then gather the version of the packages in it
update_file_exists::
"${index_rpmpkg}_update_version" string => execresult("${paths.path[grep]} \"${rpm_package[${index_rpmpkg}]}.\" ${available_updates_file} | ${paths.path[awk]} 'END {print $2}'", "useshell"),
classes => rudder_common_classes("${index_rpmpkg}_update_version_fetched"),
ifvarclass => "!(${index_rpmpkg}_update_version_fetched_kept|${index_rpmpkg}_update_version_fetched_repaired|${index_rpmpkg}_update_version_fetched_failed)";
classes:
&RPM_PACKAGE_POST_HOOK_RUN:{run |"execute_command_&i0&" expression => strcmp("&run&", "true");
}&
# Check if update file exists
"update_file_exists" expression => fileexists("${available_updates_file}");
# Detect if we want to update the package
"is_update_action_${index_rpmpkg}" expression => strcmp("${rpm_data[${index_rpmpkg}][0]}", "update");
# Gather the version of the available package
"${index_rpmpkg}_update_version_valid" not => strcmp("", "${${index_rpmpkg}_update_version}"),
ifvarclass => "(${index_rpmpkg}_update_version_fetched_kept|${index_rpmpkg}_update_version_fetched_repaired)";
"${index_rpmpkg}_package_version_defined" not => strcmp("${rpm_data[${index_rpmpkg}][1]}", "default");
"first_pass" expression => "any";
any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";
packages:
redhat|SuSE::
# Case 1: Not an update, or an update on SuSE without proper Zypper
"${rpm_package[${index_rpmpkg}]}"
package_policy => "${rpm_data[${index_rpmpkg}][0]}",
package_method => generic_nobulk("30"),
classes => rudder_common_classes_persist("rpm_package_installation_${index_rpmpkg}", "${rpm_package_check_interval}"),
ifvarclass => "(!is_update_action_${index_rpmpkg}|(SuSE.!zypper_version_ok)).!${index_rpmpkg}_package_version_defined.!(rpm_package_installation_${index_rpmpkg}_repaired|rpm_package_installation_${index_rpmpkg}_error|rpm_package_installation_${index_rpmpkg}_kept)",
comment => "Handling ${rpm_package[${index_rpmpkg}]} using yum_nobulk, policy : ${rpm_data[${index_rpmpkg}][0]}";
# Case 2: It is an update, on RedHat or SuSE with Zypper, and we didn't give a version, but we could fetch it
"${rpm_package[${index_rpmpkg}]}"
package_policy => "${rpm_data[${index_rpmpkg}][0]}",
package_method => generic_nobulk("30"),
package_select => "==",
package_version => "${${index_rpmpkg}_update_version}",
classes => rudder_common_classes_persist("rpm_package_installation_${index_rpmpkg}", "${rpm_package_check_interval}"),
ifvarclass => "is_update_action_${index_rpmpkg}.${index_rpmpkg}_update_version_valid.!${index_rpmpkg}_package_version_defined.!(rpm_package_installation_${index_rpmpkg}_repaired|rpm_package_installation_${index_rpmpkg}_error|rpm_package_installation_${index_rpmpkg}_kept)",
comment => "Handling ${rpm_package[${index_rpmpkg}]} using yum_nobulk, policy : ${rpm_data[${index_rpmpkg}][0]}";
# Case 3: We do have a version defined
"${rpm_package[${index_rpmpkg}]}"
package_policy => "${rpm_data[${index_rpmpkg}][0]}",
package_method => generic_nobulk("30"),
package_select => "${rpm_data[${index_rpmpkg}][2]}",
package_version => "${rpm_version[${index_rpmpkg}]}",
classes => rudder_common_classes_persist("rpm_package_installation_${index_rpmpkg}", "${rpm_package_check_interval}"),
ifvarclass => "${index_rpmpkg}_package_version_defined.!(rpm_package_installation_${index_rpmpkg}_repaired|rpm_package_installation_${index_rpmpkg}_error|rpm_package_installation_${index_rpmpkg}_kept)",
comment => "Handling ${rpm_package[${index_rpmpkg}]} using yum_nobulk, policy : ${rpm_data[${index_rpmpkg}][0]}";
methods:
pass2.zmd_restart.!zypper_version_ok::
"restart_zmd" usebundle => service_restart("novell-zmd"),
classes => kept_if_else_persist("zmd_kept", "zmd_restarted", "could_not_restart_zmd", "${rpm_package_check_interval}"),
ifvarclass => "!(zmd_kept|zmd_restarted|could_not_restart_zmd).!zypper_version_ok";
pass3.(redhat|SuSE)::
"any" usebundle => rudder_common_report("packageInstallation", "result_repaired", "${rpm_data[${index_rpmpkg}][3]}", "RHEL/CentOS/SuSE packages", "${rpm_package[${index_rpmpkg}]}", "Performed repair action for RPM package ${rpm_package[${index_rpmpkg}]} to comply with policy: ${rpm_data[${index_rpmpkg}][0]}"),
ifvarclass => canonify("rpm_package_installation_${index_rpmpkg}_repaired");
"any" usebundle => rudder_common_report("packageInstallation", "result_error", "${rpm_data[${index_rpmpkg}][3]}", "RHEL/CentOS/SuSE packages", "${rpm_package[${index_rpmpkg}]}", "Error taking action for RPM package ${rpm_package[${index_rpmpkg}]} with policy: ${rpm_data[${index_rpmpkg}][0]}"),
ifvarclass => canonify("rpm_package_installation_${index_rpmpkg}_error");
"any" usebundle => rudder_common_report("packageInstallation", "result_success", "${rpm_data[${index_rpmpkg}][3]}", "RHEL/CentOS/SuSE packages", "${rpm_package[${index_rpmpkg}]}", "No action required for RPM package ${rpm_package[${index_rpmpkg}]} with policy: ${rpm_data[${index_rpmpkg}][0]}"),
ifvarclass => canonify("rpm_package_installation_${index_rpmpkg}_kept");
"any" usebundle => rudder_common_report("packageInstallation", "result_error", "${rpm_data[${index_rpmpkg}][3]}", "RHEL/CentOS/SuSE packages", "${rpm_package[${index_rpmpkg}]}", "Error taking action for RPM package ${rpm_package[${index_rpmpkg}]} with policy: ${rpm_data[${index_rpmpkg}][0]} - could not fetch the version to update"),
ifvarclass => "is_update_action_${index_rpmpkg}.!${index_rpmpkg}_package_version_defined.rpm_package_installation_updated_available_packages_error";
"any" usebundle => rudder_common_report("packageInstallation", "result_success", "${rpm_data[${index_rpmpkg}][3]}", "RHEL/CentOS/SuSE packages", "${rpm_package[${index_rpmpkg}]}", "No action required for RPM package ${rpm_package[${index_rpmpkg}]} with policy: ${rpm_data[${index_rpmpkg}][0]}"),
ifvarclass => "is_update_action_${index_rpmpkg}.!${index_rpmpkg}_package_version_defined.(rpm_package_installation_updated_available_packages_kept|rpm_package_installation_updated_available_packages_repaired).!${index_rpmpkg}_update_version_valid";
# Post hooks reporting
"any" usebundle => rudder_common_report("packageInstallation", "result_repaired", "${rpm_data[${index_rpmpkg}][3]}", "Post-modification hook", "${rpm_package[${index_rpmpkg}]}", "Successfully executed post hook (${rpm_posthook[${index_rpmpkg}]}) for RPM package ${rpm_package[${index_rpmpkg}]}"),
ifvarclass => "rpm_posthook_${index_rpmpkg}_repaired";
"any" usebundle => rudder_common_report("packageInstallation", "result_error", "${rpm_data[${index_rpmpkg}][3]}", "Post-modification hook", "${rpm_package[${index_rpmpkg}]}", "Error executing post hook (${rpm_posthook[${index_rpmpkg}]}) for RPM package ${rpm_package[${index_rpmpkg}]}"),
ifvarclass => "rpm_posthook_${index_rpmpkg}_error";
"any" usebundle => rudder_common_report("packageInstallation", "result_error", "${rpm_data[${index_rpmpkg}][3]}", "Post-modification hook", "${rpm_package[${index_rpmpkg}]}", "Can't executing post hook (${rpm_posthook[${index_rpmpkg}]}) for RPM package ${rpm_package[${index_rpmpkg}]} as policy ${rpm_data[${index_rpmpkg}][0]} failed"),
ifvarclass => "rpm_package_installation_${index_rpmpkg}_error.execute_command_${index_rpmpkg}";
"any" usebundle => rudder_common_report("packageInstallation", "result_success", "${rpm_data[${index_rpmpkg}][3]}", "Post-modification hook", "${rpm_package[${index_rpmpkg}]}", "No hook executed since package promise was kept"),
ifvarclass => "rpm_package_installation_${index_rpmpkg}_kept.execute_command_${index_rpmpkg}";
"any" usebundle => rudder_common_report("packageInstallation", "result_na", "${rpm_data[${index_rpmpkg}][3]}", "Post-modification hook", "${rpm_package[${index_rpmpkg}]}", "No post hook execution set for RPM package ${rpm_package[${index_rpmpkg}]}"),
ifvarclass => "!execute_command_${index_rpmpkg}";
# ZMD Process presence related reports
pass3.!(SuSE_10.!zypper_version_ok)::
"any" usebundle => rudder_common_report("packageInstallation", "result_na", "${rpm_data[${index_rpmpkg}][3]}", "ZMD process", "None", "ZMD process presence verification not necessary. Skipping ...");
pass3.SuSE_10.!zmd_restart.zypper_version_ok::
"any" usebundle => rudder_common_report("packageInstallation", "result_success", "${rpm_data[${index_rpmpkg}][3]}", "ZMD process", "None", "The ZMD process is present. Skipping ...");
pass3.service_restart_novell_zmd_ok.zypper_version_ok::
"any" usebundle => rudder_common_report("packageInstallation", "result_repaired", "${rpm_data[${index_rpmpkg}][3]}", "ZMD process", "None", "The ZMD daemon was successfully restarted");
pass3.service_restart_novell_zmd_not_ok.zypper_version_ok::
"any" usebundle => rudder_common_report("packageInstallation", "result_error", "${rpm_data[${index_rpmpkg}][3]}", "ZMD process", "None", "The ZMD daemon failed to restart");
processes:
SuSE_10.!zypper_version_ok::
"/usr/lib/zmd/zmd.exe"
restart_class => "zmd_restart";
commands:
"${rpm_posthook[${index_rpmpkg}]}"
classes => rudder_common_classes("rpm_posthook_${index_rpmpkg}"),
contain => in_shell,
ifvarclass => "execute_command_${index_rpmpkg}.rpm_package_installation_${index_rpmpkg}_repaired.!rpm_package_installation_${index_rpmpkg}_error";
}
body package_method generic_nobulk(rpm_pkg_timeout) {
package_version_less_command => "${rudder_rpm_knowledge.rpm_compare_less}";
package_version_equal_command => "${rudder_rpm_knowledge.rpm_compare_equal}";
package_changes => "individual";
redhat::
package_list_command => "/bin/rpm -qa --qf '%{name} %{version}-%{release} %{arch}\n'";
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}-${version}";
package_list_update_ifelapsed => "${rpm_pkg_timeout}";
package_add_command => "/usr/bin/yum -y install";
package_delete_command => "/bin/rpm -e";
package_update_command => "/usr/bin/yum -y update";
package_verify_command => "/bin/rpm -V";
zypper_version_ok::
package_list_command => "/bin/rpm -qa --queryformat \"i | repos | %{name} | %{version}-%{release} | %{arch}\n\"";
package_list_update_ifelapsed => "${rpm_pkg_timeout}";
package_installed_regex => "i.*";
package_list_name_regex => "[^|]+\|[^|]+\|\s+([^\s]+).*";
package_list_version_regex => "[^|]+\|[^|]+\|[^|]+\|\s+([^\s]+).*";
package_list_arch_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_verify_command => "/usr/bin/zypper --non-interactive verify$";
SuSE_10.!zypper_version_ok::
package_list_command => "/bin/rpm -qa --queryformat \"i | repos | %{name} | %{version}-%{release} | %{arch}\n\"";
package_list_update_ifelapsed => "${rpm_pkg_timeout}";
package_installed_regex => "i.*";
package_list_name_regex => "[^|]+\|[^|]+\|\s+([^\s]+).*";
package_list_version_regex => "[^|]+\|[^|]+\|[^|]+\|\s+([^\s]+).*";
package_list_arch_regex => "[^|]+\|[^|]+\|[^|]+\|[^|]+\|\s+([^\s]+).*";
package_name_convention => "${name}";
package_add_command => "/usr/bin/rug install -y";
package_delete_command => "/usr/bin/rug remove -y";
package_update_command => "/usr/bin/rug update -y";
package_verify_command => "/usr/bin/rug verify -y$"; # $ means no args
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
######################################################
# Configures the RUG/YaST Package Managers using ZMD #
######################################################
bundle agent check_zmd_settings
{
vars:
&TRACKINGKEY:{policyInstanceId |"zmdconf_uuid[&i&]" string => "&policyInstanceId&";
}&
proxy_edit::
"zmdconf[Network][proxy-url]" string => "&ZMD_PROXY_URL&";
proxy_edit_user::
"zmdconf[Network][proxy-username]" string => "&ZMD_PROXY_USER&";
proxy_edit_password::
"zmdconf[Network][proxy-password]" string => "&ZMD_PROXY_PASSWORD&";
class_ok::
&ZMD_URL:{zmd_url |"zmd_url[&i&]" string => "&zmd_url&";
}&
&ZMD_NAME:{zmd_name |"zmd_name[&i&]" string => "&zmd_name&";
}&
"zmd_index" slist => getindices("zmd_url");
&if(ZMD_SET_REFRESH_INTERVAL)&
"zmdconf[Server][refresh-interval]" string => "&ZMD_REFRESH_INTERVAL&";
&endif&
"zmdconf[Advanced][security-level]" string => "&ZMD_SOURCEPOLICY&";
"zmdconf[Server][remote-enabled]" string => "&ZMD_REMOTE_ENABLED&";
"zmdconf[Debug][syslog-level]" string => "&ZMD_SYSLOG_LEVEL&";
"zmd_sections" slist => getindices("zmdconf");
classes:
# Repositories edition ?
"zmd_repositories_edit" not => strcmp("&ZMD_ADDREPOSITORIES&","false");
# Disable repositories ?
"zmd_disablerepositories" not => strcmp("&ZMD_DISABLEREPOSITORIES&","false");
# Is the checkzmd script present ?
"checkzmd_present" expression => fileexists("${g.rudder_tools}/checkzmd.pl");
# Do we want to set the proxy ?
"proxy_edit" not => strcmp("&ZMD_PROXY_URL&", "");
# Do we want to set the proxy username ?
"proxy_edit_user" not => strcmp("&ZMD_PROXY_USER&", "");
# Do we want to set the proxy username ?
"proxy_edit_password" not => strcmp("&ZMD_PROXY_PASSWORD&", "");
"class_ok" expression => strcmp("true", "true");
"showtime" expression => isvariable("zmd_sections");
files:
showtime.SuSE::
"/etc/zmd/zmd.conf"
create => "true",
perms => mog("600", "root", "root"),
edit_defaults => noempty_backup,
edit_line => set_advanced_zmd_config_values("check_zmd_settings.zmdconf", "${zmd_sections}"),
classes => kept_if_else("zmd_conf_kept", "zmd_conf_validated", "zmd_conf_failed");
processes:
"/usr/lib/zmd/zmd.exe"
restart_class => "zmd_restart";
commands:
showtime.SuSE.checkzmd_present::
"${g.rudder_tools}/checkzmd.pl \"${zmd_name[${zmd_index}]}\" \"${zmd_url[${zmd_index}]}\" ${zmd_index}"
contain => in_shell,
module => "true",
comment => "Analyzing ZMD's output";
showtime.SuSE.zmd_repositories_edit::
"/usr/bin/rug"
args => "sa --type=zypp \"${zmd_url[${zmd_index}]}\" \"${zmd_name[${zmd_index}]}\"",
ifvarclass => "index_${zmd_index}_not_matched",
classes => kept_if_else("source_${zmd_index}_kept", "source_${zmd_index}_added", "source_${zmd_index}_failed"),
comment => "Add the ${zmd_index} as a new source";
"/usr/bin/rug"
args => "subscribe \"${zmd_name[${zmd_index}]}\"",
ifvarclass => "source_${zmd_index}_added",
classes => kept_if_else("source_${zmd_index}_subkept", "source_${zmd_index}_subscribed", "source_${zmd_index}_subfailed"),
comment => "Subscribe ${zmd_index} as a new source";
showtime.SuSE.(zmd_restart|zmd_conf_validated)::
"/etc/init.d/novell-zmd"
args => "restart",
classes => kept_if_else("zmd_kept", "zmd_restarted", "could_not_restart_zmd"),
comment => "Restart the ZMD daemon";
reports:
# ZMD settings edition
zmd_conf_kept::
"@@zmdPackageManagerSettings@@result_success@@${zmdconf_uuid[${zmd_index}]}@@General settings@@None@@${g.execRun}##${g.uuid}@#ZMD settings were all already correct";
zmd_conf_validated::
"@@zmdPackageManagerSettings@@result_repaired@@${zmdconf_uuid[${zmd_index}]}@@General settings@@None@@${g.execRun}##${g.uuid}@#Some ZMD settings were reset";
zmd_conf_failed::
"@@zmdPackageManagerSettings@@result_error@@${zmdconf_uuid[${zmd_index}]}@@General settings@@None@@${g.execRun}##${g.uuid}@#ZMD repositories could not be edited";
"@@zmdPackageManagerSettings@@result_error@@&TRACKINGKEY&@@General settings@@None@@${g.execRun}##${g.uuid}@#ZMD repositories could not be edited";
# Ignore non-SuSE OSes
!SuSE::
"@@zmdPackageManagerSettings@@result_error@@${zmdconf_uuid[${zmd_index}]}@@zmdPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#ZMD cannot be configured on non SuSE OSes";
SuSE::
# Repositories
"@@zmdPackageManagerSettings@@result_success@@${zmdconf_uuid[${zmd_index}]}@@Repository@@${zmd_url[${zmd_index}]}@@${g.execRun}##${g.uuid}@#The ZMD source ${zmd_name[${zmd_index}]} is not here but no edition required. Skipping..."
ifvarclass => "index_${zmd_index}_not_matched.!zmd_repositories_edit";
"@@zmdPackageManagerSettings@@result_success@@${zmdconf_uuid[${zmd_index}]}@@Repository@@${zmd_url[${zmd_index}]}@@${g.execRun}##${g.uuid}@#The ZMD source ${zmd_name[${zmd_index}]} was already here. Skipping..."
ifvarclass => "index_${zmd_index}_matched.!source_${zmd_index}_subscribed";
"@@zmdPackageManagerSettings@@result_repaired@@${zmdconf_uuid[${zmd_index}]}@@Repository@@${zmd_url[${zmd_index}]}@@${g.execRun}##${g.uuid}@#The ZMD source ${zmd_name[${zmd_index}]} has been successfully added"
ifvarclass => "index_${zmd_index}_not_matched.source_${zmd_index}_subscribed";
"@@zmdPackageManagerSettings@@result_error@@${zmdconf_uuid[${zmd_index}]}@@Repository@@${zmd_url[${zmd_index}]}@@${g.execRun}##${g.uuid}@#The ZMD source ${zmd_name[${zmd_index}]} was NOT added : Could not register the source !"
ifvarclass => "source_${zmd_index}_failed";
"@@zmdPackageManagerSettings@@result_error@@${zmdconf_uuid[${zmd_index}]}@@Repository@@${zmd_url[${zmd_index}]}@@${g.execRun}##${g.uuid}@#The ZMD source ${zmd_name[${zmd_index}]} was NOT added : Could not subscribe to the source !"
ifvarclass => "source_${zmd_index}_subfailed";
# ZMD Process presence related reports
SuSE.!zmd_restart::
"@@zmdPackageManagerSettings@@result_success@@${zmdconf_uuid[${zmd_index}]}@@ZMD process@@None@@${g.execRun}##${g.uuid}@#The ZMD process is present. Skipping ...";
SuSE.zmd_restarted::
"@@zmdPackageManagerSettings@@result_repaired@@${zmdconf_uuid[${zmd_index}]}@@ZMD process@@None@@${g.execRun}##${g.uuid}@#The ZMD daemon was successfully restarted";
SuSE.could_not_restart_zmd::
"@@zmdPackageManagerSettings@@result_error@@${zmdconf_uuid[${zmd_index}]}@@ZMD process@@None@@${g.execRun}##${g.uuid}@#The ZMD daemon failed to restart";
}
bundle edit_line set_advanced_zmd_config_values(tab, sectionName)
{
# 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 an associative array containing tab[SectionName][LHS]="RHS"
# don't change value when the RHS is dontchange
# Based on set_variable_values from cfengine_stdlib.cf, modified to
# use section to define were to write, and to handle commented-out lines.
# CAUTION : for it to work nicely, you should use Cfengine with the commit n°3229
# otherwise you may risk a segfault
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");
field_edits:
# If the line is there, but commented out, first uncomment it
"#+${index}=.*"
select_region => INI_section("${sectionName}"),
edit_field => col("=","1","${index}","set"),
ifvarclass => "edit_${cindex[${index}]}";
# match a line starting like the key something
"${index}=.*"
edit_field => col("=","2","${${tab}[${sectionName}][${index}]}","set"),
select_region => INI_section("${sectionName}"),
classes => if_ok("not_${cindex[${index}]}"),
ifvarclass => "edit_${cindex[${index}]}";
insert_lines:
"[${sectionName}]"
location => start;
"${index}=${${tab}[${sectionName}][${index}]}"
select_region => INI_section("${sectionName}"),
ifvarclass => "!not_${cindex[${index}]}.edit_${cindex[${index}]}";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
######################################################
# Configures the Zypper repositories #
######################################################
bundle agent zypper_repositories_management
{
vars:
&ZYPPER_REPO_NAME:{zypper_name |"zypper_name[&i&]" string => "&zypper_name&";
}&
&ZYPPER_REPO_URL:{zypper_url |"zypper_url[&i&]" string => "&zypper_url&";
}&
&ZYPPER_REPO_TYPE:{zypper_type |"zypper_type[&i&]" string => "&zypper_type&";
}&
&ZYPPER_REPO_ENABLED:{zypper_enabled |"zypper_enabled[&i&]" string => "&zypper_enabled&";
}&
&ZYPPER_REPO_AUTOREFRESH:{zypper_autorefresh |"zypper_autorefresh[&i&]" string => "&zypper_autorefresh&";
}&
&TRACKINGKEY:{directiveId |"zypper_uuid[&i&]" string => "&directiveId&";
}&
# List of all the files to permit deletion of others repos
"zypper_files" slist => { &ZYPPER_REPO_NAME: { "rudder-&it&.repo" };separator=", "&};
"zypper_index" slist => getindices("zypper_name");
"zypper_reports_value" slist => getvalues("zypper_uuid");
classes:
# Disable repositories if the value of the variable start by true
# Since variable is unique, it can contain only one value, however, it is repeated
# as many time as there are instance of the directive, rendering the strcmp unusable in this case
"zypper_disable_other_repositories" expression => regcmp("true.*", "&ZYPPER_REPO_DISABLE_OTHER_REPOSITORIES&");
files:
SuSE::
"/etc/zypp/repos.d/rudder-${zypper_name[${zypper_index}]}.repo"
create => "true",
perms => m("644"),
edit_line => configure_zypper_repos("${zypper_name[${zypper_index}]}", "${zypper_url[${zypper_index}]}", "${zypper_enabled[${zypper_index}]}", "${zypper_type[${zypper_index}]}", "${zypper_autorefresh[${zypper_index}]}", "${sys.workdir}/inputs/zypperPackageManagerRepositories/zypper-repo.tml"),
edit_defaults => empty_backup,
classes => rudder_common_classes("zypper_repo_${zypper_index}");
SuSE.zypper_disable_other_repositories::
"/etc/zypp/repos.d/.*"
delete => tidy,
file_select => ex_list("@{zypper_files}"),
depth_search => recurse("inf"),
classes => rudder_common_classes("zypper_other_repos_disabled"),
comment => "Delete the unwanted repos as requested";
methods:
SuSE::
"repos_${zypper_index}" usebundle => rudder_common_reports_generic("Zypper Repositories Management", "zypper_repo_${zypper_index}", "${zypper_uuid[${zypper_index}]}", "Repositories", "${zypper_name[${zypper_index}]}", "Repository ${zypper_name[${zypper_index}]}");
!SuSE::
"repos_${zypper_index}" usebundle => rudder_common_report("Zypper Repositories Management", "result_na", "${zypper_uuid[${zypper_index}]}", "Repositories", "${zypper_name[${zypper_index}]}", "Repository ${zypper_name[${zypper_index}]} can only be added on SUSE/SLES systems");
# we must report on the deletion of other reports for all instances of the directives
SuSE.zypper_disable_other_repositories::
"deletion_${zypper_reports_value}" usebundle => rudder_common_reports_generic("Zypper Repositories Management", "zypper_other_repos_disabled", "${zypper_reports_value}", "Purge other repositories", "None", "Deletion of others repositories");
# For deletion of others repos, if there is effectively no others files in the folders, then
# CFEngine will not define any classes at all: since there is nothing to promise on, there
# is no outcome.
# So, if disable_other_repositories is defined, but no any zypper_other_repos_disabled classes,
# we must consider the promise to be kept
"deletion_${zypper_reports_value}"
usebundle => rudder_common_report("Zypper Repositories Management", "result_success", "${zypper_reports_value}", "Purge other repositories", "None", "Every repository other than the defined ones were already disable"),
ifvarclass => "!zypper_other_repos_disabled_kept.!zypper_other_repos_disabled_repaired.!zypper_other_repos_disabled_error";
SuSE.!zypper_disable_other_repositories::
"deletion_${zypper_reports_value}" usebundle => rudder_common_report("Zypper Repositories Management", "result_na", "${zypper_reports_value}", "Purge other repositories", "None", "The repository desactivation has not been requested. Skipping...");
!SuSE::
"deletion_${zypper_reports_value}" usebundle => rudder_common_report("Zypper Repositories Management", "result_na", "${zypper_reports_value}", "Purge other repositories", "None", "Deletion of others repositories is available only on SUSE/SLES systems");
}
bundle edit_line configure_zypper_repos(zypper_name, zypper_url, zypper_enabled, zypper_type, zypper_autorefresh, template)
{
insert_lines:
"${template}"
insert_type => "file",
expand_scalars => "true";
}
${rudder_parameters.rudder_file_edit_header}
[${configure_zypper_repos.zypper_name}]
name=${configure_zypper_repos.zypper_name}
enabled=${configure_zypper_repos.zypper_enabled}
autorefresh=${configure_zypper_repos.zypper_autorefresh}
baseurl=${configure_zypper_repos.zypper_url}
type=${configure_zypper_repos.zypper_type}
keeppackages=0
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
######################################################
# Configures the Zypper Package Manager #
######################################################
bundle agent check_zypper_settings
{
vars:
&ZYPPER_NAME:{zypper_name |"zypper_name[&i&]" string => "&zypper_name&";
}&
&ZYPPER_URL:{zypper_url |"zypper_url[&i&]" string => "&zypper_url&";
}&
&ZYPPER_TYPE:{zypper_type |"zypper_type[&i&]" string => "&zypper_type&";
}&
&ZYPPER_ENABLED:{zypper_enabled |"zypper_enabled[&i&]" string => "&zypper_enabled&";
}&
&TRACKINGKEY:{policyInstanceId |"zypper_uuid[&i&]" string => "&policyInstanceId&";
}&
# List of all the files to permit on the vhost directory
"zypper_files" slist => { &ZYPPER_NAME: { "rudder-&it&.repo" };separator=", "&};
"zypper_index" slist => getindices("zypper_name");
"zmdconf[main][solver.onlyRequires]" string => "&ZYPPER_INSTALLRECOMMENDS&";
"zypper_sections" slist => getindices("zmdconf");
classes:
# Repositories edition ?
"zypper_repositories_edit" expression => strcmp("&ZYPPER_ADDREPOSITORIES&","true");
# Disable repositories ?
"zypper_disablerepositories" not => strcmp("&ZYPPER_DISABLEREPOSITORIES&","false");
files:
SuSE::
"/etc/zypp/zypp.conf"
create => "true",
perms => mog("644", "root", "root"),
edit_defaults => noempty_backup,
edit_line => set_advanced_zypper_config_values("check_zypper_settings.zmdconf", "${zypper_sections}"),
classes => kept_if_else("zypper_conf_kept", "zypper_conf_validated", "zypper_conf_failed");
SuSE.zypper_repositories_edit::
#"/etc/zypp/repos.d/rudder-defined.repo"
# create => "true",
# perms => m("644"),
# edit_line => set_zypper_repos("check_zypper_settings.zypper_name", "check_zypper_settings.zypper_url", "check_zypper_settings.zypper_enabled", "check_zypper_settings.zypper_type"),
# edit_defaults => empty_backup,
# classes => kept_if_else("zypper_tier1_kept", "zypper_tier1_validated", "zypper_tier1_failed");
"/etc/zypp/repos.d/rudder-${zypper_name[${zypper_index}]}.repo"
create => "true",
perms => m("644"),
edit_line => set_zypper_repos("${zypper_name[${zypper_index}]}", "${zypper_url[${zypper_index}]}", "${zypper_enabled[${zypper_index}]}", "${zypper_type[${zypper_index}]}", "${g.rudder_tools}/zypper-repo.tpl"),
edit_defaults => empty_backup,
classes => kept_if_else("zypper_${zypper_index}_kept", "zypper_${zypper_index}_validated", "zypper_${zypper_index}_failed");
SuSE.zypper_disablerepositories::
"/etc/zypp/repos.d/.*"
delete => tidy,
file_select => ex_list("@{zypper_files}"),
depth_search => recurse("inf"),
classes => kept_if_else("repos_disabled_kept", "repos_disabled_ok", "repos_disabled_fail"),
comment => "Delete the unwanted repos as requested";
reports:
# ZYPPER settings edition
zypper_conf_kept.!zypper_conf_validated.!zypper_conf_failed::
"@@zypperPackageManagerSettings@@result_success@@${zypper_uuid[${zypper_index}]}@@General settings@@None@@${g.execRun}##${g.uuid}@#Zypper settings were all already correct";
zypper_conf_validated::
"@@zypperPackageManagerSettings@@result_repaired@@${zypper_uuid[${zypper_index}]}@@General settings@@None@@${g.execRun}##${g.uuid}@#Some Zypper settings were reset";
zypper_conf_failed::
"@@zypperPackageManagerSettings@@result_error@@${zypper_uuid[${zypper_index}]}@@General settings@@None@@${g.execRun}##${g.uuid}@#Zypper repositories could not be edited";
# Zypper repositories desactivation
zypper_disablerepositories.!repos_disabled_ok.!repos_disabled_fail::
"@@zypperPackageManagerSettings@@result_success@@${zypper_uuid[${zypper_index}]}@@Repository deactivation@@None@@${g.execRun}##${g.uuid}@#Every repository other than the defined ones were already disabled";
zypper_disablerepositories.repos_disabled_ok::
"@@zypperPackageManagerSettings@@result_repaired@@${zypper_uuid[${zypper_index}]}@@Repository deactivation@@None@@${g.execRun}##${g.uuid}@#Every repository other than the defined ones were disabled";
zypper_disablerepositories.repos_disabled_fail::
"@@zypperPackageManagerSettings@@result_error@@${zypper_uuid[${zypper_index}]}@@Repository deactivation@@None@@${g.execRun}##${g.uuid}@#Could not disable the other repositories!";
!zypper_disablerepositories::
"@@zypperPackageManagerSettings@@result_success@@${zypper_uuid[${zypper_index}]}@@Repository deactivation@@None@@${g.execRun}##${g.uuid}@#The repository desactivation has not been requested. Skipping...";
# Ignore non-SuSE OSes
!SuSE::
"@@zypperPackageManagerSettings@@result_error@@${zypper_uuid[${zypper_index}]}@@zypperPackageManagerSettings@@None@@${g.execRun}##${g.uuid}@#ZYPPER cannot be configured on non SuSE OSes";
!zypper_repositories_edit::
"@@zypperPackageManagerSettings@@result_success@@${zypper_uuid[${zypper_index}]}@@Repository@@${zypper_name[${zypper_index}]}@@${g.execRun}##${g.uuid}@#The source ${zypper_name[${zypper_index}]} will NOT be added as the repository addition parameter is off in the Policy Instance. Skipping...";
SuSE::
# Repositories
"@@zypperPackageManagerSettings@@result_success@@${zypper_uuid[${zypper_index}]}@@Repository@@${zypper_name[${zypper_index}]}@@${g.execRun}##${g.uuid}@#The Zypper source ${zypper_name[${zypper_index}]} was already here. Skipping..."
ifvarclass => "zypper_${zypper_index}_kept.!zypper_${zypper_index}_validated";
"@@zypperPackageManagerSettings@@result_repaired@@${zypper_uuid[${zypper_index}]}@@Repository@@${zypper_name[${zypper_index}]}@@${g.execRun}##${g.uuid}@#The Zypper source ${zypper_name[${zypper_index}]} has been successfully added"
ifvarclass => "zypper_${zypper_index}_validated";
"@@zypperPackageManagerSettings@@result_error@@${zypper_uuid[${zypper_index}]}@@Repository@@${zypper_name[${zypper_index}]}@@${g.execRun}##${g.uuid}@#The Zypper source ${zypper_name[${zypper_index}]} was NOT added!"
ifvarclass => "zypper_${zypper_index}_error";
}
bundle edit_line set_zypper_repos(zypper_name, zypper_url, zypper_enabled, zypper_type, template)
{
insert_lines:
"${template}"
insert_type => "file",
expand_scalars => "true";
}
bundle edit_line set_zypper_repos_BROKEN(zypper_name, zypper_url, zypper_enabled, zypper_type)
{
vars:
"zypper_index" slist => getindices("${zypper_name}");
insert_lines:
"${rudder_parameters.rudder_file_edit_header}"
location => start,
insert_type => "preserve_block";
"[${${zypper_name}[${zypper_index}]}]"
classes => kept_if_else("source_${zypper_index}_kept", "source_${zypper_index}_ok", "source_${zypper_index}_failed");
"name=${${zypper_name}[${zypper_index}]}"
select_region => INI_section("${${zypper_name}[${zypper_index}]}"),
classes => kept_if_else("source_${zypper_index}_kept", "source_${zypper_index}_ok", "source_${zypper_index}_failed");
"enabled=${${zypper_enabled}[${zypper_index}]}"
select_region => INI_section("${${zypper_name}[${zypper_index}]}"),
classes => kept_if_else("source_${zypper_index}_kept", "source_${zypper_index}_ok", "source_${zypper_index}_failed");
"autorefresh=0"
select_region => INI_section("${${zypper_name}[${zypper_index}]}"),
classes => kept_if_else("source_${zypper_index}_kept", "source_${zypper_index}_ok", "source_${zypper_index}_failed");
"baseurl=${${zypper_url}[${zypper_index}]}"
select_region => INI_section("${${zypper_name}[${zypper_index}]}"),
classes => kept_if_else("source_${zypper_index}_kept", "source_${zypper_index}_ok", "source_${zypper_index}_failed");
"type=${${zypper_type}[${zypper_index}]}"
select_region => INI_section("${${zypper_name}[${zypper_index}]}"),
classes => kept_if_else("source_${zypper_index}_kept", "source_${zypper_index}_ok", "source_${zypper_index}_failed");
"keeppackages=0"
select_region => INI_section("${${zypper_name}[${zypper_index}]}"),
classes => kept_if_else("source_${zypper_index}_kept", "source_${zypper_index}_ok", "source_${zypper_index}_failed");
reports:
# Repositories
"@@zypperPackageManagerSettings@@result_success@@${zypper_uuid[${zypper_index}]}@@Repository@@${zypper_url[${zypper_index}]}@@${g.execRun}##${g.uuid}@#The ZYPPER source ${zypper_name[${zypper_index}]} was already here. Skipping..."
ifvarclass => "source_${zypper_index}_kept.!source_${zypper_index}_ok";
"@@zypperPackageManagerSettings@@result_repaired@@${zypper_uuid[${zypper_index}]}@@Repository@@${zypper_url[${zypper_index}]}@@${g.execRun}##${g.uuid}@#The ZYPPER source ${zypper_name[${zypper_index}]} has been successfully added"
ifvarclass => "source_${zypper_index}_ok";
"@@zypperPackageManagerSettings@@result_error@@${zypper_uuid[${zypper_index}]}@@Repository@@${zypper_url[${zypper_index}]}@@${g.execRun}##${g.uuid}@#The ZYPPER source ${zypper_name[${zypper_index}]} was NOT added!"
ifvarclass => "source_${zypper_index}_failed";
}
bundle edit_line set_advanced_zypper_config_values(tab, sectionName)
{
# 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 an associative array containing tab[SectionName][LHS]="RHS"
# don't change value when the RHS is dontchange
# Based on set_variable_values from cfengine_stdlib.cf, modified to
# use section to define were to write, and to handle commented-out lines.
# CAUTION : for it to work nicely, you should use Cfengine with the commit n°3229
# otherwise you may risk a segfault
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");
field_edits:
# If the line is there, but commented out, first uncomment it
"#+${index}=.*"
select_region => INI_section("${sectionName}"),
edit_field => col("=","1","${index}","set"),
ifvarclass => "edit_${cindex[${index}]}";
# match a line starting like the key something
"${index}=.*"
edit_field => col("=","2","${${tab}[${sectionName}][${index}]}","set"),
select_region => INI_section("${sectionName}"),
classes => if_ok("not_${cindex[${index}]}"),
ifvarclass => "edit_${cindex[${index}]}";
insert_lines:
"${index}=${${tab}[${sectionName}][${index}]}"
select_region => INI_section("${sectionName}"),
ifvarclass => "!not_${cindex[${index}]}.edit_${cindex[${index}]}";
}
body file_select not_rudderzypperrepo
{
leaf_name => { "^[^rudder-defined.*?\.repo].*" };
file_result => "leaf_name";
}
#####################################################################################
# Copyright 2014 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
######################################################
# Setups the Zypper Package Manager #
######################################################
bundle agent zypper_package_manager_setup
{
vars:
"directive_id" string => "&TRACKINGKEY&";
"zmdconf[main][solver.onlyRequires]" string => "&ZYPPER_INSTALLRECOMMENDS&";
"zypper_sections" slist => getindices("zmdconf");
"class_prefix" string => "zypper_package_manager_setup";
classes:
files:
SuSE::
"/etc/zypp/zypp.conf"
create => "true",
perms => mog("644", "root", "root"),
edit_defaults => noempty_backup,
edit_line => set_variable_values_ini("zypper_package_manager_setup.zmdconf", "${zypper_sections}"),
classes => rudder_common_classes("${class_prefix}");
methods:
SuSE::
"suse" usebundle => rudder_common_reports_generic("Zypper package manager setup", "${class_prefix}", "${directive_id}", "General settings", "None", "The Zypper package manager setup");
!SuSE::
"not applicable" usebundle => rudder_common_report("Zypper package manager setup", "result_na", "${directive_id}", "General settings", "None", "The Zypper package manager setup is not applicable on this system");
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#################################################################
# Manage files and folders, enforcing their existence #
#################################################################
bundle agent manageFilesAndFolders {
vars:
&FILE_AND_FOLDER_MANAGEMENT_PATH:{path |"file[&i&][path]" string => "&path&";
}&
&FILE_AND_FOLDER_MANAGEMENT_PERM:{perm |"file[&i&][mode]" string => "&perm&";
}&
&FILE_AND_FOLDER_MANAGEMENT_OWNER:{owner |"file[&i&][owner]" string => "&owner&";
}&
&FILE_AND_FOLDER_MANAGEMENT_GROUP:{group |"file[&i&][group]" string => "&group&";
}&
&FILE_AND_FOLDER_MANAGEMENT_POST_HOOK_COMMAND:{cmd |"file[&i&][post_hook_command]" string => "&cmd&";
}&
&FILE_AND_FOLDER_MANAGEMENT_SYMLINK_SOURCE:{src |"file[&i&][source]" string => "&src&";
}&
&FILE_AND_FOLDER_MANAGEMENT_SYMLINK_ENFORCE:{symlink_enforced | "file[&i&][symlink_enforced]" string => "&symlink_enforced&";
}&
&FILE_AND_FOLDER_MANAGEMENT_RECURSIVE:{recursive |"file[&i&][recursive]" string => "&recursive&";
}&
&FILE_AND_FOLDER_DELETION_DAYS:{ttl |"file[&i&][ttl]" string => "&ttl&";
}&
&FILE_AND_FOLDER_DELETION_PATTERN:{pattern |"file[&i&][pattern]" string => "&pattern&";
}&
&TRACKINGKEY:{directiveId |"file[&i&][uuid]" string => "&directiveId&";
}&
"index" slist => getindices("file");
iteration_1::
"extended_modes_${index}"
string => "4",
ifvarclass => "enable_suid_${index}.!enable_sgid_${index}";
"extended_modes_${index}"
string => "2",
ifvarclass => "!enable_suid_${index}.enable_sgid_${index}";
"extended_modes_${index}"
string => "6",
ifvarclass => "enable_suid_${index}.enable_sgid_${index}";
"extended_modes_${index}"
string => "0",
ifvarclass => "!enable_suid_${index}.!enable_sgid_${index}";
classes:
# Set a class to define when we need to run the post-modification hook
&FILE_AND_FOLDER_MANAGEMENT_POST_HOOK_RUN:{run |"manageFilesAndFolders_post_hook_run_&i&" expression => strcmp("&run&", "true");
}&
&FILE_AND_FOLDER_MANAGEMENT_CHECK_PERMISSIONS:{perms |"manageFilesAndFolders_check_permissions_&i&" expression => strcmp("&perms&", "true");
}&
&FILE_AND_FOLDER_MANAGEMENT_ACTION:{nocreate | "manageFilesAndFolders_nocreate_&i&" expression => strcmp("&nocreate&", "none");
}&
&FILE_AND_FOLDER_MANAGEMENT_ACTION:{createfile | "manageFilesAndFolders_createfile_&i&" expression => strcmp("&createfile&", "file");
}&
&FILE_AND_FOLDER_MANAGEMENT_ACTION:{createdir | "manageFilesAndFolders_createdir_&i&" expression => strcmp("&createdir&", "dir");
}&
&FILE_AND_FOLDER_MANAGEMENT_ACTION:{copy | "manageFilesAndFolders_local_cp_&i&" expression => strcmp("&copy&", "copy");
}&
&FILE_AND_FOLDER_MANAGEMENT_ACTION:{createsymlink | "manageFilesAndFolders_createsymlink_&i&" expression => strcmp("&createsymlink&", "symlink");
}&
&FILE_AND_FOLDER_MANAGEMENT_ACTION:{clean | "manageFilesAndFolders_clean_&i&" expression => strcmp("&clean&", "clean");
}&
&FILE_AND_FOLDER_MANAGEMENT_RECURSIVE:{isrecursive | "manageFilesAndFolders_isrecursive_&i&" expression => strcmp("&isrecursive&", "inf");
}&
&FILE_AND_FOLDER_MANAGEMENT_OWNER:{userset | "manageFilesAndFolders_userset_&i&" expression => strcmp("&userset&", "${file[&i&][owner]}");
}&
&FILE_AND_FOLDER_MANAGEMENT_GROUP:{groupset | "manageFilesAndFolders_groupset_&i&" expression => strcmp("&groupset&", "${file[&i&][group]}");
}&
&FILE_AND_FOLDER_DELETION_OPTION:{delopt | "manageFilesAndFolders_deletion_simple_&i&" expression => strcmp("&delopt&", "none");
}&
&FILE_AND_FOLDER_DELETION_OPTION:{delopt | "manageFilesAndFolders_deletion_single_recursive_&i&" expression => strcmp("&delopt&", "single");
}&
&FILE_AND_FOLDER_DELETION_OPTION:{delopt | "manageFilesAndFolders_deletion_full_recursive_&i&" expression => strcmp("&delopt&", "full");
}&
&FILE_AND_FOLDER_DELETION_OPTION:{delopt | "manageFilesAndFolders_deletion_exterminate_&i&" expression => strcmp("&delopt&", "exterminate");
}&
&FILE_AND_FOLDER_MANAGEMENT_SUID:{suid |"enable_suid_&i&" expression => strcmp("&suid&", "true");
}&
&FILE_AND_FOLDER_MANAGEMENT_SGID:{sgid |"enable_sgid_&i&" expression => strcmp("&sgid&", "true");
}&
"manageFilesAndFolders_isdir_${index}" expression => isdir("${file[${index}][path]}");
"manageFilesAndFolders_isfile_${index}" expression => isplain("${file[${index}][path]}");
"manageFilesAndFolders_islink_${index}" expression => islink("${file[${index}][path]}");
"iteration_2" expression => "iteration_1";
"iteration_1" expression => "any";
files:
iteration_2::
# Directory
"${file[${index}][path]}/."
create => "true",
classes => kept_if_else("manageFolders_${index}_kept", "manageFolders_${index}_modified", "manageFolders_${index}_failed"),
comment => "Enforcing the existance of folder ${file[${index}][path]}",
ifvarclass => "(!manageFilesAndFolders_nocreate_${index}.!manageFilesAndFolders_createfile_${index}.manageFilesAndFolders_createdir_${index}).!manageFilesAndFolders_local_cp_${index}.!manageFilesAndFolders_createsymlink_${index}";
# File
"${file[${index}][path]}"
create => "true",
classes => kept_if_else("manageFiles_${index}_kept", "manageFiles_${index}_modified", "manageFiles_${index}_failed"),
comment => "Enforcing the existance of file ${file[${index}][path]}",
ifvarclass => "(!manageFilesAndFolders_nocreate_${index}.!manageFilesAndFolders_createdir_${index}.manageFilesAndFolders_createfile_${index}).!manageFilesAndFolders_local_cp_${index}.!manageFilesAndFolders_createsymlink_${index}";
# Local copy
"${file[${index}][path]}"
copy_from => backup_local_cp("${file[${index}][source]}"),
classes => kept_if_else("manageCp_${index}_kept", "manageCp_${index}_modified", "manageCp_${index}_failed"),
ifvarclass => "(!manageFilesAndFolders_nocreate_${index}.!manageFilesAndFolders_createdir_${index}.!manageFilesAndFolders_createfile_${index}).manageFilesAndFolders_local_cp_${index}.!manageFilesAndFolders_createsymlink_${index}",
comment => "Create ${file[${index}][path]} file as copy of ${file[${index}][source]}";
# Symlink
"${file[${index}][path]}"
# create => "true",
link_from => ln_s("${file[${index}][source]}"),
move_obstructions => "${file[${index}][symlink_enforced]}",
classes => kept_if_else("manageSyms_${index}_kept", "manageSyms_${index}_modified", "manageSyms_${index}_failed"),
ifvarclass => "(!manageFilesAndFolders_nocreate_${index}.!manageFilesAndFolders_createdir_${index}.!manageFilesAndFolders_createfile_${index}).!manageFilesAndFolders_local_cp_${index}.manageFilesAndFolders_createsymlink_${index}",
comment => "Create the ${file[${index}][path]} symlink pointing to ${file[${index}][source]}";
# Check the permissions none recursively
## With user and group
"${file[${index}][path]}"
perms => mog("${extended_modes_${index}}${file[${index}][mode]}", "${file[${index}][owner]}", "${file[${index}][group]}"),
classes => kept_if_else("manageFilesAndFolders_perms_${index}_kept", "manageFilesAndFolders_perms_${index}_modified", "manageFilesAndFolders_perms_${index}_failed"),
ifvarclass => "manageFilesAndFolders_check_permissions_${index}.!manageFilesAndFolders_isrecursive_${index}.manageFilesAndFolders_userset_${index}.manageFilesAndFolders_groupset_${index}";
## With user
"${file[${index}][path]}"
perms => mo("${extended_modes_${index}}${file[${index}][mode]}", "${file[${index}][owner]}"),
classes => kept_if_else("manageFilesAndFolders_perms_${index}_kept", "manageFilesAndFolders_perms_${index}_modified", "manageFilesAndFolders_perms_${index}_failed"),
ifvarclass => "manageFilesAndFolders_check_permissions_${index}.!manageFilesAndFolders_isrecursive_${index}.manageFilesAndFolders_userset_${index}.!manageFilesAndFolders_groupset_${index}";
## With group
"${file[${index}][path]}"
perms => mg("${extended_modes_${index}}${file[${index}][mode]}", "${file[${index}][group]}"),
classes => kept_if_else("manageFilesAndFolders_perms_${index}_kept", "manageFilesAndFolders_perms_${index}_modified", "manageFilesAndFolders_perms_${index}_failed"),
ifvarclass => "manageFilesAndFolders_check_permissions_${index}.!manageFilesAndFolders_isrecursive_${index}.manageFilesAndFolders_groupset_${index}.!manageFilesAndFolders_userset_${index}";
# Check the permissions recursively
## With user and group
"${file[${index}][path]}"
depth_search => recurse_withroot("${file[${index}][recursive]}"),
perms => mog("${extended_modes_${index}}${file[${index}][mode]}", "${file[${index}][owner]}", "${file[${index}][group]}"),
classes => kept_if_else("manageFilesAndFolders_perms_${index}_kept", "manageFilesAndFolders_perms_${index}_modified", "manageFilesAndFolders_perms_${index}_failed"),
ifvarclass => "manageFilesAndFolders_check_permissions_${index}.manageFilesAndFolders_isrecursive_${index}.manageFilesAndFolders_userset_${index}.manageFilesAndFolders_groupset_${index}";
## With user
"${file[${index}][path]}"
depth_search => recurse_withroot("${file[${index}][recursive]}"),
perms => mo("${extended_modes_${index}}${file[${index}][mode]}", "${file[${index}][owner]}"),
classes => kept_if_else("manageFilesAndFolders_perms_${index}_kept", "manageFilesAndFolders_perms_${index}_modified", "manageFilesAndFolders_perms_${index}_failed"),
ifvarclass => "manageFilesAndFolders_check_permissions_${index}.manageFilesAndFolders_isrecursive_${index}.manageFilesAndFolders_userset_${index}.!manageFilesAndFolders_groupset_${index}";
## With group
"${file[${index}][path]}"
depth_search => recurse_withroot("${file[${index}][recursive]}"),
perms => mg("${extended_modes_${index}}${file[${index}][mode]}", "${file[${index}][group]}"),
classes => kept_if_else("manageFilesAndFolders_perms_${index}_kept", "manageFilesAndFolders_perms_${index}_modified", "manageFilesAndFolders_perms_${index}_failed"),
ifvarclass => "manageFilesAndFolders_check_permissions_${index}.manageFilesAndFolders_isrecursive_${index}.manageFilesAndFolders_groupset_${index}.!manageFilesAndFolders_userset_${index}";
# This will not delete the parent
"${file[${index}][path]}"
delete => tidy,
file_select => date_pattern("${file[${index}][ttl]}", "${file[${index}][pattern]}"),
ifvarclass => "manageFilesAndFolders_clean_${index}.manageFilesAndFolders_deletion_single_recursive_${index}",
depth_search => recurse("0"),
classes => kept_if_else("manageFilesAndFolders_delete_${index}_kept", "manageFilesAndFolders_delete_${index}_modified", "manageFilesAndFolders_delete_${index}_failed");
# This will not delete the parent
"${file[${index}][path]}"
delete => tidy,
file_select => date_pattern("${file[${index}][ttl]}", "${file[${index}][pattern]}"),
depth_search => recurse("inf"),
ifvarclass => "manageFilesAndFolders_clean_${index}.(manageFilesAndFolders_deletion_full_recursive_${index}|manageFilesAndFolders_deletion_exterminate_${index})",
classes => kept_if_else("manageFilesAndFolders_delete_${index}_kept", "manageFilesAndFolders_delete_${index}_modified", "manageFilesAndFolders_delete_${index}_failed");
# This WILL delete the parent
"${file[${index}][path]}"
delete => tidy,
file_select => date_pattern("${file[${index}][ttl]}", "${file[${index}][pattern]}"),
ifvarclass => "manageFilesAndFolders_clean_${index}.(manageFilesAndFolders_deletion_simple_${index}|manageFilesAndFolders_deletion_exterminate_${index})",
classes => kept_if_else("manageFilesAndFolders_delete_${index}_kept", "manageFilesAndFolders_delete_${index}_modified", "manageFilesAndFolders_delete_${index}_failed");
commands:
"${file[${index}][post_hook_command]}"
classes => if_else("manageFilesAndFolders_${index}_command_run_ok", "manageFilesAndFolders_${index}_command_run_failed"),
contain => in_shell,
ifvarclass => "manageFilesAndFolders_post_hook_run_${index}.(manageFiles_${index}_modified|manageFolders_${index}_modified|manageCp_${index}_modified|manageSyms_${index}_modified|manageFilesAndFolders_perms_${index}_modified)";
reports:
(linux|windows)::
# Reporting for creation
## Reporting for directory creation
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The folder ${file[${index}][path]} already exists"
ifvarclass => "manageFolders_${index}_kept.!manageFolders_${index}_modified.manageFilesAndFolders_isdir_${index}.!manageFilesAndFolders_isfile_${index}.!manageFilesAndFolders_islink_${index}";
"@@manageFilesAndFolders@@result_repaired@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The folder ${file[${index}][path]} was successfully created"
ifvarclass => "manageFolders_${index}_modified";
"@@manageFilesAndFolders@@result_error@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The folder ${file[${index}][path]} could not be created"
ifvarclass => "manageFolders_${index}_failed|manageFolders_${index}_kept.(manageFilesAndFolders_isfile_${index}|manageFilesAndFolders_islink_${index})";
## Reporting for file creation
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The file ${file[${index}][path]} already exists"
ifvarclass => "manageFiles_${index}_kept.!manageFiles_${index}_modified.manageFilesAndFolders_isfile_${index}.!manageFilesAndFolders_isdir_${index}.!manageFilesAndFolders_islink_${index}";
"@@manageFilesAndFolders@@result_repaired@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The file ${file[${index}][path]} was successfully created"
ifvarclass => "manageFiles_${index}_modified";
"@@manageFilesAndFolders@@result_error@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The file ${file[${index}][path]} could not be created"
ifvarclass => "manageFiles_${index}_failed|manageFiles_${index}_kept.(manageFilesAndFolders_isdir_${index}|manageFilesAndFolders_islink_${index})";
## Reporting for local cp
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The file ${file[${index}][path]} already exists and is up to date"
ifvarclass => "manageCp_${index}_kept.!manageCp_${index}_modified.manageFilesAndFolders_isfile_${index}.!manageFilesAndFolders_isdir_${index}.!manageFilesAndFolders_islink_${index}";
"@@manageFilesAndFolders@@result_repaired@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The file ${file[${index}][path]} was successfully copied from ${file[${index}][source]}"
ifvarclass => "manageCp_${index}_modified";
"@@manageFilesAndFolders@@result_error@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The file ${file[${index}][path]} could not be created"
ifvarclass => "manageCp_${index}_failed|manageCp_${index}_kept.(manageFilesAndFolders_isdir_${index}|manageFilesAndFolders_islink_${index})";
## Reporting for symlink creation
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The symlink ${file[${index}][path]} already exists"
ifvarclass => "manageSyms_${index}_kept.!manageSyms_${index}_modified";
"@@manageFilesAndFolders@@result_repaired@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The symlink ${file[${index}][path]} was successfully created"
ifvarclass => "manageSyms_${index}_modified";
"@@manageFilesAndFolders@@result_error@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The symlink ${file[${index}][path]} could not be created"
ifvarclass => "manageSyms_${index}_failed";
## Reporting for no change
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#No file creation action specified for ${file[${index}][path]}"
ifvarclass => "manageFilesAndFolders_nocreate_${index}";
# Reporting for the permissions
## Success if not set
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@Permissions@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The item ${file[${index}][path]} was not requested to have its permission enforced"
ifvarclass => "!manageFilesAndFolders_check_permissions_${index}";
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@Permissions@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The permission of the item ${file[${index}][path]} were correct"
ifvarclass => "manageFilesAndFolders_perms_${index}_kept.!manageFilesAndFolders_perms_${index}_modified";
"@@manageFilesAndFolders@@result_repaired@@${file[${index}][uuid]}@@Permissions@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The permissions of the item ${file[${index}][path]} have been corrected"
ifvarclass => "manageFilesAndFolders_perms_${index}_modified.!manageFilesAndFolders_perms_${index}_failed";
"@@manageFilesAndFolders@@result_error@@${file[${index}][uuid]}@@Permissions@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The permissions of the item ${file[${index}][path]} could not be set"
ifvarclass => "manageFilesAndFolders_perms_${index}_failed";
"@@manageFilesAndFolders@@log_info@@${file[${index}][uuid]}@@Permissions@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The item ${file[${index}][path]} will be handled recursively"
ifvarclass => "manageFilesAndFolders_check_permissions_${index}.manageFilesAndFolders_createdir_${index}.manageFilesAndFolders_recursive_${index}";
"@@manageFilesAndFolders@@log_warn@@${file[${index}][uuid]}@@Permissions@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The item ${file[${index}][path]} will NOT be handled recursively, because it is either a file or a symlink"
ifvarclass => "manageFilesAndFolders_check_permissions_${index}.!manageFilesAndFolders_createdir_${index}.manageFilesAndFolders_recursive_${index}";
# Reporting for the deletion
## Report in the general component of the file
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@File@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#File cleaning was requested for ${file[${index}][path]}. Check specific reporting in the 'File cleaning options' component."
ifvarclass => "manageFilesAndFolders_clean_${index}";
## Success if not set
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@File cleaning options@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The item ${file[${index}][path]} was not requested to be deleted"
ifvarclass => "!manageFilesAndFolders_clean_${index}";
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@File cleaning options@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The item ${file[${index}][path]} was in conformity with the deletion policy"
ifvarclass => "manageFilesAndFolders_clean_${index}.!manageFilesAndFolders_delete_${index}_modified.!manageFilesAndFolders_delete_${index}_failed";
"@@manageFilesAndFolders@@result_repaired@@${file[${index}][uuid]}@@File cleaning options@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The item ${file[${index}][path]} has been put in conformity with the deletion policy"
ifvarclass => "manageFilesAndFolders_delete_${index}_modified";
"@@manageFilesAndFolders@@result_error@@${file[${index}][uuid]}@@File cleaning options@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#The item ${file[${index}][path]} deletion policy could not be enforced"
ifvarclass => "manageFilesAndFolders_delete_${index}_failed";
# Reporting for post-command execution
"@@manageFilesAndFolders@@result_success@@${file[${index}][uuid]}@@Post-modification hook@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#Post-execution hook did not need running"
ifvarclass => "!manageFilesAndFolders_post_hook_run_${index}|((manageFiles_${index}_kept|manageFolders_${index}_kept|manageSyms_${index}_kept|manageFilesAndFolders_perms_${index}_kept).!(manageFiles_${index}_modified|manageFolders_${index}_modified|manageSyms_${index}_modified|manageFilesAndFolders_perms_${index}_modified))";
"@@manageFilesAndFolders@@result_repaired@@${file[${index}][uuid]}@@Post-modification hook@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#Post-execution hook successfully run"
ifvarclass => "manageFilesAndFolders_${index}_command_run_ok";
"@@manageFilesAndFolders@@result_error@@${file[${index}][uuid]}@@Post-modification hook@@${file[${index}][path]}@@${g.execRun}##${g.uuid}@#An error occured when running the post-execution hook"
ifvarclass => "manageFilesAndFolders_${index}_command_run_failed";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
######################################################
# Adjust file permissions #
# ####################### #
# #
# This PT adjusts file or directory permissions #
# according to user set parameters. #
######################################################
bundle agent files_permissions
{
vars:
"dim_array" int => readstringarrayidx("file","${sys.workdir}/inputs/filesPermissions/permlist","#[^\n]*",":",1024,102400);
"filePerms" slist => getindices("file");
methods:
"any" usebundle => check_permissions("${file[${filePerms}][0]}",
"${file[${filePerms}][1]}",
"${file[${filePerms}][2]}");
}
bundle agent check_permissions(directiveId, fileName, action_parameters)
{
vars:
"identifier" string => canonify("${directiveId}${fileName}");
# Splitting the action parameters
# we need to do the split in two pass, as we cannot reliably use array with more than 10 column in CFEngine 3.6
# See https://dev.cfengine.com/issues/6674
"dim_array" int => parsestringarrayidx("permission_parameters", "${action_parameters}", "\s*#[^\n]*", ";;", 10, 4096);
# directly get the content of the value for ease of use in the technique
"user" string => "${permission_parameters[0][0]}";
"group" string => "${permission_parameters[0][1]}";
"mode" string => "${permission_parameters[0][2]}";
"edit_user" string => "${permission_parameters[0][3]}";
"edit_group" string => "${permission_parameters[0][4]}";
"edit_mode" string => "${permission_parameters[0][5]}";
"suid" string => "${permission_parameters[0][6]}";
"sgid" string => "${permission_parameters[0][7]}";
"recursion" string => "${permission_parameters[0][8]}";
# See the explication below, before the "classes_defined" class definition
classes_defined.enable_suid.!enable_sgid::
"extended_modes"
string => "4";
classes_defined.!enable_suid.enable_sgid::
"extended_modes"
string => "2";
classes_defined.enable_suid.enable_sgid::
"extended_modes"
string => "6";
classes_defined.!enable_suid.!enable_sgid::
"extended_modes"
string => "0";
classes:
"file_exists" expression => fileexists(${fileName});
"user_absent" not => userexists("${user}");
"group_absent" not => groupexists("${group}");
"edit_owner" not => strcmp("${edit_user}","false");
"edit_group" not => strcmp("${edit_group}","false");
"edit_mode" not => strcmp("${edit_mode}","false");
"edit_recurse" not => strcmp("${recursion}","false");
"enable_suid" not => strcmp("${suid}","false");
"enable_sgid" not => strcmp("${sgid}","false");
"is_symlink" expression => islink("${fileName}");
# Again, normal ordering must be altered for this to work.
# This class will block variable definition as long as the other
# classes are not defined properly
"classes_defined" expression => "any";
# When ${suid_definition} exists, it means that we can now set SUID
# and SGID bits.
"can_edit_suid_sgid" expression => isvariable("extended_modes");
files:
file_exists.edit_owner.!user_absent.!edit_recurse.!is_symlink::
"${fileName}"
perms => owner("${user}"),
comment => "Setting the file owner",
classes => kept_if_else("${identifier}_owner_ok", "${identifier}_owner_repaired", "${identifier}_owner_not_repaired");
file_exists.edit_group.!group_absent.!edit_recurse.!is_symlink::
"${fileName}"
perms => group("${group}"),
comment => "Setting the file group",
classes => kept_if_else("${identifier}_group_ok", "${identifier}_group_repaired", "${identifier}_group_not_repaired");
can_edit_suid_sgid.file_exists.edit_mode.!edit_recurse.!is_symlink::
"${fileName}"
perms => m("${extended_modes}${mode}"),
comment => "Setting the file mode",
classes => kept_if_else("${identifier}_mode_ok", "${identifier}_mode_repaired", "${identifier}_mode_not_repaired");
file_exists.edit_owner.!user_absent.edit_recurse.!is_symlink::
"${fileName}"
perms => owner("${user}"),
depth_search => recurse_with_current("inf"),
comment => "Setting the file owner",
classes => kept_if_else("${identifier}_owner_ok", "${identifier}_owner_repaired", "${identifier}_owner_not_repaired");
file_exists.edit_group.!group_absent.edit_recurse.!is_symlink::
"${fileName}"
perms => group("${group}"),
depth_search => recurse_with_current("inf"),
comment => "Setting the file group",
classes => kept_if_else("${identifier}_group_ok", "${identifier}_group_repaired", "${identifier}_group_not_repaired");
file_exists.edit_mode.edit_recurse.!is_symlink::
"${fileName}"
perms => m("${mode}"),
depth_search => recurse_with_current("inf"),
comment => "Setting the file mode",
classes => kept_if_else("${identifier}_mode_ok", "${identifier}_mode_repaired", "${identifier}_mode_not_repaired");
reports:
is_symlink::
"@@FilesPermissions@@result_error@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Will not adjust permissions on ${fileName}, because it is a symlink";
!file_exists::
"@@FilesPermissions@@result_error@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#File or directory not found: ${fileName}";
user_absent::
"@@FilesPermissions@@result_error@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#The requested user (${user}) was not found on this machine: ${fileName}'s owner can't be set";
group_absent::
"@@FilesPermissions@@result_error@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#The requested group (${group}) was not found on this machine: ${fileName}'s group can't be set";
edit_recurse::
"@@FilesPermissions@@log_info@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Permissions will be applied recursively for ${fileName}";
file_exists.can_edit_suid_sgid::
# User
"@@FilesPermissions@@log_info@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Owner ${user} already matches current owner for: ${fileName}"
ifvarclass => "${identifier}_owner_ok.!${identifier}_owner_repaired";
"@@FilesPermissions@@log_repaired@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Owner reset to ${user} for: ${fileName}"
ifvarclass => "${identifier}_owner_repaired";
"@@FilesPermissions@@result_error@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Owner ${user} could not be set for: ${fileName}"
ifvarclass => "${identifier}_owner_not_repaired";
# Group
"@@FilesPermissions@@log_info@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Group ${group} already matches current group for: ${fileName}"
ifvarclass => "${identifier}_group_ok.!${identifier}_group_repaired";
"@@FilesPermissions@@log_repaired@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Group reset to ${group} for: ${fileName}"
ifvarclass => "${identifier}_group_repaired";
"@@FilesPermissions@@result_error@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Group ${group} could not be set for: ${fileName}"
ifvarclass => "${identifier}_group_not_repaired";
# Mode
"@@FilesPermissions@@log_info@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Mode ${extended_modes}${mode} already matches current mode for: ${fileName}"
ifvarclass => "${identifier}_mode_ok.!${identifier}_mode_repaired";
"@@FilesPermissions@@log_repaired@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Mode reset to ${extended_modes}${mode} for: ${fileName}"
ifvarclass => "${identifier}_mode_repaired";
"@@FilesPermissions@@result_error@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Mode ${extended_modes}${mode} could not be set for: ${fileName}"
ifvarclass => "${identifier}_mode_not_repaired";
# Final report
"@@FilesPermissions@@result_success@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Owner, group and permissions already correct for ${fileName}"
# Success if nothing in error AND nothing repaired
ifvarclass => "(!${identifier}_owner_not_repaired.!${identifier}_group_not_repaired.!${identifier}_mode_not_repaired).(!${identifier}_owner_repaired.!${identifier}_group_repaired.!${identifier}_mode_repaired)";
"@@FilesPermissions@@result_repaired@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Owner, group or permissions were fixed for: ${fileName}"
# Repaired if nothing in error AND something repaired
ifvarclass => "!${identifier}_owner_not_repaired.!${identifier}_group_not_repaired.!${identifier}_mode_not_repaired.(${identifier}_owner_repaired|${identifier}_group_repaired|${identifier}_mode_repaired)";
"@@FilesPermissions@@result_error@@${directiveId}@@File permissions@@${fileName}@@${g.execRun}##${g.uuid}@#Owner, group or permissions could not be set for: ${fileName}"
# Error if something in error
ifvarclass => "${identifier}_owner_not_repaired|${identifier}_group_not_repaired|${identifier}_mode_not_repaired";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# List of files permission
# Format of the file :
# directiveId:file:user;;group;;mode;;edituser;;editgroup;;editmode;;suid;;sgid;;recursion
&TRACKINGKEY, FILEPERMISSION_FILENAME, FILEPERMISSION_USER, FILEPERMISSION_GROUP, FILEPERMISSION_MODE, FILEPERMISSION_EDITUSER, FILEPERMISSION_EDITGROUP, FILEPERMISSION_EDITMODE, FILEPERMISSION_SUID, FILEPERMISSION_SGID, FILEPERMISSION_RECURSION:{directiveId, fileName, user, group, perm, edituser, editgroup, editperm, suid, sgid, recursion | &directiveId&:&fileName&:&user&;;&group&;;&perm&;;&edituser&;;&editgroup&;;&editperm&;;&suid&;;&sgid&;;&recursion&
}&
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#################################################################
# Checks if a file matches a given content. If not, updates it. #
#################################################################
bundle agent check_generic_file_content {
vars:
tier1::
&GENERIC_FILE_CONTENT_PATH:{path |"generic_file_content_path[&i&]" string => "&path&";
}&
&GENERIC_FILE_CONTENT_OWNER:{owner |"generic_file_content_owner[&i&]" string => "&owner&";
}&
&GENERIC_FILE_CONTENT_GROUP:{group |"generic_file_content_group[&i&]" string => "&group&";
}&
&GENERIC_FILE_CONTENT_PERM:{perms |"generic_file_content_perms[&i&]" string => "&perms&";
}&
# Because the stupid StringTemplate systems passes the indentation as-is inside the generated variable
&GENERIC_FILE_CONTENT_PAYLOAD:{payload |"generic_file_content_payload[&i&]" string => "&payload&";
}&
&GENERIC_FILE_CONTENT_ENFORCE:{enforce |"generic_file_content_enforced[&i&]" string => "&enforce&";
}&
&GENERIC_FILE_CONTENT_POST_HOOK_COMMAND:{command |"generic_file_content_posthook[&i&]" string => "&command&";
}&
&GENERIC_FILE_CONTENT_DELETION_REGEXP:{delreg |"generic_file_content_deletion_regexp[&i&]" string => "&delreg&";
}&
&GENERIC_FILE_CONTENT_MODIFICATION_REGEXP:{delreg |"generic_file_content_modification_regexp[&i&]" string => "&delreg&";
}&
&GENERIC_FILE_CONTENT_MODIFICATION_DESTINATION:{destination |"generic_file_content_modification_destination[&i&]" string => "&destination&";
}&
&GENERIC_FILE_SECTION_HEADER:{header |"generic_file_content_section_header[&i&]" string => "&header&";
}&
# Since content is multiline, it is not indented to prevent spurious space from being inserted within
&GENERIC_FILE_SECTION_CONTENT:{content |"generic_file_content_section_content[&i&]" string => "&content&";
}&
&GENERIC_FILE_SECTION_FOOTER:{footer |"generic_file_content_section_footer[&i&]" string => "&footer&";
}&
&GENERIC_FILE_CONTENT_MIGRATE_TO_ZONE_BOOLEAN:{migrate_to_zone |"migrate_to_zone[&i&]" string => "&migrate_to_zone&";
}&
&GENERIC_FILE_CONTENT_ZONE_HEADER:{header |"generic_file_content_modification_only_zone_header[&i&]" string => "&header&";
}&
&GENERIC_FILE_CONTENT_ZONE_FOOTER:{footer |"generic_file_content_modification_only_zone_footer[&i&]" string => "&footer&";
}&
&TRACKINGKEY:{piuuid |"generic_file_content_uuid[&i&]" string => "&piuuid&";
}&
# Since classes of a bundle are not visible to the bundle edit_line, we need to define variable
# and check their values in the bundle_edit_line
&GENERIC_FILE_CONTENT_DELETION_BOOLEAN:{deletion | "generic_file_content_deletion_boolean[&i&]" string => "&deletion&";
}&
&GENERIC_FILE_CONTENT_MODIFICATION_BOOLEAN:{modification |"generic_file_content_modification_boolean[&i&]" string => "&modification&";
}&
&GENERIC_FILE_CONTENT_SECTION_MANAGEMENT:{enforce_section |"generic_file_content_section_boolean[&i&]" string => "&enforce_section&";
}&
"index" slist => getindices("generic_file_content_path");
"file_edit_go" string => "go";
# When we define the file to be checked only at creation, it means that we want to create it
&GENERIC_FILE_CONTENT_CREATE_BOOLEAN:{createfile | tier1.!enforce_at_creation_only_&i&::
"generic_file_content_creation[&i&]" string => "&createfile&";
}&
&GENERIC_FILE_CONTENT_CREATE_BOOLEAN:{createfile | tier1.enforce_at_creation_only_&i&::
"generic_file_content_creation[&i&]" string => "true";
}&
classes:
# Set a class to define when we need to run the post-modification hook
&GENERIC_FILE_CONTENT_POST_HOOK_RUN:{run |"execute_command_&i&" expression => strcmp("&run&", "true");
}&
&GENERIC_FILE_CONTENT_PERMISSION_ADJUSTMENT:{adjust |"adjust_permissions_&i&" expression => strcmp("&adjust&", "true");
}&
&GENERIC_FILE_CONTENT_DELETION_BOOLEAN:{deletion |"delete_lines_&i&" expression => strcmp("&deletion&", "true");
}&
&GENERIC_FILE_CONTENT_MODIFICATION_BOOLEAN:{modification |"modify_lines_&i&" expression => strcmp("&modification&", "true");
}&
&GENERIC_FILE_CONTENT_ENFORCE_CREATE_ONLY_BOOLEAN:{enforce_at_creation_only |"enforce_at_creation_only_&i&" expression => strcmp("&enforce_at_creation_only&", "true");
}&
&GENERIC_FILE_CONTENT_SECTION_MANAGEMENT:{enforce_section |"enforce_section_&i&" expression => strcmp("&enforce_section&", "true");
}&
&GENERIC_FILE_CONTENT_ONLY_ZONE_BOOLEAN:{only_zone |"edit_only_in_a_zone_&i&" expression => strcmp("&only_zone&", "true");
}&
"edit_section_valid_${index}" and => { isvariable("generic_file_content_section_header[${index}]"), isvariable("generic_file_content_section_footer[${index}]") } ;
"file_doesnt_exist_${index}" not => fileexists("${generic_file_content_path[${index}]}");
"creation_only_but_already_exists_${index}" expression => "enforce_at_creation_only_${index}.!file_doesnt_exist_${index}";
# define if we need to migrate to zone
"migrate_to_zone_${index}" expression => strcmp("${migrate_to_zone[${index}]}", "true");
# Workaround for #3014: no value = empty value
# In some conditions, the value of replacement is
# considerered as null instead of empty.
# This class will ensure that no variable (=null) will be considered
# as an empty variable.
"generic_file_content_modification_destination_defined_${index}" expression => isvariable("generic_file_content_modification_destination[${index}]");
# Check that value has been set before to edit the file
"edit_content_${index}" expression => isvariable("generic_file_content_payload[${index}]");
"tier1" expression => "any";
"tier2" expression => isvariable("file_edit_go");
files:
tier2::
# Edit the file
# Defines classes for the file edition globaly, as it can be globally kept even if part are modified
# (for instance, section edition have a global status kept, but several repaired status)
# Note: it is too hard to make a single bundle for editing this file, with support of zone edition and non zone edition
# So, we call a different bundle_edit_line based on the type of edition we want
"${generic_file_content_path[${index}]}"
edit_line => check_generic_file_content_edition(
"${generic_file_content_payload[${index}]}", "${generic_file_content_enforced[${index}]}",
"${generic_file_content_deletion_regexp[${index}]}", "${generic_file_content_deletion_boolean[${index}]}",
"${generic_file_content_modification_regexp[${index}]}", "${generic_file_content_modification_destination[${index}]}", "${generic_file_content_modification_boolean[${index}]}",
"${generic_file_content_section_header[${index}]}", "${generic_file_content_section_footer[${index}]}", "${generic_file_content_section_content[${index}]}", "${generic_file_content_section_boolean[${index}]}",
"${index}"
),
create => "${generic_file_content_creation[${index}]}",
edit_defaults => rudder_empty_select("${generic_file_content_enforced[${index}]}"),
ifvarclass => "!creation_only_but_already_exists_${index}.!edit_only_in_a_zone_${index}",
classes => kept_if_else("file_edition_global_files_status_${index}_kept", "file_edition_global_files_status_${index}_repaired", "file_edition_global_files_status_${index}_failed"),
comment => "Editing ${generic_file_content_path[${index}]}...";
"${generic_file_content_path[${index}]}"
edit_line => check_generic_file_content_edition_in_zone(
"${generic_file_content_payload[${index}]}", "${generic_file_content_enforced[${index}]}",
"${generic_file_content_deletion_regexp[${index}]}", "${generic_file_content_deletion_boolean[${index}]}",
"${generic_file_content_modification_regexp[${index}]}", "${generic_file_content_modification_destination[${index}]}", "${generic_file_content_modification_boolean[${index}]}",
"${generic_file_content_section_header[${index}]}", "${generic_file_content_section_footer[${index}]}", "${generic_file_content_section_content[${index}]}", "${generic_file_content_section_boolean[${index}]}",
"${generic_file_content_modification_only_zone_header[${index}]}", "${generic_file_content_modification_only_zone_footer[${index}]}", "${migrate_to_zone[${index}]}",
"${index}"
),
create => "${generic_file_content_creation[${index}]}",
edit_defaults => rudder_empty_select("${generic_file_content_enforced[${index}]}"),
ifvarclass => "!creation_only_but_already_exists_${index}.edit_only_in_a_zone_${index}",
classes => kept_if_else("file_edition_global_files_status_${index}_kept", "file_edition_global_files_status_${index}_repaired", "file_edition_global_files_status_${index}_failed"),
comment => "Editing ${generic_file_content_path[${index}]}...";
"${generic_file_content_path[${index}]}"
create => "${generic_file_content_creation[${index}]}",
perms => mog("${generic_file_content_perms[${index}]}", "${generic_file_content_owner[${index}]}", "${generic_file_content_group[${index}]}"),
classes => kept_if_else("perms_${index}_kept", "perms_${index}_modified", "perms_${index}_failed"),
ifvarclass => "adjust_permissions_${index}.!creation_only_but_already_exists_${index}",
comment => "Setting ${generic_file_content_path[${index}]} permissions...";
commands:
tier2::
"${generic_file_content_posthook[${index}]}"
classes => if_else("generic_file_content_posthook_${index}_command_run_ok", "generic_file_content_posthook_${index}_command_run_failed"),
contain => in_shell,
ifvarclass => "execute_command_${index}.file_edition_global_files_status_${index}_repaired";
reports:
tier2::
# Files edition
# No line migrations
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@File@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was already in accordance with the policy"
ifvarclass => "!migrate_to_zone_${index}.edit_content_${index}.((content_${index}_kept.!content_${index}_modified)|(file_edition_global_files_status_${index}_kept.!file_edition_global_files_status_${index}_repaired))";
"@@checkGenericFileContent@@result_repaired@@${generic_file_content_uuid[${index}]}@@File@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was successfully updated"
ifvarclass => "!migrate_to_zone_${index}.content_${index}_modified.file_edition_global_files_status_${index}_repaired";
"@@checkGenericFileContent@@result_error@@${generic_file_content_uuid[${index}]}@@File@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} could not be updated"
ifvarclass => "!migrate_to_zone_${index}.content_${index}_failed";
# if we want to migrate lines
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@File@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was already in accordance with the policy"
ifvarclass => "migrate_to_zone_${index}.edit_content_${index}.((content_${index}_kept.!content_${index}_modified.delete_out_of_zone_content_${index}_kept.!delete_out_of_zone_content_${index}_repaired)|(file_edition_global_files_status_${index}_kept.!file_edition_global_files_status_${index}_repaired))";
"@@checkGenericFileContent@@result_repaired@@${generic_file_content_uuid[${index}]}@@File@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was successfully updated"
ifvarclass => "migrate_to_zone_${index}.file_edition_global_files_status_${index}_repaired.(content_${index}_modified|delete_out_of_zone_content_${index}_repaired)";
"@@checkGenericFileContent@@result_error@@${generic_file_content_uuid[${index}]}@@File@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} could not be updated"
ifvarclass => "migrate_to_zone_${index}.(content_${index}_failed|delete_out_of_zone_content_${index}_failed)";
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@File@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#No content was given to check file ${generic_file_content_path[${index}]}, skipping"
ifvarclass => "!edit_content_${index}";
# Files edition - deletion
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Line deletion regular expressions@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was not set for any line deletion"
ifvarclass => "!delete_lines_${index}";
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Line deletion regular expressions@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was already in accordance with the deletion policy"
ifvarclass => "delete_lines_${index}.((content_deletion_kept_${index}.!content_deletion_modified_${index}.!content_deletion_failed_${index})|(file_edition_global_files_status_${index}_kept.!file_edition_global_files_status_${index}_repaired))";
"@@checkGenericFileContent@@result_repaired@@${generic_file_content_uuid[${index}]}@@Line deletion regular expressions@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was successfully updated using the deletion policy"
ifvarclass => "content_deletion_modified_${index}.file_edition_global_files_status_${index}_repaired";
"@@checkGenericFileContent@@result_error@@${generic_file_content_uuid[${index}]}@@Line deletion regular expressions@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} could not be updated using the deletion policy"
ifvarclass => "content_deletion_failed_${index}";
# Files edition - replacement
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Line replacement regular expressions@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was not set for any line replacement"
ifvarclass => "!modify_lines_${index}";
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Line replacement regular expressions@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was already in accordance with the replacement policy"
ifvarclass => "content_modification_kept_${index}.!content_modification_modified_${index}.!content_modification_failed_${index}";
"@@checkGenericFileContent@@result_repaired@@${generic_file_content_uuid[${index}]}@@Line replacement regular expressions@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was successfully updated using the replacement policy"
ifvarclass => "content_modification_modified_${index}";
"@@checkGenericFileContent@@result_error@@${generic_file_content_uuid[${index}]}@@Line replacement regular expressions@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} could not be updated using the replacement policy"
ifvarclass => "content_modification_failed_${index}";
# File edition - enforce only at creation
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@File@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} already exists, skipping content editing"
ifvarclass => "edit_content_${index}.creation_only_but_already_exists_${index}";
# Permissions edition
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Permission adjustment@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} uses default permissions"
ifvarclass => "!adjust_permissions_${index}";
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Permission adjustment@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} permissions are OK"
ifvarclass => "perms_${index}_kept";
"@@checkGenericFileContent@@result_repaired@@${generic_file_content_uuid[${index}]}@@Permission adjustment@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} permissions were adjusted"
ifvarclass => "perms_${index}_modified";
"@@checkGenericFileContent@@result_error@@${generic_file_content_uuid[${index}]}@@Permission adjustment@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} permissions could not be adjusted"
ifvarclass => "perms_${index}_failed";
# Permissions edition - enforce only at creation
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Permission adjustment@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was already existing, skipping permission checking"
ifvarclass => "adjust_permissions_${index}.creation_only_but_already_exists_${index}";
#Section edition
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Enforce content by section@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was not set for section edition, skipping"
ifvarclass => "!enforce_section_${index}";
"@@checkGenericFileContent@@result_error@@${generic_file_content_uuid[${index}]}@@Enforce content by section@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was set for section edition, but no header or footer was defined"
ifvarclass => "enforce_section_${index}.!edit_section_valid_${index}";
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Enforce content by section@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} already exists, skipping section edition"
ifvarclass => "enforce_section_${index}.creation_only_but_already_exists_${index}";
# Section edition - No migration
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Enforce content by section@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was already in accordance with the section content policy"
ifvarclass => "!migrate_to_zone_${index}.enforce_section_${index}.((section_content_modification_kept_${index}.!section_content_modification_modified_${index})|(file_edition_global_files_status_${index}_kept.!file_edition_global_files_status_${index}_repaired))";
"@@checkGenericFileContent@@result_repaired@@${generic_file_content_uuid[${index}]}@@Enforce content by section@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was successfully updated using the section content policy"
ifvarclass => "!migrate_to_zone_${index}.section_content_modification_modified_${index}.!section_content_modification_failed_${index}.file_edition_global_files_status_${index}_repaired";
"@@checkGenericFileContent@@result_error@@${generic_file_content_uuid[${index}]}@@Enforce content by section@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} could not be updated using the section content policy"
ifvarclass => "!migrate_to_zone_${index}.section_content_modification_failed_${index}";
# Section edition - migration
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Enforce content by section@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was already in accordance with the section content policy"
ifvarclass => "migrate_to_zone_${index}.enforce_section_${index}.((section_content_modification_kept_${index}.!section_content_modification_modified_${index}.delete_out_of_zone_section_${index}_kept.!delete_out_of_zone_section_${index}_repaired)|(file_edition_global_files_status_${index}_kept.!file_edition_global_files_status_${index}_repaired))";
"@@checkGenericFileContent@@result_repaired@@${generic_file_content_uuid[${index}]}@@Enforce content by section@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} was successfully updated using the section content policy"
ifvarclass => "migrate_to_zone_${index}.((section_content_modification_modified_${index}.!section_content_modification_failed_${index})|(delete_out_of_zone_section_${index}_repaired.!delete_out_of_zone_section_${index}_failed)).file_edition_global_files_status_${index}_repaired";
"@@checkGenericFileContent@@result_error@@${generic_file_content_uuid[${index}]}@@Enforce content by section@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The file ${generic_file_content_path[${index}]} could not be updated using the section content policy"
ifvarclass => "migrate_to_zone_${index}.(section_content_modification_failed_${index}|delete_out_of_zone_section_${index}_failed)";
# Posthook report
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Post-modification hook@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#No command for ${generic_file_content_path[${index}]} was to be executed"
ifvarclass => "!execute_command_${index}";
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Post-modification hook@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#${generic_file_content_path[${index}]} was in the proper state, so no command to execute"
ifvarclass => "execute_command_${index}.file_edition_global_files_status_${index}_kept.!file_edition_global_files_status_${index}_repaired";
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Post-modification hook@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The command for ${generic_file_content_path[${index}]} was correctly executed"
ifvarclass => "generic_file_content_posthook_${index}_command_run_ok";
"@@checkGenericFileContent@@result_error@@${generic_file_content_uuid[${index}]}@@Post-modification hook@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#The command for ${generic_file_content_path[${index}]} could not to be executed"
ifvarclass => "generic_file_content_posthook_${index}_command_run_failed";
"@@checkGenericFileContent@@result_success@@${generic_file_content_uuid[${index}]}@@Post-modification hook@@${generic_file_content_path[${index}]}@@${g.execRun}##${g.uuid}@#${generic_file_content_path[${index}]} already exists, skipping command execution"
ifvarclass => "execute_command_${index}.creation_only_but_already_exists_${index}";
}
# The file edition should be unitary made in this bundle
bundle edit_line check_generic_file_content_edition(
content, enforce_content_boolean,
deletion_regex, deletion_boolean,
modification_regex, modification_replacement, modification_boolean,
section_start, section_end, section_content, section_boolean,
index # For the reporting
)
{
vars:
# define all the information for the section edition
"csection" string => canonify("${section_start}");
"escaped_section_start" string => escape(${section_start});
"escaped_section_end" string => escape(${section_end});
# define the classes that will define which edition we are to do
classes:
"preserve_content" expression => strcmp("true", "${enforce_content_boolean}");
# when need to check the validity of the content on the original value, otherwise local context is always true
"edit_content" expression => isvariable("check_generic_file_content.generic_file_content_payload[${index}]");
"delete_lines" expression => strcmp("${deletion_boolean}", "true");
"replace_lines" expression => strcmp("${modification_boolean}", "true");
"replace_lines_destination_defined" expression => isvariable("check_generic_file_content.generic_file_content_modification_destination[${index}]");
"section_edition" expression => strcmp("${section_boolean}", "true");
"edit_section_valid" and => { isvariable("check_generic_file_content.generic_file_content_section_header[${index}]"), isvariable("check_generic_file_content.generic_file_content_section_footer[${index}]") } ;
# Detect if section is already there
"has_${csection}" expression => regline("${escaped_section_start}", "${edit.filename}");
delete_lines:
delete_lines::
"${deletion_regex}"
classes => kept_if_else("content_deletion_kept_${index}", "content_deletion_modified_${index}", "content_deletion_failed_${index}"),
comment => "Deleting lines using the given regexps...";
section_edition.edit_section_valid::
# Delete the content of the section
".*"
select_region => rudder_section_selector("${escaped_section_start}", "${escaped_section_end}"),
ifvarclass => "has_${csection}";
insert_lines:
preserve_content.edit_content::
"${content}"
classes => kept_if_else("content_${index}_kept", "content_${index}_modified", "content_${index}_failed"),
insert_type => "preserve_block",
comment => "Editing ...";
!preserve_content.edit_content::
"${content}"
classes => kept_if_else("content_${index}_kept", "content_${index}_modified", "content_${index}_failed"),
comment => "Editing ...";
section_edition.edit_section_valid::
# Insert new, empty section if it doesn't exist already.
"${section_start}
${section_end}"
insert_type => "preserve_block",
ifvarclass => "!has_${csection}";
# Insert missing lines into the section
"${section_content}"
select_region => rudder_section_selector("${escaped_section_start}", "${escaped_section_end}"),
classes => kept_if_else("section_content_modification_kept_${index}", "section_content_modification_modified_${index}", "section_content_modification_failed_${index}");
replace_patterns:
replace_lines.replace_lines_destination_defined::
"${modification_regex}"
replace_with => value("${modification_replacement}"),
classes => kept_if_else("content_modification_kept_${index}", "content_modification_modified_${index}", "content_modification_failed_${index}"),
comment => "Replacing lines using the given regexps...";
replace_lines.!replace_lines_destination_defined::
"${modification_regex}"
replace_with => value(""),
classes => kept_if_else("content_modification_kept_${index}", "content_modification_modified_${index}", "content_modification_failed_${index}"),
comment => "Replacing lines using the given regexps...";
}
# The file edition should be unitary made in this bundle
bundle edit_line check_generic_file_content_edition_in_zone(
content, enforce_content_boolean,
deletion_regex, deletion_boolean,
modification_regex, modification_replacement, modification_boolean,
section_start, section_end, section_content, section_boolean,
zone_start, zone_end, migrate_to_zone,
index # For the reporting
)
{
vars:
# define all the information for the section edition
"csection" string => canonify("${section_start}");
"escaped_section_start" string => escape(${section_start});
"escaped_section_end" string => escape(${section_end});
"section_delimiters" slist => { "${escaped_section_start}", "${escaped_section_end}" };
"escaped_zone_start" string => escape(${zone_start});
"escaped_zone_end" string => escape(${zone_end});
# define the classes that will define which edition we are to do
classes:
# CAUTION, the semantic of "preserve content" means we empty the file in this technique
"preserve_content" expression => strcmp("true", "${enforce_content_boolean}");
# when need to check the validity of the content on the original value, otherwise local context is always true
"edit_content" expression => isvariable("check_generic_file_content.generic_file_content_payload[${index}]");
"delete_lines" expression => strcmp("${deletion_boolean}", "true");
"replace_lines" expression => strcmp("${modification_boolean}", "true");
"replace_lines_destination_defined" expression => isvariable("check_generic_file_content.generic_file_content_modification_destination[${index}]");
"section_edition" expression => strcmp("${section_boolean}", "true");
"edit_section_valid" and => { isvariable("check_generic_file_content.generic_file_content_section_header[${index}]"), isvariable("check_generic_file_content.generic_file_content_section_footer[${index}]") } ;
!preserve_content::
# Detect if section is already there
# computation in this case is more complex:
# if section already inside of zone, we can edit it
# if section is outside of zone then remove it, and add it back in the zone
# so always delete the content of the section, then delete section out of zone. then ensure header and footer section in zone. and add content in it
"has_${csection}" expression => regline("${escaped_section_start}", "${edit.filename}");
# i can edit only if zone is there
"has_begin_zone" expression => regline("${zone_start}", "${edit.filename}");
"has_end_zone" expression => regline("${zone_end}", "${edit.filename}");
"end_zone_defined" not => strcmp("", "${zone_end}");
"has_zone" expression => "has_begin_zone.(has_end_zone|!end_zone_defined)";
any::
# If we migrate to zone, then lines ensured from the zone would be removed from outside the zone
"migrate_to_zone" expression => strcmp("${migrate_to_zone}", "true");
"pass_two" expression => "pass_one";
"pass_one" expression => "any";
delete_lines:
delete_lines.pass_two::
"${deletion_regex}"
classes => kept_if_else("content_deletion_kept_${index}", "content_deletion_modified_${index}", "content_deletion_failed_${index}"),
select_region => rudder_section_selector("${escaped_zone_start}", "${escaped_zone_end}"),
comment => "Deleting lines in zone using the given regexps...";
section_edition.edit_section_valid::
# Delete the content of the section
".*"
select_region => rudder_section_selector("${escaped_section_start}", "${escaped_section_end}"),
ifvarclass => "has_${csection}";
# move section to zone if we decide to do so
# to move, we delete from everywhere, and add it back in the proper location
section_edition.migrate_to_zone.edit_section_valid::
"${section_delimiters}"
classes => rudder_common_classes("delete_out_of_zone_section_${index}"),
comment => "Removing matched lines out of zone ...";
# remove line out of zone if we decide to do so
edit_content.migrate_to_zone.pass_two::
"${content}"
classes => rudder_common_classes("delete_out_of_zone_content_${index}"),
comment => "Removing matched lines out of zone ...";
insert_lines:
!has_zone::
"${zone_start}
${zone_end}";
preserve_content.edit_content.pass_two::
"${content}"
classes => kept_if_else("content_${index}_kept", "content_${index}_modified", "content_${index}_failed"),
select_region => rudder_section_selector("${escaped_zone_start}", "${escaped_zone_end}"),
insert_type => "preserve_block",
comment => "Editing ...";
!preserve_content.edit_content.pass_two::
"${content}"
classes => kept_if_else("content_${index}_kept", "content_${index}_modified", "content_${index}_failed"),
select_region => rudder_section_selector("${escaped_zone_start}", "${escaped_zone_end}"),
comment => "Editing ...";
section_edition.edit_section_valid.pass_two::
# Insert new, empty section always, as we remove it always to empty it
"${section_start}
${section_end}"
select_region => rudder_section_selector("${escaped_zone_start}", "${escaped_zone_end}"),
insert_type => "preserve_block";
# Insert missing lines into the section
"${section_content}"
select_region => rudder_section_selector("${escaped_section_start}", "${escaped_section_end}"),
classes => kept_if_else("section_content_modification_kept_${index}", "section_content_modification_modified_${index}", "section_content_modification_failed_${index}");
replace_patterns:
replace_lines.replace_lines_destination_defined::
"${modification_regex}"
replace_with => value("${modification_replacement}"),
classes => kept_if_else("content_modification_kept_${index}", "content_modification_modified_${index}", "content_modification_failed_${index}"),
select_region => rudder_section_selector("${escaped_zone_start}", "${escaped_zone_end}"),
comment => "Replacing lines using the given regexps...";
replace_lines.!replace_lines_destination_defined::
"${modification_regex}"
replace_with => value(""),
classes => kept_if_else("content_modification_kept_${index}", "content_modification_modified_${index}", "content_modification_failed_${index}"),
select_region => rudder_section_selector("${escaped_zone_start}", "${escaped_zone_end}"),
comment => "Replacing lines using the given regexps...";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent download_from_shared_folder
{
vars:
&COPYFILE_NAME:{name |"copyfile[&i&][name]" string => "&name&";
}&
&COPYFILE_EXCLUDE_INCLUDE:{exclude_include |"copyfile[&i&][exclude_include]" string => "&exclude_include&";
}&
&COPYFILE_EXCLUDE_INCLUDE_OPTION:{exclude_include_option |"copyfile[&i&][exclude_include_option]" string => "&exclude_include_option&";
}&
&COPYFILE_RECURSION:{rec |"copyfile[&i&][recursion]" string => "&rec&";
}&
&COPYFILE_OWNER:{owner |"copyfile[&i&][owner]" string => "&owner&";
}&
&COPYFILE_GROUP:{group |"copyfile[&i&][group]" string => "&group&";
}&
&COPYFILE_PURGE:{purge |"copyfile[&i&][purge]" string => "&purge&";
}&
&COPYFILE_COMPARE_METHOD:{compare_method |"copyfile[&i&][compare_method]" string => "&compare_method&";
}&
&COPYFILE_PERM:{perms |"copyfile[&i&][perm]" string => "&perms&";
}&
&COPYFILE_DESTINATION:{destination |"copyfile[&i&][destination]" string => "&destination&";
}&
&COPYFILE_POST_HOOK_COMMAND:{command |"copyfile[&i&][posthook]" string => "&command&";
}&
&TRACKINGKEY:{piuuid |"copyfile[&i&][uuid]" string => "&piuuid&";
}&
"shared_folder" string => "&SHARED_FILES_FOLDER&";
"index" slist => getindices("copyfile");
iteration_1::
"extended_modes_${index}"
string => "4",
ifvarclass => "enable_suid_${index}.!enable_sgid_${index}";
"extended_modes_${index}"
string => "2",
ifvarclass => "!enable_suid_${index}.enable_sgid_${index}";
"extended_modes_${index}"
string => "6",
ifvarclass => "enable_suid_${index}.enable_sgid_${index}";
"extended_modes_${index}"
string => "0",
ifvarclass => "!enable_suid_${index}.!enable_sgid_${index}";
classes:
"is_valid" not => strcmp("&SHARED_FILES_FOLDER&", "");
"exist_${index}" expression => fileexists("${copyfile[${index}][destination]}");
"is_file_${index}" not => isdir("${copyfile[${index}][destination]}");
"copy_file_${index}_dest_notdir" not => isdir(dirname("${copyfile[${index}][destination]}"));
"copy_file_${index}_user_absent" not => userexists("${copyfile[${index}][owner]}");
"copy_file_${index}_group_absent" not => groupexists("${copyfile[${index}][group]}");
"need_exclusion_${index}" and => { isvariable("copyfile[${index}][exclude_include]"), strcmp("${copyfile[${index}][exclude_include_option]}", "exclude") };
"need_inclusion_${index}" and => { isvariable("copyfile[${index}][exclude_include]"), strcmp("${copyfile[${index}][exclude_include_option]}", "include") };
"apply_regex_${index}" or => { "need_exclusion_${index}", "need_inclusion_${index}"};
&COPYFILE_SUID:{suid |"enable_suid_&i&" expression => strcmp("&suid&", "true");
}&
&COPYFILE_SGID:{sgid |"enable_sgid_&i&" expression => strcmp("&sgid&", "true");
}&
# Set a class to define when we need to run the post-modification hook
&COPYFILE_POST_HOOK_RUN:{run |"execute_command_&i&" expression => strcmp("&run&", "true");
}&
"iteration_2" expression => "iteration_1";
"iteration_1" expression => "any";
files:
is_valid.iteration_2::
# If it's a directory, without exclusion
"${copyfile[${index}][destination]}"
copy_from => rudder_copy_from("&SHARED_FILES_FOLDER&/${copyfile[${index}][name]}", "${server_info.cfserved}", "${copyfile[${index}][compare_method]}", "false", "false", "${copyfile[${index}][purge]}"),
depth_search => recurse("${copyfile[${index}][recursion]}"),
perms => mog(
"${copyfile[${index}][perm]}",
"${copyfile[${index}][owner]}",
"${copyfile[${index}][group]}"
),
comment => "Enforce content of ${copyfile[${index}][destination]} based on the content on the Rudder server with ${copyfile[${index}][compare_method]} method",
classes => rudder_common_classes("copy_file_${index}"),
ifvarclass => "(!exist_${index}|!is_file_${index}).!apply_regex_${index}";
# If it's a directory, with exclusion
"${copyfile[${index}][destination]}"
copy_from => rudder_copy_from("&SHARED_FILES_FOLDER&/${copyfile[${index}][name]}", "${server_info.cfserved}", "${copyfile[${index}][compare_method]}", "false", "false", "${copyfile[${index}][purge]}"),
depth_search => recurse("${copyfile[${index}][recursion]}"),
file_select => exclude("${copyfile[${index}][exclude_include]}"),
perms => mog(
"${copyfile[${index}][perm]}",
"${copyfile[${index}][owner]}",
"${copyfile[${index}][group]}"
),
comment => "Enforce content of ${copyfile[${index}][destination]} based on the content on the Rudder server with ${copyfile[${index}][compare_method]} method",
classes => rudder_common_classes("copy_file_${index}"),
ifvarclass => "(!exist_${index}|!is_file_${index}).need_exclusion_${index}";
# If it's a directory, with inclusion
"${copyfile[${index}][destination]}"
copy_from => rudder_copy_from("&SHARED_FILES_FOLDER&/${copyfile[${index}][name]}", "${server_info.cfserved}", "${copyfile[${index}][compare_method]}", "false", "false", "${copyfile[${index}][purge]}"),
depth_search => recurse("${copyfile[${index}][recursion]}"),
file_select => by_name("${copyfile[${index}][exclude_include]}"),
perms => mog(
"${copyfile[${index}][perm]}",
"${copyfile[${index}][owner]}",
"${copyfile[${index}][group]}"
),
comment => "Enforce content of ${copyfile[${index}][destination]} based on the content on the Rudder server with ${copyfile[${index}][compare_method]} method with inclusion of '${copyfile[${index}][exclude_include]}'",
classes => rudder_common_classes("copy_file_${index}"),
ifvarclass => "(!exist_${index}|!is_file_${index}).need_inclusion_${index}";
# If it s a file, the depth_search prevents from enforcing the file content
# Besides it is possible to specify suid or sgid only for a file since this
# is too dangerous to apply suid or sgid recursively and only copy an empty
# directory does not make sense.
# Don't take purge in account as well.
"${copyfile[${index}][destination]}"
copy_from => rudder_copy_from("&SHARED_FILES_FOLDER&/${copyfile[${index}][name]}", "${server_info.cfserved}", "${copyfile[${index}][compare_method]}", "false", "false", "false"),
perms => mog(
"${extended_modes_${index}}${copyfile[${index}][perm]}",
"${copyfile[${index}][owner]}",
"${copyfile[${index}][group]}"
),
comment => "Enforce content of file ${copyfile[${index}][destination]} based on the content on the Rudder server with ${copyfile[${index}][compare_method]} method with exclusion of '${copyfile[${index}][exclude_include]}'",
classes => rudder_common_classes("copy_file_${index}"),
ifvarclass => "exist_${index}.is_file_${index}";
commands:
"${copyfile[${index}][posthook]}"
contain => in_shell,
classes => if_else("copyfile_posthook_${index}_command_run_ok", "copyfile_posthook_${index}_command_run_failed"),
ifvarclass => "execute_command_${index}.copy_file_${index}_repaired.!copy_file_${index}_error",
comment => "Execute the posthook command if a file was changed";
reports:
!is_valid::
"@@copyFile@@result_error@@${copyfile[${index}][uuid]}@@Copy file@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#There is no shared folder on the Rudder Server, so it's not possible to copy a file from it";
is_valid::
"@@copyFile@@result_success@@${copyfile[${index}][uuid]}@@Copy file@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#The content of the file(s) is valid"
ifvarclass => "copy_file_${index}_kept.!copy_file_${index}_repaired.!copy_file_${index}_error";
"@@copyFile@@result_repaired@@${copyfile[${index}][uuid]}@@Copy file@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#The content or permissions of the file(s) has been repaired"
ifvarclass => "copy_file_${index}_repaired.!copy_file_${index}_error";
# Error conditons
## The destination is not an existing directory
"@@copyFile@@result_error@@${copyfile[${index}][uuid]}@@Copy file@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#The copy of the file failed: the destination (${copyfile[${index}][destination]}) is not stored in a valid directory"
ifvarclass => "copy_file_${index}_dest_notdir";
## File access denied
"@@copyFile@@result_error@@${copyfile[${index}][uuid]}@@Copy file@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#The copy of the file failed: access to ${copyfile[${index}][name]} denied by the server"
ifvarclass => "copy_file_${index}_denied";
## User does not exist
"@@copyFile@@result_error@@${copyfile[${index}][uuid]}@@Copy file@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#The permissions could not be applied on the file: user \"${copyfile[${index}][owner]}\" not found"
ifvarclass => "copy_file_${index}_user_absent";
## Group does not exist
"@@copyFile@@result_error@@${copyfile[${index}][uuid]}@@Copy file@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#The permissions could not be applied on the file: group \"${copyfile[${index}][group]}\" not found"
ifvarclass => "copy_file_${index}_group_absent";
## Generic failure
"@@copyFile@@result_error@@${copyfile[${index}][uuid]}@@Copy file@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#The content or permissions of the file(s) could not have been repaired (file not found?)"
ifvarclass => "copy_file_${index}_error.!copy_file_${index}_dest_notdir.!copy_file_${index}_denied.!copy_file_${index}_user_absent.!copy_file_${index}_group_absent";
#posthook reports
"@@copyFile@@result_success@@${copyfile[${index}][uuid]}@@Post-modification hook@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#No post-hook command for ${copyfile[${index}][destination]} was defined, not executing"
ifvarclass => "!execute_command_${index}";
"@@copyFile@@result_success@@${copyfile[${index}][uuid]}@@Post-modification hook@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#${copyfile[${index}][destination]} was already in the desired state, so no command was executed"
ifvarclass => "execute_command_${index}.copy_file_${index}_kept.!copy_file_${index}_repaired";
"@@copyFile@@result_success@@${copyfile[${index}][uuid]}@@Post-modification hook@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#The post-hook command for ${copyfile[${index}][destination]} was correctly executed"
ifvarclass => "copyfile_posthook_${index}_command_run_ok";
"@@copyFile@@result_error@@${copyfile[${index}][uuid]}@@Post-modification hook@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#The post-hook command for ${copyfile[${index}][destination]} couldn't be executed"
ifvarclass => "copyfile_posthook_${index}_command_run_failed";
# A copy_from + perms could result in any combinaision of success/repaired/failed, so we have to cover the failed.modified which results in no copy
"@@copyFile@@result_error@@${copyfile[${index}][uuid]}@@Post-modification hook@@${copyfile[${index}][name]}@@${g.execRun}##${g.uuid}@#${copyfile[${index}][destination]} couldn't be copied, so the post-hook command is not executed"
ifvarclass => "execute_command_${index}.copy_file_${index}_error";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
###########################################################
# Download a file from an arbitrary http/https/ftp server #
###########################################################
bundle agent execute_file_download # WARNING : If there is many instance, isn't there a risk of a bundle name collision ???
{
vars:
# If curl is here, use it
!windows.curl_installed::
"download_command" string => "${g.rudder_curl} -f --proxy '' -o \"&DOWNLOADFILE_DESTINATION&\" &DOWNLOADFILE_SOURCE&";
# If no curl is present, fallback to minicurl
!windows.!curl_installed::
"download_command" string => "${g.minicurl} --get --file \"&DOWNLOADFILE_DESTINATION&\" --url &DOWNLOADFILE_SOURCE&";
# Windows always use curl
windows::
"download_command" string => "\"${g.rudder_curl}\" -f --proxy '' -o \"&DOWNLOADFILE_DESTINATION&\" &DOWNLOADFILE_SOURCE&";
classes:
"file_not_found" not => fileexists("&DOWNLOADFILE_DESTINATION&");
files:
!windows::
"&DOWNLOADFILE_DESTINATION&"
pathtype => "literal", # force literal interpretation
perms => mog("&DOWNLOADFILE_MODE&","&DOWNLOADFILE_USER&","&DOWNLOADFILE_GROUP&"),
classes => kept_if_else("file_perms_idle", "file_perms_ok", "file_perms_fail");
commands:
file_not_found::
"${download_command}"
comment => "Getting the file from the server",
classes => kept_if_else("file_download_idle", "file_download_ok", "file_download_fail");
reports:
# File downloading part
!curl_installed::
"@@downloadFile@@log_info@@&TRACKINGKEY&@@Download a file@@&DOWNLOADFILE_SOURCE&@@${g.execRun}##${g.uuid}@#No usable cURL binary detected, falling back to miniperl instead";
!file_not_found.!file_download_ok.!file_download_fail::
"@@downloadFile@@result_success@@&TRACKINGKEY&@@Download a file@@&DOWNLOADFILE_SOURCE&@@${g.execRun}##${g.uuid}@#The file &DOWNLOADFILE_SOURCE& already present";
file_download_ok.!file_download_fail::
"@@downloadFile@@result_repaired@@&TRACKINGKEY&@@Download a file@@&DOWNLOADFILE_SOURCE&@@${g.execRun}##${g.uuid}@#The file &DOWNLOADFILE_SOURCE& has been successfully downloaded";
file_download_fail::
"@@downloadFile@@result_error@@&TRACKINGKEY&@@Download a file@@&DOWNLOADFILE_SOURCE&@@${g.execRun}##${g.uuid}@#The file &DOWNLOADFILE_SOURCE& was could not be downloaded";
# File permissions part
!windows.file_perms_idle.!file_perms_ok.!file_perms_fail::
"@@downloadFile@@result_success@@&TRACKINGKEY&@@Permissions (on UNIX systems)@@&DOWNLOADFILE_SOURCE&@@${g.execRun}##${g.uuid}@#The permissions on file &DOWNLOADFILE_SOURCE& are ok. Skipping ...";
!windows.file_perms_ok.!file_perms_fail::
"@@downloadFile@@result_repaired@@&TRACKINGKEY&@@Permissions (on UNIX systems)@@&DOWNLOADFILE_SOURCE&@@${g.execRun}##${g.uuid}@#The permissions on file &DOWNLOADFILE_SOURCE& were successfully fixed";
!windows.file_perms_fail::
"@@downloadFile@@result_error@@&TRACKINGKEY&@@Permissions (on UNIX systems)@@&DOWNLOADFILE_SOURCE&@@${g.execRun}##${g.uuid}@#The permissions on file &DOWNLOADFILE_SOURCE& were could not be fixed";
windows::
"@@downloadFile@@result_success@@&TRACKINGKEY&@@Permissions (on UNIX systems)@@&DOWNLOADFILE_SOURCE&@@${g.execRun}##${g.uuid}@#This is a windows machine. The &DOWNLOADFILE_SOURCE& file permissions will not be altered.";
}
bundle agent job_scheduler
{
vars:
"all_hours" slist => { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23" };
&JOB_COMMAND:{command |"job_scheduler_command[&i&]" string => "&command&";
}&
&JOB_TIMEOUT:{timeout |"job_scheduler_timeout[&i&]" string => "&timeout&";
}&
&JOB_KEPTCODES:{keptcodes |"job_scheduler_keptcodes[&i&]" string => "&keptcodes&";
}&
&JOB_REPAIRCODES:{repaircodes |"job_scheduler_repaircodes[&i&]" string => "&repaircodes&";
}&
&JOB_ERRORCODES:{errorcodes |"job_scheduler_errorcodes[&i&]" string => "&errorcodes&";
}&
&JOB_TIME_MIN:{mintime |"job_scheduler_time_min[&i&]" string => "&mintime&";
}&
&JOB_TIME_MAX:{maxtime |"job_scheduler_time_max[&i&]" string => "&maxtime&";
}&
&TRACKINGKEY:{uuid |"job_scheduler_uuids[&i&]" string => "&uuid&";
}&
"iterator" slist => getindices("job_scheduler_uuids");
"job_scheduler_canon_name[${iterator}]" string => canonify("${job_scheduler_command[${iterator}]}");
"kept_returncodes_${iterator}" slist => splitstring("${job_scheduler_keptcodes[${iterator}]}",",","128");
"repaired_returncodes_${iterator}" slist => splitstring("${job_scheduler_repaircodes[${iterator}]}",",","128");
"error_returncodes_${iterator}" slist => splitstring("${job_scheduler_errorcodes[${iterator}]}",",","128");
nos::
"test_hours_${iterator}[${all_hours}]" string => "job_scheduler_${all_hours}_${iterator}",
ifvarclass => "test_${all_hours}_${iterator}";
# This should work, but produces errors when CFEngine checks the promises like: "Unable to parse class expression: [garbage]"
# ifvarclass => or(and(isgreaterthan("${all_hours}", "${job_scheduler_time_min[${iterator}]}"), islessthan("${all_hours}", "${job_scheduler_time_max[${iterator}]}")), strcmp("${job_scheduler_time_min[${iterator}]}", "${all_hours}"));
nos2::
"test_hours_list_${iterator}" slist => getvalues("test_hours_${iterator}");
classes:
"job_scheduler_random_time" expression => splayclass("${sys.host}${sys.ipv4}","hourly");
# This is only necessary because the above ifvarclass produces errors like: "Unable to parse class expression: [garbage]"
"test_${all_hours}_enclosed_${iterator}" and => { isgreaterthan("${all_hours}", "${job_scheduler_time_min[${iterator}]}"), islessthan("${all_hours}", "${job_scheduler_time_max[${iterator}]}") };
"test_${all_hours}_${iterator}" or => { "test_${all_hours}_enclosed_${iterator}", strcmp("${job_scheduler_time_min[${iterator}]}", "${all_hours}") };
nos2::
"run_time_${iterator}" select_class => { "@{test_hours_list_${iterator}}" };
any::
"nos2" expression => "nos";
"nos" expression => "any";
commands:
nos2::
"${job_scheduler_command[${iterator}]}"
action => bg("10", "${job_scheduler_timeout[${iterator}]}"),
contain => in_shell,
ifvarclass => "job_scheduler_${all_hours}_${iterator}.Hr${all_hours}.job_scheduler_random_time.!job_scheduler_lock_${iterator}",
classes => kept_if_else_exclusive_persist("${job_scheduler_canon_name[${iterator}]}_ok",
"${job_scheduler_canon_name[${iterator}]}_repaired",
"${job_scheduler_canon_name[${iterator}]}_failed",
"1440", # Persist the reporting classes for 24 hours, this PT deals with daily jobs (for now anyway)
"@{job_scheduler.kept_returncodes_${iterator}}",
"@{job_scheduler.repaired_returncodes_${iterator}}",
"@{job_scheduler.error_returncodes_${iterator}}");
reports:
nos2::
# Note: if the command has not been executed (ever or since > frequency), no report will be sent until the splayclass is defined
# This will cause Rudder to report an "Unknown" status, and is by design
"@@jobScheduler@@result_success@@${job_scheduler_uuids[${iterator}]}@@Job@@${job_scheduler_command[${iterator}]}@@${g.execRun}##${g.uuid}@#Job returned a success return code after the last completed execution (${job_scheduler_command[${iterator}]})"
ifvarclass => "${job_scheduler_canon_name[${iterator}]}_ok";
"@@jobScheduler@@result_repaired@@${job_scheduler_uuids[${iterator}]}@@Job@@${job_scheduler_command[${iterator}]}@@${g.execRun}##${g.uuid}@#Job returned a repaired return code on last completed execution (${job_scheduler_command[${iterator}]})"
ifvarclass => "${job_scheduler_canon_name[${iterator}]}_repaired";
"@@jobScheduler@@result_error@@${job_scheduler_uuids[${iterator}]}@@Job@@${job_scheduler_command[${iterator}]}@@${g.execRun}##${g.uuid}@#Job failed on last completed execution (${job_scheduler_command[${iterator}]})"
ifvarclass => "${job_scheduler_canon_name[${iterator}]}_failed";
"@@jobScheduler@@log_info@@${job_scheduler_uuids[${iterator}]}@@Job@@${job_scheduler_command[${iterator}]}@@${g.execRun}##${g.uuid}@#Job has been launched (${job_scheduler_command[${iterator}]}), result will be reported on next run"
ifvarclass => "job_scheduler_${all_hours}_${iterator}.Hr${all_hours}.job_scheduler_random_time.!job_scheduler_lock_${iterator}",
# we define here the persistent class, as the command exection is done on the last iteration
comment => "Define a persistent class to prevent multiple job executions",
classes => rudder_always_classes_persist("job_scheduler_lock_${iterator}", "5");
"@@jobScheduler@@log_info@@${job_scheduler_uuids[${iterator}]}@@Job@@${job_scheduler_command[${iterator}]}@@${g.execRun}##${g.uuid}@#The command will be run at a random time after ${all_hours}:00 on this node (${job_scheduler_command[${iterator}]})"
ifvarclass => "job_scheduler_${all_hours}_${iterator}";
}
body classes kept_if_else_exclusive_persist(kept, repaired, failed, persist, keptcodes, repairedcodes, errorcodes)
{
kept_returncodes => { "@{keptcodes}" };
repaired_returncodes => { "@{repairedcodes}" };
failed_returncodes => { "@{errorcodes}" };
promise_kept => { "${kept}" };
cancel_kept => { "${repaired}", "${failed}" };
promise_repaired => { "${repaired}" };
cancel_repaired => { "${kept}", "${failed}" };
repair_failed => { "${failed}" };
repair_denied => { "${failed}" };
repair_timeout => { "${failed}" };
cancel_notkept => { "${kept}", "${repaired}" };
persist_time => "${persist}";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#
# Failsafe file
#
body common control
{
bundlesequence => { "check_lock_db_problem", "init_files", "update" };
inputs => { "common/1.0/update.cf" };
output_prefix => "rudder";
}
body agent control {
skipidentify => "&SKIPIDENTIFY&";
}
bundle common g
{
vars:
android::
"rudder_base" string => "/data/rudder";
"rudder_var" string => "/data/rudder";
!windows.!android::
"rudder_base" string => "/opt/rudder";
solaris::
"rudder_var" string => "/opt/rudder/var";
!windows.!android.!solaris::
"rudder_var" string => "/var/rudder";
!windows::
"rudder_bin" string => "${rudder_base}/bin";
"rudder_sbin" string => "${rudder_base}/sbin";
"rudder_base_sbin" string => "${rudder_base}/sbin"; #folder where tools are installed
"rudder_tools" string => "${rudder_var}/tools";
"rudder_ncf" string => "${rudder_var}/ncf";
&if(NOVA)&
windows::
"rudder_base" string => "${sys.winprogdir}\Rudder";
"rudder_var" string => "${sys.winprogdir}\Rudder\var";
"rudder_bin" string => "${rudder_base}\bin";
"rudder_sbin" string => "${rudder_base}\sbin";
"rudder_tools" string => "${rudder_sbin}";
"rudder_ncf" string => "${rudder_var}\ncf";
&endif&
any::
"uuid" string => "&UUID&";
"excludedreps" slist => { "\.X11", ".*kde.*", "\.svn", "perl" };
"rudder_tools_origin" string => "/var/rudder/tools";
"rudder_ncf_origin_common" string => "/usr/share/ncf/tree";
"rudder_ncf_origin_local" string => "&CONFIGURATION_REPOSITORY_FOLDER&/ncf";
"rudder_tools_updated_origin" string => "${rudder_tools_origin}/rudder_tools_updated";
"rudder_tools_updated" string => "${rudder_tools}/rudder_tools_updated";
# The time at which the execution started
(linux|cygwin).!(centos_3|redhat_3|centos_4|redhat_4)::
"execRun" string => execresult("/bin/date --rfc-3339=second", "noshell");
(linux|cygwin).(centos_3|redhat_3|centos_4|redhat_4)::
# We would like to use date's "--rfc-3339=second" option here, but it is not available on older OSes (RHEL 3/4, AIX 5...)
"execRun" string => execresult("/bin/date -u \"+%Y-%m-%d %T+00:00\"", "noshell");
&if(NOVA)&
windows.!cygwin::
"execRun" string => execresult("\"${g.rudder_sbin}\getDate.bat\"", "noshell");
&endif&
android::
"execRun" string => execresult("/system/xbin/date \"+%Y-%m-%d %T+02:00\"", "noshell");
aix::
# AIX's date command doesn't have a "%z" option, so we fake it by using UTC
"execRun" string => execresult("/bin/date -u \"+%Y-%m-%d %T+00:00\"", "noshell");
!linux.!cygwin.!windows.!android.!aix::
"execRun" string => execresult("/bin/date \"+%Y-%m-%d %T%:z\"", "noshell");
# definition of the node roles
&NODEROLE&
}
bundle common rudder_roles
{
classes:
# Abort if no uuid is defined
"should_not_continue" not => fileexists("${g.uuid_file}");
# Policy Server is a machine which delivers promises
"policy_server" expression => strcmp("root","${g.uuid}");
# Root Server is the top policy server machine
"root_server" expression => strcmp("root","${g.uuid}");
# We are in the failsafe phase
"failsafe" expression => "any";
}
############################################
#generate a key if not present
bundle agent init_files
{
vars:
"components" slist => { "cf-agent", "cf-serverd", "cf-execd", "cf-monitord", "cf-promises", "cf-runagent", "cf-key", "cf-hub" };
nova_edition::
"cfengine_install_path" string => "/usr/local";
community_edition::
"cfengine_install_path" string => "${g.rudder_base}";
classes:
"missing_key" not => fileexists("${sys.workdir}/ppkeys/localhost.priv");
files:
cfengine_community.!windows::
"${sys.workdir}/bin/${components}"
perms => u_p("700"),
copy_from => cp("${cfengine_install_path}/bin/${components}","localhost"),
action => immediate;
commands:
cygwin.missing_key::
"${sys.workdir}/bin/cf-key.exe";
&if(NOVA)&
windows.missing_key.!cygwin::
"\"${sys.workdir}\bin\cf-key\"";
&endif&
!windows.!cygwin.missing_key::
"${sys.workdir}/bin/cf-key";
}
# This bundle will check the "last successful inputs update", and if it is older
# than 1 hour, remove cf_lock.db (and only this DB), to give CFEngine a chance
# to run properly again.
bundle agent check_lock_db_problem{
vars:
cfengine_3_0|cfengine_3_1|cfengine_3_2::
"cf_lock_filename" string => "cf_lock.db";
!(cfengine_3_0|cfengine_3_1|cfengine_3_2)::
"cf_lock_filename" string => "cf_lock.tcdb";
files:
# The aim of this promise is to create a class when this file is older
# than one hour. The class can not be created without touching but in
# order to not modifing the mtime we use WarnOnly.
"${sys.workdir}/last_successful_inputs_update"
file_select => over_an_hour,
touch => "true",
action => WarnOnly,
classes => success("last_successful_inputs_update_too_old", "last_successful_inputs_update_check_error", "last_successful_inputs_update_ok");
"${sys.workdir}/state/${cf_lock_filename}"
delete => tidy,
ifvarclass => "last_successful_inputs_update_too_old",
classes => success("cf_lock_removed", "cf_lock_error_removing", "cf_lock_not_deleted");
reports:
cf_lock_removed::
"@@Common@@log_repaired@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Promises had not been updated for over an hour, this could indicate a broken lockfile. cf_lock DB file was removed.";
cf_lock_error_removing::
"@@Common@@result_error@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Promises have not been updated for over an hour, this could indicate a broken lockfile, but an error occured when trying to remove it";
}
body file_select over_an_hour()
{
# Select file which are older than one hour
# Use of positive mtime instead of negative one
# In order to avoid corner effects
mtime => irange(ago(0,0,0,1,0,0), now);
file_result => "!mtime";
}
body depth_search recurse(d)
{
depth => "${d}";
}
#perms validation
body perms u_p(p)
{
mode => "${p}";
}
#server may be a list
body copy_from cp(from,server)
{
servers => { "${server}" };
source => "${from}";
compare => "digest";
community_edition::
portnumber => "&COMMUNITYPORT&";
}
body copy_from copy_digest(from)
{
source => "${from}";
copy_backup => "false";
preserve => "true";
compare => "digest";
}
body action immediate
{
ifelapsed => "0";
}
body depth_search recurse_ignore(d,list)
{
depth => "${d}";
exclude_dirs => { @{list} };
}
body delete tidy
{
dirlinks => "delete";
rmdirs => "true";
}
body action WarnOnly
{
action_policy => "warn";
}
body file_select exclude(name)
{
leaf_name => { "${name}"};
file_result => "!leaf_name";
}
&GENERATIONTIMESTAMP&
#!/usr/bin/env perl
#
#####################################################################################
# Copyright 2014 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#
# This script uploads or downloads a file using Perl's LWP library and PUT/GET HTTP method.
#
use strict;
use warnings;
use Getopt::Long;
# HTTP operations
use LWP::UserAgent;
use HTTP::Request::Common;
use MIME::Base64 qw( encode_base64 );
# File handling
use File::Basename;
# Version
my $program_name = "minicurl.pl";
my $program_version = "1.0";
my $program_description = "Perl HTTP, HTTP/S, FTP download and upload tool";
## Argument handling (Getopt)
my ($get, $put, $httpstatus, $help, $debug, $version);
$get = $put = $httpstatus = $help = $debug = $version = 0;
my ($url, $file, $authentication, $response);
$url = $file = $authentication = $response = '';
GetOptions( "get!" => \$get,
"put!" => \$put,
"url:s" => \$url,
"file:s" => \$file,
"authentication=s" => \$authentication,
"http-status!" => \$httpstatus,
"help!" => \$help,
"debug!" => \$debug,
"version!" => \$version);
sub usage {
print "This is " . $program_name . ", v" . $program_version . ": " . $program_description . "\n";
print "Usage: $0 [--help] [--debug] [--http-status] [--authentication <user:password>] --get/--put --url <url> --file <file>\n";
}
if ($version >= 1) {
print $program_name . ", version " . $program_version . "\n";
exit(0);
} elsif ($help >= 1) {
usage();
exit(0);
}
if ($get == $put) {
print "ERROR: Please specify only one method to use.\n";
usage();
exit(1);
} elsif ($url eq "" || $file eq "") {
print "ERROR: The --url and --file arguments are mandatory!\n";
usage();
exit(1);
}
# Build the file basename
my $file_basename = basename($file);
# Create a HTTP Basic authentication string if applicable
$authentication = encode_base64($authentication) if ($authentication ne "");
# Make sure we use SSLv3 at least while connecting to HTTP/S
$ENV{HTTPS_VERSION} = 3;
# Create a new LWP object
my $ua = LWP::UserAgent->new;
if ($put == 1) {
# PUT
# Create a variable from the target file
my $message;
open(my $fh, '<', $file) or die "ERROR: Unable to open file $file.\n";
{
local $/;
$message = <$fh>;
}
close($fh);
# Send the file using the PUT method
if ($authentication eq "") {
$response = $ua->request(PUT $url . $file_basename, Content => $message);
} else {
$response = $ua->request(PUT $url . "/" . $file_basename, Authorization => "Basic " . $authentication, Content => $message);
}
} else {
# GET
# Get the file using the GET method
if ($authentication eq "") {
$response = $ua->request(GET $url);
} else {
$response = $ua->request(GET $url, Authorization => "Basic " . $authentication);
}
open my $fh, ">", $file or die("ERROR: Unable to open file $file.\n");
print $fh $response->content;
}
if ($response->is_success) {
print "OK (" . $response->status_line . ")\n" if ($debug >= 1);
print $response->code . "\n" if ($httpstatus >= 1);
exit(0);
}
else {
print "FAILED (" . $response->status_line . ")\n" if ($debug >= 1);
print $response->code . "\n" if ($httpstatus >= 1);
exit(1);
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#######################################################
#
# promises.cf
#
#######################################################
body common control
{
any::
output_prefix => "rudder";
inputs => {
@{va.ncf_inputs},
&INPUTLIST&
};
bundlesequence => { @{va.bs} &BUNDLELIST& , @{va.end} };
android::
# if native syslog is not available, use cfengine implementation (eg: android)
syslog_host => "${server_info.cfserved}";
syslog_port => "&SYSLOGPORT&";
}
bundle common va
{
vars:
policy_server::
"bs" slist => {
"startExecution",
"check_disable_agent",
"clean_red_button",
"update",
"set_red_button",
"internal_security",
"check_red_button_status",
"process_matching",
"check_cf_processes",
"check_uuid",
"check_log_system",
"check_rsyslog_version",
"check_cron_daemon",
"garbage_collection",
"check_binaries_freshness",
"check_zypper",
"nxlog_enable",
"configuration"
};
!policy_server::
"bs" slist => {
"startExecution",
"check_disable_agent",
"clean_red_button",
"update",
"set_red_button",
"internal_security",
"check_red_button_status",
"process_matching",
"check_cf_processes",
"check_cron_daemon",
"garbage_collection",
"check_binaries_freshness",
"check_log_system",
"check_rsyslog_version",
"nxlog_enable",
"check_zypper",
"check_uuid",
"configuration"
};
any::
"end" slist => { "endExecution" };
!android.!windows::::
"rudder_var" string => "/var/rudder";
android::
"rudder_var" string => "/data/rudder";
!windows::
"ncf_path" string => "${rudder_var}/ncf";
"rudder_tools" string => "${rudder_var}/tools";
windows::
"rudder_base" string => "${sys.winprogdir}\Rudder";
"rudder_tools" string => "${rudder_base}\sbin";
"ncf_path" string => "${rudder_base}\ncf";
!windows::
"list_compatible_inputs" string => "NCF_CACHE_PATH=${sys.workdir}/state /bin/sh ${ncf_path}/common/10_ncf_internals/list-compatible-inputs";
"ncf_common_inputs_10_40" slist => splitstring(execresult("${list_compatible_inputs} ${sys.cf_version} ${ncf_path}/common 10_ncf_internals 20_cfe_basics 30_generic_methods 40_it_ops_knowledge", "useshell"), "\n", 10000);
"ncf_common_inputs_50_60" slist => splitstring(execresult("${list_compatible_inputs} ${sys.cf_version} ${ncf_path}/common 50_techniques 60_services", "useshell"), "\n", 10000);
"ncf_local_inputs_10_40" slist => splitstring(execresult("${list_compatible_inputs} ${sys.cf_version} ${ncf_path}/local 10_ncf_internals 20_cfe_basics 30_generic_methods 40_it_ops_knowledge", "useshell"), "\n", 10000);
"ncf_local_inputs_50_60" slist => splitstring(execresult("${list_compatible_inputs} ${sys.cf_version} ${ncf_path}/local 50_techniques 60_services", "useshell"), "\n", 10000);
# ncf_inputs contains all the files of ncf, and ignore the empty lists
"ncf_inputs" slist => {
"@{ncf_common_inputs_10_40}",
"@{ncf_common_inputs_50_60}",
"@{ncf_local_inputs_10_40}",
"@{ncf_local_inputs_50_60}",
},
policy => "ifdefined";
windows::
# Windows agent only exists in 3.6 version, so as a shortcut, we can load all files of ncf
# It should be replaced by a proper script, as explained in #5659
"ncf_common_inputs" slist => splitstring(execresult("c:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command \"ls -Path 'c:\Program Files\Rudder\var\ncf\common' -Name *.cf -Recurse -Exclude promises.cf | % { Write-Host c:\Program Files\Rudder\var\ncf\common\$_ } \"", "useshell"), "\n", 10000);
"ncf_local_inputs" slist => splitstring(execresult("c:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command \"ls -Path 'c:\Program Files\Rudder\var\ncf\local' -Name *.cf -Recurse -Exclude promises.cf | % { Write-Host c:\Program Files\Rudder\var\ncf\local\$_ } \"", "useshell"), "\n", 10000);
# ncf_inputs contains all the files of ncf, and ignore the empty lists
"ncf_inputs" slist => {
"@{ncf_common_inputs}",
"@{ncf_local_inputs}",
},
policy => "ifdefined";
# definition of the machine roles
&NODEROLE&
}
bundle common rudder_roles
{
classes:
# Abort if no uuid is defined
"should_not_continue" not => fileexists("${g.uuid_file}");
# Policy Server is a machine which delivers promises
"policy_server" expression => strcmp("root","${g.uuid}");
# Root Server is the top policy server machine
"root_server" expression => strcmp("root","${g.uuid}");
}
#########################################################
# Control execution
#########################################################
bundle agent startExecution
{
reports:
cfengine_3::
"@@Common@@log_info@@&TRACKINGKEY&@@common@@StartRun@@${g.execRun}##${g.uuid}@#Start execution";
}
bundle agent endExecution
{
reports:
cfengine_3::
"@@Common@@log_info@@&TRACKINGKEY&@@common@@EndRun@@${g.execRun}##${g.uuid}@#End execution";
rudder_promises_generated_error|no_update::
"*********************************************************************************
* rudder-agent could not get an updated configuration from the policy server. *
* This can be caused by a network issue, an unavailable server, or if this *
* node was deleted from the Rudder root server. *
* Any existing configuration policy will continue to be applied without change. *
*********************************************************************************";
}
##########################################################
# Check for "disable-agent" file and cleanly stop and
# warn about this if it is present
##########################################################
bundle agent check_disable_agent
{
vars:
"components" slist => { "cf-serverd", "cf-execd", "cf-monitord" };
classes:
"should_disable_agent" expression => fileexists("${g.rudder_disable_agent_file}");
# Only define this class when we're ready to die - this is a special class name in "abortclasses"
"should_not_continue"
expression => "should_disable_agent",
ifvarclass => "abort_report_done";
processes:
should_disable_agent::
"${sys.workdir}/bin/${components}"
signals => { "term", "kill" };
reports:
should_disable_agent::
"FATAL: The file ${g.rudder_disable_agent_file} is present. Rudder will kill all running daemons and halt immediately."
classes => if_ok("abort_report_done");
}
##########################################################
# Red Button part.
# When the file ${sys.workdir}/inputs/stop exists, we must stop the
# execution of the agent on all client machines
##########################################################
bundle agent clean_red_button()
{
files:
safe.policy_server::
"${g.rudder_var}/share/[a-f0-9A-F\-]+/rules/cfengine-(community|nova)/stopFile"
delete => tidy,
comment => "Deleting the stop file on clients promises, cfengine is good to go";
safe.!policy_server::
"${sys.workdir}/inputs/stopFile"
delete => tidy,
comment => "Deleting the stop file, cfengine is good to go";
commands:
safe.policy_server::
"${sys.workdir}/bin/cf-runagent"
args => "-Dsafe",
comment => "Propagate the safe information to children";
reports:
safe::
"@@Common@@result_repaired@@&TRACKINGKEY&@@Red Button@@None@@${g.execRun}##${g.uuid}@#Authorizing Cfengine to restart";
}
bundle agent set_red_button()
{
classes:
policy_server::
"danger" expression => fileexists("${g.rudder_var}/share/root/stopFile");
methods:
danger::
"any" usebundle => setStopFile;
danger.policy_server::
"any" usebundle => stopClients;
}
bundle agent setStopFile
{
files:
danger.!policy_server::
"${sys.workdir}/inputs/stopFile"
create => "true";
danger.policy_server::
"${g.rudder_var}/share/[a-f0-9A-F\-]+/rules/cfengine-(community|nova)/stopFile"
create => "true";
reports:
danger.!policy_server::
"@@Common@@result_repaired@@&TRACKINGKEY&@@Red Button@@None@@${g.execRun}##${g.uuid}@#Creating local stop file for this node";
danger.policy_server::
"@@Common@@result_repaired@@&TRACKINGKEY&@@Red Button@@None@@${g.execRun}##${g.uuid}@#Creating stop files for all clients of this policy server";
}
bundle agent stopClients
{
classes:
policy_server::
"danger" expression => fileexists("${g.rudder_var}/share/root/stopFile");
commands:
danger.policy_server::
"${sys.workdir}/bin/cf-runagent"
args => "-Ddanger",
comment => "Propagate the danger information to children";
reports:
danger.policy_server::
"@@Common@@log_repaired@@&TRACKINGKEY&@@Red Button@@None@@${g.execRun}##${g.uuid}@#Actively stopping CFEngine operations on all clients of this policy server (via cf-runagent)";
}
bundle agent check_red_button_status()
{
classes:
!policy_server::
"should_not_continue" expression => fileexists("${sys.workdir}/inputs/stopFile");
reports:
!should_not_continue::
"@@Common@@result_success@@&TRACKINGKEY&@@Red Button@@None@@${g.execRun}##${g.uuid}@#Red Button is not in effect, continuing as normal...";
}
###################################################
# Check that CFengine services are up
###################################################
bundle agent check_cf_processes
{
vars:
# process_term defines how many maximum instances of this
# binary should be running before attempting to SIGTERM them.
# process_kill is the same for SIGKILL.
!windows::
# On windows, cf-execd is a service, and there can be only one instance of it running (by design)
"process_term[execd]" string => "2";
"process_kill[execd]" string => "5";
any::
"process_term[agent]" string => "5";
"process_kill[agent]" string => "8";
"binaries" slist => getindices("process_term");
processes:
windows::
# Using the path on windows fails, as process are not reported the same way
# And unfortunately, the cf-serverd is not a service.
"cf-serverd" restart_class => "start_server";
!windows::
"${sys.workdir}/bin/cf-serverd" restart_class => "start_server";
"${sys.workdir}/bin/cf-execd" restart_class => "start_executor";
# If there are more than 2 cf-execd's, it means cf-execd is starting to
# go crazy, so we ask politely to these processes to shut down.
"${sys.workdir}/bin/cf-${binaries}"
process_count => check_range("${binaries}", "0","${process_term[${binaries}]}"),
signals => { "term" },
classes => if_repaired("${binaries}_has_gone_wild"),
comment => "Checking if cf-${binaries} has gone wild";
# If there are too much cf-execd's/cf-agents running, it means that they are really
# going crazy. Let's be a bit less polite and more violent about killing them.
#
# These two promises overlap, because when you go past the 2/5-limit treshold,
# you still leave a chance for them to die with SIGTERM before the SIGKILL.
#
# Reason: The backend databases that stores the classes and some runtime
# parameters do really not appreciate beeing killed violently and may prevent
# the agent from operating properly.
"${sys.workdir}/bin/cf-${binaries}"
process_count => check_range("${binaries}", "0","${process_kill[${binaries}]}"),
signals => { "kill" },
classes => if_repaired("${binaries}_has_gone_really_wild"),
comment => "Checking if cf-${binaries} has gone really wild";
&if(NOVA)&
windows::
# Windows does only implement SIGTERM. Using SIGKILL makes no sense on it.
"cf-${binaries}"
process_count => check_range("${binaries}", "0","${process_term[${binaries}]}"),
signals => { "term" },
classes => if_repaired("${binaries}_has_gone_wild"),
comment => "Checking if cf-${binaries} has gone wild";
services:
# By design, there can be only one cf-execd service running on Windows
windows::
"CfengineNovaExec"
service_policy => "start",
service_method => u_bootstart,
comment => "Start the executor windows service now and at boot time";
&endif&
commands:
start_server::
"${sys.cf_serverd}"
action => u_ifwin_bg,
classes => outcome("server");
start_executor::
"${sys.cf_execd}"
action => u_ifwin_bg,
classes => outcome("executor");
reports:
cfengine_3::
"@@Common@@result_success@@&TRACKINGKEY&@@Process checking@@None@@${g.execRun}##${g.uuid}@#There is an acceptable number of CFEngine processes running on the machine"
# Here, I can not use the binaries variable as CFEngine will iterate and output two reports, breaking the reporting.
ifvarclass => "!agent_has_gone_wild.!agent_has_gone_really_wild.!execd_has_gone_wild.!execd_has_gone_really_wild";
"@@Common@@result_repaired@@&TRACKINGKEY&@@Process checking@@None@@${g.execRun}##${g.uuid}@#Warning, more than ${process_term[${binaries}]} cf-${binaries} processes were detected. They have been sent a graceful termination signal."
ifvarclass => "${binaries}_has_gone_wild.!${binaries}_has_gone_really_wild";
"@@Common@@result_error@@&TRACKINGKEY&@@Process checking@@None@@${g.execRun}##${g.uuid}@#ALERT: more than ${process_term[${binaries}]} cf-${binaries} processes were detected. Killing processes that do not respect graceful termination signals."
ifvarclass => "${binaries}_has_gone_really_wild";
}
#######################################################
# UUID file enforcing
bundle agent check_uuid
{
files:
"${g.uuid_file}"
create => "true",
edit_line => enforce_content("${g.uuid}"),
edit_defaults => noempty_backup,
perms => m("644"),
comment => "Setting the uuid variable in a machine";
}
#######################################################
# Check the log system, and configure it accordingly
# This only works with unix flavoured system
bundle agent check_log_system
{
vars:
debian::
"syslog_ng_source" string => "s_src";
SuSE::
"syslog_ng_source" string => "src";
redhat::
"syslog_ng_source" string => "s_sys";
any::
"syslog_conf_comment" string => "# Autogenerated by rudder, do not edit${const.n}";
"syslog_ng_conf_prefix" string => "filter f_local_rudder{facility(local6) and program(\"rudder.*\");};destination loghost {tcp(\"";
"syslog_ng_conf_suffix" string => "\" port (&SYSLOGPORT&));};log {source(${syslog_ng_source});filter(f_local_rudder);destination(loghost);";
"syslog_ng_conf_final" string => "flags(final);};";
"syslog_ng_conf" string => concat("${syslog_conf_comment}", "${syslog_ng_conf_prefix}", "${server_info.cfserved}", "${syslog_ng_conf_suffix}", "${syslog_ng_conf_final}");
"syslog_ng_conf_regex" string => concat("filter\ f\_local\_rudder\{facility\(local6\)\ and\ program\(\"rudder\.\*\"\)\;\}\;destination\ loghost\ \{(tcp|udp)\(\"", "[^\"]+", escape("${syslog_ng_conf_suffix}"), ".*");
classes:
!android::
"rsyslogd" expression => fileexists("/etc/rsyslog.conf");
"syslogng" expression => fileexists("/etc/syslog-ng/syslog-ng.conf");
"syslogd" expression => fileexists("/etc/syslog.conf");
files:
!windows.rsyslogd::
"/etc/rsyslog.conf"
edit_line => append_if_no_lines("$IncludeConfig /etc/rsyslog.d/*.conf"),
edit_defaults => noempty_backup,
comment => "Add the rsyslog.conf.d include if not already present",
classes => kept_if_else("rsyslog_kept", "rsyslog_repaired" , "rsyslog_failed");
!windows.rsyslogd.!policy_server::
"/etc/rsyslog.d/rudder-agent.conf"
edit_line => append_if_no_lines("#Rudder log system${const.n}if $syslogfacility-text == 'local6' and $programname startswith 'rudder' then @@${server_info.cfserved}:&SYSLOGPORT&${const.n}if $syslogfacility-text == 'local6' and $programname startswith 'rudder' then ~"),
create => "true",
edit_defaults => empty_backup,
classes => kept_if_else("rsyslog_kept", "rsyslog_repaired" , "rsyslog_failed");
SuSE.rsyslogd.policy_server::
# For SuSE, ensure that SYSLOG_DAEMON is set to 'rsyslogd' even if another syslog has been installed before
"/etc/sysconfig/syslog"
edit_line => ensure_rsyslogd_on_suse,
edit_defaults => noempty_backup,
classes => kept_if_else("rsyslog_kept", "rsyslog_repaired" , "rsyslog_failed");
!windows.syslogng.!policy_server::
"/etc/syslog-ng/syslog-ng.conf"
edit_line => edit_syslog_conf_file("${syslog_ng_conf}", "${syslog_ng_conf_regex}"),
edit_defaults => noempty_backup,
classes => kept_if_else("syslog_ng_kept", "syslog_ng_repaired" , "syslog_ng_failed");
!windows.syslogd.!policy_server::
"/etc/syslog.conf"
edit_line => fix_syslogd("@${server_info.cfserved}"),
edit_defaults => noempty_backup,
classes => kept_if_else("syslogd_kept", "syslogd_repaired" , "syslogd_failed");
#Probably, we want to do something if it is repaired ?
commands:
SuSE.(syslog_ng_repaired|rsyslog_repaired|syslogd_repaired)::
"/etc/init.d/syslog"
args => "restart",
comment => "Restarting syslog-ng after it's been updated";
syslog_ng_repaired.!SuSE::
"/etc/init.d/syslog-ng"
args => "restart",
comment => "Restarting syslog-ng after it's been updated";
rsyslog_repaired.!(SuSE|fedora)::
"/etc/init.d/rsyslog"
args => "restart",
comment => "Restarting rsyslog after it's been updated";
rsyslog_repaired.fedora::
"/bin/systemctl"
args => "restart rsyslog",
comment => "Restarting rsyslog after it's been updated";
syslogd_repaired.!SuSE.!solaris.!aix::
"/etc/init.d/syslog"
args => "restart",
comment => "Restarting rsyslog after it's been updated";
solaris.(syslog_ng_repaired|rsyslog_repaired|syslogd_repaired)::
"svcadm refresh svc:/system/system-log:default";
aix.syslogd_repaired::
"/usr/bin/refresh -s syslogd";
reports:
syslogd::
"@@Common@@log_info@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#Detected running syslog as syslogd";
syslogng::
"@@Common@@log_info@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#Detected running syslog as syslog-ng";
rsyslogd::
"@@Common@@log_info@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#Detected running syslog as rsyslog";
syslogd_failed|syslog_ng_failed|rsyslog_failed::
"@@Common@@result_error@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#Logging system could not be configured for report centralization";
syslogd_repaired|syslog_ng_repaired|rsyslog_repaired::
"@@Common@@result_repaired@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#Configured logging system for report centralization";
(syslogd.syslogd_kept.!syslogd_failed.!syslogd_repaired)|(syslogng.syslog_ng_kept.!syslog_ng_failed.!syslog_ng_repaired)|(rsyslogd.rsyslog_kept.!rsyslog_failed.!rsyslog_repaired)::
"@@Common@@result_success@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#Logging system for report centralization is already correctly configured";
android::
"@@Common@@result_success@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#This is an android machine: Logging system configuration skipped.";
}
#######################################################
# Check the version of rsyslog, and correct the conf
# file if > 5.7.1
# This is done in another bundle than check_log_system
# as it would make it too complex to read and maintain
# (we would have needed to delay the restart of the services
# at later iteration)
bundle agent check_rsyslog_version {
vars:
SuSE::
"syslog_restart_cmd" string => "/etc/init.d/syslog restart";
fedora::
"syslog_restart_cmd" string => "/bin/systemctl restart rsyslog";
!(SuSE|fedora)::
"syslog_restart_cmd" string => "/etc/init.d/rsyslog restart";
classes:
"check_rsyslog_version_present" expression => fileexists("${g.rudder_tools}/check_rsyslog_version");
"rsyslogd" expression => fileexists("/etc/rsyslog.conf");
files:
rsyslogd.rsyslog_greater_than_5_7_1::
"/etc/rsyslog.d/remove_limit.conf"
edit_line => append_if_no_lines("$SystemLogRateLimitInterval 0"),
edit_defaults => noempty_backup,
create => "true",
comment => "Add a config line in the rsyslog.conf file to prevent from dropping rudder messages",
classes => rudder_common_classes("rsyslog_limit");
commands:
rsyslogd.check_rsyslog_version_present::
"${g.rudder_tools}/check_rsyslog_version"
contain => in_shell,
module => "true",
comment => "Check rsyslog version in order to add or not a configuration line in rsyslog.conf";
rsyslog_limit_repaired::
"${syslog_restart_cmd}"
args => "restart",
classes => cf2_if_else("rsyslog_restarted", "cant_restart_rsyslog"),
comment => "restarting rsyslog";
reports:
rsyslogd.!check_rsyslog_version_present::
"@@Common@@result_error@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#The file ${g.rudder_tools}/check_rsyslog_version is missing";
rsyslog_limit_error::
"@@Common@@result_error@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#Could not remove limitation of message in rsyslog";
rsyslog_limit_repaired::
"@@Common@@log_repaired@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#Updated the rsyslog configuration to remove limitation of messages";
rsyslog_restarted::
"@@Common@@log_repaired@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#Configured logging system for report centralization";
cant_restart_rsyslog::
"@@Common@@result_error@@&TRACKINGKEY&@@Log system for reports@@None@@${g.execRun}##${g.uuid}@#Could not restart the logging system";
}
#######################################################
# Check if the cron daemon is running
# This only works with unix flavoured systems too
bundle agent check_cron_daemon
{
vars:
redhat.!fedora::
"cron_bin" string => "crond$";
"cron_restartcmd" string => "/etc/init.d/crond restart";
fedora::
"cron_bin" string => "/usr/sbin/crond -n$";
"cron_restartcmd" string => "/bin/systemctl restart crond.service";
ubuntu::
"cron_bin" string => "cron$";
"cron_restartcmd" string => "/etc/init.d/cron restart";
!(redhat|fedora|ubuntu)::
"cron_bin" string => "/usr/sbin/cron$";
"cron_restartcmd" string => "/etc/init.d/cron restart";
processes:
!android.!windows::
"${cron_bin}"
restart_class => "restart_crond";
commands:
restart_crond::
"${cron_restartcmd}"
comment => "Restarting crond",
classes => kept_if_else("crond_ok" ,"crond_restarted" , "crond_failed");
reports:
crond_failed::
"@@Common@@result_error@@&TRACKINGKEY&@@CRON Daemon@@None@@${g.execRun}##${g.uuid}@#The CRON daemon was not running and could not be restarted";
crond_restarted::
"@@Common@@result_repaired@@&TRACKINGKEY&@@CRON Daemon@@None@@${g.execRun}##${g.uuid}@#The CRON daemon has been successfully restarted";
!restart_crond.!crond_restarted.!crond_failed.!android.!windows::
"@@Common@@result_success@@&TRACKINGKEY&@@CRON Daemon@@None@@${g.execRun}##${g.uuid}@#The CRON daemon is running";
android|windows::
"@@Common@@result_na@@&TRACKINGKEY&@@CRON Daemon@@None@@${g.execRun}##${g.uuid}@#This is a system without CRON: CRON verifications skipped !";
}
###################################################################
# Trash every output report and modified files older than the TTL #
###################################################################
bundle agent garbage_collection
{
files:
"${sys.workdir}/outputs"
delete => tidy,
file_select => days_old("&CFENGINE_OUTPUTS_TTL&"),
depth_search => recurse("inf");
"${g.rudder_var}/modified-files"
delete => tidy,
file_select => days_old("&MODIFIED_FILES_TTL&"),
depth_search => recurse("inf");
}
#######################################################
# Copy the CFengine binaries from the /opt repository
# to the CFengine working directory
bundle agent check_binaries_freshness
{
vars:
community_edition::
"components" slist => { "cf-agent", "cf-serverd", "cf-execd", "cf-monitord", "cf-promises", "cf-runagent", "cf-key", "rpmvercmp" };
files:
!android.!nova_edition::
"${sys.workdir}/bin/${components}"
perms => u_p("700"),
copy_from => cp("${g.rudder_bin}/${components}", "localhost"),
classes => kept_if_else("binaries_fresh", "binaries_rotten", "binaries_missing"),
action => immediate,
comment => "Copying the CFengine binaries from ${g.rudder_sbin}/sbin to ${sys.workdir}/bin";
reports:
binaries_fresh.!binaries_rotten.!binaries_missing::
"@@Common@@result_success@@&TRACKINGKEY&@@Binaries update@@None@@${g.execRun}##${g.uuid}@#The CFengine binaries in ${sys.workdir}/bin are up to date";
binaries_rotten.!binaries_missing::
"@@Common@@result_repaired@@&TRACKINGKEY&@@Binaries update@@None@@${g.execRun}##${g.uuid}@#The CFengine binaries have been updated in ${sys.workdir}/bin";
binaries_missing::
"@@Common@@result_error@@&TRACKINGKEY&@@Binaries update@@None@@${g.execRun}##${g.uuid}@#An error occurred while updating the CFengine binaries in ${sys.workdir}/bin";
android::
"@@Common@@result_success@@&TRACKINGKEY&@@Binaries update@@None@@${g.execRun}##${g.uuid}@#This is an android machine: no CFEngine binaries update needed";
nova_edition::
"@@Common@@result_na@@&TRACKINGKEY&@@Binaries update@@None@@${g.execRun}##${g.uuid}@#This is an CFEngine enterprise system: binaries update are handled differently";
}
#######################################################
body agent control
{
# if default runtime is 5 mins we need this for long jobs
ifelapsed => "1";
#define here some environment variables
environment => { "DEBIAN_FRONTEND=noninteractive" };
abortclasses => { "should_not_continue" };
agentfacility => "LOG_LOCAL6";
skipidentify => "&SKIPIDENTIFY&";
# Repository where to put the copy of modified files
default_repository => "${g.rudder_var}/modified-files";
}
#######################################################
body executor control
{
splaytime => "&AGENT_RUN_SPLAYTIME&";
schedule => { &AGENT_RUN_SCHEDULE& };
executorfacility => "LOG_DAEMON";
windows::
# CFEngine best practice is to use full paths on Windows
exec_command => "${sys.cf_agent} -f \"${sys.workdir}\inputs\failsafe.cf\" \& ${sys.cf_agent}";
!windows::
exec_command => "${sys.cf_agent} -f failsafe.cf \&\& ${sys.cf_agent}";
}
########################################################
#Enforce that the file only contains this information
bundle edit_line enforce_content(str)
{
delete_lines:
"${str}" not_matching => "true";
insert_lines:
"${str}";
}
# Fix syslogd content : caution, the @ must be in the argument
bundle edit_line fix_syslogd(syslogd)
{
delete_lines:
any::
"^(local6)\s+(?!${syslogd}).*"
comment => "Delete missconfigured rudder syslogd destination";
"^local6\.\*\s+${syslogd}"
comment => "Delete old rudder syslogd format";
insert_lines:
any::
"# Rudder specific logging parameters";
"local6.notice ${syslogd}"
comment => "Add the rudder syslogd destination";
}
bundle edit_line edit_syslog_conf_file(line_to_add, pattern_to_remove)
{
delete_lines:
"${pattern_to_remove}";
"\$\(syslog_ng_conf\)";
insert_lines:
"${line_to_add}"
location => syslogng_log_part;
}
body location syslogng_log_part
{
select_line_matching => "^\s*log\s*\{.*";
before_after => "before";
first_last => "first";
}
bundle edit_line ensure_rsyslogd_on_suse
{
field_edits:
# match a line starting like 'SYSLOG_DAEMON=something'
"^SYSLOG_DAEMON=.*$"
edit_field => col("=","2","\"rsyslogd\"","set"),
comment => "Match a line starting like key = something";
}
#####################################################################################
# Copyright 2012 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#
# Rudder Promise Body and Bundle Library
#
# This library includes standardized bundles and bodies to be used as part of the
# "best practices" in the Techniques writing
#
##################################################
# classes body
##################################################
#
# Automatically defines classes bases on a given prefix
# The classes are defined based on the romises outcome
#
body classes rudder_common_classes(prefix)
{
promise_kept => { "${prefix}_kept" };
promise_repaired => { "${prefix}_repaired" };
repair_failed => { "${prefix}_failed" , "${prefix}_error" };
repair_denied => { "${prefix}_denied" , "${prefix}_error" };
repair_timeout => { "${prefix}_timeout", "${prefix}_error" };
}
#
# Automatically defines classes bases on a given prefix
# The classes are defined based on the promises outcome
# Same as above but persist classes for ${persist} mins
#
body classes rudder_common_classes_persist(prefix, persist)
{
promise_kept => { "${prefix}_kept" };
promise_repaired => { "${prefix}_repaired" };
repair_failed => { "${prefix}_failed" , "${prefix}_error" };
repair_denied => { "${prefix}_denied" , "${prefix}_error" };
repair_timeout => { "${prefix}_timeout", "${prefix}_error" };
persist_time => ${persist};
}
#
# Always define a class, with the given persist time
# Define the class for ${persist} minutes
#
body classes rudder_always_classes_persist(always, persist)
{
promise_kept => { "${always}" };
promise_repaired => { "${always}" };
repair_failed => { "${always}" };
repair_denied => { "${always}" };
repair_timeout => { "${always}" };
persist_time => "${persist}";
}
##################################################
# files bundles
##################################################
#
# Insert the standard Rudder disclaimer into a file
#
bundle edit_line rudder_common_disclaimer
{
insert_lines:
"${rudder_parameters.rudder_file_edit_header}"
location => start,
insert_type => "preserve_block";
}
#
# Select files older than X months
#
body file_select rudder_common_months_old(months)
{
mtime => irange(0,ago(0,"${months}",0,0,0,0));
file_result => "mtime";
}
#
# Select files older than X days
#
body file_select rudder_common_days_old(days)
{
mtime => irange(0,ago(0,0,"${days}",0,0,0));
file_result => "mtime";
}
#
# Select files older than X hours
#
body file_select rudder_common_hours_old(hours)
{
mtime => irange(0,ago(0,0,0,"${hours}",0,0));
file_result => "mtime";
}
#
# Select files older than X minutes
#
body file_select rudder_common_minutes_old(minutes)
{
mtime => irange(0,ago(0,0,0,0,"${minutes}",0));
file_result => "mtime";
}
# enforce content of section
bundle edit_line rudder_ensure_section_content(section_start, section_end, content)
{
vars:
"csection" string => canonify("${section_start}");
"escaped_section_start" string => escape(${section_start});
"escaped_section_end" string => escape(${section_end});
classes:
# Detect if section is already there
"has_${csection}" expression => regline("${escaped_section_start}", "${edit.filename}");
delete_lines:
".*"
select_region => rudder_section_selector("${escaped_section_start}", "${escaped_section_end}"),
ifvarclass => "has_${csection}";
insert_lines:
# Insert new, empty section if it doesn't exist already.
"${section_start}
${section_end}"
insert_type => "preserve_block",
ifvarclass => "!has_${csection}";
# Insert missing lines into the section
"${content}"
select_region => rudder_section_selector("${escaped_section_start}", "${escaped_section_end}");
}
body select_region rudder_section_selector(section_start, section_end)
{
select_start => "${section_start}";
select_end => "${section_end}";
}
################################################
# Reporting bundles
################################################
#
# Create and send a report to the server
# This bundle takes 6 parameters :
# technique_name : the name of the technique, human readable
# status : the status of the Component, among the following values
# result_success
# result_error
# result_repaired
# log_repaired (for logging only)
# log_warn (for logging only)
# log_info (for logging only)
# log_debug (for logging only)
# log_trace (for logging only)
# identifier : the identifier of the current Rule and Directive
# component_name : the name of the component within the Technique
# component_key : the value of the component reference variable (or None if undefined)
# message : An explanation message understandable by a human
#
bundle agent rudder_common_report(technique_name, status, identifier, component_name, component_key, message)
{
reports:
cfengine_3::
"@@${technique_name}@@${status}@@${identifier}@@${component_name}@@${component_key}@@${g.execRun}##${g.uuid}@#${message}";
}
#
# Automatically create reports based on existing classes starting by
# class_prefix (as defined by the body classes rudder_common_classes)
# Takes 6 parameters
# technique_name : the name of the technique, human readable
# class_prefix : the prefix of a set of classes to reporting on (suffixes with "kept", "repaired" or "error")
# identifier : the identifier of the current Rule and Directive
# component_name : the name of the component within the Technique
# component_key : the value of the component reference variable (None if it does not exists)
# message_prefix : The begining of an explanation message understandable by a human
#
bundle agent rudder_common_reports_generic(technique_name, class_prefix, identifier, component_name, component_key, message_prefix)
{
methods:
"success"
usebundle => rudder_common_report("${technique_name}", "result_success", "${identifier}", "${component_name}", "${component_key}", "${message_prefix} was correct"),
ifvarclass => "${class_prefix}_kept.!${class_prefix}_repaired.!${class_prefix}_error";
"repaired"
usebundle => rudder_common_report("${technique_name}", "result_repaired", "${identifier}", "${component_name}", "${component_key}", "${message_prefix} was repaired"),
ifvarclass => "${class_prefix}_repaired.!${class_prefix}_error";
"error"
usebundle => rudder_common_report("${technique_name}", "result_error", "${identifier}", "${component_name}", "${component_key}", "${message_prefix} could not be repaired"),
ifvarclass => "${class_prefix}_error";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#######################################################
#
# Site specific promises
#
#######################################################
bundle common g
{
vars:
android::
"rudder_base" string => "/data/rudder";
"rudder_var" string => "/data/rudder";
"rudder_curl" string => "/system/bin/curl";
"rudder_rm" string => "/system/xbin/rm";
!windows.!android::
"rudder_base" string => "/opt/rudder";
"rudder_curl" string => "/usr/bin/curl";
"rudder_rm" string => "/bin/rm";
solaris::
"rudder_var" string => "/opt/rudder/var";
!solaris.!windows.!android::
"rudder_var" string => "/var/rudder";
!windows::
"rudder_bin" string => "${rudder_base}/bin";
"rudder_sbin" string => "${rudder_base}/sbin";
"rudder_var_tmp" string => "${rudder_var}/tmp"; # tmp generated data
"rudder_base_sbin" string => "${rudder_base}/sbin"; #folder where tools are installed
"rudder_inventories" string => "${rudder_var}/inventories";
"uuid_file" string => "${rudder_base}/etc/uuid.hive";
"rudder_disable_agent_file" string => "${rudder_base}/etc/disable-agent";
"rudder_tools" string => "${rudder_var}/tools";
"rudder_ncf" string => "${rudder_var}/ncf";
"crontab" string => "/etc/crontab";
"gzip" string => "/bin/gzip";
# DEPRECATED: This variable is used in pre-2.9 Techniques.
"rudder_dependencies" string => "${rudder_var}/tools";
windows::
"rudder_base" string => "${sys.winprogdir}\Rudder";
"rudder_bin" string => "${rudder_base}\bin";
"rudder_sbin" string => "${rudder_base}\sbin";
"rudder_var" string => "${sys.winprogdir}\Rudder\var";
"rudder_var_tmp" string => "${rudder_var}\tmp"; # tmp generated data
"rudder_base_sbin" string => "${rudder_base}\sbin"; #folder where tools are installed
"rudder_inventories" string => "${rudder_var}\inventories";
"rudder_base_sbin_arg" string => "${sys.winprogdir}\Rudder\sbin"; # for the installer command line
"rudder_tools" string => "${rudder_sbin}";
"rudder_ncf" string => "${rudder_base}\ncf";
"escaped_workdir" string => escape("${sys.workdir}");
"rudder_curl" string => "\"${rudder_base_sbin}\curl\curl.exe\"";
"uuid_file" string => "${rudder_base}\etc\uuid.hive";
"rudder_disable_agent_file" string => "${rudder_base}\etc\disable-agent";
# DEPRECATED: This variable is used in pre-2.9 Techniques.
"rudder_dependencies" string => "${rudder_sbin}";
any::
"uuid" string => readfile("${g.uuid_file}", 60);
"server_shares_folder" string => "/var/rudder/share/${uuid}/promises/shares";
"rudder_var_reports" string => "${rudder_var}/reports";
"davuser" string => "&DAVUSER&";
"davpw" string => "&DAVPASSWORD&";
"minicurl" string => "${rudder_bin}/rudder-perl ${sys.workdir}/inputs/common/utilities/minicurl";
"excludedreps" slist => { "\.X11", ".*kde.*", "\.svn", "perl" };
"rudder_tools_origin" string => "/var/rudder/tools";
# Path where all the configurations (git with techniques, groups, ncf, etc) are stored
"rudder_configuration_repository"
string => "&CONFIGURATION_REPOSITORY_FOLDER&";
"rudder_ncf_origin_common" string => "/usr/share/ncf/tree";
"rudder_ncf_origin_local" string => "${rudder_configuration_repository}/ncf";
"rudder_tools_updated_origin" string => "${rudder_tools_origin}/rudder_tools_updated";
"rudder_tools_updated" string => "${rudder_tools}/rudder_tools_updated";
# DEPRECATED: This variable is used in pre-2.9 Techniques.
"rudder_dependencies_origin" string => "/var/rudder/tools";
# The time at which the execution started
(linux|cygwin).!(centos_3|redhat_3|centos_4|redhat_4)::
"execRun" string => execresult("/bin/date --rfc-3339=second", "noshell");
(linux|cygwin).(centos_3|redhat_3|centos_4|redhat_4)::
# We would like to use date's "--rfc-3339=second" option here, but it is not available on older OSes (RHEL 3/4, AIX 5...)
"execRun" string => execresult("/bin/date -u \"+%Y-%m-%d %T+00:00\"", "noshell");
windows.!cygwin::
"execRun" string => execresult("\"${g.rudder_sbin}\getDate.bat\"", "noshell");
android::
"execRun" string => execresult("/system/xbin/date \"+%Y-%m-%d %T%z\" | sed 's/\([-+][0-9][0-9]\)\([0-9][0-9]\)$/\1:\2/'", "useshell");
aix::
# AIX's date command doesn't have a "%z" option, so we fake it by using UTC
"execRun" string => execresult("/bin/date -u \"+%Y-%m-%d %T+00:00\"", "noshell");
!linux.!cygwin.!windows.!android.!aix::
"execRun" string => execresult("/bin/date \"+%Y-%m-%d %T%:z\"", "noshell");
classes:
"curl_installed" expression => isexecutable("${rudder_curl}");
}
&AGENT_RUN_INTERVAL&
#####################################################################################
# Copyright 2011-2012 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#
# This is Rudder's library of common CFEngine functions.
#
# Only bodies and editbundles are to be appended here !!!
#
#####################################################################################
###################################################
# Knowledge from the original stdlib
###################################################
# Uses a specific prefix to avoid collision
# when the stdlib will be updated
###################################################
bundle common rudder_debian_knowledge
# @depends paths
# @brief common Rudder Debian knowledge bundle
#
# This common bundle has useful information about Debian.
{
vars:
"dpkg_compare_equal" string => "/usr/bin/dpkg --compare-versions '${v1}' eq '${v2}'";
"dpkg_compare_less" string => "/usr/bin/dpkg --compare-versions '${v1}' lt '${v2}'";
}
bundle common rudder_rpm_knowledge
# @depends paths
# @brief common Rudder RPM knowledge bundle
#
# This common bundle has useful information about platforms using RPM
{
vars:
"rpm_compare_equal" string => "${sys.workdir}/bin/rpmvercmp '${v1}' eq '${v2}'";
"rpm_compare_less" string => "${sys.workdir}/bin/rpmvercmp '${v1}' lt '${v2}'";
}
###################################################
body depth_search recurse_visible(d)
{
depth => "${d}";
exclude_dirs => { "\..*" };
}
#perms validation
body perms u_p(p)
{
mode => "${p}";
}
#########################################################
#server may be a list
body copy_from cp(from,server)
{
servers => { "${server}" };
source => "${from}";
compare => "digest";
community_edition::
portnumber => "&COMMUNITYPORT&";
}
body copy_from scp(from, server,compare,trustkey,preserve,purge)
{
servers => { "${server}" };
source => "${from}";
compare => "${compare}";
encrypt => "true";
verify => "true";
trustkey => "${trustkey}";
preserve => "${preserve}"; #preserver permissions
purge => "${purge}";
copy_backup => "timestamp";
community_edition::
portnumber => "&COMMUNITYPORT&";
}
# This is an evolved version of copy_from scp that uses local copies if we are
# running on a policy server instead of copying from a localhost remote blindly.
body copy_from rudder_copy_from(from, server,compare,trustkey,preserve,purge) {
source => "${from}";
compare => "${compare}";
encrypt => "true";
verify => "true";
trustkey => "${trustkey}";
preserve => "${preserve}"; # Preserve the permissions
purge => "${purge}";
copy_backup => "timestamp";
!root_server::
servers => { "${server}" };
community_edition::
portnumber => "&COMMUNITYPORT&";
}
body copy_from copy(from)
{
source => "${from}";
copy_backup => "false";
preserve => "true";
}
body copy_from copy_digest(from)
{
source => "${from}";
copy_backup => "timestamp";
preserve => "true";
compare => "digest";
}
#########################################################
# This body is deprecated, and should not be used anymore
#########################################################
body classes class_trigger(if,else,kept)
{
promise_kept => { "${kept}" };
promise_repaired => { "${if}" };
repair_failed => { "${else}" };
repair_denied => { "${else}" };
repair_timeout => { "${else}" };
}
#########################################################
body location append
{
before_after => "after";
}
#########################################################
body package_method yum_remi
{
package_changes => "bulk";
package_list_command => "/usr/bin/yum list installed";
package_list_name_regex => "([^.]+).*";
package_list_version_regex => "[^\s]\s+([^\s]+).*";
package_list_arch_regex => "[^.]+\.([^\s]+).*";
package_installed_regex => ".*installed.*";
package_name_convention => "${name}.${arch}";
package_delete_convention => "${name}";
package_add_command => "/usr/bin/yum --enablerepo=remi -y install";
package_delete_command => "/bin/rpm -e";
package_verify_command => "/bin/rpm -V";
}
#perms validation
body perms p(user,mode)
{
owners => { "${user}" };
mode => "${mode}";
}
############################################
body file_select cf3_files
{
leaf_name => { "cf-.*" };
file_result => "leaf_name";
}
#########################################################
body changes lay_trip_wire
{
hash => "best";
report_changes => "content";
update_hashes => "yes";
}
########################################################
body action longjob
{
ifelapsed => "240"; # run only every 4 hours
}
#######################################################
# For the library
#######################################################
body edit_defaults noempty_backup
{
empty_file_before_editing => "false";
edit_backup => "timestamp"; # we want to keep a track of everything
max_file_size => "1024000";
}
body edit_defaults empty_backup
{
empty_file_before_editing => "true";
edit_backup => "timestamp";
max_file_size => "1024000";
}
body edit_defaults def_no_backup
{
empty_file_before_editing => "false";
edit_backup => "false";
max_file_size => "1024000";
}
########################################################
########################################################
bundle edit_line DeleteLinesMatching(regex)
{
delete_lines:
"${regex}"
action => WarnOnly;
}
########################################################
body action WarnOnly
{
action_policy => "warn";
}
########################################
# Bodies
########################################
body replace_with With(x)
{
replace_value => "${x}";
occurrences => "all";
}
########################################
################################
# For commands with a >
################################
body contain outputable
{
useshell => "true";
no_output => "false";
}
################################
# For commands with a >, in a dir
################################
body contain outputable_dir(dir)
{
useshell => "true";
no_output => "false";
chdir => "${dir}";
}
################################
# Process is launched ?
################################
body process_count islaunched(class)
{
match_range => irange("1", "500");
in_range_define => { "${class}"};
out_of_range_define => {"no_${class}"};
}
###########################################################################################
# Cancel class
# Cancel every classes passed by argument
##########################################################################################
body classes cancel_all_classes(class_to_cancel) {
cancel_kept => { "${class_to_cancel}" };
cancel_repaired => { "${class_to_cancel}" };
cancel_notkept => { "${class_to_cancel}" };
}
###########################################################################################
# Persistent class
# If the promise is repaired, define repaired for length minutes and undefine failed
# If the promise is not kept, undefine repaired and define failed for length minutes
##########################################################################################
body classes persistant_class(repaired, failed, length)
{
promise_repaired => { "${repaired}" };
repair_failed => { "${failed}" };
repair_denied => { "${failed}" };
repair_timeout => { "${failed}" };
cancel_repaired => {"${failed}"};
cancel_notkept => {"${repaired}"};
persist_time => "${length}";
}
###########################################################################################
# Persistent class
# If the promise is repaired/kept, define repaired for length minutes and undefine failed
# If the promise is not kept, undefine repaired and define failed for length minutes
##########################################################################################
body classes set_persist_classes(repaired, failed, length)
{
promise_kept => { "${repaired}" };
promise_repaired => { "${repaired}" };
repair_failed => { "${failed}" };
repair_denied => { "${failed}" };
repair_timeout => { "${failed}" };
cancel_kept => {"${failed}"};
cancel_repaired => {"${failed}"};
cancel_notkept => {"${repaired}"};
persist_time => "${length}";
}
################################################
# kept_if_else
# set kept if the promise is kept
# yes if repaired
# no if cannot repair
################################################
body classes kept_if_else(kept, yes,no)
{
promise_kept => { "${kept}" };
promise_repaired => { "${yes}" };
repair_failed => { "${no}" };
repair_denied => { "${no}" };
repair_timeout => { "${no}" };
}
#########################################
# Make a local copy with a digest check #
#########################################
body copy_from digest_cp(from)
{
source => "${from}";
compare => "digest";
copylink_patterns => { ".*" };
copy_backup => "timestamp";
}
################################################
# kept_if_else with persistant classes
# set kept if the promise is kept
# yes if repaired
# no if cannot repair
################################################
body classes kept_if_else_persist(kept, repaired, failed, persist) {
promise_kept => { "${kept}" };
promise_repaired => { "${repaired}" };
repair_failed => { "${failed}" };
repair_denied => { "${failed}" };
repair_timeout => { "${failed}" };
persist_time => "${persist}";
}
################################################
# Special kept_if_else
# set kept if the promise is kept
# yes if repaired
# no if cannot repair
# Trigger an additionnal promise if repaired
################################################
body classes kept_if_else_hook(kept,yes,no,hook)
{
promise_kept => { "${kept}" };
promise_repaired => { "${yes}", "${hook}" };
repair_failed => { "${no}" };
repair_denied => { "${no}" };
repair_timeout => { "${no}" };
}
################################################
# Simple group adjustment body
################################################
body perms group(group)
{
groups => { "${group}" };
}
################################################
# Same as recurse but without xdev
# and including the current dir
################################################
body depth_search recurse_with_current(d)
{
depth => "${d}";
include_basedir => "true";
xdev => "false";
}
########################################################################
# Mount an NFS share, and allow the user to select if it is persistent #
########################################################################
body mount rudder_nfs(server,source,type,persistence)
{
mount_type => "${type}";
mount_source => "${source}";
mount_server => "${server}";
edit_fstab => "${persistence}";
}
########################################################################
# Same as std_defs, allowing user to specify the file erase policy #
########################################################################
body edit_defaults rudder_empty_select(select)
{
empty_file_before_editing => "${select}";
max_file_size => "1024000";
edit_backup => "timestamp";
}
########################################################################
# Handle a directory recursively, including the dir itself #
########################################################################
body depth_search recurse_withroot(d)
{
depth => "${d}";
# xdev => "true";
include_basedir => "true";
}
########################################################################
# Change group and mode of a file/directory #
########################################################################
body perms mg(mode,group)
{
groups => { "${group}" };
mode => "${mode}";
}
########################################################################
# Select a file using a date AND a pattern #
########################################################################
body file_select date_pattern(age, pattern)
{
mtime => irange("0", ago(0,0,"${age}",0,0,0));
leaf_name => { "${pattern}" };
file_result => "leaf_name.mtime";
}
########################################################################
# Install a package using rug #
########################################################################
body package_method rudder_rug
{
package_changes => "individual";
package_list_command => "/bin/rpm -qa --queryformat \"i | repos | %{name} | %{version}-%{release} | %{arch}\n\"";
package_list_update_ifelapsed => "240";
package_installed_regex => "i.*";
package_list_name_regex => "[^|]+\|[^|]+\|\s+([^\s]+).*";
package_list_version_regex => "[^|]+\|[^|]+\|[^|]+\|\s+([^\s]+).*";
package_list_arch_regex => "[^|]+\|[^|]+\|[^|]+\|[^|]+\|\s+([^\s]+).*";
package_name_convention => "${name}";
package_add_command => "/usr/bin/rug install -y";
package_delete_command => "/usr/bin/rug remove -y";
package_update_command => "/usr/bin/rug update -y";
package_verify_command => "/usr/bin/rug verify -y$"; # $ means no args
# make correct version comparisons
package_version_less_command => "${rudder_rpm_knowledge.rpm_compare_less}";
package_version_equal_command => "${rudder_rpm_knowledge.rpm_compare_equal}";
}
########################################################################
# Install a package using yum but with a check from rpm #
########################################################################
body package_method rudder_yum
{
package_changes => "bulk";
package_list_command => "/bin/rpm -qa --qf '%{name} %{version}-%{release} %{arch}\n'";
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_command => "/usr/bin/yum --quiet check-update";
package_list_update_ifelapsed => "240";
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_patch_command => "/usr/bin/yum -y update";
package_delete_command => "/bin/rpm -e --nodeps --allmatches";
package_verify_command => "/bin/rpm -V";
# make correct version comparisons
package_version_less_command => "${rudder_rpm_knowledge.rpm_compare_less}";
package_version_equal_command => "${rudder_rpm_knowledge.rpm_compare_equal}";
}
###################################################
# edit_line prepend
###################################################
bundle edit_line prepend(lines)
{
insert_lines:
"${lines}"
comment => "Prepending line: ${lines}",
location => start;
}
###################################################
# edit_line rudder_line_insertion
###################################################
bundle edit_line rudder_line_insertion(lines, location)
{
insert_lines:
"${lines}"
comment => "Adding line: ${lines}",
location => rudder_location_before_after("${location}");
}
#########################################################
body location rudder_location_before_after(location)
{
before_after => "${location}";
}
###################################################
# edit_line replace_line
###################################################
bundle edit_line replace_line(regex,replacement)
{
replace_patterns:
"${regex}"
replace_with => With("${replacement}"),
comment => "Replace every occurence of ${regex} with ${replacement}";
}
###################################################
# edit_line from_to
###################################################
bundle edit_line from_to(from,to)
{
delete_lines:
"${from}" comment => "Reset ${from}";
insert_lines:
"${to}" comment => "Add ${to}";
}
###################################################
# contain in_shell_silent
###################################################
body contain in_shell_silent
{
useshell => "true";
no_output => "true";
}
###################################################
# edit_line insert_rudder_disclaimer
###################################################
bundle edit_line insert_rudder_disclaimer
{
insert_lines:
"${rudder_parameters.rudder_file_edit_header}"
location => start;
}
###################################################
# edit_line rudder_change_aix_password_entry
###################################################
bundle edit_line rudder_change_aix_password_entry(user, entry, content)
{
field_edits:
"\s*${entry}\s*=.*"
select_region => rudder_aix_user_section("${user}"),
edit_field => col("=","2"," ${content}","set");
}
###################################################
# select_region rudder_aix_user_section
###################################################
body select_region rudder_aix_user_section(x)
{
select_start => "${x}:\s*";
select_end => "\S*:\s*";
}
#####################################################################################
# Copyright 2014 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#
# This promise installs and configures nxlog
#
# This program monitors the windows event log and sends every
# Nova related information to a remote syslog, the Rudder main server
# in our case.
bundle agent nxlog_enable
{
methods:
windows::
"any" usebundle => nxlog_install;
"any" usebundle => nxlog_configure;
&if(NOVA)&
"any" usebundle => nxlog_launch;
&endif&
(nxlog_install_repaired|nxlog_configure_repaired|nxlog_service_repaired).!(nxlog_install_error|nxlog_configure_error|nxlog_service_error)::
"report" usebundle => rudder_common_report("Common", "result_repaired", "&TRACKINGKEY&", "Log system for reports", "None", "NXLog service was not installed, configured and running. Fixed.");
!nxlog_install_repaired.!nxlog_install_error.nxlog_configure_kept.!nxlog_configure_repaired.!nxlog_configure_error.nxlog_service_kept.!nxlog_service_repaired.!nxlog_service_error::
"report" usebundle => rudder_common_report("Common", "result_success", "&TRACKINGKEY&", "Log system for reports", "None", "NXLog service already installed, configured and running as expected.");
}
bundle common nxlog_common
{
vars:
windows::
"nxlog_exe" string => "${g.rudder_tools}/nxlog-ce-2.8.1248.msi";
"nxlog_tpl" string => "${g.rudder_tools}/nxlog.conf";
}
bundle agent nxlog_install
{
classes:
!x86_64::
"nxlog_ok" expression => fileexists("${sys.winprogdir}\nxlog\nxlog.exe");
x86_64::
"nxlog_ok" expression => fileexists("${sys.winprogdir86}\nxlog\nxlog.exe");
methods:
nxlog_install_repaired::
"report" usebundle => rudder_common_report("Common", "log_repaired", "&TRACKINGKEY&", "Log system for reports", "None", "Installed NXLog");
nxlog_install_failed::
"report" usebundle => rudder_common_report("Common", "result_error", "&TRACKINGKEY&", "Log system for reports", "None", "Failed to install NXLog");
commands:
windows.!nxlog_ok::
"\"${sys.winsysdir}\msiexec.exe\""
args => "/q /i \"${g.rudder_sbin}\nxlog-ce-2.8.1248.msi",
classes => rudder_common_classes("nxlog_install"),
comment => "Installing nxlog";
}
bundle agent nxlog_configure
{
vars:
!x86_64::
"nxlog_config_file" string => "${sys.winprogdir}\nxlog\conf\nxlog.conf";
"install_path" string => "${sys.winprogdir}";
x86_64::
"nxlog_config_file" string => "${sys.winprogdir86}\nxlog\conf\nxlog.conf";
"install_path" string => "${sys.winprogdir86}";
files:
"${nxlog_config_file}"
create => "true",
classes => rudder_common_classes("nxlog_configure"),
edit_line => nxlog_parameters("${server_info.cfserved}", "&SYSLOGPORT&", "TCP", "${nxlog_common.nxlog_tpl}", "${nxlog_configure.install_path}"),
edit_defaults => empty_backup;
methods:
nxlog_configure_error::
"report" usebundle => rudder_common_report("Common", "result_error", "&TRACKINGKEY&", "Log system for reports", "None", "Failed to configure NXLog");
nxlog_configure_repaired::
"report" usebundle => rudder_common_report("Common", "log_repaired", "&TRACKINGKEY&", "Log system for reports", "None", "Update NXLog configuration");
}
&if(NOVA)&
bundle agent nxlog_launch
{
methods:
nxlog_service_error::
"report" usebundle => rudder_common_report("Common", "result_error", "&TRACKINGKEY&", "Log system for reports", "None", "Error while checking or restarting NXLog server");
nxlog_service_repaired::
"report" usebundle => rudder_common_report("Common", "log_repaired", "&TRACKINGKEY&", "Log system for reports", "None", "NXLog was restarted");
services:
"nxlog"
service_policy => "start",
service_method => u_bootstart,
classes => rudder_common_classes("nxlog_service");
}
&endif&
# Parameters are used in the template, expanded thanks to the expand_scalars => true
bundle edit_line nxlog_parameters(server, port, protocol, template, install_path)
{
insert_lines:
"${template}"
insert_type => "file",
expand_scalars => "true";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent internal_security
{
vars:
!windows::
"mode" string => "600";
"user" string => "root";
"group" string => "0"; # This is "root" on most UNIX-like systems, but "system" on AIX
#windows::
# "mode" string => "755";
# "user" string => "Administrator";
# "group" string => "Administrators";
files:
!windows::
"${g.rudder_var}/cfengine-community/inputs"
depth_search => recurse("inf"),
perms => mog("${mode}", "${user}", "${group}"),
classes => kept_if_else("security_sanitization_ok", "security_sanitization_repaired", "security_sanitization_failed");
"${g.rudder_var}/cfengine-community/inputs"
perms => mog("${mode}", "${user}", "${group}"),
classes => kept_if_else("security_sanitization_ok", "security_sanitization_repaired", "security_sanitization_failed");
"${g.rudder_var}/cfengine-community/ppkeys"
depth_search => recurse("inf"),
perms => mog("${mode}", "${user}", "${group}"),
classes => kept_if_else("security_sanitization_ok", "security_sanitization_repaired", "security_sanitization_failed");
"${g.rudder_var}/cfengine-community/ppkeys"
perms => mog("${mode}", "${user}", "${group}"),
classes => kept_if_else("security_sanitization_ok", "security_sanitization_repaired", "security_sanitization_failed");
reports:
security_sanitization_ok.!security_sanitization_repaired::
"@@Common@@result_success@@&TRACKINGKEY&@@Security parameters@@None@@${g.execRun}##${g.uuid}@#The internal environment security is acceptable";
security_sanitization_repaired::
"@@Common@@result_repaired@@&TRACKINGKEY&@@Security parameters@@None@@${g.execRun}##${g.uuid}@#Some internal security parameters were adjusted";
security_sanitization_failed::
"@@Common@@result_error@@&TRACKINGKEY&@@Security parameters@@None@@${g.execRun}##${g.uuid}@#The internal environment security is NOT acceptable!";
windows::
"@@Common@@result_success@@&TRACKINGKEY&@@Security parameters@@None@@${g.execRun}##${g.uuid}@#No internal security parameters defined for Windows OSes yet";
}
#####################################################################################
# Copyright 2014 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent check_zypper
{
commands:
SuSE::
"${g.rudder_tools}/check_zypper_version"
module => "true";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent process_matching
{
vars:
# This deliberately excludes cf-execd which is handled separately below
"cf_components" slist => {
"cf-key",
# "cf-monitord", Disabled
"cf-promises",
"cf-runagent",
"cf-serverd"
};
windows::
"stop_signal" string => "kill";
!windows::
"stop_signal" string => "term";
classes:
"restart_cf" expression => "Hr05.Min00_05";
files:
linux::
# This is to cleanup /etc/crontab from pre-2.5 usage
# and initial promises before 2.7
"${g.crontab}"
edit_defaults => noempty_backup,
edit_line => cron_cleanup;
# Temporary cron file added by rudder-agent postinst to prevent from UUID removal.
# When this promise will be generated, this cron will be useless then removed.
# (see http://www.rudder-project.org/redmine/issues/3925 and http://www.rudder-project.org/redmine/issues/3930).
"/etc/cron.d/rudder-agent-uuid" delete => tidy;
community_edition.!aix::
"/etc/cron.d/rudder-agent"
create => "true",
perms => mog("644", "root", "root"),
edit_defaults => empty_backup,
edit_line => expand_template("${sys.workdir}/inputs/common/cron/rudder_agent_community_cron");
&if(NOVA)&
nova_edition.!aix.!windows::
"/etc/cron.d/rudder-agent-nova"
create => "true",
perms => mog("644", "root", "root"),
edit_defaults => empty_backup,
edit_line => expand_template("${sys.workdir}/inputs/common/cron/rudder_agent_nova_cron");
&endif&
aix::
# Cleanup the crontab
"/var/spool/cron/crontabs/root"
edit_defaults => noempty_backup,
edit_line => delete_lines_matching("0,5,10,15,20,25,30,35,40,45,50,55 \* \* \* \* if \[ -x /opt/rudder/bin/check-rudder-agent \]; then /opt/rudder/bin/check-rudder-agent; fi");
# Add Rudder entry
"/var/spool/cron/crontabs/root"
create => "true",
perms => mog("600", "root", "cron"),
edit_line => insert_lines("0,5,10,15,20,25,30,35,40,45,50,55 * * * * if [ -x /opt/rudder/bin/check-rudder-agent ]; then /opt/rudder/bin/check-rudder-agent >/dev/null; fi"),
classes => rudder_common_classes("rudder_aix_crontab_insertion"),
comment => "Insert an AIX-compatible user crontab to run /opt/rudder/bin/check-rudder-agent";
processes:
windows::
# Always stop cf-monitord
"${g.escaped_workdir}\/bin\/cf-monitord" signals => { "${stop_signal}" };
!windows::
# Always stop cf-monitord
"${sys.workdir}/bin/cf-monitord" signals => { "${stop_signal}" };
restart_cf.!policy_server::
"${cf_components}" signals => { "${stop_signal}" };
# Policy servers have both Nova and Community, don't blindly kill the wrong processes
restart_cf.policy_server::
"${sys.workdir}/bin/${cf_components}" signals => { "${stop_signal}" };
restart_cf.!windows::
"${sys.workdir}/bin/cf-execd" signals => { "${stop_signal}" };
# Note: cron will get restarted automatically by init (respawn directive in inittab)
aix.rudder_aix_crontab_insertion::
"^/usr/sbin/cron" signals => { "${stop_signal}" };
&if(NOVA)&
services:
restart_cf.windows::
"CfengineNovaExec"
service_policy => "stop",
comment => "Stop the executor service, part of scheduled restart";
"CfengineNovaExec"
service_policy => "start",
comment => "Start the executor service, part of scheduled restart";
&endif&
commands:
restart_cf.!windows::
"${sys.cf_serverd}";
"${sys.cf_execd}";
reports:
restart_cf::
"Reloaded configuration of all Cfengine components";
}
# This is to cleanup /etc/crontab from pre-2.5 usage
# and initial promises before 2.7
bundle edit_line cron_cleanup
{
# Remove old lines to replace them with new version
delete_lines:
"0,5,10,15,20,25,30,35,40,45,50,55 \* \* \* \* root if \[ \`ps -efww \| grep cf-execd \| grep \"/var/cfengine/bin/cf-execd\" \| grep -v grep \| wc -l\` -eq 0 \]; then /var/cfengine/bin/cf-execd; fi";
"0,5,10,15,20,25,30,35,40,45,50,55 \* \* \* \* root if \[ \`ps -efww \| grep cf-execd \| grep \"/var/rudder/cfengine-community/bin/cf-execd\" \| grep -v grep \| wc -l\` -eq 0 \]; then /var/rudder/cfengine-community/bin/cf-execd; fi";
"0,5,10,15,20,25,30,35,40,45,50,55 \* \* \* \* root if \[ ! -e /opt/rudder/etc/disable-agent -a \`ps -efww \| grep cf-execd \| grep \"/var/rudder/cfengine-community/bin/cf-execd\" \| grep -v grep \| wc -l\` -eq 0 \]; then /var/rudder/cfengine-community/bin/cf-execd; fi";
"0,5,10,15,20,25,30,35,40,45,50,55 \* \* \* \* root if \[ ! -e /opt/rudder/etc/disable-agent -a \`ps -efww \| grep cf-execd \| grep \"/var/cfengine/bin/cf-execd\" \| grep -v grep \| wc -l\` -eq 0 \]; then /var/cfengine/bin/cf-execd; fi";
"0,5,10,15,20,25,30,35,40,45,50,55 \* \* \* \* root if \[ ! -e /opt/rudder/etc/disable-agent -a \`ps -efww \| grep cf-execd \| grep \"/var/cfengine/bin/cf-execd\" \| grep -v grep \| wc -l\` -eq 0 \]; then /var/cfengine/bin/cf-agent -f failsafe.cf \&\& /var/cfengine/bin/cf-agent; fi";
"0,5,10,15,20,25,30,35,40,45,50,55 \* \* \* \* root if \[ ! -e /opt/rudder/etc/disable-agent -a \`ps -efww \| grep cf-execd \| grep \"/var/rudder/cfengine-community/bin/cf-execd\" \| grep -v grep \| wc -l\` -eq 0 \]; then /var/rudder/cfengine-community/bin/cf-agent -f failsafe.cf \&\& /var/rudder/cfengine-community/bin/cf-agent; fi";
"0,5,10,15,20,25,30,35,40,45,50,55 \* \* \* \* root if \[ ! -e /opt/rudder/etc/disable-agent -a \`ps -efww \| grep -E \"\(cf-execd\|cf-agent\)\" \| grep -E \"/var/cfengine/bin/\(cf-execd\|cf-agent\)\" \| grep -v grep \| wc -l\` -eq 0 ]; then /var/cfengine/bin/cf-agent -f failsafe.cf \&\& /var/cfengine/bin/cf-agent; fi";
"0,5,10,15,20,25,30,35,40,45,50,55 \* \* \* \* root if \[ ! -e /opt/rudder/etc/disable-agent -a \`ps -efww \| grep -E \"\(cf-execd\|cf-agent\)\" \| grep -E \"/var/rudder/cfengine-community/bin/\(cf-execd\|cf-agent\)\" \| grep -v grep \| wc -l\` -eq 0 ]; then /var/rudder/cfengine-community/bin/cf-agent -f failsafe.cf \&\& /var/rudder/cfengine-community/bin/cf-agent; fi";
# Remove entry with wrong escapements from /etc/crontab
"0,5,10,15,20,25,30,35,40,45,50,55 \* \* \* \* root if \[ ! -e /opt/rudder/etc/disable-agent -a \`ps -efww \| grep -E \"\(cf-execd\|cf-agent\)\" \| grep -E \"/var/rudder/cfengine-community/bin/\(cf-execd\|cf-agent\)\" \| grep -v grep \| wc -l\` -eq 0 ]; then /var/rudder/cfengine-community/bin/cf-agent -f failsafe.cf \\\&\\\& /var/rudder/cfengine-community/bin/cf-agent; fi";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#
# Define what an agent has to do when it updates
# its promises
#
#simple copy method
body copy_from remote(server, path)
{
servers => {
"${server}"
};
encrypt => "true";
trustkey => "true";
source => "${path}";
compare => "digest";
preserve => "false"; #preserver permissions
verify => "true";
purge => "true";
community_edition::
portnumber => "&COMMUNITYPORT&";
}
#simple copy method, unencrypted
body copy_from remote_unsecured(server, path)
{
servers => {
"${server}"
};
encrypt => "false";
trustkey => "true";
source => "${path}";
compare => "mtime";
preserve => "true"; #preserver permissions
verify => "true";
purge => "true";
community_edition::
portnumber => "&COMMUNITYPORT&";
}
body copy_from copy_digest_without_perms(from)
{
source => "${from}";
copy_backup => "false";
preserve => "false";
compare => "digest";
purge => "true";
community_edition::
portnumber => "&COMMUNITYPORT&";
}
body copy_from remote_unsecured_without_perms(server, path)
{
servers => {
"${server}"
};
encrypt => "false";
trustkey => "true";
source => "${path}";
compare => "digest";
preserve => "false";
verify => "true";
purge => "true";
community_edition::
portnumber => "&COMMUNITYPORT&";
}
bundle common server_info
{
vars:
any::
"policy_files" string => "/var/rudder/share/&UUID&"; #directory where to look for promises in the server for that client
policy_server::
"cfserved" string => "&POLICYSERVER&";
!policy_server::
"policy_server_file"
string => translatepath("${sys.workdir}/policy_server.dat"),
comment => "Path to file containing address to policy server";
"cfserved" string => readfile("${policy_server_file}", 2048);
}
# The update is now split in two parts
# - the action part, only launched during failsafe
# it copies files, restarts deamons, defines persistent classes
# - the report part, not done during failsafe but during regular run
# note that if in verbose_mode, then the reporting will be done
# as well during failsafe
#
# Since the defined class are persistent, the classes are still
# available during the "normal" agent execution, for reporting
bundle agent update
{
methods:
failsafe::
"update" usebundle => update_action;
(!failsafe|verbose_mode)::
"report" usebundle => update_reports;
reports:
# We want to have always reports if something goes bad
rudder_promises_generated_error|no_update::
"*********************************************************************************
* rudder-agent could not get an updated configuration from the policy server. *
* This can be caused by a network issue, an unavailable server, or if this *
* node was deleted from the Rudder root server. *
* Any existing configuration policy will continue to be applied without change. *
*********************************************************************************"
action => immediate;
}
bundle agent update_action
{
vars:
"client_inputs" string => "${sys.workdir}/inputs"; #where to put the files on the client when downloaded
"file_to_check_update" string => "rudder_promises_generated";
nova_edition::
"server_inputs" string => "${server_info.policy_files}/rules/cfengine-nova"; #actual directory with promises
community_edition::
"server_inputs" string => "${server_info.policy_files}/rules/cfengine-community"; #actual directory with promises
files:
any::
"${g.rudder_ncf}/."
create => "true",
comment => "Make sure the ncf directory exists";
root_server::
"${g.rudder_ncf}/common"
copy_from => copy_digest_without_perms("${g.rudder_ncf_origin_common}"),
depth_search => recurse_ignore("inf", @{g.excludedreps}),
perms => u_mog("644", "root", "root"),
action => immediate,
classes => success("rudder_ncf_common_updated", "rudder_ncf_common_update_error", "rudder_ncf_common_updated_ok"),
comment => "Update the common Rudder ncf instance";
"${g.rudder_ncf}/local"
copy_from => copy_digest_without_perms("${g.rudder_ncf_origin_local}"),
depth_search => recurse_ignore("inf", @{g.excludedreps}),
perms => u_mog("644", "root", "root"),
action => immediate,
classes => success("rudder_ncf_local_updated", "rudder_ncf_local_update_error", "rudder_ncf_local_updated_ok"),
comment => "Update the local Rudder ncf instance";
!root_server::
"${g.rudder_ncf}/common"
copy_from => remote_unsecured_without_perms("${server_info.cfserved}", "${g.rudder_ncf_origin_common}"),
depth_search => recurse_ignore("inf", @{g.excludedreps}),
perms => u_mog("644", "root", "0"),
action => immediate,
classes => success("rudder_ncf_common_updated", "rudder_ncf_common_update_error", "rudder_ncf_common_updated_ok"),
comment => "Update the common Rudder ncf instance";
"${g.rudder_ncf}/local"
copy_from => remote_unsecured_without_perms("${server_info.cfserved}", "${g.rudder_ncf_origin_local}"),
depth_search => recurse_ignore("inf", @{g.excludedreps}),
perms => u_mog("644", "root", "0"),
action => immediate,
classes => success("rudder_ncf_local_updated", "rudder_ncf_local_update_error", "rudder_ncf_local_updated_ok"),
comment => "Update the local Rudder ncf instance";
"${client_inputs}/${file_to_check_update}"
copy_from => remote("${server_info.cfserved}","${server_inputs}/${file_to_check_update}"),
action => immediate,
classes => success("rudder_promises_generated_repaired", "rudder_promises_generated_error", "rudder_promises_generated_ok");
# The defined class are persistent, so if they are already set, promises has already been updated
# a short while ago
rudder_promises_generated_repaired.!root_server::
"${client_inputs}"
copy_from => remote("${server_info.cfserved}","${server_inputs}"),
depth_search => recurse("inf"),
action => immediate,
classes => success("config", "no_update", "config_ok");
root_server|(rudder_promises_generated_ok|(rudder_promises_generated_repaired.(config|config_ok)).!no_update.!rudder_promises_generated_error)::
# Every time we check update inputs successfully (already up to date or
# updated), touch a file to let other promises know we are doing ok
"${sys.workdir}/last_successful_inputs_update"
touch => "true";
# Copy the tools only if the file rudder_tools_updated is not up to date
any::
"${g.rudder_tools_updated}"
copy_from => remote_unsecured("${server_info.cfserved}", "${g.rudder_tools_updated_origin}"),
action => immediate,
classes => success("rudder_tools_updated_repaired", "rudder_tools_updated_error", "rudder_tools_updated_kept"),
comment => "Check if we need to update the tools";
# We copy only if we have the class rudder_tools_updated_repaired
rudder_tools_updated_repaired::
"${g.rudder_tools}"
copy_from => remote_unsecured("${server_info.cfserved}", "${g.rudder_tools_origin}"),
depth_search => recurse_ignore("inf", @{g.excludedreps}),
action => immediate,
classes => success("rudder_tools_updated", "rudder_tools_update_error", "rudder_tools_updated_ok"),
comment => "Update the Rudder tools";
processes:
config.!windows::
"cf-serverd" restart_class => "start_server";
config.!windows::
"cf-execd" restart_class => "start_exec";
&if(NOVA)&
services:
windows::
"CfengineNovaExec"
service_policy => "start",
service_method => u_bootstart,
classes => outcome("executor"),
comment => "Start the executor windows service now and at boot time";
&endif&
commands:
start_exec.!windows::
"${sys.cf_execd}"
action => u_ifwin_bg,
classes => outcome("executor");
start_exec.cygwin::
"${sys.cf_execd}"
action => u_ifwin_bg,
classes => outcome("executor");
start_server::
"${sys.cf_serverd}"
action => u_ifwin_bg,
classes => outcome("server");
#########################################################
reports:
server_ok::
"@@Common@@log_repaired@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Started the server (cf-serverd)";
executor_ok::
"@@Common@@log_repaired@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Started the scheduler (cf-execd)";
}
# This bundle is responsible for the reporting of what happened in the update
# It can work because the classes defined during the update are persistent, so
# the classes are available for the next 4 minutes
bundle agent update_reports
{
reports:
no_update::
"@@Common@@result_error@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Cannot update node's policy (CFEngine promises)";
rudder_tools_update_error::
"@@Common@@result_error@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Cannot update Rudder tools";
rudder_ncf_common_update_error::
"@@Common@@result_error@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Cannot update common Rudder ncf instance";
rudder_ncf_local_update_error::
"@@Common@@result_error@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Cannot update local Rudder ncf instance";
rudder_promises_generated_error::
"@@Common@@result_error@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Cannot update node's policy";
(rudder_promises_generated_ok|(rudder_tools_updated_ok.rudder_ncf_common_updated_ok.rudder_ncf_local_updated_ok.config_ok)).!(rudder_promises_generated_repaired|rudder_promises_generated_error|rudder_tools_updated|rudder_tools_update_error|rudder_ncf_common_updated|rudder_ncf_common_update_error|rudder_ncf_local_updated|rudder_ncf_local_update_error|config|no_update)::
"@@Common@@result_success@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Rudder policy, tools and ncf instance are already up to date. No action required.";
rudder_tools_updated::
"@@Common@@log_repaired@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Rudder tools updated";
rudder_ncf_common_updated::
"@@Common@@log_repaired@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Rudder ncf common instance updated";
rudder_ncf_local_updated::
"@@Common@@log_repaired@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Rudder ncf local instance updated";
config::
"@@Common@@log_repaired@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Node's policy (CFEngine promises) updated";
rudder_promises_generated_repaired|config|rudder_tools_updated|rudder_ncf_common_updated|rudder_ncf_local_updated|server_ok|executor_ok::
"@@Common@@result_repaired@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Rudder policy, tools or ncf instance were updated or CFEngine service restarted";
policy_server::
"@@Common@@result_success@@&TRACKINGKEY&@@Update@@None@@${g.execRun}##${g.uuid}@#Rudder policy server doesn't need to be updated";
}
############################################
body classes outcome(x)
{
promise_repaired => {"${x}_ok"};
}
############################################
body action u_background
{
background => "true";
}
############################################
body classes success(if, else, kept)
{
promise_kept => { "${kept}" };
promise_repaired => { "${if}" };
repair_failed => { "${else}" };
repair_denied => { "${else}" };
repair_timeout => { "${else}" };
# persist for 4 minutes so that it wont overlap with the next
# execution in 5 minutes
persist_time => "4";
}
############################################
body action u_ifwin_bg
{
windows::
background => "true";
}
&if(NOVA)&
body service_method u_bootstart
{
service_autostart_policy => "boot_time";
}
&endif&
body perms u_mog(mode,user,group)
{
owners => { "${user}" };
groups => { "${group}" };
mode => "${mode}";
}
# Cron file for Rudder
#
# Will manually run cf-agent in case cf-execd is no longer running. cf-agent will fire up a new cf-execd.
#
# To temporarily avoid this behaviour, touch /opt/rudder/etc/disable-agent.
# Don't forget to remove that file when you're done!
#
# If you want to report a specific message if the Rudder agent fails to restart, please create the
# /opt/rudder/etc/rudder-restart-message.txt file with your custom message inside. It will be sent by mail
# instead of the default one.
# Add a decent PATH to the environment before triggering anything
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0,5,10,15,20,25,30,35,40,45,50,55 * * * * root . /etc/profile; if [ -e ${g.rudder_base}/bin/check-rudder-agent ]; then ${g.rudder_base}/bin/check-rudder-agent >/dev/null; else if [ ! -e ${g.rudder_base}/etc/disable-agent -a `ps -efww | grep -E "(cf-execd|cf-agent)" | grep -E "${sys.workdir}/bin/(cf-execd|cf-agent)" | grep -v grep | wc -l` -eq 0 ]; then ${sys.workdir}/bin/cf-agent -f failsafe.cf >/dev/null 2>\&1 \&\& ${sys.workdir}/bin/cf-agent >/dev/null 2>\&1; if [ $? != 0 ]; then if [ -f /opt/rudder/etc/rudder-restart-message.txt ]; then cat /opt/rudder/etc/rudder-restart-message.txt; else echo "Rudder agent was unable to restart on ${hostname}."; fi; fi; fi; fi
#####################################################################################
# Copyright 2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# This file contain the Global Parameters, to be available within all
# promises, in the form ${rudder_parameters.parameterName}
bundle common rudder_parameters {
vars:
&RUDDER_PARAMETERS:{parameter | "&parameter.parameterName&" string => "&parameter.escapedValue&";
}&
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#######################################################
#
# Server specific configuration
#
#######################################################
bundle server access_rules
{
&if(CLIENTSLIST)&
# Access rules are only defined on a policy server. Standard nodes should not share any files.
access:
policy_server::
&if(NOVA)&
"&UUID&"
handle => "policy_server_uuid",
resource_type => "literal",
admit => {".*"};
&endif&
"${def.dir_masterfiles}"
handle => "grant_access_policy",
comment => "Grant access to the policy updates",
maproot => { @{def.acl} },
admit => { @{def.acl} };
"${g.rudder_tools}"
maproot => { @{def.acl} },
admit => { @{def.acl} };
"${g.rudder_ncf_origin_common}"
maproot => { @{def.acl} },
admit => { @{def.acl} };
"${g.rudder_ncf_origin_local}"
maproot => { @{def.acl} },
admit => { @{def.acl} };
&if(SHARED_FILES_FOLDER)&
"&SHARED_FILES_FOLDER&"
comment => "Grant access to the share files",
maproot => { @{def.acl} },
admit => { @{def.acl} };
&endif&
any::
&if(SKIPIDENTIFY)&
&MANAGED_NODES_NAME, MANAGED_NODES_ID : {host, uuid |
"/var/rudder/share/&uuid&/"
maproot => { escape("&host&") },
admit => { escape("&host&") };
} &
&else&
&MANAGED_NODES_NAME, MANAGED_NODES_ID : {host, uuid |
"/var/rudder/share/&uuid&/"
maproot => { host2ip("&host&"), escape("&host&") },
admit => { host2ip("&host&"), escape("&host&") };
} &
&endif&
# the policy server must have access to the cfengine folder
"${sys.workdir}"
maproot => { host2ip("&POLICYSERVER&"), escape("&POLICYSERVER&") },
admit => { host2ip("&POLICYSERVER&"), escape("&POLICYSERVER&") };
&endif&
roles:
# Allow user root to set any class
".*" authorize => { "root" };
}
bundle common def
{
vars:
"policy_server_file"
string => translatepath("${sys.workdir}/policy_server.dat"),
comment => "Path to file containing address to policy server";
"policy_server"
string => readfile("${policy_server_file}", 2048),
comment => "IP address or hostname to locate your policy host.";
"dir_masterfiles" string => translatepath("${sys.workdir}/masterfiles");
# List here the IP masks that we grant access to on the server
&if(AUTHORIZED_NETWORKS)&
policy_server::
"acl" slist => {
"127.0.0.0/8" , "::1",
"${def.policy_server}", # the policy server can connect to a relay
&AUTHORIZED_NETWORKS:{net|"&net&",}&
};
&endif&
!policy_server::
"acl" slist => {
"${def.policy_server}"
};
}
body server control
{
&if(SKIPIDENTIFY)&
trustkeysfrom => {
@{def.acl} ,
&if(MANAGED_NODES_NAME)&
&MANAGED_NODES_NAME: {
"&it&"};separator=", "&
&endif&
}; #trustkey allows the exchange of keys
allowconnects => {
@{def.acl} ,
&if(MANAGED_NODES_NAME)&
&MANAGED_NODES_NAME: {
"&it&"};separator=", "&
&endif&
};
allowallconnects => {
@{def.acl} ,
&if(MANAGED_NODES_NAME)&
&MANAGED_NODES_NAME: {
"&it&"};separator=", "&
&endif&
};
&else&
trustkeysfrom => {
@{def.acl} ,
&if(MANAGED_NODES_NAME)&
&MANAGED_NODES_NAME: {
host2ip("&it&"), "&it&"};separator=", "&
&endif&
}; #trustkey allows the exchange of keys
allowconnects => {
@{def.acl} ,
&if(MANAGED_NODES_NAME)&
&MANAGED_NODES_NAME: {
host2ip("&it&"), "&it&"};separator=", "&
&endif&
};
allowallconnects => {
@{def.acl} ,
&if(MANAGED_NODES_NAME)&
&MANAGED_NODES_NAME: {
host2ip("&it&"), "&it&"};separator=", "&
&endif&
};
&endif&
maxconnections => "1000";
logallconnections => "true";
cfruncommand => "${sys.workdir}/bin/cf-agent -f failsafe.cf \&\& ${sys.workdir}/bin/cf-agent";
allowusers => {
"&POLICYSERVER_ADMIN&",
&MANAGED_NODES_ADMIN : {admin | "&admin&" };separator=", "&
};
denybadclocks => "&DENYBADCLOCKS&";
skipverify => { "127.0.0.0/8" , "::1", @{def.acl} };
community_edition::
port => "&COMMUNITYPORT&";
}
#######################################################
&if(CLIENTSLIST)&
body runagent control
{
hosts => {
&CLIENTSLIST: {
"&it&",}&
};
max_children => "25";
community_edition::
port => "&COMMUNITYPORT&";
}
&endif&
# Cron file for Rudder
#
# Will manually run cf-agent in case cf-execd is no longer running. cf-agent will fire up a new cf-execd.
#
# To temporarily avoid this behaviour, touch /opt/rudder/etc/disable-agent.
# Don't forget to remove that file when you're done!
#
# If you want to report a specific message if the Rudder agent fails to restart, please create the
# /opt/rudder/etc/rudder-restart-message.txt file with your custom message inside. It will be sent by mail
# instead of the default one.
# Add a decent PATH to the environment before triggering anything
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0,5,10,15,20,25,30,35,40,45,50,55 * * * * root . /etc/profile; if [ ! -e ${g.rudder_base}/etc/disable-agent -a `ps -efww | grep -E "(cf-execd|cf-agent)" | grep -E "${sys.workdir}/bin/(cf-execd|cf-agent))" | grep -v grep | wc -l` -eq 0 ]; then ${sys.workdir}/bin/cf-agent -f failsafe.cf >/dev/null 2>\&1 \&\& ${sys.workdir}/bin/cf-agent >/dev/null 2>\&1; if [ $? != 0 ]; then if [ -f /opt/rudder/etc/rudder-restart-message.txt ]; then cat /opt/rudder/etc/rudder-restart-message.txt; else echo "Rudder agent was unable to restart on ${hostname}."; fi; fi; fi
/var/log/rudder/apache2/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root adm
delaycompress
sharedscripts
postrotate
if [ -f "`. /etc/apache2/envvars ; echo ${APACHE_PID_FILE:-/var/run/apache2.pid}`" ]; then
if [ -x /usr/sbin/invoke-rc.d ]; then
invoke-rc.d apache2 reload > /dev/null
else
/etc/init.d/apache2 reload > /dev/null
fi
fi
endscript
}
/var/log/rudder/ldap/slapd.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root adm
delaycompress
postrotate
if [ -x /usr/sbin/invoke-rc.d ]; then
invoke-rc.d rsyslog rotate > /dev/null
else
/etc/init.d/rsyslog rotate > /dev/null
fi
endscript
}
/var/log/rudder/reports/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root adm
delaycompress
sharedscripts
postrotate
if [ -x /usr/sbin/invoke-rc.d ]; then
invoke-rc.d rsyslog rotate > /dev/null
else
/etc/init.d/rsyslog rotate > /dev/null
fi
endscript
}
/var/log/rudder/core/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root adm
delaycompress
}
/var/log/rudder/compliance/non-compliant-reports.log {
daily
missingok
rotate 365
compress
notifempty
create 640 root adm
delaycompress
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# Configure rsyslog on the orchestrator
# This will provide promises to add the backports repos to Debian Lenny:
# - in sources.list
# - default apt_preferences to upgrade packages installed from backports
# - a package_method to install packages from backports via cfengine
bundle agent setup_debian_backports
{
vars:
"apt_source_line" slist => { "deb http://backports.debian.org/debian-backports lenny-backports" };
"apt_components" slist => { "main" };
files:
debian_5::
"/etc/apt/sources.list"
comment => "Include extra apt repos",
edit_line => append_if_no_lines("${apt_source_line} ${apt_components}"),
edit_defaults => noempty_backup,
classes => if_repaired("apt_sources_updated");
"/etc/apt/preferences"
comment => "Set automatic upgrades for packages installed from backports (recommended setting from backports.debian.org)",
create => "true",
edit_line => append_if_no_lines("Package: *${const.n}Pin: release a=lenny-backports${const.n}Pin-Priority: 200"),
edit_defaults => noempty_backup,
classes => if_repaired("apt_preferences_repaired");
commands:
apt_sources_updated::
"/usr/bin/aptitude"
args => "update";
reports:
apt_sources_updated::
"apt's sources.list was edited, and an aptitude update will now run";
apt_preferences_repaired::
"apt's /etc/apt/preferences file was changed";
}
bundle agent install_rsyslogd {
vars:
root_server::
"rsyslog_source_file" string => "rudder-rsyslog-root.conf";
policy_server.!root_server::
"rsyslog_source_file" string => "rudder-rsyslog-relay.conf";
files:
policy_server::
"/etc/rsyslog.d/rudder.conf"
create => "true",
edit_defaults => empty,
edit_line => expand_template("${sys.workdir}/inputs/distributePolicy/rsyslog.conf/${rsyslog_source_file}"),
classes => cf2_if_else("rudder_rsyslog_conf_copied", "cannot_copy_rudder_rsyslog_conf"),
comment => "Copying rsyslog conf";
"/etc/rsyslog.conf"
edit_line => append_if_no_lines("$IncludeConfig /etc/rsyslog.d/*.conf"),
edit_defaults => noempty_backup,
comment => "Add the rsyslog.conf.d include if not already present",
classes => cf2_if_else("rsyslog_inc_ok" , "rsyslog_inc_failed");
policy_server.debian::
"/etc/rsyslog.d/pgsql.conf"
edit_line => comment_all(),
edit_defaults => noempty_backup,
classes => cf2_if_else("rudder_rsyslog_pgsql", "cannot_update_rudder_rsyslog_pgsql"),
comment => "Removing the logging of all in the database";
packages:
policy_server.debian_5.!SuSE::
"rsyslog"
package_policy => "add",
package_method => debian_backports,
classes => cf2_if_else("rsyslog_installed", "cant_install_rsyslog"),
comment => "Installing rsyslog using apt backports";
"rsyslog-pgsql"
package_policy => "add",
package_method => debian_backports,
classes => cf2_if_else("rsyslog_pgsql_installed", "cant_install_rsyslog_pgsql"),
comment => "Installing rsyslog_pgsql using apt backports";
policy_server.!debian_5.!SuSE.!redhat::
"rsyslog"
package_policy => "add",
package_method => generic,
classes => cf2_if_else("rsyslog_installed", "cant_install_rsyslog"),
comment => "Installing rsyslog using apt backports";
"rsyslog-pgsql"
package_policy => "add",
package_method => generic,
classes => cf2_if_else("rsyslog_pgsql_installed", "cant_install_rsyslog_pgsql"),
comment => "Installing rsyslog_pgsql using apt backports";
policy_server.!debian_5.!SuSE.redhat::
"rsyslog"
package_policy => "add",
package_method => rudder_yum,
classes => cf2_if_else("rsyslog_installed", "cant_install_rsyslog"),
comment => "Installing rsyslog using apt backports";
"rsyslog-pgsql"
package_policy => "add",
package_method => rudder_yum,
classes => cf2_if_else("rsyslog_pgsql_installed", "cant_install_rsyslog_pgsql"),
comment => "Installing rsyslog_pgsql using apt backports";
commands:
policy_server.(rsyslog_installed|rsyslog_pgsql_installed|rudder_rsyslog_conf_copied|rudder_rsyslog_pgsql).!SuSE::
"/etc/init.d/rsyslog"
args => "restart",
classes => cf2_if_else("rsyslog_restarted", "cant_restart_rsyslog"),
comment => "restarting rsyslog";
policy_server.(rsyslog_installed|rsyslog_pgsql_installed|rudder_rsyslog_conf_copied|rudder_rsyslog_pgsql).SuSE::
"/etc/init.d/syslog"
args => "restart",
classes => cf2_if_else("rsyslog_restarted", "cant_restart_rsyslog"),
comment => "restarting rsyslog";
reports:
cant_install_rsyslog|cant_install_rsyslog_pgsql::
"Fatal : Can't install rsyslog or rsyslog_pgsql on the Rudder root server !";
cannot_copy_rudder_rsyslog_conf::
"Fatal : Can't copy the rsyslog configuration !";
rsyslog_inc_failed::
"Fatal : Can't enable the rsyslog include directory !";
cant_restart_rsyslog::
"Fatal : Can't restart rsyslog !";
cannot_update_rudder_rsyslog_pgsql::
"Fatal : Cannot update the pgsql configuration !";
rsyslog_restarted::
"Info : Restarted rsyslog";
}
# Package method to install packages from debian-backports
body package_method debian_backports
{
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 -o Aptitude::Delete-Unused=false -t lenny-backports --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 -o Aptitude::Delete-Unused=false --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 -o Aptitude::Delete-Unused=false --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 -o APT::Get::AutomaticRemove=false --yes -t lenny-backports 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 -o APT::Get::AutomaticRemove=false --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 -o APT::Get::AutomaticRemove=false --yes install";
package_verify_command => "/usr/bin/dpkg -s";
package_noverify_returncode => "1";
}
bundle edit_line comment_all()
{
replace_patterns:
# comment all lines
"^[^#](.*)"
replace_with => comments;
}
body replace_with comments
{
replace_value => "#${match.1}"; # backreference 0
occurrences => "all"; # first, last all
}
/var/log/rudder/apache2/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root adm
delaycompress
sharedscripts
postrotate
if [ -f "`. /etc/apache2/envvars ; echo ${APACHE_PID_FILE:-/var/run/apache2.pid}`" ]; then
if [ -x /usr/sbin/invoke-rc.d ]; then
invoke-rc.d apache2 reload > /dev/null
else
/etc/init.d/apache2 reload > /dev/null
fi
fi
endscript
}
/var/log/rudder/ldap/slapd.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root adm
postrotate
if [ -x /usr/sbin/invoke-rc.d ]; then
invoke-rc.d rsyslog reload > /dev/null
else
/etc/init.d/rsyslog reload > /dev/null
fi
endscript
}
/var/log/rudder/reports/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root adm
delaycompress
sharedscripts
postrotate
if [ -x /usr/sbin/invoke-rc.d ]; then
invoke-rc.d rsyslog reload > /dev/null
else
/etc/init.d/rsyslog reload > /dev/null
fi
endscript
}
/var/log/rudder/core/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root adm
}
/var/log/rudder/compliance/non-compliant-reports.log {
daily
missingok
rotate 365
compress
notifempty
create 640 root adm
}
#####################################################################################
# Copyright 2011-2014 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent root_logrotate_check
{
vars:
(debian_5|debian_6).!ubuntu::
"logrotate_file" string => "${sys.workdir}/inputs/distributePolicy/logrotate.conf/rudder.old-debian";
debian.!(debian_5|debian_6).!ubuntu::
"logrotate_file" string => "${sys.workdir}/inputs/distributePolicy/logrotate.conf/rudder.debian";
ubuntu::
"logrotate_file" string => "${sys.workdir}/inputs/distributePolicy/logrotate.conf/rudder.ubuntu";
redhat::
"logrotate_file" string => "${sys.workdir}/inputs/distributePolicy/logrotate.conf/rudder.rhel";
!debian.!ubuntu.!redhat::
"logrotate_file" string => "${sys.workdir}/inputs/distributePolicy/logrotate.conf/rudder.suse";
files:
"/etc/logrotate.d/rudder"
copy_from => copy_digest("${logrotate_file}"),
classes => kept_if_else("rudder_logrotate_conf_ok", "rudder_logrotate_conf_copied", "cannot_copy_rudder_logrotate_conf"),
comment => "Copying the logrotate configuration";
reports:
cfengine::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check logrotate configuration@@None@@${g.execRun}##${g.uuid}@#The logrotate configuration is correct"
ifvarclass => "rudder_logrotate_conf_ok.!rudder_logrotate_conf_copied.!cannot_copy_rudder_logrotate_conf";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check logrotate configuration@@None@@${g.execRun}##${g.uuid}@#The logrotate configuration has been updated"
ifvarclass => "rudder_logrotate_conf_copied.!cannot_copy_rudder_logrotate_conf";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check logrotate configuration@@None@@${g.execRun}##${g.uuid}@#The logrotate configuration could not be updated"
ifvarclass => "cannot_copy_rudder_logrotate_conf";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent root_technique_reload
{
vars:
"root_technique_reload_rest_url" string => "http://localhost:8080/rudder/api/techniqueLibrary/reload";
classes:
"root_technique_reload_trigger" expression => fileexists("${g.rudder_base}/etc/force_technique_reload");
files:
root_technique_reload_rest_call_repaired::
"${g.rudder_base}/etc/force_technique_reload"
delete => tidy,
comment => "Deleting the force_technique_reload file because it is no longer relevant";
commands:
root_technique_reload_trigger::
"/usr/bin/curl -s ${root_technique_reload_rest_url} |/bin/grep -q OK"
contain => in_shell_silent,
classes => rudder_common_classes("root_technique_reload_rest_call"),
comment => "Reload the Technique library using the Rudder API";
reports:
root_technique_reload_trigger::
"@@DistributePolicy@@log_info@@&TRACKINGKEY&@@Check Technique library reloading file@@None@@${g.execRun}##${g.uuid}@#The ${g.rudder_base}/etc/force_technique_reload file is present. Reloading Technique library...";
root_technique_reload_rest_call_repaired::
"@@DistributePolicy@@log_repaired@@&TRACKINGKEY&@@Check Technique library reloading file@@None@@${g.execRun}##${g.uuid}@#The Technique library has been reloaded.";
root_technique_reload_rest_call_failed::
"@@DistributePolicy@@log_warn@@&TRACKINGKEY&@@Check Technique library reloading file@@None@@${g.execRun}##${g.uuid}@#The Technique library failed to reload. Will try again next time";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent root_postgres_check
{
vars:
SuSE::
"configuration_statements" slist => { "host all rudder ::1/128 md5", "host all rudder 127.0.0.1/32 md5" };
files:
SuSE::
"/var/lib/pgsql/data/pg_hba.conf"
edit_line => prepend("${configuration_statements}"),
edit_defaults => noempty_backup,
classes => kept_if_else("psql_conf_ok", "psql_conf_updated", "psql_conf_update_error"),
comment => "Edit the SuSE postgresql configuration to enable account-less logins";
commands:
SuSE::
"/etc/init.d/postgresql"
args => "restart",
classes => kept_if_else("psql_restart_ok", "psql_restart_ok", "psql_restart_error"),
ifvarclass => "psql_conf_updated";
reports:
SuSE::
# Report about the configuration file edition
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check PostgreSQL configuration@@None@@${g.execRun}##${g.uuid}@#The SuSE specific postgresql configuration is present"
ifvarclass => "psql_conf_ok.!psql_conf_updated.!psql_conf_update_error";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check PostgreSQL configuration@@None@@${g.execRun}##${g.uuid}@#The SuSE specific postgresql configuration has been added"
ifvarclass => "psql_conf_updated.!psql_conf_update_error";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check PostgreSQL configuration@@None@@${g.execRun}##${g.uuid}@#The SuSE specific postgresql configuration could not be added"
ifvarclass => "psql_conf_update_error";
# Reports about Postgres restart status
"@@DistributePolicy@@log_info@@&TRACKINGKEY&@@Check PostgreSQL configuration@@None@@${g.execRun}##${g.uuid}@#PostgreSQL has been restarted"
ifvarclass => "psql_restart_ok";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check PostgreSQL configuration@@None@@${g.execRun}##${g.uuid}@#PostgreSQL restart has failed! Rudder is most certainly broken..."
ifvarclass => "psql_restart_error";
!SuSE::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check PostgreSQL configuration@@None@@${g.execRun}##${g.uuid}@#Their is no need of specific postgresql configuration on this system";
}
/var/log/rudder/apache2/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root adm
delaycompress
sharedscripts
postrotate
if [ -f "`. /etc/apache2/envvars ; echo ${APACHE_PID_FILE:-/var/run/apache2.pid}`" ]; then
if [ -x /usr/sbin/invoke-rc.d ]; then
invoke-rc.d apache2 reload > /dev/null
else
/etc/init.d/apache2 reload > /dev/null
fi
fi
endscript
}
/var/log/rudder/ldap/slapd.log {
daily
missingok
rotate 30
compress
notifempty
create 640 syslog adm
postrotate
if [ -x /usr/sbin/invoke-rc.d ]; then
invoke-rc.d rsyslog reload > /dev/null
else
/etc/init.d/rsyslog reload > /dev/null
fi
endscript
}
/var/log/rudder/reports/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 syslog adm
delaycompress
sharedscripts
postrotate
if [ -x /usr/sbin/invoke-rc.d ]; then
invoke-rc.d rsyslog reload > /dev/null
else
/etc/init.d/rsyslog reload > /dev/null
fi
endscript
}
/var/log/rudder/core/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root adm
}
/var/log/rudder/compliance/non-compliant-reports.log {
daily
missingok
rotate 365
compress
notifempty
create 640 root adm
}
#####################################################################################
# Copyright 2014 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent compress_webapp_log
{
vars:
# compress files older than 2 days
"log_compress_delay" int => "2";
files:
"/var/log/rudder/webapp"
file_select => jetty_logs("${log_compress_delay}"),
depth_search => recurse("0"),
transformer => "${g.gzip} \"${this.promiser}\"";
}
body file_select jetty_logs(days)
{
leaf_name => { ".*\.log", ".*\.log\.\d+" };
mtime => irange(ago(0,0,"${days}",0,0,0),now);
file_result => "leaf_name.!mtime";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent root_alive_check
{
vars:
"apps_to_check" slist => { "rudder", "endpoint" };
methods:
"any" usebundle => generic_alive_check("${apps_to_check}");
}
bundle agent generic_alive_check(app)
{
vars:
"site_to_check" string => "http://localhost:8080/${app}/api/status";
"sitename" string => canonify("${site_to_check}");
"cleanup_failed_classes" slist => { "site_down_once_${sitename}", "site_alivecheck_restart_jetty_${sitename}" };
"failed_result_class" string => "site_down_once_${sitename}",
ifvarclass => "!site_down_once_${sitename}.!first_iteration_passed";
"site_failure_persist_time" string => "10",
ifvarclass => "!site_down_once_${sitename}.!first_iteration_passed";
"failed_result_class" string => "site_alivecheck_restart_jetty_${sitename}",
ifvarclass => "site_down_once_${sitename}.!first_iteration_passed";
"site_failure_persist_time" string => "0",
ifvarclass => "site_down_once_${sitename}.!first_iteration_passed";
classes:
"first_iteration_passed" expression => "any";
methods:
root_server::
"any" usebundle => generic_process_check_process(".*java.*/opt/rudder/jetty7/start.jar", "rudder-jetty", "jetty", "true", "false"),
ifvarclass => "site_alivecheck_restart_jetty_${sitename}",
classes => set_persist_classes("site_alivecheck_jetty_restarted_${sitename}", "site_down_once_${sitename}" ,"0");
commands:
root_server::
"/usr/bin/curl -s ${site_to_check} |/bin/grep -q OK"
contain => in_shell_silent,
classes => set_persist_classes_alivecheck("site_ok", "${failed_result_class}", "@{generic_alive_check.cleanup_failed_classes}", "${site_failure_persist_time}"),
comment => "Checking if ${site_to_check} is alive";
reports:
root_server::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check ${app} status@@None@@${g.execRun}##${g.uuid}@#The ${site_to_check} web application is running"
ifvarclass => "site_ok.!site_down_once_${sitename}";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check ${app} status@@None@@${g.execRun}##${g.uuid}@#This is the first time the ${site_to_check} web application failed to respond. Deferring the restart."
ifvarclass => "site_down_once_${sitename}.!site_alivecheck_restart_jetty_${sitename}";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check ${app} status@@None@@${g.execRun}##${g.uuid}@#The ${site_to_check} web application failed to respond for the second time. Restarting jetty NOW !"
ifvarclass => "site_alivecheck_restart_jetty_${sitename}";
policy_server.!root_server::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check ${app} status@@None@@${g.execRun}##${g.uuid}@#The ${site_to_check} web application check do not need to be done on relay servers. Skipping...";
}
body classes set_persist_classes_alivecheck(repaired, failed, cancelifok, length)
{
promise_kept => { "${repaired}" };
promise_repaired => { "${repaired}" };
repair_failed => { "${failed}" };
repair_denied => { "${failed}" };
repair_timeout => { "${failed}" };
cancel_kept => {"@{cancelifok}"};
cancel_repaired => {"@{cancelifok}"};
cancel_notkept => {"${repaired}"};
persist_time => "${length}";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#
# Fetch the promises from the server to be available for others machines
# Must not do it on the RootServer though...
bundle agent propagatePromises
{
vars:
any::
"server_data" string => "${server_info.policy_files}/share"; #actual directory with data to propagate
"client_data" string => "${g.rudder_var}/share/"; #where to put the files on the client when downloaded
classes:
root_server::
"rudder_tools_updated_exists" expression => fileexists("${g.rudder_tools_updated_origin}");
files:
root_server::
"${g.rudder_tools}"
copy_from => copy("${g.rudder_base}/share/tools"),
depth_search => recurse_visible("inf"),
comment => "Fetching the tools for the promises execution",
classes => classes_generic("propagate_tools");
policy_server.!root_server::
"${client_data}" #that's a loop on each files in client_inputs
copy_from => remote("${server_info.cfserved}","${server_data}"),
depth_search => recurse_visible("inf"),
comment => "Fetching the promises to propagate",
classes => if_else("promises_propagated", "could_not_propagate_promise");
"${g.rudder_ncf_origin_local}"
copy_from => remote("${server_info.cfserved}","${g.rudder_ncf_origin_local}"),
depth_search => recurse_visible("inf"),
comment => "Fetching the ncf local to propagate",
classes => if_else("ncf_local_promises_propagated", "could_not_propagate_ncf_local_promise");
"${g.rudder_ncf_origin_common}"
copy_from => remote("${server_info.cfserved}","${g.rudder_ncf_origin_common}"),
depth_search => recurse_visible("inf"),
comment => "Fetching the ncf common to propagate",
classes => if_else("ncf_common_promises_propagated", "could_not_propagate_ncf_common_promise");
"&SHARED_FILES_FOLDER&"
copy_from => remote("${server_info.cfserved}","&SHARED_FILES_FOLDER&"),
depth_search => recurse_visible("inf"),
comment => "Fetching the files shared for the promises execution",
classes => if_else("files_propagated", "could_not_propagate_files");
"${g.rudder_tools}"
copy_from => remote("${server_info.cfserved}","${g.rudder_tools}"),
depth_search => recurse_visible("inf"),
comment => "Fetching the tools for the promises execution",
classes => if_else("tools_propagated", "could_not_propagate_tools");
"${sys.workdir}/masterfiles"
copy_from => remote("${server_info.cfserved}","${sys.workdir}/masterfiles"),
depth_search => recurse_visible("inf"),
file_select => no_license_dat, #We don't want to propagate a wrong license.dat
comment => "Fetching the bootstrap promises",
classes => if_else("masterfiles_propagated", "could_not_propagate_masterfiles");
&if(NOVA)&
"${sys.workdir}/masterfiles/license.dat"
copy_from => local_cp("${sys.workdir}/inputs/license.dat"),
comment => "Putting the right license in the bootstrap",
classes => if_else("license_copied", "could_not_copy_license");
&endif&
# If rudder_tools_updated doesn't exist, or if the tools have been updated,
# set rudder_tools_updated content to current timestamp
root_server.(!rudder_tools_updated_exists|propagate_tools_repaired)::
"${g.rudder_tools_updated_origin}"
create => "true",
edit_defaults => empty,
edit_line => insert_lines("${sys.date}"),
comment => "Update the timestamp in the rudder tool updated file";
reports:
# Success if files are updated or not changed (kept or repaired).
# root server have only tools to be updated and others have tools,
# promises, masterfiles folder and licenses to be updated.
((root_server.propagate_tools_ok)|(!root_server.propagate_tools_ok.promises_propagated.masterfiles_propagated.license_copied.ncf_local_promises_propagated.ncf_common_promises_propagated)).!(propagate_tools_error|could_not_propagate_promise|could_not_propagate_masterfiles|could_not_copy_license|could_not_propagate_ncf_local_promise|could_not_propagate_ncf_common_promise)::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Propagate promises@@None@@${g.execRun}##${g.uuid}@#All files have been propagated";
could_not_propagate_promise::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Propagate promises@@None@@${g.execRun}##${g.uuid}@#Cannot propagate policy files";
could_not_propagate_files::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Propagate promises@@None@@${g.execRun}##${g.uuid}@#Cannot propagate shared files";
propagate_tools_error::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Propagate promises@@None@@${g.execRun}##${g.uuid}@#Cannot propagate tools";
could_not_propagate_ncf_local_promise::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Propagate promises@@None@@${g.execRun}##${g.uuid}@#Cannot propagate local ncf promises";
could_not_propagate_ncf_common_promise::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Propagate promises@@None@@${g.execRun}##${g.uuid}@#Cannot propagate common ncf promises";
could_not_propagate_masterfiles::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Propagate promises@@None@@${g.execRun}##${g.uuid}@#Cannot propagate masterfiles";
could_not_copy_license::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Propagate promises@@None@@${g.execRun}##${g.uuid}@#Cannot copy local license";
}
# Sending the inventory to cmdb (or syncing with the server if we are a simple relay)
# We cannot use list of paths to send the inventories because it cause the transformer to fail
# for some unknown reason
bundle agent sendInventoryToCmdb
{
files:
root_server::
"${g.rudder_inventories}/incoming"
transformer => "${g.rudder_tools}/send-clean.sh &CMDBENDPOINT& ${this.promiser} ${g.rudder_inventories}/received/ ${g.rudder_inventories}/failed/",
depth_search => recurse_visible(1),
file_select => all_files,
classes => rudder_common_classes("rudder_inventory_processing"),
comment => "Processing a local inventory";
"${g.rudder_inventories}/accepted-nodes-updates"
transformer => "${g.rudder_tools}/send-clean.sh &CMDBENDPOINT& ${this.promiser} ${g.rudder_inventories}/received/ ${g.rudder_inventories}/failed/",
depth_search => recurse_visible(1),
file_select => all_files,
classes => rudder_common_classes("rudder_inventory_processing"),
comment => "Processing a local inventory";
policy_server.!root_server::
"${g.rudder_inventories}/incoming"
transformer => "/usr/bin/curl -f -s --proxy '' --user rudder:rudder -T ${this.promiser} http://${server_info.cfserved}/inventories/",
depth_search => recurse_visible(1),
file_select => inventory_files,
classes => rudder_common_classes("rudder_inventory_relay"),
comment => "Sending an inventory to the root server";
"${g.rudder_inventories}/accepted-nodes-updates"
transformer => "/usr/bin/curl -f -s --proxy '' --user ${g.davuser}:${g.davpw} -T ${this.promiser} http://${server_info.cfserved}/inventory-updates/",
depth_search => recurse_visible(1),
file_select => inventory_files,
classes => rudder_common_classes("rudder_inventory_relay"),
comment => "Sending an inventory to the root server";
policy_server.!root_server.!rudder_inventory_relay_error::
"${g.rudder_inventories}/incoming"
transformer => "/bin/rm -f ${this.promiser}",
depth_search => recurse_visible(1),
file_select => inventory_files,
classes => rudder_common_classes("rudder_inventory_cleanup"),
comment => "Purging the received inventory files after processing";
"${g.rudder_inventories}/accepted-nodes-updates"
transformer => "/bin/rm -f ${this.promiser}",
depth_search => recurse_visible(1),
file_select => inventory_files,
classes => rudder_common_classes("rudder_inventory_cleanup"),
comment => "Purging the received inventory files after processing";
reports:
rudder_inventory_processing_repaired.!rudder_inventory_processing_error::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Send inventories to CMDB@@None@@${g.execRun}##${g.uuid}@#Incoming inventories were successfully added to Rudder";
rudder_inventory_processing_error::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Send inventories to CMDB@@None@@${g.execRun}##${g.uuid}@#Some inventories failed to add successfully to Rudder";
root_server.!rudder_inventory_processing_repaired.!rudder_inventory_processing_error::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Send inventories to CMDB@@None@@${g.execRun}##${g.uuid}@#No inventory to send";
rudder_inventory_relay_repaired.!rudder_inventory_relay_error::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Send inventories to CMDB@@None@@${g.execRun}##${g.uuid}@#Incoming inventories were successfully relayed to the root server";
rudder_inventory_relay_error::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Send inventories to CMDB@@None@@${g.execRun}##${g.uuid}@#Cannot relay some inventories to the root server";
policy_server.!root_server.!rudder_inventory_relay_repaired.!rudder_inventory_relay_error::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Send inventories to CMDB@@None@@${g.execRun}##${g.uuid}@#No inventory to relay";
rudder_inventory_cleanup_repaired.!rudder_inventory_cleanup_error::
"@@DistributePolicy@@log_info@@&TRACKINGKEY&@@Send inventories to CMDB@@None@@${g.execRun}##${g.uuid}@#Sent incoming inventories were removed from local cache";
rudder_inventory_cleanup_error::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Send inventories to CMDB@@None@@${g.execRun}##${g.uuid}@#Cannot remove incoming inventories from local cache";
}
body file_select all_files
{
leaf_name => { ".*\..*" };
file_result => "leaf_name";
}
body file_select no_license_dat
{
leaf_name => { "license\.dat" };
file_result => "!leaf_name";
}
/var/log/rudder/apache2/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root root
delaycompress
sharedscripts
postrotate
/etc/init.d/apache2 reload > /dev/null
endscript
}
/var/log/rudder/ldap/slapd.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root root
delaycompress
postrotate
/etc/init.d/syslog reload > /dev/null
endscript
}
/var/log/rudder/reports/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root root
delaycompress
sharedscripts
postrotate
/etc/init.d/syslog reload > /dev/null
endscript
}
/var/log/rudder/core/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root root
delaycompress
}
/var/log/rudder/compliance/non-compliant-reports.log {
daily
missingok
rotate 365
compress
notifempty
create 640 root root
delaycompress
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent root_init_check()
{
vars:
"service[1][name]" string => "slapd";
"service[1][binary]" string => "/opt/rudder/libexec/slapd";
"service[1][initscript]" string => "rudder-slapd";
"service[1][check_on_relay_server]" string => "false";
"service[2][name]" string => "jetty";
"service[2][binary]" string => ".*java.*/opt/rudder/jetty7/start.jar";
"service[2][initscript]" string => "rudder-jetty";
"service[2][check_on_relay_server]" string => "false";
"service[3][name]" string => "postgresql";
"service[3][binary]" string => "postgres: writer process";
"service[3][initscript]" string => "postgresql";
"service[3][check_on_relay_server]" string => "false";
"service[4][name]" string => "apache";
"service[4][check_on_relay_server]" string => "true";
!redhat::
"service[4][binary]" string => "apache2";
"service[4][initscript]" string => "apache2";
redhat::
"service[4][binary]" string => "httpd";
"service[4][initscript]" string => "httpd";
any::
"index" slist => getindices("service");
methods:
"any" usebundle => generic_process_check_process("${service[${index}][binary]}", "${service[${index}][initscript]}", "${service[${index}][name]}", "false", "${service[${index}][check_on_relay_server]}");
"any" usebundle => generic_process_check_bootstart("${service[${index}][binary]}", "${service[${index}][initscript]}", "${service[${index}][name]}");
}
bundle agent generic_process_check_process(binary, initscript, name, force_restart, check_on_relay_server) {
vars:
"canoname" string => canonify("${binary}");
classes:
"forced_trigger_${canoname}" expression => strcmp("${force_restart}", "true");
# Raise this class if we are handling a process that should be checked even on
# relay servers.
"process_exception_on_relay" expression => strcmp("${check_on_relay_server}", "true");
processes:
root_server|process_exception_on_relay::
# check the service status
"${binary}"
comment => "Check the process status",
restart_class => "process_restart_${canoname}",
classes => kept_if_else("service_running_${canoname}", "service_anomaly_${canoname}", "service_error_${canoname}");
commands:
root_server|process_exception_on_relay::
"/etc/init.d/${initscript}"
args => "restart </dev/null >/dev/null 2>/dev/null",
contain => in_shell_silent,
# action => bg("0", "120"),
classes => kept_if_else("process_restart_ok_${canoname}", "process_restart_ok_${canoname}", "process_restart_error_${canoname}"),
ifvarclass => "process_restart_${canoname}|forced_trigger_${canoname}";
reports:
root_server|process_exception_on_relay::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check ${name} process@@None@@${g.execRun}##${g.uuid}@#The ${name} process is already running"
ifvarclass => "!process_restart_${canoname}.!forced_trigger_${canoname}";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check ${name} process@@None@@${g.execRun}##${g.uuid}@#The ${name} process was not running and has been restarted"
ifvarclass => "process_restart_${canoname}.process_restart_ok_${canoname}.!forced_trigger_${canoname}";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check ${name} process@@None@@${g.execRun}##${g.uuid}@#The ${name} process has been restarted"
ifvarclass => "process_restart_ok_${canoname}.forced_trigger_${canoname}";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check ${name} process@@None@@${g.execRun}##${g.uuid}@#The ${name} process couldn't be restarted"
ifvarclass => "process_restart_error_${canoname}";
policy_server.!root_server.!process_exception_on_relay::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check ${name} process@@None@@${g.execRun}##${g.uuid}@#The ${name} process do not need to be checked on relay servers. Skipping...";
}
bundle agent generic_process_check_bootstart(binary, initscript, name) {
vars:
"canoname" string => canonify("${binary}");
SuSE::
"check_command" string => "/sbin/chkconfig --check ${initscript}";
"bootstart_command" string => "/sbin/insserv -d ${initscript}";
redhat::
"check_command" string => "/sbin/chkconfig --list ${initscript} | grep -q on";
"bootstart_command" string => "/sbin/chkconfig ${initscript} on";
files:
debian::
"/etc/rc2.d/S.*${initscript}.*"
create => "true",
action => WarnOnly,
classes => if_else("service_bootstarted_${canoname}", "service_unbootstarted_${canoname}");
commands:
(SuSE|redhat)::
"${check_command}"
contain => in_shell_silent,
classes => if_else("service_bootstarted_${canoname}", "service_unbootstarted_${canoname}"),
comment => "Check if the service ${name} is started on boot";
"${bootstart_command}"
classes => if_else("service_bootstarted_ok_${canoname}", "service_bootstarted_fail_${canoname}"),
ifvarclass => "service_unbootstarted_${canoname}",
comment => "Set the service ${name} to start on boot";
debian::
"/usr/sbin/update-rc.d ${initscript} remove \&\& /usr/sbin/update-rc.d ${initscript} defaults"
contain => in_shell,
classes => if_else("service_bootstarted_ok_${canoname}", "service_bootstarted_fail_${canoname}"),
ifvarclass => "service_unbootstarted_${canoname}",
comment => "Set the service ${name} to start on boot";
reports:
cfengine::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check ${name} boot script@@None@@${g.execRun}##${g.uuid}@#${name} is started on boot as required"
ifvarclass => "service_bootstarted_${canoname}";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check ${name} boot script@@None@@${g.execRun}##${g.uuid}@#${name} has been set to start on boot"
ifvarclass => "!service_bootstarted_${canoname}.service_bootstarted_ok_${canoname}";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check ${name} boot script@@None@@${g.execRun}##${g.uuid}@#Could not set ${name} to start on boot!"
ifvarclass => "!service_bootstarted_${canoname}.service_bootstarted_fail_${canoname}";
}
# Pre-2.8 rotation for Apache
# Before the unification of the apache log directories (http://www.rudder-project.org/redmine/issues/4010)
# we used this directory to store apache logs.
/var/log/rudder/httpd/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root root
delaycompress
sharedscripts
postrotate
/etc/init.d/httpd reload > /dev/null
endscript
}
/var/log/rudder/apache2/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root root
delaycompress
sharedscripts
postrotate
/etc/init.d/httpd reload > /dev/null
endscript
}
/var/log/rudder/ldap/slapd.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root root
delaycompress
postrotate
/etc/init.d/rsyslog reload > /dev/null
endscript
}
/var/log/rudder/reports/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root root
delaycompress
sharedscripts
postrotate
/etc/init.d/rsyslog reload > /dev/null
endscript
}
/var/log/rudder/core/*.log {
daily
missingok
rotate 30
compress
notifempty
create 640 root root
delaycompress
}
/var/log/rudder/compliance/non-compliant-reports.log {
daily
missingok
rotate 365
compress
notifempty
create 640 root root
delaycompress
}
#####################################################################################
# Copyright 2012 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent root_networks_check
{
vars:
"networks" string => join("${const.n}Allow from ","def.acl");
"file_path" string => "/opt/rudder/etc/rudder-networks.conf";
redhat::
"apache_init" string => "httpd";
!redhat::
"apache_init" string => "apache2";
files:
"${file_path}"
create => "true",
perms => mog("644", "root", "root"),
edit_defaults => empty_backup,
edit_line => insert_lines("Allow from 127.0.0.0/8${const.n}Allow from ${networks}"),
classes => kept_if_else("rudder_networks_ok", "rudder_networks_repaired","rudder_networks_failed"),
comment => "Copying rudder apache configuration";
commands:
rudder_networks_repaired::
"/etc/init.d/${apache_init}"
args => "reload",
classes => if_else("apache_restarted", "apache_restart_failed");
reports:
cfengine::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check rudder-networks.conf file@@None@@${g.execRun}##${g.uuid}@#The ${file_path} apache configuration file is OK"
ifvarclass => "rudder_networks_ok.!rudder_networks_repaired.!rudder_networks_failed";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check rudder-networks.conf file@@None@@${g.execRun}##${g.uuid}@#The ${file_path} apache configuration file has been corrected"
ifvarclass => "rudder_networks_repaired.!rudder_networks_failed";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check rudder-networks.conf file@@None@@${g.execRun}##${g.uuid}@#The ${file_path} apache configuration file was NOT edited because of an error"
ifvarclass => "rudder_networks_failed";
"@@DistributePolicy@@log_info@@&TRACKINGKEY&@@Check rudder-networks.conf file@@None@@${g.execRun}##${g.uuid}@#The Apache HTTPd has been reloaded successfully"
ifvarclass => "apache_restarted.!apache_restart_failed";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check rudder-networks.conf file@@None@@${g.execRun}##${g.uuid}@#The Apache HTTPd failed to restart"
ifvarclass => "apache_restart_failed";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# Rsyslog Rudder configuration
# Disable Repeated message reduction or reports may be lost
$RepeatedMsgReduction off
# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun &SYSLOGPORT&
# Provide udp for snare and compatibility with older syslog
$ModLoad imudp
$UDPServerRun &SYSLOGPORT&
# Load postgres module
$ModLoad ompgsql
# for Snare client
$EscapeControlCharactersOnReceive off
# Log everything
*.* /var/log/rudder/reports/all.log
# Direct to DB
$ActionQueueType Direct
$ActionQueueSaveOnShutdown on
# The RudderReportsFormat template specifies how to store
# the report in the database.
# nodeId : the node id
# ruleId : the Rule Id
# directiveId : the directive id
# eventtype : the severity
# policy : the policy name
$template RudderReportsFormat,"insert into RudderSysEvents (executionDate, nodeId, ruleId, directiveId, serial, Component, KeyValue, executionTimeStamp, eventType, msg, Policy) values ('%timereported:::date-rfc3339%','%msg:R,ERE,1,DFLT:.*##(.*)@#.*--end%', '%msg:R,ERE,1,DFLT:.*@@.*@@.*@@(.*)@@.*@@.*@@.*@@.*@@[^#]*##.*--end%' , '%msg:R,ERE,1,ZERO:.*@@.*@@.*@@.*@@(.*)@@.*@@.*@@.*@@[^#]*##.*--end%', '%msg:R,ERE,1,DFLT:.*@@.*@@.*@@.*@@.*@@(.*)@@.*@@.*@@[^#]*##.*--end%', '%msg:R,ERE,1,DFLT:.*@@.*@@.*@@.*@@.*@@.*@@(.*)@@.*@@[^#]*##.*--end%', '%msg:R,ERE,1,DFLT:.*@@.*@@.*@@.*@@.*@@.*@@.*@@(.*)@@[^#]*##.*--end%', '%msg:R,ERE,1,DFLT:.*@@.*@@.*@@.*@@.*@@.*@@.*@@.*@@([^#]*)##.*--end%', '%msg:R,ERE,1,DFLT:.*@@.*@@(.*)@@.*@@.*@@.*@@.*@@.*@@[^#]*##.*--end%', '%msg:R,ERE,1,DFLT:.*@#(.*)--end%', '%msg:R,ERE,1,DFLT:.*@@(.*)@@.*@@.*--end%' )",stdsql
# Filtering by content
# Process :
# We first store the data in the database, then we drop it to prevent
# it from reaching local storage in .log files.
# The report format is @@Policy@@State@@RuleId@@DirectiveId@@VersionId@@Component@@Key@@ExecutionTimeStamp##NodeId@#HumanReadableMessage
#
# 1 - Send every matching report in the database...
:msg, ereregex, "R: @@[ a-zA-Z0-9_\-]+?@@[a-zA-Z0-9_\-]{1,64}?@@[a-zA-Z0-9\-]+@@[a-zA-Z0-9\-]+?@@[0-9]+?@@.*?@@.*?@@[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}[+-][0-9]{1,2}:[0-9]{2}##[a-zA-Z0-9\-]+?@#.*" :ompgsql:localhost,rudder,rudder,${p.psql_password[2]};RudderReportsFormat
# 2 - Drop the remaining rudder logs to prevent local storage cluttering
## Syslog messages from "rudder"
:programname, contains, "rudder" ~
## Syslog messages from "rudder" forwarded from AIX
:msg, ereregex, "from .*: rudder:" ~
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# Rsyslog Rudder configuration
# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun &SYSLOGPORT&
# Provide udp for snare and compatibility with older syslog
$ModLoad imudp
$UDPServerRun &SYSLOGPORT&
# for Snare client
$EscapeControlCharactersOnReceive off
# Log everything
*.* /var/log/rudder/reports/all.log
# Direct to DB
$ActionQueueType Direct
$ActionQueueSaveOnShutdown on
# Filtering by content
# Process :
# We first forward the data to the root server, then we drop it to prevent
# it from reaching local storage in .log files.
# The report format is @@Policy@@State@@RuleId@@DirectiveId@@VersionId@@Component@@Key@@ExecutionTimeStamp##NodeId@#HumanReadableMessage
#
# 1 - Send every matching report to the root server
:msg, ereregex, "R: @@[ a-zA-Z0-9_\-]+?@@[a-zA-Z0-9_\-]{1,64}?@@[a-zA-Z0-9\-]+@@[a-zA-Z0-9\-]+?@@[0-9]+?@@.*?@@.*?@@[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}[+-][0-9]{1,2}:[0-9]{2}##[a-zA-Z0-9\-]+?@#.*" @@${server_info.cfserved}:&SYSLOGPORT&
# 2 - Drop the remaining rudder logs to prevent local storage cluttering
## Syslog messages from "rudder"
:programname, contains, "rudder" ~
## Syslog messages from "rudder" forwarded from AIX
:msg, ereregex, "from .*: rudder:" ~
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# Path of the promises files on the machine
&CLIENTSFOLDERS;separator=":"&
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent root_integrity_check
{
files:
root_server::
"${g.rudder_configuration_repository}"
create => "true",
action => WarnOnly,
classes => if_else("rudder_integrity_ok", "rudder_integrity_failed");
"${g.rudder_configuration_repository}/.git/index.lock"
delete => tidy,
file_select => rudder_common_minutes_old("5"),
classes => rudder_common_classes("rudder_git_lock"),
comment => "Delete the git locking file in the configuration-repository if older than 5 minutes";
reports:
root_server::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check configuration-repository folder@@None@@${g.execRun}##${g.uuid}@#The ${g.rudder_configuration_repository} directory is present"
ifvarclass => "rudder_integrity_ok.!rudder_integrity_failed";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check configuration-repository folder@@None@@${g.execRun}##${g.uuid}@#EMERGENCY: THE ${g.rudder_configuration_repository} DIRECTORY IS *ABSENT*. THIS ORCHESTRATOR WILL *NOT* OPERATE CORRECTLY."
ifvarclass => "!rudder_integrity_ok|rudder_integrity_failed";
root_server.!rudder_git_lock_repaired.!rudder_git_lock_failed::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check configuration-repository GIT lock@@None@@${g.execRun}##${g.uuid}@#The ${g.rudder_configuration_repository} GIT lock file is not present or not older than 5 minutes";
root_server.rudder_git_lock_repaired.!rudder_git_lock_failed::
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check configuration-repository GIT lock@@None@@${g.execRun}##${g.uuid}@#WARNING: THE ${g.rudder_configuration_repository} GIT LOCK FILE WAS OLDER THAN 5 MINUTES AND HAS BEEN DELETED";
root_server.rudder_git_lock_failed::
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check configuration-repository GIT lock@@None@@${g.execRun}##${g.uuid}@#TheEMERGENCY: THE ${g.rudder_configuration_repository} GIT LOCK FILE IS OLDER THAN 5 MINUTES AND COULD NOT BE DELETED. THIS ORCHESTRATOR WILL *NOT* OPERATE CORRECTLY.";
policy_server.!root_server::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check configuration-repository folder@@None@@${g.execRun}##${g.uuid}@#Nothing to check about the configuration repository on relay servers";
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check configuration-repository GIT lock@@None@@${g.execRun}##${g.uuid}@#Nothing to check about configuration repository GIT locking on relay servers";
}
#####################################################################################
# Copyright 2012 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle common p
{
vars:
root_server::
"no" int => getfields("RUDDER_PSQL_PASSWORD:.*","/opt/rudder/etc/rudder-passwords.conf",":","psql_password");
"no2" int => getfields("RUDDER_OPENLDAP_BIND_PASSWORD:.*","/opt/rudder/etc/rudder-passwords.conf",":","ldap_password");
"properties_files" slist => { "${g.rudder_base}/etc/rudder-web.properties", "${g.rudder_base}/etc/inventory-web.properties" };
"managed_files" slist => { "@{properties_files}", "/root/.pgpass", "${g.rudder_base}/etc/openldap/slapd.conf" };
}
bundle agent root_password_check_disclaimer
{
vars:
"disclaim" slist => { "@{p.managed_files}" };
files:
root_server::
"${disclaim}"
edit_line => insert_rudder_disclaimer,
comment => "Insert a disclaimer into Rudder";
}
bundle agent root_password_check_file
{
vars:
"pgpass[1]" string => "localhost";
"pgpass[2]" string => "5432";
"pgpass[3]" string => "rudder";
"pgpass[4]" string => "rudder";
"pgpass[5]" string => "${p.psql_password[2]}";
files:
root_server::
"${g.rudder_base}/etc/rudder-passwords.conf"
perms => mog("600", "root", "root"),
classes => kept_if_else("file_ok", "file_repaired", "file_error");
"/root/.pgpass"
create => "true",
edit_line => root_password_check_file_pgpass("root_password_check_file.pgpass");
reports:
root_server::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check rudder-passwords.conf and pgpass files@@None@@${g.execRun}##${g.uuid}@#The Rudder passwords file is present and secure"
ifvarclass => "file_ok.!file_repaired.!file_error";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check rudder-passwords.conf and pgpass files@@None@@${g.execRun}##${g.uuid}@#The Rudder passwords file permissions were fixed"
ifvarclass => "file_repaired.!file_error";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check rudder-passwords.conf and pgpass files@@None@@${g.execRun}##${g.uuid}@#EMERGENCY: THE ${g.rudder_base}/etc/rudder-passwords.conf FILE IS *ABSENT*. THIS RUDDER SERVER WILL *NOT* OPERATE CORRECTLY."
ifvarclass => "file_error";
policy_server.!root_server::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check rudder-passwords.conf and pgpass files@@None@@${g.execRun}##${g.uuid}@#The Rudder passwords file does not need to be checked on relay servers. Skipping...";
}
bundle agent root_password_check_ldap
{
vars:
# Build an array using ldap configuration values
"rudder[ldap.authpw]" string => "${p.ldap_password[2]}";
"slapd[rootpw]" string => "${p.ldap_password[2]}"; # Looks like a bug, I can not use execresult("/opt/rudder/sbin/slappasswd -s ${p.ldap_password[2]}","noshell");
"prop_edit" slist => { "@{p.properties_files}" };
files:
root_server::
"${prop_edit}"
edit_line => set_variable_values("root_password_check_ldap.rudder"),
classes => kept_if_else("rudder_web_password_integrity_ok", "rudder_web_password_integrity_changed", "rudder_web_password_integrity_failed"),
comment => "Verifying the Rudder Webapp properties file passwords and users";
"${g.rudder_base}/etc/openldap/slapd.conf"
edit_line => update_slapd("root_password_check_ldap.slapd"),
classes => kept_if_else("rudder_ldap_password_integrity_ok", "rudder_ldap_password_integrity_changed", "rudder_ldap_password_integrity_failed"),
comment => "Verifying the Rudder LDAP file password and user";
commands:
rudder_ldap_password_integrity_changed::
"/etc/init.d/rudder-slapd restart"
contain => in_shell,
classes => if_else("slapd_restarted", "slapd_restart_failed");
reports:
root_server::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check LDAP in rudder-webapp.properties@@None@@${g.execRun}##${g.uuid}@#The Rudder Webapp configuration files are OK (checked LDAP password)"
ifvarclass => "rudder_web_password_integrity_ok.!rudder_web_password_integrity_changed.!rudder_web_password_integrity_failed";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check LDAP in rudder-webapp.properties@@None@@${g.execRun}##${g.uuid}@#The Rudder Webapp configuration files were updated with a new LDAP password"
ifvarclass => "rudder_web_password_integrity_changed.!rudder_web_password_integrity_failed";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check LDAP in rudder-webapp.properties@@None@@${g.execRun}##${g.uuid}@#The Rudder Webapp configuration files could not be updated to set the LDAP password"
ifvarclass => "rudder_web_password_integrity_failed";
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check LDAP credentials@@None@@${g.execRun}##${g.uuid}@#The OpenLDAP configuration file is OK (checked rootdn password)"
ifvarclass => "rudder_ldap_password_integrity_ok.!rudder_ldap_password_integrity_changed.!rudder_ldap_password_integrity_failed";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check LDAP credentials@@None@@${g.execRun}##${g.uuid}@#The OpenLDAP configuration file was updated with a new rootdn password"
ifvarclass => "rudder_ldap_password_integrity_changed.!rudder_ldap_password_integrity_failed";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check LDAP credentials@@None@@${g.execRun}##${g.uuid}@#The OpenLDAP configuration file could not be updated to set the rootdn password"
ifvarclass => "rudder_ldap_password_integrity_failed";
"@@DistributePolicy@@log_info@@&TRACKINGKEY&@@Check rudder-passwords.conf file@@None@@${g.execRun}##${g.uuid}@#rudder-slapd has been restarted"
ifvarclass => "slapd_restarted";
policy_server.!root_server::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check LDAP in rudder-webapp.properties@@None@@${g.execRun}##${g.uuid}@#The Rudder Webapp configuration files do not need to be checked on relay servers. Skipping...";
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check LDAP credentials@@None@@${g.execRun}##${g.uuid}@#The OpenLDAP configuration file do not need to be checked on relay servers. Skipping...";
}
bundle agent root_password_check_psql
{
vars:
root_server::
"no" int => getfields("RUDDER_PSQL_PASSWORD:.*","/opt/rudder/etc/rudder-passwords.conf",":","psql_pass");
# Build an array using PSQL configuration values
"rudder[rudder.jdbc.password]" string => "${p.psql_password[2]}";
classes:
root_server::
"psql_cant_connect" not => returnszero("/usr/bin/psql --host localhost --username rudder --dbname rudder --quiet --output /dev/null --command 'select 1' 2> /dev/null","useshell");
files:
root_server::
"${g.rudder_base}/etc/rudder-web.properties"
edit_line => set_variable_values("root_password_check_psql.rudder"),
classes => kept_if_else("rudder_web_password_integrity_ok", "rudder_web_password_integrity_changed", "rudder_web_password_integrity_failed"),
comment => "Verifying the Rudder Webapp properties file passwords and users";
commands:
psql_cant_connect::
"/usr/bin/psql -q -c \"ALTER USER rudder WITH PASSWORD '${p.psql_password[2]}'\""
contain => setuid_sh("postgres"),
classes => if_else("postgres_updated", "postgres_update_failed");
reports:
root_server::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check SQL in rudder-webapp.properties@@None@@${g.execRun}##${g.uuid}@#The Rudder Webapp configuration files are OK (checked SQL password)"
ifvarclass => "rudder_web_password_integrity_ok.!rudder_web_password_integrity_changed.!rudder_web_password_integrity_failed";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check SQL in rudder-webapp.properties@@None@@${g.execRun}##${g.uuid}@#The Rudder Webapp configuration files were updated with a new SQL password"
ifvarclass => "rudder_web_password_integrity_changed.!rudder_web_password_integrity_failed";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check SQL in rudder-webapp.properties@@None@@${g.execRun}##${g.uuid}@#The Rudder Webapp configuration files could not be updated to set the SQL password"
ifvarclass => "rudder_web_password_integrity_failed";
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check SQL credentials@@None@@${g.execRun}##${g.uuid}@#The Rudder PostgreSQL user account's password is correct and works"
ifvarclass => "!psql_cant_connect";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check SQL credentials@@None@@${g.execRun}##${g.uuid}@#The Rudder PostgreSQL user account's password has been changed"
ifvarclass => "postgres_updated";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check SQL credentials@@None@@${g.execRun}##${g.uuid}@#The Rudder PostgreSQL user account's password could not be changed!"
ifvarclass => "postgres_update_failed";
policy_server.!root_server::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check SQL in rudder-webapp.properties@@None@@${g.execRun}##${g.uuid}@#The Rudder Webapp configuration files do not need to be checked on relay servers. Skipping...";
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check SQL credentials@@None@@${g.execRun}##${g.uuid}@#The Rudder PostgreSQL user account's do not need to be checked on relay servers. Skipping...";
}
bundle agent root_password_restart_jetty
{
commands:
rudder_web_password_integrity_changed::
"/etc/init.d/rudder-jetty restart </dev/null >/dev/null 2>/dev/null"
contain => in_shell,
classes => if_else("jetty_restarted", "jetty_restart_failed");
reports:
"@@DistributePolicy@@log_info@@&TRACKINGKEY&@@Check rudder-webapp.properties@@None@@${g.execRun}##${g.uuid}@#Jetty has been restarted"
ifvarclass => "jetty_restarted";
}
bundle agent root_password_check_dav
{
vars:
debian::
"webdav_check_wwwgroup" string => "www-data";
redhat::
"webdav_check_wwwgroup" string => "apache";
!debian.!redhat::
"webdav_check_wwwgroup" string => "www";
SuSE::
"htpasswd_bin" string => "/usr/bin/htpasswd2";
!SuSE::
"htpasswd_bin" string => "/usr/bin/htpasswd";
classes:
"dav_cant_connect" not => returnszero("/usr/bin/curl -s -f -u ${g.davuser}:${g.davpw} -T /etc/motd http://localhost/inventory-updates/motd","noshell");
files:
"${g.rudder_base}/etc/htpasswd-webdav"
create => "true",
perms => mog("640", "root", "${webdav_check_wwwgroup}");
commands:
dav_cant_connect::
# Apache reads this file when it's changed, no need to restart or reload it after it's changed
"${htpasswd_bin}"
args => "-b ${g.rudder_base}/etc/htpasswd-webdav ${g.davuser} ${g.davpw}",
classes => kept_if_else("rudder_apache_davpassword_ok", "rudder_apache_davpassword_changed", "rudder_apache_davpassword_failed"),
comment => "Repairing the Rudder WebDAV user and password";
reports:
cfengine::
"@@DistributePolicy@@result_success@@&TRACKINGKEY&@@Check WebDAV credentials@@None@@${g.execRun}##${g.uuid}@#The Rudder WebDAV user and password are OK"
ifvarclass => "!dav_cant_connect";
"@@DistributePolicy@@result_repaired@@&TRACKINGKEY&@@Check WebDAV credentials@@None@@${g.execRun}##${g.uuid}@#The Rudder WebDAV user and password were updated"
ifvarclass => "rudder_apache_davpassword_changed.!rudder_apache_davpassword_failed";
"@@DistributePolicy@@result_error@@&TRACKINGKEY&@@Check WebDAV credentials@@None@@${g.execRun}##${g.uuid}@#The Rudder WebDAV user and password could not be updated"
ifvarclass => "rudder_apache_davpassword_failed";
}
bundle edit_line update_slapd(tab)
{
vars:
"index" slist => getindices("${tab}");
delete_lines:
"${index}.*";
insert_lines:
"${index} ${${tab}[${index}]}" location => after("^rootdn.*");
}
bundle edit_line root_password_check_file_pgpass(parameter)
{
vars:
"indices" slist => getindices(${parameter});
field_edits:
"localhost:5432:rudder:.*"
# Set field of the file to parameter
edit_field => col(":","${indices}","${${parameter}[${indices}]}","set");
insert_lines:
"localhost:5432:rudder:${${parameter}[4]}:${${parameter}[5]}";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
############################################################
# Fetch PERL and Curl
############################################################
bundle agent fetchFusionTools
{
packages:
debian::
"curl"
package_policy => "add",
package_method => apt,
classes => rudder_common_classes("fetchFusionTools_install_curl"),
comment => "Installing curl using apt";
redhat::
"curl"
package_policy => "add",
package_method => rudder_yum,
classes => rudder_common_classes("fetchFusionTools_install_curl"),
comment => "Installing curl using yum";
reports:
fetchFusionTools_install_curl_error::
"@@Inventory@@result_error@@inventory-all@@inventory-all@@00@@tools@@None@@${g.execRun}##${g.uuid}@#Installing 'curl' failed. Inventory registration will fail if curl is unavailable";
}
body perms myperms
{
mode => "0700";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# Definition of variables and classes usefull for all the VM part
# Detect the existence of installed VM containenr on the computer
bundle common virtualMachines
{
vars:
# Files names for the installed VM lists
"VBoxListFile" string => "${g.rudder_var_tmp}/VBoxList.list";
"VMWareListFile" string => "${g.rudder_var_tmp}/VMWareList.list";
"VMWareScript_ServerLocation" string => "${g.rudder_tools}/vmware_info.sh";
# Attribut name for the VM tag in the inventory file
"VBoxAttr" string => "VBox";
"VMWareAttr" string => "VMWare";
# Tools for fetching data
"VMWareScript" string => "${g.inventory_directory}/vmware_info.sh";
&if(NOVA)&
windows.!cygwin::
"virtual_box_install_path" string => execresult("${sys.winsysdir}\cmd.exe /c \"echo %VBOX_INSTALL_PATH%\"", "noshell"),
comment => "Looking for VirtualBox environment variables";
&endif&
cygwin::
"virtual_box_install_path" string => execresult("/usr/bin/echo $VBOX_INSTALL_PATH | /usr/bin/sed ''s/\\\/\//g'' ", "useshell"),
comment => "Looking for VirtualBox environment variables";
classes:
!windows::
"VirtualBoxInstalled" expression => fileexists("/usr/bin/VBoxManage"),
comment => "Checking installation of VirtualBox";
"VMWareInstalled" expression => fileexists("/usr/bin/wmrun"),
comment => "Checking installation of VMWare";
&if(NOVA)&
windows::
"VirtualBoxInstalled" not => regcmp("", "${virtual_box_install_path}");
&endif&
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#
# This file launch a fusion-inventory agent
# inventory in local.
# If fusion agent is not installed,
# the installation is done
#
# Then the inventory file is improved with external informations (UUID, cf-key, VMs)
bundle agent doInventory
{
vars:
# If curl is available, use it
!windows.curl_installed::
"download_command" string => "${g.rudder_curl} -s -f --proxy '' -o \"${g.rudder_var_tmp}/uuid.txt\" http://${server_info.cfserved}/uuid";
# If not, use minicurl instead
!windows.!curl_installed::
"download_command" string => "${g.minicurl} --get --file \"${g.rudder_var_tmp}/uuid.txt\" --url http://${server_info.cfserved}/uuid";
&if(NOVA)&
# On windows, always use curl
windows::
"download_command" string => "\"${g.rudder_base_sbin}\curl\curl.exe\" -s -f --noproxy '${server_info.cfserved}' -o \"${g.rudder_var_tmp}\uuid.txt\" http://${server_info.cfserved}/uuid";
&endif&
uuid_succesfully_downloaded::
"policy_server_uuid" string => readfile("${g.rudder_var_tmp}/uuid.txt", 50);
classes:
"splaying" expression => splayclass("${sys.host}${sys.ipv4}","hourly");
# The force_inventory class may be specified by the user at runtime, or defined here
"force_inventory" expression => fileexists("${g.rudder_base}/etc/force_inventory");
uuid_succesfully_downloaded::
"uuid_valid" expression => regcmp("[a-z0-9-]+","${policy_server_uuid}");
"uuid_validity_checked"
expression => "any",
comment => "This dummy class is just used for ordering the report using !uuid_valid below";
methods:
uuid_valid.force_inventory::
"any" usebundle => fusionAgent;
"any" usebundle => listInstalledVM;
"any" usebundle => generateExtraInformations;
"any" usebundle => turnUsersToUnicode;
"any" usebundle => addInformationsToInventory;
"any" usebundle => moveInventoryToFinalDestination;
"any" usebundle => sendInventory;
"any" usebundle => cleanForceInventoryFlagFile;
# Workaround the wrong class expansion
uuid_valid.Night.splaying.!inventory_sent::
"any" usebundle => fusionAgent;
"any" usebundle => listInstalledVM;
"any" usebundle => generateExtraInformations;
"any" usebundle => turnUsersToUnicode;
"any" usebundle => addInformationsToInventory;
"any" usebundle => moveInventoryToFinalDestination;
"any" usebundle => sendInventory;
commands:
"${download_command}"
comment => "Getting the uuid from the server",
classes => if_else("uuid_succesfully_downloaded","could_not_download_uuid");
reports:
could_not_download_uuid::
"@@Inventory@@result_error@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not retrieve the UUID of the policy server";
uuid_succesfully_downloaded.uuid_validity_checked.!uuid_valid::
"@@Inventory@@result_error@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not retrieve a valid UUID from the policy server";
# Send reports to confirm this PT's success even if we don't need to send an inventory
inventory_sent::
"@@Inventory@@log_info@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#An inventory was already sent less than 8 hours ago";
!(Night.splaying).!force_inventory::
"@@Inventory@@result_success@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Next inventory scheduled between 00:00 and 06:00";
}
bundle common inventory
{
vars:
&if(NOVA)&
windows::
# Files names
"UserListFile_cp" string => "\"${g.rudder_var_tmp}\UserList.tmp\"";
"UserListFile" string => "\"${g.rudder_var_tmp}\UserList.list\"";
"cpuid_tool" string => "\"${g.rudder_tools}\cpuid-windows-V1.0.vbs\"";
&endif&
android::
"cpuid_tool" string => "${g.rudder_tools}/cpuid-android-V1.0.sh";
!aix.!windows.!android::
"cpuid_tool" string => "${g.rudder_tools}/cpuid-linux-V1.0.sh";
any::
"CPUIDFile" string => "${g.rudder_var_tmp}/cpuid.arc";
classes:
windows::
"rudder_inventory_userlist_tool_present" expression => fileexists("${g.rudder_tools}\userlist.bat");
any::
"rudder_inventory_cpuid_tool_present" expression => fileexists("${cpuid_tool}");
}
bundle agent fusionAgent
{
vars:
SuSE.xen_dom0::
"xen_tools_package" string => "xen-tools";
SuSE.xen_domu_pv::
"xen_tools_package" string => "xen-tools-domU";
debian::
"xen_tools_package" string => "xenstore-utils";
!debian.!SuSE::
"xen_tools_package" string => "xen";
files:
!windows|cygwin::
"${g.rudder_var_tmp}/inventory/."
create => "true",
comment => "Creating inventory directory",
classes => if_ok("inventoryfoldercreated");
"${g.rudder_var_reports}/."
create => "true";
&if(NOVA)&
windows.!cygwin::
"${g.rudder_var_tmp}\inventory\."
create => "true",
comment => "Creating inventory directory",
classes => if_ok("inventoryfoldercreated");
"${g.rudder_var_reports}\."
create => "true";
&endif&
packages:
xen.!redhat::
"${xen_tools_package}"
package_policy => "add",
package_method => generic,
classes => cf2_if_else("xen_installed", "cant_install_xen"),
comment => "Installing xen package for extended data";
xen.redhat::
"${xen_tools_package}"
package_policy => "add",
package_method => rudder_yum,
classes => cf2_if_else("xen_installed", "cant_install_xen"),
comment => "Installing xen package for extended data";
commands:
!windows.inventoryfoldercreated::
"${g.rudder_base}/bin/run-inventory --local=${g.rudder_var_tmp}/inventory --scan-homedirs"
classes => cf2_if_else("run_inventory", "inventory_failed"),
comment => "Generating inventory, in the temporary folder";
&if(NOVA)&
windows::
"\"C:\Program Files\Rudder\sbin\run-inventory.bat\""
args => "--local=\"${g.rudder_var_tmp}\inventory\" --scan-homedirs 2>nul",
contain => in_shell,
classes => cf2_if_else("run_inventory", "inventory_failed"),
comment => "Generating inventory";
&endif&
reports:
run_inventory::
"@@Inventory@@log_debug@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Running inventory";
inventory_failed::
"@@Inventory@@result_error@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not execute the inventory";
cant_install_curl::
"@@Inventory@@result_error@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not install curl";
cant_install_ocs::
"@@Inventory@@result_error@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not install ocs";
cant_install_xen::
"@@Inventory@@result_error@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not install xen utils on xen systems";
xen_installed::
"@@Inventory@@log_info@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Xen utils installed";
curl_installed::
"@@Inventory@@log_info@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Curl installed";
}
# List all installed VM on the machine (based on VirtualBox)
# CAUTION : Issue with path containing a whitespace, it's not working with windows
bundle agent listInstalledVM
{
files:
VirtualBoxInstalled::
"${virtualMachines.VBoxListFile}"
create => "true",
edit_line => xmlify(${virtualMachines.VBoxAttr}),
comment => "Converting file into pseudo XML";
VMWareInstalled::
"${virtualMachines.VMWareListFile}"
create => "true",
edit_line => xmlify(${virtualMachines.VMWareAttr}),
comment => "Converting file into pseudo XML";
commands:
!windows.VirtualBoxInstalled::
"/usr/bin/VBoxManage"
args => "-q list vms > ${virtualMachines.VBoxListFile}",
contain => outputable,
classes => cf2_if_else("vb_listed", "cant_list_vb"),
comment => "Generating file with list of VM";
&if(NOVA)&
windows.VirtualBoxInstalled::
"\"${virtualMachines.virtual_box_install_path}VBoxManage.exe\""
args => "-q list vms > ${virtualMachines.VBoxListFile}",
contain => outputable,
classes => cf2_if_else("vb_listed", "cant_list_vb"),
comment => "Generating file with list of VM";
&endif&
!windows.VMWareInstalled::
"${virtualMachines.VMWareScript}"
contain => outputable,
args => " > ${virtualMachines.VMWareListFile}",
classes => cf2_if_else("vm_listed", "cant_list_vm"),
comment => "Generating file with list of VM";
&if(NOVA)&
windows.VMWareInstalled::
"${virtualMachines.VMWareScript}"
contain => outputable,
args => " > ${virtualMachines.VMWareListFile}",
classes => cf2_if_else("vm_listed", "cant_list_vm"),
comment => "Generating file with list of VM";
&endif&
reports:
cant_list_vm::
"@@Inventory@@log_warn@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not list installed VMWare machines";
cant_list_vb::
"@@Inventory@@log_warn@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not list installed VirtualBox machines";
}
bundle agent generateExtraInformations
{
commands:
&if(NOVA)&
windows.rudder_inventory_userlist_tool_present::
"\"${g.rudder_tools}\userlist.bat\""
args => " > ${inventory.UserListFile_cp} ",
contain => outputable,
classes => cf2_if_else("userlist", "userlist_fail"),
comment => "Generating file with list of users";
windows.rudder_inventory_cpuid_tool_present::
"${sys.winsysdir}\cscript.exe"
args => "/Nologo \"${g.rudder_tools}/cpuid-windows-V1.0.vbs\" > \"${inventory.CPUIDFile}\"",
contain => outputable,
classes => cf2_if_else("cpuid", "cpuid_fail"),
comment => "Generating file with CPUID information";
&endif&
!windows.rudder_inventory_cpuid_tool_present::
"${inventory.cpuid_tool}"
args => " > ${inventory.CPUIDFile}",
contain => outputable,
classes => cf2_if_else("cpuid", "cpuid_fail"),
comment => "Generating file with CPUID information";
reports:
userlist::
"@@Inventory@@log_debug@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Generated the userlist";
cpuid::
"@@Inventory@@log_debug@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Generated the CPUID";
userlist_fail::
"@@Inventory@@result_error@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not generate the user list";
cpuid_fail::
"@@Inventory@@result_error@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not generate the cpuid";
!rudder_inventory_userlist_tool_present::
"@@Inventory@@log_debug@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#The user list generation tool is not present yet. Skipping...";
!rudder_inventory_cpuid_tool_present::
"@@Inventory@@log_debug@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#The CPUID generation tool is not present yet. Skipping...";
}
bundle agent turnUsersToUnicode
{
&if(NOVA)&
commands:
windows::
"\"${g.rudder_tools}\iconv.exe\""
args => " -f CP850 -t UTF-8 ${inventory.UserListFile_cp} > ${inventory.UserListFile} ",
contain => outputable_dir("${g.rudder_tools}"),
classes => cf2_if_else("userlist", "userlist_fail"),
comment => "Generating file with list of users in UTF";
&endif&
reports:
windows::
"@@Inventory@@log_debug@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#This is a windows machine. User list has been converted to Unicode";
}
# adding data to the inventory :
# UUID and CFKey in <DEVICEID>,
# list of VM in <CONTENT>
bundle agent addInformationsToInventory
{
vars:
&if(NOVA)&
windows.!cygwin::
"CFKEY_cmd" string => "${sys.winsysdir}\cmd.exe /c \"type \"${sys.workdir}\ppkeys\localhost.pub\"\"";
"USER" string => getenv("USERNAME", 40);
"RUDDERUUID_cmd" string => "${sys.winsysdir}\cscript.exe /Nologo \"${g.rudder_tools}/uuid.vbs\"";
"polserv_uuid" string => readfile( "${g.rudder_var_tmp}\uuid.txt" , "50" );
# Somehow, using the variable rather than the path fails with readstringlist
"users" slist => { readstringlist("C:\Program Files\Rudder\var\tmp\UserList.list","#.*","[\n| |\r]",50,4000) };
&endif&
cygwin::
"mywinpath" string => execresult("/usr/bin/echo $WINDIR ", "useshell");
"CFKEY_cmd" string => "/usr/bin/cat ${sys.workdir}/ppkeys/localhost.pub";
"USER_cmd" string => "/usr/bin/whoami";
"RUDDERUUID_cmd" string => "${sys.winsysdir}\cscript.exe /Nologo ${g.rudder_tools}/uuid.vbs";
"polserv_uuid" string => readfile( "${g.rudder_var_tmp}/uuid.txt" , "50" );
"users" slist => { readstringlist("${inventory.UserListFile}","#.*","[\n| |\r]",10,4000) };
xen.SuSE.xen_domu_pv::
"VMRUDDERUUID_cmd" string => "/bin/xenstore-read vm";
xen.(centos|redhat|(SuSE.xen_dom0))::
"VMRUDDERUUID_cmd" string => "/usr/bin/xenstore-read vm";
xen.(!SuSE.!centos.!redhat)::
"VMRUDDERUUID_cmd" string => "/usr/sbin/xenstore-read vm";
xen::
"VMRUDDERUUID" string => execresult("${VMRUDDERUUID_cmd}", "noshell");
xen.xenrudderuuid::
"RUDDERUUID" string => "${vmarray[1]}";
!windows::
"polserv_uuid" string => readfile( "${g.rudder_var_tmp}/uuid.txt" , "50" );
android::
"RUDDERUUID_cmd" string => "/system/xbin/sqlite3 /data/data/com.android.providers.settings/databases/settings.db \"select value from secure where name = 'android_id'\"";
"CFKEY_cmd" string => "/system/bin/cat ${sys.workdir}/ppkeys/localhost.pub";
"USER_cmd" string => "/system/xbin/whoami";
"usersnumber" int => "1";
"users" slist => {"root"};
"android_kernelname" string => "linux";
"android_kernelversion" string => execresult("/system/xbin/uname -r", "noshell");
"android_name" string => "Android";
"android_version" string => execresult("/system/bin/getprop ro.build.version.release", "noshell");
"android_fullname" string => "Android ${android_version}";
"logdate" string => execresult("/system/bin/date '+%Y-%m-%d %H:%M:%S'", "noshell");
linux.!xen::
"RUDDERUUID_cmd" string => "/usr/sbin/dmidecode -s system-uuid";
aix::
"RUDDERUUID_cmd" string => "/usr/bin/uname -f";
!windows.!android::
"CFKEY_cmd" string => "/bin/cat ${sys.workdir}/ppkeys/localhost.pub";
"USER_cmd" string => "/usr/bin/whoami";
"usersnumber" int => readstringarray("userslist","/etc/passwd","#[^\n]*",":",50,16000);
"users" slist => getindices("userslist");
any::
"CFKEY" string => execresult("${CFKEY_cmd}", "noshell");
"USER" string => execresult("${USER_cmd}", "noshell");
!xen::
"RUDDERUUID" string => execresult("${RUDDERUUID_cmd}", "noshell");
classes:
xen::
"xenrudderuuid" expression => regextract("/vm/(.*)", "${VMRUDDERUUID}", "vmarray");
any::
"uuiddefined" expression => isvariable("RUDDERUUID");
files:
&if(NOVA)&
windows::
"C:/Progra~1/Rudder/var/tmp/inventory/.*.ocs"
edit_line => add_information_to_inventory(${RUDDERUUID}, ${CFKEY}, ${USER}, ${polserv_uuid}),
edit_defaults => def_no_backup;
"C:/Progra~1/Rudder/var/tmp/inventory/.*.ocs"
edit_line => add_users_information_to_inventory(@{addInformationsToInventory.users}),
edit_defaults => def_no_backup;
&endif&
!windows.uuiddefined::
"${g.rudder_var_tmp}/inventory/.*.ocs"
edit_line => add_information_to_inventory(${RUDDERUUID}, ${CFKEY}, ${USER}, ${polserv_uuid}),
edit_defaults => def_no_backup;
"${g.rudder_var_tmp}/inventory/.*.ocs"
edit_line => add_users_information_to_inventory(@{addInformationsToInventory.users}),
edit_defaults => def_no_backup;
android::
"${g.rudder_var_tmp}/inventory/.*.ocs"
edit_line => add_information_to_android_inventory(${android_fullname}, ${android_kernelname}, ${android_kernelversion}, ${android_name}, ${android_version}),
edit_defaults => def_no_backup;
"${g.rudder_var_tmp}/inventory/.*.ocs"
edit_line => add_accesslog_to_android_inventory(${logdate}),
edit_defaults => def_no_backup;
}
# Move the inventory file in the shared directory
bundle agent moveInventoryToFinalDestination
{
files:
"${g.rudder_inventories}"
copy_from => copy("${g.rudder_var_tmp}/inventory"),
depth_search => recurse_visible(1),
file_select => inventory_files,
comment => "Moving inventory files to the final location";
}
# Send the file to the promises server
bundle agent sendInventory
{
vars:
"download_endpoint" string => "http://${server_info.cfserved}/inventory-updates/";
# If curl is available, use it
!windows.curl_installed::
"download_command_prefix" string => "${g.rudder_curl} -f -s --proxy '' --user ${g.davuser}:${g.davpw} -T";
"download_command_suffix" string => "${download_endpoint}";
# If not, use minicurl instead
!windows.!curl_installed::
"download_command_prefix" string => "${g.minicurl} --put --authentication ${g.davuser}:${g.davpw} --file";
"download_command_suffix" string => "--url ${download_endpoint}";
&if(NOVA)&
# On windows, always use curl
windows::
"download_command_prefix" string => "${g.rudder_curl} -f -s --noproxy '${server_info.cfserved}' --user ${g.davuser}:${g.davpw} -T";
"download_command_suffix" string => "${download_endpoint}";
&endif&
files:
!windows::
"${g.rudder_inventories}"
transformer => "${download_command_prefix} ${this.promiser} ${download_command_suffix}",
depth_search => recurse_visible(1),
file_select => inventory_files,
classes => persistant_class("inventory_sent", "cant_send_inventory", 480),
comment => "Sending the inventory to the server";
&if(NOVA)&
# On windows, the this.promiser variable is not evaluated the same way. We are forced to duplicate this block
windows::
"${g.rudder_inventories}"
transformer => "${download_command_prefix} \"${this.promiser}\" ${download_command_suffix}",
depth_search => recurse_visible(1),
file_select => inventory_files,
classes => persistant_class("inventory_sent", "cant_send_inventory", 480),
comment => "Sending the inventory to the server";
&endif&
# Once we've successfully sent all inventories, remove them
!windows.inventory_sent.!cant_send_inventory::
"${g.rudder_inventories}"
transformer => "${g.rudder_rm} -f ${this.promiser}",
depth_search => recurse_visible(1),
file_select => inventory_files,
classes => if_else("inventory_file_deleted", "cant_delete_inventory_file"),
comment => "Cleaning up inventory files already sent to the server";
"${g.rudder_var_tmp}/inventory"
transformer => "${g.rudder_rm} -f ${this.promiser}",
depth_search => recurse_visible(1),
file_select => inventory_files,
classes => if_else("inventory_file_deleted", "cant_delete_inventory_file"),
comment => "Cleaning up inventory files already sent to the server";
reports:
inventory_sent::
"@@Inventory@@result_success@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#The inventory has been successfully sent";
cant_send_inventory::
"@@Inventory@@result_error@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not send the inventory";
cant_delete_inventory_file::
"@@Inventory@@log_warn@@&TRACKINGKEY&@@inventory@@None@@${g.execRun}##${g.uuid}@#Could not delete inventory file after sending to server";
}
#####################################################
#Adding the list of Virtual Machines into the report
#Adding the ids in the report
#####################################################
bundle edit_line add_information_to_inventory(RUDDERUUID, CFKEY, USER, POLSRVUUID)
{
insert_lines:
"<UUID>${g.uuid}</UUID>${const.n}<USER>${USER}</USER>${const.n}<AGENTSNAME>${const.n}</AGENTSNAME>${const.n}<MACHINEID>${RUDDERUUID}</MACHINEID>${const.n}<CFKEY>${CFKEY}</CFKEY>${const.n}<HOSTNAME>${sys.fqhost}</HOSTNAME>${const.n}<POLICY_SERVER>${POLSRVUUID}</POLICY_SERVER>${const.n}"
location => after_deviceid,
insert_type => "preserve_block",
comment => "Add the UUID and CFKEY tags in the inventory file";
any::
"<VMS>${const.n}</VMS>${const.n}<USERSLIST>${const.n}</USERSLIST>"
insert_type => "preserve_block",
location => after_content;
rudder_inventory_cpuid_tool_present::
"${inventory.CPUIDFile}"
insert_type => "file",
location => after_location("<HOSTNAME>"),
comment => "Adding the CPUID data in the inventory file";
nova_edition::
"<AGENTNAME>Nova</AGENTNAME>"
location => after_location("<AGENTSNAME>"),
comment => "Adding the agent data in the inventory file";
community_edition::
"<AGENTNAME>Community</AGENTNAME>"
location => after_location("<AGENTSNAME>"),
comment => "Adding the agent data in the inventory file";
VirtualBoxInstalled::
"${virtualMachines.VBoxListFile}"
insert_type => "file",
location => after_location("<VMS>"),
comment => "Adding the list of VM in the inventory file";
VMWareInstalled::
"${virtualMachines.VMWareListFile}"
insert_type => "file",
location => after_vm,
comment => "Adding the list of VM in the inventory file";
}
bundle edit_line add_information_to_android_inventory(fullname, kernelname, kernelversion, name, version)
{
insert_lines:
android::
"<OPERATINGSYSTEM>${const.n}<FULL_NAME>${fullname}</FULL_NAME>${const.n}<KERNEL_NAME>${kernelname}</KERNEL_NAME>${const.n}<KERNEL_VERSION>${kernelversion}</KERNEL_VERSION>${const.n}<NAME>${name}</NAME>${const.n}<VERSION>${version}</VERSION>${const.n}</OPERATINGSYSTEM>"
location => after_location("<CONTENT>"),
insert_type => "preserve_block",
comment => "Adding the list of OPERATINGSYSTEM part";
}
#this bundle is necessary for OCSInventory (but not for fusioninventory)
bundle edit_line add_accesslog_to_android_inventory(logdate)
{
insert_lines:
android::
"<ACCESSLOG><LOGDATE>${logdate}</LOGDATE></ACCESSLOG>"
location => after_location("</OPERATINGSYSTEM>"),
comment => "Adding log date";
}
bundle edit_line add_users_information_to_inventory(userlist)
{
insert_lines:
(windows.rudder_inventory_userlist_tool_present)|!windows::
"<USER>${userlist}</USER>${const.n}" location => after_users,
comment => "Add the UUID and CFKEY tags in the inventory file";
}
#Locators
body location after_location(pos)
{
select_line_matching => ".*${pos}.*";
before_after => "after";
}
body location after_deviceid
{
select_line_matching => ".*<DEVICEID>.*";
before_after => "after";
}
body location after_content
{
select_line_matching => ".*<CONTENT>.*";
before_after => "after";
}
body location after_vm
{
select_line_matching => ".*<VMS>.*";
before_after => "after";
}
body location after_users
{
select_line_matching => ".*<USERSLIST>.*";
before_after => "after";
}
###############
# Editors
##############
# Convert a simple list in <VM TYPe="vmtype"><NAME>machine_name</NAME><UUID>value<UUID></VM>
bundle edit_line xmlify(ATTR)
{
replace_patterns:
"\"(.*)\" \{(.*)\}"
replace_with=> xmled(${ATTR});
}
body replace_with xmled(attribute)
{
replace_value => "<VM TYPE=\"${attribute}\"><NAME>${match.1}</NAME><UUID>${match.2}</UUID></VM>";
}
# select the inventory files that has the right extension
#I'd like to select also those older than 4 hours (ctime => irange(ago(0,0,0,4,0,0),now);) not working...
# (for some reason, ocs duplicated files over time)
body file_select inventory_files
{
any::
leaf_name => { ".*.ocs" };
file_result => "leaf_name";
&if(NOVA)&
#windows::
# leaf_name => { ".*.xml" };
# file_result => "leaf_name";
&endif&
}
body perms inventory_perms
{
mode => "0700";
}
body file_select one_day_age
#
# we can build old "include", "exclude", and "ignore"
# from these as standard patterns - these bodies can
# form a library of standard patterns
#
{
mtime => irange(ago(1,0,0,0,0,0),ago(0,0,1,0,0,0));
file_result => "mtime";
}
bundle agent cleanForceInventoryFlagFile
{
files:
"${g.rudder_base}/etc/force_inventory"
delete => tidy,
ifvarclass => "inventory_sent"; # if the force inventory file was present, and we successfully sent an inventory, clean up the flag file
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
######################################################
# Configure the ntp
# If ntp is not installed, install it (linux)
# Change the server configuration, and restart the daemon
# if the configuration changed
# Caution : a missing feature in cfe prevents from adding ,0x1 at the end of the domain name
# so it's only safe to use with ips for now
bundle agent check_clock_configuration
{
vars:
"ntpServers" slist => {&CLOCK_NTPSERVERS: { "&it&"};separator=", "&};
windows::
# For windows, we must extract both ip and domain name values
#"ipv4" slist => grep("(?:\\d{1,3}\.){3}\\d{1,3}","ntpServers");
#domain slist => not one of the above
# check that list aren't empty using reglist
&if(CLOCK_FQDNNTP)&
"keytemp" string => join("\,0x1 ", ntpServers);
"serverskey" string => "${keytemp}\,0x1";
&else&
"serverskey" string => join(" ", ntpServers);
&endif&
"current_timezone" string => execresult("\"${sys.winsysdir}\tzutil.exe\" /g", "useshell");
clock_set_france::
"linux_timezone" string => "Europe/Paris";
"windows_timezone" string => "Romance Standard Time";
clock_set_uk::
"linux_timezone" string => "Europe/London";
"windows_timezone" string => "GMT Standard Time";
clock_set_germany::
"linux_timezone" string => "Europe/Berlin";
"windows_timezone" string => "W. Europe Standard Time";
clock_set_spain::
"linux_timezone" string => "Europe/Madrid";
"windows_timezone" string => "Romance Standard Time";
clock_set_italy::
"linux_timezone" string => "Europe/Rome";
"windows_timezone" string => "W. Europe Standard Time";
clock_set_us_pacific::
"linux_timezone" string => "US/Pacific";
"windows_timezone" string => "Pacific Standard Time";
clock_set_us_mountain::
"linux_timezone" string => "US/Mountain";
"windows_timezone" string => "Mountain Standard Time";
clock_set_us_central::
"linux_timezone" string => "US/Central";
"windows_timezone" string => "Central Standard Time";
clock_set_eastern::
"linux_timezone" string => "US/Eastern";
"windows_timezone" string => "Eastern Standard Time";
clock_set_canada::
"linux_timezone" string => "America/Canada";
"windows_timezone" string => "Atlantic Standard Time";
clock_set_belgium::
"linux_timezone" string => "Europe/Brussels";
"windows_timezone" string => "Romance Standard Time";
clock_set_luxembourg::
"linux_timezone" string => "Europe/Luxembourg";
"windows_timezone" string => "Romance Standard Time";
clock_set_netherlands::
"linux_timezone" string => "Europe/Amsterdam";
"windows_timezone" string => "W. Europe Standard Time";
clock_set_norway::
"linux_timezone" string => "Europe/Oslo";
"windows_timezone" string => "Romance Standard Time";
clock_set_beijing::
"linux_timezone" string => "Europe/Paris";
"windows_timezone" string => "China Standard Time";
classes:
"clock_vardef" expression => isvariable("linux_timezone");
"clock_timezone_noedit" expression => strcmp("&CLOCK_TIMEZONE&","dontchange");
"clock_set_france" expression => strcmp("&CLOCK_TIMEZONE&","france");
"clock_set_uk" expression => strcmp("&CLOCK_TIMEZONE&","uk");
"clock_set_germany" expression => strcmp("&CLOCK_TIMEZONE&","germany");
"clock_set_spain" expression => strcmp("&CLOCK_TIMEZONE&","spain");
"clock_set_italy" expression => strcmp("&CLOCK_TIMEZONE&","italy");
"clock_set_us_pacific" expression => strcmp("&CLOCK_TIMEZONE&","us-pacific");
"clock_set_us_mountain" expression => strcmp("&CLOCK_TIMEZONE&","us-mountain");
"clock_set_us_central" expression => strcmp("&CLOCK_TIMEZONE&","us-central");
"clock_set_us_eastern" expression => strcmp("&CLOCK_TIMEZONE&","us-eastern");
"clock_set_canada" expression => strcmp("&CLOCK_TIMEZONE&","canada");
"clock_set_belgium" expression => strcmp("&CLOCK_TIMEZONE&","belgium");
"clock_set_luxembourg" expression => strcmp("&CLOCK_TIMEZONE&","luxembourg");
"clock_set_netherlands" expression => strcmp("&CLOCK_TIMEZONE&","netherlands");
"clock_set_norway" expression => strcmp("&CLOCK_TIMEZONE&","norway");
"clock_set_beijing" expression => strcmp("&CLOCK_TIMEZONE&","beijing");
"ntp_config_file_exists" expression => fileexists("/etc/ntp.conf");
clock_vardef.windows::
# check if we need to change the windows timezone
"need_to_change_timezone" not => strcmp("${windows_timezone}", "${current_timezone}");
files:
# Adjust ntp.conf (Add the servers)
!windows.(ntp_config_file_exists|ntp_installed)::
"/etc/ntp.conf"
edit_line => setNtpServer("@{this.ntpServers}"),
edit_defaults => noempty_backup,
classes => kept_if_else("ntpconf_kept", "repaired_ntpconf", "not_repaired_ntpconf");
# Copy the correct localtime file (distro independant)
!clock_timezone_noedit.!windows.clock_vardef::
"/etc/localtime"
copy_from => digest_cp("/usr/share/zoneinfo/${linux_timezone}"),
comment => "Updating the /etc/localtime file",
classes => kept_if_else("localtime_kept", "repaired_localtime", "not_repaired_localtime");
# Edit the distro dependant files to set the TZ on boot
(redhat.!clock_timezone_noedit).clock_vardef::
"/etc/sysconfig/clock"
edit_line => EditCentOSTimezone("${linux_timezone}"),
edit_defaults => noempty_backup,
classes => kept_if_else("redhattz_kept", "repaired_redhattz", "not_repaired_redhattz");
(SuSE.!clock_timezone_noedit).clock_vardef::
"/etc/sysconfig/clock"
edit_line => EditSuSETimezone("${linux_timezone}"),
edit_defaults => noempty_backup,
classes => kept_if_else("susetz_kept", "repaired_susetz", "not_repaired_susetz");
(debian.!clock_timezone_noedit).clock_vardef::
"/etc/timezone"
edit_defaults => empty_backup,
edit_line => EditDebianTimezone("${linux_timezone}"),
classes => kept_if_else("debiantz_kept", "repaired_debiantz", "not_repaired_debiantz");
# Install the NTP package
packages:
linux.!SuSE_10.!SuSE_11::
"ntp"
package_policy => "add",
package_method => generic,
classes => kept_if_else("ntp_install_kept", "ntp_installed", "cant_install_ntp"),
comment => "Installing ntp";
SuSE_11::
"ntp"
package_policy => "add",
package_method => zypper,
classes => kept_if_else("ntp_install_kept", "ntp_installed", "cant_install_ntp"),
comment => "Installing ntp using zypper";
SuSE_10::
"xntp"
package_policy => "add",
package_method => rudder_rug,
classes => kept_if_else("ntp_install_kept", "ntp_installed", "cant_install_ntp"),
comment => "Installing xntp using rug";
processes:
# If NTP is down, define its restart class
"ntpd"
restart_class => "ntpd_down";
commands:
# Restart commands
!windows.!redhat.(repaired_ntpconf|repaired_localtime|repaired_debiantz|repaired_susetz|ntpd_down)::
"/etc/init.d/ntp"
args => "restart",
classes => cf2_if_else("ntp_restarted", "cant_restart_ntp"),
comment => "restarting ntp";
redhat.(repaired_ntpconf|repaired_localtime|repaired_redhattz|ntpd_down)::
"/etc/init.d/ntpd"
args => "restart",
classes => cf2_if_else("ntp_restarted", "cant_restart_ntp"),
comment => "restarting ntp";
(windows.!clock_timezone_noedit).clock_vardef.need_to_change_timezone::
"\"${sys.winsysdir}\tzutil.exe\""
args => "/s \"${windows_timezone}\"",
contain => in_shell,
classes => rudder_common_classes("timezone_change"),
comment => "set the windows time zone";
(windows.!clock_timezone_noedit).ntp_regset::
"\"${sys.winsysdir}\net.exe\""
args => "stop W32Time",
contain => in_shell,
classes => cf2_if_else("ntp_winsvcstop", "ntp_winsvcstop"),
comment => "Restart the windows NTP service";
(windows.!clock_timezone_noedit).ntp_winsvcstop::
"\"${sys.winsysdir}\net.exe\""
args => "start W32Time",
contain => in_shell,
classes => cf2_if_else("ntp_win32time_started", "ntp_win32time_error"),
comment => "Restart the windows NTP service";
# HW clock sync command
!windows::
"/sbin/hwclock"
args => "--systohc",
action => if_elapsed("&CLOCK_SYNCSCHED&"),
classes => cf2_if_else("ntp_hwclock_synced", "ntp_hwclock_sync_error"),
comment => "synchronizing hardware clock";
&if(NOVA)&
databases:
windows::
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Parameters"
database_operation => "create",
database_rows => { "Type,REG_SZ,NTP", "NtpServer,REG_SZ,${serverskey}"},
database_type => "ms_registry",
comment => "Editing the windows registry to set the required NTP entries",
classes => kept_if_else("ntp_regkept", "ntp_regset", "ntp_regfail");
&endif&
reports:
# Global report for the "Time synchronization (NTP)" component - Linux
(ntp_install_kept|(!linux.!windows)).ntpconf_kept.!ntpd_down::
"@@ntpConfiguration@@result_success@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#ntp daemon installed, configured and running";
ntp_installed|repaired_ntpconf|ntp_restarted::
"@@ntpConfiguration@@result_repaired@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#ntp service (package, configuration and/or process) repaired";
# Global report for the "Time synchronization (NTP)" component - Windows
ntp_regkept::
"@@ntpConfiguration@@result_success@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#NTP service configured and running";
ntp_regset.ntp_win32time_started::
"@@ntpConfiguration@@result_repaired@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#NTP service repaired, it is now configured and running";
# Individual reports for the "Time synchronization (NTP)" component's parts
cant_install_ntp::
"@@ntpConfiguration@@result_error@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#ntp package could not be installed";
ntp_installed::
"@@ntpConfiguration@@log_repaired@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#ntp package installed";
ntp_install_kept::
"@@ntpConfiguration@@log_info@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#ntp package already installed";
!linux.!windows::
"@@ntpConfiguration@@log_info@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#Support to check if ntp is installed not available on this platform";
repaired_ntpconf::
"@@ntpConfiguration@@log_repaired@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#ntpd configuration updated";
not_repaired_ntpconf::
"@@ntpConfiguration@@result_error@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#ntpd configuration could not be changed";
ntpd_down::
"@@ntpConfiguration@@log_info@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#ntpd process was not running";
ntp_restarted::
"@@ntpConfiguration@@log_repaired@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#ntpd process restarted";
cant_restart_ntp::
"@@ntpConfiguration@@result_error@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#ntpd process could not be restarted";
ntp_regset::
"@@ntpConfiguration@@log_repaired@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#NTP service configured in the Windows registry. W32Time will restart";
ntp_regfail::
"@@ntpConfiguration@@result_error@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#NTP service could not be configured in the Windows registry";
ntp_regkept::
"@@ntpConfiguration@@log_info@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#NTP service was already configured in the Windows registry";
ntp_win32time_started::
"@@ntpConfiguration@@log_info@@&TRACKINGKEY&@@Time synchronization (NTP)@@None@@${g.execRun}##${g.uuid}@#NTP service (W32Time) restarted";
# Global reports for the "Time zone" component's parts
repaired_localtime|repaired_redhattz|repaired_debiantz|repaired_susetz::
"@@ntpConfiguration@@result_repaired@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Time zone was reset";
localtime_kept.((redhat.redhattz_kept)|(debian.debiantz_kept)|(SuSE.susetz_kept))::
"@@ntpConfiguration@@result_success@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Time zone was already correctly configured";
clock_timezone_noedit::
"@@ntpConfiguration@@result_success@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Time zone edition disabled";
# Individual reports for the "Time zone" component's parts
(windows.!clock_timezone_noedit).clock_vardef.!need_to_change_timezone::
"@@ntpConfiguration@@result_success@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Time zone was already correctly configured";
timezone_change_repaired|repaired_localtime::
"@@ntpConfiguration@@log_repaired@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Time zone was reset (localtime file changed)";
not_repaired_localtime|timezone_change_failed::
"@@ntpConfiguration@@result_error@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Time zone could not be set (localtime file could not be changed)";
localtime_kept::
"@@ntpConfiguration@@log_info@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Time zone was already set (localtime file didn't need changing)";
repaired_redhattz::
"@@ntpConfiguration@@log_repaired@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Red Hat-style specific time zone parameters updated (/etc/sysconfig/clock)";
not_repaired_redhattz::
"@@ntpConfiguration@@result_error@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Could not update Red Hat-style time zone parameters (/etc/sysconfig/clock)";
redhattz_kept::
"@@ntpConfiguration@@log_info@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Red Hat-style time zone parameters already correct (/etc/sysconfig/clock)";
repaired_debiantz::
"@@ntpConfiguration@@log_repaired@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Debian-style time zone parameters updated (/etc/timezone)";
not_repaired_debiantz::
"@@ntpConfiguration@@result_error@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Could not update Debian-style time zone parameters (/etc/timezone)";
debiantz_kept::
"@@ntpConfiguration@@log_info@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Debian-style time zone parameters already correct (/etc/timezone)";
repaired_susetz::
"@@ntpConfiguration@@log_repaired@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#SuSE-style time zone parameters updated (/etc/sysconfig/clock)";
not_repaired_susetz::
"@@ntpConfiguration@@result_error@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#Could not update SuSE-style time zone parameters (/etc/sysconfig/clock)";
susetz_kept::
"@@ntpConfiguration@@log_info@@&TRACKINGKEY&@@Time zone@@None@@${g.execRun}##${g.uuid}@#SuSE-style time zone parameters already correct (/etc/sysconfig/clock)";
# Global reports for the "Hardware clock (RTC)" component
(!windows.!ntp_hwclock_sync_error.!ntp_hwclock_synced)::
"@@ntpConfiguration@@result_success@@&TRACKINGKEY&@@Hardware clock (RTC)@@None@@${g.execRun}##${g.uuid}@#It is not yet time to synchronize the hardware clock with the NTP time. Skipping...";
ntp_hwclock_synced::
"@@ntpConfiguration@@result_success@@&TRACKINGKEY&@@Hardware clock (RTC)@@None@@${g.execRun}##${g.uuid}@#The hardware clock has been synchronized with the NTP time";
ntp_hwclock_sync_error::
"@@ntpConfiguration@@result_error@@&TRACKINGKEY&@@Hardware clock (RTC)@@None@@${g.execRun}##${g.uuid}@#The hardware clock could not be synchronized with the NTP time";
windows::
"@@ntpConfiguration@@result_success@@&TRACKINGKEY&@@Hardware clock (RTC)@@None@@${g.execRun}##${g.uuid}@#The hardware clock is automatically synchronized with the NTP time on Windows";
}
bundle edit_line setNtpServer(serverlist)
{
delete_lines:
"server.*";
insert_lines:
"${rudder_parameters.rudder_file_edit_header}"
location => start,
insert_type => "preserve_block";
"server ${serverlist}";
}
bundle edit_line EditCentOSTimezone(tz)
{
insert_lines:
"${rudder_parameters.rudder_file_edit_header}"
location => start,
insert_type => "preserve_block";
replace_patterns:
# Ensure the ZONE is correct
"^[# ]*ZONE\=(?!${tz}).*$"
replace_with => value("ZONE=${tz}");
# Change UTC
"^[# ]*UTC=\+.*$"
replace_with => value("UTC=false");
# Change ARC
"^[# ]*ARC\s+.*$"
replace_with => value("ARC=false");
}
bundle edit_line EditSuSETimezone(tz)
{
insert_lines:
"${rudder_parameters.rudder_file_edit_header}"
location => start,
insert_type => "preserve_block";
replace_patterns:
# Ensure the TIMEZONE is correct
"^[# ]*TIMEZONE\=(?!\"${tz}\").*$"
replace_with => value("TIMEZONE=\"${tz}\"");
# Ensure the DEFAULT_TIMEZONE is correct
"^[# ]*DEFAULT_TIMEZONE\=(?!\"${tz}\").*$"
replace_with => value("DEFAULT_TIMEZONE=\"${tz}\"");
# Ensure the SYSTOHC is correct
"^[# ]*SYSTOHC\=(?!\"yes\").*$"
replace_with => value("SYSTOHC=\"yes\"");
}
bundle edit_line EditDebianTimezone(tz)
{
insert_lines:
# Ensure the ZONE is correct
"${tz}";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle common generic_cmd_var_def {
vars:
&GENERIC_COMMAND_VARIABLE_NAME, GENERIC_COMMAND_VARIABLE_BINARY, GENERIC_COMMAND_VARIABLE_SHELL:{name, binary, shell |"&name&" string => execresult("&binary&", "&shell&");
}&
}
bundle agent generic_cmd_var_def_report {
vars:
&TRACKINGKEY:{directiveId |"generic_command_name_uuid[&i&]" string => "&directiveId&";
}&
&GENERIC_COMMAND_VARIABLE_NAME:{name |"generic_cmd_variable_name[&i&]" string => "&name&";
}&
"generic_cmd_variable_name_index" slist => getindices("generic_command_name_uuid");
reports:
cfengine_3::
"@@genericCommandVariableDefinition@@result_success@@${generic_command_name_uuid[${generic_cmd_variable_name_index}]}@@Variable command definition@@${generic_cmd_variable_name[${generic_cmd_variable_name_index}]}@@${g.execRun}##${g.uuid}@#A generic command variable definition is set for variable ${generic_cmd_variable_name[${generic_cmd_variable_name_index}]}";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle common generic_variable_definition
{
vars:
&GENERIC_VARIABLE_NAME, GENERIC_VARIABLE_CONTENT:{name, content |"&name&" string => "&content&",
policy => "overridable";
}&
}
bundle agent generic_variable_def_report
{
vars:
&TRACKINGKEY:{directiveId |"generic_name_uuid[&i&]" string => "&directiveId&";
}&
&GENERIC_VARIABLE_NAME:{name |"generic_variable_name[&i&]" string => "&name&";
}&
"generic_variable_name_index" slist => getindices("generic_name_uuid");
reports:
(linux|!linux)::
"@@genericVariableDefinition@@result_success@@${generic_name_uuid[${generic_variable_name_index}]}@@Variable definition@@${generic_variable_name[${generic_variable_name_index}]}@@${g.execRun}##${g.uuid}@#A generic variable definition is set for variable ${generic_variable_name[${generic_variable_name_index}]}";
}
#####################################################################################
# Copyright 2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
###########################################################################
# Monitor partition and optionnaly execute command if threshold is reached
#
# Take a partition mount point and check free space
# Execute a command if threshold is reached
#
bundle agent monitor_partition_size {
vars:
&PARTITION_SIZE_MONITORING_PATH:{path |"partition[&i&][path]" string => "&path&";
}&
&PARTITION_SIZE_MONITORING_FREE_SIZE:{freesize |"partition[&i&][freesize]" string => "&freesize&";
}&
&PARTITION_SIZE_MONITORING_CMD_EXEC_REPAIRED_COMMAND:{repaired_cmd |"partition[&i&][repaired_cmd]" string => "&repaired_cmd&";
}&
&TRACKINGKEY:{directiveId |"partition[&i&][uuid]" string => "&directiveId&";
}&
"index" slist => getindices("partition");
classes:
# Set classes to define when to run command executions
&PARTITION_SIZE_MONITORING_CMD_EXEC_REPAIRED_RUN:{repaired_cmd_run |"monitorPartitionSize_repaired_cmd_run_&i&" expression => strcmp("&repaired_cmd_run&", "true");
}&
commands:
"${partition[${index}][repaired_cmd]}"
classes => rudder_common_classes("monitorPartitionSize_repaired_cmd_${index}"),
contain => in_shell,
ifvarclass => "monitorPartitionSize_repaired_cmd_run_${index}.monitorPartitionSize_partition_${index}_full";
storage:
"${partition[${index}][path]}"
volume => freespacecheck("${partition[${index}][freesize]}"),
classes => if_notkept("monitorPartitionSize_partition_${index}_full"),
comment => "Check free space available on ${partition[${index}][path]}";
reports:
cfengine::
# Partition status reporting
# Success
"@@monitorPartitionSize@@result_success@@${partition[${index}][uuid]}@@Partition@@${partition[${index}][path]}@@${g.execRun}##${g.uuid}@#The partition ${partition[${index}][path]} has enough free space"
ifvarclass => "!monitorPartitionSize_partition_${index}_full";
# Error
"@@monitorPartitionSize@@result_error@@${partition[${index}][uuid]}@@Partition@@${partition[${index}][path]}@@${g.execRun}##${g.uuid}@#The partition ${partition[${index}][path]} has not enough free space"
ifvarclass => "monitorPartitionSize_partition_${index}_full";
# Repaired command execution reporting
# Success not set
"@@monitorPartitionSize@@result_success@@${partition[${index}][uuid]}@@Command execution on threshold@@${partition[${index}][path]}@@${g.execRun}##${g.uuid}@#Under threshold command execution was not set"
ifvarclass => "!monitorPartitionSize_repaired_cmd_run_${index}";
# Success not needed
"@@monitorPartitionSize@@result_success@@${partition[${index}][uuid]}@@Command execution on threshold@@${partition[${index}][path]}@@${g.execRun}##${g.uuid}@#Under threshold command execution was not needed"
ifvarclass => "monitorPartitionSize_repaired_cmd_run_${index}.!monitorPartitionSize_partition_${index}_full";
# Repaired
"@@monitorPartitionSize@@result_repaired@@${partition[${index}][uuid]}@@Command execution on threshold@@${partition[${index}][path]}@@${g.execRun}##${g.uuid}@#Under threshold command executed - ${partition[${index}][repaired_cmd]}"
ifvarclass => "monitorPartitionSize_repaired_cmd_run_${index}.monitorPartitionSize_repaired_cmd_${index}_repaired";
# Error
"@@monitorPartitionSize@@result_error@@${partition[${index}][uuid]}@@Command execution on threshold@@${partition[${index}][path]}@@${g.execRun}##${g.uuid}@#Under threshold command failed to execute"
ifvarclass => "monitorPartitionSize_repaired_cmd_run_${index}.monitorPartitionSize_repaired_cmd_${index}_error";
}
body volume freespacecheck(threshold) {
freespace => "${threshold}";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#Check the dns configuration, and correct it if required
#CAUTION : the loop for windows does not work well, a bug is opened (#82)
bundle agent check_dns_configuration
{
vars:
"resolvers" slist => {&DNS_RESOLVERS: { "&it&" };separator=", "&};
"searchlist" slist => {&DNS_SEARCHLIST: { "&it&" };separator=", "&};
"options" slist => {&DNS_OPTIONS: { "&it&" };separator=", "&};
"spaced_searchlist" string => join(" ", "searchlist");
"spaced_options" string => join(" ", "options");
&if(NOVA)&
windows::
"searchkey" string => join("\,", searchlist);
"resolvkey" string => join("\,", resolvers);
"adapters" string => execresult("\"${g.rudder_sbin}\registrydns.bat\"", "noshell"),
comment => "Fetching all the adapter";
"adapterslist" slist => splitstring("${adapters}", ";", "15");
&endif&
classes:
# DNS Resolver edition ?
"dns_resolver_edit" not => strcmp("&DNS_RESOLVERS_EDIT&","false");
# DNS Search suffix edition ?
"dns_searchlist_edit" not => strcmp("&DNS_SEARCHLIST_EDIT&","false");
# DNS options edition ?
"dns_options_edit" not => strcmp("&DNS_OPTIONS_EDIT&","false");
files:
!windows::
"${sys.resolv}"
create => "true",
edit_line => resolv_edition("${this.spaced_searchlist}", "@{this.resolvers}", "${this.spaced_options}"),
edit_defaults => noempty_backup,
classes => kept_if_else("dns_kept", "dns_repaired", "cant_repair_dns");
&if(NOVA)&
methods:
windows.dns_resolver_edit::
"any" usebundle => checkDNS(${adapterslist}, ${resolvkey});
databases:
windows.dns_resolver_edit::
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
database_operation => "verify",
database_type => "ms_registry",
database_rows => { "NameServer,REG_SZ,${resolvkey}"},
comment => "Set the top level resolver",
classes => kept_if_else("dns_resolver_kept", "dns_repaired_resolver", "cant_repair_dns_resolver");
windows.dns_searchlist_edit::
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
database_operation => "verify",
database_type => "ms_registry",
database_rows => { "SearchList,REG_SZ,${searchkey}"},
comment => "Set the search list",
classes => kept_if_else("dns_searchlist_kept", "dns_repaired_searchlist", "cant_repair_dns_searchlist");
&endif&
reports:
dns_resolver_edit::
"@@ConfigureDNS@@log_debug@@&TRACKINGKEY&@@dnsConfiguration@@None@@${g.execRun}##${g.uuid}@#Settings are to edit DNS resolvers";
dns_searchlist_edit::
"@@ConfigureDNS@@log_debug@@&TRACKINGKEY&@@dnsConfiguration@@None@@${g.execRun}##${g.uuid}@#Settings are to edit DNS searchlist";
(!windows.dns_repaired)::
"@@ConfigureDNS@@result_repaired@@&TRACKINGKEY&@@dnsConfiguration@@None@@${g.execRun}##${g.uuid}@#DNS settings were updated";
windows.((dns_repaired_resolver.!cant_repair_dns_resolver.dns_resolver_edit)|(dns_repaired_searchlist.!cant_repair_dns_searchlist.dns_searchlist_edit))::
"@@ConfigureDNS@@result_repaired@@&TRACKINGKEY&@@dnsConfiguration@@None@@${g.execRun}##${g.uuid}@#DNS settings were updated";
cant_repair_dns::
"@@ConfigureDNS@@result_error@@&TRACKINGKEY&@@dnsConfiguration@@None@@${g.execRun}##${g.uuid}@#Could not edit the ${sys.resolv} configuration file";
cant_repair_dns_searchlist::
"@@ConfigureDNS@@result_error@@&TRACKINGKEY&@@dnsConfiguration@@None@@${g.execRun}##${g.uuid}@#Could not set DNS search list in the Windows registry";
cant_repair_dns_resolver::
"@@ConfigureDNS@@result_error@@&TRACKINGKEY&@@dnsConfiguration@@None@@${g.execRun}##${g.uuid}@#Could not set DNS resolver list in the Windows registry";
!windows.dns_kept.!dns_repaired.!cant_repair_dns::
"@@ConfigureDNS@@result_success@@&TRACKINGKEY&@@dnsConfiguration@@None@@${g.execRun}##${g.uuid}@#The DNS is correctly configured";
&if(NOVA)&
#windows and something to do
windows.((dns_resolver_edit.dns_resolver_kept.!dns_repaired_resolver)|!dns_resolver_edit).((dns_searchlist_edit.dns_searchlist_kept.!dns_repaired_searchlist)|!dns_searchlist_edit)::
"@@ConfigureDNS@@result_success@@&TRACKINGKEY&@@dnsConfiguration@@None@@${g.execRun}##${g.uuid}@#The DNS is correctly configured";
&endif&
&if(COMMUNITY)&
windows::
"@@ConfigureDNS@@result_error@@&TRACKINGKEY&@@dnsConfiguration@@None@@${g.execRun}##${g.uuid}@#Can't repair the dns configuration on a Windows with community edition";
&endif&
}
&if(NOVA)&
######################################################
# For each adapter passed in arguement, add the value
# NameServer, regKey
######################################################
bundle agent checkDNS(adapter, regKey)
{
classes:
"valid" expression => regcmp("{.*","${adapter}"),
comment => "A valid adapter starts with {";
databases:
valid::
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\${adapter}"
database_operation => "verify",
database_type => "ms_registry",
database_rows => { "NameServer,REG_SZ,${regKey}"},
classes => kept_if_else("dns_resolver_kept", "dns_repaired_resolver", "cant_repair_dns_resolver");
}
&endif&
#######################################################
# Add lines in the file, formated for resolv.conf file
bundle edit_line resolv_edition(search, list, options)
{
classes:
# DNS Resolver edition ?
"dns_resolver_edit" not => strcmp("&DNS_RESOLVERS_EDIT&","false");
# DNS Search suffix edition ?
"dns_searchlist_edit" not => strcmp("&DNS_SEARCHLIST_EDIT&","false");
# DNS options edition ?
"dns_options_edit" not => strcmp("&DNS_OPTIONS_EDIT&","false");
delete_lines:
dns_searchlist_edit::
"search.*";
dns_resolver_edit::
"nameserver.*";
dns_options_edit::
"options.*";
insert_lines:
"${rudder_parameters.rudder_file_edit_header}"
location => start,
insert_type => "preserve_block";
dns_options_edit::
"options ${options}";
dns_searchlist_edit::
"search ${search}";
dns_resolver_edit::
"nameserver ${list}";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# (C) Normation 2011
#
# NOTE : I permitted the creation of the hosts file if absent, but on a purely
# functionnal side, its absence means a severe breakage of your IP stack. Be
# aware of this if a file creation is reported !
#
bundle agent check_hosts_configuration
{
vars:
&HOSTS_HOST:{host |"hosts_host[&i&]" string => "&host&";
}&
&HOSTS_IP:{ip |"hosts_ip[&i&]" string => "&ip&";
}&
"hosts_base_template" string => "&HOSTS_BASE_TEMPLATE&";
files:
!windows::
"/etc/hosts"
create => "true",
perms => m("644"),
&if (HOSTS_ENFORCE)&
edit_defaults => empty_backup,
&else&
edit_defaults => noempty_backup,
&endif&
edit_line => set_hosts_values("check_hosts_configuration.hosts_host", "check_hosts_configuration.hosts_ip", "${hosts_base_template}"),
classes => kept_if_else("hosts_edition_kept", "hosts_edition_done", "hosts_edition_failed");
windows::
"${sys.winsysdir}\drivers\etc\hosts"
create => "true",
# perms => m("644"),
&if (HOSTS_ENFORCE)&
edit_defaults => empty_backup,
&else&
edit_defaults => noempty_backup,
&endif&
edit_line => set_hosts_values("check_hosts_configuration.hosts_host", "check_hosts_configuration.hosts_ip"),
classes => kept_if_else("hosts_edition_kept", "hosts_edition_done", "hosts_edition_failed");
reports:
cfengine::
&if (HOSTS_ENFORCE)&
"@@hostsConfiguration@@log_debug@@&TRACKINGKEY&@@hostsConfiguration@@None@@${g.execRun}##${g.uuid}@#Hosts file content enforcement requested";
&endif&
hosts_edition_done::
"@@hostsConfiguration@@result_repaired@@&TRACKINGKEY&@@hostsConfiguration@@None@@${g.execRun}##${g.uuid}@#Hosts file was updated";
hosts_edition_kept.!hosts_edition_done::
"@@hostsConfiguration@@result_success@@&TRACKINGKEY&@@hostsConfiguration@@None@@${g.execRun}##${g.uuid}@#Hosts file already OK";
hosts_edition_failed::
"@@hostsConfiguration@@result_error@@&TRACKINGKEY&@@hostsConfiguration@@None@@${g.execRun}##${g.uuid}@#Hosts file could not be edited";
}
bundle edit_line set_hosts_values(hosts, ips, base_tmpl)
{
vars:
"hosts_index" slist => getindices("${hosts}");
delete_lines:
"${${ips}[${hosts_index}]}.*";
insert_lines:
&if (HOSTS_ENFORCE)&
"${base_tmpl}"
insert_type => "preserve_block";
&endif&
"${${ips}[${hosts_index}]} ${${hosts}[${hosts_index}]}";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# (C) Normation 2011
bundle agent check_nfs_client_configuration
{
vars:
&NFS_CLIENT_REMOTE_PATH:{remote_path |"nfs_client_remote_path[&i&]" string => "&remote_path&";
}&
&NFS_CLIENT_REMOTE_SERVER:{remote_server |"nfs_client_remote_server[&i&]" string => "&remote_server&";
}&
&NFS_CLIENT_LOCAL_PATH:{local_path |"nfs_client_local_path[&i&]" string => "&local_path&";
}&
&NFS_CLIENT_REMOTE_TYPE:{remote_type |"nfs_client_remote_type[&i&]" string => "&remote_type&";
}&
&NFS_CLIENT_ADDFSTAB:{addfstab |"nfs_client_addfstab[&i&]" string => "&addfstab&";
}&
&NFS_CLIENT_UMOUNT:{umount |"nfs_client_umount[&i&]" string => "&umount&";
}&
&TRACKINGKEY:{uuid |"nfs_client_uuid[&i&]" string => "&uuid&";
}&
"nfs_client_index" slist => getindices("nfs_client_remote_path");
classes:
"begin_evaluation" expression => isvariable("nfs_client_index");
begin_evaluation::
"index_${nfs_client_index}_add" expression => strcmp("${nfs_client_umount[${nfs_client_index}]}", "no");
"index_${nfs_client_index}_remove" expression => strcmp("${nfs_client_umount[${nfs_client_index}]}", "yes");
storage:
!windows::
"${nfs_client_local_path[${nfs_client_index}]}"
mount => rudder_nfs("${nfs_client_remote_server[${nfs_client_index}]}","${nfs_client_remote_path[${nfs_client_index}]}", "${nfs_client_remote_type[${nfs_client_index}]}", "${nfs_client_addfstab[${nfs_client_index}]}"),
classes => kept_if_else("${nfs_client_index}_operation_kept", "${nfs_client_index}_operation_ok", "${nfs_client_index}_operation_failed"),
ifvarclass => "index_${nfs_client_index}_add";
"${nfs_client_local_path[${nfs_client_index}]}"
mount => unmount,
classes => kept_if_else("${nfs_client_index}_operation_kept", "${nfs_client_index}_operation_ok", "${nfs_client_index}_operation_failed"),
ifvarclass => "index_${nfs_client_index}_remove";
reports:
!windows::
"@@nfsClient@@result_repaired@@${nfs_client_uuid[${nfs_client_index}]}@@NFS mountpoint@@${nfs_client_local_path[${nfs_client_index}]}@@${g.execRun}##${g.uuid}@#The path ${nfs_client_local_path[${nfs_client_index}]} was successfully mounted on ${nfs_client_remote_server[${nfs_client_index}]}:${nfs_client_remote_path[${nfs_client_index}]}"
ifvarclass => "${nfs_client_index}_operation_ok.index_${nfs_client_index}_add";
"@@nfsClient@@result_repaired@@${nfs_client_uuid[${nfs_client_index}]}@@NFS mountpoint@@${nfs_client_local_path[${nfs_client_index}]}@@${g.execRun}##${g.uuid}@#The path ${nfs_client_local_path[${nfs_client_index}]} was successfully unmounted on ${nfs_client_remote_server[${nfs_client_index}]}:${nfs_client_remote_path[${nfs_client_index}]}"
ifvarclass => "${nfs_client_index}_operation_ok.index_${nfs_client_index}_remove";
"@@nfsClient@@result_success@@${nfs_client_uuid[${nfs_client_index}]}@@NFS mountpoint@@${nfs_client_local_path[${nfs_client_index}]}@@${g.execRun}##${g.uuid}@#The path ${nfs_client_local_path[${nfs_client_index}]} was already mounted on ${nfs_client_remote_server[${nfs_client_index}]}:${nfs_client_remote_path[${nfs_client_index}]}"
ifvarclass => "${nfs_client_index}_operation_kept.index_${nfs_client_index}_add";
"@@nfsClient@@result_success@@${nfs_client_uuid[${nfs_client_index}]}@@NFS mountpoint@@${nfs_client_local_path[${nfs_client_index}]}@@${g.execRun}##${g.uuid}@#The path ${nfs_client_local_path[${nfs_client_index}]} was not mounted on ${nfs_client_remote_server[${nfs_client_index}]}:${nfs_client_remote_path[${nfs_client_index}]}"
ifvarclass => "${nfs_client_index}_operation_kept.index_${nfs_client_index}_remove";
"@@nfsClient@@result_error@@${nfs_client_uuid[${nfs_client_index}]}@@NFS mountpoint@@${nfs_client_local_path[${nfs_client_index}]}@@${g.execRun}##${g.uuid}@#The path ${nfs_client_local_path[${nfs_client_index}]} was NOT mounted on ${nfs_client_remote_server[${nfs_client_index}]}:${nfs_client_remote_path[${nfs_client_index}]}. This could be an error in the mount definition or an nfs failure"
ifvarclass => "${nfs_client_index}_operation_failed.!${nfs_client_index}_operation_ok.index_${nfs_client_index}_add";
"@@nfsClient@@result_error@@${nfs_client_uuid[${nfs_client_index}]}@@NFS mountpoint@@${nfs_client_local_path[${nfs_client_index}]}@@${g.execRun}##${g.uuid}@#The path ${nfs_client_local_path[${nfs_client_index}]} was NOT unmounted on ${nfs_client_remote_server[${nfs_client_index}]}:${nfs_client_remote_path[${nfs_client_index}]}. This could be an error in the mount definition or an nfs failure"
ifvarclass => "${nfs_client_index}_operation_failed.!${nfs_client_index}_operation_ok.index_${nfs_client_index}_remove";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
###############################################################
# Installs the NFS client
bundle agent check_nfs_client_installation
{
packages:
linux.!redhat.!SuSE::
"nfs-common"
package_policy => "add",
package_method => generic,
classes => kept_if_else("nfs_client_here", "nfs_client_installed", "cant_install_nfs_client"),
comment => "Installing NFS client using generic interface";
redhat::
"nfs-utils"
package_policy => "add",
package_method => generic,
classes => kept_if_else("nfs_client_here", "nfs_client_installed", "cant_install_nfs_client"),
comment => "Installing NFS client using generic interface";
SuSE::
"nfs-client"
package_policy => "add",
package_method => generic,
classes => kept_if_else("nfs_client_here", "nfs_client_installed", "cant_install_nfs_client"),
comment => "Installing NFS client using generic interface";
reports:
nfs_client_here::
"@@nfsClient@@result_success@@&TRACKINGKEY&@@NFS Client package install@@None@@${g.execRun}##${g.uuid}@#NFS client already installed";
nfs_client_installed::
"@@nfsClient@@result_repaired@@&TRACKINGKEY&@@NFS Client package install@@None@@${g.execRun}##${g.uuid}@#NFS client installed";
cant_install_nfs_client::
"@@nfsClient@@result_error@@&TRACKINGKEY&@@NFS Client package install@@None@@${g.execRun}##${g.uuid}@#Can't install the NFS client package";
!linux::
"@@nfsClient@@result_success@@&TRACKINGKEY&@@NFS Client package install@@None@@${g.execRun}##${g.uuid}@#Support to check if NFS client is installed not available on this platform";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# (C) Normation 2011
bundle agent check_nfs_server_configuration
{
vars:
&NFS_SERVER_PATH:{path |"nfs_server_path[&i&]" string => "&path&";
}&
&NFS_SERVER_NETWORK:{network |"nfs_server_network[&i&]" string => "&network&";
}&
&NFS_SERVER_SECURE,NFS_SERVER_READWRITE,NFS_SERVER_SYNC,NFS_SERVER_WDELAY,NFS_SERVER_HIDE,NFS_SERVER_SUBTREECHECK,NFS_SERVER_SECURELOCKS,NFS_SERVER_ACL:{secure, readwrite, sync, wdelay, hide, subtreecheck, securelocks, acl |"nfs_server_options[&i&]" string => "&secure&,&readwrite&,&sync&,&wdelay&,&hide&,&subtreecheck&,&securelocks&,&acl&";
}&
&TRACKINGKEY:{uuid |"nfs_server_uuid[&i&]" string => "&uuid&";
}&
"nfs_server_index" slist => getindices("nfs_server_path");
files:
(debian|redhat|SuSE)::
"/etc/rc2.d/S.*nfs.*"
create => "true",
#depth_search => recurse("0"),
#file_select => ssh_startlink,
action => WarnOnly,
classes => cf2_if_else("nfs_server_bootstarted", "nfs_server_unbootstarted");
!windows::
"/etc/exports"
create => "true",
perms => m("644"),
edit_defaults => noempty_backup,
edit_line => set_nfs_server_values("${nfs_server_path[${nfs_server_index}]}", "${nfs_server_network[${nfs_server_index}]}", "${nfs_server_options[${nfs_server_index}]}"),
classes => kept_if_else("nfs_server_${nfs_server_index}_kept", "nfs_server_${nfs_server_index}_done", "nfs_server_${nfs_server_index}_failed");
commands:
debian::
"/etc/init.d/nfs-kernel-server"
args => "restart",
ifvarclass => canonify("nfs_server_${nfs_server_index}_done"),
classes => cf2_if_else("nfs_server_${nfs_server_index}_restarted", "nfs_server_${nfs_server_index}_not_restarted"),
comment => "Restarting the NFS server";
"/usr/sbin/update-rc.d"
args => "nfs-kernel-server defaults",
ifvarclass => canonify("nfs_server_unbootstarted"),
comment => "adding nfs to the startup scripts";
redhat::
"/sbin/chkconfig"
args => "--add nfs",
ifvarclass => canonify("nfs_server_unbootstarted"),
comment => "adding nfs to the startup scripts";
"/sbin/chkconfig"
args => "--add nfslock",
ifvarclass => canonify("nfs_server_unbootstarted"),
comment => "adding nfslock to the startup scripts";
"/sbin/service"
args => "nfs restart",
ifvarclass => canonify("nfs_server_${nfs_server_index}_done"),
classes => cf2_if_else("nfs_server_${nfs_server_index}_restarted", "nfs_server_${nfs_server_index}_not_restarted"),
comment => "Restarting the NFS server";
"/sbin/service"
args => "nfslock restart",
ifvarclass => canonify("nfs_server_${nfs_server_index}_done"),
classes => cf2_if_else("nfs_server_${nfs_server_index}_restarted", "nfs_server_${nfs_server_index}_not_restarted"),
comment => "Restarting the NFS lock server";
SuSE::
"/sbin/chkconfig"
args => "--add nfsserver",
ifvarclass => canonify("nfs_server_unbootstarted"),
comment => "adding nfs to the startup scripts";
"/sbin/service"
args => "nfsserver restart",
ifvarclass => canonify("nfs_server_${nfs_server_index}_done"),
classes => cf2_if_else("nfs_server_${nfs_server_index}_restarted", "nfs_server_${nfs_server_index}_not_restarted"),
comment => "Restarting the NFS server";
reports:
!windows::
"@@nfsServer@@result_repaired@@${nfs_server_uuid[${nfs_server_index}]}@@NFS server settings@@${nfs_server_path[${nfs_server_index}]}@@${g.execRun}##${g.uuid}@#The export ${nfs_server_path[${nfs_server_index}]} was successfully added"
ifvarclass => canonify("nfs_server_${nfs_server_index}_done");
"@@nfsServer@@result_success@@${nfs_server_uuid[${nfs_server_index}]}@@NFS server settings@@${nfs_server_path[${nfs_server_index}]}@@${g.execRun}##${g.uuid}@#The export ${nfs_server_path[${nfs_server_index}]} is already present"
ifvarclass => canonify("nfs_server_${nfs_server_index}_kept");
"@@nfsServer@@result_error@@${nfs_server_uuid[${nfs_server_index}]}@@NFS server settings@@${nfs_server_path[${nfs_server_index}]}@@${g.execRun}##${g.uuid}@#The export ${nfs_server_path[${nfs_server_index}]} could not be added"
ifvarclass => canonify("nfs_server_${nfs_server_index}_failed");
(debian|redhat|SuSE)::
"@@nfsServer@@log_repaired@@${nfs_server_uuid[${nfs_server_index}]}@@NFS server settings@@${nfs_server_path[${nfs_server_index}]}@@${g.execRun}##${g.uuid}@#Restarted the NFS server because of the export ${nfs_server_path[${nfs_server_index}]}"
ifvarclass => canonify("nfs_server_${nfs_server_index}_restarted");
"@@nfsServer@@result_error@@${nfs_server_uuid[${nfs_server_index}]}@@NFS server settings@@${nfs_server_path[${nfs_server_index}]}@@${g.execRun}##${g.uuid}@#Could not restart the NFS server because of the export ${nfs_server_path[${nfs_server_index}]}"
ifvarclass => canonify("nfs_server_${nfs_server_index}_not_restarted");
}
bundle edit_line set_nfs_server_values(export, network, options)
{
delete_lines:
"${export}.*";
insert_lines:
"${export} ${network}(${options})";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
###############################################################
# Installs the NFS server
bundle agent check_nfs_server_installation
{
packages:
linux.!redhat::
"nfs-kernel-server"
package_policy => "add",
package_method => generic,
classes => kept_if_else("nfs_server_here", "nfs_server_installed", "cant_install_nfs_server"),
comment => "Installing NFS server using generic interface";
redhat::
"nfs-utils"
package_policy => "add",
package_method => generic,
classes => kept_if_else("nfs_server_here", "nfs_server_installed", "cant_install_nfs_server"),
comment => "Installing NFS server using generic interface";
reports:
nfs_server_here::
"@@nfsServer@@result_success@@&TRACKINGKEY&@@NFS server package install@@None@@${g.execRun}##${g.uuid}@#NFS server package already installed";
nfs_server_installed::
"@@nfsServer@@result_repaired@@&TRACKINGKEY&@@NFS server package install@@None@@${g.execRun}##${g.uuid}@#NFS server package installed";
cant_install_nfs_server::
"@@nfsServer@@result_error@@&TRACKINGKEY&@@NFS server package install@@None@@${g.execRun}##${g.uuid}@#Can't install NFS server package";
!linux::
"@@nfsServer@@result_success@@&TRACKINGKEY&@@NFS server package install@@None@@${g.execRun}##${g.uuid}@#Support to check if NFS server is installed not available on this platform";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
##########################################################################
# Routing management PT #
# #
# Objective: Check the routing parameters according to the given ones #
# and take the required actions (check or require) #
##########################################################################
bundle agent check_routing_parameters
{
vars:
&ROUTING_FOUR_DESTINATION:{destination |"route[&i&]" string => "&destination&";
}&
&ROUTING_FOUR_GATEWAY:{gateway |"gateway[&i&]" string => "&gateway&";
}&
&ROUTING_FOUR_NETMASK:{netmask |"mask[&i&]" string => "&netmask&";
}&
&ROUTING_FOUR_ACTION:{action |"action[&i&]" string => "&action&";
}&
&TRACKINGKEY:{directiveId |"routing_directive_id[&i&]" string => "&directiveId&";
}&
"routing_index" slist => getindices("route");
"displayName[${routing_index}]" string => "${route[${routing_index}]} / ${mask[${routing_index}]} to ${gateway[${routing_index}]}";
classes:
"checkroute_present" expression => fileexists("${g.rudder_tools}/checkroute.pl");
commands:
!windows.checkroute_present::
"${g.rudder_tools}/checkroute.pl ${route[${routing_index}]} ${mask[${routing_index}]} ${gateway[${routing_index}]} ${routing_index} ${action[${routing_index}]} linux"
contain => in_shell,
module => "true",
comment => "Analysing routes";
"/sbin/route add -net ${route[${routing_index}]} netmask ${mask[${routing_index}]} gw ${gateway[${routing_index}]}"
contain => in_shell,
ifvarclass => canonify("route_${routing_index}_add"),
classes => cf2_if_else("route_${routing_index}_added", "route_${routing_index}_add_failed");
"/sbin/route del -net ${route[${routing_index}]} netmask ${mask[${routing_index}]} gw ${gateway[${routing_index}]}"
contain => in_shell,
ifvarclass => canonify("route_${routing_index}_delete"),
classes => cf2_if_else("route_${routing_index}_deleted", "route_${routing_index}_delete_failed");
windows.checkroute_present::
"\"${g.rudder_base_sbin}\perl\bin\perl.exe\""
args => "\"${g.rudder_tools}\checkroute.pl\" ${route[${routing_index}]} ${mask[${routing_index}]} ${gateway[${routing_index}]} ${routing_index} ${action[${routing_index}]} windows",
contain => in_shell,
module => "true",
comment => "Analysing routes";
"\"${sys.winsysdir}\route.exe\""
args => "ADD ${route[${routing_index}]} MASK ${mask[${routing_index}]} ${gateway[${routing_index}]}",
contain => in_shell,
ifvarclass => canonify("route_${routing_index}_add"),
classes => cf2_if_else("route_${routing_index}_added", "route_${routing_index}_add_failed");
"\"${sys.winsysdir}\route.exe\""
args => "DELETE ${route[${routing_index}]}",
contain => in_shell,
ifvarclass => canonify("route_${routing_index}_delete"),
classes => cf2_if_else("route_${routing_index}_deleted", "route_${routing_index}_delete_failed");
reports:
checkroute_present::
"@@routingManagement@@result_success@@${routing_directive_id[${routing_index}]}@@IPv4 routing parameters@@${route[${routing_index}]}@@${g.execRun}##${g.uuid}@#Route ${displayName[${routing_index}]} found, as expected."
ifvarclass => canonify("route_${routing_index}_found");
# This should be a log_warn, when it's supported
"@@routingManagement@@result_error@@${routing_directive_id[${routing_index}]}@@IPv4 routing parameters@@${route[${routing_index}]}@@${g.execRun}##${g.uuid}@#Route ${displayName[${routing_index}]} found, and policy is: Check absence!"
ifvarclass => canonify("route_${routing_index}_found_warn");
"@@routingManagement@@result_success@@${routing_directive_id[${routing_index}]}@@IPv4 routing parameters@@${route[${routing_index}]}@@${g.execRun}##${g.uuid}@#Route ${displayName[${routing_index}]} not found, as expected"
ifvarclass => canonify("route_${routing_index}_notfound");
# This should be a log_warn, when it's supported
"@@routingManagement@@result_error@@${routing_directive_id[${routing_index}]}@@IPv4 routing parameters@@${route[${routing_index}]}@@${g.execRun}##${g.uuid}@#Route ${displayName[${routing_index}]} not found , and policy is: Check presence!"
ifvarclass => canonify("route_${routing_index}_notfound_warn");
"@@routingManagement@@log_info@@${routing_directive_id[${routing_index}]}@@IPv4 routing parameters@@${route[${routing_index}]}@@${g.execRun}##${g.uuid}@#Route ${displayName[${routing_index}]} not found, attempting to add route..."
ifvarclass => canonify("route_${routing_index}_add");
"@@routingManagement@@result_repaired@@${routing_directive_id[${routing_index}]}@@IPv4 routing parameters@@${route[${routing_index}]}@@${g.execRun}##${g.uuid}@#Route ${displayName[${routing_index}]} added successfully!"
ifvarclass => canonify("route_${routing_index}_added");
"@@routingManagement@@result_error@@${routing_directive_id[${routing_index}]}@@IPv4 routing parameters@@${route[${routing_index}]}@@${g.execRun}##${g.uuid}@#Could not add route ${displayName[${routing_index}]}!"
ifvarclass => canonify("route_${routing_index}_add_failed");
"@@routingManagement@@result_repaired@@${routing_directive_id[${routing_index}]}@@IPv4 routing parameters@@${route[${routing_index}]}@@${g.execRun}##${g.uuid}@#Route ${displayName[${routing_index}]} deleted successfully!"
ifvarclass => canonify("route_${routing_index}_deleted");
"@@routingManagement@@result_error@@${routing_directive_id[${routing_index}]}@@IPv4 routing parameters@@${route[${routing_index}]}@@${g.execRun}##${g.uuid}@#Could not delete route ${displayName[${routing_index}]}!"
ifvarclass => canonify("route_${routing_index}_delete_failed");
!checkroute_present::
"@@routingManagement@@result_error@@${routing_directive_id[${routing_index}]}@@IPv4 routing parameters@@${route[${routing_index}]}@@${g.execRun}##${g.uuid}@#Could not add route ${displayName[${routing_index}]}: helper program checkroute.pl not found!";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# Enforce the defined process parameters
bundle agent process_management
{
vars:
"dim_array" int => readstringarray("file","${sys.workdir}/inputs/processManagement/proclist","#[^\n]*",",",15,4000);
"procList" slist => getindices("file");
methods:
"any" usebundle => check_process("${file[${procList}][0]}",
"${file[${procList}][1]}",
"${file[${procList}][2]}",
"${file[${procList}][3]}",
"${file[${procList}][4]}",
"${file[${procList}][5]}");
}
bundle agent check_process(directiveId, name, maxInst, minInst, command, args)
{
classes:
"${name}_command_empty" expression => strcmp("command","");
"${name}_arg_empty" expression => strcmp("args","");
processes:
"${name}"
restart_class => "${name}_restart",
comment => "Verifying process presence";
"${name}"
process_count => check_process_count("${name}", "${maxInst}","${minInst}"),
classes => kept_if_else("${name}_ok", "${name}_anomaly", "${name}_error"),
comment => "Verifying process count";
commands:
"${command}"
args => "${args}",
classes => kept_if_else("${name}_restart_ok", "${name}_restart_ok", "${name}_restart_error"),
ifvarclass => and( canonify("${name}_restart"), not(canonify("${name}_command_empty")), not(canonify("${name}_arg_empty")) );
"${command}"
classes => kept_if_else("${name}_restart_ok", "${name}_restart_ok", "${name}_restart_error"),
ifvarclass => and( canonify("${name}_restart"), not(canonify("${name}_command_empty")), canonify("${name}_arg_empty") );
"/etc/init.d/${name}"
args => "restart",
classes => kept_if_else("${name}_restart_ok", "${name}_restart_ok", "${name}_restart_error"),
ifvarclass => and( canonify("${name}_restart"), canonify("${name}_command_empty") );
reports:
cfengine_3::
"@@ProcessManagement@@result_error@@${directiveId}@@Process@@${name}@@${g.execRun}##${g.uuid}@#${name}: the process count could't be checked"
ifvarclass => canonify("${name}_error");
"@@ProcessManagement@@log_info@@${directiveId}@@Process@@${name}@@${g.execRun}##${g.uuid}@#${name}: the process instance count is out of the permitted range"
ifvarclass => canonify("${name}_anomaly");
"@@ProcessManagement@@log_info@@${directiveId}@@Process@@${name}@@${g.execRun}##${g.uuid}@#${name}: the process will be restarted"
ifvarclass => canonify("${name}_restart");
"@@ProcessManagement@@result_success@@${directiveId}@@Process@@${name}@@${g.execRun}##${g.uuid}@#${name}: the process was in range (${minInst}-${maxInst})"
ifvarclass => canonify("${name}_ok");
"@@ProcessManagement@@result_repaired@@${directiveId}@@Process@@${name}@@${g.execRun}##${g.uuid}@#${name}: the process has been restarted"
ifvarclass => canonify("${name}_restart_ok");
"@@ProcessManagement@@result_error@@${directiveId}@@Process@@${name}@@${g.execRun}##${g.uuid}@#${name}: the process could not be restarted"
ifvarclass => canonify("${name}_restart_error");
}
body process_count check_process_count(name, max, min)
{
match_range => irange("${min}","${max}");
out_of_range_define => { "${name}_anomaly" };
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# List of the process parameters to enforce
# Format of the file :
# policyIsntanceId, name:maximum_instances:minimum_instances
&TRACKINGKEY, PROCESS_NAME, PROCESS_MIN_INSTANCES, PROCESS_MAX_INSTANCES, PROCESS_COMMAND, PROCESS_MAX_ARGS:{directiveId, name, maxInst, minInst, command, args | &directiveId&,&name&,&maxInst&,&minInst&,&command&,&args&
}&
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# Enforce the defined services parameters
bundle agent services_management
{
vars:
&SERVICE_MANAGED_NAME:{name |"service[&i&][name]" string => "&name&";
}&
&SERVICE_MANAGED_NAME:{name |"service[&i&][canon_name]" string => canonify("&name&");
}&
&PROCESS_MANAGED_NAME:{process |"service[&i&][process]" string => "&process&";
}&
&PROCESS_MANAGED_RUNNING:{running |"service[&i&][running]" string => "&running&";
}&
&PROCESS_MANAGED_KILLING_METHOD:{kill |"service[&i&][killMethod]" string => "&kill&";
}&
&PROCESS_MANAGED_MIN_INSTANCES:{min_instance |"service[&i&][min_instance]" string => "&min_instance&";
}&
&PROCESS_MANAGED_MAX_INSTANCES:{max_instance |"service[&i&][max_instance]" string => "&max_instance&";
}&
&TRACKINGKEY:{piuuid |"service[&i&][uuid]" string => "&piuuid&";
}&
"index" slist => getindices("service");
SuSE::
"service_check_boot_status_cmd_${index}" string => "/sbin/chkconfig --check ${service[${index}][name]}";
"service_add_boot_cmd_${index}" string => "/sbin/insserv -d ${service[${index}][name]}";
"service_remove_boot_cmd_${index}" string => "/sbin/insserv -rd ${service[${index}][name]}";
redhat::
"service_check_boot_status_cmd_${index}" string => "/sbin/chkconfig ${service[${index}][name]}";
"service_add_boot_cmd_${index}" string => "/sbin/chkconfig ${service[${index}][name]} on";
"service_remove_boot_cmd_${index}" string => "/sbin/chkconfig ${service[${index}][name]} off";
debian::
"service_add_boot_cmd_${index}" string => "/usr/sbin/update-rc.d ${service[${index}][name]} remove \&\& /usr/sbin/update-rc.d ${service[${index}][name]} defaults";
"service_remove_boot_cmd_${index}" string => "/usr/sbin/update-rc.d -f ${service[${index}][name]} remove \&\& /usr/sbin/update-rc.d ${service[${index}][name]} stop 20 2 3 4 5 .";
classes:
&PROCESS_MANAGED_NAME:{name |"defined_process_name_&i&" not => strcmp("&name&", "");
}&
&PROCESS_MANAGED_CHECK_RANGE:{check |"check_process_range_&i&" expression => strcmp("&check&", "true");
}&
&PROCESS_MANAGED_RUNNING:{running |"start_process_&i&" expression => strcmp("&running&", "true");
}&
&PROCESS_MANAGED_RUNNING:{running |"stop_process_&i&" expression => strcmp("&running&", "false");
}&
&PROCESS_MANAGED_KILLING_METHOD:{kill |"graceful_stop_process_&i&" expression => strcmp("&kill&", "graceful");
}&
&PROCESS_MANAGED_KILLING_METHOD:{kill |"term_stop_process_&i&" expression => strcmp("&kill&", "term");
}&
&PROCESS_MANAGED_KILLING_METHOD:{kill |"kill_stop_process_&i&" expression => strcmp("&kill&", "kill");
}&
&PROCESS_MANAGED_BOOTSTART:{bootstart |"bootstart_process_&i&" expression => strcmp("&bootstart&", "true");
}&
&PROCESS_MANAGED_BOOTSTART:{bootstart |"bootstart_prevent_process_&i&" expression => strcmp("&bootstart&", "false");
}&
files:
debian::
"/etc/rc2.d/S.*${service[${index}][name]}.*"
create => "true",
action => WarnOnly,
classes => if_else("service_${index}_bootstarted", "service_${index}_unbootstarted");
processes:
# check the service status
"${service[${index}][process]}"
comment => "Check the process status",
restart_class => "process_${index}_restart",
classes => kept_if_else("service_${index}_running", "service_${index}_anomaly", "service_${index}_error"),
ifvarclass => "defined_process_name_${index}.(start_process_${index}|(stop_process_${index}.graceful_stop_process_${index}))";
# enforce that the process is stopped gracefully
# Should be using process stop, but du to https://cfengine.com/bugtracker/view.php?id=758, it does not work now
#"${service[${index}][process]}"
# comment => "Stop gracefully the process",
# process_stop => "/etc/init.d/${service[${index}][name]} stop",
# classes => kept_if_else("service_${index}_already_stopped", "service_${index}_stopped", "service_${index}_error"),
# ifvarclass => "defined_process_name_${index}.stop_process_${index}.graceful_stop_process_${index}";
# enforce that the process is stopped not so gracefully
"${service[${index}][process]}"
comment => "Stop not so gracefully the process",
signals => { "${service[${index}][killMethod]}" },
classes => kept_if_else("service_${index}_already_stopped", "service_${index}_stopped", "service_${index}_error"),
ifvarclass => "defined_process_name_${index}.stop_process_${index}.(term_stop_process_${index}|kill_stop_process_${index})";
# check the range
"${service[${index}][process]}"
comment => "Check the range of process",
process_count => check_range("${service[${index}][name]}", "${service[${index}][min_instance]}", "${service[${index}][max_instance]}"),
ifvarclass => "defined_process_name_${index}.check_process_range_${index}";
commands:
"/etc/init.d/${service[${index}][name]}"
args => "start",
classes => kept_if_else("process_${index}_restart_ok", "process_${index}_restart_ok", "process_${index}_restart_error"),
ifvarclass => "process_${index}_restart.start_process_${index}";
"/etc/init.d/${service[${index}][name]}"
args => "stop",
classes => kept_if_else("process_${index}_stopped_ok", "process_${index}_stopped_ok", "process_${index}_stop_error"),
ifvarclass => "!process_${index}_restart.stop_process_${index}";
"/etc/init.d/${service[${index}][name]}"
args => "restart",
classes => kept_if_else("process_${index}_out_of_range_restart_ok", "process_${index}_out_of_range_restart_ok", "process_${index}_out_of_range_restart_error"),
ifvarclass => canonify("${service[${index}][name]}_out_of_range");
# Check whether the service is already configured to start on boot
!debian:: # Debian uses a files promise for this, see above
"${service_check_boot_status_cmd_${index}}"
classes => if_else("service_${index}_bootstarted", "service_${index}_unbootstarted"),
ifvarclass => "bootstart_process_${index}|bootstart_prevent_process_${index}",
comment => "Check if the service ${service[${index}][name]} is started on boot";
any::
"${service_add_boot_cmd_${index}}"
contain => in_shell,
classes => if_else("service_${index}_bootstarted_ok", "service_${index}_bootstarted_fail"),
ifvarclass => "service_${index}_unbootstarted.bootstart_process_${index}",
comment => "Set the service ${service[${index}][name]} to start on boot";
"${service_remove_boot_cmd_${index}}"
contain => in_shell,
classes => if_else("service_${index}_unbootstarted_ok", "service_${index}_unbootstarted_fail"),
ifvarclass => "service_${index}_bootstarted.bootstart_prevent_process_${index}",
comment => "Set the service ${service[${index}][name]} to not be started on boot";
reports:
cfengine::
"@@ServicesManagement@@result_success@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#${service[${index}][name]} didn't need to have its process checked"
ifvarclass => "!start_process_${index}.!stop_process_${index}";
"@@ServicesManagement@@result_error@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#Cannot check the status of ${service[${index}][name]}: the process name is not filed"
ifvarclass => "!defined_process_name_${index}.(start_process_${index}|stop_process_${index})";
"@@ServicesManagement@@result_success@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#Process of ${service[${index}][name]} was indeed running"
ifvarclass => "service_${index}_running.!service_${index}_anomaly.!process_${index}_restart.start_process_${index}";
"@@ServicesManagement@@result_repaired@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#Process of ${service[${index}][name]} was not running and has been restarted"
ifvarclass => "process_${index}_restart.process_${index}_restart_ok.start_process_${index}";
"@@ServicesManagement@@result_error@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#${service[${index}][name]}: the process couldn't be started"
ifvarclass => "process_${index}_restart_error";
"@@ServicesManagement@@result_success@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#Process of ${service[${index}][name]} was indeed not running"
ifvarclass => "stop_process_${index}.process_${index}_restart.graceful_stop_process_${index}";
"@@ServicesManagement@@result_repaired@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#Process of ${service[${index}][name]} was stopped"
ifvarclass => "stop_process_${index}.!process_${index}_restart.process_${index}_stopped_ok.graceful_stop_process_${index}";
"@@ServicesManagement@@result_error@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#${service[${index}][name]}: the process could't be stopped"
ifvarclass => "stop_process_${index}.!process_${index}_restart.process_${index}_stop_error.graceful_stop_process_${index}";
"@@ServicesManagement@@result_success@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#Process of ${service[${index}][name]} was indeed not running"
ifvarclass => "stop_process_${index}.service_${index}_already_stopped.!service_${index}_stopped.!graceful_stop_process_${index}";
"@@ServicesManagement@@result_repaired@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#Process of ${service[${index}][name]} was stopped"
ifvarclass => "stop_process_${index}.service_${index}_stopped.!graceful_stop_process_${index}";
"@@ServicesManagement@@result_error@@${service[${index}][uuid]}@@Process@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#${service[${index}][name]}: the process count could't be stopped"
ifvarclass => "stop_process_${index}.service_${index}_error.!graceful_stop_process_${index}";
"@@ServicesManagement@@result_success@@${service[${index}][uuid]}@@Advanced options@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#The process range is not to be checked for service ${service[${index}][name]}"
ifvarclass => "!check_process_range_${index}";
"@@ServicesManagement@@result_error@@${service[${index}][uuid]}@@Advanced options@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#The process range for service ${service[${index}][name]} cannot to be checked, for the process name is not set"
ifvarclass => "check_process_range_${index}.!defined_process_name_${index}";
"@@ServicesManagement@@result_success@@${service[${index}][uuid]}@@Advanced options@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#The process range for service ${service[${index}][name]} is correct"
ifvarclass => "check_process_range_${index}.defined_process_name_${index}.!${service[${index}][canon_name]}_out_of_range";
"@@ServicesManagement@@result_repaired@@${service[${index}][uuid]}@@Advanced options@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#The process range for service ${service[${index}][name]} was not correct, but was repaired"
ifvarclass => "check_process_range_${index}.defined_process_name_${index}.${service[${index}][canon_name]}_out_of_range.process_${index}_out_of_range_restart_ok";
"@@ServicesManagement@@result_error@@${service[${index}][uuid]}@@Advanced options@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#The process range for service ${service[${index}][name]} was not correct, but was repaired"
ifvarclass => "check_process_range_${index}.defined_process_name_${index}.${service[${index}][canon_name]}_out_of_range.process_${index}_out_of_range_restart_error";
# Service boot starting parameters
"@@ServicesManagement@@result_success@@${service[${index}][uuid]}@@Service starting parameters@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#${service[${index}][name]} starting parameters check not required"
ifvarclass => "!bootstart_process_${index}.!bootstart_prevent_process_${index}";
"@@ServicesManagement@@result_success@@${service[${index}][uuid]}@@Service starting parameters@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#${service[${index}][name]} is started on boot as required"
ifvarclass => "bootstart_process_${index}.service_${index}_bootstarted";
"@@ServicesManagement@@result_repaired@@${service[${index}][uuid]}@@Service starting parameters@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#${service[${index}][name]} has been set to start on boot"
ifvarclass => "bootstart_process_${index}.service_${index}_bootstarted_ok";
"@@ServicesManagement@@result_error@@${service[${index}][uuid]}@@Service starting parameters@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#Could not set ${service[${index}][name]} to start on boot!"
ifvarclass => "bootstart_process_${index}.service_${index}_bootstarted_fail";
"@@ServicesManagement@@result_success@@${service[${index}][uuid]}@@Service starting parameters@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#${service[${index}][name]} is not started on boot as required"
ifvarclass => "!bootstart_process_${index}.bootstart_prevent_process_${index}";
"@@ServicesManagement@@result_repaired@@${service[${index}][uuid]}@@Service starting parameters@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#${service[${index}][name]} has been prevented to start on boot"
ifvarclass => "bootstart_prevent_process_${index}.service_${index}_unbootstarted_ok";
"@@ServicesManagement@@result_error@@${service[${index}][uuid]}@@Service starting parameters@@${service[${index}][name]}@@${g.execRun}##${g.uuid}@#Could not prevent ${service[${index}][name]} to start on boot!"
ifvarclass => "bootstart_prevent_process_${index}.service_${index}_unbootstarted_fail";
}
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#
# Configure the port numbers in the OpenSSH configuration file
# The argument can be either a string or a slist
#
bundle edit_line rudder_openssh_server_port_configuration(portlist)
{
delete_lines:
"Port.*";
insert_lines:
"Port ${portlist}";
}
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
###############################################################
# Installs SSH, and checks wether it is started on boot or not.
###############################################################
bundle agent rudder_openssh_server_installation(class_prefix, service_name, params)
{
vars:
linux.!SuSE::
"rudder_openssh_server_package_name"
string => "openssh-server";
SuSE::
"rudder_openssh_server_package_name"
string => "openssh";
packages:
# Install OpenSSH if needed, using generic installation.
linux::
"${rudder_openssh_server_package_name}"
package_policy => "add",
package_method => generic,
classes => rudder_common_classes("${class_prefix}_package"),
comment => "Installing ${service_name} using the generic package manager method";
}
bundle agent rudder_openssh_server_installation_reporting(class_prefix, service_name, params)
{
methods:
"any" usebundle => rudder_common_reports_generic("${service_name}", "${class_prefix}_package", "${${params}[report]}", "SSH installation", "None", "The ${service_name} package installation");
!linux::
"any" usebundle => rudder_common_report("${service_name}", "result_success", "${${params}[report]}", "SSH installation", "None", "Support to check if ${service_name} is installed not available on this platform");
}
# This bundle is common because it defines a class that we reuse in the configuration part,
# when configuring the service, to not configure the service if the binary is not there
bundle common rudder_openssh_server_check_ssh_installation
{
classes:
# Security : if not there, SSH too, so do not bother anymore
# I cannot use the class_prefix in the class definition, because it is a bundle common
# and for some reason, CFEngine complains about it not being canonified
"rudder_openssh_server_binary_present"
expression => fileexists("/usr/sbin/sshd");
}
bundle agent rudder_openssh_server_check_ssh_installation_reporting(class_prefix, service_name, params)
{
methods:
# Make a report about the lack of proper sshd binary
"any"
usebundle => rudder_common_report("${service_name}", "result_error", "${${params}[report]}", "SSH installation", "None", "The ${service_name} is not installed, although it should have been"),
ifvarclass => "!${class_prefix}_binary_present";
}
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#####################################################################################
# This Technique installs and configures OpenSSH. See metadata.xml for more details.
#####################################################################################
bundle agent rudder_openssh_server
{
vars:
"rudder_openssh_server_service_name"
string => "OpenSSH server";
# Prefix for all the defined classes
"rudder_class_prefix"
string => "rudder_openssh_server";
# This is the file to edit
"rudder_openssh_server_config[sshd_config_file]"
string => "&OPENSSH_SERVER_CONFFILE&";
"rudder_openssh_server_config[sshd_config_ports]"
slist => {&OPENSSH_SERVER_PORTS: { "&it&" };separator=", "&};
# This is the reporting information to be added
"rudder_openssh_server_config[report]"
string => "&TRACKINGKEY&";
# Variable that holds if we want to edit ports
"rudder_openssh_server_config[edit_ports]"
string => "&OPENSSH_SERVER_PORTSEDIT&";
# Class specific parameters
rudder_openssh_server_address_family_edit.!(debian_3|redhat_3|redhat_4|centos_3|centos_4)::
"rudder_openssh_server_config[config][AddressFamily]"
string => "&OPENSSH_SERVER_ADDRESSFAMILY&";
rudder_openssh_server_protocol_edit::
"rudder_openssh_server_config[config][Protocol]"
string => "&OPENSSH_SERVER_PROTOCOL&";
rudder_openssh_server_max_sessions_edit.!(redhat|SuSE|debian_3|debian_4)::
"rudder_openssh_server_config[config][MaxSessions]"
string => "&OPENSSH_SERVER_MAXSESSIONS&";
rudder_openssh_server_challenge_response_authentication_edit::
"rudder_openssh_server_config[config][ChallengeResponseAuthentication]"
string => "&OPENSSH_SERVER_CHALLENGERESPONSEAUTHENTICATION&";
rudder_openssh_server_password_authentication_edit::
"rudder_openssh_server_config[config][PasswordAuthentication]"
string => "&OPENSSH_SERVER_PASSWORDAUTHENTICATION&";
rudder_openssh_server_pubkey_authentication_edit::
"rudder_openssh_server_config[config][PubkeyAuthentication]"
string => "&OPENSSH_SERVER_PUBKEYAUTHENTICATION&";
rudder_openssh_server_permit_empty_passwords_edit::
"rudder_openssh_server_config[config][PermitEmptyPasswords]"
string => "&OPENSSH_SERVER_PERMITEMPTYPASSWORDS&";
rudder_openssh_server_permit_root_login_edit::
"rudder_openssh_server_config[config][PermitRootLogin]"
string => "&OPENSSH_SERVER_PERMITROOTLOGIN&";
rudder_openssh_server_max_auth_tries_edit.!(debian_3|redhat_3|centos_3)::
"rudder_openssh_server_config[config][MaxAuthTries]"
string => "&OPENSSH_SERVER_MAXAUTHTRIES&";
rudder_openssh_server_login_grace_time_edit::
"rudder_openssh_server_config[config][LoginGraceTime]"
string => "&OPENSSH_SERVER_LOGINGRACETIME&";
rudder_openssh_server_use_privilege_separation_edit::
"rudder_openssh_server_config[config][UsePrivilegeSeparation]"
string => "&OPENSSH_SERVER_USEPRIVILEGESEPARATION&";
rudder_openssh_server_strict_modes_edit::
"rudder_openssh_server_config[config][StrictModes]"
string => "&OPENSSH_SERVER_STRICTMODES&";
rudder_openssh_server_allow_agent_forwarding_edit.!(redhat|SuSE|debian_3|debian_4)::
"rudder_openssh_server_config[config][AllowAgentForwarding]"
string => "&OPENSSH_SERVER_ALLOWAGENTFORWARDING&";
rudder_openssh_server_allow_tcp_forwarding_edit::
"rudder_openssh_server_config[config][AllowTcpForwarding]"
string => "&OPENSSH_SERVER_ALLOWTCPFORWARDING&";
rudder_openssh_server_permit_tunnel_edit.!(SuSE|debian_3|redhat_3|redhat_4|centos_3|centos_4)::
"rudder_openssh_server_config[config][PermitTunnel]"
string => "&OPENSSH_SERVER_PERMITTUNNEL&";
rudder_openssh_server_permit_user_environment_edit::
"rudder_openssh_server_config[config][PermitUserEnvironment]"
string => "&OPENSSH_SERVER_PERMITUSERENVIRONMENT&";
rudder_openssh_server_x11_forwarding_edit::
"rudder_openssh_server_config[config][X11Forwarding]"
string => "&OPENSSH_SERVER_X11FORWARDING&";
rudder_openssh_server_print_lastlog_edit::
"rudder_openssh_server_config[config][PrintLastLog]"
string => "&OPENSSH_SERVER_PRINTLASTLOG&";
rudder_openssh_server_printmotd_edit::
"rudder_openssh_server_config[config][PrintMotd]"
string => "&OPENSSH_SERVER_PRINTMOTD&";
rudder_openssh_server_tcp_keepalive_edit.!(redhat_3|centos_3)::
"rudder_openssh_server_config[config][TCPKeepAlive]"
string => "&OPENSSH_SERVER_TCPKEEPALIVE&";
rudder_openssh_server_log_level_edit::
"rudder_openssh_server_config[config][LogLevel]"
string => "&OPENSSH_SERVER_LOGLEVEL&";
rudder_openssh_server_syslog_facility_edit::
"rudder_openssh_server_config[config][SyslogFacility]"
string => "&OPENSSH_SERVER_SYSLOGFACILITY&";
classes:
# AddressFamily edition ?
"rudder_openssh_server_address_family_edit"
not => strcmp("&OPENSSH_SERVER_ADDRESSFAMILY&","dontchange");
# Protocol edition ?
"rudder_openssh_server_protocol_edit"
not => strcmp("&OPENSSH_SERVER_PROTOCOL&","dontchange");
# MaxSessions edition ?
"rudder_openssh_server_max_sessions_edit"
not => strcmp("&OPENSSH_SERVER_MAXSESSIONS&","dontchange");
# ChallengeResponseAuthentication edition ?
"rudder_openssh_server_challenge_response_authentication_edit"
not => strcmp("&OPENSSH_SERVER_CHALLENGERESPONSEAUTHENTICATION&","dontchange");
# PasswordAuthentication edition ?
"rudder_openssh_server_password_authentication_edit"
not => strcmp("&OPENSSH_SERVER_PASSWORDAUTHENTICATION&","dontchange");
# PubkeyAuthentication edition ?
"rudder_openssh_server_pubkey_authentication_edit"
not => strcmp("&OPENSSH_SERVER_PUBKEYAUTHENTICATION&","dontchange");
# PermitEmptyPasswords edition ?
"rudder_openssh_server_permit_empty_passwords_edit"
not => strcmp("&OPENSSH_SERVER_PERMITEMPTYPASSWORDS&","dontchange");
# PermitRootLogin edition ?
"rudder_openssh_server_permit_root_login_edit"
not => strcmp("&OPENSSH_SERVER_PERMITROOTLOGIN&","dontchange");
# MaxAuthTries edition ?
"rudder_openssh_server_max_auth_tries_edit"
not => strcmp("&OPENSSH_SERVER_MAXAUTHTRIES&","dontchange");
# LoginGraceTime edition ?
"rudder_openssh_server_login_grace_time_edit"
not => strcmp("&OPENSSH_SERVER_LOGINGRACETIME&","dontchange");
# UsePrivilegeSeparation edition ?
"rudder_openssh_server_use_privilege_separation_edit"
not => strcmp("&OPENSSH_SERVER_USEPRIVILEGESEPARATION&","dontchange");
# StrictModes edition ?
"rudder_openssh_server_strict_modes_edit"
not => strcmp("&OPENSSH_SERVER_STRICTMODES&","dontchange");
# AllowAgentForwarding edition ?
"rudder_openssh_server_allow_agent_forwarding_edit"
not => strcmp("&OPENSSH_SERVER_ALLOWAGENTFORWARDING&","dontchange");
# AllowTcpForwarding edition ?
"rudder_openssh_server_allow_tcp_forwarding_edit"
not => strcmp("&OPENSSH_SERVER_ALLOWTCPFORWARDING&","dontchange");
# PermitTunnel edition ?
"rudder_openssh_server_permit_tunnel_edit"
not => strcmp("&OPENSSH_SERVER_PERMITTUNNEL&","dontchange");
# PermitUserEnvironment edition ?
"rudder_openssh_server_permit_user_environment_edit"
not => strcmp("&OPENSSH_SERVER_PERMITUSERENVIRONMENT&","dontchange");
# X11Forwarding edition ?
"rudder_openssh_server_x11_forwarding_edit"
not => strcmp("&OPENSSH_SERVER_X11FORWARDING&","dontchange");
# PrintLastLog edition ?
"rudder_openssh_server_print_lastlog_edit"
not => strcmp("&OPENSSH_SERVER_PRINTLASTLOG&","dontchange");
# PrintMotd edition ?
"rudder_openssh_server_printmotd_edit"
not => strcmp("&OPENSSH_SERVER_PRINTMOTD&","dontchange");
# TCPKeepAlive edition ?
"rudder_openssh_server_tcp_keepalive_edit"
not => strcmp("&OPENSSH_SERVER_TCPKEEPALIVE&","dontchange");
# LogLevel edition ?
"rudder_openssh_server_log_level_edit"
not => strcmp("&OPENSSH_SERVER_LOGLEVEL&","dontchange");
# SyslogFacility edition ?
"rudder_openssh_server_syslog_facility_edit"
not => strcmp("&OPENSSH_SERVER_SYSLOGFACILITY&","dontchange");
# Defines a class to describe we are at the second iteration
# When iteration_2 is defined, it means all the variable are defined
"iteration_2"
expression => "iteration_1";
"iteration_1"
expression => "any";
methods:
# Note:
# The reporting is made on separate bundles to abstract the complexity
# inherent to the normal ordering.
"any" usebundle => rudder_openssh_server_installation("${rudder_class_prefix}", "${rudder_openssh_server_service_name}", "rudder_openssh_server.rudder_openssh_server_config");
"any" usebundle => rudder_openssh_server_installation_reporting("${rudder_class_prefix}", "${rudder_openssh_server_service_name}", "rudder_openssh_server.rudder_openssh_server_config");
"any" usebundle => rudder_openssh_server_check_ssh_installation();
"any" usebundle => rudder_openssh_server_check_ssh_installation_reporting("${rudder_class_prefix}", "${rudder_openssh_server_service_name}", "rudder_openssh_server.rudder_openssh_server_config");
iteration_2::
"any" usebundle => rudder_openssh_server_configuration("${rudder_class_prefix}", "${rudder_openssh_server_service_name}", "rudder_openssh_server.rudder_openssh_server_config");
"any" usebundle => rudder_openssh_server_configuration_reporting("${rudder_class_prefix}", "${rudder_openssh_server_service_name}", "rudder_openssh_server.rudder_openssh_server_config");
# Warn about features that are not implemented on all platforms
"any"
usebundle => rudder_common_report("${rudder_openssh_server_service_name}", "log_warn", "&TRACKINGKEY&", "SSH configuration", "None", "The ${rudder_openssh_server_service_name} parameter \"address family\" isn't implemented on Red Hat/CentOS/SuSE/Debian 3 and 4"),
ifvarclass => "rudder_openssh_server_address_family_edit.(debian_3|redhat_3|redhat_4|centos_3|centos_4)";
"any"
usebundle => rudder_common_report("${rudder_openssh_server_service_name}", "log_warn", "&TRACKINGKEY&", "SSH configuration", "None", "The ${rudder_openssh_server_service_name} parameter \"maximum authentication attemps per connection\" isn't implemented on Red Hat/CentOS"),
ifvarclass => "rudder_openssh_server_max_auth_tries_edit.(redhat_3|centos_3|debian_3)";
"any"
usebundle => rudder_common_report("${rudder_openssh_server_service_name}", "log_warn", "&TRACKINGKEY&", "SSH configuration", "None", "The ${rudder_openssh_server_service_name} parameter \"agent forwarding\" isn't implemented on Red Hat/CentOS/SuSE/Debian 3 and 4"),
ifvarclass => "rudder_openssh_server_allow_agent_forwarding_edit.(redhat|SuSE|debian_3|debian_4)";
"any"
usebundle => rudder_common_report("${rudder_openssh_server_service_name}", "log_warn", "&TRACKINGKEY&", "SSH configuration", "None", "The ${rudder_openssh_server_service_name} parameter \"max sessions\" isn't implemented on Red Hat/CentOS/SuSE/Debian 3 and 4"),
ifvarclass => "rudder_openssh_server_max_sessions_edit.(redhat|SuSE|debian_3|debian_4)";
"any"
usebundle => rudder_common_report("${rudder_openssh_server_service_name}", "log_warn", "&TRACKINGKEY&", "SSH configuration", "None", "The ${rudder_openssh_server_service_name} parameter \"permit tunnel\" isn't implemented on SuSE/Debian 3/Redhat/CentOS3 and 4"),
ifvarclass => "rudder_openssh_server_permit_tunnel_edit.(SuSE|debian_3|redhat_3|redhat_4|centos_3|centos_4)";
"any"
usebundle => rudder_common_report("${rudder_openssh_server_service_name}", "log_warn", "&TRACKINGKEY&", "SSH configuration", "None", "The ${rudder_openssh_server_service_name} parameter \"TCP Keep Alive (Time before disconnect)\" isn't implemented on Red Hat/CentOS 3"),
ifvarclass => "rudder_openssh_server_tcp_keepalive_edit.(redhat_3|centos_3)";
}
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
#####################################################################################
# Configure the OpenSSH server
#####################################################################################
# If ssh is not installed, install it (linux)
# Change the server configuration, and restart the daemon
# if the configuration changed
# WARNING : You may inadvertently create conflict with processManagement !
# This promise restarts sshd if not there, which could be done by processManagement too.
# dontchange is a generic value to prohibit the edition of the value
#####################################################################################
bundle agent rudder_openssh_server_configuration(class_prefix, service_name, params) {
vars:
# OS Specific parameters
debian::
"rudder_openssh_server_startup_command"
string => "/etc/init.d/ssh restart";
"rudder_openssh_server_startup_activation_command"
string => "/usr/sbin/update-rc.d -f ssh remove \&\& /usr/sbin/update-rc.d ssh defaults";
SuSE::
"rudder_openssh_server_startup_script_regex"
string => "/etc/init.d/rc3.d/S.*ssh.*";
(debian|redhat)::
"rudder_openssh_server_startup_script_regex"
string => "/etc/rc2.d/S.*ssh.*";
(SuSE|redhat)::
"rudder_openssh_server_startup_command"
string => "/etc/init.d/sshd restart";
"rudder_openssh_server_startup_activation_command"
string => "/sbin/chkconfig --del sshd \&\& /sbin/chkconfig --add sshd";
aix::
"rudder_openssh_server_startup_command"
string => "/usr/bin/startsrc -s sshd";
# Here are the details about the arguments given to mkssys:
## -p: Specifies the absolute path to the subsystem executable program.
## -s: Specifies a name that uniquely identifies the subsystem.
## -G: Specifies that the subsystem belongs to the Group specified.
## -u: Specifies the user ID for the subsystem.
## -S: Specifies that the subsystem uses the signals communication method.
## -f: Specifies the signal sent to the subsystem when a forced stop of the subsystem is requested.
## -n: Specifies the signal sent to the subsystem when a normal stop of the subsystem is requested.
## -a: Specifies any arguments that must be passed to the command, started as the subsystem.
## -R: Specifies that the subsystem is restarted if the subsystem stops abnormally.
## -Q: Specifies that multiple instances of the subsystem are not allowed to run at the same time.
"rudder_openssh_server_startup_activation_command"
string => "/usr/bin/mkssys -p /usr/sbin/sshd -s sshd -G ssh -u 0 -S -f 9 -n 15 -a '-D' -R -Q >/dev/null ; /usr/sbin/mkitab 'sshd:2:once:/usr/bin/startsrc -s sshd'";
any::
# Copy the list of Ports in the local bundle
# This is mandatory because we cannot use remote slist in CFEngine 3.2
"rudder_openssh_server_config_ports"
slist => { "@{${params}[sshd_config_ports]}" };
classes:
"rudder_openssh_server_ports_edit"
not => strcmp("${${params}[edit_ports]}","false");
aix::
# lssrc is clever, and kept in a cache the entry if the daemon is still running, so grepping
# /etc/inittab instead, to be sure that service is defined at boot
# Adding scope namespace so that the class is available for the reporting also
"${class_prefix}_activated_on_boot_kept"
expression => returnszero("/usr/bin/grep -q -E ^sshd: /etc/inittab", "useshell"),
scope => "namespace";
files:
"${${params}[sshd_config_file]}"
edit_line => rudder_common_disclaimer,
comment => "Insert the standard Rudder disclaimer in the OpenSSHd configuration file";
(debian|redhat|SuSE)::
# This promise will detect if there is a startup script for OpenSSH enabled on the system,
# and set a class if there is one indeed.
"${rudder_openssh_server_startup_script_regex}"
create => "true",
action => WarnOnly,
classes => if_else("${class_prefix}_activated_on_boot_kept", "${class_prefix}_activation_detection_failed");
rudder_openssh_server_ports_edit::
"${${params}[sshd_config_file]}"
edit_line => rudder_openssh_server_port_configuration("@{this.rudder_openssh_server_config_ports}"),
classes => rudder_common_classes("${class_prefix}_ports"),
comment => "Edit the OpenSSH listening ports in the configuration file";
any::
"${${params}[sshd_config_file]}"
edit_line => set_config_values("${params}[config]"),
classes => rudder_common_classes("${class_prefix}_configuration"),
comment => "Edit the OpenSSH configuration file";
processes:
any::
"/usr/sbin/sshd"
restart_class => "${class_prefix}_down",
comment => "Checking whether OpenSSH is up or not";
commands:
debian|redhat|SuSE|aix::
"${rudder_openssh_server_startup_command}"
classes => cf2_if_else("${class_prefix}_daemon_restart_repaired", "${class_prefix}_daemon_restart_error"),
ifvarclass => "${class_prefix}_ports_repaired|${class_prefix}_configuration_repaired|${class_prefix}_down",
comment => "Restarting the OpenSSH server daemon";
debian|redhat|SuSE|aix::
"${rudder_openssh_server_startup_activation_command}"
contain => in_shell,
classes => cf2_if_else("${class_prefix}_activated_on_boot_repaired", "${class_prefix}_activated_on_boot_error"),
ifvarclass => "(!${class_prefix}_activated_on_boot_kept).${class_prefix}_binary_present",
comment => "Adding the OpenSSH daemon to the startup scripts";
}
bundle agent rudder_openssh_server_configuration_reporting(class_prefix, service_name, params)
{
methods:
# Port edition defined
"any" usebundle => rudder_common_reports_generic("${service_name}", "${class_prefix}_ports", "${${params}[report]}", "SSH port configuration", "None", "The ${service_name} port configuration"),
ifvarclass => "${class_prefix}_ports_edit";
# When no port edition is defined
"any"
usebundle => rudder_common_report("${service_name}", "result_success", "${${params}[report]}", "SSH port configuration", "None", "The ${service_name} port configuration is not set to be edited"),
ifvarclass => "!${class_prefix}_ports_edit";
# SSH configuration
"any" usebundle => rudder_common_reports_generic("${service_name}", "${class_prefix}_configuration", "${${params}[report]}", "SSH configuration", "None", "The ${service_name} configuration");
# SSH start on boot
"any" usebundle => rudder_common_reports_generic("${service_name}", "${class_prefix}_activated_on_boot", "${${params}[report]}", "SSH start at boot", "None", "The ${service_name} boot starting configuration");
"any"
usebundle => rudder_common_report("${service_name}", "log_repaired", "${${params}[report]}", "SSH process", "None", "The ${service_name} was not running, trying to restart..."),
ifvarclass => "${class_prefix}_down";
"any"
usebundle => rudder_common_report("${service_name}", "result_success", "${${params}[report]}", "SSH process", "None", "The ${service_name} service is running"),
ifvarclass => "!${class_prefix}_down.!${class_prefix}_daemon_restart_repaired.!${class_prefix}_daemon_restart_error";
"any"
usebundle => rudder_common_report("${service_name}", "result_repaired", "${${params}[report]}", "SSH process", "None", "Restarted the ${service_name}"),
ifvarclass => "${class_prefix}_daemon_restart_repaired.!${class_prefix}_daemon_restart_error";
"any"
usebundle => rudder_common_report("${service_name}", "result_error", "${${params}[report]}", "SSH process", "None", "Could not restart the ${service_name}"),
ifvarclass => "${class_prefix}_daemon_restart_error";
"any"
usebundle => rudder_common_report("${service_name}", "log_info", "${${params}[report]}", "SSH start at boot", "None", "Error checking if the ${service_name} is set to be started on boot"),
ifvarclass => "${class_prefix}_activation_detection_failed";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
# Copyright (C) Normation
bundle agent check_ssh_key_distribution
{
vars:
any::
"technique_name" string => "sshKeyDistribution";
"component_name" string => "SSH key";
"config_basename" string => "authorized_keys";
&SSH_KEY_DISTRIBUTION_TAG:{key_tag |"sshkey_distribution_tag[&i&]" string => "&key_tag&";
}&
&SSH_KEY_DISTRIBUTION_NAME:{distribution_name |"sshkey_distribution_name[&i&]" string => "&distribution_name&";
}&
&SSH_KEY_DISTRIBUTION_KEY:{distribution_key |"sshkey_distribution_key[&i&]" string => "&distribution_key&";
}&
&SSH_KEY_DISTRIBUTION_EDIT_TYPE:{distribution_edit_type |"sshkey_distribution_edit_type[&i&]" string => "&distribution_edit_type&";
}&
&TRACKINGKEY:{uuid |"sshkey_distribution_uuid[&i&]" string => "&uuid&";
}&
"sshkey_distribution_index"
slist => getindices("sshkey_distribution_name");
"no_${sshkey_distribution_index}"
int => parsestringarray("userarray_${sshkey_distribution_index}", "${userdata_${sshkey_distribution_index}}", "", ":", "1000", "200000" );
"key_class_prefix[${sshkey_distribution_index}]"
string => canonify("${sshkey_distribution_tag[${sshkey_distribution_index}]}_${sshkey_distribution_uuid[${sshkey_distribution_index}]}");
"homedir[${sshkey_distribution_index}]"
string => "${userarray_${sshkey_distribution_index}[${sshkey_distribution_name[${sshkey_distribution_index}]}][5]}";
# Only Linuxes (not Slackware), Solaris and FreeBSD support PAM/getent
(linux.!slackware)|solaris|freebsd::
"userdata_${sshkey_distribution_index}"
string => execresult("/usr/bin/getent passwd ${sshkey_distribution_name[${sshkey_distribution_index}]}", "noshell");
# On systems without PAM, directly read entries from /etc/passwd instead (compatibility)
!((linux.!slackware)|solaris|freebsd)::
"userdata_${sshkey_distribution_index}"
string => execresult("/usr/bin/grep ^${sshkey_distribution_name[${sshkey_distribution_index}]}: /etc/passwd", "noshell");
any::
"gid[${sshkey_distribution_index}]"
string => "${userarray_${sshkey_distribution_index}[${sshkey_distribution_name[${sshkey_distribution_index}]}][3]}";
classes:
"begin_evaluation" expression => isvariable("sshkey_distribution_index");
begin_evaluation::
"user_${sshkey_distribution_index}_exists" expression => userexists("${sshkey_distribution_name[${sshkey_distribution_index}]}");
files:
!windows::
"${homedir[${sshkey_distribution_index}]}/.ssh/."
create => "true",
ifvarclass => canonify("user_${sshkey_distribution_index}_exists"),
perms => mog("700", "${sshkey_distribution_name[${sshkey_distribution_index}]}", "${gid[${sshkey_distribution_index}]}");
"${homedir[${sshkey_distribution_index}]}/.ssh/${config_basename}"
create => "true",
edit_defaults => rudder_empty_select("${sshkey_distribution_edit_type[${sshkey_distribution_index}]}"),
perms => mog("600", "${sshkey_distribution_name[${sshkey_distribution_index}]}", "${gid[${sshkey_distribution_index}]}"),
edit_line => append_or_replace_ssh_key("${sshkey_distribution_key[${sshkey_distribution_index}]}", "${sshkey_distribution_index}"),
ifvarclass => canonify("user_${sshkey_distribution_index}_exists"),
classes => rudder_common_classes("${key_class_prefix[${sshkey_distribution_index}]}");
methods:
!windows::
"SSH Key Report"
ifvarclass => "user_${sshkey_distribution_index}_exists",
usebundle => rudder_common_reports_generic(
"${technique_name}", "${key_class_prefix[${sshkey_distribution_index}]}",
"${sshkey_distribution_uuid[${sshkey_distribution_index}]}", "${component_name}", "${sshkey_distribution_tag[${sshkey_distribution_index}]}",
"SSH key \"${sshkey_distribution_tag[${sshkey_distribution_index}]}\" for user ${sshkey_distribution_name[${sshkey_distribution_index}]}"
);
"No User Exist Report"
ifvarclass => "!user_${sshkey_distribution_index}_exists",
usebundle => rudder_common_report(
"${technique_name}", "result_error",
"${sshkey_distribution_uuid[${sshkey_distribution_index}]}", "${component_name}", "${sshkey_distribution_tag[${sshkey_distribution_index}]}",
"The user ${sshkey_distribution_name[${sshkey_distribution_index}]} does NOT exist on this machine, not adding SSH key"
);
windows::
"No Windows Support Report"
usebundle => rudder_common_report(
"${technique_name}", "result_error",
"${sshkey_distribution_uuid[${sshkey_distribution_index}]}", "${component_name}", "${sshkey_distribution_tag[${sshkey_distribution_index}]}",
"Unable to add a SSH key for ${sshkey_distribution_name[${sshkey_distribution_index}]}: This Technique does not support Windows"
);
}
# authorized_keys file contains one line per key, in the following format:
# (optional-options\s)(<keytype>)\s(the_key=)(\soptional-comment)
# where
# - keytype is one of ssh-rsa or ssh-dss
# - key value ends with "="
# - no spaces are allowed in options, except in double-quoted strings
#
bundle edit_line append_or_replace_ssh_key(keyspec, index)
{
vars:
any::
"eline"
comment => "An escaped version of the keyspec - \Q..\E do not escape everything",
string => escape("${keyspec}");
key_parsed::
"ckey" string => canonify("${keybits[3]}");
"ekey" string => escape("${keybits[3]}");
classes:
"key_parsed"
# If the key hash happens to exceed 1000 chars $keybits[3] is going to be undefined because
# of some weird cfengine bugs, probably this one: https://cfengine.com/dev/issues/1258
# Therefore we limit the regex to extract as much of the hash as possible to make it unique enough
# without exceeding 1000 charachter limit.
# The hashes of that length apparently correspond to DSS 2048 bits keys, generated i.e. on rhel 4,
# with openssh v3.9p1-redhat. I believe that since openssh v4 DSS bitlengh is limited to 1024,
# as required by FIPS.
expression => regextract("(.*\s+)?(ssh-rsa|ssh-dss)\s+(\S{1,1000})\S*(\s+.+)?\Z", "${keyspec}", "keybits" );
insert_lines:
"${keyspec}"
# NOTE: this is only to ensure that insert is attempted *after* the replace,
# as normally insert step precedes the replace, see
# (https://cfengine.com/docs/3.5/manuals-language-concepts-normal-ordering.html)
ifvarclass => canonify("ssh_key_distribution_replace_step_attempted_${index}");
replace_patterns:
"^(?!${eline}$)(.*${ekey}.*)$"
comment => "Replace a key here",
replace_with => value("${keyspec}"),
ifvarclass => "key_parsed",
classes => always("ssh_key_distribution_replace_step_attempted_${index}");
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent file_alteration_monitor
{
vars:
&MONITOR_ENTITY_NAME:{name |"monitor_entity[&i&][name]" string => "&name&";
}&
&TRACKINGKEY:{uuid |"monitor_entity[&i&][uuid]" string => "&uuid&";
}&
"index" slist => getindices("monitor_entity");
classes:
"isfile_${index}" expression => isplain("${monitor_entity[${index}][name]}");
"isdir_${index}" expression => isdir("${monitor_entity[${index}][name]}");
files:
"${monitor_entity[${index}][name]}"
ifvarclass => "isdir_${index}",
changes => detect_all_change,
classes => kept_if_else("${index}_kept", "${index}_changed", "${index}_error"),
depth_search => recurse("inf");
"${monitor_entity[${index}][name]}"
ifvarclass => "isfile_${index}",
changes => detect_all_change,
classes => kept_if_else("${index}_kept", "${index}_changed", "${index}_error");
reports:
cfengine::
"@@fileAlterationMonitoring@@result_success@@${monitor_entity[${index}][uuid]}@@File or directory to monitor@@${monitor_entity[${index}][name]}@@${g.execRun}##${g.uuid}@#The content of ${monitor_entity[${index}][name]} is consistent"
ifvarclass => "${index}_kept";
"@@fileAlterationMonitoring@@result_repaired@@${monitor_entity[${index}][uuid]}@@File or directory to monitor@@${monitor_entity[${index}][name]}@@${g.execRun}##${g.uuid}@#The content of ${monitor_entity[${index}][name]} is INCONSISTENT: Either the file has changed or one of the elements in the directory has"
ifvarclass => "${index}_changed";
"@@fileAlterationMonitoring@@result_error@@${monitor_entity[${index}][uuid]}@@File or directory to monitor@@${monitor_entity[${index}][name]}@@${g.execRun}##${g.uuid}@#The content of ${monitor_entity[${index}][name]} could not be checked"
ifvarclass => "${index}_error";
"@@fileAlterationMonitoring@@result_error@@${monitor_entity[${index}][uuid]}@@File or directory to monitor@@${monitor_entity[${index}][name]}@@${g.execRun}##${g.uuid}@#The entity ${monitor_entity[${index}][name]} does not exist: alteration monitoring impossible"
ifvarclass => "!isdir_${index}.!isfile_${index}";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# Author : Matthieu CERDA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
bundle agent check_cron_configuration
{
vars:
&CRON_NAME:{cron_name |"cron_name[&i&]" string => "&cron_name&";
}&
&CRON_COMMAND:{cron_command |"cron_command[&i&]" string => "&cron_command&";
}&
&CRON_USER:{cron_user |"cron_user[&i&]" string => "&cron_user&";
}&
&CRON_FREQUENCY:{cron_frequency |"cron_frequency[&i&]" string => "&cron_frequency&";
}&
&CRON_MANUAL:{cron_manual |"cron_manual[&i&]" string => "&cron_manual&";
}&
&TRACKINGKEY:{uuid |"cron_uuid[&i&]" string => "&uuid&";
}&
"cron_index" slist => getindices("cron_name");
"normalorderingtwist" string => "done";
redhat::
"cron_bin" string => "crond$";
"cron_restartcmd" string => "/etc/init.d/crond restart";
ubuntu::
"cron_bin" string => "cron$";
"cron_restartcmd" string => "/etc/init.d/cron restart";
!(redhat|ubuntu)::
"cron_bin" string => "/usr/sbin/cron$";
"cron_restartcmd" string => "/etc/init.d/cron restart";
classes:
"crontab_absent" not => fileexists("/etc/crontab");
"normalorderingtwist" expression => strcmp("${normalorderingtwist}", "done");
normalorderingtwist::
"${cron_index}_manual" expression => strcmp("${cron_frequency[${cron_index}]}", "d");
"showtime" expression => strcmp("true", "true");
files:
showtime::
"/etc/cron.d/${cron_name[${cron_index}]}"
create => "true",
edit_defaults => empty_backup,
perms => mog("644", "root", "root"),
edit_line => insert_lines("${cron_manual[${cron_index}]} ${cron_user[${cron_index}]} ${cron_command[${cron_index}]}"),
ifvarclass => "${cron_index}_manual",
classes => kept_if_else("cron_file_${cron_index}_kept", "cron_file_${cron_index}_edited", "cron_file_${cron_index}_failed");
"/etc/cron.${cron_frequency[${cron_index}]}/${cron_name[${cron_index}]}"
create => "true",
edit_defaults => empty_backup,
perms => mog("755", "root", "root"),
edit_line => insert_lines("${cron_command[${cron_index}]}"),
ifvarclass => "!${cron_index}_manual",
classes => kept_if_else("cron_file_${cron_index}_kept", "cron_file_${cron_index}_edited", "cron_file_${cron_index}_failed");
processes:
"${cron_bin}"
restart_class => "cron_restart";
commands:
cron_restart::
"${cron_restartcmd}"
args => "restart",
classes => kept_if_else("cron_kept", "cron_restarted", "could_not_restart_cron"),
comment => "Restart the cron daemon";
reports:
!windows::
# Reports about the creation of the cron entries
"@@cronConfiguration@@result_success@@${cron_uuid[${cron_index}]}@@Cron entry@@${cron_name[${cron_index}]}@@${g.execRun}##${g.uuid}@#The cron file ${cron_name[${cron_index}]} was present. Skipping..."
ifvarclass => "cron_file_${cron_index}_kept.!cron_file_${cron_index}_edited";
"@@cronConfiguration@@result_repaired@@${cron_uuid[${cron_index}]}@@Cron entry@@${cron_name[${cron_index}]}@@${g.execRun}##${g.uuid}@#The cron file ${cron_name[${cron_index}]} was created successfully"
ifvarclass => "cron_file_${cron_index}_edited";
"@@cronConfiguration@@result_error@@${cron_uuid[${cron_index}]}@@Cron entry@@${cron_name[${cron_index}]}@@${g.execRun}##${g.uuid}@#Could not create the cron file ${cron_name[${cron_index}]}"
ifvarclass => "cron_file_${cron_index}_failed";
# Reports about the cron process presence
!cron_restart::
"@@cronConfiguration@@result_success@@${cron_uuid[${cron_index}]}@@Cron process@@None@@${g.execRun}##${g.uuid}@#The cron process is running. Skipping...";
cron_restarted::
"@@cronConfiguration@@result_repaired@@${cron_uuid[${cron_index}]}@@Cron process@@None@@${g.execRun}##${g.uuid}@#The cron process has been restarted";
could_not_restart_cron::
"@@cronConfiguration@@result_success@@${cron_uuid[${cron_index}]}@@Cron process@@None@@${g.execRun}##${g.uuid}@#Could not restart the cron process!";
!windows.cron_absent::
"@@cronConfiguration@@log_warn@@${cron_uuid[${cron_index}]}@@cronConfiguration@@None@@${g.execRun}##${g.uuid}@#The crontab is absent";
windows::
"@@cronConfiguration@@result_error@@${cron_uuid[${cron_index}]}@@cronConfiguration@@None@@${g.execRun}##${g.uuid}@#This is a Windows machine. This Technique currently incompatible with it";
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
##########################################################################
# Fstab configuration PT #
# ---------------------------------------------------------------------- #
# Objective : Configure /etc/fstab according to the given parameters #
##########################################################################
bundle agent check_fstab_configuration
{
vars:
&FSTAB_ORIGIN:{origin |"fstab[&i&][origin]" string => "&origin&";
}&
&FSTAB_MOUNT_SELECTOR:{selector |"fstab[&i&][selector]" string => "&selector&";
}&
&FSTAB_DESTINATION:{destination |"fstab[&i&][destination]" string => "&destination&";
}&
&FSTAB_FILESYSTEM:{filesystem |"fstab[&i&][filesystem]" string => "&filesystem&";
}&
&FSTAB_DEFAULTS, FSTAB_ASYNC, FSTAB_ATIME, FSTAB_NOAUTO, FSTAB_DEV, FSTAB_EXEC, FSTAB_SUID, FSTAB_USER, FSTAB_USERS, FSTAB_GROUP, FSTAB_MAND, FSTAB_NETDEV, FSTAB_OWNER, FSTAB_READWRITE, FSTAB_MISCOPTIONS: {defaults, async, atime, noauto, dev, exec, suid, user, users, group, mand, netdev, owner, readwrite, miscoptions | "fstab_raw_options_&i&" slist => { "&defaults&", "&async&", "&atime&", "&noauto&", "&dev&", "&exec&", "&suid&", "&user&", "&users&", "&group&", "&mand&", "&netdev&", "&owner&", "&readwrite&", "&miscoptions&" };
}&
&FSTAB_DUMP:{dump |"fstab[&i&][dump]" string => "&dump&";
}&
&FSTAB_FSCKORDER:{fsckorder |"fstab[&i&][fsckorder]" string => "&fsckorder&";
}&
&FSTAB_ALTERONLY:{alteronly |"fstab_alteronly[&i&]" string => "&alteronly&";
}&
&TRACKINGKEY:{uuid |"fstab[&i&][uuid]" string => "&uuid&";
}&
# We create an index of every fstab entry we will add ( this will be 1, 2, 3 ... )
"fstab_index" slist => getindices("fstab");
# We create a clean list of options : we list them, remove the blanks and join them as a plain string
"fstab_filtered_options_${fstab_index}" slist => grep(".+","fstab_raw_options_${fstab_index}");
"fstab[${fstab_index}][options]" string => join(",", "fstab_filtered_options_${fstab_index}");
# We prepare an array defining the order of the statements in the files ( required by the edit field as seen below )
"fields[destination]" string => "2";
"fields[filesystem]" string => "3";
"fields[options]" string => "4";
"fields[dump]" string => "5";
"fields[fsckorder]" string => "6";
files:
!windows::
"/etc/fstab"
edit_line => fstab_add_line("check_fstab_configuration.fstab", "check_fstab_configuration.fields", "check_fstab_configuration.fstab_alteronly"),
create => "true",
edit_defaults => noempty_backup,
perms => mog("0644", "root", "root"),
classes => kept_if_else("fstab_kept", "fstab_edited", "fstab_failed"),
comment => "Editing the fstab file";
reports:
fstab_kept.!fstab_edited::
"@@fstabConfiguration@@log_info@@${fstab[${fstab_index}][uuid]}@@fstabConfiguration@@None@@${g.execRun}##${g.uuid}@#The fstab file was in accordance with the required policy";
fstab_edited::
"@@fstabConfiguration@@log_info@@${fstab[${fstab_index}][uuid]}@@fstabConfiguration@@None@@${g.execRun}##${g.uuid}@#The fstab file was edited by at least one instance of this technique";
fstab_failed::
"@@fstabConfiguration@@log_warn@@${fstab[${fstab_index}][uuid]}@@fstabConfiguration@@None@@${g.execRun}##${g.uuid}@#The fstab file could NOT be edited by at least one instance of this technique!";
&if(NOVA)&
windows::
"@@fstabConfiguration@@result_error@@${fstab[${fstab_index}][uuid]}@@fstabConfiguration@@None@@${g.execRun}##${g.uuid}@#The fstabConfiguration Technique is not intended to be run on windows. Skipping.";
&endif&
}
bundle edit_line fstab_add_line(data_array, fields, alteronly)
{
vars:
"index" slist => getindices("${data_array}");
"indices_fields" slist => getindices("${fields}");
classes:
"addentry_${index}" expression => strcmp("${${alteronly}[${index}]}", "false");
"delentry_${index}" expression => strcmp("${${alteronly}[${index}]}", "delete");
"empty_origin_${index}" expression => strcmp("${${data_array}[${index}][origin]}", "");
"use_origin_${index}" expression => strcmp("${${data_array}[${index}][selector]}", "origin");
# Cannot handle an addition without the origin, nor handle a reference on the origin if there aren't any
"invalid_${index}" expression => "empty_origin_${index}.(use_origin_${index}|addentry_${index})";
delete_lines:
"^${${data_array}[${index}][origin]}[ \t]+.*"
ifvarclass => "delentry_${index}.use_origin_${index}.!invalid_${index}",
classes => kept_if_else("line_${index}_kept", "line_${index}_handled", "line_${index}_handle_failed");
"^[^#]+[ \t]+${${data_array}[${index}][destination]}[ \t]+.*"
ifvarclass => "delentry_${index}.!use_origin_${index}",
classes => kept_if_else("line_${index}_kept", "line_${index}_handled", "line_${index}_handle_failed");
field_edits:
"^${${data_array}[${index}][origin]}[ \t].*"
edit_field => fstab_col("[ \t]+","${${fields}[${indices_fields}]}","${${data_array}[${index}][${indices_fields}]}","set"),
classes => kept_if_else("line_${index}_kept", "line_${index}_handled", "line_${index}_handle_failed"),
ifvarclass => "use_origin_${index}.!invalid_${index}";
"^[^#]*[ \t]${${data_array}[${index}][destination]}[ \t].*"
edit_field => fstab_col("[ \t]+","${${fields}[${indices_fields}]}","${${data_array}[${index}][${indices_fields}]}","set"),
classes => kept_if_else("line_${index}_kept", "line_${index}_handled", "line_${index}_handle_failed"),
ifvarclass => "!use_origin_${index}";
insert_lines:
"${${data_array}[${index}][origin]} ${${data_array}[${index}][destination]} ${${data_array}[${index}][filesystem]} ${${data_array}[${index}][options]} ${${data_array}[${index}][dump]} ${${data_array}[${index}][fsckorder]}"
ifvarclass => "addentry_${index}.!line_${index}_handled.!invalid_${index}",
classes => kept_if_else("line_${index}_kept", "line_${index}_handled", "line_${index}_handle_failed");
reports:
cfengine::
"@@fstabConfiguration@@result_error@@${${data_array}[${index}][uuid]}@@fstabConfiguration@@${${data_array}[${index}][destination]}@@${g.execRun}##${g.uuid}@#The entry for ${${data_array}[${index}][destination]} is invalid, for it doesn't contain an origin : how can it be updated/inserted/deleted?"
ifvarclass => "invalid_${index}";
"@@fstabConfiguration@@result_repaired@@${${data_array}[${index}][uuid]}@@fstabConfiguration@@${${data_array}[${index}][destination]}@@${g.execRun}##${g.uuid}@#The entry for ${${data_array}[${index}][origin]} to ${${data_array}[${index}][destination]} has been handled"
ifvarclass => "line_${index}_handled";
"@@fstabConfiguration@@result_success@@${${data_array}[${index}][uuid]}@@fstabConfiguration@@${${data_array}[${index}][destination]}@@${g.execRun}##${g.uuid}@#The entry for ${${data_array}[${index}][origin]} to ${${data_array}[${index}][destination]} is already in accordance with the policy"
ifvarclass => "line_${index}_kept.!line_${index}_handled.!empty_origin_${index}";
"@@fstabConfiguration@@result_success@@${${data_array}[${index}][uuid]}@@fstabConfiguration@@${${data_array}[${index}][destination]}@@${g.execRun}##${g.uuid}@#The entry for ${${data_array}[${index}][destination]} contained the proper fields"
ifvarclass => "line_${index}_kept.!line_${index}_handled.empty_origin_${index}";
"@@fstabConfiguration@@result_error@@${${data_array}[${index}][uuid]}@@fstabConfiguration@@${${data_array}[${index}][destination]}@@${g.execRun}##${g.uuid}@#The entry for ${${data_array}[${index}][origin]} to ${${data_array}[${index}][destination]} could not be handled"
ifvarclass => "line_${index}_handle_failed";
"@@fstabConfiguration@@result_success@@${${data_array}[${index}][uuid]}@@fstabConfiguration@@${${data_array}[${index}][destination]}@@${g.execRun}##${g.uuid}@#The entry for ${${data_array}[${index}][origin]} to ${${data_array}[${index}][destination]} was not present but policy required alteration only. This line will be ignored"
ifvarclass => "!addentry_${index}.!line_${index}_handled.!line_${index}_kept.!line_${index}_handle_failed.use_origin_${index}";
"@@fstabConfiguration@@result_success@@${${data_array}[${index}][uuid]}@@fstabConfiguration@@${${data_array}[${index}][destination]}@@${g.execRun}##${g.uuid}@#The entry for ${${data_array}[${index}][destination]} was not present but policy required alteration only. This line will be ignored"
ifvarclass => "!addentry_${index}.!line_${index}_handled.!line_${index}_kept.!line_${index}_handle_failed.!use_origin_${index}";
}
# Workaround for https://dev.cfengine.com/issues/6467
body edit_field fstab_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";
}
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
##############################################################################
# This Technique configures a machine MOTD. See metadata.xml for more details.
##############################################################################
bundle agent rudder_motd
{
vars:
"rudder_motd_service_name" string => "MOTD";
# Prefix for all the defined classes
"rudder_motd_class_prefix" string => "rudder_motd";
"rudder_motd_config[payload]" string => "&MOTD&";
"rudder_motd_config[location]" string => "&MOTD_LOCATION&";
"rudder_motd_config[file_empty]" string => "&MOTD_EMPTY&";
"rudder_motd_config[trackingkey]" string => "&TRACKINGKEY&";
methods:
# Note:
# The reporting is made on separate bundles to abstract the complexity
# inherent to the normal ordering.
"any" usebundle => rudder_motd_configuration("${rudder_motd_class_prefix}", "${rudder_motd_service_name}", "${rudder_motd_config[trackingkey]}", "rudder_motd.rudder_motd_config");
"any" usebundle => rudder_motd_configuration_reporting("${rudder_motd_class_prefix}", "${rudder_motd_service_name}", "${rudder_motd_config[trackingkey]}");
}
#####################################################################################
# Copyright 2011-2013 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
##############################################################
# Sets the MOTD according to the value given in the Directive.
##############################################################
bundle agent rudder_motd_configuration(class_prefix, service_name, trackingkey, params)
{
vars:
"rudder_motd_payload" string => "${${params}[payload]}";
"rudder_motd_location" string => "${${params}[location]}";
"rudder_motd_empty" string => "${${params}[file_empty]}";
debian::
"rudder_motd_file" slist => { "/etc/motd", "/etc/motd.tail" };
!debian::
"rudder_motd_file" slist => { "/etc/motd" };
aix::
"rudder_motd_group" string => "bin";
!aix::
"rudder_motd_group" string => "root";
classes:
"rudder_motd_absent" not => fileexists("/etc/motd");
files:
# Set every MOTD file to the wanted value
!windows::
"${rudder_motd_file}"
create => "true",
edit_defaults => rudder_empty_select("${rudder_motd_empty}"),
perms => mog("644", "root", "${rudder_motd_group}"),
edit_line => rudder_line_insertion("${rudder_motd_payload}", "${rudder_motd_location}"),
classes => rudder_common_classes("${class_prefix}_file_edition");
methods:
# Here, we will define reports for elements which only have a local visibility (like the MOTD file presence detection).
!windows.rudder_motd_absent::
"any"
usebundle => rudder_common_report("${service_name}", "log_repaired", "${trackingkey}", "MOTD Configuration", "None", "The ${service_name} file was absent, it will be created");
&if(NOVA)&
databases:
windows::
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
database_operation => "create",
database_rows => { "legalnoticecaption,REG_SZ,Notice"},
database_type => "ms_registry",
comment => "Editing the windows registry";
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
database_operation => "create",
database_rows => { "legalnoticetext,REG_SZ,${rudder_motd_payload}"},
database_type => "ms_registry",
comment => "Editing the windows registry",
classes => rudder_common_classes("${class_prefix}_file_edition");
&endif&
}
# The reporting is made on separate bundles to abstract the complexity
# inherent to the normal ordering.
bundle agent rudder_motd_configuration_reporting(class_prefix, service_name, trackingkey)
{
methods:
"any" usebundle => rudder_common_reports_generic("${service_name}", "${class_prefix}_file_edition", "${trackingkey}", "MOTD Configuration", "None", "The ${service_name} file");
windows::
"any"
usebundle => rudder_common_report("${service_name}", "result_error", "${trackingkey}", "MOTD Configuration", "None", "This is a Windows machine. This Technique currently incompatible with it");
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
##########################################################################
# Group management PT #
# #
# Objective : Apply group policies on the target host #
##########################################################################
# I was forced to truncate brutally the name, as on CF3 3.1.4 more than 32 chars on the bundle name leads to arrays corruption
bundle agent check_usergroup_grp_parameters {
vars:
&USERGROUP_GROUP_NAME:{name |"usergroup_group_name[&i&]" string => "&name&";
}&
&USERGROUP_GROUP_CREATE:{create |"usergroup_group_create[&i&]" string => "&create&";
}&
&USERGROUP_GROUP_SET_GID:{setgid |"usergroup_group_set_gid[&i&]" string => "&setgid&";
}&
&USERGROUP_GROUP_GID:{gid |"usergroup_group_gid[&i&]" string => "&gid&";
}&
&USERGROUP_GROUP_ENFORCE_CONTENT:{enforce_content |"usergroup_group_enforce_content[&i&]" string => "&enforce_content&";
}&
&USERGROUP_GROUP_CONTENT:{content |"usergroup_group_content[&i&]" string => "&content&";
}&
&USERGROUP_GROUP_POLICY:{policy |"usergroup_group_policy[&i&]" string => "&policy&";
}&
&TRACKINGKEY:{directiveId |"usergroup_group_directive_id[&i&]" string => "&directiveId&";
}&
"usergroup_group_index" slist => getindices("usergroup_group_name");
methods:
"any"
usebundle => check_usergroup_group_parameters_grouphandle("${usergroup_group_name[${usergroup_group_index}]}", "${usergroup_group_create[${usergroup_group_index}]}", "${usergroup_group_set_gid[${usergroup_group_index}]}", "${usergroup_group_gid[${usergroup_group_index}]}","${usergroup_group_enforce_content[${usergroup_group_index}]}", "${usergroup_group_content[${usergroup_group_index}]}", "${usergroup_group_index}", "${usergroup_group_directive_id[${usergroup_group_index}]}");
}
bundle agent check_usergroup_group_parameters_grouphandle(name, create, setgid, gid, enforce_content, content, index, directiveId) {
vars:
"userlist" slist => splitstring("${content}",",","16");
classes:
"groupmanagement_group_${index}_absent" not => groupexists("${name}");
"groupmanagement_group_${index}_create" expression => strcmp("${create}", "true");
"groupmanagement_group_${index}_setgid" expression => strcmp("${setgid}", "true");
"groupmanagement_group_${index}_enforce_content" expression => strcmp("${enforce_content}", "true");
files:
# Enforce group content on if groupmanagement_group_${index}_enforce_content is set
"/etc/group"
edit_line => groups_file_append("${name}", "@(check_usergroup_group_parameters_grouphandle.userlist)"),
edit_defaults => noempty_backup,
classes => rudder_common_classes("groupmanagement_group_add_${index}"),
ifvarclass => "groupmanagement_group_${index}_enforce_content.(!groupmanagement_group_${index}_absent|groupmanagement_group_add_${index}_repaired)",
comment => "Set users on the group ${name} only if the group is already present";
# Enforce GID if setgid has been set
"/etc/group"
create => "false",
edit_line => set_user_field("${name}", 3, "${gid}"),
classes => rudder_common_classes("groupmanagement_group_gid_${index}"),
ifvarclass => "!groupmanagement_group_${index}_absent.groupmanagement_group_${index}_setgid";
commands:
"/usr/sbin/groupadd"
args => "-f \"${name}\"",
classes => if_else("groupmanagement_group_add_${index}_repaired", "groupmanagement_group_add_${index}_error"),
ifvarclass => "groupmanagement_group_${index}_absent.groupmanagement_group_${index}_create.!groupmanagement_group_${index}_setgid",
comment => "Add the group ${name} if it doesn't exists";
"/usr/sbin/groupadd"
args => "-f \"${name}\" -g \"${gid}\"",
classes => if_else("groupmanagement_group_add_${index}_repaired", "groupmanagement_group_add_${index}_error"),
ifvarclass => "groupmanagement_group_${index}_absent.groupmanagement_group_${index}_create.groupmanagement_group_${index}_setgid",
comment => "Add the group ${name} with GID ${gid} if it doesn't exists";
reports:
cfengine::
"@@groupManagement@@result_success@@${directiveId}@@Groups@@${name}@@${g.execRun}##${g.uuid}@#The group ${name} is already present and compliant with the policy"
ifvarclass => "groupmanagement_group_add_${index}_kept.!(groupmanagement_group_add_${index}_repaired|groupmanagement_group_add_${index}_error)";
"@@groupManagement@@result_success@@${directiveId}@@Groups@@${name}@@${g.execRun}##${g.uuid}@#The group ${name} is already present and doesn't require to have its content enforced"
ifvarclass => "!groupmanagement_group_${index}_enforce_content.!(groupmanagement_group_add_${index}_kept.groupmanagement_group_add_${index}_repaired|groupmanagement_group_add_${index}_error)";
"@@groupManagement@@result_repaired@@${directiveId}@@Groups@@${name}@@${g.execRun}##${g.uuid}@#The group ${name} has been updated"
ifvarclass => "groupmanagement_group_add_${index}_repaired.!(groupmanagement_group_add_${index}_kept|groupmanagement_group_add_${index}_error)";
"@@groupManagement@@result_error@@${directiveId}@@Groups@@${name}@@${g.execRun}##${g.uuid}@#The group ${name} could not be created or updated"
ifvarclass => "groupmanagement_group_add_${index}_error";
"@@groupManagement@@result_success@@${directiveId}@@Groups@@${name}@@${g.execRun}##${g.uuid}@#The group ${name} is not present and not set to be created"
ifvarclass => "groupmanagement_group_${index}_absent.!groupmanagement_group_${index}_create";
}
bundle edit_line groups_file_append(group,userlist)
{
vars:
"finalgroup" string => join(",","userlist");
field_edits:
"${group}:.*"
# Set field of the file to parameter
# /etc/group entry is: groupname:x:gid:users
edit_field => col(":","4","${finalgroup}","set");
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
##########################################################################
# Sudo configuration PT #
# ---------------------------------------------------------------------- #
# Objective : Configure /etc/sudoers according to the given parameters #
##########################################################################
bundle agent check_sudo_parameters
{
vars:
&SUDO_TYPE:{type |"sudo_entity_type[&i&]" string => "&type&";
}&
&SUDO_NAME:{name |"sudo_entity_name[&i&]" string => "&name&";
}&
&SUDO_NOPASSWD:{nopasswd |"sudo_entity_nopasswd[&i&]" string => "&nopasswd&";
}&
&SUDO_ALL:{alldo |"sudo_entity_all[&i&]" string => "&alldo&";
}&
&SUDO_COMMAND:{command |"sudo_entity_command[&i&]" string => "&command&";
}&
&TRACKINGKEY:{directiveId |"sudo_directive_id[&i&]" string => "&directiveId&";
}&
"sudo_index" slist => getindices("sudo_entity_type");
pass_1.visudo_use_strict_mode::
"strict_mode" string => "-s ";
pass_1.!visudo_use_strict_mode::
"strict_mode" string => "";
classes:
"sudoconfiguration_sudoers_present" expression => fileexists("/etc/sudoers");
# Check the version of visudo; if before 1.7 (so 1.6 or less), we need to use strict mode
# For version 1.7, bugs in the strict parsing prevent from using safely the strict mode (see http://www.sudo.ws/bugs/show_bug.cgi?id=519 )
# Versions after 1.7 don't need to have Aliases defined before they are used, and strict mode only checks that, so we can safely ignore it
# visudo -V can returns several lines, so we need to keep only the visudo version line
"visudo_use_strict_mode" expression => returnszero("/usr/sbin/visudo -V | grep 'visudo version' | /bin/sed -e 's/visudo version \([0-9]\+\)\.\([0-9]\+\)\..*/\1 \2/p' | /usr/bin/awk '{ if(($1<1)||($1==1 \&\& $2<=6)) { exit 0 }; exit 1 }'", "useshell");
"pass_1" expression => "any";
"pass_2" expression => isvariable("strict_mode");
files:
# Only copy /etc/sudoers if it exists (this is to avoid falling into an
# error report below)
sudoconfiguration_sudoers_present::
"/etc/sudoers.rudder"
copy_from => digest_cp("/etc/sudoers"),
perms => mog("0440", "root", "root"),
classes => kept_if_else("sudoconfiguration_sudoers_tmp_copy_kept", "sudoconfiguration_sudoers_tmp_copy_repaired", "sudoconfiguration_sudoers_tmp_copy_error"),
comment => "Copying sudoers to a temporary file for editing";
# If there is no /etc/sudoers file, remove our local copy before
# rebuilding, so that success/repaired reports make sense for the
# /etc/sudoers file, not just for our copy of it, and set result classes
# as if we had set it up correctly.
!sudoconfiguration_sudoers_present::
"/etc/sudoers.rudder"
delete => tidy,
classes => kept_if_else("sudoconfiguration_sudoers_tmp_copy_kept", "sudoconfiguration_sudoers_tmp_copy_repaired", "sudoconfiguration_sudoers_tmp_copy_error"),
comment => "Remove temporary copy of /etc/sudoers that Rudder keeps in /etc/sudoers.rudder";
((sudoconfiguration_sudoers_tmp_copy_kept|sudoconfiguration_sudoers_tmp_copy_repaired).(!sudoconfiguration_sudoers_tmp_copy_error))::
"/etc/sudoers.rudder"
edit_line => sudo_add_line("check_sudo_parameters.sudo_entity_type", "check_sudo_parameters.sudo_entity_name", "check_sudo_parameters.sudo_entity_nopasswd", "check_sudo_parameters.sudo_entity_all", "check_sudo_parameters.sudo_entity_command", "check_sudo_parameters.sudo_directive_id", "${sudo_force_content}"),
create => "true",
edit_defaults => noempty_backup,
perms => mog("0440", "root", "root"),
classes => kept_if_else("sudoconfiguration_sudoers_tmp_edit_kept", "sudoconfiguration_sudoers_tmp_edit_repair", "sudoconfiguration_sudoers_tmp_edit_error"),
comment => "Editing temporary sudoers file";
sudoconfiguration_sudoers_valid::
"/etc/sudoers"
copy_from => digest_cp("/etc/sudoers.rudder"),
create => "true",
perms => mog("0440", "root", "root"),
classes => kept_if_else("sudoconfiguration_sudoers_copy_kept", "sudoconfiguration_sudoers_copy_repaired", "sudoconfiguration_sudoers_copy_error"),
comment => "Copying sudoers to its final home";
methods:
"any"
usebundle => check_sudo_installation("${sudo_directive_id[${sudo_index}]}");
commands:
(sudoconfiguration_sudoers_tmp_edit_repair|sudoconfiguration_sudoers_tmp_edit_kept).pass_2::
"/usr/sbin/visudo"
args => "-c ${strict_mode} -f /etc/sudoers.rudder",
classes => cf2_if_else("sudoconfiguration_sudoers_valid", "sudoconfiguration_sudoers_invalid"),
comment => "Checking new sudoers validity";
reports:
sudoconfiguration_sudoers_copy_kept.!sudoconfiguration_sudoers_copy_repaired::
"@@sudoParameters@@result_success@@${sudo_directive_id[${sudo_index}]}@@sudoersFile@@None@@${g.execRun}##${g.uuid}@#The sudoers file did not require any modification";
sudoconfiguration_sudoers_copy_repaired::
"@@sudoParameters@@result_repaired@@${sudo_directive_id[${sudo_index}]}@@sudoersFile@@None@@${g.execRun}##${g.uuid}@#The sudoers file was fixed and successfully updated";
sudoconfiguration_sudoers_tmp_edit_error|sudoconfiguration_sudoers_copy_error|sudoconfiguration_sudoers_tmp_copy_error::
"@@sudoParameters@@result_error@@${sudo_directive_id[${sudo_index}]}@@sudoersFile@@None@@${g.execRun}##${g.uuid}@#The sudoers file could NOT be edited!";
sudoconfiguration_sudoers_invalid::
"@@sudoParameters@@result_error@@${sudo_directive_id[${sudo_index}]}@@sudoersFile@@None@@${g.execRun}##${g.uuid}@#The generated sudoers file is invalid. Not updating /etc/sudoers. This should not happen.";
}
bundle edit_line sudo_add_line(type, name, nopasswd, alldo, command, directiveId, force)
{
vars:
"index" slist => getindices("${type}");
check_sudo_parameters_sudo_add_line_classes_defined::
"lines[${index}]"
string => "%${${name}[${index}]} ALL=(ALL) NOPASSWD:ALL",
ifvarclass => "(sudo_${index}_isgroup.sudo_${index}_alldo.sudo_${index}_nopasswd).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "%${${name}[${index}]} ALL=(ALL) ALL",
ifvarclass => "(sudo_${index}_isgroup.sudo_${index}_alldo.!sudo_${index}_nopasswd).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "%${${name}[${index}]} ALL=(ALL) NOPASSWD:${${command}[${index}]}",
ifvarclass => "(sudo_${index}_isgroup.sudo_${index}_nopasswd.!sudo_${index}_alldo).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "%${${name}[${index}]} ALL=(ALL) ${${command}[${index}]}",
ifvarclass => "(sudo_${index}_isgroup.!sudo_${index}_nopasswd.!sudo_${index}_alldo).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "${${name}[${index}]} ALL=(ALL) NOPASSWD:ALL",
ifvarclass => "(sudo_${index}_isuser.sudo_${index}_alldo.sudo_${index}_nopasswd).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "${${name}[${index}]} ALL=(ALL) ALL",
ifvarclass => "(sudo_${index}_isuser.sudo_${index}_alldo.!sudo_${index}_nopasswd).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "${${name}[${index}]} ALL=(ALL) NOPASSWD:${${command}[${index}]}",
ifvarclass => "(sudo_${index}_isuser.sudo_${index}_nopasswd.!sudo_${index}_alldo).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "${${name}[${index}]} ALL=(ALL) ${${command}[${index}]}",
ifvarclass => "(sudo_${index}_isuser.!sudo_${index}_nopasswd.!sudo_${index}_alldo).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"all_lines" slist => getvalues("lines");
classes:
"sudo_force_content" expression => strcmp("true", "${force}");
# Is it a group ?
"sudo_${index}_isgroup" expression => strcmp("${${type}[${index}]}","group");
# Is it a user ?
"sudo_${index}_isuser" expression => strcmp("${${type}[${index}]}","user");
# Disable password asking ?
"sudo_${index}_nopasswd" expression => strcmp("${${nopasswd}[${index}]}","true");
# Should we enable ALL as command ?
"sudo_${index}_alldo" expression => strcmp("${${alldo}[${index}]}","true");
# Is command empty ?
"sudo_${index}_command_notempty" not => strcmp("${${command}[${index}]}","");
"check_sudo_parameters_sudo_add_line_classes_defined" expression => "any";
"check_sudo_parameters_sudo_add_line_vars_defined" expression => isvariable("lines[${index}]");
"all_lines_defined" expression => isvariable("all_lines");
delete_lines:
all_lines_defined.force::
".*"
delete_select => sudo_select_nomatch("${all_lines}"),
classes => if_repaired("line_deleted");
insert_lines:
replace_attempted_env_reset::
"Defaults env_reset";
check_sudo_parameters_sudo_add_line_vars_defined::
"${lines[${index}]}"
classes => kept_if_else("line_${index}_kept", "line_${index}_added", "line_${index}_add_failed");
replace_patterns:
"^(?!Defaults env_reset$)Defaults\s+env_reset$"
comment => "Normalize env_reset setting",
replace_with => value("Defaults env_reset"),
classes => always("replace_attempted_env_reset");
reports:
all_lines_defined::
"@@sudoParameters@@log_warn@@${${directiveId}[${index}]}@@Permissions@@${${name}[${index}]}@@${g.execRun}##${g.uuid}@#Entry for ${${type}[${index}]} ${${name}[${index}]} is invalid (no command given), and has been ignored"
ifvarclass => "!sudo_${index}_command_notempty.!sudo_${index}_alldo";
"@@sudoParameters@@result_repaired@@${${directiveId}[${index}]}@@Permissions@@${${name}[${index}]}@@${g.execRun}##${g.uuid}@#The ${${type}[${index}]} ${${name}[${index}]} has been handled"
ifvarclass => canonify("line_${index}_added");
"@@sudoParameters@@result_success@@${${directiveId}[${index}]}@@Permissions@@${${name}[${index}]}@@${g.execRun}##${g.uuid}@#The ${${type}[${index}]} ${${name}[${index}]} is already present"
ifvarclass => canonify("line_${index}_kept");
"@@sudoParameters@@result_error@@${${directiveId}[${index}]}@@Permissions@@${${name}[${index}]}@@${g.execRun}##${g.uuid}@#The ${${type}[${index}]} ${${name}[${index}]} could not be handled"
ifvarclass => canonify("line_${index}_add_failed");
all_lines_defined.force.line_deleted::
"@@sudoParameters@@result_repaired@@sudoersFile@@None@@${g.execRun}##${g.uuid}@#Some lines were deleted from the sudoers file. This implies either a manual edition or an intrusion attempt";
}
bundle agent check_sudo_installation(directiveId)
{
packages:
linux::
"sudo"
package_policy => "add",
package_method => generic,
classes => kept_if_else("sudoconfiguration_sudo_install_kept", "sudoconfiguration_sudo_install_repaired", "sudoconfiguration_sudo_install_error"),
comment => "Installing sudo using generic interface";
reports:
sudoconfiguration_sudo_install_kept::
"@@sudoParameters@@result_success@@${directiveId}@@Install@@None@@${g.execRun}##${g.uuid}@#sudo already installed";
sudoconfiguration_sudo_install_repaired::
"@@sudoParameters@@result_repaired@@${directiveId}@@Install@@None@@${g.execRun}##${g.uuid}@#sudo has been successfully installed";
sudoconfiguration_sudo_install_error::
"@@sudoParameters@@result_error@@${directiveId}@@Install@@None@@${g.execRun}##${g.uuid}@#Can't install sudo";
!linux::
"@@sudoParameters@@result_success@@${directiveId}@@Install@@None@@${g.execRun}##${g.uuid}@#Support to check if sudo is installed not available on this platform";
}
body delete_select sudo_select_nomatch(s)
{
delete_if_not_match_from_list => { "Defaults env_reset", @{s} };
}
#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
##########################################################################
# User/Group management PT #
# #
# Objective : Apply user/group policies on the target host #
##########################################################################
bundle agent check_usergroup_user_parameters
{
vars:
&USERGROUP_USER_LOGIN:{login |"usergroup_user_login[&i&]" string => "&login&";
}&
&USERGROUP_USER_GROUP:{group |"usergroup_user_groupname[&i&]" string => "&group&";
}&
&USERGROUP_USER_NAME:{name |"usergroup_user_fullname[&i&]" string => "&name&";
}&
&USERGROUP_USER_PASSWORD:{password |"usergroup_user_password[&i&]" string => "&password&";
}&
&USERGROUP_USER_PASSWORD_POLICY:{passwordpol |"usergroup_user_password_policy[&i&]" string => "&passwordpol&";
}&
&USERGROUP_USER_ACTION:{action |"usergroup_user_action[&i&]" string => "&action&";
}&
&USERGROUP_USER_UID:{uid |"usergroup_user_uid[&i&]" string => "&uid&";
}&
&USERGROUP_USER_HOME_PERSONNALIZE:{homeperso |"usergroup_user_home_perso[&i&]" string => "&homeperso&";
}&
&USERGROUP_USER_HOME:{home |"usergroup_user_home[&i&]" string => "&home&";
}&
&USERGROUP_USER_SHELL:{shell |"usergroup_user_shell[&i&]" string => "&shell&";
}&
&TRACKINGKEY:{directiveId |"usergroup_directive_id[&i&]" string => "&directiveId&";
}&
"usergroup_user_index" slist => getindices("usergroup_user_login");
any_2nd_pass::
# 1 - Options to use whether Fullname is defined or not
"nameopt[${usergroup_user_index}]"
string => "",
ifvarclass => "usermanagement_user_nameempty_${usergroup_user_index}";
## On UNIX
"nameopt[${usergroup_user_index}]"
string => "-c \"${usergroup_user_fullname[${usergroup_user_index}]}\"",
ifvarclass => "!usermanagement_user_nameempty_${usergroup_user_index}.!windows";
## On Windows
"nameopt[${usergroup_user_index}]"
string => "/FULLNAME:\"${usergroup_user_fullname[${usergroup_user_index}]}\"",
ifvarclass => "!usermanagement_user_nameempty_${usergroup_user_index}.windows";
## Part of reports to return whether Fullname is defined or not
"repname[${usergroup_user_index}]"
string => "Without any defined full name",
ifvarclass => "usermanagement_user_nameempty_${usergroup_user_index}";
"repname[${usergroup_user_index}]"
string => "${usergroup_user_fullname[${usergroup_user_index}]}",
ifvarclass => "!usermanagement_user_nameempty_${usergroup_user_index}";
# 2 - On UNIX, choose between using no group name or using a custom one
"groupopt[${usergroup_user_index}]"
string => "",
ifvarclass => "usermanagement_user_groupempty_${usergroup_user_index}";
"groupopt[${usergroup_user_index}]"
string => "-g ${usergroup_user_groupname[${usergroup_user_index}]}",
ifvarclass => "!usermanagement_user_groupempty_${usergroup_user_index}";
# 3 - on UNIX force user id if provided
"useropt[${usergroup_user_index}]"
string => "",
ifvarclass => "usermanagement_user_uid_empty_${usergroup_user_index}";
"useropt[${usergroup_user_index}]"
string => "-u ${usergroup_user_uid[${usergroup_user_index}]}",
ifvarclass => "!usermanagement_user_uid_empty_${usergroup_user_index}";
classes:
# Actions
"usermanagement_user_update_${usergroup_user_index}" expression => strcmp("${usergroup_user_action[${usergroup_user_index}]}","add");
"usermanagement_user_remove_${usergroup_user_index}" expression => strcmp("${usergroup_user_action[${usergroup_user_index}]}","remove");
"usermanagement_user_checkpres_${usergroup_user_index}" expression => strcmp("${usergroup_user_action[${usergroup_user_index}]}","checkhere");
"usermanagement_user_checkabs_${usergroup_user_index}" expression => strcmp("${usergroup_user_action[${usergroup_user_index}]}","checknothere");
"usermanagement_user_pershome_${usergroup_user_index}" not => strcmp("${usergroup_user_home_perso[${usergroup_user_index}]}","true");
"usermanagement_user_custom_home_defined_${usergroup_user_index}" expression => isvariable("usergroup_user_home[${usergroup_user_index}]");
"usermanagement_user_exists_${usergroup_user_index}" expression => userexists("${usergroup_user_login[${usergroup_user_index}]}");
"usermanagement_group_exists_${usergroup_user_index}" expression => groupexists("${usergroup_user_groupname[${usergroup_user_index}]}");
"usermanagement_user_pwoneshot_${usergroup_user_index}" expression => strcmp("${usergroup_user_password_policy[${usergroup_user_index}]}","oneshot");
"usermanagement_user_pweverytime_${usergroup_user_index}" expression => strcmp("${usergroup_user_password_policy[${usergroup_user_index}]}","everytime");
# with variables that are not unique, the emptyness detection is quite tricky
# either the variable is not defined, or the variable value is ""
"usermanagement_user_pw_no_variable_${usergroup_user_index}" not => isvariable("usergroup_user_password[${usergroup_user_index}]");
"usermanagement_user_pw_no_value_${usergroup_user_index}" expression => strcmp("", "${usergroup_user_password[${usergroup_user_index}]}");
"usermanagement_user_pwempty_${usergroup_user_index}" expression => "usermanagement_user_pw_no_variable_${usergroup_user_index}|usermanagement_user_pw_no_value_${usergroup_user_index}";
"usermanagement_user_name_no_variable_${usergroup_user_index}" not => isvariable("usergroup_user_fullname[${usergroup_user_index}]");
"usermanagement_user_name_no_value_${usergroup_user_index}" expression => strcmp("", "${usergroup_user_fullname[${usergroup_user_index}]}");
"usermanagement_user_nameempty_${usergroup_user_index}" expression => "usermanagement_user_name_no_variable_${usergroup_user_index}|usermanagement_user_name_no_value_${usergroup_user_index}";
"usermanagement_user_group_no_variable_${usergroup_user_index}" not => isvariable("usergroup_user_groupname[${usergroup_user_index}]");
"usermanagement_user_group_no_value_${usergroup_user_index}" expression => strcmp("", "${usergroup_user_groupname[${usergroup_user_index}]}");
"usermanagement_user_groupempty_${usergroup_user_index}" expression => "usermanagement_user_group_no_variable_${usergroup_user_index}|usermanagement_user_group_no_value_${usergroup_user_index}";
"usermanagement_user_uid_no_variable_${usergroup_user_index}" not => isvariable("usergroup_user_uid[${usergroup_user_index}]");
"usermanagement_user_uid_no_value_${usergroup_user_index}" expression => strcmp("", "${usergroup_user_uid[${usergroup_user_index}]}");
"usermanagement_user_uid_empty_${usergroup_user_index}" expression => "usermanagement_user_uid_no_variable_${usergroup_user_index}|usermanagement_user_uid_no_value_${usergroup_user_index}";
"usermanagement_user_groupmatchesname_${usergroup_user_index}" expression => strcmp("${usergroup_user_login[${usergroup_user_index}]}", "${usergroup_user_groupname[${usergroup_user_index}]}");
# Group doesn't exist and group name is defined
"usermanagement_user_group_definition_error_${usergroup_user_index}" expression => "(!usermanagement_group_exists_${usergroup_user_index}.usermanagement_user_groupmatchesname_${usergroup_user_index})|(!usermanagement_user_groupempty_${usergroup_user_index}.!usermanagement_group_exists_${usergroup_user_index})";
# check if user exists when enforcing ids
"usermanagement_uid_exists_${usergroup_user_index}" expression => userexists("${usergroup_user_uid[${usergroup_user_index}]}"),
ifvarclass => "!usermanagement_user_uid_empty_${usergroup_user_index}";
# UID is defined and already exists
"usermanagement_user_uid_definition_error_${usergroup_user_index}" expression => "!usermanagement_user_uid_empty_${usergroup_user_index}.usermanagement_uid_exists_${usergroup_user_index}";
# Class 'any' is executed before others classes defined.
# Same as 'any' but execution will be after all classes defined
"any_2nd_pass" expression => "any";
"showtime" expression => isvariable("nameopt[1]");
files:
"/etc/passwd"
create => "false",
edit_line => set_user_fullname("${usergroup_user_login[${usergroup_user_index}]}","${usergroup_user_index}","${usergroup_user_fullname[${usergroup_user_index}]}"),
edit_defaults => noempty_backup,
ifvarclass => "usermanagement_user_update_${usergroup_user_index}.!usermanagement_user_nameempty_${usergroup_user_index}";
"/etc/passwd"
create => "false",
edit_line => set_user_fullname("${usergroup_user_login[${usergroup_user_index}]}","${usergroup_user_index}","${usergroup_user_fullname[${usergroup_user_index}]}"),
edit_defaults => noempty_backup,
action => WarnOnly,
ifvarclass => "usermanagement_user_checkpres_${usergroup_user_index}.!usermanagement_user_nameempty_${usergroup_user_index}";
# Define password when user has already been created
"/etc/shadow"
create => "false",
edit_line => set_user_field("${usergroup_user_login[${usergroup_user_index}]}", 2, "${usergroup_user_password[${usergroup_user_index}]}"),
edit_defaults => noempty_backup,
classes => kept_if_else("usermanagement_user_password_ok_${usergroup_user_index}", "usermanagement_user_password_repaired_${usergroup_user_index}", "usermanagement_user_password_failed_${usergroup_user_index}"),
ifvarclass => "(usermanagement_login_add_${usergroup_user_index}_repaired.usermanagement_user_pwoneshot_${usergroup_user_index}.!usermanagement_user_pwempty_${usergroup_user_index})|(usermanagement_user_update_${usergroup_user_index}.usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_pweverytime_${usergroup_user_index}.!usermanagement_user_pwempty_${usergroup_user_index})";
commands:
&if(NOVA)&
windows.showtime::
"\"${sys.winsysdir}\net.exe\""
args => "USER ${usergroup_user_login[${usergroup_user_index}]} ${usergroup_user_password[${usergroup_user_index}]} /ADD ${nameopt[${usergroup_user_index}]}",
classes => cf2_if_else("usermanagement_login_add_${usergroup_user_index}_repaired", "usermanagement_login_add_${usergroup_user_index}_error"),
comment => "Create the user ${usergroup_user_login[${usergroup_user_index}]}",
ifvarclass => "!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_update_${usergroup_user_index}";
"\"${sys.winsysdir}\net.exe\""
args => "USER ${usergroup_user_login[${usergroup_user_index}]} /DELETE",
classes => cf2_if_else("usermanagement_login_remove_${usergroup_user_index}_repaired", "usermanagement_login_remove_${usergroup_user_index}_error"),
comment => "Delete the user ${usergroup_user_login[${usergroup_user_index}]}",
ifvarclass => "usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_remove_${usergroup_user_index}";
"\"${sys.winsysdir}\net.exe\""
args => "USER ${usergroup_user_login[${usergroup_user_index}]} ${usergroup_user_password[${usergroup_user_index}]}",
ifvarclass => "(usermanagement_login_add_${usergroup_user_index}_repaired.usermanagement_user_pwoneshot_${usergroup_user_index}.!usermanagement_user_pwempty_${usergroup_user_index})|(usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_pweverytime_${usergroup_user_index}.!usermanagement_user_pwempty_${usergroup_user_index})";
&endif&
linux.showtime::
"/usr/sbin/useradd"
args => "${useropt[${usergroup_user_index}]} ${groupopt[${usergroup_user_index}]} -m ${nameopt[${usergroup_user_index}]} -s ${usergroup_user_shell[${usergroup_user_index}]} ${usergroup_user_login[${usergroup_user_index}]}",
classes => cf2_if_else("usermanagement_login_add_${usergroup_user_index}_repaired", "usermanagement_login_add_${usergroup_user_index}_error"),
comment => "Create the user",
ifvarclass => "!usermanagement_user_uid_definition_error_${usergroup_user_index}.!usermanagement_user_group_definition_error_${usergroup_user_index}.!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_update_${usergroup_user_index}.!usermanagement_user_pershome_${usergroup_user_index}";
"/usr/sbin/useradd"
args => "${useropt[${usergroup_user_index}]} ${groupopt[${usergroup_user_index}]} -m ${nameopt[${usergroup_user_index}]} -s ${usergroup_user_shell[${usergroup_user_index}]} -d ${usergroup_user_home[${usergroup_user_index}]} ${usergroup_user_login[${usergroup_user_index}]}",
classes => cf2_if_else("usermanagement_login_add_${usergroup_user_index}_repaired", "usermanagement_login_add_${usergroup_user_index}_error"),
comment => "Create the user with a custom home directory",
ifvarclass => "!usermanagement_user_uid_definition_error_${usergroup_user_index}.!usermanagement_user_group_definition_error_${usergroup_user_index}.!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_update_${usergroup_user_index}.usermanagement_user_pershome_${usergroup_user_index}.usermanagement_user_custom_home_defined_${usergroup_user_index}";
"/usr/sbin/userdel"
args => "${usergroup_user_login[${usergroup_user_index}]}",
classes => cf2_if_else("usermanagement_login_remove_${usergroup_user_index}_repaired", "usermanagement_login_remove_${usergroup_user_index}_error"),
comment => "Delete the user ${usergroup_user_login[${usergroup_user_index}]}",
ifvarclass => "usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_remove_${usergroup_user_index}";
reports:
(linux|windows).showtime::
# Add user
## Does exist (Success)
"@@userGroupManagement@@result_success@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) is already present on the system"
ifvarclass => "usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_update_${usergroup_user_index}.!usermanagement_login_add_${usergroup_user_index}_repaired.(usermanagement_user_nameempty_${usergroup_user_index}|usermanagement_fullname_edit_${usergroup_user_index}_kept)";
## Seems to exist with a wrong Full Name (Repaired)
"@@userGroupManagement@@result_repaired@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) had a wrong fullname"
ifvarclass => "usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_update_${usergroup_user_index}.!usermanagement_user_nameempty_${usergroup_user_index}.(usermanagement_fullname_edit_${usergroup_user_index}_repaired|usermanagement_fullname_edit_${usergroup_user_index}_error)";
## Added (Repaired)
"@@userGroupManagement@@result_repaired@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) has been added to the system"
ifvarclass => "!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_update_${usergroup_user_index}.usermanagement_login_add_${usergroup_user_index}_repaired";
## Error
"@@userGroupManagement@@result_error@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) could not be added to the system"
ifvarclass => "!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_update_${usergroup_user_index}.usermanagement_login_add_${usergroup_user_index}_error";
## Could not be added, for the default path was not selected, but the custom one was not defined
"@@userGroupManagement@@result_error@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) could not be added to the system because the default home directory was not selected, but the custom path was not specified"
ifvarclass => "!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_update_${usergroup_user_index}.usermanagement_user_pershome_${usergroup_user_index}.!usermanagement_user_custom_home_defined_${usergroup_user_index}";
## Could not be added, as a custom group was asked for and did not exist on the system
"@@userGroupManagement@@result_error@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) could not be added to the system because the custom group \"${usergroup_user_groupname[${usergroup_user_index}]}\" does not exist"
ifvarclass => "usermanagement_user_update_${usergroup_user_index}.!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_group_definition_error_${usergroup_user_index}";
## Could not be added, as a custom uid was asked for and did exist on the system
"@@userGroupManagement@@result_error@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) could not be added to the system because the custom uid \"${usergroup_user_uid[${usergroup_user_index}]}\" already exists"
ifvarclass => "usermanagement_user_update_${usergroup_user_index}.!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_uid_definition_error_${usergroup_user_index}";
# Remove user
## Does not exist (Success)
"@@userGroupManagement@@result_success@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) does not exist, as required"
ifvarclass => "!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_remove_${usergroup_user_index}";
## Removed (Repaired)
"@@userGroupManagement@@result_repaired@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) has been removed from the system"
ifvarclass => "usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_remove_${usergroup_user_index}.usermanagement_login_remove_${usergroup_user_index}_repaired";
## Error
"@@userGroupManagement@@result_error@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) could not be removed from the system"
ifvarclass => "usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_remove_${usergroup_user_index}.usermanagement_login_remove_${usergroup_user_index}_error";
# Check user not exists
## Does not exist (Success)
"@@userGroupManagement@@result_success@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) is not present on the system, which is in accordance with the non presence policy"
ifvarclass => "!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_checkabs_${usergroup_user_index}";
## Does exist (Error)
"@@userGroupManagement@@result_error@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) is present on the system, which violates the non presence policy"
ifvarclass => "usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_checkabs_${usergroup_user_index}";
# Check user exists
## Does exist (Success)
"@@userGroupManagement@@result_success@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) is present on the system, which is in conformance with the presence policy"
ifvarclass => "usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_checkpres_${usergroup_user_index}.(usermanagement_user_nameempty_${usergroup_user_index}|usermanagement_fullname_edit_${usergroup_user_index}_kept)";
## Seems to exist with a wrong Full Name (Error)
"@@userGroupManagement@@result_error@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) is present on the system, but does not have the right fullname"
ifvarclass => "usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_checkpres_${usergroup_user_index}.!usermanagement_user_nameempty_${usergroup_user_index}.(usermanagement_fullname_edit_${usergroup_user_index}_repaired|usermanagement_fullname_edit_${usergroup_user_index}_error)";
## Does not exist (Error)
"@@userGroupManagement@@result_error@@${usergroup_directive_id[${usergroup_user_index}]}@@Users@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) is not present on the system, which violates the presence policy"
ifvarclass => "!usermanagement_user_exists_${usergroup_user_index}.usermanagement_user_checkpres_${usergroup_user_index}";
# Password handling
## Is OK (Success)
"@@userGroupManagement@@result_success@@${usergroup_directive_id[${usergroup_user_index}]}@@Password@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) password is OK"
ifvarclass => "usermanagement_user_password_ok_${usergroup_user_index}";
## Has been changed (Repaired)
"@@userGroupManagement@@result_repaired@@${usergroup_directive_id[${usergroup_user_index}]}@@Password@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) password has been changed"
ifvarclass => "usermanagement_user_password_repaired_${usergroup_user_index}";
## Could not be changed (Error)
"@@userGroupManagement@@result_error@@${usergroup_directive_id[${usergroup_user_index}]}@@Password@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) password could NOT be changed !"
ifvarclass => "usermanagement_user_password_failed_${usergroup_user_index}";
## Change not needed (Success)
"@@userGroupManagement@@result_success@@${usergroup_directive_id[${usergroup_user_index}]}@@Password@@${usergroup_user_login[${usergroup_user_index}]}@@${g.execRun}##${g.uuid}@#The user ${usergroup_user_login[${usergroup_user_index}]} ( ${repname[${usergroup_user_index}]} ) password change is not required"
ifvarclass => "((!usermanagement_user_password_ok_${usergroup_user_index}.!usermanagement_user_password_repaired_${usergroup_user_index}.!usermanagement_user_password_failed_${usergroup_user_index}).((usermanagement_user_pwoneshot_${usergroup_user_index}.usermanagement_user_exists_${usergroup_user_index})|usermanagement_user_pwempty_${usergroup_user_index}|(usermanagement_user_update_${usergroup_user_index}.!usermanagement_user_exists_${usergroup_user_index}.(usermanagement_user_group_definition_error_${usergroup_user_index}|usermanagement_user_uid_definition_error_${usergroup_user_index}))))|usermanagement_user_remove_${usergroup_user_index}";
}
bundle edit_line set_user_fullname(user,user_index,fullname)
{
field_edits:
"${user}:.*"
# Edit GECOS on /etc/passwd
edit_field => col(":", "5", "${fullname}", "set"),
classes => kept_if_else("usermanagement_fullname_edit_${user_index}_kept","usermanagement_fullname_edit_${user_index}_repaired","usermanagement_fullname_edit_${user_index}_error");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment