let's just use cluster.contact_points for retrieving the IP address of the scylla node in this single-node cluster. so the name of managed_cluster() is less weird. Signed-off-by: Kefu Chai <kefu.chai@scylladb.com>
147 lines
5.3 KiB
Python
147 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
# Use the run.py library from ../cql-pytest:
|
|
import sys
|
|
sys.path.insert(1, sys.path[0] + '/../cql-pytest')
|
|
import run
|
|
from util import format_tuples
|
|
|
|
import os
|
|
import requests
|
|
import signal
|
|
import yaml
|
|
import pytest
|
|
|
|
from contextlib import contextmanager
|
|
|
|
def get_scylla_with_s3_cmd(tempdir, ssl, s3_server):
|
|
'''return the command args and environmental variables for running scylla'''
|
|
scylla = run.find_scylla()
|
|
print('Scylla under test:', scylla)
|
|
def make_run_cmd(pid, d):
|
|
if ssl:
|
|
cmd, env = run.run_scylla_ssl_cql_cmd(pid, d)
|
|
else:
|
|
cmd, env = run.run_scylla_cmd(pid, d)
|
|
|
|
os_conf_path = os.path.join(tempdir, 'object_storage.yaml')
|
|
with open(os_conf_path, 'w', encoding='utf-8') as os_config_file:
|
|
s3_endpoint = {'name': s3_server.address,
|
|
'port': s3_server.port}
|
|
yaml.dump({'endpoints': [s3_endpoint]}, os_config_file)
|
|
cmd += ['--object-storage-config-file', os_conf_path]
|
|
return cmd, env
|
|
return make_run_cmd
|
|
|
|
|
|
def check_with_cql(ip, ssl):
|
|
'''return a checker which checks the readiness of scylla'''
|
|
def checker():
|
|
if ssl:
|
|
return run.check_ssl_cql(ip)
|
|
else:
|
|
return run.check_cql(ip)
|
|
return checker
|
|
|
|
|
|
def run_with_dir(run_cmd_gen, run_dir):
|
|
print(f'Start scylla (dir={run_dir}')
|
|
mask = signal.pthread_sigmask(signal.SIG_BLOCK, {})
|
|
signal.pthread_sigmask(signal.SIG_BLOCK, {signal.SIGINT, signal.SIGQUIT, signal.SIGTERM})
|
|
sys.stdout.flush()
|
|
sys.stderr.flush()
|
|
pid = os.fork()
|
|
if pid == 0:
|
|
# child
|
|
cmd, env = run_cmd_gen(os.getpid(), run_dir)
|
|
log = os.path.join(run_dir, 'log')
|
|
log_fd = os.open(log, os.O_WRONLY | os.O_CREAT | os.O_APPEND, mode=0o666)
|
|
# redirect stdout and stderr to log file
|
|
for output in [sys.stdout, sys.stderr]:
|
|
output.flush()
|
|
output_fd = output.fileno()
|
|
os.close(output_fd)
|
|
os.dup2(log_fd, output_fd)
|
|
os.setsid()
|
|
os.execve(cmd[0], cmd, dict(os.environ, **env))
|
|
# parent
|
|
signal.pthread_sigmask(signal.SIG_SETMASK, mask)
|
|
return pid
|
|
|
|
|
|
def kill_with_dir(old_pid, run_dir):
|
|
try:
|
|
print('Kill scylla')
|
|
os.killpg(old_pid, 2)
|
|
os.waitpid(old_pid, 0)
|
|
except ProcessLookupError:
|
|
pass
|
|
scylla_link = os.path.join(run_dir, 'test_scylla')
|
|
os.unlink(scylla_link)
|
|
|
|
|
|
@contextmanager
|
|
def managed_cluster(run_dir, ssl, s3_server):
|
|
'''return scylla's pid, IP and a connection to it'''
|
|
run_scylla_cmd = get_scylla_with_s3_cmd(run_dir, ssl, s3_server)
|
|
pid = run_with_dir(run_scylla_cmd, run_dir)
|
|
ip = run.pid_to_ip(pid)
|
|
run.wait_for_services(pid, [check_with_cql(ip, ssl)])
|
|
cluster = run.get_cql_cluster(ip)
|
|
try:
|
|
yield cluster
|
|
finally:
|
|
cluster.shutdown()
|
|
kill_with_dir(pid, run_dir)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_basic(test_tempdir, s3_server, ssl):
|
|
'''verify ownership table is updated, and tables written to S3 can be read after scylla restarts'''
|
|
ks = 'test_ks'
|
|
cf = 'test_cf'
|
|
rows = [('0', 'zero'),
|
|
('1', 'one'),
|
|
('2', 'two')]
|
|
|
|
with managed_cluster(test_tempdir, ssl, s3_server) as cluster:
|
|
print(f'Create keyspace (minio listening at {s3_server.address})')
|
|
replication_opts = format_tuples({'class': 'NetworkTopologyStrategy',
|
|
'replication_factor': '1'})
|
|
storage_opts = format_tuples(type='S3',
|
|
endpoint=s3_server.address,
|
|
bucket=s3_server.bucket_name)
|
|
|
|
conn = cluster.connect()
|
|
conn.execute((f"CREATE KEYSPACE {ks} WITH"
|
|
f" REPLICATION = {replication_opts} AND STORAGE = {storage_opts};"))
|
|
conn.execute(f"CREATE TABLE {ks}.{cf} ( name text primary key, value text );")
|
|
for row in rows:
|
|
cql_fmt = "INSERT INTO {}.{} ( name, value ) VALUES ('{}', '{}');"
|
|
conn.execute(cql_fmt.format(ks, cf, *row))
|
|
res = conn.execute(f"SELECT * FROM {ks}.{cf};")
|
|
|
|
ip = cluster.contact_points[0]
|
|
r = requests.post(f'http://{ip}:10000/storage_service/keyspace_flush/{ks}', timeout=60)
|
|
assert r.status_code == 200, f"Error flushing keyspace: {r}"
|
|
|
|
# Check that the ownership table is populated properly
|
|
res = conn.execute("SELECT * FROM system.sstables;")
|
|
for row in res:
|
|
assert row.location.startswith(test_tempdir), \
|
|
f'Unexpected entry location in registry: {row.location}'
|
|
assert row.status == 'sealed', f'Unexpected entry status in registry: {row.status}'
|
|
|
|
print('Restart scylla')
|
|
with managed_cluster(test_tempdir, ssl, s3_server) as cluster:
|
|
conn = cluster.connect()
|
|
res = conn.execute(f"SELECT * FROM {ks}.{cf};")
|
|
have_res = { x.name: x.value for x in res }
|
|
assert have_res == dict(rows), f'Unexpected table content: {have_res}'
|
|
|
|
print('Drop table')
|
|
conn.execute(f"DROP TABLE {ks}.{cf};")
|
|
# Check that the ownership table is de-populated
|
|
res = conn.execute("SELECT * FROM system.sstables;")
|
|
rows = "\n".join(f"{row.location} {row.status}" for row in res)
|
|
assert not rows, 'Unexpected entries in registry'
|