Skip to content

Commit

Permalink
Merge pull request #603 from aws-observability/release/v1.31.x
Browse files Browse the repository at this point in the history
Release/v1.31.x
  • Loading branch information
PaurushGarg authored Nov 15, 2023
2 parents 345d907 + 0e49186 commit a90e3cb
Show file tree
Hide file tree
Showing 332 changed files with 42,287 additions and 210 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/appsignals-e2e-eks-canary-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## This workflow aims to run the end-to-end tests in canary fashion to
## test the prod artifacts for App Signals enablement.
name: App Signals Enablement - E2E EKS Canary Testing
on:
schedule:
- cron: '0/10 * * * *' # run the workflow every 10 minutes
workflow_dispatch: # be able to run the workflow on demand

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

permissions:
id-token: write
contents: read

jobs:
e2e-canary-test:
uses: ./.github/workflows/appsignals-e2e-eks-test.yml
secrets: inherit
with:
test-cluster-name: 'e2e-canary-test'
caller-workflow-name: 'appsignals-e2e-eks-canary-test'
273 changes: 273 additions & 0 deletions .github/workflows/appsignals-e2e-eks-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
# This is a reusable workflow for running the E2E test for App Signals.
# It is meant to be called from another workflow.
# Read more about reusable workflows: https://docs.github.com/en/actions/using-workflows/reusing-workflows#overview
name: App Signals Enablement E2E Testing - EKS
on:
workflow_call:
inputs:
test-cluster-name:
required: true
type: string
appsignals-adot-image-name:
required: false
type: string
caller-workflow-name:
required: true
type: string

permissions:
id-token: write
contents: read

env:
AWS_DEFAULT_REGION: us-east-1
TEST_ACCOUNT: ${{ secrets.APP_SIGNALS_E2E_TEST_ACC }}
ENABLEMENT_SCRIPT_S3_BUCKET: ${{ secrets.APP_SIGNALS_E2E_ENABLEMENT_SCRIPT }}
SAMPLE_APP_NAMESPACE: sample-app-namespace
SAMPLE_APP_FRONTEND_SERVICE_IMAGE: ${{ secrets.APP_SIGNALS_E2E_FE_SA_IMG }}
SAMPLE_APP_REMOTE_SERVICE_IMAGE: ${{ secrets.APP_SIGNALS_E2E_RE_SA_IMG }}
METRIC_NAMESPACE: AppSignals
LOG_GROUP_NAME: /aws/appsignals/eks

jobs:
appsignals-e2e-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Generate testing id
run: echo TESTING_ID="${{ github.run_id }}-${{ github.run_number }}" >> $GITHUB_ENV

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.E2E_TEST_ROLE_ARN }}
aws-region: ${{ env.AWS_DEFAULT_REGION }}

# local directory to store the kubernetes config
- name: Create kubeconfig directory
run: mkdir -p ${{ github.workspace }}/.kube

- name: Set KUBECONFIG environment variable
run: echo KUBECONFIG="${{ github.workspace }}/.kube/config" >> $GITHUB_ENV

- name: Set up kubeconfig
run: aws eks update-kubeconfig --name ${{ inputs.test-cluster-name }} --region ${{ env.AWS_DEFAULT_REGION }}

- name: Install eksctl
run: |
mkdir ${{ github.workspace }}/eksctl
curl -sLO "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_Linux_amd64.tar.gz"
tar -xzf eksctl_Linux_amd64.tar.gz -C ${{ github.workspace }}/eksctl && rm eksctl_Linux_amd64.tar.gz
echo "${{ github.workspace }}/eksctl" >> $GITHUB_PATH
- name: Create role for AWS access from the sample app
id: create_service_account
run: |
eksctl create iamserviceaccount \
--name service-account-${{ env.TESTING_ID }} \
--namespace ${{ env.SAMPLE_APP_NAMESPACE }} \
--cluster ${{ inputs.test-cluster-name }} \
--role-name eks-s3-access-${{ env.TESTING_ID }} \
--attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
--region ${{ env.AWS_DEFAULT_REGION }} \
--approve
- name: Set up terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_wrapper: false

