Files
scylladb/test/alternator/run
Nadav Har'El a896e2dbb9 alternator: add optional support for writing to system table
In commit 44a1daf we added the ability to read system tables through
the DynamoDB API (actually, the Scan and Query requests only).
This ability is useful for tests, and can also be useful to users who
want to read information that is only available through system tables.

This patch adds support also for *writing* into system tables. This will
be useful for Alternator tests, were we want to temporarily change
some live-updatable configuration option - and so far haven't been
able to do that like we did do in some cql-pytest tests.

For reasons explained in issue #23218, only superuser roles are allowed to
write to system tables - it is not enough for the role to be granted
MODIFY permissions on the system table or on ALL KEYSPACES. Moreover,
the ability to modify system tables carries special risks, so this
patch only allows writes to the system tables if a new configuration
option "alternator_allow_system_table_write" turned on. This option is
turned off by default.

This patch also includes a test for this new configuration-writing
capability. The test scripts test/alternator/run and test.py now
run Scylla with alternator_allow_system_table_write turned on, but
the new test can also run without this option, and will be skipped
in that case (to allow running the test suite against some manually-
run instance of Scylla).

Fixes: #12348

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
2025-08-06 10:00:04 +03:00

140 lines
5.4 KiB
Python
Executable File

#!/usr/bin/env python3
# Use the run.py library from ../cqlpy:
import sys
sys.path.insert(1, sys.path[0] + '/../cqlpy')
import run
import os
import requests
import time
import cassandra.cluster
import cassandra.auth
# When tests are to be run against AWS (the "--aws" option), it is not
# necessary to start Scylla at all. All we need to do is to run pytest.
if '--aws' in sys.argv:
success = run.run_pytest(sys.path[0], sys.argv[1:])
exit(0 if success else 1)
# check_alternator() below uses verify=False to accept self-signed SSL
# certificates but then we get scary warnings. This trick disables them:
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# If the first option is "--release", download that release (see
# fetch_scylla.py for supported release numbers), and use that.
# The downloaded Scylla will be cached in the directory build/<release>,
# where <release> is the specific release downloaded - E.g., if the user
# asks "--release 2022.1" and the downloaded release is 2022.1.9, it
# will be stored in build/2022.1.9.
if len(sys.argv) > 1 and sys.argv[1] == '--release':
release = sys.argv[2]
exe = run.download_precompiled_scylla(release)
run_scylla_cmd = lambda pid, dir: run.run_precompiled_scylla_cmd(exe, pid, dir)
sys.argv = sys.argv[0:1] + sys.argv[3:]
os.environ['SCYLLA'] = exe # so find_scylla() prints the right one
else:
run_scylla_cmd = run.run_scylla_cmd
print('Scylla is: ' + run.find_scylla() + '.')
extra_scylla_options = []
remove_scylla_options = []
# If the "--vnodes" option is given, drop the "tablets" experimental
# feature (turned on in run.py) so that all tests will be run with the
# old vnode-based replication instead of tablets. This option only has
# temporary usefulness, and should eventually be removed.
if '--vnodes' in sys.argv:
sys.argv.remove('--vnodes')
remove_scylla_options.append('--enable-tablets=true')
# Tablets are now enabled by default on some releases, it is not enough to remove the enable above.
extra_scylla_options.append('--enable-tablets=false')
if "-h" in sys.argv or "--help" in sys.argv:
run.run_pytest(sys.path[0], sys.argv)
exit(0)
# run_alternator_cmd runs the same as run_scylla_cmd with *additional*
# parameters, so in particular both CQL and Alternator will be enabled.
# This is useful for us because we need CQL to setup authentication.
def run_alternator_cmd(pid, dir):
(cmd, env) = run_scylla_cmd(pid, dir)
ip = run.pid_to_ip(pid)
cmd += [
'--alternator-address', ip,
'--alternator-enforce-authorization', '1',
'--alternator-write-isolation', 'only_rmw_uses_lwt',
'--alternator-streams-time-window-s', '0',
'--alternator-timeout-in-ms', '30000',
'--alternator-ttl-period-in-seconds', '0.5',
'--alternator-allow-system-table-write=1',
# Allow testing experimental features. Following issue #9467, we need
# to add here specific experimental features as they are introduced.
# We only list here Alternator-specific experimental features - CQL
# ones are listed in test/cqlpy/run.py.
'--experimental-features=alternator-streams',
]
if '--https' in sys.argv:
run.setup_ssl_certificate(dir)
cmd += ['--alternator-https-port', '8043',
'--alternator-encryption-options', f'keyfile={dir}/scylla.key',
'--alternator-encryption-options', f'certificate={dir}/scylla.crt',
]
else:
cmd += ['--alternator-port', '8000']
cmd += extra_scylla_options
for i in remove_scylla_options:
cmd.remove(i)
# Unfortunately, earlier Scylla versions required different command line
# options to run, so for some old versions we need to drop some of the
# command line options added above, or add more options. In cqlpy/run.py's
# run_precompiled_scylla_cmd we already do this for most Scylla options,
# but here we just need to take care of the Alternator-specific options
# that we added here and were different in older versions.
if 'release' in globals():
version = release.split('~')[0].split('.')
major = [int(version[0]), int(version[1])]
print(major)
if major < [2025,4]:
cmd.remove('--alternator-allow-system-table-write=1')
return (cmd, env)
pid = run.run_with_temporary_dir(run_alternator_cmd)
ip = run.pid_to_ip(pid)
if '--https' in sys.argv:
alternator_url=f"https://{ip}:8043"
else:
alternator_url=f"http://{ip}:8000"
# Wait for both CQL and Alternator APIs to become responsive. We obviously
# need the Alternator API to test Alternator, but currently we also need
# CQL for setting up authentication.
def check_alternator(url):
try:
requests.get(url, verify=False)
except requests.ConnectionError:
raise run.NotYetUp
# Any other exception may indicate a problem, and is passed to the caller.
run.wait_for_services(pid, [
lambda: run.check_cql(ip),
lambda: check_alternator(alternator_url),
])
# Finally run pytest:
success = run.run_pytest(sys.path[0], ['--url', alternator_url] + sys.argv[1:])
run.summary = 'Alternator tests pass' if success else 'Alternator tests failure'
exit(0 if success else 1)
# Note that the run.cleanup_all() function runs now, just like on any exit
# for any reason in this script. It will delete the temporary files and
# announce the failure or success of the test (printing run.summary).