Merge pull request #3042 from baude/bridge

add varlink bridge
This commit is contained in:
OpenShift Merge Robot
2019-05-08 21:12:19 +02:00
committed by GitHub
13 changed files with 118 additions and 42 deletions

View File

@ -32,6 +32,10 @@ type MainFlags struct {
CpuProfile string CpuProfile string
LogLevel string LogLevel string
TmpDir string TmpDir string
RemoteUserName string
RemoteHost string
VarlinkAddress string
} }
type AttachValues struct { type AttachValues struct {

View File

@ -9,7 +9,11 @@ import (
const remote = true const remote = true
func init() { func init() {
// remote client specific flags can go here. rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteUserName, "username", "", "username on the remote host")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteHost, "remote-host", "", "remote host")
// TODO maybe we allow the altering of this for bridge connections?
//rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.VarlinkAddress, "varlink-address", adapter.DefaultAddress, "address of the varlink socket")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error, fatal or panic")
} }
func setSyslog() error { func setSyslog() error {

View File

@ -3,8 +3,6 @@
package shared package shared
import ( import (
"fmt"
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/varlink" "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/rootless"
@ -209,7 +207,6 @@ func boolFromVarlink(v *bool, flagName string, defaultValue bool) CRBool {
cr.Val = defaultValue cr.Val = defaultValue
cr.Changed = false cr.Changed = false
} else { } else {
fmt.Println(flagName, cr.Val)
cr.Val = *v cr.Val = *v
cr.Changed = true cr.Changed = true
} }

View File

@ -3,11 +3,17 @@
package main package main
import ( import (
"fmt"
"os"
"path/filepath"
"time" "time"
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/libpodruntime"
iopodman "github.com/containers/libpod/cmd/podman/varlink" iopodman "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/pkg/varlinkapi" "github.com/containers/libpod/pkg/varlinkapi"
"github.com/containers/libpod/version" "github.com/containers/libpod/version"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -45,13 +51,31 @@ func init() {
} }
func varlinkCmd(c *cliconfig.VarlinkValues) error { func varlinkCmd(c *cliconfig.VarlinkValues) error {
varlinkURI := adapter.DefaultAddress
if rootless.IsRootless() {
xdg, err := util.GetRootlessRuntimeDir()
if err != nil {
return err
}
socketDir := filepath.Join(xdg, "podman/io.podman")
if _, err := os.Stat(filepath.Dir(socketDir)); os.IsNotExist(err) {
if err := os.Mkdir(filepath.Dir(socketDir), 0755); err != nil {
return err
}
}
varlinkURI = fmt.Sprintf("unix:%s", socketDir)
}
args := c.InputArgs args := c.InputArgs
if len(args) < 1 {
return errors.Errorf("you must provide a varlink URI")
}
if len(args) > 1 { if len(args) > 1 {
return errors.Errorf("too many arguments. Requires exactly 1") return errors.Errorf("too many arguments. you may optionally provide 1")
} }
if len(args) > 0 {
varlinkURI = args[0]
}
logrus.Debugf("Using varlink socket: %s", varlinkURI)
timeout := time.Duration(c.Timeout) * time.Millisecond timeout := time.Duration(c.Timeout) * time.Millisecond
// Create a single runtime for varlink // Create a single runtime for varlink
@ -81,7 +105,7 @@ func varlinkCmd(c *cliconfig.VarlinkValues) error {
} }
// Run the varlink server at the given address // Run the varlink server at the given address
if err = service.Listen(args[0], timeout); err != nil { if err = service.Listen(varlinkURI, timeout); err != nil {
switch err.(type) { switch err.(type) {
case varlink.ServiceTimeoutError: case varlink.ServiceTimeoutError:
logrus.Infof("varlink service expired (use --timeout to increase session time beyond %d ms, 0 means never timeout)", c.Int64("timeout")) logrus.Infof("varlink service expired (use --timeout to increase session time beyond %d ms, 0 means never timeout)", c.Int64("timeout"))

View File

@ -7,8 +7,10 @@ podman\-varlink - Runs the varlink backend interface
**podman varlink** [*options*] *uri* **podman varlink** [*options*] *uri*
## DESCRIPTION ## DESCRIPTION
Starts the varlink service listening on *uri* that allows varlink clients to interact with podman. This should generally be done Starts the varlink service listening on *uri* that allows varlink clients to interact with podman. If no *uri* is provided, a default
with systemd. See _Configuration_ below. URI will be used depending on the user calling the varlink service. The default for the root user is `unix:/run/podman/io.podman`. Regular
users will have a default *uri* of `$XDG_RUNTIME_DIR/podman/io.podman`. For example, `unix:/run/user/1000/podman/io.podman`
The varlink service should generally be done with systemd. See _Configuration_ below.
## GLOBAL OPTIONS ## GLOBAL OPTIONS
@ -23,16 +25,23 @@ second. A value of `0` means no timeout and the session will not expire.
## EXAMPLES ## EXAMPLES
Run the podman varlink service manually and accept the default timeout. Run the podman varlink service accepting all default options.
``` ```
$ podman varlink unix:/run/podman/io.podman $ podman varlink
```
Run the podman varlink service with an alternate URI and accept the default timeout.
```
$ podman varlink unix:/tmp/io.podman
``` ```
Run the podman varlink service manually with a 5 second timeout. Run the podman varlink service manually with a 5 second timeout.
``` ```
$ podman varlink --timeout 5000 unix:/run/podman/io.podman $ podman varlink --timeout 5000
``` ```
## CONFIGURATION ## CONFIGURATION

View File

@ -3,30 +3,45 @@
package adapter package adapter
import ( import (
"fmt"
"os" "os"
"github.com/sirupsen/logrus" "github.com/pkg/errors"
"github.com/varlink/go/varlink" "github.com/varlink/go/varlink"
) )
// DefaultAddress is the default address of the varlink socket type VarlinkConnectionInfo struct {
const DefaultAddress = "unix:/run/podman/io.podman" RemoteUserName string
RemoteHost string
VarlinkAddress string
}
// Connect provides a varlink connection // Connect provides a varlink connection
func (r RemoteRuntime) Connect() (*varlink.Connection, error) { func (r RemoteRuntime) Connect() (*varlink.Connection, error) {
var err error var (
var connection *varlink.Connection err error
if bridge := os.Getenv("PODMAN_VARLINK_BRIDGE"); bridge != "" { connection *varlink.Connection
logrus.Infof("Connecting with varlink bridge") )
logrus.Debugf("%s", bridge)
logLevel := r.cmd.LogLevel
// I'm leaving this here for now as a document of the birdge format. It can be removed later once the bridge
// function is more flushed out.
//bridge := `ssh -T root@192.168.122.1 "/usr/bin/varlink -A '/usr/bin/podman varlink \$VARLINK_ADDRESS' bridge"`
if len(r.cmd.RemoteHost) > 0 {
// The user has provided a remote host endpoint
if len(r.cmd.RemoteUserName) < 1 {
return nil, errors.New("you must provide a username when providing a remote host name")
}
bridge := fmt.Sprintf(`ssh -T %s@%s /usr/bin/varlink -A \'/usr/bin/podman --log-level=%s varlink \\\$VARLINK_ADDRESS\' bridge`, r.cmd.RemoteUserName, r.cmd.RemoteHost, logLevel)
connection, err = varlink.NewBridge(bridge)
} else if bridge := os.Getenv("PODMAN_VARLINK_BRIDGE"); bridge != "" {
connection, err = varlink.NewBridge(bridge) connection, err = varlink.NewBridge(bridge)
} else { } else {
address := os.Getenv("PODMAN_VARLINK_ADDRESS") address := os.Getenv("PODMAN_VARLINK_ADDRESS")
if address == "" { if address == "" {
address = DefaultAddress address = DefaultAddress
} }
logrus.Infof("Connecting with varlink address")
logrus.Debugf("%s", address)
connection, err = varlink.NewConnection(address) connection, err = varlink.NewConnection(address)
} }
if err != nil { if err != nil {

View File

@ -0,0 +1,4 @@
package adapter
// DefaultAddress is the default address of the varlink socket
const DefaultAddress = "unix:/run/podman/io.podman"

View File

@ -38,6 +38,7 @@ type RemoteImageRuntime struct{}
type RemoteRuntime struct { type RemoteRuntime struct {
Conn *varlink.Connection Conn *varlink.Connection
Remote bool Remote bool
cmd cliconfig.MainFlags
} }
// LocalRuntime describes a typical libpod runtime // LocalRuntime describes a typical libpod runtime
@ -47,17 +48,17 @@ type LocalRuntime struct {
// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it // GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it
func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) { func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
runtime := RemoteRuntime{} runtime := RemoteRuntime{
Remote: true,
cmd: c.GlobalFlags,
}
conn, err := runtime.Connect() conn, err := runtime.Connect()
if err != nil { if err != nil {
return nil, err return nil, err
} }
runtime.Conn = conn
return &LocalRuntime{ return &LocalRuntime{
&RemoteRuntime{ &runtime,
Conn: conn,
Remote: true,
},
}, nil }, nil
} }

View File

@ -60,6 +60,7 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys st
if !start && state != libpod.ContainerStateRunning { if !start && state != libpod.ContainerStateRunning {
return call.ReplyErrorOccurred("container must be running to attach") return call.ReplyErrorOccurred("container must be running to attach")
} }
call.Reply(nil)
reader, writer, _, pw, streams := setupStreams(call) reader, writer, _, pw, streams := setupStreams(call)
go func() { go func() {

View File

@ -86,15 +86,18 @@ func (i *LibpodAPI) GetInfo(call iopodman.VarlinkCall) error {
Graph_status: graphStatus, Graph_status: graphStatus,
} }
registriesInterface := info[2].Data["registries"] if len(info) > 2 {
insecureRegistriesInterface := info[3].Data["registries"] registriesInterface := info[2].Data["registries"]
if registriesInterface != nil { if registriesInterface != nil {
registries = registriesInterface.([]string) registries = registriesInterface.([]string)
}
} }
if insecureRegistriesInterface != nil { if len(info) > 3 {
insecureRegistries = insecureRegistriesInterface.([]string) insecureRegistriesInterface := info[3].Data["registries"]
if insecureRegistriesInterface != nil {
insecureRegistries = insecureRegistriesInterface.([]string)
}
} }
podmanInfo.Store = infoStore podmanInfo.Store = infoStore
podmanInfo.Podman = pmaninfo podmanInfo.Podman = pmaninfo
podmanInfo.Registries = registries podmanInfo.Registries = registries

View File

@ -93,8 +93,8 @@ k8s.io/api kubernetes-1.10.13-beta.0 https://github.com/kubernetes/api
k8s.io/apimachinery kubernetes-1.10.13-beta.0 https://github.com/kubernetes/apimachinery k8s.io/apimachinery kubernetes-1.10.13-beta.0 https://github.com/kubernetes/apimachinery
k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go
github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7 github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7
github.com/varlink/go 64e07fabffa33e385817b41971cf2674f692f391
github.com/containers/buildah v1.8.2 github.com/containers/buildah v1.8.2
github.com/varlink/go 0f1d566d194b9d6d48e0d47c5e4d822628919066
# TODO: Gotty has not been updated since 2012. Can we find replacement? # TODO: Gotty has not been updated since 2012. Can we find replacement?
github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512 github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512
github.com/fsouza/go-dockerclient v1.3.0 github.com/fsouza/go-dockerclient v1.3.0

View File

@ -6,6 +6,7 @@ import (
"bufio" "bufio"
"io" "io"
"net" "net"
"os"
"os/exec" "os/exec"
) )
@ -30,12 +31,13 @@ func (p PipeCon) Close() error {
return nil return nil
} }
// NewConnection returns a new connection to the given address. // NewBridgeWithStderr returns a new connection with the given bridge.
func NewBridge(bridge string) (*Connection, error) { func NewBridgeWithStderr(bridge string, stderr io.Writer) (*Connection, error) {
//var err error //var err error
c := Connection{} c := Connection{}
cmd := exec.Command("sh", "-c", bridge) cmd := exec.Command("sh", "-c", bridge)
cmd.Stderr = stderr
r, err := cmd.StdoutPipe() r, err := cmd.StdoutPipe()
if err != nil { if err != nil {
return nil, err return nil, err
@ -56,3 +58,8 @@ func NewBridge(bridge string) (*Connection, error) {
return &c, nil return &c, nil
} }
// NewBridge returns a new connection with the given bridge.
func NewBridge(bridge string) (*Connection, error) {
return NewBridgeWithStderr(bridge, os.Stderr)
}

View File

@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"io" "io"
"net" "net"
"os"
"os/exec" "os/exec"
) )
@ -28,12 +29,13 @@ func (p PipeCon) Close() error {
return nil return nil
} }
// NewConnection returns a new connection to the given address. // NewBridgeWithStderr returns a new connection with the given bridge.
func NewBridge(bridge string) (*Connection, error) { func NewBridgeWithStderr(bridge string, stderr io.Writer) (*Connection, error) {
//var err error //var err error
c := Connection{} c := Connection{}
cmd := exec.Command("cmd", "/C", bridge) cmd := exec.Command("cmd", "/C", bridge)
cmd.Stderr = stderr
r, err := cmd.StdoutPipe() r, err := cmd.StdoutPipe()
if err != nil { if err != nil {
return nil, err return nil, err
@ -54,3 +56,8 @@ func NewBridge(bridge string) (*Connection, error) {
return &c, nil return &c, nil
} }
// NewBridge returns a new connection with the given bridge.
func NewBridge(bridge string) (*Connection, error) {
return NewBridgeWithStderr(bridge, os.Stderr)
}