- name: Deploy sample app via terraform
working-directory: testing/terraform/eks
run: |
terraform init
terraform validate
terraform apply -auto-approve \
-var="test_id=${{ env.TESTING_ID }}" \
-var="kube_directory_path=${{ github.workspace }}/.kube" \
-var="eks_cluster_name=${{ inputs.test-cluster-name }}" \
-var="eks_cluster_context_name=$(kubectl config current-context)" \
-var="test_namespace=${{ env.SAMPLE_APP_NAMESPACE }}" \
-var="service_account_aws_access=service-account-${{ env.TESTING_ID }}" \
-var="sample_app_image=${{ env.SAMPLE_APP_FRONTEND_SERVICE_IMAGE }}" \
-var="sample_remote_app_image=${{ env.SAMPLE_APP_REMOTE_SERVICE_IMAGE }}"
# Enable App Signals on the test cluster
- name: Pull and unzip enablement script from S3
run: aws s3 cp ${{ env.ENABLEMENT_SCRIPT_S3_BUCKET }} . && unzip -j onboarding.zip

- name: Change ADOT image if main-build
if: inputs.caller-workflow-name == 'main-build'
run: "sed -i 's#image:.*#image: ${{ inputs.appsignals-adot-image-name }}#g' instrumentation.yaml"

- name: Enable App Signals
run: |
./enable-app-signals.sh \
${{ inputs.test-cluster-name }} \
${{ env.AWS_DEFAULT_REGION }} \
${{ env.SAMPLE_APP_NAMESPACE }}
# Application pods need to be restarted for the
# app signals instrumentation to take effect
- name: Restart the app pods
run: kubectl delete pods --all -n ${{ env.SAMPLE_APP_NAMESPACE }}

- name: Wait for sample app pods to come up
run: |
kubectl wait --for=condition=Ready pod --all -n ${{ env.SAMPLE_APP_NAMESPACE }}
- name: Get remote service pod name and IP
run: |
echo "REMOTE_SERVICE_DEPLOYMENT_NAME=$(kubectl get deployments -n ${{ env.SAMPLE_APP_NAMESPACE }} --selector=app=remote-app -o jsonpath='{.items[0].metadata.name}')" >> $GITHUB_ENV
echo "REMOTE_SERVICE_POD_IP=$(kubectl get pods -n ${{ env.SAMPLE_APP_NAMESPACE }} --selector=app=remote-app -o jsonpath='{.items[0].status.podIP}')" >> $GITHUB_ENV
- name: Verify pod Adot image
run: |
kubectl get pods -n ${{ env.SAMPLE_APP_NAMESPACE }} --output json | \
jq '.items[0].status.initContainerStatuses[0].imageID'
- name: Verify pod CWAgent image
run: |
kubectl get pods -n amazon-cloudwatch --output json | \
jq '.items[0].status.containerStatuses[0].imageID'
- name: Get the sample app endpoint
run: |
echo "APP_ENDPOINT=$(terraform output sample_app_endpoint)" >> $GITHUB_ENV
working-directory: testing/terraform/eks

