Local action in playbook tree

Hello all,

Since yesterday, I am struggling with a problem where I can’t find a real solution at the moment.

As stated a week back, I am currently in the process of configuring a bunch of postfix mail servers with ansible.

The current problem is:

I have a tree of local CA certificates, which need to be synced to all my mailservers, and hashed, so openssl will recognize them.

Currently, I have the following task:

  • name: Transfer CA certs
    copy: src=$item dest={{ pfxc }}/tls/cacerts.d
    with_fileglob:
  • cacerts.d/*.pem
    notify:
  • Hash CA certs

with this handler:

  • name: Hash CA certs
    shell: c_rehash {{ pfxc }}/tls/cacerts.d

The problem I’m seeing with this is, that I can’t delete a certificate in my playbook tree, and it will be deleted on all my servers. It will only transfer new an changed certificates on all my servers.

The other solution would be a local rsync action, with --delete.

For that, I need to hash the certificates in the local playbook tree, and then transfer the whole directory, including the hash symlinks, to the server.

But as the local action also does a ssh into localhost, I lose the working directory for the ansible playbook tree (which could be in different places for different people), so I don’t know how to resolve this.

In an ideal world, I would like to declare a task to be executed by the runner (instead of delegating it to the local server), so it will be executed in my current context, with my current user and my current directory, which is the ansible tree. Is there any possibility to do that? Or do I need to work on a local module there?

Any hints are appreciated, thank you in advance!

Best regards,
Jens

Hi Jens,

I would add deletion separately in next step.

  • name: Remove deleted CA certs
    file: path={{ item }} state=absent
    with_fileglob:
  • cacerts.d.deleted/*.pem
    notify:
  • Hash CA certs

This way, you have to move to delete certs to second directory (instead of deleting them) and it is done.

David

Thanks for you input. But it feels like a slightly hackish way to do it. It would work, for sure, but IMHO there should be a way to keep a directory in sync with the target server…

I pulled the reverted commit for the synchronize module out of the git repo, but it has a similar limitation than the approaches I tried earlier - it sshs into localhost, and I have no clue how to determine where the local playbook is. Or is there a var/fact where the path to the playbook which started an action is stored? That could actually help.

Best regards,
Jens

See local_action: rsync as described in the FAQ.

But that still does ssh into localhost, something I would like to avoid - as it isn’t guaranteed where the local playbook is. Or is there a fact telling me where to find it, which I could use?

local_action should not be SSH’ing into localhost, but should be forcing the local connection type.

Is this something you are speculating on or actually observing? (If so, what version of Ansible?)

–Michael

No, I have been observing this.

Centos 6.4, with ansible 1.2.3 and with ansible-head from a git pull.

I can provide logs later on, if you want (even though it is Saturday, and the stuff is work related :wink: )

Regards,
Jens

Please let me know about the recent release.

Don’t recall this behavior and would like to see the playbook.

Hi all, sorry for jumping in, but I’m observing the same behavior.

Here is my playbook:

  • hosts: all
    gather_facts: no
    tasks:
  • name: stop vm
    raw: poweroff
  • name: pause for 5 seconds
    local_action: pause seconds=5

Here’s the error with 1.3.0:

PLAY [all] ********************************************************************

TASK: [stop vm] ***************************************************************
ESTABLISH CONNECTION FOR USER: ste
EXEC [‘ssh’, ‘-tt’, ‘-q’, ‘-o’, ‘ControlMaster=auto’, ‘-o’, ‘ControlPersist=60s’, ‘-o’, ‘ControlPath=/home/ste/.ansible/cp/ansible-ssh-%h-%p-%r’, ‘-o’, ‘Port=40067’, ‘-o’, ‘KbdInteractiveAuthentication=no’, ‘-o’, ‘PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey’, ‘-o’, ‘PasswordAuthentication=no’, ‘-o’, ‘ConnectTimeout=10’, ‘wheezy’, ‘poweroff’]
ok: [wheezy] => {“rc”: 0, “stderr”: “”, “stdout”: “”}

TASK: [pause for 5 seconds] ***************************************************
<127.0.0.1> ESTABLISH CONNECTION FOR USER: ste
<127.0.0.1> EXEC [‘ssh’, ‘-tt’, ‘-q’, ‘-o’, ‘ControlMaster=auto’, ‘-o’, ‘ControlPersist=60s’, ‘-o’, ‘ControlPath=/home/ste/.ansible/cp/ansible-ssh-%h-%p-%r’, ‘-o’, ‘Port=22’, ‘-o’, ‘KbdInteractiveAuthentication=no’, ‘-o’, ‘PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey’, ‘-o’, ‘PasswordAuthentication=no’, ‘-o’, ‘ConnectTimeout=10’, ‘127.0.0.1’, “/bin/sh -c ‘mkdir -p $HOME/.ansible/tmp/ansible-1379327501.49-139269735518415 && chmod a+rx $HOME/.ansible/tmp/ansible-1379327501.49-139269735518415 && echo $HOME/.ansible/tmp/ansible-1379327501.49-139269735518415’”]
fatal: [wheezy] => Authentication or permission failure. In some cases, you may have been able to authenticate and did not have permissions on the remote directory. Consider changing the remote temp path in ansible.cfg to a path rooted in “/tmp”. Failed command was: mkdir -p $HOME/.ansible/tmp/ansible-1379327501.49-139269735518415 && chmod a+rx $HOME/.ansible/tmp/ansible-1379327501.49-139269735518415 && echo $HOME/.ansible/tmp/ansible-1379327501.49-139269735518415, exited with result 255

FATAL: all hosts have already failed – aborting

PLAY RECAP ********************************************************************
to retry, use: --limit @/home/ste/stop.retry

wheezy : ok=1 changed=0 unreachable=0 failed=1

Here’s the error with 1.2.3:

PLAY [all] ********************************************************************

TASK: [stop vm] ***************************************************************
ESTABLISH CONNECTION FOR USER: ste
EXEC [‘ssh’, ‘-tt’, ‘-q’, ‘-o’, ‘ControlMaster=auto’, ‘-o’, ‘ControlPersist=60s’, ‘-o’, ‘ControlPath=/home/ste/.ansible/cp/ansible-ssh-%h-%p-%r’, ‘-o’, ‘Port=40067’, ‘-o’, ‘KbdInteractiveAuthentication=no’, ‘-o’, ‘PasswordAuthentication=no’, ‘-o’, ‘ConnectTimeout=10’, ‘wheezy’, ‘poweroff’]
ok: [wheezy] => {“rc”: 0, “stderr”: “”, “stdout”: “\u0007\r\r\nBroadcast message from root@wheezy (pts/1) (Mon Sep 16 07:51:04 2013):\r\r\n\r\r\n\rThe system is going down for system halt NOW!\r\r\n”}

TASK: [pause for 5 seconds] ***************************************************
<127.0.0.1> ESTABLISH CONNECTION FOR USER: ste
<127.0.0.1> EXEC [‘ssh’, ‘-tt’, ‘-q’, ‘-o’, ‘ControlMaster=auto’, ‘-o’, ‘ControlPersist=60s’, ‘-o’, ‘ControlPath=/home/ste/.ansible/cp/ansible-ssh-%h-%p-%r’, ‘-o’, ‘Port=22’, ‘-o’, ‘KbdInteractiveAuthentication=no’, ‘-o’, ‘PasswordAuthentication=no’, ‘-o’, ‘ConnectTimeout=10’, ‘127.0.0.1’, “/bin/sh -c ‘mkdir -p $HOME/.ansible/tmp/ansible-1379328665.95-125157496377766 && chmod a+rx $HOME/.ansible/tmp/ansible-1379328665.95-125157496377766 && echo $HOME/.ansible/tmp/ansible-1379328665.95-125157496377766’”]
fatal: [wheezy] => could not create temporary directory: SSH exited with return code 255

FATAL: all hosts have already failed – aborting

PLAY RECAP ********************************************************************
to retry, use: --limit @/home/ste/stop.retry

wheezy : ok=1 changed=0 unreachable=0 failed=1

It would be great if local_action would not be SSH’ing into localhost, but rather forcing the local connection type, but it doesn’t seem to be the case.

Furthermore, this is especially true for the pause command, does it ever make sense for it to not be executed on the local machine?

Finally, the fatal error message (i.e. what you see without -vvv) seems better in 1.2.3 than in 1.3.0, at least I could more clearly understand there was a problem with SSH and not with file permissions. I understand that the new error message covers both cases (“Authentication or permission failure”) but I wonder if it isn’t worth it to split it into two different messages, according to what the failure really was, as SSH authentication and filesystem permissions seem two very different issues that need to be troubleshooted very differently.

Last but not least, this is my first post to the group so I’d like to take the chance to say thank you for Ansible, I really love it!

ciao
ste

Hi Stefano, I was unable to replicate what you’re seeing using your example:

$ ansible-playbook -v test_local_action.yml

PLAY [centos6] ****************************************************************

TASK: [do something] **********************************************************
ok: [192.168.X.X] => {“changed”: false, “ping”: “pong”}
ok: [192.168.X.X] => {“changed”: false, “ping”: “pong”}

TASK: [pause for 5 seconds] ***************************************************
(^C-c = continue early, ^C-a = abort)
[192.168.X.X, 192.168.X.X]
Pausing for 5 seconds

ok: [192.168.X.X] => {“changed”: false, “delta”: 5, “rc”: 0, “start”: “2013-09-16 09:02:59.732917”, “stderr”: “”, “stdout”: “Paused for 5.0 seconds”, “stop”: “2013-09-16 09:03:04.737408”}

PLAY RECAP ********************************************************************
192.168.X.X : ok=2 changed=0 unreachable=0 failed=0
192.168.X.X : ok=2 changed=0 unreachable=0 failed=0

When run with -vvv the pause step shows:

<127.0.0.1> EXEC [‘/bin/sh’, ‘-c’, ‘mkdir -p $HOME/.ansible/tmp/ansible-1379340376.95-6553239021328 && echo $HOME/.ansible/tmp/ansible-1379340376.95-6553239021328’]
created ‘pause’ ActionModule: pause_type=seconds, duration_unit=seconds, calculated_seconds=5, prompt=None

I tested this with both the current head of devel and the release1.3.0 branch.

Could you verify the version of ansible-playbook you’re running?

Hi James,

thanks for trying to replicate.

ansible-playbook --version tell’s me it’s 1.3.0

ciao
ste

Does your inventory contain an ansible_connection option? I believe there is (or was) an open issue regarding that overriding local_action’s connection type.

Good catch, I removed the ansible_connection option from my inventory and it then worked as expected, using sh -c instead of ssh.

Thank you very much,
ste

Did you have the ansible_connection option set on localhost? That is the only way I’m able to reproduce the issue above.

No, I had ansible_connection=ssh set on the “wheezy” machine in my inventory:

wheezy ansible_ssh_port=2222 ansible_connection=ssh

Changing it as follows solved the issue for me:

wheezy ansible_ssh_port=2222

ciao
ste