summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--cloudinit/distros/debian.py7
-rw-r--r--cloudinit/distros/rhel.py73
-rw-r--r--cloudinit/log.py6
-rw-r--r--cloudinit/sources/DataSourceConfigDrive.py3
-rw-r--r--cloudinit/sources/DataSourceNoCloud.py3
-rw-r--r--cloudinit/util.py1
-rw-r--r--doc/examples/cloud-config.txt18
-rw-r--r--tests/unittests/test_datasource/test_configdrive.py5
-rwxr-xr-xtools/ccfg-merge-debug89
-rwxr-xr-xtools/make-dist-tarball14
-rwxr-xr-xtools/make-tarball12
-rwxr-xr-xtools/read-dependencies8
-rwxr-xr-xtools/read-version4
14 files changed, 197 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index 612c7fa7..06c9de25 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -52,6 +52,10 @@
(LP: #1023179)
- use python-requests rather than urllib2. By using recent versions of
python-requests, we get https support (LP: #1067888).
+ - make apt-get invoke 'dist-upgrade' rather than 'upgrade' for
+ package_upgrade. (LP: #1164147)
+ - improvements for systemd with Fedora 18
+ - workaround 2.6 kernel issue that stopped blkid from showing /dev/sr0
0.7.1:
- sysvinit: fix missing dependency in cloud-init job for RHEL 5.6
diff --git a/cloudinit/distros/debian.py b/cloudinit/distros/debian.py
index 4b779d57..0811eefd 100644
--- a/cloudinit/distros/debian.py
+++ b/cloudinit/distros/debian.py
@@ -161,7 +161,12 @@ class Distro(distros.Distro):
elif args and isinstance(args, list):
cmd.extend(args)
- cmd.append(command)
+ subcmd = command
+ if command == "upgrade":
+ subcmd = self.get_option("apt_get_upgrade_subcommand",
+ "dist-upgrade")
+
+ cmd.append(subcmd)
pkglist = util.expand_package_list('%s=%s', pkgs)
cmd.extend(pkglist)
diff --git a/cloudinit/distros/rhel.py b/cloudinit/distros/rhel.py
index 9fee5fd1..174da3ab 100644
--- a/cloudinit/distros/rhel.py
+++ b/cloudinit/distros/rhel.py
@@ -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:
diff --git a/cloudinit/log.py b/cloudinit/log.py
index da6c2851..622c946c 100644
--- a/cloudinit/log.py
+++ b/cloudinit/log.py
@@ -44,13 +44,13 @@ NOTSET = logging.NOTSET
DEF_CON_FORMAT = '%(asctime)s - %(filename)s[%(levelname)s]: %(message)s'
-def setupBasicLogging():
+def setupBasicLogging(level=DEBUG):
root = logging.getLogger()
console = logging.StreamHandler(sys.stderr)
console.setFormatter(logging.Formatter(DEF_CON_FORMAT))
- console.setLevel(DEBUG)
+ console.setLevel(level)
root.addHandler(console)
- root.setLevel(DEBUG)
+ root.setLevel(level)
def flushLoggers(root):
diff --git a/cloudinit/sources/DataSourceConfigDrive.py b/cloudinit/sources/DataSourceConfigDrive.py
index 5f152299..d3443c2b 100644
--- a/cloudinit/sources/DataSourceConfigDrive.py
+++ b/cloudinit/sources/DataSourceConfigDrive.py
@@ -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")
diff --git a/cloudinit/sources/DataSourceNoCloud.py b/cloudinit/sources/DataSourceNoCloud.py
index 08a853cc..01c99028 100644
--- a/cloudinit/sources/DataSourceNoCloud.py
+++ b/cloudinit/sources/DataSourceNoCloud.py
@@ -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"))
diff --git a/cloudinit/util.py b/cloudinit/util.py
index 36e9b83b..50de55fe 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -408,6 +408,7 @@ def system_info():
'release': platform.release(),
'python': platform.python_version(),
'uname': platform.uname(),
+ 'dist': platform.linux_distribution(),
}
diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt
index 09298655..24b4b36c 100644
--- a/doc/examples/cloud-config.txt
+++ b/doc/examples/cloud-config.txt
@@ -125,6 +125,24 @@ apt_sources:
=Y2oI
-----END PGP PUBLIC KEY BLOCK-----
+## apt config via system_info:
+# under the 'system_info', you can further customize cloud-init's interaction
+# with apt.
+# system_info:
+# apt_get_command: [command, argument, argument]
+# apt_get_upgrade_subcommand: dist-upgrade
+#
+# apt_get_command:
+# To specify a different 'apt-get' command, set 'apt_get_command'.
+# This must be a list, and the subcommand (update, upgrade) is appended to it.
+# default is:
+# ['apt-get', '--option=Dpkg::Options::=--force-confold',
+# '--option=Dpkg::options::=--force-unsafe-io', '--assume-yes', '--quiet']
+#
+# apt_get_upgrade_subcommand:
+# Specify a different subcommand for 'upgrade. The default is 'dist-upgrade'.
+# This is the subcommand that is invoked if package_upgrade is set to true above.
+
# Install additional packages on first boot
#
# Default: none
diff --git a/tests/unittests/test_datasource/test_configdrive.py b/tests/unittests/test_datasource/test_configdrive.py
index 930086db..d5935294 100644
--- a/tests/unittests/test_datasource/test_configdrive.py
+++ b/tests/unittests/test_datasource/test_configdrive.py
@@ -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")
diff --git a/tools/ccfg-merge-debug b/tools/ccfg-merge-debug
new file mode 100755
index 00000000..5b6b050a
--- /dev/null
+++ b/tools/ccfg-merge-debug
@@ -0,0 +1,89 @@
+#!/usr/bin/python
+
+from cloudinit import handlers
+from cloudinit.handlers import cloud_config as cc_part
+from cloudinit import helpers
+from cloudinit import log as logging
+from cloudinit.settings import PER_INSTANCE
+from cloudinit import user_data as ud
+
+import argparse
+import os
+import shutil
+import tempfile
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description='test cloud-config merging')
+ parser.add_argument("--output", "-o", metavar="file",
+ help="specify output file", default="-")
+ parser.add_argument('--verbose', '-v', action='count', default=0)
+ parser.add_argument('files', nargs='+')
+
+ args = parser.parse_args()
+
+ if args.verbose:
+ level = (logging.WARN, logging.INFO,
+ logging.DEBUG)[min(args.verbose, 2)]
+ logging.setupBasicLogging(level)
+
+ outfile = args.output
+ if args.output == "-":
+ outfile = "/dev/stdout"
+
+ tempd = tempfile.mkdtemp()
+ handler_dir = os.path.join(tempd, "hdir")
+ data = None # the 'init' object
+ frequency = PER_INSTANCE
+
+ paths = helpers.Paths({})
+
+ # make a '#include <f1>' style
+ udproc = ud.UserDataProcessor(paths=paths)
+ user_data_msg = udproc.process("#include\n" +
+ '\n'.join([os.path.abspath(f) for f in args.files]))
+
+ ccph = cc_part.CloudConfigPartHandler(paths=paths)
+ ccph.cloud_fn = outfile
+
+ c_handlers = helpers.ContentHandlers()
+ c_handlers.register_defaults([ccph])
+
+ called = []
+ for (_ctype, mod) in c_handlers.iteritems():
+ if mod in called:
+ continue
+ handlers.call_begin(mod, data, frequency)
+ called.append(mod)
+
+ # Walk the user data
+ part_data = {
+ 'handlers': c_handlers,
+ # Any new handlers that are encountered get writen here
+ 'handlerdir': handler_dir,
+ 'data': data,
+ # The default frequency if handlers don't have one
+ 'frequency': frequency,
+ # This will be used when new handlers are found
+ # to help write there contents to files with numbered
+ # names...
+ 'handlercount': 0,
+ }
+
+ handlers.walk(user_data_msg, handlers.walker_callback, data=part_data)
+
+ # Give callbacks opportunity to finalize
+ called = []
+ for (_ctype, mod) in c_handlers.iteritems():
+ if mod in called:
+ continue
+ handlers.call_end(mod, data, frequency)
+ called.append(mod)
+
+ shutil.rmtree(tempd)
+
+if __name__ == "__main__":
+ main()
+
+# vi: ts=4 expandtab
diff --git a/tools/make-dist-tarball b/tools/make-dist-tarball
index 7742caea..5b078515 100755
--- a/tools/make-dist-tarball
+++ b/tools/make-dist-tarball
@@ -10,16 +10,12 @@ EOF
}
topdir="$PWD"
-tag=${1}
+tag="$1"
[ -n "$tag" ] || { Usage 1>&2 ; exit 1; }
-tmpd=$(mktemp -d );
-trap "rm -Rf '${tmpd}'" 0
+out="${topdir}/cloud-init-${tag}.tar.gz"
-out=${topdir}/cloud-init-${tag}.tar.gz
-
-cd ${tmpd} &&
- bzr branch -r "tag:${tag}" "${topdir}" ./cloud-init-${tag} &&
- tar czf "${out}" cloud-init-${tag}/ --exclude cloud-init-${tag}/.bzr &&
- echo "Wrote ${out}"
+bzr export --format=tgz --root="cloud-init-$tag" \
+ "--revision=tag:${tag}" "$out" "$topdir" &&
+ echo "Wrote ${out}"
diff --git a/tools/make-tarball b/tools/make-tarball
index 47979f5b..27f5f374 100755
--- a/tools/make-tarball
+++ b/tools/make-tarball
@@ -18,18 +18,16 @@ if ! find_root; then
exit 1;
fi
+REVNO=$(bzr revno "$ROOT_DIR")
+
if [ ! -z "$1" ]; then
ARCHIVE_FN="$1"
else
- REVNO=$(bzr revno $ROOT_DIR)
- VERSION=$($ROOT_DIR/tools/read-version)
+ VERSION=$("$ROOT_DIR/tools/read-version")
ARCHIVE_FN="$PWD/cloud-init-$VERSION~bzr$REVNO.tar.gz"
fi
-FILES=$(cd $ROOT_DIR && bzr ls --versioned --recursive)
-echo "$FILES" | tar czf $ARCHIVE_FN \
- -C "$ROOT_DIR" \
- --transform "s,^,cloud-init-$VERSION~bzr$REVNO/," \
- --no-recursion --files-from -
+bzr export --format=tgz --root="cloud-init-$VERSION~bzr$REVNO" \
+ "--revision=${REVNO}" "${ARCHIVE_FN}" "$ROOT_DIR"
echo "$ARCHIVE_FN"
diff --git a/tools/read-dependencies b/tools/read-dependencies
index 4c88aa87..cadb09a8 100755
--- a/tools/read-dependencies
+++ b/tools/read-dependencies
@@ -21,15 +21,11 @@ fi
REQUIRES="$ROOT_DIR/Requires"
-if [ ! -e "$REQUIRES" ]
-then
+if [ ! -e "$REQUIRES" ]; then
echo "Unable to find 'Requires' file located at $REQUIRES"
exit 1
fi
# Filter out comments and empty liens
-DEPS=$(cat $REQUIRES | grep -Pv "^\s*#" | grep -Pv '^\s*$')
+DEPS=$(grep -Pv "^\s*#" "$REQUIRES" | grep -Pv '^\s*$')
echo "$DEPS" | sort -d -f
-
-
-
diff --git a/tools/read-version b/tools/read-version
index 323357fe..c76b24a9 100755
--- a/tools/read-version
+++ b/tools/read-version
@@ -27,5 +27,5 @@ then
exit 1
fi
-VERSION=$(grep -P "\d+.\d+.\d+:" $CHNG_LOG | cut -f1 -d ":" | head -n 1)
-echo $VERSION
+VERSION=$(grep -P "\d+.\d+.\d+:" "$CHNG_LOG" | cut -f1 -d ":" | head -n 1)
+echo "$VERSION"