commit
355d82c611
@ -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…
Reference in new issue