485 lines
13 KiB
Perl
485 lines
13 KiB
Perl
#!/usr/bin/perl
|
|
###############################################################################
|
|
#
|
|
# Copyright (c) 2009 Artica Soluciones Tecnologicas S.L.
|
|
#
|
|
# inventory Generate a hardware/software inventory.
|
|
#
|
|
# Sample usage: ./inventory <interval in days> [cpu] [ram] [video] [nic] [hd] [cdrom] [software] [init_services] [filesystem] [process] [users]
|
|
#
|
|
# 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 2 of the License.
|
|
#
|
|
# 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.
|
|
#
|
|
###############################################################################
|
|
|
|
use strict;
|
|
use constant TSTAMP_FILE => '/tmp/pandora_inventory.tstamp';
|
|
use utf8;
|
|
use Encode;
|
|
|
|
# Operation mode (LSHW or HWINFO)
|
|
my $Mode;
|
|
|
|
# Item separator
|
|
my $Separator;
|
|
|
|
# Parse module information
|
|
sub get_module_data ($$$$) {
|
|
my ($name, $hwinfo, $keys, $modules) = @_;
|
|
my %module;
|
|
|
|
# Store keys
|
|
foreach my $key (@{$keys}) {
|
|
push (@{$module{'_keys'}}, $key);
|
|
}
|
|
|
|
# Parse module data
|
|
while (my $line = shift (@{$hwinfo})) {
|
|
$line = Encode::decode("utf8", $line);
|
|
$line =~ tr/áéíóúüñçÁÉÍÓÚÜÑÇ/aeiouuncAEIOUUNC/;
|
|
|
|
if ($line =~ /$Separator/) {
|
|
unshift (@{$hwinfo}, $line);
|
|
last;
|
|
}
|
|
foreach my $key (@{$keys}) {
|
|
if ($line =~ /$key:\s+(.+)/) {
|
|
$module{$key} = $1;
|
|
# Replace semicolon by comma to avoid parse errors
|
|
$module{$key} =~ s/;/,/g;
|
|
}
|
|
}
|
|
}
|
|
|
|
# No data found
|
|
my @data = keys (%module);
|
|
return unless ($#data >= 0);
|
|
|
|
push (@{$modules->{$name}}, \%module);
|
|
}
|
|
|
|
# Get a list of information file system in machine
|
|
sub get_file_system($$) {
|
|
my ($name, $modules) = @_;
|
|
|
|
my @fileSystems = `df -h | tail -n +2`; #remove the titles of columns
|
|
|
|
foreach my $row (@fileSystems) {
|
|
next unless ($row =~ /^(\S+)\s+\S+\s+(\S+)\s+(\S+)\s+\S+\s+(\S+)/);
|
|
|
|
my %module;
|
|
$module{'filesystem'} = $1;
|
|
$module{'used'} = $2;
|
|
$module{'avail'} = $3;
|
|
$module{'mount'} = $4;
|
|
$module{'_keys'} = ['filesystem', 'used','avail', 'mount'];
|
|
push (@{$modules->{$name}}, \%module);
|
|
}
|
|
}
|
|
|
|
# Get a list of services init in machine
|
|
sub get_servicies_init_machine($$) {
|
|
my ($name, $modules) = @_;
|
|
my $runlevel = `who -r | awk '{print \$2}'`;
|
|
|
|
#ini trim($runlevel)
|
|
$runlevel =~ s/^\s*//; #ltrim
|
|
$runlevel =~ s/\s*$//; #rtrim
|
|
#end trim($runlevel)
|
|
|
|
my $script = "";
|
|
|
|
if (-e "/etc/rc" . $runlevel .".d/") {
|
|
$script = "ls /etc/rc" . $runlevel .".d/ -l | grep \"^l.*\" | awk \"{print \\\$NF}\" | sed -e \"s/\\.\\.\\///g\" | sed -e \"s/.*init\\.d\\///g\"";
|
|
}
|
|
else {
|
|
$script = "ls /etc/rc.d/rc" . $runlevel .".d/ -l | grep \"^l.*\" | grep \" S.* \" | awk \"{print \\\$NF}\" | sed -e \"s/\\.\\.\\///g\" | sed -e \"s/.*init\\.d\\///g\"";
|
|
|
|
}
|
|
|
|
my @services = `$script`;
|
|
foreach my $row (@services) {
|
|
|
|
my %module;
|
|
$row =~ s/\n//;
|
|
$module{'service'} = $row;
|
|
$module{'_keys'} = ['service'];
|
|
push (@{$modules->{$name}}, \%module);
|
|
}
|
|
}
|
|
|
|
# Get a list of running processes
|
|
sub get_processes ($$) {
|
|
my ($name, $modules) = @_;
|
|
|
|
my $script = "ps -eo command";
|
|
|
|
my @services = `$script`;
|
|
foreach my $row (@services) {
|
|
my %module;
|
|
# Remove carriage returns
|
|
$row =~ s/[\n\l\f]//g;
|
|
# Replace semicolon by comma to avoid parse errors
|
|
$row =~ s/;/,/g;
|
|
$module{'service'} = $row;
|
|
$module{'_keys'} = ['service'];
|
|
push (@{$modules->{$name}}, \%module);
|
|
}
|
|
}
|
|
|
|
# Get a list of valid users in the system
|
|
sub get_users ($$) {
|
|
my ($name, $modules) = @_;
|
|
|
|
my $script = "cat /etc/passwd";
|
|
my $user = "";
|
|
my $estado = "";
|
|
|
|
my @services = `$script`;
|
|
foreach my $row (@services) {
|
|
my %module;
|
|
|
|
next unless ($row =~ /^([A-Za-z0-9\-\_]*)/);
|
|
|
|
$user = $1;
|
|
$script = `passwd -S $user`;
|
|
if ( $script =~ /^(\S+)\sP./){
|
|
$module{'user'} = $user;
|
|
$module{'_keys'} = ['user'];
|
|
push (@{$modules->{$name}}, \%module);
|
|
}
|
|
}
|
|
}
|
|
|
|
# Get a list of installed programs
|
|
sub get_software_module_data ($$) {
|
|
my ($name, $modules) = @_;
|
|
|
|
# Guess the current distribution
|
|
my $distrib_id = "";
|
|
|
|
if ( -e "/etc/SuSE-release"){
|
|
$distrib_id = "SUSE";
|
|
} else {
|
|
open (RELEASE_FILE, '< /etc/lsb-release') or return;
|
|
$distrib_id = <RELEASE_FILE>;
|
|
last unless ($distrib_id =~ m/DISTRIB_ID\s*=\s*(\S+)/);
|
|
$distrib_id = $1;
|
|
}
|
|
|
|
# List installed programs
|
|
my @soft;
|
|
if ($distrib_id eq 'Ubuntu') {
|
|
@soft = `dpkg -l | grep ii`;
|
|
} else {
|
|
|
|
@soft = `rpm -q -a --qf "ii\t%{NAME}\t%{VERSION}\t%{SUMMARY}\n"`;
|
|
}
|
|
|
|
|
|
# Parse data
|
|
foreach my $row (@soft) {
|
|
next unless ($row =~ /^ii\s+(\S+)\s+(\S+)\s+([^\n]+)/);
|
|
|
|
my %module;
|
|
$module{'program'} = $1;
|
|
$module{'version'} = $2;
|
|
$module{'description'} = $3;
|
|
# Replace semicolon by comma to avoid parse errors
|
|
$module{'program'} =~ s/;/,/g;
|
|
$module{'version'} =~ s/;/,/g;
|
|
$module{'description'} =~ s/;/,/g;
|
|
$module{'_keys'} = ['program', 'version','description'];
|
|
push (@{$modules->{$name}}, \%module);
|
|
}
|
|
}
|
|
|
|
#Get the list of interfaces with the ip assigned
|
|
sub get_ips ($$) {
|
|
my ($name, $modules) = @_;
|
|
|
|
my $ifconfig = `ifconfig`;
|
|
|
|
my @ifconfig_array = split("\n", $ifconfig);
|
|
|
|
for(my $i = 0; $i<$#ifconfig_array; $i++) {
|
|
|
|
#Check for an interface
|
|
if ($ifconfig_array[$i] =~ /Link/) {
|
|
my %info;
|
|
|
|
my @line_split = split(" ", $ifconfig_array[$i]);
|
|
|
|
#Get interface name
|
|
$info{'interface'} = $line_split[0];
|
|
|
|
#Get IP address
|
|
my $line = $ifconfig_array[$i+1];
|
|
|
|
$line =~ s/\s+//g;
|
|
|
|
@line_split = split(":", $line);
|
|
|
|
if($line_split[1] =~ /(\d+\.\d+\.\d+\.\d+).+/) {
|
|
$info{'ip'} = $1;
|
|
}
|
|
|
|
$info{'_keys'} = ['interface', 'ip'];
|
|
push (@{$modules->{$name}}, \%info);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
#Get route table
|
|
sub get_route_table ($$) {
|
|
my ($name, $modules) = @_;
|
|
|
|
my $route_table = `route`;
|
|
|
|
my @table_split = split("\n", $route_table);
|
|
|
|
for (my $i=2; $i<=$#table_split; $i++) {
|
|
|
|
my @split = split(" ", $table_split[$i]);
|
|
|
|
my %info;
|
|
|
|
$info{'destination'} = $split[0];
|
|
$info{'gateway'} = $split[1];
|
|
$info{'mask'} = $split[2];
|
|
$info{'flags'} = $split[3];
|
|
$info{'metric'} = $split[4];
|
|
$info{'ref'} = $split[5];
|
|
$info{'use'} = $split[6];
|
|
$info{'interface'} = $split[7];
|
|
|
|
$info{'_keys'} = ['destination', 'gateway', 'mask', 'flags', 'metric', 'use', 'interface'];
|
|
|
|
push (@{$modules->{$name}}, \%info);
|
|
}
|
|
}
|
|
# Print module data
|
|
sub print_module ($$) {
|
|
my ($name, $module) = @_;
|
|
|
|
print " <inventory_module>\n";
|
|
print " <name><![CDATA[" . $name . "]]></name>\n";
|
|
print " <datalist>\n";
|
|
foreach my $item (@{$module}) {
|
|
# Compose module data
|
|
my $data = undef;
|
|
foreach my $key (@{$item->{'_keys'}}) {
|
|
$data = (!defined($data) ? '' : "$data;");
|
|
if (defined($item->{$key})) {
|
|
$data .= $item->{$key};
|
|
}
|
|
}
|
|
|
|
print " <data><![CDATA[$data]]></data>\n";
|
|
}
|
|
print " </datalist>\n";
|
|
print " </inventory_module>\n";
|
|
}
|
|
|
|
# Check command line parameters
|
|
if ($#ARGV < 0) {
|
|
print "Usage: $0 <interval> [cpu] [ram] [video] [nic] [hd] [cdrom] [software] [init_services] [filesystem] [users] [process] [ip] [route]\n\n";
|
|
exit 1;
|
|
}
|
|
|
|
# Parse command line parameters
|
|
my %enabled;
|
|
my $interval = 1;
|
|
my $enable_all = 0;
|
|
|
|
$interval = $ARGV[0];
|
|
if ($#ARGV == 0){
|
|
$enable_all = 1;
|
|
}
|
|
|
|
foreach my $module (@ARGV) {
|
|
if ($module eq "all"){
|
|
$enable_all = 1;
|
|
}
|
|
$enabled{$module} = 1;
|
|
}
|
|
|
|
# Check execution interval
|
|
if (-f TSTAMP_FILE) {
|
|
open (FILE, '<' . TSTAMP_FILE) || exit 1;
|
|
my $last_execution = <FILE>;
|
|
close (FILE);
|
|
exit 0 if ($last_execution + 86400 * $interval > time ());
|
|
}
|
|
open (FILE, '>' . TSTAMP_FILE) || exit 1;
|
|
print FILE time ();
|
|
close (FILE);
|
|
|
|
# Retrieve hardware information
|
|
$Mode = 'LSHW';
|
|
$Separator = '\s+\*\-';
|
|
my @hwinfo = `lshw 2>/dev/null`;
|
|
if ($? != 0) {
|
|
$Mode = 'HWINFO';
|
|
$Separator = 'Hardware Class:';
|
|
@hwinfo = `hwinfo --cpu --memory --gfxcard --netcard --cdrom --disk 2>/dev/null`;
|
|
}
|
|
|
|
my @locale = `locale`;
|
|
my @version = `cat /etc/issue`;
|
|
my $spanish = 0;
|
|
my $change_idiom = 0;
|
|
|
|
while (my $linea = shift (@locale)) {
|
|
if ($linea =~ /LANG=/) {
|
|
my @arr_lang = split('=', $linea);
|
|
my $lang_system = $arr_lang[1];
|
|
if ($lang_system =~ /es_ES/) {
|
|
$change_idiom = 1;
|
|
}
|
|
}
|
|
}
|
|
if ($version[0] =~ /Ubuntu 12.04/) {
|
|
if ($change_idiom == 1) {
|
|
$spanish = 1;
|
|
}
|
|
}
|
|
|
|
# Parse hardware information
|
|
my %modules;
|
|
while (my $line = shift (@hwinfo)) {
|
|
chomp ($line);
|
|
|
|
# CPU
|
|
if (($line =~ /\*\-cpu/ || $line =~ /Hardware Class: cpu/) && ($enable_all == 1 || $enabled{'cpu'} == 1)) {
|
|
if ($Mode eq 'LSHW') {
|
|
if ($spanish) { # SO Ubuntu 12.04 and idiom spanish
|
|
get_module_data ('CPU', \@hwinfo, ['producto', 'fabricante', 'capacidades'], \%modules);
|
|
} else {
|
|
get_module_data ('CPU', \@hwinfo, ['product', 'vendor', 'capacity'], \%modules);
|
|
}
|
|
} else {
|
|
get_module_data ('CPU', \@hwinfo, ['Model', 'Vendor', 'Clock'], \%modules);
|
|
}
|
|
}
|
|
|
|
# RAM
|
|
if (($line =~ /\*\-bank/ || $line =~ /Hardware Class: memory/) && ($enable_all == 1 || $enabled{'ram'} == 1)) {
|
|
if ($Mode eq 'LSHW') {
|
|
if ($spanish) { # SO Ubuntu 12.04 and idiom spanish
|
|
get_module_data ('RAM', \@hwinfo, ['descripcion', 'tamano'], \%modules);
|
|
} else {
|
|
get_module_data ('RAM', \@hwinfo, ['description', 'size'], \%modules);
|
|
}
|
|
} else {
|
|
get_module_data ('RAM', \@hwinfo, ['Model', 'Memory Size'], \%modules);
|
|
}
|
|
}
|
|
|
|
# VIDEO
|
|
if (($line =~ /\*\-display/ || $line =~ /Hardware Class: graphics card/) && ($enable_all == 1 || $enabled{'video'} == 1)) {
|
|
if ($Mode eq 'LSHW') {
|
|
if ($spanish) { # SO Ubuntu 12.04 and idiom spanish
|
|
get_module_data ('VIDEO', \@hwinfo, ['producto', 'descripcion', 'fabricante'], \%modules);
|
|
} else {
|
|
get_module_data ('VIDEO', \@hwinfo, ['product', 'description', 'vendor'], \%modules);
|
|
}
|
|
} else {
|
|
# Spaces before Device and Vendor are intentional to avoid matching SubDevice and SubVendor
|
|
get_module_data ('VIDEO', \@hwinfo, ['Model', ' Device', ' Vendor'], \%modules);
|
|
}
|
|
}
|
|
|
|
# NIC
|
|
if (($line =~ /\*\-network/ || $line =~ /Hardware Class: network/) && ($enable_all == 1 || $enabled{'nic'} == 1)) {
|
|
if ($Mode eq 'LSHW') {
|
|
if ($spanish) { # SO Ubuntu 12.04 and idiom spanish
|
|
get_module_data ('NIC', \@hwinfo, ['producto', 'descripcion', 'fabricante', 'serie'], \%modules);
|
|
} else {
|
|
get_module_data ('NIC', \@hwinfo, ['product', 'description', 'vendor', 'serial'], \%modules);
|
|
}
|
|
} else {
|
|
# Spaces before Device and Vendor are intentional to avoid matching SubDevice and SubVendor
|
|
get_module_data ('NIC', \@hwinfo, ['Model', ' Device', ' Vendor', 'HW Address'], \%modules);
|
|
}
|
|
}
|
|
|
|
# CDROM
|
|
if (($line =~ /\*\-cdrom/ || $line =~ /Hardware Class: cdrom/) && ($enable_all == 1 || $enabled{'cdrom'} == 1)) {
|
|
if ($Mode eq 'LSHW') {
|
|
if ($spanish) { # SO Ubuntu 12.04 and idiom spanish
|
|
get_module_data ('CDROM', \@hwinfo, ['producto', 'descripcion', 'fabricante'], \%modules);
|
|
} else {
|
|
get_module_data ('CDROM', \@hwinfo, ['product', 'description', 'vendor'], \%modules);
|
|
}
|
|
} else {
|
|
# Spaces before Device and Vendor are intentional to avoid matching SubDevice and SubVendor
|
|
get_module_data ('CDROM', \@hwinfo, ['Model', ' Device', ' Vendor'], \%modules);
|
|
}
|
|
}
|
|
|
|
# HD
|
|
if (($line =~ /\*\-disk/ || $line =~ /Hardware Class: disk/) && ($enable_all == 1 || $enabled{'hd'} == 1)) {
|
|
if ($Mode eq 'LSHW') {
|
|
if ($spanish) { # SO Ubuntu 12.04 and idiom spanish
|
|
get_module_data ('HD', \@hwinfo, ['producto', 'descripcion', 'tamano'], \%modules);
|
|
} else {
|
|
get_module_data ('HD', \@hwinfo, ['product', 'description', 'size'], \%modules);
|
|
}
|
|
} else {
|
|
get_module_data ('HD', \@hwinfo, ['Model', 'Serial ID', 'Size'], \%modules);
|
|
}
|
|
}
|
|
}
|
|
|
|
# Software
|
|
if ($enable_all == 1 || $enabled{'software'} == 1) {
|
|
get_software_module_data ('Software', \%modules);
|
|
}
|
|
|
|
#init_services
|
|
if ($enable_all == 1 || $enabled{'init_services'} == 1) {
|
|
get_servicies_init_machine ('Init services', \%modules);
|
|
}
|
|
|
|
#filesystem
|
|
if ($enable_all == 1 || $enabled{'filesystem'} == 1) {
|
|
get_file_system('File system', \%modules);
|
|
}
|
|
|
|
#processes
|
|
if ($enable_all == 1 || $enabled{'process'} == 1) {
|
|
get_processes('Process', \%modules);
|
|
}
|
|
|
|
#users
|
|
if ($enable_all == 1 || $enabled{'users'} == 1){
|
|
get_users ('Users', \%modules);
|
|
}
|
|
|
|
#ip
|
|
if ($enable_all == 1 || $enabled{'ip'} == 1) {
|
|
get_ips('IP', \%modules);
|
|
}
|
|
|
|
#route
|
|
if ($enable_all == 1 || $enabled{'route'} == 1) {
|
|
get_route_table('Routes', \%modules);
|
|
}
|
|
|
|
# Print module data
|
|
print "<inventory>\n";
|
|
while (my ($name, $module) = each (%modules)) {
|
|
print_module ($name, $module);
|
|
}
|
|
print "</inventory>\n";
|
|
|
|
exit 0;
|