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 os
import argparse import argparse
import logging import logging
import time
from functions import getSettings from functions import getSettings
from includes.airwatchAPI import * from includes.airwatchAPI import *
from includes.GLPIAPI import * from includes.GLPIAPI import *
@ -67,12 +68,20 @@ if(args.staginguser != None):
# ====================================== # # ====================================== #
# Vérification de la présence du verrou avant de continuer # Vérification de la présence du verrou avant de continuer
if(os.path.isfile(lockFile) and not args.force): if(os.path.isfile(lockFile) and not args.force):
logger.debug('Lock file exists, exiting...') # Récupération du temps de création de verrou en minutes
exit(0) 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: else:
# Création du verrou s'il n'existe pas
open(lockFile, "w").close() open(lockFile, "w").close()
# Initialisation de l'api Airwatch # Initialisation de l'api Airwatch

View File

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

View File

@ -55,11 +55,33 @@ class GLPIAPI:
return deviceID, data, search["totalcount"] return deviceID, data, search["totalcount"]
elif(search["totalcount"] > 1): elif(search["totalcount"] > 1):
deviceID = list(search["data"].keys())
return deviceID, search["data"], search["totalcount"] return deviceID, search["data"], search["totalcount"]
else: else:
return None, None, 0 return None, None, 0
return None, None, None 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): def UpdateInventory(self, inventory):
headers = { headers = {
"Content-Type":"Application/x-compress", "Content-Type":"Application/x-compress",
@ -78,11 +100,33 @@ class GLPIAPI:
uri = f"{self.Server}/apirest.php/Computer/" uri = f"{self.Server}/apirest.php/Computer/"
return requests.put(uri, headers=self.Headers, json=body) 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): def CreateInventoryForAirwatchDevice(self, device, deviceName, apps=None):
platforms = { platforms = {
2:"Apple iOS", 2:"Apple iOS",
5:"Android", 5:"Android",
12:"Windows Desktop" 12:"Windows"
} }
if(device.PlatformId in platforms.keys()): if(device.PlatformId in platforms.keys()):
@ -107,10 +151,28 @@ class GLPIAPI:
osArch = "Unknown" osArch = "Unknown"
softwareArch = "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") 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 = 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.SetHardware(deviceName, device.Uuid, device.TotalMemory)
inventory.AddUser(device.User) inventory.AddUser(device.User)

View File

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

View File

@ -2,6 +2,7 @@
import os import os
import argparse import argparse
import logging import logging
import time
from datetime import datetime from datetime import datetime
from functions import getSettings from functions import getSettings
from includes.airwatchAPI import * from includes.airwatchAPI import *
@ -22,7 +23,7 @@ args = parser.parse_args()
if(args.configpath != None and args.configpath != ''): if(args.configpath != None and args.configpath != ''):
settings = getSettings(args.configpath) settings = getSettings(args.configpath)
else: 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 ===========# #=========== Configuration des logs ===========#
@ -105,11 +106,21 @@ platformFilterOut = [12]
# ====================================== # # ====================================== #
# Vérification de la présence du verrou avant de continuer # Vérification de la présence du verrou avant de continuer
if(os.path.isfile(lockFile) and not args.force): if(os.path.isfile(lockFile) and not args.force):
logger.debug('Lock file exists, exiting...') # Récupération du temps de création de verrou en minutes
exit(0) 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: else:
# Création du verrou s'il n'existe pas
open(lockFile, "w").close() open(lockFile, "w").close()
logger.info("========= Synchronization started =========") 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...") loggerDouble.error(f"{count} devices matching airwatch device {device.FriendlyName} (Airwatch id={device.Id}) in GLPI (GLPI ids = {', '.join(deviceID)}), skipping this device...")
continue continue
if(count == 0): 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 continue
inventory = glpiapi.CreateInventoryForAirwatchDevice(device, data["1"], apps) inventory = glpiapi.CreateInventoryForAirwatchDevice(device, data["1"], apps)
# Mise à jour du friendly name sur Airwatch # Mise à jour du friendly name sur Airwatch
platformName = inventory.operatingsystem["name"] platformName = inventory.operatingsystem["name"]
if(device.FriendlyName != f"{data['1']} {platformName} {device.OS} - {device.User}"): osVersion = inventory.operatingsystem["version"]
newFriendlyName = f"{data['1']} {platformName} {device.OS} - {device.User}" 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}") logger.info(f"Updating device friendlyname to {newFriendlyName}")
airwatch.SetDeviceFriendlyName(device, 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 # filtre des plateformes
if(platformFilterEnabled): if(platformFilterEnabled):
if device.PlatformId in platformFilterOut: if device.PlatformId in platformFilterOut:
@ -224,6 +247,12 @@ for device in devices:
logger.info(f"Updating {deviceID} on GLPI") logger.info(f"Updating {deviceID} on GLPI")
glpiapi.UpdateInventory(inventory.Json()) 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): if(data['5'] != device.SerialNumber):
logger.info(f"Updating serial number from {data['5']} to {device.SerialNumber} in GLPI (id={deviceID})") logger.info(f"Updating serial number from {data['5']} to {device.SerialNumber} in GLPI (id={deviceID})")
glpiapi.UpdateSerialNumber(deviceID, device.SerialNumber) glpiapi.UpdateSerialNumber(deviceID, device.SerialNumber)