New to the API, not sure where to start

ejculpepper
Contributor

I have been tasked with scripting and scheduling an API call to /mobiledevices to export device data to a CSV file. I would like to learn how to call the API using a Python script and schedule it on our Windows Server hosting our JSS.

I have read several pages of documentation on starting with the API and looked through several scripts, however I am still just not grasping the concept it seems. I have little experience with scripting, so some of the sample scripts I've seen seem intimidating.

Is there such a thing as a "skeleton" script that has the most basic needs to call the API and return output to the console or a CSV file? I think once I see the basics I can build on it from there, i'm just not understanding how it all comes together to produce any output.

15 REPLIES 15

blackholemac
Valued Contributor III

I am by no means an API expert but I can reference two posts to you:

The first one: https://www.jamf.com/jamf-nation/discussions/4078/jamf-rest-api-get

This one shows the most basic curl command to get some stuff from a given device record. Another guy posted on it with a script that helped that user.

The second one: https://www.jamf.com/jamf-nation/discussions/20197/pull-asset-tag-information-from-jss-record-for-use-in-bash-scripts

This one had a helpful post from @mm2270 trying to help someone formulate a good script for asset tags

ejculpepper
Contributor

Thanks @blackholemac , i'm currently building a script in python using the second link as a reference, i'll see what I can come up with.

danshaw
Contributor II

It kinda blows my mind why there isn't any documentation on the API from JAMF. I'm starting to use it more and more and the only way I have been able to figure it out is by scouring the discussions. Hope that changes.

boberito
Valued Contributor

Just to pat myself on the back my talk from the JNUC last year may help

https://www.youtube.com/watch?v=SdSWh0ld9IY

And my GitHub of scripts. Some are python...so I dunno enjoy
http://github.com/boberito/

BradB
New Contributor III

@danshaw Take a look at https://developer.jamf.com. You can also interact directly with the API on your own Jamf Pro instance at the /api URL.

danshaw
Contributor II

@beckerbm Woah! Now we're talking. That link is a huge help. Thank you for pointing that out. As far as /api is concerned, that no longer works for me. It broke when I upgraded to v10.

BradB
New Contributor III

@danshaw Glad the link is helpful. Not sure why your /api is broken, I'd recommend opening up a support ticket on that because it should still work.

mm2270
Legendary Contributor III

@danshaw While I kind of agree that Jamf should provide more robust documentation on it, and I've advocated for that on various threads and feature requests, you do at least have access to the built in documentation on the JSS itself at https://your.jamfpro.server:8443/api
Granted, it doesn't always satisfy my needs, but it's something, and can get most people started at least.

Edit: Ok, I think I either didn't know about the API link above, or had forgotten about it. That's helpful!

Asnyder
Contributor III

I'm working on a project right now to pass information between jamf and snipe-it. Here's my section of code getting information from jamf.
This gets the serial number of the machine the script is running it on and then does a "get" on it and prints some basic info. You can change the endpoint and use it to get mobile device data. Hopefully, this gives you something else helpful to look at.

NOTE: I'm using verify false because it wasn't reading my cert for some reason. I'm sure this could be a lot cleaner as I don't know python very well. Also, hop into the macadmins python channel.

import requests
import json
import subprocess
import plistlib


#########################################
#                                       #
# GARBAGE TO GET SERIAL NUMBER          #
#                                       #
#########################################

cmd = ['/usr/sbin/system_profiler', 'SPHardwareDataType', '-xml']

proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(output, error) = proc.communicate()


info = plistlib.readPlistFromString(output)

hardware_info = info[0]['_items'][0]
hardware_info.keys()


# hardware_info['cpu_type']
# hardware_info['machine_model']
# hardware_info['serial_number']

computer_serial = hardware_info['serial_number']

############################################################################
#                                                                          #
# SET API VARIABLES                                                        #
#                                                                          #
############################################################################

