Skip to content

Instantly share code, notes, and snippets.

@timsutton
Created March 29, 2017 15:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timsutton/db17054ed3afcd8947fcd5c499ced9af to your computer and use it in GitHub Desktop.
Save timsutton/db17054ed3afcd8947fcd5c499ced9af to your computer and use it in GitHub Desktop.
Munki conditional for checking eligible OS upgrades
#!/usr/bin/python
# encoding: utf-8
#
# Modified from Hannes Juutilainen's check-1012-sierra-compatibility.py
# and check-10.8-mountainlion-compatibility.py scripts from
#
# Hannes Juutilainen <hjuutilainen@mac.com>
# https://github.com/hjuutilainen/adminscripts
#
# Modified to return a single condition, `supported_major_os_upgrades`, which is
# an array containing a list of all major OS versions that this machine can be
# upgraded to, i.e. ['10.8', '10.9', '10.10', '10.11', '10.12']
#
# Major versions which match the machine version or are older are removed from
# the list, so that Munki conditions don't need to also check for the current
# OS version - this script will handle that.
#
# See KNOWN_VERSIONS for the OS values supported.
import sys
import subprocess
import os
import re
import plistlib
from platform import mac_ver
from distutils.version import LooseVersion
from Foundation import CFPreferencesCopyAppValue
KNOWN_VERSIONS = ['10.8', '10.9', '10.10', '10.11', '10.12']
# Set this to False if you don't want any output, just the exit codes
VERBOSE = True
CONDITIONAL_KEY = 'supported_major_os_upgrades'
def logger(message, status, info):
if VERBOSE:
print "%14s: %-40s [%s]" % (message, status, info)
pass
def conditional_items_path():
# <http://code.google.com/p/munki/wiki/ConditionalItems>
# Read the location of the ManagedInstallDir from ManagedInstall.plist
bundle_id = 'ManagedInstalls'
pref_name = 'ManagedInstallDir'
managed_installs_dir = CFPreferencesCopyAppValue(pref_name, bundle_id)
# Make sure we're outputting our information to "ConditionalItems.plist"
if managed_installs_dir:
return os.path.join(managed_installs_dir, 'ConditionalItems.plist')
else:
# Munki default
return "/Library/Managed Installs/ConditionalItems.plist"
def get_full_system_version():
'''Returns a LooseVersion like '10.12', '10.11.6', etc.'''
return LooseVersion(mac_ver()[0])
def get_major_system_version():
'''Returns the major system version as just an int'''
return int(mac_ver()[0].split('.')[1])
def is_64bit_efi():
cmd = ["/usr/sbin/ioreg",
"-l",
"-p", "IODeviceTree",
]
proc = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(results, _) = proc.communicate()
efi_64 = False
for line in results.splitlines():
if re.search('firmware-abi.*EFI64', line):
efi_64 = True
break
if efi_64:
logger("EFI",
"64 bit capable",
"OK")
return True
else:
logger("EFI",
"not 64 bit capable",
"Failed")
return False
def get_board_id():
cmd = ["/usr/sbin/ioreg",
"-p", "IODeviceTree",
"-r",
"-n", "/",
"-d", "1"]
p1 = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = subprocess.Popen(["/usr/bin/grep", "board-id"], stdin=p1.stdout, stdout=subprocess.PIPE)
(results, err) = p2.communicate()
board_id = re.sub(r"^\s*\"board-id\" = <\"(.*)\">$", r"\1", results)
board_id = board_id.strip()
if board_id.startswith('Mac'):
return board_id
else:
return None
def is_virtual_machine():
cmd = ["/usr/sbin/sysctl", "-n", "machdep.cpu.features"]
p = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(results, err) = p.communicate()
for feature in results.split():
if feature == "VMM":
logger("Board ID",
"Virtual machine",
"OK")
return True
return False
def get_current_model():
cmd = ["/usr/sbin/sysctl", "-n", "hw.model"]
p = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(results, err) = p.communicate()
return results.strip()
def is_sierra_supported_model():
non_supported_models = [
'iMac4,1',
'iMac4,2',
'iMac5,1',
'iMac5,2',
'iMac6,1',
'iMac7,1',
'iMac8,1',
'iMac9,1',
'MacBook1,1',
'MacBook2,1',
'MacBook3,1',
'MacBook4,1',
'MacBook5,1',
'MacBook5,2',
'MacBookAir1,1',
'MacBookAir2,1',
'MacBookPro1,1',
'MacBookPro1,2',
'MacBookPro2,1',
'MacBookPro2,2',
'MacBookPro3,1',
'MacBookPro4,1',
'MacBookPro5,1',
'MacBookPro5,2',
'MacBookPro5,3',
'MacBookPro5,4',
'MacBookPro5,5',
'Macmini1,1',
'Macmini2,1',
'Macmini3,1',
'MacPro1,1',
'MacPro2,1',
'MacPro3,1',
'MacPro4,1',
'Xserve1,1',
'Xserve2,1',
'Xserve3,1']
current_model = get_current_model()
if current_model in non_supported_models:
logger("Model",
"\"%s\" is not supported" % current_model,
"Failed")
return False
else:
logger("Model",
current_model,
"OK")
return True
def is_sierra_supported_board_id():
platform_support_values = [
'Mac-00BE6ED71E35EB86',
'Mac-031AEE4D24BFF0B1',
'Mac-031B6874CF7F642A',
'Mac-06F11F11946D27C5',
'Mac-06F11FD93F0323C5',
'Mac-189A3D4F975D5FFC',
'Mac-27ADBB7B4CEE8E61',
'Mac-2BD1B31983FE1663',
'Mac-2E6FAB96566FE58C',
'Mac-35C1E88140C3E6CF',
'Mac-35C5E08120C7EEAF',
'Mac-3CBD00234E554E41',
'Mac-42FD25EABCABB274',
'Mac-4B7AC7E43945597E',
'Mac-4BC72D62AD45599E',
'Mac-50619A408DB004DA',
'Mac-65CE76090165799A',
'Mac-66F35F19FE2A0D05',
'Mac-6F01561E16C75D06',
'Mac-742912EFDBEE19B3',
'Mac-77EB7D7DAF985301',
'Mac-7BA5B2794B2CDB12',
'Mac-7DF21CB3ED6977E5',
'Mac-7DF2A3B5E5D671ED',
'Mac-81E3E92DD6088272',
'Mac-8ED6AF5B48C039E1',
'Mac-937CB26E2E02BB01',
'Mac-942452F5819B1C1B',
'Mac-942459F5819B171B',
'Mac-94245A3940C91C80',
'Mac-94245B3640C91C81',
'Mac-942B59F58194171B',
'Mac-942B5BF58194151B',
'Mac-942C5DF58193131B',
'Mac-9AE82516C7C6B903',
'Mac-9F18E312C5C2BF0B',
'Mac-A369DDC4E67F1C45',
'Mac-AFD8A9D944EA4843',
'Mac-B809C3757DA9BB8D',
'Mac-BE0E8AC46FE800CC',
'Mac-C08A6BB70A942AC2',
'Mac-C3EC7CD22292981F',
'Mac-DB15BD556843C820',
'Mac-E43C1C25D4880AD6',
'Mac-F2208EC8',
'Mac-F221BEC8',
'Mac-F221DCC8',
'Mac-F222BEC8',
'Mac-F2238AC8',
'Mac-F2238BAE',
'Mac-F22586C8',
'Mac-F22589C8',
'Mac-F2268CC8',
'Mac-F2268DAE',
'Mac-F2268DC8',
'Mac-F22C89C8',
'Mac-F22C8AC8',
'Mac-F305150B0C7DEEEF',
'Mac-F60DEB81FF30ACF6',
'Mac-F65AE981FFA204ED',
'Mac-FA842E06C61E91C5',
'Mac-FC02E91DDD3FA6A4',
'Mac-FFE5EF870D7BA81A']
board_id = get_board_id()
if board_id in platform_support_values:
logger("Board ID",
board_id,
"OK")
return True
else:
logger("Board ID",
"\"%s\" is not supported" % board_id,
"Failed")
return False
def append_conditional_items(item):
output_dict = dict()
current_conditional_items_path = conditional_items_path()
if os.path.exists(current_conditional_items_path):
existing_dict = plistlib.readPlist(current_conditional_items_path)
output_dict.update(existing_dict)
output_dict[CONDITIONAL_KEY] = item
plistlib.writePlist(output_dict, current_conditional_items_path)
def main():
supported_list = []
if is_virtual_machine():
supported_list = KNOWN_VERSIONS[:]
else:
if is_64bit_efi():
supported_list.extend(['10.8', '10.9', '10.10', '10.11'])
if is_sierra_supported_board_id() and is_sierra_supported_model():
if get_full_system_version() >= LooseVersion('10.7.5'):
supported_list.append('10.12')
# Now filter out all major versions <= what we're running so that
# we can't install on top of ourself, or attempt to install an
# older version
running_major_version = get_major_system_version()
filtered_list = []
for version in supported_list:
if int(version.split('.')[1]) > running_major_version:
filtered_list.append(version)
append_conditional_items(filtered_list)
if __name__ == '__main__':
sys.exit(main())
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment