Flags support
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Adam Štrauch 2022-02-03 01:31:47 +01:00
parent 2a34177ab8
commit a213fac34a
Signed by: cx
GPG Key ID: 018304FFA8988F8D
10 changed files with 181 additions and 9 deletions

View File

@ -2,6 +2,8 @@
test:
go test -v apps/*.go
go test -v apps/drivers/*.go
go test -v detector/*.go
go test -v docker/*.go
build:
#podman run --rm --privileged -ti -v ${shell pwd}:/srv docker.io/library/golang:1.14-stretch /bin/sh -c "cd /srv && go build"
@ -18,7 +20,7 @@ minio:
-p 9001:9001 \
-e MINIO_ROOT_USER=test \
-e MINIO_ROOT_PASSWORD=testtest \
minio/minio server /data --console-address ":9001"
docker.io/minio/minio:latest server /data --console-address ":9001"
.PHONY: clean
clean:

View File

@ -4,3 +4,13 @@
Node API is an microservice that runs on node servers. It provides interface between
Docker and the admin site.
## Test
On Fedora run podman API:
Root: sudo systemctl enable --now podman.socket
Rootless: podman system service -t 0 --log-level=debug

View File

@ -3,6 +3,7 @@ package apps
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/rosti-cz/node-api/detector"
)
// AppsProcessor encapsulates functions for apps manipulation
@ -109,13 +110,14 @@ func (a *AppsProcessor) Update(name string, SSHPort int, HTTPPort int, image str
}
// UpdateResources updates various metrics saved in the database
func (a *AppsProcessor) UpdateResources(name string, state string, CPUUsage float64, memory int, diskUsageBytes int, diskUsageInodes int) error {
func (a *AppsProcessor) UpdateResources(name string, state string, CPUUsage float64, memory int, diskUsageBytes int, diskUsageInodes int, flags detector.Flags) error {
err := a.DB.Model(&App{}).Where("name = ?", name).Updates(App{
State: state,
CPUUsage: CPUUsage,
MemoryUsage: memory,
DiskUsageBytes: diskUsageBytes,
DiskUsageInodes: diskUsageInodes,
Flags: flags,
}).Error
return err
}

View File

@ -7,6 +7,7 @@ import (
// This is line from GORM documentation that imports database dialect
_ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/rosti-cz/node-api/detector"
)
// ValidationError is error that holds multiple validation error messages
@ -31,11 +32,12 @@ type Label struct {
// AppState contains info about runnint application, it's not saved in the database
type AppState struct {
State string `json:"state"`
CPUUsage float64 `json:"cpu_usage"` // in percents
MemoryUsage int `json:"memory_usage"` // in MB
DiskUsageBytes int `json:"disk_usage_bytes"`
DiskUsageInodes int `json:"disk_usage_inodes"`
State string `json:"state"`
CPUUsage float64 `json:"cpu_usage"` // in percents
MemoryUsage int `json:"memory_usage"` // in MB
DiskUsageBytes int `json:"disk_usage_bytes"`
DiskUsageInodes int `json:"disk_usage_inodes"`
Flags detector.Flags `json:"flags"`
}
// Apps is list of applications
@ -83,6 +85,8 @@ type App struct {
DiskUsageBytes int `json:"disk_usage_bytes"`
// Disk usage in inodes
DiskUsageInodes int `json:"disk_usage_inodes"`
// Flags from detector of problems in the container
Flags detector.Flags `json:"flags"`
// this is gathered in docker package and has to be assembled externally
Techs AppTechs `json:"techs,omitempty" gorm:"-"` // list of available technologies in the image

37
detector/main.go Normal file
View File

@ -0,0 +1,37 @@
package detector
import (
"fmt"
"regexp"
)
// Flags is list of strings describing problems found among the processes
type Flags []string
// Check goes over patterns and tries to flag given list of processes with flags.
func Check(processes []string) (Flags, error) {
flags := Flags{}
tmpFlags := make(map[string]bool)
for _, process := range processes {
for flag, patternSet := range patterns {
for _, pattern := range patternSet {
matched, err := regexp.MatchString(".*"+pattern+".*", process)
if err != nil {
return flags, err
}
if matched {
tmpFlags[flag] = true
break
}
fmt.Println(process, pattern, flag)
}
}
}
for flag, _ := range tmpFlags {
flags = append(flags, flag)
}
return flags, nil
}

35
detector/main_test.go Normal file
View File

@ -0,0 +1,35 @@
package detector
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCheck(t *testing.T) {
flags, err := Check([]string{
"sleep",
"apache2",
"miner",
"verus-solve",
})
assert.Nil(t, err)
assert.Contains(t, flags, "miner")
flags, err = Check([]string{
"sleep",
"apache2",
"hellminer",
})
assert.Nil(t, err)
assert.Contains(t, flags, "miner")
flags, err = Check([]string{
"sleep",
"apache2",
"miner", // This is not among patterns map
})
assert.Nil(t, err)
assert.NotContains(t, flags, "miner")
}

8
detector/patterns.go Normal file
View File

@ -0,0 +1,8 @@
package detector
var patterns map[string][]string = map[string][]string{
"miner": {
`verus\-solve`,
`hellminer`,
},
}

View File

@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
@ -17,6 +18,7 @@ import (
"github.com/docker/docker/api/types/network"
dockerClient "github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
"github.com/rosti-cz/node-api/detector"
)
// Stats delay in seconds
@ -27,7 +29,7 @@ const dockerTimeout = 10
// DOCKER_SOCK tells where to connect to docker, it will be always local sock
const dockerSock = "/var/run/docker.sock"
const podmanSock = "/run/podman/podman.sock"
const podmanSock = "/run/user/1000/podman/podman.sock"
// DOCKER_API_VERSION set API version of Docker, 1.40 belongs to Docker 19.03.11
const dockerAPIVersion = "1.38"
@ -47,7 +49,10 @@ func (d *Driver) getClient() (*dockerClient.Client, error) {
}
cli, err := dockerClient.NewClient("unix://"+connectTo, dockerAPIVersion, nil, nil)
return cli, err
if err != nil {
return cli, fmt.Errorf("get docker client error: %v", err)
}
return cli, nil
}
// ConnectionStatus checks connection to the Docker daemon
@ -448,3 +453,43 @@ func (d *Driver) Exec(name string, cmd []string, stdin string, env []string, att
return &stdouterr, err
}
// GetProcesses return list of processes running under this container
func (d *Driver) GetProcesses(name string) ([]string, error) {
processes := []string{}
ctx := context.Background()
cli, err := d.getClient()
if err != nil {
return processes, err
}
defer cli.Close()
processList, err := cli.ContainerTop(ctx, name, []string{"-eo", "args"})
if err != nil {
return processes, fmt.Errorf("docker container top call error: %v", err)
}
for _, process := range processList.Processes {
if len(process) > 0 {
processes = append(processes, process[0])
}
}
return processes, nil
}
// GetFlags returns list of flags with problems found in the container, mainly used to detect miners or viruses
func (d *Driver) GetFlags(name string) (detector.Flags, error) {
processes, err := d.GetProcesses(name)
if err != nil {
return detector.Flags{}, err
}
flags, err := detector.Check(processes)
if err != nil {
return flags, err
}
return flags, nil
}

28
docker/docker_test.go Normal file
View File

@ -0,0 +1,28 @@
package docker
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetProcesses(t *testing.T) {
driver := Driver{
BindIPHTTP: "127.0.0.1",
BindIPSSH: "127.0.0.1",
}
driver.Remove("test")
_, err := driver.Create("test", "docker.io/library/busybox", "/tmp", 8990, 8922, 1, 128, []string{"sleep", "3600"})
assert.Nil(t, err)
err = driver.Start("test")
assert.Nil(t, err)
processes, err := driver.GetProcesses("test")
assert.Nil(t, err)
assert.Contains(t, processes, "sleep 3600")
driver.Remove("test")
}

View File

@ -35,6 +35,7 @@ func updateUsage(name string) error {
state.MemoryUsage,
state.DiskUsageBytes,
state.DiskUsageInodes,
state.Flags,
)
return err