Multi-line command in ansible-console - ansible

How to enter multi-line command in ansible-console, an Ansible REPL? I'm looking for something like \ at the end of the line in bash.
Regular writing from a playbook
- debug:
msg: "hello"
can be transformed to single line form
$ debug msg='hello'
However is there a way to execute
- debug:
msg: 'hello'
register: result
in ansible-console?

Ansible ad hoc commands are for specific use cases, so ansible-console as well. Therefore such things like registering variables aren't possible.
Whereby it would be possible to have the output in JSON, write it into a file and try to parse it later, a small setup which doesn't require any special environment can be look like
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Show message
debug:
msg: "Hello"
register: message
- name: Show registered message
debug:
msg: "{{ message.stdout }}"

Related

Reusing environment variables between tasks in Ansible

I'm running a few tasks in a playbook which runs a bash script and registers its output:
playbook.yml:
- name: Compare FOO to BAZ
shell: . script.sh
register: output
- name: Print the generated output
debug:
msg: "The output is {{ output }}"
- include: Run if BAZ is true
when: output.stdout == "true"
script.sh:
#!/bin/bash
FOO=$(curl example.com/file.txt)
BAR=$(cat file2.txt)
if [ $FOO == $BAR ]; then
export BAZ=true
else
export BAZ=false
fi
What happens is that Ansible registers the output of FOO=$(curl example.com/file.txt) instead of export BAZ.
Is there a way to register BAZ instead of FOO?
I tried running another task that would get the exported value:
- name: Register value of BAZ
shell: echo $BAZ
register: output
But then I realized that every task opens a separate shell on the remote host and doesn't have access to the variables that were exported in previous steps.
Is there any other way to register the right output as a variable?
I've come up with a workaround, but there must be an other way to do this...
I added a line in script.sh and cat the file in a seperate task
script.sh:
...
echo $BAZ > ~/baz.txt
then in the playbook.yml:
- name: Check value of BAZ
shell: cat ~/baz.txt
register: output
This looks a bit like using a hammer to drive a screw... or a screwdriver to plant a nail. Decide if you want to use nails or screws then use the appropriate tool.
Your question misses quite a few details so I hope my answer wont be too far from your requirements. Meanwhile here is an (untested and quite generic) example using ansible to compare your files and run a task based on the result:
- name: compare files and run task (or not...)
hosts: my_group
vars:
reference_url: https://example.com/file.txt
compared_file_path: /path/on/target/to/file2.txt
# Next var will only be defined when the two tasks below have run
file_matches: "{{ reference.content == (compared.content | b64decode) }}"
tasks:
- name: Get reference once for all hosts in play
uri:
url: "{{ reference_url }}"
return_content: true
register: reference
delegate_to: localhost
run_once: true
- name: slurp file to compare from each host in play
slurp:
path: "{{ compared_file_path }}"
register: compared
- name: run a task on each target host if compared is different
debug:
msg: "compared file is different"
when: not file_matches | bool
Just in case you would be doing all this just to check if a file needs to be updated, there's no need to bother: just download the file on the target. It will only be replaced if needed. You can even launch an action at the end of the playbook if (and only if) the file was actually updated on the target server.
- name: Update file from reference if needed
hosts: my_group
vars:
reference_url: https://example.com/file.txt
target_file_path: /path/on/target/to/file2.txt
tasks:
- name: Update file on target if needed and notify handler if changed
get_url:
url: "{{ reference_url }}"
dest: "{{ target_file_path }}"
notify: do_something_if_changed
handlers:
- name: do whatever task is needed if file was updated
debug:
msg: "file was updated: doing some work"
listen: do_something_if_changed
Some references to go further on above concepts:
uri module
get_url module
slurp module
delegating tasks in ansible
registering output of tasks
run_once
handlers

ansible write variable to local file

