Subversion Repositories zfs_utils

Rev

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

Rev 34 Rev 35
Line 50... Line 50...
50
#   makeReplicateCommands: create zfs send commands for replication based on snapshot lists
50
#   makeReplicateCommands: create zfs send commands for replication based on snapshot lists
51
 
51
 
52
 
52
 
53
# Exported functions and variables
53
# Exported functions and variables
54
 
54
 
55
our @EXPORT_OK = qw(loadConfig shredFile mountDriveByLabel mountGeli logMsg runCmd makeReplicateCommands $logFileName $displayLogsOnConsole);
55
our @EXPORT_OK = qw(loadConfig shredFile mountDriveByLabel mountGeli logMsg runCmd makeReplicateCommands sendReport $logFileName $displayLogsOnConsole);
56
 
56
 
57
 
57
 
58
our $VERSION = '0.2';
58
our $VERSION = '0.2';
59
our $logFileName = '/tmp/zfs_utils.log'; # this can be overridden by the caller, and turned off with empty string
59
our $logFileName = '/tmp/zfs_utils.log'; # this can be overridden by the caller, and turned off with empty string
60
our $displayLogsOnConsole = 1; # if non-zero, log messages are also printed to console
60
our $displayLogsOnConsole = 1; # if non-zero, log messages are also printed to console
Line 113... Line 113...
113
       close $logfh;
113
       close $logfh;
114
    }
114
    }
115
    print "$timestamp\t$msg\n" if ($displayLogsOnConsole);
115
    print "$timestamp\t$msg\n" if ($displayLogsOnConsole);
116
}
116
}
117
 
117
 
118
# find a drive by it's label by scanning /dev/gpt/ for $timeout seconds.
118
# find a drive by it's label by scanning /dev/gpt/
-
 
119
# driveInfo is a hashref with the following keys:
-
 
120
# label - the GPT label of the drive (required)
-
 
121
# filesystem - the filesystem type (default: ufs)
-
 
122
# mountPath - where to mount the drive (default: /mnt/label)
-
 
123
# timeout - how long to wait for the drive (default: 600 seconds)
-
 
