summaryrefslogtreecommitdiff
path: root/cloudinit/config
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit/config')
-rw-r--r--cloudinit/config/cc_apt_configure.py6
-rw-r--r--cloudinit/config/cc_chef.py2
-rw-r--r--cloudinit/config/cc_disk_setup.py37
-rw-r--r--cloudinit/config/cc_fan.py101
-rw-r--r--cloudinit/config/cc_final_message.py6
-rw-r--r--cloudinit/config/cc_grub_dpkg.py9
-rw-r--r--cloudinit/config/cc_keys_to_console.py2
-rw-r--r--cloudinit/config/cc_landscape.py12
-rw-r--r--cloudinit/config/cc_lxd.py85
-rw-r--r--cloudinit/config/cc_mounts.py17
-rw-r--r--cloudinit/config/cc_power_state_change.py57
-rw-r--r--cloudinit/config/cc_puppet.py6
-rw-r--r--cloudinit/config/cc_resizefs.py2
-rw-r--r--cloudinit/config/cc_rh_subscription.py12
-rw-r--r--cloudinit/config/cc_rsyslog.py1
-rw-r--r--cloudinit/config/cc_seed_random.py2
-rw-r--r--cloudinit/config/cc_set_hostname.py2
-rw-r--r--cloudinit/config/cc_set_passwords.py19
-rw-r--r--cloudinit/config/cc_snappy.py32
-rw-r--r--cloudinit/config/cc_ssh.py7
-rw-r--r--cloudinit/config/cc_update_etc_hosts.py6
-rw-r--r--cloudinit/config/cc_update_hostname.py2
-rw-r--r--cloudinit/config/cc_write_files.py4
-rw-r--r--cloudinit/config/cc_yum_add_repo.py2
24 files changed, 353 insertions, 78 deletions
diff --git a/cloudinit/config/cc_apt_configure.py b/cloudinit/config/cc_apt_configure.py
index 9e9e9e26..702977cb 100644
--- a/cloudinit/config/cc_apt_configure.py
+++ b/cloudinit/config/cc_apt_configure.py
@@ -91,7 +91,8 @@ def handle(name, cfg, cloud, log, _args):
if matchcfg:
matcher = re.compile(matchcfg).search
else:
- matcher = lambda f: False
+ def matcher(x):
+ return False
errors = add_sources(cfg['apt_sources'], params,
aa_repo_match=matcher)
@@ -173,7 +174,8 @@ def add_sources(srclist, template_params=None, aa_repo_match=None):
template_params = {}
if aa_repo_match is None:
- aa_repo_match = lambda f: False
+ def aa_repo_match(x):
+ return False
errorlist = []
for ent in srclist:
diff --git a/cloudinit/config/cc_chef.py b/cloudinit/config/cc_chef.py
index e18c5405..28711a59 100644
--- a/cloudinit/config/cc_chef.py
+++ b/cloudinit/config/cc_chef.py
@@ -285,7 +285,7 @@ def install_chef(cloud, chef_cfg, log):
chef_version = util.get_cfg_option_str(chef_cfg, 'version', None)
ruby_version = util.get_cfg_option_str(chef_cfg, 'ruby_version',
RUBY_VERSION_DEFAULT)
- install_chef_from_gems(cloud.distro, ruby_version, chef_version)
+ install_chef_from_gems(ruby_version, chef_version, cloud.distro)
# Retain backwards compat, by preferring True instead of False
# when not provided/overriden...
run = util.get_cfg_option_bool(chef_cfg, 'exec', default=True)
diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py
index d5b0d1d7..bbaf9646 100644
--- a/cloudinit/config/cc_disk_setup.py
+++ b/cloudinit/config/cc_disk_setup.py
@@ -167,11 +167,12 @@ def enumerate_disk(device, nodeps=False):
parts = [x for x in (info.strip()).splitlines() if len(x.split()) > 0]
for part in parts:
- d = {'name': None,
- 'type': None,
- 'fstype': None,
- 'label': None,
- }
+ d = {
+ 'name': None,
+ 'type': None,
+ 'fstype': None,
+ 'label': None,
+ }
for key, value in value_splitter(part):
d[key.lower()] = value
@@ -701,11 +702,12 @@ def lookup_force_flag(fs):
"""
A force flag might be -F or -F, this look it up
"""
- flags = {'ext': '-F',
- 'btrfs': '-f',
- 'xfs': '-f',
- 'reiserfs': '-f',
- }
+ flags = {
+ 'ext': '-F',
+ 'btrfs': '-f',
+ 'xfs': '-f',
+ 'reiserfs': '-f',
+ }
if 'ext' in fs.lower():
fs = 'ext'
@@ -824,10 +826,11 @@ def mkfs(fs_cfg):
# Create the commands
if fs_cmd:
- fs_cmd = fs_cfg['cmd'] % {'label': label,
- 'filesystem': fs_type,
- 'device': device,
- }
+ fs_cmd = fs_cfg['cmd'] % {
+ 'label': label,
+ 'filesystem': fs_type,
+ 'device': device,
+ }
else:
# Find the mkfs command
mkfs_cmd = util.which("mkfs.%s" % fs_type)
@@ -844,9 +847,9 @@ def mkfs(fs_cfg):
if label:
fs_cmd.extend(["-L", label])
- # File systems that support the -F flag
- if not fs_cmd and (overwrite or device_type(device) == "disk"):
- fs_cmd.append(lookup_force_flag(fs_type))
+ # File systems that support the -F flag
+ if overwrite or device_type(device) == "disk":
+ fs_cmd.append(lookup_force_flag(fs_type))
# Add the extends FS options
if fs_opts:
diff --git a/cloudinit/config/cc_fan.py b/cloudinit/config/cc_fan.py
new file mode 100644
index 00000000..39e3850e
--- /dev/null
+++ b/cloudinit/config/cc_fan.py
@@ -0,0 +1,101 @@
+# vi: ts=4 expandtab
+#
+# Copyright (C) 2015 Canonical Ltd.
+#
+# Author: Scott Moser <scott.moser@canonical.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+fan module allows configuration of Ubuntu Fan
+ https://wiki.ubuntu.com/FanNetworking
+
+Example config:
+ #cloud-config
+ fan:
+ config: |
+ # fan 240
+ 10.0.0.0/8 eth0/16 dhcp
+ 10.0.0.0/8 eth1/16 dhcp off
+ # fan 241
+ 241.0.0.0/8 eth0/16 dhcp
+ config_path: /etc/network/fan
+
+If cloud-init sees a 'fan' entry in cloud-config it will
+ a.) write 'config_path' with the contents
+ b.) install the package 'ubuntu-fan' if it is not installed
+ c.) ensure the service is started (or restarted if was previously running)
+"""
+
+from cloudinit import log as logging
+from cloudinit import util
+from cloudinit.settings import PER_INSTANCE
+
+LOG = logging.getLogger(__name__)
+
+frequency = PER_INSTANCE
+
+BUILTIN_CFG = {
+ 'config': None,
+ 'config_path': '/etc/network/fan',
+}
+
+
+def stop_update_start(service, config_file, content, systemd=False):
+ if systemd:
+ cmds = {'stop': ['systemctl', 'stop', service],
+ 'start': ['systemctl', 'start', service],
+ 'enable': ['systemctl', 'enable', service]}
+ else:
+ cmds = {'stop': ['service', 'stop'],
+ 'start': ['service', 'start']}
+
+ def run(cmd, msg):
+ try:
+ return util.subp(cmd, capture=True)
+ except util.ProcessExecutionError as e:
+ LOG.warn("failed: %s (%s): %s", service, cmd, e)
+ return False
+
+ stop_failed = not run(cmds['stop'], msg='stop %s' % service)
+ if not content.endswith('\n'):
+ content += '\n'
+ util.write_file(config_file, content, omode="w")
+
+ ret = run(cmds['start'], msg='start %s' % service)
+ if ret and stop_failed:
+ LOG.warn("success: %s started", service)
+
+ if 'enable' in cmds:
+ ret = run(cmds['enable'], msg='enable %s' % service)
+
+ return ret
+
+
+def handle(name, cfg, cloud, log, args):
+ cfgin = cfg.get('fan')
+ if not cfgin:
+ cfgin = {}
+ mycfg = util.mergemanydict([cfgin, BUILTIN_CFG])
+
+ if not mycfg.get('config'):
+ LOG.debug("%s: no 'fan' config entry. disabling", name)
+ return
+
+ util.write_file(mycfg.get('config_path'), mycfg.get('config'), omode="w")
+ distro = cloud.distro
+ if not util.which('fanctl'):
+ distro.install_packages(['ubuntu-fan'])
+
+ stop_update_start(
+ service='ubuntu-fan', config_file=mycfg.get('config_path'),
+ content=mycfg.get('config'), systemd=distro.uses_systemd())
diff --git a/cloudinit/config/cc_final_message.py b/cloudinit/config/cc_final_message.py
index ad957e12..4a51476f 100644
--- a/cloudinit/config/cc_final_message.py
+++ b/cloudinit/config/cc_final_message.py
@@ -28,9 +28,9 @@ frequency = PER_ALWAYS
# Jinja formated default message
FINAL_MESSAGE_DEF = (
- "## template: jinja\n"
- "Cloud-init v. {{version}} finished at {{timestamp}}."
- " Datasource {{datasource}}. Up {{uptime}} seconds"
+ "## template: jinja\n"
+ "Cloud-init v. {{version}} finished at {{timestamp}}."
+ " Datasource {{datasource}}. Up {{uptime}} seconds"
)
diff --git a/cloudinit/config/cc_grub_dpkg.py b/cloudinit/config/cc_grub_dpkg.py
index 456597af..3c2d9985 100644
--- a/cloudinit/config/cc_grub_dpkg.py
+++ b/cloudinit/config/cc_grub_dpkg.py
@@ -37,12 +37,11 @@ def handle(name, cfg, _cloud, log, _args):
return
idevs = util.get_cfg_option_str(mycfg, "grub-pc/install_devices", None)
- idevs_empty = util.get_cfg_option_str(mycfg,
- "grub-pc/install_devices_empty", None)
+ idevs_empty = util.get_cfg_option_str(
+ mycfg, "grub-pc/install_devices_empty", None)
if ((os.path.exists("/dev/sda1") and not os.path.exists("/dev/sda")) or
- (os.path.exists("/dev/xvda1")
- and not os.path.exists("/dev/xvda"))):
+ (os.path.exists("/dev/xvda1") and not os.path.exists("/dev/xvda"))):
if idevs is None:
idevs = ""
if idevs_empty is None:
@@ -66,7 +65,7 @@ def handle(name, cfg, _cloud, log, _args):
(idevs, idevs_empty))
log.debug("Setting grub debconf-set-selections with '%s','%s'" %
- (idevs, idevs_empty))
+ (idevs, idevs_empty))
try:
util.subp(['debconf-set-selections'], dconf_sel)
diff --git a/cloudinit/config/cc_keys_to_console.py b/cloudinit/config/cc_keys_to_console.py
index f1c1adff..aa844ee9 100644
--- a/cloudinit/config/cc_keys_to_console.py
+++ b/cloudinit/config/cc_keys_to_console.py
@@ -48,7 +48,7 @@ def handle(name, cfg, cloud, log, _args):
"ssh_fp_console_blacklist", [])
key_blacklist = util.get_cfg_option_list(cfg,
"ssh_key_console_blacklist",
- ["ssh-dss"])
+ ["ssh-dss"])
try:
cmd = [helper_path]
diff --git a/cloudinit/config/cc_landscape.py b/cloudinit/config/cc_landscape.py
index 0b9d846e..68fcb27f 100644
--- a/cloudinit/config/cc_landscape.py
+++ b/cloudinit/config/cc_landscape.py
@@ -38,12 +38,12 @@ distros = ['ubuntu']
# defaults taken from stock client.conf in landscape-client 11.07.1.1-0ubuntu2
LSC_BUILTIN_CFG = {
- 'client': {
- 'log_level': "info",
- 'url': "https://landscape.canonical.com/message-system",
- 'ping_url': "http://landscape.canonical.com/ping",
- 'data_path': "/var/lib/landscape/client",
- }
+ 'client': {
+ 'log_level': "info",
+ 'url': "https://landscape.canonical.com/message-system",
+ 'ping_url': "http://landscape.canonical.com/ping",
+ 'data_path': "/var/lib/landscape/client",
+ }
}
diff --git a/cloudinit/config/cc_lxd.py b/cloudinit/config/cc_lxd.py
new file mode 100644
index 00000000..63b8fb63
--- /dev/null
+++ b/cloudinit/config/cc_lxd.py
@@ -0,0 +1,85 @@
+# vi: ts=4 expandtab
+#
+# Copyright (C) 2016 Canonical Ltd.
+#
+# Author: Wesley Wiedenmeier <wesley.wiedenmeier@canonical.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+This module initializes lxd using 'lxd init'
+
+Example config:
+ #cloud-config
+ lxd:
+ init:
+ network_address: <ip addr>
+ network_port: <port>
+ storage_backend: <zfs/dir>
+ storage_create_device: <dev>
+ storage_create_loop: <size>
+ storage_pool: <name>
+ trust_password: <password>
+"""
+
+from cloudinit import util
+
+
+def handle(name, cfg, cloud, log, args):
+ # Get config
+ lxd_cfg = cfg.get('lxd')
+ if not lxd_cfg:
+ log.debug("Skipping module named %s, not present or disabled by cfg")
+ return
+ if not isinstance(lxd_cfg, dict):
+ log.warn("lxd config must be a dictionary. found a '%s'",
+ type(lxd_cfg))
+ return
+
+ init_cfg = lxd_cfg.get('init')
+ if not isinstance(init_cfg, dict):
+ log.warn("lxd/init config must be a dictionary. found a '%s'",
+ type(init_cfg))
+ init_cfg = {}
+
+ if not init_cfg:
+ log.debug("no lxd/init config. disabled.")
+ return
+
+ packages = []
+ # Ensure lxd is installed
+ if not util.which("lxd"):
+ packages.append('lxd')
+
+ # if using zfs, get the utils
+ if init_cfg.get("storage_backend") == "zfs" and not util.which('zfs'):
+ packages.append('zfs')
+
+ if len(packages):
+ try:
+ cloud.distro.install_packages(packages)
+ except util.ProcessExecutionError as exc:
+ log.warn("failed to install packages %s: %s", packages, exc)
+ return
+
+ # Set up lxd if init config is given
+ init_keys = (
+ 'network_address', 'network_port', 'storage_backend',
+ 'storage_create_device', 'storage_create_loop',
+ 'storage_pool', 'trust_password')
+ cmd = ['lxd', 'init', '--auto']
+ for k in init_keys:
+ if init_cfg.get(k):
+ cmd.extend(["--%s=%s" %
+ (k.replace('_', '-'), str(init_cfg[k]))])
+ util.subp(cmd)
diff --git a/cloudinit/config/cc_mounts.py b/cloudinit/config/cc_mounts.py
index 73b42f91..4fe3ee21 100644
--- a/cloudinit/config/cc_mounts.py
+++ b/cloudinit/config/cc_mounts.py
@@ -204,11 +204,12 @@ def setup_swapfile(fname, size=None, maxsize=None):
try:
util.ensure_dir(tdir)
util.log_time(LOG.debug, msg, func=util.subp,
- args=[['sh', '-c',
- ('rm -f "$1" && umask 0066 && '
- 'dd if=/dev/zero "of=$1" bs=1M "count=$2" && '
- 'mkswap "$1" || { r=$?; rm -f "$1"; exit $r; }'),
- 'setup_swap', fname, mbsize]])
+ args=[['sh', '-c',
+ ('rm -f "$1" && umask 0066 && '
+ '{ fallocate -l "${2}M" "$1" || '
+ ' dd if=/dev/zero "of=$1" bs=1M "count=$2"; } && '
+ 'mkswap "$1" || { r=$?; rm -f "$1"; exit $r; }'),
+ 'setup_swap', fname, mbsize]])
except Exception as e:
raise IOError("Failed %s: %s" % (msg, e))
@@ -262,7 +263,11 @@ def handle_swapcfg(swapcfg):
def handle(_name, cfg, cloud, log, _args):
# fs_spec, fs_file, fs_vfstype, fs_mntops, fs-freq, fs_passno
- defvals = [None, None, "auto", "defaults,nobootwait", "0", "2"]
+ def_mnt_opts = "defaults,nobootwait"
+ if cloud.distro.uses_systemd():
+ def_mnt_opts = "defaults,nofail"
+
+ defvals = [None, None, "auto", def_mnt_opts, "0", "2"]
defvals = cfg.get("mount_default_fields", defvals)
# these are our default set of mounts
diff --git a/cloudinit/config/cc_power_state_change.py b/cloudinit/config/cc_power_state_change.py
index 09d37371..cc3f7f70 100644
--- a/cloudinit/config/cc_power_state_change.py
+++ b/cloudinit/config/cc_power_state_change.py
@@ -22,6 +22,7 @@ from cloudinit import util
import errno
import os
import re
+import six
import subprocess
import time
@@ -48,10 +49,40 @@ def givecmdline(pid):
return None
+def check_condition(cond, log=None):
+ if isinstance(cond, bool):
+ if log:
+ log.debug("Static Condition: %s" % cond)
+ return cond
+
+ pre = "check_condition command (%s): " % cond
+ try:
+ proc = subprocess.Popen(cond, shell=not isinstance(cond, list))
+ proc.communicate()
+ ret = proc.returncode
+ if ret == 0:
+ if log:
+ log.debug(pre + "exited 0. condition met.")
+ return True
+ elif ret == 1:
+ if log:
+ log.debug(pre + "exited 1. condition not met.")
+ return False
+ else:
+ if log:
+ log.warn(pre + "unexpected exit %s. " % ret +
+ "do not apply change.")
+ return False
+ except Exception as e:
+ if log:
+ log.warn(pre + "Unexpected error: %s" % e)
+ return False
+
+
def handle(_name, cfg, _cloud, log, _args):
try:
- (args, timeout) = load_power_state(cfg)
+ (args, timeout, condition) = load_power_state(cfg)
if args is None:
log.debug("no power_state provided. doing nothing")
return
@@ -59,6 +90,10 @@ def handle(_name, cfg, _cloud, log, _args):
log.warn("%s Not performing power state change!" % str(e))
return
+ if condition is False:
+ log.debug("Condition was false. Will not perform state change.")
+ return
+
mypid = os.getpid()
cmdline = givecmdline(mypid)
@@ -70,8 +105,8 @@ def handle(_name, cfg, _cloud, log, _args):
log.debug("After pid %s ends, will execute: %s" % (mypid, ' '.join(args)))
- util.fork_cb(run_after_pid_gone, mypid, cmdline, timeout, log, execmd,
- [args, devnull_fp])
+ util.fork_cb(run_after_pid_gone, mypid, cmdline, timeout, log,
+ condition, execmd, [args, devnull_fp])
def load_power_state(cfg):
@@ -80,7 +115,7 @@ def load_power_state(cfg):
pstate = cfg.get('power_state')
if pstate is None:
- return (None, None)
+ return (None, None, None)
if not isinstance(pstate, dict):
raise TypeError("power_state is not a dict.")
@@ -115,7 +150,10 @@ def load_power_state(cfg):
raise ValueError("failed to convert timeout '%s' to float." %
pstate['timeout'])
- return (args, timeout)
+ condition = pstate.get("condition", True)
+ if not isinstance(condition, six.string_types + (list, bool)):
+ raise TypeError("condition type %s invalid. must be list, bool, str")
+ return (args, timeout, condition)
def doexit(sysexit):
@@ -133,7 +171,7 @@ def execmd(exe_args, output=None, data_in=None):
doexit(ret)
-def run_after_pid_gone(pid, pidcmdline, timeout, log, func, args):
+def run_after_pid_gone(pid, pidcmdline, timeout, log, condition, func, args):
# wait until pid, with /proc/pid/cmdline contents of pidcmdline
# is no longer alive. After it is gone, or timeout has passed
# execute func(args)
@@ -175,4 +213,11 @@ def run_after_pid_gone(pid, pidcmdline, timeout, log, func, args):
if log:
log.debug(msg)
+
+ try:
+ if not check_condition(condition, log):
+ return
+ except Exception as e:
+ fatal("Unexpected Exception when checking condition: %s" % e)
+
func(*args)
diff --git a/cloudinit/config/cc_puppet.py b/cloudinit/config/cc_puppet.py
index 4501598e..774d3322 100644
--- a/cloudinit/config/cc_puppet.py
+++ b/cloudinit/config/cc_puppet.py
@@ -36,8 +36,8 @@ def _autostart_puppet(log):
# Set puppet to automatically start
if os.path.exists('/etc/default/puppet'):
util.subp(['sed', '-i',
- '-e', 's/^START=.*/START=yes/',
- '/etc/default/puppet'], capture=False)
+ '-e', 's/^START=.*/START=yes/',
+ '/etc/default/puppet'], capture=False)
elif os.path.exists('/bin/systemctl'):
util.subp(['/bin/systemctl', 'enable', 'puppet.service'],
capture=False)
@@ -65,7 +65,7 @@ def handle(name, cfg, cloud, log, _args):
" doing nothing."))
elif install:
log.debug(("Attempting to install puppet %s,"),
- version if version else 'latest')
+ version if version else 'latest')
cloud.distro.install_packages(('puppet', version))
# ... and then update the puppet configuration
diff --git a/cloudinit/config/cc_resizefs.py b/cloudinit/config/cc_resizefs.py
index cbc07853..2a2a9f59 100644
--- a/cloudinit/config/cc_resizefs.py
+++ b/cloudinit/config/cc_resizefs.py
@@ -166,7 +166,7 @@ def handle(name, cfg, _cloud, log, args):
func=do_resize, args=(resize_cmd, log))
else:
util.log_time(logfunc=log.debug, msg="Resizing",
- func=do_resize, args=(resize_cmd, log))
+ func=do_resize, args=(resize_cmd, log))
action = 'Resized'
if resize_root == NOBLOCK:
diff --git a/cloudinit/config/cc_rh_subscription.py b/cloudinit/config/cc_rh_subscription.py
index 6da26d25..6087c45c 100644
--- a/cloudinit/config/cc_rh_subscription.py
+++ b/cloudinit/config/cc_rh_subscription.py
@@ -126,13 +126,11 @@ class SubscriptionManager(object):
"(True/False "
return False, not_bool
- if (self.servicelevel is not None) and \
- ((not self.auto_attach)
- or (util.is_false(str(self.auto_attach)))):
-
- no_auto = "The service-level key must be used in conjunction with "\
- "the auto-attach key. Please re-run with auto-attach: "\
- "True"
+ if (self.servicelevel is not None) and ((not self.auto_attach) or
+ (util.is_false(str(self.auto_attach)))):
+ no_auto = ("The service-level key must be used in conjunction "
+ "with the auto-attach key. Please re-run with "
+ "auto-attach: True")
return False, no_auto
return True, None
diff --git a/cloudinit/config/cc_rsyslog.py b/cloudinit/config/cc_rsyslog.py
index a0132d28..b8642d65 100644
--- a/cloudinit/config/cc_rsyslog.py
+++ b/cloudinit/config/cc_rsyslog.py
@@ -130,6 +130,7 @@ HOST_PORT_RE = re.compile(
'(([[](?P<bracket_addr>[^\]]*)[\]])|(?P<addr>[^:]*))'
'([:](?P<port>[0-9]+))?$')
+
def reload_syslog(command=DEF_RELOAD, systemd=False):
service = 'rsyslog'
if command == DEF_RELOAD:
diff --git a/cloudinit/config/cc_seed_random.py b/cloudinit/config/cc_seed_random.py
index 3288a853..1b011216 100644
--- a/cloudinit/config/cc_seed_random.py
+++ b/cloudinit/config/cc_seed_random.py
@@ -83,7 +83,7 @@ def handle(name, cfg, cloud, log, _args):
len(seed_data), seed_path)
util.append_file(seed_path, seed_data)
- command = mycfg.get('command', ['pollinate', '-q'])
+ command = mycfg.get('command', None)
req = mycfg.get('command_required', False)
try:
env = os.environ.copy()
diff --git a/cloudinit/config/cc_set_hostname.py b/cloudinit/config/cc_set_hostname.py
index 5d7f4331..f43d8d5a 100644
--- a/cloudinit/config/cc_set_hostname.py
+++ b/cloudinit/config/cc_set_hostname.py
@@ -24,7 +24,7 @@ from cloudinit import util
def handle(name, cfg, cloud, log, _args):
if util.get_cfg_option_bool(cfg, "preserve_hostname", False):
log.debug(("Configuration option 'preserve_hostname' is set,"
- " not setting the hostname in module %s"), name)
+ " not setting the hostname in module %s"), name)
return
(hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud)
diff --git a/cloudinit/config/cc_set_passwords.py b/cloudinit/config/cc_set_passwords.py
index 0c315361..58e1b713 100644
--- a/cloudinit/config/cc_set_passwords.py
+++ b/cloudinit/config/cc_set_passwords.py
@@ -45,8 +45,6 @@ def handle(_name, cfg, cloud, log, args):
password = util.get_cfg_option_str(cfg, "password", None)
expire = True
- pw_auth = "no"
- change_pwauth = False
plist = None
if 'chpasswd' in cfg:
@@ -104,11 +102,24 @@ def handle(_name, cfg, cloud, log, args):
change_pwauth = False
pw_auth = None
if 'ssh_pwauth' in cfg:
- change_pwauth = True
if util.is_true(cfg['ssh_pwauth']):
+ change_pwauth = True
pw_auth = 'yes'
- if util.is_false(cfg['ssh_pwauth']):
+ elif util.is_false(cfg['ssh_pwauth']):
+ change_pwauth = True
pw_auth = 'no'
+ elif str(cfg['ssh_pwauth']).lower() == 'unchanged':
+ log.debug('Leaving auth line unchanged')
+ change_pwauth = False
+ elif not str(cfg['ssh_pwauth']).strip():
+ log.debug('Leaving auth line unchanged')
+ change_pwauth = False
+ elif not cfg['ssh_pwauth']:
+ log.debug('Leaving auth line unchanged')
+ change_pwauth = False
+ else:
+ msg = 'Unrecognized value %s for ssh_pwauth' % cfg['ssh_pwauth']
+ util.logexc(log, msg)
if change_pwauth:
replaced_auth = False
diff --git a/cloudinit/config/cc_snappy.py b/cloudinit/config/cc_snappy.py
index 7aaec94a..fa9d54a0 100644
--- a/cloudinit/config/cc_snappy.py
+++ b/cloudinit/config/cc_snappy.py
@@ -6,7 +6,7 @@ Example config:
#cloud-config
snappy:
system_snappy: auto
- ssh_enabled: False
+ ssh_enabled: auto
packages: [etcd, pkg2.smoser]
config:
pkgname:
@@ -16,7 +16,12 @@ Example config:
packages_dir: '/writable/user-data/cloud-init/snaps'
- ssh_enabled:
- This defaults to 'False'. Set to a non-false value to enable ssh service
+ This controls the system's ssh service. The default value is 'auto'.
+ True: enable ssh service
+ False: disable ssh service
+ auto: enable ssh service if either ssh keys have been provided
+ or user has requested password authentication (ssh_pwauth).
+
- snap installation and config
The above would install 'etcd', and then install 'pkg2.smoser' with a
'<config-file>' argument where 'config-file' has 'config-blob' inside it.
@@ -58,7 +63,7 @@ NAMESPACE_DELIM = '.'
BUILTIN_CFG = {
'packages': [],
'packages_dir': '/writable/user-data/cloud-init/snaps',
- 'ssh_enabled': False,
+ 'ssh_enabled': "auto",
'system_snappy': "auto",
'config': {},
}
@@ -274,7 +279,26 @@ def handle(name, cfg, cloud, log, args):
LOG.warn("'%s' failed for '%s': %s",
pkg_op['op'], pkg_op['name'], e)
- disable_enable_ssh(mycfg.get('ssh_enabled', False))
+ # Default to disabling SSH
+ ssh_enabled = mycfg.get('ssh_enabled', "auto")
+
+ # If the user has not explicitly enabled or disabled SSH, then enable it
+ # when password SSH authentication is requested or there are SSH keys
+ if ssh_enabled == "auto":
+ user_ssh_keys = cloud.get_public_ssh_keys() or None
+ password_auth_enabled = cfg.get('ssh_pwauth', False)
+ if user_ssh_keys:
+ LOG.debug("Enabling SSH, ssh keys found in datasource")
+ ssh_enabled = True
+ elif cfg.get('ssh_authorized_keys'):
+ LOG.debug("Enabling SSH, ssh keys found in config")
+ elif password_auth_enabled:
+ LOG.debug("Enabling SSH, password authentication requested")
+ ssh_enabled = True
+ elif ssh_enabled not in (True, False):
+ LOG.warn("Unknown value '%s' in ssh_enabled", ssh_enabled)
+
+ disable_enable_ssh(ssh_enabled)
if fails:
raise Exception("failed to install/configure snaps")
diff --git a/cloudinit/config/cc_ssh.py b/cloudinit/config/cc_ssh.py
index 5bd2dec6..d24e43c0 100644
--- a/cloudinit/config/cc_ssh.py
+++ b/cloudinit/config/cc_ssh.py
@@ -30,9 +30,10 @@ from cloudinit import distros as ds
from cloudinit import ssh_util
from cloudinit import util
-DISABLE_ROOT_OPTS = ("no-port-forwarding,no-agent-forwarding,"
-"no-X11-forwarding,command=\"echo \'Please login as the user \\\"$USER\\\" "
-"rather than the user \\\"root\\\".\';echo;sleep 10\"")
+DISABLE_ROOT_OPTS = (
+ "no-port-forwarding,no-agent-forwarding,"
+ "no-X11-forwarding,command=\"echo \'Please login as the user \\\"$USER\\\""
+ " rather than the user \\\"root\\\".\';echo;sleep 10\"")
GENERATE_KEY_NAMES = ['rsa', 'dsa', 'ecdsa', 'ed25519']
KEY_FILE_TPL = '/etc/ssh/ssh_host_%s_key'
diff --git a/cloudinit/config/cc_update_etc_hosts.py b/cloudinit/config/cc_update_etc_hosts.py
index d3dd1f32..15703efe 100644
--- a/cloudinit/config/cc_update_etc_hosts.py
+++ b/cloudinit/config/cc_update_etc_hosts.py
@@ -41,10 +41,10 @@ def handle(name, cfg, cloud, log, _args):
if not tpl_fn_name:
raise RuntimeError(("No hosts template could be"
" found for distro %s") %
- (cloud.distro.osfamily))
+ (cloud.distro.osfamily))
templater.render_to_file(tpl_fn_name, '/etc/hosts',
- {'hostname': hostname, 'fqdn': fqdn})
+ {'hostname': hostname, 'fqdn': fqdn})
elif manage_hosts == "localhost":
(hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud)
@@ -57,4 +57,4 @@ def handle(name, cfg, cloud, log, _args):
cloud.distro.update_etc_hosts(hostname, fqdn)
else:
log.debug(("Configuration option 'manage_etc_hosts' is not set,"
- " not managing /etc/hosts in module %s"), name)
+ " not managing /etc/hosts in module %s"), name)
diff --git a/cloudinit/config/cc_update_hostname.py b/cloudinit/config/cc_update_hostname.py
index e396ba13..5b78afe1 100644
--- a/cloudinit/config/cc_update_hostname.py
+++ b/cloudinit/config/cc_update_hostname.py
@@ -29,7 +29,7 @@ frequency = PER_ALWAYS
def handle(name, cfg, cloud, log, _args):
if util.get_cfg_option_bool(cfg, "preserve_hostname", False):
log.debug(("Configuration option 'preserve_hostname' is set,"
- " not updating the hostname in module %s"), name)
+ " not updating the hostname in module %s"), name)
return
(hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud)
diff --git a/cloudinit/config/cc_write_files.py b/cloudinit/config/cc_write_files.py
index 4b03ea91..351cfc8c 100644
--- a/cloudinit/config/cc_write_files.py
+++ b/cloudinit/config/cc_write_files.py
@@ -92,10 +92,10 @@ def decode_perms(perm, default, log):
def extract_contents(contents, extraction_types):
- result = str(contents)
+ result = contents
for t in extraction_types:
if t == 'application/x-gzip':
- result = util.decomp_gzip(result, quiet=False)
+ result = util.decomp_gzip(result, quiet=False, decode=False)
elif t == 'application/base64':
result = base64.b64decode(result)
elif t == UNKNOWN_ENC:
diff --git a/cloudinit/config/cc_yum_add_repo.py b/cloudinit/config/cc_yum_add_repo.py
index 3b821af9..64fba869 100644
--- a/cloudinit/config/cc_yum_add_repo.py
+++ b/cloudinit/config/cc_yum_add_repo.py
@@ -92,7 +92,7 @@ def handle(name, cfg, _cloud, log, _args):
for req_field in ['baseurl']:
if req_field not in repo_config:
log.warn(("Repository %s does not contain a %s"
- " configuration 'required' entry"),
+ " configuration 'required' entry"),
repo_id, req_field)
missing_required += 1
if not missing_required: