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 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
|
||||
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] {
|
||||
case "start":
|
||||
utils.CreatePath(DataDir)
|
||||
|
@ -67,11 +47,9 @@ func main() {
|
|||
case "stop":
|
||||
i, _ := daemon.ReadPidFile(PidFile)
|
||||
Stop(i, 15)
|
||||
os.Exit(0)
|
||||
case "restart":
|
||||
i, _ := daemon.ReadPidFile(PidFile)
|
||||
Restart(i, 15)
|
||||
os.Exit(0)
|
||||
case "nodaemon":
|
||||
log.Print("STARTED AS NO-DAEMON")
|
||||
|
||||
|
@ -83,15 +61,36 @@ func main() {
|
|||
time.Sleep(10 * time.Second)
|
||||
log.Print("Killed")
|
||||
case "tmptest":
|
||||
log.Print("TEMPORARY TEST")
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
log.Print("Killed")
|
||||
log.Print("TEMPORARY TEST STARTED, log files are NOT redirecting!")
|
||||
}
|
||||
} else {
|
||||
panic("Please enter a valid option !")
|
||||
}
|
||||
PluginManager()
|
||||
log.Print("Plugin Manager Started Succesfully")
|
||||
// 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
|
||||
|
||||
import "log"
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// type Greeter interface {
|
||||
// Greet()
|
||||
// }
|
||||
|
||||
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")
|
||||
// plugins/resources
|
||||
type Resources interface {
|
||||
AgentInfo() map[string]interface{}
|
||||
}
|
||||
|
||||
// func logPlugin(mp map[string]interface{}) {
|
||||
// fmt.Printf("\nOs Info:\n")
|
||||
// for i, v := range mp {
|
||||
// fmt.Printf("%v: %v\n", i, v)
|
||||
// }
|
||||
// }
|
||||
// Loads Plugins and runs them.
|
||||
// When you create a new plugin create a new interface and call this plugin in this function
|
||||
func PluginManager() {
|
||||
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
|
||||
// // func createResponse() {
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
package main
|
||||
|
||||
// // Load Plugin with plugin name and function name
|
||||
// func LoadPlugin(plugName, funcName string) {
|
||||
// plug, err := plugin.Open("../../plugins/resources/main.so")
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// os.Exit(1)
|
||||
// }
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"plugin"
|
||||
|
||||
// symGreeter, err := plug.Lookup("Greeter")
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// os.Exit(1)
|
||||
// }
|
||||
"git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/utils"
|
||||
)
|
||||
|
||||
// var greeter Greeter
|
||||
// greeter, ok := symGreeter.(Greeter)
|
||||
// if !ok {
|
||||
// fmt.Println("unexpected type from module symbol")
|
||||
// os.Exit(1)
|
||||
// }
|
||||
// }
|
||||
// Load Plugin placed in PluginDir, returns empty interface.
|
||||
// Do not forget to cast in plugin manager
|
||||
//
|
||||
// Give Plugin Name as argument and be sure you compiled plugins with `-buildmode=plugin` to PluginDir as `pluginname.so`
|
||||
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 (
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
)
|
||||
|
||||
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.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
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=
|
||||
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=
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/utils"
|
||||
"github.com/shirou/gopsutil/disk"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
)
|
||||
|
||||
const KB = uint64(1024)
|
||||
|
@ -35,8 +36,10 @@ func GetDisks() []disk.PartitionStat {
|
|||
return parts
|
||||
}
|
||||
|
||||
// return disk usage as MiB
|
||||
// TODO different function for all disks / a specified disk?
|
||||
// return disk usage as GiB
|
||||
//
|
||||
// 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 {
|
||||
var totalSize, freeSize, usedSize uint64
|
||||
for _, part := range GetDisks() {
|
||||
|
@ -52,3 +55,17 @@ func GetDiskUsage() map[string]float64 {
|
|||
"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 (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func Byte2String(arr []int8) string {
|
||||
|
@ -55,3 +58,8 @@ func OpenLogFile(path string) *os.File {
|
|||
}
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"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
|
||||
func ResourceUsage() map[string]string {
|
||||
|
@ -31,28 +33,33 @@ func ResourceUsage() map[string]string {
|
|||
}
|
||||
|
||||
// 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{}{
|
||||
"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(),
|
||||
"hostname": osinfo.GetKernelInfo()["Hostname"],
|
||||
// TODO 'ipAddresses': str(self.Hardware.Network.ip_addresses()).replace('[', '').replace(']', ''),
|
||||
// "osName": osinfo.GetKernelInfo()["Sysname"], // TODO is it necessary?
|
||||
// "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 get distrubition name also (pardus,arch,debian,windows10 for example ...)
|
||||
// TODO 'macAddresses': str(self.Hardware.Network.mac_addresses()).replace('[', '').replace(']', ''),
|
||||
// TODO 'hardware.systemDefinitions': self.Hardware.system_definitions(),
|
||||
// TODO 'hardware.monitors': self.Hardware.monitors(),
|
||||
// TODO 'hardware.screens': self.Hardware.screens(),
|
||||
// TODO 'hardware.usbDevices': self.Hardware.usb_devices(),
|
||||
// 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,
|
||||
}
|
||||
return data
|
||||
|
@ -61,23 +68,9 @@ func (g greeting) AgentInfo() map[string]interface{} {
|
|||
func Info() map[string]string {
|
||||
inf := make(map[string]string)
|
||||
inf["name"] = "resources"
|
||||
inf["version"] = "0.0.1"
|
||||
inf["version"] = "0.0.2"
|
||||
inf["support"] = "debian"
|
||||
inf["description"] = "Resource Usage Information and Controls"
|
||||
inf["developer"] = "asandikci@aliberksandikci.com.tr"
|
||||
|
||||
// inf["task"] = "true"
|
||||
// inf["user_oriented"] = "false"
|
||||
// inf["machine_oriented"] = "false"
|
||||
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