mTLS test helpers (#7218)
* Add TLS option to (local_cluster|tmp_cluster).py * Add TLS-enabled C API test
This commit is contained in:
parent
c073f113a5
commit
02b2f97e99
|
@ -301,6 +301,31 @@ endif()
|
||||||
@LOG_DIR@
|
@LOG_DIR@
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_fdbclient_test(
|
||||||
|
NAME fdb_c_api_tests_with_tls
|
||||||
|
DISABLE_LOG_DUMP
|
||||||
|
TLS_ENABLED
|
||||||
|
COMMAND ${CMAKE_SOURCE_DIR}/bindings/c/test/apitester/run_c_api_tests.py
|
||||||
|
--cluster-file
|
||||||
|
@CLUSTER_FILE@
|
||||||
|
--tester-binary
|
||||||
|
$<TARGET_FILE:fdb_c_api_tester>
|
||||||
|
--external-client-library
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/libfdb_c_external.so
|
||||||
|
--test-dir
|
||||||
|
${CMAKE_SOURCE_DIR}/bindings/c/test/apitester/tests
|
||||||
|
--tmp-dir
|
||||||
|
@TMP_DIR@
|
||||||
|
--log-dir
|
||||||
|
@LOG_DIR@
|
||||||
|
--tls-cert-file
|
||||||
|
@CLIENT_CERT_FILE@
|
||||||
|
--tls-key-file
|
||||||
|
@CLIENT_KEY_FILE@
|
||||||
|
--tls-ca-file
|
||||||
|
@SERVER_CA_FILE@
|
||||||
|
)
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT USE_SANITIZER)
|
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT USE_SANITIZER)
|
||||||
add_test(NAME fdb_c_upgrade_single_threaded_630api
|
add_test(NAME fdb_c_upgrade_single_threaded_630api
|
||||||
COMMAND ${CMAKE_SOURCE_DIR}/tests/TestRunner/upgrade_test.py
|
COMMAND ${CMAKE_SOURCE_DIR}/tests/TestRunner/upgrade_test.py
|
||||||
|
|
|
@ -52,6 +52,9 @@ public:
|
||||||
std::vector<std::pair<std::string, std::string>> knobs;
|
std::vector<std::pair<std::string, std::string>> knobs;
|
||||||
TestSpec testSpec;
|
TestSpec testSpec;
|
||||||
std::string bgBasePath;
|
std::string bgBasePath;
|
||||||
|
std::string tlsCertFile;
|
||||||
|
std::string tlsKeyFile;
|
||||||
|
std::string tlsCaFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace FdbApiTester
|
} // namespace FdbApiTester
|
||||||
|
|
|
@ -54,7 +54,10 @@ enum TesterOptionId {
|
||||||
OPT_FDB_API_VERSION,
|
OPT_FDB_API_VERSION,
|
||||||
OPT_TRANSACTION_RETRY_LIMIT,
|
OPT_TRANSACTION_RETRY_LIMIT,
|
||||||
OPT_BLOB_GRANULE_LOCAL_FILE_PATH,
|
OPT_BLOB_GRANULE_LOCAL_FILE_PATH,
|
||||||
OPT_STATS_INTERVAL
|
OPT_STATS_INTERVAL,
|
||||||
|
OPT_TLS_CERT_FILE,
|
||||||
|
OPT_TLS_KEY_FILE,
|
||||||
|
OPT_TLS_CA_FILE,
|
||||||
};
|
};
|
||||||
|
|
||||||
CSimpleOpt::SOption TesterOptionDefs[] = //
|
CSimpleOpt::SOption TesterOptionDefs[] = //
|
||||||
|
@ -79,6 +82,9 @@ CSimpleOpt::SOption TesterOptionDefs[] = //
|
||||||
{ OPT_TRANSACTION_RETRY_LIMIT, "--transaction-retry-limit", SO_REQ_SEP },
|
{ OPT_TRANSACTION_RETRY_LIMIT, "--transaction-retry-limit", SO_REQ_SEP },
|
||||||
{ OPT_BLOB_GRANULE_LOCAL_FILE_PATH, "--blob-granule-local-file-path", SO_REQ_SEP },
|
{ OPT_BLOB_GRANULE_LOCAL_FILE_PATH, "--blob-granule-local-file-path", SO_REQ_SEP },
|
||||||
{ OPT_STATS_INTERVAL, "--stats-interval", SO_REQ_SEP },
|
{ OPT_STATS_INTERVAL, "--stats-interval", SO_REQ_SEP },
|
||||||
|
{ OPT_TLS_CERT_FILE, "--tls-cert-file", SO_REQ_SEP },
|
||||||
|
{ OPT_TLS_KEY_FILE, "--tls-key-file", SO_REQ_SEP },
|
||||||
|
{ OPT_TLS_CA_FILE, "--tls-ca-file", SO_REQ_SEP },
|
||||||
SO_END_OF_OPTIONS };
|
SO_END_OF_OPTIONS };
|
||||||
|
|
||||||
void printProgramUsage(const char* execName) {
|
void printProgramUsage(const char* execName) {
|
||||||
|
@ -122,6 +128,12 @@ void printProgramUsage(const char* execName) {
|
||||||
" Test file to run.\n"
|
" Test file to run.\n"
|
||||||
" --stats-interval MILLISECONDS\n"
|
" --stats-interval MILLISECONDS\n"
|
||||||
" Time interval in milliseconds for printing workload statistics (default: 0 - disabled).\n"
|
" Time interval in milliseconds for printing workload statistics (default: 0 - disabled).\n"
|
||||||
|
" --tls-cert-file FILE\n"
|
||||||
|
" Path to file containing client's TLS certificate chain\n"
|
||||||
|
" --tls-key-file FILE\n"
|
||||||
|
" Path to file containing client's TLS private key\n"
|
||||||
|
" --tls-ca-file FILE\n"
|
||||||
|
" Path to file containing TLS CA certificate\n"
|
||||||
" -h, --help Display this help and exit.\n",
|
" -h, --help Display this help and exit.\n",
|
||||||
FDB_API_VERSION);
|
FDB_API_VERSION);
|
||||||
}
|
}
|
||||||
|
@ -221,6 +233,15 @@ bool processArg(TesterOptions& options, const CSimpleOpt& args) {
|
||||||
case OPT_STATS_INTERVAL:
|
case OPT_STATS_INTERVAL:
|
||||||
processIntOption(args.OptionText(), args.OptionArg(), 0, 60000, options.statsIntervalMs);
|
processIntOption(args.OptionText(), args.OptionArg(), 0, 60000, options.statsIntervalMs);
|
||||||
break;
|
break;
|
||||||
|
case OPT_TLS_CERT_FILE:
|
||||||
|
options.tlsCertFile.assign(args.OptionArg());
|
||||||
|
break;
|
||||||
|
case OPT_TLS_KEY_FILE:
|
||||||
|
options.tlsKeyFile.assign(args.OptionArg());
|
||||||
|
break;
|
||||||
|
case OPT_TLS_CA_FILE:
|
||||||
|
options.tlsCaFile.assign(args.OptionArg());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -299,6 +320,18 @@ void applyNetworkOptions(TesterOptions& options) {
|
||||||
fdb_check(FdbApi::setOption(FDBNetworkOption::FDB_NET_OPTION_KNOB,
|
fdb_check(FdbApi::setOption(FDBNetworkOption::FDB_NET_OPTION_KNOB,
|
||||||
fmt::format("{}={}", knob.first.c_str(), knob.second.c_str())));
|
fmt::format("{}={}", knob.first.c_str(), knob.second.c_str())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options.tlsCertFile.empty()) {
|
||||||
|
fdb_check(FdbApi::setOption(FDBNetworkOption::FDB_NET_OPTION_TLS_CERT_PATH, options.tlsCertFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.tlsKeyFile.empty()) {
|
||||||
|
fdb_check(FdbApi::setOption(FDBNetworkOption::FDB_NET_OPTION_TLS_KEY_PATH, options.tlsKeyFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.tlsCaFile.empty()) {
|
||||||
|
fdb_check(FdbApi::setOption(FDBNetworkOption::FDB_NET_OPTION_TLS_CA_PATH, options.tlsCaFile));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void randomizeOptions(TesterOptions& options) {
|
void randomizeOptions(TesterOptions& options) {
|
||||||
|
|
|
@ -84,6 +84,15 @@ def run_tester(args, test_file):
|
||||||
cmd += ["--blob-granule-local-file-path",
|
cmd += ["--blob-granule-local-file-path",
|
||||||
args.blob_granule_local_file_path]
|
args.blob_granule_local_file_path]
|
||||||
|
|
||||||
|
if args.tls_ca_file is not None:
|
||||||
|
cmd += ["--tls-ca-file", args.tls_ca_file]
|
||||||
|
|
||||||
|
if args.tls_key_file is not None:
|
||||||
|
cmd += ["--tls-key-file", args.tls_key_file]
|
||||||
|
|
||||||
|
if args.tls_cert_file is not None:
|
||||||
|
cmd += ["--tls-cert-file", args.tls_cert_file]
|
||||||
|
|
||||||
get_logger().info('\nRunning tester \'%s\'...' % ' '.join(cmd))
|
get_logger().info('\nRunning tester \'%s\'...' % ' '.join(cmd))
|
||||||
proc = Popen(cmd, stdout=sys.stdout, stderr=sys.stderr)
|
proc = Popen(cmd, stdout=sys.stdout, stderr=sys.stderr)
|
||||||
timed_out = False
|
timed_out = False
|
||||||
|
@ -149,6 +158,12 @@ def parse_args(argv):
|
||||||
help='The directory for storing temporary files (default: None)')
|
help='The directory for storing temporary files (default: None)')
|
||||||
parser.add_argument('--blob-granule-local-file-path', type=str, default=None,
|
parser.add_argument('--blob-granule-local-file-path', type=str, default=None,
|
||||||
help='Enable blob granule tests if set, value is path to local blob granule files')
|
help='Enable blob granule tests if set, value is path to local blob granule files')
|
||||||
|
parser.add_argument('--tls-ca-file', type=str, default=None,
|
||||||
|
help='Path to client\'s TLS CA file: i.e. certificate of CA that signed the server certificate')
|
||||||
|
parser.add_argument('--tls-cert-file', type=str, default=None,
|
||||||
|
help='Path to client\'s TLS certificate file')
|
||||||
|
parser.add_argument('--tls-key-file', type=str, default=None,
|
||||||
|
help='Path to client\'s TLS private key file')
|
||||||
|
|
||||||
return parser.parse_args(argv)
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
|
@ -404,8 +404,7 @@ endfunction()
|
||||||
|
|
||||||
# Creates a single cluster before running the specified command (usually a ctest test)
|
# Creates a single cluster before running the specified command (usually a ctest test)
|
||||||
function(add_fdbclient_test)
|
function(add_fdbclient_test)
|
||||||
set(options DISABLED ENABLED DISABLE_LOG_DUMP)
|
set(options DISABLED ENABLED DISABLE_LOG_DUMP API_TEST_BLOB_GRANULES_ENABLED TLS_ENABLED)
|
||||||
set(options DISABLED ENABLED API_TEST_BLOB_GRANULES_ENABLED)
|
|
||||||
set(oneValueArgs NAME PROCESS_NUMBER TEST_TIMEOUT WORKING_DIRECTORY)
|
set(oneValueArgs NAME PROCESS_NUMBER TEST_TIMEOUT WORKING_DIRECTORY)
|
||||||
set(multiValueArgs COMMAND)
|
set(multiValueArgs COMMAND)
|
||||||
cmake_parse_arguments(T "${options}" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
|
cmake_parse_arguments(T "${options}" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
|
||||||
|
@ -435,6 +434,9 @@ function(add_fdbclient_test)
|
||||||
if(T_API_TEST_BLOB_GRANULES_ENABLED)
|
if(T_API_TEST_BLOB_GRANULES_ENABLED)
|
||||||
list(APPEND TMP_CLUSTER_CMD --blob-granules-enabled)
|
list(APPEND TMP_CLUSTER_CMD --blob-granules-enabled)
|
||||||
endif()
|
endif()
|
||||||
|
if(T_TLS_ENABLED)
|
||||||
|
list(APPEND TMP_CLUSTER_CMD --tls-enabled)
|
||||||
|
endif()
|
||||||
message(STATUS "Adding Client test ${T_NAME}")
|
message(STATUS "Adding Client test ${T_NAME}")
|
||||||
add_test(NAME "${T_NAME}"
|
add_test(NAME "${T_NAME}"
|
||||||
WORKING_DIRECTORY ${T_WORKING_DIRECTORY}
|
WORKING_DIRECTORY ${T_WORKING_DIRECTORY}
|
||||||
|
|
|
@ -179,9 +179,6 @@ mkcert::CertChainRef ChainSpec::makeChain(Arena& arena) {
|
||||||
ofsCert.write(reinterpret_cast<char const*>(cert.begin()), cert.size());
|
ofsCert.write(reinterpret_cast<char const*>(cert.begin()), cert.size());
|
||||||
auto key = chain[0].privateKeyPem;
|
auto key = chain[0].privateKeyPem;
|
||||||
ofsKey.write(reinterpret_cast<char const*>(key.begin()), key.size());
|
ofsKey.write(reinterpret_cast<char const*>(key.begin()), key.size());
|
||||||
ofsCert.close();
|
|
||||||
ofsKey.close();
|
|
||||||
ofsCa.close();
|
|
||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,17 @@ def is_port_in_use(port):
|
||||||
|
|
||||||
valid_letters_for_secret = string.ascii_letters + string.digits
|
valid_letters_for_secret = string.ascii_letters + string.digits
|
||||||
|
|
||||||
|
class TLSConfig:
|
||||||
|
# Passing a negative chain length generates expired leaf certificate
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
server_chain_len: int = 3,
|
||||||
|
client_chain_len: int = 2,
|
||||||
|
verify_peers = "Check.Valid=1",
|
||||||
|
):
|
||||||
|
self.server_chain_len = server_chain_len
|
||||||
|
self.client_chain_len = client_chain_len
|
||||||
|
self.verify_peers = verify_peers
|
||||||
|
|
||||||
def random_secret_string(length):
|
def random_secret_string(length):
|
||||||
return "".join(random.choice(valid_letters_for_secret) for _ in range(length))
|
return "".join(random.choice(valid_letters_for_secret) for _ in range(length))
|
||||||
|
@ -67,11 +78,12 @@ cluster-file = {etcdir}/fdb.cluster
|
||||||
## Default parameters for individual fdbserver processes
|
## Default parameters for individual fdbserver processes
|
||||||
[fdbserver]
|
[fdbserver]
|
||||||
command = {fdbserver_bin}
|
command = {fdbserver_bin}
|
||||||
public-address = {ip_address}:$ID
|
public-address = {ip_address}:$ID{optional_tls}
|
||||||
listen-address = public
|
listen-address = public
|
||||||
datadir = {datadir}/$ID
|
datadir = {datadir}/$ID
|
||||||
logdir = {logdir}
|
logdir = {logdir}
|
||||||
{bg_knob_line}
|
{bg_knob_line}
|
||||||
|
{tls_config}
|
||||||
# logsize = 10MiB
|
# logsize = 10MiB
|
||||||
# maxlogssize = 100MiB
|
# maxlogssize = 100MiB
|
||||||
# machine-id =
|
# machine-id =
|
||||||
|
@ -98,12 +110,15 @@ logdir = {logdir}
|
||||||
port=None,
|
port=None,
|
||||||
ip_address=None,
|
ip_address=None,
|
||||||
blob_granules_enabled: bool = False,
|
blob_granules_enabled: bool = False,
|
||||||
redundancy: str = "single"
|
redundancy: str = "single",
|
||||||
|
tls_config: TLSConfig = None,
|
||||||
|
mkcert_binary: str = "",
|
||||||
):
|
):
|
||||||
self.basedir = Path(basedir)
|
self.basedir = Path(basedir)
|
||||||
self.etc = self.basedir.joinpath("etc")
|
self.etc = self.basedir.joinpath("etc")
|
||||||
self.log = self.basedir.joinpath("log")
|
self.log = self.basedir.joinpath("log")
|
||||||
self.data = self.basedir.joinpath("data")
|
self.data = self.basedir.joinpath("data")
|
||||||
|
self.cert = self.basedir.joinpath("cert")
|
||||||
self.conf_file = self.etc.joinpath("foundationdb.conf")
|
self.conf_file = self.etc.joinpath("foundationdb.conf")
|
||||||
self.cluster_file = self.etc.joinpath("fdb.cluster")
|
self.cluster_file = self.etc.joinpath("fdb.cluster")
|
||||||
self.fdbserver_binary = Path(fdbserver_binary)
|
self.fdbserver_binary = Path(fdbserver_binary)
|
||||||
|
@ -137,11 +152,22 @@ logdir = {logdir}
|
||||||
self.use_legacy_conf_syntax = False
|
self.use_legacy_conf_syntax = False
|
||||||
self.coordinators = set()
|
self.coordinators = set()
|
||||||
self.active_servers = set(self.server_ports.keys())
|
self.active_servers = set(self.server_ports.keys())
|
||||||
|
self.tls_config = tls_config
|
||||||
|
self.mkcert_binary = Path(mkcert_binary)
|
||||||
|
self.server_cert_file = self.cert.joinpath("server_cert.pem")
|
||||||
|
self.client_cert_file = self.cert.joinpath("client_cert.pem")
|
||||||
|
self.server_key_file = self.cert.joinpath("server_key.pem")
|
||||||
|
self.client_key_file = self.cert.joinpath("client_key.pem")
|
||||||
|
self.server_ca_file = self.cert.joinpath("server_ca.pem")
|
||||||
|
self.client_ca_file = self.cert.joinpath("client_ca.pem")
|
||||||
|
|
||||||
if create_config:
|
if create_config:
|
||||||
self.create_cluster_file()
|
self.create_cluster_file()
|
||||||
self.save_config()
|
self.save_config()
|
||||||
|
|
||||||
|
if self.tls_config is not None:
|
||||||
|
self.create_tls_cert()
|
||||||
|
|
||||||
def __next_port(self):
|
def __next_port(self):
|
||||||
if self.first_port is None:
|
if self.first_port is None:
|
||||||
return get_free_port()
|
return get_free_port()
|
||||||
|
@ -166,6 +192,8 @@ logdir = {logdir}
|
||||||
logdir=self.log,
|
logdir=self.log,
|
||||||
ip_address=self.ip_address,
|
ip_address=self.ip_address,
|
||||||
bg_knob_line=bg_knob_line,
|
bg_knob_line=bg_knob_line,
|
||||||
|
tls_config=self.tls_conf_string(),
|
||||||
|
optional_tls=":tls" if self.tls_config is not None else "",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# By default, the cluster only has one process
|
# By default, the cluster only has one process
|
||||||
|
@ -190,11 +218,12 @@ logdir = {logdir}
|
||||||
def create_cluster_file(self):
|
def create_cluster_file(self):
|
||||||
with open(self.cluster_file, "x") as f:
|
with open(self.cluster_file, "x") as f:
|
||||||
f.write(
|
f.write(
|
||||||
"{desc}:{secret}@{ip_addr}:{server_port}".format(
|
"{desc}:{secret}@{ip_addr}:{server_port}{optional_tls}".format(
|
||||||
desc=self.cluster_desc,
|
desc=self.cluster_desc,
|
||||||
secret=self.cluster_secret,
|
secret=self.cluster_secret,
|
||||||
ip_addr=self.ip_address,
|
ip_addr=self.ip_address,
|
||||||
server_port=self.server_ports[0],
|
server_port=self.server_ports[0],
|
||||||
|
optional_tls=":tls" if self.tls_config is not None else "",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.coordinators = {0}
|
self.coordinators = {0}
|
||||||
|
@ -248,6 +277,10 @@ logdir = {logdir}
|
||||||
|
|
||||||
def __fdbcli_exec(self, cmd, stdout, stderr, timeout):
|
def __fdbcli_exec(self, cmd, stdout, stderr, timeout):
|
||||||
args = [self.fdbcli_binary, "-C", self.cluster_file, "--exec", cmd]
|
args = [self.fdbcli_binary, "-C", self.cluster_file, "--exec", cmd]
|
||||||
|
if self.tls_config:
|
||||||
|
args += ["--tls-certificate-file", self.client_cert_file,
|
||||||
|
"--tls-key-file", self.client_key_file,
|
||||||
|
"--tls-ca-file", self.server_ca_file]
|
||||||
res = subprocess.run(args, env=self.process_env(), stderr=stderr, stdout=stdout, timeout=timeout)
|
res = subprocess.run(args, env=self.process_env(), stderr=stderr, stdout=stdout, timeout=timeout)
|
||||||
assert res.returncode == 0, "fdbcli command {} failed with {}".format(cmd, res.returncode)
|
assert res.returncode == 0, "fdbcli command {} failed with {}".format(cmd, res.returncode)
|
||||||
return res.stdout
|
return res.stdout
|
||||||
|
@ -271,6 +304,46 @@ logdir = {logdir}
|
||||||
if self.blob_granules_enabled:
|
if self.blob_granules_enabled:
|
||||||
self.fdbcli_exec("blobrange start \\x00 \\xff")
|
self.fdbcli_exec("blobrange start \\x00 \\xff")
|
||||||
|
|
||||||
|
# Generate and install test certificate chains and keys
|
||||||
|
def create_tls_cert(self):
|
||||||
|
assert self.tls_config is not None, "TLS not enabled"
|
||||||
|
assert self.mkcert_binary.exists() and self.mkcert_binary.is_file(), "{} does not exist".format(self.mkcert_binary)
|
||||||
|
self.cert.mkdir(exist_ok=True)
|
||||||
|
server_chain_len = abs(self.tls_config.server_chain_len)
|
||||||
|
client_chain_len = abs(self.tls_config.client_chain_len)
|
||||||
|
expire_server_cert = (self.tls_config.server_chain_len < 0)
|
||||||
|
expire_client_cert = (self.tls_config.client_chain_len < 0)
|
||||||
|
args = [
|
||||||
|
str(self.mkcert_binary),
|
||||||
|
"--server-chain-length", str(server_chain_len),
|
||||||
|
"--client-chain-length", str(client_chain_len),
|
||||||
|
"--server-cert-file", str(self.server_cert_file),
|
||||||
|
"--client-cert-file", str(self.client_cert_file),
|
||||||
|
"--server-key-file", str(self.server_key_file),
|
||||||
|
"--client-key-file", str(self.client_key_file),
|
||||||
|
"--server-ca-file", str(self.server_ca_file),
|
||||||
|
"--client-ca-file", str(self.client_ca_file),
|
||||||
|
"--print-args",
|
||||||
|
]
|
||||||
|
if expire_server_cert:
|
||||||
|
args.append("--expire-server-cert")
|
||||||
|
if expire_client_cert:
|
||||||
|
args.append("--expire-client-cert")
|
||||||
|
subprocess.run(args, check=True)
|
||||||
|
|
||||||
|
# Materialize server's TLS configuration section
|
||||||
|
def tls_conf_string(self):
|
||||||
|
if self.tls_config is None:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
conf_map = {
|
||||||
|
"tls-certificate-file": self.server_cert_file,
|
||||||
|
"tls-key-file": self.server_key_file,
|
||||||
|
"tls-ca-file": self.client_ca_file,
|
||||||
|
"tls-verify-peers": self.tls_config.verify_peers,
|
||||||
|
}
|
||||||
|
return "\n".join("{} = {}".format(k, v) for k, v in conf_map.items())
|
||||||
|
|
||||||
# Get cluster status using fdbcli
|
# Get cluster status using fdbcli
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
status_output = self.fdbcli_exec_and_get("status json")
|
status_output = self.fdbcli_exec_and_get("status json")
|
||||||
|
|
|
@ -5,25 +5,27 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from local_cluster import LocalCluster, random_secret_string
|
from local_cluster import LocalCluster, TLSConfig, random_secret_string
|
||||||
from argparse import ArgumentParser, RawDescriptionHelpFormatter
|
from argparse import ArgumentParser, RawDescriptionHelpFormatter
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
class TempCluster:
|
class TempCluster(LocalCluster):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
build_dir: str,
|
build_dir: str,
|
||||||
process_number: int = 1,
|
process_number: int = 1,
|
||||||
port: str = None,
|
port: str = None,
|
||||||
blob_granules_enabled: bool = False,
|
blob_granules_enabled: bool = False,
|
||||||
|
tls_config: TLSConfig = None,
|
||||||
):
|
):
|
||||||
self.build_dir = Path(build_dir).resolve()
|
self.build_dir = Path(build_dir).resolve()
|
||||||
assert self.build_dir.exists(), "{} does not exist".format(build_dir)
|
assert self.build_dir.exists(), "{} does not exist".format(build_dir)
|
||||||
assert self.build_dir.is_dir(), "{} is not a directory".format(build_dir)
|
assert self.build_dir.is_dir(), "{} is not a directory".format(build_dir)
|
||||||
tmp_dir = self.build_dir.joinpath("tmp", random_secret_string(16))
|
tmp_dir = self.build_dir.joinpath("tmp", random_secret_string(16))
|
||||||
tmp_dir.mkdir(parents=True)
|
tmp_dir.mkdir(parents=True)
|
||||||
self.cluster = LocalCluster(
|
self.tmp_dir = tmp_dir
|
||||||
|
super().__init__(
|
||||||
tmp_dir,
|
tmp_dir,
|
||||||
self.build_dir.joinpath("bin", "fdbserver"),
|
self.build_dir.joinpath("bin", "fdbserver"),
|
||||||
self.build_dir.joinpath("bin", "fdbmonitor"),
|
self.build_dir.joinpath("bin", "fdbmonitor"),
|
||||||
|
@ -31,23 +33,21 @@ class TempCluster:
|
||||||
process_number,
|
process_number,
|
||||||
port=port,
|
port=port,
|
||||||
blob_granules_enabled=blob_granules_enabled,
|
blob_granules_enabled=blob_granules_enabled,
|
||||||
|
tls_config=tls_config,
|
||||||
|
mkcert_binary=self.build_dir.joinpath("bin", "mkcert"),
|
||||||
)
|
)
|
||||||
self.log = self.cluster.log
|
|
||||||
self.etc = self.cluster.etc
|
|
||||||
self.data = self.cluster.data
|
|
||||||
self.tmp_dir = tmp_dir
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.cluster.__enter__()
|
super().__enter__()
|
||||||
self.cluster.create_database()
|
super().create_database()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, xc_type, exc_value, traceback):
|
def __exit__(self, xc_type, exc_value, traceback):
|
||||||
self.cluster.__exit__(xc_type, exc_value, traceback)
|
super().__exit__(xc_type, exc_value, traceback)
|
||||||
shutil.rmtree(self.tmp_dir)
|
shutil.rmtree(self.tmp_dir)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.cluster.__exit__(None, None, None)
|
super().__exit__(None, None, None)
|
||||||
shutil.rmtree(self.tmp_dir)
|
shutil.rmtree(self.tmp_dir)
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,12 +94,37 @@ if __name__ == "__main__":
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--blob-granules-enabled", help="Enable blob granules", action="store_true"
|
"--blob-granules-enabled", help="Enable blob granules", action="store_true"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--tls-enabled", help="Enable TLS (with test-only certificates)", action="store_true")
|
||||||
|
parser.add_argument(
|
||||||
|
"--server-cert-chain-len",
|
||||||
|
help="Length of server TLS certificate chain including root CA. Negative value deliberately generates expired leaf certificate for TLS testing. Only takes effect with --tls-enabled.",
|
||||||
|
type=int,
|
||||||
|
default=3,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--client-cert-chain-len",
|
||||||
|
help="Length of client TLS certificate chain including root CA. Negative value deliberately generates expired leaf certificate for TLS testing. Only takes effect with --tls-enabled.",
|
||||||
|
type=int,
|
||||||
|
default=2,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--tls-verify-peer",
|
||||||
|
help="Rules to verify client certificate chain. See https://apple.github.io/foundationdb/tls.html#peer-verification",
|
||||||
|
type=str,
|
||||||
|
default="Check.Valid=1",
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
tls_config = None
|
||||||
|
if args.tls_enabled:
|
||||||
|
tls_config = TLSConfig(server_chain_len=args.server_cert_chain_len,
|
||||||
|
client_chain_len=args.client_cert_chain_len)
|
||||||
errcode = 1
|
errcode = 1
|
||||||
with TempCluster(
|
with TempCluster(
|
||||||
args.build_dir,
|
args.build_dir,
|
||||||
args.process_number,
|
args.process_number,
|
||||||
blob_granules_enabled=args.blob_granules_enabled,
|
blob_granules_enabled=args.blob_granules_enabled,
|
||||||
|
tls_config=tls_config,
|
||||||
) as cluster:
|
) as cluster:
|
||||||
print("log-dir: {}".format(cluster.log))
|
print("log-dir: {}".format(cluster.log))
|
||||||
print("etc-dir: {}".format(cluster.etc))
|
print("etc-dir: {}".format(cluster.etc))
|
||||||
|
@ -117,6 +142,18 @@ if __name__ == "__main__":
|
||||||
cmd_args.append(str(cluster.etc))
|
cmd_args.append(str(cluster.etc))
|
||||||
elif cmd == "@TMP_DIR@":
|
elif cmd == "@TMP_DIR@":
|
||||||
cmd_args.append(str(cluster.tmp_dir))
|
cmd_args.append(str(cluster.tmp_dir))
|
||||||
|
elif cmd == "@SERVER_CERT_FILE@":
|
||||||
|
cmd_args.append(str(cluster.server_cert_file))
|
||||||
|
elif cmd == "@SERVER_KEY_FILE@":
|
||||||
|
cmd_args.append(str(cluster.server_key_file))
|
||||||
|
elif cmd == "@SERVER_CA_FILE@":
|
||||||
|
cmd_args.append(str(cluster.server_ca_file))
|
||||||
|
elif cmd == "@CLIENT_CERT_FILE@":
|
||||||
|
cmd_args.append(str(cluster.client_cert_file))
|
||||||
|
elif cmd == "@CLIENT_KEY_FILE@":
|
||||||
|
cmd_args.append(str(cluster.client_key_file))
|
||||||
|
elif cmd == "@CLIENT_CA_FILE@":
|
||||||
|
cmd_args.append(str(cluster.client_ca_file))
|
||||||
elif cmd.startswith("@DATA_DIR@"):
|
elif cmd.startswith("@DATA_DIR@"):
|
||||||
cmd_args.append(str(cluster.data) + cmd[len("@DATA_DIR@") :])
|
cmd_args.append(str(cluster.data) + cmd[len("@DATA_DIR@") :])
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue