Hello community,

here is the log from the commit of package cloud-init for openSUSE:Factory 
checked in at 2017-11-03 16:28:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/cloud-init (Old)
 and      /work/SRC/openSUSE:Factory/.cloud-init.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "cloud-init"

Fri Nov  3 16:28:01 2017 rev:40 rq:538365 version:17.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/cloud-init/cloud-init.changes    2017-09-20 
17:14:13.332622059 +0200
+++ /work/SRC/openSUSE:Factory/.cloud-init.new/cloud-init.changes       
2017-11-03 16:29:18.070490741 +0100
@@ -1,0 +2,558 @@
+Thu Nov  2 13:16:49 UTC 2017 - [email protected]
+
+- Fix sed expression to set distro properly (boo#1063716)
+
+-------------------------------------------------------------------
+Thu Sep 21 17:32:55 EDT 2017 - [email protected]
+
+- Update to version 17.1 (bsc#1035106)
+  + Version numbering scheme change now YY.NUMBER_OF_RELESE_THAT_YEAR
+  + Remove cloud.cfg.suse, use generated default config file
+  + Remove addopenSUSEBase.patch, included upstream
+  + Remove suseIntegratedHandler.patch, included upstream
+  + Remove openSUSEhostsTemplate.diff, included upstream
+  + Remove cloud-init-handle-no-carrier.patch, included upstream
+  + Remove cloud-init-digital-ocean-datasource.patch,
+    use upstream implementation
+  + Remove cloud-init-digital-ocean-datasource-enable-by-default.patch,
+    use upstream implementation
+  + Remove cloud-init-fix-unicode-handling-binarydecode.patch,
+    included upstream
+  + Remove cloud-init-no-dmidecode-on-ppc64.patch, included upstream
+  + Remove dataSourceOpenNebula.patch, use upstream implementation
+  + Remove setupSUSEsysVInit.diff, included upstream
+  + Remove suseSysVInit.diff, included upstream
+  + Remove cloud-init-finalbeforelogin.patch, don't block login 
+  + Remove cloud-init-handle-not-implemented-query.patch, query option removed
+  + Remove cloud-init-spceandtabs-clean.patch, indentation fixed upstream
+  + Remove dynamicInitCmd.diff, different solution from upstream
+  + Added cloud-init-more-tasks.patch, (bsc#1047363)
+    replace cloud-init-finalbeforelogin.patch
+  + Forward port cloud-init-python2-sigpipe.patch
+  + Remove cloud-init-net-eni.patch, included upstream
+  + Remove cloud-init-service.patch, included upstream
+  + Forward port cloud-init-sysconfig-netpathfix.patch
+  + Remove cloud-init-net-sysconfig-lp1665441.patch, included upstream
+  + Remove cloud-init-python26.patch, included upstream
+  + Remove skip-argparse-on-python3.patch
+  + Add cloud-init-tests-set-exec.patch
+  + Add cloud-init-final-no-apt.patch
+  + Add zypp_add_repo_test.patch
+  + doc: document GCE datasource. [Arnd Hannemann]
+  + suse: updates to templates to support openSUSE and SLES.
+  + [Robert Schweikert] (LP: #1718640)
+  + suse: Copy sysvinit files from redhat with slight changes.
+  + [Robert Schweikert] (LP: #1718649)
+  + docs: fix sphinx module schema documentation [Chad Smith]
+  + tests: Add cloudinit package to all test targets [Chad Smith]
+  + Makefile: No longer look for yaml files in obsolete ./bin/.
+  + tests: fix ds-identify unit tests to set EC2_STRICT_ID_DEFAULT.
+  + ec2: Fix maybe_perform_dhcp_discovery to use /var/tmp as a tmpdir
+  + [Chad Smith] (LP: #1717627)
+  + Azure: wait longer for SSH pub keys to arrive.
+  + [Paul Meyer] (LP: #1717611)
+  + GCE: Fix usage of user-data. (LP: #1717598)
+  + cmdline: add collect-logs subcommand. [Chad Smith] (LP: #1607345)
+  + CloudStack: consider dhclient lease files named with a hyphen.
+  + (LP: #1717147)
+  + resizefs: Drop check for read-only device file, do not warn on
+  + overlayroot. [Chad Smith]
+  + Do not provide systemd-fsck drop-in which could cause ordering cycles.
+  + [Balint Reczey] (LP: #1717477)
+  + tests: Enable the NoCloud KVM platform [Joshua Powers]
+  + resizefs: pass mount point to xfs_growfs [Dusty Mabe]
+  + vmware: Enable nics before sending the SUCCESS event. [Sankar Tanguturi]
+  + cloud-config modules: honor distros definitions in each module
+  + [Chad Smith] (LP: #1715738, #1715690)
+  + chef: Add option to pin chef omnibus install version
+  + [Ethan Apodaca] (LP: #1462693)
+  + tests: execute: support command as string [Joshua Powers]
+  + schema and docs: Add jsonschema to resizefs and bootcmd modules
+  + [Chad Smith]
+  + tools: Add xkvm script, wrapper around qemu-system [Joshua Powers]
+  + vmware customization: return network config format
+  + [Sankar Tanguturi] (LP: #1675063)
+  + Ec2: only attempt to operate at local mode on known platforms.
+  + (LP: #1715128)
+  + Use /run/cloud-init for tempfile operations. (LP: #1707222)
+  + ds-identify: Make OpenStack return maybe on arch other than intel.
+  + (LP: #1715241)
+  + tests: mock missed openstack metadata uri network_data.json
+  + [Chad Smith] (LP: #1714376)
+  + relocate tests/unittests/helpers.py to cloudinit/tests
+  + [Lars Kellogg-Stedman]
+  + tox: add nose timer output [Joshua Powers]
+  + upstart: do not package upstart jobs, drop ubuntu-init-switch module.
+  + tests: Stop leaking calls through unmocked metadata addresses
+  + [Chad Smith] (LP: #1714117)
+  + distro: allow distro to specify a default locale [Ryan Harper]
+  + tests: fix two recently added tests for sles distro.
+  + url_helper: dynamically import oauthlib import from inside oauth_headers
+  + [Chad Smith]
+  + tox: make xenial environment run with python3.6
+  + suse: Add support for openSUSE and return SLES to a working state.
+  + [Robert Schweikert]
+  + GCE: Add a main to the GCE Datasource.
+  + ec2: Add IPv6 dhcp support to Ec2DataSource. [Chad Smith] (LP: #1639030)
+  + url_helper: fail gracefully if oauthlib is not available
+  + [Lars Kellogg-Stedman] (LP: #1713760)
+  + cloud-init analyze: fix issues running under python 2. [Andrew Jorgensen]
+  + Configure logging module to always use UTC time.
+  + [Ryan Harper] (LP: #1713158)
+  + Log a helpful message if a user script does not include shebang.
+  + [Andrew Jorgensen]
+  + cli: Fix command line parsing of coniditionally loaded subcommands.
+  + [Chad Smith] (LP: #1712676)
+  + doc: Explain error behavior in user data include file format.
+  + [Jason Butz]
+  + cc_landscape & cc_puppet: Fix six.StringIO use in writing configs
+  + [Chad Smith] (LP: #1699282, #1710932)
+  + schema cli: Add schema subcommand to cloud-init cli and cc_runcmd schema
+  + [Chad Smith]
+  + Debian: Remove non-free repositories from apt sources template.
+  + [Joonas Kylmälä] (LP: #1700091)
+  + tools: Add tooling for basic cloud-init performance analysis.
+  + [Chad Smith] (LP: #1709761)
+  + network: add v2 passthrough and fix parsing v2 config with bonds/bridge
+  + params [Ryan Harper] (LP: #1709180)
+  + doc: update capabilities with features available, link doc reference,
+  + cli example [Ryan Harper]
+  + vcloud directory: Guest Customization support for passwords
+  + [Maitreyee Saikia]
+  + ec2: Allow Ec2 to run in init-local using dhclient in a sandbox.
+  + [Chad Smith] (LP: #1709772)
+  + cc_ntp: fallback on timesyncd configuration if ntp is not installable
+  + [Ryan Harper] (LP: #1686485)
+  + net: Reduce duplicate code. Have get_interfaces_by_mac use
+  + get_interfaces.
+  + tests: Fix build tree integration tests [Joshua Powers]
+  + sysconfig: Dont repeat header when rendering resolv.conf
+  + [Ryan Harper] (LP: #1701420)
+  + archlinux: Fix bug with empty dns, do not render 'lo' devices.
+  + (LP: #1663045, #1706593)
+  + cloudinit.net: add initialize_network_device function and tests
+  + [Chad Smith]
+  + makefile: fix ci-deps-ubuntu target [Chad Smith]
+  + tests: adjust locale integration test to parse default locale.
+  + tests: remove 'yakkety' from releases as it is EOL.
+  + tests: Add initial tests for EC2 and improve a docstring.
+  + locale: Do not re-run locale-gen if provided locale is system default.
+  + archlinux: fix set hostname usage of write_file.
+  + [Joshua Powers] (LP: #1705306)
+  + sysconfig: support subnet type of 'manual'.
+  + tools/run-centos: make running with no argument show help.
+  + Drop rand_str() usage in DNS redirection detection
+  + [Bob Aman] (LP: #1088611)
+  + sysconfig: use MACADDR on bonds/bridges to configure mac_address
+  + [Ryan Harper] (LP: #1701417)
+  + net: eni route rendering missed ipv6 default route config
+  + [Ryan Harper] (LP: #1701097)
+  + sysconfig: enable mtu set per subnet, including ipv6 mtu
+  + [Ryan Harper] (LP: #1702513)
+  + sysconfig: handle manual type subnets [Ryan Harper] (LP: #1687725)
+  + sysconfig: fix ipv6 gateway routes [Ryan Harper] (LP: #1694801)
+  + sysconfig: fix rendering of bond, bridge and vlan types.
+  + [Ryan Harper] (LP: #1695092)
+  + Templatize systemd unit files for cross distro deltas. [Ryan Harper]
+  + sysconfig: ipv6 and default gateway fixes. [Ryan Harper] (LP: #1704872)
+  + net: fix renaming of nics to support mac addresses written in upper
+  + case. (LP: #1705147)
+  + tests: fixes for issues uncovered when moving to python 3.6.
+  + (LP: #1703697)
+  + sysconfig: include GATEWAY value if set in subnet
+  + [Ryan Harper] (LP: #1686856)
+  + Scaleway: add datasource with user and vendor data for Scaleway.
+  + [Julien Castets]
+  + Support comments in content read by load_shell_content.
+  + cloudinitlocal fail to run during boot [Hongjiang Zhang]
+  + doc: fix disk setup example table_type options
+  + [Sandor Zeestraten] (LP: #1703789)
+  + tools: Fix exception handling. [Joonas Kylmälä] (LP: #1701527)
+  + tests: fix usage of mock in GCE test.
+  + test_gce: Fix invalid mock of platform_reports_gce to return False
+  + [Chad Smith]
+  + test: fix incorrect keyid for apt repository.
+  + [Joshua Powers] (LP: #1702717)
+  + tests: Update version of pylxd [Joshua Powers]
+  + write_files: Remove log from helper function signatures.
+  + [Andrew Jorgensen]
+  + doc: document the cmdline options to NoCloud [Brian Candler]
+  + read_dmi_data: always return None when inside a container. (LP: #1701325)
+  + requirements.txt: remove trailing white space.
+  + Azure: Add network-config, Refactor net layer to handle duplicate macs.
+  + [Ryan Harper]
+  + Tests: Simplify the check on ssh-import-id [Joshua Powers]
+  + tests: update ntp tests after sntp added [Joshua Powers]
+  + FreeBSD: Make freebsd a variant, fix unittests and
+  + tools/build-on-freebsd.
+  + FreeBSD: fix test failure
+  + FreeBSD: replace ifdown/ifup with "ifconfig down" and "ifconfig up".
+  + [Hongjiang Zhang] (LP: #1697815)
+  + FreeBSD: fix cdrom mounting failure if /mnt/cdrom/secure did not exist.
+  + [Hongjiang Zhang] (LP: #1696295)
+  + main: Don't use templater to format the welcome message
+  + [Andrew Jorgensen]
+  + docs: Automatically generate module docs form schema if present.
+  + [Chad Smith]
+  + debian: fix path comment in /etc/hosts template.
++++ 361 more lines (skipped)
++++ between /work/SRC/openSUSE:Factory/cloud-init/cloud-init.changes
++++ and /work/SRC/openSUSE:Factory/.cloud-init.new/cloud-init.changes

Old:
----
  addopenSUSEBase.patch
  cloud-init-0.7.8.tar.gz
  cloud-init-digital-ocean-datasource-enable-by-default.patch
  cloud-init-digital-ocean-datasource.patch
  cloud-init-finalbeforelogin.patch
  cloud-init-fix-unicode-handling-binarydecode.patch
  cloud-init-handle-no-carrier.patch
  cloud-init-handle-not-implemented-query.patch
  cloud-init-net-eni.patch
  cloud-init-net-sysconfig-lp1665441.patch
  cloud-init-no-dmidecode-on-ppc64.patch
  cloud-init-python26.patch
  cloud-init-service.patch
  cloud-init-spceandtabs-clean.patch
  cloud.cfg.suse
  dataSourceOpenNebula.patch
  dynamicInitCmd.diff
  openSUSEhostsTemplate.diff
  setupSUSEsysVInit.diff
  skip-argparse-on-python3.patch
  suseIntegratedHandler.patch
  suseSysVInit.diff

New:
----
  cloud-init-17.1.tar.gz
  cloud-init-final-no-apt.patch
  cloud-init-more-tasks.patch
  cloud-init-tests-set-exec.patch
  zypp_add_repo_test.patch

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ cloud-init.spec ++++++
--- /var/tmp/diff_new_pack.jeiljh/_old  2017-11-03 16:29:19.098453326 +0100
+++ /var/tmp/diff_new_pack.jeiljh/_new  2017-11-03 16:29:19.102453181 +0100
@@ -18,73 +18,60 @@
 %global configver 0.7
 
 Name:           cloud-init
-Version:        0.7.8
+Version:        17.1
 Release:        0
 License:        GPL-3.0 and AGPL-3.0
 Summary:        Cloud node initialization tool
 Url:            http://launchpad.net/cloud-init/
 Group:          System/Management
 Source0:        %{name}-%{version}.tar.gz
-Source1:        cloud.cfg.suse
-Source2:        rsyslog-cloud-init.cfg
-Patch0:         suseSysVInit.diff
-# FIXME addopenSUSEBase.patch proposed for upstream merge
-Patch1:         addopenSUSEBase.patch
-# FIXME suseIntegratedHandler.patch proposed for upstream merge
-Patch2:         suseIntegratedHandler.patch
-Patch3:         setupSUSEsysVInit.diff
-# FIXME openSUSEhostsTemplate.diff proposed for upstream merge
-Patch5:         openSUSEhostsTemplate.diff
-# FIXME dynamicInitCmd.patch proposed for upstream merge
-Patch6:         dynamicInitCmd.diff
-Patch9:         cloud-init-no-dmidecode-on-ppc64.patch
+Source1:        rsyslog-cloud-init.cfg
+# FIXME zypp_add_repos.diff needs proposed for upstream merge
+Patch4:         zypp_add_repos.diff
+Patch5:         zypp_add_repo_test.patch
 Patch10:        cloud-init-no-user-lock-if-already-locked.patch
-Patch11:        dataSourceOpenNebula.patch
 Patch12:        fix-default-systemd-unit-dir.patch
-Patch14:        cloud-init-finalbeforelogin.patch
+# FIXME cloud-init-more-tasks.patch proposed for upstream merge
+Patch13:        cloud-init-more-tasks.patch
 # python2 disables SIGPIPE, causing broken pipe errors in shell scripts 
(bsc#903449)
 Patch20:        cloud-init-python2-sigpipe.patch
-Patch21:        cloud-init-net-eni.patch
-Patch22:        cloud-init-service.patch
-Patch23:        cloud-init-fix-unicode-handling-binarydecode.patch
-# From upstream patch
-Patch24:        cloud-init-handle-no-carrier.patch
-Patch25:        cloud-init-digital-ocean-datasource.patch
-Patch26:        cloud-init-digital-ocean-datasource-enable-by-default.patch
 Patch27:        cloud-init-sysconfig-netpathfix.patch
-Patch28:        zypp_add_repos.diff
 Patch29:        datasourceLocalDisk.patch
-Patch30:        cloud-init-handle-not-implemented-query.patch
-Patch32:        cloud-init-net-sysconfig-lp1665441.patch
-Patch33:        cloud-init-spceandtabs-clean.patch
-Patch34:        skip-argparse-on-python3.patch
+Patch34:        cloud-init-tests-set-exec.patch
+Patch35:        cloud-init-final-no-apt.patch
 BuildRequires:  fdupes
 BuildRequires:  filesystem
-%if 0%{?suse_version} && 0%{?suse_version} > 1315
-BuildRequires:  python3-devel
-BuildRequires:  python3-setuptools
-%else
-BuildRequires:  python-devel
-BuildRequires:  python-setuptools
-%endif
 # pkg-config is needed to find correct systemd unit dir
 BuildRequires:  pkg-config
 # needed for /lib/udev
 BuildRequires:  udev
 %if 0%{?suse_version} > 1320
+BuildRequires:  python3-devel
+BuildRequires:  python3-setuptools
 # Test requirements
-#BuildRequires:  python3-Cheetah
 BuildRequires:  python3-Jinja2
 BuildRequires:  python3-PrettyTable
 BuildRequires:  python3-PyYAML
-BuildRequires:  python3-configobj
-#BuildRequires:  python3-contextlib2
+BuildRequires:  python3-configobj >= 5.0.2
 BuildRequires:  python3-httpretty
 BuildRequires:  python3-jsonpatch
 BuildRequires:  python3-mock
+BuildRequires:  python3-nose
 BuildRequires:  python3-oauthlib
 BuildRequires:  python3-requests
 BuildRequires:  python3-testtools
+%else
+BuildRequires:  python-devel
+BuildRequires:  python-Jinja2
+BuildRequires:  python-PyYAML
+BuildRequires:  python-requests
+BuildRequires:  python-setuptools
+BuildRequires:  python-six
+%endif
+%if 0%{?is_opensuse} || 0%{?suse_version} == 1310 || 0%{?suse_version} == 1320
+BuildRequires:  openSUSE-release
+%else
+BuildRequires:  sles-release
 %endif
 Requires:       bash
 Requires:       file
@@ -97,9 +84,10 @@
 Requires:       openssh
 %if 0%{?suse_version} > 1320
 Requires:       python3-boto >= 2.7
-Requires:       python3-configobj
+Requires:       python3-configobj >= 5.0.2
 Requires:       python3-Jinja2
 Requires:       python3-jsonpatch
+Requires:       python3-jsonschema
 Requires:       python3-oauthlib
 Requires:       python3-PrettyTable
 Requires:       python3-pyserial
@@ -111,9 +99,10 @@
 %else
 Requires:       python-argparse
 Requires:       python-boto >= 2.7
-Requires:       python-configobj
+Requires:       python-configobj >= 5.0.2
 Requires:       python-Jinja2
 Requires:       python-jsonpatch
+Requires:       python-jsonschema
 Requires:       python-oauthlib
 Requires:       python-PrettyTable
 Requires:       python-pyserial
@@ -140,7 +129,6 @@
 %endif
 %if 0%{?suse_version} && 0%{?suse_version} <= 1210
 %define initsys sysvinit_suse
-Patch40:        cloud-init-python26.patch
 %else
 %define initsys systemd
 BuildRequires: systemd
@@ -187,52 +175,30 @@
 
 Documentation and examples for cloud-init tools
 
-%package test
-Summary:        Cloud node initialization tool  - Testsuite
-Group:          System/Management
-Requires:       cloud-init = %{version}
-
-%description test
-Cloud-init is an init script that initializes a cloud node (VM)
-according to the fetched configuration data from the admin node.
-
-Unit tests for the cloud-init tools
+#%package test
+#Summary:        Cloud node initialization tool  - Testsuite
+#Group:          System/Management
+#Requires:       cloud-init = %{version}
+#
+#%description test
+#Cloud-init is an init script that initializes a cloud node (VM)
+#according to the fetched configuration data from the admin node.
+#
+#Unit tests for the cloud-init tools
 
 %prep
 %setup -q
-%patch0 -p1
-%patch1 -p1
-%patch2
-%patch3
-%patch5
-%patch6
-%patch9
+%patch4  -p0
+%patch5  -p0
 %patch10 -p1
-%patch11
 %patch12
-%patch14
+%patch13
 %patch20
-%patch21
-%patch22
-%patch23
-%patch24
-%patch25 -p1
-%patch26 -p1
 %patch27
-%patch28 -p0
 %patch29 -p0
-%patch30
-%patch32 -p1
-%patch33 -p1
 %patch34
-%if 0%{?suse_version} && 0%{?suse_version} <= 1210
-%patch40 -p1
-%endif
+%patch35 -p1
 
-%if 0%{?suse_version} <= 1130
-# disable ecdsa for SLE 11 (not available)
-echo "ssh_genkeytypes: ['rsa', 'dsa']" >> %{SOURCE1}
-%endif
 
 %build
 %if 0%{?suse_version} && 0%{?suse_version} <= 1315
@@ -247,16 +213,11 @@
 # these tests are currently failing due to suse patches
 rm -v tests/unittests/test_distros/test_netconfig.py
 rm -v tests/unittests/test_net.py
+# Ignore test failure currently not doing anything with opennebula
 rm -v tests/unittests/test_datasource/test_opennebula.py
-rm -v tests/unittests/test_datasource/test_cloudstack.py
-# These tests fail in python 3
-rm -v tests/unittests/test_datasource/test_altcloud.py
-rm -v tests/unittests/test_handler/test_handler_apt_source_v3.py
-%if 0%{?suse_version} && 0%{?suse_version} <= 1315
-python -m testtools.run
-%else
-python3 -m testtools.run
-%endif
+# To be investigated
+rm -v tests/unittests/test_handler/test_handler_ntp.py
+make test
 %endif
 
 
@@ -275,28 +236,30 @@
 # move documentation
 mkdir -p %{buildroot}%{_defaultdocdir}
 mv %{buildroot}%{_datadir}/doc/%{name} %{buildroot}%{docdir}
-cp -a %{SOURCE1} %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg
+%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/INSERT_SUSE_DISTRO/sles/ %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg
+sed -i s/suse/sles/ %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg
 %endif
 %if 0%{?suse_version} > 1140
-%if 0%{?suse_version} == 1315
-# SLE 12
-sed -i s/INSERT_SUSE_DISTRO/sles/ %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg
+%if 0%{?is_opensuse}
+sed -i s/suse/opensuse/ %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg
 %else
-sed -i s/INSERT_SUSE_DISTRO/opensuse/ 
%{buildroot}/%{_sysconfdir}/cloud/cloud.cfg
+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 %{SOURCE2} %{buildroot}/%{_sysconfdir}/rsyslog.d/21-cloudinit.conf
+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
 
@@ -396,15 +359,11 @@
 %{docdir}/examples/*
 %{docdir}/README
 %{docdir}/*.txt
-%{docdir}/*.rst
+#%{docdir}/*.rst
 %dir %{docdir}/examples
 
-%files test
-%defattr(-,root,root)
-%if 0%{?suse_version} && 0%{?suse_version} <= 1315
-%{python_sitelib}/tests
-%else
-%{python3_sitelib}/tests
-%endif
+#%files test
+#%defattr(-,root,root)
+#%{python_sitelib}/tests
 
 %changelog

++++++ cloud-init-0.7.8.tar.gz -> cloud-init-17.1.tar.gz ++++++
++++ 59611 lines of diff (skipped)

++++++ cloud-init-final-no-apt.patch ++++++
Index: cloud-init-17.1/systemd/cloud-final.service.tmpl
===================================================================
--- cloud-init-17.1.orig/systemd/cloud-final.service.tmpl
+++ cloud-init-17.1/systemd/cloud-final.service.tmpl
@@ -4,9 +4,9 @@ Description=Execute cloud user/final scr
 After=network-online.target cloud-config.service rc-local.service
 {% if variant in ["ubuntu", "unknown", "debian"] %}
 After=multi-user.target
+Before=apt-daily.service
 {% endif %}
 Wants=network-online.target cloud-config.service
-Before=apt-daily.service
 
 [Service]
 Type=oneshot
++++++ cloud-init-more-tasks.patch ++++++
--- systemd/cloud-final.service.tmpl.orig
+++ systemd/cloud-final.service.tmpl
@@ -14,6 +14,7 @@ ExecStart=/usr/bin/cloud-init modules --
 RemainAfterExit=yes
 TimeoutSec=0
 KillMode=process
+TasksMax=infinity
 
 # Output needs to appear in instance console output
 StandardOutput=journal+console
++++++ cloud-init-python2-sigpipe.patch ++++++
--- /var/tmp/diff_new_pack.jeiljh/_old  2017-11-03 16:29:19.430441243 +0100
+++ /var/tmp/diff_new_pack.jeiljh/_new  2017-11-03 16:29:19.430441243 +0100
@@ -1,20 +1,20 @@
 --- cloudinit/util.py.orig
 +++ cloudinit/util.py
-@@ -46,6 +46,7 @@ import tempfile
- import time
+@@ -35,6 +35,7 @@ import time
+ from errno import ENOENT, ENOEXEC
  
  from base64 import b64decode, b64encode
 +from signal import signal, SIGPIPE, SIG_DFL
  from six.moves.urllib import parse as urlparse
  
  import six
-@@ -1802,7 +1803,8 @@ def subp(args, data=None, rcs=None, env=
+@@ -1815,7 +1816,8 @@ def subp(args, data=None, rcs=None, env=
  
          sp = subprocess.Popen(args, stdout=stdout,
                                stderr=stderr, stdin=stdin,
 -                              env=env, shell=shell)
 +                              env=env, shell=shell,
-+                            preexec_fn=lambda: signal(SIGPIPE, SIG_DFL))
++                              preexec_fn=lambda: signal(SIGPIPE, SIG_DFL))
          (out, err) = sp.communicate(data)
  
          # Just ensure blank instead of none.

++++++ cloud-init-sysconfig-netpathfix.patch ++++++
--- /var/tmp/diff_new_pack.jeiljh/_old  2017-11-03 16:29:19.442440806 +0100
+++ /var/tmp/diff_new_pack.jeiljh/_new  2017-11-03 16:29:19.442440806 +0100
@@ -1,15 +1,17 @@
 --- cloudinit/net/sysconfig.py.orig
 +++ cloudinit/net/sysconfig.py
-@@ -94,7 +94,7 @@ class ConfigMap(object):
+@@ -88,8 +88,8 @@ class ConfigMap(object):
  class Route(ConfigMap):
      """Represents a route configuration."""
  
--    route_fn_tpl = '%(base)s/network-scripts/route-%(name)s'
-+    route_fn_tpl = '%(base)s/network/route-%(name)s'
+-    route_fn_tpl_ipv4 = '%(base)s/network-scripts/route-%(name)s'
+-    route_fn_tpl_ipv6 = '%(base)s/network-scripts/route6-%(name)s'
++    route_fn_tpl_ipv4 = '%(base)s/network/route-%(name)s'
++    route_fn_tpl_ipv6 = '%(base)s/network/route6-%(name)s'
  
      def __init__(self, route_name, base_sysconf_dir):
          super(Route, self).__init__()
-@@ -119,7 +119,7 @@ class Route(ConfigMap):
+@@ -166,7 +166,7 @@ class Route(ConfigMap):
  class NetInterface(ConfigMap):
      """Represents a sysconfig/networking-script (and its config + 
children)."""
  
@@ -18,3 +20,14 @@
  
      iface_types = {
          'ethernet': 'Ethernet',
+@@ -602,8 +602,8 @@ def available(target=None):
+             return False
+ 
+     expected_paths = [
+-        'etc/sysconfig/network-scripts/network-functions',
+-        'etc/sysconfig/network-scripts/ifdown-eth']
++        'etc/sysconfig/network/network-functions',
++        'etc/sysconfig/network/ifdown-eth']
+     for p in expected_paths:
+         if not os.path.isfile(util.target_path(target, p)):
+             return False

++++++ cloud-init-tests-set-exec.patch ++++++
--- Makefile.orig
+++ Makefile
@@ -11,7 +11,7 @@ PIP_INSTALL := pip install
 
 ifeq ($(PYVER),python3)
   pyflakes = pyflakes3
-  unittests = unittest3
+  unittests = unittest
   yaml = yaml
 else
 ifeq ($(PYVER),python2)
@@ -19,7 +19,7 @@ ifeq ($(PYVER),python2)
   unittests = unittest
 else
   pyflakes = pyflakes pyflakes3
-  unittests = unittest unittest3
+  unittests = unittest unittest
 endif
 endif
 
++++++ fix-default-systemd-unit-dir.patch ++++++
--- /var/tmp/diff_new_pack.jeiljh/_old  2017-11-03 16:29:19.466439932 +0100
+++ /var/tmp/diff_new_pack.jeiljh/_new  2017-11-03 16:29:19.466439932 +0100
@@ -1,6 +1,6 @@
 --- setup.py.orig
 +++ setup.py
-@@ -58,8 +58,8 @@ def tiny_p(cmd, capture=True):
+@@ -49,8 +49,8 @@ def tiny_p(cmd, capture=True):
  def pkg_config_read(library, var):
      fallbacks = {
          'systemd': {
@@ -13,9 +13,9 @@
      cmd = ['pkg-config', '--variable=%s' % var, library]
 --- systemd/cloud-init-generator.orig
 +++ systemd/cloud-init-generator
-@@ -7,7 +7,7 @@ LOG_D="/run/cloud-init"
- ENABLE="enabled"
- DISABLE="disabled"
+@@ -9,7 +9,7 @@ DISABLE="disabled"
+ FOUND="found"
+ NOTFOUND="notfound"
  RUN_ENABLED_FILE="$LOG_D/$ENABLE"
 -CLOUD_SYSTEM_TARGET="/lib/systemd/system/cloud-init.target"
 +CLOUD_SYSTEM_TARGET="/usr/lib/systemd/system/cloud-init.target"

++++++ zypp_add_repo_test.patch ++++++
Index: tests/unittests/test_handler/test_handler_zypper_add_repo.py
===================================================================
--- /dev/null
+++ tests/unittests/test_handler/test_handler_zypper_add_repo.py
@@ -0,0 +1,238 @@
+
+# This file is part of cloud-init. See LICENSE file for license information.
+
+import glob
+import os
+
+from cloudinit.config import cc_zypper_add_repo
+from cloudinit import util
+
+from cloudinit.tests import helpers
+from cloudinit.tests.helpers import mock
+
+try:
+    from configparser import ConfigParser
+except ImportError:
+    from ConfigParser import ConfigParser
+import logging
+from six import StringIO
+
+LOG = logging.getLogger(__name__)
+
+
+class TestConfig(helpers.FilesystemMockingTestCase):
+    def setUp(self):
+        super(TestConfig, self).setUp()
+        self.tmp = self.tmp_dir()
+        self.zypp_conf = 'etc/zypp/zypp.conf'
+
+    def test_bad_repo_config(self):
+        """Config has no baseurl, no file should be written"""
+        cfg = {
+            'repos': [
+                {
+                    'id': 'foo',
+                    'name': 'suse-test',
+                    'enabled': '1'
+                },
+            ]
+        }
+        self.patchUtils(self.tmp)
+        cc_zypper_add_repo._write_repos(cfg['repos'], '/etc/zypp/repos.d')
+        self.assertRaises(IOError, util.load_file,
+                          "/etc/zypp/repos.d/foo.repo")
+
+    def test_write_repos(self):
+        """Verify valid repos get written"""
+        cfg = self._get_base_config_repos()
+        root_d = self.tmp_dir()
+        cc_zypper_add_repo._write_repos(cfg['zypper']['repos'], root_d)
+        repos = glob.glob('%s/*.repo' % root_d)
+        expected_repos = ['testing-foo.repo', 'testing-bar.repo']
+        if len(repos) != 2:
+            assert 'Number of repos written is "%d" expected 2' % len(repos)
+        for repo in repos:
+            repo_name = os.path.basename(repo)
+            if repo_name not in expected_repos:
+                assert 'Found repo with name "%s"; unexpected' % repo_name
+        # Validation that the content gets properly written is in another test
+
+    def test_write_repo(self):
+        """Verify the content of a repo file"""
+        cfg = {
+            'repos': [
+                {
+                    'baseurl': 'http://foo',
+                    'name': 'test-foo',
+                    'id': 'testing-foo'
+                },
+            ]
+        }
+        root_d = self.tmp_dir()
+        cc_zypper_add_repo._write_repos(cfg['repos'], root_d)
+        contents = util.load_file("%s/testing-foo.repo" % root_d)
+        parser = ConfigParser()
+        parser.readfp(StringIO(contents))
+        expected = {
+            'testing-foo': {
+                'name': 'test-foo',
+                'baseurl': 'http://foo',
+                'enabled': '1',
+                'autorefresh': '1'
+            }
+        }
+        for section in expected:
+            self.assertTrue(parser.has_section(section),
+                            "Contains section {0}".format(section))
+            for k, v in expected[section].items():
+                self.assertEqual(parser.get(section, k), v)
+
+    def test_config_write(self):
+        """Write valid configuration data"""
+        cfg = {
+            'config': {
+                'download.deltarpm': 'False',
+                'reposdir': 'foo'
+            }
+        }
+        root_d = self.tmp_dir()
+        helpers.populate_dir(root_d, {self.zypp_conf: '# Zypp config\n'})
+        self.reRoot(root_d)
+        cc_zypper_add_repo._write_zypp_config(cfg['config'])
+        cfg_out = os.path.join(root_d, self.zypp_conf)
+        contents = util.load_file(cfg_out)
+        expected = [
+            '# Zypp config',
+            '# Added via cloud.cfg',
+            'download.deltarpm=False',
+            'reposdir=foo'
+        ]
+        for item in contents.split('\n'):
+            if item not in expected:
+                self.assertIsNone(item)
+
+    @mock.patch('cloudinit.log.logging')
+    def test_config_write_skip_configdir(self, mock_logging):
+        """Write configuration but skip writing 'configdir' setting"""
+        cfg = {
+            'config': {
+                'download.deltarpm': 'False',
+                'reposdir': 'foo',
+                'configdir': 'bar'
+            }
+        }
+        root_d = self.tmp_dir()
+        helpers.populate_dir(root_d, {self.zypp_conf: '# Zypp config\n'})
+        self.reRoot(root_d)
+        cc_zypper_add_repo._write_zypp_config(cfg['config'])
+        cfg_out = os.path.join(root_d, self.zypp_conf)
+        contents = util.load_file(cfg_out)
+        expected = [
+            '# Zypp config',
+            '# Added via cloud.cfg',
+            'download.deltarpm=False',
+            'reposdir=foo'
+        ]
+        for item in contents.split('\n'):
+            if item not in expected:
+                self.assertIsNone(item)
+        # Not finding teh right path for mocking :(
+        # assert mock_logging.warning.called
+
+    def test_empty_config_section_no_new_data(self):
+        """When the config section is empty no new data should be written to
+           zypp.conf"""
+        cfg = self._get_base_config_repos()
+        cfg['zypper']['config'] = None
+        root_d = self.tmp_dir()
+        helpers.populate_dir(root_d, {self.zypp_conf: '# No data'})
+        self.reRoot(root_d)
+        cc_zypper_add_repo._write_zypp_config(cfg.get('config', {}))
+        cfg_out = os.path.join(root_d, self.zypp_conf)
+        contents = util.load_file(cfg_out)
+        self.assertEqual(contents, '# No data')
+
+    def test_empty_config_value_no_new_data(self):
+        """When the config section is not empty but there are no values
+           no new data should be written to zypp.conf"""
+        cfg = self._get_base_config_repos()
+        cfg['zypper']['config'] = {
+            'download.deltarpm': None
+        }
+        root_d = self.tmp_dir()
+        helpers.populate_dir(root_d, {self.zypp_conf: '# No data'})
+        self.reRoot(root_d)
+        cc_zypper_add_repo._write_zypp_config(cfg.get('config', {}))
+        cfg_out = os.path.join(root_d, self.zypp_conf)
+        contents = util.load_file(cfg_out)
+        self.assertEqual(contents, '# No data')
+
+    def test_handler_full_setup(self):
+        """Test that the handler ends up calling the renderers"""
+        cfg = self._get_base_config_repos()
+        cfg['zypper']['config'] = {
+            'download.deltarpm': 'False',
+        }
+        root_d = self.tmp_dir()
+        os.makedirs('%s/etc/zypp/repos.d' % root_d)
+        helpers.populate_dir(root_d, {self.zypp_conf: '# Zypp config\n'})
+        self.reRoot(root_d)
+        cc_zypper_add_repo.handle('zypper_add_repo', cfg, None, LOG, [])
+        cfg_out = os.path.join(root_d, self.zypp_conf)
+        contents = util.load_file(cfg_out)
+        expected = [
+            '# Zypp config',
+            '# Added via cloud.cfg',
+            'download.deltarpm=False',
+        ]
+        for item in contents.split('\n'):
+            if item not in expected:
+                self.assertIsNone(item)
+        repos = glob.glob('%s/etc/zypp/repos.d/*.repo' % root_d)
+        expected_repos = ['testing-foo.repo', 'testing-bar.repo']
+        if len(repos) != 2:
+            assert 'Number of repos written is "%d" expected 2' % len(repos)
+        for repo in repos:
+            repo_name = os.path.basename(repo)
+            if repo_name not in expected_repos:
+                assert 'Found repo with name "%s"; unexpected' % repo_name
+
+    def test_no_config_section_no_new_data(self):
+        """When there is no config section no new data should be written to
+           zypp.conf"""
+        cfg = self._get_base_config_repos()
+        root_d = self.tmp_dir()
+        helpers.populate_dir(root_d, {self.zypp_conf: '# No data'})
+        self.reRoot(root_d)
+        cc_zypper_add_repo._write_zypp_config(cfg.get('config', {}))
+        cfg_out = os.path.join(root_d, self.zypp_conf)
+        contents = util.load_file(cfg_out)
+        self.assertEqual(contents, '# No data')
+
+    def test_no_repo_data(self):
+        """When there is no repo data nothing should happen"""
+        root_d = self.tmp_dir()
+        self.reRoot(root_d)
+        cc_zypper_add_repo._write_repos(None, root_d)
+        content = glob.glob('%s/*' % root_d)
+        self.assertEqual(len(content), 0)
+
+    def _get_base_config_repos(self):
+        """Basic valid repo configuration"""
+        cfg = {
+            'zypper': {
+                'repos': [
+                    {
+                        'baseurl': 'http://foo',
+                        'name': 'test-foo',
+                        'id': 'testing-foo'
+                    },
+                    {
+                        'baseurl': 'http://bar',
+                        'name': 'test-bar',
+                        'id': 'testing-bar'
+                    }
+                ]
+            }
+        }
+        return cfg
Index: tests/unittests/test_handler/test_schema.py
===================================================================
--- tests/unittests/test_handler/test_schema.py
+++ tests/unittests/test_handler/test_schema.py
@@ -27,7 +27,13 @@ class GetSchemaTest(CiTestCase):
         """Every cloudconfig module with schema is listed in allOf keyword."""
         schema = get_schema()
         self.assertItemsEqual(
-            ['cc_bootcmd', 'cc_ntp', 'cc_resizefs', 'cc_runcmd'],
+            [
+                'cc_bootcmd',
+                'cc_ntp',
+                'cc_resizefs',
+                'cc_runcmd',
+                'cc_zypper_add_repo'
+                ],
             [subschema['id'] for subschema in schema['allOf']])
         self.assertEqual('cloud-config-schema', schema['id'])
         self.assertEqual(
++++++ zypp_add_repos.diff ++++++
--- /var/tmp/diff_new_pack.jeiljh/_old  2017-11-03 16:29:19.498438767 +0100
+++ /var/tmp/diff_new_pack.jeiljh/_new  2017-11-03 16:29:19.498438767 +0100
@@ -1,39 +1,110 @@
---- cloudinit/config/cc_zypp_add_repo.py
-+++ cloudinit/config/cc_zypp_add_repo.py       2016/11/23 13:10:49
-@@ -0,0 +1,112 @@
-+# vi: ts=4 expandtab
-+#
-+#    Copyright (C) 2016 SUSE LLC.
-+#    This file is based on cc_yum_add_repo.py and was rewritten by
-+#    Thorsten Kukuk <[email protected]> for zypp repos.
-+#
-+#    Original file was:
-+#
-+#    Copyright (C) 2012 Yahoo! Inc.
-+#
-+#    Author: Joshua Harlow <[email protected]>
+Index: cloudinit/config/cc_zypp_add_repo.py
+===================================================================
+--- /dev/null
++++ cloudinit/config/cc_zypper_add_repo.py
+@@ -0,0 +1,220 @@
 +#
-+#    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.
++#    Copyright (C) 2017 SUSE LLC.
 +#
-+#    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 file is part of cloud-init. See LICENSE file for license information.
++
++"""zypper_add_repo: Add zyper repositories to the system"""
 +
-+import os
 +
 +import configobj
-+import six
++import os
 +
++
++from cloudinit import log as logging
 +from cloudinit import util
++from cloudinit.config.schema import get_schema_doc
++from cloudinit.settings import PER_ALWAYS
++from six import string_types
++from textwrap import dedent
 +
 +distros = ['opensuse', 'sles']
 +
++schema = {
++    'id': 'cc_zypper_add_repo',
++    'name': 'ZypperAddRepo',
++    'title': 'Configure zypper behavior and add zypper repositories',
++    'description': dedent("""\
++        Configure zypper behavior by modifying /etc/zypp/zypp.conf. The
++        configuration writer is "dumb" and will simply append the provided
++        configuration options to the configuration file. Option settings
++        that may be duplicate will be resolved by the way the zypp.conf file
++        is parsed. The file is in INI format.
++        Add repositories to the system. No validation is performed on the
++        repository file entries, it is assumed the user is familiar with
++        the zypper repository file format."""),
++    'distros': distros,
++    'examples': [dedent("""\
++        zypper:
++          repos:
++            - id: opensuse-oss
++              name: os-oss
++              baseurl: http://dl.opensuse.org/dist/leap/v/repo/oss/
++              enabled: 1
++              autorefresh: 1
++            - id: opensuse-oss-update
++              name: os-oss-up
++              baseurl: http://dl.opensuse.org/dist/leap/v/update
++              # any setting per
++              # https://en.opensuse.org/openSUSE:Standards_RepoInfo
++              # enable and autorefresh are on by default
++          config:
++            reposdir: /etc/zypp/repos.dir
++            servicesdir: /etc/zypp/services.d
++            download.use_deltarpm: true
++            # any setting in /etc/zypp/zypp.conf
++    """)],
++    'frequency': PER_ALWAYS,
++    'type': 'object',
++    'properties': {
++        'zypper': {
++            'type': 'object',
++            'properties': {
++                'repos': {
++                    'type': 'array',
++                    'items': {
++                        'type': 'object',
++                        'properties': {
++                            'id': {
++                                'type': 'string',
++                                'description': dedent("""\
++                                    The unique id of the repo, used when
++                                     writing
++                                    /etc/zypp/repos.d/<id>.repo.""")
++                            },
++                            'baseurl': {
++                                'type': 'string',
++                                'format': 'uri',   # built-in format type
++                                'description': 'The base repositoy URL'
++                            }
++                        },
++                        'required': ['id', 'baseurl'],
++                        'additionalProperties': True
++                    },
++                    'minItems': 1
++                },
++                'config': {
++                    'type': 'object',
++                    'description': dedent("""\
++                        Any supported zypo.conf key is written to
++                        /etc/zypp/zypp.conf'""")
++                }
++            },
++            'required': [],
++            'minProperties': 1,  # Either config or repo must be provided
++            'additionalProperties': False,  # only repos and config allowed
++        }
++    }
++}
++
++__doc__ = get_schema_doc(schema)  # Supplement python help()
++
++LOG = logging.getLogger(__name__)
++
 +
 +def _canonicalize_id(repo_id):
 +    repo_id = repo_id.replace(" ", "_")
@@ -41,12 +112,12 @@
 +
 +
 +def _format_repo_value(val):
-+    if isinstance(val, (bool)):
++    if isinstance(val, bool):
 +        # zypp prefers 1/0
-+        return str(int(val))
++        return 1 if val else 0
 +    if isinstance(val, (list, tuple)):
 +        return "\n    ".join([_format_repo_value(v) for v in val])
-+    if not isinstance(val, six.string_types):
++    if not isinstance(val, string_types):
 +        return str(val)
 +    return val
 +
@@ -63,58 +134,99 @@
 +    return "\n".join(lines)
 +
 +
-+def handle(name, cfg, _cloud, log, _args):
-+    repos = cfg.get('zypp_repos')
++def _write_repos(repos, repo_base_path):
++    """Write the user-provided repo definition files
++    @param repos: A list of repo dictionary objects provided by the user's
++        cloud config.
++    @param repo_base_path: The directory path to which repo definitions are
++        written.
++    """
++
 +    if not repos:
-+        log.debug(("Skipping module named %s,"
-+                   " no 'zypp_repos' configuration found"), name)
 +        return
-+    repo_base_path = util.get_cfg_option_str(cfg, 'zypp_repo_dir',
-+                                             '/etc/zypp/repos.d/')
-+    repo_locations = {}
-+    repo_configs = {}
-+    for (repo_id, repo_config) in repos.items():
++    valid_repos = {}
++    for index, user_repo_config in enumerate(repos):
++        # Skip on absent required keys
++        missing_keys = set(['id', 
'baseurl']).difference(set(user_repo_config))
++        if missing_keys:
++            LOG.warning(
++                "Repo config at index %d is missing required config keys: %s",
++                index, ",".join(missing_keys))
++            continue
++        repo_id = user_repo_config.get('id')
 +        canon_repo_id = _canonicalize_id(repo_id)
 +        repo_fn_pth = os.path.join(repo_base_path, "%s.repo" % 
(canon_repo_id))
 +        if os.path.exists(repo_fn_pth):
-+            log.info("Skipping repo %s, file %s already exists!",
++            LOG.info("Skipping repo %s, file %s already exists!",
 +                     repo_id, repo_fn_pth)
 +            continue
-+        elif repo_id in repo_locations:
-+            log.info("Skipping repo %s, file %s already pending!",
++        elif repo_id in valid_repos:
++            LOG.info("Skipping repo %s, file %s already pending!",
 +                     repo_id, repo_fn_pth)
 +            continue
-+        if not repo_config:
-+            repo_config = {}
-+        # Do some basic sanity checks/cleaning
-+        n_repo_config = {}
-+        for (k, v) in repo_config.items():
-+            k = k.lower().strip().replace("-", "_")
-+            if k:
-+                n_repo_config[k] = v
-+        repo_config = n_repo_config
-+        missing_required = 0
-+        for req_field in ['baseurl']:
-+            if req_field not in repo_config:
-+                log.warn(("Repository %s does not contain a %s"
-+                          " configuration 'required' entry"),
-+                         repo_id, req_field)
-+                missing_required += 1
++
++        # Do some basic key formatting
++        repo_config = dict(
++            (k.lower().strip().replace("-", "_"), v)
++            for k, v in user_repo_config.items()
++            if k and k != 'id')
++
++        # Set defaults if not present
 +        for field in ['enabled', 'autorefresh']:
 +            if field not in repo_config:
 +                repo_config[field] = '1'
-+        if not missing_required:
-+            repo_configs[repo_id] = repo_config
-+            repo_locations[repo_id] = repo_fn_pth
-+        else:
-+            log.warn("Repository %s is missing %s required fields, skipping!",
-+                     repo_id, missing_required)
-+    for (c_repo_id, path) in repo_locations.items():
-+        repo_blob = _format_repository_config(c_repo_id,
-+                                              repo_configs.get(c_repo_id))
-+        util.write_file(path, repo_blob)
---- doc/examples/cloud-config-zypp-repo.txt
-+++ doc/examples/cloud-config-zypp-repo.txt    2016/11/23 12:59:42
++
++        valid_repos[repo_id] = (repo_fn_pth, repo_config)
++
++    for (repo_id, repo_data) in valid_repos.items():
++        repo_blob = _format_repository_config(repo_id, repo_data[-1])
++        util.write_file(repo_data[0], repo_blob)
++
++
++def _write_zypp_config(zypper_config):
++    """Write to the default zypp configuration file /etc/zypp/zypp.conf"""
++    if not zypper_config:
++        return
++    zypp_config = '/etc/zypp/zypp.conf'
++    zypp_conf_content = util.load_file(zypp_config)
++    new_settings = ['# Added via cloud.cfg']
++    for setting, value in zypper_config.items():
++        if setting == 'configdir':
++            msg = 'Changing the location of the zypper configuration is '
++            msg += 'not supported, skipping "configdir" setting'
++            LOG.warning(msg)
++            continue
++        if value:
++            new_settings.append('%s=%s' % (setting, value))
++    if len(new_settings) > 1:
++        new_config = zypp_conf_content + '\n'.join(new_settings)
++    else:
++        new_config = zypp_conf_content
++    util.write_file(zypp_config, new_config)
++
++
++def handle(name, cfg, _cloud, log, _args):
++    zypper_section = cfg.get('zypper')
++    if not zypper_section:
++        LOG.debug(("Skipping module named %s,"
++                   " no 'zypper' relevant configuration found"), name)
++        return
++    repos = zypper_section.get('repos')
++    if not repos:
++        LOG.debug(("Skipping module named %s,"
++                   " no 'repos' configuration found"), name)
++        return
++    zypper_config = zypper_section.get('config', {})
++    repo_base_path = zypper_config.get('reposdir', '/etc/zypp/repos.d/')
++
++    _write_zypp_config(zypper_config)
++    _write_repos(repos, repo_base_path)
++
++# vi: ts=4 expandtab
+Index: doc/examples/cloud-config-zypp-repo.txt
+===================================================================
+--- /dev/null
++++ doc/examples/cloud-config-zypp-repo.txt
 @@ -0,0 +1,18 @@
 +#cloud-config
 +# vim: syntax=yaml


Reply via email to