Skip to content

Commit

Permalink
Add Integration Test For Metric Number Of Dimension (#451)
Browse files Browse the repository at this point in the history
  • Loading branch information
sethAmazon authored Apr 21, 2022
1 parent 2ece109 commit 8eb0d14
Show file tree
Hide file tree
Showing 14 changed files with 334 additions and 47 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/integrationTest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,8 @@ jobs:
path: go.mod
key: ec2-linux-integration-test-${{ github.sha }}-${{ matrix.arrays.os }}

- name: Echo OS
run: echo run on ec2 instance os ${{ matrix.arrays.os }}
- name: Echo Test Info
run: echo run on ec2 instance os ${{ matrix.arrays.os }} test dir ${{ matrix.arrays.test_dir }}

- name: Verify Terraform version
run: terraform --version
Expand Down Expand Up @@ -392,7 +392,7 @@ jobs:
-var="key_name=${KEY_NAME}" \
-var="test_name=cw-integ-test-${{ matrix.arrays.os }}" \
-var="iam_instance_profile=${IAM_ROLE}" \
-var="tag=${{ matrix.arrays.tag }}" ; then terraform destroy -auto-approve
-var="test_dir=${{ matrix.arrays.test_dir }}" ; then terraform destroy -auto-approve
else
terraform destroy -auto-approve && exit 1
fi
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ require (
github.com/aws/aws-sdk-go-v2 v1.16.2
github.com/aws/aws-sdk-go-v2/config v1.15.3
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.18.1
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.15.4
github.com/aws/aws-sdk-go-v2/service/ec2 v1.29.0
github.com/aws/smithy-go v1.11.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3 h1:9stUQR/u2KXU6HkFJYl
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10 h1:by9P+oy3P/CwggN4ClnW2D4oL91QV7pBzBICi1chZvQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10/go.mod h1:8DcYQcz0+ZJaSxANlHIsbbi6S+zMwjwdDqwW3r9AzaE=
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.18.1 h1:8PHGmLw1QbTdXfgEpXclOk3kob72vkc/cEoyBxkmR0M=
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.18.1/go.mod h1:Z+8JhhltQDM1vIHvEtQLr1wVVAqQVLpvCDMVqYBrwr8=
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.15.4 h1:mBqjBKtZzvAc9j7gU+FEHbhTKSr02iqMOdQIL/7GZ78=
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.15.4/go.mod h1:R49Py2lGoKH7bCpwhjN9l7MfR/PU6zHXn1tCRR8cwOs=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.29.0 h1:7jk4NfzDnnSbaR9E4mOBWRZXQThq5rsqjlDC+uu9dsI=
Expand Down
25 changes: 14 additions & 11 deletions integration/generator/test_case_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,27 @@ const (
linux = "linux"
windows = "windows"
mac = "mac"
tag = "tag"
testDir = "test_dir"
)

//you can't have a const map in golang
var osToTagMap = map[string][]string{
linux: {"integration"},
windows: {},
var osToTestDirMap = map[string][]string{
linux: {"./integration/test/ca_bundle",
"./integration/test/cloudwatchlogs",
"./integration/test/metrics_number_dimension"},
// @TODO add real tests
windows: {""},
mac: {},
}

func main() {
for osType, tags := range osToTagMap {
testMatrix := genMatrix(osType, tags)
for osType, testDir := range osToTestDirMap {
testMatrix := genMatrix(osType, testDir)
writeTestMatrixFile(osType, testMatrix)
}
}

func genMatrix(targetOS string, tags []string) []map[string]string {
func genMatrix(targetOS string, testDirList []string) []map[string]string {
openTestMatrix, err := os.Open(fmt.Sprintf("integration/generator/resources/%v_test_matrix.json", targetOS))
if err != nil {
log.Panicf("can't read file %v_test_matrix.json err %v", targetOS, err)
Expand All @@ -47,11 +50,11 @@ func genMatrix(targetOS string, tags []string) []map[string]string {

var testMatrixComplete []map[string]string
for _, test := range testMatrix {
testLine := copyMap(test)
for _, testTag := range tags {
testLine[tag] = testTag
for _, testDirectory := range testDirList {
testLine := copyMap(test)
testLine[testDir] = testDirectory
testMatrixComplete = append(testMatrixComplete, testLine)
}
testMatrixComplete = append(testMatrixComplete, testLine)
}
return testMatrixComplete
}
Expand Down
1 change: 1 addition & 0 deletions integration/terraform/ec2/linux/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ for how to easily generate a new policy.
"Action": [
"cloudwatch:GetMetricData",
"cloudwatch:PutMetricData",
"cloudwatch:ListMetrics"
"ec2:DescribeVolumes",
"ec2:DescribeTags",
"logs:PutLogEvents",
Expand Down
3 changes: 2 additions & 1 deletion integration/terraform/ec2/linux/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ resource "aws_instance" "integration-test" {
"export AWS_REGION=${var.region}",
"echo run tests with the tag integration, one at a time, and verbose",
"cd ~/amazon-cloudwatch-agent",
"go test ./integration/test/... -p 1 -v --tags=${var.tag}"
"echo run sanity test && go test ./integration/test/sanity -p 1 -v --tags=integration",
"go test ${var.test_dir} -p 1 -v --tags=integration"
]
connection {
type = "ssh"
Expand Down
2 changes: 1 addition & 1 deletion integration/terraform/ec2/linux/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ variable "test_name" {
default = ""
}

variable "tag" {
variable "test_dir" {
type = string
default = ""
}
29 changes: 29 additions & 0 deletions integration/test/agent_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
package test

import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
"log"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -93,3 +97,28 @@ func ReplaceLocalStackHostName(pathIn string) {
log.Fatal(fmt.Sprint(err) + string(out))
}
}

func GetInstanceId() string {
ctx := context.Background()
c, err := config.LoadDefaultConfig(ctx)
if err != nil {
// fail fast so we don't continue the test
log.Fatalf("Error occurred while creating SDK config: %v", err)
}

// TODO: this only works for EC2 based testing
client := imds.NewFromConfig(c)
metadata, err := client.GetInstanceIdentityDocument(ctx, &imds.GetInstanceIdentityDocumentInput{})
if err != nil {
log.Fatalf("Error occurred while retrieving EC2 instance ID: %v", err)
}
return metadata.InstanceID
}

func GetCWClient(cxt context.Context) *cloudwatch.Client {
defaultConfig, err := config.LoadDefaultConfig(cxt)
if err != nil {
log.Fatalf("err occurred while creating config %v", err)
}
return cloudwatch.NewFromConfig(defaultConfig)
}
18 changes: 1 addition & 17 deletions integration/test/cloudwatchlogs/publish_logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@
package cloudwatchlogs

import (
"context"
"fmt"
"github.com/aws/amazon-cloudwatch-agent/integration/test"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
"log"
"os"

Expand Down Expand Up @@ -54,20 +51,7 @@ var testParameters = []input{
func TestWriteLogsToCloudWatch(t *testing.T) {
// this uses the {instance_id} placeholder in the agent configuration,
// so we need to determine the host's instance ID for validation
ctx := context.Background()
c, err := config.LoadDefaultConfig(ctx)
if err != nil {
// fail fast so we don't continue the test
t.Fatalf("Error occurred while creating SDK config: %v", err)
}

// TODO: this only works for EC2 based testing
client := imds.NewFromConfig(c)
metadata, err := client.GetInstanceIdentityDocument(ctx, &imds.GetInstanceIdentityDocumentInput{})
if err != nil {
t.Fatalf("Error occurred while retrieving EC2 instance ID: %v", err)
}
instanceId := metadata.InstanceID
instanceId := test.GetInstanceId()
log.Printf("Found instance id %s", instanceId)

defer cleanUp(instanceId)
Expand Down
14 changes: 0 additions & 14 deletions integration/test/empty/empty_test.go

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT

//go:build linux && integration
// +build linux,integration

package metrics_number_dimension

import (
"context"
"fmt"
"github.com/aws/amazon-cloudwatch-agent/integration/test"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
"log"
"strings"
"testing"
"time"
)

const configOutputPath = "/opt/aws/amazon-cloudwatch-agent/bin/config.json"
const configJSON = "/config.json"
const namespace = "MetricNumberDimensionTest"
const instanceId = "InstanceId"
const appendMetric = "append"

// @TODO use the value from plugins/outputs/cloudwatch/cloudwatch.go when https://github.com/aws/amazon-cloudwatch-agent/pull/361 is merged
const maxDimension = 30

//Let the agent run for 2 minutes. This will give agent enough time to call server
const agentRuntime = 2 * time.Minute

const targetString = "max MaxDimensions %v is less than than number of dimensions %v thus only taking the max number"

type input struct {
resourcePath string
findTarget bool
numberDimensionsInCW int
metricName string
}

type metric struct {
name string
value string
}

//Must run this test with parallel 1 since this will fail if more than one test is running at the same time
func TestNumberMetricDimension(t *testing.T) {

parameters := []input{
{
resourcePath: "resources/10_dimension",
findTarget: false,
numberDimensionsInCW: 10,
metricName: "mem_used_percent",
},
// @TODO add when https://github.com/aws/amazon-cloudwatch-agent/pull/361 is merged
// {resourcePath: "resources/30_dimension", findTarget: false, numberDimensionsInCW: 30, metricName: "mem_used_percent",},
// {resourcePath: "resources/35_dimension", findTarget: true, numberDimensionsInCW: 30, metricName: "mem_used_percent",},
}

for _, parameter := range parameters {
//before test run
log.Printf("resource file location %s find target %t input number dimension %d metric name %s",
parameter.resourcePath, parameter.findTarget, parameter.numberDimensionsInCW, parameter.metricName)

target := fmt.Sprintf(targetString, maxDimension, parameter.numberDimensionsInCW)

t.Run(fmt.Sprintf("resource file location %s find target %t", parameter.resourcePath, parameter.findTarget), func(t *testing.T) {
test.CopyFile(parameter.resourcePath+configJSON, configOutputPath)
test.StartAgent(configOutputPath)
time.Sleep(agentRuntime)
log.Printf("Agent has been running for : %s", agentRuntime.String())
test.StopAgent()

// test for target string
output := test.ReadAgentOutput(agentRuntime)
containsTarget := outputLogContainsTarget(output, target)
if (parameter.findTarget && !containsTarget) || (!parameter.findTarget && containsTarget) {
t.Errorf("Find target is %t contains target is %t", parameter.findTarget, containsTarget)
}

// test for cloud watch metrics
cxt := context.Background()
dimensionFilter := buildDimensionFilterList(parameter.numberDimensionsInCW)
client := test.GetCWClient(cxt)
listMetricsInput := cloudwatch.ListMetricsInput{
MetricName: aws.String(parameter.metricName),
Namespace: aws.String(namespace),
Dimensions: dimensionFilter,
}
data, err := client.ListMetrics(cxt, &listMetricsInput)
if err != nil {
t.Errorf("Error getting metric data %v", err)
}
if len(data.Metrics) == 0 {
metrics := make([]metric, len(dimensionFilter))
for i, filter := range dimensionFilter {
metrics[i] = metric{
name: *filter.Name,
value: *filter.Value,
}
}
t.Errorf("No metrics found for dimension %v metric name %v namespace %v",
metrics, parameter.metricName, namespace)
}
})
}
}

func buildDimensionFilterList(appendDimension int) []types.DimensionFilter {
// we append dimension from 0 to max number - 2
// then we add dimension instance id
// thus for max dimension 10, 0 to 8 + instance id = 10 dimension
ec2InstanceId := test.GetInstanceId()
dimensionFilter := make([]types.DimensionFilter, appendDimension)
for i := 0; i < appendDimension-1; i++ {
dimensionFilter[i] = types.DimensionFilter{
Name: aws.String(fmt.Sprintf("%s%d", appendMetric, i)),
Value: aws.String(fmt.Sprintf("%s%d", appendMetric, i)),
}
}
dimensionFilter[appendDimension-1] = types.DimensionFilter{
Name: aws.String(instanceId),
Value: aws.String(ec2InstanceId),
}
return dimensionFilter
}

func outputLogContainsTarget(output string, targetString string) bool {
log.Printf("Log file %s", output)
contains := strings.Contains(output, targetString)
log.Printf("Log file contains target string %t", contains)
return contains
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"agent": {
"metrics_collection_interval": 60,
"run_as_user": "root",
"debug": true,
"logfile": ""
},
"metrics": {
"namespace": "MetricNumberDimensionTest",
"append_dimensions": {
"InstanceId": "${aws:InstanceId}"
},
"metrics_collected": {
"mem": {
"measurement": [
"mem_used_percent"
],
"metrics_collection_interval": 60,
"append_dimensions": {
"append0": "append0",
"append1": "append1",
"append2": "append2",
"append3": "append3",
"append4": "append4",
"append5": "append5",
"append6": "append6",
"append7": "append7",
"append8": "append8"
}
}
}
}
}
Loading

0 comments on commit 8eb0d14

Please sign in to comment.