Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logs agent integ test #433

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
21aa051
update config files
varunch77 Nov 18, 2024
734f8e0
Add integ test for Logs agent
varunch77 Nov 18, 2024
5ed1a93
Have the agent sleep after starting it
varunch77 Nov 19, 2024
96522cd
update flush time to 90s
varunch77 Nov 19, 2024
b98c612
Update flush time to 120 seconds
varunch77 Nov 19, 2024
bdd40b9
Add delay to ensure tag deletion propagates
varunch77 Nov 19, 2024
43d2ca6
Change order of tests
varunch77 Nov 19, 2024
9f28f03
Change order of tests again
varunch77 Nov 19, 2024
e1bb9ce
Enable instance metadata tags
varunch77 Nov 19, 2024
fd59713
Clean up unused code
varunch77 Nov 19, 2024
6e00757
Differentiate sleep times
varunch77 Nov 19, 2024
bb229f7
Merge branch 'main' into add-logs-agent-integ-test
varunch77 Nov 19, 2024
84cc3d3
Address nits and make minor changes
varunch77 Nov 22, 2024
7a3b428
UGet region from EC2 metadata instead of hardcoding
varunch77 Nov 22, 2024
e37d84a
Revert EC2 metadata change
varunch77 Nov 22, 2024
79744f1
Revert EC2 metadata change
varunch77 Nov 22, 2024
7950725
Address misc comments
varunch77 Nov 22, 2024
37cb8a5
update code to search for log group directly
varunch77 Nov 22, 2024
006a057
Revert to search by prefix
varunch77 Nov 22, 2024
eb95406
address comments
varunch77 Dec 4, 2024
df7abce
remove unused packageS
varunch77 Dec 4, 2024
8dcc2d4
use clients from the awsservice package
varunch77 Dec 4, 2024
9f5722b
Merge remote-tracking branch 'origin/main' into add-logs-agent-integ-…
varunch77 Dec 4, 2024
6f1e4cf
Make ValidateEntity a common package
varunch77 Dec 4, 2024
5bd4a65
modify ValidateLogs to be a function in a common package
varunch77 Dec 4, 2024
d116feb
Merge remote-tracking branch 'origin/main' into add-logs-agent-integ-…
varunch77 Dec 4, 2024
6c272ee
Increase flush time
varunch77 Dec 5, 2024
58f0a88
run linter
varunch77 Dec 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 139 additions & 2 deletions test/cloudwatchlogs/publish_logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package cloudwatchlogs

