# s3-lifecycle


A small Python library to **compute and apply policies** on AWS S3 lifecycle policies—especially focused on safe, declarative **storage class transitions**—with dry-run, validation, and minimal disruption.
---
## Problem
AWS S3 lifecycle policies are typically applied by overwriting the entire configuration. That makes automated changes brittle, error-prone, and risky when you only want to tweak transitions (e.g., change from `STANDARD` → `GLACIER` after 90 days) without accidentally deleting other rules.
This library:
- Introspects the current lifecycle policy
- Compares it to the desired policy
- Shows what would change (dry-run)
- Validates rules
- Applies only the intended change safely
---
## Features
- Declarative lifecycle policy definitions (via Python / JSON)
- Diff engine: detects rule adds / updates / deletes
- Safe apply with `dry-run`
- Validation of transition semantics (e.g., non-decreasing days)
- Idempotent behavior
- Pluggable for custom validation or rule logic
---
## Quickstart
### 1. Set Up AWS Environment
Before using `s3-lifecycle`, configure AWS credentials.
#### a) Using AWS CLI
```bash
aws configure
```
Provide:
```
AWS Access Key ID [None]: <YOUR_ACCESS_KEY>
AWS Secret Access Key [None]: <YOUR_SECRET_KEY>
Default region name [None]: <YOUR_DEFAULT_REGION> # e.g., us-east-1
Default output format [None]: json
```
#### b) Using environment variables
**Linux/macOS:**
```bash
export AWS_ACCESS_KEY_ID=<YOUR_ACCESS_KEY>
export AWS_SECRET_ACCESS_KEY=<YOUR_SECRET_KEY>
export AWS_DEFAULT_REGION=us-east-1
```
**Windows (PowerShell):**
```powershell
setx AWS_ACCESS_KEY_ID "<YOUR_ACCESS_KEY>"
setx AWS_SECRET_ACCESS_KEY "<YOUR_SECRET_KEY>"
setx AWS_DEFAULT_REGION "us-east-1"
```
> ⚠️ Ensure your IAM user has `s3:GetLifecycleConfiguration` and `s3:PutLifecycleConfiguration` permissions.
---
### 2. Install the Library
```bash
git clone https://github.com/FernandoOLI/s3-lifecycle.git
cd s3-lifecycle
pip install -e .
```
---
### 3. Basic Usage
```python
from s3_lifecycle import LifecyclePolicy, LifecycleManager, validate_policy, ValidationError, ApplyError
# Example lifecycle policy dictionary
desired_policy_dict = {
"Rules": [
{
"ID": "archive-log",
"Filter": {"Prefix": "logs/"},
"Status": "Enabled",
"Transitions": [
{"Days": 300, "StorageClass": "GLACIER"},
{"Days": 390, "StorageClass": "DEEP_ARCHIVE"}
],
"Expiration": {'Days': 500},
"NoncurrentVersionTransitions": [
{"NoncurrentDays": 30, "StorageClass": "GLACIER"},
{"NoncurrentDays": 150, "StorageClass": "DEEP_ARCHIVE"}
],
"NoncurrentVersionExpiration": {'NoncurrentDays': 700}
}
]
}
def main():
try:
# Create and validate policy
policy = LifecyclePolicy.from_dict(desired_policy_dict)
validate_policy(policy)
bucket = "lifecycle-management-bucket"
# Initialize manager (will create boto3 client if not passed)
manager = LifecycleManager()
# Compute input vs current S3 bucket policy
diff_result = manager.compute(bucket, policy)
# Apply changes safely (dry_run=True prints summary only)
manager.apply(bucket, diff_result, policy, dry_run=True)
except ValidationError as ve:
print(f"Policy validation error: {ve}, details: {ve.details}")
except ApplyError as ae:
print(f"Failed to apply lifecycle policy: {ae}")
except Exception as e:
print(f"Unexpected error: {e}")
if __name__ == "__main__":
main()
```
---
### 4. Notes
- `dry_run=True` only prints changes; no modifications are applied.
- Always validate IAM permissions before running `apply`.
- Supports declarative JSON/Python policy definitions for safe incremental updates.
---
## Contributing
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/my-feature`)
3. Make your changes
4. Run tests and ensure coverage
5. Submit a Pull Request
---
## License
MIT License
Raw data
{
"_id": null,
"home_page": "https://github.com/FernandoOLI/s3_lifecycle",
"name": "s3-lifecycle",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": null,
"keywords": "aws, s3, s3_lifecycle",
"author": "Fernando Oliveira Pereira",
"author_email": "Fernando Oliveira Pereira <oliveira-fernando1@hotmail.com>",
"download_url": "https://files.pythonhosted.org/packages/c3/38/ed2c1ca85663fd24ca2cc9c71522ed786f908d07c09e730e4ebcf1f632dd/s3_lifecycle-0.1.2.tar.gz",
"platform": null,
"description": "\n# s3-lifecycle\n\n\n\n\nA small Python library to **compute and apply policies** on AWS S3 lifecycle policies\u2014especially focused on safe, declarative **storage class transitions**\u2014with dry-run, validation, and minimal disruption.\n\n---\n\n## Problem\n\nAWS S3 lifecycle policies are typically applied by overwriting the entire configuration. That makes automated changes brittle, error-prone, and risky when you only want to tweak transitions (e.g., change from `STANDARD` \u2192 `GLACIER` after 90 days) without accidentally deleting other rules.\n\nThis library:\n\n- Introspects the current lifecycle policy\n- Compares it to the desired policy\n- Shows what would change (dry-run)\n- Validates rules\n- Applies only the intended change safely\n\n---\n\n## Features\n\n- Declarative lifecycle policy definitions (via Python / JSON)\n- Diff engine: detects rule adds / updates / deletes\n- Safe apply with `dry-run`\n- Validation of transition semantics (e.g., non-decreasing days)\n- Idempotent behavior\n- Pluggable for custom validation or rule logic\n\n---\n\n## Quickstart\n\n### 1. Set Up AWS Environment\n\nBefore using `s3-lifecycle`, configure AWS credentials.\n\n#### a) Using AWS CLI\n\n```bash\naws configure\n```\n\nProvide:\n\n```\nAWS Access Key ID [None]: <YOUR_ACCESS_KEY>\nAWS Secret Access Key [None]: <YOUR_SECRET_KEY>\nDefault region name [None]: <YOUR_DEFAULT_REGION> # e.g., us-east-1\nDefault output format [None]: json\n```\n\n#### b) Using environment variables\n\n**Linux/macOS:**\n\n```bash\nexport AWS_ACCESS_KEY_ID=<YOUR_ACCESS_KEY>\nexport AWS_SECRET_ACCESS_KEY=<YOUR_SECRET_KEY>\nexport AWS_DEFAULT_REGION=us-east-1\n```\n\n**Windows (PowerShell):**\n\n```powershell\nsetx AWS_ACCESS_KEY_ID \"<YOUR_ACCESS_KEY>\"\nsetx AWS_SECRET_ACCESS_KEY \"<YOUR_SECRET_KEY>\"\nsetx AWS_DEFAULT_REGION \"us-east-1\"\n```\n\n> \u26a0\ufe0f Ensure your IAM user has `s3:GetLifecycleConfiguration` and `s3:PutLifecycleConfiguration` permissions.\n\n---\n\n### 2. Install the Library\n\n```bash\ngit clone https://github.com/FernandoOLI/s3-lifecycle.git\ncd s3-lifecycle\npip install -e .\n```\n\n---\n\n### 3. Basic Usage\n\n```python\nfrom s3_lifecycle import LifecyclePolicy, LifecycleManager, validate_policy, ValidationError, ApplyError\n\n# Example lifecycle policy dictionary\ndesired_policy_dict = {\n \"Rules\": [\n {\n \"ID\": \"archive-log\",\n \"Filter\": {\"Prefix\": \"logs/\"},\n \"Status\": \"Enabled\",\n \"Transitions\": [\n {\"Days\": 300, \"StorageClass\": \"GLACIER\"},\n {\"Days\": 390, \"StorageClass\": \"DEEP_ARCHIVE\"}\n ],\n \"Expiration\": {'Days': 500},\n \"NoncurrentVersionTransitions\": [\n {\"NoncurrentDays\": 30, \"StorageClass\": \"GLACIER\"},\n {\"NoncurrentDays\": 150, \"StorageClass\": \"DEEP_ARCHIVE\"}\n ],\n \"NoncurrentVersionExpiration\": {'NoncurrentDays': 700}\n }\n ]\n}\n\ndef main():\n try:\n # Create and validate policy\n policy = LifecyclePolicy.from_dict(desired_policy_dict)\n validate_policy(policy)\n\n bucket = \"lifecycle-management-bucket\"\n\n # Initialize manager (will create boto3 client if not passed)\n manager = LifecycleManager()\n\n # Compute input vs current S3 bucket policy\n diff_result = manager.compute(bucket, policy)\n\n # Apply changes safely (dry_run=True prints summary only)\n manager.apply(bucket, diff_result, policy, dry_run=True)\n\n except ValidationError as ve:\n print(f\"Policy validation error: {ve}, details: {ve.details}\")\n except ApplyError as ae:\n print(f\"Failed to apply lifecycle policy: {ae}\")\n except Exception as e:\n print(f\"Unexpected error: {e}\")\n\nif __name__ == \"__main__\":\n main()\n```\n\n---\n\n### 4. Notes\n\n- `dry_run=True` only prints changes; no modifications are applied. \n- Always validate IAM permissions before running `apply`. \n- Supports declarative JSON/Python policy definitions for safe incremental updates.\n\n---\n\n## Contributing\n\n1. Fork the repository \n2. Create a feature branch (`git checkout -b feature/my-feature`) \n3. Make your changes \n4. Run tests and ensure coverage \n5. Submit a Pull Request \n\n---\n\n## License\n\nMIT License\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A Python library to manage S3 lifecycle policies",
"version": "0.1.2",
"project_urls": {
"Homepage": "https://github.com/FernandoOLI/s3_lifecycle",
"Issues": "https://github.com/FernandoOLI/s3_lifecycle/issues"
},
"split_keywords": [
"aws",
" s3",
" s3_lifecycle"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "2f2e56f617b10501bd204a6b2b5c5d86fdf2eb0aace36f6217e1faf2ce0209c4",
"md5": "bbd9f96a3a202630b43e9de48e87be0e",
"sha256": "87471dab15d5153264f6184887e549e2ecf4f0303659226ec96c51b73f4a0f04"
},
"downloads": -1,
"filename": "s3_lifecycle-0.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "bbd9f96a3a202630b43e9de48e87be0e",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 9929,
"upload_time": "2025-08-28T12:52:00",
"upload_time_iso_8601": "2025-08-28T12:52:00.863025Z",
"url": "https://files.pythonhosted.org/packages/2f/2e/56f617b10501bd204a6b2b5c5d86fdf2eb0aace36f6217e1faf2ce0209c4/s3_lifecycle-0.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "c338ed2c1ca85663fd24ca2cc9c71522ed786f908d07c09e730e4ebcf1f632dd",
"md5": "2a506f7f0f5f9ce514ec699d7c59425c",
"sha256": "3bcaebc78a558215623ead2c97ee1a46470df4db1db0081ac5554700c9ebdaf4"
},
"downloads": -1,
"filename": "s3_lifecycle-0.1.2.tar.gz",
"has_sig": false,
"md5_digest": "2a506f7f0f5f9ce514ec699d7c59425c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 7908,
"upload_time": "2025-08-28T12:52:02",
"upload_time_iso_8601": "2025-08-28T12:52:02.089690Z",
"url": "https://files.pythonhosted.org/packages/c3/38/ed2c1ca85663fd24ca2cc9c71522ed786f908d07c09e730e4ebcf1f632dd/s3_lifecycle-0.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-28 12:52:02",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "FernandoOLI",
"github_project": "s3_lifecycle",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "s3-lifecycle"
}