client.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package client
  2. import (
  3. "fmt"
  4. "io"
  5. "io/ioutil"
  6. "net/http"
  7. "reflect"
  8. "strings"
  9. flag "github.com/docker/docker/libnetwork/client/mflag"
  10. )
  11. // CallFunc provides environment specific call utility to invoke backend functions from UI
  12. type CallFunc func(string, string, interface{}, map[string][]string) (io.ReadCloser, http.Header, int, error)
  13. // NetworkCli is the UI object for network subcmds
  14. type NetworkCli struct {
  15. out io.Writer
  16. err io.Writer
  17. call CallFunc
  18. }
  19. // NewNetworkCli is a convenient function to create a NetworkCli object
  20. func NewNetworkCli(out, err io.Writer, call CallFunc) *NetworkCli {
  21. return &NetworkCli{
  22. out: out,
  23. err: err,
  24. call: call,
  25. }
  26. }
  27. // getMethod is Borrowed from Docker UI which uses reflection to identify the UI Handler
  28. func (cli *NetworkCli) getMethod(args ...string) (func(string, ...string) error, bool) {
  29. camelArgs := make([]string, len(args))
  30. for i, s := range args {
  31. if len(s) == 0 {
  32. return nil, false
  33. }
  34. camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:])
  35. }
  36. methodName := "Cmd" + strings.Join(camelArgs, "")
  37. method := reflect.ValueOf(cli).MethodByName(methodName)
  38. if !method.IsValid() {
  39. return nil, false
  40. }
  41. return method.Interface().(func(string, ...string) error), true
  42. }
  43. // Cmd is borrowed from Docker UI and acts as the entry point for network UI commands.
  44. // network UI commands are designed to be invoked from multiple parent chains
  45. func (cli *NetworkCli) Cmd(chain string, args ...string) error {
  46. if len(args) > 2 {
  47. method, exists := cli.getMethod(args[:3]...)
  48. if exists {
  49. return method(chain+" "+args[0]+" "+args[1], args[3:]...)
  50. }
  51. }
  52. if len(args) > 1 {
  53. method, exists := cli.getMethod(args[:2]...)
  54. if exists {
  55. return method(chain+" "+args[0], args[2:]...)
  56. }
  57. }
  58. if len(args) > 0 {
  59. method, exists := cli.getMethod(args[0])
  60. if !exists {
  61. return fmt.Errorf("%s: '%s' is not a %s command. See '%s --help'", chain, args[0], chain, chain)
  62. }
  63. return method(chain, args[1:]...)
  64. }
  65. flag.Usage()
  66. return nil
  67. }
  68. // Subcmd is borrowed from Docker UI and performs the same function of configuring the subCmds
  69. func (cli *NetworkCli) Subcmd(chain, name, signature, description string, exitOnError bool) *flag.FlagSet {
  70. var errorHandling flag.ErrorHandling
  71. if exitOnError {
  72. errorHandling = flag.ExitOnError
  73. } else {
  74. errorHandling = flag.ContinueOnError
  75. }
  76. flags := flag.NewFlagSet(name, errorHandling)
  77. flags.Usage = func() {
  78. flags.ShortUsage()
  79. flags.PrintDefaults()
  80. }
  81. flags.ShortUsage = func() {
  82. options := ""
  83. if signature != "" {
  84. signature = " " + signature
  85. }
  86. if flags.FlagCountUndeprecated() > 0 {
  87. options = " [OPTIONS]"
  88. }
  89. fmt.Fprintf(cli.out, "\nUsage: %s %s%s%s\n\n%s\n\n", chain, name, options, signature, description)
  90. flags.SetOutput(cli.out)
  91. }
  92. return flags
  93. }
  94. func readBody(stream io.ReadCloser, hdr http.Header, statusCode int, err error) ([]byte, int, error) {
  95. if stream != nil {
  96. defer stream.Close()
  97. }
  98. if err != nil {
  99. return nil, statusCode, err
  100. }
  101. body, err := ioutil.ReadAll(stream)
  102. if err != nil {
  103. return nil, -1, err
  104. }
  105. return body, statusCode, nil
  106. }