Quick and Dirty Remote Execution with Ansible

ansibleAnsible is a wonderful tool for orchestration, configuration management and automating a lot of tasks you’d never want to do by hand.  Sometimes you just need to get in there and run a few commands across a bunch of different systems.  These systems might listen on different SSH ports, or require different entry-point users.  Parallel SSH (pssh) can be useful but I find Ansible to fit the bill even better.  Here’s some useful examples.

Take Advantage of the Inventory
Your hosts inventory is more than just a list of target hosts and groups, you can also set custom variables, SSH listen ports, usernames and more.

Here’s an example:

cat ~/ansible/data/hosts
[servers]
server01 myvariable=1234
server02 ansible_user=sadsfae
host01.example.com:8899 ansible_user=sadsfae
host02.example.com:9988 ansible_user=jhoffa
vm-test ansible_connection=local ansible_port=4423
vm-test2 ansible_connection=local
/mnt/chroot ansible_connection=chroot

[webservers]
web01 ansible_port=6696
web02 ansible_port=6697

Let’s look at some of these options:

[somethinghere] – This is a host group, and how you’ll categorize your various hosts.
myvariable
=1234 – You can pass any variable to a specific host, and refer to it via {{myvariable}}
ansible_user – Overrides the default user that Ansible will try to run as and SSH into the system.
ansible_connection – Tells whether the connection is a local resource or chroot
ansible_port – Another way to specify the SSH port Ansible uses in lieu of hostname:port

You can also apply variables to a specific group at once:

[servers:vars]
dns_server=ns1.example.com
proxy=proxy.example.com

Order and Overrides
Ansible has a particular order of what overrides what with variables, the general rule of thumb in precedence order is:

  1. CLI: ansible-playbook -e “myvariable=1234” (or –extra-vars=”myvariable=1234″)
  2. Hosts file variables
  3. variables set in group_vars/all.yml or in the task via the set_fact module.

Note: hosts file options like ansible_user will also override what’s set as -u username in the examples below.

There are other references here in the inventory official documentation.

Shell and Command Module
The shell module lets you run commands in parallel across a subset of hosts, for example I will update all my machines listed in the [servers] group.

ansible servers -u root -m shell -i hosts -a "yum update -y"

Perhaps I wanted to simply query what Ansible thinks is the local hostname?

ansible servers -u root -m shell -i hosts -a "echo {{ansible_host}}"

How about bouncing the webserver across all my hosts?

ansible webservers -u root -m command -i hosts -a "systemctl restart httpd.service"

Referencing Ansible Facts
You can get a list of the known facts (things Ansible knows about your systems) by running the following command.  Warning: it’s a lot of data.  You can also substitute the group servers for all below if you want to reference all hosts in all inventory groups.

ansible servers -u root -m setup -i hosts
--- snip ---
vm-test01 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.0.142"
],
"ansible_all_ipv6_addresses": [
"fe80::5054:ff:fe90:15e"
],
"ansible_architecture": "x86_64",
"ansible_bios_date": "01/01/2007",
"ansible_bios_version": "0.5.1",
"ansible_cmdline": {
"BOOT_IMAGE": "/vmlinuz-4.4.9-200.fc22.x86_64",
"LANG": "en_US.UTF-8",
"console": "ttyS0,115200",
"quiet": true,
"rd.luks.uuid": "luks-2db1ecfa-6dcb-4255-b35a-0f5459988b5b",
"rd.lvm.lv": "fedora/swap",
"rhgb": true,
"ro": true,
"root": "/dev/mapper/fedora-root"
-- snip --

These will come in handy when you start using playbooks to do more advanced tasks.  Note that you cannot use most of the facts that return unless you use playbooks as Ansible hasn’t discovered them yet.  Actual retention of fact discovery occurs during ansible-playbook runs whereas with the above example we’re simply querying them for our own knowledge.

Doing More with Playbooks
These examples are really basic.  You’ll want to look at creating playbooks to do more advanced tasks.  I’ve got a few Ansible playbooks that will automate tasks for you like installing the ELK stack or a multiplayer game server for further examples.

If you’ve got suggestions or additional useful tasks please share them in the comments below and I’ll update this post.

About Will Foster

hobo devop/sysadmin/SRE
This entry was posted in open source, sysadmin and tagged , , , , , . Bookmark the permalink.

4 Responses to Quick and Dirty Remote Execution with Ansible

  1. Dan says:

    Nice post, thanks.

    While Ansible can be useful in certain situations, it and ParallelSSH are not equivalent tools.

    The latter is an asynchronous parallel SSH client library as its name suggests, nothing more nothing less.

    The former is an orchestration and state configuration tool with its own DSL, a cmd line interface et al.

    For example, consider the equivalent “systemctl restart httpd.service” command using ParallelSSH:

    from pssh import ParallelSSHClient
    host_config = {‘host01.example.com’: {‘port’ : 8899′, ‘user’: sadsfae},
    ‘host01.example.com’: {‘port’ : ‘9988’, ‘user’: ‘jhoffa’},
    }
    hosts = host_config,keys()
    client = ParallelSSHClient(hosts, host_config=host_config)
    client.run_command(“systemctl restart httpd.service”, sudo=True)
    client.pool.join()

    This is the equivalent of the ansible example above in six lines of python code. As its a library, there is no command line binary to run and library code can be embedded into an application or run as a stand alone script.

    Not to say one is better than the other, as before they serve different purposes. Fabric would be an alternative tool to ansible for example and, yes, ansible is a much much better tool than fabric.

    Ansible furthermore is not asynchronous and when running commands in parallel will use threads and increase system load on the machine it is running on.

    Try and use ansible to run a command on, for example, two hundred hosts and note CPU and system load on the host it’s running from..

    ParallelSSH on the other hand could be the SSH client used _by_ ansible to run its parallel commands asynchronously.

    Liked by 1 person

    • Will Foster says:

      Thanks for the insight Dan, I haven’t really done much with pssh so I appreciate this additional information. In particular the points about asynchronism is going to be useful for doing massive one-shot commands across a large fleet.

      Like

  2. vahid Mohammadi says:

    Can we use Ansible with Reverse SSH proxy Tunnel?
    I mean if we use reverse SSH Tunnel, we don’t have the IP address of our clients to put in the host file of Ansible.
    Is there any way to use Ansible with clients behind Nat?

    Like

    • Will Foster says:

      Can we use Ansible with Reverse SSH proxy Tunnel?
      I mean if we use reverse SSH Tunnel, we don’t have the IP address of our clients to put in the host file of Ansible.
      Is there any way to use Ansible with clients behind Nat?

      Good question, the closest thing I found here is using some ~/.ssh/config trickery as outlined here. This is more for proxying through a bastion/jump host however, I’m not sure going through a reverse proxy is possible but I’ve not extensively tested this either. There is also the Ansible parameter ansible_ssh_common_args= which might be worth a try.

      Like

Have a Squat, Leave a Reply ..

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.