Subversion Repositories camp_sysinfo_client_3

Rev

Rev 113 | Rev 136 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 113 Rev 135
Line 149... Line 149...
149
# Finally got a semi-stable version of this running. Fixed a bunch of bugs
149
# Finally got a semi-stable version of this running. Fixed a bunch of bugs
150
# and appears to be working correctly.
150
# and appears to be working correctly.
151
#
151
#
152
# Version 3.3.0 20190419 RWR
152
# Version 3.3.0 20190419 RWR
153
# Converted to use YAML config file
153
# Converted to use YAML config file
-
 
154
#
-
 
155
# Version 3.4.0 20191111 RWR
-
 
156
# adding logging with priority. logging is a hash inside of %cvonfiguration which contains the following
-
 
157
# $configuration{ 'logging' } = {
-
 
158
#    'log type'  => 'string',
-
 
159
#    'log level' => #,
-
 
160
#    'other params' => something,
-
 
161
# };
-
 
162
# Currently, the only log type is 'file', which has one other additional parameter, 'log path' which
-
 
163
# points to the actual log to be created. The log is NOT limited in size, so use something else to
-
 
164
# do that.
-
 
165
# log level is an integer which is compared the a priority passed to the logging function. The
-
 
166
# higher log level is set, the more verbose the log.
-
 
167
# 0 - Normal, basically logs when the program starts and ends, and any warnings.
-
 
168
# 1 - a little more information about flow
-
 
169
# 2 - Gives ending information on structures
-
 
170
# 3 - Gives a lot of info about structures when they are initialized and at the end
-
 
171
# 4 - Crazy. Dumps just about every structure every time they are changed
-
 
172
#
-
 
173
# $TESTING has been set to a binary. If true, the report is not sent via the transports, but is dumped to /tmp/sysinfo.testing.yaml
-
 
174
   
154
 
175
 
