├── .gitignore ├── main.go ├── vendor ├── github.com │ ├── grubernaut │ │ └── gdsh │ │ │ ├── dsh │ │ │ ├── structs.go │ │ │ ├── machinelist.go │ │ │ └── execute.go │ │ │ └── LICENSE.MD │ └── hashicorp │ │ ├── consul │ │ └── api │ │ │ ├── raw.go │ │ │ ├── README.md │ │ │ ├── status.go │ │ │ ├── coordinate.go │ │ │ ├── operator.go │ │ │ ├── event.go │ │ │ ├── acl.go │ │ │ ├── health.go │ │ │ ├── catalog.go │ │ │ ├── session.go │ │ │ ├── prepared_query.go │ │ │ ├── lock.go │ │ │ ├── agent.go │ │ │ └── kv.go │ │ ├── go-cleanhttp │ │ ├── doc.go │ │ ├── README.md │ │ └── cleanhttp.go │ │ └── serf │ │ └── coordinate │ │ ├── config.go │ │ ├── phantom.go │ │ ├── client.go │ │ └── coordinate.go ├── gopkg.in │ └── urfave │ │ └── cli.v2 │ │ ├── cli.go │ │ ├── GNUmakefile │ │ ├── appveyor.yml │ │ ├── LICENSE │ │ ├── funcs.go │ │ ├── args.go │ │ ├── category.go │ │ ├── flag-types.json │ │ ├── errors.go │ │ ├── context.go │ │ ├── runtests │ │ ├── command.go │ │ ├── help.go │ │ ├── generate-flag-types │ │ ├── app.go │ │ ├── cli-v1-to-v2 │ │ ├── CHANGELOG.md │ │ └── flag_generated.go └── vendor.json ├── flags.go ├── README.md └── run.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | .imi 3 | cdsh -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "gopkg.in/urfave/cli.v2" 7 | ) 8 | 9 | func main() { 10 | cli.VersionFlag = &cli.BoolFlag{ 11 | Name: "version", 12 | Usage: "print the version", 13 | Aliases: []string{"V"}, 14 | Value: false, 15 | } 16 | 17 | app := &cli.App{ 18 | Name: "cdsh", 19 | Usage: "Consul DSH", 20 | Flags: setFlags(), 21 | Action: func(c *cli.Context) error { 22 | return run(c) 23 | }, 24 | } 25 | app.Run(os.Args) 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/grubernaut/gdsh/dsh/structs.go: -------------------------------------------------------------------------------- 1 | package dsh 2 | 3 | import "container/list" 4 | 5 | //ExecOpts does things 6 | type ExecOpts struct { 7 | MachineList *list.List 8 | CommandList *list.List 9 | ShowNames bool 10 | RemoteShell string 11 | RemoteCommand string 12 | RemoteCommandOpts string 13 | ConcurrentShell bool 14 | Verbose bool 15 | } 16 | 17 | // Signal is returned from a goroutine via a channel 18 | type Signal struct { 19 | err error 20 | errOutput string 21 | } 22 | -------------------------------------------------------------------------------- /flags.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "gopkg.in/urfave/cli.v2" 4 | 5 | func setFlags() []cli.Flag { 6 | return []cli.Flag{ 7 | &cli.BoolFlag{ 8 | Name: "verbose", 9 | Value: false, 10 | Aliases: []string{"v"}, 11 | Usage: "Verbose output", 12 | }, 13 | &cli.StringFlag{ 14 | Name: "server", 15 | Value: "", 16 | Aliases: []string{"s"}, 17 | Usage: "Consul Server Address", 18 | }, 19 | &cli.StringFlag{ 20 | Name: "service", 21 | Value: "", 22 | Aliases: []string{"S"}, 23 | Usage: "Target Consul Service", 24 | }, 25 | &cli.StringFlag{ 26 | Name: "user", 27 | Value: "", 28 | Aliases: []string{"u"}, 29 | Usage: "Remote User to connect as", 30 | }, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/cli.go: -------------------------------------------------------------------------------- 1 | // Package cli provides a minimal framework for creating and organizing command line 2 | // Go applications. cli is designed to be easy to understand and write, the most simple 3 | // cli application can be written as follows: 4 | // func main() { 5 | // (&cli.App{}).Run(os.Args) 6 | // } 7 | // 8 | // Of course this application does not do much, so let's make this an actual application: 9 | // func main() { 10 | // app := &cli.App{ 11 | // Name: "greet", 12 | // Usage: "say a greeting", 13 | // Action: func(c *cli.Context) error { 14 | // println("Greetings") 15 | // }, 16 | // } 17 | // 18 | // app.Run(os.Args) 19 | // } 20 | package cli 21 | 22 | //go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go 23 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/raw.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | // Raw can be used to do raw queries against custom endpoints 4 | type Raw struct { 5 | c *Client 6 | } 7 | 8 | // Raw returns a handle to query endpoints 9 | func (c *Client) Raw() *Raw { 10 | return &Raw{c} 11 | } 12 | 13 | // Query is used to do a GET request against an endpoint 14 | // and deserialize the response into an interface using 15 | // standard Consul conventions. 16 | func (raw *Raw) Query(endpoint string, out interface{}, q *QueryOptions) (*QueryMeta, error) { 17 | return raw.c.query(endpoint, out, q) 18 | } 19 | 20 | // Write is used to do a PUT request against an endpoint 21 | // and serialize/deserialized using the standard Consul conventions. 22 | func (raw *Raw) Write(endpoint string, in, out interface{}, q *WriteOptions) (*WriteMeta, error) { 23 | return raw.c.write(endpoint, in, out, q) 24 | } 25 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/GNUmakefile: -------------------------------------------------------------------------------- 1 | default: test 2 | 3 | deps: 4 | go get golang.org/x/tools/cmd/goimports || true 5 | go get github.com/urfave/gfmrun/... || true 6 | go list ./... \ 7 | | xargs go list -f '{{ join .Deps "\n" }}{{ printf "\n" }}{{ join .TestImports "\n" }}' \ 8 | | grep -v github.com/urfave/cli \ 9 | | xargs go get 10 | @if [ ! -f node_modules/.bin/markdown-toc ]; then \ 11 | npm install markdown-toc ; \ 12 | fi 13 | 14 | gen: deps 15 | ./runtests gen 16 | 17 | vet: 18 | ./runtests vet 19 | 20 | gfmrun: 21 | ./runtests gfmrun 22 | 23 | v1-to-v2: 24 | ./cli-v1-to-v2 --selftest 25 | 26 | migrations: 27 | ./runtests migrations 28 | 29 | toc: 30 | ./runtests toc 31 | 32 | test: deps 33 | ./runtests test 34 | 35 | all: gen vet test gfmrun v1-to-v2 migrations toc 36 | 37 | .PHONY: default gen vet test gfmrun migrations toc v1-to-v2 deps all 38 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | 3 | os: Windows Server 2012 R2 4 | 5 | clone_folder: c:\gopath\src\github.com\urfave\cli 6 | 7 | cache: 8 | - node_modules 9 | 10 | environment: 11 | GOPATH: C:\gopath 12 | GOVERSION: 1.6 13 | PYTHON: C:\Python27-x64 14 | PYTHON_VERSION: 2.7.x 15 | PYTHON_ARCH: 64 16 | 17 | install: 18 | - set PATH=%GOPATH%\bin;C:\go\bin;%PATH% 19 | - go version 20 | - go env 21 | - go get github.com/urfave/gfmrun/... 22 | - rmdir c:\gopath\src\gopkg.in\urfave\cli.v2 /s /q 23 | - rmdir c:\gopath\pkg /s /q 24 | - git clone . c:\gopath\src\gopkg.in\urfave\cli.v2 25 | - go get -v -t ./... 26 | - if not exist node_modules\.bin\markdown-toc npm install markdown-toc 27 | 28 | build_script: 29 | - python runtests vet 30 | - python runtests test 31 | - python runtests gfmrun 32 | - python cli-v1-to-v2 --selftest 33 | - python runtests migrations 34 | - python runtests toc 35 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/README.md: -------------------------------------------------------------------------------- 1 | Consul API client 2 | ================= 3 | 4 | This package provides the `api` package which attempts to 5 | provide programmatic access to the full Consul API. 6 | 7 | Currently, all of the Consul APIs included in version 0.6.0 are supported. 8 | 9 | Documentation 10 | ============= 11 | 12 | The full documentation is available on [Godoc](https://godoc.org/github.com/hashicorp/consul/api) 13 | 14 | Usage 15 | ===== 16 | 17 | Below is an example of using the Consul client: 18 | 19 | ```go 20 | // Get a new client 21 | client, err := api.NewClient(api.DefaultConfig()) 22 | if err != nil { 23 | panic(err) 24 | } 25 | 26 | // Get a handle to the KV API 27 | kv := client.KV() 28 | 29 | // PUT a new KV pair 30 | p := &api.KVPair{Key: "foo", Value: []byte("test")} 31 | _, err = kv.Put(p, nil) 32 | if err != nil { 33 | panic(err) 34 | } 35 | 36 | // Lookup the pair 37 | pair, _, err := kv.Get("foo", nil) 38 | if err != nil { 39 | panic(err) 40 | } 41 | fmt.Printf("KV: %v", pair) 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/status.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | // Status can be used to query the Status endpoints 4 | type Status struct { 5 | c *Client 6 | } 7 | 8 | // Status returns a handle to the status endpoints 9 | func (c *Client) Status() *Status { 10 | return &Status{c} 11 | } 12 | 13 | // Leader is used to query for a known leader 14 | func (s *Status) Leader() (string, error) { 15 | r := s.c.newRequest("GET", "/v1/status/leader") 16 | _, resp, err := requireOK(s.c.doRequest(r)) 17 | if err != nil { 18 | return "", err 19 | } 20 | defer resp.Body.Close() 21 | 22 | var leader string 23 | if err := decodeBody(resp, &leader); err != nil { 24 | return "", err 25 | } 26 | return leader, nil 27 | } 28 | 29 | // Peers is used to query for a known raft peers 30 | func (s *Status) Peers() ([]string, error) { 31 | r := s.c.newRequest("GET", "/v1/status/peers") 32 | _, resp, err := requireOK(s.c.doRequest(r)) 33 | if err != nil { 34 | return nil, err 35 | } 36 | defer resp.Body.Close() 37 | 38 | var peers []string 39 | if err := decodeBody(resp, &peers); err != nil { 40 | return nil, err 41 | } 42 | return peers, nil 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/grubernaut/gdsh/LICENSE.MD: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2016] [Jake Champlin] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Jeremy Saenz & Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-cleanhttp/doc.go: -------------------------------------------------------------------------------- 1 | // Package cleanhttp offers convenience utilities for acquiring "clean" 2 | // http.Transport and http.Client structs. 3 | // 4 | // Values set on http.DefaultClient and http.DefaultTransport affect all 5 | // callers. This can have detrimental effects, esepcially in TLS contexts, 6 | // where client or root certificates set to talk to multiple endpoints can end 7 | // up displacing each other, leading to hard-to-debug issues. This package 8 | // provides non-shared http.Client and http.Transport structs to ensure that 9 | // the configuration will not be overwritten by other parts of the application 10 | // or dependencies. 11 | // 12 | // The DefaultClient and DefaultTransport functions disable idle connections 13 | // and keepalives. Without ensuring that idle connections are closed before 14 | // garbage collection, short-term clients/transports can leak file descriptors, 15 | // eventually leading to "too many open files" errors. If you will be 16 | // connecting to the same hosts repeatedly from the same client, you can use 17 | // DefaultPooledClient to receive a client that has connection pooling 18 | // semantics similar to http.DefaultClient. 19 | // 20 | package cleanhttp 21 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "ignore": "test", 4 | "package": [ 5 | { 6 | "checksumSHA1": "AdGHWN2jhP4JJINo1Tgscfh35FQ=", 7 | "path": "github.com/grubernaut/gdsh/dsh", 8 | "revision": "2c33d82aa1b966d61f8ac032e297f3619f19d875", 9 | "revisionTime": "2016-09-16T05:34:18Z" 10 | }, 11 | { 12 | "checksumSHA1": "gKfOzXWPLnci9lQuwJjW5zBgAcE=", 13 | "path": "github.com/hashicorp/consul/api", 14 | "revision": "41f1764434246ba7ee91625fb9a23d94ae6d6e19", 15 | "revisionTime": "2016-10-13T15:02:20Z" 16 | }, 17 | { 18 | "checksumSHA1": "Uzyon2091lmwacNsl1hCytjhHtg=", 19 | "path": "github.com/hashicorp/go-cleanhttp", 20 | "revision": "ad28ea4487f05916463e2423a55166280e8254b5", 21 | "revisionTime": "2016-04-07T17:41:26Z" 22 | }, 23 | { 24 | "checksumSHA1": "E3Xcanc9ouQwL+CZGOUyA/+giLg=", 25 | "path": "github.com/hashicorp/serf/coordinate", 26 | "revision": "1d4fa605f6ff3ed628d7ae5eda7c0e56803e72a5", 27 | "revisionTime": "2016-10-07T00:41:22Z" 28 | }, 29 | { 30 | "checksumSHA1": "J1irW4tyCsDzaVDu6olx5fG2Nrs=", 31 | "path": "gopkg.in/urfave/cli.v2", 32 | "revision": "c72728f42438425ffcd487986936357e17ebba3f", 33 | "revisionTime": "2016-08-31T17:44:05Z" 34 | } 35 | ], 36 | "rootPath": "github.com/grubernaut/cdsh" 37 | } 38 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/funcs.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | // BashCompleteFunc is an action to execute when the bash-completion flag is set 4 | type BashCompleteFunc func(*Context) 5 | 6 | // BeforeFunc is an action to execute before any subcommands are run, but after 7 | // the context is ready if a non-nil error is returned, no subcommands are run 8 | type BeforeFunc func(*Context) error 9 | 10 | // AfterFunc is an action to execute after any subcommands are run, but after the 11 | // subcommand has finished it is run even if Action() panics 12 | type AfterFunc func(*Context) error 13 | 14 | // ActionFunc is the action to execute when no subcommands are specified 15 | type ActionFunc func(*Context) error 16 | 17 | // CommandNotFoundFunc is executed if the proper command cannot be found 18 | type CommandNotFoundFunc func(*Context, string) 19 | 20 | // OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying 21 | // customized usage error messages. This function is able to replace the 22 | // original error messages. If this function is not set, the "Incorrect usage" 23 | // is displayed and the execution is interrupted. 24 | type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error 25 | 26 | // FlagStringFunc is used by the help generation to display a flag, which is 27 | // expected to be a single line. 28 | type FlagStringFunc func(Flag) string 29 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/args.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import "errors" 4 | 5 | var ( 6 | argsRangeErr = errors.New("index out of range") 7 | ) 8 | 9 | type Args interface { 10 | // Get returns the nth argument, or else a blank string 11 | Get(n int) string 12 | // First returns the first argument, or else a blank string 13 | First() string 14 | // Tail returns the rest of the arguments (not the first one) 15 | // or else an empty string slice 16 | Tail() []string 17 | // Len returns the length of the wrapped slice 18 | Len() int 19 | // Present checks if there are any arguments present 20 | Present() bool 21 | // Slice returns a copy of the internal slice 22 | Slice() []string 23 | } 24 | 25 | type args []string 26 | 27 | func (a *args) Get(n int) string { 28 | if len(*a) > n { 29 | return (*a)[n] 30 | } 31 | return "" 32 | } 33 | 34 | func (a *args) First() string { 35 | return a.Get(0) 36 | } 37 | 38 | func (a *args) Tail() []string { 39 | if a.Len() >= 2 { 40 | tail := []string((*a)[1:]) 41 | ret := make([]string, len(tail)) 42 | copy(ret, tail) 43 | return ret 44 | } 45 | return []string{} 46 | } 47 | 48 | func (a *args) Len() int { 49 | return len(*a) 50 | } 51 | 52 | func (a *args) Present() bool { 53 | return a.Len() != 0 54 | } 55 | 56 | func (a *args) Slice() []string { 57 | ret := make([]string, len(*a)) 58 | copy(ret, []string(*a)) 59 | return ret 60 | } 61 | -------------------------------------------------------------------------------- /vendor/github.com/grubernaut/gdsh/dsh/machinelist.go: -------------------------------------------------------------------------------- 1 | package dsh 2 | 3 | import ( 4 | "bufio" 5 | "container/list" 6 | "os" 7 | ) 8 | 9 | // Generic functions for building the linked machine list 10 | 11 | // ReadMachineList will read a machine list from file, and append it 12 | // to the current machine list 13 | func (e *ExecOpts) ReadMachineList(path string) error { 14 | // Read file path 15 | file, err := os.Open(path) 16 | if err != nil { 17 | return err 18 | } 19 | defer func() { 20 | _ = file.Close() 21 | }() 22 | 23 | scan := bufio.NewScanner(file) 24 | // Add read-in file to machineList 25 | for scan.Scan() { 26 | e.MachineList = addList(e.MachineList, scan.Text()) 27 | } 28 | 29 | return nil 30 | } 31 | 32 | // SplitListAndAdd will split a comma-deliminated list of machines 33 | // and add them to the linked list 34 | func (e *ExecOpts) SplitListAndAdd(input string) error { 35 | return nil 36 | } 37 | 38 | func addList(llist *list.List, elem string) *list.List { 39 | // if empty list, push elem to front 40 | if llist.Len() == 0 { 41 | llist.PushFront(elem) 42 | return llist 43 | } 44 | // make sure element isn't nil 45 | if elem == "" { 46 | return llist 47 | } 48 | // loop through list; see if there's a match currently; if so return early 49 | for e := llist.Front(); e != nil; e = e.Next() { 50 | if e.Value == elem { 51 | return llist 52 | } 53 | } 54 | // Element not in linked list, add to end of list 55 | if elem != "" { 56 | llist.PushBack(elem) 57 | } 58 | // No error, hopefully 59 | return llist 60 | } 61 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-cleanhttp/README.md: -------------------------------------------------------------------------------- 1 | # cleanhttp 2 | 3 | Functions for accessing "clean" Go http.Client values 4 | 5 | ------------- 6 | 7 | The Go standard library contains a default `http.Client` called 8 | `http.DefaultClient`. It is a common idiom in Go code to start with 9 | `http.DefaultClient` and tweak it as necessary, and in fact, this is 10 | encouraged; from the `http` package documentation: 11 | 12 | > The Client's Transport typically has internal state (cached TCP connections), 13 | so Clients should be reused instead of created as needed. Clients are safe for 14 | concurrent use by multiple goroutines. 15 | 16 | Unfortunately, this is a shared value, and it is not uncommon for libraries to 17 | assume that they are free to modify it at will. With enough dependencies, it 18 | can be very easy to encounter strange problems and race conditions due to 19 | manipulation of this shared value across libraries and goroutines (clients are 20 | safe for concurrent use, but writing values to the client struct itself is not 21 | protected). 22 | 23 | Making things worse is the fact that a bare `http.Client` will use a default 24 | `http.Transport` called `http.DefaultTransport`, which is another global value 25 | that behaves the same way. So it is not simply enough to replace 26 | `http.DefaultClient` with `&http.Client{}`. 27 | 28 | This repository provides some simple functions to get a "clean" `http.Client` 29 | -- one that uses the same default values as the Go standard library, but 30 | returns a client that does not share any state with other clients. 31 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go: -------------------------------------------------------------------------------- 1 | package cleanhttp 2 | 3 | import ( 4 | "net" 5 | "net/http" 6 | "time" 7 | ) 8 | 9 | // DefaultTransport returns a new http.Transport with the same default values 10 | // as http.DefaultTransport, but with idle connections and keepalives disabled. 11 | func DefaultTransport() *http.Transport { 12 | transport := DefaultPooledTransport() 13 | transport.DisableKeepAlives = true 14 | transport.MaxIdleConnsPerHost = -1 15 | return transport 16 | } 17 | 18 | // DefaultPooledTransport returns a new http.Transport with similar default 19 | // values to http.DefaultTransport. Do not use this for transient transports as 20 | // it can leak file descriptors over time. Only use this for transports that 21 | // will be re-used for the same host(s). 22 | func DefaultPooledTransport() *http.Transport { 23 | transport := &http.Transport{ 24 | Proxy: http.ProxyFromEnvironment, 25 | Dial: (&net.Dialer{ 26 | Timeout: 30 * time.Second, 27 | KeepAlive: 30 * time.Second, 28 | }).Dial, 29 | TLSHandshakeTimeout: 10 * time.Second, 30 | DisableKeepAlives: false, 31 | MaxIdleConnsPerHost: 1, 32 | } 33 | return transport 34 | } 35 | 36 | // DefaultClient returns a new http.Client with similar default values to 37 | // http.Client, but with a non-shared Transport, idle connections disabled, and 38 | // keepalives disabled. 39 | func DefaultClient() *http.Client { 40 | return &http.Client{ 41 | Transport: DefaultTransport(), 42 | } 43 | } 44 | 45 | // DefaultPooledClient returns a new http.Client with the same default values 46 | // as http.Client, but with a shared Transport. Do not use this function 47 | // for transient clients as it can leak file descriptors over time. Only use 48 | // this for clients that will be re-used for the same host(s). 49 | func DefaultPooledClient() *http.Client { 50 | return &http.Client{ 51 | Transport: DefaultPooledTransport(), 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/coordinate.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "github.com/hashicorp/serf/coordinate" 5 | ) 6 | 7 | // CoordinateEntry represents a node and its associated network coordinate. 8 | type CoordinateEntry struct { 9 | Node string 10 | Coord *coordinate.Coordinate 11 | } 12 | 13 | // CoordinateDatacenterMap represents a datacenter and its associated WAN 14 | // nodes and their associates coordinates. 15 | type CoordinateDatacenterMap struct { 16 | Datacenter string 17 | Coordinates []CoordinateEntry 18 | } 19 | 20 | // Coordinate can be used to query the coordinate endpoints 21 | type Coordinate struct { 22 | c *Client 23 | } 24 | 25 | // Coordinate returns a handle to the coordinate endpoints 26 | func (c *Client) Coordinate() *Coordinate { 27 | return &Coordinate{c} 28 | } 29 | 30 | // Datacenters is used to return the coordinates of all the servers in the WAN 31 | // pool. 32 | func (c *Coordinate) Datacenters() ([]*CoordinateDatacenterMap, error) { 33 | r := c.c.newRequest("GET", "/v1/coordinate/datacenters") 34 | _, resp, err := requireOK(c.c.doRequest(r)) 35 | if err != nil { 36 | return nil, err 37 | } 38 | defer resp.Body.Close() 39 | 40 | var out []*CoordinateDatacenterMap 41 | if err := decodeBody(resp, &out); err != nil { 42 | return nil, err 43 | } 44 | return out, nil 45 | } 46 | 47 | // Nodes is used to return the coordinates of all the nodes in the LAN pool. 48 | func (c *Coordinate) Nodes(q *QueryOptions) ([]*CoordinateEntry, *QueryMeta, error) { 49 | r := c.c.newRequest("GET", "/v1/coordinate/nodes") 50 | r.setQueryOptions(q) 51 | rtt, resp, err := requireOK(c.c.doRequest(r)) 52 | if err != nil { 53 | return nil, nil, err 54 | } 55 | defer resp.Body.Close() 56 | 57 | qm := &QueryMeta{} 58 | parseQueryMeta(resp, qm) 59 | qm.RequestTime = rtt 60 | 61 | var out []*CoordinateEntry 62 | if err := decodeBody(resp, &out); err != nil { 63 | return nil, nil, err 64 | } 65 | return out, qm, nil 66 | } 67 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/category.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | type CommandCategories interface { 4 | // AddCommand adds a command to a category, creating a new category if necessary. 5 | AddCommand(category string, command *Command) 6 | // Categories returns a copy of the category slice 7 | Categories() []CommandCategory 8 | } 9 | 10 | type commandCategories []*commandCategory 11 | 12 | func newCommandCategories() CommandCategories { 13 | ret := commandCategories([]*commandCategory{}) 14 | return &ret 15 | } 16 | 17 | func (c *commandCategories) Less(i, j int) bool { 18 | return (*c)[i].Name() < (*c)[j].Name() 19 | } 20 | 21 | func (c *commandCategories) Len() int { 22 | return len(*c) 23 | } 24 | 25 | func (c *commandCategories) Swap(i, j int) { 26 | (*c)[i], (*c)[j] = (*c)[j], (*c)[i] 27 | } 28 | 29 | func (c *commandCategories) AddCommand(category string, command *Command) { 30 | for _, commandCategory := range []*commandCategory(*c) { 31 | if commandCategory.name == category { 32 | commandCategory.commands = append(commandCategory.commands, command) 33 | return 34 | } 35 | } 36 | newVal := commandCategories(append(*c, 37 | &commandCategory{name: category, commands: []*Command{command}})) 38 | (*c) = newVal 39 | } 40 | 41 | func (c *commandCategories) Categories() []CommandCategory { 42 | ret := make([]CommandCategory, len(*c)) 43 | for i, cat := range *c { 44 | ret[i] = cat 45 | } 46 | return ret 47 | } 48 | 49 | // CommandCategory is a category containing commands. 50 | type CommandCategory interface { 51 | // Name returns the category name string 52 | Name() string 53 | // VisibleCommands returns a slice of the Commands with Hidden=false 54 | VisibleCommands() []*Command 55 | } 56 | 57 | type commandCategory struct { 58 | name string 59 | commands []*Command 60 | } 61 | 62 | func newCommandCategory(name string) *commandCategory { 63 | return &commandCategory{ 64 | name: name, 65 | commands: []*Command{}, 66 | } 67 | } 68 | 69 | func (c *commandCategory) Name() string { 70 | return c.name 71 | } 72 | 73 | func (c *commandCategory) VisibleCommands() []*Command { 74 | if c.commands == nil { 75 | c.commands = []*Command{} 76 | } 77 | 78 | ret := []*Command{} 79 | for _, command := range c.commands { 80 | if !command.Hidden { 81 | ret = append(ret, command) 82 | } 83 | } 84 | return ret 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Consul DSH 2 | ========== 3 | 4 | `go get -u github.com/grubernaut/cdsh` 5 | 6 | The remote shell `exec` for consul services. 7 | 8 | ### Quick How-to 9 | 10 | ``` 11 | cdsh --server --service --user '' 12 | ``` 13 | 14 | **Note:** 15 | Be sure that you're actually able to SSH to the target consul service. (SSH Keys, Host key verification, etc) 16 | 17 | ### Options 18 | 19 | * `--server` / `-s`: Consul server to query against. Required. Can also use `CONSUL_SERVER`, but environment variable takes priority. 20 | * `--service` / `-S`: Target service to run command against 21 | * `--user` / `-u`: Remote user to connect as. If unspecified, defaults to current local user 22 | 23 | More options are likely to come in the future, such as `--tag` `--token`, `--node`, etc... 24 | 25 | If `--service` is left unspecified, `cdsh` will return a list of all available services. This will likely be changed 26 | in the future to a separate flag entirely. 27 | 28 | ### Doesn't Consul have a native `exec` command? 29 | 30 | While consul _does_ have a native `exec` command, there are a couple issues with using `consul exec`. 31 | 32 | > Agents are informed about the new job using the event system, which propagates messages via the gossip protocol. As a 33 | > result, delivery is best-effort, and there is no guarantee of execution. 34 | > ... 35 | > While events are purely gossip driven, remote execution relies on the KV store as a message broker. 36 | 37 | Using Consul K/V as a message broker _definitely_ has it's benefits, but there are often times in daily operations work, 38 | where a user might want to know immediately if they cannot connect to a service. 39 | 40 | However, the main concern with using `consul exec` is as follows: 41 | 42 | > Verbose output warning: use care to make sure that your command does not produce a large volume of output. Writes to 43 | > the KV store for this output go through the Consul servers and the Raft consensus algorithm, so having a large number 44 | > of nodes in the cluster flow a large amount of data through the KV store could make the cluster unavailable. 45 | 46 | There are quite a few times where I've needed to fetch fairly verbose log output from N-servers, and pipe the output to 47 | a file for further analysis. Using DSH completely abstracts the command output from Consul K/V, allowing the user to run 48 | fairly verbose commands without worry. 49 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/flag-types.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Bool", 4 | "type": "bool", 5 | "context_default": "false", 6 | "parser": "strconv.ParseBool(f.Value.String())" 7 | }, 8 | { 9 | "name": "Duration", 10 | "type": "time.Duration", 11 | "doctail": " (see https://golang.org/pkg/time/#ParseDuration)", 12 | "context_default": "0", 13 | "parser": "time.ParseDuration(f.Value.String())" 14 | }, 15 | { 16 | "name": "Float64", 17 | "type": "float64", 18 | "context_default": "0", 19 | "parser": "strconv.ParseFloat(f.Value.String(), 64)" 20 | }, 21 | { 22 | "name": "Generic", 23 | "type": "Generic", 24 | "dest": false, 25 | "context_default": "nil", 26 | "context_type": "interface{}" 27 | }, 28 | { 29 | "name": "Int64", 30 | "type": "int64", 31 | "context_default": "0", 32 | "parser": "strconv.ParseInt(f.Value.String(), 0, 64)" 33 | }, 34 | { 35 | "name": "Int", 36 | "type": "int", 37 | "context_default": "0", 38 | "parser": "strconv.ParseInt(f.Value.String(), 0, 64)", 39 | "parser_cast": "int(parsed)" 40 | }, 41 | { 42 | "name": "IntSlice", 43 | "type": "*IntSlice", 44 | "dest": false, 45 | "context_default": "nil", 46 | "context_type": "[]int", 47 | "parser": "(f.Value.(*IntSlice)).Value(), error(nil)" 48 | }, 49 | { 50 | "name": "Int64Slice", 51 | "type": "*Int64Slice", 52 | "dest": false, 53 | "context_default": "nil", 54 | "context_type": "[]int64", 55 | "parser": "(f.Value.(*Int64Slice)).Value(), error(nil)" 56 | }, 57 | { 58 | "name": "Float64Slice", 59 | "type": "*Float64Slice", 60 | "dest": false, 61 | "context_default": "nil", 62 | "context_type": "[]float64", 63 | "parser": "(f.Value.(*Float64Slice)).Value(), error(nil)" 64 | }, 65 | { 66 | "name": "String", 67 | "type": "string", 68 | "context_default": "\"\"", 69 | "parser": "f.Value.String(), error(nil)" 70 | }, 71 | { 72 | "name": "StringSlice", 73 | "type": "*StringSlice", 74 | "dest": false, 75 | "context_default": "nil", 76 | "context_type": "[]string", 77 | "parser": "(f.Value.(*StringSlice)).Value(), error(nil)" 78 | }, 79 | { 80 | "name": "Uint64", 81 | "type": "uint64", 82 | "context_default": "0", 83 | "parser": "strconv.ParseUint(f.Value.String(), 0, 64)" 84 | }, 85 | { 86 | "name": "Uint", 87 | "type": "uint", 88 | "context_default": "0", 89 | "parser": "strconv.ParseUint(f.Value.String(), 0, 64)", 90 | "parser_cast": "uint(parsed)" 91 | } 92 | ] 93 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/operator.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | // Operator can be used to perform low-level operator tasks for Consul. 4 | type Operator struct { 5 | c *Client 6 | } 7 | 8 | // Operator returns a handle to the operator endpoints. 9 | func (c *Client) Operator() *Operator { 10 | return &Operator{c} 11 | } 12 | 13 | // RaftServer has information about a server in the Raft configuration. 14 | type RaftServer struct { 15 | // ID is the unique ID for the server. These are currently the same 16 | // as the address, but they will be changed to a real GUID in a future 17 | // release of Consul. 18 | ID string 19 | 20 | // Node is the node name of the server, as known by Consul, or this 21 | // will be set to "(unknown)" otherwise. 22 | Node string 23 | 24 | // Address is the IP:port of the server, used for Raft communications. 25 | Address string 26 | 27 | // Leader is true if this server is the current cluster leader. 28 | Leader bool 29 | 30 | // Voter is true if this server has a vote in the cluster. This might 31 | // be false if the server is staging and still coming online, or if 32 | // it's a non-voting server, which will be added in a future release of 33 | // Consul. 34 | Voter bool 35 | } 36 | 37 | // RaftConfigration is returned when querying for the current Raft configuration. 38 | type RaftConfiguration struct { 39 | // Servers has the list of servers in the Raft configuration. 40 | Servers []*RaftServer 41 | 42 | // Index has the Raft index of this configuration. 43 | Index uint64 44 | } 45 | 46 | // RaftGetConfiguration is used to query the current Raft peer set. 47 | func (op *Operator) RaftGetConfiguration(q *QueryOptions) (*RaftConfiguration, error) { 48 | r := op.c.newRequest("GET", "/v1/operator/raft/configuration") 49 | r.setQueryOptions(q) 50 | _, resp, err := requireOK(op.c.doRequest(r)) 51 | if err != nil { 52 | return nil, err 53 | } 54 | defer resp.Body.Close() 55 | 56 | var out RaftConfiguration 57 | if err := decodeBody(resp, &out); err != nil { 58 | return nil, err 59 | } 60 | return &out, nil 61 | } 62 | 63 | // RaftRemovePeerByAddress is used to kick a stale peer (one that it in the Raft 64 | // quorum but no longer known to Serf or the catalog) by address in the form of 65 | // "IP:port". 66 | func (op *Operator) RaftRemovePeerByAddress(address string, q *WriteOptions) error { 67 | r := op.c.newRequest("DELETE", "/v1/operator/raft/peer") 68 | r.setWriteOptions(q) 69 | 70 | // TODO (slackpad) Currently we made address a query parameter. Once 71 | // IDs are in place this will be DELETE /v1/operator/raft/peer/. 72 | r.params.Set("address", string(address)) 73 | 74 | _, resp, err := requireOK(op.c.doRequest(r)) 75 | if err != nil { 76 | return err 77 | } 78 | 79 | resp.Body.Close() 80 | return nil 81 | } 82 | -------------------------------------------------------------------------------- /vendor/github.com/grubernaut/gdsh/dsh/execute.go: -------------------------------------------------------------------------------- 1 | package dsh 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "io" 8 | "os" 9 | "os/exec" 10 | "strings" 11 | ) 12 | 13 | // Execute remote commands for each host 14 | func (e *ExecOpts) Execute() error { 15 | signals := make(chan Signal) 16 | for elem := e.MachineList.Front(); elem != nil; elem = elem.Next() { 17 | cmdOpts := e.buildCmdOpts(elem.Value.(string)) 18 | if e.Verbose { 19 | fmt.Printf("Dumping parameters passed to exec\n") 20 | fmt.Printf("%#v\n", cmdOpts) 21 | } 22 | // Spawn a new goroutine 23 | go executeShell(e.RemoteShell, cmdOpts, signals, e.ShowNames, elem.Value.(string)) 24 | } 25 | 26 | // Block until routines are cleaned up 27 | var err error 28 | for i := 0; i < e.MachineList.Len(); i++ { 29 | select { 30 | case signal := <-signals: 31 | if signal.err != nil { 32 | fmt.Printf("Error executing: %s\n", signal.errOutput) 33 | err = signal.err 34 | } 35 | } 36 | } 37 | return err 38 | } 39 | 40 | // Build up command options for each item in linked list 41 | func (e *ExecOpts) buildCmdOpts(elem string) []string { 42 | var opts []string 43 | if e.RemoteCommandOpts != "" { 44 | opts = append(opts, e.RemoteCommandOpts) 45 | } 46 | // split machine name and username 47 | if strings.Contains(elem, "@") { 48 | userHost := strings.Split(elem, "@") 49 | opts = append(opts, "-l") 50 | opts = append(opts, userHost...) 51 | } else { 52 | opts = append(opts, elem) 53 | } 54 | opts = append(opts, e.RemoteCommand) 55 | return opts 56 | } 57 | 58 | // Performs the actual execution of the Remote Shell command 59 | func executeShell(cmd string, cmdOpts []string, c chan Signal, names bool, name string) { 60 | // hopefully you don't need it 61 | var errOutput bytes.Buffer 62 | run := exec.Command(cmd, cmdOpts...) 63 | run.Stderr = io.Writer(&errOutput) 64 | stdout, err := run.StdoutPipe() 65 | if err != nil { 66 | c <- Signal{ 67 | err: err, 68 | } 69 | return 70 | } 71 | run.Env = os.Environ() 72 | 73 | // Create a new scanner from stdout pipe 74 | scanner := bufio.NewScanner(stdout) 75 | // While we have stdout to print, print it. 76 | go func() { 77 | for scanner.Scan() { 78 | if names { 79 | fmt.Printf("%s: %s\n", name, scanner.Text()) 80 | } else { 81 | fmt.Printf("%s\n", scanner.Text()) 82 | } 83 | } 84 | }() 85 | 86 | if err := run.Start(); err != nil { 87 | c <- Signal{ 88 | err: err, 89 | errOutput: errOutput.String(), 90 | } 91 | return 92 | } 93 | 94 | // Block for command to finish 95 | if err := run.Wait(); err != nil { 96 | c <- Signal{ 97 | err: err, 98 | errOutput: errOutput.String(), 99 | } 100 | return 101 | } 102 | 103 | // Non-error case 104 | c <- Signal{nil, ""} 105 | } 106 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/errors.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | // OsExiter is the function used when the app exits. If not set defaults to os.Exit. 11 | var OsExiter = os.Exit 12 | 13 | // ErrWriter is used to write errors to the user. This can be anything 14 | // implementing the io.Writer interface and defaults to os.Stderr. 15 | var ErrWriter io.Writer = os.Stderr 16 | 17 | // MultiError is an error that wraps multiple errors. 18 | type MultiError interface { 19 | error 20 | // Errors returns a copy of the errors slice 21 | Errors() []error 22 | } 23 | 24 | // NewMultiError creates a new MultiError. Pass in one or more errors. 25 | func newMultiError(err ...error) MultiError { 26 | ret := multiError(err) 27 | return &ret 28 | } 29 | 30 | type multiError []error 31 | 32 | // Error implements the error interface. 33 | func (m *multiError) Error() string { 34 | errs := make([]string, len(*m)) 35 | for i, err := range *m { 36 | errs[i] = err.Error() 37 | } 38 | 39 | return strings.Join(errs, "\n") 40 | } 41 | 42 | // Errors returns a copy of the errors slice 43 | func (m *multiError) Errors() []error { 44 | errs := make([]error, len(*m)) 45 | for _, err := range *m { 46 | errs = append(errs, err) 47 | } 48 | return errs 49 | } 50 | 51 | // ExitCoder is the interface checked by `App` and `Command` for a custom exit 52 | // code 53 | type ExitCoder interface { 54 | error 55 | ExitCode() int 56 | } 57 | 58 | type exitError struct { 59 | exitCode int 60 | message string 61 | } 62 | 63 | // Exit wraps a message and exit code into an ExitCoder suitable for handling by 64 | // HandleExitCoder 65 | func Exit(message string, exitCode int) ExitCoder { 66 | return &exitError{ 67 | exitCode: exitCode, 68 | message: message, 69 | } 70 | } 71 | 72 | func (ee *exitError) Error() string { 73 | return ee.message 74 | } 75 | 76 | func (ee *exitError) ExitCode() int { 77 | return ee.exitCode 78 | } 79 | 80 | // HandleExitCoder checks if the error fulfills the ExitCoder interface, and if 81 | // so prints the error to stderr (if it is non-empty) and calls OsExiter with the 82 | // given exit code. If the given error is a MultiError, then this func is 83 | // called on all members of the Errors slice. 84 | func HandleExitCoder(err error) { 85 | if err == nil { 86 | return 87 | } 88 | 89 | if exitErr, ok := err.(ExitCoder); ok { 90 | if err.Error() != "" { 91 | fmt.Fprintln(ErrWriter, err) 92 | } 93 | OsExiter(exitErr.ExitCode()) 94 | return 95 | } 96 | 97 | if multiErr, ok := err.(MultiError); ok { 98 | for _, merr := range multiErr.Errors() { 99 | HandleExitCoder(merr) 100 | } 101 | return 102 | } 103 | 104 | if err.Error() != "" { 105 | fmt.Fprintln(ErrWriter, err) 106 | } 107 | OsExiter(1) 108 | } 109 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/serf/coordinate/config.go: -------------------------------------------------------------------------------- 1 | package coordinate 2 | 3 | // Config is used to set the parameters of the Vivaldi-based coordinate mapping 4 | // algorithm. 5 | // 6 | // The following references are called out at various points in the documentation 7 | // here: 8 | // 9 | // [1] Dabek, Frank, et al. "Vivaldi: A decentralized network coordinate system." 10 | // ACM SIGCOMM Computer Communication Review. Vol. 34. No. 4. ACM, 2004. 11 | // [2] Ledlie, Jonathan, Paul Gardner, and Margo I. Seltzer. "Network Coordinates 12 | // in the Wild." NSDI. Vol. 7. 2007. 13 | // [3] Lee, Sanghwan, et al. "On suitability of Euclidean embedding for 14 | // host-based network coordinate systems." Networking, IEEE/ACM Transactions 15 | // on 18.1 (2010): 27-40. 16 | type Config struct { 17 | // The dimensionality of the coordinate system. As discussed in [2], more 18 | // dimensions improves the accuracy of the estimates up to a point. Per [2] 19 | // we chose 8 dimensions plus a non-Euclidean height. 20 | Dimensionality uint 21 | 22 | // VivaldiErrorMax is the default error value when a node hasn't yet made 23 | // any observations. It also serves as an upper limit on the error value in 24 | // case observations cause the error value to increase without bound. 25 | VivaldiErrorMax float64 26 | 27 | // VivaldiCE is a tuning factor that controls the maximum impact an 28 | // observation can have on a node's confidence. See [1] for more details. 29 | VivaldiCE float64 30 | 31 | // VivaldiCC is a tuning factor that controls the maximum impact an 32 | // observation can have on a node's coordinate. See [1] for more details. 33 | VivaldiCC float64 34 | 35 | // AdjustmentWindowSize is a tuning factor that determines how many samples 36 | // we retain to calculate the adjustment factor as discussed in [3]. Setting 37 | // this to zero disables this feature. 38 | AdjustmentWindowSize uint 39 | 40 | // HeightMin is the minimum value of the height parameter. Since this 41 | // always must be positive, it will introduce a small amount error, so 42 | // the chosen value should be relatively small compared to "normal" 43 | // coordinates. 44 | HeightMin float64 45 | 46 | // LatencyFilterSamples is the maximum number of samples that are retained 47 | // per node, in order to compute a median. The intent is to ride out blips 48 | // but still keep the delay low, since our time to probe any given node is 49 | // pretty infrequent. See [2] for more details. 50 | LatencyFilterSize uint 51 | 52 | // GravityRho is a tuning factor that sets how much gravity has an effect 53 | // to try to re-center coordinates. See [2] for more details. 54 | GravityRho float64 55 | } 56 | 57 | // DefaultConfig returns a Config that has some default values suitable for 58 | // basic testing of the algorithm, but not tuned to any particular type of cluster. 59 | func DefaultConfig() *Config { 60 | return &Config{ 61 | Dimensionality: 8, 62 | VivaldiErrorMax: 1.5, 63 | VivaldiCE: 0.25, 64 | VivaldiCC: 0.25, 65 | AdjustmentWindowSize: 20, 66 | HeightMin: 10.0e-6, 67 | LatencyFilterSize: 3, 68 | GravityRho: 150.0, 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/event.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "bytes" 5 | "strconv" 6 | ) 7 | 8 | // Event can be used to query the Event endpoints 9 | type Event struct { 10 | c *Client 11 | } 12 | 13 | // UserEvent represents an event that was fired by the user 14 | type UserEvent struct { 15 | ID string 16 | Name string 17 | Payload []byte 18 | NodeFilter string 19 | ServiceFilter string 20 | TagFilter string 21 | Version int 22 | LTime uint64 23 | } 24 | 25 | // Event returns a handle to the event endpoints 26 | func (c *Client) Event() *Event { 27 | return &Event{c} 28 | } 29 | 30 | // Fire is used to fire a new user event. Only the Name, Payload and Filters 31 | // are respected. This returns the ID or an associated error. Cross DC requests 32 | // are supported. 33 | func (e *Event) Fire(params *UserEvent, q *WriteOptions) (string, *WriteMeta, error) { 34 | r := e.c.newRequest("PUT", "/v1/event/fire/"+params.Name) 35 | r.setWriteOptions(q) 36 | if params.NodeFilter != "" { 37 | r.params.Set("node", params.NodeFilter) 38 | } 39 | if params.ServiceFilter != "" { 40 | r.params.Set("service", params.ServiceFilter) 41 | } 42 | if params.TagFilter != "" { 43 | r.params.Set("tag", params.TagFilter) 44 | } 45 | if params.Payload != nil { 46 | r.body = bytes.NewReader(params.Payload) 47 | } 48 | 49 | rtt, resp, err := requireOK(e.c.doRequest(r)) 50 | if err != nil { 51 | return "", nil, err 52 | } 53 | defer resp.Body.Close() 54 | 55 | wm := &WriteMeta{RequestTime: rtt} 56 | var out UserEvent 57 | if err := decodeBody(resp, &out); err != nil { 58 | return "", nil, err 59 | } 60 | return out.ID, wm, nil 61 | } 62 | 63 | // List is used to get the most recent events an agent has received. 64 | // This list can be optionally filtered by the name. This endpoint supports 65 | // quasi-blocking queries. The index is not monotonic, nor does it provide provide 66 | // LastContact or KnownLeader. 67 | func (e *Event) List(name string, q *QueryOptions) ([]*UserEvent, *QueryMeta, error) { 68 | r := e.c.newRequest("GET", "/v1/event/list") 69 | r.setQueryOptions(q) 70 | if name != "" { 71 | r.params.Set("name", name) 72 | } 73 | rtt, resp, err := requireOK(e.c.doRequest(r)) 74 | if err != nil { 75 | return nil, nil, err 76 | } 77 | defer resp.Body.Close() 78 | 79 | qm := &QueryMeta{} 80 | parseQueryMeta(resp, qm) 81 | qm.RequestTime = rtt 82 | 83 | var entries []*UserEvent 84 | if err := decodeBody(resp, &entries); err != nil { 85 | return nil, nil, err 86 | } 87 | return entries, qm, nil 88 | } 89 | 90 | // IDToIndex is a bit of a hack. This simulates the index generation to 91 | // convert an event ID into a WaitIndex. 92 | func (e *Event) IDToIndex(uuid string) uint64 { 93 | lower := uuid[0:8] + uuid[9:13] + uuid[14:18] 94 | upper := uuid[19:23] + uuid[24:36] 95 | lowVal, err := strconv.ParseUint(lower, 16, 64) 96 | if err != nil { 97 | panic("Failed to convert " + lower) 98 | } 99 | highVal, err := strconv.ParseUint(upper, 16, 64) 100 | if err != nil { 101 | panic("Failed to convert " + upper) 102 | } 103 | return lowVal ^ highVal 104 | } 105 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/acl.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | const ( 4 | // ACLCLientType is the client type token 5 | ACLClientType = "client" 6 | 7 | // ACLManagementType is the management type token 8 | ACLManagementType = "management" 9 | ) 10 | 11 | // ACLEntry is used to represent an ACL entry 12 | type ACLEntry struct { 13 | CreateIndex uint64 14 | ModifyIndex uint64 15 | ID string 16 | Name string 17 | Type string 18 | Rules string 19 | } 20 | 21 | // ACL can be used to query the ACL endpoints 22 | type ACL struct { 23 | c *Client 24 | } 25 | 26 | // ACL returns a handle to the ACL endpoints 27 | func (c *Client) ACL() *ACL { 28 | return &ACL{c} 29 | } 30 | 31 | // Create is used to generate a new token with the given parameters 32 | func (a *ACL) Create(acl *ACLEntry, q *WriteOptions) (string, *WriteMeta, error) { 33 | r := a.c.newRequest("PUT", "/v1/acl/create") 34 | r.setWriteOptions(q) 35 | r.obj = acl 36 | rtt, resp, err := requireOK(a.c.doRequest(r)) 37 | if err != nil { 38 | return "", nil, err 39 | } 40 | defer resp.Body.Close() 41 | 42 | wm := &WriteMeta{RequestTime: rtt} 43 | var out struct{ ID string } 44 | if err := decodeBody(resp, &out); err != nil { 45 | return "", nil, err 46 | } 47 | return out.ID, wm, nil 48 | } 49 | 50 | // Update is used to update the rules of an existing token 51 | func (a *ACL) Update(acl *ACLEntry, q *WriteOptions) (*WriteMeta, error) { 52 | r := a.c.newRequest("PUT", "/v1/acl/update") 53 | r.setWriteOptions(q) 54 | r.obj = acl 55 | rtt, resp, err := requireOK(a.c.doRequest(r)) 56 | if err != nil { 57 | return nil, err 58 | } 59 | defer resp.Body.Close() 60 | 61 | wm := &WriteMeta{RequestTime: rtt} 62 | return wm, nil 63 | } 64 | 65 | // Destroy is used to destroy a given ACL token ID 66 | func (a *ACL) Destroy(id string, q *WriteOptions) (*WriteMeta, error) { 67 | r := a.c.newRequest("PUT", "/v1/acl/destroy/"+id) 68 | r.setWriteOptions(q) 69 | rtt, resp, err := requireOK(a.c.doRequest(r)) 70 | if err != nil { 71 | return nil, err 72 | } 73 | resp.Body.Close() 74 | 75 | wm := &WriteMeta{RequestTime: rtt} 76 | return wm, nil 77 | } 78 | 79 | // Clone is used to return a new token cloned from an existing one 80 | func (a *ACL) Clone(id string, q *WriteOptions) (string, *WriteMeta, error) { 81 | r := a.c.newRequest("PUT", "/v1/acl/clone/"+id) 82 | r.setWriteOptions(q) 83 | rtt, resp, err := requireOK(a.c.doRequest(r)) 84 | if err != nil { 85 | return "", nil, err 86 | } 87 | defer resp.Body.Close() 88 | 89 | wm := &WriteMeta{RequestTime: rtt} 90 | var out struct{ ID string } 91 | if err := decodeBody(resp, &out); err != nil { 92 | return "", nil, err 93 | } 94 | return out.ID, wm, nil 95 | } 96 | 97 | // Info is used to query for information about an ACL token 98 | func (a *ACL) Info(id string, q *QueryOptions) (*ACLEntry, *QueryMeta, error) { 99 | r := a.c.newRequest("GET", "/v1/acl/info/"+id) 100 | r.setQueryOptions(q) 101 | rtt, resp, err := requireOK(a.c.doRequest(r)) 102 | if err != nil { 103 | return nil, nil, err 104 | } 105 | defer resp.Body.Close() 106 | 107 | qm := &QueryMeta{} 108 | parseQueryMeta(resp, qm) 109 | qm.RequestTime = rtt 110 | 111 | var entries []*ACLEntry 112 | if err := decodeBody(resp, &entries); err != nil { 113 | return nil, nil, err 114 | } 115 | if len(entries) > 0 { 116 | return entries[0], qm, nil 117 | } 118 | return nil, qm, nil 119 | } 120 | 121 | // List is used to get all the ACL tokens 122 | func (a *ACL) List(q *QueryOptions) ([]*ACLEntry, *QueryMeta, error) { 123 | r := a.c.newRequest("GET", "/v1/acl/list") 124 | r.setQueryOptions(q) 125 | rtt, resp, err := requireOK(a.c.doRequest(r)) 126 | if err != nil { 127 | return nil, nil, err 128 | } 129 | defer resp.Body.Close() 130 | 131 | qm := &QueryMeta{} 132 | parseQueryMeta(resp, qm) 133 | qm.RequestTime = rtt 134 | 135 | var entries []*ACLEntry 136 | if err := decodeBody(resp, &entries); err != nil { 137 | return nil, nil, err 138 | } 139 | return entries, qm, nil 140 | } 141 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/health.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | const ( 8 | // HealthAny is special, and is used as a wild card, 9 | // not as a specific state. 10 | HealthAny = "any" 11 | HealthPassing = "passing" 12 | HealthWarning = "warning" 13 | HealthCritical = "critical" 14 | ) 15 | 16 | // HealthCheck is used to represent a single check 17 | type HealthCheck struct { 18 | Node string 19 | CheckID string 20 | Name string 21 | Status string 22 | Notes string 23 | Output string 24 | ServiceID string 25 | ServiceName string 26 | } 27 | 28 | // ServiceEntry is used for the health service endpoint 29 | type ServiceEntry struct { 30 | Node *Node 31 | Service *AgentService 32 | Checks []*HealthCheck 33 | } 34 | 35 | // Health can be used to query the Health endpoints 36 | type Health struct { 37 | c *Client 38 | } 39 | 40 | // Health returns a handle to the health endpoints 41 | func (c *Client) Health() *Health { 42 | return &Health{c} 43 | } 44 | 45 | // Node is used to query for checks belonging to a given node 46 | func (h *Health) Node(node string, q *QueryOptions) ([]*HealthCheck, *QueryMeta, error) { 47 | r := h.c.newRequest("GET", "/v1/health/node/"+node) 48 | r.setQueryOptions(q) 49 | rtt, resp, err := requireOK(h.c.doRequest(r)) 50 | if err != nil { 51 | return nil, nil, err 52 | } 53 | defer resp.Body.Close() 54 | 55 | qm := &QueryMeta{} 56 | parseQueryMeta(resp, qm) 57 | qm.RequestTime = rtt 58 | 59 | var out []*HealthCheck 60 | if err := decodeBody(resp, &out); err != nil { 61 | return nil, nil, err 62 | } 63 | return out, qm, nil 64 | } 65 | 66 | // Checks is used to return the checks associated with a service 67 | func (h *Health) Checks(service string, q *QueryOptions) ([]*HealthCheck, *QueryMeta, error) { 68 | r := h.c.newRequest("GET", "/v1/health/checks/"+service) 69 | r.setQueryOptions(q) 70 | rtt, resp, err := requireOK(h.c.doRequest(r)) 71 | if err != nil { 72 | return nil, nil, err 73 | } 74 | defer resp.Body.Close() 75 | 76 | qm := &QueryMeta{} 77 | parseQueryMeta(resp, qm) 78 | qm.RequestTime = rtt 79 | 80 | var out []*HealthCheck 81 | if err := decodeBody(resp, &out); err != nil { 82 | return nil, nil, err 83 | } 84 | return out, qm, nil 85 | } 86 | 87 | // Service is used to query health information along with service info 88 | // for a given service. It can optionally do server-side filtering on a tag 89 | // or nodes with passing health checks only. 90 | func (h *Health) Service(service, tag string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) { 91 | r := h.c.newRequest("GET", "/v1/health/service/"+service) 92 | r.setQueryOptions(q) 93 | if tag != "" { 94 | r.params.Set("tag", tag) 95 | } 96 | if passingOnly { 97 | r.params.Set(HealthPassing, "1") 98 | } 99 | rtt, resp, err := requireOK(h.c.doRequest(r)) 100 | if err != nil { 101 | return nil, nil, err 102 | } 103 | defer resp.Body.Close() 104 | 105 | qm := &QueryMeta{} 106 | parseQueryMeta(resp, qm) 107 | qm.RequestTime = rtt 108 | 109 | var out []*ServiceEntry 110 | if err := decodeBody(resp, &out); err != nil { 111 | return nil, nil, err 112 | } 113 | return out, qm, nil 114 | } 115 | 116 | // State is used to retrieve all the checks in a given state. 117 | // The wildcard "any" state can also be used for all checks. 118 | func (h *Health) State(state string, q *QueryOptions) ([]*HealthCheck, *QueryMeta, error) { 119 | switch state { 120 | case HealthAny: 121 | case HealthWarning: 122 | case HealthCritical: 123 | case HealthPassing: 124 | default: 125 | return nil, nil, fmt.Errorf("Unsupported state: %v", state) 126 | } 127 | r := h.c.newRequest("GET", "/v1/health/state/"+state) 128 | r.setQueryOptions(q) 129 | rtt, resp, err := requireOK(h.c.doRequest(r)) 130 | if err != nil { 131 | return nil, nil, err 132 | } 133 | defer resp.Body.Close() 134 | 135 | qm := &QueryMeta{} 136 | parseQueryMeta(resp, qm) 137 | qm.RequestTime = rtt 138 | 139 | var out []*HealthCheck 140 | if err := decodeBody(resp, &out); err != nil { 141 | return nil, nil, err 142 | } 143 | return out, qm, nil 144 | } 145 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/context.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "strings" 7 | ) 8 | 9 | // Context is a type that is passed through to 10 | // each Handler action in a cli application. Context 11 | // can be used to retrieve context-specific args and 12 | // parsed command-line options. 13 | type Context struct { 14 | App *App 15 | Command *Command 16 | 17 | flagSet *flag.FlagSet 18 | parentContext *Context 19 | } 20 | 21 | // NewContext creates a new context. For use in when invoking an App or Command action. 22 | func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { 23 | return &Context{App: app, flagSet: set, parentContext: parentCtx} 24 | } 25 | 26 | // NumFlags returns the number of flags set 27 | func (c *Context) NumFlags() int { 28 | return c.flagSet.NFlag() 29 | } 30 | 31 | // Set sets a context flag to a value. 32 | func (c *Context) Set(name, value string) error { 33 | return c.flagSet.Set(name, value) 34 | } 35 | 36 | // IsSet determines if the flag was actually set 37 | func (c *Context) IsSet(name string) bool { 38 | if fs := lookupFlagSet(name, c); fs != nil { 39 | isSet := false 40 | fs.Visit(func(f *flag.Flag) { 41 | if f.Name == name { 42 | isSet = true 43 | } 44 | }) 45 | return isSet 46 | } 47 | return false 48 | } 49 | 50 | // LocalFlagNames returns a slice of flag names used in this context. 51 | func (c *Context) LocalFlagNames() []string { 52 | names := []string{} 53 | c.flagSet.Visit(makeFlagNameVisitor(&names)) 54 | return names 55 | } 56 | 57 | // FlagNames returns a slice of flag names used by the this context and all of 58 | // its parent contexts. 59 | func (c *Context) FlagNames() []string { 60 | names := []string{} 61 | for _, ctx := range c.Lineage() { 62 | ctx.flagSet.Visit(makeFlagNameVisitor(&names)) 63 | } 64 | return names 65 | } 66 | 67 | // Lineage returns *this* context and all of its ancestor contexts in order from 68 | // child to parent 69 | func (c *Context) Lineage() []*Context { 70 | lineage := []*Context{} 71 | 72 | for cur := c; cur != nil; cur = cur.parentContext { 73 | lineage = append(lineage, cur) 74 | } 75 | 76 | return lineage 77 | } 78 | 79 | // Args returns the command line arguments associated with the context. 80 | func (c *Context) Args() Args { 81 | ret := args(c.flagSet.Args()) 82 | return &ret 83 | } 84 | 85 | // NArg returns the number of the command line arguments. 86 | func (c *Context) NArg() int { 87 | return c.Args().Len() 88 | } 89 | 90 | func lookupFlagSet(name string, ctx *Context) *flag.FlagSet { 91 | for _, c := range ctx.Lineage() { 92 | if f := c.flagSet.Lookup(name); f != nil { 93 | return c.flagSet 94 | } 95 | } 96 | 97 | return nil 98 | } 99 | 100 | func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { 101 | switch ff.Value.(type) { 102 | case Serializeder: 103 | set.Set(name, ff.Value.(Serializeder).Serialized()) 104 | default: 105 | set.Set(name, ff.Value.String()) 106 | } 107 | } 108 | 109 | func normalizeFlags(flags []Flag, set *flag.FlagSet) error { 110 | visited := make(map[string]bool) 111 | set.Visit(func(f *flag.Flag) { 112 | visited[f.Name] = true 113 | }) 114 | for _, f := range flags { 115 | parts := f.Names() 116 | if len(parts) == 1 { 117 | continue 118 | } 119 | var ff *flag.Flag 120 | for _, name := range parts { 121 | name = strings.Trim(name, " ") 122 | if visited[name] { 123 | if ff != nil { 124 | return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) 125 | } 126 | ff = set.Lookup(name) 127 | } 128 | } 129 | if ff == nil { 130 | continue 131 | } 132 | for _, name := range parts { 133 | name = strings.Trim(name, " ") 134 | if !visited[name] { 135 | copyFlag(name, ff, set) 136 | } 137 | } 138 | } 139 | return nil 140 | } 141 | 142 | func makeFlagNameVisitor(names *[]string) func(*flag.Flag) { 143 | return func(f *flag.Flag) { 144 | nameParts := strings.Split(f.Name, ",") 145 | name := strings.TrimSpace(nameParts[0]) 146 | 147 | for _, part := range nameParts { 148 | part = strings.TrimSpace(part) 149 | if len(part) > len(name) { 150 | name = part 151 | } 152 | } 153 | 154 | if name != "" { 155 | (*names) = append(*names, name) 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /run.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/list" 5 | "fmt" 6 | 7 | "os" 8 | 9 | "github.com/grubernaut/gdsh/dsh" 10 | consul "github.com/hashicorp/consul/api" 11 | "gopkg.in/urfave/cli.v2" 12 | ) 13 | 14 | func run(c *cli.Context) error { 15 | // If a service isn't requested, exit 16 | if c.NArg() < 1 { 17 | fmt.Printf("Error: Remote command not specified\n") 18 | return cli.ShowAppHelp(c) 19 | } 20 | 21 | // Create ExecOpts 22 | opts := defaultDSHConfig() 23 | // Set opts.Verbose output 24 | opts.Verbose = false 25 | if c.Bool("verbose") { 26 | fmt.Printf("Verbose flag on\n") 27 | opts.Verbose = true 28 | } 29 | 30 | // Find Consul server, env-var takes priority 31 | consulServer := c.String("server") 32 | if os.Getenv("CONSUL_SERVER") != "" { 33 | consulServer = os.Getenv("CONSUL_SERVER") 34 | } 35 | // Can't be empty, we need servers 36 | if consulServer == "" { 37 | fmt.Printf("Error: consul-server not supplied\n") 38 | return cli.ShowAppHelp(c) 39 | } 40 | 41 | // Create a consul catalog client 42 | catalog, err := consulCatalog(consulServer) 43 | if err != nil { 44 | return cli.Exit(fmt.Sprintf( 45 | "Error creating consul agent: %s\n", err, 46 | ), 1) 47 | } 48 | 49 | // Parse requested service, if empty return a list of available services 50 | service := c.String("service") 51 | if service == "" { 52 | fmt.Printf("No service specified. Available services:\n") 53 | avail, err := consulServices(catalog) 54 | if err != nil { 55 | return cli.Exit(fmt.Sprintf( 56 | "Error querying Consul services: %s\n", err, 57 | ), 1) 58 | } 59 | for k := range avail { 60 | fmt.Printf("%s\n", k) 61 | } 62 | return nil 63 | } 64 | 65 | // Add consul services to linked list 66 | machineList, err := populateList(catalog, service, c.String("user")) 67 | if err != nil { 68 | return cli.Exit(fmt.Sprintf( 69 | "Error populating DSH machine list: %s\n", err, 70 | ), 1) 71 | } 72 | opts.MachineList = machineList 73 | 74 | // Set remote commands to all trailing args 75 | for _, v := range c.Args().Slice() { 76 | // Initialize remote command 77 | if opts.RemoteCommand == "" && v != "" { 78 | opts.RemoteCommand = v 79 | continue 80 | } 81 | opts.RemoteCommand = fmt.Sprintf("%s %s", opts.RemoteCommand, v) 82 | } 83 | 84 | if machineList.Len() < 1 { 85 | return cli.Exit(fmt.Sprintf( 86 | "No servers found for service %s", service), 1) 87 | } 88 | 89 | // Execute DSH! 90 | if err := opts.Execute(); err != nil { 91 | return cli.Exit(fmt.Sprintf("Error executing: %s", err), 1) 92 | } 93 | return nil 94 | } 95 | 96 | // Default GDSH config 97 | // TODO: Make these configurable 98 | func defaultDSHConfig() dsh.ExecOpts { 99 | opts := dsh.ExecOpts{ 100 | ConcurrentShell: true, 101 | RemoteShell: "ssh", 102 | ShowNames: true, 103 | } 104 | return opts 105 | } 106 | 107 | // Returns all available consul services 108 | func consulServices(catalog *consul.Catalog) (map[string][]string, error) { 109 | services, _, err := catalog.Services(nil) 110 | if err != nil { 111 | return nil, err 112 | } 113 | return services, nil 114 | } 115 | 116 | // Returns a Consul Client 117 | func consulCatalog(server string) (*consul.Catalog, error) { 118 | // Create Consul Client 119 | config := consul.DefaultConfig() 120 | config.Address = server 121 | client, err := consul.NewClient(config) 122 | if err != nil { 123 | return nil, err 124 | } 125 | return client.Catalog(), nil 126 | } 127 | 128 | // Populates doubly linked machine list, with a list of requested consul services's addresses 129 | func populateList(catalog *consul.Catalog, service string, user string) (*list.List, error) { 130 | services, _, err := catalog.Service(service, "", nil) 131 | if err != nil { 132 | return nil, fmt.Errorf("Error querying consul services: %s", err) 133 | } 134 | 135 | serviceList := list.New() 136 | for _, v := range services { 137 | remoteAddr := v.Address 138 | if user != "" { 139 | remoteAddr = fmt.Sprintf("%s@%s", user, remoteAddr) 140 | } 141 | addList(serviceList, remoteAddr) 142 | } 143 | 144 | return serviceList, nil 145 | } 146 | 147 | // Populates linked list with a supplied string element, ensuring no duplicates or nil values are stored 148 | func addList(llist *list.List, elem string) { 149 | if elem == "" { 150 | return 151 | } 152 | if llist.Len() == 0 { 153 | llist.PushFront(elem) 154 | return 155 | } 156 | // Verify no items match currently 157 | for e := llist.Front(); e != nil; e = e.Next() { 158 | if e.Value == elem { 159 | return 160 | } 161 | } 162 | llist.PushBack(elem) 163 | } 164 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/runtests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | import argparse 5 | import glob 6 | import os 7 | import platform 8 | import shutil 9 | import sys 10 | import tempfile 11 | 12 | from subprocess import check_call, check_output 13 | 14 | 15 | _WINDOWS = platform.system().lower() == 'windows' 16 | _PACKAGE_NAME = os.environ.get( 17 | 'CLI_PACKAGE_NAME', 'github.com/urfave/cli' 18 | ) 19 | _TARGETS = {} 20 | 21 | 22 | def main(sysargs=sys.argv[:]): 23 | parser = argparse.ArgumentParser() 24 | parser.add_argument( 25 | 'target', nargs='?', choices=tuple(_TARGETS.keys()), default='test' 26 | ) 27 | args = parser.parse_args(sysargs[1:]) 28 | 29 | _TARGETS[args.target]() 30 | return 0 31 | 32 | 33 | def _target(func): 34 | _TARGETS[func.__name__.strip('_')] = func 35 | return func 36 | 37 | 38 | @_target 39 | def _test(): 40 | if check_output('go version'.split()).split()[2] < 'go1.2': 41 | _run('go test -v .') 42 | return 43 | 44 | coverprofiles = [] 45 | for subpackage in ['', 'altsrc']: 46 | coverprofile = 'cli.coverprofile' 47 | if subpackage != '': 48 | coverprofile = '{}.coverprofile'.format(subpackage) 49 | 50 | coverprofiles.append(coverprofile) 51 | 52 | _run('go test -v'.split() + [ 53 | '-coverprofile={}'.format(coverprofile), 54 | ('{}/{}'.format(_PACKAGE_NAME, subpackage)).rstrip('/') 55 | ]) 56 | 57 | combined_name = _combine_coverprofiles(coverprofiles) 58 | _run('go tool cover -func={}'.format(combined_name)) 59 | os.remove(combined_name) 60 | 61 | 62 | @_target 63 | def _gfmrun(): 64 | go_version = check_output('go version'.split()).split()[2] 65 | if go_version < 'go1.3': 66 | print('runtests: skip on {}'.format(go_version), file=sys.stderr) 67 | return 68 | _run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md']) 69 | 70 | 71 | @_target 72 | def _vet(): 73 | _run('go vet ./...') 74 | 75 | 76 | @_target 77 | def _migrations(): 78 | go_version = check_output('go version'.split()).split()[2] 79 | if go_version < 'go1.3': 80 | print('runtests: skip on {}'.format(go_version), file=sys.stderr) 81 | return 82 | 83 | migration_script = os.path.abspath( 84 | os.environ.get('V1TOV2', './cli-v1-to-v2') 85 | ) 86 | v1_readme_url = os.environ.get( 87 | 'V1README', 88 | 'https://raw.githubusercontent.com/urfave/cli/v1/README.md' 89 | ) 90 | 91 | tmpdir = tempfile.mkdtemp() 92 | try: 93 | os.chdir(tmpdir) 94 | _run('curl -sSL -o README.md {}'.format(v1_readme_url).split()) 95 | _run('gfmrun extract -o .'.split()) 96 | 97 | for gofile in glob.glob('*.go'): 98 | for i in (0, 1): 99 | _run(['python', migration_script, '-w', gofile]) 100 | _run('go build -o tmp.out {}'.format(gofile).split()) 101 | finally: 102 | if os.environ.get('NOCLEAN', '') == '': 103 | shutil.rmtree(tmpdir, ignore_errors=True) 104 | 105 | 106 | @_target 107 | def _toc(): 108 | exe = ['bash'] if _WINDOWS else [] 109 | _run(exe + [ 110 | os.path.join('node_modules', '.bin', 'markdown-toc'), 111 | '-i', 'README.md' 112 | ]) 113 | _run('git diff --exit-code') 114 | 115 | 116 | @_target 117 | def _gen(): 118 | go_version = check_output('go version'.split()).split()[2] 119 | if go_version < 'go1.5': 120 | print('runtests: skip on {}'.format(go_version), file=sys.stderr) 121 | return 122 | 123 | _run('go generate ./...') 124 | _run('git diff --exit-code') 125 | 126 | 127 | def _run(command): 128 | if hasattr(command, 'split'): 129 | command = command.split() 130 | print('runtests: {}'.format(' '.join(command)), file=sys.stderr) 131 | sys.stderr.flush() 132 | check_call(command) 133 | 134 | 135 | def _gfmrun_count(): 136 | with open('README.md') as infile: 137 | lines = infile.read().splitlines() 138 | return len(filter(_is_go_runnable, lines)) 139 | 140 | 141 | def _is_go_runnable(line): 142 | return line.startswith('package main') 143 | 144 | 145 | def _combine_coverprofiles(coverprofiles): 146 | combined = tempfile.NamedTemporaryFile( 147 | suffix='.coverprofile', delete=False 148 | ) 149 | combined.write('mode: set\n') 150 | 151 | for coverprofile in coverprofiles: 152 | with open(coverprofile, 'r') as infile: 153 | for line in infile.readlines(): 154 | if not line.startswith('mode: '): 155 | combined.write(line) 156 | 157 | combined.flush() 158 | name = combined.name 159 | combined.close() 160 | return name 161 | 162 | 163 | if __name__ == '__main__': 164 | sys.exit(main()) 165 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/catalog.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | type Node struct { 4 | Node string 5 | Address string 6 | TaggedAddresses map[string]string 7 | } 8 | 9 | type CatalogService struct { 10 | Node string 11 | Address string 12 | TaggedAddresses map[string]string 13 | ServiceID string 14 | ServiceName string 15 | ServiceAddress string 16 | ServiceTags []string 17 | ServicePort int 18 | ServiceEnableTagOverride bool 19 | } 20 | 21 | type CatalogNode struct { 22 | Node *Node 23 | Services map[string]*AgentService 24 | } 25 | 26 | type CatalogRegistration struct { 27 | Node string 28 | Address string 29 | TaggedAddresses map[string]string 30 | Datacenter string 31 | Service *AgentService 32 | Check *AgentCheck 33 | } 34 | 35 | type CatalogDeregistration struct { 36 | Node string 37 | Address string 38 | Datacenter string 39 | ServiceID string 40 | CheckID string 41 | } 42 | 43 | // Catalog can be used to query the Catalog endpoints 44 | type Catalog struct { 45 | c *Client 46 | } 47 | 48 | // Catalog returns a handle to the catalog endpoints 49 | func (c *Client) Catalog() *Catalog { 50 | return &Catalog{c} 51 | } 52 | 53 | func (c *Catalog) Register(reg *CatalogRegistration, q *WriteOptions) (*WriteMeta, error) { 54 | r := c.c.newRequest("PUT", "/v1/catalog/register") 55 | r.setWriteOptions(q) 56 | r.obj = reg 57 | rtt, resp, err := requireOK(c.c.doRequest(r)) 58 | if err != nil { 59 | return nil, err 60 | } 61 | resp.Body.Close() 62 | 63 | wm := &WriteMeta{} 64 | wm.RequestTime = rtt 65 | 66 | return wm, nil 67 | } 68 | 69 | func (c *Catalog) Deregister(dereg *CatalogDeregistration, q *WriteOptions) (*WriteMeta, error) { 70 | r := c.c.newRequest("PUT", "/v1/catalog/deregister") 71 | r.setWriteOptions(q) 72 | r.obj = dereg 73 | rtt, resp, err := requireOK(c.c.doRequest(r)) 74 | if err != nil { 75 | return nil, err 76 | } 77 | resp.Body.Close() 78 | 79 | wm := &WriteMeta{} 80 | wm.RequestTime = rtt 81 | 82 | return wm, nil 83 | } 84 | 85 | // Datacenters is used to query for all the known datacenters 86 | func (c *Catalog) Datacenters() ([]string, error) { 87 | r := c.c.newRequest("GET", "/v1/catalog/datacenters") 88 | _, resp, err := requireOK(c.c.doRequest(r)) 89 | if err != nil { 90 | return nil, err 91 | } 92 | defer resp.Body.Close() 93 | 94 | var out []string 95 | if err := decodeBody(resp, &out); err != nil { 96 | return nil, err 97 | } 98 | return out, nil 99 | } 100 | 101 | // Nodes is used to query all the known nodes 102 | func (c *Catalog) Nodes(q *QueryOptions) ([]*Node, *QueryMeta, error) { 103 | r := c.c.newRequest("GET", "/v1/catalog/nodes") 104 | r.setQueryOptions(q) 105 | rtt, resp, err := requireOK(c.c.doRequest(r)) 106 | if err != nil { 107 | return nil, nil, err 108 | } 109 | defer resp.Body.Close() 110 | 111 | qm := &QueryMeta{} 112 | parseQueryMeta(resp, qm) 113 | qm.RequestTime = rtt 114 | 115 | var out []*Node 116 | if err := decodeBody(resp, &out); err != nil { 117 | return nil, nil, err 118 | } 119 | return out, qm, nil 120 | } 121 | 122 | // Services is used to query for all known services 123 | func (c *Catalog) Services(q *QueryOptions) (map[string][]string, *QueryMeta, error) { 124 | r := c.c.newRequest("GET", "/v1/catalog/services") 125 | r.setQueryOptions(q) 126 | rtt, resp, err := requireOK(c.c.doRequest(r)) 127 | if err != nil { 128 | return nil, nil, err 129 | } 130 | defer resp.Body.Close() 131 | 132 | qm := &QueryMeta{} 133 | parseQueryMeta(resp, qm) 134 | qm.RequestTime = rtt 135 | 136 | var out map[string][]string 137 | if err := decodeBody(resp, &out); err != nil { 138 | return nil, nil, err 139 | } 140 | return out, qm, nil 141 | } 142 | 143 | // Service is used to query catalog entries for a given service 144 | func (c *Catalog) Service(service, tag string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) { 145 | r := c.c.newRequest("GET", "/v1/catalog/service/"+service) 146 | r.setQueryOptions(q) 147 | if tag != "" { 148 | r.params.Set("tag", tag) 149 | } 150 | rtt, resp, err := requireOK(c.c.doRequest(r)) 151 | if err != nil { 152 | return nil, nil, err 153 | } 154 | defer resp.Body.Close() 155 | 156 | qm := &QueryMeta{} 157 | parseQueryMeta(resp, qm) 158 | qm.RequestTime = rtt 159 | 160 | var out []*CatalogService 161 | if err := decodeBody(resp, &out); err != nil { 162 | return nil, nil, err 163 | } 164 | return out, qm, nil 165 | } 166 | 167 | // Node is used to query for service information about a single node 168 | func (c *Catalog) Node(node string, q *QueryOptions) (*CatalogNode, *QueryMeta, error) { 169 | r := c.c.newRequest("GET", "/v1/catalog/node/"+node) 170 | r.setQueryOptions(q) 171 | rtt, resp, err := requireOK(c.c.doRequest(r)) 172 | if err != nil { 173 | return nil, nil, err 174 | } 175 | defer resp.Body.Close() 176 | 177 | qm := &QueryMeta{} 178 | parseQueryMeta(resp, qm) 179 | qm.RequestTime = rtt 180 | 181 | var out *CatalogNode 182 | if err := decodeBody(resp, &out); err != nil { 183 | return nil, nil, err 184 | } 185 | return out, qm, nil 186 | } 187 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/session.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | const ( 10 | // SessionBehaviorRelease is the default behavior and causes 11 | // all associated locks to be released on session invalidation. 12 | SessionBehaviorRelease = "release" 13 | 14 | // SessionBehaviorDelete is new in Consul 0.5 and changes the 15 | // behavior to delete all associated locks on session invalidation. 16 | // It can be used in a way similar to Ephemeral Nodes in ZooKeeper. 17 | SessionBehaviorDelete = "delete" 18 | ) 19 | 20 | var ErrSessionExpired = errors.New("session expired") 21 | 22 | // SessionEntry represents a session in consul 23 | type SessionEntry struct { 24 | CreateIndex uint64 25 | ID string 26 | Name string 27 | Node string 28 | Checks []string 29 | LockDelay time.Duration 30 | Behavior string 31 | TTL string 32 | } 33 | 34 | // Session can be used to query the Session endpoints 35 | type Session struct { 36 | c *Client 37 | } 38 | 39 | // Session returns a handle to the session endpoints 40 | func (c *Client) Session() *Session { 41 | return &Session{c} 42 | } 43 | 44 | // CreateNoChecks is like Create but is used specifically to create 45 | // a session with no associated health checks. 46 | func (s *Session) CreateNoChecks(se *SessionEntry, q *WriteOptions) (string, *WriteMeta, error) { 47 | body := make(map[string]interface{}) 48 | body["Checks"] = []string{} 49 | if se != nil { 50 | if se.Name != "" { 51 | body["Name"] = se.Name 52 | } 53 | if se.Node != "" { 54 | body["Node"] = se.Node 55 | } 56 | if se.LockDelay != 0 { 57 | body["LockDelay"] = durToMsec(se.LockDelay) 58 | } 59 | if se.Behavior != "" { 60 | body["Behavior"] = se.Behavior 61 | } 62 | if se.TTL != "" { 63 | body["TTL"] = se.TTL 64 | } 65 | } 66 | return s.create(body, q) 67 | 68 | } 69 | 70 | // Create makes a new session. Providing a session entry can 71 | // customize the session. It can also be nil to use defaults. 72 | func (s *Session) Create(se *SessionEntry, q *WriteOptions) (string, *WriteMeta, error) { 73 | var obj interface{} 74 | if se != nil { 75 | body := make(map[string]interface{}) 76 | obj = body 77 | if se.Name != "" { 78 | body["Name"] = se.Name 79 | } 80 | if se.Node != "" { 81 | body["Node"] = se.Node 82 | } 83 | if se.LockDelay != 0 { 84 | body["LockDelay"] = durToMsec(se.LockDelay) 85 | } 86 | if len(se.Checks) > 0 { 87 | body["Checks"] = se.Checks 88 | } 89 | if se.Behavior != "" { 90 | body["Behavior"] = se.Behavior 91 | } 92 | if se.TTL != "" { 93 | body["TTL"] = se.TTL 94 | } 95 | } 96 | return s.create(obj, q) 97 | } 98 | 99 | func (s *Session) create(obj interface{}, q *WriteOptions) (string, *WriteMeta, error) { 100 | var out struct{ ID string } 101 | wm, err := s.c.write("/v1/session/create", obj, &out, q) 102 | if err != nil { 103 | return "", nil, err 104 | } 105 | return out.ID, wm, nil 106 | } 107 | 108 | // Destroy invalidates a given session 109 | func (s *Session) Destroy(id string, q *WriteOptions) (*WriteMeta, error) { 110 | wm, err := s.c.write("/v1/session/destroy/"+id, nil, nil, q) 111 | if err != nil { 112 | return nil, err 113 | } 114 | return wm, nil 115 | } 116 | 117 | // Renew renews the TTL on a given session 118 | func (s *Session) Renew(id string, q *WriteOptions) (*SessionEntry, *WriteMeta, error) { 119 | r := s.c.newRequest("PUT", "/v1/session/renew/"+id) 120 | r.setWriteOptions(q) 121 | rtt, resp, err := s.c.doRequest(r) 122 | if err != nil { 123 | return nil, nil, err 124 | } 125 | defer resp.Body.Close() 126 | 127 | wm := &WriteMeta{RequestTime: rtt} 128 | 129 | if resp.StatusCode == 404 { 130 | return nil, wm, nil 131 | } else if resp.StatusCode != 200 { 132 | return nil, nil, fmt.Errorf("Unexpected response code: %d", resp.StatusCode) 133 | } 134 | 135 | var entries []*SessionEntry 136 | if err := decodeBody(resp, &entries); err != nil { 137 | return nil, nil, fmt.Errorf("Failed to read response: %v", err) 138 | } 139 | if len(entries) > 0 { 140 | return entries[0], wm, nil 141 | } 142 | return nil, wm, nil 143 | } 144 | 145 | // RenewPeriodic is used to periodically invoke Session.Renew on a 146 | // session until a doneCh is closed. This is meant to be used in a long running 147 | // goroutine to ensure a session stays valid. 148 | func (s *Session) RenewPeriodic(initialTTL string, id string, q *WriteOptions, doneCh chan struct{}) error { 149 | ttl, err := time.ParseDuration(initialTTL) 150 | if err != nil { 151 | return err 152 | } 153 | 154 | waitDur := ttl / 2 155 | lastRenewTime := time.Now() 156 | var lastErr error 157 | for { 158 | if time.Since(lastRenewTime) > ttl { 159 | return lastErr 160 | } 161 | select { 162 | case <-time.After(waitDur): 163 | entry, _, err := s.Renew(id, q) 164 | if err != nil { 165 | waitDur = time.Second 166 | lastErr = err 167 | continue 168 | } 169 | if entry == nil { 170 | return ErrSessionExpired 171 | } 172 | 173 | // Handle the server updating the TTL 174 | ttl, _ = time.ParseDuration(entry.TTL) 175 | waitDur = ttl / 2 176 | lastRenewTime = time.Now() 177 | 178 | case <-doneCh: 179 | // Attempt a session destroy 180 | s.Destroy(id, q) 181 | return nil 182 | } 183 | } 184 | } 185 | 186 | // Info looks up a single session 187 | func (s *Session) Info(id string, q *QueryOptions) (*SessionEntry, *QueryMeta, error) { 188 | var entries []*SessionEntry 189 | qm, err := s.c.query("/v1/session/info/"+id, &entries, q) 190 | if err != nil { 191 | return nil, nil, err 192 | } 193 | if len(entries) > 0 { 194 | return entries[0], qm, nil 195 | } 196 | return nil, qm, nil 197 | } 198 | 199 | // List gets sessions for a node 200 | func (s *Session) Node(node string, q *QueryOptions) ([]*SessionEntry, *QueryMeta, error) { 201 | var entries []*SessionEntry 202 | qm, err := s.c.query("/v1/session/node/"+node, &entries, q) 203 | if err != nil { 204 | return nil, nil, err 205 | } 206 | return entries, qm, nil 207 | } 208 | 209 | // List gets all active sessions 210 | func (s *Session) List(q *QueryOptions) ([]*SessionEntry, *QueryMeta, error) { 211 | var entries []*SessionEntry 212 | qm, err := s.c.query("/v1/session/list", &entries, q) 213 | if err != nil { 214 | return nil, nil, err 215 | } 216 | return entries, qm, nil 217 | } 218 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/serf/coordinate/phantom.go: -------------------------------------------------------------------------------- 1 | package coordinate 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "math/rand" 7 | "time" 8 | ) 9 | 10 | // GenerateClients returns a slice with nodes number of clients, all with the 11 | // given config. 12 | func GenerateClients(nodes int, config *Config) ([]*Client, error) { 13 | clients := make([]*Client, nodes) 14 | for i, _ := range clients { 15 | client, err := NewClient(config) 16 | if err != nil { 17 | return nil, err 18 | } 19 | 20 | clients[i] = client 21 | } 22 | return clients, nil 23 | } 24 | 25 | // GenerateLine returns a truth matrix as if all the nodes are in a straight linke 26 | // with the given spacing between them. 27 | func GenerateLine(nodes int, spacing time.Duration) [][]time.Duration { 28 | truth := make([][]time.Duration, nodes) 29 | for i := range truth { 30 | truth[i] = make([]time.Duration, nodes) 31 | } 32 | 33 | for i := 0; i < nodes; i++ { 34 | for j := i + 1; j < nodes; j++ { 35 | rtt := time.Duration(j-i) * spacing 36 | truth[i][j], truth[j][i] = rtt, rtt 37 | } 38 | } 39 | return truth 40 | } 41 | 42 | // GenerateGrid returns a truth matrix as if all the nodes are in a two dimensional 43 | // grid with the given spacing between them. 44 | func GenerateGrid(nodes int, spacing time.Duration) [][]time.Duration { 45 | truth := make([][]time.Duration, nodes) 46 | for i := range truth { 47 | truth[i] = make([]time.Duration, nodes) 48 | } 49 | 50 | n := int(math.Sqrt(float64(nodes))) 51 | for i := 0; i < nodes; i++ { 52 | for j := i + 1; j < nodes; j++ { 53 | x1, y1 := float64(i%n), float64(i/n) 54 | x2, y2 := float64(j%n), float64(j/n) 55 | dx, dy := x2-x1, y2-y1 56 | dist := math.Sqrt(dx*dx + dy*dy) 57 | rtt := time.Duration(dist * float64(spacing)) 58 | truth[i][j], truth[j][i] = rtt, rtt 59 | } 60 | } 61 | return truth 62 | } 63 | 64 | // GenerateSplit returns a truth matrix as if half the nodes are close together in 65 | // one location and half the nodes are close together in another. The lan factor 66 | // is used to separate the nodes locally and the wan factor represents the split 67 | // between the two sides. 68 | func GenerateSplit(nodes int, lan time.Duration, wan time.Duration) [][]time.Duration { 69 | truth := make([][]time.Duration, nodes) 70 | for i := range truth { 71 | truth[i] = make([]time.Duration, nodes) 72 | } 73 | 74 | split := nodes / 2 75 | for i := 0; i < nodes; i++ { 76 | for j := i + 1; j < nodes; j++ { 77 | rtt := lan 78 | if (i <= split && j > split) || (i > split && j <= split) { 79 | rtt += wan 80 | } 81 | truth[i][j], truth[j][i] = rtt, rtt 82 | } 83 | } 84 | return truth 85 | } 86 | 87 | // GenerateCircle returns a truth matrix for a set of nodes, evenly distributed 88 | // around a circle with the given radius. The first node is at the "center" of the 89 | // circle because it's equidistant from all the other nodes, but we place it at 90 | // double the radius, so it should show up above all the other nodes in height. 91 | func GenerateCircle(nodes int, radius time.Duration) [][]time.Duration { 92 | truth := make([][]time.Duration, nodes) 93 | for i := range truth { 94 | truth[i] = make([]time.Duration, nodes) 95 | } 96 | 97 | for i := 0; i < nodes; i++ { 98 | for j := i + 1; j < nodes; j++ { 99 | var rtt time.Duration 100 | if i == 0 { 101 | rtt = 2 * radius 102 | } else { 103 | t1 := 2.0 * math.Pi * float64(i) / float64(nodes) 104 | x1, y1 := math.Cos(t1), math.Sin(t1) 105 | t2 := 2.0 * math.Pi * float64(j) / float64(nodes) 106 | x2, y2 := math.Cos(t2), math.Sin(t2) 107 | dx, dy := x2-x1, y2-y1 108 | dist := math.Sqrt(dx*dx + dy*dy) 109 | rtt = time.Duration(dist * float64(radius)) 110 | } 111 | truth[i][j], truth[j][i] = rtt, rtt 112 | } 113 | } 114 | return truth 115 | } 116 | 117 | // GenerateRandom returns a truth matrix for a set of nodes with normally 118 | // distributed delays, with the given mean and deviation. The RNG is re-seeded 119 | // so you always get the same matrix for a given size. 120 | func GenerateRandom(nodes int, mean time.Duration, deviation time.Duration) [][]time.Duration { 121 | rand.Seed(1) 122 | 123 | truth := make([][]time.Duration, nodes) 124 | for i := range truth { 125 | truth[i] = make([]time.Duration, nodes) 126 | } 127 | 128 | for i := 0; i < nodes; i++ { 129 | for j := i + 1; j < nodes; j++ { 130 | rttSeconds := rand.NormFloat64()*deviation.Seconds() + mean.Seconds() 131 | rtt := time.Duration(rttSeconds * secondsToNanoseconds) 132 | truth[i][j], truth[j][i] = rtt, rtt 133 | } 134 | } 135 | return truth 136 | } 137 | 138 | // Simulate runs the given number of cycles using the given list of clients and 139 | // truth matrix. On each cycle, each client will pick a random node and observe 140 | // the truth RTT, updating its coordinate estimate. The RNG is re-seeded for 141 | // each simulation run to get deterministic results (for this algorithm and the 142 | // underlying algorithm which will use random numbers for position vectors when 143 | // starting out with everything at the origin). 144 | func Simulate(clients []*Client, truth [][]time.Duration, cycles int) { 145 | rand.Seed(1) 146 | 147 | nodes := len(clients) 148 | for cycle := 0; cycle < cycles; cycle++ { 149 | for i, _ := range clients { 150 | if j := rand.Intn(nodes); j != i { 151 | c := clients[j].GetCoordinate() 152 | rtt := truth[i][j] 153 | node := fmt.Sprintf("node_%d", j) 154 | clients[i].Update(node, c, rtt) 155 | } 156 | } 157 | } 158 | } 159 | 160 | // Stats is returned from the Evaluate function with a summary of the algorithm 161 | // performance. 162 | type Stats struct { 163 | ErrorMax float64 164 | ErrorAvg float64 165 | } 166 | 167 | // Evaluate uses the coordinates of the given clients to calculate estimated 168 | // distances and compares them with the given truth matrix, returning summary 169 | // stats. 170 | func Evaluate(clients []*Client, truth [][]time.Duration) (stats Stats) { 171 | nodes := len(clients) 172 | count := 0 173 | for i := 0; i < nodes; i++ { 174 | for j := i + 1; j < nodes; j++ { 175 | est := clients[i].DistanceTo(clients[j].GetCoordinate()).Seconds() 176 | actual := truth[i][j].Seconds() 177 | error := math.Abs(est-actual) / actual 178 | stats.ErrorMax = math.Max(stats.ErrorMax, error) 179 | stats.ErrorAvg += error 180 | count += 1 181 | } 182 | } 183 | 184 | stats.ErrorAvg /= float64(count) 185 | fmt.Printf("Error avg=%9.6f max=%9.6f\n", stats.ErrorAvg, stats.ErrorMax) 186 | return 187 | } 188 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/serf/coordinate/client.go: -------------------------------------------------------------------------------- 1 | package coordinate 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "sort" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | // Client manages the estimated network coordinate for a given node, and adjusts 12 | // it as the node observes round trip times and estimated coordinates from other 13 | // nodes. The core algorithm is based on Vivaldi, see the documentation for Config 14 | // for more details. 15 | type Client struct { 16 | // coord is the current estimate of the client's network coordinate. 17 | coord *Coordinate 18 | 19 | // origin is a coordinate sitting at the origin. 20 | origin *Coordinate 21 | 22 | // config contains the tuning parameters that govern the performance of 23 | // the algorithm. 24 | config *Config 25 | 26 | // adjustmentIndex is the current index into the adjustmentSamples slice. 27 | adjustmentIndex uint 28 | 29 | // adjustment is used to store samples for the adjustment calculation. 30 | adjustmentSamples []float64 31 | 32 | // latencyFilterSamples is used to store the last several RTT samples, 33 | // keyed by node name. We will use the config's LatencyFilterSamples 34 | // value to determine how many samples we keep, per node. 35 | latencyFilterSamples map[string][]float64 36 | 37 | // mutex enables safe concurrent access to the client. 38 | mutex sync.RWMutex 39 | } 40 | 41 | // NewClient creates a new Client and verifies the configuration is valid. 42 | func NewClient(config *Config) (*Client, error) { 43 | if !(config.Dimensionality > 0) { 44 | return nil, fmt.Errorf("dimensionality must be >0") 45 | } 46 | 47 | return &Client{ 48 | coord: NewCoordinate(config), 49 | origin: NewCoordinate(config), 50 | config: config, 51 | adjustmentIndex: 0, 52 | adjustmentSamples: make([]float64, config.AdjustmentWindowSize), 53 | latencyFilterSamples: make(map[string][]float64), 54 | }, nil 55 | } 56 | 57 | // GetCoordinate returns a copy of the coordinate for this client. 58 | func (c *Client) GetCoordinate() *Coordinate { 59 | c.mutex.RLock() 60 | defer c.mutex.RUnlock() 61 | 62 | return c.coord.Clone() 63 | } 64 | 65 | // SetCoordinate forces the client's coordinate to a known state. 66 | func (c *Client) SetCoordinate(coord *Coordinate) { 67 | c.mutex.Lock() 68 | defer c.mutex.Unlock() 69 | 70 | c.coord = coord.Clone() 71 | } 72 | 73 | // ForgetNode removes any client state for the given node. 74 | func (c *Client) ForgetNode(node string) { 75 | c.mutex.Lock() 76 | defer c.mutex.Unlock() 77 | 78 | delete(c.latencyFilterSamples, node) 79 | } 80 | 81 | // latencyFilter applies a simple moving median filter with a new sample for 82 | // a node. This assumes that the mutex has been locked already. 83 | func (c *Client) latencyFilter(node string, rttSeconds float64) float64 { 84 | samples, ok := c.latencyFilterSamples[node] 85 | if !ok { 86 | samples = make([]float64, 0, c.config.LatencyFilterSize) 87 | } 88 | 89 | // Add the new sample and trim the list, if needed. 90 | samples = append(samples, rttSeconds) 91 | if len(samples) > int(c.config.LatencyFilterSize) { 92 | samples = samples[1:] 93 | } 94 | c.latencyFilterSamples[node] = samples 95 | 96 | // Sort a copy of the samples and return the median. 97 | sorted := make([]float64, len(samples)) 98 | copy(sorted, samples) 99 | sort.Float64s(sorted) 100 | return sorted[len(sorted)/2] 101 | } 102 | 103 | // updateVivialdi updates the Vivaldi portion of the client's coordinate. This 104 | // assumes that the mutex has been locked already. 105 | func (c *Client) updateVivaldi(other *Coordinate, rttSeconds float64) { 106 | const zeroThreshold = 1.0e-6 107 | 108 | dist := c.coord.DistanceTo(other).Seconds() 109 | if rttSeconds < zeroThreshold { 110 | rttSeconds = zeroThreshold 111 | } 112 | wrongness := math.Abs(dist-rttSeconds) / rttSeconds 113 | 114 | totalError := c.coord.Error + other.Error 115 | if totalError < zeroThreshold { 116 | totalError = zeroThreshold 117 | } 118 | weight := c.coord.Error / totalError 119 | 120 | c.coord.Error = c.config.VivaldiCE*weight*wrongness + c.coord.Error*(1.0-c.config.VivaldiCE*weight) 121 | if c.coord.Error > c.config.VivaldiErrorMax { 122 | c.coord.Error = c.config.VivaldiErrorMax 123 | } 124 | 125 | delta := c.config.VivaldiCC * weight 126 | force := delta * (rttSeconds - dist) 127 | c.coord = c.coord.ApplyForce(c.config, force, other) 128 | } 129 | 130 | // updateAdjustment updates the adjustment portion of the client's coordinate, if 131 | // the feature is enabled. This assumes that the mutex has been locked already. 132 | func (c *Client) updateAdjustment(other *Coordinate, rttSeconds float64) { 133 | if c.config.AdjustmentWindowSize == 0 { 134 | return 135 | } 136 | 137 | // Note that the existing adjustment factors don't figure in to this 138 | // calculation so we use the raw distance here. 139 | dist := c.coord.rawDistanceTo(other) 140 | c.adjustmentSamples[c.adjustmentIndex] = rttSeconds - dist 141 | c.adjustmentIndex = (c.adjustmentIndex + 1) % c.config.AdjustmentWindowSize 142 | 143 | sum := 0.0 144 | for _, sample := range c.adjustmentSamples { 145 | sum += sample 146 | } 147 | c.coord.Adjustment = sum / (2.0 * float64(c.config.AdjustmentWindowSize)) 148 | } 149 | 150 | // updateGravity applies a small amount of gravity to pull coordinates towards 151 | // the center of the coordinate system to combat drift. This assumes that the 152 | // mutex is locked already. 153 | func (c *Client) updateGravity() { 154 | dist := c.origin.DistanceTo(c.coord).Seconds() 155 | force := -1.0 * math.Pow(dist/c.config.GravityRho, 2.0) 156 | c.coord = c.coord.ApplyForce(c.config, force, c.origin) 157 | } 158 | 159 | // Update takes other, a coordinate for another node, and rtt, a round trip 160 | // time observation for a ping to that node, and updates the estimated position of 161 | // the client's coordinate. Returns the updated coordinate. 162 | func (c *Client) Update(node string, other *Coordinate, rtt time.Duration) *Coordinate { 163 | c.mutex.Lock() 164 | defer c.mutex.Unlock() 165 | 166 | rttSeconds := c.latencyFilter(node, rtt.Seconds()) 167 | c.updateVivaldi(other, rttSeconds) 168 | c.updateAdjustment(other, rttSeconds) 169 | c.updateGravity() 170 | return c.coord.Clone() 171 | } 172 | 173 | // DistanceTo returns the estimated RTT from the client's coordinate to other, the 174 | // coordinate for another node. 175 | func (c *Client) DistanceTo(other *Coordinate) time.Duration { 176 | c.mutex.RLock() 177 | defer c.mutex.RUnlock() 178 | 179 | return c.coord.DistanceTo(other) 180 | } 181 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/serf/coordinate/coordinate.go: -------------------------------------------------------------------------------- 1 | package coordinate 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | // Coordinate is a specialized structure for holding network coordinates for the 10 | // Vivaldi-based coordinate mapping algorithm. All of the fields should be public 11 | // to enable this to be serialized. All values in here are in units of seconds. 12 | type Coordinate struct { 13 | // Vec is the Euclidean portion of the coordinate. This is used along 14 | // with the other fields to provide an overall distance estimate. The 15 | // units here are seconds. 16 | Vec []float64 17 | 18 | // Err reflects the confidence in the given coordinate and is updated 19 | // dynamically by the Vivaldi Client. This is dimensionless. 20 | Error float64 21 | 22 | // Adjustment is a distance offset computed based on a calculation over 23 | // observations from all other nodes over a fixed window and is updated 24 | // dynamically by the Vivaldi Client. The units here are seconds. 25 | Adjustment float64 26 | 27 | // Height is a distance offset that accounts for non-Euclidean effects 28 | // which model the access links from nodes to the core Internet. The access 29 | // links are usually set by bandwidth and congestion, and the core links 30 | // usually follow distance based on geography. 31 | Height float64 32 | } 33 | 34 | const ( 35 | // secondsToNanoseconds is used to convert float seconds to nanoseconds. 36 | secondsToNanoseconds = 1.0e9 37 | 38 | // zeroThreshold is used to decide if two coordinates are on top of each 39 | // other. 40 | zeroThreshold = 1.0e-6 41 | ) 42 | 43 | // ErrDimensionalityConflict will be panic-d if you try to perform operations 44 | // with incompatible dimensions. 45 | type DimensionalityConflictError struct{} 46 | 47 | // Adds the error interface. 48 | func (e DimensionalityConflictError) Error() string { 49 | return "coordinate dimensionality does not match" 50 | } 51 | 52 | // NewCoordinate creates a new coordinate at the origin, using the given config 53 | // to supply key initial values. 54 | func NewCoordinate(config *Config) *Coordinate { 55 | return &Coordinate{ 56 | Vec: make([]float64, config.Dimensionality), 57 | Error: config.VivaldiErrorMax, 58 | Adjustment: 0.0, 59 | Height: config.HeightMin, 60 | } 61 | } 62 | 63 | // Clone creates an independent copy of this coordinate. 64 | func (c *Coordinate) Clone() *Coordinate { 65 | vec := make([]float64, len(c.Vec)) 66 | copy(vec, c.Vec) 67 | return &Coordinate{ 68 | Vec: vec, 69 | Error: c.Error, 70 | Adjustment: c.Adjustment, 71 | Height: c.Height, 72 | } 73 | } 74 | 75 | // IsCompatibleWith checks to see if the two coordinates are compatible 76 | // dimensionally. If this returns true then you are guaranteed to not get 77 | // any runtime errors operating on them. 78 | func (c *Coordinate) IsCompatibleWith(other *Coordinate) bool { 79 | return len(c.Vec) == len(other.Vec) 80 | } 81 | 82 | // ApplyForce returns the result of applying the force from the direction of the 83 | // other coordinate. 84 | func (c *Coordinate) ApplyForce(config *Config, force float64, other *Coordinate) *Coordinate { 85 | if !c.IsCompatibleWith(other) { 86 | panic(DimensionalityConflictError{}) 87 | } 88 | 89 | ret := c.Clone() 90 | unit, mag := unitVectorAt(c.Vec, other.Vec) 91 | ret.Vec = add(ret.Vec, mul(unit, force)) 92 | if mag > zeroThreshold { 93 | ret.Height = (ret.Height+other.Height)*force/mag + ret.Height 94 | ret.Height = math.Max(ret.Height, config.HeightMin) 95 | } 96 | return ret 97 | } 98 | 99 | // DistanceTo returns the distance between this coordinate and the other 100 | // coordinate, including adjustments. 101 | func (c *Coordinate) DistanceTo(other *Coordinate) time.Duration { 102 | if !c.IsCompatibleWith(other) { 103 | panic(DimensionalityConflictError{}) 104 | } 105 | 106 | dist := c.rawDistanceTo(other) 107 | adjustedDist := dist + c.Adjustment + other.Adjustment 108 | if adjustedDist > 0.0 { 109 | dist = adjustedDist 110 | } 111 | return time.Duration(dist * secondsToNanoseconds) 112 | } 113 | 114 | // rawDistanceTo returns the Vivaldi distance between this coordinate and the 115 | // other coordinate in seconds, not including adjustments. This assumes the 116 | // dimensions have already been checked to be compatible. 117 | func (c *Coordinate) rawDistanceTo(other *Coordinate) float64 { 118 | return magnitude(diff(c.Vec, other.Vec)) + c.Height + other.Height 119 | } 120 | 121 | // add returns the sum of vec1 and vec2. This assumes the dimensions have 122 | // already been checked to be compatible. 123 | func add(vec1 []float64, vec2 []float64) []float64 { 124 | ret := make([]float64, len(vec1)) 125 | for i, _ := range ret { 126 | ret[i] = vec1[i] + vec2[i] 127 | } 128 | return ret 129 | } 130 | 131 | // diff returns the difference between the vec1 and vec2. This assumes the 132 | // dimensions have already been checked to be compatible. 133 | func diff(vec1 []float64, vec2 []float64) []float64 { 134 | ret := make([]float64, len(vec1)) 135 | for i, _ := range ret { 136 | ret[i] = vec1[i] - vec2[i] 137 | } 138 | return ret 139 | } 140 | 141 | // mul returns vec multiplied by a scalar factor. 142 | func mul(vec []float64, factor float64) []float64 { 143 | ret := make([]float64, len(vec)) 144 | for i, _ := range vec { 145 | ret[i] = vec[i] * factor 146 | } 147 | return ret 148 | } 149 | 150 | // magnitude computes the magnitude of the vec. 151 | func magnitude(vec []float64) float64 { 152 | sum := 0.0 153 | for i, _ := range vec { 154 | sum += vec[i] * vec[i] 155 | } 156 | return math.Sqrt(sum) 157 | } 158 | 159 | // unitVectorAt returns a unit vector pointing at vec1 from vec2. If the two 160 | // positions are the same then a random unit vector is returned. We also return 161 | // the distance between the points for use in the later height calculation. 162 | func unitVectorAt(vec1 []float64, vec2 []float64) ([]float64, float64) { 163 | ret := diff(vec1, vec2) 164 | 165 | // If the coordinates aren't on top of each other we can normalize. 166 | if mag := magnitude(ret); mag > zeroThreshold { 167 | return mul(ret, 1.0/mag), mag 168 | } 169 | 170 | // Otherwise, just return a random unit vector. 171 | for i, _ := range ret { 172 | ret[i] = rand.Float64() - 0.5 173 | } 174 | if mag := magnitude(ret); mag > zeroThreshold { 175 | return mul(ret, 1.0/mag), 0.0 176 | } 177 | 178 | // And finally just give up and make a unit vector along the first 179 | // dimension. This should be exceedingly rare. 180 | ret = make([]float64, len(ret)) 181 | ret[0] = 1.0 182 | return ret, 0.0 183 | } 184 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/command.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "sort" 7 | "strings" 8 | ) 9 | 10 | // Command is a subcommand for a cli.App. 11 | type Command struct { 12 | // The name of the command 13 | Name string 14 | // A list of aliases for the command 15 | Aliases []string 16 | // A short description of the usage of this command 17 | Usage string 18 | // Custom text to show on USAGE section of help 19 | UsageText string 20 | // A longer explanation of how the command works 21 | Description string 22 | // A short description of the arguments of this command 23 | ArgsUsage string 24 | // The category the command is part of 25 | Category string 26 | // The function to call when checking for bash command completions 27 | BashComplete BashCompleteFunc 28 | // An action to execute before any sub-subcommands are run, but after the context is ready 29 | // If a non-nil error is returned, no sub-subcommands are run 30 | Before BeforeFunc 31 | // An action to execute after any subcommands are run, but after the subcommand has finished 32 | // It is run even if Action() panics 33 | After AfterFunc 34 | // The function to call when this command is invoked 35 | Action ActionFunc 36 | // Execute this function if a usage error occurs. 37 | OnUsageError OnUsageErrorFunc 38 | // List of child commands 39 | Subcommands []*Command 40 | // List of flags to parse 41 | Flags []Flag 42 | // Treat all flags as normal arguments if true 43 | SkipFlagParsing bool 44 | // Boolean to hide built-in help command 45 | HideHelp bool 46 | // Boolean to hide this command from help or completion 47 | Hidden bool 48 | 49 | // Full name of command for help, defaults to full command name, including parent commands. 50 | HelpName string 51 | commandNamePath []string 52 | } 53 | 54 | // FullName returns the full name of the command. 55 | // For subcommands this ensures that parent commands are part of the command path 56 | func (c *Command) FullName() string { 57 | if c.commandNamePath == nil { 58 | return c.Name 59 | } 60 | return strings.Join(c.commandNamePath, " ") 61 | } 62 | 63 | // Run invokes the command given the context, parses ctx.Args() to generate command-specific flags 64 | func (c *Command) Run(ctx *Context) (err error) { 65 | if len(c.Subcommands) > 0 { 66 | return c.startApp(ctx) 67 | } 68 | 69 | if !c.HideHelp && HelpFlag != nil { 70 | // append help to flags 71 | c.appendFlag(HelpFlag) 72 | } 73 | 74 | if ctx.App.EnableBashCompletion { 75 | c.appendFlag(BashCompletionFlag) 76 | } 77 | 78 | set := flagSet(c.Name, c.Flags) 79 | set.SetOutput(ioutil.Discard) 80 | 81 | if c.SkipFlagParsing { 82 | err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) 83 | } else { 84 | err = set.Parse(ctx.Args().Tail()) 85 | } 86 | 87 | if err != nil { 88 | if c.OnUsageError != nil { 89 | err := c.OnUsageError(ctx, err, false) 90 | HandleExitCoder(err) 91 | return err 92 | } 93 | fmt.Fprintf(ctx.App.Writer, "Incorrect Usage: %s\n\n", err) 94 | fmt.Fprintln(ctx.App.Writer) 95 | ShowCommandHelp(ctx, c.Name) 96 | return err 97 | } 98 | 99 | nerr := normalizeFlags(c.Flags, set) 100 | if nerr != nil { 101 | fmt.Fprintln(ctx.App.Writer, nerr) 102 | fmt.Fprintln(ctx.App.Writer) 103 | ShowCommandHelp(ctx, c.Name) 104 | return nerr 105 | } 106 | 107 | context := NewContext(ctx.App, set, ctx) 108 | 109 | if checkCommandCompletions(context, c.Name) { 110 | return nil 111 | } 112 | 113 | if checkCommandHelp(context, c.Name) { 114 | return nil 115 | } 116 | 117 | if c.After != nil { 118 | defer func() { 119 | afterErr := c.After(context) 120 | if afterErr != nil { 121 | HandleExitCoder(err) 122 | if err != nil { 123 | err = newMultiError(err, afterErr) 124 | } else { 125 | err = afterErr 126 | } 127 | } 128 | }() 129 | } 130 | 131 | if c.Before != nil { 132 | err = c.Before(context) 133 | if err != nil { 134 | fmt.Fprintln(ctx.App.Writer, err) 135 | fmt.Fprintln(ctx.App.Writer) 136 | ShowCommandHelp(ctx, c.Name) 137 | HandleExitCoder(err) 138 | return err 139 | } 140 | } 141 | 142 | context.Command = c 143 | err = c.Action(context) 144 | 145 | if err != nil { 146 | HandleExitCoder(err) 147 | } 148 | return err 149 | } 150 | 151 | // Names returns the names including short names and aliases. 152 | func (c *Command) Names() []string { 153 | return append([]string{c.Name}, c.Aliases...) 154 | } 155 | 156 | // HasName returns true if Command.Name matches given name 157 | func (c *Command) HasName(name string) bool { 158 | for _, n := range c.Names() { 159 | if n == name { 160 | return true 161 | } 162 | } 163 | return false 164 | } 165 | 166 | func (c *Command) startApp(ctx *Context) error { 167 | app := &App{ 168 | Metadata: ctx.App.Metadata, 169 | Name: fmt.Sprintf("%s %s", ctx.App.Name, c.Name), 170 | } 171 | 172 | if c.HelpName == "" { 173 | app.HelpName = c.HelpName 174 | } else { 175 | app.HelpName = app.Name 176 | } 177 | 178 | if c.Description != "" { 179 | app.Usage = c.Description 180 | } else { 181 | app.Usage = c.Usage 182 | } 183 | 184 | // set CommandNotFound 185 | app.CommandNotFound = ctx.App.CommandNotFound 186 | 187 | // set the flags and commands 188 | app.Commands = c.Subcommands 189 | app.Flags = c.Flags 190 | app.HideHelp = c.HideHelp 191 | 192 | app.Version = ctx.App.Version 193 | app.HideVersion = ctx.App.HideVersion 194 | app.Compiled = ctx.App.Compiled 195 | app.Writer = ctx.App.Writer 196 | 197 | app.Categories = newCommandCategories() 198 | for _, command := range c.Subcommands { 199 | app.Categories.AddCommand(command.Category, command) 200 | } 201 | 202 | sort.Sort(app.Categories.(*commandCategories)) 203 | 204 | // bash completion 205 | app.EnableBashCompletion = ctx.App.EnableBashCompletion 206 | if c.BashComplete != nil { 207 | app.BashComplete = c.BashComplete 208 | } 209 | 210 | // set the actions 211 | app.Before = c.Before 212 | app.After = c.After 213 | if c.Action != nil { 214 | app.Action = c.Action 215 | } else { 216 | app.Action = helpSubcommand.Action 217 | } 218 | 219 | for index, cc := range app.Commands { 220 | app.Commands[index].commandNamePath = []string{c.Name, cc.Name} 221 | } 222 | 223 | return app.RunAsSubcommand(ctx) 224 | } 225 | 226 | // VisibleFlags returns a slice of the Flags with Hidden=false 227 | func (c *Command) VisibleFlags() []Flag { 228 | return visibleFlags(c.Flags) 229 | } 230 | 231 | func (c *Command) appendFlag(fl Flag) { 232 | if !hasFlag(c.Flags, fl) { 233 | c.Flags = append(c.Flags, fl) 234 | } 235 | } 236 | 237 | func hasCommand(commands []*Command, command *Command) bool { 238 | for _, existing := range commands { 239 | if command == existing { 240 | return true 241 | } 242 | } 243 | 244 | return false 245 | } 246 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/prepared_query.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | // QueryDatacenterOptions sets options about how we fail over if there are no 4 | // healthy nodes in the local datacenter. 5 | type QueryDatacenterOptions struct { 6 | // NearestN is set to the number of remote datacenters to try, based on 7 | // network coordinates. 8 | NearestN int 9 | 10 | // Datacenters is a fixed list of datacenters to try after NearestN. We 11 | // never try a datacenter multiple times, so those are subtracted from 12 | // this list before proceeding. 13 | Datacenters []string 14 | } 15 | 16 | // QueryDNSOptions controls settings when query results are served over DNS. 17 | type QueryDNSOptions struct { 18 | // TTL is the time to live for the served DNS results. 19 | TTL string 20 | } 21 | 22 | // ServiceQuery is used to query for a set of healthy nodes offering a specific 23 | // service. 24 | type ServiceQuery struct { 25 | // Service is the service to query. 26 | Service string 27 | 28 | // Near allows baking in the name of a node to automatically distance- 29 | // sort from. The magic "_agent" value is supported, which sorts near 30 | // the agent which initiated the request by default. 31 | Near string 32 | 33 | // Failover controls what we do if there are no healthy nodes in the 34 | // local datacenter. 35 | Failover QueryDatacenterOptions 36 | 37 | // If OnlyPassing is true then we will only include nodes with passing 38 | // health checks (critical AND warning checks will cause a node to be 39 | // discarded) 40 | OnlyPassing bool 41 | 42 | // Tags are a set of required and/or disallowed tags. If a tag is in 43 | // this list it must be present. If the tag is preceded with "!" then 44 | // it is disallowed. 45 | Tags []string 46 | } 47 | 48 | // QueryTemplate carries the arguments for creating a templated query. 49 | type QueryTemplate struct { 50 | // Type specifies the type of the query template. Currently only 51 | // "name_prefix_match" is supported. This field is required. 52 | Type string 53 | 54 | // Regexp allows specifying a regex pattern to match against the name 55 | // of the query being executed. 56 | Regexp string 57 | } 58 | 59 | // PrepatedQueryDefinition defines a complete prepared query. 60 | type PreparedQueryDefinition struct { 61 | // ID is this UUID-based ID for the query, always generated by Consul. 62 | ID string 63 | 64 | // Name is an optional friendly name for the query supplied by the 65 | // user. NOTE - if this feature is used then it will reduce the security 66 | // of any read ACL associated with this query/service since this name 67 | // can be used to locate nodes with supplying any ACL. 68 | Name string 69 | 70 | // Session is an optional session to tie this query's lifetime to. If 71 | // this is omitted then the query will not expire. 72 | Session string 73 | 74 | // Token is the ACL token used when the query was created, and it is 75 | // used when a query is subsequently executed. This token, or a token 76 | // with management privileges, must be used to change the query later. 77 | Token string 78 | 79 | // Service defines a service query (leaving things open for other types 80 | // later). 81 | Service ServiceQuery 82 | 83 | // DNS has options that control how the results of this query are 84 | // served over DNS. 85 | DNS QueryDNSOptions 86 | 87 | // Template is used to pass through the arguments for creating a 88 | // prepared query with an attached template. If a template is given, 89 | // interpolations are possible in other struct fields. 90 | Template QueryTemplate 91 | } 92 | 93 | // PreparedQueryExecuteResponse has the results of executing a query. 94 | type PreparedQueryExecuteResponse struct { 95 | // Service is the service that was queried. 96 | Service string 97 | 98 | // Nodes has the nodes that were output by the query. 99 | Nodes []ServiceEntry 100 | 101 | // DNS has the options for serving these results over DNS. 102 | DNS QueryDNSOptions 103 | 104 | // Datacenter is the datacenter that these results came from. 105 | Datacenter string 106 | 107 | // Failovers is a count of how many times we had to query a remote 108 | // datacenter. 109 | Failovers int 110 | } 111 | 112 | // PreparedQuery can be used to query the prepared query endpoints. 113 | type PreparedQuery struct { 114 | c *Client 115 | } 116 | 117 | // PreparedQuery returns a handle to the prepared query endpoints. 118 | func (c *Client) PreparedQuery() *PreparedQuery { 119 | return &PreparedQuery{c} 120 | } 121 | 122 | // Create makes a new prepared query. The ID of the new query is returned. 123 | func (c *PreparedQuery) Create(query *PreparedQueryDefinition, q *WriteOptions) (string, *WriteMeta, error) { 124 | r := c.c.newRequest("POST", "/v1/query") 125 | r.setWriteOptions(q) 126 | r.obj = query 127 | rtt, resp, err := requireOK(c.c.doRequest(r)) 128 | if err != nil { 129 | return "", nil, err 130 | } 131 | defer resp.Body.Close() 132 | 133 | wm := &WriteMeta{} 134 | wm.RequestTime = rtt 135 | 136 | var out struct{ ID string } 137 | if err := decodeBody(resp, &out); err != nil { 138 | return "", nil, err 139 | } 140 | return out.ID, wm, nil 141 | } 142 | 143 | // Update makes updates to an existing prepared query. 144 | func (c *PreparedQuery) Update(query *PreparedQueryDefinition, q *WriteOptions) (*WriteMeta, error) { 145 | return c.c.write("/v1/query/"+query.ID, query, nil, q) 146 | } 147 | 148 | // List is used to fetch all the prepared queries (always requires a management 149 | // token). 150 | func (c *PreparedQuery) List(q *QueryOptions) ([]*PreparedQueryDefinition, *QueryMeta, error) { 151 | var out []*PreparedQueryDefinition 152 | qm, err := c.c.query("/v1/query", &out, q) 153 | if err != nil { 154 | return nil, nil, err 155 | } 156 | return out, qm, nil 157 | } 158 | 159 | // Get is used to fetch a specific prepared query. 160 | func (c *PreparedQuery) Get(queryID string, q *QueryOptions) ([]*PreparedQueryDefinition, *QueryMeta, error) { 161 | var out []*PreparedQueryDefinition 162 | qm, err := c.c.query("/v1/query/"+queryID, &out, q) 163 | if err != nil { 164 | return nil, nil, err 165 | } 166 | return out, qm, nil 167 | } 168 | 169 | // Delete is used to delete a specific prepared query. 170 | func (c *PreparedQuery) Delete(queryID string, q *QueryOptions) (*QueryMeta, error) { 171 | r := c.c.newRequest("DELETE", "/v1/query/"+queryID) 172 | r.setQueryOptions(q) 173 | rtt, resp, err := requireOK(c.c.doRequest(r)) 174 | if err != nil { 175 | return nil, err 176 | } 177 | defer resp.Body.Close() 178 | 179 | qm := &QueryMeta{} 180 | parseQueryMeta(resp, qm) 181 | qm.RequestTime = rtt 182 | return qm, nil 183 | } 184 | 185 | // Execute is used to execute a specific prepared query. You can execute using 186 | // a query ID or name. 187 | func (c *PreparedQuery) Execute(queryIDOrName string, q *QueryOptions) (*PreparedQueryExecuteResponse, *QueryMeta, error) { 188 | var out *PreparedQueryExecuteResponse 189 | qm, err := c.c.query("/v1/query/"+queryIDOrName+"/execute", &out, q) 190 | if err != nil { 191 | return nil, nil, err 192 | } 193 | return out, qm, nil 194 | } 195 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/help.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "strings" 8 | "text/tabwriter" 9 | "text/template" 10 | ) 11 | 12 | // AppHelpTemplate is the text template for the Default help topic. 13 | // cli.go uses text/template to render templates. You can 14 | // render custom help text by setting this variable. 15 | var AppHelpTemplate = `NAME: 16 | {{.Name}} - {{.Usage}} 17 | 18 | USAGE: 19 | {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} 20 | {{if .Version}}{{if not .HideVersion}} 21 | VERSION: 22 | {{.Version}} 23 | {{end}}{{end}}{{if len .Authors}} 24 | AUTHOR(S): 25 | {{range .Authors}}{{.}}{{end}} 26 | {{end}}{{if .VisibleCommands}} 27 | COMMANDS:{{range .VisibleCategories}}{{if .Name}} 28 | {{.Name}}:{{end}}{{range .VisibleCommands}} 29 | {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}} 30 | {{end}}{{end}}{{if .VisibleFlags}} 31 | GLOBAL OPTIONS: 32 | {{range .VisibleFlags}}{{.}} 33 | {{end}}{{end}}{{if .Copyright}} 34 | COPYRIGHT: 35 | {{.Copyright}} 36 | {{end}} 37 | ` 38 | 39 | // CommandHelpTemplate is the text template for the command help topic. 40 | // cli.go uses text/template to render templates. You can 41 | // render custom help text by setting this variable. 42 | var CommandHelpTemplate = `NAME: 43 | {{.HelpName}} - {{.Usage}} 44 | 45 | USAGE: 46 | {{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Category}} 47 | 48 | CATEGORY: 49 | {{.Category}}{{end}}{{if .Description}} 50 | 51 | DESCRIPTION: 52 | {{.Description}}{{end}}{{if .VisibleFlags}} 53 | 54 | OPTIONS: 55 | {{range .VisibleFlags}}{{.}} 56 | {{end}}{{end}} 57 | ` 58 | 59 | // SubcommandHelpTemplate is the text template for the subcommand help topic. 60 | // cli.go uses text/template to render templates. You can 61 | // render custom help text by setting this variable. 62 | var SubcommandHelpTemplate = `NAME: 63 | {{.HelpName}} - {{.Usage}} 64 | 65 | USAGE: 66 | {{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} 67 | 68 | COMMANDS:{{range .VisibleCategories}}{{if .Name}} 69 | {{.Name}}:{{end}}{{range .VisibleCommands}} 70 | {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}} 71 | {{end}}{{if .VisibleFlags}} 72 | OPTIONS: 73 | {{range .VisibleFlags}}{{.}} 74 | {{end}}{{end}} 75 | ` 76 | 77 | var helpCommand = &Command{ 78 | Name: "help", 79 | Aliases: []string{"h"}, 80 | Usage: "Shows a list of commands or help for one command", 81 | ArgsUsage: "[command]", 82 | Action: func(c *Context) error { 83 | args := c.Args() 84 | if args.Present() { 85 | return ShowCommandHelp(c, args.First()) 86 | } 87 | 88 | ShowAppHelp(c) 89 | return nil 90 | }, 91 | } 92 | 93 | var helpSubcommand = &Command{ 94 | Name: "help", 95 | Aliases: []string{"h"}, 96 | Usage: "Shows a list of commands or help for one command", 97 | ArgsUsage: "[command]", 98 | Action: func(c *Context) error { 99 | args := c.Args() 100 | if args.Present() { 101 | return ShowCommandHelp(c, args.First()) 102 | } 103 | 104 | return ShowSubcommandHelp(c) 105 | }, 106 | } 107 | 108 | // Prints help for the App or Command 109 | type helpPrinter func(w io.Writer, templ string, data interface{}) 110 | 111 | // HelpPrinter is a function that writes the help output. If not set a default 112 | // is used. The function signature is: 113 | // func(w io.Writer, templ string, data interface{}) 114 | var HelpPrinter helpPrinter = printHelp 115 | 116 | // VersionPrinter prints the version for the App 117 | var VersionPrinter = printVersion 118 | 119 | // ShowAppHelp is an action that displays the help. 120 | func ShowAppHelp(c *Context) error { 121 | HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) 122 | return nil 123 | } 124 | 125 | // DefaultAppComplete prints the list of subcommands as the default app completion method 126 | func DefaultAppComplete(c *Context) { 127 | for _, command := range c.App.Commands { 128 | if command.Hidden { 129 | continue 130 | } 131 | for _, name := range command.Names() { 132 | fmt.Fprintln(c.App.Writer, name) 133 | } 134 | } 135 | } 136 | 137 | // ShowCommandHelp prints help for the given command 138 | func ShowCommandHelp(ctx *Context, command string) error { 139 | // show the subcommand help for a command with subcommands 140 | if command == "" { 141 | HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App) 142 | return nil 143 | } 144 | 145 | for _, c := range ctx.App.Commands { 146 | if c.HasName(command) { 147 | HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) 148 | return nil 149 | } 150 | } 151 | 152 | if ctx.App.CommandNotFound == nil { 153 | return Exit(fmt.Sprintf("No help topic for '%v'", command), 3) 154 | } 155 | 156 | ctx.App.CommandNotFound(ctx, command) 157 | return nil 158 | } 159 | 160 | // ShowSubcommandHelp prints help for the given subcommand 161 | func ShowSubcommandHelp(c *Context) error { 162 | if c == nil { 163 | return nil 164 | } 165 | 166 | if c.Command != nil { 167 | return ShowCommandHelp(c, c.Command.Name) 168 | } 169 | 170 | return ShowCommandHelp(c, "") 171 | } 172 | 173 | // ShowVersion prints the version number of the App 174 | func ShowVersion(c *Context) { 175 | VersionPrinter(c) 176 | } 177 | 178 | func printVersion(c *Context) { 179 | fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) 180 | } 181 | 182 | // ShowCompletions prints the lists of commands within a given context 183 | func ShowCompletions(c *Context) { 184 | a := c.App 185 | if a != nil && a.BashComplete != nil { 186 | a.BashComplete(c) 187 | } 188 | } 189 | 190 | // ShowCommandCompletions prints the custom completions for a given command 191 | func ShowCommandCompletions(ctx *Context, command string) { 192 | c := ctx.App.Command(command) 193 | if c != nil && c.BashComplete != nil { 194 | c.BashComplete(ctx) 195 | } 196 | } 197 | 198 | func printHelp(out io.Writer, templ string, data interface{}) { 199 | funcMap := template.FuncMap{ 200 | "join": strings.Join, 201 | } 202 | 203 | w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) 204 | t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) 205 | 206 | errDebug := os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" 207 | 208 | defer func() { 209 | if r := recover(); r != nil { 210 | if errDebug { 211 | fmt.Fprintf(ErrWriter, "CLI TEMPLATE PANIC: %#v\n", r) 212 | } 213 | if os.Getenv("CLI_TEMPLATE_REPANIC") != "" { 214 | panic(r) 215 | } 216 | } 217 | }() 218 | 219 | err := t.Execute(w, data) 220 | if err != nil { 221 | if errDebug { 222 | fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err) 223 | } 224 | return 225 | } 226 | 227 | w.Flush() 228 | } 229 | 230 | func checkVersion(c *Context) bool { 231 | found := false 232 | if VersionFlag.Name != "" { 233 | for _, name := range VersionFlag.Names() { 234 | if c.Bool(name) { 235 | found = true 236 | } 237 | } 238 | } 239 | return found 240 | } 241 | 242 | func checkHelp(c *Context) bool { 243 | found := false 244 | if HelpFlag.Name != "" { 245 | for _, name := range HelpFlag.Names() { 246 | if c.Bool(name) { 247 | found = true 248 | } 249 | } 250 | } 251 | return found 252 | } 253 | 254 | func checkCommandHelp(c *Context, name string) bool { 255 | if c.Bool("h") || c.Bool("help") { 256 | ShowCommandHelp(c, name) 257 | return true 258 | } 259 | 260 | return false 261 | } 262 | 263 | func checkSubcommandHelp(c *Context) bool { 264 | if c.Bool("h") || c.Bool("help") { 265 | ShowSubcommandHelp(c) 266 | return true 267 | } 268 | 269 | return false 270 | } 271 | 272 | func checkCompletions(c *Context) bool { 273 | if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { 274 | ShowCompletions(c) 275 | return true 276 | } 277 | 278 | return false 279 | } 280 | 281 | func checkCommandCompletions(c *Context, name string) bool { 282 | if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { 283 | ShowCommandCompletions(c, name) 284 | return true 285 | } 286 | 287 | return false 288 | } 289 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/generate-flag-types: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | The flag types that ship with the cli library have many things in common, and 4 | so we can take advantage of the `go generate` command to create much of the 5 | source code from a list of definitions. These definitions attempt to cover 6 | the parts that vary between flag types, and should evolve as needed. 7 | 8 | An example of the minimum definition needed is: 9 | 10 | { 11 | "name": "SomeType", 12 | "type": "sometype", 13 | "context_default": "nil" 14 | } 15 | 16 | In this example, the code generated for the `cli` package will include a type 17 | named `SomeTypeFlag` that is expected to wrap a value of type `sometype`. 18 | Fetching values by name via `*cli.Context` will default to a value of `nil`. 19 | 20 | A more complete, albeit somewhat redundant, example showing all available 21 | definition keys is: 22 | 23 | { 24 | "name": "VeryMuchType", 25 | "type": "*VeryMuchType", 26 | "value": true, 27 | "dest": false, 28 | "doctail": " which really only wraps a []float64, oh well!", 29 | "context_type": "[]float64", 30 | "context_default": "nil", 31 | "parser": "parseVeryMuchType(f.Value.String())", 32 | "parser_cast": "[]float64(parsed)" 33 | } 34 | 35 | The meaning of each field is as follows: 36 | 37 | name (string) - The type "name", which will be suffixed with 38 | `Flag` when generating the type definition 39 | for `cli` and the wrapper type for `altsrc` 40 | type (string) - The type that the generated `Flag` type for 41 | `cli` is expected to "contain" as its `.Value` 42 | member 43 | value (bool) - Should the generated `cli` type have a `Value` 44 | member? 45 | dest (bool) - Should the generated `cli` type support a 46 | destination pointer? 47 | doctail (string) - Additional docs for the `cli` flag type comment 48 | context_type (string) - The literal type used in the `*cli.Context` 49 | reader func signature 50 | context_default (string) - The literal value used as the default by the 51 | `*cli.Context` reader funcs when no value is 52 | present 53 | parser (string) - Literal code used to parse the flag `f`, 54 | expected to have a return signature of 55 | (value, error) 56 | parser_cast (string) - Literal code used to cast the `parsed` value 57 | returned from the `parser` code 58 | """ 59 | 60 | from __future__ import print_function, unicode_literals 61 | 62 | import argparse 63 | import json 64 | import os 65 | import subprocess 66 | import sys 67 | import tempfile 68 | import textwrap 69 | 70 | 71 | class _FancyFormatter(argparse.ArgumentDefaultsHelpFormatter, 72 | argparse.RawDescriptionHelpFormatter): 73 | pass 74 | 75 | 76 | def main(sysargs=sys.argv[:]): 77 | parser = argparse.ArgumentParser( 78 | description='Generate flag type code!', 79 | formatter_class=_FancyFormatter) 80 | parser.add_argument( 81 | 'package', 82 | type=str, default='cli', choices=_WRITEFUNCS.keys(), 83 | help='Package for which flag types will be generated' 84 | ) 85 | parser.add_argument( 86 | '-i', '--in-json', 87 | type=argparse.FileType('r'), 88 | default=sys.stdin, 89 | help='Input JSON file which defines each type to be generated' 90 | ) 91 | parser.add_argument( 92 | '-o', '--out-go', 93 | type=argparse.FileType('w'), 94 | default=sys.stdout, 95 | help='Output file/stream to which generated source will be written' 96 | ) 97 | parser.epilog = __doc__ 98 | 99 | args = parser.parse_args(sysargs[1:]) 100 | _generate_flag_types(_WRITEFUNCS[args.package], args.out_go, args.in_json) 101 | return 0 102 | 103 | 104 | def _generate_flag_types(writefunc, output_go, input_json): 105 | types = json.load(input_json) 106 | 107 | tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False) 108 | writefunc(tmp, types) 109 | tmp.close() 110 | 111 | new_content = subprocess.check_output( 112 | ['goimports', tmp.name] 113 | ).decode('utf-8') 114 | 115 | print(new_content, file=output_go, end='') 116 | output_go.flush() 117 | os.remove(tmp.name) 118 | 119 | 120 | def _set_typedef_defaults(typedef): 121 | typedef.setdefault('doctail', '') 122 | typedef.setdefault('context_type', typedef['type']) 123 | typedef.setdefault('dest', True) 124 | typedef.setdefault('parser', 'f.Value, error(nil)') 125 | typedef.setdefault('parser_cast', 'parsed') 126 | 127 | 128 | def _write_cli_flag_types(outfile, types): 129 | _fwrite(outfile, """\ 130 | package cli 131 | 132 | // WARNING: This file is generated! 133 | 134 | """) 135 | 136 | for typedef in types: 137 | _set_typedef_defaults(typedef) 138 | 139 | _fwrite(outfile, """\ 140 | // {name}Flag is a flag with type {type}{doctail} 141 | type {name}Flag struct {{ 142 | Name string 143 | Aliases []string 144 | Usage string 145 | EnvVars []string 146 | Hidden bool 147 | Value {type} 148 | DefaultText string 149 | """.format(**typedef)) 150 | 151 | if typedef['dest']: 152 | _fwrite(outfile, """\ 153 | Destination *{type} 154 | """.format(**typedef)) 155 | 156 | _fwrite(outfile, "\n}\n\n") 157 | 158 | _fwrite(outfile, """\ 159 | // String returns a readable representation of this value 160 | // (for usage defaults) 161 | func (f *{name}Flag) String() string {{ 162 | return FlagStringer(f) 163 | }} 164 | 165 | // Names returns the names of the flag 166 | func (f *{name}Flag) Names() []string {{ 167 | return flagNames(f) 168 | }} 169 | 170 | // {name} looks up the value of a local {name}Flag, returns 171 | // {context_default} if not found 172 | func (c *Context) {name}(name string) {context_type} {{ 173 | if fs := lookupFlagSet(name, c); fs != nil {{ 174 | return lookup{name}(name, fs) 175 | }} 176 | return {context_default} 177 | }} 178 | 179 | func lookup{name}(name string, set *flag.FlagSet) {context_type} {{ 180 | f := set.Lookup(name) 181 | if f != nil {{ 182 | parsed, err := {parser} 183 | if err != nil {{ 184 | return {context_default} 185 | }} 186 | return {parser_cast} 187 | }} 188 | return {context_default} 189 | }} 190 | """.format(**typedef)) 191 | 192 | 193 | def _write_altsrc_flag_types(outfile, types): 194 | _fwrite(outfile, """\ 195 | package altsrc 196 | 197 | import "gopkg.in/urfave/cli.v2" 198 | 199 | // WARNING: This file is generated! 200 | 201 | """) 202 | 203 | for typedef in types: 204 | _set_typedef_defaults(typedef) 205 | 206 | _fwrite(outfile, """\ 207 | // {name}Flag is the flag type that wraps cli.{name}Flag to allow 208 | // for other values to be specified 209 | type {name}Flag struct {{ 210 | *cli.{name}Flag 211 | set *flag.FlagSet 212 | }} 213 | 214 | // New{name}Flag creates a new {name}Flag 215 | func New{name}Flag(fl *cli.{name}Flag) *{name}Flag {{ 216 | return &{name}Flag{{{name}Flag: fl, set: nil}} 217 | }} 218 | 219 | // Apply saves the flagSet for later usage calls, then calls the 220 | // wrapped {name}Flag.Apply 221 | func (f *{name}Flag) Apply(set *flag.FlagSet) {{ 222 | f.set = set 223 | f.{name}Flag.Apply(set) 224 | }} 225 | """.format(**typedef)) 226 | 227 | 228 | def _fwrite(outfile, text): 229 | print(textwrap.dedent(text), end='', file=outfile) 230 | 231 | 232 | _WRITEFUNCS = { 233 | 'cli': _write_cli_flag_types, 234 | 'altsrc': _write_altsrc_flag_types 235 | } 236 | 237 | if __name__ == '__main__': 238 | sys.exit(main()) 239 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/app.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "io/ioutil" 7 | "os" 8 | "path/filepath" 9 | "reflect" 10 | "sort" 11 | "time" 12 | ) 13 | 14 | // App is the main structure of a cli application. 15 | type App struct { 16 | // The name of the program. Defaults to path.Base(os.Args[0]) 17 | Name string 18 | // Full name of command for help, defaults to Name 19 | HelpName string 20 | // Description of the program. 21 | Usage string 22 | // Text to override the USAGE section of help 23 | UsageText string 24 | // Description of the program argument format. 25 | ArgsUsage string 26 | // Version of the program 27 | Version string 28 | // List of commands to execute 29 | Commands []*Command 30 | // List of flags to parse 31 | Flags []Flag 32 | // Boolean to enable bash completion commands 33 | EnableBashCompletion bool 34 | // Boolean to hide built-in help command 35 | HideHelp bool 36 | // Boolean to hide built-in version flag and the VERSION section of help 37 | HideVersion bool 38 | // Categories contains the categorized commands and is populated on app startup 39 | Categories CommandCategories 40 | // An action to execute when the bash-completion flag is set 41 | BashComplete BashCompleteFunc 42 | // An action to execute before any subcommands are run, but after the context is ready 43 | // If a non-nil error is returned, no subcommands are run 44 | Before BeforeFunc 45 | // An action to execute after any subcommands are run, but after the subcommand has finished 46 | // It is run even if Action() panics 47 | After AfterFunc 48 | // The action to execute when no subcommands are specified 49 | Action ActionFunc 50 | // Execute this function if the proper command cannot be found 51 | CommandNotFound CommandNotFoundFunc 52 | // Execute this function if an usage error occurs 53 | OnUsageError OnUsageErrorFunc 54 | // Compilation date 55 | Compiled time.Time 56 | // List of all authors who contributed 57 | Authors []*Author 58 | // Copyright of the binary if any 59 | Copyright string 60 | // Writer writer to write output to 61 | Writer io.Writer 62 | // ErrWriter writes error output 63 | ErrWriter io.Writer 64 | // Other custom info 65 | Metadata map[string]interface{} 66 | 67 | didSetup bool 68 | } 69 | 70 | // Tries to find out when this binary was compiled. 71 | // Returns the current time if it fails to find it. 72 | func compileTime() time.Time { 73 | info, err := os.Stat(os.Args[0]) 74 | if err != nil { 75 | return time.Now() 76 | } 77 | return info.ModTime() 78 | } 79 | 80 | // Setup runs initialization code to ensure all data structures are ready for 81 | // `Run` or inspection prior to `Run`. It is internally called by `Run`, but 82 | // will return early if setup has already happened. 83 | func (a *App) Setup() { 84 | if a.didSetup { 85 | return 86 | } 87 | 88 | a.didSetup = true 89 | 90 | if a.Name == "" { 91 | a.Name = filepath.Base(os.Args[0]) 92 | } 93 | 94 | if a.HelpName == "" { 95 | a.HelpName = filepath.Base(os.Args[0]) 96 | } 97 | 98 | if a.Usage == "" { 99 | a.Usage = "A new cli application" 100 | } 101 | 102 | if a.Version == "" { 103 | a.Version = "0.0.0" 104 | } 105 | 106 | if a.BashComplete == nil { 107 | a.BashComplete = DefaultAppComplete 108 | } 109 | 110 | if a.Action == nil { 111 | a.Action = helpCommand.Action 112 | } 113 | 114 | if a.Compiled == (time.Time{}) { 115 | a.Compiled = compileTime() 116 | } 117 | 118 | if a.Writer == nil { 119 | a.Writer = os.Stdout 120 | } 121 | 122 | newCmds := []*Command{} 123 | for _, c := range a.Commands { 124 | if c.HelpName == "" { 125 | c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) 126 | } 127 | newCmds = append(newCmds, c) 128 | } 129 | a.Commands = newCmds 130 | 131 | if a.Command(helpCommand.Name) == nil && !a.HideHelp { 132 | a.appendCommand(helpCommand) 133 | 134 | if HelpFlag != nil { 135 | a.appendFlag(HelpFlag) 136 | } 137 | } 138 | 139 | if a.EnableBashCompletion { 140 | a.appendFlag(BashCompletionFlag) 141 | } 142 | 143 | if !a.HideVersion { 144 | a.appendFlag(VersionFlag) 145 | } 146 | 147 | a.Categories = newCommandCategories() 148 | for _, command := range a.Commands { 149 | a.Categories.AddCommand(command.Category, command) 150 | } 151 | sort.Sort(a.Categories.(*commandCategories)) 152 | 153 | if a.Metadata == nil { 154 | a.Metadata = make(map[string]interface{}) 155 | } 156 | } 157 | 158 | // Run is the entry point to the cli app. Parses the arguments slice and routes 159 | // to the proper flag/args combination 160 | func (a *App) Run(arguments []string) (err error) { 161 | a.Setup() 162 | 163 | // parse flags 164 | set := flagSet(a.Name, a.Flags) 165 | set.SetOutput(ioutil.Discard) 166 | err = set.Parse(arguments[1:]) 167 | nerr := normalizeFlags(a.Flags, set) 168 | context := NewContext(a, set, nil) 169 | if nerr != nil { 170 | fmt.Fprintln(a.Writer, nerr) 171 | ShowAppHelp(context) 172 | return nerr 173 | } 174 | 175 | if checkCompletions(context) { 176 | return nil 177 | } 178 | 179 | if err != nil { 180 | if a.OnUsageError != nil { 181 | err := a.OnUsageError(context, err, false) 182 | HandleExitCoder(err) 183 | return err 184 | } 185 | fmt.Fprintf(a.Writer, "Incorrect Usage: %s\n\n", err) 186 | ShowAppHelp(context) 187 | return err 188 | } 189 | 190 | if !a.HideHelp && checkHelp(context) { 191 | ShowAppHelp(context) 192 | return nil 193 | } 194 | 195 | if !a.HideVersion && checkVersion(context) { 196 | ShowVersion(context) 197 | return nil 198 | } 199 | 200 | if a.After != nil { 201 | defer func() { 202 | if afterErr := a.After(context); afterErr != nil { 203 | if err != nil { 204 | err = newMultiError(err, afterErr) 205 | } else { 206 | err = afterErr 207 | } 208 | } 209 | }() 210 | } 211 | 212 | if a.Before != nil { 213 | beforeErr := a.Before(context) 214 | if beforeErr != nil { 215 | fmt.Fprintf(a.Writer, "%v\n\n", beforeErr) 216 | ShowAppHelp(context) 217 | HandleExitCoder(beforeErr) 218 | err = beforeErr 219 | return err 220 | } 221 | } 222 | 223 | args := context.Args() 224 | if args.Present() { 225 | name := args.First() 226 | c := a.Command(name) 227 | if c != nil { 228 | return c.Run(context) 229 | } 230 | } 231 | 232 | // Run default Action 233 | err = a.Action(context) 234 | 235 | HandleExitCoder(err) 236 | return err 237 | } 238 | 239 | // RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to 240 | // generate command-specific flags 241 | func (a *App) RunAsSubcommand(ctx *Context) (err error) { 242 | // append help to commands 243 | if len(a.Commands) > 0 { 244 | if a.Command(helpCommand.Name) == nil && !a.HideHelp { 245 | a.appendCommand(helpCommand) 246 | 247 | if HelpFlag != nil { 248 | a.appendFlag(HelpFlag) 249 | } 250 | } 251 | } 252 | 253 | newCmds := []*Command{} 254 | for _, c := range a.Commands { 255 | if c.HelpName == "" { 256 | c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) 257 | } 258 | newCmds = append(newCmds, c) 259 | } 260 | a.Commands = newCmds 261 | 262 | // append flags 263 | if a.EnableBashCompletion { 264 | a.appendFlag(BashCompletionFlag) 265 | } 266 | 267 | // parse flags 268 | set := flagSet(a.Name, a.Flags) 269 | set.SetOutput(ioutil.Discard) 270 | err = set.Parse(ctx.Args().Tail()) 271 | nerr := normalizeFlags(a.Flags, set) 272 | context := NewContext(a, set, ctx) 273 | 274 | if nerr != nil { 275 | fmt.Fprintln(a.Writer, nerr) 276 | fmt.Fprintln(a.Writer) 277 | if len(a.Commands) > 0 { 278 | ShowSubcommandHelp(context) 279 | } else { 280 | ShowCommandHelp(ctx, context.Args().First()) 281 | } 282 | return nerr 283 | } 284 | 285 | if checkCompletions(context) { 286 | return nil 287 | } 288 | 289 | if err != nil { 290 | if a.OnUsageError != nil { 291 | err = a.OnUsageError(context, err, true) 292 | HandleExitCoder(err) 293 | return err 294 | } 295 | fmt.Fprintf(a.Writer, "Incorrect Usage: %s\n\n", err) 296 | ShowSubcommandHelp(context) 297 | return err 298 | } 299 | 300 | if len(a.Commands) > 0 { 301 | if checkSubcommandHelp(context) { 302 | return nil 303 | } 304 | } else { 305 | if checkCommandHelp(ctx, context.Args().First()) { 306 | return nil 307 | } 308 | } 309 | 310 | if a.After != nil { 311 | defer func() { 312 | afterErr := a.After(context) 313 | if afterErr != nil { 314 | HandleExitCoder(err) 315 | if err != nil { 316 | err = newMultiError(err, afterErr) 317 | } else { 318 | err = afterErr 319 | } 320 | } 321 | }() 322 | } 323 | 324 | if a.Before != nil { 325 | beforeErr := a.Before(context) 326 | if beforeErr != nil { 327 | HandleExitCoder(beforeErr) 328 | err = beforeErr 329 | return err 330 | } 331 | } 332 | 333 | args := context.Args() 334 | if args.Present() { 335 | name := args.First() 336 | c := a.Command(name) 337 | if c != nil { 338 | return c.Run(context) 339 | } 340 | } 341 | 342 | // Run default Action 343 | err = a.Action(context) 344 | 345 | HandleExitCoder(err) 346 | return err 347 | } 348 | 349 | // Command returns the named command on App. Returns nil if the command does not exist 350 | func (a *App) Command(name string) *Command { 351 | for _, c := range a.Commands { 352 | if c.HasName(name) { 353 | return c 354 | } 355 | } 356 | 357 | return nil 358 | } 359 | 360 | // VisibleCategories returns a slice of categories and commands that are 361 | // Hidden=false 362 | func (a *App) VisibleCategories() []CommandCategory { 363 | ret := []CommandCategory{} 364 | for _, category := range a.Categories.Categories() { 365 | if visible := func() CommandCategory { 366 | if len(category.VisibleCommands()) > 0 { 367 | return category 368 | } 369 | return nil 370 | }(); visible != nil { 371 | ret = append(ret, visible) 372 | } 373 | } 374 | return ret 375 | } 376 | 377 | // VisibleCommands returns a slice of the Commands with Hidden=false 378 | func (a *App) VisibleCommands() []*Command { 379 | ret := []*Command{} 380 | for _, command := range a.Commands { 381 | if !command.Hidden { 382 | ret = append(ret, command) 383 | } 384 | } 385 | return ret 386 | } 387 | 388 | // VisibleFlags returns a slice of the Flags with Hidden=false 389 | func (a *App) VisibleFlags() []Flag { 390 | return visibleFlags(a.Flags) 391 | } 392 | 393 | func (a *App) hasFlag(flag Flag) bool { 394 | for _, f := range a.Flags { 395 | if reflect.DeepEqual(flag, f) { 396 | return true 397 | } 398 | } 399 | 400 | return false 401 | } 402 | 403 | func (a *App) errWriter() io.Writer { 404 | 405 | // When the app ErrWriter is nil use the package level one. 406 | if a.ErrWriter == nil { 407 | return ErrWriter 408 | } 409 | 410 | return a.ErrWriter 411 | } 412 | 413 | func (a *App) appendFlag(fl Flag) { 414 | if !hasFlag(a.Flags, fl) { 415 | a.Flags = append(a.Flags, fl) 416 | } 417 | } 418 | 419 | func (a *App) appendCommand(c *Command) { 420 | if !hasCommand(a.Commands, c) { 421 | a.Commands = append(a.Commands, c) 422 | } 423 | } 424 | 425 | // Author represents someone who has contributed to a cli project. 426 | type Author struct { 427 | Name string // The Authors name 428 | Email string // The Authors email 429 | } 430 | 431 | // String makes Author comply to the Stringer interface, to allow an easy print in the templating process 432 | func (a *Author) String() string { 433 | e := "" 434 | if a.Email != "" { 435 | e = "<" + a.Email + "> " 436 | } 437 | 438 | return fmt.Sprintf("%v %v", a.Name, e) 439 | } 440 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/lock.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | const ( 10 | // DefaultLockSessionName is the Session Name we assign if none is provided 11 | DefaultLockSessionName = "Consul API Lock" 12 | 13 | // DefaultLockSessionTTL is the default session TTL if no Session is provided 14 | // when creating a new Lock. This is used because we do not have another 15 | // other check to depend upon. 16 | DefaultLockSessionTTL = "15s" 17 | 18 | // DefaultLockWaitTime is how long we block for at a time to check if lock 19 | // acquisition is possible. This affects the minimum time it takes to cancel 20 | // a Lock acquisition. 21 | DefaultLockWaitTime = 15 * time.Second 22 | 23 | // DefaultLockRetryTime is how long we wait after a failed lock acquisition 24 | // before attempting to do the lock again. This is so that once a lock-delay 25 | // is in effect, we do not hot loop retrying the acquisition. 26 | DefaultLockRetryTime = 5 * time.Second 27 | 28 | // DefaultMonitorRetryTime is how long we wait after a failed monitor check 29 | // of a lock (500 response code). This allows the monitor to ride out brief 30 | // periods of unavailability, subject to the MonitorRetries setting in the 31 | // lock options which is by default set to 0, disabling this feature. This 32 | // affects locks and semaphores. 33 | DefaultMonitorRetryTime = 2 * time.Second 34 | 35 | // LockFlagValue is a magic flag we set to indicate a key 36 | // is being used for a lock. It is used to detect a potential 37 | // conflict with a semaphore. 38 | LockFlagValue = 0x2ddccbc058a50c18 39 | ) 40 | 41 | var ( 42 | // ErrLockHeld is returned if we attempt to double lock 43 | ErrLockHeld = fmt.Errorf("Lock already held") 44 | 45 | // ErrLockNotHeld is returned if we attempt to unlock a lock 46 | // that we do not hold. 47 | ErrLockNotHeld = fmt.Errorf("Lock not held") 48 | 49 | // ErrLockInUse is returned if we attempt to destroy a lock 50 | // that is in use. 51 | ErrLockInUse = fmt.Errorf("Lock in use") 52 | 53 | // ErrLockConflict is returned if the flags on a key 54 | // used for a lock do not match expectation 55 | ErrLockConflict = fmt.Errorf("Existing key does not match lock use") 56 | ) 57 | 58 | // Lock is used to implement client-side leader election. It is follows the 59 | // algorithm as described here: https://www.consul.io/docs/guides/leader-election.html. 60 | type Lock struct { 61 | c *Client 62 | opts *LockOptions 63 | 64 | isHeld bool 65 | sessionRenew chan struct{} 66 | lockSession string 67 | l sync.Mutex 68 | } 69 | 70 | // LockOptions is used to parameterize the Lock behavior. 71 | type LockOptions struct { 72 | Key string // Must be set and have write permissions 73 | Value []byte // Optional, value to associate with the lock 74 | Session string // Optional, created if not specified 75 | SessionOpts *SessionEntry // Optional, options to use when creating a session 76 | SessionName string // Optional, defaults to DefaultLockSessionName (ignored if SessionOpts is given) 77 | SessionTTL string // Optional, defaults to DefaultLockSessionTTL (ignored if SessionOpts is given) 78 | MonitorRetries int // Optional, defaults to 0 which means no retries 79 | MonitorRetryTime time.Duration // Optional, defaults to DefaultMonitorRetryTime 80 | LockWaitTime time.Duration // Optional, defaults to DefaultLockWaitTime 81 | LockTryOnce bool // Optional, defaults to false which means try forever 82 | } 83 | 84 | // LockKey returns a handle to a lock struct which can be used 85 | // to acquire and release the mutex. The key used must have 86 | // write permissions. 87 | func (c *Client) LockKey(key string) (*Lock, error) { 88 | opts := &LockOptions{ 89 | Key: key, 90 | } 91 | return c.LockOpts(opts) 92 | } 93 | 94 | // LockOpts returns a handle to a lock struct which can be used 95 | // to acquire and release the mutex. The key used must have 96 | // write permissions. 97 | func (c *Client) LockOpts(opts *LockOptions) (*Lock, error) { 98 | if opts.Key == "" { 99 | return nil, fmt.Errorf("missing key") 100 | } 101 | if opts.SessionName == "" { 102 | opts.SessionName = DefaultLockSessionName 103 | } 104 | if opts.SessionTTL == "" { 105 | opts.SessionTTL = DefaultLockSessionTTL 106 | } else { 107 | if _, err := time.ParseDuration(opts.SessionTTL); err != nil { 108 | return nil, fmt.Errorf("invalid SessionTTL: %v", err) 109 | } 110 | } 111 | if opts.MonitorRetryTime == 0 { 112 | opts.MonitorRetryTime = DefaultMonitorRetryTime 113 | } 114 | if opts.LockWaitTime == 0 { 115 | opts.LockWaitTime = DefaultLockWaitTime 116 | } 117 | l := &Lock{ 118 | c: c, 119 | opts: opts, 120 | } 121 | return l, nil 122 | } 123 | 124 | // Lock attempts to acquire the lock and blocks while doing so. 125 | // Providing a non-nil stopCh can be used to abort the lock attempt. 126 | // Returns a channel that is closed if our lock is lost or an error. 127 | // This channel could be closed at any time due to session invalidation, 128 | // communication errors, operator intervention, etc. It is NOT safe to 129 | // assume that the lock is held until Unlock() unless the Session is specifically 130 | // created without any associated health checks. By default Consul sessions 131 | // prefer liveness over safety and an application must be able to handle 132 | // the lock being lost. 133 | func (l *Lock) Lock(stopCh <-chan struct{}) (<-chan struct{}, error) { 134 | // Hold the lock as we try to acquire 135 | l.l.Lock() 136 | defer l.l.Unlock() 137 | 138 | // Check if we already hold the lock 139 | if l.isHeld { 140 | return nil, ErrLockHeld 141 | } 142 | 143 | // Check if we need to create a session first 144 | l.lockSession = l.opts.Session 145 | if l.lockSession == "" { 146 | if s, err := l.createSession(); err != nil { 147 | return nil, fmt.Errorf("failed to create session: %v", err) 148 | } else { 149 | l.sessionRenew = make(chan struct{}) 150 | l.lockSession = s 151 | session := l.c.Session() 152 | go session.RenewPeriodic(l.opts.SessionTTL, s, nil, l.sessionRenew) 153 | 154 | // If we fail to acquire the lock, cleanup the session 155 | defer func() { 156 | if !l.isHeld { 157 | close(l.sessionRenew) 158 | l.sessionRenew = nil 159 | } 160 | }() 161 | } 162 | } 163 | 164 | // Setup the query options 165 | kv := l.c.KV() 166 | qOpts := &QueryOptions{ 167 | WaitTime: l.opts.LockWaitTime, 168 | } 169 | 170 | start := time.Now() 171 | attempts := 0 172 | WAIT: 173 | // Check if we should quit 174 | select { 175 | case <-stopCh: 176 | return nil, nil 177 | default: 178 | } 179 | 180 | // Handle the one-shot mode. 181 | if l.opts.LockTryOnce && attempts > 0 { 182 | elapsed := time.Now().Sub(start) 183 | if elapsed > qOpts.WaitTime { 184 | return nil, nil 185 | } 186 | 187 | qOpts.WaitTime -= elapsed 188 | } 189 | attempts++ 190 | 191 | // Look for an existing lock, blocking until not taken 192 | pair, meta, err := kv.Get(l.opts.Key, qOpts) 193 | if err != nil { 194 | return nil, fmt.Errorf("failed to read lock: %v", err) 195 | } 196 | if pair != nil && pair.Flags != LockFlagValue { 197 | return nil, ErrLockConflict 198 | } 199 | locked := false 200 | if pair != nil && pair.Session == l.lockSession { 201 | goto HELD 202 | } 203 | if pair != nil && pair.Session != "" { 204 | qOpts.WaitIndex = meta.LastIndex 205 | goto WAIT 206 | } 207 | 208 | // Try to acquire the lock 209 | pair = l.lockEntry(l.lockSession) 210 | locked, _, err = kv.Acquire(pair, nil) 211 | if err != nil { 212 | return nil, fmt.Errorf("failed to acquire lock: %v", err) 213 | } 214 | 215 | // Handle the case of not getting the lock 216 | if !locked { 217 | // Determine why the lock failed 218 | qOpts.WaitIndex = 0 219 | pair, meta, err = kv.Get(l.opts.Key, qOpts) 220 | if pair != nil && pair.Session != "" { 221 | //If the session is not null, this means that a wait can safely happen 222 | //using a long poll 223 | qOpts.WaitIndex = meta.LastIndex 224 | goto WAIT 225 | } else { 226 | // If the session is empty and the lock failed to acquire, then it means 227 | // a lock-delay is in effect and a timed wait must be used 228 | select { 229 | case <-time.After(DefaultLockRetryTime): 230 | goto WAIT 231 | case <-stopCh: 232 | return nil, nil 233 | } 234 | } 235 | } 236 | 237 | HELD: 238 | // Watch to ensure we maintain leadership 239 | leaderCh := make(chan struct{}) 240 | go l.monitorLock(l.lockSession, leaderCh) 241 | 242 | // Set that we own the lock 243 | l.isHeld = true 244 | 245 | // Locked! All done 246 | return leaderCh, nil 247 | } 248 | 249 | // Unlock released the lock. It is an error to call this 250 | // if the lock is not currently held. 251 | func (l *Lock) Unlock() error { 252 | // Hold the lock as we try to release 253 | l.l.Lock() 254 | defer l.l.Unlock() 255 | 256 | // Ensure the lock is actually held 257 | if !l.isHeld { 258 | return ErrLockNotHeld 259 | } 260 | 261 | // Set that we no longer own the lock 262 | l.isHeld = false 263 | 264 | // Stop the session renew 265 | if l.sessionRenew != nil { 266 | defer func() { 267 | close(l.sessionRenew) 268 | l.sessionRenew = nil 269 | }() 270 | } 271 | 272 | // Get the lock entry, and clear the lock session 273 | lockEnt := l.lockEntry(l.lockSession) 274 | l.lockSession = "" 275 | 276 | // Release the lock explicitly 277 | kv := l.c.KV() 278 | _, _, err := kv.Release(lockEnt, nil) 279 | if err != nil { 280 | return fmt.Errorf("failed to release lock: %v", err) 281 | } 282 | return nil 283 | } 284 | 285 | // Destroy is used to cleanup the lock entry. It is not necessary 286 | // to invoke. It will fail if the lock is in use. 287 | func (l *Lock) Destroy() error { 288 | // Hold the lock as we try to release 289 | l.l.Lock() 290 | defer l.l.Unlock() 291 | 292 | // Check if we already hold the lock 293 | if l.isHeld { 294 | return ErrLockHeld 295 | } 296 | 297 | // Look for an existing lock 298 | kv := l.c.KV() 299 | pair, _, err := kv.Get(l.opts.Key, nil) 300 | if err != nil { 301 | return fmt.Errorf("failed to read lock: %v", err) 302 | } 303 | 304 | // Nothing to do if the lock does not exist 305 | if pair == nil { 306 | return nil 307 | } 308 | 309 | // Check for possible flag conflict 310 | if pair.Flags != LockFlagValue { 311 | return ErrLockConflict 312 | } 313 | 314 | // Check if it is in use 315 | if pair.Session != "" { 316 | return ErrLockInUse 317 | } 318 | 319 | // Attempt the delete 320 | didRemove, _, err := kv.DeleteCAS(pair, nil) 321 | if err != nil { 322 | return fmt.Errorf("failed to remove lock: %v", err) 323 | } 324 | if !didRemove { 325 | return ErrLockInUse 326 | } 327 | return nil 328 | } 329 | 330 | // createSession is used to create a new managed session 331 | func (l *Lock) createSession() (string, error) { 332 | session := l.c.Session() 333 | se := l.opts.SessionOpts 334 | if se == nil { 335 | se = &SessionEntry{ 336 | Name: l.opts.SessionName, 337 | TTL: l.opts.SessionTTL, 338 | } 339 | } 340 | id, _, err := session.Create(se, nil) 341 | if err != nil { 342 | return "", err 343 | } 344 | return id, nil 345 | } 346 | 347 | // lockEntry returns a formatted KVPair for the lock 348 | func (l *Lock) lockEntry(session string) *KVPair { 349 | return &KVPair{ 350 | Key: l.opts.Key, 351 | Value: l.opts.Value, 352 | Session: session, 353 | Flags: LockFlagValue, 354 | } 355 | } 356 | 357 | // monitorLock is a long running routine to monitor a lock ownership 358 | // It closes the stopCh if we lose our leadership. 359 | func (l *Lock) monitorLock(session string, stopCh chan struct{}) { 360 | defer close(stopCh) 361 | kv := l.c.KV() 362 | opts := &QueryOptions{RequireConsistent: true} 363 | WAIT: 364 | retries := l.opts.MonitorRetries 365 | RETRY: 366 | pair, meta, err := kv.Get(l.opts.Key, opts) 367 | if err != nil { 368 | // If configured we can try to ride out a brief Consul unavailability 369 | // by doing retries. Note that we have to attempt the retry in a non- 370 | // blocking fashion so that we have a clean place to reset the retry 371 | // counter if service is restored. 372 | if retries > 0 && IsServerError(err) { 373 | time.Sleep(l.opts.MonitorRetryTime) 374 | retries-- 375 | opts.WaitIndex = 0 376 | goto RETRY 377 | } 378 | return 379 | } 380 | if pair != nil && pair.Session == session { 381 | opts.WaitIndex = meta.LastIndex 382 | goto WAIT 383 | } 384 | } 385 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/cli-v1-to-v2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function, unicode_literals 3 | 4 | import argparse 5 | import io 6 | import logging 7 | import os 8 | import re 9 | import sys 10 | 11 | 12 | _DESCRIPTION = """\ 13 | Migrate arbitrary `.go` sources (mostly) from the v1 to v2 API. 14 | """ 15 | _MIGRATORS = [] 16 | 17 | 18 | def main(sysargs=sys.argv[:]): 19 | parser = argparse.ArgumentParser( 20 | description=_DESCRIPTION, 21 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 22 | parser.add_argument('path', nargs='*', 23 | type=os.path.abspath, default=os.getcwd()) 24 | parser.add_argument('-w', '--write', help='write changes back to file', 25 | action='store_true', default=False) 26 | parser.add_argument('-q', '--quiet', help='quiet down the logging', 27 | action='store_true', default=False) 28 | parser.add_argument('-D', '--debug', help='debug up the logging', 29 | action='store_true', 30 | default=(os.environ.get('DEBUG') != '')) 31 | parser.add_argument('--selftest', help='run internal tests', 32 | action='store_true', default=False) 33 | 34 | args = parser.parse_args(sysargs[1:]) 35 | 36 | if args.selftest: 37 | logging.basicConfig( 38 | level=logging.WARN, 39 | format='selftest: %(message)s' 40 | ) 41 | test_migrators() 42 | return 0 43 | 44 | level = logging.FATAL if args.quiet else logging.INFO 45 | level = logging.DEBUG if args.debug else level 46 | 47 | logging.basicConfig(level=level, format='%(message)s') 48 | 49 | paths = args.path 50 | if len(paths) == 0: 51 | paths = ['.'] 52 | 53 | for filepath in _find_candidate_files(paths): 54 | updated_source = _update_filepath(filepath) 55 | if args.write: 56 | logging.info('Updating %s', filepath) 57 | 58 | with io.open(filepath, 'w', encoding='utf-8') as outfile: 59 | outfile.write(updated_source) 60 | else: 61 | logging.info('// Updated %s:', filepath) 62 | print(updated_source) 63 | 64 | return 0 65 | 66 | 67 | def _find_candidate_files(paths): 68 | for path in paths: 69 | if not os.path.isdir(path): 70 | yield path 71 | continue 72 | 73 | for curdir, dirs, files in os.walk(path): 74 | for i, dirname in enumerate(dirs[:]): 75 | if dirname.startswith('.'): 76 | dirs.pop(i) 77 | 78 | for filename in files: 79 | if not filename.decode('utf-8').endswith('.go'): 80 | continue 81 | 82 | filepath = os.path.join(curdir, filename) 83 | if not os.access(filepath, os.R_OK | os.W_OK): 84 | continue 85 | 86 | yield filepath 87 | 88 | 89 | def _update_filepath(filepath): 90 | with io.open(filepath, encoding='utf-8') as infile: 91 | return _update_source(infile.read()) 92 | 93 | 94 | def _update_source(source): 95 | for migrator, func in _MIGRATORS: 96 | logging.debug('Running %s migrator', migrator) 97 | source = func(source) 98 | return source 99 | 100 | 101 | def _subfmt(pattern, replfmt, source, flags=re.UNICODE): 102 | def repl(match): 103 | return replfmt.format(**match.groupdict()) 104 | return re.sub(pattern, repl, source, flags=flags) 105 | 106 | 107 | def _migrator(func): 108 | _MIGRATORS.append((func.__name__.strip('_'), func)) 109 | return func 110 | 111 | 112 | @_migrator 113 | def _slice_pointer_types(source): 114 | return _subfmt( 115 | '(?P\\[\\])cli\\.(?PCommand|Author){', 116 | '{prefix}*cli.{type}{{', source 117 | ) 118 | 119 | 120 | @_migrator 121 | def _pointer_type_literal(source): 122 | return _subfmt( 123 | '(?P\\s+)cli\\.(?PCommand|Author){', 124 | '{prefix}&cli.{type}{{', source 125 | ) 126 | 127 | 128 | @_migrator 129 | def _slice_types(source): 130 | return _subfmt( 131 | '&cli\\.(?PIntSlice|StringSlice){(?P[^}]*)}', 132 | 'cli.New{type}({args})', source, flags=re.DOTALL | re.UNICODE 133 | ) 134 | 135 | 136 | @_migrator 137 | def _flag_literals(source): 138 | return _subfmt( 139 | '(?P\\s+)cli\\.(?P\\w+)Flag{', 140 | '{prefix}&cli.{type}Flag{{', source 141 | ) 142 | 143 | 144 | @_migrator 145 | def _v1_imports(source): 146 | return re.sub( 147 | '"(?:github\\.com|gopkg\\.in)/(?:codegangsta|urfave)/cli(?:\\.v1|)"', 148 | '"gopkg.in/urfave/cli.v2"', source, flags=re.UNICODE 149 | ) 150 | 151 | 152 | @_migrator 153 | def _new_exit_error(source): 154 | return re.sub('cli\\.NewExitError', 'cli.Exit', source, flags=re.UNICODE) 155 | 156 | 157 | @_migrator 158 | def _bool_t_flag(source): 159 | return _subfmt( 160 | 'cli\\.BoolTFlag{(?P[^}]*)}', 161 | 'cli.BoolFlag{{Value: true,{args}}}', 162 | source, flags=re.DOTALL | re.UNICODE 163 | ) 164 | 165 | 166 | @_migrator 167 | def _context_args_len(source): 168 | return _subfmt( 169 | 'len\\((?P\\S+)\\.Args\\(\\)\\)', 170 | '{prefix}.Args().Len()', source 171 | ) 172 | 173 | 174 | @_migrator 175 | def _context_args_index(source): 176 | return _subfmt( 177 | '\\.Args\\(\\)\\[(?P\\d+)\\]', 178 | '.Args().Get({index})', source 179 | ) 180 | 181 | 182 | @_migrator 183 | def _envvar_string(source): 184 | return re.sub( 185 | 'EnvVar:(?P\\s+)"(?P[^"]+)"', 186 | _envvar_string_repl, source, flags=re.UNICODE 187 | ) 188 | 189 | 190 | def _envvar_string_repl(match): 191 | return 'EnvVars:{ws}[]string{{{value}}}'.format( 192 | value=', '.join([ 193 | '"{}"'.format(s) for s in 194 | re.split( 195 | '\\s*,\\s*', match.groupdict()['string'], 196 | flags=re.UNICODE 197 | ) 198 | ]), 199 | **match.groupdict() 200 | ) 201 | 202 | 203 | @_migrator 204 | def _flag_name_stringly(source): 205 | return re.sub( 206 | '(?P\\s+)Name:(?P\\s+)"(?P[^"]+)"', 207 | _flag_name_stringly_repl, source, flags=re.UNICODE 208 | ) 209 | 210 | 211 | def _flag_name_stringly_repl(match): 212 | revars = dict(match.groupdict()) 213 | 214 | string = revars['string'] 215 | parts = list( 216 | reversed( 217 | sorted( 218 | filter(lambda s: len(s.strip()) > 0, [ 219 | part.strip() for part in string.split(',') 220 | ]), key=len 221 | ) 222 | ) 223 | ) 224 | 225 | if len(parts) == 1: 226 | return '{prefix}Name:{ws}"{string}"'.format(**revars) 227 | 228 | return ( 229 | '{prefix}Name:{ws}"{name}", Aliases: []string{{{aliases}}}' 230 | ).format( 231 | name=parts[0], 232 | aliases=', '.join(['"{}"'.format(s) for s in parts[1:]]), 233 | **revars 234 | ) 235 | 236 | 237 | @_migrator 238 | def _commands_opaque_type(source): 239 | return re.sub('cli\\.Commands', '[]*cli.Command', source, flags=re.UNICODE) 240 | 241 | 242 | @_migrator 243 | def _flag_names(source): 244 | return re.sub('\\.GetName\\(\\)', '.Names()[0]', source, flags=re.UNICODE) 245 | 246 | 247 | @_migrator 248 | def _app_categories(source): 249 | source = _subfmt( 250 | '(?Prange\\s+\\S+)\\.App\\.Categories\\(\\)', 251 | '{prefix}.App.Categories.Categories()', source 252 | ) 253 | 254 | return re.sub( 255 | '\\.App\\.Categories\\(\\)', '.App.Categories', 256 | source, flags=re.UNICODE 257 | ) 258 | 259 | 260 | @_migrator 261 | def _command_category_commands(source): 262 | # XXX: brittle 263 | return _subfmt( 264 | '(?P\\s+category\\.)Commands(?P[^(])', 265 | '{prefix}VisibleCommands(){suffix}', source 266 | ) 267 | 268 | 269 | @_migrator 270 | def _context_bool_t(source): 271 | # XXX: probably brittle 272 | return _subfmt( 273 | '(?P\\S+)(?:Global|)BoolT\\(', 274 | '!{prefix}Bool(', source 275 | ) 276 | 277 | 278 | @_migrator 279 | def _context_global_methods(source): 280 | return _subfmt( 281 | '\\.Global(?P' 282 | 'Bool|Duration|Float64|Generic|Int|IntSlice|String|StringSlice|' 283 | 'FlagNames|IsSet|Set' 284 | ')\\(', 285 | '.{method}(', source 286 | ) 287 | 288 | 289 | @_migrator 290 | def _context_parent(source): 291 | # XXX: brittle 292 | return re.sub('\\.Parent\\(\\)', '.Lineage()[1]', source, flags=re.UNICODE) 293 | 294 | 295 | @_migrator 296 | def _app_init(source): 297 | return re.sub( 298 | 'cli\\.NewApp\\(\\)', '(&cli.App{})', source, flags=re.UNICODE 299 | ) 300 | 301 | 302 | def test_migrators(): 303 | import difflib 304 | 305 | for i, (source, expected) in enumerate(_MIGRATOR_TESTS): 306 | actual = _update_source(source) 307 | if expected != actual: 308 | udiff = difflib.unified_diff( 309 | expected.splitlines(), actual.splitlines(), 310 | fromfile='a/source.go', tofile='b/source.go', lineterm='' 311 | ) 312 | for line in udiff: 313 | print(line) 314 | raise AssertionError('migrated source does not match expected') 315 | logging.warn('Test case %d/%d OK', i+1, len(_MIGRATOR_TESTS)) 316 | 317 | 318 | _MIGRATOR_TESTS = ( 319 | (""" 320 | \t\t\t&cli.StringSlice{"a", "b", "c"}, 321 | """, """ 322 | \t\t\tcli.NewStringSlice("a", "b", "c"), 323 | """), 324 | (""" 325 | \t\tcli.IntFlag{ 326 | \t\t\tName: "yep", 327 | \t\t\tValue: 3, 328 | \t\t} 329 | """, """ 330 | \t\t&cli.IntFlag{ 331 | \t\t\tName: "yep", 332 | \t\t\tValue: 3, 333 | \t\t} 334 | """), 335 | (""" 336 | \t\tapp.Commands = []cli.Command{ 337 | \t\t\t{ 338 | \t\t\t\tName: "whatebbs", 339 | \t\t\t}, 340 | \t\t} 341 | """, """ 342 | \t\tapp.Commands = []*cli.Command{ 343 | \t\t\t{ 344 | \t\t\t\tName: "whatebbs", 345 | \t\t\t}, 346 | \t\t} 347 | """), 348 | (""" 349 | \t\tapp.Commands = []cli.Command{ 350 | \t\t\tcli.Command{ 351 | \t\t\t\tName: "whatebbs", 352 | \t\t\t}, 353 | \t\t} 354 | """, """ 355 | \t\tapp.Commands = []*cli.Command{ 356 | \t\t\t&cli.Command{ 357 | \t\t\t\tName: "whatebbs", 358 | \t\t\t}, 359 | \t\t} 360 | """), 361 | (""" 362 | \t"github.com/codegangsta/cli" 363 | \t"github.com/urfave/cli" 364 | \t"gopkg.in/codegangsta/cli" 365 | \t"gopkg.in/codegangsta/cli.v1" 366 | \t"gopkg.in/urfave/cli" 367 | \t"gopkg.in/urfave/cli.v1" 368 | """, """ 369 | \t"gopkg.in/urfave/cli.v2" 370 | \t"gopkg.in/urfave/cli.v2" 371 | \t"gopkg.in/urfave/cli.v2" 372 | \t"gopkg.in/urfave/cli.v2" 373 | \t"gopkg.in/urfave/cli.v2" 374 | \t"gopkg.in/urfave/cli.v2" 375 | """), 376 | (""" 377 | \t\t\t\treturn cli.NewExitError("foo whatebber", 9) 378 | """, """ 379 | \t\t\t\treturn cli.Exit("foo whatebber", 9) 380 | """), 381 | (""" 382 | \t\t\tapp.Flags = []cli.Flag{ 383 | \t\t\t\tcli.StringFlag{ 384 | \t\t\t\t\tName: "aha", 385 | \t\t\t\t}, 386 | \t\t\t\tcli.BoolTFlag{ 387 | \t\t\t\t\tName: "blurp", 388 | \t\t\t\t}, 389 | \t\t\t} 390 | """, """ 391 | \t\t\tapp.Flags = []cli.Flag{ 392 | \t\t\t\t&cli.StringFlag{ 393 | \t\t\t\t\tName: "aha", 394 | \t\t\t\t}, 395 | \t\t\t\t&cli.BoolFlag{Value: true, 396 | \t\t\t\t\tName: "blurp", 397 | \t\t\t\t}, 398 | \t\t\t} 399 | """), 400 | (""" 401 | \t\t\tAction = func(c *cli.Context) error { 402 | \t\t\t\tif c.Args()[4] == "meep" { 403 | \t\t\t\t\treturn nil 404 | \t\t\t\t} 405 | \t\t\t\treturn errors.New("mope") 406 | \t\t\t} 407 | """, """ 408 | \t\t\tAction = func(c *cli.Context) error { 409 | \t\t\t\tif c.Args().Get(4) == "meep" { 410 | \t\t\t\t\treturn nil 411 | \t\t\t\t} 412 | \t\t\t\treturn errors.New("mope") 413 | \t\t\t} 414 | """), 415 | (""" 416 | \t\tapp.Flags = []cli.Flag{ 417 | \t\t\tcli.StringFlag{ 418 | \t\t\t\tName: "toots", 419 | \t\t\t\tEnvVar: "TOOTS,TOOTERS", 420 | \t\t\t}, 421 | \t\t} 422 | """, """ 423 | \t\tapp.Flags = []cli.Flag{ 424 | \t\t\t&cli.StringFlag{ 425 | \t\t\t\tName: "toots", 426 | \t\t\t\tEnvVars: []string{"TOOTS", "TOOTERS"}, 427 | \t\t\t}, 428 | \t\t} 429 | """), 430 | (""" 431 | \t\tapp.Flags = []cli.Flag{ 432 | \t\t\tcli.StringFlag{ 433 | \t\t\t\tName: "t, tootles, toots", 434 | \t\t\t}, 435 | \t\t} 436 | """, """ 437 | \t\tapp.Flags = []cli.Flag{ 438 | \t\t\t&cli.StringFlag{ 439 | \t\t\t\tName: "tootles", Aliases: []string{"toots", "t"}, 440 | \t\t\t}, 441 | \t\t} 442 | """), 443 | (""" 444 | \t\tapp := cli.NewApp() 445 | \t\tapp.HideHelp = true 446 | """, """ 447 | \t\tapp := (&cli.App{}) 448 | \t\tapp.HideHelp = true 449 | """) 450 | ) 451 | 452 | 453 | if __name__ == '__main__': 454 | sys.exit(main()) 455 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/agent.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // AgentCheck represents a check known to the agent 8 | type AgentCheck struct { 9 | Node string 10 | CheckID string 11 | Name string 12 | Status string 13 | Notes string 14 | Output string 15 | ServiceID string 16 | ServiceName string 17 | } 18 | 19 | // AgentService represents a service known to the agent 20 | type AgentService struct { 21 | ID string 22 | Service string 23 | Tags []string 24 | Port int 25 | Address string 26 | EnableTagOverride bool 27 | } 28 | 29 | // AgentMember represents a cluster member known to the agent 30 | type AgentMember struct { 31 | Name string 32 | Addr string 33 | Port uint16 34 | Tags map[string]string 35 | Status int 36 | ProtocolMin uint8 37 | ProtocolMax uint8 38 | ProtocolCur uint8 39 | DelegateMin uint8 40 | DelegateMax uint8 41 | DelegateCur uint8 42 | } 43 | 44 | // AgentServiceRegistration is used to register a new service 45 | type AgentServiceRegistration struct { 46 | ID string `json:",omitempty"` 47 | Name string `json:",omitempty"` 48 | Tags []string `json:",omitempty"` 49 | Port int `json:",omitempty"` 50 | Address string `json:",omitempty"` 51 | EnableTagOverride bool `json:",omitempty"` 52 | Check *AgentServiceCheck 53 | Checks AgentServiceChecks 54 | } 55 | 56 | // AgentCheckRegistration is used to register a new check 57 | type AgentCheckRegistration struct { 58 | ID string `json:",omitempty"` 59 | Name string `json:",omitempty"` 60 | Notes string `json:",omitempty"` 61 | ServiceID string `json:",omitempty"` 62 | AgentServiceCheck 63 | } 64 | 65 | // AgentServiceCheck is used to define a node or service level check 66 | type AgentServiceCheck struct { 67 | Script string `json:",omitempty"` 68 | DockerContainerID string `json:",omitempty"` 69 | Shell string `json:",omitempty"` // Only supported for Docker. 70 | Interval string `json:",omitempty"` 71 | Timeout string `json:",omitempty"` 72 | TTL string `json:",omitempty"` 73 | HTTP string `json:",omitempty"` 74 | TCP string `json:",omitempty"` 75 | Status string `json:",omitempty"` 76 | 77 | // In Consul 0.7 and later, checks that are associated with a service 78 | // may also contain this optional DeregisterCriticalServiceAfter field, 79 | // which is a timeout in the same Go time format as Interval and TTL. If 80 | // a check is in the critical state for more than this configured value, 81 | // then its associated service (and all of its associated checks) will 82 | // automatically be deregistered. 83 | DeregisterCriticalServiceAfter string `json:",omitempty"` 84 | } 85 | type AgentServiceChecks []*AgentServiceCheck 86 | 87 | // Agent can be used to query the Agent endpoints 88 | type Agent struct { 89 | c *Client 90 | 91 | // cache the node name 92 | nodeName string 93 | } 94 | 95 | // Agent returns a handle to the agent endpoints 96 | func (c *Client) Agent() *Agent { 97 | return &Agent{c: c} 98 | } 99 | 100 | // Self is used to query the agent we are speaking to for 101 | // information about itself 102 | func (a *Agent) Self() (map[string]map[string]interface{}, error) { 103 | r := a.c.newRequest("GET", "/v1/agent/self") 104 | _, resp, err := requireOK(a.c.doRequest(r)) 105 | if err != nil { 106 | return nil, err 107 | } 108 | defer resp.Body.Close() 109 | 110 | var out map[string]map[string]interface{} 111 | if err := decodeBody(resp, &out); err != nil { 112 | return nil, err 113 | } 114 | return out, nil 115 | } 116 | 117 | // NodeName is used to get the node name of the agent 118 | func (a *Agent) NodeName() (string, error) { 119 | if a.nodeName != "" { 120 | return a.nodeName, nil 121 | } 122 | info, err := a.Self() 123 | if err != nil { 124 | return "", err 125 | } 126 | name := info["Config"]["NodeName"].(string) 127 | a.nodeName = name 128 | return name, nil 129 | } 130 | 131 | // Checks returns the locally registered checks 132 | func (a *Agent) Checks() (map[string]*AgentCheck, error) { 133 | r := a.c.newRequest("GET", "/v1/agent/checks") 134 | _, resp, err := requireOK(a.c.doRequest(r)) 135 | if err != nil { 136 | return nil, err 137 | } 138 | defer resp.Body.Close() 139 | 140 | var out map[string]*AgentCheck 141 | if err := decodeBody(resp, &out); err != nil { 142 | return nil, err 143 | } 144 | return out, nil 145 | } 146 | 147 | // Services returns the locally registered services 148 | func (a *Agent) Services() (map[string]*AgentService, error) { 149 | r := a.c.newRequest("GET", "/v1/agent/services") 150 | _, resp, err := requireOK(a.c.doRequest(r)) 151 | if err != nil { 152 | return nil, err 153 | } 154 | defer resp.Body.Close() 155 | 156 | var out map[string]*AgentService 157 | if err := decodeBody(resp, &out); err != nil { 158 | return nil, err 159 | } 160 | return out, nil 161 | } 162 | 163 | // Members returns the known gossip members. The WAN 164 | // flag can be used to query a server for WAN members. 165 | func (a *Agent) Members(wan bool) ([]*AgentMember, error) { 166 | r := a.c.newRequest("GET", "/v1/agent/members") 167 | if wan { 168 | r.params.Set("wan", "1") 169 | } 170 | _, resp, err := requireOK(a.c.doRequest(r)) 171 | if err != nil { 172 | return nil, err 173 | } 174 | defer resp.Body.Close() 175 | 176 | var out []*AgentMember 177 | if err := decodeBody(resp, &out); err != nil { 178 | return nil, err 179 | } 180 | return out, nil 181 | } 182 | 183 | // ServiceRegister is used to register a new service with 184 | // the local agent 185 | func (a *Agent) ServiceRegister(service *AgentServiceRegistration) error { 186 | r := a.c.newRequest("PUT", "/v1/agent/service/register") 187 | r.obj = service 188 | _, resp, err := requireOK(a.c.doRequest(r)) 189 | if err != nil { 190 | return err 191 | } 192 | resp.Body.Close() 193 | return nil 194 | } 195 | 196 | // ServiceDeregister is used to deregister a service with 197 | // the local agent 198 | func (a *Agent) ServiceDeregister(serviceID string) error { 199 | r := a.c.newRequest("PUT", "/v1/agent/service/deregister/"+serviceID) 200 | _, resp, err := requireOK(a.c.doRequest(r)) 201 | if err != nil { 202 | return err 203 | } 204 | resp.Body.Close() 205 | return nil 206 | } 207 | 208 | // PassTTL is used to set a TTL check to the passing state. 209 | // 210 | // DEPRECATION NOTICE: This interface is deprecated in favor of UpdateTTL(). 211 | // The client interface will be removed in 0.8 or changed to use 212 | // UpdateTTL()'s endpoint and the server endpoints will be removed in 0.9. 213 | func (a *Agent) PassTTL(checkID, note string) error { 214 | return a.updateTTL(checkID, note, "pass") 215 | } 216 | 217 | // WarnTTL is used to set a TTL check to the warning state. 218 | // 219 | // DEPRECATION NOTICE: This interface is deprecated in favor of UpdateTTL(). 220 | // The client interface will be removed in 0.8 or changed to use 221 | // UpdateTTL()'s endpoint and the server endpoints will be removed in 0.9. 222 | func (a *Agent) WarnTTL(checkID, note string) error { 223 | return a.updateTTL(checkID, note, "warn") 224 | } 225 | 226 | // FailTTL is used to set a TTL check to the failing state. 227 | // 228 | // DEPRECATION NOTICE: This interface is deprecated in favor of UpdateTTL(). 229 | // The client interface will be removed in 0.8 or changed to use 230 | // UpdateTTL()'s endpoint and the server endpoints will be removed in 0.9. 231 | func (a *Agent) FailTTL(checkID, note string) error { 232 | return a.updateTTL(checkID, note, "fail") 233 | } 234 | 235 | // updateTTL is used to update the TTL of a check. This is the internal 236 | // method that uses the old API that's present in Consul versions prior to 237 | // 0.6.4. Since Consul didn't have an analogous "update" API before it seemed 238 | // ok to break this (former) UpdateTTL in favor of the new UpdateTTL below, 239 | // but keep the old Pass/Warn/Fail methods using the old API under the hood. 240 | // 241 | // DEPRECATION NOTICE: This interface is deprecated in favor of UpdateTTL(). 242 | // The client interface will be removed in 0.8 and the server endpoints will 243 | // be removed in 0.9. 244 | func (a *Agent) updateTTL(checkID, note, status string) error { 245 | switch status { 246 | case "pass": 247 | case "warn": 248 | case "fail": 249 | default: 250 | return fmt.Errorf("Invalid status: %s", status) 251 | } 252 | endpoint := fmt.Sprintf("/v1/agent/check/%s/%s", status, checkID) 253 | r := a.c.newRequest("PUT", endpoint) 254 | r.params.Set("note", note) 255 | _, resp, err := requireOK(a.c.doRequest(r)) 256 | if err != nil { 257 | return err 258 | } 259 | resp.Body.Close() 260 | return nil 261 | } 262 | 263 | // checkUpdate is the payload for a PUT for a check update. 264 | type checkUpdate struct { 265 | // Status is one of the api.Health* states: HealthPassing 266 | // ("passing"), HealthWarning ("warning"), or HealthCritical 267 | // ("critical"). 268 | Status string 269 | 270 | // Output is the information to post to the UI for operators as the 271 | // output of the process that decided to hit the TTL check. This is 272 | // different from the note field that's associated with the check 273 | // itself. 274 | Output string 275 | } 276 | 277 | // UpdateTTL is used to update the TTL of a check. This uses the newer API 278 | // that was introduced in Consul 0.6.4 and later. We translate the old status 279 | // strings for compatibility (though a newer version of Consul will still be 280 | // required to use this API). 281 | func (a *Agent) UpdateTTL(checkID, output, status string) error { 282 | switch status { 283 | case "pass", HealthPassing: 284 | status = HealthPassing 285 | case "warn", HealthWarning: 286 | status = HealthWarning 287 | case "fail", HealthCritical: 288 | status = HealthCritical 289 | default: 290 | return fmt.Errorf("Invalid status: %s", status) 291 | } 292 | 293 | endpoint := fmt.Sprintf("/v1/agent/check/update/%s", checkID) 294 | r := a.c.newRequest("PUT", endpoint) 295 | r.obj = &checkUpdate{ 296 | Status: status, 297 | Output: output, 298 | } 299 | 300 | _, resp, err := requireOK(a.c.doRequest(r)) 301 | if err != nil { 302 | return err 303 | } 304 | resp.Body.Close() 305 | return nil 306 | } 307 | 308 | // CheckRegister is used to register a new check with 309 | // the local agent 310 | func (a *Agent) CheckRegister(check *AgentCheckRegistration) error { 311 | r := a.c.newRequest("PUT", "/v1/agent/check/register") 312 | r.obj = check 313 | _, resp, err := requireOK(a.c.doRequest(r)) 314 | if err != nil { 315 | return err 316 | } 317 | resp.Body.Close() 318 | return nil 319 | } 320 | 321 | // CheckDeregister is used to deregister a check with 322 | // the local agent 323 | func (a *Agent) CheckDeregister(checkID string) error { 324 | r := a.c.newRequest("PUT", "/v1/agent/check/deregister/"+checkID) 325 | _, resp, err := requireOK(a.c.doRequest(r)) 326 | if err != nil { 327 | return err 328 | } 329 | resp.Body.Close() 330 | return nil 331 | } 332 | 333 | // Join is used to instruct the agent to attempt a join to 334 | // another cluster member 335 | func (a *Agent) Join(addr string, wan bool) error { 336 | r := a.c.newRequest("PUT", "/v1/agent/join/"+addr) 337 | if wan { 338 | r.params.Set("wan", "1") 339 | } 340 | _, resp, err := requireOK(a.c.doRequest(r)) 341 | if err != nil { 342 | return err 343 | } 344 | resp.Body.Close() 345 | return nil 346 | } 347 | 348 | // ForceLeave is used to have the agent eject a failed node 349 | func (a *Agent) ForceLeave(node string) error { 350 | r := a.c.newRequest("PUT", "/v1/agent/force-leave/"+node) 351 | _, resp, err := requireOK(a.c.doRequest(r)) 352 | if err != nil { 353 | return err 354 | } 355 | resp.Body.Close() 356 | return nil 357 | } 358 | 359 | // EnableServiceMaintenance toggles service maintenance mode on 360 | // for the given service ID. 361 | func (a *Agent) EnableServiceMaintenance(serviceID, reason string) error { 362 | r := a.c.newRequest("PUT", "/v1/agent/service/maintenance/"+serviceID) 363 | r.params.Set("enable", "true") 364 | r.params.Set("reason", reason) 365 | _, resp, err := requireOK(a.c.doRequest(r)) 366 | if err != nil { 367 | return err 368 | } 369 | resp.Body.Close() 370 | return nil 371 | } 372 | 373 | // DisableServiceMaintenance toggles service maintenance mode off 374 | // for the given service ID. 375 | func (a *Agent) DisableServiceMaintenance(serviceID string) error { 376 | r := a.c.newRequest("PUT", "/v1/agent/service/maintenance/"+serviceID) 377 | r.params.Set("enable", "false") 378 | _, resp, err := requireOK(a.c.doRequest(r)) 379 | if err != nil { 380 | return err 381 | } 382 | resp.Body.Close() 383 | return nil 384 | } 385 | 386 | // EnableNodeMaintenance toggles node maintenance mode on for the 387 | // agent we are connected to. 388 | func (a *Agent) EnableNodeMaintenance(reason string) error { 389 | r := a.c.newRequest("PUT", "/v1/agent/maintenance") 390 | r.params.Set("enable", "true") 391 | r.params.Set("reason", reason) 392 | _, resp, err := requireOK(a.c.doRequest(r)) 393 | if err != nil { 394 | return err 395 | } 396 | resp.Body.Close() 397 | return nil 398 | } 399 | 400 | // DisableNodeMaintenance toggles node maintenance mode off for the 401 | // agent we are connected to. 402 | func (a *Agent) DisableNodeMaintenance() error { 403 | r := a.c.newRequest("PUT", "/v1/agent/maintenance") 404 | r.params.Set("enable", "false") 405 | _, resp, err := requireOK(a.c.doRequest(r)) 406 | if err != nil { 407 | return err 408 | } 409 | resp.Body.Close() 410 | return nil 411 | } 412 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/consul/api/kv.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "net/http" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | // KVPair is used to represent a single K/V entry 13 | type KVPair struct { 14 | // Key is the name of the key. It is also part of the URL path when accessed 15 | // via the API. 16 | Key string 17 | 18 | // CreateIndex holds the index corresponding the creation of this KVPair. This 19 | // is a read-only field. 20 | CreateIndex uint64 21 | 22 | // ModifyIndex is used for the Check-And-Set operations and can also be fed 23 | // back into the WaitIndex of the QueryOptions in order to perform blocking 24 | // queries. 25 | ModifyIndex uint64 26 | 27 | // LockIndex holds the index corresponding to a lock on this key, if any. This 28 | // is a read-only field. 29 | LockIndex uint64 30 | 31 | // Flags are any user-defined flags on the key. It is up to the implementer 32 | // to check these values, since Consul does not treat them specially. 33 | Flags uint64 34 | 35 | // Value is the value for the key. This can be any value, but it will be 36 | // base64 encoded upon transport. 37 | Value []byte 38 | 39 | // Session is a string representing the ID of the session. Any other 40 | // interactions with this key over the same session must specify the same 41 | // session ID. 42 | Session string 43 | } 44 | 45 | // KVPairs is a list of KVPair objects 46 | type KVPairs []*KVPair 47 | 48 | // KVOp constants give possible operations available in a KVTxn. 49 | type KVOp string 50 | 51 | const ( 52 | KVSet KVOp = "set" 53 | KVDelete = "delete" 54 | KVDeleteCAS = "delete-cas" 55 | KVDeleteTree = "delete-tree" 56 | KVCAS = "cas" 57 | KVLock = "lock" 58 | KVUnlock = "unlock" 59 | KVGet = "get" 60 | KVGetTree = "get-tree" 61 | KVCheckSession = "check-session" 62 | KVCheckIndex = "check-index" 63 | ) 64 | 65 | // KVTxnOp defines a single operation inside a transaction. 66 | type KVTxnOp struct { 67 | Verb string 68 | Key string 69 | Value []byte 70 | Flags uint64 71 | Index uint64 72 | Session string 73 | } 74 | 75 | // KVTxnOps defines a set of operations to be performed inside a single 76 | // transaction. 77 | type KVTxnOps []*KVTxnOp 78 | 79 | // KVTxnResponse has the outcome of a transaction. 80 | type KVTxnResponse struct { 81 | Results []*KVPair 82 | Errors TxnErrors 83 | } 84 | 85 | // KV is used to manipulate the K/V API 86 | type KV struct { 87 | c *Client 88 | } 89 | 90 | // KV is used to return a handle to the K/V apis 91 | func (c *Client) KV() *KV { 92 | return &KV{c} 93 | } 94 | 95 | // Get is used to lookup a single key 96 | func (k *KV) Get(key string, q *QueryOptions) (*KVPair, *QueryMeta, error) { 97 | resp, qm, err := k.getInternal(key, nil, q) 98 | if err != nil { 99 | return nil, nil, err 100 | } 101 | if resp == nil { 102 | return nil, qm, nil 103 | } 104 | defer resp.Body.Close() 105 | 106 | var entries []*KVPair 107 | if err := decodeBody(resp, &entries); err != nil { 108 | return nil, nil, err 109 | } 110 | if len(entries) > 0 { 111 | return entries[0], qm, nil 112 | } 113 | return nil, qm, nil 114 | } 115 | 116 | // List is used to lookup all keys under a prefix 117 | func (k *KV) List(prefix string, q *QueryOptions) (KVPairs, *QueryMeta, error) { 118 | resp, qm, err := k.getInternal(prefix, map[string]string{"recurse": ""}, q) 119 | if err != nil { 120 | return nil, nil, err 121 | } 122 | if resp == nil { 123 | return nil, qm, nil 124 | } 125 | defer resp.Body.Close() 126 | 127 | var entries []*KVPair 128 | if err := decodeBody(resp, &entries); err != nil { 129 | return nil, nil, err 130 | } 131 | return entries, qm, nil 132 | } 133 | 134 | // Keys is used to list all the keys under a prefix. Optionally, 135 | // a separator can be used to limit the responses. 136 | func (k *KV) Keys(prefix, separator string, q *QueryOptions) ([]string, *QueryMeta, error) { 137 | params := map[string]string{"keys": ""} 138 | if separator != "" { 139 | params["separator"] = separator 140 | } 141 | resp, qm, err := k.getInternal(prefix, params, q) 142 | if err != nil { 143 | return nil, nil, err 144 | } 145 | if resp == nil { 146 | return nil, qm, nil 147 | } 148 | defer resp.Body.Close() 149 | 150 | var entries []string 151 | if err := decodeBody(resp, &entries); err != nil { 152 | return nil, nil, err 153 | } 154 | return entries, qm, nil 155 | } 156 | 157 | func (k *KV) getInternal(key string, params map[string]string, q *QueryOptions) (*http.Response, *QueryMeta, error) { 158 | r := k.c.newRequest("GET", "/v1/kv/"+key) 159 | r.setQueryOptions(q) 160 | for param, val := range params { 161 | r.params.Set(param, val) 162 | } 163 | rtt, resp, err := k.c.doRequest(r) 164 | if err != nil { 165 | return nil, nil, err 166 | } 167 | 168 | qm := &QueryMeta{} 169 | parseQueryMeta(resp, qm) 170 | qm.RequestTime = rtt 171 | 172 | if resp.StatusCode == 404 { 173 | resp.Body.Close() 174 | return nil, qm, nil 175 | } else if resp.StatusCode != 200 { 176 | resp.Body.Close() 177 | return nil, nil, fmt.Errorf("Unexpected response code: %d", resp.StatusCode) 178 | } 179 | return resp, qm, nil 180 | } 181 | 182 | // Put is used to write a new value. Only the 183 | // Key, Flags and Value is respected. 184 | func (k *KV) Put(p *KVPair, q *WriteOptions) (*WriteMeta, error) { 185 | params := make(map[string]string, 1) 186 | if p.Flags != 0 { 187 | params["flags"] = strconv.FormatUint(p.Flags, 10) 188 | } 189 | _, wm, err := k.put(p.Key, params, p.Value, q) 190 | return wm, err 191 | } 192 | 193 | // CAS is used for a Check-And-Set operation. The Key, 194 | // ModifyIndex, Flags and Value are respected. Returns true 195 | // on success or false on failures. 196 | func (k *KV) CAS(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) { 197 | params := make(map[string]string, 2) 198 | if p.Flags != 0 { 199 | params["flags"] = strconv.FormatUint(p.Flags, 10) 200 | } 201 | params["cas"] = strconv.FormatUint(p.ModifyIndex, 10) 202 | return k.put(p.Key, params, p.Value, q) 203 | } 204 | 205 | // Acquire is used for a lock acquisition operation. The Key, 206 | // Flags, Value and Session are respected. Returns true 207 | // on success or false on failures. 208 | func (k *KV) Acquire(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) { 209 | params := make(map[string]string, 2) 210 | if p.Flags != 0 { 211 | params["flags"] = strconv.FormatUint(p.Flags, 10) 212 | } 213 | params["acquire"] = p.Session 214 | return k.put(p.Key, params, p.Value, q) 215 | } 216 | 217 | // Release is used for a lock release operation. The Key, 218 | // Flags, Value and Session are respected. Returns true 219 | // on success or false on failures. 220 | func (k *KV) Release(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) { 221 | params := make(map[string]string, 2) 222 | if p.Flags != 0 { 223 | params["flags"] = strconv.FormatUint(p.Flags, 10) 224 | } 225 | params["release"] = p.Session 226 | return k.put(p.Key, params, p.Value, q) 227 | } 228 | 229 | func (k *KV) put(key string, params map[string]string, body []byte, q *WriteOptions) (bool, *WriteMeta, error) { 230 | if len(key) > 0 && key[0] == '/' { 231 | return false, nil, fmt.Errorf("Invalid key. Key must not begin with a '/': %s", key) 232 | } 233 | 234 | r := k.c.newRequest("PUT", "/v1/kv/"+key) 235 | r.setWriteOptions(q) 236 | for param, val := range params { 237 | r.params.Set(param, val) 238 | } 239 | r.body = bytes.NewReader(body) 240 | rtt, resp, err := requireOK(k.c.doRequest(r)) 241 | if err != nil { 242 | return false, nil, err 243 | } 244 | defer resp.Body.Close() 245 | 246 | qm := &WriteMeta{} 247 | qm.RequestTime = rtt 248 | 249 | var buf bytes.Buffer 250 | if _, err := io.Copy(&buf, resp.Body); err != nil { 251 | return false, nil, fmt.Errorf("Failed to read response: %v", err) 252 | } 253 | res := strings.Contains(string(buf.Bytes()), "true") 254 | return res, qm, nil 255 | } 256 | 257 | // Delete is used to delete a single key 258 | func (k *KV) Delete(key string, w *WriteOptions) (*WriteMeta, error) { 259 | _, qm, err := k.deleteInternal(key, nil, w) 260 | return qm, err 261 | } 262 | 263 | // DeleteCAS is used for a Delete Check-And-Set operation. The Key 264 | // and ModifyIndex are respected. Returns true on success or false on failures. 265 | func (k *KV) DeleteCAS(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) { 266 | params := map[string]string{ 267 | "cas": strconv.FormatUint(p.ModifyIndex, 10), 268 | } 269 | return k.deleteInternal(p.Key, params, q) 270 | } 271 | 272 | // DeleteTree is used to delete all keys under a prefix 273 | func (k *KV) DeleteTree(prefix string, w *WriteOptions) (*WriteMeta, error) { 274 | _, qm, err := k.deleteInternal(prefix, map[string]string{"recurse": ""}, w) 275 | return qm, err 276 | } 277 | 278 | func (k *KV) deleteInternal(key string, params map[string]string, q *WriteOptions) (bool, *WriteMeta, error) { 279 | r := k.c.newRequest("DELETE", "/v1/kv/"+key) 280 | r.setWriteOptions(q) 281 | for param, val := range params { 282 | r.params.Set(param, val) 283 | } 284 | rtt, resp, err := requireOK(k.c.doRequest(r)) 285 | if err != nil { 286 | return false, nil, err 287 | } 288 | defer resp.Body.Close() 289 | 290 | qm := &WriteMeta{} 291 | qm.RequestTime = rtt 292 | 293 | var buf bytes.Buffer 294 | if _, err := io.Copy(&buf, resp.Body); err != nil { 295 | return false, nil, fmt.Errorf("Failed to read response: %v", err) 296 | } 297 | res := strings.Contains(string(buf.Bytes()), "true") 298 | return res, qm, nil 299 | } 300 | 301 | // TxnOp is the internal format we send to Consul. It's not specific to KV, 302 | // though currently only KV operations are supported. 303 | type TxnOp struct { 304 | KV *KVTxnOp 305 | } 306 | 307 | // TxnOps is a list of transaction operations. 308 | type TxnOps []*TxnOp 309 | 310 | // TxnResult is the internal format we receive from Consul. 311 | type TxnResult struct { 312 | KV *KVPair 313 | } 314 | 315 | // TxnResults is a list of TxnResult objects. 316 | type TxnResults []*TxnResult 317 | 318 | // TxnError is used to return information about an operation in a transaction. 319 | type TxnError struct { 320 | OpIndex int 321 | What string 322 | } 323 | 324 | // TxnErrors is a list of TxnError objects. 325 | type TxnErrors []*TxnError 326 | 327 | // TxnResponse is the internal format we receive from Consul. 328 | type TxnResponse struct { 329 | Results TxnResults 330 | Errors TxnErrors 331 | } 332 | 333 | // Txn is used to apply multiple KV operations in a single, atomic transaction. 334 | // 335 | // Note that Go will perform the required base64 encoding on the values 336 | // automatically because the type is a byte slice. Transactions are defined as a 337 | // list of operations to perform, using the KVOp constants and KVTxnOp structure 338 | // to define operations. If any operation fails, none of the changes are applied 339 | // to the state store. Note that this hides the internal raw transaction interface 340 | // and munges the input and output types into KV-specific ones for ease of use. 341 | // If there are more non-KV operations in the future we may break out a new 342 | // transaction API client, but it will be easy to keep this KV-specific variant 343 | // supported. 344 | // 345 | // Even though this is generally a write operation, we take a QueryOptions input 346 | // and return a QueryMeta output. If the transaction contains only read ops, then 347 | // Consul will fast-path it to a different endpoint internally which supports 348 | // consistency controls, but not blocking. If there are write operations then 349 | // the request will always be routed through raft and any consistency settings 350 | // will be ignored. 351 | // 352 | // Here's an example: 353 | // 354 | // ops := KVTxnOps{ 355 | // &KVTxnOp{ 356 | // Verb: KVLock, 357 | // Key: "test/lock", 358 | // Session: "adf4238a-882b-9ddc-4a9d-5b6758e4159e", 359 | // Value: []byte("hello"), 360 | // }, 361 | // &KVTxnOp{ 362 | // Verb: KVGet, 363 | // Key: "another/key", 364 | // }, 365 | // } 366 | // ok, response, _, err := kv.Txn(&ops, nil) 367 | // 368 | // If there is a problem making the transaction request then an error will be 369 | // returned. Otherwise, the ok value will be true if the transaction succeeded 370 | // or false if it was rolled back. The response is a structured return value which 371 | // will have the outcome of the transaction. Its Results member will have entries 372 | // for each operation. Deleted keys will have a nil entry in the, and to save 373 | // space, the Value of each key in the Results will be nil unless the operation 374 | // is a KVGet. If the transaction was rolled back, the Errors member will have 375 | // entries referencing the index of the operation that failed along with an error 376 | // message. 377 | func (k *KV) Txn(txn KVTxnOps, q *QueryOptions) (bool, *KVTxnResponse, *QueryMeta, error) { 378 | r := k.c.newRequest("PUT", "/v1/txn") 379 | r.setQueryOptions(q) 380 | 381 | // Convert into the internal format since this is an all-KV txn. 382 | ops := make(TxnOps, 0, len(txn)) 383 | for _, kvOp := range txn { 384 | ops = append(ops, &TxnOp{KV: kvOp}) 385 | } 386 | r.obj = ops 387 | rtt, resp, err := k.c.doRequest(r) 388 | if err != nil { 389 | return false, nil, nil, err 390 | } 391 | defer resp.Body.Close() 392 | 393 | qm := &QueryMeta{} 394 | parseQueryMeta(resp, qm) 395 | qm.RequestTime = rtt 396 | 397 | if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusConflict { 398 | var txnResp TxnResponse 399 | if err := decodeBody(resp, &txnResp); err != nil { 400 | return false, nil, nil, err 401 | } 402 | 403 | // Convert from the internal format. 404 | kvResp := KVTxnResponse{ 405 | Errors: txnResp.Errors, 406 | } 407 | for _, result := range txnResp.Results { 408 | kvResp.Results = append(kvResp.Results, result.KV) 409 | } 410 | return resp.StatusCode == http.StatusOK, &kvResp, qm, nil 411 | } 412 | 413 | var buf bytes.Buffer 414 | if _, err := io.Copy(&buf, resp.Body); err != nil { 415 | return false, nil, nil, fmt.Errorf("Failed to read response: %v", err) 416 | } 417 | return false, nil, nil, fmt.Errorf("Failed request: %s", buf.String()) 418 | } 419 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | **ATTN**: This project uses [semantic versioning](http://semver.org/). 4 | 5 | ## 2.0.0 - (unreleased 2.x series) 6 | ### Added 7 | - `NewStringSlice` and `NewIntSlice` for creating their related types 8 | - `Float64SliceFlag` for unmarshaling a list of floats from the user 9 | - `Context.Lineage` to get all contexts from current up to global 10 | - `Context.LocalFlagNames` to get the flag names from *only* the current context 11 | - `BoolFlag.Value` to handle both default-false and default-true 12 | 13 | ### Changed 14 | - `Context.FlagNames` now returns all flags in the context lineage 15 | - `Context.IsSet` now considers the full context lineage 16 | 17 | ### Removed 18 | - the ability to specify `&StringSlice{...string}` or `&IntSlice{...int}`. 19 | To migrate to the new API, you may choose to run [the migrator 20 | (python) script](./cli-v1-to-v2). 21 | - The optimistic reordering of arguments and flags introduced by 22 | https://github.com/codegangsta/cli/pull/36. This behavior only worked when 23 | all arguments appeared before all flags, but caused [weird issues with boolean 24 | flags](https://github.com/codegangsta/cli/issues/103) and [reordering of the 25 | arguments](https://github.com/codegangsta/cli/issues/355) when the user 26 | attempted to mix flags and arguments. Given the trade-offs we removed support 27 | for this reordering. 28 | - adapter code for deprecated `Action` func signature 29 | - deprecated `App.Author`, `App.Email`, and `Command.ShortName` fields 30 | - All `Context.Global*` methods, as the non-global versions now traverse up 31 | the context lineage automatically. 32 | - `Context.Parent` method, as this is now available via `Context.Lineage` 33 | - `BoolTFlag` and related code, as this is now available via `BoolFlag.Value` 34 | 35 | ## [Unreleased] - (1.x series) 36 | ### Added 37 | - Flag type code generation via `go generate` 38 | - Write to stderr and exit 1 if action returns non-nil error 39 | - Added support for TOML to the `altsrc` loader 40 | 41 | ### Changed 42 | - Raise minimum tested/supported Go version to 1.2+ 43 | 44 | ## [1.18.0] - 2016-06-27 45 | ### Added 46 | - `./runtests` test runner with coverage tracking by default 47 | - testing on OS X 48 | - testing on Windows 49 | - `UintFlag`, `Uint64Flag`, and `Int64Flag` types and supporting code 50 | 51 | ### Changed 52 | - Use spaces for alignment in help/usage output instead of tabs, making the 53 | output alignment consistent regardless of tab width 54 | 55 | ### Fixed 56 | - Printing of command aliases in help text 57 | - Printing of visible flags for both struct and struct pointer flags 58 | - Display the `help` subcommand when using `CommandCategories` 59 | - No longer swallows `panic`s that occur within the `Action`s themselves when 60 | detecting the signature of the `Action` field 61 | 62 | ## [1.17.0] - 2016-05-09 63 | ### Added 64 | - Pluggable flag-level help text rendering via `cli.DefaultFlagStringFunc` 65 | - `context.GlobalBoolT` was added as an analogue to `context.GlobalBool` 66 | - Support for hiding commands by setting `Hidden: true` -- this will hide the 67 | commands in help output 68 | 69 | ### Changed 70 | - `Float64Flag`, `IntFlag`, and `DurationFlag` default values are no longer 71 | quoted in help text output. 72 | - All flag types now include `(default: {value})` strings following usage when a 73 | default value can be (reasonably) detected. 74 | - `IntSliceFlag` and `StringSliceFlag` usage strings are now more consistent 75 | with non-slice flag types 76 | - Apps now exit with a code of 3 if an unknown subcommand is specified 77 | (previously they printed "No help topic for...", but still exited 0. This 78 | makes it easier to script around apps built using `cli` since they can trust 79 | that a 0 exit code indicated a successful execution. 80 | - cleanups based on [Go Report Card 81 | feedback](https://goreportcard.com/report/github.com/urfave/cli) 82 | 83 | ## [1.16.0] - 2016-05-02 84 | ### Added 85 | - `Hidden` field on all flag struct types to omit from generated help text 86 | 87 | ### Changed 88 | - `BashCompletionFlag` (`--enable-bash-completion`) is now omitted from 89 | generated help text via the `Hidden` field 90 | 91 | ### Fixed 92 | - handling of error values in `HandleAction` and `HandleExitCoder` 93 | 94 | ## [1.15.0] - 2016-04-30 95 | ### Added 96 | - This file! 97 | - Support for placeholders in flag usage strings 98 | - `App.Metadata` map for arbitrary data/state management 99 | - `Set` and `GlobalSet` methods on `*cli.Context` for altering values after 100 | parsing. 101 | - Support for nested lookup of dot-delimited keys in structures loaded from 102 | YAML. 103 | 104 | ### Changed 105 | - The `App.Action` and `Command.Action` now prefer a return signature of 106 | `func(*cli.Context) error`, as defined by `cli.ActionFunc`. If a non-nil 107 | `error` is returned, there may be two outcomes: 108 | - If the error fulfills `cli.ExitCoder`, then `os.Exit` will be called 109 | automatically 110 | - Else the error is bubbled up and returned from `App.Run` 111 | - Specifying an `Action` with the legacy return signature of 112 | `func(*cli.Context)` will produce a deprecation message to stderr 113 | - Specifying an `Action` that is not a `func` type will produce a non-zero exit 114 | from `App.Run` 115 | - Specifying an `Action` func that has an invalid (input) signature will 116 | produce a non-zero exit from `App.Run` 117 | 118 | ### Deprecated 119 | - 120 | `cli.App.RunAndExitOnError`, which should now be done by returning an error 121 | that fulfills `cli.ExitCoder` to `cli.App.Run`. 122 | - the legacy signature for 123 | `cli.App.Action` of `func(*cli.Context)`, which should now have a return 124 | signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`. 125 | 126 | ### Fixed 127 | - Added missing `*cli.Context.GlobalFloat64` method 128 | 129 | ## [1.14.0] - 2016-04-03 (backfilled 2016-04-25) 130 | ### Added 131 | - Codebeat badge 132 | - Support for categorization via `CategorizedHelp` and `Categories` on app. 133 | 134 | ### Changed 135 | - Use `filepath.Base` instead of `path.Base` in `Name` and `HelpName`. 136 | 137 | ### Fixed 138 | - Ensure version is not shown in help text when `HideVersion` set. 139 | 140 | ## [1.13.0] - 2016-03-06 (backfilled 2016-04-25) 141 | ### Added 142 | - YAML file input support. 143 | - `NArg` method on context. 144 | 145 | ## [1.12.0] - 2016-02-17 (backfilled 2016-04-25) 146 | ### Added 147 | - Custom usage error handling. 148 | - Custom text support in `USAGE` section of help output. 149 | - Improved help messages for empty strings. 150 | - AppVeyor CI configuration. 151 | 152 | ### Changed 153 | - Removed `panic` from default help printer func. 154 | - De-duping and optimizations. 155 | 156 | ### Fixed 157 | - Correctly handle `Before`/`After` at command level when no subcommands. 158 | - Case of literal `-` argument causing flag reordering. 159 | - Environment variable hints on Windows. 160 | - Docs updates. 161 | 162 | ## [1.11.1] - 2015-12-21 (backfilled 2016-04-25) 163 | ### Changed 164 | - Use `path.Base` in `Name` and `HelpName` 165 | - Export `GetName` on flag types. 166 | 167 | ### Fixed 168 | - Flag parsing when skipping is enabled. 169 | - Test output cleanup. 170 | - Move completion check to account for empty input case. 171 | 172 | ## [1.11.0] - 2015-11-15 (backfilled 2016-04-25) 173 | ### Added 174 | - Destination scan support for flags. 175 | - Testing against `tip` in Travis CI config. 176 | 177 | ### Changed 178 | - Go version in Travis CI config. 179 | 180 | ### Fixed 181 | - Removed redundant tests. 182 | - Use correct example naming in tests. 183 | 184 | ## [1.10.2] - 2015-10-29 (backfilled 2016-04-25) 185 | ### Fixed 186 | - Remove unused var in bash completion. 187 | 188 | ## [1.10.1] - 2015-10-21 (backfilled 2016-04-25) 189 | ### Added 190 | - Coverage and reference logos in README. 191 | 192 | ### Fixed 193 | - Use specified values in help and version parsing. 194 | - Only display app version and help message once. 195 | 196 | ## [1.10.0] - 2015-10-06 (backfilled 2016-04-25) 197 | ### Added 198 | - More tests for existing functionality. 199 | - `ArgsUsage` at app and command level for help text flexibility. 200 | 201 | ### Fixed 202 | - Honor `HideHelp` and `HideVersion` in `App.Run`. 203 | - Remove juvenile word from README. 204 | 205 | ## [1.9.0] - 2015-09-08 (backfilled 2016-04-25) 206 | ### Added 207 | - `FullName` on command with accompanying help output update. 208 | - Set default `$PROG` in bash completion. 209 | 210 | ### Changed 211 | - Docs formatting. 212 | 213 | ### Fixed 214 | - Removed self-referential imports in tests. 215 | 216 | ## [1.8.0] - 2015-06-30 (backfilled 2016-04-25) 217 | ### Added 218 | - Support for `Copyright` at app level. 219 | - `Parent` func at context level to walk up context lineage. 220 | 221 | ### Fixed 222 | - Global flag processing at top level. 223 | 224 | ## [1.7.1] - 2015-06-11 (backfilled 2016-04-25) 225 | ### Added 226 | - Aggregate errors from `Before`/`After` funcs. 227 | - Doc comments on flag structs. 228 | - Include non-global flags when checking version and help. 229 | - Travis CI config updates. 230 | 231 | ### Fixed 232 | - Ensure slice type flags have non-nil values. 233 | - Collect global flags from the full command hierarchy. 234 | - Docs prose. 235 | 236 | ## [1.7.0] - 2015-05-03 (backfilled 2016-04-25) 237 | ### Changed 238 | - `HelpPrinter` signature includes output writer. 239 | 240 | ### Fixed 241 | - Specify go 1.1+ in docs. 242 | - Set `Writer` when running command as app. 243 | 244 | ## [1.6.0] - 2015-03-23 (backfilled 2016-04-25) 245 | ### Added 246 | - Multiple author support. 247 | - `NumFlags` at context level. 248 | - `Aliases` at command level. 249 | 250 | ### Deprecated 251 | - `ShortName` at command level. 252 | 253 | ### Fixed 254 | - Subcommand help output. 255 | - Backward compatible support for deprecated `Author` and `Email` fields. 256 | - Docs regarding `Names`/`Aliases`. 257 | 258 | ## [1.5.0] - 2015-02-20 (backfilled 2016-04-25) 259 | ### Added 260 | - `After` hook func support at app and command level. 261 | 262 | ### Fixed 263 | - Use parsed context when running command as subcommand. 264 | - Docs prose. 265 | 266 | ## [1.4.1] - 2015-01-09 (backfilled 2016-04-25) 267 | ### Added 268 | - Support for hiding `-h / --help` flags, but not `help` subcommand. 269 | - Stop flag parsing after `--`. 270 | 271 | ### Fixed 272 | - Help text for generic flags to specify single value. 273 | - Use double quotes in output for defaults. 274 | - Use `ParseInt` instead of `ParseUint` for int environment var values. 275 | - Use `0` as base when parsing int environment var values. 276 | 277 | ## [1.4.0] - 2014-12-12 (backfilled 2016-04-25) 278 | ### Added 279 | - Support for environment variable lookup "cascade". 280 | - Support for `Stdout` on app for output redirection. 281 | 282 | ### Fixed 283 | - Print command help instead of app help in `ShowCommandHelp`. 284 | 285 | ## [1.3.1] - 2014-11-13 (backfilled 2016-04-25) 286 | ### Added 287 | - Docs and example code updates. 288 | 289 | ### Changed 290 | - Default `-v / --version` flag made optional. 291 | 292 | ## [1.3.0] - 2014-08-10 (backfilled 2016-04-25) 293 | ### Added 294 | - `FlagNames` at context level. 295 | - Exposed `VersionPrinter` var for more control over version output. 296 | - Zsh completion hook. 297 | - `AUTHOR` section in default app help template. 298 | - Contribution guidelines. 299 | - `DurationFlag` type. 300 | 301 | ## [1.2.0] - 2014-08-02 302 | ### Added 303 | - Support for environment variable defaults on flags plus tests. 304 | 305 | ## [1.1.0] - 2014-07-15 306 | ### Added 307 | - Bash completion. 308 | - Optional hiding of built-in help command. 309 | - Optional skipping of flag parsing at command level. 310 | - `Author`, `Email`, and `Compiled` metadata on app. 311 | - `Before` hook func support at app and command level. 312 | - `CommandNotFound` func support at app level. 313 | - Command reference available on context. 314 | - `GenericFlag` type. 315 | - `Float64Flag` type. 316 | - `BoolTFlag` type. 317 | - `IsSet` flag helper on context. 318 | - More flag lookup funcs at context level. 319 | - More tests & docs. 320 | 321 | ### Changed 322 | - Help template updates to account for presence/absence of flags. 323 | - Separated subcommand help template. 324 | - Exposed `HelpPrinter` var for more control over help output. 325 | 326 | ## [1.0.0] - 2013-11-01 327 | ### Added 328 | - `help` flag in default app flag set and each command flag set. 329 | - Custom handling of argument parsing errors. 330 | - Command lookup by name at app level. 331 | - `StringSliceFlag` type and supporting `StringSlice` type. 332 | - `IntSliceFlag` type and supporting `IntSlice` type. 333 | - Slice type flag lookups by name at context level. 334 | - Export of app and command help functions. 335 | - More tests & docs. 336 | 337 | ## 0.1.0 - 2013-07-22 338 | ### Added 339 | - Initial implementation. 340 | 341 | [Unreleased]: https://github.com/urfave/cli/compare/v1.18.0...HEAD 342 | [1.18.0]: https://github.com/urfave/cli/compare/v1.17.0...v1.18.0 343 | [1.17.0]: https://github.com/urfave/cli/compare/v1.16.0...v1.17.0 344 | [1.16.0]: https://github.com/urfave/cli/compare/v1.15.0...v1.16.0 345 | [1.15.0]: https://github.com/urfave/cli/compare/v1.14.0...v1.15.0 346 | [1.14.0]: https://github.com/urfave/cli/compare/v1.13.0...v1.14.0 347 | [1.13.0]: https://github.com/urfave/cli/compare/v1.12.0...v1.13.0 348 | [1.12.0]: https://github.com/urfave/cli/compare/v1.11.1...v1.12.0 349 | [1.11.1]: https://github.com/urfave/cli/compare/v1.11.0...v1.11.1 350 | [1.11.0]: https://github.com/urfave/cli/compare/v1.10.2...v1.11.0 351 | [1.10.2]: https://github.com/urfave/cli/compare/v1.10.1...v1.10.2 352 | [1.10.1]: https://github.com/urfave/cli/compare/v1.10.0...v1.10.1 353 | [1.10.0]: https://github.com/urfave/cli/compare/v1.9.0...v1.10.0 354 | [1.9.0]: https://github.com/urfave/cli/compare/v1.8.0...v1.9.0 355 | [1.8.0]: https://github.com/urfave/cli/compare/v1.7.1...v1.8.0 356 | [1.7.1]: https://github.com/urfave/cli/compare/v1.7.0...v1.7.1 357 | [1.7.0]: https://github.com/urfave/cli/compare/v1.6.0...v1.7.0 358 | [1.6.0]: https://github.com/urfave/cli/compare/v1.5.0...v1.6.0 359 | [1.5.0]: https://github.com/urfave/cli/compare/v1.4.1...v1.5.0 360 | [1.4.1]: https://github.com/urfave/cli/compare/v1.4.0...v1.4.1 361 | [1.4.0]: https://github.com/urfave/cli/compare/v1.3.1...v1.4.0 362 | [1.3.1]: https://github.com/urfave/cli/compare/v1.3.0...v1.3.1 363 | [1.3.0]: https://github.com/urfave/cli/compare/v1.2.0...v1.3.0 364 | [1.2.0]: https://github.com/urfave/cli/compare/v1.1.0...v1.2.0 365 | [1.1.0]: https://github.com/urfave/cli/compare/v1.0.0...v1.1.0 366 | [1.0.0]: https://github.com/urfave/cli/compare/v0.1.0...v1.0.0 367 | -------------------------------------------------------------------------------- /vendor/gopkg.in/urfave/cli.v2/flag_generated.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "flag" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | // WARNING: This file is generated! 10 | 11 | // BoolFlag is a flag with type bool 12 | type BoolFlag struct { 13 | Name string 14 | Aliases []string 15 | Usage string 16 | EnvVars []string 17 | Hidden bool 18 | Value bool 19 | DefaultText string 20 | Destination *bool 21 | } 22 | 23 | // String returns a readable representation of this value 24 | // (for usage defaults) 25 | func (f *BoolFlag) String() string { 26 | return FlagStringer(f) 27 | } 28 | 29 | // Names returns the names of the flag 30 | func (f *BoolFlag) Names() []string { 31 | return flagNames(f) 32 | } 33 | 34 | // Bool looks up the value of a local BoolFlag, returns 35 | // false if not found 36 | func (c *Context) Bool(name string) bool { 37 | if fs := lookupFlagSet(name, c); fs != nil { 38 | return lookupBool(name, fs) 39 | } 40 | return false 41 | } 42 | 43 | func lookupBool(name string, set *flag.FlagSet) bool { 44 | f := set.Lookup(name) 45 | if f != nil { 46 | parsed, err := strconv.ParseBool(f.Value.String()) 47 | if err != nil { 48 | return false 49 | } 50 | return parsed 51 | } 52 | return false 53 | } 54 | 55 | // DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) 56 | type DurationFlag struct { 57 | Name string 58 | Aliases []string 59 | Usage string 60 | EnvVars []string 61 | Hidden bool 62 | Value time.Duration 63 | DefaultText string 64 | Destination *time.Duration 65 | } 66 | 67 | // String returns a readable representation of this value 68 | // (for usage defaults) 69 | func (f *DurationFlag) String() string { 70 | return FlagStringer(f) 71 | } 72 | 73 | // Names returns the names of the flag 74 | func (f *DurationFlag) Names() []string { 75 | return flagNames(f) 76 | } 77 | 78 | // Duration looks up the value of a local DurationFlag, returns 79 | // 0 if not found 80 | func (c *Context) Duration(name string) time.Duration { 81 | if fs := lookupFlagSet(name, c); fs != nil { 82 | return lookupDuration(name, fs) 83 | } 84 | return 0 85 | } 86 | 87 | func lookupDuration(name string, set *flag.FlagSet) time.Duration { 88 | f := set.Lookup(name) 89 | if f != nil { 90 | parsed, err := time.ParseDuration(f.Value.String()) 91 | if err != nil { 92 | return 0 93 | } 94 | return parsed 95 | } 96 | return 0 97 | } 98 | 99 | // Float64Flag is a flag with type float64 100 | type Float64Flag struct { 101 | Name string 102 | Aliases []string 103 | Usage string 104 | EnvVars []string 105 | Hidden bool 106 | Value float64 107 | DefaultText string 108 | Destination *float64 109 | } 110 | 111 | // String returns a readable representation of this value 112 | // (for usage defaults) 113 | func (f *Float64Flag) String() string { 114 | return FlagStringer(f) 115 | } 116 | 117 | // Names returns the names of the flag 118 | func (f *Float64Flag) Names() []string { 119 | return flagNames(f) 120 | } 121 | 122 | // Float64 looks up the value of a local Float64Flag, returns 123 | // 0 if not found 124 | func (c *Context) Float64(name string) float64 { 125 | if fs := lookupFlagSet(name, c); fs != nil { 126 | return lookupFloat64(name, fs) 127 | } 128 | return 0 129 | } 130 | 131 | func lookupFloat64(name string, set *flag.FlagSet) float64 { 132 | f := set.Lookup(name) 133 | if f != nil { 134 | parsed, err := strconv.ParseFloat(f.Value.String(), 64) 135 | if err != nil { 136 | return 0 137 | } 138 | return parsed 139 | } 140 | return 0 141 | } 142 | 143 | // GenericFlag is a flag with type Generic 144 | type GenericFlag struct { 145 | Name string 146 | Aliases []string 147 | Usage string 148 | EnvVars []string 149 | Hidden bool 150 | Value Generic 151 | DefaultText string 152 | } 153 | 154 | // String returns a readable representation of this value 155 | // (for usage defaults) 156 | func (f *GenericFlag) String() string { 157 | return FlagStringer(f) 158 | } 159 | 160 | // Names returns the names of the flag 161 | func (f *GenericFlag) Names() []string { 162 | return flagNames(f) 163 | } 164 | 165 | // Generic looks up the value of a local GenericFlag, returns 166 | // nil if not found 167 | func (c *Context) Generic(name string) interface{} { 168 | if fs := lookupFlagSet(name, c); fs != nil { 169 | return lookupGeneric(name, fs) 170 | } 171 | return nil 172 | } 173 | 174 | func lookupGeneric(name string, set *flag.FlagSet) interface{} { 175 | f := set.Lookup(name) 176 | if f != nil { 177 | parsed, err := f.Value, error(nil) 178 | if err != nil { 179 | return nil 180 | } 181 | return parsed 182 | } 183 | return nil 184 | } 185 | 186 | // Int64Flag is a flag with type int64 187 | type Int64Flag struct { 188 | Name string 189 | Aliases []string 190 | Usage string 191 | EnvVars []string 192 | Hidden bool 193 | Value int64 194 | DefaultText string 195 | Destination *int64 196 | } 197 | 198 | // String returns a readable representation of this value 199 | // (for usage defaults) 200 | func (f *Int64Flag) String() string { 201 | return FlagStringer(f) 202 | } 203 | 204 | // Names returns the names of the flag 205 | func (f *Int64Flag) Names() []string { 206 | return flagNames(f) 207 | } 208 | 209 | // Int64 looks up the value of a local Int64Flag, returns 210 | // 0 if not found 211 | func (c *Context) Int64(name string) int64 { 212 | if fs := lookupFlagSet(name, c); fs != nil { 213 | return lookupInt64(name, fs) 214 | } 215 | return 0 216 | } 217 | 218 | func lookupInt64(name string, set *flag.FlagSet) int64 { 219 | f := set.Lookup(name) 220 | if f != nil { 221 | parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) 222 | if err != nil { 223 | return 0 224 | } 225 | return parsed 226 | } 227 | return 0 228 | } 229 | 230 | // IntFlag is a flag with type int 231 | type IntFlag struct { 232 | Name string 233 | Aliases []string 234 | Usage string 235 | EnvVars []string 236 | Hidden bool 237 | Value int 238 | DefaultText string 239 | Destination *int 240 | } 241 | 242 | // String returns a readable representation of this value 243 | // (for usage defaults) 244 | func (f *IntFlag) String() string { 245 | return FlagStringer(f) 246 | } 247 | 248 | // Names returns the names of the flag 249 | func (f *IntFlag) Names() []string { 250 | return flagNames(f) 251 | } 252 | 253 | // Int looks up the value of a local IntFlag, returns 254 | // 0 if not found 255 | func (c *Context) Int(name string) int { 256 | if fs := lookupFlagSet(name, c); fs != nil { 257 | return lookupInt(name, fs) 258 | } 259 | return 0 260 | } 261 | 262 | func lookupInt(name string, set *flag.FlagSet) int { 263 | f := set.Lookup(name) 264 | if f != nil { 265 | parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) 266 | if err != nil { 267 | return 0 268 | } 269 | return int(parsed) 270 | } 271 | return 0 272 | } 273 | 274 | // IntSliceFlag is a flag with type *IntSlice 275 | type IntSliceFlag struct { 276 | Name string 277 | Aliases []string 278 | Usage string 279 | EnvVars []string 280 | Hidden bool 281 | Value *IntSlice 282 | DefaultText string 283 | } 284 | 285 | // String returns a readable representation of this value 286 | // (for usage defaults) 287 | func (f *IntSliceFlag) String() string { 288 | return FlagStringer(f) 289 | } 290 | 291 | // Names returns the names of the flag 292 | func (f *IntSliceFlag) Names() []string { 293 | return flagNames(f) 294 | } 295 | 296 | // IntSlice looks up the value of a local IntSliceFlag, returns 297 | // nil if not found 298 | func (c *Context) IntSlice(name string) []int { 299 | if fs := lookupFlagSet(name, c); fs != nil { 300 | return lookupIntSlice(name, fs) 301 | } 302 | return nil 303 | } 304 | 305 | func lookupIntSlice(name string, set *flag.FlagSet) []int { 306 | f := set.Lookup(name) 307 | if f != nil { 308 | parsed, err := (f.Value.(*IntSlice)).Value(), error(nil) 309 | if err != nil { 310 | return nil 311 | } 312 | return parsed 313 | } 314 | return nil 315 | } 316 | 317 | // Int64SliceFlag is a flag with type *Int64Slice 318 | type Int64SliceFlag struct { 319 | Name string 320 | Aliases []string 321 | Usage string 322 | EnvVars []string 323 | Hidden bool 324 | Value *Int64Slice 325 | DefaultText string 326 | } 327 | 328 | // String returns a readable representation of this value 329 | // (for usage defaults) 330 | func (f *Int64SliceFlag) String() string { 331 | return FlagStringer(f) 332 | } 333 | 334 | // Names returns the names of the flag 335 | func (f *Int64SliceFlag) Names() []string { 336 | return flagNames(f) 337 | } 338 | 339 | // Int64Slice looks up the value of a local Int64SliceFlag, returns 340 | // nil if not found 341 | func (c *Context) Int64Slice(name string) []int64 { 342 | if fs := lookupFlagSet(name, c); fs != nil { 343 | return lookupInt64Slice(name, fs) 344 | } 345 | return nil 346 | } 347 | 348 | func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { 349 | f := set.Lookup(name) 350 | if f != nil { 351 | parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil) 352 | if err != nil { 353 | return nil 354 | } 355 | return parsed 356 | } 357 | return nil 358 | } 359 | 360 | // Float64SliceFlag is a flag with type *Float64Slice 361 | type Float64SliceFlag struct { 362 | Name string 363 | Aliases []string 364 | Usage string 365 | EnvVars []string 366 | Hidden bool 367 | Value *Float64Slice 368 | DefaultText string 369 | } 370 | 371 | // String returns a readable representation of this value 372 | // (for usage defaults) 373 | func (f *Float64SliceFlag) String() string { 374 | return FlagStringer(f) 375 | } 376 | 377 | // Names returns the names of the flag 378 | func (f *Float64SliceFlag) Names() []string { 379 | return flagNames(f) 380 | } 381 | 382 | // Float64Slice looks up the value of a local Float64SliceFlag, returns 383 | // nil if not found 384 | func (c *Context) Float64Slice(name string) []float64 { 385 | if fs := lookupFlagSet(name, c); fs != nil { 386 | return lookupFloat64Slice(name, fs) 387 | } 388 | return nil 389 | } 390 | 391 | func lookupFloat64Slice(name string, set *flag.FlagSet) []float64 { 392 | f := set.Lookup(name) 393 | if f != nil { 394 | parsed, err := (f.Value.(*Float64Slice)).Value(), error(nil) 395 | if err != nil { 396 | return nil 397 | } 398 | return parsed 399 | } 400 | return nil 401 | } 402 | 403 | // StringFlag is a flag with type string 404 | type StringFlag struct { 405 | Name string 406 | Aliases []string 407 | Usage string 408 | EnvVars []string 409 | Hidden bool 410 | Value string 411 | DefaultText string 412 | Destination *string 413 | } 414 | 415 | // String returns a readable representation of this value 416 | // (for usage defaults) 417 | func (f *StringFlag) String() string { 418 | return FlagStringer(f) 419 | } 420 | 421 | // Names returns the names of the flag 422 | func (f *StringFlag) Names() []string { 423 | return flagNames(f) 424 | } 425 | 426 | // String looks up the value of a local StringFlag, returns 427 | // "" if not found 428 | func (c *Context) String(name string) string { 429 | if fs := lookupFlagSet(name, c); fs != nil { 430 | return lookupString(name, fs) 431 | } 432 | return "" 433 | } 434 | 435 | func lookupString(name string, set *flag.FlagSet) string { 436 | f := set.Lookup(name) 437 | if f != nil { 438 | parsed, err := f.Value.String(), error(nil) 439 | if err != nil { 440 | return "" 441 | } 442 | return parsed 443 | } 444 | return "" 445 | } 446 | 447 | // StringSliceFlag is a flag with type *StringSlice 448 | type StringSliceFlag struct { 449 | Name string 450 | Aliases []string 451 | Usage string 452 | EnvVars []string 453 | Hidden bool 454 | Value *StringSlice 455 | DefaultText string 456 | } 457 | 458 | // String returns a readable representation of this value 459 | // (for usage defaults) 460 | func (f *StringSliceFlag) String() string { 461 | return FlagStringer(f) 462 | } 463 | 464 | // Names returns the names of the flag 465 | func (f *StringSliceFlag) Names() []string { 466 | return flagNames(f) 467 | } 468 | 469 | // StringSlice looks up the value of a local StringSliceFlag, returns 470 | // nil if not found 471 | func (c *Context) StringSlice(name string) []string { 472 | if fs := lookupFlagSet(name, c); fs != nil { 473 | return lookupStringSlice(name, fs) 474 | } 475 | return nil 476 | } 477 | 478 | func lookupStringSlice(name string, set *flag.FlagSet) []string { 479 | f := set.Lookup(name) 480 | if f != nil { 481 | parsed, err := (f.Value.(*StringSlice)).Value(), error(nil) 482 | if err != nil { 483 | return nil 484 | } 485 | return parsed 486 | } 487 | return nil 488 | } 489 | 490 | // Uint64Flag is a flag with type uint64 491 | type Uint64Flag struct { 492 | Name string 493 | Aliases []string 494 | Usage string 495 | EnvVars []string 496 | Hidden bool 497 | Value uint64 498 | DefaultText string 499 | Destination *uint64 500 | } 501 | 502 | // String returns a readable representation of this value 503 | // (for usage defaults) 504 | func (f *Uint64Flag) String() string { 505 | return FlagStringer(f) 506 | } 507 | 508 | // Names returns the names of the flag 509 | func (f *Uint64Flag) Names() []string { 510 | return flagNames(f) 511 | } 512 | 513 | // Uint64 looks up the value of a local Uint64Flag, returns 514 | // 0 if not found 515 | func (c *Context) Uint64(name string) uint64 { 516 | if fs := lookupFlagSet(name, c); fs != nil { 517 | return lookupUint64(name, fs) 518 | } 519 | return 0 520 | } 521 | 522 | func lookupUint64(name string, set *flag.FlagSet) uint64 { 523 | f := set.Lookup(name) 524 | if f != nil { 525 | parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) 526 | if err != nil { 527 | return 0 528 | } 529 | return parsed 530 | } 531 | return 0 532 | } 533 | 534 | // UintFlag is a flag with type uint 535 | type UintFlag struct { 536 | Name string 537 | Aliases []string 538 | Usage string 539 | EnvVars []string 540 | Hidden bool 541 | Value uint 542 | DefaultText string 543 | Destination *uint 544 | } 545 | 546 | // String returns a readable representation of this value 547 | // (for usage defaults) 548 | func (f *UintFlag) String() string { 549 | return FlagStringer(f) 550 | } 551 | 552 | // Names returns the names of the flag 553 | func (f *UintFlag) Names() []string { 554 | return flagNames(f) 555 | } 556 | 557 | // Uint looks up the value of a local UintFlag, returns 558 | // 0 if not found 559 | func (c *Context) Uint(name string) uint { 560 | if fs := lookupFlagSet(name, c); fs != nil { 561 | return lookupUint(name, fs) 562 | } 563 | return 0 564 | } 565 | 566 | func lookupUint(name string, set *flag.FlagSet) uint { 567 | f := set.Lookup(name) 568 | if f != nil { 569 | parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) 570 | if err != nil { 571 | return 0 572 | } 573 | return uint(parsed) 574 | } 575 | return 0 576 | } 577 | --------------------------------------------------------------------------------