Skip to content

Commit 0059d5b

Browse files
committed
rgw/restore: Add notifications for restore events
The following notification events are added for restore operations as stated in https://docs.aws.amazon.com/AmazonS3/latest/userguide/notification-how-to-event-types-and-destinations.html s3:ObjectRestore:* s3:ObjectRestore:Post s3:ObjectRestore:Completed s3:ObjectRestore:Delete By using the ObjectRestore event types, you can receive notifications for event initiation and completion when restoring objects from the S3 Glacier Flexible Retrieval storage class, S3 Glacier Deep Archive storage class, S3 Intelligent-Tiering Archive Access tier, and S3 Intelligent-Tiering Deep Archive Access tier. You can also receive notifications for when the restored copy of an object expires. The s3:ObjectRestore:Post event type notifies you of object restoration initiation. The s3:ObjectRestore:Completed event type notifies you of restoration completion. The s3:ObjectRestore:Delete event type notifies you when the temporary copy of a restored object expires. Signed-off-by: Soumya Koduri <[email protected]>
1 parent 7cb2650 commit 0059d5b

File tree

7 files changed

+148
-11
lines changed

7 files changed

+148
-11
lines changed

doc/radosgw/s3-notification-compatibility.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,13 @@ Event Types
142142
+--------------------------------------------------------+-------------------------------------------+
143143
| ``s3:Replication:DeletionMarkerCreated`` | Defined, Supported (not generated) |
144144
+--------------------------------------------------------+-------------------------------------------+
145-
| ``s3:ObjectRestore:Post`` | Not applicable |
145+
| ``s3:ObjectRestore:*`` | Supported |
146146
+--------------------------------------------------------+-------------------------------------------+
147-
| ``s3:ObjectRestore:Complete`` | Not applicable |
147+
| ``s3:ObjectRestore:Post`` | Supported |
148+
+--------------------------------------------------------+-------------------------------------------+
149+
| ``s3:ObjectRestore:Completed`` | Supported |
150+
+--------------------------------------------------------+-------------------------------------------+
151+
| ``s3:ObjectRestore:Delete`` | Supported |
148152
+--------------------------------------------------------+-------------------------------------------+
149153
| ``s3:ReducedRedundancyLostObject`` | Not applicable |
150154
+--------------------------------------------------------+-------------------------------------------+

src/rgw/driver/rados/rgw_rados.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5693,7 +5693,8 @@ int RGWRados::restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
56935693
return ret;
56945694
}
56955695

5696-
return ret;
5696+
// this returned size can be used to send bucket notification
5697+
return accounted_size;
56975698
}
56985699

56995700
int RGWRados::check_bucket_empty(const DoutPrefixProvider *dpp, RGWBucketInfo& bucket_info, optional_yield y)

src/rgw/driver/rados/rgw_sal_rados.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3364,13 +3364,26 @@ int RadosObject::handle_obj_expiry(const DoutPrefixProvider* dpp, optional_yield
33643364
attrs[RGW_ATTR_INTERNAL_MTIME] = std::move(bl);
33653365
}
33663366
const req_context rctx{dpp, y, nullptr};
3367-
return obj_op.write_meta(0, 0, attrs, rctx, head_obj->get_trace(), false);
3367+
ret = obj_op.write_meta(0, 0, attrs, rctx, head_obj->get_trace(), false);
3368+
3369+
// send notification in case the temporary copy of restored obj is expired
3370+
if (!ret) { //send notification
3371+
string etag;
3372+
attr_iter = attrs.find(RGW_ATTR_ETAG);
3373+
if (attr_iter != attrs.end()) {
3374+
etag = rgw_bl_str(attr_iter->second);
3375+
}
3376+
store->get_rgwrestore()->send_notification(dpp, store, this, bucket, etag, 0,
3377+
get_obj().key.instance,
3378+
{rgw::notify::ObjectRestoreExpired}, y);
3379+
3380+
}
33683381
} catch (const buffer::end_of_buffer&) {
33693382
// ignore empty manifest; it's not cloud-tiered
33703383
} catch (const std::exception& e) {
33713384
}
33723385
}
3373-
return 0;
3386+
return ret;
33743387
}
33753388
}
33763389
// object is not restored/temporary; go for regular deletion

src/rgw/rgw_notify_event_type.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ namespace rgw::notify {
6666
return "s3:Replication:Delete";
6767
case ReplicationDeletionMarkerCreated:
6868
return "s3:Replication:DeletionMarkerCreated";
69+
case ObjectRestore:
70+
return "s3:ObjectRestore:*";
71+
case ObjectRestoreInitiated:
72+
return "s3:ObjectRestore:Post";
73+
case ObjectRestoreCompleted:
74+
return "s3:ObjectRestore:Completed";
75+
case ObjectRestoreExpired:
76+
return "s3:ObjectRestore:Delete";
6977
case UnknownEvent:
7078
return "s3:UnknownEvent";
7179
}
@@ -139,6 +147,14 @@ namespace rgw::notify {
139147
return ReplicationDelete;
140148
if (s == "s3:Replication:DeletionMarkerCreated")
141149
return ReplicationDeletionMarkerCreated;
150+
if (s =="s3:ObjectRestore:*")
151+
return ObjectRestore;
152+
if (s == "s3:ObjectRestore:Post")
153+
return ObjectRestoreInitiated;
154+
if (s == "s3:ObjectRestore:Completed")
155+
return ObjectRestoreCompleted;
156+
if (s == "s3:ObjectRestore:Delete")
157+
return ObjectRestoreExpired;
142158
return UnknownEvent;
143159
}
144160

src/rgw/rgw_notify_event_type.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ namespace rgw::notify {
3939
ReplicationCreate = 0x10000000,
4040
ReplicationDelete = 0x20000000,
4141
ReplicationDeletionMarkerCreated = 0x40000000,
42-
UnknownEvent = 0x100000000
42+
ObjectRestore = 0xF00000000,
43+
ObjectRestoreInitiated = 0x100000000,
44+
ObjectRestoreCompleted = 0x200000000,
45+
ObjectRestoreExpired = 0x400000000,
46+
UnknownEvent = 0x1000000000
4347
};
4448

4549
using EventTypeList = std::vector<EventType>;

src/rgw/rgw_restore.cc

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,43 @@ void RestoreEntry::generate_test_instances(std::list<RestoreEntry*>& l)
109109
l.push_back(new RestoreEntry);
110110
}
111111

112+
static std::string restore_id = "rgw restore";
113+
static std::string restore_req_id = "0";
114+
115+
void Restore::send_notification(const DoutPrefixProvider* dpp,
116+
rgw::sal::Driver* driver,
117+
rgw::sal::Object* obj,
118+
rgw::sal::Bucket* bucket,
119+
const std::string& etag,
120+
uint64_t size,
121+
const std::string& version_id,
122+
const rgw::notify::EventTypeList& event_types,
123+
optional_yield y) {
124+
// notification supported only for RADOS driver for now
125+
auto notify = driver->get_notification(
126+
dpp, obj, nullptr, event_types, bucket, restore_id,
127+
const_cast<std::string&>(bucket->get_tenant()), restore_req_id, y);
128+
129+
if (!notify) {
130+
return;
131+
}
132+
133+
int ret = notify->publish_reserve(dpp, nullptr);
134+
if (ret < 0) {
135+
ldpp_dout(dpp, 1) << "ERROR: notify publish_reserve failed with error: "
136+
<< ret << " for restore object: " << obj->get_name()
137+
<< " for event_types: " << event_types << dendl;
138+
return;
139+
}
140+
ret = notify->publish_commit(dpp, size, ceph::real_clock::now(), etag,
141+
version_id);
142+
if (ret < 0) {
143+
ldpp_dout(dpp, 5) << "WARNING: notify publish_commit failed with error: "
144+
<< ret << " for lc object: " << obj->get_name()
145+
<< " for event_types: " << event_types << dendl;
146+
}
147+
}
148+
112149
int Restore::initialize(CephContext *_cct, rgw::sal::Driver* _driver) {
113150
int ret = 0;
114151
cct = _cct;
@@ -458,6 +495,7 @@ int Restore::process_restore_entry(RestoreEntry& entry, optional_yield y)
458495
} else {
459496
ldpp_dout(this, -1) << __PRETTY_FUNCTION__ << ": ERROR: Attr RGW_ATTR_STORAGE_CLASS not found for object: " << obj->get_key() << dendl;
460497
}
498+
461499
ret = driver->get_zone()->get_zonegroup().get_placement_tier(target_placement, &tier);
462500

