]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/admin_socket.h
c5d2b48e563bf0414f19e2e4362f7ad177a75886
[ceph.git] / ceph / src / common / admin_socket.h
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) 2011 New Dream Network
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 #ifndef CEPH_COMMON_ADMIN_SOCKET_H
16 #define CEPH_COMMON_ADMIN_SOCKET_H
17
18 #if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
19 #include "crimson/admin/admin_socket.h"
20 #else
21
22 #include <condition_variable>
23 #include <mutex>
24 #include <string>
25 #include <string_view>
26 #include <thread>
27
28 #include "include/buffer.h"
29 #include "include/common_fwd.h"
30 #include "common/ref.h"
31 #include "common/cmdparse.h"
32
33 class MCommand;
34 class MMonCommand;
35
36 inline constexpr auto CEPH_ADMIN_SOCK_VERSION = std::string_view("2");
37
38 class AdminSocketHook {
39 public:
40 /**
41 * @brief
42 * Handler for admin socket commands, synchronous version
43 *
44 * Executes action associated with admin command and returns byte-stream output @c out.
45 * There is no restriction on output. Each handler defines output semantics.
46 * Typically output is textual representation of some ceph's internals.
47 * Handler should use provided formatter @c f if structuralized output is being produced.
48 *
49 * @param command[in] String matching constant part of cmddesc in @ref AdminSocket::register_command
50 * @param cmdmap[in] Parameters extracted from argument part of cmddesc in @ref AdminSocket::register_command
51 * @param f[in] Formatter created according to requestor preference, used by `ceph --format`
52 * @param errss[out] Error stream, should contain details in case of execution failure
53 * @param out[out] Produced output
54 *
55 * @retval 0 Success, errss is ignored and does not contribute to output
56 * @retval <0 Error code, errss is prepended to @c out
57 *
58 * @note If @c out is empty, then admin socket will try to flush @c f to out.
59 */
60 virtual int call(
61 std::string_view command,
62 const cmdmap_t& cmdmap,
63 ceph::Formatter *f,
64 std::ostream& errss,
65 ceph::buffer::list& out) = 0;
66
67 /**
68 * @brief
69 * Handler for admin socket commands, asynchronous version
70 *
71 * Executes action associated with admin command and prepares byte-stream response.
72 * When processing is done @c on_finish must be called.
73 * There is no restriction on output. Each handler defines own output semantics.
74 * Typically output is textual representation of some ceph's internals.
75 * Input @c inbl can be passed, see ceph --in-file.
76 * Handler should use provided formatter @c f if structuralized output is being produced.
77 * on_finish handler has following parameters:
78 * - result code of handler (same as @ref AdminSocketHook::call)
79 * - error message, text
80 * - output
81 *
82 * @param[in] command String matching constant part of cmddesc in @ref AdminSocket::register_command
83 * @param[in] cmdmap Parameters extracted from argument part of cmddesc in @ref AdminSocket::register_command
84 * @param[in] f Formatter created according to requestor preference, used by `ceph --format`
85 * @param[in] inbl Input content for handler
86 * @param[in] on_finish Function to call when processing is done
87 *
88 * @note If @c out is empty, then admin socket will try to flush @c f to out.
89 */
90 virtual void call_async(
91 std::string_view command,
92 const cmdmap_t& cmdmap,
93 ceph::Formatter *f,
94 const ceph::buffer::list& inbl,
95 std::function<void(int,const std::string&,ceph::buffer::list&)> on_finish) {
96 // by default, call the synchronous handler and then finish
97 ceph::buffer::list out;
98 std::ostringstream errss;
99 int r = call(command, cmdmap, f, errss, out);
100 on_finish(r, errss.str(), out);
101 }
102 virtual ~AdminSocketHook() {}
103 };
104
105 class AdminSocket
106 {
107 public:
108 AdminSocket(CephContext *cct);
109 ~AdminSocket();
110
111 AdminSocket(const AdminSocket&) = delete;
112 AdminSocket& operator =(const AdminSocket&) = delete;
113 AdminSocket(AdminSocket&&) = delete;
114 AdminSocket& operator =(AdminSocket&&) = delete;
115
116 /**
117 * register an admin socket command
118 *
119 * The command is registered under a command string. Incoming
120 * commands are split by space and matched against the longest
121 * registered command. For example, if 'foo' and 'foo bar' are
122 * registered, and an incoming command is 'foo bar baz', it is
123 * matched with 'foo bar', while 'foo fud' will match 'foo'.
124 *
125 * The entire incoming command string is passed to the registered
126 * hook.
127 *
128 * @param command command string
129 * @param cmddesc command syntax descriptor
130 * @param hook implementation
131 * @param help help text. if empty, command will not be included in 'help' output.
132 *
133 * @return 0 for success, -EEXIST if command already registered.
134 */
135 int register_command(std::string_view cmddesc,
136 AdminSocketHook *hook,
137 std::string_view help);
138
139 /*
140 * unregister all commands belong to hook.
141 */
142 void unregister_commands(const AdminSocketHook *hook);
143
144 bool init(const std::string& path);
145
146 void chown(uid_t uid, gid_t gid);
147 void chmod(mode_t mode);
148
149 /// execute (async)
150 void execute_command(
151 const std::vector<std::string>& cmd,
152 const ceph::buffer::list& inbl,
153 std::function<void(int,const std::string&,ceph::buffer::list&)> on_fin);
154
155 /// execute (blocking)
156 int execute_command(
157 const std::vector<std::string>& cmd,
158 const ceph::buffer::list& inbl,
159 std::ostream& errss,
160 ceph::buffer::list *outbl);
161
162 void queue_tell_command(ceph::cref_t<MCommand> m);
163 void queue_tell_command(ceph::cref_t<MMonCommand> m); // for compat
164
165 private:
166
167 void shutdown();
168 void wakeup();
169
170 std::string create_wakeup_pipe(int *pipe_rd, int *pipe_wr);
171 std::string destroy_wakeup_pipe();
172 std::string bind_and_listen(const std::string &sock_path, int *fd);
173
174 std::thread th;
175 void entry() noexcept;
176 void do_accept();
177 void do_tell_queue();
178
179 CephContext *m_cct;
180 std::string m_path;
181 int m_sock_fd = -1;
182 int m_wakeup_rd_fd = -1;
183 int m_wakeup_wr_fd = -1;
184 bool m_shutdown = false;
185
186 bool in_hook = false;
187 std::condition_variable in_hook_cond;
188 std::mutex lock; // protects `hooks`
189 std::unique_ptr<AdminSocketHook> version_hook;
190 std::unique_ptr<AdminSocketHook> help_hook;
191 std::unique_ptr<AdminSocketHook> getdescs_hook;
192
193 std::mutex tell_lock;
194 std::list<ceph::cref_t<MCommand>> tell_queue;
195 std::list<ceph::cref_t<MMonCommand>> tell_legacy_queue;
196
197 struct hook_info {
198 AdminSocketHook* hook;
199 std::string desc;
200 std::string help;
201
202 hook_info(AdminSocketHook* hook, std::string_view desc,
203 std::string_view help)
204 : hook(hook), desc(desc), help(help) {}
205 };
206
207 /// find the first hook which matches the given prefix and cmdmap
208 std::pair<int, AdminSocketHook*> find_matched_hook(
209 std::string& prefix,
210 const cmdmap_t& cmdmap);
211
212 std::multimap<std::string, hook_info, std::less<>> hooks;
213
214 friend class AdminSocketTest;
215 friend class HelpHook;
216 friend class GetdescsHook;
217 };
218
219 #endif
220 #endif