Nick,
Thanks very much for your reply and thoughts. This has helped tremendously (and will help as I write the rest of these playbooks). Alright… here goes:
Source is normally a shell-builtin, not an actual executable. As
you’re calling the command module rather than the shell module, it
doesn’t run an actual shell and so it can’t find an executable called
‘source’. That likely explains the error you are seeing, and using
‘shell’ rather than ‘command’ will likely solve that.
Thanks for this. The thought hadn’t even occurred to me that command vs shell would’ve been a way to fix it or that command wouldn’t recognize source. As Gru says, “liiiight buuulb!” I changed the module to shell quickly and it looks like that definitely got it working instantly for that particular command.
That said, 1) I don’t believe Ansible runs two consecutive shell tasks
in the same shell anyway, and 2) it uses /bin/sh rather than the
user’s default shell, making the point moot.
As to point 1 I actually had this exact thought as I was laying my head down on the pillow last night and realized I may be trying to solve a task that doesn’t even need to exist as all subsequent commands would probably already have sourced the newly updated ~/.bashrc when ansible connects to issue the next command. Do we know for a fact that this is how it occurs? What about in “fireball” mode? Does that still reconnect for each subsequent task? Trying to figure out if my playbook will be properly usable in all modes that Ansible could be run in.
As to point 2 this could give extra emphasis as to your point you made later. I was quasi-expecting Ansible to use the non-login shell (e.g. the user that’s sudoed into would have their ~/.bashrc loaded before executing commands) and that’s why I thought to put these variables here for Ansible (primarily just due to Linux/Unix defaults). I’ll get into why they go here in my particular situation next.
The above issues of making it work aside, relying on the user’s bashrc
sounds very brittle. What if he/she decides to start using another
shell in the future (such as zsh for example)?
Okay, so to put this all in perspective… I’m using Ansible to automatically provision / setup servers that have very restrictive access controls. Once I login as a non-privileged user with my SSH key I’m then able to sudo into only two other users. One is meant to install libraries / tools from source, the other to deploy the application. This is a pretty common Enterprise / restrictive setup in my experience. As a result I have learned to very strongly love GNU Stow which allows me to basically have my own /opt dir in my home folder and handles symlinking active tools / packages / libraries and all their differing subfolders, etc. into a target directory (one folder above the path where you stow things by default). Rather than having to ensure that everyone remembers the stow path properly (there’s a few of us and we’re all human after all) I’ve taken to setting a $STOW environment variable that’s loaded in the .bashrc so that we can ensure that we always use the same directory. We also want to use all the programs we’ve stowed away like pack rats so I’ve gotten used to prepending PATH with $STOW/…/bin so that we have access to git, tmux, vim, python, ruby, node, bzip2, etc., etc. all compiled from source. This way we don’t have to prepend / remember the stow directory and we don’t have to invoke git with: $ stow_path/…/bin/git, we can just simply call $ git and get the proper version.
Now… as to why .bashrc. I touched on this lightly above, but basically I need to have somewhere for these global environment variables to be set, and to my knowledge the best place for that in Linux / Unix has always been the .bashrc file. Granted, if a user somehow installs (from source in my situation) zshell or another alternative then they don’t get these variables, but keep in mind I’m 9/10 times using this to provision staging and production boxes where users shouldn’t be customizing things to their desired intent. My goal is to use Ansible to get rid of those customizations on those boxes and have a reliably consistent environment. I don’t think I’ve ever used a production box with something besides the default bash shell running and so .bashrc has always been the best solution. I would love to level up and be taught how to do this properly / differently if that isn’t correct (just so I don’t come off defensive, trying to explain my thought process, not seem stubborn as I’m 100% open to change if I’m doing it wrong).
Is there a specific reason you can’t just set any necessary environment
variables in your playbook, and/or call programs by their full path instead
of relying on $PATH?
So… the problem with putting these variables into my playbook instead of directly into $PATH is that we do our deployments using Capistrano (I’ve used it for 5 years and couldn’t be happier and have no desire to use a provisioning tool for something as simple as deployments). In turn this means that any environment variables set in Ansible playbooks won’t be accessible to my deployment environments. It also means that I’d either have to rewrite everything to deploy with Ansible (which isn’t the community best practice in Ruby world, even to use Chef or Puppet wouldn’t be ideal for the vast majority of teams) or it means I’ll have to duplicate variables in my playbook environment variables and then again somewhere in my tasks to setup those variables for the user when they login. I was expecting Ansible to load a user’s .bashrc for commands given that I’m logging in specifically to that user’s account with the sudo_user & sudo variables in my playbook; however, I can see why Ansible wouldn’t do that (especially if a user has a different shell potentially rather than bash which Ansible seems to have an expectation for as well).
So that leads to yet another question… Is there a best practice to be able to get Ansible tasks to load my .bashrc if I’m sure it’ll be there before running the shell module or am I likely to have to always do the following?
shell: source {{HOME.stdout}}/.bashrc;
The next question is, is there an alternative approach to storing environment variables / modified $PATH without having to use the .bashrc but that would still be accessible for a user actually logged into the box from a remote terminal? I’ve been playing with server setup / maintenance as a side-duty of all my jobs for about a decade and haven’t come across any, but it’s also not my full-time $dayjob and I’m not an expert by any means. I’d love to hear suggestions or tips from others as to a better approach than putting $STOW and $PATH modifications / exports in the .bashrc of the sysadmin user.
Thanks so much for all of your help and time,
Steven