summaryrefslogtreecommitdiff
path: root/cloudinit/distros/rhel.py
diff options
context:
space:
mode:
authorJoshua Harlow <harlowja@yahoo-inc.com>2012-10-10 16:21:22 -0700
committerJoshua Harlow <harlowja@yahoo-inc.com>2012-10-10 16:21:22 -0700
commit80eb53deb9f80694c5fd0e0190197de1ff496716 (patch)
treed67bcef6beca34fe371be003c23007bbd19f7f92 /cloudinit/distros/rhel.py
parentf8b71af537aab3aef04a1e5ceba19e90a1445948 (diff)
downloadvyos-cloud-init-80eb53deb9f80694c5fd0e0190197de1ff496716.tar.gz
vyos-cloud-init-80eb53deb9f80694c5fd0e0190197de1ff496716.zip
System config niceness!
1. Move out the old helpers that provided oop access/reading/writing to various standard conf files and place those in parsers instead. 2. Unify the 'update_hostname' which varied very little between distros and make it generic so that subclasses can only provide a couple of functions to obtain the hostname updating functionality 3. Implement that new set of functions in rhel/debian 4. Use the new parsers chop_comment function for similar use cases as well as add a new utils make header function that can be used for configuration files that are newly generated to use (less duplication here of this same thing being done in multiple places. 5. Add in a distro '_apply_hostname' which calls out to the 'hostname' program to set the system hostname (more duplication elimination). 6. Make the 'constant' filenames being written to for configuration by the various distros be instance members instead of string constants 'sprinkled' throughout the code
Diffstat (limited to 'cloudinit/distros/rhel.py')
-rw-r--r--cloudinit/distros/rhel.py149
1 files changed, 32 insertions, 117 deletions
diff --git a/cloudinit/distros/rhel.py b/cloudinit/distros/rhel.py
index 13fd5ec8..21f2216e 100644
--- a/cloudinit/distros/rhel.py
+++ b/cloudinit/distros/rhel.py
@@ -23,41 +23,17 @@
import os
from cloudinit import distros
-from cloudinit.distros import helpers as d_helpers
+
+from cloudinit.distros.parsers import (resolv_conf, quoting_conf)
from cloudinit import helpers
from cloudinit import log as logging
from cloudinit import util
-from cloudinit import version
from cloudinit.settings import PER_INSTANCE
LOG = logging.getLogger(__name__)
-NETWORK_FN_TPL = '/etc/sysconfig/network-scripts/ifcfg-%s'
-
-# See: http://tiny.cc/6r99fw
-# For what alot of these files that are being written
-# are and the format of them
-
-# This library is used to parse/write
-# out the various sysconfig files edited
-#
-# It has to be slightly modified though
-# to ensure that all values are quoted
-# since these configs are usually sourced into
-# bash scripts...
-from configobj import ConfigObj
-
-# See: http://tiny.cc/oezbgw
-D_QUOTE_CHARS = {
- "\"": "\\\"",
- "(": "\\(",
- ")": "\\)",
- "$": '\$',
- '`': '\`',
-}
-
def _make_sysconfig_bool(val):
if val:
@@ -66,12 +42,15 @@ def _make_sysconfig_bool(val):
return 'no'
-def _make_header():
- ci_ver = version.version_string()
- return '# Created by cloud-init v. %s' % (ci_ver)
-
-
class Distro(distros.Distro):
+ # See: http://tiny.cc/6r99fw
+ clock_conf_fn = "/etc/sysconfig/clock"
+ locale_conf_fn = '/etc/sysconfig/i18n'
+ network_conf_fn = "/etc/sysconfig/network"
+ network_script_tpl = '/etc/sysconfig/network-scripts/ifcfg-%s'
+ resolve_conf_fn = "/etc/resolv.conf"
+ tz_local_fn = "/etc/localtime"
+ tz_zone_dir = "/usr/share/zoneinfo"
def __init__(self, name, cfg, paths):
distros.Distro.__init__(self, name, cfg, paths)
@@ -84,14 +63,14 @@ class Distro(distros.Distro):
self.package_command('install', pkglist)
def _adjust_resolve(self, dns_servers, search_servers):
- r_conf = d_helpers.ResolvConf(util.load_file("/etc/resolv.conf"))
+ r_conf = resolv_conf.ResolvConf(util.load_file(self.resolve_conf_fn))
try:
r_conf.parse()
except IOError:
util.logexc(LOG,
"Failed at parsing %s reverting to an empty instance",
- "/etc/resolv.conf")
- r_conf = d_helpers.ResolvConf('')
+ self.resolve_conf_fn)
+ r_conf = resolv_conf.ResolvConf('')
r_conf.parse()
if dns_servers:
for s in dns_servers:
@@ -105,7 +84,7 @@ class Distro(distros.Distro):
r_conf.add_search_domain(s)
except ValueError:
util.logexc(LOG, "Failed at adding search domain %s", s)
- util.write_file("/etc/resolv.conf", str(r_conf), 0644)
+ util.write_file(self.resolve_conf_fn, str(r_conf), 0644)
def _write_network(self, settings):
# TODO(harlowja) fix this... since this is the ubuntu format
@@ -117,7 +96,7 @@ class Distro(distros.Distro):
searchservers = []
dev_names = entries.keys()
for (dev, info) in entries.iteritems():
- net_fn = NETWORK_FN_TPL % (dev)
+ net_fn = self.network_script_tpl % (dev)
net_cfg = {
'DEVICE': dev,
'NETMASK': info.get('netmask'),
@@ -134,12 +113,12 @@ class Distro(distros.Distro):
if 'dns-search' in info:
searchservers.extend(info['dns-search'])
if nameservers or searchservers:
- self._write_resolve(nameservers, searchservers)
+ self._adjust_resolve(nameservers, searchservers)
if dev_names:
net_cfg = {
'NETWORKING': _make_sysconfig_bool(True),
}
- self._update_sysconfig_file("/etc/sysconfig/network", net_cfg)
+ self._update_sysconfig_file(self.network_conf_fn, net_cfg)
return dev_names
def _update_sysconfig_file(self, fn, adjustments, allow_empty=False):
@@ -158,17 +137,16 @@ class Distro(distros.Distro):
if updated_am:
lines = contents.write()
if not exists:
- lines.insert(0, _make_header())
+ lines.insert(0, util.make_header())
util.write_file(fn, "\n".join(lines), 0644)
def set_hostname(self, hostname):
- self._write_hostname(hostname, '/etc/sysconfig/network')
- LOG.debug("Setting hostname to %s", hostname)
- util.subp(['hostname', hostname])
+ self._write_hostname(hostname, self.network_conf_fn)
+ self._apply_hostname(hostname)
def apply_locale(self, locale, out_fn=None):
if not out_fn:
- out_fn = '/etc/sysconfig/i18n'
+ out_fn = self.locale_conf_fn
locale_cfg = {
'LANG': locale,
}
@@ -180,30 +158,9 @@ class Distro(distros.Distro):
}
self._update_sysconfig_file(out_fn, host_cfg)
- def update_hostname(self, hostname, prev_file):
- hostname_prev = self._read_hostname(prev_file)
- hostname_in_sys = self._read_hostname("/etc/sysconfig/network")
- update_files = []
- if not hostname_prev or hostname_prev != hostname:
- update_files.append(prev_file)
- if (not hostname_in_sys or
- (hostname_in_sys == hostname_prev
- and hostname_in_sys != hostname)):
- update_files.append("/etc/sysconfig/network")
- for fn in update_files:
- try:
- self._write_hostname(hostname, fn)
- except:
- util.logexc(LOG, "Failed to write hostname %s to %s",
- hostname, fn)
- if (hostname_in_sys and hostname_prev and
- hostname_in_sys != hostname_prev):
- LOG.debug(("%s differs from /etc/sysconfig/network."
- " Assuming user maintained hostname."), prev_file)
- if "/etc/sysconfig/network" in update_files:
- # Only do this if we are running in non-adjusted root mode
- LOG.debug("Setting hostname to %s", hostname)
- util.subp(['hostname', hostname])
+ def _read_system_hostname(self):
+ return (self.network_conf_fn,
+ self._read_hostname(self.network_conf_fn))
def _read_hostname(self, filename, default=None):
(_exists, contents) = self._read_conf(filename)
@@ -219,7 +176,8 @@ class Distro(distros.Distro):
exists = True
else:
contents = []
- return (exists, QuotingConfigObj(contents))
+ return (exists,
+ quoting_conf.QuotingConfigObj(contents))
def _bring_up_interfaces(self, device_names):
if device_names and 'all' in device_names:
@@ -228,17 +186,19 @@ class Distro(distros.Distro):
return distros.Distro._bring_up_interfaces(self, device_names)
def set_timezone(self, tz):
- tz_file = os.path.join("/usr/share/zoneinfo", tz)
+ # Ensure that this timezone is actually
+ # available on this system, if not give up
+ tz_file = os.path.join(self.tz_zone_dir, str(tz))
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': tz,
+ 'ZONE': str(tz),
}
- self._update_sysconfig_file("/etc/sysconfig/clock", clock_cfg)
+ 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, "/etc/localtime")
+ util.copy(tz_file, self.tz_local_fn)
def package_command(self, command, args=None):
cmd = ['yum']
@@ -262,51 +222,6 @@ class Distro(distros.Distro):
["makecache"], freq=PER_INSTANCE)
-# This class helps adjust the configobj
-# writing to ensure that when writing a k/v
-# on a line, that they are properly quoted
-# and have no spaces between the '=' sign.
-# - This is mainly due to the fact that
-# the sysconfig scripts are often sourced
-# directly into bash/shell scripts so ensure
-# that it works for those types of use cases.
-class QuotingConfigObj(ConfigObj):
- def __init__(self, lines):
- ConfigObj.__init__(self, lines,
- interpolation=False,
- write_empty_values=True)
-
- def _quote_posix(self, text):
- if not text:
- return ''
- for (k, v) in D_QUOTE_CHARS.iteritems():
- text = text.replace(k, v)
- return '"%s"' % (text)
-
- def _quote_special(self, text):
- if text.lower() in ['yes', 'no', 'true', 'false']:
- return text
- else:
- return self._quote_posix(text)
-
- def _write_line(self, indent_string, entry, this_entry, comment):
- # Ensure it is formatted fine for
- # how these sysconfig scripts are used
- val = self._decode_element(self._quote(this_entry))
- # Single quoted strings should
- # always work.
- if not val.startswith("'"):
- # Perform any special quoting
- val = self._quote_special(val)
- key = self._decode_element(self._quote(entry, multiline=False))
- cmnt = self._decode_element(comment)
- return '%s%s%s%s%s' % (indent_string,
- key,
- "=",
- val,
- cmnt)
-
-
# This is a util function to translate a ubuntu /etc/network/interfaces 'blob'
# to a rhel equiv. that can then be written to /etc/sysconfig/network-scripts/
# TODO(harlowja) remove when we have python-netcf active...