Added client work scripts
[clearscm.git] / clients / GD / FSMon / FsmonDB.pm
1 =pod
2
3 =head2 NAME $RCSfile: FsmonDB.pm,v $
4
5 Object oriented interface to filesystems
6
7 =head2 VERSION
8
9 =over
10
11 =item Author:
12
13 Andrew DeFaria <Andrew@ClearSCM.com>
14
15 =item Revision:
16
17 $Revision: $
18
19 =item Created:
20
21 Thu Dec 11 10:39:12 MST 2008
22
23 =item Modified:
24
25 $Date:$
26
27 =back
28
29 =head2 SYNOPSIS
30
31 =head1 SYNOPSIS
32
33   use FsmonDB;
34
35   my $username = "fsmonadm";
36   my $password = "<password>";
37
38   my $fsmondb = new FsmonDB ($username, $password);
39
40   my ($errno, $errmsg) = $fsmondb->addSystem (
41     name                => hostname,
42     owner               => "root",
43     description         => "Database server",
44     ostype              => "Unix",
45     osversion           => `uname -a`,
46     monitorAllFS        => 1,
47   );
48
49   $status = $fsmondb->fsSnapshot (hostname);
50
51 =head2 DESCRIPTION
52
53 Filesystem creates a filesystem object that encapsulates information
54 about the file system as a whole.
55
56 =head2 ROUTINES
57
58 The following routines are exported:
59
60 =over
61
62 =cut
63
64 use strict;
65 use warnings;
66
67 package FsmonDB;
68
69 use Carp;
70 use DBI;
71
72 use DateUtils;
73 use Display;
74 use Filesystem;
75
76 ############################################################################
77 #
78 # insert:       Construct SQL insert statement based on passed in table
79 #               name and hash values.
80 #
81 # Parms:
82 #   table       Table name
83 #   record      Name value hash
84 #
85 # Returns:
86 #   status      ($errno, $errmsg)
87 #
88 ############################################################################
89 sub insert ($%) {
90   my ($self, $table, %values) = @_;
91
92   my $first = 1;
93   my $fields;
94   my $values;
95
96   foreach (keys %values) {
97     if ($first) {
98       $first = 0;
99     } else {
100       $fields .= ",";
101       $values .= ",";
102     } # if
103
104     if (!defined $_) {
105       $values .= "NULL";
106     } else {
107       $fields .= $_;
108       $values .= "\"" . quotemeta ($values{$_}) . "\"";
109     } # if
110   } # foreach
111
112   my $statement = "insert into $table ($fields) values ($values)";
113
114   $self->{db}->do ($statement)
115     or return $self->_dberror ("Unable to add system", $statement);
116
117   return (0, undef);
118 } # insert
119
120 ############################################################################
121 #
122 # _dberror: Output the DB error message and exit (Internal)
123 #
124 # Parms:
125 #   msg         User defined message to output
126 #   statement   SQL Statement attempted (optional)
127 #
128 # Returns:
129 #   Nothing
130 #
131 ############################################################################
132 sub _dberror ($;$) {
133   my ($self, $msg, $statement) = @_;
134
135   my $caller = (caller (1))[3];
136
137   my $returnMsg = "$caller: DBError: "  
138                 . $msg
139                 . "\nError #"
140                 . $self->{db}->err
141                 . " "
142                 . $self->{db}->errstr;
143
144   $returnMsg .= "\nSQL Statement: $statement\n" if $statement;
145
146   return ($self->{db}->err, $returnMsg);
147 } # _dberror
148
149 ############################################################################
150 #
151 # _exists: Return 1 if the value exists in the table otherwise 0
152 #
153 # Parms:
154 #   table       Name of table to search
155 #   column      Column name to search
156 #   value       Value to look for
157 #   column2     Secondary column to search for
158 #   value2      Secondary value to search for
159 #
160 # Returns:
161 #   1 if found, 0 if not
162 #
163 ############################################################################
164 sub _exists ($$$;$$) {
165   my ($self, $table, $column, $value, $column2, $value2) = @_;
166
167   my $statement = "select count(*) from $table where $column = \""
168                 . quotemeta ($value)
169                 . "\"";
170
171   $statement .= " and $column2 = \""
172              .  quotemeta ($value2)
173              . "\"" if $column2;
174
175   my $sth;
176
177   unless ($sth = $self->{db}->prepare ($statement)) {
178     my ($errNo, $errMsg) = $self->_dberror ("Unable to prepare statement", $statement);
179     display $errMsg;
180     return 0;
181   } # unless
182
183   unless ($sth->execute) {
184     my ($errNo, $errMsg) = $self->_dberror ("Unable to execute statement", $statement);
185     display $errMsg;
186     return 0;
187   } # unless
188
189   my @row = $sth->fetchrow_array;
190
191   $sth->finish;
192
193   if ($row[0]) {
194     return $row[0]
195   } else {
196     return 0;
197   } # if
198 } # _exists
199
200 ############################################################################
201 #
202 # _count:       Returns the number of entries in a table that qualify for
203 #               the given condition.
204 #
205 # Parms:
206 #   table       Name of table to search
207 #   id          condition (Default: All entries in the table)
208 #
209 # Returns:
210 #   Count of qualifying entries
211 #
212 ############################################################################
213 sub _count ($;$) {
214   my ($self, $table, $condition) = @_;
215
216   $condition = $condition ? "where $condition" : "";
217
218   my $statement = "select count(*) from $table $condition";
219
220   my $sth;
221
222   unless ($sth = $self->{db}->prepare ($statement)) {
223     my ($errNo, $errMsg) = $self->_dberror ("Unable to prepare statement", $statement);
224     display $errMsg;
225     return -1;
226   } # unless
227
228   unless ($sth->execute) {
229     my ($errNo, $errMsg) = $self->_dberror ("Unable to execute statement", $statement);
230     display $errMsg;
231     return -1;
232   } # unless
233
234   my @row = $sth->fetchrow_array;
235
236   $sth->finish;
237
238   if ($row[0]) {
239     return $row[0]
240   } else {
241     return 0;
242   } # if
243 } # _count
244
245 =pod
246
247 =head3 new ()
248
249 Construct a new FsmonDB object. The following OO style arguments are
250 supported:
251
252 Parameters:
253
254 =for html <blockquote>
255
256 =over
257
258 =item none
259
260 Returns:
261
262 =for html <blockquote>
263
264 =over
265
266 =item FsmonDB object
267
268 =back
269
270 =for html </blockquote>
271
272 =cut
273
274 sub new (;$$) {
275   my ($class, $username, $password) = @_;
276
277   $username = $username ? $username : "fsmon";
278   $password = $password ? $password : "fsmon";
279
280   my $dbname    = $ENV{FSMON_DBNAME}
281                 ? $ENV{FSMON_DBNAME}            
282                 : "fsmon";
283   my $dbserver  = $ENV{FSMON_DBSERVER}
284                 ? $ENV{FSMON_DBSERVER}
285                 : "seast1";
286   my $dbdriver  = "mysql";
287
288   my $db = DBI->connect ("DBI:$dbdriver:$dbname:$dbserver", $username,
289                          $password, {PrintError => 0})
290     or croak "Unable to connect to $dbname database as $username";
291
292   return bless {
293     db          => $db,
294     username    => $username,
295     password    => $password,
296   }, $class;
297 } # new
298
299 =pod
300
301 =head3 addSystem (%system)
302
303 Add a system record
304
305 Parameters:
306
307 =for html <blockquote>
308
309 =over
310
311 %system is a hash containing the following keys:
312
313 =item $name (required)
314
315 Name of the system
316
317 =item $owner (optional)
318
319 Person or persons responsible for this system
320
321 =item $description (optional)
322
323 Description of this system
324
325 =item $ostype (required)
326
327 An enumeration of "Linux", "Unix" or "Windows" (default Linux)
328
329 =item $osversion (optional)
330
331 String representing an OS version
332
333 Returns:
334
335 =for html <blockquote>
336
337 =over
338
339 =item FsmonDB object
340
341 =back
342
343 =for html </blockquote>
344
345 =cut
346
347 sub addSystem (%) {
348   my ($self, %record) = @_;
349
350   return $self->insert ("system", %record);
351 } # addSystem
352
353 =pod
354
355 =head3 getSystem ($system)
356
357 Get a system record
358
359 Parameters:
360
361 =for html <blockquote>
362
363 =over
364
365 =item $system (option)
366
367 Name of the system to return information about. If not specified then
368 getSystem returns all systems
369
370 Returns:
371
372 =for html <blockquote>
373
374 =over
375
376 =item If $system was specified, a hash of that system's
377 information. If $system is not specified then an array of hashes
378 containing information on all systems.
379
380 =back
381
382 =for html </blockquote>
383
384 =cut
385
386 sub getSystem (;$) {
387   my ($self, $system) = @_;
388
389   my ($statement, $sth);
390
391   if ($system) {
392     $statement = "select * from system where name = \"$system\"";
393   } else {
394     $statement = "select name from system";
395   } # unless
396
397   unless ($sth = $self->{db}->prepare ($statement)) {
398     my ($errno, $errmsg) = $self->_dberror ("Unable to prepare statement", $statement);
399     error $errmsg, $errno;
400   } # unless
401
402   unless ($sth->execute) {
403     my ($errno, $errmsg) = $self->_dberror ("Unable to execute statement", $statement);
404     error $errmsg, $errno;
405   } # unless
406
407   if ($system) {
408     return %{my $row = $sth->fetchrow_hashref};
409   } else {
410     my @records;
411
412     while (my @record = $sth->fetchrow_array) {
413       push @records, pop @record;
414     } # while
415
416     return @records;
417   } # if
418 } # addSystem
419
420 =pod
421
422 =head3 addFilesystem ($system, $mount)
423
424 Add monitoring of a filesytem identified by $mount from a $system
425
426 Parameters:
427
428 =for html <blockquote>
429
430 =over
431
432 =item $system (required)
433
434 Name of the system that this filesystem is local to
435
436 =item mount (optional)
437
438 Mount point for this file system. If undef then add all local file systems.
439
440 Returns:
441
442 =for html <blockquote>
443
444 =over
445
446 =item ($errno, $errmsg)
447
448 =back
449
450 =for html </blockquote>
451
452 =cut
453
454 sub addFilesystem ($;$) {
455   my ($self, $system, $mount) = @_;
456
457   my $fs = new Filesystem;
458
459   foreach ($fs->mounts ()) {
460     my %fsinfo = $fs->getFSInfo ($_);
461     my %filesystem = (
462       "sysname"         => $system,
463       "mount"           => $_,
464       "fs"              => $fsinfo{fs},
465     );
466     my ($errno, $errmsg);
467
468     if ($mount) {
469       if ($mount eq $_) {
470         ($errno, $errmsg) = $self->insert ("filesystems", %filesystem);
471
472         return ($errno, $errmsg) if $errno != 0;
473       } # if
474     } else {
475         ($errno, $errmsg) = $self->insert ("filesystems", %filesystem);
476
477         return ($errno, $errmsg) if $errno != 0;
478       } # if
479   } # foreach
480
481   return (0, undef);
482 } # addFilesystem
483
484 =pod
485
486 =head3 addSnapshot (%snapshot)
487
488 Add a snapshot record of a filesystem
489
490 Parameters:
491
492 =for html <blockquote>
493
494 =over
495
496 %snapshot is a hash containing the following keys:
497
498 =item sysname (required)
499
500 Name of the system that this filesystem is local to
501
502 =item mount (required)
503
504 Mount point for this file system
505
506 =item timestamp (required)
507
508 Timestamp representing the time that the snapshot of the filesystem
509 was taken.
510
511 =item size (optional)
512
513 Total size of the filesystem in bytes
514
515 =item used (optional)
516
517 Number of bytes of used space
518
519 =item free (optional)
520
521 Number of bytes free or available for use
522
523 =item reserve (optional)
524
525 Number of bytes held in reserve
526
527 Returns:
528
529 =for html <blockquote>
530
531 =over
532
533 =item ($errno, $errmsg)
534
535 =back
536
537 =for html </blockquote>
538
539 =cut
540
541 sub addSnapshot (%) {
542   my ($self, %snapshot) = @_;
543
544   return $self->insert ("fs", %snapshot);
545 } # addSnapshot
546
547 =pod
548
549 =head3 snapshot ($system)
550
551 Take a snapshot of all configured file systems for a given system
552
553 Parameters:
554
555 =for html <blockquote>
556
557 =over
558
559 =item $system
560
561 Name of the system to snapshot
562
563 Returns:
564
565 =for html <blockquote>
566
567 =over
568
569 =item ($errno, $errmsg)
570
571 =back
572
573 =for html </blockquote>
574
575 =cut
576
577 sub snapshot ($;$) {
578   my ($self, $system) = @_;
579
580   my %system    = $self->getSystem ($system);
581   my $fs        = new Filesystem (
582     $system,
583     $system{ostype},
584     $system{username},
585     $system{password},
586     qr "$system{prompt}",
587     $system{shellstyle},
588   );
589
590   if ($fs) {
591     foreach ($fs->mounts ()) {
592       my %fsinfo = $fs->getFSInfo ($_);
593       my %fs;
594
595       # Format record
596       $fs{sysname}      = $system;
597       $fs{mount}        = $_;
598       $fs{timestamp}    = Today2SQLDatetime;
599       $fs{size}         = $fsinfo{size};
600       $fs{used}         = $fsinfo{used};
601       $fs{free}         = $fsinfo{free};
602       $fs{reserve}      = $fsinfo{reserve};
603
604       my ($errno, $errmsg) = $self->addSnapshot (%fs);
605
606       return ($errno, $errmsg) if $errno != 0;
607     } # foreach
608   } # if
609
610   return (0, "");
611 } # snapshot
612
613 1;
614
615 =head1 NAME
616
617 FsmonDB - Access routines to the fsmon SQL database
618
619 =head1 VERSION
620
621 Version 1.0
622
623 =head1 DESCRIPTION
624
625 This module provides for access routines to the fsmon SQL database.
626
627 =head1 METHODS
628
629 =head2 new ($username, $password)
630
631 Opens the fsmon SQL database for the specified $username and
632 $password and returns a FsmonDB object
633
634 Parameters:
635
636 =over
637
638 =item username:
639
640 Username to connect to the database. At this time "fsmonadm" is the R/W
641 user and "fsmon" (password "reader") has R/O access (Default:
642 fsmon).
643
644 =item password:
645
646 Password to use. (Default: "fsmon").
647
648 =item Returns FsmonDB object
649
650 =back
651
652 =head2 addSystem (%testrun)
653
654 Adds the system record. Pass in a hash of field name/value pairs.
655
656 =over
657
658 =item ($errno, $errmsg)
659
660 =back
661
662 =back
663
664 =head2 CONFIGURATION AND ENVIRONMENT
665
666 None
667
668 =head2 DEPENDENCIES
669
670   ...
671
672 =head2 INCOMPATABILITIES
673
674 None yet...
675
676 =head2 BUGS AND LIMITATIONS
677
678 There are no known bugs in this module.
679
680 Please report problems to Andrew DeFaria (Andrew@ClearSCM.com).
681
682 =head2 LICENSE AND COPYRIGHT
683
684 This Perl Module is freely available; you can redistribute it and/or
685 modify it under the terms of the GNU General Public License as
686 published by the Free Software Foundation; either version 2 of the
687 License, or (at your option) any later version.
688
689 This Perl Module is distributed in the hope that it will be useful,
690 but WITHOUT ANY WARRANTY; without even the implied warranty of
691 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
692 General Public License (L<http://www.gnu.org/copyleft/gpl.html>) for more
693 details.
694
695 You should have received a copy of the GNU General Public License
696 along with this Perl Module; if not, write to the Free Software Foundation,
697 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
698 reserved.
699
700 =cut