Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ansible: how to set hostname before DNS assigned

Tags:

ansible

Does anyone have a better solution for configuring instances with a hostname before that hostname can be assigned to the server?

Let's say we're using AWS and instantiate instance ec2-1-2-3-4.compute-1.amazonaws.com. When it's configured, we'll eventually assign it a CNAME in DNS of new-instance.example.com to replace an existing instance already in production.

new-instance.example.com already exists and is in production, so we can't reassign the CNAME to ec2-1-2-3-4.compute-1.amazonaws.com until the machine is configured properly and we're ready to switch over. We want internal configuration files and the hostname on the instance to be new-instance.example.com now, however, in preparation for the DNS change. So we can't use the inventory_hostname variable because it will be ec2-1-2-3-4.compute-1.amazonaws.com. I also have normal production servers that don't need to use a new hostname, so I'd like to be able to use the existing inventory_hostname with them.

My best idea so far has been to assign a variable in the inventory file:

[production]
ec2-1-2-3-4.compute-1.amazonaws.com new_hostname=new-instance.example.com

In the playbook, I can test for the existence of new_hostname. If new_hostname exists, it's used and if it doesn't, inventory_hostname is used. This will cause a fatal error unless error_on_undefined_vars is set to false and I'd prefer not to set this for the benefit it provides of preventing typos. An example of failure below.

Test Playbook:

- hosts: all
  tasks:
    - name: "Debug hostname"
      debug: msg="inventory_hostname={{ inventory_hostname }}, hostvars[inventory_hostname]['inventory_hostname']={{ hostvars[inventory_hostname]['inventory_hostname'] }}, ansible_hostname={{ ansible_hostname }}, new_hostname={{ new_hostname }}"
      ignore_errors: yes

Results:

TASK: [Debug hostname] ********************************************************
fatal: [ec2-1-2-3-4.compute-1.amazonaws.com] => One or more undefined variables: 'new_hostname' is undefined

Setting new_hostname for every single server would work, but I don't want to set it for every one, just the ones that need the new hostname. It also breaks hostname grouping like:

ec2-1-2-3-[4:5].compute-1.amazonaws.com

If new_hostname exists, this works:

- name: "set hostname fact"
  set_fact: testvar1={{ new_hostname }} || {{ inventory_hostname }}

- name: "show hostname fact"
  debug: msg="testvar1={{ testvar1 }}"

Results:

TASK: [set hostname fact] *****************************************************
ok: [ec2-1-2-3-4.compute-1.amazonaws.com]

TASK: [show hostname fact] ****************************************************
ok: [ec2-1-2-3-4.compute-1.amazonaws.com] => {"msg": "testvar1=new-instance.example.com"}

If error_on_undefined_vars is set to the default of true, however, and new_hostname is not set, it fails.

Best practices on this strategy?

like image 247
Dave Stern Avatar asked Dec 08 '22 09:12

Dave Stern


2 Answers

Being very shy on this because I am also new to ansible and if I understand your problem, one way is to use when: something is defined on the task.

Example:

  tasks:
    - name: "Debug hostname"
      debug: msg="inventory_hostname={{ inventory_hostname }}, hostvars[inventory_hostname]['inventory_hostname']={{ hostvars[inventory_hostname]['inventory_hostname'] }}, ansible_hostname={{ ansible_hostname }}, new_hostname={{ new_hostname }}"
      when: new_hostname is defined

Now that's one approach. Another would be to make a role for that and only play that role (the spinning up procedure) separately to a target machine from an added entry in the inventory maybe. Take a look at the best practices if you like as well for some extra reading.

like image 139
Jimmy Kane Avatar answered Jan 05 '23 17:01

Jimmy Kane


When standing up cloud-init to set the hostname. (I use Chef but that isn't relevant to the solution here). This gets around the problem of setting the hostname in your automation framework as it's already set by the time the node boots.

Part of my cloud config sets the fqdn and manage_etc_hosts options like so:

fqdn: new-instance.example.com
manage_etc_hosts: true

There are plenty of example configuration fragments in the doc/examples directory and it's easy to play around and find a setup that you like.

like image 27
Tim Potter Avatar answered Jan 05 '23 16:01

Tim Potter