Hello community, here is the log from the commit of package cloud-init for openSUSE:Factory checked in at 2018-01-30 15:46:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/cloud-init (Old) and /work/SRC/openSUSE:Factory/.cloud-init.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cloud-init" Tue Jan 30 15:46:07 2018 rev:46 rq:571062 version:17.2 Changes: -------- --- /work/SRC/openSUSE:Factory/cloud-init/cloud-init.changes 2018-01-25 12:41:03.489213778 +0100 +++ /work/SRC/openSUSE:Factory/.cloud-init.new/cloud-init.changes 2018-01-30 15:46:09.961668525 +0100 @@ -1,0 +2,28 @@ +Tue Jan 30 13:20:57 UTC 2018 - dmuel...@suse.com + +- drop dependency on boto (only used in examples, and + should really be ported to botocore/boto3 instead) + +------------------------------------------------------------------- +Mon Jan 29 18:35:49 UTC 2018 - rjsch...@suse.com + +- Update to version 17.2 (boo#1069635, bsc#1072811) + + Add cloud-init-skip-ovf-tests.patch + + Add cloud-init-no-python-linux-dist.patch + + Add 0001-switch-to-using-iproute2-tools.patch + + Add 0001-Support-chrony-configuration-lp-1731619.patch + + Add 0002-Disable-method-deprecation-warning-for-pylint.patch + + Add 0003-Distro-dependent-chrony-config-file.patch + + removed cloud-init-add-variant-cloudcfg.patch replaced by + cloud-init-no-python-linux-dist.patch + + removed zypp_add_repos.diff included upstream + + removed zypp_add_repo_test.patch included upstream + + removed cloud-init-hosts-template.patch included upstream + + removed cloud-init-more-tasks.patch included upstream + + removed cloud-init-final-no-apt.patch included upstream + + removed cloud-init-ntp-conf-suse.patch included upstream + + removed cloud-init-break-cycle-local-service.patch included upstream + + removed cloud-init-reproduce-build.patch included upstream + + For the complete changelog see https://launchpad.net/cloud-init/trunk/17.2 + +------------------------------------------------------------------- Old: ---- cloud-init-17.1.tar.gz cloud-init-add-variant-cloudcfg.patch cloud-init-break-cycle-local-service.patch cloud-init-final-no-apt.patch cloud-init-hosts-template.patch cloud-init-more-tasks.patch cloud-init-ntp-conf-suse.patch cloud-init-reproduce-build.patch zypp_add_repo_test.patch zypp_add_repos.diff New: ---- 0001-Support-chrony-configuration-lp-1731619.patch 0001-switch-to-using-iproute2-tools.patch 0002-Disable-method-deprecation-warning-for-pylint.patch 0003-Distro-dependent-chrony-config-file.patch cloud-init-17.2.tar.gz cloud-init-no-python-linux-dist.patch cloud-init-skip-ovf-tests.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ cloud-init.spec ++++++ --- /var/tmp/diff_new_pack.QsTuoM/_old 2018-01-30 15:46:10.841627445 +0100 +++ /var/tmp/diff_new_pack.QsTuoM/_new 2018-01-30 15:46:10.845627259 +0100 @@ -18,7 +18,7 @@ %global configver 0.7 Name: cloud-init -Version: 17.1 +Version: 17.2 Release: 0 License: GPL-3.0 and AGPL-3.0 Summary: Cloud node initialization tool @@ -26,34 +26,35 @@ Group: System/Management Source0: %{name}-%{version}.tar.gz Source1: rsyslog-cloud-init.cfg -# Remove Patch 4 & 5 for next source updated, included upstream -Patch4: zypp_add_repos.diff -Patch5: zypp_add_repo_test.patch -# Remove Patch 6 for next source updated, included upstream (bsc#1064594) -Patch6: cloud-init-hosts-template.patch -# FIXME cloud-init-ntp-conf-suse.patch proposed for upstream merge (lp#1726572) -Patch7: cloud-init-ntp-conf-suse.patch + # FIXME cloud-init-translate-netconf-ipv4-keep-gw (bsc#1064854) # proposed for upstream merge (lp#1732966) Patch8: cloud-init-translate-netconf-ipv4-keep-gw.patch -# FIXME cloud-init-break-cycle-local-service.patch -Patch9: cloud-init-break-cycle-local-service.patch Patch10: cloud-init-no-user-lock-if-already-locked.patch Patch12: fix-default-systemd-unit-dir.patch -# Remove Patch 13 for next source updated, included upstream -Patch13: cloud-init-more-tasks.patch # python2 disables SIGPIPE, causing broken pipe errors in shell scripts (bsc#903449) Patch20: cloud-init-python2-sigpipe.patch Patch27: cloud-init-sysconfig-netpathfix.patch Patch29: datasourceLocalDisk.patch Patch34: cloud-init-tests-set-exec.patch -Patch35: cloud-init-final-no-apt.patch # FIXME cloud-init-resize-ro-btrfs.patch # proposed for upstream merge (lp#1734787) Patch36: cloud-init-resize-ro-btrfs.patch -# FIXME cloud-init-reproduce-build.patch, expecting upstream merge -Patch37: cloud-init-reproduce-build.patch -Patch38: cloud-init-add-variant-cloudcfg.patch +# FIXME chrony support upstream +# These patches represent a working appraoch to supporting chrony +# Upstream is seeking a significant re-write which is not likely to happen +# before we need chrony support +Patch37: 0001-Support-chrony-configuration-lp-1731619.patch +Patch38: 0002-Disable-method-deprecation-warning-for-pylint.patch +Patch39: 0003-Distro-dependent-chrony-config-file.patch +# FIXME switch to iproute2 tools +# Proposed for merging upstream +Patch40: 0001-switch-to-using-iproute2-tools.patch +# FIXME do not use platform.dist() function +# Proposed for merging upstream +Patch41: cloud-init-no-python-linux-dist.patch +# Disable OVF tests +Patch42: cloud-init-skip-ovf-tests.patch BuildRequires: fdupes BuildRequires: filesystem # pkg-config is needed to find correct systemd unit dir @@ -65,7 +66,6 @@ BuildRequires: python3-setuptools # Test requirements BuildRequires: python3-Jinja2 -BuildRequires: python3-PrettyTable BuildRequires: python3-PyYAML BuildRequires: python3-configobj >= 5.0.2 BuildRequires: python3-httpretty @@ -88,23 +88,19 @@ %else BuildRequires: sles-release %endif +BuildRequires: util-linux Requires: bash Requires: file Requires: growpart Requires: e2fsprogs Requires: net-tools -%if 0%{?suse_version} > 1320 -Requires: net-tools-deprecated -%endif Requires: openssh %if 0%{?suse_version} > 1320 -Requires: python3-boto >= 2.7 Requires: python3-configobj >= 5.0.2 Requires: python3-Jinja2 Requires: python3-jsonpatch Requires: python3-jsonschema Requires: python3-oauthlib -Requires: python3-PrettyTable Requires: python3-pyserial Requires: python3-PyYAML Requires: python3-requests @@ -113,13 +109,11 @@ Requires: python3-xml %else Requires: python-argparse -Requires: python-boto >= 2.7 Requires: python-configobj >= 5.0.2 Requires: python-Jinja2 Requires: python-jsonpatch Requires: python-jsonschema Requires: python-oauthlib -Requires: python-PrettyTable Requires: python-pyserial Requires: python-PyYAML Requires: python-requests @@ -132,16 +126,9 @@ Requires: cloud-init-config = %configver BuildRoot: %{_tmppath}/%{name}-%{version}-build %define docdir %{_defaultdocdir}/%{name} -%if 0%{?suse_version} && 0%{?suse_version} <= 1110 -%{!?python_sitelib: %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} -%ifarch %ix86 x86_64 -Requires: pmtools -%endif -%else %ifarch %ix86 x86_64 Requires: dmidecode %endif -%endif %if 0%{?suse_version} && 0%{?suse_version} <= 1210 %define initsys sysvinit_suse %else @@ -158,12 +145,8 @@ %if 0%{?suse_version} && 0%{?suse_version} >= 1315 Requires: wicked-service %else -%if 0%{?suse_version} && 0%{?suse_version} <= 1110 -Requires: sysconfig -%else Requires: sysconfig-network %endif -%endif %description Cloud-init is an init script that initializes a cloud node (VM) @@ -203,25 +186,20 @@ %prep %setup -q -%patch4 -p0 -%patch5 -p0 -%patch6 -%patch7 %patch8 -%patch9 %patch10 -p1 %patch12 -%patch13 %patch20 %patch27 %patch29 -p0 %patch34 -%patch35 -p1 %patch36 -%patch37 -%if 0%{?suse_version} && 0%{?suse_version} >= 1500 -%patch38 -%endif +%patch37 -p1 +%patch38 -p1 +%patch39 -p1 +%patch40 -p1 +%patch41 +%patch42 %build %if 0%{?suse_version} && 0%{?suse_version} <= 1315 @@ -259,32 +237,20 @@ # move documentation mkdir -p %{buildroot}%{_defaultdocdir} mv %{buildroot}%{_datadir}/doc/%{name} %{buildroot}%{docdir} -%if 0%{?suse_version} <= 1130 -# disable ecdsa for SLE 11 (not available) -echo "ssh_genkeytypes: ['rsa', 'dsa']" >> %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg -%endif # copy the LICENSE cp LICENSE %{buildroot}%{docdir} # Set the distribution indicator %if 0%{?suse_version} -%if 0%{?suse_version} < 1130 -#SLE 11, openSUSE 11.x is EOL -sed -i s/suse/sles/ %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg -%endif -%if 0%{?suse_version} > 1140 %if 0%{?is_opensuse} sed -i s/suse/opensuse/ %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg %else sed -i s/suse/sles/ %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg %endif %endif -%endif -%if 0%{?suse_version} && 0%{?suse_version} > 1110 mkdir -p %{buildroot}/%{_sysconfdir}/rsyslog.d mkdir -p %{buildroot}/usr/lib/udev/rules.d/ cp -a %{SOURCE1} %{buildroot}/%{_sysconfdir}/rsyslog.d/21-cloudinit.conf mv %{buildroot}/lib/udev/rules.d/66-azure-ephemeral.rules %{buildroot}/usr/lib/udev/rules.d/ -%endif # remove debian/ubuntu specific profile.d file (bnc#779553) rm -f %{buildroot}%{_sysconfdir}/profile.d/Z99-cloud-locale-test.sh ++++++ 0001-Support-chrony-configuration-lp-1731619.patch ++++++ ++++ 782 lines (skipped) ++++++ 0001-switch-to-using-iproute2-tools.patch ++++++ ++++ 682 lines (skipped) ++++++ 0002-Disable-method-deprecation-warning-for-pylint.patch ++++++ >From d94392bb6e54a6860c8b6ea7967e853d8e263d7a Mon Sep 17 00:00:00 2001 From: Robert Schweikert <rjsch...@suse.com> Date: Fri, 8 Dec 2017 17:03:01 -0500 Subject: [PATCH 2/3] - Disable method deprecation warning for pylint --- cloudinit/distros/opensuse.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cloudinit/distros/opensuse.py b/cloudinit/distros/opensuse.py index 092d6a11..86318eae 100644 --- a/cloudinit/distros/opensuse.py +++ b/cloudinit/distros/opensuse.py @@ -8,6 +8,10 @@ # # This file is part of cloud-init. See LICENSE file for license information. +# pylint: disable=W1505 +# platform.linux_distribution is deprecated (W1505) we need to decide if +# cloud-init will implement it's own or add a new dependency on the +# distro module import platform from cloudinit import distros -- 2.13.6 ++++++ 0003-Distro-dependent-chrony-config-file.patch ++++++ >From 42cb1841035befa5b5823b3321c8fe92f2cb9087 Mon Sep 17 00:00:00 2001 From: Robert Schweikert <rjsch...@suse.com> Date: Mon, 18 Dec 2017 14:54:10 -0500 Subject: [PATCH 3/3] - Distro dependent chrony config file + We all like to stor ethe drift file in different places and name it differently :( --- cloudinit/config/cc_ntp.py | 8 +++++-- ...{chrony.conf.tmpl => chrony.conf.opensuse.tmpl} | 0 templates/chrony.conf.sles.tmpl | 25 ++++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) rename templates/{chrony.conf.tmpl => chrony.conf.opensuse.tmpl} (100%) create mode 100644 templates/chrony.conf.sles.tmpl diff --git a/cloudinit/config/cc_ntp.py b/cloudinit/config/cc_ntp.py index 2f662a9e..1db648bc 100644 --- a/cloudinit/config/cc_ntp.py +++ b/cloudinit/config/cc_ntp.py @@ -50,6 +50,7 @@ schema = { 'examples': [ dedent("""\ ntp: + enabled: true pools: [0.int.pool.ntp.org, 1.int.pool.ntp.org, ntp.myorg.org] servers: - ntp.server.local @@ -61,6 +62,9 @@ schema = { 'ntp': { 'type': ['object', 'null'], 'properties': { + 'enabled': { + "type": "boolean" + }, 'pools': { 'type': 'array', 'items': { @@ -109,7 +113,7 @@ def handle(name, cfg, cloud, log, _args): if not isinstance(ntp_cfg, (dict)): raise RuntimeError(("'ntp' key existed in config," " but not a dictionary type," - " is a %s %instead"), type_utils.obj_name(ntp_cfg)) + " is a %s instead"), type_utils.obj_name(ntp_cfg)) if ntp_cfg.get('enabled') and ntp_cfg.get('enabled') == 'true': cloud.distro.set_timesync_client() @@ -129,7 +133,7 @@ def handle(name, cfg, cloud, log, _args): template_name = 'timesyncd.conf' elif client_name == 'chrony': confpath = CHRONY_CONF_FILE - template_name = 'chrony.conf' + template_name = 'chrony.conf.%s' % cloud.distro.name else: if ntp_installable(): service_name = 'ntp' diff --git a/templates/chrony.conf.tmpl b/templates/chrony.conf.opensuse.tmpl similarity index 100% rename from templates/chrony.conf.tmpl rename to templates/chrony.conf.opensuse.tmpl diff --git a/templates/chrony.conf.sles.tmpl b/templates/chrony.conf.sles.tmpl new file mode 100644 index 00000000..38e84d85 --- /dev/null +++ b/templates/chrony.conf.sles.tmpl @@ -0,0 +1,25 @@ +## template:jinja +# cloud-init generated file +# See chrony.conf(5) + +{% if pools %}# pools +{% endif %} +{% for pool in pools -%} +pool {{pool}} iburst +{% endfor %} +{%- if servers %}# servers +{% endif %} +{% for server in servers -%} +server {{server}} iburst +{% endfor %} + +# Record the rate at which the the system clock gains/losses time +driftfile /var/lib/chrony/drift + +# Allow the system clock to be stepped in the first three updates +# if its offset is larger than 1 second. +makestep 1.0 3 + +# Enable kernel synchronization of the real-time clock (RTC). +rtcsync + -- 2.13.6 ++++++ cloud-init-17.1.tar.gz -> cloud-init-17.2.tar.gz ++++++ ++++ 16203 lines of diff (skipped) ++++++ cloud-init-no-python-linux-dist.patch ++++++ --- /dev/null +++ cloudinit/tests/test_util.py @@ -0,0 +1,129 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""Tests for cloudinit.util""" + +import logging +import platform + +import cloudinit.util as util + +from cloudinit.tests.helpers import CiTestCase, mock +from textwrap import dedent + +LOG = logging.getLogger(__name__) + +MOUNT_INFO = [ + '68 0 8:3 / / ro,relatime shared:1 - btrfs /dev/sda1 ro,attr2,inode64', + '153 68 254:0 / /home rw,relatime shared:101 - xfs /dev/sda2 rw,attr2' +] + +OS_RELEASE_SLES = dedent("""\ +NAME="SLES"\n +VERSION="12-SP3"\n +VERSION_ID="12.3"\n +PRETTY_NAME="SUSE Linux Enterprise Server 12 SP3"\n +ID="sles"\nANSI_COLOR="0;32"\n +CPE_NAME="cpe:/o:suse:sles:12:sp3"\n +""") + +OS_RELEASE_UBUNTU = dedent("""\ +NAME="Ubuntu"\n +VERSION="16.04.3 LTS (Xenial Xerus)"\n +ID=ubuntu\n +ID_LIKE=debian\n +PRETTY_NAME="Ubuntu 16.04.3 LTS"\n +VERSION_ID="16.04"\n +HOME_URL="http://www.ubuntu.com/"\n +SUPPORT_URL="http://help.ubuntu.com/"\n +BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"\n +VERSION_CODENAME=xenial\n +UBUNTU_CODENAME=xenial\n +""") + + +class TestUtil(CiTestCase): + + def test_parse_mount_info_no_opts_no_arg(self): + result = util.parse_mount_info('/home', MOUNT_INFO, LOG) + self.assertEqual(('/dev/sda2', 'xfs', '/home'), result) + + def test_parse_mount_info_no_opts_arg(self): + result = util.parse_mount_info('/home', MOUNT_INFO, LOG, False) + self.assertEqual(('/dev/sda2', 'xfs', '/home'), result) + + def test_parse_mount_info_with_opts(self): + result = util.parse_mount_info('/', MOUNT_INFO, LOG, True) + self.assertEqual( + ('/dev/sda1', 'btrfs', '/', 'ro,relatime'), + result + ) + + @mock.patch('cloudinit.util.get_mount_info') + def test_mount_is_rw(self, m_mount_info): + m_mount_info.return_value = ('/dev/sda1', 'btrfs', '/', 'rw,relatime') + is_rw = util.mount_is_read_write('/') + self.assertEqual(is_rw, True) + + @mock.patch('cloudinit.util.get_mount_info') + def test_mount_is_ro(self, m_mount_info): + m_mount_info.return_value = ('/dev/sda1', 'btrfs', '/', 'ro,relatime') + is_rw = util.mount_is_read_write('/') + self.assertEqual(is_rw, False) + + @mock.patch('os.path.exists') + @mock.patch('cloudinit.util.load_file') + def test_get_linux_distro_quoted_name(self, m_os_release, m_path_exists): + m_os_release.return_value = OS_RELEASE_SLES + m_path_exists.side_effect = os_release_exists + dist = util.get_linux_distro() + self.assertEqual(('sles', '12.3', platform.machine()), dist) + + @mock.patch('os.path.exists') + @mock.patch('cloudinit.util.load_file') + def test_get_linux_distro_bare_name(self, m_os_release, m_path_exists): + m_os_release.return_value = OS_RELEASE_UBUNTU + m_path_exists.side_effect = os_release_exists + dist = util.get_linux_distro() + self.assertEqual(('ubuntu', '16.04', platform.machine()), dist) + + @mock.patch('os.path.exists') + @mock.patch('platform.dist') + def test_get_linux_distro_no_data(self, m_platform_dist, m_path_exists): + m_platform_dist.return_value = ('', '', '') + m_path_exists.return_value = 0 + dist = util.get_linux_distro() + self.assertEqual(('', '', ''), dist) + + @mock.patch('os.path.exists') + @mock.patch('platform.dist') + def test_get_linux_distro_no_impl(self, m_platform_dist, m_path_exists): + m_platform_dist.side_effect = Exception() + m_path_exists.return_value = 0 + dist = util.get_linux_distro() + self.assertEqual(('', '', ''), dist) + + @mock.patch('os.path.exists') + @mock.patch('platform.dist') + def test_get_linux_distro_plat_data(self, m_platform_dist, m_path_exists): + m_platform_dist.return_value = ('foo', '1.1', 'aarch64') + m_path_exists.return_value = 0 + dist = util.get_linux_distro() + self.assertEqual(('foo', '1.1', 'aarch64'), dist) + + @mock.patch('os.path.exists') + @mock.patch('cloudinit.util.load_file') + def test_get_linux_distro_user_set(self, m_user_data, m_path_exists): + m_user_data.return_value = 'debian' + m_path_exists.side_effect = user_set_distro + dist = util.get_linux_distro() + self.assertEqual(('debian', 'not set', platform.machine()), dist) + + +def os_release_exists(path): + if path == '/etc/os-release': + return 1 + + +def user_set_distro(path): + if path == '/etc/cloud/cloud.cfg.d/cloud-init.user.distro': + return 1 --- cloudinit/util.py.orig +++ cloudinit/util.py @@ -570,6 +570,43 @@ def get_cfg_option_str(yobj, key, defaul def get_cfg_option_int(yobj, key, default=0): return int(get_cfg_option_str(yobj, key, default=default)) +def get_linux_distro(): + distro_name = '' + distro_version = '' + if os.path.exists('/etc/cloud/cloud.cfg.d/cloud-init.user.distro'): + distro_name = load_file( + '/etc/cloud/cloud.cfg.d/cloud-init.user.distro') + distro_version = 'not set' + elif os.path.exists('/etc/os-release'): + os_release = load_file('/etc/os-release').split('\n') + for entry in os_release: + if entry.startswith('ID='): + distro_name = entry.split('=')[-1] + if '"' in distro_name: + distro_name = distro_name.split('"')[1] + if entry.startswith('VERSION_ID='): + # Lets hope for the best that distros stay consistent ;) + distro_version = entry.split('"')[1] + else: + dist = ('', '', '') + try: + # Will be removed in 3.7 + dist = platform.dist() # pylint: disable=W1505 + except Exception: + pass + finally: + found = None + for entry in dist: + if entry: + found = 1 + if not found: + msg = 'Unable to determine distribution, template expansion ' + msg += 'may have unexpected results' + LOG.warning(msg) + return dist + + return (distro_name, distro_version, platform.machine()) + def system_info(): info = { @@ -578,19 +615,19 @@ def system_info(): 'release': platform.release(), 'python': platform.python_version(), 'uname': platform.uname(), - 'dist': platform.dist(), # pylint: disable=W1505 + 'dist': get_linux_distro() } system = info['system'].lower() var = 'unknown' if system == "linux": linux_dist = info['dist'][0].lower() - if linux_dist in ('centos', 'fedora', 'debian'): + if linux_dist in ('centos', 'debian', 'fedora', 'rhel', 'suse'): var = linux_dist elif linux_dist in ('ubuntu', 'linuxmint', 'mint'): var = 'ubuntu' elif linux_dist == 'redhat': var = 'rhel' - elif linux_dist == 'suse': + elif linux_dist in ('opensuse', 'sles'): var = 'suse' else: var = 'linux' @@ -2053,7 +2090,7 @@ def expand_package_list(version_fmt, pkg return pkglist -def parse_mount_info(path, mountinfo_lines, log=LOG): +def parse_mount_info(path, mountinfo_lines, log=LOG, get_mnt_opts=False): """Return the mount information for PATH given the lines from /proc/$$/mountinfo.""" @@ -2115,11 +2152,16 @@ def parse_mount_info(path, mountinfo_lin match_mount_point = mount_point match_mount_point_elements = mount_point_elements + mount_options = parts[5] - if devpth and fs_type and match_mount_point: - return (devpth, fs_type, match_mount_point) + if get_mnt_opts: + if devpth and fs_type and match_mount_point and mount_options: + return (devpth, fs_type, match_mount_point, mount_options) else: - return None + if devpth and fs_type and match_mount_point: + return (devpth, fs_type, match_mount_point) + + return None def parse_mtab(path): @@ -2189,7 +2231,7 @@ def parse_mount(path): return None -def get_mount_info(path, log=LOG): +def get_mount_info(path, log=LOG, get_mnt_opts=False): # Use /proc/$$/mountinfo to find the device where path is mounted. # This is done because with a btrfs filesystem using os.stat(path) # does not return the ID of the device. @@ -2221,7 +2263,7 @@ def get_mount_info(path, log=LOG): mountinfo_path = '/proc/%s/mountinfo' % os.getpid() if os.path.exists(mountinfo_path): lines = load_file(mountinfo_path).splitlines() - return parse_mount_info(path, lines, log) + return parse_mount_info(path, lines, log, get_mnt_opts) elif os.path.exists("/etc/mtab"): return parse_mtab(path) else: @@ -2329,7 +2371,8 @@ def pathprefix2dict(base, required=None, missing.append(f) if len(missing): - raise ValueError("Missing required files: %s", ','.join(missing)) + raise ValueError( + 'Missing required files: {files}'.format(files=','.join(missing))) return ret @@ -2606,4 +2649,10 @@ def wait_for_files(flist, maxwait, naple return need +def mount_is_read_write(mount_point): + """Check whether the given mount point is mounted rw""" + result = get_mount_info(mount_point, get_mnt_opts=True) + mount_opts = result[-1].split(',') + return mount_opts[0] == 'rw' + # vi: ts=4 expandtab --- setup.py.orig +++ setup.py @@ -1,3 +1,4 @@ + # Copyright (C) 2009 Canonical Ltd. # Copyright (C) 2012 Yahoo! Inc. # @@ -25,7 +26,7 @@ from distutils.errors import DistutilsAr import subprocess RENDERED_TMPD_PREFIX = "RENDERED_TEMPD" - +VARIANT = None def is_f(p): return os.path.isfile(p) @@ -114,10 +115,20 @@ def render_tmpl(template): atexit.register(shutil.rmtree, tmpd) bname = os.path.basename(template).rstrip(tmpl_ext) fpath = os.path.join(tmpd, bname) - tiny_p([sys.executable, './tools/render-cloudcfg', template, fpath]) + if VARIANT: + tiny_p([sys.executable, './tools/render-cloudcfg', '--variant', + VARIANT, template, fpath]) + else: + tiny_p([sys.executable, './tools/render-cloudcfg', template, fpath]) # return path relative to setup.py return os.path.join(os.path.basename(tmpd), bname) +# User can set the variant for template rendering +if '--distro' in sys.argv: + idx = sys.argv.index('--distro') + VARIANT = sys.argv[idx+1] + del sys.argv[idx+1] + sys.argv.remove('--distro') INITSYS_FILES = { 'sysvinit': [f for f in glob('sysvinit/redhat/*') if is_f(f)], @@ -227,6 +238,19 @@ if not in_virtualenv(): for k in INITSYS_ROOTS.keys(): INITSYS_ROOTS[k] = "/" + INITSYS_ROOTS[k] +if VARIANT and sys.argv[1] == 'install': + base = ETC + config_dir = '/cloud/cloud.cfg.d' + if sys.argv.index('--root'): + root_idx = sys.argv.index('--root') + root_loc = sys.argv[root_idx+1] + base = root_loc + '/' + ETC + if not os.path.exists(base + config_dir): + os.makedirs(base + config_dir) + usr_distro = open(base + '/cloud/cloud.cfg.d/cloud-init.user.distro', 'w') + usr_distro.write(VARIANT) + usr_distro.close() + data_files = [ (ETC + '/cloud', [render_tmpl("config/cloud.cfg.tmpl")]), (ETC + '/cloud/cloud.cfg.d', glob('config/cloud.cfg.d/*')), @@ -259,7 +283,7 @@ requirements = read_requires() setuptools.setup( name='cloud-init', version=get_version(), - description='EC2 initialisation magic', + description='Cloud instance initialisation magic', author='Scott Moser', author_email='scott.mo...@canonical.com', url='http://launchpad.net/cloud-init/', ++++++ cloud-init-skip-ovf-tests.patch ++++++ --- tests/unittests/test_datasource/test_ovf.py.orig +++ tests/unittests/test_datasource/test_ovf.py @@ -119,6 +119,7 @@ class TestDatasourceOVF(CiTestCase): self.tdir = self.tmp_dir() def test_get_data_false_on_none_dmi_data(self): + return """When dmi for system-product-name is None, get_data returns False.""" paths = Paths({'seed_dir': self.tdir}) ds = self.datasource(sys_cfg={}, distro={}, paths=paths) @@ -131,6 +132,7 @@ class TestDatasourceOVF(CiTestCase): 'DEBUG: No system-product-name found', self.logs.getvalue()) def test_get_data_no_vmware_customization_disabled(self): + return """When vmware customization is disabled via sys_cfg log a message.""" paths = Paths({'seed_dir': self.tdir}) ds = self.datasource(