veyron/lib/flags: add --veyron.acl flag
Change-Id: Ib58a9995d0450f33f6c0d5fac561c72edadd8233
diff --git a/lib/flags/flags.go b/lib/flags/flags.go
index b1313e1..b8a1473 100644
--- a/lib/flags/flags.go
+++ b/lib/flags/flags.go
@@ -24,9 +24,13 @@
// --veyron.tcp.address
// --veyron.proxy
Listen
+ // --veyron.acl (which may be repeated to supply multiple values)
+ ACL
)
const defaultNamespaceRoot = "/proxy.envyor.com:8101"
+const defaultACLName = "veyron"
+const defaultACLFile = "acl.json"
// Flags represents the set of flag groups created by a call to
// CreateAndRegister.
@@ -46,7 +50,7 @@
func (nsr *namespaceRootFlagVar) Set(v string) error {
if !nsr.isSet {
- // override the default value and
+ // override the default value
nsr.isSet = true
nsr.roots = []string{}
}
@@ -54,6 +58,30 @@
return nil
}
+type aclFlagVar struct {
+ isSet bool
+ files map[string]string
+}
+
+func (aclf *aclFlagVar) String() string {
+ return fmt.Sprintf("%v", aclf.files)
+}
+
+func (aclf *aclFlagVar) Set(v string) error {
+ if !aclf.isSet {
+ // override the default value
+ aclf.isSet = true
+ aclf.files = make(map[string]string)
+ }
+ parts := strings.SplitN(v, ":", 2)
+ if len(parts) != 2 {
+ return fmt.Errorf("%q is not in 'name:file' format", v)
+ }
+ name, file := parts[0], parts[1]
+ aclf.files[name] = file
+ return nil
+}
+
// RuntimeFlags contains the values of the Runtime flag group.
type RuntimeFlags struct {
// NamespaceRoots may be initialized by NAMESPACE_ROOT* enivornment
@@ -68,6 +96,17 @@
namespaceRootsFlag namespaceRootFlagVar
}
+// ACLFlags contains the values of the ACLFlags flag group.
+type ACLFlags struct {
+ flag aclFlagVar
+}
+
+// ACLFile returns the file which is presumed to contain ACL information
+// associated with the supplied name parameter.
+func (af ACLFlags) ACLFile(name string) string {
+ return af.flag.files[name]
+}
+
// ListenFlags contains the values of the Listen flag group.
type ListenFlags struct {
ListenProtocol TCPProtocolFlag
@@ -85,11 +124,19 @@
} else {
f.namespaceRootsFlag.roots = roots
}
+
fs.Var(&f.namespaceRootsFlag, "veyron.namespace.root", "local namespace root; can be repeated to provided multiple roots")
fs.StringVar(&f.Credentials, "veyron.credentials", creds, "directory to use for storing security credentials")
return f
}
+func createAndRegisterACLFlags(fs *flag.FlagSet) *ACLFlags {
+ f := &ACLFlags{}
+ f.flag.files = map[string]string{defaultACLName: defaultACLFile}
+ fs.Var(&f.flag, "veyron.acl", "specify an acl file as <name>:<aclfile>")
+ return f
+}
+
// createAndRegisterListenFlags creates and registers the ListenFlags
// group with the supplied flag.FlagSet.
func createAndRegisterListenFlags(fs *flag.FlagSet) *ListenFlags {
@@ -116,6 +163,8 @@
f.groups[Runtime] = createAndRegisterRuntimeFlags(fs)
case Listen:
f.groups[Listen] = createAndRegisterListenFlags(fs)
+ case ACL:
+ f.groups[ACL] = createAndRegisterACLFlags(fs)
}
}
return f
@@ -145,6 +194,17 @@
return ListenFlags{}
}
+// ACLFlags returns a copy of the ACL flag group stored in Flags.
+// This copy will contain default values if the ACL flag group
+// was not specified when CreateAndRegister was called. The HasGroup
+// method can be used for testing to see if any given group was configured.
+func (f *Flags) ACLFlags() ACLFlags {
+ if p := f.groups[ACL]; p != nil {
+ return *(p.(*ACLFlags))
+ }
+ return ACLFlags{}
+}
+
// HasGroup returns group if the supplied FlagGroup has been created
// for these Flags.
func (f *Flags) HasGroup(group FlagGroup) bool {
diff --git a/lib/flags/flags_test.go b/lib/flags/flags_test.go
index c802942..ee9c32a 100644
--- a/lib/flags/flags_test.go
+++ b/lib/flags/flags_test.go
@@ -14,11 +14,11 @@
func TestFlags(t *testing.T) {
fs := flag.NewFlagSet("test", flag.ContinueOnError)
if flags.CreateAndRegister(fs) != nil {
- t.Errorf("should have failed")
+ t.Fatalf("should have returned a nil value")
}
fl := flags.CreateAndRegister(fs, flags.Runtime)
if fl == nil {
- t.Fatalf("should have returned a non-nil value")
+ t.Errorf("should have failed")
}
creds := "creddir"
roots := []string{"ab:cd:ef"}
@@ -42,6 +42,26 @@
}
}
+func TestACLFlags(t *testing.T) {
+ fs := flag.NewFlagSet("test", flag.ContinueOnError)
+ fl := flags.CreateAndRegister(fs, flags.Runtime, flags.ACL)
+ args := []string{"--veyron.acl=veyron:foo.json", "--veyron.acl=bar:bar.json", "--veyron.acl=baz:bar:baz.json"}
+ fl.Parse(args)
+ aclf := fl.ACLFlags()
+ if got, want := aclf.ACLFile("veyron"), "foo.json"; got != want {
+ t.Errorf("got %t, want %t", got, want)
+ }
+ if got, want := aclf.ACLFile("bar"), "bar.json"; got != want {
+ t.Errorf("got %t, want %t", got, want)
+ }
+ if got, want := aclf.ACLFile("wombat"), ""; got != want {
+ t.Errorf("got %t, want %t", got, want)
+ }
+ if got, want := aclf.ACLFile("baz"), "bar:baz.json"; got != want {
+ t.Errorf("got %t, want %t", got, want)
+ }
+}
+
func TestFlagError(t *testing.T) {
fs := flag.NewFlagSet("test", flag.ContinueOnError)
fs.SetOutput(ioutil.Discard)
@@ -55,6 +75,15 @@
if got, want := len(fl.Args()), 1; got != want {
t.Errorf("got %d, want %d [args: %v]", got, want, fl.Args())
}
+
+ fs = flag.NewFlagSet("test", flag.ContinueOnError)
+ fs.SetOutput(ioutil.Discard)
+ fl = flags.CreateAndRegister(fs, flags.ACL)
+ args = []string{"--veyron.acl=noname"}
+ err = fl.Parse(args)
+ if err == nil {
+ t.Fatalf("expected this to fail!")
+ }
}
func TestFlagsGroups(t *testing.T) {
@@ -138,7 +167,7 @@
os.Setenv(rootEnvVar, "")
os.Setenv(rootEnvVar0, "")
- fl := flags.CreateAndRegister(flag.NewFlagSet("test", flag.ContinueOnError), flags.Runtime)
+ fl := flags.CreateAndRegister(flag.NewFlagSet("test", flag.ContinueOnError), flags.Runtime, flags.ACL)
if err := fl.Parse([]string{}); err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -146,4 +175,8 @@
if got, want := rtf.NamespaceRoots, []string{"/proxy.envyor.com:8101"}; !reflect.DeepEqual(got, want) {
t.Errorf("got %q, want %q", got, want)
}
+ aclf := fl.ACLFlags()
+ if got, want := aclf.ACLFile("veyron"), "acl.json"; got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
}