Using ansible to launch a long running process on a remote host - ansible

I'm new to Ansible. I'm trying to start a process on a remote host using a very simple Ansible Playbook.
Here is how my playbook looks like
-
hosts: somehost
gather_facts: no
user: ubuntu
tasks:
- name: change directory and run jetty server
shell: cd /home/ubuntu/code; nohup ./run.sh
async: 45
run.sh calls a java server process with a few parameters.
My understanding was that using async my process on the remote machine would continue to run even after the playbook has completed (which should happen after around 45 seconds.)
However, as soon as my playbook exits the process started by run.sh on the remote host terminals as well.
Can anyone explain what's going and what am I missing here.
Thanks.

I have ansible playbook to deploy my Play application. I use the shell's command substitution to achieve this and it does the trick for me. I think this is because command substitution spawns a new sub-shell instance to execute the command.
-
hosts: somehost
gather_facts: no
user: ubuntu
tasks:
- name: change directory and run jetty server
shell: dummy=$(nohup /run.sh &) chdir={{/home/ubuntu/code}}

Give a longer time to async say 6 months or an year or evenmore and this should be fine.
Or convert this process to an initscript and use the service module.
and add poll: 0

I'd concur. Since it's long running, I'd call it a service and run it like so. Just create an init.d script, push that out with a 'copy' then run the service.

Related

run ssh commands on vxworks with ansible

I have some old equipment that I manage and it is running VXWorks. I am able to ssh into it and run commands, but the commands and/or the prompts are not standard. I would like to use ansible to automate some of the tasks that I do. I am not sure what module to use for this.
Is there a way to just ssh into a box and start running commands with Ansible for non Linux boxes?
Is there a way to download files via scp/sftp with Ansible for non Linux boxes?
How can I get the raw output. The commands I run are generally show commands and I need to see the output of the commands.
Is there a way to just ssh into a box and start running commands with Ansible for non Linux boxes?
That's what Ansible's raw module is for: it's a minimal wrapper for ssh <somehost> <somecommand>.
Is there a way to download files via scp/sftp with Ansible for non Linux boxes?
If the remote system supports scp or sftp, your Ansible playbooks can just run the appropriate scp/sftp command on your local system. E.g.,
- hosts: localhost
tasks:
- name: copy a file from the remote system
command: scp myserver:somefile.txt .
How can I get the raw output. The commands I run are generally show commands and I need to see the output of the commands.
When you run a command in a playbook, you can register the result, and for raw tasks that registered variable will have stdout and stderr attributes containing the output from the command. For example:
- hosts: myserver
gather_facts: false
tasks:
- name: demonstrate the raw module
raw: date
register: date
- debug:
var: date.stdout
The output from that playbook will include:
TASK [demonstrate the raw module] ************************************************************************************************************************************************************
changed: [myserver]
TASK [debug] *********************************************************************************************************************************************************************************
ok: [myserver] => {
"date.stdout": "Fri Dec 18 09:09:34 PM EST 2020\r\n"
}
The gather_facts: false part is critical, because that prevents Ansible from trying to implicitly run the setup module on your target host.

Ansible connection becomes unreachble after a while

I am running a task in ansible, and the task runs a script present on a remote host.
---
- hosts: remote_host
become: yes
gather_facts: true
connection: ssh
tasks:
- name: Run a script
shell: bash /root/script.sh
This initially establishes a connection successfully, and the task runs the script for a while, before the task fails with an "unreachable" error.
The ansible playbook itself is triggered by a Jenkins job, and the duration of run is passed as a Jenkins parameter.
When I pass the duration as 30 minutes, it runs throughout without interruptions.
But it fails after a while for a 1 hour duration.
Could this be an issue with maintaining the connection for that long?
It might be breaking from default connection timeout if it takes sometime at a place somewhere while executing.

Running a command in an ansible-playbook from the ansible host using variables from the current ansible process

Having hit a brick wall with troubleshooting why one shell script is hanging when I'm trying to run it via Ansible on the remote host, I've discovered that if I run it in an ssh session from the ansible host it executes successfully.
I now want to build that into a playbook as follows:
- name: Run script
local_action: shell ssh $TARGET "/home/ansibler/script.sh"
I just need to know how to access the $TARGET that this playbook is running on from the selected/limited inventory so I can concatenate it into that local_action.
Is there an easy way to access that?
Try with ansible_host:
- name: Run script
local_action: 'shell ssh {{ ansible_host }} "/home/ansibler/script.sh"'

Ansible wait_for for connecting machine to actually login

