Munki Conditional by the JSS's Department

Munki Conditional by the JSS's Department

2015, Sep 04    

Here in our College we have a department that is going to begin using locked printing as well as purchases a department license for SPSS. Since the license for SPSS is the same and I don't want to offer the printers to everyone I thought we could utilize JAMF's inventory information to offer items based off department. The drawback though is JAMF does not have Payload Variables for Department, Department ID or Site Name. (Our Sites are the same as the departments) If you would like for this to change you can up vote this post here JAMF Nation Feature Request. This doesn't help me now so I wanted a great way to utilize this information for use with Munki.

To do this I created a Python script that will access the Rest API of JAMF.  The Rest API provides a lot of information and I suggest reading this post: The JSS Rest API for Everyone.  Ok let's get into the fun stuff.

After a lot of trial and error I found out that in order to utilize the Rest API it was best to use cURL as the URLLIB2 in Python does not have native support for TLS. Also it is very important that as of Casper 9.73 that you will need to add this Cipher in your server.xml file in the TomCat config (JSS/Tomcat/conf/server.xml) in order for older OS X clients to utilize cURL:

TLS_RSA_WITH_AES_128_CBC_SHA

Once that is added you can pretty much copy and paste this Python script and fill in the additional information for your JSS and your Authorization Header. I would suggest creating a local user in JAMF that only can read information from the JSS.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#!/usr/bin/env python
'''This script will determine the department of
the computer as listed in the JSS so department
specific applications can be distributed to the
machine using Munki Admin conditions.
Joshua D. Miller - [email protected] - September 2, 2015
The Pennsylvania State University '''

# Import Resources needed to perform this check in JAMF
import plistlib, os, platform
from xml.dom import minidom
from subprocess import check_output
from Foundation import CFPreferencesCopyAppValue
from distutils.version import LooseVersion

# Read the location of the ManagedInstallDir from ManagedInstall.plist
# This code from the Munki Wiki - Greg Neagle
BUNDLE_ID = 'ManagedInstalls'
PREF_NAME = 'ManagedInstallDir'
MANAGEDINSTALLDIR = CFPreferencesCopyAppValue(PREF_NAME, BUNDLE_ID)
CONDITIONALITEMSPATH = os.path.join(MANAGEDINSTALLDIR, 'ConditionalItems.plist')

# Get computer name by using the native OSX scutil
COMPUTER_NAME = check_output(['/usr/sbin/scutil', '--get', 'ComputerName']).strip()

# Set the URL and only grab XML from the location portion of the inventory
URL = 'https://YourJSSHere/JSSResource/computers/name/' \
 + COMPUTER_NAME + '/subset/Location'
AUTH = 'Authorization: Basic Your Scrambled Base64 Encoded User/Pass Here'
XMLAPP = 'Accept: application/xml'
XMLCONTENT = 'Content-Type: application/xml'

# Determine the OS This is running on and then use either TLSv1 or TLSv1.2
if platform.mac_ver()[0] >= LooseVersion('10.10.5'):
    # Use cURL to get XML Data about the computer using TLSv1.2
    OUTPUT = check_output(['/usr/bin/curl', '--tlsv1.2', '-H', AUTH, '-H', \
        XMLAPP, '-H', XMLCONTENT, URL]).rstrip()
else:
    # Use cURL to get XML Data about the computer using TLSv1
    OUTPUT = check_output(['/usr/bin/curl', '--tlsv1', '-H', AUTH, '-H', \
        XMLAPP, '-H', XMLCONTENT, URL]).rstrip()

# Parse the output as XML
DOM = minidom.parseString(OUTPUT)
# Look for a specific tag
XMLTAG = DOM.getElementsByTagName('department')[0].toxml()
# Strip the tags from the output you want to print out
XMLDATA = XMLTAG.replace('<department>', '').replace('</department>', '')
DEPARTMENT_DICT = dict(department=XMLDATA)

# Read in ConditionalItems.plist and if it doesn't exist create it and write the values
if os.path.exists(CONDITIONALITEMSPATH):
    EXISTING_DICT = plistlib.readPlist(CONDITIONALITEMSPATH)
    OUTPUT_DICT = dict(EXISTING_DICT.items() + DEPARTMENT_DICT.items())
else:
    OUTPUT_DICT = DEPARTMENT_DICT
plistlib.writePlist(OUTPUT_DICT, CONDITIONALITEMSPATH)

Once you have this created you will want to deploy this with Munki into the folder /usr/local/munki/conditions.  I like to use MD5 to make sure that the file is the file I specified.  Lastly, you will just need to put in any of your manifests that hit your users (ex. global) what you want to offer based off the new conditional item Department. As always if you have any questions please be sure to let me know.