github.phpd.cn/cilium/cilium@v1.6.12/test/runtime/monitor.go (about) 1 // Copyright 2017 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package RuntimeTest 16 17 import ( 18 "context" 19 "fmt" 20 "math/rand" 21 "strings" 22 "time" 23 24 . "github.com/cilium/cilium/test/ginkgo-ext" 25 "github.com/cilium/cilium/test/helpers" 26 27 . "github.com/onsi/gomega" 28 ) 29 30 func init() { 31 // ensure that our random numbers are seeded differently on each run 32 rand.Seed(time.Now().UnixNano()) 33 } 34 35 const ( 36 // MonitorDropNotification represents the DropNotification configuration 37 // value for the Cilium monitor 38 MonitorDropNotification = "DropNotification" 39 40 // MonitorTraceNotification represents the TraceNotification configuration 41 // value for the Cilium monitor 42 MonitorTraceNotification = "TraceNotification" 43 ) 44 45 var _ = Describe("RuntimeMonitorTest", func() { 46 47 var vm *helpers.SSHMeta 48 49 BeforeAll(func() { 50 vm = helpers.InitRuntimeHelper(helpers.Runtime, logger) 51 ExpectCiliumReady(vm) 52 53 areEndpointsReady := vm.WaitEndpointsReady() 54 Expect(areEndpointsReady).Should(BeTrue()) 55 }) 56 57 JustAfterEach(func() { 58 vm.ValidateNoErrorsInLogs(CurrentGinkgoTestDescription().Duration) 59 }) 60 61 AfterFailed(func() { 62 vm.ReportFailed() 63 }) 64 65 BeforeEach(func() { 66 ExpectPolicyEnforcementUpdated(vm, helpers.PolicyEnforcementDefault) 67 }) 68 69 AfterAll(func() { 70 vm.CloseSSHClient() 71 }) 72 73 Context("With Sample Containers", func() { 74 75 BeforeAll(func() { 76 vm.SampleContainersActions(helpers.Create, helpers.CiliumDockerNetwork) 77 }) 78 79 AfterEach(func() { 80 _ = vm.PolicyDelAll() 81 }) 82 83 AfterAll(func() { 84 vm.SampleContainersActions(helpers.Delete, helpers.CiliumDockerNetwork) 85 }) 86 87 monitorConfig := func() { 88 res := vm.ExecCilium(fmt.Sprintf("config %s=true %s=true", 89 MonitorDropNotification, MonitorTraceNotification)) 90 ExpectWithOffset(1, res.WasSuccessful()).To(BeTrue(), "cannot update monitor config") 91 } 92 93 It("Cilium monitor verbose mode", func() { 94 monitorConfig() 95 96 ctx, cancel := context.WithCancel(context.Background()) 97 res := vm.ExecInBackground(ctx, "cilium monitor -v") 98 defer cancel() 99 100 areEndpointsReady := vm.WaitEndpointsReady() 101 Expect(areEndpointsReady).Should(BeTrue()) 102 103 endpoints, err := vm.GetEndpointsIds() 104 Expect(err).Should(BeNil()) 105 106 for k, v := range endpoints { 107 filter := fmt.Sprintf("FROM %s DEBUG:", v) 108 vm.ContainerExec(k, helpers.Ping(helpers.Httpd1)) 109 Expect(res.WaitUntilMatch(filter)).To(BeNil(), 110 "%q is not in the output after timeout", filter) 111 Expect(res.Output().String()).Should(ContainSubstring(filter)) 112 } 113 }) 114 115 It("Cilium monitor event types", func() { 116 monitorConfig() 117 118 _, err := vm.PolicyImportAndWait(vm.GetFullPath(policiesL3JSON), helpers.HelperTimeout) 119 Expect(err).Should(BeNil()) 120 121 areEndpointsReady := vm.WaitEndpointsReady() 122 Expect(areEndpointsReady).Should(BeTrue(), "Endpoints are not ready after timeout") 123 124 eventTypes := map[string]string{ 125 "drop": "DROP:", 126 "debug": "DEBUG:", 127 "capture": "DEBUG:", 128 } 129 130 for k, v := range eventTypes { 131 By("Type %s", k) 132 133 ctx, cancel := context.WithCancel(context.Background()) 134 defer cancel() 135 res := vm.ExecInBackground(ctx, fmt.Sprintf("cilium monitor --type %s -v", k)) 136 137 vm.ContainerExec(helpers.App1, helpers.Ping(helpers.Httpd1)) 138 vm.ContainerExec(helpers.App3, helpers.Ping(helpers.Httpd1)) 139 140 Expect(res.WaitUntilMatch(v)).To(BeNil(), 141 "%q is not in the output after timeout", v) 142 Expect(res.CountLines()).Should(BeNumerically(">", 3)) 143 Expect(res.Output().String()).Should(ContainSubstring(v)) 144 cancel() 145 } 146 147 By("all types together") 148 command := "cilium monitor -v" 149 for k := range eventTypes { 150 command = command + " --type " + k 151 } 152 153 ctx, cancel := context.WithCancel(context.Background()) 154 defer cancel() 155 156 By(command) 157 res := vm.ExecInBackground(ctx, command) 158 159 areEndpointsReady = vm.WaitEndpointsReady() 160 Expect(areEndpointsReady).Should(BeTrue()) 161 162 vm.ContainerExec(helpers.App3, helpers.Ping(helpers.Httpd1)) 163 vm.ContainerExec(helpers.App1, helpers.Ping(helpers.Httpd1)) 164 165 for _, v := range eventTypes { 166 Expect(res.WaitUntilMatch(v)).To(BeNil(), 167 "%q is not in the output after timeout", v) 168 Expect(res.Output().String()).Should(ContainSubstring(v)) 169 } 170 171 Expect(res.CountLines()).Should(BeNumerically(">", 3)) 172 }) 173 174 It("cilium monitor check --from", func() { 175 monitorConfig() 176 177 areEndpointsReady := vm.WaitEndpointsReady() 178 Expect(areEndpointsReady).Should(BeTrue()) 179 180 endpoints, err := vm.GetEndpointsIds() 181 Expect(err).Should(BeNil()) 182 183 ctx, cancel := context.WithCancel(context.Background()) 184 defer cancel() 185 186 res := vm.ExecInBackground(ctx, fmt.Sprintf( 187 "cilium monitor --type debug --from %s -v", endpoints[helpers.App1])) 188 vm.ContainerExec(helpers.App1, helpers.Ping(helpers.Httpd1)) 189 190 filter := fmt.Sprintf("FROM %s DEBUG:", endpoints[helpers.App1]) 191 Expect(res.WaitUntilMatch(filter)).To(BeNil(), 192 "%q is not in the output after timeout", filter) 193 Expect(res.CountLines()).Should(BeNumerically(">", 3)) 194 Expect(res.Output().String()).Should(ContainSubstring(filter)) 195 196 //MonitorDebug mode shouldn't have DROP lines 197 Expect(res.Output().String()).ShouldNot(ContainSubstring("DROP")) 198 }) 199 200 It("cilium monitor check --to", func() { 201 monitorConfig() 202 203 areEndpointsReady := vm.WaitEndpointsReady() 204 Expect(areEndpointsReady).Should(BeTrue()) 205 206 endpoints, err := vm.GetEndpointsIds() 207 Expect(err).Should(BeNil()) 208 209 ctx, cancel := context.WithCancel(context.Background()) 210 defer cancel() 211 res := vm.ExecInBackground(ctx, fmt.Sprintf( 212 "cilium monitor -v --to %s", endpoints[helpers.Httpd1])) 213 214 vm.ContainerExec(helpers.App1, helpers.Ping(helpers.Httpd1)) 215 vm.ContainerExec(helpers.App2, helpers.Ping(helpers.Httpd1)) 216 217 filter := fmt.Sprintf("to endpoint %s", endpoints[helpers.Httpd1]) 218 Expect(res.WaitUntilMatch(filter)).To(BeNil(), 219 "%q is not in the output after timeout", filter) 220 Expect(res.CountLines()).Should(BeNumerically(">=", 3)) 221 Expect(res.Output().String()).Should(ContainSubstring(filter)) 222 }) 223 224 It("cilium monitor check --related-to", func() { 225 monitorConfig() 226 227 areEndpointsReady := vm.WaitEndpointsReady() 228 Expect(areEndpointsReady).Should(BeTrue()) 229 230 endpoints, err := vm.GetEndpointsIds() 231 Expect(err).Should(BeNil()) 232 233 ctx, cancel := context.WithCancel(context.Background()) 234 defer cancel() 235 res := vm.ExecInBackground(ctx, fmt.Sprintf( 236 "cilium monitor -v --related-to %s", endpoints[helpers.Httpd1])) 237 238 vm.WaitEndpointsReady() 239 vm.ContainerExec(helpers.App1, helpers.CurlFail("http://httpd1/public")) 240 241 filter := fmt.Sprintf("FROM %s DEBUG:", endpoints[helpers.Httpd1]) 242 Expect(res.WaitUntilMatch(filter)).To(BeNil(), 243 "%q is not in the output after timeout", filter) 244 Expect(res.CountLines()).Should(BeNumerically(">=", 3)) 245 Expect(res.Output().String()).Should(ContainSubstring(filter)) 246 }) 247 248 It("delivers the same information to multiple monitors", func() { 249 monitorConfig() 250 251 areEndpointsReady := vm.WaitEndpointsReady() 252 Expect(areEndpointsReady).Should(BeTrue(), "Endpoints are not ready after timeout") 253 254 var monitorRes []*helpers.CmdRes 255 ctx, cancelfn := context.WithCancel(context.Background()) 256 257 for i := 1; i <= 3; i++ { 258 monitorRes = append(monitorRes, vm.ExecInBackground(ctx, "cilium monitor")) 259 } 260 261 vm.ContainerExec(helpers.App1, helpers.Ping(helpers.Httpd1)) 262 cancelfn() 263 264 for _, res := range monitorRes { 265 res.WaitUntilFinish() 266 } 267 268 Expect(monitorRes[0].CountLines()).Should(BeNumerically(">", 2)) 269 270 // Some monitor instances may see more data than others due to timing. We 271 // want to find a run of lines that matches between all monitor 272 // instances, ignoring earlier or later lines that may have not been seen 273 // by an instance. We find the shortest sample and check that those lines 274 // occur in all monitor responses. 275 var ( 276 // shortestResult is the smallest set of monitor output lines, after we 277 // trim leading init lines. 278 shortestResult string 279 280 // Output lines from each monitor, trimmed to ignore init messages. 281 // The order matches monitorRes. 282 trimmedResults []string 283 ) 284 285 // Trim the result lines to ignore startup/shutdown messages like 286 // "level=info msg="Initializing dissection cache..." subsys=monitor" 287 // "Received an interrupt, disconnecting from monitor..." 288 // and note the shortest 289 for _, result := range monitorRes { 290 lines := result.ByLines() 291 trimmedResult := make([]string, 0, len(lines)) 292 for _, line := range lines { 293 if strings.HasPrefix(line, " <- endpoint") { 294 trimmedResult = append(trimmedResult, line) 295 } 296 } 297 trimmedResults = append(trimmedResults, strings.Join(trimmedResult, "\n")) 298 299 if len(trimmedResult) < len(shortestResult) { 300 shortestResult = strings.Join(trimmedResult, "\n") 301 } 302 } 303 304 // The shortest output must occur in whole within the other outputs 305 for _, trimmedResult := range trimmedResults { 306 Expect(strings.Contains(trimmedResult, shortestResult)).Should(Equal(true), 307 "Inconsistent monitor output between 2 monitor instances during the same time period\nExpected:\n%s\nFound:\n%s\n", shortestResult, trimmedResult) 308 } 309 }) 310 311 It("checks container ids match monitor output", func() { 312 ExpectPolicyEnforcementUpdated(vm, helpers.PolicyEnforcementAlways) 313 314 ctx, cancel := context.WithCancel(context.Background()) 315 res := vm.ExecInBackground(ctx, "cilium monitor -v") 316 317 vm.ContainerExec(helpers.App1, helpers.Ping(helpers.Httpd1)) 318 vm.ContainerExec(helpers.Httpd1, helpers.Ping(helpers.App1)) 319 320 endpoints, err := vm.GetEndpointsIDMap() 321 Expect(err).Should(BeNil()) 322 323 helpers.Sleep(10) 324 cancel() 325 326 // Expected full example output: 327 // CPU 01: MARK 0x3de3947b FROM 48896 DEBUG: Attempting local delivery for container id 29381 from seclabel 263 328 // ^ ^ 329 for _, line := range res.ByLines() { 330 var toID, fromID string 331 332 fields := strings.Split(line, " ") 333 for i := range fields { 334 switch fields[i] { 335 case "FROM": 336 fromID = fields[i+1] 337 break 338 case "id": 339 toID = fields[i+1] 340 break 341 } 342 } 343 if fromID == "" || toID == "" { 344 continue 345 } 346 By("checking endpoints in monitor line:\n%q", line) 347 348 Expect(toID).Should(Not(Equal(fromID))) 349 Expect(endpoints[toID]).Should(Not(BeNil())) 350 Expect(endpoints[fromID]).Should(Not(BeNil())) 351 } 352 }) 353 }) 354 })