compatibility fixes for Fedora and RHEL

This patch fixes issues in Fedora 18 (and upcoming RHEL 7) which are
present due to their use of systemd:

 - store locale configuration in /etc/locale.conf
 - store hostname in /etc/hostname
 - use a symlink for /etc/localtime (prior code would set the timezone
   but corrupt data in /usr/share/zoneinfo due to presence of symlink)

It also contains fixes for issues unrelated to systemd adoption:

 - explicitly scan /dev/sr0 with blkid in order to get the optical drive
   in the blkid cache.  This prevents an issue on systems running 2.6
   kernels (such as RHEL 6) in which config disks on some devices won't
   be detected unless the device has previously been queried.
    (For reference, see https://patchwork.kernel.org/patch/1770241/)
 - append a newline when rewriting sysconfig files, as this is customary
   text configuration file formatting and is expected by some parsers
   (such as the ifcfg-rh plugin for NetworkManager)
This commit is contained in:
Greg Padgett 2013-03-26 17:48:40 -04:00
parent ff7b13a6e1
commit 20711e97a3
5 changed files with 63 additions and 22 deletions

View File

@ -47,8 +47,10 @@ 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"
systemd_hostname_conf_fn = "/etc/hostname"
network_script_tpl = '/etc/sysconfig/network-scripts/ifcfg-%s'
resolve_conf_fn = "/etc/resolv.conf"
tz_local_fn = "/etc/localtime"
@ -143,21 +145,36 @@ class Distro(distros.Distro):
]
if not exists:
lines.insert(0, util.make_header())
util.write_file(fn, "\n".join(lines), 0644)
util.write_file(fn, "\n".join(lines) + "\n", 0644)
def _dist_uses_systemd(self):
# Fedora 18 and RHEL 7 were the first adopters in their series
(dist, vers) = util.system_info()['dist'][:2]
major = (int)(vers.split('.')[0])
return ((dist.startswith('Red Hat Enterprise Linux') and major >= 7)
or (dist.startswith('Fedora') and major >= 18))
def apply_locale(self, locale, out_fn=None):
if not out_fn:
out_fn = self.locale_conf_fn
if self._dist_uses_systemd():
if not out_fn:
out_fn = self.systemd_locale_conf_fn
out_fn = self.systemd_locale_conf_fn
else:
if not out_fn:
out_fn = self.locale_conf_fn
locale_cfg = {
'LANG': locale,
}
self._update_sysconfig_file(out_fn, locale_cfg)
def _write_hostname(self, hostname, out_fn):
host_cfg = {
'HOSTNAME': hostname,
}
self._update_sysconfig_file(out_fn, host_cfg)
if self._dist_uses_systemd():
util.subp(['hostnamectl', 'set-hostname', str(hostname)])
else:
host_cfg = {
'HOSTNAME': hostname,
}
self._update_sysconfig_file(out_fn, host_cfg)
def _select_hostname(self, hostname, fqdn):
# See: http://bit.ly/TwitgL
@ -167,15 +184,25 @@ class Distro(distros.Distro):
return hostname
def _read_system_hostname(self):
return (self.network_conf_fn,
self._read_hostname(self.network_conf_fn))
if self._dist_uses_systemd():
host_fn = self.systemd_hostname_conf_fn
else:
host_fn = self.hostname_conf_fn
return (host_fn, self._read_hostname(host_fn))
def _read_hostname(self, filename, default=None):
(_exists, contents) = self._read_conf(filename)
if 'HOSTNAME' in contents:
return contents['HOSTNAME']
if self._dist_uses_systemd():
(out, _err) = util.subp(['hostname'])
if len(out):
return out
else:
return default
else:
return default
(_exists, contents) = self._read_conf(filename)
if 'HOSTNAME' in contents:
return contents['HOSTNAME']
else:
return default
def _read_conf(self, fn):
exists = False
@ -200,13 +227,19 @@ class Distro(distros.Distro):
if not os.path.isfile(tz_file):
raise RuntimeError(("Invalid timezone %s,"
" no file found at %s") % (tz, tz_file))
# Adjust the sysconfig clock zone setting
clock_cfg = {
'ZONE': str(tz),
}
self._update_sysconfig_file(self.clock_conf_fn, clock_cfg)
# This ensures that the correct tz will be used for the system
util.copy(tz_file, self.tz_local_fn)
if self._dist_uses_systemd():
# Currently, timedatectl complains if invoked during startup
# so for compatibility, create the link manually.
util.del_file(self.tz_local_fn)
util.sym_link(tz_file, self.tz_local_fn)
else:
# Adjust the sysconfig clock zone setting
clock_cfg = {
'ZONE': str(tz),
}
self._update_sysconfig_file(self.clock_conf_fn, clock_cfg)
# This ensures that the correct tz will be used for the system
util.copy(tz_file, self.tz_local_fn)
def package_command(self, command, args=None, pkgs=None):
if pkgs is None:

View File

@ -258,6 +258,9 @@ def find_candidate_devs():
* labeled with 'config-2'
"""
# Query optical drive to get it in blkid cache for 2.6 kernels
util.find_devs_with(path="/dev/sr0")
by_fstype = (util.find_devs_with("TYPE=vfat") +
util.find_devs_with("TYPE=iso9660"))
by_label = util.find_devs_with("LABEL=config-2")

View File

@ -87,6 +87,9 @@ class DataSourceNoCloud(sources.DataSource):
label = self.ds_cfg.get('fs_label', "cidata")
if label is not None:
# Query optical drive to get it in blkid cache for 2.6 kernels
util.find_devs_with(path="/dev/sr0")
fslist = util.find_devs_with("TYPE=vfat")
fslist.extend(util.find_devs_with("TYPE=iso9660"))

View File

@ -408,6 +408,7 @@ def system_info():
'release': platform.release(),
'python': platform.python_version(),
'uname': platform.uname(),
'dist': platform.linux_distribution(),
}

View File

@ -259,8 +259,9 @@ class TestConfigDriveDataSource(MockerTestCase):
def test_find_candidates(self):
devs_with_answers = {}
def my_devs_with(criteria):
return devs_with_answers[criteria]
def my_devs_with(*args, **kwargs):
criteria = args[0] if len(args) else kwargs.pop('criteria', None)
return devs_with_answers.get(criteria, [])
def my_is_partition(dev):
return dev[-1] in "0123456789" and not dev.startswith("sr")