From c53be5860ea1cb3d1f7d0f3eebf679a5fe935864 Mon Sep 17 00:00:00 2001 From: Greg Neagle Date: Tue, 26 May 2020 10:46:16 -0700 Subject: [PATCH] Clear bootstrap mode if there are no Munki updates and no Apple updates we can actually install without user help. --- code/client/managedsoftwareupdate | 14 ++++++++++++++ code/client/munkilib/appleupdates/au.py | 23 +++++++++++++++++++++++ code/client/munkilib/appleupdates/core.py | 6 ++++++ 3 files changed, 43 insertions(+) diff --git a/code/client/managedsoftwareupdate b/code/client/managedsoftwareupdate index fcb5a53c..4401c955 100755 --- a/code/client/managedsoftwareupdate +++ b/code/client/managedsoftwareupdate @@ -991,6 +991,20 @@ def main(): options.installonly = False options.auto = True + if runtype == 'checkandinstallatstartup': + # we're in bootstrap mode + if not updatesavailable and appleupdatesavailable: + # there are only Apple updates, but we might not be able to install + # some + if not appleupdates.installableUpdates(): + # there are no Apple updates we can actually install without + # user assistance, so clear bootstrapping mode so we don't loop + # endlessly + try: + bootstrapping.clear_bootstrap_mode() + except bootstrapping.SetupError as err: + display.display_error(err) + if updatesavailable or appleupdatesavailable: if options.installonly or options.logoutinstall: # just install diff --git a/code/client/munkilib/appleupdates/au.py b/code/client/munkilib/appleupdates/au.py index a25b41a4..2dbf0e56 100644 --- a/code/client/munkilib/appleupdates/au.py +++ b/code/client/munkilib/appleupdates/au.py @@ -494,6 +494,29 @@ class AppleUpdates(object): display.display_info(' *Logout required') reports.report['LogoutRequired'] = True + def installable_updates(self): + """Returns a list of installable Apple updates. + This may filter out updates that require a restart.""" + try: + pl_dict = FoundationPlist.readPlist(self.apple_updates_plist) + except FoundationPlist.FoundationPlistException: + # can't read it or it doesn't exist, therefore no installable + # updates + return [] + apple_updates = pl_dict.get('AppleUpdates', []) + os_version_tuple = osutils.getOsVersion(as_tuple=True) + if os_version_tuple >= (10, 14): + # in Mojave and Catalina (and perhaps beyond), it's too risky to + # install OS or Security updates because softwareupdate is just + # not reliable at this any longer. So filter out updates that + # require a restart + filtered_apple_updates = [ + item for item in apple_updates + if item.get('RestartAction', 'None') == 'None' + ] + return filtered_apple_updates + return apple_updates + def install_apple_updates(self, only_unattended=False): """Uses softwareupdate to install previously downloaded updates. diff --git a/code/client/munkilib/appleupdates/core.py b/code/client/munkilib/appleupdates/core.py index c24e6f7b..b8b25daa 100644 --- a/code/client/munkilib/appleupdates/core.py +++ b/code/client/munkilib/appleupdates/core.py @@ -74,6 +74,12 @@ def appleSoftwareUpdatesAvailable(forcecheck=False, suppresscheck=False, force_check=forcecheck, suppress_check=suppresscheck) +def installableUpdates(): + """Returns the list of installable updates, which might not include updates + that require a restart""" + return getAppleUpdatesInstance().installable_updates() + + def displayAppleUpdateInfo(): """Method for drop-in appleupdates replacement; see primary method docs.""" getAppleUpdatesInstance().display_apple_update_info()