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"