463501
if (ret < 0) {
@@ -495,6 +533,18 @@ int Restore::process_restore_entry(RestoreEntry& entry, optional_yield y)
495533
} else {
496534
ldpp_dout(this, 15) << __PRETTY_FUNCTION__ << ": Restore of object " << obj->get_key() << " succeeded" << dendl;
497535
entry.status = rgw::sal::RGWRestoreStatus::CloudRestored;
536+
537+
string etag;
538+
attr_iter = attrs.find(RGW_ATTR_ETAG);
539+
if (attr_iter != attrs.end()) {
540+
etag = rgw_bl_str(attr_iter->second);
541+
}
542+
543+
uint64_t size = ret;
544+
// send notification in case the restore is successfully completed
545+
send_notification(this, driver, obj.get(), bucket.get(), etag, size,
546+
obj->get_key().instance,
547+
{rgw::notify::ObjectRestoreCompleted}, y);
498548
}
499549

500550
done:
@@ -612,11 +662,11 @@ int Restore::update_cloud_restore_exp_date(rgw::sal::Bucket* pbucket,
612662
}
613663

614664
int Restore::restore_obj_from_cloud(rgw::sal::Bucket* pbucket,
615-
rgw::sal::Object* pobj,
616-
rgw::sal::PlacementTier* tier,
617-
std::optional<uint64_t> days,
618-
const DoutPrefixProvider* dpp,
619-
optional_yield y)
665+
rgw::sal::Object* pobj,
666+
rgw::sal::PlacementTier* tier,
667+
std::optional<uint64_t> days,
668+
const DoutPrefixProvider* dpp,
669+
optional_yield y)
620670
{
621671
int ret = 0;
622672

@@ -625,6 +675,22 @@ int Restore::restore_obj_from_cloud(rgw::sal::Bucket* pbucket,
625675
return -EINVAL;
626676
}
627677

678+
auto notify = driver->get_notification(
679+
dpp, pobj, nullptr,
680+
{rgw::notify::ObjectRestoreInitiated},
681+
pbucket, restore_id,
682+
const_cast<std::string&>(pbucket->get_tenant()), restore_req_id, y);
683+
684+
if (notify) {
685+
int ret = notify->publish_reserve(dpp, nullptr);
686+
if (ret < 0) {
687+
ldpp_dout(dpp, 1) << "ERROR: notify publish_reserve failed with error: "
688+
<< ret << " for restore object: " << pobj->get_name()
689+
<< " for event_types: rgw::notify::ObjectRestoreInitiated" << dendl;
690+
return ret;
691+
}
692+
}
693+
628694
// set restore_status as RESTORE_ALREADY_IN_PROGRESS
629695
ret = set_cloud_restore_status(this, pobj, y, rgw::sal::RGWRestoreStatus::RestoreAlreadyInProgress);
630696
if (ret < 0) {
@@ -663,6 +729,24 @@ int Restore::restore_obj_from_cloud(rgw::sal::Bucket* pbucket,
663729
}
664730

665731
ldpp_dout(this, 10) << __PRETTY_FUNCTION__ << ": Restore of object " << pobj->get_key() << " is in progress." << dendl;
732+
733+
if (notify) {
734+
auto& attrs = pobj->get_attrs();
735+
string etag;
736+
auto attr_iter = attrs.find(RGW_ATTR_ETAG);
737+
if (attr_iter != attrs.end()) {
738+
etag = rgw_bl_str(attr_iter->second);
739+
}
740+
741+
ret = notify->publish_commit(dpp, pobj->get_size(), ceph::real_clock::now(), etag,
742+
pobj->get_key().instance);
743+
if (ret < 0) {
744+
ldpp_dout(dpp, 5) << "WARNING: notify publish_commit failed with error: "
745+
<< ret << " for lc object: " << pobj->get_name()
746+
<< " for event_types: rgw::notify::ObjectRestoreInitiated" << dendl;
747+
}
748+
}
749+
666750
return ret;
667751
}
668752

src/rgw/rgw_restore.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "rgw_common.h"
2020
#include "cls/rgw/cls_rgw_types.h"
2121
#include "rgw_sal.h"
22+
#include "rgw_notify.h"
2223

2324
#include <atomic>
2425
#include <tuple>
@@ -150,6 +151,20 @@ class Restore : public DoutPrefixProvider {
150151
std::optional<uint64_t> days,
151152
const DoutPrefixProvider* dpp,
152153
optional_yield y);
154+
155+
/**
156+
* Send notification incase of restore events
157+
*/
158+
159+
void send_notification(const DoutPrefixProvider* dpp,
160+
rgw::sal::Driver* driver,
161+
rgw::sal::Object* obj,
162+
rgw::sal::Bucket* bucket,
163+
const std::string& etag,
164+
uint64_t size,
165+
const std::string& version_id,
166+
const rgw::notify::EventTypeList& event_types,
167+
optional_yield y);
153168
};
154169

155170
} // namespace rgw::restore

0 commit comments

Comments
 (0)