Subversion Repositories camp_sysinfo_client_3

Rev

Rev 125 | Rev 132 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
21 rodolico 1
#!/usr/bin/env perl
2
 
45 rodolico 3
# v1.2.0 20161022 RWR
4
# moved makeConfig here so it is usable by install and configure
77 rodolico 5
#
6
# v1.3.0 20190108 RWR
7
# added UUID and set defaults for config file
85 rodolico 8
#
9
# v1.4.0 20190204 RWR
10
# added autoconvert from v1.2 configuration file to v1.3
11
# using dumper to set configuration file
94 rodolico 12
#
13
# version 2.0 20190330 RWR
14
# changed it so all configs are YAML
125 rodolico 15
#
16
# version 2.1 20191101 RWR
17
# changed --name-- tag to name
129 rodolico 18
#
19
# version 2.2 20191105 RWR
20
# fixed where dmidecode missing caused exception
45 rodolico 21
 
21 rodolico 22
package sysinfoconf;
23
 
42 rodolico 24
 
129 rodolico 25
our $VERSION = '2.2';
21 rodolico 26
use warnings;
26 rodolico 27
use strict;  
28
 
92 rodolico 29
#use Data::Dumper;
129 rodolico 30
eval( 'use YAML::Tiny' );
31
#use YAML::Tiny;
35 rodolico 32
use File::Basename;
33
 
21 rodolico 34
use Exporter;
35
 
36
our @ISA = qw( Exporter );
37
our @EXPORT = qw( $clientName $serialNumber $hostname @moduleDirs @scriptDirs 
44 rodolico 38
                  $transports $sysinfo3 %sendTypes $binDir $moduleDir
39
                  $scriptDir $confDir $binName $confName
21 rodolico 40
                  &showConf &transportsToConfig &getAnswer &yesno  
35 rodolico 41
                  &writeConfig &processParameters $TESTING &checkDirectoryExists
115 rodolico 42
                  &runCommand &setDryRun &enableModules &makeConfig &findConf
21 rodolico 43
                );
44
 
36 rodolico 45
our $TESTING = 0;
35 rodolico 46
our $dryRun;
28 rodolico 47
our $clientName = '';
48
our $serialNumber = '';
49
our $hostname = '';
53 rodolico 50
 
104 rodolico 51
 
52
 
53 rodolico 53
my @installDirs = ( '/opt/camp/sysinfo-client', '/usr/local/opt/camp/sysinfo-client' );
54
my @confDirs =    ( '/etc/camp/sysinfo-client', '/usr/local/etc/camp/sysinfo-client' );
55
 
56
 
28 rodolico 57
our @moduleDirs = ( '/opt/camp/sysinfo-client/modules', '/etc/camp/sysinfo-client/modules' );
58
our @scriptDirs = ( '/opt/camp/sysinfo-client/scripts', '/etc/camp/sysinfo-client/scripts' );
111 rodolico 59
our $transports = {}; # holds transportation mechanisms
21 rodolico 60
 
103 rodolico 61
our $sysinfo3 = 'sysinfo-client.yaml';
21 rodolico 62
 
28 rodolico 63
our $binDir = '/opt/camp/sysinfo-client';
44 rodolico 64
our $moduleDir = $binDir . '/modules';
65
our $scriptDir = $binDir . '/scripts';
28 rodolico 66
our $confDir = '/etc/camp/sysinfo-client';
21 rodolico 67
 
28 rodolico 68
our $binName = 'sysinfo-client';
107 rodolico 69
our $confName = 'sysinfo-client.yaml';
21 rodolico 70
 
35 rodolico 71
sub setDryRun {
72
   $dryRun = shift;
73
}
21 rodolico 74
 
