]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/services/svc_user_rados.cc
b2f8f9665e0929ce4d4560a3a4b37c9f5f5323d8
[ceph.git] / ceph / src / rgw / services / svc_user_rados.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 #include <boost/algorithm/string.hpp>
5
6 #include "svc_user.h"
7 #include "svc_user_rados.h"
8 #include "svc_zone.h"
9 #include "svc_sys_obj.h"
10 #include "svc_sys_obj_cache.h"
11 #include "svc_meta.h"
12 #include "svc_meta_be_sobj.h"
13 #include "svc_sync_modules.h"
14
15 #include "rgw/rgw_user.h"
16 #include "rgw/rgw_bucket.h"
17 #include "rgw/rgw_tools.h"
18 #include "rgw/rgw_zone.h"
19 #include "rgw/rgw_rados.h"
20
21 #include "cls/user/cls_user_client.h"
22
23 #define dout_subsys ceph_subsys_rgw
24
25 #define RGW_BUCKETS_OBJ_SUFFIX ".buckets"
26
27 using namespace std;
28
29 class RGWSI_User_Module : public RGWSI_MBSObj_Handler_Module {
30 RGWSI_User_RADOS::Svc& svc;
31
32 const string prefix;
33 public:
34 RGWSI_User_Module(RGWSI_User_RADOS::Svc& _svc) : RGWSI_MBSObj_Handler_Module("user"),
35 svc(_svc) {}
36
37 void get_pool_and_oid(const string& key, rgw_pool *pool, string *oid) override {
38 if (pool) {
39 *pool = svc.zone->get_zone_params().user_uid_pool;
40 }
41 if (oid) {
42 *oid = key;
43 }
44 }
45
46 const string& get_oid_prefix() override {
47 return prefix;
48 }
49
50 bool is_valid_oid(const string& oid) override {
51 // filter out the user.buckets objects
52 return !boost::algorithm::ends_with(oid, RGW_BUCKETS_OBJ_SUFFIX);
53 }
54
55 string key_to_oid(const string& key) override {
56 return key;
57 }
58
59 string oid_to_key(const string& oid) override {
60 return oid;
61 }
62 };
63
64 RGWSI_User_RADOS::RGWSI_User_RADOS(CephContext *cct): RGWSI_User(cct) {
65 }
66
67 RGWSI_User_RADOS::~RGWSI_User_RADOS() {
68 }
69
70 void RGWSI_User_RADOS::init(RGWSI_RADOS *_rados_svc,
71 RGWSI_Zone *_zone_svc, RGWSI_SysObj *_sysobj_svc,
72 RGWSI_SysObj_Cache *_cache_svc, RGWSI_Meta *_meta_svc,
73 RGWSI_MetaBackend *_meta_be_svc,
74 RGWSI_SyncModules *_sync_modules_svc)
75 {
76 svc.user = this;
77 svc.rados = _rados_svc;
78 svc.zone = _zone_svc;
79 svc.sysobj = _sysobj_svc;
80 svc.cache = _cache_svc;
81 svc.meta = _meta_svc;
82 svc.meta_be = _meta_be_svc;
83 svc.sync_modules = _sync_modules_svc;
84 }
85
86 int RGWSI_User_RADOS::do_start(optional_yield, const DoutPrefixProvider *dpp)
87 {
88 uinfo_cache.reset(new RGWChainedCacheImpl<user_info_cache_entry>);
89 uinfo_cache->init(svc.cache);
90
91 int r = svc.meta->create_be_handler(RGWSI_MetaBackend::Type::MDBE_SOBJ, &be_handler);
92 if (r < 0) {
93 ldpp_dout(dpp, 0) << "ERROR: failed to create be handler: r=" << r << dendl;
94 return r;
95 }
96
97 RGWSI_MetaBackend_Handler_SObj *bh = static_cast<RGWSI_MetaBackend_Handler_SObj *>(be_handler);
98
99 auto module = new RGWSI_User_Module(svc);
100 be_module.reset(module);
101 bh->set_module(module);
102 return 0;
103 }
104
105 rgw_raw_obj RGWSI_User_RADOS::get_buckets_obj(const rgw_user& user) const
106 {
107 string oid = user.to_str() + RGW_BUCKETS_OBJ_SUFFIX;
108 return rgw_raw_obj(svc.zone->get_zone_params().user_uid_pool, oid);
109 }
110
111 int RGWSI_User_RADOS::read_user_info(RGWSI_MetaBackend::Context *ctx,
112 const rgw_user& user,
113 RGWUserInfo *info,
114 RGWObjVersionTracker * const objv_tracker,
115 real_time * const pmtime,
116 rgw_cache_entry_info * const cache_info,
117 map<string, bufferlist> * const pattrs,
118 optional_yield y,
119 const DoutPrefixProvider *dpp)
120 {
121 if(user.id == RGW_USER_ANON_ID) {
122 ldpp_dout(dpp, 20) << "RGWSI_User_RADOS::read_user_info(): anonymous user" << dendl;
123 return -ENOENT;
124 }
125 bufferlist bl;
126 RGWUID user_id;
127
128 RGWSI_MBSObj_GetParams params(&bl, pattrs, pmtime);
129 params.set_cache_info(cache_info);
130
131 int ret = svc.meta_be->get_entry(ctx, get_meta_key(user), params, objv_tracker, y, dpp);
132 if (ret < 0) {
133 return ret;
134 }
135
136 auto iter = bl.cbegin();
137 try {
138 decode(user_id, iter);
139 if (user_id.user_id != user) {
140 ldpp_dout(dpp, -1) << "ERROR: rgw_get_user_info_by_uid(): user id mismatch: " << user_id.user_id << " != " << user << dendl;
141 return -EIO;
142 }
143 if (!iter.end()) {
144 decode(*info, iter);
145 }
146 } catch (buffer::error& err) {
147 ldpp_dout(dpp, 0) << "ERROR: failed to decode user info, caught buffer::error" << dendl;
148 return -EIO;
149 }
150
151 return 0;
152 }
153
154 class PutOperation
155 {
156 RGWSI_User_RADOS::Svc& svc;
157 RGWSI_MetaBackend_SObj::Context_SObj *ctx;
158 RGWUID ui;
159 const RGWUserInfo& info;
160 RGWUserInfo *old_info;
161 RGWObjVersionTracker *objv_tracker;
162 const real_time& mtime;
163 bool exclusive;
164 map<string, bufferlist> *pattrs;
165 RGWObjVersionTracker ot;
166 string err_msg;
167 optional_yield y;
168
169 void set_err_msg(string msg) {
170 if (!err_msg.empty()) {
171 err_msg = std::move(msg);
172 }
173 }
174
175 public:
176 PutOperation(RGWSI_User_RADOS::Svc& svc,
177 RGWSI_MetaBackend::Context *_ctx,
178 const RGWUserInfo& info,
179 RGWUserInfo *old_info,
180 RGWObjVersionTracker *objv_tracker,
181 const real_time& mtime,
182 bool exclusive,
183 map<string, bufferlist> *pattrs,
184 optional_yield y) :
185 svc(svc), info(info), old_info(old_info),
186 objv_tracker(objv_tracker), mtime(mtime),
187 exclusive(exclusive), pattrs(pattrs), y(y) {
188 ctx = static_cast<RGWSI_MetaBackend_SObj::Context_SObj *>(_ctx);
189 ui.user_id = info.user_id;
190 }
191
192 int prepare(const DoutPrefixProvider *dpp) {
193 if (objv_tracker) {
194 ot = *objv_tracker;
195 }
196
197 if (ot.write_version.tag.empty()) {
198 if (ot.read_version.tag.empty()) {
199 ot.generate_new_write_ver(svc.meta_be->ctx());
200 } else {
201 ot.write_version = ot.read_version;
202 ot.write_version.ver++;
203 }
204 }
205
206 for (auto iter = info.swift_keys.begin(); iter != info.swift_keys.end(); ++iter) {
207 if (old_info && old_info->swift_keys.count(iter->first) != 0)
208 continue;
209 auto& k = iter->second;
210 /* check if swift mapping exists */
211 RGWUserInfo inf;
212 int r = svc.user->get_user_info_by_swift(ctx, k.id, &inf, nullptr, nullptr, y, dpp);
213 if (r >= 0 && inf.user_id != info.user_id &&
214 (!old_info || inf.user_id != old_info->user_id)) {
215 ldpp_dout(dpp, 0) << "WARNING: can't store user info, swift id (" << k.id
216 << ") already mapped to another user (" << info.user_id << ")" << dendl;
217 return -EEXIST;
218 }
219 }
220
221 /* check if access keys already exist */
222 for (auto iter = info.access_keys.begin(); iter != info.access_keys.end(); ++iter) {
223 if (old_info && old_info->access_keys.count(iter->first) != 0)
224 continue;
225 auto& k = iter->second;
226 RGWUserInfo inf;
227 int r = svc.user->get_user_info_by_access_key(ctx, k.id, &inf, nullptr, nullptr, y, dpp);
228 if (r >= 0 && inf.user_id != info.user_id &&
229 (!old_info || inf.user_id != old_info->user_id)) {
230 ldpp_dout(dpp, 0) << "WARNING: can't store user info, access key already mapped to another user" << dendl;
231 return -EEXIST;
232 }
233 }
234
235 return 0;
236 }
237
238 int put(const DoutPrefixProvider *dpp) {
239 bufferlist data_bl;
240 encode(ui, data_bl);
241 encode(info, data_bl);
242
243 RGWSI_MBSObj_PutParams params(data_bl, pattrs, mtime, exclusive);
244
245 int ret = svc.meta_be->put(ctx, RGWSI_User::get_meta_key(info.user_id), params, &ot, y, dpp);
246 if (ret < 0)
247 return ret;
248
249 return 0;
250 }
251
252 int complete(const DoutPrefixProvider *dpp) {
253 int ret;
254
255 bufferlist link_bl;
256 encode(ui, link_bl);
257
258 auto& obj_ctx = *ctx->obj_ctx;
259
260 if (!info.user_email.empty()) {
261 if (!old_info ||
262 old_info->user_email.compare(info.user_email) != 0) { /* only if new index changed */
263 ret = rgw_put_system_obj(dpp, obj_ctx, svc.zone->get_zone_params().user_email_pool, info.user_email,
264 link_bl, exclusive, NULL, real_time(), y);
265 if (ret < 0)
266 return ret;
267 }
268 }
269
270 const bool renamed = old_info && old_info->user_id != info.user_id;
271 for (auto iter = info.access_keys.begin(); iter != info.access_keys.end(); ++iter) {
272 auto& k = iter->second;
273 if (old_info && old_info->access_keys.count(iter->first) != 0 && !renamed)
274 continue;
275
276 ret = rgw_put_system_obj(dpp, obj_ctx, svc.zone->get_zone_params().user_keys_pool, k.id,
277 link_bl, exclusive, NULL, real_time(), y);
278 if (ret < 0)
279 return ret;
280 }
281
282 for (auto siter = info.swift_keys.begin(); siter != info.swift_keys.end(); ++siter) {
283 auto& k = siter->second;
284 if (old_info && old_info->swift_keys.count(siter->first) != 0 && !renamed)
285 continue;
286
287 ret = rgw_put_system_obj(dpp, obj_ctx, svc.zone->get_zone_params().user_swift_pool, k.id,
288 link_bl, exclusive, NULL, real_time(), y);
289 if (ret < 0)
290 return ret;
291 }
292
293 if (old_info) {
294 ret = remove_old_indexes(*old_info, info, y, dpp);
295 if (ret < 0) {
296 return ret;
297 }
298 }
299
300 return 0;
301 }
302
303 int remove_old_indexes(const RGWUserInfo& old_info, const RGWUserInfo& new_info, optional_yield y, const DoutPrefixProvider *dpp) {
304 int ret;
305
306 if (!old_info.user_id.empty() &&
307 old_info.user_id != new_info.user_id) {
308 if (old_info.user_id.tenant != new_info.user_id.tenant) {
309 ldpp_dout(dpp, 0) << "ERROR: tenant mismatch: " << old_info.user_id.tenant << " != " << new_info.user_id.tenant << dendl;
310 return -EINVAL;
311 }
312 ret = svc.user->remove_uid_index(ctx, old_info, nullptr, y, dpp);
313 if (ret < 0 && ret != -ENOENT) {
314 set_err_msg("ERROR: could not remove index for uid " + old_info.user_id.to_str());
315 return ret;
316 }
317 }
318
319 if (!old_info.user_email.empty() &&
320 old_info.user_email != new_info.user_email) {
321 ret = svc.user->remove_email_index(dpp, ctx, old_info.user_email, y);
322 if (ret < 0 && ret != -ENOENT) {
323 set_err_msg("ERROR: could not remove index for email " + old_info.user_email);
324 return ret;
325 }
326 }
327
328 for ([[maybe_unused]] const auto& [name, access_key] : old_info.access_keys) {
329 if (!new_info.access_keys.count(access_key.id)) {
330 ret = svc.user->remove_key_index(dpp, ctx, access_key, y);
331 if (ret < 0 && ret != -ENOENT) {
332 set_err_msg("ERROR: could not remove index for key " + access_key.id);
333 return ret;
334 }
335 }
336 }
337
338 for (auto old_iter = old_info.swift_keys.begin(); old_iter != old_info.swift_keys.end(); ++old_iter) {
339 const auto& swift_key = old_iter->second;
340 auto new_iter = new_info.swift_keys.find(swift_key.id);
341 if (new_iter == new_info.swift_keys.end()) {
342 ret = svc.user->remove_swift_name_index(dpp, ctx, swift_key.id, y);
343 if (ret < 0 && ret != -ENOENT) {
344 set_err_msg("ERROR: could not remove index for swift_name " + swift_key.id);
345 return ret;
346 }
347 }
348 }
349
350 return 0;
351 }
352
353 const string& get_err_msg() {
354 return err_msg;
355 }
356 };
357
358 int RGWSI_User_RADOS::store_user_info(RGWSI_MetaBackend::Context *ctx,
359 const RGWUserInfo& info,
360 RGWUserInfo *old_info,
361 RGWObjVersionTracker *objv_tracker,
362 const real_time& mtime,
363 bool exclusive,
364 map<string, bufferlist> *attrs,
365 optional_yield y,
366 const DoutPrefixProvider *dpp)
367 {
368 PutOperation op(svc, ctx,
369 info, old_info,
370 objv_tracker,
371 mtime, exclusive,
372 attrs,
373 y);
374
375 int r = op.prepare(dpp);
376 if (r < 0) {
377 return r;
378 }
379
380 r = op.put(dpp);
381 if (r < 0) {
382 return r;
383 }
384
385 r = op.complete(dpp);
386 if (r < 0) {
387 return r;
388 }
389
390 return 0;
391 }
392
393 int RGWSI_User_RADOS::remove_key_index(const DoutPrefixProvider *dpp,
394 RGWSI_MetaBackend::Context *_ctx,
395 const RGWAccessKey& access_key,
396 optional_yield y)
397 {
398 RGWSI_MetaBackend_SObj::Context_SObj *ctx = static_cast<RGWSI_MetaBackend_SObj::Context_SObj *>(_ctx);
399 rgw_raw_obj obj(svc.zone->get_zone_params().user_keys_pool, access_key.id);
400 auto sysobj = ctx->obj_ctx->get_obj(obj);
401 return sysobj.wop().remove(dpp, y);
402 }
403
404 int RGWSI_User_RADOS::remove_email_index(const DoutPrefixProvider *dpp,
405 RGWSI_MetaBackend::Context *_ctx,
406 const string& email,
407 optional_yield y)
408 {
409 if (email.empty()) {
410 return 0;
411 }
412 RGWSI_MetaBackend_SObj::Context_SObj *ctx = static_cast<RGWSI_MetaBackend_SObj::Context_SObj *>(_ctx);
413 rgw_raw_obj obj(svc.zone->get_zone_params().user_email_pool, email);
414 auto sysobj = ctx->obj_ctx->get_obj(obj);
415 return sysobj.wop().remove(dpp, y);
416 }
417
418 int RGWSI_User_RADOS::remove_swift_name_index(const DoutPrefixProvider *dpp, RGWSI_MetaBackend::Context *_ctx, const string& swift_name,
419 optional_yield y)
420 {
421 RGWSI_MetaBackend_SObj::Context_SObj *ctx = static_cast<RGWSI_MetaBackend_SObj::Context_SObj *>(_ctx);
422 rgw_raw_obj obj(svc.zone->get_zone_params().user_swift_pool, swift_name);
423 auto sysobj = ctx->obj_ctx->get_obj(obj);
424 return sysobj.wop().remove(dpp, y);
425 }
426
427 /**
428 * delete a user's presence from the RGW system.
429 * First remove their bucket ACLs, then delete them
430 * from the user and user email pools. This leaves the pools
431 * themselves alone, as well as any ACLs embedded in object xattrs.
432 */
433 int RGWSI_User_RADOS::remove_user_info(RGWSI_MetaBackend::Context *_ctx,
434 const RGWUserInfo& info,
435 RGWObjVersionTracker *objv_tracker,
436 optional_yield y,
437 const DoutPrefixProvider *dpp)
438 {
439 int ret;
440
441 auto kiter = info.access_keys.begin();
442 for (; kiter != info.access_keys.end(); ++kiter) {
443 ldpp_dout(dpp, 10) << "removing key index: " << kiter->first << dendl;
444 ret = remove_key_index(dpp, _ctx, kiter->second, y);
445 if (ret < 0 && ret != -ENOENT) {
446 ldpp_dout(dpp, 0) << "ERROR: could not remove " << kiter->first << " (access key object), should be fixed (err=" << ret << ")" << dendl;
447 return ret;
448 }
449 }
450
451 auto siter = info.swift_keys.begin();
452 for (; siter != info.swift_keys.end(); ++siter) {
453 auto& k = siter->second;
454 ldpp_dout(dpp, 10) << "removing swift subuser index: " << k.id << dendl;
455 /* check if swift mapping exists */
456 ret = remove_swift_name_index(dpp, _ctx, k.id, y);
457 if (ret < 0 && ret != -ENOENT) {
458 ldpp_dout(dpp, 0) << "ERROR: could not remove " << k.id << " (swift name object), should be fixed (err=" << ret << ")" << dendl;
459 return ret;
460 }
461 }
462
463 ldpp_dout(dpp, 10) << "removing email index: " << info.user_email << dendl;
464 ret = remove_email_index(dpp, _ctx, info.user_email, y);
465 if (ret < 0 && ret != -ENOENT) {
466 ldpp_dout(dpp, 0) << "ERROR: could not remove email index object for "
467 << info.user_email << ", should be fixed (err=" << ret << ")" << dendl;
468 return ret;
469 }
470
471 rgw_raw_obj uid_bucks = get_buckets_obj(info.user_id);
472 ldpp_dout(dpp, 10) << "removing user buckets index" << dendl;
473 RGWSI_MetaBackend_SObj::Context_SObj *ctx = static_cast<RGWSI_MetaBackend_SObj::Context_SObj *>(_ctx);
474 auto sysobj = ctx->obj_ctx->get_obj(uid_bucks);
475 ret = sysobj.wop().remove(dpp, y);
476 if (ret < 0 && ret != -ENOENT) {
477 ldpp_dout(dpp, 0) << "ERROR: could not remove " << info.user_id << ":" << uid_bucks << ", should be fixed (err=" << ret << ")" << dendl;
478 return ret;
479 }
480
481 ret = remove_uid_index(ctx, info, objv_tracker, y, dpp);
482 if (ret < 0 && ret != -ENOENT) {
483 return ret;
484 }
485
486 return 0;
487 }
488
489 int RGWSI_User_RADOS::remove_uid_index(RGWSI_MetaBackend::Context *ctx, const RGWUserInfo& user_info, RGWObjVersionTracker *objv_tracker,
490 optional_yield y, const DoutPrefixProvider *dpp)
491 {
492 ldpp_dout(dpp, 10) << "removing user index: " << user_info.user_id << dendl;
493
494 RGWSI_MBSObj_RemoveParams params;
495 int ret = svc.meta_be->remove(ctx, get_meta_key(user_info.user_id), params, objv_tracker, y, dpp);
496 if (ret < 0 && ret != -ENOENT && ret != -ECANCELED) {
497 string key;
498 user_info.user_id.to_str(key);
499 rgw_raw_obj uid_obj(svc.zone->get_zone_params().user_uid_pool, key);
500 ldpp_dout(dpp, 0) << "ERROR: could not remove " << user_info.user_id << ":" << uid_obj << ", should be fixed (err=" << ret << ")" << dendl;
501 return ret;
502 }
503
504 return 0;
505 }
506
507 int RGWSI_User_RADOS::get_user_info_from_index(RGWSI_MetaBackend::Context *_ctx,
508 const string& key,
509 const rgw_pool& pool,
510 RGWUserInfo *info,
511 RGWObjVersionTracker * const objv_tracker,
512 real_time * const pmtime, optional_yield y, const DoutPrefixProvider *dpp)
513 {
514 RGWSI_MetaBackend_SObj::Context_SObj *ctx = static_cast<RGWSI_MetaBackend_SObj::Context_SObj *>(_ctx);
515
516 string cache_key = pool.to_str() + "/" + key;
517
518 if (auto e = uinfo_cache->find(cache_key)) {
519 *info = e->info;
520 if (objv_tracker)
521 *objv_tracker = e->objv_tracker;
522 if (pmtime)
523 *pmtime = e->mtime;
524 return 0;
525 }
526
527 user_info_cache_entry e;
528 bufferlist bl;
529 RGWUID uid;
530
531 int ret = rgw_get_system_obj(*ctx->obj_ctx, pool, key, bl, nullptr, &e.mtime, y, dpp);
532 if (ret < 0)
533 return ret;
534
535 rgw_cache_entry_info cache_info;
536
537 auto iter = bl.cbegin();
538 try {
539 decode(uid, iter);
540
541 int ret = read_user_info(ctx, uid.user_id,
542 &e.info, &e.objv_tracker, nullptr, &cache_info, nullptr,
543 y, dpp);
544 if (ret < 0) {
545 return ret;
546 }
547 } catch (buffer::error& err) {
548 ldpp_dout(dpp, 0) << "ERROR: failed to decode user info, caught buffer::error" << dendl;
549 return -EIO;
550 }
551
552 uinfo_cache->put(dpp, svc.cache, cache_key, &e, { &cache_info });
553
554 *info = e.info;
555 if (objv_tracker)
556 *objv_tracker = e.objv_tracker;
557 if (pmtime)
558 *pmtime = e.mtime;
559
560 return 0;
561 }
562
563 /**
564 * Given an email, finds the user info associated with it.
565 * returns: 0 on success, -ERR# on failure (including nonexistence)
566 */
567 int RGWSI_User_RADOS::get_user_info_by_email(RGWSI_MetaBackend::Context *ctx,
568 const string& email, RGWUserInfo *info,
569 RGWObjVersionTracker *objv_tracker,
570 real_time *pmtime, optional_yield y,
571 const DoutPrefixProvider *dpp)
572 {
573 return get_user_info_from_index(ctx, email, svc.zone->get_zone_params().user_email_pool,
574 info, objv_tracker, pmtime, y, dpp);
575 }
576
577 /**
578 * Given an swift username, finds the user_info associated with it.
579 * returns: 0 on success, -ERR# on failure (including nonexistence)
580 */
581 int RGWSI_User_RADOS::get_user_info_by_swift(RGWSI_MetaBackend::Context *ctx,
582 const string& swift_name,
583 RGWUserInfo *info, /* out */
584 RGWObjVersionTracker * const objv_tracker,
585 real_time * const pmtime, optional_yield y,
586 const DoutPrefixProvider *dpp)
587 {
588 return get_user_info_from_index(ctx,
589 swift_name,
590 svc.zone->get_zone_params().user_swift_pool,
591 info, objv_tracker, pmtime, y, dpp);
592 }
593
594 /**
595 * Given an access key, finds the user info associated with it.
596 * returns: 0 on success, -ERR# on failure (including nonexistence)
597 */
598 int RGWSI_User_RADOS::get_user_info_by_access_key(RGWSI_MetaBackend::Context *ctx,
599 const std::string& access_key,
600 RGWUserInfo *info,
601 RGWObjVersionTracker* objv_tracker,
602 real_time *pmtime, optional_yield y,
603 const DoutPrefixProvider *dpp)
604 {
605 return get_user_info_from_index(ctx,
606 access_key,
607 svc.zone->get_zone_params().user_keys_pool,
608 info, objv_tracker, pmtime, y, dpp);
609 }
610
611 int RGWSI_User_RADOS::cls_user_update_buckets(const DoutPrefixProvider *dpp, rgw_raw_obj& obj, list<cls_user_bucket_entry>& entries, bool add, optional_yield y)
612 {
613 auto rados_obj = svc.rados->obj(obj);
614 int r = rados_obj.open(dpp);
615 if (r < 0) {
616 return r;
617 }
618
619 librados::ObjectWriteOperation op;
620 cls_user_set_buckets(op, entries, add);
621 r = rados_obj.operate(dpp, &op, y);
622 if (r < 0) {
623 return r;
624 }
625
626 return 0;
627 }
628
629 int RGWSI_User_RADOS::cls_user_add_bucket(const DoutPrefixProvider *dpp, rgw_raw_obj& obj, const cls_user_bucket_entry& entry, optional_yield y)
630 {
631 list<cls_user_bucket_entry> l;
632 l.push_back(entry);
633
634 return cls_user_update_buckets(dpp, obj, l, true, y);
635 }
636
637 int RGWSI_User_RADOS::cls_user_remove_bucket(const DoutPrefixProvider *dpp, rgw_raw_obj& obj, const cls_user_bucket& bucket, optional_yield y)
638 {
639 auto rados_obj = svc.rados->obj(obj);
640 int r = rados_obj.open(dpp);
641 if (r < 0) {
642 return r;
643 }
644
645 librados::ObjectWriteOperation op;
646 ::cls_user_remove_bucket(op, bucket);
647 r = rados_obj.operate(dpp, &op, y);
648 if (r < 0)
649 return r;
650
651 return 0;
652 }
653
654 int RGWSI_User_RADOS::add_bucket(const DoutPrefixProvider *dpp,
655 RGWSI_MetaBackend::Context *ctx,
656 const rgw_user& user,
657 const rgw_bucket& bucket,
658 ceph::real_time creation_time,
659 optional_yield y)
660 {
661 int ret;
662
663 cls_user_bucket_entry new_bucket;
664
665 bucket.convert(&new_bucket.bucket);
666 new_bucket.size = 0;
667 if (real_clock::is_zero(creation_time))
668 new_bucket.creation_time = real_clock::now();
669 else
670 new_bucket.creation_time = creation_time;
671
672 rgw_raw_obj obj = get_buckets_obj(user);
673 ret = cls_user_add_bucket(dpp, obj, new_bucket, y);
674 if (ret < 0) {
675 ldpp_dout(dpp, 0) << "ERROR: error adding bucket to user: ret=" << ret << dendl;
676 return ret;
677 }
678
679 return 0;
680 }
681
682
683 int RGWSI_User_RADOS::remove_bucket(const DoutPrefixProvider *dpp,
684 RGWSI_MetaBackend::Context *ctx,
685 const rgw_user& user,
686 const rgw_bucket& _bucket,
687 optional_yield y)
688 {
689 cls_user_bucket bucket;
690 bucket.name = _bucket.name;
691 rgw_raw_obj obj = get_buckets_obj(user);
692 int ret = cls_user_remove_bucket(dpp, obj, bucket, y);
693 if (ret < 0) {
694 ldpp_dout(dpp, 0) << "ERROR: error removing bucket from user: ret=" << ret << dendl;
695 }
696
697 return 0;
698 }
699
700 int RGWSI_User_RADOS::cls_user_flush_bucket_stats(const DoutPrefixProvider *dpp,
701 rgw_raw_obj& user_obj,
702 const RGWBucketEnt& ent, optional_yield y)
703 {
704 cls_user_bucket_entry entry;
705 ent.convert(&entry);
706
707 list<cls_user_bucket_entry> entries;
708 entries.push_back(entry);
709
710 int r = cls_user_update_buckets(dpp, user_obj, entries, false, y);
711 if (r < 0) {
712 ldpp_dout(dpp, 20) << "cls_user_update_buckets() returned " << r << dendl;
713 return r;
714 }
715
716 return 0;
717 }
718
719 int RGWSI_User_RADOS::cls_user_list_buckets(const DoutPrefixProvider *dpp,
720 rgw_raw_obj& obj,
721 const string& in_marker,
722 const string& end_marker,
723 const int max_entries,
724 list<cls_user_bucket_entry>& entries,
725 string * const out_marker,
726 bool * const truncated,
727 optional_yield y)
728 {
729 auto rados_obj = svc.rados->obj(obj);
730 int r = rados_obj.open(dpp);
731 if (r < 0) {
732 return r;
733 }
734
735 librados::ObjectReadOperation op;
736 int rc;
737
738 cls_user_bucket_list(op, in_marker, end_marker, max_entries, entries, out_marker, truncated, &rc);
739 bufferlist ibl;
740 r = rados_obj.operate(dpp, &op, &ibl, y);
741 if (r < 0)
742 return r;
743 if (rc < 0)
744 return rc;
745
746 return 0;
747 }
748
749 int RGWSI_User_RADOS::list_buckets(const DoutPrefixProvider *dpp,
750 RGWSI_MetaBackend::Context *ctx,
751 const rgw_user& user,
752 const string& marker,
753 const string& end_marker,
754 uint64_t max,
755 RGWUserBuckets *buckets,
756 bool *is_truncated, optional_yield y)
757 {
758 int ret;
759
760 buckets->clear();
761 if (user.id == RGW_USER_ANON_ID) {
762 ldpp_dout(dpp, 20) << "RGWSI_User_RADOS::list_buckets(): anonymous user" << dendl;
763 *is_truncated = false;
764 return 0;
765 }
766 rgw_raw_obj obj = get_buckets_obj(user);
767
768 bool truncated = false;
769 string m = marker;
770
771 uint64_t total = 0;
772
773 do {
774 std::list<cls_user_bucket_entry> entries;
775 ret = cls_user_list_buckets(dpp, obj, m, end_marker, max - total, entries, &m, &truncated, y);
776 if (ret == -ENOENT) {
777 ret = 0;
778 }
779
780 if (ret < 0) {
781 return ret;
782 }
783
784 for (auto& entry : entries) {
785 buckets->add(RGWBucketEnt(user, std::move(entry)));
786 total++;
787 }
788
789 } while (truncated && total < max);
790
791 if (is_truncated) {
792 *is_truncated = truncated;
793 }
794
795 return 0;
796 }
797
798 int RGWSI_User_RADOS::flush_bucket_stats(const DoutPrefixProvider *dpp,
799 RGWSI_MetaBackend::Context *ctx,
800 const rgw_user& user,
801 const RGWBucketEnt& ent,
802 optional_yield y)
803 {
804 rgw_raw_obj obj = get_buckets_obj(user);
805
806 return cls_user_flush_bucket_stats(dpp, obj, ent, y);
807 }
808
809 int RGWSI_User_RADOS::reset_bucket_stats(const DoutPrefixProvider *dpp,
810 RGWSI_MetaBackend::Context *ctx,
811 const rgw_user& user,
812 optional_yield y)
813 {
814 return cls_user_reset_stats(dpp, user, y);
815 }
816
817 int RGWSI_User_RADOS::cls_user_reset_stats(const DoutPrefixProvider *dpp, const rgw_user& user, optional_yield y)
818 {
819 rgw_raw_obj obj = get_buckets_obj(user);
820 auto rados_obj = svc.rados->obj(obj);
821 int rval, r = rados_obj.open(dpp);
822 if (r < 0) {
823 return r;
824 }
825
826 cls_user_reset_stats2_op call;
827 cls_user_reset_stats2_ret ret;
828
829 do {
830 buffer::list in, out;
831 librados::ObjectWriteOperation op;
832
833 call.time = real_clock::now();
834 ret.update_call(call);
835
836 encode(call, in);
837 op.exec("user", "reset_user_stats2", in, &out, &rval);
838 r = rados_obj.operate(dpp, &op, y, librados::OPERATION_RETURNVEC);
839 if (r < 0) {
840 return r;
841 }
842 try {
843 auto bliter = out.cbegin();
844 decode(ret, bliter);
845 } catch (ceph::buffer::error& err) {
846 return -EINVAL;
847 }
848 } while (ret.truncated);
849
850 return rval;
851 }
852
853 int RGWSI_User_RADOS::complete_flush_stats(const DoutPrefixProvider *dpp,
854 RGWSI_MetaBackend::Context *ctx,
855 const rgw_user& user, optional_yield y)
856 {
857 rgw_raw_obj obj = get_buckets_obj(user);
858 auto rados_obj = svc.rados->obj(obj);
859 int r = rados_obj.open(dpp);
860 if (r < 0) {
861 return r;
862 }
863 librados::ObjectWriteOperation op;
864 ::cls_user_complete_stats_sync(op);
865 return rados_obj.operate(dpp, &op, y);
866 }
867
868 int RGWSI_User_RADOS::cls_user_get_header(const DoutPrefixProvider *dpp,
869 const rgw_user& user, cls_user_header *header,
870 optional_yield y)
871 {
872 rgw_raw_obj obj = get_buckets_obj(user);
873 auto rados_obj = svc.rados->obj(obj);
874 int r = rados_obj.open(dpp);
875 if (r < 0) {
876 return r;
877 }
878 int rc;
879 bufferlist ibl;
880 librados::ObjectReadOperation op;
881 ::cls_user_get_header(op, header, &rc);
882 return rados_obj.operate(dpp, &op, &ibl, y);
883 }
884
885 int RGWSI_User_RADOS::cls_user_get_header_async(const DoutPrefixProvider *dpp, const string& user_str, RGWGetUserHeader_CB *cb)
886 {
887 rgw_raw_obj obj = get_buckets_obj(rgw_user(user_str));
888 auto rados_obj = svc.rados->obj(obj);
889 int r = rados_obj.open(dpp);
890 if (r < 0) {
891 return r;
892 }
893
894 auto& ref = rados_obj.get_ref();
895
896 r = ::cls_user_get_header_async(ref.pool.ioctx(), ref.obj.oid, cb);
897 if (r < 0) {
898 return r;
899 }
900
901 return 0;
902 }
903
904 int RGWSI_User_RADOS::read_stats(const DoutPrefixProvider *dpp,
905 RGWSI_MetaBackend::Context *ctx,
906 const rgw_user& user, RGWStorageStats *stats,
907 ceph::real_time *last_stats_sync,
908 ceph::real_time *last_stats_update,
909 optional_yield y)
910 {
911 string user_str = user.to_str();
912
913 RGWUserInfo info;
914 real_time mtime;
915 int ret = read_user_info(ctx, user, &info, nullptr, &mtime, nullptr, nullptr, null_yield, dpp);
916 if (ret < 0)
917 {
918 return ret;
919 }
920
921 cls_user_header header;
922 int r = cls_user_get_header(dpp, rgw_user(user_str), &header, y);
923 if (r < 0 && r != -ENOENT)
924 return r;
925
926 const cls_user_stats& hs = header.stats;
927
928 stats->size = hs.total_bytes;
929 stats->size_rounded = hs.total_bytes_rounded;
930 stats->num_objects = hs.total_entries;
931
932 if (last_stats_sync) {
933 *last_stats_sync = header.last_stats_sync;
934 }
935
936 if (last_stats_update) {
937 *last_stats_update = header.last_stats_update;
938 }
939
940 return 0;
941 }
942
943 class RGWGetUserStatsContext : public RGWGetUserHeader_CB {
944 RGWGetUserStats_CB *cb;
945
946 public:
947 explicit RGWGetUserStatsContext(RGWGetUserStats_CB * const cb)
948 : cb(cb) {}
949
950 void handle_response(int r, cls_user_header& header) override {
951 const cls_user_stats& hs = header.stats;
952 if (r >= 0) {
953 RGWStorageStats stats;
954
955 stats.size = hs.total_bytes;
956 stats.size_rounded = hs.total_bytes_rounded;
957 stats.num_objects = hs.total_entries;
958
959 cb->set_response(stats);
960 }
961
962 cb->handle_response(r);
963
964 cb->put();
965 }
966 };
967
968 int RGWSI_User_RADOS::read_stats_async(const DoutPrefixProvider *dpp, RGWSI_MetaBackend::Context *ctx,
969 const rgw_user& user, RGWGetUserStats_CB *_cb)
970 {
971 string user_str = user.to_str();
972
973 RGWGetUserStatsContext *cb = new RGWGetUserStatsContext(_cb);
974 int r = cls_user_get_header_async(dpp, user_str, cb);
975 if (r < 0) {
976 _cb->put();
977 delete cb;
978 return r;
979 }
980
981 return 0;
982 }
983