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