How to process output from Ansible using local script - ansible

I want to run some command that return some data and process these data somehow with a script that is located on ansible server. How could I do that?
For example:
I want to run
ansible all -a "cat /etc/redhat-release"
Then I want to call script called version_parser.py (located on local ansible server, not host where ansible is executing the command) with parameters name_of_server and pipe the output of this call as input.
So that in reality I get something similar like
ssh server1 "cat /etc/redhat-release" | version_parser.py server1
ssh server2 "cat /etc/redhat-release" | version_parser.py server2
...
What is most easy approach to do something like this?

You could run the remote command and store the result in a variable. Next you can run a local_action and execute your local script with the stored variable:
---
- name: Run remote command
command: "bash -c 'ls -l /etc/init.d/a* | grep -c app'"
register: store
- name: Run result against local script
local_action: "shell echo '{{ store.stdout }}' | /path/to/local/parser.py {{ inventory_hostname }}"

Related

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

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.

Passing value of script variable to the playbook output

I'm quite new to Ansible so I'm still in learning curve. I'm looking for a way to retrieve a value from script's variable and use it further along with ansible-playbook command.
Saying I have a script I would like to retrieve $hostname info in target node. The script is run in a playbook. When a $HOSTNAME value returns, how can I pass it to my wrapper script so I can reference it with other list?
The script is as simple as follows:
HOSTNAME=$(hostname)
ECHO "$HOSTNAME"
Assuming you are running a script with ansible in one task, you would register the output:
tasks:
- name: Echo value
command: "echo Hello"
register: command_output
Then in your next task, maybe you want to create a file for the hostname:
- shell: "touch {{ item }} "
with_items:
- "{{ command_output.stdout_lines }}"
That's the basic structure - you don't say what command you want to run, but this should get you started.
Here's a nice tutorial: http://www.mydailytutorials.com/ansible-register-variables/

Execute a bash script with arguments in Ansible

I am new to Ansible. I have a bash script which has three arguments to be passed. I have to run this bash script on the remote server from Ansible.
Basically, I want to declare the hostname, duration and the comment fields as arguments while executing the Ansible command. I don't want to edit the file, as I am doing it from a Slack channel.
- hosts: nagiosserver
tasks:
- name: Executing a script
command: sh /home/aravind/downtime.sh {hostname} {duration} {comments}
If you're executing ansible via ansible-playbook myplay.yml, you can pass additional variables via -e varname=varvalue. A lazy fix would be to run with
ansible-playbook myplay.yml -e my_hostname=foo -e my_duration=bar -e my_comments=foobar
But you should consider that the hostname is already defined in your inventory or gathered facts.
So you could update your playbook to use these additional variables using
- hosts: nagiosserver
tasks:
- name: Executing a script
- command: "sh /home/aravind/downtime.sh {{my_hostname}} {{my_duration}} {{my_comments}}"

How to execute a shell script on a remote server using Ansible?

