I am trying to automate the deployment of a Docker container. Three prompts need to be filled in manually in order to proceed with the deployment. However, they are not to be filled in after each other. The order in which these fields appear is very odd. First off it asks for a password and a confirmation (two fields following each other). Then, the OpenVPN script does its thing and then needs an FQDN to generate a certificate I believe.

So: I'm wondering if I can tell expect to fill in value X for field X and once the input field Y appears, fill in value Y. In other words, can I tell expect to automatically recognize input prompts and fill them in accordingly?

  • I recommend Ansible. – Rui F Ribeiro Feb 7 '18 at 11:09
  • @RuiFRibeiro Ansible introduces more challenges than the problem it's supposed to solve for this specific project. We do most of our deployment with Ansible though. – William Edwards Feb 7 '18 at 11:12
  • I have used expect in the past. It is a bit limited for this kind of actions, and involves a lot of babysitting over time. – Rui F Ribeiro Feb 7 '18 at 11:13
  • @RuiFRibeiro I am aware. – William Edwards Feb 7 '18 at 11:13
  • 1
    The answer to your current question is: yes, probably. Can you show examples of those prompts and values? Then someone here might be able to provide a useful answer. – Jeff Schaller Feb 7 '18 at 11:35

Certainly, this is what expect is for. The exp_continue command is the key here:

expect {
    "password: "   {send "$password\r"; exp_continue}
    "confirmation" {send "$confirm\r"; exp_continue}
    "FQDN"         {send "$fqdn\r"; exp_continue}
    "some other pattern"

Of course you'll have to change the quoted patterns so they match your actual case.

With this structure, the patterns can match in any order. The patterns don't even have to appear at all.

When "some other pattern" is seen, since there's no action block associated with it, it triggers the end of the encompassing expect command and the rest of the script can carry on.

For expect to be able to control a process, you must launch that process from within expect. Try this:

export hostname=$2
export OVPN_DATA="ovpn-data-$port"
docker volume create --name $OVPN_DATA

/usr/bin/expect <<'END_EXPECT'
    set timeout -1
    spawn docker run -v $env(OVPN_DATA):/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://$env(hostname)
    expect {
        "Enter PEM pass phrase:" {
            # this should match whether it's the initial or confirmation prompt
            send "secret\r"
        "Common Name" {
            send "$env(hostname)\r"

docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki
docker run -dit --restart unless-stopped --name=$port -v $OVPN_DATA:/etc/openvpn -d -p $port:1194/udp --cap-add=NET_ADMIN kylemanna/openvpn
  • The code (second block) doesn't work. Variables aren't getting passed properly I suppose? no such variable (read trace on "env(hostname)") invoked from within – William Edwards Feb 7 '18 at 19:27
  • did you export the shell variable hostname? – glenn jackman Feb 7 '18 at 20:05
  • Yes. The certificate is not generated successfully: Options error: --dh fails with '/etc/openvpn/pki/dh.pem': No such file or directory (errno=2) – William Edwards Feb 7 '18 at 20:12
  • I rewrote the code slightly and it seems to work now. Hold on. – William Edwards Feb 7 '18 at 20:17
  • Getting unable to load CA private key now but I figured that can have many reasons, so I will debug further. – William Edwards Feb 7 '18 at 20:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.