mirror of
https://github.com/munki/munki.git
synced 2026-04-23 21:40:25 -05:00
Initial commit adding client-side support for 'apple_update_metadata'
Provided that 'AppleSoftwareUpdatesOnly' preference is False, primary client manifest's catalogs are parsed for matching 'apple_update_metadata' and applied to pending Apple updates. Please note that not ALL keys presented by an apple_update_metadata item are applied as to not either clobber or complicate the listing of items provided in 'AppleUpdates.plist'. The current list of excluded keys is as follows: catalogs installed_size installer_type name version version_to_install
This commit is contained in:
@@ -702,7 +702,7 @@ def main():
|
||||
try:
|
||||
appleupdatesavailable = \
|
||||
appleupdates.appleSoftwareUpdatesAvailable(
|
||||
forcecheck=force_update_check)
|
||||
forcecheck=force_update_check, client_id=options.id)
|
||||
except:
|
||||
munkicommon.display_error('Unexpected error in appleupdates:')
|
||||
munkicommon.log(traceback.format_exc())
|
||||
@@ -715,7 +715,7 @@ def main():
|
||||
try:
|
||||
appleupdatesavailable = \
|
||||
appleupdates.appleSoftwareUpdatesAvailable(
|
||||
suppresscheck=True)
|
||||
suppresscheck=True, client_id=options.id)
|
||||
except:
|
||||
munkicommon.display_error('Unexpected error in appleupdates:')
|
||||
munkicommon.log(traceback.format_exc())
|
||||
|
||||
Regular → Executable
+72
-1
@@ -47,6 +47,7 @@ import fetch
|
||||
import launchd
|
||||
import munkicommon
|
||||
import munkistatus
|
||||
import updatecheck
|
||||
|
||||
|
||||
# Apple Software Update Catalog URLs.
|
||||
@@ -172,6 +173,10 @@ class AppleUpdates(object):
|
||||
self.local_catalog_dir, LOCAL_DOWNLOAD_CATALOG_NAME)
|
||||
|
||||
self._update_list_cache = None
|
||||
|
||||
# apple_update_metadata support
|
||||
self.apple_md = {}
|
||||
self.client_id = CLIENT_ID
|
||||
|
||||
def _ResetMunkiStatusAndDisplayMessage(self, message):
|
||||
"""Resets MunkiStatus detail/percent, logs and msgs GUI.
|
||||
@@ -825,8 +830,33 @@ class AppleUpdates(object):
|
||||
Returns:
|
||||
Boolean. True if apple updates was updated, False otherwise.
|
||||
"""
|
||||
metadata_exclusions = ['catalogs',
|
||||
'installed_size',
|
||||
'installer_type',
|
||||
'name',
|
||||
'version',
|
||||
'version_to_install']
|
||||
apple_updates = self.GetSoftwareUpdateInfo()
|
||||
if apple_updates:
|
||||
# Process update metadata only if AppleSoftwareUpdatesOnly is false
|
||||
if not munkicommon.pref('AppleSoftwareUpdatesOnly'):
|
||||
self.apple_md = updatecheck.check(
|
||||
self.client_id, apple_update_md_only=True)
|
||||
for update in apple_updates:
|
||||
matching_items = self.getAllItemsWithProductKey(
|
||||
update['productKey'])
|
||||
if matching_items:
|
||||
update_metadata = matching_items[0]
|
||||
for key in update_metadata:
|
||||
# Don't overwrite items in exclusions list
|
||||
if key in metadata_exclusions:
|
||||
continue
|
||||
else:
|
||||
# Apply non-empty metadata
|
||||
if update_metadata[key]:
|
||||
munkicommon.display_debug2(
|
||||
'Applying %s to %s...' % (key, update['display_name']))
|
||||
update[key] = update_metadata[key]
|
||||
plist = {'AppleUpdates': apple_updates}
|
||||
FoundationPlist.writePlist(plist, self.apple_updates_plist)
|
||||
return True
|
||||
@@ -1297,6 +1327,45 @@ class AppleUpdates(object):
|
||||
return updates
|
||||
|
||||
|
||||
def getAllItemsWithProductKey(self, productKey):
|
||||
"""Searches apple_md for all items matching a given Apple productKey
|
||||
|
||||
Returns:
|
||||
list of pkginfo items; sorted with newest version first. No precedence
|
||||
is given to catalog order.
|
||||
"""
|
||||
def compare_item_versions(a, b):
|
||||
"""Internal comparison function for use with sorting"""
|
||||
return cmp(munkicommon.MunkiLooseVersion(b['version']),
|
||||
munkicommon.MunkiLooseVersion(a['version']))
|
||||
|
||||
itemlist = []
|
||||
|
||||
munkicommon.display_debug1(
|
||||
'Looking for metadata matching: %s...' % productKey)
|
||||
# is productKey in the catalog name table?
|
||||
for catalogname in self.apple_md.keys():
|
||||
if productKey in self.apple_md[catalogname]['named']:
|
||||
versionsmatchingproductKey = \
|
||||
self.apple_md[catalogname]['named'][productKey]
|
||||
for vers in versionsmatchingproductKey.keys():
|
||||
if vers != 'latest':
|
||||
indexlist = \
|
||||
self.apple_md[catalogname]['named'][productKey][vers]
|
||||
for index in indexlist:
|
||||
thisitem = self.apple_md[catalogname]['items'][index]
|
||||
if not thisitem in itemlist:
|
||||
munkicommon.display_debug1(
|
||||
'Adding item %s, version %s from catalog %s...' %
|
||||
(productKey, thisitem['version'], catalogname))
|
||||
itemlist.append(thisitem)
|
||||
|
||||
if itemlist:
|
||||
# sort so latest version is first
|
||||
itemlist.sort(compare_item_versions)
|
||||
return itemlist
|
||||
|
||||
|
||||
|
||||
# Make the new appleupdates module easily dropped in with exposed funcs for now.
|
||||
|
||||
@@ -1326,8 +1395,10 @@ def installAppleUpdates():
|
||||
return getAppleUpdatesInstance().InstallAppleUpdates()
|
||||
|
||||
|
||||
def appleSoftwareUpdatesAvailable(forcecheck=False, suppresscheck=False):
|
||||
def appleSoftwareUpdatesAvailable(forcecheck=False, suppresscheck=False, client_id=''):
|
||||
"""Method for drop-in appleupdates replacement; see primary method docs."""
|
||||
global CLIENT_ID
|
||||
CLIENT_ID = client_id
|
||||
return getAppleUpdatesInstance().AppleSoftwareUpdatesAvailable(
|
||||
force_check=forcecheck, suppress_check=suppresscheck)
|
||||
|
||||
|
||||
Regular → Executable
+32
-4
@@ -44,12 +44,21 @@ from Foundation import NSDate, NSPredicate, NSTimeZone
|
||||
# This many hours before a force install deadline, start notifying the user.
|
||||
FORCE_INSTALL_WARNING_HOURS = 4
|
||||
|
||||
# Flag denoting a check from appleupdates for apple_update_metadata
|
||||
APPLE_UPDATE_MD_ONLY = False
|
||||
|
||||
def makeCatalogDB(catalogitems):
|
||||
"""Takes an array of catalog items and builds some indexes so we can
|
||||
get our common data faster. Returns a dict we can use like a database"""
|
||||
name_table = {}
|
||||
pkgid_table = {}
|
||||
|
||||
# Filter catalogitems so that they only contain apple_update_metadata items
|
||||
if APPLE_UPDATE_MD_ONLY:
|
||||
catalogitems = [item for item in catalogitems
|
||||
if item.get('installer_type') ==
|
||||
'apple_update_metadata']
|
||||
|
||||
itemindex = -1
|
||||
for item in catalogitems:
|
||||
itemindex = itemindex + 1
|
||||
@@ -2609,11 +2618,14 @@ def getDownloadCachePath(destinationpathprefix, url):
|
||||
|
||||
MACHINE = {}
|
||||
CONDITIONS = {}
|
||||
def check(client_id='', localmanifestpath=None):
|
||||
def check(client_id='', localmanifestpath=None, apple_update_md_only=False):
|
||||
"""Checks for available new or updated managed software, downloading
|
||||
installer items if needed. Returns 1 if there are available updates,
|
||||
0 if there are no available updates, and -1 if there were errors."""
|
||||
|
||||
global APPLE_UPDATE_MD_ONLY
|
||||
APPLE_UPDATE_MD_ONLY = apple_update_md_only
|
||||
|
||||
global MACHINE
|
||||
munkicommon.getMachineFacts()
|
||||
MACHINE = munkicommon.getMachineFacts()
|
||||
@@ -2627,9 +2639,6 @@ def check(client_id='', localmanifestpath=None):
|
||||
if munkicommon.munkistatusoutput:
|
||||
munkistatus.activate()
|
||||
|
||||
munkicommon.log('### Beginning managed software check ###')
|
||||
munkicommon.display_status_major('Checking for available updates...')
|
||||
|
||||
if localmanifestpath:
|
||||
mainmanifestpath = localmanifestpath
|
||||
else:
|
||||
@@ -2639,6 +2648,14 @@ def check(client_id='', localmanifestpath=None):
|
||||
|
||||
installinfo = {}
|
||||
|
||||
if APPLE_UPDATE_MD_ONLY:
|
||||
munkicommon.display_detail('**Checking for Apple Update Metadata**')
|
||||
print munkicommon.pref('AppleSoftwareUpdatesOnly')
|
||||
return getAppleUpdateMetaData(mainmanifestpath)
|
||||
|
||||
munkicommon.log('### Beginning managed software check ###')
|
||||
munkicommon.display_status_major('Checking for available updates...')
|
||||
|
||||
if mainmanifestpath:
|
||||
# initialize our installinfo record
|
||||
installinfo['processed_installs'] = []
|
||||
@@ -3123,6 +3140,17 @@ def getResourceIfChangedAtomically(url,
|
||||
verify=verify)
|
||||
|
||||
|
||||
def getAppleUpdateMetaData(manifest):
|
||||
global CATALOG
|
||||
CATALOG = {}
|
||||
if manifest:
|
||||
manifestdata = getManifestData(manifest)
|
||||
cataloglist = manifestdata.get('catalogs')
|
||||
if cataloglist:
|
||||
getCatalogs(cataloglist)
|
||||
return CATALOG
|
||||
|
||||
|
||||
def main():
|
||||
"""Placeholder"""
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user