Table des matières
WebAPI
Faisons un quick win. On souhaite réaliser un POC 1) à propos d'une requête et pour cela on va réaliser une API Web RestFul.
Requête
Tous les laptops Windows de l'entreprise sont supposés exécuter un script tous les jours. Cependant on a une tonne de tickets qui peuvent être expliqués par le fait que le script n'est pas exécuté ou bien qu'il lève une sorte de timeout.
L'idée est de logguer quelque part le moment où le script commence et finit. L'idée est bonne mais on n'a aucune idée de commencer centraliser les logs de tous les laptops. Alors pourquoi pas une API Web RestFul ?
Avant d'aller plus loin: oui je sais qu'il existe une multitude de solutions à ce problème mais la cible est surtout de faire un POC en moins d'une heure. Comme j'avais l'habitude de faire des API, c'est mon choix .
Architecture
Côté client
From client side, we are going to use Powershell command as it is native to Windows 10.
Du côté client, on va utiliser un script Powershell comme c'est natif sur Windows 10.
- client_side.ps1
# init $who=whoami $computer=hostname $server="my-server.domain.com" # before the main command, let's call the API Invoke-WebRequest ("http://{2}:5000/my_command/start/{0}/{1}" -f ($who -replace "\\", "@"), $computer, $server) -Method POST # main command my_action # after the main command, let's call the API Invoke-WebRequest ("http://{2}:5000/my_command/end/{0}/{1}" -f ($who -replace "\\", "@"), $computer, $server) -Method POST
L'API retourne quelque chose comme cela:
StatusCode : 201 StatusDescription : Created Content : {"user": "my_user", "action": "start", "ip_remote": "0.1.2.3", "computer": "my_computer"} RawContent : HTTP/1.1 201 Created Connection: close Content-Length: 115 Content-Type: application/json Date: Tue, 26 May 2020 13:46:28 GMT Server: gunicorn/20.0.4 {"user": "my_user", "action": "star... Forms : {} Headers : {[Connection, close], [Content-Length, 115], [Content-Type, application/json], [Date, Tue, 26 May 2020 13:46:28 GMT]...} Images : {} InputFields : {} Links : {} ParsedHtml : mshtml.HTMLDocumentClass RawContentLength : 115
Si on voulait adapter le script sur un environnement Linux, on pourrait partir sur quelque chose comme cela:
curl -i -XPOST --silent http://localhost:5000/my_command/start/toto/computer HTTP/1.1 201 CREATED Server: gunicorn Date: Fri, 16 Apr 2021 03:07:27 GMT Connection: close Content-Type: application/json Content-Length: 86 {"user": "toto", "action": "start", "ip_remote": "127.0.0.1", "computer": "computer"}
Côté Serveur
Lancement
python3 -m venv venv source venv/bin/activate pip install -r requirements.txt gunicorn --bind 0.0.0.0:5000 wsgi:app
Logger
- logger.py
import logging logger = logging.getLogger('api') logger.setLevel(logging.DEBUG) # create file handler which logs even debug messages fh = logging.FileHandler('api.log') fh.setLevel(logging.INFO) # create console handler with a higher log level ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) # create formatter and add it to the handlers formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) ch.setFormatter(formatter) fh.setFormatter(formatter) # add the handlers to logger logger.addHandler(ch) logger.addHandler(fh)
WSGI
- wsgi.py
from api import app if __name__ == "__main__": app.run()
API
- api.py
from flask import Flask, request from flask_restful import Resource, Api from logger import logger app = Flask(__name__) api = Api(app) class HelloWorld(Resource): def post(self, user, action, computer): logger.info(f"{computer},{action},{user},{request.remote_addr}") return { "user": user, "action": action, "ip_remote": request.remote_addr, "computer": computer } api.add_resource( HelloWorld, '/my_command/<string:action>/<string:user>/<string:computer>' ) if __name__ == '__main__': app.run(debug=True, host="0.0.0.0")
Requirements
- requirements.txt
flake8 flask_restful gunicorn