Example #1
0
// ExampleSetAndGetZone sets zone configs for a variety of key
// prefixes and verifies they can be fetched directly.
func ExampleSetAndGetZone() {
	httpServer := startAdminServer()
	defer httpServer.Close()
	testConfigFn := createTestConfigFile()
	defer os.Remove(testConfigFn)

	testData := []struct {
		prefix storage.Key
		yaml   string
	}{
		{storage.KeyMin, testConfig},
		{storage.Key("db1"), testConfig},
		{storage.Key("db 2"), testConfig},
		{storage.Key("\xfe"), testConfig},
	}

	for _, test := range testData {
		prefix := url.QueryEscape(string(test.prefix))
		runSetZone(CmdSetZone, []string{prefix, testConfigFn})
		runGetZones(CmdGetZone, []string{prefix})
	}
	// Output:
	// set zone config for key prefix ""
	// zone config for key prefix "":
	//
	// replicas:
	//   dc1:
	//   - SSD
	// range_min_bytes: 1048576
	// range_max_bytes: 67108864
	//
	// set zone config for key prefix "db1"
	// zone config for key prefix "db1":
	//
	// replicas:
	//   dc1:
	//   - SSD
	// range_min_bytes: 1048576
	// range_max_bytes: 67108864
	//
	// set zone config for key prefix "db+2"
	// zone config for key prefix "db+2":
	//
	// replicas:
	//   dc1:
	//   - SSD
	// range_min_bytes: 1048576
	// range_max_bytes: 67108864
	//
	// set zone config for key prefix "%FE"
	// zone config for key prefix "%FE":
	//
	// replicas:
	//   dc1:
	//   - SSD
	// range_min_bytes: 1048576
	// range_max_bytes: 67108864
}
Example #2
0
// ExampleLsZones creates a series of zone configs and verifies
// zone-ls works. First, no regexp lists all zone configs. Second,
// regexp properly matches results.
func ExampleLsZones() {
	httpServer := startAdminServer()
	defer httpServer.Close()
	testConfigFn := createTestConfigFile()
	defer os.Remove(testConfigFn)

	keys := []storage.Key{
		storage.KeyMin,
		storage.Key("db1"),
		storage.Key("db2"),
		storage.Key("db3"),
		storage.Key("user"),
	}

	regexps := []string{
		"",
		"db*",
		"db[12]",
	}

	for _, key := range keys {
		prefix := url.QueryEscape(string(key))
		runSetZone(CmdSetZone, []string{prefix, testConfigFn})
	}

	for i, regexp := range regexps {
		fmt.Fprintf(os.Stdout, "test case %d: %q\n", i, regexp)
		if regexp == "" {
			runLsZones(CmdLsZones, []string{})
		} else {
			runLsZones(CmdLsZones, []string{regexp})
		}
	}
	// Output:
	// set zone config for key prefix ""
	// set zone config for key prefix "db1"
	// set zone config for key prefix "db2"
	// set zone config for key prefix "db3"
	// set zone config for key prefix "user"
	// test case 0: ""
	// [default]
	// db1
	// db2
	// db3
	// user
	// test case 1: "db*"
	// db1
	// db2
	// db3
	// test case 2: "db[12]"
	// db1
	// db2
}
Example #3
0
func TestKeysAndBodyArePreserved(t *testing.T) {
	encKey := "%00some%2Fkey%20that%20encodes%E4%B8%96%E7%95%8C"
	encBody := "%00some%2FBODY%20that%20encodes"
	s := runHTTPTestFixture(t, []RequestResponse{
		{
			NewRequest("POST", encKey, encBody),
			NewResponse(200),
		},
		{
			NewRequest("GET", encKey),
			NewResponse(200, encBody, "application/octet-stream"),
		},
	})
	gr := <-s.db.Get(&storage.GetRequest{
		RequestHeader: storage.RequestHeader{
			Key:  storage.Key("\x00some/key that encodes世界"),
			User: storage.UserRoot,
		},
	})
	if gr.Error != nil {
		t.Errorf("Unable to fetch values from local db")
	}
	if !bytes.Equal(gr.Value.Bytes, []byte(encBody)) {
		t.Errorf("Expected value (%s) but got (%s)", encBody, gr.Value.Bytes)
	}
}
Example #4
0
func dbKey(path string) (storage.Key, error) {
	result, err := url.QueryUnescape(strings.TrimPrefix(path, KVKeyPrefix))
	if err == nil {
		return storage.Key(result), nil
	}
	return nil, err
}
Example #5
0
// ExampleRmZones creates a series of zone configs and verifies
// zone-rm works by deleting some and then all and verifying entries
// have been removed via zone-ls. Also verify the default zone cannot
// be removed.
func ExampleRmZones() {
	httpServer := startAdminServer()
	defer httpServer.Close()
	testConfigFn := createTestConfigFile()
	defer os.Remove(testConfigFn)

	keys := []storage.Key{
		storage.KeyMin,
		storage.Key("db1"),
	}

	for _, key := range keys {
		prefix := url.QueryEscape(string(key))
		runSetZone(CmdSetZone, []string{prefix, testConfigFn})
	}

	for _, key := range keys {
		prefix := url.QueryEscape(string(key))
		runRmZone(CmdRmZone, []string{prefix})
		runLsZones(CmdLsZones, []string{})
	}
	// Output:
	// set zone config for key prefix ""
	// set zone config for key prefix "db1"
	// [default]
	// db1
	// removed zone config for key prefix "db1"
	// [default]
}
Example #6
0
// TestBootstrap verifies the results of bootstrapping a cluster. Uses
// an in memory engine.
func TestBootstrapCluster(t *testing.T) {
	engine := storage.NewInMem(1 << 20)
	localDB, err := BootstrapCluster("cluster-1", engine)
	if err != nil {
		t.Fatal(err)
	}
	// Scan the complete contents of the local database.
	sr := <-localDB.Scan(&storage.ScanRequest{
		StartKey:   storage.KeyMin,
		EndKey:     storage.KeyMax,
		MaxResults: math.MaxInt64,
	})
	if sr.Error != nil {
		t.Fatal(sr.Error)
	}
	var keys []storage.Key
	for _, kv := range sr.Rows {
		keys = append(keys, kv.Key)
	}
	var expectedKeys = []storage.Key{
		storage.Key("\x00\x00\x00range-1"),
		storage.Key("\x00\x00\x00range-id-generator"),
		storage.Key("\x00\x00\x00store-ident"),
		storage.Key("\x00\x00meta1\xff"),
		storage.Key("\x00\x00meta2\xff"),
		storage.Key("\x00node-id-generator"),
		storage.Key("\x00store-id-generator-1"),
	}
	if !reflect.DeepEqual(keys, expectedKeys) {
		t.Errorf("expected keys mismatch:\n%s\n  -- vs. -- \n\n%s",
			formatKeys(keys), formatKeys(expectedKeys))
	}

	// TODO(spencer): check values.
}
Example #7
0
// Get retrieves the zone configuration for the specified key. If the
// key is empty, all zone configurations are returned. Otherwise, the
// leading "/" path delimiter is stripped and the zone configuration
// matching the remainder is retrieved. Note that this will retrieve
// the default zone config if "key" is equal to "/", and will list all
// configs if "key" is equal to "". The body result contains
// JSON-formatted output for a listing of keys and YAML-formatted
// output for retrieval of a zone config.
func (zh *zoneHandler) Get(path string, r *http.Request) (body []byte, contentType string, err error) {
	// Scan all zones if the key is empty.
	if len(path) == 0 {
		sr := <-zh.kvDB.Scan(&storage.ScanRequest{
			RequestHeader: storage.RequestHeader{
				Key:    storage.KeyConfigZonePrefix,
				EndKey: storage.PrefixEndKey(storage.KeyConfigZonePrefix),
				User:   storage.UserRoot,
			},
			MaxResults: maxGetResults,
		})
		if sr.Error != nil {
			err = sr.Error
			return
		}
		if len(sr.Rows) == maxGetResults {
			glog.Warningf("retrieved maximum number of results (%d); some may be missing", maxGetResults)
		}
		var prefixes []string
		for _, kv := range sr.Rows {
			trimmed := bytes.TrimPrefix(kv.Key, storage.KeyConfigZonePrefix)
			prefixes = append(prefixes, url.QueryEscape(string(trimmed)))
		}
		// JSON-encode the prefixes array.
		contentType = "application/json"
		if body, err = json.Marshal(prefixes); err != nil {
			err = util.Errorf("unable to format zone configurations: %v", err)
		}
	} else {
		zoneKey := storage.MakeKey(storage.KeyConfigZonePrefix, storage.Key(path[1:]))
		var ok bool
		config := &storage.ZoneConfig{}
		if ok, _, err = kv.GetI(zh.kvDB, zoneKey, config); err != nil {
			return
		}
		// On get, if there's no zone config for the requested prefix,
		// return a not found error.
		if !ok {
			err = util.Errorf("no config found for key prefix %q", path)
			return
		}
		var out []byte
		if out, err = yaml.Marshal(config); err != nil {
			err = util.Errorf("unable to marshal zone config %+v to yaml: %v", config, err)
			return
		}
		if !utf8.ValidString(string(out)) {
			err = util.Errorf("config contents not valid utf8: %q", out)
			return
		}
		contentType = "text/yaml"
		body = out
	}

	return
}
Example #8
0
func dbKey(path, apiPrefix string) (storage.Key, error) {
	result, err := url.QueryUnescape(strings.TrimPrefix(path, apiPrefix))
	if err == nil {
		k := storage.Key(result)
		if len(k) == 0 {
			return nil, fmt.Errorf("empty key not allowed")
		}
		return k, nil
	}
	return nil, err
}
Example #9
0
// Delete removes the zone config specified by key.
func (zh *zoneHandler) Delete(path string, r *http.Request) error {
	if len(path) == 0 {
		return util.Errorf("no path specified for zone Delete")
	}
	if path == "/" {
		return util.Errorf("the default zone configuration cannot be deleted")
	}
	zoneKey := storage.MakeKey(storage.KeyConfigZonePrefix, storage.Key(path[1:]))
	dr := <-zh.kvDB.Delete(&storage.DeleteRequest{Key: zoneKey})
	if dr.Error != nil {
		return dr.Error
	}
	return nil
}
Example #10
0
func TestReplicaLookup(t *testing.T) {

	db := NewLocalDB()
	r1 := db.addTestRange(storage.KeyMin, storage.Key("C"))
	r2 := db.addTestRange(storage.Key("C"), storage.Key("X"))
	r3 := db.addTestRange(storage.Key("X"), storage.KeyMax)
	if len(db.ranges) != 3 {
		t.Errorf("Pre-condition failed! Expected ranges to be size 3, got %d", len(db.ranges))
	}

	assertReplicaForRange(t, db.lookupReplica(storage.KeyMin), r1)
	assertReplicaForRange(t, db.lookupReplica(storage.Key("B")), r1)
	assertReplicaForRange(t, db.lookupReplica(storage.Key("C")), r2)
	assertReplicaForRange(t, db.lookupReplica(storage.Key("M")), r2)
	assertReplicaForRange(t, db.lookupReplica(storage.Key("X")), r3)
	assertReplicaForRange(t, db.lookupReplica(storage.Key("Z")), r3)
	if db.lookupReplica(storage.KeyMax) != nil {
		t.Errorf("Expected storage.KeyMax to not have an associated Replica.")
	}
}
Example #11
0
// Get retrieves the zone configuration for the specified key. If the
// key is empty, all zone configurations are returned. Otherwise, the
// leading "/" path delimiter is stripped and the zone configuration
// matching the remainder is retrieved. Note that this will retrieve
// the default zone config if "key" is equal to "/", and will list all
// configs if "key" is equal to "". The body result contains
// JSON-formmatted output via the GetZoneResponse struct.
func (zh *zoneHandler) Get(path string, r *http.Request) (body []byte, contentType string, err error) {
	contentType = "application/json"

	// Scan all zones if the key is empty.
	if len(path) == 0 {
		sr := <-zh.kvDB.Scan(&storage.ScanRequest{
			StartKey:   storage.KeyConfigZonePrefix,
			EndKey:     storage.PrefixEndKey(storage.KeyConfigZonePrefix),
			MaxResults: maxGetResults,
		})
		if sr.Error != nil {
			err = sr.Error
			return
		}
		if len(sr.Rows) == maxGetResults {
			glog.Warningf("retrieved maximum number of results (%d); some may be missing", maxGetResults)
		}
		var prefixes []string
		for _, kv := range sr.Rows {
			trimmed := bytes.TrimPrefix(kv.Key, storage.KeyConfigZonePrefix)
			prefixes = append(prefixes, url.QueryEscape(string(trimmed)))
		}
		// JSON-encode the prefixes array.
		if body, err = json.Marshal(prefixes); err != nil {
			err = util.Errorf("unable to format zone configurations: %v", err)
		}
	} else {
		zoneKey := storage.MakeKey(storage.KeyConfigZonePrefix, storage.Key(path[1:]))
		gr := <-zh.kvDB.Get(&storage.GetRequest{Key: zoneKey})
		if gr.Error != nil {
			return
		}
		// On get, if there's no zone config for the requested prefix,
		// return a not found error.
		if gr.Value.Bytes == nil {
			err = util.Errorf("no config found for key prefix %q", path)
			return
		}
		if !utf8.ValidString(string(gr.Value.Bytes)) {
			err = util.Errorf("config contents not valid utf8: %q", gr.Value)
			return
		}
		body = gr.Value.Bytes
	}

	return
}
Example #12
0
// Put writes a zone config for the specified key prefix "key".  The
// zone config is parsed from the input "body". The zone config is
// stored gob-encoded. The specified body must be valid utf8 and must
// validly parse into a zone config struct.
func (zh *zoneHandler) Put(path string, body []byte, r *http.Request) error {
	if len(path) == 0 {
		return util.Errorf("no path specified for zone Put")
	}
	configStr := string(body)
	if !utf8.ValidString(configStr) {
		return util.Errorf("config contents not valid utf8: %q", body)
	}
	config, err := storage.ParseZoneConfig(body)
	if err != nil {
		return util.Errorf("zone config has invalid format: %s: %v", configStr, err)
	}
	zoneKey := storage.MakeKey(storage.KeyConfigZonePrefix, storage.Key(path[1:]))
	if err := kv.PutI(zh.kvDB, zoneKey, config, hlc.HLTimestamp{}); err != nil {
		return err
	}
	return nil
}
Example #13
0
// Put writes a zone config for the specified key prefix "key".  The
// zone config is parsed from the input "body". The zone config is
// stored as YAML text. The specified body must be valid utf8 and
// must validly parse into a zone config struct.
func (zh *zoneHandler) Put(path string, body []byte, r *http.Request) error {
	if len(path) == 0 {
		return util.Errorf("no path specified for zone Put")
	}
	configStr := string(body)
	if !utf8.ValidString(configStr) {
		return util.Errorf("config contents not valid utf8: %q", body)
	}
	_, err := storage.ParseZoneConfig(body)
	if err != nil {
		return util.Errorf("zone config has invalid format: %s: %v", configStr, err)
	}
	zoneKey := storage.MakeKey(storage.KeyConfigZonePrefix, storage.Key(path[1:]))
	pr := <-zh.kvDB.Put(&storage.PutRequest{Key: zoneKey, Value: storage.Value{Bytes: body}})
	if pr.Error != nil {
		return pr.Error
	}
	return nil
}