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