- name: Wait for app endpoint to come online
id: endpoint-check
run: |
attempt_counter=0
max_attempts=30
until $(curl --output /dev/null --silent --head --fail http://${{ env.APP_ENDPOINT }}); do
if [ ${attempt_counter} -eq ${max_attempts} ];then
echo "Max attempts reached"
exit 1
fi
printf '.'
attempt_counter=$(($attempt_counter+1))
sleep 10
done
# Validation for app signals telemetry data
- name: Call endpoint and validate generated EMF logs
id: log-validation
if: steps.endpoint-check.outcome == 'success' && !cancelled()
run: ./gradlew testing:validator:run --args='-c log-validation.yml
--testing-id ${{ env.TESTING_ID }}
--endpoint http://${{ env.APP_ENDPOINT }}
--region ${{ env.AWS_DEFAULT_REGION }}
--account-id ${{ env.TEST_ACCOUNT }}
--metric-namespace ${{ env.METRIC_NAMESPACE }}
--log-group ${{ env.LOG_GROUP_NAME }}
--app-namespace ${{ env.SAMPLE_APP_NAMESPACE }}
--cluster ${{ inputs.test-cluster-name }}
--service-name sample-application-${{ env.TESTING_ID }}
--remote-service-deployment-name ${{ env.REMOTE_SERVICE_DEPLOYMENT_NAME }}
--request-body ip=${{ env.REMOTE_SERVICE_POD_IP }}
--rollup'

- name: Call endpoints and validate generated metrics
id: metric-validation
if: (success() || steps.log-validation.outcome == 'failure') && !cancelled()
run: ./gradlew testing:validator:run --args='-c metric-validation.yml
--testing-id ${{ env.TESTING_ID }}
--endpoint http://${{ env.APP_ENDPOINT }}
--region ${{ env.AWS_DEFAULT_REGION }}
--account-id ${{ env.TEST_ACCOUNT }}
--metric-namespace ${{ env.METRIC_NAMESPACE }}
--log-group ${{ env.LOG_GROUP_NAME }}
--app-namespace ${{ env.SAMPLE_APP_NAMESPACE }}
--cluster ${{ inputs.test-cluster-name }}
--service-name sample-application-${{ env.TESTING_ID }}
--remote-service-name sample-remote-application-${{ env.TESTING_ID }}
--remote-service-deployment-name ${{ env.REMOTE_SERVICE_DEPLOYMENT_NAME }}
--request-body ip=${{ env.REMOTE_SERVICE_POD_IP }}
--rollup'

- name: Call endpoints and validate generated traces
id: trace-validation
if: (success() || steps.log-validation.outcome == 'failure' || steps.metric-validation.outcome == 'failure') && !cancelled()
run: ./gradlew testing:validator:run --args='-c trace-validation.yml
--testing-id ${{ env.TESTING_ID }}
--endpoint http://${{ env.APP_ENDPOINT }}
--region ${{ env.AWS_DEFAULT_REGION }}
--account-id ${{ env.TEST_ACCOUNT }}
--metric-namespace ${{ env.METRIC_NAMESPACE }}
--log-group ${{ env.LOG_GROUP_NAME }}
--app-namespace ${{ env.SAMPLE_APP_NAMESPACE }}
--cluster ${{ inputs.test-cluster-name }}
--service-name sample-application-${{ env.TESTING_ID }}
--remote-service-deployment-name ${{ env.REMOTE_SERVICE_DEPLOYMENT_NAME }}
--request-body ip=${{ env.REMOTE_SERVICE_POD_IP }}
--rollup'

- name: Publish metric on test result
if: always()
run: |
if [[ "${{ steps.log-validation.outcome }}" == "success" && "${{ steps.metric-validation.outcome }}" == "success" && "${{ steps.trace-validation.outcome }}" == "success" ]]; then
aws cloudwatch put-metric-data --namespace 'ADOT/GitHubActions' \
--metric-name Success \
--dimensions repository=${{ github.repository }},branch=${{ github.ref_name }},workflow=${{ inputs.caller-workflow-name }} \
--value 1.0 \
--region us-west-2
else
aws cloudwatch put-metric-data --namespace 'ADOT/GitHubActions' \
--metric-name Success \
--dimensions repository=${{ github.repository }},branch=${{ github.ref_name }},workflow=${{ inputs.caller-workflow-name }} \
--value 0.0 \
--region us-west-2
fi
# Clean up Procedures

- name: Remove log group deletion command
if: always()
run: |
delete_log_group="aws logs delete-log-group --log-group-name '${{ env.LOG_GROUP_NAME }}' --region \$REGION"
sed -i "s#$delete_log_group##g" clean-app-signals.sh
- name: Clean Up App Signals
if: always()
continue-on-error: true
run: |
./clean-app-signals.sh \
${{ inputs.test-cluster-name }} \
${{ env.AWS_DEFAULT_REGION }} \
${{ env.SAMPLE_APP_NAMESPACE }}
# This step also deletes lingering resources from previous test runs
- name: Delete all sample app resources
if: always()
continue-on-error: true
timeout-minutes: 10
run: kubectl delete namespace ${{ env.SAMPLE_APP_NAMESPACE }}

- name: Terraform destroy
if: always()
continue-on-error: true
working-directory: testing/terraform/eks
run: |
terraform destroy -auto-approve \
-var="test_id=${{ env.TESTING_ID }}" \
-var="kube_directory_path=${{ github.workspace }}/.kube" \
-var="eks_cluster_name=${{ inputs.test-cluster-name }}" \
-var="test_namespace=${{ env.SAMPLE_APP_NAMESPACE }}" \
-var="service_account_aws_access=service-account-${{ env.TESTING_ID }}" \
-var="sample_app_image=${{ env.SAMPLE_APP_IMAGE }}"
- name: Remove aws access service account
if: always()
continue-on-error: true
run: |
eksctl delete iamserviceaccount \
--name service-account-${{ env.TESTING_ID }} \
--namespace ${{ env.SAMPLE_APP_NAMESPACE }} \
--cluster ${{ inputs.test-cluster-name }} \
--region ${{ env.AWS_DEFAULT_REGION }} \
17 changes: 17 additions & 0 deletions .github/workflows/main-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ jobs:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}

