diff --git a/examples/ibm-cos-bucket/README.md b/examples/ibm-cos-bucket/README.md index d6b828091b..f7f8556a53 100644 --- a/examples/ibm-cos-bucket/README.md +++ b/examples/ibm-cos-bucket/README.md @@ -96,6 +96,62 @@ resource "ibm_cos_bucket" "archive_expire_rule_cos" { prefix = "logs/" } } +resource "ibm_cos_bucket" "expirebucket" { + bucket_name = "a-bucket-expiredat" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + force_delete = true + object_versioning { + enable = true + } + expire_rule { + rule_id = "a-bucket-expire-rule" + enable = true + date = "2021-11-18" + prefix = "logs/" + } + noncurrent_version_expiration { + rule_id = "my-rule-id-bucket-ncversion" + enable = true + prefix = "" + noncurrent_days = 1 + } +} + +resource "ibm_cos_bucket" "cos_bucket" { + bucket_name = "a-bucket-expireddelemarkertest" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } + expire_rule { + rule_id = "my-rule-id-bucket-expired" + enable = true + expired_object_delete_marker = true + } + noncurrent_version_expiration { + rule_id = "my-rule-id-bucket-ncversion" + enable = true + prefix = "" + noncurrent_days = 1 + } +} + +resource "ibm_cos_bucket" "cos_bucket" { + bucket_name = "a-bucket-multipartupload" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + abort_incomplete_multipart_upload_days { + rule_id = var.abort_mpu_ruleid + enable = true + prefix = "" + days_after_initiation = 1 + } +} resource "ibm_cos_bucket" "retention_cos" { bucket_name = "a-bucket-retention" @@ -171,16 +227,18 @@ data "ibm_cos_bucket" "standard-ams03" { | usage_metrics_enabled | Specify true or false to set usage metrics (i.e. bytes_used). | `bool` | no | request_metrics_enabled | Specify true or false to set cos request metrics (i.e. get,put,post request). | `bool` | no | metrics_monitoring_crn | Required the first time metrics_monitoring is configured. The instance of IBM Cloud Monitoring that will receive the bucket metrics. | `string` | yes -| archive_ruleid | Unique identifier for the rule. | `string` | no | regional_loc | The location for a regional bucket. Supported values are au-syd, eu-de, eu-gb, jp-tok,,us-east,us-south. | `string` | no -| archive_days | Specifies the number of days when the specific archive rule action takes effect. | `int` | yes -| archive_types | Specifies the archive type to which you want the object to transition. Supported values are Glacier or Accelerated. | `string` | yes -| expire_ruleid | Unique identifier for the rule. | `string` | no -| expire_days | Specifies the number of days when the specific expire rule action takes effect. | `int` | yes -| expire_prefix | Specifies a prefix filter to apply to only a subset of objects with names that match the prefix. | `string` | no +| type | Specifies the archive type to which you want the object to transition. Supported values are Glacier or Accelerated. | `string` |yes +| rule_id | Unique identifier for the rule. | `string` | no +| days | Specifies the number of days when the specific expire rule action takes effect. | `int` | no +| date | After the specifies date , the current version of objects in your bucket expires.. | `string` | no +| expired_object_delete_marker | Expired object delete markers can be automatically cleaned up to improve performance in bucket. This cannot be used alongside version expiration. | `bool` | no +| prefix | Specifies a prefix filter to apply to only a subset of objects with names that match the prefix. | `string` | no +| noncurrent_days | Configuration parameter in your policy that says how long to retain a non-current version before deleting it. | `int` | no +| days_after_initiation | Specifies the number of days that govern the automatic cancellation of part upload. Clean up incomplete multi-part uploads after a period of time. | `int` | no | default | Specifies a default retention period to apply in all objects in the bucket. | `int` | yes | maximum | Specifies maximum duration of time an object can be kept unmodified in the bucket. | `int` | yes | minimum | Specifies minimum duration of time an object must be kept unmodified in the bucket. | `int` | yes | permanent | Specifies a permanent retention status either enable or disable for a bucket. | `bool` | no | enable | Specifies Versioning status either enable or Suspended for the objects in the bucket. | `bool` | no -| hard_quota | sets a maximum amount of storage (in bytes) available for a bucket. | `int` | no \ No newline at end of file +| hard_quota | sets a maximum amount of storage (in bytes) available for a bucket. | `int` | no diff --git a/examples/ibm-cos-bucket/main.tf b/examples/ibm-cos-bucket/main.tf index c884c870a1..ffa6f8a5dd 100644 --- a/examples/ibm-cos-bucket/main.tf +++ b/examples/ibm-cos-bucket/main.tf @@ -13,14 +13,14 @@ resource "ibm_resource_instance" "activity_tracker" { resource_group_id = data.ibm_resource_group.cos_group.id service = "logdnaat" plan = "lite" - location = "us-south" + location = var.regional_loc } resource "ibm_resource_instance" "metrics_monitor" { name = "metrics_monitor" resource_group_id = data.ibm_resource_group.cos_group.id service = "sysdig-monitor" plan = "graduated-tier" - location = "us-south" + location = var.regional_loc parameters = { default_receiver = true } @@ -79,6 +79,24 @@ resource "ibm_cos_bucket" "cos_bucket" { object_versioning { enable = true } + abort_incomplete_multipart_upload_days { + rule_id = var.abort_mpu_ruleid + enable = true + prefix = var.abort_mpu_prefix + days_after_initiation = var.abort_mpu_days_init + } + expire_rule { + rule_id = var.expire_ruleid + enable = true + date = var.expire_date + prefix = var.expire_prefix + } + noncurrent_version_expiration { + rule_id = var.nc_exp_ruleid + enable = true + prefix = var.nc_exp_prefix + noncurrent_days = var.nc_exp_days + } } resource "ibm_cos_bucket_object" "plaintext" { @@ -87,10 +105,3 @@ resource "ibm_cos_bucket_object" "plaintext" { content = "Hello World" key = "plaintext.txt" } - -resource "ibm_cos_bucket_object" "base64" { - bucket_crn = ibm_cos_bucket.cos_bucket.crn - bucket_location = ibm_cos_bucket.cos_bucket.region_location - content_base64 = "RW5jb2RlZCBpbiBiYXNlNjQ=" - key = "base64.txt" -} diff --git a/examples/ibm-cos-bucket/variables.tf b/examples/ibm-cos-bucket/variables.tf index 8ae98e179d..2fafba69e6 100644 --- a/examples/ibm-cos-bucket/variables.tf +++ b/examples/ibm-cos-bucket/variables.tf @@ -42,10 +42,38 @@ variable "expire_days" { default = 1 } +variable "expire_date" { + default = "" +} + variable "expire_prefix" { default = "" } +variable "nc_exp_ruleid" { + default = "test-obj-ver-exp-3" +} + +variable "nc_exp_days" { + default = 1 +} + +variable "nc_exp_prefix" { + default = "" +} + +variable "abort_mpu_ruleid" { + default = "test-abort_mpu-5" +} + +variable "abort_mpu_days_init" { + default = 1 +} + +variable "abort_mpu_prefix" { + default = "" +} + variable "default_retention" { default = "0" } diff --git a/go.mod b/go.mod index f4dde0bd84..a4ed6a07d1 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/IBM/event-notifications-go-admin-sdk v0.0.2 github.com/IBM/eventstreams-go-sdk v1.2.0 github.com/IBM/go-sdk-core/v5 v5.7.2 - github.com/IBM/ibm-cos-sdk-go v1.7.0 + github.com/IBM/ibm-cos-sdk-go v1.8.0 github.com/IBM/ibm-cos-sdk-go-config v1.2.0 github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20211109141421-a4b61b05f7d1 github.com/IBM/keyprotect-go-client v0.7.0 diff --git a/go.sum b/go.sum index 30d8f3222d..af56054594 100644 --- a/go.sum +++ b/go.sum @@ -78,6 +78,8 @@ github.com/IBM/go-sdk-core/v5 v5.7.2/go.mod h1:+YbdhrjCHC84ls4MeBp+Hj4NZCni+tDAc github.com/IBM/ibm-cos-sdk-go v1.3.1/go.mod h1:YLBAYobEA8bD27P7xpMwSQeNQu6W3DNBtBComXrRzRY= github.com/IBM/ibm-cos-sdk-go v1.7.0 h1:3DZULY/D5WzjlIm+Iaj6h0surEjQs65EZk1YAe8+rj0= github.com/IBM/ibm-cos-sdk-go v1.7.0/go.mod h1:Oi8AC5WNDhmUJgbo1GL2FtBdo0nRgbzE/1HmCL1SERU= +github.com/IBM/ibm-cos-sdk-go v1.8.0 h1:6d3BY+jo71JvQoyUwdtv4pemEfbnK/XSKQCKOEuWmks= +github.com/IBM/ibm-cos-sdk-go v1.8.0/go.mod h1:Oi8AC5WNDhmUJgbo1GL2FtBdo0nRgbzE/1HmCL1SERU= github.com/IBM/ibm-cos-sdk-go-config v1.2.0 h1:1E93234yZgVS0ntm7eUwVb3h0AAayPGcxEhhizEN1LE= github.com/IBM/ibm-cos-sdk-go-config v1.2.0/go.mod h1:Wetfgv6m1xyuzpZLQTTLIBsWstxjYa15h+Utj7x53Dk= github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20211109141421-a4b61b05f7d1 h1:T5UwRKKd+BoaPZ7UIlpJrzXzVTUEs8HcxwQ3pCIbORs= diff --git a/ibm/data_source_ibm_cos_bucket.go b/ibm/data_source_ibm_cos_bucket.go index fcc45f66f0..b369c91f65 100644 --- a/ibm/data_source_ibm_cos_bucket.go +++ b/ibm/data_source_ibm_cos_bucket.go @@ -137,6 +137,34 @@ func dataSourceIBMCosBucket() *schema.Resource { }, }, }, + "abort_incomplete_multipart_upload_days": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier for the rule. Rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + }, + "enable": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "days_after_initiation": { + Type: schema.TypeInt, + Computed: true, + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + }, + }, + }, "archive_rule": { Type: schema.TypeList, Computed: true, @@ -178,6 +206,11 @@ func dataSourceIBMCosBucket() *schema.Resource { Computed: true, Description: "Enable or disable an archive rule for a bucket", }, + "date": { + Type: schema.TypeString, + Computed: true, + Description: "Specifies the date when the specific rule action takes effect.", + }, "days": { Type: schema.TypeInt, Computed: true, @@ -188,6 +221,11 @@ func dataSourceIBMCosBucket() *schema.Resource { Computed: true, Description: "The rule applies to any objects with keys that match this prefix", }, + "expired_object_delete_marker": { + Type: schema.TypeBool, + Computed: true, + Description: "Expired object delete markers can be automatically cleaned up to improve performance in bucket. This cannot be used alongside version expiration.", + }, }, }, }, @@ -234,6 +272,35 @@ func dataSourceIBMCosBucket() *schema.Resource { }, }, }, + "noncurrent_version_expiration": { + Type: schema.TypeList, + Computed: true, + Description: "Enable configuration expire_rule to COS Bucket after a defined period of time", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier for the rule.Expire rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + }, + "enable": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable an expire rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "noncurrent_days": { + Type: schema.TypeInt, + Computed: true, + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + }, + }, + }, "hard_quota": { Type: schema.TypeInt, Computed: true, @@ -381,7 +448,7 @@ func dataSourceIBMCosBucketRead(d *schema.ResourceData, meta interface{}) error } - // Read the lifecycle configuration (archive) + // Read the lifecycle configuration gInput := &s3.GetBucketLifecycleConfigurationInput{ Bucket: aws.String(bucketName), @@ -397,12 +464,20 @@ func dataSourceIBMCosBucketRead(d *schema.ResourceData, meta interface{}) error if len(lifecycleptr.Rules) > 0 { archiveRules := archiveRuleGet(lifecycleptr.Rules) expireRules := expireRuleGet(lifecycleptr.Rules) + nc_expRules := nc_exp_RuleGet(lifecycleptr.Rules) + abort_mpuRules := abort_mpu_RuleGet(lifecycleptr.Rules) if len(archiveRules) > 0 { d.Set("archive_rule", archiveRules) } if len(expireRules) > 0 { d.Set("expire_rule", expireRules) } + if len(nc_expRules) > 0 { + d.Set("noncurrent_version_expiration", nc_expRules) + } + if len(abort_mpuRules) > 0 { + d.Set("abort_incomplete_multipart_upload_days", abort_mpuRules) + } } } diff --git a/ibm/resource_ibm_cos_bucket.go b/ibm/resource_ibm_cos_bucket.go index a01912125f..b600dd8ad4 100644 --- a/ibm/resource_ibm_cos_bucket.go +++ b/ibm/resource_ibm_cos_bucket.go @@ -190,6 +190,39 @@ func resourceIBMCOSBucket() *schema.Resource { }, }, }, + "abort_incomplete_multipart_upload_days": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Enable abort incomplete multipart upload to COS Bucket after a defined period of time", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Unique identifier for the rule. Rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + }, + "enable": { + Type: schema.TypeBool, + Required: true, + Description: "Enable or disable rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "days_after_initiation": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validateAllowedRangeInt(1, 3650), + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + }, + }, + }, "archive_rule": { Type: schema.TypeList, Optional: true, @@ -227,7 +260,7 @@ func resourceIBMCOSBucket() *schema.Resource { "expire_rule": { Type: schema.TypeList, Optional: true, - MaxItems: 1000, + MaxItems: 1, Description: "Enable configuration expire_rule to COS Bucket after a defined period of time", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -248,11 +281,25 @@ func resourceIBMCOSBucket() *schema.Resource { Computed: true, Description: "The rule applies to any objects with keys that match this prefix", }, + "date": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"expire_rule.0.days", "expire_rule.0.expired_object_delete_marker"}, + ValidateFunc: validBucketLifecycleTimestamp, + Description: "Specify a rule to expire the current version of objects in bucket after a specific date.", + }, "days": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validateAllowedRangeInt(0, 3650), - Description: "Specifies the number of days when the specific rule action takes effect.", + Type: schema.TypeInt, + Optional: true, + ConflictsWith: []string{"expire_rule.0.date", "expire_rule.0.expired_object_delete_marker"}, + ValidateFunc: validateAllowedRangeInt(1, 3650), + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + "expired_object_delete_marker": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"expire_rule.0.date", "expire_rule.0.days"}, + Description: "Expired object delete markers can be automatically cleaned up to improve performance in bucket. This cannot be used alongside version expiration.", }, }, }, @@ -296,11 +343,10 @@ func resourceIBMCOSBucket() *schema.Resource { }, }, "object_versioning": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - ConflictsWith: []string{"retention_rule", "expire_rule"}, - Description: "Protect objects from accidental deletion or overwrites. Versioning allows you to keep multiple versions of an object protecting from unintentional data loss.", + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Protect objects from accidental deletion or overwrites. Versioning allows you to keep multiple versions of an object protecting from unintentional data loss.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "enable": { @@ -312,6 +358,39 @@ func resourceIBMCOSBucket() *schema.Resource { }, }, }, + "noncurrent_version_expiration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Enable configuration expire_rule to COS Bucket after a defined period of time", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Unique identifier for the rule.Expire rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket", + }, + "enable": { + Type: schema.TypeBool, + Required: true, + Description: "Enable or disable an expire rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "noncurrent_days": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validateAllowedRangeInt(1, 3650), + Description: "Specifies the number of days when the specific rule action takes effect.", + }, + }, + }, + }, "hard_quota": { Type: schema.TypeInt, Optional: true, @@ -377,9 +456,107 @@ func archiveRuleList(archiveList []interface{}) []*s3.LifecycleRule { return rules } +func nc_expRuleList(nc_expList []interface{}) []*s3.LifecycleRule { + var nc_exp_prefix, nc_exp_status, rule_id string + var nc_days int64 + var rules []*s3.LifecycleRule + + for _, l := range nc_expList { + nc_expMap, _ := l.(map[string]interface{}) + //Rule ID + if rule_idSet, exist := nc_expMap["rule_id"]; exist { + id := rule_idSet.(string) + rule_id = id + } + + //Status Enable/Disable + if nc_exp_statusSet, exist := nc_expMap["enable"]; exist { + nc_expStatusEnabled := nc_exp_statusSet.(bool) + if nc_expStatusEnabled == true { + nc_exp_status = "Enabled" + } else { + nc_exp_status = "Disabled" + } + } + //Days + if nc_exp_daySet, exist := nc_expMap["noncurrent_days"]; exist { + nc_exp_days := int64(nc_exp_daySet.(int)) + nc_days = nc_exp_days + } + //Expire Prefix + if nc_expPrefixClassSet, exist := nc_expMap["prefix"]; exist { + prefix_check := nc_expPrefixClassSet.(string) + nc_exp_prefix = prefix_check + } + + nc_exp_rule := s3.LifecycleRule{ + ID: aws.String(rule_id), + Status: aws.String(nc_exp_status), + Filter: &s3.LifecycleRuleFilter{ + Prefix: aws.String(nc_exp_prefix), + }, + NoncurrentVersionExpiration: &s3.NoncurrentVersionExpiration{ + NoncurrentDays: aws.Int64(nc_days), + }, + } + rules = append(rules, &nc_exp_rule) + } + return rules +} + +func abortmpuRuleList(abortmpuList []interface{}) []*s3.LifecycleRule { + var abort_mpu_prefix, abort_mpu_status, rule_id string + var abort_mpu_days_init int64 + var rules []*s3.LifecycleRule + + for _, l := range abortmpuList { + abortmpuMap, _ := l.(map[string]interface{}) + //Rule ID + if rule_idSet, exist := abortmpuMap["rule_id"]; exist { + id := rule_idSet.(string) + rule_id = id + } + + //Status Enable/Disable + if abort_mpu_statusSet, exist := abortmpuMap["enable"]; exist { + abort_mpuStatusEnabled := abort_mpu_statusSet.(bool) + if abort_mpuStatusEnabled == true { + abort_mpu_status = "Enabled" + } else { + abort_mpu_status = "Disabled" + } + } + //Days + if abort_mpu_daySet, exist := abortmpuMap["days_after_initiation"]; exist { + abort_mpu_days := int64(abort_mpu_daySet.(int)) + abort_mpu_days_init = abort_mpu_days + } + //Expire Prefix + if abort_mpuPrefixClassSet, exist := abortmpuMap["prefix"]; exist { + prefix_check := abort_mpuPrefixClassSet.(string) + abort_mpu_prefix = prefix_check + } + + abort_mpu_rule := s3.LifecycleRule{ + ID: aws.String(rule_id), + Status: aws.String(abort_mpu_status), + Filter: &s3.LifecycleRuleFilter{ + Prefix: aws.String(abort_mpu_prefix), + }, + AbortIncompleteMultipartUpload: &s3.AbortIncompleteMultipartUpload{ + DaysAfterInitiation: aws.Int64(abort_mpu_days_init), + }, + } + rules = append(rules, &abort_mpu_rule) + } + return rules +} + func expireRuleList(expireList []interface{}) []*s3.LifecycleRule { var expire_prefix, expire_status, rule_id string + var expire_date time.Time var days int64 + var expired_object_del_marker bool var rules []*s3.LifecycleRule for _, l := range expireList { @@ -392,8 +569,8 @@ func expireRuleList(expireList []interface{}) []*s3.LifecycleRule { //Status Enable/Disable if expire_statusSet, exist := expireMap["enable"]; exist { - archiveStatusEnabled := expire_statusSet.(bool) - if archiveStatusEnabled == true { + expireStatusEnabled := expire_statusSet.(bool) + if expireStatusEnabled == true { expire_status = "Enabled" } else { expire_status = "Disabled" @@ -404,22 +581,45 @@ func expireRuleList(expireList []interface{}) []*s3.LifecycleRule { daysexpire := int64(daysexpireSet.(int)) days = daysexpire } + //Date + if dateexpireSet, exist := expireMap["date"]; exist { + //dateexpire := dateexpireSet.(string) + expiredatevalue := dateexpireSet.(string) + expire_date, _ = time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", expiredatevalue)) + } //Expire Prefix if expirePrefixClassSet, exist := expireMap["prefix"]; exist { - expire_prefix = expirePrefixClassSet.(string) + prefix := expirePrefixClassSet.(string) + expire_prefix = prefix } + // Expired Object Delete Marker + if expireObjectDelMarkerSet, exist := expireMap["expired_object_delete_marker"]; exist { + expired_object_del_marker = expireObjectDelMarkerSet.(bool) + } + var i *s3.LifecycleExpiration + if expired_object_del_marker == true { + i = &s3.LifecycleExpiration{ + ExpiredObjectDeleteMarker: aws.Bool(expired_object_del_marker), + } + } else if days > 0 { + i = &s3.LifecycleExpiration{ + Days: aws.Int64(days), + } + } else if !expire_date.IsZero() { + i = &s3.LifecycleExpiration{ + Date: aws.Time(expire_date), + } + } expire_rule := s3.LifecycleRule{ ID: aws.String(rule_id), Status: aws.String(expire_status), Filter: &s3.LifecycleRuleFilter{ Prefix: aws.String(expire_prefix), }, - Expiration: &s3.LifecycleExpiration{ - Days: aws.Int64(days), - }, - } + Expiration: i, + } rules = append(rules, &expire_rule) } return rules @@ -466,28 +666,36 @@ func resourceIBMCOSBucketUpdate(d *schema.ResourceData, meta interface{}) error s3Sess := session.Must(session.NewSession()) s3Client := s3.New(s3Sess, s3Conf) - //// Update the lifecycle (Archive or Expire) - if d.HasChange("archive_rule") || d.HasChange("expire_rule") { + //// Update the lifecycle (Archive or Expire or Non Current version or Abort incomplete Multipart Upload) + if d.HasChange("archive_rule") || d.HasChange("expire_rule") || d.HasChange("noncurrent_version_expiration") || d.HasChange("abort_incomplete_multipart_upload_days") { var archive, archive_ok = d.GetOk("archive_rule") var expire, expire_ok = d.GetOk("expire_rule") + var noncurrentverexp, nc_exp_ok = d.GetOk("noncurrent_version_expiration") + var abortmpu, abort_mpu_ok = d.GetOk("abort_incomplete_multipart_upload_days") var rules []*s3.LifecycleRule - if archive_ok || expire_ok { - if expire_ok { - rules = append(rules, expireRuleList(expire.([]interface{}))...) - } + if archive_ok || expire_ok || nc_exp_ok || abort_mpu_ok { if archive_ok { rules = append(rules, archiveRuleList(archive.([]interface{}))...) } - + if nc_exp_ok { + rules = append(rules, nc_expRuleList(noncurrentverexp.([]interface{}))...) + } + if abort_mpu_ok { + rules = append(rules, abortmpuRuleList(abortmpu.([]interface{}))...) + } + if expire_ok { + rules = append(rules, expireRuleList(expire.([]interface{}))...) + } lInput := &s3.PutBucketLifecycleConfigurationInput{ Bucket: aws.String(bucketName), LifecycleConfiguration: &s3.LifecycleConfiguration{ Rules: rules, }, } + _, err := s3Client.PutBucketLifecycleConfiguration(lInput) if err != nil { - return fmt.Errorf("failed to update the archive rule on COS bucket %s, %v", bucketName, err) + return fmt.Errorf("failed to update the lifecyle rule on COS bucket %s, %v", bucketName, err) } } else { @@ -819,7 +1027,7 @@ func resourceIBMCOSBucketRead(d *schema.ResourceData, meta interface{}) error { d.Set("hard_quota", bucketPtr.HardQuota) } } - // Read the lifecycle configuration (archive & expiration) + // Read the lifecycle configuration (archive & expiration or non current version or abort incomplete multipart upload) gInput := &s3.GetBucketLifecycleConfigurationInput{ Bucket: aws.String(bucketName), @@ -830,16 +1038,23 @@ func resourceIBMCOSBucketRead(d *schema.ResourceData, meta interface{}) error { if (err != nil && !strings.Contains(err.Error(), "NoSuchLifecycleConfiguration: The lifecycle configuration does not exist")) && (err != nil && bucketPtr != nil && bucketPtr.Firewall != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied")) { return err } - if lifecycleptr != nil { archiveRules := archiveRuleGet(lifecycleptr.Rules) expireRules := expireRuleGet(lifecycleptr.Rules) + nc_expRules := nc_exp_RuleGet(lifecycleptr.Rules) + abort_mpuRules := abort_mpu_RuleGet(lifecycleptr.Rules) if len(archiveRules) > 0 { d.Set("archive_rule", archiveRules) } if len(expireRules) > 0 { d.Set("expire_rule", expireRules) } + if len(nc_expRules) > 0 { + d.Set("noncurrent_version_expiration", nc_expRules) + } + if len(abort_mpuRules) > 0 { + d.Set("abort_incomplete_multipart_upload_days", abort_mpuRules) + } } // Read retention rule diff --git a/ibm/resource_ibm_cos_bucket_test.go b/ibm/resource_ibm_cos_bucket_test.go index f63f3017da..02d673bbb0 100644 --- a/ibm/resource_ibm_cos_bucket_test.go +++ b/ibm/resource_ibm_cos_bucket_test.go @@ -85,7 +85,7 @@ func TestAccIBMCosBucket_ActivityTracker_Monitor(t *testing.T) { activityServiceName := fmt.Sprintf("activity_tracker_%d", acctest.RandIntRange(10, 100)) monitorServiceName := fmt.Sprintf("metrics_monitor_%d", acctest.RandIntRange(10, 100)) bucketName := fmt.Sprintf("tf-bucket%d", acctest.RandIntRange(10, 100)) - bucketRegion := "sjc04" + bucketRegion := "ams03" bucketClass := "standard" bucketRegionType := "single_site_location" @@ -119,6 +119,7 @@ func TestAccIBMCosBucket_ActivityTracker_Monitor(t *testing.T) { }, }) } + func TestAccIBMCosBucket_Archive_Expiration(t *testing.T) { cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) @@ -231,14 +232,14 @@ func TestAccIBMCosBucket_Archive(t *testing.T) { }) } -func TestAccIBMCosBucket_Expire(t *testing.T) { +func TestAccIBMCosBucket_Expiredays(t *testing.T) { cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) bucketRegion := "us-south" bucketClass := "standard" bucketRegionType := "region_location" - ruleId := "my-rule-id-bucket-expire" + ruleId := "my-rule-id-bucket-expiredays" enable := true expireDays := 2 prefix := "prefix/" @@ -250,7 +251,7 @@ func TestAccIBMCosBucket_Expire(t *testing.T) { CheckDestroy: testAccCheckIBMCosBucketDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccCheckIBMCosBucket_expire(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDays, prefix), + Config: testAccCheckIBMCosBucket_expiredays(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDays, prefix), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), @@ -270,7 +271,59 @@ func TestAccIBMCosBucket_Expire(t *testing.T) { ), }, resource.TestStep{ - Config: testAccCheckIBMCosBucket_update_expire(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDays, prefix), + Config: testAccCheckIBMCosBucket_update_expiredays(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_Expiredate(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-expiredate" + enable := true + expireDate := "2021-11-28" + prefix := "" + expireDateUpdate := "2021-11-30" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCosBucket_expiredate(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCosBucket_expire_updateDate(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDateUpdate, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.0.date", expireDateUpdate), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCosBucket_update_expiredate(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expireDate, prefix), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), @@ -283,6 +336,119 @@ func TestAccIBMCosBucket_Expire(t *testing.T) { }) } +func TestAccIBMCosBucket_Expireddeletemarker(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-expireddeletemarker" + enable := true + prefix := "" + expiredObjectDeleteMarker := false + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCosBucket_expiredeletemarker(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, expiredObjectDeleteMarker, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "expire_rule.#", "1"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_AbortIncompeleteMPU(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-abortmpu" + enable := true + prefix := "" + daysAfterInitiation := 1 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCosBucket_abortincompletempu(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, daysAfterInitiation, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "abort_incomplete_multipart_upload_days.#", "1"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCosBucket_update_abortincompletempu(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, daysAfterInitiation, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "abort_incomplete_multipart_upload_days.#", "0"), + ), + }, + }, + }) +} + +func TestAccIBMCosBucket_noncurrentversion(t *testing.T) { + + cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) + bucketName := fmt.Sprintf("terraform%d", acctest.RandIntRange(10, 100)) + bucketRegion := "us-south" + bucketClass := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-ncversion" + enable := true + prefix := "" + noncurrentDays := 1 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMCosBucket_noncurrentversion(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, noncurrentDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "noncurrent_version_expiration.#", "1"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMCosBucket_update_noncurrentversion(cosServiceName, bucketName, bucketRegionType, bucketRegion, bucketClass, ruleId, enable, noncurrentDays, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMCosBucketExists("ibm_resource_instance.instance", "ibm_cos_bucket.bucket", bucketRegionType, bucketRegion, bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "bucket_name", bucketName), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "storage_class", bucketClass), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "region_location", bucketRegion), + resource.TestCheckResourceAttr("ibm_cos_bucket.bucket", "noncurrent_version_expiration.#", "0"), + ), + }, + }, + }) +} + func TestAccIBMCosBucket_Retention(t *testing.T) { cosServiceName := fmt.Sprintf("cos_instance_%d", acctest.RandIntRange(10, 100)) @@ -806,7 +972,7 @@ func testAccCheckIBMCosBucket_update_archive(cosServiceName string, bucketName s `, cosServiceName, bucketName, region, storageClass) } -func testAccCheckIBMCosBucket_expire(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDays int, prefix string) string { +func testAccCheckIBMCosBucket_expiredays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDays int, prefix string) string { return fmt.Sprintf(` data "ibm_resource_group" "cos_group" { @@ -866,7 +1032,7 @@ func testAccCheckIBMCosBucket_expire_updateDays(cosServiceName string, bucketNam } -func testAccCheckIBMCosBucket_update_expire(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDays int, prefix string) string { +func testAccCheckIBMCosBucket_update_expiredays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDays int, prefix string) string { return fmt.Sprintf(` data "ibm_resource_group" "cos_group" { @@ -890,6 +1056,120 @@ func testAccCheckIBMCosBucket_update_expire(cosServiceName string, bucketName st `, cosServiceName, bucketName, region, storageClass) } +func testAccCheckIBMCosBucket_expiredate(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDate string, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + expire_rule { + rule_id = "%s" + enable = true + date = "%s" + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, expireDate, prefix) +} + +func testAccCheckIBMCosBucket_expire_updateDate(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDateUpdate string, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + expire_rule { + rule_id = "%s" + enable = true + date = "%s" + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, expireDateUpdate, prefix) + +} + +func testAccCheckIBMCosBucket_update_expiredate(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expireDate string, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + } + `, cosServiceName, bucketName, region, storageClass) +} + +func testAccCheckIBMCosBucket_expiredeletemarker(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, expiredObjectDeleteMarker bool, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + expire_rule { + rule_id = "%s" + enable = true + expired_object_delete_marker = true + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, prefix) +} + func testAccCheckIBMCosBucket_archive_expire(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, arch_ruleId string, arch_enable bool, archiveDays int, ruleType string, exp_ruleId string, exp_enable bool, expireDays int, prefix string) string { return fmt.Sprintf(` @@ -1063,3 +1343,136 @@ func testAccCheckIBMCosBucket_hard_quota(cosServiceName string, bucketName strin } `, cosServiceName, bucketName, region, storageClass, hardQuota) } + +func testAccCheckIBMCosBucket_abortincompletempu(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, daysAfterInitiation int, prefix string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + abort_incomplete_multipart_upload_days { + rule_id = "%s" + enable = true + days_after_initiation = %d + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, daysAfterInitiation, prefix) +} + +func testAccCheckIBMCosBucket_abortincompletempu_updateDays(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, daysAfterInitiationUpdate int, prefix string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + abort_incomplete_multipart_upload_days { + rule_id = "%s" + enable = true + days_after_initiation = %d + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, daysAfterInitiationUpdate, prefix) + +} + +func testAccCheckIBMCosBucket_update_abortincompletempu(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, daysAfterInitiation int, prefix string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + } + `, cosServiceName, bucketName, region, storageClass) +} + +func testAccCheckIBMCosBucket_noncurrentversion(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, noncurrentDays int, prefix string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + noncurrent_version_expiration { + rule_id = "%s" + enable = true + noncurrent_days = %d + prefix = "%s" + } + } + `, cosServiceName, bucketName, region, storageClass, ruleId, noncurrentDays, prefix) +} + +func testAccCheckIBMCosBucket_update_noncurrentversion(cosServiceName string, bucketName string, regiontype string, region string, storageClass string, ruleId string, enable bool, noncurrentDays int, prefix string) string { + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + + resource "ibm_resource_instance" "instance" { + name = "%s" + service = "cloud-object-storage" + plan = "standard" + location = "global" + resource_group_id = data.ibm_resource_group.cos_group.id + } + + resource "ibm_cos_bucket" "bucket" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.instance.id + region_location = "%s" + storage_class = "%s" + } + `, cosServiceName, bucketName, region, storageClass) +} diff --git a/ibm/structures.go b/ibm/structures.go index a5382eab42..6f59b31f73 100644 --- a/ibm/structures.go +++ b/ibm/structures.go @@ -16,6 +16,7 @@ import ( "reflect" "strconv" "strings" + "time" "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" "github.com/IBM/go-sdk-core/v5/core" @@ -679,8 +680,8 @@ func flattenMetricsMonitor(in *resourceconfigurationv1.MetricsMonitoring) []inte func archiveRuleGet(in []*s3.LifecycleRule) []interface{} { rules := make([]interface{}, 0, len(in)) for _, r := range in { - // Checking this is not an expire_rule. LifeCycle rules are either archive or expire - if r.Expiration == nil { + // Checking this is not an expire_rule. LifeCycle rules are either archive or expire or non current version or abort incomplete multipart upload + if r.Expiration == nil && r.NoncurrentVersionExpiration == nil && r.AbortIncompleteMultipartUpload == nil { rule := make(map[string]interface{}) if r.Status != nil { @@ -714,7 +715,7 @@ func archiveRuleGet(in []*s3.LifecycleRule) []interface{} { func expireRuleGet(in []*s3.LifecycleRule) []interface{} { rules := make([]interface{}, 0, len(in)) for _, r := range in { - if r.Expiration != nil { + if r.Expiration != nil && r.Transitions == nil { rule := make(map[string]interface{}) if r.Status != nil { @@ -730,7 +731,21 @@ func expireRuleGet(in []*s3.LifecycleRule) []interface{} { } if r.Expiration != nil { - rule["days"] = int(*(r.Expiration).Days) + if r.Expiration.Days != nil { + days := int(*(r.Expiration).Days) + if days > 0 { + rule["days"] = days + } + } + if r.Expiration.Date != nil { + expirationTime := *(r.Expiration).Date + d := strings.Split(expirationTime.Format(time.RFC3339), "T") + rule["date"] = d[0] + } + + if r.Expiration.ExpiredObjectDeleteMarker != nil { + rule["expired_object_delete_marker"] = *(r.Expiration).ExpiredObjectDeleteMarker + } } if r.Filter != nil && r.Filter.Prefix != nil { rule["prefix"] = *(r.Filter).Prefix @@ -739,6 +754,66 @@ func expireRuleGet(in []*s3.LifecycleRule) []interface{} { rules = append(rules, rule) } } + + return rules + +} + +func nc_exp_RuleGet(in []*s3.LifecycleRule) []interface{} { + rules := make([]interface{}, 0, len(in)) + for _, r := range in { + if r.Expiration == nil && r.AbortIncompleteMultipartUpload == nil && r.Transitions == nil { + rule := make(map[string]interface{}) + if r.Status != nil { + if *r.Status == "Enabled" { + rule["enable"] = true + + } else { + rule["enable"] = false + } + + } + if r.ID != nil { + rule["rule_id"] = *r.ID + } + if r.NoncurrentVersionExpiration != nil { + rule["noncurrent_days"] = int(*(r.NoncurrentVersionExpiration).NoncurrentDays) + } + if r.Filter != nil && r.Filter.Prefix != nil { + rule["prefix"] = *(r.Filter).Prefix + } + rules = append(rules, rule) + } + } + return rules +} + +func abort_mpu_RuleGet(in []*s3.LifecycleRule) []interface{} { + rules := make([]interface{}, 0, len(in)) + for _, r := range in { + if r.Expiration == nil && r.NoncurrentVersionExpiration == nil && r.Transitions == nil { + rule := make(map[string]interface{}) + if r.Status != nil { + if *r.Status == "Enabled" { + rule["enable"] = true + + } else { + rule["enable"] = false + } + + } + if r.ID != nil { + rule["rule_id"] = *r.ID + } + if r.AbortIncompleteMultipartUpload != nil { + rule["days_after_initiation"] = int(*(r.AbortIncompleteMultipartUpload).DaysAfterInitiation) + } + if r.Filter != nil && r.Filter.Prefix != nil { + rule["prefix"] = *(r.Filter).Prefix + } + rules = append(rules, rule) + } + } return rules } diff --git a/ibm/validators.go b/ibm/validators.go index af0c5d97a8..8a26e7d3bc 100644 --- a/ibm/validators.go +++ b/ibm/validators.go @@ -12,6 +12,7 @@ import ( "regexp" "strconv" "strings" + "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -66,6 +67,17 @@ func validateAllowedStringValue(validValues []string) schema.SchemaValidateFunc } } +func validBucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + _, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value)) + if err != nil { + errors = append(errors, fmt.Errorf( + "%q cannot be parsed as RFC3339 Timestamp Format", value)) + } + + return +} + func validateRegexpLen(min, max int, regex string) schema.SchemaValidateFunc { return func(v interface{}, k string) (ws []string, errors []error) { value := v.(string) diff --git a/website/docs/d/cos_bucket.html.markdown b/website/docs/d/cos_bucket.html.markdown index 1e86ebfcdd..f570fa10ac 100644 --- a/website/docs/d/cos_bucket.html.markdown +++ b/website/docs/d/cos_bucket.html.markdown @@ -47,7 +47,14 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. - +- `crn` - (String) The CRN of the bucket. +- `cross_region_location` - (String) The location to create a cross-regional bucket. +- `single_site_location` - (String) The location to create a single site bucket. +- `storage_class` - (String) The storage class of the bucket. +- `id` - (String) The ID of the bucket. +- `region_location` - (String) The location to create a regional bucket. +- `resource_instance_id` - (String) The ID of {site.data.keyword.cos_full_notm}} instance. +- `key_protect` - (String) The CRN of the IBM Key Protect instance where a root key is already provisioned. - `allowed_ip`- (String) List of `IPv4` or `IPv6` addresses in CIDR notation to be affected by firewall. - `activity_tracking` (List) Nested block with the following structure. @@ -62,17 +69,29 @@ In addition to all argument reference list, you can access the following attribu - `enable`- (Bool) Specifies archive rule status either `enable` or `disable` for a bucket. - `type` - (String) Specifies the storage class or archive type to which you want the object to transition. Supported values are `Glacier` or `Accelerated`. - `rule_id` - (String) Unique identifier for the rule. Archive rules allow you to set a specific time frame after which objects transition to archive. -- `crn` - (String) The CRN of the bucket. -- `cross_region_location` - (String) The location to create a cross-regional bucket. - `expire_rule` (List) Nested block with the following structure. Nested scheme for `expire_rule`: - `days` - (String) Specifies the number of days when the specific rule action takes effect. + - `date` - (String) After the specifies date , the current version of objects in your bucket expires. - `enable`- (Bool) Specifies expire rule status either `enable` or `disable` for a bucket. - `prefix` - (String) Specifies a prefix filter to apply to only a subset of objects with names that match the prefix. - `rule_id` - (String) Unique identifier for the rule. Expire rules allow you to set a specific time frame after which objects are deleted. -- `id` - (String) The ID of the bucket. -- `key_protect` - (String) The CRN of the IBM Key Protect instance where a root key is already provisioned. + - `expired_object_delete_marker` - (Bool) Expired object delete markers can be automatically cleaned up to improve performance in your bucket. This cannot be used alongside version expiration. +- `abort_incomplete_multipart_upload_days` (List) Nested block with the following structure. + + Nested scheme for `abort_incomplete_multipart_upload_days`: + - `rule_id` - (String) Unique identifier for the rule. Rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket. + - `enable` - (Bool) A rule can either be `enabled` or `disabled`. A rule is active only when enabled. + - `prefix` - (String) A rule with a prefix will only apply to the objects that match. You can use multiple rules for different actions for different prefixes within the same bucket. + - `days_after_initiation` - (String) Specifies the number of days that govern the automatic cancellation of part upload. Clean up incomplete multi-part uploads after a period of time. Must be a value greater than 0. +- `noncurrent_version_expiration` (List) Nested block with the following structure. + + Nested scheme for `noncurrent_version_expiration`: + - `rule_id` - (String) Unique identifier for the rule. Rules allow you to remove versions from objects. Set Rule ID for cos bucket. + - `enable` - (Bool) A rule can either be `enabled` or `disabled`. A rule is active only when enabled. + - `prefix` - (String) The rule applies to any objects with keys that match this prefix. You can use multiple rules for different actions for different prefixes within the same bucket. + - `noncurrent_days` - (Int) Configuration parameter in your policy that says how long to retain a non-current version before deleting it. Must be greater than 0. - `metrics_monitoring`- (List) Nested block with the following structure. Nested scheme for `metrics_monitoring`: @@ -83,8 +102,6 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `object_verionining`: - `enable` - (String) Specifies versioning status either enable or suspended for the objects in the bucket. -- `region_location` - (String) The location to create a regional bucket. -- `resource_instance_id` - (String) The ID of {site.data.keyword.cos_full_notm}} instance. - `retention_rule` - (List) Nested block have the following structure: Nested scheme for `retention rule`: @@ -93,5 +110,3 @@ In addition to all argument reference list, you can access the following attribu - `minimum` - (String) Specifies minimum duration of time an object must be kept unmodified in the bucket. - `permanent` - (String) Specifies a permanent retention status either enable or disable for a bucket. - `hard_quota` - (String) Maximum bytes for the bucket. -- `single_site_location` - (String) The location to create a single site bucket. -- `storage_class` - (String) The storage class of the bucket. diff --git a/website/docs/r/cos_bucket.html.markdown b/website/docs/r/cos_bucket.html.markdown index 3fcb68b566..a274dfab79 100644 --- a/website/docs/r/cos_bucket.html.markdown +++ b/website/docs/r/cos_bucket.html.markdown @@ -158,6 +158,69 @@ resource "ibm_cos_bucket" "expire_rule_cos" { } } +### Configure expire date/days with non current version expiration enabled on COS bucket + +resource "ibm_cos_bucket" "expirebucket" { + bucket_name = "a-bucket-expiredat" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + force_delete = true + object_versioning { + enable = true + } + expire_rule { + rule_id = "a-bucket-expire-rule" + enable = true + date = "2021-11-18" + prefix = "logs/" + } + noncurrent_version_expiration { + rule_id = "my-rule-id-bucket-ncversion" + enable = true + prefix = "" + noncurrent_days = 1 + } +} + +### Configure clean up expired object delete markers on COS bucket + +resource "ibm_cos_bucket" "cos_bucket" { + bucket_name = "a-bucket-expireddelemarkertest" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } + expire_rule { + rule_id = "my-rule-id-bucket-expired" + enable = true + expired_object_delete_marker = true + } + noncurrent_version_expiration { + rule_id = "my-rule-id-bucket-ncversion" + enable = true + prefix = "" + noncurrent_days = 1 + } +} + +### Configure abort incomplete multipart upload on COS bucket + +resource "ibm_cos_bucket" "cos_bucket" { + bucket_name = "a-bucket-multipartupload" + resource_instance_id = ibm_resource_instance.cos_instance.id + region_location = "us-south" + storage_class = "standard" + abort_incomplete_multipart_upload_days { + rule_id = var.abort_mpu_ruleid + enable = true + prefix = "" + days_after_initiation = 1 + } +} + ### Configure retention rule on COS bucket resource "ibm_cos_bucket" "retention_cos" { @@ -221,26 +284,48 @@ Review the argument references that you can specify for your resource. - `archive_rule` - (Required, List) Nested archive_rule block has following structure. Nested scheme for `archive_rule`: - - `days` - (Required, String) Specifies the number of days when the specific rule action takes effect. + - `days` - (Required, Integer) Specifies the number of days when the specific rule action takes effect. - `enable` - (Required, Bool) Specifies archive rule status either `enable` or `disable` for a bucket. - `rule_id` - (Optional, Computed, String) The unique ID for the rule. Archive rules allow you to set a specific time frame after the objects transition to the archive. - `type` - (Required, String) Specifies the storage class or archive type to which you want the object to transition. Allowed values are `Glacier` or `Accelerated`. - **Note:** Archive is available in certain regions only. For more information, see [Integrated Services](https://cloud.ibm.com/docs/cloud-object-storage/basics?topic=cloud-object-storage-service-availability). -- `expire_rule` - (Required, List) Nested expire_rule block has following structure. + **Note:** + - Archive is available in certain regions only. For more information, see [Integrated Services](https://cloud.ibm.com/docs/cloud-object-storage/basics?topic=cloud-object-storage-service-availability). + - Restoring object once archive is not supported yet. +- `expire_rule` - (Required, List) An expiration rule deletes objects after a defined period (from the object creation date). see [lifecycle actions](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-versioning). Nested expire_rule block has following structure. Nested scheme for `expire_rule`: - `rule_id` - (Optional, Computed, String) Unique ID for the rule. Expire rules allow you to set a specific time frame after which objects are deleted. - `enable` - (Required, Bool) Specifies expire rule status either `enable` or `disable` for a bucket. - - `days` - (Required, String) Specifies the number of days when the specific rule action takes effect. + - `days` - (Optional, Integer) Specifies the number of days when the specific rule action takes effect. - `prefix` - (Optional, String) Specifies a prefix filter to apply to only a subset of objects with names that match the prefix. + - `date` - (Optional, String) After the specifies date , the current version of objects in your bucket expires. + - `expired_object_delete_marker` - (Optional, String) Expired object delete markers can be automatically cleaned up to improve performance in your bucket. This cannot be used alongside version expiration. This element for the Expiration action which will only remove delete markers that have no non-current versions at all & objects whose only version is a single delete marker. + + **Note:** + - Both `archive_rule` and `expire_rule` must be managed by Terraform as they use the same lifecycle configuration. If user creates any of the rule outside of Terraform by using command line or console, you can see unexpected difference like removal of any of the rule or one rule overrides another. The policy cannot match as expected due to API limitations, as the lifecycle is a single API request for both archive and expire. + - When versioning is enabled/suspended, regular object expiration will no longer remove objects, instead it will create a delete marker, unless the current version is already a delete marker, then nothing happens. If the only version of the object is a delete marker, then the delete marker is removed after X days, or on a specific date. + - expired_object_delete_marker element can not be used in conjunction with other expiry action elements (Days or Date). + - The expiry 3 action elements (Days, Date, ExpiredObjectDeleteMarker) are all mutually exclusive.Anyone parameter can apply among 3 (Days, Date, ExpiredObjectDeleteMarker) in expire_rule. + - You cannot specify both a Days and ExpiredObjectDeleteMarker tag on the same rule. Specifying the Days tag will automatically perform ExpiredObjectDeleteMarker cleanup once delete markers are old enough to satisfy the age criteria. You can create a separate rule with only the tag ExpiredObjectDeleteMarker to clean up delete markers as soon as they become the only version. +- `noncurrent_version_expiration` - (Required, List) lifecycle has a versioning related expiration action: non-current version expiration. This can remove old versions of objects after they've been non-current for a specified number of days which is specified with a NoncurrentDays parameter on the rule. see [lifecycle actions](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-versioning). Nested noncurrent_version_expiration block has following structure. + + Nested scheme for `noncurrent_version_expiration`: + - `rule_id` - (Optional, String) Unique identifier for the rule. Rules allow you to remove versions from objects. Set Rule ID for cos bucket. + - `enable` - (Requried, Bool) A rule can either be `enabled` or `disabled`. A rule is active only when enabled. + - `prefix` - (Optional, String) The rule applies to any objects with keys that match this prefix. You can use multiple rules for different actions for different prefixes within the same bucket. + - `noncurrent_days` - (Optional, Integer) Configuration parameter in your policy that says how long to retain a non-current version before deleting it. Must be greater than 0. +- `abort_incomplete_multipart_upload_days` - (Required, List) Multipart uploads allows users to upload large objects in parts and then use an API to assemble the parts into a final object that is then accessible through the S3 APIs. An in progress multipart upload that is represented by bucket, object, and uploadID parameters. Abort Multipart upload allows a COS user to configure a bucket lifecycle rule to stop multipart uploads that don't complete within a specified number of days after being initiated. When a multipart upload is not completed within the timeframe, it becomes eligible for an abort operation and the COS service is expected to stop the multipart upload (and delete the parts associated with the multipart upload). see [cleanup incomplete multipart uploads](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-lifecycle-cleanup-mpu). Nested abort_incomplete_multipart_upload_days block has following structure. + + Nested scheme for `abort_incomplete_multipart_upload_days`: + - `rule_id` - (Optional, String) Unique identifier for the rule. Rules allow you to set a specific time frame after which objects are deleted. Set Rule ID for cos bucket. + - `enable` - (Required, Bool) A rule can either be `enabled` or `disabled`. A rule is active only when enabled. + - `prefix` - (Optional, String) A rule with a prefix will only apply to the objects that match. You can use multiple rules for different actions for different prefixes within the same bucket. + - `days_after_initiation` - (Optional, Integer) Specifies the number of days that say how long to wait before cleaning up an incomplete MPU. Must be greater than 0. - **Note:** Both `archive_rule` and `expire_rule` must be managed by Terraform as they use the same lifecycle configuration. If user creates any of the rule outside of Terraform by using command line or console, you can see unexpected difference like removal of any of the rule or one rule overrides another. The policy cannot match as expected due to API limitations, as the lifecycle is a single API request for both archive and expire. -- `force_delete`- (Optional, Bool) As the default value set to **true**, it will delete all the objects in the COS Bucket and then delete the bucket. - - **Note:** `force_delete` will timeout on buckets with a large amount of objects. 24 hours before you delete the bucket you can set an expire rule to remove all the files over a day old. - `key_protect` - (Optional, String) The CRN of the IBM Key Protect root key that you want to use to encrypt data that is sent and stored in IBM Cloud Object Storage. Before you can enable IBM Key Protect encryption, you must provision an instance of IBM Key Protect and authorize the service to access IBM Cloud Object Storage. For more information, see [Server-Side Encryption with IBM Key Protect or Hyper Protect Crypto Services (SSE-KP)](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-encryption). -- `object_versioning` - (List) Nested block have the following structure: + +- `object_versioning` - (List) Object Versioning allows the COS user to keep multiple versions of an objet in a bucke to protect against accidental deletion or overwrites. With versioning, you can easilyrecover from both unintended user actions and application failure. Nested block have the following structure: Nested scheme for `object_versioning`: - `enable` : (Optional, Bool) Specifies Versioning status either enable or Suspended for the objects in the bucket.Default value set to false. @@ -250,11 +335,11 @@ Review the argument references that you can specify for your resource. - If cos bucket has versioning enabled and set to false, versioning will be suspended. - Versioning can only be suspended, we cannot disabled once after it is enabled. - To permanently delete individual versions of an object, a delete request must specify a version ID. - - Containers with object expiry cannot have versioning enabled or suspended, and containers with versioning enabled or suspended cannot have expiry lifecycle actions enabled to them. - COS Object versioning and COS Bucket Protection `(WORM)` cannot be used together. - Containers with proxy configuration cannot use versioning and vice versa. - SoftLayer accounts cannot use versioning. - Currently, you cannot support `MFA_Delete`, that is a feature to add additional security to version delete. + - `retention_rule` - (List) Nested block have the following structure: Nested scheme for `retention rule`: @@ -268,8 +353,13 @@ Review the argument references that you can specify for your resource. - The minimum retention period must be less than or equal to the default retention period, that in turn must be less than or equal to the maximum retention period. - Permanent retention can only be enabled at a IBM Cloud Object Storage bucket level with retention policy enabled and users are able to select the permanent retention period option during object uploads. Once enabled, this process can't be reversed and objects uploaded that use a permanent retention period cannot be deleted. It's the responsibility of the users to validate at their end if there's a legitimate need to permanently store objects by using Object Storage buckets with a retention policy. - force deleting the bucket will not work if any object is still under retention. As objects cannot be deleted or overwritten until the retention period has expired and all the legal holds have been removed. + - `hard_quota` - (Optional, Integer) Sets a maximum amount of storage (in bytes) available for a bucket. For more information, check the [cloud documention](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-quota). +- `force_delete`- (Optional, Bool) As the default value set to **true**, it will delete all the objects in the COS Bucket and then delete the bucket. + + **Note:** `force_delete` will timeout on buckets with a large amount of objects. 24 hours before you delete the bucket you can set an expire rule to remove all the files over a day old. + ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created.