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