/Users/deen/code/yugabyte-db/src/yb/tools/yb-admin_cli.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 | | |
33 | | #include "yb/tools/yb-admin_cli.h" |
34 | | |
35 | | #include <memory> |
36 | | #include <utility> |
37 | | |
38 | | #include <boost/lexical_cast.hpp> |
39 | | |
40 | | #include "yb/common/json_util.h" |
41 | | |
42 | | #include "yb/master/master_defaults.h" |
43 | | |
44 | | #include "yb/tools/yb-admin_client.h" |
45 | | |
46 | | #include "yb/util/flags.h" |
47 | | #include "yb/util/logging.h" |
48 | | #include "yb/util/status_format.h" |
49 | | #include "yb/util/stol_utils.h" |
50 | | #include "yb/util/string_case.h" |
51 | | |
52 | | DEFINE_string(master_addresses, "localhost:7100", |
53 | | "Comma-separated list of YB Master server addresses"); |
54 | | DEFINE_string(init_master_addrs, "", |
55 | | "host:port of any yb-master in a cluster"); |
56 | | DEFINE_int64(timeout_ms, 1000 * 60, "RPC timeout in milliseconds"); |
57 | | DEFINE_bool(exclude_dead, false, "Exclude dead tservers from output"); |
58 | | |
59 | | |
60 | | using std::cerr; |
61 | | using std::endl; |
62 | | using std::ostringstream; |
63 | | using std::make_pair; |
64 | | using std::next; |
65 | | using std::pair; |
66 | | using std::string; |
67 | | |
68 | | using yb::client::YBTableName; |
69 | | using strings::Substitute; |
70 | | |
71 | | using namespace std::placeholders; |
72 | | |
73 | | namespace yb { |
74 | | namespace tools { |
75 | | |
76 | | const Status ClusterAdminCli::kInvalidArguments = STATUS( |
77 | | InvalidArgument, "Invalid arguments for operation"); |
78 | | |
79 | | namespace { |
80 | | |
81 | | constexpr auto kBlacklistAdd = "ADD"; |
82 | | constexpr auto kBlacklistRemove = "REMOVE"; |
83 | | constexpr int32 kDefaultRpcPort = 9100; |
84 | | |
85 | | CHECKED_STATUS GetUniverseConfig(ClusterAdminClientClass* client, |
86 | 0 | const ClusterAdminCli::CLIArguments&) { |
87 | 0 | RETURN_NOT_OK_PREPEND(client->GetUniverseConfig(), "Unable to get universe config"); |
88 | 0 | return Status::OK(); |
89 | 0 | } |
90 | | |
91 | | CHECKED_STATUS ChangeBlacklist(ClusterAdminClientClass* client, |
92 | | const ClusterAdminCli::CLIArguments& args, bool blacklist_leader, |
93 | 0 | const std::string& errStr) { |
94 | 0 | if (args.size() < 2) { |
95 | 0 | return ClusterAdminCli::kInvalidArguments; |
96 | 0 | } |
97 | 0 | const auto change_type = args[0]; |
98 | 0 | if (change_type != kBlacklistAdd && change_type != kBlacklistRemove) { |
99 | 0 | return ClusterAdminCli::kInvalidArguments; |
100 | 0 | } |
101 | 0 | std::vector<HostPort> hostports; |
102 | 0 | for (const auto& arg : boost::make_iterator_range(args.begin() + 1, args.end())) { |
103 | 0 | hostports.push_back(VERIFY_RESULT(HostPort::FromString(arg, kDefaultRpcPort))); |
104 | 0 | } |
105 | |
|
106 | 0 | RETURN_NOT_OK_PREPEND(client->ChangeBlacklist(hostports, change_type == kBlacklistAdd, |
107 | 0 | blacklist_leader), errStr); |
108 | 0 | return Status::OK(); |
109 | 0 | } |
110 | | |
111 | | CHECKED_STATUS MasterLeaderStepDown( |
112 | | ClusterAdminClientClass* client, |
113 | 0 | const ClusterAdminCli::CLIArguments& args) { |
114 | 0 | const auto leader_uuid = VERIFY_RESULT(client->GetMasterLeaderUuid()); |
115 | 0 | return client->MasterLeaderStepDown( |
116 | 0 | leader_uuid, args.size() > 0 ? args[0] : std::string()); |
117 | 0 | } |
118 | | |
119 | | CHECKED_STATUS LeaderStepDown( |
120 | | ClusterAdminClientClass* client, |
121 | 0 | const ClusterAdminCli::CLIArguments& args) { |
122 | 0 | if (args.size() < 1) { |
123 | 0 | return ClusterAdminCli::kInvalidArguments; |
124 | 0 | } |
125 | 0 | std::string dest_uuid = (args.size() > 1) ? args[1] : ""; |
126 | 0 | RETURN_NOT_OK_PREPEND( |
127 | 0 | client->LeaderStepDownWithNewLeader(args[0], dest_uuid), "Unable to step down leader"); |
128 | 0 | return Status::OK(); |
129 | 0 | } |
130 | | |
131 | 0 | bool IsEqCaseInsensitive(const string& check, const string& expected) { |
132 | 0 | string upper_check, upper_expected; |
133 | 0 | ToUpperCase(check, &upper_check); |
134 | 0 | ToUpperCase(expected, &upper_expected); |
135 | 0 | return upper_check == upper_expected; |
136 | 0 | } |
137 | | |
138 | | template <class Enum> |
139 | | Result<std::pair<int, EnumBitSet<Enum>>> GetValueAndFlags( |
140 | | const CLIArgumentsIterator& begin, |
141 | | const CLIArgumentsIterator& end, |
142 | 0 | const std::initializer_list<Enum>& flags_list) { |
143 | 0 | std::pair<int, EnumBitSet<Enum>> result; |
144 | 0 | bool seen_value = false; |
145 | 0 | for (auto iter = begin; iter != end; iter = ++iter) { |
146 | 0 | bool found_flag = false; |
147 | 0 | for (auto flag : flags_list) { |
148 | 0 | if (IsEqCaseInsensitive(*iter, ToString(flag))) { |
149 | 0 | if (result.second.Test(flag)) { |
150 | 0 | return STATUS_FORMAT(InvalidArgument, "Duplicate flag: $0", flag); |
151 | 0 | } |
152 | 0 | result.second.Set(flag); |
153 | 0 | found_flag = true; |
154 | 0 | break; |
155 | 0 | } |
156 | 0 | } |
157 | 0 | if (found_flag) { |
158 | 0 | continue; |
159 | 0 | } |
160 | | |
161 | 0 | if (seen_value) { |
162 | 0 | return STATUS_FORMAT(InvalidArgument, "Multiple values: $0 and $1", result.first, *iter); |
163 | 0 | } |
164 | | |
165 | 0 | result.first = VERIFY_RESULT(CheckedStoi(*iter)); |
166 | 0 | seen_value = true; |
167 | 0 | } |
168 | |
|
169 | 0 | return result; |
170 | 0 | } Unexecuted instantiation: yb-admin_cli.cc:_ZN2yb5tools12_GLOBAL__N_116GetValueAndFlagsINS1_16ListTabletsFlagsEEENS_6ResultINSt3__14pairIiNS_10EnumBitSetIT_EEEEEERKNS5_11__wrap_iterIPKNS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEEESN_RKSt16initializer_listIS8_E Unexecuted instantiation: yb-admin_cli.cc:_ZN2yb5tools12_GLOBAL__N_116GetValueAndFlagsINS1_10AddIndexesEEENS_6ResultINSt3__14pairIiNS_10EnumBitSetIT_EEEEEERKNS5_11__wrap_iterIPKNS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEEESN_RKSt16initializer_listIS8_E |
171 | | |
172 | | YB_DEFINE_ENUM(AddIndexes, (ADD_INDEXES)); |
173 | | |
174 | | Result<pair<int, bool>> GetTimeoutAndAddIndexesFlag( |
175 | | CLIArgumentsIterator begin, |
176 | 0 | const CLIArgumentsIterator& end) { |
177 | 0 | auto temp_pair = VERIFY_RESULT(GetValueAndFlags(begin, end, kAddIndexesList)); |
178 | 0 | return std::make_pair(temp_pair.first, temp_pair.second.Test(AddIndexes::ADD_INDEXES)); |
179 | 0 | } |
180 | | |
181 | | YB_DEFINE_ENUM(ListTabletsFlags, (JSON)(INCLUDE_FOLLOWERS)); |
182 | | |
183 | | } // namespace |
184 | | |
185 | 1 | Status ClusterAdminCli::Run(int argc, char** argv) { |
186 | 1 | const string prog_name = argv[0]; |
187 | 1 | FLAGS_logtostderr = 1; |
188 | 1 | FLAGS_minloglevel = 2; |
189 | 1 | ParseCommandLineFlags(&argc, &argv, true); |
190 | 1 | InitGoogleLoggingSafe(prog_name.c_str()); |
191 | | |
192 | 1 | std::unique_ptr<ClusterAdminClientClass> client; |
193 | 1 | const string addrs = FLAGS_master_addresses; |
194 | 1 | if (!FLAGS_init_master_addrs.empty()) { |
195 | 0 | std::vector<HostPort> init_master_addrs; |
196 | 0 | RETURN_NOT_OK(HostPort::ParseStrings( |
197 | 0 | FLAGS_init_master_addrs, |
198 | 0 | master::kMasterDefaultPort, |
199 | 0 | &init_master_addrs)); |
200 | 0 | client.reset(new ClusterAdminClientClass( |
201 | 0 | init_master_addrs[0], |
202 | 0 | MonoDelta::FromMilliseconds(FLAGS_timeout_ms))); |
203 | 1 | } else { |
204 | 1 | client.reset(new ClusterAdminClientClass( |
205 | 1 | addrs, |
206 | 1 | MonoDelta::FromMilliseconds(FLAGS_timeout_ms))); |
207 | 1 | } |
208 | | |
209 | 1 | RegisterCommandHandlers(client.get()); |
210 | 1 | SetUsage(prog_name); |
211 | | |
212 | 1 | CLIArguments args; |
213 | 4 | for (int i = 0; i < argc; ++i) { |
214 | 3 | args.push_back(argv[i]); |
215 | 3 | } |
216 | | |
217 | 1 | if (args.size() < 2) { |
218 | 0 | return ClusterAdminCli::kInvalidArguments; |
219 | 0 | } |
220 | | |
221 | | // Find operation handler by operation name. |
222 | 1 | const string op = args[1]; |
223 | 1 | auto cmd = command_indexes_.find(op); |
224 | | |
225 | 1 | if (cmd == command_indexes_.end()) { |
226 | 0 | cerr << "Invalid operation: " << op << endl; |
227 | 0 | return ClusterAdminCli::kInvalidArguments; |
228 | 0 | } |
229 | | |
230 | | // Init client. |
231 | 1 | Status s = client->Init(); |
232 | | |
233 | 1 | if (PREDICT_FALSE(!s.ok())) { |
234 | 0 | cerr << s.CloneAndPrepend("Unable to establish connection to leader master at [" + addrs + "]." |
235 | 0 | " Please verify the addresses.\n\n").ToString() << endl; |
236 | 0 | return STATUS(RuntimeError, "Error connecting to cluster"); |
237 | 0 | } |
238 | | |
239 | | // Run found command. |
240 | 1 | CLIArguments command_args(args.begin() + 2, args.end()); |
241 | 1 | s = commands_[cmd->second].action_(command_args); |
242 | 1 | if (!s.ok()) { |
243 | 0 | cerr << "Error running " << cmd->first << ": " << s << endl; |
244 | 0 | return STATUS(RuntimeError, "Error running command"); |
245 | 0 | } |
246 | 1 | return Status::OK(); |
247 | 1 | } |
248 | | |
249 | 85 | void ClusterAdminCli::Register(string&& cmd_name, string&& cmd_args, Action&& action) { |
250 | 85 | command_indexes_[cmd_name] = commands_.size(); |
251 | 85 | commands_.push_back({std::move(cmd_name), std::move(cmd_args), std::move(action)}); |
252 | 85 | } |
253 | | |
254 | 6 | void ClusterAdminCli::RegisterJson(string&& cmd_name, string&& cmd_args, JsonAction&& action) { |
255 | 0 | Register(std::move(cmd_name), std::move(cmd_args), [action](const CLIArguments& args) -> Status { |
256 | 0 | auto result = VERIFY_RESULT(action(args)); |
257 | 0 | std::cout << common::PrettyWriteRapidJsonToString(result) << std::endl; |
258 | 0 | return Status::OK(); |
259 | 0 | }); |
260 | 6 | } |
261 | | |
262 | 1 | void ClusterAdminCli::SetUsage(const string& prog_name) { |
263 | 1 | ostringstream str; |
264 | | |
265 | 1 | str << prog_name << " [-master_addresses server1:port,server2:port,server3:port,...] " |
266 | 1 | << " [-timeout_ms <millisec>] [-certs_dir_name <dir_name>] <operation>" << endl |
267 | 1 | << "<operation> must be one of:" << endl; |
268 | | |
269 | 86 | for (size_t i = 0; i < commands_.size(); ++i) { |
270 | 85 | str << ' ' << i + 1 << ". " << commands_[i].name_ << commands_[i].usage_arguments_ << endl; |
271 | 85 | } |
272 | | |
273 | 1 | str << endl; |
274 | 1 | str << "<namespace>:" << endl; |
275 | 1 | str << " [(ycql|ysql).]<namespace_name>" << endl; |
276 | 1 | str << "<table>:" << endl; |
277 | 1 | str << " <namespace> <table_name> | tableid.<table_id>" << endl; |
278 | 1 | str << "<index>:" << endl; |
279 | 1 | str << " <namespace> <index_name> | tableid.<index_id>" << endl; |
280 | | |
281 | 1 | google::SetUsageMessage(str.str()); |
282 | 1 | } |
283 | | |
284 | | Result<rapidjson::Document> DdlLog( |
285 | 0 | ClusterAdminClientClass* client, const ClusterAdminCli::CLIArguments& args) { |
286 | 0 | RETURN_NOT_OK(CheckArgumentsCount(args.size(), 0, 0)); |
287 | 0 | return client->DdlLog(); |
288 | 0 | } |
289 | | |
290 | 1 | void ClusterAdminCli::RegisterCommandHandlers(ClusterAdminClientClass* client) { |
291 | 1 | DCHECK_ONLY_NOTNULL(client); |
292 | | |
293 | 1 | Register( |
294 | 1 | "change_config", |
295 | 1 | " <tablet_id> <ADD_SERVER|REMOVE_SERVER> <peer_uuid> [PRE_VOTER|PRE_OBSERVER]", |
296 | 0 | [client](const CLIArguments& args) -> Status { |
297 | 0 | if (args.size() < 3) { |
298 | 0 | return ClusterAdminCli::kInvalidArguments; |
299 | 0 | } |
300 | 0 | const string tablet_id = args[0]; |
301 | 0 | const string change_type = args[1]; |
302 | 0 | const string peer_uuid = args[2]; |
303 | 0 | boost::optional<string> member_type; |
304 | 0 | if (args.size() > 3) { |
305 | 0 | member_type = args[3]; |
306 | 0 | } |
307 | 0 | RETURN_NOT_OK_PREPEND(client->ChangeConfig(tablet_id, change_type, peer_uuid, member_type), |
308 | 0 | "Unable to change config"); |
309 | 0 | return Status::OK(); |
310 | 0 | }); |
311 | | |
312 | 1 | Register( |
313 | 1 | "list_tablet_servers", " <tablet_id>", |
314 | 0 | [client](const CLIArguments& args) -> Status { |
315 | 0 | if (args.size() < 1) { |
316 | 0 | return ClusterAdminCli::kInvalidArguments; |
317 | 0 | } |
318 | 0 | const string tablet_id = args[0]; |
319 | 0 | RETURN_NOT_OK_PREPEND(client->ListPerTabletTabletServers(tablet_id), |
320 | 0 | Substitute("Unable to list tablet servers of tablet $0", tablet_id)); |
321 | 0 | return Status::OK(); |
322 | 0 | }); |
323 | | |
324 | 1 | Register( |
325 | 1 | "backfill_indexes_for_table", " <table>", |
326 | 0 | [client](const CLIArguments& args) -> Status { |
327 | 0 | const auto table_name = VERIFY_RESULT( |
328 | 0 | ResolveSingleTableName(client, args.begin(), args.end())); |
329 | 0 | RETURN_NOT_OK_PREPEND(client->LaunchBackfillIndexForTable(table_name), |
330 | 0 | yb::Format("Unable to launch backfill for indexes in $0", |
331 | 0 | table_name)); |
332 | 0 | return Status::OK(); |
333 | 0 | }); |
334 | | |
335 | 1 | static const auto kIncludeDBType = "include_db_type"; |
336 | 1 | static const auto kIncludeTableId = "include_table_id"; |
337 | 1 | static const auto kIncludeTableType = "include_table_type"; |
338 | | |
339 | 1 | Register( |
340 | 1 | "list_tables", Format(" [$0] [$1] [$2]", kIncludeDBType, kIncludeTableId, kIncludeTableType), |
341 | 0 | [client](const CLIArguments& args) -> Status { |
342 | 0 | bool include_db_type = false; |
343 | 0 | bool include_table_id = false; |
344 | 0 | bool include_table_type = false; |
345 | 0 | const std::array<std::pair<const char*, bool*>, 3> flags{ |
346 | 0 | std::make_pair(kIncludeDBType, &include_db_type), |
347 | 0 | std::make_pair(kIncludeTableId, &include_table_id), |
348 | 0 | std::make_pair(kIncludeTableType, &include_table_type) |
349 | 0 | }; |
350 | 0 | for (const auto& arg : args) { |
351 | 0 | for (const auto& flag : flags) { |
352 | 0 | if (flag.first == arg) { |
353 | 0 | *flag.second = true; |
354 | 0 | } |
355 | 0 | } |
356 | 0 | } |
357 | 0 | RETURN_NOT_OK_PREPEND(client->ListTables(include_db_type, |
358 | 0 | include_table_id, |
359 | 0 | include_table_type), |
360 | 0 | "Unable to list tables"); |
361 | 0 | return Status::OK(); |
362 | 0 | }); |
363 | | |
364 | | // Deprecated list_tables commands with arguments should be used instead. |
365 | 1 | Register( |
366 | 1 | "list_tables_with_db_types", "", |
367 | 0 | [client](const CLIArguments&) -> Status { |
368 | 0 | RETURN_NOT_OK_PREPEND( |
369 | 0 | client->ListTables(true /* include_db_type */, |
370 | 0 | false /* include_table_id*/, |
371 | 0 | false /* include_table_type*/), |
372 | 0 | "Unable to list tables"); |
373 | 0 | return Status::OK(); |
374 | 0 | }); |
375 | | |
376 | 1 | Register( |
377 | 1 | "list_tablets", |
378 | 1 | " <table> [max_tablets] (default 10, set 0 for max) [JSON] [include_followers]", |
379 | 0 | [client](const CLIArguments& args) -> Status { |
380 | 0 | std::pair<int, EnumBitSet<ListTabletsFlags>> arguments; |
381 | 0 | const auto table_name = VERIFY_RESULT(ResolveSingleTableName( |
382 | 0 | client, args.begin(), args.end(), |
383 | 0 | [&arguments](auto i, const auto& end) -> Status { |
384 | 0 | arguments = VERIFY_RESULT(GetValueAndFlags(i, end, kListTabletsFlagsList)); |
385 | 0 | return Status::OK(); |
386 | 0 | })); |
387 | 0 | RETURN_NOT_OK_PREPEND( |
388 | 0 | client->ListTablets( |
389 | 0 | table_name, arguments.first, arguments.second.Test(ListTabletsFlags::JSON), |
390 | 0 | arguments.second.Test(ListTabletsFlags::INCLUDE_FOLLOWERS)), |
391 | 0 | Format("Unable to list tablets of table $0", table_name)); |
392 | 0 | return Status::OK(); |
393 | 0 | }); |
394 | | |
395 | 1 | static const auto kTableName = "<(<keyspace> <table_name>)|tableid.<table_id>>"; |
396 | 1 | static const auto kPlacementInfo = "placement_info"; |
397 | 1 | static const auto kReplicationFactor = "replication_factor"; |
398 | 1 | static const auto kPlacementUuid = "placement_uuid"; |
399 | | |
400 | 1 | Register( |
401 | 1 | "modify_table_placement_info", |
402 | 1 | Format(" [$0] [$1] [$2] [$3]", kTableName, kPlacementInfo, kReplicationFactor, |
403 | 1 | kPlacementUuid), |
404 | 0 | [client](const CLIArguments& args) -> Status { |
405 | 0 | if (args.size() < 3 || args.size() > 5) { |
406 | 0 | return ClusterAdminCli::kInvalidArguments; |
407 | 0 | } |
408 | 0 | std::string placement_info; |
409 | 0 | int rf = -1; |
410 | 0 | std::string placement_uuid; |
411 | 0 | const auto table_name = VERIFY_RESULT(ResolveSingleTableName( |
412 | 0 | client, args.begin(), args.end(), |
413 | 0 | [&placement_info, &rf, &placement_uuid]( |
414 | 0 | auto i, const auto& end) -> Status { |
415 | | // Get placement info. |
416 | 0 | placement_info = *i; |
417 | 0 | i = std::next(i); |
418 | | // Get replication factor. |
419 | 0 | rf = VERIFY_RESULT(CheckedStoi(*i)); |
420 | 0 | i = std::next(i); |
421 | | // Get optional placement uuid. |
422 | 0 | if (i != end) { |
423 | 0 | placement_uuid = *i; |
424 | 0 | } |
425 | 0 | return Status::OK(); |
426 | 0 | } |
427 | 0 | )); |
428 | 0 | RETURN_NOT_OK_PREPEND( |
429 | 0 | client->ModifyTablePlacementInfo(table_name, placement_info, rf, placement_uuid), |
430 | 0 | Substitute("Unable to modify placement info for table $0", table_name.ToString())); |
431 | 0 | return Status::OK(); |
432 | 0 | }); |
433 | | |
434 | 1 | Register( |
435 | 1 | "modify_placement_info", " <placement_info> <replication_factor> [placement_uuid]", |
436 | 0 | [client](const CLIArguments& args) -> Status { |
437 | 0 | if (args.size() != 2 && args.size() != 3) { |
438 | 0 | return ClusterAdminCli::kInvalidArguments; |
439 | 0 | } |
440 | 0 | int rf = boost::lexical_cast<int>(args[1]); |
441 | 0 | string placement_uuid = args.size() == 3 ? args[2] : ""; |
442 | 0 | RETURN_NOT_OK_PREPEND(client->ModifyPlacementInfo(args[0], rf, placement_uuid), |
443 | 0 | Substitute("Unable to modify placement info.")); |
444 | 0 | return Status::OK(); |
445 | 0 | }); |
446 | | |
447 | 1 | Register( |
448 | 1 | "clear_placement_info", "", |
449 | 0 | [client](const CLIArguments& args) -> Status { |
450 | 0 | if (args.size() != 0) { |
451 | 0 | return ClusterAdminCli::kInvalidArguments; |
452 | 0 | } |
453 | 0 | RETURN_NOT_OK_PREPEND(client->ClearPlacementInfo(), |
454 | 0 | Substitute("Unable to clear placement info.")); |
455 | 0 | return Status::OK(); |
456 | 0 | }); |
457 | | |
458 | 1 | Register( |
459 | 1 | "add_read_replica_placement_info", " <placement_info> <replication_factor> [placement_uuid]", |
460 | 0 | [client](const CLIArguments& args) -> Status { |
461 | 0 | if (args.size() != 2 && args.size() != 3) { |
462 | 0 | return ClusterAdminCli::kInvalidArguments; |
463 | 0 | } |
464 | 0 | int rf = boost::lexical_cast<int>(args[1]); |
465 | 0 | string placement_uuid = args.size() == 3 ? args[2] : ""; |
466 | 0 | RETURN_NOT_OK_PREPEND(client->AddReadReplicaPlacementInfo(args[0], rf, placement_uuid), |
467 | 0 | Substitute("Unable to add read replica placement info.")); |
468 | 0 | return Status::OK(); |
469 | 0 | }); |
470 | | |
471 | 1 | Register( |
472 | 1 | "modify_read_replica_placement_info", |
473 | 1 | " <placement_info> <replication_factor> [placement_uuid]", |
474 | 0 | [client](const CLIArguments& args) -> Status { |
475 | 0 | if (args.size() != 2 && args.size() != 3) { |
476 | 0 | return ClusterAdminCli::kInvalidArguments; |
477 | 0 | } |
478 | 0 | int rf = boost::lexical_cast<int>(args[1]); |
479 | 0 | string placement_uuid = args.size() == 3 ? args[2] : ""; |
480 | 0 | RETURN_NOT_OK_PREPEND(client->ModifyReadReplicaPlacementInfo(placement_uuid, args[0], rf), |
481 | 0 | Substitute("Unable to modify read replica placement info.")); |
482 | 0 | return Status::OK(); |
483 | 0 | }); |
484 | | |
485 | 1 | Register( |
486 | 1 | "delete_read_replica_placement_info", "", |
487 | 0 | [client](const CLIArguments& args) -> Status { |
488 | 0 | if (args.size() != 0) { |
489 | 0 | return ClusterAdminCli::kInvalidArguments; |
490 | 0 | } |
491 | 0 | RETURN_NOT_OK_PREPEND(client->DeleteReadReplicaPlacementInfo(), |
492 | 0 | Substitute("Unable to delete read replica placement info.")); |
493 | 0 | return Status::OK(); |
494 | 0 | }); |
495 | | |
496 | 1 | Register( |
497 | 1 | "delete_namespace", " <namespace>", |
498 | 1 | [client](const CLIArguments& args) -> Status { |
499 | 1 | if (args.size() != 1) { |
500 | 0 | return ClusterAdminCli::kInvalidArguments; |
501 | 0 | } |
502 | 1 | auto namespace_name = VERIFY_RESULT(ParseNamespaceName(args[0])); |
503 | 1 | RETURN_NOT_OK_PREPEND(client->DeleteNamespace(namespace_name), |
504 | 1 | Substitute("Unable to delete namespace $0", namespace_name.name)); |
505 | 1 | return Status::OK(); |
506 | 1 | }); |
507 | | |
508 | 1 | Register( |
509 | 1 | "delete_namespace_by_id", " <namespace_id>", |
510 | 0 | [client](const CLIArguments& args) -> Status { |
511 | 0 | if (args.size() != 1) { |
512 | 0 | return ClusterAdminCli::kInvalidArguments; |
513 | 0 | } |
514 | 0 | RETURN_NOT_OK_PREPEND(client->DeleteNamespaceById(args[0]), |
515 | 0 | Substitute("Unable to delete namespace $0", args[0])); |
516 | 0 | return Status::OK(); |
517 | 0 | }); |
518 | | |
519 | 1 | Register( |
520 | 1 | "delete_table", " <table>", |
521 | 0 | [client](const CLIArguments& args) -> Status { |
522 | 0 | const auto table_name = VERIFY_RESULT( |
523 | 0 | ResolveSingleTableName(client, args.begin(), args.end())); |
524 | 0 | RETURN_NOT_OK_PREPEND(client->DeleteTable(table_name), |
525 | 0 | Substitute("Unable to delete table $0", table_name.ToString())); |
526 | 0 | return Status::OK(); |
527 | 0 | }); |
528 | | |
529 | 1 | Register( |
530 | 1 | "delete_table_by_id", " <table_id>", |
531 | 0 | [client](const CLIArguments& args) -> Status { |
532 | 0 | if (args.size() != 1) { |
533 | 0 | return ClusterAdminCli::kInvalidArguments; |
534 | 0 | } |
535 | 0 | RETURN_NOT_OK_PREPEND(client->DeleteTableById(args[0]), |
536 | 0 | Substitute("Unable to delete table $0", args[0])); |
537 | 0 | return Status::OK(); |
538 | 0 | }); |
539 | | |
540 | 1 | Register( |
541 | 1 | "delete_index", " <index>", |
542 | 0 | [client](const CLIArguments& args) -> Status { |
543 | 0 | const auto table_name = VERIFY_RESULT( |
544 | 0 | ResolveSingleTableName(client, args.begin(), args.end())); |
545 | 0 | RETURN_NOT_OK_PREPEND(client->DeleteIndex(table_name), |
546 | 0 | Substitute("Unable to delete index $0", table_name.ToString())); |
547 | 0 | return Status::OK(); |
548 | 0 | }); |
549 | | |
550 | 1 | Register( |
551 | 1 | "delete_index_by_id", " <index_id>", |
552 | 0 | [client](const CLIArguments& args) -> Status { |
553 | 0 | if (args.size() != 1) { |
554 | 0 | return ClusterAdminCli::kInvalidArguments; |
555 | 0 | } |
556 | 0 | RETURN_NOT_OK_PREPEND(client->DeleteIndexById(args[0]), |
557 | 0 | Substitute("Unable to delete index $0", args[0])); |
558 | 0 | return Status::OK(); |
559 | 0 | }); |
560 | | |
561 | 1 | Register( |
562 | 1 | "flush_table", |
563 | 1 | " <table> [timeout_in_seconds] (default 20)" |
564 | 1 | " [ADD_INDEXES] (default false)", |
565 | 0 | [client](const CLIArguments& args) -> Status { |
566 | 0 | bool add_indexes = false; |
567 | 0 | int timeout_secs = 20; |
568 | 0 | const auto table_name = VERIFY_RESULT(ResolveSingleTableName( |
569 | 0 | client, args.begin(), args.end(), |
570 | 0 | [&add_indexes, &timeout_secs](auto i, const auto& end) -> Status { |
571 | 0 | std::tie(timeout_secs, add_indexes) = VERIFY_RESULT( |
572 | 0 | GetTimeoutAndAddIndexesFlag(i, end)); |
573 | 0 | return Status::OK(); |
574 | 0 | })); |
575 | 0 | RETURN_NOT_OK_PREPEND(client->FlushTables({table_name}, |
576 | 0 | add_indexes, |
577 | 0 | timeout_secs, |
578 | 0 | false /* is_compaction */), |
579 | 0 | Substitute("Unable to flush table $0", table_name.ToString())); |
580 | 0 | return Status::OK(); |
581 | 0 | }); |
582 | | |
583 | 1 | Register( |
584 | 1 | "flush_table_by_id", " <table_id> [timeout_in_seconds] (default 20)" |
585 | 1 | " [ADD_INDEXES] (default false)", |
586 | 0 | [client](const CLIArguments& args) -> Status { |
587 | 0 | bool add_indexes = false; |
588 | 0 | int timeout_secs = 20; |
589 | 0 | if (args.size() < 1) { |
590 | 0 | return ClusterAdminCli::kInvalidArguments; |
591 | 0 | } |
592 | 0 | std::tie(timeout_secs, add_indexes) = VERIFY_RESULT(GetTimeoutAndAddIndexesFlag( |
593 | 0 | args.begin() + 1, args.end())); |
594 | 0 | RETURN_NOT_OK_PREPEND(client->FlushTablesById({args[0]}, |
595 | 0 | add_indexes, |
596 | 0 | timeout_secs, |
597 | 0 | false /* is_compaction */), |
598 | 0 | Substitute("Unable to flush table $0", args[0])); |
599 | 0 | return Status::OK(); |
600 | 0 | }); |
601 | | |
602 | 1 | Register( |
603 | 1 | "flush_sys_catalog", "", |
604 | 0 | [client](const CLIArguments& args) -> Status { |
605 | 0 | RETURN_NOT_OK_PREPEND(client->FlushSysCatalog(), "Unable to flush table sys_catalog"); |
606 | 0 | return Status::OK(); |
607 | 0 | }); |
608 | | |
609 | 1 | Register( |
610 | 1 | "compact_sys_catalog", "", |
611 | 0 | [client](const CLIArguments& args) -> Status { |
612 | 0 | RETURN_NOT_OK_PREPEND(client->CompactSysCatalog(), "Unable to compact table sys_catalog"); |
613 | 0 | return Status::OK(); |
614 | 0 | }); |
615 | | |
616 | 1 | Register( |
617 | 1 | "compact_table", |
618 | 1 | " <table> [timeout_in_seconds] (default 20)" |
619 | 1 | " [ADD_INDEXES] (default false)", |
620 | 0 | [client](const CLIArguments& args) -> Status { |
621 | 0 | bool add_indexes = false; |
622 | 0 | int timeout_secs = 20; |
623 | 0 | const auto table_name = VERIFY_RESULT(ResolveSingleTableName( |
624 | 0 | client, args.begin(), args.end(), |
625 | 0 | [&add_indexes, &timeout_secs](auto i, const auto& end) -> Status { |
626 | 0 | std::tie(timeout_secs, add_indexes) = VERIFY_RESULT( |
627 | 0 | GetTimeoutAndAddIndexesFlag(i, end)); |
628 | 0 | return Status::OK(); |
629 | 0 | })); |
630 | | // We use the same FlushTables RPC to trigger compaction. |
631 | 0 | RETURN_NOT_OK_PREPEND(client->FlushTables({table_name}, |
632 | 0 | add_indexes, |
633 | 0 | timeout_secs, |
634 | 0 | true /* is_compaction */), |
635 | 0 | Substitute("Unable to compact table $0", table_name.ToString())); |
636 | 0 | return Status::OK(); |
637 | 0 | }); |
638 | | |
639 | 1 | Register( |
640 | 1 | "compact_table_by_id", " <table_id> [timeout_in_seconds] (default 20)" |
641 | 1 | " [ADD_INDEXES] (default false)", |
642 | 0 | [client](const CLIArguments& args) -> Status { |
643 | 0 | bool add_indexes = false; |
644 | 0 | int timeout_secs = 20; |
645 | 0 | if (args.size() < 1) { |
646 | 0 | return ClusterAdminCli::kInvalidArguments; |
647 | 0 | } |
648 | 0 | std::tie(timeout_secs, add_indexes) = VERIFY_RESULT( |
649 | 0 | GetTimeoutAndAddIndexesFlag(args.begin() + 1, args.end())); |
650 | | // We use the same FlushTables RPC to trigger compaction. |
651 | 0 | RETURN_NOT_OK_PREPEND(client->FlushTablesById({args[0]}, |
652 | 0 | add_indexes, |
653 | 0 | timeout_secs, |
654 | 0 | true /* is_compaction */), |
655 | 0 | Substitute("Unable to compact table $0", args[0])); |
656 | 0 | return Status::OK(); |
657 | 0 | }); |
658 | | |
659 | 1 | Register( |
660 | 1 | "list_all_tablet_servers", "", |
661 | 0 | [client](const CLIArguments&) -> Status { |
662 | 0 | RETURN_NOT_OK_PREPEND(client->ListAllTabletServers(FLAGS_exclude_dead), |
663 | 0 | "Unable to list tablet servers"); |
664 | 0 | return Status::OK(); |
665 | 0 | }); |
666 | | |
667 | 1 | Register( |
668 | 1 | "list_all_masters", "", |
669 | 0 | [client](const CLIArguments&) -> Status { |
670 | 0 | RETURN_NOT_OK_PREPEND(client->ListAllMasters(), |
671 | 0 | "Unable to list masters"); |
672 | 0 | return Status::OK(); |
673 | 0 | }); |
674 | | |
675 | 1 | Register( |
676 | 1 | "change_master_config", " <ADD_SERVER|REMOVE_SERVER> <ip_addr> <port> [<uuid>]", |
677 | 0 | [client](const CLIArguments& args) -> Status { |
678 | 0 | uint16_t new_port = 0; |
679 | 0 | string new_host; |
680 | |
|
681 | 0 | if (args.size() < 3 || args.size() > 4) { |
682 | 0 | return ClusterAdminCli::kInvalidArguments; |
683 | 0 | } |
684 | | |
685 | 0 | const string change_type = args[0]; |
686 | 0 | if (change_type != "ADD_SERVER" && change_type != "REMOVE_SERVER") { |
687 | 0 | return ClusterAdminCli::kInvalidArguments; |
688 | 0 | } |
689 | | |
690 | 0 | new_host = args[1]; |
691 | 0 | new_port = VERIFY_RESULT(CheckedStoi(args[2])); |
692 | |
|
693 | 0 | string given_uuid; |
694 | 0 | if (args.size() == 4) { |
695 | 0 | given_uuid = args[3]; |
696 | 0 | } |
697 | 0 | RETURN_NOT_OK_PREPEND( |
698 | 0 | client->ChangeMasterConfig(change_type, new_host, new_port, given_uuid), |
699 | 0 | "Unable to change master config"); |
700 | 0 | return Status::OK(); |
701 | 0 | }); |
702 | | |
703 | 1 | Register( |
704 | 1 | "dump_masters_state", " [CONSOLE]", |
705 | 0 | [client](const CLIArguments& args) -> Status { |
706 | 0 | bool to_console = false; |
707 | 0 | if (args.size() > 0) { |
708 | 0 | if (IsEqCaseInsensitive(args[0], "CONSOLE")) { |
709 | 0 | to_console = true; |
710 | 0 | } else { |
711 | 0 | return ClusterAdminCli::kInvalidArguments; |
712 | 0 | } |
713 | 0 | } |
714 | 0 | RETURN_NOT_OK_PREPEND(client->DumpMasterState(to_console), |
715 | 0 | "Unable to dump master state"); |
716 | 0 | return Status::OK(); |
717 | 0 | }); |
718 | | |
719 | 1 | Register( |
720 | 1 | "list_tablet_server_log_locations", "", |
721 | 0 | [client](const CLIArguments&) -> Status { |
722 | 0 | RETURN_NOT_OK_PREPEND(client->ListTabletServersLogLocations(), |
723 | 0 | "Unable to list tablet server log locations"); |
724 | 0 | return Status::OK(); |
725 | 0 | }); |
726 | | |
727 | 1 | Register( |
728 | 1 | "list_tablets_for_tablet_server", " <ts_uuid>", |
729 | 0 | [client](const CLIArguments& args) -> Status { |
730 | 0 | if (args.size() != 1) { |
731 | 0 | return ClusterAdminCli::kInvalidArguments; |
732 | 0 | } |
733 | 0 | const string& ts_uuid = args[0]; |
734 | 0 | RETURN_NOT_OK_PREPEND(client->ListTabletsForTabletServer(ts_uuid), |
735 | 0 | "Unable to list tablet server tablets"); |
736 | 0 | return Status::OK(); |
737 | 0 | }); |
738 | | |
739 | 1 | Register( |
740 | 1 | "set_load_balancer_enabled", " <0|1>", |
741 | 0 | [client](const CLIArguments& args) -> Status { |
742 | 0 | if (args.size() != 1) { |
743 | 0 | return ClusterAdminCli::kInvalidArguments; |
744 | 0 | } |
745 | | |
746 | 0 | const bool is_enabled = VERIFY_RESULT(CheckedStoi(args[0])) != 0; |
747 | 0 | RETURN_NOT_OK_PREPEND(client->SetLoadBalancerEnabled(is_enabled), |
748 | 0 | "Unable to change load balancer state"); |
749 | 0 | return Status::OK(); |
750 | 0 | }); |
751 | | |
752 | 1 | Register( |
753 | 1 | "get_load_balancer_state", "", |
754 | 0 | [client](const CLIArguments& args) -> Status { |
755 | 0 | if (args.size() != 0) { |
756 | 0 | return ClusterAdminCli::kInvalidArguments; |
757 | 0 | } |
758 | | |
759 | 0 | RETURN_NOT_OK_PREPEND(client->GetLoadBalancerState(), |
760 | 0 | "Unable to get the load balancer state"); |
761 | 0 | return Status::OK(); |
762 | 0 | }); |
763 | | |
764 | 1 | Register( |
765 | 1 | "get_load_move_completion", "", |
766 | 0 | [client](const CLIArguments&) -> Status { |
767 | 0 | RETURN_NOT_OK_PREPEND(client->GetLoadMoveCompletion(), |
768 | 0 | "Unable to get load completion"); |
769 | 0 | return Status::OK(); |
770 | 0 | }); |
771 | | |
772 | 1 | Register( |
773 | 1 | "get_leader_blacklist_completion", "", |
774 | 0 | [client](const CLIArguments&) -> Status { |
775 | 0 | RETURN_NOT_OK_PREPEND(client->GetLeaderBlacklistCompletion(), |
776 | 0 | "Unable to get leader blacklist completion"); |
777 | 0 | return Status::OK(); |
778 | 0 | }); |
779 | | |
780 | 1 | Register( |
781 | 1 | "get_is_load_balancer_idle", "", |
782 | 0 | [client](const CLIArguments&) -> Status { |
783 | 0 | RETURN_NOT_OK_PREPEND(client->GetIsLoadBalancerIdle(), |
784 | 0 | "Unable to get is load balancer idle"); |
785 | 0 | return Status::OK(); |
786 | 0 | }); |
787 | | |
788 | 1 | Register( |
789 | 1 | "list_leader_counts", " <table>", |
790 | 0 | [client](const CLIArguments& args) -> Status { |
791 | 0 | const auto table_name = VERIFY_RESULT( |
792 | 0 | ResolveSingleTableName(client, args.begin(), args.end())); |
793 | 0 | RETURN_NOT_OK_PREPEND(client->ListLeaderCounts(table_name), |
794 | 0 | "Unable to get leader counts"); |
795 | 0 | return Status::OK(); |
796 | 0 | }); |
797 | | |
798 | 1 | Register( |
799 | 1 | "setup_redis_table", "", |
800 | 0 | [client](const CLIArguments&) -> Status { |
801 | 0 | RETURN_NOT_OK_PREPEND(client->SetupRedisTable(), |
802 | 0 | "Unable to setup Redis keyspace and table"); |
803 | 0 | return Status::OK(); |
804 | 0 | }); |
805 | | |
806 | 1 | Register( |
807 | 1 | "drop_redis_table", "", |
808 | 0 | [client](const CLIArguments&) -> Status { |
809 | 0 | RETURN_NOT_OK_PREPEND(client->DropRedisTable(), |
810 | 0 | "Unable to drop Redis table"); |
811 | 0 | return Status::OK(); |
812 | 0 | }); |
813 | | |
814 | 1 | Register( |
815 | 1 | "get_universe_config", "", |
816 | 1 | std::bind(&GetUniverseConfig, client, _1)); |
817 | | |
818 | 1 | Register( |
819 | 1 | "change_blacklist", Format(" <$0|$1> <ip_addr>:<port> [<ip_addr>:<port>]...", |
820 | 1 | kBlacklistAdd, kBlacklistRemove), |
821 | 1 | std::bind(&ChangeBlacklist, client, _1, false, "Unable to change blacklist")); |
822 | | |
823 | 1 | Register( |
824 | 1 | "change_leader_blacklist", Format(" <$0|$1> <ip_addr>:<port> [<ip_addr>:<port>]...", |
825 | 1 | kBlacklistAdd, kBlacklistRemove), |
826 | 1 | std::bind(&ChangeBlacklist, client, _1, true, "Unable to change leader blacklist")); |
827 | | |
828 | 1 | Register( |
829 | 1 | "master_leader_stepdown", " [dest_uuid]", |
830 | 1 | std::bind(&MasterLeaderStepDown, client, _1)); |
831 | | |
832 | 1 | Register( |
833 | 1 | "leader_stepdown", " <tablet_id> [dest_ts_uuid]", |
834 | 1 | std::bind(&LeaderStepDown, client, _1)); |
835 | | |
836 | 1 | Register( |
837 | 1 | "split_tablet", " <tablet_id>", |
838 | 0 | [client](const CLIArguments& args) -> Status { |
839 | 0 | if (args.size() < 1) { |
840 | 0 | return ClusterAdminCli::kInvalidArguments; |
841 | 0 | } |
842 | 0 | const string tablet_id = args[0]; |
843 | 0 | RETURN_NOT_OK_PREPEND(client->SplitTablet(tablet_id), |
844 | 0 | Format("Unable to start split of tablet $0", tablet_id)); |
845 | 0 | return Status::OK(); |
846 | 0 | }); |
847 | | |
848 | 1 | Register( |
849 | 1 | "create_transaction_table", " <table_name>", |
850 | 0 | [client](const CLIArguments& args) -> Status { |
851 | 0 | if (args.size() < 1) { |
852 | 0 | return ClusterAdminCli::kInvalidArguments; |
853 | 0 | } |
854 | 0 | const string table_name = args[0]; |
855 | 0 | RETURN_NOT_OK_PREPEND(client->CreateTransactionsStatusTable(table_name), |
856 | 0 | Format("Unable to create transaction table named $0", table_name)); |
857 | 0 | return Status::OK(); |
858 | 0 | }); |
859 | | |
860 | 1 | Register( |
861 | 1 | "ysql_catalog_version", "", |
862 | 0 | [client](const CLIArguments&) -> Status { |
863 | 0 | RETURN_NOT_OK_PREPEND(client->GetYsqlCatalogVersion(), |
864 | 0 | "Unable to get catalog version"); |
865 | 0 | return Status::OK(); |
866 | 0 | }); |
867 | | |
868 | 1 | RegisterJson("ddl_log", "", std::bind(&DdlLog, client, _1)); |
869 | | |
870 | 1 | Register( |
871 | 1 | "upgrade_ysql", "", |
872 | 0 | [client](const CLIArguments&) -> Status { |
873 | 0 | RETURN_NOT_OK_PREPEND(client->UpgradeYsql(), |
874 | 0 | "Unable to upgrade YSQL cluster"); |
875 | 0 | return Status::OK(); |
876 | 0 | }); |
877 | | |
878 | 1 | Register( |
879 | | // Today we have a weird pattern recognization for table name. |
880 | | // The expected input argument for the <table> is: |
881 | | // <db type>.<namespace> <table name> |
882 | | // (with a space in between). |
883 | | // So the expected arguement size is 3 (= 2 for the table name + 1 for the retention time). |
884 | 0 | "set_wal_retention_secs", " <table> <seconds>", [client](const CLIArguments& args) -> Status { |
885 | 0 | RETURN_NOT_OK(CheckArgumentsCount(args.size(), 3, 3)); |
886 | |
|
887 | 0 | uint32_t wal_ret_secs = 0; |
888 | 0 | const auto table_name = VERIFY_RESULT( |
889 | 0 | ResolveSingleTableName(client, args.begin(), args.end(), |
890 | 0 | [&wal_ret_secs] (auto i, const auto& end) -> Status { |
891 | 0 | if (PREDICT_FALSE(i == end)) { |
892 | 0 | return STATUS(InvalidArgument, "Table name not found in the command"); |
893 | 0 | } |
894 | |
|
895 | 0 | const auto raw_time = VERIFY_RESULT(CheckedStoi(*i)); |
896 | 0 | if (raw_time < 0) { |
897 | 0 | return STATUS( |
898 | 0 | InvalidArgument, "WAL retention time must be non-negative integer in seconds"); |
899 | 0 | } |
900 | 0 | wal_ret_secs = static_cast<uint32_t>(raw_time); |
901 | 0 | return Status::OK(); |
902 | 0 | } |
903 | 0 | )); |
904 | 0 | RETURN_NOT_OK_PREPEND( |
905 | 0 | client->SetWalRetentionSecs(table_name, wal_ret_secs), |
906 | 0 | "Unable to set WAL retention time (sec) for the cluster"); |
907 | 0 | return Status::OK(); |
908 | 0 | }); |
909 | | |
910 | 0 | Register("get_wal_retention_secs", " <table>", [client](const CLIArguments& args) -> Status { |
911 | 0 | RETURN_NOT_OK(CheckArgumentsCount(args.size(), 2, 2)); |
912 | 0 | const auto table_name = VERIFY_RESULT(ResolveSingleTableName(client, args.begin(), args.end())); |
913 | 0 | RETURN_NOT_OK(client->GetWalRetentionSecs(table_name)); |
914 | 0 | return Status::OK(); |
915 | 0 | }); |
916 | 1 | } // NOLINT, prevents long function message |
917 | | |
918 | | Result<std::vector<client::YBTableName>> ResolveTableNames( |
919 | | ClusterAdminClientClass* client, |
920 | | CLIArgumentsIterator i, |
921 | | const CLIArgumentsIterator& end, |
922 | | const TailArgumentsProcessor& tail_processor, |
923 | 0 | bool allow_namespace_only) { |
924 | 0 | auto resolver = VERIFY_RESULT(client->BuildTableNameResolver()); |
925 | 0 | auto tail = i; |
926 | | // Greedy algorithm of taking as much tables as possible. |
927 | 0 | for (; i != end; ++i) { |
928 | 0 | const auto result = resolver.Feed(*i); |
929 | 0 | if (!result.ok()) { |
930 | | // If tail arguments were not processed suppose it is bad table |
931 | | // and return its parsing error instead. |
932 | 0 | if (tail_processor && tail_processor(tail, end).ok()) { |
933 | 0 | break; |
934 | 0 | } |
935 | 0 | return result.status(); |
936 | 0 | } |
937 | 0 | if (*result) { |
938 | 0 | tail = std::next(i); |
939 | 0 | } |
940 | 0 | } |
941 | |
|
942 | 0 | auto& tables = resolver.values(); |
943 | | // Handle case when no table name is followed keyspace. |
944 | 0 | if (tail != end) { |
945 | 0 | if (tail_processor) { |
946 | 0 | RETURN_NOT_OK(tail_processor(tail, end)); |
947 | 0 | } else { |
948 | 0 | if (allow_namespace_only && tables.empty()) { |
949 | 0 | auto last_namespace = resolver.last_namespace(); |
950 | 0 | if (!last_namespace.name().empty()) { |
951 | 0 | client::YBTableName table_name; |
952 | 0 | table_name.GetFromNamespaceIdentifierPB(last_namespace); |
953 | 0 | return std::vector<client::YBTableName>{table_name}; |
954 | 0 | } |
955 | 0 | } |
956 | 0 | return STATUS(InvalidArgument, "Table name is missed"); |
957 | 0 | } |
958 | 0 | } |
959 | 0 | if (tables.empty()) { |
960 | 0 | return STATUS(InvalidArgument, "Empty list of tables"); |
961 | 0 | } |
962 | 0 | return std::move(tables); |
963 | 0 | } |
964 | | |
965 | | Result<client::YBTableName> ResolveSingleTableName(ClusterAdminClientClass* client, |
966 | | CLIArgumentsIterator i, |
967 | | const CLIArgumentsIterator& end, |
968 | 0 | TailArgumentsProcessor tail_processor) { |
969 | 0 | auto tables = VERIFY_RESULT(ResolveTableNames(client, i, end, tail_processor)); |
970 | 0 | if (tables.size() != 1) { |
971 | 0 | return STATUS_FORMAT(InvalidArgument, "Single table expected, $0 found", tables.size()); |
972 | 0 | } |
973 | 0 | return std::move(tables.front()); |
974 | 0 | } |
975 | | |
976 | 0 | Status CheckArgumentsCount(size_t count, size_t min, size_t max) { |
977 | 0 | if (count < min) { |
978 | 0 | return STATUS_FORMAT( |
979 | 0 | InvalidArgument, "Too few arguments $0, should be in range [$1, $2]", count, min, max); |
980 | 0 | } |
981 | | |
982 | 0 | if (count > max) { |
983 | 0 | return STATUS_FORMAT( |
984 | 0 | InvalidArgument, "Too many arguments $0, should be in range [$1, $2]", count, min, max); |
985 | 0 | } |
986 | | |
987 | 0 | return Status::OK(); |
988 | 0 | } |
989 | | |
990 | | } // namespace tools |
991 | | } // namespace yb |
992 | | |
993 | 1 | int main(int argc, char** argv) { |
994 | 1 | yb::Status s = yb::tools::enterprise::ClusterAdminCli().Run(argc, argv); |
995 | 1 | if (s.ok()) { |
996 | 1 | return 0; |
997 | 1 | } |
998 | | |
999 | 0 | if (s.IsInvalidArgument()) { |
1000 | 0 | google::ShowUsageWithFlagsRestrict(argv[0], __FILE__); |
1001 | 0 | } |
1002 | |
|
1003 | 0 | return 1; |
1004 | 0 | } |