diff options
Diffstat (limited to 'vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command')
8 files changed, 1028 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/autohelp.go b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/autohelp.go new file mode 100644 index 000000000..082c53e27 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/autohelp.go @@ -0,0 +1,121 @@ +package command + +import ( + "flag" + "fmt" + "sort" + "strings" + + wordwrap "github.com/mitchellh/go-wordwrap" + "github.com/ryanuber/columnize" +) + +// AutoHelp specifies the necessary methods required to have their help +// completely generated for them. +type AutoHelp interface { + Usage() string + Description() string + InitOpts() + VisitAllFlags(func(f *flag.Flag)) +} + +// MakeHelp generates a help string based on the capabilities of the Command +func MakeHelp(c AutoHelp) string { + usageText := c.Usage() + + // If the length of Usage() is zero, then assume this is a hidden + // command. + if len(usageText) == 0 { + return "" + } + + descriptionText := wordwrap.WrapString(c.Description(), 60) + descrLines := strings.Split(descriptionText, "\n") + prefixedLines := make([]string, len(descrLines)) + for i := range descrLines { + prefixedLines[i] = " " + descrLines[i] + } + descriptionText = strings.Join(prefixedLines, "\n") + + c.InitOpts() + flags := []*flag.Flag{} + c.VisitAllFlags(func(f *flag.Flag) { + flags = append(flags, f) + }) + optionsText := OptionsHelpOutput(flags) + + var helpOutput string + switch { + case len(optionsText) == 0 && len(descriptionText) == 0: + helpOutput = usageText + case len(optionsText) == 0: + helpOutput = fmt.Sprintf(`Usage: %s + +%s`, + usageText, descriptionText) + case len(descriptionText) == 0 && len(optionsText) > 0: + helpOutput = fmt.Sprintf(`Usage: %s + +Options: + +%s`, + usageText, optionsText) + default: + helpOutput = fmt.Sprintf(`Usage: %s + +%s + +Options: + +%s`, + usageText, descriptionText, optionsText) + } + + return strings.TrimSpace(helpOutput) +} + +// ByOptName implements sort.Interface for flag.Flag based on the Name field. +type ByName []*flag.Flag + +func (a ByName) Len() int { return len(a) } +func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ByName) Less(i, j int) bool { + // Bubble up single-char args to the top of the list + switch { + case len(a[i].Name) == 1 && len(a[j].Name) != 1: + return true + case len(a[i].Name) != 1 && len(a[j].Name) == 1: + return false + default: + // Case-insensitive sort. Use case as a tie breaker, however. + a1 := strings.ToLower(a[i].Name) + a2 := strings.ToLower(a[j].Name) + if a1 == a2 { + return a[i].Name < a[j].Name + } else { + return a1 < a2 + } + } +} + +// OptionsHelpOutput returns a string of formatted options +func OptionsHelpOutput(flags []*flag.Flag) string { + sort.Sort(ByName(flags)) + + var output []string + for _, f := range flags { + if len(f.Usage) == 0 { + continue + } + + output = append(output, fmt.Sprintf("-%s | %s", f.Name, f.Usage)) + } + + optionsOutput := columnize.Format(output, &columnize.Config{ + Delim: "|", + Glue: " ", + Prefix: " ", + Empty: "", + }) + return optionsOutput +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/dump.go b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/dump.go new file mode 100644 index 000000000..a5618b357 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/dump.go @@ -0,0 +1,274 @@ +package command + +import ( + "flag" + "fmt" + + "github.com/hashicorp/errwrap" + sockaddr "github.com/hashicorp/go-sockaddr" + "github.com/mitchellh/cli" + "github.com/ryanuber/columnize" +) + +type DumpCommand struct { + Ui cli.Ui + + // attrNames is a list of attribute names to include in the output + attrNames []string + + // flags is a list of options belonging to this command + flags *flag.FlagSet + + // machineMode changes the output format to be machine friendly + // (i.e. tab-separated values). + machineMode bool + + // valueOnly changes the output format to include only values + valueOnly bool + + // ifOnly parses the input as an interface name + ifOnly bool + + // ipOnly parses the input as an IP address (either IPv4 or IPv6) + ipOnly bool + + // v4Only parses the input exclusively as an IPv4 address + v4Only bool + + // v6Only parses the input exclusively as an IPv6 address + v6Only bool + + // unixOnly parses the input exclusively as a UNIX Socket + unixOnly bool +} + +// Description is the long-form command help. +func (c *DumpCommand) Description() string { + return `Parse address(es) or interface and dumps various output.` +} + +// Help returns the full help output expected by `sockaddr -h cmd` +func (c *DumpCommand) Help() string { + return MakeHelp(c) +} + +// InitOpts is responsible for setup of this command's configuration via the +// command line. InitOpts() does not parse the arguments (see parseOpts()). +func (c *DumpCommand) InitOpts() { + c.flags = flag.NewFlagSet("dump", flag.ContinueOnError) + c.flags.Usage = func() { c.Ui.Output(c.Help()) } + c.flags.BoolVar(&c.machineMode, "H", false, "Machine readable output") + c.flags.BoolVar(&c.valueOnly, "n", false, "Show only the value") + c.flags.BoolVar(&c.v4Only, "4", false, "Parse the input as IPv4 only") + c.flags.BoolVar(&c.v6Only, "6", false, "Parse the input as IPv6 only") + c.flags.BoolVar(&c.ifOnly, "I", false, "Parse the argument as an interface name") + c.flags.BoolVar(&c.ipOnly, "i", false, "Parse the input as IP address (either IPv4 or IPv6)") + c.flags.BoolVar(&c.unixOnly, "u", false, "Parse the input as a UNIX Socket only") + c.flags.Var((*MultiArg)(&c.attrNames), "o", "Name of an attribute to pass through") +} + +// Run executes this command. +func (c *DumpCommand) Run(args []string) int { + if len(args) == 0 { + c.Ui.Error(c.Help()) + return 1 + } + + c.InitOpts() + addrs, err := c.parseOpts(args) + if err != nil { + if errwrap.Contains(err, "flag: help requested") { + return 0 + } + return 1 + } + for _, addr := range addrs { + var sa sockaddr.SockAddr + var ifAddrs sockaddr.IfAddrs + var err error + switch { + case c.v4Only: + sa, err = sockaddr.NewIPv4Addr(addr) + case c.v6Only: + sa, err = sockaddr.NewIPv6Addr(addr) + case c.unixOnly: + sa, err = sockaddr.NewUnixSock(addr) + case c.ipOnly: + sa, err = sockaddr.NewIPAddr(addr) + case c.ifOnly: + ifAddrs, err = sockaddr.GetAllInterfaces() + if err != nil { + break + } + + ifAddrs, _, err = sockaddr.IfByName(addr, ifAddrs) + default: + sa, err = sockaddr.NewSockAddr(addr) + } + if err != nil { + c.Ui.Error(fmt.Sprintf("Unable to parse %+q: %v", addr, err)) + return 1 + } + if sa != nil { + c.dumpSockAddr(sa) + } else if ifAddrs != nil { + c.dumpIfAddrs(ifAddrs) + } else { + panic("bad") + } + } + return 0 +} + +// Synopsis returns a terse description used when listing sub-commands. +func (c *DumpCommand) Synopsis() string { + return `Parses input as an IP or interface name(s) and dumps various information` +} + +// Usage is the one-line usage description +func (c *DumpCommand) Usage() string { + return `sockaddr dump [options] input [...]` +} + +// VisitAllFlags forwards the visitor function to the FlagSet +func (c *DumpCommand) VisitAllFlags(fn func(*flag.Flag)) { + c.flags.VisitAll(fn) +} + +func (c *DumpCommand) dumpIfAddrs(ifAddrs sockaddr.IfAddrs) { + for _, ifAddr := range ifAddrs { + c.dumpSockAddr(ifAddr.SockAddr) + } +} + +func (c *DumpCommand) dumpSockAddr(sa sockaddr.SockAddr) { + reservedAttrs := []sockaddr.AttrName{"Attribute"} + const maxNumAttrs = 32 + + output := make([]string, 0, maxNumAttrs+len(reservedAttrs)) + allowedAttrs := make(map[sockaddr.AttrName]struct{}, len(c.attrNames)+len(reservedAttrs)) + for _, attr := range reservedAttrs { + allowedAttrs[attr] = struct{}{} + } + for _, attr := range c.attrNames { + allowedAttrs[sockaddr.AttrName(attr)] = struct{}{} + } + + // allowedAttr returns true if the attribute is allowed to be appended + // to the output. + allowedAttr := func(k sockaddr.AttrName) bool { + if len(allowedAttrs) == len(reservedAttrs) { + return true + } + + _, found := allowedAttrs[k] + return found + } + + // outFmt is a small helper function to reduce the tedium below. outFmt + // returns a new slice and expects the value to already be a string. + outFmt := func(o []string, k sockaddr.AttrName, v interface{}) []string { + if !allowedAttr(k) { + return o + } + switch { + case c.valueOnly: + return append(o, fmt.Sprintf("%s", v)) + case !c.valueOnly && c.machineMode: + return append(o, fmt.Sprintf("%s\t%s", k, v)) + case !c.valueOnly && !c.machineMode: + fallthrough + default: + return append(o, fmt.Sprintf("%s | %s", k, v)) + } + } + + if !c.machineMode { + output = outFmt(output, "Attribute", "Value") + } + + // Attributes for all SockAddr types + for _, attr := range sockaddr.SockAddrAttrs() { + output = outFmt(output, attr, sockaddr.SockAddrAttr(sa, attr)) + } + + // Attributes for all IP types (both IPv4 and IPv6) + if sa.Type()&sockaddr.TypeIP != 0 { + ip := *sockaddr.ToIPAddr(sa) + for _, attr := range sockaddr.IPAttrs() { + output = outFmt(output, attr, sockaddr.IPAddrAttr(ip, attr)) + } + } + + if sa.Type() == sockaddr.TypeIPv4 { + ipv4 := *sockaddr.ToIPv4Addr(sa) + for _, attr := range sockaddr.IPv4Attrs() { + output = outFmt(output, attr, sockaddr.IPv4AddrAttr(ipv4, attr)) + } + } + + if sa.Type() == sockaddr.TypeIPv6 { + ipv6 := *sockaddr.ToIPv6Addr(sa) + for _, attr := range sockaddr.IPv6Attrs() { + output = outFmt(output, attr, sockaddr.IPv6AddrAttr(ipv6, attr)) + } + } + + if sa.Type() == sockaddr.TypeUnix { + us := *sockaddr.ToUnixSock(sa) + for _, attr := range sockaddr.UnixSockAttrs() { + output = outFmt(output, attr, sockaddr.UnixSockAttr(us, attr)) + } + } + + // Developer-focused arguments + { + arg1, arg2 := sa.DialPacketArgs() + output = outFmt(output, "DialPacket", fmt.Sprintf("%+q %+q", arg1, arg2)) + } + { + arg1, arg2 := sa.DialStreamArgs() + output = outFmt(output, "DialStream", fmt.Sprintf("%+q %+q", arg1, arg2)) + } + { + arg1, arg2 := sa.ListenPacketArgs() + output = outFmt(output, "ListenPacket", fmt.Sprintf("%+q %+q", arg1, arg2)) + } + { + arg1, arg2 := sa.ListenStreamArgs() + output = outFmt(output, "ListenStream", fmt.Sprintf("%+q %+q", arg1, arg2)) + } + + result := columnize.SimpleFormat(output) + c.Ui.Output(result) +} + +// parseOpts is responsible for parsing the options set in InitOpts(). Returns +// a list of non-parsed flags. +func (c *DumpCommand) parseOpts(args []string) ([]string, error) { + if err := c.flags.Parse(args); err != nil { + return nil, err + } + + conflictingOptsCount := 0 + if c.v4Only { + conflictingOptsCount++ + } + if c.v6Only { + conflictingOptsCount++ + } + if c.unixOnly { + conflictingOptsCount++ + } + if c.ifOnly { + conflictingOptsCount++ + } + if c.ipOnly { + conflictingOptsCount++ + } + if conflictingOptsCount > 1 { + return nil, fmt.Errorf("Conflicting options specified, only one parsing mode may be specified at a time") + } + + return c.flags.Args(), nil +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/eval.go b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/eval.go new file mode 100644 index 000000000..0554cda4f --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/eval.go @@ -0,0 +1,158 @@ +package command + +import ( + "bytes" + "flag" + "fmt" + "io" + "os" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-sockaddr/template" + "github.com/mitchellh/cli" +) + +type EvalCommand struct { + Ui cli.Ui + + // debugOutput emits framed output vs raw output. + debugOutput bool + + // flags is a list of options belonging to this command + flags *flag.FlagSet + + // rawInput disables wrapping the string in the text/template {{ }} + // handlebars. + rawInput bool + + // suppressNewline changes whether or not there's a newline between each + // arg passed to the eval subcommand. + suppressNewline bool +} + +// Description is the long-form command help. +func (c *EvalCommand) Description() string { + return `Parse the sockaddr template and evaluates the output. + +` + "The `sockaddr` library has the potential to be very complex, which is why the " + + "`sockaddr` command supports an `eval` subcommand in order to test configurations " + + "from the command line. The `eval` subcommand automatically wraps its input with " + + "the `{{` and `}}` template delimiters unless the `-r` command is specified, in " + + "which case `eval` parses the raw input. If the `template` argument passed to " + + "`eval` is a dash (`-`), then `sockaddr eval` will read from stdin and " + + "automatically sets the `-r` flag." + +} + +// Help returns the full help output expected by `sockaddr -h cmd` +func (c *EvalCommand) Help() string { + return MakeHelp(c) +} + +// InitOpts is responsible for setup of this command's configuration via the +// command line. InitOpts() does not parse the arguments (see parseOpts()). +func (c *EvalCommand) InitOpts() { + c.flags = flag.NewFlagSet("eval", flag.ContinueOnError) + c.flags.Usage = func() { c.Ui.Output(c.Help()) } + c.flags.BoolVar(&c.debugOutput, "d", false, "Debug output") + c.flags.BoolVar(&c.suppressNewline, "n", false, "Suppress newlines between args") + c.flags.BoolVar(&c.rawInput, "r", false, "Suppress wrapping the input with {{ }} delimiters") +} + +// Run executes this command. +func (c *EvalCommand) Run(args []string) int { + if len(args) == 0 { + c.Ui.Error(c.Help()) + return 1 + } + + c.InitOpts() + tmpls, err := c.parseOpts(args) + if err != nil { + if errwrap.Contains(err, "flag: help requested") { + return 0 + } + return 1 + } + inputs, outputs := make([]string, len(tmpls)), make([]string, len(tmpls)) + var rawInput, readStdin bool + for i, in := range tmpls { + if readStdin { + break + } + + rawInput = c.rawInput + if in == "-" { + rawInput = true + var f io.Reader = os.Stdin + var buf bytes.Buffer + if _, err := io.Copy(&buf, f); err != nil { + c.Ui.Error(fmt.Sprintf("[ERROR]: Error reading from stdin: %v", err)) + return 1 + } + in = buf.String() + if len(in) == 0 { + return 0 + } + readStdin = true + } + inputs[i] = in + + if !rawInput { + in = `{{` + in + `}}` + inputs[i] = in + } + + out, err := template.Parse(in) + if err != nil { + c.Ui.Error(fmt.Sprintf("ERROR[%d] in: %q\n[%d] msg: %v\n", i, in, i, err)) + return 1 + } + outputs[i] = out + } + + if c.debugOutput { + for i, out := range outputs { + c.Ui.Output(fmt.Sprintf("[%d] in: %q\n[%d] out: %q\n", i, inputs[i], i, out)) + if i != len(outputs)-1 { + if c.debugOutput { + c.Ui.Output(fmt.Sprintf("---\n")) + } + } + } + } else { + sep := "\n" + if c.suppressNewline { + sep = "" + } + c.Ui.Output(strings.Join(outputs, sep)) + } + + return 0 +} + +// Synopsis returns a terse description used when listing sub-commands. +func (c *EvalCommand) Synopsis() string { + return `Evaluates a sockaddr template` +} + +// Usage is the one-line usage description +func (c *EvalCommand) Usage() string { + return `sockaddr eval [options] [template ...]` +} + +// VisitAllFlags forwards the visitor function to the FlagSet +func (c *EvalCommand) VisitAllFlags(fn func(*flag.Flag)) { + c.flags.VisitAll(fn) +} + +// parseOpts is responsible for parsing the options set in InitOpts(). Returns +// a list of non-parsed flags. +func (c *EvalCommand) parseOpts(args []string) ([]string, error) { + if err := c.flags.Parse(args); err != nil { + return nil, err + } + + return c.flags.Args(), nil +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/multi_arg.go b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/multi_arg.go new file mode 100644 index 000000000..c626dab0f --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/multi_arg.go @@ -0,0 +1,17 @@ +package command + +import "regexp" + +type MultiArg []string + +func (v *MultiArg) String() string { + return "" +} + +func (v *MultiArg) Set(raw string) error { + parts := regexp.MustCompile(`[\s]*,[\s]*`).Split(raw, -1) + for _, part := range parts { + *v = append(*v, part) + } + return nil +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/rfc.go b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/rfc.go new file mode 100644 index 000000000..4c66b8517 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/rfc.go @@ -0,0 +1,121 @@ +package command + +import ( + "flag" + "fmt" + "strconv" + + "github.com/hashicorp/errwrap" + sockaddr "github.com/hashicorp/go-sockaddr" + "github.com/mitchellh/cli" +) + +type RFCCommand struct { + Ui cli.Ui + + // flags is a list of options belonging to this command + flags *flag.FlagSet + + // silentMode prevents any output and only returns exit code 1 when the + // IP address is NOT a member of the known RFC. Unknown RFCs return a + // status code of 2. + silentMode bool +} + +// Description is the long-form command help. +func (c *RFCCommand) Description() string { + return `Tests a given IP address to see if it is part of a known RFC. If the IP address belongs to a known RFC, return exit code 0 and print the status. If the IP does not belong to an RFC, return 1. If the RFC is not known, return 2.` +} + +// Help returns the full help output expected by `sockaddr -h cmd` +func (c *RFCCommand) Help() string { + return MakeHelp(c) +} + +// InitOpts is responsible for setup of this command's configuration via the +// command line. InitOpts() does not parse the arguments (see parseOpts()). +func (c *RFCCommand) InitOpts() { + c.flags = flag.NewFlagSet("rfc", flag.ContinueOnError) + c.flags.Usage = func() { c.Ui.Output(c.Help()) } + c.flags.BoolVar(&c.silentMode, "s", false, "Silent, only return different exit codes") +} + +// Run executes this command. +func (c *RFCCommand) Run(args []string) int { + if len(args) == 0 { + c.Ui.Error(c.Help()) + return 1 + } + + c.InitOpts() + unprocessedArgs, err := c.parseOpts(args) + if err != nil { + if errwrap.Contains(err, "flag: help requested") { + return 0 + } + return 1 + } + + switch numArgs := len(unprocessedArgs); { + case numArgs != 2 && numArgs != 0: + c.Ui.Error(`ERROR: Need an RFC Number and an IP address to test.`) + c.Ui.Error(c.Help()) + fallthrough + case numArgs == 0: + return 1 + } + + // Parse the RFC Number + rfcNum, err := strconv.ParseUint(unprocessedArgs[0], 10, 32) + if err != nil { + c.Ui.Error(fmt.Sprintf("ERROR: Invalid RFC Number %+q: %v", unprocessedArgs[0], err)) + return 2 + } + + // Parse the IP address + ipAddr, err := sockaddr.NewIPAddr(unprocessedArgs[1]) + if err != nil { + c.Ui.Error(fmt.Sprintf("ERROR: Invalid IP address %+q: %v", unprocessedArgs[1], err)) + return 3 + } + + switch inRFC := sockaddr.IsRFC(uint(rfcNum), ipAddr); { + case inRFC && !c.silentMode: + c.Ui.Output(fmt.Sprintf("%s is part of RFC %d", ipAddr, rfcNum)) + fallthrough + case inRFC: + return 0 + case !inRFC && !c.silentMode: + c.Ui.Output(fmt.Sprintf("%s is not part of RFC %d", ipAddr, rfcNum)) + fallthrough + case !inRFC: + return 1 + default: + panic("bad") + } +} + +// Synopsis returns a terse description used when listing sub-commands. +func (c *RFCCommand) Synopsis() string { + return `Test to see if an IP is part of a known RFC` +} + +// Usage is the one-line usage description +func (c *RFCCommand) Usage() string { + return `sockaddr rfc [RFC Number] [IP Address]` +} + +// VisitAllFlags forwards the visitor function to the FlagSet +func (c *RFCCommand) VisitAllFlags(fn func(*flag.Flag)) { + c.flags.VisitAll(fn) +} + +// parseOpts is responsible for parsing the options set in InitOpts(). Returns +// a list of non-parsed flags. +func (c *RFCCommand) parseOpts(args []string) ([]string, error) { + if err := c.flags.Parse(args); err != nil { + return nil, err + } + + return c.flags.Args(), nil +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/rfc_list.go b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/rfc_list.go new file mode 100644 index 000000000..11c1ac365 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/rfc_list.go @@ -0,0 +1,94 @@ +package command + +import ( + "flag" + "fmt" + "sort" + + "github.com/hashicorp/errwrap" + sockaddr "github.com/hashicorp/go-sockaddr" + "github.com/mitchellh/cli" +) + +type RFCListCommand struct { + Ui cli.Ui + + // flags is a list of options belonging to this command + flags *flag.FlagSet +} + +// Description is the long-form command help. +func (c *RFCListCommand) Description() string { + return `Lists all known RFCs.` +} + +// Help returns the full help output expected by `sockaddr -h cmd` +func (c *RFCListCommand) Help() string { + return MakeHelp(c) +} + +// InitOpts is responsible for setup of this command's configuration via the +// command line. InitOpts() does not parse the arguments (see parseOpts()). +func (c *RFCListCommand) InitOpts() { + c.flags = flag.NewFlagSet("list", flag.ContinueOnError) + c.flags.Usage = func() { c.Ui.Output(c.Help()) } +} + +type rfcNums []uint + +func (s rfcNums) Len() int { return len(s) } +func (s rfcNums) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s rfcNums) Less(i, j int) bool { return s[i] < s[j] } + +// Run executes this command. +func (c *RFCListCommand) Run(args []string) int { + if len(args) != 0 { + c.Ui.Error(c.Help()) + return 1 + } + + c.InitOpts() + _, err := c.parseOpts(args) + if err != nil { + if errwrap.Contains(err, "flag: help requested") { + return 0 + } + return 1 + } + + var rfcs rfcNums + sockaddr.VisitAllRFCs(func(rfcNum uint, sas sockaddr.SockAddrs) { + rfcs = append(rfcs, rfcNum) + }) + + sort.Sort(rfcs) + + for _, rfcNum := range rfcs { + c.Ui.Output(fmt.Sprintf("%d", rfcNum)) + } + + return 0 +} + +// Synopsis returns a terse description used when listing sub-commands. +func (c *RFCListCommand) Synopsis() string { + return `Lists all known RFCs` +} + +// Usage is the one-line usage description +func (c *RFCListCommand) Usage() string { + return `sockaddr rfc list` +} + +// VisitAllFlags forwards the visitor function to the FlagSet +func (c *RFCListCommand) VisitAllFlags(fn func(*flag.Flag)) { + c.flags.VisitAll(fn) +} + +func (c *RFCListCommand) parseOpts(args []string) ([]string, error) { + if err := c.flags.Parse(args); err != nil { + return nil, err + } + + return c.flags.Args(), nil +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/tech_support.go b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/tech_support.go new file mode 100644 index 000000000..fd706009d --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/tech_support.go @@ -0,0 +1,216 @@ +package command + +import ( + "flag" + "fmt" + "net" + "os/exec" + "runtime" + + "github.com/hashicorp/errwrap" + sockaddr "github.com/hashicorp/go-sockaddr" + "github.com/mitchellh/cli" +) + +type TechSupportCommand struct { + Ui cli.Ui + + // outputMode controls the type of output encoding. + outputMode string + + // flags is a list of options belonging to this command + flags *flag.FlagSet +} + +// Description is the long-form command help. +func (c *TechSupportCommand) Description() string { + return `Print out network diagnostic information that can be used by support. + +` + "The `sockaddr` library relies on OS-specific commands and output which can potentially be " + + "brittle. The `tech-support` subcommand emits all of the platform-specific " + + "network details required to debug why a given `sockaddr` API call is behaving " + + "differently than expected. The `-output` flag controls the output format. " + + "The default output mode is Markdown (`md`) however a raw mode (`raw`) is " + + "available to obtain the original output." +} + +// Help returns the full help output expected by `sockaddr -h cmd` +func (c *TechSupportCommand) Help() string { + return MakeHelp(c) +} + +// InitOpts is responsible for setup of this command's configuration via the +// command line. InitOpts() does not parse the arguments (see parseOpts()). +func (c *TechSupportCommand) InitOpts() { + c.flags = flag.NewFlagSet("tech-support", flag.ContinueOnError) + c.flags.Usage = func() { c.Ui.Output(c.Help()) } + c.flags.StringVar(&c.outputMode, "output", "md", `Encode the output using one of Markdown ("md") or Raw ("raw")`) +} + +// Run executes this command. +func (c *TechSupportCommand) Run(args []string) int { + c.InitOpts() + rest, err := c.parseOpts(args) + if err != nil { + if errwrap.Contains(err, "flag: help requested") { + return 0 + } + return 1 + } + if len(rest) != 0 { + c.Ui.Error(c.Help()) + return 1 + } + + ri, err := sockaddr.NewRouteInfo() + if err != nil { + c.Ui.Error(fmt.Sprintf("error loading route information: %v", err)) + return 1 + } + + const initNumCmds = 4 + type cmdResult struct { + cmd []string + out string + } + output := make(map[string]cmdResult, initNumCmds) + ri.VisitCommands(func(name string, cmd []string) { + out, err := exec.Command(cmd[0], cmd[1:]...).Output() + if err != nil { + out = []byte(fmt.Sprintf("ERROR: command %q failed: %v", name, err)) + } + + output[name] = cmdResult{ + cmd: cmd, + out: string(out), + } + }) + + out := c.rowWriterOutputFactory() + + for cmdName, result := range output { + switch c.outputMode { + case "md": + c.Ui.Output(fmt.Sprintf("## cmd: `%s`", cmdName)) + c.Ui.Output("") + c.Ui.Output(fmt.Sprintf("Command: `%#v`", result.cmd)) + c.Ui.Output("```") + c.Ui.Output(result.out) + c.Ui.Output("```") + c.Ui.Output("") + case "raw": + c.Ui.Output(fmt.Sprintf("cmd: %q: %#v", cmdName, result.cmd)) + c.Ui.Output("") + c.Ui.Output(result.out) + c.Ui.Output("") + default: + c.Ui.Error(fmt.Sprintf("Unsupported output type: %q", c.outputMode)) + return 1 + } + + out("s", "GOOS", runtime.GOOS) + out("s", "GOARCH", runtime.GOARCH) + out("s", "Compiler", runtime.Compiler) + out("s", "Version", runtime.Version()) + ifs, err := net.Interfaces() + if err != nil { + out("v", "net.Interfaces", err) + } else { + for i, intf := range ifs { + out("s", fmt.Sprintf("net.Interfaces[%d].Name", i), intf.Name) + out("s", fmt.Sprintf("net.Interfaces[%d].Flags", i), intf.Flags) + out("+v", fmt.Sprintf("net.Interfaces[%d].Raw", i), intf) + addrs, err := intf.Addrs() + if err != nil { + out("v", fmt.Sprintf("net.Interfaces[%d].Addrs", i), err) + } else { + for j, addr := range addrs { + out("s", fmt.Sprintf("net.Interfaces[%d].Addrs[%d]", i, j), addr) + } + } + } + } + } + + return 0 +} + +// Synopsis returns a terse description used when listing sub-commands. +func (c *TechSupportCommand) Synopsis() string { + return `Dumps diagnostic information about a platform's network` +} + +// Usage is the one-line usage description +func (c *TechSupportCommand) Usage() string { + return `sockaddr tech-support [options]` +} + +// VisitAllFlags forwards the visitor function to the FlagSet +func (c *TechSupportCommand) VisitAllFlags(fn func(*flag.Flag)) { + c.flags.VisitAll(fn) +} + +// parseOpts is responsible for parsing the options set in InitOpts(). Returns +// a list of non-parsed flags. +func (c *TechSupportCommand) parseOpts(args []string) ([]string, error) { + if err := c.flags.Parse(args); err != nil { + return nil, err + } + + switch c.outputMode { + case "md", "markdown": + c.outputMode = "md" + case "raw": + default: + return nil, fmt.Errorf(`Invalid output mode %q, supported output types are "md" (default) and "raw"`, c.outputMode) + } + return c.flags.Args(), nil +} + +func (c *TechSupportCommand) rowWriterOutputFactory() func(valueVerb, key string, val interface{}) { + type _Fmt string + type _Verb string + var lineNoFmt string + var keyVerb _Verb + var fmtMap map[_Verb]_Fmt + switch c.outputMode { + case "md": + lineNoFmt = "%02d." + keyVerb = "s" + fmtMap = map[_Verb]_Fmt{ + "s": "`%s`", + "-s": "%s", + "v": "`%v`", + "+v": "`%#v`", + } + case "raw": + lineNoFmt = "%02d:" + keyVerb = "-s" + fmtMap = map[_Verb]_Fmt{ + "s": "%q", + "-s": "%s", + "v": "%v", + "+v": "%#v", + } + default: + panic(fmt.Sprintf("Unsupported output type: %q", c.outputMode)) + } + + var count int + return func(valueVerb, key string, val interface{}) { + count++ + + keyFmt, ok := fmtMap[keyVerb] + if !ok { + panic(fmt.Sprintf("Invalid key verb: %q", keyVerb)) + } + + valFmt, ok := fmtMap[_Verb(valueVerb)] + if !ok { + panic(fmt.Sprintf("Invalid value verb: %q", valueVerb)) + } + + outputModeFmt := fmt.Sprintf("%s %s:\t%s", lineNoFmt, keyFmt, valFmt) + c.Ui.Output(fmt.Sprintf(outputModeFmt, count, key, val)) + } +} diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/version.go b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/version.go new file mode 100644 index 000000000..add3d1cc6 --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/version.go @@ -0,0 +1,27 @@ +package command + +import ( + "fmt" + + "github.com/mitchellh/cli" +) + +// VersionCommand is a Command implementation prints the version. +type VersionCommand struct { + HumanVersion string + Ui cli.Ui +} + +func (c *VersionCommand) Help() string { + return "" +} + +func (c *VersionCommand) Run(_ []string) int { + c.Ui.Output(fmt.Sprintf("sockaddr %s", c.HumanVersion)) + + return 0 +} + +func (c *VersionCommand) Synopsis() string { + return "Prints the sockaddr version" +} |