Skip to content

Commit 78be598

Browse files
feat: Added a new lifecycle_rules submodule which allows to add multiple expiry lifecycle rules to an existing cos bucket (#999)
1 parent ce92d6f commit 78be598

File tree

10 files changed

+335
-14
lines changed

10 files changed

+335
-14
lines changed

.secrets.baseline

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"files": "go.sum|^.secrets.baseline$",
44
"lines": null
55
},
6-
"generated_at": "2025-11-18T06:26:49Z",
6+
"generated_at": "2025-11-28T08:21:42Z",
77
"plugins_used": [
88
{
99
"name": "AWSKeyDetector"
@@ -82,15 +82,15 @@
8282
"hashed_secret": "ff9ee043d85595eb255c05dfe32ece02a53efbb2",
8383
"is_secret": false,
8484
"is_verified": false,
85-
"line_number": 40,
85+
"line_number": 41,
8686
"type": "Secret Keyword",
8787
"verified_result": null
8888
},
8989
{
9090
"hashed_secret": "a7c93faaa770c377154ea9d4d0d17a9056dbfa95",
9191
"is_secret": false,
9292
"is_verified": false,
93-
"line_number": 193,
93+
"line_number": 194,
9494
"type": "Secret Keyword",
9595
"verified_result": null
9696
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ You can configure the following aspects of your instances:
2323
* [Submodules](./modules)
2424
* [buckets](./modules/buckets)
2525
* [fscloud](./modules/fscloud)
26+
* [lifecycle_rules](./modules/lifecycle_rules)
2627
* [Examples](./examples)
2728
* <div style="display: inline-block;"><a href="./examples/advanced">Advanced example</a></div> <div style="display: inline-block; vertical-align: middle;"><a href="https://cloud.ibm.com/schematics/workspaces/create?workspace_name=cos-advanced-example&repository=https://github.com/terraform-ibm-modules/terraform-ibm-cos/tree/main/examples/advanced" target="_blank"><img src="https://cloud.ibm.com/media/docs/images/icons/Deploy_to_cloud.svg" alt="Deploy to IBM Cloud button"></a></div>
2829
* <div style="display: inline-block;"><a href="./examples/basic">Basic example</a></div> <div style="display: inline-block; vertical-align: middle;"><a href="https://cloud.ibm.com/schematics/workspaces/create?workspace_name=cos-basic-example&repository=https://github.com/terraform-ibm-modules/terraform-ibm-cos/tree/main/examples/basic" target="_blank"><img src="https://cloud.ibm.com/media/docs/images/icons/Deploy_to_cloud.svg" alt="Deploy to IBM Cloud button"></a></div>

examples/basic/main.tf

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,18 @@ module "resource_group" {
1515
##############################################################################
1616

1717
module "cos" {
18-
source = "../../"
19-
resource_group_id = module.resource_group.resource_group_id
20-
region = var.region
21-
cos_instance_name = "${var.prefix}-cos"
22-
cos_tags = var.resource_tags
23-
bucket_name = "${var.prefix}-bucket"
24-
retention_enabled = false # disable retention for test environments - enable for stage/prod
25-
kms_encryption_enabled = false
26-
cos_plan = "cos-one-rate-plan"
27-
bucket_storage_class = "onerate_active"
18+
source = "../../"
19+
resource_group_id = module.resource_group.resource_group_id
20+
region = var.region
21+
cos_instance_name = "${var.prefix}-cos"
22+
cos_tags = var.resource_tags
23+
bucket_name = "${var.prefix}-bucket"
24+
retention_enabled = false # disable retention for test environments - enable for stage/prod
25+
kms_encryption_enabled = false
26+
cos_plan = "cos-one-rate-plan"
27+
bucket_storage_class = "onerate_active"
28+
object_versioning_enabled = true
29+
access_tags = var.access_tags
2830
}
2931

3032
##############################################################################
@@ -43,3 +45,52 @@ module "buckets" {
4345
}
4446
]
4547
}
48+
49+
##############################################################################
50+
# Create Multiple Lifecycle Rules using lifecycle_rules submodule
51+
##############################################################################
52+
53+
module "advance_lifecycle_rules" {
54+
source = "../../modules/lifecycle_rules"
55+
cos_region = var.region
56+
bucket_crn = module.cos.bucket_crn
57+
expiry_rules = [
58+
{
59+
rule_id = "expiry-info-7d"
60+
days = 7
61+
prefix = "info-"
62+
},
63+
{
64+
rule_id = "expiry-error-30d"
65+
days = 30
66+
prefix = "error-"
67+
}
68+
]
69+
70+
noncurrent_expiry_rules = [
71+
{
72+
rule_id = "ncv-expire-45d"
73+
noncurrent_days = 45
74+
prefix = "data/"
75+
},
76+
{
77+
rule_id = "ncv-expire-90d"
78+
noncurrent_days = 90
79+
prefix = "archive/"
80+
}
81+
]
82+
83+
abort_multipart_rules = [
84+
{
85+
rule_id = "abort-stale-7d"
86+
days_after_initiation = 7
87+
prefix = ""
88+
},
89+
{
90+
rule_id = "abort-temp-3d"
91+
days_after_initiation = 3
92+
prefix = "tmp/"
93+
}
94+
]
95+
96+
}

examples/basic/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,9 @@ variable "resource_group" {
2525
description = "An existing resource group name to use for this example, if unset a new resource group will be created"
2626
default = null
2727
}
28+
29+
variable "access_tags" {
30+
type = list(string)
31+
description = "Optional list of access tags to be added to the created resources"
32+
default = []
33+
}

modules/lifecycle_rules/README.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Cloud Object Storage lifecycle_rules module
2+
3+
You can use this submodule to configure multiple lifecycle rules to existing IBM [Cloud Object Storage](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-getting-started-cloud-object-storage) buckets.
4+
5+
You can configure the following multiple rules to your buckets:
6+
- [expiration](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-expiry)
7+
- [noncurrent version expiration](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-expiry#noncurrentversionexpiration)
8+
- [abort incomplete multipart](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-lifecycle-cleanup-mpu)
9+
10+
### Usage
11+
```hcl
12+
module "advance_lifecycle_rules" {
13+
source = "terraform-ibm-modules/cos/ibm//modules/lifecycle_rules"
14+
cos_region = "region of the existing bucket"
15+
bucket_crn = "crn:v1:bluemix:public:cloud-object-storage:global:a/xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX:bucket:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx" # existing bucket crn
16+
object_versioning_enabled = false # False by default , must be set to true for noncurrent version expiration lifecycle rule
17+
expiry_rules = [
18+
{
19+
rule_id = "expiry-info-7d"
20+
days = 7
21+
prefix = "info-"
22+
},
23+
{
24+
rule_id = "expiry-error-30d"
25+
days = 30
26+
prefix = "error-"
27+
}
28+
]
29+
30+
noncurrent_expiry_rules = [
31+
{
32+
rule_id = "ncv-expire-45d"
33+
noncurrent_days = 45
34+
prefix = "data/"
35+
},
36+
{
37+
rule_id = "ncv-expire-90d"
38+
noncurrent_days = 90
39+
prefix = "archive/"
40+
}
41+
]
42+
43+
abort_multipart_rules = [
44+
{
45+
rule_id = "abort-stale-7d"
46+
days_after_initiation = 7
47+
prefix = ""
48+
},
49+
{
50+
rule_id = "abort-temp-3d"
51+
days_after_initiation = 3
52+
prefix = "tmp/"
53+
}
54+
]
55+
56+
}
57+
```
58+
59+
60+
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
61+
### Requirements
62+
63+
| Name | Version |
64+
|------|---------|
65+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.0 |
66+
| <a name="requirement_ibm"></a> [ibm](#requirement\_ibm) | >= 1.79.2, < 2.0.0 |
67+
68+
### Modules
69+
70+
No modules.
71+
72+
### Resources
73+
74+
| Name | Type |
75+
|------|------|
76+
| [ibm_cos_bucket_lifecycle_configuration.advance_bucket_lifecycle](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/cos_bucket_lifecycle_configuration) | resource |
77+
78+
### Inputs
79+
80+
| Name | Description | Type | Default | Required |
81+
|------|-------------|------|---------|:--------:|
82+
| <a name="input_abort_multipart_rules"></a> [abort\_multipart\_rules](#input\_abort\_multipart\_rules) | List of abort incomplete multipart upload rules | <pre>list(object({<br/> rule_id = optional(string)<br/> status = optional(string, "enable")<br/> days_after_initiation = number<br/> prefix = optional(string, "")<br/> }))</pre> | `[]` | no |
83+
| <a name="input_bucket_crn"></a> [bucket\_crn](#input\_bucket\_crn) | The CRN of an existing Cloud Object Storage bucket. | `string` | n/a | yes |
84+
| <a name="input_cos_region"></a> [cos\_region](#input\_cos\_region) | The region of existing Cloud Object Storage bucket. | `string` | n/a | yes |
85+
| <a name="input_expiry_rules"></a> [expiry\_rules](#input\_expiry\_rules) | List of expiry rules | <pre>list(object({<br/> rule_id = optional(string)<br/> status = optional(string, "enable")<br/> days = number<br/> prefix = optional(string, "")<br/> }))</pre> | `[]` | no |
86+
| <a name="input_management_endpoint_type_for_bucket"></a> [management\_endpoint\_type\_for\_bucket](#input\_management\_endpoint\_type\_for\_bucket) | The type of endpoint for the IBM terraform provider to manage the bucket. Possible values are `public`, `private`, or `direct`. | `string` | `"public"` | no |
87+
| <a name="input_noncurrent_expiry_rules"></a> [noncurrent\_expiry\_rules](#input\_noncurrent\_expiry\_rules) | List of noncurrent version expiration rules , note : this lifecycle rule requires object versioning make sure object versioning is enabled on the bucket | <pre>list(object({<br/> rule_id = optional(string)<br/> status = optional(string, "enable")<br/> noncurrent_days = number<br/> prefix = optional(string, "")<br/> }))</pre> | `[]` | no |
88+
89+
### Outputs
90+
91+
| Name | Description |
92+
|------|-------------|
93+
| <a name="output_bucket_crn"></a> [bucket\_crn](#output\_bucket\_crn) | Bucket CRN |
94+
| <a name="output_bucket_id"></a> [bucket\_id](#output\_bucket\_id) | Bucket ID |
95+
| <a name="output_bucket_location"></a> [bucket\_location](#output\_bucket\_location) | Bucket location |
96+
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

modules/lifecycle_rules/main.tf

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
locals {
2+
# Assign deterministic rule IDs if not provided
3+
expiry_rules = [
4+
for idx, r in var.expiry_rules : merge(r, {
5+
rule_id = coalesce(try(r.rule_id, null), "expiry-rule-${idx}")
6+
})
7+
]
8+
9+
noncurrent_expiry_rules = [
10+
for idx, r in var.noncurrent_expiry_rules : merge(r, {
11+
rule_id = coalesce(try(r.rule_id, null), "noncurrent-expiry-rule-${idx}")
12+
})
13+
]
14+
15+
abort_multipart_rules = [
16+
for idx, r in var.abort_multipart_rules : merge(r, {
17+
rule_id = coalesce(try(r.rule_id, null), "abort-multipart-rule-${idx}")
18+
})
19+
]
20+
}
21+
22+
23+
resource "ibm_cos_bucket_lifecycle_configuration" "advance_bucket_lifecycle" {
24+
bucket_crn = var.bucket_crn
25+
bucket_location = var.cos_region
26+
endpoint_type = var.management_endpoint_type_for_bucket
27+
28+
# Expiration rules
29+
dynamic "lifecycle_rule" {
30+
for_each = local.expiry_rules
31+
content {
32+
expiration {
33+
days = lifecycle_rule.value.days
34+
}
35+
filter {
36+
prefix = lifecycle_rule.value.prefix
37+
}
38+
rule_id = lifecycle_rule.value.rule_id
39+
status = lifecycle_rule.value.status
40+
}
41+
}
42+
43+
44+
# Noncurrent version expiration rules
45+
dynamic "lifecycle_rule" {
46+
for_each = local.noncurrent_expiry_rules
47+
content {
48+
noncurrent_version_expiration {
49+
noncurrent_days = lifecycle_rule.value.noncurrent_days
50+
}
51+
filter {
52+
prefix = lifecycle_rule.value.prefix
53+
}
54+
rule_id = lifecycle_rule.value.rule_id
55+
status = lifecycle_rule.value.status
56+
}
57+
}
58+
59+
# Abort multipart rules
60+
dynamic "lifecycle_rule" {
61+
for_each = local.abort_multipart_rules
62+
content {
63+
abort_incomplete_multipart_upload {
64+
days_after_initiation = lifecycle_rule.value.days_after_initiation
65+
}
66+
filter {
67+
prefix = lifecycle_rule.value.prefix
68+
}
69+
rule_id = lifecycle_rule.value.rule_id
70+
status = lifecycle_rule.value.status
71+
}
72+
}
73+
74+
}

modules/lifecycle_rules/outputs.tf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
output "bucket_crn" {
2+
value = ibm_cos_bucket_lifecycle_configuration.advance_bucket_lifecycle.bucket_crn
3+
description = "Bucket CRN"
4+
}
5+
6+
output "bucket_location" {
7+
value = ibm_cos_bucket_lifecycle_configuration.advance_bucket_lifecycle.bucket_location
8+
description = "Bucket location"
9+
}
10+
11+
output "bucket_id" {
12+
value = ibm_cos_bucket_lifecycle_configuration.advance_bucket_lifecycle.id
13+
description = "Bucket ID"
14+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
variable "bucket_crn" {
2+
description = "The CRN of an existing Cloud Object Storage bucket."
3+
type = string
4+
}
5+
6+
variable "cos_region" {
7+
description = "The region of existing Cloud Object Storage bucket."
8+
type = string
9+
}
10+
11+
variable "management_endpoint_type_for_bucket" {
12+
description = "The type of endpoint for the IBM terraform provider to manage the bucket. Possible values are `public`, `private`, or `direct`."
13+
type = string
14+
default = "public"
15+
validation {
16+
condition = contains(["public", "private", "direct"], var.management_endpoint_type_for_bucket)
17+
error_message = "The value isn't valid. Possible values are `public`, `private`, or `direct`."
18+
}
19+
}
20+
21+
variable "expiry_rules" {
22+
description = "List of expiry rules"
23+
type = list(object({
24+
rule_id = optional(string)
25+
status = optional(string, "enable")
26+
days = number
27+
prefix = optional(string, "")
28+
}))
29+
default = []
30+
31+
validation {
32+
condition = alltrue([for r in var.expiry_rules : r.days >= 1])
33+
error_message = "Expiry days must be >= 1."
34+
}
35+
36+
}
37+
variable "noncurrent_expiry_rules" {
38+
description = "List of noncurrent version expiration rules , note : this lifecycle rule requires object versioning make sure object versioning is enabled on the bucket"
39+
type = list(object({
40+
rule_id = optional(string)
41+
status = optional(string, "enable")
42+
noncurrent_days = number
43+
prefix = optional(string, "")
44+
}))
45+
default = []
46+
47+
validation {
48+
condition = alltrue([for r in var.noncurrent_expiry_rules : try(r.noncurrent_days, 0) >= 1])
49+
error_message = "Each noncurrent version expiration rule must have noncurrent_days >= 1."
50+
}
51+
}
52+
53+
variable "abort_multipart_rules" {
54+
description = "List of abort incomplete multipart upload rules"
55+
type = list(object({
56+
rule_id = optional(string)
57+
status = optional(string, "enable")
58+
days_after_initiation = number
59+
prefix = optional(string, "")
60+
}))
61+
default = []
62+
63+
validation {
64+
condition = alltrue([for r in var.abort_multipart_rules : try(r.days_after_initiation, 0) >= 1])
65+
error_message = "Each abort multipart rule must have days_after_initiation >= 1."
66+
}
67+
}

modules/lifecycle_rules/version.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
terraform {
2+
required_version = ">= 1.9.0"
3+
4+
# Use a flexible range in modules that future proofs the module's usage with upcoming minor and patch versions
5+
required_providers {
6+
# tflint-ignore: terraform_unused_required_providers
7+
ibm = {
8+
source = "ibm-cloud/ibm"
9+
version = ">= 1.79.2, < 2.0.0"
10+
}
11+
}
12+
}

0 commit comments

Comments
 (0)