Skip to content

NSFS | S3 | Versioning: Deleting object versions except the latest breaks ListObjectVersions #8314

@hseipp

Description

@hseipp

Environment info

Actual behavior

ListObjectVersions does not return a VersionId for last remaining version after all previous versions of a key are deleted.
Instead, ListObjectVersions only returns:

{
    "RequestCharged": null
}

Expected behavior

ListObjectVersions should report correct versioning information for the object. Example:

{
    "Versions": [
        {
            "ETag": "\"mtime-d3qrmcqwi1og-ino-105s\"",
            "Size": 9,
            "StorageClass": "STANDARD",
            "Key": "testobj",
            "VersionId": "mtime-d3qrmcqwi1og-ino-105s",
            "IsLatest": true,
            "LastModified": "2024-08-27T14:31:45+00:00",
            "Owner": {
                "DisplayName": "NooBaa",
                "ID": "123"
            }
        }
    ],
    "RequestCharged": null
}

Steps to reproduce

Execute Ceph s3-tests, function test_versioning_obj_create_read_remove()

S3TEST_CONF=s3tests.conf tox -- s3tests_boto3/functional/test_s3.py::test_versioning_obj_create_read_remove

Alternatively run the following python script (adjust profile and certificate to your needs):

#!/usr/bin/python
import boto3
session = boto3.Session(profile_name='s3user1')
endpoint = 'https://localhost:6443'
cos = session.client('s3', endpoint_url=endpoint, verify='/home/vagrant/aws-cert/tls.crt')
bucket_name = "s3tests-gr7nhf7l22gctexhbn5kw-1"
response = cos.create_bucket(Bucket=bucket_name)
response = cos.put_bucket_versioning(Bucket=bucket_name, VersioningConfiguration={'Status': 'Enabled'})
read_status = None
expected_string  = 'Enabled'
for i in range(5):
  try:
    response = cos.get_bucket_versioning(Bucket=bucket_name)
    read_status = response['Status']
  except KeyError:
    read_status = None
  if (expected_string == read_status):
            break
  time.sleep(1)
assert expected_string == read_status
version_ids = []
for i in range(5):
  data = 'content-{i}'.format(i=i)
  response = cos.put_object(Bucket=bucket_name, Key='testobj', Body=data)
  version_id = response['VersionId']
  version_ids.append(version_id)

for i in range(5):
  rm_version_id = version_ids.pop(0)
  cos.delete_object(Bucket=bucket_name, Key='testobj', VersionId=rm_version_id)
  response = cos.list_object_versions(Bucket=bucket_name)
  print("Versions: {}".format(response['Versions']))

More information - Screenshots / Logs / Other output

Output of the Python script with the error:

Versions: [{'ETag': '"mtime-d3rk3k4prklc-ino-nbe"', 'Size': 9, 'StorageClass': 'STANDARD', 'Key': 'testobj', 'VersionId': 'mtime-d3rk3k4prklc-ino-nbe', 'IsLatest': True, 'LastModified': datetime.datetime(2024, 8, 28, 12, 50, 45, tzinfo=tzlocal()), 'Owner': {'DisplayName': 'NooBaa', 'ID': '123'}}, {'ETag': '"mtime-d3rk3k4fk2yo-ino-nbd"', 'Size': 9, 'StorageClass': 'STANDARD', 'Key': 'testobj', 'VersionId': 'mtime-d3rk3k4fk2yo-ino-nbd', 'IsLatest': True, 'LastModified': datetime.datetime(2024, 8, 28, 12, 50, 45, tzinfo=tzlocal()), 'Owner': {'DisplayName': 'NooBaa', 'ID': '123'}}, {'ETag': '"mtime-d3rk3k3xc6ps-ino-nbc"', 'Size': 9, 'StorageClass': 'STANDARD', 'Key': 'testobj', 'VersionId': 'mtime-d3rk3k3xc6ps-ino-nbc', 'IsLatest': True, 'LastModified': datetime.datetime(2024, 8, 28, 12, 50, 45, tzinfo=tzlocal()), 'Owner': {'DisplayName': 'NooBaa', 'ID': '123'}}, {'ETag': '"mtime-d3rk3k37arcw-ino-nba"', 'Size': 9, 'StorageClass': 'STANDARD', 'Key': 'testobj', 'VersionId': 'mtime-d3rk3k37arcw-ino-nba', 'IsLatest': True, 'LastModified': datetime.datetime(2024, 8, 28, 12, 50, 45, tzinfo=tzlocal()), 'Owner': {'DisplayName': 'NooBaa', 'ID': '123'}}]
Versions: [{'ETag': '"mtime-d3rk3k4prklc-ino-nbe"', 'Size': 9, 'StorageClass': 'STANDARD', 'Key': 'testobj', 'VersionId': 'mtime-d3rk3k4prklc-ino-nbe', 'IsLatest': True, 'LastModified': datetime.datetime(2024, 8, 28, 12, 50, 45, tzinfo=tzlocal()), 'Owner': {'DisplayName': 'NooBaa', 'ID': '123'}}, {'ETag': '"mtime-d3rk3k4fk2yo-ino-nbd"', 'Size': 9, 'StorageClass': 'STANDARD', 'Key': 'testobj', 'VersionId': 'mtime-d3rk3k4fk2yo-ino-nbd', 'IsLatest': True, 'LastModified': datetime.datetime(2024, 8, 28, 12, 50, 45, tzinfo=tzlocal()), 'Owner': {'DisplayName': 'NooBaa', 'ID': '123'}}, {'ETag': '"mtime-d3rk3k3xc6ps-ino-nbc"', 'Size': 9, 'StorageClass': 'STANDARD', 'Key': 'testobj', 'VersionId': 'mtime-d3rk3k3xc6ps-ino-nbc', 'IsLatest': True, 'LastModified': datetime.datetime(2024, 8, 28, 12, 50, 45, tzinfo=tzlocal()), 'Owner': {'DisplayName': 'NooBaa', 'ID': '123'}}]
Versions: [{'ETag': '"mtime-d3rk3k4prklc-ino-nbe"', 'Size': 9, 'StorageClass': 'STANDARD', 'Key': 'testobj', 'VersionId': 'mtime-d3rk3k4prklc-ino-nbe', 'IsLatest': True, 'LastModified': datetime.datetime(2024, 8, 28, 12, 50, 45, tzinfo=tzlocal()), 'Owner': {'DisplayName': 'NooBaa', 'ID': '123'}}, {'ETag': '"mtime-d3rk3k4fk2yo-ino-nbd"', 'Size': 9, 'StorageClass': 'STANDARD', 'Key': 'testobj', 'VersionId': 'mtime-d3rk3k4fk2yo-ino-nbd', 'IsLatest': True, 'LastModified': datetime.datetime(2024, 8, 28, 12, 50, 45, tzinfo=tzlocal()), 'Owner': {'DisplayName': 'NooBaa', 'ID': '123'}}]
Traceback (most recent call last):
  File "create-versioned-bucket-upload-object_multiple.py", line 33, in <module>
    print("Versions: {}".format(response['Versions']))
KeyError: 'Versions'

Noobaa log with "all" mode enabled:

noobaa_20240828_1455.log.gz

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions