blob: 76e1baf49b6aaac57371694ec120230a55c30f9a [file] [log] [blame]
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -07001package flags
2
Cosmos Nicolaoud811b072014-10-28 17:46:27 -07003import (
4 "flag"
5 "fmt"
6 "os"
7 "strings"
Asim Shankar95910b62014-10-31 22:02:29 -07008
9 "veyron.io/veyron/veyron/lib/flags/consts"
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070010)
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -070011
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070012// FlagGroup is the type for identifying groups of related flags.
13type FlagGroup int
14
15const (
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -070016 // Runtime identifies the flags and associated environment variables
17 // used by the Vanadium process runtime. Namely:
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070018 // --veyron.namespace.root (which may be repeated to supply multiple values)
19 // --veyron.credentials
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -070020 Runtime FlagGroup = iota
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070021 // Listen identifies the flags typically required to configure
22 // ipc.ListenSpec. Namely:
23 // --veyron.tcp.protocol
24 // --veyron.tcp.address
25 // --veyron.proxy
26 Listen
Cosmos Nicolaou78237372014-11-04 18:19:09 -080027 // --veyron.acl (which may be repeated to supply multiple values)
Cosmos Nicolaouc7ddcf02014-11-05 16:26:56 -080028 // ACL files are named - i.e. --veyron.acl=<name>:<file> with the
29 // name <runtime> reserved for use by the runtime.
Cosmos Nicolaou78237372014-11-04 18:19:09 -080030 ACL
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070031)
32
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -070033const defaultNamespaceRoot = "/proxy.envyor.com:8101"
34
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070035// Flags represents the set of flag groups created by a call to
36// CreateAndRegister.
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -070037type Flags struct {
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -070038 FlagSet *flag.FlagSet
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070039 groups map[FlagGroup]interface{}
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -070040}
41
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070042type namespaceRootFlagVar struct {
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -070043 isSet bool // is true when a flag have has been explicitly set.
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070044 roots []string
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -070045}
46
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070047func (nsr *namespaceRootFlagVar) String() string {
48 return fmt.Sprintf("%v", nsr.roots)
49}
50
51func (nsr *namespaceRootFlagVar) Set(v string) error {
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -070052 if !nsr.isSet {
Cosmos Nicolaou78237372014-11-04 18:19:09 -080053 // override the default value
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -070054 nsr.isSet = true
55 nsr.roots = []string{}
56 }
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070057 nsr.roots = append(nsr.roots, v)
58 return nil
59}
60
Cosmos Nicolaou78237372014-11-04 18:19:09 -080061type aclFlagVar struct {
62 isSet bool
63 files map[string]string
64}
65
66func (aclf *aclFlagVar) String() string {
67 return fmt.Sprintf("%v", aclf.files)
68}
69
70func (aclf *aclFlagVar) Set(v string) error {
71 if !aclf.isSet {
72 // override the default value
73 aclf.isSet = true
74 aclf.files = make(map[string]string)
75 }
76 parts := strings.SplitN(v, ":", 2)
77 if len(parts) != 2 {
78 return fmt.Errorf("%q is not in 'name:file' format", v)
79 }
80 name, file := parts[0], parts[1]
81 aclf.files[name] = file
82 return nil
83}
84
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -070085// RuntimeFlags contains the values of the Runtime flag group.
86type RuntimeFlags struct {
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070087 // NamespaceRoots may be initialized by NAMESPACE_ROOT* enivornment
88 // variables as well as --veyron.namespace.root. The command line
89 // will override the environment.
90 NamespaceRoots []string // TODO(cnicolaou): provide flag.Value impl
91
92 // Credentials may be initialized by the the VEYRON_CREDENTIALS
93 // environment variable. The command line will override the environment.
94 Credentials string // TODO(cnicolaou): provide flag.Value impl
95
Matt Rosencrantz3e76f282014-11-10 09:38:57 -080096 // Vtrace flags control various aspects of Vtrace.
97 Vtrace VtraceFlags
98
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070099 namespaceRootsFlag namespaceRootFlagVar
100}
101
Matt Rosencrantz3e76f282014-11-10 09:38:57 -0800102type VtraceFlags struct {
103 // VtraceSampleRate is the rate (from 0.0 - 1.0) at which
104 // vtrace traces started by this process are sampled for collection.
105 SampleRate float64
106
107 // VtraceDumpOnShutdown tells the runtime to dump all stored traces
108 // to Stderr at shutdown if true.
109 DumpOnShutdown bool
110
111 // VtraceCacheSize the number of traces to cache in memory.
112 CacheSize int
113}
114
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800115// ACLFlags contains the values of the ACLFlags flag group.
116type ACLFlags struct {
117 flag aclFlagVar
118}
119
120// ACLFile returns the file which is presumed to contain ACL information
121// associated with the supplied name parameter.
122func (af ACLFlags) ACLFile(name string) string {
123 return af.flag.files[name]
124}
125
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700126// ListenFlags contains the values of the Listen flag group.
127type ListenFlags struct {
128 ListenProtocol TCPProtocolFlag
129 ListenAddress IPHostPortFlag
130 ListenProxy string
131}
132
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700133// createAndRegisterRuntimeFlags creates and registers the RuntimeFlags
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700134// group with the supplied flag.FlagSet.
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700135func createAndRegisterRuntimeFlags(fs *flag.FlagSet) *RuntimeFlags {
136 f := &RuntimeFlags{}
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700137 roots, creds := readEnv()
138 if len(roots) == 0 {
139 f.namespaceRootsFlag.roots = []string{defaultNamespaceRoot}
140 } else {
141 f.namespaceRootsFlag.roots = roots
142 }
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800143
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700144 fs.Var(&f.namespaceRootsFlag, "veyron.namespace.root", "local namespace root; can be repeated to provided multiple roots")
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700145 fs.StringVar(&f.Credentials, "veyron.credentials", creds, "directory to use for storing security credentials")
Matt Rosencrantz3e76f282014-11-10 09:38:57 -0800146
147 fs.Float64Var(&f.Vtrace.SampleRate, "veyron.vtrace.sample_rate", 0.0, "Rate (from 0.0 to 1.0) to sample vtrace traces.")
148 fs.BoolVar(&f.Vtrace.DumpOnShutdown, "veyron.vtrace.dump_on_shutdown", false, "If true, dump all stored traces on runtime shutdown.")
149 fs.IntVar(&f.Vtrace.CacheSize, "veyron.vtrace.cache_size", 1024, "The number of vtrace traces to store in memory.")
150
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700151 return f
152}
153
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800154func createAndRegisterACLFlags(fs *flag.FlagSet) *ACLFlags {
155 f := &ACLFlags{}
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800156 fs.Var(&f.flag, "veyron.acl", "specify an acl file as <name>:<aclfile>")
157 return f
158}
159
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700160// createAndRegisterListenFlags creates and registers the ListenFlags
161// group with the supplied flag.FlagSet.
162func createAndRegisterListenFlags(fs *flag.FlagSet) *ListenFlags {
163 f := &ListenFlags{}
164 f.ListenProtocol = TCPProtocolFlag{"tcp"}
165 f.ListenAddress = IPHostPortFlag{Port: "0"}
166 fs.Var(&f.ListenProtocol, "veyron.tcp.protocol", "protocol to listen with")
167 fs.Var(&f.ListenAddress, "veyron.tcp.address", "address to listen on")
168 fs.StringVar(&f.ListenProxy, "veyron.proxy", "", "object name of proxy service to use to export services across network boundaries")
169 return f
170}
171
172// CreateAndRegister creates a new set of flag groups as specified by the
173// supplied flag group parameters and registers them with the supplied
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700174// flag.Flagset.
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700175func CreateAndRegister(fs *flag.FlagSet, groups ...FlagGroup) *Flags {
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700176 if len(groups) == 0 {
177 return nil
178 }
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700179 f := &Flags{FlagSet: fs, groups: make(map[FlagGroup]interface{})}
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700180 for _, g := range groups {
181 switch g {
182 case Runtime:
183 f.groups[Runtime] = createAndRegisterRuntimeFlags(fs)
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700184 case Listen:
185 f.groups[Listen] = createAndRegisterListenFlags(fs)
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800186 case ACL:
187 f.groups[ACL] = createAndRegisterACLFlags(fs)
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700188 }
189 }
190 return f
191}
192
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700193// RuntimeFlags returns the Runtime flag subset stored in its Flags
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700194// instance.
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700195func (f *Flags) RuntimeFlags() RuntimeFlags {
196 if p := f.groups[Runtime]; p == nil {
197 return RuntimeFlags{}
198 }
199 from := f.groups[Runtime].(*RuntimeFlags)
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700200 to := *from
201 to.NamespaceRoots = make([]string, len(from.NamespaceRoots))
202 copy(to.NamespaceRoots, from.NamespaceRoots)
203 return to
204}
205
206// ListenFlags returns a copy of the Listen flag group stored in Flags.
207// This copy will contain default values if the Listen flag group
208// was not specified when CreateAndRegister was called. The HasGroup
209// method can be used for testing to see if any given group was configured.
210func (f *Flags) ListenFlags() ListenFlags {
211 if p := f.groups[Listen]; p != nil {
212 return *(p.(*ListenFlags))
213 }
214 return ListenFlags{}
215}
216
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800217// ACLFlags returns a copy of the ACL flag group stored in Flags.
218// This copy will contain default values if the ACL flag group
219// was not specified when CreateAndRegister was called. The HasGroup
220// method can be used for testing to see if any given group was configured.
221func (f *Flags) ACLFlags() ACLFlags {
222 if p := f.groups[ACL]; p != nil {
223 return *(p.(*ACLFlags))
224 }
225 return ACLFlags{}
226}
227
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700228// HasGroup returns group if the supplied FlagGroup has been created
229// for these Flags.
230func (f *Flags) HasGroup(group FlagGroup) bool {
231 _, present := f.groups[group]
232 return present
233}
234
235// Args returns the unparsed args, as per flag.Args.
236func (f *Flags) Args() []string {
237 return f.FlagSet.Args()
238}
239
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700240// readEnv reads the legacy NAMESPACE_ROOT? and VEYRON_CREDENTIALS env vars.
241func readEnv() ([]string, string) {
242 roots := []string{}
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700243 for _, ev := range os.Environ() {
244 p := strings.SplitN(ev, "=", 2)
245 if len(p) != 2 {
246 continue
247 }
248 k, v := p[0], p[1]
Asim Shankar95910b62014-10-31 22:02:29 -0700249 if strings.HasPrefix(k, consts.NamespaceRootPrefix) && len(v) > 0 {
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700250 roots = append(roots, v)
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700251 }
252 }
Asim Shankar95910b62014-10-31 22:02:29 -0700253 return roots, os.Getenv(consts.VeyronCredentials)
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700254}
255
Cosmos Nicolaoua0251092014-11-09 22:04:37 -0800256// Parse parses the supplied args, as per flag.Parse.
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700257func (f *Flags) Parse(args []string) error {
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700258 // TODO(cnicolaou): implement a single env var 'VANADIUM_OPTS'
259 // that can be used to specify any command line.
260 if err := f.FlagSet.Parse(args); err != nil {
261 return err
262 }
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700263
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700264 hasrt := f.groups[Runtime] != nil
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700265 if hasrt {
266 runtime := f.groups[Runtime].(*RuntimeFlags)
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700267 if runtime.namespaceRootsFlag.isSet {
268 // command line overrides the environment.
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700269 runtime.NamespaceRoots = runtime.namespaceRootsFlag.roots
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700270 } else {
271 // we have a default value for the command line, which
272 // is only used if the environment variables have not been
273 // supplied.
274 if len(runtime.NamespaceRoots) == 0 {
275 runtime.NamespaceRoots = runtime.namespaceRootsFlag.roots
276 }
Cosmos Nicolaou98960042014-10-31 00:05:51 -0700277 }
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700278 }
279 return nil
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700280}