Skip to content

Commit

Permalink
Merge pull request deis#4105 from technosophos/feature/deisctl-ssh-ex…
Browse files Browse the repository at this point in the history
…ec-docker

feat(deisctl): extend SSH to allow exec and docker
  • Loading branch information
technosophos committed Jul 28, 2015
2 parents e998b29 + 3febf79 commit 11cdd5c
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 24 deletions.
1 change: 1 addition & 0 deletions deisctl/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Backend interface {
Stop([]string, *sync.WaitGroup, io.Writer, io.Writer)
Scale(string, int, *sync.WaitGroup, io.Writer, io.Writer)
SSH(string) error
SSHExec(string, string) error
ListUnits() error
ListUnitFiles() error
Status(string) error
Expand Down
45 changes: 30 additions & 15 deletions deisctl/backend/fleet/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,66 @@ import (
)

// SSH opens an interactive shell to a machine in the cluster
func (c *FleetClient) SSH(name string) (err error) {
var sshClient *ssh.SSHForwardingClient
func (c *FleetClient) SSH(name string) error {
sshClient, err := c.sshConnect(name)
if err != nil {
return err
}

defer sshClient.Close()
err = ssh.Shell(sshClient)
return err
}

func (c *FleetClient) SSHExec(name, cmd string) error {
fmt.Printf("Excuting '%s' on container '%s'\n", cmd, name)

conn, err := c.sshConnect(name)
if err != nil {
return err
}

err, _ = ssh.Execute(conn, cmd)
return err
}

func (c *FleetClient) sshConnect(name string) (*ssh.SSHForwardingClient, error) {

timeout := time.Duration(Flags.SSHTimeout*1000) * time.Millisecond

ms, err := c.machineState(name)
if err != nil {
return err
return nil, err
}

// If name isn't a machine ID, try it as a unit instead
if ms == nil {
units, err := c.Units(name)

if err != nil {
return err
return nil, err
}

machID, err := c.findUnit(units[0])

if err != nil {
return err
return nil, err
}

ms, err = c.machineState(machID)

if err != nil || ms == nil {
return err
return nil, err
}
}

addr := ms.PublicIP

if tun := getTunnelFlag(); tun != "" {
sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr, getChecker(), false, timeout)
} else {
sshClient, err = ssh.NewSSHClient("core", addr, getChecker(), false, timeout)
}
if err != nil {
return err
return ssh.NewTunnelledSSHClient("core", tun, addr, getChecker(), false, timeout)
}
return ssh.NewSSHClient("core", addr, getChecker(), false, timeout)

defer sshClient.Close()
err = ssh.Shell(sshClient)
return err
}

// runCommand will attempt to run a command on a given machine. It will attempt
Expand Down
35 changes: 32 additions & 3 deletions deisctl/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,45 @@ Usage:
func (c *Client) SSH(argv []string) error {
usage := `Open an interactive shell on a machine in the cluster given a unit or machine id.
If an optional <command> is provided, that command is run remotely, and the results returned.
Usage:
deisctl ssh <target>
deisctl ssh <target> [<command>...]
`
// parse command-line arguments
args, err := docopt.Parse(usage, argv, true, "", false)
args, err := docopt.Parse(usage, argv, true, "", true)
if err != nil {
return err
}

return cmd.SSH(args["<target>"].(string), c.Backend)
var vargs []string
if v, ok := args["<command>"]; ok {
vargs = v.([]string)
}

return cmd.SSH(args["<target>"].(string), vargs, c.Backend)
}

func (c *Client) Dock(argv []string) error {
usage := `Connect to the named docker container and run commands on it.
This is equivalent to running 'docker exec -it <target> <command>'.
Usage:
deisctl dock <target> [<command>...]
`
// parse command-line arguments
args, err := docopt.Parse(usage, argv, true, "", true)
if err != nil {
return err
}

var vargs []string
if v, ok := args["<command>"]; ok {
vargs = v.([]string)
}

return cmd.Dock(args["<target>"].(string), vargs, c.Backend)
}

// Start activates the specified components.
Expand Down
22 changes: 18 additions & 4 deletions deisctl/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,10 +464,24 @@ func RefreshUnits(dir, tag, url string) error {
}

// SSH opens an interactive shell on a machine in the cluster
func SSH(target string, b backend.Backend) error {
if err := b.SSH(target); err != nil {
return err
func SSH(target string, cmd []string, b backend.Backend) error {

if len(cmd) > 0 {
return b.SSHExec(target, strings.Join(cmd, " "))
}

return nil
return b.SSH(target)
}

// Dock connects to the appropriate host and runs 'docker exec -it'.
func Dock(target string, cmd []string, b backend.Backend) error {

c := "sh"
if len(cmd) > 0 {
c = strings.Join(cmd, " ")
}

execit := fmt.Sprintf("docker exec -it %s %s", target, c)

return b.SSHExec(target, execit)
}
23 changes: 21 additions & 2 deletions deisctl/cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"sync"
"testing"

"github.com/deis/deis/deisctl/backend"
"github.com/deis/deis/deisctl/units"
)

Expand Down Expand Up @@ -69,6 +70,14 @@ func (backend *backendStub) SSH(target string) error {
}
return errors.New("Error")
}
func (backend *backendStub) SSHExec(target, command string) error {
if target == "controller" && command == "sh" {
return nil
}
return errors.New("Error")
}

var _ backend.Backend = &backendStub{}

func fakeCheckKeys() error {
return nil
Expand Down Expand Up @@ -332,7 +341,17 @@ func TestSSH(t *testing.T) {
t.Parallel()

b := backendStub{}
err := SSH("controller", &b)
err := SSH("controller", []string{}, &b)

if err != nil {
t.Error(err)
}
}
func TestSSHExec(t *testing.T) {
t.Parallel()

b := backendStub{}
err := SSH("controller", []string{"sh"}, &b)

if err != nil {
t.Error(err)
Expand All @@ -343,7 +362,7 @@ func TestSSHError(t *testing.T) {
t.Parallel()

b := backendStub{}
err := SSH("registry", &b)
err := SSH("registry", []string{}, &b)

if err == nil {
t.Error("Error expected")
Expand Down
2 changes: 2 additions & 0 deletions deisctl/deisctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ Options:
err = c.RefreshUnits(argv)
case "ssh":
err = c.SSH(argv)
case "dock":
err = c.Dock(argv)
case "help":
fmt.Print(usage)
return 0
Expand Down
27 changes: 27 additions & 0 deletions docs/troubleshooting_deis/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,33 @@ To open a interactive shell on a machine in your cluster:
$ deisctl ssh <unit>
For example, to open a shell session on the machine that is running Controller,
you can run this:

.. code-block:: console
$ deisctl ssh controller
You can execute just a single command instead of opening a shell:

.. code-block:: console
$ deisctl ssh <unit> <command>
You can also connect directly to the Docker instance of that unit:

.. code-block:: console
$ deisctl dock <unit> <command>
For example, to start a Bash session on the Builder Docker container, you can
run the following command:

.. code-block:: console
$ deisctl dock builder bash`
Troubleshooting etcd
--------------------

Expand Down

0 comments on commit 11cdd5c

Please sign in to comment.