github.com/cloudfoundry-attic/ltc@v0.0.0-20151123212628-098adc7919fc/app_examiner/app_examiner_test.go (about) 1 package app_examiner_test 2 3 import ( 4 "errors" 5 6 . "github.com/onsi/ginkgo" 7 . "github.com/onsi/gomega" 8 9 "github.com/cloudfoundry-incubator/bbs/models" 10 "github.com/cloudfoundry-incubator/ltc/app_examiner" 11 "github.com/cloudfoundry-incubator/ltc/app_examiner/fake_noaa_consumer" 12 "github.com/cloudfoundry-incubator/ltc/route_helpers" 13 "github.com/cloudfoundry-incubator/receptor" 14 "github.com/cloudfoundry-incubator/receptor/fake_receptor" 15 "github.com/cloudfoundry/sonde-go/events" 16 ) 17 18 var _ = Describe("AppExaminer", func() { 19 20 var ( 21 fakeReceptorClient *fake_receptor.FakeClient 22 fakeNoaaConsumer *fake_noaa_consumer.FakeNoaaConsumer 23 appExaminer app_examiner.AppExaminer 24 ) 25 26 BeforeEach(func() { 27 fakeReceptorClient = &fake_receptor.FakeClient{} 28 fakeNoaaConsumer = &fake_noaa_consumer.FakeNoaaConsumer{} 29 appExaminer = app_examiner.New(fakeReceptorClient, fakeNoaaConsumer) 30 }) 31 32 Describe("ListApps", func() { 33 Context("with the receptor returning both desiredlrps and actuallrps", func() { 34 BeforeEach(func() { 35 desiredLrps := []receptor.DesiredLRPResponse{ 36 { 37 ProcessGuid: "process2-scalingDown", 38 Instances: 0, 39 DiskMB: 564, 40 MemoryMB: 200, 41 Routes: route_helpers.Routes{ 42 AppRoutes: route_helpers.AppRoutes{ 43 {Hostnames: []string{"ren", "stimpy"}}, 44 }}.RoutingInfo(), 45 }, 46 { 47 ProcessGuid: "process1-scalingUp", 48 Instances: 2, 49 DiskMB: 256, 50 MemoryMB: 100, 51 Routes: route_helpers.Routes{ 52 AppRoutes: route_helpers.AppRoutes{ 53 {Hostnames: []string{"happy", "joy"}}, 54 }}.RoutingInfo(), 55 EnvironmentVariables: []receptor.EnvironmentVariable{}, 56 StartTimeout: 30, 57 CPUWeight: 94, 58 Ports: []uint16{2378, 67}, 59 LogGuid: "asdf-ojf93-9sdcsdk", 60 LogSource: "proc1-log", 61 Annotation: "Best process this side o' the Mississippi.", 62 }, 63 } 64 fakeReceptorClient.DesiredLRPsReturns(desiredLrps, nil) 65 66 actualLrps := []receptor.ActualLRPResponse{ 67 {ProcessGuid: "process3-stopping", InstanceGuid: "guid4", Index: 1, State: receptor.ActualLRPStateRunning}, 68 {ProcessGuid: "process1-scalingUp", InstanceGuid: "guid1", Index: 1, State: receptor.ActualLRPStateRunning}, 69 {ProcessGuid: "process1-scalingUp", InstanceGuid: "guid2", Index: 2, State: receptor.ActualLRPStateClaimed}, 70 {ProcessGuid: "process2-scalingDown", InstanceGuid: "guid3", Index: 1, State: receptor.ActualLRPStateRunning}, 71 } 72 fakeReceptorClient.ActualLRPsReturns(actualLrps, nil) 73 }) 74 75 It("returns a list of alphabetically sorted examined apps", func() { 76 appList, err := appExaminer.ListApps() 77 78 Expect(err).NotTo(HaveOccurred()) 79 Expect(appList).To(HaveLen(3)) 80 81 process1 := appList[0] 82 Expect(process1.ProcessGuid).To(Equal("process1-scalingUp")) 83 Expect(process1.DesiredInstances).To(Equal(2)) 84 Expect(process1.ActualRunningInstances).To(Equal(1)) 85 Expect(process1.DiskMB).To(Equal(256)) 86 Expect(process1.MemoryMB).To(Equal(100)) 87 Expect(process1.Routes).To(Equal( 88 route_helpers.Routes{ 89 AppRoutes: route_helpers.AppRoutes{ 90 {Hostnames: []string{"happy", "joy"}}, 91 }, 92 })) 93 Expect(process1.EnvironmentVariables).To(Equal([]app_examiner.EnvironmentVariable{})) 94 Expect(process1.StartTimeout).To(Equal(uint(30))) 95 Expect(process1.CPUWeight).To(Equal(uint(94))) 96 Expect(process1.Ports).To(Equal([]uint16{2378, 67})) 97 Expect(process1.LogGuid).To(Equal("asdf-ojf93-9sdcsdk")) 98 Expect(process1.LogSource).To(Equal("proc1-log")) 99 Expect(process1.Annotation).To(Equal("Best process this side o' the Mississippi.")) 100 101 process2 := appList[1] 102 Expect(process2.ProcessGuid).To(Equal("process2-scalingDown")) 103 Expect(process2.DesiredInstances).To(Equal(0)) 104 Expect(process2.ActualRunningInstances).To(Equal(1)) 105 Expect(process2.DiskMB).To(Equal(564)) 106 Expect(process2.MemoryMB).To(Equal(200)) 107 Expect(process2.Routes).To(Equal( 108 route_helpers.Routes{ 109 AppRoutes: route_helpers.AppRoutes{ 110 {Hostnames: []string{"ren", "stimpy"}}, 111 }, 112 })) 113 114 process3 := appList[2] 115 Expect(process3.ProcessGuid).To(Equal("process3-stopping")) 116 Expect(process3.DesiredInstances).To(Equal(0)) 117 Expect(process3.ActualRunningInstances).To(Equal(1)) 118 Expect(process3.DiskMB).To(Equal(0)) 119 Expect(process3.MemoryMB).To(Equal(0)) 120 Expect(process3.Routes).To(BeZero()) 121 }) 122 123 Context("with tcp-route", func() { 124 BeforeEach(func() { 125 desiredLrps := []receptor.DesiredLRPResponse{ 126 receptor.DesiredLRPResponse{ 127 ProcessGuid: "process2-scalingDown", 128 Instances: 0, 129 DiskMB: 564, 130 MemoryMB: 200, 131 Routes: route_helpers.Routes{ 132 AppRoutes: route_helpers.AppRoutes{ 133 {Hostnames: []string{"ren", "stimpy"}}}, 134 TcpRoutes: route_helpers.TcpRoutes{ 135 {ExternalPort: 51000, Port: 5222}, 136 }, 137 }.RoutingInfo(), 138 }, 139 receptor.DesiredLRPResponse{ 140 ProcessGuid: "process1-scalingUp", 141 Instances: 2, 142 DiskMB: 256, 143 MemoryMB: 100, 144 Routes: route_helpers.Routes{ 145 AppRoutes: route_helpers.AppRoutes{ 146 {Hostnames: []string{"happy", "joy"}}, 147 }, 148 TcpRoutes: route_helpers.TcpRoutes{ 149 {ExternalPort: 52000, Port: 5222}, 150 }, 151 }.RoutingInfo(), 152 EnvironmentVariables: []receptor.EnvironmentVariable{}, 153 StartTimeout: 30, 154 CPUWeight: 94, 155 Ports: []uint16{2378, 67}, 156 LogGuid: "asdf-ojf93-9sdcsdk", 157 LogSource: "proc1-log", 158 Annotation: "Best process this side o' the Mississippi.", 159 }, 160 } 161 fakeReceptorClient.DesiredLRPsReturns(desiredLrps, nil) 162 163 actualLrps := []receptor.ActualLRPResponse{ 164 receptor.ActualLRPResponse{ProcessGuid: "process3-stopping", InstanceGuid: "guid4", Index: 1, State: receptor.ActualLRPStateRunning}, 165 receptor.ActualLRPResponse{ProcessGuid: "process1-scalingUp", InstanceGuid: "guid1", Index: 1, State: receptor.ActualLRPStateRunning}, 166 receptor.ActualLRPResponse{ProcessGuid: "process1-scalingUp", InstanceGuid: "guid2", Index: 2, State: receptor.ActualLRPStateClaimed}, 167 receptor.ActualLRPResponse{ProcessGuid: "process2-scalingDown", InstanceGuid: "guid3", Index: 1, State: receptor.ActualLRPStateRunning}, 168 } 169 fakeReceptorClient.ActualLRPsReturns(actualLrps, nil) 170 }) 171 172 It("returns a list of alphabetically sorted examined apps with tcp routes", func() { 173 appList, err := appExaminer.ListApps() 174 175 Expect(err).NotTo(HaveOccurred()) 176 Expect(appList).To(HaveLen(3)) 177 178 process1 := appList[0] 179 Expect(process1.ProcessGuid).To(Equal("process1-scalingUp")) 180 Expect(process1.DesiredInstances).To(Equal(2)) 181 Expect(process1.ActualRunningInstances).To(Equal(1)) 182 Expect(process1.DiskMB).To(Equal(256)) 183 Expect(process1.MemoryMB).To(Equal(100)) 184 Expect(process1.Routes).To(Equal( 185 route_helpers.Routes{ 186 AppRoutes: route_helpers.AppRoutes{ 187 {Hostnames: []string{"happy", "joy"}}, 188 }, 189 TcpRoutes: route_helpers.TcpRoutes{ 190 { 191 ExternalPort: 52000, 192 Port: 5222, 193 }, 194 }, 195 })) 196 Expect(process1.EnvironmentVariables).To(Equal([]app_examiner.EnvironmentVariable{})) 197 Expect(process1.StartTimeout).To(Equal(uint(30))) 198 Expect(process1.CPUWeight).To(Equal(uint(94))) 199 Expect(process1.Ports).To(Equal([]uint16{2378, 67})) 200 Expect(process1.LogGuid).To(Equal("asdf-ojf93-9sdcsdk")) 201 Expect(process1.LogSource).To(Equal("proc1-log")) 202 Expect(process1.Annotation).To(Equal("Best process this side o' the Mississippi.")) 203 204 process2 := appList[1] 205 Expect(process2.ProcessGuid).To(Equal("process2-scalingDown")) 206 Expect(process2.DesiredInstances).To(Equal(0)) 207 Expect(process2.ActualRunningInstances).To(Equal(1)) 208 Expect(process2.DiskMB).To(Equal(564)) 209 Expect(process2.MemoryMB).To(Equal(200)) 210 Expect(process2.Routes).To(Equal( 211 route_helpers.Routes{ 212 AppRoutes: route_helpers.AppRoutes{ 213 {Hostnames: []string{"ren", "stimpy"}}, 214 }, 215 TcpRoutes: route_helpers.TcpRoutes{ 216 {ExternalPort: 51000, Port: 5222}, 217 }, 218 })) 219 220 process3 := appList[2] 221 Expect(process3.ProcessGuid).To(Equal("process3-stopping")) 222 Expect(process3.DesiredInstances).To(Equal(0)) 223 Expect(process3.ActualRunningInstances).To(Equal(1)) 224 Expect(process3.DiskMB).To(Equal(0)) 225 Expect(process3.MemoryMB).To(Equal(0)) 226 Expect(process3.Routes).To(BeZero()) 227 }) 228 }) 229 }) 230 231 Context("when the receptor returns errors", func() { 232 It("returns errors from from fetching the DesiredLRPs", func() { 233 fakeReceptorClient.DesiredLRPsReturns(nil, errors.New("You should go catch it.")) 234 235 _, err := appExaminer.ListApps() 236 Expect(err).To(MatchError("You should go catch it.")) 237 }) 238 239 It("returns errors from fetching the ActualLRPs", func() { 240 fakeReceptorClient.ActualLRPsReturns(nil, errors.New("Receptor is on fire!!")) 241 242 _, err := appExaminer.ListApps() 243 Expect(err).To(MatchError("Receptor is on fire!!")) 244 }) 245 }) 246 }) 247 248 Describe("ListCells", func() { 249 Context("receptor returns actual lrps that are all on existing cells", func() { 250 BeforeEach(func() { 251 actualLrps := []receptor.ActualLRPResponse{ 252 receptor.ActualLRPResponse{CellID: "Cell-1", State: receptor.ActualLRPStateRunning}, 253 receptor.ActualLRPResponse{CellID: "Cell-1", State: receptor.ActualLRPStateRunning}, 254 receptor.ActualLRPResponse{CellID: "Cell-2", State: receptor.ActualLRPStateClaimed}, 255 receptor.ActualLRPResponse{CellID: "Cell-2", State: receptor.ActualLRPStateRunning}, 256 } 257 fakeReceptorClient.ActualLRPsReturns(actualLrps, nil) 258 259 cells := []receptor.CellResponse{ 260 receptor.CellResponse{CellID: "Cell-1", Zone: "z1", Capacity: receptor.CellCapacity{MemoryMB: 12394, DiskMB: 2349083, Containers: 512}}, 261 receptor.CellResponse{CellID: "Cell-2", Zone: "z1", Capacity: receptor.CellCapacity{MemoryMB: 12394, DiskMB: 2349083, Containers: 512}}, 262 receptor.CellResponse{CellID: "Cell-3", Zone: "z2", Capacity: receptor.CellCapacity{MemoryMB: 12394, DiskMB: 2349083, Containers: 512}}, 263 } 264 fakeReceptorClient.CellsReturns(cells, nil) 265 }) 266 267 It("returns a list of alphabetically sorted examined cells", func() { 268 cellList, err := appExaminer.ListCells() 269 Expect(err).NotTo(HaveOccurred()) 270 Expect(cellList).To(HaveLen(3)) 271 272 cell1 := cellList[0] 273 Expect(cell1.CellID).To(Equal("Cell-1")) 274 Expect(cell1.RunningInstances).To(Equal(2)) 275 Expect(cell1.ClaimedInstances).To(Equal(0)) 276 Expect(cell1.Zone).To(Equal("z1")) 277 Expect(cell1.MemoryMB).To(Equal(12394)) 278 Expect(cell1.DiskMB).To(Equal(2349083)) 279 Expect(cell1.Containers).To(Equal(512)) 280 281 cell2 := cellList[1] 282 Expect(cell2.CellID).To(Equal("Cell-2")) 283 Expect(cell2.RunningInstances).To(Equal(1)) 284 Expect(cell2.ClaimedInstances).To(Equal(1)) 285 Expect(cell2.Zone).To(Equal("z1")) 286 287 cell3 := cellList[2] 288 Expect(cell3.CellID).To(Equal("Cell-3")) 289 Expect(cell3.RunningInstances).To(Equal(0)) 290 Expect(cell3.ClaimedInstances).To(Equal(0)) 291 Expect(cell3.Zone).To(Equal("z2")) 292 }) 293 }) 294 295 Context("receptor returns actual lrps that are all on existing cells with Diff Cell IDs", func() { 296 BeforeEach(func() { 297 actualLrps := []receptor.ActualLRPResponse{ 298 receptor.ActualLRPResponse{CellID: "lattice-east-01", State: receptor.ActualLRPStateRunning}, 299 receptor.ActualLRPResponse{CellID: "lattice-east-01", State: receptor.ActualLRPStateRunning}, 300 receptor.ActualLRPResponse{CellID: "north-2", State: receptor.ActualLRPStateClaimed}, 301 receptor.ActualLRPResponse{CellID: "north-2", State: receptor.ActualLRPStateRunning}, 302 receptor.ActualLRPResponse{CellID: "lattice-cell-10", State: receptor.ActualLRPStateRunning}, 303 receptor.ActualLRPResponse{CellID: "lattice-cell-10", State: receptor.ActualLRPStateRunning}, 304 } 305 fakeReceptorClient.ActualLRPsReturns(actualLrps, nil) 306 307 cells := []receptor.CellResponse{ 308 receptor.CellResponse{CellID: "lattice-east-01", Zone: "z1", Capacity: receptor.CellCapacity{MemoryMB: 12394, DiskMB: 2349083, Containers: 512}}, 309 receptor.CellResponse{CellID: "north-2", Zone: "z1", Capacity: receptor.CellCapacity{MemoryMB: 12394, DiskMB: 2349083, Containers: 512}}, 310 receptor.CellResponse{CellID: "lattice-random-3", Zone: "z2", Capacity: receptor.CellCapacity{MemoryMB: 12394, DiskMB: 2349083, Containers: 512}}, 311 receptor.CellResponse{CellID: "lattice-Jamesbond", Zone: "z9", Capacity: receptor.CellCapacity{MemoryMB: 12394, DiskMB: 2349083, Containers: 512}}, 312 receptor.CellResponse{CellID: "lattice-cell-10", Zone: "z10", Capacity: receptor.CellCapacity{MemoryMB: 12394, DiskMB: 2349083, Containers: 512}}, 313 receptor.CellResponse{CellID: "lattice-ReallyBig-10000000", Zone: "z11", Capacity: receptor.CellCapacity{MemoryMB: 12394, DiskMB: 2349083, Containers: 512}}, 314 } 315 fakeReceptorClient.CellsReturns(cells, nil) 316 }) 317 318 It("returns a list of numarically sorted examined cells", func() { 319 cellList, err := appExaminer.ListCells() 320 Expect(err).NotTo(HaveOccurred()) 321 Expect(cellList).To(HaveLen(6)) 322 323 cell1 := cellList[0] 324 Expect(cell1.CellID).To(Equal("lattice-east-01")) 325 Expect(cell1.RunningInstances).To(Equal(2)) 326 Expect(cell1.ClaimedInstances).To(Equal(0)) 327 Expect(cell1.Zone).To(Equal("z1")) 328 Expect(cell1.MemoryMB).To(Equal(12394)) 329 Expect(cell1.DiskMB).To(Equal(2349083)) 330 Expect(cell1.Containers).To(Equal(512)) 331 332 cell2 := cellList[1] 333 Expect(cell2.CellID).To(Equal("north-2")) 334 Expect(cell2.RunningInstances).To(Equal(1)) 335 Expect(cell2.ClaimedInstances).To(Equal(1)) 336 Expect(cell2.Zone).To(Equal("z1")) 337 338 cell3 := cellList[2] 339 Expect(cell3.CellID).To(Equal("lattice-random-3")) 340 Expect(cell3.RunningInstances).To(Equal(0)) 341 Expect(cell3.ClaimedInstances).To(Equal(0)) 342 Expect(cell3.Zone).To(Equal("z2")) 343 344 cell4 := cellList[3] 345 Expect(cell4.CellID).To(Equal("lattice-cell-10")) 346 Expect(cell4.RunningInstances).To(Equal(2)) 347 Expect(cell4.ClaimedInstances).To(Equal(0)) 348 Expect(cell4.Zone).To(Equal("z10")) 349 350 cell5 := cellList[4] 351 Expect(cell5.CellID).To(Equal("lattice-ReallyBig-10000000")) 352 Expect(cell5.RunningInstances).To(Equal(0)) 353 Expect(cell5.ClaimedInstances).To(Equal(0)) 354 Expect(cell5.Zone).To(Equal("z11")) 355 356 cell6 := cellList[5] 357 Expect(cell6.CellID).To(Equal("lattice-Jamesbond")) 358 Expect(cell6.RunningInstances).To(Equal(0)) 359 Expect(cell6.ClaimedInstances).To(Equal(0)) 360 Expect(cell6.Zone).To(Equal("z9")) 361 362 }) 363 }) 364 365 Context("receptor returns actual lrps, and some of their cells no longer exist", func() { 366 BeforeEach(func() { 367 actualLrps := []receptor.ActualLRPResponse{ 368 {CellID: "Cell-0", State: receptor.ActualLRPStateRunning}, 369 {CellID: "Cell-0", State: receptor.ActualLRPStateClaimed}, 370 {CellID: "Cell-1", State: receptor.ActualLRPStateRunning}, 371 } 372 fakeReceptorClient.ActualLRPsReturns(actualLrps, nil) 373 cells := []receptor.CellResponse{ 374 {CellID: "Cell-1"}, 375 } 376 fakeReceptorClient.CellsReturns(cells, nil) 377 }) 378 379 It("returns a list of alphabetically sorted examined cells", func() { 380 cellList, err := appExaminer.ListCells() 381 Expect(err).NotTo(HaveOccurred()) 382 Expect(cellList).To(HaveLen(2)) 383 384 cell0 := cellList[0] 385 Expect(cell0.CellID).To(Equal("Cell-0")) 386 Expect(cell0.Missing).To(BeTrue()) 387 Expect(cell0.RunningInstances).To(Equal(1)) 388 Expect(cell0.ClaimedInstances).To(Equal(1)) 389 }) 390 }) 391 392 Context("receptor returns unclaimed actual lrps", func() { 393 BeforeEach(func() { 394 actualLrps := []receptor.ActualLRPResponse{ 395 {State: receptor.ActualLRPStateUnclaimed}, 396 {State: receptor.ActualLRPStateUnclaimed}, 397 } 398 fakeReceptorClient.ActualLRPsReturns(actualLrps, nil) 399 fakeReceptorClient.CellsReturns([]receptor.CellResponse{}, nil) 400 }) 401 402 It("ignores unclaimed actual lrps", func() { 403 cellList, err := appExaminer.ListCells() 404 Expect(err).NotTo(HaveOccurred()) 405 Expect(cellList).To(HaveLen(0)) 406 }) 407 }) 408 409 Context("with the receptor returning errors", func() { 410 It("returns errors from from fetching the Cells", func() { 411 fakeReceptorClient.CellsReturns(nil, errors.New("You should go catch it.")) 412 413 _, err := appExaminer.ListCells() 414 Expect(err).To(MatchError("You should go catch it.")) 415 }) 416 417 It("returns errors from fetching the ActualLRPs", func() { 418 fakeReceptorClient.ActualLRPsReturns(nil, errors.New("Receptor is Running.")) 419 420 _, err := appExaminer.ListCells() 421 Expect(err).To(MatchError("Receptor is Running.")) 422 }) 423 424 }) 425 }) 426 427 Describe("AppStatus", func() { 428 var ( 429 getDesiredLRPResponse receptor.DesiredLRPResponse 430 actualLRPsByProcessGuidResponse []receptor.ActualLRPResponse 431 containerMetrics []*events.ContainerMetric 432 ) 433 434 buildContainerMetric := func(applicationId string, instanceIndex int32, cpuPercentage float64, memoryBytes, diskBytes uint64) *events.ContainerMetric { 435 return &events.ContainerMetric{ 436 ApplicationId: &applicationId, 437 InstanceIndex: &instanceIndex, 438 CpuPercentage: &cpuPercentage, 439 MemoryBytes: &memoryBytes, 440 DiskBytes: &diskBytes, 441 } 442 } 443 444 Context("When receptor successfully responds to all requests", func() { 445 BeforeEach(func() { 446 getDesiredLRPResponse = receptor.DesiredLRPResponse{ 447 ProcessGuid: "peekaboo-app", 448 Domain: "welp.org", 449 RootFS: "preloaded:rootfs2", 450 Instances: 4, 451 EnvironmentVariables: []receptor.EnvironmentVariable{ 452 {Name: "API_TOKEN", Value: "98weufsa"}, 453 {Name: "PEEKABOO_APP_NICKNAME", Value: "Bugs McGee"}, 454 }, 455 StartTimeout: 5, 456 DiskMB: 256, 457 MemoryMB: 128, 458 CPUWeight: 77, 459 Ports: []uint16{8765, 2300}, 460 Routes: route_helpers.Routes{ 461 AppRoutes: route_helpers.AppRoutes{ 462 {Hostnames: []string{"peekaboo-one.example.com", "peekaboo-too.example.com"}}, 463 }, 464 TcpRoutes: route_helpers.TcpRoutes{ 465 {ExternalPort: 52220, Port: 5222}, 466 }, 467 }.RoutingInfo(), 468 LogGuid: "9832-ur98j-idsckl", 469 LogSource: "peekaboo-lawgz", 470 Annotation: "best. game. ever.", 471 } 472 473 actualLRPsByProcessGuidResponse = []receptor.ActualLRPResponse{ 474 { 475 ProcessGuid: "peekaboo-app", 476 InstanceGuid: "aisu-8dfy8-9dhu", 477 CellID: "cell-3", 478 Domain: "welp.org", 479 Index: 1, 480 Address: "212.38.11.83", 481 Ports: []receptor.PortMapping{ 482 {HostPort: 2983, ContainerPort: 2001}, 483 }, 484 State: "CLAIMED", 485 Since: 1982, 486 CrashCount: 3, 487 }, 488 { 489 ProcessGuid: "peekaboo-app", 490 InstanceGuid: "98s98a-xcvcx4-93isl", 491 CellID: "cell-2", 492 Domain: "welp.org", 493 Index: 0, 494 Address: "211.94.88.63", 495 Ports: []receptor.PortMapping{ 496 {HostPort: 2786, ContainerPort: 2020}, 497 }, 498 State: "RUNNING", 499 Since: 2002, 500 }, 501 { 502 ProcessGuid: "peekaboo-app", 503 Index: 2, 504 State: "UNCLAIMED", 505 PlacementError: "not enough resources. eek.", 506 }, 507 { 508 ProcessGuid: "peekaboo-app", 509 Index: 3, 510 State: "CRASHED", 511 CrashCount: 7, 512 }, 513 } 514 515 containerMetrics = []*events.ContainerMetric{ 516 buildContainerMetric("peekaboo-app", 0, 0.018138574, 798729, 32768), 517 } 518 }) 519 520 It("returns a fully populated AppInfo with instances sorted by index", func() { 521 fakeReceptorClient.GetDesiredLRPReturns(getDesiredLRPResponse, nil) 522 fakeReceptorClient.ActualLRPsByProcessGuidReturns(actualLRPsByProcessGuidResponse, nil) 523 fakeNoaaConsumer.GetContainerMetricsReturns(containerMetrics, nil) 524 525 appInfo, err := appExaminer.AppStatus("peekaboo-app") 526 Expect(err).NotTo(HaveOccurred()) 527 528 Expect(appInfo.ProcessGuid).To(Equal("peekaboo-app")) 529 Expect(appInfo.RootFS).To(Equal("preloaded:rootfs2")) 530 Expect(appInfo.DesiredInstances).To(Equal(4)) 531 Expect(appInfo.ActualRunningInstances).To(Equal(1)) 532 Expect(appInfo.EnvironmentVariables).To(ConsistOf( 533 app_examiner.EnvironmentVariable{ 534 Name: "API_TOKEN", 535 Value: "98weufsa", 536 }, 537 app_examiner.EnvironmentVariable{ 538 Name: "PEEKABOO_APP_NICKNAME", 539 Value: "Bugs McGee", 540 }, 541 )) 542 Expect(appInfo.StartTimeout).To(Equal(uint(5))) 543 Expect(appInfo.DiskMB).To(Equal(256)) 544 Expect(appInfo.MemoryMB).To(Equal(128)) 545 Expect(appInfo.CPUWeight).To(Equal(uint(77))) 546 Expect(appInfo.Ports).To(ConsistOf(uint16(8765), uint16(2300))) 547 Expect(appInfo.Routes).To(Equal(route_helpers.Routes{ 548 AppRoutes: route_helpers.AppRoutes{ 549 {Hostnames: []string{"peekaboo-one.example.com", "peekaboo-too.example.com"}}, 550 }, 551 TcpRoutes: route_helpers.TcpRoutes{ 552 {ExternalPort: 52220, Port: 5222}, 553 }, 554 }, 555 )) 556 Expect(appInfo.LogGuid).To(Equal("9832-ur98j-idsckl")) 557 Expect(appInfo.LogSource).To(Equal("peekaboo-lawgz")) 558 Expect(appInfo.Annotation).To(Equal("best. game. ever.")) 559 560 Expect(appInfo.ActualInstances).To(HaveLen(4)) 561 562 instanceZero := appInfo.ActualInstances[0] 563 Expect(instanceZero.InstanceGuid).To(Equal("98s98a-xcvcx4-93isl")) 564 Expect(instanceZero.CellID).To(Equal("cell-2")) 565 Expect(instanceZero.Index).To(Equal(0)) 566 Expect(instanceZero.Ip).To(Equal("211.94.88.63")) 567 Expect(instanceZero.Ports).To(ConsistOf(app_examiner.PortMapping{ 568 HostPort: 2786, 569 ContainerPort: 2020, 570 })) 571 Expect(instanceZero.State).To(Equal("RUNNING")) 572 Expect(instanceZero.Since).To(Equal(int64(2002))) 573 Expect(instanceZero.HasMetrics).To(BeTrue()) 574 Expect(instanceZero.Metrics).To(Equal(app_examiner.InstanceMetrics{ 575 CpuPercentage: 0.018138574, 576 MemoryBytes: 798729, 577 DiskBytes: 32768, 578 })) 579 580 instanceOne := appInfo.ActualInstances[1] 581 Expect(instanceOne.InstanceGuid).To(Equal("aisu-8dfy8-9dhu")) 582 Expect(instanceOne.CellID).To(Equal("cell-3")) 583 Expect(instanceOne.Index).To(Equal(1)) 584 Expect(instanceOne.Ip).To(Equal("212.38.11.83")) 585 Expect(instanceOne.Ports).To(ConsistOf(app_examiner.PortMapping{ 586 HostPort: 2983, 587 ContainerPort: 2001, 588 })) 589 Expect(instanceOne.State).To(Equal("CLAIMED")) 590 Expect(instanceOne.Since).To(Equal(int64(1982))) 591 Expect(instanceOne.CrashCount).To(Equal(3)) 592 Expect(instanceOne.HasMetrics).To(BeFalse()) 593 594 instanceTwo := appInfo.ActualInstances[2] 595 Expect(instanceTwo.Index).To(Equal(2)) 596 Expect(instanceTwo.Ports).To(BeEmpty()) 597 Expect(instanceTwo.State).To(Equal("UNCLAIMED")) 598 Expect(instanceTwo.PlacementError).To(Equal("not enough resources. eek.")) 599 Expect(instanceTwo.HasMetrics).To(BeFalse()) 600 601 instanceThree := appInfo.ActualInstances[3] 602 Expect(instanceThree.Index).To(Equal(3)) 603 Expect(instanceThree.Ports).To(BeEmpty()) 604 Expect(instanceThree.State).To(Equal("CRASHED")) 605 Expect(instanceThree.CrashCount).To(Equal(7)) 606 Expect(instanceThree.HasMetrics).To(BeFalse()) 607 608 Expect(fakeReceptorClient.GetDesiredLRPCallCount()).To(Equal(1)) 609 Expect(fakeReceptorClient.GetDesiredLRPArgsForCall(0)).To(Equal("peekaboo-app")) 610 611 Expect(fakeReceptorClient.ActualLRPsByProcessGuidCallCount()).To(Equal(1)) 612 Expect(fakeReceptorClient.ActualLRPsByProcessGuidArgsForCall(0)).To(Equal("peekaboo-app")) 613 614 Expect(fakeNoaaConsumer.GetContainerMetricsCallCount()).To(Equal(1)) 615 appGuid, token := fakeNoaaConsumer.GetContainerMetricsArgsForCall(0) 616 Expect(appGuid).To(Equal("peekaboo-app")) 617 Expect(token).To(BeEmpty()) 618 }) 619 620 Describe("Monitors", func() { 621 It("returns AppInfo Monitor for a port monitor", func() { 622 getDesiredLRPResponse.Monitor = models.WrapAction(&models.RunAction{ 623 Path: "/tmp/healthcheck", 624 Args: []string{ 625 "-port", 626 "8765", 627 }, 628 }) 629 630 fakeReceptorClient.GetDesiredLRPReturns(getDesiredLRPResponse, nil) 631 fakeReceptorClient.ActualLRPsByProcessGuidReturns(actualLRPsByProcessGuidResponse, nil) 632 fakeNoaaConsumer.GetContainerMetricsReturns(containerMetrics, nil) 633 634 appInfo, err := appExaminer.AppStatus("peekaboo-app") 635 Expect(err).NotTo(HaveOccurred()) 636 637 Expect(appInfo.Monitor.Port).To(Equal(uint16(8765))) 638 Expect(appInfo.Monitor.URI).To(BeEmpty()) 639 Expect(appInfo.Monitor.Command).To(BeEmpty()) 640 Expect(appInfo.Monitor.CommandArgs).To(BeEmpty()) 641 }) 642 643 It("returns AppInfo Monitor for a URL monitor", func() { 644 getDesiredLRPResponse.Monitor = models.WrapAction(&models.RunAction{ 645 Path: "/tmp/healthcheck", 646 Args: []string{ 647 "-port", 648 "8765", 649 "-uri", 650 "/health", 651 }, 652 }) 653 654 fakeReceptorClient.GetDesiredLRPReturns(getDesiredLRPResponse, nil) 655 fakeReceptorClient.ActualLRPsByProcessGuidReturns(actualLRPsByProcessGuidResponse, nil) 656 fakeNoaaConsumer.GetContainerMetricsReturns(containerMetrics, nil) 657 658 appInfo, err := appExaminer.AppStatus("peekaboo-app") 659 Expect(err).NotTo(HaveOccurred()) 660 661 Expect(appInfo.Monitor.Port).To(Equal(uint16(8765))) 662 Expect(appInfo.Monitor.URI).To(Equal("/health")) 663 Expect(appInfo.Monitor.Command).To(BeEmpty()) 664 Expect(appInfo.Monitor.CommandArgs).To(BeEmpty()) 665 }) 666 667 It("returns AppInfo Monitor for a URL monitor", func() { 668 getDesiredLRPResponse.Monitor = models.WrapAction(&models.RunAction{ 669 Path: "/bin/sh", 670 Args: []string{ 671 "-c", 672 "custom-healthcheck -port 8765 -uri /health", 673 }, 674 }) 675 676 fakeReceptorClient.GetDesiredLRPReturns(getDesiredLRPResponse, nil) 677 fakeReceptorClient.ActualLRPsByProcessGuidReturns(actualLRPsByProcessGuidResponse, nil) 678 fakeNoaaConsumer.GetContainerMetricsReturns(containerMetrics, nil) 679 680 appInfo, err := appExaminer.AppStatus("peekaboo-app") 681 Expect(err).NotTo(HaveOccurred()) 682 683 Expect(appInfo.Monitor.Port).To(BeZero()) 684 Expect(appInfo.Monitor.URI).To(BeEmpty()) 685 Expect(appInfo.Monitor.Command).To(Equal("/bin/sh")) 686 Expect(appInfo.Monitor.CommandArgs).To(Equal([]string{"-c", "custom-healthcheck -port 8765 -uri /health"})) 687 }) 688 }) 689 690 Context("when desired LRP is not found, but there are actual LRPs for the process GUID (App stopping)", func() { 691 It("returns AppInfo that has ActualInstances, but is missing desiredlrp specific data", func() { 692 fakeReceptorClient.GetDesiredLRPReturns(receptor.DesiredLRPResponse{}, receptor.Error{ 693 Type: receptor.DesiredLRPNotFound, 694 Message: "Desired LRP with guid 'peekaboo-app' not found"}, 695 ) 696 fakeReceptorClient.ActualLRPsByProcessGuidReturns(actualLRPsByProcessGuidResponse, nil) 697 fakeNoaaConsumer.GetContainerMetricsReturns(containerMetrics, nil) 698 699 appInfo, err := appExaminer.AppStatus("peekaboo-app") 700 Expect(err).NotTo(HaveOccurred()) 701 702 Expect(appInfo.ProcessGuid).To(Equal("peekaboo-app")) 703 Expect(appInfo.ActualRunningInstances).To(Equal(1)) 704 705 Expect(appInfo.ActualInstances).To(HaveLen(4)) 706 707 instanceZero := appInfo.ActualInstances[0] 708 Expect(instanceZero.InstanceGuid).To(Equal("98s98a-xcvcx4-93isl")) 709 Expect(instanceZero.CellID).To(Equal("cell-2")) 710 Expect(instanceZero.Index).To(Equal(0)) 711 Expect(instanceZero.Ip).To(Equal("211.94.88.63")) 712 Expect(instanceZero.Ports).To(ConsistOf(app_examiner.PortMapping{ 713 HostPort: 2786, 714 ContainerPort: 2020, 715 })) 716 Expect(instanceZero.State).To(Equal("RUNNING")) 717 Expect(instanceZero.Since).To(Equal(int64(2002))) 718 Expect(instanceZero.HasMetrics).To(BeTrue()) 719 Expect(instanceZero.Metrics).To(Equal(app_examiner.InstanceMetrics{ 720 CpuPercentage: 0.018138574, 721 MemoryBytes: 798729, 722 DiskBytes: 32768, 723 })) 724 725 instanceOne := appInfo.ActualInstances[1] 726 Expect(instanceOne.InstanceGuid).To(Equal("aisu-8dfy8-9dhu")) 727 Expect(instanceOne.CellID).To(Equal("cell-3")) 728 Expect(instanceOne.Index).To(Equal(1)) 729 Expect(instanceOne.Ip).To(Equal("212.38.11.83")) 730 Expect(instanceOne.Ports).To(ConsistOf(app_examiner.PortMapping{ 731 HostPort: 2983, 732 ContainerPort: 2001, 733 })) 734 Expect(instanceOne.State).To(Equal("CLAIMED")) 735 Expect(instanceOne.Since).To(Equal(int64(1982))) 736 Expect(instanceOne.CrashCount).To(Equal(3)) 737 Expect(instanceOne.HasMetrics).To(BeFalse()) 738 739 instanceTwo := appInfo.ActualInstances[2] 740 Expect(instanceTwo.Index).To(Equal(2)) 741 Expect(instanceTwo.Ports).To(BeEmpty()) 742 Expect(instanceTwo.State).To(Equal("UNCLAIMED")) 743 Expect(instanceTwo.PlacementError).To(Equal("not enough resources. eek.")) 744 Expect(instanceTwo.HasMetrics).To(BeFalse()) 745 746 instanceThree := appInfo.ActualInstances[3] 747 Expect(instanceThree.Index).To(Equal(3)) 748 Expect(instanceThree.Ports).To(BeEmpty()) 749 Expect(instanceThree.State).To(Equal("CRASHED")) 750 Expect(instanceThree.CrashCount).To(Equal(7)) 751 Expect(instanceThree.HasMetrics).To(BeFalse()) 752 753 Expect(fakeReceptorClient.GetDesiredLRPCallCount()).To(Equal(1)) 754 Expect(fakeReceptorClient.ActualLRPsByProcessGuidCallCount()).To(Equal(1)) 755 756 Expect(fakeReceptorClient.GetDesiredLRPArgsForCall(0)).To(Equal("peekaboo-app")) 757 Expect(fakeReceptorClient.ActualLRPsByProcessGuidArgsForCall(0)).To(Equal("peekaboo-app")) 758 759 Expect(fakeNoaaConsumer.GetContainerMetricsCallCount()).To(Equal(1)) 760 appGuid, token := fakeNoaaConsumer.GetContainerMetricsArgsForCall(0) 761 Expect(appGuid).To(Equal("peekaboo-app")) 762 Expect(token).To(BeEmpty()) 763 }) 764 }) 765 766 It("handles empty desiredLRP with empty actualLRP response", func() { 767 fakeReceptorClient.GetDesiredLRPReturns(receptor.DesiredLRPResponse{}, nil) 768 fakeReceptorClient.ActualLRPsByProcessGuidReturns(make([]receptor.ActualLRPResponse, 0), nil) 769 770 _, err := appExaminer.AppStatus("peekaboo-app") 771 Expect(err).To(MatchError(app_examiner.AppNotFoundErrorMessage)) 772 773 Expect(fakeReceptorClient.GetDesiredLRPCallCount()).To(Equal(1)) 774 Expect(fakeReceptorClient.GetDesiredLRPArgsForCall(0)).To(Equal("peekaboo-app")) 775 776 Expect(fakeReceptorClient.ActualLRPsByProcessGuidCallCount()).To(Equal(1)) 777 Expect(fakeReceptorClient.ActualLRPsByProcessGuidArgsForCall(0)).To(Equal("peekaboo-app")) 778 779 Expect(fakeNoaaConsumer.GetContainerMetricsCallCount()).To(Equal(0)) 780 }) 781 782 }) 783 784 Context("when noaa returns container metrics without an associated actual lrp", func() { 785 It("doesn't blow up", func() { 786 getDesiredLRPResponse := receptor.DesiredLRPResponse{ 787 ProcessGuid: "peekaboo-app", 788 } 789 actualLRPs := []receptor.ActualLRPResponse{ 790 receptor.ActualLRPResponse{ 791 ProcessGuid: "peekaboo-app", 792 Index: 6, 793 }, 794 } 795 containerMetrics := []*events.ContainerMetric{ 796 buildContainerMetric("peekaboo-app", 42, 0.018138574, 798729, 32768), 797 } 798 fakeReceptorClient.GetDesiredLRPReturns(getDesiredLRPResponse, nil) 799 fakeReceptorClient.ActualLRPsByProcessGuidReturns(actualLRPs, nil) 800 fakeNoaaConsumer.GetContainerMetricsReturns(containerMetrics, nil) 801 802 appInfo, err := appExaminer.AppStatus("peekaboo-app") 803 Expect(err).NotTo(HaveOccurred()) 804 Expect(appInfo).NotTo(BeZero()) 805 Expect(appInfo.ActualInstances).To(HaveLen(1)) 806 Expect(appInfo.ActualInstances[0].HasMetrics).To(BeFalse()) 807 }) 808 }) 809 810 Context("when the receptor returns errors", func() { 811 It("returns errors from from fetching the DesiredLRPs", func() { 812 fakeReceptorClient.GetDesiredLRPReturns(receptor.DesiredLRPResponse{}, receptor.Error{ 813 Type: receptor.UnknownError, 814 Message: "Oops."}, 815 ) 816 817 _, err := appExaminer.AppStatus("app-to-status") 818 Expect(err).To(MatchError("Oops.")) 819 }) 820 821 It("returns errors from fetching the ActualLRPs", func() { 822 fakeReceptorClient.GetDesiredLRPReturns(receptor.DesiredLRPResponse{}, nil) 823 fakeReceptorClient.ActualLRPsByProcessGuidReturns(nil, receptor.Error{ 824 Type: receptor.UnknownError, 825 Message: "ABANDON SHIP!!!!"}, 826 ) 827 828 _, err := appExaminer.AppStatus("kiss-my-bumper") 829 Expect(err).To(MatchError("ABANDON SHIP!!!!")) 830 }) 831 832 It("should not panic", func() { 833 fakeReceptorClient.GetDesiredLRPReturns(receptor.DesiredLRPResponse{}, errors.New("non-receptor error")) 834 835 var err error 836 Expect(func() { _, err = appExaminer.AppStatus("kiss-my-bumper") }).ShouldNot(Panic()) 837 Expect(err).To(MatchError("non-receptor error")) 838 }) 839 }) 840 841 Context("when the noaa consumer returns errors", func() { 842 It("returns an AppInfo without container metrics", func() { 843 desiredLRPs := receptor.DesiredLRPResponse{ 844 ProcessGuid: "peekaboo-app", 845 } 846 actualLRPs := []receptor.ActualLRPResponse{ 847 {ProcessGuid: "peekaboo-app", Index: 6}, 848 } 849 fakeReceptorClient.GetDesiredLRPReturns(desiredLRPs, nil) 850 fakeReceptorClient.ActualLRPsByProcessGuidReturns(actualLRPs, nil) 851 fakeNoaaConsumer.GetContainerMetricsReturns(nil, errors.New("no metrics 4 you")) 852 853 appInfo, err := appExaminer.AppStatus("peekaboo-app") 854 Expect(err).NotTo(HaveOccurred()) 855 Expect(appInfo).NotTo(BeZero()) 856 Expect(appInfo.ActualInstances).To(HaveLen(1)) 857 Expect(appInfo.ActualInstances[0].HasMetrics).To(BeFalse()) 858 }) 859 }) 860 }) 861 862 Describe("NumOfRunningAppInstances", func() { 863 It("returns the number of running instances for a given app guid", func() { 864 actualLrpsResponse := []receptor.ActualLRPResponse{ 865 {ProcessGuid: "americano-app", State: receptor.ActualLRPStateRunning, Index: 1}, 866 {ProcessGuid: "americano-app", State: receptor.ActualLRPStateRunning, Index: 2}, 867 {ProcessGuid: "americano-app", State: receptor.ActualLRPStateClaimed, Index: 3}, 868 } 869 fakeReceptorClient.ActualLRPsByProcessGuidReturns(actualLrpsResponse, nil) 870 871 count, placementError, err := appExaminer.RunningAppInstancesInfo("americano-app") 872 Expect(err).NotTo(HaveOccurred()) 873 Expect(count).To(Equal(2)) 874 Expect(placementError).To(BeFalse()) 875 876 Expect(fakeReceptorClient.ActualLRPsByProcessGuidCallCount()).To(Equal(1)) 877 Expect(fakeReceptorClient.ActualLRPsByProcessGuidArgsForCall(0)).To(Equal("americano-app")) 878 }) 879 880 It("returns errors from the receptor", func() { 881 receptorError := errors.New("receptor did not like that request") 882 fakeReceptorClient.ActualLRPsByProcessGuidReturns([]receptor.ActualLRPResponse{}, receptorError) 883 884 _, _, err := appExaminer.RunningAppInstancesInfo("nescafe-app") 885 Expect(err).To(MatchError(receptorError)) 886 }) 887 888 Context("when there are placement errors on an instance", func() { 889 It("returns true for placementError", func() { 890 actualLrpsResponse := []receptor.ActualLRPResponse{ 891 {ProcessGuid: "americano-app", State: receptor.ActualLRPStateRunning, Index: 1}, 892 {ProcessGuid: "americano-app", State: receptor.ActualLRPStateUnclaimed, Index: 2, PlacementError: "could not place!"}, 893 {ProcessGuid: "americano-app", State: receptor.ActualLRPStateRunning, Index: 3}, 894 } 895 fakeReceptorClient.ActualLRPsByProcessGuidReturns(actualLrpsResponse, nil) 896 897 count, placementError, err := appExaminer.RunningAppInstancesInfo("americano-app") 898 Expect(err).NotTo(HaveOccurred()) 899 Expect(count).To(Equal(2)) 900 Expect(placementError).To(BeTrue()) 901 }) 902 }) 903 }) 904 905 Describe("AppExists", func() { 906 It("returns true if the docker app exists", func() { 907 actualLRPs := []receptor.ActualLRPResponse{ 908 {ProcessGuid: "americano-app"}, 909 } 910 fakeReceptorClient.ActualLRPsReturns(actualLRPs, nil) 911 912 exists, err := appExaminer.AppExists("americano-app") 913 Expect(err).NotTo(HaveOccurred()) 914 Expect(exists).To(BeTrue()) 915 }) 916 917 It("returns false if the docker app does not exist", func() { 918 fakeReceptorClient.ActualLRPsReturns([]receptor.ActualLRPResponse{}, nil) 919 920 exists, err := appExaminer.AppExists("americano-app") 921 Expect(err).NotTo(HaveOccurred()) 922 Expect(exists).To(BeFalse()) 923 }) 924 925 Describe("returning errors from the receptor", func() { 926 It("returns errors fetching the status", func() { 927 fakeReceptorClient.ActualLRPsReturns([]receptor.ActualLRPResponse{}, errors.New("Something Bad")) 928 929 _, err := appExaminer.AppExists("americano-app") 930 Expect(err).To(MatchError("Something Bad")) 931 }) 932 }) 933 }) 934 })