Sharath Arakere
Sharath Arakere

Reputation: 129

Expect script to run Ansible playbooks

I have written an Ansible playbook which prompts me to enter password interactively for SSH and SUDO like below.

$ ansible-playbook -i test --limit dev  app_name.yml  -vv --tags=stop
SSH password:
SUDO password[defaults to SSH password]:

There are various options available with Ansible like defining password in ansible_ssh_password under group_vars but it don't seem to work for me since I can't have sshpass installed in my target server nor I am allowed to make any changes to my sudoers file.

I tried to execute ansible-playbook from a little expect script below

#!/usr/bin/expect -f
set password PASSWORD
set where_to_execute  [lindex $argv 0]
set which_app_to_execute  [lindex $argv 1]
set what_to_execute  [lindex $argv 2]

send "ansible-playbook -i test --limit $where_to_execute $which_app_to_execute  -vv --tags=$what_to_execute \r"
expect "SSH password:"
send "$password \r"
expect "SUDO password*"
send "$password \r"
expect "$"
send "exit \r"

Unfortunately this is also not working may be because SSH process is not spawned by expect. Did anyone try this method and got things working. Please suggest. Thanks.

Upvotes: 2

Views: 4756

Answers (2)

Etan Reisner
Etan Reisner

Reputation: 80931

The problem with your expect scripts is that you aren't actually running the ansible command there (or any command for that matter).

You use

send "ansible-playbook -i test --limit $where_to_execute $which_app_to_execute  -vv --tags=$what_to_execute \r"

which sends that string to ... nowhere as far as I know. There's nowhere for it to go.

What you want to be doing is spawning that ansible command and then using expect to communicate with it.

Something like this:

spawn ansible-playbook -i test --limit $where_to_execute $which_app_to_execute  -vv --tags=$what_to_execute

You may also want to set the timeout value if the ansible command can take a little while (to prevent expect from killing it when it doesn't return quickly enough).

Upvotes: 3

Bernardo Vale
Bernardo Vale

Reputation: 3554

It works for me using the python implementation of expect. pexpect

install pexpect using pip: pip install pexpect

You can use this code as an workaround for your expect script:

#!/usr/bin/python
import pexpect

def main(args):

  #Setup variables
  password, where, which, what = args

  cmd = "ansible-playbook -i test --limit %s %s  -vv --tags=%s" % (where, which, what)

  child = pexpect.spawn(cmd)
  child.sendline(password)
  child.expect('SSH password:')
  child.sendline(password)
  child.expect('SUDO password*')
  child.expect(pexpect.EOF)

  print child.before


if __name__ == '__main__':
  main(sys.argv[1:])

This is the most simple example but it's working fine for me.

./myscript.py mypassword dev app_name.yml stop

As @Etan Reisner pointed out, the main difference between your code that isn't working and my pexpect code is the spawn ansible command. The above code on expect also works fine:

#!/usr/bin/expect -f
spawn /usr/bin/ansible -m ping myserver --ask-pass
expect "SSH password:"
send "mypassword\r"
expect "$ "

Upvotes: 1

Related Questions