Skip to content

Commit d0b9ac3

Browse files
authored
Merge pull request #1149 from jameshcorbett/reader-fix-jgf-properties
reader: fix jgf properties
2 parents 68c636a + f2f2899 commit d0b9ac3

File tree

4 files changed

+72
-49
lines changed

4 files changed

+72
-49
lines changed

resource/readers/resource_reader_jgf.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,13 @@ int resource_reader_jgf_t::fill_fetcher (json_t *element, fetch_helper_t &f,
401401
}
402402
*properties = json_object_get (metadata, "properties");
403403
*paths = p;
404+
if (*properties && !json_is_object (*properties)) {
405+
errno = EINVAL;
406+
m_err_msg += __FUNCTION__;
407+
m_err_msg += ": key (properties) must be an object or null for ";
408+
m_err_msg += std::string (f.vertex_id) + ".\n";
409+
goto done;
410+
}
404411
rc = 0;
405412
done:
406413
return rc;

src/python/fluxion/resourcegraph/V1.py

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def __init__(
5050
exclusive -- Exclusivity
5151
unit -- Unit of this resource
5252
size -- Amount of individual resources in this resource pool in unit
53-
properties -- Comma-separated list of property strings
53+
properties -- mapping from property name to value
5454
paths -- Fully qualified paths dictionary
5555
status -- Resource status (0 for 'up', 1 for 'down'), defaults to 0
5656
"""
@@ -127,31 +127,18 @@ def _extract_id_from_hn(self, hostName):
127127
rc = int(postfix[0])
128128
return rc
129129

130-
def _add_to_rankdict(self, key, gLabel, rankdict):
131-
if key in rankdict:
132-
rankdict[key].append(gLabel)
133-
else:
134-
rankdict[key] = [gLabel]
135-
136130
def _contains_any(self, prop_str, charset):
137131
for c in charset:
138132
if c in prop_str:
139133
return True
140134
return False
141135

142-
def _per_rank_property_dict(self, properties, rankdict):
143-
for p in properties:
144-
# This can be extended later to support scheduler specific
145-
# string (@suffix)
146-
if self._contains_any(p, "!&'\"^`|()"):
147-
raise ValueError(f"invalid character used in property={p}")
148-
self._add_to_rankdict("node", p, rankdict)
149-
150-
def _encode_child(self, ppid, hPath, rank, resType, i, rpd):
136+
def _encode_child(self, ppid, hPath, rank, resType, i, properties):
151137
path = f"{hPath}/{resType}{i}"
152-
properties = []
138+
properties = {}
153139
# This can be extended later to support fine grained property
154-
# attachment using rpd
140+
# attachment using properties passed in from parent;
141+
# for now, set empty properties
155142
vtx = FluxionResourcePoolV1(
156143
self._uniqId,
157144
resType,
@@ -169,14 +156,11 @@ def _encode_child(self, ppid, hPath, rank, resType, i, rpd):
169156
edg = FluxionResourceRelationshipV1(ppid, vtx.get_id())
170157
self._add_and_tick_uniq_id(vtx, edg)
171158

172-
def _encode_rank(self, ppid, rank, children, hList, rdict, rpd):
159+
def _encode_rank(self, ppid, rank, children, hList, rdict, properties):
173160
if rdict[rank] >= len(hList):
174161
raise ValueError(f"nodelist doesn't include node for rank={rank}")
175162
hPath = f"/cluster0/{hList[rdict[rank]]}"
176163
iden = self._extract_id_from_hn(hList[rdict[rank]])
177-
properties = []
178-
if "node" in rpd:
179-
properties = rpd["node"]
180164
vtx = FluxionResourcePoolV1(
181165
self._uniqId,
182166
"node",
@@ -195,14 +179,13 @@ def _encode_rank(self, ppid, rank, children, hList, rdict, rpd):
195179
self._add_and_tick_uniq_id(vtx, edg)
196180
for key, val in children.items():
197181
for i in IDset(val):
198-
self._encode_child(vtx.get_id(), hPath, rank, str(key), i, rpd)
182+
self._encode_child(vtx.get_id(), hPath, rank, str(key), i, properties)
199183

200184
def _encode_rlite(self, ppid, entry, hList, rdict, pdict):
201185
for rank in list(IDset(entry["rank"])):
202-
rpd = {}
203-
if rank in pdict:
204-
self._per_rank_property_dict(pdict[rank], rpd)
205-
self._encode_rank(ppid, rank, entry["children"], hList, rdict, rpd)
186+
self._encode_rank(
187+
ppid, rank, entry["children"], hList, rdict, pdict.get(rank, {})
188+
)
206189

207190
def _encode(self):
208191
hList = Hostlist(self._rv1NoSched["execution"]["nodelist"])
@@ -217,7 +200,7 @@ def _encode(self):
217200
True,
218201
"",
219202
1,
220-
[],
203+
{},
221204
"/cluster0",
222205
)
223206
self._add_and_tick_uniq_id(vtx, None)
@@ -234,11 +217,13 @@ def _encode(self):
234217
props = self._rv1NoSched["execution"]["properties"]
235218
pdict = {}
236219
for p in props:
220+
if self._contains_any(p, "!&'\"^`|()"):
221+
raise ValueError(f"invalid character used in property={p}")
237222
for rank in list(IDset(props[p])):
238223
if rank in pdict:
239-
pdict[rank].append(p)
224+
pdict[rank][p] = ""
240225
else:
241-
pdict[rank] = [p]
226+
pdict[rank] = {p: ""}
242227

243228
for entry in self._rv1NoSched["execution"]["R_lite"]:
244229
self._encode_rlite(vtx.get_id(), entry, hList, rdict, pdict)

t/python/t10001-resourcegraph.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@
4545
},
4646
}
4747

48+
RV1_3 = {
49+
"version": 1,
50+
"execution": {
51+
"R_lite": [{"rank": "0-19", "children": {"gpu": "0-1", "core": "0-7"}}],
52+
"starttime": 0.0,
53+
"expiration": 0.0,
54+
"nodelist": ["compute[0-19]"],
55+
"properties": {"pdebug": "0-9", "pbatch": "10-19"},
56+
},
57+
}
58+
4859

4960
class TestResourceGraph(unittest.TestCase):
5061
"""Test for the ResourceGraph class."""
@@ -53,7 +64,7 @@ def _check_metadata(self, metadata):
5364
if metadata["type"] in ("node", "core", "gpu", "cluster"):
5465
self.assertEqual(metadata["unit"], "")
5566
self.assertEqual(metadata["size"], 1)
56-
self.assertEqual(metadata["properties"], [])
67+
self.assertEqual(metadata["properties"], {})
5768
else:
5869
raise ValueError(metadata["type"])
5970

@@ -79,5 +90,25 @@ def test_basic_2(self):
7990
for node in graph.get_nodes():
8091
self._check_metadata(node.get_metadata())
8192

93+
def test_basic_3(self):
94+
graph = FluxionResourceGraphV1(RV1_3)
95+
self.assertTrue(graph.is_directed())
96+
j = graph.to_JSON()
97+
self.assertTrue(j["graph"]["directed"])
98+
self.assertEqual(len(j["graph"]["nodes"]), len(graph.get_nodes()))
99+
self.assertEqual(len(j["graph"]["edges"]), len(graph.get_edges()))
100+
for node in graph.get_nodes():
101+
metadata = node.get_metadata()
102+
if metadata["type"] != "node":
103+
self._check_metadata(node.get_metadata())
104+
else:
105+
self.assertEqual(metadata["unit"], "")
106+
self.assertEqual(metadata["size"], 1)
107+
self.assertEqual(len(metadata["properties"]), 1)
108+
if metadata["id"] < 10:
109+
self.assertEqual(metadata["properties"]["pdebug"], "")
110+
else:
111+
self.assertEqual(metadata["properties"]["pbatch"], "")
112+
82113

83114
unittest.main(testRunner=TAPTestRunner())

t/t8001-util-ion-R.t

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -159,24 +159,24 @@ test_expect_success 'fluxion-R: can detect insufficient nodelist' '
159159

160160
test_expect_success 'fluxion-R: encoding properties on heterogeneity works' '
161161
cat <<-EOF >expected6 &&
162-
/cluster0 -1 []
163-
/cluster0/foo2 0 ["arm-v9@core"]
164-
/cluster0/foo2/core0 0 []
165-
/cluster0/foo2/core1 0 []
166-
/cluster0/foo2/gpu0 0 []
167-
/cluster0/foo2/gpu1 0 []
168-
/cluster0/foo3 2 ["arm-v9@core","amd-mi60@gpu"]
169-
/cluster0/foo3/core0 2 []
170-
/cluster0/foo3/core1 2 []
171-
/cluster0/foo3/gpu0 2 []
172-
/cluster0/foo3/gpu1 2 []
173-
/cluster0/foo1 3 ["arm-v9@core","amd-mi60@gpu"]
174-
/cluster0/foo1/core0 3 []
175-
/cluster0/foo1/core1 3 []
176-
/cluster0/foo1/gpu0 3 []
177-
/cluster0/foo1/gpu1 3 []
178-
/cluster0/foo4 1 ["arm-v8@core"]
179-
/cluster0/foo4/core0 1 []
162+
/cluster0 -1 {}
163+
/cluster0/foo2 0 {"arm-v9@core":""}
164+
/cluster0/foo2/core0 0 {}
165+
/cluster0/foo2/core1 0 {}
166+
/cluster0/foo2/gpu0 0 {}
167+
/cluster0/foo2/gpu1 0 {}
168+
/cluster0/foo3 2 {"arm-v9@core":"","amd-mi60@gpu":""}
169+
/cluster0/foo3/core0 2 {}
170+
/cluster0/foo3/core1 2 {}
171+
/cluster0/foo3/gpu0 2 {}
172+
/cluster0/foo3/gpu1 2 {}
173+
/cluster0/foo1 3 {"arm-v9@core":"","amd-mi60@gpu":""}
174+
/cluster0/foo1/core0 3 {}
175+
/cluster0/foo1/core1 3 {}
176+
/cluster0/foo1/gpu0 3 {}
177+
/cluster0/foo1/gpu1 3 {}
178+
/cluster0/foo4 1 {"arm-v8@core":""}
179+
/cluster0/foo4/core0 1 {}
180180
EOF
181181
flux R encode -r 0 -c 0-1 -g 0-1 -p "arm-v9@core:0" -H foo2 > out6 &&
182182
flux R encode -r 1 -c 0 -H foo3 -p "arm-v8@core:1" >> out6 &&

0 commit comments

Comments
 (0)