Skip to content

Commit 5778815

Browse files
committed
librlist: add rlist_from_config()
Problem: There is no user friendly configuration format that can be used to generate Rv1 for resource configuration. Add rlist_from_config() to librlist, which can read a simple format TOML array from `resource.config` where each entry configures an idset of cores, gpus, and/or properties for a set of hosts. E.g.: [[resource.config]] hosts = "foo[0-10]" cores = "0-3" gpus = "0" [[resource.config]] hosts = "foo0" properties = [ "r0" ] [[resource.config]] hosts = "foo10" properties = [ "r10" ] Hostnames can appear multiple times and each time the host is updated, not overridden, which allows a natural configuration from generic to specific. To avoid confusion, the configuration does not incorporate ranks, instead ranks are meant to be assigned by the resource module when it reranks the config.
1 parent 6f0d4c7 commit 5778815

File tree

2 files changed

+208
-0
lines changed

2 files changed

+208
-0
lines changed

src/common/librlist/rlist.c

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2297,5 +2297,211 @@ struct rlist *rlist_from_hwloc (int rank, const char *xml)
22972297
return NULL;
22982298
}
22992299

2300+
/* Check if a resource set provided by configuration is valid.
2301+
* Returns -1 on failure with error in errp->text.
2302+
*/
2303+
static int rlist_config_check (struct rlist *rl, flux_error_t *errp)
2304+
{
2305+
struct rnode *n;
2306+
struct hostlist *empty;
2307+
int rc = -1;
2308+
2309+
if (zlistx_size (rl->nodes) == 0)
2310+
return errprintf (errp, "no hosts configured");
2311+
2312+
if (!(empty = hostlist_create ()))
2313+
return errprintf (errp, "hostlist_create: Out of memory");
2314+
2315+
n = zlistx_first (rl->nodes);
2316+
while (n) {
2317+
if (rnode_avail_total (n) <= 0) {
2318+
if (hostlist_append (empty, n->hostname) < 0) {
2319+
errprintf (errp,
2320+
"host %s was assigned no resources",
2321+
n->hostname);
2322+
goto out;
2323+
}
2324+
}
2325+
n = zlistx_next (rl->nodes);
2326+
}
2327+
if (hostlist_count (empty) > 0) {
2328+
char *s = hostlist_encode (empty);
2329+
errprintf (errp, "resource.config: %s assigned no resources", s);
2330+
free (s);
2331+
goto out;
2332+
}
2333+
rc = 0;
2334+
out:
2335+
hostlist_destroy (empty);
2336+
return rc;
2337+
}
2338+
2339+
/* Process one entry from the resource.config array
2340+
*/
2341+
static int rlist_config_add_entry (struct rlist *rl,
2342+
struct hostlist *hostmap,
2343+
flux_error_t *errp,
2344+
int index,
2345+
const char *hosts,
2346+
const char *cores,
2347+
const char *gpus,
2348+
json_t *properties)
2349+
{
2350+
struct hostlist *hl = NULL;
2351+
const char *host = NULL;
2352+
struct idset *coreids = NULL;
2353+
struct idset *gpuids = NULL;
2354+
struct idset *ranks = NULL;
2355+
int rc = -1;
2356+
2357+
if (!(hl = hostlist_decode (hosts))) {
2358+
errprintf (errp, "config[%d]: invalid hostlist '%s'", index, hosts);
2359+
goto error;
2360+
}
2361+
if (hostlist_count (hl) == 0) {
2362+
errprintf (errp, "config[%d]: empty hostlist specified", index);
2363+
goto error;
2364+
}
2365+
if (!(ranks = idset_create (0, IDSET_FLAG_AUTOGROW))) {
2366+
errprintf (errp, "idset_create: %s", strerror (errno));
2367+
goto error;
2368+
}
2369+
if (cores && !(coreids = idset_decode (cores))) {
2370+
errprintf (errp, "config[%d]: invalid idset cores='%s'", index, cores);
2371+
goto error;
2372+
}
2373+
if (gpus && !(gpuids = idset_decode (gpus))) {
2374+
errprintf (errp, "config[%d]: invalid idset gpus='%s'", index, gpus);
2375+
goto error;
2376+
}
2377+
host = hostlist_first (hl);
2378+
while (host) {
2379+
struct rnode *n;
2380+
int rank = hostlist_find (hostmap, host);
2381+
if (rank < 0) {
2382+
/*
2383+
* First time encountering this host. Append to host map
2384+
* hostlist and assign a rank.
2385+
*/
2386+
if (hostlist_append (hostmap, host) < 0) {
2387+
errprintf (errp, "failed to append %s to host map", host);
2388+
goto error;
2389+
}
2390+
rank = hostlist_count (hostmap) - 1;
2391+
}
2392+
if (idset_set (ranks, rank) < 0) {
2393+
errprintf (errp, "idset_set(ranks, %d): %s",
2394+
rank,
2395+
strerror (errno));
2396+
goto error;
2397+
}
2398+
if (!(n = rnode_new (host, rank))) {
2399+
errprintf (errp, "rnode_new: %s", strerror (errno));
2400+
goto error;
2401+
}
2402+
if (coreids && !rnode_add_child_idset (n, "core", coreids, coreids)) {
2403+
errprintf (errp, "rnode_add_child_idset: %s", strerror (errno));
2404+
goto error;
2405+
}
2406+
if (gpuids && !rnode_add_child_idset (n, "gpu", gpuids, gpuids)) {
2407+
errprintf (errp, "rnode_add_child_idset: %s", strerror (errno));
2408+
goto error;
2409+
}
2410+
if (properties) {
2411+
size_t idx;
2412+
json_t *o;
2413+
2414+
json_array_foreach (properties, idx, o) {
2415+
const char *property;
2416+
if (!(property = json_string_value (o))
2417+
|| property_string_invalid (property)) {
2418+
char *s = json_dumps (o, JSON_ENCODE_ANY);
2419+
errprintf (errp,
2420+
"config[%d]: invalid property \"%s\"",
2421+
index,
2422+
s);
2423+
free (s);
2424+
goto error;
2425+
}
2426+
if (rnode_set_property (n, property) < 0) {
2427+
errprintf (errp,
2428+
"Failed to set property %s on rank %u",
2429+
property,
2430+
rank);
2431+
goto error;
2432+
}
2433+
}
2434+
}
2435+
if (rlist_add_rnode (rl, n) < 0) {
2436+
errprintf (errp, "Unable to add rnode: %s", strerror (errno));
2437+
goto error;
2438+
}
2439+
host = hostlist_next (hl);
2440+
}
2441+
rc = 0;
2442+
error:
2443+
hostlist_destroy (hl);
2444+
idset_destroy (ranks);
2445+
idset_destroy (coreids);
2446+
idset_destroy (gpuids);
2447+
return rc;
2448+
}
2449+
2450+
struct rlist *rlist_from_config (json_t *conf, flux_error_t *errp)
2451+
{
2452+
size_t index;
2453+
json_t *entry;
2454+
struct rlist *rl = NULL;
2455+
struct hostlist *hl = NULL;
2456+
2457+
if (!conf || !json_is_array (conf)) {
2458+
errprintf (errp, "resource config must be an array");
2459+
return NULL;
2460+
}
2461+
2462+
if (!(hl = hostlist_create ())
2463+
|| !(rl = rlist_create ())) {
2464+
errprintf (errp, "Out of memory");
2465+
goto error;
2466+
}
2467+
2468+
json_array_foreach (conf, index, entry) {
2469+
const char *hosts = NULL;
2470+
const char *cores = NULL;
2471+
const char *gpus = NULL;
2472+
json_t *properties = NULL;
2473+
json_error_t error;
2474+
2475+
if (json_unpack_ex (entry, &error, 0,
2476+
"{s:s s?s s?s s?o !}",
2477+
"hosts", &hosts,
2478+
"cores", &cores,
2479+
"gpus", &gpus,
2480+
"properties", &properties) < 0) {
2481+
errprintf (errp, "config[%ld]: %s", index, error.text);
2482+
goto error;
2483+
}
2484+
if (rlist_config_add_entry (rl,
2485+
hl,
2486+
errp,
2487+
index,
2488+
hosts,
2489+
cores,
2490+
gpus,
2491+
properties) < 0)
2492+
goto error;
2493+
}
2494+
2495+
if (rlist_config_check (rl, errp) < 0)
2496+
goto error;
2497+
2498+
hostlist_destroy (hl);
2499+
return rl;
2500+
error:
2501+
hostlist_destroy (hl);
2502+
rlist_destroy (rl);
2503+
return NULL;
2504+
}
2505+
23002506
/* vi: ts=4 sw=4 expandtab
23012507
*/

src/common/librlist/rlist.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,6 @@ int rlist_assign_properties (struct rlist *rl,
280280
*/
281281
char *rlist_properties_encode (struct rlist *rl);
282282

283+
struct rlist *rlist_from_config (json_t *conf, flux_error_t *errp);
284+
283285
#endif /* !HAVE_SCHED_RLIST_H */

0 commit comments

Comments
 (0)