Skip to content

Commit 2078d62

Browse files
Add api end point to print the current database state in VTOrc (#15485)
Signed-off-by: Manan Gupta <manan@planetscale.com>
1 parent 8850e8e commit 2078d62

6 files changed

Lines changed: 102 additions & 2 deletions

File tree

go/test/endtoend/vtorc/api/api_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,24 @@ func TestAPIEndpoints(t *testing.T) {
9393
return response != "null"
9494
})
9595

96+
t.Run("Database State", func(t *testing.T) {
97+
// Get database state
98+
status, resp, err := utils.MakeAPICall(t, vtorc, "/api/database-state")
99+
require.NoError(t, err)
100+
assert.Equal(t, 200, status)
101+
assert.Contains(t, resp, `"alias": "zone1-0000000101"`)
102+
assert.Contains(t, resp, `{
103+
"TableName": "vitess_keyspace",
104+
"Rows": [
105+
{
106+
"durability_policy": "none",
107+
"keyspace": "ks",
108+
"keyspace_type": "0"
109+
}
110+
]
111+
},`)
112+
})
113+
96114
t.Run("Disable Recoveries API", func(t *testing.T) {
97115
// Disable recoveries of VTOrc
98116
status, resp, err := utils.MakeAPICall(t, vtorc, "/api/disable-global-recoveries")

go/vt/external/golib/sqlutils/sqlutils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type RowMap map[string]CellData
4242
// CellData is the result of a single (atomic) column in a single row
4343
type CellData sql.NullString
4444

45-
func (this *CellData) MarshalJSON() ([]byte, error) {
45+
func (this CellData) MarshalJSON() ([]byte, error) {
4646
if this.Valid {
4747
return json.Marshal(this.String)
4848
} else {

go/vt/vtorc/db/generate_base.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,28 @@
1616

1717
package db
1818

19+
var TableNames = []string{
20+
"database_instance",
21+
"audit",
22+
"active_node",
23+
"node_health",
24+
"topology_recovery",
25+
"database_instance_topology_history",
26+
"candidate_database_instance",
27+
"topology_failure_detection",
28+
"blocked_topology_recovery",
29+
"database_instance_last_analysis",
30+
"database_instance_analysis_changelog",
31+
"node_health_history",
32+
"vtorc_db_deployments",
33+
"global_recovery_disable",
34+
"topology_recovery_steps",
35+
"database_instance_stale_binlog_coordinates",
36+
"vitess_tablet",
37+
"vitess_keyspace",
38+
"vitess_shard",
39+
}
40+
1941
// vtorcBackend is a list of SQL statements required to build the vtorc backend
2042
var vtorcBackend = []string{
2143
`

go/vt/vtorc/inst/instance_dao.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package inst
1818

1919
import (
20+
"encoding/json"
2021
"errors"
2122
"fmt"
2223
"regexp"
@@ -1210,3 +1211,32 @@ func ExpireStaleInstanceBinlogCoordinates() error {
12101211
}
12111212
return ExecDBWriteFunc(writeFunc)
12121213
}
1214+
1215+
// GetDatabaseState takes the snapshot of the database and returns it.
1216+
func GetDatabaseState() (string, error) {
1217+
type tableState struct {
1218+
TableName string
1219+
Rows []sqlutils.RowMap
1220+
}
1221+
1222+
var dbState []tableState
1223+
for _, tableName := range db.TableNames {
1224+
ts := tableState{
1225+
TableName: tableName,
1226+
}
1227+
err := db.QueryVTOrc("select * from "+tableName, nil, func(rowMap sqlutils.RowMap) error {
1228+
ts.Rows = append(ts.Rows, rowMap)
1229+
return nil
1230+
})
1231+
if err != nil {
1232+
return "", err
1233+
}
1234+
dbState = append(dbState, ts)
1235+
}
1236+
jsonData, err := json.MarshalIndent(dbState, "", "\t")
1237+
if err != nil {
1238+
return "", err
1239+
}
1240+
1241+
return string(jsonData), nil
1242+
}

go/vt/vtorc/inst/instance_dao_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,3 +746,19 @@ func waitForCacheInitialization() {
746746
time.Sleep(100 * time.Millisecond)
747747
}
748748
}
749+
750+
func TestGetDatabaseState(t *testing.T) {
751+
// Clear the database after the test. The easiest way to do that is to run all the initialization commands again.
752+
defer func() {
753+
db.ClearVTOrcDatabase()
754+
}()
755+
756+
for _, query := range initialSQL {
757+
_, err := db.ExecVTOrc(query)
758+
require.NoError(t, err)
759+
}
760+
761+
ds, err := GetDatabaseState()
762+
require.NoError(t, err)
763+
require.Contains(t, ds, `"alias": "zone1-0000000112"`)
764+
}

go/vt/vtorc/server/api.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const (
4545
disableGlobalRecoveriesAPI = "/api/disable-global-recoveries"
4646
enableGlobalRecoveriesAPI = "/api/enable-global-recoveries"
4747
replicationAnalysisAPI = "/api/replication-analysis"
48+
databaseStateAPI = "/api/database-state"
4849
healthAPI = "/debug/health"
4950
AggregatedDiscoveryMetricsAPI = "/api/aggregated-discovery-metrics"
5051

@@ -60,6 +61,7 @@ var (
6061
disableGlobalRecoveriesAPI,
6162
enableGlobalRecoveriesAPI,
6263
replicationAnalysisAPI,
64+
databaseStateAPI,
6365
healthAPI,
6466
AggregatedDiscoveryMetricsAPI,
6567
}
@@ -86,6 +88,8 @@ func (v *vtorcAPI) ServeHTTP(response http.ResponseWriter, request *http.Request
8688
errantGTIDsAPIHandler(response, request)
8789
case replicationAnalysisAPI:
8890
replicationAnalysisAPIHandler(response, request)
91+
case databaseStateAPI:
92+
databaseStateAPIHandler(response)
8993
case AggregatedDiscoveryMetricsAPI:
9094
AggregatedDiscoveryMetricsAPIHandler(response, request)
9195
default:
@@ -104,7 +108,7 @@ func getACLPermissionLevelForAPI(apiEndpoint string) string {
104108
return acl.ADMIN
105109
case replicationAnalysisAPI:
106110
return acl.MONITORING
107-
case healthAPI:
111+
case healthAPI, databaseStateAPI:
108112
return acl.MONITORING
109113
}
110114
return acl.ADMIN
@@ -166,6 +170,16 @@ func errantGTIDsAPIHandler(response http.ResponseWriter, request *http.Request)
166170
returnAsJSON(response, http.StatusOK, instances)
167171
}
168172

173+
// databaseStateAPIHandler is the handler for the databaseStateAPI endpoint
174+
func databaseStateAPIHandler(response http.ResponseWriter) {
175+
ds, err := inst.GetDatabaseState()
176+
if err != nil {
177+
http.Error(response, err.Error(), http.StatusInternalServerError)
178+
return
179+
}
180+
writePlainTextResponse(response, ds, http.StatusOK)
181+
}
182+
169183
// AggregatedDiscoveryMetricsAPIHandler is the handler for the discovery metrics endpoint
170184
func AggregatedDiscoveryMetricsAPIHandler(response http.ResponseWriter, request *http.Request) {
171185
// return metrics for last x seconds

0 commit comments

Comments
 (0)