forked from dolthub/vitess
-
Notifications
You must be signed in to change notification settings - Fork 0
/
explorer.go
124 lines (111 loc) · 3.96 KB
/
explorer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package vtctld
import (
"errors"
"fmt"
"net/http"
"path"
"sync"
"golang.org/x/net/context"
"github.com/youtube/vitess/go/vt/topo"
"github.com/youtube/vitess/go/vt/topo/topoproto"
"github.com/youtube/vitess/go/vt/vtctld/explorer"
)
var (
// explorerMutex protects against concurrent registration attempts (e.g. OnRun).
// Other than registration, the explorer should never change.
explorerMutex sync.Mutex
explorerName string
explorerInstance explorer.Explorer
)
// HandleExplorer registers the Explorer under url, using the given template.
// It should be called by a plugin either from init() or from servenv.OnRun().
// Only one Explorer can be registered in a given instance of vtctld.
func HandleExplorer(name string, exp explorer.Explorer) {
explorerMutex.Lock()
defer explorerMutex.Unlock()
if explorerInstance != nil {
panic(fmt.Sprintf("Only one Explorer can be registered in vtctld. Trying to register %q, but %q was already registered.", name, explorerName))
}
// Topo explorer API for client-side vtctld app.
handleCollection("topodata", func(r *http.Request) (interface{}, error) {
return exp.HandlePath(path.Clean("/"+getItemPath(r.URL.Path)), r), nil
})
// save our instance
explorerInstance = exp
explorerName = name
}
// handleExplorerRedirect returns the redirect target URL.
func handleExplorerRedirect(ctx context.Context, ts topo.Server, r *http.Request) (string, error) {
keyspace := r.FormValue("keyspace")
shard := r.FormValue("shard")
cell := r.FormValue("cell")
switch r.FormValue("type") {
case "keyspace":
if keyspace == "" {
return "", errors.New("keyspace is required for this redirect")
}
return appPrefix + "#/keyspaces/", nil
case "shard":
if keyspace == "" || shard == "" {
return "", errors.New("keyspace and shard are required for this redirect")
}
return appPrefix + fmt.Sprintf("#/shard/%s/%s", keyspace, shard), nil
case "srv_keyspace":
if keyspace == "" || cell == "" {
return "", errors.New("keyspace and cell are required for this redirect")
}
return appPrefix + "#/keyspaces/", nil
case "srv_shard":
if keyspace == "" || shard == "" || cell == "" {
return "", errors.New("keyspace, shard, and cell are required for this redirect")
}
return appPrefix + fmt.Sprintf("#/shard/%s/%s", keyspace, shard), nil
case "srv_type":
tabletType := r.FormValue("tablet_type")
if keyspace == "" || shard == "" || cell == "" || tabletType == "" {
return "", errors.New("keyspace, shard, cell, and tablet_type are required for this redirect")
}
return appPrefix + fmt.Sprintf("#/shard/%s/%s", keyspace, shard), nil
case "tablet":
alias := r.FormValue("alias")
if alias == "" {
return "", errors.New("alias is required for this redirect")
}
tabletAlias, err := topoproto.ParseTabletAlias(alias)
if err != nil {
return "", fmt.Errorf("bad tablet alias %q: %v", alias, err)
}
ti, err := ts.GetTablet(ctx, tabletAlias)
if err != nil {
return "", fmt.Errorf("can't get tablet %q: %v", alias, err)
}
return appPrefix + fmt.Sprintf("#/shard/%s/%s", ti.Keyspace, ti.Shard), nil
case "replication":
if keyspace == "" || shard == "" || cell == "" {
return "", errors.New("keyspace, shard, and cell are required for this redirect")
}
return appPrefix + fmt.Sprintf("#/shard/%s/%s", keyspace, shard), nil
default:
return "", errors.New("bad redirect type")
}
}
// initExplorer initializes the redirects for explorer
func initExplorer(ts topo.Server) {
// redirects for explorers
http.HandleFunc("/explorers/redirect", func(w http.ResponseWriter, r *http.Request) {
if explorerInstance == nil {
http.Error(w, "no explorer configured", http.StatusInternalServerError)
return
}
if err := r.ParseForm(); err != nil {
httpErrorf(w, r, "cannot parse form: %s", err)
return
}
target, err := handleExplorerRedirect(context.Background(), ts, r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.Redirect(w, r, target, http.StatusFound)
})
}