cdist/docs/src/cdist-remote-exec-copy.rst

416 lines
9.7 KiB
ReStructuredText
Raw Permalink Normal View History

Remote exec and copy commands
=============================
Cdist interacts with the target host in two ways:
2016-05-20 06:50:56 +00:00
- it executes code (__remote_exec)
- and it copies files (__remote_copy)
By default this is accomplished with ssh and scp respectively.
2016-05-20 06:50:56 +00:00
The default implementations used by cdist are::
__remote_exec: ssh -o User=root
2020-09-27 08:17:35 +00:00
__remote_copy: scp -o User=root -q
The user can override these defaults by providing custom implementations and
passing them to cdist with the --remote-exec and/or --remote-copy arguments.
For __remote_exec, the custom implementation must behave as if it where ssh.
For __remote_copy, it must behave like scp.
2016-11-27 16:02:51 +00:00
Please notice, custom implementations should work like ssh/scp so __remote_copy
must support IPv6 addresses enclosed in square brackets. For __remote_exec you
must take into account that for some options (like -L) IPv6 addresses can be
specified by enclosed in square brackets (see :strong:`ssh`\ (1) and
:strong:`scp`\ (1)).
With this simple interface the user can take total control of how cdist
interacts with the target when required, while the default implementation
remains as simple as possible.
2020-09-27 08:17:35 +00:00
Examples
--------
Here are examples of using alternative __remote_copy and __remote_exec scripts.
All scripts from below are present in cdist sources in `other/examples/remote`
directory.
ssh
~~~
Same as cdist default.
**copy**
Usage: cdist config --remote-copy "/path/to/this/script" target_host
.. code-block:: sh
#echo "$@" | logger -t "cdist-ssh-copy"
scp -o User=root -q $@
**exec**
Usage: cdist config --remote-exec "/path/to/this/script" target_host
.. code-block:: sh
#echo "$@" | logger -t "cdist-ssh-exec"
ssh -o User=root $@
local
~~~~~
This effectively turns remote calling into local calling. Probably most useful
for the unit testing.
**copy**
.. code-block:: sh
code="$(echo "$@" | sed "s|\([[:space:]]\)$__target_host:|\1|g")"
cp -L $code
**exec**
.. code-block:: sh
target_host=$1; shift
echo "$@" | /bin/sh
chroot
~~~~~~
**copy**
Usage: cdist config --remote-copy "/path/to/this/script /path/to/your/chroot" target-id
.. code-block:: sh
log() {
#echo "$@" | logger -t "cdist-chroot-copy"
:
}
chroot="$1"; shift
target_host="$__target_host"
# replace target_host with chroot location
code="$(echo "$@" | sed "s|$target_host:|$chroot|g")"
log "target_host: $target_host"
log "chroot: $chroot"
log "$@"
log "$code"
# copy files into chroot
cp $code
log "-----"
**exec**
Usage: cdist config --remote-exec "/path/to/this/script /path/to/your/chroot" target-id
.. code-block:: sh
log() {
#echo "$@" | logger -t "cdist-chroot-exec"
:
}
chroot="$1"; shift
target_host="$1"; shift
script=$(mktemp "${chroot}/tmp/chroot-${0##*/}.XXXXXXXXXX")
trap cleanup INT TERM EXIT
cleanup() {
[ $__cdist_debug ] || rm "$script"
}
log "target_host: $target_host"
log "script: $script"
log "@: $@"
echo "#!/bin/sh -l" > "$script"
echo "$@" >> "$script"
chmod +x "$script"
relative_script="${script#$chroot}"
log "relative_script: $relative_script"
# run in chroot
chroot "$chroot" "$relative_script"
log "-----"
rsync
~~~~~
**copy**
Usage: cdist config --remote-copy /path/to/this/script target_host
.. code-block:: sh
# For rsync to do the right thing, the source has to end with "/" if it is
# a directory. The below preprocessor loop takes care of that.
# second last argument is the source
source_index=$(($#-1))
index=0
for arg in $@; do
if [ $index -eq 0 ]; then
# reset $@
set --
fi
index=$((index+=1))
if [ $index -eq $source_index -a -d "$arg" ]; then
arg="${arg%/}/"
fi
set -- "$@" "$arg"
done
rsync --backup --suffix=~cdist -e 'ssh -o User=root' $@
schroot
~~~~~~~
__remote_copy and __remote_exec scripts to run cdist against a chroot on the
target host over ssh.
**copy**
Usage: cdist config --remote-copy "/path/to/this/script schroot-chroot-name" target_host
.. code-block:: sh
log() {
#echo "$@" | logger -t "cdist-schroot-copy"
:
}
chroot_name="$1"; shift
target_host="$__target_host"
# get directory for given chroot_name
chroot="$(ssh -o User=root -q $target_host schroot -c $chroot_name --config | awk -F = '/directory=/ {print $2}')"
# prefix destination with chroot
code="$(echo "$@" | sed "s|$target_host:|$target_host:$chroot|g")"
log "target_host: $target_host"
log "chroot_name: $chroot_name"
log "chroot: $chroot"
log "@: $@"
log "code: $code"
# copy files into remote chroot
scp -o User=root -q $code
log "-----"
**exec**
Usage: cdist config --remote-exec "/path/to/this/script schroot-chroot-name" target_host
.. code-block:: sh
log() {
#echo "$@" | logger -t "cdist-schroot-exec"
:
}
chroot_name="$1"; shift
target_host="$1"; shift
code="ssh -o User=root -q $target_host schroot -c $chroot_name -- $@"
log "target_host: $target_host"
log "chroot_name: $chroot_name"
log "@: $@"
log "code: $code"
# run in remote chroot
$code
log "-----"
schroot-uri
~~~~~~~~~~~
__remote_exec/__remote_copy script to run cdist against a schroot target URI.
Usage::
cdist config \
--remote-exec "/path/to/this/script exec" \
--remote-copy "/path/to/this/script copy" \
target_uri
# target_uri examples:
schroot:///chroot-name
schroot://foo.ethz.ch/chroot-name
schroot://user-name@foo.ethz.ch/chroot-name
# and how to match them in .../manifest/init
case "$target_host" in
schroot://*)
# any schroot
;;
schroot://foo.ethz.ch/*)
# any schroot on specific host
;;
schroot://foo.ethz.ch/chroot-name)
# specific schroot on specific host
;;
schroot:///chroot-name)
# specific schroot on localhost
;;
esac
**copy/exec**
.. code-block:: sh
my_name="${0##*/}"
mode="$1"; shift
log() {
# uncomment me for debugging
#echo "$@" | logger -t "cdist-$my_name-$mode"
:
}
die() {
echo "$@" >&2
exit 1
}
uri="$__target_host"
scheme="${uri%%:*}"; rest="${uri#$scheme:}"; rest="${rest#//}"
authority="${rest%%/*}"; rest="${rest#$authority}"
path="${rest%\?*}"; rest="${rest#$path}"
schroot_name="${path#/}"
[ "$scheme" = "schroot" ] || die "Failed to parse scheme from __target_host ($__target_host). Expected 'schroot', got '$scheme'"
[ -n "$schroot_name" ] || die "Failed to parse schroot name from __target_host: $__target_host"
case "$authority" in
'')
# authority is empty, neither user nor host given
user=""
host=""
;;
*@*)
# authority contains @, take user from authority
user="${authority%@*}"
host="${authority#*@}"
;;
*)
# no user in authority, default to root
user="root"
host="$authority"
;;
esac
log "mode: $mode"
log "@: $@"
log "uri: $uri"
log "scheme: $scheme"
log "authority: $authority"
log "user: $user"
log "host: $host"
log "path: $path"
log "schroot_name: $schroot_name"
exec_prefix=""
copy_prefix=""
if [ -n "$host" ]; then
# we are working on a remote host
exec_prefix="ssh -o User=$user -q $host"
copy_prefix="scp -o User=$user -q"
copy_destination_prefix="$host:"
else
# working on local machine
copy_prefix="cp"
copy_destination_prefix=""
fi
log "exec_prefix: $exec_prefix"
log "copy_prefix: $copy_prefix"
log "copy_destination_prefix: $copy_destination_prefix"
case "$mode" in
exec)
# In exec mode the first argument is the __target_host which we already got from env. Get rid of it.
shift
code="$exec_prefix schroot -c $schroot_name -- sh -c '$@'"
;;
copy)
# get directory for given chroot_name
schroot_directory="$($exec_prefix schroot -c $schroot_name --config | awk -F = '/directory=/ {print $2}')"
[ -n "$schroot_directory" ] || die "Failed to retreive schroot directory for schroot: $schroot_name"
log "schroot_directory: $schroot_directory"
# prefix destination with chroot
code="$copy_prefix $(echo "$@" | sed "s|$uri:|${copy_destination_prefix}${schroot_directory}|g")"
;;
*) die "Unknown mode: $mode";;
esac
log "code: $code"
# Run the code
$code
log "-----"
sudo
~~~~
**copy**
Use rsync over ssh to copy files. Uses the "--rsync-path" option
to run the remote rsync instance with sudo.
This command assumes your ssh configuration is already set up in ~/.ssh/config.
Usage: cdist config --remote-copy /path/to/this/script target_host
.. code-block:: sh
# For rsync to do the right thing, the source has to end with "/" if it is
# a directory. The below preprocessor loop takes care of that.
# second last argument is the source
source_index=$(($#-1))
index=0
for arg in $@; do
if [ $index -eq 0 ]; then
# reset $@
set --
fi
index=$((index+=1))
if [ $index -eq $source_index -a -d "$arg" ]; then
arg="${arg%/}/"
fi
set -- "$@" "$arg"
done
rsync --copy-links --rsync-path="sudo rsync" -e 'ssh' "$@"
**exec**
Prefixes all remote commands with sudo.
This command assumes your ssh configuration is already set up in ~/.ssh/config.
Usage: cdist config --remote-exec "/path/to/this/script" target_host
.. code-block:: sh
host="$1"; shift
ssh -q "$host" sudo sh -c \""$@"\"