1bundle common inventory_any 2# @brief Do inventory for any OS 3# 4# This common bundle is for any OS work not handled by specific 5# bundles. 6{ 7 8 vars: 9 "release_data" string => "$(this.promise_dirname)/../cf_promises_release_id"; 10 11 "data" 12 data => readjson( $(release_data), inf ), 13 if => fileexists( $(release_data) ); 14 15 "id" 16 string => "$(data[releaseId])", 17 meta => { "inventory", "attribute_name=Policy Release Id" }; 18 19 reports: 20 "DEBUG|DEBUG_$(this.bundle)":: 21 "DEBUG $(this.bundle): Inventory Policy Release Id=$(id)"; 22} 23 24bundle agent inventory_autorun 25# @brief Autorun some inventory bundles 26# 27# This agent bundle runs other "autorun" inventory agent bundles 28# explicitly. It will use bundlesmatching() when CFEngine 3.5 and 29# earlier are no longer supported. 30{ 31 methods: 32 !disable_inventory_cmdb:: 33 "cmdb" usebundle => cfe_autorun_inventory_cmdb(), 34 handle => "cfe_internal_autorun_inventory_cmdb"; 35 36 !disable_inventory_LLDP:: 37 "LLDP" usebundle => cfe_autorun_inventory_LLDP(), 38 handle => "cfe_internal_autorun_inventory_LLDP"; 39 40 !disable_inventory_package_refresh:: 41 "packages_refresh" usebundle => cfe_autorun_inventory_packages(), 42 handle => "cfe_internal_autorun_inventory_packages"; 43 44 !disable_inventory_proc:: 45 "proc" usebundle => cfe_autorun_inventory_proc(), 46 handle => "cfe_internal_autorun_inventory_proc"; 47 48 "proc_cpuinfo" usebundle => cfe_autorun_inventory_proc_cpuinfo(), 49 handle => "cfe_internal_autorun_inventory_proc_cpuinfo"; 50 51 !disable_inventory_cpuinfo:: 52 "cpuinfo" usebundle => cfe_autorun_inventory_cpuinfo(), 53 handle => "cfe_internal_autorun_inventory_cpuinfo"; 54 55 !disable_inventory_fstab:: 56 "fstab" usebundle => cfe_autorun_inventory_fstab(), 57 handle => "cfe_internal_autorun_inventory_fstab"; 58 59 !disable_inventory_mtab:: 60 "mtab" usebundle => cfe_autorun_inventory_mtab(), 61 handle => "cfe_internal_autorun_inventory_mtab"; 62 63 !disable_inventory_dmidecode:: 64 "dmidecode" usebundle => cfe_autorun_inventory_dmidecode(), 65 handle => "cfe_internal_autorun_inventory_dmidecode"; 66 67 !disable_inventory_aws:: 68 "aws" usebundle => cfe_autorun_inventory_aws(), 69 handle => "cfe_internal_autorun_inventory_aws"; 70 71 !disable_inventory_aws|disable_inventory_aws_ec2_metadata:: 72 "aws" usebundle => cfe_autorun_inventory_aws_ec2_metadata(), 73 handle => "cfe_internal_autorun_inventory_ec2_metadata"; 74 75 !disable_inventory_setuid:: 76 "Inventory SetUID Files" -> { "ENT-4158" } 77 usebundle => cfe_autorun_inventory_setuid(), 78 handle => "cfe_internal_autorun_inventory_setuid"; 79 80 any:: 81 "listening ports" usebundle => cfe_autorun_inventory_listening_ports(), 82 handle => "cfe_internal_autorun_listening_ports"; 83 84 "disk" usebundle => cfe_autorun_inventory_disk(), 85 handle => "cfe_internal_autorun_disk"; 86 87 "memory" usebundle => cfe_autorun_inventory_memory(), 88 handle => "cfe_internal_autorun_memory"; 89 90 "loadaverage" usebundle => cfe_autorun_inventory_loadaverage(), 91 handle => "cfe_internal_autorun_loadaverage"; 92 93 "IP addresses" -> { "ENT-2552", "ENT-4987" } 94 usebundle => cfe_autorun_inventory_ip_addresses, 95 handle => "cfe_internal_autorun_ip_addresses"; 96} 97 98bundle agent cfe_autorun_inventory_listening_ports 99# @brief Inventory the listening ports 100# 101# This bundle uses `mon.listening_ports` and is always enabled by 102# default, as it runs instantly and has no side effects. 103{ 104 vars: 105 "ports" -> { "ENT-150" } 106 slist => sort( "mon.listening_ports", "int"), 107 meta => { "inventory", "attribute_name=Ports listening" }, 108 ifvarclass => some("[0-9]+", "mon.listening_ports"), 109 comment => "We only want to inventory the listening ports if we have 110 values that make sense."; 111} 112 113bundle agent cfe_autorun_inventory_ip_addresses 114# @brief Inventory ipv4 addresses 115# This will filter the ipv4 and ipv4 loopback address (127.0.0.1, ::as it is likely not very interesting) 116{ 117 vars: 118 "ipv4_regex" -> { "ENT-4987" } 119 string => "\b(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b"; 120 121 "ipv4_loopback_regex" -> { "ENT-2552" } 122 string => "127\.0\.0\.1", 123 comment => "Addresses that match this regular expression will be filtered 124 from the inventory for ipv4 addresses"; 125 126 "ipv6_loopback_regex" -> { "ENT-4987" } 127 string => "::1", 128 comment => "Addresses that match this regular expression will be filtered 129 from the inventory for ipv4 addresses"; 130 131 # Strings are displayed more beautifully in Mission Portal than lists, so 132 # we first generate the list of addresses to be inventoried and then do 133 # inventory using an array. 134 "ipv4_addresses" 135 slist => sort( filter( $(ipv4_regex), "sys.ip_addresses", "true", "false", inf), lex ), 136 if => not( isvariable( $(this.promiser) )); 137 138 "ipv4_addresses_non_loopback" -> { "ENT-2552" } 139 slist => sort( filter( $(ipv4_loopback_regex), "$(this.bundle).ipv4_addresses", "true", "true", inf)), 140 if => not( isvariable( $(this.promiser) )); 141 142 "ipv4[$(ipv4_addresses_non_loopback)]" -> { "ENT-2552" } 143 string => "$(ipv4_addresses_non_loopback)", 144 meta => { "inventory", "attribute_name=IPv4 addresses" }; 145 146 # sys.ip_addresses contains ipv4 and (as of 3.15.0) ipv6 addresses. We get 147 # the ipv6 addresses indirectly, based on excluding the ipv4 addresses 148 # (which we identify using a regular expression) 149 150 "ipv6_addresses" -> { "ENT-4987" } 151 slist => sort( difference( "sys.ip_addresses", "$(this.bundle).ipv4_addresses" ), lex), 152 if => not( isvariable( $(this.promiser) )); 153 154 "ipv4_addresses_non_loopback" -> { "ENT-4987" } 155 slist => sort( filter( $(ipv6_loopback_regex), "$(this.bundle).ipv4_addresses", "true", "true", inf)), 156 if => not( isvariable( $(this.promiser) )); 157 158 "ipv6[$(ipv6_addresses_non_loopback)]" -> { "ENT-4987" } 159 string => "$(ipv6_addresses_non_loopback)", 160 meta => { "inventory", "attribute_name=IPv6 addresses" }; 161 162 reports: 163 DEBUG|DEBUG_cfe_autorun_inventory_ipv4_addresses:: 164 "DEBUG $(this.bundle)"; 165 "$(const.t)Inventorying: '$(ipv4_addresses)'"; 166 "$(const.t)Inventorying: '$(ipv6_addresses)'"; 167} 168 169bundle agent cfe_autorun_inventory_disk 170# @brief Inventory the disk (Enterprise only) 171{ 172 vars: 173 enterprise:: 174 "free" -> { "ENT-5190" } 175 string => "$(mon.value_diskfree)", 176 meta => { "inventory", "attribute_name=Disk free (%)" }, 177 if => isvariable( "mon.value_diskfree" ); 178} 179 180bundle agent cfe_autorun_inventory_memory 181# @brief Inventory the memory (Enterprise only) 182{ 183 vars: 184@if minimum_version(3.11) 185 # The `with` attribute is necessary for this to work in a single promise. 186 187 enterprise_edition.windows:: 188 189 # wmic returns "TotalVisibleMemorySize=10760224" so split on = and take 190 # the second item (0-based with nth()) 191 192 "total" -> { "ENT-4188" } 193 meta => { "inventory", "attribute_name=Memory size (MB)" }, 194 string => format( "%d", eval("$(with)/1024", "math", "infix" )), 195 if => not( isvariable( "total" ) ), 196 with => nth( string_split( execresult("wmic OS get TotalVisibleMemorySize /format:list", useshell ), 197 "=", 2), 1); 198 199 "totalPhysical" -> { "CFE-2896" } 200 meta => { "inventory", "attribute_name=Physical memory (MB)" }, 201 string => format( "%d", eval("$(with)/1024", "math", "infix" )), 202 if => not( isvariable( "total" ) ), 203 with => nth( string_split( execresult("wmic ComputerSystem get TotalPhysicalMemory /format:list", useshell ), 204 "=", 2), 1); 205 206 # This is a volatile metric, perhaps not well suited for inventory 207 "free" 208 meta => { "report" }, 209 string => format( "%d", eval("$(with)/1024", "math", "infix" )), 210 if => not( isvariable( "free" ) ), 211 with => nth( string_split( execresult("wmic OS get FreePhysicalMemory /format:list", useshell ), 212 "=", 2), 1); 213@endif 214 enterprise_edition.aix:: 215 "total" -> { "CFE-2797", "CFE-2803" } 216 string => execresult("/usr/bin/lparstat -i | awk '/Online Memory/ { print $4 }'", "useshell"), 217 meta => { "inventory", "attribute_name=Memory size (MB)" }; 218 219 enterprise_edition.hpux:: 220 "total" -> { "ENT-4188" } 221 string => execresult( "machinfo | awk '/^Memory =/ {print $3}'", useshell ), 222 meta => { "inventory", "attribute_name=Memory size (MB)" }; 223 224 enterprise_edition.!(aix|windows|hpux):: 225 "total" string => "$(mon.value_mem_total)", 226 meta => { "inventory", "attribute_name=Memory size (MB)" }, 227 if => isvariable( "mon.value_mem_total" ); 228 229 "free" string => "$(mon.value_mem_free)", 230 if => and( not( isvariable( "free" ) ), 231 isvariable( "mon.value_mem_free" )), 232 meta => { "report" }; 233 234} 235 236bundle agent cfe_autorun_inventory_setuid 237# @brief Inventory setuid files and prune invalid entries from the setuid log 238{ 239 vars: 240 !disable_inventory_setuid:: 241 "candidates" slist => lsdir( "$(sys.workdir)", "cfagent\..*\.log", true ); 242 243 "setuid_log_path" 244 comment => "We select the file that matches the downcased version of the 245 hostname since sys.fqhost always returns lower case", 246 string => "$(candidates)", 247 if => strcmp( "$(sys.workdir)/cfagent.$(sys.fqhost).log", 248 string_downcase($(candidates))); 249 250 "files" slist => readstringlist( $(setuid_log_path), "", "$(const.n)", inf, inf); 251 252 "setuid[$(files)]" 253 string => "$(files)", 254 meta => { "inventory", "attribute_name=Setuid files" }, 255 if => regcmp( "104\d+", filestat( $(files), modeoct ) ); 256 257 "rootsetuid[$(files)]" 258 string => "$(files)", 259 meta => { "inventory", "attribute_name=Root owned setuid files" }, 260 if => and( regcmp( "104\d+", filestat( $(files), modeoct ) ), 261 regcmp( "0", filestat( $(files), uid ) )); 262 263 files: 264 !disable_inventory_setuid:: 265 "$(setuid_log_path)" 266 comment => "If the logged file is not currently setuid then we can 267 safely purge it from the list to avoid unnecessary work.", 268 edit_line => delete_lines_matching( escape( $(files) ) ), 269 if => not( regcmp( "104\d+", filestat( $(files), modeoct ) ) ); 270 271 reports: 272 !disable_inventory_setuid.(DEBUG|DEBUG_cfe_autorun_inventory_setuid):: 273 "$(setuid_log_path) present" 274 if => fileexists( $(setuid_log_path) ); 275 276@if minimum_version(3.11) 277 278 "Candidate: setuid Files: $(files) modeoct=$(with)" 279 with => filestat( $(files), modeoct ); 280 281 "Remove $(files) from log by matching $(with)" 282 comment => "If the logged file is not currently setuid then we can 283 safely purge it from the list to avoid unnecessary work.", 284 with => escape( $(files) ), 285 if => not( regcmp( "104\d+", filestat( $(files), modeoct ) ) ); 286 287 # The `with` attribute was introduced in 3.11 288 "Inventory: setuid Files: $(files) modeoct=$(with)" 289 with => filestat( $(files), modeoct ), 290 if => regcmp( "104\d+", filestat( $(files), modeoct ) ); 291 292 "Inventory: root owned setuid Files: $(files) modeoct=$(with)" 293 with => filestat( $(files), modeoct ), 294 if => and( regcmp( "104\d+", filestat( $(files), modeoct ) ), 295 regcmp( "0", filestat( $(files), uid ) )); 296@endif 297 298} 299 300bundle agent cfe_autorun_inventory_loadaverage 301# @brief Inventory the loadaverage (Enterprise only) 302{ 303 vars: 304 enterprise:: 305 "value" -> { "ENT-5190" } 306 string => "$(mon.value_loadavg)", 307 meta => { "report" }, 308 if => isvariable( "mon.value_loadavg" ); 309} 310 311bundle agent cfe_autorun_inventory_proc 312# @brief Do procfs inventory 313# 314# This bundle will parse these /proc files: consoles, cpuinfo, 315# meminfo, modules, partitions, version, vmstat. There are 316# some general patterns you can follow to extend it for other /proc 317# items of interest. 318# 319# Contributions welcome. /proc/net and /proc/sys in general are of 320# wide interest, if you're looking for something fun. For instance, 321# the network interfaces could be extracted here without calling 322# `ifconfig`. 323{ 324 vars: 325 "basefiles" slist => { "consoles", "cpuinfo", "modules", "partitions", "version" }; 326 "files[$(basefiles)]" string => "$(inventory_control.proc)/$(basefiles)"; 327 328 _have_proc_consoles:: 329 "console_count" int => readstringarrayidx("consoles", 330 "$(files[consoles])", 331 "\s*#[^\n]*", 332 "\s+", 333 500, 334 50000); 335 336 "console_idx" slist => getindices("consoles"); 337 338 _have_proc_modules:: 339 "module_count" int => readstringarrayidx("modules", 340 "$(files[modules])", 341 "\s*#[^\n]*", 342 "\s+", 343 2500, 344 250000); 345 346 "module_idx" slist => getindices("modules"); 347 348 _have_proc_cpuinfo:: 349 # this will extract all the keys in one bunch, so you won't get 350 # detailed info for processor 0 for example 351 "cpuinfo_count" int => readstringarrayidx("cpuinfo_array", 352 "$(files[cpuinfo])", 353 "\s*#[^\n]*", 354 "\s*:\s*", 355 500, 356 50000); 357 358 "cpuinfo_idx" slist => getindices("cpuinfo_array"); 359 "cpuinfo[$(cpuinfo_array[$(cpuinfo_idx)][0])]" string => "$(cpuinfo_array[$(cpuinfo_idx)][1])"; 360 "cpuinfo_keys" slist => getindices("cpuinfo"); 361 362 _have_proc_partitions:: 363 "partitions_count" int => readstringarrayidx("partitions_array", 364 "$(files[partitions])", 365 "major[^\n]*", 366 "\s+", 367 500, 368 50000); 369 370 "partitions_idx" slist => getindices("partitions_array"); 371 "partitions[$(partitions_array[$(partitions_idx)][4])]" string => "$(partitions_array[$(partitions_idx)][3])"; 372 "partitions_keys" slist => getindices("partitions"); 373 374 _have_proc_version:: 375 "version" string => readfile("$(files[version])", 2048); 376 377 classes: 378 "have_proc" expression => isdir($(inventory_control.proc)); 379 380 have_proc:: 381 "_have_proc_$(basefiles)" 382 expression => fileexists("$(files[$(basefiles)])"); 383 384 _have_proc_consoles:: 385 "have_console_$(consoles[$(console_idx)][0])" 386 expression => "any", 387 scope => "namespace"; 388 389 _have_proc_modules:: 390 "have_module_$(modules[$(module_idx)][0])" 391 expression => "any", 392 scope => "namespace"; 393 394 reports: 395 _have_proc_consoles.verbose_mode:: 396 "$(this.bundle): we have console $(consoles[$(console_idx)][0])"; 397 _have_proc_modules.verbose_mode:: 398 "$(this.bundle): we have module $(modules[$(module_idx)][0])"; 399 _have_proc_cpuinfo.verbose_mode:: 400 "$(this.bundle): we have cpuinfo $(cpuinfo_keys) = $(cpuinfo[$(cpuinfo_keys)])"; 401 _have_proc_partitions.verbose_mode:: 402 "$(this.bundle): we have partitions $(partitions_keys) with $(partitions[$(partitions_keys)]) blocks"; 403 _have_proc_version.verbose_mode:: 404 "$(this.bundle): we have kernel version '$(version)'"; 405} 406 407bundle agent cfe_autorun_inventory_proc_cpuinfo 408# @brief Inventory cpu information from proc 409{ 410 classes: 411 "_have_cpuinfo" expression => isvariable("default:cfe_autorun_inventory_proc.cpuinfo_idx"); 412 413 # So that we don't inventory non dereferenced variables we check to see 414 # if we have the info first This is only necessary because its currently 415 # invalid to do isvariable on an array key that contains a space 416 # Ref: redmine#7088 https://dev.cfengine.com/issues/7088 417 "have_cpuinfo_cpu_cores" expression => strcmp("cpu cores", "$(default:cfe_autorun_inventory_proc.cpuinfo_array[$(default:cfe_autorun_inventory_proc.cpuinfo_idx)][0])"); 418 "have_cpuinfo_model_name" expression => strcmp("model name", "$(default:cfe_autorun_inventory_proc.cpuinfo_array[$(default:cfe_autorun_inventory_proc.cpuinfo_idx)][0])"); 419 420 vars: 421 _have_cpuinfo:: 422 "cpuinfo_physical_cores" 423 string => "$(default:cfe_autorun_inventory_proc.cpuinfo[cpu cores])", 424 ifvarclass => "have_cpuinfo_cpu_cores"; 425 426 "cpuinfo_cpu_model_name" 427 string => "$(default:cfe_autorun_inventory_proc.cpuinfo[model name])", 428 ifvarclass => "have_cpuinfo_model_name"; 429 430 # We need to be able to count the number of unique physical id lines in 431 # /proc/cpu in order to get a physical processor count. 432 "cpuinfo_lines" slist => readstringlist( 433 "$(default:cfe_autorun_inventory_proc.files[cpuinfo])", 434 "\s*#[^\n]*", 435 "\n", 436 500, 437 50000); 438 439 "cpuinfo_processor_lines" 440 slist => grep("processor\s+:\s\d+", "cpuinfo_lines"), 441 comment => "The number of processor entries in $(default:cfe_autorun_inventory_proc.files[cpuinfo]). If no 442 'physical id' entries are found this is the processor count"; 443 444 "cpuinfo_processor_lines_count" 445 int => length("cpuinfo_processor_lines"); 446 447 "cpuinfo_physical_id_lines" 448 slist => grep("physical id.*", "cpuinfo_lines"), 449 comment => "This identifies which physical socket a logical core is on, 450 the count of the unique physical id lines tells you how 451 many physical sockets you have. THis would not be present 452 on systems that are not multicore."; 453 454 "cpuinfo_physical_id_lines_unique" 455 slist => unique("cpuinfo_physical_id_lines"); 456 457 "cpuinfo_physical_id_lines_unique_count" 458 int => length("cpuinfo_physical_id_lines_unique"); 459 460 461 # If we have physical id lines in cpu info use that for socket inventory, 462 # else we should use the number of processor lines. physical id lines 463 # seem to only be present when multiple cores are active. 464 "cpuinfo_physical_socket_inventory" 465 string => ifelse(isgreaterthan( length("cpuinfo_physical_id_lines"), 0 ), "$(cpuinfo_physical_id_lines_unique_count)", 466 "$(cpuinfo_processor_lines_count)"), 467 meta => { "inventory", "attribute_name=CPU sockets" }; 468 469 reports: 470 DEBUG|DEBUG_cfe_autorun_inventory_proc:: 471 "DEBUG $(this.bundle)"; 472 "$(const.t)cpuinfo[$(default:cfe_autorun_inventory_proc.cpuinfo_array[$(default:cfe_autorun_inventory_proc.cpuinfo_idx)][0])] = $(default:cfe_autorun_inventory_proc.cpuinfo[$(default:cfe_autorun_inventory_proc.cpuinfo_array[$(default:cfe_autorun_inventory_proc.cpuinfo_idx)][0])])"; 473 "$(const.t)CPU physical cores: '$(cpuinfo_physical_cores)'" 474 ifvarclass => "have_cpuinfo_cpu_cores"; 475 "$(const.t)CPU model name: '$(cpuinfo_cpu_model_name)'" 476 ifvarclass => "have_cpuinfo_model_name"; 477 "$(const.t)CPU Physical Sockets: '$(cpuinfo_physical_socket_inventory)'"; 478} 479 480bundle agent cfe_autorun_inventory_cpuinfo 481# @brief Inventory cpu information 482{ 483 classes: 484 "_have_proc_cpu_model_name" expression => isvariable("default:cfe_autorun_inventory_proc_cpuinfo.cpuinfo_cpu_model_name"); 485 "_have_proc_cpu_physical_cores" expression => isvariable("default:cfe_autorun_inventory_proc_cpuinfo.cpuinfo_physical_cores"); 486 487 # We only accept dmidecode values that don't look like cfengine variables, 488 # (starting with dollar), or that have an apparent empty value. 489 "_have_dmidecode_cpu_model_name" 490 not => regcmp("($(const.dollar)\(.*\)|^$)", "$(default:cfe_autorun_inventory_dmidecode.dmi[processor-version])"); 491 492 vars: 493 _have_proc_cpu_physical_cores:: 494 "cpuinfo_physical_cores" 495 string => "$(default:cfe_autorun_inventory_proc.cpuinfo[cpu cores])", 496 #ifvarclass => "have_cpuinfo_cpu_cores", 497 meta => { "inventory", "attribute_name=CPU physical cores", "derived-from=$(default:cfe_autorun_inventory_proc.files[cpuinfo])" }; 498 499 _have_proc_cpu_model_name:: 500 "cpu_model" 501 string => "$(default:cfe_autorun_inventory_proc_cpuinfo.cpuinfo_cpu_model_name)", 502 meta => { "inventory", "attribute_name=CPU model", "derived-from=$(default:cfe_autorun_inventory_proc.files[cpuinfo])" }; 503 504 _have_dmidecode_cpu_model_name.!_have_proc_cpu_model_name:: 505 "cpu_model" 506 string => "$(default:cfe_autorun_inventory_dmidecode.dmi[processor-version])", 507 meta => { "inventory", "attribute_name=CPU model", "derived-from=$(inventory_control.dmidecoder) -s processor-version" }; 508 509 reports: 510 DEBUG|DEBUG_cfe_autorun_inventory_cpuinfo:: 511 "DEBUG $(this.bundle)"; 512 "$(const.t) CPU model: $(cpu_model)"; 513 "$(const.t) CPU physical cores: $(cpuinfo_physical_cores)"; 514} 515 516bundle common cfe_autorun_inventory_aws 517# @brief inventory AWS EC2 instances 518# 519# Provides: 520# ec2_instance class based on Amazon markers in dmidecode's system-uuid, bios-version or bios-vendor 521{ 522 classes: 523 !disable_inventory_aws:: 524 "ec2_instance" -> { "CFE-2924" } 525 comment => "See http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/identify_ec2_instances.html", 526 scope => "namespace", 527 expression => regcmp("^[eE][cC]2.*", "$(cfe_autorun_inventory_dmidecode.dmi[system-uuid])"), 528 if => isvariable("cfe_autorun_inventory_dmidecode.dmi[system-uuid]"); 529 530 "ec2_instance" -> { "CFE-2924" } 531 expression => regcmp(".*[aA]mazon.*", "$(cfe_autorun_inventory_dmidecode.dmi[bios-version])"), 532 scope => "namespace", 533 if => isvariable("cfe_autorun_inventory_dmidecode.dmi[bios-version]"); 534 535 "ec2_instance" -> { "CFE-2924" } 536 expression => regcmp(".*[aA]mazon.*", "$(cfe_autorun_inventory_dmidecode.dmi[bios-vendor])"), 537 scope => "namespace", 538 if => isvariable("cfe_autorun_inventory_dmidecode.dmi[bios-vendor]"); 539 540 "ec2_instance" -> { "CFE-2924" } 541 expression => regline( "^ec2.*", "/sys/hypervisor/uuid" ), 542 scope => "namespace", 543 if => fileexists("/sys/hypervisor/uuid"); 544 545 reports: 546 (DEBUG|DEBUG_inventory_aws):: 547 "DEBUG $(this.bundle)"; 548 549 "$(const.t)+ec2_instance" 550 if => "ec2_instance"; 551} 552 553bundle agent cfe_autorun_inventory_aws_ec2_metadata 554# @brief Inventory ec2 metadata 555# Provides: 556{ 557 methods: 558 !(disable_inventory_aws|disable_inventory_aws_ec2_metadata):: 559 "cfe_autorun_inventory_aws_ec2_metadata_cache"; 560 "cfe_aws_ec2_metadata_from_cache"; 561} 562bundle agent cfe_autorun_inventory_aws_ec2_metadata_cache 563# @brief Cache ec2 metadata from http request 564# 565# Provides cache of ec2 instance metadata for inventory 566{ 567 568 vars: 569 ec2_instance.!(disable_inventory_aws|disable_inventory_aws_ec2_metadata):: 570 "URL" string => "http://169.254.169.254/latest/dynamic/instance-identity/document"; 571 "cache" string => "$(sys.statedir)/aws_ec2_metadata"; 572 573 "v" -> { "ENT-5233" } 574 string => ifelse( isgreaterthan( $(sys.cf_version_minor), 14), "suppress_inform_capable", 575 "suppress_inform_incapable"); 576 577 "response" -> { "ENT-4900" } 578 data => url_get($(URL), '{"url.max_content": 512000, "url.timeout": 1}'), 579 # To prevent `url_get` from firing on every agent run, this variable 580 # depends on a dummy command which does nothing but fires only once a day 581 depends_on => { "daily_dummy_job_$(v)" }; 582 583 commands: 584 _stdlib_path_exists_true:: 585 586 "$(paths.true)" 587 comment => "This promise is used for delaying execution of url_get, since locking does not work directly on vars type promises", 588 classes => kept_successful_command, 589 handle => "daily_dummy_job_suppress_inform_incapable", 590 action => if_elapsed_day, 591 if => strcmp( "daily_dummy_job_$(v)", "daily_dummy_job_suppress_inform_incapable" ); 592 593@if minimum_version(3.15.0) 594 "$(paths.true)" 595 comment => "This promise is used for delaying execution of url_get, since locking does not work directly on vars type promises", 596 classes => kept_successful_command, 597 handle => "daily_dummy_job_suppress_inform_capable", 598 inform => "false", 599 action => if_elapsed_day; 600@endif 601 602 files: 603 ec2_instance.!(disable_inventory_aws|disable_inventory_aws_ec2_metadata):: 604 605 cfengine_3_10:: 606 "$(cache)" 607 create => "true", 608 edit_line => lines_present( "$(response[content])" ), 609 edit_defaults => empty, 610 if => isvariable( response ); 611 612@if minimum_version(3.11) 613 # template_method inline_mustache introduced in 3.11 614 !cfengine_3_10:: 615 "$(cache)" 616 template_method => "inline_mustache", 617 edit_template_string => "{{{content}}}", 618 template_data => @(response), 619 create => "true", 620 if => isvariable( response ); 621@endif 622} 623 624bundle agent cfe_aws_ec2_metadata_from_cache 625# @brief Inventory ec2 metadata from cache 626# 627# Provides inventory for EC2 Region, EC2 Instance ID, EC2 Instance Type, EC2 628# Image ID, and EC2 Availability Zone 629{ 630 classes: 631 632 ec2_instance.!(disable_inventory_aws|disable_inventory_aws_ec2_metadata):: 633 634 "have_cached_instance_identity" 635 expression => fileexists( $(cfe_autorun_inventory_aws_ec2_metadata_cache.cache) ); 636 637 vars: 638 639 have_cached_instance_identity.ec2_instance.!(disable_inventory_aws|disable_inventory_aws_ec2_metadata):: 640 641 "data" data => readjson( $(cfe_autorun_inventory_aws_ec2_metadata_cache.cache), 100K); 642 643 "region" string => "$(data[region])", meta => { "inventory", "attribute_name=EC2 Region" }; 644 "instanceId" string => "$(data[instanceId])", meta => { "inventory", "attribute_name=EC2 Instance ID" }; 645 "instanceType" string => "$(data[instanceType])", meta => { "inventory", "attribute_name=EC2 Instance Type" }; 646 "imageId" string => "$(data[imageId])", meta => { "inventory", "attribute_name=EC2 Image ID" }; 647 "availabilityZone" string => "$(data[availabilityZone])", meta => { "inventory", "attribute_name=EC2 Availability Zone" }; 648 649 reports: 650 651 DEBUG|DEBUG_inventory_ec2_metadata|DEBUG_inventory_ec2_metadata_from_cache:: 652 "DEBUG $(this.bundle):"; 653 "$(const.t)Inventory 'EC2 Region' = '$(region)'"; 654 "$(const.t)Inventory 'EC2 Instance ID' = '$(instanceId)'"; 655 "$(const.t)Inventory 'EC2 Instance Type' = '$(instanceType)'"; 656 "$(const.t)Inventory 'EC2 Image ID' = '$(imageId)'"; 657 "$(const.t)Inventory 'EC2 Availability Zone' = '$(availabilityZone)'"; 658} 659 660bundle agent cfe_autorun_inventory_mtab 661# @brief Do mtab inventory 662# 663# The mtab format is simple: each line looks like this format: 664# `/dev/sda1 / ext4 rw,noatime,data=ordered 0 0` (in order: `DEV 665# MOUNTPOINT FSTYPE OPTIONS DUMP-FREQ PASS`). Some older Unices have 666# a different format and it's really not portable, so enable this only 667# if you know you want it. It's very handy if you want to check if a 668# file system is mounted. 669{ 670 vars: 671 have_mtab:: 672 "mount_count" int => readstringarrayidx("mounts", 673 $(inventory_control.mtab), 674 "\s*#[^\n]*", 675 "\s+", 676 500, 677 50000); 678 679 "idx" slist => getindices("mounts"); 680 681 classes: 682 "have_mtab" expression => fileexists($(inventory_control.mtab)); 683 684 # define classes like have_mount_ext4__var for a ext4 /var mount 685 "have_mount_$(mounts[$(idx)][2])_$(mounts[$(idx)][1])" 686 expression => "any", 687 scope => "namespace"; 688 689 # define classes like have_mount_ext4 if there is a ext4 mount 690 "have_mount_$(mounts[$(idx)][2])" 691 expression => "any", 692 scope => "namespace"; 693 694 reports: 695 verbose_mode:: 696 "$(this.bundle): we have a $(mounts[$(idx)][2]) mount under $(mounts[$(idx)][1])"; 697} 698 699bundle agent cfe_autorun_inventory_fstab 700# @brief Do fstab inventory 701# 702# The fstab format is simple: each line looks like this format: 703# `/dev/sda1 / auto noatime 0 1` (in order: `DEV MOUNTPOINT FSTYPE 704# OPTIONS DUMP-FREQ PASS`). Note the FSTYPE is not known from the 705# fstab. 706# 707# Solaris has 'MOUNTDEV FSCKDEV MOUNTPOINT FSTYPE PASS MOUNT-AD-BOOT 708# OPTIONS' but is not supported here. Contributions welcome. 709{ 710 vars: 711 have_fstab:: 712 "mount_count" int => readstringarrayidx("mounts", 713 $(sys.fstab), 714 "\s*#[^\n]*", 715 "\s+", 716 500, 717 50000); 718 719 "idx" slist => getindices("mounts"); 720 721 classes: 722 "have_fstab" expression => fileexists($(sys.fstab)); 723 724 # define classes like have_fs_ext4__var for a ext4 /var entry 725 "have_fs_$(mounts[$(idx)][2])_$(mounts[$(idx)][1])" 726 expression => "any", 727 scope => "namespace"; 728 729 # define classes like have__var for a /var entry 730 "have_fs_$(mounts[$(idx)][1])" 731 expression => "any", 732 scope => "namespace"; 733 734 # define classes like have_fs_ext4 if there is a ext4 entry 735 "have_fs_$(mounts[$(idx)][2])" 736 expression => "any", 737 scope => "namespace"; 738 739 reports: 740 verbose_mode:: 741 "$(this.bundle): we have a $(mounts[$(idx)][2]) fstab entry under $(mounts[$(idx)][1])"; 742} 743 744bundle agent cfe_autorun_inventory_dmidecode 745# @brief Do hardware related inventory 746# 747# This agent bundle reads dmi information from the sysfs and/or from dmidecode. 748# Sysfs is preferred for most variables, but if no sysfs (e.g. on RHEL 5), 749# or no sysfs equivalent to a dmidecode variable (e.g. system-version), 750# then dmidecode is run to collect the info. 751# For system-uuid, a parsed version of dmidecode is the preferred source. 752# 753# The variable names dmi[...] are all based on dmidecode string keywords. 754# 755# Information collected is: 756# - BIOS vendor 757# - BIOS version 758# - System serial number 759# - System manufacturer 760# - System version 761# - System product name 762# - Physical memory (MB) 763# 764# On windows where powershell is available this bundle runs gwmi to inventory: 765# - BIOS vendor 766# - BIOS version 767# - System serial number 768# - System manufacturer 769{ 770 771 vars: 772 any:: 773 "sysfs_name_for" 774 comment => "The names in /sys/devices/virtual/dmi/id/ don't match 775 the strings to be passed to dmidecode, even though the 776 values do. We use the dmidecode string names for our 777 variables since that was the original source (i.e. for 778 backward compatibility with policies based on prior 779 versions of this code).", 780 # system-version has no equivalent in sysfs that I can find. 781 # Items after the line break aren't currently collected, but mapping is provided 782 # in case someone adds them to a custom dmidefs (so that they could be gotten 783 # from sysfs in that case). 784 data => parsejson(' 785 { 786 "bios-vendor": "bios_vendor", 787 "bios-version": "bios_version", 788 "system-serial-number": "product_serial", 789 "system-manufacturer": "sys_vendor", 790 "system-product-name": "product_name", 791 "system-uuid": "product_uuid", 792 793 "baseboard-manufacturer": "board_vendor", 794 "baseboard-product-name": "board_name", 795 "baseboard-serial-number": "board_serial", 796 "baseboard-version": "board_version", 797 "bios-release-date": "bios_date", 798 "chassis-manufacturer": "chassis_vendor", 799 }'); 800 801 vars: 802 any:: 803 # The dmidefs variable controls which values are collected 804 # (and what are their inventory tags) 805 "dmidefs" data => parsejson(' 806{ 807 "bios-vendor": "BIOS vendor", 808 "bios-version": "BIOS version", 809 "system-serial-number": "System serial number", 810 "system-manufacturer": "System manufacturer", 811 "system-version": "System version", 812 "system-product-name": "System product name", 813 "system-uuid": "System UUID", 814}'); 815 816 # We override dmidefs from augments when we can. 817 818 "dmidefs" -> { "CFE-2927" } 819 data => mergedata( "def.cfe_autorun_inventory_dmidecode[dmidefs]" ), 820 if => isvariable( "def.cfe_autorun_inventory_dmidecode[dmidefs]"); 821 822 # other dmidecode variables you may want: 823 # baseboard-asset-tag 824 # baseboard-manufacturer 825 # baseboard-product-name 826 # baseboard-serial-number 827 # baseboard-version 828 # bios-release-date 829 # chassis-asset-tag 830 # chassis-manufacturer 831 # chassis-serial-number 832 # chassis-type 833 # chassis-version 834 # processor-family 835 # processor-frequency 836 # processor-manufacturer 837 #"processor-version": "CPU model" <- Collected by default, but not by iterating over the list 838 839 "dmivars" slist => getindices(dmidefs); 840 841 have_dmidecode:: 842 "decoder" string => "$(inventory_control.dmidecoder)"; 843 844 have_dmidecode._stdlib_path_exists_awk.!(redhat_4|redhat_3):: 845 # Awk script from https://kb.vmware.com/s/article/53609 846 # Edited only to add "-t1" (an improvement tested on RHEL 4/5/6/7 and FreeBSD) 847 # and to take out the "UUID: " prefix in the output. 848 # This works on a superset of systems where dmidecode -s system-uuid works, 849 # e.g. RHEL 5 with dmidecode-2.7-1.28.2.el5 where system-uuid is not one of the valid keywords; 850 # also, this returns the correct UUID on systems (such as VMWare VMs with hardware version 13) 851 # where dmidecode -s system-uuid shows the wrong UUID. Some such VMWare VMs also show the 852 # wrong UUID in sysfs, which is why we prefer the "dmidecode | awk" version to sysfs for UUID. 853 # (We still need to check sysfs for UUID to handle hosts without dmidecode such as CoreOS.) 854 "dmi[system-uuid]" 855 string => execresult( 856 "$(decoder) -u -t1 | 857 $(paths.awk) ' 858 BEGIN { in1 = 0; hd = 0} 859 /, DMI type / { in1 = 0 } 860 /Strings:/ { hd = 0 } 861 { if (hd == 2) { printf \"%s-%s\n\", $1 $2, $3 $4 $5 $6 $7 $8; hd = 0 } } 862 { if (hd == 1) { printf \"%s-%s-%s-\", $9 $10 $11 $12, $13 $14, $15 $16; hd = 2 } } 863 /, DMI type 1,/ { in1 = 1 } 864 /Header and Data:/ { if (in1 != 0) { hd = 1 } } 865 '", 866 "useshell" ), 867 if => isvariable("dmidefs[system-uuid]"), # Only run this if system-uuid is marked for collection in dmidefs 868 meta => { "inventory", "attribute_name=$(dmidefs[system-uuid])" }; 869 870 !disable_inventory_dmidecode.!windows:: 871 # The reason disable_inventory_dmidecode is referenced here but not in the other context lines 872 # is because those vars depend on have_dmidecode which won't be set during pre-eval (and won't 873 # be set at all if this bundle isn't called). Without this guard here, we would attempt to 874 # read sysfs even if dmi inventory were turned off on the host via disable_inventory_dmidecode, 875 # which would be undesirable. 876 "dmi[$(dmivars)]" 877 unless => isvariable("dmi[$(dmivars)]"), # This is just for system-uuid really, which we get from the awk script above by preference. 878 if => fileexists("/sys/devices/virtual/dmi/id/$(sysfs_name_for[$(dmivars)])"), 879 string => readfile("/sys/devices/virtual/dmi/id/$(sysfs_name_for[$(dmivars)])", 0), 880 meta => { "inventory", "attribute_name=$(dmidefs[$(dmivars)])" }; 881 882 # Redhat 4 can support the -s option to dmidecode if 883 # kernel-utils-2.4-15.el4 or greater is installed. 884 have_dmidecode.!(redhat_4|redhat_3):: 885 "dmi[$(dmivars)]" string => execresult("$(decoder) -s $(dmivars)", 886 "useshell"), 887 unless => isvariable("dmi[$(dmivars)]"), # If already defined from sysfs, don't run dmidecode 888 meta => { "inventory", "attribute_name=$(dmidefs[$(dmivars)])" }; 889 890 # We do not want to inventory the model name from here, as inventory for 891 # CPU info has been abstracted away from DMI so we just collect it 892 # manually. 893 894 "dmi[processor-version]" string => execresult("$(decoder) -s processor-version", 895 "useshell"); 896 897 windows.powershell:: 898 "dmi[bios-vendor]" string => $(bios_array[1]), 899 meta => { "inventory", "attribute_name=BIOS vendor" }; 900 901 "dmi[system-serial-number]" string => $(bios_array[2]), 902 meta => { "inventory", "attribute_name=System serial number" }; 903 904 "dmi[bios-version]" string => $(bios_array[3]), 905 meta => { "inventory", "attribute_name=BIOS version" }; 906 907 "dmi[system-version]" string => $(bios_array[4]), 908 meta => { "inventory", "attribute_name=System version" }; 909 910 "dmi[processor-version]" string => $(processor_array[1]); 911 912 "split_pscomputername" 913 slist => string_split($(system_array[1]), "PSComputerName\s.*", 2), 914 comment => "Work around weird appearance of PSComputerName into System manufacturer"; 915 916 "dmi[system-manufacturer]" string => nth(split_pscomputername, 0), 917 meta => { "inventory", "attribute_name=System manufacturer" }; 918 919 classes: 920 "have_dmidecode" expression => fileexists($(inventory_control.dmidecoder)); 921 922 windows.powershell:: 923 "bios_match" expression => regextract(".*Manufacturer\s+:\s([a-zA-Z0-9 ]+)\n.*SerialNumber\W+([a-zA-Z0-9 ]+).*SMBIOSBIOSVersion\W+([a-zA-Z0-9 ]+).*Version\W+([a-zA-Z0-9 -]+)", 924 execresult("gwmi -query 'SELECT SMBIOSBIOSVersion, Manufacturer, SerialNumber, Version FROM WIN32_BIOS'", "powershell"), 925 "bios_array"); 926 927 "processor_match" expression => regextract(".*Name\W+(.*)", 928 execresult("gwmi -query 'SELECT Name FROM WIN32_PROCESSOR'", "powershell"), 929 "processor_array"); 930 931 "system_match" expression => regextract(".*Manufacturer\W+(.*)", 932 execresult("gwmi -query 'SELECT Manufacturer FROM WIN32_COMPUTERSYSTEM'", "powershell"), 933 "system_array"); 934 935 # BEGIN Inventory Total Physical Memory MB 936 vars: 937 938 "total_physical_memory_MB" -> { "CFE-2896" } 939 string => readfile( "$(sys.statedir)/inventory-$(this.bundle)-total-physical-memory-MB.txt", 100), 940 meta => { "inventory", "attribute_name=Physical memory (MB)" }, 941 if => fileexists( "$(sys.statedir)/inventory-$(this.bundle)-total-physical-memory-MB.txt" ); 942 943 commands: 944 945 have_dmidecode:: 946 947 "$(decoder) -t 17 | $(paths.awk) '/Size.*MB/ {s+=$2} END {print s}' > '$(sys.statedir)/inventory-$(this.bundle)-total-physical-memory-MB.txt'" -> { "CFE-2896" } 948 contain => in_shell, 949 if => not( fileexists( "$(sys.statedir)/inventory-$(this.bundle)-total-physical-memory-MB.txt") ); 950 951 files: 952 953 "$(sys.statedir)/inventory-$(this.bundle)-total-physical-memory-MB.txt" -> { "CFE-2896" } 954 delete => tidy, 955 file_select => older_than(0, 0, 1, 0, 0, 0), 956 comment => "Clear the cached value for total physical memory MB once a day."; 957 958 # END Inventory Total Physical Memory MB 959 960 reports: 961 DEBUG|DEBUG_cfe_autorun_inventory_dmidecode:: 962 "DEBUG $(this.bundle): Obtained $(dmidefs[$(dmivars)]) = '$(dmi[$(dmivars)])'"; 963 "DEBUG $(this.bundle): Obtained Physical memory (MB) = '$(total_physical_memory_MB)'"; 964} 965 966bundle agent cfe_autorun_inventory_LLDP 967# @brief Do LLDP-based inventory 968# 969# This agent bundle runs lldpctl to discover information. See 970# http://vincentbernat.github.io/lldpd/ to run this yourself for 971# testing, and your Friendly Network Admin may be of help too. 972{ 973 classes: 974 "lldpctl_exec_exists" expression => fileexists($(inventory_control.lldpctl_exec)); 975 976 vars: 977 !disable_inventory_LLDP.lldpctl_exec_exists:: 978 # TODO When CFE-3108 is DONE, migrate to capturing only stdout 979 "info" -> { "CFE-3109", "CFE-3108" } 980 data => parsejson(execresult("$(inventory_control.lldpctl_json) 2>/dev/null", "useshell")), 981 if => not(isvariable("def.lldpctl_json")), 982 comment => "Not all versions of lldpctl support json, and because an 983 absent lldpd will result in an error on stderr resulting noisy logs and 984 failure to parse the json we redirect to dev null"; 985 986 "info" -> { "CFE-3109" } 987 data => parsejson(execresult($(inventory_control.lldpctl_json), "noshell")), 988 if => isvariable("def.lldpctl_json"), 989 comment => "For safety, we do not run lldpctl in a shell if the path to 990 lldpctl is customized via augments"; 991} 992 993bundle agent cfe_autorun_inventory_packages 994# @brief Package inventory auto-refresh 995# 996# This bundle is for refreshing the package inventory. It runs on 997# startup, unless disabled. Other package methods can be added below. 998{ 999 classes: 1000 "have_patches" or => { "community_edition", # not in Community 1001 fileexists("$(sys.workdir)/state/software_patches_avail.csv") }; 1002 1003 "have_inventory" and => { "have_patches", 1004 fileexists("$(sys.workdir)/state/software_packages.csv"), 1005 }; 1006 1007 vars: 1008 # if we have the patches, 7 days; otherwise keep trying 1009 "refresh" string => ifelse("have_inventory", "10080", 1010 "0"); 1011 1012 packages: 1013 1014 # The legacy implementation (package_method) of the packages type promise 1015 # requires a packages promise to be triggered in order to generate package 1016 # inventory. The following promises ensure that package inventory data 1017 # exists. As package modules become available the package_methods should be 1018 # removed. 1019 1020 suse|sles:: 1021 "cfe_internal_non_existing_package" 1022 package_policy => "add", 1023 package_method => inventory_zypper($(refresh)), 1024 action => if_elapsed_day; 1025 1026 aix:: 1027 "cfe_internal_non_existing_package" 1028 package_policy => "add", 1029 package_method => inventory_lslpp($(refresh)), 1030 action => if_elapsed_day; 1031 1032 gentoo:: 1033 "cfe_internal_non_existing_package" 1034 package_policy => "add", 1035 package_method => emerge, 1036 action => if_elapsed_day; 1037 1038 !redhat.!debian.!gentoo.!(suse|sles).!aix:: 1039 "cfe_internal_non_existing_package" 1040 package_policy => "add", 1041 package_method => generic, 1042 action => if_elapsed_day; 1043 1044 reports: 1045 DEBUG|DEBUG_cfe_autorun_inventory_packages:: 1046 "DEBUG $(this.bundle): refresh interval is $(refresh)"; 1047 "DEBUG $(this.bundle): we have the inventory files." 1048 ifvarclass => "have_inventory"; 1049 "DEBUG $(this.bundle): we don't have the inventory files." 1050 ifvarclass => "!have_inventory"; 1051} 1052 1053body package_method inventory_lslpp(update_interval) 1054# @brief AIX lslpp installation method for inventory purposes only 1055# @param update_interval how often to update the package and patch list 1056{ 1057 package_changes => "individual"; 1058 1059 package_list_update_command => "/usr/bin/true"; 1060 package_list_update_ifelapsed => $(update_interval); 1061 1062 package_list_command => "/usr/bin/lslpp -Lqc"; # list RPMs too 1063 package_list_version_regex => "[^:]+:[^:]+:([^:]+):.*"; 1064 # Make sure version is not included in the name, that indicates RPM 1065 # packages, which we should ignore. 1066 package_list_name_regex => "[^:]+:(([^-:]|-[^0-9])+):.*"; 1067 package_installed_regex => "[^:]+:(([^-:]|-[^0-9])+):[^:]+:[^:]+:.*"; 1068 1069 package_name_convention => "$(name)-$(version).+"; 1070 1071 package_add_command => "/usr/bin/true"; 1072 package_update_command => "/usr/bin/true"; 1073 package_patch_command => "/usr/bin/true"; 1074 package_delete_command => "/usr/bin/true"; 1075 package_verify_command => "/usr/bin/true"; 1076} 1077 1078body package_method inventory_zypper(update_interval) 1079# @depends common_knowledge rpm_knowledge suse_knowledge 1080# @brief SUSE zypper installation method for inventory purposes only 1081# @param update_interval how often to update the package and patch list 1082# 1083# This package method is a copy of the SUSE zypper method just for 1084# inventory purposes. 1085{ 1086 package_changes => "bulk"; 1087 1088 package_list_command => "$(paths.path[rpm]) -qa --queryformat \"i | repos | %{name} | %{version}-%{release} | %{arch}\n\""; 1089 1090 # set it to "0" to avoid caching of list during upgrade 1091 package_list_update_command => "$(suse_knowledge.call_zypper) list-updates"; 1092 package_list_update_ifelapsed => $(update_interval); 1093 1094 package_patch_list_command => "$(suse_knowledge.call_zypper) patches"; 1095 package_installed_regex => "i.*"; 1096 package_list_name_regex => "$(rpm_knowledge.rpm_name_regex)"; 1097 package_list_version_regex => "$(rpm_knowledge.rpm_version_regex)"; 1098 package_list_arch_regex => "$(rpm_knowledge.rpm_arch_regex)"; 1099 1100 package_patch_installed_regex => ".*Installed.*|.*Not Applicable.*"; 1101 package_patch_name_regex => "[^|]+\|\s+([^\s]+).*"; 1102 package_patch_version_regex => "[^|]+\|[^|]+\|\s+([^\s]+).*"; 1103 1104 package_name_convention => "$(name)"; 1105 package_add_command => "$(suse_knowledge.call_zypper) --help >/dev/null 2>&1 ; /bin/true"; 1106 package_delete_command => "$(suse_knowledge.call_zypper) --non-interactive remove --force-resolution"; 1107 package_update_command => "$(suse_knowledge.call_zypper) --non-interactive update"; 1108 package_patch_command => "$(suse_knowledge.call_zypper) --non-interactive patch$"; # $ means no args 1109 package_verify_command => "$(suse_knowledge.call_zypper) --non-interactive verify$"; 1110} 1111 1112bundle agent cfe_autorun_inventory_cmdb 1113# @brief Copy and load the CMDB inventory 1114# 1115# This bundle is for refreshing the CMDB inventory. It copies the 1116# file me.json from the server, then loads it to create variables and 1117# classes. 1118{ 1119 vars: 1120 "cmdb_dir" string => "$(sys.workdir)/cmdb", 1121 comment => "CMDB directory location", 1122 meta => { "cmdb" }; 1123 1124 "cmdb_file" string => "$(cmdb_dir)/me.json", 1125 comment => "CMDB file location", 1126 meta => { "cmdb" }; 1127 1128 files: 1129 "$(cmdb_file)" 1130 copy_from => inventory_cmdb_copy_from, 1131 classes => inventory_scoped_classes_generic("bundle", "cmdb_file"); 1132 1133 methods: 1134 cmdb_file_ok:: 1135 "load CMDB file" usebundle => inventory_cmdb_load($(cmdb_file)); 1136} 1137 1138bundle agent inventory_cmdb_load(file) 1139# @brief Load the CMDB inventory 1140# @param file Load the CMDB inventory 1141# 1142# This bundle is for loading the CMDB inventory. 1143{ 1144 classes: 1145 "have_cmdb_data" expression => isvariable("cmdb"); 1146 1147 "$(ckeys)" expression => "any", scope => "namespace"; 1148 1149 vars: 1150 "cmdb" 1151 data => readjson($(file), "999999"), 1152 ifvarclass => fileexists( $(file) ); 1153 1154 "cmdb_string" 1155 string => format("%S", cmdb), 1156 ifvarclass => isvariable( cmdb ); 1157 1158 "bkeys" slist => getindices("cmdb[vars]"); 1159 "vkeys_$(bkeys)" slist => getindices("cmdb[vars][$(bkeys)]"); 1160 "$(vkeys_$(bkeys))" string => nth("cmdb[vars][$(bkeys)]", $(vkeys)); 1161 1162 "ckeys" slist => getindices("cmdb[classes]"); 1163 1164 reports: 1165 DEBUG|DEBUG_inventory_cmdb_load:: 1166 "DEBUG $(this.bundle): Got CMDB data from $(file): $(cmdb_string)" 1167 ifvarclass => "have_cmdb_data"; 1168 "DEBUG $(this.bundle): Got CMDB key = $(vkeys_$(bkeys)), CMDB value = $((vkeys_$(bkeys)))" 1169 ifvarclass => "have_cmdb_data"; 1170 "DEBUG $(this.bundle): Got CMDB class = $(ckeys)" 1171 ifvarclass => "have_cmdb_data"; 1172 "DEBUG $(this.bundle): Could not read the CMDB data from $(file)" 1173 ifvarclass => "!have_cmdb_data"; 1174} 1175 1176body copy_from inventory_cmdb_copy_from 1177# @brief Copy from the CMDB source 1178{ 1179 !cfe_inventory_cmdb_override_file:: 1180 source => "me.json"; 1181 servers => { "$(sys.policy_hub)" }; 1182 cfe_inventory_cmdb_override_file:: 1183 source => "$(sys.inputdir)/me.json"; 1184 any:: 1185 compare => "digest"; 1186 encrypt => "true"; 1187 verify => "true"; 1188} 1189 1190body classes inventory_scoped_classes_generic(scope, x) 1191# @brief Define `x` prefixed/suffixed with promise outcome 1192# **See also:** `scope` 1193# 1194# @param scope The scope in which the class should be defined 1195# @param x The unique part of the classes to be defined 1196# 1197# Copy of `scoped_classes_generic`, which see. 1198{ 1199 scope => "$(scope)"; 1200 promise_repaired => { "promise_repaired_$(x)", "$(x)_repaired", "$(x)_ok", "$(x)_reached" }; 1201 repair_failed => { "repair_failed_$(x)", "$(x)_failed", "$(x)_not_ok", "$(x)_not_kept", "$(x)_not_repaired", "$(x)_reached" }; 1202 repair_denied => { "repair_denied_$(x)", "$(x)_denied", "$(x)_not_ok", "$(x)_not_kept", "$(x)_not_repaired", "$(x)_reached" }; 1203 repair_timeout => { "repair_timeout_$(x)", "$(x)_timeout", "$(x)_not_ok", "$(x)_not_kept", "$(x)_not_repaired", "$(x)_reached" }; 1204 promise_kept => { "promise_kept_$(x)", "$(x)_kept", "$(x)_ok", "$(x)_not_repaired", "$(x)_reached" }; 1205} 1206 1207body contain inventory_in_shell 1208# @brief run command in shell 1209# 1210# Copy of `in_shell`, which see. 1211{ 1212 useshell => "true"; # canonical "useshell" but this is backwards-compatible 1213} 1214