From 8c0399c8e6abceff702d597f46139dcd6fb996c3 Mon Sep 17 00:00:00 2001 From: "Mark A. Grondona" Date: Fri, 6 Dec 2024 00:53:18 +0000 Subject: [PATCH 1/3] libflux: add "confdir" to flux_conf_builtin_get() Problem: It would be useful to query the builtin intree or installed configuration path from libflux, but flux_conf_builtin_get() does not support that specific value. Add confdir to the list of supported keys for flux_conf_builtin_get(). --- src/common/libflux/conf.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/common/libflux/conf.c b/src/common/libflux/conf.c index 01fd7c9a75ec..106cb0523652 100644 --- a/src/common/libflux/conf.c +++ b/src/common/libflux/conf.c @@ -47,6 +47,11 @@ struct flux_conf { static const char *conf_auxkey = "flux::conf_object"; static struct builtin builtin_tab[] = { + { + .key = "confdir", + .val_installed = FLUXCONFDIR, + .val_intree = ABS_TOP_SRCDIR "/etc", + }, { .key = "lua_cpath_add", .val_installed = LUAEXECDIR "/?.so", From 23a7df7d21f35f0aa681e06ce6b17af11628ffde Mon Sep 17 00:00:00 2001 From: "Mark A. Grondona" Date: Fri, 6 Dec 2024 01:51:26 +0000 Subject: [PATCH 2/3] python: add flux.conf_builtin.conf_builtin_get() Problem: Python programs do not have access to libflux builtin configuration values via flux_conf_builtin_get(). Add flux.conf_builtin.conf_builtin_get() which provides access to this function from Python. Unfortunately, the bahavior of FLUX_CONF_AUTO must be duplicated because the builtin libflux intree vs installed tests do not work when `python` is the executable (since it isn't part of Flux). --- src/bindings/python/flux/Makefile.am | 1 + src/bindings/python/flux/conf_builtin.py | 64 ++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/bindings/python/flux/conf_builtin.py diff --git a/src/bindings/python/flux/Makefile.am b/src/bindings/python/flux/Makefile.am index 9ab728009794..1cfe05137bec 100644 --- a/src/bindings/python/flux/Makefile.am +++ b/src/bindings/python/flux/Makefile.am @@ -11,6 +11,7 @@ nobase_fluxpy_PYTHON = \ memoized_property.py \ debugged.py \ importer.py \ + conf_builtin.py \ cli/__init__.py \ cli/base.py \ cli/alloc.py \ diff --git a/src/bindings/python/flux/conf_builtin.py b/src/bindings/python/flux/conf_builtin.py new file mode 100644 index 000000000000..84ededa0f2c0 --- /dev/null +++ b/src/bindings/python/flux/conf_builtin.py @@ -0,0 +1,64 @@ +############################################################### +# Copyright 2024 Lawrence Livermore National Security, LLC +# (c.f. AUTHORS, NOTICE.LLNS, COPYING) +# +# This file is part of the Flux resource manager framework. +# For details, see https://github.com/flux-framework. +# +# SPDX-License-Identifier: LGPL-3.0 +############################################################### + +import threading +from pathlib import Path + +from flux.core.inner import raw + +tls = threading.local() +tls.FLUX_CONF_AUTO_FLAG = None + + +def _conf_builtin_get_flag(): + """Simulate the use of FLUX_CONF_AUTO for Python + + FLUX_CONF_AUTO will not work from Python since the executable will + be python and not something part of the Flux build tree or installed + by Flux. This function simulates FLUX_CONF_AUTO by returning the + correct FLUX_CONF_FLAG based on whether this module is under the + in tree PYTHONPATH or not. + """ + if tls.FLUX_CONF_AUTO_FLAG is None: + # Resolve builtin installed python path: + pythonpath = conf_builtin_get("python_path", which="intree").split(":") + for path in pythonpath: + if Path(path).resolve() in Path(__file__).resolve().parents: + # If path is one of this module's parents, + # then this module is in tree: + tls.FLUX_CONF_AUTO_FLAG = raw.FLUX_CONF_INTREE + return tls.FLUX_CONF_AUTO_FLAG + # O/w, assume we're installed + tls.FLUX_CONF_AUTO_FLAG = raw.FLUX_CONF_INSTALLED + return tls.FLUX_CONF_AUTO_FLAG + + +def conf_builtin_get(name, which="auto"): + """Get builtin (compiled-in) configuration values from libflux + + Args: + name (str): name of config value + which (str): one of "installed", "intree", or "auto" to return + the installed path, in tree path, or automatically determine + which to use. default=auto. + """ + if which == "auto": + flag = _conf_builtin_get_flag() + elif which == "installed": + flag = raw.FLUX_CONF_INSTALLED + elif which == "intree": + flag = raw.FLUX_CONF_INTREE + else: + raise ValueError("which must be one of auto, installed, or intree") + + try: + return raw.flux_conf_builtin_get(name, flag).decode("utf-8") + except OSError: + raise ValueError(f"No builtin config value for '{name}'") From 024e5cbe682a9390ea1512b545a0d64502e4d0ac Mon Sep 17 00:00:00 2001 From: "Mark A. Grondona" Date: Fri, 6 Dec 2024 02:11:33 +0000 Subject: [PATCH 3/3] testsuite: add python unit tests for conf_builtin_get() Problem: There are no unit tests for the Python interface to flux_conf_builtin_get(). Add some very simple tests. --- t/Makefile.am | 1 + t/python/t0031-conf-builtin.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100755 t/python/t0031-conf-builtin.py diff --git a/t/Makefile.am b/t/Makefile.am index feb9b9e38c3e..2c05706d82e1 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -288,6 +288,7 @@ TESTSCRIPTS = \ python/t0028-compat36.py \ python/t0029-fileref.py \ python/t0030-journal.py \ + python/t0031-conf-builtin.py \ python/t1000-service-add-remove.py if HAVE_FLUX_SECURITY diff --git a/t/python/t0031-conf-builtin.py b/t/python/t0031-conf-builtin.py new file mode 100755 index 000000000000..14795efaae71 --- /dev/null +++ b/t/python/t0031-conf-builtin.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +############################################################### +# Copyright 2024 Lawrence Livermore National Security, LLC +# (c.f. AUTHORS, NOTICE.LLNS, COPYING) +# +# This file is part of the Flux resource manager framework. +# For details, see https://github.com/flux-framework. +# +# SPDX-License-Identifier: LGPL-3.0 +############################################################### + +import unittest + +import subflux # noqa: F401 +from flux.conf_builtin import conf_builtin_get +from pycotap import TAPTestRunner + + +class TestConfBuiltin(unittest.TestCase): + + def test_conf_builtin_get(self): + with self.assertRaises(ValueError): + conf_builtin_get("foo") + + with self.assertRaises(ValueError): + conf_builtin_get("confdir", which="badarg") + + self.assertIsNotNone(conf_builtin_get("confdir")) + self.assertIsNotNone(conf_builtin_get("confdir", which="intree")) + self.assertIsNotNone(conf_builtin_get("confdir", which="installed")) + + +if __name__ == "__main__": + unittest.main(testRunner=TAPTestRunner())