diff --git a/.github/workflows/dotnet-ec2-canary.yml b/.github/workflows/dotnet-ec2-canary.yml index 1b3fb5bfa..a90c489a1 100644 --- a/.github/workflows/dotnet-ec2-canary.yml +++ b/.github/workflows/dotnet-ec2-canary.yml @@ -29,3 +29,18 @@ jobs: with: aws-region: ${{ matrix.aws-region }} caller-workflow-name: 'appsignals-dotnet-e2e-ec2-canary-test' + + + windows: + strategy: + fail-fast: false + 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' ] + uses: ./.github/workflows/dotnet-ec2-windows-retry.yml + secrets: inherit + with: + aws-region: ${{ matrix.aws-region }} + caller-workflow-name: 'appsignals-dotnet-e2e-ec2-windows-canary-test' \ No newline at end of file diff --git a/.github/workflows/dotnet-ec2-windows-retry.yml b/.github/workflows/dotnet-ec2-windows-retry.yml new file mode 100644 index 000000000..d2097b517 --- /dev/null +++ b/.github/workflows/dotnet-ec2-windows-retry.yml @@ -0,0 +1,57 @@ +## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +## SPDX-License-Identifier: Apache-2.0 + +# This is a reusable workflow for running the Enablement 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: Dotnet EC2 Windows Retry +on: + workflow_call: + inputs: + aws-region: + required: true + type: string + caller-workflow-name: + required: true + type: string + +permissions: + id-token: write + contents: read + +jobs: + dotnet-ec2-windows-attempt-1: + uses: ./.github/workflows/dotnet-ec2-windows-test.yml + secrets: inherit + with: + aws-region: ${{ inputs.aws-region }} + caller-workflow-name: ${{ inputs.caller-workflow-name }} + + dotnet-ec2-windows-attempt-2: + needs: [ dotnet-ec2-windows-attempt-1 ] + if: ${{ needs.dotnet-ec2-windows-attempt-1.outputs.job-started != 'true' }} + uses: ./.github/workflows/dotnet-ec2-windows-test.yml + secrets: inherit + with: + aws-region: ${{ inputs.aws-region }} + caller-workflow-name: ${{ inputs.caller-workflow-name }} + + publish-metric-attempt-1: + needs: [ dotnet-ec2-windows-attempt-1, dotnet-ec2-windows-attempt-2 ] + if: always() + uses: ./.github/workflows/enablement-test-publish-result.yml + secrets: inherit + with: + aws-region: ${{ inputs.aws-region }} + caller-workflow-name: ${{ inputs.caller-workflow-name }} + validation-result: ${{ needs.dotnet-ec2-windows-attempt-1.outputs.validation-result || needs.dotnet-ec2-windows-attempt-2.outputs.validation-result }} + + publish-metric-attempt-2: + needs: [ dotnet-ec2-windows-attempt-1, dotnet-ec2-windows-attempt-2, publish-metric-attempt-1 ] + if: ${{ always() && needs.publish-metric-attempt-1.outputs.job-started != 'true' }} + uses: ./.github/workflows/enablement-test-publish-result.yml + secrets: inherit + with: + aws-region: ${{ inputs.aws-region }} + caller-workflow-name: ${{ inputs.caller-workflow-name }} + validation-result: ${{ needs.dotnet-ec2-windows-attempt-1.outputs.validation-result || needs.dotnet-ec2-windows-attempt-2.outputs.validation-result }} \ No newline at end of file diff --git a/.github/workflows/dotnet-ec2-windows-test.yml b/.github/workflows/dotnet-ec2-windows-test.yml new file mode 100644 index 000000000..dc592e201 --- /dev/null +++ b/.github/workflows/dotnet-ec2-windows-test.yml @@ -0,0 +1,339 @@ +## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +## SPDX-License-Identifier: Apache-2.0 + +# This is a reusable workflow for running the DotNet E2E Canary test for Application 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: DotNet EC2 Windows Use Case +on: + workflow_call: + inputs: + aws-region: + required: true + type: string + staging_distro_name: + required: false + default: 'aws-opentelemetry-distro' + type: string + caller-workflow-name: + required: true + type: string + outputs: + job-started: + value: ${{ jobs.dotnet-ec2-windows.outputs.job-started }} + validation-result: + value: ${{ jobs.dotnet-ec2-windows.outputs.validation-result }} + +permissions: + id-token: write + contents: read + +env: + E2E_TEST_AWS_REGION: ${{ inputs.aws-region }} + E2E_TEST_ACCOUNT_ID: ${{ secrets.APPLICATION_SIGNALS_E2E_TEST_ACCOUNT_ID }} + E2E_TEST_ROLE_NAME: ${{ secrets.APPLICATION_SIGNALS_E2E_TEST_ROLE_NAME }} + SAMPLE_APP_ZIP: "aws s3 cp s3://aws-appsignals-sample-app-prod-${{ inputs.aws-region }}/dotnet-sample-app.zip ./dotnet-sample-app.zip" + METRIC_NAMESPACE: ApplicationSignals + LOG_GROUP_NAME: /aws/application-signals/data + ADOT_DISTRO_NAME: ${{ inputs.staging_distro_name }} + TEST_RESOURCES_FOLDER: ${GITHUB_WORKSPACE} + +jobs: + dotnet-ec2-windows: + runs-on: ubuntu-latest + timeout-minutes: 30 + outputs: + job-started: ${{ steps.job-started.outputs.job-started }} + validation-result: ${{ steps.validation-result.outputs.validation-result }} + steps: + - name: Check if the job started + id: job-started + run: echo "job-started=true" >> $GITHUB_OUTPUT + + - uses: actions/checkout@v4 + with: + repository: 'aws-observability/aws-application-signals-test-framework' + ref: ${{ inputs.caller-workflow-name == 'main-build' && 'main' || github.ref }} + fetch-depth: 0 + + - name: Initiate Gradlew Daemon + id: initiate-gradlew + uses: ./.github/workflows/actions/execute_and_retry + continue-on-error: true + with: + command: "./gradlew :validator:build" + cleanup: "./gradlew clean" + max_retry: 3 + sleep_time: 60 + + - name: Generate testing id + run: echo TESTING_ID="${{ github.job }}-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}" >> $GITHUB_ENV + + - 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/${{ env.E2E_TEST_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: ${{ env.E2E_TEST_AWS_REGION }} + + - name: Set Get ADOT Distro command environment variable + run: | + if [ "${{ github.event.repository.name }}" = "aws-otel-dotnet-instrumentation" ]; then + # Get staging distro file from staging bucket + echo GET_ADOT_DISTRO_COMMAND="aws s3 cp s3://adot-autoinstrumentation-dotnet-staging/${{ env.ADOT_DISTRO_NAME }} ./${{ env.ADOT_DISTRO_NAME }}; Expand-Archive -Path /${{ env.ADOT_DISTRO_NAME }} -DestinationPath ./dotnet-distro" >> $GITHUB_ENV + else + # After Release will switch to latest tag instead of hard code version for canary purpose + echo GET_ADOT_DISTRO_COMMAND="wget -O ./aws-distro-opentelemetry-dotnet-instrumentation-windows.zip https://github.com/aws-observability/aws-otel-dotnet-instrumentation/releases/latest/download/aws-distro-opentelemetry-dotnet-instrumentation-windows.zip; Expand-Archive -Path ./aws-distro-opentelemetry-dotnet-instrumentation-windows.zip -DestinationPath ./dotnet-distro -Force" >> $GITHUB_ENV + fi + + - name: Set Get CW Agent command environment variable + run: | + if [ "${{ github.event.repository.name }}" = "amazon-cloudwatch-agent" ]; then + # Get cloudwatch agent staging file if triggered by cw-a repo + echo GET_CW_AGENT_MSI_COMMAND= "aws s3 cp s3://${{ secrets.S3_INTEGRATION_BUCKET }}/integration-test/binary/${{ github.sha }}/amazon-cloudwatch-agent.msi ./cw-agent.msi" >> $GITHUB_ENV + else + echo GET_CW_AGENT_MSI_COMMAND= "wget -O ./amazon-cloudwatch-agent.msi https://amazoncloudwatch-agent.s3.amazonaws.com/windows/amd64/latest/amazon-cloudwatch-agent.msi" >> $GITHUB_ENV + fi + + - name: Set up terraform + uses: ./.github/workflows/actions/execute_and_retry + with: + command: "wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg" + post-command: 'echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list + && sudo apt update && sudo apt install terraform' + sleep_time: 60 + + - name: Initiate Terraform + uses: ./.github/workflows/actions/execute_and_retry + with: + command: "cd ${{ env.TEST_RESOURCES_FOLDER }}/terraform/dotnet/ec2/windows && terraform init && terraform validate" + cleanup: "rm -rf .terraform && rm -rf .terraform.lock.hcl" + max_retry: 6 + sleep_time: 60 + + - name: Deploy sample app via terraform and wait for endpoint to come online + working-directory: terraform/dotnet/ec2/windows + run: | + # Attempt to deploy the sample app on an EC2 instance and wait for its endpoint to come online. + # There may be occasional failures due to transitivity issues, so try up to 2 times. + # deployment_failed of 0 indicates that both the terraform deployment and the endpoint are running, while 1 indicates + # that it failed at some point + retry_counter=0 + max_retry=2 + while [ $retry_counter -lt $max_retry ]; do + echo "Attempt $retry_counter" + deployment_failed=0 + terraform apply -auto-approve \ + -var="aws_region=${{ env.E2E_TEST_AWS_REGION }}" \ + -var="test_id=${{ env.TESTING_ID }}" \ + -var="sample_app_zip=${{ env.SAMPLE_APP_ZIP }}" \ + -var="get_cw_agent_msi_command=${{ env.GET_CW_AGENT_MSI_COMMAND }}" \ + -var="get_adot_distro_command=${{ env.GET_ADOT_DISTRO_COMMAND }}" \ + || deployment_failed=$? + + if [ $deployment_failed -eq 1 ]; then + echo "Terraform deployment was unsuccessful. Will attempt to retry deployment." + fi + + # If the success is 1 then either the terraform deployment or the endpoint connection failed, so first destroy the + # resources created from terraform and try again. + if [ $deployment_failed -eq 1 ]; then + echo "Destroying terraform" + terraform destroy -auto-approve \ + -var="test_id=${{ env.TESTING_ID }}" + + retry_counter=$(($retry_counter+1)) + else + # If deployment succeeded, then exit the loop + break + fi + + if [ $retry_counter -eq $max_retry ]; then + echo "Max retry reached, failed to deploy terraform and connect to the endpoint. Exiting code" + exit 1 + fi + done + + - name: Get the ec2 instance ami id + working-directory: terraform/dotnet/ec2/windows + run: | + echo "EC2_INSTANCE_AMI=$(terraform output ec2_instance_ami)" >> $GITHUB_ENV + + - name: Get SSM outputs + working-directory: terraform/dotnet/ec2/windows + run: | + echo "FRONTEND_SSM_ASSOCIATION_ID=$(terraform output frontend_script_association_id)" >> $GITHUB_ENV + echo "REMOTE_SSM_ASSOCIATION__ID=$(terraform output remote_script_association_id)" >> $GITHUB_ENV + + - name: Get the sample app endpoint + working-directory: terraform/dotnet/ec2/windows + run: | + echo "MAIN_SERVICE_ENDPOINT=localhost:8080" >> $GITHUB_ENV + echo "REMOTE_SERVICE_IP=$(terraform output sample_app_remote_service_private_ip)" >> $GITHUB_ENV + echo "MAIN_SERVICE_INSTANCE_ID=$(terraform output main_service_instance_id)" >> $GITHUB_ENV + echo "REMOTE_SERVICE_INSTANCE_ID=$(terraform output remote_service_instance_id)" >> $GITHUB_ENV + +# A standard Windows Deployment Script are Expect to run ~5min, plus waiting for SSM to be setup in EC2 instance ~2min +# 12 Min loose upper timeout bound is designed to allow for a rate situation: in a very small chance, +# It's possible for SSM document to take up to 8min to run and still produce expect setup outcome + - name: Monitor EC2 instances readiness and SSM execute status in Systems Manager + timeout-minutes: 12 + run: | + # Allow up to 5 min for EC2 instance connect to SSM + max_attempts=30 + attempt=0 + interval=10 + + check_instance_ready() { + local instance_id=$1 + while [[ $attempt -lt $max_attempts ]]; do + state=$(aws ssm describe-instance-information --filters Key=InstanceIds,Values=$instance_id --query "InstanceInformationList[0].PingStatus" --output text) + echo "Attempt $((attempt + 1))/$max_attempts: Current SSM state of instance $instance_id: $state" + + if [[ "$state" == "Online" ]]; then + echo "Instance $instance_id is 'Online' in Systems Manager and ready." + break + else + echo "Waiting for instance $instance_id to be 'Online' in Systems Manager..." + sleep $interval + attempt=$((attempt + 1)) + fi + done + + if [[ $attempt -ge $max_attempts ]]; then + echo "Timeout reached: Instance $instance_id did not become 'Online' in Systems Manager within expected time." + exit 1 + fi + } + + check_instance_ready ${{ env.MAIN_SERVICE_INSTANCE_ID }} + check_instance_ready ${{ env.REMOTE_SERVICE_INSTANCE_ID }} + + # Allow up to 10 min for SSM Document to run + max_attempts=60 + attempt=0 + + check_status() { + local association_id=$1 + + while [[ $attempt -lt $max_attempts ]]; do + aws ssm describe-association --association-id $association_id + local status=$(aws ssm describe-association --association-id $association_id --query "AssociationDescription.Overview.AssociationStatusAggregatedCount.Success" --output text) + echo "Attempt $((attempt + 1))/$max_attempts: Current status of SSM Association $association_id: $status" + if [[ "$status" == "1" ]]; then + echo "SSM Association $association_id succeeded." + break + else + echo "Waiting for SSM Association $association_id to succeed..." + sleep $interval + attempt=$((attempt + 1)) + fi + done + + if [[ $attempt -ge $max_attempts ]]; then + echo "Max attempts reached: SSM Association $association_id did not succeed after $max_attempts attempts." + exit 1 + fi + } + + check_status ${{ env.FRONTEND_SSM_ASSOCIATION_ID }} + check_status ${{ env.REMOTE_SSM_ASSOCIATION__ID }} + + - name: Initiate Gradlew Daemon + if: steps.initiate-gradlew == 'failure' + uses: ./.github/workflows/actions/execute_and_retry + continue-on-error: true + with: + command: "./gradlew" + cleanup: "./gradlew clean" + max_retry: 3 + sleep_time: 60 + + # Validation for pulse telemetry data + - name: Validate generated EMF logs + id: log-validation + run: ./gradlew validator:run --args='-c dotnet/ec2/windows/log-validation.yml + --testing-id ${{ env.TESTING_ID }} + --endpoint http://${{ env.MAIN_SERVICE_ENDPOINT }} + --remote-service-deployment-name ${{ env.REMOTE_SERVICE_IP }}:8081 + --region ${{ env.E2E_TEST_AWS_REGION }} + --metric-namespace ${{ env.METRIC_NAMESPACE }} + --log-group ${{ env.LOG_GROUP_NAME }} + --service-name dotnet-sample-application-${{ env.TESTING_ID }} + --remote-service-name dotnet-sample-remote-application-${{ env.TESTING_ID }} + --query-string ip=${{ env.REMOTE_SERVICE_IP }}&testingId=${{ env.TESTING_ID }} + --instance-ami ${{ env.EC2_INSTANCE_AMI }} + --instance-id ${{ env.MAIN_SERVICE_INSTANCE_ID }} + --rollup' + + - name: Validate generated metrics + id: metric-validation + if: (success() || steps.log-validation.outcome == 'failure') && !cancelled() + run: ./gradlew validator:run --args='-c dotnet/ec2/windows/metric-validation.yml + --testing-id ${{ env.TESTING_ID }} + --endpoint http://${{ env.MAIN_SERVICE_ENDPOINT }} + --remote-service-deployment-name ${{ env.REMOTE_SERVICE_IP }}:8081 + --region ${{ env.E2E_TEST_AWS_REGION }} + --metric-namespace ${{ env.METRIC_NAMESPACE }} + --log-group ${{ env.LOG_GROUP_NAME }} + --service-name dotnet-sample-application-${{ env.TESTING_ID }} + --remote-service-name dotnet-sample-remote-application-${{ env.TESTING_ID }} + --query-string ip=${{ env.REMOTE_SERVICE_IP }}&testingId=${{ env.TESTING_ID }} + --instance-ami ${{ env.EC2_INSTANCE_AMI }} + --instance-id ${{ env.MAIN_SERVICE_INSTANCE_ID }} + --rollup' + + - name: Validate generated traces + id: trace-validation + if: (success() || steps.log-validation.outcome == 'failure' || steps.metric-validation.outcome == 'failure') && !cancelled() + run: ./gradlew validator:run --args='-c dotnet/ec2/windows/trace-validation.yml + --testing-id ${{ env.TESTING_ID }} + --endpoint http://${{ env.MAIN_SERVICE_ENDPOINT }} + --remote-service-deployment-name ${{ env.REMOTE_SERVICE_IP }}:8081 + --region ${{ env.E2E_TEST_AWS_REGION }} + --account-id ${{ env.ACCOUNT_ID }} + --metric-namespace ${{ env.METRIC_NAMESPACE }} + --log-group ${{ env.LOG_GROUP_NAME }} + --service-name dotnet-sample-application-${{ env.TESTING_ID }} + --remote-service-name dotnet-sample-remote-application-${{ env.TESTING_ID }} + --query-string ip=${{ env.REMOTE_SERVICE_IP }}&testingId=${{ env.TESTING_ID }} + --instance-ami ${{ env.EC2_INSTANCE_AMI }} + --instance-id ${{ env.MAIN_SERVICE_INSTANCE_ID }} + --rollup' + + - name: Refresh AWS Credentials + if: ${{ github.event.repository.name == 'aws-application-signals-test-framework' }} + 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: ${{ env.E2E_TEST_AWS_REGION }} + + - name: Save test results + if: always() + id: validation-result + run: | + if [ "${{ steps.log-validation.outcome }}" = "success" ] && [ "${{ steps.metric-validation.outcome }}" = "success" ] && [ "${{ steps.trace-validation.outcome }}" = "success" ]; then + echo "validation-result=success" >> $GITHUB_OUTPUT + else + echo "validation-result=failure" >> $GITHUB_OUTPUT + fi + + # Clean up Procedures + - name: Terraform destroy + if: always() + continue-on-error: true + working-directory: terraform/dotnet/ec2/windows + run: | + terraform destroy -auto-approve \ + -var="test_id=${{ env.TESTING_ID }}" \ No newline at end of file diff --git a/.github/workflows/dotnet-sample-app-s3-deploy.yml b/.github/workflows/dotnet-sample-app-s3-deploy.yml index 2047819ba..e24f2afb8 100644 --- a/.github/workflows/dotnet-sample-app-s3-deploy.yml +++ b/.github/workflows/dotnet-sample-app-s3-deploy.yml @@ -49,3 +49,12 @@ jobs: - name: Upload to S3 working-directory: sample-apps/dotnet run: aws s3api put-object --bucket aws-appsignals-sample-app-prod-${{ matrix.aws-region }} --body ./dotnet-sample-app.zip --key dotnet-sample-app.zip + + - name: Upload Windows Script to S3 + working-directory: sample-apps/dotnet + run: | + aws s3api put-object --bucket aws-appsignals-sample-app-prod-${{ matrix.aws-region }} --body ./dotnet-ec2-win-main-setup.ps1 --key dotnet-ec2-win-main-setup.ps1 + aws s3api put-object --bucket aws-appsignals-sample-app-prod-${{ matrix.aws-region }} --body ./dotnet-ec2-win-remote-setup.ps1 --key dotnet-ec2-win-remote-setup.ps1 + aws s3api put-object --bucket aws-appsignals-sample-app-prod-${{ matrix.aws-region }} --body ./amazon-cloudwatch-agent.json --key amazon-cloudwatch-agent.json + + diff --git a/sample-apps/dotnet/amazon-cloudwatch-agent.json b/sample-apps/dotnet/amazon-cloudwatch-agent.json new file mode 100644 index 000000000..dd82b9e51 --- /dev/null +++ b/sample-apps/dotnet/amazon-cloudwatch-agent.json @@ -0,0 +1,16 @@ +{ + "agent": { + "debug": true, + "region": "REGION" + }, + "traces": { + "traces_collected": { + "application_signals": {} + } + }, + "logs": { + "metrics_collected": { + "application_signals": {} + } + } +} \ No newline at end of file diff --git a/sample-apps/dotnet/dotnet-ec2-win-main-setup.ps1 b/sample-apps/dotnet/dotnet-ec2-win-main-setup.ps1 new file mode 100644 index 000000000..c11513f68 --- /dev/null +++ b/sample-apps/dotnet/dotnet-ec2-win-main-setup.ps1 @@ -0,0 +1,117 @@ +param ( + [string]$GetCloudwatchAgentCommand, + [string]$GetAdotDistroCommand, + [string]$GetSampleAppCommand, + [string]$TestId, + [string]$RemoteServicePrivateEndpoint, + [string]$AWSRegion +) + +# This file is used to deploy and instrumentation main sample app for Dotnet E2E Canary test +# This is the most stable way to do that in automatically test workflow invloving EC2 and SSM + +# To avoid written UI for download and extract zip step, saving lots of time +$ProgressPreference = 'SilentlyContinue' + +# Install Dotnet +wget -O dotnet-install.ps1 https://dot.net/v1/dotnet-install.ps1 +.\dotnet-install.ps1 -Version 8.0.302 + +# Install and start Cloudwatch Agent +Invoke-Expression $GetCloudwatchAgentCommand + +Write-Host "Installing Cloudwatch Agent" +msiexec /i amazon-cloudwatch-agent.msi +$timeout = 30 +$interval = 5 +$call_cloudwatch = & "C:\Program Files\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" +$elapsedTime = 0 + +while ($elapsedTime -lt $timeout) { + if ($call_cloudwatch) { + Start-Sleep -Seconds $interval + Write-Host "Install Finished" + break + } else { + Write-Host "Cloudwatch Agent not found: $filePath. Checking again in $interval seconds..." + Start-Sleep -Seconds $interval + $elapsedTime += $interval + } +} + +if ($elapsedTime -ge $timeout) { + Write-Host "CloudWatch not found after $timeout seconds." +} + +Write-Host "Install Finished" + +# Even after this step, it only expose 8080 to localhost and local (EC2) network on current config, so it's safe +# Leave it here for Debug purpose +New-NetFirewallRule -DisplayName "Allow TCP 8080" -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow + +& "C:\Program Files\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" -a fetch-config -m ec2 -s -c file:./amazon-cloudwatch-agent.json + +# Get Instrumentation Artifacts and Sample App +Invoke-Expression $GetAdotDistroCommand + +Invoke-Expression $GetSampleAppCommand + +Expand-Archive -Path .\dotnet-sample-app.zip -DestinationPath .\ -Force + +# Config Env variable for Windows EC2 + +$current_dir = Get-Location +Write-Host $current_dir + +Set-Location -Path "./asp_frontend_service" +$env:CORECLR_ENABLE_PROFILING = "1" +$env:CORECLR_PROFILER = "{918728DD-259F-4A6A-AC2B-B85E1B658318}" +$env:CORECLR_PROFILER_PATH = "$current_dir\dotnet-distro\win-x64\OpenTelemetry.AutoInstrumentation.Native.dll" +$env:DOTNET_ADDITIONAL_DEPS = "$current_dir\dotnet-distro\AdditionalDeps" +$env:DOTNET_SHARED_STORE = "$current_dir\dotnet-distro\store" +$env:DOTNET_STARTUP_HOOKS = "$current_dir\dotnet-distro\net\OpenTelemetry.AutoInstrumentation.StartupHook.dll" +$env:OTEL_DOTNET_AUTO_HOME = "$current_dir\dotnet-distro" +$env:OTEL_DOTNET_AUTO_PLUGINS = "AWS.Distro.OpenTelemetry.AutoInstrumentation.Plugin, AWS.Distro.OpenTelemetry.AutoInstrumentation" +$env:OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf" +$env:OTEL_EXPORTER_OTLP_ENDPOINT = "http://127.0.0.1:4316" +$env:OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT = "http://127.0.0.1:4316/v1/metrics" +$env:OTEL_METRICS_EXPORTER = "none" +$env:OTEL_RESOURCE_ATTRIBUTES = "service.name=dotnet-sample-application-$TestId" +$env:OTEL_AWS_APPLICATION_SIGNALS_ENABLED = "true" +$env:OTEL_TRACES_SAMPLER = "always_on" +$env:ASPNETCORE_URLS = "http://0.0.0.0:8080" + + +dotnet build + + +Start-Process -FilePath "dotnet" -ArgumentList "bin/Debug/netcoreapp8.0/asp_frontend_service.dll" + +Write-Host "Start Sleep" +Start-Sleep -Seconds 10 + +# Deploy Traffic Generator + +# Install node and setup path for node +wget -O nodejs.zip https://nodejs.org/dist/v20.16.0/node-v20.16.0-win-x64.zip +Expand-Archive -Path .\nodejs.zip -DestinationPath .\nodejs -Force +$currentdir = Get-Location +Write-Host $currentdir +$env:Path += ";$currentdir" + "\nodejs\node-v20.16.0-win-x64" + +# Bring in the traffic generator files to EC2 Instance +aws s3 cp "s3://aws-appsignals-sample-app-prod-$AWSRegion/traffic-generator.zip" "./traffic-generator.zip" +Expand-Archive -Path "./traffic-generator.zip" -DestinationPath "./" -Force + +# Install the traffic generator dependencies +npm install + +# Start traffic generator +$env:MAIN_ENDPOINT = "localhost:8080" +$env:REMOTE_ENDPOINT = $RemoteServicePrivateEndpoint +$env:ID = $TestId + +Start-Process -FilePath "npm" -ArgumentList "start" + +Write-Host "Exiting" +exit \ No newline at end of file diff --git a/sample-apps/dotnet/dotnet-ec2-win-remote-setup.ps1 b/sample-apps/dotnet/dotnet-ec2-win-remote-setup.ps1 new file mode 100644 index 000000000..b4af24791 --- /dev/null +++ b/sample-apps/dotnet/dotnet-ec2-win-remote-setup.ps1 @@ -0,0 +1,88 @@ +param ( + [string]$GetCloudwatchAgentCommand, + [string]$GetAdotDistroCommand, + [string]$GetSampleAppCommand, + [string]$TestId +) + +# This file is used to deploy and instrumentation remote sample app for Dotnet E2E Canary test +# This is the most stable way to do that in automatically test workflow invloving EC2 and SSM + +# To avoid written UI for download and extract zip step, saving lots of time +$ProgressPreference = 'SilentlyContinue' + +# Install Dotnet +wget -O dotnet-install.ps1 https://dot.net/v1/dotnet-install.ps1 +.\dotnet-install.ps1 -Version 8.0.302 + +# Install and start Cloudwatch Agent +Invoke-Expression $GetCloudwatchAgentCommand + +Write-Host "Installing Cloudwatch Agent" +msiexec /i amazon-cloudwatch-agent.msi +$timeout = 30 +$interval = 5 +$call_cloudwatch = & "C:\Program Files\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" +$elapsedTime = 0 + +while ($elapsedTime -lt $timeout) { + if ($call_cloudwatch) { + Start-Sleep -Seconds $interval + Write-Host "Install Finished" + break + } else { + Write-Host "Cloudwatch Agent not found: $filePath. Checking again in $interval seconds..." + Start-Sleep -Seconds $interval + $elapsedTime += $interval + } +} + +if ($elapsedTime -ge $timeout) { + Write-Host "CloudWatch not found after $timeout seconds." +} + +& "C:\Program Files\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" -a fetch-config -m ec2 -s -c file:./amazon-cloudwatch-agent.json + +# Get Instrumentation Artifacts and Sample App +Invoke-Expression $GetAdotDistroCommand + +Invoke-Expression $GetSampleAppCommand + +Expand-Archive -Path .\dotnet-sample-app.zip -DestinationPath .\ -Force + +# Allow income traffic from main-service +New-NetFirewallRule -DisplayName "Allow TCP 8081" -Direction Inbound -Protocol TCP -LocalPort 8081 -Action Allow + +$current_dir = Get-Location +Write-Host $current_dir + +# Config Env variable for Windows EC2 +Set-Location -Path "./asp_remote_service" +$env:CORECLR_ENABLE_PROFILING = "1" +$env:CORECLR_PROFILER = "{918728DD-259F-4A6A-AC2B-B85E1B658318}" +$env:CORECLR_PROFILER_PATH = "$current_dir\dotnet-distro\win-x64\OpenTelemetry.AutoInstrumentation.Native.dll" +$env:DOTNET_ADDITIONAL_DEPS = "$current_dir\dotnet-distro\AdditionalDeps" +$env:DOTNET_SHARED_STORE = "$current_dir\dotnet-distro\store" +$env:DOTNET_STARTUP_HOOKS = "$current_dir\dotnet-distro\net\OpenTelemetry.AutoInstrumentation.StartupHook.dll" +$env:OTEL_DOTNET_AUTO_HOME = "$current_dir\dotnet-distro" +$env:OTEL_DOTNET_AUTO_PLUGINS = "AWS.Distro.OpenTelemetry.AutoInstrumentation.Plugin, AWS.Distro.OpenTelemetry.AutoInstrumentation" +$env:OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf" +$env:OTEL_EXPORTER_OTLP_ENDPOINT = "http://127.0.0.1:4316" +$env:OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT = "http://127.0.0.1:4316/v1/metrics" +$env:OTEL_METRICS_EXPORTER = "none" +$env:OTEL_RESOURCE_ATTRIBUTES = "service.name=dotnet-sample-remote-application-$TestId" +$env:OTEL_AWS_APPLICATION_SIGNALS_ENABLED = "true" +$env:OTEL_TRACES_SAMPLER = "always_on" +$env:ASPNETCORE_URLS = "http://0.0.0.0:8081" + + +dotnet build + + +Start-Process -FilePath "dotnet" -ArgumentList "bin/Debug/netcoreapp8.0/asp_remote_service.dll" + + +Write-Host "Start Sleep" +Start-Sleep -Seconds 30 +Write-Host "Exiting" +exit \ No newline at end of file diff --git a/terraform/dotnet/ec2/windows/main.tf b/terraform/dotnet/ec2/windows/main.tf new file mode 100644 index 000000000..7c45d0d25 --- /dev/null +++ b/terraform/dotnet/ec2/windows/main.tf @@ -0,0 +1,221 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + } + } +} + +provider "aws" {} + +resource "aws_default_vpc" "default" {} + +resource "tls_private_key" "ssh_key" { + algorithm = "RSA" + rsa_bits = 4096 +} + +resource "aws_key_pair" "aws_ssh_key" { + key_name = "instance_key-${var.test_id}" + public_key = tls_private_key.ssh_key.public_key_openssh +} + +data "aws_ami" "ami" { + owners = ["amazon"] + most_recent = true + filter { + name = "name" + values = ["Windows_Server-2022-English-Full-Base-*"] + } + filter { + name = "state" + values = ["available"] + } + filter { + name = "architecture" + values = ["x86_64"] + } + filter { + name = "image-type" + values = ["machine"] + } + + filter { + name = "root-device-name" + values = ["/dev/sda1"] + } + + filter { + name = "root-device-type" + values = ["ebs"] + } + + filter { + name = "virtualization-type" + values = ["hvm"] + } +} + +locals { + ssh_key_name = aws_key_pair.aws_ssh_key.key_name + private_key_content = tls_private_key.ssh_key.private_key_pem +} + +resource "aws_instance" "main_service_instance" { + ami = data.aws_ami.ami.id + instance_type = "t3.large" + key_name = local.ssh_key_name + iam_instance_profile = "APP_SIGNALS_EC2_TEST_ROLE" + vpc_security_group_ids = [aws_default_vpc.default.default_security_group_id] + associate_public_ip_address = true + instance_initiated_shutdown_behavior = "terminate" + metadata_options { + http_tokens = "required" + } + get_password_data = true + + tags = { + Name = "main-service-${var.test_id}" + } + + user_data = <<-EOF + + Write-Host "Block RDP" + Get-NetFirewallRule -DisplayName "Remote Desktop - User Mode (TCP-In)" | Set-NetFirewallRule -Enabled False + Get-Service -Name TermService | Select-Object -ExpandProperty DependentServices | ForEach-Object { Stop-Service -Name $_.Name -Force } + Stop-Service -Name TermService -Force + Set-Service -Name TermService -StartupType Disabled + msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi /qn + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") + $awsCliInstalled = Get-Command aws -ErrorAction SilentlyContinue + + while (-not $awsCliInstalled) { + Write-Host "Waiting for AWS CLI" + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") + $awsCliInstalled = Get-Command aws -ErrorAction SilentlyContinue + Write-Host "Waiting" + Start-Sleep -Seconds 5 + } + Write-Host "AWS CLI Installed" + Write-Host "Finish execution" + + true + EOF +} + +resource "aws_instance" "remote_service_instance" { + ami = data.aws_ami.ami.id + instance_type = "t3.large" + key_name = local.ssh_key_name + iam_instance_profile = "APP_SIGNALS_EC2_TEST_ROLE" + vpc_security_group_ids = [aws_default_vpc.default.default_security_group_id] + associate_public_ip_address = true + instance_initiated_shutdown_behavior = "terminate" + metadata_options { + http_tokens = "required" + } + get_password_data = true + + tags = { + Name = "remote-service-${var.test_id}" + } + + user_data = <<-EOF + + Write-Host "Block RDP" + Get-NetFirewallRule -DisplayName "Remote Desktop - User Mode (TCP-In)" | Set-NetFirewallRule -Enabled False + Get-Service -Name TermService | Select-Object -ExpandProperty DependentServices | ForEach-Object { Stop-Service -Name $_.Name -Force } + Stop-Service -Name TermService -Force + Set-Service -Name TermService -StartupType Disabled + msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi /qn + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") + $awsCliInstalled = Get-Command aws -ErrorAction SilentlyContinue + + while (-not $awsCliInstalled) { + Write-Host "Waiting for AWS CLI" + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") + $awsCliInstalled = Get-Command aws -ErrorAction SilentlyContinue + Write-Host "Waiting" + Start-Sleep -Seconds 5 + } + Write-Host "AWS CLI Installed" + Write-Host "Finish execution" + + true + EOF +} + +# Create SSM Document for main service setup +resource "aws_ssm_document" "main_service_setup" { + name = "main_service_setup_${var.test_id}" + document_type = "Command" + + content = <<-DOC + { + "schemaVersion": "2.2", + "description": "Setup main service instance", + "mainSteps": [ + { + "action": "aws:runPowerShellScript", + "name": "setupMainService", + "inputs": { + "runCommand": [ + "aws s3 cp s3://aws-appsignals-sample-app-prod-${var.aws_region}/amazon-cloudwatch-agent.json ./amazon-cloudwatch-agent.json", + "powershell -Command \"(Get-Content -Path 'amazon-cloudwatch-agent.json') -replace 'REGION', 'us-east-1' | Set-Content -Path 'amazon-cloudwatch-agent.json'\"", + "aws s3 cp s3://aws-appsignals-sample-app-prod-${var.aws_region}/dotnet-ec2-win-main-setup.ps1 ./dotnet-ec2-win-main-setup.ps1", + "powershell -ExecutionPolicy Bypass -File ./dotnet-ec2-win-main-setup.ps1 -GetCloudwatchAgentCommand \"${var.get_cw_agent_msi_command}\" -GetAdotDistroCommand \"${var.get_adot_distro_command}\" -GetSampleAppCommand \"${var.sample_app_zip}\" -TestId \"${var.test_id}\" -RemoteServicePrivateEndpoint \"${aws_instance.remote_service_instance.private_ip}\" -AWSRegion \"${var.aws_region}\"" + ] + } + } + ] + } + DOC +} + +# Create SSM Association for main service instance +resource "aws_ssm_association" "main_service_association" { + name = aws_ssm_document.main_service_setup.name + targets { + key = "InstanceIds" + values = [aws_instance.main_service_instance.id] + } + + depends_on = [aws_instance.main_service_instance] +} + +# Create SSM Document for remote service setup +resource "aws_ssm_document" "remote_service_setup" { + name = "remote_service_setup_${var.test_id}" + document_type = "Command" + + content = <<-DOC + { + "schemaVersion": "2.2", + "description": "Setup remote service instance", + "mainSteps": [ + { + "action": "aws:runPowerShellScript", + "name": "setupRemoteService", + "inputs": { + "runCommand": [ + "aws s3 cp s3://aws-appsignals-sample-app-prod-${var.aws_region}/amazon-cloudwatch-agent.json ./amazon-cloudwatch-agent.json", + "powershell -Command \"(Get-Content -Path 'amazon-cloudwatch-agent.json') -replace 'REGION', 'us-east-1' | Set-Content -Path 'amazon-cloudwatch-agent.json'\"", + "aws s3 cp s3://aws-appsignals-sample-app-prod-${var.aws_region}/dotnet-ec2-win-remote-setup.ps1 ./dotnet-ec2-win-remote-setup.ps1", + "powershell -ExecutionPolicy Bypass -File ./dotnet-ec2-win-remote-setup.ps1 -GetCloudwatchAgentCommand \"${var.get_cw_agent_msi_command}\" -GetAdotDistroCommand \"${var.get_adot_distro_command}\" -GetSampleAppCommand \"${var.sample_app_zip}\" -TestId \"${var.test_id}\"" + ] + } + } + ] + } + DOC +} + +# Create SSM Association for remote service instance +resource "aws_ssm_association" "remote_service_association" { + name = aws_ssm_document.remote_service_setup.name + targets { + key = "InstanceIds" + values = [aws_instance.remote_service_instance.id] + } + depends_on = [aws_instance.remote_service_instance] +} \ No newline at end of file diff --git a/terraform/dotnet/ec2/windows/output.tf b/terraform/dotnet/ec2/windows/output.tf new file mode 100644 index 000000000..5853d05ce --- /dev/null +++ b/terraform/dotnet/ec2/windows/output.tf @@ -0,0 +1,38 @@ +# ------------------------------------------------------------------------ +# Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. +# ------------------------------------------------------------------------- + +output "sample_app_remote_service_private_ip" { + value = aws_instance.remote_service_instance.private_ip +} + +output "main_service_instance_id" { + value = aws_instance.main_service_instance.id +} + +output "remote_service_instance_id" { + value = aws_instance.remote_service_instance.id +} + +output "ec2_instance_ami" { + value = data.aws_ami.ami.id +} + +output "frontend_script_association_id" { + value = aws_ssm_association.main_service_association.id +} + +output "remote_script_association_id" { + value = aws_ssm_association.remote_service_association.id +} \ No newline at end of file diff --git a/terraform/dotnet/ec2/windows/variables.tf b/terraform/dotnet/ec2/windows/variables.tf new file mode 100644 index 000000000..10a6f5310 --- /dev/null +++ b/terraform/dotnet/ec2/windows/variables.tf @@ -0,0 +1,38 @@ +# ------------------------------------------------------------------------ +# Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. +# ------------------------------------------------------------------------- + +variable "test_id" { + default = "windows-e2e-test-0" +} + +variable "aws_region" { + default = "" +} + +variable "user" { + default = "ec2-user" +} + +variable "sample_app_zip" { + default = "wget -O ./dotnet-sample-app.zip https://github.com/aws-observability/aws-application-signals-test-framework/raw/dotnetE2ETests/sample-apps/dotnet/dotnet-sample-app.zip" +} + +variable "get_adot_distro_command" { + default = "wget -O ./aws-distro-opentelemetry-dotnet-instrumentation-windows.zip https://github.com/aws-observability/aws-otel-dotnet-instrumentation/releases/download/v1.1.0/aws-distro-opentelemetry-dotnet-instrumentation-windows.zip; Expand-Archive -Path ./aws-distro-opentelemetry-dotnet-instrumentation-windows.zip -DestinationPath ./dotnet-distro -Force" +} + +variable "get_cw_agent_msi_command" { + default = "wget -O ./amazon-cloudwatch-agent.msi https://amazoncloudwatch-agent.s3.amazonaws.com/windows/amd64/latest/amazon-cloudwatch-agent.msi" +} \ No newline at end of file diff --git a/validator/src/main/java/com/amazon/aoc/fileconfigs/PredefinedExpectedTemplate.java b/validator/src/main/java/com/amazon/aoc/fileconfigs/PredefinedExpectedTemplate.java index ad249dfc5..cac95b465 100644 --- a/validator/src/main/java/com/amazon/aoc/fileconfigs/PredefinedExpectedTemplate.java +++ b/validator/src/main/java/com/amazon/aoc/fileconfigs/PredefinedExpectedTemplate.java @@ -194,6 +194,27 @@ public enum PredefinedExpectedTemplate implements FileConfig { DOTNET_EC2_DEFAULT_CLIENT_CALL_METRIC("/expected-data-template/dotnet/ec2/default/client-call-metric.mustache"), DOTNET_EC2_DEFAULT_CLIENT_CALL_TRACE("/expected-data-template/dotnet/ec2/default/client-call-trace.mustache"), + /** DotNet EC2 Windows Default Test Case Validations */ + DOTNET_EC2_WINDOWS_DEFAULT_OUTGOING_HTTP_CALL_LOG( + "/expected-data-template/dotnet/ec2/windows/outgoing-http-call-log.mustache"), + DOTNET_EC2_WINDOWS_DEFAULT_OUTGOING_HTTP_CALL_METRIC( + "/expected-data-template/dotnet/ec2/windows/outgoing-http-call-metric.mustache"), + DOTNET_EC2_WINDOWS_DEFAULT_OUTGOING_HTTP_CALL_TRACE( + "/expected-data-template/dotnet/ec2/windows/outgoing-http-call-trace.mustache"), + + DOTNET_EC2_WINDOWS_DEFAULT_AWS_SDK_CALL_LOG("/expected-data-template/dotnet/ec2/windows/aws-sdk-call-log.mustache"), + DOTNET_EC2_WINDOWS_DEFAULT_AWS_SDK_CALL_METRIC("/expected-data-template/dotnet/ec2/windows/aws-sdk-call-metric.mustache"), + DOTNET_EC2_WINDOWS_DEFAULT_AWS_SDK_CALL_TRACE("/expected-data-template/dotnet/ec2/windows/aws-sdk-call-trace.mustache"), + + DOTNET_EC2_WINDOWS_DEFAULT_REMOTE_SERVICE_LOG("/expected-data-template/dotnet/ec2/windows/remote-service-log.mustache"), + DOTNET_EC2_WINDOWS_DEFAULT_REMOTE_SERVICE_METRIC("/expected-data-template/dotnet/ec2/windows/remote-service-metric.mustache"), +// Because of a time sync issue, block the remote service trace check for now +// DOTNET_EC2_WINDOWS_DEFAULT_REMOTE_SERVICE_TRACE("/expected-data-template/dotnet/ec2/windows/remote-service-trace.mustache"), + + DOTNET_EC2_WINDOWS_DEFAULT_CLIENT_CALL_LOG("/expected-data-template/dotnet/ec2/windows/client-call-log.mustache"), + DOTNET_EC2_WINDOWS_DEFAULT_CLIENT_CALL_METRIC("/expected-data-template/dotnet/ec2/windows/client-call-metric.mustache"), + DOTNET_EC2_WINDOWS_DEFAULT_CLIENT_CALL_TRACE("/expected-data-template/dotnet/ec2/windows/client-call-trace.mustache"), + /** DotNet EC2 Asg Test Case Validations */ DOTNET_EC2_ASG_OUTGOING_HTTP_CALL_LOG("/expected-data-template/dotnet/ec2/asg/outgoing-http-call-log.mustache"), DOTNET_EC2_ASG_OUTGOING_HTTP_CALL_METRIC("/expected-data-template/dotnet/ec2/asg/outgoing-http-call-metric.mustache"), diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/aws-sdk-call-log.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/aws-sdk-call-log.mustache new file mode 100644 index 000000000..06f8fadda --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/aws-sdk-call-log.mustache @@ -0,0 +1,20 @@ +[{ + "EC2.InstanceId": "^{{instanceId}}$", + "Environment": "^ec2:default$", + "PlatformType": "^AWS::EC2$", + "Operation": "GET /aws-sdk-call", + "Version": "^1$", + "Telemetry.Source": "^LocalRootSpan$", + "Host": "^ip(-[0-9]{1,3}){4}.*$" +}, +{ + "EC2.InstanceId": "^{{instanceId}}$", + "Environment": "^ec2:default$", + "PlatformType": "^AWS::EC2$", + "Operation": "GET /aws-sdk-call", + "Version": "^1$", + "RemoteService": "AWS::S3", + "RemoteOperation": "GetBucketLocation", + "Telemetry.Source": "^ClientSpan$", + "Host": "^ip(-[0-9]{1,3}){4}.*$" +}] \ No newline at end of file diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/aws-sdk-call-metric.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/aws-sdk-call-metric.mustache new file mode 100644 index 000000000..22d8da7a7 --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/aws-sdk-call-metric.mustache @@ -0,0 +1,374 @@ +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /aws-sdk-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /aws-sdk-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: AWS::S3 + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /aws-sdk-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + - + name: RemoteResourceIdentifier + value: {{testingId}} + - + name: RemoteResourceType + value: AWS::S3::Bucket + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + - + name: RemoteResourceIdentifier + value: {{testingId}} + - + name: RemoteResourceType + value: AWS::S3::Bucket + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /aws-sdk-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /aws-sdk-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: AWS::S3 + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /aws-sdk-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + - + name: RemoteResourceIdentifier + value: {{testingId}} + - + name: RemoteResourceType + value: AWS::S3::Bucket + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + - + name: RemoteResourceIdentifier + value: {{testingId}} + - + name: RemoteResourceType + value: AWS::S3::Bucket + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /aws-sdk-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /aws-sdk-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: AWS::S3 + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /aws-sdk-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + - + name: RemoteResourceIdentifier + value: {{testingId}} + - + name: RemoteResourceType + value: AWS::S3::Bucket + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GetBucketLocation + - + name: RemoteService + value: AWS::S3 + - + name: RemoteResourceIdentifier + value: {{testingId}} + - + name: RemoteResourceType + value: AWS::S3::Bucket \ No newline at end of file diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/aws-sdk-call-trace.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/aws-sdk-call-trace.mustache new file mode 100644 index 000000000..ef4a9759a --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/aws-sdk-call-trace.mustache @@ -0,0 +1,56 @@ +[{ + "name": "^{{serviceName}}$", + "http": { + "request": { + "url": "^{{endpoint}}/aws-sdk-call$", + "method": "^GET$" + } + }, + "aws": { + "account_id": "^{{accountId}}$" + }, + "annotations": { + "aws.local.service": "^{{serviceName}}$", + "aws.local.operation": "^GET /aws-sdk-call$", + "aws.local.environment": "^ec2:default$" + }, + "metadata": { + "default": { + "EC2.InstanceId": "^{{instanceId}}$", + "PlatformType": "^AWS::EC2$", + "otel.resource.host.image.id": "^{{instanceAmi}}$", + "otel.resource.host.type": "^t3.large$", + "aws.span.kind": "^LOCAL_ROOT$" + } + }, + "subsegments": [ + { + "name": "^S3$", + "aws": { + "operation": "^GetBucketLocation$" + }, + "annotations": { + "aws.local.service": "^{{serviceName}}$", + "aws.local.operation": "^GET /aws-sdk-call$", + "aws.remote.service": "^AWS::S3$", + "aws.remote.operation": "^GetBucketLocation$", + "aws.local.environment": "^ec2:default$", + "aws.remote.resource.type": "AWS::S3::Bucket" + }, + "metadata": { + "default": { + "EC2.InstanceId": "^{{instanceId}}$", + "PlatformType": "^AWS::EC2$", + "aws.span.kind": "^CLIENT$" + } + }, + "namespace": "^aws$" + } + ] +}, +{ + "name": "^S3$", + "aws": { + "operation": "^GetBucketLocation$" + } +}] \ No newline at end of file diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/client-call-log.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/client-call-log.mustache new file mode 100644 index 000000000..85036f4da --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/client-call-log.mustache @@ -0,0 +1,20 @@ +[{ + "EC2.InstanceId": "^{{instanceId}}$", + "Environment": "^ec2:default$", + "PlatformType": "^AWS::EC2$", + "Operation": "InternalOperation", + "Version": "^1$", + "Telemetry.Source": "^LocalRootSpan$", + "Host": "^ip(-[0-9]{1,3}){4}.*$" +}, +{ + "EC2.InstanceId": "^{{instanceId}}$", + "Environment": "^ec2:default$", + "PlatformType": "^AWS::EC2$", + "Operation": "InternalOperation", + "Version": "^1$", + "RemoteService": "local-root-client-call:80", + "RemoteOperation": "GET /", + "Telemetry.Source": "^ClientSpan$", + "Host": "^ip(-[0-9]{1,3}){4}.*$" +}] \ No newline at end of file diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/client-call-metric.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/client-call-metric.mustache new file mode 100644 index 000000000..85ed2565c --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/client-call-metric.mustache @@ -0,0 +1,227 @@ +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Operation + value: InternalOperation + - + name: Environment + value: ec2:default + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Operation + value: InternalOperation + - + name: Environment + value: ec2:default + - + name: RemoteService + value: local-root-client-call:80 + - + name: RemoteOperation + value: GET / + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: local-root-client-call:80 + - + name: RemoteOperation + value: GET / + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: local-root-client-call:80 + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Operation + value: InternalOperation + - + name: Environment + value: ec2:default + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Operation + value: InternalOperation + - + name: Environment + value: ec2:default + - + name: RemoteService + value: local-root-client-call:80 + - + name: RemoteOperation + value: GET / + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: local-root-client-call:80 + - + name: RemoteOperation + value: GET / + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: local-root-client-call:80 + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Operation + value: InternalOperation + - + name: Environment + value: ec2:default + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Operation + value: InternalOperation + - + name: Environment + value: ec2:default + - + name: RemoteService + value: local-root-client-call:80 + - + name: RemoteOperation + value: GET / + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: local-root-client-call:80 + - + name: RemoteOperation + value: GET / + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: local-root-client-call:80 \ No newline at end of file diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/client-call-trace.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/client-call-trace.mustache new file mode 100644 index 000000000..9ab62e784 --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/client-call-trace.mustache @@ -0,0 +1,56 @@ +[{ + "name": "^{{serviceName}}$", + "annotations": { + "aws.local.service": "^{{serviceName}}$", + "aws.local.operation": "^InternalOperation$", + "aws.local.environment": "^ec2:default$" + }, + "metadata": { + "default": { + "otel.resource.host.image.id": "^{{instanceAmi}}$", + "otel.resource.host.type": "^t3.large$" + } + }, + "subsegments": [ + { + "name": "^local-root-client-call:80$", + "http": { + "request": { + "url": "^http://local-root-client-call/$", + "method": "^GET$" + } + }, + "annotations": { + "aws.local.service": "^{{serviceName}}$", + "aws.local.operation": "^InternalOperation$", + "aws.remote.service": "^local-root-client-call:80$", + "aws.remote.operation": "GET /", + "aws.local.environment": "^ec2:default$" + }, + "metadata": { + "default": { + "EC2.InstanceId": "^{{instanceId}}$", + "PlatformType": "^AWS::EC2$", + "aws.span.kind": "^LOCAL_ROOT$" + } + }, + "namespace": "^remote$" + } + ] +}, +{ + "name": "^local-root-client-call:80$", + "http": { + "request": { + "url": "^http://local-root-client-call/$", + "method": "^GET$" + }, + "response": { + "content_length": 0 + } + }, + "annotations": { + "aws.local.service": "^local-root-client-call:80$", + "aws.local.operation": "^GET /$" + } +}] \ No newline at end of file diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/outgoing-http-call-log.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/outgoing-http-call-log.mustache new file mode 100644 index 000000000..848e84902 --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/outgoing-http-call-log.mustache @@ -0,0 +1,20 @@ +[{ + "EC2.InstanceId": "^{{instanceId}}$", + "Environment": "^ec2:default$", + "PlatformType": "^AWS::EC2$", + "Operation": "GET /outgoing-http-call", + "Version": "^1$", + "Telemetry.Source": "^LocalRootSpan$", + "Host": "^ip(-[0-9]{1,3}){4}.*$" +}, +{ + "EC2.InstanceId": "^{{instanceId}}$", + "Environment": "^ec2:default$", + "PlatformType": "^AWS::EC2$", + "Operation": "GET /outgoing-http-call", + "Version": "^1$", + "RemoteService": "aws.amazon.com:443", + "RemoteOperation": "GET /", + "Telemetry.Source": "^ClientSpan$", + "Host": "^ip(-[0-9]{1,3}){4}.*$" +}] \ No newline at end of file diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/outgoing-http-call-metric.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/outgoing-http-call-metric.mustache new file mode 100644 index 000000000..748e05178 --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/outgoing-http-call-metric.mustache @@ -0,0 +1,227 @@ +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /outgoing-http-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /outgoing-http-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET / + - + name: RemoteService + value: aws.amazon.com:443 + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET / + - + name: RemoteService + value: aws.amazon.com:443 + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: aws.amazon.com:443 + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /outgoing-http-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /outgoing-http-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET / + - + name: RemoteService + value: aws.amazon.com:443 + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET / + - + name: RemoteService + value: aws.amazon.com:443 + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: aws.amazon.com:443 + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /outgoing-http-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /outgoing-http-call + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET / + - + name: RemoteService + value: aws.amazon.com:443 + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET / + - + name: RemoteService + value: aws.amazon.com:443 + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: aws.amazon.com:443 diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/outgoing-http-call-trace.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/outgoing-http-call-trace.mustache new file mode 100644 index 000000000..44a9c334b --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/outgoing-http-call-trace.mustache @@ -0,0 +1,55 @@ +[{ + "name": "^{{serviceName}}$", + "http": { + "request": { + "url": "^{{endpoint}}/outgoing-http-call$", + "method": "^GET$" + } + }, + "aws": { + "account_id": "^{{accountId}}$" + }, + "annotations": { + "aws.local.service": "^{{serviceName}}$", + "aws.local.operation": "^GET /outgoing-http-call$", + "aws.local.environment": "^ec2:default$" + }, + "metadata": { + "default": { + "EC2.InstanceId": "^{{instanceId}}$", + "PlatformType": "^AWS::EC2$", + "otel.resource.host.image.id": "^{{instanceAmi}}$", + "otel.resource.host.type": "^t3.large$", + "aws.span.kind": "^LOCAL_ROOT$" + } + }, + "subsegments": [ + { + "name": "^aws.amazon.com:443$", + "http": { + "request": { + "url": "^https://aws.amazon.com/$", + "method": "^GET$" + } + }, + "annotations": { + "aws.local.service": "^{{serviceName}}$", + "aws.local.operation": "^GET /outgoing-http-call$", + "aws.remote.service": "^aws.amazon.com:443$", + "aws.remote.operation": "^GET /$", + "aws.local.environment": "^ec2:default$" + }, + "metadata": { + "default": { + "EC2.InstanceId": "^{{instanceId}}$", + "PlatformType": "^AWS::EC2$", + "aws.span.kind": "^CLIENT$" + } + }, + "namespace": "^remote$" + } + ] +}, +{ + "name": "^aws.amazon.com:443$" +}] diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/remote-service-log.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/remote-service-log.mustache new file mode 100644 index 000000000..cd457dc7b --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/remote-service-log.mustache @@ -0,0 +1,20 @@ +[{ + "EC2.InstanceId": "^{{instanceId}}$", + "Environment": "^ec2:default$", + "PlatformType": "^AWS::EC2$", + "Operation": "GET /remote-service", + "Version": "^1$", + "Telemetry.Source": "^LocalRootSpan$", + "Host": "^ip(-[0-9]{1,3}){4}.*$" +}, +{ + "EC2.InstanceId": "^{{instanceId}}$", + "Environment": "^ec2:default$", + "PlatformType": "^AWS::EC2$", + "Operation": "GET /remote-service", + "Version": "^1$", + "RemoteService": "{{remoteServiceDeploymentName}}", + "RemoteOperation": "GET /healthcheck", + "Telemetry.Source": "^ClientSpan$", + "Host": "^ip(-[0-9]{1,3}){4}.*$" +}] \ No newline at end of file diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/remote-service-metric.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/remote-service-metric.mustache new file mode 100644 index 000000000..bb5445d2f --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/remote-service-metric.mustache @@ -0,0 +1,312 @@ +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /remote-service + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /remote-service + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET /healthcheck + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{remoteServiceName}} + - + name: Environment + value: ec2:default + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET /healthcheck + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Latency + namespace: {{metricNamespace}} + dimensions: + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /remote-service + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /remote-service + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET /healthcheck + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Environment + value: ec2:default + - + name: Operation + value: GET /healthcheck + - + name: Service + value: {{remoteServiceName}} + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{remoteServiceName}} + - + name: Environment + value: ec2:default + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET /healthcheck + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Error + namespace: {{metricNamespace}} + dimensions: + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /remote-service + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Operation + value: GET /remote-service + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET /healthcheck + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Environment + value: ec2:default + - + name: Operation + value: GET /healthcheck + - + name: Service + value: {{remoteServiceName}} + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{remoteServiceName}} + - + name: Environment + value: ec2:default + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: Service + value: {{serviceName}} + - + name: Environment + value: ec2:default + - + name: RemoteOperation + value: GET /healthcheck + - + name: RemoteService + value: {{remoteServiceDeploymentName}} + +- + metricName: Fault + namespace: {{metricNamespace}} + dimensions: + - + name: RemoteService + value: {{remoteServiceDeploymentName}} diff --git a/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/remote-service-trace.mustache b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/remote-service-trace.mustache new file mode 100644 index 000000000..bd5d2404f --- /dev/null +++ b/validator/src/main/resources/expected-data-template/dotnet/ec2/windows/remote-service-trace.mustache @@ -0,0 +1,77 @@ +[{ + "name": "^{{serviceName}}$", + "http": { + "request": { + "url": "^{{endpoint}}/remote-service$", + "method": "^GET$" + } + }, + "aws": { + "account_id": "^{{accountId}}$" + }, + "annotations": { + "aws.local.service": "^{{serviceName}}$", + "aws.local.operation": "^GET /remote-service$", + "aws.local.environment": "^ec2:default$" + }, + "metadata": { + "default": { + "EC2.InstanceId": "^{{instanceId}}$", + "PlatformType": "^AWS::EC2$", + "otel.resource.host.image.id": "^{{instanceAmi}}$", + "otel.resource.host.type": "^t3.large$", + "aws.span.kind": "^LOCAL_ROOT$" + } + }, + "subsegments": [ + { + "name": "^{{remoteServiceDeploymentName}}$", + "http": { + "request": { + "url": "^http://(([0-9]{1,3}.){3}[0-9]{1,3}):8081/healthcheck$", + "method": "^GET$" + } + }, + "annotations": { + "aws.local.service": "^{{serviceName}}$", + "aws.local.operation": "^GET /remote-service$", + "aws.remote.service": "^{{remoteServiceDeploymentName}}$", + "aws.remote.operation": "^GET /healthcheck$", + "aws.local.environment": "^ec2:default$" + }, + "metadata": { + "default": { + "EC2.InstanceId": "^{{instanceId}}$", + "PlatformType": "^AWS::EC2$", + "aws.span.kind": "^CLIENT$" + } + }, + "namespace": "^remote$" + } + ] +}, +{ + "name": "^{{remoteServiceName}}$", + "http": { + "request": { + "url": "^http://(([0-9]{1,3}.){3}[0-9]{1,3}):8081/healthcheck$", + "method": "^GET$" + } + }, + "annotations": { + "aws.local.service": "^{{remoteServiceName}}$", + "aws.local.operation": "^GET /healthcheck$", + "aws.local.environment": "^ec2:default$" + }, + "metadata": { + "default": { + "EC2.InstanceId": "^i-[A-Za-z0-9]{17}$", + "PlatformType": "^AWS::EC2$", + "otel.resource.host.image.id": "^{{instanceAmi}}$", + "otel.resource.host.type": "^t3.large$", + "aws.span.kind": "^LOCAL_ROOT$" + } + } +}] + + diff --git a/validator/src/main/resources/validations/dotnet/ec2/windows/log-validation.yml b/validator/src/main/resources/validations/dotnet/ec2/windows/log-validation.yml new file mode 100644 index 000000000..3c91dc73c --- /dev/null +++ b/validator/src/main/resources/validations/dotnet/ec2/windows/log-validation.yml @@ -0,0 +1,25 @@ +- + validationType: "cw-log" + httpPath: "/outgoing-http-call" + httpMethod: "get" + callingType: "http" + expectedLogStructureTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_OUTGOING_HTTP_CALL_LOG" +- + validationType: "cw-log" + httpPath: "/aws-sdk-call" + httpMethod: "get" + callingType: "http-with-query" + expectedLogStructureTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_AWS_SDK_CALL_LOG" +- + validationType: "cw-log" + httpPath: "/remote-service" + httpMethod: "get" + callingType: "http-with-query" + expectedLogStructureTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_REMOTE_SERVICE_LOG" +- + validationType: "cw-log" + httpPath: "/client-call" + httpMethod: "get" + callingType: "http" + expectedLogStructureTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_CLIENT_CALL_LOG" + diff --git a/validator/src/main/resources/validations/dotnet/ec2/windows/metric-validation.yml b/validator/src/main/resources/validations/dotnet/ec2/windows/metric-validation.yml new file mode 100644 index 000000000..6ee4c7e86 --- /dev/null +++ b/validator/src/main/resources/validations/dotnet/ec2/windows/metric-validation.yml @@ -0,0 +1,25 @@ +- + validationType: "cw-metric" + httpPath: "/outgoing-http-call" + httpMethod: "get" + callingType: "http" + expectedMetricTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_OUTGOING_HTTP_CALL_METRIC" +- + validationType: "cw-metric" + httpPath: "/aws-sdk-call" + httpMethod: "get" + callingType: "http-with-query" + expectedMetricTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_AWS_SDK_CALL_METRIC" +- + validationType: "cw-metric" + httpPath: "/remote-service" + httpMethod: "get" + callingType: "http-with-query" + expectedMetricTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_REMOTE_SERVICE_METRIC" +- + validationType: "cw-metric" + httpPath: "/client-call" + httpMethod: "get" + callingType: "http" + expectedMetricTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_CLIENT_CALL_METRIC" + diff --git a/validator/src/main/resources/validations/dotnet/ec2/windows/trace-validation.yml b/validator/src/main/resources/validations/dotnet/ec2/windows/trace-validation.yml new file mode 100644 index 000000000..f9b96e830 --- /dev/null +++ b/validator/src/main/resources/validations/dotnet/ec2/windows/trace-validation.yml @@ -0,0 +1,26 @@ +- + validationType: "trace" + httpPath: "/outgoing-http-call" + httpMethod: "get" + callingType: "http" + expectedTraceTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_OUTGOING_HTTP_CALL_TRACE" +- + validationType: "trace" + httpPath: "/aws-sdk-call" + httpMethod: "get" + callingType: "http-with-query" + expectedTraceTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_AWS_SDK_CALL_TRACE" + +# Because of a time sync issue, block the remote service trace check for now +#- +# validationType: "trace" +# httpPath: "/remote-service" +# httpMethod: "get" +# callingType: "http-with-query" +# expectedTraceTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_REMOTE_SERVICE_TRACE" +- + validationType: "trace" + httpPath: "/client-call" + httpMethod: "get" + callingType: "http" + expectedTraceTemplate: "DOTNET_EC2_WINDOWS_DEFAULT_CLIENT_CALL_TRACE" \ No newline at end of file