CentOS 7: update-hostname always overwrites hostname

Bug #1424710 reported by Brian Rak on 2015-02-23
This bug affects 7 people
Affects Status Importance Assigned to Milestone

Bug Description

On CentOS 7 (systemd based), with cloud-init 0.7.5, cc_update_hostname will *always* overwrite the hostname, even if it shouldn't.

This is pretty easy to reproduce:

1) Add a 'hostname: metadata.example.com' to your user-data
2) Run 'hostnamectl set-hostname test.example.com'
3) Reboot the server
4) Check the hostname, it'll still be 'metadata.example.com'
5) Repeat 2-4, hostname will still be set

Looking at the code, this is because rhel.py doesn't populate the previous-hostname file correctly:

    def _write_hostname(self, hostname, out_fn):
        if self._dist_uses_systemd():
            util.subp(['hostnamectl', 'set-hostname', str(hostname)])
            host_cfg = {
                'HOSTNAME': hostname,
            rhel_util.update_sysconfig_file(out_fn, host_cfg)

So, Distros::update_hostname calls _write_hostname to try and save the previous hostname to /var/lib/cloud/data/previous-hostname .. however, all this does is run the hostnamectl command, which doesn't actually update this file. This means that on the next cloud-init run, /var/lib/cloud/data/previous-hostname doesn't exist so the hostname gets blindly updated again.

The fix here seems pretty simple, we just need to update previous-hostname as well when running hostnamectl. I attached a patch that does this, though I don't know the best way to implement this.. my patch fails if cloud-init's data path is changed

Related branches

Brian Rak (brak) wrote :
Lennert den Teuling (lennert) wrote :

I can confirm this bug. If you place the previous-hostname file manually it stops changing the hostname on every reboot. As a workaround i installed cloud-init-0.7.5-6.el7 (epel).

Brian Rak (brak) wrote :

The upstream version of cloud-init (from centos-extras) contains this patch:

    def _dist_uses_systemd(self):
         return ((dist.startswith('Red Hat Enterprise Linux') and major >= 7)
+ or (dist.startswith('CentOS Linux') and major >= 7)
                 or (dist.startswith('Fedora') and major >= 18))

The EPEL version does not contain this, so cloud-init is not aware that CentOS 7 uses systemd. This works around the issue because it falls back to the old method of setting the hostname (which isn't broken).

So, the EPEL version works, but only accidentally.

Lars Kellogg-Stedman (larsks) wrote :

There is actually a bigger problem here.

The update_hostname method gets the previous hostname (prev_hostname) by reading a value of prev_hostname_fn...or so you might think. But in fact, because of the way _read_hostname is implemented, this actual returns the *current* hostname on systemd based systems. This means that even if we patch _write_hostname to correctly write /var/lib/cloud/data/previous-hostname, that value will be ignored and cloud-init will *continue* to always update the hostname.

A fundamental problem with the code -- at least in 0.7.6 -- is that the base distros.Distro class doesn't provide a high enough level of abstraction. It assumes a file-based configuration for managing hostnames, and overloads functions like _read_hostname to perform multiple functions in ways that are pretty much guaranteed to fail.

I'm working on a band-aid that will resolve this problem, but the Distro class really needs to provide a high-level API that is well separated from the individual distribution drivers. In particular, the base class should probably *never* be reading or writing files outside of /var/lib/cloud.

Brian Rak (brak) wrote :

Yea, we had to patch _read_hostname and _write_hostname to explicitly look for the filename ending in /previous-hostname, and write that to an actual file (rather then relying on hostnamectl)

Seems to be working pretty well so far.

Scott Moser (smoser) on 2017-01-12
Changed in cloud-init:
status: New → Confirmed
importance: Undecided → Medium
do3meli (d-info-e) on 2018-03-29
tags: added: centos
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers