cout << " object unlink unlink object from bucket index\n";
cout << " object rewrite rewrite the specified object\n";
cout << " objects expire run expired objects cleanup\n";
+ cout << " objects expire-stale list list stale expired objects (caused by reshard)\n";
+ cout << " objects expire-stale rm remove stale expired objects\n";
cout << " period rm remove a period\n";
cout << " period get get period info\n";
cout << " period get-current get current period info\n";
OPT_OBJECT_STAT,
OPT_OBJECT_REWRITE,
OPT_OBJECTS_EXPIRE,
+ OPT_OBJECTS_EXPIRE_STALE_LIST,
+ OPT_OBJECTS_EXPIRE_STALE_RM,
OPT_BI_GET,
OPT_BI_PUT,
OPT_BI_LIST,
strcmp(cmd, "datalog") == 0 ||
strcmp(cmd, "error") == 0 ||
strcmp(cmd, "event") == 0 ||
+ strcmp(cmd, "expire-stale") == 0 ||
strcmp(cmd, "gc") == 0 ||
strcmp(cmd, "global") == 0 ||
strcmp(cmd, "key") == 0 ||
} else if (strcmp(prev_cmd, "objects") == 0) {
if (strcmp(cmd, "expire") == 0)
return OPT_OBJECTS_EXPIRE;
+ } else if ((prev_prev_cmd && strcmp(prev_prev_cmd, "objects") == 0) &&
+ (strcmp(prev_cmd, "expire-stale") == 0)) {
+ if (strcmp(cmd, "list") == 0)
+ return OPT_OBJECTS_EXPIRE_STALE_LIST;
+ if (strcmp(cmd, "rm") == 0)
+ return OPT_OBJECTS_EXPIRE_STALE_RM;
} else if (strcmp(prev_cmd, "olh") == 0) {
if (strcmp(cmd, "get") == 0)
return OPT_OLH_GET;
}
}
+ if (opt_cmd == OPT_OBJECTS_EXPIRE_STALE_LIST) {
+ ret = RGWBucketAdminOp::fix_obj_expiry(store, bucket_op, f, true);
+ if (ret < 0) {
+ cerr << "ERROR: listing returned " << cpp_strerror(-ret) << std::endl;
+ return -ret;
+ }
+ }
+
+ if (opt_cmd == OPT_OBJECTS_EXPIRE_STALE_RM) {
+ ret = RGWBucketAdminOp::fix_obj_expiry(store, bucket_op, f, false);
+ if (ret < 0) {
+ cerr << "ERROR: removing returned " << cpp_strerror(-ret) << std::endl;
+ return -ret;
+ }
+ }
+
if (opt_cmd == OPT_BUCKET_REWRITE) {
if (bucket_name.empty()) {
cerr << "ERROR: bucket not specified" << std::endl;
return 0;
}
-
int RGWBucket::policy_bl_to_stream(bufferlist& bl, ostream& o)
{
RGWAccessControlPolicy_S3 policy(g_ceph_context);
- auto iter = bl.cbegin();
- try {
- policy.decode(iter);
- } catch (buffer::error& err) {
- dout(0) << "ERROR: caught buffer::error, could not decode policy" << dendl;
- return -EIO;
+ int ret = decode_bl(bl, policy);
+ if (ret < 0) {
+ ldout(store->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl;
}
policy.to_xml(o);
return 0;
}
-static int policy_decode(RGWRados *store, bufferlist& bl, RGWAccessControlPolicy& policy)
+int rgw_object_get_attr(RGWRados* store, const RGWBucketInfo& bucket_info,
+ const rgw_obj& obj, const char* attr_name,
+ bufferlist& out_bl)
{
- auto iter = bl.cbegin();
- try {
- policy.decode(iter);
- } catch (buffer::error& err) {
- ldout(store->ctx(), 0) << "ERROR: caught buffer::error, could not decode policy" << dendl;
- return -EIO;
- }
- return 0;
+ RGWObjectCtx obj_ctx(store);
+ RGWRados::Object op_target(store, bucket_info, obj_ctx, obj);
+ RGWRados::Object::Read rop(&op_target);
+
+ return rop.get_attr(attr_name, out_bl);
}
int RGWBucket::get_policy(RGWBucketAdminOpState& op_state, RGWAccessControlPolicy& policy)
std::string object_name = op_state.get_object_name();
rgw_bucket bucket = op_state.get_bucket();
auto sysobj_ctx = store->svc.sysobj->init_obj_ctx();
- RGWObjectCtx obj_ctx(store);
RGWBucketInfo bucket_info;
map<string, bufferlist> attrs;
bufferlist bl;
rgw_obj obj(bucket, object_name);
- RGWRados::Object op_target(store, bucket_info, obj_ctx, obj);
- RGWRados::Object::Read rop(&op_target);
-
- int ret = rop.get_attr(RGW_ATTR_ACL, bl);
- if (ret < 0)
+ ret = rgw_object_get_attr(store, bucket_info, obj, RGW_ATTR_ACL, bl);
+ if (ret < 0){
return ret;
+ }
- return policy_decode(store, bl, policy);
+ ret = decode_bl(bl, policy);
+ if (ret < 0) {
+ ldout(store->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl;
+ }
+ return ret;
}
map<string, bufferlist>::iterator aiter = attrs.find(RGW_ATTR_ACL);
return -ENOENT;
}
- return policy_decode(store, aiter->second, policy);
+ ret = decode_bl(aiter->second, policy);
+ if (ret < 0) {
+ ldout(store->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl;
+ }
+
+ return ret;
}
}
+static bool has_object_expired(RGWRados *store, const RGWBucketInfo& bucket_info,
+ const rgw_obj_key& key, utime_t& delete_at)
+{
+ rgw_obj obj(bucket_info.bucket, key);
+ bufferlist delete_at_bl;
+
+ int ret = rgw_object_get_attr(store, bucket_info, obj, RGW_ATTR_DELETE_AT, delete_at_bl);
+ if (ret < 0) {
+ return false; // no delete at attr, proceed
+ }
+
+ ret = decode_bl(delete_at_bl, delete_at);
+ if (ret < 0) {
+ return false; // failed to parse
+ }
+
+ if (delete_at <= ceph_clock_now() && !delete_at.is_zero()) {
+ return true;
+ }
+
+ return false;
+}
+
+static int fix_bucket_obj_expiry(RGWRados *store, const RGWBucketInfo& bucket_info,
+ RGWFormatterFlusher& flusher, bool dry_run)
+{
+ if (bucket_info.bucket.bucket_id == bucket_info.bucket.marker) {
+ lderr(store->ctx()) << "Not a resharded bucket skipping" << dendl;
+ return 0; // not a resharded bucket, move along
+ }
+
+ Formatter *formatter = flusher.get_formatter();
+ formatter->open_array_section("expired_deletion_status");
+ auto sg = make_scope_guard([&formatter] {
+ formatter->close_section();
+ formatter->flush(std::cout);
+ });
+
+ RGWRados::Bucket target(store, bucket_info);
+ RGWRados::Bucket::List list_op(&target);
+
+ list_op.params.list_versions = bucket_info.versioned();
+ list_op.params.allow_unordered = true;
+
+ constexpr auto max_objects = 1000;
+ bool is_truncated {false};
+ do {
+ std::vector<rgw_bucket_dir_entry> objs;
+
+ int ret = list_op.list_objects(max_objects, &objs, nullptr, &is_truncated);
+ if (ret < 0) {
+ lderr(store->ctx()) << "ERROR failed to list objects in the bucket" << dendl;
+ return ret;
+ }
+ for (const auto& obj : objs) {
+ rgw_obj_key key(obj.key);
+ utime_t delete_at;
+ if (has_object_expired(store, bucket_info, key, delete_at)) {
+ formatter->open_object_section("object_status");
+ formatter->dump_string("object", key.name);
+ formatter->dump_stream("delete_at") << delete_at;
+
+ if (!dry_run) {
+ ret = rgw_remove_object(store, bucket_info, bucket_info.bucket, key);
+ formatter->dump_int("status", ret);
+ }
+
+ formatter->close_section(); // object_status
+ }
+ }
+ formatter->flush(cout); // regularly flush every 1k entries
+ } while (is_truncated);
+
+ return 0;
+}
+
+int RGWBucketAdminOp::fix_obj_expiry(RGWRados *store, RGWBucketAdminOpState& op_state,
+ RGWFormatterFlusher& flusher, bool dry_run)
+{
+ RGWBucket admin_bucket;
+ int ret = admin_bucket.init(store, op_state);
+ if (ret < 0) {
+ lderr(store->ctx()) << "failed to initialize bucket" << dendl;
+ return ret;
+ }
+
+ return fix_bucket_obj_expiry(store, admin_bucket.get_bucket_info(), flusher, dry_run);
+}
+
void rgw_data_change::dump(Formatter *f) const
{
string type;