]> git.proxmox.com Git - ceph.git/blob - ceph/src/mon/ConfigKeyService.cc
update sources to v12.1.0
[ceph.git] / ceph / src / mon / ConfigKeyService.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) 2013 Inktank, Inc
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 <sstream>
16 #include <stdlib.h>
17 #include <limits.h>
18
19 #include "mon/Monitor.h"
20 #include "mon/ConfigKeyService.h"
21 #include "mon/MonitorDBStore.h"
22 #include "mon/OSDMonitor.h"
23 #include "common/errno.h"
24 #include "include/stringify.h"
25
26 #define dout_subsys ceph_subsys_mon
27 #undef dout_prefix
28 #define dout_prefix _prefix(_dout, mon, this)
29 static ostream& _prefix(std::ostream *_dout, const Monitor *mon,
30 const ConfigKeyService *service) {
31 return *_dout << "mon." << mon->name << "@" << mon->rank
32 << "(" << mon->get_state_name() << ")." << service->get_name()
33 << "(" << service->get_epoch() << ") ";
34 }
35
36 const string ConfigKeyService::STORE_PREFIX = "mon_config_key";
37
38 int ConfigKeyService::store_get(const string &key, bufferlist &bl)
39 {
40 return mon->store->get(STORE_PREFIX, key, bl);
41 }
42
43 void ConfigKeyService::get_store_prefixes(set<string>& s)
44 {
45 s.insert(STORE_PREFIX);
46 }
47
48 void ConfigKeyService::store_put(const string &key, bufferlist &bl, Context *cb)
49 {
50 MonitorDBStore::TransactionRef t = paxos->get_pending_transaction();
51 t->put(STORE_PREFIX, key, bl);
52 if (cb)
53 paxos->queue_pending_finisher(cb);
54 paxos->trigger_propose();
55 }
56
57 void ConfigKeyService::store_delete(const string &key, Context *cb)
58 {
59 MonitorDBStore::TransactionRef t = paxos->get_pending_transaction();
60 store_delete(t, key);
61 if (cb)
62 paxos->queue_pending_finisher(cb);
63 paxos->trigger_propose();
64 }
65
66 void ConfigKeyService::store_delete(
67 MonitorDBStore::TransactionRef t,
68 const string &key)
69 {
70 t->erase(STORE_PREFIX, key);
71 }
72
73 bool ConfigKeyService::store_exists(const string &key)
74 {
75 return mon->store->exists(STORE_PREFIX, key);
76 }
77
78 void ConfigKeyService::store_list(stringstream &ss)
79 {
80 KeyValueDB::Iterator iter =
81 mon->store->get_iterator(STORE_PREFIX);
82
83 JSONFormatter f(true);
84 f.open_array_section("keys");
85
86 while (iter->valid()) {
87 string key(iter->key());
88 f.dump_string("key", key);
89 iter->next();
90 }
91 f.close_section();
92 f.flush(ss);
93 }
94
95 bool ConfigKeyService::store_has_prefix(const string &prefix)
96 {
97 KeyValueDB::Iterator iter =
98 mon->store->get_iterator(STORE_PREFIX);
99
100 while (iter->valid()) {
101 string key(iter->key());
102 size_t p = key.find(prefix);
103 if (p != string::npos && p == 0) {
104 return true;
105 }
106 iter->next();
107 }
108 return false;
109 }
110
111 void ConfigKeyService::store_dump(stringstream &ss)
112 {
113 KeyValueDB::Iterator iter =
114 mon->store->get_iterator(STORE_PREFIX);
115
116 JSONFormatter f(true);
117 f.open_object_section("config-key store");
118
119 while (iter->valid()) {
120 f.dump_string(iter->key().c_str(), iter->value().to_str());
121 iter->next();
122 }
123 f.close_section();
124 f.flush(ss);
125 }
126
127 void ConfigKeyService::store_delete_prefix(
128 MonitorDBStore::TransactionRef t,
129 const string &prefix)
130 {
131 KeyValueDB::Iterator iter =
132 mon->store->get_iterator(STORE_PREFIX);
133
134 while (iter->valid()) {
135 string key(iter->key());
136
137 size_t p = key.find(prefix);
138 if (p != string::npos && p == 0) {
139 store_delete(t, key);
140 }
141 iter->next();
142 }
143 }
144
145 bool ConfigKeyService::service_dispatch(MonOpRequestRef op)
146 {
147 Message *m = op->get_req();
148 assert(m != NULL);
149 dout(10) << __func__ << " " << *m << dendl;
150
151 if (!in_quorum()) {
152 dout(1) << __func__ << " not in quorum -- waiting" << dendl;
153 paxos->wait_for_readable(op, new Monitor::C_RetryMessage(mon, op));
154 return false;
155 }
156
157 assert(m->get_type() == MSG_MON_COMMAND);
158
159 MMonCommand *cmd = static_cast<MMonCommand*>(m);
160
161 assert(!cmd->cmd.empty());
162
163 int ret = 0;
164 stringstream ss;
165 bufferlist rdata;
166
167 string prefix;
168 map<string, cmd_vartype> cmdmap;
169
170 if (!cmdmap_from_json(cmd->cmd, &cmdmap, ss)) {
171 return false;
172 }
173
174 cmd_getval(g_ceph_context, cmdmap, "prefix", prefix);
175 string key;
176 cmd_getval(g_ceph_context, cmdmap, "key", key);
177
178 if (prefix == "config-key get") {
179 ret = store_get(key, rdata);
180 if (ret < 0) {
181 assert(!rdata.length());
182 ss << "error obtaining '" << key << "': " << cpp_strerror(ret);
183 goto out;
184 }
185 ss << "obtained '" << key << "'";
186
187 } else if (prefix == "config-key put") {
188 if (!mon->is_leader()) {
189 mon->forward_request_leader(op);
190 // we forward the message; so return now.
191 return true;
192 }
193
194 bufferlist data;
195 string val;
196 if (cmd_getval(g_ceph_context, cmdmap, "val", val)) {
197 // they specified a value in the command instead of a file
198 data.append(val);
199 } else if (cmd->get_data_len() > 0) {
200 // they specified '-i <file>'
201 data = cmd->get_data();
202 }
203 if (data.length() > (size_t) g_conf->mon_config_key_max_entry_size) {
204 ret = -EFBIG; // File too large
205 ss << "error: entry size limited to "
206 << g_conf->mon_config_key_max_entry_size << " bytes. "
207 << "Use 'mon config key max entry size' to manually adjust";
208 goto out;
209 }
210 // we'll reply to the message once the proposal has been handled
211 ss << "set " << key;
212 store_put(key, data,
213 new Monitor::C_Command(mon, op, 0, ss.str(), 0));
214 // return for now; we'll put the message once it's done.
215 return true;
216
217 } else if (prefix == "config-key del" ||
218 prefix == "config-key rm") {
219 if (!mon->is_leader()) {
220 mon->forward_request_leader(op);
221 return true;
222 }
223
224 if (!store_exists(key)) {
225 ret = 0;
226 ss << "no such key '" << key << "'";
227 goto out;
228 }
229 store_delete(key, new Monitor::C_Command(mon, op, 0, "key deleted", 0));
230 // return for now; we'll put the message once it's done
231 return true;
232
233 } else if (prefix == "config-key exists") {
234 bool exists = store_exists(key);
235 ss << "key '" << key << "'";
236 if (exists) {
237 ss << " exists";
238 ret = 0;
239 } else {
240 ss << " doesn't exist";
241 ret = -ENOENT;
242 }
243
244 } else if (prefix == "config-key list") {
245 stringstream tmp_ss;
246 store_list(tmp_ss);
247 rdata.append(tmp_ss);
248 ret = 0;
249
250 } else if (prefix == "config-key dump") {
251 stringstream tmp_ss;
252 store_dump(tmp_ss);
253 rdata.append(tmp_ss);
254 ret = 0;
255
256 }
257
258 out:
259 if (!cmd->get_source().is_mon()) {
260 string rs = ss.str();
261 mon->reply_command(op, ret, rs, rdata, 0);
262 }
263
264 return (ret == 0);
265 }
266
267 string _get_dmcrypt_prefix(const uuid_d& uuid, const string k)
268 {
269 return "dm-crypt/osd/" + stringify(uuid) + "/" + k;
270 }
271
272 int ConfigKeyService::validate_osd_destroy(
273 const int32_t id,
274 const uuid_d& uuid)
275 {
276 string dmcrypt_prefix = _get_dmcrypt_prefix(uuid, "");
277 string daemon_prefix =
278 "daemon-private/osd." + stringify(id) + "/";
279
280 if (!store_has_prefix(dmcrypt_prefix) &&
281 !store_has_prefix(daemon_prefix)) {
282 return -ENOENT;
283 }
284 return 0;
285 }
286
287 void ConfigKeyService::do_osd_destroy(int32_t id, uuid_d& uuid)
288 {
289 string dmcrypt_prefix = _get_dmcrypt_prefix(uuid, "");
290 string daemon_prefix =
291 "daemon-private/osd." + stringify(id) + "/";
292
293 MonitorDBStore::TransactionRef t = paxos->get_pending_transaction();
294 for (auto p : { dmcrypt_prefix, daemon_prefix }) {
295 store_delete_prefix(t, p);
296 }
297
298 paxos->trigger_propose();
299 }
300
301 int ConfigKeyService::validate_osd_new(
302 const uuid_d& uuid,
303 const string& dmcrypt_key,
304 stringstream& ss)
305 {
306 string dmcrypt_prefix = _get_dmcrypt_prefix(uuid, "luks");
307 bufferlist value;
308 value.append(dmcrypt_key);
309
310 if (store_exists(dmcrypt_prefix)) {
311 bufferlist existing_value;
312 int err = store_get(dmcrypt_prefix, existing_value);
313 if (err < 0) {
314 dout(10) << __func__ << " unable to get dm-crypt key from store (r = "
315 << err << ")" << dendl;
316 return err;
317 }
318 if (existing_value.contents_equal(value)) {
319 // both values match; this will be an idempotent op.
320 return EEXIST;
321 }
322 ss << "dm-crypt key already exists and does not match";
323 return -EEXIST;
324 }
325 return 0;
326 }
327
328 void ConfigKeyService::do_osd_new(
329 const uuid_d& uuid,
330 const string& dmcrypt_key)
331 {
332 assert(paxos->is_plugged());
333
334 string dmcrypt_key_prefix = _get_dmcrypt_prefix(uuid, "luks");
335 bufferlist dmcrypt_key_value;
336 dmcrypt_key_value.append(dmcrypt_key);
337 // store_put() will call trigger_propose
338 store_put(dmcrypt_key_prefix, dmcrypt_key_value, nullptr);
339 }