Move syncbase discovery to the ref repo.
This change also includes the chnage in:
https://vanadium-review.googlesource.com/#/c/22812/
Please see that change for details.
MultiPart: 1/2
Change-Id: I3fdfbe27cfdbb4fc8beb91f7401d59a46d18c850
diff --git a/syncbase/.api b/syncbase/.api
index 78e1422..ecea5e1 100644
--- a/syncbase/.api
+++ b/syncbase/.api
@@ -1,6 +1,5 @@
pkg syncbase, const DeleteChange ChangeType
pkg syncbase, const PutChange ChangeType
-pkg syncbase, func NewDiscovery(*context.T) (discovery.T, error)
pkg syncbase, func NewService(string) Service
pkg syncbase, func NewValue(*context.T, interface{}) (*Value, error)
pkg syncbase, func Prefix(string) PrefixRange
@@ -13,8 +12,6 @@
pkg syncbase, method (*ConflictRow) VDLRead(vdl.Decoder) error
pkg syncbase, method (*ConflictRowSet) VDLRead(vdl.Decoder) error
pkg syncbase, method (*ConflictScanSet) VDLRead(vdl.Decoder) error
-pkg syncbase, method (*Discovery) Advertise(*context.T, *discovery.Advertisement, []security.BlessingPattern) (<-chan struct{}, error)
-pkg syncbase, method (*Discovery) Scan(*context.T, string) (<-chan discovery.Update, error)
pkg syncbase, method (*Resolution) VDLRead(vdl.Decoder) error
pkg syncbase, method (*ResolvedRow) VDLRead(vdl.Decoder) error
pkg syncbase, method (*Value) Get(interface{}) error
@@ -131,7 +128,6 @@
pkg syncbase, type DatabaseHandle interface, GetResumeMarker(*context.T) (watch.ResumeMarker, error)
pkg syncbase, type DatabaseHandle interface, Id() wire.Id
pkg syncbase, type DatabaseHandle interface, ListCollections(*context.T) ([]wire.Id, error)
-pkg syncbase, type Discovery struct
pkg syncbase, type PrefixRange interface { Limit, Prefix, Start }
pkg syncbase, type PrefixRange interface, Limit() string
pkg syncbase, type PrefixRange interface, Prefix() string
diff --git a/syncbase/discovery.go b/syncbase/discovery.go
deleted file mode 100644
index 3ec1f6a..0000000
--- a/syncbase/discovery.go
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright 2016 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package syncbase
-
-import (
- "strings"
-
- "v.io/v23"
- "v.io/v23/context"
- "v.io/v23/discovery"
- "v.io/v23/security"
-)
-
-const visibilityKey = "vis"
-
-// Discovery implements v.io/v23/discovery.T for syncbase based
-// applications.
-// TODO(mattr): Actually this is not syncbase specific. At some
-// point we should just replace the result of v23.NewDiscovery
-// with this.
-type Discovery struct {
- nhDiscovery discovery.T
- // TODO(mattr): Add global discovery.
-}
-
-// NewDiscovery creates a new syncbase discovery object.
-func NewDiscovery(ctx *context.T) (discovery.T, error) {
- nhDiscovery, err := v23.NewDiscovery(ctx)
- if err != nil {
- return nil, err
- }
- return &Discovery{nhDiscovery: nhDiscovery}, nil
-}
-
-// Scan implements v.io/v23/discovery/T.Scan.
-func (d *Discovery) Scan(ctx *context.T, query string) (<-chan discovery.Update, error) {
- nhUpdates, err := d.nhDiscovery.Scan(ctx, query)
- if err != nil {
- return nil, err
- }
-
- // Currently setting visibility on the neighborhood discovery
- // service turns IBE encryption on. We currently don't have the
- // infrastructure support for IBE, so that would make our advertisements
- // unreadable by everyone.
- // Instead we add the visibility list to the attributes of the advertisement
- // and filter on the client side. This is a temporary measure until
- // IBE is set up. See v.io/i/1345.
- updates := make(chan discovery.Update)
- go func() {
- for u := range nhUpdates {
- patterns := splitPatterns(u.Attribute(visibilityKey))
- if len(patterns) > 0 && !matchesPatterns(ctx, patterns) {
- continue
- }
- updates <- update{u}
- }
- close(updates)
- }()
-
- return updates, nil
-}
-
-// Advertise implements v.io/v23/discovery/T.Advertise.
-func (d *Discovery) Advertise(ctx *context.T, ad *discovery.Advertisement, visibility []security.BlessingPattern) (<-chan struct{}, error) {
- // Currently setting visibility on the neighborhood discovery
- // service turns IBE encryption on. We currently don't have the
- // infrastructure support for IBE, so that would make our advertisements
- // unreadable by everyone.
- // Instead we add the visibility list to the attributes of the advertisement
- // and filter on the client side. This is a temporary measure until
- // IBE is set up. See v.io/i/1345.
- adCopy := *ad
- if len(visibility) > 0 {
- adCopy.Attributes = make(discovery.Attributes, len(ad.Attributes)+1)
- for k, v := range ad.Attributes {
- adCopy.Attributes[k] = v
- }
- patterns := joinPatterns(visibility)
- adCopy.Attributes[visibilityKey] = patterns
- }
- ch, err := d.nhDiscovery.Advertise(ctx, &adCopy, nil)
- ad.Id = adCopy.Id
- return ch, err
-}
-
-func matchesPatterns(ctx *context.T, patterns []security.BlessingPattern) bool {
- p := v23.GetPrincipal(ctx)
- blessings := p.BlessingStore().PeerBlessings()
- for _, b := range blessings {
- names := security.BlessingNames(p, b)
- for _, pattern := range patterns {
- if pattern.MatchedBy(names...) {
- return true
- }
- }
- }
- return false
-}
-
-// update wraps the discovery.Update to remove the visibility attribute which we add.
-type update struct {
- discovery.Update
-}
-
-func (u update) Attribute(name string) string {
- if name == visibilityKey {
- return ""
- }
- return u.Update.Attribute(name)
-}
-
-func (u update) Advertisement() discovery.Advertisement {
- cp := u.Update.Advertisement()
- orig := cp.Attributes
- cp.Attributes = make(discovery.Attributes, len(orig))
- for k, v := range orig {
- if k != visibilityKey {
- cp.Attributes[k] = v
- }
- }
- return cp
-}
-
-// blessingSeparator is used to join multiple blessings into a
-// single string.
-// Note that comma cannot appear in blessings, see:
-// v.io/v23/security/certificate.go
-const blessingsSeparator = ','
-
-// joinPatterns concatenates the elements of a to create a single string.
-// The string can be split again with SplitPatterns.
-func joinPatterns(a []security.BlessingPattern) string {
- if len(a) == 0 {
- return ""
- }
- if len(a) == 1 {
- return string(a[0])
- }
- n := (len(a) - 1)
- for i := 0; i < len(a); i++ {
- n += len(a[i])
- }
-
- b := make([]byte, n)
- bp := copy(b, a[0])
- for _, s := range a[1:] {
- b[bp] = blessingsSeparator
- bp++
- bp += copy(b[bp:], s)
- }
- return string(b)
-}
-
-// splitPatterns splits BlessingPatterns that were joined with
-// JoinBlessingPattern.
-func splitPatterns(patterns string) []security.BlessingPattern {
- if patterns == "" {
- return nil
- }
- n := strings.Count(patterns, string(blessingsSeparator)) + 1
- out := make([]security.BlessingPattern, n)
- last, start := 0, 0
- for i, r := range patterns {
- if r == blessingsSeparator {
- out[last] = security.BlessingPattern(patterns[start:i])
- last++
- start = i + 1
- }
- }
- out[last] = security.BlessingPattern(patterns[start:])
- return out
-}
diff --git a/syncbase/discovery_pattern_test.go b/syncbase/discovery_pattern_test.go
deleted file mode 100644
index 1d61faa..0000000
--- a/syncbase/discovery_pattern_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package syncbase
-
-import (
- "reflect"
- "testing"
-
- "v.io/v23/security"
-)
-
-func TestJoinSplitPatterns(t *testing.T) {
- cases := []struct {
- patterns []security.BlessingPattern
- joined string
- }{
- {nil, ""},
- {[]security.BlessingPattern{"a", "b"}, "a,b"},
- {[]security.BlessingPattern{"a:b:c", "d:e:f"}, "a:b:c,d:e:f"},
- {[]security.BlessingPattern{"alpha:one", "alpha:two", "alpha:three"}, "alpha:one,alpha:two,alpha:three"},
- }
- for _, c := range cases {
- if got := joinPatterns(c.patterns); got != c.joined {
- t.Errorf("%#v, got %q, wanted %q", c.patterns, got, c.joined)
- }
- if got := splitPatterns(c.joined); !reflect.DeepEqual(got, c.patterns) {
- t.Errorf("%q, got %#v, wanted %#v", c.joined, got, c.patterns)
- }
- }
- // Special case, Joining an empty non-nil list results in empty string.
- if got := joinPatterns([]security.BlessingPattern{}); got != "" {
- t.Errorf("Joining empty list: got %q, want %q", got, "")
- }
-}
diff --git a/syncbase/discovery_test.go b/syncbase/discovery_test.go
deleted file mode 100644
index 8408b0d..0000000
--- a/syncbase/discovery_test.go
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright 2016 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package syncbase_test
-
-import (
- "fmt"
- "reflect"
- "testing"
- "time"
-
- "v.io/v23"
- "v.io/v23/context"
- "v.io/v23/discovery"
- "v.io/v23/security"
- "v.io/v23/security/access"
- wire "v.io/v23/services/syncbase"
- "v.io/v23/syncbase"
- "v.io/v23/verror"
- tu "v.io/x/ref/services/syncbase/testutil"
- "v.io/x/ref/test/testutil"
-)
-
-func TestSyncgroupDiscovery(t *testing.T) {
- _, ctx, sName, rootp, cleanup := tu.SetupOrDieCustom("o:app1:client1", "server",
- tu.DefaultPerms(access.AllTypicalTags(), "root:o:app1:client1"))
- defer cleanup()
- d := tu.CreateDatabase(t, ctx, syncbase.NewService(sName), "d")
- collection1 := tu.CreateCollection(t, ctx, d, "c1")
- collection2 := tu.CreateCollection(t, ctx, d, "c2")
-
- c1Updates, err := scanAs(ctx, rootp, "o:app1:client1")
- if err != nil {
- panic(err)
- }
- c2Updates, err := scanAs(ctx, rootp, "o:app1:client2")
- if err != nil {
- panic(err)
- }
-
- sgId := d.Syncgroup(ctx, "sg1").Id()
- spec := wire.SyncgroupSpec{
- Description: "test syncgroup sg1",
- Perms: tu.DefaultPerms(wire.AllSyncgroupTags, "root:server", "root:o:app1:client1"),
- Collections: []wire.Id{collection1.Id()},
- }
- createSyncgroup(t, ctx, d, sgId, spec, verror.ID(""))
-
- // First update is for syncbase, and not a specific syncgroup.
- u := <-c1Updates
- attrs := u.Advertisement().Attributes
- peer := attrs[wire.DiscoveryAttrPeer]
- if peer == "" || len(attrs) != 1 {
- t.Errorf("Got %v, expected only a peer name.", attrs)
- }
- // Client2 should see the same.
- if err := expect(c2Updates, &discovery.AdId{}, find, discovery.Attributes{wire.DiscoveryAttrPeer: peer}); err != nil {
- t.Error(err)
- }
-
- sg1Attrs := discovery.Attributes{
- wire.DiscoveryAttrDatabaseName: "d",
- wire.DiscoveryAttrDatabaseBlessing: "root:o:app1",
- wire.DiscoveryAttrSyncgroupName: "sg1",
- wire.DiscoveryAttrSyncgroupBlessing: "root:o:app1:client1",
- }
- sg2Attrs := discovery.Attributes{
- wire.DiscoveryAttrDatabaseName: "d",
- wire.DiscoveryAttrDatabaseBlessing: "root:o:app1",
- wire.DiscoveryAttrSyncgroupName: "sg2",
- wire.DiscoveryAttrSyncgroupBlessing: "root:o:app1:client1",
- }
-
- // Then we should see an update for the created syncgroup.
- var sg1AdId discovery.AdId
- if err := expect(c1Updates, &sg1AdId, find, sg1Attrs); err != nil {
- t.Error(err)
- }
-
- // Now update the spec to add client2 to the permissions.
- spec.Perms = tu.DefaultPerms(wire.AllSyncgroupTags, "root:server", "root:o:app1:client1", "root:o:app1:client2")
- if err := d.SyncgroupForId(sgId).SetSpec(ctx, spec, ""); err != nil {
- t.Fatalf("sg.SetSpec failed: %v", err)
- }
-
- // Client1 should see a lost and a found message.
- if err := expect(c1Updates, &sg1AdId, both, sg1Attrs); err != nil {
- t.Error(err)
- }
- // Client2 should just now see the found message.
- if err := expect(c2Updates, &sg1AdId, find, sg1Attrs); err != nil {
- t.Error(err)
- }
-
- // Now create a second syncgroup.
- sg2Id := d.Syncgroup(ctx, "sg2").Id()
- spec2 := wire.SyncgroupSpec{
- Description: "test syncgroup sg2",
- Perms: tu.DefaultPerms(wire.AllSyncgroupTags, "root:server", "root:o:app1:client1", "root:o:app1:client2"),
- Collections: []wire.Id{collection2.Id()},
- }
- createSyncgroup(t, ctx, d, sg2Id, spec2, verror.ID(""))
-
- // Both clients should see the new syncgroup.
- var sg2AdId discovery.AdId
- if err := expect(c1Updates, &sg2AdId, find, sg2Attrs); err != nil {
- t.Error(err)
- }
- if err := expect(c2Updates, &sg2AdId, find, sg2Attrs); err != nil {
- t.Error(err)
- }
-
- spec2.Perms = tu.DefaultPerms(wire.AllSyncgroupTags, "root:server", "root:o:app1:client1")
- if err := d.SyncgroupForId(sg2Id).SetSpec(ctx, spec2, ""); err != nil {
- t.Fatalf("sg.SetSpec failed: %v", err)
- }
- if err := expect(c2Updates, &sg2AdId, lose, sg2Attrs); err != nil {
- t.Error(err)
- }
-}
-
-func scanAs(ctx *context.T, rootp security.Principal, as string) (<-chan discovery.Update, error) {
- idp := testutil.IDProviderFromPrincipal(rootp)
- p := testutil.NewPrincipal()
- if err := idp.Bless(p, as); err != nil {
- return nil, err
- }
- ctx, err := v23.WithPrincipal(ctx, p)
- if err != nil {
- return nil, err
- }
- dis, err := syncbase.NewDiscovery(ctx)
- if err != nil {
- return nil, err
- }
- return dis.Scan(ctx, `v.InterfaceName="v.io/x/ref/services/syncbase/server/interfaces/Sync"`)
-}
-
-const (
- lose = "lose"
- find = "find"
- both = "both"
-)
-
-func expect(ch <-chan discovery.Update, id *discovery.AdId, typ string, want discovery.Attributes) error {
- select {
- case u := <-ch:
- if (u.IsLost() && typ == find) || (!u.IsLost() && typ == lose) {
- return fmt.Errorf("IsLost mismatch. Got %v, wanted %v", u, typ)
- }
- ad := u.Advertisement()
- got := ad.Attributes
- if id.IsValid() {
- if *id != ad.Id {
- return fmt.Errorf("mismatched id, got %v, want %v", ad.Id, id)
- }
- } else {
- *id = ad.Id
- }
- if !reflect.DeepEqual(got, want) {
- return fmt.Errorf("got %v, want %v", got, want)
- }
- if typ == both {
- typ = lose
- if u.IsLost() {
- typ = find
- }
- return expect(ch, id, typ, want)
- }
- return nil
- case <-time.After(2 * time.Second):
- return fmt.Errorf("timed out")
- }
-}