Skip to content

Commit f44d70d

Browse files
committed
switch error field add
1 parent f2ecee7 commit f44d70d

5 files changed

Lines changed: 246 additions & 89 deletions

File tree

nodescraper/command_artifact_html.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,17 @@
121121
}
122122
pre.stderr { color: var(--fail-fg); }
123123
.no-results { color: var(--muted); padding: 24px; text-align: center; display: none; }
124+
.copy-btn {
125+
flex: 0 0 auto;
126+
display: inline-flex; align-items: center; justify-content: center;
127+
background: var(--bg); color: var(--muted);
128+
border: 1px solid var(--border); border-radius: 6px;
129+
padding: 5px 7px; cursor: pointer; line-height: 0;
130+
transition: color .15s ease, border-color .15s ease, background .15s ease;
131+
}
132+
.copy-btn:hover { background: var(--panel-hover); border-color: var(--accent); color: var(--text); }
133+
.copy-btn.copied { color: var(--ok-fg); border-color: var(--ok-fg); }
134+
.copy-btn svg { display: block; }
124135
</style>
125136
</head>
126137
<body>
@@ -143,6 +154,9 @@
143154
<span class="chevron">&#9656;</span>
144155
<code class="title">{command}</code>
145156
<span class="badge {badge_cls}">exit {exit_code}</span>
157+
<button class="copy-btn" type="button" title="Copy output" aria-label="Copy output">
158+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
159+
</button>
146160
</summary>
147161
<div class="body">
148162
{stdout_block}
@@ -176,6 +190,51 @@
176190
document.getElementById('collapseAll').addEventListener('click', () => {
177191
items.forEach(d => d.open = false);
178192
});
193+
194+
const copyButtons = Array.from(document.querySelectorAll('.copy-btn'));
195+
const COPY_SVG = copyButtons.length ? copyButtons[0].innerHTML : '';
196+
const CHECK_SVG = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>';
197+
198+
function showCopied(btn) {
199+
btn.classList.add('copied');
200+
btn.innerHTML = CHECK_SVG;
201+
if (btn._resetTimer) clearTimeout(btn._resetTimer);
202+
btn._resetTimer = setTimeout(() => {
203+
btn.classList.remove('copied');
204+
btn.innerHTML = COPY_SVG;
205+
}, 1200);
206+
}
207+
208+
function fallbackCopy(text, btn) {
209+
const ta = document.createElement('textarea');
210+
ta.value = text;
211+
ta.style.position = 'fixed';
212+
ta.style.top = '-1000px';
213+
ta.style.opacity = '0';
214+
document.body.appendChild(ta);
215+
ta.focus();
216+
ta.select();
217+
try { document.execCommand('copy'); showCopied(btn); } catch (e) {}
218+
document.body.removeChild(ta);
219+
}
220+
221+
copyButtons.forEach(btn => {
222+
btn.addEventListener('click', (e) => {
223+
e.preventDefault();
224+
e.stopPropagation();
225+
const card = btn.closest('details.cmd');
226+
const parts = [];
227+
card.querySelectorAll('pre').forEach(pre => {
228+
if (!pre.classList.contains('empty')) parts.push(pre.textContent);
229+
});
230+
const text = parts.join('\\n');
231+
if (navigator.clipboard && navigator.clipboard.writeText) {
232+
navigator.clipboard.writeText(text).then(() => showCopied(btn)).catch(() => fallbackCopy(text, btn));
233+
} else {
234+
fallbackCopy(text, btn);
235+
}
236+
});
237+
});
179238
</script>
180239
</body>
181240
</html>

nodescraper/plugins/inband/switch/scale_out_arista/scaleoutaristadata.py

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#
2525
###############################################################################
2626

27-
from typing import ClassVar, Dict, List, Optional, Union
27+
from typing import ClassVar, Dict, List, Optional
2828

2929
from pydantic import BaseModel, ConfigDict
3030
from pydantic.alias_generators import to_camel
@@ -98,8 +98,8 @@ class FanConfiguration(BaseModel):
9898
speed_hw_override: Optional[bool] = None
9999
speed_stable: Optional[bool] = None
100100

