Node index finalization
This commit is contained in:
parent
e6f8d49cc8
commit
c45c27ac38
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
rosti.db
|
rosti.db
|
||||||
node-api
|
node-api
|
||||||
.history/
|
.history/
|
||||||
|
api-node-17.http
|
||||||
|
22
main.go
22
main.go
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/rosti-cz/node-api/apps"
|
"github.com/rosti-cz/node-api/apps"
|
||||||
"github.com/rosti-cz/node-api/common"
|
"github.com/rosti-cz/node-api/common"
|
||||||
"github.com/rosti-cz/node-api/docker"
|
"github.com/rosti-cz/node-api/docker"
|
||||||
"github.com/rosti-cz/node-api/nodes"
|
"github.com/rosti-cz/node-api/node"
|
||||||
)
|
)
|
||||||
|
|
||||||
// JSONIndent Indendation of JSON output format
|
// JSONIndent Indendation of JSON output format
|
||||||
@ -18,8 +18,6 @@ const JSONIndent = " "
|
|||||||
func main() {
|
func main() {
|
||||||
// Close database at the end
|
// Close database at the end
|
||||||
db := common.GetDBConnection()
|
db := common.GetDBConnection()
|
||||||
// db.AutoMigrate(apps.Label{})
|
|
||||||
// db.AutoMigrate(apps.App{})
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
// Templating
|
// Templating
|
||||||
@ -27,11 +25,24 @@ func main() {
|
|||||||
|
|
||||||
// Stats loop
|
// Stats loop
|
||||||
go func() {
|
go func() {
|
||||||
|
for {
|
||||||
err := gatherContainerStats()
|
err := gatherContainerStats()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("LOOP ERROR:", err.Error())
|
log.Println("LOOP ERROR:", err.Error())
|
||||||
}
|
}
|
||||||
time.Sleep(5 * time.Minute)
|
time.Sleep(5 * time.Minute)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Node stats
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
err := node.Log()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("NODE PERFORMANCE LOG ERROR:", err.Error())
|
||||||
|
}
|
||||||
|
time.Sleep(5 * time.Minute)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// API
|
// API
|
||||||
@ -324,7 +335,10 @@ func main() {
|
|||||||
|
|
||||||
// Return info about the node including performance index
|
// Return info about the node including performance index
|
||||||
e.GET("/v1/node", func(c echo.Context) error {
|
e.GET("/v1/node", func(c echo.Context) error {
|
||||||
node := nodes.GetNodeInfo()
|
node, err := node.GetNodeInfo()
|
||||||
|
if err != nil {
|
||||||
|
return c.JSONPretty(http.StatusInternalServerError, Message{Message: err.Error()}, JSONIndent)
|
||||||
|
}
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, node)
|
return c.JSON(http.StatusOK, node)
|
||||||
})
|
})
|
||||||
|
134
node/load.go
Normal file
134
node/load.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/rosti-cz/node-api/common"
|
||||||
|
|
||||||
|
"github.com/shirou/gopsutil/cpu"
|
||||||
|
"github.com/shirou/gopsutil/disk"
|
||||||
|
"github.com/shirou/gopsutil/load"
|
||||||
|
"github.com/shirou/gopsutil/mem"
|
||||||
|
)
|
||||||
|
|
||||||
|
const history = 72 * 3600 / 300 // 3 days, one record every five minutes
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
db := common.GetDBConnection()
|
||||||
|
db.AutoMigrate(PerformanceLog{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log creates a record for all important metrics used as
|
||||||
|
func Log() error {
|
||||||
|
performanceLog := PerformanceLog{}
|
||||||
|
|
||||||
|
// Load
|
||||||
|
loadStats, err := load.Avg()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
performanceLog.Load1 = loadStats.Load1
|
||||||
|
performanceLog.Load5 = loadStats.Load5
|
||||||
|
performanceLog.Load15 = loadStats.Load15
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
memoryStat, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
performanceLog.Memory = memoryStat.UsedPercent / 100.0
|
||||||
|
|
||||||
|
// Disk space
|
||||||
|
diskUsage, err := disk.Usage("/srv")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
performanceLog.DiskSpaceUsage = diskUsage.UsedPercent / 100.0
|
||||||
|
|
||||||
|
// Save
|
||||||
|
db := common.GetDBConnection()
|
||||||
|
err = db.Create(&performanceLog).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// and clean
|
||||||
|
// we have to use this stupid approach because DELETE doesn't support ORDER BY and LIMIT
|
||||||
|
toDeleteLogs := []PerformanceLog{}
|
||||||
|
err = db.Order("id DESC").Limit("99").Offset(history).Find(&toDeleteLogs).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, toDeleteLog := range toDeleteLogs {
|
||||||
|
err = db.Delete(&toDeleteLog).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index returns number from 0 to 1 where 0 means least loaded and 1 maximally loaded.
|
||||||
|
// It uses history of last 72 hours
|
||||||
|
func index() (*Node, error) {
|
||||||
|
node := Node{
|
||||||
|
Index: 1.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of CPUs
|
||||||
|
cpus, err := cpu.Counts(true)
|
||||||
|
if err != nil {
|
||||||
|
return &node, err
|
||||||
|
}
|
||||||
|
|
||||||
|
db := common.GetDBConnection()
|
||||||
|
|
||||||
|
logs := []PerformanceLog{}
|
||||||
|
|
||||||
|
err = db.Find(&logs).Error
|
||||||
|
if err != nil {
|
||||||
|
return &node, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalLoad1 float64
|
||||||
|
var totalLoad5 float64
|
||||||
|
var totalLoad15 float64
|
||||||
|
var totalDiskSpaceUsage float64
|
||||||
|
var totalMemory float64
|
||||||
|
|
||||||
|
// If there is no record we have to wait until it is, until then the server is "full"
|
||||||
|
if len(logs) == 0 {
|
||||||
|
return &node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, log := range logs {
|
||||||
|
totalLoad1 += log.Load1
|
||||||
|
totalLoad5 += log.Load5
|
||||||
|
totalLoad15 += log.Load15
|
||||||
|
totalDiskSpaceUsage += log.DiskSpaceUsage
|
||||||
|
totalMemory += log.Memory
|
||||||
|
}
|
||||||
|
|
||||||
|
node.Load1Index = totalLoad1 / float64(len(logs)) / float64(cpus)
|
||||||
|
node.Load5Index = totalLoad5 / float64(len(logs)) / float64(cpus)
|
||||||
|
node.Load15Index = totalLoad15 / float64(len(logs)) / float64(cpus)
|
||||||
|
node.MemoryIndex = totalMemory / float64(len(logs))
|
||||||
|
node.DiskSpaceIndex = totalDiskSpaceUsage / float64(len(logs))
|
||||||
|
|
||||||
|
var indexes []float64
|
||||||
|
indexes = append(indexes, node.Load5Index)
|
||||||
|
indexes = append(indexes, node.MemoryIndex)
|
||||||
|
indexes = append(indexes, node.DiskSpaceIndex)
|
||||||
|
|
||||||
|
finalIndex := float64(0)
|
||||||
|
for _, index := range indexes {
|
||||||
|
if index > finalIndex {
|
||||||
|
finalIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.Index = finalIndex
|
||||||
|
|
||||||
|
return &node, nil
|
||||||
|
}
|
7
node/main.go
Normal file
7
node/main.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
// GetNodeInfo returns information about this node
|
||||||
|
func GetNodeInfo() (*Node, error) {
|
||||||
|
node, err := index()
|
||||||
|
return node, err
|
||||||
|
}
|
27
node/types.go
Normal file
27
node/types.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import "github.com/jinzhu/gorm"
|
||||||
|
|
||||||
|
// Node keeps info about server
|
||||||
|
type Node struct {
|
||||||
|
Index float64 `json:"index"` // 0 is empty server, 1 means full server
|
||||||
|
Load1Index float64 `json:"load1_index"` // 0 is empty server, 1 means resource fully used
|
||||||
|
Load5Index float64 `json:"load5_index"` // 0 is empty server, 1 means resource fully used
|
||||||
|
Load15Index float64 `json:"load15_index"` // 0 is empty server, 1 means resource fully used
|
||||||
|
MemoryIndex float64 `json:"memory_index"` // 0 is empty server, 1 means resource fully used
|
||||||
|
DiskSpaceIndex float64 `json:"disk_space_index"` // 0 is empty server, 1 means resource fully used
|
||||||
|
|
||||||
|
// TODO not implemented
|
||||||
|
SoldMemory int `json:"-"` // allocated to containers
|
||||||
|
}
|
||||||
|
|
||||||
|
// PerformanceLog keeps track of performance history
|
||||||
|
type PerformanceLog struct {
|
||||||
|
gorm.Model
|
||||||
|
|
||||||
|
Load1 float64
|
||||||
|
Load5 float64
|
||||||
|
Load15 float64
|
||||||
|
DiskSpaceUsage float64
|
||||||
|
Memory float64
|
||||||
|
}
|
@ -1,66 +0,0 @@
|
|||||||
package nodes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/jinzhu/gorm"
|
|
||||||
"github.com/shirou/gopsutil/cpu"
|
|
||||||
"github.com/shirou/gopsutil/disk"
|
|
||||||
"github.com/shirou/gopsutil/load"
|
|
||||||
"github.com/shirou/gopsutil/mem"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PerformanceLog keeps track of performance history
|
|
||||||
type PerformanceLog struct {
|
|
||||||
gorm.Model
|
|
||||||
|
|
||||||
Load1 float64
|
|
||||||
Load5 float64
|
|
||||||
Load15 float64
|
|
||||||
DiskSpaceUsage float64
|
|
||||||
Memory float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log creates a record for all important metrics used as
|
|
||||||
func Log() error {
|
|
||||||
performanceLog := PerformanceLog{}
|
|
||||||
|
|
||||||
// Load
|
|
||||||
loadStats, err := load.Avg()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
performanceLog.Load1 = loadStats.Load1
|
|
||||||
performanceLog.Load5 = loadStats.Load5
|
|
||||||
performanceLog.Load15 = loadStats.Load15
|
|
||||||
|
|
||||||
// Memory
|
|
||||||
memoryStat, err := mem.VirtualMemory()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
performanceLog.Memory = memoryStat.UsedPercent / 100.0
|
|
||||||
|
|
||||||
// Disk space
|
|
||||||
diskUsage, err := disk.Usage("/srv")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
performanceLog.DiskSpaceUsage = diskUsage.UsedPercent / 100.0
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Index returns number from 0 to 1 where 0 means least loaded and 1 maximally loaded.
|
|
||||||
// It uses history of last 72 hours
|
|
||||||
func Index() (float64, error) {
|
|
||||||
// Number of CPUs
|
|
||||||
cpus, err := cpu.Counts(true)
|
|
||||||
if err != nil {
|
|
||||||
return 1.0, err
|
|
||||||
}
|
|
||||||
log.Println(cpus)
|
|
||||||
|
|
||||||
return 1.0, err
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package nodes
|
|
||||||
|
|
||||||
// Node keeps info about server
|
|
||||||
type Node struct {
|
|
||||||
OccupationIndex float32 // bigger number bigger load, number over 1 means full server
|
|
||||||
Memory int
|
|
||||||
SoldMemory int // allocated to containers
|
|
||||||
LoadOverDay float32 // average load 5 in last 24 hours
|
|
||||||
DiskSpaceUsed int // Usage of overall disk space
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetNodeInfo returns information about this node
|
|
||||||
func GetNodeInfo() *Node {
|
|
||||||
node := Node{
|
|
||||||
OccupationIndex: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
return &node
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user