28 rodolico 75
our %sendTypes = ( 
21 rodolico 76
                  'SendEmail' =>    { 'sendScript' => 'sendEmailScript',
77
                                      'keys' => 
78
                                      [
79
                                        'mailTo',
80
                                        'mailSubject',
81
                                        'mailCC',
82
                                        'mailBCC',
83
                                        'mailServer',
84
                                        'mailFrom',
85
                                        'logFile',
86
                                        'otherCLParams',
87
                                        'tls',
88
                                        'smtpUser',
89
                                        'smtpPass',
90
                                        'sendEmailScriptLocation'
91
                                      ],
92
                                    },
93
                  'HTTP Upload' =>  { 'sendScript' => 'upload_http',
94
                                      'keys' => 
95
                                      [
96
                                        'URL',
97
                                        'key for report',
98
                                        'key for date',
99
                                        'key for hostname',
100
                                        'key for client',
101
                                        'key for serial number'
102
                                      ]
86 rodolico 103
                                    },
104
                  'Save Local' =>   { 'sendScript' => 'save_local',
105
                                      'keys' =>
106
                                      [
107
                                         'output directory'
108
                                      ]
109
                                   }
21 rodolico 110
                );
111
 
112
 
37 rodolico 113
sub enableModules {
114
   my $moduleDir = shift;
115
   my %modules;
116
   if ( opendir( my $dh, "$moduleDir" ) ) {
117
      %modules = map{ $_ => { 'enabled' => -x "$moduleDir/$_" } } 
118
                 grep { ! /^\./ } 
119
                 readdir $dh;
120
      closedir( $dh );
121
      foreach my $filename ( keys %modules ) {
122
         if ( open FILE,"<$moduleDir/$_" ) {
123
            my @descript = grep{ /^# Description: (.*)/ } <FILE>;
124
            close FILE;
125
            chomp @descript;
126
            $modules{$filename}{'description'} = $descript[0];
127
         } # if
128
      } # foreach
129
   } # if
130
} # enableModules
131
 
21 rodolico 132
sub showConf {
81 rodolico 133
 
35 rodolico 134
   my $configuration = shift;
92 rodolico 135
   $configuration = Dump($configuration);
84 rodolico 136
   return $configuration;
21 rodolico 137
}
138
 
139
sub transportsToConfig {
35 rodolico 140
   my $transports = shift;
21 rodolico 141
   my $config;
142
   foreach my $priority ( sort { $a <=> $b } keys %$transports ) {
124 rodolico 143
      my $name = $$transports{ $priority }{'name'};
21 rodolico 144
      $config .= "# Tranport $name at priority $priority\n";
145
      my $thisOne = $$transports{ $priority };
146
      foreach my $key ( sort keys %$thisOne ) {
147
         $config .= "\$\$transports{$priority}{'$key'} = '$$thisOne{$key}';\n";
148
      } # foreach
149
   } # foreach
150
   return $config;
151
} # transportsToConfig
152
 
94 rodolico 153
 
154
# read the configuration file passed in and return a reference to it
155
# to the calling routine
156
sub readConfig {
157
   my $filename = shift;
158
   my $config;
159
   return $config unless -e $filename;
160
   if ( open CONF,"<$filename" ) {
161
      my $contents = join( '', <CONF> );
162
      close CONF;
163
      # now, look to see what kind of file this is.
164
      if ( $contents =~ m/^---(\s*#.*)?$/m ) {
165
         print "Reading $filename as YAML\n";
166
         #print "Contents are:\n\n=====================$contents\n=====================\n";
167
         # this is a yaml file
168
         #$contents = YAML::Tiny->read( $config );
169
         $config = Load( $contents );
170
      } elsif ( $contents =~ m/\$clientName/ ) {
171
         # this is old style
172
         print "Reading $filename as old school file\n";
173
         my $clientName = '';
174
         my $serialNumber = '';
175
         my $hostname = '';
176
         my @moduleDirs;
177
         my @scriptDirs;
178
         my $UUID = '';
179
         my $transports;
180
         # now, eval the information we just read.
181
         # NOTE: we must turn off strict while doing this, and we die if something breaks.
182
         no strict "vars";
183
         eval( $contents );
184
         use strict "vars";
185
         die "Error during eval: $@\n" if $@;
186
         $config->{'clientName'} = $clientName if $clientName;
187
         $config->{'serialNumber'} = $serialNumber if $serialNumber;
188
         $config->{'UUID'} = $UUID unless $config->{'UUID'};
189
         $config->{'hostname'} = $hostname if $hostname;
190
         $config->{'moduleDirs'} = [ @moduleDirs ] if @moduleDirs;
191
         $config->{'scriptDirs'} = [ @scriptDirs ] if @scriptDirs;
192
         $config->{'transports'} = $transports if $transports;
129 rodolico 193
         foreach my $trans ( keys %{$config->{'transports'}} ) {
194
            if ( exists ( $config->{'transports'}->{$trans}->{'-name-'} ) ) {
195
               $config->{'transports'}->{$trans}->{'name'} = $config->{'transports'}->{$trans}->{'-name-'};
196
               delete( $config->{'transports'}->{$trans}->{'-name-'} );
197
            }
198
         }
94 rodolico 199
      }
200
   } else {
201
         warn "Could not read config file $filename, skipped: $!\n";
202
   }
203
   return $config;
204
}
205
 
45 rodolico 206
sub makeConfig {
207
   my @configFileNames = @_;
208
   my %config;
209
 
210
   foreach my $config ( @configFileNames ) {
129 rodolico 211
      my $thisConfig = &readConfig( $config ) if $config && -e $config;
94 rodolico 212
      # add the new config to %config, overwriting any existing keys which are duplicated
213
      @config{keys %$thisConfig} = values %$thisConfig;
45 rodolico 214
   }
94 rodolico 215
   # now, ensure the correct values are loaded in some areas
81 rodolico 216
   unless ( $config{'hostname'} ) {
45 rodolico 217
      $hostname = `hostname -f`;
218
      chomp $hostname;
81 rodolico 219
      $config{'hostname'} = $hostname;
45 rodolico 220
   }
84 rodolico 221
   unless ( $config{'serialNumber'} ) {
53 rodolico 222
      $serialNumber = `dmidecode -t 1 | grep 'Serial Number' | cut -d':' -f2` if `which dmidecode`;
223
      chomp $serialNumber;
224
      $serialNumber =~ s/\s//gi;
84 rodolico 225
      $config{'serialNumber'} = $serialNumber;
53 rodolico 226
   }
81 rodolico 227
   unless ( $config{'UUID'} ) {
129 rodolico 228
      my $UUID = `which dmidecode` ?  `dmidecode -t 1 | grep -i uuid | cut -d':' -f2` : '';
77 rodolico 229
      $UUID =~ s/\s//gi;
81 rodolico 230
      $config{'UUID'} = $UUID;
77 rodolico 231
   }
45 rodolico 232
 
110 rodolico 233
   # ensure we have the default SaveLocal transport defined
234
   unless ( defined $config{'transports'}{'99'} ) {
235
      $config{'transports'}{'99'} = {
236
                         'name'=> 'SaveLocal',
237
                         'output directory' => '/tmp',
238
                         'sendScript' => 'save_local'
239
                        };
240
   }
241
 
45 rodolico 242
   return \%config;
243
}
244
 
21 rodolico 245
# prompt the user for a response, then allow them to enter it
246
# the first response is considered the default and is printed
247
# in all caps if more than one exists
248
# first answer is used if they simply press the Enter
249
# key. The response is returned all lower case if more than one
250
# exists.
251
# it is assumed 
252
sub getAnswer {
253
   my ( $prompt, @answers ) = @_;
254
   $answers[0] = '' unless defined( $answers[0] );
255
   my $default = $answers[0];
256
   my $onlyOneAnswer = scalar( @answers ) == 1;
257
   print $prompt . '[ ';
258
   $answers[0] = uc $answers[0] unless $onlyOneAnswer;
259
   print join( ' | ', @answers ) . ' ]: ';
28 rodolico 260
   my $thisAnswer = <>;
21 rodolico 261
   chomp $thisAnswer;
262
   $thisAnswer = $default unless $thisAnswer;
263
   return $thisAnswer;
264
}
265
 
266
sub yesno {
40 rodolico 267
   my ( $prompt, $default ) = @_;
268
   $default = 'yes' unless $default;
269
   my $answer = &getAnswer( $prompt, $default eq 'yes' ? ('yes','no' ) : ('no', 'yes') );
21 rodolico 270
   return lc( substr( $answer, 0, 1 ) ) eq 'y';
271
}
272
 
35 rodolico 273
# runs a system command. Also, if in testing mode, simply shows what
274
# would have been done.
275
sub runCommand {
276
   while ( my $command = shift ) {
277
      if ( $dryRun ) {
278
         print "$command\n";
279
      } else {
280
         `$command`;
281
      }
282
   }
283
   return 1;
284
} # runCommand
285
 
286
# checks if a directory exists and, if not, creates it
287
my %directories; # holds list of directories already created so no need to do an I/O
288
 
289
sub checkDirectoryExists {
290
   my ( $filename,$mod,$owner ) = @_;
291
   $mod = "0700" unless $mod;
292
   $owner = "root:root" unless $owner;
293
   print "Checking Directory for $filename with $mod and $owner\n" if $TESTING > 2;
294
   my ($fn, $dirname) = fileparse( $filename );
295
   print "\tParsing out $dirname and $filename\n" if $TESTING > 2;
296
   return '' if exists $directories{$dirname};
297
   if ( -d $dirname ) {
298
      $directories{$dirname} = 1;
299
      return '';
300
   }
301
   if ( &runCommand( "mkdir -p $dirname", "chmod $mod $dirname", "chown $owner $dirname" ) ) {
302
      $directories{$dirname} = 1;
303
   }
304
   return '';   
305
}
306
 
21 rodolico 307
sub writeConfig {
35 rodolico 308
   my ( $filename,$content ) = @_;
129 rodolico 309
   if ( $filename ) { # they sent us a filename
310
      my $path;
311
      ($filename, $path ) = fileparse( $filename );
312
      `mkdir -p $path` unless -d $path;
313
      $filename = $path . '/' . $filename;
21 rodolico 314
      `cp $filename $filename.bak` if ( -e $filename );
129 rodolico 315
      unless ( $dryRun ) {
316
         open CONF,">$filename" or die "Could not write to $filename: $!\n";
317
         print CONF $content;
318
         close CONF;
319
         `chmod 600 $filename`;
320
      }
321
   } else { # no path provided, so just create a temp file
322
      # we will create a temporary file and return the name
323
      # it is the calling programs responsiblity to remove the file
324
      my $fh;
325
      ($fh,$filename) = tempfile( UNLINK => 0 );
326
      print $fh $content;
327
      close $fh
21 rodolico 328
   }
129 rodolico 329
   return $filename;
21 rodolico 330
}
331
 
332
sub processParameters {
333
   while ( my $parameter = shift ) {
334
      if ( $parameter eq '-v' ) {
26 rodolico 335
         print "$VERSION\n";
21 rodolico 336
         exit;
337
      }
338
   } # while
339
}
340
 
53 rodolico 341
sub findConf {
342
   my $confName = shift;
343
   for ( my $i = 0; $i < @confDirs; $i++ ) {
344
      if ( -d $confDirs[ $i ] ) {
55 rodolico 345
         return ( $confDirs[$i],  $confName );
53 rodolico 346
      }
347
   }
104 rodolico 348
   return ( '', $confName );
53 rodolico 349
}
21 rodolico 350
 
104 rodolico 351
 
352
 
353
 
21 rodolico 354
1;