feat: implement plugin structure
- Plugin Manager - Plugin Opener - Code refactoring - Memory usage with gopsutil/mem
This commit is contained in:
parent
73c6ceac7f
commit
b3fcfc2f06
8 changed files with 131 additions and 103 deletions
|
@ -19,29 +19,9 @@ const LogFile = DataDir + "ahenk.log"
|
||||||
const LibDir = "/usr/share/ahenk-go/"
|
const LibDir = "/usr/share/ahenk-go/"
|
||||||
const PluginDir = LibDir + "/plugins/"
|
const PluginDir = LibDir + "/plugins/"
|
||||||
|
|
||||||
// FIXME there isn't any difference with Stop() function
|
|
||||||
// TODO There can be a Start() function in it but start function doesnt work properly right now
|
|
||||||
func Restart(pid, signal int) {
|
|
||||||
Stop(pid, signal)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop Ahenkd Daemon with a specific PID (running from second copy)
|
|
||||||
// do not forget to use also os.Exit() when using in ExecStop
|
|
||||||
func Stop(pid, signal int) {
|
|
||||||
log.Println("Stop Signal Caught")
|
|
||||||
|
|
||||||
// FILLME what you want to do before stopping daemon?
|
|
||||||
|
|
||||||
if err := syscall.Kill(pid, syscall.Signal(signal)); err == nil {
|
|
||||||
log.Printf("Ahenk Daemon with pid number %v Successfully stopped", pid) // TODO Also log to /etc/ahenk-go/ahenkd.log
|
|
||||||
} else {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main Function that starts daemon and controls arguments
|
// Main Function that starts daemon and controls arguments
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) == 2 && slices.Contains([]string{"start", "stop", "restart", "nodaemon"}, os.Args[1]) {
|
if len(os.Args) == 2 && slices.Contains([]string{"start", "stop", "restart", "nodaemon", "tmptest"}, os.Args[1]) {
|
||||||
switch os.Args[1] {
|
switch os.Args[1] {
|
||||||
case "start":
|
case "start":
|
||||||
utils.CreatePath(DataDir)
|
utils.CreatePath(DataDir)
|
||||||
|
@ -67,11 +47,9 @@ func main() {
|
||||||
case "stop":
|
case "stop":
|
||||||
i, _ := daemon.ReadPidFile(PidFile)
|
i, _ := daemon.ReadPidFile(PidFile)
|
||||||
Stop(i, 15)
|
Stop(i, 15)
|
||||||
os.Exit(0)
|
|
||||||
case "restart":
|
case "restart":
|
||||||
i, _ := daemon.ReadPidFile(PidFile)
|
i, _ := daemon.ReadPidFile(PidFile)
|
||||||
Restart(i, 15)
|
Restart(i, 15)
|
||||||
os.Exit(0)
|
|
||||||
case "nodaemon":
|
case "nodaemon":
|
||||||
log.Print("STARTED AS NO-DAEMON")
|
log.Print("STARTED AS NO-DAEMON")
|
||||||
|
|
||||||
|
@ -83,15 +61,36 @@ func main() {
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
log.Print("Killed")
|
log.Print("Killed")
|
||||||
case "tmptest":
|
case "tmptest":
|
||||||
log.Print("TEMPORARY TEST")
|
log.Print("TEMPORARY TEST STARTED, log files are NOT redirecting!")
|
||||||
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
log.Print("Killed")
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic("Please enter a valid option !")
|
panic("Please enter a valid option !")
|
||||||
}
|
}
|
||||||
PluginManager()
|
PluginManager()
|
||||||
log.Print("Plugin Manager Started Succesfully")
|
|
||||||
// NEXT Make PluginManager async !
|
// NEXT Make PluginManager async !
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME there isn't any difference with Stop() function
|
||||||
|
// TODO There can be a Start() function in it but start function doesnt work properly right now
|
||||||
|
// Restart ahenk daemon with a specific PID (running from second copy)
|
||||||
|
func Restart(pid, signal int) {
|
||||||
|
Stop(pid, signal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop ahenk daemon with a specific PID (running from second copy)
|
||||||
|
func Stop(pid, signal int) {
|
||||||
|
log.Println("Stop Signal Caught")
|
||||||
|
|
||||||
|
// FILLME what you want to do before stopping daemon?
|
||||||
|
|
||||||
|
if err := syscall.Kill(pid, syscall.Signal(signal)); err == nil {
|
||||||
|
log.Printf("Ahenk Daemon with pid number %v Successfully stopped", pid)
|
||||||
|
f := utils.OpenLogFile(LogFile)
|
||||||
|
defer f.Close()
|
||||||
|
log.SetOutput(f)
|
||||||
|
log.Printf("Ahenk Daemon with pid number %v Successfully stopped", pid)
|
||||||
|
} else {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
|
@ -1,31 +1,32 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "log"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// type Greeter interface {
|
// plugins/resources
|
||||||
// Greet()
|
type Resources interface {
|
||||||
// }
|
AgentInfo() map[string]interface{}
|
||||||
|
|
||||||
func PluginManager() {
|
|
||||||
// LoadPlugin("resources")
|
|
||||||
|
|
||||||
// // 4. use the module
|
|
||||||
// greeter.Greet()
|
|
||||||
|
|
||||||
// greeter.Myvar()
|
|
||||||
// // for {
|
|
||||||
// // logPlugin(greeter.AgentInfo())
|
|
||||||
// // time.Sleep(30 * time.Second)
|
|
||||||
// // }
|
|
||||||
log.Print("plugin manager started succesfully")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// func logPlugin(mp map[string]interface{}) {
|
// Loads Plugins and runs them.
|
||||||
// fmt.Printf("\nOs Info:\n")
|
// When you create a new plugin create a new interface and call this plugin in this function
|
||||||
// for i, v := range mp {
|
func PluginManager() {
|
||||||
// fmt.Printf("%v: %v\n", i, v)
|
var resources Resources = LoadPlugin("resources").(Resources)
|
||||||
// }
|
for {
|
||||||
// }
|
logPlugin("AgentInfo", resources.AgentInfo())
|
||||||
|
time.Sleep(30 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logs plugin outputs.
|
||||||
|
func logPlugin(title string, mp map[string]interface{}) {
|
||||||
|
fmt.Printf("\n----- %v -----\n", title)
|
||||||
|
for i, v := range mp {
|
||||||
|
fmt.Printf("%v: %v\n", i, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// // TODO response to Lider
|
// // TODO response to Lider
|
||||||
// // func createResponse() {
|
// // func createResponse() {
|
||||||
|
|
|
@ -1,25 +1,32 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
// // Load Plugin with plugin name and function name
|
import (
|
||||||
// func LoadPlugin(plugName, funcName string) {
|
"fmt"
|
||||||
// plug, err := plugin.Open("../../plugins/resources/main.so")
|
"os"
|
||||||
// if err != nil {
|
"plugin"
|
||||||
// fmt.Println(err)
|
|
||||||
// os.Exit(1)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// symGreeter, err := plug.Lookup("Greeter")
|
"git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/utils"
|
||||||
// if err != nil {
|
)
|
||||||
// fmt.Println(err)
|
|
||||||
// os.Exit(1)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var greeter Greeter
|
// Load Plugin placed in PluginDir, returns empty interface.
|
||||||
// greeter, ok := symGreeter.(Greeter)
|
// Do not forget to cast in plugin manager
|
||||||
// if !ok {
|
//
|
||||||
// fmt.Println("unexpected type from module symbol")
|
// Give Plugin Name as argument and be sure you compiled plugins with `-buildmode=plugin` to PluginDir as `pluginname.so`
|
||||||
// os.Exit(1)
|
func LoadPlugin(plugName string) interface{} {
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // NEXT move plugin-manager.go main here !
|
// TODO if error caugth try without relative path, this will be good for local testing
|
||||||
|
plug, err := plugin.Open(PluginDir + plugName + ".so")
|
||||||
|
utils.Check(err)
|
||||||
|
|
||||||
|
// TODO also allow lookup another symbol other than PlugnameConnect
|
||||||
|
symGreeter, err := plug.Lookup(utils.FirstUpperEN(plugName) + "Connect")
|
||||||
|
utils.Check(err)
|
||||||
|
|
||||||
|
var plugOut interface{}
|
||||||
|
plugOut, ok := symGreeter.(interface{})
|
||||||
|
if !ok {
|
||||||
|
fmt.Println("unexpected type from module symbol")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return plugOut
|
||||||
|
}
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -10,6 +10,7 @@ require (
|
||||||
require (
|
require (
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||||
|
golang.org/x/text v0.12.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -38,6 +38,8 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||||
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/utils"
|
"git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/utils"
|
||||||
"github.com/shirou/gopsutil/disk"
|
"github.com/shirou/gopsutil/disk"
|
||||||
|
"github.com/shirou/gopsutil/mem"
|
||||||
)
|
)
|
||||||
|
|
||||||
const KB = uint64(1024)
|
const KB = uint64(1024)
|
||||||
|
@ -35,8 +36,10 @@ func GetDisks() []disk.PartitionStat {
|
||||||
return parts
|
return parts
|
||||||
}
|
}
|
||||||
|
|
||||||
// return disk usage as MiB
|
// return disk usage as GiB
|
||||||
// TODO different function for all disks / a specified disk?
|
//
|
||||||
|
// TODO different functions for all disks / a specified disk?
|
||||||
|
// FIXME Wrong Disk values for docker !!! (probably because counting also virtual mountpoints?)
|
||||||
func GetDiskUsage() map[string]float64 {
|
func GetDiskUsage() map[string]float64 {
|
||||||
var totalSize, freeSize, usedSize uint64
|
var totalSize, freeSize, usedSize uint64
|
||||||
for _, part := range GetDisks() {
|
for _, part := range GetDisks() {
|
||||||
|
@ -52,3 +55,17 @@ func GetDiskUsage() map[string]float64 {
|
||||||
"used": utils.Byte2GiB(usedSize),
|
"used": utils.Byte2GiB(usedSize),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return memory usage as GiB
|
||||||
|
//
|
||||||
|
// TODO also implement swap usage
|
||||||
|
func GetMemoryUsage() map[string]float64 {
|
||||||
|
v, _ := mem.VirtualMemory()
|
||||||
|
return map[string]float64{
|
||||||
|
"total": utils.Byte2GiB(v.Total),
|
||||||
|
"free": utils.Byte2GiB(v.Free),
|
||||||
|
"used": utils.Byte2GiB(v.Used),
|
||||||
|
"avaliable": utils.Byte2GiB(v.Available),
|
||||||
|
"cached": utils.Byte2GiB(v.Cached),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@ package utils
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/text/cases"
|
||||||
|
"golang.org/x/text/language"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Byte2String(arr []int8) string {
|
func Byte2String(arr []int8) string {
|
||||||
|
@ -55,3 +58,8 @@ func OpenLogFile(path string) *os.File {
|
||||||
}
|
}
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Makes first character uppercase of given English string
|
||||||
|
func FirstUpperEN(str string) string {
|
||||||
|
return cases.Title(language.English).String(str)
|
||||||
|
} // TODO cases.NoLower vs cases.Compact !
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/osinfo"
|
"git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/osinfo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type greeting string
|
type plug string
|
||||||
|
|
||||||
|
// exported plugin Symbol
|
||||||
|
var ResourcesConnect plug
|
||||||
|
|
||||||
// return instant resource usage information
|
// return instant resource usage information
|
||||||
func ResourceUsage() map[string]string {
|
func ResourceUsage() map[string]string {
|
||||||
|
@ -31,28 +33,33 @@ func ResourceUsage() map[string]string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// return general Agent information (that changes rarely)
|
// return general Agent information (that changes rarely)
|
||||||
func (g greeting) AgentInfo() map[string]interface{} {
|
func (p plug) AgentInfo() map[string]interface{} {
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"System": runtime.GOOS, "Release": osinfo.GetKernelInfo()["Release"],
|
"System": runtime.GOOS, "Kernel": osinfo.GetKernelInfo()["Release"],
|
||||||
|
"hostname": osinfo.GetKernelInfo()["Hostname"],
|
||||||
|
"osMachine": osinfo.GetKernelInfo()["Machine"],
|
||||||
|
"diskTotal": osinfo.GetDiskUsage()["total"],
|
||||||
|
"diskUsed": osinfo.GetDiskUsage()["used"],
|
||||||
|
"diskFree": osinfo.GetDiskUsage()["free"],
|
||||||
|
"diskUsage": osinfo.GetDiskUsage()["used"] / osinfo.GetDiskUsage()["total"],
|
||||||
|
"memoryTotal": osinfo.GetMemoryUsage()["total"],
|
||||||
|
"memoryFree": osinfo.GetMemoryUsage()["free"],
|
||||||
|
"memoryAvaliable": osinfo.GetMemoryUsage()["avaliable"],
|
||||||
|
"memoryUsed": osinfo.GetMemoryUsage()["used"],
|
||||||
|
"memoryCached": osinfo.GetMemoryUsage()["cached"],
|
||||||
|
"memoryUsage": (osinfo.GetMemoryUsage()["used"] + osinfo.GetMemoryUsage()["cached"]) / osinfo.GetMemoryUsage()["total"], //REVIEW just used/total ?
|
||||||
|
|
||||||
|
// TODO is calling all functions one by one slow downs code?
|
||||||
|
|
||||||
// TODO 'agentVersion': self.get_agent_version(),
|
// TODO 'agentVersion': self.get_agent_version(),
|
||||||
"hostname": osinfo.GetKernelInfo()["Hostname"],
|
|
||||||
// TODO 'ipAddresses': str(self.Hardware.Network.ip_addresses()).replace('[', '').replace(']', ''),
|
// TODO 'ipAddresses': str(self.Hardware.Network.ip_addresses()).replace('[', '').replace(']', ''),
|
||||||
// "osName": osinfo.GetKernelInfo()["Sysname"], // TODO is it necessary?
|
// TODO get distrubition name also (pardus,arch,debian,windows10 for example ...)
|
||||||
// "osNodeName": osinfo.GetKernelInfo()["NodeName"],// TODO is it necessary?
|
|
||||||
// "osVersion": osinfo.GetKernelInfo()["Version"], // TODO is it necessary?
|
|
||||||
"osMachine": osinfo.GetKernelInfo()["Machine"],
|
|
||||||
// TODO get distrubition name also (pardus,arch,debian,windows10 for example ...)
|
|
||||||
// TODO 'macAddresses': str(self.Hardware.Network.mac_addresses()).replace('[', '').replace(']', ''),
|
// TODO 'macAddresses': str(self.Hardware.Network.mac_addresses()).replace('[', '').replace(']', ''),
|
||||||
// TODO 'hardware.systemDefinitions': self.Hardware.system_definitions(),
|
// TODO 'hardware.systemDefinitions': self.Hardware.system_definitions(),
|
||||||
// TODO 'hardware.monitors': self.Hardware.monitors(),
|
// TODO 'hardware.monitors': self.Hardware.monitors(),
|
||||||
// TODO 'hardware.screens': self.Hardware.screens(),
|
// TODO 'hardware.screens': self.Hardware.screens(),
|
||||||
// TODO 'hardware.usbDevices': self.Hardware.usb_devices(),
|
// TODO 'hardware.usbDevices': self.Hardware.usb_devices(),
|
||||||
// TODO 'hardware.printers': self.Hardware.printers(),
|
// TODO 'hardware.printers': self.Hardware.printers(),
|
||||||
"diskTotal": osinfo.GetDiskUsage()["total"],
|
|
||||||
"diskUsed": osinfo.GetDiskUsage()["used"],
|
|
||||||
"diskFree": osinfo.GetDiskUsage()["free"],
|
|
||||||
// TODO "diskUsage": osinfo.GetDiskUsage()["Usage"],
|
|
||||||
// TODO 'memory': self.Hardware.Memory.total(),
|
|
||||||
// TODO 'Device': device,
|
// TODO 'Device': device,
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
|
@ -61,23 +68,9 @@ func (g greeting) AgentInfo() map[string]interface{} {
|
||||||
func Info() map[string]string {
|
func Info() map[string]string {
|
||||||
inf := make(map[string]string)
|
inf := make(map[string]string)
|
||||||
inf["name"] = "resources"
|
inf["name"] = "resources"
|
||||||
inf["version"] = "0.0.1"
|
inf["version"] = "0.0.2"
|
||||||
inf["support"] = "debian"
|
inf["support"] = "debian"
|
||||||
inf["description"] = "Resource Usage Information and Controls"
|
inf["description"] = "Resource Usage Information and Controls"
|
||||||
inf["developer"] = "asandikci@aliberksandikci.com.tr"
|
inf["developer"] = "asandikci@aliberksandikci.com.tr"
|
||||||
|
|
||||||
// inf["task"] = "true"
|
|
||||||
// inf["user_oriented"] = "false"
|
|
||||||
// inf["machine_oriented"] = "false"
|
|
||||||
return inf
|
return inf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g greeting) Greet() {
|
|
||||||
fmt.Println("Hello Universe")
|
|
||||||
}
|
|
||||||
func (g greeting) Myvar() {
|
|
||||||
fmt.Println("I am here")
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is exported
|
|
||||||
var Greeter greeting
|
|
||||||
|
|
Loading…
Reference in a new issue