inventory/
The CFEngine 3 inventory modules are pieces of CFEngine policy that are loaded
and used by promises.cf
in order to inventory the system.
CFEngine Enterprise has specific functionality to show and use inventory data, but users of the Community Version can use them as well locally on each host.
How It Works
The inventory modules are called in promises.cf
:
body common control
{
bundlesequence => {
# Common bundle first (Best Practice)
inventory_control,
@(inventory.bundles),
...
As you see, this calls the inventory_control
bundle, and then each
bundle in the list inventory.bundles
. That list is built in the
top-level common inventory
bundle, which will load the right things
for some common cases. The any.cf
inventory module is always loaded;
the rest are loaded if they are appropriate for the platform. For
instance, Debian systems will load debian.cf
and linux.cf
and
lsb.cf
but may load others as needed.
The effect for users is that the right inventory modules will be loaded and evaluated.
The inventory_control
bundle lives in def.cf
and defines what
inventory modules should be disabled. You can simply set
disable_inventory
to avoid the whole system, or you can look for the
disable_inventory_xyz
class to disable module xyz
.
Any inventory module works the same way, by doing some discovery work
and then tagging its classes and variables with the report
or
inventory
tags. For example:
vars:
"ports" slist => { @(mon.listening_ports) },
meta => { "inventory", "attribute_name=Ports listening" };
This defines a reported attribute "Ports listening" which contains a list of strings representing the listening ports. More on this in a second.
Your Very Own Inventory Module
The good news is, writing an inventory module is incredibly easy.
They are just CFEngine bundles. You can see a simple one that collects
the listening ports in any.cf
:
bundle agent cfe_autorun_inventory_listening_ports
# @brief Inventory the listening ports
#
# This bundle uses `mon.listening_ports` and is always enabled by
# default, as it runs instantly and has no side effects.
{
vars:
"ports" slist => { @(mon.listening_ports) },
meta => { "inventory", "attribute_name=Ports listening" };
}
Well, the slist copy is a CFEngine detail (we get the listening ports from the
monitoring daemon), so just assume that the data is correct. What's important is
the second line that starts with meta
.
That defines metadata for the promise that CFEngine will use to determine that
this data is indeed inventory data and should be reported to the CFEngine
Enterprise Hub.
That's it. Really. The comments are optional but nice to have. You don't have to
put your new bundle in a file under the inventory
directory, either. The
variables and classes can be declared anywhere as long as they have the right
tags. So you can use the services
directory or whatever else makes sense to
you.
CFEngine Enterprise vs. Community
In CFEngine Enterprise, the reported data is aggregated in the hub and reported across the whole host population.
In CFEngine Community, users can use the classesmatching()
and
variablesmatching()
functions to collect all the inventory variables
and classes and report them in other ways.
Implementation Best Practice for CFEngine Enterprise
It is important that inventory variables and classes are continually defined. Only inventory variables and classes defined during the last reported run are available for use by the inventory reporting interface.
Inventory items that change frequently can create a burden on the Enterprise reporting infrastructure. Generally, inventory attributes should change infrequently.
If you wish to inventory attributes that frequently change or are expensive to discover consider implementing a sample interval and caching mechanism.
What Modules Are Available?
As soon as you use the promises.cf
provided in the parent directory,
quite a few inventory modules will be enabled (if appropriate for your
system). Here's the list of modules and what they provide. Note they
are all enabled by code in def.cf
as explained above.
Package Inventory
- lives in:
any.cf
- applies to: All systems
- runs: package modules in order to report on packages installed and patches available
- disable: define the class
disable_inventory_package_refresh
. Note this also disables the default package inventory used by the new packages promise implementation. This will cause thepackagesmatching()
andpackageupdatesmatching()
functions to rely on data supplied by the legacy package promise implementation.
LSB
- lives in:
lsb.cf
- applies to: LSB systems (most Linux distributions, basically)
- runs:
lsb_release -a
- sample data:
Distributor ID: Ubuntu
Description: Ubuntu 14.04 LTS
Release: 14.04
Codename: trusty
provides:
- classes
lsb_$(os)
,lsb_$(os)_$(release)
,lsb_$(os)_$(codename)
- variables:
inventory_lsb.os
(Distributor ID),inventory_lsb.codename
,inventory_lsb.release
,inventory_lsb.flavor
,inventory_lsb.description
- classes
sample output:
% cf-agent -KI -binventory_control,inventory_lsb
R: inventory_lsb: OS = Ubuntu, codename = trusty, release = 14.04, flavor = Ubuntu_14_04, description = Ubuntu 14.04 LTS
SUSE
- lives in:
suse.cf
- applies to: SUSE Linux
- provides classes:
suse_pure
andsuse_derived
Debian
- lives in:
debian.cf
- applies to: Debian and its derivatives
- provides:
- variables:
inventory_debian.mint_release
andinventory_debian.mint_codename
- classes:
debian_pure
,debian_derived
,linuxmint
,lmde
,linuxmint_$(mint_release)
,linuxmint_$(mint_codename)
,$(mint_codename)
- variables:
Red Hat
- lives in:
redhat.cf
- applies to: Red Hat and its derivatives
- provides classes:
redhat_pure
,redhat_derived
Windows
- lives in:
windows.cf
Mac OS X
- lives in:
macos.cf
Generic (unknown OS)
- lives in:
generic.cf
(seeany.cf
for generally applicable inventory modules)
LLDP
- lives in:
any.cf
- runs
inventory_control.lldpctl_exec
through a Perl filter - provides variables:
cfe_autorun_inventory_LLDP.K
for eachK
returned by the LLDB executable
mtab
- lives in:
any.cf
- parses:
/etc/mtab
provides classes:
have_mount_FSTYPE
andhave_mount_FSTYPE_MOUNTPOINT
sample output (note this is verbose mode with
-v
because there's a lot of output):
% cf-agent -Kv -binventory_control,cfe_autorun_inventory_mtab|grep 'cfe_autorun_inventory_mtab: we have'
R: cfe_autorun_inventory_mtab: we have a ext4 mount under /
...
R: cfe_autorun_inventory_mtab: we have a cgroup mount under /sys/fs/cgroup/systemd
R: cfe_autorun_inventory_mtab: we have a tmpfs mount under /run/shm
fstab
- lives in:
any.cf
- parses:
sys.fstab
provides classes:
have_fs_FSTYPE
have_fs_MOUNTPOINT
andhave_fs_FSTYPE_MOUNTPOINT
sample output (note this is verbose mode with
-v
because there's a LOT of output):
% cf-agent -Kv -binventory_control,cfe_autorun_inventory_fstab|grep 'cfe_autorun_inventory_fstab: we have'
R: cfe_autorun_inventory_fstab: we have a ext4 fstab entry under /
R: cfe_autorun_inventory_fstab: we have a cifs fstab entry under /backups/load
R: cfe_autorun_inventory_fstab: we have a auto fstab entry under /mnt/cdrom
CMDB
- lives in:
any.cf
- parses:
me.json
(which is copied from the policy server; see implementation) - provides classes:
CLASS
for each CLASS found under theclasses
key in the JSON data - provides variables:
inventory_cmdb_load.VARNAME
for each VARNAME found under thevars
key in the JSON data
DMI decoding
- lives in:
any.cf
- runs:
dmidecode
provides variables:
cfe_autorun_inventory_dmidecode.dmi[K]
for each key K in thedmidecode
outputsample output (sudo is needed to access the DMI):
% sudo /var/cfengine/bin/cf-agent -KI -binventory_control,cfe_autorun_inventory_dmidecode
R: cfe_autorun_inventory_dmidecode: Obtained BIOS vendor = 'Intel Corp.'
R: cfe_autorun_inventory_dmidecode: Obtained BIOS version = 'BLH6710H.86A.0146.2013.1555.1888'
R: cfe_autorun_inventory_dmidecode: Obtained System serial number = ''
R: cfe_autorun_inventory_dmidecode: Obtained System manufacturer = ''
R: cfe_autorun_inventory_dmidecode: Obtained System version = ''
R: cfe_autorun_inventory_dmidecode: Obtained CPU model = 'Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz'
Listening ports
- lives in:
any.cf
- provides variables:
cfe_autorun_inventory_listening_ports.ports
as a copy ofmon.listening_ports
Disk space
- lives in:
any.cf
- provides variables:
cfe_autorun_inventory_disk.free
as a copy ofmon.value_diskfree
Available memory
- lives in:
any.cf
- provides variables:
cfe_autorun_inventory_memory.free
as a copy ofmon.value_mem_free
andcfe_autorun_inventory_memory.total
as a copy ofmon.value_mem_total
Load average
- lives in:
any.cf
- provides variables:
cfe_autorun_inventory_loadaverage.value
as a copy ofmon.value_loadavg
procfs
- lives in:
any.cf
- parses:
consoles
,cpuinfo
,modules
,partitions
,version
- provides variables:
cfe_autorun_inventory_proc.console_count
,cfe_autorun_inventory_proc.cpuinfo[K]
for each CPU info key,cfe_autorun_inventory_proc.paritions[K]
for each partition key provides classes:
_have_console_CONSOLENAME
,have_module_MODULENAME
sample output (note this is verbose mode with
-v
because there's a LOT of output):
% cf-agent -Kv -binventory_control,cfe_autorun_inventory_proc|grep 'cfe_autorun_inventory_proc: we have'
R: cfe_autorun_inventory_proc: we have console tty0
R: cfe_autorun_inventory_proc: we have module snd_seq_midi
...
R: cfe_autorun_inventory_proc: we have module ghash_clmulni_intel
R: cfe_autorun_inventory_proc: we have cpuinfo flags = fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx lahf_lm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid
...
R: cfe_autorun_inventory_proc: we have cpuinfo model name = Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz
R: cfe_autorun_inventory_proc: we have partitions sr0 with 1048575 blocks
...
R: cfe_autorun_inventory_proc: we have partitions sda with 468851544 blocks
R: cfe_autorun_inventory_proc: we have kernel version 'Linux version 3.11.0-15-generic (buildd@roseapple) (gcc version 4.8.1 (Ubuntu/Linaro 4.8.1-10ubuntu8) ) #25-Ubuntu SMP Thu Jan 30 17:22:01 UTC 2014'