test: Use in-memory SQLite for PyKMIP server

The PyKMIP server uses an SQLite database to store artifacts such as
encryption keys. By default, SQLite performs a full journal and data
flush to disk on every CREATE TABLE operation. Each operation triggers
three fdatasync(2) calls. If we multiply this by 16, that is the number
of tables created by the server, we get a significant number of file
syncs, which can last for several seconds on slow machines.

This behavior has led to CI stability issues from KMIP unit tests where
the server failed to complete its schema creation within the 20-second
timeout (observed on spider9 and spider11).

Fix this by configuring the server to use an in-memory SQLite.

Fixes #24842.

Signed-off-by: Nikos Dragazis <nikolaos.dragazis@scylladb.com>

Closes scylladb/scylladb#24995

(cherry picked from commit 2656fca504)

Closes scylladb/scylladb#25300
This commit is contained in:
Nikos Dragazis
2025-07-15 21:08:20 +03:00
committed by Avi Kivity
parent 7aa7f50b3a
commit 257ebbeca9
2 changed files with 33 additions and 5 deletions

View File

@@ -358,8 +358,8 @@ auth_suite=TLS1.2
policy_path={}
enable_tls_client_auth=False
logging_level=DEBUG
database_path={}/pykmip.db
)foo", info.cert, info.key, info.ca, tmp.path().string(), tmp.path().string());
database_path=:memory:
)foo", info.cert, info.key, info.ca, tmp.path().string());
auto cfgfile = fmt::format("{}/pykmip.conf", tmp.path().string());
auto log = fmt::format("{}/pykmip.log", tmp.path().string());

View File

@@ -1,13 +1,39 @@
import ssl
import sys
import functools
import sqlalchemy
from sqlalchemy.pool import StaticPool
from kmip.services import auth
from kmip.services.server.server import build_argument_parser
from kmip.services.server.server import KmipServer
# Helper wrapper for running pykmip in scylla testing. Needed because TLS options
# (hardcoded) in pykmip are obsolete and will not work with connecting using gnutls
# of any modern variety.
# Helper wrapper for running pykmip in scylla testing. Needed for the following
# reasons:
#
# * TLS options (hardcoded) in pykmip are obsolete and will not work with
# connecting using gnutls of any modern variety.
#
# * We need to use an in-memory SQLite database for testing (file-based SQLite
# issues many fdatasync's which have been proven to reduce CI stability in
# some slow machines). An in-memory SQLite database is bound to a single
# connection. In order to share it among multiple threads, the connection
# itself must be shared. We achieve that with the StaticPool.
# https://docs.sqlalchemy.org/en/20/dialects/sqlite.html#using-a-memory-database-in-multiple-threads
def monkey_patch_create_engine():
original_create_engine = sqlalchemy.create_engine
@functools.wraps(original_create_engine)
def patched_create_engine(*args, **kwargs):
if args and isinstance(args[0], str) and args[0].startswith('sqlite:///:memory:'):
kwargs['poolclass'] = StaticPool
return original_create_engine(*args, **kwargs)
sqlalchemy.create_engine = patched_create_engine
class TLS13AuthenticationSuite(auth.TLS12AuthenticationSuite):
"""
@@ -60,6 +86,8 @@ def main():
kwargs['live_policies'] = True
monkey_patch_create_engine()
# Create and start the server.
s = KmipServer(**kwargs)
# Fix TLS. Try to get this into mainline project, but that will take time...