Table of Contents

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

Architecture WebAPI

Source DIA

Client side

From client side, we are going to use Powershell command as it is native to 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

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

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