Ansible append hostname if not FQDN - ansible

When ubuntu is installed by default, the hostname is just whatever is input into the installer.
How can I check that hostname, and append it to be a FQDN if it is not already a FQDN?
Example pseudo-yaml
- name: Set FQDN LAN hostname
hostname: "{{ current_hostname }}.lan.example.com"
when: <hostname does not end with .lan.example.com>

I take that you are looking for a condition to be matched in when:. You can use the ansible_fqdn magic (fact) variable.
Example:
- hostname:
name: "{{ ansible_hostname }}.lan.example.com"
when: ( 'lan.example' not in ansible_fqdn )

Module hostname is idempotent
There is no reason to use the condition in this task. The module will either change the hostname if it is different or keep it unchanged if it is already set. For example
- name: Set FQDN LAN hostname
hostname:
name: srv.lan.example.com
Variable ansible_hostname
This variable always keeps the name of the host. It's possible to use it to make sure the hostname is FQDN. For example
- name: Set FQDN LAN hostname
hostname:
name: "{{ ansible_hostname }}.lan.example.com"

Related

Edit IPs with Ansible

Is it possible to customize a IP adress with Ansible. For example when the remote system IP is 127.34.34.21 the DNS IP is 127.34.34.1
The DNS IP is always the system IP but the last number is 1. Is it possible that Ansible can do this dynamical?
Look up the system IP > Customize it > set the new IP as DNS IP.
Q: "Is it possible to customize an IP address with Ansible?"
A: Yes. It is. There are many options.
Use split method and join filter. For example
- set_fact:
dns: "{{ ip.split('.')[:3]|join('.') ~ '.1' }}"
vars:
ip: 127.34.34.21
- debug:
var: dns
give
dns: 127.34.34.1
It's possible to use the splitext filter instead of split/join. For example, the task below gives the same result
- set_fact:
dns: "{{ (ip|splitext)[0] ~ '.1' }}"
Next option is ipaddr filter. For example, the task below gives the same result
- set_fact:
dns: "{{ (ip ~ '/24')|ipaddr('first_usable') }}"
Q: "Is it possible that Ansible can do this dynamical?"
A: Yes. It is. You'll have to decide which IP address to use. For example, use ansible_default_ipv4.address
- debug:
var: ansible_default_ipv4.address
- set_fact:
dns: "{{ (ip ~ '/24')|ipaddr('first_usable') }}"
vars:
ip: "{{ ansible_default_ipv4.address }}"
- debug:
var: dns
give (abridged)
ansible_default_ipv4.address: 10.1.0.27
dns: 10.1.0.1
See setup. See other attributes of the variable ansible_default_ipv4. See variable ansible_all_ipv4_addresses.

how to set hostname using inventory file

I have my hosts in an inventory file as below:
cnamgw01b ansible_ssh_host=172.17.0.26
cnamgw01a ansible_ssh_host=172.17.1.26
cnamgw02b ansible_ssh_host=172.17.0.23
cnamgw02a ansible_ssh_host=172.17.1.23
cnamgw03a ansible_ssh_host=172.17.1.13
cnamgw03b ansible_ssh_host=172.17.0.13
These are new builds and I would like to set the hostname based on the inventory file. I already have a script in place that updated the inventory file as new VM's are turned up and assigns a random hostname. I would like to take this hostname assigned and set it as the hosts hostname. How can I accomplish this? Also note that I also use folders to subdivide the hosts by region
You can use the ansible module hostname to set hostname.
https://docs.ansible.com/ansible/latest/modules/hostname_module.html
- hosts: all
tasks:
- name: Set hostname
hostname:
name: {{ inventory_hostname }}
You could run something like this to set the system hostname to the inventory hostname:
- hosts: all
tasks:
- name: set system hostname
command: hostnamectl set-hostname {{ inventory_hostname }}
That is, the variable inventory_hostname holds the name of the current host as it was named in your inventory.
This task assumes you have the hostnamectl command available. You could instead write the value of inventory_hostname to /etc/hostname and call the hostname command separately.

How do I correctly use the ansible hostname module?

