github.com/mier85/go-sensor@v1.30.1-0.20220920111756-9bf41b3bc7e0/fargate_agent_test.go (about) 1 // (c) Copyright IBM Corp. 2021 2 // (c) Copyright Instana Inc. 2020 3 4 //go:build fargate && integration 5 // +build fargate,integration 6 7 package instana_test 8 9 import ( 10 "encoding/json" 11 "log" 12 "net/http" 13 "net/http/httptest" 14 "os" 15 "testing" 16 "time" 17 18 "github.com/instana/testify/assert" 19 "github.com/instana/testify/require" 20 instana "github.com/mier85/go-sensor" 21 ) 22 23 var agent *serverlessAgent 24 25 func TestMain(m *testing.M) { 26 teardownEnv := setupAWSFargateEnv() 27 defer teardownEnv() 28 29 teardownSrv := setupMetadataServer() 30 defer teardownSrv() 31 32 defer restoreEnvVarFunc("INSTANA_AGENT_KEY") 33 os.Setenv("INSTANA_AGENT_KEY", "testkey1") 34 35 defer restoreEnvVarFunc("INSTANA_ZONE") 36 os.Setenv("INSTANA_ZONE", "testzone") 37 38 defer restoreEnvVarFunc("INSTANA_TAGS") 39 os.Setenv("INSTANA_TAGS", "key1=value1,key2") 40 41 defer restoreEnvVarFunc("INSTANA_SECRETS") 42 os.Setenv("INSTANA_SECRETS", "contains-ignore-case:key,password,secret,classified") 43 44 defer restoreEnvVarFunc("CLASSIFIED_DATA") 45 os.Setenv("CLASSIFIED_DATA", "classified") 46 47 var err error 48 agent, err = setupServerlessAgent() 49 if err != nil { 50 log.Fatalf("failed to initialize serverless agent: %s", err) 51 } 52 53 instana.InitSensor(instana.DefaultOptions()) 54 55 os.Exit(m.Run()) 56 } 57 58 func TestFargateAgent_SendMetrics(t *testing.T) { 59 defer agent.Reset() 60 61 require.Eventually(t, func() bool { return len(agent.Bundles) > 0 }, 2*time.Second, 500*time.Millisecond) 62 63 collected := agent.Bundles[0] 64 65 assert.Equal(t, "arn:aws:ecs:us-east-2:012345678910:task/9781c248-0edd-4cdb-9a93-f63cb662a5d3::nginx-curl", collected.Header.Get("X-Instana-Host")) 66 assert.Equal(t, "testkey1", collected.Header.Get("X-Instana-Key")) 67 assert.NotEmpty(t, collected.Header.Get("X-Instana-Time")) 68 69 var payload struct { 70 Metrics struct { 71 Plugins []struct { 72 Name string `json:"name"` 73 EntityID string `json:"entityId"` 74 Data map[string]interface{} `json:"data"` 75 } `json:"plugins"` 76 } `json:"metrics"` 77 } 78 require.NoError(t, json.Unmarshal(collected.Body, &payload)) 79 80 pluginData := make(map[string][]serverlessAgentPluginPayload) 81 for _, plugin := range payload.Metrics.Plugins { 82 pluginData[plugin.Name] = append(pluginData[plugin.Name], serverlessAgentPluginPayload{plugin.EntityID, plugin.Data}) 83 } 84 85 t.Run("AWS ECS Task plugin payload", func(t *testing.T) { 86 require.Len(t, pluginData["com.instana.plugin.aws.ecs.task"], 1) 87 d := pluginData["com.instana.plugin.aws.ecs.task"][0] 88 89 assert.NotEmpty(t, d.EntityID) 90 assert.Equal(t, d.Data["taskArn"], d.EntityID) 91 92 assert.Equal(t, "testzone", d.Data["instanaZone"]) 93 assert.Equal(t, map[string]interface{}{"key1": "value1", "key2": nil}, d.Data["tags"]) 94 assert.Equal(t, "default", d.Data["clusterArn"]) 95 assert.Equal(t, "nginx", d.Data["taskDefinition"]) 96 assert.Equal(t, "5", d.Data["taskDefinitionVersion"]) 97 }) 98 99 t.Run("AWS ECS Container plugin payload", func(t *testing.T) { 100 require.Len(t, pluginData["com.instana.plugin.aws.ecs.container"], 2) 101 102 containers := make(map[string]serverlessAgentPluginPayload) 103 for _, container := range pluginData["com.instana.plugin.aws.ecs.container"] { 104 containers[container.EntityID] = container 105 } 106 107 t.Run("instrumented", func(t *testing.T) { 108 d := containers["arn:aws:ecs:us-east-2:012345678910:task/9781c248-0edd-4cdb-9a93-f63cb662a5d3::nginx-curl"] 109 require.NotEmpty(t, d) 110 111 assert.NotEmpty(t, d.EntityID) 112 113 require.IsType(t, d.Data["taskArn"], "") 114 require.IsType(t, d.Data["containerName"], "") 115 assert.Equal(t, d.Data["taskArn"].(string)+"::"+d.Data["containerName"].(string), d.EntityID) 116 117 if assert.NotEmpty(t, d.Data["taskArn"]) { 118 require.NotEmpty(t, pluginData["com.instana.plugin.aws.ecs.task"]) 119 assert.Equal(t, pluginData["com.instana.plugin.aws.ecs.task"][0].EntityID, d.Data["taskArn"]) 120 } 121 122 assert.Equal(t, true, d.Data["instrumented"]) 123 assert.Equal(t, "go", d.Data["runtime"]) 124 assert.Equal(t, "43481a6ce4842eec8fe72fc28500c6b52edcc0917f105b83379f88cac1ff3946", d.Data["dockerId"]) 125 }) 126 127 t.Run("non-instrumented", func(t *testing.T) { 128 d := containers["arn:aws:ecs:us-east-2:012345678910:task/9781c248-0edd-4cdb-9a93-f63cb662a5d3::~internal~ecs~pause"] 129 require.NotEmpty(t, d) 130 131 assert.NotEmpty(t, d.EntityID) 132 133 require.IsType(t, d.Data["taskArn"], "") 134 require.IsType(t, d.Data["containerName"], "") 135 assert.Equal(t, d.Data["taskArn"].(string)+"::"+d.Data["containerName"].(string), d.EntityID) 136 137 if assert.NotEmpty(t, d.Data["taskArn"]) { 138 require.NotEmpty(t, pluginData["com.instana.plugin.aws.ecs.task"]) 139 assert.Equal(t, pluginData["com.instana.plugin.aws.ecs.task"][0].EntityID, d.Data["taskArn"]) 140 } 141 142 assert.Nil(t, d.Data["instrumented"]) 143 assert.Empty(t, d.Data["runtime"]) 144 assert.Equal(t, "731a0d6a3b4210e2448339bc7015aaa79bfe4fa256384f4102db86ef94cbbc4c", d.Data["dockerId"]) 145 }) 146 }) 147 148 t.Run("Docker plugin payload", func(t *testing.T) { 149 require.Len(t, pluginData["com.instana.plugin.docker"], 2) 150 151 containers := make(map[string]serverlessAgentPluginPayload) 152 for _, container := range pluginData["com.instana.plugin.docker"] { 153 containers[container.EntityID] = container 154 } 155 156 t.Run("instrumented", func(t *testing.T) { 157 d := containers["arn:aws:ecs:us-east-2:012345678910:task/9781c248-0edd-4cdb-9a93-f63cb662a5d3::nginx-curl"] 158 require.NotEmpty(t, d) 159 160 assert.NotEmpty(t, d.EntityID) 161 assert.Equal(t, "43481a6ce4842eec8fe72fc28500c6b52edcc0917f105b83379f88cac1ff3946", d.Data["Id"]) 162 }) 163 164 t.Run("non-instrumented", func(t *testing.T) { 165 d := containers["arn:aws:ecs:us-east-2:012345678910:task/9781c248-0edd-4cdb-9a93-f63cb662a5d3::~internal~ecs~pause"] 166 require.NotEmpty(t, d) 167 168 assert.NotEmpty(t, d.EntityID) 169 assert.Equal(t, "731a0d6a3b4210e2448339bc7015aaa79bfe4fa256384f4102db86ef94cbbc4c", d.Data["Id"]) 170 }) 171 }) 172 173 t.Run("Process plugin payload", func(t *testing.T) { 174 require.Len(t, pluginData["com.instana.plugin.process"], 1) 175 d := pluginData["com.instana.plugin.process"][0] 176 177 assert.NotEmpty(t, d.EntityID) 178 179 assert.Equal(t, "docker", d.Data["containerType"]) 180 assert.Equal(t, "43481a6ce4842eec8fe72fc28500c6b52edcc0917f105b83379f88cac1ff3946", d.Data["container"]) 181 if assert.IsType(t, map[string]interface{}{}, d.Data["env"]) { 182 env := d.Data["env"].(map[string]interface{}) 183 184 assert.Equal(t, os.Getenv("INSTANA_ZONE"), env["INSTANA_ZONE"]) 185 assert.Equal(t, os.Getenv("INSTANA_TAGS"), env["INSTANA_TAGS"]) 186 assert.Equal(t, os.Getenv("INSTANA_AGENT_KEY"), env["INSTANA_AGENT_KEY"]) 187 188 assert.Equal(t, "<redacted>", env["INSTANA_SECRETS"]) 189 assert.Equal(t, "<redacted>", env["CLASSIFIED_DATA"]) 190 } 191 }) 192 193 t.Run("Go process plugin payload", func(t *testing.T) { 194 require.Len(t, pluginData["com.instana.plugin.golang"], 1) 195 d := pluginData["com.instana.plugin.golang"][0] 196 197 assert.NotEmpty(t, d.EntityID) 198 199 require.NotEmpty(t, pluginData["com.instana.plugin.process"]) 200 assert.Equal(t, pluginData["com.instana.plugin.process"][0].EntityID, d.EntityID) 201 202 assert.NotEmpty(t, d.Data["metrics"]) 203 }) 204 } 205 206 func TestFargateAgent_SendSpans(t *testing.T) { 207 defer agent.Reset() 208 209 sensor := instana.NewSensor("testing") 210 211 sp := sensor.Tracer().StartSpan("entry") 212 sp.SetTag("value", "42") 213 sp.Finish() 214 215 require.Eventually(t, func() bool { 216 if len(agent.Bundles) == 0 { 217 return false 218 } 219 220 for _, bundle := range agent.Bundles { 221 var payload struct { 222 Spans []json.RawMessage `json:"spans"` 223 } 224 225 json.Unmarshal(bundle.Body, &payload) 226 if len(payload.Spans) > 0 { 227 return true 228 } 229 } 230 231 return false 232 }, 4*time.Second, 500*time.Millisecond) 233 234 var spans []map[string]json.RawMessage 235 for _, bundle := range agent.Bundles { 236 var payload struct { 237 Spans []map[string]json.RawMessage `json:"spans"` 238 } 239 240 require.NoError(t, json.Unmarshal(bundle.Body, &payload), "%s", string(bundle.Body)) 241 spans = append(spans, payload.Spans...) 242 } 243 244 require.Len(t, spans, 1) 245 assert.JSONEq(t, `{"hl": true, "cp": "aws", "e": "arn:aws:ecs:us-east-2:012345678910:task/9781c248-0edd-4cdb-9a93-f63cb662a5d3::nginx-curl"}`, string(spans[0]["f"])) 246 } 247 248 func setupAWSFargateEnv() func() { 249 teardown := restoreEnvVarFunc("AWS_EXECUTION_ENV") 250 os.Setenv("AWS_EXECUTION_ENV", "AWS_ECS_FARGATE") 251 252 return teardown 253 } 254 255 func setupMetadataServer() func() { 256 mux := http.NewServeMux() 257 mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { 258 http.ServeFile(w, req, "aws/testdata/container_metadata.json") 259 }) 260 mux.HandleFunc("/task", func(w http.ResponseWriter, req *http.Request) { 261 http.ServeFile(w, req, "aws/testdata/task_metadata.json") 262 }) 263 mux.HandleFunc("/task/stats", func(w http.ResponseWriter, req *http.Request) { 264 http.ServeFile(w, req, "aws/testdata/task_stats.json") 265 }) 266 267 srv := httptest.NewServer(mux) 268 269 teardown := restoreEnvVarFunc("ECS_CONTAINER_METADATA_URI") 270 os.Setenv("ECS_CONTAINER_METADATA_URI", srv.URL) 271 272 return func() { 273 teardown() 274 srv.Close() 275 } 276 }