master
greg 12 months ago
commit 355d82c611
  1. 86
      DOCS.md
  2. 6
      Dockerfile
  3. 21
      LICENSE
  4. 30
      README.md
  5. 153
      upload.sh

@ -0,0 +1,86 @@
Use the Rsync plugin to synchronize files to remote hosts, and execute arbitrary commands on those hosts.
## Config
The following parameters are used to configure the plugin:
- **user** - user to log in as on the remote machines, defaults to `root`
- **key** - private SSH key for the remote machines
- **hosts** - hostnames or ip-addresses of the remote machines
- **port** - port to connect to on the remote machines, defaults to `22`
- **source** - source folder to synchronize from, defaults to `./`
- **target** - target folder on remote machines to synchronize to
- **include** - rsync include filter
- **exclude** - rsync exclude filter
- **recursive** - recursively synchronize, defaults to `false`
- **delete** - delete target folder contents, defaults to `false`
- **args** - instruct plugin to use these additional rsync CLI arguments, example: `"--blocking-io"`
- **prescript** - list of commands to execute on remote machines before rsync occurs
- **script** - list of commands to execute on remote machines after rsync occurs
- **log_level** - ssh log level, defaults to quiet
It is highly recommended to put your private key into a secret (`rsync_key`) so it is not exposed to users. This can be done using the drone-cli:
```sh
drone secret add \
--repository your/repo \
--name rsync_key \
--data @./id_rsa \
```
Add the secret to your `.drone.yml`:
```yaml
kind: pipeline
steps:
- name: rsync
image: drillster/drone-rsync
settings:
user: some-user
key:
from_secret: rsync_key
hosts:
- remote1
source: ./dist
target: ~/packages
secrets: [ rsync_key ]
```
See the [secret guides](https://docs.drone.io/user-guide/secrets/pre-repository/) for additional information on secrets.
## Examples
```yaml
kind: pipeline
name: default
steps:
- name: rsync
image: drillster/drone-rsync
settings:
hosts:
- remote1
- remote2
user:
from_secret: rsync_user
key:
from_secret: rsync_key
source: ./dist
target: ~/packages
include:
- "app.tar.gz"
- "app.tar.gz.md5"
exclude:
- "**.*"
prescript:
- cd ~/packages
- md5sum -c app.tar.gz.md5
- tar -xf app.tar.gz -C ~/app
script:
- cd ~/packages
- md5sum -c app.tar.gz.md5
- tar -xf app.tar.gz -C ~/app
```
The example above illustrates a situation where an app package (`app.tar.gz`) will be deployed to 2 remote hosts (`remote1` and `remote2`). An md5 checksum will be deployed as well. After deploying, the md5 checksum is used to check the deployed package. If successful the package is extracted.
## Important
The script passed to **script** will be executed on remote machines directly after rsync completes to deploy the files. It will be executed step by step until a command returns a non-zero exit-code. If this happens, the entire plugin will exit and fail the build.

@ -0,0 +1,6 @@
FROM alpine:latest
RUN apk add --no-cache --update ca-certificates bash openssh-client rsync
COPY upload.sh /usr/local/
ENTRYPOINT ["/usr/local/upload.sh"]

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Drillster
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,30 @@
# drone-rsync
[![drone-rsync on Docker Hub](https://img.shields.io/docker/automated/drillster/drone-rsync.svg)](https://hub.docker.com/r/drillster/drone-rsync/)
This is a pure Bash [Drone](https://github.com/drone/drone) >= 0.5 plugin to sync files to remote hosts.
For more information on how to use the plugin, please take a look at [the docs](https://github.com/Drillster/drone-rsync/blob/master/DOCS.md).
## Docker
Build the docker image by running:
```bash
docker build --rm=true -t drillster/drone-rsync .
```
## Usage
Execute from the working directory (assuming you have an SSH server running on 127.0.0.1:22):
```bash
docker run --rm \
-e PLUGIN_KEY=$(cat some-private-key) \
-e PLUGIN_HOSTS="127.0.0.1, 127.0.0.2, 127.0.0.3" \
-e PLUGIN_PORTS="22, 23, 24" \
-e PLUGIN_TARGET="./" \
-e PLUGIN_PRESCRIPT="echo \"Prescript Done!\"" \
-e PLUGIN_SCRIPT="echo \"Postscript Done!\"" \
-e PLUGIN_ARGS="--blocking-io" \
-v $(pwd):$(pwd) \
-w $(pwd) \
drillster/drone-rsync
```

@ -0,0 +1,153 @@
#!/bin/bash
if [ -z "$PLUGIN_HOSTS" ]; then
echo "Specify at least one host!"
exit 1
fi
if [ -z "$PLUGIN_TARGET" ]; then
echo "Specify a target!"
exit 1
fi
DEFAULT_PORT=$PLUGIN_PORT
if [ -z "$PLUGIN_PORT" ]; then
echo "Port not specified, using default port 22!"
DEFAULT_PORT="22"
fi
SOURCE=$PLUGIN_SOURCE
if [ -z "$PLUGIN_SOURCE" ]; then
echo "No source folder specified, using default './'"
SOURCE="./"
fi
USER=$RSYNC_USER
if [ -z "$RSYNC_USER" ]; then
if [ -z "$PLUGIN_USER" ]; then
echo "No user specified, using root!"
USER="root"
else
USER=$PLUGIN_USER
fi
fi
SSH_KEY=$RSYNC_KEY
if [ -z "$RSYNC_KEY" ]; then
if [ -z "$PLUGIN_KEY" ]; then
echo "No private key specified!"
exit 1
fi
SSH_KEY=$PLUGIN_KEY
fi
if [ -z "$PLUGIN_ARGS" ]; then
ARGS=
else
ARGS=$PLUGIN_ARGS
fi
if [ -z "$PLUGIN_LOG_LEVEL" ]; then
LOG_LEVEL=quiet
else
LOG_LEVEL=$PLUGIN_LOG_LEVEL
fi
# Building rsync command
expr="rsync -az $ARGS"
if [[ -n "$PLUGIN_RECURSIVE" && "$PLUGIN_RECURSIVE" == "true" ]]; then
expr="$expr -r"
fi
if [[ -n "$PLUGIN_DELETE" && "$PLUGIN_DELETE" == "true" ]]; then
expr="$expr --del"
fi
expr="$expr -e 'ssh -p %s -o UserKnownHostsFile=/dev/null -o LogLevel=$LOG_LEVEL -o StrictHostKeyChecking=no'"
# Include
IFS=','; read -ra INCLUDE <<< "$PLUGIN_INCLUDE"
for include in "${INCLUDE[@]}"; do
expr="$expr --include=$include"
done
# Exclude
IFS=','; read -ra EXCLUDE <<< "$PLUGIN_EXCLUDE"
for exclude in "${EXCLUDE[@]}"; do
expr="$expr --exclude=$exclude"
done
# Filter
IFS=','; read -ra FILTER <<< "$PLUGIN_FILTER"
for filter in "${FILTER[@]}"; do
expr="$expr --filter=$filter"
done
expr="$expr $SOURCE"
# Prepare SSH
home="/root"
mkdir -p "$home/.ssh"
printf "StrictHostKeyChecking no\n" > "$home/.ssh/config"
chmod 0700 "$home/.ssh/config"
keyfile="$home/.ssh/id_rsa"
echo "$SSH_KEY" | grep -q "ssh-ed25519"
if [ $? -eq 0 ]; then
printf "Using ed25519 based key\n"
keyfile="$home/.ssh/id_ed25519"
fi
echo "$SSH_KEY" | grep -q "ecdsa-"
if [ $? -eq 0 ]; then
printf "Using ecdsa based key\n"
keyfile="$home/.ssh/id_ecdsa"
fi
echo "$SSH_KEY" > $keyfile
chmod 0600 $keyfile
function join_with { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
# Parse SSH precommands
IFS=','; read -ra COMMANDS <<< "$PLUGIN_PRESCRIPT"
prescript=$(join_with ' && ' "${COMMANDS[@]}")
# Parse SSH postcommands
IFS=','; read -ra COMMANDS <<< "$PLUGIN_SCRIPT"
postscript=$(join_with ' && ' "${COMMANDS[@]}")
# Run rsync
IFS=','; read -ra HOSTS <<< "$PLUGIN_HOSTS"
IFS=','; read -ra PORTS <<< "$PLUGIN_PORTS"
result=0
for ((i=0; i < ${#HOSTS[@]}; i++))
do
HOST=${HOSTS[$i]}
PORT=${PORTS[$i]}
if [ -z $PORT ]
then
# Default Port 22
PORT=$DEFAULT_PORT
fi
echo $(printf "%s" "$ $(printf "$expr" "$PORT") $USER@$HOST:$PLUGIN_TARGET ...")
if [ -n "$PLUGIN_PRESCRIPT" ]; then
echo $(printf "%s" "$ ssh -p $PORT $USER@$HOST ...")
echo $(printf "%s" " > $prescript ...")
eval "ssh -p $PORT $USER@$HOST '$prescript'"
result=$(($result+$?))
echo $(printf "%s" "$ ssh -p $PORT $USER@$HOST result: $?")
if [ "$result" -gt "0" ]; then exit $result; fi
fi
eval "$(printf "$expr" "$PORT") $USER@$HOST:$PLUGIN_TARGET"
result=$(($result+$?))
if [ "$result" -gt "0" ]; then exit $result; fi
if [ -n "$PLUGIN_SCRIPT" ]; then
echo $(printf "%s" "$ ssh -p $PORT $USER@$HOST ...")
echo $(printf "%s" " > $postscript ...")
eval "ssh -p $PORT $USER@$HOST '$postscript'"
result=$(($result+$?))
echo $(printf "%s" "$ ssh -p $PORT $USER@$HOST result: $?")
if [ "$result" -gt "0" ]; then exit $result; fi
fi
done
exit $result
Loading…
Cancel
Save