import (
"context"
"fmt"
"log"
"os"
Expand All @@ -15,7 +16,11 @@ import (
"testing"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types"
"github.com/aws/aws-sdk-go-v2/service/ec2"
ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"

"github.com/aws/amazon-cloudwatch-agent-test/environment"
Expand All @@ -29,9 +34,18 @@ const (
logLineId2 = "bar"
logFilePath = "/tmp/cwagent_log_test.log" // TODO: not sure how well this will work on Windows
sleepForFlush = 20 * time.Second // default flush interval is 5 seconds
sleepForExtendedFlush = 180 * time.Second // increase flush time for the two main tests
retryWaitTime = 30 * time.Second
configPathAutoRemoval = "resources/config_auto_removal.json"
standardLogGroupClass = "STANDARD"
infrequentAccessLogGroupClass = "INFREQUENT_ACCESS"

entityType = "@entity.KeyAttributes.Type"
entityName = "@entity.KeyAttributes.Name"
entityEnvironment = "@entity.KeyAttributes.Environment"
entityPlatform = "@entity.Attributes.PlatformType"
entityInstanceId = "@entity.Attributes.EC2.InstanceId"
queryString = "fields @message, @entity.KeyAttributes.Type, @entity.KeyAttributes.Name, @entity.KeyAttributes.Environment, @entity.Attributes.PlatformType, @entity.Attributes.EC2.InstanceId"
)

var (
Expand Down Expand Up @@ -70,6 +84,7 @@ var (
logGroupClass: types.LogGroupClassInfrequentAccess,
},
}
resourceNotFoundException *types.ResourceNotFoundException
)

type writeToCloudWatchTestInput struct {
Expand Down Expand Up @@ -119,9 +134,9 @@ func TestWriteLogsToCloudWatch(t *testing.T) {

// ensure that there is enough time from the "start" time and the first log line,
// so we don't miss it in the GetLogEvents call
time.Sleep(sleepForFlush)
time.Sleep(sleepForExtendedFlush)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just increase sleepForFlush? Do we use sleepForFlush anywhere else in the code?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah we use sleepForFlush in other places too. For the other test cases, waiting for 180 seconds instead of 20 seconds would be overkill and sometimes results in a timeout as it can cause all the test cases in the file take over an hour to run. This is because we call sleepForFlush before and after the agent runs and some of the test cases are set to loop multiple times so this extra 160 seconds adds up quickly. We only want the tests to wait for 180 seconds in two places, which is why I just created another variable.

writeLogLines(t, f, param.iterations)
time.Sleep(sleepForFlush)
time.Sleep(sleepForExtendedFlush)
common.StopAgent()
end := time.Now()

Expand All @@ -139,6 +154,128 @@ func TestWriteLogsToCloudWatch(t *testing.T) {
}
}

// TestWriteLogsWithEntityInfo writes logs and validates that the
// log events are associated with entities from CloudWatch Logs
func TestWriteLogsWithEntityInfo(t *testing.T) {
instanceId := awsservice.GetInstanceId()
log.Printf("Found instance id %s", instanceId)

// Define tags to create for EC2 test case
tagsToCreate := []ec2Types.Tag{
{
Key: aws.String("service"),
Value: aws.String("service-test"),
},
}

testCases := map[string]struct {
agentConfigPath string
iterations int
useEC2Tag bool
expectedEntity common.ExpectedEntity
}{
"IAMRole": {
agentConfigPath: filepath.Join("resources", "config_log.json"),
iterations: 1000,
expectedEntity: common.ExpectedEntity{
EntityType: "Service",
Name: "cwa-e2e-iam-role", //should match the name of the IAM role used in our testing
Environment: "ec2:default",
PlatformType: "AWS::EC2",
InstanceId: instanceId,
},
},
"ServiceInConfig": {
agentConfigPath: filepath.Join("resources", "config_log_service_name.json"),
iterations: 1000,
expectedEntity: common.ExpectedEntity{
EntityType: "Service",
Name: "service-in-config", //should match the service.name value in the config file
Environment: "environment-in-config", //should match the deployment.environment value in the config file
PlatformType: "AWS::EC2",
InstanceId: instanceId,
},
},
"EC2Tags": {
agentConfigPath: filepath.Join("resources", "config_log.json"),
iterations: 1000,
useEC2Tag: true,
expectedEntity: common.ExpectedEntity{
EntityType: "Service",
Name: "service-test", //should match the value in tagsToCreate
Environment: "ec2:default",
PlatformType: "AWS::EC2",
InstanceId: instanceId,
},
},
}
for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
t.Cleanup(func() {
// delete the log group/stream after each test case
awsservice.DeleteLogGroupAndStream(instanceId, instanceId)

// delete EC2 tags added to the instance for the test
if testCase.useEC2Tag {
input := &ec2.DeleteTagsInput{
Resources: []string{instanceId},
Tags: tagsToCreate,
}
_, err := awsservice.Ec2Client.DeleteTags(context.TODO(), input)
assert.NoError(t, err)
// Add a short delay to ensure tag deletion propagates
time.Sleep(5 * time.Second)
}
})
if testCase.useEC2Tag {
// enable instance metadata tags
modifyInput := &ec2.ModifyInstanceMetadataOptionsInput{
InstanceId: aws.String(instanceId),
InstanceMetadataTags: ec2Types.InstanceMetadataTagsStateEnabled,
}
_, modifyErr := awsservice.Ec2Client.ModifyInstanceMetadataOptions(context.TODO(), modifyInput)
assert.NoError(t, modifyErr)

input := &ec2.CreateTagsInput{
Resources: []string{instanceId},
Tags: tagsToCreate,
}
_, createErr := awsservice.Ec2Client.CreateTags(context.TODO(), input)
assert.NoError(t, createErr)
}
id := uuid.New()
f, err := os.Create(logFilePath + "-" + id.String())
if err != nil {
t.Fatalf("Error occurred creating log file for writing: %v", err)
}

// Defer file closing and removal with error handling
defer func() {
if err := f.Close(); err != nil {
t.Errorf("Error occurred closing log file: %v", err)
}
if err := os.Remove(logFilePath + "-" + id.String()); err != nil {
t.Errorf("Error occurred removing log file: %v", err)
}
}()

common.DeleteFile(common.AgentLogFile)
common.TouchFile(common.AgentLogFile)

common.CopyFile(testCase.agentConfigPath, configOutputPath)

common.StartAgent(configOutputPath, true, false)
time.Sleep(sleepForExtendedFlush)
writeLogLines(t, f, testCase.iterations)
time.Sleep(sleepForExtendedFlush)
common.StopAgent()
end := time.Now()

common.ValidateLogEntity(t, instanceId, instanceId, &end, queryString, testCase.expectedEntity, "EC2")
})
}
}

// TestAutoRemovalStopAgent configures agent to monitor a file with auto removal on.
// Then it restarts the agent.
// Verify the file is NOT removed.
Expand Down
2 changes: 1 addition & 1 deletion test/cloudwatchlogs/resources/config_log.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"files": {
"collect_list": [
{
"file_path": "/tmp/cwagent_log_test.log",
"file_path": "/tmp/cwagent_log_test.log*",
"log_group_name": "{instance_id}",
"log_stream_name": "{instance_id}",
"timezone": "UTC"
Expand Down
22 changes: 22 additions & 0 deletions test/cloudwatchlogs/resources/config_log_service_name.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"agent": {
"run_as_user": "root",
"debug": true
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/tmp/cwagent_log_test.log*",
"log_group_name": "{instance_id}",
"log_stream_name": "{instance_id}",
"timezone": "UTC",
"service.name": "service-in-config",
"deployment.environment": "environment-in-config"
}
]
}
}
}
}
Loading
Loading