2022-02-05 01:22:53 +00:00
|
|
|
package containers
|
2020-07-09 22:27:23 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2020-07-15 21:32:28 +00:00
|
|
|
"log"
|
2020-07-11 11:04:37 +00:00
|
|
|
"os"
|
2020-07-09 22:27:23 +00:00
|
|
|
"os/exec"
|
2020-07-11 11:04:37 +00:00
|
|
|
"path/filepath"
|
2020-07-09 22:27:23 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2020-07-25 22:34:16 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/rosti-cz/node-api/apps"
|
2020-07-09 22:27:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Return bytes, inodes occupied by a directory and/or error if there is any
|
|
|
|
func du(path string) (int, int, error) {
|
|
|
|
space, inodes := 0, 0
|
|
|
|
|
|
|
|
// Occupied space
|
|
|
|
var out bytes.Buffer
|
2020-07-15 21:32:28 +00:00
|
|
|
var errOut bytes.Buffer
|
2020-07-16 21:24:09 +00:00
|
|
|
command := exec.Command("/usr/bin/du", "-b", "-s", path)
|
2020-07-09 22:27:23 +00:00
|
|
|
command.Stdout = &out
|
2020-07-15 21:32:28 +00:00
|
|
|
command.Stderr = &errOut
|
2020-07-09 22:27:23 +00:00
|
|
|
err := command.Run()
|
|
|
|
if err != nil {
|
2020-07-15 21:32:28 +00:00
|
|
|
log.Println(errOut.String())
|
2020-07-09 22:27:23 +00:00
|
|
|
return space, inodes, err
|
|
|
|
}
|
|
|
|
fields := strings.Fields(strings.TrimSpace(out.String()))
|
|
|
|
out.Reset()
|
2020-07-15 21:32:28 +00:00
|
|
|
errOut.Reset()
|
2020-07-09 22:27:23 +00:00
|
|
|
|
|
|
|
if len(fields) == 2 {
|
|
|
|
space, err = strconv.Atoi(fields[0])
|
|
|
|
if err != nil {
|
|
|
|
return space, inodes, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Occupied inodes
|
2020-07-15 21:32:28 +00:00
|
|
|
command = exec.Command("/usr/bin/du", "--inodes", "-s", path)
|
2020-07-09 22:27:23 +00:00
|
|
|
command.Stdout = &out
|
2020-07-15 21:32:28 +00:00
|
|
|
command.Stderr = &errOut
|
2020-07-09 22:27:23 +00:00
|
|
|
err = command.Run()
|
|
|
|
if err != nil {
|
2020-07-15 21:32:28 +00:00
|
|
|
log.Println(errOut.String())
|
2020-07-09 22:27:23 +00:00
|
|
|
return space, inodes, err
|
|
|
|
}
|
|
|
|
fields = strings.Fields(strings.TrimSpace(out.String()))
|
|
|
|
out.Reset()
|
2020-07-15 21:32:28 +00:00
|
|
|
errOut.Reset()
|
2020-07-09 22:27:23 +00:00
|
|
|
|
|
|
|
if len(fields) == 2 {
|
2020-07-15 21:32:28 +00:00
|
|
|
inodes, err = strconv.Atoi(fields[0])
|
2020-07-09 22:27:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return inodes, inodes, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return space, inodes, nil
|
|
|
|
}
|
2020-07-11 11:04:37 +00:00
|
|
|
|
2022-02-07 17:20:22 +00:00
|
|
|
// Removes content of given directory and then the directory itself
|
2020-07-11 11:04:37 +00:00
|
|
|
func removeDirectory(dir string) error {
|
|
|
|
d, err := os.Open(dir)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer d.Close()
|
|
|
|
names, err := d.Readdirnames(-1)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, name := range names {
|
|
|
|
err = os.RemoveAll(filepath.Join(dir, name))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2022-02-07 17:20:22 +00:00
|
|
|
|
|
|
|
err = os.Remove(filepath.Join(dir))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-07-11 11:04:37 +00:00
|
|
|
return nil
|
|
|
|
}
|
2020-07-25 22:34:16 +00:00
|
|
|
|
|
|
|
// CPUMemoryStats returns list of applications with updated CPU and memory usage effectively.
|
|
|
|
// Sample is number of seconds between two measurements of the CPU usage. More means more precise.
|
|
|
|
func CPUMemoryStats(applist *[]apps.App, sample int) (*[]apps.App, error) {
|
|
|
|
if sample <= 0 {
|
|
|
|
sample = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
containers := []Container{}
|
|
|
|
for _, app := range *applist {
|
|
|
|
containers = append(containers, Container{App: &app})
|
|
|
|
}
|
|
|
|
|
|
|
|
startMap := make(map[string]int64)
|
|
|
|
endMap := make(map[string]int64)
|
|
|
|
|
|
|
|
start := time.Now().UnixNano()
|
|
|
|
for _, container := range containers {
|
|
|
|
cpu, _, err := container.GetRawResourceStats()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
startMap[container.App.Name] = cpu
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(time.Duration(sample) * time.Second)
|
|
|
|
|
|
|
|
for idx, container := range containers {
|
|
|
|
cpu, memory, err := container.GetRawResourceStats()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
endMap[container.App.Name] = cpu
|
|
|
|
containers[idx].App.MemoryUsage = memory
|
|
|
|
}
|
|
|
|
|
|
|
|
end := time.Now().UnixNano()
|
|
|
|
difference := (float64(end) - float64(start)) / float64(1000000000)
|
|
|
|
|
|
|
|
updatedApps := []apps.App{}
|
|
|
|
for _, container := range containers {
|
|
|
|
app := *container.App
|
|
|
|
app.CPUUsage = (float64(endMap[app.Name]) - float64(startMap[app.Name])) / difference / 10000000.0
|
|
|
|
updatedApps = append(updatedApps, app)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &updatedApps, nil
|
|
|
|
}
|