Skip to content

Commit

Permalink
Merge branch 'pythonTraffic' into main_instrument
Browse files Browse the repository at this point in the history
  • Loading branch information
zzhlogin committed Jan 26, 2024
2 parents 83fa7b6 + fd93b31 commit ea5e681
Show file tree
Hide file tree
Showing 10 changed files with 337 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
# SPDX-License-Identifier: Apache-2.0
import json
import os
import time

import requests
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed, HttpResponseNotFound
from django.views.decorators.csrf import csrf_exempt
from dotenv import load_dotenv
from MainService.models import Vehicle
Expand Down Expand Up @@ -40,14 +41,23 @@ def vehicle(request):

def get_vehicle_by_id(request, vehicle_id):
if request.method == "GET":
throttle_time = request.GET.get("throttle")
if throttle_time:
print("going to throttle for " + throttle_time + " seconds")
time.sleep(int(throttle_time))

vehicle_objects = Vehicle.objects.filter(id=vehicle_id).values()
if not vehicle_objects:
return HttpResponseNotFound("Vehicle with id=" + str(vehicle_id) + " is not found")
return HttpResponse(vehicle_objects)
return HttpResponseNotAllowed("Only GET requests are allowed!")


def get_vehicle_image(request, vehicle_id):
if request.method == "GET":
vehicle_object = Vehicle.objects.filter(id=vehicle_id).first()
if not vehicle_object:
return HttpResponseNotFound("Vehicle with id=" + str(vehicle_id) + " is not found")
image_name = getattr(vehicle_object, "image_name")
return HttpResponse(requests.get(get_image_endpoint() + "/images/name/" + image_name, timeout=10))
return HttpResponseNotAllowed("Only GET requests are allowed!")
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Use the official lightweight Node.js 16 image.
# https://hub.docker.com/_/node
FROM node:16-slim

# Create and change to the app directory.
WORKDIR /usr/src/app

# Copy application dependency manifests to the container image.
# A wildcard is used to ensure copying both package.json AND package-lock.json (if available).
# Copying this first prevents re-running npm install on every code change.
COPY package*.json ./

# Install production dependencies.
# If you have native dependencies, you'll need additional tools.
# For a full list of package.json changes, see:
# https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md
RUN npm install --only=production

# Copy local code to the container image.
COPY . .

# Run the web service on container startup.
CMD [ "node", "index.js" ]

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Random Traffic Generator
The traffic generator generates the following traffic:
1. Every minute, sends a single POST request to the VehicleInventoryApp and sends a single GET request.
2. Every hour, sends a burst of requests: 5 POST requests to the VehicleInventoryApp and 5 GET requests.
3. Every 5 minutes, sleeps for random amount of time between 30-60 seconds and then sends a GET request to the VehicleInventoryApp with a random throttle param between 5-20 seconds. The backend reads that throttle param and simulates throttling for that amount of time before responding to the request.
4. Every 5 minutes, sleeps for random amount of time between 30-60 seconds and then sends a GET request to the VehicleInventoryApp with an invalid car id to trigger 404 error.
5. Every 5 minutes, sleeps for random amount of time between 30-60 seconds and then sends a GET request to the ImageServiceApp with a non existent image name to trigger 500 error due to S3 Error: "An error occurred (NoSuchKey) when calling the GetObject operation: The specified key does not exist."

## Running locally
1. Run `npm install`
2. Run locally:
- If you are running against you applicaiton locally, just run `node index.js`. The default endpoint is `0.0.0.0:8000` for the ImageServiceApp and `0.0.0.0:8001` for VehicleInventoryApp.
- If you want to run against the application on EKS, before running the `node index.js`, run `export <EKS_URL>`.

## Deploying to EKS
Run `bash build.sh <account_id> <region>`. This does the following:
1. This will retrieve the endpoint from EKS ingress-nginx pod
2. Build docker image of the traffic
3. Push the docker image to ECR
4. Deploy the image to EKS

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
account=$1
region=$2

# Save the endpoint URL to a variable
endpoint=$(kubectl get svc -n ingress-nginx | grep "ingress-nginx" | awk '{print $4}')

# Print the endpoint
echo "Endpoint: $endpoint"

export REPOSITORY_PREFIX=${account}.dkr.ecr.${region}.amazonaws.com
aws ecr get-login-password --region ${region} | docker login --username AWS --password-stdin ${REPOSITORY_PREFIX}
aws ecr create-repository --repository-name random-traffic-generator --region ${region} || true
docker build -t random-traffic-generator:latest .
docker tag random-traffic-generator:latest ${REPOSITORY_PREFIX}/random-traffic-generator:latest
docker push ${REPOSITORY_PREFIX}/random-traffic-generator:latest

