diff --git a/.gitignore b/.gitignore index 5e54c62c7a..67bce955ef 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ stamp-h1 /libpromises/Makefile /misc/Makefile /misc/selinux/Makefile +/python/Makefile /tests/Makefile /tests/acceptance/25_cf-execd/Makefile /tests/acceptance/Makefile diff --git a/Makefile.am b/Makefile.am index cb35cd24dd..a964a7357b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,6 +46,7 @@ SUBDIRS = \ cf-net \ cf-secret \ misc \ + python \ ext \ examples \ tests \ diff --git a/configure.ac b/configure.ac index 71a9ff36c0..b4a71b40d3 100644 --- a/configure.ac +++ b/configure.ac @@ -1872,6 +1872,7 @@ AC_CONFIG_FILES([Makefile contrib/vagrant-ci/centos-7-x64/Makefile misc/Makefile misc/selinux/Makefile + python/Makefile ext/Makefile examples/Makefile tests/Makefile diff --git a/python/Makefile.am b/python/Makefile.am new file mode 100644 index 0000000000..fe2e898f4c --- /dev/null +++ b/python/Makefile.am @@ -0,0 +1,33 @@ +# +# Copyright 2024 Northern.tech AS +# +# This file is part of CFEngine 3 - written and maintained by Northern.tech AS. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA +# +# To the extent this program is licensed as part of the Enterprise +# versions of CFEngine, the applicable Commercial Open Source License +# (COSL) may apply to this file if you as a licensee so wish it. See +# included file COSL.txt. +# + +pythonbindingsdir = $(libdir)/python +dist_pythonbindings_DATA = README + +if !NDEBUG +if LINUX +# The dbm_test_api is only compile in on Linux in debug builds. +dist_pythonbindings_DATA += test_cfe_db.py +endif +endif diff --git a/python/README b/python/README new file mode 100644 index 0000000000..6a58c63851 --- /dev/null +++ b/python/README @@ -0,0 +1,10 @@ +This directory contains Python packages and modules for working with CFEngine +and its libraries. + +If you want to use one of these, PYTHONPATH and LD_LIBRARY_PATH variables can +make things easier when used like this: + + PYTHONPATH=/var/cfengine/lib/python LD_LIBRARY_PATH=/var/cfengine/lib python3 + +That will make sure that the bindings are found by Python and that CFEngine's +libraries are found by dlopen() (used by ctypes.CDLL() etc.). diff --git a/python/test_cfe_db.py b/python/test_cfe_db.py new file mode 100644 index 0000000000..ccb14eab28 --- /dev/null +++ b/python/test_cfe_db.py @@ -0,0 +1,76 @@ +import ctypes + +# Based on the dbid enum from libpromises/dbm_api.h +dbs = ( + "classes", # Deprecated + "variables", # Deprecated + "performance", + "checksums", # Deprecated + "filestats", # Deprecated + "changes", + "observations", + "state", + "lastseen", + "audit", + "locks", + "history", + "measure", + "static", + "scalars", + "windows_registry", + "cache", + "license", + "value", + "agent_execution", + "bundles", # Deprecated + "packages_installed", # new package promise installed packages list + "packages_updates", # new package promise list of available updates + "cookies", # Enterprise reporting cookies for duplicate host detection +) + +def get_db_id(db_name): + return dbs.index(db_name) + + +class _SimulationStruct(ctypes.Structure): + pass + +class _FilamentStruct(ctypes.Structure): + pass + +_promises = ctypes.CDLL("libpromises.so.3.0.6") + +_promises.SimulateDBLoad.restype = ctypes.POINTER(_SimulationStruct) +_promises.SimulateDBLoad.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_long, ctypes.c_long, + ctypes.c_int, ctypes.c_int, ctypes.c_long, ctypes.c_long, + ctypes.c_long, ctypes.c_long] +def SimulateDBLoad(db_id, + read_keys_refresh_s=5, + read_min_interval_ms=100, + read_max_interval_ms=200, + write_sample_size_pct=50, + write_prune_interval_s=10, + write_min_interval_ms=200, + write_max_interval_ms=400, + iter_min_interval_ms=1000, + iter_max_interval_ms=2000): + return _promises.SimulateDBLoad(db_id, + read_keys_refresh_s, read_min_interval_ms, read_max_interval_ms, + write_sample_size_pct, + write_prune_interval_s, write_min_interval_ms, write_max_interval_ms, + iter_min_interval_ms, iter_max_interval_ms) + +_promises.StopSimulation.restype = None # void +_promises.StopSimulation.argtypes = [ctypes.POINTER(_SimulationStruct)] +def StopSimulation(simulation): + _promises.StopSimulation(simulation) + +_promises.FillUpDB.restype = ctypes.POINTER(_FilamentStruct) +_promises.FillUpDB.argtypes = [ctypes.c_int, ctypes.c_int] +def FillUpDB(db_id, usage): + return _promises.FillUpDB(db_id, usage) + +_promises.RemoveFilament.restype = None # void +_promises.RemoveFilament.argtypes = [ctypes.POINTER(_FilamentStruct)] +def RemoveFilament(filament): + _promises.RemoveFilament(filament)