Skip to content

Commit 365f88d

Browse files
committed
Deploy Traffic Generator
1 parent 8cdc51d commit 365f88d

File tree

4 files changed

+206
-0
lines changed

4 files changed

+206
-0
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# This workflow will build and the traffic generator image to each region whenever there is an update made to the traffic-generator folder.
2+
# This image will be used by EKS and K8s test to call sample app endpoints
3+
name: Create and Push Traffic Generator Image
4+
5+
on:
6+
workflow_dispatch:
7+
push:
8+
branches:
9+
- main
10+
paths:
11+
- 'traffic-generator/**'
12+
13+
permissions:
14+
id-token: write
15+
contents: read
16+
17+
env:
18+
E2E_TEST_ACCOUNT_ID: ${{ secrets.APPLICATION_SIGNALS_E2E_TEST_ACCOUNT_ID }}
19+
E2E_TEST_ROLE_NAME: ${{ secrets.APPLICATION_SIGNALS_E2E_TEST_ROLE_NAME }}
20+
21+
jobs:
22+
build-and-push-image:
23+
runs-on: ubuntu-latest
24+
strategy:
25+
matrix:
26+
aws-region: ['af-south-1','ap-east-1','ap-northeast-1','ap-northeast-2','ap-northeast-3','ap-south-1','ap-south-2','ap-southeast-1',
27+
'ap-southeast-2','ap-southeast-3','ap-southeast-4','ca-central-1','eu-central-1','eu-central-2','eu-north-1',
28+
'eu-south-1','eu-south-2','eu-west-1','eu-west-2','eu-west-3','il-central-1','me-central-1','me-south-1', 'sa-east-1',
29+
'us-east-1','us-east-2', 'us-west-1', 'us-west-2']
30+
steps:
31+
- name: Checkout repository
32+
uses: actions/checkout@v4
33+
34+
- name: Configure AWS Credentials
35+
uses: aws-actions/configure-aws-credentials@v4
36+
with:
37+
role-to-assume: arn:aws:iam::${{ env.E2E_TEST_ACCOUNT_ID }}:role/${{ env.E2E_TEST_ROLE_NAME }}
38+
aws-region: us-east-1
39+
40+
- name: Retrieve account
41+
uses: aws-actions/aws-secretsmanager-get-secrets@v1
42+
with:
43+
secret-ids: |
44+
ACCOUNT_ID, region-account/${{ matrix.aws-region }}
45+
46+
- name: Configure AWS Credentials
47+
uses: aws-actions/configure-aws-credentials@v4
48+
with:
49+
role-to-assume: arn:aws:iam::${{ env.ACCOUNT_ID }}:role/${{ env.E2E_TEST_ROLE_NAME }}
50+
aws-region: ${{ matrix.aws-region }}
51+
52+
- name: Login to Amazon ECR
53+
id: login-ecr
54+
uses: aws-actions/amazon-ecr-login@v2
55+
56+
- name: Build, tag, and push image to Amazon ECR
57+
working-directory: traffic-generator
58+
env:
59+
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
60+
REPOSITORY: e2e-test-resource
61+
IMAGE_TAG: traffic-generator
62+
run: |
63+
docker build -t $REGISTRY/$REPOSITORY:$IMAGE_TAG .
64+
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
65+
66+
upload-files:
67+
runs-on: ubuntu-latest
68+
strategy:
69+
matrix:
70+
aws-region: ['af-south-1','ap-east-1','ap-northeast-1','ap-northeast-2','ap-northeast-3','ap-south-1','ap-south-2','ap-southeast-1',
71+
'ap-southeast-2','ap-southeast-3','ap-southeast-4','ca-central-1','eu-central-1','eu-central-2','eu-north-1',
72+
'eu-south-1','eu-south-2','eu-west-1','eu-west-2','eu-west-3','il-central-1','me-central-1','me-south-1', 'sa-east-1',
73+
'us-east-1','us-east-2', 'us-west-1', 'us-west-2']
74+
steps:
75+
- name: Checkout repository
76+
uses: actions/checkout@v4
77+
78+
- name: Configure AWS Credentials
79+
uses: aws-actions/configure-aws-credentials@v4
80+
with:
81+
role-to-assume: arn:aws:iam::${{ env.E2E_TEST_ACCOUNT_ID }}:role/${{ env.E2E_TEST_ROLE_NAME }}
82+
aws-region: us-east-1
83+
84+
- name: Retrieve account
85+
uses: aws-actions/aws-secretsmanager-get-secrets@v1
86+
with:
87+
secret-ids: |
88+
ACCOUNT_ID, region-account/${{ matrix.aws-region }}
89+
90+
- name: Configure AWS Credentials
91+
uses: aws-actions/configure-aws-credentials@v4
92+
with:
93+
role-to-assume: arn:aws:iam::${{ env.ACCOUNT_ID }}:role/${{ env.E2E_TEST_ROLE_NAME }}
94+
aws-region: ${{ matrix.aws-region }}
95+
96+
- name: Upload traffic generator files
97+
working-directory: traffic-generator
98+
run: |
99+
zip traffic-generator.zip ./index.js ./package.json
100+
aws s3 cp traffic-generator.zip s3://aws-appsignals-sample-app-prod-${{ matrix.aws-region }}/traffic-generator.zip

