// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2017 Red Hat * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include // For extension #include // For regex, regex_search #include "common/admin_socket_client.h" // For AdminSocketClient #include "common/ceph_json.h" // For JSONParser, JSONObjIter #include "include/buffer.h" // For bufferlist #include "admin_socket_output.h" void AdminSocketOutput::add_target(const std::string& target) { if (target == "all") { add_target("osd"); add_target("mon"); add_target("mgr"); add_target("mds"); add_target("client"); return; } targets.insert(target); } void AdminSocketOutput::add_command(const std::string& target, const std::string& command) { auto seek = custom_commands.find(target); if (seek != custom_commands.end()) { seek->second.push_back(command); } else { std::vector vec; vec.push_back(command); custom_commands.insert(std::make_pair(target, vec)); } } void AdminSocketOutput::add_test(const std::string &target, const std::string &command, bool (*test)(std::string &)) { auto seek = tests.find(target); if (seek != tests.end()) { seek->second.push_back(std::make_pair(command, test)); } else { std::vector> vec; vec.push_back(std::make_pair(command, test)); tests.insert(std::make_pair(target, vec)); } } void AdminSocketOutput::postpone(const std::string &target, const std::string& command) { auto seek = postponed_commands.find(target); if (seek != postponed_commands.end()) { seek->second.push_back(command); } else { std::vector vec; vec.push_back(command); postponed_commands.insert(std::make_pair(target, vec)); } } bool AdminSocketOutput::init_sockets() { std::cout << "Initialising sockets" << std::endl; for (const auto &x : bfs::directory_iterator(socketdir)) { std::cout << x.path() << std::endl; if (bfs::extension(x.path()) == ".asok") { for (auto &target : targets) { if (boost::regex_search(x.path().filename().string(), boost::regex(prefix + target + R"(\..*\.asok)"))) { std::cout << "Found " << target << " socket " << x.path() << std::endl; sockets.insert(std::make_pair(target, x.path().string())); targets.erase(target); } } if (targets.empty()) { std::cout << "Found all required sockets" << std::endl; break; } } } return !sockets.empty() && targets.empty(); } std::pair AdminSocketOutput::run_command(AdminSocketClient &client, const std::string raw_command, bool send_untouched) { std::cout << "Sending command \"" << raw_command << "\"" << std::endl; std::string command; std::string output; if (send_untouched) { command = raw_command; } else { command = "{\"prefix\":\"" + raw_command + "\"}"; } client.do_request(command, &output); return std::make_pair(command, output); } bool AdminSocketOutput::gather_socket_output() { std::cout << "Gathering socket output" << std::endl; for (const auto& socket : sockets) { std::string response; AdminSocketClient client(socket.second); std::cout << std::endl << "Sending request to " << socket << std::endl << std::endl; client.do_request("{\"prefix\":\"help\"}", &response); std::cout << response << '\n'; JSONParser parser; bool ret = parser.parse(response.c_str(), response.size()); if (!ret) { cerr << "parse error" << std::endl; return false; } socket_results sresults; JSONObjIter iter = parser.find_first(); const auto postponed_iter = postponed_commands.find(socket.first); std::vector postponed; if (postponed_iter != postponed_commands.end()) { postponed = postponed_iter->second; } std::cout << "Sending commands to " << socket.first << " socket" << std::endl; for (; !iter.end(); ++iter) { if (std::find(postponed.begin(), postponed.end(), (*iter)->get_name()) != std::end(postponed)) { std::cout << "Command \"" << (*iter)->get_name() << "\" postponed" << std::endl; continue; } sresults.insert(run_command(client, (*iter)->get_name())); } if (sresults.empty()) { return false; } // Custom commands const auto seek = custom_commands.find(socket.first); if (seek != custom_commands.end()) { std::cout << std::endl << "Sending custom commands:" << std::endl; for (const auto& raw_command : seek->second) { sresults.insert(run_command(client, raw_command, true)); } } // Postponed commands if (!postponed.empty()) std::cout << std::endl << "Sending postponed commands" << std::endl; for (const auto& command : postponed) { sresults.insert(run_command(client, command)); } results.insert( std::pair(socket.first, sresults)); } return true; } std::string AdminSocketOutput::get_result(const std::string target, const std::string command) const { const auto& target_results = results.find(target); if (target_results == results.end()) return std::string(""); else { const auto& result = target_results->second.find(command); if (result == target_results->second.end()) return std::string(""); else return result->second; } } bool AdminSocketOutput::run_tests() const { for (const auto& socket : sockets) { const auto& seek = tests.find(socket.first); if (seek != tests.end()) { std::cout << std::endl; std::cout << "Running tests for " << socket.first << " socket" << std::endl; for (const auto& test : seek->second) { auto result = get_result(socket.first, test.first); if(result.empty()) { std::cout << "Failed to find result for command: " << test.first << std::endl; return false; } else { std::cout << "Running test for command: " << test.first << std::endl; const auto& test_func = test.second; bool res = test_func(result); if (res == false) return false; else std::cout << "Test passed" << std::endl; } } } } return true; } void AdminSocketOutput::exec() { ceph_assert(init_directories()); ceph_assert(init_sockets()); ceph_assert(gather_socket_output()); ceph_assert(run_tests()); }