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