Compare commits
10 Commits
main
...
ad634c7ec3
| Author | SHA1 | Date | |
|---|---|---|---|
| ad634c7ec3 | |||
| 84c52ae234 | |||
| 5eb7b6b778 | |||
| e0e5ea37ce | |||
| 70211dc9ac | |||
| 43c4ba4639 | |||
| b63ff9d788 | |||
| 05a0b50741 | |||
| c46e426282 | |||
| 1228e2ac2a |
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. Un chemin personnalisé vers un fichier de configuration peut être renseigné avec le paramètre -c.
|
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.
|
||||||
|
|
||||||
Voici un exemple du fichier de configuration :
|
Voici un exemple du fichier de configuration :
|
||||||
|
|
||||||
@@ -85,6 +85,10 @@ 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 :
|
||||||
|
|
||||||
@@ -98,9 +102,28 @@ apt-get install -y python3 python3-pip git
|
|||||||
yum install -y python3 python3-pip git
|
yum install -y python3 python3-pip git
|
||||||
```
|
```
|
||||||
|
|
||||||
**Dépendances python**
|
## Modules python nécessaires
|
||||||
|
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**
|
||||||
```
|
```
|
||||||
python3 -m pip install cryptography requests toml
|
python -m pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
**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
|
||||||
@@ -172,7 +195,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=airwatchSync.service
|
Unit=airwatchStaging.service
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=timers.target
|
WantedBy=timers.target
|
||||||
|
|||||||
28
compose.yml
Normal file
28
compose.yml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
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
Normal file
10
dockerfile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
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
Normal file
26
pre-start.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
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,7 +2,6 @@
|
|||||||
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 *
|
||||||
@@ -21,7 +20,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("./conf/settings.conf")
|
settings = getSettings(f"{os.path.realpath(os.path.dirname(__file__))}/conf/settings.conf")
|
||||||
|
|
||||||
#=========== Configuration des logs ===========#
|
#=========== Configuration des logs ===========#
|
||||||
|
|
||||||
@@ -42,7 +41,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('./logs/stagingUserAssignation.log')
|
fileHandler = logging.FileHandler(f'{os.path.realpath(os.path.dirname(__file__))}/logs/stagingUserAssignation.log')
|
||||||
fileHandler.setLevel(logginglevel)
|
fileHandler.setLevel(logginglevel)
|
||||||
fileHandler.setFormatter(formatter)
|
fileHandler.setFormatter(formatter)
|
||||||
logger.addHandler(fileHandler)
|
logger.addHandler(fileHandler)
|
||||||
@@ -57,7 +56,8 @@ if(not args.silent):
|
|||||||
#======== Paramètres du script ========#
|
#======== Paramètres du script ========#
|
||||||
|
|
||||||
# Emplacement du verrou
|
# Emplacement du verrou
|
||||||
lockFile = './airwatchStagingUserAssignation.lock'
|
nameForLockFile = settings["GLPI"]["UserAgent"].replace(' ', '-')
|
||||||
|
lockFile = f'{os.path.realpath(os.path.dirname(__file__))}/{nameForLockFile}_StagingUserAssignation.lock'
|
||||||
|
|
||||||
debug=args.debug
|
debug=args.debug
|
||||||
|
|
||||||
@@ -68,20 +68,12 @@ 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):
|
||||||
# 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...')
|
logger.debug('Lock file exists, exiting...')
|
||||||
exit(0)
|
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
|
||||||
@@ -151,9 +143,15 @@ 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.info(f"More than one entry found in GLPI for device with id {device.Id}")
|
logger.error(f"{count} devices matching airwatch device {device.FriendlyName} (Airwatch id={device.Id}) in GLPI trashbin (GLPI ids = {', '.join(deviceID)}), skipping this device...")
|
||||||
else:
|
else:
|
||||||
logger.error(f"Device {device.Id} with serialnumber {device.SerialNumber} not found in GLPI (in trash bin ?)")
|
deviceIDTrash, dataTrash, deviceCountTrash = glpiapi.GetDevice(device, trashbin=True)
|
||||||
|
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,7 +5,6 @@ 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)
|
||||||
|
|||||||
215
scripts/includes/GLPIAPI.py
Normal file
215
scripts/includes/GLPIAPI.py
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class GLPIAPI:
|
||||||
|
def __init__(self, settings):
|
||||||
|
self.Server = settings["GLPI"]["Server"]
|
||||||
|
self.AppToken = settings["GLPI"]["AppToken"]
|
||||||
|
self.UserToken = settings["GLPI"]["UserToken"]
|
||||||
|
self.UserAgent = settings["GLPI"]["UserAgent"]
|
||||||
|
self.SessionToken = None
|
||||||
|
self.StatusCode = None
|
||||||
|
self.Headers = None
|
||||||
|
self.InitConnection()
|
||||||
|
|
||||||
|
def InitConnection(self):
|
||||||
|
initURI = '/apirest.php/initSession/'
|
||||||
|
GLPIHeaders = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
"Authorization": f"user_token {self.UserToken}",
|
||||||
|
"App-Token": self.AppToken
|
||||||
|
}
|
||||||
|
|
||||||
|
# Récupération d'un token de session
|
||||||
|
uri = f"{self.Server}{initURI}"
|
||||||
|
result = requests.get(uri, headers=GLPIHeaders)
|
||||||
|
self.StatusCode = result.status_code
|
||||||
|
if(result.status_code == 200):
|
||||||
|
self.SessionToken = result.json()["session_token"]
|
||||||
|
self.Headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
"Session-Token": self.SessionToken,
|
||||||
|
"App-Token": self.AppToken
|
||||||
|
}
|
||||||
|
|
||||||
|
def GetDevice(self, device, trashbin=False):
|
||||||
|
if(trashbin):
|
||||||
|
checkDeleted = 1
|
||||||
|
else:
|
||||||
|
checkDeleted = 0
|
||||||
|
if(device.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
|
||||||
|
search_parameter = f'is_deleted={checkDeleted}&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[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}$'
|
||||||
|
else:
|
||||||
|
# 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}$'
|
||||||
|
|
||||||
|
searchUri = f"{self.Server}/apirest.php/search/computer?{search_parameter}"
|
||||||
|
search = requests.get(searchUri, headers=self.Headers)
|
||||||
|
if(search.status_code == 200):
|
||||||
|
search = search.json()
|
||||||
|
if(search["totalcount"] == 1):
|
||||||
|
deviceID = list(search["data"].keys())[0]
|
||||||
|
data = search["data"][deviceID]
|
||||||
|
|
||||||
|
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 UpdateInventory(self, inventory):
|
||||||
|
headers = {
|
||||||
|
"Content-Type":"Application/x-compress",
|
||||||
|
"user-agent":self.UserAgent
|
||||||
|
}
|
||||||
|
return requests.post(self.Server, headers=headers, data=inventory)
|
||||||
|
|
||||||
|
def UpdateSerialNumber(self, deviceid, serialnumber):
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"input" : {
|
||||||
|
"id" : deviceid,
|
||||||
|
"serial" : serialnumber
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
if(device.PlatformId in platforms.keys()):
|
||||||
|
platformName = platforms[device.PlatformId]
|
||||||
|
else:
|
||||||
|
platformName = "Unknown"
|
||||||
|
|
||||||
|
processorArchs = {
|
||||||
|
0:{
|
||||||
|
"osArch":"arm64",
|
||||||
|
"softwareArch":"arm64"
|
||||||
|
},
|
||||||
|
9:{
|
||||||
|
"osArch":"64-bit",
|
||||||
|
"softwareArch":"x86_64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(device.Arch in processorArchs.keys()):
|
||||||
|
osArch = processorArchs[device.Arch]["osArch"]
|
||||||
|
softwareArch = processorArchs[device.Arch]["softwareArch"]
|
||||||
|
else:
|
||||||
|
osArch = "Unknown"
|
||||||
|
softwareArch = "Unknown"
|
||||||
|
|
||||||
|
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)
|
||||||
|
inventory.SetHardware(deviceName, device.Uuid, device.TotalMemory)
|
||||||
|
inventory.AddUser(device.User)
|
||||||
|
|
||||||
|
if(apps != None):
|
||||||
|
for app in apps:
|
||||||
|
if(app.Status != "Installed"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
install_date = datetime.strptime(app.InstallDate, "%Y-%m-%dT%H:%M:%S.%f").strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
if(install_date == "1-01-01"):
|
||||||
|
inventory.AddSoftware(app.Name, app.Version, app.Size, softwareArch, app.Guid)
|
||||||
|
else:
|
||||||
|
inventory.AddSoftware(app.Name, app.Version, app.Size, softwareArch, app.Guid, install_date)
|
||||||
|
|
||||||
|
return inventory
|
||||||
|
|
||||||
|
class GLPIInventory:
|
||||||
|
def __init__(self, logdate=None, versionclient=None, tag=None, deviceid=None, itemtype=None):
|
||||||
|
self.logdate = logdate
|
||||||
|
self.versionclient = versionclient
|
||||||
|
self.users = []
|
||||||
|
self.operatingsystem = {}
|
||||||
|
self.softwares = []
|
||||||
|
self.hardware = {}
|
||||||
|
self.tag = tag
|
||||||
|
self.deviceId = deviceid
|
||||||
|
self.itemType = itemtype
|
||||||
|
|
||||||
|
|
||||||
|
def AddUser(self, user):
|
||||||
|
self.users += [{
|
||||||
|
"login": user
|
||||||
|
}]
|
||||||
|
|
||||||
|
def DelUser(self, user):
|
||||||
|
for i in range(0, len(self.users)):
|
||||||
|
if(self.users[i]["login"] == user):
|
||||||
|
del self.users[i]
|
||||||
|
|
||||||
|
def AddSoftware(self, name, version, filesize, arch, guid, install_date=None):
|
||||||
|
if(install_date == None):
|
||||||
|
self.softwares += [{
|
||||||
|
"name": name,
|
||||||
|
"guid": guid,
|
||||||
|
"version": version,
|
||||||
|
"filesize": filesize,
|
||||||
|
"arch": arch
|
||||||
|
}]
|
||||||
|
else:
|
||||||
|
self.softwares += [{
|
||||||
|
"name": name,
|
||||||
|
"guid": guid,
|
||||||
|
"version": version,
|
||||||
|
"install_date": install_date,
|
||||||
|
"filesize": filesize,
|
||||||
|
"arch": arch
|
||||||
|
}]
|
||||||
|
|
||||||
|
def DelSoftware(self, guid):
|
||||||
|
for i in range(0, len(self.softwares)):
|
||||||
|
if(self.softwares[i]["guid"] == guid):
|
||||||
|
del self.softwares[i]
|
||||||
|
|
||||||
|
def SetHardware(self, name, uuid, memory):
|
||||||
|
self.hardware = {
|
||||||
|
"name": name,
|
||||||
|
"uuid": uuid,
|
||||||
|
"memory": memory
|
||||||
|
}
|
||||||
|
|
||||||
|
def SetOperatingSystem(self, name, version, arch):
|
||||||
|
self.operatingsystem = {
|
||||||
|
"name": name,
|
||||||
|
"version": version,
|
||||||
|
"full_name": f"{name} {version}",
|
||||||
|
"arch": arch
|
||||||
|
}
|
||||||
|
|
||||||
|
def Json(self):
|
||||||
|
inventory = {
|
||||||
|
"action": "inventory",
|
||||||
|
"content":{
|
||||||
|
"accesslog":{
|
||||||
|
"logdate": self.logdate
|
||||||
|
},
|
||||||
|
"versionclient": self.versionclient,
|
||||||
|
"users": self.users,
|
||||||
|
"operatingsystem": self.operatingsystem,
|
||||||
|
"softwares": self.softwares,
|
||||||
|
"hardware": self.hardware
|
||||||
|
},
|
||||||
|
"tag": self.tag,
|
||||||
|
"deviceid": self.deviceId,
|
||||||
|
"itemtype": self.itemType
|
||||||
|
}
|
||||||
|
return json.dumps(inventory)
|
||||||
0
scripts/includes/__init__.py
Normal file
0
scripts/includes/__init__.py
Normal file
205
scripts/includes/airwatchAPI.py
Normal file
205
scripts/includes/airwatchAPI.py
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
import base64
|
||||||
|
import requests
|
||||||
|
from cryptography.hazmat.primitives.serialization import pkcs12, pkcs7
|
||||||
|
from cryptography.hazmat.primitives import hashes, serialization
|
||||||
|
|
||||||
|
class AirwatchAPI:
|
||||||
|
def __init__(self, settings):
|
||||||
|
self.Server = settings["AIRWATCH"]["Server"]
|
||||||
|
self.APIKey = settings["AIRWATCH"]["APIKey"]
|
||||||
|
self.AuthMethod = (settings["AIRWATCH"]["AuthenticationMethod"]).upper()
|
||||||
|
|
||||||
|
if(self.AuthMethod == "PASSWORD"):
|
||||||
|
self.APIUser = settings["AIRWATCH"]["APIUser"]
|
||||||
|
self.APIPassword = settings["AIRWATCH"]["APIPassword"]
|
||||||
|
|
||||||
|
if(self.AuthMethod == "CMSURL"):
|
||||||
|
self.CertificatePath = settings["AIRWATCH"]["CertificatePath"]
|
||||||
|
self.CertificatePassword = settings["AIRWATCH"]["CertificatePassword"]
|
||||||
|
|
||||||
|
def GetHeaders(self, uri):
|
||||||
|
if(self.AuthMethod == "PASSWORD"):
|
||||||
|
airwatchAPIUserToken = base64.b64encode(f"{self.APIUser}:{self.APIPassword}".encode('ascii')).decode("ascii")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"Authorization": f"Basic {airwatchAPIUserToken}",
|
||||||
|
"aw-tenant-code": self.APIKey,
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
signing_data = uri.split('?')[0]
|
||||||
|
with open(self.CertificatePath, 'rb') as certfile:
|
||||||
|
cert = certfile.read()
|
||||||
|
key, certificate, additional_certs = pkcs12.load_key_and_certificates(cert, self.CertificatePassword.encode())
|
||||||
|
options = [pkcs7.PKCS7Options.DetachedSignature]
|
||||||
|
signed_data = pkcs7.PKCS7SignatureBuilder().set_data(signing_data.encode("UTF-8")).add_signer(certificate, key, hashes.SHA256()).sign(serialization.Encoding.DER, options)
|
||||||
|
signed_data_b64 = base64.b64encode(signed_data).decode()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"Authorization": f"CMSURL'1 {signed_data_b64}",
|
||||||
|
"aw-tenant-code": self.APIKey,
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
def GetUser(self, username):
|
||||||
|
cmdURI = f'/API/system/users/search?username={username}'
|
||||||
|
airwatchHeaders = self.GetHeaders(cmdURI)
|
||||||
|
uri = f"{self.Server}{cmdURI}"
|
||||||
|
user = requests.get(uri, headers=airwatchHeaders)
|
||||||
|
if(user.status_code == 200):
|
||||||
|
return AirwatchUser(user.json()["Users"][0])
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def GetDevices(self, user: str = ""):
|
||||||
|
if(user == ""):
|
||||||
|
cmdURI = f"/API/mdm/devices/search?pagesize=500&page="
|
||||||
|
else:
|
||||||
|
cmdURI = f"/API/mdm/devices/search?user={user}&pagesize=500&page="
|
||||||
|
airwatchHeaders = self.GetHeaders(cmdURI)
|
||||||
|
pageNum = 0
|
||||||
|
devices = []
|
||||||
|
uri = f"{self.Server}{cmdURI}{pageNum}"
|
||||||
|
result = requests.get(uri, headers=airwatchHeaders)
|
||||||
|
if(result.status_code == 200):
|
||||||
|
deviceTotalCount = result.json()["Total"]
|
||||||
|
|
||||||
|
while(len(devices) != deviceTotalCount):
|
||||||
|
uri = f"{self.Server}{cmdURI}{pageNum}"
|
||||||
|
result = requests.get(uri, headers=airwatchHeaders).json()["Devices"]
|
||||||
|
for device in result:
|
||||||
|
devices += [AirwatchDevice(device)]
|
||||||
|
pageNum += 1
|
||||||
|
return devices
|
||||||
|
return None
|
||||||
|
|
||||||
|
def GetDeviceApps(self, device):
|
||||||
|
cmdURI = f"/api/mdm/devices/{device.Uuid}/apps/search"
|
||||||
|
airwatchHeaders = self.GetHeaders(cmdURI)
|
||||||
|
uri = f"{self.Server}{cmdURI}"
|
||||||
|
apps = []
|
||||||
|
result = requests.get(uri, headers=airwatchHeaders)
|
||||||
|
if(result.status_code == 200):
|
||||||
|
for app in result.json()["app_items"]:
|
||||||
|
apps += [AirwatchApplication(app)]
|
||||||
|
return apps
|
||||||
|
return None
|
||||||
|
|
||||||
|
def ResetDEPProfiles(self, groupUuid):
|
||||||
|
cmdURI = f"/API/mdm/dep/groups/{groupUuid}/devices"
|
||||||
|
uri = f"{self.Server}{cmdURI}"
|
||||||
|
airwatchHeaders = self.GetHeaders(cmdURI)
|
||||||
|
result = requests.get(uri, headers=airwatchHeaders)
|
||||||
|
if(result.status_code == 200):
|
||||||
|
for device in result.json():
|
||||||
|
if (device["enrollmentStatus"] != "Unenrolled"):
|
||||||
|
continue
|
||||||
|
assignDEPProfileURI = f"/API/mdm/dep/profiles/{device['profileUuid']}/devices/{device['deviceSerialNumber']}?action=Assign"
|
||||||
|
uri = f"{airwatchServer}{assignDEPProfileURI}"
|
||||||
|
airwatchHeaders = self.GetHeaders(assignDEPProfileURI)
|
||||||
|
requests.put(uri, headers=airwatchHeaders)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def GetEnrollmentTokens(self, groupUuid, deviceType=2):
|
||||||
|
cmdURI = f"/API/mdm/groups/{groupUuid}/enrollment-tokens?device_type={deviceType}&page_size=500"
|
||||||
|
uri = f"{self.Server}{cmdURI}"
|
||||||
|
airwatchHeaders = self.GetHeaders(cmdURI)
|
||||||
|
result = requests.get(uri, headers=airwatchHeaders)
|
||||||
|
return result.json()["tokens"]
|
||||||
|
|
||||||
|
def UpdateUserOnEnrollmentTokens(self, groupUuid,user, serialnumber):
|
||||||
|
body = {
|
||||||
|
"registration_type": "REGISTER_DEVICE",
|
||||||
|
"device_registration_record": {
|
||||||
|
"user_uuid": user.Uuid,
|
||||||
|
"friendly_name": serialnumber,
|
||||||
|
"ownership_type": "CORPORATE_DEDICATED",
|
||||||
|
"serial_number": serialnumber,
|
||||||
|
"to_email_address": user.Email,
|
||||||
|
"message_type": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmdURI = f"/API/mdm/groups/{groupUuid}/enrollment-tokens"
|
||||||
|
airwatchHeaders = self.GetHeaders(cmdURI)
|
||||||
|
airwatchHeaders["Accept"] = "application/json;version=2"
|
||||||
|
uri = f"{self.Server}{cmdURI}"
|
||||||
|
print(uri)
|
||||||
|
return requests.post(uri, headers=airwatchHeaders, json=body)
|
||||||
|
|
||||||
|
def SyncDEPDevices(self, groupUuid):
|
||||||
|
cmdURI = f"/API/mdm/dep/groups/{groupUuid}/devices?action=sync"
|
||||||
|
uri = f"{self.Server}{cmdURI}"
|
||||||
|
airwatchHeaders = self.GetHeaders(cmdURI)
|
||||||
|
return requests.put(uri, headers=airwatchHeaders).status_code
|
||||||
|
|
||||||
|
def SetDeviceFriendlyName(self, device, friendlyName):
|
||||||
|
cmdURI = f"/API/mdm/devices/{device.Id}"
|
||||||
|
airwatchHeaders = self.GetHeaders(cmdURI)
|
||||||
|
uri = f"{self.Server}{cmdURI}"
|
||||||
|
body = {
|
||||||
|
"DeviceFriendlyName":friendlyName
|
||||||
|
}
|
||||||
|
return requests.put(uri, headers=airwatchHeaders, json=body).status_code
|
||||||
|
|
||||||
|
def SetDeviceUser(self, device, airwatchUser):
|
||||||
|
cmdURI = f'/API/mdm/devices/{device.Id}/enrollmentuser/{airwatchUser.Id}'
|
||||||
|
uri = f"{self.Server}{cmdURI}"
|
||||||
|
airwatchHeaders = self.GetHeaders(cmdURI)
|
||||||
|
return requests.patch(uri, headers=airwatchHeaders).status_code
|
||||||
|
|
||||||
|
def DeleteDevice(self, device):
|
||||||
|
cmdURI = f"/API/mdm/devices/{device.Id}"
|
||||||
|
airwatchHeaders = self.GetHeaders(cmdURI)
|
||||||
|
uri = f"{self.Server}{cmdURI}"
|
||||||
|
return requests.delete(uri, headers=airwatchHeaders).status_code
|
||||||
|
|
||||||
|
class AirwatchUser:
|
||||||
|
|
||||||
|
def __init__(self, user):
|
||||||
|
self.Id = user["Id"]["Value"]
|
||||||
|
self.Uuid = user["Uuid"]
|
||||||
|
self.UserName = user["UserName"]
|
||||||
|
self.FirstName = user["FirstName"]
|
||||||
|
self.LastName = user["LastName"]
|
||||||
|
self.Enabled = user["Status"]
|
||||||
|
self.Email = user["Email"]
|
||||||
|
self.DisplayName = user["DisplayName"]
|
||||||
|
self.Group = user["Group"]
|
||||||
|
self.GroupId = user["LocationGroupId"]
|
||||||
|
self.OrgUuid = user["OrganizationGroupUuid"]
|
||||||
|
self.DeviceCount = int(user["EnrolledDevicesCount"])
|
||||||
|
|
||||||
|
class AirwatchDevice:
|
||||||
|
|
||||||
|
def __init__(self, device):
|
||||||
|
self.Id = device["Id"]["Value"]
|
||||||
|
self.Uuid = device["Uuid"]
|
||||||
|
self.SerialNumber = device["SerialNumber"]
|
||||||
|
self.Imei = device["Imei"]
|
||||||
|
self.MacAddress = device["MacAddress"]
|
||||||
|
self.FriendlyName = device["DeviceFriendlyName"]
|
||||||
|
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"]
|
||||||
|
self.UserEmail = device["UserEmailAddress"]
|
||||||
|
self.PlatformId = device["PlatformId"]["Id"]["Value"]
|
||||||
|
self.Platform = device["Platform"]
|
||||||
|
self.OS = device["OperatingSystem"]
|
||||||
|
self.Arch = device["ProcessorArchitecture"]
|
||||||
|
self.TotalMemory = device["TotalPhysicalMemory"]
|
||||||
|
self.EnrollmentStatus = device["EnrollmentStatus"]
|
||||||
|
self.LastEnrolledOn = device["LastEnrolledOn"]
|
||||||
|
self.LastSeen = device["LastSeen"]
|
||||||
|
|
||||||
|
class AirwatchApplication:
|
||||||
|
|
||||||
|
def __init__(self, application):
|
||||||
|
self.Name = application["name"]
|
||||||
|
self.Guid = application["bundle_id"]
|
||||||
|
self.Size = application["size"]
|
||||||
|
self.Version = application["installed_version"]
|
||||||
|
self.InstallDate = application["latest_uem_action_time"]
|
||||||
|
self.Status = application["installed_status"]
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
--extra-index-url=https://gitlab.forge.education.gouv.fr/api/v4/projects/13771/packages/pypi/simple
|
cryptography
|
||||||
--extra-index-url=https://gitlab.forge.education.gouv.fr/api/v4/projects/13820/packages/pypi/simple
|
requests
|
||||||
AirwatchAPI==1.0.3
|
|
||||||
GLPIAPI==1.0.3
|
|
||||||
toml
|
toml
|
||||||
@@ -2,11 +2,10 @@
|
|||||||
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 AirwatchAPI.AirwatchAPI import *
|
from includes.airwatchAPI import *
|
||||||
from GLPIAPI.GLPIAPI import *
|
from includes.GLPIAPI import *
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("-sF", "--searchFilter", dest="searchfilter", type=str, choices=["Id", "SerialNumber", "Imei", "UserName"])
|
parser.add_argument("-sF", "--searchFilter", dest="searchfilter", type=str, choices=["Id", "SerialNumber", "Imei", "UserName"])
|
||||||
@@ -23,7 +22,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("{os.path.realpath(os.path.dirname(__file__))}/conf/settings.conf")
|
||||||
|
|
||||||
#=========== Configuration des logs ===========#
|
#=========== Configuration des logs ===========#
|
||||||
|
|
||||||
@@ -106,27 +105,17 @@ 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):
|
||||||
# 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...')
|
logger.debug('Lock file exists, exiting...')
|
||||||
exit(0)
|
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 =========")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
airwatch = AirwatchAPI(Server=settings["AIRWATCH"]["Server"], APIKey=settings["AIRWATCH"]["APIKey"], AuthMethod=settings["AIRWATCH"]["AuthenticationMethod"], CertPath=settings["AIRWATCH"]["CertificatePath"], CertPass=settings["AIRWATCH"]["CertificatePassword"])
|
airwatch = AirwatchAPI(settings)
|
||||||
# recherche des appareils
|
# recherche des appareils
|
||||||
devices = airwatch.GetDevices()
|
devices = airwatch.GetDevices()
|
||||||
logger.info("Airwatch server connection succeeded")
|
logger.info("Airwatch server connection succeeded")
|
||||||
@@ -141,7 +130,7 @@ except Exception as error:
|
|||||||
|
|
||||||
# Initialisation de l'api GLPI
|
# Initialisation de l'api GLPI
|
||||||
try:
|
try:
|
||||||
glpiapi = GLPIAPI(Server=settings["GLPI"]["Server"], AppToken=settings["GLPI"]["AppToken"], UserToken=settings["GLPI"]["UserToken"], UserAgent=settings["GLPI"]["UserAgent"])
|
glpiapi = GLPIAPI(settings)
|
||||||
logger.info("GLPI server connection succeeded")
|
logger.info("GLPI server connection succeeded")
|
||||||
except requests.exceptions.ConnectionError as error:
|
except requests.exceptions.ConnectionError as error:
|
||||||
logger.critical(f"Connection to GLPI server failed : {error}")
|
logger.critical(f"Connection to GLPI server failed : {error}")
|
||||||
@@ -196,7 +185,7 @@ if(searchFilter != None):
|
|||||||
if(searchFilter == 'Id'):
|
if(searchFilter == 'Id'):
|
||||||
devices = [device for device in devices if getattr(device, "Id") == searchValue]
|
devices = [device for device in devices if getattr(device, "Id") == searchValue]
|
||||||
else:
|
else:
|
||||||
devices = [device for device in devices if getattr(device, searchFilter) == searchValue]
|
devices = [device for device in devices if getattr(device, "searchFilter") == searchValue]
|
||||||
|
|
||||||
for device in devices:
|
for device in devices:
|
||||||
if(device.EnrollmentStatus != 'Enrolled'):
|
if(device.EnrollmentStatus != 'Enrolled'):
|
||||||
@@ -209,13 +198,13 @@ for device in devices:
|
|||||||
|
|
||||||
logger.info(f"Searching device {device.FriendlyName} (Airwatch id={device.Id}) on GLPI")
|
logger.info(f"Searching device {device.FriendlyName} (Airwatch id={device.Id}) on GLPI")
|
||||||
|
|
||||||
deviceID, data, count = glpiapi.GetComputers(airwatchDevice=device)
|
deviceID, data, count = glpiapi.GetDevice(device)
|
||||||
apps = airwatch.GetDeviceApps(device)
|
apps = airwatch.GetDeviceApps(device)
|
||||||
if(count > 1):
|
if(count > 1):
|
||||||
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.GetComputers(device)
|
deviceIDTrash, dataTrash, countTrash = glpiapi.GetDevice(device, trashbin=True)
|
||||||
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):
|
||||||
@@ -227,18 +216,11 @@ 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"]
|
||||||
osVersion = inventory.operatingsystem["version"]
|
if(device.FriendlyName != f"{data['1']} {platformName} {device.OS} - {device.User}"):
|
||||||
if(device.FriendlyName != f"{data['1']} {platformName} {osVersion} - {device.User}"):
|
newFriendlyName = f"{data['1']} {platformName} {device.OS} - {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.SetCustomField(itemType="Computer", containerName="mdt", containerID=4, itemId=deviceID, fieldName="appareilsurmagentafield", data=airwatchlink)
|
|
||||||
|
|
||||||
|
|
||||||
# filtre des plateformes
|
# filtre des plateformes
|
||||||
if(platformFilterEnabled):
|
if(platformFilterEnabled):
|
||||||
if device.PlatformId in platformFilterOut:
|
if device.PlatformId in platformFilterOut:
|
||||||
@@ -248,12 +230,6 @@ 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.GetUsers(username=device.User)
|
|
||||||
if(userCount == 1):
|
|
||||||
logger.info(f"Updating user from {data['70']} to {device.User} in GLPI (id={deviceID})")
|
|
||||||
glpiapi.UpdateItemUser(deviceID, "Computer", 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
Normal file
39
start.sh
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/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