Skip to content

Commit

Permalink
enhancement(clone): support for snapshot clone
Browse files Browse the repository at this point in the history
  • Loading branch information
ujjwal-ibm committed Feb 20, 2023
1 parent e91be0e commit 23395cc
Show file tree
Hide file tree
Showing 17 changed files with 807 additions and 4 deletions.
14 changes: 13 additions & 1 deletion examples/ibm-is-ng/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -580,10 +580,11 @@ resource "ibm_is_instance" "instance4" {
keys = [ibm_is_ssh_key.sshkey.id]
}

// creating a snapshot from boot volume
// creating a snapshot from boot volume with clone
resource "ibm_is_snapshot" "b_snapshot" {
name = "my-snapshot-boot"
source_volume = ibm_is_instance.instance4.volume_attachments[0].volume_id
clones = [var.zone1]
tags = ["tags1"]
}

Expand All @@ -603,6 +604,17 @@ data "ibm_is_snapshot" "ds_snapshot" {
data "ibm_is_snapshots" "ds_snapshots" {
}

// data source for snapshot clones
data "ibm_is_snapshot_clones" "ds_snapshot_clones" {
snapshot = ibm_is_snapshot.b_snapshot.id
}

// data source for snapshot clones
data "ibm_is_snapshot_clones" "ds_snapshot_clone" {
snapshot = ibm_is_snapshot.b_snapshot.id
zone = var.zone1
}

// restoring a boot volume from snapshot in a new instance
resource "ibm_is_instance" "instance5" {
name = "instance5"
Expand Down
2 changes: 2 additions & 0 deletions ibm/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,8 @@ func Provider() *schema.Provider {
"ibm_is_security_group_rules": vpc.DataSourceIBMIsSecurityGroupRules(),
"ibm_is_security_group_target": vpc.DataSourceIBMISSecurityGroupTarget(),
"ibm_is_security_group_targets": vpc.DataSourceIBMISSecurityGroupTargets(),
"ibm_is_snapshot_clone": vpc.DataSourceSnapshotClone(),
"ibm_is_snapshot_clones": vpc.DataSourceSnapshotClones(),
"ibm_is_snapshot": vpc.DataSourceSnapshot(),
"ibm_is_snapshots": vpc.DataSourceSnapshots(),
"ibm_is_volume": vpc.DataSourceIBMISVolume(),
Expand Down
31 changes: 30 additions & 1 deletion ibm/service/vpc/data_source_ibm_is_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,13 @@ func DataSourceSnapshot() *schema.Resource {
Computed: true,
Description: "The size of the snapshot",
},

isSnapshotClones: {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
Description: "Zones for creating the snapshot clone",
},
isSnapshotCapturedAt: {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -253,6 +259,18 @@ func snapshotGetByNameOrID(d *schema.ResourceData, meta interface{}, name, id st
if snapshot.OperatingSystem != nil && snapshot.OperatingSystem.Name != nil {
d.Set(isSnapshotOperatingSystem, *snapshot.OperatingSystem.Name)
}

var clones []string
clones = make([]string, 0)
if snapshot.Clones != nil {
for _, clone := range snapshot.Clones {
if clone.Zone != nil && clone.Zone.Name != nil {
clones = append(clones, *clone.Zone.Name)
}
}
}
d.Set(isSnapshotClones, flex.NewStringSet(schema.HashString, clones))

backupPolicyPlanList := []map[string]interface{}{}
if snapshot.BackupPolicyPlan != nil {
backupPolicyPlan := map[string]interface{}{}
Expand Down Expand Up @@ -319,6 +337,17 @@ func snapshotGetByNameOrID(d *schema.ResourceData, meta interface{}, name, id st
if snapshot.OperatingSystem != nil && snapshot.OperatingSystem.Name != nil {
d.Set(isSnapshotOperatingSystem, *snapshot.OperatingSystem.Name)
}
var clones []string
clones = make([]string, 0)
if snapshot.Clones != nil {
for _, clone := range snapshot.Clones {
if clone.Zone != nil && clone.Zone.Name != nil {
clones = append(clones, *clone.Zone.Name)
}
}
}
d.Set(isSnapshotClones, flex.NewStringSet(schema.HashString, clones))

backupPolicyPlanList := []map[string]interface{}{}
if snapshot.BackupPolicyPlan != nil {
backupPolicyPlan := map[string]interface{}{}
Expand Down
85 changes: 85 additions & 0 deletions ibm/service/vpc/data_source_ibm_is_snapshot_clone.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright IBM Corp. 2017, 2021 All Rights Reserved.
// Licensed under the Mozilla Public License v2.0

package vpc

import (
"context"
"fmt"

"github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns"
"github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex"
"github.com/IBM/vpc-go-sdk/vpcv1"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func DataSourceSnapshotClone() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceIBMISSnapshotCloneRead,

Schema: map[string]*schema.Schema{
isSnapshot: {
Type: schema.TypeString,
Required: true,
},

isSnapshotCloneAvailable: {
Type: schema.TypeBool,
Computed: true,
Description: "Indicates whether this snapshot clone is available for use.",
},

isSnapshotCloneCreatedAt: {
Type: schema.TypeString,
Computed: true,
Description: "The date and time that this snapshot clone was created.",
},

isSnapshotCloneZone: {
Type: schema.TypeString,
Required: true,
Description: "The zone this snapshot clone resides in.",
},
},
}
}

func dataSourceIBMISSnapshotCloneRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
id := d.Get(isSnapshot).(string)
zone := d.Get(isSnapshotCloneZone).(string)
err := getSnapshotClone(context, d, meta, id, zone)
if err != nil {
return diag.FromErr(err)
}
return nil
}

func getSnapshotClone(context context.Context, d *schema.ResourceData, meta interface{}, id, zone string) error {
sess, err := meta.(conns.ClientSession).VpcV1API()
if err != nil {
return err
}

getSnapshotCloneOptions := &vpcv1.GetSnapshotCloneOptions{
ID: &id,
ZoneName: &zone,
}

clone, response, err := sess.GetSnapshotCloneWithContext(context, getSnapshotCloneOptions)
if err != nil {
return fmt.Errorf("[ERROR] Error fetching snapshot(%s) clone(%s) %s\n%s", id, zone, err, response)
}

if clone != nil && clone.Zone != nil {
d.SetId(*clone.Zone.Name)
d.Set(isSnapshotCloneZone, *clone.Zone.Name)
d.Set(isSnapshotCloneAvailable, *clone.Available)
if clone.CreatedAt != nil {
d.Set(isSnapshotCloneCreatedAt, flex.DateTimeToString(clone.CreatedAt))
}
} else {
return fmt.Errorf("[ERROR] No snapshot(%s) clone(%s) found", id, zone)
}
return nil
}
56 changes: 56 additions & 0 deletions ibm/service/vpc/data_source_ibm_is_snapshot_clone_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright IBM Corp. 2017, 2021 All Rights Reserved.
// Licensed under the Mozilla Public License v2.0

package vpc_test

import (
"fmt"
"strings"
"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"
)

func TestAccIBMISSnapshotCloneDatasource_basic(t *testing.T) {
var snapshot string
snpName := "data.ibm_is_snapshot_clone.ds_snapshot_clone"
vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100))
name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100))
subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100))
publicKey := strings.TrimSpace(`
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR
`)
sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100))
volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100))
name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100))
resource.Test(t, resource.TestCase{
PreCheck: func() { acc.TestAccPreCheck(t) },
Providers: acc.TestAccProviders,
CheckDestroy: testAccCheckIBMISSnapshotDestroy,
Steps: []resource.TestStep{
{
Config: testDSCheckIBMISSnapshotCloneConfig(vpcname, subnetname, sshname, publicKey, volname, name, name1),
Check: resource.ComposeTestCheckFunc(
testAccCheckIBMISSnapshotExists("ibm_is_snapshot.testacc_snapshot", snapshot),
resource.TestCheckResourceAttr(
"ibm_is_snapshot.testacc_snapshot", "name", name1),
resource.TestCheckResourceAttrSet(snpName, "available"),
resource.TestCheckResourceAttrSet(snpName, "created_at"),
),
},
},
})
}

