Files
scylladb/db/object_storage_endpoint_param.cc
Pavel Emelyanov a6618f225c object_storage_endpoint_param: Make it formattable for real
Currently the formatter converts it to json and then tries to emit into
the output context with the "...{{}}" format string. The intent was to
have the "...{<json text>}" output. However, the double curly brace in
format string means "print a curly brace", so the output of the above
formatting is "...{}", literally.

Fix by keeping a single curly brace. The "<json text>" thing will have
its own surrounding curly braces.

Fixes #27718

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>

Closes scylladb/scylladb#27687
2025-12-17 11:48:39 +01:00

140 lines
4.9 KiB
C++

/*
* Copyright (C) 2025-present ScyllaDB
*
*/
/*
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
*/
#include <string>
#include <variant>
#include <yaml-cpp/yaml.h>
#include <boost/lexical_cast.hpp>
#include "utils/s3/creds.hh"
#include "object_storage_endpoint_param.hh"
using namespace std::string_literals;
db::object_storage_endpoint_param::object_storage_endpoint_param(s3_storage s)
: _data(std::move(s))
{}
db::object_storage_endpoint_param::object_storage_endpoint_param(std::string endpoint, s3::endpoint_config config)
: object_storage_endpoint_param(s3_storage{std::move(endpoint), std::move(config)})
{}
db::object_storage_endpoint_param::object_storage_endpoint_param(gs_storage s)
: _data(std::move(s))
{}
db::object_storage_endpoint_param::object_storage_endpoint_param() = default;
db::object_storage_endpoint_param::object_storage_endpoint_param(const object_storage_endpoint_param&) = default;
std::string db::object_storage_endpoint_param::s3_storage::to_json_string() const {
return fmt::format("{{ \"port\": {}, \"use_https\": {}, \"aws_region\": \"{}\", \"iam_role_arn\": \"{}\" }}",
config.port, config.use_https, config.region, config.role_arn
);
}
std::string db::object_storage_endpoint_param::s3_storage::key() const {
return endpoint;
}
std::string db::object_storage_endpoint_param::gs_storage::to_json_string() const {
return fmt::format("{{ \"type\": \"gs\", \"credentials_file\": \"{}\" }}",
credentials_file
);
}
std::string db::object_storage_endpoint_param::gs_storage::key() const {
return endpoint;
}
bool db::object_storage_endpoint_param::is_s3_storage() const {
return std::holds_alternative<s3_storage>(_data);
}
bool db::object_storage_endpoint_param::is_gs_storage() const {
return std::holds_alternative<gs_storage>(_data);
}
bool db::object_storage_endpoint_param::is_storage_of_type(std::string_view type) const {
if (type == s3_type) {
return is_s3_storage();
}
if (type == gs_type) {
return is_gs_storage();
}
return false;
}
const db::object_storage_endpoint_param::s3_storage& db::object_storage_endpoint_param::get_s3_storage() const {
return std::get<db::object_storage_endpoint_param::s3_storage>(_data);
}
const db::object_storage_endpoint_param::gs_storage& db::object_storage_endpoint_param::get_gs_storage() const {
return std::get<db::object_storage_endpoint_param::gs_storage>(_data);
}
std::strong_ordering db::object_storage_endpoint_param::operator<=>(const object_storage_endpoint_param&) const = default;
bool db::object_storage_endpoint_param::operator==(const object_storage_endpoint_param&) const = default;
std::string db::object_storage_endpoint_param::to_json_string() const {
return std::visit([](auto& o) { return o.to_json_string(); }, _data);
}
std::string db::object_storage_endpoint_param::key() const {
return std::visit([](auto& o) { return o.key(); }, _data);
}
const std::string& db::object_storage_endpoint_param::type() const {
if (is_s3_storage()) {
return s3_type;
} else if (is_gs_storage()) {
return gs_type;
}
throw std::runtime_error("Should not reach");
}
db::object_storage_endpoint_param db::object_storage_endpoint_param::decode(const YAML::Node& node) {
auto name = node["name"];
auto aws_region = node["aws_region"];
auto iam_role_arn = node["iam_role_arn"];
auto type = node["type"];
auto get_opt = [](auto& node, const std::string& key, auto def) {
auto tmp = node[key];
return tmp ? tmp.template as<std::decay_t<decltype(def)>>() : def;
};
// aws s3 endpoint.
if (!type || type.as<std::string>() == s3_type || aws_region || iam_role_arn) {
s3_storage ep;
ep.endpoint = name.as<std::string>();
ep.config.port = node["port"].as<unsigned>();
ep.config.use_https = node["https"].as<bool>(false);
ep.config.region = aws_region ? aws_region.as<std::string>() : std::getenv("AWS_DEFAULT_REGION");
ep.config.role_arn = iam_role_arn ? iam_role_arn.as<std::string>() : "";
return object_storage_endpoint_param{std::move(ep)};
}
// GCS endpoint
if (type.as<std::string>() == gs_type) {
gs_storage ep;
ep.endpoint = name.as<std::string>();
ep.credentials_file = get_opt(node, "credentials_file", ""s);
return object_storage_endpoint_param(std::move(ep));
}
// TODO: other types
throw std::invalid_argument(fmt::format("Could not decode object_storage_endpoint_param: {}", boost::lexical_cast<std::string>(node)));
}
const std::string db::object_storage_endpoint_param::s3_type = "s3";
const std::string db::object_storage_endpoint_param::gs_type = "gs";
auto fmt::formatter<db::object_storage_endpoint_param>::format(const db::object_storage_endpoint_param& e, fmt::format_context& ctx) const
-> decltype(ctx.out()) {
return fmt::format_to(ctx.out(), "object_storage_endpoint_param{}", e.to_json_string());
}