Adding support for restore cli in admin ops, added existing clis list and statusw
Fixes: https://tracker.ceph.com/issues/70931
Signed-off-by: Jiffin Tony Thottan <thottanjiffin@gmail.com>
rgw_realm_watcher.cc
rgw_bucket_logging.cc
rgw_rest_bucket_logging.cc
- rgw_bucket_sync.cc)
+ rgw_bucket_sync.cc
+ rgw_rest_restore.cc)
list(APPEND librgw_common_srcs
driver/immutable_config/store.cc
#include "rgw_rest_realm.h"
#include "rgw_rest_ratelimit.h"
#include "rgw_rest_zero.h"
+#include "rgw_rest_restore.h"
#include "rgw_swift_auth.h"
#include "rgw_log.h"
#include "rgw_lib.h"
admin_resource->register_resource("info", new RGWRESTMgr_Info);
admin_resource->register_resource("usage", new RGWRESTMgr_Usage);
admin_resource->register_resource("account", new RGWRESTMgr_Account);
+ admin_resource->register_resource("restore", new RGWRESTMgr_Restore);
/* Register driver-specific admin APIs */
env.driver->register_admin_apis(admin_resource);
rest.register_resource(g_conf()->rgw_admin_entry, admin_resource);
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab ft=cpp
+
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright contributors to the Ceph project
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include "rgw_rest_restore.h"
+#include "rgw_restore.h"
+
+class RGWOp_Restore_Status : public RGWRESTOp {
+
+public:
+ RGWOp_Restore_Status() {}
+
+ int check_caps(const RGWUserCaps& caps) override {
+ return caps.check_cap("buckets", RGW_CAP_READ);
+ }
+
+ void execute(optional_yield y) override;
+
+ const char* name() const override { return "get_restore_status"; }
+};
+
+void RGWOp_Restore_Status::execute(optional_yield y)
+{
+ std::string bucket_name, tenant, object;
+ RESTArgs::get_string(s, "bucket", bucket_name, &bucket_name);
+ RESTArgs::get_string(s, "tenant", tenant, &tenant);
+ RESTArgs::get_string(s, "object", object, &object);
+ rgw::restore::RestoreEntry entry;
+
+ entry.bucket = rgw_bucket {tenant, bucket_name};
+ entry.obj_key = rgw_obj_key {object};
+
+ op_ret = driver->get_rgwrestore()->status(this, entry, s->err.message,
+ flusher, y);
+}
+
+class RGWOp_Restore_List : public RGWRESTOp {
+
+public:
+ RGWOp_Restore_List() {}
+
+ int check_caps(const RGWUserCaps& caps) override {
+ return caps.check_cap("buckets", RGW_CAP_READ);
+ }
+
+ void execute(optional_yield y) override;
+
+ const char* name() const override { return "get_restore_list"; }
+};
+
+void RGWOp_Restore_List::execute(optional_yield y)
+{
+ std::string bucket_name, tenant, restore_status_filter;
+ std::optional<std::string> restore_status_filter_optional;
+ bool exists = false;
+ RESTArgs::get_string(s, "bucket", bucket_name, &bucket_name);
+ RESTArgs::get_string(s, "tenant", tenant, &tenant);
+ RESTArgs::get_string(s, "restore-status-filter", "", &restore_status_filter, &exists);
+ rgw::restore::RestoreEntry entry;
+
+ entry.bucket = rgw_bucket {tenant, bucket_name};
+
+ if (exists) {
+ restore_status_filter_optional = restore_status_filter;
+ }
+
+ op_ret = driver->get_rgwrestore()->list(this, entry, restore_status_filter_optional,
+ s->err.message, flusher, y);
+}
+
+RGWOp* RGWHandler_Restore::op_get()
+{
+ if (s->info.args.sub_resource_exists("object"))
+ return new RGWOp_Restore_Status;
+
+ return new RGWOp_Restore_List;
+}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab ft=cpp
+
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright contributors to the Ceph project
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include "rgw_rest.h"
+#include "rgw_rest_s3.h"
+
+class RGWHandler_Restore : public RGWHandler_Auth_S3 {
+ protected:
+ RGWOp *op_get() override;
+ public:
+ using RGWHandler_Auth_S3::RGWHandler_Auth_S3;
+ ~RGWHandler_Restore() override = default;
+
+ int read_permissions(RGWOp*, optional_yield y) override {
+ return 0;
+ }
+};
+
+class RGWRESTMgr_Restore : public RGWRESTMgr {
+ public:
+ RGWRESTMgr_Restore() = default;
+ ~RGWRESTMgr_Restore() override = default;
+
+ RGWHandler_REST *get_handler(rgw::sal::Driver* driver, struct req_state*,
+ const rgw::auth::StrategyRegistry& auth_registry,
+ const std::string&) override {
+ return new RGWHandler_Restore(auth_registry);
+ }
+};
\ No newline at end of file
constexpr int32_t hours_in_a_day = 24;
constexpr int32_t secs_in_a_day = hours_in_a_day * 60 * 60;
+static constexpr size_t listing_max_entries = 1000;
using namespace std;
using namespace rgw::sal;
return ret;
}
+int Restore::list(const DoutPrefixProvider* dpp, RestoreEntry& entry,
+ std::optional<string> restore_status_filter,
+ std::string& err_msg, RGWFormatterFlusher& flusher, optional_yield y)
+{
+ int ret = 0;
+ std::unique_ptr<rgw::sal::Bucket> bucket;
+ ret = driver->load_bucket(dpp, entry.bucket, &bucket, y);
+ if (ret < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: could not init bucket: " << cpp_strerror(-ret) << dendl;
+ return ret;
+ }
+ rgw::sal::Bucket::ListParams params;
+ rgw::sal::Bucket::ListResults results;
+ params.list_versions = bucket->versioned();
+ params.allow_unordered = true;
+ flusher.start(0);
+ auto f = flusher.get_formatter();
+ f->open_object_section("restore_list");
+ do {
+ ret = bucket->list(dpp, params, listing_max_entries, results, y);
+ if (ret < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: driver->list_objects(): " << cpp_strerror(-ret) << dendl;
+ return ret;
+ }
+ for (vector<rgw_bucket_dir_entry>::iterator iter = results.objs.begin(); iter != results.objs.end(); ++iter) {
+ std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(iter->key.name);
+ if (obj) {
+ ret = obj->get_obj_attrs(y, dpp);
+ if (ret < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << dendl;
+ return -ret;
+ }
+ for (map<string, bufferlist>::iterator getattriter = obj->get_attrs().begin(); getattriter != obj->get_attrs().end(); ++getattriter) {
+ bufferlist& bl = getattriter->second;
+ if (getattriter->first == RGW_ATTR_RESTORE_STATUS) {
+ rgw::sal::RGWRestoreStatus rs;
+ {
+ using ceph::decode;
+ try {
+ decode(rs, bl);
+ } catch (const JSONDecoder::err& e) {
+ ldpp_dout(dpp, 0) << "failed to decode JSON input: " << e.what() << dendl;
+ return EINVAL;
+ }
+ }
+ if (restore_status_filter) {
+ if (restore_status_filter == rgw::sal::rgw_restore_status_dump(rs)) {
+ f->dump_string(iter->key.name, rgw::sal::rgw_restore_status_dump(rs));
+ }
+ } else {
+ f->dump_string(iter->key.name, rgw::sal::rgw_restore_status_dump(rs));
+ }
+ }
+ }
+ }
+ }
+ } while (results.is_truncated);
+ f->close_section();
+ flusher.flush();
+
+ return ret;
+}
+
+int Restore::status(const DoutPrefixProvider* dpp, RestoreEntry& entry,
+ std::string& err_msg, RGWFormatterFlusher& flusher,
+ optional_yield y)
+{
+ int ret = 0;
+ std::unique_ptr<rgw::sal::Bucket> bucket;
+ ret = driver->load_bucket(dpp, entry.bucket, &bucket, y);
+ if (ret < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: could not init bucket: " << cpp_strerror(-ret) << dendl;
+ return ret;
+ }
+ if (!entry.obj_key.name.empty()) {
+ flusher.start(0);
+ auto f = flusher.get_formatter();
+ f->open_object_section("object restore status");
+ f->dump_string("name", entry.obj_key.name);
+ std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(entry.obj_key);
+ ret = obj->get_obj_attrs(y, dpp);
+ if (ret < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << dendl;
+ return -ret;
+ }
+ map<string, bufferlist>::iterator iter;
+ for (iter = obj->get_attrs().begin(); iter != obj->get_attrs().end(); ++iter) {
+ bufferlist& bl = iter->second;
+ {
+ using ceph::decode;
+ if (iter->first == RGW_ATTR_RESTORE_STATUS) {
+ rgw::sal::RGWRestoreStatus rs;
+ try {
+ decode(rs, bl);
+ } catch (const JSONDecoder::err& e) {
+ ldpp_dout(dpp, 0) << "failed to decode JSON input: " << e.what() << dendl;
+ return EINVAL;
+ }
+ f->dump_string("RestoreStatus", rgw::sal::rgw_restore_status_dump(rs));
+ } else if (iter->first == RGW_ATTR_RESTORE_TYPE) {
+ rgw::sal::RGWRestoreType rt;
+ try {
+ decode(rt, bl);
+ } catch (const JSONDecoder::err& e) {
+ ldpp_dout(dpp, 0) << "failed to decode JSON input: " << e.what() << dendl;
+ return EINVAL;
+ }
+ f->dump_string("RestoreType", rgw::sal::rgw_restore_type_dump(rt));
+ } else if (iter->first == RGW_ATTR_RESTORE_EXPIRY_DATE) {
+ ceph::real_time restore_expiry_date;
+ try {
+ decode(restore_expiry_date, bl);
+ } catch (const JSONDecoder::err& e) {
+ ldpp_dout(dpp, 0) << "failed to decode JSON input: " << e.what() << dendl;
+ return EINVAL;
+ }
+ encode_json("RestoreExpiryDate", restore_expiry_date, f);
+ } else if (iter->first == RGW_ATTR_RESTORE_TIME) {
+ ceph::real_time restore_time;
+ try {
+ decode(restore_time, bl);
+ } catch (const JSONDecoder::err& e) {
+ ldpp_dout(dpp, 0) << "failed to decode JSON input: " << e.what() << dendl;
+ return EINVAL;
+ }
+ encode_json("RestoreTime", restore_time, f);
+ } else if (iter->first == RGW_ATTR_RESTORE_VERSIONED_EPOCH) {
+ uint64_t versioned_epoch;
+ try {
+ decode(versioned_epoch, bl);
+ } catch (const JSONDecoder::err& e) {
+ ldpp_dout(dpp, 0) << "failed to decode JSON input: " << e.what() << dendl;
+ return EINVAL;
+ }
+ f->dump_unsigned("RestoreVersionedEpoch", versioned_epoch);
+ }
+ }
+ }
+ f->close_section();
+ flusher.flush();
+ }
+
+ return ret;
+}
+
} // namespace rgw::restore
const std::string& version_id,
const rgw::notify::EventTypeList& event_types,
optional_yield y);
+ // list restore status of objects in the bucket
+ int list(const DoutPrefixProvider* dpp, RestoreEntry& entry,
+ std::optional<std::string> restore_status_filter, std::string& err_msg,
+ RGWFormatterFlusher& flusher, optional_yield y);
+
+ // restore status of an object in a bucket
+ int status(const DoutPrefixProvider* dpp, RestoreEntry& entry,
+ std::string& err_msg, RGWFormatterFlusher& flusher,
+ optional_yield y);
};
} // namespace rgw::restore