From b5bc93bf8dd0ff8167dd1e3105f6e7dd310ea9c4 Mon Sep 17 00:00:00 2001 From: Greg Neagle Date: Fri, 6 Feb 2015 08:52:40 -0800 Subject: [PATCH] Make MSC responsible for triggering a restart if needed and GUI user is present to avoid process synchronization issues --- .../MSCStatusController.py | 4 +++- .../Managed Software Center/munki.py | 19 +++++++++++++++++++ .../MunkiStatus/MSUStatusWindowController.py | 4 ++++ code/apps/MunkiStatus/MunkiStatus/munki.py | 2 +- code/client/managedsoftwareupdate | 14 ++++++++++---- 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/code/apps/Managed Software Center/Managed Software Center/MSCStatusController.py b/code/apps/Managed Software Center/Managed Software Center/MSCStatusController.py index f5692de28..efe14fd94 100644 --- a/code/apps/Managed Software Center/Managed Software Center/MSCStatusController.py +++ b/code/apps/Managed Software Center/Managed Software Center/MSCStatusController.py @@ -156,6 +156,8 @@ def updateStatus_(self, notification): #NSApp.activateIgnoringOtherApps_(YES) #? do we really want to do this? #self.statusWindowController.window().orderFrontRegardless() elif command == 'showRestartAlert': + if self.session_started: + self.sessionEnded_(0) self.doRestartAlert() elif command == 'quit': self.sessionEnded_(0) @@ -223,7 +225,7 @@ def restartAlertDidEnd_returnCode_contextInfo_( self, alert, returncode, contextinfo): '''Called when restartAlert ends''' self._status_restartAlertDismissed = 1 - # TO-DO: initiate actual restart + munki.restartNow() def setMessage_(self, messageText): '''Display main status message''' diff --git a/code/apps/Managed Software Center/Managed Software Center/munki.py b/code/apps/Managed Software Center/Managed Software Center/munki.py index 28c62f5a7..b39c60f57 100644 --- a/code/apps/Managed Software Center/Managed Software Center/munki.py +++ b/code/apps/Managed Software Center/Managed Software Center/munki.py @@ -46,6 +46,25 @@ def call(cmd): (output, err) = proc.communicate() return proc.returncode + +def osascript(osastring): + """Wrapper to run AppleScript commands""" + cmd = ['/usr/bin/osascript', '-e', osastring] + proc = subprocess.Popen(cmd, shell=False, bufsize=1, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (out, err) = proc.communicate() + if proc.returncode != 0: + print >> sys.stderr, 'Error: ', err + if out: + return str(out).decode('UTF-8').rstrip('\n') + + +def restartNow(): + '''Trigger a restart''' + osascript('tell application "System Events" to restart') + + BUNDLE_ID = u'ManagedInstalls' def reload_prefs(): diff --git a/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py b/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py index f81e17b43..d4d2b3e57 100644 --- a/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py +++ b/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py @@ -290,6 +290,10 @@ def updateStatus_(self, notification): if command == 'activate': self.window.orderFrontRegardless() elif command == 'showRestartAlert': + # clean up timer + if self.timer: + self.timer.invalidate() + self.timer = None self.doRestartAlert() elif command == 'quit': self.cleanUpStatusSession() diff --git a/code/apps/MunkiStatus/MunkiStatus/munki.py b/code/apps/MunkiStatus/MunkiStatus/munki.py index 072697a57..2dc97319a 100644 --- a/code/apps/MunkiStatus/MunkiStatus/munki.py +++ b/code/apps/MunkiStatus/MunkiStatus/munki.py @@ -23,6 +23,7 @@ import os import stat import subprocess +from SystemConfiguration import SCDynamicStoreCopyConsoleUser INSTALLATLOGOUTFILE = "/private/tmp/com.googlecode.munki.installatlogout" @@ -36,7 +37,6 @@ def call(cmd): def getconsoleuser(): - from SystemConfiguration import SCDynamicStoreCopyConsoleUser cfuser = SCDynamicStoreCopyConsoleUser( None, None, None ) return cfuser[0] diff --git a/code/client/managedsoftwareupdate b/code/client/managedsoftwareupdate index 938342dec..5ecf4ec37 100755 --- a/code/client/managedsoftwareupdate +++ b/code/client/managedsoftwareupdate @@ -272,13 +272,19 @@ def doRestart(): dummy_retcode = subprocess.call(['/sbin/shutdown', '-r', 'now']) else: if munkicommon.munkistatusoutput: - # someone is logged in and we're using munkistatus + # someone is logged in and we're using Managed Software Center. + # We need to notifiy the active user that a restart is required. + # We actually should almost never get here; generally Munki knows + # a restart is needed before even starting the updates and forces + # a logout before applying the updates munkicommon.display_info( 'Notifying currently logged-in user to restart.') munkistatus.activate() munkistatus.restartAlert() - munkicommon.osascript( - 'tell application "System Events" to restart') + # Managed Software Center will trigger a restart + # when the alert is dismissed. If a user gets clever and subverts + # this restart (perhaps by force-quitting the app), + # that's their problem... else: print 'Please restart immediately.' @@ -357,7 +363,7 @@ def sendStartNotification(): def sendEndNotification(): - '''Sends a start notification via NSDistributedNotificationCenter''' + '''Sends an ended notification via NSDistributedNotificationCenter''' userInfo = {'pid': os.getpid()} sendDistrubutedNotification( 'com.googlecode.munki.managedsoftwareupdate.ended',