redhat is different from sles when setting hostname by cloud-init.

Bug #1649802 reported by nafeiyang
24
This bug affects 4 people
Affects Status Importance Assigned to Milestone
cloud-init
Expired
Undecided
Unassigned

Bug Description

Boot a vm with redhat image via openstack, after vm start up, type hostname command ,find it set the hostname with string .novalocal, this is not expect.

Steps of reproduce.
1 Boot two vms, one is rhel, one is suse for comparision, set the vms name with ".test" for both
nova boot --flavor 0g0 --image rhel72image rhel72.test
nova boot --flavor 0g0 --image sles12image sles12hostname.test

2 The boot success.
nova list
| dcbd39cb-4cfc-4298-942e-44232a157551 | rhel72.test | ACTIVE | - | Running | mgt_network503=192.168.99.7 |
| 662e00e1-ca27-4e8a-b490-80a3296bbe29 | sles12hostname.test | ACTIVE | - | Running | mgt_network503=192.168.99.16 |

3 Logon the vm, and type hostname command.
Logon rhel vm:
[root@rhel72 ~]# hostname
rhel72.test.novalocal

sles12hostname:~ # hostname
sles12hostname

4 I don't change the default logger for cloud-init on both vms. We don't expect rhel is set with hostname "rhel72.test.novalocal" (It's from configdrive's meta_data.json I think). What I expect is rhel can behavior similar as sles do,just set rhel72 as its hostname.

Here are the meta_data.json for both
[root@rhel72 ~]# cat /mnt/openstack/latest/meta_data.json
{"files": [{"path": "/etc/sysconfig/network-scripts/ifcfg-enccw0.0.1000", "content_path": "/content/0000"}, {"path": "/tmp/znetconfig.sh", "content_path": "/content/0001"}], "random_seed": "Qg5L7UJ2ZEILjK8fFDo6R1MESgFjpwgfvz+HMxlSRHtuit36xoTm4XCpdHJ2mavJIPl6hIXIeTb6JLUUu2jwfXhOQKJWPhvQAwByjr8yKbn3N3Z+ilYR2TmMnSMFTu+gBeZXVI7yOG+1HXOoSnGRHtuS3cKztnK0vThz21dID2qPRWYv98bkJCPwKH7LURVwb2HAEWR/hkJrMKpMld6SPxhGVSMTSq5Rwq4IZkDWJwn4Tn1AqOTa8m8TVvrrQG2z+AkLRiEUZN/6yAB92cThHab0OwEkoFHdZHSYK1dOgQ0QTzs6k7FKYurSQENSg+npXDH62r0tOaW9qr0dj89wvz6fIBjxDaPuu8C55SUzv/xBqVKKg5m+1Ca/hFfIi9GIiMRxZcQq1k45ygd7zhBR7t3zQjRjPyJ0tGOxLyBd6JwdpRQ2GPctkVCmTIU1WqGPA6aI5lRombjc+Fm/wgarmAG64OmPFXb4UX/13vTEhjDYXg5iVXK7gIffIJuCjRP1mmLxZvEbr+GmTohkIdhjE9fp7+S3GN9XYxHmFDv/Jk63AFbgDCCZLwutqECuLpgiDcMuDv2XUXeXjmF/aB0UF49p99jsjVP0ESHoeJ6dxUdJwokr66tnpBmBFg2KH3sk+QHiy2AHPgRy1kGS6uCOh1fvEp8W/9jg1C9Q8dBkh6E=", "uuid": "67655c8c-6b2a-49a5-80aa-59e12262e0fc", "availability_zone": "nova", "hostname": "rhel72.test.novalocal", "launch_index": 0, "devices": [], "project_id": "3fb34d2550b74f14a36f7d435e4423d7", "name": "rhel72.test"}

