From 599685ef43b794d94005dc935b0cb1b0a9109309 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Fri, 29 Apr 2022 13:30:15 -0600 Subject: [PATCH 1/6] upstart: drop vestigial support for upstart upstream cloud-init not longer publishes to distribution versions which support upstart. Trusty has not been receiving cloud-init updates since 0.7.5 and Xenial stopped getting updates as version 21.1. Even though Ubuntu Xenial's default init system is systemd there was still an option for folks to launch amd maintain images which relied on upstart. Now that Xenial no longer has updates from upstream cloud-init we can drop all upstart support. Old Fedora and RHEL releases which use upstart are also not receiving cloud-init updates from tip of main. --- MANIFEST.in | 1 - cloudinit/analyze/show.py | 2 +- cloudinit/handlers/__init__.py | 1 - cloudinit/handlers/upstart_job.py | 107 ----------------------- cloudinit/helpers.py | 1 - cloudinit/stages.py | 2 - cloudinit/util.py | 7 +- config/cloud.cfg.tmpl | 3 - doc/rtd/topics/format.rst | 10 --- doc/rtd/topics/instancedata.rst | 1 - setup.py | 2 - tests/unittests/test_builtin_handlers.py | 66 -------------- upstart/cloud-config.conf | 9 -- upstart/cloud-final.conf | 10 --- upstart/cloud-init-blocknet.conf | 83 ------------------ upstart/cloud-init-container.conf | 57 ------------ upstart/cloud-init-local.conf | 16 ---- upstart/cloud-init-nonet.conf | 66 -------------- upstart/cloud-init.conf | 9 -- upstart/cloud-log-shutdown.conf | 19 ---- 20 files changed, 2 insertions(+), 470 deletions(-) delete mode 100644 cloudinit/handlers/upstart_job.py delete mode 100644 upstart/cloud-config.conf delete mode 100644 upstart/cloud-final.conf delete mode 100644 upstart/cloud-init-blocknet.conf delete mode 100644 upstart/cloud-init-container.conf delete mode 100644 upstart/cloud-init-local.conf delete mode 100644 upstart/cloud-init-nonet.conf delete mode 100644 upstart/cloud-init.conf delete mode 100644 upstart/cloud-log-shutdown.conf diff --git a/MANIFEST.in b/MANIFEST.in index 57a85ea723d..c2d2b5dd222 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -10,7 +10,6 @@ graft templates graft tests graft tools graft udev -graft upstart prune build prune dist prune .tox diff --git a/cloudinit/analyze/show.py b/cloudinit/analyze/show.py index e1e340ce9a7..abfa0913149 100644 --- a/cloudinit/analyze/show.py +++ b/cloudinit/analyze/show.py @@ -188,7 +188,7 @@ def parse_epoch_as_float(self): def dist_check_timestamp(): """ Determine which init system a particular linux distro is using. - Each init system (systemd, upstart, etc) has a different way of + Each init system (systemd, etc) has a different way of providing timestamps. :return: timestamps of kernelboot, kernelendboot, and cloud-initstart diff --git a/cloudinit/handlers/__init__.py b/cloudinit/handlers/__init__.py index 7d8a9208ce2..17755277b6f 100644 --- a/cloudinit/handlers/__init__.py +++ b/cloudinit/handlers/__init__.py @@ -44,7 +44,6 @@ "#include-once": "text/x-include-once-url", "#!": "text/x-shellscript", "#cloud-config": "text/cloud-config", - "#upstart-job": "text/upstart-job", "#part-handler": "text/part-handler", "#cloud-boothook": "text/cloud-boothook", "#cloud-config-archive": "text/cloud-config-archive", diff --git a/cloudinit/handlers/upstart_job.py b/cloudinit/handlers/upstart_job.py deleted file mode 100644 index 4bc95f97151..00000000000 --- a/cloudinit/handlers/upstart_job.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser -# Author: Juerg Haefliger -# Author: Joshua Harlow -# -# This file is part of cloud-init. See LICENSE file for license information. - -import os -import re - -from cloudinit import handlers -from cloudinit import log as logging -from cloudinit import subp, util -from cloudinit.settings import PER_INSTANCE - -LOG = logging.getLogger(__name__) - - -class UpstartJobPartHandler(handlers.Handler): - - prefixes = ["#upstart-job"] - - def __init__(self, paths, **_kwargs): - handlers.Handler.__init__(self, PER_INSTANCE) - self.upstart_dir = paths.upstart_conf_d - - def handle_part(self, data, ctype, filename, payload, frequency): - if ctype in handlers.CONTENT_SIGNALS: - return - - # See: https://bugs.launchpad.net/bugs/819507 - if frequency != PER_INSTANCE: - return - - if not self.upstart_dir: - return - - filename = util.clean_filename(filename) - (_name, ext) = os.path.splitext(filename) - if not ext: - ext = "" - ext = ext.lower() - if ext != ".conf": - filename = filename + ".conf" - - payload = util.dos2unix(payload) - path = os.path.join(self.upstart_dir, filename) - util.write_file(path, payload, 0o644) - - if SUITABLE_UPSTART: - subp.subp(["initctl", "reload-configuration"], capture=False) - - -def _has_suitable_upstart(): - # (LP: #1124384) - # a bug in upstart means that invoking reload-configuration - # at this stage in boot causes havoc. So, try to determine if upstart - # is installed, and reloading configuration is OK. - if not os.path.exists("/sbin/initctl"): - return False - try: - (version_out, _err) = subp.subp(["initctl", "version"]) - except Exception: - util.logexc(LOG, "initctl version failed") - return False - - # expecting 'initctl version' to output something like: init (upstart X.Y) - if re.match("upstart 1.[0-7][)]", version_out): - return False - if "upstart 0." in version_out: - return False - elif "upstart 1.8" in version_out: - if not os.path.exists("/usr/bin/dpkg-query"): - return False - try: - (dpkg_ver, _err) = subp.subp( - ["dpkg-query", "--showformat=${Version}", "--show", "upstart"], - rcs=[0, 1], - ) - except Exception: - util.logexc(LOG, "dpkg-query failed") - return False - - try: - good = "1.8-0ubuntu1.2" - subp.subp(["dpkg", "--compare-versions", dpkg_ver, "ge", good]) - return True - except subp.ProcessExecutionError as e: - if e.exit_code == 1: - pass - else: - util.logexc( - LOG, "dpkg --compare-versions failed [%s]", e.exit_code - ) - except Exception: - util.logexc(LOG, "dpkg --compare-versions failed") - return False - else: - return True - - -SUITABLE_UPSTART = _has_suitable_upstart() - -# vi: ts=4 expandtab diff --git a/cloudinit/helpers.py b/cloudinit/helpers.py index c2c9e5842bc..ce08e90d958 100644 --- a/cloudinit/helpers.py +++ b/cloudinit/helpers.py @@ -337,7 +337,6 @@ def __init__(self, path_cfgs, ds=None): self.run_dir = path_cfgs.get("run_dir", "/run/cloud-init") self.instance_link = os.path.join(self.cloud_dir, "instance") self.boot_finished = os.path.join(self.instance_link, "boot-finished") - self.upstart_conf_d = path_cfgs.get("upstart_dir") self.seed_dir = os.path.join(self.cloud_dir, "seed") # This one isn't joined, since it should just be read-only template_dir = path_cfgs.get("templates_dir", "/etc/cloud/templates/") diff --git a/cloudinit/stages.py b/cloudinit/stages.py index 3dece33633d..a5c52c5376f 100644 --- a/cloudinit/stages.py +++ b/cloudinit/stages.py @@ -24,7 +24,6 @@ from cloudinit.handlers.shell_script_by_frequency import ( ShellScriptByFreqPartHandler, ) -from cloudinit.handlers.upstart_job import UpstartJobPartHandler from cloudinit.net import cmdline from cloudinit.reporting import events from cloudinit.settings import ( @@ -527,7 +526,6 @@ def _default_handlers(self, opts=None): ShellScriptByFreqPartHandler(PER_INSTANCE, **opts), ShellScriptByFreqPartHandler(PER_ONCE, **opts), BootHookPartHandler(**opts), - UpstartJobPartHandler(**opts), ] opts.update( {"sub_handlers": [cloudconfig_handler, shellscript_handler]} diff --git a/cloudinit/util.py b/cloudinit/util.py index 0e8f2f58e5d..ef55bc2b341 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -417,7 +417,7 @@ def multi_log( # This will result in duplicate stderr and stdout messages if # stderr was True. # - # even though upstart or systemd might have set up output to go to + # even though systemd might have set up output to go to # /dev/console, the user may have configured elsewhere via # cloud-config 'output'. If there is /dev/console, messages will # still get there. @@ -2220,10 +2220,6 @@ def _is_container_systemd(): return _cmd_exits_zero(["systemd-detect-virt", "--quiet", "--container"]) -def _is_container_upstart(): - return _cmd_exits_zero(["running-in-container"]) - - def _is_container_old_lxc(): return _cmd_exits_zero(["lxc-is-container"]) @@ -2246,7 +2242,6 @@ def is_container(): checks = ( _is_container_systemd, _is_container_freebsd, - _is_container_upstart, _is_container_old_lxc, ) diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl index bd4d552b5f4..e8724257745 100644 --- a/config/cloud.cfg.tmpl +++ b/config/cloud.cfg.tmpl @@ -100,8 +100,6 @@ cloud_init_modules: # The modules that run in the 'config' stage cloud_config_modules: {% if variant in ["ubuntu", "unknown", "debian"] %} -# Emit the cloud config ready event -# this can be used by upstart jobs for 'start on cloud-config'. - snap {% endif %} {% if variant not in ["photon"] %} @@ -203,7 +201,6 @@ system_info: paths: cloud_dir: /var/lib/cloud/ templates_dir: /etc/cloud/templates/ - upstart_dir: /etc/init/ package_mirrors: - arches: [i386, amd64] failsafe: diff --git a/doc/rtd/topics/format.rst b/doc/rtd/topics/format.rst index 84029fa86c6..a4b772a2483 100644 --- a/doc/rtd/topics/format.rst +++ b/doc/rtd/topics/format.rst @@ -95,7 +95,6 @@ Supported content-types are listed from the cloud-init subcommand make-mime: cloud-config-jsonp jinja2 part-handler - upstart-job x-include-once-url x-include-url x-shellscript @@ -203,15 +202,6 @@ Example Also this `blog`_ post offers another example for more advanced usage. -Upstart Job -=========== - -Content is placed into a file in ``/etc/init``, and will be consumed by upstart -as any other upstart job. - -Begins with: ``#upstart-job`` or ``Content-Type: text/upstart-job`` when using -a MIME archive. - Disabling User-Data =================== diff --git a/doc/rtd/topics/instancedata.rst b/doc/rtd/topics/instancedata.rst index f08ead695f3..0c44d04e130 100644 --- a/doc/rtd/topics/instancedata.rst +++ b/doc/rtd/topics/instancedata.rst @@ -263,7 +263,6 @@ EC2 instance: "[handler_cloudLogHandler]\nclass=handlers.SysLogHandler\nlevel=DEBUG\nformatter=simpleFormatter\nargs=(\"/dev/log\", handlers.SysLogHandler.LOG_USER)\n" ], "cloud_config_modules": [ - "emit_upstart", "snap", "ssh-import-id", "locale", diff --git a/setup.py b/setup.py index a7ddf604091..47e041a56ac 100755 --- a/setup.py +++ b/setup.py @@ -156,7 +156,6 @@ def render_tmpl(template, mode=None): for f in glob("systemd/*") if is_f(f) and is_generator(f) ], - "upstart": [f for f in glob("upstart/*") if is_f(f)], } INITSYS_ROOTS = { "sysvinit": "etc/rc.d/init.d", @@ -169,7 +168,6 @@ def render_tmpl(template, mode=None): "systemd.generators": pkg_config_read( "systemd", "systemdsystemgeneratordir" ), - "upstart": "etc/init/", } INITSYS_TYPES = sorted([f.partition(".")[0] for f in INITSYS_ROOTS.keys()]) diff --git a/tests/unittests/test_builtin_handlers.py b/tests/unittests/test_builtin_handlers.py index 0dae924dbf7..a3cd3d31930 100644 --- a/tests/unittests/test_builtin_handlers.py +++ b/tests/unittests/test_builtin_handlers.py @@ -24,7 +24,6 @@ get_script_folder_by_frequency, path_map, ) -from cloudinit.handlers.upstart_job import UpstartJobPartHandler from cloudinit.settings import PER_ALWAYS, PER_INSTANCE, PER_ONCE from tests.unittests.helpers import ( CiTestCase, @@ -36,71 +35,6 @@ INSTANCE_DATA_FILE = "instance-data-sensitive.json" -class TestUpstartJobPartHandler(FilesystemMockingTestCase): - - mpath = "cloudinit.handlers.upstart_job." - - def test_upstart_frequency_no_out(self): - c_root = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, c_root) - up_root = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, up_root) - paths = helpers.Paths( - { - "cloud_dir": c_root, - "upstart_dir": up_root, - } - ) - h = UpstartJobPartHandler(paths) - # No files should be written out when - # the frequency is ! per-instance - h.handle_part("", handlers.CONTENT_START, None, None, None) - h.handle_part( - "blah", - "text/upstart-job", - "test.conf", - "blah", - frequency=PER_ALWAYS, - ) - h.handle_part("", handlers.CONTENT_END, None, None, None) - self.assertEqual(0, len(os.listdir(up_root))) - - def test_upstart_frequency_single(self): - # files should be written out when frequency is ! per-instance - new_root = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, new_root) - - self.patchOS(new_root) - self.patchUtils(new_root) - paths = helpers.Paths( - { - "upstart_dir": "/etc/upstart", - } - ) - - util.ensure_dir("/run") - util.ensure_dir("/etc/upstart") - - with mock.patch(self.mpath + "SUITABLE_UPSTART", return_value=True): - with mock.patch.object(subp, "subp") as m_subp: - h = UpstartJobPartHandler(paths) - h.handle_part("", handlers.CONTENT_START, None, None, None) - h.handle_part( - "blah", - "text/upstart-job", - "test.conf", - "blah", - frequency=PER_INSTANCE, - ) - h.handle_part("", handlers.CONTENT_END, None, None, None) - - self.assertEqual(len(os.listdir("/etc/upstart")), 1) - - m_subp.assert_called_once_with( - ["initctl", "reload-configuration"], capture=False - ) - - class TestJinjaTemplatePartHandler(CiTestCase): with_logs = True diff --git a/upstart/cloud-config.conf b/upstart/cloud-config.conf deleted file mode 100644 index 2c3ef67b100..00000000000 --- a/upstart/cloud-config.conf +++ /dev/null @@ -1,9 +0,0 @@ -# cloud-config - Handle applying the settings specified in cloud-config -description "Handle applying cloud-config" -emits cloud-config - -start on (filesystem and started rsyslog) -console output -task - -exec cloud-init modules --mode=config diff --git a/upstart/cloud-final.conf b/upstart/cloud-final.conf deleted file mode 100644 index 72ae505299d..00000000000 --- a/upstart/cloud-final.conf +++ /dev/null @@ -1,10 +0,0 @@ -# cloud-final.conf - run "final" jobs -# this runs around traditional "rc.local" time. -# and after all cloud-config jobs are run -description "execute cloud user/final scripts" - -start on (stopped rc RUNLEVEL=[2345] and stopped cloud-config) -console output -task - -exec cloud-init modules --mode=final diff --git a/upstart/cloud-init-blocknet.conf b/upstart/cloud-init-blocknet.conf deleted file mode 100644 index be09e7d8e2d..00000000000 --- a/upstart/cloud-init-blocknet.conf +++ /dev/null @@ -1,83 +0,0 @@ -# cloud-init-blocknet -# the purpose of this job is -# * to block networking from coming up until cloud-init-nonet has run -# * timeout if they all do not come up in a reasonable amount of time -description "block networking until cloud-init-local" -start on (starting network-interface - or starting network-manager - or starting networking) -stop on stopped cloud-init-local - -instance $JOB${INTERFACE:+/}${INTERFACE:-} -export INTERFACE -task - -script - set +e # you cannot trap TERM reliably with 'set -e' - SLEEP_CHILD="" - - static_network_up() { - local emitted="/run/network/static-network-up-emitted" - # /run/network/static-network-up-emitted is written by - # upstart (via /etc/network/if-up.d/upstart). its presense would - # indicate that static-network-up has already fired. - [ -e "$emitted" -o -e "/var/$emitted" ] - } - msg() { - local uptime="" idle="" msg="" - if [ -r /proc/uptime ]; then - read uptime idle < /proc/uptime - fi - msg="${UPSTART_INSTANCE}${uptime:+[${uptime}]}: $*" - echo "$msg" - } - - handle_sigterm() { - # if we received sigterm and static networking is up then it probably - # came from upstart as a result of 'stop on static-network-up' - msg "got sigterm" - if [ -n "$SLEEP_CHILD" ]; then - if ! kill $SLEEP_CHILD 2>/dev/null; then - [ ! -d "/proc/$SLEEP_CHILD" ] || - msg "hm.. failed to kill sleep pid $SLEEP_CHILD" - fi - fi - msg "stopped" - exit 0 - } - - dowait() { - msg "blocking $1 seconds" - # all this 'exec -a' does is get me a nicely named process in 'ps' - # ie, 'sleep-block-network-interface.eth1' - if [ -x /bin/bash ]; then - bash -c 'exec -a sleep-block-$1 sleep $2' -- "$UPSTART_INSTANCE" "$1" & - else - sleep "$1" & - fi - SLEEP_CHILD=$! - msg "sleepchild=$SLEEP_CHILD" - wait $SLEEP_CHILD - SLEEP_CHILD="" - } - - trap handle_sigterm TERM - - if [ -n "$INTERFACE" -a "${INTERFACE#lo}" != "${INTERFACE}" ]; then - msg "ignoring interface ${INTERFACE}"; - exit 0; - fi - - # static_network_up already occurred - static_network_up && { msg "static_network_up already"; exit 0; } - - # local-finished cloud-init-local success or failure - lfin="/run/cloud-init/local-finished" - disable="/etc/cloud/no-blocknet" - [ -f "$lfin" ] && { msg "$lfin found"; exit 0; } - [ -f "$disable" ] && { msg "$disable found"; exit 0; } - - dowait 120 - msg "gave up waiting for $lfin" - exit 1 -end script diff --git a/upstart/cloud-init-container.conf b/upstart/cloud-init-container.conf deleted file mode 100644 index 6bdbe77e3c3..00000000000 --- a/upstart/cloud-init-container.conf +++ /dev/null @@ -1,57 +0,0 @@ -# in a lxc container, events for network interfaces do not -# get created or may be missed. This helps cloud-init-nonet along -# by emitting those events if they have not been emitted. - -start on container -stop on static-network-up -task - -emits net-device-added - -console output - -script - # if we are inside a container, then we may have to emit the ifup - # events for 'auto' network devices. - set -f - - # from /etc/network/if-up.d/upstart - MARK_DEV_PREFIX="/run/network/ifup." - MARK_STATIC_NETWORK_EMITTED="/run/network/static-network-up-emitted" - # if the all static network interfaces are already up, nothing to do - [ -f "$MARK_STATIC_NETWORK_EMITTED" ] && exit 0 - - # ifquery will exit failure if there is no /run/network directory. - # normally that would get created by one of network-interface.conf - # or networking.conf. But, it is possible that we're running - # before either of those have. - mkdir -p /run/network - - # get list of all 'auto' interfaces. if there are none, nothing to do. - auto_list=$(ifquery --list --allow auto 2>/dev/null) || : - [ -z "$auto_list" ] && exit 0 - set -- ${auto_list} - [ "$*" = "lo" ] && exit 0 - - # we only want to emit for interfaces that do not exist, so filter - # out anything that does not exist. - for iface in "$@"; do - [ "$iface" = "lo" ] && continue - # skip interfaces that are already up - [ -f "${MARK_DEV_PREFIX}${iface}" ] && continue - - if [ -d /sys/net ]; then - # if /sys is mounted, and there is no /sys/net/iface, then no device - [ -e "/sys/net/$iface" ] && continue - else - # sys wasn't mounted, so just check via 'ifconfig' - ifconfig "$iface" >/dev/null 2>&1 || continue - fi - initctl emit --no-wait net-device-added "INTERFACE=$iface" && - emitted="$emitted $iface" || - echo "warn: ${UPSTART_JOB} failed to emit net-device-added INTERFACE=$iface" - done - - [ -z "${emitted# }" ] || - echo "${UPSTART_JOB}: emitted ifup for ${emitted# }" -end script diff --git a/upstart/cloud-init-local.conf b/upstart/cloud-init-local.conf deleted file mode 100644 index 5def043ddec..00000000000 --- a/upstart/cloud-init-local.conf +++ /dev/null @@ -1,16 +0,0 @@ -# cloud-init - the initial cloud-init job -# crawls metadata service, emits cloud-config -start on mounted MOUNTPOINT=/ and mounted MOUNTPOINT=/run - -task - -console output - -script - lfin=/run/cloud-init/local-finished - ret=0 - cloud-init init --local || ret=$? - [ -r /proc/uptime ] && read up idle < /proc/uptime || up="N/A" - echo "$ret up $up" > "$lfin" - exit $ret -end script diff --git a/upstart/cloud-init-nonet.conf b/upstart/cloud-init-nonet.conf deleted file mode 100644 index 6abf657322e..00000000000 --- a/upstart/cloud-init-nonet.conf +++ /dev/null @@ -1,66 +0,0 @@ -# cloud-init-no-net -# the purpose of this job is -# * to block running of cloud-init until all network interfaces -# configured in /etc/network/interfaces are up -# * timeout if they all do not come up in a reasonable amount of time -start on mounted MOUNTPOINT=/ and stopped cloud-init-local -stop on static-network-up -task - -console output - -script - set +e # you cannot trap TERM reliably with 'set -e' - SLEEP_CHILD="" - - static_network_up() { - local emitted="/run/network/static-network-up-emitted" - # /run/network/static-network-up-emitted is written by - # upstart (via /etc/network/if-up.d/upstart). its presense would - # indicate that static-network-up has already fired. - [ -e "$emitted" -o -e "/var/$emitted" ] - } - msg() { - local uptime="" idle="" - if [ -r /proc/uptime ]; then - read uptime idle < /proc/uptime - fi - echo "$UPSTART_JOB${uptime:+[${uptime}]}:" "$1" - } - - handle_sigterm() { - # if we received sigterm and static networking is up then it probably - # came from upstart as a result of 'stop on static-network-up' - if [ -n "$SLEEP_CHILD" ]; then - if ! kill $SLEEP_CHILD 2>/dev/null; then - [ ! -d "/proc/$SLEEP_CHILD" ] || - msg "hm.. failed to kill sleep pid $SLEEP_CHILD" - fi - fi - if static_network_up; then - msg "static networking is now up" - exit 0 - fi - msg "recieved SIGTERM, networking not up" - exit 2 - } - - dowait() { - [ $# -eq 2 ] || msg "waiting $1 seconds for network device" - sleep "$1" & - SLEEP_CHILD=$! - wait $SLEEP_CHILD - SLEEP_CHILD="" - } - - trap handle_sigterm TERM - - # static_network_up already occurred - static_network_up && exit 0 - - dowait 5 silent - dowait 10 - dowait 115 - msg "gave up waiting for a network device." - : > /var/lib/cloud/data/no-net -end script diff --git a/upstart/cloud-init.conf b/upstart/cloud-init.conf deleted file mode 100644 index 41ddd284d72..00000000000 --- a/upstart/cloud-init.conf +++ /dev/null @@ -1,9 +0,0 @@ -# cloud-init - the initial cloud-init job -# crawls metadata service, emits cloud-config -start on mounted MOUNTPOINT=/ and stopped cloud-init-nonet - -task - -console output - -exec /usr/bin/cloud-init init diff --git a/upstart/cloud-log-shutdown.conf b/upstart/cloud-log-shutdown.conf deleted file mode 100644 index 278b9c060a5..00000000000 --- a/upstart/cloud-log-shutdown.conf +++ /dev/null @@ -1,19 +0,0 @@ -# log shutdowns and reboots to the console (/dev/console) -# this is useful for correlating logs -start on runlevel PREVLEVEL=2 - -task -console output - -script - # runlevel(7) says INIT_HALT will be set to HALT or POWEROFF - date=$(date --utc) - case "$RUNLEVEL:$INIT_HALT" in - 6:*) mode="reboot";; - 0:HALT) mode="halt";; - 0:POWEROFF) mode="poweroff";; - 0:*) mode="shutdown-unknown";; - esac - { read seconds idle < /proc/uptime; } 2>/dev/null || : - echo "$date: shutting down for $mode${seconds:+ [up ${seconds%.*}s]}." -end script From 78d78b9e79d7b1d7f1268939f296fa5987f7972c Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Tue, 3 May 2022 15:25:46 -0600 Subject: [PATCH 2/6] upstart: remove upstart-job doc examples --- doc/examples/upstart-cloud-config.txt | 12 ------------ doc/examples/upstart-rclocal.txt | 12 ------------ 2 files changed, 24 deletions(-) delete mode 100644 doc/examples/upstart-cloud-config.txt delete mode 100644 doc/examples/upstart-rclocal.txt diff --git a/doc/examples/upstart-cloud-config.txt b/doc/examples/upstart-cloud-config.txt deleted file mode 100644 index 1fcec34d5d6..00000000000 --- a/doc/examples/upstart-cloud-config.txt +++ /dev/null @@ -1,12 +0,0 @@ -#upstart-job -description "My test job" - -start on cloud-config -console output -task - -script -echo "====BEGIN=======" -echo "HELLO WORLD: $UPSTART_JOB" -echo "=====END========" -end script diff --git a/doc/examples/upstart-rclocal.txt b/doc/examples/upstart-rclocal.txt deleted file mode 100644 index 5cd049a932a..00000000000 --- a/doc/examples/upstart-rclocal.txt +++ /dev/null @@ -1,12 +0,0 @@ -#upstart-job -description "a test upstart job" - -start on stopped rc RUNLEVEL=[2345] -console output -task - -script -echo "====BEGIN=======" -echo "HELLO RC.LOCAL LIKE WORLD: $UPSTART_JOB" -echo "=====END========" -end script From dbb9ee84e9631701a288f17d16d4142b730b0ea5 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Wed, 4 May 2022 11:05:57 -0600 Subject: [PATCH 3/6] flake --- tests/unittests/test_builtin_handlers.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/unittests/test_builtin_handlers.py b/tests/unittests/test_builtin_handlers.py index a3cd3d31930..2813ab4abb2 100644 --- a/tests/unittests/test_builtin_handlers.py +++ b/tests/unittests/test_builtin_handlers.py @@ -5,13 +5,11 @@ import copy import errno import os -import shutil -import tempfile from textwrap import dedent import pytest -from cloudinit import handlers, helpers, subp, util +from cloudinit import handlers, helpers, util from cloudinit.cmd.devel import read_cfg_paths from cloudinit.handlers.cloud_config import CloudConfigPartHandler from cloudinit.handlers.jinja_template import ( @@ -27,7 +25,6 @@ from cloudinit.settings import PER_ALWAYS, PER_INSTANCE, PER_ONCE from tests.unittests.helpers import ( CiTestCase, - FilesystemMockingTestCase, mock, skipUnlessJinja, ) From dd19768377fdc3eff34c34e79ef89565e7f1cc04 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Wed, 4 May 2022 11:25:40 -0600 Subject: [PATCH 4/6] isort --- tests/unittests/test_builtin_handlers.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/unittests/test_builtin_handlers.py b/tests/unittests/test_builtin_handlers.py index 2813ab4abb2..4f9eeb656a2 100644 --- a/tests/unittests/test_builtin_handlers.py +++ b/tests/unittests/test_builtin_handlers.py @@ -23,11 +23,7 @@ path_map, ) from cloudinit.settings import PER_ALWAYS, PER_INSTANCE, PER_ONCE -from tests.unittests.helpers import ( - CiTestCase, - mock, - skipUnlessJinja, -) +from tests.unittests.helpers import CiTestCase, mock, skipUnlessJinja INSTANCE_DATA_FILE = "instance-data-sensitive.json" From a2f204e5c0b1cfe6a95a34354941cc5b93646b53 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Thu, 5 May 2022 11:04:02 -0600 Subject: [PATCH 5/6] review comments --- cloudinit/cmd/main.py | 7 +++---- doc/examples/cloud-config-archive.txt | 7 ++----- doc/examples/cloud-config.txt | 11 ----------- doc/rtd/topics/analyze.rst | 2 -- doc/rtd/topics/debugging.rst | 1 - doc/userdata.txt | 6 ------ systemd/cloud-config.target | 19 +++++++++++++------ systemd/cloud-init.target | 7 ++++++- 8 files changed, 24 insertions(+), 36 deletions(-) diff --git a/cloudinit/cmd/main.py b/cloudinit/cmd/main.py index afd0a8d81b6..e082e2d9e06 100644 --- a/cloudinit/cmd/main.py +++ b/cloudinit/cmd/main.py @@ -342,8 +342,8 @@ def main_init(name, args): " exist from a previous run that would allow us" " to stop early." ) - # no-net is written by upstart cloud-init-nonet when network failed - # to come up + # A /var/lib/cloud/data/no-net marker file can prevent network + # datasource detection. stop_files = [ os.path.join(path_helper.get_cpath("data"), "no-net"), ] @@ -394,8 +394,7 @@ def main_init(name, args): except sources.DataSourceNotFoundException: # In the case of 'cloud-init init' without '--local' it is a bit # more likely that the user would consider it failure if nothing was - # found. When using upstart it will also mentions job failure - # in console log if exit code is != 0. + # found. if mode == sources.DSMODE_LOCAL: LOG.debug("No local datasource found") else: diff --git a/doc/examples/cloud-config-archive.txt b/doc/examples/cloud-config-archive.txt index 23b1024c182..f8a3d778bce 100644 --- a/doc/examples/cloud-config-archive.txt +++ b/doc/examples/cloud-config-archive.txt @@ -9,8 +9,5 @@ multi line payload here - - type: text/upstart-job - filename: my-upstart.conf - content: | - whats this, yo? - + type: text/cloud-config + content: '#cloud-config\n\n password: gocubs' diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt index ec9a51d8766..177c56000cc 100644 --- a/doc/examples/cloud-config.txt +++ b/doc/examples/cloud-config.txt @@ -455,17 +455,6 @@ ssh_pwauth: True # default is False manual_cache_clean: False -# When cloud-init is finished running including having run -# cloud_init_modules, then it will run this command. The default -# is to emit an upstart signal as shown below. If the value is a -# list, it will be passed to Popen. If it is a string, it will be -# invoked through 'sh -c'. -# -# default value: -# cc_ready_cmd: [ initctl, emit, cloud-config, CLOUD_CFG=/var/lib/instance//cloud-config.txt ] -# example: -# cc_ready_cmd: [ sh, -c, 'echo HI MOM > /tmp/file' ] - ## configure interaction with ssh server # ssh_svcname: ssh # set the name of the option to 'service restart' diff --git a/doc/rtd/topics/analyze.rst b/doc/rtd/topics/analyze.rst index 709131b8627..61213e2879d 100644 --- a/doc/rtd/topics/analyze.rst +++ b/doc/rtd/topics/analyze.rst @@ -100,7 +100,6 @@ execution. 00.00000s (modules-final/config-chef) 00.00000s (modules-config/config-snap_config) 00.00000s (modules-config/config-ntp) - 00.00000s (modules-config/config-emit_upstart) 00.00000s (modules-config/config-disable-ec2-metadata) 00.00000s (init-network/setup-datasource) @@ -138,7 +137,6 @@ The following is an abbreviated example of the show output: Finished stage: (init-network) 02.72100 seconds Starting stage: modules-config - |`->config-emit_upstart ran successfully @15.43100s +00.00000s |`->config-snap ran successfully @15.43100s +00.00100s ... |`->config-runcmd ran successfully @16.22300s +00.00100s diff --git a/doc/rtd/topics/debugging.rst b/doc/rtd/topics/debugging.rst index a4a2779f456..23ef0dfe479 100644 --- a/doc/rtd/topics/debugging.rst +++ b/doc/rtd/topics/debugging.rst @@ -33,7 +33,6 @@ subcommands default to reading /var/log/cloud-init.log. The time the event takes is printed after the "+" character. Starting stage: modules-config - |`->config-emit_upstart ran successfully @05.47600s +00.00100s |`->config-snap_config ran successfully @05.47700s +00.00100s |`->config-ssh-import-id ran successfully @05.47800s +00.00200s |`->config-locale ran successfully @05.48000s +00.00100s diff --git a/doc/userdata.txt b/doc/userdata.txt index 355966a8f9e..e44a4952bc8 100644 --- a/doc/userdata.txt +++ b/doc/userdata.txt @@ -52,12 +52,6 @@ finds. However, certain types of user-data are handled specially. This content is "cloud-config" data. See the examples for a commented example of supported config formats. - * Upstart Job - begins with #upstart-job or Content-Type: text/upstart-job - - Content is placed into a file in /etc/init, and will be consumed - by upstart as any other upstart job. - * Cloud Boothook begins with #cloud-boothook or Content-Type: text/cloud-boothook diff --git a/systemd/cloud-config.target b/systemd/cloud-config.target index ae9b7d02df9..2d65e3433ce 100644 --- a/systemd/cloud-config.target +++ b/systemd/cloud-config.target @@ -1,9 +1,16 @@ -# 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. +# cloud-config.target is the earliest synchronization point in cloud-init's +# boot stages that indicates the completion of datasource detection (cloud-id) +# and the presence of any meta-data, vendor-data and user-data. + +# Any services started at cloud-config.target will need to be aware that +# cloud-init configuration modules have not yet completed initial system +# configuration of cloud-config modules and there may be race conditions with +# ongoing cloud-init setup, package installs or user-data scripts. + +# Services that need to start at this point should use the directives +# "After=cloud-config.target" and "Wants=cloud-config.target" as appropriate. + +# To order services after all cloud-init operations, see cloud-init.target. [Unit] Description=Cloud-config availability diff --git a/systemd/cloud-init.target b/systemd/cloud-init.target index 083c3b6f79b..760dfee5e4e 100644 --- a/systemd/cloud-init.target +++ b/systemd/cloud-init.target @@ -1,7 +1,12 @@ -# cloud-init target is enabled by cloud-init-generator +# cloud-init.target is enabled by cloud-init-generator # To disable it you can either: # a.) boot with kernel cmdline of 'cloud-init=disabled' # b.) touch a file /etc/cloud/cloud-init.disabled +# +# cloud-init.target is a synchronization point when all cloud-init's initial +# system configuration tasks have completed. To order a service after cloud-init +# is done, add the directives as applicable: +# After=cloud-init.target and Wants=cloud-init.target [Unit] Description=Cloud-init target After=multi-user.target From 008c1c2cc8365f7d235fbc16b17e476efb34e4d4 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Thu, 5 May 2022 12:42:19 -0600 Subject: [PATCH 6/6] cli: init drop /v/l/c/data/no-net marker to skip init-network --- cloudinit/cmd/main.py | 27 ------------------- tests/unittests/cmd/test_main.py | 46 -------------------------------- 2 files changed, 73 deletions(-) diff --git a/cloudinit/cmd/main.py b/cloudinit/cmd/main.py index e082e2d9e06..5ad29bea7c5 100644 --- a/cloudinit/cmd/main.py +++ b/cloudinit/cmd/main.py @@ -337,31 +337,6 @@ def main_init(name, args): if mode == sources.DSMODE_NETWORK: existing = "trust" sys.stderr.write("%s\n" % (netinfo.debug_info())) - LOG.debug( - "Checking to see if files that we need already" - " exist from a previous run that would allow us" - " to stop early." - ) - # A /var/lib/cloud/data/no-net marker file can prevent network - # datasource detection. - stop_files = [ - os.path.join(path_helper.get_cpath("data"), "no-net"), - ] - existing_files = [] - for fn in stop_files: - if os.path.isfile(fn): - existing_files.append(fn) - - if existing_files: - LOG.debug( - "[%s] Exiting. stop file %s existed", mode, existing_files - ) - return (None, []) - else: - LOG.debug( - "Execution continuing, no previous run detected that" - " would allow us to stop early." - ) else: existing = "check" mcfg = util.get_cfg_option_bool(init.cfg, "manual_cache_clean", False) @@ -375,8 +350,6 @@ def main_init(name, args): existing = "trust" init.purge_cache() - # Delete the no-net file as well - util.del_file(os.path.join(path_helper.get_cpath("data"), "no-net")) # Stage 5 bring_up_interfaces = _should_bring_up_interfaces(init, args) diff --git a/tests/unittests/cmd/test_main.py b/tests/unittests/cmd/test_main.py index 3e778b0bd51..2f7a1fb166d 100644 --- a/tests/unittests/cmd/test_main.py +++ b/tests/unittests/cmd/test_main.py @@ -56,50 +56,6 @@ def setUp(self): self.stderr = StringIO() self.patchStdoutAndStderr(stderr=self.stderr) - def test_main_init_run_net_stops_on_file_no_net(self): - """When no-net file is present, main_init does not process modules.""" - stop_file = os.path.join(self.cloud_dir, "data", "no-net") # stop file - write_file(stop_file, "") - cmdargs = myargs( - debug=False, - files=None, - force=False, - local=False, - reporter=None, - subcommand="init", - ) - (_item1, item2) = wrap_and_call( - "cloudinit.cmd.main", - { - "util.close_stdin": True, - "netinfo.debug_info": "my net debug info", - "util.fixup_output": ("outfmt", "errfmt"), - }, - main.main_init, - "init", - cmdargs, - ) - # We should not run write_files module - self.assertFalse( - os.path.exists(os.path.join(self.new_root, "etc/blah.ini")), - "Unexpected run of write_files module produced blah.ini", - ) - self.assertEqual([], item2) - # Instancify is called - instance_id_path = "var/lib/cloud/data/instance-id" - self.assertFalse( - os.path.exists(os.path.join(self.new_root, instance_id_path)), - "Unexpected call to datasource.instancify produced instance-id", - ) - expected_logs = [ - "Exiting. stop file ['{stop_file}'] existed\n".format( - stop_file=stop_file - ), - "my net debug info", # netinfo.debug_info - ] - for log in expected_logs: - self.assertIn(log, self.stderr.getvalue()) - def test_main_init_run_net_runs_modules(self): """Modules like write_files are run in 'net' mode.""" cmdargs = myargs( @@ -137,7 +93,6 @@ def test_main_init_run_net_runs_modules(self): expected_logs = [ "network config is disabled by fallback", # apply_network_config "my net debug info", # netinfo.debug_info - "no previous run detected", ] for log in expected_logs: self.assertIn(log, self.stderr.getvalue()) @@ -209,7 +164,6 @@ def set_hostname(name, cfg, cloud, log, args): expected_logs = [ "network config is disabled by fallback", # apply_network_config "my net debug info", # netinfo.debug_info - "no previous run detected", ] for log in expected_logs: self.assertIn(log, self.stderr.getvalue())