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