# GetBucketLifecycleConfiguration

GetBucketLifecycleConfiguration returns a bucket's lifecycle configuration: the rules that
expire current object versions, delete noncurrent versions and abort incomplete multipart
uploads. They are the same rules the dashboard shows and edits, whichever way they were set.
The deprecated [GetBucketLifecycle](https://docs.strg.com/s3-api/GetBucketLifecycle) sends exactly the same request,
so this operation is the better choice. [Lifecycle policies](https://docs.strg.com/lifecycle-policies)
explains what the rules do.

**Info: Good to know on STRG**

- A rule that expires current versions reads back as two rules: yours, and a companion rule on
  the same prefix with the ID `<your ID>_marker`, which tidies away expired delete markers.
- Rules hold the three actions STRG offers - `Expiration`, `NoncurrentVersionExpiration`
  and `AbortIncompleteMultipartUpload` - each filtered by key prefix.
- `x-amz-expected-bucket-owner` is welcome and has nothing to check: a key only ever reaches
  buckets of its own account.

## When you'd use it

- **Changing one rule among several.** A lifecycle configuration is always replaced as a
  whole, so a deploy script that adds a rule for a new `tmp/` prefix first reads the current
  rules, adds its own, and sends the full set back with
  [PutBucketLifecycleConfiguration](https://docs.strg.com/s3-api/PutBucketLifecycleConfiguration).
- **Keeping storage costs in check.** Every version of every object is billed as stored data,
  so a nightly audit can read each bucket's rules and flag any bucket without a
  `NoncurrentVersionExpiration` rule.
- **Settings kept in code.** An infrastructure tool that manages bucket settings reads the
  current rules to compare them with what it expects, and only writes when they differ.

## Request

```http
GET /?lifecycle HTTP/1.1
Host: my-bucket.s3.eu-central-1.strg.com
Authorization: AWS4-HMAC-SHA256 Credential=...
x-amz-date: 20260926T120000Z
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
```

Path-style, the same request is `GET /my-bucket?lifecycle` on `s3.eu-central-1.strg.com`.
[Addressing](https://docs.strg.com/s3-api/overview#addressing) in the S3 API overview has both styles.

### Permissions

The access key needs **Read lifecycle rules** (`bucket-lifecycle:read`). A key limited to
certain buckets works too, as long as this bucket is one of them. A key prefix does not narrow
this operation, because the configuration belongs to the whole bucket.
[Access keys](https://docs.strg.com/access-keys) has every permission.

### URI parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Bucket` | String | Yes | The bucket whose lifecycle configuration is read. |
| `lifecycle` | Flag | Yes | Selects the lifecycle subresource. Sent without a value. |

STRG answers `501 NotImplemented` to any other query parameter, so a client knows straight
away. The `X-Amz-*` parameters of a presigned URL and the `x-id` parameter the JavaScript SDK
adds are welcome.

### Request headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `x-amz-expected-bucket-owner` | String | No | Welcome, with nothing to check: an access key only ever reaches its own account's buckets. |

### Request body

None.

## Response

A bucket with lifecycle rules answers `200 OK` with the configuration. A bucket without any
answers `404 NoSuchLifecycleConfiguration`.

### Response headers

| Name | Description |
| --- | --- |
| `x-amz-request-id` | The request ID, useful in a support request. |
| `x-amz-transition-default-minimum-object-size` | Relates to storage-class transitions, which STRG has no use for, so this header carries no meaning for a STRG bucket. |

### Response body

A `LifecycleConfiguration` element holding one `Rule` element per rule.

| Element | Description |
| --- | --- |
| `Rule` | One lifecycle rule. |
| `Rule/ID` | The rule's ID. The ID set with [PutBucketLifecycleConfiguration](https://docs.strg.com/s3-api/PutBucketLifecycleConfiguration) is kept, including across a save in the dashboard. A rule added in the dashboard gets a generated ID. |
| `Rule/Filter/Prefix` | The key prefix the rule applies to. Empty means every object in the bucket. A rule set with an empty `Filter` reads back with an empty `Prefix`. |
| `Rule/Status` | `Enabled`. |
| `Rule/Expiration/Days` | Days after creation when the current version of an object becomes a noncurrent version (a delete marker is placed on top of it). |
| `Rule/Expiration/ExpiredObjectDeleteMarker` | `true`, on the companion rule only - described below. |
| `Rule/NoncurrentVersionExpiration/NoncurrentDays` | Days after a version becomes noncurrent when it is permanently deleted. |
| `Rule/AbortIncompleteMultipartUpload/DaysAfterInitiation` | Days after a multipart upload starts when it is aborted if not completed. |

The S3 elements for other kinds of rule - `Transition`, `NoncurrentVersionTransition`,
`Expiration/Date`, `NewerNoncurrentVersions`, tag and object-size filters, `And` - never
appear. STRG keeps lifecycle rules to the three actions above, and
[PutBucketLifecycleConfiguration](https://docs.strg.com/s3-api/PutBucketLifecycleConfiguration) answers the others
with `501 NotImplemented`.

**The companion rule.** Every rule with `Expiration/Days` is followed by a second rule on the
same prefix, with the ID `<ID>_marker` and `Expiration/ExpiredObjectDeleteMarker` set to
`true`, which removes a delete marker once no versions remain beneath it. STRG adds it
when the rules are saved. There is no need to send it back with
[PutBucketLifecycleConfiguration](https://docs.strg.com/s3-api/PutBucketLifecycleConfiguration): STRG adds it
again.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<LifecycleConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <Rule>
    <ID>expire-logs</ID>
    <Filter>
      <Prefix>logs/</Prefix>
    </Filter>
    <Status>Enabled</Status>
    <Expiration>
      <Days>30</Days>
    </Expiration>
    <NoncurrentVersionExpiration>
      <NoncurrentDays>7</NoncurrentDays>
    </NoncurrentVersionExpiration>
    <AbortIncompleteMultipartUpload>
      <DaysAfterInitiation>1</DaysAfterInitiation>
    </AbortIncompleteMultipartUpload>
  </Rule>
  <Rule>
    <ID>expire-logs_marker</ID>
    <Filter>
      <Prefix>logs/</Prefix>
    </Filter>
    <Status>Enabled</Status>
    <Expiration>
      <ExpiredObjectDeleteMarker>true</ExpiredObjectDeleteMarker>
    </Expiration>
  </Rule>
</LifecycleConfiguration>
```

## Errors

These are the answers a client can get instead of `200`, and the situation behind each.

| Code | HTTP status | When |
| --- | --- | --- |
| `NoSuchLifecycleConfiguration` | 404 | The bucket has no lifecycle rules. |
| `NoSuchBucket` | 404 | The bucket does not exist, it is in a region other than the endpoint's, or the account stores nothing in this endpoint's region yet. |
| `AccessDenied` | 403 | The access key does not hold **Read lifecycle rules**, the bucket is outside its scope, or the account is not active. |
| `InvalidAccessKeyId` | 403 | The access key does not exist, has expired or has been revoked - or it was created moments ago and is not yet usable in this region, where the account already stores data. A retry a moment later succeeds. |
| `SignatureDoesNotMatch` | 403 | The request signature does not match. |
| `RequestTimeTooSkewed` | 403 | The request time is more than 15 minutes from the server's. |
| `AuthorizationHeaderMalformed` | 400 | The signature's credential scope names a region other than the endpoint's. |
| `NotImplemented` | 501 | The request carries a query parameter this operation does not take. |
| `SlowDown` | 503 | Too many requests at once. A retry after the `Retry-After` interval goes through. |
| `ServiceUnavailable` | 503 | A temporary failure. A retry of the same request is safe. |

## Differences from Amazon S3

| Aspect | Amazon S3 | STRG |
| --- | --- | --- |
| Expiration rules | Returned as sent | Each rule with `Expiration/Days` is followed by a companion `<ID>_marker` rule with `ExpiredObjectDeleteMarker`. A script can skip it, or leave it out before sending the rules back - STRG adds it again either way |
| Rule contents | Transitions, dates, tag and size filters, `NewerNoncurrentVersions` | `Expiration/Days`, `NoncurrentVersionExpiration/NoncurrentDays` and `AbortIncompleteMultipartUpload`, filtered by prefix - three actions that cover expiring data, old versions and abandoned uploads |
| Bucket in another region | `301` redirect with `x-amz-bucket-region` | `404 NoSuchBucket`, also when the account stores nothing in the endpoint's region. The bucket's own regional endpoint reaches it |
| `x-amz-expected-bucket-owner` | Checked against the bucket owner | Welcome, with nothing to check: a key only reaches its own account's buckets |

## Examples

Reading the lifecycle rules of `my-bucket`:

**AWS CLI**

```bash
aws s3api get-bucket-lifecycle-configuration \
  --bucket my-bucket \
  --endpoint-url https://s3.eu-central-1.strg.com \
  --region eu-central-1
```

For a bucket without rules, the command ends with `NoSuchLifecycleConfiguration`.

**Python (boto3)**

```python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.eu-central-1.strg.com",
    region_name="eu-central-1",
)

try:
    rules = s3.get_bucket_lifecycle_configuration(Bucket="my-bucket")["Rules"]
except s3.exceptions.ClientError as error:
    if error.response["Error"]["Code"] != "NoSuchLifecycleConfiguration":
        raise
    rules = []

# The companion rules STRG adds to every expiration rule are skipped.
for rule in rules:
    if rule.get("Expiration", {}).get("ExpiredObjectDeleteMarker"):
        continue
    print(rule["ID"], rule["Filter"].get("Prefix", ""))
```

**JavaScript (AWS SDK v3)**

```javascript
import { GetBucketLifecycleConfigurationCommand, S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({
  endpoint: "https://s3.eu-central-1.strg.com",
  region: "eu-central-1",
});

let rules = [];
try {
  const output = await client.send(
    new GetBucketLifecycleConfigurationCommand({ Bucket: "my-bucket" }),
  );
  rules = output.Rules ?? [];
} catch (error) {
  if (error.name !== "NoSuchLifecycleConfiguration") throw error;
}

// The companion rules STRG adds to every expiration rule are skipped.
for (const rule of rules) {
  if (rule.Expiration?.ExpiredObjectDeleteMarker) continue;
  console.log(rule.ID, rule.Filter?.Prefix ?? "");
}
```

## Related

- [PutBucketLifecycleConfiguration](https://docs.strg.com/s3-api/PutBucketLifecycleConfiguration)
- [DeleteBucketLifecycle](https://docs.strg.com/s3-api/DeleteBucketLifecycle)
- [GetBucketLifecycle](https://docs.strg.com/s3-api/GetBucketLifecycle) (deprecated)
- [Lifecycle policies](https://docs.strg.com/lifecycle-policies)
- [Access keys](https://docs.strg.com/access-keys)
- [S3 API overview](https://docs.strg.com/s3-api/overview)
