Skip to content

Commit eba5b3c

Browse files
authored
Add Python E2E tests. (#45)
Add python E2E tests.
1 parent 296d7a9 commit eba5b3c

4 files changed

+696
-0
lines changed
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
## SPDX-License-Identifier: Apache-2.0
3+
4+
# This is a reusable workflow for running the Python E2E Canary test for Application Signals.
5+
# It is meant to be called from another workflow.
6+
# Read more about reusable workflows: https://docs.github.com/en/actions/using-workflows/reusing-workflows#overview
7+
name: Application Signals Enablement E2E Testing - Python EC2 Use Case
8+
on:
9+
workflow_call:
10+
inputs:
11+
aws-region:
12+
required: true
13+
type: string
14+
staging_wheel_name:
15+
required: false
16+
default: 'aws-opentelemetry-distro'
17+
type: string
18+
caller-workflow-name:
19+
required: true
20+
type: string
21+
22+
permissions:
23+
id-token: write
24+
contents: read
25+
26+
env:
27+
SAMPLE_APP_ZIP: s3://${{ secrets.APP_SIGNALS_E2E_EC2_JAR }}-prod-${{ inputs.aws-region }}/python-sample-app.zip
28+
METRIC_NAMESPACE: AppSignals
29+
LOG_GROUP_NAME: /aws/appsignals/generic
30+
ADOT_WHEEL_NAME: ${{ inputs.staging_wheel_name }}
31+
TEST_RESOURCES_FOLDER: ${GITHUB_WORKSPACE}
32+
GET_CW_AGENT_RPM_COMMAND: "wget -O cw-agent.rpm https://amazoncloudwatch-agent-${{ inputs.aws-region }}.s3.${{ inputs.aws-region }}.amazonaws.com/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm"
33+
34+
jobs:
35+
python-e2e-ec2-test:
36+
runs-on: ubuntu-latest
37+
container:
38+
image: public.ecr.aws/h6o3z5z9/aws-application-signals-test-framework-workflow-container:latest
39+
steps:
40+
- uses: actions/checkout@v4
41+
with:
42+
fetch-depth: 0
43+
44+
- name: Generate testing id
45+
run: echo TESTING_ID="${{ github.job }}-${{ env.AWS_DEFAULT_REGION }}-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}" >> $GITHUB_ENV
46+
47+
- name: Configure AWS Credentials
48+
uses: aws-actions/configure-aws-credentials@v4
49+
with:
50+
role-to-assume: ${{ secrets.E2E_SECRET_TEST_ROLE_ARN }}
51+
aws-region: us-east-1
52+
53+
- name: Retrieve account
54+
uses: aws-actions/aws-secretsmanager-get-secrets@v1
55+
with:
56+
secret-ids:
57+
ACCOUNT_ID, region-account/${{ inputs.aws-region }}
58+
59+
- name: Configure AWS Credentials
60+
uses: aws-actions/configure-aws-credentials@v4
61+
with:
62+
role-to-assume: arn:aws:iam::${{ env.ACCOUNT_ID }}:role/${{ secrets.E2E_TEST_ROLE_ARN }}
63+
aws-region: ${{ inputs.aws-region }}
64+
65+
- uses: actions/download-artifact@v3
66+
if: inputs.caller-workflow-name == 'main-build'
67+
with:
68+
name: ${{ inputs.staging_wheel_name }}
69+
70+
- name: Upload main-build adot.whl to s3
71+
if: inputs.caller-workflow-name == 'main-build'
72+
run: aws s3 cp ${{ inputs.staging_wheel_name }} s3://adot-main-build-staging-jar/${{ env.ADOT_WHEEL_NAME }}
73+
74+
- name: Set Get ADOT Wheel command environment variable
75+
working-directory: terraform/python/ec2
76+
run: |
77+
if [ ${{ inputs.caller-workflow-name }} == "main-build" ]; then
78+
# Reusing the adot-main-build-staging-jar bucket to store the python wheel file
79+
echo GET_ADOT_WHEEL_COMMAND="aws s3 cp s3://adot-main-build-staging-jar/${{ env.ADOT_WHEEL_NAME }} ./${{ env.ADOT_WHEEL_NAME }} && python3.9 -m pip install ${{ env.ADOT_WHEEL_NAME }}" >> $GITHUB_ENV
80+
else
81+
echo GET_ADOT_WHEEL_COMMAND="python3.9 -m pip install aws-opentelemetry-distro" >> $GITHUB_ENV
82+
fi
83+
84+
- name: Initiate Terraform
85+
uses: ./.github/workflows/actions/execute_and_retry
86+
with:
87+
command: "cd ${{ env.TEST_RESOURCES_FOLDER }}/terraform/python/ec2 && terraform init && terraform validate"
88+
cleanup: "rm -rf .terraform && rm -rf .terraform.lock.hcl"
89+
90+
- name: Deploy sample app via terraform and wait for endpoint to come online
91+
working-directory: terraform/python/ec2
92+
run: |
93+
# Attempt to deploy the sample app on an EC2 instance and wait for its endpoint to come online.
94+
# There may be occasional failures due to transitivity issues, so try up to 2 times.
95+
# deployment_failed of 0 indicates that both the terraform deployment and the endpoint are running, while 1 indicates
96+
# that it failed at some point
97+
retry_counter=0
98+
max_retry=2
99+
while [ $retry_counter -lt $max_retry ]; do
100+
echo "Attempt $retry_counter"
101+
deployment_failed=0
102+
terraform apply -auto-approve \
103+
-var="aws_region=${{ inputs.aws-region }}" \
104+
-var="test_id=${{ env.TESTING_ID }}" \
105+
-var="sample_app_zip=${{ env.SAMPLE_APP_ZIP }}" \
106+
-var="get_cw_agent_rpm_command=${{ env.GET_CW_AGENT_RPM_COMMAND }}" \
107+
-var="get_adot_wheel_command=${{ env.GET_ADOT_WHEEL_COMMAND }}" \
108+
|| deployment_failed=$?
109+
110+
if [ $deployment_failed -eq 1 ]; then
111+
echo "Terraform deployment was unsuccessful. Will attempt to retry deployment."
112+
fi
113+
114+
# If the deployment_failed is still 0, then the terraform deployment succeeded and now try to connect to the endpoint.
115+
# Attempts to connect will be made for up to 10 minutes
116+
if [ $deployment_failed -eq 0 ]; then
117+
echo "Attempting to connect to the endpoint"
118+
sample_app_endpoint=http://$(terraform output sample_app_main_service_public_dns):8000
119+
attempt_counter=0
120+
max_attempts=60
121+
until $(curl --output /dev/null --silent --head --fail $(echo "$sample_app_endpoint" | tr -d '"')); do
122+
if [ ${attempt_counter} -eq ${max_attempts} ];then
123+
echo "Failed to connect to endpoint. Will attempt to redeploy sample app."
124+
deployment_failed=1
125+
break
126+
fi
127+
128+
printf '.'
129+
attempt_counter=$(($attempt_counter+1))
130+
sleep 10
131+
done
132+
fi
133+
134+
# If the success is 1 then either the terraform deployment or the endpoint connection failed, so first destroy the
135+
# resources created from terraform and try again.
136+
if [ $deployment_failed -eq 1 ]; then
137+
echo "Destroying terraform"
138+
terraform destroy -auto-approve \
139+
-var="test_id=${{ env.TESTING_ID }}"
140+
141+
retry_counter=$(($retry_counter+1))
142+
else
143+
# If deployment succeeded, then exit the loop
144+
break
145+
fi
146+
147+
if [ $retry_counter -eq $max_retry ]; then
148+
echo "Max retry reached, failed to deploy terraform and connect to the endpoint. Exiting code"
149+
exit 1
150+
fi
151+
done
152+
153+
- name: Get the ec2 instance ami id
154+
run: |
155+
echo "EC2_INSTANCE_AMI=$(terraform output ec2_instance_ami)" >> $GITHUB_ENV
156+
working-directory: terraform/python/ec2
157+
158+
- name: Get the sample app endpoint
159+
run: |
160+
echo "MAIN_SERVICE_ENDPOINT=$(terraform output sample_app_main_service_public_dns):8000" >> $GITHUB_ENV
161+
echo "REMOTE_SERVICE_IP=$(terraform output sample_app_remote_service_public_ip)" >> $GITHUB_ENV
162+
working-directory: terraform/python/ec2
163+
164+
# This steps increases the speed of the validation by creating the telemetry data in advance
165+
- name: Call all test APIs
166+
continue-on-error: true
167+
run: |
168+
curl -S -s -o /dev/null http://${{ env.MAIN_SERVICE_ENDPOINT }}/outgoing-http-call; echo
169+
curl -S -s -o /dev/null http://${{ env.MAIN_SERVICE_ENDPOINT }}/aws-sdk-call; echo
170+
curl -S -s -o /dev/null http://${{ env.MAIN_SERVICE_ENDPOINT }}/remote-service?ip=${{ env.REMOTE_SERVICE_IP }}; echo
171+
curl -S -s -o /dev/null http://${{ env.MAIN_SERVICE_ENDPOINT }}/client-call; echo
172+
173+
- name: Initiate Gradlew Daemon
174+
uses: ./.github/workflows/actions/execute_and_retry
175+
with:
176+
command: "./gradlew"
177+
cleanup: "./gradlew clean"
178+
max_retry: 4
179+
sleep_time: 30
180+
181+
# Validation for pulse telemetry data
182+
- name: Validate generated EMF logs
183+
id: log-validation
184+
run: ./gradlew validator:run --args='-c python/ec2/log-validation.yml
185+
--endpoint http://${{ env.MAIN_SERVICE_ENDPOINT }}
186+
--remote-service-deployment-name ${{ env.REMOTE_SERVICE_IP }}:8001
187+
--region ${{ inputs.aws-region }}
188+
--metric-namespace ${{ env.METRIC_NAMESPACE }}
189+
--log-group ${{ env.LOG_GROUP_NAME }}
190+
--service-name python-sample-application-${{ env.TESTING_ID }}
191+
--remote-service-name python-sample-remote-application-${{ env.TESTING_ID }}
192+
--request-body ip=${{ env.REMOTE_SERVICE_IP }}
193+
--instance-ami ${{ env.EC2_INSTANCE_AMI }}
194+
--rollup'
195+
196+
- name: Validate generated metrics
197+
id: metric-validation
198+
if: (success() || steps.log-validation.outcome == 'failure') && !cancelled()
199+
run: ./gradlew validator:run --args='-c python/ec2/metric-validation.yml
200+
--endpoint http://${{ env.MAIN_SERVICE_ENDPOINT }}
201+
--remote-service-deployment-name ${{ env.REMOTE_SERVICE_IP }}:8001
202+
--region ${{ inputs.aws-region }}
203+
--metric-namespace ${{ env.METRIC_NAMESPACE }}
204+
--log-group ${{ env.LOG_GROUP_NAME }}
205+
--service-name python-sample-application-${{ env.TESTING_ID }}
206+
--remote-service-name python-sample-remote-application-${{ env.TESTING_ID }}
207+
--request-body ip=${{ env.REMOTE_SERVICE_IP }}
208+
--instance-ami ${{ env.EC2_INSTANCE_AMI }}
209+
--rollup'
210+
211+
- name: Validate generated traces
212+
id: trace-validation
213+
if: (success() || steps.log-validation.outcome == 'failure' || steps.metric-validation.outcome == 'failure') && !cancelled()
214+
run: ./gradlew validator:run --args='-c python/ec2/trace-validation.yml
215+
--endpoint http://${{ env.MAIN_SERVICE_ENDPOINT }}
216+
--remote-service-deployment-name ${{ env.REMOTE_SERVICE_IP }}:8001
217+
--region ${{ inputs.aws-region }}
218+
--account-id ${{ env.ACCOUNT_ID }}
219+
--metric-namespace ${{ env.METRIC_NAMESPACE }}
220+
--log-group ${{ env.LOG_GROUP_NAME }}
221+
--service-name python-sample-application-${{ env.TESTING_ID }}
222+
--remote-service-name python-sample-remote-application-${{ env.TESTING_ID }}
223+
--request-body ip=${{ env.REMOTE_SERVICE_IP }}
224+
--instance-ami ${{ env.EC2_INSTANCE_AMI }}
225+
--rollup'
226+
227+
- name: Publish metric on test result
228+
if: always()
229+
run: |
230+
if [ "${{ steps.log-validation.outcome }}" = "success" ] && [ "${{ steps.metric-validation.outcome }}" = "success" ] && [ "${{ steps.trace-validation.outcome }}" = "success" ]; then
231+
aws cloudwatch put-metric-data --namespace 'ADOT/GitHubActions' \
232+
--metric-name Failure \
233+
--dimensions repository=${{ github.repository }},branch=${{ github.ref_name }},workflow=${{ inputs.caller-workflow-name }} \
234+
--value 0.0 \
235+
--region ${{ inputs.aws-region }}
236+
else
237+
aws cloudwatch put-metric-data --namespace 'ADOT/GitHubActions' \
238+
--metric-name Failure \
239+
--dimensions repository=${{ github.repository }},branch=${{ github.ref_name }},workflow=${{ inputs.caller-workflow-name }} \
240+
--value 1.0 \
241+
--region ${{ inputs.aws-region }}
242+
fi
243+
244+
# Clean up Procedures
245+
- name: Terraform destroy
246+
if: always()
247+
continue-on-error: true
248+
working-directory: terraform/python/ec2
249+
run: |
250+
terraform destroy -auto-approve \
251+
-var="test_id=${{ env.TESTING_ID }}"

0 commit comments

Comments
 (0)