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