]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
cls/user: add interfaces to index user account resources
authorCasey Bodley <cbodley@redhat.com>
Sun, 19 Nov 2023 18:07:20 +0000 (13:07 -0500)
committerCasey Bodley <cbodley@redhat.com>
Fri, 12 Apr 2024 19:34:27 +0000 (15:34 -0400)
Signed-off-by: Casey Bodley <cbodley@redhat.com>
(cherry picked from commit b56fc946eac20d982cd0743305a630948d5b12d6)

src/cls/user/cls_user.cc
src/cls/user/cls_user_client.cc
src/cls/user/cls_user_client.h
src/cls/user/cls_user_ops.cc
src/cls/user/cls_user_ops.h
src/cls/user/cls_user_types.cc
src/cls/user/cls_user_types.h
src/tools/ceph-dencoder/rgw_types.h

index e278ad7fc12834ae2fc355d4cf6232f29a34eddf..0447bf33a2c82ef11115080bd7e2175b057a21ad 100644 (file)
@@ -2,11 +2,14 @@
 // vim: ts=8 sw=2 smarttab
 
 #include <errno.h>
+#include <algorithm>
+#include <cctype>
 
 #include "include/utime.h"
 #include "objclass/objclass.h"
 
 #include "cls_user_ops.h"
+#include "rgw/rgw_string.h"
 
 using std::map;
 using std::string;
@@ -71,7 +74,8 @@ static int get_existing_bucket_entry(cls_method_context_t hctx, const string& bu
   return 0;
 }
 
