diff --git a/examples/ibm-is-ng/main.tf b/examples/ibm-is-ng/main.tf index 896216cc78..c344f98a6c 100644 --- a/examples/ibm-is-ng/main.tf +++ b/examples/ibm-is-ng/main.tf @@ -1408,7 +1408,14 @@ resource "ibm_is_image_obsolete" "example" { image = ibm_is_image.image1.id } - +resource "ibm_is_share" "share" { + zone = "us-east-1" + source_share_crn = "crn:v1:staging:public:is:us-south-1:a/efe5afc483594adaa8325e2b4d1290df::share:r134-d8c8821c-a227-451d-a9ed-0c0cd2358829" + encryption_key = "crn:v1:staging:public:kms:us-south:a/efe5afc483594adaa8325e2b4d1290df:1be45161-6dae-44ca-b248-837f98004057:key:3dd21cc5-cc20-4f7c-bc62-8ec9a8a3d1bd" + replication_cron_spec = "5 * * * *" + name = "tfp-temp-crr" + profile = "dp2" +} //snapshot consistency group resource "ibm_is_snapshot_consistency_group" "is_snapshot_consistency_group_instance" { diff --git a/go.mod b/go.mod index 638e7af953..d409ddb66f 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/IBM/schematics-go-sdk v0.2.2 github.com/IBM/secrets-manager-go-sdk/v2 v2.0.2 github.com/IBM/vpc-beta-go-sdk v0.6.0 - github.com/IBM/vpc-go-sdk v0.45.0 + github.com/IBM/vpc-go-sdk v0.46.0 github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/akamai/AkamaiOPEN-edgegrid-golang/v5 v5.0.0 @@ -241,4 +241,4 @@ exclude ( github.com/kubernetes-incubator/external-storage v0.20.4-openstorage-rc2 k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible k8s.io/client-go v12.0.0+incompatible -) \ No newline at end of file +) diff --git a/go.sum b/go.sum index dd2b86dde3..2005088c96 100644 --- a/go.sum +++ b/go.sum @@ -180,6 +180,8 @@ github.com/IBM/vpc-go-sdk v0.43.0 h1:uy/qWIqETCXraUG2cq5sjScr6pZ79ZteY1v5iLUVQ3Q github.com/IBM/vpc-go-sdk v0.43.0/go.mod h1:kRz9tqPvpHoA/qGrC/qVjTbi4ICuTChpG76L89liGL4= github.com/IBM/vpc-go-sdk v0.45.0 h1:RFbUZH5vBRGAEW5+jRzbDlxB+a+GvG9EBhyYO52Tvrs= github.com/IBM/vpc-go-sdk v0.45.0/go.mod h1:4Hs5d/aClmsxAzwDQkwG+ri0vW2ykPJdpM6hDLRwKcA= +github.com/IBM/vpc-go-sdk v0.46.0 h1:OwXH3oaYgYmzt559n77AteSpNsW4H1PoeHcR4EOolzk= +github.com/IBM/vpc-go-sdk v0.46.0/go.mod h1:4Hs5d/aClmsxAzwDQkwG+ri0vW2ykPJdpM6hDLRwKcA= github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E= github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Logicalis/asn1 v0.0.0-20190312173541-d60463189a56 h1:vuquMR410psHNax14XKNWa0Ae/kYgWJcXi0IFuX60N0= diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index 4968af4c8a..8a90bdea06 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -104,6 +104,8 @@ var ( DedicatedHostGroupFamily string DedicatedHostGroupClass string ShareProfileName string + SourceShareCRN string + ShareEncryptionKey string VNIId string VolumeProfileName string VSIUnattachedBootVolumeID string @@ -848,6 +850,18 @@ func init() { fmt.Println("[INFO] Set the environment variable IS_SHARE_PROFILE for testing ibm_is_instance resource else it is set to default value 'tier-3iops'") } + SourceShareCRN = os.Getenv("IS_SOURCE_SHARE_CRN") + if SourceShareCRN == "" { + SourceShareCRN = "crn:v1:staging:public:is:us-east-1:a/efe5afc483594adaa8325e2b4d1290df::share:r142-a106f162-86e4-4d7f-be75-193cc55a93e9" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_SHARE_PROFILE for testing ibm_is_instance resource else it is set to default value") + } + + ShareEncryptionKey = os.Getenv("IS_SHARE_ENCRYPTION_KEY") + if ShareEncryptionKey == "" { + ShareEncryptionKey = "crn:v1:staging:public:kms:us-south:a/efe5afc483594adaa8325e2b4d1290df:1be45161-6dae-44ca-b248-837f98004057:key:3dd21cc5-cc20-4f7c-bc62-8ec9a8a3d1bd" // for next gen infrastructure + fmt.Println("[INFO] Set the environment variable IS_SHARE_PROFILE for testing ibm_is_instance resource else it is set to default value") + } + VolumeProfileName = os.Getenv("IS_VOLUME_PROFILE") if VolumeProfileName == "" { VolumeProfileName = "general-purpose" diff --git a/ibm/service/vpc/data_source_ibm_is_share.go b/ibm/service/vpc/data_source_ibm_is_share.go index b1671d68f6..e5bd0c5559 100644 --- a/ibm/service/vpc/data_source_ibm_is_share.go +++ b/ibm/service/vpc/data_source_ibm_is_share.go @@ -64,6 +64,30 @@ func DataSourceIbmIsShare() *schema.Resource { Computed: true, Description: "The maximum input/output operation performance bandwidth per second for the file share.", }, + "latest_sync": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information about the latest synchronization for this file share.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "completed_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The completed date and time of last synchronization between the replica share and its source.", + }, + "data_transferred": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The data transferred (in bytes) in the last synchronization between the replica and its source.", + }, + "started_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The start date and time of last synchronization between the replica share and its source.", + }, + }, + }, + }, "latest_job": &schema.Schema{ Type: schema.TypeList, Computed: true, @@ -410,7 +434,17 @@ func dataSourceIbmIsShareRead(context context.Context, d *schema.ResourceData, m if err = d.Set("iops", share.Iops); err != nil { return diag.FromErr(fmt.Errorf("Error setting iops: %s", err)) } - + latest_syncs := []map[string]interface{}{} + if share.LatestSync != nil { + latest_sync := make(map[string]interface{}) + latest_sync["completed_at"] = flex.DateTimeToString(share.LatestSync.CompletedAt) + if share.LatestSync.DataTransferred != nil { + latest_sync["data_transferred"] = *share.LatestSync.DataTransferred + } + latest_sync["started_at"] = flex.DateTimeToString(share.LatestSync.CompletedAt) + latest_syncs = append(latest_syncs, latest_sync) + } + d.Set("latest_sync", latest_syncs) if share.LatestJob != nil { err = d.Set("latest_job", dataSourceShareFlattenLatestJob(*share.LatestJob)) if err != nil { diff --git a/ibm/service/vpc/data_source_ibm_is_shares.go b/ibm/service/vpc/data_source_ibm_is_shares.go index dbeffabe24..f4829e0671 100644 --- a/ibm/service/vpc/data_source_ibm_is_shares.go +++ b/ibm/service/vpc/data_source_ibm_is_shares.go @@ -78,6 +78,30 @@ func DataSourceIbmIsShares() *schema.Resource { Computed: true, Description: "The maximum input/output operation performance bandwidth per second for the file share.", }, + "latest_sync": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information about the latest synchronization for this file share.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "completed_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The completed date and time of last synchronization between the replica share and its source.", + }, + "data_transferred": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The data transferred (in bytes) in the last synchronization between the replica and its source.", + }, + "started_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The start date and time of last synchronization between the replica share and its source.", + }, + }, + }, + }, "latest_job": &schema.Schema{ Type: schema.TypeList, Computed: true, @@ -455,6 +479,17 @@ func dataSourceShareCollectionSharesToMap(meta interface{}, sharesItem vpcv1.Sha if sharesItem.Iops != nil { sharesMap["iops"] = sharesItem.Iops } + latest_syncs := []map[string]interface{}{} + if sharesItem.LatestSync != nil { + latest_sync := make(map[string]interface{}) + latest_sync["completed_at"] = flex.DateTimeToString(sharesItem.LatestSync.CompletedAt) + if sharesItem.LatestSync.DataTransferred != nil { + latest_sync["data_transferred"] = *sharesItem.LatestSync.DataTransferred + } + latest_sync["started_at"] = flex.DateTimeToString(sharesItem.LatestSync.CompletedAt) + latest_syncs = append(latest_syncs, latest_sync) + } + sharesMap["latest_sync"] = latest_syncs if sharesItem.LifecycleState != nil { sharesMap["lifecycle_state"] = sharesItem.LifecycleState } diff --git a/ibm/service/vpc/resource_ibm_is_share.go b/ibm/service/vpc/resource_ibm_is_share.go index 487479fd42..39fcaa0d72 100644 --- a/ibm/service/vpc/resource_ibm_is_share.go +++ b/ibm/service/vpc/resource_ibm_is_share.go @@ -54,12 +54,11 @@ func ResourceIbmIsShare() *schema.Resource { Schema: map[string]*schema.Schema{ "encryption_key": { - Type: schema.TypeString, - Optional: true, - RequiredWith: []string{"size"}, - ForceNew: true, - Computed: true, - Description: "The CRN of the key to use for encrypting this file share.If no encryption key is provided, the share will not be encrypted.", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + Description: "The CRN of the key to use for encrypting this file share.If no encryption key is provided, the share will not be encrypted.", }, "initial_owner": { Type: schema.TypeList, @@ -105,8 +104,8 @@ func ResourceIbmIsShare() *schema.Resource { Type: schema.TypeInt, Optional: true, Computed: true, - ExactlyOneOf: []string{"size", "source_share"}, - ConflictsWith: []string{"replication_cron_spec", "source_share"}, + ExactlyOneOf: []string{"size", "source_share", "source_share_crn"}, + ConflictsWith: []string{"replication_cron_spec", "source_share", "source_share_crn"}, ValidateFunc: validate.InvokeValidator("ibm_is_share", "size"), Description: "The size of the file share rounded up to the next gigabyte.", }, @@ -511,16 +510,25 @@ func ResourceIbmIsShare() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - ConflictsWith: []string{"replica_share", "size"}, + Computed: true, + ConflictsWith: []string{"replica_share", "size", "source_share_crn"}, RequiredWith: []string{"replication_cron_spec"}, Description: "The ID of the source file share for this replica file share. The specified file share must not already have a replica, and must not be a replica.", }, + "source_share_crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ConflictsWith: []string{"replica_share", "size", "source_share"}, + RequiredWith: []string{"replication_cron_spec"}, + Description: "The CRN of the source file share for this replica file share. The specified file share must not already have a replica, and must not be a replica.", + }, "replication_cron_spec": &schema.Schema{ Type: schema.TypeString, Optional: true, DiffSuppressFunc: suppressCronSpecDiff, Computed: true, - RequiredWith: []string{"source_share"}, ConflictsWith: []string{"replica_share", "size"}, Description: "The cron specification for the file share replication schedule.Replication of a share can be scheduled to occur at most once per hour.", }, @@ -563,6 +571,30 @@ func ResourceIbmIsShare() *schema.Resource { Computed: true, Description: "The date and time that the file share was last synchronized to its replica.This property will be present when the `replication_role` is `source`.", }, + "latest_sync": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Information about the latest synchronization for this file share.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "completed_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The completed date and time of last synchronization between the replica share and its source.", + }, + "data_transferred": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The data transferred (in bytes) in the last synchronization between the replica and its source.", + }, + "started_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The start date and time of last synchronization between the replica share and its source.", + }, + }, + }, + }, "latest_job": &schema.Schema{ Type: schema.TypeList, Computed: true, @@ -727,17 +759,18 @@ func resourceIbmIsShareCreate(context context.Context, d *schema.ResourceData, m accessControlMode := accessControlModeIntf.(string) sharePrototype.AccessControlMode = &accessControlMode } + if encryptionKeyIntf, ok := d.GetOk("encryption_key"); ok { + encryptionKey := encryptionKeyIntf.(string) + encryptionKeyIdentity := &vpcv1.EncryptionKeyIdentity{ + CRN: &encryptionKey, + } + sharePrototype.EncryptionKey = encryptionKeyIdentity + } if sizeIntf, ok := d.GetOk("size"); ok { size := int64(sizeIntf.(int)) sharePrototype.Size = &size - if encryptionKeyIntf, ok := d.GetOk("encryption_key"); ok { - encryptionKey := encryptionKeyIntf.(string) - encryptionKeyIdentity := &vpcv1.EncryptionKeyIdentity{ - CRN: &encryptionKey, - } - sharePrototype.EncryptionKey = encryptionKeyIdentity - } + initial_owner := &vpcv1.ShareInitialOwner{} if initialOwnerIntf, ok := d.GetOk("initial_owner"); ok { initialOwnerMap := initialOwnerIntf.([]interface{})[0].(map[string]interface{}) @@ -823,7 +856,15 @@ func resourceIbmIsShareCreate(context context.Context, d *schema.ResourceData, m sharePrototype.SourceShare = &vpcv1.ShareIdentity{ ID: &sourceShare, } + } else { + sourceShareCRN := d.Get("source_share_crn").(string) + if sourceShareCRN != "" { + sharePrototype.SourceShare = &vpcv1.ShareIdentity{ + CRN: &sourceShareCRN, + } + } } + replicationCronSpec := d.Get("replication_cron_spec").(string) sharePrototype.ReplicationCronSpec = &replicationCronSpec } @@ -1075,9 +1116,17 @@ func resourceIbmIsShareRead(context context.Context, d *schema.ResourceData, met return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) } - // if share.LastSyncAt != nil { - // d.Set("last_sync_at", share.LastSyncAt.String()) - // } + latest_syncs := []map[string]interface{}{} + if share.LatestSync != nil { + latest_sync := make(map[string]interface{}) + latest_sync["completed_at"] = flex.DateTimeToString(share.LatestSync.CompletedAt) + if share.LatestSync.DataTransferred != nil { + latest_sync["data_transferred"] = *share.LatestSync.DataTransferred + } + latest_sync["started_at"] = flex.DateTimeToString(share.LatestSync.CompletedAt) + latest_syncs = append(latest_syncs, latest_sync) + } + d.Set("latest_sync", latest_syncs) latest_jobs := []map[string]interface{}{} if share.LatestJob != nil { latest_job := make(map[string]interface{}) diff --git a/ibm/service/vpc/resource_ibm_is_share_test.go b/ibm/service/vpc/resource_ibm_is_share_test.go index 353e1fe570..b5f4c0d6ae 100644 --- a/ibm/service/vpc/resource_ibm_is_share_test.go +++ b/ibm/service/vpc/resource_ibm_is_share_test.go @@ -38,6 +38,28 @@ func TestAccIbmIsShareBasic(t *testing.T) { }) } +func TestAccIbmIsShareCrossRegionReplication(t *testing.T) { + var conf vpcv1.Share + name := fmt.Sprintf("tf-fs-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmIsShareDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmIsShareCrossRegionReplicaConfig(name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmIsShareExists("ibm_is_share.is_share", conf), + resource.TestCheckResourceAttrSet("ibm_is_share.is_share", "source_share_crn"), + resource.TestCheckResourceAttrSet("ibm_is_share.is_share", "encryption_key"), + resource.TestCheckResourceAttr("ibm_is_share.is_share", "name", name), + resource.TestCheckResourceAttr("ibm_is_share.is_share", "encryption", "user_managed"), + ), + }, + }, + }) +} + func TestAccIbmIsShareAllArgs(t *testing.T) { var conf vpcv1.Share @@ -157,7 +179,18 @@ func testAccCheckIbmIsShareConfigBasic(name string) string { } `, name, acc.ShareProfileName) } - +func testAccCheckIbmIsShareCrossRegionReplicaConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_is_share" "is_share" { + zone = "us-south-2" + encryption_key = "%s" + source_share_crn = "%s" + replication_cron_spec = "0 */5 * * *" + name = "%s" + profile = "%s" + } + `, acc.ShareEncryptionKey, acc.SourceShareCRN, name, acc.ShareProfileName) +} func testAccCheckIbmIsShareConfig(vpcName, name string, size int, shareTergetName string) string { return fmt.Sprintf(` diff --git a/website/docs/d/is_share.html.markdown b/website/docs/d/is_share.html.markdown index c338555af8..45a1875c8b 100644 --- a/website/docs/d/is_share.html.markdown +++ b/website/docs/d/is_share.html.markdown @@ -48,9 +48,14 @@ The following attributes are exported: - `created_at` - The date and time that the file share is created. - `crn` - The CRN for this share. - `encryption` - The type of encryption used for this file share. -- `encryption_key` - The CRN of the key used to encrypt this file share. Nested `encryption_key` blocks have the following structure: +- `encryption_key` - The CRN of the key used to encrypt this file share. - `href` - The URL for this share. - `iops` - The maximum input/output operation performance bandwidth per second for the file share. +- `latest_sync` - (List) Information about the latest synchronization for this file share. +Nested `latest_sync` blocks have the following structure: + - `completed_at` - (String) The completed date and time of last synchronization between the replica share and its source. + - `data_transferred` - (Integer) The data transferred (in bytes) in the last synchronization between the replica and its source. + - `started_at` - (String) The start date and time of last synchronization between the replica share and its source. - `latest_job` - The latest job associated with this file share.This property will be absent if no jobs have been created for this file share. Nested `latest_job` blocks have the following structure: - `status` - The status of the file share job - `status_reasons` - The reasons for the file share job status (if any). Nested `status_reasons` blocks have the following structure: diff --git a/website/docs/d/is_shares.html.markdown b/website/docs/d/is_shares.html.markdown index 122b519f9e..88a6099736 100644 --- a/website/docs/d/is_shares.html.markdown +++ b/website/docs/d/is_shares.html.markdown @@ -32,10 +32,15 @@ The following attributes are exported: - `created_at` - The date and time that the file share is created. - `crn` - The CRN for this share. - `encryption` - The type of encryption used for this file share. - - `encryption_key` - The CRN of the key used to encrypt this file share. Nested `encryption_key` blocks have the following structure: + - `encryption_key` - The CRN of the key used to encrypt this file share. - `href` - The URL for this share. - `id` - The unique identifier for this file share. - `iops` - The maximum input/output operation performance bandwidth per second for the file share. + - `latest_sync` - (List) Information about the latest synchronization for this file share. + Nested `latest_sync` blocks have the following structure: + - `completed_at` - (String) The completed date and time of last synchronization between the replica share and its source. + - `data_transferred` - (Integer) The data transferred (in bytes) in the last synchronization between the replica and its source. + - `started_at` - (String) The start date and time of last synchronization between the replica share and its source. - `latest_job` - The latest job associated with this file share.This property will be absent if no jobs have been created for this file share. Nested `latest_job` blocks have the following structure: - `status` - The status of the file share job - `status_reasons` - The reasons for the file share job status (if any). Nested `status_reasons` blocks have the following structure: diff --git a/website/docs/r/is_share.html.markdown b/website/docs/r/is_share.html.markdown index ffaa72f235..2319e75337 100644 --- a/website/docs/r/is_share.html.markdown +++ b/website/docs/r/is_share.html.markdown @@ -8,7 +8,7 @@ subcategory: "VPC infrastructure" # ibm\_is_share -Provides a resource for Share. This allows Share to be created, updated and deleted. +Provides a resource for Share. This allows Share to be created, updated and deleted. For more information, about share replication, see [Share replication](https://cloud.ibm.com/docs/vpc?topic=vpc-file-storage-replication). ~> **NOTE** New shares should be created with profile `dp2`. Old Tiered profiles will be deprecated soon. @@ -51,6 +51,25 @@ resource "ibm_is_share" "example-2" { } } ``` +## Example Usage (Create a cross regional replication) +```terraform +resource "ibm_is_share" "example-3" { + provider = ibm.syd + access_control_mode = "security_group" + name = "my-share" + size = 200 + profile = "dp2" + zone = "au-syd-2" +} +resource "ibm_is_share" "example-4" { + provider = ibm.ussouth + zone = "us-south-3" + source_share_crn = ibm_is_share.example-3.crn + name = "my-replica1" + profile = "dp2" + replication_cron_spec = "0 */5 * * *" +} +``` ## Argument Reference The following arguments are supported: @@ -130,6 +149,7 @@ The following arguments are supported: - `replication_cron_spec` - (Optional, String) The cron specification for the file share replication schedule. - `size` - (Required, Integer) The size of the file share rounded up to the next gigabyte. - `source_share` - (Optional, String) The ID of the source file share for this replica file share. The specified file share must not already have a replica, and must not be a replica. +- `source_share_crn` - (Optional, String) The CRN of the source file share. - `tags` - (Optional, List of Strings) The list of user tags to attach to the share. - `zone` - (Required, string) The globally unique name for this zone. @@ -146,7 +166,11 @@ The following attributes are exported: - `href` - (String) The URL for this share. - `id` - (String) The unique identifier of the Share. - `iops` - (Integer) The maximum input/output operation performance bandwidth per second for the file share. -- `last_sync_at` - (String) The date and time that the file share was last synchronized to its replica.This property will be present when the `replication_role` is `source`. +- `latest_sync` - (List) Information about the latest synchronization for this file share. +Nested `latest_sync` blocks have the following structure: + - `completed_at` - (String) The completed date and time of last synchronization between the replica share and its source. + - `data_transferred` - (Integer) The data transferred (in bytes) in the last synchronization between the replica and its source. + - `started_at` - (String) The start date and time of last synchronization between the replica share and its source. - `latest_job` - (List) The latest job associated with this file share.This property will be absent if no jobs have been created for this file share. Nested `latest_job` blocks have the following structure: - `status` - (String) The status of the file share job - `status_reasons` - (List) The reasons for the file share job status (if any). Nested `status_reasons` blocks have the following structure: