And the refactoring continues...

This commit is contained in:
Greg Neagle
2017-01-01 15:16:07 -08:00
parent 242bbc9855
commit f338e5ead5
3 changed files with 84 additions and 112 deletions
+34 -48
View File
@@ -55,15 +55,16 @@ except ImportError:
print >> sys.stderr, str(err)
sys.exit(200)
else:
from munkilib import munkicommon
from munkilib import updatecheck
from munkilib import appleupdates
from munkilib import authrestart
from munkilib import fetch
from munkilib import installer
from munkilib import installinfo
from munkilib import munkicommon
from munkilib import munkistatus
from munkilib import appleupdates
from munkilib import FoundationPlist
from munkilib import updatecheck
from munkilib import utils
from munkilib import authrestart
from munkilib import FoundationPlist
def signal_handler(signum, dummy_frame):
@@ -219,9 +220,8 @@ def doInstallTasks(do_apple_updates, only_unattended=False):
Boolean. True if a restart is required, False otherwise.
"""
if not only_unattended:
# first, clear the last notified date
# so we can get notified of new changes after this round
# of installs
# first, clear the last notified date so we can get notified of new
# changes after this round of installs
clearLastNotifiedDate()
munki_need_to_restart = False
@@ -320,30 +320,30 @@ def doRestart():
def munkiUpdatesAvailable():
"""Return count of available updates."""
updatesavailable = 0
installinfo = os.path.join(munkicommon.pref('ManagedInstallDir'),
'InstallInfo.plist')
if os.path.exists(installinfo):
install_info = os.path.join(
munkicommon.pref('ManagedInstallDir'), 'InstallInfo.plist')
if os.path.exists(install_info):
try:
plist = FoundationPlist.readPlist(installinfo)
plist = FoundationPlist.readPlist(install_info)
updatesavailable = (len(plist.get('removals', [])) +
len(plist.get('managed_installs', [])))
except (AttributeError,
FoundationPlist.NSPropertyListSerializationException):
munkicommon.display_error(
'Install info at %s is invalid.' % installinfo)
'Install info at %s is invalid.' % install_info)
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):
install_info = os.path.join(
munkicommon.pref('ManagedInstallDir'), 'InstallInfo.plist')
if os.path.exists(install_info):
try:
plist = FoundationPlist.readPlist(installinfo)
plist = FoundationPlist.readPlist(install_info)
except FoundationPlist.NSPropertyListSerializationException:
munkicommon.display_error(
'Install info at %s is invalid.' % installinfo)
'Install info at %s is invalid.' % install_info)
else:
# check managed_installs
for item in plist.get('managed_installs', []):
@@ -555,9 +555,9 @@ def main():
options.quiet = True
options.checkonly = False
options.installonly = True
# if we're running at the loginwindow,
# let's make sure the user triggered
# the update before logging out, or we triggered it before restarting.
# if we're running at the loginwindow, let's make sure the user
# triggered the update before logging out, or we triggered it before
# restarting.
user_triggered = False
flagfiles = [checkandinstallatstartupflag,
installatstartupflag,
@@ -570,9 +570,8 @@ def main():
options.installonly = False
options.auto = True
# HACK: sometimes this runs before the network is up.
# we'll attempt to wait up to 60 seconds for the
# network interfaces to come up
# before continuing
# we'll attempt to wait up to 60 seconds for the network
# interfaces to come up before continuing
munkicommon.display_status_minor('Waiting for network...')
for dummy_i in range(60):
if networkUp():
@@ -718,7 +717,7 @@ def main():
server = munkicommon.pref('ManifestURL') or \
munkicommon.pref('SoftwareRepoURL')
warn_if_server_is_default(server)
result = updatecheck.checkServer(server)
result = fetch.check_server(server)
if result != (0, 'OK'):
munkicommon.display_error(
'managedsoftwareupdate: server check for %s failed: %s'
@@ -842,8 +841,7 @@ def main():
if appleupdatesavailable:
appleupdates.displayAppleUpdateInfo()
# send a notification event so MSU can update its display
# if needed
# send a notification event so MSU can update its display if needed
sendUpdateNotification()
mustrestart = False
@@ -959,9 +957,8 @@ def main():
if options.installonly and not options.quiet:
print 'Nothing to install or remove.'
if runtype == 'checkandinstallatstartup':
# we have nothing to do, so remove the
# checkandinstallatstartupflag file
# so we'll stop running at startup/logout
# we have nothing to do, so remove the checkandinstallatstartupflag
# file so we'll stop running at startup/logout
if os.path.exists(checkandinstallatstartupflag):
os.unlink(checkandinstallatstartupflag)
@@ -978,8 +975,7 @@ def main():
munkicommon.set_pref('PendingUpdateCount',
updatesavailable + appleupdatesavailable)
# send a notification event so Dock tile badge can be updated
# if needed
# send a notification event so Dock tile badge can be updated if needed
sendDockUpdateNotification()
munkicommon.display_status_major('Finishing...')
@@ -996,18 +992,17 @@ def main():
print 'Done.'
if notify_user:
# it may have been more than a minute since we ran our
# original updatecheck so tickle the updatecheck time
# so MSU.app knows to display results immediately
# it may have been more than a minute since we ran our original
# updatecheck so tickle the updatecheck time so MSC.app knows to
# display results immediately
recordUpdateCheckResult(1)
if force_action:
notifyUserOfUpdates(force=True)
time.sleep(2)
startLogoutHelper()
elif munkicommon.getconsoleuser() == u'loginwindow':
# someone is logged in, but we're sitting at
# the loginwindow due to fast user switching
# so do nothing
# someone is logged in, but we're sitting at the loginwindow due to
# to fast user switching so do nothing
pass
elif not munkicommon.pref('SuppressUserNotification'):
notifyUserOfUpdates()
@@ -1032,21 +1027,12 @@ def main():
if not munkicommon.currentGUIusers():
# no-one is logged in
idleseconds = getIdleSeconds()
if not idleseconds > 10:
if idleseconds <= 10:
# system is not idle, but check again in case someone has
# simply briefly touched the mouse to see progress.
time.sleep(15)
idleseconds = getIdleSeconds()
if idleseconds > 10:
# no-one is logged in and the machine has been idle
# for a few seconds; kill the loginwindow
# (which will cause us to run again)
#munkicommon.log(
# 'Killing loginwindow so we will run again...')
#cmd = ['/usr/bin/killall', 'loginwindow']
#dummy_retcode = subprocess.call(cmd)
# with the new LaunchAgent, we don't have to kill
# the loginwindow
pass
else:
# if the trigger file is present when we exit, we'll
Regular → Executable
+34
View File
@@ -633,5 +633,39 @@ def getDataFromURL(url):
return ''
def check_server(url):
"""A function we can call to check to see if the server is
available before we kick off a full run. This can be fooled by
ISPs that return results for non-existent web servers...
Returns a tuple (error_code, error_description)"""
# rewritten 12 Dec 2016 to use gurl so we use system proxies, if any
# deconstruct URL to get scheme
url_parts = urlparse.urlsplit(url)
if url_parts.scheme in ('http', 'https'):
pass
elif url_parts.scheme == 'file':
if url_parts.hostname not in [None, '', 'localhost']:
return (-1, 'Non-local hostnames not supported for file:// URLs')
if os.path.exists(url_parts.path):
return (0, 'OK')
else:
return (-1, 'Path %s does not exist' % url_parts.path)
else:
return (-1, 'Unsupported URL scheme')
# we have an HTTP or HTTPS URL
try:
# attempt to get something at the url
dummy_data = getDataFromURL(url)
except ConnectionError, err:
# err should contain a tuple with code and description
return (err[0], err[1])
except (GurlError, DownloadError):
# HTTP errors, etc are OK -- we just need to be able to connect
pass
return (0, 'OK')
if __name__ == '__main__':
print 'This is a library of support tools for the Munki Suite.'
+16 -64
View File
@@ -24,18 +24,8 @@ Created by Greg Neagle on 2008-11-13.
# standard libs
import datetime
import os
import urlparse
from urllib import quote_plus
# Apple's libs
# PyLint cannot properly find names inside Cocoa libraries, so issues bogus
# No name 'Foo' in module 'Bar' warnings. Disable them.
# pylint: disable=E0611
from Foundation import NSDate
# pylint: enable=E0611
# our libs
from . import appleupdates
from . import catalogs
from . import compare
from . import download
@@ -46,7 +36,6 @@ from . import licensing
from . import manifestutils
from . import munkicommon
from . import munkistatus
from . import profiles
from . import FoundationPlist
@@ -622,15 +611,6 @@ def processManifestForKey(manifest, manifest_key, installinfo,
dummy_result = processRemoval(item, cataloglist, installinfo)
def getReceiptsToRemove(item):
"""Returns a list of receipts to remove for item"""
name = item['name']
pkgdata = catalogs.analyze_installed_pkgs()
if name in pkgdata['receipts_for_name']:
return pkgdata['receipts_for_name'][name]
return []
def processRemoval(manifestitem, cataloglist, installinfo):
"""Processes a manifest item; attempts to determine if it
needs to be removed, and if it can be removed.
@@ -649,9 +629,17 @@ def processRemoval(manifestitem, cataloglist, installinfo):
Returns a boolean; when processing dependencies, a false return
will stop the removal of a dependent item.
"""
def get_receipts_to_remove(item):
"""Returns a list of receipts to remove for item"""
name = item['name']
pkgdata = catalogs.analyze_installed_pkgs()
if name in pkgdata['receipts_for_name']:
return pkgdata['receipts_for_name'][name]
return []
manifestitemname_withversion = os.path.split(manifestitem)[1]
munkicommon.display_debug1(
'* Processing manifest item %s for removal' %
'* Processing manifest item %s for removal' %
manifestitemname_withversion)
(manifestitemname, includedversion) = catalogs.split_name_and_version(
@@ -660,11 +648,10 @@ def processRemoval(manifestitem, cataloglist, installinfo):
# have we processed this already?
if manifestitemname in [catalogs.split_name_and_version(item)[0]
for item in installinfo['processed_installs']]:
munkicommon.display_warning('Will not attempt to remove %s '
'because some version of it is in '
'the list of managed installs, or '
'it is required by another managed '
'install.', manifestitemname)
munkicommon.display_warning(
'Will not attempt to remove %s because some version of it is in '
'the list of managed installs, or it is required by another'
' managed install.', manifestitemname)
return False
elif manifestitemname in installinfo['processed_uninstalls']:
munkicommon.display_debug1(
@@ -687,9 +674,8 @@ def processRemoval(manifestitem, cataloglist, installinfo):
if not infoitems:
munkicommon.display_warning(
'Could not process item %s for removal. '
'No pkginfo found in catalogs: %s ',
manifestitemname, ', '.join(cataloglist))
'Could not process item %s for removal. No pkginfo found in '
'catalogs: %s ', manifestitemname, ', '.join(cataloglist))
return False
installEvidence = False
@@ -722,7 +708,7 @@ def processRemoval(manifestitem, cataloglist, installinfo):
if item.get('uninstallable') and 'uninstall_method' in item:
uninstallmethod = item['uninstall_method']
if uninstallmethod == 'removepackages':
packagesToRemove = getReceiptsToRemove(item)
packagesToRemove = get_receipts_to_remove(item)
if packagesToRemove:
uninstall_item = item
elif uninstallmethod.startswith('Adobe'):
@@ -933,40 +919,6 @@ def processRemoval(manifestitem, cataloglist, installinfo):
return True
def checkServer(url):
"""A function we can call to check to see if the server is
available before we kick off a full run. This can be fooled by
ISPs that return results for non-existent web servers...
Returns a tuple (error_code, error_description)"""
# rewritten 12 Dec 2016 to use gurl so we use system proxies, if any
# deconstruct URL to get scheme
url_parts = urlparse.urlsplit(url)
if url_parts.scheme in ('http', 'https'):
pass
elif url_parts.scheme == 'file':
if url_parts.hostname not in [None, '', 'localhost']:
return (-1, 'Non-local hostnames not supported for file:// URLs')
if os.path.exists(url_parts.path):
return (0, 'OK')
else:
return (-1, 'Path %s does not exist' % url_parts.path)
else:
return (-1, 'Unsupported URL scheme')
# we have an HTTP or HTTPS URL
try:
# attempt to get something at the url
dummy_data = fetch.getDataFromURL(url)
except fetch.ConnectionError, err:
# err should contain a tuple with code and description
return (err[0], err[1])
except (fetch.GurlError, fetch.DownloadError):
# HTTP errors, etc are OK -- we just need to be able to connect
pass
return (0, 'OK')
class UpdateCheckAbortedError(Exception):
'''Exception used to break out of checking for updates'''
pass