====== WebAPI ====== Faisons un //quick win//. On souhaite réaliser un POC ((Preuve de concept)) à 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 ===== {{ :en:python:web-api.png?600 |Architecture WebAPI}} {{ :en:python:web-api.dia |Source DIA}} ===== 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. # 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 ==== 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 ==== from api import app if __name__ == "__main__": app.run() ==== API ==== 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///' ) if __name__ == '__main__': app.run(debug=True, host="0.0.0.0") ==== Requirements ==== flake8 flask_restful gunicorn