]>
Commit | Line | Data |
---|---|---|
31f18b77 FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2017 Red Hat | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <iostream> | |
11fdf7f2 | 16 | #include <regex> // For regex, regex_search |
31f18b77 FG |
17 | |
18 | #include "common/admin_socket_client.h" // For AdminSocketClient | |
19 | #include "common/ceph_json.h" // For JSONParser, JSONObjIter | |
20 | #include "include/buffer.h" // For bufferlist | |
21 | ||
22 | #include "admin_socket_output.h" | |
23 | ||
24 | void AdminSocketOutput::add_target(const std::string& target) { | |
25 | if (target == "all") { | |
26 | add_target("osd"); | |
27 | add_target("mon"); | |
28 | add_target("mgr"); | |
29 | add_target("mds"); | |
30 | add_target("client"); | |
31 | return; | |
32 | } | |
33 | targets.insert(target); | |
34 | } | |
35 | ||
36 | void AdminSocketOutput::add_command(const std::string& target, | |
37 | const std::string& command) { | |
38 | auto seek = custom_commands.find(target); | |
39 | if (seek != custom_commands.end()) { | |
40 | seek->second.push_back(command); | |
41 | } else { | |
42 | std::vector<std::string> vec; | |
43 | vec.push_back(command); | |
44 | custom_commands.insert(std::make_pair(target, vec)); | |
45 | } | |
46 | ||
47 | } | |
48 | ||
49 | void AdminSocketOutput::add_test(const std::string &target, | |
50 | const std::string &command, | |
51 | bool (*test)(std::string &)) { | |
52 | auto seek = tests.find(target); | |
53 | if (seek != tests.end()) { | |
54 | seek->second.push_back(std::make_pair(command, test)); | |
55 | } else { | |
56 | std::vector<std::pair<std::string, bool (*)(std::string &)>> vec; | |
57 | vec.push_back(std::make_pair(command, test)); | |
58 | tests.insert(std::make_pair(target, vec)); | |
59 | } | |
60 | } | |
61 | ||
62 | void AdminSocketOutput::postpone(const std::string &target, | |
63 | const std::string& command) { | |
64 | auto seek = postponed_commands.find(target); | |
65 | if (seek != postponed_commands.end()) { | |
66 | seek->second.push_back(command); | |
67 | } else { | |
68 | std::vector<string> vec; | |
69 | vec.push_back(command); | |
70 | postponed_commands.insert(std::make_pair(target, vec)); | |
71 | } | |
72 | } | |
73 | ||
74 | bool AdminSocketOutput::init_sockets() { | |
75 | std::cout << "Initialising sockets" << std::endl; | |
9f95a23c TL |
76 | std::string socket_regex = R"(\..*\.asok)"; |
77 | for (const auto &x : fs::recursive_directory_iterator(socketdir)) { | |
31f18b77 | 78 | std::cout << x.path() << std::endl; |
11fdf7f2 | 79 | if (x.path().extension() == ".asok") { |
9f95a23c TL |
80 | for (auto target = targets.cbegin(); target != targets.cend();) { |
81 | std::regex reg(prefix + *target + socket_regex); | |
82 | if (std::regex_search(x.path().filename().string(), reg)) { | |
83 | std::cout << "Found " << *target << " socket " << x.path() | |
31f18b77 | 84 | << std::endl; |
9f95a23c TL |
85 | sockets.insert(std::make_pair(*target, x.path().string())); |
86 | target = targets.erase(target); | |
87 | } | |
88 | else { | |
89 | ++target; | |
31f18b77 FG |
90 | } |
91 | } | |
92 | if (targets.empty()) { | |
93 | std::cout << "Found all required sockets" << std::endl; | |
94 | break; | |
95 | } | |
96 | } | |
97 | } | |
98 | ||
99 | return !sockets.empty() && targets.empty(); | |
100 | } | |
101 | ||
102 | std::pair<std::string, std::string> | |
103 | AdminSocketOutput::run_command(AdminSocketClient &client, | |
11fdf7f2 | 104 | const std::string &raw_command, |
31f18b77 FG |
105 | bool send_untouched) { |
106 | std::cout << "Sending command \"" << raw_command << "\"" << std::endl; | |
107 | std::string command; | |
108 | std::string output; | |
109 | if (send_untouched) { | |
110 | command = raw_command; | |
111 | } else { | |
112 | command = "{\"prefix\":\"" + raw_command + "\"}"; | |
113 | } | |
11fdf7f2 TL |
114 | std::string err = client.do_request(command, &output); |
115 | if (!err.empty()) { | |
116 | std::cerr << __func__ << " AdminSocketClient::do_request errored with: " | |
117 | << err << std::endl; | |
118 | ceph_abort(); | |
119 | } | |
31f18b77 FG |
120 | return std::make_pair(command, output); |
121 | } | |
122 | ||
123 | bool AdminSocketOutput::gather_socket_output() { | |
124 | ||
125 | std::cout << "Gathering socket output" << std::endl; | |
126 | for (const auto& socket : sockets) { | |
127 | std::string response; | |
128 | AdminSocketClient client(socket.second); | |
129 | std::cout << std::endl | |
130 | << "Sending request to " << socket << std::endl | |
131 | << std::endl; | |
11fdf7f2 TL |
132 | std::string err = client.do_request("{\"prefix\":\"help\"}", &response); |
133 | if (!err.empty()) { | |
134 | std::cerr << __func__ << " AdminSocketClient::do_request errored with: " | |
135 | << err << std::endl; | |
136 | return false; | |
137 | } | |
31f18b77 FG |
138 | std::cout << response << '\n'; |
139 | ||
140 | JSONParser parser; | |
141 | bool ret = parser.parse(response.c_str(), response.size()); | |
142 | if (!ret) { | |
143 | cerr << "parse error" << std::endl; | |
144 | return false; | |
145 | } | |
146 | ||
147 | socket_results sresults; | |
148 | JSONObjIter iter = parser.find_first(); | |
149 | const auto postponed_iter = postponed_commands.find(socket.first); | |
150 | std::vector<std::string> postponed; | |
151 | if (postponed_iter != postponed_commands.end()) { | |
152 | postponed = postponed_iter->second; | |
153 | } | |
154 | std::cout << "Sending commands to " << socket.first << " socket" | |
155 | << std::endl; | |
156 | for (; !iter.end(); ++iter) { | |
157 | if (std::find(postponed.begin(), postponed.end(), (*iter)->get_name()) | |
158 | != std::end(postponed)) { | |
159 | std::cout << "Command \"" << (*iter)->get_name() << "\" postponed" | |
160 | << std::endl; | |
161 | continue; | |
162 | } | |
163 | sresults.insert(run_command(client, (*iter)->get_name())); | |
164 | } | |
165 | ||
166 | if (sresults.empty()) { | |
167 | return false; | |
168 | } | |
169 | ||
170 | // Custom commands | |
171 | const auto seek = custom_commands.find(socket.first); | |
172 | if (seek != custom_commands.end()) { | |
173 | std::cout << std::endl << "Sending custom commands:" << std::endl; | |
174 | for (const auto& raw_command : seek->second) { | |
175 | sresults.insert(run_command(client, raw_command, true)); | |
176 | } | |
177 | } | |
178 | ||
179 | // Postponed commands | |
180 | if (!postponed.empty()) | |
181 | std::cout << std::endl << "Sending postponed commands" << std::endl; | |
182 | for (const auto& command : postponed) { | |
183 | sresults.insert(run_command(client, command)); | |
184 | } | |
185 | ||
186 | results.insert( | |
187 | std::pair<std::string, socket_results>(socket.first, sresults)); | |
188 | ||
189 | } | |
190 | ||
191 | return true; | |
192 | } | |
193 | ||
11fdf7f2 TL |
194 | std::string AdminSocketOutput::get_result(const std::string &target, |
195 | const std::string &command) const { | |
31f18b77 FG |
196 | const auto& target_results = results.find(target); |
197 | if (target_results == results.end()) | |
198 | return std::string(""); | |
199 | else { | |
200 | const auto& result = target_results->second.find(command); | |
201 | if (result == target_results->second.end()) | |
202 | return std::string(""); | |
203 | else | |
204 | return result->second; | |
205 | } | |
206 | } | |
207 | ||
208 | bool AdminSocketOutput::run_tests() const { | |
209 | for (const auto& socket : sockets) { | |
210 | const auto& seek = tests.find(socket.first); | |
211 | if (seek != tests.end()) { | |
212 | std::cout << std::endl; | |
213 | std::cout << "Running tests for " << socket.first << " socket" << std::endl; | |
214 | for (const auto& test : seek->second) { | |
215 | auto result = get_result(socket.first, test.first); | |
216 | if(result.empty()) { | |
217 | std::cout << "Failed to find result for command: " << test.first << std::endl; | |
218 | return false; | |
219 | } else { | |
220 | std::cout << "Running test for command: " << test.first << std::endl; | |
221 | const auto& test_func = test.second; | |
222 | bool res = test_func(result); | |
223 | if (res == false) | |
224 | return false; | |
225 | else | |
226 | std::cout << "Test passed" << std::endl; | |
227 | } | |
228 | } | |
229 | } | |
230 | } | |
231 | ||
232 | return true; | |
233 | } | |
234 | ||
235 | void AdminSocketOutput::exec() { | |
236 | ceph_assert(init_directories()); | |
237 | ceph_assert(init_sockets()); | |
238 | ceph_assert(gather_socket_output()); | |
239 | ceph_assert(run_tests()); | |
240 | } |