ef3f20
From 326a466c0bdd89a161ba78b49e990c80ffacbb13 Mon Sep 17 00:00:00 2001
ef3f20
From: Lars Kellogg-Stedman <lars@redhat.com>
ef3f20
Date: Mon, 1 May 2017 21:27:40 -0400
ef3f20
Subject: [PATCH] systemd: replace generator with unit conditionals
ef3f20
ef3f20
In order to avoid problems caused by changes to upstream unit files,
ef3f20
this patch completely separates our systemd units from those
ef3f20
distributed by upstream.  The RHEL unit files can be found in the
ef3f20
rhel/systemd directory.
ef3f20
ef3f20
This commit replaces the generator with Conditional* statements in the
ef3f20
unit files. You are still able to disable cloud-init by setting
ef3f20
cloud-init=disabled on the kernel command line or by touching
ef3f20
/etc/cloud/cloud-init.disable.
ef3f20
ef3f20
We also retarget the cloud-init services from cloud-init.target back
ef3f20
to multi-user.target, which resolves the root cause of rhbz#1440831.
ef3f20
ef3f20
Resolves: rhbz#1440831
ef3f20
X-downstream-only: true
ef3f20
---
ef3f20
 rhel/systemd/cloud-config.service     | 18 ++++++++++++
ef3f20
 rhel/systemd/cloud-config.target      | 11 +++++++
ef3f20
 rhel/systemd/cloud-final.service      | 19 ++++++++++++
ef3f20
 rhel/systemd/cloud-init-local.service | 26 +++++++++++++++++
ef3f20
 rhel/systemd/cloud-init.service       | 25 ++++++++++++++++
ef3f20
 setup.py                              | 54 -----------------------------------
ef3f20
 6 files changed, 99 insertions(+), 54 deletions(-)
ef3f20
 create mode 100644 rhel/systemd/cloud-config.service
ef3f20
 create mode 100644 rhel/systemd/cloud-config.target
ef3f20
 create mode 100644 rhel/systemd/cloud-final.service
ef3f20
 create mode 100644 rhel/systemd/cloud-init-local.service
ef3f20
 create mode 100644 rhel/systemd/cloud-init.service
