Skip to content

Commit

Permalink
Add ECS Metadata Integration Test for detect changes in ECS Container…
Browse files Browse the repository at this point in the history
… Agent Metadata Endpoint (#458)

* Initial commit for ecs

* Add basic for fargate with terraform

* Fix typo for CWAgent config

* Add some tpl files for task def

* Add new policy

* Add basic components for CWAgent fargate on terraform

* Finish formating terraform

* Add basic testing

* Add basic testing

* fix some constraint

* change to us west-2

* Add emf processor for config and sample app

* Add redis sample app

* Add redis sample app

* Add basic testing for ecs fargate

* reduce variables

* Add readme doc and use make fmt

* Add basic integration test on github workflow

* delete xtool

* Fix json config for default and ecs

* Add ecs linux fargate and integration test

* Change image repo again

* Test integration test workflow

* Delete branchs for testing

* Test workflow

* Fix tag for build docker image

* Change back to format

* Add back build constraints

* Change to use test cwl

* Change name to ecs fargate

* Change to path go.mod

* Fix variables and fix default extra app

* Delete retry for testing

* Add lock

* Add unique for service role

* Test and fixing readme

* Add security group

* Fix path testing

* Test ecs

* test for success path

* Test again with go

* Test again for constraints

* Test again

* Add basic testing

* Change to cwagent integration test

* Add back from source

* Fix deprecated vpc and fix cloudwatch agent config issue

* Fix cloudwatch agent issues

* Add back check_secrets

* Add back ECS fargate
  • Loading branch information
khanhntd authored May 6, 2022
1 parent 3a85fd6 commit be2a6bd
Show file tree
Hide file tree
Showing 27 changed files with 848 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ By submitting this pull request, I confirm that you can use, modify, copy, and r
# Tests
_Describe what tests you have done._

#Requirements
# Requirements
_Before commit the code, please do the following steps._
1. Run `make fmt` and `make fmt-sh`
2. Run `make linter`
Expand Down
123 changes: 120 additions & 3 deletions .github/workflows/integrationTest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,73 @@ env:
PASSPHRASE: ${{ secrets.PASSPHRASE }}
GPG_KEY_NAME: ${{ secrets.GPG_KEY_NAME }}
GPG_TTY: $(tty)
ECR_INTEGRATION_TEST_REPO: "cwagent-integration-test"

on:
push:
branches:
- master

workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true

jobs:
MakeDockerImage:
name: 'MakeDockerImage'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Cache if success
id: build-docker-image
uses: actions/cache@v2
with:
path: |
RELEASE_NOTES
key: build-docker-image-${{ github.run_id }}

- name: Configure AWS Credentials
if: steps.build-docker-image.outputs.cache-hit != 'true'
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.TERRAFORM_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.TERRAFORM_AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2

- name: Login ECR
if: steps.build-docker-image.outputs.cache-hit != 'true'
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1

- name: Set up Docker Buildx
if: steps.build-docker-image.outputs.cache-hit != 'true'
uses: docker/setup-buildx-action@v1

- name: Set up QEMU
if: steps.build-docker-image.outputs.cache-hit != 'true'
uses: docker/setup-qemu-action@v1

#Build the cloudwatch agent image for two primary reasons:
#-Using the cloudwatch agent image to do the integration test (can be used for internal)
#-Export it for the future use in CD release pipeline
#Documentation: https://github.com/docker/build-push-action
- name: Build Cloudwatch Agent Image
uses: docker/build-push-action@v2
if: steps.build-docker-image.outputs.cache-hit != 'true'
with:
file: amazon-cloudwatch-container-insights/cloudwatch-agent-dockerfile/source/Dockerfile
context: .
push: true
tags: |
${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_INTEGRATION_TEST_REPO }}:${{ github.sha }}
build-args: BUILDMODE=copy
cache-from: type=registry
cache-to: type=inline
platforms: linux/amd64, linux/arm64

MakeBinary:
name: 'MakeBinary'
runs-on: ubuntu-latest
Expand Down Expand Up @@ -92,6 +147,7 @@ jobs:
outputs:
ec2_linux_matrix: ${{ steps.set-matrix.outputs.ec2_linux_matrix }}
ec2_windows_matrix: ${{ steps.set-matrix.outputs.ec2_windows_matrix }}
ecs_fargate_matrix: ${{ steps.set-matrix.outputs.ecs_fargate_matrix }}
steps:
- uses: actions/checkout@v2

