#####################################################################################
# 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 .
#
#####################################################################################
#
# 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)
# Compute the inventory time
bundle agent computeInventoryTime
{
vars:
"run_interval" int => "&AGENT_RUN_INTERVAL&";
"inventory_time_hours" slist => { "Hr00", "Hr01", "Hr02", "Hr03", "Hr04", "Hr05" };
"inventory_time_selection" slist => maplist("${this}_select", "inventory_time_hours");
classes:
"splaying" expression => splayclass("${sys.host}${sys.ipv4}","hourly");
"inventory_run_selection" select_class => { "@{computeInventoryTime.inventory_time_selection}"};
# If this is the default 5 minute schedule, this is the standart case
"default_schedule" expression => isgreaterthan("6", "${run_interval}");
# If the interval is between 6 and 59 minutes, then we "splay" by the select_class, so between Midnight and 5 am
"less_than_one_hour_interval" expression => isgreaterthan("59", "${run_interval}");
# Compute if we are currently in the hour where the inventory should be done
"inventory_hour_selection" expression => "${inventory_time_hours}.${inventory_time_hours}_select";
# Inventory will be during the night, at the hour selected, with a splay is this is the default schedule, else at the first run during the selected hour
# if the interval is less than one hour, else at the first run of the night
"inventory_time" expression => "Night.((splaying.default_schedule.inventory_hour_selection)|(!default_schedule.less_than_one_hour_interval.inventory_hour_selection)|(!less_than_one_hour_interval))",
scope => "namespace";
}
bundle agent doInventory
{
classes:
"disable_inventory" expression => fileexists("${g.rudder_disable_inventory_file}");
methods:
ignore_disable_inventory|!disable_inventory::
"any" usebundle => doInventory_always;
!(ignore_disable_inventory|!disable_inventory)::
"any" usebundle => rudder_common_report("Inventory", "log_warn", "&TRACKINGKEY&", "inventory", "None", "The file ${g.rudder_disable_inventory_file} is present, so Rudder will not send an inventory. Use 'rudder agent inventory -f' to override this temporarily");
}
bundle agent doInventory_always
{
vars:
uuid_succesfully_downloaded::
"policy_server_uuid" string => readfile("${sys.workdir}/rudder-server-uuid.txt", 50);
classes:
# 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"),
scope => "namespace";
"inventory_proxy_defined" expression => isvariable("node.properties[inventory_proxy]"),
scope => "namespace";
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";
any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";
&if(INITIAL)&
"initial_promises" expression => "any",
scope => "namespace";
&endif&
files:
# Clean policy server uuid file defined in 2.11 or earlier version, as location in 3.0+ is ${sys.workdir}/rudder-server-uuid.txt
"${g.rudder_var_tmp}/uuid.txt"
delete => tidy;
methods:
# Compute the inventory time
"any" usebundle => computeInventoryTime;
force_inventory|((inventory_time|initial_promises).!inventory_sent)::
"any" usebundle => download_server_uuid;
uuid_valid.(force_inventory|((inventory_time|initial_promises).!inventory_sent))::
"any" usebundle => fusionAgent;
"any" usebundle => listInstalledVM;
"any" usebundle => generateExtraInformations;
"any" usebundle => turnUsersToUnicode;
"any" usebundle => addInformationsToInventory;
"any" usebundle => checkInventoryFile;
uuid_valid.(force_inventory|((inventory_time|initial_promises).!inventory_sent)).inventory_valid::
"any" usebundle => moveInventoryToFinalDestination;
"any" usebundle => signInventories;
"any" usebundle => compressInventories;
"any" usebundle => sendInventory;
"any" usebundle => cleanForceInventoryFlagFile;
pass3.uuid_succesfully_downloaded.uuid_validity_checked.!uuid_valid::
"any" usebundle => rudder_common_report("Inventory", "result_error", "&TRACKINGKEY&", "inventory", "None", "Could not retrieve a valid UUID from the policy server");
# Send reports to confirm this technique success even if we don't need to send an inventory
pass3.inventory_sent::
"any" usebundle => rudder_common_report("Inventory", "log_info", "&TRACKINGKEY&", "inventory", "None", "An inventory was already sent less than 8 hours ago");
pass3.!(Night.splaying).!force_inventory::
"any" usebundle => rudder_common_report("Inventory", "result_success", "&TRACKINGKEY&", "inventory", "None", "Next inventory scheduled between 00:00 and 06:00");
}
bundle agent download_server_uuid
{
vars:
# If curl is available, use it
!windows.curl_installed.!inventory_proxy_defined::
"download_command" string => "${g.rudder_curl} -L -k -1 -s -f --proxy '' -o \"${sys.workdir}/rudder-server-uuid.txt\" ${g.inventory_upload_protocol}://${server_info.cfserved}/uuid";
!windows.curl_installed.inventory_proxy_defined::
"download_command" string => "${g.rudder_curl} -L -k -1 -s -f --proxy '${node.properties[inventory_proxy]}' -o \"${sys.workdir}/rudder-server-uuid.txt\" ${g.inventory_upload_protocol}://${server_info.cfserved}/uuid";
# If not, use minicurl instead
!windows.!curl_installed::
"download_command" string => "${g.minicurl} --no-verify --get --file \"${sys.workdir}/rudder-server-uuid.txt\" --url ${g.inventory_upload_protocol}://${server_info.cfserved}/uuid";
&if(NOVA)&
# On windows, always use curl
windows::
"download_command" string => "\"${g.rudder_base_sbin}\curl\curl.exe\" -L -k -1 -s -f --noproxy '${server_info.cfserved}' -o \"${sys.workdir}\rudder-server-uuid.txt\" ${g.inventory_upload_protocol}://${server_info.cfserved}/uuid";
&endif&
methods:
could_not_download_uuid::
"any" usebundle => rudder_common_report("Inventory", "result_error", "&TRACKINGKEY&", "inventory", "None", "Could not retrieve the UUID of the policy server");
commands:
"${download_command}"
comment => "Getting the uuid from the server",
classes => if_else("uuid_succesfully_downloaded","could_not_download_uuid");
}
bundle common inventory
{
vars:
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\"";
android::
"cpuid_tool" string => "${g.rudder_tools}/cpuid-android-V1.0.sh";
!aix.!windows.!android.!solaris::
"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_domu_hv)::
"xen_tools_package" string => "xen-tools-domU";
debian::
"xen_tools_package" string => "xenstore-utils";
!debian.!SuSE::
"xen_tools_package" string => "xen";
# guarding execresult to save a lot of time during policy validation
!windows.(force_inventory|inventory_time|initial_promises)::
"fusion_inventory_version" string => execresult("${g.rudder_base}/bin/run-inventory --version | ${paths.path[grep]} '[0-9]\.[0-9]' | ${paths.path[sed]} 's%.*(\([0-9]\+\)\.\([0-9]\+\).*).*%\1\2%'", "useshell");
"inventory_path" string => "${g.rudder_var_tmp}/inventory", policy => "overridable"; # Default value
"inventory_path_edition" string => "${g.rudder_var_tmp}/inventory/.*.ocs", policy => "overridable"; # Default value for editing the inventory files
!windows.fusion_inventory_version_23_or_later::
# FusionInventory 2.3+ permits to specify the exact inventory file name we want
"inventory_path" string => "${g.rudder_var_tmp}/inventory/${sys.uqhost}-${g.uuid}.ocs";
"inventory_path_edition" string => "${g.rudder_var_tmp}/inventory/${sys.uqhost}-${g.uuid}.ocs";
windows:: # We assume we always have FusionInventory 2.3+ on Windows
"inventory_path" string => "${g.rudder_var_tmp}\inventory\${sys.uqhost}-${g.uuid}.ocs";
"inventory_path_edition" string => "${g.rudder_var_tmp}\inventory\${sys.uqhost}-${g.uuid}.ocs";
classes:
!windows::
# CFEngine doesn't have a ">=" operator, so I'm using "! <" instead
"fusion_inventory_version_23_or_later" not => islessthan("${fusion_inventory_version}", "23");
any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";
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";
methods:
pass3.run_inventory::
"any" usebundle => rudder_common_report("Inventory", "log_debug", "&TRACKINGKEY&", "inventory", "None", "Running inventory");
pass3.inventory_failed::
"any" usebundle => rudder_common_report("Inventory", "result_error", "&TRACKINGKEY&", "inventory", "None", "Could not execute the inventory");
pass3.cant_install_curl::
"any" usebundle => rudder_common_report("Inventory", "result_error", "&TRACKINGKEY&", "inventory", "None", "Could not install curl");
pass3.cant_install_ocs::
"any" usebundle => rudder_common_report("Inventory", "result_error", "&TRACKINGKEY&", "inventory", "None", "Could not install ocs");
pass3.cant_install_xen::
"any" usebundle => rudder_common_report("Inventory", "result_error", "&TRACKINGKEY&", "inventory", "None", "Could not install Xen utils on Xen system");
pass3.xen_installed::
"any" usebundle => rudder_common_report("Inventory", "log_info", "&TRACKINGKEY&", "inventory", "None", "Xen utils installed");
pass3.curl_installed::
"any" usebundle => rudder_common_report("Inventory", "log_info", "&TRACKINGKEY&", "inventory", "None", "Curl installed");
commands:
!windows.inventoryfoldercreated::
"${g.rudder_base}/bin/run-inventory --local=${inventory_path}"
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=\"${inventory_path}\" 2>nul",
contain => in_shell,
classes => cf2_if_else("run_inventory", "inventory_failed"),
comment => "Generating inventory";
&endif&
}
# 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
{
classes:
any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";
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";
methods:
pass3.cant_list_vm::
"any" usebundle => rudder_common_report("Inventory", "log_warn", "&TRACKINGKEY&", "inventory", "None", "Could not list installed VMWare machines");
pass3.cant_list_vb::
"any" usebundle => rudder_common_report("Inventory", "log_warn", "&TRACKINGKEY&", "inventory", "None", "Could not list installed VirtualBox machines");
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&
}
bundle agent generateExtraInformations
{
classes:
any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";
methods:
pass3.userlist::
"any" usebundle => rudder_common_report("Inventory", "log_debug", "&TRACKINGKEY&", "inventory", "None", "Generated the userlist");
pass3.cpuid::
"any" usebundle => rudder_common_report("Inventory", "log_debug", "&TRACKINGKEY&", "inventory", "None", "Generated the CPUID");
pass3.userlist_fail::
"any" usebundle => rudder_common_report("Inventory", "result_error", "&TRACKINGKEY&", "inventory", "None", "Could not generate the user list");
pass3.cpuid_fail::
"any" usebundle => rudder_common_report("Inventory", "result_error", "&TRACKINGKEY&", "inventory", "None", "Could not generate the CPUID");
pass3.!rudder_inventory_userlist_tool_present::
"any" usebundle => rudder_common_report("Inventory", "log_debug", "&TRACKINGKEY&", "inventory", "None", "User list generation tool is not present yet. Skipping...");
pass3.!rudder_inventory_cpuid_tool_present::
"any" usebundle => rudder_common_report("Inventory", "log_debug", "&TRACKINGKEY&", "inventory", "None", "CPUID generation tool not available for this platform, or not present yet. Skipping...");
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";
}
bundle agent turnUsersToUnicode
{
&if(NOVA)&
classes:
any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";
methods:
pass3.windows::
"any" usebundle => rudder_common_report("Inventory", "log_debug", "&TRACKINGKEY&", "inventory", "None", "This is a windows machine. User list has been converted to Unicode");
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&
}
# adding data to the inventory :
# UUID and CFKey in ,
# list of VM in
bundle agent addInformationsToInventory
{
vars:
# define CFKEY
windows.!cygwin::
"CFKEY_cmd" string => "${sys.winsysdir}\cmd.exe /c \"type \"${sys.workdir}\ppkeys\localhost.pub\"\"";
windows.cygwin::
"CFKEY_cmd" string => "/usr/bin/cat ${sys.workdir}/ppkeys/localhost.pub";
android::
"CFKEY_cmd" string => "/system/bin/cat ${sys.workdir}/ppkeys/localhost.pub";
!windows.!android::
"CFKEY_cmd" string => "/bin/cat ${sys.workdir}/ppkeys/localhost.pub";
any::
"CFKEY" string => execresult("${CFKEY_cmd}", "noshell");
# define USER
windows.!cygwin::
"USER" string => getenv("USERNAME", 40);
windows.cygwin::
"USER" string => execresult("/usr/bin/whoami", "noshell");
android::
"USER" string => execresult("/system/xbin/whoami", "noshell");
solaris::
"USER" string => execresult("/usr/bin/id | /usr/bin/cut -d\( -f2 | /usr/bin/cut -d\) -f1", "noshell");
!windows.!android.!solaris::
"USER" string => execresult("/usr/bin/whoami", "noshell");
# define RUDDERUUID
windows.!cygwin::
"RUDDERUUID" string => execresult("${sys.winsysdir}\cscript.exe /Nologo \"${g.rudder_tools}/uuid.vbs\"", "noshell");
windows.cygwin::
"RUDDERUUID" string => execresult("${sys.winsysdir}\cscript.exe /Nologo ${g.rudder_tools}/uuid.vbs", "noshell");
android::
"RUDDERUUID" string => execresult("/system/xbin/sqlite3 /data/data/com.android.providers.settings/databases/settings.db \"select value from secure where name = 'android_id'\"", "noshell");
aix::
"RUDDERUUID" string => execresult("/usr/bin/uname -f", "noshell");
solaris::
"RUDDERUUID" string => execresult("smbios | grep UUID | sed 's/ UUID: //'", "useshell");
freebsd::
"RUDDERUUID" string => execresult("/usr/local/sbin/dmidecode -s system-uuid", "noshell");
linux.!xen::
"RUDDERUUID" string => execresult("/usr/sbin/dmidecode -s system-uuid", "noshell");
linux.xen.xenrudderuuid:: # xenrudderuuid is defined at second pass
"RUDDERUUID" string => "${vmarray[1]}";
# all cases should have been covered, so no default
# define VMRUDDERUUID when we have xen
xen.SuSE.(xen_domu_pv|xen_domu_hv)::
"VMRUDDERUUID_cmd" string => "/bin/xenstore-read vm";
xen.((SuSE.xen_dom0)|centos|redhat)::
"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");
# define users
windows.!cygwin::
# 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) };
windows.cygwin::
"users" slist => { readstringlist("${inventory.UserListFile}","#.*","[\n| |\r]",10,4000) };
android::
"users" slist => {"root"};
!windows.!android::
"usersnumber" int => readstringarray("userslist","/etc/passwd","#[^\n]*",":",50,16000);
"users" slist => getindices("userslist");
# define specific variables
android::
"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.!armv6l.!armv7l)::
"RUDDERUUID_cmd" string => "/usr/sbin/dmidecode -s system-uuid";
aix::
"RUDDERUUID_cmd" string => "/usr/bin/uname -f";
solaris::
"RUDDERUUID" string => execresult("smbios | grep UUID | sed 's/ UUID: //'", "useshell");
freebsd::
"RUDDERUUID_cmd" string => "/usr/local/sbin/dmidecode -s system-uuid";
!windows.!android::
"CFKEY_cmd" string => "/bin/cat ${sys.workdir}/ppkeys/localhost.pub";
"usersnumber" int => readstringarray("userslist","/etc/passwd","#[^\n]*",":",50,16000);
"users" slist => getindices("userslist");
!windows.!android.!solaris::
"USER" string => execresult("/usr/bin/whoami", "noshell");
solaris::
"USER" string => execresult("id | cut -d\( -f2 | cut -d\) -f1", "useshell");
any::
"CFKEY" string => execresult("${CFKEY_cmd}", "noshell");
"USER" string => execresult("${USER_cmd}", "noshell");
rudder_server_roles_dir_exists::
# Roles of the system, fetch from the server_roles_path folder
# Don't extract file starting by . (especially . and .., but also hidden files)
"rudder_roles" slist => lsdir("${g.server_roles_path}", "^[^.].*", "false");
linux.(armv6l|armv7l)::
"ARMCPUINFO" string => readfile( "/proc/cpuinfo", "0" );
linux.(armv6l|armv7l).armv6lorv7lrudderuuid::
"RUDDERUUID" string => "${serialarray[1]}";
!xen.!armv6l.!armv7l::
"RUDDERUUID" string => execresult("${RUDDERUUID_cmd}", "noshell");
classes:
xen::
"xenrudderuuid" expression => regextract("/vm/(.*)", "${VMRUDDERUUID}", "vmarray");
linux.(armv6l|armv7l)::
"armv6lorv7lrudderuuid" expression => regextract("Serial[\s]+:[\s](.*)\N", "${ARMCPUINFO}", "serialarray");
any::
"uuiddefined" expression => isvariable("RUDDERUUID");
files:
uuiddefined::
"${fusionAgent.inventory_path_edition}"
edit_line => add_information_to_inventory(${RUDDERUUID}, ${CFKEY}, ${USER}, ${doInventory_always.policy_server_uuid}),
comment => "Adding basic informations to Rudder Inventory",
edit_defaults => def_no_backup_size("25M");
"${fusionAgent.inventory_path_edition}"
edit_line => add_users_information_to_inventory(@{addInformationsToInventory.users}),
comment => "Adding user informations to Rudder Inventory",
edit_defaults => def_no_backup_size("25M");
uuiddefined.rudder_server_roles_dir_exists::
"${fusionAgent.inventory_path_edition}"
edit_line => add_server_roles_information_to_inventory("@{addInformationsToInventory.rudder_roles}"),
comment => "Adding server roles informations to Rudder Inventory",
edit_defaults => def_no_backup_size("25M");
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_size("25M");
"${g.rudder_var_tmp}/inventory/.*.ocs"
edit_line => add_accesslog_to_android_inventory(${logdate}),
edit_defaults => def_no_backup_size("25M");
}
# Check that the inventory file is valid
bundle agent checkInventoryFile
{
vars:
"inventory_file" slist => findfiles("${g.rudder_var_tmp}/inventory/*.ocs");
"inventory_file_count" int => length("inventory_file");
!windows.has_rudder_perl::
"perl_command" string => "/opt/rudder/bin/perl -I /opt/rudder/lib/perl5";
!windows.!has_rudder_perl::
"perl_command" string => "/usr/bin/perl";
windows::
"perl_command" string => "C:\Program Files\FusionInventory-Agent\perl\bin\perl.exe";
classes:
# To check if inventory file is there, we need to count the file (filexists is not enough if inventory_file is an empty list))
"inventory_file_exist" expression => isgreaterthan("${inventory_file_count}", "0");
"has_rudder_perl" expression => fileexists("/opt/rudder/bin/perl");
pass1.inventory_file_exist.!windows::
"inventory_valid" expression => returnszero("${perl_command} ${this.promise_dirname}/test-inventory.pl ${inventory_file}", "noshell"),
scope => "namespace";
pass1.inventory_file_exist.windows::
"inventory_valid" expression => returnszero("\"${perl_command}\" \"${this.promise_dirname}/test-inventory.pl\" \"${inventory_file}\"", "noshell"),
scope => "namespace";
any::
"pass2" expression => "pass1";
"pass1" expression => "any";
methods:
pass2.inventory_file_exist.!inventory_valid::
"any" usebundle => rudder_common_report("Inventory", "result_error", "&TRACKINGKEY&", "inventory", "None", "Generated inventory has been detected as invalid");
reports:
pass2.inventory_file_exist.!inventory_valid::
# Print information to the user in addition to the reporting
"********************************************************************************
* WARNING Generated inventory is not valid, as it is missing mandatory fields. *
* Not sending it to the Rudder Server *
* You can get a full error message by running: ${perl_command} ${this.promise_dirname}/test-inventory.pl ${inventory_file}
********************************************************************************";
}
# 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 => by_name("@{g.inventory_file_types}"),
comment => "Moving inventory files to the final location";
}
# sign inventories
bundle agent signInventories
{
vars:
!windows::
# Keep "/opt/rudder/bin/signature.sh" as a fallback until we don't support agents < 4.0 anymore
"sign_script" string => ifelse(fileexists("${g.rudder_base}/bin/rudder-sign"), "${g.rudder_base}/bin/rudder-sign", "${g.rudder_base}/bin/signature.sh");
windows::
"sign_script" string => "C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe -ExecutionPolicy Bypass -File \"C:\Program Files\Rudder\sbin\signature.ps1\" -file";
classes:
"sign_script_exists" expression => fileexists("${sign_script}");
files:
!windows.sign_script_exists::
"${g.rudder_inventories}"
transformer => "${sign_script} \"${this.promiser}\"",
depth_search => recurse_visible(1),
file_select => by_name("@{g.uncompressed_inventory_file_types}"),
comment => "Signing inventory files";
}
# compress inventories if possible
bundle agent compressInventories
{
files:
!windows.gzip_installed::
"${g.rudder_inventories}"
transformer => "${g.gzip} -fq ${this.promiser}",
depth_search => recurse_visible(1),
file_select => by_name("@{g.uncompressed_inventory_file_types}"),
comment => "gzip inventory files";
}
# Send the file to the promises server
bundle agent sendInventory
{
vars:
&if(INITIAL)&
"download_endpoint" string => "${g.inventory_upload_protocol}://${server_info.cfserved}/inventories/";
&else&
"download_endpoint" string => "${g.inventory_upload_protocol}://${server_info.cfserved}/inventory-updates/";
&endif&
# If curl is available, use it
!windows.curl_installed.!inventory_proxy_defined::
"download_command_prefix" string => "${g.rudder_curl} -L -k -1 -f -s --proxy '' --user ${g.davuser}:${g.davpw} -T";
"download_command_suffix" string => "${download_endpoint}";
!windows.curl_installed.inventory_proxy_defined::
"download_command_prefix" string => "${g.rudder_curl} -L -k -1 -f -s --proxy '${node.properties[inventory_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} --no-verify --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} -L -k -1 -f -s --noproxy '${server_info.cfserved}' --user ${g.davuser}:${g.davpw} -T";
"download_command_suffix" string => "${download_endpoint}";
&endif&
classes:
any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";
files:
!windows::
"${g.rudder_inventories}"
transformer => "${download_command_prefix} ${this.promiser} ${download_command_suffix}",
depth_search => recurse_visible(1),
file_select => by_name("@{g.signed_inventory_file_types}"),
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 => by_name("@{g.signed_inventory_file_types}"),
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 => by_name("@{g.signed_inventory_file_types}"),
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_sent"
create => "true",
touch => "true",
comment => "Create local info about successful upload";
"${g.rudder_var_tmp}/inventory"
transformer => "${g.rudder_rm} -f ${this.promiser}",
depth_search => recurse_visible(1),
file_select => by_name("@{g.signed_inventory_file_types}"),
classes => if_else("inventory_file_deleted", "cant_delete_inventory_file"),
comment => "Cleaning up inventory files already sent to the server";
methods:
pass3.inventory_sent::
"any" usebundle => rudder_common_report("Inventory", "result_success", "&TRACKINGKEY&", "inventory", "None", "The inventory has been successfully sent");
pass3.cant_send_inventory::
"any" usebundle => rudder_common_report("Inventory", "result_error", "&TRACKINGKEY&", "inventory", "None", "Could not send the inventory");
pass3.cant_delete_inventory_file::
"any" usebundle => rudder_common_report("Inventory", "log_warn", "&TRACKINGKEY&", "inventory", "None", "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:
"${g.uuid}${const.n}${USER}${const.n}${const.n}${const.n}${RUDDERUUID}${const.n}${CFKEY}${const.n}${POLSRVUUID}${const.n}${const.n}${const.n}"
location => after_deviceid,
insert_type => "preserve_block",
comment => "Add the UUID and CFKEY tags in the inventory file";
any::
"${const.n}${const.n}${const.n}"
insert_type => "preserve_block",
location => after_content;
rudder_inventory_cpuid_tool_present.!aix::
"${inventory.CPUIDFile}"
insert_type => "file",
location => after_location(""),
comment => "Adding the CPUID data in the inventory file";
nova_edition::
"Nova"
location => after_location(""),
comment => "Adding the agent data in the inventory file";
community_edition::
"Community"
location => after_location(""),
comment => "Adding the agent data in the inventory file";
VirtualBoxInstalled::
"${virtualMachines.VBoxListFile}"
insert_type => "file",
location => after_location(""),
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::
"${const.n}${fullname}${const.n}${kernelname}${const.n}${kernelversion}${const.n}${name}${const.n}${version}${const.n}"
location => after_location(""),
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::
"${logdate}"
location => after_location(""),
comment => "Adding log date";
}
bundle edit_line add_users_information_to_inventory(userlist)
{
insert_lines:
(windows.rudder_inventory_userlist_tool_present)|!windows::
"${userlist}${const.n}" location => after_users,
comment => "Add the UUID and CFKEY tags in the inventory file";
}
bundle edit_line add_server_roles_information_to_inventory(server_roles)
{
insert_lines:
"${server_roles}"
location => after_location(""),
comment => "Adding server role to inventory";
}
#Locators
body location after_location(pos)
{
select_line_matching => ".*${pos}.*";
before_after => "after";
}
body location after_deviceid
{
select_line_matching => ".*.*";
before_after => "after";
}
body location after_content
{
select_line_matching => ".*.*";
before_after => "after";
}
body location after_vm
{
select_line_matching => ".*.*";
before_after => "after";
}
body location after_users
{
select_line_matching => ".*.*";
before_after => "after";
}
###############
# Editors
##############
# Convert a simple list in machine_namevalue
bundle edit_line xmlify(ATTR)
{
replace_patterns:
"\"(.*)\" \{(.*)\}"
replace_with=> xmled(${ATTR});
}
body replace_with xmled(attribute)
{
replace_value => "${match.1}${match.2}";
}
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
}