Bash: lokale Variablen auf remote host über ssh ausführen

ghostadmin

Grand Admiral Special
Mitglied seit
11.11.2001
Beiträge
25.200
Renomée
186
Standort
Dahoam Studios
Ich habe folgenden Codeausschnitt
Code:
sshuser=root
sshhost=remotehost
sshport=8022
zfsdisks=da1 
zfspool=tank
rsyncpasswd=$(cat /etc/.rsyncpass)
ssh "${sshuser}@${sshhost}" -p "$sshport" bash -s << EOF
echo "shell is" $SHELL
checkzfs=$(zpool list | grep $zfspool | awk '{ print $7}')
if [ "$?" != "ONLINE" ]; then
    for device in $zfsdisks; do
        echo $rsyncpasswd | geli attach -j - /dev/${device}
    done
    sleep 5
    zpool import -R $zfspool
    sleep 5
else
    echo "Zpool is online"
fi
EOF

Funktioniert aber leider vorne und hinten nicht. Es kommt z.B. Fehlermeldung das es zpool nicht gibt (Befehl existiert auf remote system aber nicht lokal) oder die Variable $device ist leer.
Die Befehle scheinen teilweise lokal ausgeführt zu werden.
for device in ... das scheint lokal statt remote zu laufen

Lässt man die ganzen checks weg, dann geht es. Aber kann man das nicht irgendwie so hinbiegen?
 
Vermutlich solltest du das mal beachten:
http://en.wikipedia.org/wiki/Here_document#Unix-Shells

By default, variables are interpolated and commands in backticks are evaluated.

Code:
 cat << EOF
 Working dir $PWD
 EOF
yields:

Code:
Working dir /home/user
This can be disabled by quoting any part of the label. For example by setting it in single or double quotes:

Code:
 cat << "EOF"
 Working dir $PWD
 EOF
yields
Code:
Working dir $PWD

Denn aktuell werden eben deine Befehle lokal evaluiert.

---------- Beitrag hinzugefügt um 07:26 ---------- Vorheriger Beitrag um 07:24 ----------

Here wollte jemand auch etwas ähnliches machen nur dass der Ausführungskontext in diesem Fall ein SQL Interpreter war und die Variablen vom Interpreter zu evaluiert werden müssen und nicht vom lokalen Prompt.
http://stackoverflow.com/questions/2500436/how-does-cat-eof-work-in-bash
 
if und for per ssh so zu übergeben wird nicht funktionieren bzw ist dies eine zu große fehlerquelle, da du nie weißt was das remotesystem ausgiibt.
du musst alle ssh-befehle für das remotesystem mit den ssh variablen ausführen und die if und for schleifen lokal auswerten.

auch kommst du hier besser nen alias für ssh zu setzen.

ich würde nie for oder if schleife an die bash eines anderen servers so übergeben.
werte auf dem remote ermitteln und lokal in if und for verarbeiten.

Code:
alias sshextern='ssh "${sshuser}@${sshhost}" -p "$sshport"'

if ( `sshextern zpool list | grep $zfspool | awk '{print $7}'` != "Online" );then
 ....
 ( sshextern zpool import -R $zfspool && echo "Import $zfspool erfolgreich" ) || echo "Import $zfspool fehlgeschlagen"
else
 echo "$zfspool Online"
fi

Nicht getestet sollte aber verdeutlichen was ich mein


 
Der Alias ging im Script nicht aber mit einer Variable geht dann endlich alles.
Also einfach
Code:
sshextern="ssh ${sshuser}@{sshhost} -p $sshport"

Bei dieser Zeile ist irgendwo ein Syntax Error:
Code:
if ( `sshextern zpool list | grep $zfspool | awk '{print $7}'` != "Online" ); then
 
Der Syntaxfehler kommt meistens, wenn mehr als 1 Ergebnis oder kein Ergebnis bei dem "grep" raus kommt.
aber wie gesagt, habs nicht getestet, da ich kein ZFS aktuell zu hand habe. Sauber wäre die Lösung, da hier immer ein Ergebis herauskommt:



if ( `sshextern zpool list | grep $zfspool | grep -c "Online"'` -lt 1 ); then
 
awk hätte schon "online" geliefert, keine Ahnung aber mit dem zweiten grep gehts jetzt.

Dafür habe ich jetzt in:
Code:
( $sshextern echo $rsyncpasswd | geli attach -j - /dev/${device} && echo "attached ${device}" ) || echo "could not attach ${device}"

Zeile 68: geli: Kommando nicht gefunden.
could not attach da1

Versucht der jetzt geli lokal auszuführen weils nach pipe kommt?
 
