Merged with munki master; manually resolved 'munkiimport' merge conflicts

This commit is contained in:
Heig Gregorian
2013-02-12 10:00:12 -08:00
9 changed files with 445 additions and 218 deletions

View File

@@ -66,8 +66,8 @@ class MSUAppDelegate(NSObject):
NSLog("MSU GUI version: %s" % ver)
munki.log("MSU", "launched", "VER=%s" % ver)
runmode = NSUserDefaults.standardUserDefaults().stringForKey_("mode") or \
os.environ.get("ManagedSoftwareUpdateMode")
runmode = (NSUserDefaults.standardUserDefaults().stringForKey_("mode")
or os.environ.get("ManagedSoftwareUpdateMode"))
if runmode:
self.runmode = runmode
NSLog("Runmode: %s" % runmode)
@@ -81,8 +81,8 @@ class MSUAppDelegate(NSObject):
if NSApp.respondsToSelector_('disableRelaunchOnLogin'):
NSApp.disableRelaunchOnLogin()
# register for notification messages so we can be told if available updates
# change while we are open
# register for notification messages so we can be told if available
# updates change while we are open
notification_center = NSDistributedNotificationCenter.defaultCenter()
notification_center.addObserver_selector_name_object_suspensionBehavior_(
self,
@@ -199,7 +199,8 @@ class MSUAppDelegate(NSObject):
alertMessageText = NSLocalizedString(u"Update check failed", None)
if self.managedsoftwareupdate_task == "installwithnologout":
alertMessageText = NSLocalizedString(u"Install session failed", None)
alertMessageText = NSLocalizedString(
u"Install session failed", None)
if socketSessionResult == -1:
# connection was dropped unexpectedly
@@ -209,9 +210,13 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Quit", None),
objc.nil,
objc.nil,
NSLocalizedString(u"There is a configuration problem with the managed software installer. The process ended unexpectedly. Contact your systems administrator.", None))
NSLocalizedString(
(u"There is a configuration problem with the managed "
"software installer. The process ended unexpectedly. "
"Contact your systems administrator."), None))
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
return
elif socketSessionResult == -2:
@@ -222,9 +227,13 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Quit", None),
objc.nil,
objc.nil,
NSLocalizedString(u"There is a configuration problem with the managed software installer. Could not start the process. Contact your systems administrator.", None))
NSLocalizedString(
(u"There is a configuration problem with the managed "
"software installer. Could not start the process. "
"Contact your systems administrator."), None))
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
return
if self.managedsoftwareupdate_task == "installwithnologout":
@@ -260,9 +269,13 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Quit", None),
objc.nil,
objc.nil,
NSLocalizedString(u"Managed Software Update cannot contact the update server at this time.\nIf this situation continues, contact your systems administrator.", None))
NSLocalizedString(
(u"Managed Software Update cannot contact the update "
"server at this time.\nIf this situation continues, "
"contact your systems administrator."), None))
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
elif lastCheckResult == -2:
munki.log("MSU", "cant_update", "failed preflight")
alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
@@ -270,9 +283,12 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Quit", None),
objc.nil,
objc.nil,
NSLocalizedString(u"Managed Software Update failed its preflight check.\nTry again later.", None))
NSLocalizedString(
(u"Managed Software Update failed its preflight "
"check.\nTry again later."), None))
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
def noUpdatesAlert(self):
if self._optionalInstalls:
@@ -281,7 +297,9 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Quit", None),
NSLocalizedString(u"Optional software...", None),
NSLocalizedString(u"Check again", None),
NSLocalizedString(u"There is no new software for your computer at this time.", None))
NSLocalizedString(
u"There is no new software for your computer at this time.",
None))
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
else:
@@ -290,9 +308,12 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Quit", None),
objc.nil,
NSLocalizedString(u"Check again", None),
NSLocalizedString(u"There is no new software for your computer at this time.", None))
NSLocalizedString(
u"There is no new software for your computer at this time.",
None))
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
def checkForUpdates(self):
@@ -321,9 +342,13 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Quit", None),
objc.nil,
objc.nil,
NSLocalizedString(u"There is a configuration problem with the managed software installer. Could not start the update check process. Contact your systems administrator.", None))
NSLocalizedString(
(u"There is a configuration problem with the managed "
"software installer. Could not start the update check "
"process. Contact your systems administrator."), None))
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
def applicationDidBecomeActive_(self, sender):
pass
@@ -349,70 +374,78 @@ class MSUAppDelegate(NSObject):
def getAvailableUpdates(self):
updatelist = []
installinfo = munki.getInstallInfo()
munki_updates_contain_apple_items = \
munki.munkiUpdatesContainAppleItems()
if installinfo:
updatelist = installinfo.get("managed_installs", [])
for update in updatelist:
force_install_after_date = update.get('force_install_after_date')
if force_install_after_date:
# insert installation deadline into description
local_date = munki.discardTimeZoneFromDate(force_install_after_date)
date_str = munki.stringFromDate(local_date)
forced_date_text = NSLocalizedString(u"This item must be installed by ", None)
description = update["description"]
# prepend deadline info to description. This will fail if the description is HTML...
update["description"] = forced_date_text + date_str + "\n\n" + description
updatelist.extend(installinfo.get('managed_installs', []))
if not munki_updates_contain_apple_items:
appleupdates = munki.getAppleUpdates()
updatelist.extend(appleupdates.get("AppleUpdates", []))
for update in updatelist:
force_install_after_date = update.get(
'force_install_after_date')
if force_install_after_date:
# insert installation deadline into description
local_date = munki.discardTimeZoneFromDate(
force_install_after_date)
date_str = munki.stringFromDate(local_date)
forced_date_text = NSLocalizedString(
u"This item must be installed by ", None)
description = update["description"]
# prepend deadline info to description. This will fail if
# the description is HTML...
update["description"] = (forced_date_text + date_str
+ "\n\n" + description)
if installinfo.get("removals"):
removallist = installinfo.get("removals")
restartNeeded = False
logoutNeeded = False
showRemovalDetail = munki.getRemovalDetailPrefs()
for item in removallist:
restartAction = item.get("RestartAction")
if restartAction in ["RequireRestart", "RecommendRestart"]:
restartNeeded = True
if restartAction in ["RequireLogout", "RecommendLogout"]:
logoutNeeded = True
if showRemovalDetail:
item["display_name"] = ((item.get("display_name") or item.get("name", ""))
+ NSLocalizedString(u" (will be removed)", None))
item["description"] = NSLocalizedString(u"This item will be removed.", None)
updatelist.append(item)
if not showRemovalDetail:
row = {}
row["display_name"] = NSLocalizedString(u"Software removals", None)
row["version"] = ""
row["description"] = NSLocalizedString(u"Scheduled removal of managed software.", None)
if restartNeeded:
row["RestartAction"] = "RequireRestart"
elif logoutNeeded:
row["RestartAction"] = "RequireLogout"
updatelist.append(row)
if installinfo.get("removals"):
removallist = installinfo.get("removals")
restartNeeded = False
logoutNeeded = False
showRemovalDetail = munki.getRemovalDetailPrefs()
for item in removallist:
restartAction = item.get("RestartAction")
if restartAction in ["RequireRestart", "RecommendRestart"]:
restartNeeded = True
if restartAction in ["RequireLogout", "RecommendLogout"]:
logoutNeeded = True
if showRemovalDetail:
item["display_name"] = (
(item.get("display_name") or item.get("name", ""))
+ NSLocalizedString(u" (will be removed)", None))
item["description"] = NSLocalizedString(
u"This item will be removed.", None)
updatelist.append(item)
if not showRemovalDetail:
row = {}
row["display_name"] = NSLocalizedString(
u"Software removals", None)
row["version"] = ""
row["description"] = NSLocalizedString(
u"Scheduled removal of managed software.", None)
if restartNeeded:
row["RestartAction"] = "RequireRestart"
elif logoutNeeded:
row["RestartAction"] = "RequireLogout"
updatelist.append(row)
if updatelist:
self._sortUpdateList(updatelist)
#self._sortUpdateList(updatelist)
self._listofupdates = updatelist
self.enableUpdateNowBtn_(YES)
#self.performSelector_withObject_afterDelay_("enableUpdateNowBtn:", YES, 4)
#self.performSelector_withObject_afterDelay_(
# "enableUpdateNowBtn:", YES, 4)
self.getOptionalInstalls()
else:
appleupdates = munki.getAppleUpdates()
if appleupdates:
munki.log("MSU", "appleupdates")
self._listofupdates = appleupdates.get("AppleUpdates", [])
self.update_view_controller.updateNowBtn.setEnabled_(YES)
self.update_view_controller.optionalSoftwareBtn.setHidden_(YES)
else:
self._listofupdates = []
self.update_view_controller.updateNowBtn.setEnabled_(NO)
self.getOptionalInstalls()
self._listofupdates = []
self.update_view_controller.updateNowBtn.setEnabled_(NO)
self.getOptionalInstalls()
def buildOptionalInstallsData(self):
table = []
selfservedata = munki.readSelfServiceManifest()
selfserve_installs = selfservedata.get('managed_installs',[])
selfserve_uninstalls = selfservedata.get('managed_uninstalls',[])
selfserve_installs = selfservedata.get('managed_installs', [])
selfserve_uninstalls = selfservedata.get('managed_uninstalls', [])
for item in self._optionalInstalls:
row = {}
@@ -424,10 +457,12 @@ class MSUAppDelegate(NSObject):
row['original_managed'] = (item['name'] in selfserve_installs)
row['itemname'] = item['name']
row['name'] = item.get("display_name") or item['name']
row['version'] = munki.trimVersionString(item.get("version_to_install"))
row['version'] = munki.trimVersionString(
item.get("version_to_install"))
row['description'] = item.get("description", "")
if item.get("installer_item_size"):
row['size'] = munki.humanReadable(item.get("installer_item_size"))
row['size'] = munki.humanReadable(
item.get("installer_item_size"))
elif item.get("installed_size"):
row['size'] = munki.humanReadable(item.get("installed_size"))
else:
@@ -472,7 +507,8 @@ class MSUAppDelegate(NSObject):
# user selected for install
optional_install_choices['managed_installs'].append(row['itemname'])
elif row['original_managed']:
# was managed, but user deselected it; we should remove it if possible
# was managed, but user deselected it; we should remove it if
# possible
optional_install_choices['managed_uninstalls'].append(row['itemname'])
munki.writeSelfServiceManifest(optional_install_choices)
self.checkForUpdates()
@@ -485,18 +521,22 @@ class MSUAppDelegate(NSObject):
for item in self._listofupdates:
row = {}
row['image'] = self._emptyImage
if item.get("RestartAction") == "RequireRestart" or item.get("RestartAction") == "RecommendRestart":
if (item.get("RestartAction") == "RequireRestart"
or item.get("RestartAction") == "RecommendRestart"):
row['image'] = self._restartImage
self.restart_required = True
elif item.get("RestartAction") == "RequireLogout" or item.get("RestartAction") == "RecommendLogout":
elif (item.get("RestartAction") == "RequireLogout"
or item.get("RestartAction") == "RecommendLogout"):
row['image'] = self._logoutImage
self.logout_required = True
if item.get("force_install_after_date"):
row['image'] = self._exclamationImage
row['name'] = item.get("display_name") or item.get("name","")
row['version'] = munki.trimVersionString(item.get("version_to_install"))
row['version'] = munki.trimVersionString(
item.get("version_to_install"))
if item.get("installer_item_size"):
row['size'] = munki.humanReadable(item.get("installer_item_size"))
row['size'] = munki.humanReadable(
item.get("installer_item_size"))
elif item.get("installed_size"):
row['size'] = munki.humanReadable(item.get("installed_size"))
else:
@@ -510,18 +550,21 @@ class MSUAppDelegate(NSObject):
if self.restart_required:
self.update_view_controller.restartInfoFld.setStringValue_(
NSLocalizedString(u"Restart will be required.", None))
self.update_view_controller.restartImageFld.setImage_(self._restartImage)
self.update_view_controller.restartImageFld.setImage_(
self._restartImage)
elif self.logout_required:
self.update_view_controller.restartInfoFld.setStringValue_(
NSLocalizedString(u"Logout will be required.", None))
self.update_view_controller.restartImageFld.setImage_(self._logoutImage)
self.update_view_controller.restartImageFld.setImage_(
self._logoutImage)
def forcedLogoutWarning(self, notification_obj):
NSApp.activateIgnoringOtherApps_(True)
info = notification_obj.userInfo()
moreText = NSLocalizedString(
u"\nAll pending updates will be installed. Unsaved work will be lost.\nYou may avoid the forced logout by logging out now.", None)
(u"\nAll pending updates will be installed. Unsaved work will be "
"lost.\nYou may avoid the forced logout by logging out now."), None)
logout_time = None
if info:
logout_time = info.get('logout_time')
@@ -533,13 +576,19 @@ class MSUAppDelegate(NSObject):
if time_til_logout > 55:
deadline_str = munki.stringFromDate(logout_time)
munki.log("user", "forced_logout_warning_initial")
infoText = NSLocalizedString(u"A logout will be forced at approximately %s.", None) % deadline_str + moreText
formatString = NSLocalizedString(
u"A logout will be forced at approximately %s.", None)
infoText = formatString % deadline_str + moreText
elif time_til_logout > 0:
munki.log("user", "forced_logout_warning_%s" % time_til_logout)
infoText = NSLocalizedString(u"A logout will be forced in less than %s minutes.", None) % time_til_logout + moreText
formatString = NSLocalizedString(
u"A logout will be forced in less than %s minutes.", None)
infoText = formatString % time_til_logout + moreText
else:
munki.log("user", "forced_logout_warning_final")
infoText = NSLocalizedString(u"A logout will be forced in less than a minute.\nAll pending updates will be installed. Unsaved work will be lost.", None)
infoText = NSLocalizedString(
(u"A logout will be forced in less than a minute.\nAll pending "
"updates will be installed. Unsaved work will be lost."), None)
# Set the OK button to default, unless less than 5 minutes to logout
# in which case only the Logout button should be displayed.
@@ -561,7 +610,8 @@ class MSUAppDelegate(NSObject):
NSApp.endSheet_(self._currentAlert.window())
self._currentAlert = None
alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
NSLocalizedString(u"Forced Logout for Mandatory Install", None),
NSLocalizedString(
u"Forced Logout for Mandatory Install", None),
self._force_warning_btns[NSAlertDefaultReturn],
self._force_warning_btns[NSAlertAlternateReturn],
objc.nil,
@@ -576,9 +626,14 @@ class MSUAppDelegate(NSObject):
time_til_logout = deadline.timeIntervalSinceNow()
if time_til_logout > 0:
deadline_str = munki.stringFromDate(deadline)
infoText = NSLocalizedString("One or more updates must be installed by %s. A logout may be forced if you wait too long to update.", None) % deadline_str
formatString = NSLocalizedString(
(u"One or more updates must be installed by %s. A logout "
"may be forced if you wait too long to update."), None)
infoText = formatString % deadline_str
else:
infoText = NSLocalizedString("One or more mandatory updates are overdue for installation. A logout will be forced soon.", None)
infoText = NSLocalizedString(
(u"One or more mandatory updates are overdue for "
"installation. A logout will be forced soon."), None)
alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
NSLocalizedString(u"Manadatory Updates Pending", None),
NSLocalizedString(u"Show updates", None),
@@ -587,7 +642,8 @@ class MSUAppDelegate(NSObject):
infoText)
self._currentAlert = alert
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.confirmLaterAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.confirmLaterAlertDidEnd_returnCode_contextInfo_, objc.nil)
else:
munki.log("user", "exit_later_clicked")
NSApp.terminate_(self)
@@ -601,7 +657,11 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Cancel", None),
objc.nil,
objc.nil,
NSLocalizedString("There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out.", None))
NSLocalizedString(
(u"There are other users logged into this computer.\n"
"Updating now could cause other users to lose their "
"work.\n\nPlease try again later after the other users "
"have logged out."), None))
self._currentAlert = alert
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.multipleUserAlertDidEnd_returnCode_contextInfo_, objc.nil)
@@ -611,17 +671,24 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Logout and update", None),
NSLocalizedString(u"Cancel", None),
objc.nil,
NSLocalizedString(u"A restart is required after updating. Please be patient as there may be a short delay at the login window. Logout and update now?", None))
NSLocalizedString(
(u"A restart is required after updating. Please be patient "
"as there may be a short delay at the login window. Logout "
"and update now?"), None))
self._currentAlert = alert
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil)
elif self.logout_required or munki.installRequiresLogout():
alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
NSLocalizedString(u"Logout Required", None),
NSLocalizedString(u"Logout and update", None),
NSLocalizedString(u"Cancel", None),
objc.nil,
NSLocalizedString(u"A logout is required before updating. Please be patient as there may be a short delay at the login window. Logout and update now?", None))
NSLocalizedString(
(u"A logout is required before updating. Please be patient "
"as there may be a short delay at the login window. Logout "
"and update now?"), None))
self._currentAlert = alert
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil)
@@ -631,10 +698,14 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Logout and update", None),
NSLocalizedString(u"Cancel", None),
NSLocalizedString(u"Update without logging out", None),
NSLocalizedString(u"A logout is recommended before updating. Please be patient as there may be a short delay at the login window. Logout and update now?", None))
NSLocalizedString(
(u"A logout is recommended before updating. Please be "
"patient as there may be a short delay at the login "
"window. Logout and update now?"), None))
self._currentAlert = alert
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil)
def alertIfBlockingAppsRunning(self):
@@ -650,15 +721,21 @@ class MSUAppDelegate(NSObject):
running_apps = munki.getRunningBlockingApps(apps_to_check)
if running_apps:
alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
NSLocalizedString(u"Conflicting applications running", None),
NSLocalizedString(
u"Conflicting applications running", None),
NSLocalizedString(u"OK", None),
objc.nil,
objc.nil,
NSLocalizedString(u"You must quit the following applications before proceeding with installation:\n\n%s", None) % '\n'.join(running_apps))
NSLocalizedString(
(u"You must quit the following applications before "
"proceeding with installation:\n\n%s"), None)
% '\n'.join(running_apps))
munki.log("MSU", "conflicting_apps", ','.join(running_apps))
self._currentAlert = alert
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.blockingAppsRunningAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.blockingAppsRunningAlertDidEnd_returnCode_contextInfo_,
objc.nil)
return True
else:
return False
@@ -669,16 +746,20 @@ class MSUAppDelegate(NSObject):
if (power_info.get('PowerSource') == 'Battery Power'
and power_info.get('BatteryCharge', 0) < 50):
alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
NSLocalizedString(u"Your computer is not connected to a power source.", None),
NSLocalizedString(u"Continue", None),
NSLocalizedString(u"Cancel", None),
objc.nil,
NSLocalizedString(u"For best results, you should connect your computer to a power source before updating. Are you sure you want to continue the update?", None))
NSLocalizedString(
u"Your computer is not connected to a power source.", None),
NSLocalizedString(u"Continue", None),
NSLocalizedString(u"Cancel", None),
objc.nil,
NSLocalizedString(
(u"For best results, you should connect your computer to a "
"power source before updating. Are you sure you want to "
"continue the update?"), None))
munki.log("MSU", "alert_on_battery_power")
# making UI consistent with Apple Software Update...
# set Cancel button to be activated by return key
alert.buttons()[1].setKeyEquivalent_('\r')
# set Ccontinue button to be activated by Escape key
# set Continue button to be activated by Escape key
alert.buttons()[0].setKeyEquivalent_(chr(27))
buttonPressed = alert.runModal()
if buttonPressed == NSAlertAlternateReturn:
@@ -692,15 +773,20 @@ class MSUAppDelegate(NSObject):
NSLocalizedString(u"Quit", None),
objc.nil,
objc.nil,
NSLocalizedString(u"There is a configuration problem with the managed software installer. Could not start the install session. Contact your systems administrator.", None))
NSLocalizedString(
(u"There is a configuration problem with the managed "
"software installer. Could not start the install session. "
"Contact your systems administrator."), None))
munki.log("MSU", "cannot_start")
self._currentAlert = alert
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
self.mainWindowController.theWindow, self,
self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil)
@PyObjCTools.AppHelper.endSheetMethod
def logoutAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo):
def logoutAlertDidEnd_returnCode_contextInfo_(
self, alert, returncode, contextinfo):
self._currentAlert = None
if returncode == NSAlertDefaultReturn:
if self.alertIfRunnningOnBattery():
@@ -736,17 +822,20 @@ class MSUAppDelegate(NSObject):
@PyObjCTools.AppHelper.endSheetMethod
def blockingAppsRunningAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo):
def blockingAppsRunningAlertDidEnd_returnCode_contextInfo_(
self, alert, returncode, contextinfo):
self._currentAlert = None
@PyObjCTools.AppHelper.endSheetMethod
def multipleUserAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo):
def multipleUserAlertDidEnd_returnCode_contextInfo_(
self, alert, returncode, contextinfo):
self._currentAlert = None
@PyObjCTools.AppHelper.endSheetMethod
def confirmLaterAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo):
def confirmLaterAlertDidEnd_returnCode_contextInfo_(
self, alert, returncode, contextinfo):
self._currentAlert = None
if returncode == NSAlertAlternateReturn:
munki.log("user", "exit_later_clicked")
@@ -754,7 +843,8 @@ class MSUAppDelegate(NSObject):
@PyObjCTools.AppHelper.endSheetMethod
def forceLogoutWarningDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo):
def forceLogoutWarningDidEnd_returnCode_contextInfo_(
self, alert, returncode, contextinfo):
self._currentAlert = None
btn_pressed = self._force_warning_btns.get(returncode)
if btn_pressed == self._force_warning_logout_btn:
@@ -765,7 +855,8 @@ class MSUAppDelegate(NSObject):
@PyObjCTools.AppHelper.endSheetMethod
def quitAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo):
def quitAlertDidEnd_returnCode_contextInfo_(
self, alert, returncode, contextinfo):
self._currentAlert = None
if returncode == NSAlertDefaultReturn:
munki.log("user", "quit")

