From d06c82195e9e9f9e5f55c82bfa6f801f8227cb7b Mon Sep 17 00:00:00 2001
From: Seth L <81644108+sethAmazon@users.noreply.github.com>
Date: Mon, 13 Nov 2023 11:42:16 -0500
Subject: [PATCH] Add win user data test (#377)
---
Makefile | 1 +
generator/test_case_generator.go | 4 +
terraform/ec2/win/install_and_start_agent.tpl | 24 ++
terraform/ec2/win/main.tf | 88 ++++++-
.../resources/traceid_generator.go | 2 +-
.../windows/userdata/agent_config.json | 216 ++++++++++++++++++
test/feature/windows/userdata/parameters.yml | 157 +++++++++++++
7 files changed, 485 insertions(+), 7 deletions(-)
create mode 100644 terraform/ec2/win/install_and_start_agent.tpl
create mode 100644 test/feature/windows/userdata/agent_config.json
create mode 100644 test/feature/windows/userdata/parameters.yml
diff --git a/Makefile b/Makefile
index 59ccb8485..c54a5eab7 100644
--- a/Makefile
+++ b/Makefile
@@ -47,6 +47,7 @@ install-golang-lint:
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TOOLS_BIN_DIR) v1.50.1
fmt: install-goimports addlicense
+ terraform fmt -recursive
go fmt ./...
@echo $(ALL_SRC) | xargs -n 10 $(GOIMPORTS) $(GOIMPORTS_OPT)
diff --git a/generator/test_case_generator.go b/generator/test_case_generator.go
index 655d1c8ee..5518f19d9 100644
--- a/generator/test_case_generator.go
+++ b/generator/test_case_generator.go
@@ -122,6 +122,10 @@ var testTypeToTestConfig = map[string][]testConfig{
{testDir: "../../../test/restart"},
{testDir: "../../../test/acceptance"},
{testDir: "../../../test/feature/windows/event_logs"},
+ {
+ testDir: "../../../test/feature/windows/userdata",
+ targets: map[string]map[string]struct{}{"os": {"win-2019": {}}},
+ },
// assume role test doesn't add much value, and it already being tested with linux
//{testDir: "../../../test/assume_role"},
},
diff --git a/terraform/ec2/win/install_and_start_agent.tpl b/terraform/ec2/win/install_and_start_agent.tpl
new file mode 100644
index 000000000..a60ea2dcf
--- /dev/null
+++ b/terraform/ec2/win/install_and_start_agent.tpl
@@ -0,0 +1,24 @@
+
+$installDirectory = "c:\temp\cw"
+$downloadDirectory = $installDirectory
+$logsDirectory = $installDirectory
+$cwAgentInstaller = "$downloadDirectory\amazon-cloudwatch-agent.msi"
+$cwAgentInstallPath = "C:\\Program Files\\Amazon\\AmazonCloudWatchAgent"
+
+New-Item -ItemType "directory" -Path $installDirectory
+
+Set-Location -Path $installDirectory
+
+Write-host "Installing Powershell S3 CLI"
+Install-PackageProvider NuGet -Force;
+Set-PSRepository PSGallery -InstallationPolicy Trusted
+Install-Module -Name AWS.Tools.S3 -AllowClobber
+
+Write-host "Installing Cloudwatch Agent"
+${copy_object}
+Start-Process -FilePath msiexec -Args "/i $cwAgentInstaller /l*v $logsDirectory\installCWAgentLog.log /qn" -Verb RunAs -Wait
+
+Write-host "Load config"
+
+& "$cwAgentInstallPath\amazon-cloudwatch-agent-ctl.ps1" -a fetch-config -m ec2 -s -c ssm:${agent_json_config}
+
\ No newline at end of file
diff --git a/terraform/ec2/win/main.tf b/terraform/ec2/win/main.tf
index 3de3828c7..8026bd714 100644
--- a/terraform/ec2/win/main.tf
+++ b/terraform/ec2/win/main.tf
@@ -62,6 +62,7 @@ resource "aws_instance" "cwagent" {
vpc_security_group_ids = [module.basic_components.security_group]
associate_public_ip_address = true
instance_initiated_shutdown_behavior = "terminate"
+ user_data = length(regexall("/feature/windows/userdata", var.test_dir)) > 0 ? data.template_file.user_data.rendered : ""
get_password_data = true
metadata_options {
@@ -72,18 +73,20 @@ resource "aws_instance" "cwagent" {
tags = {
Name = "cwagent-integ-test-ec2-windows-${var.test_name}-${module.common.testing_id}"
}
+ depends_on = [aws_ssm_parameter.upload_ssm]
}
# Size of windows json is too large thus can't use standard tier
resource "aws_ssm_parameter" "upload_ssm" {
- count = var.use_ssm == true && length(regexall("/feature/windows", var.test_dir)) > 0 ? 1 : 0
+ count = length(regexall("/feature/windows", var.test_dir)) > 0 ? 1 : 0
name = local.ssm_parameter_name
type = "String"
tier = "Advanced"
value = file(module.validator.agent_config)
}
-resource "null_resource" "integration_test_setup" {
+resource "null_resource" "integration_test_setup_agent" {
+ count = length(regexall("/feature/windows/userdata", var.test_dir)) > 0 ? 0 : 1
depends_on = [aws_instance.cwagent, module.validator, aws_ssm_parameter.upload_ssm]
# Install software
@@ -99,6 +102,24 @@ resource "null_resource" "integration_test_setup" {
inline = [
"aws s3 cp s3://${var.s3_bucket}/integration-test/packaging/${var.cwa_github_sha}/amazon-cloudwatch-agent.msi .",
"start /wait msiexec /i amazon-cloudwatch-agent.msi /norestart /qb-",
+ ]
+ }
+}
+
+resource "null_resource" "integration_test_setup_validator" {
+ depends_on = [aws_instance.cwagent, module.validator, aws_ssm_parameter.upload_ssm]
+
+ # Install software
+ connection {
+ type = "winrm"
+ user = "Administrator"
+ password = rsadecrypt(aws_instance.cwagent.password_data, local.private_key_content)
+ host = aws_instance.cwagent.public_dns
+ }
+
+ # Install agent binaries
+ provisioner "remote-exec" {
+ inline = [
"aws s3 cp s3://${var.s3_bucket}/integration-test/validator/${var.cwa_github_sha}/windows/${var.arc}/validator.exe .",
]
}
@@ -123,7 +144,8 @@ resource "null_resource" "integration_test_reboot" {
}
depends_on = [
- null_resource.integration_test_setup,
+ null_resource.integration_test_setup_agent,
+ null_resource.integration_test_setup_validator,
]
}
@@ -144,7 +166,8 @@ resource "null_resource" "integration_test_run" {
# run go test when it's not feature test
count = length(regexall("/feature/windows", var.test_dir)) < 1 ? 1 : 0
depends_on = [
- null_resource.integration_test_setup,
+ null_resource.integration_test_setup_agent,
+ null_resource.integration_test_setup_agent,
null_resource.integration_test_wait,
]
@@ -170,9 +193,10 @@ resource "null_resource" "integration_test_run" {
resource "null_resource" "integration_test_run_validator" {
# run validator only when test_dir is not passed e.g. the default from variable.tf
- count = length(regexall("/feature/windows", var.test_dir)) > 0 ? 1 : 0
+ count = length(regexall("/feature/windows", var.test_dir)) > 0 && length(regexall("/feature/windows/userdata", var.test_dir)) < 1 ? 1 : 0
depends_on = [
- null_resource.integration_test_setup,
+ null_resource.integration_test_setup_agent,
+ null_resource.integration_test_setup_validator,
null_resource.integration_test_wait,
]
@@ -213,6 +237,42 @@ resource "null_resource" "integration_test_run_validator" {
}
}
+resource "null_resource" "integration_test_run_validator_userdata" {
+ # run validator only when test_dir is not passed e.g. the default from variable.tf
+ count = length(regexall("/feature/windows/userdata", var.test_dir)) > 0 ? 1 : 0
+ depends_on = [
+ null_resource.integration_test_setup_validator,
+ null_resource.integration_test_wait,
+ ]
+
+ connection {
+ type = "winrm"
+ user = "Administrator"
+ password = rsadecrypt(aws_instance.cwagent.password_data, local.private_key_content)
+ host = aws_instance.cwagent.public_dns
+ }
+
+ provisioner "file" {
+ source = module.validator.agent_config
+ destination = module.validator.instance_agent_config
+ }
+
+ provisioner "file" {
+ source = module.validator.validator_config
+ destination = module.validator.instance_validator_config
+ }
+
+ //runs validator and sets up prometheus java agent
+ provisioner "remote-exec" {
+ inline = [
+ "set AWS_REGION=${var.region}",
+ "validator.exe --validator-config=${module.validator.instance_validator_config} --preparation-mode=true",
+ "powershell.exe \"& \"C:ProgramFiles\\Amazon\\AmazonCloudWatchAgent\\amazon-cloudwatch-agent-ctl.ps1\" -m ec2 -a status\"",
+ "validator.exe --validator-config=${module.validator.instance_validator_config} --preparation-mode=false"
+ ]
+ }
+}
+
data "aws_ami" "latest" {
most_recent = true
@@ -221,3 +281,19 @@ data "aws_ami" "latest" {
values = [var.ami]
}
}
+
+#####################################################################
+# Generate template file for EC2 userdata script
+#####################################################################
+data "template_file" "user_data" {
+ template = file("install_and_start_agent.tpl")
+
+ vars = {
+ copy_object = "Copy-S3Object -BucketName ${var.s3_bucket} -Key integration-test/packaging/${var.cwa_github_sha}/amazon-cloudwatch-agent.msi -region ${var.region} -LocalFile $cwAgentInstaller"
+ agent_json_config = local.ssm_parameter_name
+ }
+}
+
+output "userdata" {
+ value = data.template_file.user_data.rendered
+}
diff --git a/test/app_signals/resources/traceid_generator.go b/test/app_signals/resources/traceid_generator.go
index a56fde0f8..2f2ef6592 100644
--- a/test/app_signals/resources/traceid_generator.go
+++ b/test/app_signals/resources/traceid_generator.go
@@ -17,4 +17,4 @@ func main() {
binary.BigEndian.PutUint32(r[0:4], uint32(epochNow))
rand.Read(r[4:])
fmt.Printf("%s", hex.EncodeToString(r[:]))
-}
\ No newline at end of file
+}
diff --git a/test/feature/windows/userdata/agent_config.json b/test/feature/windows/userdata/agent_config.json
new file mode 100644
index 000000000..154989e58
--- /dev/null
+++ b/test/feature/windows/userdata/agent_config.json
@@ -0,0 +1,216 @@
+{
+ "agent": {
+ "debug": true
+ },
+ "metrics": {
+ "namespace": "CloudWatchAgentWinFeature",
+ "metrics_collected": {
+ "Processor": {
+ "measurement": [
+ {
+ "name":"% Idle Time",
+ "rename": "Idle_Time"
+ },
+ {
+ "name":"% Interrupt Time",
+ "rename": "Interrupt_Time"
+ },
+ {
+ "name":"% User Time",
+ "rename": "User_Time"
+ },
+ {
+ "name":"% Processor Time",
+ "rename": "Processor_Time"
+ }
+ ],
+ "resources": [
+ "*"
+ ],
+ "metrics_collection_interval": 1
+ },
+ "LogicalDisk": {
+ "measurement": [
+ {
+ "name":"% Free Space",
+ "rename":"Free_Space"
+ }
+ ],
+ "resources": [
+ "*"
+ ],
+ "metrics_collection_interval": 1
+ },
+ "PhysicalDisk": {
+ "measurement": [
+ {
+ "name":"% Disk Time",
+ "rename": "Disk_Time"
+ },
+ {
+ "name":"Disk Write Bytes/sec",
+ "rename": "Write_Bytes_Per_Sec"
+ },
+ {
+ "name":"Disk Read Bytes/sec",
+ "rename": "Read_Bytes_Per_Sec"
+ },
+ {
+ "name":"Disk Writes/sec",
+ "rename": "Write_Per_Sec"
+ },
+ {
+ "name":"Disk Reads/sec",
+ "rename": "Disk_Read_Per_Sec"
+ }
+ ],
+ "resources": [
+ "*"
+ ],
+ "metrics_collection_interval": 1
+ },
+ "Network Interface": {
+ "measurement": [
+ {
+ "name":"Bytes Sent/sec",
+ "rename": "Bytes_Sent_Per_Sec"
+ },
+ {
+ "name":"Bytes Received/sec",
+ "rename": "Bytes_Received_Per_Sec"
+ },
+ {
+ "name":"Packets Sent/sec",
+ "rename": "Packets_Sent_Per_Sec"
+ },
+ {
+ "name":"Packets Received/sec",
+ "rename": "Packets_Received_Per_Sec"
+ }
+ ],
+ "resources": [
+ "*"
+ ],
+ "metrics_collection_interval": 1
+ },
+ "Memory": {
+ "measurement": [
+ {
+ "name": "Available Bytes",
+ "rename": "Available_Bytes"
+ },
+ {
+ "name":"Cache Faults/sec",
+ "rename": "Cache_Faults_Per_Sec"
+ },
+ {
+ "name":"Page Faults/sec",
+ "rename": "Page_Faults_Per_sec"
+ },
+ {
+ "name":"Pages/sec",
+ "rename":"Page_Per_Sec"
+ }
+ ],
+ "metrics_collection_interval": 1
+ },
+ "System": {
+ "measurement": [
+ {
+ "name": "Processor Queue Length",
+ "rename": "Processor_Queue_Length"
+ }
+ ],
+ "metrics_collection_interval": 1
+ },
+ "TCPv4": {
+ "measurement": [
+ {
+ "name": "Connections Established",
+ "rename": "Connections_Established"
+ }
+ ],
+ "metrics_collection_interval": 1
+ },
+ "TCPv6": {
+ "measurement": [
+ {
+ "name": "Connections Established",
+ "rename": "Connections_Established"
+ }
+ ],
+ "metrics_collection_interval": 1
+ },
+ "procstat": [
+ {
+ "exe": "amazon-cloudwatch-agent",
+ "measurement": [
+ "cpu_usage",
+ "memory_rss"
+ ],
+ "metrics_collection_interval": 1
+ }
+ ]
+ },
+ "append_dimensions": {
+ "InstanceId": "${aws:InstanceId}"
+ },
+ "force_flush_interval": 30
+ },
+ "logs": {
+ "logs_collected": {
+ "windows_events": {
+ "collect_list": [
+ {
+ "event_name": "Security",
+ "event_levels": [
+ "INFORMATION",
+ "WARNING",
+ "ERROR",
+ "CRITICAL",
+ "VERBOSE"
+ ],
+ "log_group_name": "{instance_id}",
+ "log_stream_name": "SecurityEvent"
+ },
+ {
+ "event_name": "System",
+ "event_levels": [
+ "INFORMATION",
+ "WARNING",
+ "ERROR",
+ "CRITICAL",
+ "VERBOSE"
+ ],
+ "log_group_name": "{instance_id}",
+ "log_stream_name": "System"
+ },
+ {
+ "event_name": "Application",
+ "event_levels": [
+ "INFORMATION",
+ "WARNING",
+ "ERROR",
+ "CRITICAL",
+ "VERBOSE"
+ ],
+ "log_group_name": "{instance_id}",
+ "log_stream_name": "Application"
+ }
+ ]
+ },
+
+ "files": {
+ "collect_list": [
+ {
+ "file_path": "C:/Users/Administrator/AppData/Local/Temp/test1.log",
+ "log_group_name": "{instance_id}",
+ "log_stream_name": "test1.log",
+ "timezone": "UTC"
+ }
+ ]
+ }
+ },
+ "force_flush_interval": 5
+ }
+}
diff --git a/test/feature/windows/userdata/parameters.yml b/test/feature/windows/userdata/parameters.yml
new file mode 100644
index 000000000..4331804a2
--- /dev/null
+++ b/test/feature/windows/userdata/parameters.yml
@@ -0,0 +1,157 @@
+# Receivers that agent needs to tests
+receivers: ["system"]
+
+#Test case name
+test_case: "win_feature_userdata"
+validate_type: "feature"
+# Only support metrics/traces/logs, even in this case we validate more than logs,
+# we only make this data_type as a placeholder
+data_type: "metrics"
+
+# Number of metrics to be sent or number of log lines being written each minute
+values_per_minute: "2"
+# Number of seconds the agent should run and collect the metrics. In this case, 1 minutes
+agent_collection_period: 60
+
+cloudwatch_agent_config: ""
+
+# Metric that the test needs to validate; moreover, the stress validation already has
+# InstanceID dimension; therefore, does not need to validate it
+# https://github.com/aws/amazon-cloudwatch-agent-test/pull/109/files#diff-47c87373e751dd9fd5ce504e44b320765c8b84d6cde524a4e8a32cfa34674165R124-R135
+metric_namespace: "CloudWatchAgentWinFeature"
+metric_validation:
+ # Validate Memory metrics
+ - metric_name: "Available_Bytes"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Memory"
+ - metric_name: "Cache_Faults_Per_Sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Memory"
+ - metric_name: "Page_Faults_Per_sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Memory"
+ - metric_name: "Page_Per_Sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Memory"
+# Validations for Logical Disks
+ - metric_name: "Free_Space"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "LogicalDisk"
+ - name: "instance"
+ value: "C:"
+# Validations for Physical Disks
+ - metric_name: "Disk_Time"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "PhysicalDisk"
+ - name: "instance"
+ value: "0 C:"
+ - metric_name: "Write_Bytes_Per_Sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "PhysicalDisk"
+ - name: "instance"
+ value: "0 C:"
+ - metric_name: "Read_Bytes_Per_Sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "PhysicalDisk"
+ - name: "instance"
+ value: "0 C:"
+ - metric_name: "Write_Per_Sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "PhysicalDisk"
+ - name: "instance"
+ value: "0 C:"
+ - metric_name: "Disk_Read_Per_Sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "PhysicalDisk"
+ - name: "instance"
+ value: "0 C:"
+
+# Validations for Processor
+ - metric_name: "Idle_Time"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Processor"
+ - name: "instance"
+ value: "0"
+ - metric_name: "Interrupt_Time"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Processor"
+ - name: "instance"
+ value: "0"
+ - metric_name: "User_Time"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Processor"
+ - name: "instance"
+ value: "0"
+ - metric_name: "Processor_Time"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Processor"
+ - name: "instance"
+ value: "0"
+# Validations for Network Interface
+ - metric_name: "Bytes_Sent_Per_Sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Network Interface"
+ - name: "instance"
+ value: "Amazon Elastic Network Adapter"
+ - metric_name: "Bytes_Received_Per_Sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Network Interface"
+ - name: "instance"
+ value: "Amazon Elastic Network Adapter"
+ - metric_name: "Packets_Sent_Per_Sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Network Interface"
+ - name: "instance"
+ value: "Amazon Elastic Network Adapter"
+ - metric_name: "Packets_Received_Per_Sec"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "Network Interface"
+ - name: "instance"
+ value: "Amazon Elastic Network Adapter"
+# Validations for TCPv4 and TCPv6
+ - metric_name: "Connections_Established"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "TCPv4"
+ - metric_name: "Connections_Established"
+ metric_sample_count: 60
+ metric_dimension:
+ - name: "objectname"
+ value: "TCPv6"