mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-07 09:05:55 +00:00
added basic ssh based remote operation
This commit is contained in:
parent
508e579f3e
commit
a57f806ee5
2 changed files with 165 additions and 0 deletions
30
remote/remote_test.go
Normal file
30
remote/remote_test.go
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package remote
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestRemote(t *testing.T) {
|
||||
|
||||
Convey("Login", t, func() {
|
||||
pem_file := "id_dsa"
|
||||
if _, err := os.Stat(pem_file); err == nil {
|
||||
ssh, err := New("50.16.204.123:22", "todd", "id_dsa")
|
||||
So(err, ShouldEqual, nil)
|
||||
err = ssh.Launch("sleep 10 && date", "background")
|
||||
So(err, ShouldEqual, nil)
|
||||
content, _ := ssh.Run("date", false)
|
||||
ssh.CopyTo([]byte(content), "uploadfile")
|
||||
results, _ := ssh.CopyFrom("uploadfile")
|
||||
ok := bytes.Equal([]byte(content), results)
|
||||
So(ok, ShouldEqual, true)
|
||||
} else {
|
||||
fmt.Println("No credentials so SSH Test ignored")
|
||||
So(true, ShouldEqual, true)
|
||||
}
|
||||
})
|
||||
}
|
||||
135
remote/ssh.go
Normal file
135
remote/ssh.go
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
package remote
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"github.com/wsxiaoys/terminal/color"
|
||||
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
)
|
||||
|
||||
type keychain struct {
|
||||
keys []ssh.Signer
|
||||
}
|
||||
|
||||
func (k *keychain) Key(i int) (ssh.PublicKey, error) {
|
||||
if i < 0 || i >= len(k.keys) {
|
||||
return nil, nil
|
||||
}
|
||||
return k.keys[i].PublicKey(), nil
|
||||
}
|
||||
|
||||
func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
|
||||
return k.keys[i].Sign(rand, data)
|
||||
}
|
||||
|
||||
func (k *keychain) add(key ssh.Signer) {
|
||||
k.keys = append(k.keys, key)
|
||||
}
|
||||
|
||||
func (k *keychain) loadPEM(file string) error {
|
||||
buf, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key, err := ssh.ParsePrivateKey(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k.add(key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *keychain) loadPEMString(buf string) error {
|
||||
key, err := ssh.ParsePrivateKey([]byte(buf))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k.add(key)
|
||||
return nil
|
||||
}
|
||||
|
||||
type SSH struct {
|
||||
client *ssh.ClientConn
|
||||
}
|
||||
|
||||
func (self *SSH) Launch(command string, server_log_path string) error {
|
||||
command = fmt.Sprintf("/usr/bin/nohup bash -c \\\n\"%s\" `</dev/null` >%s 2>&1 &", command, server_log_path)
|
||||
var b bytes.Buffer
|
||||
var e bytes.Buffer
|
||||
session, _ := self.client.NewSession()
|
||||
defer session.Close()
|
||||
session.Stdout = &b
|
||||
session.Stderr = &e
|
||||
return session.Run(command)
|
||||
}
|
||||
|
||||
func (self *SSH) Run(command string, sudo bool) (string, error) {
|
||||
var b bytes.Buffer
|
||||
var e bytes.Buffer
|
||||
session, _ := self.client.NewSession()
|
||||
defer session.Close()
|
||||
session.Stdout = &b
|
||||
session.Stderr = &e
|
||||
if sudo {
|
||||
command = fmt.Sprintf("/usr/bin/sudo bash <<CMD\nexport PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin\n%s\nCMD", command)
|
||||
} else {
|
||||
command = fmt.Sprintf("bash <<CMD\nexport PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n%s\nCMD", command)
|
||||
}
|
||||
|
||||
if err := session.Run(command); err != nil {
|
||||
//error
|
||||
return e.String(), err
|
||||
}
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
func (self *SSH) CopyTo(content []byte, dest_name string) error {
|
||||
|
||||
session, err := self.client.NewSession()
|
||||
defer session.Close()
|
||||
|
||||
go func() {
|
||||
w, _ := session.StdinPipe()
|
||||
defer w.Close()
|
||||
w.Write(content)
|
||||
}()
|
||||
err = session.Run(fmt.Sprintf("/bin/cat >%s", dest_name))
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SSH) CopyFrom(dest_name string) ([]byte, error) {
|
||||
|
||||
session, _ := self.client.NewSession()
|
||||
defer session.Close()
|
||||
var b bytes.Buffer
|
||||
session.Stdout = &b
|
||||
session.Run(fmt.Sprintf("/bin/cat %s", dest_name))
|
||||
|
||||
return b.Bytes(), nil
|
||||
|
||||
}
|
||||
|
||||
func New(host, user, pem_path string) (*SSH, error) {
|
||||
ret := new(SSH)
|
||||
k := new(keychain)
|
||||
k.loadPEM(pem_path)
|
||||
config := &ssh.ClientConfig{
|
||||
User: user,
|
||||
Auth: []ssh.ClientAuth{
|
||||
ssh.ClientAuthKeyring(k),
|
||||
},
|
||||
}
|
||||
client, err := ssh.Dial("tcp", host, config)
|
||||
if err != nil {
|
||||
|
||||
color.Printf("@{!r}%s: Failed to connect: %s\n", host, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
ret.client = client
|
||||
|
||||
return ret, err
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue