]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/services/svc_user_rados.cc
import quincy beta 17.1.0
[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
20effc67
TL
27using namespace std;
28
9f95a23c
TL
29class RGWSI_User_Module : public RGWSI_MBSObj_Handler_Module {
30 RGWSI_User_RADOS::Svc& svc;
31
32 const string prefix;
33public:
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
64RGWSI_User_RADOS::RGWSI_User_RADOS(CephContext *cct): RGWSI_User(cct) {
65}
66
67RGWSI_User_RADOS::~RGWSI_User_RADOS() {
68}
69
70void 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
b3b6e05e 86int RGWSI_User_RADOS::do_start(optional_yield, const DoutPrefixProvider *dpp)
9f95a23c
TL
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) {
b3b6e05e 93 ldpp_dout(dpp, 0) << "ERROR: failed to create be handler: r=" << r << dendl;
9f95a23c
TL
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
105rgw_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
111int 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,
b3b6e05e
TL
118 optional_yield y,
119 const DoutPrefixProvider *dpp)
9f95a23c 120{
e306af50 121 if(user.id == RGW_USER_ANON_ID) {
b3b6e05e 122 ldpp_dout(dpp, 20) << "RGWSI_User_RADOS::read_user_info(): anonymous user" << dendl;
e306af50
TL
123 return -ENOENT;
124 }
9f95a23c
TL
125 bufferlist bl;
126 RGWUID user_id;
127
128 RGWSI_MBSObj_GetParams params(&bl, pattrs, pmtime);
129 params.set_cache_info(cache_info);
130
b3b6e05e 131 int ret = svc.meta_be->get_entry(ctx, get_meta_key(user), params, objv_tracker, y, dpp);
9f95a23c
TL
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) {
b3b6e05e 140 ldpp_dout(dpp, -1) << "ERROR: rgw_get_user_info_by_uid(): user id mismatch: " << user_id.user_id << " != " << user << dendl;
9f95a23c
TL
141 return -EIO;
142 }
143 if (!iter.end()) {
144 decode(*info, iter);
145 }
146 } catch (buffer::error& err) {
b3b6e05e 147 ldpp_dout(dpp, 0) << "ERROR: failed to decode user info, caught buffer::error" << dendl;
9f95a23c
TL
148 return -EIO;
149 }
150
151 return 0;
152}
153
154class 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
175public:
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
b3b6e05e 192 int prepare(const DoutPrefixProvider *dpp) {
9f95a23c
TL
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;
b3b6e05e 212 int r = svc.user->get_user_info_by_swift(ctx, k.id, &inf, nullptr, nullptr, y, dpp);
9f95a23c
TL
213 if (r >= 0 && inf.user_id != info.user_id &&
214 (!old_info || inf.user_id != old_info->user_id)) {
b3b6e05e 215 ldpp_dout(dpp, 0) << "WARNING: can't store user info, swift id (" << k.id
9f95a23c
TL
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;
b3b6e05e 227 int r = svc.user->get_user_info_by_access_key(ctx, k.id, &inf, nullptr, nullptr, y, dpp);
9f95a23c
TL
228 if (r >= 0 && inf.user_id != info.user_id &&
229 (!old_info || inf.user_id != old_info->user_id)) {
b3b6e05e 230 ldpp_dout(dpp, 0) << "WARNING: can't store user info, access key already mapped to another user" << dendl;
9f95a23c
TL
231 return -EEXIST;
232 }
233 }
234
235 return 0;
236 }
237
b3b6e05e 238 int put(const DoutPrefixProvider *dpp) {
9f95a23c
TL
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
b3b6e05e 245 int ret = svc.meta_be->put(ctx, RGWSI_User::get_meta_key(info.user_id), params, &ot, y, dpp);
9f95a23c
TL
246 if (ret < 0)
247 return ret;
248
249 return 0;
250 }
251
b3b6e05e 252 int complete(const DoutPrefixProvider *dpp) {
9f95a23c
TL
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 */
b3b6e05e 263 ret = rgw_put_system_obj(dpp, obj_ctx, svc.zone->get_zone_params().user_email_pool, info.user_email,
9f95a23c
TL
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
b3b6e05e 276 ret = rgw_put_system_obj(dpp, obj_ctx, svc.zone->get_zone_params().user_keys_pool, k.id,
9f95a23c
TL
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
b3b6e05e 287 ret = rgw_put_system_obj(dpp, obj_ctx, svc.zone->get_zone_params().user_swift_pool, k.id,
9f95a23c
TL
288 link_bl, exclusive, NULL, real_time(), y);
289 if (ret < 0)
290 return ret;
291 }
292
293 if (old_info) {
b3b6e05e 294 ret = remove_old_indexes(*old_info, info, y, dpp);
9f95a23c
TL
295 if (ret < 0) {
296 return ret;
297 }
298 }
299
300 return 0;
301 }
302
b3b6e05e 303 int remove_old_indexes(const RGWUserInfo& old_info, const RGWUserInfo& new_info, optional_yield y, const DoutPrefixProvider *dpp) {
9f95a23c
TL
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) {
b3b6e05e 309 ldpp_dout(dpp, 0) << "ERROR: tenant mismatch: " << old_info.user_id.tenant << " != " << new_info.user_id.tenant << dendl;
9f95a23c
TL
310 return -EINVAL;
311 }
b3b6e05e 312 ret = svc.user->remove_uid_index(ctx, old_info, nullptr, y, dpp);
9f95a23c
TL
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) {
b3b6e05e 321 ret = svc.user->remove_email_index(dpp, ctx, old_info.user_email, y);
9f95a23c
TL
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)) {
b3b6e05e 330 ret = svc.user->remove_key_index(dpp, ctx, access_key, y);
9f95a23c
TL
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()) {
b3b6e05e 342 ret = svc.user->remove_swift_name_index(dpp, ctx, swift_key.id, y);
9f95a23c
TL
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
358int 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,
b3b6e05e
TL
365 optional_yield y,
366 const DoutPrefixProvider *dpp)
9f95a23c
TL
367{
368 PutOperation op(svc, ctx,
369 info, old_info,
370 objv_tracker,
371 mtime, exclusive,
372 attrs,
373 y);
374
b3b6e05e 375 int r = op.prepare(dpp);
9f95a23c
TL
376 if (r < 0) {
377 return r;
378 }
379
b3b6e05e 380 r = op.put(dpp);
9f95a23c
TL
381 if (r < 0) {
382 return r;
383 }
384
b3b6e05e 385 r = op.complete(dpp);
9f95a23c
TL
386 if (r < 0) {
387 return r;
388 }
389
390 return 0;
391}
392
b3b6e05e
TL
393int RGWSI_User_RADOS::remove_key_index(const DoutPrefixProvider *dpp,
394 RGWSI_MetaBackend::Context *_ctx,
9f95a23c
TL
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);
b3b6e05e 401 return sysobj.wop().remove(dpp, y);
9f95a23c
TL
402}
403
b3b6e05e
TL
404int RGWSI_User_RADOS::remove_email_index(const DoutPrefixProvider *dpp,
405 RGWSI_MetaBackend::Context *_ctx,
9f95a23c
TL
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);
b3b6e05e 415 return sysobj.wop().remove(dpp, y);
9f95a23c
TL
416}
417
b3b6e05e 418int RGWSI_User_RADOS::remove_swift_name_index(const DoutPrefixProvider *dpp, RGWSI_MetaBackend::Context *_ctx, const string& swift_name,
9f95a23c
TL
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);
b3b6e05e 424 return sysobj.wop().remove(dpp, y);
9f95a23c
TL
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 */
433int RGWSI_User_RADOS::remove_user_info(RGWSI_MetaBackend::Context *_ctx,
434 const RGWUserInfo& info,
435 RGWObjVersionTracker *objv_tracker,
b3b6e05e
TL
436 optional_yield y,
437 const DoutPrefixProvider *dpp)
9f95a23c
TL
438{
439 int ret;
440
9f95a23c
TL
441 auto kiter = info.access_keys.begin();
442 for (; kiter != info.access_keys.end(); ++kiter) {
b3b6e05e
TL
443 ldpp_dout(dpp, 10) << "removing key index: " << kiter->first << dendl;
444 ret = remove_key_index(dpp, _ctx, kiter->second, y);
9f95a23c 445 if (ret < 0 && ret != -ENOENT) {
b3b6e05e 446 ldpp_dout(dpp, 0) << "ERROR: could not remove " << kiter->first << " (access key object), should be fixed (err=" << ret << ")" << dendl;
9f95a23c
TL
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;
b3b6e05e 454 ldpp_dout(dpp, 10) << "removing swift subuser index: " << k.id << dendl;
9f95a23c 455 /* check if swift mapping exists */
b3b6e05e 456 ret = remove_swift_name_index(dpp, _ctx, k.id, y);
9f95a23c 457 if (ret < 0 && ret != -ENOENT) {
b3b6e05e 458 ldpp_dout(dpp, 0) << "ERROR: could not remove " << k.id << " (swift name object), should be fixed (err=" << ret << ")" << dendl;
9f95a23c
TL
459 return ret;
460 }
461 }
462
b3b6e05e
TL
463 ldpp_dout(dpp, 10) << "removing email index: " << info.user_email << dendl;
464 ret = remove_email_index(dpp, _ctx, info.user_email, y);
9f95a23c 465 if (ret < 0 && ret != -ENOENT) {
b3b6e05e 466 ldpp_dout(dpp, 0) << "ERROR: could not remove email index object for "
9f95a23c
TL
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);
b3b6e05e 472 ldpp_dout(dpp, 10) << "removing user buckets index" << dendl;
9f95a23c
TL
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);
b3b6e05e 475 ret = sysobj.wop().remove(dpp, y);
9f95a23c 476 if (ret < 0 && ret != -ENOENT) {
b3b6e05e 477 ldpp_dout(dpp, 0) << "ERROR: could not remove " << info.user_id << ":" << uid_bucks << ", should be fixed (err=" << ret << ")" << dendl;
9f95a23c
TL
478 return ret;
479 }
480
b3b6e05e 481 ret = remove_uid_index(ctx, info, objv_tracker, y, dpp);
9f95a23c
TL
482 if (ret < 0 && ret != -ENOENT) {
483 return ret;
484 }
485
486 return 0;
487}
488
489int RGWSI_User_RADOS::remove_uid_index(RGWSI_MetaBackend::Context *ctx, const RGWUserInfo& user_info, RGWObjVersionTracker *objv_tracker,
b3b6e05e 490 optional_yield y, const DoutPrefixProvider *dpp)
9f95a23c 491{
b3b6e05e 492 ldpp_dout(dpp, 10) << "removing user index: " << user_info.user_id << dendl;
9f95a23c
TL
493
494 RGWSI_MBSObj_RemoveParams params;
b3b6e05e 495 int ret = svc.meta_be->remove(ctx, get_meta_key(user_info.user_id), params, objv_tracker, y, dpp);
9f95a23c
TL
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);
b3b6e05e 500 ldpp_dout(dpp, 0) << "ERROR: could not remove " << user_info.user_id << ":" << uid_obj << ", should be fixed (err=" << ret << ")" << dendl;
9f95a23c
TL
501 return ret;
502 }
503
504 return 0;
505}
506
507int 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,
b3b6e05e 512 real_time * const pmtime, optional_yield y, const DoutPrefixProvider *dpp)
9f95a23c
TL
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
b3b6e05e 531 int ret = rgw_get_system_obj(*ctx->obj_ctx, pool, key, bl, nullptr, &e.mtime, y, dpp);
9f95a23c
TL
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,
b3b6e05e 543 y, dpp);
9f95a23c
TL
544 if (ret < 0) {
545 return ret;
546 }
547 } catch (buffer::error& err) {
b3b6e05e 548 ldpp_dout(dpp, 0) << "ERROR: failed to decode user info, caught buffer::error" << dendl;
9f95a23c
TL
549 return -EIO;
550 }
551
b3b6e05e 552 uinfo_cache->put(dpp, svc.cache, cache_key, &e, { &cache_info });
9f95a23c
TL
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 */
567int RGWSI_User_RADOS::get_user_info_by_email(RGWSI_MetaBackend::Context *ctx,
568 const string& email, RGWUserInfo *info,
569 RGWObjVersionTracker *objv_tracker,
b3b6e05e
TL
570 real_time *pmtime, optional_yield y,
571 const DoutPrefixProvider *dpp)
9f95a23c
TL
572{
573 return get_user_info_from_index(ctx, email, svc.zone->get_zone_params().user_email_pool,
b3b6e05e 574 info, objv_tracker, pmtime, y, dpp);
9f95a23c
TL
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 */
581int 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,
b3b6e05e
TL
585 real_time * const pmtime, optional_yield y,
586 const DoutPrefixProvider *dpp)
9f95a23c
TL
587{
588 return get_user_info_from_index(ctx,
589 swift_name,
590 svc.zone->get_zone_params().user_swift_pool,
b3b6e05e 591 info, objv_tracker, pmtime, y, dpp);
9f95a23c
TL
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 */
598int 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,
b3b6e05e
TL
602 real_time *pmtime, optional_yield y,
603 const DoutPrefixProvider *dpp)
9f95a23c
TL
604{
605 return get_user_info_from_index(ctx,
606 access_key,
607 svc.zone->get_zone_params().user_keys_pool,
b3b6e05e 608 info, objv_tracker, pmtime, y, dpp);
9f95a23c
TL
609}
610
b3b6e05e 611int 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)
9f95a23c
TL
612{
613 auto rados_obj = svc.rados->obj(obj);
b3b6e05e 614 int r = rados_obj.open(dpp);
9f95a23c
TL
615 if (r < 0) {
616 return r;
617 }
618
619 librados::ObjectWriteOperation op;
620 cls_user_set_buckets(op, entries, add);
b3b6e05e 621 r = rados_obj.operate(dpp, &op, y);
9f95a23c
TL
622 if (r < 0) {
623 return r;
624 }
625
626 return 0;
627}
628
b3b6e05e 629int RGWSI_User_RADOS::cls_user_add_bucket(const DoutPrefixProvider *dpp, rgw_raw_obj& obj, const cls_user_bucket_entry& entry, optional_yield y)
9f95a23c
TL
630{
631 list<cls_user_bucket_entry> l;
632 l.push_back(entry);
633
b3b6e05e 634 return cls_user_update_buckets(dpp, obj, l, true, y);
9f95a23c
TL
635}
636
b3b6e05e 637int RGWSI_User_RADOS::cls_user_remove_bucket(const DoutPrefixProvider *dpp, rgw_raw_obj& obj, const cls_user_bucket& bucket, optional_yield y)
9f95a23c
TL
638{
639 auto rados_obj = svc.rados->obj(obj);
b3b6e05e 640 int r = rados_obj.open(dpp);
9f95a23c
TL
641 if (r < 0) {
642 return r;
643 }
644
645 librados::ObjectWriteOperation op;
646 ::cls_user_remove_bucket(op, bucket);
b3b6e05e 647 r = rados_obj.operate(dpp, &op, y);
9f95a23c
TL
648 if (r < 0)
649 return r;
650
651 return 0;
652}
653
b3b6e05e
TL
654int RGWSI_User_RADOS::add_bucket(const DoutPrefixProvider *dpp,
655 RGWSI_MetaBackend::Context *ctx,
9f95a23c
TL
656 const rgw_user& user,
657 const rgw_bucket& bucket,
f67539c2
TL
658 ceph::real_time creation_time,
659 optional_yield y)
9f95a23c
TL
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);
b3b6e05e 673 ret = cls_user_add_bucket(dpp, obj, new_bucket, y);
9f95a23c 674 if (ret < 0) {
b3b6e05e 675 ldpp_dout(dpp, 0) << "ERROR: error adding bucket to user: ret=" << ret << dendl;
9f95a23c
TL
676 return ret;
677 }
678
679 return 0;
680}
681
682
b3b6e05e
TL
683int RGWSI_User_RADOS::remove_bucket(const DoutPrefixProvider *dpp,
684 RGWSI_MetaBackend::Context *ctx,
9f95a23c 685 const rgw_user& user,
f67539c2
TL
686 const rgw_bucket& _bucket,
687 optional_yield y)
9f95a23c
TL
688{
689 cls_user_bucket bucket;
690 bucket.name = _bucket.name;
691 rgw_raw_obj obj = get_buckets_obj(user);
b3b6e05e 692 int ret = cls_user_remove_bucket(dpp, obj, bucket, y);
9f95a23c 693 if (ret < 0) {
b3b6e05e 694 ldpp_dout(dpp, 0) << "ERROR: error removing bucket from user: ret=" << ret << dendl;
9f95a23c
TL
695 }
696
697 return 0;
698}
699
b3b6e05e
TL
700int RGWSI_User_RADOS::cls_user_flush_bucket_stats(const DoutPrefixProvider *dpp,
701 rgw_raw_obj& user_obj,
f67539c2 702 const RGWBucketEnt& ent, optional_yield y)
9f95a23c
TL
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
b3b6e05e 710 int r = cls_user_update_buckets(dpp, user_obj, entries, false, y);
9f95a23c 711 if (r < 0) {
b3b6e05e 712 ldpp_dout(dpp, 20) << "cls_user_update_buckets() returned " << r << dendl;
9f95a23c
TL
713 return r;
714 }
715
716 return 0;
717}
718
b3b6e05e
TL
719int RGWSI_User_RADOS::cls_user_list_buckets(const DoutPrefixProvider *dpp,
720 rgw_raw_obj& obj,
9f95a23c
TL
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,
f67539c2
TL
726 bool * const truncated,
727 optional_yield y)
9f95a23c
TL
728{
729 auto rados_obj = svc.rados->obj(obj);
b3b6e05e 730 int r = rados_obj.open(dpp);
9f95a23c
TL
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;
b3b6e05e 740 r = rados_obj.operate(dpp, &op, &ibl, y);
9f95a23c
TL
741 if (r < 0)
742 return r;
743 if (rc < 0)
744 return rc;
745
746 return 0;
747}
748
b3b6e05e
TL
749int RGWSI_User_RADOS::list_buckets(const DoutPrefixProvider *dpp,
750 RGWSI_MetaBackend::Context *ctx,
f67539c2
TL
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)
9f95a23c
TL
757{
758 int ret;
759
760 buckets->clear();
e306af50 761 if (user.id == RGW_USER_ANON_ID) {
b3b6e05e 762 ldpp_dout(dpp, 20) << "RGWSI_User_RADOS::list_buckets(): anonymous user" << dendl;
e306af50
TL
763 *is_truncated = false;
764 return 0;
f67539c2 765 }
9f95a23c
TL
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;
b3b6e05e 775 ret = cls_user_list_buckets(dpp, obj, m, end_marker, max - total, entries, &m, &truncated, y);
9f95a23c
TL
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
b3b6e05e
TL
798int RGWSI_User_RADOS::flush_bucket_stats(const DoutPrefixProvider *dpp,
799 RGWSI_MetaBackend::Context *ctx,
9f95a23c 800 const rgw_user& user,
f67539c2
TL
801 const RGWBucketEnt& ent,
802 optional_yield y)
9f95a23c
TL
803{
804 rgw_raw_obj obj = get_buckets_obj(user);
805
b3b6e05e 806 return cls_user_flush_bucket_stats(dpp, obj, ent, y);
9f95a23c
TL
807}
808
b3b6e05e
TL
809int RGWSI_User_RADOS::reset_bucket_stats(const DoutPrefixProvider *dpp,
810 RGWSI_MetaBackend::Context *ctx,
f67539c2
TL
811 const rgw_user& user,
812 optional_yield y)
9f95a23c 813{
b3b6e05e 814 return cls_user_reset_stats(dpp, user, y);
9f95a23c
TL
815}
816
b3b6e05e 817int RGWSI_User_RADOS::cls_user_reset_stats(const DoutPrefixProvider *dpp, const rgw_user& user, optional_yield y)
9f95a23c
TL
818{
819 rgw_raw_obj obj = get_buckets_obj(user);
820 auto rados_obj = svc.rados->obj(obj);
b3b6e05e 821 int rval, r = rados_obj.open(dpp);
9f95a23c
TL
822 if (r < 0) {
823 return r;
824 }
f6b5b4d7
TL
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);
b3b6e05e 838 r = rados_obj.operate(dpp, &op, y, librados::OPERATION_RETURNVEC);
f6b5b4d7
TL
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;
9f95a23c
TL
851}
852
b3b6e05e
TL
853int RGWSI_User_RADOS::complete_flush_stats(const DoutPrefixProvider *dpp,
854 RGWSI_MetaBackend::Context *ctx,
f67539c2 855 const rgw_user& user, optional_yield y)
9f95a23c
TL
856{
857 rgw_raw_obj obj = get_buckets_obj(user);
858 auto rados_obj = svc.rados->obj(obj);
b3b6e05e 859 int r = rados_obj.open(dpp);
9f95a23c
TL
860 if (r < 0) {
861 return r;
862 }
863 librados::ObjectWriteOperation op;
864 ::cls_user_complete_stats_sync(op);
b3b6e05e 865 return rados_obj.operate(dpp, &op, y);
9f95a23c
TL
866}
867
b3b6e05e
TL
868int RGWSI_User_RADOS::cls_user_get_header(const DoutPrefixProvider *dpp,
869 const rgw_user& user, cls_user_header *header,
f67539c2 870 optional_yield y)
9f95a23c
TL
871{
872 rgw_raw_obj obj = get_buckets_obj(user);
873 auto rados_obj = svc.rados->obj(obj);
b3b6e05e 874 int r = rados_obj.open(dpp);
9f95a23c
TL
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);
b3b6e05e 882 return rados_obj.operate(dpp, &op, &ibl, y);
9f95a23c
TL
883}
884
b3b6e05e 885int RGWSI_User_RADOS::cls_user_get_header_async(const DoutPrefixProvider *dpp, const string& user_str, RGWGetUserHeader_CB *cb)
9f95a23c
TL
886{
887 rgw_raw_obj obj = get_buckets_obj(rgw_user(user_str));
888 auto rados_obj = svc.rados->obj(obj);
b3b6e05e 889 int r = rados_obj.open(dpp);
9f95a23c
TL
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
b3b6e05e
TL
904int RGWSI_User_RADOS::read_stats(const DoutPrefixProvider *dpp,
905 RGWSI_MetaBackend::Context *ctx,
9f95a23c
TL
906 const rgw_user& user, RGWStorageStats *stats,
907 ceph::real_time *last_stats_sync,
f67539c2
TL
908 ceph::real_time *last_stats_update,
909 optional_yield y)
9f95a23c
TL
910{
911 string user_str = user.to_str();
912
20effc67
TL
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
9f95a23c 921 cls_user_header header;
b3b6e05e 922 int r = cls_user_get_header(dpp, rgw_user(user_str), &header, y);
20effc67 923 if (r < 0 && r != -ENOENT)
9f95a23c
TL
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
943class RGWGetUserStatsContext : public RGWGetUserHeader_CB {
944 RGWGetUserStats_CB *cb;
945
946public:
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
b3b6e05e 968int RGWSI_User_RADOS::read_stats_async(const DoutPrefixProvider *dpp, RGWSI_MetaBackend::Context *ctx,
9f95a23c
TL
969 const rgw_user& user, RGWGetUserStats_CB *_cb)
970{
971 string user_str = user.to_str();
972
973 RGWGetUserStatsContext *cb = new RGWGetUserStatsContext(_cb);
b3b6e05e 974 int r = cls_user_get_header_async(dpp, user_str, cb);
9f95a23c
TL
975 if (r < 0) {
976 _cb->put();
977 delete cb;
978 return r;
979 }
980
981 return 0;
982}
983