runtimes/google/naming/namespace: Move parsing server blessing patterns from StartCall into ResolveX.
Also stop parsing the root mounttable blessing pattern, which we're getting rid.
Change-Id: Ic0ade79c5f62977a3016292d62b7d26bc480db16
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 064f282..544ed1c 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -6,7 +6,6 @@
"math"
"math/rand"
"net"
- "regexp"
"strings"
"sync"
"time"
@@ -86,8 +85,6 @@
errBlessingAdd = verror.Register(pkgPath+".blessingAddFailed", verror.NoRetry, "failed to add blessing granted to server {3}{:4}")
)
-var serverPatternRegexp = regexp.MustCompile("^\\[([^\\]]+)\\](.*)")
-
// TODO(ribrdb): Flip this to true once everything is updated.
const enableSecureServerAuth = false
@@ -366,41 +363,42 @@
// tryCall makes a single attempt at a call, against possibly multiple servers.
func (c *client) tryCall(ctx context.T, name, method string, args []interface{}, skipResolve bool, opts []ipc.CallOpt) (ipc.Call, verror.ActionCode, verror.E) {
- mtPattern, serverPattern, name := splitObjectName(name)
noDischarges := shouldNotFetchDischarges(opts)
// Resolve name unless told not to.
var servers []string
+ var pattern security.BlessingPattern
+ var resolveOpts []naming.ResolveOpt
if skipResolve {
- servers = []string{name}
+ resolveOpts = append(resolveOpts, naming.SkipResolveOpt{})
+ } else if noDischarges {
+ resolveOpts = append(resolveOpts, vc.NoDischarges{})
+ }
+
+ if resolved, err := c.ns.ResolveX(ctx, name, resolveOpts...); err != nil {
+ vlog.Errorf("ResolveX: %v", err)
+ if verror.Is(err, naming.ErrNoSuchName.ID) {
+ return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name)
+ }
+ return nil, verror.NoRetry, verror.Make(verror.NoExist, ctx, name, err)
} else {
- resolveOpts := []naming.ResolveOpt{naming.RootBlessingPatternOpt(mtPattern)}
- if noDischarges {
- resolveOpts = append(resolveOpts, vc.NoDischarges{})
+ pattern = security.BlessingPattern(resolved.Pattern)
+ if len(resolved.Servers) == 0 {
+ return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name)
}
- if resolved, err := c.ns.Resolve(ctx, name, resolveOpts...); err != nil {
- if verror.Is(err, naming.ErrNoSuchName.ID) {
- return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name)
+ // An empty set of protocols means all protocols...
+ ordered, err := filterAndOrderServers(naming.ToStringSlice(resolved), c.preferredProtocols)
+ if err != nil {
+ return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name, err)
+ } else if len(ordered) == 0 {
+ // sooo annoying....
+ r := []interface{}{err}
+ r = append(r, name)
+ for _, s := range resolved.Servers {
+ r = append(r, s)
}
- return nil, verror.NoRetry, verror.Make(verror.NoExist, ctx, name, err)
- } else {
- if len(resolved) == 0 {
- return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name)
- }
- // An empty set of protocols means all protocols...
- ordered, err := filterAndOrderServers(resolved, c.preferredProtocols)
- if err != nil {
- return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name, err)
- } else if len(ordered) == 0 {
- // sooo annoying....
- r := []interface{}{err}
- r = append(r, name)
- for _, s := range resolved {
- r = append(r, s)
- }
- return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, r)
- }
- servers = ordered
+ return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, r)
}
+ servers = ordered
}
// servers is now orderd by the priority heurestic implemented in
@@ -469,7 +467,7 @@
if r.flow.LocalPrincipal() != nil {
// Validate caveats on the server's identity for the context associated with this call.
var err error
- if serverB, grantedB, err = c.authorizeServer(ctx, r.flow, name, method, serverPattern, opts); err != nil {
+ if serverB, grantedB, err = c.authorizeServer(ctx, r.flow, name, method, pattern, opts); err != nil {
r.err = verror.Make(errNotTrusted, ctx,
name, r.flow.RemoteBlessings(), err)
vlog.VI(2).Infof("ipc: err: %s", r.err)
@@ -915,28 +913,3 @@
func (fc *flowClient) RemoteBlessings() ([]string, security.Blessings) {
return fc.server, fc.flow.RemoteBlessings()
}
-
-func splitObjectName(name string) (mtPattern, serverPattern security.BlessingPattern, objectName string) {
- objectName = name
- match := serverPatternRegexp.FindSubmatch([]byte(name))
- if match != nil {
- objectName = string(match[2])
- if naming.Rooted(objectName) {
- mtPattern = security.BlessingPattern(match[1])
- } else {
- serverPattern = security.BlessingPattern(match[1])
- return
- }
- }
- if !naming.Rooted(objectName) {
- return
- }
-
- address, relative := naming.SplitAddressName(objectName)
- match = serverPatternRegexp.FindSubmatch([]byte(relative))
- if match != nil {
- serverPattern = security.BlessingPattern(match[1])
- objectName = naming.JoinAddressName(address, string(match[2]))
- }
- return
-}
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index c796e26..e7a680c 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -1322,44 +1322,6 @@
}
}
-func TestSplitObjectName(t *testing.T) {
- cases := []struct {
- input, mt, server, name string
- }{
- {"[foo/bar]", "", "foo/bar", ""},
- {"[x/y/...]/", "x/y/...", "", "/"},
- {"[foo]a", "", "foo", "a"},
- {"[foo]/a", "foo", "", "/a"},
- {"[foo]/a/[bar]", "foo", "bar", "/a"},
- {"a/b", "", "", "a/b"},
- {"[foo]a/b", "", "foo", "a/b"},
- {"/a/b", "", "", "/a/b"},
- {"[foo]/a/b", "foo", "", "/a/b"},
- {"/a/[bar]b", "", "bar", "/a/b"},
- {"[foo]/a/[bar]b", "foo", "bar", "/a/b"},
- {"/a/b[foo]", "", "", "/a/b[foo]"},
- {"/a/b/[foo]c", "", "", "/a/b/[foo]c"},
- {"/[01:02::]:444", "", "", "/[01:02::]:444"},
- {"[foo]/[01:02::]:444", "foo", "", "/[01:02::]:444"},
- {"/[01:02::]:444/foo", "", "", "/[01:02::]:444/foo"},
- {"[a]/[01:02::]:444/foo", "a", "", "/[01:02::]:444/foo"},
- {"/[01:02::]:444/[b]foo", "", "b", "/[01:02::]:444/foo"},
- {"[c]/[01:02::]:444/[d]foo", "c", "d", "/[01:02::]:444/foo"},
- }
- for _, c := range cases {
- mt, server, name := splitObjectName(c.input)
- if string(mt) != c.mt {
- t.Errorf("%q: unexpected mt pattern: %q not %q", c.input, mt, c.mt)
- }
- if string(server) != c.server {
- t.Errorf("%q: unexpected server pattern: %q not %q", c.input, server, c.server)
- }
- if name != c.name {
- t.Errorf("%q: unexpected name: %q not %q", c.input, name, c.name)
- }
- }
-}
-
func TestServerBlessingsOpt(t *testing.T) {
var (
pserver = tsecurity.NewPrincipal("server")
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 1b6a66d..9a44ec4 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -145,10 +145,12 @@
}
var names []string
if s.ns != nil {
+ var entry *naming.MountEntry
var err error
- if names, err = s.ns.Resolve(s.ctx, address); err != nil {
+ if entry, err = s.ns.ResolveX(s.ctx, address); err != nil {
return "", err
}
+ names = naming.ToStringSlice(entry)
} else {
names = append(names, address)
}
diff --git a/runtimes/google/naming/namespace/all_test.go b/runtimes/google/naming/namespace/all_test.go
index 2bb395c..8c1bd07 100644
--- a/runtimes/google/naming/namespace/all_test.go
+++ b/runtimes/google/naming/namespace/all_test.go
@@ -665,7 +665,6 @@
name := naming.Join(root.name, mt2MP)
// First check with a non-matching blessing pattern.
- println("********")
_, err = ns.Resolve(r.NewContext(), name, naming.RootBlessingPatternOpt("root/foobar"))
if !verror.Is(err, verror.NotTrusted.ID) {
t.Errorf("Resolve expected NotTrusted error, got %v", err)
@@ -681,13 +680,4 @@
// After successful lookup it should be cached, so the pattern doesn't matter.
testResolveWithPattern(t, r, ns, name, naming.RootBlessingPatternOpt("root/foobar"), addWSName(mts[mt2MP].name)...)
-
- // Test calling a method.
- jokeName := naming.Join(root.name, mt4MP, j1MP)
- runServer(t, r, &dispatcher{}, naming.Join(mts["mt4"].name, j1MP))
- _, err = r.Client().StartCall(r.NewContext(), "[root/foobar]"+jokeName, "KnockKnock", nil)
- if err == nil {
- t.Errorf("StartCall expected NoAccess error, got %v", err)
- }
- knockKnock(t, r, "[root/server]"+jokeName)
}
diff --git a/runtimes/google/naming/namespace/glob_test.go b/runtimes/google/naming/namespace/glob_test.go
index 790b459..b85188e 100644
--- a/runtimes/google/naming/namespace/glob_test.go
+++ b/runtimes/google/naming/namespace/glob_test.go
@@ -25,3 +25,41 @@
}
}
}
+
+func TestSplitObjectName(t *testing.T) {
+ cases := []struct {
+ input, mt, server, name string
+ }{
+ {"[foo/bar]", "", "foo/bar", ""},
+ {"[x/y/...]/", "x/y/...", "", "/"},
+ {"[foo]a", "", "foo", "a"},
+ {"[foo]/a", "foo", "", "/a"},
+ {"[foo]/a/[bar]", "foo", "bar", "/a"},
+ {"a/b", "", "", "a/b"},
+ {"[foo]a/b", "", "foo", "a/b"},
+ {"/a/b", "", "", "/a/b"},
+ {"[foo]/a/b", "foo", "", "/a/b"},
+ {"/a/[bar]b", "", "bar", "/a/b"},
+ {"[foo]/a/[bar]b", "foo", "bar", "/a/b"},
+ {"/a/b[foo]", "", "", "/a/b[foo]"},
+ {"/a/b/[foo]c", "", "", "/a/b/[foo]c"},
+ {"/[01:02::]:444", "", "", "/[01:02::]:444"},
+ {"[foo]/[01:02::]:444", "foo", "", "/[01:02::]:444"},
+ {"/[01:02::]:444/foo", "", "", "/[01:02::]:444/foo"},
+ {"[a]/[01:02::]:444/foo", "a", "", "/[01:02::]:444/foo"},
+ {"/[01:02::]:444/[b]foo", "", "b", "/[01:02::]:444/foo"},
+ {"[c]/[01:02::]:444/[d]foo", "c", "d", "/[01:02::]:444/foo"},
+ }
+ for _, c := range cases {
+ mt, server, name := splitObjectName(c.input)
+ if string(mt) != c.mt {
+ t.Errorf("%q: unexpected mt pattern: %q not %q", c.input, mt, c.mt)
+ }
+ if string(server) != c.server {
+ t.Errorf("%q: unexpected server pattern: %q not %q", c.input, server, c.server)
+ }
+ if name != c.name {
+ t.Errorf("%q: unexpected name: %q not %q", c.input, name, c.name)
+ }
+ }
+}
diff --git a/runtimes/google/naming/namespace/namespace.go b/runtimes/google/naming/namespace/namespace.go
index 16ec70e..9ddc49d 100644
--- a/runtimes/google/naming/namespace/namespace.go
+++ b/runtimes/google/naming/namespace/namespace.go
@@ -1,12 +1,14 @@
package namespace
import (
+ "regexp"
"sync"
"time"
inaming "veyron.io/veyron/veyron/runtimes/google/naming"
"veyron.io/veyron/veyron2/naming"
+ "veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/verror"
"veyron.io/veyron/veyron2/vlog"
)
@@ -14,6 +16,8 @@
const defaultMaxResolveDepth = 32
const defaultMaxRecursiveGlobDepth = 10
+var serverPatternRegexp = regexp.MustCompile("^\\[([^\\]]+)\\](.*)")
+
// namespace is an implementation of naming.Namespace.
type namespace struct {
sync.RWMutex
@@ -111,7 +115,9 @@
// rootMountEntry 'roots' a name creating a mount entry for the name.
func (ns *namespace) rootMountEntry(name string) (*naming.MountEntry, bool) {
name = naming.Clean(name)
+ _, objPattern, name := splitObjectName(name)
e := new(naming.MountEntry)
+ e.Pattern = string(objPattern)
expiration := time.Now().Add(time.Hour) // plenty of time for a call
address, suffix := naming.SplitAddressName(name)
if len(address) == 0 {
@@ -181,3 +187,28 @@
}
return nil
}
+
+func splitObjectName(name string) (mtPattern, serverPattern security.BlessingPattern, objectName string) {
+ objectName = name
+ match := serverPatternRegexp.FindSubmatch([]byte(name))
+ if match != nil {
+ objectName = string(match[2])
+ if naming.Rooted(objectName) {
+ mtPattern = security.BlessingPattern(match[1])
+ } else {
+ serverPattern = security.BlessingPattern(match[1])
+ return
+ }
+ }
+ if !naming.Rooted(objectName) {
+ return
+ }
+
+ address, relative := naming.SplitAddressName(objectName)
+ match = serverPatternRegexp.FindSubmatch([]byte(relative))
+ if match != nil {
+ serverPattern = security.BlessingPattern(match[1])
+ objectName = naming.JoinAddressName(address, string(match[2]))
+ }
+ return
+}
diff --git a/runtimes/google/naming/namespace/resolve.go b/runtimes/google/naming/namespace/resolve.go
index e1c4109..aca359e 100644
--- a/runtimes/google/naming/namespace/resolve.go
+++ b/runtimes/google/naming/namespace/resolve.go
@@ -77,6 +77,9 @@
vlog.Infof("ResolveX(%s) called from %s:%d", name, file, line)
vlog.Infof("ResolveX(%s) -> rootMountEntry %v", name, *e)
}
+ if skipResolve(opts) {
+ return e, nil
+ }
if len(e.Servers) == 0 {
return nil, verror.Make(naming.ErrNoSuchName, ctx, name)
}
@@ -271,6 +274,15 @@
return flushed
}
+func skipResolve(opts []naming.ResolveOpt) bool {
+ for _, opt := range opts {
+ if _, ok := opt.(naming.SkipResolveOpt); ok {
+ return true
+ }
+ }
+ return false
+}
+
func getRootPattern(opts []naming.ResolveOpt) string {
for _, opt := range opts {
if pattern, ok := opt.(naming.RootBlessingPatternOpt); ok {
diff --git a/runtimes/google/testing/mocks/naming/namespace.go b/runtimes/google/testing/mocks/naming/namespace.go
index e3403e5..d6cdb35 100644
--- a/runtimes/google/testing/mocks/naming/namespace.go
+++ b/runtimes/google/testing/mocks/naming/namespace.go
@@ -10,19 +10,26 @@
"veyron.io/veyron/veyron2/naming"
verror "veyron.io/veyron/veyron2/verror2"
"veyron.io/veyron/veyron2/vlog"
+
+ vnamespace "veyron.io/veyron/veyron/runtimes/google/naming/namespace"
)
// NewSimpleNamespace returns a simple implementation of a Namespace
// server for use in tests. In particular, it ignores TTLs and not
// allow fully overlapping mount names.
func NewSimpleNamespace() naming.Namespace {
- return &namespace{mounts: make(map[string][]string)}
+ ns, err := vnamespace.New()
+ if err != nil {
+ panic(err)
+ }
+ return &namespace{mounts: make(map[string][]string), ns: ns}
}
// namespace is a simple partial implementation of naming.Namespace.
type namespace struct {
sync.Mutex
mounts map[string][]string
+ ns naming.Namespace
}
func (ns *namespace) Mount(ctx context.T, name, server string, _ time.Duration, _ ...naming.MountOpt) error {
@@ -79,13 +86,18 @@
func (ns *namespace) ResolveX(ctx context.T, name string, opts ...naming.ResolveOpt) (*naming.MountEntry, error) {
defer vlog.LogCall()()
- e := new(naming.MountEntry)
- if address, _ := naming.SplitAddressName(name); len(address) > 0 {
- e.Servers = []naming.MountedServer{naming.MountedServer{Server: name, Expires: time.Now().Add(1000 * time.Hour)}}
+ e, err := ns.ns.ResolveX(ctx, name, naming.SkipResolveOpt{})
+ if err != nil {
+ return e, err
+ }
+ if len(e.Servers) > 0 {
+ e.Servers[0].Server = naming.JoinAddressName(e.Servers[0].Server, e.Name)
+ e.Name = ""
return e, nil
}
ns.Lock()
defer ns.Unlock()
+ name = e.Name
for prefix, servers := range ns.mounts {
if strings.HasPrefix(name, prefix) {
e.Name = strings.TrimLeft(strings.TrimPrefix(name, prefix), "/")