diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | cloudinit/distros/debian.py | 7 | ||||
-rw-r--r-- | cloudinit/distros/rhel.py | 73 | ||||
-rw-r--r-- | cloudinit/log.py | 6 | ||||
-rw-r--r-- | cloudinit/sources/DataSourceConfigDrive.py | 3 | ||||
-rw-r--r-- | cloudinit/sources/DataSourceNoCloud.py | 3 | ||||
-rw-r--r-- | cloudinit/util.py | 1 | ||||
-rw-r--r-- | doc/examples/cloud-config.txt | 18 | ||||
-rw-r--r-- | tests/unittests/test_datasource/test_configdrive.py | 5 | ||||
-rwxr-xr-x | tools/ccfg-merge-debug | 89 | ||||
-rwxr-xr-x | tools/make-dist-tarball | 14 | ||||
-rwxr-xr-x | tools/make-tarball | 12 | ||||
-rwxr-xr-x | tools/read-dependencies | 8 | ||||
-rwxr-xr-x | tools/read-version | 4 |
14 files changed, 197 insertions, 50 deletions
@@ -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" |