traffic-generator/Dockerfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Use the official lightweight Node.js 16 image.
2+
# https://hub.docker.com/_/node
3+
# FROM node:16-slim
4+
FROM public.ecr.aws/eks-distro-build-tooling/nodejs:16
5+
6+
# Create and change to the app directory
7+
WORKDIR /usr/src/app
8+
9+
# Copy application dependency manifests to the container image.
10+
# A wildcard is used to ensure copying both package.json AND package-lock.json (if available).
11+
# Copying this first prevents re-running npm install on every code change.
12+
COPY package*.json ./
13+
14+
# Install dependencies
15+
RUN npm install
16+
17+
# Copy local code to the container image.
18+
COPY . .
19+
20+
# Run the web service on container startup.
21+
CMD [ "npm", "start" ]

traffic-generator/index.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
const axios = require('axios');
2+
3+
// Send API requests to the sample app
4+
const sendRequests = async (urls) => {
5+
try {
6+
const fetchPromises = urls.map(url => axios.get(url));
7+
const responses = await Promise.all(fetchPromises);
8+
9+
// Handle the responses
10+
responses.forEach((response, index) => {
11+
if (response.status === 200) {
12+
const data = response.data;
13+
console.log(`Response from ${urls[index]}:`, data);
14+
} else {
15+
console.error(`Failed to fetch ${urls[index]}:`, response.statusText);
16+
}
17+
});
18+
} catch (error) {
19+
console.error('Error sending GET requests:', error);
20+
}
21+
}
22+
23+
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
24+
25+
// This loop will run until the environment variables are available
26+
const waitForEnvVariables = async () => {
27+
while (!process.env.MAIN_ENDPOINT || !process.env.REMOTE_ENDPOINT || !process.env.ID || !process.env.CANARY_TYPE) {
28+
console.log('Environment variables not set. Waiting for 10 seconds...');
29+
await sleep(10000); // Wait for 10 seconds
30+
}
31+
};
32+
33+
// Traffic generator that sends traffic every specified interval. Send request immediately then every 2 minutes afterwords
34+
const trafficGenerator = async (interval) => {
35+
await waitForEnvVariables();
36+
37+
const mainEndpoint = process.env.MAIN_ENDPOINT;
38+
const remoteEndpoint = process.env.REMOTE_ENDPOINT;
39+
const id = process.env.ID;
40+
const canaryType = process.env.CANARY_TYPE
41+
42+
let urls = [
43+
`http://${mainEndpoint}/outgoing-http-call`,
44+
`http://${mainEndpoint}/aws-sdk-call?ip=${remoteEndpoint}&testingId=${id}`,
45+
`http://${mainEndpoint}/remote-service?ip=${remoteEndpoint}&testingId=${id}`,
46+
`http://${mainEndpoint}/client-call`
47+
];
48+
49+
if (canaryType === 'java-eks' || canaryType === 'python-eks') {
50+
urls.push(`http://${mainEndpoint}/mysql`)
51+
}
52+
53+
// Need to call some APIs so that it exceeds the metric limiter threshold and make the test
54+
// APIs generate AllOtherOperations metric. Sleep for a minute to let cloudwatch service process the API call
55+
// Calling it here before calling the remote sample app endpoint because the API generated by it is validated
56+
// for AllOtherRemoteOperations in the metric validation step
57+
if (canaryType === 'java-metric-limiter'){
58+
const fakeUrls = [
59+
`http://${mainEndpoint}`,
60+
`http://${mainEndpoint}/fake-endpoint`
61+
]
62+
// Send the fake requests and wait a minute
63+
await sendRequests(fakeUrls);
64+
await sleep(60000);
65+
}
66+
67+
await sendRequests(urls);
68+
setInterval(() => sendRequests(urls), interval);
69+
}
70+
71+
const interval = 60 * 1000;
72+
// Start sending GET requests every minute (60,000 milliseconds)
73+
trafficGenerator(interval);

traffic-generator/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "traffic-generator",
3+
"version": "1.0.0",
4+
"description": "A simple traffic generator that sends GET requests to a list of URLs every 2 minutes",
5+
"main": "index.js",
6+
"scripts": {
7+
"start": "node index.js"
8+
},
9+
"dependencies": {
10+
"axios": "^1.4.0"
11+
}
12+
}

0 commit comments

Comments
 (0)