====== 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