mirror of
https://github.com/munki/munki.git
synced 2026-05-04 03:20:19 -05:00
And the refactoring continues...
This commit is contained in:
@@ -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
@@ -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.'
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user