1*c17001d7SMatt Spinler#!/usr/bin/env perl 2*c17001d7SMatt Spinler 3*c17001d7SMatt Spinler#This script generates fan definitions from the MRW 4*c17001d7SMatt Spinler#and outputs them in a YAML file. 5*c17001d7SMatt Spinler 6*c17001d7SMatt Spinleruse strict; 7*c17001d7SMatt Spinleruse warnings; 8*c17001d7SMatt Spinler 9*c17001d7SMatt Spinleruse Getopt::Long; 10*c17001d7SMatt Spinleruse mrw::Inventory; 11*c17001d7SMatt Spinleruse mrw::Targets; 12*c17001d7SMatt Spinleruse mrw::Util; 13*c17001d7SMatt Spinleruse Scalar::Util qw(looks_like_number); 14*c17001d7SMatt Spinler 15*c17001d7SMatt Spinlermy $serverwizFile; 16*c17001d7SMatt Spinlermy $outputFile; 17*c17001d7SMatt SpinlerGetOptions("i=s" => \$serverwizFile, 18*c17001d7SMatt Spinler "o=s" => \$outputFile) or printUsage(); 19*c17001d7SMatt Spinler 20*c17001d7SMatt Spinlerif ((not defined $serverwizFile) || 21*c17001d7SMatt Spinler (not defined $outputFile)) 22*c17001d7SMatt Spinler{ 23*c17001d7SMatt Spinler printUsage(); 24*c17001d7SMatt Spinler} 25*c17001d7SMatt Spinler 26*c17001d7SMatt Spinlermy $targets = Targets->new; 27*c17001d7SMatt Spinler$targets->loadXML($serverwizFile); 28*c17001d7SMatt Spinler 29*c17001d7SMatt Spinlermy @inventory = Inventory::getInventory($targets); 30*c17001d7SMatt Spinler 31*c17001d7SMatt Spinlermy %fans = findFans(); 32*c17001d7SMatt Spinler 33*c17001d7SMatt SpinlerprintFanYAML(\%fans, $outputFile); 34*c17001d7SMatt Spinler 35*c17001d7SMatt Spinler 36*c17001d7SMatt Spinler#This function returns a hash representing the fans in the system. 37*c17001d7SMatt Spinler#The hash looks like: 38*c17001d7SMatt Spinler# $fans{<name>}{<zone>} 39*c17001d7SMatt Spinler# $fans{<name>}{<profile>} 40*c17001d7SMatt Spinler# @fans{<name>}{sensors} 41*c17001d7SMatt Spinler# 42*c17001d7SMatt Spinler# Where: 43*c17001d7SMatt Spinler# <name> = inventory name 44*c17001d7SMatt Spinler# <zone> = cooling zone number 45*c17001d7SMatt Spinler# <profile> = cooling zone profile, such as air, water, or all 46*c17001d7SMatt Spinler# <sensors> = an array of the hwmon sensors for the fan's tachs 47*c17001d7SMatt Spinlersub findFans 48*c17001d7SMatt Spinler{ 49*c17001d7SMatt Spinler my %tachs; 50*c17001d7SMatt Spinler my %fans; 51*c17001d7SMatt Spinler 52*c17001d7SMatt Spinler #Find fans by looking at the TACH connections. We could also find 53*c17001d7SMatt Spinler #parts of type FAN, but we need the tach connection anyway to 54*c17001d7SMatt Spinler #lookup the sensors on the other end... 55*c17001d7SMatt Spinler for my $target (keys %{$targets->getAllTargets()}) 56*c17001d7SMatt Spinler { 57*c17001d7SMatt Spinler my $connections = $targets->findConnections($target, "TACH"); 58*c17001d7SMatt Spinler next if ($connections eq ""); 59*c17001d7SMatt Spinler 60*c17001d7SMatt Spinler for my $tach (sort @{$connections->{CONN}}) 61*c17001d7SMatt Spinler { 62*c17001d7SMatt Spinler #Because findConnections is recursive, we can hit this same 63*c17001d7SMatt Spinler #connection multiple times, so only use it once. 64*c17001d7SMatt Spinler next if (exists $tachs{$tach->{SOURCE}}{$tach->{DEST}}); 65*c17001d7SMatt Spinler $tachs{$tach->{SOURCE}}{$tach->{DEST}} = 1; 66*c17001d7SMatt Spinler 67*c17001d7SMatt Spinler #Note: SOURCE = tach unit on fan, DEST = tach unit on fan ctlr 68*c17001d7SMatt Spinler 69*c17001d7SMatt Spinler my $fru = Util::getEnclosingFru($targets, $tach->{SOURCE}); 70*c17001d7SMatt Spinler my $name = Util::getObmcName(\@inventory, $fru); 71*c17001d7SMatt Spinler 72*c17001d7SMatt Spinler my $sensor = getSensor($tach->{DEST}); 73*c17001d7SMatt Spinler push @{$fans{$name}{sensors}}, $sensor; 74*c17001d7SMatt Spinler 75*c17001d7SMatt Spinler #Get the cooling zone and profile from the fan controller part 76*c17001d7SMatt Spinler my $part = $targets->getTargetParent($tach->{SOURCE}); 77*c17001d7SMatt Spinler my $zone = $targets->getAttribute($part, "COOLING_ZONE"); 78*c17001d7SMatt Spinler if (!looks_like_number($zone)) 79*c17001d7SMatt Spinler { 80*c17001d7SMatt Spinler die "Cooling zone '$zone' on $part is not a number\n"; 81*c17001d7SMatt Spinler } 82*c17001d7SMatt Spinler 83*c17001d7SMatt Spinler #If the profile isn't set, just set it to be 'all'. 84*c17001d7SMatt Spinler my $profile = ""; 85*c17001d7SMatt Spinler if (!$targets->isBadAttribute($part, "COOLING_ZONE_PROFILE")) 86*c17001d7SMatt Spinler { 87*c17001d7SMatt Spinler $profile = $targets->getAttribute($part, 88*c17001d7SMatt Spinler "COOLING_ZONE_PROFILE"); 89*c17001d7SMatt Spinler } 90*c17001d7SMatt Spinler 91*c17001d7SMatt Spinler if ($profile eq "") 92*c17001d7SMatt Spinler { 93*c17001d7SMatt Spinler $profile = "all"; 94*c17001d7SMatt Spinler } 95*c17001d7SMatt Spinler 96*c17001d7SMatt Spinler $fans{$name}{profile} = lc $profile; 97*c17001d7SMatt Spinler $fans{$name}{zone} = $zone; 98*c17001d7SMatt Spinler } 99*c17001d7SMatt Spinler } 100*c17001d7SMatt Spinler 101*c17001d7SMatt Spinler return %fans; 102*c17001d7SMatt Spinler} 103*c17001d7SMatt Spinler 104*c17001d7SMatt Spinler 105*c17001d7SMatt Spinler#Find what hwmon will call this unit's reading by looking in 106*c17001d7SMatt Spinler#the child unit-hwmon-feature unit. 107*c17001d7SMatt Spinlersub getSensor 108*c17001d7SMatt Spinler{ 109*c17001d7SMatt Spinler my ($unit) = @_; 110*c17001d7SMatt Spinler 111*c17001d7SMatt Spinler my @hwmons = Util::getChildUnitsWithTargetType($targets, 112*c17001d7SMatt Spinler "unit-hwmon-feature", 113*c17001d7SMatt Spinler $unit); 114*c17001d7SMatt Spinler die "No HWMON children found for $unit\n" unless (scalar @hwmons != 0); 115*c17001d7SMatt Spinler 116*c17001d7SMatt Spinler my $name = $targets->getAttributeField($hwmons[0], 117*c17001d7SMatt Spinler "HWMON_FEATURE", 118*c17001d7SMatt Spinler "DESCRIPTIVE_NAME"); 119*c17001d7SMatt Spinler die "No HWMON name for hwmon unit $hwmons[0]\n" if ($name eq ""); 120*c17001d7SMatt Spinler 121*c17001d7SMatt Spinler return $name; 122*c17001d7SMatt Spinler} 123*c17001d7SMatt Spinler 124*c17001d7SMatt Spinler 125*c17001d7SMatt Spinler#Creates the YAML representation of the data 126*c17001d7SMatt Spinlersub printFanYAML 127*c17001d7SMatt Spinler{ 128*c17001d7SMatt Spinler my ($fans, $file) = @_; 129*c17001d7SMatt Spinler 130*c17001d7SMatt Spinler open (F, ">$file") or die "Could not open $file\n"; 131*c17001d7SMatt Spinler 132*c17001d7SMatt Spinler print F "fans:\n"; 133*c17001d7SMatt Spinler 134*c17001d7SMatt Spinler while (my ($fan, $data) = each(%{$fans})) 135*c17001d7SMatt Spinler { 136*c17001d7SMatt Spinler print F " - inventory: $fan\n"; 137*c17001d7SMatt Spinler print F " cooling_zone: $data->{zone}\n"; 138*c17001d7SMatt Spinler print F " cooling_profile: $data->{profile}\n"; 139*c17001d7SMatt Spinler print F " sensors:\n"; 140*c17001d7SMatt Spinler for my $s (@{$data->{sensors}}) 141*c17001d7SMatt Spinler { 142*c17001d7SMatt Spinler print F " - $s\n"; 143*c17001d7SMatt Spinler } 144*c17001d7SMatt Spinler } 145*c17001d7SMatt Spinler 146*c17001d7SMatt Spinler close F; 147*c17001d7SMatt Spinler} 148*c17001d7SMatt Spinler 149*c17001d7SMatt Spinler 150*c17001d7SMatt Spinlersub printUsage 151*c17001d7SMatt Spinler{ 152*c17001d7SMatt Spinler print "$0 -i [XML filename] -o [output YAML filename]\n"; 153*c17001d7SMatt Spinler exit(1); 154*c17001d7SMatt Spinler} 155