# JSS SETUP
jss = "https://jss.mycompany.com:8443/JSSResource/computers/serialnumber/"+computer_serial
jss_user = "readuser"
jss_password = "readpassword"
jss_headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
}

########################################
# GET JSS INFO AND STORE IN VARIABLES  #
########################################
jss_response = requests.get(jss, auth=(jss_user, jss_password), headers=jss_headers, verify=False)
print("JSS RESPONSE")
#print(jss_response.text)

jss_result = json.loads(jss_response.text)

jss_computer_name = (jss_result['computer']['general']['name'])
jss_asset_tag = (jss_result['computer']['general']['asset_tag'])
print(jss_computer_name)
print(jss_asset_tag)
print("
")
print("
")

ejculpepper
Contributor

Thank you to @Asnyder , @beckerbm , and @boberito for your responses, after reading through documentation from the resources you suggested and referencing some sample code, I believe I understand the theory behind how this all works now. I've pieced together a basic section of code to prompt for input, query our JSS using /mobiledevices, and output the data as JSON and XML just as a test to see what output I get.

I got the JSON output to work fine, however I am receiving an error on my XML portion. I am using xml.etree.ElementTree to parse the XML, I thought I had the code correct from what i've seen, but I receive an error stating:

Traceback (most recent call last): xml = eTree.fromstring(response_xml.read()) File "C:Python27amd64libxmletreeElementTree.py", line 1312, in XML return parser.close() File "C:Python27amd64libxmletreeElementTree.py", line 1671, in close self._raiseerror(v) File "C:Python27amd64libxmletreeElementTree.py", line 1523, in _raiseerror raise err
xml.etree.ElementTree.ParseError: no element found: line 1, column 0

Below is the full code block i'm using:

import xml.etree.ElementTree as eTree
import urllib2
import base64
import json


#Prompt user for API credentials and JSS URL
apiUser = raw_input("Enter API Username: ")
apiPass = raw_input("Enter API Password: ")
jssURL = raw_input("Enter JSS URL: ")

#request
request = urllib2.Request(jssURL + "/JSSResource/mobiledevices")
request.add_header('Accept', 'application/json')
request.add_header('Authorization', 'Basic ' + base64.b64encode(apiUser + ':' + apiPass))

#response in JSON
response_json = urllib2.urlopen(request)
response_data = json.loads(response_json.read())
print response_data

#response in XML
response_xml = urllib2.urlopen(request)
response_xml.code
response_xml.read()
xml = eTree.fromstring(response_xml.read())

Any ideas on what i'm doing wrong with the XML section?

Asnyder
Contributor III

@ejculpepper

You're asking for json and then trying to parse it as xml

request.add_header('Accept', 'application/json')

Is saying that you want to receive json, and then you try to parse that as xml instead of json.

xml = eTree.fromstring(response_xml.read())

ejculpepper
Contributor

@Asnyder

I thought that might be an issue, so I tried commenting out the json portion of the request and response, but I still received the same error when trying to parse the XML.

I started a Python course over the weekend, going to skip to the section covering this topic to see if I can figure out what i'm doing wrong. I've forgotten most of what I learned in Python years ago...haven't had to use it until now.

Asnyder
Contributor III

@ejculpepper Try keeping everything the same but use 'application/xml' instead of 'application/json' and comment out the json section. I use the requests module so I'm not very familiar with how urllib2 works.

ejculpepper
Contributor

@Asnyder

Just tried using 'application/xml' instead of 'application/json', received the same error as before.

I got the code working using the requests module instead, so I now have the xml and json responses to work with. I think i'll use this method for the time being to build my code, i'll work on getting the urllib2 module working properly on the side.

Thank you!

nberanger
Contributor

@ejculpepper Did you ever get your script working? I am just starting to look at Snie-IT and will also want a way to have the info from Jamf synced to it. At this point I don't know enough about Python to create something myself, so I am hoping to be able to work with a script someone else has created ;-)