Skip to content

Commit 0f4c1fc

Browse files
committed
BUG #26970629 - CLUSTER CREATION FAILS IF PORT WAS NOT WRITTEN ON THE CONNECTION STRING
- The Admin API operations on a database should be done through a TCP connection A new validation was added to the pre-condition checks in order to verify that the actual session is done through TCP.
1 parent c4d441c commit 0f4c1fc

9 files changed

+77
-11
lines changed

modules/adminapi/mod_dba_common.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ ReplicationGroupState check_function_preconditions(const std::string &class_name
233233
error = "a Classic Session is required to perform this operation";
234234
else if (!session->is_connected())
235235
error = "The session was closed. An open session is required to perform this operation";
236+
else if (!session->is_tcp())
237+
error = "a Classic Session through TCP/IP is required to perform this operation";
236238
else{
237239
// Retrieves the instance configuration type from the perspective of the active session
238240
auto instance_type = get_gr_instance_type(session->connection());

modules/base_session.cc

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -293,15 +293,9 @@ void ShellBaseSession::load_connection_data(const shcore::Argument_list &args) {
293293
// Anything found on any of the indicated sources: URI, options map and stored session
294294
if (2 == args.size())
295295
_password = args.string_at(1).c_str();
296+
}
296297

297-
// Default port will be != 0 only when applicable
298-
if (_port==0) {
299-
int default_port = get_default_port();
300-
301-
if (default_port != 0)
302-
_port = default_port;
303-
}
304-
298+
void ShellBaseSession::set_uri() {
305299
std::string sock_port = (_port == 0) ? _sock : boost::lexical_cast<std::string>(_port);
306300

307301
if (_schema.empty())

modules/base_session.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class SHCORE_PUBLIC ShellBaseSession : public shcore::Cpp_object_bridge {
9090
struct shcore::SslInfo _ssl_info;
9191

9292
void load_connection_data(const shcore::Argument_list &args);
93+
void set_uri();
9394
private:
9495
void init();
9596

modules/mod_mysql_session.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ Value ClassicSession::connect(const Argument_list &args) {
113113

114114
_default_schema = _schema;
115115

116+
// Sets the default port when required
117+
if (is_tcp() && _port == 0)
118+
_port = 3306;
119+
120+
set_uri();
121+
116122
if (!_default_schema.empty())
117123
update_schema_cache(_default_schema, true);
118124
}

modules/mod_mysql_session.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ class SHCORE_PUBLIC ClassicSession : public ShellDevelopmentSession, public std:
164164
#endif
165165
virtual bool is_connected() const { return _conn ? true : false; }
166166

167+
bool is_tcp() { return _conn->is_tcp(); }
168+
167169
virtual int get_default_port();
168170

169171
private:

modules/mod_mysqlx_session.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ Value BaseSession::connect(const Argument_list &args) {
158158

159159
_connection_id = _session.get_connection_id();
160160

161+
// TODO(rennox): Implement is_tcp() for X protocol
162+
if (_port == 0 && _sock.empty())
163+
_port = 33060;
164+
165+
set_uri();
166+
161167
_default_schema = _schema;
162168
if (!_default_schema.empty())
163169
update_schema_cache(_default_schema, true);

modules/mysql_connection.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ void Connection::throw_on_connection_fail() {
209209
}
210210

211211
Connection::Connection(const std::string &uri_, const char *password)
212-
: _mysql(NULL) {
212+
: _mysql(NULL), _tcp(false) {
213213
std::string protocol;
214214
std::string user;
215215
std::string pass;
@@ -258,11 +258,14 @@ Connection::Connection(const std::string &uri_, const char *password)
258258
if (!mysql_real_connect(_mysql, host.c_str(), user.c_str(), pass.c_str(), db.empty() ? NULL : db.c_str(), port, sock.empty() ? NULL : sock.c_str(), flags)) {
259259
throw_on_connection_fail();
260260
}
261+
262+
std::string connection_info(get_connection_info());
263+
_tcp = (connection_info.find("via TCP/IP") != std::string::npos);
261264
}
262265

263266
Connection::Connection(const std::string &host, int port, const std::string &socket, const std::string &user, const std::string &password, const std::string &schema,
264267
const struct shcore::SslInfo& ssl_info)
265-
: _mysql(NULL) {
268+
: _mysql(NULL), _tcp(false) {
266269
long flags = CLIENT_MULTI_RESULTS | CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
267270

268271
// No option should be silently ignored, on conflicts an error is raised
@@ -292,6 +295,9 @@ Connection::Connection(const std::string &host, int port, const std::string &soc
292295
if (!mysql_real_connect(_mysql, host.c_str(), user.c_str(), password.c_str(), schema.empty() ? NULL : schema.c_str(), port, socket.empty() ? NULL : socket.c_str(), flags)) {
293296
throw_on_connection_fail();
294297
}
298+
299+
std::string connection_info(get_connection_info());
300+
_tcp = (connection_info.find("via TCP/IP") != std::string::npos);
295301
}
296302

297303
bool Connection::setup_ssl(const struct shcore::SslInfo& ssl_info) {

modules/mysql_connection.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,15 @@ class SHCORE_PUBLIC Connection : public std::enable_shared_from_this<Connection>
161161
const char* get_server_info() { _prev_result.reset(); return mysql_get_server_info(_mysql); }
162162
const char* get_stats() { _prev_result.reset(); return mysql_stat(_mysql); }
163163
const char* get_ssl_cipher() { _prev_result.reset(); return mysql_get_ssl_cipher(_mysql); }
164+
bool is_tcp() { return _tcp; }
164165

165166
private:
166167
bool setup_ssl(const struct shcore::SslInfo& ssl_info);
167168
void throw_on_connection_fail();
168169
std::string _uri;
169170
MYSQL *_mysql;
170171
MySQL_timer _timer;
172+
bool _tcp;
171173

172174
std::shared_ptr<MYSQL_RES> _prev_result;
173175
};

unittest/shell_cmdline_regressions_t.cc

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include <string>
1717
#include "unittest/test_utils/command_line_test.h"
1818
#include "utils/utils_file.h"
19+
#include "utils/utils_connection.h"
20+
#include "modules/mysql_connection.h"
1921

2022
namespace tests {
2123

@@ -129,5 +131,50 @@ TEST_F(Command_line_test, bug24905066) {
129131
"'some_unexisting_schema'");
130132
}
131133
}
132-
134+
TEST_F(Command_line_test, bug26970629) {
135+
std::string variable;
136+
std::string host;
137+
std::string pwd = "--password=";
138+
139+
if (!_pwd.empty())
140+
pwd += _pwd;
141+
#ifdef _WIN32
142+
variable = "named_pipe";
143+
host = "--host=.";
144+
#else
145+
variable = "socket";
146+
host = "--host=localhost";
147+
#endif
148+
shcore::SslInfo info;
149+
std::shared_ptr<mysqlsh::mysql::Connection> connection(
150+
new mysqlsh::mysql::Connection(_host, _mysql_port_number, "", _user, _pwd,
151+
"", info));
152+
153+
auto result = connection->run_sql("show variables like '" + variable + "'");
154+
155+
auto row = result->fetch_one();
156+
157+
std::string socket = "--socket=" + row->get_value_as_string(1);
158+
159+
connection->close();
160+
161+
if (socket.empty()) {
162+
SCOPED_TRACE("Socket/Pipe Connections are Disabled, they must be enabled.");
163+
FAIL();
164+
} else {
165+
std::string usr = "--user=" + _user;
166+
execute({_mysqlsh, usr.c_str(), pwd.c_str(), host.c_str(), socket.c_str(),
167+
"-e", "dba.getCluster()", NULL});
168+
MY_EXPECT_CMD_OUTPUT_CONTAINS(
169+
"Dba.getCluster: a Classic Session through TCP/IP is required to "
170+
"perform this operation");
171+
_output.clear();
172+
173+
execute({_mysqlsh, usr.c_str(), pwd.c_str(), host.c_str(), socket.c_str(),
174+
"-e", "dba.createCluster('sample')", NULL});
175+
MY_EXPECT_CMD_OUTPUT_CONTAINS(
176+
"Dba.createCluster: a Classic Session through TCP/IP is required to "
177+
"perform this operation");
178+
}
179+
}
133180
}

0 commit comments

Comments
 (0)