Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JGF simplification #1293

Merged
merged 6 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 65 additions & 24 deletions resource/readers/resource_reader_jgf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <map>
#include <unordered_set>
#include <unistd.h>
#include <regex>
#include <jansson.h>
#include "resource/readers/resource_reader_jgf.hpp"
#include "resource/store/resource_graph_store.hpp"
Expand Down Expand Up @@ -57,7 +58,7 @@
int exclusive = -1;
resource_pool_t::status_t status = resource_pool_t::status_t::UP;
const char *type = NULL;
const char *name = NULL;
std::string name;
const char *unit = NULL;
const char *basename = NULL;
const char *vertex_id = NULL;
Expand Down Expand Up @@ -119,7 +120,7 @@

const char *fetch_helper_t::get_proper_name () const
{
return (is_name_remapped ()) ? get_remapped_name ().c_str () : name;
return (is_name_remapped ()) ? get_remapped_name ().c_str () : name.c_str ();
}

int64_t fetch_helper_t::get_proper_id () const
Expand All @@ -141,7 +142,7 @@
exclusive = -1;
status = resource_pool_t::status_t::UP;
type = NULL;
name = NULL;
name.clear ();
unit = NULL;
basename = NULL;
vertex_id = NULL;
Expand Down Expand Up @@ -341,36 +342,83 @@
return 0;
}

int resource_reader_jgf_t::apply_defaults (fetch_helper_t &f, const char *name)
{
if (f.uniq_id == -1) {
try {
f.uniq_id = static_cast<int64_t> (std::stoll (std::string{f.vertex_id}));
} catch (std::invalid_argument const &ex) {
m_err_msg += __FUNCTION__;
m_err_msg += ": value for key (uniq_id) could not be inferred from outer ";
m_err_msg += "'id' field " + std::string (f.vertex_id) + ".\n";
return -1;

Check warning on line 354 in resource/readers/resource_reader_jgf.cpp

View check run for this annotation

Codecov / codecov/patch

resource/readers/resource_reader_jgf.cpp#L350-L354

Added lines #L350 - L354 were not covered by tests
}
}
if (f.id == -1) {
f.id = f.uniq_id;
// for nodes, see if there is an integer suffix on the hostname and use it if so
if (f.type == std::string{"node"} && name != NULL) {
trws marked this conversation as resolved.
Show resolved Hide resolved
std::string sname{name};
std::regex nodesuffix ("(\\d+$)");
std::smatch r;
if (std::regex_search (sname, r, nodesuffix)) {
try {
f.id = std::stoll (r.str (0));
} catch (std::invalid_argument const &ex) {
m_err_msg += __FUNCTION__;
m_err_msg += ": could not extract ID from hostname ";
m_err_msg += sname;
return -1;

Check warning on line 371 in resource/readers/resource_reader_jgf.cpp

View check run for this annotation

Codecov / codecov/patch

resource/readers/resource_reader_jgf.cpp#L367-L371

Added lines #L367 - L371 were not covered by tests
}
}
}
}
if (f.exclusive == -1)
f.exclusive = 0;
if (f.size == -1)
f.size = 1;
if (f.basename == NULL)
f.basename = f.type;
if (name == NULL) {
f.name = f.basename;
f.name.append (std::to_string (f.id));
} else {
f.name = name;
}
if (f.unit == NULL)
f.unit = "";
return 0;
}

