зеркало из https://github.com/github/vitess-gh.git
v3 proto: vtctld & zktopo integration
This commit is contained in:
Родитель
b80eaa5a43
Коммит
2c06df4e5e
|
@ -0,0 +1,25 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>VSchema view</title>
|
||||
<style>
|
||||
html {font-family: sans-serif;}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
{{if .Error}}
|
||||
<h2>Error</h2>
|
||||
{{.Error}}
|
||||
{{else}}
|
||||
<h2>Success</h2>
|
||||
{{end}}
|
||||
<pre>{{.Output}}</pre>
|
||||
|
||||
<form method="post">
|
||||
Upload VSchema<br><textarea name="vschema" cols=80 rows=30>{{.Input}}</textarea><br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -339,6 +339,8 @@ var indexContent = IndexContent{
|
|||
ToplevelLinks: map[string]string{
|
||||
"DbTopology Tool": "/dbtopo",
|
||||
"Serving Graph": "/serving_graph",
|
||||
"Schema editor": "/schema_editor",
|
||||
"Schema view": "/vschema",
|
||||
},
|
||||
}
|
||||
var ts topo.Server
|
||||
|
@ -444,10 +446,6 @@ func main() {
|
|||
templateLoader.ServeTemplate("index.html", indexContent, w, r)
|
||||
})
|
||||
|
||||
http.HandleFunc("/schema_editor/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, *schemaEditorDir+r.URL.Path)
|
||||
})
|
||||
|
||||
// keyspace actions
|
||||
http.HandleFunc("/keyspace_actions", func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
|
@ -560,6 +558,40 @@ func main() {
|
|||
templateLoader.ServeTemplate("serving_graph.html", servingGraph, w, r)
|
||||
})
|
||||
|
||||
// vschema editor
|
||||
http.HandleFunc("/schema_editor/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, *schemaEditorDir+r.URL.Path)
|
||||
})
|
||||
|
||||
// vschema viewer
|
||||
http.HandleFunc("/vschema", func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
httpError(w, "cannot parse form: %s", err)
|
||||
return
|
||||
}
|
||||
schemafier, ok := wr.TopoServer().(topo.Schemafier)
|
||||
if !ok {
|
||||
httpError(w, "%s", fmt.Errorf("%T doesn's support schemafier API", wr.TopoServer()))
|
||||
}
|
||||
var data struct {
|
||||
Error error
|
||||
Input, Output string
|
||||
}
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
data.Input = r.FormValue("vschema")
|
||||
data.Error = schemafier.SaveVSchema(data.Input)
|
||||
}
|
||||
vschema, err := schemafier.GetVSchema()
|
||||
if err != nil {
|
||||
if data.Error == nil {
|
||||
data.Error = fmt.Errorf("Error fetching schema: %s", err)
|
||||
}
|
||||
}
|
||||
data.Output = vschema
|
||||
templateLoader.ServeTemplate("vschema.html", data, w, r)
|
||||
})
|
||||
|
||||
// redirects for explorers
|
||||
http.HandleFunc("/explorers/redirect", func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
|
@ -695,5 +727,6 @@ func main() {
|
|||
}
|
||||
http.Redirect(w, r, target, http.StatusFound)
|
||||
})
|
||||
|
||||
servenv.RunDefault()
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ func main() {
|
|||
log.Info(*cell, *schemaFile)
|
||||
if *schemaFile != "" {
|
||||
var err error
|
||||
if schema, err = planbuilder.LoadSchemaJSON(*schemaFile); err != nil {
|
||||
if schema, err = planbuilder.LoadFile(*schemaFile); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -281,6 +281,13 @@ type Server interface {
|
|||
GetSubprocessFlags() []string
|
||||
}
|
||||
|
||||
// Schemafier is a temporary interface for supporting vschema
|
||||
// reads and writes. It will eventually be merged into Server.
|
||||
type Schemafier interface {
|
||||
SaveVSchema(string) error
|
||||
GetVSchema() (string, error)
|
||||
}
|
||||
|
||||
// Registry for Server implementations.
|
||||
var serverImpls map[string]Server = make(map[string]Server)
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// TODO(sougou): The comments below look obsolete. Need to verify.
|
||||
// Package test contains utilities to test topo.Server
|
||||
// implementations. If you are testing your implementation, you will
|
||||
// want to call CheckAll in your test method. For an example, look at
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2015, Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
)
|
||||
|
||||
func CheckVSchema(t *testing.T, ts topo.Server) {
|
||||
schemafier, ok := ts.(topo.Schemafier)
|
||||
if !ok {
|
||||
t.Errorf("%T is not a Schemafier", ts)
|
||||
return
|
||||
}
|
||||
got, err := schemafier.GetVSchema()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := "{}"
|
||||
if got != want {
|
||||
t.Errorf("GetVSchema: %s, want %s", got, want)
|
||||
}
|
||||
|
||||
err = schemafier.SaveVSchema("aa")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
got, err = schemafier.GetVSchema()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want = "aa"
|
||||
if got != want {
|
||||
t.Errorf("GetVSchema: %s, want %s", got, want)
|
||||
}
|
||||
|
||||
err = schemafier.SaveVSchema("bb")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
got, err = schemafier.GetVSchema()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want = "bb"
|
||||
if got != want {
|
||||
t.Errorf("GetVSchema: %s, want %s", got, want)
|
||||
}
|
||||
}
|
|
@ -84,7 +84,7 @@ func TestPlanName(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPlan(t *testing.T) {
|
||||
schema, err := LoadSchemaJSON(locateFile("schema_test.json"))
|
||||
schema, err := LoadFile(locateFile("schema_test.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
package planbuilder
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
|
||||
"github.com/youtube/vitess/go/jscfg"
|
||||
)
|
||||
|
||||
// Schema represents the denormalized version of SchemaFormal,
|
||||
|
@ -186,13 +186,20 @@ type ColVindexFormal struct {
|
|||
Name string
|
||||
}
|
||||
|
||||
// LoadSchemaJSON loads the formal representation of a schema
|
||||
// from a JSON file and returns the more usable denormalized
|
||||
// representaion (Schema) for it.
|
||||
func LoadSchemaJSON(filename string) (schema *Schema, err error) {
|
||||
// LoadFile creates a new Schema from a JSON file.
|
||||
func LoadFile(filename string) (schema *Schema, err error) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ReadFile failed: %v %v", filename, err)
|
||||
}
|
||||
return NewSchema(data)
|
||||
}
|
||||
|
||||
// NewSchema creates a new Schema from a JSON byte array.
|
||||
func NewSchema(data []byte) (schema *Schema, err error) {
|
||||
var source SchemaFormal
|
||||
if err := jscfg.ReadJson(filename, &source); err != nil {
|
||||
return nil, err
|
||||
if err := json.Unmarshal(data, &source); err != nil {
|
||||
return nil, fmt.Errorf("Unmarshal failed: %v %s %v", source, data, err)
|
||||
}
|
||||
return BuildSchema(&source)
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
package planbuilder
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -265,23 +263,16 @@ func TestShardedSchemaNotOwned(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLoadSchemaFail(t *testing.T) {
|
||||
badSchema := "{,}"
|
||||
f, err := ioutil.TempFile("", "schema_test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fname := f.Name()
|
||||
f.Close()
|
||||
defer os.Remove(fname)
|
||||
|
||||
err = ioutil.WriteFile(fname, []byte(badSchema), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = LoadSchemaJSON(fname)
|
||||
want := "ReadJson failed"
|
||||
_, err := LoadFile("bogus file name")
|
||||
want := "ReadFile failed"
|
||||
if err == nil || !strings.HasPrefix(err.Error(), want) {
|
||||
t.Errorf("LoadSchemaJSON: \n%q, should start with \n%q", err, want)
|
||||
t.Errorf("LoadFile: \n%q, should start with \n%q", err, want)
|
||||
}
|
||||
|
||||
_, err = NewSchema([]byte("{,}"))
|
||||
want = "Unmarshal failed"
|
||||
if err == nil || !strings.HasPrefix(err.Error(), want) {
|
||||
t.Errorf("LoadFile: \n%q, should start with \n%q", err, want)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -206,7 +206,7 @@ func createTestSchema(schemaJSON string) *planbuilder.Schema {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
schema, err := planbuilder.LoadSchemaJSON(fname)
|
||||
schema, err := planbuilder.LoadFile(fname)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -45,3 +45,17 @@ func (s *TestServer) LockSrvShardForAction(ctx context.Context, cell, keyspace,
|
|||
}
|
||||
return s.Server.LockSrvShardForAction(ctx, cell, keyspace, shard, contents)
|
||||
}
|
||||
|
||||
// TODO(sougou): Remove these two functions after they're
|
||||
// migrated into topo.Server.
|
||||
// SaveVSchema has to be redefined here.
|
||||
// Otherwise the test type assertion fails.
|
||||
func (s *TestServer) SaveVSchema(vschema string) error {
|
||||
return s.Server.(topo.Schemafier).SaveVSchema(vschema)
|
||||
}
|
||||
|
||||
// GetVSchema has to be redefined here.
|
||||
// Otherwise the test type assertion fails.
|
||||
func (s *TestServer) GetVSchema() (string, error) {
|
||||
return s.Server.(topo.Schemafier).GetVSchema()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2015, Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package zktopo
|
||||
|
||||
import (
|
||||
"github.com/youtube/vitess/go/zk"
|
||||
"launchpad.net/gozk/zookeeper"
|
||||
)
|
||||
|
||||
/*
|
||||
This file contains the vschema management code for zktopo.Server
|
||||
*/
|
||||
|
||||
const (
|
||||
globalVSchemaPath = "/zk/global/vt/vschema"
|
||||
)
|
||||
|
||||
// SaveVSchema saves the JSON vschema into the topo.
|
||||
func (zkts *Server) SaveVSchema(vschema string) error {
|
||||
_, err := zk.CreateOrUpdate(zkts.zconn, globalVSchemaPath, vschema, 0, zookeeper.WorldACL(zookeeper.PERM_ALL), true)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetVSchema fetches the JSON vschema from the topo.
|
||||
func (zkts *Server) GetVSchema() (string, error) {
|
||||
data, _, err := zkts.zconn.Get(globalVSchemaPath)
|
||||
if err != nil {
|
||||
if zookeeper.IsError(err, zookeeper.ZNONODE) {
|
||||
return "{}", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return data, nil
|
||||
}
|
|
@ -63,3 +63,9 @@ func TestSrvShardLock(t *testing.T) {
|
|||
defer ts.Close()
|
||||
test.CheckSrvShardLock(t, ts)
|
||||
}
|
||||
|
||||
func TestVSchema(t *testing.T) {
|
||||
ts := NewTestServer(t, []string{"test"})
|
||||
defer ts.Close()
|
||||
test.CheckVSchema(t, ts)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче