Merge "services/device/mgmt_v23_test.go: multi-user integration tests"
diff --git a/cmd/mounttable/impl_test.go b/cmd/mounttable/impl_test.go
index 4e50553..cc46ed1 100644
--- a/cmd/mounttable/impl_test.go
+++ b/cmd/mounttable/impl_test.go
@@ -131,7 +131,7 @@
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
// Test the 'glob' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"glob", naming.JoinAddressName(endpoint.String(), ""), "*"}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"glob", naming.JoinAddressName(endpoint.String(), ""), "*"}); err != nil {
t.Fatalf("%v", err)
}
const deadRE = `\(Deadline ([^)]+)\)`
@@ -141,7 +141,7 @@
stdout.Reset()
// Test the 'mount' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"mount", "server", endpoint.Name(), "123s"}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"mount", "server", endpoint.Name(), "123s"}); err != nil {
t.Fatalf("%v", err)
}
if got, want := strings.TrimSpace(stdout.String()), "Name mounted successfully."; got != want {
@@ -150,7 +150,7 @@
stdout.Reset()
// Test the 'unmount' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"unmount", "server", endpoint.Name()}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"unmount", "server", endpoint.Name()}); err != nil {
t.Fatalf("%v", err)
}
if got, want := strings.TrimSpace(stdout.String()), "Unmount successful or name not mounted."; got != want {
@@ -160,7 +160,7 @@
// Test the 'resolvestep' command.
vlog.Infof("resovestep %s", naming.JoinAddressName(endpoint.String(), "name"))
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"resolvestep", naming.JoinAddressName(endpoint.String(), "name")}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"resolvestep", naming.JoinAddressName(endpoint.String(), "name")}); err != nil {
t.Fatalf("%v", err)
}
if got, wantRE := strings.TrimSpace(stdout.String()), regexp.MustCompile(`Servers: \[\{server1 [^}]+\}\] Suffix: "name" MT: false`); !wantRE.MatchString(got) {
diff --git a/cmd/principal/main.go b/cmd/principal/main.go
index f2a3de6..b604464 100644
--- a/cmd/principal/main.go
+++ b/cmd/principal/main.go
@@ -91,10 +91,19 @@
Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
p := v23.GetPrincipal(ctx)
if flagDumpShort {
- fmt.Printf("%v\n", p.BlessingStore().Default())
+ fmt.Printf("%s\n", printAnnotatedBlessingsNames(p.BlessingStore().Default()))
return nil
}
fmt.Printf("Public key : %v\n", p.PublicKey())
+ // NOTE(caprita): We print the default blessings name
+ // twice (it's also printed as part of the blessing
+ // store below) -- the reason we print it here is to
+ // expose whether the blessings are expired. Ideally,
+ // the blessings store would print the expiry
+ // information about each blessing in the store, but
+ // that would require deeper changes beyond the
+ // principal tool.
+ fmt.Printf("Default Blessings : %s\n", printAnnotatedBlessingsNames(p.BlessingStore().Default()))
fmt.Println("---------------- BlessingStore ----------------")
fmt.Printf("%v", p.BlessingStore().DebugString())
fmt.Println("---------------- BlessingRoots ----------------")
@@ -127,12 +136,7 @@
if err != nil {
return fmt.Errorf("failed to decode certificate chains: %v", err)
}
- // If the Blessings are expired, print a message saying so.
- expiredMessage := ""
- if exp := blessings.Expiry(); !exp.IsZero() && exp.Before(time.Now()) {
- expiredMessage = " [EXPIRED]"
- }
- fmt.Printf("Blessings : %v%s\n", blessings, expiredMessage)
+ fmt.Printf("Blessings : %s\n", printAnnotatedBlessingsNames(blessings))
fmt.Printf("PublicKey : %v\n", blessings.PublicKey())
fmt.Printf("Certificate chains : %d\n", len(wire.CertificateChains))
for idx, chain := range wire.CertificateChains {
@@ -787,6 +791,15 @@
}
)
+func printAnnotatedBlessingsNames(b security.Blessings) string {
+ // If the Blessings are expired, print a message saying so.
+ expiredMessage := ""
+ if exp := b.Expiry(); !exp.IsZero() && exp.Before(time.Now()) {
+ expiredMessage = " [EXPIRED]"
+ }
+ return fmt.Sprintf("%v%s", b, expiredMessage)
+}
+
func blessArgs(args []string) (tobless, extension, remoteKey, remoteToken string, err error) {
if len(flagRemoteArgFile) > 0 && (len(flagBlessRemoteKey)+len(flagBlessRemoteToken) > 0) {
return "", "", "", "", fmt.Errorf("--remote-key and --remote-token cannot be provided with --remote-arg-file")
diff --git a/cmd/principal/principal_v23_test.go b/cmd/principal/principal_v23_test.go
index 734b4d1..9e80947 100644
--- a/cmd/principal/principal_v23_test.go
+++ b/cmd/principal/principal_v23_test.go
@@ -128,9 +128,10 @@
func V23TestDump(t *v23tests.T) {
var (
- outputDir = t.NewTempDir("")
- bin = t.BuildGoPkg("v.io/x/ref/cmd/principal")
- aliceDir = filepath.Join(outputDir, "alice")
+ outputDir = t.NewTempDir("")
+ bin = t.BuildGoPkg("v.io/x/ref/cmd/principal")
+ aliceDir = filepath.Join(outputDir, "alice")
+ aliceExpiredDir = filepath.Join(outputDir, "alice-expired")
)
bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr)
@@ -138,6 +139,7 @@
blessEnv := credEnv(aliceDir)
got := removePublicKeys(bin.WithEnv(blessEnv).Start("dump").Output())
want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+Default Blessings : alice
---------------- BlessingStore ----------------
Default Blessings alice
Peer pattern Blessings
@@ -149,6 +151,35 @@
if want != got {
t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want)
}
+
+ got = bin.WithEnv(blessEnv).Start("dump", "-s").Output()
+ want = "alice\n"
+ if want != got {
+ t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want)
+ }
+
+ bin.Start("--v23.credentials="+aliceDir, "fork", "--for", "-1h", aliceExpiredDir, "expired").WaitOrDie(os.Stdout, os.Stderr)
+ blessEnv = credEnv(aliceExpiredDir)
+ got = removePublicKeys(bin.WithEnv(blessEnv).Start("dump").Output())
+ want = `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+Default Blessings : alice/expired [EXPIRED]
+---------------- BlessingStore ----------------
+Default Blessings alice/expired
+Peer pattern Blessings
+... alice/expired
+---------------- BlessingRoots ----------------
+Public key Pattern
+XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [alice]
+`
+ if want != got {
+ t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want)
+ }
+
+ got = bin.WithEnv(blessEnv).Start("dump", "-s").Output()
+ want = "alice/expired [EXPIRED]\n"
+ if want != got {
+ t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want)
+ }
}
func V23TestGetRecognizedRoots(t *v23tests.T) {
@@ -286,6 +317,7 @@
// first "bless" command. (alice/friend/carol).
got := removePublicKeys(bin.Start("--v23.credentials="+carolDir, "dump").Output())
want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+Default Blessings : alice/friend/carol
---------------- BlessingStore ----------------
Default Blessings alice/friend/carol
Peer pattern Blessings
@@ -324,6 +356,7 @@
{
got := removePublicKeys(bin.Start("--v23.credentials="+alicePhoneDir, "dump").Output())
want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+Default Blessings : alice/phone
---------------- BlessingStore ----------------
Default Blessings alice/phone
Peer pattern Blessings
@@ -359,6 +392,7 @@
{
got := removePublicKeys(bin.Start("--v23.credentials="+alicePhoneCalendarDir, "dump").Output())
want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+Default Blessings : alice/phone/calendar
---------------- BlessingStore ----------------
Default Blessings alice/phone/calendar
Peer pattern Blessings
diff --git a/cmd/servicerunner/doc.go b/cmd/servicerunner/doc.go
new file mode 100644
index 0000000..939f99d
--- /dev/null
+++ b/cmd/servicerunner/doc.go
@@ -0,0 +1,74 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+// +build wspr
+
+/*
+Command servicerunner runs several Vanadium services, including the mounttable,
+proxy and wspr. It prints a JSON map with their vars to stdout (as a single
+line), then waits forever.
+
+Usage:
+ servicerunner [flags]
+
+The servicerunner flags are:
+ -identd=
+ Name of wspr identd server.
+ -port=8124
+ Port for wspr to listen on.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -external-http-addr=
+ External address on which the HTTP server listens on. If none is provided the
+ server will only listen on -http-addr.
+ -http-addr=localhost:0
+ Address on which the HTTP server listens on.
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -tls-config=
+ Comma-separated list of TLS certificate and private key files. This must be
+ provided.
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/cmd/servicerunner/main.go b/cmd/servicerunner/main.go
index d08ae2b..aa944cc 100644
--- a/cmd/servicerunner/main.go
+++ b/cmd/servicerunner/main.go
@@ -5,10 +5,13 @@
// +build wspr
//
// We restrict to a special build-tag since it's required by wsprlib.
+//
+// Manually run the following to generate the doc.go file. This isn't a
+// go:generate comment, since generate also needs to be run with -tags=wspr,
+// which is troublesome for presubmit tests.
+//
+// cd $V23_ROOT/release/go/src && go run v.io/x/lib/cmdline/testdata/gendoc.go -tags=wspr v.io/x/ref/cmd/servicerunner -help
-// Command servicerunner runs several Vanadium services, including the
-// mounttable, proxy and wspr. It prints a JSON map with their vars to stdout
-// (as a single line), then waits forever.
package main
import (
@@ -23,24 +26,46 @@
"v.io/v23/options"
"v.io/v23/rpc"
"v.io/v23/security"
-
+ "v.io/x/lib/cmdline"
"v.io/x/ref/envvar"
"v.io/x/ref/lib/signals"
"v.io/x/ref/runtime/factories/generic"
"v.io/x/ref/services/identity/identitylib"
"v.io/x/ref/services/mounttable/mounttablelib"
+ "v.io/x/ref/services/wspr/wsprlib"
"v.io/x/ref/test/expect"
"v.io/x/ref/test/modules"
)
-func panicOnError(err error) {
- if err != nil {
- panic(err)
- }
-}
+var (
+ port int
+ identd string
+)
func init() {
+ wsprlib.OverrideCaveatValidation()
+ cmdServiceRunner.Flags.IntVar(&port, "port", 8124, "Port for wspr to listen on.")
+ cmdServiceRunner.Flags.StringVar(&identd, "identd", "", "Name of wspr identd server.")
modules.RegisterChild("rootMT", ``, rootMT)
+ modules.RegisterChild(wsprdCommand, modules.Usage(&cmdServiceRunner.Flags), startWSPR)
+}
+
+const wsprdCommand = "wsprd"
+
+func main() {
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdServiceRunner)
+}
+
+var cmdServiceRunner = &cmdline.Command{
+ Runner: cmdline.RunnerFunc(run),
+ Name: "servicerunner",
+ Short: "Runs several services, including the mounttable, proxy and wspr.",
+ Long: `
+Command servicerunner runs several Vanadium services, including the mounttable,
+proxy and wspr. It prints a JSON map with their vars to stdout (as a single
+line), then waits forever.
+`,
}
func rootMT(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
@@ -101,17 +126,20 @@
return nil
}
-func main() {
+func run(env *cmdline.Env, args []string) error {
+ // The dispatch to modules children must occur after the call to cmdline.Main
+ // (which calls cmdline.Parse), so that servicerunner flags are registered on
+ // the global flag.CommandLine.
if modules.IsModulesChildProcess() {
- panicOnError(modules.Dispatch())
- return
+ return modules.Dispatch()
}
+ // We must wait until after we've dispatched to children before calling
+ // v23.Init, otherwise we'll end up initializing twice.
ctx, shutdown := v23.Init()
defer shutdown()
vars := map[string]string{}
-
sh, err := modules.NewShell(ctx, nil, false, nil)
if err != nil {
panic(fmt.Sprintf("modules.NewShell: %s", err))
@@ -119,8 +147,12 @@
defer sh.Cleanup(os.Stderr, os.Stderr)
h, err := sh.Start("rootMT", nil, "--v23.tcp.protocol=ws", "--v23.tcp.address=127.0.0.1:0")
- panicOnError(err)
- panicOnError(updateVars(h, vars, "MT_NAME"))
+ if err != nil {
+ return err
+ }
+ if err := updateVars(h, vars, "MT_NAME"); err != nil {
+ return err
+ }
// Set envvar.NamespacePrefix env var, consumed downstream.
sh.SetVar(envvar.NamespacePrefix, vars["MT_NAME"])
@@ -132,17 +164,46 @@
defer proxyShutdown()
vars["PROXY_NAME"] = proxyEndpoint.Name()
- h, err = sh.Start(WSPRDCommand, nil, "--v23.tcp.protocol=ws", "--v23.tcp.address=127.0.0.1:0", "--v23.proxy=test/proxy", "--identd=test/identd")
- panicOnError(err)
- panicOnError(updateVars(h, vars, "WSPR_ADDR"))
+ h, err = sh.Start(wsprdCommand, nil, "--v23.tcp.protocol=ws", "--v23.tcp.address=127.0.0.1:0", "--v23.proxy=test/proxy", "--identd=test/identd")
+ if err != nil {
+ return err
+ }
+ if err := updateVars(h, vars, "WSPR_ADDR"); err != nil {
+ return err
+ }
h, err = sh.Start(identitylib.TestIdentitydCommand, nil, "--v23.tcp.protocol=ws", "--v23.tcp.address=127.0.0.1:0", "--v23.proxy=test/proxy", "--http-addr=localhost:0")
- panicOnError(err)
- panicOnError(updateVars(h, vars, "TEST_IDENTITYD_NAME", "TEST_IDENTITYD_HTTP_ADDR"))
+ if err != nil {
+ return err
+ }
+ if err := updateVars(h, vars, "TEST_IDENTITYD_NAME", "TEST_IDENTITYD_HTTP_ADDR"); err != nil {
+ return err
+ }
bytes, err := json.Marshal(vars)
- panicOnError(err)
+ if err != nil {
+ return err
+ }
fmt.Println(string(bytes))
<-signals.ShutdownOnSignals(ctx)
+ return nil
+}
+
+func startWSPR(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+ ctx, shutdown := v23.Init()
+ defer shutdown()
+
+ l := v23.GetListenSpec(ctx)
+ proxy := wsprlib.NewWSPR(ctx, port, &l, identd, nil)
+ defer proxy.Shutdown()
+
+ addr := proxy.Listen()
+ go func() {
+ proxy.Serve()
+ }()
+
+ fmt.Fprintf(stdout, "WSPR_ADDR=%s\n", addr)
+ modules.WaitForEOF(stdin)
+ return nil
}
diff --git a/cmd/servicerunner/wspr.go b/cmd/servicerunner/wspr.go
deleted file mode 100644
index f8fd122..0000000
--- a/cmd/servicerunner/wspr.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-// +build wspr
-//
-// We restrict to a special build-tag in order to enable
-// security.OverrideCaveatValidation, which isn't generally available.
-
-package main
-
-import (
- "flag"
- "fmt"
- "io"
-
- "v.io/v23"
-
- "v.io/x/ref/services/wspr/wsprlib"
- "v.io/x/ref/test/modules"
-)
-
-var (
- port *int = flag.CommandLine.Int("port", 0, "Port to listen on.")
- identd *string = flag.CommandLine.String("identd", "", "identd server name. Must be set.")
-)
-
-const WSPRDCommand = "wsprd"
-
-func init() {
- wsprlib.OverrideCaveatValidation()
- modules.RegisterChild(WSPRDCommand, modules.Usage(flag.CommandLine), startWSPR)
-}
-
-func startWSPR(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- ctx, shutdown := v23.Init()
- defer shutdown()
-
- l := v23.GetListenSpec(ctx)
- proxy := wsprlib.NewWSPR(ctx, *port, &l, *identd, nil)
- defer proxy.Shutdown()
-
- addr := proxy.Listen()
- go func() {
- proxy.Serve()
- }()
-
- fmt.Fprintf(stdout, "WSPR_ADDR=%s\n", addr)
- modules.WaitForEOF(stdin)
- return nil
-}
diff --git a/cmd/vrpc/vrpc_test.go b/cmd/vrpc/vrpc_test.go
index a6643fc..4ff920f 100644
--- a/cmd/vrpc/vrpc_test.go
+++ b/cmd/vrpc/vrpc_test.go
@@ -144,7 +144,7 @@
var stdout, stderr bytes.Buffer
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
args := []string{"signature", fmt.Sprintf("-show-reserved=%v", showReserved), name}
- if err := v23cmd.ParseAndRun(cmdVRPC, ctx, env, args); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdVRPC, ctx, env, args); err != nil {
t.Fatalf("%s: %v", args, err)
}
@@ -292,7 +292,7 @@
for _, test := range tests {
var stdout, stderr bytes.Buffer
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
- if err := v23cmd.ParseAndRun(cmdVRPC, ctx, env, []string{"signature", name, test.Method}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdVRPC, ctx, env, []string{"signature", name, test.Method}); err != nil {
t.Errorf("%q failed: %v", test.Method, err)
continue
}
@@ -335,7 +335,7 @@
for _, test := range tests {
var stdout, stderr bytes.Buffer
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
- if err := v23cmd.ParseAndRun(cmdVRPC, ctx, env, []string{"call", name, test.Method, test.InArgs}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdVRPC, ctx, env, []string{"call", name, test.Method, test.InArgs}); err != nil {
t.Errorf("%q(%s) failed: %v", test.Method, test.InArgs, err)
continue
}
diff --git a/examples/rps/rpsbot/doc.go b/examples/rps/rpsbot/doc.go
new file mode 100644
index 0000000..d30af8e
--- /dev/null
+++ b/examples/rps/rpsbot/doc.go
@@ -0,0 +1,71 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command rpsbot repeatedly runs automated games, implementing all three roles. It
+publishes itself as player, judge, and scorekeeper. Then, it initiates games
+with other players, in a loop. As soon as one game is over, it starts a new one.
+
+Usage:
+ rpsbot [flags]
+
+The rpsbot flags are:
+ -acl-file=
+ File containing JSON-encoded Permissions.
+ -name=
+ Identifier to publish as (defaults to user@hostname).
+ -num-games=-1
+ Number of games to play (-1 means unlimited).
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/examples/rps/rpsbot/main.go b/examples/rps/rpsbot/main.go
index 3206d9a..4fbcaab 100644
--- a/examples/rps/rpsbot/main.go
+++ b/examples/rps/rpsbot/main.go
@@ -2,42 +2,57 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Command rpsbot repeatedly runs automated games, implementing all three roles.
-// It publishes itself as player, judge, and scorekeeper. Then, it initiates
-// games with other players, in a loop. As soon as one game is over, it starts a
-// new one.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
"fmt"
"math/rand"
"time"
"v.io/v23"
"v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/examples/rps"
"v.io/x/ref/examples/rps/internal"
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
)
var (
- name = flag.String("name", "", "identifier to publish itself as (defaults to user@hostname)")
- numGames = flag.Int("num-games", -1, "number of games to play (-1 means unlimited)")
- permsFile = flag.String("acl-file", "", "file containing the JSON-encoded Permissions")
+ name, aclFile string
+ numGames int
)
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdRoot.Flags.StringVar(&name, "name", "", "Identifier to publish as (defaults to user@hostname).")
+ cmdRoot.Flags.StringVar(&aclFile, "acl-file", "", "File containing JSON-encoded Permissions.")
+ cmdRoot.Flags.IntVar(&numGames, "num-games", -1, "Number of games to play (-1 means unlimited).")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdRoot)
+}
- auth := internal.NewAuthorizer(*permsFile)
+var cmdRoot = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runBot),
+ Name: "rpsbot",
+ Short: "repeatedly runs automated games",
+ Long: `
+Command rpsbot repeatedly runs automated games, implementing all three roles.
+It publishes itself as player, judge, and scorekeeper. Then, it initiates games
+with other players, in a loop. As soon as one game is over, it starts a new one.
+`,
+}
+
+func runBot(ctx *context.T, env *cmdline.Env, args []string) error {
+ auth := internal.NewAuthorizer(aclFile)
server, err := v23.NewServer(ctx)
if err != nil {
- vlog.Fatalf("NewServer failed: %v", err)
+ return fmt.Errorf("NewServer failed: %v", err)
}
rand.Seed(time.Now().UnixNano())
@@ -46,32 +61,33 @@
listenSpec := v23.GetListenSpec(ctx)
eps, err := server.Listen(listenSpec)
if err != nil {
- vlog.Fatalf("Listen(%v) failed: %v", listenSpec, err)
+ return fmt.Errorf("Listen(%v) failed: %v", listenSpec, err)
}
- if *name == "" {
- *name = internal.CreateName()
+ if name == "" {
+ name = internal.CreateName()
}
names := []string{
- fmt.Sprintf("rps/judge/%s", *name),
- fmt.Sprintf("rps/player/%s", *name),
- fmt.Sprintf("rps/scorekeeper/%s", *name),
+ fmt.Sprintf("rps/judge/%s", name),
+ fmt.Sprintf("rps/player/%s", name),
+ fmt.Sprintf("rps/scorekeeper/%s", name),
}
if err := server.Serve(names[0], rps.RockPaperScissorsServer(rpsService), auth); err != nil {
- vlog.Fatalf("Serve(%v) failed: %v", names[0], err)
+ return fmt.Errorf("Serve(%v) failed: %v", names[0], err)
}
for _, n := range names[1:] {
if err := server.AddName(n); err != nil {
- vlog.Fatalf("(%v) failed: %v", n, err)
+ return fmt.Errorf("(%v) failed: %v", n, err)
}
}
vlog.Infof("Listening on endpoint %s (published as %v)", eps, names)
go initiateGames(ctx, rpsService)
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
func initiateGames(ctx *context.T, rpsService *RPS) {
- for i := 0; i < *numGames || *numGames == -1; i++ {
+ for i := 0; i < numGames || numGames == -1; i++ {
if err := rpsService.Player().InitiateGame(ctx); err != nil {
vlog.Infof("Failed to initiate game: %v", err)
}
diff --git a/examples/rps/rpsplayer/doc.go b/examples/rps/rpsplayer/doc.go
new file mode 100644
index 0000000..139c943
--- /dev/null
+++ b/examples/rps/rpsplayer/doc.go
@@ -0,0 +1,68 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command rpsplayer implements the Player interface, which enables a human to play
+the game.
+
+Usage:
+ rpsplayer [flags]
+
+The rpsplayer flags are:
+ -acl-file=
+ File containing JSON-encoded Permissions.
+ -name=
+ Identifier to publish as (defaults to user@hostname).
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/examples/rps/rpsplayer/main.go b/examples/rps/rpsplayer/main.go
index 456bd80..f24515b 100644
--- a/examples/rps/rpsplayer/main.go
+++ b/examples/rps/rpsplayer/main.go
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Command rpsplayer implements the Player interface, which enables a human to
-// play the game.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
"errors"
- "flag"
"fmt"
"sort"
"strings"
@@ -21,22 +21,35 @@
"v.io/v23/rpc"
"v.io/v23/security"
"v.io/v23/vtrace"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/examples/rps"
"v.io/x/ref/examples/rps/internal"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
)
-var (
- name = flag.String("name", "", "identifier to publish itself as (defaults to user@hostname)")
- permsFile = flag.String("acl-file", "", "file containing the JSON-encoded Permissions")
-)
+var name, aclFile string
func main() {
- rootctx, shutdown := v23.Init()
- defer shutdown()
+ cmdRoot.Flags.StringVar(&name, "name", "", "Identifier to publish as (defaults to user@hostname).")
+ cmdRoot.Flags.StringVar(&aclFile, "acl-file", "", "File containing JSON-encoded Permissions.")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdRoot)
+}
+var cmdRoot = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runPlayer),
+ Name: "rpsplayer",
+ Short: "Implements the Player interface",
+ Long: `
+Command rpsplayer implements the Player interface, which enables a human to play
+the game.
+`,
+}
+
+func runPlayer(rootctx *context.T, env *cmdline.Env, args []string) error {
for {
ctx, _ := vtrace.WithNewTrace(rootctx)
if selectOne([]string{"Initiate Game", "Wait For Challenge"}) == 0 {
@@ -50,6 +63,7 @@
break
}
}
+ return nil
}
type gameChallenge struct {
@@ -119,10 +133,10 @@
if err != nil {
vlog.Fatalf("Listen(%v) failed: %v", listenSpec, err)
}
- if *name == "" {
- *name = internal.CreateName()
+ if name == "" {
+ name = internal.CreateName()
}
- if err := server.Serve(fmt.Sprintf("rps/player/%s", *name), rps.PlayerServer(&impl{ch: ch}), internal.NewAuthorizer(*permsFile)); err != nil {
+ if err := server.Serve(fmt.Sprintf("rps/player/%s", name), rps.PlayerServer(&impl{ch: ch}), internal.NewAuthorizer(aclFile)); err != nil {
vlog.Fatalf("Serve failed: %v", err)
}
vlog.Infof("Listening on endpoint /%s", ep)
diff --git a/examples/rps/rpsscorekeeper/doc.go b/examples/rps/rpsscorekeeper/doc.go
new file mode 100644
index 0000000..9a529f0
--- /dev/null
+++ b/examples/rps/rpsscorekeeper/doc.go
@@ -0,0 +1,67 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command rpsscorekeeper implements the ScoreKeeper interface. It publishes
+itself as a score keeper for the rock-paper-scissors game and prints out all the
+score cards it receives to stdout.
+
+Usage:
+ rpsscorekeeper [flags]
+
+The rpsscorekeeper flags are:
+ -acl-file=
+ File containing JSON-encoded Permissions.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/examples/rps/rpsscorekeeper/main.go b/examples/rps/rpsscorekeeper/main.go
index 8348a9d..3ec7224 100644
--- a/examples/rps/rpsscorekeeper/main.go
+++ b/examples/rps/rpsscorekeeper/main.go
@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Command rpsscorekeeper implements the ScoreKeeper interface. It publishes
-// itself as a score keeper for the rock-paper-scissors game and prints out all
-// the score cards it receives to stdout.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
"fmt"
"os"
@@ -16,16 +15,33 @@
"v.io/v23/context"
"v.io/v23/rpc"
"v.io/v23/security"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/examples/rps"
"v.io/x/ref/examples/rps/internal"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
)
-var (
- permsFile = flag.String("acl-file", "", "file containing the JSON-encoded Permissions")
-)
+var aclFile string
+
+func main() {
+ cmdRoot.Flags.StringVar(&aclFile, "acl-file", "", "File containing JSON-encoded Permissions.")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdRoot)
+}
+
+var cmdRoot = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runScoreKeeper),
+ Name: "rpsscorekeeper",
+ Short: "Implements the ScoreKeeper interface",
+ Long: `
+Command rpsscorekeeper implements the ScoreKeeper interface. It publishes
+itself as a score keeper for the rock-paper-scissors game and prints out all the
+score cards it receives to stdout.
+`,
+}
type impl struct {
ch chan rps.ScoreCard
@@ -38,13 +54,10 @@
return nil
}
-func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
-
+func runScoreKeeper(ctx *context.T, env *cmdline.Env, args []string) error {
server, err := v23.NewServer(ctx)
if err != nil {
- vlog.Fatalf("NewServer failed: %v", err)
+ return fmt.Errorf("NewServer failed: %v", err)
}
defer server.Stop()
@@ -54,18 +67,19 @@
listenSpec := v23.GetListenSpec(ctx)
ep, err := server.Listen(listenSpec)
if err != nil {
- vlog.Fatalf("Listen(%v) failed: %v", listenSpec, err)
+ return fmt.Errorf("Listen(%v) failed: %v", listenSpec, err)
}
hostname, err := os.Hostname()
if err != nil {
- vlog.Fatalf("os.Hostname failed: %v", err)
+ return fmt.Errorf("os.Hostname failed: %v", err)
}
- if err := server.Serve(fmt.Sprintf("rps/scorekeeper/%s", hostname), rps.ScoreKeeperServer(rpsService), internal.NewAuthorizer(*permsFile)); err != nil {
- vlog.Fatalf("Serve failed: %v", err)
+ if err := server.Serve(fmt.Sprintf("rps/scorekeeper/%s", hostname), rps.ScoreKeeperServer(rpsService), internal.NewAuthorizer(aclFile)); err != nil {
+ return fmt.Errorf("Serve failed: %v", err)
}
vlog.Infof("Listening on endpoint /%s", ep)
for score := range ch {
fmt.Print("======================\n", internal.FormatScoreCard(score))
}
+ return nil
}
diff --git a/examples/tunnel/tunneld/doc.go b/examples/tunnel/tunneld/doc.go
new file mode 100644
index 0000000..d300fab
--- /dev/null
+++ b/examples/tunnel/tunneld/doc.go
@@ -0,0 +1,65 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command tunneld runs the tunneld daemon, which implements the Tunnel interface.
+
+Usage:
+ tunneld [flags]
+
+The tunneld flags are:
+ -name=
+ Name to publish the server as.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/examples/tunnel/tunneld/main.go b/examples/tunnel/tunneld/main.go
index 2b0900b..05a44c2 100644
--- a/examples/tunnel/tunneld/main.go
+++ b/examples/tunnel/tunneld/main.go
@@ -2,50 +2,65 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon tunneld implements the Tunnel interface.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
"fmt"
"v.io/v23"
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/examples/tunnel"
"v.io/x/ref/lib/security/securityflag"
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
)
-var (
- name = flag.String("name", "", "name at which to publish the server")
-)
+var name string
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdRoot.Flags.StringVar(&name, "name", "", "Name to publish the server as.")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdRoot)
+}
+var cmdRoot = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runTunnelD),
+ Name: "tunneld",
+ Short: "Runs the tunneld daemon",
+ Long: `
+Command tunneld runs the tunneld daemon, which implements the Tunnel interface.
+`,
+}
+
+func runTunnelD(ctx *context.T, env *cmdline.Env, args []string) error {
auth := securityflag.NewAuthorizerOrDie()
server, err := v23.NewServer(ctx)
if err != nil {
- vlog.Fatalf("NewServer failed: %v", err)
+ return fmt.Errorf("NewServer failed: %v", err)
}
defer server.Stop()
listenSpec := v23.GetListenSpec(ctx)
if _, err := server.Listen(listenSpec); err != nil {
- vlog.Fatalf("Listen(%v) failed: %v", listenSpec, err)
+ return fmt.Errorf("Listen(%v) failed: %v", listenSpec, err)
}
- if err := server.Serve(*name, tunnel.TunnelServer(&T{}), auth); err != nil {
- vlog.Fatalf("Serve(%v) failed: %v", *name, err)
+ if err := server.Serve(name, tunnel.TunnelServer(&T{}), auth); err != nil {
+ return fmt.Errorf("Serve(%v) failed: %v", name, err)
}
status := server.Status()
vlog.Infof("Listening on: %v", status.Endpoints)
if len(status.Endpoints) > 0 {
fmt.Printf("NAME=%s\n", status.Endpoints[0].Name())
}
- vlog.Infof("Published as %q", *name)
+ vlog.Infof("Published as %q", name)
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
diff --git a/examples/tunnel/vsh/doc.go b/examples/tunnel/vsh/doc.go
new file mode 100644
index 0000000..84fbb9b
--- /dev/null
+++ b/examples/tunnel/vsh/doc.go
@@ -0,0 +1,95 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command vsh runs the Vanadium shell, a Tunnel client that can be used to run
+shell commands or start an interactive shell on a remote tunneld server.
+
+To open an interactive shell, use:
+ vsh <object name>
+
+To run a shell command, use:
+ vsh <object name> <command to run>
+
+The -L flag will forward connections from a local port to a remote address
+through the tunneld service. The flag value is localaddr,remoteaddr. E.g.
+ -L :14141,www.google.com:80
+
+vsh can't be used directly with tools like rsync because vanadium object names
+don't look like traditional hostnames, which rsync doesn't understand. For
+compatibility with such tools, vsh has a special feature that allows passing the
+vanadium object name via the VSH_NAME environment variable.
+
+ $ VSH_NAME=<object name> rsync -avh -e vsh /foo/* myhost:/foo/
+
+In this example, the "myhost" host will be substituted with $VSH_NAME by vsh and
+rsync will work as expected.
+
+Usage:
+ vsh [flags] <object name> [command]
+
+<object name> is the Vanadium object name to connect to.
+
+[command] is the shell command and args to run, for non-interactive vsh.
+
+The vsh flags are:
+ -L=
+ Forward local to remote, format is "localaddr,remoteaddr".
+ -N=false
+ Do not execute a shell. Only do port forwarding.
+ -T=false
+ Disable pseudo-terminal allocation.
+ -local_protocol=tcp
+ Local network protocol for port forwarding.
+ -remote_protocol=tcp
+ Remote network protocol for port forwarding.
+ -t=false
+ Force allocation of pseudo-terminal.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/examples/tunnel/vsh/main.go b/examples/tunnel/vsh/main.go
index 94ec21c..90cda41 100644
--- a/examples/tunnel/vsh/main.go
+++ b/examples/tunnel/vsh/main.go
@@ -2,113 +2,109 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Command vsh is a Tunnel client that can be used to start a shell on the
-// server.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
"errors"
- "flag"
"fmt"
"net"
"os"
- "path"
"strings"
- "v.io/v23"
"v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/examples/tunnel"
"v.io/x/ref/examples/tunnel/internal"
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/generic"
)
var (
- disablePty = flag.Bool("T", false, "Disable pseudo-terminal allocation.")
- forcePty = flag.Bool("t", false, "Force allocation of pseudo-terminal.")
-
- portforward = flag.String("L", "", "localaddr,remoteaddr Forward local 'localaddr' to 'remoteaddr'")
- lprotocol = flag.String("local_protocol", "tcp", "Local network protocol for port forwarding")
- rprotocol = flag.String("remote_protocol", "tcp", "Remote network protocol for port forwarding")
-
- noshell = flag.Bool("N", false, "Do not execute a shell. Only do port forwarding.")
+ disablePty, forcePty, noshell bool
+ portforward, lprotocol, rprotocol string
)
-func init() {
- flag.Usage = func() {
- bname := path.Base(os.Args[0])
- fmt.Fprintf(os.Stderr, `%s: Vanadium Shell.
+func main() {
+ cmdVsh.Flags.BoolVar(&disablePty, "T", false, "Disable pseudo-terminal allocation.")
+ cmdVsh.Flags.BoolVar(&forcePty, "t", false, "Force allocation of pseudo-terminal.")
+ cmdVsh.Flags.BoolVar(&noshell, "N", false, "Do not execute a shell. Only do port forwarding.")
+ cmdVsh.Flags.StringVar(&portforward, "L", "", `Forward local to remote, format is "localaddr,remoteaddr".`)
+ cmdVsh.Flags.StringVar(&lprotocol, "local_protocol", "tcp", "Local network protocol for port forwarding.")
+ cmdVsh.Flags.StringVar(&rprotocol, "remote_protocol", "tcp", "Remote network protocol for port forwarding.")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdVsh)
+}
-This tool is used to run shell commands or an interactive shell on a remote
-tunneld service.
+var cmdVsh = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runVsh),
+ Name: "vsh",
+ Short: "Vanadium shell",
+ Long: `
+Command vsh runs the Vanadium shell, a Tunnel client that can be used to run
+shell commands or start an interactive shell on a remote tunneld server.
To open an interactive shell, use:
- %s <object name>
+ vsh <object name>
To run a shell command, use:
- %s <object name> <command to run>
+ vsh <object name> <command to run>
The -L flag will forward connections from a local port to a remote address
through the tunneld service. The flag value is localaddr,remoteaddr. E.g.
-L :14141,www.google.com:80
-%s can't be used directly with tools like rsync because vanadium object names
+vsh can't be used directly with tools like rsync because vanadium object names
don't look like traditional hostnames, which rsync doesn't understand. For
-compatibility with such tools, %s has a special feature that allows passing the
+compatibility with such tools, vsh has a special feature that allows passing the
vanadium object name via the VSH_NAME environment variable.
- $ VSH_NAME=<object name> rsync -avh -e %s /foo/* v23:/foo/
+ $ VSH_NAME=<object name> rsync -avh -e vsh /foo/* myhost:/foo/
-In this example, the "v23" host will be substituted with $VSH_NAME by %s and
+In this example, the "myhost" host will be substituted with $VSH_NAME by vsh and
rsync will work as expected.
+`,
+ ArgsName: "<object name> [command]",
+ ArgsLong: `
+<object name> is the Vanadium object name to connect to.
-Full flags:
-`, os.Args[0], bname, bname, bname, bname, os.Args[0], bname)
- flag.PrintDefaults()
- }
+[command] is the shell command and args to run, for non-interactive vsh.
+`,
}
-func main() {
- // Work around the fact that os.Exit doesn't run deferred functions.
- os.Exit(realMain())
-}
-
-func realMain() int {
- ctx, shutdown := v23.Init()
- defer shutdown()
-
- oname, cmd, err := objectNameAndCommandLine()
+func runVsh(ctx *context.T, env *cmdline.Env, args []string) error {
+ oname, cmd, err := objectNameAndCommandLine(args)
if err != nil {
- flag.Usage()
- fmt.Fprintf(os.Stderr, "\n%v\n", err)
- return 1
+ return env.UsageErrorf("%v", err)
}
t := tunnel.TunnelClient(oname)
- if len(*portforward) > 0 {
+ if len(portforward) > 0 {
go runPortForwarding(ctx, t, oname)
}
- if *noshell {
+ if noshell {
<-signals.ShutdownOnSignals(ctx)
- return 0
+ return nil
}
opts := shellOptions(cmd)
stream, err := t.Shell(ctx, cmd, opts)
if err != nil {
- fmt.Fprintf(os.Stderr, "Error: %v\n", err)
- return 1
+ return err
}
if opts.UsePty {
saved := internal.EnterRawTerminalMode()
defer internal.RestoreTerminalSettings(saved)
}
- runIOManager(os.Stdin, os.Stdout, os.Stderr, stream)
+ runIOManager(env.Stdin, env.Stdout, env.Stderr, stream)
exitMsg := fmt.Sprintf("Connection to %s closed.", oname)
exitStatus, err := stream.Finish()
@@ -120,15 +116,15 @@
// Otherwise, the exit message might get confused with the output
// of the command that was run.
if err != nil {
- fmt.Fprintln(os.Stderr, exitMsg)
+ fmt.Fprintln(env.Stderr, exitMsg)
} else if len(cmd) == 0 {
fmt.Println(exitMsg)
}
- return int(exitStatus)
+ return cmdline.ErrExitCode(exitStatus)
}
func shellOptions(cmd string) (opts tunnel.ShellOpts) {
- opts.UsePty = (len(cmd) == 0 || *forcePty) && !*disablePty
+ opts.UsePty = (len(cmd) == 0 || forcePty) && !disablePty
opts.Environment = environment()
ws, err := internal.GetWindowSize()
if err != nil {
@@ -154,8 +150,7 @@
// send to the server. The object name is the first non-flag argument.
// The command line is the concatenation of all non-flag arguments excluding
// the object name.
-func objectNameAndCommandLine() (string, string, error) {
- args := flag.Args()
+func objectNameAndCommandLine(args []string) (string, string, error) {
if len(args) < 1 {
return "", "", errors.New("object name missing")
}
@@ -175,8 +170,8 @@
}
func runPortForwarding(ctx *context.T, t tunnel.TunnelClientMethods, oname string) {
- // *portforward is localaddr,remoteaddr
- parts := strings.Split(*portforward, ",")
+ // portforward is localaddr,remoteaddr
+ parts := strings.Split(portforward, ",")
var laddr, raddr string
if len(parts) != 2 {
vlog.Fatalf("-L flag expects 2 values separated by a comma")
@@ -184,9 +179,9 @@
laddr = parts[0]
raddr = parts[1]
- ln, err := net.Listen(*lprotocol, laddr)
+ ln, err := net.Listen(lprotocol, laddr)
if err != nil {
- vlog.Fatalf("net.Listen(%q, %q) failed: %v", *lprotocol, laddr, err)
+ vlog.Fatalf("net.Listen(%q, %q) failed: %v", lprotocol, laddr, err)
}
defer ln.Close()
vlog.VI(1).Infof("Listening on %q", ln.Addr())
@@ -196,9 +191,9 @@
vlog.Infof("Accept failed: %v", err)
continue
}
- stream, err := t.Forward(ctx, *rprotocol, raddr)
+ stream, err := t.Forward(ctx, rprotocol, raddr)
if err != nil {
- vlog.Infof("Tunnel(%q, %q) failed: %v", *rprotocol, raddr, err)
+ vlog.Infof("Tunnel(%q, %q) failed: %v", rprotocol, raddr, err)
conn.Close()
continue
}
diff --git a/lib/apilog/log.go b/lib/apilog/log.go
new file mode 100644
index 0000000..3eb4f92
--- /dev/null
+++ b/lib/apilog/log.go
@@ -0,0 +1,165 @@
+// 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.
+
+// Package apilog provides a function to be used in conjunction with vtrace
+// and logcop automatically injected logging calls. These are called on
+// entry/exit for methods that implements a v23 API call.
+package apilog
+
+import (
+ "fmt"
+ "path"
+ "reflect"
+ "runtime"
+ "sync/atomic"
+
+ "v.io/x/lib/vlog"
+
+ "v.io/v23/context"
+)
+
+// logCallLogLevel is the log level beyond which calls are logged.
+const logCallLogLevel = 1
+
+func callerFuncName() string {
+ var funcName string
+ const stackSkip = 1
+ pc, _, _, ok := runtime.Caller(stackSkip + 1)
+ if ok {
+ function := runtime.FuncForPC(pc)
+ if function != nil {
+ funcName = path.Base(function.Name())
+ }
+ }
+ return funcName
+}
+
+// TODO(cnicolaou): remove LogCall from vlog.
+
+// LogCall logs that its caller has been called given the arguments
+// passed to it. It returns a function that is supposed to be called
+// when the caller returns, logging the caller’s return along with the
+// arguments it is provided with.
+// File name and line number of the call site and a randomly generated
+// invocation identifier is logged automatically. The path through which
+// the caller function returns will be logged automatically too.
+//
+// The canonical way to use LogCall is along the lines of the following:
+//
+// func Function(ctx *context.T, a Type1, b Type2) ReturnType {
+// defer apilog.LogCall(ctx, a, b)(ctx)
+// // ... function body ...
+// return retVal
+// }
+//
+// To log the return value as the function returns, the following
+// pattern should be used. Note that pointers to the output
+// variables should be passed to the returning function, not the
+// variables themselves. Also note that nil can be used when a context.T
+// is not available:
+//
+// func Function(a Type1, b Type2) (r ReturnType) {
+// defer apilog.LogCall(nil, a, b)(nil, &r)
+// // ... function body ...
+// return computeReturnValue()
+// }
+//
+// Note that when using this pattern, you do not need to actually
+// assign anything to the named return variable explicitly. A regular
+// return statement would automatically do the proper return variable
+// assignments.
+//
+// The log injector tool will automatically insert a LogCall invocation
+// into all implementations of the public API it runs, unless a Valid
+// Log Construct is found. A Valid Log Construct is defined as one of
+// the following at the beginning of the function body (i.e. should not
+// be preceded by any non-whitespace or non-comment tokens):
+// 1. defer apilog.LogCall(optional arguments)(optional pointers to return values)
+// 2. defer apilog.LogCallf(argsFormat, optional arguments)(returnValuesFormat, optional pointers to return values)
+// 3. // nologcall
+//
+// The comment "// nologcall" serves as a hint to log injection and
+// checking tools to exclude the function from their consideration.
+// It is used as follows:
+//
+// func FunctionWithoutLogging(args ...interface{}) {
+// // nologcall
+// // ... function body ...
+// }
+//
+func LogCall(ctx *context.T, v ...interface{}) func(*context.T, ...interface{}) {
+ if !vlog.V(logCallLogLevel) { // TODO(mattr): add call to vtrace.
+ return func(*context.T, ...interface{}) {}
+ }
+ callerFuncName := callerFuncName()
+ invocationId := newInvocationIdentifier()
+ var output string
+ if len(v) > 0 {
+ output = fmt.Sprintf("call[%s %s]: args:%v", callerFuncName, invocationId, v)
+ } else {
+ output = fmt.Sprintf("call[%s %s]", callerFuncName, invocationId)
+ }
+ vlog.Info(output)
+ // TODO(mattr): annotate vtrace span.
+ return func(ctx *context.T, v ...interface{}) {
+ var output string
+ if len(v) > 0 {
+ output = fmt.Sprintf("return[%s %s]: %v", callerFuncName, invocationId, derefSlice(v))
+ } else {
+ output = fmt.Sprintf("return[%s %s]", callerFuncName, invocationId)
+ }
+ vlog.Info(output)
+ // TODO(mattr): annotate vtrace span.
+ }
+}
+
+// LogCallf behaves identically to LogCall, except it lets the caller to
+// customize the log messages via format specifiers, like the following:
+//
+// func Function(a Type1, b Type2) (r, t ReturnType) {
+// defer apilog.LogCallf(nil, "a: %v, b: %v", a, b)(nil, "(r,t)=(%v,%v)", &r, &t)
+// // ... function body ...
+// return finalR, finalT
+// }
+//
+func LogCallf(ctx *context.T, format string, v ...interface{}) func(*context.T, string, ...interface{}) {
+ if !vlog.V(logCallLogLevel) { // TODO(mattr): add call to vtrace.
+ return func(*context.T, string, ...interface{}) {}
+ }
+ callerFuncName := callerFuncName()
+ invocationId := newInvocationIdentifier()
+ output := fmt.Sprintf("call[%s %s]: %s", callerFuncName, invocationId, fmt.Sprintf(format, v...))
+ vlog.Info(output)
+ // TODO(mattr): annotate vtrace span.
+ return func(ctx *context.T, format string, v ...interface{}) {
+ output := fmt.Sprintf("return[%s %s]: %v", callerFuncName, invocationId, fmt.Sprintf(format, derefSlice(v)...))
+ vlog.Info(output)
+ // TODO(mattr): annotate vtrace span.
+ }
+}
+
+func derefSlice(slice []interface{}) []interface{} {
+ o := make([]interface{}, 0, len(slice))
+ for _, x := range slice {
+ o = append(o, reflect.Indirect(reflect.ValueOf(x)).Interface())
+ }
+ return o
+}
+
+var invocationCounter uint64 = 0
+
+// newInvocationIdentifier generates a unique identifier for a method invocation
+// to make it easier to match up log lines for the entry and exit of a function
+// when looking at a log transcript.
+func newInvocationIdentifier() string {
+ const (
+ charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"
+ charSetLen = uint64(len(charSet))
+ )
+ r := []byte{'@'}
+ for n := atomic.AddUint64(&invocationCounter, 1); n > 0; n /= charSetLen {
+ r = append(r, charSet[n%charSetLen])
+ }
+ return string(r)
+}
diff --git a/lib/v23cmd/v23cmd.go b/lib/v23cmd/v23cmd.go
index 86154a3..3174701 100644
--- a/lib/v23cmd/v23cmd.go
+++ b/lib/v23cmd/v23cmd.go
@@ -11,80 +11,83 @@
//
// The RunnerFunc package-level function allows us to write run functions of the
// form Run(ctx, env, args), retaining static type-safety, and also getting the
-// flag.Parse ordering right. In addition the Run and ParseAndRun functions may
-// be called in tests, to pass your own ctx into your command runners.
+// flag.Parse ordering right.
package v23cmd
import (
- "errors"
-
"v.io/v23"
"v.io/v23/context"
"v.io/x/lib/cmdline"
)
-var (
- ErrUnknownRunner = errors.New("v23cmd: unknown runner")
-
- // The strategy behind this package is this slice, which only grows and never
- // shrinks. Here we maintain a mapping between an index number and the
- // originally registered function, so that we can look the function up in a
- // typesafe manner.
- funcs []func(*context.T, *cmdline.Env, []string) error
- initFn = v23.Init
-)
-
-// indexRunner implements cmdline.Runner by looking up the index in the funcs
-// slice to retrieve the originally registered function.
-type indexRunner uint
-
-func (ix indexRunner) Run(env *cmdline.Env, args []string) error {
- if int(ix) < len(funcs) {
- ctx, shutdown := initFn()
- err := funcs[ix](ctx, env, args)
- shutdown()
- return err
- }
- return ErrUnknownRunner
+type runner struct {
+ run func(*context.T, *cmdline.Env, []string) error
+ init func() (*context.T, v23.Shutdown)
}
-// RunnerFunc behaves similarly to cmdline.RunnerFunc, but takes a run function
-// fn that includes a context as the first arg. The context is created via
-// v23.Init when Run is called on the returned Runner.
-func RunnerFunc(fn func(*context.T, *cmdline.Env, []string) error) cmdline.Runner {
- ix := indexRunner(len(funcs))
- funcs = append(funcs, fn)
- return ix
+func (r runner) Run(env *cmdline.Env, args []string) error {
+ ctx, shutdown := r.init()
+ defer shutdown()
+ return r.run(ctx, env, args)
}
-// Lookup returns the function registered via RunnerFunc corresponding to
-// runner, or nil if it doesn't exist.
-func Lookup(runner cmdline.Runner) func(*context.T, *cmdline.Env, []string) error {
- if ix, ok := runner.(indexRunner); ok && int(ix) < len(funcs) {
- return funcs[ix]
- }
- return nil
+// RunnerFunc is like cmdline.RunnerFunc, but takes a run function that includes
+// a context as the first arg. The context is created via v23.Init when Run is
+// called on the returned Runner.
+func RunnerFunc(run func(*context.T, *cmdline.Env, []string) error) cmdline.Runner {
+ return runner{run, v23.Init}
}
-// Run performs Lookup, and then runs the function with the given ctx, env and
-// args.
+// RunnerFuncWithInit is like RunnerFunc, but allows specifying the init
+// function used to create the context.
+//
+// This is typically used to set properties on the context before it is passed
+// to the run function. E.g. you may use this to set a deadline on the context:
+//
+// var cmdRoot = &cmdline.Command{
+// Runner: v23cmd.RunnerFuncWithInit(runRoot, initWithDeadline)
+// ...
+// }
+//
+// func runRoot(ctx *context.T, env *cmdline.Env, args []string) error {
+// ...
+// }
+//
+// func initWithDeadline() (*context.T, v23.Shutdown) {
+// ctx, shutdown := v23.Init()
+// ctx, cancel := context.WithTimeout(ctx, time.Minute)
+// return ctx, func(){ cancel(); shutdown() }
+// }
+//
+// func main() {
+// cmdline.Main(cmdRoot)
+// }
+//
+// An alternative to the above example is to call context.WithTimeout within
+// runRoot. The advantage of using RunnerFuncWithInit is that your regular code
+// can use a context with a 1 minute timeout, while your testing code can use
+// v23cmd.ParseAndRunForTest to pass a context with a 10 second timeout.
+func RunnerFuncWithInit(run func(*context.T, *cmdline.Env, []string) error, init func() (*context.T, v23.Shutdown)) cmdline.Runner {
+ return runner{run, init}
+}
+
+// ParseAndRunForTest parses the cmd with the given env and args, and calls Run
+// on the returned runner. If the runner was created by the v23cmd package,
+// calls the run function directly with the given ctx, env and args.
//
// Doesn't call v23.Init; the context initialization is up to you.
-func Run(runner cmdline.Runner, ctx *context.T, env *cmdline.Env, args []string) error {
- if fn := Lookup(runner); fn != nil {
- return fn(ctx, env, args)
- }
- return ErrUnknownRunner
-}
-
-// ParseAndRun parses the cmd with the given env and args, and calls Run to run
-// the returned runner with the ctx, env and args.
//
-// Doesn't call v23.Init; the context initialization is up to you.
-func ParseAndRun(cmd *cmdline.Command, ctx *context.T, env *cmdline.Env, args []string) error {
- runner, args, err := cmdline.Parse(cmd, env, args)
+// Only meant to be called within tests - if used in non-test code the ordering
+// of flag.Parse calls will be wrong. The correct ordering is for cmdline.Parse
+// to be called before v23.Init, but this function takes a ctx argument and then
+// calls cmdline.Parse.
+func ParseAndRunForTest(cmd *cmdline.Command, ctx *context.T, env *cmdline.Env, args []string) error {
+ r, args, err := cmdline.Parse(cmd, env, args)
if err != nil {
return err
}
- return Run(runner, ctx, env, args)
+ if x, ok := r.(runner); ok {
+ return x.run(ctx, env, args)
+ }
+ return r.Run(env, args)
}
diff --git a/lib/v23cmd/v23cmd_test.go b/lib/v23cmd/v23cmd_test.go
new file mode 100644
index 0000000..c053962
--- /dev/null
+++ b/lib/v23cmd/v23cmd_test.go
@@ -0,0 +1,117 @@
+// 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.
+
+package v23cmd
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+
+ "v.io/v23"
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
+ _ "v.io/x/ref/runtime/factories/generic"
+)
+
+var cmdRoot = &cmdline.Command{
+ Name: "root",
+ Short: "root",
+ Long: "root",
+ Children: []*cmdline.Command{cmdNoV23, cmdNoInit, cmdWithInit},
+}
+
+var cmdNoV23 = &cmdline.Command{
+ Name: "no_v23",
+ Short: "no_v23",
+ Long: "no_v23",
+ Runner: cmdline.RunnerFunc(runNoV23),
+}
+
+var cmdNoInit = &cmdline.Command{
+ Name: "no_init",
+ Short: "no_init",
+ Long: "no_init",
+ Runner: RunnerFunc(runNoInit),
+}
+
+var cmdWithInit = &cmdline.Command{
+ Name: "with_init",
+ Short: "with_init",
+ Long: "with_init",
+ Runner: RunnerFuncWithInit(runWithInit, initFunc),
+}
+
+func runNoV23(env *cmdline.Env, args []string) error {
+ fmt.Fprintf(env.Stdout, "NoV23")
+ return nil
+}
+
+func runNoInit(ctx *context.T, env *cmdline.Env, args []string) error {
+ fmt.Fprintf(env.Stdout, "NoInit %v %v", ctx.Value(initKey), ctx.Value(forTestKey))
+ return nil
+}
+
+func runWithInit(ctx *context.T, env *cmdline.Env, args []string) error {
+ fmt.Fprintf(env.Stdout, "WithInit %v %v", ctx.Value(initKey), ctx.Value(forTestKey))
+ return nil
+}
+
+const (
+ initKey = "init key"
+ initValue = "<init value>"
+ forTestKey = "for test key"
+ forTestValue = "<for test value>"
+)
+
+func initFunc() (*context.T, v23.Shutdown) {
+ ctx, shutdown := v23.Init()
+ return context.WithValue(ctx, initKey, initValue), shutdown
+}
+
+func TestParseAndRun(t *testing.T) {
+ tests := []struct {
+ cmd string
+ stdout string
+ }{
+ {"no_v23", "NoV23"},
+ {"no_init", "NoInit <nil> <nil>"},
+ {"with_init", "WithInit <init value> <nil>"},
+ }
+ for _, test := range tests {
+ var stdout bytes.Buffer
+ env := &cmdline.Env{Stdout: &stdout}
+ if err := cmdline.ParseAndRun(cmdRoot, env, []string{test.cmd}); err != nil {
+ t.Errorf("ParseAndRun failed: %v", err)
+ }
+ if got, want := stdout.String(), test.stdout; got != want {
+ t.Errorf("got stdout %q, want %q", got, want)
+ }
+ }
+}
+
+func TestParseAndRunForTest(t *testing.T) {
+ tests := []struct {
+ cmd string
+ stdout string
+ }{
+ {"no_v23", "NoV23"},
+ {"no_init", "NoInit <nil> <for test value>"},
+ {"with_init", "WithInit <nil> <for test value>"},
+ }
+ for _, test := range tests {
+ ctx, shutdown := v23.Init()
+ ctx = context.WithValue(ctx, forTestKey, forTestValue)
+
+ var stdout bytes.Buffer
+ env := &cmdline.Env{Stdout: &stdout}
+ if err := ParseAndRunForTest(cmdRoot, ctx, env, []string{test.cmd}); err != nil {
+ t.Errorf("ParseAndRunForTest failed: %v", err)
+ }
+ if got, want := stdout.String(), test.stdout; got != want {
+ t.Errorf("got stdout %q, want %q", got, want)
+ }
+ shutdown()
+ }
+}
diff --git a/lib/vdl/codegen/java/file_client_interface.go b/lib/vdl/codegen/java/file_client_interface.go
index ffc17c8..229dbfa 100644
--- a/lib/vdl/codegen/java/file_client_interface.go
+++ b/lib/vdl/codegen/java/file_client_interface.go
@@ -19,7 +19,7 @@
package {{ .PackagePath }};
{{ .ServiceDoc }}
-{{ .AccessModifier }} interface {{ .ServiceName }}Client {{ .Extends }} {
+public interface {{ .ServiceName }}Client {{ .Extends }} {
{{ range $method := .Methods }}
{{/* If this method has multiple return arguments, generate the class. */}}
{{ if $method.IsMultipleRet }}
@@ -33,8 +33,8 @@
{{/* Generate the method signature. */}}
{{ $method.Doc }}
- {{ $method.AccessModifier }} {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext context{{ $method.Args }}) throws io.v.v23.verror.VException;
- {{ $method.AccessModifier }} {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext context{{ $method.Args }}, final io.v.v23.Options vOpts) throws io.v.v23.verror.VException;
+ {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext context{{ $method.Args }}) throws io.v.v23.verror.VException;
+ {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext context{{ $method.Args }}, final io.v.v23.Options vOpts) throws io.v.v23.verror.VException;
{{ end }}
}
`
@@ -45,7 +45,6 @@
}
type clientInterfaceMethod struct {
- AccessModifier string
Args string
Doc string
Name string
@@ -85,7 +84,6 @@
retArgs[i].Type = javaType(method.OutArgs[i].Type, false, env)
}
return clientInterfaceMethod{
- AccessModifier: accessModifierForName(method.Name),
Args: javaDeclarationArgStr(method.InArgs, env, true),
Doc: method.Doc,
Name: vdlutil.FirstRuneToLower(method.Name),
@@ -105,23 +103,21 @@
methods[i] = processClientInterfaceMethod(iface, method, env)
}
data := struct {
- FileDoc string
- AccessModifier string
- Extends string
- Methods []clientInterfaceMethod
- PackagePath string
- ServiceDoc string
- ServiceName string
- Source string
+ FileDoc string
+ Extends string
+ Methods []clientInterfaceMethod
+ PackagePath string
+ ServiceDoc string
+ ServiceName string
+ Source string
}{
- FileDoc: iface.File.Package.FileDoc,
- AccessModifier: accessModifierForName(iface.Name),
- Extends: javaClientExtendsStr(iface.Embeds),
- Methods: methods,
- PackagePath: javaPath(javaGenPkgPath(iface.File.Package.GenPath)),
- ServiceDoc: javaDoc(iface.Doc),
- ServiceName: javaServiceName,
- Source: iface.File.BaseName,
+ FileDoc: iface.File.Package.FileDoc,
+ Extends: javaClientExtendsStr(iface.Embeds),
+ Methods: methods,
+ PackagePath: javaPath(javaGenPkgPath(iface.File.Package.GenPath)),
+ ServiceDoc: javaDoc(iface.Doc),
+ ServiceName: javaServiceName,
+ Source: iface.File.BaseName,
}
var buf bytes.Buffer
err := parseTmpl("client interface", clientInterfaceTmpl).Execute(&buf, data)
diff --git a/lib/vdl/codegen/java/file_server_interface.go b/lib/vdl/codegen/java/file_server_interface.go
index d3d8891..4e50cbd 100644
--- a/lib/vdl/codegen/java/file_server_interface.go
+++ b/lib/vdl/codegen/java/file_server_interface.go
@@ -22,7 +22,7 @@
@io.v.v23.vdl.VServer(
serverWrapper = {{ .ServerWrapperPath }}.class
)
-{{ .AccessModifier }} interface {{ .ServiceName }}Server {{ .Extends }} {
+public interface {{ .ServiceName }}Server {{ .Extends }} {
{{ range $method := .Methods }}
{{/* If this method has multiple return arguments, generate the class. */}}
{{ if $method.IsMultipleRet }}
@@ -36,7 +36,7 @@
{{/* Generate the method signature. */}}
{{ $method.Doc }}
- {{ $method.AccessModifier }} {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext ctx, final io.v.v23.rpc.ServerCall call{{ $method.Args }}) throws io.v.v23.verror.VException;
+ {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext ctx, final io.v.v23.rpc.ServerCall call{{ $method.Args }}) throws io.v.v23.verror.VException;
{{ end }}
}
`
@@ -58,7 +58,6 @@
}
type serverInterfaceMethod struct {
- AccessModifier string
Args string
Doc string
Name string
@@ -84,7 +83,6 @@
}
return serverInterfaceMethod{
- AccessModifier: accessModifierForName(method.Name),
Args: args,
Doc: method.Doc,
Name: vdlutil.FirstRuneToLower(method.Name),
@@ -105,7 +103,6 @@
javaServiceName := vdlutil.FirstRuneToUpper(iface.Name)
data := struct {
FileDoc string
- AccessModifier string
Extends string
Methods []serverInterfaceMethod
PackagePath string
@@ -116,7 +113,6 @@
Source string
}{
FileDoc: iface.File.Package.FileDoc,
- AccessModifier: accessModifierForName(iface.Name),
Extends: javaServerExtendsStr(iface.Embeds),
Methods: methods,
PackagePath: javaPath(javaGenPkgPath(iface.File.Package.GenPath)),
diff --git a/runtime/internal/rpc/benchmark/benchmark/doc.go b/runtime/internal/rpc/benchmark/benchmark/doc.go
new file mode 100644
index 0000000..e9eaa9a
--- /dev/null
+++ b/runtime/internal/rpc/benchmark/benchmark/doc.go
@@ -0,0 +1,105 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command benchmark runs the benchmark client.
+
+Usage:
+ benchmark [flags]
+
+The benchmark flags are:
+ -chunk_count=0
+ Number of chunks to send per streaming RPC (if zero, use non-streaming RPC).
+ -iterations=100
+ Number of iterations to run.
+ -mux_chunk_count=0
+ Number of chunks to send in background.
+ -mux_payload_size=0
+ Size of payload to send in background.
+ -payload_size=0
+ Size of payload in bytes.
+ -server=
+ Address of the server to connect to.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -test.bench=
+ regular expression to select benchmarks to run
+ -test.benchmem=false
+ print memory allocations for benchmarks
+ -test.benchtime=1s
+ approximate run time for each benchmark
+ -test.blockprofile=
+ write a goroutine blocking profile to the named file after execution
+ -test.blockprofilerate=1
+ if >= 0, calls runtime.SetBlockProfileRate()
+ -test.coverprofile=
+ write a coverage profile to the named file after execution
+ -test.cpu=
+ comma-separated list of number of CPUs to use for each test
+ -test.cpuprofile=
+ write a cpu profile to the named file during execution
+ -test.memprofile=
+ write a memory profile to the named file after execution
+ -test.memprofilerate=0
+ if >=0, sets runtime.MemProfileRate
+ -test.outputdir=
+ directory in which to write profiles
+ -test.parallel=1
+ maximum test parallelism
+ -test.run=
+ regular expression to select tests and examples to run
+ -test.short=false
+ run smaller test suite to save time
+ -test.timeout=0
+ if positive, sets an aggregate time limit for all tests
+ -test.v=false
+ verbose: print additional output
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/runtime/internal/rpc/benchmark/benchmark/main.go b/runtime/internal/rpc/benchmark/benchmark/main.go
index 1afe697..b74bd81 100644
--- a/runtime/internal/rpc/benchmark/benchmark/main.go
+++ b/runtime/internal/rpc/benchmark/benchmark/main.go
@@ -2,58 +2,70 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// A simple command-line tool to run the benchmark client.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
"fmt"
- "os"
"testing"
"time"
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
+ "v.io/x/lib/vlog"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/generic"
"v.io/x/ref/runtime/internal/rpc/benchmark/internal"
- tbm "v.io/x/ref/test/benchmark"
-
- "v.io/v23"
- "v.io/x/lib/vlog"
+ "v.io/x/ref/test/benchmark"
)
var (
- server = flag.String("server", "", "address of the server to connect to")
-
- iterations = flag.Int("iterations", 100, "number of iterations to run")
-
- chunkCnt = flag.Int("chunk_count", 0, "number of chunks to send per streaming RPC (if zero, use non-streaming RPC)")
- payloadSize = flag.Int("payload_size", 0, "size of payload in bytes")
- chunkCntMux = flag.Int("mux_chunk_count", 0, "number of chunks to send in background")
- payloadSizeMux = flag.Int("mux_payload_size", 0, "size of payload to send in background")
+ server string
+ iterations, chunkCnt, payloadSize, chunkCntMux, payloadSizeMux int
)
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdRoot.Flags.StringVar(&server, "server", "", "Address of the server to connect to.")
+ cmdRoot.Flags.IntVar(&iterations, "iterations", 100, "Number of iterations to run.")
+ cmdRoot.Flags.IntVar(&chunkCnt, "chunk_count", 0, "Number of chunks to send per streaming RPC (if zero, use non-streaming RPC).")
+ cmdRoot.Flags.IntVar(&payloadSize, "payload_size", 0, "Size of payload in bytes.")
+ cmdRoot.Flags.IntVar(&chunkCntMux, "mux_chunk_count", 0, "Number of chunks to send in background.")
+ cmdRoot.Flags.IntVar(&payloadSizeMux, "mux_payload_size", 0, "Size of payload to send in background.")
- if *chunkCntMux > 0 && *payloadSizeMux > 0 {
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdRoot)
+}
+
+var cmdRoot = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runBenchmark),
+ Name: "benchmark",
+ Short: "Run the benchmark client",
+ Long: "Command benchmark runs the benchmark client.",
+}
+
+func runBenchmark(ctx *context.T, env *cmdline.Env, args []string) error {
+ if chunkCntMux > 0 && payloadSizeMux > 0 {
dummyB := testing.B{}
- _, stop := internal.StartEchoStream(&dummyB, ctx, *server, 0, *chunkCntMux, *payloadSizeMux, nil)
+ _, stop := internal.StartEchoStream(&dummyB, ctx, server, 0, chunkCntMux, payloadSizeMux, nil)
defer stop()
- vlog.Infof("Started background streaming (chunk_size=%d, payload_size=%d)", *chunkCntMux, *payloadSizeMux)
+ vlog.Infof("Started background streaming (chunk_size=%d, payload_size=%d)", chunkCntMux, payloadSizeMux)
}
dummyB := testing.B{}
- stats := tbm.NewStats(16)
+ stats := benchmark.NewStats(16)
now := time.Now()
- if *chunkCnt == 0 {
- internal.CallEcho(&dummyB, ctx, *server, *iterations, *payloadSize, stats)
+ if chunkCnt == 0 {
+ internal.CallEcho(&dummyB, ctx, server, iterations, payloadSize, stats)
} else {
- internal.CallEchoStream(&dummyB, ctx, *server, *iterations, *chunkCnt, *payloadSize, stats)
+ internal.CallEchoStream(&dummyB, ctx, server, iterations, chunkCnt, payloadSize, stats)
}
elapsed := time.Since(now)
- fmt.Printf("iterations: %d chunk_count: %d payload_size: %d\n", *iterations, *chunkCnt, *payloadSize)
+ fmt.Printf("iterations: %d chunk_count: %d payload_size: %d\n", iterations, chunkCnt, payloadSize)
fmt.Printf("elapsed time: %v\n", elapsed)
- stats.Print(os.Stdout)
+ stats.Print(env.Stdout)
+ return nil
}
diff --git a/runtime/internal/rpc/benchmark/benchmarkd/doc.go b/runtime/internal/rpc/benchmark/benchmarkd/doc.go
new file mode 100644
index 0000000..b00942c
--- /dev/null
+++ b/runtime/internal/rpc/benchmark/benchmarkd/doc.go
@@ -0,0 +1,91 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command benchmarkd runs the benchmark server.
+
+Usage:
+ benchmarkd
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -test.bench=
+ regular expression to select benchmarks to run
+ -test.benchmem=false
+ print memory allocations for benchmarks
+ -test.benchtime=1s
+ approximate run time for each benchmark
+ -test.blockprofile=
+ write a goroutine blocking profile to the named file after execution
+ -test.blockprofilerate=1
+ if >= 0, calls runtime.SetBlockProfileRate()
+ -test.coverprofile=
+ write a coverage profile to the named file after execution
+ -test.cpu=
+ comma-separated list of number of CPUs to use for each test
+ -test.cpuprofile=
+ write a cpu profile to the named file during execution
+ -test.memprofile=
+ write a memory profile to the named file after execution
+ -test.memprofilerate=0
+ if >=0, sets runtime.MemProfileRate
+ -test.outputdir=
+ directory in which to write profiles
+ -test.parallel=1
+ maximum test parallelism
+ -test.run=
+ regular expression to select tests and examples to run
+ -test.short=false
+ run smaller test suite to save time
+ -test.timeout=0
+ if positive, sets an aggregate time limit for all tests
+ -test.v=false
+ verbose: print additional output
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/runtime/internal/rpc/benchmark/benchmarkd/main.go b/runtime/internal/rpc/benchmark/benchmarkd/main.go
index a9ce539..e5053fd 100644
--- a/runtime/internal/rpc/benchmark/benchmarkd/main.go
+++ b/runtime/internal/rpc/benchmark/benchmarkd/main.go
@@ -2,24 +2,38 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// A simple command-line tool to run the benchmark server.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
"v.io/v23"
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
-
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
"v.io/x/ref/runtime/internal/rpc/benchmark/internal"
)
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdRoot)
+}
+var cmdRoot = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runBenchmarkD),
+ Name: "benchmarkd",
+ Short: "Run the benchmark server",
+ Long: "Command benchmarkd runs the benchmark server.",
+}
+
+func runBenchmarkD(ctx *context.T, env *cmdline.Env, args []string) error {
ep, stop := internal.StartServer(ctx, v23.GetListenSpec(ctx))
vlog.Infof("Listening on %s", ep.Name())
defer stop()
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
diff --git a/runtime/internal/rpc/stream/proxy/proxy_test.go b/runtime/internal/rpc/stream/proxy/proxy_test.go
index c325e13..a438489 100644
--- a/runtime/internal/rpc/stream/proxy/proxy_test.go
+++ b/runtime/internal/rpc/stream/proxy/proxy_test.go
@@ -385,13 +385,6 @@
t.Fatal(err)
}
defer ln.Close()
- go func() {
- for {
- if _, err := ln.Accept(); err != nil {
- return
- }
- }
- }()
// Create the stream.Manager for a client.
client := manager.InternalNew(naming.FixedRoutingID(0xcccccccccccccccc))
@@ -406,6 +399,9 @@
if err != nil {
t.Fatal(err)
}
+ if _, err = ln.Accept(); err != nil {
+ t.Fatal(err)
+ }
// Trigger the idle timers.
triggerTimers()
@@ -418,7 +414,7 @@
// There is one active flow. The VC should be kept open.
time.Sleep(waitTime)
if numProcs := proxy.NumProcesses(Proxy); numProcs != 2 {
- t.Errorf("Want VC is kept open; closed")
+ t.Errorf("Want VC is kept open, but closed: number of processes: %d", numProcs)
}
flow.Close()
diff --git a/runtime/internal/rpc/stream/vc/reader.go b/runtime/internal/rpc/stream/vc/reader.go
index 80f1c9b..127d451 100644
--- a/runtime/internal/rpc/stream/vc/reader.go
+++ b/runtime/internal/rpc/stream/vc/reader.go
@@ -102,8 +102,8 @@
func (r *reader) SetDeadline(deadline <-chan struct{}) {
r.mu.Lock()
- defer r.mu.Unlock()
r.deadline = deadline
+ r.mu.Unlock()
}
func (r *reader) BytesRead() uint32 {
diff --git a/runtime/internal/rpc/stream/vc/writer.go b/runtime/internal/rpc/stream/vc/writer.go
index 32f51d3..684a357 100644
--- a/runtime/internal/rpc/stream/vc/writer.go
+++ b/runtime/internal/rpc/stream/vc/writer.go
@@ -173,8 +173,8 @@
func (w *writer) SetDeadline(deadline <-chan struct{}) {
w.mu.Lock()
- defer w.mu.Unlock()
w.deadline = deadline
+ w.mu.Unlock()
}
// Release allows the next 'bytes' of data to be removed from the buffer queue
diff --git a/runtime/internal/rpc/stress/stress/doc.go b/runtime/internal/rpc/stress/stress/doc.go
new file mode 100644
index 0000000..5e37ed6
--- /dev/null
+++ b/runtime/internal/rpc/stress/stress/doc.go
@@ -0,0 +1,156 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command stress is a tool to stress/load test RPC by issuing randomly generated
+requests.
+
+Usage:
+ stress <command>
+
+The stress commands are:
+ stress Run stress test
+ stats Print out stress stats of servers
+ load Run load test
+ stop Stop servers
+ help Display help for commands or topics
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+
+Stress stress
+
+Run stress test
+
+Usage:
+ stress stress [flags] <server> ...
+
+<server> ... A list of servers to connect to.
+
+The stress stress flags are:
+ -duration=1m0s
+ duration of the test to run
+ -format=text
+ Stats output format; either text or json
+ -max-chunk-count=1000
+ maximum number of chunks to send per streaming RPC
+ -max-payload-size=10000
+ maximum size of payload in bytes
+ -workers=1
+ number of test workers to run
+
+Stress stats
+
+Print out stress stats of servers
+
+Usage:
+ stress stats [flags] <server> ...
+
+<server> ... A list of servers to connect to.
+
+The stress stats flags are:
+ -format=text
+ Stats output format; either text or json
+
+Stress load
+
+Run load test
+
+Usage:
+ stress load [flags] <server> ...
+
+<server> ... A list of servers to connect to.
+
+The stress load flags are:
+ -cpu=0
+ number of cpu cores to use; if zero, use the number of servers to test
+ -duration=1m0s
+ duration of the test to run
+ -format=text
+ Stats output format; either text or json
+ -payload-size=1000
+ size of payload in bytes
+
+Stress stop
+
+Stop servers
+
+Usage:
+ stress stop <server> ...
+
+<server> ... A list of servers to stop.
+
+Stress help
+
+Help with no args displays the usage of the parent command.
+
+Help with args displays the usage of the specified sub-command or help topic.
+
+"help ..." recursively displays help for all commands and topics.
+
+Usage:
+ stress help [flags] [command/topic ...]
+
+[command/topic ...] optionally identifies a specific sub-command or help topic.
+
+The stress help flags are:
+ -style=compact
+ The formatting style for help output:
+ compact - Good for compact cmdline output.
+ full - Good for cmdline output, shows all global flags.
+ godoc - Good for godoc processing.
+ Override the default by setting the CMDLINE_STYLE environment variable.
+ -width=<terminal width>
+ Format output to this target width in runes, or unlimited if width < 0.
+ Defaults to the terminal width if available. Override the default by setting
+ the CMDLINE_WIDTH environment variable.
+*/
+package main
diff --git a/runtime/internal/rpc/stress/stress/main.go b/runtime/internal/rpc/stress/stress/main.go
index 8645cad..03d3950 100644
--- a/runtime/internal/rpc/stress/stress/main.go
+++ b/runtime/internal/rpc/stress/stress/main.go
@@ -2,6 +2,9 @@
// 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 $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go .
+
package main
import (
@@ -37,7 +40,7 @@
cmdRoot := &cmdline.Command{
Name: "stress",
Short: "Tool to stress/load test RPC",
- Long: "Tool to stress/load test RPC by issuing randomly generated requests",
+ Long: "Command stress is a tool to stress/load test RPC by issuing randomly generated requests.",
Children: []*cmdline.Command{
cmdStressTest,
cmdStressStats,
@@ -45,5 +48,6 @@
cmdStopServers,
},
}
+ cmdline.HideGlobalFlagsExcept()
cmdline.Main(cmdRoot)
}
diff --git a/runtime/internal/rpc/stress/stressd/doc.go b/runtime/internal/rpc/stress/stressd/doc.go
new file mode 100644
index 0000000..29e8a4c
--- /dev/null
+++ b/runtime/internal/rpc/stress/stressd/doc.go
@@ -0,0 +1,65 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command stressd runs the stress-test server.
+
+Usage:
+ stressd [flags]
+
+The stressd flags are:
+ -duration=0
+ Duration of the stress test to run; if zero, there is no limit.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/runtime/internal/rpc/stress/stressd/main.go b/runtime/internal/rpc/stress/stressd/main.go
index 3286e7f..71ae935 100644
--- a/runtime/internal/rpc/stress/stressd/main.go
+++ b/runtime/internal/rpc/stress/stressd/main.go
@@ -2,38 +2,50 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// A simple command-line tool to run the benchmark server.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
+ "fmt"
"runtime"
"time"
"v.io/v23"
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
-
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/static"
"v.io/x/ref/runtime/internal/rpc/stress/internal"
)
-var (
- duration = flag.Duration("duration", 0, "duration of the stress test to run; if zero, there is no limit.")
-)
+var duration time.Duration
func main() {
- runtime.GOMAXPROCS(runtime.NumCPU())
+ cmdRoot.Flags.DurationVar(&duration, "duration", 0, "Duration of the stress test to run; if zero, there is no limit.")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdRoot)
+}
- ctx, shutdown := v23.Init()
- defer shutdown()
+var cmdRoot = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runStressD),
+ Name: "stressd",
+ Short: "Run the stress-test server",
+ Long: "Command stressd runs the stress-test server.",
+}
+
+func runStressD(ctx *context.T, env *cmdline.Env, args []string) error {
+ runtime.GOMAXPROCS(runtime.NumCPU())
server, ep, stop := internal.StartServer(ctx, v23.GetListenSpec(ctx))
vlog.Infof("listening on %s", ep.Name())
var timeout <-chan time.Time
- if *duration > 0 {
- timeout = time.After(*duration)
+ if duration > 0 {
+ timeout = time.After(duration)
}
select {
case <-timeout:
@@ -42,7 +54,8 @@
}
if err := server.Stop(); err != nil {
- vlog.Fatalf("Stop() failed: %v", err)
+ return fmt.Errorf("Stop() failed: %v", err)
}
vlog.Info("stopped.")
+ return nil
}
diff --git a/services/agent/agentd/doc.go b/services/agent/agentd/doc.go
new file mode 100644
index 0000000..58fce80
--- /dev/null
+++ b/services/agent/agentd/doc.go
@@ -0,0 +1,78 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command agentd runs the security agent daemon, which holds a private key in
+memory and makes it available to a subprocess.
+
+Loads the private key specified in privatekey.pem in V23_CREDENTIALS into
+memory, then starts the specified command with access to the private key via the
+agent protocol instead of directly reading from disk.
+
+Usage:
+ agentd [flags] command [command_args...]
+
+The command is started as a subprocess with the given [command_args...].
+
+The agentd flags are:
+ -additional-principals=
+ If non-empty, allow for the creation of new principals and save them in this
+ directory.
+ -new-principal-blessing-name=
+ If creating a new principal (--v23.credentials does not exist), then have it
+ blessed with this name.
+ -no-passphrase=false
+ If true, user will not be prompted for principal encryption passphrase.
+ -restart-exit-code=
+ If non-empty, will restart the command when it exits, provided that the
+ command's exit code matches the value of this flag. The value must be an
+ integer, or an integer preceded by '!' (in which case all exit codes except
+ the flag will trigger a restart).
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/agent/agentd/main.go b/services/agent/agentd/main.go
index 5956c79..7a0c214 100644
--- a/services/agent/agentd/main.go
+++ b/services/agent/agentd/main.go
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon agentd holds a private key in memory and makes it available to a
-// subprocess via the agent protocol.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
@@ -21,6 +22,7 @@
"v.io/v23"
"v.io/v23/security"
"v.io/v23/verror"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/envvar"
vsecurity "v.io/x/ref/lib/security"
@@ -37,46 +39,51 @@
errCantReadPassphrase = verror.Register(pkgPath+".errCantReadPassphrase", verror.NoRetry, "{1:}{2:} failed to read passphrase{:_}")
errNeedPassphrase = verror.Register(pkgPath+".errNeedPassphrase", verror.NoRetry, "{1:}{2:} Passphrase required for decrypting principal{:_}")
errCantParseRestartExitCode = verror.Register(pkgPath+".errCantParseRestartExitCode", verror.NoRetry, "{1:}{2:} Failed to parse restart exit code{:_}")
+
+ keypath, restartExitCode, newname string
+ noPassphrase bool
)
-var (
- keypath = flag.String("additional-principals", "", "If non-empty, allow for the creation of new principals and save them in this directory.")
- noPassphrase = flag.Bool("no-passphrase", false, "If true, user will not be prompted for principal encryption passphrase.")
+func main() {
+ cmdAgentD.Flags.StringVar(&keypath, "additional-principals", "", "If non-empty, allow for the creation of new principals and save them in this directory.")
+ cmdAgentD.Flags.BoolVar(&noPassphrase, "no-passphrase", false, "If true, user will not be prompted for principal encryption passphrase.")
// TODO(caprita): We use the exit code of the child to determine if the
// agent should restart it. Consider changing this to use the unix
// socket for this purpose.
- restartExitCode = flag.String("restart-exit-code", "", "If non-empty, will restart the command when it exits, provided that the command's exit code matches the value of this flag. The value must be an integer, or an integer preceded by '!' (in which case all exit codes except the flag will trigger a restart.")
+ cmdAgentD.Flags.StringVar(&restartExitCode, "restart-exit-code", "", "If non-empty, will restart the command when it exits, provided that the command's exit code matches the value of this flag. The value must be an integer, or an integer preceded by '!' (in which case all exit codes except the flag will trigger a restart).")
- newname = flag.String("new-principal-blessing-name", "", "If creating a new principal (--v23.credentials does not exist), then have it blessed with this name.")
-)
+ cmdAgentD.Flags.StringVar(&newname, "new-principal-blessing-name", "", "If creating a new principal (--v23.credentials does not exist), then have it blessed with this name.")
-func main() {
- os.Exit(Main())
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdAgentD)
}
-func Main() int {
- flag.Usage = func() {
- fmt.Fprintf(os.Stderr, `Usage: %s [agent options] command command_args...
+var cmdAgentD = &cmdline.Command{
+ Runner: cmdline.RunnerFunc(runAgentD),
+ Name: "agentd",
+ Short: "Holds a private key in memory and makes it available to a subprocess",
+ Long: fmt.Sprintf(`
+Command agentd runs the security agent daemon, which holds a private key in
+memory and makes it available to a subprocess.
Loads the private key specified in privatekey.pem in %v into memory, then
starts the specified command with access to the private key via the
agent protocol instead of directly reading from disk.
+`, envvar.Credentials),
+ ArgsName: "command [command_args...]",
+ ArgsLong: `
+The command is started as a subprocess with the given [command_args...].
+`,
+}
-`, os.Args[0], envvar.Credentials)
- flag.PrintDefaults()
- }
- flag.Parse()
- if len(flag.Args()) < 1 {
- fmt.Fprintln(os.Stderr, "Need at least one argument.")
- flag.Usage()
- return 1
+func runAgentD(env *cmdline.Env, args []string) error {
+ if len(args) < 1 {
+ return env.UsageErrorf("Need at least one argument.")
}
var restartOpts restartOptions
if err := restartOpts.parse(); err != nil {
- fmt.Fprintln(os.Stderr, err)
- flag.Usage()
- return 1
+ return env.UsageErrorf("%v", err)
}
// This is a bit tricky. We're trying to share the runtime's
@@ -93,26 +100,26 @@
f.Set("")
}
if len(dir) == 0 {
- vlog.Fatalf("The %v environment variable must be set to a directory: %q", envvar.Credentials, os.Getenv(envvar.Credentials))
+ return env.UsageErrorf("The %v environment variable must be set to a directory: %q", envvar.Credentials, os.Getenv(envvar.Credentials))
}
p, passphrase, err := newPrincipalFromDir(dir)
if err != nil {
- vlog.Fatalf("failed to create new principal from dir(%s): %v", dir, err)
+ return fmt.Errorf("failed to create new principal from dir(%s): %v", dir, err)
}
// Clear out the environment variable before v23.Init.
if err = envvar.ClearCredentials(); err != nil {
- vlog.Fatalf("envvar.ClearCredentials: %v", err)
+ return fmt.Errorf("envvar.ClearCredentials: %v", err)
}
ctx, shutdown := v23.Init()
defer shutdown()
if ctx, err = v23.WithPrincipal(ctx, p); err != nil {
- vlog.Panicf("failed to set principal for ctx: %v", err)
+ return fmt.Errorf("failed to set principal for ctx: %v", err)
}
- if *keypath == "" && passphrase != nil {
+ if keypath == "" && passphrase != nil {
// If we're done with the passphrase, zero it out so it doesn't stay in memory
for i := range passphrase {
passphrase[i] = 0
@@ -124,15 +131,15 @@
var sock, mgrSock *os.File
var endpoint string
if sock, endpoint, err = server.RunAnonymousAgent(ctx, p, childAgentFd); err != nil {
- vlog.Fatalf("RunAnonymousAgent: %v", err)
+ return fmt.Errorf("RunAnonymousAgent: %v", err)
}
if err = os.Setenv(envvar.AgentEndpoint, endpoint); err != nil {
- vlog.Fatalf("setenv: %v", err)
+ return fmt.Errorf("setenv: %v", err)
}
- if *keypath != "" {
- if mgrSock, err = server.RunKeyManager(ctx, *keypath, passphrase); err != nil {
- vlog.Fatalf("RunKeyManager: %v", err)
+ if keypath != "" {
+ if mgrSock, err = server.RunKeyManager(ctx, keypath, passphrase); err != nil {
+ return fmt.Errorf("RunKeyManager: %v", err)
}
}
@@ -140,9 +147,9 @@
for {
// Run the client and wait for it to finish.
cmd := exec.Command(flag.Args()[0], flag.Args()[1:]...)
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
+ cmd.Stdin = env.Stdin
+ cmd.Stdout = env.Stdout
+ cmd.Stderr = env.Stderr
cmd.ExtraFiles = []*os.File{sock}
if mgrSock != nil {
@@ -151,7 +158,7 @@
err = cmd.Start()
if err != nil {
- vlog.Fatalf("Error starting child: %v", err)
+ return fmt.Errorf("Error starting child: %v", err)
}
shutdown := make(chan struct{})
go func() {
@@ -178,7 +185,10 @@
// right after cmd.Start().
sock.Close()
mgrSock.Close()
- return exitCode
+ if exitCode != 0 {
+ return cmdline.ErrExitCode(exitCode)
+ }
+ return nil
}
func newPrincipalFromDir(dir string) (security.Principal, []byte, error) {
@@ -195,7 +205,7 @@
func handleDoesNotExist(dir string) (security.Principal, []byte, error) {
fmt.Println("Private key file does not exist. Creating new private key...")
var pass []byte
- if !*noPassphrase {
+ if !noPassphrase {
var err error
if pass, err = getPassword("Enter passphrase (entering nothing will store unencrypted): "); err != nil {
return nil, nil, verror.New(errCantReadPassphrase, nil, err)
@@ -205,7 +215,7 @@
if err != nil {
return nil, pass, err
}
- name := *newname
+ name := newname
if len(name) == 0 {
name = "agent_principal"
}
@@ -214,7 +224,7 @@
}
func handlePassphrase(dir string) (security.Principal, []byte, error) {
- if *noPassphrase {
+ if noPassphrase {
return nil, nil, verror.New(errNeedPassphrase, nil)
}
pass, err := getPassword("Private key file is encrypted. Please enter passphrase.\nEnter passphrase: ")
@@ -300,7 +310,7 @@
}
func (opts *restartOptions) parse() error {
- code := *restartExitCode
+ code := restartExitCode
if code == "" {
return nil
}
diff --git a/services/agent/agentlib/agent_v23_test.go b/services/agent/agentlib/agent_v23_test.go
index cecdcc0..dcd9646 100644
--- a/services/agent/agentlib/agent_v23_test.go
+++ b/services/agent/agentlib/agent_v23_test.go
@@ -48,15 +48,18 @@
fmt.Fprintln(agent.Stdin(), "BADPASSWORD")
agent.ExpectEOF()
var stdout, stderr bytes.Buffer
- if err := agent.Wait(&stdout, &stderr); err == nil {
+ err := agent.Wait(&stdout, &stderr)
+ if err == nil {
i.Fatalf("expected an error.STDOUT:%v\nSTDERR:%v\n", stdout.String(), stderr.String())
- } else if got, want := err.Error(), "exit status 255"; got != want {
- i.Fatalf("Got %q, want %q", got, want)
- } else if got, want := stderr.String(), "passphrase incorrect for decrypting private key"; !strings.Contains(got, want) {
- i.Fatalf("Got %q, wanted it to contain %q", got, want)
+ }
+ if got, want := err.Error(), "exit status 1"; got != want {
+ i.Errorf("Got %q, want %q", got, want)
+ }
+ if got, want := stderr.String(), "passphrase incorrect for decrypting private key"; !strings.Contains(got, want) {
+ i.Errorf("Got %q, wanted it to contain %q", got, want)
}
if err := agent.Error(); err != nil {
- i.Fatal(err)
+ i.Error(err)
}
}
diff --git a/services/agent/internal/pingpong/doc.go b/services/agent/internal/pingpong/doc.go
new file mode 100644
index 0000000..606ad9a
--- /dev/null
+++ b/services/agent/internal/pingpong/doc.go
@@ -0,0 +1,60 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command pingpong runs a pingpong client or server. If no args are given the
+server is run, otherwise the client is run.
+
+Usage:
+ pingpong [server]
+
+If [server] is specified, pingpong is run in client mode, and connects to the
+named server.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/agent/internal/pingpong/main.go b/services/agent/internal/pingpong/main.go
index 559d4a1..24265f7 100644
--- a/services/agent/internal/pingpong/main.go
+++ b/services/agent/internal/pingpong/main.go
@@ -2,22 +2,46 @@
// 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 $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
"fmt"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/rpc"
"v.io/v23/security"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/generic"
)
+func main() {
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdPingPong)
+}
+
+var cmdPingPong = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runPingPong),
+ Name: "pingpong",
+ Short: "Runs pingpong client or server",
+ Long: `
+Command pingpong runs a pingpong client or server. If no args are given the
+server is run, otherwise the client is run.
+`,
+ ArgsName: "[server]",
+ ArgsLong: `
+If [server] is specified, pingpong is run in client mode, and connects to the
+named server.
+`,
+}
+
type pongd struct{}
func (f *pongd) Ping(ctx *context.T, call rpc.ServerCall, message string) (result string, err error) {
@@ -26,49 +50,48 @@
return fmt.Sprintf("pong (client:%v server:%v)", client, server), nil
}
-func clientMain(ctx *context.T, server string) {
+func clientMain(ctx *context.T, server string) error {
fmt.Println("Pinging...")
pong, err := PingPongClient(server).Ping(ctx, "ping")
if err != nil {
- vlog.Fatal("error pinging: ", err)
+ return fmt.Errorf("error pinging: %v", err)
}
fmt.Println(pong)
+ return nil
}
-func serverMain(ctx *context.T) {
+func serverMain(ctx *context.T) error {
s, err := v23.NewServer(ctx)
if err != nil {
- vlog.Fatal("failure creating server: ", err)
+ return fmt.Errorf("failure creating server: %v", err)
}
vlog.Info("Waiting for ping")
spec := rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}}
- if endpoints, err := s.Listen(spec); err == nil {
- fmt.Printf("NAME=%v\n", endpoints[0].Name())
- } else {
- vlog.Fatal("error listening to service:", err)
+ endpoints, err := s.Listen(spec)
+ if err != nil {
+ return fmt.Errorf("error listening to service: %v", err)
}
+ fmt.Printf("NAME=%v\n", endpoints[0].Name())
// Provide an empty name, no need to mount on any mounttable.
//
// Use the default authorization policy (nil authorizer), which will
// only authorize clients if the blessings of the client is a prefix of
// that of the server or vice-versa.
if err := s.Serve("", PingPongServer(&pongd{}), nil); err != nil {
- vlog.Fatal("error serving service: ", err)
+ return fmt.Errorf("error serving service: %v", err)
}
// Wait forever.
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
-func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
-
- if len(flag.Args()) == 0 {
- serverMain(ctx)
- } else if len(flag.Args()) == 1 {
- clientMain(ctx, flag.Args()[0])
- } else {
- vlog.Fatalf("Expected at most one argument, the object name of the server. Got %v", flag.Args())
+func runPingPong(ctx *context.T, env *cmdline.Env, args []string) error {
+ switch len(args) {
+ case 0:
+ return serverMain(ctx)
+ case 1:
+ return clientMain(ctx, args[0])
}
+ return env.UsageErrorf("Too many arguments")
}
diff --git a/services/agent/internal/test_principal/doc.go b/services/agent/internal/test_principal/doc.go
new file mode 100644
index 0000000..d99fe3f
--- /dev/null
+++ b/services/agent/internal/test_principal/doc.go
@@ -0,0 +1,56 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command test_principal runs tests against a principal.
+
+Usage:
+ test_principal
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/agent/internal/test_principal/main.go b/services/agent/internal/test_principal/main.go
index 3da8db6..120e55f 100644
--- a/services/agent/internal/test_principal/main.go
+++ b/services/agent/internal/test_principal/main.go
@@ -2,6 +2,9 @@
// 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 $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
@@ -14,8 +17,11 @@
"runtime"
"v.io/v23"
+ "v.io/v23/context"
"v.io/v23/security"
+ "v.io/x/lib/cmdline"
"v.io/x/ref/envvar"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/generic"
)
@@ -29,25 +35,23 @@
}
func main() {
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdTestPrincipal)
+}
+
+var cmdTestPrincipal = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runTestPrincipal),
+ Name: "test_principal",
+ Short: "Runs tests against a principal",
+ Long: "Command test_principal runs tests against a principal.",
+}
+
+func runTestPrincipal(ctx *context.T, env *cmdline.Env, args []string) error {
var errors []string
- defer func() {
- if len(errors) == 0 {
- return
- }
- // Print out all errors and exit with failure.
- for _, e := range errors {
- fmt.Fprintln(os.Stderr, e)
- }
- os.Exit(1)
- }()
errorf := func(format string, args ...interface{}) {
_, file, line, _ := runtime.Caller(1)
errors = append(errors, fmt.Sprintf("%v:%d: %v", file, line, fmt.Sprintf(format, args...)))
}
-
- ctx, shutdown := v23.Init()
- defer shutdown()
-
p := v23.GetPrincipal(ctx)
// Make sure we're running under a pristine agent to begin with.
// The agent aims to be transparent, so use a collection of heuristics
@@ -131,4 +135,13 @@
if forpeer := p.BlessingStore().ForPeer("superman/friend"); !reflect.DeepEqual(forpeer, b) {
errorf("BlessingStore().ForPeer returned %v and not %v", forpeer, b)
}
+
+ if len(errors) > 0 {
+ // Print out all errors and exit with failure.
+ for _, e := range errors {
+ fmt.Fprintln(env.Stderr, e)
+ }
+ return cmdline.ErrExitCode(1)
+ }
+ return nil
}
diff --git a/services/application/application/impl_test.go b/services/application/application/impl_test.go
index d9b872f..7b55427 100644
--- a/services/application/application/impl_test.go
+++ b/services/application/application/impl_test.go
@@ -157,7 +157,7 @@
profile := "myprofile"
// Test the 'Match' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"match", appName, profile}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"match", appName, profile}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := jsonEnv, strings.TrimSpace(stdout.String()); got != expected {
@@ -178,7 +178,7 @@
if err = f.Close(); err != nil {
t.Fatalf("%v", err)
}
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"put", appName, profile, fileName}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"put", appName, profile, fileName}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := "Application envelope added successfully.", strings.TrimSpace(stdout.String()); got != expected {
@@ -187,7 +187,7 @@
stdout.Reset()
// Test the 'remove' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"remove", appName, profile}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"remove", appName, profile}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := "Application envelope removed successfully.", strings.TrimSpace(stdout.String()); got != expected {
@@ -197,7 +197,7 @@
// Test the 'edit' command. (nothing changed)
os.Setenv("EDITOR", "true")
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"edit", appName, profile}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"edit", appName, profile}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := "Nothing changed", strings.TrimSpace(stdout.String()); got != expected {
@@ -207,7 +207,7 @@
// Test the 'edit' command.
os.Setenv("EDITOR", "perl -pi -e 's/arg1/arg111/'")
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"edit", appName, profile}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"edit", appName, profile}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := "Application envelope updated successfully.", strings.TrimSpace(stdout.String()); got != expected {
diff --git a/services/application/applicationd/doc.go b/services/application/applicationd/doc.go
new file mode 100644
index 0000000..f86ff46
--- /dev/null
+++ b/services/application/applicationd/doc.go
@@ -0,0 +1,68 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command applicationd runs the application daemon, which implements the
+v.io/x/ref/services/repository.Application interface.
+
+Usage:
+ applicationd [flags]
+
+The applicationd flags are:
+ -name=
+ Name to mount the application repository as.
+ -store=
+ Local directory to store application envelopes in.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/application/applicationd/main.go b/services/application/applicationd/main.go
index 1ba1cbf..0d3756c 100644
--- a/services/application/applicationd/main.go
+++ b/services/application/applicationd/main.go
@@ -2,58 +2,74 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon applicationd implements the v.io/x/ref/services/repository.Application
-// interface.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
+ "fmt"
"v.io/v23"
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
-
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
)
-var (
- name = flag.String("name", "", "name to mount the application repository as")
- store = flag.String("store", "", "local directory to store application envelopes in")
-)
+var name, store string
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdAppD.Flags.StringVar(&name, "name", "", "Name to mount the application repository as.")
+ cmdAppD.Flags.StringVar(&store, "store", "", "Local directory to store application envelopes in.")
- if *store == "" {
- vlog.Fatalf("Specify a directory for storing application envelopes using --store=<name>")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdAppD)
+}
+
+var cmdAppD = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runAppD),
+ Name: "applicationd",
+ Short: "Runs the application daemon.",
+ Long: `
+Command applicationd runs the application daemon, which implements the
+v.io/x/ref/services/repository.Application interface.
+`,
+}
+
+func runAppD(ctx *context.T, env *cmdline.Env, args []string) error {
+ if store == "" {
+ return env.UsageErrorf("Specify a directory for storing application envelopes using --store=<name>")
}
server, err := v23.NewServer(ctx)
if err != nil {
- vlog.Fatalf("NewServer() failed: %v", err)
+ return fmt.Errorf("NewServer() failed: %v", err)
}
defer server.Stop()
- dispatcher, err := NewDispatcher(*store)
+ dispatcher, err := NewDispatcher(store)
if err != nil {
- vlog.Fatalf("NewDispatcher() failed: %v", err)
+ return fmt.Errorf("NewDispatcher() failed: %v", err)
}
ls := v23.GetListenSpec(ctx)
endpoints, err := server.Listen(ls)
if err != nil {
- vlog.Fatalf("Listen(%s) failed: %v", ls, err)
+ return fmt.Errorf("Listen(%s) failed: %v", ls, err)
}
- if err := server.ServeDispatcher(*name, dispatcher); err != nil {
- vlog.Fatalf("Serve(%v) failed: %v", *name, err)
+ if err := server.ServeDispatcher(name, dispatcher); err != nil {
+ return fmt.Errorf("Serve(%v) failed: %v", name, err)
}
epName := endpoints[0].Name()
- if *name != "" {
- vlog.Infof("Application repository serving at %q (%q)", *name, epName)
+ if name != "" {
+ vlog.Infof("Application repository serving at %q (%q)", name, epName)
} else {
vlog.Infof("Application repository serving at %q", epName)
}
// Wait until shutdown.
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
diff --git a/services/binary/binary/impl_test.go b/services/binary/binary/impl_test.go
index 85414b3..36a5c01 100644
--- a/services/binary/binary/impl_test.go
+++ b/services/binary/binary/impl_test.go
@@ -141,7 +141,7 @@
env := &cmdline.Env{Stdout: &out, Stderr: &out}
// Test the 'delete' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"delete", naming.JoinAddressName(endpoint.String(), "exists")}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"delete", naming.JoinAddressName(endpoint.String(), "exists")}); err != nil {
t.Fatalf("%v failed: %v\n%v", "delete", err, out.String())
}
if expected, got := "Binary deleted successfully", strings.TrimSpace(out.String()); got != expected {
@@ -157,7 +157,7 @@
defer os.RemoveAll(dir)
file := path.Join(dir, "testfile")
defer os.Remove(file)
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"download", naming.JoinAddressName(endpoint.String(), "exists"), file}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"download", naming.JoinAddressName(endpoint.String(), "exists"), file}); err != nil {
t.Fatalf("%v failed: %v\n%v", "download", err, out.String())
}
if expected, got := "Binary downloaded to file "+file, strings.TrimSpace(out.String()); got != expected {
@@ -173,13 +173,13 @@
out.Reset()
// Test the 'upload' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"upload", naming.JoinAddressName(endpoint.String(), "exists"), file}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"upload", naming.JoinAddressName(endpoint.String(), "exists"), file}); err != nil {
t.Fatalf("%v failed: %v\n%v", "upload", err, out.String())
}
out.Reset()
// Test the 'url' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"url", naming.JoinAddressName(endpoint.String(), "")}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"url", naming.JoinAddressName(endpoint.String(), "")}); err != nil {
t.Fatalf("%v failed: %v\n%v", "url", err, out.String())
}
if expected, got := "test-download-url", strings.TrimSpace(out.String()); got != expected {
diff --git a/services/binary/binaryd/doc.go b/services/binary/binaryd/doc.go
new file mode 100644
index 0000000..ab358a6
--- /dev/null
+++ b/services/binary/binaryd/doc.go
@@ -0,0 +1,70 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command binaryd runs the binary daemon, which implements the
+v.io/v23/services/repository.Binary interface.
+
+Usage:
+ binaryd [flags]
+
+The binaryd flags are:
+ -http=:0
+ TCP address on which the HTTP server runs.
+ -name=
+ Name to mount the binary repository as.
+ -root-dir=
+ Root directory for the binary repository.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/binary/binaryd/main.go b/services/binary/binaryd/main.go
index efb5761..883f080 100644
--- a/services/binary/binaryd/main.go
+++ b/services/binary/binaryd/main.go
@@ -2,32 +2,50 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon binaryd implements the v.io/v23/services/repository.Binary interface.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
+ "fmt"
"net"
"net/http"
"os"
"v.io/v23"
"v.io/v23/context"
- "v.io/x/lib/vlog"
-
+ "v.io/x/lib/cmdline"
"v.io/x/lib/netstate"
+ "v.io/x/lib/vlog"
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
"v.io/x/ref/services/internal/binarylib"
)
const defaultDepth = 3
-var (
- name = flag.String("name", "", "name to mount the binary repository as")
- rootDirFlag = flag.String("root-dir", "", "root directory for the binary repository")
- httpAddr = flag.String("http", ":0", "TCP address on which the HTTP server runs")
-)
+var name, rootDirFlag, httpAddr string
+
+func main() {
+ cmdBinaryD.Flags.StringVar(&name, "name", "", "Name to mount the binary repository as.")
+ cmdBinaryD.Flags.StringVar(&rootDirFlag, "root-dir", "", "Root directory for the binary repository.")
+ cmdBinaryD.Flags.StringVar(&httpAddr, "http", ":0", "TCP address on which the HTTP server runs.")
+
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdBinaryD)
+}
+
+var cmdBinaryD = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runBinaryD),
+ Name: "binaryd",
+ Short: "Runs the binary daemon.",
+ Long: `
+Command binaryd runs the binary daemon, which implements the
+v.io/v23/services/repository.Binary interface.
+`,
+}
// toIPPort tries to swap in the 'best' accessible IP for the host part of the
// address, if the provided address has an unspecified IP.
@@ -52,27 +70,21 @@
return net.JoinHostPort(host, port)
}
-func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
-
- rootDir, err := binarylib.SetupRootDir(*rootDirFlag)
+func runBinaryD(ctx *context.T, env *cmdline.Env, args []string) error {
+ rootDir, err := binarylib.SetupRootDir(rootDirFlag)
if err != nil {
- vlog.Errorf("SetupRootDir(%q) failed: %v", *rootDirFlag, err)
- return
+ return fmt.Errorf("SetupRootDir(%q) failed: %v", rootDirFlag, err)
}
vlog.Infof("Binary repository rooted at %v", rootDir)
- listener, err := net.Listen("tcp", *httpAddr)
+ listener, err := net.Listen("tcp", httpAddr)
if err != nil {
- vlog.Errorf("Listen(%s) failed: %v", *httpAddr, err)
- os.Exit(1)
+ return fmt.Errorf("Listen(%s) failed: %v", httpAddr, err)
}
rootURL := toIPPort(ctx, listener.Addr().String())
state, err := binarylib.NewState(rootDir, rootURL, defaultDepth)
if err != nil {
- vlog.Errorf("NewState(%v, %v, %v) failed: %v", rootDir, rootURL, defaultDepth, err)
- return
+ return fmt.Errorf("NewState(%v, %v, %v) failed: %v", rootDir, rootURL, defaultDepth, err)
}
vlog.Infof("Binary repository HTTP server at: %q", rootURL)
go func() {
@@ -83,32 +95,29 @@
}()
server, err := v23.NewServer(ctx)
if err != nil {
- vlog.Errorf("NewServer() failed: %v", err)
- return
+ return fmt.Errorf("NewServer() failed: %v", err)
}
defer server.Stop()
ls := v23.GetListenSpec(ctx)
endpoints, err := server.Listen(ls)
if err != nil {
- vlog.Errorf("Listen(%s) failed: %v", ls, err)
- return
+ return fmt.Errorf("Listen(%s) failed: %v", ls, err)
}
dis, err := binarylib.NewDispatcher(v23.GetPrincipal(ctx), state)
if err != nil {
- vlog.Errorf("NewDispatcher() failed: %v\n", err)
- return
+ return fmt.Errorf("NewDispatcher() failed: %v\n", err)
}
- if err := server.ServeDispatcher(*name, dis); err != nil {
- vlog.Errorf("ServeDispatcher(%v) failed: %v", *name, err)
- return
+ if err := server.ServeDispatcher(name, dis); err != nil {
+ return fmt.Errorf("ServeDispatcher(%v) failed: %v", name, err)
}
epName := endpoints[0].Name()
- if *name != "" {
- vlog.Infof("Binary repository serving at %q (%q)", *name, epName)
+ if name != "" {
+ vlog.Infof("Binary repository serving at %q (%q)", name, epName)
} else {
vlog.Infof("Binary repository serving at %q", epName)
}
// Wait until shutdown.
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
diff --git a/services/build/build/impl_test.go b/services/build/build/impl_test.go
index 4df3e5a..c37c367 100644
--- a/services/build/build/impl_test.go
+++ b/services/build/build/impl_test.go
@@ -79,7 +79,7 @@
var stdout, stderr bytes.Buffer
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
args := []string{"build", naming.JoinAddressName(endpoint.String(), ""), "v.io/x/ref/services/build/build"}
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, args); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, args); err != nil {
t.Fatalf("Run failed: %v", err)
}
if got, want := strings.TrimSpace(stdout.String()), ""; got != want {
diff --git a/services/build/buildd/doc.go b/services/build/buildd/doc.go
new file mode 100644
index 0000000..2113099
--- /dev/null
+++ b/services/build/buildd/doc.go
@@ -0,0 +1,71 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command buildd runs the builder daemon, which implements the
+v.io/v23/services/build.Builder interface.
+
+Usage:
+ buildd [flags]
+
+The buildd flags are:
+ -gobin=go
+ Path to the Go compiler.
+ -goroot=<GOROOT>
+ GOROOT to use with the Go compiler. The default is the value of the GOROOT
+ environment variable.
+ -name=
+ Name to mount the build server as.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/build/buildd/main.go b/services/build/buildd/main.go
index c4dc55c..ed25222 100644
--- a/services/build/buildd/main.go
+++ b/services/build/buildd/main.go
@@ -2,49 +2,64 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon buildd implements the v.io/v23/services/build.Builder interface.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
+ "fmt"
"os"
"v.io/v23"
+ "v.io/v23/context"
"v.io/v23/services/build"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/lib/security/securityflag"
"v.io/x/ref/lib/signals"
-
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
)
-var (
- gobin = flag.String("gobin", "go", "path to the Go compiler")
- goroot = flag.String("goroot", os.Getenv("GOROOT"), "GOROOT to use with the Go compiler")
- name = flag.String("name", "", "name to mount the build server as")
-)
+var gobin, goroot, name string
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdBuildD.Flags.StringVar(&gobin, "gobin", "go", "Path to the Go compiler.")
+ cmdBuildD.Flags.StringVar(&goroot, "goroot", os.Getenv("GOROOT"), "GOROOT to use with the Go compiler. The default is the value of the GOROOT environment variable.")
+ cmdBuildD.Flags.Lookup("goroot").DefValue = "<GOROOT>"
+ cmdBuildD.Flags.StringVar(&name, "name", "", "Name to mount the build server as.")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdBuildD)
+}
+
+var cmdBuildD = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runBuildD),
+ Name: "buildd",
+ Short: "Runs the builder daemon.",
+ Long: `
+Command buildd runs the builder daemon, which implements the
+v.io/v23/services/build.Builder interface.
+`,
+}
+
+func runBuildD(ctx *context.T, env *cmdline.Env, args []string) error {
server, err := v23.NewServer(ctx)
if err != nil {
- vlog.Errorf("NewServer() failed: %v", err)
- return
+ return fmt.Errorf("NewServer() failed: %v", err)
}
ls := v23.GetListenSpec(ctx)
endpoint, err := server.Listen(ls)
if err != nil {
- vlog.Errorf("Listen(%s) failed: %v", ls, err)
- return
+ return fmt.Errorf("Listen(%s) failed: %v", ls, err)
}
- if err := server.Serve(*name, build.BuilderServer(NewBuilderService(*gobin, *goroot)), securityflag.NewAuthorizerOrDie()); err != nil {
- vlog.Errorf("Serve(%v) failed: %v", *name, err)
- return
+ if err := server.Serve(name, build.BuilderServer(NewBuilderService(gobin, goroot)), securityflag.NewAuthorizerOrDie()); err != nil {
+ return fmt.Errorf("Serve(%v) failed: %v", name, err)
}
vlog.Infof("Build server running at endpoint=%q", endpoint)
// Wait until shutdown.
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
diff --git a/services/device/device/acl_test.go b/services/device/device/acl_test.go
index 3e76185..1a12227 100644
--- a/services/device/device/acl_test.go
+++ b/services/device/device/acl_test.go
@@ -46,7 +46,7 @@
// Test the 'get' command.
rootTape := tapes.forSuffix("")
- rootTape.SetResponses([]interface{}{GetPermissionsResponse{
+ rootTape.SetResponses(GetPermissionsResponse{
perms: access.Permissions{
"Admin": access.AccessList{
In: []security.BlessingPattern{"self"},
@@ -58,9 +58,9 @@
},
version: "aVersionForToday",
err: nil,
- }})
+ })
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"acl", "get", deviceName}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"acl", "get", deviceName}); err != nil {
t.Fatalf("error: %v", err)
}
if expected, got := strings.TrimSpace(`
@@ -93,7 +93,7 @@
deviceName := endpoint.Name()
// Some tests to validate parse.
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"acl", "set", deviceName}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"acl", "set", deviceName}); err == nil {
t.Fatalf("failed to correctly detect insufficient parameters")
}
if expected, got := "ERROR: set: incorrect number of arguments 1, must be 1 + 2n", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -102,7 +102,7 @@
stderr.Reset()
stdout.Reset()
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"acl", "set", deviceName, "foo"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"acl", "set", deviceName, "foo"}); err == nil {
t.Fatalf("failed to correctly detect insufficient parameters")
}
if expected, got := "ERROR: set: incorrect number of arguments 2, must be 1 + 2n", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -111,7 +111,7 @@
stderr.Reset()
stdout.Reset()
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"acl", "set", deviceName, "foo", "bar", "ohno"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"acl", "set", deviceName, "foo", "bar", "ohno"}); err == nil {
t.Fatalf("failed to correctly detect insufficient parameters")
}
if expected, got := "ERROR: set: incorrect number of arguments 4, must be 1 + 2n", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -120,7 +120,7 @@
stderr.Reset()
stdout.Reset()
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"acl", "set", deviceName, "foo", "!"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"acl", "set", deviceName, "foo", "!"}); err == nil {
t.Fatalf("failed to detect invalid parameter")
}
if expected, got := "ERROR: failed to parse access tags for \"foo\": empty access tag", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -131,19 +131,20 @@
stderr.Reset()
stdout.Reset()
rootTape := tapes.forSuffix("")
- rootTape.SetResponses([]interface{}{GetPermissionsResponse{
- perms: access.Permissions{
- "Admin": access.AccessList{
- In: []security.BlessingPattern{"self"},
+ rootTape.SetResponses(
+ GetPermissionsResponse{
+ perms: access.Permissions{
+ "Admin": access.AccessList{
+ In: []security.BlessingPattern{"self"},
+ },
+ "Read": access.AccessList{
+ In: []security.BlessingPattern{"other", "self"},
+ NotIn: []string{"other/bob"},
+ },
},
- "Read": access.AccessList{
- In: []security.BlessingPattern{"other", "self"},
- NotIn: []string{"other/bob"},
- },
+ version: "aVersionForToday",
+ err: nil,
},
- version: "aVersionForToday",
- err: nil,
- },
verror.NewErrBadVersion(nil),
GetPermissionsResponse{
perms: access.Permissions{
@@ -159,14 +160,14 @@
err: nil,
},
nil,
- })
+ )
// set command that:
// - Adds entry for "friends" to "Write" & "Admin"
// - Adds a blacklist entry for "friend/alice" for "Admin"
// - Edits existing entry for "self" (adding "Write" access)
// - Removes entry for "other/bob/baddevice"
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{
"acl",
"set",
deviceName,
@@ -233,14 +234,13 @@
stderr.Reset()
// GetPermissions fails.
- rootTape.SetResponses([]interface{}{GetPermissionsResponse{
+ rootTape.SetResponses(GetPermissionsResponse{
perms: access.Permissions{},
version: "aVersionForToday",
err: verror.New(errOops, nil),
- },
})
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"acl", "set", deviceName, "vana/bad", "Read"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"acl", "set", deviceName, "vana/bad", "Read"}); err == nil {
t.Fatalf("GetPermissions RPC inside perms set command failed but error wrongly not detected")
} else if expected, got := `^GetPermissions\(`+deviceName+`\) failed:.*oops!`, err.Error(); !regexp.MustCompile(expected).MatchString(got) {
t.Fatalf("Unexpected output from list. Got %q, regexp %q", got, expected)
@@ -260,19 +260,20 @@
stderr.Reset()
// SetPermissions fails with something other than a bad version failure.
- rootTape.SetResponses([]interface{}{GetPermissionsResponse{
- perms: access.Permissions{
- "Read": access.AccessList{
- In: []security.BlessingPattern{"other", "self"},
+ rootTape.SetResponses(
+ GetPermissionsResponse{
+ perms: access.Permissions{
+ "Read": access.AccessList{
+ In: []security.BlessingPattern{"other", "self"},
+ },
},
+ version: "aVersionForToday",
+ err: nil,
},
- version: "aVersionForToday",
- err: nil,
- },
verror.New(errOops, nil),
- })
+ )
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"acl", "set", deviceName, "friend", "Read"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"acl", "set", deviceName, "friend", "Read"}); err == nil {
t.Fatalf("SetPermissions should have failed: %v", err)
} else if expected, got := `^SetPermissions\(`+deviceName+`\) failed:.*oops!`, err.Error(); !regexp.MustCompile(expected).MatchString(got) {
t.Fatalf("Unexpected output from list. Got %q, regexp %q", got, expected)
diff --git a/services/device/device/impl_test.go b/services/device/device/impl_test.go
index fdef9b9..ba7008a 100644
--- a/services/device/device/impl_test.go
+++ b/services/device/device/impl_test.go
@@ -47,7 +47,7 @@
rootTape := tapes.forSuffix("")
// Test the 'list' command.
- rootTape.SetResponses([]interface{}{ListAssociationResponse{
+ rootTape.SetResponses(ListAssociationResponse{
na: []device.Association{
{
"root/self",
@@ -59,9 +59,9 @@
},
},
err: nil,
- }})
+ })
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"associate", "list", deviceName}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"associate", "list", deviceName}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := "root/self alice_self_account\nroot/other alice_other_account", strings.TrimSpace(stdout.String()); got != expected {
@@ -74,7 +74,7 @@
stdout.Reset()
// Test list with bad parameters.
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"associate", "list", deviceName, "hello"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"associate", "list", deviceName, "hello"}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
if got, expected := len(rootTape.Play()), 0; got != expected {
@@ -99,7 +99,7 @@
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
deviceName := naming.JoinAddressName(endpoint.String(), "")
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"add", "one"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"add", "one"}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
rootTape := tapes.forSuffix("")
@@ -109,8 +109,8 @@
rootTape.Rewind()
stdout.Reset()
- rootTape.SetResponses([]interface{}{nil})
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"associate", "add", deviceName, "alice", "root/self"}); err != nil {
+ rootTape.SetResponses(nil)
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"associate", "add", deviceName, "alice", "root/self"}); err != nil {
t.Fatalf("%v", err)
}
expected := []interface{}{
@@ -122,8 +122,8 @@
rootTape.Rewind()
stdout.Reset()
- rootTape.SetResponses([]interface{}{nil})
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"associate", "add", deviceName, "alice", "root/other", "root/self"}); err != nil {
+ rootTape.SetResponses(nil)
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"associate", "add", deviceName, "alice", "root/other", "root/self"}); err != nil {
t.Fatalf("%v", err)
}
expected = []interface{}{
@@ -151,7 +151,7 @@
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
deviceName := naming.JoinAddressName(endpoint.String(), "")
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"remove", "one"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"remove", "one"}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
rootTape := tapes.forSuffix("")
@@ -161,8 +161,8 @@
rootTape.Rewind()
stdout.Reset()
- rootTape.SetResponses([]interface{}{nil})
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"associate", "remove", deviceName, "root/self"}); err != nil {
+ rootTape.SetResponses(nil)
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"associate", "remove", deviceName, "root/self"}); err != nil {
t.Fatalf("%v", err)
}
expected := []interface{}{
@@ -242,7 +242,7 @@
InstallStimulus{"Install", appNameNoFetch, cfg, pkg, application.Envelope{}, nil},
},
} {
- rootTape.SetResponses([]interface{}{c.tapeResponse})
+ rootTape.SetResponses(c.tapeResponse)
if c.config != nil {
jsonConfig, err := json.Marshal(c.config)
if err != nil {
@@ -258,7 +258,7 @@
c.args = append([]string{fmt.Sprintf("--packages=%s", string(jsonPackages))}, c.args...)
}
c.args = append([]string{"install"}, c.args...)
- err := v23cmd.ParseAndRun(cmd, ctx, env, c.args)
+ err := v23cmd.ParseAndRunForTest(cmd, ctx, env, c.args)
if c.shouldErr {
if err == nil {
t.Fatalf("test case %d: wrongly failed to receive a non-nil error.", i)
@@ -304,7 +304,7 @@
}
// Confirm that we correctly enforce the number of arguments.
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"claim", "nope"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"claim", "nope"}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
if expected, got := "ERROR: claim: incorrect number of arguments, expected atleast 2 (max: 4), got 1", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -315,7 +315,7 @@
rootTape := tapes.forSuffix("")
rootTape.Rewind()
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"claim", "nope", "nope", "nope", "nope", "nope"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"claim", "nope", "nope", "nope", "nope", "nope"}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
if expected, got := "ERROR: claim: incorrect number of arguments, expected atleast 2 (max: 4), got 5", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -335,7 +335,7 @@
t.Fatalf("Failed to marshal principal public key: %v", err)
}
}
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"claim", deviceName, "grant", pairingToken, base64.URLEncoding.EncodeToString(deviceKeyWrong)}); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"claim", deviceName, "grant", pairingToken, base64.URLEncoding.EncodeToString(deviceKeyWrong)}); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
t.Fatalf("wrongly failed to receive correct error on claim with incorrect device key:%v id:%v", err, verror.ErrorID(err))
}
stdout.Reset()
@@ -343,10 +343,8 @@
rootTape.Rewind()
// Correct operation.
- rootTape.SetResponses([]interface{}{
- nil,
- })
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"claim", deviceName, "grant", pairingToken, base64.URLEncoding.EncodeToString(deviceKey)}); err != nil {
+ rootTape.SetResponses(nil)
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"claim", deviceName, "grant", pairingToken, base64.URLEncoding.EncodeToString(deviceKey)}); err != nil {
t.Fatalf("Claim(%s, %s, %s) failed: %v", deviceName, "grant", pairingToken, err)
}
if got, expected := len(rootTape.Play()), 1; got != expected {
@@ -366,10 +364,8 @@
stderr.Reset()
// Error operation.
- rootTape.SetResponses([]interface{}{
- verror.New(errOops, nil),
- })
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"claim", deviceName, "grant", pairingToken}); err == nil {
+ rootTape.SetResponses(verror.New(errOops, nil))
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"claim", deviceName, "grant", pairingToken}); err == nil {
t.Fatal("claim() failed to detect error:", err)
}
expected = []interface{}{
@@ -398,7 +394,7 @@
appName := naming.JoinAddressName(endpoint.String(), "")
// Confirm that we correctly enforce the number of arguments.
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"instantiate", "nope"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"instantiate", "nope"}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
if expected, got := "ERROR: instantiate: incorrect number of arguments, expected 2, got 1", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -409,7 +405,7 @@
rootTape := tapes.forSuffix("")
rootTape.Rewind()
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"instantiate", "nope", "nope", "nope"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"instantiate", "nope", "nope", "nope"}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
if expected, got := "ERROR: instantiate: incorrect number of arguments, expected 2, got 3", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -420,12 +416,11 @@
rootTape.Rewind()
// Correct operation.
- rootTape.SetResponses([]interface{}{InstantiateResponse{
+ rootTape.SetResponses(InstantiateResponse{
err: nil,
instanceID: "app1",
- },
})
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"instantiate", appName, "grant"}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"instantiate", appName, "grant"}); err != nil {
t.Fatalf("instantiate %s %s failed: %v", appName, "grant", err)
}
@@ -445,12 +440,11 @@
stderr.Reset()
// Error operation.
- rootTape.SetResponses([]interface{}{InstantiateResponse{
+ rootTape.SetResponses(InstantiateResponse{
verror.New(errOops, nil),
"",
- },
})
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"instantiate", appName, "grant"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"instantiate", appName, "grant"}); err == nil {
t.Fatalf("instantiate failed to detect error")
}
expected = []interface{}{
@@ -478,8 +472,8 @@
debugMessage := "the secrets of the universe, revealed"
rootTape := tapes.forSuffix("")
- rootTape.SetResponses([]interface{}{debugMessage})
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"debug", appName}); err != nil {
+ rootTape.SetResponses(debugMessage)
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"debug", appName}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := debugMessage, strings.TrimSpace(stdout.String()); got != expected {
@@ -527,8 +521,8 @@
} {
rootTape.Rewind()
stdout.Reset()
- rootTape.SetResponses([]interface{}{c.tapeResponse})
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"status", appName}); err != nil {
+ rootTape.SetResponses(c.tapeResponse)
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"status", appName}); err != nil {
t.Errorf("%v", err)
}
if expected, got := c.expected, strings.TrimSpace(stdout.String()); got != expected {
diff --git a/services/device/device/instance_impl_test.go b/services/device/device/instance_impl_test.go
index 6f56cc2..1397cca 100644
--- a/services/device/device/instance_impl_test.go
+++ b/services/device/device/instance_impl_test.go
@@ -38,7 +38,7 @@
appName := naming.JoinAddressName(endpoint.String(), "appname")
// Confirm that we correctly enforce the number of arguments.
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"kill"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"kill"}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
if expected, got := "ERROR: kill: incorrect number of arguments, expected 1, got 0", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -49,7 +49,7 @@
appTape := tapes.forSuffix("appname")
appTape.Rewind()
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"kill", "nope", "nope"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"kill", "nope", "nope"}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
if expected, got := "ERROR: kill: incorrect number of arguments, expected 1, got 2", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -60,11 +60,9 @@
appTape.Rewind()
// Test the 'kill' command.
- appTape.SetResponses([]interface{}{
- nil,
- })
+ appTape.SetResponses(nil)
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"kill", appName}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"kill", appName}); err != nil {
t.Fatalf("kill failed when it shouldn't: %v", err)
}
if expected, got := "Kill succeeded", strings.TrimSpace(stdout.String()); got != expected {
@@ -81,10 +79,8 @@
stdout.Reset()
// Test kill with bad parameters.
- appTape.SetResponses([]interface{}{
- verror.New(errOops, nil),
- })
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{"kill", appName}); err == nil {
+ appTape.SetResponses(verror.New(errOops, nil))
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{"kill", appName}); err == nil {
t.Fatalf("wrongly didn't receive a non-nil error.")
}
// expected the same.
@@ -111,7 +107,7 @@
appName := naming.JoinAddressName(endpoint.String(), "appname")
// Confirm that we correctly enforce the number of arguments.
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{lower}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{lower}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
if expected, got := "ERROR: "+lower+": incorrect number of arguments, expected 1, got 0", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -122,7 +118,7 @@
appTape := tapes.forSuffix("appname")
appTape.Rewind()
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{lower, "nope", "nope"}); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{lower, "nope", "nope"}); err == nil {
t.Fatalf("wrongly failed to receive a non-nil error.")
}
if expected, got := "ERROR: "+lower+": incorrect number of arguments, expected 1, got 2", strings.TrimSpace(stderr.String()); !strings.HasPrefix(got, expected) {
@@ -133,10 +129,8 @@
appTape.Rewind()
// Correct operation.
- appTape.SetResponses([]interface{}{
- nil,
- })
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{lower, appName}); err != nil {
+ appTape.SetResponses(nil)
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{lower, appName}); err != nil {
t.Fatalf("%s failed when it shouldn't: %v", lower, err)
}
if expected, got := upper+" succeeded", strings.TrimSpace(stdout.String()); got != expected {
@@ -150,10 +144,8 @@
stdout.Reset()
// Test list with bad parameters.
- appTape.SetResponses([]interface{}{
- verror.New(errOops, nil),
- })
- if err := v23cmd.ParseAndRun(cmd, ctx, env, []string{lower, appName}); err == nil {
+ appTape.SetResponses(verror.New(errOops, nil))
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, []string{lower, appName}); err == nil {
t.Fatalf("wrongly didn't receive a non-nil error.")
}
// expected the same.
diff --git a/services/device/device/local_install_test.go b/services/device/device/local_install_test.go
index 5899c04..e3880e7 100644
--- a/services/device/device/local_install_test.go
+++ b/services/device/device/local_install_test.go
@@ -76,7 +76,7 @@
},
} {
c.args = append([]string{"install-local"}, c.args...)
- if err := v23cmd.ParseAndRun(cmd, ctx, env, c.args); err == nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, c.args); err == nil {
t.Fatalf("test case %d: wrongly failed to receive a non-nil error.", i)
} else {
fmt.Fprintln(&stderr, "ERROR:", err)
@@ -224,7 +224,7 @@
},
} {
const appId = "myBestAppID"
- rootTape.SetResponses([]interface{}{InstallResponse{appId, nil}})
+ rootTape.SetResponses(InstallResponse{appId, nil})
if c.config != nil {
jsonConfig, err := json.Marshal(c.config)
if err != nil {
@@ -240,7 +240,7 @@
c.args = append([]string{fmt.Sprintf("--packages=%s", string(jsonPackages))}, c.args...)
}
c.args = append([]string{"install-local"}, c.args...)
- if err := v23cmd.ParseAndRun(cmd, ctx, env, c.args); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmd, ctx, env, c.args); err != nil {
t.Fatalf("test case %d: %v", i, err)
}
if expected, got := naming.Join(deviceName, appId), strings.TrimSpace(stdout.String()); got != expected {
diff --git a/services/device/device/mock_test.go b/services/device/device/mock_test.go
index 4d7d3ea..55975ee 100644
--- a/services/device/device/mock_test.go
+++ b/services/device/device/mock_test.go
@@ -6,17 +6,21 @@
import (
"fmt"
+ "reflect"
+ "sort"
"sync"
+ "testing"
)
-// tape is not thread-safe.
-// TODO(caprita): We should make it thread-safe just in case.
type tape struct {
+ sync.Mutex
stimuli []interface{}
responses []interface{}
}
func (t *tape) Record(call interface{}) interface{} {
+ t.Lock()
+ defer t.Unlock()
t.stimuli = append(t.stimuli, call)
if len(t.responses) < 1 {
@@ -27,17 +31,26 @@
return resp
}
-func (t *tape) SetResponses(responses []interface{}) {
- t.responses = responses
+func (t *tape) SetResponses(responses ...interface{}) {
+ t.Lock()
+ defer t.Unlock()
+ t.responses = make([]interface{}, len(responses))
+ copy(t.responses, responses)
}
func (t *tape) Rewind() {
+ t.Lock()
+ defer t.Unlock()
t.stimuli = make([]interface{}, 0)
t.responses = make([]interface{}, 0)
}
func (t *tape) Play() []interface{} {
- return t.stimuli
+ t.Lock()
+ defer t.Unlock()
+ resp := make([]interface{}, len(t.stimuli))
+ copy(resp, t.stimuli)
+ return resp
}
func newTape() *tape {
@@ -46,8 +59,6 @@
return t
}
-// tapeMap provides thread-safe access to the tapes, but each tape is not
-// thread-safe.
type tapeMap struct {
sync.Mutex
tapes map[string]*tape
@@ -70,3 +81,83 @@
}
return t
}
+
+func TestOneTape(t *testing.T) {
+ tm := newTapeMap()
+ if _, ok := tm.forSuffix("mytape").Record("foo").(error); !ok {
+ t.Errorf("Expected error")
+ }
+ tm.forSuffix("mytape").SetResponses("b", "c")
+ if want, got := "b", tm.forSuffix("mytape").Record("bar"); want != got {
+ t.Errorf("Expected %v, got %v", want, got)
+ }
+ if want, got := "c", tm.forSuffix("mytape").Record("baz"); want != got {
+ t.Errorf("Expected %v, got %v", want, got)
+ }
+ if want, got := []interface{}{"foo", "bar", "baz"}, tm.forSuffix("mytape").Play(); !reflect.DeepEqual(want, got) {
+ t.Errorf("Expected %v, got %v", want, got)
+ }
+ tm.forSuffix("mytape").Rewind()
+ if want, got := []interface{}{}, tm.forSuffix("mytape").Play(); !reflect.DeepEqual(want, got) {
+ t.Errorf("Expected %v, got %v", want, got)
+ }
+}
+
+func TestManyTapes(t *testing.T) {
+ tm := newTapeMap()
+ tapes := []string{"duct tape", "cassette tape", "watergate tape", "tape worm"}
+ for _, tp := range tapes {
+ tm.forSuffix(tp).SetResponses(tp + "resp")
+ }
+ for _, tp := range tapes {
+ if want, got := tp+"resp", tm.forSuffix(tp).Record(tp+"stimulus"); want != got {
+ t.Errorf("Expected %v, got %v", want, got)
+ }
+ }
+ for _, tp := range tapes {
+ if want, got := []interface{}{tp + "stimulus"}, tm.forSuffix(tp).Play(); !reflect.DeepEqual(want, got) {
+ t.Errorf("Expected %v, got %v", want, got)
+ }
+ }
+}
+
+func TestTapeParallelism(t *testing.T) {
+ tm := newTapeMap()
+ var resp []interface{}
+ const N = 100
+ for i := 0; i < N; i++ {
+ resp = append(resp, fmt.Sprintf("resp%010d", i))
+ }
+ tm.forSuffix("mytape").SetResponses(resp...)
+ results := make(chan string, N)
+ for i := 0; i < N; i++ {
+ go func(index int) {
+ results <- tm.forSuffix("mytape").Record(fmt.Sprintf("stimulus%010d", index)).(string)
+ }(i)
+ }
+ var res []string
+ for i := 0; i < N; i++ {
+ r := <-results
+ res = append(res, r)
+ }
+ sort.Strings(res)
+ var expectedRes []string
+ for i := 0; i < N; i++ {
+ expectedRes = append(expectedRes, fmt.Sprintf("resp%010d", i))
+ }
+ if want, got := expectedRes, res; !reflect.DeepEqual(want, got) {
+ t.Errorf("Expected %v, got %v", want, got)
+ }
+ var expectedStimuli []string
+ for i := 0; i < N; i++ {
+ expectedStimuli = append(expectedStimuli, fmt.Sprintf("stimulus%010d", i))
+ }
+ var gotStimuli []string
+ for _, s := range tm.forSuffix("mytape").Play() {
+ gotStimuli = append(gotStimuli, s.(string))
+ }
+ sort.Strings(gotStimuli)
+ if want, got := expectedStimuli, gotStimuli; !reflect.DeepEqual(want, got) {
+ t.Errorf("Expected %v, got %v", want, got)
+ }
+}
diff --git a/services/device/internal/impl/instance_reaping.go b/services/device/internal/impl/instance_reaping.go
index 9dc2b3e..59ae4b0 100644
--- a/services/device/internal/impl/instance_reaping.go
+++ b/services/device/internal/impl/instance_reaping.go
@@ -5,6 +5,7 @@
package impl
import (
+ "os"
"path/filepath"
"sync"
"syscall"
@@ -19,10 +20,24 @@
"v.io/x/lib/vlog"
)
+const (
+ AppcycleReconciliation = "V23_APPCYCLE_RECONCILIATION"
+)
+
var (
errPIDIsNotInteger = verror.Register(pkgPath+".errPIDIsNotInteger", verror.NoRetry, "{1:}{2:} __debug/stats/system/pid isn't an integer{:_}")
+
+ v23PIDMgmt = true
)
+func init() {
+ // TODO(rjkroege): Environment variables do not survive device manager updates.
+ // Use an alternative mechanism.
+ if os.Getenv(AppcycleReconciliation) != "" {
+ v23PIDMgmt = false
+ }
+}
+
type pidInstanceDirPair struct {
instanceDir string
pid int
@@ -57,11 +72,11 @@
}
}
-// processStatusPolling polls for the continued existence of a set of tracked
-// pids.
-// TODO(rjkroege): There are nicer ways to provide this functionality.
-// For example, use the kevent facility in darwin or replace init.
-// See http://www.incenp.org/dvlpt/wait4.html for inspiration.
+// processStatusPolling polls for the continued existence of a set of
+// tracked pids. TODO(rjkroege): There are nicer ways to provide this
+// functionality. For example, use the kevent facility in darwin or
+// replace init. See http://www.incenp.org/dvlpt/wait4.html for
+// inspiration.
func processStatusPolling(r reaper, trackedPids map[string]int) {
poll := func() {
for idir, pid := range trackedPids {
@@ -81,8 +96,9 @@
// This implementation cannot detect if a process exited
// and was replaced by an arbitrary non-Vanadium process
// within the polling interval.
- // TODO(rjkroege): Consider probing the appcycle service of
- // the pid to confirm.
+ // TODO(rjkroege): Probe the appcycle service of the app
+ // to confirm that its pid is valid iff v23PIDMgmt
+ // is false.
default:
// The kill system call manpage says that this can only happen
// if the kernel claims that 0 is an invalid signal.
@@ -150,6 +166,79 @@
// In seconds.
const appCycleTimeout = 5
+// processStatusViaAppCycleMgr updates the status based on getting the
+// pid from the AppCycleMgr because the data in the instance info might
+// be outdated: the app may have exited and an arbitrary non-Vanadium
+// process may have been executed with the same pid.
+func processStatusViaAppCycleMgr(ctx *context.T, c chan<- pidErrorTuple, instancePath string, info *instanceInfo, state device.InstanceState) {
+ nctx, _ := context.WithTimeout(ctx, appCycleTimeout*time.Second)
+
+ name := naming.Join(info.AppCycleMgrName, "__debug/stats/system/pid")
+ sclient := stats.StatsClient(name)
+ v, err := sclient.Value(nctx)
+ if err != nil {
+ vlog.Infof("Instance: %v error: %v", instancePath, err)
+ // No process is actually running for this instance.
+ vlog.VI(2).Infof("perinstance stats fetching failed: %v", err)
+ if err := transitionInstance(instancePath, state, device.InstanceStateNotRunning); err != nil {
+ vlog.Errorf("transitionInstance(%s,%s,%s) failed: %v", instancePath, state, device.InstanceStateNotRunning, err)
+ }
+ c <- pidErrorTuple{ipath: instancePath, err: err}
+ return
+ }
+ // Convert the stat value from *vdl.Value into an int pid.
+ var pid int
+ if err := vdl.Convert(&pid, v); err != nil {
+ err = verror.New(errPIDIsNotInteger, ctx, err)
+ vlog.Errorf(err.Error())
+ c <- pidErrorTuple{ipath: instancePath, err: err}
+ return
+ }
+
+ ptuple := pidErrorTuple{ipath: instancePath, pid: pid}
+
+ // Update the instance info.
+ if info.Pid != pid {
+ info.Pid = pid
+ ptuple.err = saveInstanceInfo(ctx, instancePath, info)
+ }
+
+ // The instance was found to be running, so update its state accordingly
+ // (in case the device restarted while the instance was in one of the
+ // transitional states like launching, dying, etc).
+ if err := transitionInstance(instancePath, state, device.InstanceStateRunning); err != nil {
+ vlog.Errorf("transitionInstance(%s,%v,%s) failed: %v", instancePath, state, device.InstanceStateRunning, err)
+ }
+
+ vlog.VI(0).Infof("perInstance go routine for %v ending", instancePath)
+ c <- ptuple
+}
+
+// processStatusViaKill updates the status based on sending a kill signal
+// to the process. This assumes that most processes on the system are
+// likely to be managed by the device manager and a live process is not
+// responsive because the agent has been restarted rather than being
+// created through a different means.
+func processStatusViaKill(c chan<- pidErrorTuple, instancePath string, info *instanceInfo, state device.InstanceState) {
+ pid := info.Pid
+
+ switch err := syscall.Kill(pid, 0); err {
+ case syscall.ESRCH:
+ // No such PID.
+ if err := transitionInstance(instancePath, state, device.InstanceStateNotRunning); err != nil {
+ vlog.Errorf("transitionInstance(%s,%s,%s) failed: %v", instancePath, state, device.InstanceStateNotRunning, err)
+ }
+ c <- pidErrorTuple{ipath: instancePath, err: err, pid: pid}
+ case nil, syscall.EPERM:
+ // The instance was found to be running, so update its state.
+ if err := transitionInstance(instancePath, state, device.InstanceStateRunning); err != nil {
+ vlog.Errorf("transitionInstance(%s,%v, %v) failed: %v", instancePath, state, device.InstanceStateRunning, err)
+ }
+ vlog.VI(0).Infof("perInstance go routine for %v ending", instancePath)
+ c <- pidErrorTuple{ipath: instancePath, err: nil, pid: pid}
+ }
+}
+
func perInstance(ctx *context.T, instancePath string, c chan<- pidErrorTuple, wg *sync.WaitGroup) {
defer wg.Done()
vlog.Infof("Instance: %v", instancePath)
@@ -169,65 +258,23 @@
return
}
vlog.VI(2).Infof("perInstance firing up on %s", instancePath)
- nctx, _ := context.WithTimeout(ctx, appCycleTimeout*time.Second)
-
- var ptuple pidErrorTuple
- ptuple.ipath = instancePath
// Read the instance data.
info, err := loadInstanceInfo(ctx, instancePath)
if err != nil {
vlog.Errorf("loadInstanceInfo failed: %v", err)
-
// Something has gone badly wrong.
// TODO(rjkroege,caprita): Consider removing the instance or at
// least set its state to something indicating error?
- ptuple.err = err
- c <- ptuple
+ c <- pidErrorTuple{err: err, ipath: instancePath}
return
}
- // Get the pid from the AppCycleMgr because the data in the instance
- // info might be outdated: the app may have exited and an arbitrary
- // non-Vanadium process may have been executed with the same pid.
- name := naming.Join(info.AppCycleMgrName, "__debug/stats/system/pid")
- sclient := stats.StatsClient(name)
- v, err := sclient.Value(nctx)
- if err != nil {
- vlog.Infof("Instance: %v error: %v", instancePath, err)
- // No process is actually running for this instance.
- vlog.VI(2).Infof("perinstance stats fetching failed: %v", err)
- if err := transitionInstance(instancePath, state, device.InstanceStateNotRunning); err != nil {
- vlog.Errorf("transitionInstance(%s,%s,%s) failed: %v", instancePath, state, device.InstanceStateNotRunning, err)
- }
- ptuple.err = err
- c <- ptuple
+ if !v23PIDMgmt {
+ processStatusViaAppCycleMgr(ctx, c, instancePath, info, state)
return
}
- // Convert the stat value from *vdl.Value into an int pid.
- var pid int
- if err := vdl.Convert(&pid, v); err != nil {
- ptuple.err = verror.New(errPIDIsNotInteger, ctx, err)
- vlog.Errorf(ptuple.err.Error())
- c <- ptuple
- return
- }
-
- ptuple.pid = pid
- // Update the instance info.
- if info.Pid != pid {
- info.Pid = pid
- ptuple.err = saveInstanceInfo(ctx, instancePath, info)
- }
- // The instance was found to be running, so update its state accordingly
- // (in case the device restarted while the instance was in one of the
- // transitional states like launching, dying, etc).
- if err := transitionInstance(instancePath, state, device.InstanceStateRunning); err != nil {
- vlog.Errorf("transitionInstance(%s,%v,%s) failed: %v", instancePath, state, device.InstanceStateRunning, err)
- }
-
- vlog.VI(0).Infof("perInstance go routine for %v ending", instancePath)
- c <- ptuple
+ processStatusViaKill(c, instancePath, info, state)
}
// Digs through the directory hierarchy
diff --git a/services/device/internal/impl/instance_reaping_kill_test.go b/services/device/internal/impl/instance_reaping_kill_test.go
new file mode 100644
index 0000000..e702a4c
--- /dev/null
+++ b/services/device/internal/impl/instance_reaping_kill_test.go
@@ -0,0 +1,131 @@
+// 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.
+
+package impl_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "syscall"
+ "testing"
+ "time"
+
+ "v.io/v23/services/device"
+
+ "v.io/x/ref/envvar"
+ "v.io/x/ref/services/device/internal/impl/utiltest"
+ "v.io/x/ref/services/internal/servicetest"
+)
+
+func TestReapReconciliationViaKill(t *testing.T) {
+ cleanup, ctx, sh, envelope, root, helperPath, _ := utiltest.StartupHelper(t)
+ defer cleanup()
+
+ // Start a device manager.
+ // (Since it will be restarted, use the VeyronCredentials environment
+ // to maintain the same set of credentials across runs)
+ dmCreds, err := ioutil.TempDir("", "TestReapReconciliationViaKill")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dmCreds)
+ dmEnv := []string{fmt.Sprintf("%v=%v", envvar.Credentials, dmCreds)}
+
+ dmh := servicetest.RunCommand(t, sh, dmEnv, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
+ servicetest.ReadPID(t, dmh)
+ utiltest.ClaimDevice(t, ctx, "claimable", "dm", "mydevice", utiltest.NoPairingToken)
+
+ // Create the local server that the app uses to let us know it's ready.
+ pingCh, cleanup := utiltest.SetupPingServer(t, ctx)
+ defer cleanup()
+ utiltest.Resolve(t, ctx, "pingserver", 1)
+
+ // Create an envelope for the app.
+ *envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps", "appV1")
+
+ // Install the app.
+ appID := utiltest.InstallApp(t, ctx)
+
+ // Start three app instances.
+ instances := make([]string, 3)
+ for i, _ := range instances {
+ instances[i] = utiltest.LaunchApp(t, ctx, appID)
+ pingCh.VerifyPingArgs(t, utiltest.UserName(t), "default", "")
+ }
+
+ // Get pid of instance[0]
+ pid := utiltest.GetPid(t, ctx, appID, instances[0])
+
+ // Shutdown the first device manager.
+ syscall.Kill(dmh.Pid(), syscall.SIGINT)
+ dmh.Expect("dm terminated")
+ dmh.ExpectEOF()
+ dmh.Shutdown(os.Stderr, os.Stderr)
+ utiltest.ResolveExpectNotFound(t, ctx, "dm") // Ensure a clean slate.
+
+ // Kill instance[0] and wait until it exits before proceeding.
+ syscall.Kill(pid, 9)
+ timeOut := time.After(5 * time.Second)
+ for syscall.Kill(pid, 0) == nil {
+ select {
+ case <-timeOut:
+ t.Fatalf("Timed out waiting for PID %v to terminate", pid)
+ case <-time.After(time.Millisecond):
+ // Try again.
+ }
+ }
+
+ // Run another device manager to replace the dead one.
+ dmh = servicetest.RunCommand(t, sh, dmEnv, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
+ servicetest.ReadPID(t, dmh)
+ utiltest.Resolve(t, ctx, "dm", 1) // Verify the device manager has published itself.
+
+ // By now, we've reconciled the state of the tree with which processes
+ // are actually alive. instance-0 is not alive.
+ expected := []device.InstanceState{device.InstanceStateNotRunning, device.InstanceStateRunning, device.InstanceStateRunning}
+ for i, _ := range instances {
+ utiltest.VerifyState(t, ctx, expected[i], appID, instances[i])
+ }
+
+ // Start instance[0] over-again to show that an app marked not running
+ // by reconciliation can be restarted.
+ utiltest.RunApp(t, ctx, appID, instances[0])
+ pingCh.VerifyPingArgs(t, utiltest.UserName(t), "default", "")
+
+ // Kill instance[1]
+ pid = utiltest.GetPid(t, ctx, appID, instances[1])
+ syscall.Kill(pid, 9)
+
+ // Make a fourth instance. This forces a polling of processes so that
+ // the state is updated.
+ instances = append(instances, utiltest.LaunchApp(t, ctx, appID))
+ pingCh.VerifyPingArgs(t, utiltest.UserName(t), "default", "")
+
+ // Stop the fourth instance to make sure that there's no way we could
+ // still be running the polling loop before doing the below.
+ utiltest.TerminateApp(t, ctx, appID, instances[3])
+
+ // Verify that reaper picked up the previous instances and was watching
+ // instance[1]
+ expected = []device.InstanceState{device.InstanceStateRunning, device.InstanceStateNotRunning, device.InstanceStateRunning, device.InstanceStateDeleted}
+ for i, _ := range instances {
+ utiltest.VerifyState(t, ctx, expected[i], appID, instances[i])
+ }
+
+ utiltest.TerminateApp(t, ctx, appID, instances[2])
+
+ expected = []device.InstanceState{device.InstanceStateRunning, device.InstanceStateNotRunning, device.InstanceStateDeleted, device.InstanceStateDeleted}
+ for i, _ := range instances {
+ utiltest.VerifyState(t, ctx, expected[i], appID, instances[i])
+ }
+ utiltest.TerminateApp(t, ctx, appID, instances[0])
+
+ // TODO(rjkroege): Should be in a defer to ensure that the device
+ // manager is cleaned up even if the test fails in an exceptional way.
+ utiltest.VerifyNoRunningProcesses(t)
+ syscall.Kill(dmh.Pid(), syscall.SIGINT)
+ dmh.Expect("dm terminated")
+ dmh.ExpectEOF()
+}
diff --git a/services/device/internal/impl/reaping/instance_reaping_test.go b/services/device/internal/impl/reaping/instance_reaping_test.go
index 195799d..f3378db 100644
--- a/services/device/internal/impl/reaping/instance_reaping_test.go
+++ b/services/device/internal/impl/reaping/instance_reaping_test.go
@@ -12,27 +12,15 @@
"testing"
"time"
- "v.io/v23/context"
- "v.io/v23/naming"
"v.io/v23/services/device"
- "v.io/v23/services/stats"
"v.io/x/ref/envvar"
+ "v.io/x/ref/services/device/internal/impl"
"v.io/x/ref/services/device/internal/impl/utiltest"
"v.io/x/ref/services/internal/servicetest"
)
-func getPid(t *testing.T, ctx *context.T, appID, instanceID string) int {
- name := naming.Join("dm", "apps/"+appID+"/"+instanceID+"/stats/system/pid")
- c := stats.StatsClient(name)
- v, err := c.Value(ctx)
- if err != nil {
- t.Fatalf("Value() failed: %v\n", err)
- }
- return int(v.Int())
-}
-
-func TestReapReconciliation(t *testing.T) {
+func TestReapReconciliationViaAppCycle(t *testing.T) {
cleanup, ctx, sh, envelope, root, helperPath, _ := utiltest.StartupHelper(t)
defer cleanup()
@@ -44,7 +32,7 @@
t.Fatal(err)
}
defer os.RemoveAll(dmCreds)
- dmEnv := []string{fmt.Sprintf("%v=%v", envvar.Credentials, dmCreds)}
+ dmEnv := []string{fmt.Sprintf("%v=%v", envvar.Credentials, dmCreds), fmt.Sprintf("%v=%v", impl.AppcycleReconciliation, "1")}
dmh := servicetest.RunCommand(t, sh, dmEnv, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
servicetest.ReadPID(t, dmh)
@@ -69,7 +57,7 @@
}
// Get pid of instance[0]
- pid := getPid(t, ctx, appID, instances[0])
+ pid := utiltest.GetPid(t, ctx, appID, instances[0])
// Shutdown the first device manager.
syscall.Kill(dmh.Pid(), syscall.SIGINT)
@@ -108,7 +96,7 @@
pingCh.VerifyPingArgs(t, utiltest.UserName(t), "default", "")
// Kill instance[1]
- pid = getPid(t, ctx, appID, instances[1])
+ pid = utiltest.GetPid(t, ctx, appID, instances[1])
syscall.Kill(pid, 9)
// Make a fourth instance. This forces a polling of processes so that
diff --git a/services/device/internal/impl/utiltest/helpers.go b/services/device/internal/impl/utiltest/helpers.go
index 8e9d88a..d7e262b 100644
--- a/services/device/internal/impl/utiltest/helpers.go
+++ b/services/device/internal/impl/utiltest/helpers.go
@@ -720,3 +720,13 @@
}
}
}
+
+func GetPid(t *testing.T, ctx *context.T, appID, instanceID string) int {
+ name := naming.Join("dm", "apps/"+appID+"/"+instanceID+"/stats/system/pid")
+ c := stats.StatsClient(name)
+ v, err := c.Value(ctx)
+ if err != nil {
+ t.Fatalf("Value() failed: %v", err)
+ }
+ return int(v.Int())
+}
diff --git a/services/identity/identityd/doc.go b/services/identity/identityd/doc.go
new file mode 100644
index 0000000..76b91c1
--- /dev/null
+++ b/services/identity/identityd/doc.go
@@ -0,0 +1,111 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command identityd runs a daemon HTTP server that uses OAuth to create
+security.Blessings objects.
+
+Starts an HTTP server that brokers blessings after authenticating through OAuth.
+
+To generate TLS certificates so the HTTP server can use SSL:
+ go run $(go list -f {{.Dir}} "crypto/tls")/generate_cert.go --host <IP address>
+
+To use Google as an OAuth provider the -google-config-* flags must be set to
+point to the a JSON file obtained after registering the application with the
+Google Developer Console at https://cloud.google.com/console
+
+More details on Google OAuth at:
+ https://developers.google.com/accounts/docs/OAuth2Login
+
+More details on the design of identityd at:
+ https://v.io/designdocs/identity-service.html
+
+Usage:
+ identityd [flags]
+
+The identityd flags are:
+ -assets-prefix=
+ Host serving the web assets for the identity server.
+ -external-http-addr=
+ External address on which the HTTP server listens on. If none is provided
+ the server will only listen on -http-addr.
+ -google-config-android=
+ Path to the JSON-encoded OAuth client configuration for Android applications
+ that obtain blessings from this server (via the
+ OAuthBlesser.BlessUsingAccessToken RPC) from this server.
+ -google-config-chrome=
+ Path to the JSON-encoded OAuth client configuration for Chrome browser
+ applications that obtain blessings from this server (via the
+ OAuthBlesser.BlessUsingAccessToken RPC) from this server.
+ -google-config-web=
+ Path to JSON-encoded OAuth client configuration for the web application that
+ renders the audit log for blessings provided by this provider.
+ -http-addr=localhost:8125
+ Address on which the HTTP server listens on.
+ -mount-prefix=identity
+ Mount name prefix to use. May be rooted.
+ -sql-config=
+ Path to file containing a json object of the following form:
+ {
+ "dataSourceName": "[username[:password]@][protocol[(address)]]/dbname", (the connection string required by go-sql-driver)
+ "tlsServerName": "serverName", (the domain name of the sql server for ssl)
+ "rootCertPath": "/path/server-ca.pem", (the root certificate of the sql server for ssl)
+ "clientCertPath": "/path/client-cert.pem", (the client certificate for ssl)
+ "clientKeyPath": "/path/client-key.pem" (the client private key for ssl)
+ }
+ -tls-config=
+ Comma-separated list of TLS certificate and private key files, in that order.
+ This must be provided.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/identity/identityd/main.go b/services/identity/identityd/main.go
index c483d89..37f5bff3 100644
--- a/services/identity/identityd/main.go
+++ b/services/identity/identityd/main.go
@@ -2,23 +2,22 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon identityd is an HTTP server that uses OAuth to create
-// security.Blessings objects.
-//
-// For more information on our setup of the identity server see:
-// https://docs.google.com/document/d/1ebQ1sQn95cFu8yQM36rpJ8mQvsU29aa1o03ADhi52BM
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
"database/sql"
- "flag"
"fmt"
"os"
"time"
"v.io/v23"
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
-
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/static"
"v.io/x/ref/services/identity/internal/auditor"
"v.io/x/ref/services/identity/internal/blesser"
@@ -26,51 +25,79 @@
"v.io/x/ref/services/identity/internal/oauth"
"v.io/x/ref/services/identity/internal/revocation"
"v.io/x/ref/services/identity/internal/server"
- "v.io/x/ref/services/identity/internal/util"
)
var (
- // Configuration for various Google OAuth-based clients.
- googleConfigWeb = flag.String("google-config-web", "", "Path to JSON-encoded OAuth client configuration for the web application that renders the audit log for blessings provided by this provider.")
- googleConfigChrome = flag.String("google-config-chrome", "", "Path to the JSON-encoded OAuth client configuration for Chrome browser applications that obtain blessings from this server (via the OAuthBlesser.BlessUsingAccessToken RPC) from this server.")
- googleConfigAndroid = flag.String("google-config-android", "", "Path to the JSON-encoded OAuth client configuration for Android applications that obtain blessings from this server (via the OAuthBlesser.BlessUsingAccessToken RPC) from this server.")
- emailClassifier util.EmailClassifier
-
- // Flags controlling the HTTP server
- externalHttpAddr = flag.String("external-http-addr", "", "External address on which the HTTP server listens on. If none is provided the server will only listen on -http-addr.")
- httpAddr = flag.String("http-addr", "localhost:8125", "Address on which the HTTP server listens on.")
- tlsConfig = flag.String("tls-config", "", "Comma-separated list of TLS certificate and private key files, in that order. This must be provided.")
- assetsPrefix = flag.String("assets-prefix", "", "host serving the web assets for the identity server")
- mountPrefix = flag.String("mount-prefix", "identity", "mount name prefix to use. May be rooted.")
+ googleConfigWeb, googleConfigChrome, googleConfigAndroid string
+ externalHttpAddr, httpAddr, tlsConfig, assetsPrefix, mountPrefix string
)
-func main() {
- flag.Var(&emailClassifier, "email-classifier", "A comma-separated list of <domain>=<prefix> pairs. For example 'google.com=internal,v.io=trusted'. When specified, then the blessings generated for email address of <domain> will use the extension <prefix>/<email> instead of the default extension of users/<email>.")
- flag.Usage = usage
- ctx, shutdown := v23.Init()
- defer shutdown()
+func init() {
+ // Configuration for various Google OAuth-based clients.
+ cmdIdentityD.Flags.StringVar(&googleConfigWeb, "google-config-web", "", "Path to JSON-encoded OAuth client configuration for the web application that renders the audit log for blessings provided by this provider.")
+ cmdIdentityD.Flags.StringVar(&googleConfigChrome, "google-config-chrome", "", "Path to the JSON-encoded OAuth client configuration for Chrome browser applications that obtain blessings from this server (via the OAuthBlesser.BlessUsingAccessToken RPC) from this server.")
+ cmdIdentityD.Flags.StringVar(&googleConfigAndroid, "google-config-android", "", "Path to the JSON-encoded OAuth client configuration for Android applications that obtain blessings from this server (via the OAuthBlesser.BlessUsingAccessToken RPC) from this server.")
+ // Flags controlling the HTTP server
+ cmdIdentityD.Flags.StringVar(&externalHttpAddr, "external-http-addr", "", "External address on which the HTTP server listens on. If none is provided the server will only listen on -http-addr.")
+ cmdIdentityD.Flags.StringVar(&httpAddr, "http-addr", "localhost:8125", "Address on which the HTTP server listens on.")
+ cmdIdentityD.Flags.StringVar(&tlsConfig, "tls-config", "", "Comma-separated list of TLS certificate and private key files, in that order. This must be provided.")
+ cmdIdentityD.Flags.StringVar(&assetsPrefix, "assets-prefix", "", "Host serving the web assets for the identity server.")
+ cmdIdentityD.Flags.StringVar(&mountPrefix, "mount-prefix", "identity", "Mount name prefix to use. May be rooted.")
+}
+
+func main() {
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdIdentityD)
+}
+
+var cmdIdentityD = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runIdentityD),
+ Name: "identityd",
+ Short: "Runs HTTP server that creates security.Blessings objects",
+ Long: `
+Command identityd runs a daemon HTTP server that uses OAuth to create
+security.Blessings objects.
+
+Starts an HTTP server that brokers blessings after authenticating through OAuth.
+
+To generate TLS certificates so the HTTP server can use SSL:
+ go run $(go list -f {{.Dir}} "crypto/tls")/generate_cert.go --host <IP address>
+
+To use Google as an OAuth provider the -google-config-* flags must be set to
+point to the a JSON file obtained after registering the application with the
+Google Developer Console at https://cloud.google.com/console
+
+More details on Google OAuth at:
+ https://developers.google.com/accounts/docs/OAuth2Login
+
+More details on the design of identityd at:
+ https://v.io/designdocs/identity-service.html
+`,
+}
+
+func runIdentityD(ctx *context.T, env *cmdline.Env, args []string) error {
var sqlDB *sql.DB
var err error
- if len(*sqlConf) > 0 {
- if sqlDB, err = dbFromConfigFile(*sqlConf); err != nil {
- vlog.Fatalf("failed to create sqlDB: %v", err)
+ if sqlConf != "" {
+ if sqlDB, err = dbFromConfigFile(sqlConf); err != nil {
+ return env.UsageErrorf("Failed to create sqlDB: %v", err)
}
}
- googleoauth, err := oauth.NewGoogleOAuth(*googleConfigWeb)
+ googleoauth, err := oauth.NewGoogleOAuth(googleConfigWeb)
if err != nil {
- vlog.Fatalf("Failed to setup GoogleOAuth: %v", err)
+ return env.UsageErrorf("Failed to setup GoogleOAuth: %v", err)
}
auditor, reader, err := auditor.NewSQLBlessingAuditor(sqlDB)
if err != nil {
- vlog.Fatalf("Failed to create sql auditor from config: %v", err)
+ return fmt.Errorf("Failed to create sql auditor from config: %v", err)
}
revocationManager, err := revocation.NewRevocationManager(sqlDB)
if err != nil {
- vlog.Fatalf("Failed to start RevocationManager: %v", err)
+ return fmt.Errorf("Failed to start RevocationManager: %v", err)
}
listenSpec := v23.GetListenSpec(ctx)
@@ -80,44 +107,25 @@
reader,
revocationManager,
googleOAuthBlesserParams(googleoauth, revocationManager),
- caveats.NewBrowserCaveatSelector(*assetsPrefix),
- &emailClassifier,
- *assetsPrefix,
- *mountPrefix)
- s.Serve(ctx, &listenSpec, *externalHttpAddr, *httpAddr, *tlsConfig)
-}
-
-func usage() {
- fmt.Fprintf(os.Stderr, `%s starts an HTTP server that brokers blessings after authenticating through OAuth.
-
-To generate TLS certificates so the HTTP server can use SSL:
-go run $(go list -f {{.Dir}} "crypto/tls")/generate_cert.go --host <IP address>
-
-To use Google as an OAuth provider the --google-config-* flags must be set to point to
-the a JSON file obtained after registering the application with the Google Developer Console
-at https://cloud.google.com/console
-
-More details on Google OAuth at:
-https://developers.google.com/accounts/docs/OAuth2Login
-
-Flags:
-`, os.Args[0])
- flag.PrintDefaults()
+ caveats.NewBrowserCaveatSelector(assetsPrefix),
+ assetsPrefix,
+ mountPrefix)
+ s.Serve(ctx, &listenSpec, externalHttpAddr, httpAddr, tlsConfig)
+ return nil
}
func googleOAuthBlesserParams(oauthProvider oauth.OAuthProvider, revocationManager revocation.RevocationManager) blesser.OAuthBlesserParams {
params := blesser.OAuthBlesserParams{
OAuthProvider: oauthProvider,
BlessingDuration: 365 * 24 * time.Hour,
- EmailClassifier: &emailClassifier,
RevocationManager: revocationManager,
}
- if clientID, err := getOAuthClientID(*googleConfigChrome); err != nil {
+ if clientID, err := getOAuthClientID(googleConfigChrome); err != nil {
vlog.Info(err)
} else {
params.AccessTokenClients = append(params.AccessTokenClients, oauth.AccessTokenClient{Name: "chrome", ClientID: clientID})
}
- if clientID, err := getOAuthClientID(*googleConfigAndroid); err != nil {
+ if clientID, err := getOAuthClientID(googleConfigAndroid); err != nil {
vlog.Info(err)
} else {
params.AccessTokenClients = append(params.AccessTokenClients, oauth.AccessTokenClient{Name: "android", ClientID: clientID})
diff --git a/services/identity/identityd/sql.go b/services/identity/identityd/sql.go
index fc5c127..7b8b09e 100644
--- a/services/identity/identityd/sql.go
+++ b/services/identity/identityd/sql.go
@@ -9,7 +9,6 @@
"crypto/x509"
"database/sql"
"encoding/json"
- "flag"
"fmt"
"io/ioutil"
@@ -17,7 +16,10 @@
)
// Flag controlling auditing and revocation of Blessing operations.
-var sqlConf = flag.String("sql-config", "", `Path to file containing a json object of the following form:
+var sqlConf string
+
+func init() {
+ cmdIdentityD.Flags.StringVar(&sqlConf, "sql-config", "", `Path to file containing a json object of the following form:
{
"dataSourceName": "[username[:password]@][protocol[(address)]]/dbname", (the connection string required by go-sql-driver)
"tlsServerName": "serverName", (the domain name of the sql server for ssl)
@@ -25,6 +27,7 @@
"clientCertPath": "/path/client-cert.pem", (the client certificate for ssl)
"clientKeyPath": "/path/client-key.pem" (the client private key for ssl)
}`)
+}
// The key used by both go-sql-driver and tls for ssl.
const tlsRegisteredKey = "identitydTLS"
diff --git a/services/identity/identitylib/test_identityd.go b/services/identity/identitylib/test_identityd.go
index 1559091..03cdf0a 100644
--- a/services/identity/identitylib/test_identityd.go
+++ b/services/identity/identitylib/test_identityd.go
@@ -94,7 +94,6 @@
revocationManager,
params,
caveats.NewMockCaveatSelector(),
- nil,
"",
"identity")
diff --git a/services/identity/internal/blesser/macaroon.go b/services/identity/internal/blesser/macaroon.go
index c96c7cf..4a035d2 100644
--- a/services/identity/internal/blesser/macaroon.go
+++ b/services/identity/internal/blesser/macaroon.go
@@ -6,6 +6,7 @@
import (
"fmt"
+ "strings"
"time"
"v.io/x/ref/services/identity"
@@ -48,6 +49,13 @@
if len(m.Caveats) == 0 {
m.Caveats = []security.Caveat{security.UnconstrainedUse()}
}
+ var extension string
+ // TODO(ashankar): Remove after the transition from running identityd as "dev.v.io/root" to "dev.v.io/u" is complete.
+ if local := security.LocalBlessingNames(ctx, secCall); len(local) == 1 && strings.HasSuffix(local[0], security.ChainSeparator+"u") {
+ extension = m.Name
+ } else {
+ extension = strings.Join([]string{"users", m.Name}, security.ChainSeparator)
+ }
return secCall.LocalPrincipal().Bless(secCall.RemoteBlessings().PublicKey(),
- secCall.LocalBlessings(), m.Name, m.Caveats[0], m.Caveats[1:]...)
+ secCall.LocalBlessings(), extension, m.Caveats[0], m.Caveats[1:]...)
}
diff --git a/services/identity/internal/blesser/macaroon_test.go b/services/identity/internal/blesser/macaroon_test.go
index 7e537f6..3306825 100644
--- a/services/identity/internal/blesser/macaroon_test.go
+++ b/services/identity/internal/blesser/macaroon_test.go
@@ -35,7 +35,7 @@
if _, err := blesser.Bless(ctx, call, newMacaroon(t, key, m)); err == nil || err.Error() != wantErr {
t.Errorf("Bless(...) failed with error: %v, want: %v", err, wantErr)
}
- m = oauth.BlessingMacaroon{Creation: time.Now(), Name: "user", Caveats: []security.Caveat{cOnlyMethodFoo}}
+ m = oauth.BlessingMacaroon{Creation: time.Now(), Name: "bugsbunny", Caveats: []security.Caveat{cOnlyMethodFoo}}
b, err := blesser.Bless(ctx, call, newMacaroon(t, key, m))
if err != nil {
t.Errorf("Bless failed: %v", err)
@@ -51,13 +51,13 @@
t.Errorf("Got blessing with info %v, want nil", got)
}
// But once it recognizes the provider, it should see exactly the name
- // "provider/user" for the caveat cOnlyMethodFoo.
+ // "provider/users/bugsbunny" for the caveat cOnlyMethodFoo.
user.AddToRoots(b)
binfo := user.BlessingsInfo(b)
if num := len(binfo); num != 1 {
t.Errorf("Got blessings with %d names, want exactly one name", num)
}
- wantName := "provider/user"
+ wantName := "provider/users/bugsbunny"
if got, want := binfo[wantName], []security.Caveat{cOnlyMethodFoo}; !reflect.DeepEqual(got, want) {
t.Errorf("binfo[%q]: Got %v, want %v", wantName, got, want)
}
diff --git a/services/identity/internal/blesser/oauth.go b/services/identity/internal/blesser/oauth.go
index 127658d..e79c9c2 100644
--- a/services/identity/internal/blesser/oauth.go
+++ b/services/identity/internal/blesser/oauth.go
@@ -12,7 +12,6 @@
"v.io/x/ref/services/identity"
"v.io/x/ref/services/identity/internal/oauth"
"v.io/x/ref/services/identity/internal/revocation"
- "v.io/x/ref/services/identity/internal/util"
"v.io/v23/context"
"v.io/v23/rpc"
@@ -24,7 +23,6 @@
authcodeClient struct{ ID, Secret string }
accessTokenClients []oauth.AccessTokenClient
duration time.Duration
- emailClassifier *util.EmailClassifier
dischargerLocation string
revocationManager revocation.RevocationManager
}
@@ -35,8 +33,6 @@
OAuthProvider oauth.OAuthProvider
// The OAuth client IDs and names for the clients of the BlessUsingAccessToken RPCs.
AccessTokenClients []oauth.AccessTokenClient
- // Determines prefixes used for blessing extensions based on email address.
- EmailClassifier *util.EmailClassifier
// The object name of the discharger service. If this is empty then revocation caveats will not be granted.
DischargerLocation string
// The revocation manager that generates caveats and manages revocation.
@@ -56,7 +52,6 @@
return identity.OAuthBlesserServer(&oauthBlesser{
oauthProvider: p.OAuthProvider,
duration: p.BlessingDuration,
- emailClassifier: p.EmailClassifier,
dischargerLocation: p.DischargerLocation,
revocationManager: p.RevocationManager,
accessTokenClients: p.AccessTokenClients,
@@ -69,10 +64,10 @@
if err != nil {
return noblessings, "", err
}
- return b.bless(call.Security(), email, clientName)
+ return b.bless(ctx, call.Security(), email, clientName)
}
-func (b *oauthBlesser) bless(call security.Call, email, clientName string) (security.Blessings, string, error) {
+func (b *oauthBlesser) bless(ctx *context.T, call security.Call, email, clientName string) (security.Blessings, string, error) {
var noblessings security.Blessings
self := call.LocalPrincipal()
if self == nil {
@@ -88,16 +83,22 @@
if err != nil {
return noblessings, "", err
}
- extension := strings.Join([]string{
- b.emailClassifier.Classify(email),
- email,
- // Append clientName (e.g., "android", "chrome") to the email and then bless under that.
- // Since blessings issued by this process do not have many caveats on them and typically
- // have a large expiry duration, we include the clientName in the extension so that
- // servers can explicitly distinguish these clients while specifying authorization policies
- // (say, via AccessLists).
- clientName,
- }, security.ChainSeparator)
+ var parts []string
+ // TODO(ashankar): Remove this - here only for the transition from
+ // running identityd as "dev.v.io/root" to running it as "dev.v.io/u"
+ // At that point, can also remove the "ctx" argument to this method.
+ if bnames := security.LocalBlessingNames(ctx, call); len(bnames) == 1 && strings.HasSuffix(bnames[0], security.ChainSeparator+"u") {
+ parts = []string{email}
+ } else {
+ parts = []string{"users", email}
+ }
+ // Append clientName (e.g., "android", "chrome") to the email and then bless under that.
+ // Since blessings issued by this process do not have many caveats on them and typically
+ // have a large expiry duration, we include the clientName in the extension so that
+ // servers can explicitly distinguish these clients while specifying authorization policies
+ // (say, via AccessLists).
+ parts = append(parts, clientName)
+ extension := strings.Join(parts, security.ChainSeparator)
blessing, err := self.Bless(call.RemoteBlessings().PublicKey(), call.LocalBlessings(), extension, caveat)
if err != nil {
return noblessings, "", err
diff --git a/services/identity/internal/identityd_test/doc.go b/services/identity/internal/identityd_test/doc.go
new file mode 100644
index 0000000..d7d7b6e
--- /dev/null
+++ b/services/identity/internal/identityd_test/doc.go
@@ -0,0 +1,86 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command identityd_test runs a daemon HTTP server that uses OAuth to create
+security.Blessings objects.
+
+Starts a test version of the identityd server that mocks out oauth, auditing,
+and revocation.
+
+To generate TLS certificates so the HTTP server can use SSL:
+ go run $(go list -f {{.Dir}} "crypto/tls")/generate_cert.go --host <IP address>
+
+Usage:
+ identityd_test [flags]
+
+The identityd_test flags are:
+ -assets-prefix=
+ Host serving the web assets for the identity server.
+ -browser=false
+ Whether to open a browser caveat selector.
+ -external-http-addr=
+ External address on which the HTTP server listens on. If none is provided
+ the server will only listen on -http-addr.
+ -http-addr=localhost:0
+ Address on which the HTTP server listens on.
+ -mount-prefix=identity
+ Mount name prefix to use. May be rooted.
+ -oauth-email=testemail@example.com
+ Username for the mock oauth to put in the returned blessings.
+ -tls-config=
+ Comma-separated list of TLS certificate and private key files, in that order.
+ This must be provided.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/identity/internal/identityd_test/main.go b/services/identity/internal/identityd_test/main.go
index 59e0f0d..f9cccac 100644
--- a/services/identity/internal/identityd_test/main.go
+++ b/services/identity/internal/identityd_test/main.go
@@ -2,19 +2,20 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// HTTP server that uses OAuth to create security.Blessings objects.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
"flag"
- "fmt"
"net"
- "os"
"time"
"v.io/v23"
- "v.io/x/lib/vlog"
-
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/static"
"v.io/x/ref/services/identity/internal/auditor"
"v.io/x/ref/services/identity/internal/blesser"
@@ -26,49 +27,72 @@
)
var (
- // Flags controlling the HTTP server
- externalHttpAddr = flag.String("external-http-addr", "", "External address on which the HTTP server listens on. If none is provided the server will only listen on -http-addr.")
- httpAddr = flag.String("http-addr", "localhost:0", "Address on which the HTTP server listens on.")
- tlsConfig = flag.String("tls-config", "", "Comma-separated list of TLS certificate and private key files, in that order. This must be provided.")
- assetsPrefix = flag.String("assets-prefix", "", "host serving the web assets for the identity server")
- mountPrefix = flag.String("mount-prefix", "identity", "mount name prefix to use. May be rooted.")
- browser = flag.Bool("browser", false, "whether to open a browser caveat selector")
- oauthEmail = flag.String("oauth-email", "testemail@example.com", "Username for the mock oauth to put in the returned blessings")
+ externalHttpAddr, httpAddr, tlsConfig, assetsPrefix, mountPrefix string
+ browser bool
+ oauthEmail string
)
-func main() {
- flag.Usage = usage
- ctx, shutdown := v23.Init()
- defer shutdown()
+func init() {
+ // Flags controlling the HTTP server
+ cmdTest.Flags.StringVar(&externalHttpAddr, "external-http-addr", "", "External address on which the HTTP server listens on. If none is provided the server will only listen on -http-addr.")
+ cmdTest.Flags.StringVar(&httpAddr, "http-addr", "localhost:0", "Address on which the HTTP server listens on.")
+ cmdTest.Flags.StringVar(&tlsConfig, "tls-config", "", "Comma-separated list of TLS certificate and private key files, in that order. This must be provided.")
+ cmdTest.Flags.StringVar(&assetsPrefix, "assets-prefix", "", "Host serving the web assets for the identity server.")
+ cmdTest.Flags.StringVar(&mountPrefix, "mount-prefix", "identity", "Mount name prefix to use. May be rooted.")
+ cmdTest.Flags.BoolVar(&browser, "browser", false, "Whether to open a browser caveat selector.")
+ cmdTest.Flags.StringVar(&oauthEmail, "oauth-email", "testemail@example.com", "Username for the mock oauth to put in the returned blessings.")
+}
+func main() {
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdTest)
+}
+
+var cmdTest = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runIdentityDTest),
+ Name: "identityd_test",
+ Short: "Runs HTTP server that creates security.Blessings objects",
+ Long: `
+Command identityd_test runs a daemon HTTP server that uses OAuth to create
+security.Blessings objects.
+
+Starts a test version of the identityd server that mocks out oauth, auditing,
+and revocation.
+
+To generate TLS certificates so the HTTP server can use SSL:
+ go run $(go list -f {{.Dir}} "crypto/tls")/generate_cert.go --host <IP address>
+`,
+}
+
+func runIdentityDTest(ctx *context.T, env *cmdline.Env, args []string) error {
// Duration to use for tls cert and blessing duration.
duration := 365 * 24 * time.Hour
// If no tlsConfig has been provided, write and use our own.
if flag.Lookup("tls-config").Value.String() == "" {
- addr := *externalHttpAddr
- if *externalHttpAddr == "" {
- addr = *httpAddr
+ addr := externalHttpAddr
+ if externalHttpAddr == "" {
+ addr = httpAddr
}
host, _, err := net.SplitHostPort(addr)
if err != nil {
// NOTE(caprita): The (non-test) identityd binary
// accepts an address with no port. Should this test
// binary do the same instead?
- vlog.Fatalf("Failed to parse %q: %v", addr, err)
+ return env.UsageErrorf("Failed to parse http address %q: %v", addr, err)
}
certFile, keyFile, err := util.WriteCertAndKey(host, duration)
if err != nil {
- vlog.Fatal(err)
+ return err
}
if err := flag.Set("tls-config", certFile+","+keyFile); err != nil {
- vlog.Fatal(err)
+ return err
}
}
auditor, reader := auditor.NewMockBlessingAuditor()
revocationManager := revocation.NewMockRevocationManager()
- oauthProvider := oauth.NewMockOAuth(*oauthEmail)
+ oauthProvider := oauth.NewMockOAuth(oauthEmail)
params := blesser.OAuthBlesserParams{
OAuthProvider: oauthProvider,
@@ -77,8 +101,8 @@
}
caveatSelector := caveats.NewMockCaveatSelector()
- if *browser {
- caveatSelector = caveats.NewBrowserCaveatSelector(*assetsPrefix)
+ if browser {
+ caveatSelector = caveats.NewBrowserCaveatSelector(assetsPrefix)
}
listenSpec := v23.GetListenSpec(ctx)
@@ -89,20 +113,8 @@
revocationManager,
params,
caveatSelector,
- nil,
- *assetsPrefix,
- *mountPrefix)
- s.Serve(ctx, &listenSpec, *externalHttpAddr, *httpAddr, *tlsConfig)
-}
-
-func usage() {
- fmt.Fprintf(os.Stderr, `%s starts a test version of the identityd server that
-mocks out oauth, auditing, and revocation.
-
-To generate TLS certificates so the HTTP server can use SSL:
-go run $(go list -f {{.Dir}} "crypto/tls")/generate_cert.go --host <IP address>
-
-Flags:
-`, os.Args[0])
- flag.PrintDefaults()
+ assetsPrefix,
+ mountPrefix)
+ s.Serve(ctx, &listenSpec, externalHttpAddr, httpAddr, tlsConfig)
+ return nil
}
diff --git a/services/identity/internal/oauth/handler.go b/services/identity/internal/oauth/handler.go
index c2de6ab..50c753a 100644
--- a/services/identity/internal/oauth/handler.go
+++ b/services/identity/internal/oauth/handler.go
@@ -75,10 +75,6 @@
// MacaroonBlessingService is the object name to which macaroons create by this HTTP
// handler can be exchanged for a blessing.
MacaroonBlessingService string
- // EmailClassifier is used to decide the prefix used for blessing extensions.
- // For example, if EmailClassifier.Classify("foo@bar.com") returns "guests",
- // then the email foo@bar.com will receive the blessing "guests/foo@bar.com".
- EmailClassifier *util.EmailClassifier
// OAuthProvider is used to authenticate and get a blessee email.
OAuthProvider OAuthProvider
// CaveatSelector is used to obtain caveats from the user when seeking a blessing.
@@ -387,10 +383,13 @@
util.HTTPServerError(w, fmt.Errorf("failed to get server blessings"))
return
}
- parts := []string{
- string(localBlessings[0]),
- h.args.EmailClassifier.Classify(email),
- email,
+ var parts []string
+ // TODO(ashankar): Remove after the transition from running identityd
+ // as "dev.v.io/root" to "dev.v.io/u" is complete.
+ if local := string(localBlessings[0]); strings.HasSuffix(local, security.ChainSeparator+"u") {
+ parts = []string{local, email}
+ } else {
+ parts = []string{local, "users", email}
}
fullBlessingName := strings.Join(parts, security.ChainSeparator)
if err := h.args.CaveatSelector.Render(fullBlessingName, outputMacaroon, redirectURL(h.args.Addr, sendMacaroonRoute), w, r); err != nil {
@@ -416,10 +415,7 @@
util.HTTPBadRequest(w, r, fmt.Errorf("failed to create caveats: %v", err))
return
}
- parts := []string{
- h.args.EmailClassifier.Classify(inputMacaroon.Email),
- inputMacaroon.Email,
- }
+ parts := []string{inputMacaroon.Email}
if len(blessingExtension) > 0 {
parts = append(parts, blessingExtension)
}
diff --git a/services/identity/internal/server/identityd.go b/services/identity/internal/server/identityd.go
index 9a34e15..4294c71 100644
--- a/services/identity/internal/server/identityd.go
+++ b/services/identity/internal/server/identityd.go
@@ -35,7 +35,6 @@
"v.io/x/ref/services/identity/internal/oauth"
"v.io/x/ref/services/identity/internal/revocation"
"v.io/x/ref/services/identity/internal/templates"
- "v.io/x/ref/services/identity/internal/util"
)
const (
@@ -57,7 +56,6 @@
revocationManager revocation.RevocationManager
oauthBlesserParams blesser.OAuthBlesserParams
caveatSelector caveats.CaveatSelector
- emailClassifier *util.EmailClassifier
rootedObjectAddrs []naming.Endpoint
assetsPrefix string
mountNamePrefix string
@@ -68,7 +66,7 @@
// - auditor and blessingLogReader to audit the root principal and read audit logs
// - revocationManager to store revocation data and grant discharges
// - oauthBlesserParams to configure the identity.OAuthBlesser service
-func NewIdentityServer(oauthProvider oauth.OAuthProvider, auditor audit.Auditor, blessingLogReader auditor.BlessingLogReader, revocationManager revocation.RevocationManager, oauthBlesserParams blesser.OAuthBlesserParams, caveatSelector caveats.CaveatSelector, emailClassifier *util.EmailClassifier, assetsPrefix, mountNamePrefix string) *IdentityServer {
+func NewIdentityServer(oauthProvider oauth.OAuthProvider, auditor audit.Auditor, blessingLogReader auditor.BlessingLogReader, revocationManager revocation.RevocationManager, oauthBlesserParams blesser.OAuthBlesserParams, caveatSelector caveats.CaveatSelector, assetsPrefix, mountNamePrefix string) *IdentityServer {
return &IdentityServer{
oauthProvider: oauthProvider,
auditor: auditor,
@@ -76,7 +74,6 @@
revocationManager: revocationManager,
oauthBlesserParams: oauthBlesserParams,
caveatSelector: caveatSelector,
- emailClassifier: emailClassifier,
assetsPrefix: assetsPrefix,
mountNamePrefix: mountNamePrefix,
}
@@ -166,7 +163,6 @@
MacaroonBlessingService: naming.JoinAddressName(published[0], macaroonService),
OAuthProvider: s.oauthProvider,
CaveatSelector: s.caveatSelector,
- EmailClassifier: s.emailClassifier,
AssetsPrefix: s.assetsPrefix,
}
if s.revocationManager != nil {
diff --git a/services/identity/internal/util/classify.go b/services/identity/internal/util/classify.go
deleted file mode 100644
index 40e0663..0000000
--- a/services/identity/internal/util/classify.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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.
-
-package util
-
-import (
- "fmt"
- "strings"
- "sync"
-)
-
-const defaultClass = "users"
-
-// EmailClassifier classifies/categorizes email addresses based on the domain.
-type EmailClassifier struct {
- mu sync.RWMutex
- m map[string]string
-}
-
-// Classify returns the classification of email.
-func (c *EmailClassifier) Classify(email string) string {
- if c == nil {
- return defaultClass
- }
- parts := strings.Split(email, "@")
- if len(parts) != 2 {
- return defaultClass
- }
- domain := parts[1]
- c.mu.RLock()
- defer c.mu.RUnlock()
- if class := c.m[domain]; len(class) > 0 {
- return class
- }
- return defaultClass
-}
-
-// Set implements flag.Value.
-//
-// value should be a comma-separated list of <domain>=<class> pairs.
-func (c *EmailClassifier) Set(value string) error {
- m := make(map[string]string)
- for _, entry := range strings.Split(value, ",") {
- pair := strings.Split(entry, "=")
- if len(pair) != 2 {
- return fmt.Errorf("invalid pair %q: must be in <domain>=<class> format", entry)
- }
- domain := strings.TrimSpace(pair[0])
- class := strings.TrimSpace(pair[1])
- if len(domain) == 0 {
- return fmt.Errorf("empty domain in %q", entry)
- }
- if len(class) == 0 {
- return fmt.Errorf("empty class in %q", entry)
- }
- m[domain] = class
- }
- c.mu.Lock()
- c.m = m
- c.mu.Unlock()
- return nil
-}
-
-// Get implements flag.Getter.
-func (c *EmailClassifier) Get() interface{} {
- return c
-}
-
-func (c *EmailClassifier) String() string {
- c.mu.RLock()
- defer c.mu.RUnlock()
- return fmt.Sprintf("%v", c.m)
-}
diff --git a/services/identity/internal/util/classify_test.go b/services/identity/internal/util/classify_test.go
deleted file mode 100644
index 859d86d..0000000
--- a/services/identity/internal/util/classify_test.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.
-
-package util
-
-import (
- "flag"
- "testing"
-)
-
-func TestEmailClassifier(t *testing.T) {
- fs := flag.NewFlagSet("TestEmailClassifier", flag.PanicOnError)
- var c EmailClassifier
- fs.Var(&c, "myflag", "my usage")
- if err := fs.Parse([]string{"--myflag", "foo.com=internal,bar.com=external"}); err != nil {
- t.Fatal(err)
- }
- tests := []struct {
- in, out string
- }{
- {"batman@foo.com", "internal"},
- {"bugsbunny@foo.com.com", "users"},
- {"daffyduck@bar.com", "external"},
- {"joker@other.com", "users"},
- }
- for _, test := range tests {
- if got := c.Classify(test.in); got != test.out {
- t.Errorf("%q: Got %q, want %q", test.in, got, test.out)
- }
- }
-}
diff --git a/services/mounttable/mounttabled/doc.go b/services/mounttable/mounttabled/doc.go
new file mode 100644
index 0000000..8c86b66
--- /dev/null
+++ b/services/mounttable/mounttabled/doc.go
@@ -0,0 +1,77 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command mounttabled runs the mounttable daemon, which implements the
+v.io/v23/services/mounttable interfaces.
+
+Usage:
+ mounttabled [flags]
+
+The mounttabled flags are:
+ -acls=
+ AccessList file. Default is to allow all access.
+ -name=
+ If provided, causes the mount table to mount itself under this name. The
+ name may be absolute for a remote mount table service (e.g. "/<remote mt
+ address>//some/suffix") or could be relative to this process' default mount
+ table (e.g. "some/suffix").
+ -neighborhood-name=
+ If provided, enables sharing with the local neighborhood with the provided
+ name. The address of this mounttable will be published to the neighboorhood
+ and everything in the neighborhood will be visible on this mounttable.
+ -persist-dir=
+ Directory in which to persist permissions.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/mounttable/mounttabled/mounttable.go b/services/mounttable/mounttabled/mounttable.go
index 7616d2b..2bc4363 100644
--- a/services/mounttable/mounttabled/mounttable.go
+++ b/services/mounttable/mounttabled/mounttable.go
@@ -2,37 +2,50 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon mounttabled implements the v.io/v23/services/mounttable interfaces.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
"fmt"
- "os"
"v.io/v23"
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
-
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
"v.io/x/ref/services/mounttable/mounttablelib"
)
-var (
- mountName = flag.String("name", "", `<name>, if provided, causes the mount table to mount itself under that name. The name may be absolute for a remote mount table service (e.g., "/<remote mt address>//some/suffix") or could be relative to this process' default mount table (e.g., "some/suffix").`)
- aclFile = flag.String("acls", "", "AccessList file. Default is to allow all access.")
- nhName = flag.String("neighborhood-name", "", `<nh name>, if provided, will enable sharing with the local neighborhood with the provided name. The address of this mounttable will be published to the neighboorhood and everything in the neighborhood will be visible on this mounttable.`)
- persistDir = flag.String("persist-dir", "", `Directory in which to persist permissions.`)
-)
+var mountName, aclFile, nhName, persistDir string
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdMTD.Flags.StringVar(&mountName, "name", "", `If provided, causes the mount table to mount itself under this name. The name may be absolute for a remote mount table service (e.g. "/<remote mt address>//some/suffix") or could be relative to this process' default mount table (e.g. "some/suffix").`)
+ cmdMTD.Flags.StringVar(&aclFile, "acls", "", "AccessList file. Default is to allow all access.")
+ cmdMTD.Flags.StringVar(&nhName, "neighborhood-name", "", `If provided, enables sharing with the local neighborhood with the provided name. The address of this mounttable will be published to the neighboorhood and everything in the neighborhood will be visible on this mounttable.`)
+ cmdMTD.Flags.StringVar(&persistDir, "persist-dir", "", `Directory in which to persist permissions.`)
- name, stop, err := mounttablelib.StartServers(ctx, v23.GetListenSpec(ctx), *mountName, *nhName, *aclFile, *persistDir, "mounttable")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdMTD)
+}
+
+var cmdMTD = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runMountTableD),
+ Name: "mounttabled",
+ Short: "Runs the mounttable interface daemon",
+ Long: `
+Command mounttabled runs the mounttable daemon, which implements the
+v.io/v23/services/mounttable interfaces.
+`,
+}
+
+func runMountTableD(ctx *context.T, env *cmdline.Env, args []string) error {
+ name, stop, err := mounttablelib.StartServers(ctx, v23.GetListenSpec(ctx), mountName, nhName, aclFile, persistDir, "mounttable")
if err != nil {
- vlog.Errorf("mounttablelib.StartServers failed: %v", err)
- os.Exit(1)
+ return fmt.Errorf("mounttablelib.StartServers failed: %v", err)
}
defer stop()
@@ -42,4 +55,5 @@
// Wait until signal is received.
vlog.Info("Received signal ", <-signals.ShutdownOnSignals(ctx))
+ return nil
}
diff --git a/services/profile/profile/impl_test.go b/services/profile/profile/impl_test.go
index 2c4e135..cf2b402 100644
--- a/services/profile/profile/impl_test.go
+++ b/services/profile/profile/impl_test.go
@@ -131,7 +131,7 @@
exists := naming.JoinAddressName(endpoint.String(), "exists")
// Test the 'label' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"label", exists}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"label", exists}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := spec.Label, strings.TrimSpace(stdout.String()); got != expected {
@@ -140,7 +140,7 @@
stdout.Reset()
// Test the 'description' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"description", exists}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"description", exists}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := spec.Description, strings.TrimSpace(stdout.String()); got != expected {
@@ -149,7 +149,7 @@
stdout.Reset()
// Test the 'spec' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"specification", exists}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"specification", exists}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := fmt.Sprintf("%#v", spec), strings.TrimSpace(stdout.String()); got != expected {
@@ -158,7 +158,7 @@
stdout.Reset()
// Test the 'put' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"put", exists}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"put", exists}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := "Profile added successfully.", strings.TrimSpace(stdout.String()); got != expected {
@@ -167,7 +167,7 @@
stdout.Reset()
// Test the 'remove' command.
- if err := v23cmd.ParseAndRun(cmdRoot, ctx, env, []string{"remove", exists}); err != nil {
+ if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, []string{"remove", exists}); err != nil {
t.Fatalf("%v", err)
}
if expected, got := "Profile removed successfully.", strings.TrimSpace(stdout.String()); got != expected {
diff --git a/services/profile/profiled/doc.go b/services/profile/profiled/doc.go
new file mode 100644
index 0000000..07c2b63
--- /dev/null
+++ b/services/profile/profiled/doc.go
@@ -0,0 +1,68 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command profiled runs the profile daemon, which implements the
+v.io/x/ref/services/repository.Profile interface.
+
+Usage:
+ profiled [flags]
+
+The profiled flags are:
+ -name=
+ Name to mount the profile repository as.
+ -store=
+ Local directory to store profiles in.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/profile/profiled/main.go b/services/profile/profiled/main.go
index 9dd307f..9fd3b35 100644
--- a/services/profile/profiled/main.go
+++ b/services/profile/profiled/main.go
@@ -2,54 +2,70 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon profiled implements the v.io/x/ref/services/repository.Profile
-// interface.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
+ "fmt"
"v.io/v23"
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/lib/security/securityflag"
"v.io/x/ref/lib/signals"
-
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
)
-var (
- name = flag.String("name", "", "name to mount the profile repository as")
- store = flag.String("store", "", "local directory to store profiles in")
-)
+var name, store string
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdProfileD.Flags.StringVar(&name, "name", "", "Name to mount the profile repository as.")
+ cmdProfileD.Flags.StringVar(&store, "store", "", "Local directory to store profiles in.")
- if *store == "" {
- vlog.Fatalf("Specify a directory for storing profiles using --store=<name>")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdProfileD)
+}
+
+var cmdProfileD = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runProfileD),
+ Name: "profiled",
+ Short: "Runs the profile daemon.",
+ Long: `
+Command profiled runs the profile daemon, which implements the
+v.io/x/ref/services/repository.Profile interface.
+`,
+}
+
+func runProfileD(ctx *context.T, env *cmdline.Env, args []string) error {
+ if store == "" {
+ return env.UsageErrorf("Specify a directory for storing profiles using --store=<name>")
}
server, err := v23.NewServer(ctx)
if err != nil {
- vlog.Fatalf("NewServer() failed: %v", err)
+ return fmt.Errorf("NewServer() failed: %v", err)
}
- dispatcher, err := NewDispatcher(*store, securityflag.NewAuthorizerOrDie())
+ dispatcher, err := NewDispatcher(store, securityflag.NewAuthorizerOrDie())
if err != nil {
- vlog.Fatalf("NewDispatcher() failed: %v", err)
+ return fmt.Errorf("NewDispatcher() failed: %v", err)
}
ls := v23.GetListenSpec(ctx)
endpoint, err := server.Listen(ls)
if err != nil {
- vlog.Fatalf("Listen(%s) failed: %v", ls, err)
+ return fmt.Errorf("Listen(%s) failed: %v", ls, err)
}
- if err := server.ServeDispatcher(*name, dispatcher); err != nil {
- vlog.Fatalf("ServeDispatcher(%v) failed: %v", *name, err)
+ if err := server.ServeDispatcher(name, dispatcher); err != nil {
+ return fmt.Errorf("ServeDispatcher(%v) failed: %v", name, err)
}
vlog.Infof("Profile repository running at endpoint=%q", endpoint)
// Wait until shutdown.
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
diff --git a/services/proxy/proxyd/doc.go b/services/proxy/proxyd/doc.go
new file mode 100644
index 0000000..7fd0915
--- /dev/null
+++ b/services/proxy/proxyd/doc.go
@@ -0,0 +1,77 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command proxyd is a daemon that listens for connections from Vanadium services
+(typically behind NATs) and proxies these services to the outside world.
+
+Usage:
+ proxyd [flags]
+
+The proxyd flags are:
+ -access-list=
+ Blessings that are authorized to listen via the proxy. JSON-encoded
+ representation of access.AccessList. An empty string implies the default
+ authorization policy.
+ -healthz-address=
+ Network address on which the HTTP healthz server runs. It is intended to be
+ used with a load balancer. The load balancer must be able to reach this
+ address in order to verify that the proxy server is running.
+ -name=
+ Name to mount the proxy as.
+ -published-address=
+ DEPRECATED - the proxy now uses listenspecs and the address chooser
+ mechanism.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/proxy/proxyd/main.go b/services/proxy/proxyd/main.go
index 920c7ad..2804ef6 100644
--- a/services/proxy/proxyd/main.go
+++ b/services/proxy/proxyd/main.go
@@ -2,51 +2,65 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon proxyd listens for connections from Vanadium services (typically
-// behind NATs) and proxies these services to the outside world.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
"bytes"
"encoding/json"
- "flag"
"fmt"
"net/http"
"time"
"v.io/v23"
+ "v.io/v23/context"
"v.io/v23/rpc"
"v.io/v23/security"
"v.io/v23/security/access"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
-
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
"v.io/x/ref/runtime/factories/static"
)
-var (
- pubAddress = flag.String("published-address", "", "deprecated - the proxy now uses listenspecs and the address chooser mechanism")
- healthzAddr = flag.String("healthz-address", "", "Network address on which the HTTP healthz server runs. It is intended to be used with a load balancer. The load balancer must be able to reach this address in order to verify that the proxy server is running")
- name = flag.String("name", "", "Name to mount the proxy as")
- acl = flag.String("access-list", "", "Blessings that are authorized to listen via the proxy. JSON-encoded representation of access.AccessList. An empty string implies the default authorization policy.")
-)
+var pubAddress, healthzAddr, name, acl string
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdProxyD.Flags.StringVar(&pubAddress, "published-address", "", "DEPRECATED - the proxy now uses listenspecs and the address chooser mechanism.")
+ cmdProxyD.Flags.StringVar(&healthzAddr, "healthz-address", "", "Network address on which the HTTP healthz server runs. It is intended to be used with a load balancer. The load balancer must be able to reach this address in order to verify that the proxy server is running.")
+ cmdProxyD.Flags.StringVar(&name, "name", "", "Name to mount the proxy as.")
+ cmdProxyD.Flags.StringVar(&acl, "access-list", "", "Blessings that are authorized to listen via the proxy. JSON-encoded representation of access.AccessList. An empty string implies the default authorization policy.")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdProxyD)
+}
+
+var cmdProxyD = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runProxyD),
+ Name: "proxyd",
+ Short: "Proxies services to the outside world",
+ Long: `
+Command proxyd is a daemon that listens for connections from Vanadium services
+(typically behind NATs) and proxies these services to the outside world.
+`,
+}
+
+func runProxyD(ctx *context.T, env *cmdline.Env, args []string) error {
listenSpec := v23.GetListenSpec(ctx)
if len(listenSpec.Addrs) != 1 {
- vlog.Fatalf("proxyd can only listen on one address: %v", listenSpec.Addrs)
+ return env.UsageErrorf("proxyd can only listen on one address: %v", listenSpec.Addrs)
}
if listenSpec.Proxy != "" {
- vlog.Fatalf("proxyd cannot listen through another proxy")
+ return env.UsageErrorf("proxyd cannot listen through another proxy")
}
var authorizer security.Authorizer
- if len(*acl) > 0 {
+ if len(acl) > 0 {
var list access.AccessList
- if err := json.NewDecoder(bytes.NewBufferString(*acl)).Decode(&list); err != nil {
- vlog.Fatalf("invalid --access-list: %v", err)
+ if err := json.NewDecoder(bytes.NewBufferString(acl)).Decode(&list); err != nil {
+ return env.UsageErrorf("invalid -access-list: %v", err)
}
// Always add ourselves, for the the reserved methods server
// started below.
@@ -55,13 +69,13 @@
authorizer = list
}
- proxyShutdown, proxyEndpoint, err := static.NewProxy(ctx, listenSpec, authorizer, *name)
+ proxyShutdown, proxyEndpoint, err := static.NewProxy(ctx, listenSpec, authorizer, name)
if err != nil {
- vlog.Fatal(err)
+ return err
}
defer proxyShutdown()
- if len(*name) > 0 {
+ if len(name) > 0 {
// Print out a directly accessible name for the proxy table so
// that integration tests can reliably read it from stdout.
fmt.Printf("NAME=%s\n", proxyEndpoint.Name())
@@ -69,30 +83,31 @@
fmt.Printf("Proxy listening on %s\n", proxyEndpoint)
}
- if len(*healthzAddr) != 0 {
- go startHealthzServer(*healthzAddr)
+ if len(healthzAddr) != 0 {
+ go startHealthzServer(healthzAddr)
}
// Start an RPC Server that listens through the proxy itself. This
// server will serve reserved methods only.
server, err := v23.NewServer(ctx)
if err != nil {
- vlog.Fatalf("NewServer failed: %v", err)
+ return fmt.Errorf("NewServer failed: %v", err)
}
defer server.Stop()
ls := rpc.ListenSpec{Proxy: proxyEndpoint.Name()}
if _, err := server.Listen(ls); err != nil {
- vlog.Fatalf("Listen(%v) failed: %v", ls, err)
+ return fmt.Errorf("Listen(%v) failed: %v", ls, err)
}
var monitoringName string
- if len(*name) > 0 {
- monitoringName = *name + "-mon"
+ if len(name) > 0 {
+ monitoringName = name + "-mon"
}
if err := server.ServeDispatcher(monitoringName, &nilDispatcher{}); err != nil {
- vlog.Fatalf("ServeDispatcher(%v) failed: %v", monitoringName, err)
+ return fmt.Errorf("ServeDispatcher(%v) failed: %v", monitoringName, err)
}
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
type nilDispatcher struct{}
diff --git a/services/role/roled/doc.go b/services/role/roled/doc.go
new file mode 100644
index 0000000..7f0ea03
--- /dev/null
+++ b/services/role/roled/doc.go
@@ -0,0 +1,67 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command roled runs the Role interface daemon.
+
+Usage:
+ roled [flags]
+
+The roled flags are:
+ -config-dir=
+ The directory where the role configuration files are stored.
+ -name=
+ The name to publish for this service.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/role/roled/main.go b/services/role/roled/main.go
index aea1ab7..42bce3f 100644
--- a/services/role/roled/main.go
+++ b/services/role/roled/main.go
@@ -2,57 +2,67 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon roled implements the Role interface.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
"fmt"
- "os"
"v.io/v23"
-
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/static"
irole "v.io/x/ref/services/role/roled/internal"
)
-var (
- configDir = flag.String("config-dir", "", "The directory where the role configuration files are stored.")
- name = flag.String("name", "", "The name to publish for this service.")
-)
+var configDir, name string
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdRoleD.Flags.StringVar(&configDir, "config-dir", "", "The directory where the role configuration files are stored.")
+ cmdRoleD.Flags.StringVar(&name, "name", "", "The name to publish for this service.")
- if len(*configDir) == 0 {
- fmt.Fprintf(os.Stderr, "--config-dir must be specified\n")
- os.Exit(1)
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdRoleD)
+}
+
+var cmdRoleD = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runRoleD),
+ Name: "roled",
+ Short: "Runs the Role interface daemon.",
+ Long: "Command roled runs the Role interface daemon.",
+}
+
+func runRoleD(ctx *context.T, env *cmdline.Env, args []string) error {
+ if len(configDir) == 0 {
+ return env.UsageErrorf("-config-dir must be specified")
}
- if len(*name) == 0 {
- fmt.Fprintf(os.Stderr, "--name must be specified\n")
- os.Exit(1)
+ if len(name) == 0 {
+ return env.UsageErrorf("-name must be specified")
}
server, err := v23.NewServer(ctx)
if err != nil {
- vlog.Fatalf("NewServer failed: %v", err)
+ return fmt.Errorf("NewServer failed: %v", err)
}
listenSpec := v23.GetListenSpec(ctx)
eps, err := server.Listen(listenSpec)
if err != nil {
- vlog.Fatalf("Listen(%v) failed: %v", listenSpec, err)
+ return fmt.Errorf("Listen(%v) failed: %v", listenSpec, err)
}
vlog.Infof("Listening on: %q", eps)
- if err := server.ServeDispatcher(*name, irole.NewDispatcher(*configDir, *name)); err != nil {
- vlog.Fatalf("ServeDispatcher(%q) failed: %v", *name, err)
+ if err := server.ServeDispatcher(name, irole.NewDispatcher(configDir, name)); err != nil {
+ return fmt.Errorf("ServeDispatcher(%q) failed: %v", name, err)
}
- if len(*name) > 0 {
- fmt.Printf("NAME=%s\n", *name)
+ if len(name) > 0 {
+ fmt.Printf("NAME=%s\n", name)
} else if len(eps) > 0 {
fmt.Printf("NAME=%s\n", eps[0].Name())
}
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
diff --git a/services/wspr/browsprd/main_nacl.go b/services/wspr/browsprd/main_nacl.go
index dcc23c3..4d07423 100644
--- a/services/wspr/browsprd/main_nacl.go
+++ b/services/wspr/browsprd/main_nacl.go
@@ -21,6 +21,7 @@
vsecurity "v.io/x/ref/lib/security"
_ "v.io/x/ref/runtime/factories/chrome"
"v.io/x/ref/runtime/internal/lib/websocket"
+ "v.io/x/ref/services/wspr/internal/app"
"v.io/x/ref/services/wspr/internal/browspr"
"v.io/x/ref/services/wspr/internal/channel/channel_nacl"
"v.io/x/ref/services/wspr/internal/rpc/server"
@@ -298,14 +299,14 @@
// HandleBrowsprMessage handles one-way messages of the type "browsprMsg" by
// sending them to browspr's handler.
-func (inst *browsprInstance) HandleBrowsprMessage(instanceId int32, origin string, message ppapi.Var) error {
- str, err := message.AsString()
+func (inst *browsprInstance) HandleBrowsprMessage(instanceId int32, origin string, varMsg ppapi.Var) error {
+ msg, err := varToMessage(varMsg)
if err != nil {
- return fmt.Errorf("Error while converting message to string: %v", err)
+ return fmt.Errorf("Invalid message: %v", err)
}
- vlog.VI(1).Infof("Calling browspr's HandleMessage: instanceId %d origin %s message %s", instanceId, origin, str)
- if err := inst.browspr.HandleMessage(instanceId, origin, str); err != nil {
+ vlog.VI(1).Infof("Calling browspr's HandleMessage: instanceId %d origin %s message %s", instanceId, origin, msg)
+ if err := inst.browspr.HandleMessage(instanceId, origin, msg); err != nil {
return fmt.Errorf("Error while handling message in browspr: %v", err)
}
return nil
@@ -415,3 +416,25 @@
func (*browsprInstance) MouseLockLost() {
vlog.VI(2).Infof("Got to MouseLockLost()")
}
+
+func varToMessage(v ppapi.Var) (app.Message, error) {
+ var msg app.Message
+ id, err := v.LookupIntValuedKey("id")
+ if err != nil {
+ return msg, err
+ }
+ ty, err := v.LookupIntValuedKey("type")
+ if err != nil {
+ return msg, err
+ }
+ data, err := v.LookupStringValuedKey("data")
+ if err != nil {
+ // OK for message to have empty data.
+ data = ""
+ }
+
+ msg.Id = int32(id)
+ msg.Data = data
+ msg.Type = app.MessageType(ty)
+ return msg, nil
+}
diff --git a/services/wspr/internal/app/app.go b/services/wspr/internal/app/app.go
index de2ebae..1063717 100644
--- a/services/wspr/internal/app/app.go
+++ b/services/wspr/internal/app/app.go
@@ -167,7 +167,7 @@
if blessings, ok := item.(security.Blessings); ok {
item = principal.ConvertBlessingsToHandle(blessings, c.blessingsCache.GetOrAddHandle(blessings))
}
- vomItem, err := lib.VomEncode(item)
+ vomItem, err := lib.HexVomEncode(item)
if err != nil {
w.Error(verror.New(marshallingError, ctx, item, err))
continue
@@ -442,7 +442,7 @@
)
func (l *localCall) Send(item interface{}) error {
- vomItem, err := lib.VomEncode(item)
+ vomItem, err := lib.HexVomEncode(item)
if err != nil {
err = verror.New(marshallingError, l.ctx, item, err)
l.w.Error(err)
@@ -732,7 +732,7 @@
// parseVeyronRequest parses a json rpc request into a RpcRequest object.
func (c *Controller) parseVeyronRequest(data string) (*RpcRequest, error) {
var msg RpcRequest
- if err := lib.VomDecode(data, &msg); err != nil {
+ if err := lib.HexVomDecode(data, &msg); err != nil {
return nil, err
}
vlog.VI(2).Infof("RpcRequest: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
diff --git a/services/wspr/internal/app/app.go.orig b/services/wspr/internal/app/app.go.orig
index fcefaa8..7243674 100644
--- a/services/wspr/internal/app/app.go.orig
+++ b/services/wspr/internal/app/app.go.orig
@@ -161,7 +161,7 @@
if blessings, ok := item.(security.Blessings); ok {
item = principal.ConvertBlessingsToHandle(blessings, c.blessingsCache.GetOrAddHandle(blessings))
}
- vomItem, err := lib.VomEncode(item)
+ vomItem, err := lib.HexVomEncode(item)
if err != nil {
w.Error(verror.New(marshallingError, ctx, item, err))
continue
@@ -205,7 +205,7 @@
OutArgs: results,
TraceResponse: vtrace.GetResponse(ctx),
}
- encoded, err := lib.VomEncode(response)
+ encoded, err := lib.HexVomEncode(response)
if err != nil {
w.Error(err)
return
@@ -430,7 +430,7 @@
)
func (l *localCall) Send(item interface{}) error {
- vomItem, err := lib.VomEncode(item)
+ vomItem, err := lib.HexVomEncode(item)
if err != nil {
err = verror.New(marshallingError, l.ctx, item, err)
l.w.Error(err)
@@ -717,7 +717,7 @@
// parseVeyronRequest parses a json rpc request into a RpcRequest object.
func (c *Controller) parseVeyronRequest(data string) (*RpcRequest, error) {
var msg RpcRequest
- if err := lib.VomDecode(data, &msg); err != nil {
+ if err := lib.HexVomDecode(data, &msg); err != nil {
return nil, err
}
vlog.VI(2).Infof("RpcRequest: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
diff --git a/services/wspr/internal/app/app_test.go b/services/wspr/internal/app/app_test.go
index 991f2dc..464790c 100644
--- a/services/wspr/internal/app/app_test.go
+++ b/services/wspr/internal/app/app_test.go
@@ -202,7 +202,7 @@
}
go func() {
for _, value := range testCase.streamingInputs {
- controller.SendOnStream(0, lib.VomEncodeOrDie(value), &writer)
+ controller.SendOnStream(0, lib.HexVomEncodeOrDie(value), &writer)
}
controller.CloseStream(0)
}()
@@ -223,7 +223,7 @@
}
func makeRPCResponse(outArgs ...*vdl.Value) string {
- return lib.VomEncodeOrDie(RpcResponse{
+ return lib.HexVomEncodeOrDie(RpcResponse{
OutArgs: outArgs,
TraceResponse: vtrace.Response{},
})
@@ -259,19 +259,19 @@
numOutArgs: 1,
expectedStream: []lib.Response{
lib.Response{
- Message: lib.VomEncodeOrDie(int32(1)),
+ Message: lib.HexVomEncodeOrDie(int32(1)),
Type: lib.ResponseStream,
},
lib.Response{
- Message: lib.VomEncodeOrDie(int32(3)),
+ Message: lib.HexVomEncodeOrDie(int32(3)),
Type: lib.ResponseStream,
},
lib.Response{
- Message: lib.VomEncodeOrDie(int32(6)),
+ Message: lib.HexVomEncodeOrDie(int32(6)),
Type: lib.ResponseStream,
},
lib.Response{
- Message: lib.VomEncodeOrDie(int32(10)),
+ Message: lib.HexVomEncodeOrDie(int32(10)),
Type: lib.ResponseStream,
},
lib.Response{
@@ -379,7 +379,7 @@
vomClientStream := []string{}
for _, m := range testCase.clientStream {
- vomClientStream = append(vomClientStream, lib.VomEncodeOrDie(m))
+ vomClientStream = append(vomClientStream, lib.HexVomEncodeOrDie(m))
}
mock := &mockJSServer{
t: t,
diff --git a/services/wspr/internal/app/granter.go b/services/wspr/internal/app/granter.go
index 40df476..bd9d4a9 100644
--- a/services/wspr/internal/app/granter.go
+++ b/services/wspr/internal/app/granter.go
@@ -29,7 +29,7 @@
GranterHandle: g.granterHandle,
Call: server.ConvertSecurityCall(g.c, ctx, call, true),
}
- encoded, err := lib.VomEncode(request)
+ encoded, err := lib.HexVomEncode(request)
if err != nil {
return security.Blessings{}, err
}
@@ -64,7 +64,7 @@
func (g *granterStream) Send(item interface{}) error {
dataString := item.(string)
var gr *GranterResponse
- if err := lib.VomDecode(dataString, &gr); err != nil {
+ if err := lib.HexVomDecode(dataString, &gr); err != nil {
return fmt.Errorf("error decoding granter response: %v", err)
}
g.c <- gr
diff --git a/services/wspr/internal/app/mock_jsServer_test.go b/services/wspr/internal/app/mock_jsServer_test.go
index 1113022..1c3bf96 100644
--- a/services/wspr/internal/app/mock_jsServer_test.go
+++ b/services/wspr/internal/app/mock_jsServer_test.go
@@ -14,6 +14,7 @@
"v.io/v23/vdl"
"v.io/v23/vdlroot/signature"
+ "v.io/v23/verror"
"v.io/v23/vom"
"v.io/x/ref/internal/reflectutil"
"v.io/x/ref/services/wspr/internal/lib"
@@ -73,13 +74,16 @@
return fmt.Errorf("Unknown message type: %d", responseType)
}
-func internalErrJSON(args interface{}) string {
- return fmt.Sprintf(`{"err": {
- "idAction": {
- "id": "v.io/v23/verror.Internal",
- "action": 0
- },
- "paramList": ["%v"]}, "results":[null]}`, args)
+func internalErr(args interface{}) string {
+ err := verror.E{
+ ID: verror.ID("v.io/v23/verror.Internal"),
+ Action: verror.ActionCode(0),
+ ParamList: []interface{}{args},
+ }
+
+ return lib.HexVomEncodeOrDie(server.LookupReply{
+ Err: err,
+ })
}
func (m *mockJSServer) Error(err error) {
@@ -108,26 +112,23 @@
}()
m.controllerReady.RLock()
defer m.controllerReady.RUnlock()
+
msg, err := normalize(v)
if err != nil {
- m.controller.HandleLookupResponse(m.flowCount, internalErrJSON(err))
+ m.controller.HandleLookupResponse(m.flowCount, internalErr(err))
return nil
}
expected := map[string]interface{}{"serverId": 0.0, "suffix": "adder"}
if !reflect.DeepEqual(msg, expected) {
- m.controller.HandleLookupResponse(m.flowCount, internalErrJSON(fmt.Sprintf("got: %v, want: %v", msg, expected)))
+ m.controller.HandleLookupResponse(m.flowCount, internalErr(fmt.Sprintf("got: %v, want: %v", msg, expected)))
return nil
}
- bytes, err := json.Marshal(map[string]interface{}{
- "handle": 0,
- "signature": lib.VomEncodeOrDie(m.serviceSignature),
- "hasAuthorizer": m.hasAuthorizer,
+ lookupReply := lib.HexVomEncodeOrDie(server.LookupReply{
+ Handle: 0,
+ Signature: m.serviceSignature,
+ HasAuthorizer: m.hasAuthorizer,
})
- if err != nil {
- m.controller.HandleLookupResponse(m.flowCount, internalErrJSON(fmt.Sprintf("failed to serialize %v", err)))
- return nil
- }
- m.controller.HandleLookupResponse(m.flowCount, string(bytes))
+ m.controller.HandleLookupResponse(m.flowCount, lookupReply)
return nil
}
@@ -147,62 +148,58 @@
m.hasCalledAuth = true
if !m.hasAuthorizer {
- m.controller.HandleAuthResponse(m.flowCount, internalErrJSON("unexpected auth request"))
+ m.controller.HandleAuthResponse(m.flowCount, internalErr("unexpected auth request"))
return nil
}
var msg server.AuthRequest
- if err := lib.VomDecode(v.(string), &msg); err != nil {
- m.controller.HandleAuthResponse(m.flowCount, internalErrJSON(fmt.Sprintf("error decoding %v:", err)))
+ if err := lib.HexVomDecode(v.(string), &msg); err != nil {
+ m.controller.HandleAuthResponse(m.flowCount, internalErr(fmt.Sprintf("error decoding %v:", err)))
return nil
}
if msg.Handle != 0 {
- m.controller.HandleAuthResponse(m.flowCount, internalErrJSON(fmt.Sprintf("unexpected handled: %v", msg.Handle)))
+ m.controller.HandleAuthResponse(m.flowCount, internalErr(fmt.Sprintf("unexpected handled: %v", msg.Handle)))
return nil
}
call := msg.Call
if field, got, want := "Method", call.Method, lib.LowercaseFirstCharacter(m.method); got != want {
- m.controller.HandleAuthResponse(m.flowCount, internalErrJSON(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
+ m.controller.HandleAuthResponse(m.flowCount, internalErr(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
return nil
}
if field, got, want := "Suffix", call.Suffix, "adder"; got != want {
- m.controller.HandleAuthResponse(m.flowCount, internalErrJSON(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
+ m.controller.HandleAuthResponse(m.flowCount, internalErr(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
return nil
}
// We expect localBlessings and remoteBlessings to be set and the publicKey be a string
if !validateBlessing(call.LocalBlessings) {
- m.controller.HandleAuthResponse(m.flowCount, internalErrJSON(fmt.Sprintf("bad localblessing:%v", call.LocalBlessings)))
+ m.controller.HandleAuthResponse(m.flowCount, internalErr(fmt.Sprintf("bad localblessing:%v", call.LocalBlessings)))
return nil
}
if !validateBlessing(call.RemoteBlessings) {
- m.controller.HandleAuthResponse(m.flowCount, internalErrJSON(fmt.Sprintf("bad remoteblessing:%v", call.RemoteBlessings)))
+ m.controller.HandleAuthResponse(m.flowCount, internalErr(fmt.Sprintf("bad remoteblessing:%v", call.RemoteBlessings)))
return nil
}
// We expect endpoints to be set
if !validateEndpoint(call.LocalEndpoint) {
- m.controller.HandleAuthResponse(m.flowCount, internalErrJSON(fmt.Sprintf("bad endpoint:%v", call.LocalEndpoint)))
+ m.controller.HandleAuthResponse(m.flowCount, internalErr(fmt.Sprintf("bad endpoint:%v", call.LocalEndpoint)))
return nil
}
if !validateEndpoint(call.RemoteEndpoint) {
- m.controller.HandleAuthResponse(m.flowCount, internalErrJSON(fmt.Sprintf("bad endpoint:%v", call.RemoteEndpoint)))
+ m.controller.HandleAuthResponse(m.flowCount, internalErr(fmt.Sprintf("bad endpoint:%v", call.RemoteEndpoint)))
return nil
}
- bytes, err := json.Marshal(map[string]interface{}{
- "err": m.authError,
+ authReply := lib.HexVomEncodeOrDie(server.AuthReply{
+ Err: m.authError,
})
- if err != nil {
- m.controller.HandleAuthResponse(m.flowCount, internalErrJSON(fmt.Sprintf("failed to serialize %v", err)))
- return nil
- }
- m.controller.HandleAuthResponse(m.flowCount, string(bytes))
+ m.controller.HandleAuthResponse(m.flowCount, authReply)
return nil
}
@@ -212,23 +209,23 @@
}()
if m.hasCalledAuth != m.hasAuthorizer {
- m.controller.HandleServerResponse(m.flowCount, internalErrJSON("authorizer hasn't been called yet"))
+ m.controller.HandleServerResponse(m.flowCount, internalErr("authorizer hasn't been called yet"))
return nil
}
var msg server.ServerRpcRequest
- if err := lib.VomDecode(v.(string), &msg); err != nil {
- m.controller.HandleServerResponse(m.flowCount, internalErrJSON(err))
+ if err := lib.HexVomDecode(v.(string), &msg); err != nil {
+ m.controller.HandleServerResponse(m.flowCount, internalErr(err))
return nil
}
if field, got, want := "Method", msg.Method, lib.LowercaseFirstCharacter(m.method); got != want {
- m.controller.HandleServerResponse(m.flowCount, internalErrJSON(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
+ m.controller.HandleServerResponse(m.flowCount, internalErr(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
return nil
}
if field, got, want := "Handle", msg.Handle, int32(0); got != want {
- m.controller.HandleServerResponse(m.flowCount, internalErrJSON(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
+ m.controller.HandleServerResponse(m.flowCount, internalErr(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
return nil
}
@@ -239,18 +236,18 @@
}
}
if field, got, want := "Args", vals, m.inArgs; !reflectutil.DeepEqual(got, want, &reflectutil.DeepEqualOpts{SliceEqNilEmpty: true}) {
- m.controller.HandleServerResponse(m.flowCount, internalErrJSON(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
+ m.controller.HandleServerResponse(m.flowCount, internalErr(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
return nil
}
call := msg.Call.SecurityCall
if field, got, want := "Suffix", call.Suffix, "adder"; got != want {
- m.controller.HandleServerResponse(m.flowCount, internalErrJSON(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
+ m.controller.HandleServerResponse(m.flowCount, internalErr(fmt.Sprintf("unexpected value for %s: got %v, want %v", field, got, want)))
return nil
}
if !validateBlessing(call.RemoteBlessings) {
- m.controller.HandleServerResponse(m.flowCount, internalErrJSON(fmt.Sprintf("bad Remoteblessing:%v", call.RemoteBlessings)))
+ m.controller.HandleServerResponse(m.flowCount, internalErr(fmt.Sprintf("bad Remoteblessing:%v", call.RemoteBlessings)))
return nil
}
@@ -288,7 +285,7 @@
defer m.sender.Done()
m.controllerReady.RLock()
for _, v := range m.serverStream {
- m.controller.SendOnStream(m.rpcFlow, lib.VomEncodeOrDie(v), m)
+ m.controller.SendOnStream(m.rpcFlow, lib.HexVomEncodeOrDie(v), m)
}
m.controllerReady.RUnlock()
}
@@ -314,12 +311,9 @@
Results: []*vdl.Value{m.finalResponse},
Err: m.finalError,
}
- vomReply, err := lib.VomEncode(reply)
- if err != nil {
- m.t.Fatalf("Failed to serialize the reply: %v", err)
- }
+
m.controllerReady.RLock()
- m.controller.HandleServerResponse(m.rpcFlow, vomReply)
+ m.controller.HandleServerResponse(m.rpcFlow, lib.HexVomEncodeOrDie(reply))
m.controllerReady.RUnlock()
return nil
}
diff --git a/services/wspr/internal/app/stream.go b/services/wspr/internal/app/stream.go
index 1a8c653..74852c7 100644
--- a/services/wspr/internal/app/stream.go
+++ b/services/wspr/internal/app/stream.go
@@ -81,7 +81,7 @@
config := <-os.initChan
for msg := range os.messages {
var item interface{}
- if err := lib.VomDecode(msg.data, &item); err != nil {
+ if err := lib.HexVomDecode(msg.data, &item); err != nil {
msg.writer.Error(fmt.Errorf("failed to decode stream arg from %v: %v", msg.data, err))
break
}
diff --git a/services/wspr/internal/browspr/browspr.go b/services/wspr/internal/browspr/browspr.go
index 5052ed5..8971fc3 100644
--- a/services/wspr/internal/browspr/browspr.go
+++ b/services/wspr/internal/browspr/browspr.go
@@ -17,6 +17,7 @@
"v.io/v23/vtrace"
"v.io/x/lib/vlog"
"v.io/x/ref/services/wspr/internal/account"
+ "v.io/x/ref/services/wspr/internal/app"
"v.io/x/ref/services/wspr/internal/principal"
)
@@ -92,7 +93,7 @@
// HandleMessage handles most messages from javascript and forwards them to a
// Controller.
-func (b *Browspr) HandleMessage(instanceId int32, origin, msg string) error {
+func (b *Browspr) HandleMessage(instanceId int32, origin string, msg app.Message) error {
b.mu.Lock()
p, ok := b.activeInstances[instanceId]
b.mu.Unlock()
diff --git a/services/wspr/internal/browspr/browspr_test.go b/services/wspr/internal/browspr/browspr_test.go
index 7f54006..cdb460c 100644
--- a/services/wspr/internal/browspr/browspr_test.go
+++ b/services/wspr/internal/browspr/browspr_test.go
@@ -7,7 +7,6 @@
import (
"bytes"
"encoding/hex"
- "encoding/json"
"strings"
"testing"
"time"
@@ -83,7 +82,12 @@
ctx, shutdown := test.InitForTest()
defer shutdown()
- proxySpec := rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}}
+ proxySpec := rpc.ListenSpec{
+ Addrs: rpc.ListenAddrs{{
+ Protocol: "tcp",
+ Address: "127.0.0.1:0",
+ }},
+ }
proxyShutdown, proxyEndpoint, err := generic.NewProxy(ctx, proxySpec, security.AllowEveryone())
if err != nil {
t.Fatalf("Failed to start proxy: %v", err)
@@ -195,13 +199,10 @@
}
vomRPC := hex.EncodeToString(buf.Bytes())
- msg, err := json.Marshal(app.Message{
+ msg := app.Message{
Id: 1,
Data: vomRPC,
Type: app.VeyronRequestMessage,
- })
- if err != nil {
- t.Fatalf("Failed to marshall app message to json: %v", err)
}
createInstanceMessage := CreateInstanceMessage{
@@ -212,7 +213,7 @@
}
_, err = browspr.HandleCreateInstanceRpc(vdl.ValueOf(createInstanceMessage))
- err = browspr.HandleMessage(msgInstanceId, msgOrigin, string(msg))
+ err = browspr.HandleMessage(msgInstanceId, msgOrigin, msg)
if err != nil {
t.Fatalf("Error while handling message: %v", err)
}
@@ -227,7 +228,7 @@
}
var outMsg app.Message
- if err := lib.VomDecode(receivedMsg, &outMsg); err != nil {
+ if err := lib.HexVomDecode(receivedMsg, &outMsg); err != nil {
t.Fatalf("Failed to unmarshall outgoing message: %v", err)
}
if outMsg.Id != int32(1) {
@@ -238,7 +239,7 @@
}
var responseMsg lib.Response
- if err := lib.VomDecode(outMsg.Data, &responseMsg); err != nil {
+ if err := lib.HexVomDecode(outMsg.Data, &responseMsg); err != nil {
t.Fatalf("Failed to unmarshall outgoing response: %v", err)
}
if responseMsg.Type != lib.ResponseFinal {
@@ -250,7 +251,7 @@
t.Errorf("Got unexpected response message body of type %T, expected type string", responseMsg.Message)
}
var result app.RpcResponse
- if err := lib.VomDecode(outArg, &result); err != nil {
+ if err := lib.HexVomDecode(outArg, &result); err != nil {
t.Errorf("Failed to vom decode args from %v: %v", outArg, err)
}
if got, want := result.OutArgs[0], vdl.StringValue("[InputValue]"); !vdl.EqualValue(got, want) {
diff --git a/services/wspr/internal/browspr/pipe.go b/services/wspr/internal/browspr/pipe.go
index 138e3ef..34280b4 100644
--- a/services/wspr/internal/browspr/pipe.go
+++ b/services/wspr/internal/browspr/pipe.go
@@ -5,9 +5,6 @@
package browspr
import (
- "encoding/json"
- "fmt"
-
"v.io/x/lib/vlog"
"v.io/x/ref/services/wspr/internal/app"
"v.io/x/ref/services/wspr/internal/lib"
@@ -85,16 +82,7 @@
p.controller.Cleanup()
}
-func (p *pipe) handleMessage(jsonMsg string) error {
- var msg app.Message
- if err := json.Unmarshal([]byte(jsonMsg), &msg); err != nil {
- fullErr := fmt.Errorf("Can't unmarshall message: %s error: %v", jsonMsg, err)
- // Send the failed to unmarshal error to the client.
- errWriter := &postMessageWriter{p: p}
- errWriter.Error(fullErr)
- return fullErr
- }
-
+func (p *pipe) handleMessage(msg app.Message) error {
writer := p.createWriter(msg.Id)
p.controller.HandleIncomingMessage(msg, writer)
return nil
diff --git a/services/wspr/internal/lib/vom.go b/services/wspr/internal/lib/hex_vom.go
similarity index 89%
rename from services/wspr/internal/lib/vom.go
rename to services/wspr/internal/lib/hex_vom.go
index 3864c4e..ded745dd 100644
--- a/services/wspr/internal/lib/vom.go
+++ b/services/wspr/internal/lib/hex_vom.go
@@ -12,7 +12,7 @@
"v.io/v23/vom"
)
-func VomEncode(v interface{}) (string, error) {
+func HexVomEncode(v interface{}) (string, error) {
var buf bytes.Buffer
encoder := vom.NewEncoder(&buf)
if err := encoder.Encode(v); err != nil {
@@ -21,15 +21,15 @@
return hex.EncodeToString(buf.Bytes()), nil
}
-func VomEncodeOrDie(v interface{}) string {
- s, err := VomEncode(v)
+func HexVomEncodeOrDie(v interface{}) string {
+ s, err := HexVomEncode(v)
if err != nil {
panic(err)
}
return s
}
-func VomDecode(data string, v interface{}) error {
+func HexVomDecode(data string, v interface{}) error {
binbytes, err := hex.DecodeString(data)
if err != nil {
return fmt.Errorf("Error decoding hex string %q: %v", data, err)
diff --git a/services/wspr/internal/rpc/server/dispatcher.go b/services/wspr/internal/rpc/server/dispatcher.go
index 6d8e2cc..fa76d75 100644
--- a/services/wspr/internal/rpc/server/dispatcher.go
+++ b/services/wspr/internal/rpc/server/dispatcher.go
@@ -5,8 +5,6 @@
package server
import (
- "bytes"
- "encoding/json"
"sync"
"v.io/v23/rpc"
@@ -30,22 +28,6 @@
createAuthorizer(handle int32, hasAuthorizer bool) (security.Authorizer, error)
}
-type lookupIntermediateReply struct {
- Handle int32
- HasAuthorizer bool
- HasGlobber bool
- Signature string
- Err *verror.E
-}
-
-type lookupReply struct {
- Handle int32
- HasAuthorizer bool
- HasGlobber bool
- Signature []signature.Interface
- Err *verror.E
-}
-
type dispatcherRequest struct {
ServerId uint32 `json:"serverId"`
Suffix string `json:"suffix"`
@@ -58,7 +40,7 @@
flowFactory flowFactory
invokerFactory invokerFactory
authFactory authFactory
- outstandingLookups map[int32]chan lookupReply
+ outstandingLookups map[int32]chan LookupReply
closed bool
}
@@ -71,7 +53,7 @@
flowFactory: flowFactory,
invokerFactory: invokerFactory,
authFactory: authFactory,
- outstandingLookups: make(map[int32]chan lookupReply),
+ outstandingLookups: make(map[int32]chan LookupReply),
}
}
@@ -82,7 +64,7 @@
for _, ch := range d.outstandingLookups {
verr := NewErrServerStopped(nil).(verror.E)
- ch <- lookupReply{Err: &verr}
+ ch <- LookupReply{Err: &verr}
}
}
@@ -95,7 +77,7 @@
return nil, nil, NewErrServerStopped(nil)
}
flow := d.flowFactory.createFlow()
- ch := make(chan lookupReply, 1)
+ ch := make(chan LookupReply, 1)
d.outstandingLookups[flow.ID] = ch
d.mu.Unlock()
@@ -105,7 +87,7 @@
}
if err := flow.Writer.Send(lib.ResponseDispatcherLookup, message); err != nil {
verr := verror.Convert(verror.ErrInternal, nil, err).(verror.E)
- ch <- lookupReply{Err: &verr}
+ ch <- LookupReply{Err: &verr}
}
reply := <-ch
@@ -145,27 +127,14 @@
return
}
- var intermediateReply lookupIntermediateReply
- decoder := json.NewDecoder(bytes.NewBufferString(data))
- if err := decoder.Decode(&intermediateReply); err != nil {
- err2 := verror.Convert(verror.ErrInternal, nil, err).(verror.E)
- intermediateReply = lookupIntermediateReply{Err: &err2}
+ var lookupReply LookupReply
+ if err := lib.HexVomDecode(data, &lookupReply); err != nil {
+ err2 := verror.Convert(verror.ErrInternal, nil, err)
+ lookupReply = LookupReply{Err: err2}
vlog.Errorf("unmarshaling invoke request failed: %v, %s", err, data)
}
- reply := lookupReply{
- Handle: intermediateReply.Handle,
- HasAuthorizer: intermediateReply.HasAuthorizer,
- HasGlobber: intermediateReply.HasGlobber,
- Err: intermediateReply.Err,
- }
- if reply.Err == nil && intermediateReply.Signature != "" {
- if err := lib.VomDecode(intermediateReply.Signature, &reply.Signature); err != nil {
- err2 := verror.Convert(verror.ErrInternal, nil, err).(verror.E)
- reply.Err = &err2
- }
- }
- ch <- reply
+ ch <- lookupReply
}
// StopServing implements dispatcher StopServing.
diff --git a/services/wspr/internal/rpc/server/dispatcher_test.go b/services/wspr/internal/rpc/server/dispatcher_test.go
index b869c6a..43039ae 100644
--- a/services/wspr/internal/rpc/server/dispatcher_test.go
+++ b/services/wspr/internal/rpc/server/dispatcher_test.go
@@ -14,6 +14,7 @@
"v.io/v23/security"
"v.io/v23/vdl"
"v.io/v23/vdlroot/signature"
+ "v.io/v23/verror"
"v.io/x/ref/services/wspr/internal/lib"
"v.io/x/ref/services/wspr/internal/lib/testwriter"
)
@@ -88,8 +89,12 @@
t.Errorf("failed to get dispatch request %v", err)
t.Fail()
}
- jsonResponse := fmt.Sprintf(`{"handle":1,"hasAuthorizer":false,"signature":"%s"}`, lib.VomEncodeOrDie(expectedSig))
- d.handleLookupResponse(0, jsonResponse)
+ reply := LookupReply{
+ Handle: 1,
+ HasAuthorizer: false,
+ Signature: expectedSig,
+ }
+ d.handleLookupResponse(0, lib.HexVomEncodeOrDie(reply))
}()
invoker, auth, err := d.Lookup("a/b")
@@ -133,8 +138,12 @@
t.Errorf("failed to get dispatch request %v", err)
t.Fail()
}
- jsonResponse := fmt.Sprintf(`{"handle":1,"hasAuthorizer":true,"signature":"%s"}`, lib.VomEncodeOrDie(expectedSig))
- d.handleLookupResponse(0, jsonResponse)
+ reply := LookupReply{
+ Handle: 1,
+ HasAuthorizer: true,
+ Signature: expectedSig,
+ }
+ d.handleLookupResponse(0, lib.HexVomEncodeOrDie(reply))
}()
invoker, auth, err := d.Lookup("a/b")
@@ -175,8 +184,10 @@
t.Errorf("failed to get dispatch request %v", err)
t.Fail()
}
- jsonResponse := `{"err":{"id":"v23/verror.Exists","msg":"bad stuff"}}`
- d.handleLookupResponse(0, jsonResponse)
+ reply := LookupReply{
+ Err: verror.New(verror.ErrNoExist, nil),
+ }
+ d.handleLookupResponse(0, lib.HexVomEncodeOrDie(reply))
}()
_, _, err := d.Lookup("a/b")
diff --git a/services/wspr/internal/rpc/server/server.go b/services/wspr/internal/rpc/server/server.go
index 9ce5ac9..f056c91 100644
--- a/services/wspr/internal/rpc/server/server.go
+++ b/services/wspr/internal/rpc/server/server.go
@@ -7,7 +7,6 @@
package server
import (
- "encoding/json"
"fmt"
"sync"
"time"
@@ -54,10 +53,6 @@
Context() *context.T
}
-type authReply struct {
- Err *verror.E
-}
-
// AuthRequest is a request for a javascript authorizer to run
// This is exported to make the app test easier.
type AuthRequest struct {
@@ -179,7 +174,7 @@
Args: vdlValArgs,
Call: rpcCall,
}
- vomMessage, err := lib.VomEncode(message)
+ vomMessage, err := lib.HexVomEncode(message)
if err != nil {
return errHandler(err)
}
@@ -288,7 +283,7 @@
Args: []*vdl.Value{vdl.ValueOf(pattern)},
Call: rpcCall,
}
- vomMessage, err := lib.VomEncode(message)
+ vomMessage, err := lib.HexVomEncode(message)
if err != nil {
return errHandler(err)
}
@@ -325,7 +320,7 @@
item = principal.ConvertBlessingsToHandle(blessings, blessingsCache.GetOrAddBlessingsHandle(blessings))
}
- vomItem, err := lib.VomEncode(item)
+ vomItem, err := lib.HexVomEncode(item)
if err != nil {
w.Error(verror.Convert(verror.ErrInternal, nil, err))
return
@@ -563,7 +558,7 @@
}
vlog.VI(0).Infof("Sending out auth request for %v, %v", flow.ID, message)
- vomMessage, err := lib.VomEncode(message)
+ vomMessage, err := lib.HexVomEncode(message)
if err != nil {
replyChan <- verror.Convert(verror.ErrInternal, nil, err)
} else if err := flow.Writer.Send(lib.ResponseAuthRequest, vomMessage); err != nil {
@@ -653,7 +648,7 @@
// Decode the result and send it through the channel
var reply lib.ServerRpcReply
- if err := lib.VomDecode(data, &reply); err != nil {
+ if err := lib.HexVomDecode(data, &reply); err != nil {
reply.Err = err
}
@@ -694,10 +689,10 @@
return
}
// Decode the result and send it through the channel
- var reply authReply
- if decoderErr := json.Unmarshal([]byte(data), &reply); decoderErr != nil {
- err := verror.Convert(verror.ErrInternal, nil, decoderErr).(verror.E)
- reply = authReply{Err: &err}
+ var reply AuthReply
+ if err := lib.HexVomDecode(data, &reply); err != nil {
+ err = verror.Convert(verror.ErrInternal, nil, err)
+ reply = AuthReply{Err: err}
}
vlog.VI(0).Infof("response received from JavaScript server for "+
@@ -725,7 +720,7 @@
}
var reply CaveatValidationResponse
- if err := lib.VomDecode(data, &reply); err != nil {
+ if err := lib.HexVomDecode(data, &reply); err != nil {
vlog.Errorf("failed to decode validation response %q: error %v", data, err)
ch <- []error{}
return
diff --git a/services/wspr/internal/rpc/server/server.vdl b/services/wspr/internal/rpc/server/server.vdl
index f069c39..790960c 100644
--- a/services/wspr/internal/rpc/server/server.vdl
+++ b/services/wspr/internal/rpc/server/server.vdl
@@ -7,6 +7,7 @@
import (
"time"
+ "signature"
"v.io/v23/security"
"v.io/v23/vtrace"
"v.io/x/ref/services/wspr/internal/principal"
@@ -60,3 +61,17 @@
Args []any
Call ServerRpcRequestCall
}
+
+// A reply from javascript to a lookup request.
+type LookupReply struct {
+ Handle int32
+ HasAuthorizer bool
+ HasGlobber bool
+ Signature []signature.Interface
+ Err error
+}
+
+// A reply from javascript to an auth request.
+type AuthReply struct {
+ Err error
+}
diff --git a/services/wspr/internal/rpc/server/server.vdl.go b/services/wspr/internal/rpc/server/server.vdl.go
index 4956bca..6a18704 100644
--- a/services/wspr/internal/rpc/server/server.vdl.go
+++ b/services/wspr/internal/rpc/server/server.vdl.go
@@ -16,6 +16,7 @@
// VDL user imports
"v.io/v23/security"
+ "v.io/v23/vdlroot/signature"
"v.io/v23/vdlroot/time"
"v.io/v23/vtrace"
"v.io/x/ref/services/wspr/internal/principal"
@@ -94,6 +95,30 @@
}) {
}
+// A reply from javascript to a lookup request.
+type LookupReply struct {
+ Handle int32
+ HasAuthorizer bool
+ HasGlobber bool
+ Signature []signature.Interface
+ Err error
+}
+
+func (LookupReply) __VDLReflect(struct {
+ Name string `vdl:"v.io/x/ref/services/wspr/internal/rpc/server.LookupReply"`
+}) {
+}
+
+// A reply from javascript to an auth request.
+type AuthReply struct {
+ Err error
+}
+
+func (AuthReply) __VDLReflect(struct {
+ Name string `vdl:"v.io/x/ref/services/wspr/internal/rpc/server.AuthReply"`
+}) {
+}
+
func init() {
vdl.Register((*Context)(nil))
vdl.Register((*SecurityCall)(nil))
@@ -101,6 +126,8 @@
vdl.Register((*CaveatValidationResponse)(nil))
vdl.Register((*ServerRpcRequestCall)(nil))
vdl.Register((*ServerRpcRequest)(nil))
+ vdl.Register((*LookupReply)(nil))
+ vdl.Register((*AuthReply)(nil))
}
var (
diff --git a/services/wspr/wsprd/doc.go b/services/wspr/wsprd/doc.go
new file mode 100644
index 0000000..e0c33d7
--- /dev/null
+++ b/services/wspr/wsprd/doc.go
@@ -0,0 +1,69 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+// +build wspr
+
+/*
+Command wsprd runs the wspr web socket proxy daemon.
+
+Usage:
+ wsprd [flags]
+
+The wsprd flags are:
+ -identd=
+ Name of identd server.
+ -port=8124
+ Port to listen on.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.permissions.file=map[]
+ specify a perms file as <name>:<permsfile>
+ -v23.permissions.literal=
+ explicitly specify the runtime perms as a JSON-encoded access.Permissions.
+ Overrides all --v23.permissions.file flags.
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/services/wspr/wsprd/main.go b/services/wspr/wsprd/main.go
index cde3f9f..dbc135f 100644
--- a/services/wspr/wsprd/main.go
+++ b/services/wspr/wsprd/main.go
@@ -6,34 +6,57 @@
//
// We restrict wsprd to a special build-tag in order to enable
// security.OverrideCaveatValidation, which isn't generally available.
+//
+// Manually run the following to generate the doc.go file. This isn't a
+// go:generate comment, since generate also needs to be run with -tags=wspr,
+// which is troublesome for presubmit tests.
+//
+// cd $V23_ROOT/release/go/src && go run v.io/x/lib/cmdline/testdata/gendoc.go -tags=wspr v.io/x/ref/services/wspr/wsprd -help
-// Daemon wsprd implements the wspr web socket proxy as a stand-alone server.
package main
import (
- "flag"
"fmt"
"net"
"v.io/v23"
+ "v.io/v23/context"
+ "v.io/x/lib/cmdline"
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
// TODO(cnicolaou,benj): figure out how to support roaming as a chrome plugin
_ "v.io/x/ref/runtime/factories/roaming"
"v.io/x/ref/services/wspr/wsprlib"
)
-func main() {
+var (
+ port int
+ identd string
+)
+
+func init() {
wsprlib.OverrideCaveatValidation()
- port := flag.Int("port", 8124, "Port to listen on.")
- identd := flag.String("identd", "", "name of identd server.")
+ cmdWsprD.Flags.IntVar(&port, "port", 8124, "Port to listen on.")
+ cmdWsprD.Flags.StringVar(&identd, "identd", "", "Name of identd server.")
+}
- flag.Parse()
+func main() {
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdWsprD)
+}
- ctx, shutdown := v23.Init()
- defer shutdown()
+var cmdWsprD = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runWsprD),
+ Name: "wsprd",
+ Short: "Runs the wspr web socket proxy daemon",
+ Long: `
+Command wsprd runs the wspr web socket proxy daemon.
+`,
+}
+func runWsprD(ctx *context.T, env *cmdline.Env, args []string) error {
listenSpec := v23.GetListenSpec(ctx)
- proxy := wsprlib.NewWSPR(ctx, *port, &listenSpec, *identd, nil)
+ proxy := wsprlib.NewWSPR(ctx, port, &listenSpec, identd, nil)
defer proxy.Shutdown()
addr := proxy.Listen()
@@ -44,4 +67,5 @@
nhost, nport, _ := net.SplitHostPort(addr.String())
fmt.Printf("Listening on host: %s port: %s\n", nhost, nport)
<-signals.ShutdownOnSignals(ctx)
+ return nil
}
diff --git a/test/hello/helloclient/doc.go b/test/hello/helloclient/doc.go
new file mode 100644
index 0000000..b5467e0
--- /dev/null
+++ b/test/hello/helloclient/doc.go
@@ -0,0 +1,60 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command helloclient is a simple client mainly used in regression tests.
+
+Usage:
+ helloclient [flags]
+
+The helloclient flags are:
+ -name=
+ Name of the hello server.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/test/hello/helloclient/helloclient.go b/test/hello/helloclient/helloclient.go
index a50ad5d..c5c931a 100644
--- a/test/hello/helloclient/helloclient.go
+++ b/test/hello/helloclient/helloclient.go
@@ -2,37 +2,53 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Command helloclient is the simplest possible client. It is mainly used in simple
-// regression tests.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
+ "errors"
"fmt"
"time"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/verror"
+ "v.io/x/lib/cmdline"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/generic"
)
-var name *string = flag.String("name", "", "Name of the hello server")
+var name string
func main() {
- ctx, shutdown := v23.Init()
- defer shutdown()
+ cmdHelloClient.Flags.StringVar(&name, "name", "", "Name of the hello server.")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdHelloClient)
+}
+var cmdHelloClient = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runHelloClient),
+ Name: "helloclient",
+ Short: "Simple client mainly used in regression tests.",
+ Long: `
+Command helloclient is a simple client mainly used in regression tests.
+`,
+}
+
+func runHelloClient(ctx *context.T, env *cmdline.Env, args []string) error {
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
var result string
- err := v23.GetClient(ctx).Call(ctx, *name, "Hello", nil, []interface{}{&result})
+ err := v23.GetClient(ctx).Call(ctx, name, "Hello", nil, []interface{}{&result})
if err != nil {
- panic(verror.DebugString(err))
+ return errors.New(verror.DebugString(err))
}
- if result != "hello" {
- panic(fmt.Sprintf("Unexpected result. Wanted %q, got %q", "hello", result))
+ if got, want := result, "hello"; got != want {
+ return fmt.Errorf("Unexpected result, got %q, want %q", got, want)
}
+ return nil
}
diff --git a/test/hello/helloserver/doc.go b/test/hello/helloserver/doc.go
new file mode 100644
index 0000000..4029e67
--- /dev/null
+++ b/test/hello/helloserver/doc.go
@@ -0,0 +1,60 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+Command helloserver is a simple server mainly used in regression tests.
+
+Usage:
+ helloserver [flags]
+
+The helloserver flags are:
+ -name=
+ Name to publish under.
+
+The global flags are:
+ -alsologtostderr=true
+ log to standard error as well as files
+ -log_backtrace_at=:0
+ when logging hits line file:N, emit a stack trace
+ -log_dir=
+ if non-empty, write log files to this directory
+ -logtostderr=false
+ log to standard error instead of files
+ -max_stack_buf_size=4292608
+ max size in bytes of the buffer to use for logging stack traces
+ -stderrthreshold=2
+ logs at or above this threshold go to stderr
+ -v=0
+ log level for V logs
+ -v23.credentials=
+ directory to use for storing security credentials
+ -v23.i18n-catalogue=
+ 18n catalogue files to load, comma separated
+ -v23.metadata=<just specify -v23.metadata to activate>
+ Displays metadata for the program and exits.
+ -v23.namespace.root=[/(dev.v.io/role/vprod/service/mounttabled)@ns.dev.v.io:8101]
+ local namespace root; can be repeated to provided multiple roots
+ -v23.proxy=
+ object name of proxy service to use to export services across network
+ boundaries
+ -v23.tcp.address=
+ address to listen on
+ -v23.tcp.protocol=wsh
+ protocol to listen with
+ -v23.vtrace.cache-size=1024
+ The number of vtrace traces to store in memory.
+ -v23.vtrace.collect-regexp=
+ Spans and annotations that match this regular expression will trigger trace
+ collection.
+ -v23.vtrace.dump-on-shutdown=true
+ If true, dump all stored traces on runtime shutdown.
+ -v23.vtrace.sample-rate=0
+ Rate (from 0.0 to 1.0) to sample vtrace traces.
+ -vmodule=
+ comma-separated list of pattern=N settings for file-filtered logging
+*/
+package main
diff --git a/test/hello/helloserver/helloserver.go b/test/hello/helloserver/helloserver.go
index 6ca4393..9acde0d 100644
--- a/test/hello/helloserver/helloserver.go
+++ b/test/hello/helloserver/helloserver.go
@@ -2,24 +2,40 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Daemon helloserver is the simplest possible server. It is mainly
-// used in simple regression tests.
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
package main
import (
- "flag"
"fmt"
- "os"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/rpc"
"v.io/v23/security"
+ "v.io/x/lib/cmdline"
"v.io/x/ref/lib/signals"
+ "v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/generic"
)
-var name *string = flag.String("name", "", "Name to publish under")
+var name string
+
+func main() {
+ cmdHelloServer.Flags.StringVar(&name, "name", "", "Name to publish under.")
+ cmdline.HideGlobalFlagsExcept()
+ cmdline.Main(cmdHelloServer)
+}
+
+var cmdHelloServer = &cmdline.Command{
+ Runner: v23cmd.RunnerFunc(runHelloServer),
+ Name: "helloserver",
+ Short: "Simple server mainly used in regression tests.",
+ Long: `
+Command helloserver is a simple server mainly used in regression tests.
+`,
+}
type helloServer struct{}
@@ -27,10 +43,7 @@
return "hello", nil
}
-func run() error {
- ctx, shutdown := v23.Init()
- defer shutdown()
-
+func runHelloServer(ctx *context.T, env *cmdline.Env, args []string) error {
server, err := v23.NewServer(ctx)
if err != nil {
return fmt.Errorf("NewServer: %v", err)
@@ -44,15 +57,9 @@
} else {
fmt.Println("SERVER_NAME=proxy")
}
- if err := server.Serve(*name, &helloServer{}, security.AllowEveryone()); err != nil {
+ if err := server.Serve(name, &helloServer{}, security.AllowEveryone()); err != nil {
return fmt.Errorf("Serve: %v", err)
}
<-signals.ShutdownOnSignals(ctx)
return nil
}
-
-func main() {
- if err := run(); err != nil {
- os.Exit(1)
- }
-}