blob: 351e662d41ea3dcc909922404a23886cd2d102cb [file] [log] [blame]
Vishwanatha Subbannad0039432017-03-30 00:10:47 +05301#!/usr/bin/env perl
Andrew Geissler65ca8e12022-07-16 11:36:14 -04002
Vishwanatha Subbanna37066462016-12-13 17:06:18 +05303use strict;
4use warnings;
5
6use mrw::Targets; # Set of APIs allowing access to parsed ServerWiz2 XML output
7use mrw::Inventory; # To get list of Inventory targets
8use Getopt::Long; # For parsing command line arguments
9use Data::Dumper qw(Dumper); # Dumping blob
Vishwanatha Subbannad0039432017-03-30 00:10:47 +053010use List::Util qw(first);
Vishwanatha Subbanna37066462016-12-13 17:06:18 +053011
12# Globals
13my $force = 0;
14my $serverwizFile = "";
15my $debug = 0;
16my $outputFile = "";
17my $verbose = 0;
18
19# Command line argument parsing
20GetOptions(
21"f" => \$force, # numeric
22"i=s" => \$serverwizFile, # string
23"o=s" => \$outputFile, # string
24"d" => \$debug,
25"v" => \$verbose,
26)
27or printUsage();
28
29if (($serverwizFile eq "") or ($outputFile eq ""))
30{
31 printUsage();
32}
33
34# Hashmap of all the LED groups with the properties
35my %hashGroup;
36
37# hash of targets to Names that have the FRU Inventory instances
38my %invHash;
39
Vishwanatha Subbannae36476e2017-07-19 16:36:02 +053040# Hash of Enclosure Fault LED names and their properties
41# These are generally front-fault-led and rear-fault-led
42my %encFaults;
Vishwanatha Subbanna37066462016-12-13 17:06:18 +053043
Vishwanatha Subbannad0039432017-03-30 00:10:47 +053044# These groups are a must in all the systems.
45# Its fine if they don't map to any physical LED
46my @defaultGroup = ("BmcBooted", "PowerOn");
47
Vishwanatha Subbannac5e127d2017-05-15 12:08:42 +053048# This group contains all the LEDs with the action Blink
49my $lampTest = "LampTest";
50
Vishwanatha Subbanna37066462016-12-13 17:06:18 +053051# API used to access parsed XML data
52my $targetObj = Targets->new;
53if($verbose == 1)
54{
55 $targetObj->{debug} = 1;
56}
57
58if($force == 1)
59{
60 $targetObj->{force} = 1;
61}
62
63$targetObj->loadXML($serverwizFile);
64print "Loaded MRW XML: $serverwizFile \n";
65
66# Iterate over Inventory and get all the Inventory targets.
67my @inventory = Inventory::getInventory($targetObj);
68for my $item (@inventory)
69{
70 # Target to Obmc_Name hash.
71 $invHash{$item->{TARGET}} = $item->{OBMC_NAME};
72}
73
74# For debugging purpose.
75printDebug("\nList of Inventory targets\n");
76foreach my $key (sort keys %invHash)
77{
78 printDebug("$invHash{$key}\n");
79}
80
81# Process all the targets in the XML. If the target is associated with a FRU,
82# then remember it so that when we do the FRU inventory lookup, we know if
83# that Inventory has a LED associated with it or not.
84foreach my $target (sort keys %{$targetObj->getAllTargets()})
85{
86 # Some the target instances may *not* have this MRW_TYPE attribute.
87 if($targetObj->isBadAttribute($target, "MRW_TYPE"))
88 {
89 next;
90 }
91
92 # Return true if not populated -or- not present
93 if("LED" eq $targetObj->getMrwType($target))
94 {
95 # Just for clarity.
96 my $ledTarget = $target;
97
98 # OBMC_NAME field of the FRU
99 # fruPath ex /system/chassis/motherboard/dimm1
100 # device "dimm1"
101 my $fruPath = '';
102 my $device = '';
103
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530104 # Find if this LED is associated with a FRU.
105 # Example, FAN will have LED on that assembly.
106 my $conns = $targetObj->findConnections($ledTarget, "LOGICAL_ASSOCIATION");
107 if ($conns ne "")
108 {
109 # This LED is associated with a FRU
110 for my $conn (@{$conns->{CONN}})
111 {
112 my $destTarget = $conn->{DEST_PARENT};
113 # If we have found this, then that means, we do not need to
114 # hand cook a group name. delete this value from the inventory
115 # array
116 if(exists($invHash{$destTarget}))
117 {
118 # This will remove a particular {key, value} pair
119 $fruPath = $invHash{$destTarget};
120 printDebug("$destTarget : $fruPath is having associated LED\n");
121 delete ($invHash{$destTarget});
122 }
123 }
124 # fetch FruName from the device path
125 $device = getFruName($fruPath);
126 printDebug("$target; $device has device\n");
127 }
128
129 if($targetObj->isBadAttribute($ledTarget, "CONTROL_GROUPS"))
130 {
131 next;
132 }
133
Vishwanatha Subbannaa9660422017-05-05 16:06:21 +0530134 # By default, Blink takes higher priority
135 my $priority = "'Blink'";
136
137 # Get the priority. Since rest everything is populated,
138 # default to Blink than err'ing out. Not checking for
139 # validity of this since it must be present.
140 if($targetObj->getAttribute($ledTarget, "LED_PRIORITY") eq "ON")
141 {
142 $priority = "'On'";
143 }
144
Matt Spinler312fa6b2018-02-09 14:21:20 -0600145 #The MRW instance name must match the LED name in the device tree
146 my $name = $targetObj->getInstanceName($ledTarget);
Vishwanatha Subbannae36476e2017-07-19 16:36:02 +0530147
148 # Get if this LED is a ENC-FAULT type.
149 if(!$targetObj->isBadAttribute($target, "LED_TYPE"))
150 {
151 if("ENC-FAULT" eq $targetObj->getAttribute($ledTarget, "LED_TYPE"))
152 {
153 $encFaults{$name} = $priority;
154 }
155 }
156
157 # Defines the LEDs and the Groups that they belong to
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530158 my $controlGroup = $targetObj->getAttribute($ledTarget, "CONTROL_GROUPS");
159
160 #remove spaces, because serverwiz isn't good at removing them itself
161 $controlGroup =~ s/\s//g;
162 my @groups= split(',', $controlGroup); #just a long 16x3 = 48 element list
163
164 for (my $i = 0; $i < scalar @groups; $i += 3)
165 {
166 if (($groups[$i] ne "NA") && ($groups[$i] ne ""))
167 {
168 my $groupName = $groups[$i];
169 printDebug("$groupName\n");
170
171 my $blinkFreq = $groups[$i+1];
172 my $action = "'On'";
173 my $period = 0;
174
175 # Period in milli seconds
176 my $dutyCycle = $groups[$i+2];
177 if($blinkFreq > 0)
178 {
179 $action = "'Blink'";
180 $period = (1 / $blinkFreq) * 1000;
181 }
182
183 # Insert into hash map;
Vishwanatha Subbannae36476e2017-07-19 16:36:02 +0530184 $hashGroup{$groupName}{$name}{"Action"} = $action;
185 $hashGroup{$groupName}{$name}{"Period"} = $period;
186 $hashGroup{$groupName}{$name}{"DutyOn"} = $dutyCycle;
187 $hashGroup{$groupName}{$name}{"Priority"} = $priority;
Vishwanatha Subbannac5e127d2017-05-15 12:08:42 +0530188
189 # Need to update the LampTest group.
Vishwanatha Subbannae36476e2017-07-19 16:36:02 +0530190 $hashGroup{$lampTest}{$name}{"Action"} = "'Blink'";
191 $hashGroup{$lampTest}{$name}{"Period"} = 1000;
192 $hashGroup{$lampTest}{$name}{"DutyOn"} = 50;
193
194 # Priority of a particular LED needs to stay SAME across
195 # all groups
196 $hashGroup{$lampTest}{$name}{"Priority"} = $priority;
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530197 }
198 } # Walk CONTROL_GROUP
199 } # Has LED target
200} # All the targets
201
202
203# These are the FRUs that do not have associated LEDs. All of these need to be
204# mapped to some group, which will be named after this target name and the
205# elements of the group are EnclosureFaults Front and Back
206printDebug("\n======================================================================\n");
207printDebug("\nFRUs that do not have associated LEDs\n");
208foreach my $key (sort keys %invHash)
209{
210 my $device = getFruName($invHash{$key});
211
212 # For each of these device, the Group record would be this :
213 my $groupName = $device . "Fault";
214 printDebug("$device :: $groupName\n");
215
216 # Setup roll-up LEDs to the ones that are of type ENC-FAULT
Vishwanatha Subbannae36476e2017-07-19 16:36:02 +0530217 foreach my $led (sort keys %encFaults)
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530218 {
Vishwanatha Subbannae36476e2017-07-19 16:36:02 +0530219 $hashGroup{$groupName}{$led}{"Action"} = "'On'";
220 $hashGroup{$groupName}{$led}{"Period"} = 0;
221 $hashGroup{$groupName}{$led}{"DutyOn"} = 50;
222
223 # Priority of a particular LED needs to stay SAME across
224 # all groups
225 $hashGroup{$groupName}{$led}{"Priority"} = $encFaults{$led};
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530226 }
227}
228printDebug("\n======================================================================\n");
229
George Liu78ae5822020-04-15 11:12:38 +0800230my $index = rindex($outputFile, ".");
231my $suffix = substr($outputFile, $index + 1);
232if (lc($suffix) eq "json")
233{
234 # Generate the JSON file
235 generateJSONFile();
236}
237else
238{
239 # Generate the yaml file
240 generateYamlFile();
241}
242
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530243#------------------------------------END OF MAIN-----------------------
244
245# Gven a '/' separated string, returns the leaf.
246# Ex: /a/b/c/d returns device=d
247sub getFruName
248{
249 my $path = shift;
250 my $device = '';
251 my $lastSlash=rindex($path, '/');
252 $device=substr($path, $lastSlash+1);
253}
254
255sub generateYamlFile
256{
257 my $fileName = $outputFile;
258 my $groupCopy = '';
259 my $ledCopy = '';
260 open(my $fh, '>', $fileName) or die "Could not open file '$fileName' $!";
261
262 foreach my $group (sort keys %hashGroup)
263 {
264 if($group ne $groupCopy)
265 {
Vishwanatha Subbannad0039432017-03-30 00:10:47 +0530266 # If one of these is a default group, then delete it from the array
267 # that is being maintained to create one by hand if all default ones
268 # are not defined
269 my $index = first {$defaultGroup[$_] eq $group} 0..$#defaultGroup;
270 if (defined $index)
271 {
272 splice @defaultGroup, $index, 1;
273 }
274
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530275 $groupCopy = '';
276 $ledCopy = '';
277 }
278
Vishwanatha Subbannac5e127d2017-05-15 12:08:42 +0530279 foreach my $led (sort keys %{ $hashGroup{$group} })
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530280 {
Vishwanatha Subbannac5e127d2017-05-15 12:08:42 +0530281 foreach my $property (sort keys %{ $hashGroup{$group}{$led}})
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530282 {
283 if($group ne $groupCopy)
284 {
285 $groupCopy = $group;
286 print $fh "$group:\n";
287 }
288 print $fh " ";
289 if($led ne $ledCopy)
290 {
291 $ledCopy = $led;
292 print $fh "$led:\n";
293 print $fh " ";
294 }
295 print $fh " ";
296 print $fh "$property:";
297 print $fh " $hashGroup{$group}{$led}{$property}\n";
298 }
299 }
300 }
Vishwanatha Subbannad0039432017-03-30 00:10:47 +0530301 # If we need to hand create some of the groups, do so now.
302 foreach my $name (@defaultGroup)
303 {
304 print $fh "$name:\n";
305 }
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530306 close $fh;
307}
308
George Liu78ae5822020-04-15 11:12:38 +0800309sub generateJSONFile
310{
311 package LEDGroups;
312 use JSON;
313 my $JSON = JSON->new->utf8->pretty(1);
314 $JSON->convert_blessed(1);
315
316 sub led
317 {
318 my $class = shift;
319 my $self = {
320 group => shift,
321 members => shift,
322 };
323 bless $self, $class;
324 return $self;
325 }
326
327 sub member
328 {
329 my $class = shift;
330 my $self = {
George Liu1b1aa6e2020-07-02 18:00:33 +0800331 Name => shift,
George Liu78ae5822020-04-15 11:12:38 +0800332 Action => shift,
333 DutyOn => shift,
334 Period => shift,
335 Priority => shift,
336 };
337 bless $self, $class;
338 return $self;
339 }
340
341 sub TO_JSON {
342 return { %{ shift() } };
343 }
344
345 my $fileName = $outputFile;
346 open(my $fh, '>', $fileName) or die "Could not open file '$fileName' $!";
347
348 my @leds = ();
349 foreach my $group (sort keys %hashGroup)
350 {
351 my @members = ();
352 foreach my $led (sort keys %{ $hashGroup{$group} })
353 {
354 my $action;
355 my $dutyOn;
356 my $period;
357 my $priority;
358
359 if (exists $hashGroup{$group}{$led}{Action})
360 {
361 $action = $hashGroup{$group}{$led}{Action};
362 $action = substr($action, 1, length($action) - 2);
363 }
364
365 if (exists $hashGroup{$group}{$led}{DutyOn})
366 {
367 $dutyOn = $hashGroup{$group}{$led}{DutyOn};
368 }
369
370 if (exists $hashGroup{$group}{$led}{Period})
371 {
372 $period = $hashGroup{$group}{$led}{Period};
373 }
374
375 if (exists $hashGroup{$group}{$led}{Priority})
376 {
377 $priority = $hashGroup{$group}{$led}{Priority};
378 $priority = substr($priority, 1, length($priority) - 2);
379 }
380
381 my $m = member LEDGroups($led, $action, $dutyOn, $period, $priority);
382 push @members, $m;
383 }
384 my $l = led LEDGroups($group, \@members);
385 push @leds, $l;
386 }
387 my %ledJson = ('leds' => \@leds);
388 my $json = $JSON->canonical(1)->encode(\%ledJson);
389 print $fh $json;
390 close $fh;
391}
392
Vishwanatha Subbanna37066462016-12-13 17:06:18 +0530393# Helper function to put debug statements.
394sub printDebug
395{
396 my $str = shift;
397 print "DEBUG: ", $str, "\n" if $debug;
398}
399
400# Usage
401sub printUsage
402{
403 print "
404 $0 -i [XML filename] -o [Output filename] [OPTIONS]
405Options:
406 -f = force output file creation even when errors
407 -d = debug mode
408 -v = verbose mode - for verbose o/p from Targets.pm
409
410PS: mrw::Targets can be found in https://github.com/open-power/serverwiz/
411 mrw::Inventory can be found in https://github.com/openbmc/phosphor-mrw-tools/
412 \n";
413 exit(1);
414}
415#------------------------------------END OF SUB-----------------------