int resource_reader_jgf_t::fill_fetcher (json_t *element,
fetch_helper_t &f,
json_t **paths,
json_t **properties)
{
int rc = -1;
json_t *p = NULL;
json_t *metadata = NULL;
const char *name = NULL;

if ((json_unpack (element, "{ s:s }", "id", &f.vertex_id) < 0)) {
errno = EINVAL;
m_err_msg += __FUNCTION__;
m_err_msg += ": JGF vertex id key is not found in a node.\n";
goto done;
return -1;

Check warning on line 405 in resource/readers/resource_reader_jgf.cpp

View check run for this annotation

Codecov / codecov/patch

resource/readers/resource_reader_jgf.cpp#L405

Added line #L405 was not covered by tests
}
if ((metadata = json_object_get (element, "metadata")) == NULL) {
errno = EINVAL;
m_err_msg += __FUNCTION__;
m_err_msg += ": key (metadata) is not found in an JGF node for ";
m_err_msg += std::string (f.vertex_id) + ".\n";
goto done;
return -1;

Check warning on line 412 in resource/readers/resource_reader_jgf.cpp

View check run for this annotation

Codecov / codecov/patch

resource/readers/resource_reader_jgf.cpp#L412

Added line #L412 was not covered by tests
}
if ((json_unpack (metadata,
"{ s:s s:s s:s s:I s:I s:I s?:i s:b s:s s:I }",
"{ s:s s?s s?s s?I s?I s?I s?i s?b s?s s?I s:o s?o }",
"type",
&f.type,
"basename",
&f.basename,
"name",
&f.name,
&name,
"id",
&f.id,
"uniq_id",
Expand All @@ -384,33 +432,26 @@
"unit",
&f.unit,
"size",
&f.size))
&f.size,
"paths",
paths,
"properties",
properties))
< 0) {
errno = EINVAL;
m_err_msg += __FUNCTION__;
m_err_msg += ": malformed metadata in an JGF node for ";
m_err_msg += std::string (f.vertex_id) + "\n";
goto done;
}
if ((p = json_object_get (metadata, "paths")) == NULL) {
errno = EINVAL;
m_err_msg += __FUNCTION__;
m_err_msg += ": key (paths) does not exist in an JGF node for ";
m_err_msg += std::string (f.vertex_id) + ".\n";
goto done;
return -1;

Check warning on line 445 in resource/readers/resource_reader_jgf.cpp

View check run for this annotation

Codecov / codecov/patch

resource/readers/resource_reader_jgf.cpp#L445

Added line #L445 was not covered by tests
}
*properties = json_object_get (metadata, "properties");
*paths = p;
if (*properties && !json_is_object (*properties)) {
errno = EINVAL;
m_err_msg += __FUNCTION__;
m_err_msg += ": key (properties) must be an object or null for ";
m_err_msg += std::string (f.vertex_id) + ".\n";
goto done;
return -1;

Check warning on line 452 in resource/readers/resource_reader_jgf.cpp

View check run for this annotation

Codecov / codecov/patch

resource/readers/resource_reader_jgf.cpp#L452

Added line #L452 was not covered by tests
}
rc = 0;
done:
return rc;
return apply_defaults (f, name);
}

int resource_reader_jgf_t::unpack_vtx (json_t *element, fetch_helper_t &f)
Expand Down
1 change: 1 addition & 0 deletions resource/readers/resource_reader_jgf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class resource_reader_jgf_t : public resource_reader_base_t {
int fetch_jgf (const std::string &str, json_t **jgf_p, json_t **nodes_p, json_t **edges_p);
int unpack_and_remap_vtx (fetch_helper_t &f, json_t *paths, json_t *properties);
int remap_aware_unpack_vtx (fetch_helper_t &f, json_t *paths, json_t *properties);
int apply_defaults (fetch_helper_t &f, const char *name);
int fill_fetcher (json_t *element, fetch_helper_t &f, json_t **path, json_t **properties);
int unpack_vtx (json_t *element, fetch_helper_t &f);
vtx_t create_vtx (resource_graph_t &g, const fetch_helper_t &fetcher);
Expand Down
138 changes: 50 additions & 88 deletions src/python/fluxion/resourcegraph/V1.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
# SPDX-License-Identifier: LGPL-3.0
##############################################################

import re

from flux.idset import IDset
from flux.hostlist import Hostlist
from fluxion.jsongraph.objects.graph import Graph, Node, Edge
Expand All @@ -24,16 +22,16 @@
self,
vtxId,
resType,
basename,
name,
iden,
uniqId,
rank,
exclusive,
unit,
size,
properties,
path,
basename=None,
name=None,
iden=None,
uniqId=None,
rank=None,
exclusive=None,
unit=None,
size=None,
properties=None,
path=None,
status=0,
):
"""Constructor
Expand All @@ -57,18 +55,30 @@
raise ValueError(f"resource type={resType} unsupported by RV1")
metadata = {
"type": resType,
"basename": basename,
"name": name,
"id": iden,
"uniq_id": uniqId,
"rank": rank,
"exclusive": exclusive,
"unit": unit,
"size": size,
"properties": properties,
"paths": {"containment": path},
}
if status != 0: # reduce the footprint by only adding status if nonzero
if basename is not None:
metadata["basename"] = basename

Check warning on line 60 in src/python/fluxion/resourcegraph/V1.py

View check run for this annotation

Codecov / codecov/patch

src/python/fluxion/resourcegraph/V1.py#L60

Added line #L60 was not covered by tests
if name is not None:
metadata["name"] = name
if iden is not None:
metadata["id"] = iden
if uniqId is not None:
metadata["uniq_id"] = uniqId

Check warning on line 66 in src/python/fluxion/resourcegraph/V1.py

View check run for this annotation

Codecov / codecov/patch

src/python/fluxion/resourcegraph/V1.py#L66

Added line #L66 was not covered by tests
if rank is not None:
metadata["rank"] = rank
if exclusive is not None:
metadata["exclusive"] = exclusive

Check warning on line 70 in src/python/fluxion/resourcegraph/V1.py

View check run for this annotation

Codecov / codecov/patch

src/python/fluxion/resourcegraph/V1.py#L70

Added line #L70 was not covered by tests
if unit:
metadata["unit"] = unit

Check warning on line 72 in src/python/fluxion/resourcegraph/V1.py

View check run for this annotation

Codecov / codecov/patch

src/python/fluxion/resourcegraph/V1.py#L72

Added line #L72 was not covered by tests
if size is not None:
metadata["size"] = size

Check warning on line 74 in src/python/fluxion/resourcegraph/V1.py

View check run for this annotation

Codecov / codecov/patch

src/python/fluxion/resourcegraph/V1.py#L74

Added line #L74 was not covered by tests
if properties:
metadata["properties"] = properties
if path is not None:
metadata["paths"] = {"containment": path}
else:
raise ValueError("path must not be None")

Check warning on line 80 in src/python/fluxion/resourcegraph/V1.py

View check run for this annotation

Codecov / codecov/patch

src/python/fluxion/resourcegraph/V1.py#L80

Added line #L80 was not covered by tests
if status != 0:
metadata["status"] = status
super().__init__(vtxId, metadata=metadata)

Expand All @@ -82,16 +92,6 @@
Fluxion Resource Relationship V1 Class: extend jsongraph's Edge class
"""

