package ecs import ( "testing" "time" "github.com/docker/docker/api/types/container" "github.com/stretchr/testify/require" ) // codified golden objects for tests // stats const pauseStatsKey = "e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba" const nginxStatsKey = "fffe894e232d46c76475cfeabf4907f712e8b92618a37fca3ef0805bbbfb0299" var pauseStatsRead = mustParseNano("2018-11-19T15:40:00.936081344Z") var pauseStatsPreRead = mustParseNano("2018-11-19T15:39:59.933000984Z") var nginxStatsRead = mustParseNano("2018-11-19T15:40:00.93733207Z") var nginxStatsPreRead = mustParseNano("2018-11-19T15:39:59.934291009Z") func mustParseNano(value string) time.Time { t, err := time.Parse(time.RFC3339Nano, value) if err != nil { panic(err) } return t } var validStats = map[string]*container.StatsResponse{ pauseStatsKey: { Read: pauseStatsRead, PreRead: pauseStatsPreRead, BlkioStats: container.BlkioStats{ IoServiceBytesRecursive: []container.BlkioStatEntry{ { Major: 202, Minor: 26368, Op: "Read", Value: 790528, }, { Major: 202, Minor: 26368, Op: "Write", }, { Major: 202, Minor: 26368, Op: "Sync", Value: 790528, }, { Major: 202, Minor: 26368, Op: "Async", }, { Major: 202, Minor: 26368, Op: "Total", Value: 790528, }, { Major: 253, Minor: 1, Op: "Read", Value: 790528, }, { Major: 253, Minor: 1, Op: "Write", }, { Major: 253, Minor: 1, Op: "Sync", Value: 790528, }, { Major: 253, Minor: 1, Op: "Async", }, { Major: 253, Minor: 1, Op: "Total", Value: 790528, }, { Major: 253, Minor: 2, Op: "Read", Value: 790528, }, { Major: 253, Minor: 2, Op: "Write", }, { Major: 253, Minor: 2, Op: "Sync", Value: 790528, }, { Major: 253, Minor: 2, Op: "Async", }, { Major: 253, Minor: 2, Op: "Total", Value: 790528, }, { Major: 253, Minor: 4, Op: "Read", Value: 790528, }, { Major: 253, Minor: 4, Op: "Write", }, { Major: 253, Minor: 4, Op: "Sync", Value: 790528, }, { Major: 253, Minor: 4, Op: "Async", }, { Major: 253, Minor: 4, Op: "Total", Value: 790528, }, }, IoServicedRecursive: []container.BlkioStatEntry{ { Major: 202, Minor: 26368, Op: "Read", Value: 10, }, { Major: 202, Minor: 26368, Op: "Write", }, { Major: 202, Minor: 26368, Op: "Sync", Value: 10, }, { Major: 202, Minor: 26368, Op: "Async", }, { Major: 202, Minor: 26368, Op: "Total", Value: 10, }, { Major: 253, Minor: 1, Op: "Read", Value: 10, }, { Major: 253, Minor: 1, Op: "Write", }, { Major: 253, Minor: 1, Op: "Sync", Value: 10, }, { Major: 253, Minor: 1, Op: "Async", }, { Major: 253, Minor: 1, Op: "Total", Value: 10, }, { Major: 253, Minor: 2, Op: "Read", Value: 10, }, { Major: 253, Minor: 2, Op: "Write", }, { Major: 253, Minor: 2, Op: "Sync", Value: 10, }, { Major: 253, Minor: 2, Op: "Async", }, { Major: 253, Minor: 2, Op: "Total", Value: 10, }, { Major: 253, Minor: 4, Op: "Read", Value: 10, }, { Major: 253, Minor: 4, Op: "Write", }, { Major: 253, Minor: 4, Op: "Sync", Value: 10, }, { Major: 253, Minor: 4, Op: "Async", }, { Major: 253, Minor: 4, Op: "Total", Value: 10, }, }, }, CPUStats: container.CPUStats{ CPUUsage: container.CPUUsage{ PercpuUsage: []uint64{ 26426156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, UsageInUsermode: 20000000, TotalUsage: 26426156, }, SystemUsage: 2336100000000, OnlineCPUs: 1, ThrottlingData: container.ThrottlingData{}, }, PreCPUStats: container.CPUStats{ CPUUsage: container.CPUUsage{ PercpuUsage: []uint64{ 26426156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, UsageInUsermode: 20000000, TotalUsage: 26426156, }, SystemUsage: 2335090000000, OnlineCPUs: 1, ThrottlingData: container.ThrottlingData{}, }, MemoryStats: container.MemoryStats{ Stats: map[string]uint64{ "cache": 790528, "mapped_file": 618496, "total_inactive_file": 782336, "pgpgout": 1040, "rss": 40960, "total_mapped_file": 618496, "pgpgin": 1243, "pgmajfault": 6, "total_rss": 40960, "hierarchical_memory_limit": 536870912, "total_pgfault": 1298, "total_active_file": 8192, "active_anon": 40960, "total_active_anon": 40960, "total_pgpgout": 1040, "total_cache": 790528, "active_file": 8192, "pgfault": 1298, "inactive_file": 782336, "total_pgpgin": 1243, "hierarchical_memsw_limit": 9223372036854772000, }, MaxUsage: 4825088, Usage: 1343488, Limit: 1033658368, }, Networks: map[string]container.NetworkStats{ "eth0": { RxBytes: uint64(5338), RxDropped: uint64(0), RxErrors: uint64(0), RxPackets: uint64(36), TxBytes: uint64(648), TxDropped: uint64(0), TxErrors: uint64(0), TxPackets: uint64(8), }, "eth5": { RxBytes: uint64(4641), RxDropped: uint64(0), RxErrors: uint64(0), RxPackets: uint64(26), TxBytes: uint64(690), TxDropped: uint64(0), TxErrors: uint64(0), TxPackets: uint64(9), }, }, }, nginxStatsKey: { Read: nginxStatsRead, PreRead: nginxStatsPreRead, BlkioStats: container.BlkioStats{ IoServiceBytesRecursive: []container.BlkioStatEntry{ { Major: 202, Minor: 26368, Op: "Read", Value: 5730304, }, { Major: 202, Minor: 26368, Op: "Write", }, { Major: 202, Minor: 26368, Op: "Sync", Value: 5730304, }, { Major: 202, Minor: 26368, Op: "Async", }, { Major: 202, Minor: 26368, Op: "Total", Value: 5730304, }, { Major: 253, Minor: 1, Op: "Read", Value: 5730304, }, { Major: 253, Minor: 1, Op: "Write", }, { Major: 253, Minor: 1, Op: "Sync", Value: 5730304, }, { Major: 253, Minor: 1, Op: "Async", }, { Major: 253, Minor: 1, Op: "Total", Value: 5730304, }, { Major: 253, Minor: 2, Op: "Read", Value: 5730304, }, { Major: 253, Minor: 2, Op: "Write", }, { Major: 253, Minor: 2, Op: "Sync", Value: 5730304, }, { Major: 253, Minor: 2, Op: "Async", }, { Major: 253, Minor: 2, Op: "Total", Value: 5730304, }, { Major: 253, Minor: 5, Op: "Read", Value: 5730304, }, { Major: 253, Minor: 5, Op: "Write", }, { Major: 253, Minor: 5, Op: "Sync", Value: 5730304, }, { Major: 253, Minor: 5, Op: "Async", }, { Major: 253, Minor: 5, Op: "Total", Value: 5730304, }, }, IoServicedRecursive: []container.BlkioStatEntry{ { Major: 202, Minor: 26368, Op: "Read", Value: 156, }, { Major: 202, Minor: 26368, Op: "Write", }, { Major: 202, Minor: 26368, Op: "Sync", Value: 156, }, { Major: 202, Minor: 26368, Op: "Async", }, { Major: 202, Minor: 26368, Op: "Total", Value: 156, }, { Major: 253, Minor: 1, Op: "Read", Value: 156, }, { Major: 253, Minor: 1, Op: "Write", }, { Major: 253, Minor: 1, Op: "Sync", Value: 156, }, { Major: 253, Minor: 1, Op: "Async", }, { Major: 253, Minor: 1, Op: "Total", Value: 156, }, { Major: 253, Minor: 2, Op: "Read", Value: 156, }, { Major: 253, Minor: 2, Op: "Write", }, { Major: 253, Minor: 2, Op: "Sync", Value: 156, }, { Major: 253, Minor: 2, Op: "Async", }, { Major: 253, Minor: 2, Op: "Total", Value: 156, }, { Major: 253, Minor: 5, Op: "Read", Value: 147, }, { Major: 253, Minor: 5, Op: "Write", }, { Major: 253, Minor: 5, Op: "Sync", Value: 147, }, { Major: 253, Minor: 5, Op: "Async", }, { Major: 253, Minor: 5, Op: "Total", Value: 147, }, }, }, CPUStats: container.CPUStats{ CPUUsage: container.CPUUsage{ PercpuUsage: []uint64{ 65599511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, UsageInUsermode: 40000000, TotalUsage: 65599511, UsageInKernelmode: 10000000, }, SystemUsage: 2336100000000, OnlineCPUs: 1, ThrottlingData: container.ThrottlingData{}, }, PreCPUStats: container.CPUStats{ CPUUsage: container.CPUUsage{ PercpuUsage: []uint64{ 65599511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, UsageInUsermode: 40000000, TotalUsage: 65599511, UsageInKernelmode: 10000000, }, SystemUsage: 2335090000000, OnlineCPUs: 1, ThrottlingData: container.ThrottlingData{}, }, MemoryStats: container.MemoryStats{ Stats: map[string]uint64{ "cache": 5787648, "mapped_file": 3616768, "total_inactive_file": 4321280, "pgpgout": 1674, "rss": 1597440, "total_mapped_file": 3616768, "pgpgin": 3477, "pgmajfault": 40, "total_rss": 1597440, "total_inactive_anon": 4096, "hierarchical_memory_limit": 536870912, "total_pgfault": 2924, "total_active_file": 1462272, "active_anon": 1597440, "total_active_anon": 1597440, "total_pgpgout": 1674, "total_cache": 5787648, "inactive_anon": 4096, "active_file": 1462272, "pgfault": 2924, "inactive_file": 4321280, "total_pgpgin": 3477, "hierarchical_memsw_limit": 9223372036854772000, }, MaxUsage: 8667136, Usage: 8179712, Limit: 1033658368, }, }, } // meta var metaPauseCreated = mustParseNano("2018-11-19T15:31:26.641964373Z") var metaPauseStarted = mustParseNano("2018-11-19T15:31:27.035698679Z") var metaCreated = mustParseNano("2018-11-19T15:31:27.614884084Z") var metaStarted = mustParseNano("2018-11-19T15:31:27.975996351Z") var metaPullStart = mustParseNano("2018-11-19T15:31:27.197327103Z") var metaPullStop = mustParseNano("2018-11-19T15:31:27.609089471Z") var validMeta = ecsTask{ Cluster: "test", TaskARN: "arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a", Family: "nginx", Revision: "2", DesiredStatus: "RUNNING", KnownStatus: "RUNNING", Containers: []ecsContainer{ { ID: pauseStatsKey, Name: "~internal~ecs~pause", DockerName: "ecs-nginx-2-internalecspause", Image: "amazon/amazon-ecs-pause:0.1.0", ImageID: "", Labels: map[string]string{ "com.amazonaws.ecs.cluster": "test", "com.amazonaws.ecs.container-name": "~internal~ecs~pause", "com.amazonaws.ecs.task-arn": "arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a", "com.amazonaws.ecs.task-definition-family": "nginx", "com.amazonaws.ecs.task-definition-version": "2", }, DesiredStatus: "RESOURCES_PROVISIONED", KnownStatus: "RESOURCES_PROVISIONED", Limits: map[string]float64{ "CPU": 0, "Memory": 0, }, CreatedAt: metaPauseCreated, StartedAt: metaPauseStarted, Type: "CNI_PAUSE", Networks: []network{ { NetworkMode: "awsvpc", IPv4Addresses: []string{ "172.31.25.181", }, }, }, }, { ID: nginxStatsKey, Name: "nginx", DockerName: "ecs-nginx-2-nginx", Image: "nginx:alpine", ImageID: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", Labels: map[string]string{ "com.amazonaws.ecs.cluster": "test", "com.amazonaws.ecs.container-name": "nginx", "com.amazonaws.ecs.task-arn": "arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a", "com.amazonaws.ecs.task-definition-family": "nginx", "com.amazonaws.ecs.task-definition-version": "2", }, DesiredStatus: "RUNNING", KnownStatus: "RUNNING", Limits: map[string]float64{ "CPU": 0, "Memory": 0, }, CreatedAt: metaCreated, StartedAt: metaStarted, Type: "NORMAL", Networks: []network{ { NetworkMode: "awsvpc", IPv4Addresses: []string{ "172.31.25.181", }, }, }, }, }, Limits: map[string]float64{ "CPU": 0.5, "Memory": 512, }, PullStartedAt: metaPullStart, PullStoppedAt: metaPullStop, } func TestResolveEndpoint(t *testing.T) { tests := []struct { name string given Ecs exp Ecs setEnv func(*testing.T) }{ { name: "Endpoint is explicitly set => use v2 metadata", given: Ecs{ EndpointURL: "192.162.0.1/custom_endpoint", }, exp: Ecs{ EndpointURL: "192.162.0.1/custom_endpoint", metadataVersion: 2, }, }, { name: "Endpoint is not set, ECS_CONTAINER_METADATA_URI is not set => use v2 metadata", given: Ecs{ EndpointURL: "", }, exp: Ecs{ EndpointURL: v2Endpoint, metadataVersion: 2, }, }, { name: "Endpoint is not set, ECS_CONTAINER_METADATA_URI is set => use v3 metadata", setEnv: func(t *testing.T) { t.Setenv("ECS_CONTAINER_METADATA_URI", "v3-endpoint.local") }, given: Ecs{ EndpointURL: "", }, exp: Ecs{ EndpointURL: "v3-endpoint.local", metadataVersion: 3, }, }, { name: "Endpoint is not set, ECS_CONTAINER_METADATA_URI_V4 is set => use v4 metadata", setEnv: func(t *testing.T) { t.Setenv("ECS_CONTAINER_METADATA_URI_V4", "v4-endpoint.local") }, given: Ecs{ EndpointURL: "", }, exp: Ecs{ EndpointURL: "v4-endpoint.local", metadataVersion: 4, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.setEnv != nil { tt.setEnv(t) } act := tt.given resolveEndpoint(&act) require.Equal(t, tt.exp, act) }) } }