View File

@@ -24,7 +24,7 @@
<key>pfm_default</key>
<false/>
<key>pfm_description</key>
<string>Set to true to only install updates from an Apple Software Update server. No munki repository is needed or used.</string>
<string>Set to true to only install updates from an Apple Software Update server. No Munki repository is needed or used.</string>
<key>pfm_targets</key>
<array>
<string>system-managed</string>
@@ -40,7 +40,7 @@
<key>pfm_default</key>
<false/>
<key>pfm_description</key>
<string>Set to true to install updates from an Apple Software Update server, in addition to "regular" munki updates.</string>
<string>Set to true to install updates from an Apple Software Update server, in addition to "regular" Munki updates.</string>
<key>pfm_targets</key>
<array>
<string>system-managed</string>
@@ -72,7 +72,7 @@
<key>pfm_default</key>
<string>http://munki/repo</string>
<key>pfm_description</key>
<string>Base URL for munki repository</string>
<string>Base URL for Munki repository</string>
<key>pfm_targets</key>
<array>
<string>system-managed</string>
@@ -88,7 +88,7 @@
<key>pfm_default</key>
<string>http://munki/repo/pkgs</string>
<key>pfm_description</key>
<string>Base URL for munki pkgs.
<string>Base URL for Munki pkgs.
Useful if your packages are served from a different server than your catalogs or manifests.</string>
<key>pfm_targets</key>
<array>
@@ -105,7 +105,7 @@ Useful if your packages are served from a different server than your catalogs or
<key>pfm_default</key>
<string>http://munki/repo/catalogs</string>
<key>pfm_description</key>
<string>Base URL for munki catalogs.
<string>Base URL for Munki catalogs.
Useful if your catalogs are served from a different server than your packages or manifests.</string>
<key>pfm_targets</key>
<array>
@@ -122,7 +122,7 @@ Useful if your catalogs are served from a different server than your packages or
<key>pfm_default</key>
<string>http://munki/repo/manifests</string>
<key>pfm_description</key>
<string>Base URL for munki manifests.
<string>Base URL for Munki manifests.
Useful if your manifests are served from a different server than your catalogs or packages.</string>
<key>pfm_targets</key>
<array>
@@ -139,7 +139,7 @@ Useful if your manifests are served from a different server than your catalogs o
<key>pfm_default</key>
<string></string>
<key>pfm_description</key>
<string>Identifier for munki client. Usually is the same as a manifest name on the munki server.</string>
<string>Identifier for Munki client. Usually is the same as a manifest name on the Munki server.</string>
<key>pfm_targets</key>
<array>
<string>system-managed</string>
@@ -155,7 +155,7 @@ Useful if your manifests are served from a different server than your catalogs o
<key>pfm_default</key>
<string>/Library/Managed Installs</string>
<key>pfm_description</key>
<string>Folder where munki keeps its data on the client.</string>
<string>Folder where Munki keeps its data on the client.</string>
<key>pfm_targets</key>
<array>
<string>system-managed</string>
@@ -220,8 +220,8 @@ Set to 0 to have Managed Software Update notify every time a background check ru
<key>pfm_default</key>
<false/>
<key>pfm_description</key>
<string>Set to true to cause munki to use an SSL client certificate when communicating with the munki server.
Requires an https:// URL for the munki repo.
<string>Set to true to cause Munki to use an SSL client certificate when communicating with the Munki server.
Requires an https:// URL for the Munki repo.
Client cert should be named "munki.pem" and stored in a "certs" directory in the Managed Installs folder (typically /Library/Managed Installs).</string>
<key>pfm_targets</key>
<array>
@@ -238,7 +238,7 @@ Client cert should be named "munki.pem" and stored in a "certs" directory in the
<key>pfm_default</key>
<false/>
<key>pfm_description</key>
<string>Set to true to cause munki to use the CN of the client certificate as the Client Identifier.
<string>Set to true to cause Munki to use the CN of the client certificate as the Client Identifier.
Used in combination with the UseClientCertificate key.</string>
<key>pfm_targets</key>
<array>
@@ -291,7 +291,7 @@ AdditionalHttpHeaders must be an array of strings with valid HTTP header format.
<string>hash-strict</string>
</array>
<key>pfm_description</key>
<string>Controls how munki verifies the integrity of downloaded packages.
<string>Controls how Munki verifies the integrity of downloaded packages.
Possible values are:
none: No integrity check is performed.
hash: Integrity check is performed if package info contains checksum information.
@@ -322,13 +322,29 @@ Managed Software Update can still be manually invoked to discover and install up
<key>pfm_name</key>
<string>SuppressAutoInstall</string>
<key>pfm_title</key>
<string>Suppress Auto Install at loginwindow</string>
<string>Suppress Auto Install</string>
<key>pfm_type</key>
<string>boolean</string>
<key>pfm_default</key>
<false/>
<key>pfm_description</key>
<string>If true, munki will not automatically install when the machine has no users logged in.</string>
<string>If true, Munki will not automatically install any item.</string>
<key>pfm_targets</key>
<array>
<string>system-managed</string>
</array>
</dict>
<dict>
<key>pfm_name</key>
<string>SuppressLoginwindowInstall</string>
<key>pfm_title</key>
<string>Suppress Automatic Install at loginwindow</string>
<key>pfm_type</key>
<string>boolean</string>
<key>pfm_default</key>
<false/>
<key>pfm_description</key>
<string>If true, Munki will not automatically install when the machine has no users logged in.</string>
<key>pfm_targets</key>
<array>
<string>system-managed</string>

