Skip to content

Added x-amz-expiration missing HTTP header in the response of object operations #8958

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

achouhan09
Copy link
Member

@achouhan09 achouhan09 commented Apr 9, 2025

Describe the Problem

S3-compatible clients expect the x-amz-expiration response header when an object is subject to a lifecycle expiration rule. However, NooBaa was not setting this header in GET, PUT, or HEAD responses, even when valid expiration rules were configured.

Explain the Changes

  1. Added set_expiration_header() function to include the x-amz-expiration header in GET, PUT, and HEAD object responses.
  2. Implemented parse_expiration_header() to convert lifecycle expiration rules (days or date) into proper s3 style header format.

Below is the output for header of putObject, headObject and getObject (after the fix):

Screenshot from 2025-04-30 18-30-45

Issues: Fixed #xxx / Gap #xxx

  1. Fixed: NSFS | S3 | Lifecycle: bunch of expiration header tests failed #8554

Testing Instructions:

  1. Added ceph-s3 tests.
  • Tests added

Note: Need to fix for nsfs.

@achouhan09 achouhan09 marked this pull request as draft April 9, 2025 13:25
@achouhan09 achouhan09 force-pushed the amz-exp-fix branch 2 times, most recently from 4ffea5c to d5690b2 Compare April 22, 2025 13:30
@achouhan09 achouhan09 marked this pull request as ready for review April 22, 2025 13:31
@achouhan09 achouhan09 force-pushed the amz-exp-fix branch 4 times, most recently from 1e0964c to b0aadfc Compare April 28, 2025 17:35
@achouhan09
Copy link
Member Author

PR is ready for review. For testing we can add ceph-s3 tests which are failing for missing x-amz-expiration header.

Copy link
Contributor

@shirady shirady left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments and questions

@shirady
Copy link
Contributor

shirady commented Apr 29, 2025

Hi @achouhan09,

  • I don't have prior knowledge about this header - if you can share what you tested in AWS it can be useful (I would also attach it in the PR description). I read this part in the blog to understand it quickly (link):

If you make a GET or a HEAD request on an object that has been scheduled for expiration, the response will include an x-amz-expiration header that includes this expiration date and the corresponding rule Id.

  • I saw in the comment above you mentioned the failing Ceph tests - can you add them in this PR?
    You can remove them from the blacklist/pending list so they will run automatically in the CI.

  • In AWS docs GetObject I found:

If the object expiration is configured (see PutBucketLifecycleConfiguration), the response includes this header. It includes the expiry-date and rule-id key-value pairs providing object expiration information. The value of the rule-id is URL-encoded.

Note - same comment in AWS docs HeadObject and also in AWS docs PutObject

Did you test in AWS the url-encoded part so we can understand what they do there?

I also saw this comment:

Note
Object expiration information is not returned in directory buckets and this header returns the value "NotImplemented" in all responses for directory buckets.

@romayalon @nadavMiz just want you to notice, I think it is fine to implement it in NSFS, but I would like you to think about it.

@achouhan09
Copy link
Member Author

Hi @achouhan09,

  • I don't have prior knowledge about this header - if you can share what you tested in AWS it can be useful (I would also attach it in the PR description). I read this part in the blog to understand it quickly (link):

If you make a GET or a HEAD request on an object that has been scheduled for expiration, the response will include an x-amz-expiration header that includes this expiration date and the corresponding rule Id.

  • I saw in the comment above you mentioned the failing Ceph tests - can you add them in this PR?
    You can remove them from the blacklist/pending list so they will run automatically in the CI.
  • In AWS docs GetObject I found:

If the object expiration is configured (see PutBucketLifecycleConfiguration), the response includes this header. It includes the expiry-date and rule-id key-value pairs providing object expiration information. The value of the rule-id is URL-encoded.

Note - same comment in AWS docs HeadObject and also in AWS docs PutObject

Did you test in AWS the url-encoded part so we can understand what they do there?

I also saw this comment:

Note
Object expiration information is not returned in directory buckets and this header returns the value "NotImplemented" in all responses for directory buckets.

@romayalon @nadavMiz just want you to notice, I think it is fine to implement it in NSFS, but I would like you to think about it.

@shirady

  • Updated PR description.
  • Added ceph s3 tests - which are failing before the fix.
  • Here, as per the aws documentation the rule-id should be url-encoded in x-amz-expiration but aws itself is not doing so, please check below screenshot:
    Screenshot from 2025-04-30 16-23-09

cc @romayalon @nadavMiz

@achouhan09 achouhan09 requested a review from shirady April 30, 2025 13:30
achouhan09 added 3 commits May 7, 2025 20:13
… GET/PUT/HEAD

Signed-off-by: Aayush Chouhan <achouhan@redhat.com>
Signed-off-by: Aayush Chouhan <achouhan@redhat.com>
Signed-off-by: Aayush Chouhan <achouhan@redhat.com>
@achouhan09 achouhan09 force-pushed the amz-exp-fix branch 3 times, most recently from 1c4c44b to 872cedd Compare May 7, 2025 18:08
Signed-off-by: Aayush Chouhan <achouhan@redhat.com>
* @param {Object} object_md
* @returns {Object|undefined}
*/
function get_lifecycle_rule_for_object(rules, object_md) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think http_utils id a good place to put this function. there is a file lifecycle_utils. its currently mostly by nc lifecycle. but it really should be for lifecycle in general

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also there is also a function in nc called _build_lifecycle_filter that creates a function that validates the filter. there is probably something similar in containerized lifecycle, that you might be able to use. this will make it easier if we will ever want to change the filter validation to change it only in one spot.

if (!matches_all_tags) continue;
}

const priority = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this priority? why do you need it?

*/
async function set_expiration_header(req, res, object_md) {
const rules = req.params.bucket && await req.object_sdk.get_bucket_lifecycle_configuration_rules({ name: req.params.bucket });
if (!object_md) { // calculating object_md for putObject
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from what I understand this only happens for put commands. its better that you construct this outside this function and pass the object_md as a parameter. also you should get as much information as you can from the response and not from the request

* Example output:
* expiry-date="Thu, 10 Apr 2025 00:00:00 GMT", rule-id="rule_id"
*/
function parse_expiration_header(rule, create_time) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think its a good name. you don't parse the header, you write it

@@ -363,9 +363,6 @@ s3tests_boto3/functional/test_s3.py::test_lifecycle_expiration_tags2
s3tests_boto3/functional/test_s3.py::test_lifecycle_expiration_versioned_tags2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good if we will add our own tests as well. check that it works on both containerized and non-containerized environments

@nadavMiz
Copy link
Contributor

nadavMiz commented May 8, 2025

since the documentation is not clear on this flag. I think it would also be good to check against aws if it exist for versioned objects as well. if it does it doesn't have to be in this PR, but at least we will open a gap for it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

NSFS | S3 | Lifecycle: bunch of expiration header tests failed
3 participants