# GetBucketLifecycle

Returns the lifecycle rules set on a bucket - the rules that tidy it up for you by expiring old
versions and abandoned uploads ([Lifecycle policies](https://docs.strg.com/lifecycle-policies) explains them).
This is the older form of
[GetBucketLifecycleConfiguration](https://docs.strg.com/s3-api/GetBucketLifecycleConfiguration): both send the same
request and receive the same answer, and GetBucketLifecycleConfiguration is the better choice for
new code, because its output includes each rule's prefix.

**Note: Deprecated**

Amazon S3 deprecated `GetBucketLifecycle` in favour of
[GetBucketLifecycleConfiguration](https://docs.strg.com/s3-api/GetBucketLifecycleConfiguration). STRG answers it,
so older tools keep working, but a client parsing the response as `GetBucketLifecycle` output
does not see each rule's prefix. The AWS SDK for JavaScript v3 does not offer this operation at
all.

**Info: Good to know on STRG**

- A rule's prefix always comes back inside `<Filter>`, never as a top-level `<Prefix>`. Clients
  that parse the response as this operation's output skip `<Filter>`, so every rule looks as if
  it applies to the whole bucket.
- A rule that expires current versions comes back as two rules: the rule itself, and a companion
  rule with the ID `<id>_marker` that clears away expired delete markers on the same prefix.
- Rules count in days and use three actions: `Expiration` in days, `NoncurrentVersionExpiration`
  and `AbortIncompleteMultipartUpload`. Every object stays in one storage class, so there are no
  transitions, and there is no date-based expiration.
- `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

- **An older backup or sync tool** that checks a bucket's lifecycle rules before it runs, and
  was written against this operation, gets a well-formed answer and carries on.
- **A script that only needs to know whether rules exist** - an audit that every bucket cleans up
  its old versions, say - can tell a `200 OK` from `404 NoSuchLifecycleConfiguration` either way.
- **Anything that needs the prefixes**, such as a report of which part of a bucket each rule
  covers, is better served by
  [GetBucketLifecycleConfiguration](https://docs.strg.com/s3-api/GetBucketLifecycleConfiguration), which sends the same
  request and reads the prefix too.

## 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) has the details.

### Permissions

The access key needs **Read lifecycle rules** (`bucket-lifecycle:read`). A key limited to certain
buckets reaches only those. A key prefix does not narrow this operation, since the configuration
belongs to the whole bucket. [Access keys](https://docs.strg.com/access-keys) has the full picture.

### URI parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Bucket` | String | Yes | The bucket whose lifecycle rules are read. |
| `lifecycle` | Flag | Yes | Selects the lifecycle subresource. Takes no value. |

Any other query parameter gets `501 NotImplemented`, so a client knows straight away, except the
`X-Amz-*` parameters of a presigned URL and the `x-id` parameter the JavaScript SDK adds.

### 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 a `LifecycleConfiguration` document. A bucket
without any answers `404 NoSuchLifecycleConfiguration`.

### Response headers

| Name | Description |
| --- | --- |
| `x-amz-request-id` | The request ID, handy for a support request. |

### Response body

`LifecycleConfiguration` holds one `Rule` element per rule. The members this operation defines:

| Element | Type | Description |
| --- | --- | --- |
| `Rule` | Container | One lifecycle rule. Repeated. |
| `Rule/ID` | String | The rule's ID, up to 255 characters: the one set with [PutBucketLifecycleConfiguration](https://docs.strg.com/s3-api/PutBucketLifecycleConfiguration), a generated one for a rule added in the dashboard, or `<id>_marker` for a companion rule. |
| `Rule/Prefix` | String | Never returned. The prefix is in `Rule/Filter/Prefix`, which this operation's output does not define; [GetBucketLifecycleConfiguration](https://docs.strg.com/s3-api/GetBucketLifecycleConfiguration) reads it. |
| `Rule/Status` | String | Always `Enabled`: every rule STRG stores is active. |
| `Rule/Expiration/Days` | Integer | Days after an object is uploaded until its current version becomes a previous version. |
| `Rule/Expiration/ExpiredObjectDeleteMarker` | Boolean | `true` on a companion rule: a delete marker with no versions left behind it is removed. |
| `Rule/Expiration/Date` | Timestamp | Never returned: rules count in days. |
| `Rule/NoncurrentVersionExpiration/NoncurrentDays` | Integer | Days after a version becomes a previous version until it is deleted permanently. |
| `Rule/NoncurrentVersionExpiration/NewerNoncurrentVersions` | Integer | Never returned: previous versions expire by age alone. |
| `Rule/AbortIncompleteMultipartUpload/DaysAfterInitiation` | Integer | Days after a multipart upload starts until it is aborted if still incomplete. |
| `Rule/Transition` | Container | Never returned: STRG has one storage class. |
| `Rule/NoncurrentVersionTransition` | Container | Never returned, for the same reason. |

The document as sent, for a rule on `logs/` that uses all three actions:

```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>2</DaysAfterInitiation>
    </AbortIncompleteMultipartUpload>
  </Rule>
  <Rule>
    <ID>expire-logs_marker</ID>
    <Filter>
      <Prefix>logs/</Prefix>
    </Filter>
    <Status>Enabled</Status>
    <Expiration>
      <ExpiredObjectDeleteMarker>true</ExpiredObjectDeleteMarker>
    </Expiration>
  </Rule>
</LifecycleConfiguration>
```

A client reading this as `GetBucketLifecycle` output gets both rules, without their prefix.

## Errors

The answers this operation can give, 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. |
| `AccessDenied` | 403 | The access key does not hold **Read lifecycle rules**, or the bucket is outside its scope. |
| `InvalidAccessKeyId` | 403 | The access key does not exist, has expired or been revoked - or it was created moments ago and is not yet usable in this endpoint's region, in which case the same request works shortly after. |
| `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 in a short time. The answer carries `Retry-After`, and the AWS SDKs retry on their own. |
| `ServiceUnavailable` | 503 | A temporary failure. The AWS SDKs retry it on their own. |

## Differences from Amazon S3

| Aspect | Amazon S3 | STRG |
| --- | --- | --- |
| Rule prefix | Returned as a top-level `Prefix` for a rule set with one | Always inside `Filter`, which this operation's parsers skip. [GetBucketLifecycleConfiguration](https://docs.strg.com/s3-api/GetBucketLifecycleConfiguration) shows the prefixes. |
| Expiration of current versions | One rule | Two rules: the rule and its `<id>_marker` companion, which clears away expired delete markers |
| Actions | Transitions, date-based expiration, `NewerNoncurrentVersions` | `Expiration` in days, `NoncurrentVersionExpiration` in days and `AbortIncompleteMultipartUpload` - one storage class, so no transitions |
| Bucket in another region | `301` redirect with `x-amz-bucket-region` | `404 NoSuchBucket`. The bucket's own regional endpoint answers for 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 |

[Differences from Amazon S3](https://docs.strg.com/s3-api/overview#differences-from-amazon-s3) covers the ones that
apply to every operation.

## Examples

Reading the lifecycle rules of `my-bucket`:

**AWS CLI**

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

The output lists each rule without its prefix. `aws s3api get-bucket-lifecycle-configuration`
shows the same rules with their prefixes.

**Python (boto3)**

```python
import boto3

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

response = s3.get_bucket_lifecycle(Bucket="my-bucket")
for rule in response["Rules"]:
    print(rule["ID"], rule["Status"])
```

`get_bucket_lifecycle_configuration` returns the same rules with each `Filter` and its prefix.

**JavaScript (AWS SDK v3)**

The AWS SDK for JavaScript v3 has no command for this deprecated operation.
`GetBucketLifecycleConfigurationCommand` sends the same request and reads the prefixes as well:

```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",
});

const { Rules } = await client.send(
  new GetBucketLifecycleConfigurationCommand({ Bucket: "my-bucket" }),
);
for (const rule of Rules ?? []) {
  console.log(rule.ID, rule.Filter?.Prefix, rule.Status);
}
```

## Related

- [GetBucketLifecycleConfiguration](https://docs.strg.com/s3-api/GetBucketLifecycleConfiguration)
- [PutBucketLifecycleConfiguration](https://docs.strg.com/s3-api/PutBucketLifecycleConfiguration)
- [PutBucketLifecycle](https://docs.strg.com/s3-api/PutBucketLifecycle)
- [DeleteBucketLifecycle](https://docs.strg.com/s3-api/DeleteBucketLifecycle)
- [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)
