Пример #1
0
func makeTestGossip(t *testing.T) (*gossip.Gossip, func()) {
	n := simulation.NewNetwork(1, "tcp", gossip.TestInterval)
	g := n.Nodes[0].Gossip
	permConfig := &config.PermConfig{
		Read:  []string{""},
		Write: []string{""},
	}

	configMap, err := config.NewPrefixConfigMap([]*config.PrefixConfig{
		{proto.KeyMin, nil, permConfig},
	})
	if err != nil {
		t.Fatalf("failed to make prefix config map, err: %s", err.Error())
	}
	if err := g.AddInfo(gossip.KeySentinel, "cluster1", time.Hour); err != nil {
		t.Fatal(err)
	}
	if err := g.AddInfo(gossip.KeyConfigPermission, configMap, time.Hour); err != nil {
		t.Fatal(err)
	}
	if err := g.AddInfo(gossip.KeyFirstRangeDescriptor, testRangeDescriptor, time.Hour); err != nil {
		t.Fatal(err)
	}
	nodeIDKey := gossip.MakeNodeIDKey(1)
	if err := g.AddInfo(nodeIDKey, &proto.NodeDescriptor{
		NodeID:  1,
		Address: util.MakeUnresolvedAddr(testAddress.Network(), testAddress.String()),
		Attrs:   proto.Attributes{Attrs: []string{"attr1", "attr2"}},
	}, time.Hour); err != nil {
		t.Fatal(err)
	}
	return g, n.Stop
}
Пример #2
0
// TestGCQueueLookupGCPolicy verifies the hierarchical lookup of GC
// policy in the event that the longest matching key prefix does not
// have a zone configured.
func TestGCQueueLookupGCPolicy(t *testing.T) {
	defer leaktest.AfterTest(t)
	zoneConfig1 := config.ZoneConfig{
		ReplicaAttrs:  []proto.Attributes{},
		RangeMinBytes: 1 << 10,
		RangeMaxBytes: 1 << 18,
		GC: &config.GCPolicy{
			TTLSeconds: 60 * 60, // 1 hour only
		},
	}
	zoneConfig2 := config.ZoneConfig{
		ReplicaAttrs:  []proto.Attributes{},
		RangeMinBytes: 1 << 10,
		RangeMaxBytes: 1 << 18,
		// Note that there is no GC set here, so we should select the
		// hierarchical parent's GC policy; in this case, zoneConfig1.
	}
	configs := []*config.PrefixConfig{
		{proto.KeyMin, nil, &zoneConfig1},
		{proto.Key("/db1"), nil, &zoneConfig2},
	}
	pcc, err := config.NewPrefixConfigMap(configs)
	if err != nil {
		t.Fatal(err)
	}

	// Setup test context and add new zone config map. This would normally
	// start a split, but splits are disabled in this testing configuration
	// because the mock DB does not support splits.
	tc := testContext{}
	tc.Start(t)
	defer tc.Stop()
	if err := tc.rng.rm.Gossip().AddInfo(gossip.KeyConfigZone, pcc, 0); err != nil {
		t.Fatal(err)
	}

	// Create a new range within "/db1" and verify that lookup of
	// zone config results in the
	rng2 := createRange(tc.store, 2, proto.Key("/db1/a"), proto.Key("/db1/b"))
	if err := tc.store.AddReplicaTest(rng2); err != nil {
		t.Fatal(err)
	}

	gcQ := newGCQueue()
	gcPolicy, err := gcQ.lookupGCPolicy(rng2)
	if err != nil {
		t.Fatal(err)
	}
	if ttl := gcPolicy.TTLSeconds; ttl != 60*60 {
		t.Errorf("expected TTL=%d; got %d", 60*60, ttl)
	}
}
Пример #3
0
// loadConfigMap scans the config entries under keyPrefix and
// instantiates/returns a config map and its sha256 hash. Prefix
// configuration maps include accounting, permissions, users, and zones.
func loadConfigMap(eng engine.Engine, keyPrefix proto.Key, configI gogoproto.Message) (config.PrefixConfigMap, []byte, error) {
	// TODO(tschottdorf): Currently this does not handle intents well.
	kvs, _, err := engine.MVCCScan(eng, keyPrefix, keyPrefix.PrefixEnd(), 0, proto.MaxTimestamp, true /* consistent */, nil)
	if err != nil {
		return nil, nil, err
	}
	var cfgs []*config.PrefixConfig
	sha := sha256.New()
	for _, kv := range kvs {
		// Instantiate an instance of the config type by unmarshalling
		// proto encoded config from the Value into a new instance of configI.
		cfg := reflect.New(reflect.TypeOf(configI).Elem()).Interface().(gogoproto.Message)
		if err := gogoproto.Unmarshal(kv.Value.Bytes, cfg); err != nil {
			return nil, nil, util.Errorf("unable to unmarshal config key %s: %s", string(kv.Key), err)
		}
		cfgs = append(cfgs, &config.PrefixConfig{Prefix: bytes.TrimPrefix(kv.Key, keyPrefix), Config: cfg})
		sha.Write(kv.Value.Bytes)
	}
	m, err := config.NewPrefixConfigMap(cfgs)
	return m, sha.Sum(nil), err
}
Пример #4
0
// TestVerifyPermissions verifies permissions are checked for single
// zones and across multiple zones. It also verifies that permissions
// are checked hierarchically.
func TestVerifyPermissions(t *testing.T) {
	defer leaktest.AfterTest(t)
	n := simulation.NewNetwork(1, "tcp", gossip.TestInterval)
	ds := NewDistSender(nil, n.Nodes[0].Gossip)
	config1 := &config.PermConfig{
		Read:  []string{"read1", "readAll", "rw1", "rwAll"},
		Write: []string{"write1", "writeAll", "rw1", "rwAll"}}
	config2 := &config.PermConfig{
		Read:  []string{"read2", "readAll", "rw2", "rwAll"},
		Write: []string{"write2", "writeAll", "rw2", "rwAll"}}
	configs := []*config.PrefixConfig{
		{proto.KeyMin, nil, config1},
		{proto.Key("a"), nil, config2},
	}
	configMap, err := config.NewPrefixConfigMap(configs)
	if err != nil {
		t.Fatalf("failed to make prefix config map, err: %s", err.Error())
	}
	if err := ds.gossip.AddInfo(gossip.KeyConfigPermission, configMap, time.Hour); err != nil {
		t.Fatal(err)
	}

	allRequestTypes := []proto.Request{
		&proto.GetRequest{},
		&proto.PutRequest{},
		&proto.ConditionalPutRequest{},
		&proto.IncrementRequest{},
		&proto.DeleteRequest{},
		&proto.DeleteRangeRequest{},
		&proto.ScanRequest{},
		&proto.ReverseScanRequest{},
		&proto.EndTransactionRequest{},
		&proto.AdminSplitRequest{},
		&proto.AdminMergeRequest{},
		&proto.HeartbeatTxnRequest{},
		&proto.GCRequest{},
		&proto.PushTxnRequest{},
		&proto.RangeLookupRequest{},
		&proto.ResolveIntentRequest{},
		&proto.ResolveIntentRangeRequest{},
		&proto.MergeRequest{},
		&proto.TruncateLogRequest{},
		&proto.LeaderLeaseRequest{},
		&proto.BatchRequest{},
	}

	var readOnlyRequests []proto.Request
	var writeOnlyRequests []proto.Request
	var readWriteRequests []proto.Request

	for _, r := range allRequestTypes {
		if proto.IsRead(r) && !proto.IsWrite(r) {
			readOnlyRequests = append(readOnlyRequests, r)
		}
		if proto.IsWrite(r) && !proto.IsRead(r) {
			writeOnlyRequests = append(writeOnlyRequests, r)
		}
		if proto.IsRead(r) && proto.IsWrite(r) {
			readWriteRequests = append(readWriteRequests, r)
		}
	}

	testData := []struct {
		// Permission-based db methods from the storage package.
		requests         []proto.Request
		user             string
		startKey, endKey proto.Key
		hasPermission    bool
	}{
		// Test permissions within a single range
		{readOnlyRequests, "read1", proto.KeyMin, proto.KeyMin, true},
		{readOnlyRequests, "rw1", proto.KeyMin, proto.KeyMin, true},
		{readOnlyRequests, "write1", proto.KeyMin, proto.KeyMin, false},
		{readOnlyRequests, "random", proto.KeyMin, proto.KeyMin, false},
		{readWriteRequests, "rw1", proto.KeyMin, proto.KeyMin, true},
		{readWriteRequests, "read1", proto.KeyMin, proto.KeyMin, false},
		{readWriteRequests, "write1", proto.KeyMin, proto.KeyMin, false},
		{writeOnlyRequests, "write1", proto.KeyMin, proto.KeyMin, true},
		{writeOnlyRequests, "rw1", proto.KeyMin, proto.KeyMin, true},
		{writeOnlyRequests, "read1", proto.KeyMin, proto.KeyMin, false},
		{writeOnlyRequests, "random", proto.KeyMin, proto.KeyMin, false},
		// Test permissions hierarchically.
		{readOnlyRequests, "read1", proto.Key("a"), proto.Key("a1"), true},
		{readWriteRequests, "rw1", proto.Key("a"), proto.Key("a1"), true},
		{writeOnlyRequests, "write1", proto.Key("a"), proto.Key("a1"), true},
		// Test permissions across both ranges.
		{readOnlyRequests, "readAll", proto.KeyMin, proto.Key("b"), true},
		{readOnlyRequests, "read1", proto.KeyMin, proto.Key("b"), true},
		{readOnlyRequests, "read2", proto.KeyMin, proto.Key("b"), false},
		{readOnlyRequests, "random", proto.KeyMin, proto.Key("b"), false},
		{readWriteRequests, "rwAll", proto.KeyMin, proto.Key("b"), true},
		{readWriteRequests, "rw1", proto.KeyMin, proto.Key("b"), true},
		{readWriteRequests, "random", proto.KeyMin, proto.Key("b"), false},
		{writeOnlyRequests, "writeAll", proto.KeyMin, proto.Key("b"), true},
		{writeOnlyRequests, "write1", proto.KeyMin, proto.Key("b"), true},
		{writeOnlyRequests, "write2", proto.KeyMin, proto.Key("b"), false},
		{writeOnlyRequests, "random", proto.KeyMin, proto.Key("b"), false},
		// Test permissions within and around the boundaries of a range,
		// representatively using rw methods.
		{readWriteRequests, "rw2", proto.Key("a"), proto.Key("b"), true},
		{readWriteRequests, "rwAll", proto.Key("a"), proto.Key("b"), true},
		{readWriteRequests, "rw2", proto.Key("a"), proto.Key("a"), true},
		{readWriteRequests, "rw2", proto.Key("a"), proto.Key("a1"), true},
		{readWriteRequests, "rw2", proto.Key("a"), proto.Key("b1"), false},
		{readWriteRequests, "rw2", proto.Key("a3"), proto.Key("a4"), true},
		{readWriteRequests, "rw2", proto.Key("a3"), proto.Key("b1"), false},
	}

	for i, test := range testData {
		for _, r := range test.requests {
			*r.Header() = proto.RequestHeader{
				User:   test.user,
				Key:    test.startKey,
				EndKey: test.endKey,
			}
			err := ds.verifyPermissions(r)
			if err != nil && test.hasPermission {
				t.Errorf("test %d: user %s should have had permission to %s, err: %s",
					i, test.user, r.Method(), err.Error())
				break
			} else if err == nil && !test.hasPermission {
				t.Errorf("test %d: user %s should not have had permission to %s",
					i, test.user, r.Method())
				break
			}
		}
	}
	n.Stop()
}
Пример #5
0
// TestSplitQueueShouldQueue verifies shouldQueue method correctly
// combines splits in accounting and zone configs with the size of
// the range.
func TestSplitQueueShouldQueue(t *testing.T) {
	defer leaktest.AfterTest(t)
	tc := testContext{}
	tc.Start(t)
	defer tc.Stop()

	// Set accounting and zone configs.
	acctMap, err := config.NewPrefixConfigMap([]*config.PrefixConfig{
		{proto.KeyMin, nil, config1},
		{proto.Key("/dbA"), nil, config2},
	})
	if err != nil {
		t.Fatal(err)
	}
	if err := tc.gossip.AddInfo(gossip.KeyConfigAccounting, acctMap, 0); err != nil {
		t.Fatal(err)
	}

	zoneMap, err := config.NewPrefixConfigMap([]*config.PrefixConfig{
		{proto.KeyMin, nil, &config.ZoneConfig{RangeMaxBytes: 64 << 20}},
		{proto.Key("/dbB"), nil, &config.ZoneConfig{RangeMaxBytes: 64 << 20}},
	})
	if err != nil {
		t.Fatal(err)
	}
	if err := tc.gossip.AddInfo(gossip.KeyConfigZone, zoneMap, 0); err != nil {
		t.Fatal(err)
	}

	testCases := []struct {
		start, end proto.Key
		bytes      int64
		shouldQ    bool
		priority   float64
	}{
		// No intersection, no bytes.
		{proto.KeyMin, proto.Key("/"), 0, false, 0},
		// Intersection in accounting, no bytes.
		{proto.Key("/"), proto.Key("/dbA1"), 0, true, 1},
		// Intersection in zone, no bytes.
		{proto.Key("/dbA"), proto.Key("/dbC"), 0, true, 1},
		// Multiple intersections, no bytes.
		{proto.KeyMin, proto.KeyMax, 0, true, 1},
		// No intersection, max bytes.
		{proto.KeyMin, proto.Key("/"), 64 << 20, false, 0},
		// No intersection, max bytes+1.
		{proto.KeyMin, proto.Key("/"), 64<<20 + 1, true, 1},
		// No intersection, max bytes * 2.
		{proto.KeyMin, proto.Key("/"), 64 << 21, true, 2},
		// Intersection, max bytes +1.
		{proto.KeyMin, proto.KeyMax, 64<<20 + 1, true, 2},
	}

	splitQ := newSplitQueue(nil, tc.gossip)

	for i, test := range testCases {
		if err := tc.rng.stats.SetMVCCStats(tc.rng.rm.Engine(), engine.MVCCStats{KeyBytes: test.bytes}); err != nil {
			t.Fatal(err)
		}
		copy := *tc.rng.Desc()
		copy.StartKey = test.start
		copy.EndKey = test.end
		if err := tc.rng.setDesc(&copy); err != nil {
			t.Fatal(err)
		}
		shouldQ, priority := splitQ.shouldQueue(proto.ZeroTimestamp, tc.rng)
		if shouldQ != test.shouldQ {
			t.Errorf("%d: should queue expected %t; got %t", i, test.shouldQ, shouldQ)
		}
		if math.Abs(priority-test.priority) > 0.00001 {
			t.Errorf("%d: priority expected %f; got %f", i, test.priority, priority)
		}
	}
}