Skip to content

Commit 9a9e14d

Browse files
committed
RGW/logging: add rest API to flush logging bucket
Signed-off-by: Ali Masarwa <[email protected]>
1 parent bb40fe4 commit 9a9e14d

File tree

11 files changed

+165
-2
lines changed

11 files changed

+165
-2
lines changed

doc/radosgw/bucket_logging.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ This time (in seconds) could be set per source bucket via a Ceph extension to th
2727
or globally via the `rgw_bucket_logging_obj_roll_time` configuration option. If not set, the default time is 5 minutes.
2828
Adding a log object to the log bucket is done "lazily", meaning, that if no more records are written to the object, it may
2929
remain outside of the log bucket even after the configured time has passed.
30+
To counter that, you can flush all logging objects on a given source bucket to log them,
31+
regardless if enough time passed or if no more records are written to the object.
3032

3133
Standard
3234
````````

doc/radosgw/s3/bucketops.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,3 +894,27 @@ HTTP Response
894894
| ``404`` | NoSuchBucket | The bucket does not exist |
895895
+---------------+-----------------------+----------------------------------------------------------+
896896

897+
Flush Bucket Logging
898+
--------------------
899+
900+
Flushes all logging objects for a given source bucket (logging bucket are written lazily).
901+
902+
Syntax
903+
~~~~~~
904+
905+
::
906+
907+
POST /{bucket}?logging HTTP/1.1
908+
909+
910+
HTTP Response
911+
~~~~~~~~~~~~~
912+
913+
+---------------+-----------------------+----------------------------------------------------------+
914+
| HTTP Status | Status Code | Description |
915+
+===============+=======================+==========================================================+
916+
| ``201`` | Created | Flushed all logging objects successfully |
917+
+---------------+-----------------------+----------------------------------------------------------+
918+
| ``404`` | NoSuchBucket | The bucket does not exist |
919+
+---------------+-----------------------+----------------------------------------------------------+
920+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import boto3
2+
import sys
3+
4+
5+
if len(sys.argv) == 2:
6+
# bucket name as first argument
7+
bucketname = sys.argv[1]
8+
else:
9+
print('Usage: ' + sys.argv[0] + ' <bucket>')
10+
sys.exit(1)
11+
12+
# endpoint and keys from vstart
13+
endpoint = 'http://127.0.0.1:8000/'+bucketname
14+
access_key='0555b35654ad1656d804'
15+
secret_key='h7GhxuBLTrlhVUyxSPUKUV8r/2EI4ngqJxD7iBdBYLhwluN30JaT3Q=='
16+
17+
client = boto3.client('s3',
18+
endpoint_url=endpoint,
19+
aws_access_key_id=access_key,
20+
aws_secret_access_key=secret_key)
21+
22+
# flushing the logs for bucket logging
23+
print(client.post_bucket_logging(Bucket=bucketname))

examples/rgw/boto3/service-2.sdk-extras.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@
1313
"documentationUrl":"https://docs.ceph.com/docs/master/radosgw/s3/bucketops/#delete-notification",
1414
"documentation":"<p>Deletes the notification configuration from the bucket.</p>"
1515
},
16+
"PostBucketLogging":{
17+
"name":"PostBucketLogging",
18+
"http":{
19+
"method":"POST",
20+
"requestUri":"/{Bucket}?logging",
21+
"responseCode":201
22+
},
23+
"input":{"shape":"PostBucketLoggingRequest"},
24+
"documentationUrl":"https://docs.ceph.com/docs/master/radosgw/s3/bucketops/#post-bucket-logging",
25+
"documentation":"<p>Flushes the logging objects of the buckets.</p>"
26+
},
1627
"GetUsageStats":{
1728
"name":"GetUsageStats",
1829
"http":{
@@ -146,6 +157,18 @@
146157
}
147158
}
148159
},
160+
"PostBucketLoggingRequest":{
161+
"type":"structure",
162+
"required":["Bucket"],
163+
"members":{
164+
"Bucket":{
165+
"shape":"BucketName",
166+
"documentation":"<p>Name of the bucket to flush its logging objects.</p>",
167+
"location":"uri",
168+
"locationName":"Bucket"
169+
}
170+
}
171+
},
149172
"FilterRule":{
150173
"type":"structure",
151174
"members":{

src/rgw/rgw_admin.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7599,7 +7599,7 @@ int main(int argc, const char **argv)
75997599
<< "' to target bucket '" << configuration.target_bucket << "'" << std::endl;
76007600
return -ret;
76017601
}
7602-
cerr << "flushed pending logging object '" << obj_name
7602+
cout << "flushed pending logging object '" << obj_name
76037603
<< "' to target bucket '" << configuration.target_bucket << "'" << std::endl;
76047604
return 0;
76057605
}

