diff --git a/.secrets.baseline b/.secrets.baseline index 21b6b8b5e1..ffcfb32582 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2022-07-13T10:12:14Z", + "generated_at": "2022-07-19T10:25:33Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -307,16 +307,6 @@ "verified_result": null } ], - "examples/ibm-cd-toolchain/main.tf": [ - { - "hashed_secret": "638bac731294171648258260ff2af4a09bc02aa2", - "is_secret": false, - "is_verified": false, - "line_number": 12, - "type": "Secret Keyword", - "verified_result": null - } - ], "examples/ibm-cis/README.md": [ { "hashed_secret": "1f1c2ad5fded044aae42281c1fd4253dd624bf65", @@ -660,7 +650,7 @@ "hashed_secret": "813274ccae5b6b509379ab56982d862f7b5969b6", "is_secret": false, "is_verified": false, - "line_number": 744, + "line_number": 747, "type": "Base64 High Entropy String", "verified_result": null } @@ -720,7 +710,7 @@ "hashed_secret": "da8cae6284528565678de15e03d461e23fe22538", "is_secret": false, "is_verified": false, - "line_number": 1514, + "line_number": 1551, "type": "Secret Keyword", "verified_result": null } @@ -730,7 +720,7 @@ "hashed_secret": "c8b6f5ef11b9223ac35a5663975a466ebe7ebba9", "is_secret": false, "is_verified": false, - "line_number": 1384, + "line_number": 1399, "type": "Secret Keyword", "verified_result": null }, @@ -738,7 +728,7 @@ "hashed_secret": "8abf4899c01104241510ba87685ad4de76b0c437", "is_secret": false, "is_verified": false, - "line_number": 1390, + "line_number": 1405, "type": "Secret Keyword", "verified_result": null } @@ -1608,7 +1598,7 @@ "hashed_secret": "884a58e4c2c5d195d3876787bdc63af6c5af2924", "is_secret": false, "is_verified": false, - "line_number": 375, + "line_number": 413, "type": "Secret Keyword", "verified_result": null } @@ -1643,6 +1633,16 @@ "verified_result": null } ], + "ibm/service/cos/resource_ibm_cos_replication_configuration.go": [ + { + "hashed_secret": "b02fa7fd7ca08b5dc86c2548e40f8a21171ef977", + "is_secret": false, + "is_verified": false, + "line_number": 368, + "type": "Secret Keyword", + "verified_result": null + } + ], "ibm/service/database/data_source_ibm_database_connection.go": [ { "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", diff --git a/examples/ibm-cos-bucket/README.md b/examples/ibm-cos-bucket/README.md index 3f6633c6a9..a95de98df6 100644 --- a/examples/ibm-cos-bucket/README.md +++ b/examples/ibm-cos-bucket/README.md @@ -232,6 +232,127 @@ resource "ibm_cos_bucket" "cos_bucket" { } ``` +## COS REPLICATION + +Replication allows users to define rules for automatic, asynchronous copying of objects from a source bucket to a destination bucket in the same or different location. + +**Note:** + + you must have `writer` or `manager` platform roles on source bucket and sufficient platform roles to create new [IAM policies](https://cloud.ibm.com/docs/account?topic=account-iamoverview#iamoverview) that allow the source bucket to write to the destination bucket. + Add depends_on on ibm_iam_authorization_policy.policy in template to make sure replication only enabled once iam authorization policy set. + +## Example usage +The following example creates an instance of IBM Cloud Object Storage. Then, multiple buckets are created and configured replication policy. + +```terraform +data "ibm_resource_group" "cos_group" { + name = "cos-resource-group" +} + +resource "ibm_resource_instance" "cos_instance_source" { + name = "cos-instance-src" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_resource_instance" "cos_instance_destination" { + name = "cos-instance-dest" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_cos_bucket" "cos_bucket_source" { + bucket_name = "a-bucket-source" + resource_instance_id = ibm_resource_instance.cos_instance_source.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } +} + +resource "ibm_cos_bucket" "cos_bucket_destination" { + bucket_name = "a-bucket-destination" + resource_instance_id = ibm_resource_instance.cos_instance_destination.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } +} + + +### Configure IAM authorization policy + +resource "ibm_iam_authorization_policy" "policy" { + roles = [ + "Writer", + ] + subject_attributes { + name = "accountId" + value = "an-account-id" + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_source.guid + } + subject_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_source.bucket_name + } + subject_attributes { + name = "resourceType" + value = "bucket" + } + resource_attributes { + name = "accountId" + value = "an-account-id" + } + resource_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_destination.guid + } + resource_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_destination.bucket_name + } + resource_attributes { + name = "resourceType" + value = "bucket" + } +} + +### Configure replication policy + +resource "ibm_cos_bucket_replication_rule" "cos_bucket_repl" { + depends_on = [ + ibm_iam_authorization_policy.policy + ] + bucket_crn = ibm_cos_bucket.cos_bucket_source.crn + bucket_location = ibm_cos_bucket.cos_bucket_source.region_location + replication_rule { + rule_id = "a-rule-id" + enable = "true" + prefix = "a-prefix" + priority = "a-priority-associated-with-the-rule" + deletemarker_replication_status = "Enabled/Suspened" + destination_bucket_crn = ibm_cos_bucket.cos_bucket_destination.crn + } +} + +``` @@ -277,4 +398,12 @@ resource "ibm_cos_bucket" "cos_bucket" { | permanent | Specifies a permanent retention status either enable or disable for a bucket. | `bool` | no | enable | Specifies Versioning status either **enable or suspended** for an objects in the bucket. | `bool` | no | hard_quota | sets a maximum amount of storage (in bytes) available for a bucket. | `int` | no +| bucket\_crn | The CRN of the source COS bucket. | `string` | yes | +| bucket\_location | The location of the source COS bucket. | `string` | yes | +| destination_bucket_crn | The CRN of your destination bucket that you want to replicate to. | `String` | yes +| deletemarker_replication_status | Specifies whether Object storage replicates delete markers. Valid values are Enabled or Disabled. | `String` | no +| status | Specifies whether the rule is enabled. Valid values are Enabled or Disabled. | `String` | yes +| rule_id | The rule id. | `String` | no +| priority | A priority is associated with each rule. The rule will be applied in a higher priority if there are multiple rules configured. The higher the number, the higher the priority | `String` | no +| prefix | An object key name prefix that identifies the subset of objects to which the rule applies. | `String` | no {: caption="inputs"} diff --git a/examples/ibm-cos-bucket/main.tf b/examples/ibm-cos-bucket/main.tf index cf92ad801f..90db3e9c63 100644 --- a/examples/ibm-cos-bucket/main.tf +++ b/examples/ibm-cos-bucket/main.tf @@ -98,6 +98,176 @@ resource "ibm_cos_bucket" "cos_bucket" { noncurrent_days = var.nc_exp_days } } +//Replication +resource "ibm_resource_instance" "cos_instance_source" { + name = "cos-instance-src" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_cos_bucket" "cos_bucket_source" { + bucket_name = "sourcetest" + resource_instance_id = ibm_resource_instance.cos_instance_source.id + region_location = var.regional_loc + storage_class = var.storage + object_versioning { + enable = true + } +} + +resource "ibm_resource_instance" "cos_instance_destination" { + name = "cos-instance-dest" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_cos_bucket" "cos_bucket_destination" { + bucket_name = "desttest" + resource_instance_id = ibm_resource_instance.cos_instance_destination.id + region_location = var.regional_loc + storage_class = var.storage + object_versioning { + enable = true + } +} + +resource "ibm_cos_bucket" "cos_bucket_destination_1" { + bucket_name = "desttest01" + resource_instance_id = ibm_resource_instance.cos_instance_destination.id + region_location = var.regional_loc + storage_class = var.storage + object_versioning { + enable = true + } +} + +resource "ibm_iam_authorization_policy" "policy" { + roles = [ + "Writer", + ] + subject_attributes { + name = "accountId" + value = "12345" + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_source.guid + } + subject_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_source.bucket_name + } + subject_attributes { + name = "resourceType" + value = "bucket" + } + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = "12345" + } + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceInstance" + operator = "stringEquals" + value = ibm_resource_instance.cos_instance_destination.guid + } + resource_attributes { + name = "resource" + operator = "stringEquals" + value = ibm_cos_bucket.cos_bucket_destination.bucket_name + } + resource_attributes { + name = "resourceType" + operator = "stringEquals" + value = "bucket" + } +} + +resource "ibm_iam_authorization_policy" "policy1" { + roles = [ + "Writer", + ] + subject_attributes { + name = "accountId" + value = "12345" + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_source.guid + } + subject_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_source.bucket_name + } + subject_attributes { + name = "resourceType" + value = "bucket" + } + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = "12345" + } + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceInstance" + operator = "stringEquals" + value = ibm_resource_instance.cos_instance_destination.guid + } + resource_attributes { + name = "resource" + operator = "stringEquals" + value = ibm_cos_bucket.cos_bucket_destination_1.bucket_name + } + resource_attributes { + name = "resourceType" + operator = "stringEquals" + value = "bucket" + } +} + + +resource "ibm_cos_bucket_replication_rule" "cos_bucket_repl" { + depends_on = [ + ibm_iam_authorization_policy.policy, ibm_iam_authorization_policy.policy1 + ] + bucket_crn = ibm_cos_bucket.cos_bucket_source.crn + bucket_location = ibm_cos_bucket.cos_bucket_source.region_location + replication_rule { + enable = true + prefix = var.replicate_prefix + priority = var.replicate_priority + deletemarker_replication_status = var.delmarkerrep_status + destination_bucket_crn = ibm_cos_bucket.cos_bucket_destination.crn + } + replication_rule { + enable = true + priority = "2" + deletemarker_replication_status = var.delmarkerrep_status + destination_bucket_crn = ibm_cos_bucket.cos_bucket_destination_1.crn + } +} resource "ibm_cos_bucket_object" "plaintext" { bucket_crn = ibm_cos_bucket.cos_bucket.crn @@ -127,4 +297,4 @@ resource "ibm_cos_bucket" "cos_bucket_sat" { days = 20 prefix = "logs/" } -} +} \ No newline at end of file diff --git a/examples/ibm-cos-bucket/variables.tf b/examples/ibm-cos-bucket/variables.tf index 10669f9161..5982ada2f4 100644 --- a/examples/ibm-cos-bucket/variables.tf +++ b/examples/ibm-cos-bucket/variables.tf @@ -93,3 +93,23 @@ variable "quota" { variable "satellite_location_id" { default = "" } + +variable "replicate_ruleid" { + default = "" +} + +variable "replicate_prefix" { + default = "" +} + +variable "replicate_priority" { + default = "1" +} + +variable "delmarkerrep_status" { + default = true +} + +variable "dest_rep_bkt_crn" { + default = "" +} \ No newline at end of file diff --git a/go.mod b/go.mod index afdf7f71f5..dce88f7688 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/IBM/event-notifications-go-admin-sdk v0.1.2 github.com/IBM/eventstreams-go-sdk v1.2.0 github.com/IBM/go-sdk-core/v5 v5.10.1 - github.com/IBM/ibm-cos-sdk-go v1.8.0 + github.com/IBM/ibm-cos-sdk-go v1.9.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/ibm-hpcs-uko-sdk v0.0.4 diff --git a/go.sum b/go.sum index f8b68e6f4f..ba1c83a3c2 100644 --- a/go.sum +++ b/go.sum @@ -48,6 +48,8 @@ github.com/IBM/go-sdk-core/v5 v5.10.1/go.mod h1:u/33BzPy8sthgEhSeBnf6/kPCqwvC9VK github.com/IBM/ibm-cos-sdk-go v1.3.1/go.mod h1:YLBAYobEA8bD27P7xpMwSQeNQu6W3DNBtBComXrRzRY= 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 v1.9.0 h1:kXTLB9GBwks3+YZopYz/eRbdyeVl2BXFALeqtQ8Duoc= +github.com/IBM/ibm-cos-sdk-go v1.9.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/acctest/acctest.go b/ibm/acctest/acctest.go index 698e4866a8..75fdc81b5f 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -184,6 +184,9 @@ var CdResourceGroupID string var ISCertificateCrn string var ISClientCaCrn string +// COS Replication Bucket +var IBM_AccountID_REPL string + func init() { testlogger := os.Getenv("TF_LOG") if testlogger != "" { @@ -971,6 +974,11 @@ func init() { if ISClientCaCrn == "" { fmt.Println("[INFO] Set the environment variable IS_CLIENT_CA_CRN for testing ibm_is_vpn_server resource") } + + IBM_AccountID_REPL = os.Getenv("IBM_AccountID_REPL") + if IBM_AccountID_REPL == "" { + fmt.Println("[INFO] Set the environment variable IBM_AccountID_REPL for setting up authorization policy to enable replication feature resource or datasource else tests will fail if this is not set correctly") + } } var TestAccProviders map[string]*schema.Provider diff --git a/ibm/flex/structures.go b/ibm/flex/structures.go index f6fcc16f46..0111803967 100644 --- a/ibm/flex/structures.go +++ b/ibm/flex/structures.go @@ -872,6 +872,43 @@ func FlattenCosObejctVersioning(in *s3.GetBucketVersioningOutput) []interface{} return versioning } +func ReplicationRuleGet(in *s3.ReplicationConfiguration) []map[string]interface{} { + rules := make([]map[string]interface{}, 0, 1) + if in != nil { + for _, replicaterule := range in.Rules { + replicationConfig := make(map[string]interface{}) + if replicaterule.DeleteMarkerReplication != nil { + if *(replicaterule.DeleteMarkerReplication).Status == "Enabled" { + replicationConfig["deletemarker_replication_status"] = true + } else { + replicationConfig["deletemarker_replication_status"] = false + } + } + if replicaterule.Destination != nil { + replicationConfig["destination_bucket_crn"] = *(replicaterule.Destination).Bucket + } + if replicaterule.ID != nil { + replicationConfig["rule_id"] = *replicaterule.ID + } + if replicaterule.Priority != nil { + replicationConfig["priority"] = int(*replicaterule.Priority) + } + if replicaterule.Status != nil { + if *replicaterule.Status == "Enabled" { + replicationConfig["enable"] = true + } else { + replicationConfig["enable"] = false + } + } + if replicaterule.Filter != nil && replicaterule.Filter.Prefix != nil { + replicationConfig["prefix"] = *(replicaterule.Filter).Prefix + } + rules = append(rules, replicationConfig) + } + } + return rules +} + func FlattenLimits(in *whisk.Limits) []interface{} { att := make(map[string]interface{}) if in.Timeout != nil { diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 8b31015f1a..baf9fc9307 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -818,6 +818,7 @@ func Provider() *schema.Provider { "ibm_ob_logging": kubernetes.ResourceIBMObLogging(), "ibm_ob_monitoring": kubernetes.ResourceIBMObMonitoring(), "ibm_cos_bucket": cos.ResourceIBMCOSBucket(), + "ibm_cos_bucket_replication_rule": cos.ResourceIBMCOSBucketReplicationConfiguration(), "ibm_cos_bucket_object": cos.ResourceIBMCOSBucketObject(), "ibm_dns_domain": classicinfrastructure.ResourceIBMDNSDomain(), "ibm_dns_domain_registration_nameservers": classicinfrastructure.ResourceIBMDNSDomainRegistrationNameservers(), diff --git a/ibm/service/cos/data_source_ibm_cos_bucket.go b/ibm/service/cos/data_source_ibm_cos_bucket.go index cfab6c24c8..f58b35eec3 100644 --- a/ibm/service/cos/data_source_ibm_cos_bucket.go +++ b/ibm/service/cos/data_source_ibm_cos_bucket.go @@ -318,6 +318,44 @@ func DataSourceIBMCosBucket() *schema.Resource { }, }, }, + "replication_rule": { + Type: schema.TypeList, + Computed: true, + Description: "Replicate objects between buckets, replicate across source and destination. A container for replication rules can add up to 1,000 rules. The maximum size of a replication configuration is 2 MB.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Computed: true, + Description: "A unique identifier for the rule. The maximum value is 255 characters.", + }, + "priority": { + Type: schema.TypeInt, + Computed: true, + }, + "enable": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable an replication rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Computed: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "deletemarker_replication_status": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether to replicate delete markers. It should be either Enable or Disable", + }, + "destination_bucket_crn": { + Type: schema.TypeString, + Computed: true, + Description: "The Cloud Resource Name (CRN) of the bucket where you want COS to store the results", + }, + }, + }, + }, "hard_quota": { Type: schema.TypeInt, Computed: true, @@ -548,6 +586,24 @@ func dataSourceIBMCosBucketRead(d *schema.ResourceData, meta interface{}) error } } + // Get the replication rules + getBucketReplicationInput := &s3.GetBucketReplicationInput{ + Bucket: aws.String(bucketName), + } + + replicationptr, err := s3Client.GetBucketReplication(getBucketReplicationInput) + + if err != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { + return err + } + + if replicationptr != nil { + replicationRules := flex.ReplicationRuleGet(replicationptr.ReplicationConfiguration) + if len(replicationRules) > 0 { + d.Set("replication_rule", replicationRules) + } + } + return nil } diff --git a/ibm/service/cos/resource_ibm_cos_replication_configuration.go b/ibm/service/cos/resource_ibm_cos_replication_configuration.go new file mode 100644 index 0000000000..f3bce17dd3 --- /dev/null +++ b/ibm/service/cos/resource_ibm_cos_replication_configuration.go @@ -0,0 +1,396 @@ +package cos + +import ( + "bytes" + "fmt" + "strings" + "time" + + bxsession "github.com/IBM-Cloud/bluemix-go/session" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/ibm-cos-sdk-go/aws" + "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam" + token "github.com/IBM/ibm-cos-sdk-go/aws/credentials/ibmiam/token" + "github.com/IBM/ibm-cos-sdk-go/aws/session" + "github.com/IBM/ibm-cos-sdk-go/service/s3" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + validation "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func ResourceIBMCOSBucketReplicationConfiguration() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMCOSBucketReplicationConfigurationCreate, + Read: resourceIBMCOSBucketReplicationConfigurationRead, + Update: resourceIBMCOSBucketReplicationConfigurationUpdate, + Delete: resourceIBMCOSBucketReplicationConfigurationDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "bucket_crn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "COS bucket CRN", + }, + "bucket_location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "COS bucket location", + }, + "endpoint_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private", "direct"}), + Description: "COS endpoint type: public, private, direct", + Default: "public", + }, + "replication_rule": { + Type: schema.TypeSet, + Required: true, + MaxItems: 1000, + Description: "Replicate objects between buckets, replicate across source and destination. A container for replication rules can add up to 1,000 rules. The maximum size of a replication configuration is 2 MB.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringLenBetween(0, 255), + Description: "A unique identifier for the rule. The maximum value is 255 characters.", + }, + "priority": { + Type: schema.TypeInt, + Optional: true, + Description: "A priority is associated with each rule. There may be cases where multiple rules may be applicable to an object that is uploaded. ", + }, + "enable": { + Type: schema.TypeBool, + Required: true, + Description: "Enable or disable an replication rule for a bucket", + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + Description: "The rule applies to any objects with keys that match this prefix", + }, + "deletemarker_replication_status": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether to replicate delete markers. It should be either Enable or Disable", + }, + "destination_bucket_crn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ValidateRegexps(`^crn:.+:.+:.+:.+:.+:a\/[0-9a-f]{32}:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}:bucket:[a-z-A-Z]*[0-9]*$`), + Description: "The Cloud Resource Name (CRN) of the bucket where you want COS to store the results", + }, + }, + }, + Set: resourceIBMCOSReplicationReuleHash, + }, + }, + } +} + +func replicationRuleSet(replicateList []interface{}) []*s3.ReplicationRule { + + var rules []*s3.ReplicationRule + for _, l := range replicateList { + bkt_replication_rule := s3.ReplicationRule{} + replicateMap, _ := l.(map[string]interface{}) + + //Rule ID + if rule_idSet, exist := replicateMap["rule_id"]; exist { + id := rule_idSet.(string) + bkt_replication_rule.ID = aws.String(id) + } + + //Status Enable/Disable + if statusSet, exist := replicateMap["enable"]; exist { + StatusEnabled := statusSet.(bool) + if StatusEnabled == true { + bkt_replication_rule.Status = aws.String("Enabled") + } else { + bkt_replication_rule.Status = aws.String("Disabled") + } + } + //Days + if priorSet, exist := replicateMap["priority"]; exist { + replicate_priority := int64(priorSet.(int)) + bkt_replication_rule.Priority = aws.Int64(replicate_priority) + } + //Replication Prefix + if PrefixClassSet, exist := replicateMap["prefix"]; exist { + prefix_check := PrefixClassSet.(string) + bkt_replication_rule.Filter = &s3.ReplicationRuleFilter{Prefix: aws.String(prefix_check)} + + } + //DeleteMarkerReplicationStatus + if delMarkerStatusSet, exist := replicateMap["deletemarker_replication_status"]; exist { + del_marker_status_value := delMarkerStatusSet.(bool) + if del_marker_status_value == true { + bkt_replication_rule.DeleteMarkerReplication = &s3.DeleteMarkerReplication{Status: aws.String("Enabled")} + } else { + bkt_replication_rule.DeleteMarkerReplication = &s3.DeleteMarkerReplication{Status: aws.String("Disabled")} + } + } + //Destination CRN + if dest_bucket_CrnSet, exist := replicateMap["destination_bucket_crn"]; exist { + dest_bucketcrn_value := dest_bucket_CrnSet.(string) + bkt_replication_rule.Destination = &s3.Destination{Bucket: aws.String(dest_bucketcrn_value)} + } + + rules = append(rules, &bkt_replication_rule) + + } + return rules +} + +func resourceIBMCOSBucketReplicationConfigurationCreate(d *schema.ResourceData, meta interface{}) error { + bucketCRN := d.Get("bucket_crn").(string) + bucketName := strings.Split(bucketCRN, ":bucket:")[1] + instanceCRN := fmt.Sprintf("%s::", strings.Split(bucketCRN, ":bucket:")[0]) + + bucketLocation := d.Get("bucket_location").(string) + endpointType := d.Get("endpoint_type").(string) + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + s3Client, err := getS3ClientSession(bxSession, bucketLocation, endpointType, instanceCRN) + var rules []*s3.ReplicationRule + + replication, ok := d.GetOk("replication_rule") + if ok { + rules = append(rules, replicationRuleSet(replication.(*schema.Set).List())...) + + } + putBucketReplicationInput := &s3.PutBucketReplicationInput{ + Bucket: aws.String(bucketName), + ReplicationConfiguration: &s3.ReplicationConfiguration{ + Rules: rules, + }, + } + + _, err = s3Client.PutBucketReplication(putBucketReplicationInput) + + if err != nil { + return fmt.Errorf("failed to create the replication rule on COS bucket %s, %v", bucketName, err) + } + + //Generating a fake id which contains every information about to get the bucket via s3 api + bktID := fmt.Sprintf("%s:%s:%s:meta:%s:%s", strings.Replace(instanceCRN, "::", "", -1), "bucket", bucketName, bucketLocation, endpointType) + d.SetId(bktID) + + return resourceIBMCOSBucketReplicationConfigurationRead(d, meta) +} + +func resourceIBMCOSBucketReplicationConfigurationUpdate(d *schema.ResourceData, meta interface{}) error { + bucketCRN := d.Get("bucket_crn").(string) + bucketName := strings.Split(bucketCRN, ":bucket:")[1] + instanceCRN := fmt.Sprintf("%s::", strings.Split(bucketCRN, ":bucket:")[0]) + + bucketLocation := d.Get("bucket_location").(string) + endpointType := d.Get("endpoint_type").(string) + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + s3Client, err := getS3ClientSession(bxSession, bucketLocation, endpointType, instanceCRN) + if err != nil { + return err + } + + if d.HasChange("replication_rule") { + var rules []*s3.ReplicationRule + + replication, ok := d.GetOk("replication_rule") + if ok { + rules = append(rules, replicationRuleSet(replication.(*schema.Set).List())...) + + } + putBucketReplication := &s3.PutBucketReplicationInput{ + Bucket: aws.String(bucketName), + ReplicationConfiguration: &s3.ReplicationConfiguration{ + Rules: rules, + }, + } + + _, err = s3Client.PutBucketReplication(putBucketReplication) + + if err != nil { + return fmt.Errorf("failed to update the replication rule on COS bucket %s, %v", bucketName, err) + } + + } + return resourceIBMCOSBucketReplicationConfigurationRead(d, meta) +} + +func resourceIBMCOSBucketReplicationConfigurationRead(d *schema.ResourceData, meta interface{}) error { + + bucketCRN := parseBucketReplId(d.Id(), "bucketCRN") + bucketName := parseBucketReplId(d.Id(), "bucketName") + bucketLocation := parseBucketReplId(d.Id(), "bucketLocation") + instanceCRN := parseBucketReplId(d.Id(), "instanceCRN") + endpointType := parseBucketReplId(d.Id(), "endpointType") + + d.Set("bucket_crn", bucketCRN) + d.Set("bucket_location", bucketLocation) + if endpointType != "" { + d.Set("endpoint_type", endpointType) + } + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + s3Client, err := getS3ClientSession(bxSession, bucketLocation, endpointType, instanceCRN) + if err != nil { + return err + } + + getBucketReplicationInput := &s3.GetBucketReplicationInput{ + Bucket: aws.String(bucketName), + } + + replicationptr, err := s3Client.GetBucketReplication(getBucketReplicationInput) + + if err != nil && !strings.Contains(err.Error(), "AccessDenied: Access Denied") { + return err + } + + if replicationptr != nil { + replicationRules := flex.ReplicationRuleGet(replicationptr.ReplicationConfiguration) + if len(replicationRules) > 0 { + d.Set("replication_rule", replicationRules) + } + } + + return nil +} + +func resourceIBMCOSBucketReplicationConfigurationDelete(d *schema.ResourceData, meta interface{}) error { + bucketName := parseBucketReplId(d.Id(), "bucketName") + bucketLocation := parseBucketReplId(d.Id(), "bucketLocation") + instanceCRN := parseBucketReplId(d.Id(), "instanceCRN") + endpointType := parseBucketReplId(d.Id(), "endpointType") + + bxSession, err := meta.(conns.ClientSession).BluemixSession() + if err != nil { + return err + } + + s3Client, err := getS3ClientSession(bxSession, bucketLocation, endpointType, instanceCRN) + if err != nil { + return err + } + + deleteBucketReplicationInput := &s3.DeleteBucketReplicationInput{ + Bucket: aws.String(bucketName), + } + + _, err = s3Client.DeleteBucketReplication(deleteBucketReplicationInput) + + if err != nil { + return err + } + return nil +} + +func parseBucketReplId(id string, info string) string { + bucketCRN := strings.Split(id, ":meta:")[0] + meta := strings.Split(id, ":meta:")[1] + + if info == "bucketName" { + return strings.Split(bucketCRN, ":bucket:")[1] + } + if info == "instanceCRN" { + return fmt.Sprintf("%s::", strings.Split(bucketCRN, ":bucket:")[0]) + } + if info == "bucketCRN" { + return bucketCRN + } + if info == "bucketLocation" { + return strings.Split(meta, ":")[0] + } + if info == "endpointType" { + return strings.Split(meta, ":")[1] + } + + return parseBucketId(bucketCRN, info) +} + +func getCosEndpointType(bucketLocation string, endpointType string) string { + if bucketLocation != "" { + switch endpointType { + case "public": + return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + case "private": + return fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + case "direct": + return fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + default: + return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + } + } + return "" +} + +func getS3ClientSession(bxSession *bxsession.Session, bucketLocation string, endpointType string, instanceCRN string) (*s3.S3, error) { + var s3Conf *aws.Config + + apiEndpoint := getCosEndpointType(bucketLocation, endpointType) + apiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) + if apiEndpoint == "" { + return nil, fmt.Errorf("the endpoint doesn't exists for given location %s and endpoint type %s", bucketLocation, endpointType) + } + + authEndpoint, err := bxSession.Config.EndpointLocator.IAMEndpoint() + if err != nil { + return nil, err + } + authEndpointPath := fmt.Sprintf("%s%s", authEndpoint, "/identity/token") + apiKey := bxSession.Config.BluemixAPIKey + if apiKey != "" { + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewStaticCredentials(aws.NewConfig(), authEndpointPath, apiKey, instanceCRN)).WithS3ForcePathStyle(true) + } + iamAccessToken := bxSession.Config.IAMAccessToken + if iamAccessToken != "" { + initFunc := func() (*token.Token, error) { + return &token.Token{ + AccessToken: bxSession.Config.IAMAccessToken, + RefreshToken: bxSession.Config.IAMRefreshToken, + TokenType: "Bearer", + ExpiresIn: int64((time.Hour * 248).Seconds()) * -1, + Expiration: time.Now().Add(-1 * time.Hour).Unix(), + }, nil + } + s3Conf = aws.NewConfig().WithEndpoint(apiEndpoint).WithCredentials(ibmiam.NewCustomInitFuncCredentials(aws.NewConfig(), initFunc, authEndpointPath, instanceCRN)).WithS3ForcePathStyle(true) + } + s3Sess := session.Must(session.NewSession()) + return s3.New(s3Sess, s3Conf), nil +} + +func resourceIBMCOSReplicationReuleHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", + m["destination_bucket_crn"].(string))) + + return conns.String(buf.String()) +} diff --git a/ibm/service/cos/resource_ibm_cos_replication_configuration_test.go b/ibm/service/cos/resource_ibm_cos_replication_configuration_test.go new file mode 100644 index 0000000000..bc344293b9 --- /dev/null +++ b/ibm/service/cos/resource_ibm_cos_replication_configuration_test.go @@ -0,0 +1,163 @@ +package cos_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// Replication features +func TestAccIBMCosBucket_Bucket_Replication(t *testing.T) { + + accountID := acc.IBM_AccountID_REPL + cosServiceNameSrc := fmt.Sprintf("cos_instance_src_%d", acctest.RandIntRange(10, 100)) + cosServiceNameDest := fmt.Sprintf("cos_instance_dest_%d", acctest.RandIntRange(10, 100)) + bucketNameSrc := fmt.Sprintf("terraform-testacc-src-%d", acctest.RandIntRange(10, 100)) + bucketNameDest := fmt.Sprintf("terraform-testacc-dest-%d", acctest.RandIntRange(10, 100)) + bucketRegionSrc := "us-south" + bucketRegionDest := "us-south" + bucketClassSrc := "standard" + bucketClassDest := "standard" + bucketRegionType := "region_location" + ruleId := "my-rule-id-bucket-replication" + enable := true + prefix := "" + priority := 1 + deletemarker_replication_status := true + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMCosBucketDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMCosBucket_replication(accountID, cosServiceNameSrc, cosServiceNameDest, bucketNameSrc, bucketNameDest, bucketRegionType, bucketRegionSrc, bucketRegionDest, bucketClassSrc, bucketClassDest, ruleId, enable, priority, deletemarker_replication_status, prefix), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_source", "bucket_name", bucketNameSrc), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_destination", "bucket_name", bucketNameDest), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_source", "storage_class", bucketClassSrc), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_destination", "storage_class", bucketClassDest), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_source", "region_location", bucketRegionSrc), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_destination", "region_location", bucketRegionDest), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_source", "object_versioning.#", "1"), + resource.TestCheckResourceAttr("ibm_cos_bucket.cos_bucket_destination", "object_versioning.#", "1"), + resource.TestCheckResourceAttr("ibm_cos_bucket_replication_rule.cos_bucket_repl", "replication_rule.#", "1"), + ), + }, + }, + }) +} + +// create cos instance & buckets for source and destination and enable replication rule after iam authorization policy set on resource attributes.. +func testAccCheckIBMCosBucket_replication(accountID, cosServiceNameSrc string, cosServiceNameDest string, bucketNameSrc string, bucketNameDest string, regiontype string, regionSrc string, regionDest string, storageClassSrc string, storageClassDest string, ruleId string, enable bool, priority int, deletemarker_replication_status bool, prefix string) string { + + return fmt.Sprintf(` + data "ibm_resource_group" "cos_group" { + is_default=true + } + resource "ibm_resource_instance" "cos_instance_source" { + name = "%s" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" + } + + resource "ibm_cos_bucket" "cos_bucket_source" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.cos_instance_source.id + region_location = "%s" + storage_class = "%s" + object_versioning { + enable = true + } + } + resource "ibm_resource_instance" "cos_instance_destination" { + name = "%s" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" + } + + resource "ibm_cos_bucket" "cos_bucket_destination" { + bucket_name = "%s" + resource_instance_id = ibm_resource_instance.cos_instance_destination.id + region_location = "%s" + storage_class = "%s" + object_versioning { + enable = true + } + } + + resource "ibm_iam_authorization_policy" "policy" { + roles = [ + "Writer", + ] + subject_attributes { + name = "accountId" + value = "%s" + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_source.guid + } + subject_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_source.bucket_name + } + subject_attributes { + name = "resourceType" + value = "bucket" + } + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = "%s" + } + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceInstance" + operator = "stringEquals" + value = ibm_resource_instance.cos_instance_destination.guid + } + resource_attributes { + name = "resource" + operator = "stringEquals" + value = ibm_cos_bucket.cos_bucket_destination.bucket_name + } + resource_attributes { + name = "resourceType" + operator = "stringEquals" + value = "bucket" + } + } + resource "ibm_cos_bucket_replication_rule" "cos_bucket_repl" { + depends_on = [ + ibm_iam_authorization_policy.policy + ] + bucket_crn = ibm_cos_bucket.cos_bucket_source.crn + bucket_location = ibm_cos_bucket.cos_bucket_source.region_location + replication_rule { + rule_id = "%s" + enable = true + prefix = "%s" + priority = 1 + deletemarker_replication_status = true + destination_bucket_crn = ibm_cos_bucket.cos_bucket_destination.crn + } + } + + `, cosServiceNameSrc, bucketNameSrc, regionSrc, storageClassSrc, cosServiceNameDest, bucketNameDest, regionDest, storageClassDest, accountID, accountID, ruleId, prefix) +} diff --git a/website/docs/d/cos_bucket.html.markdown b/website/docs/d/cos_bucket.html.markdown index 04da780a9e..b3f1063a11 100644 --- a/website/docs/d/cos_bucket.html.markdown +++ b/website/docs/d/cos_bucket.html.markdown @@ -55,6 +55,12 @@ data "ibm_cos_bucket" "cos-bucket-sat" { } ``` +# ibm_cos_bucket_replication_rule + +Retrieves information of replication configuration on an existing bucket. . For more information, about configuration options, see [Replicating objects](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-replication-overview). + +To configure a replication policy on a bucket, you must enable object versioning on both source and destination buckets by using the [Versioning objects](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-versioning). + ## Argument reference Review the argument references that you can specify for your data source. @@ -129,6 +135,16 @@ In addition to all argument reference list, you can access the following attribu - `maximum` - (String) Specifies maximum duration of time an object can be kept unmodified in the bucket. - `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. +- `replication_rule`- (List) Nested block have the following structure: + + Nested scheme for `replication_rule`: + - `rule_id`- (String) The rule id. + - `enable`- (Bool) Specifies whether the rule is enabled. Specify true for Enabling it or false for Disabling it. + - `prefix`- (String) An object key name prefix that identifies the subset of objects to which the rule applies. + - `priority`- (Int) A priority is associated with each rule. The rule will be applied in a higher priority if there are multiple rules configured. The higher the number, the higher the priority + - `deletemarker_replication_status`- (Bool) Specifies whether Object storage replicates delete markers. Specify true for Enabling it or false for Disabling it. + - `destination_bucket_crn`- (String) The CRN of your destination bucket that you want to replicate to. + - `single_site_location` - (String) The location to create a single site bucket. - `storage_class` - (String) The storage class of the bucket. - `s3_endpoint_public` - (String) Public endpoint for cos bucket. diff --git a/website/docs/r/cos_replication.html.markdown b/website/docs/r/cos_replication.html.markdown new file mode 100644 index 0000000000..e8ba249a7b --- /dev/null +++ b/website/docs/r/cos_replication.html.markdown @@ -0,0 +1,176 @@ +--- + +subcategory: "Object Storage" +layout: "ibm" +page_title: "IBM : Cloud Object Storage Bucket Replication" +description: + "Manages IBM Cloud Object Storage Bucket Replication." +--- + +# ibm_cos_bucket_replication_rule +Create/replaces or delete replication configuration on an existing bucket. For more information, about configuration options, see [Replicating objects](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-replication-overview). + +To configure a replication policy on a bucket, you must enable object versioning on both source and destination buckets by using the [Versioning objects](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-versioning). + +**Note:** + + you must have `writer` or `manager` platform roles on source bucket and sufficient platform roles to create new [IAM policies](https://cloud.ibm.com/docs/account?topic=account-iamoverview#iamoverview) that allow the source bucket to write to the destination bucket. + Add depends_on on ibm_iam_authorization_policy.policy in template to make sure replication only enabled once iam authorization policy set. + We are addressing Create functionality for replication now. Update functionality will be in-progress. + + +--- + +## Example usage +The following example creates an instance of IBM Cloud Object Storage. Then, multiple buckets are created and configured replication policy. + +```terraform +data "ibm_resource_group" "cos_group" { + name = "cos-resource-group" +} + +resource "ibm_resource_instance" "cos_instance_source" { + name = "cos-instance-src" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_resource_instance" "cos_instance_destination" { + name = "cos-instance-dest" + resource_group_id = data.ibm_resource_group.cos_group.id + service = "cloud-object-storage" + plan = "standard" + location = "global" +} + +resource "ibm_cos_bucket" "cos_bucket_source" { + bucket_name = "a-bucket-source" + resource_instance_id = ibm_resource_instance.cos_instance_source.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } +} + +resource "ibm_cos_bucket" "cos_bucket_destination" { + bucket_name = "a-bucket-destination" + resource_instance_id = ibm_resource_instance.cos_instance_destination.id + region_location = "us-south" + storage_class = "standard" + object_versioning { + enable = true + } +} + + +### Configure IAM authorization policy + +resource "ibm_iam_authorization_policy" "policy" { + roles = [ + "Writer", + ] + subject_attributes { + name = "accountId" + value = "an-account-id" + } + subject_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + subject_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_source.guid + } + subject_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_source.bucket_name + } + subject_attributes { + name = "resourceType" + value = "bucket" + } + resource_attributes { + name = "accountId" + value = "an-account-id" + } + resource_attributes { + name = "serviceName" + value = "cloud-object-storage" + } + resource_attributes { + name = "serviceInstance" + value = ibm_resource_instance.cos_instance_destination.guid + } + resource_attributes { + name = "resource" + value = ibm_cos_bucket.cos_bucket_destination.bucket_name + } + resource_attributes { + name = "resourceType" + value = "bucket" + } +} + +### Configure replication policy + +resource "ibm_cos_bucket_replication_rule" "cos_bucket_repl" { + depends_on = [ + ibm_iam_authorization_policy.policy + ] + bucket_crn = ibm_cos_bucket.cos_bucket_source.crn + bucket_location = ibm_cos_bucket.cos_bucket_source.region_location + replication_rule { + rule_id = "a-rule-id" + enable = "true" + prefix = "a-prefix" + priority = "a-priority-associated-with-the-rule" + deletemarker_replication_status = "Enabled/Suspened" + destination_bucket_crn = ibm_cos_bucket.cos_bucket_destination.crn + } +} + +``` + +## Argument reference +Review the argument references that you can specify for your resource. +- `bucket_crn` - (Required, Forces new resource, String) The CRN of the COS bucket. +- `bucket_location` - (Required, Forces new resource, String) The location of the COS bucket. +- `endpoint_type`- (Optional, String) The type of the endpoint either `public` or `private` or `direct` to be used for buckets. Default value is `public`. +- `replication_rule`- (Required, List) Nested block have the following structure: + + Nested scheme for `replication_rule`: + - `rule_id`- (Optional, String) The rule id. + - `enable`- (Required, Bool) Specifies whether the rule is enabled. Specify true for Enabling it or false for Disabling it. + - `prefix`- (Optional, String) An object key name prefix that identifies the subset of objects to which the rule applies. + - `priority`- (Optional, Int) A priority is associated with each rule. The rule will be applied in a higher priority if there are multiple rules configured. The higher the number, the higher the priority + - `deletemarker_replication_status`- (Optional, Bool) Specifies whether Object storage replicates delete markers.Specify true for Enabling it or false for Disabling it. + - `destination_bucket_crn`- (Required, String) The CRN of your destination bucket that you want to replicate to. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `crn` - (String) The CRN of the bucket. +- `id` - (String) The ID of the bucket. + +## Import IBM COS Bucket +The `ibm_cos_bucket_replication_rule` resource can be imported by using the `id`. The ID is formed from the `CRN` (Cloud Resource Name). The `CRN` and bucket location can be found on the portal. + +id = `$CRN:meta:$bucketlocation:$endpointtype` + +**Syntax** + +``` +$ terraform import ibm_cos_bucket_replication_rule.mybucket `$CRN:meta:$bucketlocation:public` + +``` + +**Example** + +``` + +$ terraform import ibm_cos_bucket_replication_rule.mybucket crn:v1:bluemix:public:cloud-object-storage:global:a/4ea1882a2d3401ed1e459979941966ea:31fa970d-51d0-4b05-893e-251cba75a7b3:bucket:mybucketname:meta:us-south:public + +``` \ No newline at end of file