Expand All @@ -105,13 +161,15 @@ jobs:
id: set-matrix
run: |
go run --tags=generator integration/generator/test_case_generator.go
echo "::set-output name=ec2_linux_matrix::$(echo $(cat integration/generator/resources/linux_complete_test_matrix.json))"
echo "::set-output name=ec2_windows_matrix::$(echo $(cat integration/generator/resources/windows_complete_test_matrix.json))"
echo "::set-output name=ec2_linux_matrix::$(echo $(cat integration/generator/resources/ec2_linux_complete_test_matrix.json))"
echo "::set-output name=ec2_windows_matrix::$(echo $(cat integration/generator/resources/ec2_windows_complete_test_matrix.json))"
echo "::set-output name=ecs_fargate_matrix::$(echo $(cat integration/generator/resources/ecs_fargate_complete_test_matrix.json))"
- name: Echo test plan matrix
run: |
echo ${{ steps.set-matrix.outputs.ec2_linux_matrix }}
echo ${{ steps.set-matrix.outputs.ec2_windows_matrix }}
echo ${{ steps.set-matrix.outputs.ecs_fargate_matrix }}
MakeMSIZip:
name: 'MakeMSIZip'
Expand Down Expand Up @@ -499,4 +557,63 @@ jobs:
run: terraform init

- name: Terraform destroy
run: terraform destroy --auto-approve
run: terraform destroy --auto-approve

ECSFargateIntegrationTest:
name: 'ECSFargateIntegrationTest'
runs-on: ubuntu-latest
needs: [MakeDockerImage, GenerateTestMatrix]
strategy:
fail-fast: false
matrix:
arrays: ${{ fromJson(needs.GenerateTestMatrix.outputs.ecs_fargate_matrix) }}
steps:
- uses: actions/checkout@v2

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.TERRAFORM_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.TERRAFORM_AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-2

- name: Cache if success
id: ecs-fargate-integration-test
uses: actions/cache@v2
with:
path: go.mod
key: ecs-fargate-integration-test-${{ github.sha }}-${{ matrix.arrays.os }}

- name: Login ECR
id: login-ecr
if: steps.ecs-fargate-integration-test.outputs.cache-hit != 'true'
uses: aws-actions/amazon-ecr-login@v1

- name: Verify Terraform version
if: steps.ecs-fargate-integration-test.outputs.cache-hit != 'true'
run: terraform --version

