diff options
author | shreyanshjain7174 <ssanchet@redhat.com> | 2024-08-05 09:44:52 +0200 |
---|---|---|
committer | Soumya Koduri <skoduri@redhat.com> | 2024-10-03 10:28:43 +0200 |
commit | 1b66bc527eb2ffa26a13816b4de310b3c25d8ace (patch) | |
tree | 24e08ee92d963016a91c84b518ff85ccd428b632 /src/rgw | |
parent | cloud restore: completing read through (diff) | |
download | ceph-1b66bc527eb2ffa26a13816b4de310b3c25d8ace.tar.xz ceph-1b66bc527eb2ffa26a13816b4de310b3c25d8ace.zip |
RGW: Cloud Restore cli and its corresponding response for user.
* For first and repititive request 202 Accepted will be corresponding response code.
* For CloudRestored status 200 OK will be corresponding response code.
* For conflicting requests 409 Conflict corresponding response code.
Also Fixed storage class update while listing objects.
Earlier while restoring object temporarily list-objects (s3api) and
radosgw-admin bucket list didn't have updated storage class. With this
fixed it now has the cloudtier storage class.
Signed-off-by: shreyanshjain7174 <ssanchet@redhat.com>
Diffstat (limited to 'src/rgw')
-rw-r--r-- | src/rgw/driver/rados/rgw_rados.cc | 24 | ||||
-rw-r--r-- | src/rgw/rgw_op.cc | 67 | ||||
-rw-r--r-- | src/rgw/rgw_op.h | 18 | ||||
-rw-r--r-- | src/rgw/rgw_op_type.h | 1 | ||||
-rw-r--r-- | src/rgw/rgw_rest.h | 6 | ||||
-rw-r--r-- | src/rgw/rgw_rest_s3.cc | 104 | ||||
-rw-r--r-- | src/rgw/rgw_rest_s3.h | 10 |
7 files changed, 230 insertions, 0 deletions
diff --git a/src/rgw/driver/rados/rgw_rados.cc b/src/rgw/driver/rados/rgw_rados.cc index 868a798b79a..693d464d731 100644 --- a/src/rgw/driver/rados/rgw_rados.cc +++ b/src/rgw/driver/rados/rgw_rados.cc @@ -3213,6 +3213,30 @@ int RGWRados::Object::Write::_do_write_meta(uint64_t size, uint64_t accounted_si op.setxattr(RGW_ATTR_STORAGE_CLASS, bl); } + /* For temporary restored copies, storage-class returned + * in GET/list-objects should correspond to original + * cloudtier storage class. For GET its handled in its REST + * response by verifying RESTORE_TYPE in attrs. But the same + * cannot be done for list-objects response and hence this + * needs to be updated in bi entry itself. + */ + auto attr_iter = attrs.find(RGW_ATTR_RESTORE_TYPE); + if (attr_iter != attrs.end()) { + rgw::sal::RGWRestoreType rt; + bufferlist bl = attr_iter->second; + auto iter = bl.cbegin(); + decode(rt, iter); + + if (rt == rgw::sal::RGWRestoreType::Temporary) { + // temporary restore; set storage-class to cloudtier storage class + auto c_iter = attrs.find(RGW_ATTR_CLOUDTIER_STORAGE_CLASS); + + if (c_iter != attrs.end()) { + storage_class = rgw_bl_str(c_iter->second); + } + } + } + if (!op.size()) return 0; diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 0ac92fe2877..67829e6320a 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -5246,6 +5246,73 @@ void RGWPutMetadataObject::execute(optional_yield y) op_ret = s->object->set_obj_attrs(this, &attrs, &rmattrs, s->yield, rgw::sal::FLAG_LOG_OP); } +int RGWRestoreObj::init_processing(optional_yield y) +{ + int op_ret = get_params(y); + if (op_ret < 0) { + return op_ret; + } + + return RGWOp::init_processing(y); +} + +int RGWRestoreObj::verify_permission(optional_yield y) +{ + if (!verify_bucket_permission(this, s, ARN(s->object->get_obj()), + rgw::IAM::s3RestoreObject)) { + return -EACCES; + } + + return 0; +} + +void RGWRestoreObj::pre_exec() +{ + rgw_bucket_object_pre_exec(s); +} + +void RGWRestoreObj::execute(optional_yield y) +{ + if (!s->bucket_exists) { + op_ret = -ERR_NO_SUCH_BUCKET; + return; + } + + s->object->set_atomic(); + int op_ret = s->object->get_obj_attrs(y, this); + if (op_ret < 0) { + ldpp_dout(this, 1) << "failed to fetch get_obj_attrs op ret = " << op_ret << dendl; + return; + } + rgw::sal::Attrs attrs = s->object->get_attrs(); + auto attr_iter = attrs.find(RGW_ATTR_MANIFEST); + if (attr_iter != attrs.end()) { + RGWObjManifest m; + decode(m, attr_iter->second); + RGWObjTier tier_config; + m.get_tier_config(&tier_config); + if (m.get_tier_type() == "cloud-s3") { + ldpp_dout(this, 20) << "execute: expiry days" << expiry_days <<dendl; + op_ret = handle_cloudtier_obj(s, this, driver, attrs, false, expiry_days, true, y); + if (op_ret < 0) { + ldpp_dout(this, 4) << "Cannot get cloud tiered object: " << *s->object + <<". Failing with " << op_ret << dendl; + if (op_ret == -ERR_INVALID_OBJECT_STATE) { + s->err.message = "This object was transitioned to cloud-s3"; + } + } + } else { + ldpp_dout(this, 20) << "not cloud tier object erroring" << dendl; + op_ret = -ERR_INVALID_OBJECT_STATE; + } + } else { + ldpp_dout(this, 20) << " manifest not found" << dendl; + } + ldpp_dout(this, 20) << "completed restore" << dendl; + + return; +} + int RGWDeleteObj::handle_slo_manifest(bufferlist& bl, optional_yield y) { RGWSLOInfo slo_info; diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h index 47a4c3da609..df05500a437 100644 --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@ -1461,6 +1461,24 @@ public: virtual bool need_object_expiration() { return false; } }; +class RGWRestoreObj : public RGWOp { +protected: + std::optional<uint64_t> expiry_days; +public: + RGWRestoreObj() {} + + int init_processing(optional_yield y) override; + int verify_permission(optional_yield y) override; + void pre_exec() override; + void execute(optional_yield y) override; + virtual int get_params(optional_yield y) {return 0;} + + void send_response() override = 0; + const char* name() const override { return "restore_obj"; } + RGWOpType get_type() override { return RGW_OP_RESTORE_OBJ; } + uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; } +}; + class RGWDeleteObj : public RGWOp { protected: bool delete_marker; diff --git a/src/rgw/rgw_op_type.h b/src/rgw/rgw_op_type.h index 12291d64cb3..f0c3b072e47 100644 --- a/src/rgw/rgw_op_type.h +++ b/src/rgw/rgw_op_type.h @@ -25,6 +25,7 @@ enum RGWOpType { RGW_OP_PUT_METADATA_BUCKET, RGW_OP_PUT_METADATA_OBJECT, RGW_OP_SET_TEMPURL, + RGW_OP_RESTORE_OBJ, RGW_OP_DELETE_OBJ, RGW_OP_COPY_OBJ, RGW_OP_GET_ACLS, diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h index fae60c50f4d..3abba0124a6 100644 --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@ -318,6 +318,12 @@ public: ~RGWPutMetadataObject_ObjStore() override {} }; +class RGWRestoreObj_ObjStore : public RGWRestoreObj { +public: + RGWRestoreObj_ObjStore() {} + ~RGWRestoreObj_ObjStore() override {} +}; + class RGWDeleteObj_ObjStore : public RGWDeleteObj { public: RGWDeleteObj_ObjStore() {} diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 0289aca6773..6df57b39fea 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -3451,6 +3451,106 @@ int RGWPostObj_ObjStore_S3::get_encrypt_filter( return res; } +struct RestoreObjectRequest { + std::optional<uint64_t> days; + + void decode_xml(XMLObj *obj) { + RGWXMLDecoder::decode_xml("Days", days, obj); + } + + void dump_xml(Formatter *f) const { + encode_xml("Days", days, f); + } +}; + +int RGWRestoreObj_ObjStore_S3::get_params(optional_yield y) +{ + std::string expected_bucket_owner; + + if (s->info.env->get("x-amz-expected-bucket-owner") != nullptr) { + expected_bucket_owner = s->info.env->get("x-amz-expected-bucket-owner"); + } + + const auto max_size = s->cct->_conf->rgw_max_put_param_size; + + RGWXMLDecoder::XMLParser parser; + int r = 0; + bufferlist data; + std::tie(r, data) = read_all_input(s, max_size, false); + + if (r < 0) { + return r; + } + + if(!parser.init()) { + return -EINVAL; + } + + if (!parser.parse(data.c_str(), data.length(), 1)) { + return -ERR_MALFORMED_XML; + } + + RestoreObjectRequest request; + + try { + RGWXMLDecoder::decode_xml("RestoreRequest", request, &parser); + } + catch (RGWXMLDecoder::err &err) { + ldpp_dout(this, 5) << "Malformed restore request: " << err << dendl; + return -EINVAL; + } + + if (request.days) { + expiry_days = request.days.value(); + ldpp_dout(this, 10) << "expiry_days=" << expiry_days << dendl; + } else { + expiry_days=nullopt; + ldpp_dout(this, 10) << "expiry_days=" << expiry_days << dendl; + } + + return 0; +} + +void RGWRestoreObj_ObjStore_S3::send_response() +{ + if (op_ret < 0) + { + set_req_state_err(s, op_ret); + dump_errno(s); + end_header(s, this); + dump_start(s); + return; + } + + rgw::sal::Attrs attrs = s->object->get_attrs(); + auto attr_iter = attrs.find(RGW_ATTR_RESTORE_STATUS); + rgw::sal::RGWRestoreStatus restore_status; + if (attr_iter != attrs.end()) { + bufferlist bl = attr_iter->second; + auto iter = bl.cbegin(); + decode(restore_status, iter); + } + ldpp_dout(this, 10) << "restore_status=" << restore_status << dendl; + + if (attr_iter == attrs.end() || restore_status != rgw::sal::RGWRestoreStatus::None) { + s->err.http_ret = 202; //Accepted + dump_header(s, "x-amz-restore", rgw_bl_str(restore_status)); + } else if (restore_status != rgw::sal::RGWRestoreStatus::RestoreAlreadyInProgress) { + s->err.http_ret = 409; // Conflict + dump_header_if_nonempty(s, "x-amz-restore", rgw_bl_str(restore_status)); + } else if (restore_status != rgw::sal::RGWRestoreStatus::CloudRestored) { + s->err.http_ret = 200; // OK + dump_header_if_nonempty(s, "x-amz-restore", rgw_bl_str(restore_status)); + } else { + s->err.http_ret = 202; // Accepted + dump_header_if_nonempty(s, "x-amz-restore", rgw_bl_str(restore_status)); + } + + dump_errno(s); + end_header(s, this); + dump_start(s); +} + int RGWDeleteObj_ObjStore_S3::get_params(optional_yield y) { const char *if_unmod = s->info.env->get("HTTP_X_AMZ_DELETE_IF_UNMODIFIED_SINCE"); @@ -4910,6 +5010,9 @@ RGWOp *RGWHandler_REST_Obj_S3::op_post() if (s->info.args.exists("uploads")) return new RGWInitMultipart_ObjStore_S3; + if (s->info.args.exists("restore")) + return new RGWRestoreObj_ObjStore_S3; + if (is_select_op()) return rgw::s3select::create_s3select_op(); @@ -5961,6 +6064,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s, case RGW_OP_PUT_BUCKET_TAGGING: case RGW_OP_PUT_BUCKET_REPLICATION: case RGW_OP_PUT_LC: + case RGW_OP_RESTORE_OBJ: case RGW_OP_SET_REQUEST_PAYMENT: case RGW_OP_PUBSUB_NOTIF_CREATE: case RGW_OP_PUBSUB_NOTIF_DELETE: diff --git a/src/rgw/rgw_rest_s3.h b/src/rgw/rgw_rest_s3.h index d86123a2525..63909f57036 100644 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@ -327,6 +327,16 @@ public: rgw::sal::DataProcessor *cb) override; }; +class RGWRestoreObj_ObjStore_S3 : public RGWRestoreObj_ObjStore { + +public: + RGWRestoreObj_ObjStore_S3() {} + ~RGWRestoreObj_ObjStore_S3() override {} + + int get_params(optional_yield y) override; + void send_response() override; +}; + class RGWDeleteObj_ObjStore_S3 : public RGWDeleteObj_ObjStore { public: RGWDeleteObj_ObjStore_S3() {} |