ansiblerackspace-cloudopenstack-novapyraxnovaclient

Set SSH Host IP Address on Rackspace for Ansible


The Question

When using the rax module to spin up servers and get inventory, how do I tell Ansible to connect to the IP address on an isolated network rather than the server's public IP?

Note: Ansible is being run from a server on the same isolated network.

The Problem

I spin up a server in the Rackspace Cloud using Ansible with the rax module, and I add it to an isolated/private network. I then add it to inventory and begin configuring it. The first thing I do is lock down SSH, in part by telling it to bind only to the IP address given to the host on the isolated network. The catch is, that means ansible can't connect over the public IP address, so I also set ansible_ssh_host to the private IP. (This happens when I add the host to inventory.)

- name: Add servers to group
  local_action:
    module: add_host
    hostname: "{{ item.name }}"
    ansible_ssh_host: "{{ item.rax.addresses.my_network_name[0].addr }}"
    groups: launched
  with_items: rax_response.success
  when: rax_response.action = 'create'

This works just fine on that first run of creating and configuring new instances. Unfortunately, the next time I try to connect to these servers, the connection is refused because Ansible is trying at an IP address on which SSH isn't listening. This happens because:

  1. Ansible tries to connect to ansible_ssh_host...
  2. But the rax.py inventory script has set ansible_ssh_host to the accessIPv4 returned by Rackspace...
  3. And Rackspace has set accessIPv4 to the public IP address of the server.

Now, I'm not sure what to do about this. Rackspace does allow an API call to update a server and set its accessIPv4, so I thought I could run another local_action after creating the server to do that. Unfortunately, the rax module doesn't appear to allow updating a server, and even if it did it depends on pyrax which in turn depends on novaclient, and novaclient only allows updating the name of the server, not accessIPv4.

Surely someone has done this before. What is the right way to tell Ansible to connect on the isolated network when getting dynamic inventory via the rax module?


Solution

  • You can manually edit the rax.py file and change line 125 and line 163 from:

    hostvars['ansible_ssh_host'] = server.accessIPv4
    

    to:

    hostvars['ansible_ssh_host'] = server.addresses['private'][0]['addr']
    

    This should make the value of ansible_ssh_host the private IP.