]>
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 | ||
20effc67 TL |
27 | using namespace std; |
28 | ||
9f95a23c TL |
29 | class RGWSI_User_Module : public RGWSI_MBSObj_Handler_Module { |
30 | RGWSI_User_RADOS::Svc& svc; | |
31 | ||
32 | const string prefix; | |
33 | public: | |
34 | RGWSI_User_Module(RGWSI_User_RADOS::Svc& _svc) : RGWSI_MBSObj_Handler_Module("user"), | |
35 | svc(_svc) {} | |
36 | ||
37 | void get_pool_and_oid(const string& key, rgw_pool *pool, string *oid) override { | |
38 | if (pool) { | |
39 | *pool = svc.zone->get_zone_params().user_uid_pool; | |
40 | } | |
41 | if (oid) { | |
42 | *oid = key; | |
43 | } | |
44 | } | |
45 | ||
46 | const string& get_oid_prefix() override { | |
47 | return prefix; | |
48 | } | |
49 | ||
50 | bool is_valid_oid(const string& oid) override { | |
51 | // filter out the user.buckets objects | |
52 | return !boost::algorithm::ends_with(oid, RGW_BUCKETS_OBJ_SUFFIX); | |
53 | } | |
54 | ||
55 | string key_to_oid(const string& key) override { | |
56 | return key; | |
57 | } | |
58 | ||
59 | string oid_to_key(const string& oid) override { | |
60 | return oid; | |
61 | } | |
62 | }; | |
63 | ||
64 | RGWSI_User_RADOS::RGWSI_User_RADOS(CephContext *cct): RGWSI_User(cct) { | |
65 | } | |
66 | ||
67 | RGWSI_User_RADOS::~RGWSI_User_RADOS() { | |
68 | } | |
69 | ||
70 | void RGWSI_User_RADOS::init(RGWSI_RADOS *_rados_svc, | |
71 | RGWSI_Zone *_zone_svc, RGWSI_SysObj *_sysobj_svc, | |
72 | RGWSI_SysObj_Cache *_cache_svc, RGWSI_Meta *_meta_svc, | |
73 | RGWSI_MetaBackend *_meta_be_svc, | |
74 | RGWSI_SyncModules *_sync_modules_svc) | |
75 | { | |
76 | svc.user = this; | |
77 | svc.rados = _rados_svc; | |
78 | svc.zone = _zone_svc; | |
79 | svc.sysobj = _sysobj_svc; | |
80 | svc.cache = _cache_svc; | |
81 | svc.meta = _meta_svc; | |
82 | svc.meta_be = _meta_be_svc; | |
83 | svc.sync_modules = _sync_modules_svc; | |
84 | } | |
85 | ||
b3b6e05e | 86 | int 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 | ||
105 | rgw_raw_obj RGWSI_User_RADOS::get_buckets_obj(const rgw_user& user) const | |
106 | { | |
107 | string oid = user.to_str() + RGW_BUCKETS_OBJ_SUFFIX; | |
108 | return rgw_raw_obj(svc.zone->get_zone_params().user_uid_pool, oid); | |
109 | } | |
110 | ||
111 | int RGWSI_User_RADOS::read_user_info(RGWSI_MetaBackend::Context *ctx, | |
112 | const rgw_user& user, | |
113 | RGWUserInfo *info, | |
114 | RGWObjVersionTracker * const objv_tracker, | |
115 | real_time * const pmtime, | |
116 | rgw_cache_entry_info * const cache_info, | |
117 | map<string, bufferlist> * const pattrs, | |
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 | ||
154 | class PutOperation | |
155 | { | |
156 | RGWSI_User_RADOS::Svc& svc; | |
157 | RGWSI_MetaBackend_SObj::Context_SObj *ctx; | |
158 | RGWUID ui; | |
159 | const RGWUserInfo& info; | |
160 | RGWUserInfo *old_info; | |
161 | RGWObjVersionTracker *objv_tracker; | |
162 | const real_time& mtime; | |
163 | bool exclusive; | |
164 | map<string, bufferlist> *pattrs; | |
165 | RGWObjVersionTracker ot; | |
166 | string err_msg; | |
167 | optional_yield y; | |
168 | ||
169 | void set_err_msg(string msg) { | |
170 | if (!err_msg.empty()) { | |
171 | err_msg = std::move(msg); | |
172 | } | |
173 | } | |
174 | ||
175 | public: | |
176 | PutOperation(RGWSI_User_RADOS::Svc& svc, | |
177 | RGWSI_MetaBackend::Context *_ctx, | |
178 | const RGWUserInfo& info, | |
179 | RGWUserInfo *old_info, | |
180 | RGWObjVersionTracker *objv_tracker, | |
181 | const real_time& mtime, | |
182 | bool exclusive, | |
183 | map<string, bufferlist> *pattrs, | |
184 | optional_yield y) : | |
185 | svc(svc), info(info), old_info(old_info), | |
186 | objv_tracker(objv_tracker), mtime(mtime), | |
187 | exclusive(exclusive), pattrs(pattrs), y(y) { | |
188 | ctx = static_cast<RGWSI_MetaBackend_SObj::Context_SObj *>(_ctx); | |
189 | ui.user_id = info.user_id; | |
190 | } | |
191 | ||
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 | ||
358 | int RGWSI_User_RADOS::store_user_info(RGWSI_MetaBackend::Context *ctx, | |
359 | const RGWUserInfo& info, | |
360 | RGWUserInfo *old_info, | |
361 | RGWObjVersionTracker *objv_tracker, | |
362 | const real_time& mtime, | |
363 | bool exclusive, | |
364 | map<string, bufferlist> *attrs, | |
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 |
393 | int 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 |
404 | int 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 | 418 | int 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 | */ | |
433 | int 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 | ||
489 | int 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 | ||
507 | int RGWSI_User_RADOS::get_user_info_from_index(RGWSI_MetaBackend::Context *_ctx, | |
508 | const string& key, | |
509 | const rgw_pool& pool, | |
510 | RGWUserInfo *info, | |
511 | RGWObjVersionTracker * const objv_tracker, | |
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 | */ | |
567 | int 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 | */ | |
581 | int RGWSI_User_RADOS::get_user_info_by_swift(RGWSI_MetaBackend::Context *ctx, | |
582 | const string& swift_name, | |
583 | RGWUserInfo *info, /* out */ | |
584 | RGWObjVersionTracker * const objv_tracker, | |
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 | */ | |
598 | int RGWSI_User_RADOS::get_user_info_by_access_key(RGWSI_MetaBackend::Context *ctx, | |
599 | const std::string& access_key, | |
600 | RGWUserInfo *info, | |
601 | RGWObjVersionTracker* objv_tracker, | |
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 | 611 | int RGWSI_User_RADOS::cls_user_update_buckets(const DoutPrefixProvider *dpp, rgw_raw_obj& obj, list<cls_user_bucket_entry>& entries, bool add, optional_yield y) |
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 | 629 | int RGWSI_User_RADOS::cls_user_add_bucket(const DoutPrefixProvider *dpp, rgw_raw_obj& obj, const cls_user_bucket_entry& entry, optional_yield y) |
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 | 637 | int 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 |
654 | int 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 |
683 | int 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 |
700 | int 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 |
719 | int 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 |
749 | int 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 |
798 | int 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 |
809 | int 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 | 817 | int 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 |
853 | int 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 |
868 | int 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 | 885 | int 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 |
904 | int 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 | ||
943 | class RGWGetUserStatsContext : public RGWGetUserHeader_CB { | |
944 | RGWGetUserStats_CB *cb; | |
945 | ||
946 | public: | |
947 | explicit RGWGetUserStatsContext(RGWGetUserStats_CB * const cb) | |
948 | : cb(cb) {} | |
949 | ||
950 | void handle_response(int r, cls_user_header& header) override { | |
951 | const cls_user_stats& hs = header.stats; | |
952 | if (r >= 0) { | |
953 | RGWStorageStats stats; | |
954 | ||
955 | stats.size = hs.total_bytes; | |
956 | stats.size_rounded = hs.total_bytes_rounded; | |
957 | stats.num_objects = hs.total_entries; | |
958 | ||
959 | cb->set_response(stats); | |
960 | } | |
961 | ||
962 | cb->handle_response(r); | |
963 | ||
964 | cb->put(); | |
965 | } | |
966 | }; | |
967 | ||
b3b6e05e | 968 | int 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 |