]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
rgw/rados: add rgwrados::users namespace abstraction for cls_user
authorCasey Bodley <cbodley@redhat.com>
Mon, 18 Dec 2023 03:49:20 +0000 (22:49 -0500)
committerCasey Bodley <cbodley@redhat.com>
Wed, 10 Apr 2024 17:09:14 +0000 (13:09 -0400)
Signed-off-by: Casey Bodley <cbodley@redhat.com>
src/rgw/CMakeLists.txt
src/rgw/driver/rados/account.cc
src/rgw/driver/rados/account.h
src/rgw/driver/rados/users.cc [new file with mode: 0644]
src/rgw/driver/rados/users.h [new file with mode: 0644]
src/tools/ceph-dencoder/rgw_types.h

index 1ddddb00c238530891b0704c0f0e1631015cea52..84a5bc9e56c97f1278c7dedb01871ccb8215d6f9 100644 (file)
@@ -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
index f7c86099eee88e21f2369c49a8493bd68a673860..b018ee3e37077547f3d765659e6c2e5d9a82aecf 100644 (file)
@@ -16,6 +16,8 @@
 #include "account.h"
 
 #include <boost/algorithm/string.hpp>
+#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;
 }
 
index c73d68bc626d334a0c94c334dcc11872d998000f..d7755f7e011c63fa1672b3eb5eac3238e65e143c 100644 (file)
@@ -20,6 +20,7 @@
 #include <memory>
 #include <string>
 #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 (file)
index 0000000..702863a
--- /dev/null
@@ -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<std::string>& 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<cls_user_account_resource> 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<resource_metadata*>& 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 (file)
index 0000000..5a5094b
--- /dev/null
@@ -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 <list>
+#include <string>
+#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<std::string>& 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<resource_metadata*>& o);
+};
+WRITE_CLASS_ENCODER(resource_metadata);
+
+} // namespace rgwrados::users
index aa0a3783d7d64258b633cccf7ee656b2bcd9c465..d02c22436a8f3f1a0ddb3634d955a82509462a43 100644 (file)
@@ -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