func testDSCheckIBMISSnapshotCloneConfig(vpcname, subnetname, sshname, publicKey, volname, name, sname string) string {
return testAccCheckIBMISSnapshotCloneConfig(vpcname, subnetname, sshname, publicKey, volname, name, sname) +
fmt.Sprintf(`
data "ibm_is_snapshot_clone" "ds_snapshot_clone" {
snapshot = ibm_is_snapshot.testacc_snapshot.id
zone = "%s"
}
`, acc.ISZoneName)
}
113 changes: 113 additions & 0 deletions ibm/service/vpc/data_source_ibm_is_snapshot_clones.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright IBM Corp. 2017, 2021 All Rights Reserved.
// Licensed under the Mozilla Public License v2.0

package vpc

import (
"context"
"fmt"
"time"

"github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns"
"github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex"
"github.com/IBM/vpc-go-sdk/vpcv1"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

const (
isSnapshot = "snapshot"
isSnapshotClones = "clones"
isSnapshotCloneAvailable = "available"
isSnapshotCloneCreatedAt = "created_at"
isSnapshotCloneZone = "zone"
)

func DataSourceSnapshotClones() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceIBMISSnapshotClonesRead,

Schema: map[string]*schema.Schema{
isSnapshot: {
Type: schema.TypeString,
Required: true,
},

isSnapshotClones: {
Type: schema.TypeList,
Description: "List of snapshot clones",
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
isSnapshotCloneAvailable: {
Type: schema.TypeBool,
Computed: true,
Description: "Indicates whether this snapshot clone is available for use.",
},

isSnapshotCloneCreatedAt: {
Type: schema.TypeString,
Computed: true,
Description: "The date and time that this snapshot clone was created.",
},

isSnapshotCloneZone: {
Type: schema.TypeString,
Computed: true,
Description: "The zone this snapshot clone resides in.",
},
},
},
},
},
}
}

func dataSourceIBMISSnapshotClonesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
id := d.Get(isSnapshot).(string)
err := getSnapshotClones(context, d, meta, id)
if err != nil {
return diag.FromErr(err)
}
return nil
}

func getSnapshotClones(context context.Context, d *schema.ResourceData, meta interface{}, id string) error {
sess, err := meta.(conns.ClientSession).VpcV1API()
if err != nil {
return err
}

listSnapshotClonesOptions := &vpcv1.ListSnapshotClonesOptions{
ID: &id,
}

clonesCollection, response, err := sess.ListSnapshotClonesWithContext(context, listSnapshotClonesOptions)
if err != nil {
return fmt.Errorf("[ERROR] Error fetching snapshot(%s) clones %s\n%s", id, err, response)
}
clones := clonesCollection.Clones

clonesInfo := make([]map[string]interface{}, 0)
for _, clone := range clones {
l := map[string]interface{}{
isSnapshotCloneAvailable: *clone.Available,
}
if clone.CreatedAt != nil {
l[isSnapshotCloneCreatedAt] = flex.DateTimeToString(clone.CreatedAt)
}
if clone.Zone != nil {
l[isSnapshotCloneZone] = *clone.Zone.Name
}

clonesInfo = append(clonesInfo, l)
}
d.SetId(dataSourceIBMISSnapshotClonesID(d))
d.Set(isSnapshotClones, clonesInfo)
return nil
}

// dataSourceIBMISSnapshotClonesID returns a reasonable ID for the clone list.
func dataSourceIBMISSnapshotClonesID(d *schema.ResourceData) string {
return time.Now().UTC().String()
}
Loading

0 comments on commit 23395cc

Please sign in to comment.