]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | ||
f67539c2 | 84 | int 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 | ||
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 | { | |
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 | ||
151 | class 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 | ||
172 | public: | |
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 | ||
355 | int 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 | ||
389 | int 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 | ||
399 | int 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 | ||
412 | int 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 | */ | |
427 | int 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 | ||
484 | int 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 | ||
502 | int 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 | */ | |
562 | int 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 | */ | |
575 | int 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 | */ | |
591 | int 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 | 603 | int 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 | 621 | int 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 | 629 | int 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 | ||
646 | int 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 | ||
674 | int 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 | ||
690 | int 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 | ||
708 | int 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 | ||
737 | int 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 | ||
785 | int 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 | ||
795 | int 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 | 802 | int 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 | ||
838 | int 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 |
852 | int 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 | ||
868 | int 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 | ||
887 | int 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 | ||
917 | class RGWGetUserStatsContext : public RGWGetUserHeader_CB { | |
918 | RGWGetUserStats_CB *cb; | |
919 | ||
920 | public: | |
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 | ||
942 | int 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 |