124
# check_interval - how often to check for the drive (default: 15 seconds)
119
# If the drive is found, mount it on mountPath and return the mountPath.
125
# If the drive is found, mount it on mountPath and return the mountPath.
120
# If not found, return empty string.
126
# If not found, return empty string.
121
sub mountDriveByLabel {
127
sub mountDriveByLabel {
122
   my ($label, $mountPath, $timeout, $checkEvery, $filesystem ) = @_;
128
   my ( $driveInfo ) = @_;
123
   unless ($label) {
129
   unless ($driveInfo->{label}) {
124
      logMsg("mountDriveByLabel: No label provided");
130
      logMsg("mountDriveByLabel: No drive label provided");
125
      return '';
131
      return '';
126
   }
132
   }
127
   unless ( $label =~ /^[a-zA-Z0-9_\-]+$/ ) {
133
   unless ( $driveInfo->{label} =~ /^[a-zA-Z0-9_\-]+$/ ) {
128
      logMsg("mountDriveByLabel: Invalid label '$label'");
134
      logMsg("mountDriveByLabel: Invalid label '$driveInfo->{label}'");
129
      return '';
135
      return '';
130
   }
136
   }
131
 
137
 
132
   logMsg("mountDriveByLabel: Looking for drive with label '$label'");
138
   logMsg("mountDriveByLabel: Looking for drive with label '$driveInfo->{label}'");
133
   # default to /mnt/label if not provided
139
   # default to /mnt/label if not provided
134
   $mountPath //= "/mnt/$label"; # this is where we'll mount it if we find it
140
   $driveInfo->{mountPath} //= "/mnt/$driveInfo->{label}"; # this is where we'll mount it if we find it
135
   $filesystem //= 'ufs'; # default to mounting ufs
141
   $driveInfo->{filesystem} //= 'ufs'; # default to mounting ufs
136
   # The location for the label depends on filesystem. Only providing access to ufs and msdos here for safety.
142
   # The location for the label depends on filesystem. Only providing access to ufs and msdos here for safety.
137
   # gpt labeled drives for ufs are in /dev/gpt/, for msdosfs in /dev/msdosfs/
143
   # gpt labeled drives for ufs are in /dev/gpt/, for msdosfs in /dev/msdosfs/
138
   $label = $filesystem eq 'msdos' ? "/dev/msdosfs/$label" : "/dev/gpt/$label"; 
144
   $driveInfo->{mountPath} = $driveInfo->{filesystem} eq 'msdos' ? "/dev/msdosfs/$driveInfo->{label}" : "/dev/gpt/$driveInfo->{label}"; 
139
   # drive already mounted, just return the path
145
   # drive already mounted, just return the path
140
   return $mountPath if ( runCmd( "mount | grep '$mountPath'" ) );
146
   return $driveInfo->{mountPath} if ( runCmd( "mount | grep '$driveInfo->{mountPath}'" ) );
141
   # default to 10 minutes (600 seconds) if not provided
147
   # default to 10 minutes (600 seconds) if not provided
142
   $timeout //= 600;
148
   $driveInfo->{timeout} //= 600;
143
   # default to checking every minute if not provided
149
   # default to checking every minute if not provided
144
   $checkEvery //= 15;
150
   $driveInfo->{check_interval} //= 15;
145
   # wait up to $timeout seconds for device to appear, checking every 10 seconds
151
   # wait up to $timeout seconds for device to appear, checking every 10 seconds
146
   while ( $timeout > 0 ) {
152
   while ( $driveInfo->{timeout} > 0 ) {
147
      if ( -e "$label" ) {
153
      if ( -e "$driveInfo->{label}" ) {
148
         last;
154
         last;
149
      } else {
155
      } else {
150
         sleep $checkEvery;
156
         sleep $driveInfo->{check_interval};
151
         $timeout -= $checkEvery;
157
         $driveInfo->{timeout} -= $driveInfo->{check_interval};
152
         print "Waiting for drive labeled $label\n";
158
         print "Waiting for drive labeled $driveInfo->{label}\n";
153
      }
159
      }
154
    }
160
    }
155
    # if we found it, mount and return mount path
161
    # if we found it, mount and return mount path
156
    if ( -e "$label" ) {
162
    if ( -e "$driveInfo->{label}" ) {
157
       # ensure mount point
163
       # ensure mount point
158
       unless ( -d $mountPath || make_path($mountPath) ) {
164
       unless ( -d $driveInfo->{mountPath} || make_path($driveInfo->{mountPath}) ) {
159
         logMsg("Failed to create $mountPath: $!");
165
         logMsg("Failed to create $driveInfo->{mountPath}: $!");
160
         return '';
166
         return '';
161
       }
167
       }
162
       # mount device (let mount detect filesystem)
168
       # mount device (let mount detect filesystem)
163
       unless ( runCmd( "mount -t $filesystem $label $mountPath" ) ) {
169
       unless ( runCmd( "mount -t $driveInfo->{filesystem} $driveInfo->{label} $driveInfo->{mountPath}" ) ) {
164
         logMsg("Failed to mount $label on $mountPath: $!");
170
         logMsg("Failed to mount $driveInfo->{label} on $driveInfo->{mountPath}: $!");
165
         return '';
171
         return '';
166
       }
172
       }
167
       return $mountPath;
173
       return $driveInfo->{mountPath};
168
    } else {
174
    } else {
169
       return '';
175
       return '';
170
    }
176
    }
171
}
177
}
172
 
178
 
Line 534... Line 540...
534
 
540
 
535
   # return arrayref of commands (caller can iterate or join with pipes)
541
   # return arrayref of commands (caller can iterate or join with pipes)
536
   return \%commands;
542
   return \%commands;
537
}
543
}
538
 
544
 
-
 
545
# Send report via email and/or copy to target drive.
-
 
546
# $reportConfig is a hashref with optional keys:
-
 
547
#   email - email address to send report to
-
 
