Escape characters in Ansible script - bash

I have an issue with a shell command in my Ansible script. This shell command doesn't work properly on the script, while it works great directly on the server.
Here is the problematic code:
- name: export keys
shell: "export NR_INSTALL_PATH=$(which php | sed 's/\/php$//g') ; export NR_INSTALL_KEY='somekey'; export NR_INSTALL_SILENT=1; newrelic-install install"
After I investigated the issue, I have noticed that the problematic part is:
which php | sed 's/\/php$//g'
This code suppose to get the executable path of PHP, and remove the last directory from the path. Instead of the expected result, i get only the first directory of the path (/bin).
Is that issue related to escape characters? Can someone tell me how to fix it?
Do I have more characters from the original command that I need to escape?
Is there a way to print the bash command that actually has been received by the server? (That's how I will be able to know what has been changed from the original command).

This syntax should work:
- name: export keys
shell: 'export NR_INSTALL_PATH=$(which php | sed "s/\/php$//g") ; export NR_INSTALL_KEY="somekey"; export NR_INSTALL_SILENT=1; newrelic-install install'
For example:
- set_fact:
php_path: /usr/bin/php
- shell: 'export NR_INSTALL_PATH=$(echo {{ php_path }} | sed "s/\/php$//g") ; echo $NR_INSTALL_PATH'
register: result
- debug: var=result.stdout
returns:
TASK [debug] *******************************************************************
ok: [localhost] => {
"result.stdout": "/usr/bin"
}
Is there a way to print the bash command that actually has been received by the server?
Not an Ansible way (because it is oblivious to how shell interprets the command), but you can run the shell with -x option enabled:
- command: /bin/bash -x -c 'export NR_INSTALL_PATH=$(echo {{ php_path }} | sed "s/\/php$//g") ; echo $NR_INSTALL_PATH'
register: result
- debug: var=result.err
And you will get a full trace in the log.
Notice: you asked about "bash", but it doesn't necessarily have to be bash - Ansible might run /bin/sh by default.

Related

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!

how to install the script interactive via ansible playbook

I can run the script with the command line argument on the linux server it works fine.
for e.g.: ./install.sh -n -I <IP address of the server>
The above command is able to install the script on the server.
When I am trying to do via ansible (version 2.5) playbook using the shell module it gives me an argument error.
- name: Running the script
shell: yes | ./fullinstall
Expect modules has been tried.
--my-arg1=IP address
- shell: "./install.sh -n -I"
args:
chdir: somedir/
creates: somelog.txt
You can look here for examples.
You can also place the install.sh file on the server as a template. Then you can set the variables as desired in Jinja2.
- name: Template install.sh
template:
src: /install.sh.j2
dest: /tmp/install.sh
- shell: "cd /tmp/ ; ./install.sh
Your install.sh.j2 contains:
IP adres: {{ my_ip }}
And set the variable on the command line with:
ansible-playbook -e my_ip="192.168.0.1"
Use command module
- name: run script
command: /path/to/install.sh -n -I {{ ip_addrress }}
playbook
ansible-playbook -e ip_address="192.168.3.9" play.yml
If you want to interactively wanted to enter the IP address, use prompt module.

Need syntax to work with both Ansible shell & command module

The below syntax works fine.
---
- hosts: all
tasks:
- name: run this command and ignore the result
shell: echo "The server is UP since " `uptime`
However when i change shell module to command module I was expecting this to still work.
command: echo "The server is UP since " `uptime`
But it does not print the uptime value with the command module.
Can I not have the same syntax to work with both the shell as well as the command module ?
Can I not have the same syntax to work with both the shell as well as the command module ?
Yes, of course, by just manually doing the job that shell: is going to do and wrapping the string in sh -c
- set_fact:
the_command: sh -c 'echo "The server is UP since `uptime`"'
- command: '{{ the_command }}'
- shell: '{{ the_command }}'

Using ssh-keyscan in shell module does not produce any output in Ansible

I'm trying to follow this solution to add use the shell module and ssh-keyscan to add a key to my known_hosts file of a newly created EC2 instance.
After trying to do this multiple ways as listed on that question I eventually ran just the ssh-keyscan command using the shell module without the append. I am getting no output from this task:
- name: accept new ssh fingerprints
shell: ssh-keyscan -H {{ item.public_ip }}
args:
executable: /bin/bash
with_items: "{{ ec2.instances }}"
register: keyscan
- debug: var=keyscan
Debug here shows nothing in stdout and stdout_lines and nothing in stderr and stderr_lines
Note: I tried running this with the bash as the executable shown after reading that the shell module defaults to /bin/sh which is the dash shell on my Linux Mint VirtualBox. But it's the same regardless.
I have tested the shell command with the following task and I see the proper output in stdout and stdout_lines:
- name: test the shell
shell: echo hello
args:
executable: /bin/bash
register: hello
- debug: var=hello
What is going on here? Running ssh-keyscan in a terminal (not through Ansible) works as expected.
EDIT: Looking at the raw_params output from debug shows ssh-keyscan -H x.x.x.x and copying and pasting this into the terminal works as expected.
The answer is that it doesn't work the first time. While researching another method I stumbled across the retries keyword in ansible that allows a retry of whatever command. I tried this and on attempt number 2 in the retry loop it is working.

Setting an environment variable in Ansible from a command output of bash command

I would like to set output of a shell command as an environment variable in Ansible.
I did the following to achieve it:
- name: Copy content of config.json into variable
shell: /bin/bash -l -c "cat /storage/config.json"
register: copy_config
tags: something
- name: set config
shell: "echo $TEMP_CONFIG"
environment:
TEMP_CONFIG: "{{copy_config}}"
tags: something
But somehow after the ansible run, when I do run the following command:
echo ${TEMP_CONFIG}
in my terminal it gives an empty result.
Any help would be appreciated.
There are at least two problems:
You should pass copy_config.stdout as a variable
- name: set config
shell: "echo $TEMP_CONFIG"
environment:
TEMP_CONFIG: "{{copy_config.stdout}}"
tags: something
You need to register the results of the above task and then again print the stdout, so:
- name: set config
shell: "echo $TEMP_CONFIG"
environment:
TEMP_CONFIG: "{{copy_config.stdout}}"
tags: something
register: shell_echo
- debug:
var: shell_echo.stdout
You never will be able to pass the variable to a non-related process this way. So unless you registered the results in an rc-file (like ~/.bash_profile which is sourced on interactive login if you use Bash) no other shell process would be able to see the value of TEMP_CONFIG. This is how system works.

Resources