163 lines
4.9 KiB
TypeScript
163 lines
4.9 KiB
TypeScript
import moment from 'moment'
|
|
import { normalizeInterface } from '../ultils/helper.js'
|
|
import { PhysicalTestReport, PhysicalTestResult, PortState } from '../ultils/types.js'
|
|
const LINK_UPDOWN_REGEX =
|
|
/Interface\s+((?:FastEthernet|GigabitEthernet|TenGigabitEthernet|TwentyFiveGigE|FortyGigabitEthernet|HundredGigE|Ethernet|Port-channel|Fa|Gi|Te|Hu|Eth)[\w\/.-]+),\s+changed state to\s+(up|down)/i
|
|
|
|
export class PhysicalPortTest {
|
|
public ports = new Map<string, PortState>()
|
|
private expectedPorts: string[]
|
|
public done = false
|
|
private startTime: Date
|
|
public inventory: any
|
|
|
|
constructor(expectedPorts: string[]) {
|
|
this.expectedPorts = expectedPorts
|
|
this.startTime = new Date()
|
|
this.inventory = ''
|
|
|
|
expectedPorts.forEach((p) => {
|
|
this.ports.set(normalizeInterface(p), {
|
|
name: normalizeInterface(p),
|
|
tested: false,
|
|
})
|
|
})
|
|
}
|
|
|
|
start(expectedPorts: string[], inventory: any) {
|
|
this.ports.clear()
|
|
this.startTime = new Date()
|
|
this.expectedPorts = expectedPorts
|
|
this.inventory = inventory
|
|
this.done = false
|
|
expectedPorts.forEach((p) => {
|
|
this.ports.set(normalizeInterface(p), {
|
|
name: normalizeInterface(p),
|
|
tested: false,
|
|
})
|
|
})
|
|
// this.connection.writeCommand('terminal length 0')
|
|
// this.connection.writeCommand('terminal monitor')
|
|
// this.connection.onLog((line) => {
|
|
// this.handleLog(line);
|
|
// });
|
|
}
|
|
|
|
handleLog(line: string) {
|
|
const match = line.match(LINK_UPDOWN_REGEX)
|
|
if (!match) return
|
|
|
|
const rawIface = match[1]
|
|
const state = match[2] as 'up' | 'down'
|
|
const iface = normalizeInterface(rawIface)
|
|
|
|
const port = this.ports.get(iface)
|
|
if (!port) return
|
|
|
|
// tránh update trùng state liên tiếp
|
|
if (port.lastState === state) return
|
|
|
|
port.lastState = state
|
|
port.lastSeen = new Date()
|
|
|
|
// chỉ cần UP 1 lần là pass
|
|
if (state === 'up' && !port.tested) {
|
|
port.tested = true
|
|
this.checkDone()
|
|
}
|
|
|
|
return this.getTestedPorts()
|
|
}
|
|
|
|
getTestedPorts(): string[] {
|
|
return Array.from(this.ports.values())
|
|
.filter((p) => p.tested)
|
|
.map((p) => p.name)
|
|
.sort()
|
|
}
|
|
|
|
private checkDone() {
|
|
const testedCount = [...this.ports.values()].filter((p) => p.tested).length
|
|
|
|
if (testedCount === this.expectedPorts.length) {
|
|
this.done = true
|
|
this.onDone()
|
|
}
|
|
}
|
|
|
|
onDone() {
|
|
this.getFormReport()
|
|
// this.ports.clear()
|
|
console.log('✅ Physical Test DONE')
|
|
}
|
|
|
|
getFormReport() {
|
|
const report: PhysicalTestReport = {
|
|
device: {
|
|
model: this?.inventory?.pid || '',
|
|
serial: this?.inventory?.sn || '',
|
|
},
|
|
startTime: this.startTime,
|
|
endTime: new Date(),
|
|
durationMs: Date.now() - this.startTime.getTime(),
|
|
ports: Array.from(this.ports.values()),
|
|
}
|
|
return this.generateEmailReport(report)
|
|
// console.log('✅ Physical Test DONE')
|
|
}
|
|
|
|
getResult(): PhysicalTestResult {
|
|
const tested = [...this.ports.values()].filter((p) => p.tested)
|
|
const missing = [...this.ports.values()].filter((p) => !p.tested).map((p) => p.name)
|
|
|
|
return {
|
|
expected: this.expectedPorts.length,
|
|
tested: tested.length,
|
|
missingPorts: missing,
|
|
status: this.done ? 'DONE' : 'RUNNING',
|
|
}
|
|
}
|
|
|
|
generateEmailReport(report: PhysicalTestReport): string {
|
|
const tested = report.ports.filter((p) => p.tested)
|
|
const missing = report.ports.filter((p) => !p.tested)
|
|
|
|
const status = missing.length === 0 ? 'PASS' : 'WARNING'
|
|
|
|
return `
|
|
Physical Port Test Report<br/>
|
|
────────────────────────────────<br/>
|
|
Model : <b>${report.device.model ?? 'N/A'}</b><br/>
|
|
Serial Number : <b>${report.device.serial ?? 'N/A'}</b><br/>
|
|
Started At : ${moment(report.startTime).format('YYYY/MM/DD, HH:mm:ss')}<br/>
|
|
Finished At : ${moment(report.endTime).format('YYYY/MM/DD, HH:mm:ss')}<br/>
|
|
Duration : ${Math.floor(report.durationMs / 1000)} sec<br/>
|
|
Status : ${status === 'PASS' ? '✅ PASS' : '⚠️ WARNING'}<br/>
|
|
<br/>
|
|
────────────────────────────────<br/>
|
|
<b>Test Summary</b><br/>
|
|
────────────<br/>
|
|
Total Ports : ${report.ports.length}<br/>
|
|
Ports Tested (UP) : ${tested.length}<br/>
|
|
Ports Missing : ${missing.length}<br/>
|
|
<br/>
|
|
────────────────────────────────<br/>
|
|
<b>Passed Ports</b><br/>
|
|
────────────<br/>
|
|
${tested.map((p) => p.name).join('<br/>')}<br/>
|
|
<br/>
|
|
${
|
|
missing.length
|
|
? `
|
|
────────────────────────────────<br/>
|
|
<b>Missing Ports</b><br/>
|
|
─────────────<br/>
|
|
${missing.map((p) => p.name).join('<br/>')}
|
|
`
|
|
: ''
|
|
}<br/>
|
|
<br/>
|
|
`.trim()
|
|
}
|
|
}
|