dhcp hell:

17 January 2018

the 3-day nightmare of trying to get dhcp and dns to play nice on openstack :/

what i’d like to do:

  1. set the hostname of a VM to the server name that is configured in Openstack (something that can be queried by the VM on boot/creation)
  2. configure the DNS on the VM to point to 2 internal DNS servers
  3. specify a single searchdomain
  4. set the GATEWAYDEV to be eth0 on the VM

setup:

k so we have a heat template that creates some network resources an junk:

...
submarine:
  type: OS::Neutron::Subnet
  properties:
    cidr: 192.168.128.0/24
    dns_nameservers: ['8.8.8.7', '8.8.4.3']
    name:
      list_join: [-, [{get_param: "OS::stack_name"}, subnet]]
    network: {get_resource: netmarine}
...

simple enough

this is used as a base to run packer to configure a VM image in Openstack with the above 4 settings (this image will later be used to spin up VMs for a k8s deployment)

problems:

  1. using dchp on the vm will give me the correct DNS IPs but my hostname gets reset to <some_server_name>.openstacklocal or <some_other_server_name>.novalocal
  2. i have no control over this deployment of openstack so can’t make the (very simple) change to nova.conf so that the neutron routers don’t propagate openstacklocal or novalocal as searcdomains/fqdns :/

what i do:

wrestling with cloud-init @ first doesnt seem so bad.

i can make something like this werk apparently:

#cloud-config
manage_resolv_conf: true
resolv_conf:
  nameservers:
    - 8.8.8.7
    - 8.8.4.3
  searchdomains:
    - katy.kates
  domain: katy.kates
  options:
    rotate: true
    timeout: 1

ok… let’s try making a garbage /etc/resolv.conf and reloading cloud-init with:

cloud-init init

ez

you can even delete everything in /var/lib/cloud and this will put it all back automagically

ok. seems to work. let’s try a reboot!

; generated by dhclient-script! :P
search openstack.local nova.local
nameserver 8.8.8.7
nameserver 8.8.4.3

i hate dhclient.
i did not know this about myself but it’s true. i do.

how about we do something in /etc/dhcp/dhclient.conf?
i heard supersede works…???

# Generated by automatedbutlertypecithing
supersede domain-name "katy.kates";
supersede domain-name-servers 8.8.8.7, 8.8.4.3;
request subnet-mask, broadcast-address, time-offset, routers, netbios-scope, interface-mtu;
timeout 300;
retry 60;

reboot and…
nope
resolv.conf is back to the stupid dhclient .openstacklocal .novalocal garbage

it turns out the internet says i can cripple the functionality of dhclient by overriding the script’s functions!
i feel instinctively (is there any other way 2feel?) that this is a terrible idea but srsly the thought of ripping the functionality out of this script feels satisfyingly vengeful even tho i know i am anthropomorphizing a script ://

what the heck lets do it

# Generated by automatedbutlertypething
eventually_add_hostnames_domain_to_search() {
        exit 0
}
make_resolv_conf() {
        exit 0
}

awww damn it cloud-init
at this point i just want to burn it all down :O arg

bootcmd:
 - hostnamectl set-hostname --static $(curl --silent http://169.254.169.254/latest/meta-data/hostname | awk -F '.' '{print $1}')
 - grep -qF 'PEERDNS' "/etc/sysconfig/network-scripts/ifcfg-eth0" || echo 'PEERDNS=no' >> /etc/sysconfig/network-scripts/ifcfg-eth0
preserve_hostname: true
manage_etc_hosts: false
manage_resolv_conf: false

wait. no. there’s some logic missing in that grep/echo combo. if grep finds PEERDNS=yes in the file it won’t ever echo PEERDNS=no ://///

let’s instead put some of this stuff into ansible! yay!

- name: Ensure eth0 is always the GATEWAYDEV
  lineinfile:
    path: /etc/sysconfig/network
    line: "{{ item }}"
    state: present
    insertafter: EOF
  with_items:
    - GATEWAYDEV=eth0

- name: Disable PEERDNS on eth0
  lineinfile:
    path: /etc/sysconfig/network-scripts/ifcfg-eth0
    regexp: '"PEERDNS="yes"'
    line: "PEERDNS=no"

right, well, GATEWAYDEV worked but no luck for PEERDNS… the eth device on a vm built from the image we just created has a nice little header on the eth config: generated by cloud-init

arg. at this point i’m tired of cloud-init. i dread the prospect of continuing to wrestle with the stupid thing to get a nic config to do what i want. plus it seems like overkill to manage the entire nic config when all i want is just to disable dns peering. jeeez. bootcmd has worked well so far. i get bash. bash is my friend.

bootcmd:
 - hostnamectl set-hostname --static $(curl --silent http://169.254.169.254/latest/meta-data/hostname | awk -F '.' '{print $1}')
 - sed -i '/^PEERDNS=/{h;s/=.*/=no/};${x;/^$/{s//PEERDNS=no/;H};x}' /etc/sysconfig/network-scripts/ifcfg-eth*
preserve_hostname: true
manage_etc_hosts: false
manage_resolv_conf: false

don’t ask me to explain that sed. i cobbled it together from stackoverflow posts on how to swap a string if it exists; otherwise, create it.

this works. it’s persistent. i hope to never have to do this again :/