Search code examples
ansibleansible-awx

How to run plays using Ansible AWX on all hosts in a group using localhost


I'm trying to create a playbook that creates EC2 snapshots of some AWS Windows servers. I'm having a lot of trouble understanding how to get the correct directives in place to make sure things are running as they can. What I need to do is:

  • run the AWS commands locally, i.e. on the AWX host (as this is preferable to having to configure credentials on every server)
  • run the commands against each host in the inventory

I've done this in the past with a different group of Linux servers with no issue. But the fact that I'm having these issues makes me think that's not working as I think it is (I'm pretty new to all things Ansible/AWX).

The first step is I need to identify instances that are usually turned off and turn them on, then to take snapshots, then to turn them off again if they are usually turned off. So this is my main.yml:

---
- name: start the instance if the default state is stopped
  import_playbook: start-instance.yml
  when: default_state is defined and default_state == 'stopped'

- name: run the snapshot script
  import_playbook: instance-snapshot.yml

- name: stop the instance if the default state is stopped
  import_playbook: stop-instance.yml
  when: default_state is defined and default_state == 'stopped'

And this is start-instance.yml

---
- name: make sure instances are running
  hosts: all
  gather_facts: false
  connection: local
  tasks:
    - name: start the instances
      ec2:
        instance_id: "{{ instance_id }}"
        region: "{{ aws_region }}"
        state: running
        wait: true
      register: ec2
    - name: pause for 120 seconds to allow the instance to start
      pause: seconds=120

When I run this, I get the following error:

fatal: [myhost,mydomain.com]: UNREACHABLE! => {
    "changed": false,
    "msg": "ssl: HTTPSConnectionPool(host='myhost,mydomain.com', port=5986): Max retries exceeded with url: /wsman (Caused by ConnectTimeoutError(<requests.packages.urllib3.connection.VerifiedHTTPSConnection object at 0x7f99045e6bd0>, 'Connection to myhost,mydomain.com timed out. (connect timeout=30)'))",
    "unreachable": true

I've learnt enough to know that this means it is, indeed, trying to connect to each Windows host which is not what I want. However, I thought having connection: local resolved this as it seemed to with another template I have which uses and identical playbook.

So If I change start-instance.yml to instead say "connection: localhost", then the play runs - but skips the steps because it determines that no hosts meet the condition (i.e. default_state is defined and default_state == 'stopped'). This tells me that the play is running on using localhost to run the play, but is also running it against localhost instead of the list of hosts in the inventory in AWX.

My hosts have variables defined in AWX such as instance ID, region, default state. I know in normal Ansible use we would have the instance IDs in the playbook and that's how Ansible would know which AWS instances to start up, but in this case I need it to get this information from AWX.

Is there any way to do this? So, run the tasks (start the instances, pause for 120 seconds) against all hosts in my AWX inventory, using localhost?


Solution

  • In the end I used delegate_to for this. I changed the code to this:

    ---
    - name: make sure instances are running
      hosts: all
      gather_facts: false
      tasks:
        - name: start the instances
          delegate_to: localhost
          ec2:
            instance_id: "{{ instance_id }}"
            region: "{{ aws_region }}"
            state: running
            wait: true
          register: ec2
        - name: pause for 120 seconds to allow the instance to start
          pause: seconds=120
    

    And AWX correctly used localhost to run the tasks I added delegation to.

    Worth noting I got stuck for a while before realising my template needed two sets of credentials - one IAM user with correct permissions to run the AWS commands, and one for the machine credentials for the Windows instances.