]> git.proxmox.com Git - ceph.git/blame - ceph/src/crimson/admin/admin_socket.h
import 15.2.0 Octopus source
[ceph.git] / ceph / src / crimson / admin / admin_socket.h
CommitLineData
9f95a23c
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3#pragma once
4
5/**
6 A Crimson-wise version of the src/common/admin_socket.h
7
8 Note: assumed to be running on a single core.
9*/
10#include <map>
11#include <string>
12#include <string_view>
13
14#include <seastar/core/future.hh>
15#include <seastar/core/gate.hh>
16#include <seastar/core/iostream.hh>
17#include <seastar/core/shared_mutex.hh>
18#include <seastar/core/shared_ptr.hh>
19#include <seastar/net/api.hh>
20
21#include "common/cmdparse.h"
22
23using namespace std::literals;
24
25namespace crimson::admin {
26
27class AdminSocket;
28
29/**
30 * A specific hook must implement exactly one of the two interfaces:
31 * (1) call(command, cmdmap, format, out)
32 * or
33 * (2) exec_command(formatter, command, cmdmap, format, out)
34 *
35 * The default implementation of (1) above calls exec_command() after handling
36 * most of the boiler-plate choirs:
37 * - setting up the formatter, with an appropiate 'section' already opened;
38 * - handling possible failures (exceptions or future_exceptions) returned
39 * by (2)
40 * - flushing the output to the outgoing bufferlist.
41 */
42class AdminSocketHook {
43 public:
44 AdminSocketHook(std::string_view prefix,
45 std::string_view desc,
46 std::string_view help) :
47 prefix{prefix}, desc{desc}, help{help}
48 {}
49 /**
50 * \retval 'false' for hook execution errors
51 */
52 virtual seastar::future<ceph::bufferlist>
53 call(std::string_view command,
54 std::string_view format,
55 const cmdmap_t& cmdmap) const = 0;
56 virtual ~AdminSocketHook() {}
57 const std::string_view prefix;
58 const std::string_view desc;
59 const std::string_view help;
60};
61
62class AdminSocket : public seastar::enable_lw_shared_from_this<AdminSocket> {
63 public:
64 AdminSocket() = default;
65 ~AdminSocket() = default;
66
67 AdminSocket(const AdminSocket&) = delete;
68 AdminSocket& operator=(const AdminSocket&) = delete;
69 AdminSocket(AdminSocket&&) = delete;
70 AdminSocket& operator=(AdminSocket&&) = delete;
71
72 using hook_server_tag = const void*;
73
74 /**
75 * create the async Seastar thread that handles asok commands arriving
76 * over the socket.
77 */
78 seastar::future<> start(const std::string& path);
79
80 seastar::future<> stop();
81
82 /**
83 * register an admin socket hooks server
84 *
85 * The server registers a set of APIs under a common hook_server_tag.
86 *
87 * Commands (APIs) are registered under a command string. Incoming
88 * commands are split by spaces and matched against the longest
89 * registered command. For example, if 'foo' and 'foo bar' are
90 * registered, and an incoming command is 'foo bar baz', it is
91 * matched with 'foo bar', while 'foo fud' will match 'foo'.
92 *
93 * The entire incoming command string is passed to the registered
94 * hook.
95 *
96 * \param server_tag a tag identifying the server registering the hook
97 * \param apis_served a vector of the commands served by this server. Each
98 * command registration includes its identifying command string, the
99 * expected call syntax, and some help text.
100 *
101 * A note regarding the help text: if empty, command will not be
102 * included in 'help' output.
103 *
104 * \retval a shared ptr to the asok server itself, or nullopt if
105 * a block with same tag is already registered.
106 */
107 seastar::future<> register_command(std::unique_ptr<AdminSocketHook>&& hook);
108
109 /**
110 * Registering the APIs that are served directly by the admin_socket server.
111 */
112 seastar::future<> register_admin_commands();
113
114 private:
115 /**
116 * the result of analyzing an incoming command, and locating it in
117 * the registered APIs collection.
118 */
119 struct parsed_command_t {
120 cmdmap_t parameters;
121 std::string format;
122 const AdminSocketHook& hook;
123 };
124 // and the shorthand:
125 using maybe_parsed_t = std::optional<AdminSocket::parsed_command_t>;
126
127 seastar::future<> handle_client(seastar::input_stream<char>& inp,
128 seastar::output_stream<char>& out);
129
130 seastar::future<> execute_line(std::string cmdline,
131 seastar::output_stream<char>& out);
132
133 seastar::future<> finalize_response(seastar::output_stream<char>& out,
134 ceph::bufferlist&& msgs);
135
136 bool validate_command(const parsed_command_t& parsed,
137 const std::string& command_text,
138 ceph::bufferlist& out) const;
139
140 std::optional<seastar::server_socket> server_sock;
141 std::optional<seastar::connected_socket> connected_sock;
142
143 /**
144 * stopping incoming ASOK requests at shutdown
145 */
146 seastar::gate stop_gate;
147
148 /**
149 * parse the incoming command line into the sequence of words that identifies
150 * the API, and into its arguments. Locate the command string in the
151 * registered blocks.
152 */
153 maybe_parsed_t parse_cmd(std::string command_text, bufferlist& out);
154
155 /**
156 * The servers table is protected by a rw-lock, to be acquired exclusively
157 * only when registering or removing a server.
158 * The lock is locked-shared when executing any hook.
159 */
160 mutable seastar::shared_mutex servers_tbl_rwlock;
161 using hooks_t = std::map<std::string_view, std::unique_ptr<AdminSocketHook>>;
162 hooks_t hooks;
163
164 public:
165 /**
166 * iterator support
167 */
168 hooks_t::const_iterator begin() const {
169 return hooks.cbegin();
170 }
171 hooks_t::const_iterator end() const {
172 return hooks.cend();
173 }
174
175 friend class AdminSocketTest;
176 friend class HelpHook;
177 friend class GetdescsHook;
178};
179
180} // namespace crimson::admin