101-
error_fields: ClassVar[dict[str, str]] = {
102-
"status": "ok",
101+
error_fields: ClassVar[dict[str, List[str]]] = {
102+
"status": ["ok"],
103103
}
104104

105105

@@ -124,9 +124,9 @@ class AristaSystemEnv(BaseModel):
124124
power_supply_slots: Optional[List[FanConfiguration]] = None
125125
fan_tray_slots: Optional[List[FanConfiguration]] = None
126126

127-
error_fields: ClassVar[dict[str, Union[str, bool]]] = {
128-
"system_status": "coolingOk",
129-
"fans_status": "fanAlarmOk",
127+
error_fields: ClassVar[dict[str, List[str]]] = {
128+
"system_status": ["coolingOk"],
129+
"fans_status": ["fanAlarmOk"],
130130
}
131131

132132

@@ -139,9 +139,9 @@ class VlanInformation(BaseModel):
139139
interface_mode: Optional[str] = None
140140
interface_forwarding_model: Optional[str] = None
141141

142-
error_fields: ClassVar[dict[str, str]] = {
143-
"interface_mode": "routed",
144-
"interface_forwarding_model": "routed",
142+
error_fields: ClassVar[dict[str, List[str]]] = {
143+
"interface_mode": ["routed"],
144+
"interface_forwarding_model": ["routed"],
145145
}
146146

147147

@@ -160,10 +160,10 @@ class AristaPortStatus(BaseModel):
160160
line_protocol_status: Optional[str] = None
161161
interface_damped: Optional[bool] = None
162162

163-
error_fields: ClassVar[dict[str, str]] = {
164-
"link_status": "connected",
165-
"duplex": "duplexFull",
166-
"line_protocol_status": "up",
163+
error_fields: ClassVar[dict[str, List[str]]] = {
164+
"link_status": ["connected"],
165+
"duplex": ["duplexFull"],
166+
"line_protocol_status": ["up"],
167167
}
168168

169169

@@ -180,14 +180,14 @@ class AristaCountersErrors(BaseModel):
180180
alignment_errors: Optional[int] = None
181181
symbol_errors: Optional[int] = None
182182

183-
error_fields: ClassVar[dict[str, str]] = {
184-
"in_errors": "0",
185-
"frame_too_longs": "0",
186-
"out_errors": "0",
187-
"frame_too_shorts": "0",
188-
"fcs_errors": "0",
189-
"alignment_errors": "0",
190-
"symbol_errors": "0",
183+
error_fields: ClassVar[dict[str, List[str]]] = {
184+
"in_errors": ["0"],
185+
"frame_too_longs": ["0"],
186+
"out_errors": ["0"],
187+
"frame_too_shorts": ["0"],
188+
"fcs_errors": ["0"],
189+
"alignment_errors": ["0"],
190+
"symbol_errors": ["0"],
191191
}
192192

193193

@@ -259,10 +259,10 @@ class AristaDroppedPacketCounters(BaseModel):
259259
out_uc_dropped_pkts: Optional[int] = None
260260
out_mc_dropped_pkts: Optional[int] = None
261261

262-
warning_fields: ClassVar[dict[str, str]] = {
263-
"in_dropped_pkts": "0",
264-
"out_uc_dropped_pkts": "0",
265-
"out_mc_dropped_pkts": "0",
262+
warning_fields: ClassVar[dict[str, List[str]]] = {
263+
"in_dropped_pkts": ["0"],
264+
"out_uc_dropped_pkts": ["0"],
265+
"out_mc_dropped_pkts": ["0"],
266266
}
267267

268268

@@ -275,10 +275,10 @@ class AristaDropPrecedenceCounters(BaseModel):
275275
dp1_dropped_pkts: Optional[int] = None
276276
dp2_dropped_pkts: Optional[int] = None
277277

278-
error_fields: ClassVar[dict[str, str]] = {
279-
"dp0_dropped_pkts": "0",
280-
"dp1_dropped_pkts": "0",
281-
"dp2_dropped_pkts": "0",
278+
error_fields: ClassVar[dict[str, List[str]]] = {
279+
"dp0_dropped_pkts": ["0"],
280+
"dp1_dropped_pkts": ["0"],
281+
"dp2_dropped_pkts": ["0"],
282282
}
283283

284284

@@ -293,9 +293,9 @@ class AristaPerQueueCounters(BaseModel):
293293
pkts_drop: Optional[int] = None
294294
bytes_drop: Optional[int] = None
295295

296-
warning_fields: ClassVar[dict[str, str]] = {
297-
"pkts_drop": "0",
298-
"bytes_drop": "0",
296+
warning_fields: ClassVar[dict[str, List[str]]] = {
297+
"pkts_drop": ["0"],
298+
"bytes_drop": ["0"],
299299
}
300300

301301

@@ -311,9 +311,9 @@ class AristaPauseFrameCounters(BaseModel):
311311
tx_pause: Optional[int] = None
312312
rx_pause: Optional[int] = None
313313

314-
error_fields: ClassVar[dict[str, str]] = {
315-
"tx_pause": "0",
316-
"rx_pause": "0",
314+
error_fields: ClassVar[dict[str, List[str]]] = {
315+
"tx_pause": ["0"],
316+
"rx_pause": ["0"],
317317
}
318318

319319

@@ -325,8 +325,8 @@ class AristaEcnCounters(BaseModel):
325325
txq: Optional[str] = None
326326
marked_packets: Optional[str] = None
327327

328-
warning_fields: ClassVar[dict[str, str]] = {
329-
"marked_packets": "0",
328+
warning_fields: ClassVar[dict[str, List[str]]] = {
329+
"marked_packets": ["0", "-"],
330330
}
331331

332332

@@ -338,9 +338,9 @@ class AristaPfcCounters(BaseModel):
338338
rx_frames: Optional[int] = None
339339
tx_frames: Optional[int] = None
340340

341-
warning_fields: ClassVar[dict[str, str]] = {
342-
"rx_frames": "0",
343-
"tx_frames": "0",
341+
warning_fields: ClassVar[dict[str, List[str]]] = {
342+
"rx_frames": ["0"],
343+
"tx_frames": ["0"],
344344
}
345345

346346

nodescraper/plugins/inband/switch/scale_out_dell/scaleoutdelldata.py

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ class DellArpEntry(BaseModel):
4444
type: Optional[str] = None
4545
action: Optional[str] = None
4646

47-
error_fields: ClassVar[dict[str, str]] = {
48-
"address": "NOT_NULL",
49-
"hardware_address": "NOT_NULL",
47+
error_fields: ClassVar[dict[str, List[str]]] = {
48+
"address": ["NOT_NULL"],
49+
"hardware_address": ["NOT_NULL"],
5050
}
5151

5252

@@ -62,8 +62,8 @@ class DellRouteEntry(BaseModel):
6262
distance_metric: Optional[str] = None
6363
last_update: Optional[str] = None
6464

65-
error_fields: ClassVar[dict[str, str]] = {
66-
"destination": "NOT_NULL",
65+
error_fields: ClassVar[dict[str, List[str]]] = {
66+
"destination": ["NOT_NULL"],
6767
}
6868

6969

@@ -81,8 +81,8 @@ class DellInterfaceStatus(BaseModel):
8181
mtu: Optional[int] = None
8282
alternate_name: Optional[str] = None
8383

84-
error_fields: ClassVar[dict[str, str]] = {
85-
"oper": "up",
84+
error_fields: ClassVar[dict[str, List[str]]] = {
85+
"oper": ["up"],
8686
}
8787

8888

@@ -112,17 +112,17 @@ class DellInterfaceCounters(BaseModel):
112112
tx_drp: Optional[int] = None
113113
tx_oversize: Optional[int] = None
114114

115-
error_fields: ClassVar[dict[str, str]] = {
116-
"state": "U",
117-
"rx_err": "0",
118-
"rx_oversize": "0",
119-
"tx_err": "0",
120-
"tx_oversize": "0",
115+
error_fields: ClassVar[dict[str, List[str]]] = {
116+
"state": ["U"],
117+
"rx_err": ["0"],
118+
"rx_oversize": ["0"],
119+
"tx_err": ["0"],
120+
"tx_oversize": ["0"],
121121
}
122122

123-
warning_fields: ClassVar[dict[str, str]] = {
124-
"rx_drp": "0",
125-
"tx_drp": "0",
123+
warning_fields: ClassVar[dict[str, List[str]]] = {
124+
"rx_drp": ["0"],
125+
"tx_drp": ["0"],
126126
}
127127

128128

@@ -168,14 +168,14 @@ class DellInterfaceDetailCounters(BaseModel):
168168

169169
time_since_counters_last_cleared: Optional[str] = None
170170

171-
error_fields: ClassVar[dict[str, str]] = {
172-
"packets_received_9217_16383_octets": "0",
173-
"packets_transmitted_9217_16383_octets": "0",
174-
"jabbers_received": "0",
175-
"fragments_received": "0",
176-
"undersize_received": "0",
177-
"overruns_received": "0",
178-
"crc_errors_received": "0",
171+
error_fields: ClassVar[dict[str, List[str]]] = {
172+
"packets_received_9217_16383_octets": ["0"],
173+
"packets_transmitted_9217_16383_octets": ["0"],
174+
"jabbers_received": ["0"],
175+
"fragments_received": ["0"],
176+
"undersize_received": ["0"],
177+
"overruns_received": ["0"],
178+
"crc_errors_received": ["0"],
179179
}
180180

181181

@@ -193,9 +193,9 @@ class DellQueueCounter(BaseModel):
193193
drop_pkts: Optional[int] = None
194194
drop_bytes: Optional[int] = None
195195

196-
warning_fields: ClassVar[dict[str, str]] = {
197-
"drop_pkts": "0",
198-
"drop_bytes": "0",
196+
warning_fields: ClassVar[dict[str, List[str]]] = {
197+
"drop_pkts": ["0"],
198+
"drop_bytes": ["0"],
199199
}
200200

201201

@@ -217,15 +217,15 @@ class DellPfcStatistics(BaseModel):
217217
pfc6: Optional[int] = None
218218
pfc7: Optional[int] = None
219219

220-
warning_fields: ClassVar[dict[str, str]] = {
221-
"pfc0": "0",
222-
"pfc1": "0",
223-
"pfc2": "0",
224-
"pfc3": "0",
225-
"pfc4": "0",
226-
"pfc5": "0",
227-
"pfc6": "0",
228-
"pfc7": "0",
220+
warning_fields: ClassVar[dict[str, List[str]]] = {
221+
"pfc0": ["0"],
222+
"pfc1": ["0"],
223+
"pfc2": ["0"],
224+
"pfc3": ["0"],
225+
"pfc4": ["0"],
226+
"pfc5": ["0"],
227+
"pfc6": ["0"],
228+
"pfc7": ["0"],
229229
}
230230

231231

@@ -247,17 +247,17 @@ class DellPfcWatchdogQueueStats(BaseModel):
247247
rx_last_ok: Optional[int] = None
248248
rx_last_drop: Optional[int] = None
249249

250-
warning_fields: ClassVar[dict[str, str]] = {
251-
"storms_detected": "0",
252-
"storms_restored": "0",
253-
"transmitted_ok": "0",
254-
"transmitted_drop": "0",
255-
"received_ok": "0",
256-
"received_drop": "0",
257-
"tx_last_ok": "0",
258-
"tx_last_drop": "0",
259-
"rx_last_ok": "0",
260-
"rx_last_drop": "0",
250+
warning_fields: ClassVar[dict[str, List[str]]] = {
251+
"storms_detected": ["0"],
252+
"storms_restored": ["0"],
253+
"transmitted_ok": ["0"],
254+
"transmitted_drop": ["0"],
255+
"received_ok": ["0"],
256+
"received_drop": ["0"],
257+
"tx_last_ok": ["0"],
258+
"tx_last_drop": ["0"],
259+
"rx_last_ok": ["0"],
260+
"rx_last_drop": ["0"],
261261
}
262262

263263

0 commit comments

Comments
 (0)