Skip to content

Commit

Permalink
Add HealthCheck's healthy map to the VTGate UI (#14521)
Browse files Browse the repository at this point in the history
  • Loading branch information
frouioui authored Nov 16, 2023
1 parent a40a89b commit f8066f6
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 18 deletions.
5 changes: 4 additions & 1 deletion go/cmd/vtcombo/cli/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ func addStatusParts(vtg *vtgate.VTGate) {
servenv.AddStatusPart("Gateway Status", vtgate.StatusTemplate, func() any {
return vtg.GetGatewayCacheStatus()
})
servenv.AddStatusPart("Health Check Cache", discovery.HealthCheckTemplate, func() any {
servenv.AddStatusPart("Health Check - Cache", discovery.HealthCheckCacheTemplate, func() any {
return vtg.Gateway().TabletsCacheStatus()
})
servenv.AddStatusPart("Health Check - Healthy Tablets", discovery.HealthCheckHealthyTemplate, func() any {
return vtg.Gateway().TabletsHealthyStatus()
})
}
5 changes: 4 additions & 1 deletion go/cmd/vtgate/cli/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ func addStatusParts(vtg *vtgate.VTGate) {
servenv.AddStatusPart("Gateway Status", vtgate.StatusTemplate, func() any {
return vtg.GetGatewayCacheStatus()
})
servenv.AddStatusPart("Health Check Cache", discovery.HealthCheckTemplate, func() any {
servenv.AddStatusPart("Health Check - Cache", discovery.HealthCheckCacheTemplate, func() any {
return vtg.Gateway().TabletsCacheStatus()
})
servenv.AddStatusPart("Health Check - Healthy Tablets", discovery.HealthCheckHealthyTemplate, func() any {
return vtg.Gateway().TabletsHealthyStatus()
})
}
11 changes: 11 additions & 0 deletions go/vt/discovery/fake_healthcheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,17 @@ func (fhc *FakeHealthCheck) CacheStatus() TabletsCacheStatusList {
return tcsl
}

// HealthyStatus returns the status for each healthy tablet
func (fhc *FakeHealthCheck) HealthyStatus() TabletsCacheStatusList {
tcsMap := fhc.CacheStatusMap()
tcsl := make(TabletsCacheStatusList, 0, len(tcsMap))
for _, tcs := range tcsMap {
tcsl = append(tcsl, tcs)
}
sort.Sort(tcsl)
return tcsl
}

// CacheStatusMap returns a map of the health check cache.
func (fhc *FakeHealthCheck) CacheStatusMap() map[string]*TabletsCacheStatus {
tcsMap := make(map[string]*TabletsCacheStatus)
Expand Down
67 changes: 53 additions & 14 deletions go/vt/discovery/healthcheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ var (

// How much to sleep between each check.
waitAvailableTabletInterval = 100 * time.Millisecond

// HealthCheckCacheTemplate uses healthCheckTemplate with the `HealthCheck Tablet - Cache` title to create the
// HTML code required to render the cache of the HealthCheck.
HealthCheckCacheTemplate = fmt.Sprintf(healthCheckTemplate, "HealthCheck - Cache")

// HealthCheckHealthyTemplate uses healthCheckTemplate with the `HealthCheck Tablet - Healthy Tablets` title to
// create the HTML code required to render the list of healthy tablets from the HealthCheck.
HealthCheckHealthyTemplate = fmt.Sprintf(healthCheckTemplate, "HealthCheck - Healthy Tablets")
)

// See the documentation for NewHealthCheck below for an explanation of these parameters.
Expand All @@ -104,8 +112,9 @@ const (
// DefaultTopologyWatcherRefreshInterval is used as the default value for
// the refresh interval of a topology watcher.
DefaultTopologyWatcherRefreshInterval = 1 * time.Minute
// HealthCheckTemplate is the HTML code to display a TabletsCacheStatusList
HealthCheckTemplate = `
// healthCheckTemplate is the HTML code to display a TabletsCacheStatusList, it takes a parameter for the title
// as the template can be used for both HealthCheck's cache and healthy tablets list.
healthCheckTemplate = `
<style>
table {
border-collapse: collapse;
Expand All @@ -117,7 +126,7 @@ const (
</style>
<table class="refreshRequired">
<tr>
<th colspan="5">HealthCheck Tablet Cache</th>
<th colspan="5">%s</th>
</tr>
<tr>
<th>Cell</th>
Expand Down Expand Up @@ -193,6 +202,9 @@ type HealthCheck interface {
// CacheStatus returns a displayable version of the health check cache.
CacheStatus() TabletsCacheStatusList

// HealthyStatus returns a displayable version of the health check healthy list.
HealthyStatus() TabletsCacheStatusList

// CacheStatusMap returns a map of the health check cache.
CacheStatusMap() map[string]*TabletsCacheStatus

Expand Down Expand Up @@ -622,28 +634,55 @@ func (hc *HealthCheckImpl) CacheStatus() TabletsCacheStatusList {
return tcsl
}

// HealthyStatus returns a displayable version of the cache.
func (hc *HealthCheckImpl) HealthyStatus() TabletsCacheStatusList {
tcsMap := hc.HealthyStatusMap()
tcsl := make(TabletsCacheStatusList, 0, len(tcsMap))
for _, tcs := range tcsMap {
tcsl = append(tcsl, tcs)
}
sort.Sort(tcsl)
return tcsl
}

func (hc *HealthCheckImpl) CacheStatusMap() map[string]*TabletsCacheStatus {
tcsMap := make(map[string]*TabletsCacheStatus)
hc.mu.Lock()
defer hc.mu.Unlock()
for _, ths := range hc.healthData {
for _, th := range ths {
key := fmt.Sprintf("%v.%v.%v.%v", th.Tablet.Alias.Cell, th.Target.Keyspace, th.Target.Shard, th.Target.TabletType.String())
var tcs *TabletsCacheStatus
var ok bool
if tcs, ok = tcsMap[key]; !ok {
tcs = &TabletsCacheStatus{
Cell: th.Tablet.Alias.Cell,
Target: th.Target,
}
tcsMap[key] = tcs
}
tcs.TabletsStats = append(tcs.TabletsStats, th)
tabletHealthToTabletCacheStatus(th, tcsMap)
}
}
return tcsMap
}

func (hc *HealthCheckImpl) HealthyStatusMap() map[string]*TabletsCacheStatus {
tcsMap := make(map[string]*TabletsCacheStatus)
hc.mu.Lock()
defer hc.mu.Unlock()
for _, ths := range hc.healthy {
for _, th := range ths {
tabletHealthToTabletCacheStatus(th, tcsMap)
}
}
return tcsMap
}

func tabletHealthToTabletCacheStatus(th *TabletHealth, tcsMap map[string]*TabletsCacheStatus) {
key := fmt.Sprintf("%v.%v.%v.%v", th.Tablet.Alias.Cell, th.Target.Keyspace, th.Target.Shard, th.Target.TabletType.String())
var tcs *TabletsCacheStatus
var ok bool
if tcs, ok = tcsMap[key]; !ok {
tcs = &TabletsCacheStatus{
Cell: th.Tablet.Alias.Cell,
Target: th.Target,
}
tcsMap[key] = tcs
}
tcs.TabletsStats = append(tcs.TabletsStats, th)
}

// Close stops the healthcheck.
func (hc *HealthCheckImpl) Close() error {
hc.mu.Lock()
Expand Down
4 changes: 2 additions & 2 deletions go/vt/discovery/healthcheck_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1267,7 +1267,7 @@ func TestTemplate(t *testing.T) {
TabletsStats: ts,
}
templ := template.New("")
templ, err := templ.Parse(HealthCheckTemplate)
templ, err := templ.Parse(healthCheckTemplate)
require.Nil(t, err, "error parsing template: %v", err)
wr := &bytes.Buffer{}
err = templ.Execute(wr, []*TabletsCacheStatus{tcs})
Expand Down Expand Up @@ -1295,7 +1295,7 @@ func TestDebugURLFormatting(t *testing.T) {
TabletsStats: ts,
}
templ := template.New("")
templ, err := templ.Parse(HealthCheckTemplate)
templ, err := templ.Parse(healthCheckTemplate)
require.Nil(t, err, "error parsing template")
wr := &bytes.Buffer{}
err = templ.Execute(wr, []*TabletsCacheStatus{tcs})
Expand Down
5 changes: 5 additions & 0 deletions go/vt/vtgate/tabletgateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,11 @@ func (gw *TabletGateway) TabletsCacheStatus() discovery.TabletsCacheStatusList {
return gw.hc.CacheStatus()
}

// TabletsHealthyStatus returns a displayable version of the health check healthy list.
func (gw *TabletGateway) TabletsHealthyStatus() discovery.TabletsCacheStatusList {
return gw.hc.HealthyStatus()
}

func (gw *TabletGateway) updateDefaultConnCollation(tablet *topodatapb.Tablet) {
if atomic.CompareAndSwapUint32(&gw.defaultConnCollation, 0, tablet.DefaultConnCollation) {
return
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f8066f6

Please sign in to comment.