Ansible.windows.win_hostname: does not update the Ansible environment

This should automatically updat the ansing ansible_hostname I am thinking but it is not.

name: rename host
ansible.windows.win_hostname:
name: “{{ comp_name }}”
register: res

Hello @ekim1975 welcome to the Ansible Community Forum!

With the little information you did provide is hard to guess what you’re trying to achieve, but I’ll give it a try.

Should we understand that you do want to use your ansible inventory hostnames to rename a set of Windows target hosts?

If that’ so, instead of using ansible_hostname, I believe you need to use inventory_hostname instead (I’m blindly supposing you already parsed ansible_hostname into comp_name from the remote node’s facts in a prior task on your playbook, which btw will result in no chages at all, since you will be assigning the very same hostname that node had during fact gathering).

That is because in Ansible (provided you did enable the gather_facts keyword on your play) ansible_hostname is a fact obtained from the remote node itself. On the other hand, inventory_hostname is what we know as a magic variable - One that in this particular case gets the current inventory hostname value for each instance of a playbook task.

So, maybe you should be trying something like this instead?

- name: rename host
  ansible.windows.win_hostname:
    name: “{{ inventory_hostname }}”
 register: res

Hi Jordi!

It is a pleasure to have joined this Ansible forum. I look forward to interacting with this community. I have been using Ansible for about a year so I am still somewhat of a novice.

In regards to my question.

I do set the {{ comp_name }} in my playbook (ex: DARTH-VADER) of what i want to change the name to… I am just dealing with a single node, which is an AWS ec2 instance.

I tried to use “inventory_host”, that you mention above but that returns the IP address. ansible_host also returns the IP address. This is good because I had a heck of a time finding a method of returning JUST the ip address without the single quotes and brackets. I was using this: {{ ansible_all_ipv4_addresses | regex_replace(“[']”,“”) }} I can use it in some places in my playbook and roles, but in other places Ansible complains.

Ah yes of course, you should build your inventory accordingly in order to set the inventory hostname instead of the IP. For example, you may use the names of the hosts as an alias in your inventory, and then assign an IP address to the ansible_host host_var, like this:

---
kvm_guests:
  hosts:
    win10-vm:
      ansible_host: 192.168.30.30

Then you will be able to use the inventory_hostname magic var to dynamically assign it’s host name to the remote nodes.

Anyway, now that I got more information in regards of your original question, I believe I understand better what you wanted to achieve :slight_smile:

Did you reboot your windows node AFTER renaming it? Be aware that the hostname change will not be effective until you reboot the node (as noted on the ansible.windows.win_hostname module docs), so if you gather facts without rebooting, you won’t notice the change on them…

Here is an example to illustrate better what I just said:

---
- name: "Ansible.windows.win_hostname: does not update the Ansible environment"
  hosts: all
  gather_facts: true
  vars:
    comp_name: new-win10-vm
  tasks:

    - name: Rename host
      ansible.windows.win_hostname:
        name: "{{ comp_name }}"

    - name: Get host facts before rebooting
      ansible.builtin.setup:
      register: pre_facts

    - name: Show facts for the current host BEFORE rebooting -> {{ inventory_hostname }}
      ansible.builtin.debug:
        var: pre_facts.ansible_facts.ansible_hostname

    - name: Reboot windows node
      ansible.windows.win_reboot:

    - name: Get host facts after rebooting
      ansible.builtin.setup:
      register: post_facts

    - name: Show updated facts for the current host AFTER rebooting -> {{ inventory_hostname }}
      ansible.builtin.debug:
        var: post_facts.ansible_facts.ansible_hostname
...

Now, if you check the gathered facts before and after rebooting:

PLAY [Ansible.windows.win_hostname: does not update the Ansible environment] ***************************************************************************************************

TASK [Rename host] *************************************************************************************************************************************************************
changed: [win10-vm]

TASK [Get host facts before rebooting] *****************************************************************************************************************************************
ok: [win10-vm]

TASK [Show facts for the current host BEFORE rebooting -> win10-vm] ************************************************************************************************************
ok: [win10-vm] => {
    "pre_facts.ansible_facts.ansible_hostname": "win10-vm"
}

TASK [Reboot windows node] *****************************************************************************************************************************************************
changed: [win10-vm]

TASK [Get host facts after rebooting] ******************************************************************************************************************************************
ok: [win10-vm]

TASK [Show updated facts for the current host AFTER rebooting -> win10-vm] *****************************************************************************************************
ok: [win10-vm] => {
    "post_facts.ansible_facts.ansible_hostname": "new-win10-vm"
}

PLAY RECAP *********************************************************************************************************************************************************************
win10-vm                   : ok=6    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Hope it helps!

1 Like

Now, for the same price I can answer this one also :smiley:

I’d suggest you using the regex plugins as a last resort resource. To get the IPv4 address from the ansible_facts dict, you can do it in different ways:

If you know for sure that the remote node has only one IP address, you can get it directly from the list of ip_addresses, as it will be always its first element:

    - name: get host IP address
      ansible.builtin.debug:
        var: ansible_facts.ip_addresses | first

However, if you got several nic’s on the remote node, you might want to filter by interface name, or whatever suits you better. For that the selectattr jinja2 filter comes super handy:

    - name: Get host IP address using interface name
      ansible.builtin.debug:
        var: interface[0].ipv4.address
      vars:
        interface: "{{ ansible_facts.interfaces | selectattr('interface_name', 'eq', 'Intel(R) 82574L Gigabit Network Connection #2') }}"

(On the second case, notice that interface will always be a list of only one element after filtering with selectattr, so we get the first element with [0])

cheers

1 Like

The host name thing worked:
post_facts.ansible_facts.ansible_hostname

But the IP did not not: ansible_facts.ip_addresses

note that it still returned the single quotes and brackets [‘1234:567:890:12345’, ‘10.11.12.13’]

That is because what you got there is a list. In short, on Ansible we have different data structures; variables, lists and dictionaries. Vars can store one, and only one element / value (a string, integer, etc). A list is a collection of indexed elements, which can be of different types. Dicts are collections of key:value elements - That is, elements that can be referenced by a key.

Let’s focus on lists, since that’s what we got on ansible_facts.ip_addresses. A list can be set using different formats, which are equivalent:

raw

my_list: ["element_1","element_2","element_N"]

yaml

my_list:
  - element_1
    element_2
    element_N

Now, if you wanted to show the first element of this list, you should use its index to do so, like:

- name: get host IP address
  ansible.builtin.debug:
    var: ansible_facts.ip_addresses[0]

For the second element:

- name: get host IP address
  ansible.builtin.debug:
    var: ansible_facts.ip_addresses[1]

etc.

You can also use jinja filters to get the first or last element of the list instead of indexes, which adds readibility to our code:

- name: get host IP address
  ansible.builtin.debug:
    var: ansible_facts.ip_addresses | first

Summing- up, if you wanted to show the IP address on the list you did provide, you should be using either [1] index, or the last jinja filter, like this:

- name: get host IP address
  ansible.builtin.debug:
    var: ansible_facts.ip_addresses[1]

- name: get host IP address
  ansible.builtin.debug:
    var: ansible_facts.ip_addresses | last

PS: In your list → ["1234:567:890:12345", "10.11.12.13"] the element with index [0] doesn’t look as an IPv4, so I’m using the [1] index to illustrate it better. On my first example I’ve used the index [0] or the first filter because what I do get from my windows node facts is just an IP address, so its a list of only one element. Anyway, I hope that with this explanation you got the point. If you did not, feel free to ask :slight_smile:

1 Like

That makes sense now. Thanks!

1 Like