View File

@@ -190,6 +190,20 @@ def getInstallInfo():
return plist
def munkiUpdatesContainAppleItems():
"""Return True if there are any Apple items in the list of updates"""
installinfo = getInstallInfo()
# check managed_installs
for item in installinfo.get('managed_installs', []):
if item.get('apple_item'):
return True
# check removals
for item in installinfo.get('removals', []):
if item.get('apple_item'):
return True
return False
def thereAreUpdatesToBeForcedSoon(hours=72):
'''Return True if any updates need to be installed within the next
X hours, false otherwise'''

View File

@@ -169,20 +169,20 @@ def runScript(script, display_name, runtype):
try:
utils.verifyFileOnlyWritableByMunkiAndRoot(script)
except utils.VerifyFilePermissionsError, e:
except utils.VerifyFilePermissionsError, err:
# preflight/postflight is insecure, but if the currently executing
# file is insecure too we are no worse off.
try:
utils.verifyFileOnlyWritableByMunkiAndRoot(__file__)
except utils.VerifyFilePermissionsError, e:
except utils.VerifyFilePermissionsError, err:
# OK, managedsoftwareupdate is insecure anyway - warn & execute.
munkicommon.display_warning('Multiple munki executable scripts '
'have insecure file permissions. Executing '
'%s anyway. Error: %s' % (display_name, e))
'%s anyway. Error: %s' % (display_name, err))
else:
# Just the preflight/postflight is insecure. Do not execute.
munkicommon.display_warning('Skipping execution of %s due to '
'insecure file permissions. Error: %s' % (display_name, e))
'insecure file permissions. Error: %s' % (display_name, err))
return result
try:
@@ -197,16 +197,17 @@ def runScript(script, display_name, runtype):
munkicommon.display_info('%s stderr: %s' % (display_name, stderr))
except utils.ScriptNotFoundError:
pass # script is not required, so pass
except utils.RunExternalScriptError, e:
munkicommon.display_warning(str(e))
except utils.RunExternalScriptError, err:
munkicommon.display_warning(str(err))
return result
def doInstallTasks(only_unattended=False):
def doInstallTasks(do_apple_updates, only_unattended=False):
"""Perform our installation/removal tasks.
Args:
only_unattended: Boolean. If True, only do unattended_(un)install items.
do_apple_updates: Boolean. If True, install Apple updates
only_unattended: Boolean. If True, only do unattended_(un)install items.
Returns:
Boolean. True if a restart is required, False otherwise.
@@ -218,31 +219,20 @@ def doInstallTasks(only_unattended=False):
clearLastNotifiedDate()
need_to_restart = False
# munki updates take priority over Apple Updates, because
# a munki install or (especially) removal could make a
# pending Apple update no longer necessary or even complicate
# or prevent the removal of another item.
# Therefore we only install Apple updates if there are no
# pending munki updates.
if munkiUpdatesAvailable():
# install munki updates
try:
need_to_restart = installer.run(only_unattended=only_unattended)
except:
munkicommon.display_error(
'Unexpected error in munkilib.installer:')
munkicommon.display_error('Unexpected error in munkilib.installer:')
munkicommon.log(traceback.format_exc())
munkicommon.savereport()
raise
# clear any Apple update info since it may no longer
# be relevant
if not only_unattended:
appleupdates.clearAppleUpdateInfo()
elif ((munkicommon.pref('InstallAppleSoftwareUpdates') or
munkicommon.pref('AppleSoftwareUpdatesOnly'))
and not only_unattended):
if do_apple_updates and not only_unattended:
# (note we do not currently support doing Apple updates
# as unattended_installs. Support may be added in the future)
# are we supposed to handle Apple Software Updates?
try:
need_to_restart = appleupdates.installAppleUpdates()
@@ -317,6 +307,28 @@ def munkiUpdatesAvailable():
munkicommon.display_error('Install info at %s is invalid.' %
installinfo)
return updatesavailable
def munkiUpdatesContainAppleItems():
"""Return True if there are any Apple items in the list of updates"""
installinfo = os.path.join(munkicommon.pref('ManagedInstallDir'),
'InstallInfo.plist')
if os.path.exists(installinfo):
try:
plist = FoundationPlist.readPlist(installinfo)
except FoundationPlist.NSPropertyListSerializationException:
munkicommon.display_error('Install info at %s is invalid.' %
installinfo)
else:
# check managed_installs
for item in plist.get('managed_installs', []):
if item.get('apple_item'):
return True
# check removals
for item in plist.get('removals', []):
if item.get('apple_item'):
return True
return False
def recordUpdateCheckResult(result):
@@ -557,7 +569,7 @@ def main():
munkicommon.log("### Starting managedsoftwareupdate run: %s ###" % runtype)
if options.verbose:
print 'Managed Software Update Tool'
print 'Copyright 2010-2012 The Munki Project'
print 'Copyright 2010-2013 The Munki Project'
print 'http://code.google.com/p/munki\n'
munkicommon.display_status_major('Starting...')
@@ -660,43 +672,63 @@ def main():
if updatecheckresult is not None:
recordUpdateCheckResult(updatecheckresult)
updatesavailable = munkiUpdatesAvailable()
appleupdatesavailable = False
if (not updatesavailable and not options.installonly and
not munkicommon.stopRequested()):
# if there are no munki updates,
# are we supposed to check for and install Apple Software Updates?
if ((munkicommon.pref('InstallAppleSoftwareUpdates') or
applesoftwareupdatesonly) and not options.munkipkgsonly):
# should we do Apple Software updates this run?
if applesoftwareupdatesonly:
# admin told us to only do Apple updates this run
should_do_apple_updates = True
elif options.munkipkgsonly:
# admin told us to skip Apple updates for this run
should_do_apple_updates = False
elif munkiUpdatesContainAppleItems():
# shouldn't run Software Update if we're doing Apple items
# with Munki items
should_do_apple_updates = False
else:
# check the normal preferences
should_do_apple_updates = munkicommon.pref(
'InstallAppleSoftwareUpdates')
if should_do_apple_updates:
if (not options.installonly and not munkicommon.stopRequested()):
force_update_check = False
if (options.manualcheck or runtype == 'checkandinstallatstartup'):
force_update_check = True
if (runtype == 'custom' and applesoftwareupdatesonly):
force_update_check = True
try:
appleupdatesavailable = \
appleupdates.appleSoftwareUpdatesAvailable(
forcecheck=(options.manualcheck or
runtype == 'checkandinstallatstartup' or
(runtype == 'custom' and
applesoftwareupdatesonly)))
forcecheck=force_update_check)
except:
munkicommon.display_error('Unexpected error in appleupdates:')
munkicommon.log(traceback.format_exc())
munkicommon.savereport()
raise
if (not updatesavailable and options.installonly and
not options.munkipkgsonly and
(munkicommon.pref('InstallAppleSoftwareUpdates') or
applesoftwareupdatesonly)):
# just look and see if there are already downloaded Apple updates
# to install; don't run softwareupdate to check with Apple
try:
appleupdatesavailable = \
appleupdates.appleSoftwareUpdatesAvailable(suppresscheck=True)
except:
munkicommon.display_error('Unexpected error in appleupdates:')
munkicommon.log(traceback.format_exc())
munkicommon.savereport()
raise
if options.installonly:
# just look and see if there are already downloaded Apple updates
# to install; don't run softwareupdate to check with Apple
try:
appleupdatesavailable = \
appleupdates.appleSoftwareUpdatesAvailable(
suppresscheck=True)
except:
munkicommon.display_error('Unexpected error in appleupdates:')
munkicommon.log(traceback.format_exc())
munkicommon.savereport()
raise
if not options.installonly:
# display any available update information
if updatecheckresult:
updatecheck.displayUpdateInfo()
if appleupdatesavailable:
appleupdates.displayAppleUpdateInfo()
# send a notification event so MSU can update its display
# if needed
sendUpdateNotification()
@@ -708,7 +740,7 @@ def main():
if updatesavailable or appleupdatesavailable:
if options.installonly or options.logoutinstall:
# just install
mustrestart = doInstallTasks()
mustrestart = doInstallTasks(appleupdatesavailable)
elif options.auto:
if not munkicommon.currentGUIusers(): # no GUI users
if munkicommon.pref('SuppressAutoInstall'):
@@ -729,7 +761,7 @@ def main():
munkicommon.log('Installing only items marked unattended '
'because SuppressLoginwindowInstall is '
'true.')
doInstallTasks(only_unattended=True)
doInstallTasks(appleupdatesavailable, only_unattended=True)
elif getIdleSeconds() < 10:
munkicommon.log('Skipping auto install at loginwindow '
'because system is not idle '
@@ -738,7 +770,7 @@ def main():
# no GUI users, system is idle, so we can install
# but first, enable status output over login window
munkicommon.munkistatusoutput = True
mustrestart = doInstallTasks()
mustrestart = doInstallTasks(appleupdatesavailable)
else: # there are GUI users
if munkicommon.pref('SuppressAutoInstall'):
@@ -750,7 +782,7 @@ def main():
# don't require a logout
unused_action = updatecheck.checkForceInstallPackages()
# install anything that can be done unattended
doInstallTasks(only_unattended=True)
doInstallTasks(appleupdatesavailable, only_unattended=True)
# send a notification event so MSU can update its display
# if needed

View File

@@ -572,7 +572,8 @@ def configure():
('repo_url',
'Repo fileshare URL (example: afp://munki.example.com/repo)'),
('pkginfo_extension', 'pkginfo extension (Example: .plist)'),
('editor', 'pkginfo editor (examples: /usr/bin/vi or TextMate.app)')]:
('editor', 'pkginfo editor (examples: /usr/bin/vi or TextMate.app)'),
('default_catalog', 'Default catalog to use (example: testing)')]:
_prefs[key] = raw_input_with_default('%15s: ' % prompt, pref(key))
@@ -653,7 +654,7 @@ def main():
APPLEMETADATA = True
# Verify that arguments, presumed to be for
# 'makepkginfo' are valid and return installer_item
installer_item = makePkgInfo(arguments, True)
installer_item = makePkgInfo(options=arguments, test_mode=True)
if not installer_item and not APPLEMETADATA:
cleanupAndExit(-1)
@@ -686,7 +687,7 @@ def main():
exit(-1)
if not APPLEMETADATA:
if os.path.isdir(installer_item):
if os.path.isdir(installer_item): # Start of indent
if munkicommon.hasValidDiskImageExt(installer_item):
# a directory named foo.dmg or foo.iso!
print >> sys.stderr, '%s is an unknown type.' % installer_item
@@ -703,7 +704,13 @@ def main():
# append the installer_item to arguments which
# may have changed if bundle was wrapped into dmg
arguments.append(installer_item)
arguments.append(installer_item) # End of indent
# if catalog/catalogs have not been explictly specified via command-line,
# append our default catalog
if not '--catalog' in arguments and not '-c' in arguments:
default_catalog = pref('default_catalog') or 'testing'
arguments.extend(['--catalog', default_catalog])
pkginfo = makePkgInfo(arguments, False)
if not pkginfo:
# makepkginfo returned an error

View File

@@ -441,8 +441,8 @@ class AppleUpdates(object):
if fileurl.startswith('file://localhost'):
fileurl = fileurl[len('file://localhost'):]
pathname = urllib2.unquote(fileurl).rstrip('/')
appname = os.path.basename(pathname)
blocking_apps.append(appname)
executable = munkicommon.getAppBundleExecutable(pathname)
blocking_apps.append(executable or pathname)
return blocking_apps
@@ -721,7 +721,13 @@ class AppleUpdates(object):
munkicommon.display_info('Skipping Apple Software Update check '
'because sucatalog is unchanged, installed Apple packages are '
'unchanged and we recently did a full check.')
return False
#return False
# instead of returning False, return True if we have cached updates
# False otherwise
if self.GetSoftwareUpdateInfo():
return True
else:
return False
product_ids = self.GetAvailableUpdateProductIDs()
if not product_ids:
@@ -840,11 +846,13 @@ class AppleUpdates(object):
'Error reading: %s', self.apple_updates_plist)
return
apple_updates = pl_dict.get('AppleUpdates', [])
if apple_updates:
munkicommon.report['AppleUpdates'] = apple_updates
munkicommon.display_info(
'The following Apple Software Updates are available to '
'install:')
if not apple_updates:
munkicommon.display_info('No available Apple Software Updates.')
return
munkicommon.report['AppleUpdates'] = apple_updates
munkicommon.display_info(
'The following Apple Software Updates are available to '
'install:')
for item in apple_updates:
munkicommon.display_info(
' + %s-%s' % (
@@ -1264,11 +1272,8 @@ class AppleUpdates(object):
return False
if munkicommon.stopRequested():
return False
if self.WriteAppleUpdatesFile():
self.DisplayAppleUpdateInfo()
return True
else:
return False
return self.WriteAppleUpdatesFile()
def SoftwareUpdateList(self):
"""Returns a list of str update names using softwareupdate -l."""
@@ -1325,3 +1330,8 @@ def appleSoftwareUpdatesAvailable(forcecheck=False, suppresscheck=False):
"""Method for drop-in appleupdates replacement; see primary method docs."""
return getAppleUpdatesInstance().AppleSoftwareUpdatesAvailable(
force_check=forcecheck, suppress_check=suppresscheck)
def displayAppleUpdateInfo():
"""Method for drop-in appleupdates replacement; see primary method docs."""
getAppleUpdatesInstance().DisplayAppleUpdateInfo()

View File

@@ -1221,6 +1221,23 @@ def getVersionString(plist, key=None):
return ''
def getAppBundleExecutable(bundlepath):
"""Returns path to the actual executable in an app bundle or None"""
infoPlist = os.path.join(bundlepath, 'Contents', 'Info.plist')
if os.path.exists(infoPlist):
plist = FoundationPlist.readPlist(infoPlist)
if 'CFBundleExecutable' in plist:
executable = plist['CFBundleExecutable']
elif 'CFBundleName' in plist:
executable = plist['CFBundleName']
else:
executable = os.path.splitext(os.path.basename(bundlepath))[0]
executable_path = os.path.join(bundlepath, 'Contents/MacOS', executable)
if os.path.exists(executable_path):
return executable_path
return None
def getBundleVersion(bundlepath, key=None):
"""
Returns version number from a bundle.

