Reputation: 27822
I want to automate a database backup with help from expect: First, the script establishes a forwarded port from the remote database port to my local machine using ssh. Then I use the database utility to dump all databases.
Therefore, I have the following expect script inside a bash script:
#!/bin/sh
expect <<- DONE
set timeout -1
# port-forward remote database port 3306 to local port 3307
spawn ssh -M -S /var/run/examplecom-mysql-socket -fnNT -L 3307:localhost:3306 [email protected]
expect {
# conditional prompt appears in case ssh-agent is not active
"*.ssh/id_rsa':*" {
send -- "$SSH_PASSPHRASE\r"
}
# ?!?!?!? What to expect here in case ssh-agent is active, therefore no password needed, and therefore no prompt appears?
}
# dump remote database by connecting to forwarded port
spawn mysqldump --all-databases --user=root --password --protocol=TCP --host=localhost --port=3307 --verbose --result-file=${DB_DUMP_FILE}
expect {
# prompt appears for database password
"*?asswor?:*" {
send -- "$PASSWORD_MYSQL_ROOT\r"
}
}
expect eof
DONE
This script may run within two scenarios:
Enter passphrase for key '${HOME}/.ssh/id_rsa':
, which the first expect rule happily matches, and correctly sends the SSH passphrase.I am struggling to get both scenarios working in my expect script. In particular, I don't know how to modify the script so that the "silent" active-ssh-agent is "expected" and therefore the expect script can continue with starting the database dump.
I tried the expect multiple things approach (at above ?!?!?!?
comment location) by trying out:
eof
.But none worked. I found similar problems and suggested solutions around StackExchange: * How to use expect with optional prompts? * https://superuser.com/q/412259/137881 * TCL / Expect Scripting - Using a conditional statement to attempt a secondary login password
But the solutinos seem to cause code duplications: Each conditional prompt means copy and pasting the rest of the script, which makes the script get convoluted quickly with nested conditional prompts for each ssh statement.
How can I have expect work gracefully in situations where ssh does not prompt for the passphrase/password because of an active ssh-agent?
Upvotes: 1
Views: 1893
Reputation: 246774
Yeah, that's a funny one. Since you're using ssh -N
, you don't launch any process on the remote host, and the ssh session just sits there. You would just have to sleep for a couple of seconds and hope the tunnel gets established.
set timeout 2
spawn ssh -M -S /var/run/examplecom-mysql-socket -fnNT -L 3307:localhost:3306 [email protected]
expect {
# conditional prompt appears in case ssh-agent is not active
"*.ssh/id_rsa':*" { send -- "$SSH_PASSPHRASE\r" }
# wait until the timeout, then carry on with the rest of the script
timeout
}
set timeout -1
# ...
Or, remove -N
, then you can expect to see the prompt on the remote host.
spawn ssh -M -S /var/run/examplecom-mysql-socket -fnT -L 3307:localhost:3306 [email protected]
# ..........................................^^^^
expect {
# conditional prompt appears in case ssh-agent is not active
"*.ssh/id_rsa':*" { send -- "$SSH_PASSPHRASE\r" }
# I assume your prompt ends with a dollar sign and a space
-re {\$ $}
}
Now you can spawn the mysql command and interact with that.
Upvotes: 2