====== WebAPI ====== Let's try to make a quick win. We have to make a Proof Of Concept about something and writing a Web RestFul API is a good candidate. ===== Request ===== All Windows laptops in your company are supposed to execute a script every day. However you have a lot of tickets that may be explained by the fact that this daily script is not executed or too long and raises a kind of timeout. Your idea is to log when the script starts and when it ends. A good one! However you have no idea how to quickly centralize these log files from all laptops. Why not a Web RestFul API? :-) Before going further: yes I know that a lot of solutions may solve this issue but the target is to make the POC in less than one hour. As I used to develop Web Restful API then it is my choice. ===== Architecture ===== {{ :en:python:web-api.png?600 |Architecture WebAPI}} {{ :en:python:web-api.dia |Source DIA}} ===== Client side ===== From client side, we are going to use Powershell command as it is native to 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 API returns something like this: 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 If you are running linux laptop you can adapt the script with curl. 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"} ===== Server side ===== ==== Run it ==== 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