logouthelper now properly checks both InstallInfo.plist and AppleUpdates.plist for 'force_install_after_date' items.

This commit is contained in:
Greg Neagle
2013-03-08 13:28:46 -08:00
parent dbca31a486
commit f8f558edc5

View File

@@ -22,7 +22,6 @@ Created by Greg Neagle on 2011-06-21.
A helper tool for forced logouts to allow munki to force install items by
a certain deadline.
"""
import os
@@ -40,6 +39,11 @@ from Foundation import NSNotificationPostToAllSessions
NOTIFICATION_MINS = [240, 180, 120, 90, 60, 45, 30, 15, 10, 5]
MINIMUM_NOTIFICATION_MINS = 60
def log(msg):
'''Logs messages from this tool with an identifier'''
PROCESS_ID = 'com.googlecode.munki.logouthelper'
munkicommon.log('%s: %s' % (PROCESS_ID, msg))
def earliestForceInstallDate():
'''Check installable packages for force_install_after_dates
@@ -48,22 +52,34 @@ def earliestForceInstallDate():
earliest_date = None
ManagedInstallDir = munkicommon.pref('ManagedInstallDir')
installinfo_types = {
'InstallInfo.plist' : 'managed_installs',
'AppleUpdates.plist': 'AppleUpdates'
}
installinfopath = os.path.join(ManagedInstallDir, 'InstallInfo.plist')
try:
installinfo = FoundationPlist.readPlist(installinfopath)
except FoundationPlist.NSPropertyListSerializationException:
return None
for install in installinfo.get('managed_installs', []):
force_install_date = install.get('force_install_after_date')
if force_install_date:
force_install_date = updatecheck.subtractTimeZoneOffsetFromDate(
force_install_date)
if not earliest_date or force_install_date < earliest_date:
earliest_date = force_install_date
for plist_name in installinfo_types.keys():
key_to_check = installinfo_types[plist_name]
plist_path = os.path.join(ManagedInstallDir, plist_name)
try:
installinfo = FoundationPlist.readPlist(plist_path)
except FoundationPlist.NSPropertyListSerializationException:
continue
for install in installinfo.get(key_to_check, []):
force_install_date = install.get('force_install_after_date')
if force_install_date:
force_install_date = updatecheck.subtractTimeZoneOffsetFromDate(
force_install_date)
if not earliest_date or force_install_date < earliest_date:
earliest_date = force_install_date
return earliest_date
@@ -94,7 +110,7 @@ def alertUserOfForcedLogout(info=None):
# if set, convert Python dictionary to NSDictionary.
if info is not None:
info = NSDictionary.dictionaryWithDictionary_(info)
info = NSDictionary.dictionaryWithDictionary_(info)
# cause MSU.app to display the Forced Logout warning
dnc = NSDistributedNotificationCenter.defaultCenter()
dnc.postNotificationName_object_userInfo_options_(
@@ -110,8 +126,7 @@ def alertUserOfForcedLogout(info=None):
def main():
'''Check for logged-in users and upcoming forced installs;
notify the user if needed; sleep a minute and do it again.'''
ID = 'com.googlecode.munki.logouthelper'
munkicommon.log('%s invoked' % ID)
log('launched')
sent_notifications = []
logout_time_override = None
minimum_notifications_logout_time = NSDate.date().addTimeInterval_(
@@ -119,48 +134,53 @@ def main():
while True:
if not munkicommon.currentGUIusers():
# no-one is logged in, so bail
munkicommon.log('%s: no-one logged in' % ID)
log('no-one logged in')
time.sleep(10) # makes launchd happy
munkicommon.log('%s exited' % ID)
log('exited')
exit(0)
# we check each time because items might have been added or removed
# from the list; or their install date may have been changed.
next_logout_time = earliestForceInstallDate()
if not next_logout_time:
# no forced logout needed, so bail
log('no forced installs found')
time.sleep(10) # makes launchd happy
log('exited')
exit(0)
tmp_logout_time = earliestForceInstallDate()
if logout_time_override is None:
logout_time = tmp_logout_time
logout_time = next_logout_time
else:
# allow the new (tmp_)logout_time from InstallInfo to be used
# if it has changed since when we decided to override it.
if logout_time_override != tmp_logout_time:
logout_time = tmp_logout_time
# allow the new next_logout_time from InstallInfo to be used
# if it has changed to a later time since when we decided to
# override it.
if next_logout_time > logout_time_override:
logout_time = next_logout_time
log('reset logout_time to: %s' % logout_time)
logout_time_override = None
sent_notifications = []
if not logout_time:
# no forced logout needed, so bail
munkicommon.log('%s: no forced installs found' % ID)
time.sleep(10) # makes launchd happy
munkicommon.log('%s exited' % ID)
exit(0)
elif logout_time < minimum_notifications_logout_time:
if MINIMUM_NOTIFICATION_MINS not in sent_notifications:
# logout time is in the past, and the minimum notification
# has not been sent, so reset the logout_time to the future.
munkicommon.log('%d minute notification not sent.' % (
MINIMUM_NOTIFICATION_MINS))
logout_time = minimum_notifications_logout_time
munkicommon.log('Reset logout_time to: %s' % logout_time)
logout_time_override = logout_time
# always give at least a MINIMUM_NOTIFICATION_MINS warning
if logout_time < minimum_notifications_logout_time:
if MINIMUM_NOTIFICATION_MINS not in sent_notifications:
# logout time is in the past, and the minimum notification
# has not been sent, so reset the logout_time to the future.
log('%d minute notification not sent.'
% MINIMUM_NOTIFICATION_MINS)
logout_time = minimum_notifications_logout_time
log('reset logout_time to: %s' % logout_time)
logout_time_override = logout_time
minutes_until_logout = int(logout_time.timeIntervalSinceNow() / 60)
info = {'logout_time': logout_time}
if minutes_until_logout in NOTIFICATION_MINS:
sent_notifications.append(minutes_until_logout)
munkicommon.log(
'%s: Warning user of %s minutes until forced logout' %
(ID, minutes_until_logout))
log('Warning user of %s minutes until forced logout'
% minutes_until_logout)
alertUserOfForcedLogout(info)
elif minutes_until_logout < 1:
munkicommon.log('%s: Forced logout in 60 seconds' % ID)
log('Forced logout in 60 seconds')
alertUserOfForcedLogout(info)
time.sleep(60)
@@ -168,9 +188,9 @@ def main():
break
if munkicommon.currentGUIusers() and earliestForceInstallDate():
munkicommon.log('%s: Beginning forced logout' % ID)
log('Beginning forced logout')
munkicommon.forceLogoutNow()
munkicommon.log('%s exited' % ID)
log('exited')
exit(0)
if __name__ == '__main__':