diff --git a/cloud-init-break-cycle-local-service.patch b/cloud-init-break-cycle-local-service.patch new file mode 100644 index 0000000..dc2c025 --- /dev/null +++ b/cloud-init-break-cycle-local-service.patch @@ -0,0 +1,15 @@ +--- systemd/cloud-init-local.service.tmpl.orig ++++ systemd/cloud-init-local.service.tmpl +@@ -13,12 +13,6 @@ Before=shutdown.target + Before=sysinit.target + Conflicts=shutdown.target + {% endif %} +-{% if variant in ["suse"] %} +-# Other distros use Before=sysinit.target. There is not a clearly identified +-# reason for usage of basic.target instead. +-Before=basic.target +-Conflicts=shutdown.target +-{% endif %} + RequiresMountsFor=/var/lib/cloud + + [Service] diff --git a/cloud-init-hosts-template.patch b/cloud-init-hosts-template.patch new file mode 100644 index 0000000..19ac198 --- /dev/null +++ b/cloud-init-hosts-template.patch @@ -0,0 +1,95 @@ +--- templates/hosts.suse.tmpl.orig ++++ templates/hosts.suse.tmpl +@@ -13,12 +13,18 @@ you need to add the following to config: + # /etc/cloud/cloud.cfg or cloud-config from user-data + # + # The following lines are desirable for IPv4 capable hosts +-127.0.0.1 localhost ++127.0.0.1 {{fqdn}} {{hostname}} ++127.0.0.1 localhost.localdomain localhost ++127.0.0.1 localhost4.localdomain4 localhost4 + + # The following lines are desirable for IPv6 capable hosts ++::1 {{fqdn}} {{hostname}} ++::1 localhost.localdomain localhost ++::1 localhost6.localdomain6 localhost6 + ::1 localhost ipv6-localhost ipv6-loopback +-fe00::0 ipv6-localnet + ++ ++fe00::0 ipv6-localnet + ff00::0 ipv6-mcastprefix + ff02::1 ipv6-allnodes + ff02::2 ipv6-allrouters +--- /dev/null ++++ tests/unittests/test_handler/test_handler_etc_hosts.py +@@ -0,0 +1,69 @@ ++# This file is part of cloud-init. See LICENSE file for license information. ++ ++from cloudinit.config import cc_update_etc_hosts ++ ++from cloudinit import cloud ++from cloudinit import distros ++from cloudinit import helpers ++from cloudinit import util ++ ++from cloudinit.tests import helpers as t_help ++ ++import logging ++import os ++import shutil ++ ++LOG = logging.getLogger(__name__) ++ ++ ++class TestHostsFile(t_help.FilesystemMockingTestCase): ++ def setUp(self): ++ super(TestHostsFile, self).setUp() ++ self.tmp = self.tmp_dir() ++ ++ def _fetch_distro(self, kind): ++ cls = distros.fetch(kind) ++ paths = helpers.Paths({}) ++ return cls(kind, {}, paths) ++ ++ def test_write_etc_hosts_suse_localhost(self): ++ cfg = { ++ 'manage_etc_hosts': 'localhost', ++ 'hostname': 'cloud-init.test.us' ++ } ++ os.makedirs('%s/etc/' % self.tmp) ++ hosts_content = '192.168.1.1 blah.blah.us blah\n' ++ fout = open('%s/etc/hosts' % self.tmp, 'w') ++ fout.write(hosts_content) ++ fout.close() ++ distro = self._fetch_distro('sles') ++ distro.hosts_fn = '%s/etc/hosts' % self.tmp ++ paths = helpers.Paths({}) ++ ds = None ++ cc = cloud.Cloud(ds, paths, {}, distro, None) ++ self.patchUtils(self.tmp) ++ cc_update_etc_hosts.handle('test', cfg, cc, LOG, []) ++ contents = util.load_file('%s/etc/hosts' % self.tmp) ++ if '127.0.0.1\tcloud-init.test.us\tcloud-init' not in contents: ++ self.assertIsNone('No entry for 127.0.0.1 in etc/hosts') ++ if '192.168.1.1\tblah.blah.us\tblah' not in contents: ++ self.assertIsNone('Default etc/hosts content modified') ++ ++ def test_write_etc_hosts_suse_template(self): ++ cfg = { ++ 'manage_etc_hosts': 'template', ++ 'hostname': 'cloud-init.test.us' ++ } ++ shutil.copytree('templates', '%s/etc/cloud/templates' % self.tmp) ++ distro = self._fetch_distro('sles') ++ paths = helpers.Paths({}) ++ paths.template_tpl = '%s' % self.tmp + '/etc/cloud/templates/%s.tmpl' ++ ds = None ++ cc = cloud.Cloud(ds, paths, {}, distro, None) ++ self.patchUtils(self.tmp) ++ cc_update_etc_hosts.handle('test', cfg, cc, LOG, []) ++ contents = util.load_file('%s/etc/hosts' % self.tmp) ++ if '127.0.0.1 cloud-init.test.us cloud-init' not in contents: ++ self.assertIsNone('No entry for 127.0.0.1 in etc/hosts') ++ if '::1 cloud-init.test.us cloud-init' not in contents: ++ self.assertIsNone('No entry for 127.0.0.1 in etc/hosts') diff --git a/cloud-init-ntp-conf-suse.patch b/cloud-init-ntp-conf-suse.patch new file mode 100644 index 0000000..54ff770 --- /dev/null +++ b/cloud-init-ntp-conf-suse.patch @@ -0,0 +1,166 @@ +--- cloudinit/config/cc_ntp.py.orig ++++ cloudinit/config/cc_ntp.py +@@ -23,7 +23,7 @@ frequency = PER_INSTANCE + NTP_CONF = '/etc/ntp.conf' + TIMESYNCD_CONF = '/etc/systemd/timesyncd.conf.d/cloud-init.conf' + NR_POOL_SERVERS = 4 +-distros = ['centos', 'debian', 'fedora', 'opensuse', 'ubuntu'] ++distros = ['centos', 'debian', 'fedora', 'opensuse', 'sles', 'ubuntu'] + + + # The schema definition for each cloud-config module is a strict contract for +@@ -172,6 +172,9 @@ def rename_ntp_conf(config=None): + + def generate_server_names(distro): + names = [] ++ pool_distro = distro ++ if distro == 'sles': ++ pool_distro = 'opensuse' + for x in range(0, NR_POOL_SERVERS): + name = "%d.%s.pool.ntp.org" % (x, distro) + names.append(name) +--- /dev/null ++++ templates/ntp.conf.opensuse.tmpl +@@ -0,0 +1,88 @@ ++## template:jinja ++ ++## ++## Radio and modem clocks by convention have addresses in the ++## form 127.127.t.u, where t is the clock type and u is a unit ++## number in the range 0-3. ++## ++## Most of these clocks require support in the form of a ++## serial port or special bus peripheral. The particular ++## device is normally specified by adding a soft link ++## /dev/device-u to the particular hardware device involved, ++## where u correspond to the unit number above. ++## ++## Generic DCF77 clock on serial port (Conrad DCF77) ++## Address: 127.127.8.u ++## Serial Port: /dev/refclock-u ++## ++## (create soft link /dev/refclock-0 to the particular ttyS?) ++## ++# server 127.127.8.0 mode 5 prefer ++ ++## ++## Undisciplined Local Clock. This is a fake driver intended for backup ++## and when no outside source of synchronized time is available. ++## ++# server 127.127.1.0 # local clock (LCL) ++# fudge 127.127.1.0 stratum 10 # LCL is unsynchronized ++ ++## ++## Add external Servers using ++## # rcntpd addserver ++## The servers will only be added to the currently running instance, not ++## to /etc/ntp.conf. ++## ++{% if pools %}# pools ++{% endif %} ++{% for pool in pools -%} ++pool {{pool}} iburst ++{% endfor %} ++{%- if servers %}# servers ++{% endif %} ++{% for server in servers -%} ++server {{server}} iburst ++{% endfor %} ++ ++# Access control configuration; see /usr/share/doc/packages/ntp/html/accopt.html for ++# details. The web page ++# might also be helpful. ++# ++# Note that "restrict" applies to both servers and clients, so a configuration ++# that might be intended to block requests from certain clients could also end ++# up blocking replies from your own upstream servers. ++ ++# By default, exchange time with everybody, but don't allow configuration. ++restrict -4 default notrap nomodify nopeer noquery ++restrict -6 default notrap nomodify nopeer noquery ++ ++# Local users may interrogate the ntp server more closely. ++restrict 127.0.0.1 ++restrict ::1 ++ ++# Clients from this (example!) subnet have unlimited access, but only if ++# cryptographically authenticated. ++#restrict 192.168.123.0 mask 255.255.255.0 notrust ++ ++## ++## Miscellaneous stuff ++## ++ ++driftfile /var/lib/ntp/drift/ntp.drift # path for drift file ++ ++logfile /var/log/ntp # alternate log file ++# logconfig =syncstatus + sysevents ++# logconfig =all ++ ++# statsdir /tmp/ # directory for statistics files ++# filegen peerstats file peerstats type day enable ++# filegen loopstats file loopstats type day enable ++# filegen clockstats file clockstats type day enable ++ ++# ++# Authentication stuff ++# ++keys /etc/ntp.keys # path for keys file ++trustedkey 1 # define trusted keys ++requestkey 1 # key (7) for accessing server variables ++controlkey 1 # key (6) for accessing server variables ++ +--- templates/ntp.conf.sles.tmpl.orig ++++ templates/ntp.conf.sles.tmpl +@@ -1,17 +1,5 @@ + ## template:jinja + +-################################################################################ +-## /etc/ntp.conf +-## +-## Sample NTP configuration file. +-## See package 'ntp-doc' for documentation, Mini-HOWTO and FAQ. +-## Copyright (c) 1998 S.u.S.E. GmbH Fuerth, Germany. +-## +-## Author: Michael Andres, +-## Michael Skibbe, +-## +-################################################################################ +- + ## + ## Radio and modem clocks by convention have addresses in the + ## form 127.127.t.u, where t is the clock type and u is a unit +--- tests/unittests/test_handler/test_handler_ntp.py.orig ++++ tests/unittests/test_handler/test_handler_ntp.py +@@ -429,5 +429,31 @@ class TestNtp(FilesystemMockingTestCase) + "[Time]\nNTP=192.168.2.1 192.168.2.2 0.mypool.org \n", + content.decode()) + ++ def test_write_ntp_config_template_defaults_pools_empty_lists_sles(self): ++ """write_ntp_config_template defaults pools servers upon empty config. ++ ++ When both pools and servers are empty, default NR_POOL_SERVERS get ++ configured. ++ """ ++ distro = 'sles' ++ mycloud = self._get_cloud(distro) ++ ntp_conf = self.tmp_path('ntp.conf', self.new_root) # Doesn't exist ++ # Create ntp.conf.tmpl ++ with open('{0}.tmpl'.format(ntp_conf), 'wb') as stream: ++ stream.write(NTP_TEMPLATE) ++ with mock.patch('cloudinit.config.cc_ntp.NTP_CONF', ntp_conf): ++ cc_ntp.write_ntp_config_template({}, mycloud, ntp_conf) ++ content = util.read_file_or_url('file://' + ntp_conf).contents ++ default_pools = [ ++ "{0}.{1}.pool.ntp.org".format(x, 'opensuse') ++ for x in range(0, cc_ntp.NR_POOL_SERVERS)] ++ self.assertEqual( ++ "servers []\npools {0}\n".format(default_pools), ++ content.decode()) ++ self.assertIn( ++ "Adding distro default ntp pool servers: {0}".format( ++ ",".join(default_pools)), ++ self.logs.getvalue()) ++ + + # vi: ts=4 expandtab diff --git a/cloud-init-translate-netconf-ipv4-keep-gw.patch b/cloud-init-translate-netconf-ipv4-keep-gw.patch new file mode 100644 index 0000000..3a34fd7 --- /dev/null +++ b/cloud-init-translate-netconf-ipv4-keep-gw.patch @@ -0,0 +1,46 @@ +--- cloudinit/distros/net_util.py.orig ++++ cloudinit/distros/net_util.py +@@ -67,6 +67,10 @@ + # } + # } + ++import re ++ ++ipv4 = re.compile("\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}") ++ + def translate_network(settings): + # Get the standard cmd, args from the ubuntu format + entries = [] +@@ -88,7 +92,14 @@ def translate_network(settings): + consume = {} + consume[cmd] = args + else: +- consume[cmd] = args ++ if consume.get(cmd): ++ val = consume[cmd] ++ if isinstance(val, list): ++ consume[cmd].append(args) ++ else: ++ consume[cmd] = [val, args] ++ else: ++ consume[cmd] = args + # Check if anything left over to consume + absorb = False + for (cmd, args) in consume.items(): +@@ -148,6 +159,16 @@ def translate_network(settings): + hw_addr = hw_split[1] + if hw_addr: + iface_info['hwaddress'] = hw_addr ++ if 'post-up' in info: ++ routes = info['post-up'] ++ if isinstance(routes, list): ++ for route_info in routes: ++ if 'default gw' in route_info: ++ iface_info['gateway'] = ipv4.search( ++ route_info).group(0) ++ elif 'default gw' in routes: ++ iface_info['gateway'] = ipv4.search(routes).group(0) ++ + # If ipv6 is enabled, device will have multiple IPs, so we need to + # update the dictionary instead of overwriting it... + if dev_name in real_ifaces: diff --git a/cloud-init.changes b/cloud-init.changes index 119526d..7e0c4db 100644 --- a/cloud-init.changes +++ b/cloud-init.changes @@ -1,3 +1,32 @@ +------------------------------------------------------------------- +Sun Nov 19 20:43:46 UTC 2017 - rjschwei@suse.com + +- Add cloud-init-break-cycle-local-service.patch + + Let systemd pull in the default targets. This breaks a cycle + +------------------------------------------------------------------- +Fri Nov 17 17:10:09 UTC 2017 - rjschwei@suse.com + +- Fix variable name in cloud-init-translate-netconf-ipv4-keep-gw.patch + +------------------------------------------------------------------- +Thu Nov 16 22:48:40 UTC 2017 - rjschwei@suse.com + +- Add cloud-init-translate-netconf-ipv4-keep-gw.patch (boo#1064854) + + Properly insert the gateway information for v1 json network config data + +------------------------------------------------------------------- +Sat Nov 11 12:32:54 UTC 2017 - rjschwei@suse.com + +- Add cloud-init-ntp-conf-suse.patch + + ntp configuration was broken on sles and opensuse lp#1726572 + +------------------------------------------------------------------- +Wed Nov 8 21:26:15 UTC 2017 - rjschwei@suse.com + +- Add cloud-init-hosts-template.patch (bsc#1064594) + + Properly expand the /etc/hosst file when manage_etc_hosts is set + ------------------------------------------------------------------- Thu Nov 2 13:16:49 UTC 2017 - rjschwei@suse.com diff --git a/cloud-init.spec b/cloud-init.spec index de728da..1ab6c4c 100644 --- a/cloud-init.spec +++ b/cloud-init.spec @@ -26,12 +26,21 @@ Url: http://launchpad.net/cloud-init/ Group: System/Management Source0: %{name}-%{version}.tar.gz Source1: rsyslog-cloud-init.cfg -# FIXME zypp_add_repos.diff needs proposed for upstream merge +# 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 -# FIXME cloud-init-more-tasks.patch proposed for upstream merge +# 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 @@ -190,6 +199,10 @@ Documentation and examples for cloud-init tools %setup -q %patch4 -p0 %patch5 -p0 +%patch6 +%patch7 +%patch8 +%patch9 %patch10 -p1 %patch12 %patch13