Skip to content

Commit 155fc0c

Browse files
committed
BUG#35992885 BUG#35997569
BUG#35992885 .rescan() fails to add unmanaged instance if recovery account is unsupported During Cluster.rescan(), a check is made to verify if the recovery account of a given instance has the correct format. If it hasn't, an error is thrown ("ERROR: Unsupported recovery account 'rpl_user' has been found for instance ..." as reported in the issue), meaning that the account isn't updated. This patch makes sure that rescan properly deals with accounts with unknown formats, by creating a new user (with the correct format) and assigning it to the recovery channel. BUG#35997569 Replica misconfiguration after rescan() + setPrimaryInstance() Up until now, the commands ReplicaSet.rescan() and dba.createReplicaSet (with "adoptFromAR" to 1), didn't change the replication account already associated with the async replication channel. This means that the account format would be different than the format of an account created by the AdminAPI. This could lead to problems as described in BUG#35997569. This patch makes sure that rescan(), if necessary, creates new users with the correct format and updates the channel to use that user instead. Also, when createReplicaSet() is adopting from an existing AR channel, it now guarantees that said channel is using the correct account format, by creating a new user if necessary. Change-Id: Ia8601d72b67e6b31fe1c7cff2432beec11d62397
1 parent b358fba commit 155fc0c

File tree

19 files changed

+583
-321
lines changed

19 files changed

+583
-321
lines changed

modules/adminapi/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ file(GLOB adminapi_module_SOURCES
7878
"replica_set/describe.cc"
7979
"replica_set/dissolve.cc"
8080
"replica_set/replica_set_impl.cc"
81-
"replica_set/replica_set_status.cc"
8281
"replica_set/rescan.cc"
82+
"replica_set/status.cc"
8383
"cluster/add_instance.cc"
8484
"cluster/add_replica_instance.cc"
8585
"cluster/rejoin_instance.cc"

modules/adminapi/cluster/cluster_impl.cc

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,8 @@ void Cluster_impl::ensure_metadata_has_server_id(
645645
});
646646
}
647647