In my working environment, virtual machines are created and after creating login access information is added to them and there can be delays so just waiting for my ansible script to check if SSH is available is not enough, I actually need to check if ansible can get inside the remote machine via ssh.
Here is my old script which fails me:
- name: wait for instances to listen on port:22
wait_for:
state: started
host: "{{ item }}"
port: 22
with_items: myservers
How can I rewrite this task snippet to achieve waiting for the localmachine can ssh into the remote machines (again not only checking if ssh is ready at the remote but it can actually authenticate to it).
This is somewhat ugly, but given your needs it might work:
- local_action: command ssh myuser#{{ ansible_inventory_hostname }} exit
register: log_output
until: log_output.stdout.find("Last login") > -1
retries: 10
delay: 5
The first line would cause your ansible host to try to ssh into the target host and immediately issue an "exit" to return control back to ansible. Any output from that command gets stored in the log_output variable. The until clause will check the output for the string 'Last login' (you may want to change this to something else depending on your environment), and Ansible will retry this task up to 10 times with a 5 second delay between attempts.
Bruce P's answer was close to what I needed, but my ssh doesn't print any banner when running a command, so checking stdout is problematic.
- local_action: command ssh "{{ hostname }}" exit
register: ssh_test
until: ssh_test.rc == 0
retries: 25
delay: 5
So instead I use the return code to check for success
As long as your Ansible user is already installed on the image you are using to create the new server instance, the wait_for command works well.
If that is not the case, then you need to poll the system that adds that user to the newly created instance for when you should continue - of course that system will have to have something to poll against...
The (very ugly) alternative is to put a static pause in your script that will wait the appropriate amount of time between the instance being created and the user being added like so:
- pause: seconds=1
Try not to though, static pauses are a bad way of solving this issue.

It is possible to async a local_action in ansible?

I'm using Ansible to provision vagrant machines. Now I want the playbook to uncompress the database dump, import it in the vm and then recompress it back.
In "normal" mode this is not a big deal, but since my dumps can be pretty big the uncompress/compress operation take lots of time. I would like to use the "fire and forget" method described here https://docs.ansible.com/playbooks_async.html
The idea is:
"fire and forget" the dump bunzip
[ do all the other operations like package install, configurations ecc]
get back to the bunzip
import dump
fire and forget dump recompression
If I attempt to bunzip using a local_action it dies with ERROR: unexpected error: unable to determine jid
It is possible to do an async local task?
Edit
Tasks list example
# start async unzip
- name: bunzip dump
command: bunzip2 /vagrant/vagrant_provision/dump.sql.bz2
async: 10000
poll: 0
register: bunzip_status
#[... do other things ...]
# connect back to unzip and wait for it to end
- name: Check for dump bunzip
async_status: jid={{ bunzip_status.ansible_job_id }}
register: bunzip_result
until: bunzip_result.finished
retries: 80
#[... Import db ...]
# Fire and forget dump recompression
- name: Recompress dump
command: bzip2 /vagrant/vagrant_provision/dump.sql
async: 10000
poll: 0
Now.. since I'm using this to provision a vagrant environment I partially solved by putting my playbook and files inside the vagrant shared folder and referencing them by absolute path, and it works.
But the question is: It is possible to async a local_action (or even simply a delegate_to)?
In this case the use of local_action instead to do the archive/unarchive remotely allows me to use all my cpus (4 versus 1 assigned to vm) to do those operations and that I can even shutdown the vm during the final recompression without having to wait for it to finish.
I've gotten to the point where I make use of gnu screen whenever I want to background/async a command in Ansible so that I can verify that the command is running properly.
Given what you're describing you'd need to come up with a way to notify Ansible when you've reached step #3. To do that you'd probably want to create a temporary flag file that Ansible can look for. So to do what you describe I'd probably do something along these lines:
First, I'd create a wrapper script to unbzip the file just to make things a bit cleaner. It would create the flag file that I mentioned when the bunzip is complete. Here's a bare-bones example:
#!/bin/bash
rm -f /tmp/bunzip.done
bunzip /path/to/file.bz2
touch /tmp/bunzip.done
exit
Then I'd then execute this from within Ansible in a screen session like this (I use sudo in this example since I also typically sudo my screen sessions to a specific user):
- name: invoke bunzip script
local_action: command /usr/bin/screen -d -m sudo -u someuser /path/to/bzip_script.sh
async: True
poll: 0
At this point you can do whatever you need to do within Ansible. Once you get to step #3 then you would want to do something like this:
- name: wait for bunzip if it is still running
local_action: wait_for path=/tmp/bunzip.done state=present
As long as the wait_for script returns without error you should be able to safely reference the bunzipped data at this point. wait_for defaults to a 300 second timeout, so you may need to increase that if you expect bunzip to take longer.

Resources