shell module: Bash <(process substitution) with ansible - shell

I want to run a command:
- name: install pip
shell: "python <(curl https://bootstrap.pypa.io/get-pip.py)"
But achieve an error
failed: [default] => {"changed": true, "cmd": "python <(curl https://bootstrap.pypa.io/get-pip.py)", "delta": "0:00:00.002073", "end": "2014-12-03 15:52:01.780837", "rc": 2, "start": "2014-12-03 15:52:01.778764", "warnings": []}
stderr: /bin/sh: 1: Syntax error: "(" unexpected
I tried to change it to something like:
python <$(curl https://bootstrap.pypa.io/get-pip.py)
but it doesn't work. Any thoughts?
NB: this question about using < operator in shell module and I know that better to use apt for install something

Use command module if you actually do not need shell.
Also you will be better off using get_url module for downloading the file instead of relying on curl being installed on remote server.
Recent versions of Ansible will display a warning when you try to use curl instead of get_url module also:
"warnings": ["Consider using get_url module rather than running curl"]
Here is how I would do this:
- name: Download pip installer
get_url:
url=https://bootstrap.pypa.io/get-pip.py
dest=/tmp/get-pip.py
mode=0440
- name: Install pip
command: /usr/bin/python /tmp/get-pip.py
For extra options to get_url module visit: http://docs.ansible.com/get_url_module.html

EDIT: though this answers this the question I think mgsk's answer is a better answer since I agree that it's not the right way to go about it with Ansible.
This should fix your issue:
- name: install pip
shell: "python <(curl https://bootstrap.pypa.io/get-pip.py)" executable=/bin/bash
If you are wondering the difference between these two commands:
python <(curl https://bootstrap.pypa.io/get-pip.py)
python <$(curl https://bootstrap.pypa.io/get-pip.py)
The first one uses process substitution which is a bash feature which is why you cannot use it with /bin/sh as your shell. What it's doing is taking the output of the curl command (which is a python script), writing it to a temporary file and using that file as an argument to python which takes a python script as its first argument.
The second one is an ambiguous redirect because the python script that is generated from the curl is not a file

- name: configure zookeeper /etc/zookeeper/conf/zoo.cfg
shell: "{{ item }}"
with_items:
if [ -f /etc/zookeeper/conf/zoo_cfg.org ] ;
then cp /etc/zookeeper/conf/zoo_cfg.org /etc/zookeeper/conf/zoo.cfg ;
else cp /etc/zookeeper/conf/zoo.cfg /etc/zookeeper/conf/zoo_cfg.org;
fi;
cat /vagrant/zoo.cfg.j2 >> /etc/zookeeper/conf/zoo.cfg;

Related

Change current directory and stay there [duplicate]

- name: Go to the folder
command: chdir=/opt/tools/temp
When I run my playbook, I get:
TASK: [Go to the folder] *****************************
failed: [host] => {"failed": true, "rc": 256}
msg: no command given
Any help is much appreciated.
There's no concept of current directory in Ansible. You can specify current directory for specific task, like you did in your playbook. The only missing part was the actual command to execute. Try this:
- name: Go to the folder and execute command
command: chdir=/opt/tools/temp ls
This question was in the results for when I was trying to figure out why 'shell' was not respecting my chdir entries when I had to revert to Ansible 1.9. So I will be posting my solution.
I had
- name: task name
shell:
cmd: touch foobar
creates: foobar
chdir: /usr/lib/foobar
It worked with Ansible > 2, but for 1.9 I had to change it to.
- name: task name
shell: touch foobar
args:
creates: foobar
chdir: /usr/lib/foobar
Just wanted to share.
If you need a login console (like for bundler), then you have to do the command like this.
command: bash -lc "cd /path/to/folder && bundle install"
You can change into a directory before running a command with ansible with chdir.
Here's an example I just setup:
- name: Run a pipenv install
environment:
LANG: "en_GB.UTF-8"
command: "pipenv install --dev"
args:
chdir: "{{ dir }}/proj"

Ansible playbook complains about quotes

I'm using Ubuntu 16 with Ansible 2.2.1.0.
I am trying to install docker-compose with the following playbook:
- name: Install Docker Compose.
shell: "curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose"
file:
dest=/usr/local/bin/docker-compose mode=x
src=/usr/local/bin/docker-compose dest=/usr/bin/docker-compose state=link
I get this error:
- name: Install Docker Compose.
shell: "curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose"
^ here
This one looks easy to fix. It seems that there is a value started
with a quote, and the YAML parser is expecting to see the line ended
with the same kind of quote. For instance:
when: "ok" in result.stdout
Could be written as:
when: '"ok" in result.stdout'
What is the problem? I have starting and ending quotes.
shell module hasn't file parameter and shell and name should be on same column that why you got the error and also use a double quote for URL and not full shell command:
- name: Install Docker Compose.
shell: curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose"
You can use the get_url module to download the file to the destination and set permission. And I highly recommend using Ansible role that presented by contributors on the ansible galaxy and not to reinvited wheels!

Ansible sudo command without password checking

I would like to use ansible in a full automated context, where I cannot manually type passwords. To deal with this, I connect the servers with SSH public key, and I whitelisted severals commands such as apt-get install * in my sudoers configuration so I do not need a password to run them. For instance sudo apt-get install git.
However if the setting become is True in a playbook, ansible asks me for a password it does not need.
How can I tell ansible to run a command as sudo, without asking me a password?
Do you know another way to install apt packages without password?
Should I use another become method?
sudoers conf
myuser ALL = NOPASSWD: /usr/bin/apt-get install *
ansible
- name: install the latest version of ntpdate
package:
name: ntpdate
state: latest
become: True
Produces this output:
failed: [x.x.x.x] (item=ntpdate) => {"failed": true, "item": "python3-dev", "module_stderr": "", "module_stdout": "sudo: a password is required\r\n", "msg": "MODULE FAILURE", "rc": 1}
The simple answer is that you cannot do it without enabling all commands (or at least python).
Ansible does not run the commands as you expect it to run. It runs Python scripts. You can see the exact command when you execute ansible-playbook with -vvv. They are much more complex and to enable them you would have to add them to sudoers, for example:
sudo -H -S -n -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-xxxxxx;
/usr/bin/python /var/www/.ansible/tmp/ansible-tmp-xxxxxxxx/apt.py;
rm -rf "/var/www/.ansible/tmp/ansible-tmp-xxxxxxxx/" > /dev/null 2>&1'"'"'
&& sleep 0
The tricky part is that all spaces, quotes, and other special characters are relevant and until you get the correct command pattern by trial and error, replacing characters with wildcards, the system will not allow the command to run with elevated privileges. Effectively you won't be able to whitelist all the commands Ansible runs.
The only exception is raw module which runs the given command intact.
In all the Ansible playbooks I have worked on, I had to do only 2 things so that tasks run with become:True
Create file /etc/sudoers.d/demo on the target hosts with below content:
demo ALL=(ALL) NOPASSWD:ALL
Copy ssh id from Ansible host to target host using ssh-copy-id
template/without_sudo
%sudo ALL=(ALL) NOPASSWD: ALL
%sudo ALL=(ALL) NOPASSWD: /sbin/poweroff, /sbin/reboot, /sbin/shutdown
tasks/main.yml
- name: Sudoers no password
raw: echo '{{ user_password }}' | sudo -S sh -c 'echo "{{ lookup('file', 'templates/without_sudo') }}" > /etc/sudoers.d/without_sudo'
no sudo for the rest of the ansible command
You can use the ansible 'command' module with sudo as part of the command, instead of 'become: yes'
- name: install the latest version of ntpdate
command: 'sudo apt-get update ntpdate'
The downside is that this is much less portable. The upside is, it works... and you only need to whitelist the specific command.
in my opinion, if you set your node with =(ALL) NOPASSWD:ALL. then anybody: including the hackers can access your nodes.
so what I can suggest ,
ansible-playbook <name>.yml --ask-sudo-pass
this will ask your node sudo password. and u can execute ur operation, as I guess you know ur node's credential.

Run several commands with Ansible

I am using ansible 1.9 and want to run two commands. I have tried several variations:
- name: npm build
command: npm run build
args:
chdir: "{{ app_dir }}"
- name: clean up
shell: sed_index.sh
args:
chdir: "{{ app_dir }}"
On running I get the following error:
"stderr": "/bin/sh: 1: npm: not found"
However
npm run build
works fine when I log in to the server and run it in the app_dir.
I also tried:
- name: npm install and clean
command: "{{ item }} chdir={{ app_dir }}"
with_items:
- npm run build
- sed_index.sh
Again I get a npm not found error.
If I comment out the npm run build command I get an error when running the sed_index script on the 'cd dist' command below, saying 'dist' not found.
sed_index.sh
#!/usr/bin/env bash
cd dist
sed -i 's|=static/css/font-awesome.min.css rel=stylesheet>|=/app/static/css/font-awesome.min.css rel=stylesheet>|g' index.html
Any ideas?
The npm executable is probably not in a standard location like /usr/bin/npm. Probably /usr/local/bin/npm, but it's up to you to find where it's installed and use the fully qualified path. From a login that can run the npm command, execute 'which npm'. The output will be what you want to use instead of just npm.
FYI - When I'm doing a one-off or other small task that I don't want to take the time to write a playbook for, if it's not an easy one liner in Ansible I write a small script to execute via the script module. One of the first commands in those scripts is to set the PATH if I know some of the commands are in non-standard locations.
Use full path to the npm executable. Ansible runs commands in non-interactive shell session and your environment set in rc files is not read.
Regarding the second problem: if you get a "'dist' not found" error, it means either dist directory does not exist, or you call it from a wrong directory. It's impossible to tell given the information you provided.
#techraf answer should help you to solve this issue.
For some reason if you look for an alternate way, give a try like below with ansible command:
ansible -m shell -a "/bin/bash -c 'cd {{app_dir}} && npm run build && ./sed_index.sh'" -e "app_dir=/path/to/app_dir" <host/group name>
You should be able to convert it back to your playbook once you get it running.

Ansible: How to change active directory in Ansible Playbook?

- name: Go to the folder
command: chdir=/opt/tools/temp
When I run my playbook, I get:
TASK: [Go to the folder] *****************************
failed: [host] => {"failed": true, "rc": 256}
msg: no command given
Any help is much appreciated.
There's no concept of current directory in Ansible. You can specify current directory for specific task, like you did in your playbook. The only missing part was the actual command to execute. Try this:
- name: Go to the folder and execute command
command: chdir=/opt/tools/temp ls
This question was in the results for when I was trying to figure out why 'shell' was not respecting my chdir entries when I had to revert to Ansible 1.9. So I will be posting my solution.
I had
- name: task name
shell:
cmd: touch foobar
creates: foobar
chdir: /usr/lib/foobar
It worked with Ansible > 2, but for 1.9 I had to change it to.
- name: task name
shell: touch foobar
args:
creates: foobar
chdir: /usr/lib/foobar
Just wanted to share.
If you need a login console (like for bundler), then you have to do the command like this.
command: bash -lc "cd /path/to/folder && bundle install"
You can change into a directory before running a command with ansible with chdir.
Here's an example I just setup:
- name: Run a pipenv install
environment:
LANG: "en_GB.UTF-8"
command: "pipenv install --dev"
args:
chdir: "{{ dir }}/proj"

Resources