From 686f6ca9404fd3f00c71c7b63c0c581f7360ffd7 Mon Sep 17 00:00:00 2001 From: Sunitha Gudisagar Date: Fri, 16 Dec 2022 13:10:41 +0530 Subject: [PATCH] Volume From Snapshot Development And Migration PR --- go.mod | 2 +- go.sum | 3 + .../data_source_ibm_is_instance_template.go | 4 +- .../data_source_ibm_is_instance_templates.go | 2 +- ibm/service/vpc/data_source_ibm_is_volume.go | 50 +++++++ ibm/service/vpc/data_source_ibm_is_volumes.go | 57 ++++++++ .../vpc/resource_ibm_is_instance_template.go | 10 +- ibm/service/vpc/resource_ibm_is_volume.go | 123 ++++++++++++++++-- .../vpc/resource_ibm_is_volume_test.go | 41 ++++++ website/docs/d/is_volume.html.markdown | 7 + website/docs/d/is_volumes.html.markdown | 12 ++ website/docs/r/is_volume.html.markdown | 21 ++- 12 files changed, 307 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 748d8fda70..aca33a6c33 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/IBM/scc-go-sdk/v4 v4.0.2 github.com/IBM/schematics-go-sdk v0.2.1 github.com/IBM/secrets-manager-go-sdk v0.1.19 - github.com/IBM/vpc-go-sdk v0.27.0 + github.com/IBM/vpc-go-sdk v0.28.0 github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 github.com/Shopify/sarama v1.29.1 github.com/apache/openwhisk-client-go v0.0.0-20200201143223-a804fb82d105 diff --git a/go.sum b/go.sum index 960b3efbb1..70e37fc46c 100644 --- a/go.sum +++ b/go.sum @@ -74,6 +74,7 @@ github.com/IBM/go-sdk-core/v5 v5.5.1/go.mod h1:Sn+z+qTDREQvCr+UFa22TqqfXNxx3o723 github.com/IBM/go-sdk-core/v5 v5.6.3/go.mod h1:tt/B9rxLkRtglE7pvqLuYikgCXaZFL3btdruJaoUeek= github.com/IBM/go-sdk-core/v5 v5.6.5/go.mod h1:tt/B9rxLkRtglE7pvqLuYikgCXaZFL3btdruJaoUeek= github.com/IBM/go-sdk-core/v5 v5.7.0/go.mod h1:+YbdhrjCHC84ls4MeBp+Hj4NZCni+tDAc0XQUqRO9Jc= +github.com/IBM/go-sdk-core/v5 v5.7.2/go.mod h1:+YbdhrjCHC84ls4MeBp+Hj4NZCni+tDAc0XQUqRO9Jc= github.com/IBM/go-sdk-core/v5 v5.8.0/go.mod h1:+YbdhrjCHC84ls4MeBp+Hj4NZCni+tDAc0XQUqRO9Jc= github.com/IBM/go-sdk-core/v5 v5.9.2/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV0j68/rlZsE= github.com/IBM/go-sdk-core/v5 v5.9.5/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV0j68/rlZsE= @@ -106,6 +107,8 @@ github.com/IBM/secrets-manager-go-sdk v0.1.19 h1:0GPs5EoTaWNsjo4QPj64GNxlWfN8VHJ github.com/IBM/secrets-manager-go-sdk v0.1.19/go.mod h1:eO3dBhzPrHkkt+yPex/jB2xD6qHZxBko+Aw+0tfqHeA= github.com/IBM/vpc-go-sdk v0.27.0 h1:PBpgjh5bjxrMT5BlaHfyaiJ/71pvycbmVQMuPOQ33ZY= github.com/IBM/vpc-go-sdk v0.27.0/go.mod h1:jYjS3EySPkC7DuOg33gMHtm8DcIf75Tc+Gxo3zmMBTQ= +github.com/IBM/vpc-go-sdk v0.28.0 h1:cOxzyxqjSZZqdSY0EiQEAzAGAVtYh2JBcvbve6OZguc= +github.com/IBM/vpc-go-sdk v0.28.0/go.mod h1:jYjS3EySPkC7DuOg33gMHtm8DcIf75Tc+Gxo3zmMBTQ= github.com/Logicalis/asn1 v0.0.0-20190312173541-d60463189a56 h1:vuquMR410psHNax14XKNWa0Ae/kYgWJcXi0IFuX60N0= github.com/Logicalis/asn1 v0.0.0-20190312173541-d60463189a56/go.mod h1:Zb3OT4l0mf7P/GOs2w2Ilj5sdm5Whoq3pa24dAEBHFc= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= diff --git a/ibm/service/vpc/data_source_ibm_is_instance_template.go b/ibm/service/vpc/data_source_ibm_is_instance_template.go index 3787c211b9..ea4ba223f6 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_template.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_template.go @@ -565,7 +565,7 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso volumeAttach[isInstanceTemplateVolAttName] = *volume.Name volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete volumeIntf := volume.Volume - volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) + volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentPrototypeVolume) newVolumeArr := []map[string]interface{}{} newVolume := map[string]interface{}{} @@ -817,7 +817,7 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso volumeAttach[isInstanceTemplateVolAttName] = *volume.Name volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete volumeIntf := volume.Volume - volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) + volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentPrototypeVolume) newVolumeArr := []map[string]interface{}{} newVolume := map[string]interface{}{} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_templates.go b/ibm/service/vpc/data_source_ibm_is_instance_templates.go index c8743f62c6..b33a6d38ab 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_templates.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_templates.go @@ -589,7 +589,7 @@ func dataSourceIBMISInstanceTemplatesRead(d *schema.ResourceData, meta interface volumeAttach[isInstanceTemplateVolAttName] = *volume.Name volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete volumeIntf := volume.Volume - volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) + volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentPrototypeVolume) newVolumeArr := []map[string]interface{}{} newVolume := map[string]interface{}{} diff --git a/ibm/service/vpc/data_source_ibm_is_volume.go b/ibm/service/vpc/data_source_ibm_is_volume.go index ea8f705d31..e19adf8e0f 100644 --- a/ibm/service/vpc/data_source_ibm_is_volume.go +++ b/ibm/service/vpc/data_source_ibm_is_volume.go @@ -109,6 +109,38 @@ func DataSourceIBMISVolume() *schema.Resource { Computed: true, Description: "Link to documentation about this status reason", }, + + isVolumeHealthReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumeHealthReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this health state.", + }, + + isVolumeHealthReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this health state.", + }, + + isVolumeHealthReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this health state.", + }, + }, + }, + }, + + isVolumeHealthState: { + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource.", + }, }, }, }, @@ -271,6 +303,24 @@ func volumeGet(d *schema.ResourceData, meta interface{}, name string) error { } d.Set(isVolumeStatusReasons, statusReasonsList) } + if vol.HealthReasons != nil { + healthReasonsList := make([]map[string]interface{}, 0) + for _, sr := range vol.HealthReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isVolumeHealthReasonsCode] = *sr.Code + currentSR[isVolumeHealthReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isVolumeHealthReasonsMoreInfo] = *sr.Message + } + healthReasonsList = append(healthReasonsList, currentSR) + } + } + d.Set(isVolumeHealthReasons, healthReasonsList) + } + if vol.HealthState != nil { + d.Set(isVolumeHealthState, *vol.HealthState) + } controller, err := flex.GetBaseController(meta) if err != nil { return err diff --git a/ibm/service/vpc/data_source_ibm_is_volumes.go b/ibm/service/vpc/data_source_ibm_is_volumes.go index 292e403d8f..32d92ff6f0 100644 --- a/ibm/service/vpc/data_source_ibm_is_volumes.go +++ b/ibm/service/vpc/data_source_ibm_is_volumes.go @@ -494,6 +494,37 @@ func DataSourceIBMIsVolumes() *schema.Resource { Set: flex.ResourceIBMVPCHash, Description: "Access management tags for the volume instance", }, + isVolumeHealthReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumeHealthReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this health state.", + }, + + isVolumeHealthReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this health state.", + }, + + isVolumeHealthReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this health state.", + }, + }, + }, + }, + + isVolumeHealthState: { + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource.", + }, }, }, }, @@ -639,6 +670,9 @@ func dataSourceVolumeCollectionVolumesToMap(volumesItem vpcv1.Volume, meta inter if volumesItem.Status != nil { volumesMap[isVolumesStatus] = volumesItem.Status } + if volumesItem.HealthState != nil { + volumesMap[isVolumeHealthState] = volumesItem.HealthState + } if volumesItem.StatusReasons != nil { statusReasonsList := []map[string]interface{}{} for _, statusReasonsItem := range volumesItem.StatusReasons { @@ -646,6 +680,13 @@ func dataSourceVolumeCollectionVolumesToMap(volumesItem vpcv1.Volume, meta inter } volumesMap[isVolumesStatusReasons] = statusReasonsList } + if volumesItem.HealthReasons != nil { + healthReasonsList := []map[string]interface{}{} + for _, healthReasonsItem := range volumesItem.HealthReasons { + healthReasonsList = append(healthReasonsList, dataSourceVolumeCollectionVolumesHealthReasonsToMap(healthReasonsItem)) + } + volumesMap[isVolumeHealthReasons] = healthReasonsList + } if volumesItem.VolumeAttachments != nil { volumeAttachmentsList := []map[string]interface{}{} for _, volumeAttachmentsItem := range volumesItem.VolumeAttachments { @@ -812,6 +853,22 @@ func dataSourceVolumeCollectionVolumesStatusReasonsToMap(statusReasonsItem vpcv1 return statusReasonsMap } +func dataSourceVolumeCollectionVolumesHealthReasonsToMap(statusReasonsItem vpcv1.VolumeHealthReason) (healthReasonsMap map[string]interface{}) { + healthReasonsMap = map[string]interface{}{} + + if statusReasonsItem.Code != nil { + healthReasonsMap[isVolumeHealthReasonsCode] = statusReasonsItem.Code + } + if statusReasonsItem.Message != nil { + healthReasonsMap[isVolumeHealthReasonsMessage] = statusReasonsItem.Message + } + if statusReasonsItem.MoreInfo != nil { + healthReasonsMap[isVolumeHealthReasonsMoreInfo] = statusReasonsItem.MoreInfo + } + + return healthReasonsMap +} + func dataSourceVolumeCollectionVolumesVolumeAttachmentsToMap(volumeAttachmentsItem vpcv1.VolumeAttachmentReferenceVolumeContext) (volumeAttachmentsMap map[string]interface{}) { volumeAttachmentsMap = map[string]interface{}{} diff --git a/ibm/service/vpc/resource_ibm_is_instance_template.go b/ibm/service/vpc/resource_ibm_is_instance_template.go index 215003ed1c..b8ff203a6a 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template.go @@ -741,10 +741,10 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n // Handle volume attachments if volsintf, ok := d.GetOk(isInstanceTemplateVolumeAttachments); ok { vols := volsintf.([]interface{}) - var intfs []vpcv1.VolumeAttachmentPrototypeInstanceContext + var intfs []vpcv1.VolumeAttachmentPrototype for _, resource := range vols { vol := resource.(map[string]interface{}) - volInterface := &vpcv1.VolumeAttachmentPrototypeInstanceContext{} + volInterface := &vpcv1.VolumeAttachmentPrototype{} deleteVolBool := vol[isInstanceTemplateVolumeDeleteOnInstanceDelete].(bool) volInterface.DeleteVolumeOnInstanceDelete = &deleteVolBool attachmentnamestr := vol[isInstanceTemplateVolAttachmentName].(string) @@ -752,7 +752,7 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n volIdStr := vol[isInstanceTemplateVolAttVol].(string) if volIdStr != "" { - volInterface.Volume = &vpcv1.VolumeAttachmentVolumePrototypeInstanceContextVolumeIdentity{ + volInterface.Volume = &vpcv1.VolumeAttachmentPrototypeVolume{ ID: &volIdStr, } } else { @@ -761,7 +761,7 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n profileName := newvol[isInstanceTemplateVolAttVolProfile].(string) capacity := int64(newvol[isInstanceTemplateVolAttVolCapacity].(int)) - volPrototype := &vpcv1.VolumeAttachmentVolumePrototypeInstanceContextVolumePrototypeInstanceContext{ + volPrototype := &vpcv1.VolumeAttachmentPrototypeVolumeVolumePrototypeInstanceContext{ Profile: &vpcv1.VolumeProfileIdentity{ Name: &profileName, }, @@ -1215,7 +1215,7 @@ func instanceTemplateGet(d *schema.ResourceData, meta interface{}, ID string) er newVolumeArr := []map[string]interface{}{} newVolume := map[string]interface{}{} volumeIntf := volume.Volume - volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) + volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentPrototypeVolume) if volumeInst.ID != nil { volumeAttach[isInstanceTemplateVolAttVol] = *volumeInst.ID } diff --git a/ibm/service/vpc/resource_ibm_is_volume.go b/ibm/service/vpc/resource_ibm_is_volume.go index 5811062819..f30f68228e 100644 --- a/ibm/service/vpc/resource_ibm_is_volume.go +++ b/ibm/service/vpc/resource_ibm_is_volume.go @@ -45,6 +45,11 @@ const ( isVolumeAccessTags = "access_tags" isVolumeUserTagType = "user" isVolumeAccessTagType = "access" + isVolumeHealthReasons = "health_reasons" + isVolumeHealthReasonsCode = "code" + isVolumeHealthReasonsMessage = "message" + isVolumeHealthReasonsMoreInfo = "more_info" + isVolumeHealthState = "health_state" ) func ResourceIBMISVolume() *schema.Resource { @@ -116,11 +121,19 @@ func ResourceIBMISVolume() *schema.Resource { isVolumeCapacity: { Type: schema.TypeInt, Optional: true, - Default: 100, ForceNew: false, + Computed: true, ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeCapacity), Description: "Volume capacity value", }, + isVolumeSourceSnapshot: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeSourceSnapshot), + Description: "The unique identifier for this snapshot", + }, isVolumeResourceGroup: { Type: schema.TypeString, Optional: true, @@ -171,11 +184,36 @@ func ResourceIBMISVolume() *schema.Resource { }, }, }, + isVolumeHealthReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumeHealthReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this health state.", + }, - isVolumeSourceSnapshot: { + isVolumeHealthReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this health state.", + }, + + isVolumeHealthReasonsMoreInfo: { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this health state.", + }, + }, + }, + }, + + isVolumeHealthState: { Type: schema.TypeString, Computed: true, - Description: "Identifier of the snapshot from which this volume was cloned", + Description: "The health of this resource.", }, isVolumeDeleteAllSnapshots: { Type: schema.TypeBool, @@ -275,6 +313,15 @@ func ResourceIBMISVolumeValidator() *validate.ResourceValidator { Type: validate.TypeInt, MinValue: "10", MaxValue: "16000"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVolumeSourceSnapshot, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[-0-9a-z_]+$`, + MinValueLength: 1, + MaxValueLength: 64}) validateSchema = append(validateSchema, validate.ValidateSchema{ Identifier: isVolumeIops, @@ -301,14 +348,8 @@ func resourceIBMISVolumeCreate(d *schema.ResourceData, meta interface{}) error { volName := d.Get(isVolumeName).(string) profile := d.Get(isVolumeProfileName).(string) zone := d.Get(isVolumeZone).(string) - var volCapacity int64 - if capacity, ok := d.GetOk(isVolumeCapacity); ok { - volCapacity = int64(capacity.(int)) - } else { - volCapacity = 100 - } - err := volCreate(d, meta, volName, profile, zone, volCapacity) + err := volCreate(d, meta, volName, profile, zone) if err != nil { return err } @@ -316,15 +357,15 @@ func resourceIBMISVolumeCreate(d *schema.ResourceData, meta interface{}) error { return resourceIBMISVolumeRead(d, meta) } -func volCreate(d *schema.ResourceData, meta interface{}, volName, profile, zone string, volCapacity int64) error { +func volCreate(d *schema.ResourceData, meta interface{}, volName, profile, zone string) error { sess, err := vpcClient(meta) if err != nil { return err } + log.Println("I AM INSIDE func volCreate(d *schema.ResourceData, meta interface{}, volName, profile, zone string)") options := &vpcv1.CreateVolumeOptions{ VolumePrototype: &vpcv1.VolumePrototype{ - Name: &volName, - Capacity: &volCapacity, + Name: &volName, Zone: &vpcv1.ZoneIdentity{ Name: &zone, }, @@ -335,6 +376,44 @@ func volCreate(d *schema.ResourceData, meta interface{}, volName, profile, zone } volTemplate := options.VolumePrototype.(*vpcv1.VolumePrototype) + var volCapacity int64 + if sourceSnapsht, ok := d.GetOk(isVolumeSourceSnapshot); ok { + sourceSnapshot := sourceSnapsht.(string) + snapshotIdentity := &vpcv1.SnapshotIdentity{ + ID: &sourceSnapshot, + } + volTemplate.SourceSnapshot = snapshotIdentity + getSnapshotOptions := &vpcv1.GetSnapshotOptions{ + ID: &sourceSnapshot, + } + snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error fetching snapshot %s\n%s", err, response) + } + if (response != nil && response.StatusCode == 404) || snapshot == nil { + return fmt.Errorf("[ERROR] No snapshot found with id %s", sourceSnapshot) + } + minimumCapacity := *snapshot.MinimumCapacity + if capacity, ok := d.GetOk(isVolumeCapacity); ok { + if int64(capacity.(int)) > minimumCapacity { + volCapacity = int64(capacity.(int)) + } else { + volCapacity = minimumCapacity + } + volTemplate.Capacity = &volCapacity + } + } else { + + if capacity, ok := d.GetOk(isVolumeCapacity); ok { + if int64(capacity.(int)) > 0 { + volCapacity = int64(capacity.(int)) + } + } else { + volCapacity = 100 + } + volTemplate.Capacity = &volCapacity + } + if key, ok := d.GetOk(isVolumeEncryptionKey); ok { encryptionKey := key.(string) volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ @@ -438,6 +517,9 @@ func volGet(d *schema.ResourceData, meta interface{}, id string) error { d.Set(isVolumeSourceSnapshot, *vol.SourceSnapshot.ID) } d.Set(isVolumeStatus, *vol.Status) + if vol.HealthState != nil { + d.Set(isVolumeHealthState, *vol.HealthState) + } d.Set(isVolumeBandwidth, int(*vol.Bandwidth)) //set the status reasons if vol.StatusReasons != nil { @@ -466,6 +548,21 @@ func volGet(d *schema.ResourceData, meta interface{}, id string) error { "Error on get of resource volume (%s) access tags: %s", d.Id(), err) } d.Set(isVolumeAccessTags, accesstags) + if vol.HealthReasons != nil { + healthReasonsList := make([]map[string]interface{}, 0) + for _, sr := range vol.HealthReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isVolumeHealthReasonsCode] = *sr.Code + currentSR[isVolumeHealthReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isVolumeHealthReasonsMoreInfo] = *sr.Message + } + healthReasonsList = append(healthReasonsList, currentSR) + } + } + d.Set(isVolumeHealthReasons, healthReasonsList) + } controller, err := flex.GetBaseController(meta) if err != nil { return err diff --git a/ibm/service/vpc/resource_ibm_is_volume_test.go b/ibm/service/vpc/resource_ibm_is_volume_test.go index 831830587e..d37f3b1e22 100644 --- a/ibm/service/vpc/resource_ibm_is_volume_test.go +++ b/ibm/service/vpc/resource_ibm_is_volume_test.go @@ -49,6 +49,35 @@ func TestAccIBMISVolume_basic(t *testing.T) { }) } +func TestAccIBMISVolume_snapshot(t *testing.T) { + var vol string + 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: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVolumeConfigSnapshot(vpcname, subnetname, sshname, publicKey, volname, name, name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttrSet("ibm_is_volume.storage", "health_state"), + resource.TestCheckResourceAttrSet("ibm_is_volume.storage", "health_reasons.#"), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", volname), + ), + }, + }, + }) +} func TestAccIBMISVolumeUsertag_basic(t *testing.T) { var vol string name := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) @@ -507,3 +536,15 @@ func testAccCheckIBMISVolumeUsertagConfig(name, usertag string) string { `, name, usertag) } + +func testAccCheckIBMISVolumeConfigSnapshot(vpcname, subnetname, sshname, publicKey, volname, name, name1 string) string { + + return testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, volname, name, name1) + fmt.Sprintf(` + resource "ibm_is_volume" "storage" { + name = "%s" + profile = "general-purpose" + zone = "%s" + source_snapshot= ibm_is_snapshot.testacc_snapshot.id + } + `, volname, acc.ISZoneName) +} diff --git a/website/docs/d/is_volume.html.markdown b/website/docs/d/is_volume.html.markdown index 2cd2c4040a..620c10b4e4 100644 --- a/website/docs/d/is_volume.html.markdown +++ b/website/docs/d/is_volume.html.markdown @@ -49,6 +49,13 @@ In addition to all argument reference list, you can access the following attribu - `crn` - (String) The crn of this volume. - `encryption_key` - (String) The key to use for encrypting this volume. - `encryption_type` - (String) The type of ecryption used in the volume [**provider_managed**, **user_managed**]. +- `health_reasons` - (List) The reasons for the current health_state (if any). + + Nested scheme for `health_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this health state. + - `message` - (String) An explanation of the reason for this health state. + - `more_info` - (String) Link to documentation about the reason for this health state. +- `health_state` - (String) The health of this resource. - `iops` - (String) The bandwidth for the volume. - `profile` - (String) The profile to use for this volume. - `resource_group` - (String) The resource group ID for this volume. diff --git a/website/docs/d/is_volumes.html.markdown b/website/docs/d/is_volumes.html.markdown index 3bf12c328b..43d10cff98 100644 --- a/website/docs/d/is_volumes.html.markdown +++ b/website/docs/d/is_volumes.html.markdown @@ -17,6 +17,11 @@ data "ibm_is_volumes" "example" { } ``` +## Argument reference +Review the argument references that you can specify for your data source. + +- `volume_name` - (Required, String) Filters the collection to resources with the exact specified name. +- `zone_name` - (Optional, String) Filters the collection to resources in the zone with the exact specified name. ## Attribute Reference @@ -38,6 +43,13 @@ In addition to all argument references listed, you can access the following attr - `encryption_key` - (Optional, List) The root key used to wrap the data encryption key for the volume.This property will be present for volumes with an `encryption` type of`user_managed`. Nested scheme for **encryption_key**: - `crn` - (String) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource. + - `health_reasons` - (List) The reasons for the current health_state (if any). + + Nested scheme for `health_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this health state. + - `message` - (String) An explanation of the reason for this health state. + - `more_info` - (String) Link to documentation about the reason for this health state. + - `health_state` - (String) The health of this resource. - `href` - (String) The URL for this volume. - Constraints: The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. - `id` - (String) The unique identifier for this volume. diff --git a/website/docs/r/is_volume.html.markdown b/website/docs/r/is_volume.html.markdown index 51c869a569..372319ae2d 100644 --- a/website/docs/r/is_volume.html.markdown +++ b/website/docs/r/is_volume.html.markdown @@ -45,6 +45,15 @@ resource "ibm_is_volume" "example" { ``` +The following example creates a volume from snapshot. +```terraform +resource "ibm_is_volume" "storage" { + name = "example-volume" + profile = "general-purpose" + zone = "us-south-1" + source_snapshot = ibm_is_snapshot.example.id +} +``` ## Timeouts The `ibm_is_volume` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: @@ -64,7 +73,7 @@ Review the argument references that you can specify for your resource. **•** `access_tags` must be in the format `key:value`. - `capacity` - (Optional, Integer) (The capacity of the volume in gigabytes. This defaults to `100`, minimum to `10 ` and maximum to `16000`. - ~> **NOTE:** Supports only expansion on update (must be attached to a running instance and must not be less than the current volume capacity). Can be updated only if volume is attached to an running virtual server instance. Stopped instance will be started on update of capacity of the volume. + ~> **NOTE:** Supports only expansion on update (must be attached to a running instance and must not be less than the current volume capacity). Can be updated only if volume is attached to an running virtual server instance. Stopped instance will be started on update of capacity of the volume.If `source_snapshot` is provided `capacity` must be at least the snapshot's minimum_capacity. The maximum value may increase in the future and If unspecified, the capacity will be the source snapshot's minimum_capacity. - `bandwidth` - (Integer) The maximum bandwidth (in megabits per second) for the volume - `delete_all_snapshots` - (Optional, Bool) Deletes all snapshots created from this volume. @@ -94,15 +103,21 @@ Review the argument references that you can specify for your resource. ~> **NOTE:** tiered profiles [`general-purpose`, `5iops-tier`, `10iops-tier`] can be upgraded and downgraded into each other if volume is attached to an running virtual server instance. Stopped instances will be started on update of volume. - `resource_group` - (Optional, Forces new resource, String) The resource group ID for this volume. - `resource_controller_url` - (Optional, Forces new resource, String) The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance. +- `source_snapshot` - The ID of snapshot from which to clone the volume. - `tags`- (Optional, Array of Strings) A list of user tags that you want to add to your volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) - `zone` - (Required, Forces new resource, String) The location of the volume. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. - - `encryption_type` - (String) The type of encryption used in the volume [**provider_managed**, **user_managed**]. +- `health_reasons` - (List) The reasons for the current health_state (if any). + + Nested scheme for `health_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this health state. + - `message` - (String) An explanation of the reason for this health state. + - `more_info` - (String) Link to documentation about the reason for this health state. +- `health_state` - (String) The health of this resource. - `id` - (String) The unique identifier of the volume. -- `source_snapshot` - ID of the snapshot, if volume was created from it. - `status` - (String) The status of volume. Supported values are **available**, **failed**, **pending**, **unusable**, or **pending_deletion**. - `status_reasons` - (List) Array of reasons for the current status.