From 5db4509b8eb1ce91723c5277cb758071f0af4e4d Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Mon, 11 Jun 2012 23:31:09 -0700 Subject: [PATCH] rgw: limit number of buckets per user Adding a configurable max_buckets per user. Bucket creation verifies that max_buckets has not reached. Backport: dho Signed-off-by: Yehuda Sadeh Reviewed-by: Sage Weil --- src/rgw/rgw_admin.cc | 6 ++++++ src/rgw/rgw_common.h | 16 +++++++++++++--- src/rgw/rgw_op.cc | 11 +++++++++++ src/rgw/rgw_rest.cc | 1 + src/rgw/rgw_user.h | 2 ++ 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index 1c4b7fecdc94e..12cd38de5f135 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -314,6 +314,7 @@ static void show_user_info(RGWUserInfo& info, Formatter *formatter) formatter->dump_string("display_name", info.display_name); formatter->dump_string("email", info.user_email); formatter->dump_int("suspended", (int)info.suspended); + formatter->dump_int("max_buckets", (int)info.max_buckets); // subusers formatter->open_array_section("subusers"); @@ -565,6 +566,7 @@ int main(int argc, char **argv) int skip_zero_entries = false; // log show int purge_keys = false; int yes_i_really_mean_it = false; + int max_buckets = -1; std::string val; std::ostringstream errs; @@ -619,6 +621,8 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } auid = tmp; + } else if (ceph_argparse_witharg(args, i, &val, "--max-buckets", (char*)NULL)) { + max_buckets = atoi(val.c_str()); } else if (ceph_argparse_witharg(args, i, &val, "--date", (char*)NULL)) { date = val; if (end_date.empty()) @@ -876,6 +880,8 @@ int main(int argc, char **argv) case OPT_KEY_CREATE: if (!user_id.empty()) info.user_id = user_id; + if (max_buckets >= 0) + info.max_buckets = max_buckets; if (key_type == KEY_TYPE_SWIFT) { access_key = info.user_id; access_key.append(":"); diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 4b93ff3e361ca..7c3f567f1abf0 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -66,6 +66,8 @@ using ceph::crypto::MD5; #define RGW_SUSPENDED_USER_AUID (uint64_t)-2 +#define RGW_DEFAULT_MAX_BUCKETS 1000 + #define CGI_PRINTF(state, format, ...) do { \ int __ret = FCGX_FPrintF(state->fcgx->out, format, __VA_ARGS__); \ if (state->header_ended) \ @@ -117,6 +119,7 @@ using ceph::crypto::MD5; #define ERR_INVALID_UTF8 2017 #define ERR_UNPROCESSABLE_ENTITY 2018 #define ERR_TOO_LARGE 2019 +#define ERR_TOO_MANY_BUCKETS 2020 #define ERR_USER_SUSPENDED 2100 #define ERR_INTERNAL_ERROR 2200 @@ -328,11 +331,12 @@ struct RGWUserInfo map swift_keys; map subusers; __u8 suspended; + uint32_t max_buckets; - RGWUserInfo() : auid(0), suspended(0) {} + RGWUserInfo() : auid(0), suspended(0), max_buckets(RGW_DEFAULT_MAX_BUCKETS) {} void encode(bufferlist& bl) const { - ENCODE_START(9, 9, bl); + ENCODE_START(10, 9, bl); ::encode(auid, bl); string access_key; string secret_key; @@ -361,10 +365,11 @@ struct RGWUserInfo ::encode(subusers, bl); ::encode(suspended, bl); ::encode(swift_keys, bl); + ::encode(max_buckets, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { - DECODE_START_LEGACY_COMPAT_LEN_32(9, 9, 9, bl); + DECODE_START_LEGACY_COMPAT_LEN_32(10, 9, 9, bl); if (struct_v >= 2) ::decode(auid, bl); else auid = CEPH_AUTH_UID_DEFAULT; string access_key; @@ -398,6 +403,11 @@ struct RGWUserInfo if (struct_v >= 8) { ::decode(swift_keys, bl); } + if (struct_v >= 10) { + ::decode(max_buckets, bl); + } else { + max_buckets = RGW_DEFAULT_MAX_BUCKETS; + } DECODE_FINISH(bl); } void dump(Formatter *f) const; diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 022fcd90c471f..50354c5128b6c 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -533,6 +533,17 @@ int RGWCreateBucket::verify_permission() if (!rgw_user_is_authenticated(s->user)) return -EACCES; + if (s->user.max_buckets) { + RGWUserBuckets buckets; + int ret = rgw_read_user_buckets(s->user.user_id, buckets, false); + if (ret < 0) + return ret; + + if (buckets.count() >= s->user.max_buckets) { + return -ERR_TOO_MANY_BUCKETS; + } + } + return 0; } diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index 56452c473c5b2..9d7e13f524659 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -49,6 +49,7 @@ const static struct rgw_html_errors RGW_HTML_ERRORS[] = { { ERR_INVALID_PART_ORDER, 400, "InvalidPartOrder" }, { ERR_REQUEST_TIMEOUT, 400, "RequestTimeout" }, { ERR_TOO_LARGE, 400, "EntityTooLarge" }, + { ERR_TOO_MANY_BUCKETS, 400, "TooManyBuckets" }, { ERR_LENGTH_REQUIRED, 411, "MissingContentLength" }, { EACCES, 403, "AccessDenied" }, { EPERM, 403, "AccessDenied" }, diff --git a/src/rgw/rgw_user.h b/src/rgw/rgw_user.h index 6c2cb807cd219..01ed1d9c51f07 100644 --- a/src/rgw/rgw_user.h +++ b/src/rgw/rgw_user.h @@ -120,6 +120,8 @@ public: * Cleanup data structure */ void clear() { buckets.clear(); } + + size_t count() { return buckets.size(); } }; WRITE_CLASS_ENCODER(RGWUserBuckets) -- 2.39.5