+Rate Limit
+==========
+
+The Admin Operations API enables you to set and get ratelimit configurations on users and on bucket and global rate limit configurations. See `Rate Limit Management`_ for additional details.
+Rate Limit includes the maximum number of operations and/or bytes per minute, separated by read and/or write, to a bucket and/or by a user and the maximum storage size in megabytes.
+
+To view rate limit, the user must have a ``ratelimit=read`` capability. To set,
+modify or disable a ratelimit, the user must have ``ratelimit=write`` capability.
+See the `Admin Guide`_ for details.
+
+Valid parameters for quotas include:
+
+- **Bucket:** The ``bucket`` option allows you to specify a rate limit for
+ a bucket.
+
+- **User:** The ``uid`` option allows you to specify a rate limit for a user.
+
+- **Maximum Read Bytes:** The ``max-read-bytes`` setting allows you to specify
+ the maximum number of read bytes per minute. A 0 value disables this setting.
+
+- **Maximum Write Bytes:** The ``max-write-bytes`` setting allows you to specify
+ the maximum number of write bytes per minute. A 0 value disables this setting.
+
+- **Maximum Read Ops:** The ``max-read-ops`` setting allows you to specify
+ the maximum number of read ops per minute. A 0 value disables this setting.
+
+- **Maximum Write Ops:** The ``max-write-ops`` setting allows you to specify
+ the maximum number of write ops per minute. A 0 value disables this setting.
+
+- **Global:** The ``global`` option allows you to specify a global rate limit.
+ The value should be either 'True' or 'False'.
+
+- **Rate Limit Scope:** The ``ratelimit-scope`` option sets the scope for the rate limit.
+ The options are ``bucket`` , ``user`` and ``anonymous``.
+ ``anonymous`` is only valid for setting global configuration
+
+- **Enable/Disable Rate Limit:** The ``enabled`` option specifies whether the
+ rate limit should be enabled. The value should be either 'True' or 'False'.
+
+Get User Rate Limit
+~~~~~~~~~~~~~~~~~~~
+
+To get a rate limit, the user must have ``ratelimit`` capability set with ``read``
+permission. ::
+
+ GET /{admin}/ratelimit?ratelimit-scope=user&uid=<uid>
+
+
+Set User Rate Limit
+~~~~~~~~~~~~~~~~~~~
+
+To set a rate limit, the user must have ``ratelimit`` capability set with ``write``
+permission. ::
+
+ POST /{admin}/ratelimit?ratelimit-scope=user&uid=<uid><[&max-read-bytes=<bytes>][&max-write-bytes=<bytes>][&max-read-ops=<ops>][&max-write-ops=<ops>][enabled=<True|False>]>
+
+
+
+Get Bucket Rate Limit
+~~~~~~~~~~~~~~~~~~~~~
+
+To get a rate limit, the user must have ``users`` capability set with ``read``
+permission. ::
+
+ GET /{admin}/ratelimit?bucket=<bucket>&ratelimit-scope=bucket
+
+
+
+Set Rate Limit for an Individual Bucket
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To set a rate limit, the user must have ``ratelimit`` capability set with ``write``
+permission. ::
+
+ POST /{admin}/ratelimit?bucket=<bucket-name>&ratelimit-scope=bucket<[&max-read-bytes=<bytes>][&max-write-bytes=<bytes>][&max-read-ops=<ops>][&max-write-ops=<ops>]>
+
+
+
+Get Global Rate Limit
+~~~~~~~~~~~~~~~~~~~~~
+
+To get a global rate limit, the user must have ``ratelimit`` capability set with ``read``
+permission. ::
+
+ GET /{admin}/ratelimit?global=<True|False>
+
+
+
+Set Global User Rate Limit
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To set a rate limit, the user must have ``ratelimit`` capability set with ``write``
+permission. ::
+
+ POST /{admin}/ratelimit?ratelimit-scope=user&global=<True|False><[&max-read-bytes=<bytes>][&max-write-bytes=<bytes>][&max-read-ops=<ops>][&max-write-ops=<ops>][enabled=<True|False>]>
+
+
+
+Set Global Rate Limit Bucket
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To set a rate limit, the user must have ``ratelimit`` capability set with ``write``
+permission. ::
+
+ POST /{admin}/ratelimit?ratelimit-scope=bucket&global=<True|False><[&max-read-bytes=<bytes>][&max-write-bytes=<bytes>][&max-read-ops=<ops>][&max-write-ops=<ops>]>
+
+
+
+Set Global Anonymous User Rate Limit
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To set a rate limit, the user must have ``ratelimit`` capability set with ``write``
+permission. ::
+
+ POST /{admin}/ratelimit?ratelimit-scope=anon&global=<True|False><[&max-read-bytes=<bytes>][&max-write-bytes=<bytes>][&max-read-ops=<ops>][&max-write-ops=<ops>][enabled=<True|False>]>
+
+
+
Standard Error Responses
========================
.. _Admin Guide: ../admin
.. _Quota Management: ../admin#quota-management
+.. _Rate Limit Management: ../admin#rate-limit-management
.. _IrekFasikhov/go-rgwadmin: https://github.com/IrekFasikhov/go-rgwadmin
.. _QuentinPerez/go-radosgw: https://github.com/QuentinPerez/go-radosgw
.. _twonote/radosgw-admin4j: https://github.com/twonote/radosgw-admin4j
return 'usage', ''
elif cmd[0] == 'info':
return 'info', ''
+ elif cmd[0] == 'ratelimit':
+ return 'ratelimit', ''
elif cmd[0] == 'zone' or cmd[0] in zone_sub_resources:
if cmd[0] == 'zone':
return 'zone', ''
admin_display_name = 'Ms. Admin User'
admin_access_key = 'MH1WC2XQ1S8UISFDZC8W'
admin_secret_key = 'dQyrTPA0s248YeN5bBv4ukvKU0kh54LWWywkrpoG'
- admin_caps = 'users=read, write; usage=read, write; buckets=read, write; zone=read, write; info=read'
+ admin_caps = 'users=read, write; usage=read, write; buckets=read, write; zone=read, write; info=read;ratelimit=read, write'
user1 = 'foo'
user2 = 'fud'
+ ratelimit_user = 'ratelimit_user'
subuser1 = 'foo:foo1'
subuser2 = 'foo:foo2'
display_name1 = 'Foo'
assert len(name) > 0
# fsid is a uuid, but I'm not going to try to parse it
assert len(fsid) > 0
+
+ # TESTCASE 'ratelimit' 'user' 'info' 'succeeds'
+ (ret, out) = rgwadmin_rest(admin_conn,
+ ['user', 'create'],
+ {'uid' : ratelimit_user,
+ 'display-name' : display_name1,
+ 'email' : email,
+ 'access-key' : access_key,
+ 'secret-key' : secret_key,
+ 'max-buckets' : '1000'
+ })
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'info'], {'ratelimit-scope' : 'user', 'uid' : ratelimit_user})
+ assert ret == 200
+
+ # TESTCASE 'ratelimit' 'user' 'info' 'not existing user' 'fails'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'info'], {'ratelimit-scope' : 'user', 'uid' : ratelimit_user + 'string'})
+ assert ret == 404
+
+ # TESTCASE 'ratelimit' 'user' 'info' 'uid not specified' 'fails'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'info'], {'ratelimit-scope' : 'user'})
+ assert ret == 400
+
+ # TESTCASE 'ratelimit' 'bucket' 'info' 'succeeds'
+ ratelimit_bucket = 'ratelimitbucket'
+ connection.create_bucket(ratelimit_bucket)
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'info'], {'ratelimit-scope' : 'bucket', 'bucket' : ratelimit_bucket})
+ assert ret == 200
+
+ # TESTCASE 'ratelimit' 'bucket' 'info' 'not existing bucket' 'fails'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'info'], {'ratelimit-scope' : 'bucket', 'bucket' : ratelimit_bucket + 'string'})
+ assert ret == 404
+
+ # TESTCASE 'ratelimit' 'bucket' 'info' 'bucket not specified' 'fails'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'info'], {'ratelimit-scope' : 'bucket'})
+ assert ret == 400
+
+ # TESTCASE 'ratelimit' 'global' 'info' 'succeeds'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'info'], {'global' : 'true'})
+ assert ret == 200
+
+ # TESTCASE 'ratelimit' 'user' 'modify' 'not existing user' 'fails'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'modify'], {'ratelimit-scope' : 'user', 'uid' : ratelimit_user + 'string', 'enabled' : 'true'})
+ assert ret == 404
+
+ # TESTCASE 'ratelimit' 'user' 'modify' 'uid not specified' 'fails'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'modify'], {'ratelimit-scope' : 'user'})
+ assert ret == 400
+
+ # TESTCASE 'ratelimit' 'bucket' 'modify' 'not existing bucket' 'fails'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'modify'], {'ratelimit-scope' : 'bucket', 'bucket' : ratelimit_bucket + 'string', 'enabled' : 'true'})
+ assert ret == 404
+
+ # TESTCASE 'ratelimit' 'bucket' 'modify' 'bucket not specified' 'fails'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'modify'], {'ratelimit-scope' : 'bucket', 'enabled' : 'true'})
+ assert ret == 400
+
+ # TESTCASE 'ratelimit' 'user' 'modifiy' 'enabled' 'max-read-bytes = 2' 'succeeds'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'modify'], {'ratelimit-scope' : 'user', 'uid' : ratelimit_user, 'enabled' : 'true', 'max-read-bytes' : '2'})
+ assert ret == 200
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'info'], {'ratelimit-scope' : 'user', 'uid' : ratelimit_user})
+ assert ret == 200
+ user_ratelimit = out['user_ratelimit']
+ assert user_ratelimit['enabled'] == True
+ assert user_ratelimit['max_read_bytes'] == 2
+
+ # TESTCASE 'ratelimit' 'bucket' 'modifiy' 'enabled' 'max-write-bytes = 2' 'succeeds'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'modify'], {'ratelimit-scope' : 'bucket', 'bucket' : ratelimit_bucket, 'enabled' : 'true', 'max-write-bytes' : '2'})
+ assert ret == 200
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'info'], {'ratelimit-scope' : 'bucket', 'bucket' : ratelimit_bucket})
+ assert ret == 200
+ bucket_ratelimit = out['bucket_ratelimit']
+ assert bucket_ratelimit['enabled'] == True
+ assert bucket_ratelimit['max_write_bytes'] == 2
+
+ # TESTCASE 'ratelimit' 'global' 'modify' 'anonymous' 'enabled' 'succeeds'
+ (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'modify'], {'ratelimit-scope' : 'bucket', 'global': 'true', 'enabled' : 'true'})
+ assert ret == 200
\ No newline at end of file
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab ft=cpp
+#include "rgw_rest_ratelimit.h"
+class RGWOp_Ratelimit_Info : public RGWRESTOp {
+int check_caps(const RGWUserCaps& caps) override {
+ return caps.check_cap("ratelimit", RGW_CAP_READ);
+}
+
+ void execute(optional_yield y) override;
+
+ const char* name() const override { return "get_ratelimit_info"; }
+};
+void RGWOp_Ratelimit_Info::execute(optional_yield y)
+{
+ ldpp_dout(this, 20) << "" << dendl;
+ std::string uid_str;
+ std::string ratelimit_scope;
+ std::string bucket_name;
+ std::string tenant_name;
+ bool global = false;
+ RESTArgs::get_string(s, "uid", uid_str, &uid_str);
+ RESTArgs::get_string(s, "ratelimit-scope", ratelimit_scope, &ratelimit_scope);
+ RESTArgs::get_string(s, "bucket", bucket_name, &bucket_name);
+ RESTArgs::get_string(s, "tenant", tenant_name, &tenant_name);
+ // RESTArgs::get_bool default value to true even if global is empty
+ bool exists;
+ std::string sval = s->info.args.get("global", &exists);
+ if (exists) {
+ if (!boost::iequals(sval,"true") && !boost::iequals(sval,"false")) {
+ op_ret = -EINVAL;
+ ldpp_dout(this, 20) << "global is not equal to true or false" << dendl;
+ return;
+ }
+ }
+ RESTArgs::get_bool(s, "global", false, &global);
+
+ if (ratelimit_scope == "bucket" && !bucket_name.empty() && !global) {
+ std::unique_ptr<rgw::sal::Bucket> bucket;
+ int r = store->get_bucket(s, nullptr, tenant_name, bucket_name, &bucket, y);
+ if (r != 0) {
+ op_ret = r;
+ ldpp_dout(this, 0) << "Error on getting bucket info" << dendl;
+ return;
+ }
+ RGWRateLimitInfo ratelimit_info;
+ auto iter = bucket->get_attrs().find(RGW_ATTR_RATELIMIT);
+ if (iter != bucket->get_attrs().end()) {
+ try {
+ bufferlist& bl = iter->second;
+ auto biter = bl.cbegin();
+ decode(ratelimit_info, biter);
+ } catch (buffer::error& err) {
+ ldpp_dout(this, 0) << "Error on decoding ratelimit info from bucket" << dendl;
+ op_ret = -EIO;
+ return;
+ }
+ }
+ flusher.start(0);
+ s->formatter->open_object_section("bucket_ratelimit");
+ encode_json("bucket_ratelimit", ratelimit_info, s->formatter);
+ s->formatter->close_section();
+ flusher.flush();
+ return;
+ }
+ if (ratelimit_scope == "user" && !uid_str.empty() && !global) {
+ RGWRateLimitInfo ratelimit_info;
+ rgw_user user(uid_str);
+ std::unique_ptr<rgw::sal::User> user_sal;
+ user_sal = store->get_user(user);
+ if (!rgw::sal::User::empty(user_sal)) {
+ op_ret = user_sal->load_user(this, y);
+ if (op_ret) {
+ ldpp_dout(this, 0) << "Cannot load user info" << dendl;
+ return;
+ }
+ } else {
+ ldpp_dout(this, 0) << "User does not exist" << dendl;
+ op_ret = -ENOENT;
+ return;
+ }
+
+ auto iter = user_sal->get_attrs().find(RGW_ATTR_RATELIMIT);
+ if(iter != user_sal->get_attrs().end()) {
+ try {
+ bufferlist& bl = iter->second;
+ auto biter = bl.cbegin();
+ decode(ratelimit_info, biter);
+ } catch (buffer::error& err) {
+ ldpp_dout(this, 0) << "Error on decoding ratelimit info from user" << dendl;
+ op_ret = -EIO;
+ return;
+ }
+ }
+ flusher.start(0);
+ s->formatter->open_object_section("user_ratelimit");
+ encode_json("user_ratelimit", ratelimit_info, s->formatter);
+ s->formatter->close_section();
+ flusher.flush();
+ }
+ if (global) {
+ std::string realm_id = store->get_zone()->get_realm().get_id();
+ RGWPeriodConfig period_config;
+ op_ret = period_config.read(this, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm_id, y);
+ if (op_ret && op_ret != -ENOENT) {
+ ldpp_dout(this, 0) << "Error on period config read" << dendl;
+ return;
+ }
+ flusher.start(0);
+ s->formatter->open_object_section("period_config");
+ encode_json("bucket_ratelimit", period_config.bucket_ratelimit, s->formatter);
+ encode_json("user_ratelimit", period_config.user_ratelimit, s->formatter);
+ encode_json("anonymous_ratelimit", period_config.anon_ratelimit, s->formatter);
+ s->formatter->close_section();
+ flusher.flush();
+ return;
+ }
+ op_ret = -EINVAL;
+ return;
+}
+
+class RGWOp_Ratelimit_Set : public RGWRESTOp {
+ int check_caps(const RGWUserCaps& caps) override {
+ return caps.check_cap("ratelimit", RGW_CAP_WRITE);
+ }
+
+ void execute(optional_yield y) override;
+
+ const char* name() const override { return "put_ratelimit_info"; }
+
+ void set_ratelimit_info(bool have_max_read_ops, int64_t max_read_ops, bool have_max_write_ops, int64_t max_write_ops,
+ bool have_max_read_bytes, int64_t max_read_bytes, bool have_max_write_bytes, int64_t max_write_bytes,
+ bool have_enabled, bool enabled, bool& ratelimit_configured, RGWRateLimitInfo& ratelimit_info);
+};
+
+
+ void RGWOp_Ratelimit_Set::set_ratelimit_info(bool have_max_read_ops, int64_t max_read_ops, bool have_max_write_ops, int64_t max_write_ops,
+ bool have_max_read_bytes, int64_t max_read_bytes, bool have_max_write_bytes, int64_t max_write_bytes,
+ bool have_enabled, bool enabled, bool& ratelimit_configured, RGWRateLimitInfo& ratelimit_info)
+ {
+ if (have_max_read_ops) {
+ if (max_read_ops >= 0) {
+ ratelimit_info.max_read_ops = max_read_ops;
+ ratelimit_configured = true;
+ }
+ }
+ if (have_max_write_ops) {
+ if (max_write_ops >= 0) {
+ ratelimit_info.max_write_ops = max_write_ops;
+ ratelimit_configured = true;
+ }
+ }
+ if (have_max_read_bytes) {
+ if (max_read_bytes >= 0) {
+ ratelimit_info.max_read_bytes = max_read_bytes;
+ ratelimit_configured = true;
+ }
+ }
+ if (have_max_write_bytes) {
+ if (max_write_bytes >= 0) {
+ ratelimit_info.max_write_bytes = max_write_bytes;
+ ratelimit_configured = true;
+ }
+ }
+ if (have_enabled) {
+ ratelimit_info.enabled = enabled;
+ ratelimit_configured = true;
+ }
+ if (!ratelimit_configured) {
+ ldpp_dout(this, 0) << "No rate limit configuration arguments have been sent" << dendl;
+ op_ret = -EINVAL;
+ return;
+ }
+
+ }
+
+
+void RGWOp_Ratelimit_Set::execute(optional_yield y)
+{
+ std::string uid_str;
+ std::string ratelimit_scope;
+ std::string bucket_name;
+ std::string tenant_name;
+ RGWRateLimitInfo ratelimit_info;
+ bool ratelimit_configured = false;
+ bool enabled = false;
+ bool have_enabled = false;
+ bool global = false;
+ int64_t max_read_ops = 0;
+ bool have_max_read_ops = false;
+ int64_t max_write_ops = 0;
+ bool have_max_write_ops = false;
+ int64_t max_read_bytes = 0;
+ bool have_max_read_bytes = false;
+ int64_t max_write_bytes = 0;
+ bool have_max_write_bytes = false;
+ RESTArgs::get_string(s, "uid", uid_str, &uid_str);
+ RESTArgs::get_string(s, "ratelimit-scope", ratelimit_scope, &ratelimit_scope);
+ RESTArgs::get_string(s, "bucket", bucket_name, &bucket_name);
+ RESTArgs::get_string(s, "tenant", tenant_name, &tenant_name);
+ // check there was no -EINVAL coming from get_int64
+ op_ret = RESTArgs::get_int64(s, "max-read-ops", 0, &max_read_ops, &have_max_read_ops);
+ op_ret |= RESTArgs::get_int64(s, "max-write-ops", 0, &max_write_ops, &have_max_write_ops);
+ op_ret |= RESTArgs::get_int64(s, "max-read-bytes", 0, &max_read_bytes, &have_max_read_bytes);
+ op_ret |= RESTArgs::get_int64(s, "max-write-bytes", 0, &max_write_bytes, &have_max_write_bytes);
+ if (op_ret) {
+ ldpp_dout(this, 0) << "one of the maximum arguments could not be parsed" << dendl;
+ return;
+ }
+ // RESTArgs::get_bool default value to true even if enabled or global are empty
+ std::string sval = s->info.args.get("enabled", &have_enabled);
+ if (have_enabled) {
+ if (!boost::iequals(sval,"true") && !boost::iequals(sval,"false")) {
+ ldpp_dout(this, 20) << "enabled is not equal to true or false" << dendl;
+ op_ret = -EINVAL;
+ return;
+ }
+ }
+ RESTArgs::get_bool(s, "enabled", false, &enabled, &have_enabled);
+ bool exists;
+ sval = s->info.args.get("global", &exists);
+ if (exists) {
+ if (!boost::iequals(sval,"true") && !boost::iequals(sval,"false")) {
+ ldpp_dout(this, 20) << "global is not equal to true or faslse" << dendl;
+ op_ret = -EINVAL;
+ return;
+ }
+ }
+ RESTArgs::get_bool(s, "global", false, &global, nullptr);
+ set_ratelimit_info(have_max_read_ops, max_read_ops, have_max_write_ops, max_write_ops,
+ have_max_read_bytes, max_read_bytes, have_max_write_bytes, max_write_bytes,
+ have_enabled, enabled, ratelimit_configured, ratelimit_info);
+ if (op_ret) {
+ return;
+ }
+ if (ratelimit_scope == "user" && !uid_str.empty() && !global) {
+ rgw_user user(uid_str);
+ std::unique_ptr<rgw::sal::User> user_sal;
+ user_sal = store->get_user(user);
+ if (!rgw::sal::User::empty(user_sal)) {
+ op_ret = user_sal->load_user(this, y);
+ if (op_ret) {
+ ldpp_dout(this, 0) << "Cannot load user info" << dendl;
+ return;
+ }
+ } else {
+ ldpp_dout(this, 0) << "User does not exist" << dendl;
+ op_ret = -ENOENT;
+ return;
+ }
+ auto iter = user_sal->get_attrs().find(RGW_ATTR_RATELIMIT);
+ if (iter != user_sal->get_attrs().end()) {
+ try {
+ bufferlist& bl = iter->second;
+ auto biter = bl.cbegin();
+ decode(ratelimit_info, biter);
+ } catch (buffer::error& err) {
+ ldpp_dout(this, 0) << "Error on decoding ratelimit info from user" << dendl;
+ op_ret = -EIO;
+ return;
+ }
+ }
+ set_ratelimit_info(have_max_read_ops, max_read_ops, have_max_write_ops, max_write_ops,
+ have_max_read_bytes, max_read_bytes, have_max_write_bytes, max_write_bytes,
+ have_enabled, enabled, ratelimit_configured, ratelimit_info);
+ bufferlist bl;
+ ratelimit_info.encode(bl);
+ rgw::sal::Attrs attr;
+ attr[RGW_ATTR_RATELIMIT] = bl;
+ op_ret = user_sal->merge_and_store_attrs(this, attr, y);
+ return;
+ }
+
+ if (ratelimit_scope == "bucket" && !bucket_name.empty() && !global) {
+ ldpp_dout(this, 0) << "getting bucket info" << dendl;
+ std::unique_ptr<rgw::sal::Bucket> bucket;
+ op_ret = store->get_bucket(this, nullptr, tenant_name, bucket_name, &bucket, y);
+ if (op_ret) {
+ ldpp_dout(this, 0) << "Error on getting bucket info" << dendl;
+ return;
+ }
+ auto iter = bucket->get_attrs().find(RGW_ATTR_RATELIMIT);
+ if (iter != bucket->get_attrs().end()) {
+ try {
+ bufferlist& bl = iter->second;
+ auto biter = bl.cbegin();
+ decode(ratelimit_info, biter);
+ } catch (buffer::error& err) {
+ ldpp_dout(this, 0) << "Error on decoding ratelimit info from bucket" << dendl;
+ op_ret = -EIO;
+ return;
+ }
+ }
+ bufferlist bl;
+ set_ratelimit_info(have_max_read_ops, max_read_ops, have_max_write_ops, max_write_ops,
+ have_max_read_bytes, max_read_bytes, have_max_write_bytes, max_write_bytes,
+ have_enabled, enabled, ratelimit_configured, ratelimit_info);
+ ratelimit_info.encode(bl);
+ rgw::sal::Attrs attr;
+ attr[RGW_ATTR_RATELIMIT] = bl;
+ op_ret = bucket->merge_and_store_attrs(this, attr, y);
+ return;
+ }
+ if (global) {
+ std::string realm_id = store->get_zone()->get_realm().get_id();
+ RGWPeriodConfig period_config;
+ op_ret = period_config.read(s, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm_id, y);
+ if (op_ret && op_ret != -ENOENT) {
+ ldpp_dout(this, 0) << "Error on period config read" << dendl;
+ return;
+ }
+ if (ratelimit_scope == "bucket") {
+ ratelimit_info = period_config.bucket_ratelimit;
+ set_ratelimit_info(have_max_read_ops, max_read_ops, have_max_write_ops, max_write_ops,
+ have_max_read_bytes, max_read_bytes, have_max_write_bytes, max_write_bytes,
+ have_enabled, enabled, ratelimit_configured, ratelimit_info);
+ period_config.bucket_ratelimit = ratelimit_info;
+ op_ret = period_config.write(s, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm_id, y);
+ return;
+ }
+ if (ratelimit_scope == "anon") {
+ ratelimit_info = period_config.anon_ratelimit;
+ set_ratelimit_info(have_max_read_ops, max_read_ops, have_max_write_ops, max_write_ops,
+ have_max_read_bytes, max_read_bytes, have_max_write_bytes, max_write_bytes,
+ have_enabled, enabled, ratelimit_configured, ratelimit_info);
+ period_config.anon_ratelimit = ratelimit_info;
+ op_ret = period_config.write(s, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm_id, y);
+ return;
+ }
+ if (ratelimit_scope == "user") {
+ ratelimit_info = period_config.user_ratelimit;
+ set_ratelimit_info(have_max_read_ops, max_read_ops, have_max_write_ops, max_write_ops,
+ have_max_read_bytes, max_read_bytes, have_max_write_bytes, max_write_bytes,
+ have_enabled, enabled, ratelimit_configured, ratelimit_info);
+ period_config.user_ratelimit = ratelimit_info;
+ op_ret = period_config.write(s, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm_id, y);
+ return;
+ }
+ }
+ op_ret = -EINVAL;
+ return;
+}
+RGWOp* RGWHandler_Ratelimit::op_get()
+{
+ return new RGWOp_Ratelimit_Info;
+}
+RGWOp* RGWHandler_Ratelimit::op_post()
+{
+ return new RGWOp_Ratelimit_Set;
+}
\ No newline at end of file