From c644cb8974d3cf9882dbb2e839861ee47664b992 Mon Sep 17 00:00:00 2001 From: Leif Ahlgrimm <58110221+leifahlgrimm@users.noreply.github.com> Date: Tue, 5 May 2020 23:21:14 +0200 Subject: [PATCH 1/6] Fix asset tag only updating when number Removed the isdigit() check for the Snipe asset tag as this creates issues when a non-digit prefix is used. --- jamf2snipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jamf2snipe b/jamf2snipe index 03c9912..383bd77 100755 --- a/jamf2snipe +++ b/jamf2snipe @@ -747,7 +747,7 @@ for jamf_type in jamf_types: # The user arg below is set to false if it's called, so this would fail if the user called it. if (jamf['general']['asset_tag'] != snipe['rows'][0]['asset_tag']) and user_args.do_not_update_jamf : logging.info("JAMF doesn't have the same asset tag as SNIPE so we'll update it because it should be authoritative.") - if snipe['rows'][0]['asset_tag'][0].isdigit(): + if snipe['rows'][0]['asset_tag'][0]: if jamf_type == 'computers': update_jamf_asset_tag("{}".format(jamf['general']['id']), '{}'.format(snipe['rows'][0]['asset_tag'])) logging.info("Device is a computer, updating computer record") From c4a07e239d60c76a7cbf1123fdc5eb34c468b2ce Mon Sep 17 00:00:00 2001 From: Dalton Durst Date: Mon, 13 Jul 2020 17:39:09 -0500 Subject: [PATCH 2/6] Print exceptions during is-up detection Exceptions aren't very likely during this initialization step, but if they occur the user definitely wants to know about them. --- jamf2snipe | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jamf2snipe b/jamf2snipe index 383bd77..66a96a0 100755 --- a/jamf2snipe +++ b/jamf2snipe @@ -511,11 +511,13 @@ logging.info("SSL Verification is set to: {}".format(user_args.do_not_verify_ssl logging.info("Running tests to see if hosts are up.") try: SNIPE_UP = True if requests.get(snipe_base, verify=user_args.do_not_verify_ssl, hooks={'response': request_handler}).status_code is 200 else False -except: +except Exception as e: + logging.exception(e) SNIPE_UP = False try: JAMF_UP = True if requests.get(jamfpro_base, verify=user_args.do_not_verify_ssl, hooks={'response': request_handler}).status_code in (200, 401) else False -except: +except Exception as e: + logging.exception(e) JAMF_UP = False if SNIPE_UP is False: From cc774dd55dc49eaa8b3bbb3422746d1b9f023153 Mon Sep 17 00:00:00 2001 From: goneafk Date: Thu, 29 Oct 2020 16:13:40 -0700 Subject: [PATCH 3/6] Fixed two condition checks for updating attributes I fixed two condition checks to make sure the data from Jamf and the data from Snipe are aligned. These are successfully set attributes, but showing as failing because the data doesn't line up at time of comparison. Snipe adds " 00:00:00" to the date, and json reports None for a blank value while the Jamf data contains an empty string. By doing these two conditional checks, I stop getting 3 warnings for ever machine updating that has these attributes updating in the case of purchase date, or not changing as is the case with my empty custom attributes. --- jamf2snipe | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jamf2snipe b/jamf2snipe index 383bd77..c948513 100755 --- a/jamf2snipe +++ b/jamf2snipe @@ -444,6 +444,10 @@ def update_snipe_asset(snipe_id, payload): logging.debug("Got back status code: 200 - Checking the payload updated properly: If you error here it's because you configure the API mapping right.") jsonresponse = response.json() for key in payload: + if key == 'purchase_date': + payload[key] = payload[key] + " 00:00:00" + if payload[key] is '': + payload[key] = None if jsonresponse['payload'][key] != payload[key]: logging.warning('Unable to update ID: {}. We failed to update the {} field with "{}"'.format(snipe_id, key, payload[key])) goodupdate = False From a590368959f884a26371d94d04720142855cb16e Mon Sep 17 00:00:00 2001 From: Laura Seidler <42136707+lauraseidler@users.noreply.github.com> Date: Sun, 11 Apr 2021 02:00:56 +0200 Subject: [PATCH 4/6] Interpolate environment variables in config (#59) This is helpful to run the same script in multiple environments, where adapting the `settings.conf` file might not be possible or desirable. --- README.md | 10 ++++++++++ jamf2snipe | 8 +++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5175b3d..781c785 100755 --- a/README.md +++ b/README.md @@ -117,6 +117,16 @@ Some example API mappings can be found below: More information can be found in the ./jamf2snipe file about associations and [valid subsets](https://github.com/ParadoxGuitarist/jamf2snipe/blob/master/jamf2snipe#L33). +### Environment variables + +Config values can be set through environment variables, e.g.: +``` +[jamf] +url = $JAMF_URL +username = $JAMF_USERNAME +password = $JAMF_PASSWORD +``` + ## Testing It is *always* a good idea to create a test environment to ensure everything works as expected before running anything in production. diff --git a/jamf2snipe b/jamf2snipe index 6bca223..a9275e0 100755 --- a/jamf2snipe +++ b/jamf2snipe @@ -52,6 +52,12 @@ import time import configparser import argparse import logging +import os + +class EnvironmentInterpolation(configparser.BasicInterpolation): + def before_get(self, parser, section, option, value, defaults): + value = super().before_get(parser, section, option, value, defaults) + return os.path.expandvars(value) # Set us up for using runtime arguments by defining them. runtimeargs = argparse.ArgumentParser() @@ -86,7 +92,7 @@ if user_args.dryrun: # Find a valid settings.conf file. logging.info("Searching for a valid settings.conf file.") -config = configparser.ConfigParser() +config = configparser.ConfigParser(interpolation=EnvironmentInterpolation()) logging.debug("Checking for a settings.conf in /opt/jamf2snipe ...") config.read("/opt/jamf2snipe/settings.conf") if 'snipe-it' not in set(config): From 5773c063df6556362e4f3295d88eb7dcd632c3d2 Mon Sep 17 00:00:00 2001 From: Eli Young Date: Thu, 16 Dec 2021 15:40:11 -0800 Subject: [PATCH 5/6] Avoid tracking settings.conf (#63) This moves the sample settings.conf file to settings.conf.example to help users and developers avoid accidentally committing and publishing their credentials. --- .gitignore | 2 +- README.md | 4 ++-- settings.conf => settings.conf.example | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) rename settings.conf => settings.conf.example (62%) diff --git a/.gitignore b/.gitignore index a9d73c8..304a0c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -settings.conf \ No newline at end of file +settings.conf diff --git a/README.md b/README.md index 781c785..2c27582 100755 --- a/README.md +++ b/README.md @@ -68,13 +68,13 @@ Lastly, if the asset_tag field is blank in JAMF when it is being created in Snip 4. Install dependencies - `pip install -r /path/to/jamf2snipe/requirements.txt` -5. Configure settings.conf +5. Copy settings.conf.example to settings.conf and configure 6. Run `python jamf2snipe` & profit ### Linux 1. Copy the files to your system (recommend installing to /opt/jamf2snipe/* ). Make sure you meet all the system requirements. -2. Edit the settings.conf to match your current environment. The script will look for a valid settings.conf in /opt/jamf2snipe/settings.conf, /etc/jamf2snipe/settings.conf, or in the current folder (in that order): so either copy the file to one of those locations, or be sure that the user running the program is in the same folder as the settings.conf. +2. Copy settings.conf.example to settings.conf. Edit settings.conf to match your current environment. The script will look for a valid settings.conf in /opt/jamf2snipe/settings.conf, /etc/jamf2snipe/settings.conf, or in the current folder (in that order): so either copy the file to one of those locations, or be sure that the user running the program is in the same folder as the settings.conf. ## Configuration - settings.conf: diff --git a/settings.conf b/settings.conf.example similarity index 62% rename from settings.conf rename to settings.conf.example index 5a0ce68..1aa67be 100644 --- a/settings.conf +++ b/settings.conf.example @@ -4,17 +4,17 @@ username = a-valid-username password = a-valid-password [snipe-it] -#Required +# Required url = http://FQDN.your.snipe.instance.com apikey = YOUR-API-KEY-HERE manufacturer_id = 2 -defaultStatus = 2 +defaultStatus = 2 computer_model_category_id = 2 mobile_model_category_id = 3 -#Not Required, uncomment to use -#computer_custom_fieldset_id = 3 -#mobile_custom_fieldset_id = 4 -#asset_tag = general serial_number # If not specified, defaults to jamf-{id} or jamf-m-{id} +# Not Required, uncomment to use +# computer_custom_fieldset_id = 3 +# mobile_custom_fieldset_id = 4 +# asset_tag = general serial_number # If not specified, defaults to jamf-{id} or jamf-m-{id} [computers-api-mapping] name = general name @@ -22,8 +22,8 @@ _snipeit_mac_address_1 = general mac_address [mobile_devices-api-mapping] -_snipeit_imei_4 = network imei +_snipeit_imei_4 = network imei name = general name [user-mapping] # The field from jamf that you want to search Snipe with -jamf_api_field = location username \ No newline at end of file +jamf_api_field = location username From 7bb02ae4c93450723a566a9a0f7c7e984be932d1 Mon Sep 17 00:00:00 2001 From: Eli Young Date: Wed, 22 Dec 2021 17:13:48 -0800 Subject: [PATCH 6/6] Checkin assets with no assigned user Resolves: #68 --- jamf2snipe | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jamf2snipe b/jamf2snipe index a9275e0..a552445 100755 --- a/jamf2snipe +++ b/jamf2snipe @@ -482,6 +482,9 @@ def checkin_snipe_asset(asset_id): # Function that checks out an asset in snipe def checkout_snipe_asset(user, asset_id, checked_out_user=None): logging.debug('Asset {} is being checked out to {}'.format(user, asset_id)) + if user == '': + logging.info("Checking in {}".format(asset_id)) + return checkin_snipe_asset(asset_id) user_id = get_snipe_user_id(user) if user_id == 'NotFound': logging.info("User {} not found".format(user))