- name: Pull base image of Contract Tests Sample Apps
run: docker pull public.ecr.aws/docker/library/amazoncorretto:17-alpine

- name: Run contract tests
uses: gradle/gradle-build-action@v2
with:
arguments: contractTests -PlocalDocker=true

- name: Get current version
shell: bash
run: |
Expand Down Expand Up @@ -443,6 +451,15 @@ jobs:
APP_IMAGE: public.ecr.aws/aws-otel-test/aws-otel-java-spark-awssdkv1:${{ github.sha }}
VALIDATOR_COMMAND: -c spark-otel-trace-metric-validation.yml --endpoint http://app:4567 --metric-namespace aws-otel-integ-test -t ${{ github.run_id }}-${{ github.run_number }}

e2e-test:
needs: build
uses: ./.github/workflows/appsignals-e2e-eks-test.yml
secrets: inherit
with:
test-cluster-name: "e2e-adot-test"
appsignals-adot-image-name: 611364707713.dkr.ecr.us-west-2.amazonaws.com/adot-autoinstrumentation-java-operator-staging:${{ needs.build.outputs.java_agent_tag }}
caller-workflow-name: 'main-build'

publish-build-status:
needs: [test_Spring_App_With_Java_Agent, test_Spark_App_With_Java_Agent, test_Spark_AWS_SDK_V1_App_With_Java_Agent, run-batch-job]
if: ${{ always() }}
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ jobs:
with:
arguments: build integrationTests --stacktrace -PenableCoverage=true -PlocalDocker=true

- name: Pull base image of Contract Tests Sample Apps
if: ${{ matrix.os == 'ubuntu-latest' }}
run: docker pull public.ecr.aws/docker/library/amazoncorretto:17-alpine

- name: Run contract tests
uses: gradle/gradle-build-action@v2
if: ${{ matrix.os == 'ubuntu-latest' }}
with:
arguments: contractTests -PlocalDocker=true -i

- name: Get current version
if: ${{ matrix.os == 'ubuntu-latest' }}
shell: bash
Expand Down
50 changes: 50 additions & 0 deletions appsignals-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Introduction

This directory contain tests that are used exclusively for appsignals:
* Contract tests for semantic conventions.
* Contract tests for appsignals specific attributes.

# How it works?

The tests present here rely on the auto-instrumentation of a sample application which will send telemetry signals to
a mock collector. The tests will use the data collected by the mock collector to perform assertions and validate that
the contracts are being respected.


# Types of tested frameworks

The frameworks and libraries that are tested in the contract tests should fall in the following categories (more can be added on demand):
* http-servers - applications meant to test http servers.
* http-clients - applications meant to test http clients.
* aws-sdk - Applications meant to test the AWS SDK
* pub-sub - Asynchronous type of application where you typically have a publisher and a subscriber communicating using a message broker.

When testing a framework, we will create a sample application. The sample applications are stored following this
convention: `appsignals-tests/images/<application-type>/<framework-name>`

# Adding tests for a new library or framework

The steps to add a new test for a library or framework are:

* Create a sample application that can be run inside a docker image using Jib.
* The sample application should be its own gradlew subproject. (you need to add it to `settings.gradle.kts` in the root of this project)
* The sample application should be located in the directory `appsignals-tests/images/<application-type>/<framework-name>`
* Add a test class for the sample application.
* The test class should created in `appsignals-tests/contract/tests`.
* The name of the java package for the test classes should follow this convention: `software.amazon.opentelemetry.appsignals.test.<application-type>`

# How to run the tests locally?

Pre-requirements:
* Ensure Docker is running on your machine.
* Ensure AWS credentials are exported to environment variables.

From the root of this project execute:

```
## login to public ECR
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
# Run the tests
./gradlew appsignals-tests:contract-tests:contractTests
```
Loading

0 comments on commit a90e3cb

Please sign in to comment.