Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / admin_socket_output.cc
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>
16 #include <boost/filesystem/convenience.hpp> // For extension
17 #include <boost/regex.hpp>                 // For regex, regex_search
18
19 #include "common/admin_socket_client.h"     // For AdminSocketClient
20 #include "common/ceph_json.h"               // For JSONParser, JSONObjIter
21 #include "include/buffer.h"                 // For bufferlist
22
23 #include "admin_socket_output.h"
24
25 void AdminSocketOutput::add_target(const std::string& target) {
26   if (target == "all") {
27     add_target("osd");
28     add_target("mon");
29     add_target("mgr");
30     add_target("mds");
31     add_target("client");
32     return;
33   }
34   targets.insert(target);
35 }
36
37 void AdminSocketOutput::add_command(const std::string& target,
38                                     const std::string& command) {
39   auto seek = custom_commands.find(target);
40   if (seek != custom_commands.end()) {
41     seek->second.push_back(command);
42   } else {
43     std::vector<std::string> vec;
44     vec.push_back(command);
45     custom_commands.insert(std::make_pair(target, vec));
46   }
47
48 }
49
50 void AdminSocketOutput::add_test(const std::string &target,
51                                  const std::string &command,
52                                  bool (*test)(std::string &)) {
53   auto seek = tests.find(target);
54   if (seek != tests.end()) {
55     seek->second.push_back(std::make_pair(command, test));
56   } else {
57     std::vector<std::pair<std::string, bool (*)(std::string &)>> vec;
58     vec.push_back(std::make_pair(command, test));
59     tests.insert(std::make_pair(target, vec));
60   }
61 }
62
63 void AdminSocketOutput::postpone(const std::string &target,
64                                  const std::string& command) {
65   auto seek = postponed_commands.find(target);
66   if (seek != postponed_commands.end()) {
67     seek->second.push_back(command);
68   } else {
69     std::vector<string> vec;
70     vec.push_back(command);
71     postponed_commands.insert(std::make_pair(target, vec));
72   }
73 }
74
75 bool AdminSocketOutput::init_sockets() {
76   std::cout << "Initialising sockets" << std::endl;
77   for (const auto &x : bfs::directory_iterator(socketdir)) {
78     std::cout << x.path() << std::endl;
79     if (bfs::extension(x.path()) == ".asok") {
80       for (auto &target : targets) {
81         if (boost::regex_search(x.path().filename().string(),
82             boost::regex(prefix + target + R"(\..*\.asok)"))) {
83           std::cout << "Found " << target << " socket " << x.path()
84                     << std::endl;
85           sockets.insert(std::make_pair(target, x.path().string()));
86           targets.erase(target);
87         }
88       }
89       if (targets.empty()) {
90         std::cout << "Found all required sockets" << std::endl;
91         break;
92       }
93     }
94   }
95
96   return !sockets.empty() && targets.empty();
97 }
98
99 std::pair<std::string, std::string>
100 AdminSocketOutput::run_command(AdminSocketClient &client,
101                                const std::string raw_command,
102                                bool send_untouched) {
103   std::cout << "Sending command \"" << raw_command << "\"" << std::endl;
104   std::string command;
105   std::string output;
106   if (send_untouched) {
107     command = raw_command;
108   } else {
109     command = "{\"prefix\":\"" + raw_command + "\"}";
110   }
111   client.do_request(command, &output);
112   return std::make_pair(command, output);
113 }
114
115 bool AdminSocketOutput::gather_socket_output() {
116
117   std::cout << "Gathering socket output" << std::endl;
118   for (const auto& socket : sockets) {
119     std::string response;
120     AdminSocketClient client(socket.second);
121     std::cout << std::endl
122               << "Sending request to " << socket << std::endl
123               << std::endl;
124     client.do_request("{\"prefix\":\"help\"}", &response);
125     std::cout << response << '\n';
126
127     JSONParser parser;
128     bool ret = parser.parse(response.c_str(), response.size());
129     if (!ret) {
130       cerr << "parse error" << std::endl;
131       return false;
132     }
133
134     socket_results sresults;
135     JSONObjIter iter = parser.find_first();
136     const auto postponed_iter = postponed_commands.find(socket.first);
137     std::vector<std::string> postponed;
138     if (postponed_iter != postponed_commands.end()) {
139       postponed = postponed_iter->second;
140     }
141     std::cout << "Sending commands to " << socket.first << " socket"
142               << std::endl;
143     for (; !iter.end(); ++iter) {
144       if (std::find(postponed.begin(), postponed.end(), (*iter)->get_name())
145           != std::end(postponed)) {
146         std::cout << "Command \"" << (*iter)->get_name() << "\" postponed"
147                   << std::endl;
148         continue;
149       }
150       sresults.insert(run_command(client, (*iter)->get_name()));
151     }
152
153     if (sresults.empty()) {
154       return false;
155     }
156
157     // Custom commands
158     const auto seek = custom_commands.find(socket.first);
159     if (seek != custom_commands.end()) {
160       std::cout << std::endl << "Sending custom commands:" << std::endl;
161       for (const auto& raw_command : seek->second) {
162         sresults.insert(run_command(client, raw_command, true));
163       }
164     }
165
166     // Postponed commands
167     if (!postponed.empty())
168       std::cout << std::endl << "Sending postponed commands" << std::endl;
169     for (const auto& command : postponed) {
170       sresults.insert(run_command(client, command));
171     }
172
173     results.insert(
174         std::pair<std::string, socket_results>(socket.first, sresults));
175
176   }
177
178   return true;
179 }
180
181 std::string AdminSocketOutput::get_result(const std::string target,
182                                           const std::string command) const {
183   const auto& target_results = results.find(target);
184   if (target_results == results.end())
185     return std::string("");
186   else {
187     const auto& result = target_results->second.find(command);
188     if (result == target_results->second.end())
189       return std::string("");
190     else
191       return result->second;
192   }
193 }
194
195 bool AdminSocketOutput::run_tests() const {
196   for (const auto& socket : sockets) {
197     const auto& seek = tests.find(socket.first);
198     if (seek != tests.end()) {
199       std::cout << std::endl;
200       std::cout << "Running tests for " << socket.first << " socket" << std::endl;
201       for (const auto& test : seek->second) {
202           auto result = get_result(socket.first, test.first);
203           if(result.empty()) {
204             std::cout << "Failed to find result for command: " << test.first << std::endl;
205             return false;
206           } else {
207             std::cout << "Running test for command: " << test.first << std::endl;
208             const auto& test_func = test.second;
209             bool res = test_func(result);
210             if (res == false)
211               return false;
212             else
213               std::cout << "Test passed" << std::endl;
214           }
215         }
216       }
217     }
218
219   return true;
220 }
221
222 void AdminSocketOutput::exec() {
223   ceph_assert(init_directories());
224   ceph_assert(init_sockets());
225   ceph_assert(gather_socket_output());
226   ceph_assert(run_tests());
227 }