From 8739246151fff6f6403e990a93ffe9b97c221e1d Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Wed, 21 Oct 2015 12:34:42 -0700 Subject: [PATCH] initial commit for ssh plugin --- .drone.sec | 1 + .drone.yml | 29 +++++++++++++++++++ .gitignore | 2 ++ DOCS.md | 19 +++++++++++++ Dockerfile | 12 ++++++++ logo.svg | 7 +++++ main.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ main_test.go | 44 +++++++++++++++++++++++++++++ 8 files changed, 192 insertions(+) create mode 100644 .drone.sec create mode 100644 .drone.yml create mode 100644 DOCS.md create mode 100644 Dockerfile create mode 100644 logo.svg create mode 100644 main.go create mode 100644 main_test.go diff --git a/.drone.sec b/.drone.sec new file mode 100644 index 0000000..a8cf72e --- /dev/null +++ b/.drone.sec @@ -0,0 +1 @@ +eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.1v4prWhimHOoJmXNSKBt5IjNBsTYNaKLZOtxZO_n7iv-nKiTFEQnxbNtIvLVRTPAbhBIlr8XqR-zDlttB_B9PHrLxfKFe7emNgHa66xKSmLNbT2f2oPwv1l-gGGAHQSrpbz3VfG9JtLjsci-UaDPf7ovUe_KqnPPVhw92shvY_8pt6IIBnM_trG7nzwL9sKOVz6kOkPi1rXsTCiylgShCp7yIFWXCJPAQXygdBfy2U0CiIS5u2d6kS9kiOEmq5j7oDSw8kkglM3PPRWXH2iYGA7W1LuKTthX904S55iAJ9vanAo7uuDKtRBfz6reYG-O6wNGP9H8QQOe87lA5GMdPQ.KMKq9cLqmgUF6LOT.UtS2QLKukG_mcUB4z6OddpZftBpUG6IAGTMHKMYfZd170pBVWpApW5jzPpb1CzIzMc-8muuMbKHu6f6YeZlkpOCet8uO19nlSmk8Tx9IAQUk_e2mhFysaUpljqMLDNGKWKZiFRoJ4uQMmcZlkiozQDhEkcHbBGQ2TnzRZlSJ9DhFDo1-WqLZks56btnh-Iat79Vb3IkEzT8Bpybq9bSREy2YK8wBe6XqSf8qUQ.EEfQBB-UuDyuf_ZERANIPA diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..90f5079 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,29 @@ +build: + image: golang:1.5 + environment: + - GO15VENDOREXPERIMENT=1 + - GOOS=linux + - GOARCH=amd64 + - CGO_ENABLED=0 + commands: + - go get + - go build + - go test + +publish: + docker: + username: drone + password: $$DOCKER_PASS + email: $$DOCKER_EMAIL + repo: plugins/drone-ssh + when: + branch: master + +plugin: + name: SSH + desc: Use SSH to execute commands on a remote host + type: deploy + image: plugins/drone-ssh + labels: + - deploy + - ssh diff --git a/.gitignore b/.gitignore index daf913b..a0a8502 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ _testmain.go *.exe *.test *.prof + +drone-ssh \ No newline at end of file diff --git a/DOCS.md b/DOCS.md new file mode 100644 index 0000000..e32bcea --- /dev/null +++ b/DOCS.md @@ -0,0 +1,19 @@ +Use the SSH plugin to execute commands on a remote server. The following parameters are used to configure this plugin: + +* `host` - address or IP of the remote machine +* `port` - port to connect to on the remote machine +* `user` - user to log in as on the remote machine +* `commands` - list of commands to execute + +The following is a sample SSH configuration in your .drone.yml file: + +```yaml +deploy: + ssh: + host: foo.com + user: root + port: 22 + commands: + - echo hello + - echo world +``` \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d021147 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +# Docker image for the Drone build runner +# +# CGO_ENABLED=0 go build -a -tags netgo +# docker build --rm=true -t plugins/drone-ssh . + +FROM gliderlabs/alpine:3.1 +RUN apk add --update \ + python \ + py-pip \ + && pip install awscli +ADD drone-ssh /bin/ +ENTRYPOINT ["/bin/drone-ssh"] \ No newline at end of file diff --git a/logo.svg b/logo.svg new file mode 100644 index 0000000..c06ba82 --- /dev/null +++ b/logo.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..8604952 --- /dev/null +++ b/main.go @@ -0,0 +1,78 @@ +package main + +import ( + "fmt" + "net" + "os" + "strconv" + "strings" + + "github.com/drone/drone-plugin-go/plugin" + "golang.org/x/crypto/ssh" +) + +// Params stores the git clone parameters used to +// configure and customzie the git clone behavior. +type Params struct { + Commands []string `json:"commands"` + Login string `json:"user"` + Port int `json:"port"` + Host string `json:"host"` +} + +func main() { + v := new(Params) + w := new(plugin.Workspace) + plugin.Param("workspace", w) + plugin.Param("vargs", &v) + plugin.MustParse() + + err := run(w.Keys, v) + if err != nil { + os.Exit(1) + } +} + +func run(keys *plugin.Keypair, params *Params) error { + + // if no username is provided assume root + if len(params.Login) == 0 { + params.Login = "root" + } + + // if no username is provided assume root + if params.Port == 0 { + params.Port = 22 + } + + // join the host and port if necessary + host := net.JoinHostPort( + params.Host, + strconv.Itoa(params.Port), + ) + + signer, err := ssh.ParsePrivateKey([]byte(keys.Private)) + if err != nil { + return fmt.Errorf("Error parsing private key. %s.", err) + } + + config := &ssh.ClientConfig{ + User: params.Login, + Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)}, + } + + client, err := ssh.Dial("tcp", host, config) + if err != nil { + return fmt.Errorf("Error dialing server. %s.", err) + } + + session, err := client.NewSession() + if err != nil { + return fmt.Errorf("Error starting ssh session. %s.", err) + } + defer session.Close() + + session.Stdout = os.Stdout + session.Stderr = os.Stderr + return session.Run(strings.Join(params.Commands, "\n")) +} diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..2083397 --- /dev/null +++ b/main_test.go @@ -0,0 +1,44 @@ +package main + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/drone/drone-plugin-go/plugin" +) + +var ( + host = os.Getenv("TEST_SSH_HOST") + user = os.Getenv("TEST_SSH_USER") + key = os.Getenv("TEST_SSH_KEY") +) + +func TestRun(t *testing.T) { + + // only runs the test if a host server is provided + if len(host) == 0 { + t.Skipf("TEST_SSH_HOST not provided") + return + } + + out, err := ioutil.ReadFile(key) + if err != nil { + t.Errorf("Unable to read or find a test privte key. %s", err) + } + + params := &Params{ + Commands: []string{"whoami", "time", "ps -ax"}, + Login: user, + Host: host, + } + + keys := &plugin.Keypair{ + Private: string(out), + } + + err = run(keys, params) + if err != nil { + t.Errorf("Unable to run SSH commands. %s.", err) + } +}