From 222d628b5795fe972b27e4eddb1f0f6567241bdb Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 07 2019 06:05:29 +0000 Subject: import cloud-init-18.2-6.el8 --- diff --git a/.cloud-init.metadata b/.cloud-init.metadata new file mode 100644 index 0000000..5f02606 --- /dev/null +++ b/.cloud-init.metadata @@ -0,0 +1 @@ +703864e79a15335d1e2552866b63d25f55f8a555 SOURCES/cloud-init-18.2.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b4be453 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/cloud-init-18.2.tar.gz diff --git a/SOURCES/0001-Add-initial-redhat-setup.patch b/SOURCES/0001-Add-initial-redhat-setup.patch new file mode 100644 index 0000000..0de3cdd --- /dev/null +++ b/SOURCES/0001-Add-initial-redhat-setup.patch @@ -0,0 +1,482 @@ +From 8ff55af097479b3d29519f15624aa6c69fda3bba Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 31 May 2018 16:45:23 +0200 +Subject: Add initial redhat setup + +--- + cloudinit/config/cc_chef.py | 6 +- + cloudinit/settings.py | 7 +- + redhat/.gitignore | 1 + + redhat/Makefile | 71 ++++++++ + redhat/Makefile.common | 35 ++++ + redhat/cloud-init-tmpfiles.conf | 1 + + redhat/cloud-init.spec.template | 318 +++++++++++++++++++++++++++++++++ + redhat/rpmbuild/BUILD/.gitignore | 3 + + redhat/rpmbuild/RPMS/.gitignore | 3 + + redhat/rpmbuild/SOURCES/.gitignore | 3 + + redhat/rpmbuild/SPECS/.gitignore | 3 + + redhat/rpmbuild/SRPMS/.gitignore | 3 + + redhat/scripts/frh.py | 27 +++ + redhat/scripts/git-backport-diff | 327 ++++++++++++++++++++++++++++++++++ + redhat/scripts/git-compile-check | 215 ++++++++++++++++++++++ + redhat/scripts/process-patches.sh | 73 ++++++++ + redhat/scripts/tarball_checksum.sh | 3 + + rhel/README.rhel | 5 + + rhel/cloud-init-tmpfiles.conf | 1 + + rhel/cloud.cfg | 66 +++++++ + rhel/systemd/cloud-config.service | 18 ++ + rhel/systemd/cloud-config.target | 11 ++ + rhel/systemd/cloud-final.service | 19 ++ + rhel/systemd/cloud-init-local.service | 31 ++++ + rhel/systemd/cloud-init.service | 25 +++ + setup.py | 64 +------ + tools/read-version | 19 +- + 27 files changed, 1274 insertions(+), 84 deletions(-) + create mode 100644 redhat/.gitignore + create mode 100644 redhat/Makefile + create mode 100644 redhat/Makefile.common + create mode 100644 redhat/cloud-init-tmpfiles.conf + create mode 100644 redhat/cloud-init.spec.template + create mode 100644 redhat/rpmbuild/BUILD/.gitignore + create mode 100644 redhat/rpmbuild/RPMS/.gitignore + create mode 100644 redhat/rpmbuild/SOURCES/.gitignore + create mode 100644 redhat/rpmbuild/SPECS/.gitignore + create mode 100644 redhat/rpmbuild/SRPMS/.gitignore + create mode 100755 redhat/scripts/frh.py + create mode 100755 redhat/scripts/git-backport-diff + create mode 100755 redhat/scripts/git-compile-check + create mode 100755 redhat/scripts/process-patches.sh + create mode 100755 redhat/scripts/tarball_checksum.sh + create mode 100644 rhel/README.rhel + create mode 100644 rhel/cloud-init-tmpfiles.conf + create mode 100644 rhel/cloud.cfg + create mode 100644 rhel/systemd/cloud-config.service + create mode 100644 rhel/systemd/cloud-config.target + create mode 100644 rhel/systemd/cloud-final.service + create mode 100644 rhel/systemd/cloud-init-local.service + create mode 100644 rhel/systemd/cloud-init.service + +diff --git a/cloudinit/config/cc_chef.py b/cloudinit/config/cc_chef.py +index 46abedd..fe7bda8 100644 +--- a/cloudinit/config/cc_chef.py ++++ b/cloudinit/config/cc_chef.py +@@ -33,7 +33,7 @@ file). + + chef: + directories: (defaulting to /etc/chef, /var/log/chef, /var/lib/chef, +- /var/cache/chef, /var/backups/chef, /var/run/chef) ++ /var/cache/chef, /var/backups/chef, /run/chef) + validation_cert: (optional string to be written to file validation_key) + special value 'system' means set use existing file + validation_key: (optional the path for validation_cert. default +@@ -88,7 +88,7 @@ CHEF_DIRS = tuple([ + '/var/lib/chef', + '/var/cache/chef', + '/var/backups/chef', +- '/var/run/chef', ++ '/run/chef', + ]) + REQUIRED_CHEF_DIRS = tuple([ + '/etc/chef', +@@ -112,7 +112,7 @@ CHEF_RB_TPL_DEFAULTS = { + 'json_attribs': CHEF_FB_PATH, + 'file_cache_path': "/var/cache/chef", + 'file_backup_path': "/var/backups/chef", +- 'pid_file': "/var/run/chef/client.pid", ++ 'pid_file': "/run/chef/client.pid", + 'show_time': True, + } + CHEF_RB_TPL_BOOL_KEYS = frozenset(['show_time']) +diff --git a/cloudinit/settings.py b/cloudinit/settings.py +index dde5749..a5a1eec 100644 +--- a/cloudinit/settings.py ++++ b/cloudinit/settings.py +@@ -43,13 +43,16 @@ CFG_BUILTIN = { + ], + 'def_log_file': '/var/log/cloud-init.log', + 'log_cfgs': [], +- 'syslog_fix_perms': ['syslog:adm', 'root:adm', 'root:wheel'], ++ 'mount_default_fields': [None, None, 'auto', 'defaults,nofail', '0', '2'], ++ 'ssh_deletekeys': False, ++ 'ssh_genkeytypes': [], ++ 'syslog_fix_perms': [], + 'system_info': { + 'paths': { + 'cloud_dir': '/var/lib/cloud', + 'templates_dir': '/etc/cloud/templates/', + }, +- 'distro': 'ubuntu', ++ 'distro': 'rhel', + 'network': {'renderers': None}, + }, + 'vendor_data': {'enabled': True, 'prefix': []}, +diff --git a/rhel/README.rhel b/rhel/README.rhel +new file mode 100644 +index 0000000..aa29630 +--- /dev/null ++++ b/rhel/README.rhel +@@ -0,0 +1,5 @@ ++The following cloud-init modules are currently unsupported on this OS: ++ - apt_update_upgrade ('apt_update', 'apt_upgrade', 'apt_mirror', 'apt_preserve_sources_list', 'apt_old_mirror', 'apt_sources', 'debconf_selections', 'packages' options) ++ - byobu ('byobu_by_default' option) ++ - chef ++ - grub_dpkg +diff --git a/rhel/cloud-init-tmpfiles.conf b/rhel/cloud-init-tmpfiles.conf +new file mode 100644 +index 0000000..0c6d2a3 +--- /dev/null ++++ b/rhel/cloud-init-tmpfiles.conf +@@ -0,0 +1 @@ ++d /run/cloud-init 0700 root root - - +diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg +new file mode 100644 +index 0000000..986f241 +--- /dev/null ++++ b/rhel/cloud.cfg +@@ -0,0 +1,66 @@ ++users: ++ - default ++ ++disable_root: 1 ++ssh_pwauth: 0 ++ ++mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2'] ++resize_rootfs_tmp: /dev ++ssh_deletekeys: 0 ++ssh_genkeytypes: ~ ++syslog_fix_perms: ~ ++ ++cloud_init_modules: ++ - migrator ++ - bootcmd ++ - write-files ++ - growpart ++ - resizefs ++ - set_hostname ++ - update_hostname ++ - update_etc_hosts ++ - rsyslog ++ - users-groups ++ - ssh ++ ++cloud_config_modules: ++ - mounts ++ - locale ++ - set-passwords ++ - rh_subscription ++ - yum-add-repo ++ - package-update-upgrade-install ++ - timezone ++ - puppet ++ - chef ++ - salt-minion ++ - mcollective ++ - disable-ec2-metadata ++ - runcmd ++ ++cloud_final_modules: ++ - rightscale_userdata ++ - scripts-per-once ++ - scripts-per-boot ++ - scripts-per-instance ++ - scripts-user ++ - ssh-authkey-fingerprints ++ - keys-to-console ++ - phone-home ++ - final-message ++ ++system_info: ++ default_user: ++ name: cloud-user ++ lock_passwd: true ++ gecos: Cloud User ++ groups: [wheel, adm, systemd-journal] ++ sudo: ["ALL=(ALL) NOPASSWD:ALL"] ++ shell: /bin/bash ++ distro: rhel ++ paths: ++ cloud_dir: /var/lib/cloud ++ templates_dir: /etc/cloud/templates ++ ssh_svcname: sshd ++ ++# vim:syntax=yaml +diff --git a/rhel/systemd/cloud-config.service b/rhel/systemd/cloud-config.service +new file mode 100644 +index 0000000..12ca9df +--- /dev/null ++++ b/rhel/systemd/cloud-config.service +@@ -0,0 +1,18 @@ ++[Unit] ++Description=Apply the settings specified in cloud-config ++After=network-online.target cloud-config.target ++Wants=network-online.target cloud-config.target ++ConditionPathExists=!/etc/cloud/cloud-init.disabled ++ConditionKernelCommandLine=!cloud-init=disabled ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/bin/cloud-init modules --mode=config ++RemainAfterExit=yes ++TimeoutSec=0 ++ ++# Output needs to appear in instance console output ++StandardOutput=journal+console ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/rhel/systemd/cloud-config.target b/rhel/systemd/cloud-config.target +new file mode 100644 +index 0000000..ae9b7d0 +--- /dev/null ++++ b/rhel/systemd/cloud-config.target +@@ -0,0 +1,11 @@ ++# cloud-init normally emits a "cloud-config" upstart event to inform third ++# parties that cloud-config is available, which does us no good when we're ++# using systemd. cloud-config.target serves as this synchronization point ++# instead. Services that would "start on cloud-config" with upstart can ++# instead use "After=cloud-config.target" and "Wants=cloud-config.target" ++# as appropriate. ++ ++[Unit] ++Description=Cloud-config availability ++Wants=cloud-init-local.service cloud-init.service ++After=cloud-init-local.service cloud-init.service +diff --git a/rhel/systemd/cloud-final.service b/rhel/systemd/cloud-final.service +new file mode 100644 +index 0000000..32a83d8 +--- /dev/null ++++ b/rhel/systemd/cloud-final.service +@@ -0,0 +1,19 @@ ++[Unit] ++Description=Execute cloud user/final scripts ++After=network-online.target cloud-config.service rc-local.service ++Wants=network-online.target cloud-config.service ++ConditionPathExists=!/etc/cloud/cloud-init.disabled ++ConditionKernelCommandLine=!cloud-init=disabled ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/bin/cloud-init modules --mode=final ++RemainAfterExit=yes ++TimeoutSec=0 ++KillMode=process ++ ++# Output needs to appear in instance console output ++StandardOutput=journal+console ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/rhel/systemd/cloud-init-local.service b/rhel/systemd/cloud-init-local.service +new file mode 100644 +index 0000000..656eddb +--- /dev/null ++++ b/rhel/systemd/cloud-init-local.service +@@ -0,0 +1,31 @@ ++[Unit] ++Description=Initial cloud-init job (pre-networking) ++DefaultDependencies=no ++Wants=network-pre.target ++After=systemd-remount-fs.service ++Requires=dbus.socket ++After=dbus.socket ++Before=NetworkManager.service network.service ++Before=network-pre.target ++Before=shutdown.target ++Before=firewalld.target ++Conflicts=shutdown.target ++RequiresMountsFor=/var/lib/cloud ++ConditionPathExists=!/etc/cloud/cloud-init.disabled ++ConditionKernelCommandLine=!cloud-init=disabled ++ ++[Service] ++Type=oneshot ++ExecStartPre=/bin/mkdir -p /run/cloud-init ++ExecStartPre=/sbin/restorecon /run/cloud-init ++ExecStartPre=/usr/bin/touch /run/cloud-init/enabled ++ExecStart=/usr/bin/cloud-init init --local ++ExecStart=/bin/touch /run/cloud-init/network-config-ready ++RemainAfterExit=yes ++TimeoutSec=0 ++ ++# Output needs to appear in instance console output ++StandardOutput=journal+console ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/rhel/systemd/cloud-init.service b/rhel/systemd/cloud-init.service +new file mode 100644 +index 0000000..68fc5f1 +--- /dev/null ++++ b/rhel/systemd/cloud-init.service +@@ -0,0 +1,25 @@ ++[Unit] ++Description=Initial cloud-init job (metadata service crawler) ++Wants=cloud-init-local.service ++Wants=sshd-keygen.service ++Wants=sshd.service ++After=cloud-init-local.service ++After=NetworkManager.service network.service ++Before=network-online.target ++Before=sshd-keygen.service ++Before=sshd.service ++Before=systemd-user-sessions.service ++ConditionPathExists=!/etc/cloud/cloud-init.disabled ++ConditionKernelCommandLine=!cloud-init=disabled ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/bin/cloud-init init ++RemainAfterExit=yes ++TimeoutSec=0 ++ ++# Output needs to appear in instance console output ++StandardOutput=journal+console ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/setup.py b/setup.py +index bc3f52a..47cf842 100755 +--- a/setup.py ++++ b/setup.py +@@ -125,11 +125,6 @@ INITSYS_FILES = { + 'sysvinit_deb': [f for f in glob('sysvinit/debian/*') if is_f(f)], + 'sysvinit_openrc': [f for f in glob('sysvinit/gentoo/*') if is_f(f)], + 'sysvinit_suse': [f for f in glob('sysvinit/suse/*') if is_f(f)], +- 'systemd': [render_tmpl(f) +- for f in (glob('systemd/*.tmpl') + +- glob('systemd/*.service') + +- glob('systemd/*.target')) if is_f(f)], +- 'systemd.generators': [f for f in glob('systemd/*-generator') if is_f(f)], + 'upstart': [f for f in glob('upstart/*') if is_f(f)], + } + INITSYS_ROOTS = { +@@ -138,9 +133,6 @@ INITSYS_ROOTS = { + 'sysvinit_deb': 'etc/init.d', + 'sysvinit_openrc': 'etc/init.d', + 'sysvinit_suse': 'etc/init.d', +- 'systemd': pkg_config_read('systemd', 'systemdsystemunitdir'), +- 'systemd.generators': pkg_config_read('systemd', +- 'systemdsystemgeneratordir'), + 'upstart': 'etc/init/', + } + INITSYS_TYPES = sorted([f.partition(".")[0] for f in INITSYS_ROOTS.keys()]) +@@ -178,47 +170,6 @@ class MyEggInfo(egg_info): + return ret + + +-# TODO: Is there a better way to do this?? +-class InitsysInstallData(install): +- init_system = None +- user_options = install.user_options + [ +- # This will magically show up in member variable 'init_sys' +- ('init-system=', None, +- ('init system(s) to configure (%s) [default: None]' % +- (", ".join(INITSYS_TYPES)))), +- ] +- +- def initialize_options(self): +- install.initialize_options(self) +- self.init_system = "" +- +- def finalize_options(self): +- install.finalize_options(self) +- +- if self.init_system and isinstance(self.init_system, str): +- self.init_system = self.init_system.split(",") +- +- if len(self.init_system) == 0: +- self.init_system = ['systemd'] +- +- bad = [f for f in self.init_system if f not in INITSYS_TYPES] +- if len(bad) != 0: +- raise DistutilsArgError( +- "Invalid --init-system: %s" % (','.join(bad))) +- +- for system in self.init_system: +- # add data files for anything that starts with '.' +- datakeys = [k for k in INITSYS_ROOTS +- if k.partition(".")[0] == system] +- for k in datakeys: +- if not INITSYS_FILES[k]: +- continue +- self.distribution.data_files.append( +- (INITSYS_ROOTS[k], INITSYS_FILES[k])) +- # Force that command to reinitalize (with new file list) +- self.distribution.reinitialize_command('install_data', True) +- +- + if not in_virtualenv(): + USR = "/" + USR + ETC = "/" + ETC +@@ -228,11 +179,9 @@ if not in_virtualenv(): + INITSYS_ROOTS[k] = "/" + INITSYS_ROOTS[k] + + data_files = [ +- (ETC + '/cloud', [render_tmpl("config/cloud.cfg.tmpl")]), + (ETC + '/cloud/cloud.cfg.d', glob('config/cloud.cfg.d/*')), + (ETC + '/cloud/templates', glob('templates/*')), +- (USR_LIB_EXEC + '/cloud-init', ['tools/ds-identify', +- 'tools/uncloud-init', ++ (USR_LIB_EXEC + '/cloud-init', ['tools/uncloud-init', + 'tools/write-ssh-key-fingerprints']), + (USR + '/share/doc/cloud-init', [f for f in glob('doc/*') if is_f(f)]), + (USR + '/share/doc/cloud-init/examples', +@@ -244,15 +193,8 @@ if os.uname()[0] != 'FreeBSD': + data_files.extend([ + (ETC + '/NetworkManager/dispatcher.d/', + ['tools/hook-network-manager']), +- (ETC + '/dhcp/dhclient-exit-hooks.d/', ['tools/hook-dhclient']), +- (LIB + '/udev/rules.d', [f for f in glob('udev/*.rules')]) ++ ('/usr/lib/udev/rules.d', [f for f in glob('udev/*.rules')]) + ]) +-# Use a subclass for install that handles +-# adding on the right init system configuration files +-cmdclass = { +- 'install': InitsysInstallData, +- 'egg_info': MyEggInfo, +-} + + requirements = read_requires() + +@@ -267,8 +209,6 @@ setuptools.setup( + scripts=['tools/cloud-init-per'], + license='Dual-licensed under GPLv3 or Apache 2.0', + data_files=data_files, +- install_requires=requirements, +- cmdclass=cmdclass, + entry_points={ + 'console_scripts': [ + 'cloud-init = cloudinit.cmd.main:main' +diff --git a/tools/read-version b/tools/read-version +index 3ea9e66..d43cc8f 100755 +--- a/tools/read-version ++++ b/tools/read-version +@@ -65,23 +65,8 @@ output_json = '--json' in sys.argv + src_version = ci_version.version_string() + version_long = None + +-if is_gitdir(_tdir) and which("git"): +- flags = [] +- if use_tags: +- flags = ['--tags'] +- cmd = ['git', 'describe', '--abbrev=8', '--match=[0-9]*'] + flags +- +- version = tiny_p(cmd).strip() +- +- if not version.startswith(src_version): +- sys.stderr.write("git describe version (%s) differs from " +- "cloudinit.version (%s)\n" % (version, src_version)) +- sys.exit(1) +- +- version_long = tiny_p(cmd + ["--long"]).strip() +-else: +- version = src_version +- version_long = None ++version = src_version ++version_long = None + + # version is X.Y.Z[+xxx.gHASH] + # version_long is None or X.Y.Z-xxx-gHASH +-- +1.8.3.1 + diff --git a/SOURCES/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch b/SOURCES/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch new file mode 100644 index 0000000..13e1baf --- /dev/null +++ b/SOURCES/0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch @@ -0,0 +1,307 @@ +From 48610bf1f404fc8c71e0091ad4b877e851e06642 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 31 May 2018 19:37:55 +0200 +Subject: Do not write NM_CONTROLLED=no in generated interface config files + +X-downstream-only: true +Signed-off-by: Ryan McCabe +--- + cloudinit/net/sysconfig.py | 1 - + tests/unittests/test_distros/test_netconfig.py | 4 ---- + tests/unittests/test_net.py | 30 -------------------------- + 3 files changed, 35 deletions(-) + +diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py +index 39d89c4..cefb5c5 100644 +--- a/cloudinit/net/sysconfig.py ++++ b/cloudinit/net/sysconfig.py +@@ -233,7 +233,6 @@ class Renderer(renderer.Renderer): + iface_defaults = tuple([ + ('ONBOOT', True), + ('USERCTL', False), +- ('NM_CONTROLLED', False), + ('BOOTPROTO', 'none'), + ]) + +diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py +index 1c2e45f..2f69455 100644 +--- a/tests/unittests/test_distros/test_netconfig.py ++++ b/tests/unittests/test_distros/test_netconfig.py +@@ -479,7 +479,6 @@ DEVICE=eth0 + GATEWAY=192.168.1.254 + IPADDR=192.168.1.5 + NETMASK=255.255.255.0 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -496,7 +495,6 @@ USERCTL=no + # + BOOTPROTO=dhcp + DEVICE=eth1 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -630,7 +628,6 @@ DEVICE=eth0 + IPV6ADDR=2607:f0d0:1002:0011::2/64 + IPV6INIT=yes + IPV6_DEFAULTGW=2607:f0d0:1002:0011::1 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -645,7 +642,6 @@ USERCTL=no + # + BOOTPROTO=dhcp + DEVICE=eth1 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index c12a487..95318ed 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -144,7 +144,6 @@ GATEWAY=172.19.3.254 + HWADDR=fa:16:3e:ed:9a:59 + IPADDR=172.19.1.34 + NETMASK=255.255.252.0 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -212,7 +211,6 @@ IPADDR=172.19.1.34 + IPADDR1=10.0.0.10 + NETMASK=255.255.252.0 + NETMASK1=255.255.255.0 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -302,7 +300,6 @@ IPV6ADDR_SECONDARIES="2001:DB9::10/64 2001:DB10::10/64" + IPV6INIT=yes + IPV6_DEFAULTGW=2001:DB8::1 + NETMASK=255.255.252.0 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -417,7 +414,6 @@ NETWORK_CONFIGS = { + BOOTPROTO=none + DEVICE=eth1 + HWADDR=cf:d6:af:48:e8:80 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no"""), +@@ -432,7 +428,6 @@ NETWORK_CONFIGS = { + HWADDR=c0:d6:9f:2c:e8:80 + IPADDR=192.168.21.3 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no"""), +@@ -544,7 +539,6 @@ NETWORK_CONFIGS = { + IPV6ADDR=2001:1::1/64 + IPV6INIT=yes + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -745,14 +739,12 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + DHCPV6C=yes + IPV6INIT=yes + MACADDR=aa:bb:cc:dd:ee:ff +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Bond + USERCTL=no"""), + 'ifcfg-bond0.200': textwrap.dedent("""\ + BOOTPROTO=dhcp + DEVICE=bond0.200 +- NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=bond0 + TYPE=Ethernet +@@ -768,7 +760,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + IPV6INIT=yes + IPV6_DEFAULTGW=2001:4800:78ff:1b::1 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + PRIO=22 + STP=no +@@ -778,7 +769,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + BOOTPROTO=none + DEVICE=eth0 + HWADDR=c0:d6:9f:2c:e8:80 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no"""), +@@ -795,7 +785,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + MTU=1500 + NETMASK=255.255.255.0 + NETMASK1=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=eth0 + TYPE=Ethernet +@@ -806,7 +795,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + DEVICE=eth1 + HWADDR=aa:d6:9f:2c:e8:80 + MASTER=bond0 +- NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes + TYPE=Ethernet +@@ -816,7 +804,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + DEVICE=eth2 + HWADDR=c0:bb:9f:2c:e8:80 + MASTER=bond0 +- NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes + TYPE=Ethernet +@@ -826,7 +813,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + BRIDGE=br0 + DEVICE=eth3 + HWADDR=66:bb:9f:2c:e8:80 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no"""), +@@ -835,7 +821,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + BRIDGE=br0 + DEVICE=eth4 + HWADDR=98:bb:9f:2c:e8:80 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no"""), +@@ -843,7 +828,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + BOOTPROTO=dhcp + DEVICE=eth5 + HWADDR=98:bb:9f:2c:e8:8a +- NM_CONTROLLED=no + ONBOOT=no + TYPE=Ethernet + USERCTL=no""") +@@ -1125,7 +1109,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + IPV6INIT=yes + NETMASK=255.255.255.0 + NETMASK1=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Bond + USERCTL=no +@@ -1135,7 +1118,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + DEVICE=bond0s0 + HWADDR=aa:bb:cc:dd:e8:00 + MASTER=bond0 +- NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes + TYPE=Ethernet +@@ -1153,7 +1135,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + DEVICE=bond0s1 + HWADDR=aa:bb:cc:dd:e8:01 + MASTER=bond0 +- NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes + TYPE=Ethernet +@@ -1190,7 +1171,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + BOOTPROTO=none + DEVICE=en0 + HWADDR=aa:bb:cc:dd:e8:00 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no"""), +@@ -1206,7 +1186,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + IPV6_DEFAULTGW=2001:1::1 + NETMASK=255.255.255.0 + NETMASK1=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=en0 + TYPE=Ethernet +@@ -1247,7 +1226,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + DEVICE=br0 + IPADDR=192.168.2.2 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=yes + PRIO=22 + STP=no +@@ -1261,7 +1239,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + HWADDR=52:54:00:12:34:00 + IPV6ADDR=2001:1::100/96 + IPV6INIT=yes +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -1273,7 +1250,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + HWADDR=52:54:00:12:34:01 + IPV6ADDR=2001:1::101/96 + IPV6INIT=yes +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -1347,7 +1323,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + HWADDR=52:54:00:12:34:00 + IPADDR=192.168.1.2 + NETMASK=255.255.255.0 +- NM_CONTROLLED=no + ONBOOT=no + TYPE=Ethernet + USERCTL=no +@@ -1357,7 +1332,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + DEVICE=eth1 + HWADDR=52:54:00:12:34:aa + MTU=1480 +- NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -1366,7 +1340,6 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + BOOTPROTO=none + DEVICE=eth2 + HWADDR=52:54:00:12:34:ff +- NM_CONTROLLED=no + ONBOOT=no + TYPE=Ethernet + USERCTL=no +@@ -1639,7 +1612,6 @@ class TestSysConfigRendering(CiTestCase): + BOOTPROTO=dhcp + DEVICE=eth1000 + HWADDR=07-1C-C6-75-A4-BE +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -1759,7 +1731,6 @@ GATEWAY=10.0.2.2 + HWADDR=52:54:00:12:34:00 + IPADDR=10.0.2.15 + NETMASK=255.255.255.0 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +@@ -1780,7 +1751,6 @@ USERCTL=no + # + BOOTPROTO=dhcp + DEVICE=eth0 +-NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no +-- +1.8.3.1 + diff --git a/SOURCES/0003-limit-permissions-on-def_log_file.patch b/SOURCES/0003-limit-permissions-on-def_log_file.patch new file mode 100644 index 0000000..20d7e7b --- /dev/null +++ b/SOURCES/0003-limit-permissions-on-def_log_file.patch @@ -0,0 +1,66 @@ +From a49f5cd665c3bdb6a40c95d561791b6bbce9f079 Mon Sep 17 00:00:00 2001 +From: Lars Kellogg-Stedman +Date: Fri, 7 Apr 2017 18:50:54 -0400 +Subject: limit permissions on def_log_file + +This sets a default mode of 0600 on def_log_file, and makes this +configurable via the def_log_file_mode option in cloud.cfg. + +LP: #1541196 +Resolves: rhbz#1424612 +X-approved-upstream: true +--- + cloudinit/settings.py | 1 + + cloudinit/stages.py | 3 ++- + doc/examples/cloud-config.txt | 4 ++++ + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/cloudinit/settings.py b/cloudinit/settings.py +index a5a1eec..4efe6b6 100644 +--- a/cloudinit/settings.py ++++ b/cloudinit/settings.py +@@ -42,6 +42,7 @@ CFG_BUILTIN = { + 'None', + ], + 'def_log_file': '/var/log/cloud-init.log', ++ 'def_log_file_mode': 0o600, + 'log_cfgs': [], + 'mount_default_fields': [None, None, 'auto', 'defaults,nofail', '0', '2'], + 'ssh_deletekeys': False, +diff --git a/cloudinit/stages.py b/cloudinit/stages.py +index bc4ebc8..40336e0 100644 +--- a/cloudinit/stages.py ++++ b/cloudinit/stages.py +@@ -145,8 +145,9 @@ class Init(object): + def _initialize_filesystem(self): + util.ensure_dirs(self._initial_subdirs()) + log_file = util.get_cfg_option_str(self.cfg, 'def_log_file') ++ log_file_mode = util.get_cfg_option_int(self.cfg, 'def_log_file_mode') + if log_file: +- util.ensure_file(log_file) ++ util.ensure_file(log_file, mode=log_file_mode) + perms = self.cfg.get('syslog_fix_perms') + if not perms: + perms = {} +diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt +index bd84c64..99e6fdd 100644 +--- a/doc/examples/cloud-config.txt ++++ b/doc/examples/cloud-config.txt +@@ -397,10 +397,14 @@ timezone: US/Eastern + # if syslog_fix_perms is a list, it will iterate through and use the + # first pair that does not raise error. + # ++# 'def_log_file' will be created with mode 'def_log_file_mode', which ++# is specified as a numeric value and defaults to 0600. ++# + # the default values are '/var/log/cloud-init.log' and 'syslog:adm' + # the value of 'def_log_file' should match what is configured in logging + # if either is empty, then no change of ownership will be done + def_log_file: /var/log/my-logging-file.log ++def_log_file_mode: 0600 + syslog_fix_perms: syslog:root + + # you can set passwords for a user or multiple users +-- +1.8.3.1 + diff --git a/SOURCES/0005-add-power-state-change-module-to-cloud_final_modules.patch b/SOURCES/0005-add-power-state-change-module-to-cloud_final_modules.patch new file mode 100644 index 0000000..fd0605e --- /dev/null +++ b/SOURCES/0005-add-power-state-change-module-to-cloud_final_modules.patch @@ -0,0 +1,27 @@ +From 2d6b469b1aa915c219fa19012b1fc3c57b218cb3 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 31 May 2018 19:47:44 +0200 +Subject: add power-state-change module to cloud_final_modules + +Resolves: rhbz#1252477 +X-downstream-only: true +Signed-off-by: Ryan McCabe +--- + rhel/cloud.cfg | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg +index 986f241..8644872 100644 +--- a/rhel/cloud.cfg ++++ b/rhel/cloud.cfg +@@ -48,6 +48,7 @@ cloud_final_modules: + - keys-to-console + - phone-home + - final-message ++ - power-state-change + + system_info: + default_user: +-- +1.8.3.1 + diff --git a/SOURCES/0006-azure-ensure-that-networkmanager-hook-script-runs.patch b/SOURCES/0006-azure-ensure-that-networkmanager-hook-script-runs.patch new file mode 100644 index 0000000..51ed40f --- /dev/null +++ b/SOURCES/0006-azure-ensure-that-networkmanager-hook-script-runs.patch @@ -0,0 +1,63 @@ +From c48497435e8195dbd87262c2f00e484e63fe3343 Mon Sep 17 00:00:00 2001 +From: Lars Kellogg-Stedman +Date: Thu, 15 Jun 2017 12:20:39 -0400 +Subject: azure: ensure that networkmanager hook script runs + +The networkmanager hook script was failing to run due to the changes +we made to resolve rhbz#1440831. This corrects the regression by +allowing the NM hook script to run regardless of whether or not +cloud-init is "enabled". + +Resolves: rhbz#1460206 +X-downstream-only: true +--- + tools/hook-dhclient | 3 +-- + tools/hook-network-manager | 3 +-- + tools/hook-rhel.sh | 3 +-- + 3 files changed, 3 insertions(+), 6 deletions(-) + +diff --git a/tools/hook-dhclient b/tools/hook-dhclient +index 02122f3..181cd51 100755 +--- a/tools/hook-dhclient ++++ b/tools/hook-dhclient +@@ -13,8 +13,7 @@ is_azure() { + } + + is_enabled() { +- # only execute hooks if cloud-init is enabled and on azure +- [ -e /run/cloud-init/enabled ] || return 1 ++ # only execute hooks if cloud-init is running on azure + is_azure + } + +diff --git a/tools/hook-network-manager b/tools/hook-network-manager +index 67d9044..1d52cad 100755 +--- a/tools/hook-network-manager ++++ b/tools/hook-network-manager +@@ -13,8 +13,7 @@ is_azure() { + } + + is_enabled() { +- # only execute hooks if cloud-init is enabled and on azure +- [ -e /run/cloud-init/enabled ] || return 1 ++ # only execute hooks if cloud-init running on azure + is_azure + } + +diff --git a/tools/hook-rhel.sh b/tools/hook-rhel.sh +index 513a551..d75767e 100755 +--- a/tools/hook-rhel.sh ++++ b/tools/hook-rhel.sh +@@ -13,8 +13,7 @@ is_azure() { + } + + is_enabled() { +- # only execute hooks if cloud-init is enabled and on azure +- [ -e /run/cloud-init/enabled ] || return 1 ++ # only execute hooks if cloud-init is running on azure + is_azure + } + +-- +1.8.3.1 + diff --git a/SOURCES/0007-sysconfig-Don-t-write-BOOTPROTO-dhcp-for-ipv6-dhcp.patch b/SOURCES/0007-sysconfig-Don-t-write-BOOTPROTO-dhcp-for-ipv6-dhcp.patch new file mode 100644 index 0000000..027abbe --- /dev/null +++ b/SOURCES/0007-sysconfig-Don-t-write-BOOTPROTO-dhcp-for-ipv6-dhcp.patch @@ -0,0 +1,49 @@ +From 867056799c8dca5e8e7768df71fd8e7ff08d200d Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 31 May 2018 20:00:32 +0200 +Subject: sysconfig: Don't write BOOTPROTO=dhcp for ipv6 dhcp + +Don't write BOOTPROTO=dhcp for ipv6 dhcp, as BOOTPROTO applies +only to ipv4. Explicitly write IPV6_AUTOCONF=no for dhcp on ipv6. + +X-downstream-only: yes + +Resolves: rhbz#1519271 +Signed-off-by: Ryan McCabe +--- + cloudinit/net/sysconfig.py | 2 +- + tests/unittests/test_net.py | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py +index cefb5c5..f870b0f 100644 +--- a/cloudinit/net/sysconfig.py ++++ b/cloudinit/net/sysconfig.py +@@ -286,7 +286,7 @@ class Renderer(renderer.Renderer): + if subnet_type == 'dhcp6': + iface_cfg['IPV6INIT'] = True + iface_cfg['DHCPV6C'] = True +- iface_cfg['BOOTPROTO'] = 'dhcp' ++ iface_cfg['IPV6_AUTOCONF'] = False + elif subnet_type in ['dhcp4', 'dhcp']: + iface_cfg['BOOTPROTO'] = 'dhcp' + elif subnet_type == 'static': +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index 95318ed..9cf41bc 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -734,9 +734,10 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + """miimon=100" + BONDING_SLAVE0=eth1 + BONDING_SLAVE1=eth2 +- BOOTPROTO=dhcp ++ BOOTPROTO=none + DEVICE=bond0 + DHCPV6C=yes ++ IPV6_AUTOCONF=no + IPV6INIT=yes + MACADDR=aa:bb:cc:dd:ee:ff + ONBOOT=yes +-- +1.8.3.1 + diff --git a/SOURCES/0008-DataSourceAzure.py-use-hostnamectl-to-set-hostname.patch b/SOURCES/0008-DataSourceAzure.py-use-hostnamectl-to-set-hostname.patch new file mode 100644 index 0000000..ee23035 --- /dev/null +++ b/SOURCES/0008-DataSourceAzure.py-use-hostnamectl-to-set-hostname.patch @@ -0,0 +1,56 @@ +From 004f265bace18a6e45d954c5d7bdfe344a19178e Mon Sep 17 00:00:00 2001 +From: Vitaly Kuznetsov +Date: Tue, 17 Apr 2018 13:07:54 +0200 +Subject: DataSourceAzure.py: use hostnamectl to set hostname + +RH-Author: Vitaly Kuznetsov +Message-id: <20180417130754.12918-3-vkuznets@redhat.com> +Patchwork-id: 79659 +O-Subject: [RHEL7.6/7.5.z cloud-init PATCH 2/2] DataSourceAzure.py: use hostnamectl to set hostname +Bugzilla: 1568717 +RH-Acked-by: Eduardo Otubo +RH-Acked-by: Mohammed Gamal +RH-Acked-by: Cathy Avery + +The right way to set hostname in RHEL7 is: + + $ hostnamectl set-hostname HOSTNAME + +DataSourceAzure, however, uses: + $ hostname HOSTSNAME + +instead and this causes problems. We can't simply change +'BUILTIN_DS_CONFIG' in DataSourceAzure.py as 'hostname' is being used +for both getting and setting the hostname. + +Long term, this should be fixed in a different way. Cloud-init +has distro-specific hostname setting/getting (see +cloudinit/distros/rhel.py) and DataSourceAzure.py needs to be switched +to use these. + +Resolves: rhbz#1434109 + +X-downstream-only: yes + +Signed-off-by: Vitaly Kuznetsov +Signed-off-by: Miroslav Rezanina +--- + cloudinit/sources/DataSourceAzure.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py +index 0ee622e..23b4d53 100644 +--- a/cloudinit/sources/DataSourceAzure.py ++++ b/cloudinit/sources/DataSourceAzure.py +@@ -228,7 +228,7 @@ def get_hostname(hostname_command='hostname'): + + + def set_hostname(hostname, hostname_command='hostname'): +- util.subp([hostname_command, hostname]) ++ util.subp(['hostnamectl', 'set-hostname', str(hostname)]) + + + @contextlib.contextmanager +-- +1.8.3.1 + diff --git a/SOURCES/0009-sysconfig-Don-t-disable-IPV6_AUTOCONF.patch b/SOURCES/0009-sysconfig-Don-t-disable-IPV6_AUTOCONF.patch new file mode 100644 index 0000000..6562738 --- /dev/null +++ b/SOURCES/0009-sysconfig-Don-t-disable-IPV6_AUTOCONF.patch @@ -0,0 +1,49 @@ +From 643e0ba0cf8b4a28e83c2a4db7d93ec423b24a02 Mon Sep 17 00:00:00 2001 +From: Vitaly Kuznetsov +Date: Thu, 26 Apr 2018 09:27:49 +0200 +Subject: sysconfig: Don't disable IPV6_AUTOCONF + +RH-Author: Vitaly Kuznetsov +Message-id: <20180426092749.7251-2-vkuznets@redhat.com> +Patchwork-id: 79904 +O-Subject: [RHEL7.6/7.5.z cloud-init PATCH 1/1] sysconfig: Don't disable IPV6_AUTOCONF +Bugzilla: 1578702 +RH-Acked-by: Mohammed Gamal +RH-Acked-by: Cathy Avery +RH-Acked-by: Eduardo Otubo + +Downstream-only commit 118458a3fb ("sysconfig: Don't write BOOTPROTO=dhcp +for ipv6 dhcp") did two things: +1) Disabled BOOTPROTO='dhcp' for dhcp6 setups. This change seems to be + correct as BOOTPROTO is unrelated to IPv6. The change was since merged + upstream (commit a57928d3c314d9568712cd190cb1e721e14c108b). +2) Explicitly disabled AUTOCONF and this broke many valid configurations + using it instead of DHCPV6C. Revert this part of the change. In case + DHCPV6C-only support is needed something like a new 'dhcpv6c_only' + network type needs to be suggested upstream. + +X-downstream-only: yes + +Resolves: rhbz#1558854 + +Signed-off-by: Vitaly Kuznetsov +Signed-off-by: Miroslav Rezanina +--- + cloudinit/net/sysconfig.py | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py +index f870b0f..bd81832 100644 +--- a/cloudinit/net/sysconfig.py ++++ b/cloudinit/net/sysconfig.py +@@ -286,7 +286,6 @@ class Renderer(renderer.Renderer): + if subnet_type == 'dhcp6': + iface_cfg['IPV6INIT'] = True + iface_cfg['DHCPV6C'] = True +- iface_cfg['IPV6_AUTOCONF'] = False + elif subnet_type in ['dhcp4', 'dhcp']: + iface_cfg['BOOTPROTO'] = 'dhcp' + elif subnet_type == 'static': +-- +1.8.3.1 + diff --git a/SOURCES/ci-Adding-disk_setup-to-rhel-cloud.cfg.patch b/SOURCES/ci-Adding-disk_setup-to-rhel-cloud.cfg.patch new file mode 100644 index 0000000..ebf7715 --- /dev/null +++ b/SOURCES/ci-Adding-disk_setup-to-rhel-cloud.cfg.patch @@ -0,0 +1,43 @@ +From da4d99e4d4c9b0a6992378009a402d510d99010d Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Fri, 5 Oct 2018 09:53:03 +0200 +Subject: [PATCH 4/4] Adding disk_setup to rhel/cloud.cfg + +RH-Author: Eduardo Otubo +Message-id: <20181005095303.20597-5-otubo@redhat.com> +Patchwork-id: 82387 +O-Subject: [RHEL-8.0 cloud-init PATCH 4/4] Adding disk_setup to rhel/cloud.cfg +Bugzilla: 1615599 +RH-Acked-by: Cathy Avery +RH-Acked-by: Vitaly Kuznetsov +RH-Acked-by: Miroslav Rezanina + +When Azure VM is de-allocated and started again its resource disk +needs to be re-partitioned and a RHEL supported filesystem needs to be +created on top. Include disk_setup module in the default RHEL config +which does the job. + +X-downstream-only: yes +Resolves: rhbz#1615599 + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + rhel/cloud.cfg | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg +index bb6bc4d..4a73981 100644 +--- a/rhel/cloud.cfg ++++ b/rhel/cloud.cfg +@@ -11,6 +11,7 @@ ssh_genkeytypes: ~ + syslog_fix_perms: ~ + + cloud_init_modules: ++ - disk_setup + - migrator + - bootcmd + - write-files +-- +1.8.3.1 + diff --git a/SOURCES/ci-Adding-systemd-mount-options-to-wait-for-cloud-init.patch b/SOURCES/ci-Adding-systemd-mount-options-to-wait-for-cloud-init.patch new file mode 100644 index 0000000..64d86d7 --- /dev/null +++ b/SOURCES/ci-Adding-systemd-mount-options-to-wait-for-cloud-init.patch @@ -0,0 +1,43 @@ +From 764159f648256d3e00aa2e78d2734a6fc89db9ef Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Fri, 5 Oct 2018 09:53:00 +0200 +Subject: [PATCH 1/4] Adding systemd mount options to wait for cloud-init + +RH-Author: Eduardo Otubo +Message-id: <20181005095303.20597-2-otubo@redhat.com> +Patchwork-id: 82384 +O-Subject: [RHEL-8.0 cloud-init PATCH 1/4] Adding systemd mount options to wait for cloud-init +Bugzilla: 1615599 +RH-Acked-by: Cathy Avery +RH-Acked-by: Vitaly Kuznetsov +RH-Acked-by: Miroslav Rezanina + +This patch adds systemd mount options to wait for cloud-init. On Azure, +cloud-init needs to format ephemeral disk before we are able to mount +it. + +X-downstream-only: yes +Resolves: rhbz#1615599 + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + rhel/cloud.cfg | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg +index 8644872..bb6bc4d 100644 +--- a/rhel/cloud.cfg ++++ b/rhel/cloud.cfg +@@ -4,7 +4,7 @@ users: + disable_root: 1 + ssh_pwauth: 0 + +-mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2'] ++mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service', '0', '2'] + resize_rootfs_tmp: /dev + ssh_deletekeys: 0 + ssh_genkeytypes: ~ +-- +1.8.3.1 + diff --git a/SOURCES/ci-Azure-Ignore-NTFS-mount-errors-when-checking-ephemer.patch b/SOURCES/ci-Azure-Ignore-NTFS-mount-errors-when-checking-ephemer.patch new file mode 100644 index 0000000..263014a --- /dev/null +++ b/SOURCES/ci-Azure-Ignore-NTFS-mount-errors-when-checking-ephemer.patch @@ -0,0 +1,423 @@ +From 767c4f590bd1ac6cd32c34be8cb813a2cbec08ad Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Fri, 5 Oct 2018 09:53:01 +0200 +Subject: [PATCH 2/4] Azure: Ignore NTFS mount errors when checking ephemeral + drive + +RH-Author: Eduardo Otubo +Message-id: <20181005095303.20597-3-otubo@redhat.com> +Patchwork-id: 82385 +O-Subject: [RHEL-8.0 cloud-init PATCH 2/4] Azure: Ignore NTFS mount errors when checking ephemeral drive +Bugzilla: 1615599 +RH-Acked-by: Cathy Avery +RH-Acked-by: Vitaly Kuznetsov +RH-Acked-by: Miroslav Rezanina + +commit aa4eeb80839382117e1813e396dc53aa634fd7ba +Author: Paul Meyer +Date: Wed May 23 15:45:39 2018 -0400 + + Azure: Ignore NTFS mount errors when checking ephemeral drive + + The Azure data source provides a method to check whether a NTFS partition + on the ephemeral disk is safe for reformatting to ext4. The method checks + to see if there are customer data files on the disk. However, mounting + the partition fails on systems that do not have the capability of + mounting NTFS. Note that in this case, it is also very unlikely that the + NTFS partition would have been used by the system (since it can't mount + it). The only case would be where an update to the system removed the + capability to mount NTFS, the likelihood of which is also very small. + This change allows the reformatting of the ephemeral disk to ext4 on + systems where mounting NTFS is not supported. + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + cloudinit/sources/DataSourceAzure.py | 63 ++++++++++++---- + cloudinit/util.py | 5 +- + tests/unittests/test_datasource/test_azure.py | 105 +++++++++++++++++++++----- + 3 files changed, 138 insertions(+), 35 deletions(-) + +diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py +index 23b4d53..7e49455 100644 +--- a/cloudinit/sources/DataSourceAzure.py ++++ b/cloudinit/sources/DataSourceAzure.py +@@ -214,6 +214,7 @@ BUILTIN_CLOUD_CONFIG = { + } + + DS_CFG_PATH = ['datasource', DS_NAME] ++DS_CFG_KEY_PRESERVE_NTFS = 'never_destroy_ntfs' + DEF_EPHEMERAL_LABEL = 'Temporary Storage' + + # The redacted password fails to meet password complexity requirements +@@ -400,14 +401,9 @@ class DataSourceAzure(sources.DataSource): + if found == ddir: + LOG.debug("using files cached in %s", ddir) + +- # azure / hyper-v provides random data here +- # TODO. find the seed on FreeBSD platform +- # now update ds_cfg to reflect contents pass in config +- if not util.is_FreeBSD(): +- seed = util.load_file("/sys/firmware/acpi/tables/OEM0", +- quiet=True, decode=False) +- if seed: +- self.metadata['random_seed'] = seed ++ seed = _get_random_seed() ++ if seed: ++ self.metadata['random_seed'] = seed + + user_ds_cfg = util.get_cfg_by_path(self.cfg, DS_CFG_PATH, {}) + self.ds_cfg = util.mergemanydict([user_ds_cfg, self.ds_cfg]) +@@ -537,7 +533,9 @@ class DataSourceAzure(sources.DataSource): + return fabric_data + + def activate(self, cfg, is_new_instance): +- address_ephemeral_resize(is_new_instance=is_new_instance) ++ address_ephemeral_resize(is_new_instance=is_new_instance, ++ preserve_ntfs=self.ds_cfg.get( ++ DS_CFG_KEY_PRESERVE_NTFS, False)) + return + + @property +@@ -581,17 +579,29 @@ def _has_ntfs_filesystem(devpath): + return os.path.realpath(devpath) in ntfs_devices + + +-def can_dev_be_reformatted(devpath): +- """Determine if block device devpath is newly formatted ephemeral. ++def can_dev_be_reformatted(devpath, preserve_ntfs): ++ """Determine if the ephemeral drive at devpath should be reformatted. + +- A newly formatted disk will: ++ A fresh ephemeral disk is formatted by Azure and will: + a.) have a partition table (dos or gpt) + b.) have 1 partition that is ntfs formatted, or + have 2 partitions with the second partition ntfs formatted. + (larger instances with >2TB ephemeral disk have gpt, and will + have a microsoft reserved partition as part 1. LP: #1686514) + c.) the ntfs partition will have no files other than possibly +- 'dataloss_warning_readme.txt'""" ++ 'dataloss_warning_readme.txt' ++ ++ User can indicate that NTFS should never be destroyed by setting ++ DS_CFG_KEY_PRESERVE_NTFS in dscfg. ++ If data is found on NTFS, user is warned to set DS_CFG_KEY_PRESERVE_NTFS ++ to make sure cloud-init does not accidentally wipe their data. ++ If cloud-init cannot mount the disk to check for data, destruction ++ will be allowed, unless the dscfg key is set.""" ++ if preserve_ntfs: ++ msg = ('config says to never destroy NTFS (%s.%s), skipping checks' % ++ (".".join(DS_CFG_PATH), DS_CFG_KEY_PRESERVE_NTFS)) ++ return False, msg ++ + if not os.path.exists(devpath): + return False, 'device %s does not exist' % devpath + +@@ -624,18 +634,27 @@ def can_dev_be_reformatted(devpath): + bmsg = ('partition %s (%s) on device %s was ntfs formatted' % + (cand_part, cand_path, devpath)) + try: +- file_count = util.mount_cb(cand_path, count_files) ++ file_count = util.mount_cb(cand_path, count_files, mtype="ntfs", ++ update_env_for_mount={'LANG': 'C'}) + except util.MountFailedError as e: ++ if "mount: unknown filesystem type 'ntfs'" in str(e): ++ return True, (bmsg + ' but this system cannot mount NTFS,' ++ ' assuming there are no important files.' ++ ' Formatting allowed.') + return False, bmsg + ' but mount of %s failed: %s' % (cand_part, e) + + if file_count != 0: ++ LOG.warning("it looks like you're using NTFS on the ephemeral disk, " ++ 'to ensure that filesystem does not get wiped, set ' ++ '%s.%s in config', '.'.join(DS_CFG_PATH), ++ DS_CFG_KEY_PRESERVE_NTFS) + return False, bmsg + ' but had %d files on it.' % file_count + + return True, bmsg + ' and had no important files. Safe for reformatting.' + + + def address_ephemeral_resize(devpath=RESOURCE_DISK_PATH, maxwait=120, +- is_new_instance=False): ++ is_new_instance=False, preserve_ntfs=False): + # wait for ephemeral disk to come up + naplen = .2 + missing = util.wait_for_files([devpath], maxwait=maxwait, naplen=naplen, +@@ -651,7 +670,7 @@ def address_ephemeral_resize(devpath=RESOURCE_DISK_PATH, maxwait=120, + if is_new_instance: + result, msg = (True, "First instance boot.") + else: +- result, msg = can_dev_be_reformatted(devpath) ++ result, msg = can_dev_be_reformatted(devpath, preserve_ntfs) + + LOG.debug("reformattable=%s: %s", result, msg) + if not result: +@@ -965,6 +984,18 @@ def _check_freebsd_cdrom(cdrom_dev): + return False + + ++def _get_random_seed(): ++ """Return content random seed file if available, otherwise, ++ return None.""" ++ # azure / hyper-v provides random data here ++ # TODO. find the seed on FreeBSD platform ++ # now update ds_cfg to reflect contents pass in config ++ if util.is_FreeBSD(): ++ return None ++ return util.load_file("/sys/firmware/acpi/tables/OEM0", ++ quiet=True, decode=False) ++ ++ + def list_possible_azure_ds_devs(): + devlist = [] + if util.is_FreeBSD(): +diff --git a/cloudinit/util.py b/cloudinit/util.py +index 0ab2c48..c8e14ba 100644 +--- a/cloudinit/util.py ++++ b/cloudinit/util.py +@@ -1608,7 +1608,8 @@ def mounts(): + return mounted + + +-def mount_cb(device, callback, data=None, rw=False, mtype=None, sync=True): ++def mount_cb(device, callback, data=None, rw=False, mtype=None, sync=True, ++ update_env_for_mount=None): + """ + Mount the device, call method 'callback' passing the directory + in which it was mounted, then unmount. Return whatever 'callback' +@@ -1670,7 +1671,7 @@ def mount_cb(device, callback, data=None, rw=False, mtype=None, sync=True): + mountcmd.extend(['-t', mtype]) + mountcmd.append(device) + mountcmd.append(tmpd) +- subp(mountcmd) ++ subp(mountcmd, update_env=update_env_for_mount) + umount = tmpd # This forces it to be unmounted (when set) + mountpoint = tmpd + break +diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py +index 3e8b791..af2c93a 100644 +--- a/tests/unittests/test_datasource/test_azure.py ++++ b/tests/unittests/test_datasource/test_azure.py +@@ -1,10 +1,10 @@ + # This file is part of cloud-init. See LICENSE file for license information. + + from cloudinit import helpers +-from cloudinit.util import b64e, decode_binary, load_file, write_file + from cloudinit.sources import DataSourceAzure as dsaz +-from cloudinit.util import find_freebsd_part +-from cloudinit.util import get_path_dev_freebsd ++from cloudinit.util import (b64e, decode_binary, load_file, write_file, ++ find_freebsd_part, get_path_dev_freebsd, ++ MountFailedError) + from cloudinit.version import version_string as vs + from cloudinit.tests.helpers import (CiTestCase, TestCase, populate_dir, mock, + ExitStack, PY26, SkipTest) +@@ -95,6 +95,8 @@ class TestAzureDataSource(CiTestCase): + self.patches = ExitStack() + self.addCleanup(self.patches.close) + ++ self.patches.enter_context(mock.patch.object(dsaz, '_get_random_seed')) ++ + super(TestAzureDataSource, self).setUp() + + def apply_patches(self, patches): +@@ -335,6 +337,18 @@ fdescfs /dev/fd fdescfs rw 0 0 + self.assertTrue(ret) + self.assertEqual(data['agent_invoked'], '_COMMAND') + ++ def test_sys_cfg_set_never_destroy_ntfs(self): ++ sys_cfg = {'datasource': {'Azure': { ++ 'never_destroy_ntfs': 'user-supplied-value'}}} ++ data = {'ovfcontent': construct_valid_ovf_env(data={}), ++ 'sys_cfg': sys_cfg} ++ ++ dsrc = self._get_ds(data) ++ ret = self._get_and_setup(dsrc) ++ self.assertTrue(ret) ++ self.assertEqual(dsrc.ds_cfg.get(dsaz.DS_CFG_KEY_PRESERVE_NTFS), ++ 'user-supplied-value') ++ + def test_username_used(self): + odata = {'HostName': "myhost", 'UserName': "myuser"} + data = {'ovfcontent': construct_valid_ovf_env(data=odata)} +@@ -676,6 +690,8 @@ class TestAzureBounce(CiTestCase): + mock.MagicMock(return_value={}))) + self.patches.enter_context( + mock.patch.object(dsaz.util, 'which', lambda x: True)) ++ self.patches.enter_context( ++ mock.patch.object(dsaz, '_get_random_seed')) + + def _dmi_mocks(key): + if key == 'system-uuid': +@@ -957,7 +973,9 @@ class TestCanDevBeReformatted(CiTestCase): + # return sorted by partition number + return sorted(ret, key=lambda d: d[0]) + +- def mount_cb(device, callback): ++ def mount_cb(device, callback, mtype, update_env_for_mount): ++ self.assertEqual('ntfs', mtype) ++ self.assertEqual('C', update_env_for_mount.get('LANG')) + p = self.tmp_dir() + for f in bypath.get(device).get('files', []): + write_file(os.path.join(p, f), content=f) +@@ -988,14 +1006,16 @@ class TestCanDevBeReformatted(CiTestCase): + '/dev/sda2': {'num': 2}, + '/dev/sda3': {'num': 3}, + }}}) +- value, msg = dsaz.can_dev_be_reformatted("/dev/sda") ++ value, msg = dsaz.can_dev_be_reformatted("/dev/sda", ++ preserve_ntfs=False) + self.assertFalse(value) + self.assertIn("3 or more", msg.lower()) + + def test_no_partitions_is_false(self): + """A disk with no partitions can not be formatted.""" + self.patchup({'/dev/sda': {}}) +- value, msg = dsaz.can_dev_be_reformatted("/dev/sda") ++ value, msg = dsaz.can_dev_be_reformatted("/dev/sda", ++ preserve_ntfs=False) + self.assertFalse(value) + self.assertIn("not partitioned", msg.lower()) + +@@ -1007,7 +1027,8 @@ class TestCanDevBeReformatted(CiTestCase): + '/dev/sda1': {'num': 1}, + '/dev/sda2': {'num': 2, 'fs': 'ext4', 'files': []}, + }}}) +- value, msg = dsaz.can_dev_be_reformatted("/dev/sda") ++ value, msg = dsaz.can_dev_be_reformatted("/dev/sda", ++ preserve_ntfs=False) + self.assertFalse(value) + self.assertIn("not ntfs", msg.lower()) + +@@ -1020,7 +1041,8 @@ class TestCanDevBeReformatted(CiTestCase): + '/dev/sda2': {'num': 2, 'fs': 'ntfs', + 'files': ['secret.txt']}, + }}}) +- value, msg = dsaz.can_dev_be_reformatted("/dev/sda") ++ value, msg = dsaz.can_dev_be_reformatted("/dev/sda", ++ preserve_ntfs=False) + self.assertFalse(value) + self.assertIn("files on it", msg.lower()) + +@@ -1032,7 +1054,8 @@ class TestCanDevBeReformatted(CiTestCase): + '/dev/sda1': {'num': 1}, + '/dev/sda2': {'num': 2, 'fs': 'ntfs', 'files': []}, + }}}) +- value, msg = dsaz.can_dev_be_reformatted("/dev/sda") ++ value, msg = dsaz.can_dev_be_reformatted("/dev/sda", ++ preserve_ntfs=False) + self.assertTrue(value) + self.assertIn("safe for", msg.lower()) + +@@ -1043,7 +1066,8 @@ class TestCanDevBeReformatted(CiTestCase): + 'partitions': { + '/dev/sda1': {'num': 1, 'fs': 'zfs'}, + }}}) +- value, msg = dsaz.can_dev_be_reformatted("/dev/sda") ++ value, msg = dsaz.can_dev_be_reformatted("/dev/sda", ++ preserve_ntfs=False) + self.assertFalse(value) + self.assertIn("not ntfs", msg.lower()) + +@@ -1055,9 +1079,14 @@ class TestCanDevBeReformatted(CiTestCase): + '/dev/sda1': {'num': 1, 'fs': 'ntfs', + 'files': ['file1.txt', 'file2.exe']}, + }}}) +- value, msg = dsaz.can_dev_be_reformatted("/dev/sda") +- self.assertFalse(value) +- self.assertIn("files on it", msg.lower()) ++ with mock.patch.object(dsaz.LOG, 'warning') as warning: ++ value, msg = dsaz.can_dev_be_reformatted("/dev/sda", ++ preserve_ntfs=False) ++ wmsg = warning.call_args[0][0] ++ self.assertIn("looks like you're using NTFS on the ephemeral disk", ++ wmsg) ++ self.assertFalse(value) ++ self.assertIn("files on it", msg.lower()) + + def test_one_partition_ntfs_empty_is_true(self): + """1 mountable ntfs partition and no files can be formatted.""" +@@ -1066,7 +1095,8 @@ class TestCanDevBeReformatted(CiTestCase): + 'partitions': { + '/dev/sda1': {'num': 1, 'fs': 'ntfs', 'files': []} + }}}) +- value, msg = dsaz.can_dev_be_reformatted("/dev/sda") ++ value, msg = dsaz.can_dev_be_reformatted("/dev/sda", ++ preserve_ntfs=False) + self.assertTrue(value) + self.assertIn("safe for", msg.lower()) + +@@ -1078,7 +1108,8 @@ class TestCanDevBeReformatted(CiTestCase): + '/dev/sda1': {'num': 1, 'fs': 'ntfs', + 'files': ['dataloss_warning_readme.txt']} + }}}) +- value, msg = dsaz.can_dev_be_reformatted("/dev/sda") ++ value, msg = dsaz.can_dev_be_reformatted("/dev/sda", ++ preserve_ntfs=False) + self.assertTrue(value) + self.assertIn("safe for", msg.lower()) + +@@ -1093,7 +1124,8 @@ class TestCanDevBeReformatted(CiTestCase): + 'num': 1, 'fs': 'ntfs', 'files': [self.warning_file], + 'realpath': '/dev/sdb1'} + }}}) +- value, msg = dsaz.can_dev_be_reformatted(epath) ++ value, msg = dsaz.can_dev_be_reformatted(epath, ++ preserve_ntfs=False) + self.assertTrue(value) + self.assertIn("safe for", msg.lower()) + +@@ -1112,10 +1144,49 @@ class TestCanDevBeReformatted(CiTestCase): + epath + '-part3': {'num': 3, 'fs': 'ext', + 'realpath': '/dev/sdb3'} + }}}) +- value, msg = dsaz.can_dev_be_reformatted(epath) ++ value, msg = dsaz.can_dev_be_reformatted(epath, ++ preserve_ntfs=False) + self.assertFalse(value) + self.assertIn("3 or more", msg.lower()) + ++ def test_ntfs_mount_errors_true(self): ++ """can_dev_be_reformatted does not fail if NTFS is unknown fstype.""" ++ self.patchup({ ++ '/dev/sda': { ++ 'partitions': { ++ '/dev/sda1': {'num': 1, 'fs': 'ntfs', 'files': []} ++ }}}) ++ ++ err = ("Unexpected error while running command.\n", ++ "Command: ['mount', '-o', 'ro,sync', '-t', 'auto', ", ++ "'/dev/sda1', '/fake-tmp/dir']\n" ++ "Exit code: 32\n" ++ "Reason: -\n" ++ "Stdout: -\n" ++ "Stderr: mount: unknown filesystem type 'ntfs'") ++ self.m_mount_cb.side_effect = MountFailedError( ++ 'Failed mounting %s to %s due to: %s' % ++ ('/dev/sda', '/fake-tmp/dir', err)) ++ ++ value, msg = dsaz.can_dev_be_reformatted('/dev/sda', ++ preserve_ntfs=False) ++ self.assertTrue(value) ++ self.assertIn('cannot mount NTFS, assuming', msg) ++ ++ def test_never_destroy_ntfs_config_false(self): ++ """Normally formattable situation with never_destroy_ntfs set.""" ++ self.patchup({ ++ '/dev/sda': { ++ 'partitions': { ++ '/dev/sda1': {'num': 1, 'fs': 'ntfs', ++ 'files': ['dataloss_warning_readme.txt']} ++ }}}) ++ value, msg = dsaz.can_dev_be_reformatted("/dev/sda", ++ preserve_ntfs=True) ++ self.assertFalse(value) ++ self.assertIn("config says to never destroy NTFS " ++ "(datasource.Azure.never_destroy_ntfs)", msg) ++ + + class TestAzureNetExists(CiTestCase): + +-- +1.8.3.1 + diff --git a/SOURCES/ci-Enable-cloud-init-by-default-on-vmware.patch b/SOURCES/ci-Enable-cloud-init-by-default-on-vmware.patch new file mode 100644 index 0000000..00edc76 --- /dev/null +++ b/SOURCES/ci-Enable-cloud-init-by-default-on-vmware.patch @@ -0,0 +1,45 @@ +From f5c6832cede618d83c2a3844287922fa2874521d Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Mon, 17 Dec 2018 11:27:29 +0100 +Subject: [PATCH] Enable cloud-init by default on vmware + +RH-Author: Eduardo Otubo +Message-id: <20181217112729.16625-1-otubo@redhat.com> +Patchwork-id: 83538 +O-Subject: [RHEL-8.0 cloud-init PATCH] Enable cloud-init by default on vmware +Bugzilla: 1644335 +RH-Acked-by: Vitaly Kuznetsov +RH-Acked-by: Miroslav Rezanina + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1644335 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=19536284 +Tested: By me + +According to BZ#1644335, the variable `disable_vmware_customization' +should be set to `false' in order to enable cloud-init by default on +VMware. This patch sets it accordingly. + +X-downstream-only: yes +Resolves: rhbz#1644335 + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + rhel/cloud.cfg | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg +index 4a73981d..f0db3c12 100644 +--- a/rhel/cloud.cfg ++++ b/rhel/cloud.cfg +@@ -9,6 +9,7 @@ resize_rootfs_tmp: /dev + ssh_deletekeys: 0 + ssh_genkeytypes: ~ + syslog_fix_perms: ~ ++disable_vmware_customization: false + + cloud_init_modules: + - disk_setup +-- +2.19.1 + diff --git a/SOURCES/ci-Fix-string-missmatch-when-mounting-ntfs.patch b/SOURCES/ci-Fix-string-missmatch-when-mounting-ntfs.patch new file mode 100644 index 0000000..1e6b8ba --- /dev/null +++ b/SOURCES/ci-Fix-string-missmatch-when-mounting-ntfs.patch @@ -0,0 +1,41 @@ +From f502ab105bca61613a4ff83aa5ea373bc00bb4e9 Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Thu, 10 Jan 2019 10:03:14 +0100 +Subject: [PATCH] Fix string missmatch when mounting ntfs + +RH-Author: Eduardo Otubo +Message-id: <20190110100314.32713-1-otubo@redhat.com> +Patchwork-id: 83943 +O-Subject: [RHEL-8.0 cloud-init PATCH] Fix string missmatch when mounting ntfs +Bugzilla: 1664227 +RH-Acked-by: Vitaly Kuznetsov +RH-Acked-by: Mohammed Gamal + +This patch fixes a simple string missmatch when attempting to mount ntfs +partitions. + +X-downstream-only: yes +Resolves: rhbz#1664227 + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + cloudinit/sources/DataSourceAzure.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py +index 46d57446..61d374a7 100644 +--- a/cloudinit/sources/DataSourceAzure.py ++++ b/cloudinit/sources/DataSourceAzure.py +@@ -646,7 +646,7 @@ def can_dev_be_reformatted(devpath, preserve_ntfs): + file_count = util.mount_cb(cand_path, count_files, mtype="ntfs", + update_env_for_mount={'LANG': 'C'}) + except util.MountFailedError as e: +- if "mount: unknown filesystem type 'ntfs'" in str(e): ++ if "unknown filesystem type 'ntfs'" in str(e): + return True, (bmsg + ' but this system cannot mount NTFS,' + ' assuming there are no important files.' + ' Formatting allowed.') +-- +2.19.1 + diff --git a/SOURCES/ci-azure-Add-reported-ready-marker-file.patch b/SOURCES/ci-azure-Add-reported-ready-marker-file.patch new file mode 100644 index 0000000..fb83c6e --- /dev/null +++ b/SOURCES/ci-azure-Add-reported-ready-marker-file.patch @@ -0,0 +1,330 @@ +From b03bfae6c032a2590e094e9bceeedd47525ca057 Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Fri, 5 Oct 2018 09:53:02 +0200 +Subject: [PATCH 3/4] azure: Add reported ready marker file. + +RH-Author: Eduardo Otubo +Message-id: <20181005095303.20597-4-otubo@redhat.com> +Patchwork-id: 82386 +O-Subject: [RHEL-8.0 cloud-init PATCH 3/4] azure: Add reported ready marker file. +Bugzilla: 1615599 +RH-Acked-by: Cathy Avery +RH-Acked-by: Vitaly Kuznetsov +RH-Acked-by: Miroslav Rezanina + +commit aae494c39f4c6f625e7409ca262e657d085dd5d1 +Author: Joshua Chan +Date: Thu May 3 14:50:16 2018 -0600 + + azure: Add reported ready marker file. + + This change is for Azure VM Preprovisioning. A bug was found when after + azure VMs report ready the first time, during the time when VM is polling + indefinitely for the new ovf-env.xml from Instance Metadata Service + (IMDS), if a reboot happens, we send another report ready signal to the + fabric, which deletes the reprovisioning data on the node. + + This marker file is used to fix this issue so that we will only send a + report ready signal to the fabric when no marker file is present. Then, + create a marker file so that when a reboot does occur, we check if a + marker file has been created and decide whether we would like to send the + repot ready signal. + + LP: #1765214 + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + cloudinit/sources/DataSourceAzure.py | 21 +++- + tests/unittests/test_datasource/test_azure.py | 170 ++++++++++++++++++-------- + 2 files changed, 134 insertions(+), 57 deletions(-) + +diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py +index 7e49455..46d5744 100644 +--- a/cloudinit/sources/DataSourceAzure.py ++++ b/cloudinit/sources/DataSourceAzure.py +@@ -48,6 +48,7 @@ DEFAULT_FS = 'ext4' + # DMI chassis-asset-tag is set static for all azure instances + AZURE_CHASSIS_ASSET_TAG = '7783-7084-3265-9085-8269-3286-77' + REPROVISION_MARKER_FILE = "/var/lib/cloud/data/poll_imds" ++REPORTED_READY_MARKER_FILE = "/var/lib/cloud/data/reported_ready" + IMDS_URL = "http://169.254.169.254/metadata/reprovisiondata" + + +@@ -439,11 +440,12 @@ class DataSourceAzure(sources.DataSource): + LOG.debug("negotiating already done for %s", + self.get_instance_id()) + +- def _poll_imds(self, report_ready=True): ++ def _poll_imds(self): + """Poll IMDS for the new provisioning data until we get a valid + response. Then return the returned JSON object.""" + url = IMDS_URL + "?api-version=2017-04-02" + headers = {"Metadata": "true"} ++ report_ready = bool(not os.path.isfile(REPORTED_READY_MARKER_FILE)) + LOG.debug("Start polling IMDS") + + def exc_cb(msg, exception): +@@ -453,13 +455,17 @@ class DataSourceAzure(sources.DataSource): + # call DHCP and setup the ephemeral network to acquire the new IP. + return False + +- need_report = report_ready + while True: + try: + with EphemeralDHCPv4() as lease: +- if need_report: ++ if report_ready: ++ path = REPORTED_READY_MARKER_FILE ++ LOG.info( ++ "Creating a marker file to report ready: %s", path) ++ util.write_file(path, "{pid}: {time}\n".format( ++ pid=os.getpid(), time=time())) + self._report_ready(lease=lease) +- need_report = False ++ report_ready = False + return readurl(url, timeout=1, headers=headers, + exception_cb=exc_cb, infinite=True).contents + except UrlError: +@@ -493,8 +499,10 @@ class DataSourceAzure(sources.DataSource): + if (cfg.get('PreprovisionedVm') is True or + os.path.isfile(path)): + if not os.path.isfile(path): +- LOG.info("Creating a marker file to poll imds") +- util.write_file(path, "%s: %s\n" % (os.getpid(), time())) ++ LOG.info("Creating a marker file to poll imds: %s", ++ path) ++ util.write_file(path, "{pid}: {time}\n".format( ++ pid=os.getpid(), time=time())) + return True + return False + +@@ -529,6 +537,7 @@ class DataSourceAzure(sources.DataSource): + "Error communicating with Azure fabric; You may experience." + "connectivity issues.", exc_info=True) + return False ++ util.del_file(REPORTED_READY_MARKER_FILE) + util.del_file(REPROVISION_MARKER_FILE) + return fabric_data + +diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py +index af2c93a..ed810d2 100644 +--- a/tests/unittests/test_datasource/test_azure.py ++++ b/tests/unittests/test_datasource/test_azure.py +@@ -1196,19 +1196,9 @@ class TestAzureNetExists(CiTestCase): + self.assertTrue(hasattr(dsaz, "DataSourceAzureNet")) + + +-@mock.patch('cloudinit.sources.DataSourceAzure.util.subp') +-@mock.patch.object(dsaz, 'get_hostname') +-@mock.patch.object(dsaz, 'set_hostname') +-class TestAzureDataSourcePreprovisioning(CiTestCase): +- +- def setUp(self): +- super(TestAzureDataSourcePreprovisioning, self).setUp() +- tmp = self.tmp_dir() +- self.waagent_d = self.tmp_path('/var/lib/waagent', tmp) +- self.paths = helpers.Paths({'cloud_dir': tmp}) +- dsaz.BUILTIN_DS_CONFIG['data_dir'] = self.waagent_d ++class TestPreprovisioningReadAzureOvfFlag(CiTestCase): + +- def test_read_azure_ovf_with_true_flag(self, *args): ++ def test_read_azure_ovf_with_true_flag(self): + """The read_azure_ovf method should set the PreprovisionedVM + cfg flag if the proper setting is present.""" + content = construct_valid_ovf_env( +@@ -1217,7 +1207,7 @@ class TestAzureDataSourcePreprovisioning(CiTestCase): + cfg = ret[2] + self.assertTrue(cfg['PreprovisionedVm']) + +- def test_read_azure_ovf_with_false_flag(self, *args): ++ def test_read_azure_ovf_with_false_flag(self): + """The read_azure_ovf method should set the PreprovisionedVM + cfg flag to false if the proper setting is false.""" + content = construct_valid_ovf_env( +@@ -1226,7 +1216,7 @@ class TestAzureDataSourcePreprovisioning(CiTestCase): + cfg = ret[2] + self.assertFalse(cfg['PreprovisionedVm']) + +- def test_read_azure_ovf_without_flag(self, *args): ++ def test_read_azure_ovf_without_flag(self): + """The read_azure_ovf method should not set the + PreprovisionedVM cfg flag.""" + content = construct_valid_ovf_env() +@@ -1234,12 +1224,121 @@ class TestAzureDataSourcePreprovisioning(CiTestCase): + cfg = ret[2] + self.assertFalse(cfg['PreprovisionedVm']) + +- @mock.patch('cloudinit.sources.DataSourceAzure.util.is_FreeBSD') +- @mock.patch('cloudinit.net.dhcp.EphemeralIPv4Network') +- @mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery') +- @mock.patch('requests.Session.request') ++ ++@mock.patch('os.path.isfile') ++class TestPreprovisioningShouldReprovision(CiTestCase): ++ ++ def setUp(self): ++ super(TestPreprovisioningShouldReprovision, self).setUp() ++ tmp = self.tmp_dir() ++ self.waagent_d = self.tmp_path('/var/lib/waagent', tmp) ++ self.paths = helpers.Paths({'cloud_dir': tmp}) ++ dsaz.BUILTIN_DS_CONFIG['data_dir'] = self.waagent_d ++ ++ @mock.patch('cloudinit.sources.DataSourceAzure.util.write_file') ++ def test__should_reprovision_with_true_cfg(self, isfile, write_f): ++ """The _should_reprovision method should return true with config ++ flag present.""" ++ isfile.return_value = False ++ dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) ++ self.assertTrue(dsa._should_reprovision( ++ (None, None, {'PreprovisionedVm': True}, None))) ++ ++ def test__should_reprovision_with_file_existing(self, isfile): ++ """The _should_reprovision method should return True if the sentinal ++ exists.""" ++ isfile.return_value = True ++ dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) ++ self.assertTrue(dsa._should_reprovision( ++ (None, None, {'preprovisionedvm': False}, None))) ++ ++ def test__should_reprovision_returns_false(self, isfile): ++ """The _should_reprovision method should return False ++ if config and sentinal are not present.""" ++ isfile.return_value = False ++ dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) ++ self.assertFalse(dsa._should_reprovision((None, None, {}, None))) ++ ++ @mock.patch('cloudinit.sources.DataSourceAzure.DataSourceAzure._poll_imds') ++ def test_reprovision_calls__poll_imds(self, _poll_imds, isfile): ++ """_reprovision will poll IMDS.""" ++ isfile.return_value = False ++ hostname = "myhost" ++ username = "myuser" ++ odata = {'HostName': hostname, 'UserName': username} ++ _poll_imds.return_value = construct_valid_ovf_env(data=odata) ++ dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) ++ dsa._reprovision() ++ _poll_imds.assert_called_with() ++ ++ ++@mock.patch('cloudinit.net.dhcp.EphemeralIPv4Network') ++@mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery') ++@mock.patch('requests.Session.request') ++@mock.patch( ++ 'cloudinit.sources.DataSourceAzure.DataSourceAzure._report_ready') ++class TestPreprovisioningPollIMDS(CiTestCase): ++ ++ def setUp(self): ++ super(TestPreprovisioningPollIMDS, self).setUp() ++ self.tmp = self.tmp_dir() ++ self.waagent_d = self.tmp_path('/var/lib/waagent', self.tmp) ++ self.paths = helpers.Paths({'cloud_dir': self.tmp}) ++ dsaz.BUILTIN_DS_CONFIG['data_dir'] = self.waagent_d ++ ++ @mock.patch('cloudinit.sources.DataSourceAzure.util.write_file') ++ def test_poll_imds_calls_report_ready(self, write_f, report_ready_func, ++ fake_resp, m_dhcp, m_net): ++ """The poll_imds will call report_ready after creating marker file.""" ++ report_marker = self.tmp_path('report_marker', self.tmp) ++ lease = { ++ 'interface': 'eth9', 'fixed-address': '192.168.2.9', ++ 'routers': '192.168.2.1', 'subnet-mask': '255.255.255.0', ++ 'unknown-245': '624c3620'} ++ m_dhcp.return_value = [lease] ++ dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) ++ mock_path = ( ++ 'cloudinit.sources.DataSourceAzure.REPORTED_READY_MARKER_FILE') ++ with mock.patch(mock_path, report_marker): ++ dsa._poll_imds() ++ self.assertEqual(report_ready_func.call_count, 1) ++ report_ready_func.assert_called_with(lease=lease) ++ ++ def test_poll_imds_report_ready_false(self, report_ready_func, ++ fake_resp, m_dhcp, m_net): ++ """The poll_imds should not call reporting ready ++ when flag is false""" ++ report_marker = self.tmp_path('report_marker', self.tmp) ++ write_file(report_marker, content='dont run report_ready :)') ++ m_dhcp.return_value = [{ ++ 'interface': 'eth9', 'fixed-address': '192.168.2.9', ++ 'routers': '192.168.2.1', 'subnet-mask': '255.255.255.0', ++ 'unknown-245': '624c3620'}] ++ dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) ++ mock_path = ( ++ 'cloudinit.sources.DataSourceAzure.REPORTED_READY_MARKER_FILE') ++ with mock.patch(mock_path, report_marker): ++ dsa._poll_imds() ++ self.assertEqual(report_ready_func.call_count, 0) ++ ++ ++@mock.patch('cloudinit.sources.DataSourceAzure.util.subp') ++@mock.patch('cloudinit.sources.DataSourceAzure.util.write_file') ++@mock.patch('cloudinit.sources.DataSourceAzure.util.is_FreeBSD') ++@mock.patch('cloudinit.net.dhcp.EphemeralIPv4Network') ++@mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery') ++@mock.patch('requests.Session.request') ++class TestAzureDataSourcePreprovisioning(CiTestCase): ++ ++ def setUp(self): ++ super(TestAzureDataSourcePreprovisioning, self).setUp() ++ tmp = self.tmp_dir() ++ self.waagent_d = self.tmp_path('/var/lib/waagent', tmp) ++ self.paths = helpers.Paths({'cloud_dir': tmp}) ++ dsaz.BUILTIN_DS_CONFIG['data_dir'] = self.waagent_d ++ + def test_poll_imds_returns_ovf_env(self, fake_resp, m_dhcp, m_net, +- m_is_bsd, *args): ++ m_is_bsd, write_f, subp): + """The _poll_imds method should return the ovf_env.xml.""" + m_is_bsd.return_value = False + m_dhcp.return_value = [{ +@@ -1265,12 +1364,8 @@ class TestAzureDataSourcePreprovisioning(CiTestCase): + prefix_or_mask='255.255.255.0', router='192.168.2.1') + self.assertEqual(m_net.call_count, 1) + +- @mock.patch('cloudinit.sources.DataSourceAzure.util.is_FreeBSD') +- @mock.patch('cloudinit.net.dhcp.EphemeralIPv4Network') +- @mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery') +- @mock.patch('requests.Session.request') + def test__reprovision_calls__poll_imds(self, fake_resp, m_dhcp, m_net, +- m_is_bsd, *args): ++ m_is_bsd, write_f, subp): + """The _reprovision method should call poll IMDS.""" + m_is_bsd.return_value = False + m_dhcp.return_value = [{ +@@ -1302,32 +1397,5 @@ class TestAzureDataSourcePreprovisioning(CiTestCase): + prefix_or_mask='255.255.255.0', router='192.168.2.1') + self.assertEqual(m_net.call_count, 1) + +- @mock.patch('cloudinit.sources.DataSourceAzure.util.write_file') +- @mock.patch('os.path.isfile') +- def test__should_reprovision_with_true_cfg(self, isfile, write_f, *args): +- """The _should_reprovision method should return true with config +- flag present.""" +- isfile.return_value = False +- dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) +- self.assertTrue(dsa._should_reprovision( +- (None, None, {'PreprovisionedVm': True}, None))) +- +- @mock.patch('os.path.isfile') +- def test__should_reprovision_with_file_existing(self, isfile, *args): +- """The _should_reprovision method should return True if the sentinal +- exists.""" +- isfile.return_value = True +- dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) +- self.assertTrue(dsa._should_reprovision( +- (None, None, {'preprovisionedvm': False}, None))) +- +- @mock.patch('os.path.isfile') +- def test__should_reprovision_returns_false(self, isfile, *args): +- """The _should_reprovision method should return False +- if config and sentinal are not present.""" +- isfile.return_value = False +- dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) +- self.assertFalse(dsa._should_reprovision((None, None, {}, None))) +- + + # vi: ts=4 expandtab +-- +1.8.3.1 + diff --git a/SOURCES/ci-net-Make-sysconfig-renderer-compatible-with-Network-.patch b/SOURCES/ci-net-Make-sysconfig-renderer-compatible-with-Network-.patch new file mode 100644 index 0000000..114366c --- /dev/null +++ b/SOURCES/ci-net-Make-sysconfig-renderer-compatible-with-Network-.patch @@ -0,0 +1,216 @@ +From 09b873ca69821ac2a3e306da0af0437b849d1dd8 Mon Sep 17 00:00:00 2001 +From: Eduardo Otubo +Date: Fri, 18 Jan 2019 16:55:36 +0100 +Subject: [PATCH] net: Make sysconfig renderer compatible with Network Manager. + +RH-Author: Eduardo Otubo +Message-id: <20190118165536.25963-1-otubo@redhat.com> +Patchwork-id: 84052 +O-Subject: [RHEL-8.0 cloud-init PATCH] net: Make sysconfig renderer compatible with Network Manager. +Bugzilla: 1602784 +RH-Acked-by: Vitaly Kuznetsov +RH-Acked-by: Mohammed Gamal + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1602784 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=19877292 +Tested by: upstream maintainers and me + +commit 3861102fcaf47a882516d8b6daab518308eb3086 +Author: Eduardo Otubo +Date: Fri Jan 18 15:36:19 2019 +0000 + + net: Make sysconfig renderer compatible with Network Manager. + + The 'sysconfig' renderer is activated if, and only if, there's ifup and + ifdown commands present in its search dictonary or the network-scripts + configuration files are found. This patch adds a check for Network- + Manager configuration file as well. + + This solution is based on the use of the plugin 'ifcfg-rh' present in + Network-Manager and is designed to support Fedora 29 or other + distributions that also replaced network-scripts by Network-Manager. + +Signed-off-by: Eduardo Otubo +Signed-off-by: Miroslav Rezanina +--- + cloudinit/net/sysconfig.py | 36 +++++++++++++++++++++++ + tests/unittests/test_net.py | 71 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 107 insertions(+) + +diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py +index bd81832..42291aa 100644 +--- a/cloudinit/net/sysconfig.py ++++ b/cloudinit/net/sysconfig.py +@@ -10,11 +10,14 @@ from cloudinit.distros.parsers import resolv_conf + from cloudinit import log as logging + from cloudinit import util + ++from configobj import ConfigObj ++ + from . import renderer + from .network_state import ( + is_ipv6_addr, net_prefix_to_ipv4_mask, subnet_is_ipv6) + + LOG = logging.getLogger(__name__) ++NM_CFG_FILE = "/etc/NetworkManager/NetworkManager.conf" + + + def _make_header(sep='#'): +@@ -46,6 +49,24 @@ def _quote_value(value): + return value + + ++def enable_ifcfg_rh(path): ++ """Add ifcfg-rh to NetworkManager.cfg plugins if main section is present""" ++ config = ConfigObj(path) ++ if 'main' in config: ++ if 'plugins' in config['main']: ++ if 'ifcfg-rh' in config['main']['plugins']: ++ return ++ else: ++ config['main']['plugins'] = [] ++ ++ if isinstance(config['main']['plugins'], list): ++ config['main']['plugins'].append('ifcfg-rh') ++ else: ++ config['main']['plugins'] = [config['main']['plugins'], 'ifcfg-rh'] ++ config.write() ++ LOG.debug('Enabled ifcfg-rh NetworkManager plugins') ++ ++ + class ConfigMap(object): + """Sysconfig like dictionary object.""" + +@@ -597,6 +618,8 @@ class Renderer(renderer.Renderer): + netrules_content = self._render_persistent_net(network_state) + netrules_path = util.target_path(target, self.netrules_path) + util.write_file(netrules_path, netrules_content, file_mode) ++ if available_nm(target=target): ++ enable_ifcfg_rh(util.target_path(target, path=NM_CFG_FILE)) + + # always write /etc/sysconfig/network configuration + sysconfig_path = util.target_path(target, "etc/sysconfig/network") +@@ -608,6 +631,13 @@ class Renderer(renderer.Renderer): + + + def available(target=None): ++ sysconfig = available_sysconfig(target=target) ++ nm = available_nm(target=target) ++ ++ return any([nm, sysconfig]) ++ ++ ++def available_sysconfig(target=None): + expected = ['ifup', 'ifdown'] + search = ['/sbin', '/usr/sbin'] + for p in expected: +@@ -623,4 +653,10 @@ def available(target=None): + return True + + ++def available_nm(target=None): ++ if not os.path.isfile(util.target_path(target, path=NM_CFG_FILE)): ++ return False ++ return True ++ ++ + # vi: ts=4 expandtab +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index 9cf41bc..8e520f6 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -24,6 +24,7 @@ import os + import textwrap + import yaml + ++ + DHCP_CONTENT_1 = """ + DEVICE='eth0' + PROTO='dhcp' +@@ -1542,6 +1543,7 @@ iface eth1 inet dhcp + + class TestSysConfigRendering(CiTestCase): + ++ nm_cfg_file = "/etc/NetworkManager/NetworkManager.conf" + scripts_dir = '/etc/sysconfig/network-scripts' + header = ('# Created by cloud-init on instance boot automatically, ' + 'do not edit.\n#\n') +@@ -1853,6 +1855,75 @@ iface eth0 inet dhcp + self.assertEqual( + expected, dir2dict(tmp_dir)['/etc/network/interfaces']) + ++ def test_check_ifcfg_rh(self): ++ """ifcfg-rh plugin is added NetworkManager.conf if conf present.""" ++ render_dir = self.tmp_dir() ++ nm_cfg = util.target_path(render_dir, path=self.nm_cfg_file) ++ util.ensure_dir(os.path.dirname(nm_cfg)) ++ ++ # write a template nm.conf, note plugins is a list here ++ with open(nm_cfg, 'w') as fh: ++ fh.write('# test_check_ifcfg_rh\n[main]\nplugins=foo,bar\n') ++ self.assertTrue(os.path.exists(nm_cfg)) ++ ++ # render and read ++ entry = NETWORK_CONFIGS['small'] ++ found = self._render_and_read(network_config=yaml.load(entry['yaml']), ++ dir=render_dir) ++ self._compare_files_to_expected(entry[self.expected_name], found) ++ self._assert_headers(found) ++ ++ # check ifcfg-rh is in the 'plugins' list ++ config = sysconfig.ConfigObj(nm_cfg) ++ self.assertIn('ifcfg-rh', config['main']['plugins']) ++ ++ def test_check_ifcfg_rh_plugins_string(self): ++ """ifcfg-rh plugin is append when plugins is a string.""" ++ render_dir = self.tmp_path("render") ++ os.makedirs(render_dir) ++ nm_cfg = util.target_path(render_dir, path=self.nm_cfg_file) ++ util.ensure_dir(os.path.dirname(nm_cfg)) ++ ++ # write a template nm.conf, note plugins is a value here ++ util.write_file(nm_cfg, '# test_check_ifcfg_rh\n[main]\nplugins=foo\n') ++ ++ # render and read ++ entry = NETWORK_CONFIGS['small'] ++ found = self._render_and_read(network_config=yaml.load(entry['yaml']), ++ dir=render_dir) ++ self._compare_files_to_expected(entry[self.expected_name], found) ++ self._assert_headers(found) ++ ++ # check raw content has plugin ++ nm_file_content = util.load_file(nm_cfg) ++ self.assertIn('ifcfg-rh', nm_file_content) ++ ++ # check ifcfg-rh is in the 'plugins' list ++ config = sysconfig.ConfigObj(nm_cfg) ++ self.assertIn('ifcfg-rh', config['main']['plugins']) ++ ++ def test_check_ifcfg_rh_plugins_no_plugins(self): ++ """enable_ifcfg_plugin creates plugins value if missing.""" ++ render_dir = self.tmp_path("render") ++ os.makedirs(render_dir) ++ nm_cfg = util.target_path(render_dir, path=self.nm_cfg_file) ++ util.ensure_dir(os.path.dirname(nm_cfg)) ++ ++ # write a template nm.conf, note plugins is missing ++ util.write_file(nm_cfg, '# test_check_ifcfg_rh\n[main]\n') ++ self.assertTrue(os.path.exists(nm_cfg)) ++ ++ # render and read ++ entry = NETWORK_CONFIGS['small'] ++ found = self._render_and_read(network_config=yaml.load(entry['yaml']), ++ dir=render_dir) ++ self._compare_files_to_expected(entry[self.expected_name], found) ++ self._assert_headers(found) ++ ++ # check ifcfg-rh is in the 'plugins' list ++ config = sysconfig.ConfigObj(nm_cfg) ++ self.assertIn('ifcfg-rh', config['main']['plugins']) ++ + + class TestNetplanNetRendering(CiTestCase): + +-- +1.8.3.1 + diff --git a/SOURCES/cloud-init-tmpfiles.conf b/SOURCES/cloud-init-tmpfiles.conf new file mode 100644 index 0000000..0c6d2a3 --- /dev/null +++ b/SOURCES/cloud-init-tmpfiles.conf @@ -0,0 +1 @@ +d /run/cloud-init 0700 root root - - diff --git a/SPECS/cloud-init.spec b/SPECS/cloud-init.spec new file mode 100644 index 0000000..60bf175 --- /dev/null +++ b/SPECS/cloud-init.spec @@ -0,0 +1,371 @@ +%{!?license: %global license %%doc} + +# The only reason we are archful is because dmidecode is ExclusiveArch +# https://bugzilla.redhat.com/show_bug.cgi?id=1067089 +%global debug_package %{nil} + +Name: cloud-init +Version: 18.2 +Release: 6%{?dist} +Summary: Cloud instance init scripts + +Group: System Environment/Base +License: GPLv3 +URL: http://launchpad.net/cloud-init +Source0: https://launchpad.net/cloud-init/trunk/%{version}/+download/%{name}-%{version}.tar.gz +Source1: cloud-init-tmpfiles.conf + +Patch0001: 0001-Add-initial-redhat-setup.patch +Patch0002: 0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch +Patch0003: 0003-limit-permissions-on-def_log_file.patch +Patch0005: 0005-add-power-state-change-module-to-cloud_final_modules.patch +Patch0006: 0006-azure-ensure-that-networkmanager-hook-script-runs.patch +Patch0007: 0007-sysconfig-Don-t-write-BOOTPROTO-dhcp-for-ipv6-dhcp.patch +Patch0008: 0008-DataSourceAzure.py-use-hostnamectl-to-set-hostname.patch +Patch0009: 0009-sysconfig-Don-t-disable-IPV6_AUTOCONF.patch +# For bz#1615599 - [Azure] cloud-init fails to mount /dev/sdb1 after stop(deallocate)&&start VM +Patch10: ci-Adding-systemd-mount-options-to-wait-for-cloud-init.patch +# For bz#1615599 - [Azure] cloud-init fails to mount /dev/sdb1 after stop(deallocate)&&start VM +Patch11: ci-Azure-Ignore-NTFS-mount-errors-when-checking-ephemer.patch +# For bz#1615599 - [Azure] cloud-init fails to mount /dev/sdb1 after stop(deallocate)&&start VM +Patch12: ci-azure-Add-reported-ready-marker-file.patch +# For bz#1615599 - [Azure] cloud-init fails to mount /dev/sdb1 after stop(deallocate)&&start VM +Patch13: ci-Adding-disk_setup-to-rhel-cloud.cfg.patch +# For bz#1644335 - [ESXi][RHEL8.0]Enable cloud-init by default on VMware +Patch14: ci-Enable-cloud-init-by-default-on-vmware.patch +# For bz#1664227 - [Azure]String missmatch causes the /dev/sdb1 mounting failed after stop&start VM +Patch15: ci-Fix-string-missmatch-when-mounting-ntfs.patch +# For bz#1602784 - cloud-init: Sometimes image boots fingerprints is configured, there's a network device present but it's not configured +Patch16: ci-net-Make-sysconfig-renderer-compatible-with-Network-.patch + +BuildArch: noarch + +BuildRequires: pkgconfig(systemd) +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: systemd + +# For tests +BuildRequires: iproute +BuildRequires: python3-configobj +# # https://bugzilla.redhat.com/show_bug.cgi?id=1417029 +BuildRequires: python3-httpretty >= 0.8.14-2 +BuildRequires: python3-jinja2 +BuildRequires: python3-jsonpatch +BuildRequires: python3-jsonschema +BuildRequires: python3-mock +BuildRequires: python3-nose +BuildRequires: python3-oauthlib +BuildRequires: python3-prettytable +BuildRequires: python3-pyserial +BuildRequires: python3-PyYAML +BuildRequires: python3-requests +BuildRequires: python3-six +BuildRequires: python3-unittest2 +# dnf is needed to make cc_ntp unit tests work +# https://bugs.launchpad.net/cloud-init/+bug/1721573 +BuildRequires: /usr/bin/dnf + +Requires: e2fsprogs +Requires: iproute +Requires: libselinux-python3 +Requires: net-tools +Requires: policycoreutils-python3 +Requires: procps +Requires: python3-configobj +Requires: python3-jinja2 +Requires: python3-jsonpatch +Requires: python3-jsonschema +Requires: python3-oauthlib +Requires: python3-prettytable +Requires: python3-pyserial +Requires: python3-PyYAML +Requires: python3-requests +Requires: python3-six +Requires: shadow-utils +Requires: util-linux +Requires: xfsprogs + +%{?systemd_requires} + +%description +Cloud-init is a set of init scripts for cloud instances. Cloud instances +need special scripts to run during initialization to retrieve and install +ssh keys and to let the user run various scripts. + + +%prep +%autosetup -p1 + +# Change shebangs +sed -i -e 's|#!/usr/bin/env python|#!/usr/bin/env python3|' \ + -e 's|#!/usr/bin/python|#!/usr/bin/python3|' tools/* cloudinit/ssh_util.py + +%build +%py3_build + + +%install +%py3_install -- + +python3 tools/render-cloudcfg --variant fedora > $RPM_BUILD_ROOT/%{_sysconfdir}/cloud/cloud.cfg + +mkdir -p $RPM_BUILD_ROOT/var/lib/cloud + +# /run/cloud-init needs a tmpfiles.d entry +mkdir -p $RPM_BUILD_ROOT/run/cloud-init +mkdir -p $RPM_BUILD_ROOT/%{_tmpfilesdir} +cp -p %{SOURCE1} $RPM_BUILD_ROOT/%{_tmpfilesdir}/%{name}.conf + +# We supply our own config file since our software differs from Ubuntu's. +cp -p rhel/cloud.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/cloud/cloud.cfg + +mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rsyslog.d +cp -p tools/21-cloudinit.conf $RPM_BUILD_ROOT/%{_sysconfdir}/rsyslog.d/21-cloudinit.conf + +# Make installed NetworkManager hook name less generic +mv $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/hook-network-manager \ + $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/cloud-init-azure-hook + +# Install our own systemd units (rhbz#1440831) +mkdir -p $RPM_BUILD_ROOT%{_unitdir} +cp rhel/systemd/* $RPM_BUILD_ROOT%{_unitdir}/ + + +%clean +rm -rf $RPM_BUILD_ROOT + + +%post +if [ $1 -eq 1 ] ; then + # Initial installation + # Enabled by default per "runs once then goes away" exception + /bin/systemctl enable cloud-config.service >/dev/null 2>&1 || : + /bin/systemctl enable cloud-final.service >/dev/null 2>&1 || : + /bin/systemctl enable cloud-init.service >/dev/null 2>&1 || : + /bin/systemctl enable cloud-init-local.service >/dev/null 2>&1 || : +elif [ $1 -eq 2 ]; then + # Upgrade. If the upgrade is from a version older than 0.7.9-8, + # there will be stale systemd config + /bin/systemctl is-enabled cloud-config.service >/dev/null 2>&1 && + /bin/systemctl reenable cloud-config.service >/dev/null 2>&1 || : + + /bin/systemctl is-enabled cloud-final.service >/dev/null 2>&1 && + /bin/systemctl reenable cloud-final.service >/dev/null 2>&1 || : + + /bin/systemctl is-enabled cloud-init.service >/dev/null 2>&1 && + /bin/systemctl reenable cloud-init.service >/dev/null 2>&1 || : + + /bin/systemctl is-enabled cloud-init-local.service >/dev/null 2>&1 && + /bin/systemctl reenable cloud-init-local.service >/dev/null 2>&1 || : +fi + +%preun +if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable cloud-config.service >/dev/null 2>&1 || : + /bin/systemctl --no-reload disable cloud-final.service >/dev/null 2>&1 || : + /bin/systemctl --no-reload disable cloud-init.service >/dev/null 2>&1 || : + /bin/systemctl --no-reload disable cloud-init-local.service >/dev/null 2>&1 || : + # One-shot services -> no need to stop +fi + +%postun +%systemd_postun + + +%files +%license LICENSE +%doc ChangeLog rhel/README.rhel +%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg +%dir %{_sysconfdir}/cloud/cloud.cfg.d +%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/*.cfg +%doc %{_sysconfdir}/cloud/cloud.cfg.d/README +%dir %{_sysconfdir}/cloud/templates +%config(noreplace) %{_sysconfdir}/cloud/templates/* +%{_unitdir}/cloud-config.service +%{_unitdir}/cloud-config.target +%{_unitdir}/cloud-final.service +%{_unitdir}/cloud-init-local.service +%{_unitdir}/cloud-init.service +%{_tmpfilesdir}/%{name}.conf +%{python3_sitelib}/* +%{_libexecdir}/%{name} +%{_bindir}/cloud-init* +%doc %{_datadir}/doc/%{name} +%dir /run/cloud-init +%dir /var/lib/cloud +/etc/NetworkManager/dispatcher.d/cloud-init-azure-hook +%{_udevrulesdir}/66-azure-ephemeral.rules + +%dir %{_sysconfdir}/rsyslog.d +%config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf + +%changelog +* Wed Jan 23 2019 Miroslav Rezanina - 18.2-6.el8 +- ci-net-Make-sysconfig-renderer-compatible-with-Network-.patch [bz#1602784] +- Resolves: bz#1602784 + (cloud-init: Sometimes image boots fingerprints is configured, there's a network device present but it's not configured) + +* Fri Jan 18 2019 Miroslav Rezanina - 18.2-5.el8 +- ci-Fix-string-missmatch-when-mounting-ntfs.patch [bz#1664227] +- Resolves: bz#1664227 + ([Azure]String missmatch causes the /dev/sdb1 mounting failed after stop&start VM) + +* Thu Jan 10 2019 <> - 18.2-4.el8 +- ci-Enable-cloud-init-by-default-on-vmware.patch [bz#1644335] +- Resolves: bz#1644335 + ([ESXi][RHEL8.0]Enable cloud-init by default on VMware) + +* Wed Nov 28 2018 Miroslav Rezanina - 18.2-3.el8 +- ci-Adding-systemd-mount-options-to-wait-for-cloud-init.patch [bz#1615599] +- ci-Azure-Ignore-NTFS-mount-errors-when-checking-ephemer.patch [bz#1615599] +- ci-azure-Add-reported-ready-marker-file.patch [bz#1615599] +- ci-Adding-disk_setup-to-rhel-cloud.cfg.patch [bz#1615599] +- Resolves: bz#1615599 + ([Azure] cloud-init fails to mount /dev/sdb1 after stop(deallocate)&&start VM) + +* Tue Nov 06 2018 Miroslav Rezanina - 18.2-2.el7 +- Revert "remove 'tee' command from logging configuration" [bz#1626117] +- Resolves: rhbz#1626117] + (cloud-init-0.7.9-9 doesn't feed cloud-init-output.log) + +* Fri Jun 29 2018 Miroslav Rezanina - 18.2-1.el7 +- Rebase to 18.2 [bz#1515909] + Resolves: rhbz#1515909 + +* Tue Feb 13 2018 Ryan McCabe 0.7.9-24 +- Set DHCP_HOSTNAME on Azure to allow for the hostname to be + published correctly when bouncing the network. + Resolves: rhbz#1434109 + +* Mon Jan 15 2018 Ryan McCabe 0.7.9-23 +- Fix a bug tha caused cloud-init to fail as a result of trying + to rename bonds. + Resolves: rhbz#1512247 + +* Mon Jan 15 2018 Ryan McCabe 0.7.9-22 +- Apply patch from -21 + Resolves: rhbz#1489270 + +* Mon Jan 15 2018 Ryan McCabe 0.7.9-21 +- sysconfig: Fix a potential traceback introduced in the + 0.7.9-17 build + Resolves: rhbz#1489270 + +* Sun Dec 17 2017 Ryan McCabe 0.7.9-20 +- sysconfig: Correct rendering for dhcp on ipv6 + Resolves: rhbz#1519271 + +* Thu Nov 30 2017 Ryan McCabe 0.7.9-19 +- sysconfig: Fix rendering of default gateway for ipv6 + Resolves: rhbz#1492726 + +* Fri Nov 24 2017 Ryan McCabe 0.7.9-18 +- Start the cloud-init init local service after the dbus socket is created + so that the hostnamectl command works. + Resolves: rhbz#1450521 + +* Tue Nov 21 2017 Ryan McCabe 0.7.9-17 +- Correctly render DNS and DOMAIN for sysconfig + Resolves: rhbz#1489270 + +* Mon Nov 20 2017 Ryan McCabe 0.7.9-16 +- Disable NetworkManager management of resolv.conf if nameservers + are specified by configuration. + Resolves: rhbz#1454491 + +* Mon Nov 13 2017 Ryan McCabe 0.7.9-15 +- Fix a null reference error in the rh_subscription module + Resolves: rhbz#1498974 + +* Mon Nov 13 2017 Ryan McCabe 0-7.9-14 +- Include gateway if it's included in subnet configration + Resolves: rhbz#1492726 + +* Sun Nov 12 2017 Ryan McCabe 0-7.9-13 +- Do proper cleanup of systemd units when upgrading from versions + 0.7.9-3 through 0.7.9-8. + Resolves: rhbz#1465730 + +* Thu Nov 09 2017 Ryan McCabe 0.7.9-12 +- Prevent Azure NM and dhclient hooks from running when cloud-init is + disabled (rhbz#1474226) + +* Tue Oct 31 2017 Ryan McCabe 0.7.9-11 +- Fix rendering of multiple static IPs per interface file + Resolves: rhbz#bz1497954 + +* Tue Sep 26 2017 Ryan McCabe 0.7.9-10 +- AliCloud: Add support for the Alibaba Cloud datasource (rhbz#1482547) + +* Thu Jun 22 2017 Lars Kellogg-Stedman 0.7.9-9 +- RHEL/CentOS: Fix default routes for IPv4/IPv6 configuration. (rhbz#1438082) +- azure: ensure that networkmanager hook script runs (rhbz#1440831 rhbz#1460206) +- Fix ipv6 subnet detection (rhbz#1438082) + +* Tue May 23 2017 Lars Kellogg-Stedman 0.7.9-8 +- Update patches + +* Mon May 22 2017 Lars Kellogg-Stedman 0.7.9-7 +- Add missing sysconfig unit test data (rhbz#1438082) +- Fix dual stack IPv4/IPv6 configuration for RHEL (rhbz#1438082) +- sysconfig: Raise ValueError when multiple default gateways are present. (rhbz#1438082) +- Bounce network interface for Azure when using the built-in path. (rhbz#1434109) +- Do not write NM_CONTROLLED=no in generated interface config files (rhbz#1385172) + +* Wed May 10 2017 Lars Kellogg-Stedman 0.7.9-6 +- add power-state-change module to cloud_final_modules (rhbz#1252477) +- remove 'tee' command from logging configuration (rhbz#1424612) +- limit permissions on def_log_file (rhbz#1424612) +- Bounce network interface for Azure when using the built-in path. (rhbz#1434109) +- OpenStack: add 'dvs' to the list of physical link types. (rhbz#1442783) + +* Wed May 10 2017 Lars Kellogg-Stedman 0.7.9-5 +- systemd: replace generator with unit conditionals (rhbz#1440831) + +* Thu Apr 13 2017 Charalampos Stratakis 0.7.9-4 +- Import to RHEL 7 +Resolves: rhbz#1427280 + +* Tue Mar 07 2017 Lars Kellogg-Stedman 0.7.9-3 +- fixes for network config generation +- avoid dependency cycle at boot (rhbz#1420946) + +* Tue Jan 17 2017 Lars Kellogg-Stedman 0.7.9-2 +- use timeout from datasource config in openstack get_data (rhbz#1408589) + +* Thu Dec 01 2016 Lars Kellogg-Stedman - 0.7.9-1 +- Rebased on upstream 0.7.9. +- Remove dependency on run-parts + +* Wed Jan 06 2016 Lars Kellogg-Stedman - 0.7.6-8 +- make rh_subscription plugin do nothing in the absence of a valid + configuration [RH:1295953] +- move rh_subscription module to cloud_config stage + +* Wed Jan 06 2016 Lars Kellogg-Stedman - 0.7.6-7 +- correct permissions on /etc/ssh/sshd_config [RH:1296191] + +* Thu Sep 03 2015 Lars Kellogg-Stedman - 0.7.6-6 +- rebuild for ppc64le + +* Tue Jul 07 2015 Lars Kellogg-Stedman - 0.7.6-5 +- bump revision for new build + +* Tue Jul 07 2015 Lars Kellogg-Stedman - 0.7.6-4 +- ensure rh_subscription plugin is enabled by default + +* Wed Apr 29 2015 Lars Kellogg-Stedman - 0.7.6-3 +- added dependency on python-jinja2 [RH:1215913] +- added rhn_subscription plugin [RH:1227393] +- require pyserial to support smartos data source [RH:1226187] + +* Fri Jan 16 2015 Lars Kellogg-Stedman - 0.7.6-2 +- Rebased RHEL version to Fedora rawhide +- Backported fix for https://bugs.launchpad.net/cloud-init/+bug/1246485 +- Backported fix for https://bugs.launchpad.net/cloud-init/+bug/1411829 + +* Fri Nov 14 2014 Colin Walters - 0.7.6-1 +- New upstream version [RH:974327] +- Drop python-cheetah dependency (same as above bug)