Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/extra summary #666

Merged
merged 9 commits into from
Mar 17, 2021
94 changes: 94 additions & 0 deletions pkg/visor/hypervisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ func (hv *Hypervisor) makeMux() chi.Router {
r.Get("/dmsg", hv.getDmsg())

r.Get("/visors", hv.getVisors())
r.Get("/visors-summary", hv.getVisorsExtraSummary())
r.Get("/visors/{pk}", hv.getVisor())
r.Get("/visors/{pk}/summary", hv.getVisorSummary())
r.Get("/visors/{pk}/health", hv.getHealth())
Expand Down Expand Up @@ -489,6 +490,99 @@ func (hv *Hypervisor) getVisorSummary() http.HandlerFunc {
})
}

type extraSummaryWithDmsgResp struct {
extraSummaryResp
IsHypervisor bool `json:"is_hypervisor"`
DmsgStats *dmsgtracker.DmsgClientSummary `json:"dmsg_stats"`
}

func (hv *Hypervisor) getVisorsExtraSummary() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
hv.mu.RLock()
wg := new(sync.WaitGroup)
wg.Add(len(hv.visors))

i := 0
if hv.visor != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there currently any possiblity of this code executing when hv.Visor would be nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed there isn't. I took the code for getting visors and modified it to have additional info in response. However, we never start hypervisor without visor, except in tests. However, some tests rely on nil response on an "empty" hypervisor. Not sure if it's worth the trouble to change the tests and remove nil-checks everywhere.

i++
}

dmsgStats := make(map[string]dmsgtracker.DmsgClientSummary)
wg.Add(1)
go func() {
summary := hv.getDmsgSummary()
for _, stat := range summary {
dmsgStats[stat.PK.String()] = stat
}
wg.Done()
}()

summaries := make([]extraSummaryWithDmsgResp, len(hv.visors)+i)

if hv.visor != nil {
summary, err := hv.visor.ExtraSummary()
if err != nil {
log.WithError(err).Warn("Failed to obtain summary of this visor.")
summary = &ExtraSummary{}
summary.Summary.PubKey = hv.visor.conf.PK
}

addr := dmsg.Addr{PK: hv.c.PK, Port: hv.c.DmsgPort}
summaries[0] = extraSummaryWithDmsgResp{
extraSummaryResp: extraSummaryResp{
TCPAddr: addr.String(),
Online: err == nil,
ExtraSummary: summary,
},
IsHypervisor: true,
}
}

for pk, c := range hv.visors {
go func(pk cipher.PubKey, c Conn, i int) {
log := hv.log(r).
WithField("visor_addr", c.Addr).
WithField("func", "getVisors")

log.Debug("Requesting summary via RPC.")

summary, err := c.API.ExtraSummary()
if err != nil {
log.WithError(err).
Warn("Failed to obtain summary via RPC.")
summary = &ExtraSummary{}
summary.Summary.PubKey = pk
} else {
log.Debug("Obtained summary via RPC.")
}
resp := extraSummaryWithDmsgResp{
extraSummaryResp: extraSummaryResp{
TCPAddr: c.Addr.String(),
Online: err == nil,
ExtraSummary: summary,
},
IsHypervisor: false,
}
resp.ExtraSummary = summary
summaries[i] = resp
wg.Done()
}(pk, c, i)
i++
}

wg.Wait()
for i := 0; i < len(summaries); i++ {
if stat, ok := dmsgStats[summaries[i].Summary.PubKey.String()]; ok {
summaries[i].DmsgStats = &stat
}
}

hv.mu.RUnlock()

httputil.WriteJSON(w, r, http.StatusOK, summaries)
}
}

// returns app summaries of a given node of pk
func (hv *Hypervisor) getApps() http.HandlerFunc {
return hv.withCtx(hv.visorCtx, func(w http.ResponseWriter, r *http.Request, ctx *httpCtx) {
Expand Down