1 package org.metricshub.ipmi.client.runner;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.stream.Collectors;
28
29 import org.metricshub.ipmi.client.IpmiClientConfiguration;
30 import org.metricshub.ipmi.client.model.Fru;
31 import org.metricshub.ipmi.core.coding.commands.IpmiVersion;
32 import org.metricshub.ipmi.core.coding.commands.fru.BaseUnit;
33 import org.metricshub.ipmi.core.coding.commands.fru.GetFruInventoryAreaInfo;
34 import org.metricshub.ipmi.core.coding.commands.fru.GetFruInventoryAreaInfoResponseData;
35 import org.metricshub.ipmi.core.coding.commands.fru.ReadFruData;
36 import org.metricshub.ipmi.core.coding.commands.fru.ReadFruDataResponseData;
37 import org.metricshub.ipmi.core.coding.commands.fru.record.BoardInfo;
38 import org.metricshub.ipmi.core.coding.commands.fru.record.ChassisInfo;
39 import org.metricshub.ipmi.core.coding.commands.fru.record.FruRecord;
40 import org.metricshub.ipmi.core.coding.commands.fru.record.ProductInfo;
41 import org.metricshub.ipmi.core.coding.commands.sdr.ReserveSdrRepository;
42 import org.metricshub.ipmi.core.coding.commands.sdr.ReserveSdrRepositoryResponseData;
43 import org.metricshub.ipmi.core.coding.commands.sdr.record.CompactSensorRecord;
44 import org.metricshub.ipmi.core.coding.commands.sdr.record.EntityId;
45 import org.metricshub.ipmi.core.coding.commands.sdr.record.FruDeviceLocatorRecord;
46 import org.metricshub.ipmi.core.coding.commands.sdr.record.SensorRecord;
47 import org.metricshub.ipmi.core.coding.payload.CompletionCode;
48 import org.metricshub.ipmi.core.coding.payload.lan.IPMIException;
49 import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
50
51
52
53
54 public class GetFrusRunner extends AbstractIpmiRunner<List<Fru>> {
55
56
57
58
59 private static final int DEFAULT_FRU_ID = 0;
60
61
62
63
64
65 private static final int FRU_READ_PACKET_SIZE = 16;
66
67 private boolean systemBoardFruUpdated = false;
68
69 public GetFrusRunner(IpmiClientConfiguration ipmiConfiguration) {
70 super(ipmiConfiguration);
71 }
72
73 @Override
74 public List<Fru> call() throws Exception {
75 final List<Fru> result = new ArrayList<>();
76
77 super.startSession();
78
79
80
81
82 nextRecId = 0;
83
84
85
86 int reservationId = 0;
87 int lastReservationId = -1;
88
89 List<FruRecord> systemBoardFruRecords = getFruRecords(DEFAULT_FRU_ID);
90
91
92
93 while (nextRecId < MAX_REPO_RECORD_ID) {
94
95 SensorRecord sensorRecord = null;
96
97 try {
98
99
100 sensorRecord = super.getSensorData(reservationId);
101
102 processFruRecord(result, sensorRecord, systemBoardFruRecords);
103
104 } catch (IPMIException e) {
105
106
107
108 if (lastReservationId == reservationId || e.getCompletionCode() != CompletionCode.ReservationCanceled) {
109 throw e;
110 }
111
112 lastReservationId = reservationId;
113
114
115
116
117
118
119 reservationId = ((ReserveSdrRepositoryResponseData) connector.sendMessage(handle,
120 new ReserveSdrRepository(IpmiVersion.V20, handle.getCipherSuite(), AuthenticationType.RMCPPlus))).getReservationId();
121 }
122
123 }
124
125 return result;
126 }
127
128
129
130
131
132
133
134
135
136 private void processFruRecord(final List<Fru> result, final SensorRecord sensorRecord, final List<FruRecord> systemBoardFruRecords) throws Exception {
137 try {
138
139 Fru fru = null;
140 if (sensorRecord instanceof FruDeviceLocatorRecord) {
141 FruDeviceLocatorRecord fruLocator = (FruDeviceLocatorRecord) sensorRecord;
142
143 if (fruLocator.isLogical()) {
144 List<FruRecord> fruRecords = getFruRecords(fruLocator.getDeviceId());
145
146 if (!fruRecords.isEmpty()) {
147 fru = new Fru(fruLocator, fruRecords);
148 }
149 }
150 } else if (!systemBoardFruRecords.isEmpty()
151 && !systemBoardFruUpdated
152 && sensorRecord instanceof CompactSensorRecord
153 && ((CompactSensorRecord) sensorRecord).getEntityId().equals(EntityId.SystemBoard)) {
154
155
156
157
158
159 CompactSensorRecord compactSensorRecord = (CompactSensorRecord) sensorRecord;
160
161 BoardInfo boardInfo = systemBoardFruRecords.stream()
162 .filter(BoardInfo.class::isInstance)
163 .map(BoardInfo.class::cast)
164 .findFirst()
165 .orElse(null);
166
167 if (boardInfo != null) {
168
169
170 FruDeviceLocatorRecord locator = new FruDeviceLocatorRecord();
171 locator.setFruEntityId(EntityId.SystemBoard.getCode());
172 locator.setFruEntityInstance(compactSensorRecord.getEntityInstanceNumber());
173 locator.setName(boardInfo.getBoardProductName() + " " + compactSensorRecord.getEntityInstanceNumber());
174
175 fru = new Fru(locator, systemBoardFruRecords);
176
177
178 systemBoardFruUpdated = true;
179
180 }
181 }
182
183
184 if (fru != null) {
185 result.add(fru);
186 }
187
188 } catch (IPMIException e) {
189
190 }
191
192 }
193
194
195
196
197
198
199
200
201 private List<FruRecord> getFruRecords(int fruId) throws Exception {
202 List<ReadFruDataResponseData> fruData = new ArrayList<>();
203
204
205 GetFruInventoryAreaInfoResponseData info = (GetFruInventoryAreaInfoResponseData) connector.sendMessage(handle,
206 new GetFruInventoryAreaInfo(IpmiVersion.V20, handle.getCipherSuite(), AuthenticationType.RMCPPlus, fruId));
207
208 int size = info.getFruInventoryAreaSize();
209 BaseUnit unit = info.getFruUnit();
210
211
212
213 for (int i = 0; i < size; i += FRU_READ_PACKET_SIZE) {
214 int fruReadPacketSize = FRU_READ_PACKET_SIZE;
215 if (i + fruReadPacketSize > size) {
216 fruReadPacketSize = size % FRU_READ_PACKET_SIZE;
217 }
218 try {
219
220 ReadFruDataResponseData data = (ReadFruDataResponseData) connector.sendMessage(handle,
221 new ReadFruData(IpmiVersion.V20, handle.getCipherSuite(), AuthenticationType.RMCPPlus, fruId, unit, i, fruReadPacketSize));
222
223 fruData.add(data);
224
225 } catch (Exception e) {
226
227 }
228 }
229
230 try {
231
232 return ReadFruData.decodeFruData(fruData).stream()
233 .filter(fruRecord -> fruRecord instanceof BoardInfo || fruRecord instanceof ChassisInfo || fruRecord instanceof ProductInfo)
234 .collect(Collectors.toList());
235
236 } catch (Exception e) {
237
238 }
239
240 return new ArrayList<>();
241 }
242 }