From: Shilpa Jagannath Date: Wed, 30 Jul 2025 19:48:32 +0000 (-0400) Subject: rgw/multisite: forward create_key request to master, fetch the newly created key X-Git-Tag: testing/wip-pdonnell-testing-20260323.122957-tentacle~608 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=49a37eeb4d022c4662e04bd580e7cb4f4dd0675a;p=ceph-ci.git rgw/multisite: forward create_key request to master, fetch the newly created key and store it on secondary. also, include 'create_date' in the user info response to help identify timestamp of each key. Signed-off-by: Shilpa Jagannath (cherry picked from commit e46f3324791c8b6d82d3c40be4b0803538d9cb61) --- diff --git a/PendingReleaseNotes b/PendingReleaseNotes index ef4f558c402..68ba361bca9 100644 --- a/PendingReleaseNotes +++ b/PendingReleaseNotes @@ -26,6 +26,8 @@ * RGW: Bucket resharding now does most of its processing before it starts to block write operations. This should significantly reduce the client-visible impact of resharding on large buckets. +* RGW: 'create_key' admin API's response only includes the latest key created instead + of all keys. * RBD: All Python APIs that produce timestamps now return "aware" `datetime` objects instead of "naive" ones (i.e. those including time zone information diff --git a/qa/suites/rgw/multisite/tasks/test_multi.yaml b/qa/suites/rgw/multisite/tasks/test_multi.yaml index 422535db609..e7a16c99f25 100644 --- a/qa/suites/rgw/multisite/tasks/test_multi.yaml +++ b/qa/suites/rgw/multisite/tasks/test_multi.yaml @@ -15,3 +15,6 @@ tasks: - rgw-multisite-tests: config: reconfigure_delay: 90 +- radosgw-admin-rest: + admin-client: c1.client.0 # create user on master zone + rest-client: c2.client.0 # send admin api requests to secondary zone diff --git a/src/rgw/driver/rados/rgw_rest_user.cc b/src/rgw/driver/rados/rgw_rest_user.cc index 43206f58c83..18c0386c15b 100644 --- a/src/rgw/driver/rados/rgw_rest_user.cc +++ b/src/rgw/driver/rados/rgw_rest_user.cc @@ -35,7 +35,13 @@ int fetch_access_keys_from_master(const DoutPrefixProvider* dpp, req_state* s, } RGWUserInfo ui; - ui.decode_json(&jp); + try { + ui.decode_json(&jp); + } catch (const JSONDecoder::err& e) { + cout << "failed to decode JSON input: " << e.what() << std::endl; + return -EINVAL; + } + keys = std::move(ui.access_keys); create_date = ui.create_date; return 0; @@ -719,9 +725,6 @@ void RGWOp_Key_Create::execute(optional_yield y) op_state.access_key_active = active; } - if (gen_key) - op_state.set_generate_key(); - if (!key_type_str.empty()) { int32_t key_type = KEY_TYPE_UNDEFINED; if (key_type_str.compare("swift") == 0) @@ -732,6 +735,34 @@ void RGWOp_Key_Create::execute(optional_yield y) op_state.set_key_type(key_type); } + if (!s->penv.site->is_meta_master()) { + bufferlist data; + JSONParser jp; + int ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + &data, &jp, s->info, s->err, y); + if (ret < 0) { + ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << ret << dendl; + return; + } + + RGWAccessKey key; + try { + key.decode_json(&jp); + } catch (const JSONDecoder::err& e) { + cout << "failed to decode JSON input: " << e.what() << std::endl; + ret = -EINVAL; + return; + } + op_state.op_master_key = std::move(key); + + // set_generate_key() is not set if keys have already been fetched from master zone + gen_key = false; + } + + if (gen_key) { + op_state.set_generate_key(); + } + op_ret = RGWUserAdminOp_Key::create(s, driver, op_state, flusher, y); } @@ -779,6 +810,13 @@ void RGWOp_Key_Remove::execute(optional_yield y) op_state.set_key_type(key_type); } + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + nullptr, nullptr, s->info, s->err, y); + if (op_ret < 0) { + ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; + return; + } + op_ret = RGWUserAdminOp_Key::remove(s, driver, op_state, flusher, y); } diff --git a/src/rgw/driver/rados/rgw_user.cc b/src/rgw/driver/rados/rgw_user.cc index cce593c6bd5..ac202823c11 100644 --- a/src/rgw/driver/rados/rgw_user.cc +++ b/src/rgw/driver/rados/rgw_user.cc @@ -106,11 +106,30 @@ static void dump_access_keys_info(Formatter *f, RGWUserInfo &info) f->dump_string("access_key", k.id); f->dump_string("secret_key", k.key); f->dump_bool("active", k.active); + encode_json("create_date", k.create_date, f); f->close_section(); } f->close_section(); } + +static void dump_master_key(Formatter *f, RGWUserInfo &info) +{ + f->open_object_section("user_info"); + RGWAccessKey& k = info.master_key; + const char *sep = (k.subuser.empty() ? "" : ":"); + const char *subuser = (k.subuser.empty() ? "" : k.subuser.c_str()); + string s; + info.user_id.to_str(s); + f->dump_format("user", "%s%s%s", s.c_str(), sep, subuser); + f->dump_string("access_key", k.id); + f->dump_string("secret_key", k.key); + f->dump_bool("active", k.active); + encode_json("create_date", k.create_date, f); + f->close_section(); +} + + static void dump_swift_keys_info(Formatter *f, RGWUserInfo &info) { map::iterator kiter; @@ -264,6 +283,7 @@ int RGWAccessKeyPool::init(RGWUserAdminOpState& op_state) swift_keys = op_state.get_swift_keys(); access_keys = op_state.get_access_keys(); + master_key = op_state.get_master_key(); keys_allowed = true; @@ -344,6 +364,11 @@ map* RGWUserAdminOpState::get_access_keys() return &user->get_info().access_keys; } +RGWAccessKey *RGWUserAdminOpState::get_master_key() +{ + return &user->get_info().master_key; +} + map* RGWUserAdminOpState::get_subusers() { return &user->get_info().subusers; @@ -489,7 +514,7 @@ int RGWAccessKeyPool::check_op(RGWUserAdminOpState& op_state, /* see if the access key was specified */ if (key_type == KEY_TYPE_S3 && !op_state.will_gen_access() && - op_state.get_access_key().empty()) { + op_state.get_access_key().empty() && op_state.get_master_access_key().empty()) { set_err_msg(err_msg, "empty access key"); return -ERR_INVALID_ACCESS_KEY; } @@ -591,7 +616,7 @@ int RGWAccessKeyPool::generate_key(const DoutPrefixProvider *dpp, RGWUserAdminOp //Secret key if (!gen_secret) { - if (op_state.get_secret_key().empty()) { + if (op_state.get_secret_key().empty() && op_state.get_master_secret_key().empty()) { set_err_msg(err_msg, "empty secret key"); return -ERR_INVALID_SECRET_KEY; } @@ -625,8 +650,6 @@ int RGWAccessKeyPool::generate_key(const DoutPrefixProvider *dpp, RGWUserAdminOp } // finally create the new key - new_key.id = id; - new_key.key = key; if (op_state.create_date) { new_key.create_date = *op_state.create_date; @@ -635,7 +658,16 @@ int RGWAccessKeyPool::generate_key(const DoutPrefixProvider *dpp, RGWUserAdminOp } if (key_type == KEY_TYPE_S3) { - access_keys->emplace(id, new_key); + if (!op_state.get_master_access_key().empty()) { + // use the key fetched from master + new_key = op_state.op_master_key; + access_keys->emplace(new_key.id, new_key); + } else { + new_key.id = id; + new_key.key = key; + access_keys->emplace(id, new_key); + } + *master_key = new_key; } else if (key_type == KEY_TYPE_SWIFT) { swift_keys->emplace(id, new_key); } @@ -2610,8 +2642,9 @@ int RGWUserAdminOp_Key::create(const DoutPrefixProvider *dpp, if (key_type == KEY_TYPE_SWIFT) dump_swift_keys_info(formatter, info); - else if (key_type == KEY_TYPE_S3) - dump_access_keys_info(formatter, info); + else if (key_type == KEY_TYPE_S3) { + dump_master_key(formatter, info); + } flusher.flush(); } diff --git a/src/rgw/driver/rados/rgw_user.h b/src/rgw/driver/rados/rgw_user.h index 4ae7d13eff7..bda4858b296 100644 --- a/src/rgw/driver/rados/rgw_user.h +++ b/src/rgw/driver/rados/rgw_user.h @@ -145,8 +145,10 @@ struct RGWUserAdminOpState { // key_attributes std::string id; // access key std::string key; // secret key - // access keys fetched for a user in the middle of an op + // access keys fetched for a user in the middle of a create_user op std::map op_access_keys; + // access key fetched for a user in the middle of a create_key op + RGWAccessKey op_master_key; int32_t key_type{-1}; bool access_key_exist = false; std::optional access_key_active; @@ -445,6 +447,8 @@ struct RGWUserAdminOpState { std::string get_subuser() { return subuser; } std::string get_access_key() { return id; } std::string get_secret_key() { return key; } + std::string get_master_access_key() { return op_master_key.id; } + std::string get_master_secret_key() { return op_master_key.key; } std::string get_caps() { return caps; } std::string get_user_email() { return user_email; } std::string get_display_name() { return display_name; } diff --git a/src/rgw/rgw_common.cc b/src/rgw/rgw_common.cc index 50057d144ee..290f73d0c7e 100644 --- a/src/rgw/rgw_common.cc +++ b/src/rgw/rgw_common.cc @@ -2852,7 +2852,6 @@ void RGWUserInfo::dump(Formatter *f) const encode_json_map("subusers", NULL, "subuser", NULL, user_info_dump_subuser,(void *)this, subusers, f); encode_json_map("keys", NULL, "key", NULL, user_info_dump_key,(void *)this, access_keys, f); encode_json_map("swift_keys", NULL, "key", NULL, user_info_dump_swift_key,(void *)this, swift_keys, f); - encode_json("caps", caps, f); char buf[256];