From 22c19222c484a0b8dfc157418790ab72c3d58b12 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Sun, 17 Dec 2023 22:49:20 -0500 Subject: [PATCH] rgw/rados: add rgwrados::users namespace abstraction for cls_user Signed-off-by: Casey Bodley --- src/rgw/CMakeLists.txt | 3 +- src/rgw/driver/rados/account.cc | 64 ++++++++++ src/rgw/driver/rados/account.h | 14 +++ src/rgw/driver/rados/users.cc | 174 ++++++++++++++++++++++++++++ src/rgw/driver/rados/users.h | 87 ++++++++++++++ src/tools/ceph-dencoder/rgw_types.h | 3 + 6 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 src/rgw/driver/rados/users.cc create mode 100644 src/rgw/driver/rados/users.h diff --git a/src/rgw/CMakeLists.txt b/src/rgw/CMakeLists.txt index 1ddddb00c23..84a5bc9e56c 100644 --- a/src/rgw/CMakeLists.txt +++ b/src/rgw/CMakeLists.txt @@ -199,7 +199,8 @@ set(librgw_common_srcs driver/rados/rgw_zone.cc driver/rados/sync_fairness.cc driver/rados/topic.cc - driver/rados/topic_migration.cc) + driver/rados/topic_migration.cc + driver/rados/users.cc) list(APPEND librgw_common_srcs driver/immutable_config/store.cc diff --git a/src/rgw/driver/rados/account.cc b/src/rgw/driver/rados/account.cc index f7c86099eee..b018ee3e370 100644 --- a/src/rgw/driver/rados/account.cc +++ b/src/rgw/driver/rados/account.cc @@ -16,6 +16,8 @@ #include "account.h" #include +#include "include/rados/librados.hpp" +#include "cls/user/cls_user_types.h" #include "common/errno.h" #include "rgw_account.h" #include "rgw_common.h" @@ -31,6 +33,7 @@ namespace rgwrados::account { static constexpr std::string_view buckets_oid_prefix = "buckets."; +static constexpr std::string_view users_oid_prefix = "users."; static const std::string account_oid_prefix = "account."; static constexpr std::string_view name_oid_prefix = "name."; @@ -43,6 +46,14 @@ rgw_raw_obj get_buckets_obj(const RGWZoneParams& zone, return {zone.account_pool, get_buckets_key(account_id)}; } +static std::string get_users_key(std::string_view account_id) { + return string_cat_reserve(users_oid_prefix, account_id); +} +rgw_raw_obj get_users_obj(const RGWZoneParams& zone, + std::string_view account_id) { + return {zone.account_pool, get_users_key(account_id)}; +} + static std::string get_account_key(std::string_view account_id) { return string_cat_reserve(account_oid_prefix, account_id); } @@ -386,7 +397,60 @@ int remove(const DoutPrefixProvider* dpp, << obj << " with: " << cpp_strerror(r) << dendl; } // not fatal } + { + // remove the users object + const rgw_raw_obj obj = get_users_obj(zone, info.id); + r = rgw_delete_system_obj(dpp, &sysobj, obj.pool, obj.oid, nullptr, y); + if (r < 0) { + ldpp_dout(dpp, 20) << "WARNING: failed to remove users obj " + << obj << " with: " << cpp_strerror(r) << dendl; + } // not fatal + } + + return 0; +} + +// read the resource count from cls_user_account_header +int resource_count(const DoutPrefixProvider* dpp, + optional_yield y, + librados::Rados& rados, + const rgw_raw_obj& obj, + uint32_t& count) +{ + rgw_rados_ref ref; + int r = rgw_get_rados_ref(dpp, &rados, obj, &ref); + if (r < 0) { + return r; + } + + librados::ObjectReadOperation op; + bufferlist bl; + int ret = 0; + op.omap_get_header(&bl, &ret); + + r = ref.operate(dpp, &op, nullptr, y); + if (r == -ENOENT) { // doesn't exist yet + count = 0; + return 0; + } + if (r < 0) { + return r; + } + + if (!bl.length()) { // exists but no header yet + count = 0; + return 0; + } + + cls_user_account_header header; + try { + auto p = bl.cbegin(); + decode(header, p); + } catch (const buffer::error&) { + return -EIO; + } + count = header.count; return 0; } diff --git a/src/rgw/driver/rados/account.h b/src/rgw/driver/rados/account.h index c73d68bc626..d7755f7e011 100644 --- a/src/rgw/driver/rados/account.h +++ b/src/rgw/driver/rados/account.h @@ -20,6 +20,7 @@ #include #include #include "include/encoding.h" +#include "include/rados/librados_fwd.hpp" #include "common/async/yield_context.h" namespace ceph { class Formatter; } @@ -45,6 +46,11 @@ auto create_metadata_handler(RGWSI_SysObj& sysobj, const RGWZoneParams& zone) rgw_raw_obj get_buckets_obj(const RGWZoneParams& zone, std::string_view account_id); +/// Return the rados object that tracks the given account's users. This +/// can be used with the cls_user interface in namespace rgwrados::users. +rgw_raw_obj get_users_obj(const RGWZoneParams& zone, + std::string_view account_id); + /// Read account info by id int read(const DoutPrefixProvider* dpp, @@ -98,4 +104,12 @@ int remove(const DoutPrefixProvider* dpp, const RGWAccountInfo& info, RGWObjVersionTracker& objv); + +/// Read the resource count from an account index object. +int resource_count(const DoutPrefixProvider* dpp, + optional_yield y, + librados::Rados& rados, + const rgw_raw_obj& obj, + uint32_t& count); + } // namespace rgwrados::account diff --git a/src/rgw/driver/rados/users.cc b/src/rgw/driver/rados/users.cc new file mode 100644 index 00000000000..702863a768e --- /dev/null +++ b/src/rgw/driver/rados/users.cc @@ -0,0 +1,174 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright contributors to the Ceph project + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "users.h" + +#include "include/rados/librados.hpp" +#include "common/ceph_json.h" +#include "common/dout.h" +#include "cls/user/cls_user_client.h" +#include "rgw_common.h" +#include "rgw_sal.h" + +namespace rgwrados::users { + +int add(const DoutPrefixProvider* dpp, + optional_yield y, + librados::Rados& rados, + const rgw_raw_obj& obj, + const RGWUserInfo& user, + bool exclusive, uint32_t limit) +{ + resource_metadata meta; + meta.user_id = user.user_id.id; + + cls_user_account_resource resource; + resource.name = user.display_name; + resource.path = user.path; + encode(meta, resource.metadata); + + rgw_rados_ref ref; + int r = rgw_get_rados_ref(dpp, &rados, obj, &ref); + if (r < 0) { + return r; + } + + librados::ObjectWriteOperation op; + ::cls_user_account_resource_add(op, resource, exclusive, limit); + return ref.operate(dpp, &op, y); +} + +int get(const DoutPrefixProvider* dpp, + optional_yield y, + librados::Rados& rados, + const rgw_raw_obj& obj, + std::string_view name, + std::string& user_id) +{ + cls_user_account_resource resource; + + rgw_rados_ref ref; + int r = rgw_get_rados_ref(dpp, &rados, obj, &ref); + if (r < 0) { + return r; + } + + librados::ObjectReadOperation op; + int ret = 0; + ::cls_user_account_resource_get(op, name, resource, &ret); + + r = ref.operate(dpp, &op, nullptr, y); + if (r < 0) { + return r; + } + if (ret < 0) { + return ret; + } + + resource_metadata meta; + try { + auto p = resource.metadata.cbegin(); + decode(meta, p); + } catch (const buffer::error&) { + return -EIO; + } + user_id = std::move(meta.user_id); + return 0; +} + +int remove(const DoutPrefixProvider* dpp, + optional_yield y, + librados::Rados& rados, + const rgw_raw_obj& obj, + std::string_view name) +{ + rgw_rados_ref ref; + int r = rgw_get_rados_ref(dpp, &rados, obj, &ref); + if (r < 0) { + return r; + } + + librados::ObjectWriteOperation op; + ::cls_user_account_resource_rm(op, name); + return ref.operate(dpp, &op, y); +} + +int list(const DoutPrefixProvider* dpp, + optional_yield y, + librados::Rados& rados, + const rgw_raw_obj& obj, + std::string_view marker, + std::string_view path_prefix, + uint32_t max_items, + std::vector& ids, + std::string& next_marker) +{ + rgw_rados_ref ref; + int r = rgw_get_rados_ref(dpp, &rados, obj, &ref); + if (r < 0) { + return r; + } + + librados::ObjectReadOperation op; + std::vector entries; + bool truncated = false; + int ret = 0; + ::cls_user_account_resource_list(op, marker, path_prefix, max_items, + entries, &truncated, &next_marker, &ret); + + r = ref.operate(dpp, &op, nullptr, y); + if (r == -ENOENT) { + next_marker.clear(); + return 0; + } + if (r < 0) { + return r; + } + if (ret < 0) { + return ret; + } + + for (auto& resource : entries) { + resource_metadata meta; + try { + auto p = resource.metadata.cbegin(); + decode(meta, p); + } catch (const buffer::error&) { + return -EIO; + } + ids.push_back(std::move(meta.user_id)); + } + + if (!truncated) { + next_marker.clear(); + } + return 0; +} + + +void resource_metadata::dump(ceph::Formatter* f) const +{ + encode_json("user_id", user_id, f); +} + +void resource_metadata::generate_test_instances(std::list& o) +{ + o.push_back(new resource_metadata); + auto m = new resource_metadata; + m->user_id = "uid"; + o.push_back(m); +} + +} // namespace rgwrados::users diff --git a/src/rgw/driver/rados/users.h b/src/rgw/driver/rados/users.h new file mode 100644 index 00000000000..5a5094b6b54 --- /dev/null +++ b/src/rgw/driver/rados/users.h @@ -0,0 +1,87 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright contributors to the Ceph project + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#pragma once + +#include +#include +#include "include/rados/librados_fwd.hpp" +#include "include/encoding.h" +#include "rgw_sal_fwd.h" + +namespace ceph { class Formatter; } +class DoutPrefixProvider; +class optional_yield; +struct rgw_raw_obj; +struct RGWUserInfo; + + +namespace rgwrados::users { + +/// Add the given user to the list. +int add(const DoutPrefixProvider* dpp, + optional_yield y, + librados::Rados& rados, + const rgw_raw_obj& obj, + const RGWUserInfo& user, + bool exclusive, uint32_t limit); + +/// Look up a user's id by name in the list. +int get(const DoutPrefixProvider* dpp, + optional_yield y, + librados::Rados& rados, + const rgw_raw_obj& obj, + std::string_view name, + std::string& user_id); + +/// Remove the given user from the list. +int remove(const DoutPrefixProvider* dpp, + optional_yield y, + librados::Rados& rados, + const rgw_raw_obj& obj, + std::string_view name); + +/// Return a paginated listing of user ids. +int list(const DoutPrefixProvider* dpp, + optional_yield y, + librados::Rados& rados, + const rgw_raw_obj& obj, + std::string_view marker, + std::string_view path_prefix, + uint32_t max_items, + std::vector& ids, + std::string& next_marker); + +// user-specific metadata for cls_user_account_resource +struct resource_metadata { + std::string user_id; + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + encode(user_id, bl); + ENCODE_FINISH(bl); + } + void decode(bufferlist::const_iterator& bl) { + DECODE_START(1, bl); + decode(user_id, bl); + DECODE_FINISH(bl); + } + + void dump(ceph::Formatter* f) const; + static void generate_test_instances(std::list& o); +}; +WRITE_CLASS_ENCODER(resource_metadata); + +} // namespace rgwrados::users diff --git a/src/tools/ceph-dencoder/rgw_types.h b/src/tools/ceph-dencoder/rgw_types.h index aa0a3783d7d..d02c22436a8 100644 --- a/src/tools/ceph-dencoder/rgw_types.h +++ b/src/tools/ceph-dencoder/rgw_types.h @@ -246,4 +246,7 @@ TYPE(RGWUID) #include "rgw_user_types.h" TYPE(rgw_user) +#include "driver/rados/users.h" +TYPE(rgwrados::users::resource_metadata) + #endif -- 2.39.5