Reputation: 1727
I can SSH to the remote host and do a source /home/username/.bashrc
— everything works fine.
However if I do:
- name: source bashrc
action: command source /home/username/.bashrc
I get:
failed: [hostname] => {"cmd": ["source", "/home/username/.bashrc"], "failed": true, "rc": 2}
msg: [Errno 2] No such file or directory
I have no idea what I'm doing wrong.
Upvotes: 108
Views: 102702
Reputation: 2334
You have two options to use source with Ansible. One is with the shell
module and /bin/sh
(the default in Ansible).
source
is called .
in /bin/sh
.
So, your command would be:
- name: source bashrc
shell: . /home/username/.bashrc && [the actual command you want run]
Note you have to run a command after sourcing .bashrc
because each SSH session is distinct — every Ansible command runs in a separate SSH transaction.
Your second option is to force Ansible shell to use bash and, then, you can use the source
command:
- name: source bashrc
shell: source /home/username/.bashrc && [the actual command you want run]
args:
executable: /bin/bash
Finally, I'll note that you may want to actually source /etc/profile
if you're on Ubuntu or similar, which more completely simulates a local login.
Upvotes: 115
Reputation: 700
I found become as best solution:
- name: Source .bashrc
shell: . .bashrc
become: true
You can change the user by adding (default: root):
- name: Source .bashrc
shell: . .bashrc
become: true
become-user: {your_remote_user}
More info here: Ansible become
Upvotes: 2
Reputation: 1216
Many responses recommend to source ~/.bashrc but main problem is that ansible shell is not interactive and ~/.bashrc implementation by default ignores non interactive shell (check its beginning).
The best solution for executing commands as user after its ssh interactive login I found is:
- hosts: all
tasks:
- name: source user profile file
#become: yes
#become_user: my_user # in case you want to become different user (make sure acl package is installed)
shell: bash -ilc 'which python' # example command which prints
register: which_python
- debug:
var: which_python
bash: '-i' means interactive shell, so .bashrc won't be ignored '-l' means login shell which sources full user profile
Upvotes: 11
Reputation: 25637
My 2 cents, i circumnavigated the problem sourcing ~/.nvm/nvm.sh
into ~/.profile
and then using sudo -iu
as suggested in another answer.
Tried on January 2018 vs Ubuntu 16.04.5
- name: Installing Nvm
shell: >
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
args:
creates: "/home/{{ ansible_user }}/.nvm/nvm.sh"
tags:
- nodejs
- name: Source nvm in ~/.profile
sudo: yes
sudo_user: "{{ ansible_user }}"
lineinfile: >
dest=~/.profile
line="source ~/.nvm/nvm.sh"
create=yes
tags:
- nodejs
register: output
- name: Installing node
command: sudo -iu {{ ansible_user }} nvm install --lts
args:
executable: /bin/bash
tags:
- nodejs
Upvotes: 1
Reputation: 61521
So command
will only run executables. source
per se is not an executable. (It's a builtin shell command).
Is there any reason why you want to source
a full environment variable?
There are other ways to include environment variables in Ansible. For example, the environment
directive:
- name: My Great Playbook
hosts: all
tasks:
- name: Run my command
sudo: no
action: command <your-command>
environment:
HOME: /home/myhome
Another way is to use the shell
Ansible module:
- name: source bashrc
sudo: no
action: shell source /home/username/.bashrc && <your-command>
or
- name: source bashrc
sudo: no
shell: source /home/username/.bashrc && <your-command>
In these cases, the shell instance/environment will terminate once the Ansible step is run.
Upvotes: 25
Reputation: 7828
I've tried all the options above with ansible 2.4.1.0 and no one works until another two and here is the detail to re-produce the case.
$ cat ~/.bash_aliases
alias ta="echo 'this is test for ansible interactive shell'";
And this is the ansible test:
- name: Check the basic string operations
hosts: 127.0.0.1
connection: local
tasks:
- name: Test Interactive Bash Failure
shell: ta
ignore_errors: True
- name: Test Interactive Bash Using Source
shell: source ~/.bash_aliases && ta
args:
executable: /bin/bash
ignore_errors: yes
- name: Test Interactive Bash Using .
shell: . ~/.bash_aliases && ta
ignore_errors: yes
- name: Test Interactive Bash Using /bin/bash -ci
shell: /bin/bash -ic 'ta'
register: result
ignore_errors: yes
- debug: msg="{{ result }}"
- name: Test Interactive Bash Using sudo -ui
shell: sudo -ui hearen ta
register: result
ignore_errors: yes
- name: Test Interactive Bash Using ssh -tt localhost /bin/bash -ci
shell: ssh -tt localhost /bin/bash -ci 'ta'
register: result
ignore_errors: yes
And this is the result:
$ ansible-playbook testInteractiveBash.yml
[WARNING]: Could not match supplied host pattern, ignoring: all
[WARNING]: provided hosts list is empty, only localhost is available
PLAY [Check the basic string operations] ************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************************
ok: [127.0.0.1]
TASK [Test Interactive Bash Failure] ****************************************************************************************************************************************************
fatal: [127.0.0.1]: FAILED! => {"changed": true, "cmd": "ta", "delta": "0:00:00.001341", "end": "2018-10-31 10:11:39.485897", "failed": true, "msg": "non-zero return code", "rc": 127, "start": "2018-10-31 10:11:39.484556", "stderr": "/bin/sh: 1: ta: not found", "stderr_lines": ["/bin/sh: 1: ta: not found"], "stdout": "", "stdout_lines": []}
...ignoring
TASK [Test Interactive Bash Using Source] ***********************************************************************************************************************************************
fatal: [127.0.0.1]: FAILED! => {"changed": true, "cmd": "source ~/.bash_aliases && ta", "delta": "0:00:00.002769", "end": "2018-10-31 10:11:39.588352", "failed": true, "msg": "non-zero return code", "rc": 127, "start": "2018-10-31 10:11:39.585583", "stderr": "/bin/bash: ta: command not found", "stderr_lines": ["/bin/bash: ta: command not found"], "stdout": "", "stdout_lines": []}
...ignoring
TASK [Test Interactive Bash Using .] ****************************************************************************************************************************************************
fatal: [127.0.0.1]: FAILED! => {"changed": true, "cmd": ". ~/.bash_aliases && ta", "delta": "0:00:00.001425", "end": "2018-10-31 10:11:39.682609", "failed": true, "msg": "non-zero return code", "rc": 127, "start": "2018-10-31 10:11:39.681184", "stderr": "/bin/sh: 1: ta: not found", "stderr_lines": ["/bin/sh: 1: ta: not found"], "stdout": "", "stdout_lines": []}
...ignoring
TASK [Test Interactive Bash Using /bin/bash -ci] ****************************************************************************************************************************************
changed: [127.0.0.1]
TASK [debug] ****************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"msg": {
"changed": true,
"cmd": "/bin/bash -ic 'ta'",
"delta": "0:00:00.414534",
"end": "2018-10-31 10:11:40.189365",
"failed": false,
"rc": 0,
"start": "2018-10-31 10:11:39.774831",
"stderr": "",
"stderr_lines": [],
"stdout": "this is test for ansible interactive shell",
"stdout_lines": [
"this is test for ansible interactive shell"
]
}
}
TASK [Test Interactive Bash Using sudo -ui] *********************************************************************************************************************************************
[WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running sudo
fatal: [127.0.0.1]: FAILED! => {"changed": true, "cmd": "sudo -ui hearen ta", "delta": "0:00:00.007906", "end": "2018-10-31 10:11:40.306128", "failed": true, "msg": "non-zero return code", "rc": 1, "start": "2018-10-31 10:11:40.298222", "stderr": "sudo: unknown user: i\nsudo: unable to initialize policy plugin", "stderr_lines": ["sudo: unknown user: i", "sudo: unable to initialize policy plugin"], "stdout": "", "stdout_lines": []}
...ignoring
TASK [Test Interactive Bash Using ssh -tt localhost /bin/bash -ci] **********************************************************************************************************************
hearen@localhost's password:
changed: [127.0.0.1]
PLAY RECAP ******************************************************************************************************************************************************************************
127.0.0.1 : ok=8 changed=6 unreachable=0 failed=0
There are two options worked:
shell: /bin/bash -ic 'ta'
shell: ssh -tt localhost /bin/bash -ci 'ta'
but this one requires password input locally.Upvotes: 6
Reputation: 151
I was experiencing this same issue when trying to get virtualenvwrapper to work on an Ubuntu server. I was using Ansible like this:
- name: Make virtual environment
shell: source /home/username/.bashrc && makevirtualenv virenvname
args:
executable: /bin/bash
but the source command was not working.
Eventually I discovered that the .bashrc file has a few lines at the top of the file that prevent source from working when called by Ansible:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
I commented out those lines in .bashrc and everything worked as expected after that.
Upvotes: 12
Reputation: 105
The right way should be:
- hosts: all
tasks:
- name: source bashrc file
shell: "{{ item }}"
with_items:
- source ~/.bashrc
- your other command
Note: it's test in ansible 2.0.2
version
Upvotes: -3
Reputation: 5742
Well I tried the listed answers but those didn't worked for me while installing ruby through rbenv. I had to source below lines from /root/.bash_profile
PATH=$PATH:$HOME/bin:$HOME/.rbenv/bin:$HOME/.rbenv/plugins/ruby-build/bin
export PATH
eval "$(rbenv init -)"
Finally, I came up with this
- shell: sudo su - root -c 'rbenv install -v {{ ruby_version }}'
One can use this with any command.
- shell: sudo su - root -c 'your command'
Upvotes: 3
Reputation: 508
I know this answer come too late but I have seen in enough code you can use the sudo option -i
so:
- name: source bashrc
shell: sudo -iu {{ansible_user_id}} [the actual command you want run]
As said in the documentation
The -i (simulate initial login) option runs the shell specified by the password database entry of the target user as a login shell. This means that login-specific
resource files such as .profile or .login will be read by the shell. If a command is specified, it is passed to the shell for execution via the shell's -c option.
If no command is specified, an interactive shell is executed. sudo attempts to change to that user's home directory before running the shell. It also initializes
the environment to a minimal set of variables, similar to what is present when a user logs in. The Command environment section below documents in detail how the -i
option affects the environment in which a command is run.
Upvotes: 21