namespace: Resolve goes all the way while ShallowResolve is the old behavior.
MultiPart: 1/4
Change-Id: I3f03f7f76c6a695d40201b74ba2b8d4400911bd7
diff --git a/cmd/namespace/doc.go b/cmd/namespace/doc.go
index 64a2ddb..a91480a 100644
--- a/cmd/namespace/doc.go
+++ b/cmd/namespace/doc.go
@@ -128,6 +128,8 @@
-insecure=false
Insecure mode: May return results from untrusted servers and invoke Resolve
on untrusted mounttables
+ -s=false
+ True to perform a shallow resolution
Namespace resolvetomt - Finds the address of the mounttable that holds an object name
diff --git a/cmd/namespace/impl.go b/cmd/namespace/impl.go
index 30eb4ec..b776ddf 100644
--- a/cmd/namespace/impl.go
+++ b/cmd/namespace/impl.go
@@ -40,11 +40,13 @@
flagInsecureResolve bool
flagInsecureResolveToMT bool
flagDeleteSubtree bool
+ flagShallowResolve bool
)
func init() {
cmdGlob.Flags.BoolVar(&flagLongGlob, "l", false, "Long listing format.")
cmdResolve.Flags.BoolVar(&flagInsecureResolve, "insecure", false, "Insecure mode: May return results from untrusted servers and invoke Resolve on untrusted mounttables")
+ cmdResolve.Flags.BoolVar(&flagShallowResolve, "s", false, "True to perform a shallow resolution")
cmdResolveToMT.Flags.BoolVar(&flagInsecureResolveToMT, "insecure", false, "Insecure mode: May return results from untrusted servers and invoke Resolve on untrusted mounttables")
cmdDelete.Flags.BoolVar(&flagDeleteSubtree, "r", false, "Delete all children of the name in addition to the name itself.")
}
@@ -213,7 +215,13 @@
if flagInsecureResolve {
opts = append(opts, options.NameResolutionAuthorizer{security.AllowEveryone()})
}
- me, err := ns.Resolve(ctx, name, opts...)
+ var err error
+ var me *naming.MountEntry
+ if flagShallowResolve {
+ me, err = ns.ShallowResolve(ctx, name, opts...)
+ } else {
+ me, err = ns.Resolve(ctx, name, opts...)
+ }
if err != nil {
ctx.Infof("ns.Resolve(%q) failed: %v", name, err)
return err
diff --git a/cmd/vrpc/vrpc.go b/cmd/vrpc/vrpc.go
index af9538b..774cfd3 100644
--- a/cmd/vrpc/vrpc.go
+++ b/cmd/vrpc/vrpc.go
@@ -139,6 +139,16 @@
ArgsLong: serverDesc,
}
+func getNamespaceOpts(opts []rpc.CallOpt) []naming.NamespaceOpt {
+ var out []naming.NamespaceOpt
+ for _, o := range opts {
+ if co, ok := o.(naming.NamespaceOpt); ok {
+ out = append(out, co)
+ }
+ }
+ return out
+}
+
func runSignature(ctx *context.T, env *cmdline.Env, args []string) error {
// Error-check args.
var server, method string
@@ -159,6 +169,14 @@
if flagInsecure {
opts = append(opts, insecureOpts...)
}
+ if flagShallowResolve {
+ // Find the containing mount table.
+ me, err := v23.GetNamespace(ctx).ShallowResolve(ctx, server, getNamespaceOpts(opts)...)
+ if err != nil {
+ return err
+ }
+ opts = append(opts, options.Preresolved{me})
+ }
if method != "" {
methodSig, err := reserved.MethodSignature(ctx, server, method, opts...)
if err != nil {
diff --git a/cmd/vrpc/vrpc_test.go b/cmd/vrpc/vrpc_test.go
index f004bb9..7cb9f94 100644
--- a/cmd/vrpc/vrpc_test.go
+++ b/cmd/vrpc/vrpc_test.go
@@ -131,7 +131,7 @@
defer shutdown()
var stdout, stderr bytes.Buffer
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
- args := []string{"signature", fmt.Sprintf("-show-reserved=%v", showReserved), name}
+ args := []string{"signature", "-s", fmt.Sprintf("-show-reserved=%v", showReserved), name}
if err := v23cmd.ParseAndRunForTest(cmdVRPC, ctx, env, args); err != nil {
t.Fatalf("%s: %v", args, err)
}
diff --git a/runtime/internal/naming/endpoint.go b/runtime/internal/naming/endpoint.go
index 382de34..aa9a66e 100644
--- a/runtime/internal/naming/endpoint.go
+++ b/runtime/internal/naming/endpoint.go
@@ -47,9 +47,6 @@
func NewEndpoint(input string) (*Endpoint, error) {
ep := new(Endpoint)
- // We have to guess this is a mount table if we don't know.
- ep.IsMountTable = true
-
// If the endpoint does not end in a @, it must be in [blessing@]host:port format.
if parts := hostportEP.FindStringSubmatch(input); len(parts) > 0 {
hostport := parts[len(parts)-1]
@@ -60,6 +57,7 @@
err := ep.parseHostPort(blessing, hostport)
return ep, err
}
+
// Trim the prefix and suffix and parse the rest.
input = strings.TrimPrefix(strings.TrimSuffix(input, suffix), separator)
parts := strings.Split(input, separator)
@@ -82,6 +80,11 @@
if _, _, err := net.SplitHostPort(hostport); err != nil {
return errInvalidEndpointString
}
+ if strings.HasSuffix(hostport, "#") {
+ hostport = strings.TrimSuffix(hostport, "#")
+ } else {
+ ep.IsMountTable = true
+ }
ep.Protocol = naming.UnknownProtocol
ep.Address = hostport
ep.RID = naming.NullRoutingID
diff --git a/runtime/internal/naming/namespace/all_test.go b/runtime/internal/naming/namespace/all_test.go
index 6c93b0c..1baed6a 100644
--- a/runtime/internal/naming/namespace/all_test.go
+++ b/runtime/internal/naming/namespace/all_test.go
@@ -31,9 +31,9 @@
func resolveWithRetry(ctx *context.T, name string, opts ...naming.NamespaceOpt) *naming.MountEntry {
ns := v23.GetNamespace(ctx)
for {
- mp, err := ns.Resolve(ctx, name, opts...)
+ me, err := ns.ShallowResolve(ctx, name, opts...)
if err == nil {
- return mp
+ return me
}
time.Sleep(100 * time.Millisecond)
}
@@ -189,7 +189,7 @@
}
func testResolve(t *testing.T, ctx *context.T, ns namespace.T, name string, want ...string) {
- doResolveTest(t, "Resolve", ns.Resolve, ctx, name, want)
+ doResolveTest(t, "Resolve", ns.ShallowResolve, ctx, name, want)
}
type serverEntry struct {
@@ -219,7 +219,9 @@
eps := s.Status().Endpoints
t.Logf("server %q -> %s", eps[0].Name(), mountPoint)
// Wait until the mount point appears in the mount table.
- resolveWithRetry(ctx, mountPoint)
+ if len(mountPoint) > 0 {
+ resolveWithRetry(ctx, mountPoint)
+ }
return &serverEntry{mountPoint: mountPoint, stop: s.Stop, endpoint: eps[0], name: eps[0].Name()}
}
@@ -672,14 +674,15 @@
// (which has different blessings)
hproot := fmt.Sprintf("(otherroot)@%v", rootmt.endpoint.Addr())
eproot := naming.FormatEndpoint(rootmt.endpoint.Addr().Network(), rootmt.endpoint.Addr().String(), rootmt.endpoint.RoutingID(), naming.BlessingOpt("otherroot"), naming.ServesMountTable(rootmt.endpoint.ServesMountTable()))
+ ns := v23.GetNamespace(ctx)
for _, root := range []string{hproot, eproot} {
name := naming.JoinAddressName(root, "mt")
- // Rooted name resolutions should fail authorization because of the "otherrot"
- if e, err := clientNs.Resolve(clientCtx, name); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
+ // Rooted name resolutions should fail authorization because of the "otherroot"
+ if e, err := ns.ShallowResolve(clientCtx, name); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
t.Errorf("resolve(%q) returned (%v, errorid=%v %v), wanted errorid=%v", name, e, verror.ErrorID(err), err, verror.ErrNotTrusted.ID)
}
// But not fail if the server authorization is skipped.
- if e, err := clientNs.Resolve(clientCtx, name, options.NameResolutionAuthorizer{security.AllowEveryone()}); err != nil {
+ if e, err := ns.ShallowResolve(clientCtx, name, options.NameResolutionAuthorizer{security.AllowEveryone()}); err != nil {
t.Errorf("resolve(%q): Got (%v, %v), expected resolution to succeed", name, e, err)
}
diff --git a/runtime/internal/naming/namespace/resolve.go b/runtime/internal/naming/namespace/resolve.go
index 4b0dfc7..2a0825d 100644
--- a/runtime/internal/naming/namespace/resolve.go
+++ b/runtime/internal/naming/namespace/resolve.go
@@ -96,6 +96,7 @@
// Resolve implements v.io/v23/naming.Namespace.
func (ns *namespace) Resolve(ctx *context.T, name string, opts ...naming.NamespaceOpt) (*naming.MountEntry, error) {
defer apilog.LogCallf(ctx, "name=%.10s...,opts...=%v", name, opts)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
+
// If caller supplied a mount entry, use it.
e, skipResolution := preresolved(opts)
if e != nil {
@@ -123,7 +124,7 @@
if ctx.V(2) {
ctx.Infof("Resolve(%s) loop %v", name, *e)
}
- if !e.ServesMountTable || terminal(e) {
+ if !e.ServesMountTable {
if ctx.V(1) {
ctx.Infof("Resolve(%s) -> %v", name, *e)
}
@@ -148,6 +149,26 @@
return nil, verror.New(naming.ErrResolutionDepthExceeded, ctx)
}
+// ShallowResolve implements v.io/v23/naming.Namespace.
+func (ns *namespace) ShallowResolve(ctx *context.T, name string, opts ...naming.NamespaceOpt) (*naming.MountEntry, error) {
+ defer apilog.LogCallf(ctx, "name=%.10s...,opts...=%v", name, opts)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
+
+ // Find the containing mount table.
+ me, err := ns.ResolveToMountTable(ctx, name, opts...)
+ if err != nil {
+ return nil, err
+ }
+ if terminal(me) {
+ return me, nil
+ }
+
+ // Resolve the entry directly.
+ client := v23.GetClient(ctx)
+ entry := new(naming.MountEntry)
+ err = client.Call(ctx, name, "ResolveStep", nil, []interface{}{entry}, append(getCallOpts(opts), options.Preresolved{me})...)
+ return entry, err
+}
+
// ResolveToMountTable implements v.io/v23/naming.Namespace.
func (ns *namespace) ResolveToMountTable(ctx *context.T, name string, opts ...naming.NamespaceOpt) (*naming.MountEntry, error) {
defer apilog.LogCallf(ctx, "name=%.10s...,opts...=%v", name, opts)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
diff --git a/runtime/internal/rpc/resolve_test.go b/runtime/internal/rpc/resolve_test.go
index e5b1e0a..feace08 100644
--- a/runtime/internal/rpc/resolve_test.go
+++ b/runtime/internal/rpc/resolve_test.go
@@ -76,7 +76,7 @@
ctx := sh.Ctx
ns := v23.GetNamespace(ctx)
- proxyEp, _ := inaming.NewEndpoint("proxy.v.io:123")
+ proxyEp, _ := inaming.NewEndpoint("proxy.v.io:123#")
proxyEpStr := proxyEp.String()
proxyAddr := naming.JoinAddressName(proxyEpStr, "")
if err := ns.Mount(ctx, "proxy", proxyAddr, time.Hour); err != nil {
@@ -94,7 +94,7 @@
result string
err error
}{
- {"/proxy.v.io:123", proxyEpStr, nil},
+ {"/proxy.v.io:123#", proxyEpStr, nil},
{"proxy.v.io:123", "", notfound},
{"proxy", proxyEpStr, nil},
{naming.JoinAddressName(ns.Roots()[0], "proxy"), proxyEpStr, nil},
diff --git a/runtime/internal/testing/mocks/naming/namespace.go b/runtime/internal/testing/mocks/naming/namespace.go
index fd0e407..a15e6d3 100644
--- a/runtime/internal/testing/mocks/naming/namespace.go
+++ b/runtime/internal/testing/mocks/naming/namespace.go
@@ -135,6 +135,10 @@
return nil, verror.New(naming.ErrNoSuchName, ctx, fmt.Sprintf("Resolve name %q not found in %v", name, ns.mounts))
}
+func (ns *namespaceMock) ShallowResolve(ctx *context.T, name string, opts ...naming.NamespaceOpt) (*naming.MountEntry, error) {
+ return ns.Resolve(ctx, name, opts...)
+}
+
func (ns *namespaceMock) ResolveToMountTable(ctx *context.T, name string, opts ...naming.NamespaceOpt) (*naming.MountEntry, error) {
defer apilog.LogCallf(ctx, "name=%.10s...,opts...=%v", name, opts)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
// TODO(mattr): Implement this method for tests that might need it.
diff --git a/services/device/mgmt_v23_test.go b/services/device/mgmt_v23_test.go
index f8821d2..85e3547 100644
--- a/services/device/mgmt_v23_test.go
+++ b/services/device/mgmt_v23_test.go
@@ -283,7 +283,7 @@
if err := testutil.RetryFor(10*time.Second, func() error {
// Set ExitErrorIsOk to true since we expect "namespace resolve" to fail
// if the name doesn't exist.
- c := withArgs(namespaceBin, "resolve", name)
+ c := withArgs(namespaceBin, "resolve", "-s", name)
c.ExitErrorIsOk = true
c.AddStderrWriter(os.Stderr)
if res = tr(c.Stdout()); len(res) > 0 {
@@ -475,7 +475,7 @@
if err := testutil.RetryFor(10*time.Second, func() error {
// Set ExitErrorIsOk to true since we expect "namespace resolve" to fail
// if the name doesn't exist.
- c := withArgs(namespaceBin, "resolve", name)
+ c := withArgs(namespaceBin, "resolve", "-s", name)
c.ExitErrorIsOk = true
c.AddStderrWriter(os.Stderr)
switch res = tr(c.Stdout()); {
@@ -518,7 +518,7 @@
resolve(mtEP + "/global")
namespaceRoot := sh.Vars[ref.EnvNamespacePrefix]
- output = withArgs(namespaceBin, "resolve", mtEP+"/global").Stdout()
+ output = withArgs(namespaceBin, "resolve", "-s", mtEP+"/global").Stdout()
if got, want := tr(output), namespaceRoot; got != want {
t.Fatalf("got %q, want %q", got, want)
}
@@ -537,7 +537,7 @@
if err := testutil.RetryFor(10*time.Second, func() error {
// Set ExitErrorIsOk to true since we expect "namespace resolve" to fail
// if the name doesn't exist.
- c := withArgs(namespaceBin, "resolve", name)
+ c := withArgs(namespaceBin, "resolve", "-s", name)
c.ExitErrorIsOk = true
c.AddStderrWriter(os.Stderr)
if res = tr(c.Stdout()); len(res) == 0 {
diff --git a/services/wspr/internal/namespace/namespace.vdl b/services/wspr/internal/namespace/namespace.vdl
index fba8427..0bc7e81 100644
--- a/services/wspr/internal/namespace/namespace.vdl
+++ b/services/wspr/internal/namespace/namespace.vdl
@@ -27,6 +27,12 @@
// ResolveToMountTable resolves a name to the address of the mounttable
// directly hosting it.
ResolveToMountTable(name string) ([]string | error)
+ // ShallowResolve resolves the object name into its mounted servers. It is the same
+ // as Resolve except when mounttables are stacked below the same mount point. For example,
+ // if service D is mounted onto /MTA/a/b and /MTA/a/b is mounted onto /MTB/x/y then
+ // Resolve(/MTB/x/y) will return a pointer to D while ShallowResolve(/MTB/x/y) will
+ // return a pointer to /MTA/a/b.
+ ShallowResolve(name string) ([]string | error)
// FlushCacheEntry removes the namespace cache entry for a given name.
FlushCacheEntry(name string) (bool | error)
// DisableCache disables the naming cache.
diff --git a/services/wspr/internal/namespace/namespace.vdl.go b/services/wspr/internal/namespace/namespace.vdl.go
index 3163740..8dbf960 100644
--- a/services/wspr/internal/namespace/namespace.vdl.go
+++ b/services/wspr/internal/namespace/namespace.vdl.go
@@ -39,6 +39,12 @@
// ResolveToMountTable resolves a name to the address of the mounttable
// directly hosting it.
ResolveToMountTable(_ *context.T, name string, _ ...rpc.CallOpt) ([]string, error)
+ // ShallowResolve resolves the object name into its mounted servers. It is the same
+ // as Resolve except when mounttables are stacked below the same mount point. For example,
+ // if service D is mounted onto /MTA/a/b and /MTA/a/b is mounted onto /MTB/x/y then
+ // Resolve(/MTB/x/y) will return a pointer to D while ShallowResolve(/MTB/x/y) will
+ // return a pointer to /MTA/a/b.
+ ShallowResolve(_ *context.T, name string, _ ...rpc.CallOpt) ([]string, error)
// FlushCacheEntry removes the namespace cache entry for a given name.
FlushCacheEntry(_ *context.T, name string, _ ...rpc.CallOpt) (bool, error)
// DisableCache disables the naming cache.
@@ -99,6 +105,11 @@
return
}
+func (c implNamespaceClientStub) ShallowResolve(ctx *context.T, i0 string, opts ...rpc.CallOpt) (o0 []string, err error) {
+ err = v23.GetClient(ctx).Call(ctx, c.name, "ShallowResolve", []interface{}{i0}, []interface{}{&o0}, opts...)
+ return
+}
+
func (c implNamespaceClientStub) FlushCacheEntry(ctx *context.T, i0 string, opts ...rpc.CallOpt) (o0 bool, err error) {
err = v23.GetClient(ctx).Call(ctx, c.name, "FlushCacheEntry", []interface{}{i0}, []interface{}{&o0}, opts...)
return
@@ -216,6 +227,12 @@
// ResolveToMountTable resolves a name to the address of the mounttable
// directly hosting it.
ResolveToMountTable(_ *context.T, _ rpc.ServerCall, name string) ([]string, error)
+ // ShallowResolve resolves the object name into its mounted servers. It is the same
+ // as Resolve except when mounttables are stacked below the same mount point. For example,
+ // if service D is mounted onto /MTA/a/b and /MTA/a/b is mounted onto /MTB/x/y then
+ // Resolve(/MTB/x/y) will return a pointer to D while ShallowResolve(/MTB/x/y) will
+ // return a pointer to /MTA/a/b.
+ ShallowResolve(_ *context.T, _ rpc.ServerCall, name string) ([]string, error)
// FlushCacheEntry removes the namespace cache entry for a given name.
FlushCacheEntry(_ *context.T, _ rpc.ServerCall, name string) (bool, error)
// DisableCache disables the naming cache.
@@ -248,6 +265,12 @@
// ResolveToMountTable resolves a name to the address of the mounttable
// directly hosting it.
ResolveToMountTable(_ *context.T, _ rpc.ServerCall, name string) ([]string, error)
+ // ShallowResolve resolves the object name into its mounted servers. It is the same
+ // as Resolve except when mounttables are stacked below the same mount point. For example,
+ // if service D is mounted onto /MTA/a/b and /MTA/a/b is mounted onto /MTB/x/y then
+ // Resolve(/MTB/x/y) will return a pointer to D while ShallowResolve(/MTB/x/y) will
+ // return a pointer to /MTA/a/b.
+ ShallowResolve(_ *context.T, _ rpc.ServerCall, name string) ([]string, error)
// FlushCacheEntry removes the namespace cache entry for a given name.
FlushCacheEntry(_ *context.T, _ rpc.ServerCall, name string) (bool, error)
// DisableCache disables the naming cache.
@@ -313,6 +336,10 @@
return s.impl.ResolveToMountTable(ctx, call, i0)
}
+func (s implNamespaceServerStub) ShallowResolve(ctx *context.T, call rpc.ServerCall, i0 string) ([]string, error) {
+ return s.impl.ShallowResolve(ctx, call, i0)
+}
+
func (s implNamespaceServerStub) FlushCacheEntry(ctx *context.T, call rpc.ServerCall, i0 string) (bool, error) {
return s.impl.FlushCacheEntry(ctx, call, i0)
}
@@ -403,6 +430,16 @@
},
},
{
+ Name: "ShallowResolve",
+ Doc: "// ShallowResolve resolves the object name into its mounted servers. It is the same\n// as Resolve except when mounttables are stacked below the same mount point. For example,\n// if service D is mounted onto /MTA/a/b and /MTA/a/b is mounted onto /MTB/x/y then\n// Resolve(/MTB/x/y) will return a pointer to D while ShallowResolve(/MTB/x/y) will\n// return a pointer to /MTA/a/b.",
+ InArgs: []rpc.ArgDesc{
+ {"name", ``}, // string
+ },
+ OutArgs: []rpc.ArgDesc{
+ {"", ``}, // []string
+ },
+ },
+ {
Name: "FlushCacheEntry",
Doc: "// FlushCacheEntry removes the namespace cache entry for a given name.",
InArgs: []rpc.ArgDesc{
diff --git a/services/wspr/internal/namespace/request_handler.go b/services/wspr/internal/namespace/request_handler.go
index c262a50..2fbf221 100644
--- a/services/wspr/internal/namespace/request_handler.go
+++ b/services/wspr/internal/namespace/request_handler.go
@@ -62,6 +62,14 @@
return me.Names(), nil
}
+func (s *Server) ShallowResolve(ctx *context.T, _ rpc.ServerCall, name string) ([]string, error) {
+ me, err := s.ns.ShallowResolve(ctx, name)
+ if err != nil {
+ return nil, verror.Convert(verror.ErrInternal, ctx, err)
+ }
+ return me.Names(), nil
+}
+
func (s *Server) ResolveToMountTable(ctx *context.T, _ rpc.ServerCall, name string) ([]string, error) {
me, err := s.ns.ResolveToMountTable(ctx, name)
if err != nil {