]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: limit number of buckets per user
authorYehuda Sadeh <yehuda@inktank.com>
Tue, 12 Jun 2012 06:31:09 +0000 (23:31 -0700)
committerSage Weil <sage@inktank.com>
Thu, 14 Jun 2012 21:12:56 +0000 (14:12 -0700)
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>
src/rgw/rgw_admin.cc
src/rgw/rgw_common.h
src/rgw/rgw_op.cc
src/rgw/rgw_rest.cc
src/rgw/rgw_user.h

index 1c4b7fecdc94eab0ce9148f8c5dbe8dbcfff3531..12cd38de5f135976558d8aced4f528a0d9801e60 100644 (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(":");
index 4b93ff3e361cad17783675cc464a2887e2f88fcd..7c3f567f1abf0e12241cc63c2edbf90da6a4778a 100644 (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;
index 022fcd90c471f58755c4e11ef0615e3245712a71..50354c5128b6c74bbbb09a193f4b8cfe552a50bd 100644 (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;
 }
 
index 56452c473c5b2ab71668b067313a909e6c973782..9d7e13f5246596b70ed57b9f6a8cd76054a3f820 100644 (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" },
index 6c2cb807cd2196f182a9cc224825b464cd57de6b..01ed1d9c51f07cb103770db85f7c71851da74752 100644 (file)
@@ -120,6 +120,8 @@ public:
    * Cleanup data structure
    */
   void clear() { buckets.clear(); }
+
+  size_t count() { return buckets.size(); }
 };
 WRITE_CLASS_ENCODER(RGWUserBuckets)