Compare commits
11 Commits
ad634c7ec3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1168cf62f3 | |||
| 73a94c3c50 | |||
| 8e698cfc49 | |||
| e25463ff89 | |||
| 064ecfad43 | |||
| 13bc1f46d7 | |||
| a89a17020a | |||
| 078d4f0923 | |||
| 20f28b71db | |||
| 2bb3eec219 | |||
| 2fa704f381 |
31
README.md
31
README.md
@ -3,7 +3,7 @@
|
|||||||
## Explication de l'usage des scripts et de la configuration :
|
## Explication de l'usage des scripts et de la configuration :
|
||||||
|
|
||||||
### Fichier de configuration global settings.json
|
### Fichier de configuration global settings.json
|
||||||
Les scripts prennent les informations de configuration du fichier de configuration présent dans le répertoire conf, si celui-ci n'existe pas au lancement d'un script, il est automatiquement créé avec des valeurs d'exemples.
|
Les scripts prennent les informations de configuration du fichier de configuration présent dans le répertoire conf, si celui-ci n'existe pas au lancement d'un script, il est automatiquement créé avec des valeurs d'exemples. Un chemin personnalisé vers un fichier de configuration peut être renseigné avec le paramètre -c.
|
||||||
|
|
||||||
Voici un exemple du fichier de configuration :
|
Voici un exemple du fichier de configuration :
|
||||||
|
|
||||||
@ -85,10 +85,6 @@ Il récupère le nom de l'utilisateur de staging dans le fichier de configuratio
|
|||||||
- **-s / --silent** : exécute le script sans faire de retour dans la console, les informations seront toujours présentes dans les fichiers de log
|
- **-s / --silent** : exécute le script sans faire de retour dans la console, les informations seront toujours présentes dans les fichiers de log
|
||||||
- **-v / --verbose** : affiche des informations lors de son exécution, utile pour résoudre des problèmes liés à des droits d'accès API ou des problèmes d'ouvertures réseaux
|
- **-v / --verbose** : affiche des informations lors de son exécution, utile pour résoudre des problèmes liés à des droits d'accès API ou des problèmes d'ouvertures réseaux
|
||||||
|
|
||||||
## Installation avec docker
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Dépendances
|
## Dépendances
|
||||||
Installation des paquets linux :
|
Installation des paquets linux :
|
||||||
|
|
||||||
@ -102,28 +98,9 @@ apt-get install -y python3 python3-pip git
|
|||||||
yum install -y python3 python3-pip git
|
yum install -y python3 python3-pip git
|
||||||
```
|
```
|
||||||
|
|
||||||
## Modules python nécessaires
|
**Dépendances python**
|
||||||
Voici la liste des modules python nécessaires au fonctionnement des scripts :
|
|
||||||
- cryptography
|
|
||||||
- requests
|
|
||||||
- toml
|
|
||||||
|
|
||||||
Un fichier requirements.txt contenant les modules dont dépendent les scripts est présent dans le répertoire scripts.
|
|
||||||
Les modules peuvent être installés de plusieurs façons :
|
|
||||||
|
|
||||||
**Avec le gestionnaire de paquet python Pip**
|
|
||||||
```
|
```
|
||||||
python -m pip install -r requirements.txt
|
python3 -m pip install cryptography requests toml
|
||||||
```
|
|
||||||
|
|
||||||
**Avec le gestionnaire de paquet apt (debian/ubuntu)**
|
|
||||||
```
|
|
||||||
apt-get install -y python3-cryptography python3-requests python3-toml
|
|
||||||
```
|
|
||||||
|
|
||||||
**Avec le gestionnaire de paquet yum (redhat/centos)**
|
|
||||||
```
|
|
||||||
yum install -y python3-cryptography python3-requests python3-toml
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation des scripts
|
## Installation des scripts
|
||||||
@ -195,7 +172,7 @@ Description=Script qui assigne les appareils en staging aux utilisateurs en se b
|
|||||||
[Timer]
|
[Timer]
|
||||||
OnUnitInactiveSec=1m
|
OnUnitInactiveSec=1m
|
||||||
AccuracySec=1us
|
AccuracySec=1us
|
||||||
Unit=airwatchStaging.service
|
Unit=airwatchSync.service
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=timers.target
|
WantedBy=timers.target
|
||||||
|
|||||||
28
compose.yml
28
compose.yml
@ -1,28 +0,0 @@
|
|||||||
services:
|
|
||||||
sync:
|
|
||||||
image: emitlinks/airwatchConnector
|
|
||||||
restart: unless-stopped
|
|
||||||
volumes:
|
|
||||||
- ./conf:/airwatchConnector/conf
|
|
||||||
- ./certs:/airwatchConnector/certs
|
|
||||||
- ./logs:/airwatchConnector/logs
|
|
||||||
healthcheck:
|
|
||||||
test: if [ -f $(ls /airwatchConnector/*_SyncGLPI.lock) ]; then exit 0; else exit 1; fi
|
|
||||||
interval: 5m
|
|
||||||
start_period: 3h
|
|
||||||
environment:
|
|
||||||
TASK: "syncGLPI"
|
|
||||||
|
|
||||||
stagingAssignment:
|
|
||||||
image: emitlinks/airwatchConnector
|
|
||||||
restart: unless-stopped
|
|
||||||
volumes:
|
|
||||||
- ./conf:/airwatchConnector/conf
|
|
||||||
- ./certs:/airwatchConnector/certs
|
|
||||||
- ./logs:/airwatchConnector/logs
|
|
||||||
healthcheck:
|
|
||||||
test: if [ -f $(ls /airwatchConnector/*_StagingUserAssignation.lock) ]; then exit 0; else exit 1; fi
|
|
||||||
interval: 15s
|
|
||||||
start_period: 5m
|
|
||||||
environment:
|
|
||||||
TASK: "stagingAssignment"
|
|
||||||
10
dockerfile
10
dockerfile
@ -1,10 +0,0 @@
|
|||||||
FROM python
|
|
||||||
RUN <<-EOF
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y python3-cryptography python3-requests python3-toml
|
|
||||||
EOF
|
|
||||||
ADD scripts\* /airwatchConnector
|
|
||||||
ADD pre-start.py /
|
|
||||||
ADD start.sh /
|
|
||||||
RUN chmod u+x /start.sh
|
|
||||||
ENTRYPOINT ["/start.sh"]
|
|
||||||
26
pre-start.py
26
pre-start.py
@ -1,26 +0,0 @@
|
|||||||
import os
|
|
||||||
import toml
|
|
||||||
|
|
||||||
baseDir = "/airwatchConnector"
|
|
||||||
logDir = f"{baseDir}/logs"
|
|
||||||
confDir = f"{baseDir}/conf"
|
|
||||||
confFiles = os.listdir(confDir)
|
|
||||||
|
|
||||||
# On récupère que les fichiers .conf
|
|
||||||
confFiles = [conf for conf in confFiles if os.path.isfile(f"{confDir}/{conf}") and not conf.endswith(".conf")]
|
|
||||||
|
|
||||||
for conf in confFiles:
|
|
||||||
# On forme un nom à partir du nom du fichier de conf sans l'extension
|
|
||||||
# et on enlève les espaces
|
|
||||||
confName = conf[:5].replace(' ', '')
|
|
||||||
|
|
||||||
with open(f"{confDir}/{conf}", "r") as f:
|
|
||||||
settings = toml.load(f)
|
|
||||||
|
|
||||||
# Create log folder
|
|
||||||
if(settings["LOGS"]["Enabled"]):
|
|
||||||
logPath = settings["LOGS"].get(Path)
|
|
||||||
if not os.path.exists(f"{logDir}/{logPath}"):
|
|
||||||
os.makedirs(f"{logDir}/{logPath}")
|
|
||||||
|
|
||||||
|
|
||||||
@ -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 *
|
||||||
@ -20,7 +21,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(f"{os.path.realpath(os.path.dirname(__file__))}/conf/settings.conf")
|
settings = getSettings("./conf/settings.conf")
|
||||||
|
|
||||||
#=========== Configuration des logs ===========#
|
#=========== Configuration des logs ===========#
|
||||||
|
|
||||||
@ -41,7 +42,7 @@ if(settings["LOGS"]["Enabled"]):
|
|||||||
if(settings["LOGS"].get("Path") and settings["LOGS"].get("Path") != ""):
|
if(settings["LOGS"].get("Path") and settings["LOGS"].get("Path") != ""):
|
||||||
fileHandler = logging.FileHandler(f"{settings['LOGS'].get('Path')}stagingUserAssignation.log")
|
fileHandler = logging.FileHandler(f"{settings['LOGS'].get('Path')}stagingUserAssignation.log")
|
||||||
else:
|
else:
|
||||||
fileHandler = logging.FileHandler(f'{os.path.realpath(os.path.dirname(__file__))}/logs/stagingUserAssignation.log')
|
fileHandler = logging.FileHandler('./logs/stagingUserAssignation.log')
|
||||||
fileHandler.setLevel(logginglevel)
|
fileHandler.setLevel(logginglevel)
|
||||||
fileHandler.setFormatter(formatter)
|
fileHandler.setFormatter(formatter)
|
||||||
logger.addHandler(fileHandler)
|
logger.addHandler(fileHandler)
|
||||||
@ -56,8 +57,7 @@ if(not args.silent):
|
|||||||
#======== Paramètres du script ========#
|
#======== Paramètres du script ========#
|
||||||
|
|
||||||
# Emplacement du verrou
|
# Emplacement du verrou
|
||||||
nameForLockFile = settings["GLPI"]["UserAgent"].replace(' ', '-')
|
lockFile = './airwatchStagingUserAssignation.lock'
|
||||||
lockFile = f'{os.path.realpath(os.path.dirname(__file__))}/{nameForLockFile}_StagingUserAssignation.lock'
|
|
||||||
|
|
||||||
debug=args.debug
|
debug=args.debug
|
||||||
|
|
||||||
@ -68,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
|
||||||
@ -143,15 +151,9 @@ for device in devices:
|
|||||||
else:
|
else:
|
||||||
logger.warning(f"Device with id {device.Id} is not assigned to any user in GLPI, skipping the device")
|
logger.warning(f"Device with id {device.Id} is not assigned to any user in GLPI, skipping the device")
|
||||||
elif(deviceCount > 1):
|
elif(deviceCount > 1):
|
||||||
logger.error(f"{count} devices matching airwatch device {device.FriendlyName} (Airwatch id={device.Id}) in GLPI trashbin (GLPI ids = {', '.join(deviceID)}), skipping this device...")
|
logger.info(f"More than one entry found in GLPI for device with id {device.Id}")
|
||||||
else:
|
else:
|
||||||
deviceIDTrash, dataTrash, deviceCountTrash = glpiapi.GetDevice(device, trashbin=True)
|
logger.error(f"Device {device.Id} with serialnumber {device.SerialNumber} not found in GLPI (in trash bin ?)")
|
||||||
if(countTrash > 1):
|
|
||||||
logger.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:
|
|
||||||
logger.error(f"Device {device.FriendlyName} (Airwatch id={device.Id}) not found in GLPI.")
|
|
||||||
|
|
||||||
|
|
||||||
# Suppression du verrou
|
# Suppression du verrou
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -33,21 +33,17 @@ class GLPIAPI:
|
|||||||
"App-Token": self.AppToken
|
"App-Token": self.AppToken
|
||||||
}
|
}
|
||||||
|
|
||||||
def GetDevice(self, device, trashbin=False):
|
def GetDevice(self, device):
|
||||||
if(trashbin):
|
|
||||||
checkDeleted = 1
|
|
||||||
else:
|
|
||||||
checkDeleted = 0
|
|
||||||
if(device.Imei != ''):
|
if(device.Imei != ''):
|
||||||
# Recherche des appareils en fonction du numéro de série ou de l'imei
|
# Recherche des appareils en fonction du numéro de série ou de l'imei
|
||||||
# l'imei pouvant être dans le champ numéro de série ou les champs imei custom
|
# l'imei pouvant être dans le champ numéro de série ou les champs imei custom
|
||||||
search_parameter = f'is_deleted={checkDeleted}&criteria[0][field]=5&withindexes=true&criteria[0][searchtype]=contains&criteria[0][value]=^{device.SerialNumber}$'\
|
search_parameter = f'is_deleted=0&criteria[0][field]=5&withindexes=true&criteria[0][searchtype]=contains&criteria[0][value]=^{device.SerialNumber}$'\
|
||||||
f'&criteria[1][link]=OR&criteria[1][field]=5&criteria[1][searchtype]=contains&criteria[1][value]=^{device.Imei}$'\
|
f'&criteria[1][link]=OR&criteria[1][field]=5&criteria[1][searchtype]=contains&criteria[1][value]=^{device.Imei}$'\
|
||||||
f'&criteria[2][link]=OR&criteria[2][field]=76667&criteria[2][searchtype]=contains&criteria[2][value]=^{device.Imei}$'\
|
f'&criteria[2][link]=OR&criteria[2][field]=76667&criteria[2][searchtype]=contains&criteria[2][value]=^{device.Imei}$'\
|
||||||
f'&criteria[3][link]=OR&criteria[3][field]=76670&criteria[3][searchtype]=contains&criteria[3][value]=^{device.Imei}$'
|
f'&criteria[3][link]=OR&criteria[3][field]=76670&criteria[3][searchtype]=contains&criteria[3][value]=^{device.Imei}$'
|
||||||
else:
|
else:
|
||||||
# Recherche des appareils en fonction du numéro de série seulement
|
# Recherche des appareils en fonction du numéro de série seulement
|
||||||
search_parameter = f'is_deleted={checkDeleted}&criteria[0][field]=5&withindexes=true&criteria[0][searchtype]=contains&criteria[0][value]=^{device.SerialNumber}$'
|
search_parameter = f'is_deleted=0&criteria[0][field]=5&withindexes=true&criteria[0][searchtype]=contains&criteria[0][value]=^{device.SerialNumber}$'
|
||||||
|
|
||||||
searchUri = f"{self.Server}/apirest.php/search/computer?{search_parameter}"
|
searchUri = f"{self.Server}/apirest.php/search/computer?{search_parameter}"
|
||||||
search = requests.get(searchUri, headers=self.Headers)
|
search = requests.get(searchUri, headers=self.Headers)
|
||||||
@ -65,6 +61,27 @@ class GLPIAPI:
|
|||||||
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",
|
||||||
@ -83,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()):
|
||||||
@ -112,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)
|
||||||
|
|
||||||
|
|||||||
@ -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"]
|
||||||
|
|||||||
@ -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,7 +215,7 @@ 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):
|
||||||
deviceIDTrash, dataTrash, countTrash = glpiapi.GetDevice(device, trashbin=True)
|
deviceIDTrash, dataTrash, countTrash = glpiapi.GetDevice(device)
|
||||||
if(countTrash > 1):
|
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...")
|
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):
|
elif(countTrash == 1):
|
||||||
@ -216,11 +227,17 @@ for device in devices:
|
|||||||
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:
|
||||||
@ -230,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)
|
||||||
|
|||||||
39
start.sh
39
start.sh
@ -1,39 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
python /pre-start.py
|
|
||||||
|
|
||||||
if [ $CONF != '' ]; then
|
|
||||||
case $TASK in
|
|
||||||
|
|
||||||
syncGLPI)
|
|
||||||
python3 /airwatchConnector/sync.py -c $CONF -f
|
|
||||||
;;
|
|
||||||
|
|
||||||
stagingAssignment)
|
|
||||||
python3 /airwatchConnector/stagingUserAssignation.py -c $CONF -f
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
confFiles = $(ls /airwatchConnector/conf/*.conf)
|
|
||||||
if [ $confFiles = '' ]; then exit 1; do
|
|
||||||
for CONF in $confFiles; do
|
|
||||||
case $TASK in
|
|
||||||
|
|
||||||
syncGLPI)
|
|
||||||
python3 /airwatchConnector/sync.py -c $CONF -for
|
|
||||||
;;
|
|
||||||
|
|
||||||
stagingAssignment)
|
|
||||||
python3 /airwatchConnector/stagingUserAssignation.py -c $CONF -f
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
Reference in New Issue
Block a user