* 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
- 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
}
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;
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)
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);
}
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);
}
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<string, RGWAccessKey>::iterator kiter;
swift_keys = op_state.get_swift_keys();
access_keys = op_state.get_access_keys();
+ master_key = op_state.get_master_key();
keys_allowed = true;
return &user->get_info().access_keys;
}
+RGWAccessKey *RGWUserAdminOpState::get_master_key()
+{
+ return &user->get_info().master_key;
+}
+
map<std::string, RGWSubUser>* RGWUserAdminOpState::get_subusers()
{
return &user->get_info().subusers;
/* 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;
}
//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;
}
}
// 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;
}
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);
}
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();
}
// 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<std::string, RGWAccessKey> 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<bool> access_key_active;
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; }
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];