Printing command stdout on console during runtime - ansible

Sometimes I have to wait very long during running ansible command. For example such command can be executed 30 minutes for my module:
- name: make project
shell: make -j4 install
args:
chdir: "{{ project_dir }}/build"
I would like to see the stdout of this command live, during runtime, not when the command has finished (I see the output when the command has finished, but I need responsiveness, so I'm not interested in something like -v, -vvv or -vvvv). Is it possible to force ansible to print the output during running command (not to buffer it and not to print it at the end)?

You can't print the output while the command runs, but you can print it after the command finished:
- name: make project
shell: make -j4 install
args:
chdir: "{{ project_dir }}/build"
register: out
ignore_errors: yes
- name: print output
debug:
msg: "{{ out.stdout }}"
- name: fail when make failed
fail:
msg: "make task failed"
when: out.rc != 0
The ignore_errors: yes and the fail-task are there, so the output will get printed before your play fails in case the make-task fails.
You should also consider using the make module instead of running make in a shell.

Related

Use string variable (or some other way) as command with args?

Is it possible to pass command (with args) as variable in ansible?
For example, I have this playbook:
- name: My playbook
hosts: myhosts
tasks:
- name: Run Service Command
ansible.builtin.command: "docker compose run --rm service {{ cmd }}"
args:
chdir: "{{ PATH_COMPOSE_DIR }}"
And then I try to run it as:
ansible-playbook my-book.yml -e cmd="my-cmd --arg1 --arg2"
But then it just stucks on running it and nothing happens. Don't see any errors, anything.
If I fully define command on ansible task or just use variables on arg values, it works. But would be nice to be able to pass whole command, so playbook could be more versatile.

How to emulate raw command with EOF?

I am trying to emulate this behavior with Ansible raw command but I could not find any feature that achieve this
ssh user#host.com <<EOF
command
exit
EOF
You are simply sending the script:
command
exit
To the remote host. The <<EOF and EOF parts are parsed by your local shell and aren't part of the command. The equivalent ansible task would be:
- raw: |
command
exit
In most cases (if the remote target is running a semi-standard shell), you won't need the exit either; the script will exit after the last command completes.
You don't need to send a multiline commands via ssh, perhaps you have connected with ssh already with ansible when you set ansible_connection variable, e.g. in your inventory file:
[my_host_group]
host.com
[my_host_group:vars]
ansible_connection=ssh
ansible_become_user=root
ansible_ssh_user=user
Then execute a tasks with bash:
- name: Executing multiline command on host.com under user
ansible.builtin.shell: command
delegate_to: "{{ groups['my_host_group'][0] }}"
become: False
Or just use ansible.builtin.command module instead of ansible.builtin.shell if your command is simple and not multi line.
You don't need an exit at the end of your script either (until you want to change an exit code and return them to ansible). 'Failed when' conditions is your firend:
- name: Executing multiline command on host.com under user
ansible.builtin.shell: command
delegate_to: "{{ groups['my_host_group'][0] }}"
register: your_script_results
ignore_errors: True
become: False
- name: Print an exit code on script error
ansible.builtin.debug:
msg: "Script was failed with {{ your_script_results.rc }} exit code"
when: your_script_results.failed

Ansible register variable not defined

Before running a patching playbook, I ran the playbook with the "--check" option as a dry run. However, one of the plays within the playbook to check whether the group needs a reboot, doesn't register the "reboot_hint" variable as intended
- name: check for reboot
shell: needs-restarting -r
register: reboot_hint
failed_when: reboot_hint.rc > 1
- name: debug, show the reboot hint variable
debug:
var:
- reboot_hint.rc
- reboot_hint
I get the message: ""VARIABLE IS NOT DEFINED!"" for the run.
What could be causing this? I am expect a return value of "1" or "0". I do get that when I go into the command line, run the "needs-restarting -r" and "echo $?
No core libraries or services have been updated.
Reboot is probably not necessary.
> echo $?
0
You're running --check and thus the shell command doesn't run. Because the shell command doesn't run there's nothing to register.
You can read more about this in https://docs.ansible.com/ansible/latest/user_guide/playbooks_checkmode.html#enabling-or-disabling-check-mode-for-tasks
A simple fix is adding check_mode: no, e.g.
- name: check for reboot
check_mode: no
shell: needs-restarting -r
register: reboot_hint
failed_when: reboot_hint.rc > 1
This forces the task to run even when check-mode is enabled.

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.

Resources