From c90e3e7fe59db0bfbce0c10bba8a9ff71c7c7266 Mon Sep 17 00:00:00 2001 From: Anders F Björklund Date: Fri, 11 Jan 2019 23:28:20 +0100 Subject: Add bridge support, for the varlink connection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read the $PODMAN_VARLINK_BRIDGE environment variable (normally looks like: "ssh user@host varlink bridge") Also respect $PODMAN_VARLINK_ADDRESS as an override, if using a different podman socket than the default. Signed-off-by: Anders F Björklund --- vendor/github.com/varlink/go/.gitignore | 1 + vendor/github.com/varlink/go/.travis.yml | 6 +- vendor/github.com/varlink/go/cmd/varlink/main.go | 295 +++++++++++++++++++++ vendor/github.com/varlink/go/varlink/bridge.go | 59 +++++ .../varlink/go/varlink/bridge_windows.go | 57 ++++ vendor/github.com/varlink/go/varlink/connection.go | 7 + vendor/github.com/varlink/go/varlink/service.go | 67 +---- .../varlink/go/varlink/socketactivation.go | 63 +++++ .../varlink/go/varlink/socketactivation_windows.go | 7 + 9 files changed, 499 insertions(+), 63 deletions(-) create mode 100644 vendor/github.com/varlink/go/cmd/varlink/main.go create mode 100644 vendor/github.com/varlink/go/varlink/bridge.go create mode 100644 vendor/github.com/varlink/go/varlink/bridge_windows.go create mode 100644 vendor/github.com/varlink/go/varlink/socketactivation.go create mode 100644 vendor/github.com/varlink/go/varlink/socketactivation_windows.go (limited to 'vendor') diff --git a/vendor/github.com/varlink/go/.gitignore b/vendor/github.com/varlink/go/.gitignore index 69e30cff1..a43b0e2d3 100644 --- a/vendor/github.com/varlink/go/.gitignore +++ b/vendor/github.com/varlink/go/.gitignore @@ -1 +1,2 @@ /cmd/varlink-go-certification/orgvarlinkcertification/orgvarlinkcertification.go +/.idea diff --git a/vendor/github.com/varlink/go/.travis.yml b/vendor/github.com/varlink/go/.travis.yml index c090a924f..fa9963500 100644 --- a/vendor/github.com/varlink/go/.travis.yml +++ b/vendor/github.com/varlink/go/.travis.yml @@ -1,11 +1,13 @@ language: go sudo: false go: -- '1.9' -- 1.10.x +- '1.10' +- 1.11.x install: - go get golang.org/x/tools/cmd/cover - go get github.com/mattn/goveralls +- go get github.com/TylerBrock/colorjson +- go get github.com/fatih/color script: - go generate ./... - '"$HOME/gopath/bin/goveralls" -v -show -service=travis-ci -repotoken "$COVERALLS_TOKEN"' diff --git a/vendor/github.com/varlink/go/cmd/varlink/main.go b/vendor/github.com/varlink/go/cmd/varlink/main.go new file mode 100644 index 000000000..1de4e1a45 --- /dev/null +++ b/vendor/github.com/varlink/go/cmd/varlink/main.go @@ -0,0 +1,295 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "github.com/TylerBrock/colorjson" + "github.com/fatih/color" + "github.com/varlink/go/varlink" + "os" + "strings" +) + +var bold = color.New(color.Bold) +var errorBoldRed = bold.Sprint(color.New(color.FgRed).Sprint("Error:")) +var bridge string + +func ErrPrintf(format string, a ...interface{}) { + fmt.Fprintf(os.Stderr, "%s ", errorBoldRed) + fmt.Fprintf(os.Stderr, format, a...) +} + +func print_usage(set *flag.FlagSet, arg_help string) { + if set == nil { + fmt.Fprintf(os.Stderr, "Usage: %s [GLOBAL OPTIONS] COMMAND ...\n", os.Args[0]) + } else { + fmt.Fprintf(os.Stderr, "Usage: %s [GLOBAL OPTIONS] %s [OPTIONS] %s\n", os.Args[0], set.Name(), arg_help) + } + + fmt.Fprintln(os.Stderr, "\nGlobal Options:") + flag.PrintDefaults() + + if set == nil { + fmt.Fprintln(os.Stderr, "\nCommands:") + fmt.Fprintln(os.Stderr, " info\tPrint information about a service") + fmt.Fprintln(os.Stderr, " help\tPrint interface description or service information") + fmt.Fprintln(os.Stderr, " call\tCall a method") + } else { + fmt.Fprintln(os.Stderr, "\nOptions:") + set.PrintDefaults() + } + os.Exit(1) +} + +func varlink_call(args []string) { + var err error + var oneway bool + + callFlags := flag.NewFlagSet("help", flag.ExitOnError) + callFlags.BoolVar(&oneway, "-oneway", false, "Use bridge for connection") + var help bool + callFlags.BoolVar(&help, "help", false, "Prints help information") + var usage = func() { print_usage(callFlags, "<[ADDRESS/]INTERFACE.METHOD> [ARGUMENTS]") } + callFlags.Usage = usage + + _ = callFlags.Parse(args) + + if help { + usage() + } + + var con *varlink.Connection + var address string + var methodName string + + if len(bridge) != 0 { + con, err = varlink.NewBridge(bridge) + + if err != nil { + ErrPrintf("Cannot connect with bridge '%s': %v\n", bridge, err) + os.Exit(2) + } + address = "bridge:" + bridge + methodName = callFlags.Arg(0) + } else { + uri := callFlags.Arg(0) + if uri == "" { + usage() + } + + li := strings.LastIndex(uri, "/") + + if li == -1 { + ErrPrintf("Invalid address '%s'\n", uri) + os.Exit(2) + } + + address = uri[:li] + methodName = uri[li+1:] + + con, err = varlink.NewConnection(address) + + if err != nil { + ErrPrintf("Cannot connect to '%s': %v\n", address, err) + os.Exit(2) + } + } + var parameters string + var params json.RawMessage + + parameters = callFlags.Arg(1) + if parameters == "" { + params = nil + } else { + json.Unmarshal([]byte(parameters), ¶ms) + } + + var flags uint64 + flags = 0 + if oneway { + flags |= varlink.Oneway + } + recv, err := con.Send(methodName, params, flags) + + var retval map[string]interface{} + + // FIXME: Use cont + _, err = recv(&retval) + + f := colorjson.NewFormatter() + f.Indent = 2 + f.KeyColor = color.New(color.FgCyan) + f.StringColor = color.New(color.FgMagenta) + f.NumberColor = color.New(color.FgMagenta) + f.BoolColor = color.New(color.FgMagenta) + f.NullColor = color.New(color.FgMagenta) + + if err != nil { + ErrPrintf("Error calling '%s': %v\n", methodName, err) + switch e := err.(type) { + case *varlink.Error: + println(e.Name) + errorRawParameters := e.Parameters.(*json.RawMessage) + + if errorRawParameters == nil { + break + } + var param map[string]interface{} + _ = json.Unmarshal(*errorRawParameters, ¶m) + c, _ := f.Marshal(param) + ErrPrintf("%v\n", string(c)) + } + os.Exit(2) + } + c, _ := f.Marshal(retval) + fmt.Println(string(c)) +} + +func varlink_help(args []string) { + var err error + + helpFlags := flag.NewFlagSet("help", flag.ExitOnError) + var help bool + helpFlags.BoolVar(&help, "help", false, "Prints help information") + var usage = func() { print_usage(helpFlags, "<[ADDRESS/]INTERFACE>") } + helpFlags.Usage = usage + + _ = helpFlags.Parse(args) + + if help { + usage() + } + + var con *varlink.Connection + var address string + var interfaceName string + + if len(bridge) != 0 { + con, err = varlink.NewBridge(bridge) + + if err != nil { + ErrPrintf("Cannot connect with bridge '%s': %v\n", bridge, err) + os.Exit(2) + } + address = "bridge:" + bridge + interfaceName = helpFlags.Arg(0) + } else { + uri := helpFlags.Arg(0) + if uri == "" && bridge == "" { + ErrPrintf("No ADDRESS or activation or bridge\n\n") + usage() + } + + li := strings.LastIndex(uri, "/") + + if li == -1 { + ErrPrintf("Invalid address '%s'\n", uri) + os.Exit(2) + } + + address = uri[:li] + + con, err = varlink.NewConnection(address) + + if err != nil { + ErrPrintf("Cannot connect to '%s': %v\n", address, err) + os.Exit(2) + } + + interfaceName = uri[li+1:] + } + description, err := con.GetInterfaceDescription(interfaceName) + + if err != nil { + ErrPrintf("Cannot get interface description for '%s': %v\n", interfaceName, err) + os.Exit(2) + } + + fmt.Println(description) +} + +func varlink_info(args []string) { + var err error + infoFlags := flag.NewFlagSet("info", flag.ExitOnError) + var help bool + infoFlags.BoolVar(&help, "help", false, "Prints help information") + var usage = func() { print_usage(infoFlags, "[ADDRESS]") } + infoFlags.Usage = usage + + _ = infoFlags.Parse(args) + + if help { + usage() + } + + var con *varlink.Connection + var address string + + if len(bridge) != 0 { + con, err = varlink.NewBridge(bridge) + + if err != nil { + ErrPrintf("Cannot connect with bridge '%s': %v\n", bridge, err) + os.Exit(2) + } + address = "bridge:" + bridge + } else { + address = infoFlags.Arg(0) + + if address == "" && bridge == "" { + ErrPrintf("No ADDRESS or activation or bridge\n\n") + usage() + } + + con, err = varlink.NewConnection(address) + + if err != nil { + ErrPrintf("Cannot connect to '%s': %v\n", address, err) + os.Exit(2) + } + } + + var vendor, product, version, url string + var interfaces []string + + err = con.GetInfo(&vendor, &product, &version, &url, &interfaces) + + if err != nil { + ErrPrintf("Cannot get info for '%s': %v\n", address, err) + os.Exit(2) + } + + fmt.Printf("%s %s\n", bold.Sprint("Vendor:"), vendor) + fmt.Printf("%s %s\n", bold.Sprint("Product:"), product) + fmt.Printf("%s %s\n", bold.Sprint("Version:"), version) + fmt.Printf("%s %s\n", bold.Sprint("URL:"), url) + fmt.Printf("%s\n %s\n\n", bold.Sprint("Interfaces:"), strings.Join(interfaces[:], "\n ")) +} + +func main() { + var debug bool + var colorMode string + + flag.CommandLine.Usage = func() { print_usage(nil, "") } + flag.BoolVar(&debug, "debug", false, "Enable debug output") + flag.StringVar(&bridge, "bridge", "", "Use bridge for connection") + flag.StringVar(&colorMode, "color", "auto", "colorize output [default: auto] [possible values: on, off, auto]") + + flag.Parse() + + if colorMode != "on" && (os.Getenv("TERM") == "" || colorMode == "off") { + color.NoColor = true // disables colorized output + } + + switch flag.Arg(0) { + case "info": + varlink_info(flag.Args()[1:]) + case "help": + varlink_help(flag.Args()[1:]) + case "call": + varlink_call(flag.Args()[1:]) + default: + print_usage(nil, "") + } +} diff --git a/vendor/github.com/varlink/go/varlink/bridge.go b/vendor/github.com/varlink/go/varlink/bridge.go new file mode 100644 index 000000000..b20c0925a --- /dev/null +++ b/vendor/github.com/varlink/go/varlink/bridge.go @@ -0,0 +1,59 @@ +// +build !windows + +package varlink + +import ( + "bufio" + "io" + "log" + "net" + "os/exec" +) + +type PipeCon struct { + net.Conn + reader *io.ReadCloser + writer *io.WriteCloser +} + +func (p PipeCon) Close() error { + err1 := (*p.reader).Close() + err2 := (*p.writer).Close() + if err1 != nil { + return err1 + } + if err2 != nil { + return err2 + } + return nil +} + +// NewConnection returns a new connection to the given address. +func NewBridge(bridge string) (*Connection, error) { + //var err error + + c := Connection{} + cmd := exec.Command("sh", "-c", bridge) + r, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + w, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + c.conn = PipeCon{nil, &r, &w} + c.address = "" + c.reader = bufio.NewReader(r) + c.writer = bufio.NewWriter(w) + + go func() { + err := cmd.Run() + if err != nil { + log.Fatal(err) + } + }() + + return &c, nil +} + diff --git a/vendor/github.com/varlink/go/varlink/bridge_windows.go b/vendor/github.com/varlink/go/varlink/bridge_windows.go new file mode 100644 index 000000000..692367a1a --- /dev/null +++ b/vendor/github.com/varlink/go/varlink/bridge_windows.go @@ -0,0 +1,57 @@ +package varlink + +import ( + "bufio" + "io" + "log" + "net" + "os/exec" +) + +type PipeCon struct { + net.Conn + reader *io.ReadCloser + writer *io.WriteCloser +} + +func (p PipeCon) Close() error { + err1 := (*p.reader).Close() + err2 := (*p.writer).Close() + if err1 != nil { + return err1 + } + if err2 != nil { + return err2 + } + return nil +} + +// NewConnection returns a new connection to the given address. +func NewBridge(bridge string) (*Connection, error) { + //var err error + + c := Connection{} + cmd := exec.Command("cmd", "/C", bridge) + r, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + w, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + c.conn = PipeCon{nil, &r, &w} + c.address = "" + c.reader = bufio.NewReader(r) + c.writer = bufio.NewWriter(w) + + go func() { + err := cmd.Run() + if err != nil { + log.Fatal(err) + } + }() + + return &c, nil +} + diff --git a/vendor/github.com/varlink/go/varlink/connection.go b/vendor/github.com/varlink/go/varlink/connection.go index 43bec6393..ac9542408 100644 --- a/vendor/github.com/varlink/go/varlink/connection.go +++ b/vendor/github.com/varlink/go/varlink/connection.go @@ -3,6 +3,7 @@ package varlink import ( "bufio" "encoding/json" + "fmt" "net" "strings" ) @@ -18,6 +19,7 @@ const ( // Error is a varlink error returned from a method call. type Error struct { + error Name string Parameters interface{} } @@ -189,6 +191,11 @@ func NewConnection(address string) (*Connection, error) { var err error words := strings.SplitN(address, ":", 2) + + if len(words) != 2 { + return nil, fmt.Errorf("Protocol missing") + } + protocol := words[0] addr := words[1] diff --git a/vendor/github.com/varlink/go/varlink/service.go b/vendor/github.com/varlink/go/varlink/service.go index 551ba4e53..cb461f917 100644 --- a/vendor/github.com/varlink/go/varlink/service.go +++ b/vendor/github.com/varlink/go/varlink/service.go @@ -6,10 +6,8 @@ import ( "fmt" "net" "os" - "strconv" "strings" "sync" - "syscall" "time" ) @@ -110,58 +108,6 @@ func (s *Service) handleMessage(writer *bufio.Writer, request []byte) error { return iface.VarlinkDispatch(c, methodname) } -func activationListener() net.Listener { - pid, err := strconv.Atoi(os.Getenv("LISTEN_PID")) - if err != nil || pid != os.Getpid() { - return nil - } - - nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS")) - if err != nil || nfds < 1 { - return nil - } - - fd := -1 - - // If more than one file descriptor is passed, find the - // "varlink" tag. The first file descriptor is always 3. - if nfds > 1 { - fdnames, set := os.LookupEnv("LISTEN_FDNAMES") - if !set { - return nil - } - - names := strings.Split(fdnames, ":") - if len(names) != nfds { - return nil - } - - for i, name := range names { - if name == "varlink" { - fd = 3 + i - break - } - } - - if fd < 0 { - return nil - } - - } else { - fd = 3 - } - - syscall.CloseOnExec(fd) - - file := os.NewFile(uintptr(fd), "varlink") - listener, err := net.FileListener(file) - if err != nil { - return nil - } - - return listener -} - // Shutdown shuts down the listener of a running service. func (s *Service) Shutdown() { s.running = false @@ -253,18 +199,17 @@ func getListener(protocol string, address string) (net.Listener, error) { } func (s *Service) refreshTimeout(timeout time.Duration) error { - switch s.protocol { - case "unix": - if err := s.listener.(*net.UnixListener).SetDeadline(time.Now().Add(timeout)); err != nil { + switch l := s.listener.(type) { + case *net.UnixListener: + if err:= l.SetDeadline(time.Now().Add(timeout)); err != nil { return err } - - case "tcp": - if err := s.listener.(*net.TCPListener).SetDeadline(time.Now().Add(timeout)); err != nil { + case *net.TCPListener: + if err:= l.SetDeadline(time.Now().Add(timeout)); err != nil { return err } - } + } return nil } diff --git a/vendor/github.com/varlink/go/varlink/socketactivation.go b/vendor/github.com/varlink/go/varlink/socketactivation.go new file mode 100644 index 000000000..a64c0dc8e --- /dev/null +++ b/vendor/github.com/varlink/go/varlink/socketactivation.go @@ -0,0 +1,63 @@ +// +build !windows + +package varlink + +import ( + "net" + "os" + "strconv" + "strings" + "syscall" +) + +func activationListener() net.Listener { + pid, err := strconv.Atoi(os.Getenv("LISTEN_PID")) + if err != nil || pid != os.Getpid() { + return nil + } + + nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS")) + if err != nil || nfds < 1 { + return nil + } + + fd := -1 + + // If more than one file descriptor is passed, find the + // "varlink" tag. The first file descriptor is always 3. + if nfds > 1 { + fdnames, set := os.LookupEnv("LISTEN_FDNAMES") + if !set { + return nil + } + + names := strings.Split(fdnames, ":") + if len(names) != nfds { + return nil + } + + for i, name := range names { + if name == "varlink" { + fd = 3 + i + break + } + } + + if fd < 0 { + return nil + } + + } else { + fd = 3 + } + + syscall.CloseOnExec(fd) + + file := os.NewFile(uintptr(fd), "varlink") + listener, err := net.FileListener(file) + if err != nil { + return nil + } + + return listener +} diff --git a/vendor/github.com/varlink/go/varlink/socketactivation_windows.go b/vendor/github.com/varlink/go/varlink/socketactivation_windows.go new file mode 100644 index 000000000..fb0894531 --- /dev/null +++ b/vendor/github.com/varlink/go/varlink/socketactivation_windows.go @@ -0,0 +1,7 @@ +package varlink + +import "net" + +func activationListener() net.Listener { + return nil +} -- cgit v1.2.3-54-g00ecf