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

Add api end point to print the current database state in VTOrc #15485

Merged
merged 3 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions go/test/endtoend/vtorc/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,24 @@ func TestAPIEndpoints(t *testing.T) {
return response != "null"
})

t.Run("Database State", func(t *testing.T) {
// Get database state
status, resp, err := utils.MakeAPICall(t, vtorc, "/api/database-state")
require.NoError(t, err)
assert.Equal(t, 200, status)
assert.Contains(t, resp, `"alias": "zone1-0000000101"`)
assert.Contains(t, resp, `{
"TableName": "vitess_keyspace",
"Rows": [
{
"durability_policy": "none",
"keyspace": "ks",
"keyspace_type": "0"
}
]
},`)
})

t.Run("Disable Recoveries API", func(t *testing.T) {
// Disable recoveries of VTOrc
status, resp, err := utils.MakeAPICall(t, vtorc, "/api/disable-global-recoveries")
Expand Down
2 changes: 1 addition & 1 deletion go/vt/external/golib/sqlutils/sqlutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type RowMap map[string]CellData
// CellData is the result of a single (atomic) column in a single row
type CellData sql.NullString

func (this *CellData) MarshalJSON() ([]byte, error) {
func (this CellData) MarshalJSON() ([]byte, error) {
if this.Valid {
return json.Marshal(this.String)
} else {
Expand Down
22 changes: 22 additions & 0 deletions go/vt/vtorc/db/generate_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,28 @@

package db

var TableNames = []string{
"database_instance",
"audit",
"active_node",
"node_health",
"topology_recovery",
"database_instance_topology_history",
"candidate_database_instance",
"topology_failure_detection",
"blocked_topology_recovery",
"database_instance_last_analysis",
"database_instance_analysis_changelog",
"node_health_history",
"vtorc_db_deployments",
"global_recovery_disable",
"topology_recovery_steps",
"database_instance_stale_binlog_coordinates",
GuptaManan100 marked this conversation as resolved.
Show resolved Hide resolved
"vitess_tablet",
"vitess_keyspace",
"vitess_shard",
}

// vtorcBackend is a list of SQL statements required to build the vtorc backend
var vtorcBackend = []string{
`
Expand Down
30 changes: 30 additions & 0 deletions go/vt/vtorc/inst/instance_dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package inst

import (
"encoding/json"
"errors"
"fmt"
"regexp"
Expand Down Expand Up @@ -1210,3 +1211,32 @@ func ExpireStaleInstanceBinlogCoordinates() error {
}
return ExecDBWriteFunc(writeFunc)
}

// GetDatabaseState takes the snapshot of the database and returns it.
func GetDatabaseState() (string, error) {
type tableState struct {
TableName string
Rows []sqlutils.RowMap
}

var dbState []tableState
for _, tableName := range db.TableNames {
ts := tableState{
TableName: tableName,
}
err := db.QueryVTOrc("select * from "+tableName, nil, func(rowMap sqlutils.RowMap) error {
ts.Rows = append(ts.Rows, rowMap)
return nil
})
if err != nil {
return "", err
}
dbState = append(dbState, ts)
}
jsonData, err := json.MarshalIndent(dbState, "", "\t")
if err != nil {
return "", err
}

return string(jsonData), nil
}
16 changes: 16 additions & 0 deletions go/vt/vtorc/inst/instance_dao_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -746,3 +746,19 @@ func waitForCacheInitialization() {
time.Sleep(100 * time.Millisecond)
}
}

func TestGetDatabaseState(t *testing.T) {
// Clear the database after the test. The easiest way to do that is to run all the initialization commands again.
defer func() {
db.ClearVTOrcDatabase()
}()

for _, query := range initialSQL {
_, err := db.ExecVTOrc(query)
require.NoError(t, err)
}

ds, err := GetDatabaseState()
require.NoError(t, err)
require.Contains(t, ds, `"alias": "zone1-0000000112"`)
}
16 changes: 15 additions & 1 deletion go/vt/vtorc/server/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const (
disableGlobalRecoveriesAPI = "/api/disable-global-recoveries"
enableGlobalRecoveriesAPI = "/api/enable-global-recoveries"
replicationAnalysisAPI = "/api/replication-analysis"
databaseStateAPI = "/api/database-state"
healthAPI = "/debug/health"
AggregatedDiscoveryMetricsAPI = "/api/aggregated-discovery-metrics"

Expand All @@ -60,6 +61,7 @@ var (
disableGlobalRecoveriesAPI,
enableGlobalRecoveriesAPI,
replicationAnalysisAPI,
databaseStateAPI,
healthAPI,
AggregatedDiscoveryMetricsAPI,
}
Expand All @@ -86,6 +88,8 @@ func (v *vtorcAPI) ServeHTTP(response http.ResponseWriter, request *http.Request
errantGTIDsAPIHandler(response, request)
case replicationAnalysisAPI:
replicationAnalysisAPIHandler(response, request)
case databaseStateAPI:
databaseStateAPIHandler(response)
case AggregatedDiscoveryMetricsAPI:
AggregatedDiscoveryMetricsAPIHandler(response, request)
default:
Expand All @@ -104,7 +108,7 @@ func getACLPermissionLevelForAPI(apiEndpoint string) string {
return acl.ADMIN
case replicationAnalysisAPI:
return acl.MONITORING
case healthAPI:
case healthAPI, databaseStateAPI:
return acl.MONITORING
}
return acl.ADMIN
Expand Down Expand Up @@ -166,6 +170,16 @@ func errantGTIDsAPIHandler(response http.ResponseWriter, request *http.Request)
returnAsJSON(response, http.StatusOK, instances)
}

// databaseStateAPIHandler is the handler for the databaseStateAPI endpoint
func databaseStateAPIHandler(response http.ResponseWriter) {
ds, err := inst.GetDatabaseState()
if err != nil {
http.Error(response, err.Error(), http.StatusInternalServerError)
return
}
writePlainTextResponse(response, ds, http.StatusOK)
}

// AggregatedDiscoveryMetricsAPIHandler is the handler for the discovery metrics endpoint
func AggregatedDiscoveryMetricsAPIHandler(response http.ResponseWriter, request *http.Request) {
// return metrics for last x seconds
Expand Down
Loading