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