155
# find our location and use it for searching for libraries
176
# find our location and use it for searching for libraries
156
BEGIN {
177
BEGIN {
157
   use FindBin;
178
   use FindBin;
158
   use File::Spec;
179
   use File::Spec;
Line 161... Line 182...
161
 
182
 
162
use YAML::Tiny;
183
use YAML::Tiny;
163
 
184
 
164
# Following are global variables overridden if configuration file exists
185
# Following are global variables overridden if configuration file exists
165
 
186
 
166
my $TESTING = 0; # level's 0 (none) to 4 defined and increase verbosity while decreasing functionality
187
my $TESTING = 0; # if set to 1, will do everything, but will dump output to /tmp/sysinfo.testing.yaml
167
our $VERSION = '3.3.0';
-
 
168
 
188
 
169
my $indentLevel = 2; # number of spaces to indent per level in XML or YAML
189
our $VERSION = '3.4.0';
170
 
190
 
171
$indentLevel = 3 if $TESTING;
191
my $indentLevel = 2; # number of spaces to indent per level in XML or YAML
172
if ($TESTING) {
-
 
173
   use Data::Dumper;
-
 
174
}
-
 
175
 
192
 
176
# paths to search for configuration file
193
# paths to search for configuration file
177
my @confFileSearchPath = ( '.', '/etc/camp/sysinfo-client', '/etc/camp', '/usr/local/etc/camp/sysinfo-client' );
194
my @confFileSearchPath = ( '.', '/etc/camp/sysinfo-client', '/etc/camp', '/usr/local/etc/camp/sysinfo-client' );
178
 
195
 
179
my $configurationFile = 'sysinfo-client.yaml'; # name of the configuration file
196
my $configurationFile = 'sysinfo-client.yaml'; # name of the configuration file
180
 
197
 
181
my $reportDate = &getReportDate; # set report date
198
my $reportDate = &timeStamp(); # set report date
182
 
199
 
183
my %configuration = (
200
my %configuration = (
-
 
201
   'logging' => [],    # if set, will point to logging
184
   'moduleDirs' => [], # search paths for modules
202
   'moduleDirs' => [], # search paths for modules
185
   'scriptDirs' => [], # search paths for scripts
203
   'scriptDirs' => [], # search paths for scripts
186
   'clientName' => '',  # Required!! Must be set in conf file (no defaults)
204
   'clientName' => '',  # Required!! Must be set in conf file (no defaults)
187
   'serialNumber' => '', # serial number of machine
205
   'serialNumber' => '', # serial number of machine
188
   'UUID'         => '', # UUID of machine
206
   'UUID'         => '', # UUID of machine
Line 192... Line 210...
192
;
210
;
193
 
211
 
194
my $DATA_VERSION = '3.0.0'; # used in sending the data file. sets version of XML/YAML data file
212
my $DATA_VERSION = '3.0.0'; # used in sending the data file. sets version of XML/YAML data file
195
 
213
 
196
 
214
 
-
 
215
# function to simply things
-
 
216
# first parameter is the priority, if <= $logDef->{'log level'} will print
-
 
217
# all subsequent parameters assumed to be strings to sent to the log
-
 
218
# returns 0 on failure
-
 
219
#         1 on success
-
 
220
#         2 if priority > log level
-
 
221
#        -1 if $logDef is unset
-
 
222
# currently, only logs to a file
-
 
223
sub logIt {
-
 
224
   my $priority = shift;
-
 
225
 
-
 
226
   return -1 unless exists $configuration{'logging'};
-
 
227
   return 2 unless $priority <= $configuration{'logging'}{'log level'};
-
 
228
   if ( $configuration{'logging'}{'log type'} eq 'file' ) {
-
 
229
      if ( open LOG, '>>' . $configuration{'logging'}{'log path'} ) {
-
 
230
         while ( my $t = shift ) {
-
 
231
            print LOG &timeStamp() . "\t$t\n";
-
 
232
         }
-
 
233
         close LOG;
-
 
234
      }
-
 
235
   } else {
-
 
236
      warn "Log type $configuration{'logging'} incorrectly configured\n";
-
 
237
      return 0;
-
 
238
   }
-
 
239
   return 1;
-
 
240
}
-
 
241
 
197
 
242
 
198
#######################################################
243
#######################################################
199
#
244
#
200
# findFile( $filename, @directories )
245
# findFile( $filename, @directories )
201
#
246
#
Line 225... Line 270...
225
# Parameters: configuration file fully path/file name
270
# Parameters: configuration file fully path/file name
226
# NOTE: conf file must be a valid Perl file
271
# NOTE: conf file must be a valid Perl file
227
#
272
#
228
#######################################################
273
#######################################################
229
 
274
 
230
sub loadConfigurationFile {
275
sub loadConfigurationFile {   
231
   my ( $fileName, @searchPath ) = @_;
276
   my ( $fileName, @searchPath ) = @_;
232
   my $confFile;
277
   my $confFile;
233
   if ( $confFile = &findFile( $fileName, \@searchPath ) ) {
278
   if ( $confFile = &findFile( $fileName, \@searchPath ) ) {
234
      print "Opening configuration from $confFile\n" if $TESTING > 2;
279
      &logIt( 2, "Opening configuration from $confFile" );
235
      my $yaml = YAML::Tiny->read( $confFile );
280
      my $yaml = YAML::Tiny->read( $confFile );
-
 
281
      &logIt( 4, "Opening configuration from $confFile" );
236
      return $yaml->[0];
282
      return $yaml->[0];
237
   }
283
   }
238
   die "Can not find $fileName in any of " . join( "\n\t", @searchPath ) . "\n";
284
   die "Can not find $fileName in any of " . join( "\n\t", @searchPath ) . "\n";
239
}
285
}
240
 
286
 
Line 265... Line 311...
265
# would then be sent via e-mail to an administrative account, possibly root
311
# would then be sent via e-mail to an administrative account, possibly root
266
#
312
#
267
#######################################################
313
#######################################################
268
sub sendResults {
314
sub sendResults {
269
   my ( $globals, $transports, $message, $scriptDirectory ) = @_;
315
   my ( $globals, $transports, $message, $scriptDirectory ) = @_;
270
#   die Dumper( $transports );
316
   &logIt( 3, "Entering sendResults" );
271
   foreach my $key ( sort { $a <=> $b } %$transports ) {
317
   foreach my $key ( sort { $a <=> $b } %$transports ) {
272
      if ( $transports->{$key}->{'sendScript'} ) {
318
      if ( $transports->{$key}->{'sendScript'} ) {
273
         print "Trying to find file " . $transports->{$key}->{'sendScript'} . " in " . join( "\n\t", @{$scriptDirectory} ) . "\n" if $TESTING > 2;;
319
         &logIt( 3, "Trying to find file " . $transports->{$key}->{'sendScript'} . " in " . join( "\n\t", @{$scriptDirectory} ) );
274
         my $sendScript = &findFile( $transports->{$key}->{'sendScript'}, $scriptDirectory );
320
         my $sendScript = &findFile( $transports->{$key}->{'sendScript'}, $scriptDirectory );
275
         if ( $sendScript ) {
321
         if ( $sendScript ) {
276
            # load the chosen script into memory
322
            # load the chosen script into memory
277
            require $sendScript;
323
            require $sendScript;
278
            # merge the globals in
324
            # merge the globals in
279
            while ( my ( $gkey, $value ) = each %$globals ) { 
325
            while ( my ( $gkey, $value ) = each %$globals ) { 
280
               $transports->{$key}->{$gkey} = $value; 
326
               $transports->{$key}->{$gkey} = $value; 
281
            }
327
            }
282
            # do variable substitution for any values which need it
328
            # do variable substitution for any values which need it
283
            foreach my $thisOne ( keys %{$transports->{$key}} ) {
329
            foreach my $thisOne ( keys %{$transports->{$key}} ) {
284
               print "$thisOne\n" if $TESTING > 3;
330
               &logIt( 4, "$thisOne" );
285
               if ( $transports->{$key}->{$thisOne} =~ m/(\$configuration\{'hostname'\})|(\$reportDate)|(\$configuration\{'clientName'\})|(\$configuration\{'serialNumber'\})/ ) {
331
               if ( $transports->{$key}->{$thisOne} =~ m/(\$configuration\{'hostname'\})|(\$reportDate)|(\$configuration\{'clientName'\})|(\$configuration\{'serialNumber'\})/ ) {
286
                  $transports->{$key}->{$thisOne} = eval "\"$transports->{$key}->{$thisOne}\"";
332
                  $transports->{$key}->{$thisOne} = eval "\"$transports->{$key}->{$thisOne}\"";
287
               }
333
               }
288
            }
334
            }
289
            
335
            
290
            #%$transports{$key}{keys %$globals} = values %$globals;
336
            #%$transports{$key}{keys %$globals} = values %$globals;
291
            #print Dumper( $$transports[$key] );
337
            #print Dumper( $$transports[$key] );
292
            #next;
338
            #next;
293
            # execute the "doit" sub from that script
339
            # execute the "doit" sub from that script
294
            if ( $TESTING > 3 ) {
-
 
295
               print $message;
340
            &logIt( 3, $message );
296
            } else {
-
 
297
               my $return = &doit( $transports->{$key}, $message );
341
            my $return = &doit( $transports->{$key}, $message );
298
               return $return if ( $return == 1 );
342
            return $return if ( $return == 1 );
299
            }
-
 
300
         } else {
343
         } else {
301
            print "Could not find " . $$transports[$key]{'sendScript'} . ", trying next transport\n";
344
            &logIt( 0,"Could not find " . $$transports[$key]{'sendScript'} . ", trying next transport" );
302
         } # if..else
345
         } # if..else
303
      } # if
346
      } # if
304
   } # foreach
347
   } # foreach
305
   # if we made it here, we have not sent the report, so just return it to the user
348
   # if we made it here, we have not sent the report, so just return it to the user
306
   # if called from a cron job, it will (hopefully) be sent to root
349
   # if called from a cron job, it will (hopefully) be sent to root
-
 
350
   &logIt( 0, 'Error, reached ' . __LINE__ . " which should not happen, message was\n$message" );
307
   print $message;
351
   print $message;
308
   return 1;
352
   return 1;
309
}
353
}
310
 
354
 
311
#######################################################
355
#######################################################
312
#
356
#
313
# getReportDate
-
 
314
#
-
 
315
# return current system date as YYYY-MM-DD HH:MM:SS
-
 
316
#
-
 
317
#######################################################
-
 
318
sub getReportDate {
-
 
319
   my ($second, $minute, $hour, $dayOfMonth, $month, $year) = localtime();
-
 
320
   return sprintf( "%4u-%02u-%02u %02u:%02u:%02u", $year+1900, $month+1, $dayOfMonth, $hour, $minute, $second );
-
 
321
}
-
 
322
 
-
 
323
#######################################################
-
 
324
#
-
 
325
# getHostName
357
# getHostName
326
#
358
#
327
# return hostname from hostname -f
359
# return hostname from hostname -f
328
#
360
#
329
#######################################################
361
#######################################################
330
sub getHostName {
362
sub getHostName {
-
 
363
   &logIt( 3, "Entering getHostName" );
331
   my $hostname = `hostname -f`;
364
   my $hostname = `hostname -f`;
332
   chomp $hostname;
365
   chomp $hostname;
333
   return $hostname;
366
   return $hostname;
334
}
367
}
335
 
368
 
Line 418... Line 451...
418
#
451
#
419
#
452
#
420
#######################################################
453
#######################################################
421
sub tabDelimitedToHash {
454
sub tabDelimitedToHash {
422
   my ($hashRef, $tabdelim) = @_;
455
   my ($hashRef, $tabdelim) = @_;
-
 
456
   &logIt( 3, "Entering tabDelimitedToHash" );
423
   foreach my $line ( split( "\n", $tabdelim ) ) { # split on newlines, then process each line in turn
457
   foreach my $line ( split( "\n", $tabdelim ) ) { # split on newlines, then process each line in turn
424
      $line =~ s/'/\\'/gi; # escape single quotes
458
      $line =~ s/'/\\'/gi; # escape single quotes
425
      my @fields = split( / *\t */, $line ); # get all the field values into array
459
      my @fields = split( / *\t */, $line ); # get all the field values into array
426
      my $theValue = pop @fields; # the last one is the value, so save it
460
      my $theValue = pop @fields; # the last one is the value, so save it
427
      # now, we build a Perl statement that would create the assignment. The goal is
461
      # now, we build a Perl statement that would create the assignment. The goal is
Line 449... Line 483...
449
#
483
#
450
#######################################################
484
#######################################################
451
 
485
 
452
sub validatePermission {
486
sub validatePermission {
453
   my $file = shift;
487
   my $file = shift;
-
 
488
   &logIt( 3, "Entering validatePermission with $file" );
454
   my $return;
489
   my $return;
455
   # must be owned by root
490
   # must be owned by root
456
   my $owner = (stat($file))[4];
491
   my $owner = (stat($file))[4];
457
   $return .= " - Bad Owner [$owner]" if $owner;
492
   $return .= " - Bad Owner [$owner]" if $owner;
458
   # must not have any permissions for group or world
493
   # must not have any permissions for group or world
Line 482... Line 517...
482
# on failure, the returned output of the script is assumed to be an error message
517
# on failure, the returned output of the script is assumed to be an error message
483
# and is displayed on STDERR
518
# and is displayed on STDERR
484
#######################################################
519
#######################################################
485
sub ProcessModules {
520
sub ProcessModules {
486
   my ( $system, $moduleDir ) = @_;
521
   my ( $system, $moduleDir ) = @_;
-
 
522
   &logIt( 3, "Entering processModules" );
487
   # open the module directory
523
   # open the module directory
488
   return unless -d $moduleDir;
524
   return unless -d $moduleDir;
489
   opendir( my $dh, $moduleDir ) || die "Module Directory $moduleDir can not be opened: $!\n";
525
   opendir( my $dh, $moduleDir ) || die "Module Directory $moduleDir can not be opened: $!\n";
490
   # and get all files which are executable and contain nothing but alpha-numerics and underscores (must begin with alpha-numeric)
526
   # and get all files which are executable and contain nothing but alpha-numerics and underscores (must begin with alpha-numeric)
491
   my @modules = grep { /^[a-zA-Z0-9][a-zA-Z0-9_]+$/ && -x "$moduleDir/$_" } readdir( $dh );
527
   my @modules = grep { /^[a-zA-Z0-9][a-zA-Z0-9_]+$/ && -x "$moduleDir/$_" } readdir( $dh );
Line 493... Line 529...
493
   foreach my $modFile ( sort @modules ) { # for each valid script
529
   foreach my $modFile ( sort @modules ) { # for each valid script
494
      if ( my $error = &validatePermission( "$moduleDir$modFile" ) ) {
530
      if ( my $error = &validatePermission( "$moduleDir$modFile" ) ) {
495
         print STDERR "Not Processed: $error\n";
531
         print STDERR "Not Processed: $error\n";
496
         next;
532
         next;
497
      }
533
      }
498
      print "Processing module $moduleDir$modFile\n" if $TESTING > 2;
534
      &logIt( 3, "Processing module $moduleDir$modFile");
499
      my $output = qx/$moduleDir$modFile $moduleDir/; # execute it and grab the output
535
      my $output = qx/$moduleDir$modFile $moduleDir/; # execute it and grab the output
500
      my $exitCode = $? >> 8; # process the exitCode
536
      my $exitCode = $? >> 8; # process the exitCode
501
      # exitCode 0 - processed normally
537
      # exitCode 0 - processed normally
502
      # exitCode 1 - not applicable to this machine
538
      # exitCode 1 - not applicable to this machine
503
      if ( $exitCode && $exitCode > 1) { # if non-zero, error, so show an error message
539
      if ( $exitCode && $exitCode > 1) { # if non-zero, error, so show an error message
504
         warn "Error in $moduleDir$modFile, [$output]\n";
540
         warn "Error in $moduleDir$modFile, [$output]\n";
-
 
541
         &logIt( 0, "Error in $moduleDir$modFile, [$output]" );
505
      } else { # otherwise, call tabDelimitedToHash to save the data
542
      } else { # otherwise, call tabDelimitedToHash to save the data
506
         &tabDelimitedToHash( $system, $output );
543
         &tabDelimitedToHash( $system, $output );
507
      } # if
544
      } # if
508
   } # foreach
545
   } # foreach
509
   # add sysinfo-client (me) to the software list, since we're obviously installed
546
   # add sysinfo-client (me) to the software list, since we're obviously installed
Line 520... Line 557...
520
}
557
}
521
 
558
 
522
&processParameters( @ARGV );
559
&processParameters( @ARGV );
523
 
560
 
524
# load the configuration file
561
# load the configuration file
525
 
-
 
526
#die "Searching for $configurationFile in = \n" . join( "\n", @confFileSearchPath ) . "\n";
-
 
527
%configuration = %{ &loadConfigurationFile( $configurationFile, @confFileSearchPath) };
562
%configuration = %{ &loadConfigurationFile( $configurationFile, @confFileSearchPath) };
528
#eval ( &loadConfigurationFile( $configurationFile, @confFileSearchPath) ) or die "Could not load config: $@\n";
-
 
529
die Dumper( \%configuration ) . "\n" if $TESTING > 4;
-
 
530
 
563
 
531
# user did not define a serial number, so make something up
564
# user did not define a serial number, so make something up
532
$configuration{'serialNumber'} = '' unless $configuration{'serialNumber'};
565
$configuration{'serialNumber'} = '' unless $configuration{'serialNumber'};
533
# oops, no client name (required) so tell them and exit
566
# oops, no client name (required) so tell them and exit
534
die "No client name defined in $configurationFile" unless $configuration{'clientName'};
567
die "No client name defined in $configurationFile" unless $configuration{'clientName'};
535
 
568
 
-
 
569
&logIt( 0, 'Starting sysinfo Run' );
-
 
570
&logIt( 3, "Configuration is\n" . Data::Dumper->Dump( [\%configuration], [ qw($configuration) ] ) );
-
 
571
 
536
$TESTING = $configuration{'TESTING'} if defined $configuration{'TESTING'};
572
$TESTING = $configuration{'TESTING'} if defined $configuration{'TESTING'};
537
 
573
 
538
print "Testing => $TESTING\n" if $TESTING;
574
&logIt( 0, "Testing => $TESTING" ) if $TESTING;
539
 
575
 
540
 
576
 
541
my $System; # hash reference that will store all info we are going to send to the server
577
my $System; # hash reference that will store all info we are going to send to the server
542
# some defaults.
578
# some defaults.
543
$$System{'report'}{'version'} = $DATA_VERSION;
579
$System->{'report'}->{'version'} = $DATA_VERSION;
544
$$System{'report'}{'date'} = $reportDate;
580
$System->{'report'}->{'date'} = $reportDate;
545
$$System{'report'}{'client'} = $configuration{'clientName'};
581
$System->{'report'}->{'client'} = $configuration{'clientName'};
546
$$System{'system'}{'hostname'} = $configuration{'hostname'};
582
$System->{'system'}->{'hostname'} = $configuration{'hostname'};
547
$$System{'system'}{'serial'} = $configuration{'serialNumber'};
583
$System->{'system'}->{'serial'} = $configuration{'serialNumber'};
548
$$System{'system'}{'UUID'} = $configuration{'UUID'};
584
$System->{'system'}->{'UUID'} = $configuration{'UUID'};
-
 
585
 
-
 
586
&logIt( 3, "Initial System\n" . Data::Dumper->Dump( [$System], [qw( $System )] ) );
549
 
587
 
550
# process any modules in the system
588
# process any modules in the system
551
foreach my $moduleDir ( @{$configuration{'moduleDirs'}} ) {
589
foreach my $moduleDir ( @{$configuration{'moduleDirs'}} ) {
-
 
590
   &logIt( 3, "Processing modules from $moduleDir" );
552
   &ProcessModules( $System, "$moduleDir/" );
591
   &ProcessModules( $System, "$moduleDir/" );
553
}
592
}
554
 
593
 
-
 
594
&logIt( 4, "After processing modules\n" . Data::Dumper->Dump( [$System], [qw( $System )] ) );
-
 
595
 
555
# now, everything ins in $System, so convert it to the proper output format
596
# now, everything ins in $System, so convert it to the proper output format
556
#my $out = "#sysinfo: $VERSION YAML\n---\n" . &hashToYAML( $System ) . "...\n";
597
#my $out = "#sysinfo: $VERSION YAML\n---\n" . &hashToYAML( $System ) . "...\n";
557
 
598
 
558
my $out =  "#sysinfo: $VERSION YAML\n" . Dump( $System );
599
my $out =  "#sysinfo: $VERSION YAML\n" . Dump( $System );
559
 
600
 
560
#print Data::Dumper->Dump([$System],['System']) if $TESTING>2;
601
&logIt( 4, 'At line number ' . __LINE__ . "\n" . Data::Dumper->Dump([$System],[qw($System)]) );
561
 
602
 
562
# load some global values for use in the script, if required
603
# load some global values for use in the script, if required
563
my $globals = { 
604
my $globals = { 
564
      'data version' => $DATA_VERSION,
605
      'data version' => $DATA_VERSION,
565
      'report date'  => $reportDate,
606
      'report date'  => $reportDate,
Line 567... Line 608...
567
      'host name'    => $configuration{'hostname'},
608
      'host name'    => $configuration{'hostname'},
568
      'serial number'=> $configuration{'serialNumber'},
609
      'serial number'=> $configuration{'serialNumber'},
569
      'UUID'         => $configuration{'UUID'}
610
      'UUID'         => $configuration{'UUID'}
570
      };
611
      };
571
 
612
 
-
 
613
&logIt( 4, "Globals initialized\n" . Data::Dumper->Dump([$globals],[qw($globals)]) );
-
 
614
 
-
 
615
if ( $TESTING ) {
-
 
616
   open DATA, ">/tmp/sysinfo.testing.yaml" or die "Could not write to /tmp/sysinfo.testing.yaml: $!\n";
-
 
617
   print DATA $out;
-
 
618
   close DATA;
-
 
619
} else {
572
# and send the results to the server
620
   # and send the results to the server
573
if ( my $success = &sendResults( $globals, $configuration{'transports'}, $out, $configuration{'scriptDirs'} ) != 1 ) {
621
   if ( my $success = &sendResults( $globals, $configuration{'transports'}, $out, $configuration{'scriptDirs'} ) != 1 ) {
574
   print "Error $success while sending report from $configuration{'hostname'}\n";
622
      &logIt( 0, "Error $success while sending report from $configuration{'hostname'}" );
-
 
623
   }
575
}
624
}
576
 
625
 
-
 
626
&logIt( 0, 'Ending sysinfo Run' );
-
 
627
 
577
1;
628
1;