不可能的来源。巴希尔与安塞尔

我可以 ssh 到远程主机并做一个 source /home/username/.bashrc-一切工作正常。 然而,如果我这样做:

- name: source bashrc
sudo: no
action: command source /home/username/.bashrc

我得到了:

failed: [hostname] => {"cmd": ["source", "/home/username/.bashrc"], "failed": true, "rc": 2}
msg: [Errno 2] No such file or directory

我不知道我做错了什么..。

84633 次浏览

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.

You have two options to use source with ansible. One is with the "shell:" command and /bin/sh (the ansible default). "source" is called "." in /bin/sh. So your command would be:

- name: source bashrc
sudo: no
shell: . /home/username/.bashrc && [the actual command you want run]

Note you have to run a command after sourcing .bashrc b/c 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
sudo: no
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.

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.

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'

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

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

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.

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.

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

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