You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by la...@apache.org on 2026/09/01 00:23:51 UTC
(airavata-custos) 01/02: Decode SLURM TRES counts as fractional values
This is an automated email from the ASF dual-hosted git repository.
lahirujayathilake pushed a commit to branch billing-tres
in repository https://gitbox.apache.org/repos/asf/airavata-custos.git
commit 8ac79417cb829bc8ed1e85c2e581ac7159a0efc9
Author: lahiruj <la...@gmail.com>
AuthorDate: Thu Aug 13 01:04:52 2026 -0400
Decode SLURM TRES counts as fractional values
---
.../internal/subscribers/association_writer.go | 6 +++---
connectors/SLURM/Rest-Client/pkg/client/tres.go | 4 ++--
connectors/SLURM/Rest-Client/pkg/client/types.go | 8 +++++---
connectors/SLURM/Rest-Client/pkg/client/types_test.go | 15 +++++++++++++++
4 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/connectors/SLURM/Association-Mapper/internal/subscribers/association_writer.go b/connectors/SLURM/Association-Mapper/internal/subscribers/association_writer.go
index 5a14265ce..af5676d02 100644
--- a/connectors/SLURM/Association-Mapper/internal/subscribers/association_writer.go
+++ b/connectors/SLURM/Association-Mapper/internal/subscribers/association_writer.go
@@ -33,9 +33,9 @@ import (
// and name; a plain resource like "cpu" has no name.
func tresFor(resourceType string, count int64) client.TRES {
if typ, name, ok := strings.Cut(resourceType, "/"); ok {
- return client.TRES{Type: typ, Name: name, Count: count}
+ return client.TRES{Type: typ, Name: name, Count: float64(count)}
}
- return client.TRES{Type: resourceType, Count: count}
+ return client.TRES{Type: resourceType, Count: float64(count)}
}
// errNotProvisioned means the account does not exist on the cluster yet, so
@@ -66,7 +66,7 @@ func sameTRES(want, got []client.TRES) bool {
if len(want) != len(got) {
return false
}
- counts := make(map[string]int64, len(want))
+ counts := make(map[string]float64, len(want))
for _, t := range want {
counts[t.Type] = t.Count
}
diff --git a/connectors/SLURM/Rest-Client/pkg/client/tres.go b/connectors/SLURM/Rest-Client/pkg/client/tres.go
index 9a7120398..4c8154a0b 100644
--- a/connectors/SLURM/Rest-Client/pkg/client/tres.go
+++ b/connectors/SLURM/Rest-Client/pkg/client/tres.go
@@ -38,9 +38,9 @@ func ParseTRES(s string) ([]TRES, error) {
if len(kv) != 2 {
return nil, fmt.Errorf("malformed TRES entry %q (want key=value)", p)
}
- n, err := strconv.ParseInt(strings.TrimSpace(kv[1]), 10, 64)
+ n, err := strconv.ParseFloat(strings.TrimSpace(kv[1]), 64)
if err != nil {
- return nil, fmt.Errorf("TRES count %q not an integer", kv[1])
+ return nil, fmt.Errorf("TRES count %q not a number", kv[1])
}
t := TRES{Count: n}
key := strings.TrimSpace(kv[0])
diff --git a/connectors/SLURM/Rest-Client/pkg/client/types.go b/connectors/SLURM/Rest-Client/pkg/client/types.go
index e15945bed..1b96cb14e 100644
--- a/connectors/SLURM/Rest-Client/pkg/client/types.go
+++ b/connectors/SLURM/Rest-Client/pkg/client/types.go
@@ -33,10 +33,12 @@ type ErrorResponse struct {
} `json:"warnings"`
}
+// Billing weights scale a count down to the share of a node the job held, so
+// a count arrives fractional and an integer field fails the whole decode.
type TRES struct {
- Type string `json:"type"`
- Name string `json:"name,omitempty"`
- Count int64 `json:"count"`
+ Type string `json:"type"`
+ Name string `json:"name,omitempty"`
+ Count float64 `json:"count"`
}
type Account struct {
diff --git a/connectors/SLURM/Rest-Client/pkg/client/types_test.go b/connectors/SLURM/Rest-Client/pkg/client/types_test.go
index 8f26f9737..7572af603 100644
--- a/connectors/SLURM/Rest-Client/pkg/client/types_test.go
+++ b/connectors/SLURM/Rest-Client/pkg/client/types_test.go
@@ -41,3 +41,18 @@ func TestJobInfoDecodes(t *testing.T) {
t.Fatalf("core fields: %+v", j)
}
}
+
+// An integer count field fails the whole decode, dropping every job in the
+// response, not just this one.
+func TestJobInfoDecodesFractionalTresCount(t *testing.T) {
+ raw := `{"account":"proj-a","user":"user-a","partition":"gpu","job_id":8,
+ "time":{"start":1000,"end":4600},
+ "tres":{"allocated":[{"type":"cpu","count":90},{"type":"billing","count":2.8125}]}}`
+ var j JobInfo
+ if err := json.Unmarshal([]byte(raw), &j); err != nil {
+ t.Fatalf("decode: %v", err)
+ }
+ if got := j.Tres.Allocated[1].Count; got != 2.8125 {
+ t.Fatalf("billing count: want 2.8125, got %v", got)
+ }
+}