escape user, password and host. [#METR-12221]

This commit is contained in:
Andrey Mironov 2014-08-14 15:50:36 +04:00
parent 61af8baa77
commit ec0cee0afe
3 changed files with 50 additions and 24 deletions

View File

@ -33,7 +33,6 @@ public:
{
std::string dir_name;
int weight;
bool internal_replication;
};
std::vector<ShardInfo> shard_info_vec;
std::vector<size_t> slot_to_shard;
@ -67,7 +66,7 @@ public:
Address(const String & host_port_, const String & user_, const String & password_);
};
static bool isLocal(const Address & address);
static bool addressIsLocal(const Poco::Net::SocketAddress & address);
// private:
/// Массив шардов. Каждый шард - адреса одного сервера.

View File

@ -1,4 +1,5 @@
#include <DB/Interpreters/Cluster.h>
#include <DB/Common/escapeForFileName.h>
#include <Poco/Util/AbstractConfiguration.h>
#include <Poco/Util/Application.h>
#include <Poco/Net/NetworkInterface.h>
@ -38,8 +39,10 @@ namespace
inline std::string addressToDirName(const Cluster::Address & address)
{
return
address.user + (address.password.empty() ? "" : (':' + address.password)) + '@' +
address.host_port.host().toString() + ':' + std::to_string(address.host_port.port());
escapeForFileName(address.user) +
(address.password.empty() ? "" : (':' + escapeForFileName(address.password))) + '@' +
escapeForFileName(address.host_port.host().toString()) + ':' +
std::to_string(address.host_port.port());
}
}
@ -72,11 +75,12 @@ Cluster::Cluster(const Settings & settings, const DataTypeFactory & data_type_fa
{
const auto & prefix = config_prefix + *it;
const auto weight = config.getInt(prefix + ".weight", 1);
const auto internal_replication = config.getBool(prefix + ".internal_replication", false);
if (weight == 0)
continue;
addresses.emplace_back(prefix);
slot_to_shard.insert(std::end(slot_to_shard), weight, shard_info_vec.size());
shard_info_vec.push_back({addressToDirName(addresses.back()), weight, internal_replication});
shard_info_vec.push_back({addressToDirName(addresses.back()), weight});
}
else if (0 == strncmp(it->c_str(), "shard", strlen("shard")))
{
@ -88,14 +92,18 @@ Cluster::Cluster(const Settings & settings, const DataTypeFactory & data_type_fa
const auto & partial_prefix = config_prefix + *it + ".";
const auto weight = config.getInt(partial_prefix + ".weight", 1);
const auto internal_replication = config.getBool(partial_prefix + ".internal_replication", false);
if (weight == 0)
continue;
// const auto internal_replication = config.getBool(partial_prefix + ".internal_replication", false);
std::string dir_name{};
auto first = true;
for (auto jt = replica_keys.begin(); jt != replica_keys.end(); ++jt)
{
if (0 == strncmp(jt->data(), "weight", strlen("weight")))
if (0 == strncmp(jt->data(), "weight", strlen("weight")) ||
0 == strncmp(jt->data(), "internal_replication", strlen("internal_replication")))
continue;
if (0 == strncmp(jt->c_str(), "replica", strlen("replica")))
@ -111,7 +119,7 @@ Cluster::Cluster(const Settings & settings, const DataTypeFactory & data_type_fa
}
slot_to_shard.insert(std::end(slot_to_shard), weight, shard_info_vec.size());
shard_info_vec.push_back({dir_name, weight, internal_replication});
shard_info_vec.push_back({dir_name, weight});
}
else
throw Exception("Unknown element in config: " + *it, ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG);
@ -130,7 +138,7 @@ Cluster::Cluster(const Settings & settings, const DataTypeFactory & data_type_fa
bool has_local_replics = false;
for (Addresses::const_iterator jt = it->begin(); jt != it->end(); ++jt)
{
if (isLocal(*jt))
if (addressIsLocal(jt->host_port))
{
has_local_replics = true;
break;
@ -156,7 +164,7 @@ Cluster::Cluster(const Settings & settings, const DataTypeFactory & data_type_fa
{
for (Addresses::const_iterator it = addresses.begin(); it != addresses.end(); ++it)
{
if (isLocal(*it))
if (addressIsLocal(it->host_port))
{
++local_nodes_num;
}
@ -215,20 +223,20 @@ Poco::Timespan Cluster::saturate(const Poco::Timespan & v, const Poco::Timespan
}
bool Cluster::isLocal(const Address & address)
bool Cluster::addressIsLocal(const Poco::Net::SocketAddress & address)
{
/// Если среди реплик существует такая, что:
/// - её порт совпадает с портом, который слушает сервер;
/// - её хост резолвится в набор адресов, один из которых совпадает с одним из адресов сетевых интерфейсов сервера
/// то нужно всегда ходить на этот шард без межпроцессного взаимодействия
UInt16 clickhouse_port = Poco::Util::Application::instance().config().getInt("tcp_port", 0);
static Poco::Net::NetworkInterface::NetworkInterfaceList interfaces = Poco::Net::NetworkInterface::list();
const UInt16 clickhouse_port = Poco::Util::Application::instance().config().getInt("tcp_port", 0);
static auto interfaces = Poco::Net::NetworkInterface::list();
if (clickhouse_port == address.host_port.port() &&
if (clickhouse_port == address.port() &&
interfaces.end() != std::find_if(interfaces.begin(), interfaces.end(),
[&](const Poco::Net::NetworkInterface & interface) { return interface.address() == address.host_port.host(); }))
[&](const Poco::Net::NetworkInterface & interface) { return interface.address() == address.host(); }))
{
LOG_INFO(&Poco::Util::Application::instance().logger(), "Replica with address " << address.host_port.toString() << " will be processed as local.");
LOG_INFO(&Poco::Util::Application::instance().logger(), "Replica with address " << address.toString() << " will be processed as local.");
return true;
}
return false;

View File

@ -259,7 +259,9 @@ void StorageDistributed::directoryMonitorFunc(const std::string & name)
const auto & path = this->path + name + '/';
std::cout << "created monitor for directory " << path << std::endl;
// ConnectionPools pools;
auto is_local = false;
ConnectionPools pools;
for (auto it = boost::make_split_iterator(name, boost::first_finder(",")); it != decltype(it){}; ++it)
{
const auto & address = boost::copy_range<std::string>(*it);
@ -270,25 +272,42 @@ void StorageDistributed::directoryMonitorFunc(const std::string & name)
throw Exception{"Shard address '" + address + "' does not match to 'user[:password]@host:port' pattern"};
const auto has_pw = colon < user_pw_end;
const auto host_end = has_pw ? colon : strchr(user_pw_end + 1, ':');
const auto host_end = has_pw ? strchr(user_pw_end + 1, ':') : colon;
if (!host_end)
throw Exception{"Shard address '" + address + "' does not contain port"};
const std::string user{address.data(), has_pw ? colon : user_pw_end};
const auto password = has_pw ? std::string{colon + 1, user_pw_end} : std::string{};
const std::string host{user_pw_end + 1, host_end};
const auto user = unescapeForFileName({address.data(), has_pw ? colon : user_pw_end});
const auto password = has_pw ? unescapeForFileName({colon + 1, user_pw_end}) : std::string{};
const auto host = unescapeForFileName({user_pw_end + 1, host_end});
const auto port = DB::parse<UInt16>(host_end + 1);
// pools.emplace_back(new ConnectionPool(1, host, port, remote_database, "default", "", getName() + '_' + name));
std::cout
<< "\taddress " << host
<< " port " << port
<< " user " << user
<< " password " << password
<< std::endl;
if (Cluster::addressIsLocal({host, port}))
{
is_local = true;
break;
}
pools.emplace_back(new ConnectionPool{
1, host, port, "",
user, password, context.getDataTypeFactory(),
getName() + '_' + name
});
}
// auto pool = pools.size() == 1 ? pools[0] : new ConnectionPoolWithFailover(pools, DB::LoadBalancing::RANDOM);
std::cout << "local? " << std::boolalpha << is_local << std::endl;
const auto pool = is_local
? (pools.size() == 1
? pools[0]
: new ConnectionPoolWithFailover(pools, DB::LoadBalancing::RANDOM)
)
: nullptr;
while (!quit.load(std::memory_order_relaxed))
{