I’m trying to set up a playbook to create KVM clients, and am having a problem setting up dhcp static leases.
I’m adding an entry for the mac address allocated to the new KVM client, and isc-dhcp-server requires this to be added to the dhcpd.conf file, rather than adding a dedicated file to a subdirectory.
The problem comes when I try and create multiple targets concurrently. Appending one target to dhcpd.conf isn’t guaranteed to preserve the appended text from other targets, so if you’re adding client1 and client2, you often only see the entry for client1 ( or 2 )
The only way I’ve managed to get it to work is to run the client creation serially. Whilst this may be a good idea anyway for the additional load on the kvm server, I would like the opportunity to add some level of parallelism to this.
Any suggestions on how to ensure all client details are appended to the remote dhcpd.conf, or should I maybe look for an alternative dhcp server that does allow multiple config files so I can name them uniquely for each target?
OK. You are using lineinfile and blockinfile to manage your dhcpd.conf.
So this is what is happening with your playbook. You are running it against multiple hosts but you delegate each task to a single host. This means that each task runs in parallel - one instance of a task per host. All of these task instances are trying to update the same file on a single host (your DHCP server). There is a race condition. Task instances are fighting with one another to make a change in the config file and the last one to win will make the change. Changes from other task instances will be lost. This also depends on the fork level (-f option) but let’s not go into that.
Now, Ansible does have some guards against race condition but judging by your example, it is not working correctly. I wonder if race condition prevention only works for delegate_to: localhost? Someone from the dev team can potentially say more on the subject.
To resolve this, you have to make your Ansible code update the config file only once. There are two ways to do this. One is to move your tasks to a separate play that will target only your DHCP server like so:
- hosts: your_dhcp_server
tasks:
# your tasks without delegate_to
The other way is to add run_once: true to each task.
Regardless of the way you choose, you also have to loop over a list of all of your hosts in each task.
Final note. lineinfile and blockinfile are unreliable especially if you are making multiple changes in the config file. It’s best to use template to reliably manage the whole config file.