auto scroll after unlinking port
[racktables-contribs] / yaml_import / ask-4rt+yaml.pl
1 #!/usr/bin/perl
2 #
3 # Copyright (C) 2011 PSMN / ENS de Lyon - LT
4 # This script is licenced under CeCILL, see COPYING
5 # or http://www.cecill.info/ (french GPL v2 equivalent)
6 #
7 # $Id: ask-4rt+yaml.pl 112 2011-06-14 13:50:09Z gruiick $
8 #
9 # Authors
10 # . Loïs Taulelle <lois dot taulelle at ens-lyon dot fr>
11 #
12 # Parameters understood:
13 # [hostbase] : the base of hostname (ex: dl165lin)
14 # [start] : numerotation start (ex: 10)
15 # [end] : the end... this is the end (ex: 82)
16 # => process a list from dl165lin10 to dl165lin82
17 # or
18 # [hostname] & --uniq : when there's only one host to deal with
19 #
20 # Environment:
21 # Unix only, need following CPAN modules:
22 # YAML::Tiny Log::Logger File::Tools (for File::Basename File::Copy File::Path)
23 # File::List Parse::DMIDecode
24 #
25 # Configuration:
26 # yes, see $debug and $log variables
27 #
28 use strict;
29 use warnings;
30 use YAML::Tiny;
31 use Log::Logger;
32 #use File::Tools;
33 use File::Basename;
34 use File::Copy;
35 use File::Path;
36 use File::List;
37 use Parse::DMIDecode ();
38
39 ## Create objects and set environment
40 # Configuration
41 my $log = "no"; # yes|no
42 my $debug = "yes"; # yes|no
43 my $fqdn = "ens-lyon.fr";
44
45 # global scalars & objects
46 my $scriptname = basename($0, ".pl");
47 my $hostbase = "";
48 my $start = "";
49 my $end = "";
50 my $uniqueness = "";
51 my @hostArray =();
52 my $dmi_decoder = Parse::DMIDecode->new();
53 my $yaml = YAML::Tiny->new;
54
55 # init logs
56 my $logline = new Log::Logger;
57 my $logfile = "";
58 if ( $log eq "yes" )
59 {
60 $logfile = "$scriptname.log";
61 print ("There will be logs: $logfile \n\n");
62 }
63 else
64 {
65 # TODO verbose and silent mode ?
66 $logfile = "/dev/null";
67 print ("no logs! \n");
68 }
69 $logline->open_append("$logfile");
70 my $date = &getDate();
71 $logline->log_print("\t Job start at $date \n");
72
73 # init debug
74 if ( $debug eq "yes" )
75 {
76 use Data::Dumper;
77 $logline->log_print("\t DEBUG MODE ON \n");
78 }
79
80
81 ## main program
82 # proceeding arguments
83 if ( $#ARGV == -1 or $#ARGV != 2 )
84 {
85 if ( $#ARGV == 1 )
86 {
87 if ( $ARGV[1] eq "--uniq" )
88 {
89
90 if ( $debug eq "yes" )
91 {
92 print ("Arguments: \n");
93 print Dumper(@ARGV);
94 }
95 if ( $log eq "yes" )
96 {
97 $logline->log_print("$scriptname called with: @ARGV \n");
98 }
99
100 $uniqueness = "1";
101 $hostArray[0] = $ARGV[0];
102 &main();
103 }
104 else
105 {
106 &printUsage();
107 }
108 }
109 else
110 {
111 &printUsage();
112 }
113 }
114 else # assuming $#ARGV == 2
115 {
116
117 if ( $debug eq "yes" )
118 {
119 print ("Arguments: \n");
120 print Dumper(@ARGV);
121 }
122 if ( $log eq "yes" )
123 {
124 $logline->log_print("$scriptname called with: @ARGV \n");
125 }
126
127 $hostbase = $ARGV[0];
128 $start = $ARGV[1];
129 $end = $ARGV[2];
130 $uniqueness = "0";
131 &setHostList();
132 &main();
133 }
134
135 ## subs
136
137 sub main
138 {
139 if ( $uniqueness eq "0" )
140 {
141 foreach my $i ($start .. $end)
142 {
143 my $host_os = &getOS($hostArray[$i]);
144 &getSMBios($hostArray[$i],$host_os);
145 &getIfConfig($hostArray[$i],$host_os);
146 &writeYaml($hostArray[$i]);
147 }
148 }
149 elsif ( $uniqueness eq "1" )
150 {
151 my $host_os = &getOS($hostArray[0]);
152 &getSMBios($hostArray[0],$host_os);
153 &getIfConfig($hostArray[0],$host_os);
154 &writeYaml($hostArray[0]);
155 }
156 }
157
158 sub printUsage
159 {
160 $logline->log_print("\n\t TOO FEW OR MANY ARGUMENTS! \n");
161 $logline->log_print("Usage: $scriptname.pl [hostbase] [start] [end]");
162 $logline->log_print("or");
163 $logline->fail("Usage: $scriptname.pl [hostname] --uniq");
164 }
165
166
167 sub writeYaml
168 # generate the yaml structures, and write it to yaml file
169 # take $hostArray[$i] as filename
170 # see skel.yaml
171 {
172 my $filename = (my $host = $_[0]);
173 $yaml->[0]->{name} = $_[0];
174 $yaml->[0]->{parameters}->{fqdn} = "$host.$fqdn";
175 $yaml->write( "$filename.yaml" ) || $logline->fail("\t cannot write $filename!");
176
177 if ( $debug eq "yes" )
178 {
179 print ("$filename.yaml writed successfully \n");
180 }
181 if ( $log eq "yes" )
182 {
183 $logline->log_print("$filename.yaml writed successfully \n");
184 }
185 }
186
187 sub setHostList
188 # generate the hostnames list from call arguments
189 # sub take no argument
190 {
191 for my $i ($start .. $end)
192 {
193 $hostArray[$i] = "$hostbase$i";
194
195 if ( $debug eq "yes" )
196 {
197 print ("\t $hostArray[$i] \n");
198 }
199 }
200 }
201
202 sub getOS
203 # ask host for OS release, return OS type
204 # my $os = &getOS($host);
205 {
206 my $host = $_[0];
207 my $os_internal = "sun"; # pick one, cannot be NULL.
208 my $release = "";
209 my @release_internal = qx(ssh $host cat /etc/release); # have to start with something
210
211 if ( $release_internal[0] eq "" )
212 {
213 @release_internal = qx(ssh $host cat /etc/redhat-release);
214 # TODO debian ? others ? BSD's ? LSB ?
215 # Xen/kvm/vmware/vbox has something to deal with:
216 # $yaml->[0]->{parameters}->{hypervisor} = "No|Yes";
217
218 if ( $release_internal[0] =~ /CentOS/i )
219 {
220 $os_internal = "centos";
221 $release = $release_internal[0];
222 }
223 elsif ( $release_internal[0] =~ /Red Hat/i )
224 {
225 $os_internal = "redhat";
226 $release = $release_internal[0];
227 }
228 }
229 elsif ( $release_internal[0] =~ /Solaris/i )
230 {
231 $os_internal = "sun";
232 $release = $release_internal[0];
233 }
234 $release =~ s/^\s+//; $release =~ s/\s+$//; # cleanup result
235
236 # save this to yaml
237 $yaml->[0]->{parameters}->{operatingsystem} = $release;
238 my ($digits) = $release =~ /(\d+(?:\.)?\d+)/;
239 $yaml->[0]->{parameters}->{operatingsystemrelease} = $digits;
240 $yaml->[0]->{parameters}->{hypervisor} = "No"; # fixed, for now
241
242 if ( $debug eq "yes" )
243 {
244 print ("$release, $digits\n");
245 }
246 if ( $log eq "yes" )
247 {
248 $logline->log_print("$host.$fqdn: $release, $digits\n");
249 }
250
251 return $os_internal;
252 }
253
254 sub getSMBios
255 # ask host for dmidecode information
256 # &getSMBios($host,$os);
257 {
258 my $host = $_[0];
259 my $os = $_[1];
260 my $product_name = "";
261 my $serial_number = "";
262 my $uuid = "";
263
264 if ( $os eq "sun" )
265 # Parse::dmidecode doesn't parse Oracle/Sun smbios output, so back to basics.
266 {
267 my @bios_raw = qx(ssh uroot\@$host smbios);
268 my $biosLine = "";
269 my $pn_state = (my $sn_state = (my $uu_state = "0"));
270
271 foreach $biosLine (@bios_raw)
272 {
273 if ( $biosLine =~ /Product:/ )
274 {
275 if ( $pn_state == "0" )
276 {
277 $product_name = $biosLine;
278 $product_name =~ s/\s+Product:\s+//; chomp $product_name; # cleanup
279
280 if ( $debug eq "yes" )
281 {
282 print ("$product_name \n");
283 }
284 $pn_state = "1";
285 }
286 else {next;} # don't waste time with other lines
287 }
288 elsif ( $biosLine =~ /Serial Number:/ )
289 {
290 if ( $sn_state == "0" )
291 {
292 $serial_number = $biosLine;
293 $serial_number =~ s/\s+Serial Number:\s+//; chomp $serial_number;
294
295 if ( $debug eq "yes" )
296 {
297 print ("$serial_number \n");
298 }
299 $sn_state = "1";
300 }
301 else {next;} # don't waste time with other lines
302 }
303 elsif ( $biosLine =~ /UUID:/ )
304 {
305 if ( $uu_state == "0" )
306 {
307 $uuid = $biosLine;
308 $uuid =~ s/\s+UUID:\s+//; chomp $uuid;
309
310 if ( $debug eq "yes" )
311 {
312 print ("$uuid \n");
313 }
314 $uu_state = "1";
315 }
316 else {next;} # don't waste time with other lines
317 }
318 }
319 }
320 else
321 # Welcome to Parse::dmidecode world
322 {
323 $dmi_decoder->parse( qx(ssh $host dmidecode) );
324 $product_name = $dmi_decoder->keyword("system-product-name");
325 $serial_number = $dmi_decoder->keyword("system-serial-number");
326 $uuid = $dmi_decoder->keyword("system-uuid");
327 }
328 # save this to yaml
329 $yaml->[0]->{parameters}->{productname} = $product_name;
330 $yaml->[0]->{parameters}->{serialnumber} = $serial_number;
331 $yaml->[0]->{parameters}->{uuid} = $uuid;
332
333 if ( $debug eq "yes" )
334 {
335 print ("$host: $product_name ; $serial_number ; $uuid ; $os \n");
336 }
337 if ( $log eq "yes" )
338 {
339 $logline->log_print("$host: $product_name ; $serial_number ; $uuid ; $os \n");
340 }
341 }
342
343 sub getIfConfig
344 # ask host for IPv4 IF informations
345 # &getIfConfig($host,$os);
346 {
347 my $host = $_[0];
348 my $os = $_[1];
349 my @ifname = ();
350 my @ifip = ();
351 my @iftype = (); # for future uses (maybe...)
352 my @ifmac = ();
353 my $ifNstate = (my $ifIstate = (my $ifTstate = (my $ifMstate = "0")));
354 my @ifconfigRaw = ();
355 my $ifconfigLine = "";
356 my $ifTlist = "";
357
358 if ( $os eq "sun" )
359 # specific sort/regexp for SunOS, ifconfig output's not "standard"
360 {
361 @ifconfigRaw = qx(ssh uroot\@$host ifconfig -a);
362
363 foreach $ifconfigLine (@ifconfigRaw)
364 {
365 if ( $ifconfigLine =~ /^(\S+)\:/ )
366 {
367 if ( $ifconfigLine =~ /^lo/ )
368 # interface is local, don't keep
369 {
370 next;
371 }
372 elsif ( $ifconfigLine =~ /^(\S+\:[0-9]{1})\:(\s+)/ )
373 # interface is an alias, doesn't have MAC
374 {
375 $ifname[$ifNstate] = $1;
376 $ifname[$ifNstate] =~ s/\:/\./; # ":" is yaml reserved, so we use "."
377 $iftype[$ifTstate] = "Ethernet";
378 $ifmac[$ifMstate] = $ifmac[$ifMstate-1];
379
380 if ( $debug eq "yes" )
381 {
382 print ("$host: $ifname[$ifNstate] \n");
383 print ("$host: $iftype[$ifTstate] = $ifmac[$ifMstate] \n");
384 }
385 if ( $log eq "yes" )
386 {
387 $logline->log_print("$host: $ifname[$ifNstate] ; $iftype[$ifTstate] ; $ifmac[$ifMstate] \n");
388 }
389
390 $ifNstate++;
391 $ifTstate++;
392 $ifMstate++;
393 }
394 else
395 # assume real interface
396 {
397 $ifname[$ifNstate] = $1;
398
399 if ( $debug eq "yes" )
400 {
401 print ("$host: $ifname[$ifNstate] \n");
402 }
403 if ( $log eq "yes" )
404 {
405 $logline->log_print("$host: $ifname[$ifNstate] \n");
406 }
407 $ifNstate++;
408 }
409 }
410 elsif ( $ifconfigLine =~ /inet (?:addr\:)?(\d+(?:\.\d+){3})/ )
411 {
412 if ( $1 =~ /127\.0\.0\.1/ )
413 # IP is local, don't keep
414 {
415 next;
416 }
417 else
418 {
419 $ifip[$ifIstate] = $1;
420
421 if ( $debug eq "yes" )
422 {
423 print ("$host: $ifip[$ifIstate] \n");
424 }
425 if ( $log eq "yes" )
426 {
427 $logline->log_print("$host: $ifip[$ifIstate] \n");
428 }
429 $ifIstate++;
430 }
431 }
432 elsif ( $ifconfigLine =~ /(\s+)ether(\s+)/ )
433 # real interface have MAC
434 {
435 $iftype[$ifTstate] = "Ethernet";
436 $ifconfigLine =~ s/\s+ether\s+//; chomp $ifconfigLine;
437 $ifmac[$ifMstate] = $ifconfigLine;
438 $ifmac[$ifMstate] =~ s/\s+$//; # remove trailing spaces, chomp does not make it.
439
440 if ( $debug eq "yes" )
441 {
442 print ("$host: $iftype[$ifTstate] = $ifmac[$ifMstate] \n");
443 }
444 if ( $log eq "yes" )
445 {
446 $logline->log_print("$host: $iftype[$ifTstate] ; $ifmac[$ifMstate] \n");
447 }
448 $ifTstate++;
449 $ifMstate++;
450 }
451 else {next;} # don't waste time with other lines
452 }
453 }
454 else
455 # welcome to "linux compliant" ifconfig output
456 # cpan really lacks a Parse::ifconfig :o)
457 {
458 @ifconfigRaw = qx(ssh $host ifconfig);
459
460 foreach $ifconfigLine (@ifconfigRaw)
461 {
462 if ( $ifconfigLine =~ /^(\S+)/ )
463 {
464 if ( $ifconfigLine =~ /^lo/ )
465 # interface is local, don't keep
466 {
467 next;
468 }
469 elsif ( $ifconfigLine =~ /^(\S+(?:\:)?[0-9]{1}) (\s+)/ )
470 # interface is real or alias
471 {
472 $ifname[$ifNstate] = $1;
473 $ifname[$ifNstate] =~ s/\:/\./; # ":" is yaml reserved, so we use "."
474
475 if ( $ifconfigLine =~ /Link encap:(.+)\s+HWaddr\s+(\S+)/ )
476 # hardware address
477 {
478 $iftype[$ifTstate] = $1; chomp $iftype[$ifTstate];
479 # TODO filter infiniband... if infiniband: next; else: keep;
480 $ifmac[$ifMstate] = $2;
481 }
482
483 if ( $debug eq "yes" )
484 {
485 print ("$host: $ifname[$ifNstate] \n");
486 print ("$host: $iftype[$ifTstate] = $ifmac[$ifMstate] \n");
487 }
488 if ( $log eq "yes" )
489 {
490 $logline->log_print("$host: $ifname[$ifNstate] ; $iftype[$ifTstate] ; $ifmac[$ifMstate] \n");
491 }
492
493 $ifNstate++;
494 $ifTstate++;
495 $ifMstate++;
496 }
497 }
498 elsif ( $ifconfigLine =~ /inet (?:addr\:)?(\d+(?:\.\d+){3})/ )
499 {
500 if ( $1 =~ /127\.0\.0\.1/ )
501 # do not want local IP
502 {
503 next;
504 }
505 else
506 {
507 $ifip[$ifIstate] = $1;
508
509 if ( $debug eq "yes" )
510 {
511 print ("$host: $ifip[$ifIstate] \n");
512 }
513 if ( $log eq "yes" )
514 {
515 $logline->log_print(" ");
516 }
517
518 $ifIstate++;
519 }
520 }
521 else {next;} # don't waste time with other lines
522 }
523 }
524
525 if ( $debug eq "yes" )
526 {
527 print Dumper(@ifname);
528 print Dumper(@ifip);
529 print Dumper(@iftype);
530 print Dumper(@ifmac);
531 }
532
533 # save this to yaml
534 # $yaml->[0]->{parameters}->{interfaces} is a list
535 # other network parameters are {interfaces} dependant
536 foreach my $i (0 .. $#ifname)
537 {
538 $ifTlist = "$ifTlist"."${ifname[$i]},";
539 print ("$ifTlist \n");
540 my $foo = "ipaddress_"."${ifname[$i]}";
541 $yaml->[0]->{parameters}->{$foo} = $ifip[$i];
542 my $bar = "macaddress_"."${ifname[$i]}";
543 $yaml->[0]->{parameters}->{$bar} = $ifmac[$i];
544 }
545 $ifTlist =~ s/,$//; # remove trailing comma
546 $yaml->[0]->{parameters}->{interfaces} = $ifTlist ;
547
548 if ( $debug eq "yes" )
549 {
550 print Dumper($yaml);
551 }
552 }
553
554 sub getDate
555 # return date in human-readable format for logs
556 {
557 my $result = `date +%Y%m%d-%H:%M`;
558 chomp($result);
559 return $result;
560 }
561