YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/tools/yb-admin-multi-master-test.cc
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
// Tests for the yb-admin command-line tool with multiple masters.
33
34
#include <regex>
35
36
#include <gtest/gtest.h>
37
38
#include "yb/client/client.h"
39
40
#include "yb/integration-tests/external_mini_cluster-itest-base.h"
41
42
#include "yb/util/status_format.h"
43
#include "yb/util/string_util.h"
44
#include "yb/util/subprocess.h"
45
#include "yb/util/test_util.h"
46
47
namespace yb {
48
namespace tools {
49
50
namespace {
51
52
static const char* const kAdminToolName = "yb-admin";
53
54
} // namespace
55
56
class YBAdminMultiMasterTest : public ExternalMiniClusterITestBase {
57
 protected:
58
  YB_STRONGLY_TYPED_BOOL(UseUUID);
59
60
  void TestRemoveDownMaster(UseUUID use_uuid);
61
};
62
63
0
TEST_F(YBAdminMultiMasterTest, InitialMasterAddresses) {
64
0
  auto admin_path = GetToolPath(kAdminToolName);
65
0
  ASSERT_NO_FATALS(StartCluster({}, {}, 1/*num tservers*/, 3/*num masters*/));
66
67
  // Verify that yb-admin query results with --init_master_addrs match
68
  // query results with the full master addresses
69
0
  auto non_leader_idx = ASSERT_RESULT(cluster_->GetFirstNonLeaderMasterIndex());
70
0
  auto non_leader = cluster_->master(non_leader_idx);
71
0
  HostPort non_leader_hp = non_leader->bound_rpc_hostport();
72
0
  std::string output1;
73
0
  ASSERT_OK(Subprocess::Call(ToStringVector(
74
0
      admin_path, "-init_master_addrs", non_leader_hp.ToString(),
75
0
      "list_all_masters"), &output1));
76
0
  LOG(INFO) << "init_master_addrs: list_all_masters: " << output1;
77
0
  std::string output2;
78
0
  ASSERT_OK(Subprocess::Call(ToStringVector(
79
0
      admin_path, "-master_addresses", cluster_->GetMasterAddresses(),
80
0
      "list_all_masters"), &output2));
81
0
  LOG(INFO) << "full master_addresses: list_all_masters: " << output2;
82
0
  ASSERT_EQ(output1, output2);
83
84
0
  output1.clear();
85
0
  output2.clear();
86
87
0
  ASSERT_OK(Subprocess::Call(ToStringVector(
88
0
      admin_path, "-init_master_addrs", non_leader_hp.ToString(),
89
0
      "get_universe_config"), &output1));
90
  // Remove the time output from list_all_tablet_servers since it doesn't match
91
0
  LOG(INFO) << "init_master_addrs: get_universe_config: " << output1;
92
0
  ASSERT_OK(Subprocess::Call(ToStringVector(
93
0
      admin_path, "-master_addresses", cluster_->GetMasterAddresses(),
94
0
      "get_universe_config"), &output2));
95
0
  LOG(INFO) << "full master_addresses: get_universe_config: " << output2;
96
0
  ASSERT_EQ(output1, output2);
97
0
}
98
99
0
void YBAdminMultiMasterTest::TestRemoveDownMaster(UseUUID use_uuid) {
100
0
  const int kNumInitMasters = 3;
101
0
  const auto admin_path = GetToolPath(kAdminToolName);
102
0
  ASSERT_NO_FATALS(StartCluster({}, {}, 1/*num tservers*/, kNumInitMasters));
103
0
  const auto master_addrs = cluster_->GetMasterAddresses();
104
0
  auto idx = ASSERT_RESULT(cluster_->GetFirstNonLeaderMasterIndex());
105
0
  const auto addr = cluster_->master(idx)->bound_rpc_addr();
106
0
  const auto uuid = cluster_->master(idx)->uuid();
107
0
  ASSERT_OK(cluster_->master(idx)->Pause());
108
109
0
  std::string output2;
110
0
  ASSERT_OK(Subprocess::Call(ToStringVector(
111
0
      admin_path, "-master_addresses", cluster_->GetMasterAddresses(),
112
0
      "list_all_masters"), &output2));
113
0
  LOG(INFO) << "list_all_masters \n" << output2;
114
0
  const auto lines2 = StringSplit(output2, '\n');
115
0
  ASSERT_EQ(lines2.size(), kNumInitMasters + 1);
116
117
0
  std::string output3;
118
0
  auto args = ToStringVector(
119
0
      admin_path, "-master_addresses", cluster_->GetMasterAddresses(), "change_master_config",
120
0
      "REMOVE_SERVER", addr.host(), addr.port());
121
0
  if (use_uuid) {
122
0
    args.push_back(uuid);
123
0
  }
124
0
  ASSERT_OK(Subprocess::Call(args, &output3));
125
0
  LOG(INFO) << "change_master_config: REMOVE_SERVER\n" << output3;
126
127
0
  std::string output4;
128
0
  ASSERT_OK(Subprocess::Call(ToStringVector(
129
0
      admin_path, "-master_addresses", cluster_->GetMasterAddresses(),
130
0
      "list_all_masters"), &output4));
131
0
  LOG(INFO) << "list_all_masters \n" << output4;
132
0
  const auto lines4 = StringSplit(output4, '\n');
133
0
  ASSERT_EQ(lines4.size(), kNumInitMasters);
134
0
}
135
136
0
TEST_F(YBAdminMultiMasterTest, RemoveDownMaster) {
137
0
  TestRemoveDownMaster(UseUUID::kFalse);
138
0
}
139
140
0
TEST_F(YBAdminMultiMasterTest, RemoveDownMasterByUuid) {
141
0
  TestRemoveDownMaster(UseUUID::kTrue);
142
0
}
143
144
0
TEST_F(YBAdminMultiMasterTest, AddShellMaster) {
145
0
  const auto admin_path = GetToolPath(kAdminToolName);
146
0
  const int kNumInitMasters = 2;
147
0
  ASSERT_NO_FATALS(StartCluster({}, {}, 1/*num tservers*/, kNumInitMasters));
148
0
  const auto master_addrs = cluster_->GetMasterAddresses();
149
150
0
  std::string output2;
151
0
  ASSERT_OK(Subprocess::Call(ToStringVector(
152
0
      admin_path, "-master_addresses", cluster_->GetMasterAddresses(),
153
0
      "list_all_masters"), &output2));
154
0
  LOG(INFO) << "list_all_masters \n" << output2;
155
0
  const auto lines2 = StringSplit(output2, '\n');
156
0
  ASSERT_EQ(lines2.size(), kNumInitMasters + 1);
157
158
0
  ExternalMaster* shell_master = nullptr;
159
0
  cluster_->StartShellMaster(&shell_master);
160
0
  ASSERT_NE(shell_master, nullptr);
161
0
  scoped_refptr<ExternalMaster> shell_master_ref(shell_master);
162
0
  const auto shell_addr = shell_master->bound_rpc_addr();
163
164
0
  std::string output3;
165
0
  ASSERT_OK(Subprocess::Call(ToStringVector(
166
0
      admin_path, "-master_addresses", cluster_->GetMasterAddresses(),
167
0
      "change_master_config", "ADD_SERVER", shell_addr.host(), shell_addr.port()), &output3));
168
0
  LOG(INFO) << "change_master_config: ADD_SERVER\n" << output3;
169
170
0
  std::string output4;
171
0
  ASSERT_OK(Subprocess::Call(ToStringVector(
172
0
      admin_path, "-master_addresses", cluster_->GetMasterAddresses(),
173
0
      "list_all_masters"), &output4));
174
0
  LOG(INFO) << "list_all_masters \n" << output4;
175
0
  const auto lines4 = StringSplit(output4, '\n');
176
0
  ASSERT_EQ(lines4.size(), kNumInitMasters + 2);
177
0
}
178
179
0
TEST_F(YBAdminMultiMasterTest, TestMasterLeaderStepdown) {
180
0
  const int kNumInitMasters = 3;
181
0
  ASSERT_NO_FATALS(StartCluster({}, {}, 1/*num tservers*/, kNumInitMasters));
182
0
  std::string out;
183
0
  auto call_admin = [
184
0
      &out,
185
0
      admin_path = GetToolPath(kAdminToolName),
186
0
      master_address = ToString(cluster_->GetMasterAddresses())] (
187
0
      const std::initializer_list<std::string>& args) mutable {
188
0
    auto cmds = ToStringVector(admin_path, "-master_addresses", master_address);
189
0
    std::copy(args.begin(), args.end(), std::back_inserter(cmds));
190
0
    return Subprocess::Call(cmds, &out);
191
0
  };
192
0
  auto regex_fetch_first = [&out](const std::string& exp) -> Result<std::string> {
193
0
    std::smatch match;
194
0
    if (!std::regex_search(out.cbegin(), out.cend(), match, std::regex(exp)) || match.size() != 2) {
195
0
      return STATUS_FORMAT(NotFound, "No pattern in '$0'", out);
196
0
    }
197
0
    return match[1];
198
0
  };
199
200
0
  ASSERT_OK(call_admin({"list_all_masters"}));
201
0
  const auto new_leader_id = ASSERT_RESULT(
202
0
      regex_fetch_first(R"(\s+([a-z0-9]{32})\s+\S+\s+\S+\s+FOLLOWER)"));
203
0
  ASSERT_OK(call_admin({"master_leader_stepdown", new_leader_id}));
204
205
0
  ASSERT_OK(WaitFor([&]() -> Result<bool> {
206
0
    RETURN_NOT_OK(call_admin({"list_all_masters"}));
207
0
    return new_leader_id ==
208
0
        VERIFY_RESULT(regex_fetch_first(R"(\s+([a-z0-9]{32})\s+\S+\s+\S+\s+LEADER)"));
209
0
  }, 5s, "Master leader stepdown"));
210
211
0
  ASSERT_OK(call_admin({"master_leader_stepdown"}));
212
213
0
  ASSERT_OK(WaitFor([&]() -> Result<bool> {
214
0
    RETURN_NOT_OK(call_admin({"list_all_masters"}));
215
0
    return new_leader_id !=
216
0
      VERIFY_RESULT(regex_fetch_first(R"(\s+([a-z0-9]{32})\s+\S+\s+\S+\s+LEADER)"));
217
0
  }, 5s, "Master leader stepdown"));
218
0
}
219
220
}  // namespace tools
221
}  // namespace yb