client_script/profile_reader.pl (357 lines of code) (raw):
#!/usr/bin/env perl
use warnings;
use Data::Dumper;
use XML::Simple;
use LWP::UserAgent;
use Getopt::Long;
use XML::Parser;
use DateTime;
use Try::Tiny;
use File::Slurp;
my $format="text";
my $useXml;
my $outputUri;
GetOptions("xml"=>\$useXml, "out=s"=>\$outputUri);
$format="xml" if($useXml);
my $hostname = `hostname`;
chomp $hostname;
sub getIpAddresses {
my $systemInfo = `system_profiler SPNetworkDataType`;
my @addresses;
foreach(split(/\n/,$systemInfo)){
if(/IPv4 Addresses:\s*(.*)$/){
chomp $1;
push @addresses,$1;
}
}
return @addresses;
}
sub getFibreInfo {
my $systemInfo = `system_profiler SPFibreChannelDataType`;
my $domainId=-1;
my $data = {};
foreach(split(/\n/,$systemInfo)){
$domainId=$1 if(/^\s+Fibre Channel Domain (\d+)/);
$data->{"Domain_$domainId"}->{"lunCount"}=0 if($domainId>=0 and not defined $data->{"Domain_$domainId"});
$data->{"Domain_$domainId"}->{"Status"}=$1 if(/^\s+Status: (.*)$/);
$data->{"Domain_$domainId"}->{"WWN"}=$1 if(/^\s+Port World Wide Name: (.*)$/ and not defined $data->{"Domain_$domainId"}->{"WWN"});
$data->{"Domain_$domainId"}->{"Speed"}=$1 if(/^\s+Speed: (.*)$/);
++($data->{"Domain_$domainId"}->{"lunCount"}) if(/^\s+SCSI Logical Unit (.*)$/);
$data->{"Product"}=$1 if(/^\s+Product: (.*)$/);
}
return $data;
}
sub getHardwareInfo {
my $hwInfo = `system_profiler SPHardwareDataType`;
my $data = {};
foreach(split(/\n/,$hwInfo)){
$data->{"model"} = $1 if(/^\s+Model Name: (.*)\s*$/);
$data->{"hw_uuid"} = $1 if(/^\s+Hardware UUID: (.*)\s*$/);
}
return $data;
}
sub getComputerName {
my $systemInfo = `system_profiler SPSoftwareDataType`;
foreach(split(/\n/,$systemInfo)){
return $1 if(/^\s+Computer Name: (.*)$/);
}
}
sub getDriverInfo {
my $systemInfo = `system_profiler SPExtensionsDataType`;
my $data = {};
my $currentSection;
foreach(split(/\n/, $systemInfo)){
$currentSection=$1 if(/^\s*(ATTO.*):$/);
$currentSection=undef if(defined $currentSection and /^\s*$/ and defined $data->{$currentSection}->{"Version"});
if(defined $currentSection) {
$data->{$currentSection}->{"Version"} = $1 if (/^\s*Version: (.*)$/);
$data->{$currentSection}->{"BundleID"} = $1 if (/^\s*Bundle ID: (.*)$/);
$data->{$currentSection}->{"Version"} = $1 if (/^\s*Version: (.*)$/);
$data->{$currentSection}->{"Loaded"} = $1 if (/^\s*Loaded: (.*)$/);
$data->{$currentSection}->{"GetInfoString"} = $1 if (/^\s*Get Info String: (.*)$/);
$data->{$currentSection}->{"ObtainedFrom"} = $1 if (/^\s*Obtained From: (.*)$/);
$data->{$currentSection}->{"Kind"} = $1 if (/^\s*Kind: (.*)$/);
$data->{$currentSection}->{"Architecture"} = $1 if (/^\s*Architecture: (.*)$/);
$data->{$currentSection}->{"Location"} = $1 if (/^\s*Location: (.*)$/);
$data->{$currentSection}->{"KextVersion"} = $1 if (/^\s*Kext Version: (.*)$/);
$data->{$currentSection}->{"Loadable"} = $1 if (/^\s*Loadable: (.*)$/);
$data->{$currentSection}->{"Dependencies"} = $1 if (/^\s*Dependencies: (.*)$/);
$data->{$currentSection}->{"SignedBy"} = $1 if (/^\s*Signed by: (.*)$/);
}
}
my $arrayOutput=[];
foreach(keys %$data){
my $updatedHash = $data->{$_};
$updatedHash->{"DriverName"} = $_;
push @$arrayOutput, $updatedHash;
}
return $arrayOutput;
}
sub breakdownTimespec {
my ($timespec) = @_;
if($timespec=~/(\d+):(\d+)/){
return {days=>0,hours=>$1,minutes=>$2}
} elsif($timespec=~/(\d+)\+(\d+):(\d+)/){
return {days=>$1,hours=>$2,minutes=>$3}
}
}
sub breakdownLongDate {
my ($datespec) = @_;
if($datespec=~/^\s*([^\-]+)\s/){
return $1;
}
}
sub getLoginHistory {
my $rawHistory = `last | grep console | grep -v localhome | head`;
my @result;
foreach(split(/\n/, $rawHistory)){
if(/^([\w_]+)\s+([\w\d\.]+)\s+([^\(]+)\s*\(([\d+:]+)\)/) {
push @result, { "hostname"=>$hostname, "username" => $1, "location" =>$2, login=>breakdownLongDate($3), duration=>breakdownTimespec($4)}
}
}
return \@result;
}
sub checkDenyDlc {
return [] if(! -f "/Library/Preferences/com.apple.xsan.plist");
my $xsanContent = `plutil -convert xml1 /Library/Preferences/com.apple.xsan.plist -o - | grep useDLC -A 10`;
return [] if($? != 0); #text was not found
my @result;
foreach(split(/\n/, $xsanContent)){
push @result, "false" if(/^\s+<false\/>/);
push @result, "true" if(/^\s+<true\/>/);
last if(/^\s+<\/dict>/)
}
return \@result;
}
sub printHash {
my ($data,$indentLevel,$withComma)=@_;
my $indent="";
$indent = "$indent\t" for(1..$indentLevel);
my $nKeys = scalar (keys %$data);
my $n=0;
print "$indent\{";
my $nextWithComma = $n!=$nKeys;
foreach(keys %$data){
++$n;
if(ref $data->{$_} eq "HASH"){
print "$indent\"$_\": ";
printHash($data->{$_},$indentLevel+1,$nextWithComma);
} elsif(ref $data->{$_} eq "ARRAY"){
die "ARRAY output not implemented";
} else {
printkv($_,$data->{$_},$indent,1,$nextWithComma);
}
}
print "$indent\}";
if($withComma){
print ",\n";
} else {
print "\n";
}
}
sub printkv {
my($k,$v,$indent, $quote,$withComma)=@_;
my $end;
if($withComma){
$end=",";
} else {
$end="";
}
if($quote){
print "$indent\"$k\":\"$v\"$end\n";
} else {
print "$indent\"$k\":$v,\n";
}
}
sub checkXsand {
my $xsandContent = `pgrep xsand`;
if ($xsandContent eq '') {
return 'Not running';
} else {
return 'Running';
}
}
sub checkMounts {
my $mountsContent = `mount | grep acfs`;
my $mountInt=1;
my $data = {};
foreach(split(/\n/, $mountsContent)){
my @fields = split / /, $_;
my @fieldsParts = split /\//, $fields[2];
$data->{"$mountInt"}->{"mountPath"}="$fields[2]";
$data->{"$mountInt"}->{"name"}="$fieldsParts[-1]";
$mountInt = $mountInt + 1;
}
my $arrayOutput=[];
foreach(keys %$data){
my $updatedHash = $data->{$_};
$updatedHash->{"number"} = $_;
push @$arrayOutput, $updatedHash;
}
return $arrayOutput;
}
sub doPing {
my ($serverIp) = @_;
my $pingContent = `ping -c 1 $serverIp`;
my @pingContentArray = split /\n/, $pingContent;
my $pingResult;
no warnings 'uninitialized';
no warnings 'substr';
try {
$pingResult = substr $pingContentArray[4], 23, 1;
};
use warnings 'uninitialized';
use warnings 'substr';
return $pingResult;
}
sub pingMetaDataControllers {
my $xsanNameServersConfigFile = read_file('/Library/Preferences/Xsan/fsnameservers');
my $data = {};
my $pingInt=1;
my $percentagePacketLoss = 0;
foreach(split(/\n/, $xsanNameServersConfigFile)){
my $pingStatus;
my $packetLoss;
my $iPAddress = $_;
if($iPAddress =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/)
{
$iPAddress = $1;
}
my $pingResult = doPing($iPAddress);
if (defined $pingResult) {
$pingStatus = 'true';
$packetLoss = '0';
} else {
$pingStatus = 'false';
my $pingResults = 0;
for($pingCount=1;$pingCount<=10;++$pingCount) {
my $pingResultTwo = doPing($iPAddress);
if (defined $pingResultTwo) {
$pingStatus = 'true';
} else {
$pingResults++;
}
}
$percentagePacketLoss = $pingResults * 10;
}
my $percentagePacketLossForXML = 0;
if ($percentagePacketLoss != 0) {
$percentagePacketLossForXML = $percentagePacketLoss;
}
$data->{"$pingInt"}->{"ip"}="$iPAddress";
$data->{"$pingInt"}->{"ping"}="$pingStatus";
$data->{"$pingInt"}->{"packetloss"}="$percentagePacketLossForXML";
$pingInt = $pingInt + 1;
}
my $arrayOutput=[];
foreach(keys %$data){
my $updatedHash = $data->{$_};
$updatedHash->{"number"} = $_;
push @$arrayOutput, $updatedHash;
}
return $arrayOutput;
}
sub getPlutoHelperAgentVersion {
my $plutoHelperAgentInfo = `defaults read /Applications/PlutoHelperAgent.app/Contents/Info.plist | grep CFBundleShortVersionString`;
foreach(split(/\n/,$plutoHelperAgentInfo)){
return $1 if(/^\s+CFBundleShortVersionString = "(.*)..$/);
}
}
sub getPremiereProVersion {
my $premiereProInfo = `defaults read /Applications/Adobe\\ Premiere\\ Pro\\ 20*/Adobe\\ Premiere\\ Pro\\ 20*.app/Contents/Info.plist | grep "Adobe Product Version"`;
foreach(split(/\n/,$premiereProInfo)){
return $1 if(/^\s+"Adobe Product Version" = "(.*)..$/);
}
}
print "Run starting on $hostname at " . DateTime->now() . " UTC\n";
print "--------------------------------------------\n";
print "Collecting computer name...\n";
my $computerName = getComputerName;
print "Collecting IP addresses...\n";
my @ipInfo = getIpAddresses;
print "Collecting fibrechannel info...\n";
my $fibreInfo = getFibreInfo;
print "Collecting login history...\n";
my $recentLogins = getLoginHistory;
print "Collecting hardware info...\n";
my $hwInfo = getHardwareInfo;
print "Collecting DLC status...\n";
my $denyDlc = checkDenyDlc;
print "Collecting fibre drivers info...\n";
my $driverInfo = getDriverInfo;
print "Collecting xsand status...\n";
my $xsandStatus = checkXsand;
print "Collecting mount info...\n";
my $mountInfo = checkMounts;
print "Collecting ping info...\n";
my $pingInfo = pingMetaDataControllers;
print "Collecting Pluto Helper Agent info...\n";
my $plutoHelperAgentInfo = getPlutoHelperAgentVersion;
print "Collecting Premiere Pro info...\n";
my $premiereProInfo = getPremiereProVersion;
if($format eq "text"){
print "Report for $hostname ($computerName)\n\n";
print "IP Addresses:\n";
print "\t$_\n" foreach(@ipInfo);
print "Fibrechannel:\n";
print Dumper($fibreInfo);
print "Recent logins:\n";
print Dumper($recentLogins);
print "Hardware info:\n";
print Dumper($hwInfo);
print "Driver info:\n";
print Dumper($driverInfo);
print "DenyDLC run:\n";
print Dumper($denyDlc);
print "Xsand status:\n";
print Dumper($xsandStatus);
print "Mounts:\n";
print Dumper($mountInfo);
print "Ping:\n";
print Dumper($pingInfo);
print "Pluto Helper Agent info.:\n";
print Dumper($plutoHelperAgentInfo);
print "Premiere Pro info.:\n";
print Dumper($premiereProInfo);
} elsif($format eq "xml"){
my $data = {
"hostname"=>$hostname,
"computerName"=>$computerName,
"ipAddresses"=>\@ipInfo,
"fibrechannel"=>$fibreInfo,
"model"=>$hwInfo->{"model"},
"hw_uuid"=>$hwInfo->{"hw_uuid"},
"denyDlc"=>{"volume"=>$denyDlc},
"driverInfo"=>{"driver"=>$driverInfo},
"XsandStatus"=>{"status"=>$xsandStatus},
"sanVolumesVisible"=>{"mount"=>$mountInfo},
"mdcConnectivity"=>{"mdc"=>$pingInfo},
"plutoHelperAgentInfo"=>$plutoHelperAgentInfo,
"premiereProInfo"=>$premiereProInfo,
};
my $content = XMLout($data,RootName=>"data", KeyAttr=>[ "model","hw_uuid","computerName","denyDlc"]);
my $loginsContent = XMLout({recentLogins=>$recentLogins},RootName=>"logins", KeyAttr => "recentLogin");
if($outputUri){
my $ua=LWP::UserAgent->new;
$ua->timeout(30);
$ua->env_proxy;
my $response=$ua->post("$outputUri/api/hostinfo", Content=>$content, "Content-Type"=>"application/xml");
if($response->is_success){
print "Sent report to $outputUri\n"
} else {
print $content . "\n";
print "Could not send report to $outputUri: ".$response->decoded_content;
}
my $loginresponse =$ua->post("$outputUri/api/logins", Content=>$loginsContent, "Content-Type"=>"application/xml");
if($loginresponse->is_success){
print "Sent report to $outputUri"
} else {
print $content . "\n";
print "Could not send report to $outputUri: ".$loginresponse->decoded_content;
}
} else {
print $content . "\n";
print $loginsContent . "\n";
}
}
print "Run completed at " . DateTime->now() . " UTC\n";
print "--------------------------------------------\n";