sles12hostname:~ # cat /mnt/openstack/latest/meta_data.json
{"files": [{"path": "/etc/sysconfig/network/ifcfg-eth0", "content_path": "/content/0000"}, {"path": "/etc/udev/rules.d/70-persistent-net.rules", "content_path": "/content/0001"}, {"path": "/etc/sysconfig/network/routes", "content_path": "/content/0002"}, {"path": "/tmp/znetconfig.sh", "content_path": "/content/0003"}], "random_seed": "EfwPK1nHQcnOb8oQk5MVj6DI/SgoM4H9Bc4XCxxPVm4yNJ7gWcgImwTGHNp+BsQS9sdC6iXoLhso7UhpQdj/2c8MqHuQlI0kbgRra2CxSsUWtDibaq38SMQVHrea57K3lby6HhbsexpWApkWfu5zOWYTl2zXUq3yT5DCPrvL9SeZoGU+taABkM4w1zTSLsWdh6LGCZLhWrvOqyy09Y3kVyErShWJ6c0Q5QlcSRVmL1RDc9OMo6x7le+C9v7rZLzkJt+G/84ugnpm+RSdzv9EIkGom9jUKCiByS22dxY1HkcnnEM8wD/Q/LAIBG151vtEDhCLopZYAz4R+RicVTBnG0Oljra27Y5YKTOc74Q//xbbyjfGN5252IQDuogdRszNuvUHClc3/NoF7sFdszb1P+6ni8xXpAzuKc6EVFP7kfkIC9fkAZPsYTWJPCrxHOrPXEC3YVR0VMcy/LxI+4rHXjNzKuq+TdYuNweMhwonYgn52dEq6V2zhDzl/SEzeb+7JKN1McH0Y0fLy2egNghNCFJMX3ztcR8O8V3qtptV1yZJbpzNomlDEkdSvhrYrmi40WOoxat3WbNW3hkDaTWpOFuXOTrPJU/+bOWDTYns2qMBeWw2U/Hb0HAxdsfM9rMC5dTcTZK+O0IdQhfes4y6y84EJDvBqKkBnYx9fwXAwfU=", "uuid": "662e00e1-ca27-4e8a-b490-80a3296bbe29", "availability_zone": "nova", "hostname": "sles12hostname.test.novalocal", "launch_index": 0, "devices": [], "project_id": "3fb34d2550b74f14a36f7d435e4423d7", "name": "sles12hostname.test"}

Here are the logs for both vm
For rhel:
Dec 14 03:26:29 tempest cloud-init: Cloud-init v. 0.7.6 running 'init-local' at Wed, 14 Dec 2016 08:26:29 +0000. Up 11.12 seconds.
Dec 14 03:26:30 tempest journal: [CLOUDINIT] stages.py[INFO]: Loaded datasource DataSourceConfigDrive - DataSourceConfigDrive [local,ver=2][source=/dev/loop0]
Dec 14 03:26:30 tempest journal: [CLOUDINIT] stages.py[INFO]: Skipping modules ['ca-certs'] because they are not verified on distro 'rhel'. To run anyway, add them to 'unverified_modules' in config.
Dec 14 03:26:30 tempest dbus[487]: [system] Activating via systemd: service name='org.freedesktop.hostname1' unit='dbus-org.freedesktop.hostname1.service'
Dec 14 03:26:30 tempest dbus-daemon: dbus[487]: [system] Activating via systemd: service name='org.freedesktop.hostname1' unit='dbus-org.freedesktop.hostname1.service'
Dec 14 03:26:30 tempest systemd: Starting Hostname Service...
Dec 14 03:26:30 tempest dbus[487]: [system] Successfully activated service 'org.freedesktop.hostname1'
Dec 14 03:26:30 tempest dbus-daemon: dbus[487]: [system] Successfully activated service 'org.freedesktop.hostname1'
Dec 14 03:26:30 tempest systemd: Started Hostname Service.
Dec 14 03:26:30 tempest systemd-hostnamed: Changed static host name to 'rhel72.test.novalocal'
Dec 14 03:26:30 tempest systemd-hostnamed: Changed host name to 'rhel72.test.novalocal'
Dec 14 03:26:30 tempest journal: [CLOUDINIT] __init__.py[INFO]: User rhel already exists, skipping.

For sles:
2016-12-13T06:07:27.696423-05:00 tempest [CLOUDINIT] stages.py[DEBUG]: Running module set_hostname (<module 'cloudinit.config.cc_set_hostname' from '/usr/lib/python2.7/site-packages/cloud_init-0.7.6-py2.7.egg/cloudinit/config/cc_set_hostname.pyc'>) with frequency once-per-instance
2016-12-13T06:07:27.696573-05:00 tempest [CLOUDINIT] util.py[DEBUG]: Writing to /var/lib/cloud/instances/662e00e1-ca27-4e8a-b490-80a3296bbe29/sem/config_set_hostname - wb: [420] 20 bytes
2016-12-13T06:07:27.696723-05:00 tempest [CLOUDINIT] helpers.py[DEBUG]: Running config-set_hostname using lock (<FileLock using file '/var/lib/cloud/instances/662e00e1-ca27-4e8a-b490-80a3296bbe29/sem/config_set_hostname'>)
2016-12-13T06:07:27.696871-05:00 tempest [CLOUDINIT] cc_set_hostname.py[DEBUG]: Setting the hostname to sles12hostname.test.novalocal (sles12hostname)
2016-12-13T06:07:27.697530-05:00 tempest [CLOUDINIT] util.py[DEBUG]: Reading from /etc/HOSTNAME (quiet=False)
2016-12-13T06:07:27.697693-05:00 tempest [CLOUDINIT] util.py[DEBUG]: Read 8 bytes from /etc/HOSTNAME
2016-12-13T06:07:27.697846-05:00 tempest [CLOUDINIT] util.py[DEBUG]: Writing to /etc/HOSTNAME - wb: [420] 15 bytes
2016-12-13T06:07:27.698897-05:00 tempest [CLOUDINIT] __init__.py[DEBUG]: Non-persistently setting the system hostname to sles12hostname
2016-12-13T06:07:27.699068-05:00 tempest [CLOUDINIT] util.py[DEBUG]: Running command ['hostname', u'sles12hostname'] with allowed return codes [0] (shell=False, capture=True)