I am trying to use ansible to modify the hostnames of a dozen newly created Virtual Machines, and I am failing to understand how to loop correctly.
Here is the playbook I've written:
---
- hosts: k8s_kvm_vms
tasks:
- name: "update hostnames"
hostname:
name: "{{ item }}"
with_items:
- centos01
- centos02
...
The result is that it updates each host with each hostname. So if I have 12 machines, each hostname would be "centos12" at the end of the playbook.
I expect this behavior to essentially produce the same result as:
num=0
for ip in ${list_of_ips[*]}; do
ssh $ip hostnamectl set-hostname centos${num}
num=$((num+1))
done
If I were to write it myself in bash
The answer on this page leads me to believe I would have to include all of the IP addresses in my playbook. In my opinion, the advantage of scripting would be that I could have the same hostnames even if their IP changes (I just have to copy the ip addresses into /etc/ansible/hosts) which I could reuse with other playbooks. I have read the ansible page on the hostname module, but their example leads me to believe I would, instead of using a loop, have to define a task for each individual IP address. If this is the case, why use ansible over a bash script?
ansible hostname module
You can create a new variable for each of the servers in the inventory like
[k8s_kvm_vms]
server1 new_hostname=centos1
server2 new_hostname=centos2
Playbook:
---
- hosts: k8s_kvm_vms
tasks:
- name: "update hostnames"
hostname:
name: "{{ new_hostname }}"
I think you need to sudo to change the hostname thus you should add "become: yes"
---
- hosts: k8s_kvm_vms
become: yes
tasks:
- name: "update hostnames"
hostname:
name: "{{ new_hostname }}"

Ansible: How to update multiple lines or append if doesn't yet exist

I need to use Ansible to manage an .ssh/config.
Based on whether a unique "Host foo-host" exists (ignoring the values for Hostname, User, & Port), I need to:
1.) add the 4 lines for this host, if not present,
2.) or update the 4 lines, if already present (e.g. in case hostname, port, or user changed).
Host foo-host
Hostname localhost
User ubuntu
Port 2000
Host bar-host
Hostname localhost
User ubuntu
Port 2000
How can I achieve this with Ansible?
I've tried LINEINFILE, but that cannot manage multiple lines. If the Host already exists, it will keep the earlier lines 2-4 for this host and constantly grow longer.
- name: (Matches on hostname only)
lineinfile:
dest: /home/ubuntu/.ssh/config
state: present
regexp: "^Host foo-host\n$"
line: "Host foo-host\n Hostname localhost\n User fooUser\n Port 1234"
OR
- name: (Matches on multiple lines)
lineinfile:
dest: /home/ubuntu/.ssh/config
state: present
regexp: "^Host foo-host\n Hostname localhost\n User .*\n Port"
line: "Host foo-host\n Hostname localhost\n User fooUser\n Port 1234"
I've tried BLOCKINFILE, but this does not behave in the same way as LINEINFILE. It will only have contain the block from most recent run BLOCKINFILE task, but as mentioned, I need it to append if doesn't exist or update if already exists.
- name: Update ssh config
blockinfile:
path: /home/ubuntu/.ssh/config
regexp: "^Host {{ HOSTNAME }}$"
block: |
Host {{ HOSTNAME }}
Hostname localhost
User {{ USER }}
Port {{ PORT }}

How to get IP address of host when passed as extra-vars in Ansible?

Say I am passing the hostnames to an Ansible playbook like so:
ansible-playbook ansible/db-playbook.yml --extra-vars "master=mydb-master, slave=mydb-slave"
In the playbook I want to access the actual ip address of the mydb-slave host:
- name: Copy ssh key to Slave
command: ... "{{ mydb-slave }}"
In this case the output is the string literal mydb-slave, but I require the full ip address.
Make sure that the python module dnspython is installed on the host you are running ansible, then the following should work (if the hosts given are DNS names):
- name: Lookup slave IP
set_fact: slave_ip="{{ lookup('dig', '{{ slave }}')}}"
- name: Copy ssh key to Slave
command: ... "{{ slave_ip }}"
If the hosts are in your ansible inventory, the following should work:
- name: Copy ssh key to Slave
command: ... "{{ hostvars[slave]['ansible_eth0']['ipv4']['address'] }}"

Resources