]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/account: add bucket_quota to RGWAccountInfo
authorCasey Bodley <cbodley@redhat.com>
Thu, 18 Apr 2024 16:14:14 +0000 (12:14 -0400)
committerCasey Bodley <cbodley@redhat.com>
Tue, 23 Apr 2024 16:36:57 +0000 (12:36 -0400)
support bucket quotas per account the same way as for user

Fixes: https://tracker.ceph.com/issues/65551
Signed-off-by: Casey Bodley <cbodley@redhat.com>
(cherry picked from commit b9677714b2a57e4f97ff87c9d654f4dddae3c2b2)

doc/radosgw/account.rst
src/rgw/rgw_account.cc
src/rgw/rgw_account.h
src/rgw/rgw_admin.cc
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_op.cc
src/test/cli/radosgw-admin/help.t

index 28c70fc0310731f20386d0da818a13c10a676199..15fb91c9e84bcbadf88495e0ee67986f22884994 100644 (file)
@@ -153,8 +153,13 @@ To view account stats::
 
 To enable an account quota::
 
-       radosgw-admin quota set --account-id={accountid} --max-size=10G
-       radosgw-admin quota enable --account-id={accountid}
+       radosgw-admin quota set --quota-scope=account --account-id={accountid} --max-size=10G
+       radosgw-admin quota enable --quota-scope=account --account-id={accountid}
+
+To enable a bucket quota for the account::
+
+       radosgw-admin quota set --quota-scope=bucket --account-id={accountid} --max-objects=1000000
+       radosgw-admin quota enable --quota-scope=bucket --account-id={accountid}
 
 Migrate an existing User into an Account
 ----------------------------------------
index 44aa9a3d4c7afde37b69df8e959876249645f3b6..d7e9acd7f5168b8378b34887d6bb51eb59cc460e 100644 (file)
@@ -227,14 +227,22 @@ int modify(const DoutPrefixProvider* dpp,
     info.max_buckets = *op_state.max_buckets;
   }
 
