From: Yehuda Sadeh Date: Wed, 15 Jan 2014 22:35:57 +0000 (-0800) Subject: rgw: implement restful set user quota request X-Git-Tag: v0.78~270^2~4 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=8a69ac89e29ed29ed3b164d620b38c51fff584c2;p=ceph.git rgw: implement restful set user quota request Signed-off-by: Yehuda Sadeh --- diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h index 15ac863aa52d..28b8a911cb31 100644 --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@ -2,6 +2,8 @@ #define CEPH_RGW_REST_H #define TIME_BUF_SIZE 128 +#include "common/ceph_json.h" +#include "include/assert.h" /* needed because of common/ceph_json.h */ #include "rgw_op.h" #include "rgw_formats.h" @@ -18,6 +20,41 @@ extern void rgw_flush_formatter(struct req_state *s, extern int rgw_rest_read_all_input(struct req_state *s, char **data, int *plen, int max_len); +template +int rgw_rest_get_json_input(CephContext *cct, req_state *s, T& out, int max_len, bool *empty) +{ + int rv, data_len; + char *data; + + if (empty) + *empty = false; + + if ((rv = rgw_rest_read_all_input(s, &data, &data_len, max_len)) < 0) { + return rv; + } + + if (!data_len) { + if (empty) { + *empty = true; + } + + return -EINVAL; + } + + JSONParser parser; + + if (!parser.parse(data, data_len)) { + free(data); + return -EINVAL; + } + + decode_json_obj(out, &parser); + + free(data); + return 0; +} + + class RESTArgs { public: static int get_string(struct req_state *s, const string& name, const string& def_val, string *val, bool *existed = NULL); diff --git a/src/rgw/rgw_rest_replica_log.cc b/src/rgw/rgw_rest_replica_log.cc index 2543f32fba6e..e7dd962f0f76 100644 --- a/src/rgw/rgw_rest_replica_log.cc +++ b/src/rgw/rgw_rest_replica_log.cc @@ -38,29 +38,6 @@ static int parse_to_utime(string& in, utime_t& out) { } -template -static int get_input(req_state *s, T& out) { - int rv, data_len; - char *data; - - if ((rv = rgw_rest_read_all_input(s, &data, &data_len, REPLICA_INPUT_MAX_LEN)) < 0) { - dout(5) << "Error - reading input data - " << rv << dendl; - return rv; - } - - JSONParser parser; - - if (!parser.parse(data, data_len)) { - free(data); - return -EINVAL; - } - - decode_json_obj(out, &parser); - - free(data); - return 0; -} - void RGWOp_OBJLog_SetBounds::execute() { string id_str = s->info.args.get("id"), marker = s->info.args.get("marker"), @@ -97,7 +74,8 @@ void RGWOp_OBJLog_SetBounds::execute() { bufferlist bl; list markers; - if ((http_ret = get_input(s, markers)) < 0) { + if ((http_ret = rgw_rest_get_json_input(store->ctx(), s, markers, REPLICA_INPUT_MAX_LEN, NULL)) < 0) { + dout(5) << "Error - retrieving input data - " << http_ret << dendl; return; } @@ -211,7 +189,8 @@ void RGWOp_BILog_SetBounds::execute() { bufferlist bl; list markers; - if ((http_ret = get_input(s, markers)) < 0) { + if ((http_ret = rgw_rest_get_json_input(store->ctx(), s, markers, REPLICA_INPUT_MAX_LEN, NULL)) < 0) { + dout(5) << "Error - retrieving input data - " << http_ret << dendl; return; } diff --git a/src/rgw/rgw_rest_user.cc b/src/rgw/rgw_rest_user.cc index 759997fa69be..0613c49f3145 100644 --- a/src/rgw/rgw_rest_user.cc +++ b/src/rgw/rgw_rest_user.cc @@ -615,6 +615,8 @@ struct UserQuotas { RGWQuotaInfo bucket_quota; RGWQuotaInfo user_quota; + UserQuotas() {} + UserQuotas(RGWUserInfo& info) { bucket_quota = info.bucket_quota; user_quota = info.user_quota; @@ -654,6 +656,11 @@ void RGWOp_Quota_Info::execute() RESTArgs::get_string(s, "uid", uid, &uid); RESTArgs::get_string(s, "quota-type", quota_type, "a_type); + if (uid.empty()) { + http_ret = -EINVAL; + return; + } + bool show_all = quota_type.empty(); bool show_bucket = show_all || (quota_type == "bucket"); bool show_user = show_all || (quota_type == "user"); @@ -663,7 +670,6 @@ void RGWOp_Quota_Info::execute() return; } - op_state.set_user_id(uid); RGWUser user; @@ -689,6 +695,179 @@ void RGWOp_Quota_Info::execute() flusher.flush(); } +class RGWOp_Quota_Set : public RGWRESTOp { + +public: + RGWOp_Quota_Set() {} + + int check_caps(RGWUserCaps& caps) { + return caps.check_cap("users", RGW_CAP_WRITE); + } + + void execute(); + + virtual const string name() { return "set_quota_info"; } +}; + +/** + * set quota + * + * two different ways to set the quota info: as json struct in the message body or via http params. + * + * as json: + * + * PUT /admin/user?uid=["a-type=] + * + * whereas quota-type is optional and is either user, or bucket + * + * if quota-type is not specified then we expect to get a structure that contains both quotas, + * otherwise we'll only get the relevant configuration. + * + * E.g., if quota type not specified: + * { + * "user_quota" : { + * "max_size_kb" : 4096, + * "max_objects" : -1, + * "enabled" : false + * }, + * "bucket_quota" : { + * "max_size_kb" : 1024, + * "max_objects" : -1, + * "enabled" : true + * } + * } + * + * + * or if quota type is specified: + * { + * "max_size_kb" : 4096, + * "max_objects" : -1, + * "enabled" : false + * } + * + * Another option is not to pass any body and set the following http params: + * + * + * max-size-kb= + * max-objects= + * enabled[={true,false}] + * + * all params are optionals and default to the current settings. With this type of configuration the + * quota-type param is mandatory. + * + */ + +void RGWOp_Quota_Set::execute() +{ + RGWUserAdminOpState op_state; + + std::string uid; + std::string quota_type; + + RESTArgs::get_string(s, "uid", uid, &uid); + RESTArgs::get_string(s, "quota-type", quota_type, "a_type); + + if (uid.empty()) { + http_ret = -EINVAL; + return; + } + + bool set_all = quota_type.empty(); + bool set_bucket = set_all || (quota_type == "bucket"); + bool set_user = set_all || (quota_type == "user"); + + if (!(set_all || set_bucket || set_user)) { + ldout(store->ctx(), 20) << "invalid quota type" << dendl; + http_ret = -EINVAL; + return; + } + + bool use_http_params; + + if (s->length > 0) { + use_http_params = false; + } else { + const char *encoding = s->info.env->get("HTTP_TRANSFER_ENCODING"); + use_http_params = (!encoding || strcmp(encoding, "chunked") != 0); + } + + if (use_http_params && set_all) { + ldout(store->ctx(), 20) << "quota type was not specified, can't set all quotas via http headers" << dendl; + http_ret = -EINVAL; + return; + } + + op_state.set_user_id(uid); + + RGWUser user; + http_ret = user.init(store, op_state); + if (http_ret < 0) { + ldout(store->ctx(), 20) << "failed initializing user info: " << http_ret << dendl; + return; + } + +#define QUOTA_INPUT_MAX_LEN 1024 + if (set_all) { + UserQuotas quotas; + + if ((http_ret = rgw_rest_get_json_input(store->ctx(), s, quotas, QUOTA_INPUT_MAX_LEN, NULL)) < 0) { + ldout(store->ctx(), 20) << "failed to retrieve input" << dendl; + return; + } + + op_state.set_user_quota(quotas.user_quota); + op_state.set_bucket_quota(quotas.bucket_quota); + } else { + RGWQuotaInfo quota; + + if (!use_http_params) { + bool empty; + http_ret = rgw_rest_get_json_input(store->ctx(), s, quota, QUOTA_INPUT_MAX_LEN, &empty); + if (http_ret < 0) { + ldout(store->ctx(), 20) << "failed to retrieve input" << dendl; + if (!empty) + return; + + /* was probably chunked input, but no content provided, configure via http params */ + use_http_params = true; + } + } + + if (use_http_params) { + RGWUserInfo info; + string err_msg; + http_ret = user.info(info, &err_msg); + if (http_ret < 0) { + ldout(store->ctx(), 20) << "failed to get user info: " << http_ret << dendl; + return; + } + RGWQuotaInfo *old_quota; + if (set_user) { + old_quota = &info.user_quota; + } else { + old_quota = &info.bucket_quota; + } + + RESTArgs::get_int64(s, "max-objects", old_quota->max_objects, "a.max_objects); + RESTArgs::get_int64(s, "max-size-kb", old_quota->max_size_kb, "a.max_size_kb); + RESTArgs::get_bool(s, "enabled", old_quota->enabled, "a.enabled); + } + + if (set_user) { + op_state.set_user_quota(quota); + } else { + op_state.set_bucket_quota(quota); + } + } + + string err; + http_ret = user.modify(op_state, &err); + if (http_ret < 0) { + ldout(store->ctx(), 20) << "failed updating user info: " << http_ret << ": " << err << dendl; + return; + } +} + RGWOp *RGWHandler_User::op_get() { if (s->info.args.sub_resource_exists("quota"))