diff --git a/python/pacemaker/Makefile.am b/python/pacemaker/Makefile.am index df9cc46eef..99a137ad78 100644 --- a/python/pacemaker/Makefile.am +++ b/python/pacemaker/Makefile.am @@ -1,17 +1,18 @@ # -# Copyright 2023 the Pacemaker project contributors +# Copyright 2023-2024 the Pacemaker project contributors # # The version control history for this file may have further details. # # This source code is licensed under the GNU General Public License version 2 # or later (GPLv2+) WITHOUT ANY WARRANTY. # MAINTAINERCLEANFILES = Makefile.in pkgpython_PYTHON = __init__.py \ + _library.py \ exitstatus.py nodist_pkgpython_PYTHON = buildoptions.py SUBDIRS = _cts diff --git a/python/pacemaker/_library.py b/python/pacemaker/_library.py new file mode 100644 index 0000000000..cd6bc4ef44 --- /dev/null +++ b/python/pacemaker/_library.py @@ -0,0 +1,38 @@ +"""A module providing private library management code.""" + +__all__ = ["_libcrmcommon"] +__copyright__ = "Copyright 2024 the Pacemaker project contributors" +__license__ = "GNU Lesser General Public License version 2.1 or later (LGPLv2.1+)" + +import ctypes +from ctypes.util import find_library +from glob import glob +import os + +from pacemaker.buildoptions import BuildOptions + + +def load_library(basename): + """Find and load the library with the given base name.""" + path = find_library(basename) + + # If the library was not found anywhere in the default locations, also search + # for it in the build directory + if path is None: + # pylint: disable=protected-access + for d in glob("%s/lib/*/.libs" % BuildOptions._BUILD_DIR): + path = "%s/lib%s.so" % (d, basename) + + if os.path.exists(path): + break + + path = None + + if path is None: + raise FileNotFoundError(basename) + + return ctypes.cdll.LoadLibrary(path) + + +_libcrmcommon = load_library("crmcommon") +_libcrmcommon.crm_exit_str.restype = ctypes.c_char_p diff --git a/python/pacemaker/exitstatus.py b/python/pacemaker/exitstatus.py index 7294d518e7..03f7d2c8e2 100644 --- a/python/pacemaker/exitstatus.py +++ b/python/pacemaker/exitstatus.py @@ -1,62 +1,68 @@ """A module providing constants relating to why a process or function exited.""" __all__ = ["ExitStatus"] __copyright__ = "Copyright 2023-2024 the Pacemaker project contributors" __license__ = "GNU Lesser General Public License version 2.1 or later (LGPLv2.1+)" from enum import IntEnum, unique +from pacemaker._library import _libcrmcommon + # These values must be kept in sync with include/crm/common/results.h @unique class ExitStatus(IntEnum): """ Exit status codes for a function or process. These constants describe both success and failure conditions. """ OK = 0 ERROR = 1 INVALID_PARAM = 2 UNIMPLEMENT_FEATURE = 3 INSUFFICIENT_PRIV = 4 NOT_INSTALLED = 5 NOT_CONFIGURED = 6 NOT_RUNNING = 7 PROMOTED = 8 FAILED_PROMOTED = 9 USAGE = 64 DATAERR = 65 NOINPUT = 66 NOUSER = 67 NOHOST = 68 UNAVAILABLE = 69 SOFTWARE = 70 OSERR = 71 OSFILE = 72 CANTCREAT = 73 IOERR = 74 TEMPFAIL = 75 PROTOCOL = 76 NOPERM = 77 CONFIG = 78 FATAL = 100 PANIC = 101 DISCONNECT = 102 OLD = 103 DIGEST = 104 NOSUCH = 105 QUORUM = 106 UNSAFE = 107 EXISTS = 108 MULTIPLE = 109 EXPIRED = 110 NOT_YET_IN_EFFECT = 111 INDETERMINATE = 112 UNSATISFIED = 113 TIMEOUT = 124 DEGRADED = 190 DEGRADED_PROMOTED = 191 NONE = 193 MAX = 255 + + def __str__(self): + """Given an ExitStatus, return the matching error string.""" + return _libcrmcommon.crm_exit_str(self.value).decode()