View File

@@ -1451,6 +1451,24 @@ def lookForUpdatesForVersion(itemname, itemversion, cataloglist):
return update_list
def isAppleItem(item_pl):
"""Returns True if the item to be installed or removed appears to be from
Apple. If we are installing or removing any Apple items in a check/install
cycle, we skip checking/installing Apple updates from an Apple Software
Update server so we don't stomp on each other"""
# check receipts
for receipt in item_pl.get('receipts', []):
if receipt.get('packageid', '').startswith('com.apple.'):
return True
# check installs items
for install_item in item_pl.get('installs', []):
if install_item.get('CFBundleIdentifier', '').startswith('com.apple.'):
return True
# if we get here, no receipts or installs items have Apple
# identifiers
return False
def processManagedUpdate(manifestitem, cataloglist, installinfo):
"""Process a managed_updates item to see if it is installed, and if so,
if it needs an update.
@@ -1746,12 +1764,19 @@ def processInstall(manifestitem, cataloglist, installinfo):
'postinstall_script',
'items_to_copy', # used w/ copy_from_dmg
'copy_local', # used w/ AdobeCS5 Updaters
'force_install_after_date']
'force_install_after_date',
'apple_item']
for key in optional_keys:
if key in item_pl:
iteminfo[key] = item_pl[key]
if not 'apple_item' in iteminfo:
# admin did not explictly mark this item; let's determine if
# it's from Apple
if isAppleItem(item_pl):
iteminfo['apple_item'] = True
installinfo['managed_installs'].append(iteminfo)
update_list = []
@@ -2186,6 +2211,9 @@ def processRemoval(manifestitem, cataloglist, installinfo):
for key in optionalKeys:
if key in uninstall_item:
iteminfo[key] = uninstall_item[key]
if isAppleItem(item_pl):
iteminfo['apple_item'] = True
if packagesToRemove:
# remove references for each package
@@ -2866,10 +2894,30 @@ def check(client_id='', localmanifestpath=None):
munkicommon.report['ItemsToRemove'] = \
installinfo.get('removals', [])
munkicommon.savereport()
munkicommon.log('### End managed software check ###')
installcount = len(installinfo.get('managed_installs', []))
removalcount = len(installinfo.get('removals', []))
if installcount or removalcount:
return 1
else:
return 0
def displayUpdateInfo():
'''Prints info about available updates'''
ManagedInstallDir = munkicommon.pref('ManagedInstallDir')
installinfopath = os.path.join(ManagedInstallDir, 'InstallInfo.plist')
try:
installinfo = FoundationPlist.readPlist(installinfopath)
except FoundationPlist.NSPropertyListSerializationException:
installinfo = {}
installcount = len(installinfo.get('managed_installs', []))
removalcount = len(installinfo.get('removals', []))
munkicommon.log('')
if installcount:
munkicommon.display_info('')
munkicommon.display_info(
@@ -2906,14 +2954,6 @@ def check(client_id='', localmanifestpath=None):
munkicommon.display_info(
'No changes to managed software are available.')
munkicommon.savereport()
munkicommon.log('### End managed software check ###')
if installcount or removalcount:
return 1
else:
return 0
def subtractTimeZoneOffsetFromDate(the_date):
"""Input: NSDate object