def __init__(self, parentId, vtxId):
"""Constructor
parentId -- Parent vertex Id
vtxId -- Child vertex Id
"""
super().__init__(
parentId,
vtxId,
)


class FluxionResourceGraphV1(Graph):
"""
Expand All @@ -118,88 +118,51 @@
self.add_edge(edg)
self._tick_uniq_id()

def _extract_id_from_hn(self, hostName):
postfix = re.findall(r"(\d+$)", hostName)
rc = self._uniqId
if len(postfix) == 1:
rc = int(postfix[0])
return rc

def _contains_any(self, prop_str, charset):
for c in charset:
if c in prop_str:
return True
return False

def _encode_child(self, ppid, hPath, rank, resType, i, properties):
path = f"{hPath}/{resType}{i}"
properties = {}
# This can be extended later to support fine grained property
# attachment using properties passed in from parent;
# for now, set empty properties
def _encode_child(self, ppid, path, rank, resType, i):
vtx = FluxionResourcePoolV1(
self._uniqId,
resType,
resType,
resType + str(i),
i,
self._uniqId,
rank,
True,
"",
1,
properties,
path,
self._uniqId, resType, iden=i, rank=rank, path=f"{path}/{resType}{i}"
)
edg = FluxionResourceRelationshipV1(ppid, vtx.get_id())
self._add_and_tick_uniq_id(vtx, edg)

def _encode_rank(self, ppid, rank, children, hList, rdict, properties):
if rdict[rank] >= len(hList):
raise ValueError(f"nodelist doesn't include node for rank={rank}")
hPath = f"/cluster0/{hList[rdict[rank]]}"
iden = self._extract_id_from_hn(hList[rdict[rank]])
def _encode_rank(self, ppid, path, rank, children, hostname, properties):
path = f"{path}/{hostname}"
vtx = FluxionResourcePoolV1(
self._uniqId,
"node",
"node",
hList[rdict[rank]],
iden,
self._uniqId,
rank,
True,
"",
1,
properties,
hPath,
name=hostname,
rank=rank,
properties=properties,
path=path,
)
edg = FluxionResourceRelationshipV1(ppid, vtx.get_id())
self._add_and_tick_uniq_id(vtx, edg)
for key, val in children.items():
for i in IDset(val):
self._encode_child(vtx.get_id(), hPath, rank, str(key), i, properties)
self._encode_child(vtx.get_id(), path, rank, str(key), i)

def _encode_rlite(self, ppid, entry, hList, rdict, pdict):
def _encode_rlite(self, ppid, path, entry, hList, rdict, pdict):
for rank in list(IDset(entry["rank"])):
if rdict[rank] >= len(hList):
raise ValueError(f"nodelist doesn't include node for rank={rank}")

Check warning on line 153 in src/python/fluxion/resourcegraph/V1.py

View check run for this annotation

Codecov / codecov/patch

src/python/fluxion/resourcegraph/V1.py#L153

Added line #L153 was not covered by tests
hostname = hList[rdict[rank]]
self._encode_rank(
ppid, rank, entry["children"], hList, rdict, pdict.get(rank, {})
ppid, path, rank, entry["children"], hostname, pdict.get(rank)
)

def _encode(self):
hList = Hostlist(self._rv1NoSched["execution"]["nodelist"])
path = "/cluster0"
vtx = FluxionResourcePoolV1(
self._uniqId,
"cluster",
"cluster",
"cluster0",
0,
self._uniqId,
-1,
True,
"",
1,
{},
"/cluster0",
path=path,
)
self._add_and_tick_uniq_id(vtx, None)
i = 0
Expand All @@ -222,6 +185,5 @@
pdict[rank][p] = ""
else:
pdict[rank] = {p: ""}

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