Versucht der jetzt geli lokal auszuführen weils nach pipe kommt?
Ja. Ich würde gar nicht so einen Zirkus machen und ein Skript zusammenbauen und das auf dem Remote-System ausführen. Ob du das vorher zusammenbaust oder zum Auführzeitpunkt (und das dann hochlädst), ist egal.

MfG Dalai
 
Zirkus heisst für mich mehrere Scripts und das Passwort auf einem System als Datei zu speichern wo es nicht hingehört.

Man musste nur das ganze in double quotes setzen.

Und bei dem If habe ich eckige Klammern gesetzt.

Code:
#!/bin/bash
#rsync script for sending files over ssh to an ecrypted zfs storage
#dont forget to configure passwordless login over ssh
progname=$(basename "$0") #get this file name, used only for mail
logpath=/var/log/rsync
emailto=root

# parameters for backup target
sshuser=root
sshhost=somehost
sshport=8022
sshtargetfolder=/mnt/tank/backup # create path manually if not exist
zfspool=tank #doesnt mount on bootup because disks are encrypted
zfsdisks=da1 #encrypted disks to mount, separate multiple devices with blank between
rsyncpasswd=$(cat /etc/.rsyncpass) #stored on local disk, used on remote ssh

#additional parameters when machine resides on a esx host
esxuser=root
esxhost=someesxhost
esxport=8023

sshextern="ssh ${sshuser}@${sshhost} -p $sshport"

start_rsync()
{
echo "--- Starting $1 ---" | sudo -u "$sshuser" tee -a "$logpath"/rsync.log
startrsync=$(sudo -u "$sshuser" rsync -avze "ssh -p $sshport" --stats --progress --inplace --delete --log-file="$logpath"/rsync.log "$2" "${sshuser}@${sshhost}:${sshtargetfolder}")
# start again if errorlevel not 0 and did not run 10 times
if [ "$?" != "0" ] && [ "$i" -lt "10" ]; then
echo "There was an error during transmission, starting again ..."
((i++))
start_rsync "$1" "$2"
fi
}

#loop mount of local data with encfs and create encrypted view
#it is importand that .encfs6.xml will be kept for decrypting
#encfs --reverse /data/Dokumente /mnt/encfsDokumente
#umount with: fusermount -u /mnt/encfsDokumente

# startup remote vmware guest on a esx host
# first check if guest responds
$sshextern exit
# if return value not 0 then start guest on esx host
if [ "$?" != "0" ]; then
    ssh "${esxuser}@${esxhost}" -p "$esxport" "vim-cmd vmsvc/power.on 4"
    echo "wait 120s ..."
    sleep 120 # allow 120sec to come up
fi
# check if guest is now alive and exit script if thats not the case
$sshextern exit
if [ "$?" != "0" ]; then
    echo "could not wake up ${sshhost}"
    exit $?
fi

# or use wol to wakeup
#if [ "$(ping -c 1 $sshhost | grep "1 received")" ]; then
#    echo "OK: Remote host is pingable"
#else
#    /usr/bin/wakeonlan "$wolmac"
#    sleep 120
#fi

# attach geli encrypted disks and import zfs pool
if [ $($sshextern zpool list | grep $zfspool | grep -c "ONLINE") -ne 1 ]; then
    for device in $zfsdisks; do
        if [ $($sshextern geli status | grep $device | grep -c "ACTIVE") -ne 1 ]; then
            ( $sshextern "echo $rsyncpasswd | geli attach -j - /dev/${device}" && echo "attached ${device}" ) || echo "could not attach ${device}"
        else
            echo "$device already attached"
        fi
    done
    sleep 5
    ( $sshextern zpool import $zfspool && echo "${zfspool} was imported" ) || echo "could not import ${zfspool}"
    sleep 5
    if [ $($sshextern zpool list | grep $zfspool | grep -c "ONLINE") -ne 1 ]; then
        echo "${zfspool} is not ONLINE after import"
        exit $?
    fi
else
    echo "$zfspool is ONLINE"
fi


# remove old local log (because of mailing logs)
if [ -f "$logpath"/rsync.log ]; then
    rm -f "$logpath"/rsync.log
fi

# reset error counter and start rsync
echo "start rsync ..."
i=0 && start_rsync yourstuff /data/yourstuff


# export remote zfs pool, to have it not faulted on next boot
( $sshextern zpool export -f $zfspool && echo "${zfspool} was exported" && sleep 10 ) || echo "could not export ${zfspool}"

# mail
mail -s "[$progname] - rsync running on $(hostname) to $sshhost completed" "$emailto" < "$logpath"/rsync.log && echo "mail was delivered"

# shutdown remote host
ssh "${sshuser}@${sshhost}" -p "$sshport" "shutdown -p now"
 
Zuletzt bearbeitet:
Zurück
Oben Unten