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 <yehuda@inktank.com>
Reviewed-by: Sage Weil <sage@inktank.com>
This commit is contained in:
Yehuda Sadeh 2012-06-11 23:31:09 -07:00 committed by Sage Weil
parent 0adb33d867
commit 5db4509b8e
5 changed files with 33 additions and 3 deletions

View File

@ -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(":");

View File

@ -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<string, RGWAccessKey> swift_keys;
map<string, RGWSubUser> 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;

View File

@ -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;
}

View File

@ -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" },

View File

@ -120,6 +120,8 @@ public:
* Cleanup data structure
*/
void clear() { buckets.clear(); }
size_t count() { return buckets.size(); }
};
WRITE_CLASS_ENCODER(RGWUserBuckets)