|
3 | 3 | package handlers |
4 | 4 |
|
5 | 5 | import ( |
| 6 | + "time" |
6 | 7 | "fmt" |
7 | 8 | "html/template" |
8 | 9 | "log" |
@@ -32,6 +33,9 @@ type ifaceJSON struct { |
32 | 33 | Type string `json:"type"` |
33 | 34 | Enabled *bool `json:"enabled"` |
34 | 35 | OperStatus string `json:"oper-status"` |
| 36 | + LastChange string `json:"last-change"` |
| 37 | + HigherLayerIf []string `json:"higher-layer-if"` |
| 38 | + LowerLayerIf []string `json:"lower-layer-if"` |
35 | 39 | PhysAddress string `json:"phys-address"` |
36 | 40 | CustomPhysAddress *customPhysAddress `json:"infix-interfaces:custom-phys-address"` |
37 | 41 | IfIndex int `json:"if-index"` |
@@ -545,6 +549,9 @@ type ifaceDetailData struct { |
545 | 549 | Type string |
546 | 550 | Status string |
547 | 551 | StatusUp bool |
| 552 | + LastChange string // local time with age, "" if unknown |
| 553 | + HigherLayer []string // interfaces stacked on top of this one |
| 554 | + LowerLayer []string // interfaces this one is stacked on |
548 | 555 | PhysAddr string |
549 | 556 | IfIndex int |
550 | 557 | MTU int |
@@ -646,6 +653,9 @@ func buildDetailData(r *http.Request, iface *ifaceJSON) ifaceDetailData { |
646 | 653 | StatusUp: iface.OperStatus == "up", |
647 | 654 | PhysAddr: iface.PhysAddress, |
648 | 655 | IfIndex: iface.IfIndex, |
| 656 | + LastChange: formatLastChange(iface.LastChange), |
| 657 | + HigherLayer: iface.HigherLayerIf, |
| 658 | + LowerLayer: iface.LowerLayerIf, |
649 | 659 | } |
650 | 660 |
|
651 | 661 | if iface.IPv4 != nil { |
@@ -916,6 +926,19 @@ func buildWifiScanEntry(sr wifiScanResultJSON) wifiScanEntry { |
916 | 926 | return e |
917 | 927 | } |
918 | 928 |
|
| 929 | +// formatLastChange renders a YANG date-and-time as local time with its age. |
| 930 | +func formatLastChange(s string) string { |
| 931 | + if s == "" { |
| 932 | + return "" |
| 933 | + } |
| 934 | + t, err := time.Parse(time.RFC3339, s) |
| 935 | + if err != nil { |
| 936 | + return s |
| 937 | + } |
| 938 | + return fmt.Sprintf("%s (%s ago)", t.Local().Format("2006-01-02 15:04:05"), |
| 939 | + formatRelDuration(time.Since(t))) |
| 940 | +} |
| 941 | + |
919 | 942 | func formatDuration(secs int64) string { |
920 | 943 | if secs < 60 { |
921 | 944 | return fmt.Sprintf("%ds", secs) |
@@ -982,6 +1005,9 @@ func (h *InterfacesHandler) fieldDescriptions() map[string]string { |
982 | 1005 | ethPath := ifPath + "/ieee802-ethernet-interface:ethernet" |
983 | 1006 | return map[string]string{ |
984 | 1007 | "mtu": schema.DescriptionOf(mgr, ifPath+"/ietf-ip:ipv4/mtu"), |
| 1008 | + "last-change": schema.DescriptionOf(mgr, ifPath+"/last-change"), |
| 1009 | + "higher-layer-if": schema.DescriptionOf(mgr, ifPath+"/higher-layer-if"), |
| 1010 | + "lower-layer-if": schema.DescriptionOf(mgr, ifPath+"/lower-layer-if"), |
985 | 1011 | "speed": schema.DescriptionOf(mgr, ifPath+"/speed"), |
986 | 1012 | "duplex": schema.DescriptionOf(mgr, ethPath+"/duplex"), |
987 | 1013 | "autoneg": schema.DescriptionOf(mgr, ethPath+"/auto-negotiation/enable"), |
|
0 commit comments