I am planning to execute a shell script on a remote server using Ansible playbook.
blank test.sh file:
touch test.sh
Playbook:
---
- name: Transfer and execute a script.
hosts: server
user: test_user
sudo: yes
tasks:
- name: Transfer the script
copy: src=test.sh dest=/home/test_user mode=0777
- name: Execute the script
local_action: command sudo sh /home/test_user/test.sh
When I run the playbook, the transfer successfully occurs but the script is not executed.
you can use script module
Example
- name: Transfer and execute a script.
hosts: all
tasks:
- name: Copy and Execute the script
script: /home/user/userScript.sh
local_action runs the command on the local server, not on the servers you specify in hosts parameter.
Change your "Execute the script" task to
- name: Execute the script
command: sh /home/test_user/test.sh
and it should do it.
You don't need to repeat sudo in the command line because you have defined it already in the playbook.
According to Ansible Intro to Playbooks user parameter was renamed to remote_user in Ansible 1.4 so you should change it, too
remote_user: test_user
So, the playbook will become:
---
- name: Transfer and execute a script.
hosts: server
remote_user: test_user
sudo: yes
tasks:
- name: Transfer the script
copy: src=test.sh dest=/home/test_user mode=0777
- name: Execute the script
command: sh /home/test_user/test.sh
It's better to use script module for that:
http://docs.ansible.com/script_module.html
For someone wants an ad-hoc command
ansible group_or_hostname -m script -a "/home/user/userScript.sh"
or use relative path
ansible group_or_hostname -m script -a "userScript.sh"
Contrary to all the other answers and comments, there are some downsides to using the script module. Especially when you are running it on a remote(not localhost) host. Here is a snippet from the official ansible documentation:
It is usually preferable to write Ansible modules rather than pushing
scripts. Convert your script to an Ansible module for bonus points!
The ssh connection plugin will force pseudo-tty allocation via -tt
when scripts are executed. Pseudo-ttys do not have a stderr channel
and all stderr is sent to stdout. If you depend on separated stdout
and stderr result keys, please switch to a copy+command set of tasks
instead of using script.
If the path to the local script contains spaces, it needs to be
quoted.
This module is also supported for Windows targets.
For example, run this script using script module for any host other than localhost and notice the stdout and stderr of the script.
#!/bin/bash
echo "Hello from the script"
nonoexistingcommand
echo "hello again"
You will get something like the below; notice the stdout has all the stderr merged.(ideally line 6: nonoexistingcommand: command not found should be in stderr) So, if you are searching for some substring in stdout in the script output. you may get incorrect results.:
ok: [192.168.122.83] => {
"script_out": {
"changed": true,
"failed": false,
"rc": 0,
"stderr": "Shared connection to 192.168.122.83 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.122.83 closed."
],
"stdout": "Hello from the script\r\n/home/ps/.ansible/tmp/ansible-tmp-1660578527.4335434-35162-230921807808160/my_script.sh: line 6: nonoexistingcommand: command not found\r\nhello again\r\n",
"stdout_lines": [
"Hello from the script",
"/home/ps/.ansible/tmp/ansible-tmp-1660578527.4335434-35162-230921807808160/my_script.sh: line 6: nonoexistingcommand: command not found",
"hello again"
]
}
}
The documentation is not encouraging users to use the script module; consider converting your script into an ansible module; here is a simple post by me that explains how to convert your script into an ansible module.
You can use template module to copy if script exists on local machine to remote machine and execute it.
- name: Copy script from local to remote machine
hosts: remote_machine
tasks:
- name: Copy script to remote_machine
template: src=script.sh.2 dest=<remote_machine path>/script.sh mode=755
- name: Execute script on remote_machine
script: sh <remote_machine path>/script.sh
Since nothing is defined about "the script", means complexity, content, runtime, runtime environment, size, tasks to perform, etc. are unknown, it might be possible to use an unrecommended approach like in "How to copy content provided in command prompt with special chars in a file using Ansible?"
---
- hosts: test
become: false
gather_facts: false
tasks:
- name: Exec sh script on Remote Node
shell:
cmd: |
date
ps -ef | grep ssh
echo "That's all folks"
register: result
- name: Show result
debug:
msg: "{{ result.stdout }}"
which is a multi-line shell command only (annot.: ... just inline code) and resulting into an output of
TASK [Show result] ****************************************************
ok: [test.example.com] =>
msg: |-
Sat Sep 3 21:00:00 CEST 2022
root 709 1 0 Aug11 ? 00:00:00 /usr/sbin/sshd -D
root 123456 709 14 21:00 ? 00:00:00 sshd: user [priv]
user 123456 123456 1 21:00 ? 00:00:00 sshd: user#pts/0
root 123456 123456 0 21:00 pts/0 00:00:00 grep ssh
That's all folks
One could just add more lines, complexity, necessary output, etc.
Because of script module – Runs a local script on a remote node after transferring it - Notes
It is usually preferable to write Ansible modules rather than pushing scripts.
I also recommend to get familar with writing an own module and as already mentioned in the answer of P....
You can execute local scripts at ansible without having to transfer the file to the remote server, this way:
ansible my_remote_server -m shell -a "`cat /localpath/to/script.sh`"

Resources