2015-04-26 03:19:01 -04:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
2015-06-15 11:42:14 -04:00
|
|
|
"net/http"
|
2015-04-26 03:19:01 -04:00
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
|
2016-09-07 15:30:02 -04:00
|
|
|
flag "github.com/docker/libnetwork/client/mflag"
|
2015-04-26 03:19:01 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// CallFunc provides environment specific call utility to invoke backend functions from UI
|
2015-06-15 11:42:14 -04:00
|
|
|
type CallFunc func(string, string, interface{}, map[string][]string) (io.ReadCloser, http.Header, int, error)
|
2015-04-26 03:19:01 -04:00
|
|
|
|
|
|
|
// NetworkCli is the UI object for network subcmds
|
|
|
|
type NetworkCli struct {
|
|
|
|
out io.Writer
|
|
|
|
err io.Writer
|
|
|
|
call CallFunc
|
|
|
|
}
|
|
|
|
|
2015-05-04 05:54:19 -04:00
|
|
|
// NewNetworkCli is a convenient function to create a NetworkCli object
|
2015-04-26 03:19:01 -04:00
|
|
|
func NewNetworkCli(out, err io.Writer, call CallFunc) *NetworkCli {
|
|
|
|
return &NetworkCli{
|
|
|
|
out: out,
|
|
|
|
err: err,
|
|
|
|
call: call,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// getMethod is Borrowed from Docker UI which uses reflection to identify the UI Handler
|
|
|
|
func (cli *NetworkCli) getMethod(args ...string) (func(string, ...string) error, bool) {
|
|
|
|
camelArgs := make([]string, len(args))
|
|
|
|
for i, s := range args {
|
|
|
|
if len(s) == 0 {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:])
|
|
|
|
}
|
|
|
|
methodName := "Cmd" + strings.Join(camelArgs, "")
|
|
|
|
method := reflect.ValueOf(cli).MethodByName(methodName)
|
|
|
|
if !method.IsValid() {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
return method.Interface().(func(string, ...string) error), true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cmd is borrowed from Docker UI and acts as the entry point for network UI commands.
|
|
|
|
// network UI commands are designed to be invoked from multiple parent chains
|
|
|
|
func (cli *NetworkCli) Cmd(chain string, args ...string) error {
|
2015-05-22 10:54:23 -04:00
|
|
|
if len(args) > 2 {
|
|
|
|
method, exists := cli.getMethod(args[:3]...)
|
|
|
|
if exists {
|
|
|
|
return method(chain+" "+args[0]+" "+args[1], args[3:]...)
|
|
|
|
}
|
|
|
|
}
|
2015-04-26 03:19:01 -04:00
|
|
|
if len(args) > 1 {
|
|
|
|
method, exists := cli.getMethod(args[:2]...)
|
|
|
|
if exists {
|
2015-05-17 10:07:09 -04:00
|
|
|
return method(chain+" "+args[0], args[2:]...)
|
2015-04-26 03:19:01 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(args) > 0 {
|
|
|
|
method, exists := cli.getMethod(args[0])
|
|
|
|
if !exists {
|
2016-11-14 19:41:54 -05:00
|
|
|
return fmt.Errorf("%s: '%s' is not a %s command. See '%s --help'", chain, args[0], chain, chain)
|
2015-04-26 03:19:01 -04:00
|
|
|
}
|
|
|
|
return method(chain, args[1:]...)
|
|
|
|
}
|
2015-05-17 10:07:09 -04:00
|
|
|
flag.Usage()
|
|
|
|
return nil
|
2015-04-26 03:19:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Subcmd is borrowed from Docker UI and performs the same function of configuring the subCmds
|
|
|
|
func (cli *NetworkCli) Subcmd(chain, name, signature, description string, exitOnError bool) *flag.FlagSet {
|
|
|
|
var errorHandling flag.ErrorHandling
|
|
|
|
if exitOnError {
|
|
|
|
errorHandling = flag.ExitOnError
|
|
|
|
} else {
|
|
|
|
errorHandling = flag.ContinueOnError
|
|
|
|
}
|
|
|
|
flags := flag.NewFlagSet(name, errorHandling)
|
|
|
|
flags.Usage = func() {
|
2015-06-15 22:56:56 -04:00
|
|
|
flags.ShortUsage()
|
|
|
|
flags.PrintDefaults()
|
|
|
|
}
|
|
|
|
flags.ShortUsage = func() {
|
2015-04-26 03:19:01 -04:00
|
|
|
options := ""
|
|
|
|
if signature != "" {
|
|
|
|
signature = " " + signature
|
|
|
|
}
|
|
|
|
if flags.FlagCountUndeprecated() > 0 {
|
|
|
|
options = " [OPTIONS]"
|
|
|
|
}
|
|
|
|
fmt.Fprintf(cli.out, "\nUsage: %s %s%s%s\n\n%s\n\n", chain, name, options, signature, description)
|
|
|
|
flags.SetOutput(cli.out)
|
|
|
|
}
|
|
|
|
return flags
|
|
|
|
}
|
|
|
|
|
2015-06-15 11:42:14 -04:00
|
|
|
func readBody(stream io.ReadCloser, hdr http.Header, statusCode int, err error) ([]byte, int, error) {
|
2015-04-26 03:19:01 -04:00
|
|
|
if stream != nil {
|
|
|
|
defer stream.Close()
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, statusCode, err
|
|
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(stream)
|
|
|
|
if err != nil {
|
|
|
|
return nil, -1, err
|
|
|
|
}
|
|
|
|
return body, statusCode, nil
|
|
|
|
}
|