Merge 'tools/scylla-sstable: pass error handler to utils::config_file::read_from_file()' from Botond Dénes

The default error handler throws an exception, which means scylla-sstable will exit with exception if there is any problem in the configuration. Not even ScyllaDB itself is this harsh -- it will just log a warning for most errors. A tool should be much more lenient. So this patch passes an error handler which just logs all errors with debug level.
If reading an sstable fails, the user is expected to investigate turning debug-level logging on. When they do so, they will see any problems while reading the configuration (if it is relevant, e.g. when using EAR).

Fixes: #16538

Closes scylladb/scylladb#16657

* github.com:scylladb/scylladb:
  tools/scylla-sstable: pass error handler to utils::config_file::read_from_file()
  tools/scylla-sstable: allow always passing --scylla-yaml-file option
This commit is contained in:
Pavel Emelyanov
2024-01-09 14:28:49 +03:00
2 changed files with 32 additions and 2 deletions

View File

@@ -993,3 +993,29 @@ def test_scylla_sstable_no_args(scylla_path):
Usage: scylla sstable OPERATION [OPTIONS] ...
Try `scylla sstable --help` for more information.
"""
def test_scylla_sstable_bad_scylla_yaml(cql, test_keyspace, scylla_path, scylla_data_dir):
""" scylla-sstable should not choke on deprecated/unrecognized/etc options in scylla.yaml
It should just log a debug-level log and proceed with reading it.
This test checks that the config is successfully read, even if there are errors.
Reproduces: https://github.com/scylladb/scylladb/issues/16538
"""
with scylla_sstable(simple_clustering_table, cql, test_keyspace, scylla_data_dir) as (schema_file, sstables):
with tempfile.NamedTemporaryFile("w+t") as scylla_yaml:
scylla_yaml.write("foo: bar")
scylla_yaml.flush()
res = subprocess.run([scylla_path,
"sstable", "dump-data",
"--scylla-yaml", scylla_yaml.name,
"--schema-file", schema_file,
"--logger-log-level", "scylla-sstable=debug"]
+ sstables,
text=True, stderr=subprocess.PIPE)
assert res.returncode == 0
print(res.stderr) # when the test fails, it helps to see what the actual output is
stderr_lines = res.stderr.split('\n')
for expected_msg in (
"error processing configuration item: Unknown option : foo",
"Successfully read scylla.yaml from"):
assert any(map(lambda stderr_line: expected_msg in stderr_line, stderr_lines))

View File

@@ -2993,7 +2993,9 @@ $ scylla sstable validate /path/to/md-123456-big-Data.db /path/to/md-123457-big-
}
if (file_exists(scylla_yaml_path).get()) {
dbcfg.read_from_file(scylla_yaml_path).get();
dbcfg.read_from_file(scylla_yaml_path, [] (const sstring& opt, const sstring& msg, std::optional<::utils::config_file::value_status> status) {
sst_log.debug("error processing configuration item: {} : {}", msg, opt);
}).get();
dbcfg.setup_directories();
sst_log.debug("Successfully read scylla.yaml from {} location of {}", scylla_yaml_path_source, scylla_yaml_path);
} else {
@@ -3014,7 +3016,9 @@ $ scylla sstable validate /path/to/md-123456-big-Data.db /path/to/md-123457-big-
if (!schema_sources) {
sst_log.debug("No user-provided schema source, attempting to auto-detect it");
schema_with_source = try_load_schema_autodetect(app_config, dbcfg);
} else if (schema_sources == 1) {
} else if (schema_sources == 1 || (schema_sources == 2 && app_config.contains("scylla-yaml-file"))) {
// We make an exception for the case where 2 schema sources are provided, but one of them is scylla-yaml file.
// We want to always accept the --scylla-yaml-file option.
sst_log.debug("Single schema source provided");
schema_with_source = try_load_schema_from_user_provided_source(app_config, dbcfg);
} else {