blob: b389a1393888b6c8dbb3eb2b1163f2b2b28dc74f [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
Robin Thellend8fea01c2014-12-11 13:48:10 -080033const defaultNamespaceRoot = "/ns.dev.v.io:8101"
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -070034
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 Nicolaou96fa9172014-12-16 12:57:18 -080057 for _, t := range nsr.roots {
58 if v == t {
59 return nil
60 }
61 }
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070062 nsr.roots = append(nsr.roots, v)
63 return nil
64}
65
Cosmos Nicolaou78237372014-11-04 18:19:09 -080066type aclFlagVar struct {
67 isSet bool
68 files map[string]string
69}
70
71func (aclf *aclFlagVar) String() string {
72 return fmt.Sprintf("%v", aclf.files)
73}
74
75func (aclf *aclFlagVar) Set(v string) error {
76 if !aclf.isSet {
77 // override the default value
78 aclf.isSet = true
79 aclf.files = make(map[string]string)
80 }
81 parts := strings.SplitN(v, ":", 2)
82 if len(parts) != 2 {
83 return fmt.Errorf("%q is not in 'name:file' format", v)
84 }
85 name, file := parts[0], parts[1]
86 aclf.files[name] = file
87 return nil
88}
89
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -070090// RuntimeFlags contains the values of the Runtime flag group.
91type RuntimeFlags struct {
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070092 // NamespaceRoots may be initialized by NAMESPACE_ROOT* enivornment
93 // variables as well as --veyron.namespace.root. The command line
94 // will override the environment.
95 NamespaceRoots []string // TODO(cnicolaou): provide flag.Value impl
96
Mike Burrows63214cb2014-12-22 14:46:42 -080097 // Credentials may be initialized by the VEYRON_CREDENTIALS
Cosmos Nicolaoud811b072014-10-28 17:46:27 -070098 // environment variable. The command line will override the environment.
99 Credentials string // TODO(cnicolaou): provide flag.Value impl
100
Mike Burrows63214cb2014-12-22 14:46:42 -0800101 // I18nCatalogue may be initialized by the VANADIUM_I18N_CATALOGUE
102 // environment variable. The command line will override the
103 // environment.
104 I18nCatalogue string
105
Matt Rosencrantz3e76f282014-11-10 09:38:57 -0800106 // Vtrace flags control various aspects of Vtrace.
107 Vtrace VtraceFlags
108
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700109 namespaceRootsFlag namespaceRootFlagVar
110}
111
Matt Rosencrantz3e76f282014-11-10 09:38:57 -0800112type VtraceFlags struct {
113 // VtraceSampleRate is the rate (from 0.0 - 1.0) at which
114 // vtrace traces started by this process are sampled for collection.
115 SampleRate float64
116
117 // VtraceDumpOnShutdown tells the runtime to dump all stored traces
118 // to Stderr at shutdown if true.
119 DumpOnShutdown bool
120
121 // VtraceCacheSize the number of traces to cache in memory.
122 CacheSize int
123}
124
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800125// ACLFlags contains the values of the ACLFlags flag group.
126type ACLFlags struct {
127 flag aclFlagVar
128}
129
130// ACLFile returns the file which is presumed to contain ACL information
131// associated with the supplied name parameter.
132func (af ACLFlags) ACLFile(name string) string {
133 return af.flag.files[name]
134}
135
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800136// ListenAddrs is the set of listen addresses captured from the command line.
137// ListenAddrs mirrors ipc.ListenAddrs.
138type ListenAddrs []struct {
139 Protocol, Address string
140}
141
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700142// ListenFlags contains the values of the Listen flag group.
143type ListenFlags struct {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800144 Addrs ListenAddrs
145 ListenProxy string
146 protocol TCPProtocolFlag
147 addresses ipHostPortFlagVar
148}
149
150type ipHostPortFlagVar struct {
151 validator IPHostPortFlag
152 flags *ListenFlags
153}
154
155// Implements flag.Value.Get
156func (ip ipHostPortFlagVar) Get() interface{} {
157 return ip.String()
158}
159
160// Implements flag.Value.Set
161func (ip *ipHostPortFlagVar) Set(s string) error {
162 if err := ip.validator.Set(s); err != nil {
163 return err
164 }
165 a := struct {
166 Protocol, Address string
167 }{
168 ip.flags.protocol.String(),
169 ip.validator.String(),
170 }
Cosmos Nicolaou96fa9172014-12-16 12:57:18 -0800171 for _, t := range ip.flags.Addrs {
172 if t.Protocol == a.Protocol && t.Address == a.Address {
173 return nil
174 }
175 }
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800176 ip.flags.Addrs = append(ip.flags.Addrs, a)
177 return nil
178}
179
180// Implements flag.Value.String
181func (ip ipHostPortFlagVar) String() string {
182 s := ""
183 for _, a := range ip.flags.Addrs {
184 s += fmt.Sprintf("(%s %s)", a.Protocol, a.Address)
185 }
186 return s
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700187}
188
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700189// createAndRegisterRuntimeFlags creates and registers the RuntimeFlags
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700190// group with the supplied flag.FlagSet.
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700191func createAndRegisterRuntimeFlags(fs *flag.FlagSet) *RuntimeFlags {
192 f := &RuntimeFlags{}
Mike Burrows63214cb2014-12-22 14:46:42 -0800193 roots, creds, i18nCatalogue := readEnv()
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700194 if len(roots) == 0 {
195 f.namespaceRootsFlag.roots = []string{defaultNamespaceRoot}
196 } else {
197 f.namespaceRootsFlag.roots = roots
198 }
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800199
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700200 fs.Var(&f.namespaceRootsFlag, "veyron.namespace.root", "local namespace root; can be repeated to provided multiple roots")
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700201 fs.StringVar(&f.Credentials, "veyron.credentials", creds, "directory to use for storing security credentials")
Mike Burrows63214cb2014-12-22 14:46:42 -0800202 fs.StringVar(&f.I18nCatalogue, "vanadium.i18n_catalogue", i18nCatalogue, "18n catalogue files to load, comma separated")
Matt Rosencrantz3e76f282014-11-10 09:38:57 -0800203
204 fs.Float64Var(&f.Vtrace.SampleRate, "veyron.vtrace.sample_rate", 0.0, "Rate (from 0.0 to 1.0) to sample vtrace traces.")
205 fs.BoolVar(&f.Vtrace.DumpOnShutdown, "veyron.vtrace.dump_on_shutdown", false, "If true, dump all stored traces on runtime shutdown.")
206 fs.IntVar(&f.Vtrace.CacheSize, "veyron.vtrace.cache_size", 1024, "The number of vtrace traces to store in memory.")
207
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700208 return f
209}
210
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800211func createAndRegisterACLFlags(fs *flag.FlagSet) *ACLFlags {
212 f := &ACLFlags{}
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800213 fs.Var(&f.flag, "veyron.acl", "specify an acl file as <name>:<aclfile>")
214 return f
215}
216
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700217// createAndRegisterListenFlags creates and registers the ListenFlags
218// group with the supplied flag.FlagSet.
219func createAndRegisterListenFlags(fs *flag.FlagSet) *ListenFlags {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800220 f := &ListenFlags{
221 protocol: TCPProtocolFlag{"tcp"},
222 addresses: ipHostPortFlagVar{validator: IPHostPortFlag{Port: "0"}},
223 }
224 f.addresses.flags = f
225
226 fs.Var(&f.protocol, "veyron.tcp.protocol", "protocol to listen with")
227 fs.Var(&f.addresses, "veyron.tcp.address", "address to listen on")
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700228 fs.StringVar(&f.ListenProxy, "veyron.proxy", "", "object name of proxy service to use to export services across network boundaries")
229 return f
230}
231
232// CreateAndRegister creates a new set of flag groups as specified by the
233// supplied flag group parameters and registers them with the supplied
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700234// flag.Flagset.
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700235func CreateAndRegister(fs *flag.FlagSet, groups ...FlagGroup) *Flags {
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700236 if len(groups) == 0 {
237 return nil
238 }
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700239 f := &Flags{FlagSet: fs, groups: make(map[FlagGroup]interface{})}
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700240 for _, g := range groups {
241 switch g {
242 case Runtime:
243 f.groups[Runtime] = createAndRegisterRuntimeFlags(fs)
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700244 case Listen:
245 f.groups[Listen] = createAndRegisterListenFlags(fs)
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800246 case ACL:
247 f.groups[ACL] = createAndRegisterACLFlags(fs)
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700248 }
249 }
250 return f
251}
252
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700253// RuntimeFlags returns the Runtime flag subset stored in its Flags
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700254// instance.
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700255func (f *Flags) RuntimeFlags() RuntimeFlags {
256 if p := f.groups[Runtime]; p == nil {
257 return RuntimeFlags{}
258 }
259 from := f.groups[Runtime].(*RuntimeFlags)
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700260 to := *from
261 to.NamespaceRoots = make([]string, len(from.NamespaceRoots))
262 copy(to.NamespaceRoots, from.NamespaceRoots)
263 return to
264}
265
266// ListenFlags returns a copy of the Listen flag group stored in Flags.
267// This copy will contain default values if the Listen flag group
268// was not specified when CreateAndRegister was called. The HasGroup
269// method can be used for testing to see if any given group was configured.
270func (f *Flags) ListenFlags() ListenFlags {
271 if p := f.groups[Listen]; p != nil {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800272 lf := p.(*ListenFlags)
273 n := *lf
274 if len(lf.Addrs) == 0 {
275 n.Addrs = ListenAddrs{{n.protocol.String(),
276 n.addresses.validator.String()}}
277 return n
278 }
279 n.Addrs = make(ListenAddrs, len(lf.Addrs))
280 copy(n.Addrs, lf.Addrs)
281 return n
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700282 }
283 return ListenFlags{}
284}
285
Cosmos Nicolaou78237372014-11-04 18:19:09 -0800286// ACLFlags returns a copy of the ACL flag group stored in Flags.
287// This copy will contain default values if the ACL flag group
288// was not specified when CreateAndRegister was called. The HasGroup
289// method can be used for testing to see if any given group was configured.
290func (f *Flags) ACLFlags() ACLFlags {
291 if p := f.groups[ACL]; p != nil {
292 return *(p.(*ACLFlags))
293 }
294 return ACLFlags{}
295}
296
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700297// HasGroup returns group if the supplied FlagGroup has been created
298// for these Flags.
299func (f *Flags) HasGroup(group FlagGroup) bool {
300 _, present := f.groups[group]
301 return present
302}
303
304// Args returns the unparsed args, as per flag.Args.
305func (f *Flags) Args() []string {
306 return f.FlagSet.Args()
307}
308
Mike Burrows63214cb2014-12-22 14:46:42 -0800309// readEnv reads the legacy NAMESPACE_ROOT?, VEYRON_CREDENTIALS,
310// and VANADIUM_I18N_CATALOGUE env vars.
311func readEnv() ([]string, string, string) {
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700312 roots := []string{}
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700313 for _, ev := range os.Environ() {
314 p := strings.SplitN(ev, "=", 2)
315 if len(p) != 2 {
316 continue
317 }
318 k, v := p[0], p[1]
Asim Shankar95910b62014-10-31 22:02:29 -0700319 if strings.HasPrefix(k, consts.NamespaceRootPrefix) && len(v) > 0 {
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700320 roots = append(roots, v)
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700321 }
322 }
Mike Burrows63214cb2014-12-22 14:46:42 -0800323 return roots, os.Getenv(consts.VeyronCredentials), os.Getenv(consts.I18nCatalogueFiles)
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700324}
325
Cosmos Nicolaoua0251092014-11-09 22:04:37 -0800326// Parse parses the supplied args, as per flag.Parse.
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700327func (f *Flags) Parse(args []string) error {
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700328 // TODO(cnicolaou): implement a single env var 'VANADIUM_OPTS'
329 // that can be used to specify any command line.
330 if err := f.FlagSet.Parse(args); err != nil {
331 return err
332 }
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700333
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700334 hasrt := f.groups[Runtime] != nil
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700335 if hasrt {
336 runtime := f.groups[Runtime].(*RuntimeFlags)
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700337 if runtime.namespaceRootsFlag.isSet {
338 // command line overrides the environment.
Cosmos Nicolaoue5b41502014-10-29 22:55:09 -0700339 runtime.NamespaceRoots = runtime.namespaceRootsFlag.roots
Cosmos Nicolaoue497a4b2014-10-31 09:50:01 -0700340 } else {
341 // we have a default value for the command line, which
342 // is only used if the environment variables have not been
343 // supplied.
344 if len(runtime.NamespaceRoots) == 0 {
345 runtime.NamespaceRoots = runtime.namespaceRootsFlag.roots
346 }
Cosmos Nicolaou98960042014-10-31 00:05:51 -0700347 }
Cosmos Nicolaoud811b072014-10-28 17:46:27 -0700348 }
349 return nil
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700350}