kurtcms.org

Thinking. Writing. Philosophising.

Email Github LinkedIn

API: Return the Round Trip Time (RTT), Jitter and Packet Loss to an IP or Hostname

Posted on March 3, 2022 — 6 Minutes Read

Despite the long history of Application Programming Interface (API) that was once used to describe different things, in an age of software-defined, container-based and on-demand application deployment in a microservice architecture, it has come to refer to that which allows one application to interact and communicate with the others. Each API has its own specification that adheres to a standard and the most popular of which in an age of web services is the Representational State Transfer (REST) framework that uses the HTTP protocol for data transfer in an IP network. Endpoints that are available for a call, along with the parameters of the request and of the response are well defined in the respective API specification. With the inner workings and intricacies of each application abstracted away by the API, new services that respond to emerging business needs can be rapidly developed and seamlessly integrated to the existing architecture by continuous integration/continuous delivery (CI/CD).

Building upon the FastAPI framework that taps into the lightweight and high-performance Asynchronous Server Gateway Interface (ASGI), Starlette, and the Python data validation module, Pydantic; and with the endpoints secured by Auth0 based on the JSON Web Key (JWK) specification (RFC 7517); this API returns the round trip time (RTT), jitter and packet loss to the specified IP address or hostname, given a validated Auth0 JSON Web Token (JWT, RFC 7519). Taking advantage of the modularity and scalability of containers, the API is orchestrated with Docker Compose for rapid and modular deployment that fits in any microservice architecture, and is shared on Github for reference and further development. With Docker Compose, deployment is as simple as:

  1. Download a copy of the API;
  2. Create the environment variables for retrieving the JSON Web Key Set (JWKS) from Auth0;
  3. Docker Compose to start the API.

NGINX is deployed for the web server, with Certbot by the Electronic Frontier Foundation (EFF) for obtaining and renewing a signed SSL/TLS certificate on a given root domain from Let’s Encrypt, a non-profit Certificate Authority by the Internet Security Research Group (ISRG).

A Bash script is imported to execute ping and to convert the output at runtime to comma separated values (CSV), for a subsequent computation with NumPy and pandas, of the descriptive statistics on the RTT measured. The source code of the Bash script is available in another Git repository.

Git Clone

Download a copy of the app with git clone. Be sure to pass the --recurse-submodules argument to initialise and update each submodule in the repository.

$ git clone --recurse-submodules https://github.com/kurtcms/pingapi /app/pingapi/

Permission

Provide the imported Bash script with execute permission.

$ chmod +x /app/pingapi/pingc/pingc.sh

Auth0 JWT

A JWT in the OAuth 2.0 Bearer Token schema (RFC 6750) is required to access the API.

Register an API with Auth0, and then retrieve an access token with the domain, the client ID, the client secret and the audience of the registered API.

$ curl --request POST \
    --url https://kurtcms.us.auth0.com/oauth/token \
    --header "content-type: application/json" \
    --data '{"client_id":"(redacted)","client_secret":"(redacted),"audience":"https://kurtcms.org/pingapi/","grant_type":"client_credentials"}'

Environment Variables

The API expects the domain, the issuer, the audience and the signing algorithm for retrieving the JWKS from Auth0, as environment variables in a .env file in the same directory.

Be sure to create the .env file.

$ nano /app/pingapi/.env

And define the variables accordingly.

# For retrieving the JSON Web Key Set (JWKS) from Auth0
AUTH0_DOMAIN = kurtcms.us.auth0.com
AUTH0_ISSUER = https://kurtcms.us.auth0.com/
AUTH0_AUDIENCE = https://kurtcms.org/pingapi/
AUTH0_ALGORITHMS = RS256

Docker Compose

With Docker Compose, the API may be provisioned with a single command.

Install

Install Docker and Docker Compose with the Bash script that comes with API.

$ chmod +x /app/pingapi/docker-compose/docker-compose.sh \
    && /app/pingapi/docker-compose/docker-compose.sh

SSL/TLS Certificate

A dummy SSL/TLS certificate and private key will need to be created for NGINX to start service, and for Certbot to subsequently obtain a signed SSL/TLS certificate from Let’s Encrypt by answering a HTTP-01 challenge.

Create the dummy certificate before obtaining a signed one with the Bash script that comes with API.

$ chmod +x /app/pingapi/certbot/certbot.sh \
    && /app/pingapi/certbot/certbot.sh

Enter the root domain and the email address for registration and recovery when prompted.

Up and Down

Start the containers with Docker Compose.

$ docker-compose -f /app/pingapi/docker-compose.yml up -d

Stopping the containers is as simple as a single command.

$ docker-compose -f /app/pingapi/docker-compose.yml down

API Specifications

Powered by Swagger UI, an OpenAPI, or formerly known as Swagger, specification is available at /docs. An alternative specification powered by Redoc is also available at /redoc.

Below are the endpoints available along with their corresponding parameters and responses.

GET /pingapi/[ip]?c=[int]

Return the RTT, jitter and packet loss to the given IP address or hostname in the specified duration as measured by ping at one ICMP datagram per second.

Duration must be greater than 0 and less than 60.

$ curl -X GET "https://kurtcms.org/pingapi/1.1.1.1?c=5" \
    -H "Authorization: Bearer (redacted)" \
    -i

Response

HTTP/1.1 200 OK
date: Thu, 24 Feb 2022 15:45:30 GMT
server: uvicorn
content-length: 167
content-type: application/json

{"date_time":"20220224154530","ip_host":"1.1.1.1","rtt_mean":2.56,"rtt_min":2.17,"rtt_max":3.62,"jitter":0.61,"count_requested":5,"count_received":5,"packet_loss":0.0}

POST /pingapi

Return the RTT, jitter and packet loss to the given IP address or hostname in the specified duration as measured by ping at one ICMP datagram per second.

Duration must be greater than 0 and less than 60.

$ curl -X POST "https://kurtcms.org/pingapi/" \
    -H "Authorization: Bearer (redacted)" \
    -H "Content-Type: application/json" \
    -d '{"ip":"1.1.1.1","c":"5"}' \
    -i

Response

HTTP/1.1 200 OK
date: Thu, 24 Feb 2022 15:45:45 GMT
server: uvicorn
content-length: 167
content-type: application/json

{"date_time":"20220224154545","ip_host":"1.1.1.1","rtt_mean":2.61,"rtt_min":2.13,"rtt_max":3.82,"jitter":0.71,"count_requested":5,"count_received":5,"packet_loss":0.0}

SSL/TLS Certificate Renewal

Certbot is instructed by Docker Compose to attempt a SSL/TLS certificate renewal every 12 hours, which should be more than adequate considering the certificate is valid for 90 days.

NGINX is instructed to reload its configuration every 24 hours to ensure the renewed certificate will come into effect at most 12 hours after a renewal, which should also be well in advance of an impending expiry.

Edit the docker-compose.yml should these intervals need to be adjusted.

$ nano /app/pingapi/docker-compose.yml

Modify the values as appropriate.

  nginx:
    ...
    command: "/bin/sh -c 'while :; do sleep 24h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

  certbot:
    ...
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

Thoughts

Asynchronous coding (async) at the heart of FastAPI by the Python library, asyncio, allows the APIs built on top, to turn the wait time for a request to be sent back and forth, between the client and the server, into time that may be used to process the next request in the queue, and is most fitting for web services which has clients connecting and requesting resources from remote networks.