Lots of logging and reporting changes.

Added munkicommon.validPlist() to check for plist validity when getting a manifest or catalog file.
Added call to updatecheck.checkServer() to test for server availability before doing a check for updates.

git-svn-id: http://munki.googlecode.com/svn/trunk@319 a4e17f2e-e282-11dd-95e1-755cbddbdd66
This commit is contained in:
Greg Neagle
2009-11-11 23:38:12 +00:00
parent d0854962d5
commit b4beeafcfe
5 changed files with 266 additions and 154 deletions
+4 -4
View File
@@ -245,7 +245,7 @@ def runAdobeSetup(dmgpath):
retcode = p.poll()
if retcode:
munkicommon.display_error("***Adobe Setup error: %s: %s***" % (retcode, adobeSetupError(retcode)))
munkicommon.display_error("Adobe Setup error: %s: %s" % (retcode, adobeSetupError(retcode)))
else:
munkicommon.display_error("%s doesn't appear to contain an Adobe CS4 update." % os.path.basename(dmgpath))
retcode = -1
@@ -304,21 +304,21 @@ def runAdobeUberTool(dmgpath, pkgname='', uninstalling=False):
payloadpath = loginfo[26:]
payloadfilename = os.path.basename(payloadpath)
payloadname = os.path.splitext(payloadfilename)[0]
munkicommon.display_status("Installing payload: %s" % payloadname)
munkicommon.display_status("Installing payload: %s (%s of %s)" % (payloadname, payload_completed_count, number_of_payloads))
except:
pass
# uninstalling
if loginfo.startswith("Physical payload uninstall result"):
# increment payload_completed_count
payload_completed_count = payload_completed_count + 1
munkicommon.display_status("Removed Adobe payload %s" % payload_completed_count)
munkicommon.display_status("Removed Adobe payload %s of %s" % (payload_completed_count, number_of_payloads))
if munkicommon.munkistatusoutput:
munkistatus.percent(getPercent(payload_completed_count, number_of_payloads))
# ubertool completed
retcode = p.poll()
if retcode:
munkicommon.display_error("***Adobe Setup error: %s: %s***" % (retcode, adobeSetupError(retcode)))
munkicommon.display_error("Adobe Setup error: %s: %s" % (retcode, adobeSetupError(retcode)))
else:
munkicommon.display_error("No %s found" % ubertool)
retcode = -1
+15 -7
View File
@@ -49,7 +49,7 @@ def selectSoftwareUpdateServer():
oldsusserver = out.rstrip('\n')
cmd = ['/usr/bin/defaults', 'write', '/Library/Preferences/com.apple.SoftwareUpdate',
'CatalogURL', munkilib.pref('SoftwareUpdateServerURL')]
'CatalogURL', munkicommon.pref('SoftwareUpdateServerURL')]
retcode = subprocess.call(cmd)
@@ -203,7 +203,12 @@ def kickOffUpdatesAndRestart():
# need to restart loginwindow so it notices the change
cmd = [ '/usr/bin/killall', 'loginwindow' ]
retcode = subprocess.call(cmd)
# and now we can remove the AccessibilityAPIFile
# argh! big problem. killing loginwindow also kills us if we're
# running as a LaunchAgent in the LoginWindow context
# We'll get relaunched, but then we lose our place in the code
# and have to start over.
# now we can remove the AccessibilityAPIFile
os.unlink(AccessibilityAPIFile)
# before we kick off the update, leave a trigger file so munki will install stuff
@@ -229,8 +234,7 @@ def kickOffUpdatesAndRestart():
while True:
line = p.stdout.readline()
if not line and (p.poll() != None):
break
break
return
else:
# unsupported OS version
@@ -446,11 +450,13 @@ def installAppleUpdates():
appleupdatelist = []
if appleupdatelist == []:
# we don't have any updates in appleUpdatesFile,
# or appleUpdatesFile is out-of-date, so check updatesindexfile
# or appleUpdatesFile is out-of-date, so check updatesindexfile
appleupdatelist = getSoftwareUpdateInfo()
# did we find some Apple updates?
if appleupdatelist:
munkicommon.report['AppleUpdateList'] = appleupdatelist
munkicommon.savereport()
try:
# once we start, we should remove /Library/Updates/index.plist
# because it will point to items we've already installed
@@ -462,8 +468,10 @@ def installAppleUpdates():
except:
pass
# now try to install the updates
restartneeded = installer.installWithInfo("/Library/Updates", appleupdatelist, appleupdates=True)
restartneeded = installer.installWithInfo("/Library/Updates", appleupdatelist)
if restartneeded:
munkicommon.report['RestartRequired'] = True
munkicommon.savereport()
return restartneeded
+31 -30
View File
@@ -32,6 +32,13 @@ import FoundationPlist
from removepackages import removepackages
# initialize our report fields
# we do this here because appleupdates.installAppleUpdates()
# calls installWithInfo()
munkicommon.report['InstallResults'] = []
munkicommon.report['RemovalResults'] = []
def install(pkgpath, choicesXMLpath=None):
"""
Uses the apple installer to install the package or metapackage
@@ -102,12 +109,15 @@ def install(pkgpath, choicesXMLpath=None):
print status.encode('UTF-8')
sys.stdout.flush()
elif msg.startswith("%"):
percent = float(msg[1:])
if osvers < 10:
# Leopard uses a float from 0 to 1
percent = int(percent * 100)
if munkicommon.munkistatusoutput:
percent = float(msg[1:])
if osvers < 10:
# Leopard uses a float from 0 to 1
percent = int(percent * 100)
munkistatus.percent(percent)
munkistatus.percent(percent)
else:
print "%s percent complete" % percent
sys.stdout.flush()
elif msg.startswith(" Error"):
if munkicommon.munkistatusoutput:
munkistatus.detail(msg)
@@ -218,16 +228,7 @@ def copyAppFromDMG(dmgpath):
return -1
def getInstallCount(installList):
count = 0
for item in installList:
if 'installed' in item:
if not item['installed']:
count +=1
return count
def installWithInfo(dirpath, installlist, appleupdates=False):
def installWithInfo(dirpath, installlist):
"""
Uses the installlist to install items in the
correct order.
@@ -306,9 +307,13 @@ def installWithInfo(dirpath, installlist, appleupdates=False):
# record install success/failure
if retcode == 0:
munkicommon.log("Install of %s-%s: SUCCESS" % (display_name, version_to_install), "Install.log")
success_msg = "Install of %s-%s: SUCCESS" % (display_name, version_to_install)
munkicommon.log(success_msg, "Install.log")
munkicommon.report['InstallResults'].append(success_msg)
else:
munkicommon.log("Install of %s-%s: FAILED with return code: %s" % (display_name, version_to_install, retcode), "Install.log")
failure_msg = "Install of %s-%s: FAILED with return code: %s" % (display_name, version_to_install, retcode)
munkicommon.log(failure_msg, "Install.log")
munkicommon.report['InstallResults'].append(failure_msg)
# check to see if this installer item is needed by any additional items in installinfo
# this might happen if there are mulitple things being installed with choicesXML files
@@ -333,15 +338,6 @@ def installWithInfo(dirpath, installlist, appleupdates=False):
return restartflag
def getRemovalCount(removalList):
count = 0
for item in removalList:
if 'installed' in item:
if item['installed']:
count +=1
return count
def processRemovals(removallist):
restartFlag = False
index = 0
@@ -452,17 +448,19 @@ def processRemovals(removallist):
# record removal success/failure
if retcode == 0:
munkicommon.log("Removal of %s: SUCCESS" % name, "Install.log")
success_msg = "Removal of %s: SUCCESS" % name
munkicommon.log(success_msg, "Install.log")
munkicommon.report['RemovalResults'].append(success_msg)
else:
munkicommon.log("Removal of %s: FAILED with return code: %s" % (name, retcode), "Install.log")
failure_msg = "Removal of %s: FAILED with return code: %s" % (name, retcode)
munkicommon.log(failure_msg, "Install.log")
munkicommon.report['RemovalResults'].append(failure_msg)
return restartFlag
def run():
managedinstallbase = munkicommon.pref('ManagedInstallDir')
installdir = os.path.join(managedinstallbase , 'Cache')
@@ -484,6 +482,7 @@ def run():
if "removals" in pl:
# filter list to items that need to be removed
removallist = [item for item in pl['removals'] if item.get('installed')]
munkicommon.report['ItemsToRemove'] = removallist
if removallist:
if munkicommon.munkistatusoutput:
if len(removallist) == 1:
@@ -498,6 +497,7 @@ def run():
if not munkicommon.stopRequested():
# filter list to items that need to be installed
installlist = [item for item in pl['managed_installs'] if item.get('installed') == False]
munkicommon.report['ItemsToInstall'] = installlist
if installlist:
if munkicommon.munkistatusoutput:
if len(installlist) == 1:
@@ -513,6 +513,7 @@ def run():
munkicommon.log("No %s found." % installinfo)
munkicommon.log("### End managed installer session ###")
munkicommon.savereport()
return (removals_need_restart or installs_need_restart)
+95 -10
View File
@@ -119,12 +119,13 @@ def display_detail(msg):
These are usually logged only, but can be printed to
stdout if verbose is set to 2 or higher
"""
log(msg)
if munkistatusoutput:
pass
elif verbose > 1:
print msg.encode('UTF-8')
sys.stdout.flush()
if logginglevel > 0:
log(msg)
def display_debug1(msg):
@@ -138,7 +139,7 @@ def display_debug1(msg):
print msg.encode('UTF-8')
sys.stdout.flush()
if logginglevel > 1:
log(msg)
log("DEBUG1: %s" % msg)
def display_debug2(msg):
@@ -151,7 +152,7 @@ def display_debug2(msg):
elif verbose > 3:
print msg.encode('UTF-8')
if logginglevel > 2:
log(msg)
log("DEBUG2: %s" % msg)
def reset_warnings():
@@ -170,6 +171,8 @@ def display_warning(msg):
log(warning)
# append this warning to our warnings log
log(warning, "warnings.log")
# collect the warning for later reporting
report['Warnings'].append(msg)
def reset_errors():
@@ -189,10 +192,12 @@ def display_error(msg):
# append this error to our errors log
log(errmsg, "errors.log")
# collect the errors for later reporting
errors = errors + msg + '\n'
report['Errors'].append(msg)
def log(msg, logname=''):
# date/time format string
formatstr = "%b %d %H:%M:%S"
if not logname:
# use our regular logfile
logpath = logfile
@@ -200,7 +205,7 @@ def log(msg, logname=''):
logpath = os.path.join(os.path.dirname(logfile), logname)
try:
f = open(logpath, mode='a', buffering=1)
print >>f, time.ctime(), msg.encode('UTF-8')
print >>f, time.strftime(formatstr), msg.encode('UTF-8')
f.close()
except:
pass
@@ -234,8 +239,89 @@ def rotate_main_log():
rotatelog(logfile)
def printreportitem(label, value, indent=0):
indentspace = " "
if type(value) == type(None):
print indentspace*indent, "%s: !NONE!" % label
elif type(value) == list or type(value).__name__ == 'NSCFArray':
if label:
print indentspace*indent, "%s:" % label
index = 0
for item in value:
index += 1
printreportitem(index, item, indent+1)
elif type(value) == dict or type(value).__name__ == 'NSCFDictionary':
if label:
print indentspace*indent, "%s:" % label
for subkey in value.keys():
printreportitem(subkey, value[subkey], indent+1)
else:
print indentspace*indent, "%s: %s" % (label, value)
def printreport(reportdict):
"""Prints the report dictionary in a pretty(?) way"""
for key in reportdict.keys():
printreportitem(key, reportdict[key])
def savereport():
FoundationPlist.writePlist(report, os.path.join(pref('ManagedInstallDir'), "ManagedInstallReport.plist"))
def archive_report():
reportfile = os.path.join(pref('ManagedInstallDir'), "ManagedInstallReport.plist")
if os.path.exists(reportfile):
modtime = os.stat(reportfile).st_mtime
formatstr = "%Y-%m-%d-%H%M%S"
archivename = "ManagedInstallReport-" + time.strftime(formatstr,time.localtime(modtime)) + ".plist"
archivepath = os.path.join(pref('ManagedInstallDir'), "Archives")
if not os.path.exists(archivepath):
try:
os.mkdir(archivepath)
except:
display_warning("Could not create report archive path.")
try:
os.rename(reportfile, os.path.join(archivepath, archivename))
# convert to binary format to compress
#cmd = ['/usr/bin/plutil', '-convert', 'binary1', os.path.join(archivepath, archivename)]
#p = subprocess.Popen(cmd, shell=False, bufsize=1, stdin=subprocess.PIPE,
# stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#(out, err) = p.communicate()
except:
display_warning("Could not archive report.")
# now keep number of archived reports to 100 or fewer
p = subprocess.Popen(['/bin/ls', '-t1', archivepath],
bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(output, err) = p.communicate()
if output:
archiveitems = [item for item in output.splitlines() if item.startswith("ManagedInstallReport-")]
if len(archiveitems) > 100:
for item in archiveitems[100:]:
itempath = os.path.join(archivepath, archiveitem)
if os.path.isfile(itempath):
try:
os.unlink(itempath)
except:
display_warning("Could not remove archive item %s" % itempath)
# misc functions
def validPlist(path):
'''Uses plutil to determine if path contains a valid plist.
Returns True or False.'''
cmd = ['/usr/bin/plutil', '-lint', '-s' , path]
p = subprocess.Popen(cmd, shell=False, bufsize=1, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = p.communicate()
if p.returncode == 0:
return True
else:
return False
def stopRequested():
"""Allows user to cancel operations when
MunkiStatus is being used"""
@@ -689,8 +775,7 @@ def getInstalledPackageVersion(pkgid):
Returns the version string of the installed pkg
if it exists, or an empty string if it does not
"""
# First check (Leopard and later) package database
try:
p = subprocess.Popen(["/usr/sbin/pkgutil", "--pkg-info-plist", pkgid], bufsize=1,
@@ -876,12 +961,12 @@ def cleanUpTmpDir():
debug = False
verbose = 1
munkistatusoutput = False
errors = ""
warnings = ""
tmpdir = tempfile.mkdtemp()
logfile = pref('LogFile')
logginglevel = pref('LoggingLevel')
report = {}
report['Errors'] = []
report['Warnings'] = []
def main():
+121 -103
View File
@@ -40,25 +40,6 @@ import munkicommon
import munkistatus
import FoundationPlist
def reporterrors():
# just a placeholder right now;
# this needs to be expanded to support error reporting
# via email and HTTP CGI.
# (and maybe moved to a library module so the installer
# can use it, too.)
managedinstallprefs = munkicommon.prefs()
clientidentifier = managedinstallprefs.get('ClientIdentifier','')
#alternate_id = option_id
hostname = os.uname()[1]
print "installcheck errors %s:" % datetime.datetime.now().ctime()
print "Hostname: %s" % hostname
print "Client identifier: %s" % clientidentifier
#print "Alternate ID: %s" % alternate_id
print "-----------------------------------------"
print munkicommon.errors
# global to hold our catalog DBs
catalog = {}
@@ -615,15 +596,13 @@ def download_installeritem(location):
pkgname = os.path.basename(location)
destinationpath = os.path.join(mycachedir, pkgname)
munkicommon.display_detail("Downloading %s from %s" % (pkgname, location))
# bump up verboseness so we get download percentage done feedback.
# this is kind of a hack...
oldverbose = munkicommon.verbose
munkicommon.verbose = oldverbose + 1
munkicommon.log("Downloading %s from %s" % (pkgname, location))
dl_message = "Downloading %s..." % pkgname
(path, err) = getHTTPfileIfNewerAtomically(pkgurl, destinationpath, message=dl_message)
# set verboseness back.
munkicommon.verbose = oldverbose
@@ -632,8 +611,7 @@ def download_installeritem(location):
else:
munkicommon.display_error("Could not download %s from server." % pkgname)
munkicommon.display_error(err)
return False
return False
def isItemInInstallInfo(manifestitem_pl, thelist, vers=''):
@@ -1423,13 +1401,20 @@ def getCatalogs(cataloglist):
if not catalogname in catalog:
catalogurl = catalogbaseurl + urllib2.quote(catalogname)
catalogpath = os.path.join(catalog_dir, catalogname)
munkicommon.log("Getting catalog %s..." % catalogname)
munkicommon.display_detail("Getting catalog %s..." % catalogname)
message = "Retreiving catalog '%s'..." % catalogname
(newcatalog, err) = getHTTPfileIfNewerAtomically(catalogurl, catalogpath, message=message)
if newcatalog:
catalog[catalogname] = makeCatalogDB(FoundationPlist.readPlist(newcatalog))
if munkicommon.validPlist(newcatalog):
catalog[catalogname] = makeCatalogDB(FoundationPlist.readPlist(newcatalog))
else:
munkicommon.display_error("Retreived catalog %s is invalid." % catalogname)
try:
os.unlink(newcatalog)
except:
pass
else:
munkicommon.display_error("Could not retreive catalog %s from server." % catalog)
munkicommon.display_error("Could not retrieve catalog %s from server." % catalogname)
munkicommon.display_error(err)
@@ -1449,25 +1434,34 @@ def getmanifest(partialurl, suppress_errors=False):
manifestname = "client_manifest.plist"
else:
# request for nested manifest
munkicommon.log("Getting manifest %s..." % partialurl)
munkicommon.display_detail("Getting manifest %s..." % partialurl)
manifestname = os.path.split(partialurl)[1]
manifesturl = manifestbaseurl + urllib2.quote(partialurl)
manifestpath = os.path.join(manifest_dir, manifestname)
message = "Retreiving list of software for this machine..."
(newmanifest, err) = getHTTPfileIfNewerAtomically(manifesturl, manifestpath, message=message)
if not newmanifest and not suppress_errors:
munkicommon.display_error("Could not retreive manifest %s from the server." % partialurl)
munkicommon.display_error(err)
return newmanifest
if not newmanifest:
if not suppress_errors:
munkicommon.display_error("Could not retrieve manifest %s from the server." % partialurl)
munkicommon.display_error(err)
return None
if munkicommon.validPlist(newmanifest):
return newmanifest
else:
munkicommon.display_error("manifest returned for %s is invalid." % partialurl)
try:
os.unlink(newmanifest)
except:
pass
return None
def getPrimaryManifest(alternate_id):
"""
Gets the client manifest from the server
"""
global errors
manifest = ""
manifesturl = munkicommon.pref('ManifestURL') or munkicommon.pref('SoftwareRepoURL') + "/manifests/"
if not manifesturl.endswith('?') and not manifesturl.endswith('/'):
@@ -1489,43 +1483,31 @@ def getPrimaryManifest(alternate_id):
if not manifest:
# last resort - try for the site_default manifest
clientidentifier = "site_default"
munkicommon.display_detail("Request failed. Trying ..." % clientidentifier)
munkicommon.display_detail("Request failed. Trying %s..." % clientidentifier)
if not manifest:
manifest = getmanifest(manifesturl + urllib2.quote(clientidentifier))
if manifest:
# record this info for later
munkicommon.report['ManifestName'] = clientidentifier
munkicommon.display_detail("Using manifest: %s" % clientidentifier)
# clear out any errors we got while trying to find
# the primary manifest
errors = ""
return manifest
def getInstallCount(installinfo):
count = 0
for item in installinfo.get('managed_installs',[]):
if 'installer_item' in item:
count +=1
return count
def getRemovalCount(installinfo):
count = 0
for item in installinfo.get('removals',[]):
if 'installed' in item:
if item['installed']:
count +=1
return count
def checkServer():
'''in progress'''
managedinstallprefs = munkicommon.prefs()
manifesturl = managedinstallprefs['ManifestURL']
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...'''
# deconstruct URL so we can check availability
port = 80
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(manifesturl)
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(url)
if scheme == "http":
port = 80
elif scheme == "https":
port = 443
else:
return False
# get rid of any embedded username/password
netlocparts = netloc.split("@")
netloc = netlocparts[-1]
@@ -1533,15 +1515,27 @@ def checkServer():
netlocparts = netloc.split(":")
host = netlocparts[0]
if len(netlocparts) == 2:
port = netlocparts[1]
port = int(netlocparts[1])
s = socket.socket()
#try:
s.connect((host, port))
s.close()
return True
#except:
#return False
# set timeout to 5 secs
s.settimeout(5.0)
try:
s.connect((host, port))
s.close()
return (0, 'OK')
except socket.error, err:
if type(err) == str:
return (-1, err)
else:
return err
except socket.timeout, err:
return (-1, err)
except Exception, err:
# common errors
# (50, 'Network is down')
# (8, 'nodename nor servname provided, or not known')
# (61, 'Connection refused')
return tuple(err)
# HTTP download functions
@@ -1554,8 +1548,8 @@ def checkServer():
# one on the server.
#
# Possible failure mode: if client's main catalog gets pointed
# to a different, older, catalog, we'll fail to retreive it.
# Need to check content length as well, and if it changes, retreive
# to a different, older, catalog, we'll fail to retrieve it.
# Need to check content length as well, and if it changes, retrieve
# it anyway.
#
# Should probably cleanup/unify
@@ -1598,6 +1592,8 @@ def httpDownload(url, filename, headers={}, postData=None, reporthook=None, mess
UseClientCertificate = munkicommon.pref('UseClientCertificate')
cert = os.path.join(ManagedInstallDir, 'certs', pemfile)
# set default timeout so we don't hang if the server stops responding
socket.setdefaulttimeout(30)
reqObj = urllib2.Request(url, postData, headers)
if UseClientCertificate == True:
@@ -1660,7 +1656,7 @@ def getfilefromhttpurl(url,filepath, ifmodifiedsince=None, message=None):
"""
gets a file from a url.
If 'ifmodifiedsince' is specified, this header is set
and the file is not retreived if it hasn't changed on the server.
and the file is not retrieved if it hasn't changed on the server.
Returns 0 if successful, or HTTP error code
"""
def reporthook(block_count, block_size, file_size):
@@ -1732,7 +1728,7 @@ def getHTTPfileIfNewerAtomically(url,destinationpath, message=None):
err = "SSL_CTX_use_certificate_chain_file error: Certificate Invalid or Missing"
destinationpath = None
else:
err = "Error code: %s retreiving %s" % (result, url)
err = "Error code: %s retrieving %s" % (result, url)
destinationpath = None
if os.path.exists(mytemppath):
@@ -1744,6 +1740,7 @@ def getHTTPfileIfNewerAtomically(url,destinationpath, message=None):
def getMachineFacts():
global machine
machine['hostname'] = os.uname()[1]
machine['arch'] = os.uname()[4]
cmd = ['/usr/bin/sw_vers', '-productVersion']
p = subprocess.Popen(cmd, shell=False, bufsize=1, stdin=subprocess.PIPE,
@@ -1755,13 +1752,12 @@ def getMachineFacts():
# some globals
machine = {}
def check(id=''):
'''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.'''
getMachineFacts()
munkicommon.report['MachineInfo'] = machine
ManagedInstallDir = munkicommon.pref('ManagedInstallDir')
@@ -1804,19 +1800,38 @@ def check(id=''):
# this could happen if an item is downloaded on one
# updatecheck run, but later removed from the manifest
# before it is installed or removed
cache_list = []
for item in installinfo['managed_installs']:
if "installer_item" in item:
cache_list.append(item["installer_item"])
for item in installinfo['removals']:
if "uninstaller_item" in item:
cache_list.append(item["uninstaller_item"])
#cache_list = []
#for item in installinfo['managed_installs']:
# if "installer_item" in item:
# cache_list.append(item["installer_item"])
#for item in installinfo['removals']:
# if "uninstaller_item" in item:
# cache_list.append(item["uninstaller_item"])
cache_list = [item["installer_item"] for item in installinfo['managed_installs'] if item.get("installer_item")]
cache_list.extend([item["uninstaller_item"] for item in installinfo['removals'] if item.get("uninstaller_item")])
cachedir = os.path.join(ManagedInstallDir, "Cache")
for item in os.listdir(cachedir):
if item not in cache_list:
munkicommon.display_detail("Removing %s from cache" % item)
os.unlink(os.path.join(cachedir, item))
# filter managed_installs to get items already installed
installed_items = [item for item in installinfo['managed_installs'] if item.get('installed')]
# filter managed_installs to get problem items: not installed, but no installer item
problem_items = [item for item in installinfo['managed_installs'] if item.get('installed') == False and not item.get('installer_item')]
# filter removals to get items already removed (or never installed)
removed_items = [item for item in installinfo['removals'] if item.get('installed') == False]
# filter managed_installs and removals lists so they have only items that need action
installinfo['managed_installs'] = [item for item in installinfo['managed_installs'] if item.get('installer_item')]
installinfo['removals'] = [item for item in installinfo['removals'] if item.get('installed')]
munkicommon.report['ManagedInstalls'] = installed_items
munkicommon.report['ProblemInstalls'] = problem_items
munkicommon.report['RemovedItems'] = removed_items
munkicommon.report['ItemsToInstall'] = installinfo['managed_installs']
munkicommon.report['ItemsToRemove'] = installinfo['removals']
# write out install list so our installer
# can use it to install things in the right order
installinfochanged = True
@@ -1832,43 +1847,46 @@ def check(id=''):
else:
# couldn't get a primary manifest. Check to see if we have a valid InstallList from
# an earlier run.
munkicommon.display_error("Could not retreive managed install primary manifest.")
munkicommon.display_error("Could not retrieve managed install primary manifest.")
installinfopath = os.path.join(ManagedInstallDir, "InstallInfo.plist")
if os.path.exists(installinfopath):
try:
installinfo = FoundationPlist.readPlist(installinfopath)
munkicommon.report['ItemsToInstall'] = installinfo.get('managed_installs',[])
munkicommon.report['ItemsToRemove'] = installinfo.get('removals',[])
except:
installinfo = {}
installcount = getInstallCount(installinfo)
removalcount = getRemovalCount(installinfo)
installcount = len(installinfo.get("managed_installs",[]))
removalcount = len(installinfo.get("removals",[]))
if installcount:
munkicommon.log("")
if installcount:
munkicommon.display_info("The following items will be installed or upgraded:")
for item in installinfo['managed_installs']:
if item.get('installer_item'):
munkicommon.display_info(" + %s-%s" % (item.get('name',''), item.get('version_to_install','')))
if item.get('description'):
munkicommon.display_info(" %s" % item['description'])
if item.get('RestartAction') == 'RequireRestart':
munkicommon.display_info(" *Restart required")
for item in installinfo['managed_installs']:
if item.get('installer_item'):
munkicommon.display_info(" + %s-%s" % (item.get('name',''), item.get('version_to_install','')))
if item.get('description'):
munkicommon.display_info(" %s" % item['description'])
if item.get('RestartAction') == 'RequireRestart':
munkicommon.display_info(" *Restart required")
munkicommon.report['RestartRequired'] = True
if removalcount:
munkicommon.display_info("The following items will be removed:")
for item in installinfo['removals']:
if item.get('installed'):
munkicommon.display_info(" - %s" % item.get('name'))
if item.get('RestartAction') == 'RequireRestart':
munkicommon.display_info(" *Restart required")
for item in installinfo['removals']:
if item.get('installed'):
munkicommon.display_info(" - %s" % item.get('name'))
if item.get('RestartAction') == 'RequireRestart':
munkicommon.display_info(" *Restart required")
munkicommon.report['RestartRequired'] = True
if installcount == 0 and removalcount == 0:
munkicommon.display_info("No changes to managed software are available.")
munkicommon.savereport()
munkicommon.log("### End managed software check ###")
if munkicommon.errors:
reporterrors()
if installcount or removalcount:
return 1
else: