mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 17:51:21 +00:00
Merge pull request #121 from tomwilkie/refactor
Refactor topology 'views' and their http handlers
This commit is contained in:
@@ -34,15 +34,15 @@ func makeTopologyList(rep Reporter) func(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
url := "/api/topology/" + name
|
||||
var groupedURL string
|
||||
if def.hasGrouped {
|
||||
groupedURL = url + "grouped"
|
||||
if def.groupedTopology != "" {
|
||||
groupedURL = "/api/topology/" + def.groupedTopology
|
||||
}
|
||||
|
||||
a = append(a, APITopologyDesc{
|
||||
Name: def.human,
|
||||
URL: url,
|
||||
GroupedURL: groupedURL,
|
||||
Stats: stats(def.topologySelecter(rpt).RenderBy(def.MapFunc, def.PseudoFunc, false)),
|
||||
Stats: stats(def.selector(rpt).RenderBy(def.mapper, def.pseudo)),
|
||||
})
|
||||
}
|
||||
respondWith(w, http.StatusOK, a)
|
||||
|
||||
@@ -41,68 +41,57 @@ func selectNetwork(r report.Report) report.Topology {
|
||||
return r.Network
|
||||
}
|
||||
|
||||
// makeTopologyHandlers make /api/topology/* handlers.
|
||||
func makeTopologyHandlers(
|
||||
rep Reporter,
|
||||
topo topologySelecter,
|
||||
mapping report.MapFunc,
|
||||
pseudo report.PseudoFunc,
|
||||
grouped bool,
|
||||
get *mux.Router,
|
||||
base string,
|
||||
) {
|
||||
// Full topology.
|
||||
get.HandleFunc(base, func(w http.ResponseWriter, r *http.Request) {
|
||||
respondWith(w, http.StatusOK, APITopology{
|
||||
Nodes: topo(rep.Report()).RenderBy(mapping, pseudo, grouped),
|
||||
})
|
||||
// Full topology.
|
||||
func handleTopology(rep Reporter, t topologyView, w http.ResponseWriter, r *http.Request) {
|
||||
respondWith(w, http.StatusOK, APITopology{
|
||||
Nodes: t.selector(rep.Report()).RenderBy(t.mapper, t.pseudo),
|
||||
})
|
||||
}
|
||||
|
||||
// Websocket for the full topology. This route overlaps with the next.
|
||||
get.HandleFunc(base+"/ws", func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
respondWith(w, http.StatusInternalServerError, err.Error())
|
||||
// Websocket for the full topology. This route overlaps with the next.
|
||||
func handleWs(rep Reporter, t topologyView, w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
respondWith(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
loop := websocketLoop
|
||||
if t := r.Form.Get("t"); t != "" {
|
||||
var err error
|
||||
if loop, err = time.ParseDuration(t); err != nil {
|
||||
respondWith(w, http.StatusBadRequest, t)
|
||||
return
|
||||
}
|
||||
loop := websocketLoop
|
||||
if t := r.Form.Get("t"); t != "" {
|
||||
var err error
|
||||
if loop, err = time.ParseDuration(t); err != nil {
|
||||
respondWith(w, http.StatusBadRequest, t)
|
||||
return
|
||||
}
|
||||
}
|
||||
handleWebsocket(w, r, rep, topo, mapping, pseudo, grouped, loop)
|
||||
})
|
||||
}
|
||||
handleWebsocket(w, r, rep, t, loop)
|
||||
}
|
||||
|
||||
// Individual nodes.
|
||||
get.HandleFunc(base+"/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
vars = mux.Vars(r)
|
||||
nodeID = vars["id"]
|
||||
rpt = rep.Report()
|
||||
node, ok = topo(rpt).RenderBy(mapping, pseudo, grouped)[nodeID]
|
||||
)
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
originHostFunc := func(id string) (OriginHost, bool) { return getOriginHost(rpt.HostMetadatas, id) }
|
||||
originNodeFunc := func(id string) (OriginNode, bool) { return getOriginNode(topo(rpt), id) }
|
||||
respondWith(w, http.StatusOK, APINode{Node: makeDetailed(node, originHostFunc, originNodeFunc)})
|
||||
})
|
||||
// Individual nodes.
|
||||
func handleNode(rep Reporter, t topologyView, w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
vars = mux.Vars(r)
|
||||
nodeID = vars["id"]
|
||||
rpt = rep.Report()
|
||||
node, ok = t.selector(rpt).RenderBy(t.mapper, t.pseudo)[nodeID]
|
||||
)
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
originHostFunc := func(id string) (OriginHost, bool) { return getOriginHost(rpt.HostMetadatas, id) }
|
||||
originNodeFunc := func(id string) (OriginNode, bool) { return getOriginNode(t.selector(rpt), id) }
|
||||
respondWith(w, http.StatusOK, APINode{Node: makeDetailed(node, originHostFunc, originNodeFunc)})
|
||||
}
|
||||
|
||||
// Individual edges.
|
||||
get.HandleFunc(base+"/{local}/{remote}", func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
vars = mux.Vars(r)
|
||||
localID = vars["local"]
|
||||
remoteID = vars["remote"]
|
||||
rpt = rep.Report()
|
||||
metadata = topo(rpt).EdgeMetadata(mapping, grouped, localID, remoteID).Transform()
|
||||
)
|
||||
respondWith(w, http.StatusOK, APIEdge{Metadata: metadata})
|
||||
})
|
||||
// Individual edges.
|
||||
func handleEdge(rep Reporter, t topologyView, w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
vars = mux.Vars(r)
|
||||
localID = vars["local"]
|
||||
remoteID = vars["remote"]
|
||||
rpt = rep.Report()
|
||||
metadata = t.selector(rpt).EdgeMetadata(t.mapper, localID, remoteID).Transform()
|
||||
)
|
||||
respondWith(w, http.StatusOK, APIEdge{Metadata: metadata})
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
@@ -113,10 +102,7 @@ func handleWebsocket(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
rep Reporter,
|
||||
topo topologySelecter,
|
||||
mapping report.MapFunc,
|
||||
psuedo report.PseudoFunc,
|
||||
grouped bool,
|
||||
t topologyView,
|
||||
loop time.Duration,
|
||||
) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
@@ -141,7 +127,7 @@ func handleWebsocket(
|
||||
tick = time.Tick(loop)
|
||||
)
|
||||
for {
|
||||
newTopo := topo(rep.Report()).RenderBy(mapping, psuedo, grouped)
|
||||
newTopo := t.selector(rep.Report()).RenderBy(t.mapper, t.pseudo)
|
||||
diff := report.TopoDiff(previousTopo, newTopo)
|
||||
previousTopo = newTopo
|
||||
|
||||
|
||||
@@ -14,42 +14,39 @@ func Router(c Reporter) *mux.Router {
|
||||
router := mux.NewRouter()
|
||||
get := router.Methods("GET").Subrouter()
|
||||
get.HandleFunc("/api/topology", makeTopologyList(c))
|
||||
for name, def := range topologyRegistry {
|
||||
makeTopologyHandlers(
|
||||
c,
|
||||
def.topologySelecter,
|
||||
def.MapFunc,
|
||||
def.PseudoFunc,
|
||||
false, // not grouped
|
||||
get,
|
||||
"/api/topology/"+name,
|
||||
)
|
||||
if def.hasGrouped {
|
||||
makeTopologyHandlers(
|
||||
c,
|
||||
def.topologySelecter,
|
||||
def.MapFunc,
|
||||
def.PseudoFunc,
|
||||
true, // grouped
|
||||
get,
|
||||
"/api/topology/"+name+"grouped",
|
||||
)
|
||||
}
|
||||
}
|
||||
get.HandleFunc("/api/topology/{topology}", captureTopology(c, handleTopology))
|
||||
get.HandleFunc("/api/topology/{topology}/ws", captureTopology(c, handleWs))
|
||||
get.HandleFunc("/api/topology/{topology}/{id}", captureTopology(c, handleNode))
|
||||
get.HandleFunc("/api/topology/{topology}/{local}/{remote}", captureTopology(c, handleEdge))
|
||||
get.HandleFunc("/api/origin/host/{id}", makeOriginHostHandler(c))
|
||||
get.HandleFunc("/api/report", makeRawReportHandler(c))
|
||||
get.PathPrefix("/").Handler(http.FileServer(FS(false))) // everything else is static
|
||||
return router
|
||||
}
|
||||
|
||||
var topologyRegistry = map[string]struct {
|
||||
human string
|
||||
topologySelecter
|
||||
report.MapFunc
|
||||
report.PseudoFunc
|
||||
hasGrouped bool
|
||||
}{
|
||||
"applications": {"Applications", selectProcess, report.ProcessPID, report.GenericPseudoNode, true},
|
||||
"containers": {"Containers", selectProcess, report.ProcessContainer, report.NoPseudoNode, true},
|
||||
"hosts": {"Hosts", selectNetwork, report.NetworkHostname, report.GenericPseudoNode, false},
|
||||
func captureTopology(rep Reporter, f func(Reporter, topologyView, http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
topology, ok := topologyRegistry[mux.Vars(r)["topology"]]
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
f(rep, topology, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
type topologyView struct {
|
||||
human string
|
||||
selector topologySelecter
|
||||
mapper report.MapFunc
|
||||
pseudo report.PseudoFunc
|
||||
groupedTopology string
|
||||
}
|
||||
|
||||
var topologyRegistry = map[string]topologyView{
|
||||
"applications": {"Applications", selectProcess, report.ProcessPID, report.GenericPseudoNode, "applications-grouped"},
|
||||
"applications-grouped": {"Applications", selectProcess, report.ProcessName, report.GenericGroupedPseudoNode, ""},
|
||||
"containers": {"Containers", selectProcess, report.ProcessContainer, report.NoPseudoNode, "containers-grouped"},
|
||||
"containers-grouped": {"Containers", selectProcess, report.ProcessContainerImage, report.NoPseudoNode, ""},
|
||||
"hosts": {"Hosts", selectNetwork, report.NetworkHostname, report.GenericPseudoNode, ""},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user