Abdull
Abdull

Reputation: 27822

expect script with optional ssh-agent passphrase prompt?

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:

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:

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

Answers (1)

glenn jackman
glenn jackman

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

Related Questions