Merge "veyron/services/mgmt/suidhelper/impl: chown, setuid"
diff --git a/lib/modules/core/mounttable.go b/lib/modules/core/mounttable.go
index 9326030..b0104d5 100644
--- a/lib/modules/core/mounttable.go
+++ b/lib/modules/core/mounttable.go
@@ -89,7 +89,7 @@
output += fmt.Sprintf("R%d=%s[", entry, n.Name)
t := ""
for _, s := range n.Servers {
- t += fmt.Sprintf("%s:%s, ", s.Server, s.TTL)
+ t += fmt.Sprintf("%s:%s, ", s.Server, s.Expires)
}
t = strings.TrimSuffix(t, ", ")
output += fmt.Sprintf("%s]\n", t)
diff --git a/profiles/internal/gce/gce_linux_android.go b/profiles/internal/gce/gce_linux_android.go
index eafa31c..24288f1 100644
--- a/profiles/internal/gce/gce_linux_android.go
+++ b/profiles/internal/gce/gce_linux_android.go
@@ -9,7 +9,7 @@
)
func RunningOnGCE() bool {
- panic("The GCE profile was unexpectedly used with android.")
+ return false
}
func ExternalIPAddress() (net.IP, error) {
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index dba781d..39e0649 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -318,9 +318,6 @@
ln.Close()
return nil, err
}
- if ipaddr == nil {
- vlog.VI(2).Infof("the address %q requested for listening contained a fixed IP address which disables roaming, use :0 instead", address)
- }
s.Lock()
if s.stopped {
@@ -330,9 +327,14 @@
return nil, errServerStopped
}
- h, _, _ := net.SplitHostPort(address)
+ var ip net.IP
+ if ipaddr != nil {
+ ip = net.ParseIP(ipaddr.String())
+ } else {
+ vlog.VI(2).Infof("the address %q requested for listening contained a fixed IP address which disables roaming, use :0 instead", address)
+ }
publisher := listenSpec.StreamPublisher
- if ip := net.ParseIP(h); ip != nil && ip.IsLoopback() && publisher != nil {
+ if ip != nil && !ip.IsLoopback() && publisher != nil {
streamName := listenSpec.StreamName
ch := make(chan config.Setting)
_, err := publisher.ForkStream(streamName, ch)
diff --git a/runtimes/google/lib/publisher/publisher.go b/runtimes/google/lib/publisher/publisher.go
index 83468e2..f7e474a 100644
--- a/runtimes/google/lib/publisher/publisher.go
+++ b/runtimes/google/lib/publisher/publisher.go
@@ -313,17 +313,17 @@
func (ps *pubState) published() []string {
var ret []string
for _, name := range ps.names {
- mtServers, err := ps.ns.ResolveToMountTable(ps.ctx, name)
+ e, err := ps.ns.ResolveToMountTableX(ps.ctx, name)
if err != nil {
vlog.Errorf("ipc pub: couldn't resolve %v to mount table: %v", name, err)
continue
}
- if len(mtServers) == 0 {
+ if len(e.Servers) == 0 {
vlog.Errorf("ipc pub: no mount table found for %v", name)
continue
}
- for _, s := range mtServers {
- ret = append(ret, naming.MakeResolvable(s))
+ for _, s := range e.Servers {
+ ret = append(ret, naming.JoinAddressName(s.Server, e.Name))
}
}
return ret
diff --git a/runtimes/google/naming/namespace/all_test.go b/runtimes/google/naming/namespace/all_test.go
index ad6a9b0..9c29b25 100644
--- a/runtimes/google/naming/namespace/all_test.go
+++ b/runtimes/google/naming/namespace/all_test.go
@@ -143,7 +143,7 @@
if err != nil {
boom(t, "Failed to ResolveToMountTable %q: %s", name, err)
}
- compare(t, "ResolveToMoutTable", name, servers, want)
+ compare(t, "ResolveToMountTable", name, servers, want)
}
func testResolve(t *testing.T, r veyron2.Runtime, ns naming.Namespace, name string, want ...string) {
diff --git a/runtimes/google/naming/namespace/cache.go b/runtimes/google/naming/namespace/cache.go
index 4686928..01b704e 100644
--- a/runtimes/google/naming/namespace/cache.go
+++ b/runtimes/google/naming/namespace/cache.go
@@ -19,26 +19,25 @@
// cache is a generic interface to the resolution cache.
type cache interface {
- remember(prefix string, servers []mountedServer)
+ remember(prefix string, entry *naming.MountEntry)
forget(names []string)
- lookup(name string) ([]mountedServer, string)
+ lookup(name string) (naming.MountEntry, error)
}
// ttlCache is an instance of cache that obeys ttl from the mount points.
type ttlCache struct {
sync.Mutex
- epochStart time.Time
- entries map[string][]mountedServer
+ entries map[string]naming.MountEntry
}
// newTTLCache creates an empty ttlCache.
func newTTLCache() cache {
- return &ttlCache{epochStart: time.Now(), entries: make(map[string][]mountedServer)}
+ return &ttlCache{entries: make(map[string]naming.MountEntry)}
}
-func isStale(now uint32, servers []mountedServer) bool {
- for _, s := range servers {
- if s.TTL <= now {
+func isStale(now time.Time, e naming.MountEntry) bool {
+ for _, s := range e.Servers {
+ if s.Expires.Before(now) {
return true
}
}
@@ -54,11 +53,6 @@
return strings.TrimSuffix(name, "/")
}
-// esecs returns seconds since start of this cache's epoch.
-func (c *ttlCache) esecs() uint32 {
- return uint32(time.Since(c.epochStart).Seconds())
-}
-
// randomDrop randomly removes one cache entry. Assumes we've already locked the cache.
func (c *ttlCache) randomDrop() {
n := rand.Intn(len(c.entries))
@@ -74,7 +68,7 @@
// cleaner reduces the number of entries. Assumes we've already locked the cache.
func (c *ttlCache) cleaner() {
// First dump any stale entries.
- now := c.esecs()
+ now := time.Now()
for k, v := range c.entries {
if len(c.entries) < cacheHisteresisSize {
return
@@ -91,12 +85,19 @@
}
// remember the servers associated with name with suffix removed.
-func (c *ttlCache) remember(prefix string, servers []mountedServer) {
+func (c *ttlCache) remember(prefix string, entry *naming.MountEntry) {
+ // Remove suffix. We only care about the name that gets us
+ // to the mounttable from the last mounttable.
prefix = normalize(prefix)
- for i := range servers {
- // Remember when this cached entry times out relative to our epoch.
- servers[i].TTL += c.esecs()
+ prefix = naming.TrimSuffix(prefix, entry.Name)
+ // Copy the entry.
+ var ce naming.MountEntry
+ for _, s := range entry.Servers {
+ ce.Servers = append(ce.Servers, s)
}
+ ce.MT = entry.MT
+ // All keys must be terminal.
+ prefix = naming.MakeTerminal(prefix)
c.Lock()
// Enforce an upper limit on the cache size.
if len(c.entries) >= maxCacheEntries {
@@ -104,7 +105,7 @@
c.cleaner()
}
}
- c.entries[prefix] = servers
+ c.entries[prefix] = ce
c.Unlock()
}
@@ -125,25 +126,26 @@
}
// lookup searches the cache for a maximal prefix of name and returns the associated servers,
-// prefix, and suffix. If any of the associated servers is past its TTL, don't return anything
+// prefix, and suffix. If any of the associated servers is expired, don't return anything
// since that would reduce availability.
-func (c *ttlCache) lookup(name string) ([]mountedServer, string) {
+func (c *ttlCache) lookup(name string) (naming.MountEntry, error) {
name = normalize(name)
c.Lock()
defer c.Unlock()
- now := c.esecs()
+ now := time.Now()
for prefix, suffix := name, ""; len(prefix) > 0; prefix, suffix = backup(prefix, suffix) {
- servers, ok := c.entries[prefix]
+ e, ok := c.entries[prefix]
if !ok {
continue
}
- if isStale(now, servers) {
- return nil, ""
+ if isStale(now, e) {
+ return e, naming.ErrNoSuchName
}
- vlog.VI(2).Infof("namespace cache %s -> %v %s", name, servers, suffix)
- return servers, suffix
+ vlog.VI(2).Infof("namespace cache %s -> %v %s", name, e.Servers, e.Name)
+ e.Name = suffix
+ return e, nil
}
- return nil, ""
+ return naming.MountEntry{}, naming.ErrNoSuchName
}
// backup moves the last element of the prefix to the suffix. "//" is preserved. Thus
@@ -170,7 +172,7 @@
// nullCache is an instance of cache that does nothing.
type nullCache int
-func newNullCache() cache { return nullCache(1) }
-func (nullCache) remember(prefix string, servers []mountedServer) {}
-func (nullCache) forget(names []string) {}
-func (nullCache) lookup(name string) ([]mountedServer, string) { return nil, "" }
+func newNullCache() cache { return nullCache(1) }
+func (nullCache) remember(prefix string, entry *naming.MountEntry) {}
+func (nullCache) forget(names []string) {}
+func (nullCache) lookup(name string) (e naming.MountEntry, err error) { return e, naming.ErrNoSuchName }
diff --git a/runtimes/google/naming/namespace/cache_test.go b/runtimes/google/naming/namespace/cache_test.go
index e3908a5..d707509 100644
--- a/runtimes/google/naming/namespace/cache_test.go
+++ b/runtimes/google/naming/namespace/cache_test.go
@@ -3,17 +3,22 @@
import (
"fmt"
"testing"
+ "time"
"veyron.io/veyron/veyron2/naming"
)
-func compatible(server string, servers []mountedServer) bool {
+func compatible(server string, servers []naming.MountedServer) bool {
if len(servers) == 0 {
return server == ""
}
return servers[0].Server == server
}
+func future(secs uint32) time.Time {
+ return time.Now().Add(time.Duration(secs) * time.Second)
+}
+
// TestCache tests the cache directly rather than via the namespace methods.
func TestCache(t *testing.T) {
preload := []struct {
@@ -27,63 +32,69 @@
}
c := newTTLCache()
for _, p := range preload {
- c.remember(naming.TrimSuffix(p.name, p.suffix), []mountedServer{mountedServer{Server: p.server, TTL: 30}})
+ e := &naming.MountEntry{Name: p.suffix, Servers: []naming.MountedServer{naming.MountedServer{Server: p.server, Expires: future(30)}}}
+ c.remember(p.name, e)
}
tests := []struct {
- name string
- suffix string
- server string
+ name string
+ suffix string
+ server string
+ succeed bool
}{
- {"/h1//a/b/c/d", "c/d", "/h2"},
- {"/h2//c/d", "d", "/h3"},
- {"/h3//d", "", "/h4:1234"},
- {"/notintcache", "", ""},
- {"/h1//a/b/f//g", "f//g", "/h2"},
- {"/h3//d//e", "//e", "/h4:1234"},
+ {"/h1//a/b/c/d", "c/d", "/h2", true},
+ {"/h2//c/d", "d", "/h3", true},
+ {"/h3//d", "", "/h4:1234", true},
+ {"/notintcache", "", "", false},
+ {"/h1//a/b/f//g", "f//g", "/h2", true},
+ {"/h3//d//e", "//e", "/h4:1234", true},
}
for _, p := range tests {
- servers, suffix := c.lookup(p.name)
- if suffix != p.suffix || !compatible(p.server, servers) {
- t.Errorf("%s: unexpected depth: got %v, %s not %s, %s", p.name, servers, suffix, p.server, p.suffix)
+ e, err := c.lookup(p.name)
+ if (err == nil) != p.succeed {
+ t.Errorf("%s: lookup failed", p.name)
+ }
+ if e.Name != p.suffix || !compatible(p.server, e.Servers) {
+ t.Errorf("%s: got %v, %s not %s, %s", p.name, e.Name, e.Servers, p.suffix, p.server)
}
}
}
func TestCacheLimit(t *testing.T) {
c := newTTLCache().(*ttlCache)
- servers := []mountedServer{mountedServer{Server: "the rain in spain", TTL: 3000}}
+ e := &naming.MountEntry{Servers: []naming.MountedServer{naming.MountedServer{Server: "the rain in spain", Expires: future(3000)}}}
for i := 0; i < maxCacheEntries; i++ {
- c.remember(fmt.Sprintf("%d", i), servers)
+ c.remember(fmt.Sprintf("%d", i), e)
if len(c.entries) > maxCacheEntries {
t.Errorf("unexpected cache size: got %d not %d", len(c.entries), maxCacheEntries)
}
}
// Adding one more element should reduce us to 3/4 full.
- c.remember(fmt.Sprintf("%d", maxCacheEntries), servers)
+ c.remember(fmt.Sprintf("%d", maxCacheEntries), e)
if len(c.entries) != cacheHisteresisSize {
t.Errorf("cache shrunk wrong amount: got %d not %d", len(c.entries), cacheHisteresisSize)
}
}
func TestCacheTTL(t *testing.T) {
+ before := time.Now()
c := newTTLCache().(*ttlCache)
// Fill cache.
- servers := []mountedServer{mountedServer{Server: "the rain in spain", TTL: 3000}}
+ e := &naming.MountEntry{Servers: []naming.MountedServer{naming.MountedServer{Server: "the rain in spain", Expires: future(3000)}}}
for i := 0; i < maxCacheEntries; i++ {
- c.remember(fmt.Sprintf("%d", i), servers)
+ c.remember(fmt.Sprintf("%d", i), e)
}
// Time out half the entries.
i := len(c.entries) / 2
for k := range c.entries {
- c.entries[k][0].TTL = 0
+ c.entries[k].Servers[0].Expires = before
if i == 0 {
break
}
i--
}
// Add an entry and make sure we now have room.
- c.remember(fmt.Sprintf("%d", maxCacheEntries+2), servers)
+ c.remember(fmt.Sprintf("%d", maxCacheEntries+2), e)
if len(c.entries) > cacheHisteresisSize {
t.Errorf("entries did not timeout: got %d not %d", len(c.entries), cacheHisteresisSize)
}
@@ -101,7 +112,8 @@
ns, _ := New(nil)
c := ns.resolutionCache.(*ttlCache)
for _, p := range preload {
- c.remember(p.name, []mountedServer{mountedServer{Server: p.server, TTL: 3000}})
+ e := &naming.MountEntry{Servers: []naming.MountedServer{naming.MountedServer{Server: "p.server", Expires: future(3000)}}}
+ c.remember(p.name, e)
}
toflush := "/h1/xyzzy"
if ns.FlushCacheEntry(toflush) {
@@ -112,17 +124,17 @@
t.Errorf("%s should have caused something to flush", toflush)
}
name := preload[2].name
- if _, ok := c.entries[name]; ok {
- t.Errorf("%s should have been flushed", name)
+ if _, ok := c.entries[name]; !ok {
+ t.Errorf("%s should not have been flushed", name)
}
if len(c.entries) != 2 {
t.Errorf("%s flushed too many entries", toflush)
}
+ toflush = preload[1].name
if !ns.FlushCacheEntry(toflush) {
t.Errorf("%s should have caused something to flush", toflush)
}
- name = preload[1].name
- if _, ok := c.entries[name]; ok {
+ if _, ok := c.entries[toflush]; ok {
t.Errorf("%s should have been flushed", name)
}
if len(c.entries) != 1 {
@@ -146,8 +158,9 @@
name := "/h1//a"
serverName := "/h2//"
c := ns.resolutionCache.(*ttlCache)
- c.remember(name, []mountedServer{mountedServer{Server: serverName, TTL: 3000}})
- if servers, _ := c.lookup(name); servers == nil || servers[0].Server != serverName {
+ e := &naming.MountEntry{Servers: []naming.MountedServer{naming.MountedServer{Server: serverName, Expires: future(3000)}}}
+ c.remember(name, e)
+ if ne, err := c.lookup(name); err != nil || ne.Servers[0].Server != serverName {
t.Errorf("should have found the server in the cache")
}
@@ -157,8 +170,8 @@
t.Errorf("caching not disabled")
}
nc := ns.resolutionCache.(nullCache)
- nc.remember(name, []mountedServer{mountedServer{Server: serverName, TTL: 3000}})
- if servers, _ := nc.lookup(name); servers != nil {
+ nc.remember(name, e)
+ if _, err := nc.lookup(name); err == nil {
t.Errorf("should not have found the server in the cache")
}
@@ -168,8 +181,8 @@
t.Errorf("caching disabled")
}
c = ns.resolutionCache.(*ttlCache)
- c.remember(name, []mountedServer{mountedServer{Server: serverName, TTL: 3000}})
- if servers, _ := c.lookup(name); servers == nil || servers[0].Server != serverName {
+ c.remember(name, e)
+ if ne, err := c.lookup(name); err != nil || ne.Servers[0].Server != serverName {
t.Errorf("should have found the server in the cache")
}
}
diff --git a/runtimes/google/naming/namespace/glob.go b/runtimes/google/naming/namespace/glob.go
index 0992eaa..89fdfb1 100644
--- a/runtimes/google/naming/namespace/glob.go
+++ b/runtimes/google/naming/namespace/glob.go
@@ -4,12 +4,12 @@
"container/list"
"io"
"strings"
- "time"
"veyron.io/veyron/veyron/lib/glob"
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/naming"
+ "veyron.io/veyron/veyron2/services/mounttable/types"
"veyron.io/veyron/veyron2/vlog"
)
@@ -57,7 +57,7 @@
// At this point we're commited to a server since it answered tha call.
for {
- var e mountEntry
+ var e types.MountEntry
err := call.Recv(&e)
if err == io.EOF {
break
@@ -127,24 +127,6 @@
return reply, nil
}
-func convertStringsToServers(servers []string) (ret []naming.MountedServer) {
- for _, s := range servers {
- ret = append(ret, naming.MountedServer{Server: s})
- }
- return
-}
-
-// TODO(p): I may just give up and assume that these two will always be the same. For
-// now this lets me make the RPC interface and the model's MountTable structs be arbitrarily
-// different.
-func convertServers(servers []mountedServer) []naming.MountedServer {
- var reply []naming.MountedServer
- for _, s := range servers {
- reply = append(reply, naming.MountedServer{Server: s.Server, TTL: time.Duration(s.TTL) * time.Second})
- }
- return reply
-}
-
// depth returns the directory depth of a given name.
func depth(name string) int {
name = strings.Trim(name, "/")
diff --git a/runtimes/google/naming/namespace/mount.go b/runtimes/google/naming/namespace/mount.go
index 35d5c01..8339a8b 100644
--- a/runtimes/google/naming/namespace/mount.go
+++ b/runtimes/google/naming/namespace/mount.go
@@ -6,6 +6,7 @@
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/naming"
+ "veyron.io/veyron/veyron2/options"
"veyron.io/veyron/veyron2/services/mounttable/types"
"veyron.io/veyron/veyron2/vlog"
)
@@ -13,7 +14,7 @@
// mountIntoMountTable mounts a single server into a single mount table.
func mountIntoMountTable(ctx context.T, client ipc.Client, name, server string, ttl time.Duration, flags types.MountFlag) error {
ctx, _ = ctx.WithTimeout(callTimeout)
- call, err := client.StartCall(ctx, name, "Mount", []interface{}{server, uint32(ttl.Seconds()), flags})
+ call, err := client.StartCall(ctx, name, "Mount", []interface{}{server, uint32(ttl.Seconds()), flags}, options.NoResolve(true))
if err != nil {
return err
}
@@ -26,7 +27,7 @@
// unmountFromMountTable removes a single mounted server from a single mount table.
func unmountFromMountTable(ctx context.T, client ipc.Client, name, server string) error {
ctx, _ = ctx.WithTimeout(callTimeout)
- call, err := client.StartCall(ctx, name, "Unmount", []interface{}{server})
+ call, err := client.StartCall(ctx, name, "Unmount", []interface{}{server}, options.NoResolve(true))
if err != nil {
return err
}
diff --git a/runtimes/google/naming/namespace/namespace.go b/runtimes/google/naming/namespace/namespace.go
index 88855c0..5c2ceca 100644
--- a/runtimes/google/naming/namespace/namespace.go
+++ b/runtimes/google/naming/namespace/namespace.go
@@ -107,6 +107,32 @@
return []string{name}
}
+// rootMountEntry 'roots' a name creating a mount entry for the name.
+func (ns *namespace) rootMountEntry(name string) *naming.MountEntry {
+ e := new(naming.MountEntry)
+ expiration := time.Now().Add(time.Hour) // plenty of time for a call
+ address, suffix := naming.SplitAddressName(name)
+ if len(address) == 0 {
+ e.MT = true
+ e.Name = name
+ ns.RLock()
+ defer ns.RUnlock()
+ for _, r := range ns.roots {
+ e.Servers = append(e.Servers, naming.MountedServer{Server: r, Expires: expiration})
+ }
+ return e
+ }
+ // TODO(p): right now I assume any address handed to me to be resolved is a mount table.
+ // Eventually we should do something like the following:
+ // if ep, err := ns.rt.NewEndpoint(address); err == nil && ep.ServesMountTable() {
+ // e.MT = true
+ // }
+ e.MT = true
+ e.Name = suffix
+ e.Servers = append(e.Servers, naming.MountedServer{Server: address, Expires: expiration})
+ return e
+}
+
// notAnMT returns true if the error indicates this isn't a mounttable server.
func notAnMT(err error) bool {
switch verror.ErrorID(err) {
diff --git a/runtimes/google/naming/namespace/resolve.go b/runtimes/google/naming/namespace/resolve.go
index f246c06..b6a8315 100644
--- a/runtimes/google/naming/namespace/resolve.go
+++ b/runtimes/google/naming/namespace/resolve.go
@@ -7,40 +7,32 @@
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/naming"
+ "veyron.io/veyron/veyron2/options"
+ "veyron.io/veyron/veyron2/services/mounttable/types"
"veyron.io/veyron/veyron2/verror"
"veyron.io/veyron/veyron2/vlog"
)
-func convertServersToStrings(servers []mountedServer, suffix string) (ret []string) {
- for _, s := range servers {
- ret = append(ret, naming.Join(s.Server, suffix))
- }
- return
-}
-
-func (ns *namespace) resolveAgainstMountTable(ctx context.T, client ipc.Client, names []string) ([]string, error) {
+func (ns *namespace) resolveAgainstMountTable(ctx context.T, client ipc.Client, e *naming.MountEntry) (*naming.MountEntry, error) {
// Try each server till one answers.
finalErr := errors.New("no servers to resolve query")
- for _, name := range names {
- // We want to resolve the name against the MountTable specified in its
- // address, without recursing through ourselves. To this we force
- // the entire name component to be terminal.
- name = naming.MakeTerminal(name)
+ for _, s := range e.Servers {
+ name := naming.JoinAddressName(s.Server, e.Name)
// First check the cache.
- if servers, suffix := ns.resolutionCache.lookup(name); len(servers) > 0 {
- return convertServersToStrings(servers, suffix), nil
+ if ne, err := ns.resolutionCache.lookup(name); err == nil {
+ vlog.VI(2).Infof("resolveAMT %s from cache -> %v", name, convertServersToStrings(ne.Servers, ne.Name))
+ return &ne, nil
}
// Not in cache, call the real server.
callCtx, _ := ctx.WithTimeout(callTimeout)
- call, err := client.StartCall(callCtx, name, "ResolveStep", nil)
+ call, err := client.StartCall(callCtx, name, "ResolveStepX", nil, options.NoResolve(true))
if err != nil {
finalErr = err
vlog.VI(2).Infof("ResolveStep.StartCall %s failed: %s", name, err)
continue
}
- servers := []mountedServer{}
- var suffix string
- ierr := call.Finish(&servers, &suffix, &err)
+ var entry types.MountEntry
+ ierr := call.Finish(&entry, &err)
if ierr != nil {
// Internal/system error.
finalErr = ierr
@@ -57,15 +49,17 @@
continue
}
// Add result to cache.
- ns.resolutionCache.remember(naming.TrimSuffix(name, suffix), servers)
- return convertServersToStrings(servers, suffix), nil
+ ne := convertMountEntry(&entry)
+ ns.resolutionCache.remember(name, ne)
+ vlog.VI(2).Infof("resolveAMT %s -> %v", name, *ne)
+ return ne, nil
}
return nil, finalErr
}
-func terminal(names []string) bool {
- for _, name := range names {
- if !naming.Terminal(name) {
+func terminal(e *naming.MountEntry) bool {
+ for _, s := range e.Servers {
+ if !naming.Terminal(naming.JoinAddressName(s.Server, e.Name)) {
return false
}
}
@@ -79,79 +73,86 @@
return
}
-// Resolve implements veyron2/naming.Namespace.
-func (ns *namespace) Resolve(ctx context.T, name string) ([]string, error) {
+// ResolveX implements veyron2/naming.Namespace.
+func (ns *namespace) ResolveX(ctx context.T, name string) (*naming.MountEntry, error) {
defer vlog.LogCall()()
- names := ns.rootName(name)
+ e := ns.rootMountEntry(name)
if vlog.V(2) {
_, file, line, _ := runtime.Caller(1)
- vlog.Infof("Resolve(%s) called from %s:%d", name, file, line)
- vlog.Infof("Resolve(%s) -> rootNames %s", name, names)
+ vlog.Infof("ResolveX(%s) called from %s:%d", name, file, line)
+ vlog.Infof("ResolveX(%s) -> rootMountEntry %v", name, *e)
}
- if len(names) == 0 {
+ if len(e.Servers) == 0 {
return nil, naming.ErrNoMountTable
}
// Iterate walking through mount table servers.
for remaining := ns.maxResolveDepth; remaining > 0; remaining-- {
- vlog.VI(2).Infof("Resolve(%s) loop %s", name, names)
- if terminal(names) {
- vlog.VI(1).Infof("Resolve(%s) -> %s", name, names)
- return names, nil
+ vlog.VI(2).Infof("ResolveX(%s) loop %v", name, *e)
+ if !e.MT || terminal(e) {
+ vlog.VI(1).Infof("ResolveX(%s) -> %v", name, *e)
+ return e, nil
}
var err error
- curr := names
- if names, err = ns.resolveAgainstMountTable(ctx, ns.rt.Client(), names); err != nil {
+ curr := e
+ if e, err = ns.resolveAgainstMountTable(ctx, ns.rt.Client(), curr); err != nil {
// If the name could not be found in the mount table, return an error.
if verror.Equal(naming.ErrNoSuchNameRoot, err) {
err = naming.ErrNoSuchName
}
if verror.Equal(naming.ErrNoSuchName, err) {
- vlog.VI(1).Infof("Resolve(%s) -> (NoSuchName: %v)", name, curr)
+ vlog.VI(1).Infof("ResolveX(%s) -> (NoSuchName: %v)", name, curr)
return nil, err
}
// Any other failure (server not found, no ResolveStep
// method, etc.) are a sign that iterative resolution can
// stop.
- t := makeTerminal(curr)
- vlog.VI(1).Infof("Resolve(%s) -> %s", name, t)
- return t, nil
+ vlog.VI(1).Infof("ResolveX(%s) -> %v", name, curr)
+ return curr, nil
}
}
return nil, naming.ErrResolutionDepthExceeded
}
-// ResolveToMountTable implements veyron2/naming.Namespace.
-func (ns *namespace) ResolveToMountTable(ctx context.T, name string) ([]string, error) {
+// Resolve implements veyron2/naming.Namespace.
+func (ns *namespace) Resolve(ctx context.T, name string) ([]string, error) {
defer vlog.LogCall()()
- names := ns.rootName(name)
+ e, err := ns.ResolveX(ctx, name)
+ if err != nil {
+ return nil, err
+ }
+ return naming.ToStringSlice(e), nil
+}
+
+// ResolveToMountTableX implements veyron2/naming.Namespace.
+func (ns *namespace) ResolveToMountTableX(ctx context.T, name string) (*naming.MountEntry, error) {
+ defer vlog.LogCall()()
+ e := ns.rootMountEntry(name)
if vlog.V(2) {
_, file, line, _ := runtime.Caller(1)
- vlog.Infof("ResolveToMountTable(%s) called from %s:%d", name, file, line)
- vlog.Infof("ResolveToMountTable(%s) -> rootNames %s", name, names)
+ vlog.Infof("ResolveToMountTableX(%s) called from %s:%d", name, file, line)
+ vlog.Infof("ResolveToMountTableX(%s) -> rootNames %v", name, e)
}
- if len(names) == 0 {
+ if len(e.Servers) == 0 {
return nil, naming.ErrNoMountTable
}
- last := names
+ last := e
for remaining := ns.maxResolveDepth; remaining > 0; remaining-- {
- vlog.VI(2).Infof("ResolveToMountTable(%s) loop %s", name, names)
+ vlog.VI(2).Infof("ResolveToMountTable(%s) loop %v", name, e)
var err error
- curr := names
- if terminal(curr) {
- t := makeTerminal(last)
- vlog.VI(1).Infof("ResolveToMountTable(%s) -> %s", name, t)
- return t, nil
+ curr := e
+ // If the next name to resolve doesn't point to a mount table, we're done.
+ if !e.MT || terminal(e) {
+ vlog.VI(1).Infof("ResolveToMountTableX(%s) -> %v", name, last)
+ return last, nil
}
- if names, err = ns.resolveAgainstMountTable(ctx, ns.rt.Client(), names); err != nil {
+ if e, err = ns.resolveAgainstMountTable(ctx, ns.rt.Client(), e); err != nil {
if verror.Equal(naming.ErrNoSuchNameRoot, err) {
- t := makeTerminal(last)
- vlog.VI(1).Infof("ResolveToMountTable(%s) -> %s (NoSuchRoot: %v)", name, t, curr)
- return t, nil
+ vlog.VI(1).Infof("ResolveToMountTableX(%s) -> %v (NoSuchRoot: %v)", name, last, curr)
+ return last, nil
}
if verror.Equal(naming.ErrNoSuchName, err) {
- t := makeTerminal(curr)
- vlog.VI(1).Infof("ResolveToMountTable(%s) -> %s (NoSuchName: %v)", name, t, curr)
- return t, nil
+ vlog.VI(1).Infof("ResolveToMountTableX(%s) -> %v (NoSuchName: %v)", name, curr, curr)
+ return curr, nil
}
// Lots of reasons why another error can happen. We are trying
// to single out "this isn't a mount table".
@@ -159,22 +160,30 @@
// that means "we are up but don't implement what you are
// asking for".
if notAnMT(err) {
- t := makeTerminal(last)
- vlog.VI(1).Infof("ResolveToMountTable(%s) -> %s", name, t)
- return t, nil
+ vlog.VI(1).Infof("ResolveToMountTableX(%s) -> %v", name, last)
+ return last, nil
}
// TODO(caprita): If the server is unreachable for
// example, we may still want to return its parent
// mounttable rather than an error.
- vlog.VI(1).Infof("ResolveToMountTable(%s) -> %v", name, err)
+ vlog.VI(1).Infof("ResolveToMountTableX(%s) -> %v", name, err)
return nil, err
}
-
last = curr
}
return nil, naming.ErrResolutionDepthExceeded
}
+// ResolveToMountTable implements veyron2/naming.Namespace.
+func (ns *namespace) ResolveToMountTable(ctx context.T, name string) ([]string, error) {
+ defer vlog.LogCall()()
+ e, err := ns.ResolveToMountTableX(ctx, name)
+ if err != nil {
+ return nil, err
+ }
+ return naming.ToStringSlice(e), nil
+}
+
func finishUnresolve(call ipc.Call) ([]string, error) {
var newNames []string
var unresolveErr error
@@ -245,14 +254,14 @@
// all branches since we want to flush all entries at which we might end up whereas in a resolution,
// we stop with the first branch that works.
n := naming.MakeTerminal(n)
- if mts, suffix := ns.resolutionCache.lookup(n); mts != nil {
+ if e, err := ns.resolutionCache.lookup(n); err == nil {
// Recurse.
- for _, server := range mts {
- flushed = flushed || ns.FlushCacheEntry(naming.Join(server.Server, suffix))
+ for _, s := range e.Servers {
+ flushed = flushed || ns.FlushCacheEntry(naming.Join(s.Server, e.Name))
}
if !flushed {
// Forget the entry we just used.
- ns.resolutionCache.forget([]string{naming.TrimSuffix(n, suffix)})
+ ns.resolutionCache.forget([]string{naming.TrimSuffix(n, e.Name)})
flushed = true
}
}
diff --git a/runtimes/google/naming/namespace/stub.go b/runtimes/google/naming/namespace/stub.go
index 9661cae..5e1699c 100644
--- a/runtimes/google/naming/namespace/stub.go
+++ b/runtimes/google/naming/namespace/stub.go
@@ -1,21 +1,38 @@
package namespace
-// This file defines data types that are also defined in the idl for the
-// mounttable. We live with the duplication here to avoid having to depend
-// on stubs which in turn depend on the runtime etc.
+import (
+ "time"
-// mountedServer mirrors mounttable.MountedServer
-type mountedServer struct {
- // Server is the OA that's mounted.
- Server string
- // TTL is the remaining time (in seconds) before the mount entry expires.
- TTL uint32
+ "veyron.io/veyron/veyron2/naming"
+ "veyron.io/veyron/veyron2/services/mounttable/types"
+)
+
+func convertServersToStrings(servers []naming.MountedServer, suffix string) (ret []string) {
+ for _, s := range servers {
+ ret = append(ret, naming.Join(s.Server, suffix))
+ }
+ return
}
-// mountEntry mirrors mounttable.MountEntry
-type mountEntry struct {
- // Name is the mounted name.
- Name string
- // Servers (if present) specifies the mounted names (Link is empty).
- Servers []mountedServer
+func convertStringsToServers(servers []string) (ret []naming.MountedServer) {
+ for _, s := range servers {
+ ret = append(ret, naming.MountedServer{Server: s})
+ }
+ return
+}
+
+func convertServers(servers []types.MountedServer) []naming.MountedServer {
+ var reply []naming.MountedServer
+ for _, s := range servers {
+ if s.TTL == 0 {
+ s.TTL = 32000000 // > 1 year
+ }
+ expires := time.Now().Add(time.Duration(s.TTL) * time.Second)
+ reply = append(reply, naming.MountedServer{Server: s.Server, Expires: expires})
+ }
+ return reply
+}
+
+func convertMountEntry(e *types.MountEntry) *naming.MountEntry {
+ return &naming.MountEntry{Name: e.Name, MT: e.MT, Servers: convertServers(e.Servers)}
}
diff --git a/runtimes/google/testing/mocks/naming/namespace.go b/runtimes/google/testing/mocks/naming/namespace.go
index 58c914c..bff47f6 100644
--- a/runtimes/google/testing/mocks/naming/namespace.go
+++ b/runtimes/google/testing/mocks/naming/namespace.go
@@ -77,6 +77,34 @@
return nil, verror.NoExistf("Resolve name %q not found in %v", name, ns.mounts)
}
+func (ns *namespace) ResolveX(ctx context.T, name string) (*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)}}
+ return e, nil
+ }
+ ns.Lock()
+ defer ns.Unlock()
+ for prefix, servers := range ns.mounts {
+ if strings.HasPrefix(name, prefix) {
+ e.Name = strings.TrimLeft(strings.TrimPrefix(name, prefix), "/")
+ for _, s := range servers {
+ e.Servers = append(e.Servers, naming.MountedServer{Server: s, Expires: time.Now().Add(1000 * time.Hour)})
+ }
+ return e, nil
+ }
+ }
+ return nil, verror.NoExistf("Resolve name %q not found in %v", name, ns.mounts)
+}
+
+func (ns *namespace) ResolveToMountTableX(ctx context.T, name string) (*naming.MountEntry, error) {
+ defer vlog.LogCall()()
+ // TODO(mattr): Implement this method for tests that might need it.
+ panic("ResolveToMountTable not implemented")
+ return nil, nil
+}
+
func (ns *namespace) ResolveToMountTable(ctx context.T, name string) ([]string, error) {
defer vlog.LogCall()()
// TODO(mattr): Implement this method for tests that might need it.
diff --git a/services/mounttable/lib/mounttable.go b/services/mounttable/lib/mounttable.go
index ce6e6f3..b052b1b 100644
--- a/services/mounttable/lib/mounttable.go
+++ b/services/mounttable/lib/mounttable.go
@@ -275,7 +275,8 @@
// Make sure the server name is reasonable.
epString, _ := naming.SplitAddressName(server)
- if _, err := rt.R().NewEndpoint(epString); err != nil {
+ ep, err := rt.R().NewEndpoint(epString)
+ if err != nil {
return fmt.Errorf("malformed address %q for mounted server %q", epString, server)
}
@@ -289,10 +290,11 @@
if hasReplaceFlag(flags) {
n.mount = nil
}
+ wantMT := hasMTFlag(flags) || ep.ServesMountTable()
if n.mount == nil {
- n.mount = &mount{servers: NewServerList(), mt: hasMTFlag(flags)}
+ n.mount = &mount{servers: NewServerList(), mt: wantMT}
} else {
- if hasMTFlag(flags) != n.mount.mt {
+ if wantMT != n.mount.mt {
return fmt.Errorf("MT doesn't match")
}
}
diff --git a/tools/debug/impl.go b/tools/debug/impl.go
index 4448abe..3b4ba10 100644
--- a/tools/debug/impl.go
+++ b/tools/debug/impl.go
@@ -91,7 +91,7 @@
}
fmt.Fprint(cmd.Stdout(), me.Name)
for _, s := range me.Servers {
- fmt.Fprintf(cmd.Stdout(), " %s (TTL %s)", s.Server, s.TTL)
+ fmt.Fprintf(cmd.Stdout(), " %s (Expires %s)", s.Server, s.Expires)
}
fmt.Fprintln(cmd.Stdout())
}
diff --git a/tools/mounttable/impl.go b/tools/mounttable/impl.go
index 1ad5896..1c88cc7 100644
--- a/tools/mounttable/impl.go
+++ b/tools/mounttable/impl.go
@@ -7,20 +7,27 @@
"veyron.io/veyron/veyron/lib/cmdline"
"veyron.io/veyron/veyron2/context"
+ "veyron.io/veyron/veyron2/naming"
+ "veyron.io/veyron/veyron2/options"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/services/mounttable"
+ "veyron.io/veyron/veyron2/services/mounttable/types"
)
func bindMT(ctx context.T, name string) (mounttable.MountTable, error) {
- mts, err := rt.R().Namespace().ResolveToMountTable(ctx, name)
+ e, err := rt.R().Namespace().ResolveToMountTableX(ctx, name)
if err != nil {
return nil, err
}
- if len(mts) == 0 {
+ if len(e.Servers) == 0 {
return nil, fmt.Errorf("Failed to find any mount tables at %q", name)
}
- fmt.Println(mts)
- return mounttable.BindMountTable(mts[0])
+ var servers []string
+ for _, s := range e.Servers {
+ servers = append(servers, naming.JoinAddressName(s.Server, e.Name))
+ }
+ fmt.Println(servers)
+ return mounttable.BindMountTable(servers[0])
}
var cmdGlob = &cmdline.Command{
@@ -86,23 +93,38 @@
}
func runMount(cmd *cmdline.Command, args []string) error {
- if expected, got := 3, len(args); expected != got {
- return cmd.UsageErrorf("mount: incorrect number of arguments, expected %d, got %d", expected, got)
+ got := len(args)
+ if got < 2 || got > 4 {
+ return cmd.UsageErrorf("mount: incorrect number of arguments, expected 2, 3, or 4, got %d", got)
+ }
+ var flags types.MountFlag
+ var seconds uint32
+ if got >= 3 {
+ ttl, err := time.ParseDuration(args[2])
+ if err != nil {
+ return fmt.Errorf("TTL parse error: %v", err)
+ }
+ seconds = uint32(ttl.Seconds())
+ }
+ if got >= 4 {
+ for _, c := range args[3] {
+ switch c {
+ case 'M':
+ flags |= types.MountFlag(types.MT)
+ case 'R':
+ flags |= types.MountFlag(types.Replace)
+ }
+ }
}
ctx, cancel := rt.R().NewContext().WithTimeout(time.Minute)
defer cancel()
- c, err := bindMT(ctx, args[0])
- if err != nil {
- return fmt.Errorf("bind error: %v", err)
- }
- ttl, err := time.ParseDuration(args[2])
- if err != nil {
- return fmt.Errorf("TTL parse error: %v", err)
- }
- err = c.Mount(ctx, args[1], uint32(ttl.Seconds()), 0)
+ call, err := rt.R().Client().StartCall(ctx, args[0], "Mount", []interface{}{args[1], seconds, 0}, options.NoResolve(true))
if err != nil {
return err
}
+ if ierr := call.Finish(&err); ierr != nil {
+ return ierr
+ }
fmt.Fprintln(cmd.Stdout(), "Name mounted successfully.")
return nil
@@ -126,14 +148,13 @@
}
ctx, cancel := rt.R().NewContext().WithTimeout(time.Minute)
defer cancel()
- c, err := bindMT(ctx, args[0])
- if err != nil {
- return fmt.Errorf("bind error: %v", err)
- }
- err = c.Unmount(ctx, args[1])
+ call, err := rt.R().Client().StartCall(ctx, args[0], "Unmount", []interface{}{args[1]}, options.NoResolve(true))
if err != nil {
return err
}
+ if ierr := call.Finish(&err); ierr != nil {
+ return ierr
+ }
fmt.Fprintln(cmd.Stdout(), "Name unmounted successfully.")
return nil
diff --git a/tools/namespace/impl.go b/tools/namespace/impl.go
index 0980229..5b00ce6 100644
--- a/tools/namespace/impl.go
+++ b/tools/namespace/impl.go
@@ -5,7 +5,7 @@
"time"
"veyron.io/veyron/veyron/lib/cmdline"
-
+ "veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/vlog"
)
@@ -38,7 +38,7 @@
for res := range c {
fmt.Fprint(cmd.Stdout(), res.Name)
for _, s := range res.Servers {
- fmt.Fprintf(cmd.Stdout(), " %s (TTL %s)", s.Server, s.TTL)
+ fmt.Fprintf(cmd.Stdout(), " %s (Expires %s)", s.Server, s.Expires)
}
fmt.Fprintln(cmd.Stdout())
}
@@ -156,13 +156,13 @@
ns := rt.R().Namespace()
ctx, cancel := rt.R().NewContext().WithTimeout(time.Minute)
defer cancel()
- servers, err := ns.ResolveToMountTable(ctx, name)
+ e, err := ns.ResolveToMountTableX(ctx, name)
if err != nil {
- vlog.Infof("ns.ResolveToMountTable(%q) failed: %v", name, err)
+ vlog.Infof("ns.ResolveToMountTableX(%q) failed: %v", name, err)
return err
}
- for _, s := range servers {
- fmt.Fprintln(cmd.Stdout(), s)
+ for _, s := range e.Servers {
+ fmt.Fprintln(cmd.Stdout(), naming.JoinAddressName(s.Server, e.Name))
}
return nil
}
diff --git a/tools/naming/simulator/mt_complex.scr b/tools/naming/simulator/mt_complex.scr
index a5c85e2..027ddff 100644
--- a/tools/naming/simulator/mt_complex.scr
+++ b/tools/naming/simulator/mt_complex.scr
@@ -238,7 +238,7 @@
# Now, use mount directly to create a 'symlink'
set symlink_target=some/deep/name/that/is/a/mount
-mount tl/b/symlink /$mt_b_addr/$symlink_target 1h
+mount tl/b/symlink /$mt_b_addr/$symlink_target 1h M
wait $_
ls -l tl/b/symlink