ef3f20
ef3f20
diff --git a/rhel/systemd/cloud-config.service b/rhel/systemd/cloud-config.service
ef3f20
new file mode 100644
ef3f20
index 0000000..12ca9df
ef3f20
--- /dev/null
ef3f20
+++ b/rhel/systemd/cloud-config.service
ef3f20
@@ -0,0 +1,18 @@
ef3f20
+[Unit]
ef3f20
+Description=Apply the settings specified in cloud-config
ef3f20
+After=network-online.target cloud-config.target
ef3f20
+Wants=network-online.target cloud-config.target
ef3f20
+ConditionPathExists=!/etc/cloud/cloud-init.disabled
ef3f20
+ConditionKernelCommandLine=!cloud-init=disabled
ef3f20
+
ef3f20
+[Service]
ef3f20
+Type=oneshot
ef3f20
+ExecStart=/usr/bin/cloud-init modules --mode=config
ef3f20
+RemainAfterExit=yes
ef3f20
+TimeoutSec=0
ef3f20
+
ef3f20
+# Output needs to appear in instance console output
ef3f20
+StandardOutput=journal+console
ef3f20
+
ef3f20
+[Install]
ef3f20
+WantedBy=multi-user.target
ef3f20
diff --git a/rhel/systemd/cloud-config.target b/rhel/systemd/cloud-config.target
ef3f20
new file mode 100644
ef3f20
index 0000000..ae9b7d0
ef3f20
--- /dev/null
ef3f20
+++ b/rhel/systemd/cloud-config.target
ef3f20
@@ -0,0 +1,11 @@
ef3f20
+# cloud-init normally emits a "cloud-config" upstart event to inform third
ef3f20
+# parties that cloud-config is available, which does us no good when we're
ef3f20
+# using systemd.  cloud-config.target serves as this synchronization point
ef3f20
+# instead.  Services that would "start on cloud-config" with upstart can
ef3f20
+# instead use "After=cloud-config.target" and "Wants=cloud-config.target"
ef3f20
+# as appropriate.
ef3f20
+
ef3f20
+[Unit]
ef3f20
+Description=Cloud-config availability
ef3f20
+Wants=cloud-init-local.service cloud-init.service
ef3f20
+After=cloud-init-local.service cloud-init.service
ef3f20
diff --git a/rhel/systemd/cloud-final.service b/rhel/systemd/cloud-final.service
ef3f20
new file mode 100644
ef3f20
index 0000000..32a83d8
ef3f20
--- /dev/null
ef3f20
+++ b/rhel/systemd/cloud-final.service
ef3f20
@@ -0,0 +1,19 @@
ef3f20
+[Unit]
ef3f20
+Description=Execute cloud user/final scripts
ef3f20
+After=network-online.target cloud-config.service rc-local.service
ef3f20
+Wants=network-online.target cloud-config.service
ef3f20
+ConditionPathExists=!/etc/cloud/cloud-init.disabled
ef3f20
+ConditionKernelCommandLine=!cloud-init=disabled
ef3f20
+
ef3f20
+[Service]
ef3f20
+Type=oneshot
ef3f20
+ExecStart=/usr/bin/cloud-init modules --mode=final
ef3f20
+RemainAfterExit=yes
ef3f20
+TimeoutSec=0
ef3f20
+KillMode=process
ef3f20
+
ef3f20
+# Output needs to appear in instance console output
ef3f20
+StandardOutput=journal+console
ef3f20
+
ef3f20
+[Install]
ef3f20
+WantedBy=multi-user.target
ef3f20
diff --git a/rhel/systemd/cloud-init-local.service b/rhel/systemd/cloud-init-local.service
ef3f20
new file mode 100644
ef3f20
index 0000000..8174937
ef3f20
--- /dev/null
ef3f20
+++ b/rhel/systemd/cloud-init-local.service
ef3f20
@@ -0,0 +1,26 @@
ef3f20
+[Unit]
ef3f20
+Description=Initial cloud-init job (pre-networking)
ef3f20
+DefaultDependencies=no
ef3f20
+Wants=network-pre.target
ef3f20
+After=systemd-remount-fs.service
ef3f20
+Before=NetworkManager.service network.service
ef3f20
+Before=network-pre.target
ef3f20
+Before=shutdown.target
ef3f20
+Before=sysinit.target
ef3f20
+Conflicts=shutdown.target
ef3f20
+RequiresMountsFor=/var/lib/cloud
ef3f20
+ConditionPathExists=!/etc/cloud/cloud-init.disabled
ef3f20
+ConditionKernelCommandLine=!cloud-init=disabled
ef3f20
+
ef3f20
+[Service]
ef3f20
+Type=oneshot
ef3f20
+ExecStart=/usr/bin/cloud-init init --local
ef3f20
+ExecStart=/bin/touch /run/cloud-init/network-config-ready
ef3f20
+RemainAfterExit=yes
ef3f20
+TimeoutSec=0
ef3f20
+
ef3f20
+# Output needs to appear in instance console output
ef3f20
+StandardOutput=journal+console
ef3f20
+
ef3f20
+[Install]
ef3f20
+WantedBy=multi-user.target
ef3f20
diff --git a/rhel/systemd/cloud-init.service b/rhel/systemd/cloud-init.service
ef3f20
new file mode 100644
ef3f20
index 0000000..68fc5f1
ef3f20
--- /dev/null
ef3f20
+++ b/rhel/systemd/cloud-init.service
ef3f20
@@ -0,0 +1,25 @@
ef3f20
+[Unit]
ef3f20
+Description=Initial cloud-init job (metadata service crawler)
ef3f20
+Wants=cloud-init-local.service
ef3f20
+Wants=sshd-keygen.service
ef3f20
+Wants=sshd.service
ef3f20
+After=cloud-init-local.service
ef3f20
+After=NetworkManager.service network.service
ef3f20
+Before=network-online.target
ef3f20
+Before=sshd-keygen.service
ef3f20
+Before=sshd.service
ef3f20
+Before=systemd-user-sessions.service
ef3f20
+ConditionPathExists=!/etc/cloud/cloud-init.disabled
ef3f20
+ConditionKernelCommandLine=!cloud-init=disabled
ef3f20
+
ef3f20
+[Service]
ef3f20
+Type=oneshot
ef3f20
+ExecStart=/usr/bin/cloud-init init
ef3f20
+RemainAfterExit=yes
ef3f20
+TimeoutSec=0
ef3f20
+
ef3f20
+# Output needs to appear in instance console output
ef3f20
+StandardOutput=journal+console
ef3f20
+
ef3f20
+[Install]
ef3f20
+WantedBy=multi-user.target
ef3f20
diff --git a/setup.py b/setup.py
ef3f20
index cc20c60..83723bf 100755
ef3f20
--- a/setup.py
ef3f20
+++ b/setup.py
ef3f20
@@ -63,9 +63,6 @@ INITSYS_FILES = {
ef3f20
     'sysvinit_freebsd': [f for f in glob('sysvinit/freebsd/*') if is_f(f)],
ef3f20
     'sysvinit_deb': [f for f in glob('sysvinit/debian/*') if is_f(f)],
ef3f20
     'sysvinit_openrc': [f for f in glob('sysvinit/gentoo/*') if is_f(f)],
ef3f20
-    'systemd': [f for f in (glob('systemd/*.service') +
ef3f20
-                            glob('systemd/*.target')) if is_f(f)],
ef3f20
-    'systemd.generators': [f for f in glob('systemd/*-generator') if is_f(f)],
ef3f20
     'upstart': [f for f in glob('upstart/*') if is_f(f)],
ef3f20
 }
