bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/bosun/sched/host.go (about) 1 package sched // import "bosun.org/cmd/bosun/sched" 2 import ( 3 "encoding/json" 4 "fmt" 5 "strconv" 6 "time" 7 8 "bosun.org/metadata" 9 "bosun.org/opentsdb" 10 "bosun.org/slog" 11 ) 12 13 func (s *Schedule) Host(filter string) (map[string]*HostData, error) { 14 timeFilterAge := time.Hour * 2 * 24 15 hosts := make(map[string]*HostData) 16 allHosts, err := s.Search.TagValuesByTagKey("host", timeFilterAge) 17 if err != nil { 18 return nil, err 19 } 20 for _, h := range allHosts { 21 hosts[h] = newHostData() 22 } 23 states, err := s.GetOpenStates() 24 if err != nil { 25 return nil, err 26 } 27 silences := s.Silenced() 28 // These are all fetched by metric since that is how we store it in redis, 29 // so this makes for the fastest response 30 tagsByKey := func(metric, hostKey string) (map[string][]opentsdb.TagSet, error) { 31 byKey := make(map[string][]opentsdb.TagSet) 32 tags, err := s.Search.FilteredTagSets(metric, nil, 0) 33 if err != nil { 34 return byKey, err 35 } 36 for _, ts := range tags { 37 if host, ok := ts[hostKey]; ok { 38 // Make sure the host exists based on our time filter 39 if _, ok := hosts[host]; ok { 40 byKey[host] = append(byKey[host], ts) 41 } 42 } 43 } 44 return byKey, nil 45 } 46 oldTimestamp := utcNow().Add(-timeFilterAge).Unix() 47 oldOrErr := func(ts int64, err error) bool { 48 if ts < oldTimestamp || err != nil { 49 return true 50 } 51 return false 52 } 53 osNetBytesTags, err := tagsByKey("os.net.bytes", "host") 54 if err != nil { 55 return nil, err 56 } 57 osNetVirtualBytesTags, err := tagsByKey("os.net.virtual.bytes", "host") 58 if err != nil { 59 return nil, err 60 } 61 osNetBondBytesTags, err := tagsByKey("os.net.bond.bytes", "host") 62 if err != nil { 63 return nil, err 64 } 65 osNetTunnelBytesTags, err := tagsByKey("os.net.tunnel.bytes", "host") 66 if err != nil { 67 return nil, err 68 } 69 osNetOtherBytesTags, err := tagsByKey("os.net.other.bytes", "host") 70 if err != nil { 71 return nil, err 72 } 73 osNetIfSpeedTags, err := tagsByKey("os.net.ifspeed", "host") 74 if err != nil { 75 return nil, err 76 } 77 osNetVirtualIfSpeedTags, err := tagsByKey("os.net.virtual.ifspeed", "host") 78 if err != nil { 79 return nil, err 80 } 81 osNetBondIfSpeedTags, err := tagsByKey("os.net.bond.ifspeed", "host") 82 if err != nil { 83 return nil, err 84 } 85 osNetTunnelIfSpeedTags, err := tagsByKey("os.net.tunnel.ifspeed", "host") 86 if err != nil { 87 return nil, err 88 } 89 osNetOtherIfSpeedTags, err := tagsByKey("os.net.other.ifspeed", "host") 90 if err != nil { 91 return nil, err 92 } 93 hwChassisTags, err := tagsByKey("hw.chassis", "host") 94 if err != nil { 95 return nil, err 96 } 97 hwPhysicalDiskTags, err := tagsByKey("hw.storage.pdisk", "host") 98 if err != nil { 99 return nil, err 100 } 101 hwVirtualDiskTags, err := tagsByKey("hw.storage.vdisk", "host") 102 if err != nil { 103 return nil, err 104 } 105 hwControllersTags, err := tagsByKey("hw.storage.controller", "host") 106 if err != nil { 107 return nil, err 108 } 109 hwBatteriesTags, err := tagsByKey("hw.storage.battery", "host") 110 if err != nil { 111 return nil, err 112 } 113 hwPowerSuppliesTags, err := tagsByKey("hw.ps", "host") 114 if err != nil { 115 return nil, err 116 } 117 hwTempsTags, err := tagsByKey("hw.chassis.temps.reading", "host") 118 if err != nil { 119 return nil, err 120 } 121 hwBoardPowerTags, err := tagsByKey("hw.chassis.power.reading", "host") 122 if err != nil { 123 return nil, err 124 } 125 diskTags, err := tagsByKey("os.disk.fs.space_total", "host") 126 if err != nil { 127 return nil, err 128 } 129 serviceTags, err := tagsByKey("os.service.running", "host") 130 if err != nil { 131 return nil, err 132 } 133 // Will assume the same tagsets exist .mem_real, .mem_virtual and possibly .count 134 processTags, err := tagsByKey("os.proc.cpu", "host") 135 if err != nil { 136 return nil, err 137 } 138 // Will make the assumption that the metric bosun.ping.timeout, resolved, and rtt 139 // all share the same tagset 140 icmpTimeOutTags, err := tagsByKey("bosun.ping.timeout", "dst_host") 141 if err != nil { 142 return nil, err 143 } 144 for name, host := range hosts { 145 host.Name = name 146 hostTagSet := opentsdb.TagSet{"host": host.Name} 147 hostMetadata, err := s.GetMetadata("", hostTagSet) 148 if err != nil { 149 slog.Error(err) 150 } 151 processHostIncidents(host, states, silences) 152 for _, ts := range icmpTimeOutTags[host.Name] { 153 // The host tag represents the polling source for these set of metrics 154 source, ok := ts["host"] 155 if !ok { 156 slog.Errorf("couldn't find source tag for icmp data for host %s", host.Name) 157 } 158 // 1 Means it timed out 159 timeout, timestamp, err := s.Search.GetLast("bosun.ping.timeout", ts.String(), false) 160 if oldOrErr(timestamp, err) { 161 continue 162 } 163 rtt, rttTimestamp, _ := s.Search.GetLast("bosun.ping.rtt", ts.String(), false) 164 // 1 means dns resolution was successful 165 dnsLookup, dnsTimestamp, dnsErr := s.Search.GetLast("bosun.ping.resolved", ts.String(), false) 166 host.ICMPData[source] = &ICMPData{ 167 TimedOut: timeout == 1 && err == nil, 168 TimedOutLastUpdated: timestamp, 169 DNSResolved: dnsLookup == 1 && dnsErr == nil, 170 DNSResolvedLastUpdated: dnsTimestamp, 171 RTTMS: rtt, 172 RTTLastUpdated: rttTimestamp, 173 } 174 175 } 176 for _, ts := range serviceTags[host.Name] { 177 name, ok := ts["name"] 178 if !ok { 179 slog.Errorf("couldn't find service name tag %s for host %s", name, host.Name) 180 continue 181 } 182 fstatus, timestamp, err := s.Search.GetLast("os.service.running", ts.String(), false) 183 running := false 184 if fstatus != 0 { 185 running = true 186 } 187 if !oldOrErr(timestamp, err) { 188 host.Services[name] = &ServiceStatus{ 189 Running: running, 190 RunningLastUpdated: timestamp, 191 } 192 } 193 } 194 for _, ts := range processTags[host.Name] { 195 name, ok := ts["name"] 196 if !ok { 197 slog.Errorf("couldn't find process name tag %s for host %s", name, host.Name) 198 continue 199 } 200 p := &Process{} 201 p.CPUPercentUsed, p.CPUPercentLastUpdated, err = s.Search.GetLast("os.proc.cpu", ts.String(), true) 202 if oldOrErr(p.CPUPercentLastUpdated, err) { 203 continue 204 } 205 p.UsedRealBytes, p.UsedRealBytesLastUpdated, _ = s.Search.GetLastInt64("os.proc.mem.real", ts.String(), false) 206 p.UsedVirtualBytes, p.UsedVirtualBytesLastUpdated, _ = s.Search.GetLastInt64("os.proc.mem.virtual", ts.String(), false) 207 p.Count, p.CountLastUpdated, _ = s.Search.GetLastInt64("os.proc.count", ts.String(), false) 208 host.Processes[name] = p 209 } 210 // Process Hardware Chassis States 211 for _, ts := range hwChassisTags[host.Name] { 212 component, ok := ts["component"] 213 if !ok { 214 return nil, fmt.Errorf("couldn't find component tag for host %s", host.Name) 215 } 216 fstatus, timestamp, err := s.Search.GetLast("hw.chassis", ts.String(), false) 217 if !oldOrErr(timestamp, err) { 218 host.Hardware.ChassisComponents[component] = &ChassisComponent{ 219 Status: statusString(int64(fstatus), 0, "Ok", "Bad"), 220 StatusLastUpdated: timestamp, 221 } 222 } 223 } 224 for _, ts := range hwTempsTags[host.Name] { 225 name, ok := ts["name"] 226 if !ok { 227 slog.Errorf("couldn't find name tag %s for host %s", name, host.Name) 228 } 229 t := &Temp{} 230 var tStatus float64 231 tStatus, t.StatusLastUpdated, err = s.Search.GetLast("hw.chassis.temps", ts.String(), false) 232 t.Celsius, t.CelsiusLastUpdated, _ = s.Search.GetLast("hw.chassis.temps.reading", ts.String(), false) 233 if oldOrErr(t.StatusLastUpdated, err) { 234 continue 235 } 236 t.Status = statusString(int64(tStatus), 0, "Ok", "Bad") 237 host.Hardware.Temps[name] = t 238 } 239 for _, ts := range hwPowerSuppliesTags[host.Name] { 240 id, ok := ts["id"] 241 if !ok { 242 return nil, fmt.Errorf("couldn't find power supply tag for host %s", host.Name) 243 } 244 idPlus, err := strconv.Atoi(id) 245 if err != nil { 246 slog.Errorf("couldn't conver it do integer for power supply id %s", id) 247 } 248 idPlus++ 249 ps := &PowerSupply{} 250 fstatus, timestamp, err := s.Search.GetLast("hw.ps", ts.String(), false) 251 ps.Amps, ps.AmpsLastUpdated, _ = s.Search.GetLast("hw.chassis.current.reading", opentsdb.TagSet{"host": host.Name, "id": fmt.Sprintf("PS%v", idPlus)}.String(), false) 252 ps.Volts, ps.VoltsLastUpdated, _ = s.Search.GetLast("hw.chassis.volts.reading", opentsdb.TagSet{"host": host.Name, "name": fmt.Sprintf("PS%v_Voltage_%v", idPlus, idPlus)}.String(), false) 253 if oldOrErr(timestamp, err) { 254 continue 255 } 256 ps.Status = statusString(int64(fstatus), 0, "Ok", "Bad") 257 host.Hardware.PowerSupplies[id] = ps 258 for _, m := range hostMetadata { 259 if m.Name != "psMeta" || m.Time.Before(utcNow().Add(-timeFilterAge)) || !m.Tags.Equal(ts) { 260 continue 261 } 262 if val, ok := m.Value.(string); ok { 263 err = json.Unmarshal([]byte(val), &ps) 264 if err != nil { 265 slog.Errorf("error unmarshalling power supply meta for host %s, while generating host api: %s", host.Name, err) 266 } else { 267 host.Hardware.PowerSupplies[id] = ps 268 } 269 } 270 } 271 } 272 for _, ts := range hwBatteriesTags[host.Name] { 273 id, ok := ts["id"] 274 if !ok { 275 slog.Errorf("couldn't find battery id tag %s for host %s", id, host.Name) 276 continue 277 } 278 fstatus, timestamp, err := s.Search.GetLast("hw.storage.battery", ts.String(), false) 279 if !oldOrErr(timestamp, err) { 280 host.Hardware.Storage.Batteries[id] = &Battery{ 281 Status: statusString(int64(fstatus), 0, "Ok", "Bad"), 282 StatusLastUpdated: timestamp, 283 } 284 } 285 } 286 for _, ts := range hwBoardPowerTags[host.Name] { 287 fstatus, timestamp, err := s.Search.GetLast("hw.chassis.power.reading", ts.String(), false) 288 if !oldOrErr(timestamp, err) { 289 host.Hardware.BoardPowerReading = &BoardPowerReading{ 290 Watts: int64(fstatus), 291 WattsLastUpdated: timestamp, 292 } 293 } 294 } 295 for _, ts := range hwPhysicalDiskTags[host.Name] { 296 id, ok := ts["id"] 297 if !ok { 298 return nil, fmt.Errorf("couldn't find physical disk id tag for host %s", host.Name) 299 } 300 pd := &PhysicalDisk{} 301 fstatus, timestamp, err := s.Search.GetLast("hw.storage.pdisk", ts.String(), false) 302 if !oldOrErr(timestamp, err) { 303 pd.Status = statusString(int64(fstatus), 0, "Ok", "Bad") 304 pd.StatusLastUpdated = timestamp 305 host.Hardware.Storage.PhysicalDisks[id] = pd 306 } 307 for _, m := range hostMetadata { 308 if m.Name != "physicalDiskMeta" || m.Time.Before(utcNow().Add(-timeFilterAge)) || !m.Tags.Equal(ts) { 309 continue 310 } 311 if val, ok := m.Value.(string); ok { 312 err = json.Unmarshal([]byte(val), &pd) 313 if err != nil { 314 slog.Errorf("error unmarshalling addresses for host %s, interface %s while generating host api: %s", host.Name, m.Tags["iface"], err) 315 } else { 316 host.Hardware.Storage.PhysicalDisks[id] = pd 317 } 318 } 319 } 320 } 321 for _, ts := range hwVirtualDiskTags[host.Name] { 322 id, ok := ts["id"] 323 if !ok { 324 return nil, fmt.Errorf("couldn't find virtual disk id tag for host %s", host.Name) 325 } 326 fstatus, timestamp, err := s.Search.GetLast("hw.storage.vdisk", ts.String(), false) 327 if !oldOrErr(timestamp, err) { 328 host.Hardware.Storage.VirtualDisks[id] = &VirtualDisk{ 329 Status: statusString(int64(fstatus), 0, "Ok", "Bad"), 330 StatusLastUpdated: timestamp, 331 } 332 } 333 } 334 for _, ts := range hwControllersTags[host.Name] { 335 id, ok := ts["id"] 336 if !ok { 337 return nil, fmt.Errorf("couldn't find controller id tag for host %s", host.Name) 338 } 339 fstatus, timestamp, err := s.Search.GetLast("hw.storage.controller", ts.String(), false) 340 c := &Controller{} 341 if !oldOrErr(timestamp, err) { 342 c.Status = statusString(int64(fstatus), 0, "Ok", "Bad") 343 c.StatusLastUpdated = timestamp 344 host.Hardware.Storage.Controllers[id] = c 345 } 346 for _, m := range hostMetadata { 347 if m.Name != "controllerMeta" || m.Time.Before(utcNow().Add(-timeFilterAge)) || !m.Tags.Equal(ts) { 348 continue 349 } 350 if val, ok := m.Value.(string); ok { 351 err = json.Unmarshal([]byte(val), &c) 352 if err != nil { 353 slog.Errorf("error unmarshalling controller meta for host %s: %s", host.Name, err) 354 } else { 355 host.Hardware.Storage.Controllers[id] = c 356 } 357 } 358 } 359 } 360 for _, ts := range diskTags[host.Name] { 361 disk, ok := ts["disk"] 362 if !ok { 363 return nil, fmt.Errorf("couldn't find disk tag for host %s", host.Name) 364 } 365 d := &Disk{} 366 d.TotalBytes, d.StatsLastUpdated, err = s.Search.GetLastInt64("os.disk.fs.space_total", ts.String(), false) 367 d.UsedBytes, _, _ = s.Search.GetLastInt64("os.disk.fs.space_used", ts.String(), false) 368 if oldOrErr(d.StatsLastUpdated, err) { 369 continue 370 } 371 host.Disks[disk] = d 372 for _, m := range hostMetadata { 373 if m.Name != "label" || m.Time.Before(utcNow().Add(-timeFilterAge)) || !m.Tags.Equal(ts) { 374 continue 375 } 376 if label, ok := m.Value.(string); ok { 377 host.Disks[disk].Label = label 378 break 379 } 380 } 381 } 382 // Get CPU, Memory, Uptime 383 var timestamp int64 384 var cpu float64 385 if cpu, timestamp, err = s.Search.GetLast("os.cpu", hostTagSet.String(), true); err != nil { 386 cpu, timestamp, _ = s.Search.GetLast("cisco.cpu", hostTagSet.String(), false) 387 } 388 host.CPU.PercentUsed = cpu 389 host.CPU.StatsLastUpdated = timestamp 390 host.Memory.TotalBytes, host.Memory.StatsLastUpdated, _ = s.Search.GetLast("os.mem.total", hostTagSet.String(), false) 391 host.Memory.UsedBytes, _, _ = s.Search.GetLast("os.mem.used", hostTagSet.String(), false) 392 host.UptimeSeconds, _, _ = s.Search.GetLastInt64("os.system.uptime", hostTagSet.String(), false) 393 for _, m := range hostMetadata { 394 if m.Time.Before(utcNow().Add(-timeFilterAge)) { 395 continue 396 } 397 var iface *HostInterface 398 if name := m.Tags["iface"]; name != "" { 399 if host.Interfaces[name] == nil { 400 h := new(HostInterface) 401 host.Interfaces[name] = h 402 } 403 iface = host.Interfaces[name] 404 } 405 if name := m.Tags["iname"]; name != "" && iface != nil { 406 iface.Name = name 407 } 408 switch val := m.Value.(type) { 409 case string: 410 switch m.Name { 411 case "addresses": 412 if iface != nil { 413 addresses := []string{} 414 err = json.Unmarshal([]byte(val), &addresses) 415 if err != nil { 416 slog.Errorf("error unmarshalling addresses for host %s, interface %s while generating host api: %s", host.Name, m.Tags["iface"], err) 417 } 418 for _, address := range addresses { 419 iface.IPAddresses = append(iface.IPAddresses, address) 420 } 421 } 422 case "cdpCacheEntries": 423 if iface != nil { 424 var cdpCacheEntries CDPCacheEntries 425 err = json.Unmarshal([]byte(val), &cdpCacheEntries) 426 if err != nil { 427 slog.Errorf("error unmarshalling cdpCacheEntries for host %s, interface %s while generating host api: %s", host.Name, m.Tags["iface"], err) 428 } else { 429 iface.CDPCacheEntries = cdpCacheEntries 430 } 431 } 432 case "remoteMacs": 433 if iface != nil { 434 remoteMacs := []string{} 435 err = json.Unmarshal([]byte(val), &remoteMacs) 436 if err != nil { 437 slog.Errorf("error unmarshalling remoteMacs for host %s, interface %s while generating host api: %s", host.Name, m.Tags["iface"], err) 438 } else { 439 iface.RemoteMacs = remoteMacs 440 } 441 } 442 case "description", "alias": 443 if iface != nil { 444 iface.Description = val 445 } 446 case "dataStores": 447 dataStores := []string{} 448 err = json.Unmarshal([]byte(val), &dataStores) 449 if err != nil { 450 slog.Errorf("error unmarshalling datastores for host %s while generating host api: %s", host.Name, err) 451 } 452 for _, dataStore := range dataStores { 453 tags := opentsdb.TagSet{"disk": dataStore}.String() 454 total, totalTs, totalErr := s.Search.GetLastInt64("vsphere.disk.space_total", tags, false) 455 used, usedTs, usedErr := s.Search.GetLastInt64("vsphere.disk.space_used", tags, false) 456 if totalErr != nil || usedErr != nil || totalTs < 1 || usedTs < 1 { 457 continue 458 } 459 host.Disks[dataStore] = &Disk{ 460 TotalBytes: total, 461 UsedBytes: used, 462 } 463 } 464 case "mac": 465 if iface != nil { 466 iface.MAC = val 467 } 468 case "manufacturer": 469 host.Manufacturer = val 470 case "master": 471 if iface != nil { 472 iface.Master = val 473 } 474 case "memory": 475 if name := m.Tags["name"]; name != "" { 476 fstatus, timestamp, err := s.Search.GetLast("hw.chassis.memory", opentsdb.TagSet{"host": host.Name, "name": name}.String(), false) 477 // Status code uses the severity function in collectors/dell_hw.go. That is a binary 478 // state that is 0 for non-critical or Ok. Todo would be to update this with more 479 // complete status codes when HW collector is refactored and we have something to 480 // clean out addr entries from the tagset metadata db 481 host.Hardware.Memory[name] = &MemoryModule{ 482 StatusLastUpdated: timestamp, 483 Size: val, 484 } 485 // Only set if we have a value 486 if err == nil && timestamp > 0 { 487 host.Hardware.Memory[name].Status = statusString(int64(fstatus), 0, "Ok", "Bad") 488 } 489 } 490 case "hypervisor": 491 host.VM = &VM{} 492 host.VM.Host = val 493 powerstate, timestamp, err := s.Search.GetLast("vsphere.guest.powered_state", opentsdb.TagSet{"guest": host.Name}.String(), false) 494 if timestamp > 0 && err != nil { 495 switch int64(powerstate) { 496 case 0: 497 host.VM.PowerState = "poweredOn" 498 case 1: 499 host.VM.PowerState = "poweredOff" 500 case 2: 501 host.VM.PowerState = "suspended" 502 } 503 host.VM.PowerStateLastUpdated = timestamp 504 } 505 if hostsHost, ok := hosts[val]; ok { 506 hostsHost.Guests = append(hostsHost.Guests, host.Name) 507 } 508 case "model": 509 host.Model = val 510 case "name": 511 if iface != nil { 512 iface.Name = val 513 } 514 case "processor": 515 if name := m.Tags["name"]; name != "" { 516 host.CPU.Processors[name] = val 517 } 518 case "serialNumber": 519 host.SerialNumber = val 520 case "version": 521 host.OS.Version = val 522 case "versionCaption", "uname": 523 host.OS.Caption = val 524 } 525 case float64: 526 switch m.Name { 527 case "speed": 528 if iface != nil { 529 iface.LinkSpeed = int64(val) 530 } 531 } 532 } 533 } 534 GetIfaceBits := func(netType string, ifaceId string, iface *HostInterface, host string, tags []opentsdb.TagSet) error { 535 metric := "os.net." + netType + ".bytes" 536 if netType == "" { 537 metric = "os.net.bytes" 538 } 539 for _, ts := range tags { 540 if ts["iface"] != ifaceId { 541 continue 542 } 543 dir, ok := ts["direction"] 544 if !ok { 545 continue 546 } 547 val, timestamp, _ := s.Search.GetLastInt64(metric, ts.String(), true) 548 if dir == "in" { 549 iface.Inbps = val * 8 550 } 551 if dir == "out" { 552 iface.Outbps = val * 8 553 } 554 iface.StatsLastUpdated = timestamp 555 iface.Type = netType 556 } 557 return nil 558 } 559 GetIfaceSpeed := func(netType string, ifaceId string, iface *HostInterface, host string, tags []opentsdb.TagSet) error { 560 metric := "os.net." + netType + ".ifspeed" 561 if netType == "" { 562 metric = "os.net.ifspeed" 563 } 564 for _, ts := range tags { 565 if ts["iface"] != ifaceId { 566 continue 567 } 568 val, timestamp, err := s.Search.GetLastInt64(metric, ts.String(), false) 569 if !oldOrErr(timestamp, err) { 570 iface.LinkSpeed = val 571 } 572 } 573 return nil 574 } 575 for ifaceId, iface := range host.Interfaces { 576 if err := GetIfaceBits("", ifaceId, iface, host.Name, osNetBytesTags[host.Name]); err != nil { 577 return nil, err 578 } 579 if err := GetIfaceBits("virtual", ifaceId, iface, host.Name, osNetVirtualBytesTags[host.Name]); err != nil { 580 return nil, err 581 } 582 if err := GetIfaceBits("bond", ifaceId, iface, host.Name, osNetBondBytesTags[host.Name]); err != nil { 583 return nil, err 584 } 585 if err := GetIfaceBits("tunnel", ifaceId, iface, host.Name, osNetTunnelBytesTags[host.Name]); err != nil { 586 return nil, err 587 } 588 if err := GetIfaceBits("other", ifaceId, iface, host.Name, osNetOtherBytesTags[host.Name]); err != nil { 589 return nil, err 590 } 591 if err := GetIfaceSpeed("", ifaceId, iface, host.Name, osNetIfSpeedTags[host.Name]); err != nil { 592 return nil, err 593 } 594 if err := GetIfaceSpeed("virtual", ifaceId, iface, host.Name, osNetVirtualIfSpeedTags[host.Name]); err != nil { 595 return nil, err 596 } 597 if err := GetIfaceSpeed("bond", ifaceId, iface, host.Name, osNetBondIfSpeedTags[host.Name]); err != nil { 598 return nil, err 599 } 600 if err := GetIfaceSpeed("tunnel", ifaceId, iface, host.Name, osNetTunnelIfSpeedTags[host.Name]); err != nil { 601 return nil, err 602 } 603 if err := GetIfaceSpeed("other", ifaceId, iface, host.Name, osNetOtherIfSpeedTags[host.Name]); err != nil { 604 return nil, err 605 } 606 } 607 host.Clean() 608 } 609 return hosts, nil 610 } 611 612 func statusString(val, goodVal int64, goodName, badName string) string { 613 if val == goodVal { 614 return goodName 615 } 616 return badName 617 } 618 619 func processHostIncidents(host *HostData, states States, silences SilenceTester) { 620 for ak, state := range states { 621 if stateHost, ok := state.AlertKey.Group()["host"]; !ok { 622 continue 623 } else if stateHost != host.Name { 624 continue 625 } 626 silenced := silences(ak) 627 is := IncidentStatus{ 628 IncidentID: state.Id, 629 Active: state.IsActive(), 630 AlertKey: state.AlertKey, 631 Status: state.CurrentStatus, 632 StatusTime: state.Last().Time.Unix(), 633 Subject: state.Subject, 634 Silenced: silenced != nil, 635 LastAbnormalStatus: state.LastAbnormalStatus, 636 LastAbnormalTime: state.LastAbnormalTime, 637 NeedsAck: state.NeedAck, 638 } 639 host.OpenIncidents = append(host.OpenIncidents, is) 640 } 641 } 642 643 // Cisco Discovery Protocol 644 type CDPCacheEntry struct { 645 DeviceID string 646 DevicePort string 647 } 648 649 type CDPCacheEntries []CDPCacheEntry 650 651 type HostInterface struct { 652 Description string `json:",omitempty"` 653 IPAddresses []string `json:",omitempty"` 654 RemoteMacs []string `json:",omitempty"` 655 CDPCacheEntries CDPCacheEntries `json:",omitempty"` 656 Inbps int64 657 LinkSpeed int64 `json:",omitempty"` 658 MAC string `json:",omitempty"` 659 Master string `json:",omitempty"` 660 Name string `json:",omitempty"` 661 Outbps int64 662 StatsLastUpdated int64 663 Type string 664 } 665 666 type Disk struct { 667 UsedBytes int64 668 TotalBytes int64 669 Label string `json:",omitempty"` 670 StatsLastUpdated int64 671 } 672 673 type MemoryModule struct { 674 // Maybe this should be a bool but that might be limiting 675 Status string 676 StatusLastUpdated int64 677 Size string 678 } 679 680 type ChassisComponent struct { 681 Status string 682 StatusLastUpdated int64 683 } 684 685 type PowerSupply struct { 686 Status string 687 StatusLastUpdated int64 688 Amps float64 689 AmpsLastUpdated int64 690 Volts float64 691 VoltsLastUpdated int64 692 metadata.HWPowerSupplyMeta //Should be renamed to Meta 693 } 694 695 type PhysicalDisk struct { 696 Status string 697 StatusLastUpdated int64 698 metadata.HWDiskMeta 699 } 700 701 type VirtualDisk struct { 702 Status string 703 StatusLastUpdated int64 704 } 705 706 type Controller struct { 707 Status string 708 StatusLastUpdated int64 709 metadata.HWControllerMeta 710 } 711 712 type Temp struct { 713 Celsius float64 714 Status string 715 StatusLastUpdated int64 716 CelsiusLastUpdated int64 717 } 718 719 type ICMPData struct { 720 TimedOut bool 721 TimedOutLastUpdated int64 722 DNSResolved bool 723 DNSResolvedLastUpdated int64 724 RTTMS float64 725 RTTLastUpdated int64 726 } 727 728 func newHostData() *HostData { 729 hd := &HostData{} 730 hd.CPU.Processors = make(map[string]string) 731 hd.Interfaces = make(map[string]*HostInterface) 732 hd.Disks = make(map[string]*Disk) 733 hd.Services = make(map[string]*ServiceStatus) 734 hd.Processes = make(map[string]*Process) 735 hd.ICMPData = make(map[string]*ICMPData) 736 hd.Hardware = &Hardware{} 737 hd.Hardware.ChassisComponents = make(map[string]*ChassisComponent) 738 hd.Hardware.Temps = make(map[string]*Temp) 739 hd.Hardware.PowerSupplies = make(map[string]*PowerSupply) 740 hd.Hardware.Memory = make(map[string]*MemoryModule) 741 hd.Hardware.Storage.PhysicalDisks = make(map[string]*PhysicalDisk) 742 hd.Hardware.Storage.VirtualDisks = make(map[string]*VirtualDisk) 743 hd.Hardware.Storage.Controllers = make(map[string]*Controller) 744 hd.Hardware.Storage.Batteries = make(map[string]*Battery) 745 return hd 746 } 747 748 // Clean sets certain maps to nil so they don't get marshalled in JSON 749 // The logic is to remove ones that monitored devices might lack, such 750 // as hardware information 751 func (hd *HostData) Clean() { 752 if len(hd.CPU.Processors) == 0 { 753 hd.CPU.Processors = nil 754 } 755 if len(hd.Disks) == 0 { 756 hd.Disks = nil 757 } 758 if len(hd.Services) == 0 { 759 hd.Services = nil 760 } 761 if len(hd.Processes) == 0 { 762 hd.Processes = nil 763 } 764 hwLen := len(hd.Hardware.ChassisComponents) + 765 len(hd.Hardware.Memory) + 766 len(hd.Hardware.Storage.PhysicalDisks) + 767 len(hd.Hardware.Storage.VirtualDisks) + 768 len(hd.Hardware.Storage.Controllers) + 769 len(hd.Hardware.PowerSupplies) + 770 len(hd.Hardware.Temps) + 771 len(hd.Hardware.Storage.Batteries) 772 if hwLen == 0 { 773 hd.Hardware = nil 774 } 775 } 776 777 type Hardware struct { 778 Memory map[string]*MemoryModule `json:",omitempty"` 779 ChassisComponents map[string]*ChassisComponent `json:",omitempty"` 780 Storage struct { 781 Controllers map[string]*Controller `json:",omitempty"` 782 PhysicalDisks map[string]*PhysicalDisk `json:",omitempty"` 783 VirtualDisks map[string]*VirtualDisk `json:",omitempty"` 784 Batteries map[string]*Battery 785 } 786 Temps map[string]*Temp 787 PowerSupplies map[string]*PowerSupply `json:",omitempty"` 788 BoardPowerReading *BoardPowerReading 789 } 790 791 type BoardPowerReading struct { 792 Watts int64 793 WattsLastUpdated int64 794 } 795 796 type VM struct { 797 Host string `json:",omitempty"` 798 PowerState string `json:",omitempty"` 799 PowerStateLastUpdated int64 `json:",omitempty"` 800 } 801 802 type Battery struct { 803 Status string 804 StatusLastUpdated int64 805 } 806 807 type ServiceStatus struct { 808 Running bool 809 RunningLastUpdated int64 810 } 811 812 type Process struct { 813 CPUPercentUsed float64 814 CPUPercentLastUpdated int64 815 UsedRealBytes int64 816 UsedRealBytesLastUpdated int64 817 UsedVirtualBytes int64 818 UsedVirtualBytesLastUpdated int64 819 Count int64 820 CountLastUpdated int64 821 } 822 823 type HostData struct { 824 CPU struct { 825 Logical int64 `json:",omitempty"` 826 Physical int64 `json:",omitempty"` 827 PercentUsed float64 828 StatsLastUpdated int64 829 Processors map[string]string `json:",omitempty"` 830 } 831 ICMPData map[string]*ICMPData 832 Disks map[string]*Disk 833 OpenIncidents []IncidentStatus 834 Interfaces map[string]*HostInterface 835 UptimeSeconds int64 `json:",omitempty"` 836 Manufacturer string `json:",omitempty"` 837 Hardware *Hardware `json:",omitempty"` 838 Memory struct { 839 TotalBytes float64 840 UsedBytes float64 841 StatsLastUpdated int64 842 } 843 Processes map[string]*Process `json:",omitempty"` 844 Services map[string]*ServiceStatus `json:",omitempty"` 845 Model string `json:",omitempty"` 846 Name string `json:",omitempty"` 847 OS struct { 848 Caption string `json:",omitempty"` 849 Version string `json:",omitempty"` 850 } 851 SerialNumber string `json:",omitempty"` 852 VM *VM `json:",omitempty"` 853 Guests []string `json:",omitempty"` 854 }