diff --git a/.gitignore b/.gitignore index 831eb91..579280b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,4 @@ go.work # Go temporary test files -**/plugins/tmptest/** \ No newline at end of file +# **/plugins/tmptest/** \ No newline at end of file diff --git a/Makefile b/Makefile index 8b61679..a84fa1e 100644 --- a/Makefile +++ b/Makefile @@ -23,18 +23,18 @@ preclean: sudo rm -rf /usr/bin/${OLD_DAEMON_NAME} sudo rm -rf /usr/bin/${PYTHON_DAEMON_NAME} - @# TODO systemd control for both three process for docker - @# REVIEW are both killall and systemctl commands running? - @pgrep -x ${DAEMON_NAME} && (sudo killall "${DAEMON_NAME}" || sudo systemctl disable "${DAEMON_NAME}" || sudo systemctl stop "${DAEMON_NAME}") || echo "no ${DAEMON_NAME} found" - @pgrep -x ${OLD_DAEMON_NAME} && (sudo killall "${OLD_DAEMON_NAME}" || sudo systemctl disable "${OLD_DAEMON_NAME}" || sudo systemctl stop "${OLD_DAEMON_NAME}") || echo "no ${OLD_DAEMON_NAME} found" + # @# TODO systemd control for both three process for docker + # @# REVIEW are both killall and systemctl commands running? + # @pgrep -x ${DAEMON_NAME} && (sudo killall "${DAEMON_NAME}" || sudo systemctl disable "${DAEMON_NAME}" || sudo systemctl stop "${DAEMON_NAME}") || echo "no ${DAEMON_NAME} found" + # @pgrep -x ${OLD_DAEMON_NAME} && (sudo killall "${OLD_DAEMON_NAME}" || sudo systemctl disable "${OLD_DAEMON_NAME}" || sudo systemctl stop "${OLD_DAEMON_NAME}") || echo "no ${OLD_DAEMON_NAME} found" - @# TODO - @# echo -e "Do you want to remove python implementation of ahenk if installed in system?" - @# read -rp "(Y/N) " input + # @# TODO + # @# echo -e "Do you want to remove python implementation of ahenk if installed in system?" + # @# read -rp "(Y/N) " input - @pgrep -x ${PYTHON_DAEMON_NAME} && (sudo killall "${PYTHON_DAEMON_NAME}" || sudo systemctl disable "${PYTHON_DAEMON_NAME}" || sudo systemctl stop "${PYTHON_DAEMON_NAME}") || echo "no ${PYTHON_DAEMON_NAME} found" + # @pgrep -x ${PYTHON_DAEMON_NAME} && (sudo killall "${PYTHON_DAEMON_NAME}" || sudo systemctl disable "${PYTHON_DAEMON_NAME}" || sudo systemctl stop "${PYTHON_DAEMON_NAME}") || echo "no ${PYTHON_DAEMON_NAME} found" - sudo systemctl daemon-reload + # sudo systemctl daemon-reload sudo rm -rf ${DATA_DIR} @echo -e "PRE-CLENING DONE\n" test: @@ -48,6 +48,13 @@ install: sudo go build -buildmode=plugin -o ${DESTDIR}/${PLUGIN_DIR}/tmptest.so ./plugins/tmptest @sudo mkdir -p "${DESTDIR}/${DATA_DIR}" +linux_goloader_install: + sudo go build -o ${DESTDIR}/usr/bin/${REPO_NAME} ./cmd/ahenk-go/ + + @sudo mkdir -p "${DESTDIR}/${DATA_DIR}" + sudo cp -r ./plugins "${DESTDIR}/${DATA_DIR}/" + + windows_install: sudo env GOOS=windows GOARCH=amd64 go build -o ${DESTDIR}/usr/bin/${REPO_NAME} ./cmd/ahenk-go/ @sudo mkdir -p "${DESTDIR}/${LIB_DIR}" diff --git a/cmd/ahenk-go/main.go b/cmd/ahenk-go/ahenk-go.go similarity index 59% rename from cmd/ahenk-go/main.go rename to cmd/ahenk-go/ahenk-go.go index cc2e7cc..4bfdf17 100644 --- a/cmd/ahenk-go/main.go +++ b/cmd/ahenk-go/ahenk-go.go @@ -5,33 +5,29 @@ import ( "os" "os/user" + "git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/confdir" + "git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/pluginmanager" "git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/utils" "github.com/sevlyar/go-daemon" "golang.org/x/exp/slices" ) -const PidFile = "/run/ahenk-go.pid" -const ExecutablePath = "/usr/bin/ahenk-go" -const DataDir = "/etc/ahenk-go/" -const LogFile = DataDir + "ahenk.log" -const LibDir = "/usr/share/ahenk-go/" -const PluginDir = LibDir + "/plugins/" - // Main Function that starts daemon and controls arguments func main() { + confdir.GetPaths() 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) + utils.CreatePath(confdir.Paths.Data) cntxt := &daemon.Context{ - PidFileName: PidFile, + PidFileName: confdir.Paths.Pid, PidFilePerm: 0644, - LogFileName: LogFile, + LogFileName: confdir.Paths.Logs + "main.log", LogFilePerm: 0640, - WorkDir: LibDir, + WorkDir: confdir.Paths.Data, Umask: 027, - Args: []string{ExecutablePath, "start"}, + Args: []string{confdir.Paths.Program, "start"}, } d, err := cntxt.Reborn() if err != nil { @@ -44,22 +40,27 @@ func main() { log.Println("- - - - - - - - - - - - - - - - - -") log.Print("Daemon Succesfully Started") case "stop": - i, _ := daemon.ReadPidFile(PidFile) + i, _ := daemon.ReadPidFile(confdir.Paths.Pid) Stop(i, 15) case "restart": - i, _ := daemon.ReadPidFile(PidFile) + i, _ := daemon.ReadPidFile(confdir.Paths.Pid) Restart(i, 15) case "nodaemon": log.Print("STARTED AS NO-DAEMON") - f := utils.OpenLogFile(LogFile) + f := utils.OpenLogFile(confdir.Paths.Logs + "main.log") defer f.Close() log.SetOutput(f) // TODO Also pipe fmt.Print* commands case "tmptest": log.Print("TEMPORARY TEST STARTED, log files are NOT redirecting!") - PluginManager("tmptest") + plugFunctions := map[string][]string{ + "tmptest": {"TmpTest"}, + "resources": {"AhenkInfo", "ResourceUsage"}, + } + pluginmanager.StartPlugins(plugFunctions) + } } else { panic("Please enter a valid option !") @@ -73,6 +74,8 @@ func main() { log.Fatal("Ahenk-go requires superuser privilege") } - PluginManager() - // NEXT Make PluginManager async ! + // plugFunctions := map[string][]string{ + // "resources": {"AhenkInfo", "ResourceUsage"}, + // } + // pluginmanager.StartPlugins(plugFunctions) } diff --git a/cmd/ahenk-go/main_linux.go b/cmd/ahenk-go/ahenk-go_linux.go similarity index 88% rename from cmd/ahenk-go/main_linux.go rename to cmd/ahenk-go/ahenk-go_linux.go index 07b70c1..dfbf7c5 100644 --- a/cmd/ahenk-go/main_linux.go +++ b/cmd/ahenk-go/ahenk-go_linux.go @@ -7,6 +7,7 @@ import ( "os" "syscall" + "git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/confdir" "git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/utils" ) @@ -25,7 +26,7 @@ func Stop(pid, signal int) { 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) + f := utils.OpenLogFile(confdir.Paths.Logs + "main.log") defer f.Close() log.SetOutput(f) log.Printf("Ahenk Daemon with pid number %v Successfully stopped", pid) diff --git a/cmd/ahenk-go/main_windows.go b/cmd/ahenk-go/ahenk-go_windows.go similarity index 100% rename from cmd/ahenk-go/main_windows.go rename to cmd/ahenk-go/ahenk-go_windows.go diff --git a/cmd/ahenk-go/plugin-manager.go b/cmd/ahenk-go/plugin-manager.go deleted file mode 100644 index cc2cc20..0000000 --- a/cmd/ahenk-go/plugin-manager.go +++ /dev/null @@ -1,103 +0,0 @@ -package main - -import ( - "encoding/json" - "log" - "time" - - "git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/utils" -) - -// General Functions/Methods that each plugin has -type PlugGeneral interface { - Info() map[string]interface{} -} - -// plugins/resources -type Resources interface { - AgentInfo() map[string]interface{} - ResourceUsage() map[string]interface{} -} - -// plugins/resources -type TmpTest interface { - TmpTest() -} - -// FILLME creating new plugin interface, template -// type NewPluginInterface interface { -// PluginMethod() returnType -// } - -// Loads Plugins and runs them concurrently. -// When you create a new plugin create a new interface and call this plugin in this function -func PluginManager(params ...string) { - chanPlug := make(chan interface{}) - - go LoadPlugin("resources", chanPlug) - res, ok := <-chanPlug - var resources Resources = res.(Resources) - checkPlugin(resources, ok) - - if len(params) > 0 && params[0] == "tmptest" { - go LoadPlugin("tmptest", chanPlug) - res, ok := <-chanPlug - var tmptest TmpTest = res.(TmpTest) - checkPlugin(res, ok) - tmptest.TmpTest() - } - - // FILLME Loading new plugin, template - // go LoadPlugin("pluginName", chanPlug) - // res, ok = <-chanPlug - // var pluginName NewPluginInterface = res.(NewPluginInterface) - // checkPlugin(res, ok) - - // Run plugins concurrently and log out - go logPlugin("AgentInfo", resources.AgentInfo(), true) - for { - go logPlugin("ResourceUsage", resources.ResourceUsage(), true) - - // FILLME Running/Log out a plugin, template - // go logPlugin("InfoAboutFunction", pluginName.Function(), true) - - time.Sleep(30 * time.Second) - } -} - -// Logs plugin outputs. -func logPlugin(title string, mp map[string]interface{}, toJson bool) { - log.Printf("\n----- %v -----\n", title) - if toJson { - data, err := json.MarshalIndent(&mp, "", " ") - utils.Check(err) - log.Println(string(data)) - } else { - for i, v := range mp { - log.Printf("%v: %v\n", i, v) - } - } -} - -// Checks plugin status -func checkPlugin(plugVal interface{}, status bool) { - if status { - if plugVal == nil { - log.Fatal("Plugin loaded but there is no value!") - } else { - plugInfo := plugVal.(PlugGeneral).Info() - log.Printf("Plugin \"%v\" loaded and ready to use, version \"%v\" ", plugInfo["name"], plugInfo["version"]) - } - } else { - if plugVal == nil { - log.Fatal("Plugin closed and there is no value! ") - } else { - log.Fatal("Plugin closed or there is an error") - } - } -} - -// // TODO response to Lider -// // func createResponse() { - -// // } diff --git a/cmd/ahenk-go/plugin-opener.go b/cmd/ahenk-go/plugin-opener.go deleted file mode 100644 index 1a9604e..0000000 --- a/cmd/ahenk-go/plugin-opener.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "fmt" - "os" - "plugin" - - "git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/utils" -) - -// Load Plugin placed in PluginDir, returns empty interface with channel -// 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, chn chan interface{}) { - - // 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 - symPlug, err := plug.Lookup(utils.FirstUpperEN(plugName) + "Connect") - utils.Check(err) - - var plugOut interface{} - plugOut, ok := symPlug.(interface{}) - if !ok { - fmt.Println("unexpected type from module symbol") - os.Exit(1) - } - chn <- plugOut -} - -// NEXT implement unload function -// func UnloadPlugin(plugName string) interface{} { - -// } diff --git a/go.mod b/go.mod index e569f23..9901325 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( ) require ( + github.com/eh-steve/goloader v0.0.0-20230730231803-5c95d7a5f4e2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/stretchr/testify v1.8.4 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect @@ -18,6 +19,7 @@ require ( ) require ( + github.com/eh-steve/goloader/jit v0.0.0-20230731163325-b789213e8550 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // direct golang.org/x/sys v0.11.0 // direct diff --git a/go.sum b/go.sum index 4fe0a6e..bab0633 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/eh-steve/goloader v0.0.0-20230730231803-5c95d7a5f4e2 h1:0mZ2Y8x4dhPfm9eOlbzBx31YSLaECdPvKEBrL5Hc0YE= +github.com/eh-steve/goloader v0.0.0-20230730231803-5c95d7a5f4e2/go.mod h1:k7xs3CUwCvOU9aw851I6AEb6ZzZJ3nos5dZ6A/2ewM0= +github.com/eh-steve/goloader/jit v0.0.0-20230731163325-b789213e8550 h1:clY7T47fFZdFcILcu7uksS7FStRaKMssCYGW0l/AoMo= +github.com/eh-steve/goloader/jit v0.0.0-20230731163325-b789213e8550/go.mod h1:p18VKcPYO8oWGYcQt/K5EGIGqak0ZT5HwVirGpUGZBg= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..3aa05fa --- /dev/null +++ b/go.work.sum @@ -0,0 +1,4 @@ +github.com/eh-steve/goloader/jit/testdata v0.0.0-20230730231803-5c95d7a5f4e2/go.mod h1:GyUY1mfY7NCdoVRo5H8+kmhLa/xE418ZcjfDfgwicXw= +github.com/eh-steve/goloader/unload v0.0.0-20230730231803-5c95d7a5f4e2/go.mod h1:bA/aiceMvuZh45HAA/xzWJKT4E9EXqzmuPsB9yT/D/M= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/pkg/confdir/confdir.go b/pkg/confdir/confdir.go new file mode 100644 index 0000000..247dc0d --- /dev/null +++ b/pkg/confdir/confdir.go @@ -0,0 +1,16 @@ +package confdir + +type Path struct { + Program string `json:"Program"` + UserConfig string `json:"User Config"` + Data string `json:"Data"` + Plugins string `json:"Plugins"` + Logs string `json:"Logs"` + Pid string `json:"pid"` +} + +var Paths Path + +func GetPaths() { + Paths = getPaths() +} diff --git a/pkg/confdir/confdir_linux.go b/pkg/confdir/confdir_linux.go new file mode 100644 index 0000000..8f97ba9 --- /dev/null +++ b/pkg/confdir/confdir_linux.go @@ -0,0 +1,16 @@ +//go:build linux && !windows + +package confdir + +import "os" + +func getPaths() Path { + var path Path + path.Program = "/usr/bin/ahenk-go" + path.UserConfig, _ = os.UserConfigDir() + path.Data = "/etc/ahenk-go/" + path.Plugins = path.Data + "plugins/" + path.Logs = path.Data + "logs/" + path.Pid = "/run/ahenk-go.pid" + return path +} diff --git a/pkg/confdir/confdir_windows.go b/pkg/confdir/confdir_windows.go new file mode 100644 index 0000000..507b9db --- /dev/null +++ b/pkg/confdir/confdir_windows.go @@ -0,0 +1,16 @@ +//go:build windows + +package confdir + +import "os" + +func getPaths() Path { + var path Path + path.Program = "TODO" + path.UserConfig, _ = os.UserConfigDir() + path.Data = "TODO" + path.Plugins = path.Data + "plugins/" + path.Logs = path.Data + "logs/" + path.Pid = "TODO" + return path +} diff --git a/pkg/confdir/go.mod b/pkg/confdir/go.mod new file mode 100644 index 0000000..654335c --- /dev/null +++ b/pkg/confdir/go.mod @@ -0,0 +1,3 @@ +module git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/confdir + +go 1.21.0 diff --git a/pkg/pluginmanager/go.mod b/pkg/pluginmanager/go.mod new file mode 100644 index 0000000..2d66bb9 --- /dev/null +++ b/pkg/pluginmanager/go.mod @@ -0,0 +1,7 @@ +module git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/pluginmanager + +go 1.21.0 + +require github.com/eh-steve/goloader/jit v0.0.0-20230731163325-b789213e8550 + +require github.com/eh-steve/goloader v0.0.0-20230730231803-5c95d7a5f4e2 // indirect diff --git a/pkg/pluginmanager/go.sum b/pkg/pluginmanager/go.sum new file mode 100644 index 0000000..7b3dda3 --- /dev/null +++ b/pkg/pluginmanager/go.sum @@ -0,0 +1,4 @@ +github.com/eh-steve/goloader v0.0.0-20230730231803-5c95d7a5f4e2 h1:0mZ2Y8x4dhPfm9eOlbzBx31YSLaECdPvKEBrL5Hc0YE= +github.com/eh-steve/goloader v0.0.0-20230730231803-5c95d7a5f4e2/go.mod h1:k7xs3CUwCvOU9aw851I6AEb6ZzZJ3nos5dZ6A/2ewM0= +github.com/eh-steve/goloader/jit v0.0.0-20230731163325-b789213e8550 h1:clY7T47fFZdFcILcu7uksS7FStRaKMssCYGW0l/AoMo= +github.com/eh-steve/goloader/jit v0.0.0-20230731163325-b789213e8550/go.mod h1:p18VKcPYO8oWGYcQt/K5EGIGqak0ZT5HwVirGpUGZBg= diff --git a/pkg/pluginmanager/jitconf_linux.go b/pkg/pluginmanager/jitconf_linux.go new file mode 100644 index 0000000..2690bc4 --- /dev/null +++ b/pkg/pluginmanager/jitconf_linux.go @@ -0,0 +1,15 @@ +//go:build linux && !windows + +package pluginmanager + +import "github.com/eh-steve/goloader/jit" + +func getJITConf() jit.BuildConfig { + return jit.BuildConfig{ + KeepTempFiles: true, // Files are copied/written to a temp dir to ensure it is writable. This retains the temporary copies + ExtraBuildFlags: []string{"-x"}, // Flags passed to go build command + BuildEnv: []string{"GOOS=linux"}, // Env vars to set for go build toolchain + TmpDir: "", // To control where temporary files are copied + DebugLog: false, // + } +} diff --git a/pkg/pluginmanager/jitconf_windows.go b/pkg/pluginmanager/jitconf_windows.go new file mode 100644 index 0000000..a18aa18 --- /dev/null +++ b/pkg/pluginmanager/jitconf_windows.go @@ -0,0 +1,15 @@ +//go:build windows + +package pluginmanager + +import "github.com/eh-steve/goloader/jit" + +func getJITConf() jit.BuildConfig { + return jit.BuildConfig{ + KeepTempFiles: true, // Files are copied/written to a temp dir to ensure it is writable. This retains the temporary copies + ExtraBuildFlags: []string{"-x"}, // Flags passed to go build command + BuildEnv: []string{"GOOS=windows"}, // Env vars to set for go build toolchain + TmpDir: "", // To control where temporary files are copied + DebugLog: true, // + } +} diff --git a/pkg/pluginmanager/pluginmanager.go b/pkg/pluginmanager/pluginmanager.go new file mode 100644 index 0000000..9c77b3d --- /dev/null +++ b/pkg/pluginmanager/pluginmanager.go @@ -0,0 +1,132 @@ +package pluginmanager + +import "fmt" + +// General Functions/Methods that each plugin has +type PlugGeneral interface { + Info() (interface{}, error) +} + +// plugins/resources +type Resources interface { + AgentInfo() (interface{}, error) + ResourceUsage() (interface{}, error) +} + +type TmpTest interface { + TmpTest() (interface{}, error) +} + +type anny any + +// Start All plugins +func StartPlugins(params map[string][]string) { + // GeneralFunctions := []string{"Info"} + + conf := getJITConf() + chanPlug := make(chan PluginStruct) + + // var myint TmpTest + + // for i, v := range params { + // v := append(v, GeneralFunctions...) + // go LoadPlugin2(i, v, conf, chanPlug) + // } + + go LoadPlugin3("tmptest", conf, chanPlug) + a, ok := <-chanPlug + var an anny = a + fmt.Println(a, ok) + fmt.Println(an) + var aa []func() (interface{}, error) + for _, v := range a.Functions { + aa = append(aa, v) + } + fmt.Println(aa) + var loo interface{} = aa + fmt.Println(loo.(TmpTest)) +} + +// +// ------------------------- +// OLD PLUGIN IMPLEMENTATION +// ------------------------- +// + +// // FILLME creating new plugin interface, template +// // type NewPluginInterface interface { +// // PluginMethod() returnType +// // } + +// Loads Plugins and runs them concurrently. +// When you create a new plugin create a new interface and call this plugin in this function +// func PluginManager(params ...string) { +// chanPlug := make(chan interface{}) + +// go LoadPlugin("resources", chanPlug) +// res, ok := <-chanPlug +// var resources Resources = res.(Resources) +// checkPlugin(resources, ok) + +// if len(params) > 0 && params[0] == "tmptest" { +// go LoadPlugin("tmptest", chanPlug) +// res, ok := <-chanPlug +// var tmptest TmpTest = res.(TmpTest) +// checkPlugin(res, ok) +// tmptest.TmpTest() +// } + +// // FILLME Loading new plugin, template +// // go LoadPlugin("pluginName", chanPlug) +// // res, ok = <-chanPlug +// // var pluginName NewPluginInterface = res.(NewPluginInterface) +// // checkPlugin(res, ok) + +// // Run plugins concurrently and log out +// go logPlugin("AgentInfo", resources.AgentInfo(), true) +// for { +// go logPlugin("ResourceUsage", resources.ResourceUsage(), true) + +// // FILLME Running/Log out a plugin, template +// // go logPlugin("InfoAboutFunction", pluginName.Function(), true) + +// time.Sleep(30 * time.Second) +// } +// } + +// // Logs plugin outputs. +// func logPlugin(title string, mp map[string]interface{}, toJson bool) { +// log.Printf("\n----- %v -----\n", title) +// if toJson { +// data, err := json.MarshalIndent(&mp, "", " ") +// utils.Check(err) +// log.Println(string(data)) +// } else { +// for i, v := range mp { +// log.Printf("%v: %v\n", i, v) +// } +// } +// } + +// // Checks plugin status +// func checkPlugin(plugVal interface{}, status bool) { +// if status { +// if plugVal == nil { +// log.Fatal("Plugin loaded but there is no value!") +// } else { +// plugInfo, _ := plugVal.(PlugGeneral).Info() +// log.Printf("Plugin \"%v\" loaded and ready to use, version \"%v\" ", plugInfo["name"], plugInfo["version"]) +// } +// } else { +// if plugVal == nil { +// log.Fatal("Plugin closed and there is no value! ") +// } else { +// log.Fatal("Plugin closed or there is an error") +// } +// } +// } + +// // // TODO response to Lider +// // // func createResponse() { + +// // // } diff --git a/pkg/pluginmanager/pluginopener.go b/pkg/pluginmanager/pluginopener.go new file mode 100644 index 0000000..2516c85 --- /dev/null +++ b/pkg/pluginmanager/pluginopener.go @@ -0,0 +1,140 @@ +package pluginmanager + +import ( + "fmt" + "os" + "plugin" + + "git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/confdir" + "git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/utils" + "github.com/eh-steve/goloader/jit" +) + +// type mytype func() (interface{}, error) + +type PluginStruct struct { + PluginFunction map[string]interface{} + Functions map[string](func() (interface{}, error)) +} + +func LoadPlugin3(plugName string, conf jit.BuildConfig, chn chan PluginStruct) { + loadable, err := jit.BuildGoPackage(conf, confdir.Paths.Plugins+plugName+"/") + utils.Check(err) + module, err := loadable.Load() + utils.Check(err) + plugSymbols := module.SymbolsByPkg[loadable.ImportPath] + + // fmt.Println(*deneme, *deneme2) + + // var empt interface{} = plugSymbols + // a = empt.(TmpTest) + + // var a TmpTest + // jit.RegisterTypes(plugSymbols["TmpTest"]) + var plugMan PluginStruct + plugMan.PluginFunction = plugSymbols + fmt.Println(plugMan.PluginFunction) + plugMan.Functions = make(map[string](func() (interface{}, error))) + for i, v := range plugMan.PluginFunction { + switch f := v.(type) { + case func([]byte) (interface{}, error): + result, err := f([]byte(`{"k":"v"}`)) + if err != nil { + panic(err) + } + fmt.Println(result) + case func() (interface{}, error): + fmt.Println(i, 1) + plugMan.Functions[i] = f + default: + fmt.Println(f) + panic("Function signature was not what was expected") + } + } + fmt.Println(plugMan.Functions) + for i, o := range plugMan.Functions { + // fmt.Println(i, o) + fmt.Println(i, &o) + // fmt.Println(i, *o) + } + // plugMan.Functions["TmpTest"]() + fmt.Println(1) + chn <- plugMan + // var empt mytype = plugSymbols["TmpTest"].(mytype) + + // a := empt.(TmpTest) + // fmt.Println(empt) + + // switch f := plugSymbols["MyFunc"].(type) { + // case func([]byte) (interface{}, error): + // result, err := f([]byte(`{"k":"v"}`)) + // if err != nil { + // panic(err) + // } + // fmt.Println(result) + // default: + // fmt.Println(f) + // panic("Function signature was not what was expected") + // } + + // chn <- deneme +} + +// func LoadPlugin2(plugName string, plugFunction []string, conf jit.BuildConfig, chn chan interface{}) { + +// loadable, err := jit.BuildGoPackage(conf, confdir.Paths.Plugins+plugName+"/") +// utils.Check(err) + +// module, err := loadable.Load() + +// plugSymbols := module.SymbolsByPkg[loadable.ImportPath] +// utils.Check(err) + +// for i, v := range plugFunction { +// var f interface{} = plugSymbols + +// } + +// // switch f := plugSymbols["MyFunc"].(type) { +// // case func([]byte) (interface{}, error): +// // result, err := f([]byte(`{"k":"v"}`)) +// // if err != nil { +// // panic(err) +// // } +// // fmt.Println(result) +// // default: +// // fmt.Println(f) +// // panic("Function signature was not what was expected") +// // } + +// // chn <- +// } + +// +// ------------------------- +// OLD PLUGIN IMPLEMENTATION +// ------------------------- +// + +// Load Plugin placed in PluginDir, returns empty interface with channel +// 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, chn chan interface{}) { + + // TODO if error caugth try without relative path, this will be good for local testing + plug, err := plugin.Open(confdir.Paths.Plugins + plugName + ".so") + utils.Check(err) + + // TODO also allow lookup another symbol other than PlugnameConnect + symPlug, err := plug.Lookup(utils.FirstUpperEN(plugName) + "Connect") + utils.Check(err) + + var plugOut interface{} + plugOut, ok := symPlug.(interface{}) + if !ok { + fmt.Println("unexpected type from module symbol") + os.Exit(1) + } + chn <- plugOut +} diff --git a/plugins/resources/go.mod b/plugins/resources/go.mod new file mode 100644 index 0000000..137add4 --- /dev/null +++ b/plugins/resources/go.mod @@ -0,0 +1,19 @@ +module git.aliberksandikci.com.tr/Liderahenk/ahenk-go/plugins/resources + +go 1.21.0 + +require git.aliberksandikci.com.tr/Liderahenk/ahenk-go v0.0.0-20230831165035-c1bc30d83082 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect + github.com/zcalusic/sysinfo v1.0.1 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/plugins/resources/go.sum b/plugins/resources/go.sum new file mode 100644 index 0000000..98031b2 --- /dev/null +++ b/plugins/resources/go.sum @@ -0,0 +1,29 @@ +git.aliberksandikci.com.tr/Liderahenk/ahenk-go v0.0.0-20230831165035-c1bc30d83082 h1:xSuQQVwNcORPGt23VKivLIhOipz0hx9e5evxxiyV/No= +git.aliberksandikci.com.tr/Liderahenk/ahenk-go v0.0.0-20230831165035-c1bc30d83082/go.mod h1:CsfyC8E2IhrkmUf84/GvIDaofgSxtYdw3lojgQ8YMYc= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zcalusic/sysinfo v1.0.1 h1:cVh8q3codjh43AGRTa54dJ2Zq+qPejv8n2VWpxKViwc= +github.com/zcalusic/sysinfo v1.0.1/go.mod h1:LxwKwtQdbTIQc65drhjQzYzt0o7jfB80LrrZm7SWn8o= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.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= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/plugins/resources/info.go b/plugins/resources/info.go index b58dec1..d6c6574 100644 --- a/plugins/resources/info.go +++ b/plugins/resources/info.go @@ -1,6 +1,6 @@ -package main +package resources -func (p plug) Info() map[string]interface{} { +func Info() (interface{}, error) { return map[string]interface{}{ "name": "resources", "version": "0.1.0", @@ -10,5 +10,5 @@ func (p plug) Info() map[string]interface{} { }, "description": "Resource Usage Information and Controls", "developer": "asandikci@aliberksandikci.com.tr", - } + }, nil } diff --git a/plugins/resources/main.go b/plugins/resources/main.go index ec64da3..e3a0f0d 100644 --- a/plugins/resources/main.go +++ b/plugins/resources/main.go @@ -1,4 +1,4 @@ -package main +package resources import ( "runtime" @@ -6,13 +6,8 @@ import ( "git.aliberksandikci.com.tr/Liderahenk/ahenk-go/pkg/osinfo" ) -type plug string - -// exported plugin Symbol -var ResourcesConnect plug - // return instant resource usage information -func (p plug) ResourceUsage() map[string]interface{} { +func ResourceUsage() (interface{}, error) { var system osinfo.System system.GetSystemInfo() @@ -35,13 +30,13 @@ func (p plug) ResourceUsage() map[string]interface{} { } // TODO see https://github.com/Pardus-LiderAhenk/ahenk/blob/master/src/plugins/resource-usage/resource_info_fetcher.py - return data + return data, nil } // return general Agent system information // // these values changes rarely, see ResourceUsage() function for instant resource usage information -func (p plug) AgentInfo() map[string]interface{} { +func AgentInfo() (interface{}, error) { var system osinfo.System system.GetSystemInfo() @@ -63,5 +58,5 @@ func (p plug) AgentInfo() map[string]interface{} { // REVIEW is calling all functions one by one slow downs code? // TODO see https://github.com/Pardus-LiderAhenk/ahenk/blob/master/src/plugins/resource-usage/agent_info.py - return data + return data, nil } diff --git a/plugins/tmptest/go.mod b/plugins/tmptest/go.mod new file mode 100644 index 0000000..1543b3d --- /dev/null +++ b/plugins/tmptest/go.mod @@ -0,0 +1,3 @@ +module git.aliberksandikci.com.tr/Liderahenk/ahenk-go/plugins/tmptest + +go 1.21.0