Compare commits

...

11 Commits

6 changed files with 127 additions and 16 deletions

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
cryptography
requests
toml

View File

@ -2,6 +2,7 @@
import os
import argparse
import logging
import time
from functions import getSettings
from includes.airwatchAPI import *
from includes.GLPIAPI import *
@ -66,13 +67,21 @@ if(args.staginguser != None):
stagingUser = args.staginguser
# ====================================== #
# Vérification de la présence du verrou avant de continuer
if(os.path.isfile(lockFile) and not args.force):
logger.debug('Lock file exists, exiting...')
exit(0)
# Récupération du temps de création de verrou en minutes
lockTime = (time.time() - os.path.getmtime(lockFile)) // 60
# Recréation du verrou s'il existe depuis plus de 3 heures (crash)
# sinon on quitte, une synchro est déjà en cours
if(lockTime > 180):
os.remove(lockFile)
open(lockFile, "w").close()
else:
logger.debug('Lock file exists, exiting...')
exit(0)
else:
# Création du verrou s'il n'existe pas
open(lockFile, "w").close()
# Initialisation de l'api Airwatch

View File

@ -5,6 +5,7 @@ def getSettings(settingsPath):
settingsDefault ="""
[AIRWATCH]
Server = "https://airwatchServer"
ConsoleURI = "https://airwatchConsole"
APIKey = "APIKEY"
# Méthode d'authentification (CMSURL or PASSWORD)

View File

@ -55,11 +55,33 @@ class GLPIAPI:
return deviceID, data, search["totalcount"]
elif(search["totalcount"] > 1):
deviceID = list(search["data"].keys())
return deviceID, search["data"], search["totalcount"]
else:
return None, None, 0
return None, None, None
def GetUser(self, username=None, email=None):
if(username != None):
search_parameter = f'is_deleted=0&criteria[0][field]=1&withindexes=true&criteria[0][searchtype]=contains&criteria[0][value]=^{username}$'
elif(email != None):
search_parameter = f'is_deleted=0&criteria[0][field]=5&withindexes=true&criteria[0][searchtype]=contains&criteria[0][value]=^{email}$'
searchUri = f"{self.Server}/apirest.php/search/user?{search_parameter}"
search = requests.get(searchUri, headers=self.Headers)
if(search.status_code == 200):
search = search.json()
if(search["totalcount"] == 1):
userID = list(search["data"].keys())[0]
data = search["data"][userID]
return userID, data, search["totalcount"]
elif(search["totalcount"] > 1):
userID = list(search["data"].keys())
return userID, search["data"], search["totalcount"]
else:
return None, None, 0
def UpdateInventory(self, inventory):
headers = {
"Content-Type":"Application/x-compress",
@ -77,12 +99,34 @@ class GLPIAPI:
}
uri = f"{self.Server}/apirest.php/Computer/"
return requests.put(uri, headers=self.Headers, json=body)
def UpdateUser(self, deviceid, username):
body = {
"input" : {
"id" : deviceid,
"users_id" : username
}
}
uri = f"{self.Server}/apirest.php/Computer/"
return requests.put(uri, headers=self.Headers, json=body)
def UpdateAirwatchLink(self, deviceid, airwatchlink):
body = {
"input": {
"id": deviceid,
"appareilsurmagentafield": airwatchlink
}
}
uri = f"{self.Server}/apirest.php/Computer/"
return requests.put(uri, headers=self.Headers, json=body)
def CreateInventoryForAirwatchDevice(self, device, deviceName, apps=None):
platforms = {
2:"Apple iOS",
5:"Android",
12:"Windows Desktop"
12:"Windows"
}
if(device.PlatformId in platforms.keys()):
@ -107,10 +151,28 @@ class GLPIAPI:
osArch = "Unknown"
softwareArch = "Unknown"
windowsOSTranslation = {
"10.0.19043":"10 21H1",
"10.0.19044":"10 21H2",
"10.0.19045":"10 22H2",
"10.0.22000":"11 21H2",
"10.0.22621":"11 22H2",
"10.0.22631":"11 23H2",
"10.0.26100":"11 24H2",
"10.0.26200":"11 25H2"
}
logDate = datetime.strptime(device.LastSeen, "%Y-%m-%dT%H:%M:%S.%f").strftime("%Y-%m-%d %H:%M:%S")
inventory = GLPIInventory(logdate=logDate, versionclient=self.UserAgent, tag=device.Group, deviceid=f"{deviceName} - {device.SerialNumber}", itemtype="Computer")
inventory.SetOperatingSystem(platformName, device.OS, osArch)
if(platformName == "Windows"):
if(device.OS in windowsOSTranslation.keys()):
inventory.SetOperatingSystem(platformName, windowsOSTranslation[str(device.OS)], osArch)
else:
platformName = "Windows Desktop"
inventory.SetOperatingSystem(platformName, device.OS, osArch)
else:
inventory.SetOperatingSystem(platformName, device.OS, osArch)
inventory.SetHardware(deviceName, device.Uuid, device.TotalMemory)
inventory.AddUser(device.User)

View File

@ -168,7 +168,10 @@ class AirwatchUser:
self.Group = user["Group"]
self.GroupId = user["LocationGroupId"]
self.OrgUuid = user["OrganizationGroupUuid"]
self.DeviceCount = int(user["EnrolledDevicesCount"])
if(user["EnrolledDevicesCount"] != ''):
self.DeviceCount = int(user["EnrolledDevicesCount"])
else:
self.DeviceCount = 0
class AirwatchDevice:
@ -182,8 +185,12 @@ class AirwatchDevice:
self.GroupId = device["LocationGroupId"]["Id"]["Value"]
self.Group = device["LocationGroupName"]
self.GroupUuid = device["LocationGroupId"]["Uuid"]
self.UserId = device["UserId"]["Id"]["Value"]
self.User = device["UserName"]
if(device["UserId"].get("Id") != None):
self.UserId = device["UserId"]["Id"]["Value"]
self.User = device["UserName"]
else:
self.UserId = None
self.User = None
self.UserEmail = device["UserEmailAddress"]
self.PlatformId = device["PlatformId"]["Id"]["Value"]
self.Platform = device["Platform"]

View File

@ -2,6 +2,7 @@
import os
import argparse
import logging
import time
from datetime import datetime
from functions import getSettings
from includes.airwatchAPI import *
@ -22,7 +23,7 @@ args = parser.parse_args()
if(args.configpath != None and args.configpath != ''):
settings = getSettings(args.configpath)
else:
settings = getSettings("{os.path.realpath(os.path.dirname(__file__))}/conf/settings.conf")
settings = getSettings(f"{os.path.realpath(os.path.dirname(__file__))}/conf/settings.conf")
#=========== Configuration des logs ===========#
@ -105,11 +106,21 @@ platformFilterOut = [12]
# ====================================== #
# Vérification de la présence du verrou avant de continuer
if(os.path.isfile(lockFile) and not args.force):
logger.debug('Lock file exists, exiting...')
exit(0)
# Récupération du temps de création de verrou en minutes
lockTime = (time.time() - os.path.getmtime(lockFile)) // 60
# Recréation du verrou s'il existe depuis plus de 3 heures (crash)
# sinon on quitte, une synchro est déjà en cours
if(lockTime > 180):
os.remove(lockFile)
open(lockFile, "w").close()
else:
logger.debug('Lock file exists, exiting...')
exit(0)
else:
# Création du verrou s'il n'existe pas
open(lockFile, "w").close()
logger.info("========= Synchronization started =========")
@ -204,17 +215,29 @@ for device in devices:
loggerDouble.error(f"{count} devices matching airwatch device {device.FriendlyName} (Airwatch id={device.Id}) in GLPI (GLPI ids = {', '.join(deviceID)}), skipping this device...")
continue
if(count == 0):
loggerMissing.error(f"Device {device.FriendlyName} (id={device.Id}) not found in GLPI, is it in the trash bin ? Skipping device...")
deviceIDTrash, dataTrash, countTrash = glpiapi.GetDevice(device)
if(countTrash > 1):
loggerDouble.error(f"{countTrash} devices matching airwatch device {device.FriendlyName} (Airwatch id={device.Id}) in GLPI trashbin (GLPI ids = {', '.join(deviceIDTrash)}), skipping this device...")
elif(countTrash == 1):
logger.warning(f"Device {device.FriendlyName} (Airwatch id={device.Id}) in GLPI trashbin (GLPI id={deviceIDTrash}), skipping...")
else:
loggerMissing.error(f"Device {device.FriendlyName} (Airwatch id={device.Id}) not found in GLPI.")
continue
inventory = glpiapi.CreateInventoryForAirwatchDevice(device, data["1"], apps)
# Mise à jour du friendly name sur Airwatch
platformName = inventory.operatingsystem["name"]
if(device.FriendlyName != f"{data['1']} {platformName} {device.OS} - {device.User}"):
newFriendlyName = f"{data['1']} {platformName} {device.OS} - {device.User}"
osVersion = inventory.operatingsystem["version"]
if(device.FriendlyName != f"{data['1']} {platformName} {osVersion} - {device.User}"):
newFriendlyName = f"{data['1']} {platformName} {osVersion} - {device.User}"
logger.info(f"Updating device friendlyname to {newFriendlyName}")
airwatch.SetDeviceFriendlyName(device, newFriendlyName)
# Mise à jour de l'url vers la page airwatch de l'appareil sur GLPI
airwatchlink = f"{settings['AIRWATCH']['ConsoleURI']}/AirWatch/#/AirWatch/Device/Details/Summary/{device.Id}"
if(data['76689'] != airwatchlink):
glpiapi.UpdateAirwatchLink(deviceID, airwatchlink)
# filtre des plateformes
if(platformFilterEnabled):
if device.PlatformId in platformFilterOut:
@ -224,6 +247,12 @@ for device in devices:
logger.info(f"Updating {deviceID} on GLPI")
glpiapi.UpdateInventory(inventory.Json())
if(data['70'] == None and device.User != settings["AIRWATCH"]["StagingUser"]):
userID, userData, userCount = glpiapi.GetUser(device.User)
if(userCount == 1):
logger.info(f"Updating user from {data['70']} to {device.User} in GLPI (id={deviceID})")
glpiapi.UpdateUser(deviceID, userID)
if(data['5'] != device.SerialNumber):
logger.info(f"Updating serial number from {data['5']} to {device.SerialNumber} in GLPI (id={deviceID})")
glpiapi.UpdateSerialNumber(deviceID, device.SerialNumber)