From abba1972d140cfdfdf658ea2bf5e8b73a09f8565 Mon Sep 17 00:00:00 2001 From: James Wells Date: Mon, 8 Nov 2021 06:58:55 -0800 Subject: [PATCH] Converted TCL list style and added hint parser. --- README.md | 2 +- assets/examples/hello-earth.tcl | 2 +- cmd/gagent/main.go | 82 +++++++++++++++++---------------- internal/client/client.go | 46 +++++++++++++++--- internal/gstructs/gstructs.go | 29 ++++++------ internal/setup/setup.go | 2 +- 6 files changed, 100 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index f8f2141..f97ed54 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Imagine, for a moment, that you are on Mars and need to perform a data search in 1 : ################### 2 : ### Hello Earth ### 3 : ################### -4 : array set GHINT ["thermal measurements" "gravity measurements" "gravity fluctuations"] +4 : set GHINT [split "thermal measurements, gravity measurements, gravity fluctuations" ,] 5 : proc hello_earth {} { 6 : puts "Hello Earth, does localized tempurature variations alter specific gravity?" 7 : } diff --git a/assets/examples/hello-earth.tcl b/assets/examples/hello-earth.tcl index 845fb0e..5a2d120 100644 --- a/assets/examples/hello-earth.tcl +++ b/assets/examples/hello-earth.tcl @@ -1,7 +1,7 @@ ################### ### Hello Earth ### ################### -array set GHINT ["thermal measurements" "gravity measurements" "gravity fluctuations"] +set GHINT [split "thermal measurements, gravity measurements, gravity fluctuations" ,] proc hello_earth {} { puts "Hello Earth, does localized tempurature variations alter specific gravity?" } diff --git a/cmd/gagent/main.go b/cmd/gagent/main.go index bc1fd5f..3736ac9 100644 --- a/cmd/gagent/main.go +++ b/cmd/gagent/main.go @@ -30,28 +30,31 @@ import ( ) var ( - semVER = "0.0.2" + semVER = "0.0.3" ) var ( wg sync.WaitGroup ) -var exitCodes = struct { - m map[string]int -}{m: map[string]int{}} +/* + * Exit Codes + * 0 Success + * 1 Configuration file is missing or unreadable + * 2 Setup failed + * 3 Invalid mode of operation + * 4 Agent file is missing or unreadable + * 5 Agent is missing tags + * 6 No routers defined + * 7 No workers defined + * 8 Agent not defined + * 9 Agent hints / tags not defined + * 10 Router not connected + */ var config gstructs.GagentConfig -var agent gstructs.AgentDetails func main() { - filter := &logutils.LevelFilter{ - Levels: []logutils.LogLevel{"DEBUG", "INFO", "WARN", "ERROR"}, - MinLevel: logutils.LogLevel("DEBUG"), - Writer: os.Stderr, - } - log.SetOutput(filter) - log.Printf("[DEBUG] Configuration is %v\n", config) switch config.Mode { @@ -60,7 +63,7 @@ func main() { if len(config.Routers) == 0 { log.Printf("[ERROR] No routers defined.\n") - os.Exit(exitCodes.m["NO_ROUTERS_DEFINED"]) + os.Exit(6) } wg.Add(1) @@ -71,7 +74,7 @@ func main() { if len(config.Workers) == 0 { log.Printf("[ERROR] No workers defined.\n") - os.Exit(exitCodes.m["NO_WORKERS_DEFINED"]) + os.Exit(7) } wg.Add(1) @@ -82,7 +85,7 @@ func main() { if len(config.Routers) == 0 { log.Printf("[ERROR] No routers defined.\n") - os.Exit(exitCodes.m["NO_ROUTERS_DEFINED"]) + os.Exit(6) } wg.Add(1) @@ -96,38 +99,27 @@ func main() { default: log.Printf("[ERROR] Unknown operating mode, exiting.\n") - os.Exit(exitCodes.m["INVALID_MODE"]) + os.Exit(3) } wg.Wait() - os.Exit(exitCodes.m["SUCCESS"]) + os.Exit(0) } func init() { - var err error + // var err error autorestart.StartWatcher() + filter := &logutils.LevelFilter{ + Levels: []logutils.LogLevel{"DEBUG", "INFO", "WARN", "ERROR"}, + MinLevel: logutils.LogLevel("DEBUG"), + Writer: os.Stderr, + } + log.SetOutput(filter) + http.Handle("/metrics", promhttp.Handler()) - /* - * Start Prometheus metrics exporter - */ - go http.ListenAndServe(fmt.Sprintf("%s:%d", config.ListenAddr, config.ClientPort), nil) - - /* - * Initialize the exit codes - */ - exitCodes.m["SUCCESS"] = 0 - exitCodes.m["INVALID_MODE"] = 1 - exitCodes.m["CONFIG_FILE_MISSING"] = 2 - exitCodes.m["NO_ROUTERS_DEFINED"] = 3 - exitCodes.m["NO_WORKERS_DEFINED"] = 4 - exitCodes.m["AGENT_NOT_DEFINED"] = 5 - exitCodes.m["AGENT_LOAD_FAILED"] = 6 - exitCodes.m["AGENT_MISSING_TAGS"] = 7 - exitCodes.m["AGENT_NOT_DEFINED"] = 8 - /* * Initialize the configuration */ @@ -152,6 +144,12 @@ func init() { */ config.ListenAddr = "0.0.0.0" + /* + * By default, G'Agent will use port 9101 or monitoring via prometheus. + * It can be overridden in the configuration file by setting clientport + */ + config.MonitorPort = 9101 + /* * By default, G'Agent client will use port 35571 to communicate with the * routers, but you can override it by setting the clientport in the @@ -223,10 +221,10 @@ func init() { config.File = opts["--config"].(string) } - err = hclsimple.DecodeFile(config.File, nil, &config) + err := hclsimple.DecodeFile(config.File, nil, &config) if err != nil && opts["setup"] == false { log.Printf("[ERROR] Failed to load configuration file: %s.\n", config.File) - os.Exit(exitCodes.m["CONFIG_FILE_MISSING"]) + os.Exit(1) } /* @@ -239,7 +237,7 @@ func init() { config.Mode = "client" if opts["--agent"] == nil { log.Printf("[ERROR] Agent file not specified") - os.Exit(exitCodes.m["AGENT_NOT_DEFINED"]) + os.Exit(8) } else { config.File = opts["--agent"].(string) } @@ -263,4 +261,10 @@ func init() { } log.Printf("[DEBUG] Config is %v\n", config) + + /* + * Start Prometheus metrics exporter + */ + go http.ListenAndServe(fmt.Sprintf("%s:%d", config.ListenAddr, config.MonitorPort), nil) + } diff --git a/internal/client/client.go b/internal/client/client.go index c6c2435..d069837 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -6,6 +6,8 @@ import ( ioutil "io/ioutil" log "log" os "os" + regexp "regexp" + strings "strings" sync "sync" time "time" @@ -32,12 +34,14 @@ func Main(wg *sync.WaitGroup, config gstructs.GagentConfig) { agent.ScriptCode, err = ioutil.ReadFile(config.File) if err != nil { log.Printf("[ERROR] No such file or directory: %s", config.File) - os.Exit(6) + os.Exit(4) } agent.Shasum = fmt.Sprintf("%x", sha.Sum256(agent.ScriptCode)) agent.Status = "loaded" - log.Printf("[DEBUG] SHA256 of Agent file: %s", agent.Shasum) + log.Printf("[INFO] SHA256 of Agent file: %s", agent.Shasum) + log.Printf("[DEBUG] Agent file contents: \n%s\n", agent.ScriptCode) } + agent.Hints = getTagsFromHints(agent) for key := range config.Routers { /* @@ -51,12 +55,27 @@ func Main(wg *sync.WaitGroup, config gstructs.GagentConfig) { wg.Add(1) go sendAgent(wg, config.UUID, connectString, agent.ScriptCode) - time.Sleep(10 * time.Millisecond) } } +/* + * Parse Agent file for GHINT data to populate the G'Agent hints + */ +func getTagsFromHints(agent gstructs.AgentDetails) []string { + var tags []string + re := regexp.MustCompile(`\s*set\s+GHINT\s*\[\s*split\s*"(?P.+)"\s*\,\s*\]`) + res := re.FindStringSubmatch(string(agent.ScriptCode)) + if len(res) < 1 { + log.Printf("[ERROR] Agent is missing GHINT tags") + os.Exit(4) + } + tags = strings.Split(res[1], ",") + log.Printf("[DEBUG] G'Agent hints: %v\n", tags) + + return tags +} + func sendAgent(wg *sync.WaitGroup, uuid string, connectString string, agent []byte) { - log.Printf("[DEBUG] Attempting to connect to %s\n", connectString) defer wg.Done() var mu sync.Mutex @@ -66,10 +85,23 @@ func sendAgent(wg *sync.WaitGroup, uuid string, connectString string, agent []by defer sock.Close() sock.SetIdentity(uuid) - sock.Connect(connectString) + + log.Printf("[DEBUG] Attempting to connect to %s\n", connectString) + err := sock.Connect(connectString) + if err != nil { + log.Printf("[ERROR] Failed to connect to %s\n", connectString) + os.Exit(10) + } log.Printf("[DEBUG] Start sending agent...\n") - sock.SendMessage(agent) - log.Printf("[DEBUG] End sending agent...\n") + status, err := sock.SendMessage(agent) + if err != nil { + log.Printf("[ERROR] Failed to send agent to router\n") + // os.Exit(11) + return + } + log.Printf("[DEBUG] Agent send status: %d\n", status) mu.Unlock() + time.Sleep(10 * time.Second) + } diff --git a/internal/gstructs/gstructs.go b/internal/gstructs/gstructs.go index a73bc63..a626c34 100644 --- a/internal/gstructs/gstructs.go +++ b/internal/gstructs/gstructs.go @@ -2,19 +2,20 @@ package gstructs // GagentConfig is the primary construct used by all modes type GagentConfig struct { - Name string `hcl:"name,optional"` - Mode string `hcl:"mode,attr"` - UUID string `hcl:"uuid,optional"` - ListenAddr string `hcl:"listenaddr,optional"` - ClientPort int64 `hcl:"clientport,optional"` - RouterPort int64 `hcl:"routerport,optional"` - WorkerPort int64 `hcl:"workerport,optional"` - Clients []*ClientDetails `hcl:"client,block"` - Routers []*RouterDetails `hcl:"router,block"` - Workers []*WorkerDetails `hcl:"worker,block"` - Version string - File string - CMode bool + Name string `hcl:"name,optional"` + Mode string `hcl:"mode,attr"` + UUID string `hcl:"uuid,optional"` + MonitorPort int `hcl:"monitorport,optional"` + ListenAddr string `hcl:"listenaddr,optional"` + ClientPort int64 `hcl:"clientport,optional"` + RouterPort int64 `hcl:"routerport,optional"` + WorkerPort int64 `hcl:"workerport,optional"` + Clients []*ClientDetails `hcl:"client,block"` + Routers []*RouterDetails `hcl:"router,block"` + Workers []*WorkerDetails `hcl:"worker,block"` + Version string + File string + CMode bool } /* @@ -127,5 +128,5 @@ type AgentDetails struct { Shasum string `hcl:"shasum"` Status string `hcl:"status"` ScriptCode []byte - Hints []*string + Hints []string } diff --git a/internal/setup/setup.go b/internal/setup/setup.go index 8c3357d..f4af155 100644 --- a/internal/setup/setup.go +++ b/internal/setup/setup.go @@ -12,7 +12,7 @@ import ( ) func Main(wg *sync.WaitGroup, config gs.GagentConfig) { - log.Printf("[INFO] setup mode\n") + log.Printf("[INFO] Starting setup\n") defer wg.Done() f := hclwrite.NewEmptyFile()