View File

@@ -949,7 +949,7 @@ class TestAppleUpdates(mox.MoxTestBase):
self.mox.StubOutWithMock(appleupdates.hashlib, 'sha256')
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
cmd = ['/usr/sbin/pkgutil', '--regexp', '-pkg-info-plist',
cmd = ['/usr/sbin/pkgutil', '--regexp', '--pkg-info-plist',
'com\.apple\.*']
output = 'output!'
@@ -1109,7 +1109,7 @@ class TestAppleUpdates(mox.MoxTestBase):
'unchanged, installed Apple packages are unchanged and we '
'recently did a full check.')
self.mox.ReplayAll()
self.assertFalse(self.au.CheckForSoftwareUpdates(force_check=False))
self.assertTrue(self.au.CheckForSoftwareUpdates(force_check=False))
self.mox.VerifyAll()
def testCheckForSoftwareUpdatesWhenUpdateListEmpty(self):
@@ -1508,7 +1508,7 @@ class TestAppleUpdates(mox.MoxTestBase):
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
self.mox.StubOutWithMock(self.au, 'CheckForSoftwareUpdates')
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
# Cannot stub out the builtin NSDate methods, so stub the entire module.
mock_nsdate_module = self.mox.CreateMockAnything()
self.mox.StubOutWithMock(appleupdates, 'NSDate', mock_nsdate_module)
@@ -1531,7 +1531,7 @@ class TestAppleUpdates(mox.MoxTestBase):
self.au.CheckForSoftwareUpdates(force_check=True).AndReturn(True)
appleupdates.munkicommon.stopRequested().AndReturn(False)
self.au.WriteAppleUpdatesFile().AndReturn(True)
self.au.DisplayAppleUpdateInfo().AndReturn(None)
#self.au.DisplayAppleUpdateInfo().AndReturn(None)
self.mox.ReplayAll()
out = self.au.AppleSoftwareUpdatesAvailable(
@@ -1545,7 +1545,7 @@ class TestAppleUpdates(mox.MoxTestBase):
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
self.mox.StubOutWithMock(self.au, 'CheckForSoftwareUpdates')
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
# Cannot stub out the builtin NSDate methods, so stub the entire module.
mock_nsdate_module = self.mox.CreateMockAnything()
self.mox.StubOutWithMock(appleupdates, 'NSDate', mock_nsdate_module)
@@ -1568,7 +1568,7 @@ class TestAppleUpdates(mox.MoxTestBase):
self.au.CheckForSoftwareUpdates(force_check=False).AndReturn(True)
appleupdates.munkicommon.stopRequested().AndReturn(False)
self.au.WriteAppleUpdatesFile().AndReturn(True)
self.au.DisplayAppleUpdateInfo().AndReturn(None)
#self.au.DisplayAppleUpdateInfo().AndReturn(None)
self.mox.ReplayAll()
out = self.au.AppleSoftwareUpdatesAvailable(
@@ -1582,7 +1582,7 @@ class TestAppleUpdates(mox.MoxTestBase):
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
self.mox.StubOutWithMock(self.au, 'CheckForSoftwareUpdates')
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
# use a date string that will not parse correctly.
appleupdates.munkicommon.pref('LastAppleSoftwareUpdateCheck').AndReturn(
@@ -1591,7 +1591,7 @@ class TestAppleUpdates(mox.MoxTestBase):
self.au.CheckForSoftwareUpdates(force_check=True).AndReturn(True)
appleupdates.munkicommon.stopRequested().AndReturn(False)
self.au.WriteAppleUpdatesFile().AndReturn(True)
self.au.DisplayAppleUpdateInfo().AndReturn(None)
#self.au.DisplayAppleUpdateInfo().AndReturn(None)
self.mox.ReplayAll()
out = self.au.AppleSoftwareUpdatesAvailable(
@@ -1604,12 +1604,12 @@ class TestAppleUpdates(mox.MoxTestBase):
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
self.mox.StubOutWithMock(self.au, 'CheckForSoftwareUpdates')
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
self.au.CheckForSoftwareUpdates(force_check=True).AndReturn(True)
appleupdates.munkicommon.stopRequested().AndReturn(False)
self.au.WriteAppleUpdatesFile().AndReturn(True)
self.au.DisplayAppleUpdateInfo().AndReturn(None)
#self.au.DisplayAppleUpdateInfo().AndReturn(None)
self.mox.ReplayAll()
out = self.au.AppleSoftwareUpdatesAvailable(
@@ -1617,15 +1617,15 @@ class TestAppleUpdates(mox.MoxTestBase):
self.assertTrue(out)
self.mox.VerifyAll()
def testAppleSoftwareUpdatesAvailableSupressCheck(self):
def testAppleSoftwareUpdatesAvailableSuppressCheck(self):
"""Tests AppleSoftwareUpdatesAvailable() with suppress_check=True."""
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
appleupdates.munkicommon.stopRequested().AndReturn(False)
self.au.WriteAppleUpdatesFile().AndReturn(True)
self.au.DisplayAppleUpdateInfo().AndReturn(None)
#self.au.DisplayAppleUpdateInfo().AndReturn(None)
self.mox.ReplayAll()
out = self.au.AppleSoftwareUpdatesAvailable(
@@ -1637,7 +1637,7 @@ class TestAppleUpdates(mox.MoxTestBase):
"""Tests AppleSoftwareUpdatesAvailable() when no updates available."""
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
appleupdates.munkicommon.stopRequested().AndReturn(False)
self.au.WriteAppleUpdatesFile().AndReturn(False)