summaryrefslogtreecommitdiff
path: root/cloudinit/distros
diff options
context:
space:
mode:
authorScott Moser <smoser@ubuntu.com>2016-04-04 12:07:19 -0400
committerScott Moser <smoser@ubuntu.com>2016-04-04 12:07:19 -0400
commit7d8a3194552387fa9e21216bcd9a3bfc76fa2b04 (patch)
treec8dc45b013208a4e5e09e6ade63b3b5994f80aa3 /cloudinit/distros
parent93f5af9f5075a416c65c1d0350c374e16f32f0d5 (diff)
parent210b041b2fead7a57af91f60a6f89d9e5aa1ed4a (diff)
downloadvyos-cloud-init-7d8a3194552387fa9e21216bcd9a3bfc76fa2b04.tar.gz
vyos-cloud-init-7d8a3194552387fa9e21216bcd9a3bfc76fa2b04.zip
merge with trunk
Diffstat (limited to 'cloudinit/distros')
-rw-r--r--cloudinit/distros/__init__.py173
-rw-r--r--cloudinit/distros/arch.py10
-rw-r--r--cloudinit/distros/debian.py20
-rw-r--r--cloudinit/distros/freebsd.py13
-rw-r--r--cloudinit/distros/gentoo.py6
-rw-r--r--cloudinit/distros/net_util.py2
-rw-r--r--cloudinit/distros/parsers/hostname.py4
-rw-r--r--cloudinit/distros/parsers/hosts.py2
-rw-r--r--cloudinit/distros/parsers/resolv_conf.py4
-rw-r--r--cloudinit/distros/parsers/sys_conf.py12
-rw-r--r--cloudinit/distros/rhel.py19
-rw-r--r--cloudinit/distros/rhel_util.py4
-rw-r--r--cloudinit/distros/sles.py4
13 files changed, 172 insertions, 101 deletions
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index 5eab780b..418421b9 100644
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -21,12 +21,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from StringIO import StringIO
+import six
+from six import StringIO
import abc
-import itertools
import os
import re
+import stat
from cloudinit import importer
from cloudinit import log as logging
@@ -36,6 +37,7 @@ from cloudinit import util
from cloudinit.distros.parsers import hosts
+
OSFAMILIES = {
'debian': ['debian', 'ubuntu'],
'redhat': ['fedora', 'rhel'],
@@ -73,6 +75,9 @@ class Distro(object):
# to write this blob out in a distro format
raise NotImplementedError()
+ def _write_network_config(self, settings):
+ raise NotImplementedError()
+
def _find_tz_file(self, tz):
tz_file = os.path.join(self.tz_zone_dir, str(tz))
if not os.path.isfile(tz_file):
@@ -88,6 +93,13 @@ class Distro(object):
self._write_hostname(writeable_hostname, self.hostname_conf_fn)
self._apply_hostname(writeable_hostname)
+ def uses_systemd(self):
+ try:
+ res = os.lstat('/run/systemd/system')
+ return stat.S_ISDIR(res.st_mode)
+ except:
+ return False
+
@abc.abstractmethod
def package_command(self, cmd, args=None, pkgs=None):
raise NotImplementedError()
@@ -108,12 +120,11 @@ class Distro(object):
arch = self.get_primary_arch()
return _get_arch_package_mirror_info(mirror_info, arch)
- def get_package_mirror_info(self, arch=None,
- availability_zone=None):
+ def get_package_mirror_info(self, arch=None, data_source=None):
# This resolves the package_mirrors config option
# down to a single dict of {mirror_name: mirror_url}
arch_info = self._get_arch_package_mirror_info(arch)
- return _get_package_mirror_info(availability_zone=availability_zone,
+ return _get_package_mirror_info(data_source=data_source,
mirror_info=arch_info)
def apply_network(self, settings, bring_up=True):
@@ -124,6 +135,14 @@ class Distro(object):
return self._bring_up_interfaces(dev_names)
return False
+ def apply_network_config(self, netconfig, bring_up=False):
+ # Write it out
+ dev_names = self._write_network_config(netconfig)
+ # Now try to bring them up
+ if bring_up:
+ return self._bring_up_interfaces(dev_names)
+ return False
+
@abc.abstractmethod
def apply_locale(self, locale, out_fn=None):
raise NotImplementedError()
@@ -203,10 +222,19 @@ class Distro(object):
# If the system hostname is different than the previous
# one or the desired one lets update it as well
- if (not sys_hostname) or (sys_hostname == prev_hostname
- and sys_hostname != hostname):
+ if ((not sys_hostname) or (sys_hostname == prev_hostname and
+ sys_hostname != hostname)):
update_files.append(sys_fn)
+ # If something else has changed the hostname after we set it
+ # initially, we should not overwrite those changes (we should
+ # only be setting the hostname once per instance)
+ if (sys_hostname and prev_hostname and
+ sys_hostname != prev_hostname):
+ LOG.info("%s differs from %s, assuming user maintained hostname.",
+ prev_hostname_fn, sys_fn)
+ return
+
# Remove duplicates (incase the previous config filename)
# is the same as the system config filename, don't bother
# doing it twice
@@ -221,11 +249,6 @@ class Distro(object):
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)
-
# If the system hostname file name was provided set the
# non-fqdn as the transient hostname.
if sys_fn in update_files:
@@ -272,12 +295,12 @@ class Distro(object):
if header:
contents.write("%s\n" % (header))
contents.write("%s\n" % (eh))
- util.write_file(self.hosts_fn, contents.getvalue(), mode=0644)
+ util.write_file(self.hosts_fn, contents.getvalue(), mode=0o644)
def _bring_up_interface(self, device_name):
cmd = ['ifup', device_name]
LOG.debug("Attempting to run bring up interface %s using command %s",
- device_name, cmd)
+ device_name, cmd)
try:
(_out, err) = util.subp(cmd)
if len(err):
@@ -307,6 +330,11 @@ class Distro(object):
LOG.info("User %s already exists, skipping." % name)
return
+ if 'create_groups' in kwargs:
+ create_groups = kwargs.pop('create_groups')
+ else:
+ create_groups = True
+
adduser_cmd = ['useradd', name]
log_adduser_cmd = ['useradd', name]
@@ -317,6 +345,7 @@ class Distro(object):
"gecos": '--comment',
"homedir": '--home',
"primary_group": '--gid',
+ "uid": '--uid',
"groups": '--groups',
"passwd": '--password',
"shell": '--shell',
@@ -333,8 +362,21 @@ class Distro(object):
redact_opts = ['passwd']
+ groups = kwargs.get('groups')
+ if groups:
+ if isinstance(groups, (list, tuple)):
+ kwargs['groups'] = ",".join(groups)
+ else:
+ groups = groups.split(",")
+
+ if create_groups:
+ for group in kwargs.get('groups').split(","):
+ if not util.is_group(group):
+ self.create_group(group)
+ LOG.debug("created group %s for user %s", name, group)
+
# Check the values and create the command
- for key, val in kwargs.iteritems():
+ for key, val in kwargs.items():
if key in adduser_opts and val and isinstance(val, str):
adduser_cmd.extend([adduser_opts[key], val])
@@ -380,6 +422,10 @@ class Distro(object):
if 'plain_text_passwd' in kwargs and kwargs['plain_text_passwd']:
self.set_passwd(name, kwargs['plain_text_passwd'])
+ # Set password if hashed password is provided and non-empty
+ if 'hashed_passwd' in kwargs and kwargs['hashed_passwd']:
+ self.set_passwd(name, kwargs['hashed_passwd'], hashed=True)
+
# Default locking down the account. 'lock_passwd' defaults to True.
# lock account unless lock_password is False.
if kwargs.get('lock_passwd', True):
@@ -393,7 +439,7 @@ class Distro(object):
if 'ssh_authorized_keys' in kwargs:
# Try to handle this in a smart manner.
keys = kwargs['ssh_authorized_keys']
- if isinstance(keys, (basestring, str)):
+ if isinstance(keys, six.string_types):
keys = [keys]
if isinstance(keys, dict):
keys = list(keys.values())
@@ -468,7 +514,7 @@ class Distro(object):
util.make_header(base="added"),
"#includedir %s" % (path), '']
sudoers_contents = "\n".join(lines)
- util.write_file(sudo_base, sudoers_contents, 0440)
+ util.write_file(sudo_base, sudoers_contents, 0o440)
else:
lines = ['', util.make_header(base="added"),
"#includedir %s" % (path), '']
@@ -478,7 +524,7 @@ class Distro(object):
except IOError as e:
util.logexc(LOG, "Failed to write %s", sudo_base)
raise e
- util.ensure_dir(path, 0750)
+ util.ensure_dir(path, 0o750)
def write_sudo_rules(self, user, rules, sudo_file=None):
if not sudo_file:
@@ -491,7 +537,7 @@ class Distro(object):
if isinstance(rules, (list, tuple)):
for rule in rules:
lines.append("%s %s" % (user, rule))
- elif isinstance(rules, (basestring, str)):
+ elif isinstance(rules, six.string_types):
lines.append("%s %s" % (user, rules))
else:
msg = "Can not create sudoers rule addition with type %r"
@@ -506,7 +552,7 @@ class Distro(object):
content,
]
try:
- util.write_file(sudo_file, "\n".join(contents), 0440)
+ util.write_file(sudo_file, "\n".join(contents), 0o440)
except IOError as e:
util.logexc(LOG, "Failed to write sudoers file %s", sudo_file)
raise e
@@ -517,8 +563,10 @@ class Distro(object):
util.logexc(LOG, "Failed to append sudoers file %s", sudo_file)
raise e
- def create_group(self, name, members):
+ def create_group(self, name, members=None):
group_add_cmd = ['groupadd', name]
+ if not members:
+ members = []
# Check if group exists, and then add it doesn't
if util.is_group(name):
@@ -528,21 +576,21 @@ class Distro(object):
util.subp(group_add_cmd)
LOG.info("Created new group %s" % name)
except Exception:
- util.logexc("Failed to create group %s", name)
+ util.logexc(LOG, "Failed to create group %s", name)
# Add members to the group, if so defined
if len(members) > 0:
for member in members:
if not util.is_user(member):
LOG.warn("Unable to add group member '%s' to group '%s'"
- "; user does not exist.", member, name)
+ "; user does not exist.", member, name)
continue
util.subp(['usermod', '-a', '-G', name, member])
LOG.info("Added user '%s' to group '%s'" % (member, name))
-def _get_package_mirror_info(mirror_info, availability_zone=None,
+def _get_package_mirror_info(mirror_info, data_source=None,
mirror_filter=util.search_for_mirror):
# given a arch specific 'mirror_info' entry (from package_mirrors)
# search through the 'search' entries, and fallback appropriately
@@ -550,21 +598,28 @@ def _get_package_mirror_info(mirror_info, availability_zone=None,
if not mirror_info:
mirror_info = {}
- ec2_az_re = ("^[a-z][a-z]-(%s)-[1-9][0-9]*[a-z]$" %
- "north|northeast|east|southeast|south|southwest|west|northwest")
+ # ec2 availability zones are named cc-direction-[0-9][a-d] (us-east-1b)
+ # the region is us-east-1. so region = az[0:-1]
+ directions_re = '|'.join([
+ 'central', 'east', 'north', 'northeast', 'northwest',
+ 'south', 'southeast', 'southwest', 'west'])
+ ec2_az_re = ("^[a-z][a-z]-(%s)-[1-9][0-9]*[a-z]$" % directions_re)
subst = {}
- if availability_zone:
- subst['availability_zone'] = availability_zone
+ if data_source and data_source.availability_zone:
+ subst['availability_zone'] = data_source.availability_zone
+
+ if re.match(ec2_az_re, data_source.availability_zone):
+ subst['ec2_region'] = "%s" % data_source.availability_zone[0:-1]
- if availability_zone and re.match(ec2_az_re, availability_zone):
- subst['ec2_region'] = "%s" % availability_zone[0:-1]
+ if data_source and data_source.region:
+ subst['region'] = data_source.region
results = {}
- for (name, mirror) in mirror_info.get('failsafe', {}).iteritems():
+ for (name, mirror) in mirror_info.get('failsafe', {}).items():
results[name] = mirror
- for (name, searchlist) in mirror_info.get('search', {}).iteritems():
+ for (name, searchlist) in mirror_info.get('search', {}).items():
mirrors = []
for tmpl in searchlist:
try:
@@ -604,30 +659,30 @@ def _get_arch_package_mirror_info(package_mirrors, arch):
# is the standard form used in the rest
# of cloud-init
def _normalize_groups(grp_cfg):
- if isinstance(grp_cfg, (str, basestring)):
+ if isinstance(grp_cfg, six.string_types):
grp_cfg = grp_cfg.strip().split(",")
- if isinstance(grp_cfg, (list)):
+ if isinstance(grp_cfg, list):
c_grp_cfg = {}
for i in grp_cfg:
- if isinstance(i, (dict)):
+ if isinstance(i, dict):
for k, v in i.items():
if k not in c_grp_cfg:
- if isinstance(v, (list)):
+ if isinstance(v, list):
c_grp_cfg[k] = list(v)
- elif isinstance(v, (basestring, str)):
+ elif isinstance(v, six.string_types):
c_grp_cfg[k] = [v]
else:
raise TypeError("Bad group member type %s" %
type_utils.obj_name(v))
else:
- if isinstance(v, (list)):
+ if isinstance(v, list):
c_grp_cfg[k].extend(v)
- elif isinstance(v, (basestring, str)):
+ elif isinstance(v, six.string_types):
c_grp_cfg[k].append(v)
else:
raise TypeError("Bad group member type %s" %
type_utils.obj_name(v))
- elif isinstance(i, (str, basestring)):
+ elif isinstance(i, six.string_types):
if i not in c_grp_cfg:
c_grp_cfg[i] = []
else:
@@ -635,7 +690,7 @@ def _normalize_groups(grp_cfg):
type_utils.obj_name(i))
grp_cfg = c_grp_cfg
groups = {}
- if isinstance(grp_cfg, (dict)):
+ if isinstance(grp_cfg, dict):
for (grp_name, grp_members) in grp_cfg.items():
groups[grp_name] = util.uniq_merge_sorted(grp_members)
else:
@@ -661,29 +716,29 @@ def _normalize_groups(grp_cfg):
# entry 'default' which will be marked as true
# all other users will be marked as false.
def _normalize_users(u_cfg, def_user_cfg=None):
- if isinstance(u_cfg, (dict)):
+ if isinstance(u_cfg, dict):
ad_ucfg = []
for (k, v) in u_cfg.items():
- if isinstance(v, (bool, int, basestring, str, float)):
+ if isinstance(v, (bool, int, float) + six.string_types):
if util.is_true(v):
ad_ucfg.append(str(k))
- elif isinstance(v, (dict)):
+ elif isinstance(v, dict):
v['name'] = k
ad_ucfg.append(v)
else:
raise TypeError(("Unmappable user value type %s"
" for key %s") % (type_utils.obj_name(v), k))
u_cfg = ad_ucfg
- elif isinstance(u_cfg, (str, basestring)):
+ elif isinstance(u_cfg, six.string_types):
u_cfg = util.uniq_merge_sorted(u_cfg)
users = {}
for user_config in u_cfg:
- if isinstance(user_config, (str, basestring, list)):
+ if isinstance(user_config, (list,) + six.string_types):
for u in util.uniq_merge(user_config):
if u and u not in users:
users[u] = {}
- elif isinstance(user_config, (dict)):
+ elif isinstance(user_config, dict):
if 'name' in user_config:
n = user_config.pop('name')
prev_config = users.get(n) or {}
@@ -784,11 +839,11 @@ def normalize_users_groups(cfg, distro):
old_user = cfg['user']
# Translate it into the format that is more useful
# going forward
- if isinstance(old_user, (basestring, str)):
+ if isinstance(old_user, six.string_types):
old_user = {
'name': old_user,
}
- if not isinstance(old_user, (dict)):
+ if not isinstance(old_user, dict):
LOG.warn(("Format for 'user' key must be a string or "
"dictionary and not %s"), type_utils.obj_name(old_user))
old_user = {}
@@ -813,7 +868,7 @@ def normalize_users_groups(cfg, distro):
default_user_config = util.mergemanydict([old_user, distro_user_config])
base_users = cfg.get('users', [])
- if not isinstance(base_users, (list, dict, str, basestring)):
+ if not isinstance(base_users, (list, dict) + six.string_types):
LOG.warn(("Format for 'users' key must be a comma separated string"
" or a dictionary or a list and not %s"),
type_utils.obj_name(base_users))
@@ -822,12 +877,12 @@ def normalize_users_groups(cfg, distro):
if old_user:
# Ensure that when user: is provided that this user
# always gets added (as the default user)
- if isinstance(base_users, (list)):
+ if isinstance(base_users, list):
# Just add it on at the end...
base_users.append({'name': 'default'})
- elif isinstance(base_users, (dict)):
+ elif isinstance(base_users, dict):
base_users['default'] = dict(base_users).get('default', True)
- elif isinstance(base_users, (str, basestring)):
+ elif isinstance(base_users, six.string_types):
# Just append it on to be re-parsed later
base_users += ",default"
@@ -852,11 +907,11 @@ def extract_default(users, default_name=None, default_config=None):
return config['default']
tmp_users = users.items()
- tmp_users = dict(itertools.ifilter(safe_find, tmp_users))
+ tmp_users = dict(filter(safe_find, tmp_users))
if not tmp_users:
return (default_name, default_config)
else:
- name = tmp_users.keys()[0]
+ name = list(tmp_users)[0]
config = tmp_users[name]
config.pop('default', None)
return (name, config)
@@ -866,7 +921,7 @@ def fetch(name):
locs, looked_locs = importer.find_module(name, ['', __name__], ['Distro'])
if not locs:
raise ImportError("No distribution found for distro %s (searched %s)"
- % (name, looked_locs))
+ % (name, looked_locs))
mod = importer.import_module(locs[0])
cls = getattr(mod, 'Distro')
return cls
@@ -877,5 +932,9 @@ def set_etc_timezone(tz, tz_file=None, tz_conf="/etc/timezone",
util.write_file(tz_conf, str(tz).rstrip() + "\n")
# This ensures that the correct tz will be used for the system
if tz_local and tz_file:
- util.copy(tz_file, tz_local)
+ # use a symlink if there exists a symlink or tz_local is not present
+ if os.path.islink(tz_local) or not os.path.exists(tz_local):
+ os.symlink(tz_file, tz_local)
+ else:
+ util.copy(tz_file, tz_local)
return
diff --git a/cloudinit/distros/arch.py b/cloudinit/distros/arch.py
index 68bf1aab..93a2e008 100644
--- a/cloudinit/distros/arch.py
+++ b/cloudinit/distros/arch.py
@@ -66,7 +66,7 @@ class Distro(distros.Distro):
settings, entries)
dev_names = entries.keys()
# Format for netctl
- for (dev, info) in entries.iteritems():
+ for (dev, info) in entries.items():
nameservers = []
net_fn = self.network_conf_dir + dev
net_cfg = {
@@ -74,7 +74,7 @@ class Distro(distros.Distro):
'Interface': dev,
'IP': info.get('bootproto'),
'Address': "('%s/%s')" % (info.get('address'),
- info.get('netmask')),
+ info.get('netmask')),
'Gateway': info.get('gateway'),
'DNS': str(tuple(info.get('dns-nameservers'))).replace(',', '')
}
@@ -86,7 +86,7 @@ class Distro(distros.Distro):
if nameservers:
util.write_file(self.resolve_conf_fn,
- convert_resolv_conf(nameservers))
+ convert_resolv_conf(nameservers))
return dev_names
@@ -102,7 +102,7 @@ class Distro(distros.Distro):
def _bring_up_interface(self, device_name):
cmd = ['netctl', 'restart', device_name]
LOG.debug("Attempting to run bring up interface %s using command %s",
- device_name, cmd)
+ device_name, cmd)
try:
(_out, err) = util.subp(cmd)
if len(err):
@@ -129,7 +129,7 @@ class Distro(distros.Distro):
if not conf:
conf = HostnameConf('')
conf.set_hostname(your_hostname)
- util.write_file(out_fn, str(conf), 0644)
+ util.write_file(out_fn, conf, 0o644)
def _read_system_hostname(self):
sys_hostname = self._read_hostname(self.hostname_conf_fn)
diff --git a/cloudinit/distros/debian.py b/cloudinit/distros/debian.py
index b09eb094..5d7e6cfc 100644
--- a/cloudinit/distros/debian.py
+++ b/cloudinit/distros/debian.py
@@ -26,6 +26,7 @@ from cloudinit import distros
from cloudinit import helpers
from cloudinit import log as logging
from cloudinit import util
+from cloudinit import net
from cloudinit.distros.parsers.hostname import HostnameConf
@@ -45,7 +46,8 @@ APT_GET_WRAPPER = {
class Distro(distros.Distro):
hostname_conf_fn = "/etc/hostname"
locale_conf_fn = "/etc/default/locale"
- network_conf_fn = "/etc/network/interfaces"
+ network_conf_fn = "/etc/network/interfaces.d/50-cloud-init.cfg"
+ links_prefix = "/etc/systemd/network/50-cloud-init-"
def __init__(self, name, cfg, paths):
distros.Distro.__init__(self, name, cfg, paths)
@@ -76,6 +78,15 @@ class Distro(distros.Distro):
util.write_file(self.network_conf_fn, settings)
return ['all']
+ def _write_network_config(self, netconfig):
+ ns = net.parse_net_config_data(netconfig)
+ net.render_network_state(target="/", network_state=ns,
+ eni=self.network_conf_fn,
+ links_prefix=self.links_prefix,
+ netrules=None)
+ util.del_file("/etc/network/interfaces.d/eth0.cfg")
+ return []
+
def _bring_up_interfaces(self, device_names):
use_all = False
for d in device_names:
@@ -97,7 +108,7 @@ class Distro(distros.Distro):
if not conf:
conf = HostnameConf('')
conf.set_hostname(your_hostname)
- util.write_file(out_fn, str(conf), 0644)
+ util.write_file(out_fn, str(conf), 0o644)
def _read_system_hostname(self):
sys_hostname = self._read_hostname(self.hostname_conf_fn)
@@ -159,8 +170,9 @@ class Distro(distros.Distro):
# Allow the output of this to flow outwards (ie not be captured)
util.log_time(logfunc=LOG.debug,
- msg="apt-%s [%s]" % (command, ' '.join(cmd)), func=util.subp,
- args=(cmd,), kwargs={'env': e, 'capture': False})
+ msg="apt-%s [%s]" % (command, ' '.join(cmd)),
+ func=util.subp,
+ args=(cmd,), kwargs={'env': e, 'capture': False})
def update_package_sources(self):
self._runner.run("update-sources", self.package_command,
diff --git a/cloudinit/distros/freebsd.py b/cloudinit/distros/freebsd.py
index c59a074b..91bf4a4e 100644
--- a/cloudinit/distros/freebsd.py
+++ b/cloudinit/distros/freebsd.py
@@ -17,8 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-
-from StringIO import StringIO
+import six
+from six import StringIO
import re
@@ -207,8 +207,9 @@ class Distro(distros.Distro):
redact_opts = ['passwd']
- for key, val in kwargs.iteritems():
- if key in adduser_opts and val and isinstance(val, basestring):
+ for key, val in kwargs.items():
+ if (key in adduser_opts and val and
+ isinstance(val, six.string_types)):
adduser_cmd.extend([adduser_opts[key], val])
# Redact certain fields from the logs
@@ -287,7 +288,7 @@ class Distro(distros.Distro):
nameservers = []
searchdomains = []
dev_names = entries.keys()
- for (device, info) in entries.iteritems():
+ for (device, info) in entries.items():
# Skip the loopback interface.
if device.startswith('lo'):
continue
@@ -339,7 +340,7 @@ class Distro(distros.Distro):
resolvconf.add_search_domain(domain)
except ValueError:
util.logexc(LOG, "Failed to add search domain %s", domain)
- util.write_file(self.resolv_conf_fn, str(resolvconf), 0644)
+ util.write_file(self.resolv_conf_fn, str(resolvconf), 0o644)
return dev_names
diff --git a/cloudinit/distros/gentoo.py b/cloudinit/distros/gentoo.py
index 09dd0d73..6267dd6e 100644
--- a/cloudinit/distros/gentoo.py
+++ b/cloudinit/distros/gentoo.py
@@ -66,7 +66,7 @@ class Distro(distros.Distro):
def _bring_up_interface(self, device_name):
cmd = ['/etc/init.d/net.%s' % device_name, 'restart']
LOG.debug("Attempting to run bring up interface %s using command %s",
- device_name, cmd)
+ device_name, cmd)
try:
(_out, err) = util.subp(cmd)
if len(err):
@@ -88,7 +88,7 @@ class Distro(distros.Distro):
(_out, err) = util.subp(cmd)
if len(err):
LOG.warn("Running %s resulted in stderr output: %s", cmd,
- err)
+ err)
except util.ProcessExecutionError:
util.logexc(LOG, "Running interface command %s failed", cmd)
return False
@@ -108,7 +108,7 @@ class Distro(distros.Distro):
if not conf:
conf = HostnameConf('')
conf.set_hostname(your_hostname)
- util.write_file(out_fn, str(conf), 0644)
+ util.write_file(out_fn, conf, 0o644)
def _read_system_hostname(self):
sys_hostname = self._read_hostname(self.hostname_conf_fn)
diff --git a/cloudinit/distros/net_util.py b/cloudinit/distros/net_util.py
index 8b28e2d1..cadfa6b6 100644
--- a/cloudinit/distros/net_util.py
+++ b/cloudinit/distros/net_util.py
@@ -103,7 +103,7 @@ def translate_network(settings):
consume[cmd] = args
# Check if anything left over to consume
absorb = False
- for (cmd, args) in consume.iteritems():
+ for (cmd, args) in consume.items():
if cmd == 'iface':
absorb = True
if absorb:
diff --git a/cloudinit/distros/parsers/hostname.py b/cloudinit/distros/parsers/hostname.py
index 617b3c36..efb185d4 100644
--- a/cloudinit/distros/parsers/hostname.py
+++ b/cloudinit/distros/parsers/hostname.py
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from StringIO import StringIO
+from six import StringIO
from cloudinit.distros.parsers import chop_comment
@@ -84,5 +84,5 @@ class HostnameConf(object):
hostnames_found.add(head)
if len(hostnames_found) > 1:
raise IOError("Multiple hostnames (%s) found!"
- % (hostnames_found))
+ % (hostnames_found))
return entries
diff --git a/cloudinit/distros/parsers/hosts.py b/cloudinit/distros/parsers/hosts.py
index 94c97051..3c5498ee 100644
--- a/cloudinit/distros/parsers/hosts.py
+++ b/cloudinit/distros/parsers/hosts.py
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from StringIO import StringIO
+from six import StringIO
from cloudinit.distros.parsers import chop_comment
diff --git a/cloudinit/distros/parsers/resolv_conf.py b/cloudinit/distros/parsers/resolv_conf.py
index 5733c25a..2ed13d9c 100644
--- a/cloudinit/distros/parsers/resolv_conf.py
+++ b/cloudinit/distros/parsers/resolv_conf.py
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from StringIO import StringIO
+from six import StringIO
from cloudinit import util
@@ -132,7 +132,7 @@ class ResolvConf(object):
# Some hard limit on 256 chars total
raise ValueError(("Adding %r would go beyond the "
"256 maximum search list character limit")
- % (search_domain))
+ % (search_domain))
self._remove_option('search')
self._contents.append(('option', ['search', s_list, '']))
return flat_sds
diff --git a/cloudinit/distros/parsers/sys_conf.py b/cloudinit/distros/parsers/sys_conf.py
index 20ca1871..6157cf32 100644
--- a/cloudinit/distros/parsers/sys_conf.py
+++ b/cloudinit/distros/parsers/sys_conf.py
@@ -16,7 +16,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from StringIO import StringIO
+import six
+from six import StringIO
import pipes
import re
@@ -69,15 +70,14 @@ class SysConf(configobj.ConfigObj):
return out_contents.getvalue()
def _quote(self, value, multiline=False):
- if not isinstance(value, (str, basestring)):
+ if not isinstance(value, six.string_types):
raise ValueError('Value "%s" is not a string' % (value))
if len(value) == 0:
return ''
quot_func = None
if value[0] in ['"', "'"] and value[-1] in ['"', "'"]:
if len(value) == 1:
- quot_func = (lambda x:
- self._get_single_quote(x) % x)
+ quot_func = (lambda x: self._get_single_quote(x) % x)
else:
# Quote whitespace if it isn't the start + end of a shell command
if value.strip().startswith("$(") and value.strip().endswith(")"):
@@ -90,10 +90,10 @@ class SysConf(configobj.ConfigObj):
# to use single quotes which won't get expanded...
if re.search(r"[\n\"']", value):
quot_func = (lambda x:
- self._get_triple_quote(x) % x)
+ self._get_triple_quote(x) % x)
else:
quot_func = (lambda x:
- self._get_single_quote(x) % x)
+ self._get_single_quote(x) % x)
else:
quot_func = pipes.quote
if not quot_func:
diff --git a/cloudinit/distros/rhel.py b/cloudinit/distros/rhel.py
index d9588632..812e7002 100644
--- a/cloudinit/distros/rhel.py
+++ b/cloudinit/distros/rhel.py
@@ -73,7 +73,7 @@ class Distro(distros.Distro):
searchservers = []
dev_names = entries.keys()
use_ipv6 = False
- for (dev, info) in entries.iteritems():
+ for (dev, info) in entries.items():
net_fn = self.network_script_tpl % (dev)
net_cfg = {
'DEVICE': dev,
@@ -111,13 +111,6 @@ class Distro(distros.Distro):
rhel_util.update_sysconfig_file(self.network_conf_fn, net_cfg)
return dev_names
- def 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 self.uses_systemd():
if not out_fn:
@@ -132,7 +125,11 @@ class Distro(distros.Distro):
rhel_util.update_sysconfig_file(out_fn, locale_cfg)
def _write_hostname(self, hostname, out_fn):
- if self.uses_systemd():
+ # systemd will never update previous-hostname for us, so
+ # we need to do it ourselves
+ if self.uses_systemd() and out_fn.endswith('/previous-hostname'):
+ util.write_file(out_fn, hostname)
+ elif self.uses_systemd():
util.subp(['hostnamectl', 'set-hostname', str(hostname)])
else:
host_cfg = {
@@ -155,7 +152,9 @@ class Distro(distros.Distro):
return (host_fn, self._read_hostname(host_fn))
def _read_hostname(self, filename, default=None):
- if self.uses_systemd():
+ if self.uses_systemd() and filename.endswith('/previous-hostname'):
+ return util.load_file(filename).strip()
+ elif self.uses_systemd():
(out, _err) = util.subp(['hostname'])
if len(out):
return out
diff --git a/cloudinit/distros/rhel_util.py b/cloudinit/distros/rhel_util.py
index 063d536e..84aad623 100644
--- a/cloudinit/distros/rhel_util.py
+++ b/cloudinit/distros/rhel_util.py
@@ -50,7 +50,7 @@ def update_sysconfig_file(fn, adjustments, allow_empty=False):
]
if not exists:
lines.insert(0, util.make_header())
- util.write_file(fn, "\n".join(lines) + "\n", 0644)
+ util.write_file(fn, "\n".join(lines) + "\n", 0o644)
# Helper function to read a RHEL/SUSE /etc/sysconfig/* file
@@ -86,4 +86,4 @@ def update_resolve_conf_file(fn, dns_servers, search_servers):
r_conf.add_search_domain(s)
except ValueError:
util.logexc(LOG, "Failed at adding search domain %s", s)
- util.write_file(fn, str(r_conf), 0644)
+ util.write_file(fn, r_conf, 0o644)
diff --git a/cloudinit/distros/sles.py b/cloudinit/distros/sles.py
index 43682a12..620c974c 100644
--- a/cloudinit/distros/sles.py
+++ b/cloudinit/distros/sles.py
@@ -62,7 +62,7 @@ class Distro(distros.Distro):
nameservers = []
searchservers = []
dev_names = entries.keys()
- for (dev, info) in entries.iteritems():
+ for (dev, info) in entries.items():
net_fn = self.network_script_tpl % (dev)
mode = info.get('auto')
if mode and mode.lower() == 'true':
@@ -113,7 +113,7 @@ class Distro(distros.Distro):
if not conf:
conf = HostnameConf('')
conf.set_hostname(hostname)
- util.write_file(out_fn, str(conf), 0644)
+ util.write_file(out_fn, str(conf), 0o644)
def _read_system_hostname(self):
host_fn = self.hostname_conf_fn