ef3f20
 INITSYS_ROOTS = {
ef3f20
@@ -73,9 +70,6 @@ INITSYS_ROOTS = {
ef3f20
     'sysvinit_freebsd': '/usr/local/etc/rc.d',
ef3f20
     'sysvinit_deb': '/etc/init.d',
ef3f20
     'sysvinit_openrc': '/etc/init.d',
ef3f20
-    'systemd': pkg_config_read('systemd', 'systemdsystemunitdir'),
ef3f20
-    'systemd.generators': pkg_config_read('systemd',
ef3f20
-                                          'systemdsystemgeneratordir'),
ef3f20
     'upstart': '/etc/init/',
ef3f20
 }
ef3f20
 INITSYS_TYPES = sorted([f.partition(".")[0] for f in INITSYS_ROOTS.keys()])
ef3f20
@@ -117,50 +111,8 @@ def read_requires():
ef3f20
     return str(deps).splitlines()
ef3f20
 
ef3f20
 
ef3f20
-# TODO: Is there a better way to do this??
ef3f20
-class InitsysInstallData(install):
ef3f20
-    init_system = None
ef3f20
-    user_options = install.user_options + [
ef3f20
-        # This will magically show up in member variable 'init_sys'
ef3f20
-        ('init-system=', None,
ef3f20
-         ('init system(s) to configure (%s) [default: None]' %
ef3f20
-          (", ".join(INITSYS_TYPES)))),
ef3f20
-    ]
ef3f20
-
ef3f20
-    def initialize_options(self):
ef3f20
-        install.initialize_options(self)
ef3f20
-        self.init_system = ""
ef3f20
-
ef3f20
-    def finalize_options(self):
ef3f20
-        install.finalize_options(self)
ef3f20
-
ef3f20
-        if self.init_system and isinstance(self.init_system, str):
ef3f20
-            self.init_system = self.init_system.split(",")
ef3f20
-
ef3f20
-        if len(self.init_system) == 0:
ef3f20
-            raise DistutilsArgError(
ef3f20
-                ("You must specify one of (%s) when"
ef3f20
-                 " specifying init system(s)!") % (", ".join(INITSYS_TYPES)))
ef3f20
-
ef3f20
-        bad = [f for f in self.init_system if f not in INITSYS_TYPES]
ef3f20
-        if len(bad) != 0:
ef3f20
-            raise DistutilsArgError(
ef3f20
-                "Invalid --init-system: %s" % (','.join(bad)))
ef3f20
-
ef3f20
-        for system in self.init_system:
ef3f20
-            # add data files for anything that starts with '<system>.'
ef3f20
-            datakeys = [k for k in INITSYS_ROOTS
ef3f20
-                        if k.partition(".")[0] == system]
ef3f20
-            for k in datakeys:
ef3f20
-                self.distribution.data_files.append(
ef3f20
-                    (INITSYS_ROOTS[k], INITSYS_FILES[k]))
ef3f20
-        # Force that command to reinitalize (with new file list)
ef3f20
-        self.distribution.reinitialize_command('install_data', True)
ef3f20
-
ef3f20
-
ef3f20
 if in_virtualenv():
ef3f20
     data_files = []
ef3f20
-    cmdclass = {}
ef3f20
 else:
ef3f20
     data_files = [
ef3f20
         (ETC + '/cloud', glob('config/*.cfg')),
ef3f20
@@ -176,11 +128,6 @@ else:
ef3f20
             [f for f in glob('doc/examples/seed/*') if is_f(f)]),
ef3f20
         ('/usr/lib/udev/rules.d', [f for f in glob('udev/*.rules')]),
ef3f20
     ]
ef3f20
-    # Use a subclass for install that handles
ef3f20
-    # adding on the right init system configuration files
ef3f20
-    cmdclass = {
ef3f20
-        'install': InitsysInstallData,
ef3f20
-    }
ef3f20
 
ef3f20
 
ef3f20
 requirements = read_requires()
ef3f20
@@ -198,7 +145,6 @@ setuptools.setup(
ef3f20
     scripts=['tools/cloud-init-per'],
ef3f20
     license='Dual-licensed under GPLv3 or Apache 2.0',
ef3f20
     data_files=data_files,
ef3f20
-    cmdclass=cmdclass,
ef3f20
     entry_points={
ef3f20
         'console_scripts': [
ef3f20
             'cloud-init = cloudinit.cmd.main:main'