From 2d50762c956c3fbc01f21c9e8b60ff85448f0c9f Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Sun, 19 Nov 2023 13:07:20 -0500 Subject: [PATCH] cls/user: add interfaces to index user account resources Signed-off-by: Casey Bodley (cherry picked from commit b56fc946eac20d982cd0743305a630948d5b12d6) --- src/cls/user/cls_user.cc | 238 +++++++++++++++++++++++++++- src/cls/user/cls_user_client.cc | 121 ++++++++++++++ src/cls/user/cls_user_client.h | 27 ++++ src/cls/user/cls_user_ops.cc | 86 ++++++++++ src/cls/user/cls_user_ops.h | 132 +++++++++++++++ src/cls/user/cls_user_types.cc | 32 ++++ src/cls/user/cls_user_types.h | 48 ++++++ src/tools/ceph-dencoder/rgw_types.h | 8 + 8 files changed, 689 insertions(+), 3 deletions(-) diff --git a/src/cls/user/cls_user.cc b/src/cls/user/cls_user.cc index e278ad7fc1283..0447bf33a2c82 100644 --- a/src/cls/user/cls_user.cc +++ b/src/cls/user/cls_user.cc @@ -2,11 +2,14 @@ // vim: ts=8 sw=2 smarttab #include +#include +#include #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 +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 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 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); } diff --git a/src/cls/user/cls_user_client.cc b/src/cls/user/cls_user_client.cc index b74f55b48b2fd..acc94ca326a2e 100644 --- a/src/cls/user/cls_user_client.cc +++ b/src/cls/user/cls_user_client.cc @@ -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* entries; + bool* truncated; + std::string* next_marker; + int* pret; +public: + ResourceListCB(std::vector* 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& 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)); +} diff --git a/src/cls/user/cls_user_client.h b/src/cls/user/cls_user_client.h index 03d975c59cb51..a1120f86400b6 100644 --- a/src/cls/user/cls_user_client.h +++ b/src/cls/user/cls_user_client.h @@ -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& entries, + bool* truncated, std::string* next_marker, + int* pret); + #endif diff --git a/src/cls/user/cls_user_ops.cc b/src/cls/user/cls_user_ops.cc index 5ae9d2c93b820..f787c1eeb0226 100644 --- a/src/cls/user/cls_user_ops.cc +++ b/src/cls/user/cls_user_ops.cc @@ -116,3 +116,89 @@ void cls_user_complete_stats_sync_op::generate_test_instances(list& 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& 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& 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& 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& 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& 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); +} diff --git a/src/cls/user/cls_user_ops.h b/src/cls/user/cls_user_ops.h index 7edd1bc15cef2..d638896340b8a 100644 --- a/src/cls/user/cls_user_ops.h +++ b/src/cls/user/cls_user_ops.h @@ -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& 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& 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& 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& 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& ls); +}; +WRITE_CLASS_ENCODER(cls_user_account_resource_list_op) + +struct cls_user_account_resource_list_ret { + std::vector 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& ls); +}; +WRITE_CLASS_ENCODER(cls_user_account_resource_list_ret) + #endif diff --git a/src/cls/user/cls_user_types.cc b/src/cls/user/cls_user_types.cc index 0d823f0bea20f..23f2044e9636b 100644 --- a/src/cls/user/cls_user_types.cc +++ b/src/cls/user/cls_user_types.cc @@ -109,3 +109,35 @@ void cls_user_header::generate_test_instances(list& 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& 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& 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); +} diff --git a/src/cls/user/cls_user_types.h b/src/cls/user/cls_user_types.h index a139449d3c3ea..8193ff4139ace 100644 --- a/src/cls/user/cls_user_types.h +++ b/src/cls/user/cls_user_types.h @@ -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& 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& 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 diff --git a/src/tools/ceph-dencoder/rgw_types.h b/src/tools/ceph-dencoder/rgw_types.h index 97a3330d7db6a..1b974a9bf8706 100644 --- a/src/tools/ceph-dencoder/rgw_types.h +++ b/src/tools/ceph-dencoder/rgw_types.h @@ -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) -- 2.39.5