648-
void Cluster_impl::ensure_metadata_has_recovery_accounts() {
648+
void Cluster_impl::ensure_metadata_has_recovery_accounts(
649+
bool allow_non_standard_format) {
649650
auto endpoints =
650651
get_metadata_storage()->get_instances_with_recovery_accounts(get_id());
651652

@@ -657,16 +658,17 @@ void Cluster_impl::ensure_metadata_has_recovery_accounts() {
657658

658659
execute_in_members(
659660
{}, get_cluster_server()->get_connection_options(), {},
660-
[this, &console, &endpoints](const std::shared_ptr<Instance> &instance,
661-
const mysqlshdk::gr::Member &gr_member) {
661+
[this, &console, &endpoints, &allow_non_standard_format](
662+
const std::shared_ptr<Instance> &instance,
663+
const mysqlshdk::gr::Member &gr_member) {
662664
std::string recovery_user = mysqlshdk::mysql::get_replication_user(
663665
*instance, mysqlshdk::gr::k_gr_recovery_channel);
664666

665667
log_debug("Fixing recovering account '%s' in instance '%s'",
666668
recovery_user.c_str(), instance->descr().c_str());
667669

668-
bool recovery_is_valid = false;
669-
if (!recovery_user.empty()) {
670+
bool recovery_is_valid = allow_non_standard_format;
671+
if (!recovery_is_valid && !recovery_user.empty()) {
670672
recovery_is_valid =
671673
shcore::str_beginswith(
672674
recovery_user,
@@ -675,31 +677,30 @@ void Cluster_impl::ensure_metadata_has_recovery_accounts() {
675677
recovery_user, mysqlshdk::gr::k_group_recovery_user_prefix);
676678
}
677679

678-
if (!recovery_user.empty()) {
679-
if (!recovery_is_valid) {
680-
console->print_error(shcore::str_format(
681-
"Unsupported recovery account '%s' has been found for instance "
682-
"'%s'. Operations such as "
683-
"<Cluster>.<<<resetRecoveryAccountsPassword>>>() and "
684-
"<Cluster>.<<<addInstance>>>() may fail. Please remove and add "
685-
"the instance back to the Cluster to ensure a supported "
686-
"recovery account is used.",
687-
recovery_user.c_str(), instance->descr().c_str()));
688-
return true;
689-
}
690-
691-
auto it = endpoints.find(instance->get_uuid());
692-
if ((it != endpoints.end()) && (it->second != recovery_user)) {
693-
get_metadata_storage()->update_instance_repl_account(
694-
gr_member.uuid, Cluster_type::GROUP_REPLICATION,
695-
Replica_type::GROUP_MEMBER, recovery_user,
696-
get_replication_user_host());
697-
}
680+
if (recovery_user.empty())
681+
throw std::logic_error(shcore::str_format(
682+
"Recovery user account not found for server address '%s' with "
683+
"UUID %s",
684+
instance->descr().c_str(), instance->get_uuid().c_str()));
685+
686+
if (!recovery_is_valid) {
687+
console->print_error(shcore::str_format(
688+
"Unsupported recovery account '%s' has been found for instance "
689+
"'%s'. Operations such as "
690+
"<Cluster>.<<<resetRecoveryAccountsPassword>>>() and "
691+
"<Cluster>.<<<addInstance>>>() may fail. Please remove and add "
692+
"the instance back to the Cluster to ensure a supported "
693+
"recovery account is used.",
694+
recovery_user.c_str(), instance->descr().c_str()));
695+
return true;
696+
}
698697

699-
} else {
700-
throw std::logic_error(
701-
"Recovery user account not found for server address: " +
702-
instance->descr() + " with UUID " + instance->get_uuid());
698+
auto it = endpoints.find(instance->get_uuid());
699+
if ((it != endpoints.end()) && (it->second != recovery_user)) {
700+
get_metadata_storage()->update_instance_repl_account(
701+
gr_member.uuid, Cluster_type::GROUP_REPLICATION,
702+
Replica_type::GROUP_MEMBER, recovery_user,
703+
get_replication_user_host());
703704
}
704705

705706
return true;
@@ -1432,7 +1433,7 @@ void Cluster_impl::update_replication_allowed_host(const std::string &host) {
14321433
current_console()->print_note(
14331434
"Legacy cluster account management detected, will update it "
14341435
"first.");
1435-
ensure_metadata_has_recovery_accounts();
1436+
ensure_metadata_has_recovery_accounts(false);
14361437
goto retry;
14371438
} else {
14381439
throw shcore::Exception::runtime_error(

modules/adminapi/cluster/cluster_impl.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ class Cluster_impl final : public Base_cluster_impl,
492492

493493
/**
494494
* Get the list of instances in the states described in the states vector.
495+
*
495496
* @param states Vector of strings with the states of members whose
496497
* instance_metadata we will retrieve from the cluster. If the states vector
497498
* is empty, return the list of all instances.
@@ -521,8 +522,12 @@ class Cluster_impl final : public Base_cluster_impl,
521522
* Checks for missing metadata recovery account entries, and fix them using
522523
* info from mysql.slave_master_info.
523524
*
525+
* @param allow_non_standard_format If true, account that don't follow the
526+
* AdminAPI format are stored, otherwise, a message is generated and the
527+
* account ignored.
528+
*
524529
*/
525-
void ensure_metadata_has_recovery_accounts();
530+
void ensure_metadata_has_recovery_accounts(bool allow_non_standard_format);
526531

527532
/**
528533
* Get an online instance from the cluster.

modules/adminapi/cluster/rescan.cc

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ shcore::Value Rescan::execute() {
10191019
}
10201020

10211021
// Print warning about not used instances in addInstances.
1022-
{
1022+
if (!m_options.add_instances_list.empty()) {
10231023
std::vector<std::string> not_used_add_instances;
10241024
not_used_add_instances.reserve(m_options.add_instances_list.size());
10251025

@@ -1039,20 +1039,16 @@ shcore::Value Rescan::execute() {
10391039
}
10401040

10411041
// Check if there are missing instances
1042-
std::shared_ptr<shcore::Value::Array_type> missing_instances;
1043-
10441042
if (result->has_key("unavailableInstances")) {
1045-
missing_instances = result->get_array("unavailableInstances");
1046-
1047-
remove_metadata_for_instances(missing_instances);
1043+
remove_metadata_for_instances(result->get_array("unavailableInstances"));
10481044
}
10491045

10501046
if (result->has_key("updatedInstances")) {
10511047
update_metadata_for_instances(result->get_array("updatedInstances"));
10521048
}
10531049

10541050
// Fix all missing recovery accounts from metadata.
1055-
m_cluster->ensure_metadata_has_recovery_accounts();
1051+
m_cluster->ensure_metadata_has_recovery_accounts(true);
10561052

10571053
// This calls ensures all of the instances have server_id as instance
10581054
// attribute, including the case were rescan is executed and no new/updated
@@ -1108,7 +1104,7 @@ shcore::Value Rescan::execute() {
11081104
ensure_transaction_size_limit_consistency();
11091105

11101106
// Print warning about not used instances in removeInstances.
1111-
{
1107+
if (!m_options.remove_instances_list.empty()) {
11121108
std::vector<std::string> not_used_remove_instances;
11131109
not_used_remove_instances.reserve(m_options.remove_instances_list.size());
11141110

@@ -1133,7 +1129,7 @@ shcore::Value Rescan::execute() {
11331129
// the auto-increment settings on all of them.
11341130
if (result->has_key("newTopologyMode") &&
11351131
!result->is_null("newTopologyMode")) {
1136-
std::string new_topology_mode = result->get_string("newTopologyMode");
1132+
auto new_topology_mode = result->get_string("newTopologyMode");
11371133

11381134
if (!new_topology_mode.empty()) {
11391135
console->print_note("The topology mode of the cluster changed to '" +

modules/adminapi/cluster_set/cluster_set_impl.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
#include "modules/adminapi/common/server_features.h"
4444
#include "modules/adminapi/common/undo.h"
4545
#include "modules/adminapi/dba/create_cluster.h"
46-
#include "modules/adminapi/replica_set/replica_set_status.h"
4746
#include "mysqlshdk/include/shellcore/shell_notifications.h"
4847
#include "mysqlshdk/libs/mysql/async_replication.h"
4948
#include "mysqlshdk/libs/mysql/binlog_utils.h"

0 commit comments

Comments
 (0)