]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/services/svc_cls.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rgw / services / svc_cls.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4
5 #include "svc_cls.h"
6 #include "svc_rados.h"
7 #include "svc_zone.h"
8
9 #include "rgw/rgw_zone.h"
10
11 #include "cls/otp/cls_otp_client.h"
12 #include "cls/log/cls_log_client.h"
13 #include "cls/lock/cls_lock_client.h"
14
15
16 #define dout_subsys ceph_subsys_rgw
17
18 using namespace std;
19
20 static string log_lock_name = "rgw_log_lock";
21
22 int RGWSI_Cls::do_start(optional_yield y, const DoutPrefixProvider *dpp)
23 {
24 int r = mfa.do_start(y, dpp);
25 if (r < 0) {
26 ldpp_dout(dpp, 0) << "ERROR: failed to start mfa service" << dendl;
27 return r;
28 }
29
30 return 0;
31 }
32
33 int RGWSI_Cls::MFA::get_mfa_obj(const DoutPrefixProvider *dpp, const rgw_user& user, std::optional<RGWSI_RADOS::Obj> *obj)
34 {
35 string oid = get_mfa_oid(user);
36 rgw_raw_obj o(zone_svc->get_zone_params().otp_pool, oid);
37
38 obj->emplace(rados_svc->obj(o));
39 int r = (*obj)->open(dpp);
40 if (r < 0) {
41 ldpp_dout(dpp, 4) << "failed to open rados context for " << o << dendl;
42 return r;
43 }
44
45 return 0;
46 }
47
48 int RGWSI_Cls::MFA::get_mfa_ref(const DoutPrefixProvider *dpp, const rgw_user& user, rgw_rados_ref *ref)
49 {
50 std::optional<RGWSI_RADOS::Obj> obj;
51 int r = get_mfa_obj(dpp, user, &obj);
52 if (r < 0) {
53 return r;
54 }
55 *ref = obj->get_ref();
56 return 0;
57 }
58
59 int RGWSI_Cls::MFA::check_mfa(const DoutPrefixProvider *dpp, const rgw_user& user, const string& otp_id, const string& pin, optional_yield y)
60 {
61 rgw_rados_ref ref;
62 int r = get_mfa_ref(dpp, user, &ref);
63 if (r < 0) {
64 return r;
65 }
66
67 rados::cls::otp::otp_check_t result;
68
69 r = rados::cls::otp::OTP::check(cct, ref.pool.ioctx(), ref.obj.oid, otp_id, pin, &result);
70 if (r < 0)
71 return r;
72
73 ldpp_dout(dpp, 20) << "OTP check, otp_id=" << otp_id << " result=" << (int)result.result << dendl;
74
75 return (result.result == rados::cls::otp::OTP_CHECK_SUCCESS ? 0 : -EACCES);
76 }
77
78 void RGWSI_Cls::MFA::prepare_mfa_write(librados::ObjectWriteOperation *op,
79 RGWObjVersionTracker *objv_tracker,
80 const ceph::real_time& mtime)
81 {
82 RGWObjVersionTracker ot;
83
84 if (objv_tracker) {
85 ot = *objv_tracker;
86 }
87
88 if (ot.write_version.tag.empty()) {
89 if (ot.read_version.tag.empty()) {
90 ot.generate_new_write_ver(cct);
91 } else {
92 ot.write_version = ot.read_version;
93 ot.write_version.ver++;
94 }
95 }
96
97 ot.prepare_op_for_write(op);
98 struct timespec mtime_ts = real_clock::to_timespec(mtime);
99 op->mtime2(&mtime_ts);
100 }
101
102 int RGWSI_Cls::MFA::create_mfa(const DoutPrefixProvider *dpp, const rgw_user& user, const rados::cls::otp::otp_info_t& config,
103 RGWObjVersionTracker *objv_tracker, const ceph::real_time& mtime, optional_yield y)
104 {
105 std::optional<RGWSI_RADOS::Obj> obj;
106 int r = get_mfa_obj(dpp, user, &obj);
107 if (r < 0) {
108 return r;
109 }
110
111 librados::ObjectWriteOperation op;
112 prepare_mfa_write(&op, objv_tracker, mtime);
113 rados::cls::otp::OTP::create(&op, config);
114 r = obj->operate(dpp, &op, y);
115 if (r < 0) {
116 ldpp_dout(dpp, 20) << "OTP create, otp_id=" << config.id << " result=" << (int)r << dendl;
117 return r;
118 }
119
120 return 0;
121 }
122
123 int RGWSI_Cls::MFA::remove_mfa(const DoutPrefixProvider *dpp,
124 const rgw_user& user, const string& id,
125 RGWObjVersionTracker *objv_tracker,
126 const ceph::real_time& mtime,
127 optional_yield y)
128 {
129 std::optional<RGWSI_RADOS::Obj> obj;
130 int r = get_mfa_obj(dpp, user, &obj);
131 if (r < 0) {
132 return r;
133 }
134
135 librados::ObjectWriteOperation op;
136 prepare_mfa_write(&op, objv_tracker, mtime);
137 rados::cls::otp::OTP::remove(&op, id);
138 r = obj->operate(dpp, &op, y);
139 if (r < 0) {
140 ldpp_dout(dpp, 20) << "OTP remove, otp_id=" << id << " result=" << (int)r << dendl;
141 return r;
142 }
143
144 return 0;
145 }
146
147 int RGWSI_Cls::MFA::get_mfa(const DoutPrefixProvider *dpp, const rgw_user& user, const string& id, rados::cls::otp::otp_info_t *result,
148 optional_yield y)
149 {
150 rgw_rados_ref ref;
151
152 int r = get_mfa_ref(dpp, user, &ref);
153 if (r < 0) {
154 return r;
155 }
156
157 r = rados::cls::otp::OTP::get(nullptr, ref.pool.ioctx(), ref.obj.oid, id, result);
158 if (r < 0) {
159 return r;
160 }
161
162 return 0;
163 }
164
165 int RGWSI_Cls::MFA::list_mfa(const DoutPrefixProvider *dpp, const rgw_user& user, list<rados::cls::otp::otp_info_t> *result,
166 optional_yield y)
167 {
168 rgw_rados_ref ref;
169
170 int r = get_mfa_ref(dpp, user, &ref);
171 if (r < 0) {
172 return r;
173 }
174
175 r = rados::cls::otp::OTP::get_all(nullptr, ref.pool.ioctx(), ref.obj.oid, result);
176 if (r < 0) {
177 return r;
178 }
179
180 return 0;
181 }
182
183 int RGWSI_Cls::MFA::otp_get_current_time(const DoutPrefixProvider *dpp, const rgw_user& user, ceph::real_time *result,
184 optional_yield y)
185 {
186 rgw_rados_ref ref;
187
188 int r = get_mfa_ref(dpp, user, &ref);
189 if (r < 0) {
190 return r;
191 }
192
193 r = rados::cls::otp::OTP::get_current_time(ref.pool.ioctx(), ref.obj.oid, result);
194 if (r < 0) {
195 return r;
196 }
197
198 return 0;
199 }
200
201 int RGWSI_Cls::MFA::set_mfa(const DoutPrefixProvider *dpp, const string& oid, const list<rados::cls::otp::otp_info_t>& entries,
202 bool reset_obj, RGWObjVersionTracker *objv_tracker,
203 const real_time& mtime,
204 optional_yield y)
205 {
206 rgw_raw_obj o(zone_svc->get_zone_params().otp_pool, oid);
207 auto obj = rados_svc->obj(o);
208 int r = obj.open(dpp);
209 if (r < 0) {
210 ldpp_dout(dpp, 4) << "failed to open rados context for " << o << dendl;
211 return r;
212 }
213 librados::ObjectWriteOperation op;
214 if (reset_obj) {
215 op.remove();
216 op.set_op_flags2(LIBRADOS_OP_FLAG_FAILOK);
217 op.create(false);
218 }
219 prepare_mfa_write(&op, objv_tracker, mtime);
220 rados::cls::otp::OTP::set(&op, entries);
221 r = obj.operate(dpp, &op, y);
222 if (r < 0) {
223 ldpp_dout(dpp, 20) << "OTP set entries.size()=" << entries.size() << " result=" << (int)r << dendl;
224 return r;
225 }
226
227 return 0;
228 }
229
230 int RGWSI_Cls::MFA::list_mfa(const DoutPrefixProvider *dpp, const string& oid, list<rados::cls::otp::otp_info_t> *result,
231 RGWObjVersionTracker *objv_tracker, ceph::real_time *pmtime,
232 optional_yield y)
233 {
234 rgw_raw_obj o(zone_svc->get_zone_params().otp_pool, oid);
235 auto obj = rados_svc->obj(o);
236 int r = obj.open(dpp);
237 if (r < 0) {
238 ldpp_dout(dpp, 4) << "failed to open rados context for " << o << dendl;
239 return r;
240 }
241 auto& ref = obj.get_ref();
242 librados::ObjectReadOperation op;
243 struct timespec mtime_ts;
244 if (pmtime) {
245 op.stat2(nullptr, &mtime_ts, nullptr);
246 }
247 objv_tracker->prepare_op_for_read(&op);
248 r = rados::cls::otp::OTP::get_all(&op, ref.pool.ioctx(), ref.obj.oid, result);
249 if (r < 0) {
250 return r;
251 }
252 if (pmtime) {
253 *pmtime = ceph::real_clock::from_timespec(mtime_ts);
254 }
255
256 return 0;
257 }
258
259 void RGWSI_Cls::TimeLog::prepare_entry(cls_log_entry& entry,
260 const real_time& ut,
261 const string& section,
262 const string& key,
263 bufferlist& bl)
264 {
265 cls_log_add_prepare_entry(entry, utime_t(ut), section, key, bl);
266 }
267
268 int RGWSI_Cls::TimeLog::init_obj(const DoutPrefixProvider *dpp, const string& oid, RGWSI_RADOS::Obj& obj)
269 {
270 rgw_raw_obj o(zone_svc->get_zone_params().log_pool, oid);
271 obj = rados_svc->obj(o);
272 return obj.open(dpp);
273
274 }
275 int RGWSI_Cls::TimeLog::add(const DoutPrefixProvider *dpp,
276 const string& oid,
277 const real_time& ut,
278 const string& section,
279 const string& key,
280 bufferlist& bl,
281 optional_yield y)
282 {
283 RGWSI_RADOS::Obj obj;
284
285 int r = init_obj(dpp, oid, obj);
286 if (r < 0) {
287 return r;
288 }
289
290 librados::ObjectWriteOperation op;
291 utime_t t(ut);
292 cls_log_add(op, t, section, key, bl);
293
294 return obj.operate(dpp, &op, y);
295 }
296
297 int RGWSI_Cls::TimeLog::add(const DoutPrefixProvider *dpp,
298 const string& oid,
299 std::list<cls_log_entry>& entries,
300 librados::AioCompletion *completion,
301 bool monotonic_inc,
302 optional_yield y)
303 {
304 RGWSI_RADOS::Obj obj;
305
306 int r = init_obj(dpp, oid, obj);
307 if (r < 0) {
308 return r;
309 }
310
311 librados::ObjectWriteOperation op;
312 cls_log_add(op, entries, monotonic_inc);
313
314 if (!completion) {
315 r = obj.operate(dpp, &op, y);
316 } else {
317 r = obj.aio_operate(completion, &op);
318 }
319 return r;
320 }
321
322 int RGWSI_Cls::TimeLog::list(const DoutPrefixProvider *dpp,
323 const string& oid,
324 const real_time& start_time,
325 const real_time& end_time,
326 int max_entries, std::list<cls_log_entry>& entries,
327 const string& marker,
328 string *out_marker,
329 bool *truncated,
330 optional_yield y)
331 {
332 RGWSI_RADOS::Obj obj;
333
334 int r = init_obj(dpp, oid, obj);
335 if (r < 0) {
336 return r;
337 }
338
339 librados::ObjectReadOperation op;
340
341 utime_t st(start_time);
342 utime_t et(end_time);
343
344 cls_log_list(op, st, et, marker, max_entries, entries,
345 out_marker, truncated);
346
347 bufferlist obl;
348
349 int ret = obj.operate(dpp, &op, &obl, y);
350 if (ret < 0)
351 return ret;
352
353 return 0;
354 }
355
356 int RGWSI_Cls::TimeLog::info(const DoutPrefixProvider *dpp,
357 const string& oid,
358 cls_log_header *header,
359 optional_yield y)
360 {
361 RGWSI_RADOS::Obj obj;
362
363 int r = init_obj(dpp, oid, obj);
364 if (r < 0) {
365 return r;
366 }
367
368 librados::ObjectReadOperation op;
369
370 cls_log_info(op, header);
371
372 bufferlist obl;
373
374 int ret = obj.operate(dpp, &op, &obl, y);
375 if (ret < 0)
376 return ret;
377
378 return 0;
379 }
380
381 int RGWSI_Cls::TimeLog::info_async(const DoutPrefixProvider *dpp,
382 RGWSI_RADOS::Obj& obj,
383 const string& oid,
384 cls_log_header *header,
385 librados::AioCompletion *completion)
386 {
387 int r = init_obj(dpp, oid, obj);
388 if (r < 0) {
389 return r;
390 }
391
392 librados::ObjectReadOperation op;
393
394 cls_log_info(op, header);
395
396 int ret = obj.aio_operate(completion, &op, nullptr);
397 if (ret < 0)
398 return ret;
399
400 return 0;
401 }
402
403 int RGWSI_Cls::TimeLog::trim(const DoutPrefixProvider *dpp,
404 const string& oid,
405 const real_time& start_time,
406 const real_time& end_time,
407 const string& from_marker,
408 const string& to_marker,
409 librados::AioCompletion *completion,
410 optional_yield y)
411 {
412 RGWSI_RADOS::Obj obj;
413
414 int r = init_obj(dpp, oid, obj);
415 if (r < 0) {
416 return r;
417 }
418
419 utime_t st(start_time);
420 utime_t et(end_time);
421
422 librados::ObjectWriteOperation op;
423 cls_log_trim(op, st, et, from_marker, to_marker);
424
425 if (!completion) {
426 r = obj.operate(dpp, &op, y);
427 } else {
428 r = obj.aio_operate(completion, &op);
429 }
430 return r;
431 }
432
433 int RGWSI_Cls::Lock::lock_exclusive(const DoutPrefixProvider *dpp,
434 const rgw_pool& pool,
435 const string& oid,
436 timespan& duration,
437 string& zone_id,
438 string& owner_id,
439 std::optional<string> lock_name)
440 {
441 auto p = rados_svc->pool(pool);
442 int r = p.open(dpp);
443 if (r < 0) {
444 return r;
445 }
446
447 uint64_t msec = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
448 utime_t ut(msec / 1000, msec % 1000);
449
450 rados::cls::lock::Lock l(lock_name.value_or(log_lock_name));
451 l.set_duration(ut);
452 l.set_cookie(owner_id);
453 l.set_tag(zone_id);
454 l.set_may_renew(true);
455
456 return l.lock_exclusive(&p.ioctx(), oid);
457 }
458
459 int RGWSI_Cls::Lock::unlock(const DoutPrefixProvider *dpp,
460 const rgw_pool& pool,
461 const string& oid,
462 string& zone_id,
463 string& owner_id,
464 std::optional<string> lock_name)
465 {
466 auto p = rados_svc->pool(pool);
467 int r = p.open(dpp);
468 if (r < 0) {
469 return r;
470 }
471
472 rados::cls::lock::Lock l(lock_name.value_or(log_lock_name));
473 l.set_tag(zone_id);
474 l.set_cookie(owner_id);
475
476 return l.unlock(&p.ioctx(), oid);
477 }
478