From 44e7fff54c5b3da63f8814256070cc34267ad166 Mon Sep 17 00:00:00 2001 From: Rusty Myers Date: Wed, 18 Oct 2023 14:24:02 -0400 Subject: [PATCH 01/28] Adding config file --- sync.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/sync.py b/sync.py index eea492c..0f84f6e 100755 --- a/sync.py +++ b/sync.py @@ -12,6 +12,7 @@ import async_timeout import aiohttp import uvloop +import configparser logging.basicConfig( level=logging.DEBUG, @@ -417,6 +418,37 @@ async def main(): if args.jenkins: write_jenkins_file() + # Get configs from files + CONFIG_FILE_LOCATIONS = ['jamfapi.cfg',os.path.expanduser('~/jamfapi.cfg')] + CONFIG_FILE = '' + # Parse Config File + CONFPARSER = configparser.ConfigParser() + for config_path in CONFIG_FILE_LOCATIONS: + if os.path.exists(config_path): + print("Found Config: {0}".format(config_path)) + CONFIG_FILE = config_path + + if CONFIG_FILE == "": + config_ = configparser.ConfigParser() + config_['jss'] = {} + config_['jss']['username'] = "username" + config_['jss']['password'] = "password" + config_['jss']['server'] = "server" + print(config_) + with open('jamfapi.cfg', 'w') as configfile: + config_.write(configfile) + print("Config File Created. Please edit jamfapi.cfg and run again.") + + print("No Config File found!") + exit(0) + else: + # Read local directory, user home, then /etc/ for besapi.conf + CONFPARSER.read(CONFIG_FILE) + # If file exists + # Get config + args.username = CONFPARSER.get('jss', 'username') + args.password = CONFPARSER.get('jss', 'password') + args.url = CONFPARSER.get('jss', 'server') # Ask for password if not supplied via command line args if not args.password: From 78915979c09ad37e7e7ba28074b26e9a19127fe6 Mon Sep 17 00:00:00 2001 From: Rusty Myers Date: Wed, 18 Oct 2023 14:34:37 -0400 Subject: [PATCH 02/28] Adding Requirements, configparser to download.py --- requirements.txt | 1 + tools/download.py | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1871bbf..c201a9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ cchardet aiodns uvloop requests +configparser \ No newline at end of file diff --git a/tools/download.py b/tools/download.py index 95b2aa6..c9961dd 100755 --- a/tools/download.py +++ b/tools/download.py @@ -6,6 +6,7 @@ import os import argparse import urllib3 +import configparser # Suppress the warning in dev urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) @@ -145,7 +146,38 @@ def download_scripts(mode, overwrite=None,): parser.add_argument('--overwrite', action='store_true') # Overwrites existing files parser.add_argument('--do_not_verify_ssl', action='store_false') # Skips SSL verification args = parser.parse_args() - + # Get configs from files + CONFIG_FILE_LOCATIONS = ['jamfapi.cfg',os.path.expanduser('~/jamfapi.cfg')] + CONFIG_FILE = '' + # Parse Config File + CONFPARSER = configparser.ConfigParser() + for config_path in CONFIG_FILE_LOCATIONS: + if os.path.exists(config_path): + print("Found Config: {0}".format(config_path)) + CONFIG_FILE = config_path + + if CONFIG_FILE == "": + config_ = configparser.ConfigParser() + config_['jss'] = {} + config_['jss']['username'] = "username" + config_['jss']['password'] = "password" + config_['jss']['server'] = "server" + print(config_) + with open('jamfapi.cfg', 'w') as configfile: + config_.write(configfile) + print("Config File Created. Please edit jamfapi.cfg and run again.") + + print("No Config File found!") + exit(0) + else: + # Read local directory, user home, then /etc/ for besapi.conf + CONFPARSER.read(CONFIG_FILE) + # If file exists + # Get config + args.username = CONFPARSER.get('jss', 'username') + args.password = CONFPARSER.get('jss', 'password') + args.url = CONFPARSER.get('jss', 'server') + # Ask for password if not supplied via command line args if args.password: password = args.password From af81b87d9339be12600dce7b55057ffadb1538b1 Mon Sep 17 00:00:00 2001 From: Rusty Myers Date: Wed, 18 Oct 2023 15:56:26 -0400 Subject: [PATCH 03/28] Adding token auth, configparser, and export_path --- tools/download.py | 71 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/tools/download.py b/tools/download.py index c9961dd..dc5a071 100755 --- a/tools/download.py +++ b/tools/download.py @@ -11,7 +11,24 @@ # Suppress the warning in dev urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) -mypath = os.path.dirname(os.path.realpath(__file__)) +# https://github.com/lazymutt/Jamf-Pro-API-Sampler/blob/5f8efa92911271248f527e70bd682db79bc600f2/jamf_duplicate_detection.py#L99 +def get_uapi_token(): + ''' + fetches api token + ''' + jamf_test_url = url + "/api/v1/auth/token" + response = requests.post(url=jamf_test_url, auth=(username, password)) + response_json = response.json() + return response_json['token'] + + +def invalidate_uapi_token(uapi_token): + ''' + invalidates api token + ''' + jamf_test_url = url + "/api/v1/auth/invalidate-token" + headers = {'Accept': '*/*', 'Authorization': 'Bearer ' + uapi_token} + _ = requests.post(url=jamf_test_url, headers=headers) def download_scripts(mode, overwrite=None,): """ Downloads Scripts to ./scripts and Extension Attributes to ./extension_attributes @@ -47,12 +64,13 @@ def download_scripts(mode, overwrite=None,): download_path = 'scripts' script_xml = 'script_contents' - + token = get_uapi_token() # Get all IDs of resource type - r = requests.get(args.url + '/JSSResource/%s' %resource, - auth = (args.username, password), - headers= {'Accept': 'application/xml','Content-Type': 'application/xml'}, - verify=args.do_not_verify_ssl) + r = requests.get(url + '/JSSResource/%s' %resource, + headers= {'Accept': 'application/xml', + 'Content-Type': 'application/xml', + 'Authorization': 'Bearer ' + token}, + verify=args.do_not_verify_ssl) # Basic error handling if r.status_code != 200: @@ -67,9 +85,11 @@ def download_scripts(mode, overwrite=None,): for resource_id in resource_ids: get_script = True - r = requests.get(args.url + '/JSSResource/%s/id/%s' % (resource,resource_id), - auth = (args.username, password), - headers= {'Accept': 'application/xml','Content-Type': 'application/xml'}, verify=args.do_not_verify_ssl) + r = requests.get(url + '/JSSResource/%s/id/%s' % (resource,resource_id), + headers= {'Accept': 'application/xml', + 'Content-Type': 'application/xml', + 'Authorization': 'Bearer ' + token}, + verify=args.do_not_verify_ssl) tree = ET.fromstring(r.content) if mode == 'ea': @@ -79,7 +99,7 @@ def download_scripts(mode, overwrite=None,): # continue # Determine resource path (folder name) - resource_path = os.path.join(mypath, '..', download_path ,tree.find('name').text) + resource_path = os.path.join(export_path, download_path ,tree.find('name').text) # Check to see if it exists if os.path.exists(resource_path): @@ -135,14 +155,14 @@ def download_scripts(mode, overwrite=None,): xmlstr = minidom.parseString(ET.tostring(tree, encoding='unicode', method='xml')).toprettyxml(indent=" ") with open(os.path.join(resource_path, '%s.xml' % mode), 'w') as f: f.write(xmlstr) - - + invalidate_uapi_token(token) if __name__ == '__main__': parser = argparse.ArgumentParser(description='Download Scripts from Jamf') parser.add_argument('--url') parser.add_argument('--username') parser.add_argument('--password') + parser.add_argument('--export_path') parser.add_argument('--overwrite', action='store_true') # Overwrites existing files parser.add_argument('--do_not_verify_ssl', action='store_false') # Skips SSL verification args = parser.parse_args() @@ -162,7 +182,8 @@ def download_scripts(mode, overwrite=None,): config_['jss']['username'] = "username" config_['jss']['password'] = "password" config_['jss']['server'] = "server" - print(config_) + config_['jss']['export_path'] = "export_path" + with open('jamfapi.cfg', 'w') as configfile: config_.write(configfile) print("Config File Created. Please edit jamfapi.cfg and run again.") @@ -174,16 +195,30 @@ def download_scripts(mode, overwrite=None,): CONFPARSER.read(CONFIG_FILE) # If file exists # Get config - args.username = CONFPARSER.get('jss', 'username') - args.password = CONFPARSER.get('jss', 'password') - args.url = CONFPARSER.get('jss', 'server') - + username = CONFPARSER.get('jss', 'username') + password = CONFPARSER.get('jss', 'password') + url = CONFPARSER.get('jss', 'server') + try: + export_path = CONFPARSER.get('jss', 'export_path') + except: + # Export to current directory by default + export_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + # Ask for password if not supplied via command line args if args.password: password = args.password - else: + elif password is None: password = getpass.getpass() + + if args.export_path: + export_path = args.export_path + + if args.url: + url = args.url + if args.username: + username = args.username + # Run script download for extension attributes download_scripts(overwrite=args.overwrite, mode='ea') # Run script download for scripts From 8029a4c07d7289e9958f8e2061c0876aa5a8d966 Mon Sep 17 00:00:00 2001 From: Rusty Myers Date: Wed, 18 Oct 2023 16:07:26 -0400 Subject: [PATCH 04/28] Adding token auth, configparser, and sync_path --- extension_attributes/Last User/ea.sh | 2 +- extension_attributes/Last User/ea.xml | 2 +- scripts/Install Software Updates/script.sh | 2 +- sync.py | 135 +++++++++++++-------- 4 files changed, 87 insertions(+), 54 deletions(-) diff --git a/extension_attributes/Last User/ea.sh b/extension_attributes/Last User/ea.sh index a9bd9df..059b4d3 100644 --- a/extension_attributes/Last User/ea.sh +++ b/extension_attributes/Last User/ea.sh @@ -4,4 +4,4 @@ lastUser=`defaults read /Library/Preferences/com.apple.loginwindow lastUserName` if [ $lastUser == "" ]; then echo "No logins" else - echo "$lastUser" + echo "$lastUser" \ No newline at end of file diff --git a/extension_attributes/Last User/ea.xml b/extension_attributes/Last User/ea.xml index 0a11e78..8195681 100644 --- a/extension_attributes/Last User/ea.xml +++ b/extension_attributes/Last User/ea.xml @@ -1,6 +1,7 @@ Last User + true This attribute displays the last user to log in. This attribute applies to both Mac and Windows. String @@ -9,5 +10,4 @@ diff --git a/tools/ci_tests/validate_files_and_folders.sh b/tools/ci_tests/validate_files_and_folders.sh old mode 100644 new mode 100755 index 7433be8..81d113c --- a/tools/ci_tests/validate_files_and_folders.sh +++ b/tools/ci_tests/validate_files_and_folders.sh @@ -5,20 +5,20 @@ #Load up some variables #Define scripts and templates folders -scripts=$(ls -p scripts | grep -v '/$' | sed -e 's/\..*$//') -scripts_templates=$(ls -p scripts/templates/| sed -e 's/\..*$//') +scripts=$(ls -1 scripts | grep -v "templates") +scripts_templates=$(ls -1 scripts/templates/) #Define EA and templates -extensionattributes=$(ls -p extension_attributes | grep -v '/$' | sed -e 's/\..*$//') -extensionattributes_templates=$(ls -p extension_attributes/templates/| sed -e 's/\..*$//') +extensionattributes=$(ls -1 extension_attributes | grep -v "templates") +extensionattributes_templates=$(ls -1 extension_attributes/templates/) #Validate both the Script and the Template for the Script exist. -echo "Making sure files exist in both places in scripts and scripts/Templates" +echo "Making sure files with same names exist in both places in scripts and scripts/Templates" scriptcompare=$(sdiff -bBWsw 75 <(echo "$scripts") <(echo "$scripts_templates" )) if [ "$scriptcompare" == "" ]; then - echo "Script and Script Template Exist All good in the hood!" + echo "Script and Script Template Exist in both folders!" else echo "Errors! occurred please correct the below" echo " Scripts | Templates" @@ -31,10 +31,10 @@ fi #Valate both the EA and the Template for the EA exist. -echo "Making sure files exist in both places extension_attributes and extension_attributes/Templates" +echo "Making sure files with same names exist in both places extension_attributes and extension_attributes/Templates" eacompare=$(sdiff -bBWsw 75 <(echo "$extensionattributes") <(echo "$extensionattributes_templates")) if [ "$eacompare" == "" ]; then - echo "EA and EA Template Exist All good in the hood!" + echo "EA and EA Template Exist in both folders!" else echo "Errors! occurred please correct the below" echo " Extension Attributes | Templates" diff --git a/tools/ci_tests/validatexml.sh b/tools/ci_tests/validatexml.sh old mode 100644 new mode 100755 index b20eaeb..c17f525 --- a/tools/ci_tests/validatexml.sh +++ b/tools/ci_tests/validatexml.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/zsh ################################################################################### ## Validates XML for proper formatting ################################################################################### @@ -9,10 +9,10 @@ function scripts() { printf "\033[31m Working on Scripts\n" printf "\033[31m---------------------------------------------------------------------------------\n" printf "\033[0m" -scriptfolders=$(ls -ltr ./scripts | cut -c52- | awk 'NR>1') +scriptfolders=$(ls -1 ./scripts | awk 'NR>1') while read folder ; do echo "$folder" - xmllint --noout ./scripts/"$folder"/*.xml + xmllint --noout ./scripts/"$folder"/*.xml done <<< "$scriptfolders" } @@ -20,7 +20,7 @@ scriptfolders=$(ls -ltr ./scripts | cut -c52- | awk 'NR>1') function ea(){ - eafolders=$(ls -ltr ./extension_attributes | cut -c52- | awk 'NR>1') + eafolders=$(ls -1 ./extension_attributes | awk 'NR>1') printf "\033[31m---------------------------------------------------------------------------------\n" printf "\033[31m Working on Extension Attributes\n" @@ -30,7 +30,7 @@ function ea(){ echo "$folder" - xmllint --noout ./extension_attributes/"$folder"/*.xml + xmllint --noout ./extension_attributes/"$folder"/*.xml done <<< "$eafolders" } diff --git a/tools/ci_tests/verifyEA.py b/tools/ci_tests/verifyEA.py old mode 100644 new mode 100755 index 8e40a16..3995a19 --- a/tools/ci_tests/verifyEA.py +++ b/tools/ci_tests/verifyEA.py @@ -1,60 +1,125 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import requests -from xml.etree import ElementTree as ET +from defusedxml import ElementTree as eTree import os import getpass import json +import configparser # Use this script to validate that EA values aren't changing as a result of syncing # Overwrite computers.json overwrite = False +smart_group = "1018" # Constants -url = 'https://your.jss.com' -username = getpass.getuser() -password = getpass.getpass() +# Get configs from files +CONFIG_FILE_LOCATIONS = ["jamfapi.cfg", os.path.expanduser("~/jamfapi.cfg")] +CONFIG_FILE = "" +# Parse Config File +CONFPARSER = configparser.ConfigParser() +for config_path in CONFIG_FILE_LOCATIONS: + if os.path.exists(config_path): + print("Found Config: {0}".format(config_path)) + CONFIG_FILE = config_path + +if CONFIG_FILE != "": + # Get config + CONFPARSER.read(CONFIG_FILE) + try: + username = CONFPARSER.get("jss", "username") + except configparser.NoOptionError: + print("Can't find username in configfile") + try: + password = CONFPARSER.get("jss", "password") + except configparser.NoOptionError: + print("Can't find password in configfile") + try: + url = CONFPARSER.get("jss", "server") + except configparser.NoOptionError: + print("Can't find url in configfile") + try: + smart_group = CONFPARSER.get("verifyEA", "smart_group") + except configparser.NoOptionError: + print("Can't find smart_group in configfile") + +else: + url = "https://your.jss.com" + username = getpass.getuser() + password = getpass.getpass() + smart_group = input("Enter smart_group") + + +def get_uapi_token(): + """ + fetches api token + """ + jamf_test_url = url + "/api/v1/auth/token" + response = requests.post(url=jamf_test_url, auth=(username, password), timeout=5) + response_json = response.json() + return response_json["token"] + + +def invalidate_uapi_token(uapi_token): + """ + invalidates api token + """ + jamf_test_url = url + "/api/v1/auth/invalidate-token" + headers = {"Accept": "*/*", "Authorization": "Bearer " + uapi_token} + _ = requests.post(url=jamf_test_url, headers=headers, timeout=5) def overwrite_file(): - print('Overwriting File: computers.json...') - with open('computers.json', 'w') as f: + print("Overwriting File: computers.json...") + with open("computers.json", "w") as f: f.write(json.dumps(computers)) + def read_file(): - print('Reading cached data from disk...') - with open('computers.json', 'r') as f: + print("Reading cached data from disk...") + with open("computers.json", "r") as f: computers_from_disk = json.load(f) return computers_from_disk -def build_computers_data_object(): - # Get IDs for computers - print('Communicating with the Jamf Pro Server...') + +def build_computers_data_object(token, group_id): + """Builds computer data into local file + params: token, group_id + returns: computers objects json + """ + print("Communicating with the Jamf Pro Server...") computers = {} - r = requests.get(url + '/JSSResource/computergroups/id/810', - auth = (username, password), - headers= {'Content-Type': 'application/xml'}) + r = requests.get( + url + "/JSSResource/computergroups/id/{0}".format(group_id), + headers={"Content-Type": "application/xml", "Authorization": "Bearer " + token}, + ) - tree = ET.fromstring(r.content) - resource_ids = [ e.text for e in tree.findall('computers/computer/id') ] + tree = eTree.fromstring(r.content) + resource_ids = [e.text for e in tree.findall("computers/computer/id")] # Download each resource and save to disk for resource_id in resource_ids: - # Get detailed information about the record - r = requests.get(url + '/JSSResource/computers/id/%s' % (resource_id), - auth = (username, password), - headers={'Content-Type': 'application/json'}) - - # Parse xml - tree = ET.fromstring(r.content) - ea_values = [ e.text for e in tree.findall('extension_attributes/extension_attribute/value') ] - ea_names = [ e.text for e in tree.findall('extension_attributes/extension_attribute/name') ] - - # Build the json for the comparison + r = requests.get( + url + "/JSSResource/computers/id/{0}".format(resource_id), + headers={"Content-Type": "application/json", "Authorization": "Bearer " + token}, + ) + + # Parse xml + tree = eTree.fromstring(r.content) + ea_values = [ + e.text + for e in tree.findall("extension_attributes/extension_attribute/value") + ] + ea_names = [ + e.text + for e in tree.findall("extension_attributes/extension_attribute/name") + ] + + # Build the json for the comparison computers[resource_id] = {} - for k,v in zip(ea_names,ea_values): + for k, v in zip(ea_names, ea_values): computers[resource_id][k] = v return computers @@ -67,25 +132,34 @@ def compare_computer(computer_id): print("Processing Computer ID: %s" % computer_id) for key in computers[computer_id].keys(): if computers[computer_id][key] != computers_from_disk[computer_id][key]: - print("Value Change Found\n\tEA Name:\t{}\n\tOriginal Value:\t{}\n\tNew Value:\t{}".format(key,computers[computer_id][key],computers_from_disk[computer_id][key])) + print( + "Value Change Found\n\tEA Name:\t{}\n\tOriginal Value:\t{}\n\tNew Value:\t{}".format( + key, + computers[computer_id][key], + computers_from_disk[computer_id][key], + ) + ) + # Is this the first time it was run? mypath = os.path.dirname(os.path.realpath(__file__)) -if os.path.exists(os.path.join(mypath,'computers.json')): +if os.path.exists(os.path.join(mypath, "computers.json")): computers_from_disk = read_file() else: - print('No cached data found, writing new data to computers.json') + print("No cached data found, writing new data to computers.json") overwrite = True -# Get computers information from JSS -computers = build_computers_data_object() +token = get_uapi_token() + +# Get computers information from JSS smart group +computers = build_computers_data_object(token, smart_group) # Overwrite local file? -if overwrite == True: +if overwrite == True: overwrite_file() - + print("Computer data staged for comparison with future runs.") else: # Compare each computer - print('Analyzing the results...') + print("Analyzing the results...") for computer_id in list(computers.keys()): compare_computer(computer_id) diff --git a/tools/download.py b/tools/download.py index 904c082..3d90c18 100755 --- a/tools/download.py +++ b/tools/download.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import getpass import requests -from defusedxml import ElementTree as ET +from defusedxml import ElementTree as eTree from xml.dom import minidom import os import argparse @@ -79,7 +79,7 @@ def download_scripts( "Authorization": "Bearer " + token, }, verify=args.do_not_verify_ssl, - timeout=5 + timeout=5, ) # Basic error handling @@ -91,7 +91,7 @@ def download_scripts( % r.status_code ) exit(1) - tree = ET.fromstring(r.content) + tree = eTree.fromstring(r.content) resource_ids = [e.text for e in tree.findall(".//id")] # Download each resource and save to disk @@ -106,9 +106,9 @@ def download_scripts( "Authorization": "Bearer " + token, }, verify=args.do_not_verify_ssl, - timeout=5 + timeout=5, ) - tree = ET.fromstring(r.content) + tree = eTree.fromstring(r.content) if mode == "ea": if tree.find("input_type/type").text != "script": @@ -134,7 +134,7 @@ def download_scripts( # Create script string, and determine the file extension if get_script: - xmlstr = ET.tostring( + xmlstr = eTree.tostring( tree.find(script_xml), encoding="unicode", method="text" ).replace("\r", "") if xmlstr.startswith("#!/bin/sh"): @@ -172,7 +172,7 @@ def download_scripts( pass xmlstr = minidom.parseString( - ET.tostring(tree, encoding="unicode", method="xml") + eTree.tostring(tree, encoding="unicode", method="xml") ).toprettyxml(indent=" ") with open(os.path.join(resource_path, "%s.xml" % mode), "w") as f: f.write(xmlstr) @@ -204,26 +204,23 @@ def download_scripts( CONFIG_FILE = config_path if CONFIG_FILE != "": - try: - # Get config - CONFPARSER.read(CONFIG_FILE) - except: - print("Can't read config file") + # Get config + CONFPARSER.read(CONFIG_FILE) try: username = CONFPARSER.get("jss", "username") - except: + except configparser.NoOptionError: print("Can't find username in configfile") try: password = CONFPARSER.get("jss", "password") - except: + except configparser.NoOptionError: print("Can't find password in configfile") try: url = CONFPARSER.get("jss", "server") - except: + except configparser.NoOptionError: print("Can't find url in configfile") try: export_path = CONFPARSER.get("jss", "export_path") - except: + except configparser.NoOptionError: print("Can't find export_path in config") # Ask for password if not supplied via command line args From 2749dc548925c32f27d56332b99b20e623c8c89b Mon Sep 17 00:00:00 2001 From: Rusty Myers Date: Wed, 1 Nov 2023 12:07:56 -0400 Subject: [PATCH 26/28] Adding exception type to download, compressing configs for verify --- tools/ci_tests/verifyEA.py | 18 +++++++----------- tools/download.py | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/tools/ci_tests/verifyEA.py b/tools/ci_tests/verifyEA.py index 3995a19..1dcd01c 100755 --- a/tools/ci_tests/verifyEA.py +++ b/tools/ci_tests/verifyEA.py @@ -29,21 +29,15 @@ CONFPARSER.read(CONFIG_FILE) try: username = CONFPARSER.get("jss", "username") - except configparser.NoOptionError: - print("Can't find username in configfile") - try: password = CONFPARSER.get("jss", "password") - except configparser.NoOptionError: - print("Can't find password in configfile") - try: url = CONFPARSER.get("jss", "server") - except configparser.NoOptionError: - print("Can't find url in configfile") - try: smart_group = CONFPARSER.get("verifyEA", "smart_group") except configparser.NoOptionError: - print("Can't find smart_group in configfile") - + print("Can't find configs in configfile") + pass + except configparser.NoSectionError: + print("Can't find sections in configfile") + pass else: url = "https://your.jss.com" username = getpass.getuser() @@ -93,6 +87,7 @@ def build_computers_data_object(token, group_id): r = requests.get( url + "/JSSResource/computergroups/id/{0}".format(group_id), headers={"Content-Type": "application/xml", "Authorization": "Bearer " + token}, + timeout=5 ) tree = eTree.fromstring(r.content) @@ -104,6 +99,7 @@ def build_computers_data_object(token, group_id): r = requests.get( url + "/JSSResource/computers/id/{0}".format(resource_id), headers={"Content-Type": "application/json", "Authorization": "Bearer " + token}, + timeout=5 ) # Parse xml diff --git a/tools/download.py b/tools/download.py index 3d90c18..02ef580 100755 --- a/tools/download.py +++ b/tools/download.py @@ -168,7 +168,7 @@ def download_scripts( tree.remove(tree.find("id")) tree.remove(tree.find("script_contents_encoded")) tree.remove(tree.find("filename")) - except: + except TypeError: pass xmlstr = minidom.parseString( From 1306f489842a8edff21ba66bbdd1e39ef81b08be Mon Sep 17 00:00:00 2001 From: Rusty Myers Date: Wed, 1 Nov 2023 13:17:42 -0400 Subject: [PATCH 27/28] Update verifyEA.py Fixing extra pass and if statement comparing to True. Adding file_path variable to use with functions --- tools/ci_tests/verifyEA.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/ci_tests/verifyEA.py b/tools/ci_tests/verifyEA.py index 1dcd01c..76980ca 100755 --- a/tools/ci_tests/verifyEA.py +++ b/tools/ci_tests/verifyEA.py @@ -34,7 +34,6 @@ smart_group = CONFPARSER.get("verifyEA", "smart_group") except configparser.NoOptionError: print("Can't find configs in configfile") - pass except configparser.NoSectionError: print("Can't find sections in configfile") pass @@ -64,15 +63,15 @@ def invalidate_uapi_token(uapi_token): _ = requests.post(url=jamf_test_url, headers=headers, timeout=5) -def overwrite_file(): +def overwrite_file(file_path): print("Overwriting File: computers.json...") - with open("computers.json", "w") as f: + with open(file_path, "w") as f: f.write(json.dumps(computers)) -def read_file(): +def read_file(file_path): print("Reading cached data from disk...") - with open("computers.json", "r") as f: + with open(file_path, "r") as f: computers_from_disk = json.load(f) return computers_from_disk @@ -139,8 +138,9 @@ def compare_computer(computer_id): # Is this the first time it was run? mypath = os.path.dirname(os.path.realpath(__file__)) -if os.path.exists(os.path.join(mypath, "computers.json")): - computers_from_disk = read_file() +myfile = os.path.join(mypath, "computers.json") +if os.path.exists(myfile): + computers_from_disk = read_file(myfile) else: print("No cached data found, writing new data to computers.json") overwrite = True @@ -151,8 +151,8 @@ def compare_computer(computer_id): computers = build_computers_data_object(token, smart_group) # Overwrite local file? -if overwrite == True: - overwrite_file() +if overwrite: + overwrite_file(myfile) print("Computer data staged for comparison with future runs.") else: # Compare each computer From 06d19b9f166adbd5b3467716c2eef1296b1d10e5 Mon Sep 17 00:00:00 2001 From: Rusty Myers Date: Wed, 1 Nov 2023 13:24:21 -0400 Subject: [PATCH 28/28] Update validate xml to work on folders except exclude. Removing pass from except --- tools/ci_tests/validatexml.sh | 4 ++-- tools/ci_tests/verifyEA.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/ci_tests/validatexml.sh b/tools/ci_tests/validatexml.sh index c17f525..78f203b 100755 --- a/tools/ci_tests/validatexml.sh +++ b/tools/ci_tests/validatexml.sh @@ -9,7 +9,7 @@ function scripts() { printf "\033[31m Working on Scripts\n" printf "\033[31m---------------------------------------------------------------------------------\n" printf "\033[0m" -scriptfolders=$(ls -1 ./scripts | awk 'NR>1') +scriptfolders=$(ls -1 ./scripts | grep -v templates) while read folder ; do echo "$folder" xmllint --noout ./scripts/"$folder"/*.xml @@ -20,7 +20,7 @@ scriptfolders=$(ls -1 ./scripts | awk 'NR>1') function ea(){ - eafolders=$(ls -1 ./extension_attributes | awk 'NR>1') + eafolders=$(ls -1 ./extension_attributes | grep -v templates) printf "\033[31m---------------------------------------------------------------------------------\n" printf "\033[31m Working on Extension Attributes\n" diff --git a/tools/ci_tests/verifyEA.py b/tools/ci_tests/verifyEA.py index 76980ca..43825f9 100755 --- a/tools/ci_tests/verifyEA.py +++ b/tools/ci_tests/verifyEA.py @@ -36,7 +36,6 @@ print("Can't find configs in configfile") except configparser.NoSectionError: print("Can't find sections in configfile") - pass else: url = "https://your.jss.com" username = getpass.getuser()