summaryrefslogtreecommitdiffstats
path: root/src/rgw
diff options
context:
space:
mode:
authorshreyanshjain7174 <ssanchet@redhat.com>2024-08-05 09:44:52 +0200
committerSoumya Koduri <skoduri@redhat.com>2024-10-03 10:28:43 +0200
commit1b66bc527eb2ffa26a13816b4de310b3c25d8ace (patch)
tree24e08ee92d963016a91c84b518ff85ccd428b632 /src/rgw
parentcloud restore: completing read through (diff)
downloadceph-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.cc24
-rw-r--r--src/rgw/rgw_op.cc67
-rw-r--r--src/rgw/rgw_op.h18
-rw-r--r--src/rgw/rgw_op_type.h1
-rw-r--r--src/rgw/rgw_rest.h6
-rw-r--r--src/rgw/rgw_rest_s3.cc104
-rw-r--r--src/rgw/rgw_rest_s3.h10
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() {}