Skip to content

Commit 41455ef

Browse files
committed
webui: show last change and interface layering
The interface detail page lists a fixed set of status fields, so the new ietf-interfaces leaves did not show up. Add last change with its age, and the lower and higher layer interfaces linked to their own pages. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
1 parent c1dfc31 commit 41455ef

3 files changed

Lines changed: 53 additions & 0 deletions

File tree

‎src/webui/internal/handlers/interfaces.go‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package handlers
44

55
import (
6+
"time"
67
"fmt"
78
"html/template"
89
"log"
@@ -32,6 +33,9 @@ type ifaceJSON struct {
3233
Type string `json:"type"`
3334
Enabled *bool `json:"enabled"`
3435
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"`
3539
PhysAddress string `json:"phys-address"`
3640
CustomPhysAddress *customPhysAddress `json:"infix-interfaces:custom-phys-address"`
3741
IfIndex int `json:"if-index"`
@@ -545,6 +549,9 @@ type ifaceDetailData struct {
545549
Type string
546550
Status string
547551
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
548555
PhysAddr string
549556
IfIndex int
550557
MTU int
@@ -646,6 +653,9 @@ func buildDetailData(r *http.Request, iface *ifaceJSON) ifaceDetailData {
646653
StatusUp: iface.OperStatus == "up",
647654
PhysAddr: iface.PhysAddress,
648655
IfIndex: iface.IfIndex,
656+
LastChange: formatLastChange(iface.LastChange),
657+
HigherLayer: iface.HigherLayerIf,
658+
LowerLayer: iface.LowerLayerIf,
649659
}
650660

651661
if iface.IPv4 != nil {
@@ -916,6 +926,19 @@ func buildWifiScanEntry(sr wifiScanResultJSON) wifiScanEntry {
916926
return e
917927
}
918928

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+
919942
func formatDuration(secs int64) string {
920943
if secs < 60 {
921944
return fmt.Sprintf("%ds", secs)
@@ -982,6 +1005,9 @@ func (h *InterfacesHandler) fieldDescriptions() map[string]string {
9821005
ethPath := ifPath + "/ieee802-ethernet-interface:ethernet"
9831006
return map[string]string{
9841007
"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"),
9851011
"speed": schema.DescriptionOf(mgr, ifPath+"/speed"),
9861012
"duplex": schema.DescriptionOf(mgr, ethPath+"/duplex"),
9871013
"autoneg": schema.DescriptionOf(mgr, ethPath+"/auto-negotiation/enable"),
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package handlers
2+
3+
import (
4+
"strings"
5+
"testing"
6+
"time"
7+
)
8+
9+
func TestFormatLastChange(t *testing.T) {
10+
if got := formatLastChange(""); got != "" {
11+
t.Errorf("empty: got %q", got)
12+
}
13+
if got := formatLastChange("garbage"); got != "garbage" {
14+
t.Errorf("unparsable: got %q", got)
15+
}
16+
17+
stamp := time.Now().Add(-90 * time.Second).UTC().Format("2006-01-02T15:04:05+00:00")
18+
got := formatLastChange(stamp)
19+
if !strings.HasSuffix(got, "(1m ago)") {
20+
t.Errorf("age: got %q", got)
21+
}
22+
}

‎src/webui/templates/pages/iface-detail.html‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ <h2>{{.Name}}</h2>
2626
<th>Status</th>
2727
<td><span class="status-dot {{if .StatusUp}}status-up{{else}}status-down{{end}}"></span>{{.Status}}</td>
2828
</tr>
29+
{{if .LastChange}}<tr><th>Last change{{template "field-info" (index .Desc "last-change")}}</th><td>{{.LastChange}}</td></tr>{{end}}
30+
{{if .LowerLayer}}<tr><th>Lower layer{{template "field-info" (index .Desc "lower-layer-if")}}</th><td>{{template "iface-links" .LowerLayer}}</td></tr>{{end}}
31+
{{if .HigherLayer}}<tr><th>Higher layer{{template "field-info" (index .Desc "higher-layer-if")}}</th><td>{{template "iface-links" .HigherLayer}}</td></tr>{{end}}
2932
{{if .PhysAddr}}<tr><th>MAC Address</th><td>{{.PhysAddr}}</td></tr>{{end}}
3033
{{if .MTU}}<tr><th>MTU{{template "field-info" (index .Desc "mtu")}}</th><td>{{.MTU}}</td></tr>{{end}}
3134
{{if .Speed}}<tr><th>Speed{{template "field-info" (index .Desc "speed")}}</th><td>{{.Speed}}</td></tr>{{end}}
@@ -176,3 +179,5 @@ <h3>Addresses</h3>
176179
</section>
177180
{{end}}
178181
{{end}}
182+
183+
{{define "iface-links"}}{{range $i, $name := .}}{{if $i}}, {{end}}<a href="/interfaces/{{$name}}" hx-get="/interfaces/{{$name}}" hx-target="#content" hx-push-url="true">{{$name}}</a>{{end}}{{end}}

0 commit comments

Comments
 (0)