-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
*Issue description:* This is a part of four series of PR to remove public endpoints for E2E testing to comply with security best practices. - [Deploy Traffic Generator](#140) - [Remove Public Endpoints from K8s](#141) - [Remove Public Endpoints from EKS](#139) - [Remove Public Endpoints from EC2](#144) Since the public endpoints will be removed, we are unable to call the sample app APIs directly from the workflow. Therefore, we will be using a traffic generator that is installed alongside the sample app applications to call the APIs This PR will be responsible for creating the traffic generator as well as saving them to private ECR and S3 bucket. The private ECR will be used by EKS and K8s platform while the S3 bucket will be used by EC2 Platforms. The traffic generator will first wait while it receives the appropriate environment variable. Once that is received, it will ping the API endpoints every minute. There is some additional logic depending on which canary it is running for. Test run: https://github.com/aws-observability/aws-application-signals-test-framework/actions/runs/10118562925 Test run after comment: https://github.com/aws-observability/aws-application-signals-test-framework/actions/runs/10148623963 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
- Loading branch information
Showing
4 changed files
with
206 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# This workflow will build and push the traffic generator to each region whenever there is an update made to the traffic-generator folder. | ||
# This image will be used by EKS and K8s test to call sample app endpoints while the zip files will be used by EC2 Platforms | ||
name: Create and Push Traffic Generator | ||
|
||
on: | ||
workflow_dispatch: | ||
push: | ||
branches: | ||
- main | ||
paths: | ||
- 'sample-apps/traffic-generator/**' | ||
|
||
permissions: | ||
id-token: write | ||
contents: read | ||
|
||
env: | ||
E2E_TEST_ACCOUNT_ID: ${{ secrets.APPLICATION_SIGNALS_E2E_TEST_ACCOUNT_ID }} | ||
E2E_TEST_ROLE_NAME: ${{ secrets.APPLICATION_SIGNALS_E2E_TEST_ROLE_NAME }} | ||
|
||
jobs: | ||
build-and-push-image: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
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', | ||
'ap-southeast-2','ap-southeast-3','ap-southeast-4','ca-central-1','eu-central-1','eu-central-2','eu-north-1', | ||
'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', | ||
'us-east-1','us-east-2', 'us-west-1', 'us-west-2'] | ||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Configure AWS Credentials | ||
uses: aws-actions/configure-aws-credentials@v4 | ||
with: | ||
role-to-assume: arn:aws:iam::${{ env.E2E_TEST_ACCOUNT_ID }}:role/${{ env.E2E_TEST_ROLE_NAME }} | ||
aws-region: us-east-1 | ||
|
||
- name: Retrieve account | ||
uses: aws-actions/aws-secretsmanager-get-secrets@v1 | ||
with: | ||
secret-ids: | | ||
ACCOUNT_ID, region-account/${{ matrix.aws-region }} | ||
- name: Configure AWS Credentials | ||
uses: aws-actions/configure-aws-credentials@v4 | ||
with: | ||
role-to-assume: arn:aws:iam::${{ env.ACCOUNT_ID }}:role/${{ env.E2E_TEST_ROLE_NAME }} | ||
aws-region: ${{ matrix.aws-region }} | ||
|
||
- name: Login to Amazon ECR | ||
id: login-ecr | ||
uses: aws-actions/amazon-ecr-login@v2 | ||
|
||
- name: Build, tag, and push image to Amazon ECR | ||
working-directory: sample-apps/traffic-generator | ||
env: | ||
REGISTRY: ${{ steps.login-ecr.outputs.registry }} | ||
REPOSITORY: e2e-test-resource | ||
IMAGE_TAG: traffic-generator | ||
run: | | ||
docker build -t $REGISTRY/$REPOSITORY:$IMAGE_TAG . | ||
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG | ||
upload-files-to-s3: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
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', | ||
'ap-southeast-2','ap-southeast-3','ap-southeast-4','ca-central-1','eu-central-1','eu-central-2','eu-north-1', | ||
'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', | ||
'us-east-1','us-east-2', 'us-west-1', 'us-west-2'] | ||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Configure AWS Credentials | ||
uses: aws-actions/configure-aws-credentials@v4 | ||
with: | ||
role-to-assume: arn:aws:iam::${{ env.E2E_TEST_ACCOUNT_ID }}:role/${{ env.E2E_TEST_ROLE_NAME }} | ||
aws-region: us-east-1 | ||
|
||
- name: Retrieve account | ||
uses: aws-actions/aws-secretsmanager-get-secrets@v1 | ||
with: | ||
secret-ids: | | ||
ACCOUNT_ID, region-account/${{ matrix.aws-region }} | ||
- name: Configure AWS Credentials | ||
uses: aws-actions/configure-aws-credentials@v4 | ||
with: | ||
role-to-assume: arn:aws:iam::${{ env.ACCOUNT_ID }}:role/${{ env.E2E_TEST_ROLE_NAME }} | ||
aws-region: ${{ matrix.aws-region }} | ||
|
||
- name: Upload traffic generator files | ||
working-directory: sample-apps/traffic-generator | ||
run: | | ||
zip traffic-generator.zip ./index.js ./package.json | ||
aws s3 cp traffic-generator.zip s3://aws-appsignals-sample-app-prod-${{ matrix.aws-region }}/traffic-generator.zip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Use the official lightweight Node.js 16 image. | ||
# https://hub.docker.com/_/node | ||
# FROM node:16-slim | ||
FROM public.ecr.aws/eks-distro-build-tooling/nodejs:16 | ||
|
||
# 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 dependencies | ||
RUN npm install | ||
|
||
# Copy local code to the container image. | ||
COPY . . | ||
|
||
# Run the web service on container startup. | ||
CMD [ "npm", "start" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
const axios = require('axios'); | ||
|
||
// Send API requests to the sample app | ||
const sendRequests = async (urls) => { | ||
try { | ||
const fetchPromises = urls.map(url => axios.get(url)); | ||
const responses = await Promise.all(fetchPromises); | ||
|
||
// Handle the responses | ||
responses.forEach((response, index) => { | ||
if (response.status === 200) { | ||
const data = response.data; | ||
console.log(`Response from ${urls[index]}:`, data); | ||
} else { | ||
console.error(`Failed to fetch ${urls[index]}:`, response.statusText); | ||
} | ||
}); | ||
} catch (error) { | ||
console.error('Error sending GET requests:', error); | ||
} | ||
} | ||
|
||
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); | ||
|
||
// This loop will run until the environment variables are available | ||
const waitForEnvVariables = async () => { | ||
while (!process.env.MAIN_ENDPOINT || !process.env.REMOTE_ENDPOINT || !process.env.ID || !process.env.CANARY_TYPE) { | ||
console.log('Environment variables not set. Waiting for 10 seconds...'); | ||
await sleep(10000); // Wait for 10 seconds | ||
} | ||
}; | ||
|
||
// Traffic generator that sends traffic every specified interval. Send request immediately then every 2 minutes afterwords | ||
const trafficGenerator = async (interval) => { | ||
await waitForEnvVariables(); | ||
|
||
const mainEndpoint = process.env.MAIN_ENDPOINT; | ||
const remoteEndpoint = process.env.REMOTE_ENDPOINT; | ||
const id = process.env.ID; | ||
const canaryType = process.env.CANARY_TYPE | ||
|
||
let urls = [ | ||
`http://${mainEndpoint}/outgoing-http-call`, | ||
`http://${mainEndpoint}/aws-sdk-call?ip=${remoteEndpoint}&testingId=${id}`, | ||
`http://${mainEndpoint}/remote-service?ip=${remoteEndpoint}&testingId=${id}`, | ||
`http://${mainEndpoint}/client-call` | ||
]; | ||
|
||
if (canaryType === 'java-eks' || canaryType === 'python-eks') { | ||
urls.push(`http://${mainEndpoint}/mysql`) | ||
} | ||
|
||
// Need to call some APIs so that it exceeds the metric limiter threshold and make the test | ||
// APIs generate AllOtherOperations metric. Sleep for a minute to let cloudwatch service process the API call | ||
// Calling it here before calling the remote sample app endpoint because the API generated by it is validated | ||
// for AllOtherRemoteOperations in the metric validation step | ||
if (canaryType === 'java-metric-limiter'){ | ||
const fakeUrls = [ | ||
`http://${mainEndpoint}`, | ||
`http://${mainEndpoint}/fake-endpoint` | ||
] | ||
// Send the fake requests and wait a minute | ||
await sendRequests(fakeUrls); | ||
await sleep(60000); | ||
} | ||
|
||
await sendRequests(urls); | ||
setInterval(() => sendRequests(urls), interval); | ||
} | ||
|
||
const interval = 60 * 1000; | ||
// Start sending GET requests every minute (60,000 milliseconds) | ||
trafficGenerator(interval); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"name": "traffic-generator", | ||
"version": "1.0.0", | ||
"description": "A simple traffic generator that sends GET requests to a list of URLs every 2 minutes", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "node index.js" | ||
}, | ||
"dependencies": { | ||
"axios": "^1.4.0" | ||
} | ||
} |