Skip to content

Commit

Permalink
Add an env implementation for varlink bridge
Browse files Browse the repository at this point in the history
  • Loading branch information
afbjorklund committed Nov 25, 2018
1 parent 3dbf45a commit e076649
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 9 deletions.
4 changes: 4 additions & 0 deletions commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ var Commands = []cli.Command{
Description: "Argument is a machine name.",
Action: runCommand(cmdEnv),
Flags: []cli.Flag{
cli.BoolFlag{
Name: "varlink",
Usage: "Set varlink bridge, instead of podman variables",
},
cli.StringFlag{
Name: "shell",
Usage: "Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, emacs], default is auto-detect",
Expand Down
35 changes: 30 additions & 5 deletions commands/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
)

const (
envTmpl = `{{ .Prefix }}PODMAN_USER{{ .Delimiter }}{{ .PodmanUser }}{{ .Suffix }}{{ .Prefix }}PODMAN_HOST{{ .Delimiter }}{{ .PodmanHost }}{{ .Suffix }}{{ .Prefix }}PODMAN_PORT{{ .Delimiter }}{{ .PodmanPort }}{{ .Suffix }}{{ .Prefix }}PODMAN_IDENTITY_FILE{{ .Delimiter }}{{ .IdentityFile }}{{ .Suffix }}{{ if .KnownHosts }}{{ .Prefix }}PODMAN_KNOWN_HOSTS{{ .Delimiter }}{{ .KnownHosts }}{{ .Suffix }}{{else}}{{ .Prefix }}PODMAN_IGNORE_HOSTS{{ .Delimiter }}true{{ .Suffix }}{{end}}{{ .Prefix }}PODMAN_MACHINE_NAME{{ .Delimiter }}{{ .MachineName }}{{ .Suffix }}{{ if .ComposePathsVar }}{{ .Prefix }}COMPOSE_CONVERT_WINDOWS_PATHS{{ .Delimiter }}true{{ .Suffix }}{{end}}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}`
envTmpl = `{{ .Prefix }}PODMAN_USER{{ .Delimiter }}{{ .PodmanUser }}{{ .Suffix }}{{ .Prefix }}PODMAN_HOST{{ .Delimiter }}{{ .PodmanHost }}{{ .Suffix }}{{ .Prefix }}PODMAN_PORT{{ .Delimiter }}{{ .PodmanPort }}{{ .Suffix }}{{ .Prefix }}PODMAN_IDENTITY_FILE{{ .Delimiter }}{{ .IdentityFile }}{{ .Suffix }}{{ if .KnownHosts }}{{ .Prefix }}PODMAN_KNOWN_HOSTS{{ .Delimiter }}{{ .KnownHosts }}{{ .Suffix }}{{else}}{{ .Prefix }}PODMAN_IGNORE_HOSTS{{ .Delimiter }}true{{ .Suffix }}{{end}}{{ .Prefix }}PODMAN_MACHINE_NAME{{ .Delimiter }}{{ .MachineName }}{{ .Suffix }}{{ if .ComposePathsVar }}{{ .Prefix }}COMPOSE_CONVERT_WINDOWS_PATHS{{ .Delimiter }}true{{ .Suffix }}{{end}}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}`
bridgeTmpl = `{{ .Prefix }}VARLINK_BRIDGE{{ .Delimiter }}{{ .VarlinkBridge }}{{ .Suffix }}{{ .UsageHint }}`
)

var (
Expand All @@ -36,6 +37,7 @@ type ShellConfig struct {
PodmanPort int
IdentityFile string
KnownHosts string
VarlinkBridge string
UsageHint string
MachineName string
NoProxyVar string
Expand Down Expand Up @@ -65,7 +67,11 @@ func cmdEnv(c CommandLine, api libmachine.API) error {
}
}

return executeTemplateStdout(shellCfg)
if c.Bool("varlink") {
return executeTemplateStdout(shellCfg, bridgeTmpl)
} else {
return executeTemplateStdout(shellCfg, envTmpl)
}
}

func shellCfgSet(c CommandLine, api libmachine.API) (*ShellConfig, error) {
Expand All @@ -91,7 +97,7 @@ func shellCfgSet(c CommandLine, api libmachine.API) (*ShellConfig, error) {
var shellCfg *ShellConfig
hint := defaultUsageHinter.GenerateUsageHint(userShell, os.Args)

if host.Driver != nil {
if host.Driver != nil && c.Bool("varlink") == false {

user := host.Driver.GetSSHUsername()
if err != nil {
Expand Down Expand Up @@ -123,6 +129,25 @@ func shellCfgSet(c CommandLine, api libmachine.API) (*ShellConfig, error) {
UsageHint: hint,
MachineName: host.Name,
}

} else if host.Driver != nil {

client, err := host.CreateExternalRootSSHClient()
if err != nil {
return nil, err
}

command := []string{client.BinaryPath}
command = append(command, client.BaseArgs...)
command = append(command, "varlink", "bridge")
bridge := strings.Join(command, " ")

shellCfg = &ShellConfig{
VarlinkBridge: bridge,
UsageHint: hint,
MachineName: host.Name,
}

} else {
shellCfg = &ShellConfig{
UsageHint: hint,
Expand Down Expand Up @@ -234,9 +259,9 @@ func shellCfgUnset(c CommandLine, api libmachine.API) (*ShellConfig, error) {
return shellCfg, nil
}

func executeTemplateStdout(shellCfg *ShellConfig) error {
func executeTemplateStdout(shellCfg *ShellConfig, strTmpl string) error {
t := template.New("envConfig")
tmpl, err := t.Parse(envTmpl)
tmpl, err := t.Parse(strTmpl)
if err != nil {
return err
}
Expand Down
88 changes: 88 additions & 0 deletions commands/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package commands

import (
"os"
"strings"
"testing"

"github.com/boot2podman/machine/commands/commandstest"
"github.com/boot2podman/machine/drivers/fakedriver"
"github.com/boot2podman/machine/libmachine"
"github.com/boot2podman/machine/libmachine/drivers"
"github.com/boot2podman/machine/libmachine/host"
"github.com/boot2podman/machine/libmachine/libmachinetest"
"github.com/boot2podman/machine/libmachine/ssh"
"github.com/boot2podman/machine/libmachine/state"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -549,3 +552,88 @@ func TestShellCfgUnset(t *testing.T) {
os.Setenv(test.noProxyVar, "")
}
}

type FakeRootSSHClientCreator struct {
rootclient *ssh.ExternalClient
}

func (fsc *FakeRootSSHClientCreator) CreateSSHClient(d drivers.Driver) (ssh.Client, error) {
return nil, nil
}

func (fsc *FakeRootSSHClientCreator) CreateExternalRootSSHClient(d drivers.Driver) (*ssh.ExternalClient, error) {
if fsc.rootclient == nil {
fsc.rootclient = &ssh.ExternalClient{}
}
return fsc.rootclient, nil
}

func TestVarlink(t *testing.T) {
const (
usageHint = "This is the varlink usage hint"
)

defer revertUsageHinter(defaultUsageHinter)
defaultUsageHinter = &SimpleUsageHintGenerator{usageHint}

sshBinaryPath := "/usr/bin/ssh"
sshBaseArgs := "-F /dev/null -o LogLevel=quiet-o root@localhost"

cc := FakeRootSSHClientCreator{rootclient: &ssh.ExternalClient{}}
cc.rootclient.BinaryPath = sshBinaryPath
cc.rootclient.BaseArgs = strings.Split(sshBaseArgs, " ")

var tests = []struct {
description string
commandLine CommandLine
api libmachine.API
clientCreator host.SSHClientCreator
expectedShellCfg *ShellConfig
expectedErr error
}{
{
description: "bash shell varlink happy path",
commandLine: &commandstest.FakeCommandLine{
CliArgs: nil,
LocalFlags: &commandstest.FakeFlagger{
Data: map[string]interface{}{
"shell": "bash",
"varlink": true,
},
},
},
api: &libmachinetest.FakeAPI{
Hosts: []*host.Host{
{
Name: defaultMachineName,
Driver: &fakedriver.Driver{
MockState: state.Running,
MockIP: "127.0.0.1",
MockHostname: "localhost",
},
},
},
},
clientCreator: &cc,
expectedShellCfg: &ShellConfig{
Prefix: "export ",
Delimiter: "=\"",
Suffix: "\"\n",
UsageHint: usageHint,
MachineName: defaultMachineName,
VarlinkBridge: sshBinaryPath + " " + sshBaseArgs + " varlink bridge",
},
expectedErr: nil,
},
}

for _, test := range tests {
host.SetSSHClientCreator(test.clientCreator)

t.Log(test.description)

shellCfg, err := shellCfgSet(test.commandLine, test.api)
assert.Equal(t, test.expectedShellCfg, shellCfg)
assert.Equal(t, test.expectedErr, err)
}
}
4 changes: 4 additions & 0 deletions commands/ssh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ func (fsc *FakeSSHClientCreator) CreateSSHClient(d drivers.Driver) (ssh.Client,
return fsc.client, nil
}

func (fsc *FakeSSHClientCreator) CreateExternalRootSSHClient(d drivers.Driver) (*ssh.ExternalClient, error) {
return nil, nil
}

func TestCmdSSH(t *testing.T) {
testCases := []struct {
commandLine CommandLine
Expand Down
9 changes: 5 additions & 4 deletions drivers/fakedriver/fakedriver.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import (

type Driver struct {
*drivers.BaseDriver
MockState state.State
MockIP string
MockName string
MockState state.State
MockIP string
MockName string
MockHostname string
}

func (d *Driver) GetCreateFlags() []mcnflag.Flag {
Expand Down Expand Up @@ -57,7 +58,7 @@ func (d *Driver) GetIP() (string, error) {
}

func (d *Driver) GetSSHHostname() (string, error) {
return "", nil
return d.MockHostname, nil
}

func (d *Driver) GetSSHKeyPath() string {
Expand Down
30 changes: 30 additions & 0 deletions libmachine/host/host.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package host

import (
"os/exec"
"regexp"

"github.com/boot2podman/machine/libmachine/auth"
Expand All @@ -22,6 +23,7 @@ var (

type SSHClientCreator interface {
CreateSSHClient(d drivers.Driver) (ssh.Client, error)
CreateExternalRootSSHClient(d drivers.Driver) (*ssh.ExternalClient, error)
}

type StandardSSHClientCreator struct {
Expand Down Expand Up @@ -86,6 +88,34 @@ func (creator *StandardSSHClientCreator) CreateSSHClient(d drivers.Driver) (ssh.
return ssh.NewClient(d.GetSSHUsername(), addr, port, auth)
}

func (h *Host) CreateExternalRootSSHClient() (*ssh.ExternalClient, error) {
return stdSSHClientCreator.CreateExternalRootSSHClient(h.Driver)
}

func (creator *StandardSSHClientCreator) CreateExternalRootSSHClient(d drivers.Driver) (*ssh.ExternalClient, error) {
sshBinaryPath, err := exec.LookPath("ssh")
if err != nil {
return &ssh.ExternalClient{}, err
}

addr, err := d.GetSSHHostname()
if err != nil {
return &ssh.ExternalClient{}, err
}

port, err := d.GetSSHPort()
if err != nil {
return &ssh.ExternalClient{}, err
}

auth := &ssh.Auth{}
if d.GetSSHKeyPath() != "" {
auth.Keys = []string{d.GetSSHKeyPath()}
}

return ssh.NewExternalClient(sshBinaryPath, "root", addr, port, auth)
}

func (h *Host) runActionForState(action func() error, desiredState state.State) error {
if drivers.MachineInState(h.Driver, desiredState)() {
return mcnerror.ErrHostAlreadyInState{
Expand Down

0 comments on commit e076649

Please sign in to comment.