Compare commits

...

114 Commits

Author SHA1 Message Date
Bo-Yi Wu b83dae891d add arch
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-05-15 07:08:08 +08:00
Bo-Yi Wu 27b9f04a04 remove secrets flag
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-05-15 06:45:04 +08:00
Bo-Yi Wu f6128860ab chore: Add short variable 2019-05-14 22:15:29 +08:00
Bo-Yi Wu 3505455bb7 Update README.md 2019-05-09 14:16:02 +08:00
Bo-Yi Wu 29018dba3a chore: switch finished to struct{} for zero allocate (#140) 2019-03-30 08:03:16 +08:00
Bo-Yi Wu e7fd9e9b89 docs: update to drone 1.0
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-11 14:47:55 +08:00
Bo-Yi Wu 56b67e1314 chore: change command timeout flag (#138)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-11 14:36:17 +08:00
Bo-Yi Wu e79f8934dc chore: remove build number 2019-03-10 23:44:59 +08:00
Bo-Yi Wu 2fd7649e83 fix: trigger build fail if error 2019-03-10 23:40:29 +08:00
Bo-Yi Wu 89fce5b1d3 chore(variable): change UserName to Username
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-06 11:00:09 +08:00
Bo-Yi Wu 0b241dd368 chore: add revive config
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-04 16:17:27 +08:00
Bo-Yi Wu a92fa054fe chore: add lint check
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-04 16:10:45 +08:00
Bo-Yi Wu 3342cdf59a refactor: error var missingXXX should have name of the form errFoo
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-04 14:47:28 +08:00
Bo-Yi Wu aa95c51e7f refactor(error): update error
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-04 14:42:28 +08:00
Bo-Yi Wu 86a962988d docs: update logo path
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-04 14:28:19 +08:00
Bo-Yi Wu 2584920545 chore: update go module
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-04 14:27:51 +08:00
Bo-Yi Wu d128f2fecf update image path
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-04 12:05:16 +08:00
Bo-Yi Wu 83f8486e15 docs: update badge
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-04 12:01:14 +08:00
Bo-Yi Wu d32a2675d5 feat(vendor): switch to go module (#137)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2019-03-04 10:55:52 +08:00
Bo-Yi Wu 7ac526845d Revert "feat: upgrade easyssh-proxy and update flag of timeout field (#127)" (#128)
This reverts commit eb33537e3f.
2018-10-23 15:54:40 +08:00
Bo-Yi Wu eb33537e3f feat: upgrade easyssh-proxy and update flag of timeout field (#127) 2018-10-23 15:14:48 +08:00
Bo-Yi Wu 3a227c8854 fix: Fix golint to new URL 2018-10-14 15:24:55 +08:00
Bo-Yi Wu d3999bf6cc add microbadger webhook
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2018-10-09 09:02:46 +08:00
Bo-Yi Wu f9cc37282c update golang to 1.11
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2018-09-26 15:42:19 +08:00
Bo-Yi Wu 6e431b0c53 test: add TestCommandScriptStop (#124) 2018-09-26 15:35:57 +08:00
Marco Vito Moscaritolo 3499506089 exit after first error (#123)
Closes #121 

WIP
2018-09-26 15:23:31 +08:00
Josh Komoroske 6c0b475c15 Customization of logger output destination (#117)
* Customization of logger output destination

* Tests to verify output correctness
2018-02-28 14:52:15 +08:00
Josh Komoroske 60993a71e2 Preservation of forwarded environment (#113)
* Tests for omitting unset variables

* Preservation of forwarded environment
2018-02-28 13:44:44 +08:00
Bo-Yi Wu 8bfc58f9d0 test: Add escapeArg testing (#116) 2018-02-27 14:58:43 +08:00
Damian Kaczmarek 7f4cb1c1d0 improve: shell escaping, allow for whitespace and single quotes (#108) 2018-02-27 14:48:38 +08:00
Josh Komoroske f92f762c9d Load PLUGIN_ENV_FILE before app is run (#112) 2018-02-24 19:47:07 +08:00
Bo-Yi Wu 84cb184039 refactor(drone): replace facebook with discord. 2017-12-18 09:34:36 +08:00
Bo-Yi Wu 31c084fd3e remove unused doc.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-12-18 09:30:13 +08:00
Bo-Yi Wu 69b3a40978 update drone-docker plugin. (#107)
* update drone-docker plugin.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* add testing

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* add testing

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* add testing

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-11-09 23:32:01 -06:00
Damian Kaczmarek 4d443c40f2 fix: ssh process error not resulting in pipeline error (#105)
* fix: ssh process error not resulting in pipeline error

* Update main.go
2017-11-09 20:47:15 -06:00
Bo-Yi Wu 9dd4b8db8d add arm arm64 and amd64 build. (#106)
* add arm arm64 and amd64 build.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* add release folder to ignore list.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-11-09 20:12:30 -06:00
Damian Kaczmarek 45f43d7ffd fix: escaping special characters when passing env to ssh (#104) 2017-11-09 19:01:28 -06:00
Bo-Yi Wu 7220c94832 Add sync mode. (#101)
* Add sync mode.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* close channel in sync mode.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* close channel in sync mode.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-10-29 21:31:51 -05:00
Bo-Yi Wu 2d5668ff17 Update document for mount key path. (#100)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-10-29 20:46:16 -05:00
Bo-Yi Wu 6f1ace35bf add build number for drone.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-09-04 17:22:52 +08:00
Bo-Yi Wu 05ebe5b663 update docs
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-09-04 14:40:20 +08:00
Bo-Yi Wu e331f975ad update docs.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-09-04 14:38:04 +08:00
Bo-Yi Wu f943ff7179 update dockerfile. (#99)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-19 21:48:30 +08:00
Bo-Yi Wu 65e15c4aab update gopath (#98)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-19 21:45:07 +08:00
Bo-Yi Wu 83273b5669 add cloc command
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-19 21:35:53 +08:00
Bo-Yi Wu a8392b5f22 fix typo
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-15 15:01:51 +08:00
Bo-Yi Wu e057a699a4 refactor: add group build for drone. (#97)
* refactor: add group build for drone.

* remove codecov_token

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* fix format

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* fix path

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-15 14:52:35 +08:00
Bo-Yi Wu 14fddbbba5 feat: add multiple stage build for docker. (#96)
* feat: add multiple stage build for docker.

* remove unused target

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-15 14:23:25 +08:00
Bo-Yi Wu 5fbd22f265 refactor(Makefile): allow overriding default go program (#95)
* refactor(Makefile): allow overriding default go program

* fix typo

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-15 14:05:11 +08:00
Bo-Yi Wu bf269615ce update docs (#94)
* update docs

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* [ci skip] add username secret.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-13 23:06:31 +08:00
Bo-Yi Wu 538a5a6ce5 remove unsed space.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-09 22:25:26 +08:00
DINESH S 78f4f15754 Update doc with custom secrets example (#93) fix #19 2017-08-09 22:24:08 +08:00
Bo-Yi Wu 40323f23e5 update testing
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-01 17:24:38 +08:00
Bo-Yi Wu ed83305de8 add debug mode. (#92)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-01 16:54:34 +08:00
Bo-Yi Wu 4e625fa760 feat: add editor config. 2017-08-01 16:04:55 +08:00
Bo-Yi Wu c79b44dca2 update env key.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-01 12:51:36 +08:00
Bo-Yi Wu c86c472904 fix: env to ToUpper
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-01 12:40:35 +08:00
Bo-Yi Wu ecfaecd46d feat(env): pass secret to remote server. (#91)
* feat(env): pass secret to remote server.

* add testing

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-08-01 12:01:37 +08:00
Bo-Yi Wu e6d4fa77d1 add notify
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-06-24 22:58:13 +08:00
Bo-Yi Wu 9651a4eb6c feat: add check unused package. (#85) 2017-06-03 01:13:19 -05:00
Bo-Yi Wu b5b13e8b72 upgrade easyssh to 1.1.6 (#81)
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-16 15:45:00 +08:00
Bo-Yi Wu 26b3d47ee2 add exit code example.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-13 13:47:00 +08:00
Bo-Yi Wu 0a78278313 add return error code command example.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-12 14:21:33 +08:00
Bo-Yi Wu a7c37e0936 fix panic from easyssh-proxy
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-11 15:14:28 +08:00
Bo-Yi Wu 699d9148d8 update readme.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-10 21:55:56 +08:00
Bo-Yi Wu ceec42efdd bump easyssh package.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-10 21:37:48 +08:00
Bo-Yi Wu 88b5394dac update output
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-10 21:26:34 +08:00
Bo-Yi Wu 1637772e0b hide domain if only single host in config. (#80)
* hide domain if only single host in config.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* fix host

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* refactor

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-10 21:17:31 +08:00
Bo-Yi Wu efdac217bd update log format.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-10 16:42:37 +08:00
Bo-Yi Wu f81056261d add demo gif
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-10 16:21:22 +08:00
Bo-Yi Wu 3fffe80a14 remove timestamp in log
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-10 15:36:20 +08:00
Bo-Yi Wu 2d568d1fde Support stream output logs. (#79)
* Support stream output logs.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* fix block channel.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-10 11:34:00 +08:00
Bo-Yi Wu f26bd7f7f7 update makefile
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-09 15:13:50 +08:00
Bo-Yi Wu 95427edbba update makefile
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-09 15:11:17 +08:00
Bo-Yi Wu 7f168bd1cb update makefile
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-09 15:07:57 +08:00
Bo-Yi Wu b6c973ef1e fix: get exit code from ssh run command. (#78) 2017-05-09 09:38:31 +08:00
Bo-Yi Wu 356b2ae6cc feat: support group build (#76) 2017-05-08 09:06:35 +08:00
Bo-Yi Wu b698d56d60 add some secrets.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-02 22:03:26 +08:00
Bo-Yi Wu 06f4f77ebc update drone to 0.6
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-05-02 21:51:15 +08:00
Bo-Yi Wu b63f275e9e refactor: show errors if set password and key at the same time (#72) 2017-04-23 11:49:40 +08:00
Bo-Yi Wu 4d8adbffca fix: missing github release key 2017-04-21 17:16:55 +08:00
Bo-Yi Wu c73e22e279 refactor: HostKeyCallback is the function type used for verifying server (#68) 2017-04-15 20:49:33 +08:00
Bo-Yi Wu 6c2d8f278d refactor: remove drone sig. (#65) 2017-04-14 09:09:46 +08:00
Bo-Yi Wu a4dc098318 refactor: check gofmt error. (#63) 2017-04-01 22:22:26 +08:00
Bo-Yi Wu c2776cbaed feat: add when.local=false to disable plugin steps locally (#62) 2017-04-01 14:24:31 +08:00
Bo-Yi Wu 05b1a61165 refactor: upgrade easyssh to support DefaultConfig (#61) 2017-04-01 13:57:53 +08:00
Bo-Yi Wu d447bbd595 [ci skip] add proxy config docs
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-03-23 13:45:04 +08:00
Bo-Yi Wu 6921b0b786 fix: command line variable. (#58) 2017-03-04 23:13:55 +08:00
Bo-Yi Wu 20a4793249 fix: typo 2017-03-04 22:11:45 +08:00
Bo-Yi Wu b6ec7c2347 fix: remove check error string. (#57) 2017-03-04 22:01:48 +08:00
Bo-Yi Wu e5dc646e5d fix: redefined: user (#56) 2017-03-04 21:26:18 +08:00
Bo-Yi Wu 530df8d98b feat: Support proxy command. (#55) 2017-03-04 18:31:49 +08:00
Bo-Yi Wu 7e4e0224ee feat: Add time out flag. (#53)
* feat: Add time out flag.

* fix testing

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-03-04 17:50:05 +08:00
Bo-Yi Wu 28ffc3a790 release v1.1.0
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2017-03-04 17:37:25 +08:00
Bo-Yi Wu 6f6e20312f docs: [ci skip] update docs. 2017-03-03 16:15:29 +08:00
Bo-Yi Wu 4507e5e4f0 docs: improve docs (#50) 2017-03-03 16:11:21 +08:00
Bo-Yi Wu bb0d89368f refactor: hash is a much faster shell-builtin alternative to which. (#47) 2017-02-27 21:55:05 +08:00
Kittipun Khantitrirat fdc7a43f73 Fixed logging output typo when finished (#46) 2017-02-26 09:36:19 +08:00
Bo-Yi Wu 833d26f473 feat: support username flag. (#45)
* feat: support username flag.
2017-02-21 11:44:37 +08:00
Bo-Yi Wu 7871a8e9f5 feat: switch glide to govendor. (#43)
* feat: switch glide to govendor.
2017-02-18 23:45:53 +08:00
Bo-Yi Wu 3a5b4aa23b docs: [ci skip] add drone plugin document link. 2017-02-08 10:26:46 +08:00
Bo-Yi Wu 03be9e5be0 refactor: remove unnecessary func. (#40) 2017-02-04 16:37:26 +08:00
Bo-Yi Wu 3943bd28ff docs: [ci skip] add drone document. (#39) 2017-01-31 21:19:00 +08:00
Bo-Yi Wu a8cc62009f refactor: update ssh host using JoinHostPort 2017-01-30 00:45:46 +08:00
Bo-Yi Wu b704ba55cb docs: [ci skip] remove sleep flag. 2017-01-29 12:58:36 +08:00
Bo-Yi Wu 6e733c0a03 feat: add easyssh and go routine. (#38) 2017-01-29 12:57:00 +08:00
Bo-Yi Wu c086c6a226 fix: update image path. 2017-01-28 11:52:56 +08:00
Bo-Yi Wu d87def7ef9 feat: Add unconvert command 2017-01-28 11:42:54 +08:00
Bo-Yi Wu 7314547924 docs: Add change docker image note. 2017-01-25 10:22:01 +08:00
Bo-Yi Wu d9476acbfa docs: remove duplicated of port config. (#36) 2017-01-25 09:21:53 +08:00
Bo-Yi Wu da4a550afd feat: add command line flag. 2017-01-24 15:31:06 +08:00
Bo-Yi Wu 95f777f22e test: improve testing. 2017-01-24 15:06:46 +08:00
Bo-Yi Wu 876c4c1cee feat: Support import private key from file path. (#34) 2017-01-24 11:28:48 +08:00
Bo-Yi Wu 79530c6026 feat: add some testing. (#32) 2017-01-23 16:00:48 +08:00
30 changed files with 1992 additions and 348 deletions
+16
View File
@@ -0,0 +1,16 @@
local pipeline = import 'pipeline.libsonnet';
local name = 'drone-ssh';
[
pipeline.test,
pipeline.build(name, 'linux', 'amd64'),
pipeline.build(name, 'linux', 'arm64'),
pipeline.build(name, 'linux', 'arm'),
pipeline.release,
pipeline.notifications(depends_on=[
'linux-amd64',
'linux-arm64',
'linux-arm',
'release-binary',
]),
]
+379 -69
View File
@@ -1,78 +1,388 @@
workspace:
base: /srv/app
path: src/github.com/appleboy/drone-ssh
---
kind: pipeline
name: testing
pipeline:
clone:
image: plugins/git
tags: true
platform:
os: linux
arch: amd64
# restore the cache from an sftp server
restore_cache:
image: appleboy/drone-sftp-cache
restore: true
mount: [ .glide, vendor ]
ignore_branch: true
steps:
- name: vet
pull: always
image: golang:1.12
commands:
- make vet
environment:
GO111MODULE: on
volumes:
- name: gopath
path: /go
test:
image: appleboy/golang-testing
pull: true
environment:
TAGS: netgo
GOPATH: /srv/app
commands:
- make dep_install
- make vet
- make lint
- make test
- make coverage
- make build
# build binary for docker image
- make static_build
when:
event: [ push, tag, pull_request ]
- name: lint
pull: always
image: golang:1.12
commands:
- make lint
environment:
GO111MODULE: on
volumes:
- name: gopath
path: /go
release:
image: appleboy/golang-testing
pull: true
environment:
TAGS: netgo
GOPATH: /srv/app
commands:
- make release
when:
event: [ tag ]
branch: [ refs/tags/* ]
- name: misspell
pull: always
image: golang:1.12
commands:
- make misspell-check
environment:
GO111MODULE: on
volumes:
- name: gopath
path: /go
publish_tag:
image: plugins/docker
repo: ${DRONE_REPO}
tags: [ '${DRONE_TAG}' ]
when:
event: [ tag ]
branch: [ refs/tags/* ]
- name: test
pull: always
image: golang:1.12-alpine
commands:
- apk add git make curl perl bash build-base zlib-dev ucl-dev
- make ssh-server
- make test
- make coverage
environment:
GO111MODULE: on
volumes:
- name: gopath
path: /go
publish_latest:
image: plugins/docker
repo: ${DRONE_REPO}
tags: [ 'latest' ]
when:
event: [ push ]
branch: [ master ]
- name: codecov
pull: always
image: robertstettner/drone-codecov
settings:
token:
from_secret: codecov_token
release:
image: plugins/github-release
volumes:
- name: gopath
temp: {}
---
kind: pipeline
name: linux-amd64
platform:
os: linux
arch: amd64
steps:
- name: build-push
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/amd64/drone-ssh"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
exclude:
- tag
- name: build-tag
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/amd64/drone-ssh"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
- tag
- name: executable
pull: always
image: golang:1.12
commands:
- ./release/linux/amd64/drone-ssh --help
- name: dryrun
pull: always
image: plugins/docker:linux-amd64
settings:
cache_from: appleboy/drone-ssh
dockerfile: docker/Dockerfile.linux.amd64
dry_run: true
repo: appleboy/drone-ssh
tags: linux-amd64
when:
event:
- pull_request
- name: publish
pull: always
image: plugins/docker:linux-amd64
settings:
auto_tag: true
auto_tag_suffix: linux-amd64
cache_from: appleboy/drone-ssh
daemon_off: false
dockerfile: docker/Dockerfile.linux.amd64
password:
from_secret: docker_password
repo: appleboy/drone-ssh
username:
from_secret: docker_username
when:
event:
exclude:
- pull_request
trigger:
ref:
- refs/heads/master
- "refs/pull/**"
- "refs/tags/**"
depends_on:
- testing
---
kind: pipeline
name: linux-arm64
platform:
os: linux
arch: arm64
steps:
- name: build-push
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm64/drone-ssh"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
exclude:
- tag
- name: build-tag
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm64/drone-ssh"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
- tag
- name: executable
pull: always
image: golang:1.12
commands:
- ./release/linux/arm64/drone-ssh --help
- name: dryrun
pull: always
image: plugins/docker:linux-arm64
settings:
cache_from: appleboy/drone-ssh
dockerfile: docker/Dockerfile.linux.arm64
dry_run: true
repo: appleboy/drone-ssh
tags: linux-arm64
when:
event:
- pull_request
- name: publish
pull: always
image: plugins/docker:linux-arm64
settings:
auto_tag: true
auto_tag_suffix: linux-arm64
cache_from: appleboy/drone-ssh
daemon_off: false
dockerfile: docker/Dockerfile.linux.arm64
password:
from_secret: docker_password
repo: appleboy/drone-ssh
username:
from_secret: docker_username
when:
event:
exclude:
- pull_request
trigger:
ref:
- refs/heads/master
- "refs/pull/**"
- "refs/tags/**"
depends_on:
- testing
---
kind: pipeline
name: linux-arm
platform:
os: linux
arch: arm
steps:
- name: build-push
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm/drone-ssh"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
exclude:
- tag
- name: build-tag
pull: always
image: golang:1.12
commands:
- "go build -v -ldflags '-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}' -a -o release/linux/arm/drone-ssh"
environment:
CGO_ENABLED: 0
GO111MODULE: on
when:
event:
- tag
- name: executable
pull: always
image: golang:1.12
commands:
- ./release/linux/arm/drone-ssh --help
- name: dryrun
pull: always
image: plugins/docker:linux-arm
settings:
cache_from: appleboy/drone-ssh
dockerfile: docker/Dockerfile.linux.arm
dry_run: true
repo: appleboy/drone-ssh
tags: linux-arm
when:
event:
- pull_request
- name: publish
pull: always
image: plugins/docker:linux-arm
settings:
auto_tag: true
auto_tag_suffix: linux-arm
cache_from: appleboy/drone-ssh
daemon_off: false
dockerfile: docker/Dockerfile.linux.arm
password:
from_secret: docker_password
repo: appleboy/drone-ssh
username:
from_secret: docker_username
when:
event:
exclude:
- pull_request
trigger:
ref:
- refs/heads/master
- "refs/pull/**"
- "refs/tags/**"
depends_on:
- testing
---
kind: pipeline
name: release-binary
platform:
os: linux
arch: amd64
steps:
- name: build-all-binary
pull: always
image: golang:1.12
commands:
- make release
environment:
GO111MODULE: on
when:
event:
- tag
- name: deploy-all-binary
pull: always
image: plugins/github-release
settings:
api_key:
from_secret: github_release_api_key
files:
- dist/release/*
when:
event: [ tag ]
branch: [ refs/tags/* ]
- "dist/release/*"
when:
event:
- tag
# rebuild the cache on the sftp server
rebuild_cache:
image: appleboy/drone-sftp-cache
rebuild: true
mount: [ .glide, vendor ]
ignore_branch: true
when:
branch: master
trigger:
ref:
- "refs/tags/**"
depends_on:
- testing
---
kind: pipeline
name: notifications
platform:
os: linux
arch: amd64
steps:
- name: manifest
pull: always
image: plugins/manifest
settings:
ignore_missing: true
password:
from_secret: docker_password
spec: docker/manifest.tmpl
username:
from_secret: docker_username
- name: microbadger
pull: always
image: plugins/webhook:1
settings:
url:
from_secret: microbadger_url
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
depends_on:
- linux-amd64
- linux-arm64
- linux-arm
- release-binary
...
-1
View File
@@ -1 +0,0 @@
eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9zcnYvYXBwCiAgcGF0aDogc3JjL2dpdGh1Yi5jb20vYXBwbGVib3kvZHJvbmUtc3NoCgpwaXBlbGluZToKICBjbG9uZToKICAgIGltYWdlOiBwbHVnaW5zL2dpdAogICAgdGFnczogdHJ1ZQoKICAjIHJlc3RvcmUgdGhlIGNhY2hlIGZyb20gYW4gc2Z0cCBzZXJ2ZXIKICByZXN0b3JlX2NhY2hlOgogICAgaW1hZ2U6IGFwcGxlYm95L2Ryb25lLXNmdHAtY2FjaGUKICAgIHJlc3RvcmU6IHRydWUKICAgIG1vdW50OiBbIC5nbGlkZSwgdmVuZG9yIF0KICAgIGlnbm9yZV9icmFuY2g6IHRydWUKCiAgdGVzdDoKICAgIGltYWdlOiBhcHBsZWJveS9nb2xhbmctdGVzdGluZwogICAgcHVsbDogdHJ1ZQogICAgZW52aXJvbm1lbnQ6CiAgICAgIFRBR1M6IG5ldGdvCiAgICAgIEdPUEFUSDogL3Nydi9hcHAKICAgIGNvbW1hbmRzOgogICAgICAtIG1ha2UgZGVwX2luc3RhbGwKICAgICAgLSBtYWtlIHZldAogICAgICAtIG1ha2UgbGludAogICAgICAtIG1ha2UgdGVzdAogICAgICAtIG1ha2UgY292ZXJhZ2UKICAgICAgLSBtYWtlIGJ1aWxkCiAgICAgICMgYnVpbGQgYmluYXJ5IGZvciBkb2NrZXIgaW1hZ2UKICAgICAgLSBtYWtlIHN0YXRpY19idWlsZAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFsgcHVzaCwgdGFnLCBwdWxsX3JlcXVlc3QgXQoKICByZWxlYXNlOgogICAgaW1hZ2U6IGFwcGxlYm95L2dvbGFuZy10ZXN0aW5nCiAgICBwdWxsOiB0cnVlCiAgICBlbnZpcm9ubWVudDoKICAgICAgVEFHUzogbmV0Z28KICAgICAgR09QQVRIOiAvc3J2L2FwcAogICAgY29tbWFuZHM6CiAgICAgIC0gbWFrZSByZWxlYXNlCiAgICB3aGVuOgogICAgICBldmVudDogWyB0YWcgXQogICAgICBicmFuY2g6IFsgcmVmcy90YWdzLyogXQoKICBwdWJsaXNoX3RhZzoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogJHtEUk9ORV9SRVBPfQogICAgdGFnczogWyAnJHtEUk9ORV9UQUd9JyBdCiAgICB3aGVuOgogICAgICBldmVudDogWyB0YWcgXQogICAgICBicmFuY2g6IFsgcmVmcy90YWdzLyogXQoKICBwdWJsaXNoX2xhdGVzdDoKICAgIGltYWdlOiBwbHVnaW5zL2RvY2tlcgogICAgcmVwbzogJHtEUk9ORV9SRVBPfQogICAgdGFnczogWyAnbGF0ZXN0JyBdCiAgICB3aGVuOgogICAgICBldmVudDogWyBwdXNoIF0KICAgICAgYnJhbmNoOiBbIG1hc3RlciBdCgogIHJlbGVhc2U6CiAgICBpbWFnZTogcGx1Z2lucy9naXRodWItcmVsZWFzZQogICAgZmlsZXM6CiAgICAgIC0gZGlzdC9yZWxlYXNlLyoKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbIHRhZyBdCiAgICAgIGJyYW5jaDogWyByZWZzL3RhZ3MvKiBdCgogICMgcmVidWlsZCB0aGUgY2FjaGUgb24gdGhlIHNmdHAgc2VydmVyCiAgcmVidWlsZF9jYWNoZToKICAgIGltYWdlOiBhcHBsZWJveS9kcm9uZS1zZnRwLWNhY2hlCiAgICByZWJ1aWxkOiB0cnVlCiAgICBtb3VudDogWyAuZ2xpZGUsIHZlbmRvciBdCiAgICBpZ25vcmVfYnJhbmNoOiB0cnVlCiAgICB3aGVuOgogICAgICBicmFuY2g6IG1hc3Rlcgo.MvA91xJBP4JoAxLObpbaumlNtzjO_Gc3znDbTRUjAGY
+42
View File
@@ -0,0 +1,42 @@
# unifying the coding style for different editors and IDEs => editorconfig.org
; indicate this is the root of the project
root = true
###########################################################
; common
###########################################################
[*]
charset = utf-8
end_of_line = LF
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
###########################################################
; make
###########################################################
[Makefile]
indent_style = tab
[makefile]
indent_style = tab
###########################################################
; markdown
###########################################################
[*.md]
trim_trailing_whitespace = false
###########################################################
; golang
###########################################################
[*.go]
indent_style = tab
+2 -1
View File
@@ -25,5 +25,6 @@ _testmain.go
.env
coverage.txt
release
drone-ssh
vendor
.cover
+25
View File
@@ -0,0 +1,25 @@
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 1
warningCode = 1
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.if-return]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
+188 -54
View File
@@ -1,67 +1,201 @@
Use the SSH plugin to execute commands on a remote server. You will need to
supply Drone with a private SSH key to being able to connect to a host.
---
date: 2017-01-29T00:00:00+00:00
title: SSH
author: appleboy
tags: [ publish, ssh ]
repo: appleboy/drone-ssh
logo: term.svg
image: appleboy/drone-ssh
---
## Config
The following parameters are used to configure the 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
* **passsword** - password to log in as on the remote machine
* **key** - private SSH key for the remote machine
* **sleep** - sleep for seconds between host connections
* **timeout** - timeout for the tcp connection attempt
* **script** - list of commands to execute
The following secret values can be set to configure the plugin.
* **SSH_HOST** - corresponds to **host**
* **SSH_PORT** - corresponds to **port**
* **SSH_USER** - corresponds to **user**
* **SSH_PASSWORD** - corresponds to **password**
* **SSH_KEY** - corresponds to **key**
* **SSH_SLEEP** - corresponds to **sleep**
* **SSH_TIMEOUT** - corresponds to **timeout**
## Examples
Example configuration in your .drone.yml file for a single host:
Use the SSH plugin to execute commands on a remote server. The below pipeline configuration demonstrates simple usage:
```yaml
pipeline:
ssh:
image: plugins/ssh
host: foo.com
user: root
password: 1234
port: 22
script:
- echo hello
- echo world
image: appleboy/drone-ssh
settings:
host: foo.com
username: root
password: 1234
port: 22
script:
- echo hello
- echo world
```
Example configuration in your .drone.yml file for multiple hosts:
Example configuration in your `.drone.yml` file for multiple hosts:
```yaml
```diff
pipeline:
ssh:
image: plugins/ssh
host:
- foo.com
- bar.com
user: root
port: 22
sleep: 5
script:
- echo hello
- echo world
image: appleboy/drone-ssh
settings:
host:
+ - foo.com
+ - bar.com
username: root
password: 1234
port: 22
script:
- echo hello
- echo world
```
In the above example Drone executes the commands on multiple hosts
sequentially. If the commands fail on a single host this plugin exits
immediatly, and will not run your commands on the remaining hosts in the
list.
Example configuration for command timeout, default value is 60 seconds:
The above example also uses the `sleep` parameter. The sleep parameter
instructs Drone to sleep for N seconds between host executions.
```diff
pipeline:
ssh:
image: appleboy/drone-ssh
settings:
host: foo.com
username: root
password: 1234
port: 22
+ command_timeout: 2m
script:
- echo hello
- echo world
```
Example configuration for execute commands on a remote server using SSHProxyCommand:
```diff
pipeline:
ssh:
image: appleboy/drone-ssh
settings:
host: foo.com
username: root
password: 1234
port: 22
script:
- echo hello
- echo world
+ proxy_host: 10.130.33.145
+ proxy_user: ubuntu
+ proxy_port: 22
+ proxy_password: 1234
```
Example configuration using password from secrets:
```diff
pipeline:
ssh:
image: appleboy/drone-ssh
settings:
host: foo.com
username: root
+ password:
+ from_secret: ssh_password
port: 22
script:
- echo hello
- echo world
```
Example configuration using ssh key from secrets:
```diff
pipeline:
ssh:
image: appleboy/drone-ssh
settings:
host: foo.com
username: root
port: 22
+ key:
+ from_secret: ssh_key
script:
- echo hello
- echo world
```
Example configuration for exporting custom secrets:
```diff
pipeline:
ssh:
image: appleboy/drone-ssh
settings:
host: foo.com
username: root
password: 1234
port: 22
+ envs:
- aws_access_key_id
script:
- export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
```
# Secret Reference
ssh_username
: account for target host user
ssh_password
: password for target host user
ssh_key
: plain text of user private key
proxy_ssh_username
: account for user of proxy server
proxy_ssh_password
: password for user of proxy server
proxy_ssh_key
: plain text of user private key for proxy server
# Parameter Reference
host
: target hostname or IP
port
: ssh port of target host
username
: account for target host user
password
: password for target host user
key
: plain text of user private key
key_path
: key path of user private key
envs
: custom secrets which are made available in the script section
script
: execute commands on a remote server
timeout
: Timeout is the maximum amount of time for the TCP connection to establish.
command_timeout
: Command timeout is the maximum amount of time for the execute commands, default is 60 secs.
proxy_host
: proxy hostname or IP
proxy_port
: ssh port of proxy host
proxy_username
: account for proxy host user
proxy_password
: password for proxy host user
proxy_key
: plain text of proxy private key
proxy_key_path
: key path of proxy private key
-10
View File
@@ -1,10 +0,0 @@
FROM alpine:3.4
RUN apk update && \
apk add \
ca-certificates \
openssh-client && \
rm -rf /var/cache/apk/*
ADD drone-ssh /bin/
ENTRYPOINT ["/bin/drone-ssh"]
-10
View File
@@ -1,10 +0,0 @@
FROM armhfbuild/alpine:3.4
RUN apk update && \
apk add \
ca-certificates \
openssh-client && \
rm -rf /var/cache/apk/*
ADD drone-ssh /bin/
ENTRYPOINT ["/bin/drone-ssh"]
+62 -35
View File
@@ -1,14 +1,15 @@
.PHONY: test drone-ssh build fmt vet errcheck lint install update release-dirs release-build release-copy release-check release coverage
DIST := dist
EXECUTABLE := drone-ssh
GOFMT ?= gofmt "-s"
GO ?= go
# for dockerhub
DEPLOY_ACCOUNT := appleboy
DEPLOY_IMAGE := $(EXECUTABLE)
TARGETS ?= linux darwin windows
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
ARCHS ?= amd64 386
PACKAGES ?= $(shell $(GO) list ./...)
SOURCES ?= $(shell find . -name "*.go" -type f)
TAGS ?=
LDFLAGS ?= -X 'main.Version=$(VERSION)'
@@ -28,42 +29,50 @@ endif
all: build
fmt:
find . -name "*.go" -type f -not -path "./vendor/*" | xargs gofmt -s -w
$(GOFMT) -w $(SOURCES)
vet:
go vet $(PACKAGES)
errcheck:
@which errcheck > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/kisielk/errcheck; \
fi
errcheck $(PACKAGES)
$(GO) vet $(PACKAGES)
lint:
@which golint > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/golang/lint/golint; \
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/mgechev/revive; \
fi
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
revive -config .revive.toml ./... || exit 1
test:
for PKG in $(PACKAGES); do go test -v -cover -coverprofile $$GOPATH/src/$$PKG/coverage.txt $$PKG || exit 1; done;
.PHONY: misspell-check
misspell-check:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -error $(SOURCES)
html:
go tool cover -html=coverage.txt
.PHONY: misspell
misspell:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell -w $(SOURCES)
dep_install:
glide install
.PHONY: fmt-check
fmt-check:
@diff=$$($(GOFMT) -d $(SOURCES)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
dep_update:
glide up
test: fmt-check
@$(GO) test -v -cover -coverprofile coverage.txt $(PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
install: $(SOURCES)
go install -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)'
$(GO) install -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)'
build: $(EXECUTABLE)
$(EXECUTABLE): $(SOURCES)
go build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o $@
$(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o $@
release: release-dirs release-build release-copy release-check
@@ -72,9 +81,9 @@ release-dirs:
release-build:
@which gox > /dev/null; if [ $$? -ne 0 ]; then \
go get -u github.com/mitchellh/gox; \
$(GO) get -u github.com/mitchellh/gox; \
fi
gox -os="$(TARGETS)" -arch="amd64 386" -tags="$(TAGS)" -ldflags="-s -w $(LDFLAGS)" -output="$(DIST)/binaries/$(EXECUTABLE)-$(VERSION)-{{.OS}}-{{.Arch}}"
gox -os="$(TARGETS)" -arch="$(ARCHS)" -tags="$(TAGS)" -ldflags="-s -w $(LDFLAGS)" -output="$(DIST)/binaries/$(EXECUTABLE)-$(VERSION)-{{.OS}}-{{.Arch}}"
release-copy:
$(foreach file,$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*),cp $(file) $(DIST)/release/$(notdir $(file));)
@@ -82,14 +91,22 @@ release-copy:
release-check:
cd $(DIST)/release; $(foreach file,$(wildcard $(DIST)/release/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
# for docker.
static_build:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o $(DEPLOY_IMAGE)
build_linux_amd64:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/amd64/$(DEPLOY_IMAGE)
build_linux_i386:
CGO_ENABLED=0 GOOS=linux GOARCH=386 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/i386/$(DEPLOY_IMAGE)
build_linux_arm64:
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/arm64/$(DEPLOY_IMAGE)
build_linux_arm:
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/arm/$(DEPLOY_IMAGE)
docker_image:
docker build -t $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE) .
docker: static_build docker_image
docker: docker_image
docker_deploy:
ifeq ($(tag),)
@@ -100,15 +117,25 @@ endif
docker tag $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):latest $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):$(tag)
docker push $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):$(tag)
ssh-server:
adduser -h /home/drone-scp -s /bin/bash -D -S drone-scp
echo drone-scp:1234 | chpasswd
mkdir -p /home/drone-scp/.ssh
chmod 700 /home/drone-scp/.ssh
cp tests/.ssh/id_rsa.pub /home/drone-scp/.ssh/authorized_keys
chown -R drone-scp /home/drone-scp/.ssh
# install ssh and start server
apk add --update openssh openrc
rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key
sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
./tests/entrypoint.sh /usr/sbin/sshd -D &
coverage:
sed -i '/main.go/d' coverage.txt
curl -s https://codecov.io/bash > .codecov && \
chmod +x .codecov && \
./.codecov -f coverage.txt
clean:
go clean -x -i ./...
rm -rf coverage.txt $(EXECUTABLE) $(DIST) vendor
$(GO) clean -x -i ./...
rm -rf coverage.txt $(EXECUTABLE) $(DIST)
version:
@echo $(VERSION)
+82 -19
View File
@@ -1,20 +1,69 @@
<img src="ssh.png">
<img src="images/ssh.png">
# drone-ssh
[![GitHub tag](https://img.shields.io/github/tag/appleboy/drone-ssh.svg)](https://github.com/appleboy/drone-ssh/releases) [![GoDoc](https://godoc.org/github.com/appleboy/drone-ssh?status.svg)](https://godoc.org/github.com/appleboy/drone-ssh) [![Build Status](http://drone.wu-boy.com/api/badges/appleboy/drone-ssh/status.svg)](http://drone.wu-boy.com/appleboy/drone-ssh) [![codecov](https://codecov.io/gh/appleboy/drone-ssh/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/drone-ssh) [![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/drone-ssh)](https://goreportcard.com/report/github.com/appleboy/drone-ssh) [![Docker Pulls](https://img.shields.io/docker/pulls/appleboy/drone-ssh.svg)](https://hub.docker.com/r/appleboy/drone-ssh/) [![](https://images.microbadger.com/badges/image/appleboy/drone-ssh.svg)](https://microbadger.com/images/appleboy/drone-ssh "Get your own image badge on microbadger.com")
[![GitHub tag](https://img.shields.io/github/tag/appleboy/drone-ssh.svg)](https://github.com/appleboy/drone-ssh/releases)
[![GoDoc](https://godoc.org/github.com/appleboy/drone-ssh?status.svg)](https://godoc.org/github.com/appleboy/drone-ssh)
[![Build Status](https://cloud.drone.io/api/badges/appleboy/drone-ssh/status.svg)](https://cloud.drone.io/appleboy/drone-ssh)
[![codecov](https://codecov.io/gh/appleboy/drone-ssh/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/drone-ssh)
[![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/drone-ssh)](https://goreportcard.com/report/github.com/appleboy/drone-ssh)
[![Docker Pulls](https://img.shields.io/docker/pulls/appleboy/drone-ssh.svg)](https://hub.docker.com/r/appleboy/drone-ssh/)
[![](https://images.microbadger.com/badges/image/appleboy/drone-ssh.svg)](https://microbadger.com/images/appleboy/drone-ssh "Get your own image badge on microbadger.com")
Drone plugin to execute commands on a remote host through SSH. For the usage
information and a listing of the available options please take a look at
[the docs](DOCS.md).
information and a listing of the available options please take a look at [the docs](http://plugins.drone.io/appleboy/drone-ssh/).
## Build
**Note: Please update your image config path to `appleboy/drone-ssh` for drone. `plugins/ssh` is no longer maintained.**
Build the binary with the following commands:
![demo](./images/demo2017.05.10.gif)
## Breaking changes
`v1.5.0`: change command timeout flag to `Duration`. See the following setting:
```diff
pipeline:
scp:
image: appleboy/drone-scp
settings:
host:
- example1.com
- example2.com
username: ubuntu
password:
from_secret: ssh_password
port: 22
- command_timeout: 120
+ command_timeout: 2m
script:
- echo "Hello World"
```
## Build or Download a binary
The pre-compiled binaries can be downloaded from [release page](https://github.com/appleboy/drone-ssh/releases). Support the following OS type.
* Windows amd64/386
* Linux arm/amd64/386
* Darwin amd64/386
With `Go` installed
```
go build
go test
$ go get -u -v github.com/appleboy/drone-ssh
```
or build the binary with the following command:
```
$ export GOOS=linux
$ export GOARCH=amd64
$ export CGO_ENABLED=0
$ export GO111MODULE=on
$ go test -cover ./...
$ go build -v -a -tags netgo -o release/linux/amd64/drone-ssh .
```
## Docker
@@ -22,16 +71,7 @@ go test
Build the docker image with the following commands:
```
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo
docker build -t appleboy/drone-ssh .
```
Please note incorrectly building the image for the correct x64 linux and with
GCO disabled will result in an error when running the Docker image:
```
docker: Error response from daemon: Container command
'/bin/drone-ssh' not found or does not exist..
$ make docker
```
## Usage
@@ -41,10 +81,33 @@ Execute from the working directory:
```sh
docker run --rm \
-e PLUGIN_HOST=foo.com \
-e PLUGIN_USER=root \
-e PLUGIN_USERNAME=root \
-e PLUGIN_KEY="$(cat ${HOME}/.ssh/id_rsa)" \
-e PLUGIN_SCRIPT=whoami \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-ssh
```
## Mount key from file path
Please make sure that enable the `trusted` mode in project setting for [drone 0.8 version](https://0-8-0.docs.drone.io/).
![trusted mode](./images/trust.png)
Mount private key in `volumes` setting of `.drone.yml` config
```diff
pipeline:
ssh:
image: appleboy/drone-ssh
host: xxxxx.com
username: deploy
+ volumes:
+ - /root/drone_rsa:/root/ssh/drone_rsa
key_path: /root/ssh/drone_rsa
script:
- echo "test ssh"
```
See the detail of [issue comment](https://github.com/appleboy/drone-ssh/issues/51#issuecomment-336732928).
+12
View File
@@ -0,0 +1,12 @@
FROM plugins/base:linux-amd64
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
org.label-schema.name="Drone SSH" \
org.label-schema.vendor="Bo-Yi Wu" \
org.label-schema.schema-version="1.0"
RUN apk add --no-cache ca-certificates && \
rm -rf /var/cache/apk/*
ADD release/linux/amd64/drone-ssh /bin/
ENTRYPOINT ["/bin/drone-ssh"]
+12
View File
@@ -0,0 +1,12 @@
FROM plugins/base:linux-arm
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
org.label-schema.name="Drone SSH" \
org.label-schema.vendor="Bo-Yi Wu" \
org.label-schema.schema-version="1.0"
RUN apk add --no-cache ca-certificates && \
rm -rf /var/cache/apk/*
ADD release/linux/arm/drone-ssh /bin/
ENTRYPOINT ["/bin/drone-ssh"]
+12
View File
@@ -0,0 +1,12 @@
FROM plugins/base:linux-arm64
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
org.label-schema.name="Drone SSH" \
org.label-schema.vendor="Bo-Yi Wu" \
org.label-schema.schema-version="1.0"
RUN apk add --no-cache ca-certificates && \
rm -rf /var/cache/apk/*
ADD release/linux/arm64/drone-ssh /bin/
ENTRYPOINT ["/bin/drone-ssh"]
+9
View File
@@ -0,0 +1,9 @@
FROM microsoft/nanoserver:10.0.14393.1884
LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
org.label-schema.name="Drone SSH" \
org.label-schema.vendor="Bo-Yi Wu" \
org.label-schema.schema-version="1.0"
ADD drone-ssh.exe /drone-ssh.exe
ENTRYPOINT [ "\\drone-ssh.exe" ]
+25
View File
@@ -0,0 +1,25 @@
image: appleboy/drone-ssh:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}}
tags:
{{#each build.tags}}
- {{this}}
{{/each}}
{{/if}}
manifests:
-
image: appleboy/drone-ssh:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform:
architecture: amd64
os: linux
-
image: appleboy/drone-ssh:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform:
architecture: arm64
os: linux
variant: v8
-
image: appleboy/drone-ssh:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
platform:
architecture: arm
os: linux
variant: v7
Generated
-29
View File
@@ -1,29 +0,0 @@
hash: 0c9184ed3a3b510feedfeb4fa4a119bdfa1a88b5dcfe9977944817a512958d44
updated: 2017-01-23T10:04:51.354467848+08:00
imports:
- name: github.com/joho/godotenv
version: a01a834e1654b4c9ca5b3ad05159445cc9c7ad08
subpackages:
- autoload
- name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
subpackages:
- assert
- name: github.com/urfave/cli
version: 0bdeddeeb0f650497d603c4ad7b20cfe685682f6
- name: golang.org/x/crypto
version: c3b1d0d6d8690eaebe3064711b026770cc37efa3
subpackages:
- curve25519
- ed25519
- ed25519/internal/edwards25519
- ssh
testImports:
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
subpackages:
- spew
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
-15
View File
@@ -1,15 +0,0 @@
package: github.com/appleboy/drone-ssh
import:
- package: github.com/joho/godotenv
version: ^1.0.0
subpackages:
- autoload
- package: github.com/urfave/cli
version: ^1.19.1
- package: golang.org/x/crypto
subpackages:
- ssh
- package: github.com/stretchr/testify
version: ^1.1.4
subpackages:
- assert
+10
View File
@@ -0,0 +1,10 @@
module github.com/appleboy/drone-ssh
go 1.12
require (
github.com/appleboy/easyssh-proxy v1.2.0
github.com/joho/godotenv v1.3.0
github.com/stretchr/testify v1.3.0
github.com/urfave/cli v1.20.0
)
+17
View File
@@ -0,0 +1,17 @@
github.com/appleboy/easyssh-proxy v1.2.0 h1:KvaUGC18WkBFet+N1oofQy03jkC5HaKFn2XGxFxCTtg=
github.com/appleboy/easyssh-proxy v1.2.0/go.mod h1:vHskChUNhxwW4dXMe2MNE/k+UBCkBagrQDm70UWZrS0=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25 h1:jsG6UpNLt9iAsb0S2AGW28DveNzzgmbXR+ENoPjUeIU=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

+114 -34
View File
@@ -1,21 +1,29 @@
package main
import (
"log"
"os"
"time"
"github.com/appleboy/easyssh-proxy"
"github.com/joho/godotenv"
_ "github.com/joho/godotenv/autoload"
"github.com/urfave/cli"
)
// Version set at compile-time
var Version = "v1.0.0-dev"
var Version string
func main() {
// Load env-file if it exists first
if filename, found := os.LookupEnv("PLUGIN_ENV_FILE"); found {
_ = godotenv.Load(filename)
}
app := cli.NewApp()
app.Name = "Drone SSH"
app.Usage = "Executing remote ssh commands"
app.Copyright = "Copyright (c) 2017 Bo-Yi Wu"
app.Copyright = "Copyright (c) 2019 Bo-Yi Wu"
app.Authors = []cli.Author{
{
Name: "Bo-Yi Wu",
@@ -28,48 +36,107 @@ func main() {
cli.StringFlag{
Name: "ssh-key",
Usage: "private ssh key",
EnvVar: "PLUGIN_SSH_KEY,PLUGIN_KEY,SSH_KEY",
EnvVar: "PLUGIN_SSH_KEY,PLUGIN_KEY,SSH_KEY,KEY",
},
cli.StringFlag{
Name: "user",
Name: "key-path,i",
Usage: "ssh private key path",
EnvVar: "PLUGIN_KEY_PATH,SSH_KEY_PATH,PATH",
},
cli.StringFlag{
Name: "username,user,u",
Usage: "connect as user",
EnvVar: "PLUGIN_USER,SSH_USER",
EnvVar: "PLUGIN_USERNAME,PLUGIN_USER,SSH_USERNAME,USERNAME",
Value: "root",
},
cli.StringFlag{
Name: "password",
Name: "password,P",
Usage: "user password",
EnvVar: "PLUGIN_PASSWORD,SSH_PASSWORD",
EnvVar: "PLUGIN_PASSWORD,SSH_PASSWORD,PASSWORD",
},
cli.StringSliceFlag{
Name: "host",
Name: "host,H",
Usage: "connect to host",
EnvVar: "PLUGIN_HOST,SSH_HOST",
EnvVar: "PLUGIN_HOST,SSH_HOST,HOST",
},
cli.IntFlag{
Name: "port",
Name: "port,p",
Usage: "connect to port",
EnvVar: "PLUGIN_PORT,SSH_PORT",
EnvVar: "PLUGIN_PORT,SSH_PORT,PORT",
Value: 22,
},
cli.IntFlag{
Name: "sleep",
Usage: "sleep between hosts",
EnvVar: "PLUGIN_SLEEP,SSH_SLEEP",
cli.BoolFlag{
Name: "sync",
Usage: "sync mode",
EnvVar: "PLUGIN_SYNC,SYNC",
},
cli.DurationFlag{
Name: "timeout",
Name: "timeout,t",
Usage: "connection timeout",
EnvVar: "PLUGIN_TIMEOUT,SSH_TIMEOUT",
EnvVar: "PLUGIN_TIMEOUT,SSH_TIMEOUT,TIMEOUT",
},
cli.DurationFlag{
Name: "command.timeout,T",
Usage: "command timeout",
EnvVar: "PLUGIN_COMMAND_TIMEOUT,SSH_COMMAND_TIMEOUT,COMMAND_TIMEOUT",
Value: 60 * time.Second,
},
cli.StringSliceFlag{
Name: "script",
Name: "script,s",
Usage: "execute commands",
EnvVar: "PLUGIN_SCRIPT,SSH_SCRIPT",
EnvVar: "PLUGIN_SCRIPT,SSH_SCRIPT,SCRIPT",
},
cli.BoolFlag{
Name: "script.stop",
Usage: "stop script after first failure",
EnvVar: "PLUGIN_SCRIPT_STOP,STOP",
},
cli.StringFlag{
Name: "env-file",
Usage: "source env file",
Name: "proxy.ssh-key",
Usage: "private ssh key of proxy",
EnvVar: "PLUGIN_PROXY_SSH_KEY,PLUGIN_PROXY_KEY,PROXY_SSH_KEY",
},
cli.StringFlag{
Name: "proxy.key-path",
Usage: "ssh private key path of proxy",
EnvVar: "PLUGIN_PROXY_KEY_PATH,PROXY_SSH_KEY_PATH",
},
cli.StringFlag{
Name: "proxy.username",
Usage: "connect as user of proxy",
EnvVar: "PLUGIN_PROXY_USERNAME,PLUGIN_PROXY_USER,PROXY_SSH_USERNAME",
Value: "root",
},
cli.StringFlag{
Name: "proxy.password",
Usage: "user password of proxy",
EnvVar: "PLUGIN_PROXY_PASSWORD,PROXY_SSH_PASSWORD",
},
cli.StringFlag{
Name: "proxy.host",
Usage: "connect to host of proxy",
EnvVar: "PLUGIN_PROXY_HOST,PROXY_SSH_HOST",
},
cli.StringFlag{
Name: "proxy.port",
Usage: "connect to port of proxy",
EnvVar: "PLUGIN_PROXY_PORT,PROXY_SSH_PORT",
Value: "22",
},
cli.DurationFlag{
Name: "proxy.timeout",
Usage: "proxy connection timeout",
EnvVar: "PLUGIN_PROXY_TIMEOUT,PROXY_SSH_TIMEOUT",
},
cli.StringSliceFlag{
Name: "envs",
Usage: "Pass envs",
EnvVar: "PLUGIN_ENVS",
},
cli.BoolFlag{
Name: "debug",
Usage: "debug mode",
EnvVar: "PLUGIN_DEBUG,DEBUG",
},
}
@@ -106,25 +173,38 @@ REPOSITORY:
Github: https://github.com/appleboy/drone-ssh
`
app.Run(os.Args)
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
func run(c *cli.Context) error {
if c.String("env-file") != "" {
_ = godotenv.Load(c.String("env-file"))
}
plugin := Plugin{
Config: Config{
Key: c.String("ssh-key"),
User: c.String("user"),
Password: c.String("password"),
Host: c.StringSlice("host"),
Port: c.Int("port"),
Sleep: c.Int("sleep"),
Timeout: c.Duration("timeout"),
Script: c.StringSlice("script"),
Key: c.String("ssh-key"),
KeyPath: c.String("key-path"),
Username: c.String("user"),
Password: c.String("password"),
Host: c.StringSlice("host"),
Port: c.Int("port"),
Timeout: c.Duration("timeout"),
CommandTimeout: c.Duration("command.timeout"),
Script: c.StringSlice("script"),
ScriptStop: c.Bool("script.stop"),
Envs: c.StringSlice("envs"),
Debug: c.Bool("debug"),
Sync: c.Bool("sync"),
Proxy: easyssh.DefaultConfig{
Key: c.String("proxy.ssh-key"),
KeyPath: c.String("proxy.key-path"),
User: c.String("proxy.username"),
Password: c.String("proxy.password"),
Server: c.String("proxy.host"),
Port: c.String("proxy.port"),
Timeout: c.Duration("proxy.timeout"),
},
},
Writer: os.Stdout,
}
return plugin.Exec()
+281
View File
@@ -0,0 +1,281 @@
{
test:: {
kind: 'pipeline',
name: 'testing',
platform: {
os: 'linux',
arch: 'amd64',
},
steps: [
{
name: 'vet',
image: 'golang:1.12',
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'make vet',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'lint',
image: 'golang:1.12',
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'make lint',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'misspell',
image: 'golang:1.12',
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'make misspell-check',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'test',
image: 'golang:1.12-alpine',
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'apk add git make curl perl bash build-base zlib-dev ucl-dev',
'make ssh-server',
'make test',
'make coverage',
],
volumes: [
{
name: 'gopath',
path: '/go',
},
],
},
{
name: 'codecov',
image: 'robertstettner/drone-codecov',
pull: 'always',
settings: {
token: { 'from_secret': 'codecov_token' },
},
},
],
volumes: [
{
name: 'gopath',
temp: {},
},
],
},
build(name, os='linux', arch='amd64'):: {
kind: 'pipeline',
name: os + '-' + arch,
platform: {
os: os,
arch: arch,
},
steps: [
{
name: 'build-push',
image: 'golang:1.12',
pull: 'always',
environment: {
CGO_ENABLED: '0',
GO111MODULE: 'on',
},
commands: [
'go build -v -ldflags \'-X main.build=${DRONE_BUILD_NUMBER}\' -a -o release/' + os + '/' + arch + '/' + name,
],
when: {
event: {
exclude: [ 'tag' ],
},
},
},
{
name: 'build-tag',
image: 'golang:1.12',
pull: 'always',
environment: {
CGO_ENABLED: '0',
GO111MODULE: 'on',
},
commands: [
'go build -v -ldflags \'-X main.version=${DRONE_TAG##v} -X main.build=${DRONE_BUILD_NUMBER}\' -a -o release/' + os + '/' + arch + '/' + name,
],
when: {
event: [ 'tag' ],
},
},
{
name: 'executable',
image: 'golang:1.12',
pull: 'always',
commands: [
'./release/' + os + '/' + arch + '/' + name + ' --help',
],
},
{
name: 'dryrun',
image: 'plugins/docker:' + os + '-' + arch,
pull: 'always',
settings: {
daemon_off: false,
dry_run: true,
tags: os + '-' + arch,
dockerfile: 'docker/Dockerfile.' + os + '.' + arch,
repo: 'appleboy/' + name,
cache_from: 'appleboy/' + name,
},
when: {
event: [ 'pull_request' ],
},
},
{
name: 'publish',
image: 'plugins/docker:' + os + '-' + arch,
pull: 'always',
settings: {
daemon_off: 'false',
auto_tag: true,
auto_tag_suffix: os + '-' + arch,
dockerfile: 'docker/Dockerfile.' + os + '.' + arch,
repo: 'appleboy/' + name,
cache_from: 'appleboy/' + name,
username: { 'from_secret': 'docker_username' },
password: { 'from_secret': 'docker_password' },
},
when: {
event: {
exclude: [ 'pull_request' ],
},
},
},
],
depends_on: [
'testing',
],
trigger: {
ref: [
'refs/heads/master',
'refs/pull/**',
'refs/tags/**',
],
},
},
release:: {
kind: 'pipeline',
name: 'release-binary',
platform: {
os: 'linux',
arch: 'amd64',
},
steps: [
{
name: 'build-all-binary',
image: 'golang:1.12',
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'make release'
],
when: {
event: [ 'tag' ],
},
},
{
name: 'deploy-all-binary',
image: 'plugins/github-release',
pull: 'always',
settings: {
files: [ 'dist/release/*' ],
api_key: { 'from_secret': 'github_release_api_key' },
},
when: {
event: [ 'tag' ],
},
},
],
depends_on: [
'testing',
],
trigger: {
ref: [
'refs/tags/**',
],
},
},
notifications(os='linux', arch='amd64', depends_on=[]):: {
kind: 'pipeline',
name: 'notifications',
platform: {
os: os,
arch: arch,
},
steps: [
{
name: 'manifest',
image: 'plugins/manifest',
pull: 'always',
settings: {
username: { from_secret: 'docker_username' },
password: { from_secret: 'docker_password' },
spec: 'docker/manifest.tmpl',
ignore_missing: true,
},
},
{
name: 'microbadger',
image: 'plugins/webhook:1',
pull: 'always',
settings: {
url: { 'from_secret': 'microbadger_url' },
},
},
],
depends_on: depends_on,
trigger: {
ref: [
'refs/heads/master',
'refs/tags/**',
],
},
},
signature(key):: {
kind: 'signature',
hmac: key,
}
}
+160 -67
View File
@@ -1,108 +1,201 @@
package main
import (
"errors"
"fmt"
"log"
"net"
"io"
"os"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/crypto/ssh"
"github.com/appleboy/easyssh-proxy"
)
const (
missingHostOrUser = "Error: missing server host or user"
missingPasswordOrKey = "Error: can't connect without a private SSH key or password"
var (
errMissingHost = errors.New("Error: missing server host")
errMissingPasswordOrKey = errors.New("Error: can't connect without a private SSH key or password")
errCommandTimeOut = errors.New("Error: command timeout")
errSetPasswordandKey = errors.New("can't set password and key at the same time")
)
type (
// Config for the plugin.
Config struct {
Key string
User string
Password string
Host []string
Port int
Sleep int
Timeout time.Duration
Script []string
Key string
KeyPath string
Username string
Password string
Host []string
Port int
Timeout time.Duration
CommandTimeout time.Duration
Script []string
ScriptStop bool
Envs []string
Proxy easyssh.DefaultConfig
Debug bool
Sync bool
}
// Plugin structure
Plugin struct {
Config Config
Writer io.Writer
}
)
func escapeArg(arg string) string {
return "'" + strings.Replace(arg, "'", `'\''`, -1) + "'"
}
func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
// Create MakeConfig instance with remote username, server address and path to private key.
ssh := &easyssh.MakeConfig{
Server: host,
User: p.Config.Username,
Password: p.Config.Password,
Port: strconv.Itoa(p.Config.Port),
Key: p.Config.Key,
KeyPath: p.Config.KeyPath,
Timeout: p.Config.Timeout,
Proxy: easyssh.DefaultConfig{
Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port,
Key: p.Config.Proxy.Key,
KeyPath: p.Config.Proxy.KeyPath,
Timeout: p.Config.Proxy.Timeout,
},
}
p.log(host, "======CMD======")
p.log(host, strings.Join(p.Config.Script, "\n"))
p.log(host, "======END======")
env := []string{}
for _, key := range p.Config.Envs {
key = strings.ToUpper(key)
if val, found := os.LookupEnv(key); found {
env = append(env, key+"="+escapeArg(val))
}
}
p.Config.Script = append(env, p.scriptCommands()...)
if p.Config.Debug {
p.log(host, "======ENV======")
p.log(host, strings.Join(env, "\n"))
p.log(host, "======END======")
}
stdoutChan, stderrChan, doneChan, errChan, err := ssh.Stream(strings.Join(p.Config.Script, "\n"), p.Config.CommandTimeout)
if err != nil {
errChannel <- err
} else {
// read from the output channel until the done signal is passed
isTimeout := true
loop:
for {
select {
case isTimeout = <-doneChan:
break loop
case outline := <-stdoutChan:
p.log(host, "out:", outline)
case errline := <-stderrChan:
p.log(host, "err:", errline)
case err = <-errChan:
}
}
// get exit code or command error.
if err != nil {
errChannel <- err
}
// command time out
if !isTimeout {
errChannel <- errCommandTimeOut
}
}
wg.Done()
}
func (p Plugin) log(host string, message ...interface{}) {
if p.Writer == nil {
p.Writer = os.Stdout
}
if count := len(p.Config.Host); count == 1 {
fmt.Fprintf(p.Writer, "%s", fmt.Sprintln(message...))
} else {
fmt.Fprintf(p.Writer, "%s: %s", host, fmt.Sprintln(message...))
}
}
// Exec executes the plugin.
func (p Plugin) Exec() error {
if len(p.Config.Host) == 0 && p.Config.User == "" {
return fmt.Errorf(missingHostOrUser)
if len(p.Config.Host) == 0 {
return errMissingHost
}
if p.Config.Key == "" && p.Config.Password == "" {
return fmt.Errorf(missingPasswordOrKey)
if len(p.Config.Key) == 0 && len(p.Config.Password) == 0 && len(p.Config.KeyPath) == 0 {
return errMissingPasswordOrKey
}
for i, host := range p.Config.Host {
addr := net.JoinHostPort(
host,
strconv.Itoa(p.Config.Port),
)
if len(p.Config.Key) != 0 && len(p.Config.Password) != 0 {
return errSetPasswordandKey
}
// auths holds the detected ssh auth methods
auths := []ssh.AuthMethod{}
if p.Config.Key != "" {
signer, err := ssh.ParsePrivateKey([]byte(p.Config.Key))
if err != nil {
return fmt.Errorf("Error: Failed to parse private key. %s", err)
}
auths = append(auths, ssh.PublicKeys(signer))
wg := sync.WaitGroup{}
wg.Add(len(p.Config.Host))
errChannel := make(chan error)
finished := make(chan struct{})
for _, host := range p.Config.Host {
if p.Config.Sync {
p.exec(host, &wg, errChannel)
} else {
go p.exec(host, &wg, errChannel)
}
}
// figure out what auths are requested, what is supported
if p.Config.Password != "" {
auths = append(auths, ssh.Password(p.Config.Password))
}
config := &ssh.ClientConfig{
Timeout: p.Config.Timeout,
User: p.Config.User,
Auth: auths,
}
log.Printf("+ ssh %s@%s -p %d\n", p.Config.User, addr, p.Config.Port)
client, err := ssh.Dial("tcp", addr, config)
go func() {
wg.Wait()
close(finished)
}()
select {
case <-finished:
case err := <-errChannel:
if err != nil {
return fmt.Errorf("Error: Failed to dial to server. %s", err)
}
session, err := client.NewSession()
if err != nil {
return fmt.Errorf("Error: Failed to start a SSH session. %s", err)
}
defer session.Close()
session.Stdout = os.Stdout
session.Stderr = os.Stderr
if err := session.Run(strings.Join(p.Config.Script, "\n")); err != nil {
return err
}
if p.Config.Sleep != 0 && i != len(p.Config.Host)-1 {
log.Printf("+ sleep %d\n", p.Config.Sleep)
time.Sleep(time.Duration(p.Config.Sleep) * time.Second)
}
}
fmt.Println("==========================================")
fmt.Println("Successfully executed commands to all host.")
fmt.Println("==========================================")
return nil
}
func (p Plugin) scriptCommands() []string {
numCommands := len(p.Config.Script)
if p.Config.ScriptStop {
numCommands *= 2
}
commands := make([]string, numCommands)
for _, cmd := range p.Config.Script {
if p.Config.ScriptStop {
commands = append(commands, "DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;")
}
commands = append(commands, cmd)
}
return commands
}
+503 -4
View File
@@ -1,8 +1,13 @@
package main
import (
"bytes"
"os"
"strings"
"testing"
"time"
"github.com/appleboy/easyssh-proxy"
"github.com/stretchr/testify/assert"
)
@@ -12,19 +17,513 @@ func TestMissingHostOrUser(t *testing.T) {
err := plugin.Exec()
assert.NotNil(t, err)
assert.Equal(t, missingHostOrUser, err.Error())
assert.Equal(t, errMissingHost, err)
}
func TestMissingKeyOrPassword(t *testing.T) {
plugin := Plugin{
Config{
Host: []string{"localhost"},
User: "ubuntu",
Host: []string{"localhost"},
Username: "ubuntu",
},
os.Stdout,
}
err := plugin.Exec()
assert.NotNil(t, err)
assert.Equal(t, missingPasswordOrKey, err.Error())
assert.Equal(t, errMissingPasswordOrKey, err)
}
func TestSetPasswordAndKey(t *testing.T) {
plugin := Plugin{
Config{
Host: []string{"localhost"},
Username: "ubuntu",
Password: "1234",
Key: "1234",
},
os.Stdout,
}
err := plugin.Exec()
assert.NotNil(t, err)
assert.Equal(t, errSetPasswordandKey, err)
}
func TestIncorrectPassword(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
Password: "123456",
Script: []string{"whoami"},
CommandTimeout: 60 * time.Second,
},
}
err := plugin.Exec()
assert.NotNil(t, err)
}
func TestSSHScriptFromRawKey(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
CommandTimeout: 60 * time.Second,
Key: `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA4e2D/qPN08pzTac+a8ZmlP1ziJOXk45CynMPtva0rtK/RB26
VbfAF0hIJji7ltvnYnqCU9oFfvEM33cTn7T96+od8ib/Vz25YU8ZbstqtIskPuwC
bv3K0mAHgsviJyRD7yM+QKTbBQEgbGuW6gtbMKhiYfiIB4Dyj7AdS/fk3v26wDgz
7SHI5OBqu9bv1KhxQYdFEnU3PAtAqeccgzNpbH3eYLyGzuUxEIJlhpZ/uU2G9ppj
/cSrONVPiI8Ahi4RrlZjmP5l57/sq1ClGulyLpFcMw68kP5FikyqHpHJHRBNgU57
1y0Ph33SjBbs0haCIAcmreWEhGe+/OXnJe6VUQIDAQABAoIBAH97emORIm9DaVSD
7mD6DqA7c5m5Tmpgd6eszU08YC/Vkz9oVuBPUwDQNIX8tT0m0KVs42VVPIyoj874
bgZMJoucC1G8V5Bur9AMxhkShx9g9A7dNXJTmsKilRpk2TOk7wBdLp9jZoKoZBdJ
jlp6FfaazQjjKD6zsCsMATwAoRCBpBNsmT6QDN0n0bIgY0tE6YGQaDdka0dAv68G
R0VZrcJ9voT6+f+rgJLoojn2DAu6iXaM99Gv8FK91YCymbQlXXgrk6CyS0IHexN7
V7a3k767KnRbrkqd3o6JyNun/CrUjQwHs1IQH34tvkWScbseRaFehcAm6mLT93RP
muauvMECgYEA9AXGtfDMse0FhvDPZx4mx8x+vcfsLvDHcDLkf/lbyPpu97C27b/z
ia07bu5TAXesUZrWZtKA5KeRE5doQSdTOv1N28BEr8ZwzDJwfn0DPUYUOxsN2iIy
MheO5A45Ko7bjKJVkZ61Mb1UxtqCTF9mqu9R3PBdJGthWOd+HUvF460CgYEA7QRf
Z8+vpGA+eSuu29e0xgRKnRzed5zXYpcI4aERc3JzBgO4Z0er9G8l66OWVGdMfpe6
CBajC5ToIiT8zqoYxXwqJgN+glir4gJe3mm8J703QfArZiQrdk0NTi5bY7+vLLG/
knTrtpdsKih6r3kjhuPPaAsIwmMxIydFvATKjLUCgYEAh/y4EihRSk5WKC8GxeZt
oiZ58vT4z+fqnMIfyJmD5up48JuQNcokw/LADj/ODiFM7GUnWkGxBrvDA3H67WQm
49bJjs8E+BfUQFdTjYnJRlpJZ+7Zt1gbNQMf5ENw5CCchTDqEq6pN0DVf8PBnSIF
KvkXW9KvdV5J76uCAn15mDkCgYA1y8dHzbjlCz9Cy2pt1aDfTPwOew33gi7U3skS
RTerx29aDyAcuQTLfyrROBkX4TZYiWGdEl5Bc7PYhCKpWawzrsH2TNa7CRtCOh2E
R+V/84+GNNf04ALJYCXD9/ugQVKmR1XfDRCvKeFQFE38Y/dvV2etCswbKt5tRy2p
xkCe/QKBgQCkLqafD4S20YHf6WTp3jp/4H/qEy2X2a8gdVVBi1uKkGDXr0n+AoVU
ib4KbP5ovZlrjL++akMQ7V2fHzuQIFWnCkDA5c2ZAqzlM+ZN+HRG7gWur7Bt4XH1
7XC9wlRna4b3Ln8ew3q1ZcBjXwD4ppbTlmwAfQIaZTGJUgQbdsO9YA==
-----END RSA PRIVATE KEY-----
`,
Script: []string{"whoami"},
},
}
err := plugin.Exec()
assert.Nil(t, err)
}
func TestSSHScriptFromKeyFile(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost", "127.0.0.1"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{"whoami", "ls -al"},
CommandTimeout: 60 * time.Second,
},
}
err := plugin.Exec()
assert.Nil(t, err)
}
func TestStreamFromSSHCommand(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost", "127.0.0.1"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{"whoami", "for i in {1..5}; do echo ${i}; sleep 1; done", "echo 'done'"},
CommandTimeout: 60 * time.Second,
},
}
err := plugin.Exec()
assert.Nil(t, err)
}
func TestSSHScriptWithError(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost", "127.0.0.1"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{"exit 1"},
CommandTimeout: 60 * time.Second,
},
}
err := plugin.Exec()
// Process exited with status 1
assert.NotNil(t, err)
}
func TestSSHCommandTimeOut(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{"sleep 5"},
CommandTimeout: 1 * time.Second,
},
}
err := plugin.Exec()
assert.NotNil(t, err)
}
func TestProxyCommand(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{"whoami"},
CommandTimeout: 1 * time.Second,
Proxy: easyssh.DefaultConfig{
Server: "localhost",
User: "drone-scp",
Port: "22",
KeyPath: "./tests/.ssh/id_rsa",
},
},
}
err := plugin.Exec()
assert.Nil(t, err)
}
func TestSSHCommandError(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{"mkdir a", "mkdir a"},
CommandTimeout: 60 * time.Second,
},
}
err := plugin.Exec()
assert.NotNil(t, err)
}
func TestSSHCommandExitCodeError(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{
"set -e",
"echo 1",
"mkdir a",
"mkdir a",
"echo 2",
},
CommandTimeout: 60 * time.Second,
},
}
err := plugin.Exec()
assert.NotNil(t, err)
}
func TestSetENV(t *testing.T) {
os.Setenv("FOO", `' 1) '`)
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Envs: []string{"foo"},
Debug: true,
Script: []string{"whoami; echo $FOO"},
CommandTimeout: 1 * time.Second,
Proxy: easyssh.DefaultConfig{
Server: "localhost",
User: "drone-scp",
Port: "22",
KeyPath: "./tests/.ssh/id_rsa",
},
},
}
err := plugin.Exec()
assert.Nil(t, err)
}
func TestSetExistingENV(t *testing.T) {
os.Setenv("FOO", "Value for foo")
os.Setenv("BAR", "")
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Envs: []string{"foo", "bar", "baz"},
Debug: true,
Script: []string{"export FOO", "export BAR", "export BAZ", "env | grep -q '^FOO=Value for foo$'", "env | grep -q '^BAR=$'", "if env | grep -q BAZ; then false; else true; fi"},
CommandTimeout: 1 * time.Second,
Proxy: easyssh.DefaultConfig{
Server: "localhost",
User: "drone-scp",
Port: "22",
KeyPath: "./tests/.ssh/id_rsa",
},
},
}
err := plugin.Exec()
assert.Nil(t, err)
}
func TestSyncMode(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost", "127.0.0.1"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{"whoami", "for i in {1..3}; do echo ${i}; sleep 1; done", "echo 'done'"},
CommandTimeout: 60 * time.Second,
Sync: true,
},
}
err := plugin.Exec()
assert.Nil(t, err)
}
func Test_escapeArg(t *testing.T) {
type args struct {
arg string
}
tests := []struct {
name string
args args
want string
}{
{
name: "escape nothing",
args: args{
arg: "Hi I am appleboy",
},
want: `'Hi I am appleboy'`,
},
{
name: "escape single quote",
args: args{
arg: "Hi I am 'appleboy'",
},
want: `'Hi I am '\''appleboy'\'''`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := escapeArg(tt.args.arg)
assert.Equal(t, tt.want, got)
})
}
}
func TestCommandOutput(t *testing.T) {
var (
buffer bytes.Buffer
expected = `
localhost: ======CMD======
localhost: pwd
whoami
uname
localhost: ======END======
localhost: out: /home/drone-scp
localhost: out: drone-scp
localhost: out: Linux
127.0.0.1: ======CMD======
127.0.0.1: pwd
whoami
uname
127.0.0.1: ======END======
127.0.0.1: out: /home/drone-scp
127.0.0.1: out: drone-scp
127.0.0.1: out: Linux
`
)
plugin := Plugin{
Config: Config{
Host: []string{"localhost", "127.0.0.1"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{
"pwd",
"whoami",
"uname",
},
CommandTimeout: 60 * time.Second,
Sync: true,
},
Writer: &buffer,
}
err := plugin.Exec()
assert.Nil(t, err)
assert.Equal(t, unindent(expected), unindent(buffer.String()))
}
func TestScriptStop(t *testing.T) {
var (
buffer bytes.Buffer
expected = `
======CMD======
mkdir a/b/c
mkdir d/e/f
======END======
err: mkdir: can't create directory 'a/b/c': No such file or directory
`
)
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{
"mkdir a/b/c",
"mkdir d/e/f",
},
CommandTimeout: 10 * time.Second,
ScriptStop: true,
},
Writer: &buffer,
}
err := plugin.Exec()
assert.NotNil(t, err)
assert.Equal(t, unindent(expected), unindent(buffer.String()))
}
func TestNoneScriptStop(t *testing.T) {
var (
buffer bytes.Buffer
expected = `
======CMD======
mkdir a/b/c
mkdir d/e/f
======END======
err: mkdir: can't create directory 'a/b/c': No such file or directory
err: mkdir: can't create directory 'd/e/f': No such file or directory
`
)
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{
"mkdir a/b/c",
"mkdir d/e/f",
},
CommandTimeout: 10 * time.Second,
},
Writer: &buffer,
}
err := plugin.Exec()
assert.NotNil(t, err)
assert.Equal(t, unindent(expected), unindent(buffer.String()))
}
func TestEnvOutput(t *testing.T) {
var (
buffer bytes.Buffer
expected = `
======CMD======
echo "[${ENV_1}]"
echo "[${ENV_2}]"
echo "[${ENV_3}]"
echo "[${ENV_4}]"
echo "[${ENV_5}]"
echo "[${ENV_6}]"
echo "[${ENV_7}]"
======END======
======ENV======
ENV_1='test'
ENV_2='test test'
ENV_3='test '
ENV_4=' test test '
ENV_5='test'\'''
ENV_6='test"'
ENV_7='test,!#;?.@$~'\''"'
======END======
out: [test]
out: [test test]
out: [test ]
out: [ test test ]
out: [test']
out: [test"]
out: [test,!#;?.@$~'"]
`
)
os.Setenv("ENV_1", `test`)
os.Setenv("ENV_2", `test test`)
os.Setenv("ENV_3", `test `)
os.Setenv("ENV_4", ` test test `)
os.Setenv("ENV_5", `test'`)
os.Setenv("ENV_6", `test"`)
os.Setenv("ENV_7", `test,!#;?.@$~'"`)
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Envs: []string{"env_1", "env_2", "env_3", "env_4", "env_5", "env_6", "env_7"},
Debug: true,
Script: []string{
`echo "[${ENV_1}]"`,
`echo "[${ENV_2}]"`,
`echo "[${ENV_3}]"`,
`echo "[${ENV_4}]"`,
`echo "[${ENV_5}]"`,
`echo "[${ENV_6}]"`,
`echo "[${ENV_7}]"`,
},
CommandTimeout: 10 * time.Second,
Proxy: easyssh.DefaultConfig{
Server: "localhost",
User: "drone-scp",
Port: "22",
KeyPath: "./tests/.ssh/id_rsa",
},
},
Writer: &buffer,
}
err := plugin.Exec()
assert.Nil(t, err)
assert.Equal(t, unindent(expected), unindent(buffer.String()))
}
func unindent(text string) string {
return strings.TrimSpace(strings.Replace(text, "\t", "", -1))
}
+27
View File
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA4e2D/qPN08pzTac+a8ZmlP1ziJOXk45CynMPtva0rtK/RB26
VbfAF0hIJji7ltvnYnqCU9oFfvEM33cTn7T96+od8ib/Vz25YU8ZbstqtIskPuwC
bv3K0mAHgsviJyRD7yM+QKTbBQEgbGuW6gtbMKhiYfiIB4Dyj7AdS/fk3v26wDgz
7SHI5OBqu9bv1KhxQYdFEnU3PAtAqeccgzNpbH3eYLyGzuUxEIJlhpZ/uU2G9ppj
/cSrONVPiI8Ahi4RrlZjmP5l57/sq1ClGulyLpFcMw68kP5FikyqHpHJHRBNgU57
1y0Ph33SjBbs0haCIAcmreWEhGe+/OXnJe6VUQIDAQABAoIBAH97emORIm9DaVSD
7mD6DqA7c5m5Tmpgd6eszU08YC/Vkz9oVuBPUwDQNIX8tT0m0KVs42VVPIyoj874
bgZMJoucC1G8V5Bur9AMxhkShx9g9A7dNXJTmsKilRpk2TOk7wBdLp9jZoKoZBdJ
jlp6FfaazQjjKD6zsCsMATwAoRCBpBNsmT6QDN0n0bIgY0tE6YGQaDdka0dAv68G
R0VZrcJ9voT6+f+rgJLoojn2DAu6iXaM99Gv8FK91YCymbQlXXgrk6CyS0IHexN7
V7a3k767KnRbrkqd3o6JyNun/CrUjQwHs1IQH34tvkWScbseRaFehcAm6mLT93RP
muauvMECgYEA9AXGtfDMse0FhvDPZx4mx8x+vcfsLvDHcDLkf/lbyPpu97C27b/z
ia07bu5TAXesUZrWZtKA5KeRE5doQSdTOv1N28BEr8ZwzDJwfn0DPUYUOxsN2iIy
MheO5A45Ko7bjKJVkZ61Mb1UxtqCTF9mqu9R3PBdJGthWOd+HUvF460CgYEA7QRf
Z8+vpGA+eSuu29e0xgRKnRzed5zXYpcI4aERc3JzBgO4Z0er9G8l66OWVGdMfpe6
CBajC5ToIiT8zqoYxXwqJgN+glir4gJe3mm8J703QfArZiQrdk0NTi5bY7+vLLG/
knTrtpdsKih6r3kjhuPPaAsIwmMxIydFvATKjLUCgYEAh/y4EihRSk5WKC8GxeZt
oiZ58vT4z+fqnMIfyJmD5up48JuQNcokw/LADj/ODiFM7GUnWkGxBrvDA3H67WQm
49bJjs8E+BfUQFdTjYnJRlpJZ+7Zt1gbNQMf5ENw5CCchTDqEq6pN0DVf8PBnSIF
KvkXW9KvdV5J76uCAn15mDkCgYA1y8dHzbjlCz9Cy2pt1aDfTPwOew33gi7U3skS
RTerx29aDyAcuQTLfyrROBkX4TZYiWGdEl5Bc7PYhCKpWawzrsH2TNa7CRtCOh2E
R+V/84+GNNf04ALJYCXD9/ugQVKmR1XfDRCvKeFQFE38Y/dvV2etCswbKt5tRy2p
xkCe/QKBgQCkLqafD4S20YHf6WTp3jp/4H/qEy2X2a8gdVVBi1uKkGDXr0n+AoVU
ib4KbP5ovZlrjL++akMQ7V2fHzuQIFWnCkDA5c2ZAqzlM+ZN+HRG7gWur7Bt4XH1
7XC9wlRna4b3Ln8ew3q1ZcBjXwD4ppbTlmwAfQIaZTGJUgQbdsO9YA==
-----END RSA PRIVATE KEY-----
+1
View File
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDh7YP+o83TynNNpz5rxmaU/XOIk5eTjkLKcw+29rSu0r9EHbpVt8AXSEgmOLuW2+dieoJT2gV+8QzfdxOftP3r6h3yJv9XPblhTxluy2q0iyQ+7AJu/crSYAeCy+InJEPvIz5ApNsFASBsa5bqC1swqGJh+IgHgPKPsB1L9+Te/brAODPtIcjk4Gq71u/UqHFBh0USdTc8C0Cp5xyDM2lsfd5gvIbO5TEQgmWGln+5TYb2mmP9xKs41U+IjwCGLhGuVmOY/mXnv+yrUKUa6XIukVwzDryQ/kWKTKoekckdEE2BTnvXLQ+HfdKMFuzSFoIgByat5YSEZ7785ecl7pVR drone-scp@localhost
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
if [ ! -f "/etc/ssh/ssh_host_rsa_key" ]; then
# generate fresh rsa key
ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa
fi
if [ ! -f "/etc/ssh/ssh_host_dsa_key" ]; then
# generate fresh dsa key
ssh-keygen -f /etc/ssh/ssh_host_dsa_key -N '' -t dsa
fi
exec "$@"