I have the following ansible playbook that writes the content of the variable "hello" as a message (I got this code from an example online). I tried modifying it so it would write this to a local file however I got an error. The modified code and error message are below:
original code (successful):
- hosts: all
vars:
hello: world
tasks:
- name: Ansible Basic Variable Example
debug:
msg: "{{ hello }}"
modified code (unsuccessful):
- hosts: all
vars:
hello: world
tasks:
- name: Ansible Basic Variable Example
- local_action: copy content={{hello}} dest=~/ansible_logfile
debug:
msg: "{{ hello }}"
error message:
ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path.
The error appears to have been in '/space/mathewLewis/towerCodeDeploy/playBooks/test.yml': line 5, column 5, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
tasks:
- name: Ansible Basic Variable Example
^ here
I would like to know how to write a variable to a file correctly
It's a simple syntax error.
A Task is an entry in the list of tasks, which in YAML is designated by a - (dash).
Task names are optional in Ansible.
Both copy and debug are modules, which are supposed to be a task's "action".
What the error message is telling you is that the task with name: Ansible Basic Variable Example does not have an action, which is because your local_action is a separate task, indicated by a -.
Fixing your example with appropriate names for the tasks:
- name: Write variable to file
local_action: copy content="{{hello}}" dest=~/ansible_logfile
- name: Output the variable
debug:
msg: "{{ hello }}"
Thomas Hirsh's answer is correct. However, I found this representation less confusing (I'm a newbie to ansible):
- name: "Controller"
hosts: "controller.jeff.ddns.net"
tasks:
- name: "Register a variable to be shared with the clients"
set_fact: shared_fact="Brother"
- name: "Client"
hosts: "client.jeff.ddns.net"
tasks:
- name: "writing to hostvars.json"
local_action: copy content="{{hostvars | to_json(indent=4) }}" dest="hostvars.json"
This example has two plays. The controller play only sets a variable. The client is what actually writes to the file. In this case, hostvars has a complicated structure, so I used the to_json(indent=4) filter to convert to a good .json file, suitable for use with jq .

Evaluate Ansible stdout for end of output

I have a shell task that gets the defrag configuration, and stores it in a variable, like:
- name: Check if hugepages is disabled
shell: cat /sys/kernel/mm/transparent_hugepage/defrag
register: hugepages_status
changed_when: False
In the following task, I want to evaluate the hugepages_status, to see if the last word in it is "never". How can I read the hugepages_status to evaluate just the last word in the string?
Something like:
- name: Disable hugepages
shell: echo never | sudo tee /sys/kernel/mm/transparent_hugepage/defrag
when: swap_status.stdout != "*never"
You can use is search that will search for the string irrespective of the position. I think this would suffice for this scenario. Let me know in case you are looking to search at the end only.
---
- name: play
hosts: localhost
tasks:
- name: Check if hugepages is disabled
shell: cat /sys/kernel/mm/transparent_hugepage/defrag
register: hugepages_status
- name: display the output
debug:
var: hugepages_status.stdout_lines
when: hugepages_status.stdout is search('never')

Using ansible ignore_errors in a loop

I'm using ansible 2.4.0 and try to use ignore_errors depending on check mode and with_items in combination.
According to the docs about check_mode you can define ignore_errors based on if ansible is running in check mode or not. Without the with_items directive this works good, but with both elements a fail is always ignored.
Working example without with_items:
# test_i.yml
- name: test without array and with ignore
hosts: all
gather_facts: no
tasks:
- fail: msg="I fail, but ignored in check mode"
ignore_errors: "{{ ansible_check_mode }}"
- debug: msg="Reachable only in check mode"
Not working example:
# test_ai.yml
- name: test with array and with ignore
hosts: all
gather_facts: no
tasks:
- fail: msg="I am always skipped"
ignore_errors: "{{ ansible_check_mode }}"
with_items: [ 1, 2 ]
- debug: msg="Always reached"
Execute with and results:
ansible-playbook test_i.yml --check
# ok=2, failed=0, but fail-task printed in red
ansible-playbook test_i.yml
# ok=0, failed=1, canceled after fail task
ansible-playbook test_ai.yml --check
# ok=2, failed=0, but fail-task items printed in red
ansible-playbook test_ai.yml
# ok=2, failed=0, same as with check
If the ignore_errors is removed or commented out, the task fails as desired, but then it does in check mode, too. It works even if check_mode is defined as false - but that wouldn't make any sense, would it.
Am I missing something or might this be a bug?
Yes, this is a bug. I've filed an issue 31831 with explanation.

Ansible and debugging script

I want to run a python script locally, and print (debug) the output. Running the script outside of ansible gives my this:
$ python ../scripts/test-winrm-v5.py
i-746726df
Here's my playbook:
$ cat test4.yml
- name: list instance ids
hosts: all
gather_facts: false
tasks:
local_action: shell python ../scripts/test-winrm-v5.sh
register: result
debug: msg="{{ result }}"
Here's what I get when I run the playbook:
$ ansible-playbook -i ../inventory/phani test4.yml
PLAY [list instance ids] ******************************************************
PLAY RECAP ********************************************************************
Why doesn't the output from the script get displayed?
Looks like I had some control character on the debug line. I typed that line again, and now it's working. Here's the playbook:
- name: list instance ids
hosts: windows
tasks:
- debug: msg="System {{ inventory_hostname }}"
- local_action: shell python ../scripts/test-winrm-v5.py
register: result
- debug: msg="Result of running script is {{ result.stdout }}"

Resources