-static int read_header(cls_method_context_t hctx, cls_user_header *header)
+template <typename T>
+static int read_header(cls_method_context_t hctx, T *header)
 {
   bufferlist bl;
 
@@ -80,7 +84,7 @@ static int read_header(cls_method_context_t hctx, cls_user_header *header)
     return ret;
 
   if (bl.length() == 0) {
-    *header = cls_user_header();
+    *header = T();
     return 0;
   }
 
@@ -501,6 +505,221 @@ static int cls_user_reset_stats2(cls_method_context_t hctx,
   return 0;
 } /* cls_user_reset_stats2 */
 
+
+// account resource names must be unique and aren't distinguished by case, so
+// convert all keys to lowercase
+static std::string resource_key(std::string_view name)
+{
+  std::string key;
+  key.resize(name.size());
+  std::transform(name.begin(), name.end(), key.begin(),
+                 [](unsigned char c) { return std::tolower(c); });
+  return key;
+}
+
+static int cls_account_resource_add(cls_method_context_t hctx,
+                                    buffer::list *in, buffer::list *out)
+{
+  cls_user_account_resource_add_op op;
+  try {
+    auto bliter = in->cbegin();
+    decode(op, bliter);
+  } catch (const ceph::buffer::error& err) {
+    CLS_LOG(0, "ERROR: %s failed to decode op", __func__);
+    return -EINVAL;
+  }
+
+  CLS_LOG(20, "adding account resource name=%s path=%s",
+          op.entry.name.c_str(), op.entry.path.c_str());
+
+  const std::string key = resource_key(op.entry.name);
+
+  // does this resource entry exist?
+  bufferlist readbl; // unused
+  int ret = cls_cxx_map_get_val(hctx, key, &readbl);
+  if (ret < 0 && ret != -ENOENT) {
+    return ret;
+  }
+  const bool exists = (ret == 0);
+
+  std::optional<cls_user_account_header> header;
+  if (!exists) {
+    // if this is a new entry, update the resource count in the account header
+    ret = read_header(hctx, &header.emplace());
+    if (ret < 0) {
+      CLS_LOG(0, "ERROR: failed to read account header ret=%d", ret);
+      return ret;
+    }
+    if (header->count >= op.limit) {
+      CLS_LOG(4, "account resource limit exceeded, %u >= %u",
+              header->count, op.limit);
+      return -EUSERS; // too many users
+    }
+    header->count++;
+  } else if (op.exclusive) {
+    return -EEXIST;
+  }
+
+  // write/overwrite the entry
+  bufferlist writebl;
+  encode(op.entry, writebl);
+  ret = cls_cxx_map_set_val(hctx, key, &writebl);
+  if (ret < 0) {
+    CLS_LOG(0, "ERROR: failed to write account resource: %d", ret);
+    return ret;
+  }
+
+  // write the updated account header
+  if (header) {
+    bufferlist headerbl;
+    encode(*header, headerbl);
+    return cls_cxx_map_write_header(hctx, &headerbl);
+  }
+  return 0;
+} // cls_account_resource_add
+
+static int cls_account_resource_get(cls_method_context_t hctx,
+                                    bufferlist *in, bufferlist *out)
+{
+  cls_user_account_resource_get_op op;
+  try {
+    auto p = in->cbegin();
+    decode(op, p);
+  } catch (const ceph::buffer::error& err) {
+    CLS_LOG(0, "ERROR: %s failed to decode op", __func__);
+    return -EINVAL;
+  }
+
+  CLS_LOG(20, "reading account resource name=%s", op.name.c_str());
+
+  const std::string key = resource_key(op.name);
+
+  bufferlist bl;
+  int r = cls_cxx_map_get_val(hctx, key, &bl);
+  if (r < 0) {
+    return r;
+  }
+
+  cls_user_account_resource_get_ret ret;
+  try {
+    auto iter = bl.cbegin();
+    decode(ret.entry, iter);
+  } catch (ceph::buffer::error& err) {
+    CLS_LOG(0, "ERROR: failed to decode entry %s", key.c_str());
+    return -EIO;
+  }
+
+  encode(ret, *out);
+  return 0;
+} // cls_account_resource_get
+
+static int cls_account_resource_rm(cls_method_context_t hctx,
+                                   buffer::list *in, buffer::list *out)
+{
+  cls_user_account_resource_rm_op op;
+  try {
+    auto bliter = in->cbegin();
+    decode(op, bliter);
+  } catch (const ceph::buffer::error& err) {
+    CLS_LOG(0, "ERROR: %s failed to decode op", __func__);
+    return -EINVAL;
+  }
+
+  CLS_LOG(20, "removing account resource name=%s", op.name.c_str());
+
+  const std::string key = resource_key(op.name);
+
+  // verify that the resource entry exists, so we can return ENOENT otherwise.
+  // remove_key() alone would return success either way
+  bufferlist readbl; // unused
+  int ret = cls_cxx_map_get_val(hctx, key, &readbl);
+  if (ret < 0) {
+    return ret;
+  }
+
+  // remove the resource entry
+  ret = cls_cxx_map_remove_key(hctx, key);
+  if (ret < 0) {
+    CLS_LOG(0, "ERROR: failed to remove account resource: %d", ret);
+    return ret;
+  }
+
+  // update resource count in the account header
+  cls_user_account_header header;
+  ret = read_header(hctx, &header);
+  if (ret < 0) {
+    CLS_LOG(0, "ERROR: failed to read account header ret=%d", ret);
+    return ret;
+  }
+  if (header.count) { // guard underflow
+    header.count--;
+  }
+
+  bufferlist headerbl;
+  encode(header, headerbl);
+  return cls_cxx_map_write_header(hctx, &headerbl);
+} // cls_account_resource_rm
+
+static int cls_account_resource_list(cls_method_context_t hctx,
+                                     bufferlist *in, bufferlist *out)
+{
+  cls_user_account_resource_list_op op;
+  try {
+    auto p = in->cbegin();
+    decode(op, p);
+  } catch (const ceph::buffer::error& err) {
+    CLS_LOG(0, "ERROR: %s failed to decode op", __func__);
+    return -EINVAL;
+  }
+  CLS_LOG(20, "listing account resources from marker=%s path_prefix=%s max_entries=%d",
+          op.marker.c_str(), op.path_prefix.c_str(), (int)op.max_entries);
+
+  const std::string prefix; // empty
+  const uint32_t max_entries = std::min(op.max_entries, 1000u);
+  std::map<std::string, bufferlist> entries;
+  bool truncated = false;
+
+  int rc = cls_cxx_map_get_vals(hctx, op.marker, prefix, max_entries,
+                                &entries, &truncated);
+  if (rc < 0) {
+    return rc;
+  }
+
+  cls_user_account_resource_list_ret ret;
+
+  // copy matching decoded omap values into a vector
+  for (auto& [key, bl] : entries) {
+    // decode as cls_user_account_resource
+    cls_user_account_resource entry;
+    try {
+      auto p = bl.cbegin();
+      decode(entry, p);
+    } catch (const ceph::buffer::error& e) {
+      CLS_LOG(1, "ERROR: %s failed to decode resource entry at key=%s",
+              __func__, key.c_str());
+      return -EIO;
+    }
+
+    // filter entries by path prefix
+    if (entry.path.starts_with(op.path_prefix)) {
+      CLS_LOG(20, "included resource path=%s name=%s",
+              entry.path.c_str(), entry.name.c_str());
+      ret.entries.push_back(std::move(entry));
+    }
+  }
+
+  ret.truncated = truncated;
+  if (!entries.empty()) {
+    ret.marker = entries.rbegin()->first;
+  }
+  CLS_LOG(20, "entries=%d next_marker=%s truncated=%d",
+          (int)ret.entries.size(), ret.marker.c_str(), (int)ret.truncated);
+
+  encode(ret, *out);
+  return 0;
+} // cls_account_resource_list
+
+
 CLS_INIT(user)
 {
   CLS_LOG(1, "Loaded user class!");
@@ -527,5 +746,18 @@ CLS_INIT(user)
   cls_register_cxx_method(h_class, "reset_user_stats", CLS_METHOD_RD | CLS_METHOD_WR, cls_user_reset_stats, &h_user_reset_stats);
   cls_register_cxx_method(h_class, "reset_user_stats2", CLS_METHOD_RD | CLS_METHOD_WR, cls_user_reset_stats2, &h_user_reset_stats2);
 
-  return;
+  // account
+  cls_method_handle_t h_account_resource_add;
+  cls_method_handle_t h_account_resource_get;
+  cls_method_handle_t h_account_resource_rm;
+  cls_method_handle_t h_account_resource_list;
+
+  cls_register_cxx_method(h_class, "account_resource_add", CLS_METHOD_RD | CLS_METHOD_WR,
+                          cls_account_resource_add, &h_account_resource_add);
+  cls_register_cxx_method(h_class, "account_resource_get", CLS_METHOD_RD,
+                          cls_account_resource_get, &h_account_resource_get);
+  cls_register_cxx_method(h_class, "account_resource_rm", CLS_METHOD_RD | CLS_METHOD_WR,
+                          cls_account_resource_rm, &h_account_resource_rm);
+  cls_register_cxx_method(h_class, "account_resource_list", CLS_METHOD_RD,
+                          cls_account_resource_list, &h_account_resource_list);
 }
index b74f55b48b2fd493795b71920a154dbfc40956a2..acc94ca326a2e480afc794ccb7d59b2807dd7b9b 100644 (file)
@@ -162,3 +162,124 @@ int cls_user_get_header_async(IoCtx& io_ctx, string& oid, RGWGetUserHeader_CB *c
 
   return 0;
 }
+
+
+void cls_user_account_resource_add(librados::ObjectWriteOperation& op,
+                                   const cls_user_account_resource& entry,
+                                   bool exclusive, uint32_t limit)
+{
+  cls_user_account_resource_add_op call;
+  call.entry = entry;
+  call.exclusive = exclusive;
+  call.limit = limit;
+
+  bufferlist inbl;
+  encode(call, inbl);
+  op.exec("user", "account_resource_add", inbl);
+}
+
+class ResourceGetCB : public librados::ObjectOperationCompletion {
+  cls_user_account_resource* entry;
+  int* pret;
+public:
+  ResourceGetCB(cls_user_account_resource* entry, int* pret)
+    : entry(entry), pret(pret)
+  {}
+  void handle_completion(int r, bufferlist& outbl) override {
+    if (r >= 0) {
+      cls_user_account_resource_get_ret ret;
+      try {
+        auto iter = outbl.cbegin();
+        decode(ret, iter);
+        if (entry) {
+          *entry = std::move(ret.entry);
+        }
+      } catch (const ceph::buffer::error& err) {
+        r = -EIO;
+      }
+    }
+    if (pret) {
+      *pret = r;
+    }
+  }
+};
+
+void cls_user_account_resource_get(librados::ObjectReadOperation& op,
+                                   std::string_view name,
+                                   cls_user_account_resource& entry,
+                                   int* pret)
+{
+  cls_user_account_resource_get_op call;
+  call.name = name;
+
+  bufferlist inbl;
+  encode(call, inbl);
+  op.exec("user", "account_resource_get", inbl,
+          new ResourceGetCB(&entry, pret));
+}
+
+void cls_user_account_resource_rm(librados::ObjectWriteOperation& op,
+                                  std::string_view name)
+{
+  cls_user_account_resource_rm_op call;
+  call.name = name;
+
+  bufferlist inbl;
+  encode(call, inbl);
+  op.exec("user", "account_resource_rm", inbl);
+}
+
+class ResourceListCB : public librados::ObjectOperationCompletion {
+  std::vector<cls_user_account_resource>* entries;
+  bool* truncated;
+  std::string* next_marker;
+  int* pret;
+public:
+  ResourceListCB(std::vector<cls_user_account_resource>* entries,
+                 bool* truncated, std::string* next_marker, int* pret)
+    : entries(entries), truncated(truncated),
+      next_marker(next_marker), pret(pret)
+  {}
+  void handle_completion(int r, bufferlist& outbl) override {
+    if (r >= 0) {
+      cls_user_account_resource_list_ret ret;
+      try {
+        auto iter = outbl.cbegin();
+        decode(ret, iter);
+        if (entries) {
+          *entries = std::move(ret.entries);
+        }
+        if (next_marker) {
+          *next_marker = std::move(ret.marker);
+        }
+        if (truncated) {
+          *truncated = ret.truncated;
+        }
+      } catch (const ceph::buffer::error& err) {
+        r = -EIO;
+      }
+    }
+    if (pret) {
+      *pret = r;
+    }
+  }
+};
+
+void cls_user_account_resource_list(librados::ObjectReadOperation& op,
+                                    std::string_view marker,
+                                    std::string_view path_prefix,
+                                    uint32_t max_entries,
+                                    std::vector<cls_user_account_resource>& entries,
+                                    bool* truncated, std::string* next_marker,
+                                    int* pret)
+{
+  cls_user_account_resource_list_op call;
+  call.marker = marker;
+  call.path_prefix = path_prefix;
+  call.max_entries = max_entries;
+
+  bufferlist inbl;
+  encode(call, inbl);
+  op.exec("user", "account_resource_list", inbl,
+          new ResourceListCB(&entries, truncated, next_marker, pret));
+}
index 03d975c59cb5107202d53e3ca5978b739307bf6a..a1120f86400b6be08061e1fc4faf9c4d6b21f766 100644 (file)
@@ -33,4 +33,31 @@ void cls_user_get_header(librados::ObjectReadOperation& op, cls_user_header *hea
 int cls_user_get_header_async(librados::IoCtx& io_ctx, std::string& oid, RGWGetUserHeader_CB *ctx);
 void cls_user_reset_stats(librados::ObjectWriteOperation& op);
 
+// Account resources
+
+/// Add or overwrite an entry to the account's list of resources. Returns
+/// -EUSERS (Too many users) if the resource count would exceed the given limit.
+void cls_user_account_resource_add(librados::ObjectWriteOperation& op,
+                                   const cls_user_account_resource& entry,
+                                   bool exclusive, uint32_t limit);
+
+/// Look up an account resource by case-insensitive name.
+void cls_user_account_resource_get(librados::ObjectReadOperation& op,
+                                   std::string_view name,
+                                   cls_user_account_resource& entry,
+                                   int* pret);
+
+/// Remove an account resources by case-insensitive name.
+void cls_user_account_resource_rm(librados::ObjectWriteOperation& op,
+                                  std::string_view name);
+
+/// List the resources linked to an account.
+void cls_user_account_resource_list(librados::ObjectReadOperation& op,
+                                    std::string_view marker,
+                                    std::string_view path_prefix,
+                                    uint32_t max_entries,
+                                    std::vector<cls_user_account_resource>& entries,
+                                    bool* truncated, std::string* next_marker,
+                                    int* pret);
+
 #endif
index 5ae9d2c93b82063fed652843a7be3e914fb37fb9..f787c1eeb0226e56b68fcff62ffbe33041ae2845 100644 (file)
@@ -116,3 +116,89 @@ void cls_user_complete_stats_sync_op::generate_test_instances(list<cls_user_comp
 }
 
 
+void cls_user_account_resource_add_op::dump(Formatter *f) const
+{
+  encode_json("name", entry.name, f);
+  encode_json("path", entry.path, f);
+  encode_json("limit", limit, f);
+}
+
+void cls_user_account_resource_add_op::generate_test_instances(std::list<cls_user_account_resource_add_op*>& ls)
+{
+  ls.push_back(new cls_user_account_resource_add_op);
+  cls_user_account_resource_add_op *op = new cls_user_account_resource_add_op;
+  cls_user_gen_test_resource(op->entry);
+  ls.push_back(op);
+}
+
+void cls_user_account_resource_get_op::dump(Formatter *f) const
+{
+  encode_json("name", name, f);
+}
+
+void cls_user_account_resource_get_op::generate_test_instances(std::list<cls_user_account_resource_get_op*>& ls)
+{
+  ls.push_back(new cls_user_account_resource_get_op);
+  cls_user_account_resource_get_op *op = new cls_user_account_resource_get_op;
+  op->name = "name";
+  ls.push_back(op);
+}
+
+void cls_user_account_resource_get_ret::dump(Formatter *f) const
+{
+  encode_json("entry", entry, f);
+}
+
+void cls_user_account_resource_get_ret::generate_test_instances(std::list<cls_user_account_resource_get_ret*>& ls)
+{
+  ls.push_back(new cls_user_account_resource_get_ret);
+  cls_user_account_resource_get_ret *ret = new cls_user_account_resource_get_ret;
+  cls_user_gen_test_resource(ret->entry);
+  ls.push_back(ret);
+}
+
+void cls_user_account_resource_rm_op::dump(Formatter *f) const
+{
+  encode_json("name", name, f);
+}
+
+void cls_user_account_resource_rm_op::generate_test_instances(std::list<cls_user_account_resource_rm_op*>& ls)
+{
+  ls.push_back(new cls_user_account_resource_rm_op);
+  cls_user_account_resource_rm_op *op = new cls_user_account_resource_rm_op;
+  op->name = "name";
+  ls.push_back(op);
+}
+
+void cls_user_account_resource_list_op::dump(Formatter *f) const
+{
+  encode_json("marker", marker, f);
+  encode_json("path_prefix", path_prefix, f);
+  encode_json("max_entries", max_entries, f);
+}
+
+void cls_user_account_resource_list_op::generate_test_instances(std::list<cls_user_account_resource_list_op*>& ls)
+{
+  ls.push_back(new cls_user_account_resource_list_op);
+  cls_user_account_resource_list_op *op = new cls_user_account_resource_list_op;
+  op->marker = "marker";
+  op->path_prefix = "path";
+  op->max_entries = 20;
+  ls.push_back(op);
+}
+
+void cls_user_account_resource_list_ret::dump(Formatter *f) const
+{
+  encode_json("entries", entries, f);
+  encode_json("truncated", truncated, f);
+  encode_json("marker", marker, f);
+}
+
+void cls_user_account_resource_list_ret::generate_test_instances(std::list<cls_user_account_resource_list_ret*>& ls)
+{
+  ls.push_back(new cls_user_account_resource_list_ret);
+  cls_user_account_resource_list_ret *ret = new cls_user_account_resource_list_ret;
+  cls_user_gen_test_resource(ret->entries.emplace_back());
+  ret->truncated = true;
+  ls.push_back(ret);
+}
index 7edd1bc15cef213bccfc993da158b7d0784c49b9..d638896340b8affb8afeb3471354055ae9a21683 100644 (file)
@@ -264,4 +264,136 @@ struct cls_user_complete_stats_sync_op {
 WRITE_CLASS_ENCODER(cls_user_complete_stats_sync_op)
 
 
+struct cls_user_account_resource_add_op {
+  cls_user_account_resource entry;
+  bool exclusive = false;
+  uint32_t limit = 0;
+
+  void encode(ceph::buffer::list& bl) const {
+    ENCODE_START(1, 1, bl);
+    encode(entry, bl);
+    encode(exclusive, bl);
+    encode(limit, bl);
+    ENCODE_FINISH(bl);
+  }
+  void decode(ceph::buffer::list::const_iterator& bl) {
+    DECODE_START(1, bl);
+    decode(entry, bl);
+    decode(exclusive, bl);
+    decode(limit, bl);
+    DECODE_FINISH(bl);
+  }
+
+  void dump(ceph::Formatter* f) const;
+  static void generate_test_instances(std::list<cls_user_account_resource_add_op*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_user_account_resource_add_op)
+
+struct cls_user_account_resource_get_op {
+  std::string name;
+
+  void encode(ceph::buffer::list& bl) const {
+    ENCODE_START(1, 1, bl);
+    encode(name, bl);
+    ENCODE_FINISH(bl);
+  }
+  void decode(ceph::buffer::list::const_iterator& bl) {
+    DECODE_START(1, bl);
+    decode(name, bl);
+    DECODE_FINISH(bl);
+  }
+
+  void dump(ceph::Formatter* f) const;
+  static void generate_test_instances(std::list<cls_user_account_resource_get_op*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_user_account_resource_get_op)
+
+struct cls_user_account_resource_get_ret {
+  cls_user_account_resource entry;
+
+  void encode(ceph::buffer::list& bl) const {
+    ENCODE_START(1, 1, bl);
+    encode(entry, bl);
+    ENCODE_FINISH(bl);
+  }
+  void decode(ceph::buffer::list::const_iterator& bl) {
+    DECODE_START(1, bl);
+    decode(entry, bl);
+    DECODE_FINISH(bl);
+  }
+
+  void dump(ceph::Formatter* f) const;
+  static void generate_test_instances(std::list<cls_user_account_resource_get_ret*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_user_account_resource_get_ret)
+
+struct cls_user_account_resource_rm_op {
+  std::string name;
+
+  void encode(ceph::buffer::list& bl) const {
+    ENCODE_START(1, 1, bl);
+    encode(name, bl);
+    ENCODE_FINISH(bl);
+  }
+  void decode(ceph::buffer::list::const_iterator& bl) {
+    DECODE_START(1, bl);
+    decode(name, bl);
+    DECODE_FINISH(bl);
+  }
+
+  void dump(ceph::Formatter* f) const;
+  static void generate_test_instances(std::list<cls_user_account_resource_rm_op*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_user_account_resource_rm_op)
+
+struct cls_user_account_resource_list_op {
+  std::string marker;
+  std::string path_prefix;
+  uint32_t max_entries = 0;
+
+  void encode(ceph::buffer::list& bl) const {
+    ENCODE_START(1, 1, bl);
+    encode(marker, bl);
+    encode(path_prefix, bl);
+    encode(max_entries, bl);
+    ENCODE_FINISH(bl);
+  }
+  void decode(ceph::buffer::list::const_iterator& bl) {
+    DECODE_START(1, bl);
+    decode(marker, bl);
+    decode(path_prefix, bl);
+    decode(max_entries, bl);
+    DECODE_FINISH(bl);
+  }
+
+  void dump(ceph::Formatter* f) const;
+  static void generate_test_instances(std::list<cls_user_account_resource_list_op*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_user_account_resource_list_op)
+
+struct cls_user_account_resource_list_ret {
+  std::vector<cls_user_account_resource> entries;
+  bool truncated = false;
+  std::string marker;
+
+  void encode(ceph::buffer::list& bl) const {
+    ENCODE_START(1, 1, bl);
+    encode(entries, bl);
+    encode(truncated, bl);
+    encode(marker, bl);
+    ENCODE_FINISH(bl);
+  }
+  void decode(ceph::buffer::list::const_iterator& bl) {
+    DECODE_START(1, bl);
+    decode(entries, bl);
+    decode(truncated, bl);
+    decode(marker, bl);
+    DECODE_FINISH(bl);
+  }
+
+  void dump(ceph::Formatter* f) const;
+  static void generate_test_instances(std::list<cls_user_account_resource_list_ret*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_user_account_resource_list_ret)
+
 #endif
index 0d823f0bea20f5a8011c892db9254ee881e85a07..23f2044e9636b3f8fa7c7d0d3bc9ecd7d6fc5215 100644 (file)
@@ -109,3 +109,35 @@ void cls_user_header::generate_test_instances(list<cls_user_header*>& ls)
   cls_user_gen_test_header(h);
   ls.push_back(h);
 }
+
+
+void cls_user_account_header::dump(ceph::Formatter* f) const
+{
+  encode_json("count", count, f);
+}
+
+void cls_user_account_header::generate_test_instances(std::list<cls_user_account_header*>& ls)
+{
+  ls.push_back(new cls_user_account_header);
+}
+
+void cls_user_account_resource::dump(ceph::Formatter* f) const
+{
+  encode_json("name", name, f);
+  encode_json("path", path, f);
+  // skip metadata
+}
+
+void cls_user_gen_test_resource(cls_user_account_resource& r)
+{
+  r.name = "name";
+  r.path = "path";
+}
+
+void cls_user_account_resource::generate_test_instances(std::list<cls_user_account_resource*>& ls)
+{
+  ls.push_back(new cls_user_account_resource);
+  auto p = new cls_user_account_resource;
+  cls_user_gen_test_resource(*p);
+  ls.push_back(p);
+}
index a139449d3c3ea44be3e350e4e321dee1e65af3ef..8193ff4139aced998aafc416d021d283c3d3bff0 100644 (file)
@@ -216,9 +216,57 @@ struct cls_user_header {
 };
 WRITE_CLASS_ENCODER(cls_user_header)
 
+// omap header for an account index object
+struct cls_user_account_header {
+  uint32_t count = 0;
+
+  void encode(ceph::buffer::list& bl) const {
+    ENCODE_START(1, 1, bl);
+    encode(count, bl);
+    ENCODE_FINISH(bl);
+  }
+  void decode(ceph::buffer::list::const_iterator& bl) {
+    DECODE_START(1, bl);
+    decode(count, bl);
+    DECODE_FINISH(bl);
+  }
+  void dump(ceph::Formatter* f) const;
+  static void generate_test_instances(std::list<cls_user_account_header*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_user_account_header)
+
+// account resource entry
+struct cls_user_account_resource {
+  // index by name for put/delete
+  std::string name;
+  // index by path for listing by PathPrefix
+  std::string path;
+  // additional opaque metadata depending on resource type
+  ceph::buffer::list metadata;
+
+  void encode(ceph::buffer::list& bl) const {
+    ENCODE_START(1, 1, bl);
+    encode(name, bl);
+    encode(path, bl);
+    encode(metadata, bl);
+    ENCODE_FINISH(bl);
+  }
+  void decode(ceph::buffer::list::const_iterator& bl) {
+    DECODE_START(1, bl);
+    decode(name, bl);
+    decode(path, bl);
+    decode(metadata, bl);
+    DECODE_FINISH(bl);
+  }
+  void dump(ceph::Formatter* f) const;
+  static void generate_test_instances(std::list<cls_user_account_resource*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_user_account_resource)
+
 void cls_user_gen_test_bucket(cls_user_bucket *bucket, int i);
 void cls_user_gen_test_bucket_entry(cls_user_bucket_entry *entry, int i);
 void cls_user_gen_test_stats(cls_user_stats *stats);
 void cls_user_gen_test_header(cls_user_header *h);
+void cls_user_gen_test_resource(cls_user_account_resource& r);
 
 #endif
index 97a3330d7db6a13185ae4dbb603f59b321990b82..1b974a9bf87062cd880e68e408b664ea5c374471 100644 (file)
@@ -125,6 +125,8 @@ TYPE(cls_user_bucket)
 TYPE(cls_user_bucket_entry)
 TYPE(cls_user_stats)
 TYPE(cls_user_header)
+TYPE(cls_user_account_header)
+TYPE(cls_user_account_resource)
 
 #include "cls/user/cls_user_ops.h"
 TYPE(cls_user_set_buckets_op)
@@ -134,6 +136,12 @@ TYPE(cls_user_list_buckets_ret)
 TYPE(cls_user_get_header_op)
 TYPE(cls_user_get_header_ret)
 TYPE(cls_user_complete_stats_sync_op)
+TYPE(cls_user_account_resource_add_op)
+TYPE(cls_user_account_resource_get_op)
+TYPE(cls_user_account_resource_get_ret)
+TYPE(cls_user_account_resource_rm_op)
+TYPE(cls_user_account_resource_list_op)
+TYPE(cls_user_account_resource_list_ret)
 
 #include "cls/journal/cls_journal_types.h"
 TYPE(cls::journal::ObjectPosition)