implement basic status checking
diff --git a/service.go b/service.go
index 916299c..03fd218 100644
--- a/service.go
+++ b/service.go
@@ -14,6 +14,8 @@
"code.hackerspace.pl/q3k/topo/graph"
"code.hackerspace.pl/q3k/topo/state"
+
+ pb "code.hackerspace.pl/q3k/topo/proto/control"
)
type ServiceConfig struct {
@@ -34,9 +36,6 @@
}
}
-type TopologyStatus struct {
-}
-
const topologyFragment = `
<script src="/assets/viz.js"></script>
<script>
@@ -59,58 +58,179 @@
<div id="graph" style="text-align: center;"></div>
`
+const switchportsFragment = `
+ <style type="text/css">
+ .table td,th {
+ background-color: #eee;
+ padding: 0.2em 0.4em 0.2em 0.4em;
+ }
+ .table th {
+ background-color: #c0c0c0;
+ }
+ .table {
+ background-color: #fff;
+ border-spacing: 0.2em;
+ margin-left: auto;
+ margin-right: auto;
+ }
+ </style>
+ <div>
+ <table class="table">
+ <tr>
+ <th>Switch</th>
+ <th>Port</th>
+ <th>Link State</th>
+ <th>Port Mode</th>
+ <th>MTU</th>
+ <th>Sync Status</th>
+ </tr>
+ {{range .Ports }}
+ {{ if .Managed }}
+ <tr>
+ {{ else }}
+ <tr style="opacity: 0.5">
+ {{ end}}
+ <td style="text-align: right;">{{ .Switch }}</td>
+ <td>{{ .Name }}</td>
+ {{ if eq .State "DOWN" }}
+ <td style="background-color: #ff3030;">{{ .State }}</td>
+ {{ else }}
+ <td>{{ .State }}</td>
+ {{ end }}
+ <td>{{ .Mode }}</td>
+ <td>{{ .MTU }}</td>
+ {{ if .Managed }}
+ <td style="background-color: #30ff30;">OK</td>
+ {{ else }}
+ <td><i>Unmanaged</i></td>
+ {{ end }}
+ </tr>
+ {{end}}
+ </table>
+ </div>
+`
+
func (s *Service) Run() {
assets := packr.NewBox("./assets")
http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(assets)))
-
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/debug/status", http.StatusSeeOther)
})
+ http.HandleFunc("/debug/graphviz", s.httpHandleGraphviz)
- http.HandleFunc("/debug/graphviz", func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, "graph G {\n")
- fmt.Fprintf(w, " ranksep = 2\n")
- fmt.Fprintf(w, " splines = polyline\n")
- fmt.Fprintf(w, " rankdir = LR\n")
- for _, machine := range s.gr.Machines {
- portNames := []string{}
- for _, port := range machine.Ports {
- name := fmt.Sprintf("<%s> %s", port.Name, port.Name)
- portNames = append(portNames, name)
- }
- ports := strings.Join(portNames, "|")
- fmt.Fprintf(w, " %s [shape=record label=\"{ %s | { %s }}\"]\n", machine.Name, machine.Name, ports)
- }
- for _, sw := range s.gr.Switches {
- portNames := []string{}
- portsOrdered := []*graph.SwitchPort{}
- for _, port := range sw.Ports {
- portsOrdered = append(portsOrdered, port)
- }
- sort.Slice(portsOrdered, func(i, j int) bool {
- return sortorder.NaturalLess(portsOrdered[i].Name, portsOrdered[j].Name)
- })
- for _, port := range portsOrdered {
- name := fmt.Sprintf("<%s> %s", port.Name, port.Name)
- portNames = append(portNames, name)
- }
- ports := strings.Join(portNames, "|")
- fmt.Fprintf(w, " %s [shape=record label=\"{{ %s } | %s}\"]\n", sw.Name, ports, sw.Name)
- }
- for _, machine := range s.gr.Machines {
- for _, port := range machine.Ports {
- if port.OtherEnd == nil {
- continue
- }
- fmt.Fprintf(w, " %s:%q:e -- %s:%q:w\n", machine.Name, port.Name, port.OtherEnd.Switch.Name, port.OtherEnd.Name)
- }
- }
- fmt.Fprintf(w, "}\n")
- })
-
+ statusz.AddStatusPart("Switch Ports", switchportsFragment, s.statusHandleSwitchports)
statusz.AddStatusPart("Topology", topologyFragment, func(ctx context.Context) interface{} {
- return &TopologyStatus{}
+ return nil
})
glog.Infof("Debug listening on %s....", s.config.DebugListen)
http.ListenAndServe(s.config.DebugListen, nil)
}
+
+func (s *Service) statusHandleSwitchports(ctx context.Context) interface{} {
+ managedPorts := make(map[string]bool)
+ s.gr.Mu.RLock()
+ for _, sw := range s.gr.Switches {
+ for _, port := range sw.Ports {
+ managedPorts[sw.Name+"|"+port.Name] = true
+ }
+ }
+ s.gr.Mu.RUnlock()
+
+ s.stm.Mu.RLock()
+ defer s.stm.Mu.RUnlock()
+
+ res := struct {
+ Ports []*struct {
+ Switch string
+ Name string
+ State string
+ Mode string
+ Managed bool
+ MTU string
+ }
+ }{}
+ for _, sw := range s.stm.Switches {
+ for _, po := range sw.Ports {
+ state := "INVALID"
+ switch po.Proto.LinkState {
+ case pb.SwitchPort_LINKSTATE_DOWN:
+ state = "DOWN"
+ case pb.SwitchPort_LINKSTATE_UP:
+ state = "UP"
+ }
+ mode := "INVALID"
+ switch po.Proto.PortMode {
+ case pb.SwitchPort_PORTMODE_SWITCHPORT_UNTAGGED:
+ mode = fmt.Sprintf("UNTAGGED (%d)", po.Proto.VlanNative)
+ case pb.SwitchPort_PORTMODE_SWITCHPORT_TAGGED:
+ mode = fmt.Sprintf("TAGGED (%v)", po.Proto.VlanTagged)
+ case pb.SwitchPort_PORTMODE_SWITCHPORT_GENERIC:
+ mode = "GENERIC"
+ case pb.SwitchPort_PORTMODE_ROUTED:
+ mode = "ROUTED"
+ case pb.SwitchPort_PORTMODE_MANGLED:
+ mode = "MANGLED"
+ }
+
+ managed := managedPorts[sw.Name+"|"+po.Proto.Name]
+ res.Ports = append(res.Ports, &struct {
+ Switch string
+ Name string
+ State string
+ Mode string
+ Managed bool
+ MTU string
+ }{
+ Switch: sw.Name,
+ Name: po.Proto.Name,
+ State: state,
+ Mode: mode,
+ Managed: managed,
+ MTU: fmt.Sprintf("%d", po.Proto.Mtu),
+ })
+ }
+ }
+
+ return res
+}
+
+func (s *Service) httpHandleGraphviz(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "graph G {\n")
+ fmt.Fprintf(w, " ranksep = 2\n")
+ fmt.Fprintf(w, " splines = polyline\n")
+ fmt.Fprintf(w, " rankdir = LR\n")
+ for _, machine := range s.gr.Machines {
+ portNames := []string{}
+ for _, port := range machine.Ports {
+ name := fmt.Sprintf("<%s> %s", port.Name, port.Name)
+ portNames = append(portNames, name)
+ }
+ ports := strings.Join(portNames, "|")
+ fmt.Fprintf(w, " %s [shape=record label=\"{ %s | { %s }}\"]\n", machine.Name, machine.Name, ports)
+ }
+ for _, sw := range s.gr.Switches {
+ portNames := []string{}
+ portsOrdered := []*graph.SwitchPort{}
+ for _, port := range sw.Ports {
+ portsOrdered = append(portsOrdered, port)
+ }
+ sort.Slice(portsOrdered, func(i, j int) bool {
+ return sortorder.NaturalLess(portsOrdered[i].Name, portsOrdered[j].Name)
+ })
+ for _, port := range portsOrdered {
+ name := fmt.Sprintf("<%s> %s", port.Name, port.Name)
+ portNames = append(portNames, name)
+ }
+ ports := strings.Join(portNames, "|")
+ fmt.Fprintf(w, " %s [shape=record label=\"{{ %s } | %s}\"]\n", sw.Name, ports, sw.Name)
+ }
+ for _, machine := range s.gr.Machines {
+ for _, port := range machine.Ports {
+ if port.OtherEnd == nil {
+ continue
+ }
+ fmt.Fprintf(w, " %s:%q:e -- %s:%q:w\n", machine.Name, port.Name, port.OtherEnd.Switch.Name, port.OtherEnd.Name)
+ }
+ }
+ fmt.Fprintf(w, "}\n")
+}