From 168e0ba7a0cb516c36d194cbcee5713ee1756001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Di=20Domenico?= Date: Mon, 23 May 2022 11:52:11 +0200 Subject: [PATCH] Make paths to files configurable (#5) * Add 'paths' to config struct * Update test configs * Implement new paths config entry * Set default paths * Make defaults setting nicer * Rename paths structure and move logfile out of it * Move default paths to config package * Create binpaths struct if non-existent --- .../goslmailer.conf.annotated_example | 4 ++++ cmd/goslmailer/goslmailer.go | 2 +- internal/config/config.go | 18 +++++++++++++++++ internal/slurmjob/getjobcontext.go | 8 ++++---- internal/slurmjob/sacct.go | 20 +++++++++---------- test_data/config_test/gobler.conf | 6 +++++- test_data/config_test/goslmailer.conf | 6 +++++- 7 files changed, 47 insertions(+), 17 deletions(-) diff --git a/cmd/goslmailer/goslmailer.conf.annotated_example b/cmd/goslmailer/goslmailer.conf.annotated_example index fc49217..13d6b74 100644 --- a/cmd/goslmailer/goslmailer.conf.annotated_example +++ b/cmd/goslmailer/goslmailer.conf.annotated_example @@ -1,5 +1,9 @@ { "logfile": "/tmp/goslmailer.log", # if specified; append logs to this file; else; dump to stderr + "binpaths": { # paths to required (slurm) binaries + "sacct":"/usr/bin/sacct", + "sstat":"/usr/bin/sstat" + }, "defaultconnector": "msteams", # default connector to be used for message delivery for receivers without full 'connector:user' specification "connectors": { # map of connector configurations "msteams": { # each connector has it's own map of config attributes diff --git a/cmd/goslmailer/goslmailer.go b/cmd/goslmailer/goslmailer.go index 5a51fd0..07bd2c2 100644 --- a/cmd/goslmailer/goslmailer.go +++ b/cmd/goslmailer/goslmailer.go @@ -62,7 +62,7 @@ func main() { // get job statistics based on the SLURM_JOB_ID from slurmEnv struct // only if job is END or FAIL(?) - job.GetJobStats(log, ic.CmdParams.Subject) + job.GetJobStats(log, ic.CmdParams.Subject, cfg.Binpaths) // generate hints based on SlurmEnv and JobStats (e.g. "too much memory requested" or "walltime << requested queue") // only if job is END or fail(?) diff --git a/internal/config/config.go b/internal/config/config.go index e81d734..173f7f3 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -13,6 +13,7 @@ import ( type ConfigContainer struct { Logfile string `json:"logfile"` + Binpaths map[string]string `json:"binpaths"` DefaultConnector string `json:"defaultconnector"` Connectors map[string]map[string]string `json:"connectors"` QosMap map[uint64]string `json:"qosmap"` @@ -32,6 +33,23 @@ func (cc *ConfigContainer) GetConfig(name string) error { if err != nil { return err } + + if cc.Binpaths == nil { + cc.Binpaths = make(map[string]string) + } + + // set default paths + defaultpaths := map[string]string{ + "sacct": "/usr/bin/sacct", + "sstat": "/usr/bin/sstat", + } + + for key, path := range defaultpaths { + if _, exists := cc.Binpaths[key]; !exists { + cc.Binpaths[key] = path + } + } + return nil } diff --git a/internal/slurmjob/getjobcontext.go b/internal/slurmjob/getjobcontext.go index c049b88..ab7ba82 100644 --- a/internal/slurmjob/getjobcontext.go +++ b/internal/slurmjob/getjobcontext.go @@ -122,7 +122,7 @@ func (j *JobContext) IsJobFinished() bool { } // Get additional job statistics from external source (e.g. jobinfo or sacct) -func (j *JobContext) GetJobStats(log *log.Logger, subject string) { +func (j *JobContext) GetJobStats(log *log.Logger, subject string, paths map[string]string) { log.Print("Start retrieving job stats") log.Printf("%#v", j.SlurmEnvironment) jobId := j.SlurmEnvironment.SLURM_JOBID @@ -141,16 +141,16 @@ func (j *JobContext) GetJobStats(log *log.Logger, subject string) { jobId = j.SlurmEnvironment.SLURM_ARRAY_JOB_ID } log.Printf("Fetch job info %s", jobId) - j.JobStats = *GetSacctMetrics(jobId, log) + j.JobStats = *GetSacctMetrics(jobId, log, paths) counter := 0 for !IsJobFinished(j.JobStats.State) && j.JobStats.State != j.SlurmEnvironment.SLURM_JOB_STATE && counter < 5 { time.Sleep(2 * time.Second) - j.JobStats = *GetSacctMetrics(jobId, log) + j.JobStats = *GetSacctMetrics(jobId, log, paths) counter += 1 } if j.JobStats.State == "RUNNING" { log.Print("Update job with live stats") - updateJobStatsWithLiveData(&j.JobStats, jobId, log) + updateJobStatsWithLiveData(&j.JobStats, jobId, log, paths) } log.Printf("Finished retrieving job stats") } diff --git a/internal/slurmjob/sacct.go b/internal/slurmjob/sacct.go index d1c0027..57ee2e2 100644 --- a/internal/slurmjob/sacct.go +++ b/internal/slurmjob/sacct.go @@ -200,16 +200,16 @@ func (m SacctMetrics) CalcSystemComputePercentage() float64 { return 0.0 } -func GetSacctMetrics(jobId string, log *log.Logger) *SacctMetrics { - return ParseSacctMetrics(GetSacctData(jobId, log)) +func GetSacctMetrics(jobId string, log *log.Logger, paths map[string]string) *SacctMetrics { + return ParseSacctMetrics(GetSacctData(jobId, log, paths)) } -func GetSstatMetrics(jobId string, log *log.Logger) *SstatMetrics { - return ParseSstatMetrics(GetSstatData(jobId, log)) +func GetSstatMetrics(jobId string, log *log.Logger, paths map[string]string) *SstatMetrics { + return ParseSstatMetrics(GetSstatData(jobId, log, paths)) } -func updateJobStatsWithLiveData(metrics *SacctMetrics, jobId string, log *log.Logger) { - liveMetrics := GetSstatMetrics(jobId, log) +func updateJobStatsWithLiveData(metrics *SacctMetrics, jobId string, log *log.Logger, paths map[string]string) { + liveMetrics := GetSstatMetrics(jobId, log, paths) if liveMetrics.MaxRSS > 0 { metrics.MaxRSS = liveMetrics.MaxRSS } @@ -222,9 +222,9 @@ func updateJobStatsWithLiveData(metrics *SacctMetrics, jobId string, log *log.Lo } // Execute the saccct command and return its output -func GetSacctData(jobId string, log *log.Logger) []byte { +func GetSacctData(jobId string, log *log.Logger, paths map[string]string) []byte { formatLine := "JobName,User,Partition,NodeList,ncpus,State,Submit,start,end,timelimit,elapsed,CPUTime,TotalCPU,UserCPU,SystemCPU,ReqMem,MaxRSS,MaxDiskWrite,MaxDiskRead,MaxRSSNode,MaxDiskWriteNode,MaxDiskReadNode,Comment" - cmd := exec.Command("/usr/bin/sacct", "-j", jobId, "-n", "-p", "--format", formatLine) + cmd := exec.Command(paths["sacct"], "-j", jobId, "-n", "-p", "--format", formatLine) output, err := cmd.CombinedOutput() if err != nil { log.Fatal(output) @@ -232,9 +232,9 @@ func GetSacctData(jobId string, log *log.Logger) []byte { return output } -func GetSstatData(jobId string, log *log.Logger) []byte { +func GetSstatData(jobId string, log *log.Logger, paths map[string]string) []byte { formatLine := "JobID,MaxRSS,MaxDiskWrite,MaxDiskRead,MaxRSSNode,MaxDiskWriteNode,MaxDiskReadNode" - cmd := exec.Command("/usr/bin/sstat", "-a", "-j", jobId, "-n", "-p", "--format", formatLine) + cmd := exec.Command(paths["sstat"], "-a", "-j", jobId, "-n", "-p", "--format", formatLine) output, err := cmd.CombinedOutput() if err != nil { log.Fatal(output) diff --git a/test_data/config_test/gobler.conf b/test_data/config_test/gobler.conf index 4e8aa85..c62b88d 100755 --- a/test_data/config_test/gobler.conf +++ b/test_data/config_test/gobler.conf @@ -1,5 +1,9 @@ { - "logfile": "", + "logfile": "/tmp/goslmailer.log", + "binpaths": { + "sacct":"/usr/bin/sacct", + "sstat":"/usr/bin/sstat" + }, "defaultconnector": "msteams", "connectors": { "msteams": { diff --git a/test_data/config_test/goslmailer.conf b/test_data/config_test/goslmailer.conf index 9b2819c..aacf3c5 100755 --- a/test_data/config_test/goslmailer.conf +++ b/test_data/config_test/goslmailer.conf @@ -1,5 +1,9 @@ { - "logfile": "", + "logfile": "/tmp/goslmailer.log", + "binpaths": { + "sacct":"/usr/bin/sacct", + "sstat":"/usr/bin/sstat" + }, "defaultconnector": "msteams", "connectors": { "msteams": {