forked from 0k/0k-charms
Browse Source
new: [rsync-backup] add charm
new: [rsync-backup] add charm
Signed-off-by: Valentin Lab <valentin.lab@kalysto.org>0k/dev/master
Valentin Lab
5 years ago
8 changed files with 227 additions and 2 deletions
-
4rsync-backup-target/build/src/etc/ssh/sshd_config
-
27rsync-backup/build/Dockerfile
-
71rsync-backup/build/entrypoint.sh
-
35rsync-backup/hooks/backup-relation-joined
-
22rsync-backup/hooks/init
-
48rsync-backup/hooks/schedule_command-relation-joined
-
5rsync-backup/lib/common
-
17rsync-backup/metadata.yml
@ -0,0 +1,27 @@ |
|||||
|
FROM alpine:3.9 |
||||
|
|
||||
|
MAINTAINER Valentin Lab <valentin.lab@kalysto.org> |
||||
|
|
||||
|
|
||||
|
RUN apk add bash rsync sudo openssh-client |
||||
|
|
||||
|
# RUN apt-get update && \ |
||||
|
# DEBIAN_FRONTEND=noninteractive apt-get install --force-yes -y --no-install-recommends rsync sudo openssh-client && \ |
||||
|
# apt-get clean && \ |
||||
|
# rm -rf /var/lib/apt/lists/* |
||||
|
|
||||
|
## New user/group rsync/rsync with home dir in /var/lib/rsync |
||||
|
RUN mkdir -p /var/lib/rsync && \ |
||||
|
addgroup -S rsync && \ |
||||
|
adduser -S rsync -h /var/lib/rsync -G rsync && \ |
||||
|
chown rsync:rsync /var/lib/rsync |
||||
|
|
||||
|
## New user/group rsync/rsync with home dir in /var/lib/rsync |
||||
|
# RUN mkdir -p /var/lib/rsync && \ |
||||
|
# groupadd -r rsync && \ |
||||
|
# useradd -r rsync -d /var/lib/rsync -g rsync && \ |
||||
|
# chown rsync:rsync /var/lib/rsync |
||||
|
|
||||
|
COPY ./entrypoint.sh /entrypoint.sh |
||||
|
|
||||
|
ENTRYPOINT [ "/entrypoint.sh" ] |
@ -0,0 +1,71 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
[ "$UID" != "0" ] && echo "You must be root." 2>&1 && exit 1 |
||||
|
|
||||
|
## |
||||
|
## code |
||||
|
## |
||||
|
|
||||
|
|
||||
|
user=rsync |
||||
|
src="$1" |
||||
|
|
||||
|
if [ -z "$src" ]; then |
||||
|
echo "You must provide a source directory as first argument." >&2 |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
if ! [ -d "$src" ]; then |
||||
|
echo "Folder '$src' not found, please provide a valid directory as first argument." >&2 |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
dest="$2" |
||||
|
|
||||
|
if [ -z "$dest" ]; then |
||||
|
echo "You must provide a host as target." >&2 |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
|
||||
|
rsync_options=(${RSYNC_OPTIONS:-}) |
||||
|
ssh_options=(${SSH_OPTIONS:--o StrictHostKeyChecking=no}) |
||||
|
|
||||
|
|
||||
|
if echo "$dest" | grep "/" >/dev/null 2>&1; then |
||||
|
rsync_options=("--bwlimit" "$(echo "$dest" | cut -f 2 -d "/")" "${rsync_options[@]}") |
||||
|
dest="$(echo "$dest" | cut -f 1 -d "/")" |
||||
|
fi |
||||
|
|
||||
|
if echo "$dest" | grep ":" >/dev/null 2>&1; then |
||||
|
ssh_options=("-p" "$(echo "$dest" | cut -f 2 -d ":")" "${ssh_options[@]}") |
||||
|
dest="$(echo "$dest" | cut -f 1 -d ":")" |
||||
|
fi |
||||
|
|
||||
|
|
||||
|
hostname=$(hostname) |
||||
|
hostname=${LABEL_HOSTNAME:-$hostname} |
||||
|
|
||||
|
dest_path="/var/mirror/$hostname" |
||||
|
|
||||
|
touch /etc/rsync/exclude-patterns |
||||
|
touch /etc/rsync/include-patterns |
||||
|
|
||||
|
if ! [ -s "/etc/rsync/include-patterns" ]; then |
||||
|
echo "Nothing to do as /etc/rsync/include-patterns is empty." |
||||
|
exit 0 |
||||
|
fi |
||||
|
|
||||
|
cmd=(/usr/bin/rsync "${rsync_options[@]}" -azvA |
||||
|
-e "sudo -u $user ssh ${ssh_options[*]}" |
||||
|
--include-from /etc/rsync/include-patterns |
||||
|
--exclude-from /etc/rsync/exclude-patterns |
||||
|
--delete --partial --partial-dir .rsync-partial |
||||
|
--numeric-ids "$src/" "$user@$dest":"$dest_path") |
||||
|
|
||||
|
rsync_uid_gid=$(stat -c "%u:%g" "/var/lib/rsync") |
||||
|
chown "$rsync_uid_gid" "/var/lib/rsync/.ssh" -R |
||||
|
|
||||
|
echo "${cmd[@]}" |
||||
|
|
||||
|
exec "${cmd[@]}" |
@ -0,0 +1,35 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
## When writing relation script, remember: |
||||
|
## - they should be idempotents |
||||
|
## - they can be launched while the dockers is already up |
||||
|
## - they are launched from the host |
||||
|
## - the target of the link is launched first, and get a chance to ``relation-set`` |
||||
|
## - both side of the scripts get to use ``relation-get``. |
||||
|
|
||||
|
. lib/common |
||||
|
|
||||
|
set -e |
||||
|
|
||||
|
exclude_patterns=$(relation-get "exclude-patterns") || true |
||||
|
include_patterns=$(relation-get "include-patterns") || true |
||||
|
include_patterns=${include_patterns:-"- /"} |
||||
|
|
||||
|
while read-0 pattern; do |
||||
|
if [[ "$pattern" != /* ]]; then |
||||
|
err "Invalid pattern '$pattern' provided as ${WHITE}exclude-pattern${NORMAL}, " \ |
||||
|
"in relation's options." |
||||
|
exit 1 |
||||
|
fi |
||||
|
echo "/$BASE_SERVICE_NAME$pattern" |
||||
|
done < <(e "$exclude_patterns" | shyaml get-values-0) >> "$RSYNC_EXCLUDE_PATTERNS" |
||||
|
|
||||
|
while read-0 pattern; do |
||||
|
if [[ "$pattern" != /* ]]; then |
||||
|
err "Invalid pattern '$pattern' provided as ${WHITE}exclude-pattern${NORMAL}, " \ |
||||
|
"in relation's options." |
||||
|
exit 1 |
||||
|
fi |
||||
|
echo "/$BASE_SERVICE_NAME$pattern" |
||||
|
done < <(e "$include_patterns" | shyaml get-values-0) >> "$RSYNC_INCLUDE_PATTERNS" |
||||
|
|
@ -0,0 +1,22 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
## Init is run on host |
||||
|
## For now it is run every time the script is launched, but |
||||
|
## it should be launched only once after build. |
||||
|
|
||||
|
## Accessible variables are: |
||||
|
## - SERVICE_NAME Name of current service |
||||
|
## - DOCKER_BASE_IMAGE Base image from which this service might be built if any |
||||
|
## - SERVICE_DATASTORE Location on host of the DATASTORE of this service |
||||
|
## - SERVICE_CONFIGSTORE Location on host of the CONFIGSTORE of this service |
||||
|
|
||||
|
. lib/common |
||||
|
|
||||
|
set -e |
||||
|
|
||||
|
|
||||
|
RSYNC_EXCLUDE_PATTERNS="$SERVICE_CONFIGSTORE/etc/rsync/exclude-patterns" |
||||
|
|
||||
|
mkdir -p "${RSYNC_EXCLUDE_PATTERNS%/*}" |
||||
|
echo "/*/" > "$RSYNC_EXCLUDE_PATTERNS" ## start a new |
||||
|
echo > "$RSYNC_INCLUDE_PATTERNS" ## start a new |
@ -0,0 +1,48 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
## When writing relation script, remember: |
||||
|
## - they should be idempotents |
||||
|
## - they can be launched while the dockers is already up |
||||
|
## - they are launched from the host |
||||
|
## - the target of the link is launched first, and get a chance to ``relation-set`` |
||||
|
## - both side of the scripts get to use ``relation-get``. |
||||
|
|
||||
|
. lib/common |
||||
|
|
||||
|
set -e |
||||
|
|
||||
|
schedule=$(relation-get schedule) |
||||
|
|
||||
|
if ! echo "$schedule" | egrep '^\s*(([0-9/,*-]+\s+){4,4}[0-9/,*-]+|@[a-z]+)\s*$' >/dev/null 2>&1; then |
||||
|
err "Unrecognized schedule '$schedule'." |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
private_key=$(options-get private-key) || exit 1 |
||||
|
target=$(options-get target) || exit 1 |
||||
|
ident=$(options-get ident) || exit 1 |
||||
|
|
||||
|
home=/var/lib/rsync |
||||
|
local_path_key=$home/.ssh |
||||
|
host_path_key="$SERVICE_CONFIGSTORE${local_path_key}" |
||||
|
|
||||
|
echo "$private_key" | file_put "$host_path_key/id_rsa" |
||||
|
chmod 600 "$host_path_key/id_rsa" |
||||
|
|
||||
|
label="${SERVICE_NAME}" |
||||
|
DST=$CONFIGSTORE/$TARGET_CHARM_NAME/etc/cron/$label |
||||
|
|
||||
|
## Warning: using '\' in heredoc will be removed in the final cron file, which |
||||
|
## is totally wanted: cron does not support multilines. |
||||
|
file_put "$DST" <<EOF |
||||
|
$schedule root lock $label -v -D -p 10 -k -c "\ |
||||
|
docker run --rm \ |
||||
|
-e LABEL_HOSTNAME=\"$ident\" \ |
||||
|
-v \"$RSYNC_CONFIG_DIR:/etc/rsync\" \ |
||||
|
-v \"$host_path_key:$local_path_key\" \ |
||||
|
-v \"$HOST_DATASTORE:/mnt/source\" \ |
||||
|
--network ${PROJECT_NAME}_default \ |
||||
|
\"$DOCKER_BASE_IMAGE\" \ |
||||
|
/mnt/source \"$target\"" 2>&1 | ts '\%F \%T' >> /var/log/cron/${label}_script.log |
||||
|
EOF |
||||
|
chmod +x "$DST" |
@ -0,0 +1,5 @@ |
|||||
|
|
||||
|
|
||||
|
RSYNC_CONFIG_DIR="$SERVICE_CONFIGSTORE/etc/rsync" |
||||
|
RSYNC_INCLUDE_PATTERNS="$RSYNC_CONFIG_DIR/include-patterns" |
||||
|
RSYNC_EXCLUDE_PATTERNS="$RSYNC_CONFIG_DIR/exclude-patterns" |
@ -0,0 +1,17 @@ |
|||||
|
description: Rsync Backup Service |
||||
|
type: run-once |
||||
|
|
||||
|
provides: |
||||
|
backup: |
||||
|
|
||||
|
uses: |
||||
|
schedule-command: |
||||
|
constraint: required |
||||
|
auto: summon |
||||
|
solves: |
||||
|
missing-feature: "scheduling of backups" |
||||
|
default-options: |
||||
|
## backup every day on random time |
||||
|
schedule: !bash-stdout | |
||||
|
printf "%d %d * * *" "$((RANDOM % 60))" "$((RANDOM % 6))" |
||||
|
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue