Mac provisioning: running PlistBuddy or sqlite3 from a playbook doesn't work

I’m writing a Mac setup playbook and am borrowing heavily from various “dotfiles” around the web to help with configuring certain aspects of OS X.

Here’s my current dotfile which is effectively just a bash script:

https://bitbucket.org/dbohea/mac-setup-playbook/src/0b4d30a3e44a16462d94808c66e15eba0aa44f7d/osx.sh?at=master

This runs just fine directly from the command line. Oddly, when run from an Ansible playbook, none of the PlistBuddy or sqlite3 commands seem to work.

Anyone know why this may be or what I can do to fix it?

PS - Before anyone suggests it, it’s nothing to do with the if statement at the end of the file - I’ve tested this.

It’s probable something to do with the PATH in your bash environment. When you login interactively, the .profile rc file gets run and normally sets up the PATH. I would imagine that when you login via ansible you don’t have the directory for PlistBuddy or sqlite3 in your PATH so those commands fail.

You can either fiddle with your ssh_args in the ansible config files to tell ssh to make the shell a login shell, or you can just put the full path to Sqlite3 and PlistBuddy on those lines of your .bashrc file.

Thanks Mark - I’ll take a closer look at that and post my findings back here.

Thanks to some advice from elsewhere, I did try to run “shell: which sqlite3” from within my playbook and then compared the output to what I receive when I run “which sqlite3” in the command line. The results are the same.

If there was a PATH issue with Ansible trying to run sqlite3, wouldn’t the above test fail (i.e. output from each command wouldn’t match)?

Yes, if the which command found the binary from within ansible, then it should find it when running the script via ansible. That seems pretty odd that it doesn’t. I know that the script asks for the sudo password so you can run it locally, but does it run via sudo when run by ansible? If so then it would be using root’s path and not yours.

Can I see the playbook line in question.

Many things don’t trust the system path, but most of them do. The command module is one of those things.

Though if you need explicit environment variable control, take a look here:

http://docs.ansible.com/playbooks_environment.html

Sure, the role that attempts to run the bash script is here:

https://bitbucket.org/dbohea/mac-setup-playbook/src/414cda3c20b9e20d82c34a2776d0d0c34b6c5d97/roles/osx/tasks/main.yml?at=master

Ok so from your playbook:

  • name: Execute .osx
  # TODO: doesn't run commands that use PlistBuddy or sqlite3
  shell: ./osx.sh --ansible
  notify: killall

Inside osx.sh are PlistBuddy and sqlite3 absolute-pathed?  I assume they are not.  I suspect they are in a path defined in your local environment, and won't be in the path for ansible, because of the way we enforce centralized and reliable configurations - not trusting 500 servers who might all have different .bashrcs, etc, we don't log in with interactive shells.

You'll want to read this section:

