From 326a466c0bdd89a161ba78b49e990c80ffacbb13 Mon Sep 17 00:00:00 2001 From: Lars Kellogg-Stedman Date: Mon, 1 May 2017 21:27:40 -0400 Subject: [PATCH] systemd: replace generator with unit conditionals In order to avoid problems caused by changes to upstream unit files, this patch completely separates our systemd units from those distributed by upstream. The RHEL unit files can be found in the rhel/systemd directory. This commit replaces the generator with Conditional* statements in the unit files. You are still able to disable cloud-init by setting cloud-init=disabled on the kernel command line or by touching /etc/cloud/cloud-init.disable. We also retarget the cloud-init services from cloud-init.target back to multi-user.target, which resolves the root cause of rhbz#1440831. Resolves: rhbz#1440831 X-downstream-only: true --- rhel/systemd/cloud-config.service | 18 ++++++++++++ rhel/systemd/cloud-config.target | 11 +++++++ rhel/systemd/cloud-final.service | 19 ++++++++++++ rhel/systemd/cloud-init-local.service | 26 +++++++++++++++++ rhel/systemd/cloud-init.service | 25 ++++++++++++++++ setup.py | 54 ----------------------------------- 6 files changed, 99 insertions(+), 54 deletions(-) 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/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..8174937 --- /dev/null +++ b/rhel/systemd/cloud-init-local.service @@ -0,0 +1,26 @@ +[Unit] +Description=Initial cloud-init job (pre-networking) +DefaultDependencies=no +Wants=network-pre.target +After=systemd-remount-fs.service +Before=NetworkManager.service network.service +Before=network-pre.target +Before=shutdown.target +Before=sysinit.target +Conflicts=shutdown.target +RequiresMountsFor=/var/lib/cloud +ConditionPathExists=!/etc/cloud/cloud-init.disabled +ConditionKernelCommandLine=!cloud-init=disabled + +[Service] +Type=oneshot +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 cc20c60..83723bf 100755 --- a/setup.py +++ b/setup.py @@ -63,9 +63,6 @@ INITSYS_FILES = { 'sysvinit_freebsd': [f for f in glob('sysvinit/freebsd/*') if is_f(f)], '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)], - 'systemd': [f for f in (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 = { @@ -73,9 +70,6 @@ INITSYS_ROOTS = { 'sysvinit_freebsd': '/usr/local/etc/rc.d', 'sysvinit_deb': '/etc/init.d', 'sysvinit_openrc': '/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()]) @@ -117,50 +111,8 @@ def read_requires(): return str(deps).splitlines() -# 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: - raise DistutilsArgError( - ("You must specify one of (%s) when" - " specifying init system(s)!") % (", ".join(INITSYS_TYPES))) - - 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: - 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 in_virtualenv(): data_files = [] - cmdclass = {} else: data_files = [ (ETC + '/cloud', glob('config/*.cfg')), @@ -176,11 +128,6 @@ else: [f for f in glob('doc/examples/seed/*') if is_f(f)]), ('/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, - } requirements = read_requires() @@ -198,7 +145,6 @@ setuptools.setup( scripts=['tools/cloud-init-per'], license='Dual-licensed under GPLv3 or Apache 2.0', data_files=data_files, - cmdclass=cmdclass, entry_points={ 'console_scripts': [ 'cloud-init = cloudinit.cmd.main:main'