Revision history for this message
nafeiyang (nafeiy) wrote :

With further check I find the hostname is set again in cc_update_hostname.py, in this step rhel and sles is different at _select_hostname. However, I think sles's method is reasonable. I guess customer don't want to see the .novalocal in hostname.

for rhel.py
    def _select_hostname(self, hostname, fqdn):
        # See: http://bit.ly/TwitgL
        # Should be fqdn if we can use it
        if fqdn:
            return fqdn
        return hostname

For sles.py
    def _select_hostname(self, hostname, fqdn):
        # Prefer the short hostname over the long
        # fully qualified domain name
        if not hostname:
            return fqdn
        return hostname

A quesitons is why rhel use hostname_conf_fn = "/etc/sysconfig/network" ? Is this a bug?
class Distro(distros.Distro):
    # See: http://tiny.cc/6r99fw
    clock_conf_fn = "/etc/sysconfig/clock"
    locale_conf_fn = '/etc/sysconfig/i18n'
    systemd_locale_conf_fn = '/etc/locale.conf'
    network_conf_fn = "/etc/sysconfig/network"
    hostname_conf_fn = "/etc/sysconfig/network"

Revision history for this message
nafeiyang (nafeiy) wrote :

If check further, I find for rhel7 which use systemd, the /var/lib/cloud/data/previous-hostname will not be updated.

This is because in following code, it seems the prev_hostname will be got by reading contents in /var/lib/cloud/data/previous-hostname

cloudinit/distros/__init__.py
        # If the previous hostname file exists lets see if we
        # can get a hostname from it
        if prev_hostname_fn and os.path.exists(prev_hostname_fn):
            prev_hostname = self._read_hostname(prev_hostname_fn)
        else:
            prev_hostname = None

However in rhel.py, it will use the result of hostname command to get the prev_hostname, but not by reading the contents in /var/lib/cloud/data/previous-hostname.

    def _read_hostname(self, filename, default=None):
        if self._dist_uses_systemd():
            (out, _err) = util.subp(['hostname'])
            if len(out):
                return out
            else:
                return default
        else:
            (_exists, contents) = rhel_util.read_sysconfig_file(filename)
            if 'HOSTNAME' in contents:
                return contents['HOSTNAME']
            else:
                return default

And when updating the /var/lib/cloud/data/previous-hostname file, it will never update it.

        for fn in update_files:
            try:
                self._write_hostname(hostname, fn)
            except IOError:
                util.logexc(LOG, "Failed to write hostname %s to %s", hostname,
                            fn)

        if (sys_hostname and prev_hostname and
                sys_hostname != prev_hostname):
            LOG.debug("%s differs from %s, assuming user maintained hostname.",
                       prev_hostname_fn, sys_fn)

Because for rhel6, the hostnamectl just update the /etc/hostname file, but not update /var/lib/cloud/data/previous-hostname file. So the content in this file will keeps no change forever. We need a fix to change the work mechanism for rhel7. For sles, it works as expect.

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

Revision history for this message
Vern Hart (vern) wrote :

I've seen a similar situation where the hostname on rhel 7.5 (and 7.4) instances is getting set to whatever.novalocal and that seems to be interfering with the domain getting set properly. In the same environment, Ubuntu 18.04 and Cirros instances are getting their hostnames (and domainnames) from designate (via dhcp), as you'd expect.

At first I thought it might be because cloud-init sets the hostname AFTER dhclient on rhel, thereby over-ridding whatever was received by dhcp but upon further investigation, in the Ubuntu instances, cloud-init sets the hostname after dhclient as well. The difference seems to be that in the Ubuntu scenario, cloud-init does something different.

The version of cloud-init on RHEL 7.5 is 0.7.9. The version of cloud-init on Ubuntu 18.04 is 18.4.

We were able to work around the problem by sending this in userdata:

  #cloud-config
  preserve_hostname: true

This causes the proper behavior in RHEL and doesn't change the behavior in Ubuntu.

Revision history for this message
Ryan Harper (raharper) wrote :

Have you had a chance to file a bug against RHEL's cloud-init, or test a more recent release? We also have a daily build of cloud-init for centos which you could try to see if the issue remains or needs further work.

https://copr.fedorainfracloud.org/coprs/g/cloud-init/cloud-init-dev/

Changed in cloud-init:
status: New → Incomplete
Revision history for this message
nafeiyang (nafeiy) wrote :

I have not working on this project for a long time. Will forward to colleagues who still work on this to have a check.

Revision history for this message
Launchpad Janitor (janitor) wrote :

[Expired for cloud-init because there has been no activity for 60 days.]

Changed in cloud-init:
status: Incomplete → Expired
Revision history for this message
James Falcon (falcojr) wrote :
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.