diff options
Diffstat (limited to '')
-rw-r--r-- | src/rgw/rgw_rest_ratelimit.cc | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/src/rgw/rgw_rest_ratelimit.cc b/src/rgw/rgw_rest_ratelimit.cc new file mode 100644 index 000000000..b482b4f82 --- /dev/null +++ b/src/rgw/rgw_rest_ratelimit.cc @@ -0,0 +1,349 @@ +// -*- 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 = driver->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 = driver->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 = driver->get_zone()->get_realm_id(); + RGWPeriodConfig period_config; + op_ret = period_config.read(this, static_cast<rgw::sal::RadosStore*>(driver)->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 = driver->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 = driver->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 = driver->get_zone()->get_realm_id(); + RGWPeriodConfig period_config; + op_ret = period_config.read(s, static_cast<rgw::sal::RadosStore*>(driver)->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*>(driver)->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*>(driver)->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*>(driver)->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; +} |