| // Copyright 2015 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. |
| |
| // The following enables go generate to generate the doc.go file. |
| //go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . |
| |
| package main |
| |
| import ( |
| "encoding/json" |
| "fmt" |
| "os" |
| "regexp" |
| "sort" |
| "time" |
| |
| "v.io/x/lib/cmdline" |
| "v.io/x/lib/set" |
| |
| "v.io/v23" |
| "v.io/v23/context" |
| "v.io/v23/naming" |
| "v.io/v23/options" |
| "v.io/v23/security" |
| "v.io/v23/security/access" |
| "v.io/v23/verror" |
| |
| "v.io/x/ref/lib/v23cmd" |
| _ "v.io/x/ref/runtime/factories/generic" |
| ) |
| |
| func main() { |
| cmdline.HideGlobalFlagsExcept(regexp.MustCompile(`^v23\.namespace\.root$`)) |
| cmdline.Main(cmdRoot) |
| } |
| |
| var ( |
| flagLongGlob bool |
| 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.") |
| } |
| |
| var cmdGlob = &cmdline.Command{ |
| Runner: v23cmd.RunnerFunc(runGlob), |
| Name: "glob", |
| Short: "Returns all matching entries from the namespace", |
| Long: "Returns all matching entries from the namespace.", |
| ArgsName: "<pattern>", |
| ArgsLong: ` |
| <pattern> is a glob pattern that is matched against all the names below the |
| specified mount name. |
| `, |
| } |
| |
| func runGlob(ctx *context.T, env *cmdline.Env, args []string) error { |
| if expected, got := 1, len(args); expected != got { |
| return env.UsageErrorf("glob: incorrect number of arguments, expected %d, got %d", expected, got) |
| } |
| pattern := args[0] |
| |
| ctx, cancel := context.WithTimeout(ctx, time.Minute) |
| defer cancel() |
| |
| ns := v23.GetNamespace(ctx) |
| |
| c, err := ns.Glob(ctx, pattern) |
| if err != nil { |
| ctx.Infof("ns.Glob(%q) failed: %v", pattern, err) |
| return err |
| } |
| if flagLongGlob { |
| // Show all the information we received. |
| for res := range c { |
| switch v := res.(type) { |
| case *naming.GlobReplyEntry: |
| fmt.Fprint(env.Stdout, v.Value.Name) |
| for _, s := range v.Value.Servers { |
| delta := s.Deadline.Time.Sub(time.Now()) |
| fmt.Fprintf(env.Stdout, " %s (Expires in %d sec)", s.Server, int(delta.Seconds())) |
| } |
| fmt.Fprintln(env.Stdout) |
| case *naming.GlobReplyError: |
| fmt.Fprintf(env.Stderr, "Error: %s: %v\n", v.Value.Name, v.Value.Error) |
| } |
| } |
| return nil |
| } |
| // Show a sorted list of unique names, and any errors. |
| resultSet := make(map[string]struct{}) |
| errors := []*naming.GlobError{} |
| for res := range c { |
| switch v := res.(type) { |
| case *naming.GlobReplyEntry: |
| if v.Value.Name != "" { |
| resultSet[v.Value.Name] = struct{}{} |
| } |
| case *naming.GlobReplyError: |
| errors = append(errors, &v.Value) |
| } |
| } |
| results := set.String.ToSlice(resultSet) |
| sort.Strings(results) |
| for _, result := range results { |
| fmt.Fprintln(env.Stdout, result) |
| } |
| for _, err := range errors { |
| fmt.Fprintf(env.Stderr, "Error: %s: %v\n", err.Name, err.Error) |
| } |
| return nil |
| } |
| |
| var cmdMount = &cmdline.Command{ |
| Runner: v23cmd.RunnerFunc(runMount), |
| Name: "mount", |
| Short: "Adds a server to the namespace", |
| Long: "Adds server <server> to the namespace with name <name>.", |
| ArgsName: "<name> <server> <ttl>", |
| ArgsLong: ` |
| <name> is the name to add to the namespace. |
| <server> is the object address of the server to add. |
| <ttl> is the TTL of the new entry. It is a decimal number followed by a unit |
| suffix (s, m, h). A value of 0s represents an infinite duration. |
| `, |
| } |
| |
| func runMount(ctx *context.T, env *cmdline.Env, args []string) error { |
| if expected, got := 3, len(args); expected != got { |
| return env.UsageErrorf("mount: incorrect number of arguments, expected %d, got %d", expected, got) |
| } |
| name := args[0] |
| server := args[1] |
| ttlArg := args[2] |
| |
| ttl, err := time.ParseDuration(ttlArg) |
| if err != nil { |
| return fmt.Errorf("TTL parse error: %v", err) |
| } |
| |
| ctx, cancel := context.WithTimeout(ctx, time.Minute) |
| defer cancel() |
| |
| ns := v23.GetNamespace(ctx) |
| if err = ns.Mount(ctx, name, server, ttl); err != nil { |
| ctx.Infof("ns.Mount(%q, %q, %s) failed: %v", name, server, ttl, err) |
| return err |
| } |
| fmt.Fprintln(env.Stdout, "Server mounted successfully.") |
| return nil |
| } |
| |
| var cmdUnmount = &cmdline.Command{ |
| Runner: v23cmd.RunnerFunc(runUnmount), |
| Name: "unmount", |
| Short: "Removes a server from the namespace", |
| Long: "Removes server <server> with name <name> from the namespace.", |
| ArgsName: "<name> <server>", |
| ArgsLong: ` |
| <name> is the name to remove from the namespace. |
| <server> is the object address of the server to remove. |
| `, |
| } |
| |
| func runUnmount(ctx *context.T, env *cmdline.Env, args []string) error { |
| if expected, got := 2, len(args); expected != got { |
| return env.UsageErrorf("unmount: incorrect number of arguments, expected %d, got %d", expected, got) |
| } |
| name := args[0] |
| server := args[1] |
| |
| ctx, cancel := context.WithTimeout(ctx, time.Minute) |
| defer cancel() |
| |
| ns := v23.GetNamespace(ctx) |
| |
| if err := ns.Unmount(ctx, name, server); err != nil { |
| ctx.Infof("ns.Unmount(%q, %q) failed: %v", name, server, err) |
| return err |
| } |
| fmt.Fprintln(env.Stdout, "Server unmounted successfully.") |
| return nil |
| } |
| |
| var cmdResolve = &cmdline.Command{ |
| Runner: v23cmd.RunnerFunc(runResolve), |
| Name: "resolve", |
| Short: "Translates a object name to its object address(es)", |
| Long: "Translates a object name to its object address(es).", |
| ArgsName: "<name>", |
| ArgsLong: "<name> is the name to resolve.", |
| } |
| |
| func runResolve(ctx *context.T, env *cmdline.Env, args []string) error { |
| if expected, got := 1, len(args); expected != got { |
| return env.UsageErrorf("resolve: incorrect number of arguments, expected %d, got %d", expected, got) |
| } |
| name := args[0] |
| |
| ctx, cancel := context.WithTimeout(ctx, time.Minute) |
| defer cancel() |
| |
| ns := v23.GetNamespace(ctx) |
| |
| var opts []naming.NamespaceOpt |
| if flagInsecureResolve { |
| opts = append(opts, options.NameResolutionAuthorizer{security.AllowEveryone()}) |
| } |
| 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 |
| } |
| for _, n := range me.Names() { |
| fmt.Fprintln(env.Stdout, n) |
| } |
| return nil |
| } |
| |
| var cmdResolveToMT = &cmdline.Command{ |
| Runner: v23cmd.RunnerFunc(runResolveToMT), |
| Name: "resolvetomt", |
| Short: "Finds the address of the mounttable that holds an object name", |
| Long: "Finds the address of the mounttable that holds an object name.", |
| ArgsName: "<name>", |
| ArgsLong: "<name> is the name to resolve.", |
| } |
| |
| func runResolveToMT(ctx *context.T, env *cmdline.Env, args []string) error { |
| if expected, got := 1, len(args); expected != got { |
| return env.UsageErrorf("resolvetomt: incorrect number of arguments, expected %d, got %d", expected, got) |
| } |
| name := args[0] |
| |
| ctx, cancel := context.WithTimeout(ctx, time.Minute) |
| defer cancel() |
| |
| ns := v23.GetNamespace(ctx) |
| var opts []naming.NamespaceOpt |
| if flagInsecureResolveToMT { |
| opts = append(opts, options.NameResolutionAuthorizer{security.AllowEveryone()}) |
| } |
| e, err := ns.ResolveToMountTable(ctx, name, opts...) |
| if err != nil { |
| ctx.Infof("ns.ResolveToMountTable(%q) failed: %v", name, err) |
| return err |
| } |
| for _, s := range e.Servers { |
| fmt.Fprintln(env.Stdout, naming.JoinAddressName(s.Server, e.Name)) |
| } |
| return nil |
| } |
| |
| var cmdPermissions = &cmdline.Command{ |
| Name: "permissions", |
| Short: "Manipulates permissions on an entry in the namespace", |
| Long: ` |
| Commands to get and set the permissions on a name - controlling the blessing |
| names required to resolve the name. |
| |
| The permissions are provided as an JSON-encoded version of the Permissions type |
| defined in v.io/v23/security/access/types.vdl. |
| `, |
| Children: []*cmdline.Command{cmdPermissionsGet, cmdPermissionsSet}, |
| } |
| |
| var cmdPermissionsSet = &cmdline.Command{ |
| Runner: v23cmd.RunnerFunc(runPermissionsSet), |
| Name: "set", |
| Short: "Sets permissions on a mount name", |
| Long: ` |
| Set replaces the permissions controlling usage of a mount name. |
| `, |
| ArgsName: "<name> <permissions>", |
| ArgsLong: ` |
| <name> is the name on which permissions are to be set. |
| |
| <permissions> is the path to a file containing a JSON-encoded Permissions |
| object (defined in v.io/v23/security/access/types.vdl), or "-" for STDIN. |
| `, |
| } |
| |
| func runPermissionsSet(ctx *context.T, env *cmdline.Env, args []string) error { |
| if expected, got := 2, len(args); expected != got { |
| return env.UsageErrorf("set: incorrect number of arguments, expected %d, got %d", expected, got) |
| } |
| name := args[0] |
| var perms access.Permissions |
| file := os.Stdin |
| if args[1] != "-" { |
| var err error |
| if file, err = os.Open(args[1]); err != nil { |
| return err |
| } |
| defer file.Close() |
| } |
| if err := json.NewDecoder(file).Decode(&perms); err != nil { |
| return err |
| } |
| ctx, cancel := context.WithTimeout(ctx, time.Minute) |
| defer cancel() |
| ns := v23.GetNamespace(ctx) |
| for { |
| _, etag, err := ns.GetPermissions(ctx, name) |
| if err != nil && verror.ErrorID(err) != naming.ErrNoSuchName.ID { |
| return err |
| } |
| if err = ns.SetPermissions(ctx, name, perms, etag); verror.ErrorID(err) == verror.ErrBadVersion.ID { |
| ctx.Infof("SetPermissions(%q, %q) failed: %v, retrying...", name, etag, err) |
| continue |
| } |
| return err |
| } |
| } |
| |
| var cmdPermissionsGet = &cmdline.Command{ |
| Runner: v23cmd.RunnerFunc(runPermissionsGet), |
| Name: "get", |
| Short: "Gets permissions on a mount name", |
| ArgsName: "<name>", |
| ArgsLong: ` |
| <name> is a name in the namespace. |
| `, |
| Long: ` |
| Get retrieves the permissions on the usage of a name. |
| |
| The output is a JSON-encoded Permissions object (defined in |
| v.io/v23/security/access/types.vdl). |
| `, |
| } |
| |
| func runPermissionsGet(ctx *context.T, env *cmdline.Env, args []string) error { |
| if expected, got := 1, len(args); expected != got { |
| return env.UsageErrorf("get: incorrect number of arguments, expected %d, got %d", expected, got) |
| } |
| name := args[0] |
| ctx, cancel := context.WithTimeout(ctx, time.Minute) |
| defer cancel() |
| |
| perms, _, err := v23.GetNamespace(ctx).GetPermissions(ctx, name) |
| if err != nil { |
| return err |
| } |
| return json.NewEncoder(env.Stdout).Encode(perms) |
| } |
| |
| var cmdDelete = &cmdline.Command{ |
| Runner: v23cmd.RunnerFunc(runDelete), |
| Name: "delete", |
| Short: "Deletes a name from the namespace", |
| ArgsName: "<name>", |
| ArgsLong: "<name> is a name to delete.", |
| Long: "Deletes a name from the namespace.", |
| } |
| |
| func runDelete(ctx *context.T, env *cmdline.Env, args []string) error { |
| if expected, got := 1, len(args); expected != got { |
| return env.UsageErrorf("delete: incorrect number of arguments, expected %d, got %d", expected, got) |
| } |
| name := args[0] |
| ctx, cancel := context.WithTimeout(ctx, time.Minute) |
| defer cancel() |
| |
| return v23.GetNamespace(ctx).Delete(ctx, name, flagDeleteSubtree) |
| } |
| |
| var cmdRoot = &cmdline.Command{ |
| Name: "namespace", |
| Short: "resolves and manages names in the Vanadium namespace", |
| Long: ` |
| Command namespace resolves and manages names in the Vanadium namespace. |
| |
| The namespace roots are set from the command line via --v23.namespace.root |
| command line option or from environment variables that have a name starting |
| with V23_NAMESPACE, e.g. V23_NAMESPACE, V23_NAMESPACE_2, V23_NAMESPACE_GOOGLE, |
| etc. The command line options override the environment. |
| `, |
| Children: []*cmdline.Command{cmdGlob, cmdMount, cmdUnmount, cmdResolve, cmdResolveToMT, cmdPermissions, cmdDelete}, |
| } |