src/rgw/rgw_iam_policy.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ static const actpair actpairs[] =
113113
{ "s3:PutBucketCORS", s3PutBucketCORS },
114114
{ "s3:PutBucketEncryption", s3PutBucketEncryption },
115115
{ "s3:PutBucketLogging", s3PutBucketLogging },
116+
{ "s3:PostBucketLogging", s3PostBucketLogging },
116117
{ "s3:PutBucketNotification", s3PutBucketNotification },
117118
{ "s3:PutBucketOwnershipControls", s3PutBucketOwnershipControls },
118119
{ "s3:PutBucketPolicy", s3PutBucketPolicy },
@@ -1406,6 +1407,9 @@ const char* action_bit_string(uint64_t action) {
14061407
case s3PutBucketLogging:
14071408
return "s3:PutBucketLogging";
14081409

1410+
case s3PostBucketLogging:
1411+
return "s3:PostBucketLogging";
1412+
14091413
case s3GetBucketTagging:
14101414
return "s3:GetBucketTagging";
14111415

src/rgw/rgw_iam_policy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ enum {
8181
s3PutBucketNotification,
8282
s3GetBucketLogging,
8383
s3PutBucketLogging,
84+
s3PostBucketLogging,
8485
s3GetBucketTagging,
8586
s3PutBucketTagging,
8687
s3GetBucketWebsite,
@@ -298,6 +299,7 @@ inline int op_to_perm(std::uint64_t op) {
298299
case s3PutBucketCORS:
299300
case s3PutBucketEncryption:
300301
case s3PutBucketLogging:
302+
case s3PostBucketLogging:
301303
case s3PutBucketNotification:
302304
case s3PutBucketPolicy:
303305
case s3PutBucketRequestPayment:

src/rgw/rgw_op_type.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ enum RGWOpType {
117117
RGW_OP_DETACH_GROUP_POLICY,
118118
RGW_OP_LIST_ATTACHED_GROUP_POLICIES,
119119
RGW_OP_PUT_BUCKET_LOGGING,
120+
RGW_OP_POST_BUCKET_LOGGING,
120121
/* rgw specific */
121122
RGW_OP_ADMIN_SET_METADATA,
122123
RGW_OP_GET_OBJ_LAYOUT,

src/rgw/rgw_rest_bucket_logging.cc

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,84 @@ class RGWPutBucketLoggingOp : public RGWDefaultResponseOp {
209209
}
210210
};
211211

212+
// Post /<bucket name>/?logging
213+
// actual configuration is XML encoded in the body of the message
214+
class RGWPostBucketLoggingOp : public RGWDefaultResponseOp {
215+
int verify_permission(optional_yield y) override {
216+
auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false);
217+
if (has_s3_resource_tag)
218+
rgw_iam_add_buckettags(this, s);
219+
220+
if (!verify_bucket_permission(this, s, rgw::IAM::s3PostBucketLogging)) {
221+
return -EACCES;
222+
}
223+
224+
return 0;
225+
}
226+
227+
const char* name() const override { return "post_bucket_logging"; }
228+
RGWOpType get_type() override { return RGW_OP_POST_BUCKET_LOGGING; }
229+
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
230+
231+
void execute(optional_yield y) override {
232+
op_ret = verify_bucket_logging_params(this, s);
233+
if (op_ret < 0) {
234+
return;
235+
}
236+
237+
std::unique_ptr<rgw::sal::Bucket> bucket;
238+
op_ret = driver->load_bucket(this, rgw_bucket(s->bucket_tenant, s->bucket_name),
239+
&bucket, y);
240+
if (op_ret < 0) {
241+
ldpp_dout(this, 1) << "ERROR: failed to get bucket '" << s->bucket_name << "', ret = " << op_ret << dendl;
242+
return;
243+
}
244+
const auto& bucket_attrs = bucket->get_attrs();
245+
auto iter = bucket_attrs.find(RGW_ATTR_BUCKET_LOGGING);
246+
if (iter == bucket_attrs.end()) {
247+
ldpp_dout(this, 1) << "WARNING: no logging configured on bucket" << dendl;
248+
return;
249+
}
250+
rgw::bucketlogging::configuration configuration;
251+
try {
252+
configuration.enabled = true;
253+
decode(configuration, iter->second);
254+
} catch (buffer::error& err) {
255+
ldpp_dout(this, 1) << "ERROR: failed to decode logging attribute '" << RGW_ATTR_BUCKET_LOGGING
256+
<< "'. error: " << err.what() << dendl;
257+
op_ret = -EINVAL;
258+
return;
259+
}
260+
261+
std::unique_ptr<rgw::sal::Bucket> target_bucket;
262+
op_ret = driver->load_bucket(this, rgw_bucket(s->bucket_tenant, configuration.target_bucket),
263+
&target_bucket, y);
264+
if (op_ret < 0) {
265+
ldpp_dout(this, 1) << "ERROR: failed to get target bucket '" << configuration.target_bucket << "', ret = " << op_ret << dendl;
266+
return;
267+
}
268+
std::string obj_name;
269+
RGWObjVersionTracker objv_tracker;
270+
op_ret = target_bucket->get_logging_object_name(obj_name, configuration.target_prefix, null_yield, this, &objv_tracker);
271+
if (op_ret < 0) {
272+
ldpp_dout(this, 1) << "ERROR: failed to get pending logging object name from target bucket '" << configuration.target_bucket << "'" << dendl;
273+
return;
274+
}
275+
op_ret = rgw::bucketlogging::rollover_logging_object(configuration, target_bucket, obj_name, this, null_yield, true, &objv_tracker);
276+
if (op_ret < 0) {
277+
ldpp_dout(this, 1) << "ERROR: failed to flush pending logging object '" << obj_name
278+
<< "' to target bucket '" << configuration.target_bucket << "'" << dendl;
279+
return;
280+
}
281+
ldpp_dout(this, 20) << "flushed pending logging object '" << obj_name
282+
<< "' to target bucket '" << configuration.target_bucket << "'" << dendl;
283+
}
284+
};
285+
286+
RGWOp* RGWHandler_REST_BucketLogging_S3::create_post_op() {
287+
return new RGWPostBucketLoggingOp();
288+
}
289+
212290
RGWOp* RGWHandler_REST_BucketLogging_S3::create_put_op() {
213291
return new RGWPutBucketLoggingOp();
214292
}

src/rgw/rgw_rest_bucket_logging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ class RGWHandler_REST_BucketLogging_S3 : public RGWHandler_REST_S3 {
1414
virtual ~RGWHandler_REST_BucketLogging_S3() = default;
1515
static RGWOp* create_get_op();
1616
static RGWOp* create_put_op();
17+
static RGWOp* create_post_op();
1718
};
1819

0 commit comments

Comments
 (0)