548
#   targetDrive - hashref with keys:
-
 
549
#       label - GPT or msdosfs label of the target drive
-
 
550
#       mount_point - optional mount point to use (if not provided, /mnt/label is used)
-
 
551
# $subject is the email subject
-
 
552
# $logFile is the path to the log file to send/copy
-
 
553
sub sendReport {
-
 
554
   my ( $reportConfig, $subject, $logFile ) = @_;
-
 
555
   return unless defined $reportConfig;
-
 
556
   if ( defined $reportConfig->{email} && $reportConfig->{email} ne '' ) {
-
 
557
      sendEmailReport( $reportConfig->{email}, $subject, $logFile );
-
 
558
   }
-
 
559
   if ( defined $reportConfig->{targetDrive} ) {
-
 
560
      my $mountPoint = mountDriveByLabel( $reportConfig->{targetDrive}->{label}, $reportConfig->{targetDrive}->{mount_point}, 300 );
-
 
561
      if ( defined $mountPoint ) {
-
 
562
         copyReportToDrive( $logFile, $mountPoint );
-
 
563
         `umount $mountPoint`;
-
 
564
         rmdir $mountPoint;
-
 
565
      } else {
-
 
566
         logMsg( "Warning: could not mount report target drive with label '$reportConfig->{targetDrive}->{label}'" );
-
 
567
      }
-
 
568
   }
-
 
569
}
-
 
570
 
-
 
571
# Copy the report log file to the specified mount point.
-
 
572
# $logFile is the path to the log file to copy.
-
 
573
# $mountPoint is the mount point of the target drive.
-
 
574
# Does nothing if log file or mount point are invalid.
-
 
575
sub copyReportToDrive {
-
 
576
   my ( $logFile, $mountPoint ) = @_;
-
 
577
   return unless defined $logFile && -e $logFile;
-
 
578
   return unless defined $mountPoint && -d $mountPoint;
-
 
579
 
-
 
580
   my $targetFile = "$mountPoint/" . ( split( /\//, $logFile ) )[-1];
-
 
581
   logMsg( "Copying report log file $logFile to drive at $mountPoint" );
-
 
582
   unless ( copy( $logFile, $targetFile ) ) {
-
 
583
      logMsg( "Could not copy report log file to target drive: $!" );
-
 
584
   }
-
 
585
}
-
 
586
 
-
 
587
# Send an email report with the contents of the log file.
-
 
588
# $to is the recipient email address.
-
 
589
# $subject is the email subject.
-
 
590
# $logFile is the path to the log file to send.
-
 
591
# Does nothing if any parameter is invalid.
-
 
592
sub sendEmailReport {
-
 
593
   my ( $to, $subject, $logFile ) = @_;
-
 
594
   return unless defined $to && $to ne '';
-
 
595
   return unless defined $subject && $subject ne '';
-
 
596
   return unless defined $logFile && -e $logFile;
-
 
597
 
-
 
598
   logMsg( "Sending email report to $to with subject '$subject'" );
-
 
599
   open my $mailfh, '|-', '/usr/sbin/sendmail -t' or do {
-
 
600
      logMsg( "Could not open sendmail: $!" );
-
 
601
      return;
-
 
602
   };
-
 
603
   print $mailfh "To: $to\n";
-
 
604
   print $mailfh "Subject: $subject\n";
-
 
605
   print $mailfh "MIME-Version: 1.0\n";
-
 
606
   print $mailfh "Content-Type: text/plain; charset=\"utf-8\"\n";
-
 
607
   print $mailfh "\n"; # end of headers
-
 
608
 
-
 
609
   open my $logfh, '<', $logFile or do {
-
 
610
      logMsg( "Could not open log file $logFile for reading: $!" );
-
 
611
      close $mailfh;
-
 
612
      return;
-
 
613
   };
-
 
614
   while ( my $line = <$logfh> ) {
-
 
615
      print $mailfh $line;
-
 
616
   }
-
 
617
   close $logfh;
-
 
618
   close $mailfh;
-
 
619
}  
539
 
620
 
540
1;
621
1;