-  if (op_state.quota_max_size) {
-    info.quota.max_size = *op_state.quota_max_size;
-  }
-  if (op_state.quota_max_objects) {
-    info.quota.max_objects = *op_state.quota_max_objects;
-  }
-  if (op_state.quota_enabled) {
-    info.quota.enabled = *op_state.quota_enabled;
+  RGWQuotaInfo* pquota = nullptr;
+  if (op_state.quota_scope == "account") {
+    pquota = &info.quota;
+  } else if (op_state.quota_scope == "bucket") {
+    pquota = &info.bucket_quota;
+  }
+  if (pquota) {
+    if (op_state.quota_max_size) {
+      pquota->max_size = *op_state.quota_max_size;
+    }
+    if (op_state.quota_max_objects) {
+      pquota->max_objects = *op_state.quota_max_objects;
+    }
+    if (op_state.quota_enabled) {
+      pquota->enabled = *op_state.quota_enabled;
+    }
   }
 
   constexpr bool exclusive = false;
index f942d674b0ec5fa8fb8c11085f6e3af2a8cd0639..2a6f3e2379751a54ec39aeee9621b20f5c3b3d24 100644 (file)
@@ -49,6 +49,7 @@ struct AdminOpState {
   std::optional<int32_t> max_groups;
   std::optional<int32_t> max_access_keys;
   std::optional<int32_t> max_buckets;
+  std::string quota_scope;
   std::optional<int64_t> quota_max_size;
   std::optional<int64_t> quota_max_objects;
   std::optional<bool> quota_enabled;
index b9dc45a7418592bee4c7796b65ffc7a98668e3a4..ec439e6618fbf22acf34744f46703e9359133e78 100644 (file)
@@ -468,7 +468,7 @@ void usage()
   cout << "\nQuota options:\n";
   cout << "   --max-objects                 specify max objects (negative value to disable)\n";
   cout << "   --max-size                    specify max size (in B/K/M/G/T, negative value to disable)\n";
-  cout << "   --quota-scope                 scope of quota (bucket, user)\n";
+  cout << "   --quota-scope                 scope of quota (bucket, user, account)\n";
   cout << "\nRate limiting options:\n";
   cout << "   --max-read-ops                specify max requests per minute for READ ops per RGW (GET and HEAD request methods), 0 means unlimited\n";
   cout << "   --max-read-bytes              specify max bytes per minute for READ ops per RGW (GET and HEAD request methods), 0 means unlimited\n";
@@ -10666,6 +10666,13 @@ next:
       op_state.tenant = tenant;
       op_state.account_name = account_name;
 
+      if (quota_scope != "bucket" && quota_scope != "account") {
+        cerr << "ERROR: invalid quota scope specification. Please specify "
+            "either --quota-scope=bucket or --quota-scope=account" << std::endl;
+        return EINVAL;
+      }
+      op_state.quota_scope = quota_scope;
+
       if (opt_cmd == OPT::QUOTA_ENABLE) {
         op_state.quota_enabled = true;
       } else if (opt_cmd == OPT::QUOTA_DISABLE) {
index f5b834e0672d36720bb3901345db6a4bf4b8e52e..4c9203093487e5fa2320cae33c2b60d584dcf7ef 100644 (file)
@@ -3018,6 +3018,7 @@ void RGWAccountInfo::dump(Formatter * const f) const
   encode_json("name", name, f);
   encode_json("email", email, f);
   encode_json("quota", quota, f);
+  encode_json("bucket_quota", bucket_quota, f);
   encode_json("max_users", max_users, f);
   encode_json("max_roles", max_roles, f);
   encode_json("max_groups", max_groups, f);
@@ -3032,6 +3033,7 @@ void RGWAccountInfo::decode_json(JSONObj* obj)
   JSONDecoder::decode_json("name", name, obj);
   JSONDecoder::decode_json("email", email, obj);
   JSONDecoder::decode_json("quota", quota, obj);
+  JSONDecoder::decode_json("bucket_quota", bucket_quota, obj);
   JSONDecoder::decode_json("max_users", max_users, obj);
   JSONDecoder::decode_json("max_roles", max_roles, obj);
   JSONDecoder::decode_json("max_groups", max_groups, obj);
index 63e7f9eacc1f3849c2624f4b24731cd117be1123..c95acae4510eefa5b1dc9cf2683ad4b8bc2c515e 100644 (file)
@@ -787,6 +787,7 @@ struct RGWAccountInfo {
   std::string name;
   std::string email;
   RGWQuotaInfo quota;
+  RGWQuotaInfo bucket_quota;
 
   static constexpr int32_t DEFAULT_USER_LIMIT = 1000;
   int32_t max_users = DEFAULT_USER_LIMIT;
@@ -804,7 +805,7 @@ struct RGWAccountInfo {
   int32_t max_access_keys = DEFAULT_ACCESS_KEY_LIMIT;
 
   void encode(bufferlist& bl) const {
-    ENCODE_START(1, 1, bl);
+    ENCODE_START(2, 1, bl);
     encode(id, bl);
     encode(tenant, bl);
     encode(name, bl);
@@ -815,11 +816,12 @@ struct RGWAccountInfo {
     encode(max_groups, bl);
     encode(max_buckets, bl);
     encode(max_access_keys, bl);
+    encode(bucket_quota, bl);
     ENCODE_FINISH(bl);
   }
 
   void decode(bufferlist::const_iterator& bl) {
-    DECODE_START(1, bl);
+    DECODE_START(2, bl);
     decode(id, bl);
     decode(tenant, bl);
     decode(name, bl);
@@ -830,6 +832,9 @@ struct RGWAccountInfo {
     decode(max_groups, bl);
     decode(max_buckets, bl);
     decode(max_access_keys, bl);
+    if (struct_v >= 2) {
+      decode(bucket_quota, bl);
+    }
     DECODE_FINISH(bl);
   }
 
index 481e14b541647d8a3efeba82312380c1b31bfa9e..602280182d7a7f956538131f136cd0500277c29e 100644 (file)
@@ -1408,8 +1408,8 @@ static int get_owner_quota_info(DoutPrefixProvider* dpp,
         RGWObjVersionTracker objv; // ignored
         int r = driver->load_account_by_id(dpp, y, account_id, info, attrs, objv);
         if (r >= 0) {
-          // no bucket quota
           quotas.user_quota = info.quota;
+          quotas.bucket_quota = info.bucket_quota;
         }
         return r;
       }), owner);
index af29e827591dd10b0678c25f3491849c377bbf86..b334806398bb279b9a88be2c926e070724542340 100644 (file)
   Quota options:
      --max-objects                 specify max objects (negative value to disable)
      --max-size                    specify max size (in B/K/M/G/T, negative value to disable)
-     --quota-scope                 scope of quota (bucket, user)
+     --quota-scope                 scope of quota (bucket, user, account)
   
   Rate limiting options:
      --max-read-ops                specify max requests per minute for READ ops per RGW (GET and HEAD request methods), 0 means unlimited