- name: Terraform apply
if: steps.ecs-fargate-integration-test.outputs.cache-hit != 'true'
uses: nick-invision/retry@v2
with:
max_attempts: 3
timeout_minutes: 15
retry_wait_seconds: 5
command: |
cd integration/terraform/ecs/linux
terraform init
if terraform apply --auto-approve -var="test_dir=${{ matrix.arrays.test_dir }}" -var="cwagent_image_repo=${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_INTEGRATION_TEST_REPO }}" -var="cwagent_image_tag=${{ github.sha }}" ; then
terraform destroy -auto-approve
else
terraform destroy -auto-approve && exit 1
fi
- name: Terraform destroy
if: ${{ cancelled() && steps.ecs-fargate-integration-test.outputs.cache-hit != 'true'
uses: nick-invision/retry@v2
with:
max_attempts: 3
timeout_minutes: 8
retry_wait_seconds: 5
command: cd integration/terraform/ecs/linux && terraform destroy --auto-approve
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ require (
github.com/BurntSushi/toml v0.3.1
github.com/Jeffail/gabs v1.4.0
github.com/aws/aws-sdk-go v1.30.15
github.com/aws/aws-sdk-go-v2 v1.16.2
github.com/aws/aws-sdk-go-v2 v1.16.3
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
Expand All @@ -68,7 +68,7 @@ require (
github.com/prometheus/common v0.9.1
github.com/prometheus/prometheus v1.8.2-0.20200420081721-18254838fbe2
github.com/shirou/gopsutil v2.20.5+incompatible
github.com/stretchr/testify v1.5.1
github.com/stretchr/testify v1.7.0
github.com/xeipuuv/gojsonschema v1.2.0
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
Expand Down
8 changes: 6 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,9 @@ github.com/aws/aws-sdk-go v1.30.15 h1:Sd8QDVzzE8Sl+xNccmdj0HwMrFowv6uVUx9tGsCE1Z
github.com/aws/aws-sdk-go v1.30.15/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/aws/aws-sdk-go-v2 v1.13.0/go.mod h1:L6+ZpqHaLbAaxsqV0L4cvxZY7QupWJB4fhkf8LXvC7w=
github.com/aws/aws-sdk-go-v2 v1.16.2 h1:fqlCk6Iy3bnCumtrLz9r3mJ/2gUT0pJ0wLFVIdWh+JA=
github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
github.com/aws/aws-sdk-go-v2 v1.16.3 h1:0W1TSJ7O6OzwuEvIXAtJGvOeQ0SGAhcpxPN2/NK5EhM=
github.com/aws/aws-sdk-go-v2 v1.16.3/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
github.com/aws/aws-sdk-go-v2/config v1.15.3 h1:5AlQD0jhVXlGzwo+VORKiUuogkG7pQcLJNzIzK7eodw=
github.com/aws/aws-sdk-go-v2/config v1.15.3/go.mod h1:9YL3v07Xc/ohTsxFXzan9ZpFpdTOFl4X65BAKYaz8jg=
github.com/aws/aws-sdk-go-v2/credentials v1.11.2 h1:RQQ5fzclAKJyY5TvF+fkjJEwzK4hnxQCLOu5JXzDmQo=
Expand Down Expand Up @@ -1028,8 +1029,9 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
Expand Down Expand Up @@ -1471,6 +1473,8 @@ gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
Expand Down
2 changes: 2 additions & 0 deletions integration/generator/resources/ec2_mac_test_matrix.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[
]
16 changes: 12 additions & 4 deletions integration/generator/test_case_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@ const (

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

func main() {
Expand All @@ -37,11 +42,14 @@ func main() {

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)
}

byteValueTestMatrix, _ := ioutil.ReadAll(openTestMatrix)
_ = openTestMatrix.Close()

var testMatrix []map[string]string
err = json.Unmarshal(byteValueTestMatrix, &testMatrix)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions integration/terraform/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fmt:
terraform fmt -recursive

check-fmt:
terraform fmt -recursive -check
64 changes: 64 additions & 0 deletions integration/terraform/ecs/linux/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
Running ECS Fargate Integration Tests
=========================

## 1. How ECS Fargate are set up?
**Step 1:** Create a Fargate ECS Cluster with the default VPC Network.
**Step 2:** Create a security group to assign to the service in step 5 which allows all inbound
traffics and outbound traffics
**Step 3:** Create a IAM Role and IAM Execution Role for the containers to pull the image and
execute their purposes
**Step 4:** Create a [task definition](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definitions.html)
to decide which containers serve a specific task and assign the IAM roles in step 3 to the containers
**Step 5:** Create a [service](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_services.html) which configure
how many tasks are running in parallel and ensure availability of the task.

## 2. Setup resources
By running `terraform apply -auto-approve -lock=false`,
you agree to setup the following resources:
* 1 IAM Task Role and 1 Execution Task Role (similar to [these IAM Roles](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy_servicelens_CloudWatch_agent_deploy_ECS.html))
* 2 SSM Parameter Store
* 2 Task Definitions and 2 Services for those task definitions
* 1 Security group which allows all inbound and outbound traffics.

To be more specifically,
* **IAM Task Role:** Contain the following policy
* **CloudWatchAgentPolicy:** CloudWatchAgent's related actions
* **service_discovery_police:** For describe ECS tasks and services
```json
{
"Statement": [
{
"Action": [
"ecs:ListTasks",
"ecs:ListServices",
"ecs:DescribeTasks",
"ecs:DescribeTaskDefinition",
"ecs:DescribeServices",
"ecs:DescribeContainerInstances",
"ec2:DescribeInstances"
],
"Effect": "Allow",
"Resource": "*",
"Sid": ""
}
],
"Version": "2012-10-17"
}
```

* **IAM Execution Task Role:** Contain the following policy
* **AmazonECSTaskExecutionRolePolicy:** Pull CloudWatch Agent's image and extra app's image from ECR.
* **AmazonSSMReadOnlyAccess:** Pull Cloudwatch Agent's and Prometheus's config from SSM Parameter Store.
* **CloudWatchAgent Parameter Store:** Store CloudWatchAgent's configuration and CloudWatchAgent will pull the config from there. [Example configuration](default_resources/default_amazon_cloudwatch_agent.json)
* **Prometheus Parameter Store:** Store Prometheus's configuration and CloudWatchAgent will pull the config from there. [Example configuration](default_resources/default_ecs_prometheus.tpl)

## 3. Run tests in your AWS account
````
cd integration/terraform/ecs && terraform init && terraform apply -auto-approve \
-var="test_dir={{your test case folder name}} \
````

Don't forget to clean up your resources after integration test has passed:
````
terraform destroy -auto-approve
````
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"logs": {
"metrics_collected": {
"prometheus": {
"prometheus_config_path": "env:PROMETHEUS_CONFIG_CONTENT",
"ecs_service_discovery": {
"sd_frequency": "1m",
"sd_result_file": "/tmp/cwagent_ecs_auto_sd.yaml",
"docker_label": {}
},
"emf_processor": {
"metric_declaration": [
{
"source_labels": ["container_name"],
"label_matcher": "^redis-exporter-.*$",
"dimensions": [["ClusterName","TaskDefinitionFamily"]],
"metric_selectors": [
"^redis_net_(in|out)put_bytes_total$",
"^redis_(expired|evicted)_keys_total$",
"^redis_keyspace_(hits|misses)_total$",
"^redis_memory_used_bytes$",
"^redis_connected_clients$"
]
}
]
}
}
},
"force_flush_interval": 5
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
global:
scrape_interval: 1m
scrape_timeout: 10s
scrape_configs:
- job_name: cwagent-ecs-file-sd-config
sample_limit: 10000
file_sd_configs:
- files: [ "/tmp/cwagent_ecs_auto_sd.yaml" ]
Loading

0 comments on commit be2a6bd

Please sign in to comment.