[http://docs.ansible.com/playbooks_environment.html](http://docs.ansible.com/playbooks_environment.html)


Then:

Thanks for looking.

PlistBuddy is called with an absolute path in osx.sh (see lines 198-205 for example):

https://bitbucket.org/dbohea/mac-setup-playbook/src/0b4d30a3e44a16462d94808c66e15eba0aa44f7d/osx.sh?at=master

I added the following but it doesn’t seem tt make a difference (sqlite3 doesn’t seem to get run):

`

  • name: Execute .osx

TODO: doesn’t run commands that use PlistBuddy or sqlite3

shell: ./osx.sh --ansible
notify: killall
environment:
PATH: “/usr/bin:/usr/bin/sqlite3/bin”
`

I also tried the following but still no dice:

PATH: "/usr/bin:/usr/bin/sqlite3"

If it’s absolutely pathed that shouldn’t matter and shouldn’t be an ansible thing.

When you say it’s not being run, perhaps this is an issue with your shell script.

Ansible will tell you if the script failed and returned a non-zero status, of course, and can include output from the script if you want to add some debug.

However, if plist buddy does call sqlite and sqlite is in a different path (I don’t know ANYTHING about plistbuddy) you would still need to set the path stuff.

The script runs as expected when run directly from the command line. Admittedly, I’ve copied and tweaked the script - it wasn’t written to be run from Ansible.

I know nothing about plistbuddy either :slight_smile: but it and sqlite3 are being called by different parts of the shell script - I don’t think they’re calling each other.

I’m gonna put this on the shelf and fallback to running this script after the playbook, directly from the command line. Not really the Ansible way I know but I can’t spend any more time on it right now.

Thanks for all your help. If you get any bright ideas, please post them!

Please try the path thing first, if sqlite is not at the default paths but is something configured in the user environment, that would explain why the shell script and plist buddy couldn’t find it.

I appreciate your persistence Michael :slight_smile: Thanks for all your help so far.

I did try the path thing (a few comments up where I quoted some code snippets) but it didn’t seem to make any difference. The locations that I added to PATH could have been incorrect of course - I based them on what was returned from running the following:

which sqlite3

This returns:

`
/usr/bin/sqlite3

`

If I run “echo $PATH” from within my playbook I get:

`

/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

`

As you can see, “usr/bin” is in there.

Am I missing something obvious here? I’m not a sys-admin as I’m sure you can tell. Do I need to add that massive PATH above via Ansible’s environment module?

Yeah since it’s in /usr/bin that is most definitely NOT a path thing.

I’m not sure what the failure mode here was, possibly the script died when it saw a shell wasn’t interactive?

OK, good to rule the PATH out then.

Not sure what you mean by failure mode but here’s the -vvvv output for the task that tries to run the script in case that helps. As you can see, “stderr” and “stdout” don’t seem to have anything to say.

`

TASK: [osx | Execute .osx] ****************************************************

<127.0.0.1> REMOTE_MODULE command ./osx.sh --ansible #USE_SHELL

<127.0.0.1> EXEC [‘/bin/sh’, ‘-c’, ‘mkdir -p $HOME/.ansible/tmp/ansible-tmp-1408559599.6-238488648926013 && chmod a+rx $HOME/.ansible/tmp/ansible-tmp-1408559599.6-238488648926013 && echo $HOME/.ansible/tmp/ansible-tmp-1408559599.6-238488648926013’]

<127.0.0.1> PUT /var/folders/5d/ry1gfqbx0rs8bmpy7lw0909w0000gn/T/tmpjDc9QL TO /Users/danbohea/.ansible/tmp/ansible-tmp-1408559599.6-238488648926013/command

<127.0.0.1> EXEC [‘/bin/sh’, ‘-c’, u’LANG=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 /usr/bin/python /Users/danbohea/.ansible/tmp/ansible-tmp-1408559599.6-238488648926013/command; rm -rf /Users/danbohea/.ansible/tmp/ansible-tmp-1408559599.6-238488648926013/ >/dev/null 2>&1’]

changed: [127.0.0.1] => {“changed”: true, “cmd”: “./osx.sh --ansible”, “delta”: “0:00:01.105129”, “end”: “2014-08-20 11:33:20.811287”, “rc”: 0, “start”: “2014-08-20 11:33:19.706158”, “stderr”: “”, “stdout”: “”}

`

I mean this by “the way in which something fails”.

Yeah, I have no idea here.

Your script returned a non-zero exit code and no output, which is all ansible knows. It would depend on the behavior of the script. And that script may not have proper error handling to say why what was called in that script died.

I’d start by adding extra output to your script, etc.

OK, I’ll do some more poking & prodding and see what I can turn up. Thanks again.

Cracked it! It absolutely was down to errors in the script that I was just missing: one I’d inherited from where I’d copied it from (the sqlite3 command) and another of my own doing that was attempting to change a property in a file that didn’t exist yet.

Thank you sooooooo much for all your help and for pushing me to see this through proper style :smiley:

This playbook is gonna rock hard!

UPDATE: running either works just fine.