sed -e 's#\${REPOSITORY_PREFIX}'"#${REPOSITORY_PREFIX}#g" -e 's#\${URL}'"#$endpoint#g" deployment.yaml | kubectl apply -f -


Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: random-traffic-generator
labels:
app: random-traffic-generator
spec:
replicas: 1
selector:
matchLabels:
app: random-traffic-generator
template:
metadata:
labels:
app: random-traffic-generator
spec:
containers:
- name: random-traffic-generator
image: ${REPOSITORY_PREFIX}
env:
- name: URL
value: "${URL}"

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const axios = require('axios');
const cron = require('node-cron');

const imageUrl = process.env.URL ? `${process.env.URL}/images` : 'http://0.0.0.0:8000/images'
const vehicleURL = process.env.URL ? `${process.env.URL}/vehicle-inventory` : 'http://0.0.0.0:8001/vehicle-inventory'

function getRandomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}


function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

// sends two requests every minute, 1 POST request and 1 GET request
const postGetCarsTrafficTask = cron.schedule('* * * * *', async () => {
console.log('add 1 car every 1 minutes');
const carData = {"make": "BMW", "model": "M340", "year": 2022, "image_name": "newCar.jpg"}
axios.post(`${vehicleURL}/`, carData, { timeout: 10000 })
.catch(err => {
console.error(err.response && err.response.data);
});

// gets image from image service through the vehicle service
axios.get(`${vehicleURL}/1/image`, { timeout: 10000 })
.catch(err => {
console.error(err.response && err.response.data);
}); // Catch and log errors
}, { scheduled: false });
postGetCarsTrafficTask.start();

// sends a burst of traffic sending 10 requests every hour:
// 5 POST requests and 5 GET requests.
const postGetCarsTrafficBurstTask = cron.schedule('0 * * * *', async () => {
console.log('add 5 cars within 1 minutes');
const carData = {"make": "BMW", "model": "M340", "year": 2022, "image_name": "newCar.jpg"}
for (let i = 0; i < 5; i++) {
axios.post(`${vehicleURL}/`, carData, { timeout: 10000 })
.catch(err => {
console.error(err.response && err.response.data);
}); // Catch and log errors

// gets image from image service through the vehicle service
axios.get(`${vehicleURL}/1/image`, { timeout: 10000 })
.catch(err => {
console.error(err.response && err.response.data);
}); // Catch and log errors
}
}, { scheduled: false });
postGetCarsTrafficBurstTask.start();

// sends a GET request with custom throttle parameter in the body that mimics being throttled. The throttle time
// is going to be random between 5 - 20 secs.
const getCarThrottle = cron.schedule('*/5 * * * *', async () => {
sleepSecs = getRandomNumber(30,60);
console.log(`sleep ${sleepSecs} seconds`);
await sleep(sleepSecs*1000);
throttleSecs = getRandomNumber(5,20);
console.log(`request will be throttled for ${throttleSecs} seconds`)
axios.get(`${vehicleURL}/1`, {params: {"throttle": 5}}, { timeout: 10000 })
.catch(err => {
console.error(err.response && err.response.data);
}); // Catch and log errors
}, { scheduled: false });
getCarThrottle.start();

// sends an invalid GET request with a non existent car id to trigger 404 error
const getInvalidRequest = cron.schedule('*/5 * * * *', async () => {
sleepSecs = getRandomNumber(30,120);
console.log(`sleep ${sleepSecs} seconds`);
await sleep(sleepSecs*1000);
console.log("getting non existent car to trigger 404");
axios.get(`${vehicleURL}/123456789`, { timeout: 10000 })
.catch(err => {
console.error(err.response && err.response.data);
}); // Catch and log errors
}, { scheduled: false });
getInvalidRequest.start();

// sends an invalid GET request with a non existent image name to trigger 500 error due to S3 Error:
// "An error occurred (NoSuchKey) when calling the GetObject operation: The specified key does not exist."
const getNonExistentImage = cron.schedule('*/5 * * * *', async () => {
sleepSecs = getRandomNumber(30,120);
console.log(`sleep ${sleepSecs} seconds`);
await sleep(sleepSecs*1000);
console.log('get an non existent image to trigger aws error');
axios.get(`${imageUrl}/name/doesnotexist.jpeg`)
.catch(err => {
console.error(err.response && err.response.data);
}); // Catch and log errors
}, { scheduled: false });
getNonExistentImage.start();

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "random-traffic-generator",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.4.0",
"node-cron": "^3.0.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

REGION=${2:-"us-east-1"}
REGION=${1:-"us-east-1"}

aws ecr get-login-password --region ${REGION} | docker login --username AWS --password-stdin ${REPOSITORY_PREFIX}

Expand Down

0 comments on commit ea5e681

Please sign in to comment.