diff --git a/ChangeLog b/ChangeLog index 8113da9c..1286e7c1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 0.7.5: - open 0.7.5 + - Add a debug log message around import failures + - add a 'debug' module for easily printing out some information about + datasource and cloud-init [Shraddha Pandhe] + - support running apt with 'eatmydata' via configuration token + apt_get_wrapper (LP: #1236531). + - convert paths provided in config-drive 'files' to string before writing + (LP: #1260072). 0.7.4: - fix issue mounting 'ephemeral0' if ephemeral0 was an alias for a partitioned block device with target filesystem on ephemeral0.1. diff --git a/cloudinit/config/cc_debug.py b/cloudinit/config/cc_debug.py new file mode 100644 index 00000000..cfd31fa1 --- /dev/null +++ b/cloudinit/config/cc_debug.py @@ -0,0 +1,79 @@ +# vi: ts=4 expandtab +# +# Copyright (C) 2013 Yahoo! Inc. +# +# 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 . + +from StringIO import StringIO +from cloudinit import util +from cloudinit import type_utils +import copy + + +def _make_header(text): + header = StringIO() + header.write("-" * 80) + header.write("\n") + header.write(text.center(80, ' ')) + header.write("\n") + header.write("-" * 80) + header.write("\n") + return header.getvalue() + + +def handle(name, cfg, cloud, log, args): + verbose = util.get_cfg_by_path(cfg, ('debug', 'verbose'), default=True) + if args: + # if args are provided (from cmdline) then explicitly set verbose + out_file = args[0] + verbose = True + else: + out_file = util.get_cfg_by_path(cfg, ('debug', 'output')) + + if not verbose: + log.debug(("Skipping module named %s," + " verbose printing disabled"), name) + return + # Clean out some keys that we just don't care about showing... + dump_cfg = copy.deepcopy(cfg) + for k in ['log_cfgs']: + dump_cfg.pop(k, None) + all_keys = list(dump_cfg.keys()) + for k in all_keys: + if k.startswith("_"): + dump_cfg.pop(k, None) + # Now dump it... + to_print = StringIO() + to_print.write(_make_header("Config")) + to_print.write(util.yaml_dumps(dump_cfg)) + to_print.write("\n") + to_print.write(_make_header("MetaData")) + to_print.write(util.yaml_dumps(cloud.datasource.metadata)) + to_print.write("\n") + to_print.write(_make_header("Misc")) + to_print.write("Datasource: %s\n" % + (type_utils.obj_name(cloud.datasource))) + to_print.write("Distro: %s\n" % (type_utils.obj_name(cloud.distro))) + to_print.write("Hostname: %s\n" % (cloud.get_hostname(True))) + to_print.write("Instance ID: %s\n" % (cloud.get_instance_id())) + to_print.write("Locale: %s\n" % (cloud.get_locale())) + to_print.write("Launch IDX: %s\n" % (cloud.launch_index)) + contents = to_print.getvalue() + content_to_file = [] + for line in contents.splitlines(): + line = "ci-info: %s\n" % (line) + content_to_file.append(line) + if out_file: + util.write_file(out_file, "".join(content_to_file), 0644, "w") + else: + util.multi_log("".join(content_to_file), console=True, stderr=False) diff --git a/cloudinit/distros/debian.py b/cloudinit/distros/debian.py index 8fe49cbe..1ae232fd 100644 --- a/cloudinit/distros/debian.py +++ b/cloudinit/distros/debian.py @@ -36,6 +36,10 @@ LOG = logging.getLogger(__name__) APT_GET_COMMAND = ('apt-get', '--option=Dpkg::Options::=--force-confold', '--option=Dpkg::options::=--force-unsafe-io', '--assume-yes', '--quiet') +APT_GET_WRAPPER = { + 'command': 'eatmydata', + 'enabled': 'auto', +} class Distro(distros.Distro): @@ -148,7 +152,13 @@ class Distro(distros.Distro): # See: http://tiny.cc/kg91fw # Or: http://tiny.cc/mh91fw e['DEBIAN_FRONTEND'] = 'noninteractive' - cmd = list(self.get_option("apt_get_command", APT_GET_COMMAND)) + + wcfg = self.get_option("apt_get_wrapper", APT_GET_WRAPPER) + cmd = _get_wrapper_prefix( + wcfg.get('command', APT_GET_WRAPPER['command']), + wcfg.get('enabled', APT_GET_WRAPPER['enabled'])) + + cmd.extend(list(self.get_option("apt_get_command", APT_GET_COMMAND))) if args and isinstance(args, str): cmd.append(args) @@ -166,7 +176,9 @@ class Distro(distros.Distro): cmd.extend(pkglist) # Allow the output of this to flow outwards (ie not be captured) - util.subp(cmd, env=e, capture=False) + util.log_time(logfunc=LOG.debug, + 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, @@ -175,3 +187,15 @@ class Distro(distros.Distro): def get_primary_arch(self): (arch, _err) = util.subp(['dpkg', '--print-architecture']) return str(arch).strip() + + +def _get_wrapper_prefix(cmd, mode): + if isinstance(cmd, str): + cmd = [str(cmd)] + + if (util.is_true(mode) or + (str(mode).lower() == "auto" and cmd[0] and + util.which(cmd[0]))): + return cmd + else: + return [] diff --git a/cloudinit/importer.py b/cloudinit/importer.py index 71cf2726..a094141a 100644 --- a/cloudinit/importer.py +++ b/cloudinit/importer.py @@ -36,6 +36,7 @@ def find_module(base_name, search_paths, required_attrs=None): found_places = [] if not required_attrs: required_attrs = [] + # NOTE(harlowja): translate the search paths to include the base name. real_paths = [] for path in search_paths: real_path = [] @@ -50,8 +51,9 @@ def find_module(base_name, search_paths, required_attrs=None): mod = None try: mod = import_module(full_path) - except ImportError: - pass + except ImportError as e: + LOG.debug("Failed at attempted import of '%s' due to: %s", + full_path, e) if not mod: continue found_attrs = 0 diff --git a/cloudinit/util.py b/cloudinit/util.py index b69e2bb0..6b30af5e 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -170,6 +170,8 @@ class SeLinuxGuard(object): def __exit__(self, excp_type, excp_value, excp_traceback): if self.selinux and self.selinux.is_selinux_enabled(): path = os.path.realpath(os.path.expanduser(self.path)) + # path should be a string, not unicode + path = str(path) do_restore = False try: # See if even worth restoring?? diff --git a/doc/examples/cloud-config-datasources.txt b/doc/examples/cloud-config-datasources.txt index 65a3cdf5..3bde4aac 100644 --- a/doc/examples/cloud-config-datasources.txt +++ b/doc/examples/cloud-config-datasources.txt @@ -49,7 +49,6 @@ datasource: hostname_bounce: interface: eth0 policy: on # [can be 'on', 'off' or 'force'] - } SmartOS: # Smart OS datasource works over a serial console interacting with diff --git a/doc/examples/cloud-config-disk-setup.txt b/doc/examples/cloud-config-disk-setup.txt index 6ad61c33..0dfef8e8 100644 --- a/doc/examples/cloud-config-disk-setup.txt +++ b/doc/examples/cloud-config-disk-setup.txt @@ -1,24 +1,24 @@ -Cloud-init supports the creation of simple partition tables and file systems -on devices. +# Cloud-init supports the creation of simple partition tables and file systems +# on devices. -Default disk definitions for AWS --------------------------------- -(Not implemented yet, but provided for future documentation) +# Default disk definitions for AWS +# -------------------------------- +# (Not implemented yet, but provided for future documentation) - disk_setup: - ephmeral0: - type: 'mbr' - layout: True - overwrite: False +disk_setup: + ephmeral0: + type: 'mbr' + layout: True + overwrite: False - fs_setup: - - label: None, - filesystem: ext3 - device: ephemeral0 - partition: auto +fs_setup: + - label: None, + filesystem: ext3 + device: ephemeral0 + partition: auto -Default disk definitions for Windows Azure ------------------------------------------- +# Default disk definitions for Windows Azure +# ------------------------------------------ device_aliases: {'ephemeral0': '/dev/sdb'} disk_setup: @@ -34,8 +34,8 @@ fs_setup: replace_fs: ntfs -Default disk definitions for SmartOS ------------------------------------- +# Default disk definitions for SmartOS +# ------------------------------------ device_aliases: {'ephemeral0': '/dev/sdb'} disk_setup: @@ -49,203 +49,203 @@ fs_setup: filesystem: ext3 device: ephemeral0.0 -Cavaut for SmartOS: if ephemeral disk is not defined, then the disk will - not be automatically added to the mounts. +# Cavaut for SmartOS: if ephemeral disk is not defined, then the disk will +# not be automatically added to the mounts. -The default definition is used to make sure that the ephemeral storage is -setup properly. +# The default definition is used to make sure that the ephemeral storage is +# setup properly. -"disk_setup": disk partitioning --------------------------------- +# "disk_setup": disk partitioning +# -------------------------------- -The disk_setup directive instructs Cloud-init to partition a disk. The format is: +# The disk_setup directive instructs Cloud-init to partition a disk. The format is: - disk_setup: - ephmeral0: - type: 'mbr' - layout: 'auto' - /dev/xvdh: - type: 'mbr' - layout: - - 33 - - [33, 82] - - 33 - overwrite: True +disk_setup: + ephmeral0: + type: 'mbr' + layout: 'auto' + /dev/xvdh: + type: 'mbr' + layout: + - 33 + - [33, 82] + - 33 + overwrite: True -The format is a list of dicts of dicts. The first value is the name of the -device and the subsequent values define how to create and layout the partition. +# The format is a list of dicts of dicts. The first value is the name of the +# device and the subsequent values define how to create and layout the +# partition. +# The general format is: +# disk_setup: +# : +# type: 'mbr' +# layout: +# overwrite: +# +# Where: +# : The name of the device. 'ephemeralX' and 'swap' are special +# values which are specific to the cloud. For these devices +# Cloud-init will look up what the real devices is and then +# use it. +# +# For other devices, the kernel device name is used. At this +# time only simply kernel devices are supported, meaning +# that device mapper and other targets may not work. +# +# Note: At this time, there is no handling or setup of +# device mapper targets. +# +# type=: Currently the following are supported: +# 'mbr': default and setups a MS-DOS partition table +# +# Note: At this time only 'mbr' partition tables are allowed. +# It is anticipated in the future that we'll have GPT as +# option in the future, or even "RAID" to create a mdadm +# RAID. +# +# layout={...}: The device layout. This is a list of values, with the +# percentage of disk that partition will take. +# Valid options are: +# [, [, is the _percentage_ of the disk to use, while +# is the numerical value of the partition type. +# +# The following setups two partitions, with the first +# partition having a swap label, taking 1/3 of the disk space +# and the remainder being used as the second partition. +# /dev/xvdh': +# type: 'mbr' +# layout: +# - [33,82] +# - 66 +# overwrite: True +# +# When layout is "true" it means single partition the entire +# device. +# +# When layout is "false" it means don't partition or ignore +# existing partitioning. +# +# If layout is set to "true" and overwrite is set to "false", +# it will skip partitioning the device without a failure. +# +# overwrite=: This describes whether to ride with saftey's on and +# everything holstered. +# +# 'false' is the default, which means that: +# 1. The device will be checked for a partition table +# 2. The device will be checked for a file system +# 3. If either a partition of file system is found, then +# the operation will be _skipped_. +# +# 'true' is cowboy mode. There are no checks and things are +# done blindly. USE with caution, you can do things you +# really, really don't want to do. +# +# +# fs_setup: Setup the file system +# ------------------------------- +# +# fs_setup describes the how the file systems are supposed to look. -The general format is: - disk_setup: - : - type: 'mbr' - layout: - overwrite: +fs_setup: + - label: ephemeral0 + filesystem: 'ext3' + device: 'ephemeral0' + partition: 'auto' + - label: mylabl2 + filesystem: 'ext4' + device: '/dev/xvda1' + - special: + cmd: mkfs -t %(FILESYSTEM)s -L %(LABEL)s %(DEVICE)s + filesystem: 'btrfs' + device: '/dev/xvdh' -Where: - : The name of the device. 'ephemeralX' and 'swap' are special - values which are specific to the cloud. For these devices - Cloud-init will look up what the real devices is and then - use it. - - For other devices, the kernel device name is used. At this - time only simply kernel devices are supported, meaning - that device mapper and other targets may not work. - - Note: At this time, there is no handling or setup of - device mapper targets. - - type=: Currently the following are supported: - 'mbr': default and setups a MS-DOS partition table - - Note: At this time only 'mbr' partition tables are allowed. - It is anticipated in the future that we'll have GPT as - option in the future, or even "RAID" to create a mdadm - RAID. - - layout={...}: The device layout. This is a list of values, with the - percentage of disk that partition will take. - Valid options are: - [, [, is the _percentage_ of the disk to use, while - is the numerical value of the partition type. - - The following setups two partitions, with the first - partition having a swap label, taking 1/3 of the disk space - and the remainder being used as the second partition. - /dev/xvdh': - type: 'mbr' - layout: - - [33,82] - - 66 - overwrite: True - - When layout is "true" it means single partition the entire - device. - - When layout is "false" it means don't partition or ignore - existing partitioning. - - If layout is set to "true" and overwrite is set to "false", - it will skip partitioning the device without a failure. - - overwrite=: This describes whether to ride with saftey's on and - everything holstered. - - 'false' is the default, which means that: - 1. The device will be checked for a partition table - 2. The device will be checked for a file system - 3. If either a partition of file system is found, then - the operation will be _skipped_. - - 'true' is cowboy mode. There are no checks and things are - done blindly. USE with caution, you can do things you - really, really don't want to do. - - -fs_setup: Setup the file system -------------------------------- - -fs_setup describes the how the file systems are supposed to look. - - fs_setup: - - label: ephemeral0 - filesystem: 'ext3' - device: 'ephemeral0' - partition: 'auto' - - label: mylabl2 - filesystem: 'ext4' - device: '/dev/xvda1' - - special: - cmd: mkfs -t %(FILESYSTEM)s -L %(LABEL)s %(DEVICE)s - filesystem: 'btrfs' - device: '/dev/xvdh' - -The general format is: - fs_setup: - - label: